Merge branch 'fixes'
diff --git a/Documentation/cvs-migration.txt b/Documentation/cvs-migration.txt
index 7c4dbef..4361278 100644
--- a/Documentation/cvs-migration.txt
+++ b/Documentation/cvs-migration.txt
@@ -24,7 +24,7 @@
 people think it's a bug in CVS that makes it tag (and check in changes)
 one file at a time.  So most projects you'll ever see will use CVS
 'as if' it was sane.  In which case you'll find it very easy indeed to
-move over to Git. 
+move over to git. 
 
 First off: this is not a git tutorial. See
 link:tutorial.html[Documentation/tutorial.txt] for how git
@@ -229,7 +229,7 @@
 "o-file.c", it would find the commit that changed the statement
 when it was in "o-file.c".
 
-NOTE: The current versions of "git-diff-tree -C" is not eager
+NOTE: The current version of "git-diff-tree -C" is not eager
   enough to find copies, and it will miss the fact that a-file.c
   was created by copying o-file.c unless o-file.c was somehow
   changed in the same commit.
diff --git a/Documentation/diff-format.txt b/Documentation/diff-format.txt
index 6e9fa8c..dacd8fb 100644
--- a/Documentation/diff-format.txt
+++ b/Documentation/diff-format.txt
@@ -1,8 +1,8 @@
 The output format from "git-diff-index", "git-diff-tree" and
 "git-diff-files" are very similar.
 
-These commands all compare two sets of things; what are
-compared are different:
+These commands all compare two sets of things; what is 
+compared differs:
 
 git-diff-index <tree-ish>::
         compares the <tree-ish> and the files on the filesystem.
@@ -46,7 +46,7 @@
 . path for "dst"; only exists for C or R.
 . an LF or a NUL when '-z' option is used, to terminate the record.
 
-<sha1> is shown as all 0's if new is a file on the filesystem
+<sha1> is shown as all 0's if a file is new on the filesystem
 and it is out of sync with the cache.
 
 Example:
@@ -91,7 +91,7 @@
 where:
 
      <old|new>-file:: are files GIT_EXTERNAL_DIFF can use to read the
-		      contents of <old|ne>,
+		      contents of <old|new>,
      <old|new>-hex:: are the 40-hexdigit SHA1 hashes,
      <old|new>-mode:: are the octal representation of the file modes.
 
@@ -121,12 +121,11 @@
 involved.  Especially, even for a creation or a deletion,
 `/dev/null` is _not_ used in place of `a/` or `b/` filenames.
 +
-When rename/copy is involved, `file1` and `file2` shows the
+When rename/copy is involved, `file1` and `file2` show the
 name of the source file of the rename/copy and the name of
 the file that rename/copy produces, respectively.
 
-2.   It is followed by extended header lines that are one or
-     more of:
+2.   It is followed by one or more extended header lines:
 
        old mode <mode>
        new mode <mode>
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 613a60d..06500d0 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -5,9 +5,8 @@
 	Synonym for "-p".
 
 -r::
-	Look recursively in subdirectories; this flag does not
-	mean anything to commands other than "git-diff-tree";
-	other diff commands always look at all the subdirectories.
+	Look recursively in subdirectories; only used by "git-diff-tree";
+	other diff commands always work recursively.
 
 -z::
 	\0 line termination on output
@@ -28,26 +27,26 @@
 	Detect copies as well as renames.
 
 --find-copies-harder::
-	By default, -C option finds copies only if the original
-	file of the copy was modified in the same changeset for
-	performance reasons.  This flag makes the command
+	For performance reasons, by default, -C option finds copies only 
+	if the original file of the copy was modified in the same 
+	changeset.  This flag makes the command
 	inspect unmodified files as candidates for the source of
 	copy.  This is a very expensive operation for large
 	projects, so use it with caution.
 
 -l<num>::
 	-M and -C options require O(n^2) processing time where n
-	in the number of potential rename/copy targets.  This
+	is the number of potential rename/copy targets.  This
 	option prevents rename/copy detection from running if
-	the number of rename/copy targets exceed the specified
+	the number of rename/copy targets exceeds the specified
 	number.
 
 -S<string>::
