From 8371234ecaaf6e14fe3f2082a855eff1bbd79ae9 Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Wed, 13 Dec 2006 05:42:44 -0500 Subject: [PATCH 1/7] Remove uncontested renamed files during merge. Prior to 65ac6e9c3f47807cb603af07a6a9e1a43bc119ae we deleted a file from the working directory during a merge if the file existed before the merge started but was renamed by the branch being merged in. This broke in 65ac6e as git-merge-recursive did not actually update the working directory on an uncontested rename. Signed-off-by: Shawn O. Pearce Signed-off-by: Junio C Hamano --- merge-recursive.c | 2 +- t/t6023-merge-rename-nocruft.sh | 97 +++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 1 deletion(-) create mode 100755 t/t6023-merge-rename-nocruft.sh diff --git a/merge-recursive.c b/merge-recursive.c index 32e186c15e..866a4e480b 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -889,7 +889,7 @@ static int process_renames(struct path_list *a_renames, struct diff_filespec src_other, dst_other; int try_merge, stage = a_renames == renames1 ? 3: 2; - remove_file(1, ren1_src, 1); + remove_file(1, ren1_src, index_only); hashcpy(src_other.sha1, ren1->src_entry->stages[stage].sha); src_other.mode = ren1->src_entry->stages[stage].mode; diff --git a/t/t6023-merge-rename-nocruft.sh b/t/t6023-merge-rename-nocruft.sh new file mode 100755 index 0000000000..69c66cf6fa --- /dev/null +++ b/t/t6023-merge-rename-nocruft.sh @@ -0,0 +1,97 @@ +#!/bin/sh + +test_description='Merge-recursive merging renames' +. ./test-lib.sh + +test_expect_success setup \ +' +cat >A <<\EOF && +a aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +b bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +c cccccccccccccccccccccccccccccccccccccccccccccccc +d dddddddddddddddddddddddddddddddddddddddddddddddd +e eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +f ffffffffffffffffffffffffffffffffffffffffffffffff +g gggggggggggggggggggggggggggggggggggggggggggggggg +h hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh +i iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii +j jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj +k kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk +l llllllllllllllllllllllllllllllllllllllllllllllll +m mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm +n nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn +o oooooooooooooooooooooooooooooooooooooooooooooooo +EOF + +cat >M <<\EOF && +A AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +B BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB +C CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC +D DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD +E EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE +F FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +G GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG +H HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH +I IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII +J JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ +K KKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK +L LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL +M MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM +N NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN +O OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO +EOF + +git add A M && +git commit -m "initial has A and M" && +git branch white && +git branch red && + +git checkout white && +sed -e "/^g /s/.*/g : white changes a line/" B && +sed -e "/^G /s/.*/G : colored branch changes a line/" N && +rm -f A M && +git update-index --add --remove A B M N && +git commit -m "white renames A->B, M->N" && + +git checkout red && +echo created by red >R && +git update-index --add R && +git commit -m "red creates R" && + +git checkout master' + +# This test broke in 65ac6e9c3f47807cb603af07a6a9e1a43bc119ae +test_expect_success 'merge white into red (A->B,M->N)' \ +' + git checkout -b red-white red && + git merge white && + git write-tree >/dev/null || { + echo "BAD: merge did not complete" + return 1 + } + + test -f B || { + echo "BAD: B does not exist in working directory" + return 1 + } + test -f N || { + echo "BAD: N does not exist in working directory" + return 1 + } + test -f R || { + echo "BAD: R does not exist in working directory" + return 1 + } + + test -f A && { + echo "BAD: A still exists in working directory" + return 1 + } + test -f M && { + echo "BAD: M still exists in working directory" + return 1 + } + return 0 +' + +test_done From 0c4e95d083f77de03a64b65f5633ed0ba082a26e Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 13 Dec 2006 09:32:40 -0800 Subject: [PATCH 2/7] git merge: reword failure message. 99.9999% of the time, the command is used with a single strategy; after a merge failure, saying "No strategy handled the merge" is technically correct, but there is no point stressing we tried and failed all the possibilities the user has given. Just say that it failed. Signed-off-by: Junio C Hamano --- git-merge.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/git-merge.sh b/git-merge.sh index a948878b91..2f3d936b9c 100755 --- a/git-merge.sh +++ b/git-merge.sh @@ -400,7 +400,14 @@ fi case "$best_strategy" in '') restorestate - echo >&2 "No merge strategy handled the merge." + case "$use_strategies" in + ?*' '?*) + echo >&2 "No merge strategy handled the merge." + ;; + *) + echo >&2 "Merge with strategy $use_strategies failed." + ;; + esac exit 2 ;; "$wt_strategy") From 7ef0435088f41165ece95b6f226d3c15438505a5 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 13 Dec 2006 00:58:28 -0800 Subject: [PATCH 3/7] spurious .sp in manpages This is just a random hack to work around problems people seem to be seeing in manpage backend of xmlto (it appears we are getting ".sp" at the end of line without line break). Could people test this out? Signed-off-by: Junio C Hamano --- Documentation/callouts.xsl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/callouts.xsl b/Documentation/callouts.xsl index ad03755d8f..6a361a2136 100644 --- a/Documentation/callouts.xsl +++ b/Documentation/callouts.xsl @@ -13,4 +13,18 @@ .br + + + + + + + + + + + + From 411fb8baa6862b76f7bdd9fc0d5844855a4db589 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 13 Dec 2006 10:03:39 -0800 Subject: [PATCH 4/7] git-push: accept tag as advertised. The documentation talked about "git push $URL tag " as a short-hand for refs/tags/:refs/tags/ for a long time but that was never the case (the short-hand was for "git fetch"). Instead of fixing the documentation, just add a bit of code to match it since it is easy to do and would make it more consistent. Signed-off-by: Junio C Hamano --- builtin-push.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/builtin-push.c b/builtin-push.c index d23974e708..b7412e8293 100644 --- a/builtin-push.c +++ b/builtin-push.c @@ -57,11 +57,36 @@ static void expand_refspecs(void) static void set_refspecs(const char **refs, int nr) { if (nr) { - size_t bytes = nr * sizeof(char *); - - refspec = xrealloc(refspec, bytes); - memcpy(refspec, refs, bytes); - refspec_nr = nr; + int pass; + for (pass = 0; pass < 2; pass++) { + /* pass 0 counts and allocates, pass 1 fills */ + int i, cnt; + for (i = cnt = 0; i < nr; i++) { + if (!strcmp("tag", refs[i])) { + int len; + char *tag; + if (nr <= ++i) + die("tag shorthand without "); + if (pass) { + len = strlen(refs[i]) + 11; + tag = xmalloc(len); + strcpy(tag, "refs/tags/"); + strcat(tag, refs[i]); + refspec[cnt] = tag; + } + cnt++; + continue; + } + if (pass) + refspec[cnt] = refs[i]; + cnt++; + } + if (!pass) { + size_t bytes = cnt * sizeof(char *); + refspec_nr = cnt; + refspec = xrealloc(refspec, bytes); + } + } } expand_refspecs(); } From 37adac765a469f8f8495e2befe7afeda65a2b272 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 13 Dec 2006 10:30:11 -0800 Subject: [PATCH 5/7] send-pack: tighten checks for remote names "git push $URL HEAD~6" created a bogus ref HEAD~6 immediately under $GIT_DIR of the remote repository. While we should keep refspecs that have arbitrary extended SHA-1 expression on the source side working (e.g. "HEAD~6:refs/tags/yesterday"), we should not create bogus ref on the other end. Signed-off-by: Junio C Hamano --- refs.c | 2 +- send-pack.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/refs.c b/refs.c index 96ea8b6907..e56abb8585 100644 --- a/refs.c +++ b/refs.c @@ -534,7 +534,7 @@ int check_ref_format(const char *ref) level++; if (!ch) { if (level < 2) - return -1; /* at least of form "heads/blah" */ + return -2; /* at least of form "heads/blah" */ return 0; } } diff --git a/send-pack.c b/send-pack.c index 328dbbc16a..cc884f3b2d 100644 --- a/send-pack.c +++ b/send-pack.c @@ -406,6 +406,25 @@ static int send_pack(int in, int out, int nr_refspec, char **refspec) return ret; } +static void verify_remote_names(int nr_heads, char **heads) +{ + int i; + + for (i = 0; i < nr_heads; i++) { + const char *remote = strchr(heads[i], ':'); + + remote = remote ? (remote + 1) : heads[i]; + switch (check_ref_format(remote)) { + case 0: /* ok */ + case -2: /* ok but a single level -- that is fine for + * a match pattern. + */ + continue; + } + die("remote part of refspec is not a valid name in %s", + heads[i]); + } +} int main(int argc, char **argv) { @@ -457,6 +476,8 @@ int main(int argc, char **argv) usage(send_pack_usage); if (heads && send_all) usage(send_pack_usage); + verify_remote_names(nr_heads, heads); + pid = git_connect(fd, dest, exec); if (pid < 0) return 1; From 753f96a455534ad60b670376fb3d89179281e541 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 13 Dec 2006 10:55:21 -0800 Subject: [PATCH 6/7] branch --color: change default color selection. Showing local and remote branches in green and red was simply overkill, as all we wanted was to make it easy to tell them apart (local ones can be built on top by committing, but the remote tracking ones can't). Use plain coloring for local branches and paint remotes in red. Signed-off-by: Junio C Hamano --- builtin-branch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builtin-branch.c b/builtin-branch.c index 7c87b8d579..d1c243d372 100644 --- a/builtin-branch.c +++ b/builtin-branch.c @@ -23,8 +23,8 @@ static char branch_colors[][COLOR_MAXLEN] = { "\033[m", /* reset */ "", /* PLAIN (normal) */ "\033[31m", /* REMOTE (red) */ - "\033[32m", /* LOCAL (green) */ - "\033[1;32m", /* CURRENT (boldgreen) */ + "", /* LOCAL (normal) */ + "\033[32m", /* CURRENT (green) */ }; enum color_branch { COLOR_BRANCH_RESET = 0, From b11121d9e330c40f5d089636f176d089e5bb1885 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 1 Dec 2006 20:45:45 -0800 Subject: [PATCH 7/7] git-blame: show lines attributed to boundary commits differently. When blaming with revision ranges, often many lines are attributed to different commits at the boundary, but they are not interesting for the purpose of finding project history during that revision range. This outputs the lines blamed on boundary commits differently. When showing "human format" output, their SHA-1 are shown with '^' prefixed. In "porcelain format", the commit will be shown with an extra attribute line "boundary". Signed-off-by: Junio C Hamano --- builtin-blame.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/builtin-blame.c b/builtin-blame.c index dc3ffeaff8..a250724463 100644 --- a/builtin-blame.c +++ b/builtin-blame.c @@ -1090,6 +1090,11 @@ static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt) if (!(commit->object.flags & UNINTERESTING) && !(revs->max_age != -1 && commit->date < revs->max_age)) pass_blame(sb, suspect, opt); + else { + commit->object.flags |= UNINTERESTING; + if (commit->object.parsed) + mark_parents_uninteresting(commit); + } /* Take responsibility for the remaining entries */ for (ent = sb->ent; ent; ent = ent->next) @@ -1273,6 +1278,8 @@ static void emit_porcelain(struct scoreboard *sb, struct blame_entry *ent) printf("committer-tz %s\n", ci.committer_tz); printf("filename %s\n", suspect->path); printf("summary %s\n", ci.summary); + if (suspect->commit->object.flags & UNINTERESTING) + printf("boundary\n"); } else if (suspect->commit->object.flags & MORE_THAN_ONE_PATH) printf("filename %s\n", suspect->path); @@ -1308,8 +1315,14 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt) cp = nth_line(sb, ent->lno); for (cnt = 0; cnt < ent->num_lines; cnt++) { char ch; + int length = (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8; - printf("%.*s", (opt & OUTPUT_LONG_OBJECT_NAME) ? 40 : 8, hex); + if (suspect->commit->object.flags & UNINTERESTING) { + length--; + putchar('^'); + } + + printf("%.*s", length, hex); if (opt & OUTPUT_ANNOTATE_COMPAT) printf("\t(%10s\t%10s\t%d)", ci.author, format_time(ci.author_time, ci.author_tz,