Merge branch 'master'
diff --git a/Documentation/git-am.txt b/Documentation/git-am.txt
index e4df4a4..1ceed11 100644
--- a/Documentation/git-am.txt
+++ b/Documentation/git-am.txt
@@ -8,8 +8,8 @@
 
 SYNOPSIS
 --------
-'git-am' [--signoff] [--dotest=<dir>] [--utf8] [--3way] <mbox>...
-'git-am' [--skip]
+'git-am' [--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way] <mbox>...
+'git-am' [--skip | --resolved]
 
 DESCRIPTION
 -----------
@@ -31,6 +31,10 @@
 	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 @@
 --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 @@
 . 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/Makefile b/Makefile
index e5cf5ef..819c48c 100644
--- a/Makefile
+++ b/Makefile
@@ -466,7 +466,7 @@
 ### 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)
diff --git a/apply.c b/apply.c
index 129edb1..50be8f3 100644
--- a/apply.c
+++ b/apply.c
@@ -893,12 +893,24 @@
 	patchsize = parse_single_patch(buffer + offset + hdrsize, size - offset - hdrsize, patch);
 
 	if (!patchsize) {
-		static const char binhdr[] = "Binary files ";
+		static const char *binhdr[] = {
+			"Binary files ",
+			"Files ",
+			NULL,
+		};
+		int i;
+		int hd = hdrsize + offset;
+		unsigned long llen = linelen(buffer + hd, size - hd);
 
-		if (sizeof(binhdr) - 1 < size - offset - hdrsize &&
-		    !memcmp(binhdr, buffer + hdrsize + offset,
-			    sizeof(binhdr)-1))
-			patch->is_binary = 1;
+		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
diff --git a/date.c b/date.c
index 73c063b..d2a67cc 100644
--- a/date.c
+++ b/date.c
@@ -34,7 +34,7 @@
 };
 
 static const char *weekday_names[] = {
-	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
+	"Sundays", "Mondays", "Tuesdays", "Wednesdays", "Thursdays", "Fridays", "Saturdays"
 };
 
 /*
@@ -531,6 +531,22 @@
 		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;
diff --git a/git-am.sh b/git-am.sh
index 98a390a..8f073c9 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=<dir>] [--utf8] [--3way] <mbox>"
+    echo >&2 "usage: $0 [--signoff] [--dotest=<dir>] [--utf8] [--binary] [--3way] <mbox>"
     echo >&2 "	or, when resuming"
     echo >&2 "	$0 [--skip | --resolved]"
     exit 1;
@@ -40,7 +40,7 @@
 	    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 @@
 		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 @@
 }
 
 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 @@
 	--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 @@
 		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 @@
 	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 @@
 
 	case "$resolved" in
 	'')
-		git-apply --index "$dotest/patch"
+		git-apply $binary --index "$dotest/patch"
 		apply_status=$?
 		;;
 	t)
diff --git a/git-archimport.perl b/git-archimport.perl
index 23becb7..c3bed08 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -30,6 +30,24 @@
 
 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;
@@ -52,14 +70,14 @@
 
 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 <<END;
 Usage: ${\basename $0}     # fetch/update GIT from Arch
-       [ -h ] [ -v ] [ -T ] [ -t tempdir ] 
+       [ -o ] [ -h ] [ -v ] [ -T ] [ -t tempdir ] 
        repository/arch-branch [ repository/arch-branch] ...
 END
     exit(1);
@@ -195,25 +213,68 @@
     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;
 }
 
 # 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;
+}
+
+# old versions of git-archimport just use the <category--branch> 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) {
+    $ps->{branch} = git_branchname($ps->{id});
 
     #
     # ensure we have a clean state 
@@ -424,16 +485,9 @@
     $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`;
 
@@ -581,19 +635,24 @@
 # write/read a tag
 sub tag {
     my ($tag, $commit) = @_;
-    $tag =~ s|/|--|g; 
-    $tag = shell_quote($tag);
+ 
+    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")
+        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 = <C>;
         chomp $commit;
@@ -608,15 +667,16 @@
 # 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 +686,10 @@
 	    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 = <C>;
         chomp $commit;
@@ -662,7 +722,7 @@
     # 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} = [];
 	}
@@ -686,7 +746,13 @@
 	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
@@ -779,12 +845,7 @@
     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;
diff --git a/git-repack.sh b/git-repack.sh
index f347207..e58fdd6 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -11,7 +11,7 @@
 	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 @@
 	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.idx  "$PACKDIR/pack-$name.idx" ||
 exit
 
-if test "$remove_redandant" = t
+if test "$remove_redundant" = t
 then
 	sync
 	redundant=$(git-pack-redundant --all)
diff --git a/pack-redundant.c b/pack-redundant.c
index fcb36ff..51d7341 100644
--- a/pack-redundant.c
+++ b/pack-redundant.c
@@ -33,6 +33,7 @@
 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 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 @@
 
 	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;
+	/* 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 subset;
+	return hint[0];
 }
 
 int is_superset(struct pack_list *pl, struct llist *list)
@@ -401,6 +435,8 @@
 	/* 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;