From: Junio C Hamano Date: Wed, 27 Dec 2006 10:43:46 +0000 (-0800) Subject: Merge branch 'master' into js/shallow X-Git-Tag: v1.5.0-rc1~172^2 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/37818d7db070f67a20df58ac7d5e04cc63ef1867?hp=-c Merge branch 'master' into js/shallow This is to adjust to: count-objects -v: show number of packs as well. which will break a test in this series. Signed-off-by: Junio C Hamano --- 37818d7db070f67a20df58ac7d5e04cc63ef1867 diff --combined Makefile index ea5d2cf723,52d4a3a86a..c21b91bfab --- a/Makefile +++ b/Makefile @@@ -69,7 -69,8 +69,8 @@@ all # # Define NO_MMAP if you want to avoid mmap. # - # Define WITH_OWN_SUBPROCESS_PY if you want to use with python 2.3. + # Define NO_FAST_WORKING_DIRECTORY if accessing objects in pack files is + # generally faster on your platform than accessing the working directory. # # Define NO_IPV6 if you lack IPv6 support and getaddrinfo(). # @@@ -78,13 -79,6 +79,6 @@@ # # Define NO_ICONV if your libc does not properly support iconv. # - # Define NO_ACCURATE_DIFF if your diff program at least sometimes misses - # a missing newline at the end of the file. - # - # Define COLLISION_CHECK below if you believe that SHA1's - # 1461501637330902918203684832716283019655932542976 hashes do not give you - # sufficient guarantee that no collisions between objects will ever happen. - # # Define USE_NSEC below if you want git to care about sub-second file mtimes # and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and # it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely @@@ -93,6 -87,10 +87,10 @@@ # # Define USE_STDEV below if you want git to care about the underlying device # change being considered an inode change from the update-cache perspective. + # + # Define NO_PERL_MAKEMAKER if you cannot use Makefiles generated by perl's + # MakeMaker (e.g. using ActiveState under Cygwin). + # GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE @$(SHELL_PATH) ./GIT-VERSION-GEN @@@ -116,7 -114,6 +114,6 @@@ prefix = $(HOME bindir = $(prefix)/bin gitexecdir = $(bindir) template_dir = $(prefix)/share/git-core/templates/ - GIT_PYTHON_DIR = $(prefix)/share/git-core/python # DESTDIR= # default configuration for gitweb @@@ -135,7 -132,7 +132,7 @@@ GITWEB_FAVICON = git-favicon.pn GITWEB_SITE_HEADER = GITWEB_SITE_FOOTER = - export prefix bindir gitexecdir template_dir GIT_PYTHON_DIR + export prefix bindir gitexecdir template_dir CC = gcc AR = ar @@@ -173,18 -170,14 +170,14 @@@ SCRIPT_SH = git-lost-found.sh git-quiltimport.sh SCRIPT_PERL = \ + git-add--interactive.perl \ git-archimport.perl git-cvsimport.perl git-relink.perl \ - git-shortlog.perl git-rerere.perl \ git-cvsserver.perl \ git-svnimport.perl git-cvsexportcommit.perl \ git-send-email.perl git-svn.perl - SCRIPT_PYTHON = \ - git-merge-recursive-old.py - SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \ $(patsubst %.perl,%,$(SCRIPT_PERL)) \ - $(patsubst %.py,%,$(SCRIPT_PYTHON)) \ git-cherry-pick git-status git-instaweb # ... and all the rest that could be moved out of bindir to gitexecdir @@@ -227,12 -220,8 +220,8 @@@ endi ifndef PERL_PATH PERL_PATH = /usr/bin/perl endif - ifndef PYTHON_PATH - PYTHON_PATH = /usr/bin/python - endif - PYMODULES = \ - gitMergeCommon.py + export PERL_PATH LIB_FILE=libgit.a XDIFF_LIB=xdiff/lib.a @@@ -241,7 -230,8 +230,8 @@@ LIB_H = archive.h blob.h cache.h commit.h csum-file.h delta.h grep.h \ diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \ run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \ - tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h + tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \ + utf8.h DIFF_OBJS = \ diff.o diff-lib.o diffcore-break.o diffcore-order.o \ @@@ -260,7 -250,8 +250,7 @@@ LIB_OBJS = revision.o pager.o tree-walk.o xdiff-interface.o \ write_or_die.o trace.o list-objects.o grep.o \ alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \ - color.o wt-status.o archive-zip.o archive-tar.o shallow.o - color.o wt-status.o archive-zip.o archive-tar.o \ - utf8.o ++ color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o BUILTIN_OBJS = \ builtin-add.o \ @@@ -288,6 -279,7 +278,7 @@@ builtin-ls-tree.o \ builtin-mailinfo.o \ builtin-mailsplit.o \ + builtin-merge-file.o \ builtin-mv.o \ builtin-name-rev.o \ builtin-pack-objects.o \ @@@ -295,11 -287,14 +286,14 @@@ builtin-prune-packed.o \ builtin-push.o \ builtin-read-tree.o \ + builtin-reflog.o \ builtin-repo-config.o \ + builtin-rerere.o \ builtin-rev-list.o \ builtin-rev-parse.o \ builtin-rm.o \ builtin-runstatus.o \ + builtin-shortlog.o \ builtin-show-branch.o \ builtin-stripspace.o \ builtin-symbolic-ref.o \ @@@ -334,18 -329,6 +328,6 @@@ ifeq ($(uname_S),Darwin NEEDS_SSL_WITH_CRYPTO = YesPlease NEEDS_LIBICONV = YesPlease NO_STRLCPY = YesPlease - ifndef NO_FINK - ifeq ($(shell test -d /sw/lib && echo y),y) - BASIC_CFLAGS += -I/sw/include - BASIC_LDFLAGS += -L/sw/lib - endif - endif - ifndef NO_DARWIN_PORTS - ifeq ($(shell test -d /opt/local/lib && echo y),y) - BASIC_CFLAGS += -I/opt/local/include - BASIC_LDFLAGS += -L/opt/local/lib - endif - endif endif ifeq ($(uname_S),SunOS) NEEDS_SOCKET = YesPlease @@@ -374,6 -357,7 +356,7 @@@ ifeq ($(uname_O),Cygwin NO_SYMLINK_HEAD = YesPlease NEEDS_LIBICONV = YesPlease NO_C99_FORMAT = YesPlease + NO_FAST_WORKING_DIRECTORY = UnfortunatelyYes # There are conflicting reports about this. # On some boxes NO_MMAP is needed, and not so elsewhere. # Try uncommenting this if you see things break -- YMMV. @@@ -423,12 -407,17 +406,17 @@@ endi -include config.mak.autogen -include config.mak - ifdef WITH_OWN_SUBPROCESS_PY - PYMODULES += compat/subprocess.py - else - ifeq ($(NO_PYTHON),) - ifneq ($(shell $(PYTHON_PATH) -c 'import subprocess;print"OK"' 2>/dev/null),OK) - PYMODULES += compat/subprocess.py + ifeq ($(uname_S),Darwin) + ifndef NO_FINK + ifeq ($(shell test -d /sw/lib && echo y),y) + BASIC_CFLAGS += -I/sw/include + BASIC_LDFLAGS += -L/sw/lib + endif + endif + ifndef NO_DARWIN_PORTS + ifeq ($(shell test -d /opt/local/lib && echo y),y) + BASIC_CFLAGS += -I/opt/local/include + BASIC_LDFLAGS += -L/opt/local/lib endif endif endif @@@ -520,6 -509,9 +508,9 @@@ ifdef NO_MMA COMPAT_CFLAGS += -DNO_MMAP COMPAT_OBJS += compat/mmap.o endif + ifdef NO_FAST_WORKING_DIRECTORY + BASIC_CFLAGS += -DNO_FAST_WORKING_DIRECTORY + endif ifdef NO_IPV6 BASIC_CFLAGS += -DNO_IPV6 endif @@@ -558,8 -550,8 +549,8 @@@ els endif endif endif - ifdef NO_ACCURATE_DIFF - BASIC_CFLAGS += -DNO_ACCURATE_DIFF + ifdef NO_PERL_MAKEMAKER + export NO_PERL_MAKEMAKER endif # Shell quote (do not use $(call) to accommodate ancient setups); @@@ -574,8 -566,6 +565,6 @@@ prefix_SQ = $(subst ','\'',$(prefix) SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH)) PERL_PATH_SQ = $(subst ','\'',$(PERL_PATH)) - PYTHON_PATH_SQ = $(subst ','\'',$(PYTHON_PATH)) - GIT_PYTHON_DIR_SQ = $(subst ','\'',$(GIT_PYTHON_DIR)) LIBS = $(GITLIBS) $(EXTLIBS) @@@ -592,8 -582,8 +581,8 @@@ export prefix TAR INSTALL DESTDIR SHELL all: $(ALL_PROGRAMS) $(BUILT_INS) git$X gitk gitweb/gitweb.cgi - all: perl/Makefile - $(MAKE) -C perl + all: + $(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' all $(MAKE) -C templates strip: $(PROGRAMS) git$X @@@ -622,12 -612,15 +611,15 @@@ $(patsubst %.sh,%,$(SCRIPT_SH)) : % : % -e 's|@@PERL@@|$(PERL_PATH_SQ)|g' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ - -e 's/@@NO_PYTHON@@/$(NO_PYTHON)/g' \ $@.sh >$@+ chmod +x $@+ mv $@+ $@ - $(patsubst %.perl,%,$(SCRIPT_PERL)): perl/Makefile + $(patsubst %.perl,%,$(SCRIPT_PERL)): perl/perl.mak + + perl/perl.mak: GIT-CFLAGS + $(MAKE) -C perl PERL_PATH='$(PERL_PATH_SQ)' prefix='$(prefix_SQ)' $(@F) + $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl rm -f $@ $@+ INSTLIBDIR=`$(MAKE) -C perl -s --no-print-directory instlibdir` && \ @@@ -644,15 -637,6 +636,6 @@@ chmod +x $@+ mv $@+ $@ - $(patsubst %.py,%,$(SCRIPT_PYTHON)) : % : %.py GIT-CFLAGS - rm -f $@ $@+ - sed -e '1s|#!.*python|#!$(PYTHON_PATH_SQ)|' \ - -e 's|@@GIT_PYTHON_PATH@@|$(GIT_PYTHON_DIR_SQ)|g' \ - -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ - $@.py >$@+ - chmod +x $@+ - mv $@+ $@ - git-cherry-pick: git-revert cp $< $@+ mv $@+ $@ @@@ -689,7 -673,6 +672,6 @@@ git-instaweb: git-instaweb.sh gitweb/gi sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \ -e 's/@@GIT_VERSION@@/$(GIT_VERSION)/g' \ -e 's/@@NO_CURL@@/$(NO_CURL)/g' \ - -e 's/@@NO_PYTHON@@/$(NO_PYTHON)/g' \ -e '/@@GITWEB_CGI@@/r gitweb/gitweb.cgi' \ -e '/@@GITWEB_CGI@@/d' \ -e '/@@GITWEB_CSS@@/r gitweb/gitweb.css' \ @@@ -709,7 -692,6 +691,6 @@@ configure: configure.a git$X git.spec \ $(patsubst %.sh,%,$(SCRIPT_SH)) \ $(patsubst %.perl,%,$(SCRIPT_PERL)) \ - $(patsubst %.py,%,$(SCRIPT_PYTHON)) \ : GIT-VERSION-FILE %.o: %.c GIT-CFLAGS @@@ -759,7 -741,8 +740,8 @@@ $(DIFF_OBJS): diffcore. $(LIB_FILE): $(LIB_OBJS) rm -f $@ && $(AR) rcs $@ $(LIB_OBJS) - XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o + XDIFF_OBJS=xdiff/xdiffi.o xdiff/xprepare.o xdiff/xutils.o xdiff/xemit.o \ + xdiff/xmerge.o $(XDIFF_OBJS): xdiff/xinclude.h xdiff/xmacros.h xdiff/xdiff.h xdiff/xtypes.h \ xdiff/xutils.h xdiff/xprepare.h xdiff/xdiffi.h xdiff/xemit.h @@@ -783,7 -766,7 +765,7 @@@ tags find . -name '*.[hcS]' -print | xargs ctags -a ### Detect prefix changes - TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):$(GIT_PYTHON_DIR_SQ):\ + TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\ $(bindir_SQ):$(gitexecdir_SQ):$(template_dir_SQ):$(prefix_SQ) GIT-CFLAGS: .FORCE-GIT-CFLAGS @@@ -799,7 -782,6 +781,6 @@@ # However, the environment gets quite big, and some programs have problems # with that. - export NO_PYTHON export NO_SVN_TESTS test: all @@@ -808,8 -790,8 +789,8 @@@ test-date$X: test-date.c date.o ctype.o $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) test-date.c date.o ctype.o - test-delta$X: test-delta.c diff-delta.o patch-delta.o - $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^ + test-delta$X: test-delta.o diff-delta.o patch-delta.o $(GITLIBS) + $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS) $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS) @@@ -833,9 -815,7 +814,7 @@@ install: al $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexecdir_SQ)' $(INSTALL) git$X gitk '$(DESTDIR_SQ)$(bindir_SQ)' $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install - $(MAKE) -C perl install - $(INSTALL) -d -m755 '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)' - $(INSTALL) $(PYMODULES) '$(DESTDIR_SQ)$(GIT_PYTHON_DIR_SQ)' + $(MAKE) -C perl prefix='$(prefix_SQ)' install if test 'z$(bindir_SQ)' != 'z$(gitexecdir_SQ)'; \ then \ ln -f '$(DESTDIR_SQ)$(bindir_SQ)/git$X' \ @@@ -848,6 -828,8 +827,8 @@@ install-doc: $(MAKE) -C Documentation install + quick-install-doc: + $(MAKE) -C Documentation quick-install @@@ -905,8 -887,7 +886,7 @@@ clean rm -f $(htmldocs).tar.gz $(manpages).tar.gz rm -f gitweb/gitweb.cgi $(MAKE) -C Documentation/ clean - [ ! -f perl/Makefile ] || $(MAKE) -C perl/ clean || $(MAKE) -C perl/ clean - rm -f perl/ppport.h perl/Makefile.old + $(MAKE) -C perl clean $(MAKE) -C templates/ clean $(MAKE) -C t/ clean rm -f GIT-VERSION-FILE GIT-CFLAGS @@@ -922,7 -903,6 +902,6 @@@ check-docs: case "$$v" in \ git-merge-octopus | git-merge-ours | git-merge-recursive | \ git-merge-resolve | git-merge-stupid | git-merge-recur | \ - git-merge-recursive-old | \ git-ssh-pull | git-ssh-push ) continue ;; \ esac ; \ test -f "Documentation/$$v.txt" || \ diff --combined commit.c index d5103cd3c6,3167ce62ac..59ea77c577 --- a/commit.c +++ b/commit.c @@@ -1,7 -1,6 +1,7 @@@ #include "cache.h" #include "tag.h" #include "commit.h" +#include "pkt-line.h" int save_commit_buffer = 1; @@@ -222,8 -221,6 +222,8 @@@ static void prepare_commit_graft(void return; graft_file = get_graft_file(); read_graft_file(graft_file); + /* make sure shallows are read */ + is_repository_shallow(); commit_graft_prepared = 1; } @@@ -237,37 -234,6 +237,37 @@@ static struct commit_graft *lookup_comm return commit_graft[pos]; } +int write_shallow_commits(int fd, int use_pack_protocol) +{ + int i, count = 0; + for (i = 0; i < commit_graft_nr; i++) + if (commit_graft[i]->nr_parent < 0) { + const char *hex = + sha1_to_hex(commit_graft[i]->sha1); + count++; + if (use_pack_protocol) + packet_write(fd, "shallow %s", hex); + else { + write(fd, hex, 40); + write(fd, "\n", 1); + } + } + return count; +} + +int unregister_shallow(const unsigned char *sha1) +{ + int pos = commit_graft_pos(sha1); + if (pos < 0) + return -1; + if (pos + 1 < commit_graft_nr) + memcpy(commit_graft + pos, commit_graft + pos + 1, + sizeof(struct commit_graft *) + * (commit_graft_nr - pos - 1)); + commit_graft_nr--; + return 0; +} + int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size) { char *tail = buffer; @@@ -902,11 -868,11 +902,11 @@@ void sort_in_topological_order_fn(struc /* merge-rebase stuff */ - /* bits #0..7 in revision.h */ - #define PARENT1 (1u<< 8) - #define PARENT2 (1u<< 9) - #define STALE (1u<<10) - #define RESULT (1u<<11) + /* bits #0..15 in revision.h */ + #define PARENT1 (1u<<16) + #define PARENT2 (1u<<17) + #define STALE (1u<<18) + #define RESULT (1u<<19) static struct commit *interesting(struct commit_list *list) { @@@ -1043,3 -1009,20 +1043,20 @@@ struct commit_list *get_merge_bases(str free(rslt); return result; } + + int in_merge_bases(struct commit *rev1, struct commit *rev2) + { + struct commit_list *bases, *b; + int ret = 0; + + bases = get_merge_bases(rev1, rev2, 1); + for (b = bases; b; b = b->next) { + if (!hashcmp(rev1->object.sha1, b->item->object.sha1)) { + ret = 1; + break; + } + } + + free_commit_list(bases); + return ret; + } diff --combined commit.h index e9e158f4e1,10eea9f26f..936f8fce30 --- a/commit.h +++ b/commit.h @@@ -97,7 -97,7 +97,7 @@@ void sort_in_topological_order_fn(struc struct commit_graft { unsigned char sha1[20]; - int nr_parent; + int nr_parent; /* < 0 if shallow commit */ unsigned char parent[FLEX_ARRAY][20]; /* more */ }; @@@ -107,11 -107,5 +107,12 @@@ int read_graft_file(const char *graft_f extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup); +extern int register_shallow(const unsigned char *sha1); +extern int unregister_shallow(const unsigned char *sha1); +extern int write_shallow_commits(int fd, int use_pack_protocol); +extern int is_repository_shallow(); +extern struct commit_list *get_shallow_commits(struct object_array *heads, + int depth, int shallow_flag, int not_shallow_flag); + + int in_merge_bases(struct commit *rev1, struct commit *rev2); #endif /* COMMIT_H */ diff --combined fetch-pack.c index 80979b83be,92322cf4da..c527bf9e96 --- a/fetch-pack.c +++ b/fetch-pack.c @@@ -5,15 -5,13 +5,14 @@@ #include "tag.h" #include "exec_cmd.h" #include "sideband.h" - #include static int keep_pack; static int quiet; static int verbose; static int fetch_all; +static int depth; static const char fetch_pack_usage[] = -"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [host:]directory ..."; +"git-fetch-pack [--all] [-q] [-v] [-k] [--thin] [--exec=upload-pack] [--depth=] [host:]directory ..."; static const char *exec = "git-upload-pack"; #define COMPLETE (1U << 0) @@@ -181,41 -179,10 +180,41 @@@ static int find_common(int fd[2], unsig packet_write(fd[1], "want %s\n", sha1_to_hex(remote)); fetching++; } + if (is_repository_shallow()) + write_shallow_commits(fd[1], 1); + if (depth > 0) + packet_write(fd[1], "deepen %d", depth); packet_flush(fd[1]); if (!fetching) return 1; + if (depth > 0) { + char line[1024]; + unsigned char sha1[20]; + int len; + + while ((len = packet_read_line(fd[0], line, sizeof(line)))) { + if (!strncmp("shallow ", line, 8)) { + if (get_sha1_hex(line + 8, sha1)) + die("invalid shallow line: %s", line); + register_shallow(sha1); + continue; + } + if (!strncmp("unshallow ", line, 10)) { + if (get_sha1_hex(line + 10, sha1)) + die("invalid unshallow line: %s", line); + if (!lookup_object(sha1)) + die("object not found: %s", line); + /* make sure that it is parsed as shallow */ + parse_object(sha1); + if (unregister_shallow(sha1)) + die("no shallow found: %s", line); + continue; + } + die("expected shallow/unshallow, got %s", line); + } + } + flushes = 0; retval = -1; while ((sha1 = get_rev())) { @@@ -342,8 -309,7 +341,8 @@@ static void filter_refs(struct ref **re if (!memcmp(ref->name, "refs/", 5) && check_ref_format(ref->name + 5)) ; /* trash */ - else if (fetch_all) { + else if (fetch_all && + (!depth || strncmp(ref->name, "refs/tags/", 10) )) { *newtail = ref; ref->next = NULL; newtail = &ref->next; @@@ -402,11 -368,9 +401,11 @@@ static int everything_local(struct ref } } - for_each_ref(mark_complete, NULL); - if (cutoff) - mark_recent_complete_commits(cutoff); + if (!depth) { + for_each_ref(mark_complete, NULL); + if (cutoff) + mark_recent_complete_commits(cutoff); + } /* * Mark all complete remote refs as common refs. @@@ -558,8 -522,6 +557,8 @@@ static int fetch_pack(int fd[2], int nr int status; get_remote_heads(fd[0], &ref, 0, NULL, 0); + if (is_repository_shallow() && !server_supports("shallow")) + die("Server does not support shallow clients"); if (server_supports("multi_ack")) { if (verbose) fprintf(stderr, "Server supports multi_ack\n"); @@@ -603,14 -565,35 +602,37 @@@ return 0; } + static int remove_duplicates(int nr_heads, char **heads) + { + int src, dst; + + for (src = dst = 0; src < nr_heads; src++) { + /* If heads[src] is different from any of + * heads[0..dst], push it in. + */ + int i; + for (i = 0; i < dst; i++) { + if (!strcmp(heads[i], heads[src])) + break; + } + if (i < dst) + continue; + if (src != dst) + heads[dst] = heads[src]; + dst++; + } + heads[dst] = 0; + return dst; + } + int main(int argc, char **argv) { int i, ret, nr_heads; char *dest = NULL, **heads; int fd[2]; pid_t pid; + struct stat st; + struct lock_file lock; setup_git_directory(); @@@ -644,12 -627,6 +666,12 @@@ verbose = 1; continue; } + if (!strncmp("--depth=", arg, 8)) { + depth = strtol(arg + 8, NULL, 0); + if (stat(git_path("shallow"), &st)) + st.st_mtime = 0; + continue; + } usage(fetch_pack_usage); } dest = arg; @@@ -662,6 -639,8 +684,8 @@@ pid = git_connect(fd, dest, exec); if (pid < 0) return 1; + if (heads && nr_heads) + nr_heads = remove_duplicates(nr_heads, heads); ret = fetch_pack(fd, nr_heads, heads); close(fd[0]); close(fd[1]); @@@ -680,34 -659,5 +704,34 @@@ } } + if (!ret && depth > 0) { + struct cache_time mtime; + char *shallow = git_path("shallow"); + int fd; + + mtime.sec = st.st_mtime; +#ifdef USE_NSEC + mtime.usec = st.st_mtim.usec; +#endif + if (stat(shallow, &st)) { + if (mtime.sec) + die("shallow file was removed during fetch"); + } else if (st.st_mtime != mtime.sec +#ifdef USE_NSEC + || st.st_mtim.usec != mtime.usec +#endif + ) + die("shallow file was changed during fetch"); + + fd = hold_lock_file_for_update(&lock, shallow, 1); + if (!write_shallow_commits(fd, 0)) { + unlink(shallow); + rollback_lock_file(&lock); + } else { + close(fd); + commit_lock_file(&lock); + } + } + return !!ret; } diff --combined git-clone.sh index 8c0a93ebd1,490f3e48db..f37eb9d105 --- a/git-clone.sh +++ b/git-clone.sh @@@ -14,7 -14,7 +14,7 @@@ die() } usage() { - die "Usage: $0 [--template=] [--use-immingled-remote] [--reference ] [--bare] [-l [-s]] [-q] [-u ] [--origin ] [--depth ] [-n] []" - die "Usage: $0 [--template=] [--reference ] [--bare] [-l [-s]] [-q] [-u ] [--origin ] [-n] []" ++ die "Usage: $0 [--template=] [--reference ] [--bare] [-l [-s]] [-q] [-u ] [--origin ] [--depth ] [-n] []" } get_repo_base() { @@@ -48,6 -48,10 +48,10 @@@ Perhaps git-update-server-info needs t case "$name" in *^*) continue;; esac + case "$bare,$name" in + yes,* | ,heads/* | ,tags/*) ;; + *) continue ;; + esac if test -n "$use_separate_remote" && branch_name=`expr "z$name" : 'zheads/\(.*\)'` then @@@ -116,7 -120,6 +120,7 @@@ reference origin= origin_override= use_separate_remote=t +depth= while case "$#,$1" in 0,*) break ;; @@@ -134,11 -137,9 +138,9 @@@ *,--template=*) template="$1" ;; *,-q|*,--quiet) quiet=-q ;; - *,--use-separate-remote) - # default - use_separate_remote=t ;; - *,--use-immingled-remote) - use_separate_remote= ;; + *,--use-separate-remote) ;; + *,--no-separate-remote) + die "clones are always made with separate-remote layout" ;; 1,--reference) usage ;; *,--reference) shift; reference="$1" ;; @@@ -162,10 -163,6 +164,10 @@@ *,-u|*,--upload-pack) shift upload_pack="--exec=$1" ;; + 1,--depth) usage;; + *,--depth) + shift + depth="--depth=$1";; *,-*) usage ;; *) break ;; esac @@@ -177,7 -174,7 +179,7 @@@ repo="$1 test -n "$repo" || die 'you must specify a repository to clone.' - # --bare implies --no-checkout and --use-immingled-remote + # --bare implies --no-checkout and --no-separate-remote if test yes = "$bare" then if test yes = "$origin_override" @@@ -270,10 -267,6 +272,10 @@@ yes,yes *) case "$repo" in rsync://*) + case "$depth" in + "") ;; + *) die "shallow over rsync not supported" ;; + esac rsync $quiet -av --ignore-existing \ --exclude info "$repo/objects/" "$GIT_DIR/objects/" || exit @@@ -302,10 -295,6 +304,10 @@@ git-ls-remote "$repo" >"$GIT_DIR/CLONE_HEAD" || exit 1 ;; https://*|http://*|ftp://*) + case "$depth" in + "") ;; + *) die "shallow over http or ftp not supported" ;; + esac if test -z "@@NO_CURL@@" then clone_dumb_http "$repo" "$D" @@@ -315,8 -304,8 +317,8 @@@ ;; *) case "$upload_pack" in - '') git-fetch-pack --all -k $quiet "$repo" ;; - *) git-fetch-pack --all -k $quiet "$upload_pack" "$repo" ;; + '') git-fetch-pack --all -k $quiet $depth "$repo" ;; + *) git-fetch-pack --all -k $quiet "$upload_pack" $depth "$repo" ;; esac >"$GIT_DIR/CLONE_HEAD" || die "fetch-pack from '$repo' failed." ;; @@@ -336,12 -325,8 +338,8 @@@ cd "$D" || exi if test -z "$bare" && test -f "$GIT_DIR/REMOTE_HEAD" then - # Figure out which remote branch HEAD points at. - case "$use_separate_remote" in - '') remote_top=refs/heads ;; - *) remote_top="refs/remotes/$origin" ;; - esac - + # a non-bare repository is always in separate-remote layout + remote_top="refs/remotes/$origin" head_sha1=`cat "$GIT_DIR/REMOTE_HEAD"` case "$head_sha1" in 'ref: refs/'*) @@@ -375,41 -360,28 +373,28 @@@ ) ) - # Write out remotes/$origin file, and update our "$head_points_at". + # Write out remote.$origin config, and update our "$head_points_at". case "$head_points_at" in ?*) - mkdir -p "$GIT_DIR/remotes" && + # Local default branch git-symbolic-ref HEAD "refs/heads/$head_points_at" && - case "$use_separate_remote" in - t) origin_track="$remote_top/$head_points_at" - git-update-ref HEAD "$head_sha1" ;; - *) origin_track="$remote_top/$origin" - git-update-ref "refs/heads/$origin" "$head_sha1" ;; - esac && - echo >"$GIT_DIR/remotes/$origin" \ - "URL: $repo - Pull: refs/heads/$head_points_at:$origin_track" && - (cd "$GIT_DIR/$remote_top" && find . -type f -print) | - while read dotslref - do - name=`expr "$dotslref" : './\(.*\)'` - if test "z$head_points_at" = "z$name" - then - continue - fi - if test "$use_separate_remote" = '' && - test "z$origin" = "z$name" - then - continue - fi - echo "Pull: refs/heads/${name}:$remote_top/${name}" - done >>"$GIT_DIR/remotes/$origin" && - case "$use_separate_remote" in - t) - rm -f "refs/remotes/$origin/HEAD" - git-symbolic-ref "refs/remotes/$origin/HEAD" \ - "refs/remotes/$origin/$head_points_at" - esac + + # Tracking branch for the primary branch at the remote. + origin_track="$remote_top/$head_points_at" && + git-update-ref HEAD "$head_sha1" && + + # Upstream URL + git-repo-config remote."$origin".url "$repo" && + + # Set up the mappings to track the remote branches. + git-repo-config remote."$origin".fetch \ + "refs/heads/*:$remote_top/*" '^$' && + rm -f "refs/remotes/$origin/HEAD" + git-symbolic-ref "refs/remotes/$origin/HEAD" \ + "refs/remotes/$origin/$head_points_at" && + + git-repo-config branch."$head_points_at".remote "$origin" && + git-repo-config branch."$head_points_at".merge "refs/heads/$head_points_at" esac case "$no_checkout" in diff --combined git-fetch.sh index f0645d97c9,ffbd44f0e1..5f316053fb --- a/git-fetch.sh +++ b/git-fetch.sh @@@ -2,7 -2,13 +2,13 @@@ # USAGE=' ...' + SUBDIRECTORY_OK=Yes . git-sh-setup + TOP=$(git-rev-parse --show-cdup) + if test ! -z "$TOP" + then + cd "$TOP" + fi . git-parse-remote _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]' _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" @@@ -21,7 -27,6 +27,7 @@@ update_head_ok exec= upload_pack= keep= +shallow_depth= while case "$#" in 0) break ;; esac do case "$1" in @@@ -57,13 -62,6 +63,13 @@@ --reflog-action=*) rloga=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;; + --depth=*) + shallow_depth="--depth=`expr "z$1" : 'z-[^=]*=\(.*\)'`" + ;; + --depth) + shift + shallow_depth="--depth=$1" + ;; -*) usage ;; @@@ -96,6 -94,10 +102,10 @@@ the : >"$GIT_DIR/FETCH_HEAD" fi + # Global that is reused later + ls_remote_result=$(git ls-remote $upload_pack "$remote") || + die "Cannot get the repository state from $remote" + append_fetch_head () { head_="$1" remote_="$2" @@@ -240,11 -242,8 +250,8 @@@ esa reflist=$(get_remote_refs_for_fetch "$@") if test "$tags" then - taglist=`IFS=" " && - ( - git-ls-remote $upload_pack --tags "$remote" || - echo fail ouch - ) | + taglist=`IFS=' ' && + echo "$ls_remote_result" | while read sha1 name do case "$sha1" in @@@ -253,6 -252,8 +260,8 @@@ esac case "$name" in *^*) continue ;; + refs/tags/*) ;; + *) continue ;; esac if git-check-ref-format "$name" then @@@ -304,8 -305,6 +313,8 @@@ fetch_main () # There are transports that can fetch only one head at a time... case "$remote" in http://* | https://* | ftp://*) + test -n "$shallow_depth" && + die "shallow clone with http not supported" proto=`expr "$remote" : '\([^:]*\):'` if [ -n "$GIT_SSL_NO_VERIFY" ]; then curl_extra_args="-k" @@@ -314,28 -313,24 +323,26 @@@ "`git-repo-config --bool http.noEPSV`" = true ]; then noepsv_opt="--disable-epsv" fi - max_depth=5 - depth=0 - head="ref: $remote_name" - while (expr "z$head" : "zref:" && expr $depth \< $max_depth) >/dev/null - do - remote_name_quoted=$(@@PERL@@ -e ' - my $u = $ARGV[0]; - $u =~ s/^ref:\s*//; - $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg; - print "$u"; - ' "$head") - head=$(curl -nsfL $curl_extra_args $noepsv_opt "$remote/$remote_name_quoted") - depth=$( expr \( $depth + 1 \) ) - done + + # Find $remote_name from ls-remote output. + head=$( + IFS=' ' + echo "$ls_remote_result" | + while read sha1 name + do + test "z$name" = "z$remote_name" || continue + echo "$sha1" + break + done + ) expr "z$head" : "z$_x40\$" >/dev/null || - die "Failed to fetch $remote_name from $remote" + die "No such ref $remote_name at $remote" echo >&2 "Fetching $remote_name from $remote using $proto" git-http-fetch -v -a "$head" "$remote/" || exit ;; rsync://*) + test -n "$shallow_depth" && + die "shallow clone with rsync not supported" TMP_HEAD="$GIT_DIR/TMP_HEAD" rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1 head=$(git-rev-parse --verify TMP_HEAD) @@@ -371,7 -366,7 +378,7 @@@ esac append_fetch_head "$head" "$remote" \ - "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" + "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" || exit done @@@ -383,7 -378,7 +390,7 @@@ pack_lockfile= IFS=" $LF" ( - git-fetch-pack --thin $exec $keep "$remote" $rref || echo failed "$remote" + git-fetch-pack --thin $exec $keep $shallow_depth "$remote" $rref || echo failed "$remote" ) | while read sha1 remote_name do @@@ -425,15 -420,16 +432,16 @@@ done local_name=$(expr "z$found" : 'z[^:]*:\(.*\)') append_fetch_head "$sha1" "$remote" \ - "$remote_name" "$remote_nick" "$local_name" "$not_for_merge" - done + "$remote_name" "$remote_nick" "$local_name" \ + "$not_for_merge" || exit + done && if [ "$pack_lockfile" ]; then rm -f "$pack_lockfile"; fi ) || exit ;; esac } - fetch_main "$reflist" + fetch_main "$reflist" || exit # automated tag following case "$no_tags$tags" in @@@ -442,17 -438,11 +450,11 @@@ *:refs/*) # effective only when we are following remote branch # using local tracking branch. - taglist=$(IFS=" " && - git-ls-remote $upload_pack --tags "$remote" | - sed -n -e 's|^\('"$_x40"'\) \(refs/tags/.*\)^{}$|\1 \2|p' \ - -e 's|^\('"$_x40"'\) \(refs/tags/.*\)$|\1 \2|p' | + taglist=$(IFS=' ' && + echo "$ls_remote_result" | + git-show-ref --exclude-existing=refs/tags/ | while read sha1 name do - git-show-ref --verify --quiet -- "$name" && continue - git-check-ref-format "$name" || { - echo >&2 "warning: tag ${name} ignored" - continue - } git-cat-file -t "$sha1" >/dev/null 2>&1 || continue echo >&2 "Auto-following $name" echo ".${name}:${name}" @@@ -461,9 -451,7 +463,9 @@@ case "$taglist" in '') ;; ?*) + # do not deepen a shallow tree when following tags + shallow_depth= - fetch_main "$taglist" ;; + fetch_main "$taglist" || exit ;; esac esac diff --combined t/t5500-fetch-pack.sh index fa10840303,f7625a6f46..77c3c575d8 --- a/t/t5500-fetch-pack.sh +++ b/t/t5500-fetch-pack.sh @@@ -128,49 -128,4 +128,54 @@@ pull_to_client 2nd "B" $((64*3) pull_to_client 3rd "A" $((1*3)) # old fails +test_expect_success "clone shallow" "git-clone --depth 2 . shallow" + +(cd shallow; git-count-objects -v) > count.shallow + +test_expect_success "clone shallow object count" \ + "test \"in-pack: 18\" = \"$(grep in-pack count.shallow)\"" + - test_expect_success "clone shallow object count (part 2)" \ - "test -z \"$(grep -v in-pack count.shallow | sed "s/^.*: 0//")\"" ++count_output () { ++ sed -e '/^in-pack:/d' -e '/^packs:/d' -e '/: 0$/d' "$1" ++} ++ ++test_expect_success "clone shallow object count (part 2)" ' ++ test -z "$(count_output count.shallow)" ++' + +test_expect_success "fsck in shallow repo" \ + "(cd shallow; git-fsck-objects --full)" + +#test_done; exit + +add B66 $B65 +add B67 $B66 + +test_expect_success "pull in shallow repo" \ + "(cd shallow; git pull .. B)" + +(cd shallow; git-count-objects -v) > count.shallow +test_expect_success "clone shallow object count" \ + "test \"count: 6\" = \"$(grep count count.shallow)\"" + +add B68 $B67 +add B69 $B68 + +test_expect_success "deepening pull in shallow repo" \ + "(cd shallow; git pull --depth 4 .. B)" + +(cd shallow; git-count-objects -v) > count.shallow +test_expect_success "clone shallow object count" \ + "test \"count: 12\" = \"$(grep count count.shallow)\"" + +test_expect_success "deepening fetch in shallow repo" \ + "(cd shallow; git fetch --depth 4 .. A:A)" + +(cd shallow; git-count-objects -v) > count.shallow +test_expect_success "clone shallow object count" \ + "test \"count: 18\" = \"$(grep count count.shallow)\"" + +test_expect_failure "pull in shallow repo with missing merge base" \ + "(cd shallow; git pull --depth 4 .. A)" + test_done diff --combined upload-pack.c index d4a7b625f4,32b06b2e66..c568ef066c --- a/upload-pack.c +++ b/upload-pack.c @@@ -1,6 -1,3 +1,3 @@@ - #include - #include - #include #include "cache.h" #include "refs.h" #include "pkt-line.h" @@@ -9,9 -6,6 +6,9 @@@ #include "object.h" #include "commit.h" #include "exec_cmd.h" +#include "diff.h" +#include "revision.h" +#include "list-objects.h" static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] "; @@@ -22,10 -16,6 +19,10 @@@ #define COMMON_KNOWN (1u << 14) #define REACHABLE (1u << 15) +#define SHALLOW (1u << 16) +#define NOT_SHALLOW (1u << 17) +#define CLIENT_SHALLOW (1u << 18) + static unsigned long oldest_have; static int multi_ack, nr_our_refs; @@@ -64,40 -54,6 +61,40 @@@ static ssize_t send_client_data(int fd return safe_write(fd, data, sz); } +FILE *pack_pipe = NULL; +static void show_commit(struct commit *commit) +{ + if (commit->object.flags & BOUNDARY) + fputc('-', pack_pipe); + if (fputs(sha1_to_hex(commit->object.sha1), pack_pipe) < 0) + die("broken output pipe"); + fputc('\n', pack_pipe); + fflush(pack_pipe); + free(commit->buffer); + commit->buffer = NULL; +} + +static void show_object(struct object_array_entry *p) +{ + /* An object with name "foo\n0000000..." can be used to + * confuse downstream git-pack-objects very badly. + */ + const char *ep = strchr(p->name, '\n'); + if (ep) { + fprintf(pack_pipe, "%s %.*s\n", sha1_to_hex(p->item->sha1), + (int) (ep - p->name), + p->name); + } + else + fprintf(pack_pipe, "%s %s\n", + sha1_to_hex(p->item->sha1), p->name); +} + +static void show_edge(struct commit *commit) +{ + fprintf(pack_pipe, "-%s\n", sha1_to_hex(commit->object.sha1)); +} + static void create_pack_file(void) { /* Pipes between rev-list to pack-objects, pack-objects to us @@@ -119,40 -75,48 +116,40 @@@ if (!pid_rev_list) { int i; - int args; - const char **argv; - const char **p; - char *buf; + struct rev_info revs; - if (create_full_pack) { - args = 10; - use_thin_pack = 0; /* no point doing it */ - } - else - args = have_obj.nr + want_obj.nr + 5; - p = xmalloc(args * sizeof(char *)); - argv = (const char **) p; - buf = xmalloc(args * 45); + pack_pipe = fdopen(lp_pipe[1], "w"); - dup2(lp_pipe[1], 1); - close(0); - close(lp_pipe[0]); - close(lp_pipe[1]); - *p++ = "rev-list"; - *p++ = use_thin_pack ? "--objects-edge" : "--objects"; if (create_full_pack) - *p++ = "--all"; - else { + use_thin_pack = 0; /* no point doing it */ + init_revisions(&revs, NULL); + revs.tag_objects = 1; + revs.tree_objects = 1; + revs.blob_objects = 1; + if (use_thin_pack) + revs.edge_hint = 1; + + if (create_full_pack) { + const char *args[] = {"rev-list", "--all", NULL}; + setup_revisions(2, args, &revs, NULL); + } else { for (i = 0; i < want_obj.nr; i++) { struct object *o = want_obj.objects[i].item; - *p++ = buf; - memcpy(buf, sha1_to_hex(o->sha1), 41); - buf += 41; + /* why??? */ + o->flags &= ~UNINTERESTING; + add_pending_object(&revs, o, NULL); } - } - if (!create_full_pack) for (i = 0; i < have_obj.nr; i++) { struct object *o = have_obj.objects[i].item; - *p++ = buf; - *buf++ = '^'; - memcpy(buf, sha1_to_hex(o->sha1), 41); - buf += 41; + o->flags |= UNINTERESTING; + add_pending_object(&revs, o, NULL); } - *p++ = NULL; - execv_git_cmd(argv); - die("git-upload-pack: unable to exec git-rev-list"); + setup_revisions(0, NULL, &revs, NULL); + } + prepare_revision_walk(&revs); + mark_edges_uninteresting(revs.commits, &revs, show_edge); + traverse_commit_list(&revs, show_commit, show_object); + exit(0); } if (pipe(pu_pipe) < 0) @@@ -492,9 -456,8 +489,9 @@@ static int get_common_commits(void static void receive_needs(void) { + struct object_array shallows = {0, 0, NULL}; static char line[1000]; - int len; + int len, depth = 0; for (;;) { struct object *o; @@@ -502,29 -465,8 +499,29 @@@ len = packet_read_line(0, line, sizeof(line)); reset_timeout(); if (!len) - return; + break; + if (!strncmp("shallow ", line, 8)) { + unsigned char sha1[20]; + struct object *object; + use_thin_pack = 0; + if (get_sha1(line + 8, sha1)) + die("invalid shallow line: %s", line); + object = parse_object(sha1); + if (!object) + die("did not find object for %s", line); + object->flags |= CLIENT_SHALLOW; + add_object_array(object, NULL, &shallows); + continue; + } + if (!strncmp("deepen ", line, 7)) { + char *end; + use_thin_pack = 0; + depth = strtol(line + 7, &end, 0); + if (end == line + 7 || depth <= 0) + die("Invalid deepen: %s", line); + continue; + } if (strncmp("want ", line, 5) || get_sha1_hex(line+5, sha1_buf)) die("git-upload-pack: protocol error, " @@@ -556,58 -498,11 +553,58 @@@ add_object_array(o, NULL, &want_obj); } } + if (depth == 0 && shallows.nr == 0) + return; + if (depth > 0) { + struct commit_list *result, *backup; + int i; + backup = result = get_shallow_commits(&want_obj, depth, + SHALLOW, NOT_SHALLOW); + while (result) { + struct object *object = &result->item->object; + if (!(object->flags & (CLIENT_SHALLOW|NOT_SHALLOW))) { + packet_write(1, "shallow %s", + sha1_to_hex(object->sha1)); + register_shallow(object->sha1); + } + result = result->next; + } + free_commit_list(backup); + for (i = 0; i < shallows.nr; i++) { + struct object *object = shallows.objects[i].item; + if (object->flags & NOT_SHALLOW) { + struct commit_list *parents; + packet_write(1, "unshallow %s", + sha1_to_hex(object->sha1)); + object->flags &= ~CLIENT_SHALLOW; + /* make sure the real parents are parsed */ + unregister_shallow(object->sha1); + object->parsed = 0; + parse_commit((struct commit *)object); + parents = ((struct commit *)object)->parents; + while (parents) { + add_object_array(&parents->item->object, + NULL, &want_obj); + parents = parents->next; + } + } + /* make sure commit traversal conforms to client */ + register_shallow(object->sha1); + } + packet_flush(1); + } else + if (shallows.nr > 0) { + int i; + for (i = 0; i < shallows.nr; i++) + register_shallow(shallows.objects[i].item->sha1); + } + free(shallows.objects); } static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data) { - static const char *capabilities = "multi_ack thin-pack side-band side-band-64k ofs-delta"; + static const char *capabilities = "multi_ack thin-pack side-band" + " side-band-64k ofs-delta shallow"; struct object *o = parse_object(sha1); if (!o)