-	Look for differences that contains the change in <string>.
+	Look for differences that contain the change in <string>.
 
 --pickaxe-all::
 	When -S finds a change, show all the changes in that
-	changeset, not just the files that contains the change
+	changeset, not just the files that contain the change
 	in <string>.
 
 -O<orderfile>::
diff --git a/Documentation/diffcore.txt b/Documentation/diffcore.txt
index a1f03df..9d20a4f 100644
--- a/Documentation/diffcore.txt
+++ b/Documentation/diffcore.txt
@@ -177,7 +177,7 @@
 ---------------------
 
 This transformation is used to merge filepairs broken by
-diffcore-break, and were not transformed into rename/copy by
+diffcore-break, and not transformed into rename/copy by
 diffcore-rename, back into a single modification.  This always
 runs when diffcore-break is used.
 
@@ -206,10 +206,10 @@
 * -B/60 (the same as above, since diffcore-break defaults to 50%).
 
 Note that earlier implementation left a broken pair as a separate
-creation and deletion patches.  This was unnecessary hack and
+creation and deletion patches.  This was an unnecessary hack and
 the latest implementation always merges all the broken pairs
 back into modifications, but the resulting patch output is
-formatted differently to still let the reviewing easier for such
+formatted differently for easier review in case of such
 a complete rewrite by showing the entire contents of old version
 prefixed with '-', followed by the entire contents of new
 version prefixed with '+'.
diff --git a/Documentation/git-add.txt b/Documentation/git-add.txt
index ae1ea76..4a03b4c 100644
--- a/Documentation/git-add.txt
+++ b/Documentation/git-add.txt
@@ -11,7 +11,7 @@
 
 DESCRIPTION
 -----------
-A simple wrapper to git-update-index to add files to the cache for people used
+A simple wrapper for git-update-index to add files to the cache for people used
 to do "cvs add".
 
 OPTIONS
diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt
index 4f7e119..8cbbb4b 100644
--- a/Documentation/git-apply.txt
+++ b/Documentation/git-apply.txt
@@ -13,7 +13,7 @@
 
 DESCRIPTION
 -----------
-Reads supplied diff output and applies it on a GIT index file
+Reads supplied diff output and applies it on a git index file
 and a work tree.
 
 OPTIONS
diff --git a/Documentation/git-applymbox.txt b/Documentation/git-applymbox.txt
index 5022643..bb54378 100644
--- a/Documentation/git-applymbox.txt
+++ b/Documentation/git-applymbox.txt
@@ -22,7 +22,7 @@
 -q::
 	Apply patches interactively.  The user will be given
 	opportunity to edit the log message and the patch before
-	attempting to apply patch in each e-mail message.
+	attempting to apply it.
 
 -k::
 	Usually the program 'cleans up' the Subject: header line
diff --git a/Documentation/git-archimport.txt b/Documentation/git-archimport.txt
index 6054731..b6793cf 100644
--- a/Documentation/git-archimport.txt
+++ b/Documentation/git-archimport.txt
@@ -20,20 +20,23 @@
 as a merge whenever possible (see discussion below). 
 
 The script expects you to provide the key roots where it can start the import 
-from an 'initial import' or 'tag' type of Arch commit. It will follow and import 
-new branches within the provided roots. 
+from an 'initial import' or 'tag' type of Arch commit. It will follow and 
+import new branches within the provided roots. 
 
 It expects to be dealing with one project only. If it sees 
-branches that have different roots, it will refuse to run. In that case, edit your
-<archive/branch> parameters to define clearly the scope of the import. 
+branches that have different roots, it will refuse to run. In that case, 
+edit your <archive/branch> parameters to define clearly the scope of the 
+import. 
 
-`git-archimport` uses `tla` extensively in the background to access the Arch repository.
+`git-archimport` uses `tla` extensively in the background to access the 
+Arch repository.
 Make sure you have a recent version of `tla` available in the path. `tla` must
 know about the repositories you pass to `git-archimport`. 
 
 For the initial import `git-archimport` expects to find itself in an empty 
 directory. To follow the development of a project that uses Arch, rerun 
-`git-archimport` with the same parameters as the initial import to perform incremental imports.
+`git-archimport` with the same parameters as the initial import to perform 
+incremental imports.
 
 MERGES
 ------
