From a7fb51d3d4d303d61831b2fe5127a088b050e60b Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 12 Nov 2005 01:25:33 -0800 Subject: [PATCH 01/10] remove shellquote usage for tags use ',' to encode '/' in "archivename/foo--bar--0.0" so we can allow "--branch"-less trees which are valid in Arch ("archivename/foo--0.0") Signed-off-by: Eric Wong Signed-off-by: Martin Langhoff --- git-archimport.perl | 55 +++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/git-archimport.perl b/git-archimport.perl index 23becb7962..b7c1fbf0ca 100755 --- a/git-archimport.perl +++ b/git-archimport.perl @@ -52,6 +52,7 @@ $ENV{'TZ'}="UTC"; my $git_dir = $ENV{"GIT_DIR"} || ".git"; $ENV{"GIT_DIR"} = $git_dir; +my $ptag_dir = "$git_dir/archimport/tags"; our($opt_h,$opt_v, $opt_T, $opt_C,$opt_t); @@ -195,16 +196,19 @@ unless (-d $git_dir) { # initial import opendir(DIR, "$git_dir/archimport/tags") || die "can't opendir: $!"; while (my $file = readdir(DIR)) { - # skip non-interesting-files - next unless -f "$git_dir/archimport/tags/$file"; - next if $file =~ m/--base-0$/; # don't care for base-0 + # skip non-interesting-files + next unless -f "$ptag_dir/$file"; + + # convert first '--' to '/' from old git-archimport to use + # as an archivename/c--b--v private tag + if ($file !~ m!,!) { + my $oldfile = $file; + $file =~ s!--!,!; + print STDERR "converting old tag $oldfile to $file\n"; + rename("$ptag_dir/$oldfile", "$ptag_dir/$file") or die $!; + } my $sha = ptag($file); chomp $sha; - # reconvert the 3rd '--' sequence from the end - # into a slash - # $file = reverse $file; - # $file =~ s!^(.+?--.+?--.+?--.+?)--(.+)$!$1/$2!; - # $file = reverse $file; $rptags{$sha} = $file; } closedir DIR; @@ -581,19 +585,20 @@ sub parselog { # write/read a tag sub tag { my ($tag, $commit) = @_; - $tag =~ s|/|--|g; - $tag = shell_quote($tag); + + # don't use subdirs for tags yet, it could screw up other porcelains + $tag =~ s|/|,|; if ($commit) { - open(C,">$git_dir/refs/tags/$tag") + open(C,">","$git_dir/refs/tags/$tag") or die "Cannot create tag $tag: $!\n"; print C "$commit\n" or die "Cannot write tag $tag: $!\n"; close(C) or die "Cannot write tag $tag: $!\n"; - print " * Created tag ' $tag' on '$commit'\n" if $opt_v; + print " * Created tag '$tag' on '$commit'\n" if $opt_v; } else { # read - open(C,"<$git_dir/refs/tags/$tag") + open(C,"<","$git_dir/refs/tags/$tag") or die "Cannot read tag $tag: $!\n"; $commit = ; chomp $commit; @@ -608,15 +613,16 @@ sub tag { # reads fail softly if the tag isn't there sub ptag { my ($tag, $commit) = @_; - $tag =~ s|/|--|g; - $tag = shell_quote($tag); + + # don't use subdirs for tags yet, it could screw up other porcelains + $tag =~ s|/|,|g; - unless (-d "$git_dir/archimport/tags") { - mkpath("$git_dir/archimport/tags"); - } + my $tag_file = "$ptag_dir/$tag"; + my $tag_branch_dir = dirname($tag_file); + mkpath($tag_branch_dir) unless (-d $tag_branch_dir); if ($commit) { # write - open(C,">$git_dir/archimport/tags/$tag") + open(C,">",$tag_file) or die "Cannot create tag $tag: $!\n"; print C "$commit\n" or die "Cannot write tag $tag: $!\n"; @@ -626,10 +632,10 @@ sub ptag { unless $tag =~ m/--base-0$/; } else { # read # if the tag isn't there, return 0 - unless ( -s "$git_dir/archimport/tags/$tag") { + unless ( -s $tag_file) { return 0; } - open(C,"<$git_dir/archimport/tags/$tag") + open(C,"<",$tag_file) or die "Cannot read tag $tag: $!\n"; $commit = ; chomp $commit; @@ -779,12 +785,7 @@ sub commitid2pset { chomp $commitid; my $name = $rptags{$commitid} || die "Cannot find reverse tag mapping for $commitid"; - # the keys in %rptag are slightly munged; unmunge - # reconvert the 3rd '--' sequence from the end - # into a slash - $name = reverse $name; - $name =~ s!^(.+?--.+?--.+?--.+?)--(.+)$!$1/$2!; - $name = reverse $name; + $name =~ s|,|/|; my $ps = $psets{$name} || (print Dumper(sort keys %psets)) && die "Cannot find patchset for $name"; return $ps; From 9b626e752eebcc49acab19085947e67b5e61e39f Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 12 Nov 2005 01:27:21 -0800 Subject: [PATCH 02/10] archimport: don't die on merge-base failure Don't die if we can't find a merge base, Arch allows arbitrary cherry-picks between unrelated branches and we should not die when that happens Signed-off-by: Eric Wong Signed-off-by: Martin Langhoff --- git-archimport.perl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/git-archimport.perl b/git-archimport.perl index b7c1fbf0ca..d8e6f4e448 100755 --- a/git-archimport.perl +++ b/git-archimport.perl @@ -692,7 +692,13 @@ sub find_parents { next unless -e "$git_dir/refs/heads/$branch"; my $mergebase = `git-merge-base $branch $ps->{branch}`; - die "Cannot find merge base for $branch and $ps->{branch}" if $?; + if ($?) { + # Don't die here, Arch supports one-way cherry-picking + # between branches with no common base (or any relationship + # at all beforehand) + warn "Cannot find merge base for $branch and $ps->{branch}"; + next; + } chomp $mergebase; # now walk up to the mergepoint collecting what patches we have From 22ff00fc8bde65414653ed139fd13d90f00fe662 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 12 Nov 2005 01:29:20 -0800 Subject: [PATCH 03/10] Disambiguate the term 'branch' in Arch vs git Disambiguate the term 'branch' in Arch vs git, and start using fully-qualified names. Signed-off-by: Eric Wong Signed-off-by: Martin Langhoff --- git-archimport.perl | 65 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/git-archimport.perl b/git-archimport.perl index d8e6f4e448..47174391a7 100755 --- a/git-archimport.perl +++ b/git-archimport.perl @@ -30,6 +30,24 @@ See man (1) git-archimport for more details. Add print in front of the shell commands invoked via backticks. +=head1 Devel Notes + +There are several places where Arch and git terminology are intermixed +and potentially confused. + +The notion of a "branch" in git is approximately equivalent to +a "archive/category--branch--version" in Arch. Also, it should be noted +that the "--branch" portion of "archive/category--branch--version" is really +optional in Arch although not many people (nor tools!) seem to know this. +This means that "archive/category--version" is also a valid "branch" +in git terms. + +We always refer to Arch names by their fully qualified variant (which +means the "archive" name is prefixed. + +For people unfamiliar with Arch, an "archive" is the term for "repository", +and can contain multiple, unrelated branches. + =cut use strict; @@ -215,9 +233,41 @@ unless (-d $git_dir) { # initial import } # process patchsets -foreach my $ps (@psets) { +# extract the Arch repository name (Arch "archive" in Arch-speak) +sub extract_reponame { + my $fq_cvbr = shift; # archivename/[[[[category]branch]version]revision] + return (split(/\//, $fq_cvbr))[0]; +} + +sub extract_versionname { + my $name = shift; + $name =~ s/--(?:patch|version(?:fix)?|base)-\d+$//; + return $name; +} - $ps->{branch} = branchname($ps->{id}); +# convert a fully-qualified revision or version to a unique dirname: +# normalperson@yhbt.net-05/mpd--uclinux--1--patch-2 +# becomes: normalperson@yhbt.net-05,mpd--uclinux--1 +# +# the git notion of a branch is closer to +# archive/category--branch--version than archive/category--branch, so we +# use this to convert to git branch names. +# Also, keep archive names but replace '/' with ',' since it won't require +# subdirectories, and is safer than swapping '--' which could confuse +# reverse-mapping when dealing with bastard branches that +# are just archive/category--version (no --branch) +sub tree_dirname { + my $revision = shift; + my $name = extract_versionname($revision); + $name =~ s#/#,#; + return $name; +} + +*git_branchname = *tree_dirname; + +# process patchsets +foreach my $ps (@psets) { + $ps->{branch} = git_branchname($ps->{id}); # # ensure we have a clean state @@ -428,16 +478,9 @@ foreach my $ps (@psets) { $opt_v && print " + parents: $par \n"; } -sub branchname { - my $id = shift; - $id =~ s#^.+?/##; - my @parts = split(m/--/, $id); - return join('--', @parts[0..1]); -} - sub apply_import { my $ps = shift; - my $bname = branchname($ps->{id}); + my $bname = git_branchname($ps->{id}); `mkdir -p $tmp`; @@ -668,7 +711,7 @@ sub find_parents { # simple loop to split the merges # per branch foreach my $merge (@{$ps->{merges}}) { - my $branch = branchname($merge); + my $branch = git_branchname($merge); unless (defined $branches{$branch} ){ $branches{$branch} = []; } From fee3365fe13f36fdd432b1ede9980062cf744663 Mon Sep 17 00:00:00 2001 From: Martin Langhoff Date: Thu, 17 Nov 2005 21:20:45 +1300 Subject: [PATCH 04/10] archimport: allow for old style branch and public tag names This patch adds the -o switch, which lets old trees tracked by git-archmirror continue working with their old branch and tag names to make life easier for people tracking your tree. Private tags that are only used internally by git-archimport continue to be new-style, and automatically converted upon first run. [ ml: rebased to skip import overhaul ] Signed-off-by:: Eric Wong Signed-off-by: Martin Langhoff --- git-archimport.perl | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/git-archimport.perl b/git-archimport.perl index 47174391a7..c3bed08086 100755 --- a/git-archimport.perl +++ b/git-archimport.perl @@ -72,13 +72,12 @@ my $git_dir = $ENV{"GIT_DIR"} || ".git"; $ENV{"GIT_DIR"} = $git_dir; my $ptag_dir = "$git_dir/archimport/tags"; -our($opt_h,$opt_v, $opt_T, - $opt_C,$opt_t); +our($opt_h,$opt_v, $opt_T,$opt_t,$opt_o); sub usage() { print STDERR < part: +sub old_style_branchname { + my $id = shift; + my $ret = safe_pipe_capture($TLA,'parse-package-name','-p',$id); + chomp $ret; + return $ret; +} + +*git_branchname = $opt_o ? *old_style_branchname : *tree_dirname; # process patchsets foreach my $ps (@psets) { @@ -629,8 +636,12 @@ sub parselog { sub tag { my ($tag, $commit) = @_; - # don't use subdirs for tags yet, it could screw up other porcelains - $tag =~ s|/|,|; + if ($opt_o) { + $tag =~ s|/|--|g; + } else { + # don't use subdirs for tags yet, it could screw up other porcelains + $tag =~ s|/|,|g; + } if ($commit) { open(C,">","$git_dir/refs/tags/$tag") From 3200d1aee0c22a34d075aafefe3e92f4f7d08840 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 17 Nov 2005 20:46:29 -0800 Subject: [PATCH 05/10] Deal with binary diff output from GNU diff 2.8.7 Some vintage of diff says just "Files X and Y differ\n", instead of "Binary files X and Y differ\n", so catch both patterns. Signed-off-by: Junio C Hamano --- apply.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/apply.c b/apply.c index 129edb1889..50be8f3e22 100644 --- a/apply.c +++ b/apply.c @@ -893,12 +893,24 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch) patchsize = parse_single_patch(buffer + offset + hdrsize, size - offset - hdrsize, patch); if (!patchsize) { - static const char binhdr[] = "Binary files "; - - if (sizeof(binhdr) - 1 < size - offset - hdrsize && - !memcmp(binhdr, buffer + hdrsize + offset, - sizeof(binhdr)-1)) - patch->is_binary = 1; + static const char *binhdr[] = { + "Binary files ", + "Files ", + NULL, + }; + int i; + int hd = hdrsize + offset; + unsigned long llen = linelen(buffer + hd, size - hd); + + if (!memcmp(" differ\n", buffer + hd + llen - 8, 8)) + for (i = 0; binhdr[i]; i++) { + int len = strlen(binhdr[i]); + if (len < size - hd && + !memcmp(binhdr[i], buffer + hd, len)) { + patch->is_binary = 1; + break; + } + } /* Empty patch cannot be applied if: * - it is a binary patch and we do not do binary_replace, or From d2ac1cd263d1856938b5223ef96d8b1eb7db4ccd Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Thu, 17 Nov 2005 10:40:22 -0500 Subject: [PATCH 06/10] 'make clean' forgot about some files Signed-off-by: Nicolas Pitre Signed-off-by: Junio C Hamano --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ebff990b58..3bdd0597c1 100644 --- a/Makefile +++ b/Makefile @@ -466,7 +466,7 @@ deb: dist ### Cleaning rules clean: - rm -f *.o mozilla-sha1/*.o ppc/*.o compat/*.o $(PROGRAMS) $(LIB_FILE) + rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o git $(PROGRAMS) $(LIB_FILE) rm -f $(filter-out gitk,$(SCRIPTS)) rm -f *.spec *.pyc *.pyo rm -rf $(GIT_TARNAME) From 0adb3358f6538aaa9006f4068d6757cd506afcdd Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 17 Nov 2005 14:34:47 +0000 Subject: [PATCH 07/10] git-repack: Fix variable name Three times remove_redandant -> remove_redundant. Signed-off-by: Ralf Baechle Signed-off-by: Junio C Hamano --- git-repack.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/git-repack.sh b/git-repack.sh index f34720701b..e58fdd6d87 100755 --- a/git-repack.sh +++ b/git-repack.sh @@ -11,7 +11,7 @@ do case "$1" in -n) no_update_info=t ;; -a) all_into_one=t ;; - -d) remove_redandant=t ;; + -d) remove_redundant=t ;; -l) local=t ;; *) break ;; esac @@ -42,7 +42,7 @@ name=$(git-rev-list --objects $rev_list $(git-rev-parse $rev_parse) | exit 1 if [ -z "$name" ]; then echo Nothing new to pack. - if test "$remove_redandant" = t ; then + if test "$remove_redundant" = t ; then echo "Removing redundant packs." sync redundant=$(git-pack-redundant --all) @@ -60,7 +60,7 @@ mv .tmp-pack-$name.pack "$PACKDIR/pack-$name.pack" && mv .tmp-pack-$name.idx "$PACKDIR/pack-$name.idx" || exit -if test "$remove_redandant" = t +if test "$remove_redundant" = t then sync redundant=$(git-pack-redundant --all) From 751a71e2b5f3667ab7ffffccad3e2b58726eb1c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20Sandstr=C3=B6m?= Date: Thu, 17 Nov 2005 14:11:56 +0100 Subject: [PATCH 08/10] Make git-pack-redundant non-horribly slow on large sets of packs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the smallest-set detection algortithm so that when we have found a good set, we don't check any larger sets. Signed-off-by: Lukas Sandström Signed-off-by: Junio C Hamano --- pack-redundant.c | 60 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/pack-redundant.c b/pack-redundant.c index fcb36ff901..51d7341b0b 100644 --- a/pack-redundant.c +++ b/pack-redundant.c @@ -33,6 +33,7 @@ struct pack_list { struct pll { struct pll *next; struct pack_list *pl; + size_t pl_size; }; inline void llist_free(struct llist *list) @@ -249,18 +250,45 @@ void cmp_two_packs(struct pack_list *p1, struct pack_list *p2) } } +void pll_insert(struct pll **pll, struct pll **hint_table) +{ + struct pll *prev; + int i = (*pll)->pl_size - 1; + + if (hint_table[i] == NULL) { + hint_table[i--] = *pll; + for (; i >= 0; --i) { + if (hint_table[i] != NULL) + break; + } + if (hint_table[i] == NULL) /* no elements in list */ + die("Why did this happen?"); + } + + prev = hint_table[i]; + while (prev->next && prev->next->pl_size < (*pll)->pl_size) + prev = prev->next; + + (*pll)->next = prev->next; + prev->next = *pll; +} + /* all the permutations have to be free()d at the same time, * since they refer to each other */ struct pll * get_all_permutations(struct pack_list *list) { struct pll *subset, *pll, *new_pll = NULL; /*silence warning*/ - + static struct pll **hint = NULL; + if (hint == NULL) + hint = xcalloc(pack_list_size(list), sizeof(struct pll *)); + if (list == NULL) return NULL; if (list->next == NULL) { new_pll = xmalloc(sizeof(struct pll)); + hint[0] = new_pll; new_pll->next = NULL; new_pll->pl = list; return new_pll; @@ -268,24 +296,30 @@ struct pll * get_all_permutations(struct pack_list *list) pll = subset = get_all_permutations(list->next); while (pll) { + if (pll->pl->pack == list->pack) { + pll = pll->next; + continue; + } new_pll = xmalloc(sizeof(struct pll)); - new_pll->next = pll->next; - pll->next = new_pll; new_pll->pl = xmalloc(sizeof(struct pack_list)); memcpy(new_pll->pl, list, sizeof(struct pack_list)); new_pll->pl->next = pll->pl; + new_pll->pl_size = pll->pl_size + 1; + + pll_insert(&new_pll, hint); - pll = new_pll->next; + pll = pll->next; } - /* add ourself to the end */ - new_pll->next = xmalloc(sizeof(struct pll)); - new_pll->next->pl = xmalloc(sizeof(struct pack_list)); - new_pll->next->next = NULL; - memcpy(new_pll->next->pl, list, sizeof(struct pack_list)); - new_pll->next->pl->next = NULL; - - return subset; + /* add ourself */ + new_pll = xmalloc(sizeof(struct pll)); + new_pll->pl = xmalloc(sizeof(struct pack_list)); + memcpy(new_pll->pl, list, sizeof(struct pack_list)); + new_pll->pl->next = NULL; + new_pll->pl_size = 1; + pll_insert(&new_pll, hint); + + return hint[0]; } int is_superset(struct pack_list *pl, struct llist *list) @@ -401,6 +435,8 @@ void minimize(struct pack_list **min) /* find the permutations which contain all missing objects */ perm_all = perm = get_all_permutations(non_unique); while (perm) { + if (perm_ok && perm->pl_size > perm_ok->pl_size) + break; /* ignore all larger permutations */ if (is_superset(perm->pl, missing)) { new_perm = xmalloc(sizeof(struct pll)); new_perm->pl = perm->pl; From 6b7b0427728fe31ee2d9375a36f1c27974432979 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 17 Nov 2005 12:36:30 -0800 Subject: [PATCH 09/10] Teach "approxidate" about weekday syntax This allows people to use syntax like "last thursday" for the approxidate. (Or, indeed, more complex "three thursdays ago", but I suspect that would be pretty unusual). NOTE! The parsing is strictly sequential, so if you do "one day before last thursday" it will _not_ do what you think it does. It will take the current time, subtract one day, and then go back to the thursday before that. So to get what you want, you'd have to write it the other way around: "last thursday and one day before" which is insane (it's usually the same as "last wednesday" _except_ if today is Thursday, in which case "last wednesday" is yesterday, and "last thursday and one day before" is eight days ago). Similarly, "last thursday one month ago" will first go back to last thursday, and then go back one month from there, not the other way around. I doubt anybody would ever use insane dates like that, but I thought I'd point out that the approxidate parsing is not exactly "standard English". Side note 2: if you want to avoid spaces (because of quoting issues), you can use any non-alphanumberic character instead. So git log --since=2.days.ago works without any quotes. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- date.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/date.c b/date.c index 73c063b9ab..d2a67ccf07 100644 --- a/date.c +++ b/date.c @@ -34,7 +34,7 @@ static const char *month_names[] = { }; static const char *weekday_names[] = { - "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" + "Sundays", "Mondays", "Tuesdays", "Wednesdays", "Thursdays", "Fridays", "Saturdays" }; /* @@ -531,6 +531,22 @@ static const char *approxidate_alpha(const char *date, struct tm *tm, int *num) tl++; } + for (i = 0; i < 7; i++) { + int match = match_string(date, weekday_names[i]); + if (match >= 3) { + int diff, n = *num -1; + *num = 0; + + diff = tm->tm_wday - i; + if (diff <= 0) + n++; + diff += 7*n; + + update_tm(tm, diff * 24 * 60 * 60); + return end; + } + } + if (match_string(date, "months") >= 5) { int n = tm->tm_mon - *num; *num = 0; From 087b6742fcab74f7a53626b98969bed27d288e2b Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 16 Nov 2005 16:46:24 -0800 Subject: [PATCH 10/10] git-am: --binary; document --resume and --binary. Now git-apply can grok binary replacement patches, give --binary flag to git-am. As a safety measure, this is not by default enabled, so that you do not let malicious e-mailed patch to replace an arbitrary path with just a couple of lines (diff index lines, the filename and string "Binary files "...) by accident. Signed-off-by: Junio C Hamano --- Documentation/git-am.txt | 24 ++++++++++++++++-------- git-am.sh | 20 ++++++++++++++------ 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt index e4df4a46ec..1ceed112f2 100644 --- a/Documentation/git-am.txt +++ b/Documentation/git-am.txt @@ -8,8 +8,8 @@ git-am - Apply a series of patches in a mailbox SYNOPSIS -------- -'git-am' [--signoff] [--dotest=] [--utf8] [--3way] ... -'git-am' [--skip] +'git-am' [--signoff] [--dotest=] [--utf8] [--binary] [--3way] ... +'git-am' [--skip | --resolved] DESCRIPTION ----------- @@ -31,6 +31,10 @@ OPTIONS Pass `--utf8` and `--keep` flags to `git-mailinfo` (see gitlink:git-mailinfo[1]). +--binary:: + Pass `--allow-binary-replacement` flag to `git-apply` + (see gitlink:git-apply[1]). + --3way:: When the patch does not apply cleanly, fall back on 3-way merge, if the patch records the identity of blobs @@ -44,6 +48,13 @@ OPTIONS --interactive:: Run interactively, just like git-applymbox. +--resolved:: + After a patch failure (e.g. attempting to apply + conflicting patch), the user has applied it by hand and + the index file stores the result of the application. + Make a commit using the authorship and commit log + extracted from the e-mail message and the current index + file, and continue. DISCUSSION ---------- @@ -56,12 +67,9 @@ recover from this in one of two ways: . skip the current one by re-running the command with '--skip' option. -. hand resolve the conflict in the working directory, run 'git - diff HEAD' to extract the merge result into a patch form and - replacing the patch in .dotest/patch file. After doing this, - run `git-reset --hard HEAD` to bring the working tree to the - state before half-applying the patch, then re-run the command - without any options. +. hand resolve the conflict in the working directory, and update + the index file to bring it in a state that the patch should + have produced. Then run the command with '--resume' option. The command refuses to process new mailboxes while `.dotest` directory exists, so if you decide to start over from scratch, diff --git a/git-am.sh b/git-am.sh index 98a390ab45..8f073c90f6 100755 --- a/git-am.sh +++ b/git-am.sh @@ -4,7 +4,7 @@ . git-sh-setup || die "Not a git archive" usage () { - echo >&2 "usage: $0 [--signoff] [--dotest=] [--utf8] [--3way] " + echo >&2 "usage: $0 [--signoff] [--dotest=] [--utf8] [--binary] [--3way] " echo >&2 " or, when resuming" echo >&2 " $0 [--skip | --resolved]" exit 1; @@ -40,7 +40,7 @@ fall_back_3way () { cd "$dotest/patch-merge-tmp-dir" && GIT_INDEX_FILE="../patch-merge-tmp-index" \ GIT_OBJECT_DIRECTORY="$O_OBJECT" \ - git-apply --index <../patch + git-apply $binary --index <../patch ) then echo Using index info to reconstruct a base tree... @@ -71,7 +71,7 @@ fall_back_3way () { GIT_OBJECT_DIRECTORY="$O_OBJECT" && export GIT_INDEX_FILE GIT_OBJECT_DIRECTORY && git-read-tree "$base" && - git-apply --index && + git-apply $binary --index && mv ../patch-merge-tmp-index ../patch-merge-index && echo "$base" >../patch-merge-base ) <"$dotest/patch" 2>/dev/null && break @@ -98,7 +98,7 @@ fall_back_3way () { } prec=4 -dotest=.dotest sign= utf8= keep= skip= interactive= resolved= +dotest=.dotest sign= utf8= keep= skip= interactive= resolved= binary= while case "$#" in 0) break;; esac do @@ -113,6 +113,9 @@ do --interacti|--interactiv|--interactive) interactive=t; shift ;; + -b|--b|--bi|--bin|--bina|--binar|--binary) + binary=t; shift ;; + -3|--3|--3w|--3wa|--3way) threeway=t; shift ;; -s|--s|--si|--sig|--sign|--signo|--signof|--signoff) @@ -169,9 +172,10 @@ else exit 1 } - # -s, -u and -k flags are kept for the resuming session after + # -b, -s, -u and -k flags are kept for the resuming session after # a patch failure. # -3 and -i can and must be given when resuming. + echo "$binary" >"$dotest/binary" echo "$sign" >"$dotest/sign" echo "$utf8" >"$dotest/utf8" echo "$keep" >"$dotest/keep" @@ -187,6 +191,10 @@ case "$resolved" in fi esac +if test "$(cat "$dotest/binary")" = t +then + binary=--allow-binary-replacement +fi if test "$(cat "$dotest/utf8")" = t then utf8=-u @@ -339,7 +347,7 @@ do case "$resolved" in '') - git-apply --index "$dotest/patch" + git-apply $binary --index "$dotest/patch" apply_status=$? ;; t)