From 1b76ead0044c865cc005ea2d8d2aeec526632810 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Thu, 17 Jul 2008 19:01:30 +0200 Subject: [PATCH 01/24] Documentation/RelNotes-1.6.0.txt: Expand on the incompatible packfiles Note that v1.4.4.5 supports pack index v2, and describe how to keep your repositories backwards-compatible, shall you need to. Signed-off-by: Petr Baudis Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.6.0.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/RelNotes-1.6.0.txt b/Documentation/RelNotes-1.6.0.txt index b29ba25229..9bbb07ef9b 100644 --- a/Documentation/RelNotes-1.6.0.txt +++ b/Documentation/RelNotes-1.6.0.txt @@ -21,7 +21,9 @@ main git.git codebase. By default, packfiles created with this version uses delta-base-offset encoding introduced in v1.4.4. Pack idx files are using version 2 that allows larger packs and added robustness thanks to its CRC checking, -introduced in v1.5.2. +introduced in v1.5.2 and v1.4.4.5. If you want to keep your repositories +backwards compatible past these versions, set repack.useDeltaBaseOffset +to false or pack.indexVersion to 1, respectively. GIT_CONFIG, which was only documented as affecting "git config", but actually affected all git commands, now only affects "git config". From 6c69207c73aaf63c13105d526453d0bd75f12f34 Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Fri, 18 Jul 2008 01:53:55 +0200 Subject: [PATCH 02/24] api-run-command.txt: typofix Replace "run_command_v_opt_dir" by "run_command_v_opt_cd". Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- Documentation/technical/api-run-command.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/technical/api-run-command.txt b/Documentation/technical/api-run-command.txt index 3e1342acf4..75aa5d4923 100644 --- a/Documentation/technical/api-run-command.txt +++ b/Documentation/technical/api-run-command.txt @@ -30,7 +30,7 @@ Functions start_command() followed by finish_command(). Takes a pointer to a `struct child_process` that specifies the details. -`run_command_v_opt`, `run_command_v_opt_dir`, `run_command_v_opt_cd_env`:: +`run_command_v_opt`, `run_command_v_opt_cd`, `run_command_v_opt_cd_env`:: Convenience functions that encapsulate a sequence of start_command() followed by finish_command(). The argument argv From 72972eb3749daecf328badbc1c1952cb513f34f9 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 17 Jul 2008 21:30:33 -0700 Subject: [PATCH 03/24] builtin-remote.c: fix earlier "skip_prefix()" conversion The original code relied on an insane definition of skip_prefix() that returned an empty string for a NULL input and returned the original if the given "prefix" is not a prefix at all (it would have been justifiable if it were called "come_up_with_a_short_name_to_report_ref()" or something, though). In any case, when we replaced it with a more saner definition of the function whose behaviour is true to its name, its callers needed to be adjusted but the conversion missed one call site. This introduces a helper function "abbrev_ref()" whose purpose is to get a full refname and its possible prefix and to strip the prefix part if it matches, or refname itself in full if it doesn't. This makes the callers easier to read again. Signed-off-by: Junio C Hamano --- builtin-remote.c | 51 ++++++++++++++++++------------------------------ 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/builtin-remote.c b/builtin-remote.c index 1491354a9d..db12668cfe 100644 --- a/builtin-remote.c +++ b/builtin-remote.c @@ -147,6 +147,15 @@ struct branch_info { static struct path_list branch_list; +static const char *abbrev_ref(const char *name, const char *prefix) +{ + const char *abbrev = skip_prefix(name, prefix); + if (abbrev) + return abbrev; + return name; +} +#define abbrev_branch(name) abbrev_ref((name), "refs/heads/") + static int config_read_branches(const char *key, const char *value, void *cb) { if (!prefixcmp(key, "branch.")) { @@ -176,18 +185,12 @@ static int config_read_branches(const char *key, const char *value, void *cb) info->remote = xstrdup(value); } else { char *space = strchr(value, ' '); - const char *ptr = skip_prefix(value, "refs/heads/"); - if (ptr) - value = ptr; + value = abbrev_branch(value); while (space) { char *merge; merge = xstrndup(value, space - value); path_list_append(merge, &info->merge); - ptr = skip_prefix(space + 1, "refs/heads/"); - if (ptr) - value = ptr; - else - value = space + 1; + value = abbrev_branch(space + 1); space = strchr(value, ' '); } path_list_append(xstrdup(value), &info->merge); @@ -219,12 +222,7 @@ static int handle_one_branch(const char *refname, refspec.dst = (char *)refname; if (!remote_find_tracking(states->remote, &refspec)) { struct path_list_item *item; - const char *name, *ptr; - ptr = skip_prefix(refspec.src, "refs/heads/"); - if (ptr) - name = ptr; - else - name = refspec.src; + const char *name = abbrev_branch(refspec.src); /* symbolic refs pointing nowhere were handled already */ if ((flags & REF_ISSYMREF) || unsorted_path_list_has_path(&states->tracked, @@ -253,7 +251,6 @@ static int get_ref_states(const struct ref *ref, struct ref_states *states) struct path_list *target = &states->tracked; unsigned char sha1[20]; void *util = NULL; - const char *ptr; if (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1)) target = &states->new; @@ -262,10 +259,7 @@ static int get_ref_states(const struct ref *ref, struct ref_states *states) if (hashcmp(sha1, ref->new_sha1)) util = &states; } - ptr = skip_prefix(ref->name, "refs/heads/"); - if (!ptr) - ptr = ref->name; - path_list_append(ptr, target)->util = util; + path_list_append(abbrev_branch(ref->name), target)->util = util; } free_refs(fetch_map); @@ -460,10 +454,8 @@ static int append_ref_to_tracked_list(const char *refname, memset(&refspec, 0, sizeof(refspec)); refspec.dst = (char *)refname; - if (!remote_find_tracking(states->remote, &refspec)) { - path_list_append(skip_prefix(refspec.src, "refs/heads/"), - &states->tracked); - } + if (!remote_find_tracking(states->remote, &refspec)) + path_list_append(abbrev_branch(refspec.src), &states->tracked); return 0; } @@ -530,15 +522,10 @@ static int show(int argc, const char **argv) "es" : ""); for (i = 0; i < states.remote->push_refspec_nr; i++) { struct refspec *spec = states.remote->push + i; - const char *p = "", *q = ""; - if (spec->src) - p = skip_prefix(spec->src, "refs/heads/"); - if (spec->dst) - q = skip_prefix(spec->dst, "refs/heads/"); printf(" %s%s%s%s", spec->force ? "+" : "", - p ? p : spec->src, - spec->dst ? ":" : "", - q ? q : spec->dst); + abbrev_branch(spec->src), + spec->dst ? ":" : "", + spec->dst ? abbrev_branch(spec->dst) : ""); } printf("\n"); } @@ -588,7 +575,7 @@ static int prune(int argc, const char **argv) result |= delete_ref(refname, NULL); printf(" * [%s] %s\n", dry_run ? "would prune" : "pruned", - skip_prefix(refname, "refs/remotes/")); + abbrev_ref(refname, "refs/remotes/")); } /* NEEDSWORK: free remote */ From d85fe389594dc1b6f64c0aae7146a6d92399c3a9 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 17 Jul 2008 22:39:09 -0700 Subject: [PATCH 04/24] rev-list: honor --quiet option Nick Andrew noticed that rev-list lets --quiet option to be parsed by underlying diff_options parser but did not pick up the result. This resulted in --quiet option to become effectively a no-op. Signed-off-by: Junio C Hamano --- builtin-rev-list.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/builtin-rev-list.c b/builtin-rev-list.c index 83a7b1349e..39ec61c428 100644 --- a/builtin-rev-list.c +++ b/builtin-rev-list.c @@ -597,6 +597,7 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) revs.commit_format = CMIT_FMT_UNSPECIFIED; argc = setup_revisions(argc, argv, &revs, NULL); + quiet = DIFF_OPT_TST(&revs.diffopt, QUIET); for (i = 1 ; i < argc; i++) { const char *arg = argv[i]; @@ -628,10 +629,6 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) read_revisions_from_stdin(&revs); continue; } - if (!strcmp(arg, "--quiet")) { - quiet = 1; - continue; - } usage(rev_list_usage); } From a70c232e0fcb1a72cec024def0f8b1377f15daf4 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 18 Jul 2008 00:11:40 -0700 Subject: [PATCH 05/24] http-fetch: do not SEGV after fetching a bad pack idx file Signed-off-by: Junio C Hamano --- http-walker.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/http-walker.c b/http-walker.c index 99f397e32b..74033060c4 100644 --- a/http-walker.c +++ b/http-walker.c @@ -442,6 +442,8 @@ static int setup_index(struct walker *walker, struct alt_base *repo, unsigned ch return -1; new_pack = parse_pack_index(sha1); + if (!new_pack) + return -1; /* parse_pack_index() already issued error message */ new_pack->next = repo->packs; repo->packs = new_pack; return 0; From 4d2646727997c82c04a82ce38e56d76e7b5d268b Mon Sep 17 00:00:00 2001 From: Olivier Marin Date: Sat, 19 Jul 2008 18:24:46 +0200 Subject: [PATCH 06/24] builtin-rm: fix index lock file path When hold_locked_index() is called with a relative git_dir and you are outside the work tree, the lock file become relative to the current directory. So when later setup_work_tree() change the current directory it breaks lock file path and commit_locked_index() fails. This patch move index locking code after setup_work_tree() call to make lock file relative to the working tree as it should be and add a test case. Noticed by Nick Andrew. Signed-off-by: Olivier Marin Signed-off-by: Junio C Hamano --- builtin-rm.c | 10 +++++----- t/t3600-rm.sh | 12 ++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/builtin-rm.c b/builtin-rm.c index 22c9bd1c6c..abdab7f001 100644 --- a/builtin-rm.c +++ b/builtin-rm.c @@ -146,11 +146,6 @@ int cmd_rm(int argc, const char **argv, const char *prefix) git_config(git_default_config, NULL); - newfd = hold_locked_index(&lock_file, 1); - - if (read_cache() < 0) - die("index file corrupt"); - argc = parse_options(argc, argv, builtin_rm_options, builtin_rm_usage, 0); if (!argc) usage_with_options(builtin_rm_usage, builtin_rm_options); @@ -158,6 +153,11 @@ int cmd_rm(int argc, const char **argv, const char *prefix) if (!index_only) setup_work_tree(); + newfd = hold_locked_index(&lock_file, 1); + + if (read_cache() < 0) + die("index file corrupt"); + pathspec = get_pathspec(prefix, argv); seen = NULL; for (i = 0; pathspec[i] ; i++) diff --git a/t/t3600-rm.sh b/t/t3600-rm.sh index f542f0af41..7893d8c40e 100755 --- a/t/t3600-rm.sh +++ b/t/t3600-rm.sh @@ -217,4 +217,16 @@ test_expect_success 'Remove nonexistent file returns nonzero exit status' ' ! git rm nonexistent ' +test_expect_success 'Call "rm" from outside the work tree' ' + mkdir repo && + cd repo && + git init && + echo something > somefile && + git add somefile && + git commit -m "add a file" && + (cd .. && + git --git-dir=repo/.git --work-tree=repo rm somefile) && + test_must_fail git ls-files --error-unmatch somefile +' + test_done From a1b6fb04b1c1b581dfac5c13641af8b3ae44810f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 19 Jul 2008 10:58:01 -0700 Subject: [PATCH 07/24] GIT 1.5.6.4 Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.5.6.4.txt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Documentation/RelNotes-1.5.6.4.txt b/Documentation/RelNotes-1.5.6.4.txt index 130418864e..d8968f1ecb 100644 --- a/Documentation/RelNotes-1.5.6.4.txt +++ b/Documentation/RelNotes-1.5.6.4.txt @@ -28,16 +28,20 @@ Fixes since v1.5.6.3 be huge by saying "no common commits", but this was an unnecessary noise; it is already known by the user anyway. +* "git-http-fetch" would have segfaulted when pack idx file retrieved + from the other side was corrupt. + +* "git-index-pack" used too much memory when dealing with a deep delta chain. + * "git-mailinfo" (hence "git-am") did not correctly handle in-body [PATCH] line to override the commit title taken from the mail Subject header. * "git-rebase -i -p" lost parents that are not involved in the history being rewritten. -Contains other various documentation fixes. +* "git-rm" lost track of where the index file was when GIT_DIR was + specified as a relative path. --- -exec >/var/tmp/1 -echo O=$(git describe maint) -O=v1.5.6.3-21-gebcce31 -git shortlog --no-merges $O..maint +* "git-rev-list --quiet" was not quiet as advertised. + +Contains other various documentation fixes. From bb3e4f03be815067814624b1e0b2f6de054519cd Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 17 Jul 2008 23:18:43 -0700 Subject: [PATCH 08/24] t9001 (send-email): Do not use hardcoded /bin/sh in test Scriptlets used form inside this test began with hardcoded "#!/bin/sh". By setting SHELL_PATH the user is already telling us that what the vendor has in /bin/sh isn't POSIX enough, and we really should try to honor that request. Originally noticed by SungHyun Nam who later tested this patch and verified that it fixes the issue on Solaris 9. Signed-off-by: Junio C Hamano --- t/t9001-send-email.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index de5b9802c9..1c857cf4ab 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -13,7 +13,7 @@ test_expect_success \ test_expect_success \ 'Setup helper tool' \ - '(echo "#!/bin/sh" + '(echo "#!$SHELL_PATH" echo shift echo output=1 echo "while test -f commandline\$output; do output=\$((\$output+1)); done" @@ -138,7 +138,7 @@ test_expect_success 'Valid In-Reply-To when prompting' ' ' test_expect_success 'setup fake editor' ' - (echo "#!/bin/sh" && + (echo "#!$SHELL_PATH" && echo "echo fake edit >>\"\$1\"" ) >fake-editor && chmod +x fake-editor @@ -235,7 +235,7 @@ test_expect_success 'sendemail.cc unset' ' test_expect_success '--compose adds MIME for utf8 body' ' clean_fake_sendmail && - (echo "#!/bin/sh" && + (echo "#!$SHELL_PATH" && echo "echo utf8 body: àéìöú >>\"\$1\"" ) >fake-editor-utf8 && chmod +x fake-editor-utf8 && @@ -254,7 +254,7 @@ test_expect_success '--compose adds MIME for utf8 body' ' test_expect_success '--compose respects user mime type' ' clean_fake_sendmail && - (echo "#!/bin/sh" && + (echo "#!$SHELL_PATH" && echo "(echo MIME-Version: 1.0" echo " echo Content-Type: text/plain\\; charset=iso-8859-1" echo " echo Content-Transfer-Encoding: 8bit" From 78568448239ea09c8a78b72741863be1148c4660 Mon Sep 17 00:00:00 2001 From: Stephan Beyer Date: Fri, 18 Jul 2008 03:04:30 +0200 Subject: [PATCH 09/24] Link git-shell only to a subset of libgit.a Commit 5b8e6f85 introduced stubs for three functions that make no sense for git-shell. But those stubs defined libgit.a functions a second time so that a linker can complain. Now git-shell is only linked to a subset of libgit.a. Signed-off-by: Stephan Beyer Signed-off-by: Junio C Hamano --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 75c4ead47a..c01345e784 100644 --- a/Makefile +++ b/Makefile @@ -1203,6 +1203,9 @@ git-http-push$X: revision.o http.o http-push.o $(GITLIBS) $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \ $(LIBS) $(CURL_LIBCURL) $(EXPAT_LIBEXPAT) +git-shell$X: compat/strlcpy.o abspath.o ctype.o exec_cmd.o quote.o strbuf.o usage.o wrapper.o shell.o + $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) + $(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H) $(patsubst git-%$X,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h) builtin-revert.o wt-status.o: wt-status.h From 374488f31d70e6f009abf533a1c0a8077301f18d Mon Sep 17 00:00:00 2001 From: Fabian Emmes Date: Thu, 17 Jul 2008 19:00:26 +0200 Subject: [PATCH 10/24] Testsuite: Unset CVS_SERVER The CVS_SERVER environment variable can cause some of the cvsimport tests to fail. So unset this variable at the beginning of the test script. Signed-off-by: Fabian Emmes Signed-off-by: Lars Noschinski Signed-off-by: Junio C Hamano --- t/t9600-cvsimport.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh index 1e01e5c748..0d7786a8c7 100755 --- a/t/t9600-cvsimport.sh +++ b/t/t9600-cvsimport.sh @@ -5,6 +5,7 @@ test_description='git-cvsimport basic tests' CVSROOT=$(pwd)/cvsroot export CVSROOT +unset CVS_SERVER # for clean cvsps cache HOME=$(pwd) export HOME From b20171ebf7df3c31cce5cde3efaaf257b4ac2447 Mon Sep 17 00:00:00 2001 From: Lars Noschinski Date: Thu, 17 Jul 2008 19:00:27 +0200 Subject: [PATCH 11/24] cvsserver: Add support for packed refs req_update still parses /refs/heads manually. Replace this by a call to show-ref. Signed-off-by: Lars Noschinski Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index e5ba57f394..23b8ed398f 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -947,21 +947,15 @@ sub req_update # projects (heads in this case) to checkout. # if ($state->{module} eq '') { - my $heads_dir = $state->{CVSROOT} . '/refs/heads'; - if (!opendir HEADS, $heads_dir) { - print "E [server aborted]: Failed to open directory, " - . "$heads_dir: $!\nerror\n"; - return 0; - } + my $showref = `git show-ref --heads`; print "E cvs update: Updating .\n"; - while (my $head = readdir(HEADS)) { - if (-f $state->{CVSROOT} . '/refs/heads/' . $head) { - print "E cvs update: New directory `$head'\n"; - } - } - closedir HEADS; - print "ok\n"; - return 1; + for my $line (split '\n', $showref) { + if ( $line =~ m% refs/heads/(.*)$% ) { + print "E cvs update: New directory `$1'\n"; + } + } + print "ok\n"; + return 1; } From 89a9167fac209649116a6e1b7a39b4f4c974f86b Mon Sep 17 00:00:00 2001 From: Lars Noschinski Date: Thu, 17 Jul 2008 19:00:29 +0200 Subject: [PATCH 12/24] cvsserver: Add cvs co -c support Implement cvs checkout's -c option by returning a list of all "modules". This is more useful than displaying a perl warning if -c is given. Signed-off-by: Lars Noschinski Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index 23b8ed398f..b0a805c688 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -801,6 +801,18 @@ sub req_co argsplit("co"); + # Provide list of modules, if -c was used. + if (exists $state->{opt}{c}) { + my $showref = `git show-ref --heads`; + for my $line (split '\n', $showref) { + if ( $line =~ m% refs/heads/(.*)$% ) { + print "M $1\t$1\n"; + } + } + print "ok\n"; + return 1; + } + my $module = $state->{args}[0]; $state->{module} = $module; my $checkout_path = $module; From 42f7a2dae8dfb858cce4a685e8e8506d77cbd1cb Mon Sep 17 00:00:00 2001 From: Fabian Emmes Date: Thu, 17 Jul 2008 19:00:30 +0200 Subject: [PATCH 13/24] testsuite for cvs co -c Check that all branches are displayed. Signed-off-by: Fabian Emmes Signed-off-by: Lars Noschinski Signed-off-by: Junio C Hamano --- t/t9400-git-cvsserver-server.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh index e97aaa6c2a..d49f0df8c4 100755 --- a/t/t9400-git-cvsserver-server.sh +++ b/t/t9400-git-cvsserver-server.sh @@ -470,4 +470,15 @@ test_expect_success 'cvs status (no subdirs in header)' ' ! grep / <../out ' +#------------ +# CVS CHECKOUT +#------------ + +cd "$WORKDIR" +test_expect_success 'cvs co -c (shows module database)' ' + GIT_CONFIG="$git_config" cvs co -c > out && + grep "^master[ ]\+master$" < out && + ! grep -v "^master[ ]\+master$" < out +' + test_done From fe77b6959c47e1eaec0c96599b2c5ce7907707ec Mon Sep 17 00:00:00 2001 From: Eric Raible Date: Fri, 18 Jul 2008 09:34:42 +0200 Subject: [PATCH 14/24] Teach lookup_prog not to select directories Without this simple fix "git gui" in the git source directory finds the git-gui directory instead of the tcl script in /usr/bin. Signed-off-by: Eric Raible Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- compat/mingw.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compat/mingw.c b/compat/mingw.c index c0bc849e45..772cad510d 100644 --- a/compat/mingw.c +++ b/compat/mingw.c @@ -536,7 +536,8 @@ static char *lookup_prog(const char *dir, const char *cmd, int isexe, int exe_on return xstrdup(path); path[strlen(path)-4] = '\0'; if ((!exe_only || isexe) && access(path, F_OK) == 0) - return xstrdup(path); + if (!(GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY)) + return xstrdup(path); return NULL; } From b8c5db35fc23913d72c52d990d399b8ef66b646f Mon Sep 17 00:00:00 2001 From: Johannes Sixt Date: Sat, 19 Jul 2008 11:32:45 +0200 Subject: [PATCH 15/24] builtin-clone: rewrite guess_dir_name() The function has to do three small and independent tasks, but all of them were crammed into a single loop. This rewrites the function entirely by unrolling these tasks. We also now use is_dir_sep(c) instead of c == '/' to increase portability. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- builtin-clone.c | 57 ++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 27 deletions(-) diff --git a/builtin-clone.c b/builtin-clone.c index 8112716c10..352224591f 100644 --- a/builtin-clone.c +++ b/builtin-clone.c @@ -95,35 +95,38 @@ static char *get_repo_path(const char *repo, int *is_bundle) static char *guess_dir_name(const char *repo, int is_bundle) { - const char *p, *start, *end, *limit; - int after_slash_or_colon; + const char *end = repo + strlen(repo), *start; - /* Guess dir name from repository: strip trailing '/', - * strip trailing '[:/]*.{git,bundle}', strip leading '.*[/:]'. */ + /* + * Strip trailing slashes and /.git + */ + while (repo < end && is_dir_sep(end[-1])) + end--; + if (end - repo > 5 && is_dir_sep(end[-5]) && + !strncmp(end - 4, ".git", 4)) { + end -= 5; + while (repo < end && is_dir_sep(end[-1])) + end--; + } - after_slash_or_colon = 1; - limit = repo + strlen(repo); - start = repo; - end = limit; - for (p = repo; p < limit; p++) { - const char *prefix = is_bundle ? ".bundle" : ".git"; - if (!prefixcmp(p, prefix)) { - if (!after_slash_or_colon) - end = p; - p += strlen(prefix) - 1; - } else if (!prefixcmp(p, ".bundle")) { - if (!after_slash_or_colon) - end = p; - p += 7; - } else if (*p == '/' || *p == ':') { - if (end == limit) - end = p; - after_slash_or_colon = 1; - } else if (after_slash_or_colon) { - start = p; - end = limit; - after_slash_or_colon = 0; - } + /* + * Find last component, but be prepared that repo could have + * the form "remote.example.com:foo.git", i.e. no slash + * in the directory part. + */ + start = end; + while (repo < start && !is_dir_sep(start[-1]) && start[-1] != ':') + start--; + + /* + * Strip .{bundle,git}. + */ + if (is_bundle) { + if (end - start > 7 && !strncmp(end - 7, ".bundle", 7)) + end -= 7; + } else { + if (end - start > 4 && !strncmp(end - 4, ".git", 4)) + end -= 4; } return xstrndup(start, end - start); From c09df8a74e8b5e106ad853cbb1e52f36b3663386 Mon Sep 17 00:00:00 2001 From: Peter Harris Date: Fri, 18 Jul 2008 09:34:44 +0200 Subject: [PATCH 16/24] Add ANSI control code emulation for the Windows console This adds only the minimum necessary to keep git pull/merge's diffstat from wrapping. Notably absent is support for the K (erase) operation, and support for POSIX write. Signed-off-by: Peter Harris Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- Makefile | 2 +- compat/mingw.h | 11 ++ compat/winansi.c | 345 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 compat/winansi.c diff --git a/Makefile b/Makefile index c01345e784..2b670d7845 100644 --- a/Makefile +++ b/Makefile @@ -741,7 +741,7 @@ ifneq (,$(findstring MINGW,$(uname_S))) COMPAT_CFLAGS += -D__USE_MINGW_ACCESS -DNOGDI -Icompat COMPAT_CFLAGS += -DSNPRINTF_SIZE_CORR=1 COMPAT_CFLAGS += -DSTRIP_EXTENSION=\".exe\" - COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o + COMPAT_OBJS += compat/mingw.o compat/fnmatch.o compat/regex.o compat/winansi.o EXTLIBS += -lws2_32 X = .exe template_dir = ../share/git-core/templates/ diff --git a/compat/mingw.h b/compat/mingw.h index 5a3bcee29b..8ffec51e73 100644 --- a/compat/mingw.h +++ b/compat/mingw.h @@ -193,6 +193,17 @@ static inline unsigned int git_ntohl(unsigned int x) sig_handler_t mingw_signal(int sig, sig_handler_t handler); #define signal mingw_signal +/* + * ANSI emulation wrappers + */ + +int winansi_fputs(const char *str, FILE *stream); +int winansi_printf(const char *format, ...) __attribute__((format (printf, 1, 2))); +int winansi_fprintf(FILE *stream, const char *format, ...) __attribute__((format (printf, 2, 3))); +#define fputs winansi_fputs +#define printf(...) winansi_printf(__VA_ARGS__) +#define fprintf(...) winansi_fprintf(__VA_ARGS__) + /* * git specific compatibility */ diff --git a/compat/winansi.c b/compat/winansi.c new file mode 100644 index 0000000000..e2d96dfe6f --- /dev/null +++ b/compat/winansi.c @@ -0,0 +1,345 @@ +/* + * Copyright 2008 Peter Harris + */ + +#include +#include "../git-compat-util.h" + +/* + Functions to be wrapped: +*/ +#undef printf +#undef fprintf +#undef fputs +/* TODO: write */ + +/* + ANSI codes used by git: m, K + + This file is git-specific. Therefore, this file does not attempt + to implement any codes that are not used by git. + + TODO: K +*/ + +static HANDLE console; +static WORD plain_attr; +static WORD attr; +static int negative; + +static void init(void) +{ + CONSOLE_SCREEN_BUFFER_INFO sbi; + + static int initialized = 0; + if (initialized) + return; + + console = GetStdHandle(STD_OUTPUT_HANDLE); + if (console == INVALID_HANDLE_VALUE) + console = NULL; + + if (!console) + return; + + GetConsoleScreenBufferInfo(console, &sbi); + attr = plain_attr = sbi.wAttributes; + negative = 0; + + initialized = 1; +} + + +#define FOREGROUND_ALL (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define BACKGROUND_ALL (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE) + +static void set_console_attr(void) +{ + WORD attributes = attr; + if (negative) { + attributes &= ~FOREGROUND_ALL; + attributes &= ~BACKGROUND_ALL; + + /* This could probably use a bitmask + instead of a series of ifs */ + if (attr & FOREGROUND_RED) + attributes |= BACKGROUND_RED; + if (attr & FOREGROUND_GREEN) + attributes |= BACKGROUND_GREEN; + if (attr & FOREGROUND_BLUE) + attributes |= BACKGROUND_BLUE; + + if (attr & BACKGROUND_RED) + attributes |= FOREGROUND_RED; + if (attr & BACKGROUND_GREEN) + attributes |= FOREGROUND_GREEN; + if (attr & BACKGROUND_BLUE) + attributes |= FOREGROUND_BLUE; + } + SetConsoleTextAttribute(console, attributes); +} + +static const char *set_attr(const char *str) +{ + const char *func; + size_t len = strspn(str, "0123456789;"); + func = str + len; + + switch (*func) { + case 'm': + do { + long val = strtol(str, (char **)&str, 10); + switch (val) { + case 0: /* reset */ + attr = plain_attr; + negative = 0; + break; + case 1: /* bold */ + attr |= FOREGROUND_INTENSITY; + break; + case 2: /* faint */ + case 22: /* normal */ + attr &= ~FOREGROUND_INTENSITY; + break; + case 3: /* italic */ + /* Unsupported */ + break; + case 4: /* underline */ + case 21: /* double underline */ + /* Wikipedia says this flag does nothing */ + /* Furthermore, mingw doesn't define this flag + attr |= COMMON_LVB_UNDERSCORE; */ + break; + case 24: /* no underline */ + /* attr &= ~COMMON_LVB_UNDERSCORE; */ + break; + case 5: /* slow blink */ + case 6: /* fast blink */ + /* We don't have blink, but we do have + background intensity */ + attr |= BACKGROUND_INTENSITY; + break; + case 25: /* no blink */ + attr &= ~BACKGROUND_INTENSITY; + break; + case 7: /* negative */ + negative = 1; + break; + case 27: /* positive */ + negative = 0; + break; + case 8: /* conceal */ + case 28: /* reveal */ + /* Unsupported */ + break; + case 30: /* Black */ + attr &= ~FOREGROUND_ALL; + break; + case 31: /* Red */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED; + break; + case 32: /* Green */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN; + break; + case 33: /* Yellow */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_GREEN; + break; + case 34: /* Blue */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_BLUE; + break; + case 35: /* Magenta */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_RED | FOREGROUND_BLUE; + break; + case 36: /* Cyan */ + attr &= ~FOREGROUND_ALL; + attr |= FOREGROUND_GREEN | FOREGROUND_BLUE; + break; + case 37: /* White */ + attr |= FOREGROUND_RED | + FOREGROUND_GREEN | + FOREGROUND_BLUE; + break; + case 38: /* Unknown */ + break; + case 39: /* reset */ + attr &= ~FOREGROUND_ALL; + attr |= (plain_attr & FOREGROUND_ALL); + break; + case 40: /* Black */ + attr &= ~BACKGROUND_ALL; + break; + case 41: /* Red */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED; + break; + case 42: /* Green */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN; + break; + case 43: /* Yellow */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_GREEN; + break; + case 44: /* Blue */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_BLUE; + break; + case 45: /* Magenta */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_RED | BACKGROUND_BLUE; + break; + case 46: /* Cyan */ + attr &= ~BACKGROUND_ALL; + attr |= BACKGROUND_GREEN | BACKGROUND_BLUE; + break; + case 47: /* White */ + attr |= BACKGROUND_RED | + BACKGROUND_GREEN | + BACKGROUND_BLUE; + break; + case 48: /* Unknown */ + break; + case 49: /* reset */ + attr &= ~BACKGROUND_ALL; + attr |= (plain_attr & BACKGROUND_ALL); + break; + default: + /* Unsupported code */ + break; + } + str++; + } while (*(str-1) == ';'); + + set_console_attr(); + break; + case 'K': + /* TODO */ + break; + default: + /* Unsupported code */ + break; + } + + return func + 1; +} + +static int ansi_emulate(const char *str, FILE *stream) +{ + int rv = 0; + const char *pos = str; + + while (*pos) { + pos = strstr(str, "\033["); + if (pos) { + size_t len = pos - str; + + if (len) { + size_t out_len = fwrite(str, 1, len, stream); + rv += out_len; + if (out_len < len) + return rv; + } + + str = pos + 2; + rv += 2; + + fflush(stream); + + pos = set_attr(str); + rv += pos - str; + str = pos; + } else { + rv += strlen(str); + fputs(str, stream); + return rv; + } + } + return rv; +} + +int winansi_fputs(const char *str, FILE *stream) +{ + int rv; + + if (!isatty(fileno(stream))) + return fputs(str, stream); + + init(); + + if (!console) + return fputs(str, stream); + + rv = ansi_emulate(str, stream); + + if (rv >= 0) + return 0; + else + return EOF; +} + +static int winansi_vfprintf(FILE *stream, const char *format, va_list list) +{ + int len, rv; + char small_buf[256]; + char *buf = small_buf; + va_list cp; + + if (!isatty(fileno(stream))) + goto abort; + + init(); + + if (!console) + goto abort; + + va_copy(cp, list); + len = vsnprintf(small_buf, sizeof(small_buf), format, cp); + va_end(cp); + + if (len > sizeof(small_buf) - 1) { + buf = malloc(len + 1); + if (!buf) + goto abort; + + len = vsnprintf(buf, len + 1, format, list); + } + + rv = ansi_emulate(buf, stream); + + if (buf != small_buf) + free(buf); + return rv; + +abort: + rv = vfprintf(stream, format, list); + return rv; +} + +int winansi_fprintf(FILE *stream, const char *format, ...) +{ + va_list list; + int rv; + + va_start(list, format); + rv = winansi_vfprintf(stream, format, list); + va_end(list); + + return rv; +} + +int winansi_printf(const char *format, ...) +{ + va_list list; + int rv; + + va_start(list, format); + rv = winansi_vfprintf(stdout, format, list); + va_end(list); + + return rv; +} From c47f10246ac6413ac6902bd70e45492174fac873 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Fri, 18 Jul 2008 15:40:41 +0200 Subject: [PATCH 17/24] Documentation/git-submodule.txt: Further clarify the description This patch rewrites the general description yet again, first clarifying the high-level concept, mentioning the difference to remotes and using the subtree merge strategy, then getting to the details about tree entries and .gitmodules file. The patch also makes few smallar grammar fixups within the rest of the description and clarifies how does 'init' relate to 'update --init'. Cc: Heikki Orsila Signed-off-by: Petr Baudis Signed-off-by: Junio C Hamano --- Documentation/git-submodule.txt | 65 +++++++++++++++++++++++---------- 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/Documentation/git-submodule.txt b/Documentation/git-submodule.txt index bb4e6fbf59..829b03201d 100644 --- a/Documentation/git-submodule.txt +++ b/Documentation/git-submodule.txt @@ -18,24 +18,44 @@ SYNOPSIS DESCRIPTION ----------- -Submodules are a special kind of tree entries which refer to a particular tree -state in another repository. The tree entry describes -the existence of a submodule with the given name and the exact revision that -should be used, while an entry in `.gitmodules` file gives the location of -the repository. +Submodules allow foreign repositories to be embedded within +a dedicated subdirectory of the source tree, always pointed +at a particular commit. -When checked out, submodules will maintain their own independent repositories -within their directories; the only link between the submodule and the "parent -project" is the tree entry within the parent project mentioned above. +They are not to be confused with remotes, which are meant mainly +for branches of the same project; submodules are meant for +different projects you would like to make part of your source tree, +while the history of the two projects still stays completely +independent and you cannot modify the contents of the submodule +from within the main project. +If you want to merge the project histories and want to treat the +aggregated whole as a single project from then on, you may want to +add a remote for the other project and use the 'subtree' merge strategy, +instead of treating the other project as a submodule. Directories +that come from both projects can be cloned and checked out as a whole +if you choose to go that route. -This command will manage the tree entries and contents of the gitmodules file -for you, as well as inspecting the status of your submodules and updating them. -When adding a new submodule to the tree, the 'add' subcommand is to be used. -However, when pulling a tree containing submodules, these will not be checked -out by default; the 'init' and 'update' subcommands will maintain submodules -checked out and at appropriate revision in your working tree. You can inspect -the current status of your submodules using the 'submodule' subcommand and get -an overview of changes 'update' would perform using the 'summary' subcommand. +Submodules are composed from a so-called `gitlink` tree entry +in the main repository that refers to a particular commit object +within the inner repository that is completely separate. +A record in the `.gitmodules` file at the root of the source +tree assigns a logical name to the submodule and describes +the default URL the submodule shall be cloned from. +The logical name can be used for overriding this URL within your +local repository configuration (see 'submodule init'). + +This command will manage the tree entries and contents of the +gitmodules file for you, as well as inspect the status of your +submodules and update them. +When adding a new submodule to the tree, the 'add' subcommand +is to be used. However, when pulling a tree containing submodules, +these will not be checked out by default; +the 'init' and 'update' subcommands will maintain submodules +checked out and at appropriate revision in your working tree. +You can briefly inspect the up-to-date status of your submodules +using the 'status' subcommand and get a detailed overview of the +difference between the index and checkouts using the 'summary' +subcommand. COMMANDS @@ -78,10 +98,15 @@ status:: repository. This command is the default command for 'git-submodule'. init:: - Initialize the submodules, i.e. register in .git/config each submodule - name and url found in .gitmodules. The key used in .git/config is - `submodule.$name.url`. This command does not alter existing information - in .git/config. + Initialize the submodules, i.e. register each submodule name + and url found in .gitmodules into .git/config. + The key used in .git/config is `submodule.$name.url`. + This command does not alter existing information in .git/config. + You can then customize the submodule clone URLs in .git/config + for your local setup and proceed to 'git submodule update'; + you can also just use 'git submodule update --init' without + the explicit 'init' step if you do not intend to customize + any submodule locations. update:: Update the registered submodules, i.e. clone missing submodules and From 6259ac6628477aa5ebde9bd9e8daaeecca2a74ae Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Fri, 18 Jul 2008 16:11:07 +0200 Subject: [PATCH 18/24] Documentation: How to ignore local changes in tracked files This patch explains more carefully that `.gitignore` concerns only untracked files and refers the reader to git update-index --assume-unchanged in the need of ignoring uncommitted changes in already tracked files. The description of this option is lifted to a more "porcelainish" level and explains the caveats of this usecase. Whether feasible or not, I believe adding this functionality to the porcelain is out of the scope of this patch. (And I personally think that referring to the plumbing in the case of such a special usage is fine.) This is currently probably one of the top FAQs at #git and the --assume-unchanged switch is not widely known; gitignore(5) is the first place where people are likely to look for it. Signed-off-by: Petr Baudis Signed-off-by: Junio C Hamano --- Documentation/git-update-index.txt | 10 ++++++++++ Documentation/gitignore.txt | 9 +++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt index a91fd214d2..6b930bc163 100644 --- a/Documentation/git-update-index.txt +++ b/Documentation/git-update-index.txt @@ -88,6 +88,16 @@ OPTIONS sometimes helpful when working with a big project on a filesystem that has very slow lstat(2) system call (e.g. cifs). ++ +This option can be also used as a coarse file-level mechanism +to ignore uncommitted changes in tracked files (akin to what +`.gitignore` does for untracked files). +You should remember that an explicit 'git add' operation will +still cause the file to be refreshed from the working tree. +Git will fail (gracefully) in case it needs to modify this file +in the index e.g. when merging in a commit; +thus, in case the assumed-untracked file is changed upstream, +you will need to handle the situation manually. -g:: --again:: diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt index fc0efd8ec8..59321a2e82 100644 --- a/Documentation/gitignore.txt +++ b/Documentation/gitignore.txt @@ -13,9 +13,14 @@ DESCRIPTION ----------- A `gitignore` file specifies intentionally untracked files that -git should ignore. Each line in a `gitignore` file specifies a -pattern. +git should ignore. +Note that all the `gitignore` files really concern only files +that are not already tracked by git; +in order to ignore uncommitted changes in already tracked files, +please refer to the 'git update-index --assume-unchanged' +documentation. +Each line in a `gitignore` file specifies a pattern. When deciding whether to ignore a path, git normally checks `gitignore` patterns from multiple sources, with the following order of precedence, from highest to lowest (within one level of From 3a176c6cde650f8907b2dbafafb72f6375038613 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Fri, 18 Jul 2008 16:30:32 +0200 Subject: [PATCH 19/24] archive: make zip compression level independent from core git zlib_compression_level is the compression level used for git's object store. It's 1 by default, which is the fastest setting. This variable is also used as the default compression level for ZIP archives created by git archive. For archives, however, zlib's own default of 6 is more appropriate, as it's favouring small size over speed -- archive creation is not that performance critical most of the time. This patch makes git archive independent from git's internal compression level setting. It affects invocations of git archive without explicitly specified compression level option, only. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- archive-zip.c | 9 +++++---- archive.h | 1 + builtin-archive.c | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/archive-zip.c b/archive-zip.c index d56e5cfc1e..fb12398b0f 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -93,7 +93,7 @@ static void copy_le32(unsigned char *dest, unsigned int n) } static void *zlib_deflate(void *data, unsigned long size, - unsigned long *compressed_size) + int compression_level, unsigned long *compressed_size) { z_stream stream; unsigned long maxsize; @@ -101,7 +101,7 @@ static void *zlib_deflate(void *data, unsigned long size, int result; memset(&stream, 0, sizeof(stream)); - deflateInit(&stream, zlib_compression_level); + deflateInit(&stream, compression_level); maxsize = deflateBound(&stream, size); buffer = xmalloc(maxsize); @@ -157,7 +157,7 @@ static int write_zip_entry(struct archiver_args *args, method = 0; attr2 = S_ISLNK(mode) ? ((mode | 0777) << 16) : (mode & 0111) ? ((mode) << 16) : 0; - if (S_ISREG(mode) && zlib_compression_level != 0) + if (S_ISREG(mode) && args->compression_level != 0) method = 8; crc = crc32(crc, buffer, size); out = buffer; @@ -169,7 +169,8 @@ static int write_zip_entry(struct archiver_args *args, } if (method == 8) { - deflated = zlib_deflate(buffer, size, &compressed_size); + deflated = zlib_deflate(buffer, size, args->compression_level, + &compressed_size); if (deflated && compressed_size - 6 < size) { /* ZLIB --> raw compressed data (see RFC 1950) */ /* CMF and FLG ... */ diff --git a/archive.h b/archive.h index 96bb1cd853..4a02371f37 100644 --- a/archive.h +++ b/archive.h @@ -13,6 +13,7 @@ struct archiver_args { time_t time; const char **pathspec; unsigned int verbose : 1; + int compression_level; }; typedef int (*write_archive_fn_t)(struct archiver_args *); diff --git a/builtin-archive.c b/builtin-archive.c index d5e3af879e..cff6ce7de3 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -185,9 +185,10 @@ int parse_archive_args(int argc, const char **argv, const struct archiver **ar, if (!*ar) die("Unknown archive format '%s'", format); + args->compression_level = Z_DEFAULT_COMPRESSION; if (compression_level != -1) { if ((*ar)->flags & USES_ZLIB_COMPRESSION) - zlib_compression_level = compression_level; + args->compression_level = compression_level; else { die("Argument not supported for format '%s': -%d", format, compression_level); From 8575ea559ec4f0ea8b292bca7b262f221c5aa122 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Scharfe?= Date: Fri, 18 Jul 2008 16:30:47 +0200 Subject: [PATCH 20/24] archive: remove unused headers Remove obsolete #includes. Signed-off-by: Rene Scharfe Signed-off-by: Junio C Hamano --- archive-tar.c | 2 -- archive-zip.c | 5 ----- builtin-archive.c | 2 -- 3 files changed, 9 deletions(-) diff --git a/archive-tar.c b/archive-tar.c index f9eb726116..13029619e5 100644 --- a/archive-tar.c +++ b/archive-tar.c @@ -2,9 +2,7 @@ * Copyright (c) 2005, 2006 Rene Scharfe */ #include "cache.h" -#include "commit.h" #include "tar.h" -#include "builtin.h" #include "archive.h" #define RECORDSIZE (512) diff --git a/archive-zip.c b/archive-zip.c index fb12398b0f..cf285044e3 100644 --- a/archive-zip.c +++ b/archive-zip.c @@ -2,11 +2,6 @@ * Copyright (c) 2006 Rene Scharfe */ #include "cache.h" -#include "commit.h" -#include "blob.h" -#include "tree.h" -#include "quote.h" -#include "builtin.h" #include "archive.h" static int zip_date; diff --git a/builtin-archive.c b/builtin-archive.c index cff6ce7de3..df97724696 100644 --- a/builtin-archive.c +++ b/builtin-archive.c @@ -7,10 +7,8 @@ #include "archive.h" #include "commit.h" #include "tree-walk.h" -#include "exec_cmd.h" #include "pkt-line.h" #include "sideband.h" -#include "attr.h" static const char archive_usage[] = \ "git archive --format= [--prefix=/] [--verbose] [] [path...]"; From c0be8aa06b85f3f18fd4c49dfbda14c2943ccda7 Mon Sep 17 00:00:00 2001 From: Petr Baudis Date: Sat, 19 Jul 2008 20:17:22 +0200 Subject: [PATCH 21/24] Documentation/git-merge.txt: Partial rewrite of How Merge Works The git-merge documentation's "HOW MERGE WORKS" section is confusingly composed and actually omits the most interesting part, the merging of the arguments into HEAD itself, surprisingly not actually mentioning the fast-forward merge anywhere. This patch replaces the "[NOTE]" screenful of highly technical details by a single sentence summing up the interesting information, and instead explains how are the arguments compared with HEAD and the three possible inclusion states that are named "Already up-to-date", "Fast-forward" and "True merge". It also makes it clear that the rest of the section talks only about the true merge situation, and slightly expands the talk on solving conflicts. Junio initiated the removal of the Note screenful altogether and offered many stylistical fixes. Signed-off-by: Petr Baudis Signed-off-by: Junio C Hamano --- Documentation/git-merge.txt | 66 ++++++++++++++----------------------- 1 file changed, 24 insertions(+), 42 deletions(-) diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt index 019e4ca8f5..a7487d3dfd 100644 --- a/Documentation/git-merge.txt +++ b/Documentation/git-merge.txt @@ -57,50 +57,31 @@ HOW MERGE WORKS A merge is always between the current `HEAD` and one or more commits (usually, branch head or tag), and the index file must -exactly match the -tree of `HEAD` commit (i.e. the contents of the last commit) when -it happens. In other words, `git diff --cached HEAD` must -report no changes. +match the tree of `HEAD` commit (i.e. the contents of the last commit) +when it starts out. In other words, `git diff --cached HEAD` must +report no changes. (One exception is when the changed index +entries are already in the same state that would result from +the merge anyway.) -[NOTE] -This is a bit of a lie. In certain special cases, your index is -allowed to be different from the tree of the `HEAD` commit. The most -notable case is when your `HEAD` commit is already ahead of what -is being merged, in which case your index can have arbitrary -differences from your `HEAD` commit. Also, your index entries -may have differences from your `HEAD` commit that match -the result of a trivial merge (e.g. you received the same patch -from an external source to produce the same result as what you are -merging). For example, if a path did not exist in the common -ancestor and your head commit but exists in the tree you are -merging into your repository, and if you already happen to have -that path exactly in your index, the merge does not have to -fail. +Three kinds of merge can happen: -Otherwise, merge will refuse to do any harm to your repository -(that is, it may fetch the objects from remote, and it may even -update the local branch used to keep track of the remote branch -with `git pull remote rbranch:lbranch`, but your working tree, -`.git/HEAD` pointer and index file are left intact). In addition, -merge always sets `.git/ORIG_HEAD` to the original state of HEAD so -a problematic merge can be removed by using `git reset ORIG_HEAD`. +* The merged commit is already contained in `HEAD`. This is the + simplest case, called "Already up-to-date." -You may have local modifications in the working tree files. In -other words, 'git-diff' is allowed to report changes. -However, the merge uses your working tree as the working area, -and in order to prevent the merge operation from losing such -changes, it makes sure that they do not interfere with the -merge. Those complex tables in read-tree documentation define -what it means for a path to "interfere with the merge". And if -your local modifications interfere with the merge, again, it -stops before touching anything. +* `HEAD` is already contained in the merged commit. This is the + most common case especially when involved through 'git pull': + you are tracking an upstream repository, committed no local + changes and now you want to update to a newer upstream revision. + Your `HEAD` (and the index) is updated to at point the merged + commit, without creating an extra merge commit. This is + called "Fast-forward". -So in the above two "failed merge" case, you do not have to -worry about loss of data --- you simply were not ready to do -a merge, so no merge happened at all. You may want to finish -whatever you were in the middle of doing, and retry the same -pull after you are done and ready. +* Both the merged commit and `HEAD` are independent and must be + tied together by a merge commit that has them both as its parents. + The rest of this section describes this "True merge" case. +The chosen merge strategy merges the two commits into a single +new source tree. When things cleanly merge, these things happen: 1. The results are updated both in the index file and in your @@ -142,12 +123,13 @@ After seeing a conflict, you can do two things: * Decide not to merge. The only clean-up you need are to reset the index file to the `HEAD` commit to reverse 2. and to clean - up working tree changes made by 2. and 3.; 'git-reset' can + up working tree changes made by 2. and 3.; 'git-reset --hard' can be used for this. * Resolve the conflicts. `git diff` would report only the - conflicting paths because of the above 2. and 3. Edit the - working tree files into a desirable shape, 'git-add' or 'git-rm' + conflicting paths because of the above 2. and 3. + Edit the working tree files into a desirable shape + ('git mergetool' can ease this task), 'git-add' or 'git-rm' them, to make the index file contain what the merge result should be, and run 'git-commit' to commit the result. From 4a3fedd5976ae9175cc418876d17ca568278b426 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 18 Jul 2008 23:24:26 -0700 Subject: [PATCH 22/24] .mailmap update A few people sent in patches under slightly different spelling recently. Hopefully this catches most of them if not all (with help from Dscho). Signed-off-by: Junio C Hamano --- .mailmap | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.mailmap b/.mailmap index f88ae77a1f..373476bdc0 100644 --- a/.mailmap +++ b/.mailmap @@ -5,22 +5,28 @@ # same person appearing not to be so. # +Alexander Gavrilov Aneesh Kumar K.V Brian M. Carlson Chris Shoemaker Dana L. How Dana L. How Daniel Barkalow +David D. Kilzer David Kågedal +David S. Miller +Dirk Süsserott Fredrik Kuivinen H. Peter Anvin H. Peter Anvin H. Peter Anvin Horst H. von Brand +İsmail Dönmez Jay Soffian Joachim Berdal Haga Jon Loeliger Jon Seymour +Jonathan Nieder Junio C Hamano Karl Hasselström Kent Engstrom @@ -30,9 +36,12 @@ Li Hong Lukas Sandström Martin Langhoff Michael Coleman +Michael W. Olson Michele Ballabio Nanako Shiraishi +Nanako Shiraishi Nguyễn Thái Ngọc Duy +Philippe Bruhat Ramsay Allan Jones René Scharfe Robert Fitzsimons From 03db4525d38119f7778d6e9117f27c47db8466d4 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Sat, 19 Jul 2008 16:21:24 +0400 Subject: [PATCH 23/24] Support gitlinks in fast-import. Currently fast-import/export cannot be used for repositories with submodules. This patch extends the relevant programs to make them correctly process gitlinks. Links can be represented by two forms of the Modify command: M 160000 SHA1 some/path which sets the link target explicitly, or M 160000 :mark some/path where the mark refers to a commit. The latter form can be used by importing tools to build all submodules simultaneously in one physical repository, and then simply fetch them apart. Signed-off-by: Alexander Gavrilov Signed-off-by: Junio C Hamano --- Documentation/git-fast-import.txt | 3 + builtin-fast-export.c | 19 +++- fast-import.c | 16 +++- t/t9300-fast-import.sh | 152 ++++++++++++++++++++++++++++++ t/t9301-fast-export.sh | 42 +++++++++ 5 files changed, 227 insertions(+), 5 deletions(-) diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt index 2d01d0d100..c2f483a8d2 100644 --- a/Documentation/git-fast-import.txt +++ b/Documentation/git-fast-import.txt @@ -481,6 +481,9 @@ in octal. Git only supports the following modes: what you want. * `100755` or `755`: A normal, but executable, file. * `120000`: A symlink, the content of the file will be the link target. +* `160000`: A gitlink, SHA-1 of the object refers to a commit in + another repository. Git links can only be specified by SHA or through + a commit mark. They are used to implement submodules. In both formats `` is the complete path of the file to be added (if not already existing) or modified (if already existing). diff --git a/builtin-fast-export.c b/builtin-fast-export.c index 76f3167276..a443d59460 100644 --- a/builtin-fast-export.c +++ b/builtin-fast-export.c @@ -136,9 +136,18 @@ static void show_filemodify(struct diff_queue_struct *q, if (is_null_sha1(spec->sha1)) printf("D %s\n", spec->path); else { - struct object *object = lookup_object(spec->sha1); - printf("M %06o :%d %s\n", spec->mode, - get_object_mark(object), spec->path); + /* + * Links refer to objects in another repositories; + * output the SHA-1 verbatim. + */ + if (S_ISGITLINK(spec->mode)) + printf("M %06o %s %s\n", spec->mode, + sha1_to_hex(spec->sha1), spec->path); + else { + struct object *object = lookup_object(spec->sha1); + printf("M %06o :%d %s\n", spec->mode, + get_object_mark(object), spec->path); + } } } } @@ -196,8 +205,10 @@ static void handle_commit(struct commit *commit, struct rev_info *rev) diff_root_tree_sha1(commit->tree->object.sha1, "", &rev->diffopt); + /* Export the referenced blobs, and remember the marks. */ for (i = 0; i < diff_queued_diff.nr; i++) - handle_object(diff_queued_diff.queue[i]->two->sha1); + if (!S_ISGITLINK(diff_queued_diff.queue[i]->two->mode)) + handle_object(diff_queued_diff.queue[i]->two->sha1); mark_next_object(&commit->object); if (!is_encoding_utf8(encoding)) diff --git a/fast-import.c b/fast-import.c index c4d054ecc7..7089e6f9e6 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1868,6 +1868,7 @@ static void file_change_m(struct branch *b) case S_IFREG | 0644: case S_IFREG | 0755: case S_IFLNK: + case S_IFGITLINK: case 0644: case 0755: /* ok */ @@ -1900,7 +1901,20 @@ static void file_change_m(struct branch *b) p = uq.buf; } - if (inline_data) { + if (S_ISGITLINK(mode)) { + if (inline_data) + die("Git links cannot be specified 'inline': %s", + command_buf.buf); + else if (oe) { + if (oe->type != OBJ_COMMIT) + die("Not a commit (actually a %s): %s", + typename(oe->type), command_buf.buf); + } + /* + * Accept the sha1 without checking; it expected to be in + * another repository. + */ + } else if (inline_data) { static struct strbuf buf = STRBUF_INIT; if (p != uq.buf) { diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index e17afa8c30..1fc06c5a23 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -918,4 +918,156 @@ test_expect_success \ grep "progress " expect && test_cmp expect actual' +### +### series P (gitlinks) +### + +cat >input < $GIT_COMMITTER_DATE +data 12 +sub_initial +M 100644 :1 file + +blob +mark :3 +data < $GIT_COMMITTER_DATE +data 8 +initial +from refs/heads/master +M 100644 :3 .gitmodules +M 160000 :2 sub + +blob +mark :5 +data 20 +test file +more data + +commit refs/heads/sub +mark :6 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data 11 +sub_second +from :2 +M 100644 :5 file + +commit refs/heads/subuse1 +mark :7 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data 7 +second +from :4 +M 160000 :6 sub + +INPUT_END + +test_expect_success \ + 'P: supermodule & submodule mix' \ + 'git-fast-import input < $GIT_COMMITTER_DATE +data 8 +initial +from refs/heads/master +M 100644 :1 .gitmodules +M 160000 $SUBPREV sub + +commit refs/heads/subuse2 +mark :3 +committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE +data 7 +second +from :2 +M 160000 $SUBLAST sub + +INPUT_END + +test_expect_success \ + 'P: verbatim SHA gitlinks' \ + 'git branch -D sub && + git gc && git prune && + git-fast-import input < $GIT_COMMITTER_DATE +data <input < $GIT_COMMITTER_DATE +data < file && + git add file && + git commit -m sub_initial && + cd .. && + git submodule add "`pwd`/sub" sub && + git commit -m initial && + test_tick && + cd sub && + echo more data >> file && + git add file && + git commit -m sub_second && + cd .. && + git add sub && + git commit -m second + +' + +test_expect_success 'submodule fast-export | fast-import' ' + + SUBENT1=$(git ls-tree master^ sub) && + SUBENT2=$(git ls-tree master sub) && + rm -rf new && + mkdir new && + git --git-dir=new/.git init && + git fast-export --signed-tags=strip --all | + (cd new && + git fast-import && + test "$SUBENT1" = "$(git ls-tree refs/heads/master^ sub)" && + test "$SUBENT2" = "$(git ls-tree refs/heads/master sub)" && + git checkout master && + git submodule init && + git submodule update && + cmp sub/file ../sub/file) + +' + test_done From 09651dd86eb07d1d6f1a2e88fe7b4860891808c1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 19 Jul 2008 15:52:12 -0700 Subject: [PATCH 24/24] Getting closer to 1.6.0-rc0 Update the links to "stale" versions of documentation to link to 1.5.6.4 Signed-off-by: Junio C Hamano --- Documentation/RelNotes-1.6.0.txt | 9 ++++++++- Documentation/git.txt | 9 +++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Documentation/RelNotes-1.6.0.txt b/Documentation/RelNotes-1.6.0.txt index 9bbb07ef9b..7da62d08d6 100644 --- a/Documentation/RelNotes-1.6.0.txt +++ b/Documentation/RelNotes-1.6.0.txt @@ -136,6 +136,9 @@ Updates since v1.5.6 * git-archive can be told to omit certain paths from its output using export-ignore attributes. +* git-archive uses the zlib default compression level when creating + zip archive. + * With -v option, git-branch describes the remote tracking statistics similar to the way git-checkout reports by how many commits your branch is ahead/behind. @@ -155,6 +158,8 @@ Updates since v1.5.6 * git-clone can clone from a remote whose URL would be rewritten by configuration stored in $HOME/.gitconfig now. +* git-cvsserver learned to respond to "cvs co -c". + * git-diff --check now checks leftover merge conflict markers. * When remote side used to have branch 'foo' and git-fetch finds that now @@ -166,6 +171,8 @@ Updates since v1.5.6 * fast-export learned to export and import marks file; this can be used to interface with fast-import incrementally. +* fast-import and fast-export learned to export and import gitlinks. + * git-rebase records the original tip of branch in ORIG_HEAD before it is rewound. @@ -210,6 +217,6 @@ this release, unless otherwise noted. --- exec >/var/tmp/1 -O=v1.5.6.3-436-g1f8dc67 +O=v1.5.6.4-432-g6796399 echo O=$(git describe refs/heads/master) git shortlog --no-merges $O..refs/heads/master ^refs/heads/maint diff --git a/Documentation/git.txt b/Documentation/git.txt index 27b9d31f7e..44ea35e949 100644 --- a/Documentation/git.txt +++ b/Documentation/git.txt @@ -43,12 +43,13 @@ unreleased) version of git, that is available from 'master' branch of the `git.git` repository. Documentation for older releases are available here: -* link:v1.5.6.3/git.html[documentation for release 1.5.6.3] +* link:v1.5.6.4/git.html[documentation for release 1.5.6.4] * release notes for - link:RelNotes-1.5.6.3.txt[1.5.6.3]. - link:RelNotes-1.5.6.2.txt[1.5.6.2]. - link:RelNotes-1.5.6.1.txt[1.5.6.1]. + link:RelNotes-1.5.6.4.txt[1.5.6.4], + link:RelNotes-1.5.6.3.txt[1.5.6.3], + link:RelNotes-1.5.6.2.txt[1.5.6.2], + link:RelNotes-1.5.6.1.txt[1.5.6.1], link:RelNotes-1.5.6.txt[1.5.6]. * link:v1.5.5.4/git.html[documentation for release 1.5.5.4]