diff --git a/Documentation/git-bisect.txt b/Documentation/git-bisect.txt
index ede06da..39fa665 100644
--- a/Documentation/git-bisect.txt
+++ b/Documentation/git-bisect.txt
@@ -76,7 +76,7 @@
 
 to see the currently remaining suspects in `gitk`.
 
-The good/bad you told the command is logged, and `git bisect
+The good/bad input is logged, and `git bisect
 log` shows what you have done so far.  You can truncate its
 output somewhere and save it in a file, and run
 
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index a2a0cfb..a7121a4 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -23,7 +23,7 @@
 	The name of the branch to create.
 
 start-point::
-	Where to make the branch; defaults to HEAD.
+	Where to create the branch; defaults to HEAD.
 
 Author
 ------
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index 44983b6..f21a6e0 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -32,7 +32,7 @@
 
 <type>::
 	Typically this matches the real type of <object> but asking
-	for a type that can trivially dereferenced from the given
+	for a type that can trivially be dereferenced from the given
 	<object> is also permitted.  An example is to ask for a
 	"tree" with <object> being a commit object that contains it,
 	or to ask for a "blob" with <object> being a tag object that
diff --git a/Documentation/git-cherry-pick.txt b/Documentation/git-cherry-pick.txt
index cd5b97d..8462e06 100644
--- a/Documentation/git-cherry-pick.txt
+++ b/Documentation/git-cherry-pick.txt
@@ -22,7 +22,7 @@
 	Commit to cherry-pick.
 
 -r::
-	Usuall the command appends which commit was
+	Usually the command appends which commit was
 	cherry-picked after the original commit message when
 	making a commit.  This option, '--replay', causes it to
 	use the original commit message intact.  This is useful
diff --git a/Documentation/git-clone-pack.txt b/Documentation/git-clone-pack.txt
index 83d17a0..a7868e5 100644
--- a/Documentation/git-clone-pack.txt
+++ b/Documentation/git-clone-pack.txt
@@ -26,8 +26,8 @@
 
 --exec=<git-upload-pack>::
 	Use this to specify the path to 'git-upload-pack' on the
-	remote side, if is not found on your $PATH.
-	Installations of sshd ignores the user's environment
+	remote side, if it is not found on your $PATH.
+	Installations of sshd ignore the user's environment
 	setup scripts for login shells (e.g. .bash_profile) and
 	your privately installed GIT may not be found on the system
 	default $PATH.  Another workaround suggested is to set
diff --git a/Documentation/git-commit-tree.txt b/Documentation/git-commit-tree.txt
index 895f733..9aba868 100644
--- a/Documentation/git-commit-tree.txt
+++ b/Documentation/git-commit-tree.txt
@@ -36,7 +36,7 @@
 	An existing tree object
 
 -p <parent commit>::
-	Each '-p' indicates a the id of a parent commit object.
+	Each '-p' indicates the id of a parent commit object.
 	
 
 Commit Information
diff --git a/Documentation/git-symbolic-ref.txt b/Documentation/git-symbolic-ref.txt
new file mode 100644
index 0000000..a851ae2
--- /dev/null
+++ b/Documentation/git-symbolic-ref.txt
@@ -0,0 +1,52 @@
+git-symbolic-ref(1)
+===================
+
+NAME
+----
+git-symbolic-ref - read and modify symbolic refs
+
+SYNOPSIS
+--------
+'git-symbolic-ref' <name> [<ref>]
+
+DESCRIPTION
+-----------
+Given one argument, reads which branch head the given symbolic
+ref refers to and outputs its path, relative to the `.git/`
+directory.  Typically you would give `HEAD` as the <name>
+argument to see on which branch your working tree is on.
+
+Give two arguments, create or update a symbolic ref <name> to
+point at the given branch <ref>.
+
+Traditionally, `.git/HEAD` is a symlink pointing at
+`refs/heads/master`.  When we want to switch to another branch,
+we did `ln -sf refs/heads/newbranch .git/HEAD`, and when we want
+to find out which branch we are on, we did `readlink .git/HEAD`.
+This was fine, and internally that is what still happens by
+default, but on platforms that does not have working symlinks,
+or that does not have the `readlink(1)` command, this was a bit
+cumbersome.  On some platforms, `ln -sf` does not even work as
+advertised (horrors).
+
+A symbolic ref can be a regular file that stores a string that
+begins with `ref: refs/`.  For example, your `.git/HEAD` *can*
+be a regular file whose contents is `ref: refs/heads/master`.
+This can be used on a filesystem that does not support symbolic
+links.  Instead of doing `readlink .git/HEAD`, `git-symbolic-ref
+HEAD` can be used to find out which branch we are on.  To point
+the HEAD to `newbranch`, instead of `ln -sf refs/heads/newbranch
+.git/HEAD`, `git-symbolic-ref HEAD refs/heads/newbranch` can be
+used.
+
+Currently, .git/HEAD uses a regular file symbolic ref on Cygwin,
+and everywhere else it is implemented as a symlink.  This can be
+changed at compilation time.
+
+Author
+------
+Written by Junio C Hamano <junkio@cox.net>
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/Documentation/git-update-ref.txt b/Documentation/git-update-ref.txt
new file mode 100644
index 0000000..69715aa
--- /dev/null
+++ b/Documentation/git-update-ref.txt
@@ -0,0 +1,58 @@
+git-update-ref(1)
+=================
+
+NAME
+----
+git-update-ref - update the object name stored in a ref safely
+
+SYNOPSIS
+--------
+`git-update-ref` <ref> <newvalue> [<oldvalue>]
+
+DESCRIPTION
+-----------
+Given two arguments, stores the <newvalue> in the <ref>, possibly
+dereferencing the symbolic refs.  E.g. `git-update-ref HEAD
+<newvalue>` updates the current branch head to the new object.
+
+Given three arguments, stores the <newvalue> in the <ref>,
+possibly dereferencing the symbolic refs, after verifying that
+the current value of the <ref> matches <oldvalue>.
+E.g. `git-update-ref refs/heads/master <newvalue> <oldvalue>`
+updates the master branch head to <newvalue> only if its current
+value is <oldvalue>.
+
+It also allows a "ref" file to be a symbolic pointer to another
+ref file by starting with the four-byte header sequence of
+"ref:".
+
+More importantly, it allows the update of a ref file to follow
+these symbolic pointers, whether they are symlinks or these
+"regular file symbolic refs".  It follows *real* symlinks only
+if they start with "refs/": otherwise it will just try to read
+them and update them as a regular file (i.e. it will allow the
+filesystem to follow them, but will overwrite such a symlink to
+somewhere else with a regular filename).
+
+In general, using
+
+	git-update-ref HEAD "$head"
+
+should be a _lot_ safer than doing
+
+	echo "$head" > "$GIT_DIR/HEAD"
+
+both from a symlink following standpoint *and* an error checking
+standpoint.  The "refs/" rule for symlinks means that symlinks
+that point to "outside" the tree are safe: they'll be followed
+for reading but not for writing (so we'll never write through a
+ref symlink to some other tree, if you have copied a whole
+archive by creating a symlink tree).
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
diff --git a/clone-pack.c b/clone-pack.c
index 49820c6..c102ca8 100644
--- a/clone-pack.c
+++ b/clone-pack.c
@@ -51,6 +51,7 @@
 	struct ref *head = NULL, *head_ptr, *master_ref;
 	char *head_path;
 
+	/* Upload-pack must report HEAD first */
 	if (!strcmp(ref->name, "HEAD")) {
 		head = ref;
 		ref = ref->next;
@@ -60,17 +61,21 @@
 	while (ref) {
 		if (is_master(ref))
 			master_ref = ref;
-		if (head && !memcmp(ref->old_sha1, head->old_sha1, 20)) {
-			if (!head_ptr || ref == master_ref)
-				head_ptr = ref;
-		}
+		if (head &&
+		    !memcmp(ref->old_sha1, head->old_sha1, 20) &&
+		    !strncmp(ref->name, "refs/heads/",11) &&
+		    (!head_ptr || ref == master_ref))
+			head_ptr = ref;
+
 		write_one_ref(ref);
 		ref = ref->next;
 	}
-	if (!head)
+	if (!head) {
+		fprintf(stderr, "No HEAD in remote.\n");
 		return;
+	}
 
-	head_path = git_path("HEAD");
+	head_path = strdup(git_path("HEAD"));
 	if (!head_ptr) {
 		/*
 		 * If we had a master ref, and it wasn't HEAD, we need to undo the
@@ -82,6 +87,7 @@
 			unlink(head_path);
 		}
 		write_one_ref(head);
+		free(head_path);
 		return;
 	}
 
@@ -89,13 +95,15 @@
 	if (master_ref)
 		return;
 
+	fprintf(stderr, "Setting HEAD to %s\n", head_ptr->name);
+
 	/*
 	 * Uhhuh. Other end didn't have master. We start HEAD off with
 	 * the first branch with the same value.
 	 */
-	unlink(head_path);
-	if (symlink(head_ptr->name, head_path) < 0)
+	if (create_symref(head_path, head_ptr->name) < 0)
 		die("unable to link HEAD to %s", head_ptr->name);
+	free(head_path);
 }
 
 static int clone_pack(int fd[2], int nr_match, char **match)
diff --git a/diff.h b/diff.h
index 7f4079c..2f4a7b4 100644
--- a/diff.h
+++ b/diff.h
@@ -103,7 +103,7 @@
 /* these are not diff-raw status letters proper, but used by
  * diffcore-filter insn to specify additional restrictions.
  */
-#define DIFF_STATUS_FILTER_AON		'A'
+#define DIFF_STATUS_FILTER_AON		'*'
 #define DIFF_STATUS_FILTER_BROKEN	'B'
 
 #endif /* DIFF_H */
diff --git a/git-commit.sh b/git-commit.sh
index 1206c20..591fcdc 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -133,10 +133,13 @@
 
 case "$signoff" in
 t)
-	git-var GIT_COMMITTER_IDENT | sed -e '
-		s/>.*/>/
-		s/^/Signed-off-by: /
-	' >>.editmsg
+	{
+		echo
+		git-var GIT_COMMITTER_IDENT | sed -e '
+			s/>.*/>/
+			s/^/Signed-off-by: /
+		'
+	} >>.editmsg
 	;;
 esac
 
@@ -195,7 +198,7 @@
 	PARENTS=""
 fi
 git-status >>.editmsg
-if [ "$?" != "0" -a ! -f $GIT_DIR/MERGE_HEAD ]
+if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ]
 then
 	rm -f .editmsg
 	git-status
diff --git a/git-external-diff-script b/git-external-diff-script
deleted file mode 100755
index 137280a..0000000
--- a/git-external-diff-script
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/bin/sh
-# Copyright (C) 2005 Junio C Hamano
-#
-# This script is designed to emulate what the built-in diff driver
-# does when set as GIT_EXTERNAL_SCRIPT.
-
-case "$#" in
-1)
-    echo "* Unmerged path $1"
-    exit 0 ;;
-*)
-    name1="$1" tmp1="$2" hex1="$3" mode1="$4" tmp2="$5" hex2="$6" mode2="$7"
-    case "$#" in
-    7)
-	name2="$name1" ;;
-    9)
-	name2="$8" xfrm_msg="$9" ;;
-    esac ;;	
-esac
-
-show_create () {
-    name_="$1" tmp_="$2" hex_="$3" mode_="$4"
-    echo "diff --git a/$name_ b/$name_"
-    echo "new file mode $mode_"
-    diff ${GIT_DIFF_OPTS-'-pu'} -L /dev/null -L "b/$name_" /dev/null "$tmp_"
-}
-
-show_delete () {
-    name_="$1" tmp_="$2" hex_="$3" mode_="$4"
-    echo "diff --git a/$name_ b/$name_"
-    echo "deleted file mode $mode_"
-    diff ${GIT_DIFF_OPTS-'-pu'} -L "a/$name_" -L /dev/null "$tmp_" /dev/null
-}
-
-case "$mode1" in
-120*) type1=l ;;
-100*) type1=f ;;
-.)    show_create "$name2" "$tmp2" "$hex2" "$mode2"
-      exit 0 ;;
-esac
-case "$mode2" in
-120*) type2=l ;;
-100*) type2=f ;;
-.)    show_delete "$name1" "$tmp1" "$hex1" "$mode1"
-      exit 0 ;;
-esac
-
-if test "$type1" != "$type2"
-then
-	show_delete "$name1" "$tmp1" "$hex1" "$mode1"
-	show_create "$name2" "$tmp2" "$hex2" "$mode2"
-	exit 0
-fi
-
-echo diff --git "a/$name1" "b/$name2"
-if test "$mode1" != "$mode2"
-then
-    echo "old mode $mode1"
-    echo "new mode $mode2"
-    if test "$xfrm_msg" != ""
-    then
-	echo "$xfrm_msg"
-    fi
-fi
-diff ${GIT_DIFF_OPTS-'-pu'} -L "a/$name1" -L "b/$name2" "$tmp1" "$tmp2"
-exit 0
-
diff --git a/git-fetch.sh b/git-fetch.sh
index 61da6a9..d398866 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -49,7 +49,7 @@
 
 if test "" = "$append"
 then
-	: >$GIT_DIR/FETCH_HEAD
+	: >"$GIT_DIR/FETCH_HEAD"
 fi
 
 append_fetch_head () {
@@ -86,11 +86,11 @@
     if git-cat-file commit "$head_" >/dev/null 2>&1
     then
 	headc_=$(git-rev-parse --verify "$head_^0") || exit
-	echo "$headc_	$not_for_merge_	$note_" >>$GIT_DIR/FETCH_HEAD
+	echo "$headc_	$not_for_merge_	$note_" >>"$GIT_DIR/FETCH_HEAD"
 	echo >&2 "* committish: $head_"
 	echo >&2 "  $note_"
     else
-	echo "$head_	not-for-merge	$note_" >>$GIT_DIR/FETCH_HEAD
+	echo "$head_	not-for-merge	$note_" >>"$GIT_DIR/FETCH_HEAD"
 	echo >&2 "* non-commit: $head_"
 	echo >&2 "  $note_"
     fi
diff --git a/git-format-patch.sh b/git-format-patch.sh
index 525a2f2..2844799 100755
--- a/git-format-patch.sh
+++ b/git-format-patch.sh
@@ -128,10 +128,6 @@
 	q
 }'
 
-_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
-_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
-stripCommitHead='/^'"$_x40"' (from '"$_x40"')$/d'
-
 git-cherry -v "$rev1" "$rev2" |
 while read sign rev comment
 do
@@ -216,7 +212,7 @@
 	echo
 	git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
 	echo
-	git-diff-tree -p $diff_opts "$commit" | sed -e "$stripCommitHead"
+	git-diff-tree -p $diff_opts "$commit"
 
 	case "$mbox" in
 	t)
diff --git a/index.c b/index.c
index bdde65f..ad0eafe 100644
--- a/index.c
+++ b/index.c
@@ -22,14 +22,16 @@
 
 int hold_index_file_for_update(struct cache_file *cf, const char *path)
 {
+	int fd;
 	sprintf(cf->lockfile, "%s.lock", path);
-	cf->next = cache_file_list;
-	cache_file_list = cf;
-	if (!cf->next) {
+	fd = open(cf->lockfile, O_RDWR | O_CREAT | O_EXCL, 0666);
+	if (fd >=0 && !cf->next) {
+		cf->next = cache_file_list;
+		cache_file_list = cf;
 		signal(SIGINT, remove_lock_file_on_signal);
 		atexit(remove_lock_file);
 	}
-	return open(cf->lockfile, O_RDWR | O_CREAT | O_EXCL, 0666);
+	return fd;
 }
 
 int commit_index_file(struct cache_file *cf)
diff --git a/refs.c b/refs.c
index 2aac90c..5a8cbd4 100644
--- a/refs.c
+++ b/refs.c
@@ -46,7 +46,7 @@
 	len -= 4;
 	while (len && isspace(*buf))
 		buf++, len--;
-	if (len >= 5 && !memcmp("refs/", buffer, 5))
+	if (len >= 5 && !memcmp("refs/", buf, 5))
 		return 0;
 	return -1;
 }
diff --git a/rev-list.c b/rev-list.c
index 5ec9ccb..c60aa72 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "refs.h"
 #include "tag.h"
 #include "commit.h"
 #include "tree.h"
@@ -489,6 +490,22 @@
 	commit_list_insert(com, lst);
 }
 
+/* for_each_ref() callback does not allow user data -- Yuck. */
+static struct commit_list **global_lst;
+
+static int include_one_commit(const char *path, const unsigned char *sha1)
+{
+	struct commit *com = get_commit_reference(path, 0);
+	handle_one_commit(com, global_lst);
+	return 0;
+}
+
+static void handle_all(struct commit_list **lst)
+{
+	global_lst = lst;
+	for_each_ref(include_one_commit);
+	global_lst = NULL;
+}
 
 int main(int argc, char **argv)
 {
@@ -542,6 +559,10 @@
 			bisect_list = 1;
 			continue;
 		}
+		if (!strcmp(arg, "--all")) {
+			handle_all(&list);
+			continue;
+		}
 		if (!strcmp(arg, "--objects")) {
 			tag_objects = 1;
 			tree_objects = 1;
diff --git a/rev-parse.c b/rev-parse.c
index 507b531..41b9dae 100644
--- a/rev-parse.c
+++ b/rev-parse.c
@@ -32,6 +32,7 @@
 static int is_rev_argument(const char *arg)
 {
 	static const char *rev_args[] = {
+		"--all",
 		"--bisect",
 		"--header",
 		"--max-age=",
diff --git a/upload-pack.c b/upload-pack.c
index da10742..83f5a35 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -30,10 +30,18 @@
 
 	if (!pid) {
 		int i;
-		int args = nr_has + nr_needs + 5;
-		char **argv = xmalloc(args * sizeof(char *));
-		char *buf = xmalloc(args * 45);
-		char **p = argv;
+		int args;
+		char **argv;
+		char *buf;
+		char **p;
+
+		if (MAX_NEEDS <= nr_needs)
+			args = nr_has + 10;
+		else
+			args = nr_has + nr_needs + 5;
+		argv = xmalloc(args * sizeof(char *));
+		buf = xmalloc(args * 45);
+		p = argv;
 
 		dup2(fd[1], 1);
 		close(0);
@@ -41,10 +49,14 @@
 		close(fd[1]);
 		*p++ = "git-rev-list";
 		*p++ = "--objects";
-		for (i = 0; i < nr_needs; i++) {
-			*p++ = buf;
-			memcpy(buf, sha1_to_hex(needs_sha1[i]), 41);
-			buf += 41;
+		if (MAX_NEEDS <= nr_needs)
+			*p++ = "--all";
+		else {
+			for (i = 0; i < nr_needs; i++) {
+				*p++ = buf;
+				memcpy(buf, sha1_to_hex(needs_sha1[i]), 41);
+				buf += 41;
+			}
 		}
 		for (i = 0; i < nr_has; i++) {
 			*p++ = buf;
@@ -129,18 +141,24 @@
 
 	needs = 0;
 	for (;;) {
+		unsigned char dummy[20], *sha1_buf;
 		len = packet_read_line(0, line, sizeof(line));
 		if (!len)
 			return needs;
 
-		/*
-		 * This is purely theoretical right now: git-fetch-pack only
-		 * ever asks for a single HEAD
-		 */
-		if (needs >= MAX_NEEDS)
-			die("I'm only doing a max of %d requests", MAX_NEEDS);
-		if (strncmp("want ", line, 5) || get_sha1_hex(line+5, needs_sha1[needs]))
-			die("git-upload-pack: protocol error, expected to get sha, not '%s'", line);
+		sha1_buf = dummy;
+		if (needs == MAX_NEEDS) {
+			fprintf(stderr,
+				"warning: supporting only a max of %d requests. "
+				"sending everything instead.\n",
+				MAX_NEEDS);
+		}
+		else if (needs < MAX_NEEDS)
+			sha1_buf = needs_sha1[needs];
+
+		if (strncmp("want ", line, 5) || get_sha1_hex(line+5, sha1_buf))
+			die("git-upload-pack: protocol error, "
+			    "expected to get sha, not '%s'", line);
 		needs++;
 	}
 }