GIT 1.0.0

Signed-off-by: Junio C Hamano <junkio@cox.net>
diff --git a/.gitignore b/.gitignore
index 8a6bd02..6bd508e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -60,7 +60,6 @@
 git-mktag
 git-name-rev
 git-mv
-git-octopus
 git-pack-redundant
 git-pack-objects
 git-parse-remote
diff --git a/Documentation/diff-options.txt b/Documentation/diff-options.txt
index 6b496ed..9e574a0 100644
--- a/Documentation/diff-options.txt
+++ b/Documentation/diff-options.txt
@@ -18,6 +18,14 @@
 	object name of pre- and post-image blob on the "index"
 	line when generating a patch format output.	
 
+--abbrev[=<n>]::
+	Instead of showing the full 40-byte hexadecimal object
+	name in diff-raw format output and diff-tree header
+	lines, show only handful dhexigits prefix.  This is
+	independent of --full-index option above, which controls
+	the diff-patch output format.  Non default number of
+	digits can be specified with --abbrev=<n>.
+
 -B::
 	Break complete rewrite changes into pairs of delete and create.
 
diff --git a/Documentation/everyday.txt b/Documentation/everyday.txt
index d8d7a64..3ab9b91 100644
--- a/Documentation/everyday.txt
+++ b/Documentation/everyday.txt
@@ -211,10 +211,12 @@
 
 <1> repeat as needed.
 <2> extract patches from your branch for e-mail submission.
-<3> "pull" fetches from "origin" by default and merges.
-<4> look at the changes since last time we checked, only in the
+<3> "pull" fetches from "origin" by default and merges into the
+current branch.
+<4> immediately after pulling, look at the changes done upstream
+since last time we checked, only in the
 area we are interested in.
-<5> fetch from a specific branch from a specific repository and and merge.
+<5> fetch from a specific branch from a specific repository and merge.
 <6> revert the pull.
 <7> garbage collect leftover objects from reverted pull.
 <8> from time to time, obtain official tags from the "origin"
@@ -330,16 +332,18 @@
 <8> and bundle topic branches still cooking.
 <9> backport a critical fix.
 <10> create a signed tag.
-<11> make sure I did not accidentally rewound master beyond what I
+<11> make sure I did not accidentally rewind master beyond what I
 already pushed out.  "ko" shorthand points at the repository I have
 at kernel.org, and looks like this:
-$ cat .git/remotes/ko
-URL: kernel.org:/pub/scm/git/git.git
-Pull: master:refs/tags/ko-master
-Pull: maint:refs/tags/ko-maint
-Push: master
-Push: +pu
-Push: maint
+    $ cat .git/remotes/ko
+    URL: kernel.org:/pub/scm/git/git.git
+    Pull: master:refs/tags/ko-master
+    Pull: maint:refs/tags/ko-maint
+    Push: master
+    Push: +pu
+    Push: maint
+In the output from "git show-branch", "master" should have
+everything "ko-master" has.
 <12> push out the bleeding edge.
 <13> push the tag out, too.
 ------------
@@ -357,8 +361,8 @@
   * gitlink:git-shell[1] can be used as a 'restricted login shell'
     for shared central repository users.
 
-  * link:howto/update-hook-example.txt[update hook howto] has a
-    good example of managing a shared central repository.
+link:howto/update-hook-example.txt[update hook howto] has a good
+example of managing a shared central repository.
 
 
 Examples
@@ -424,3 +428,14 @@
 david is the release manager and is the only person who can
 create and push version tags.
 ------------
+
+HTTP server to support dumb protocol transfer.::
++
+------------
+dev$ git update-server-info <1>
+dev$ ftp user@isp.example.com <2>
+ftp> cp -r .git /home/user/myproject.git
+
+<1> make sure your info/refs and objects/info/packs are up-to-date
+<2> upload to public HTTP server hosted by your ISP.
+------------
diff --git a/Documentation/git-archimport.txt b/Documentation/git-archimport.txt
index fcda012..a2bd788 100644
--- a/Documentation/git-archimport.txt
+++ b/Documentation/git-archimport.txt
@@ -8,7 +8,8 @@
 
 SYNOPSIS
 --------
-`git-archimport` [ -h ] [ -v ] [ -T ] [ -t tempdir ] 
+`git-archimport` [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ]
+                 [ -D depth ] [ -t tempdir ] 
                  <archive/branch> [ <archive/branch> ]
 
 DESCRIPTION
@@ -63,6 +64,26 @@
 	Many tags. Will create a tag for every commit, reflecting the commit 
 	name in the Arch repository.
 
+-f::
+	Use the fast patchset import strategy.  This can be significantly
+	faster for large trees, but cannot handle directory renames or
+	permissions changes.  The default strategy is slow and safe.
+
+-o::
+	Use this for compatibility with old-style branch names used by
+	earlier versions of git-archimport.  Old-style branch names
+	were category--branch, whereas new-style branch names are
+	archive,category--branch--version.
+
+-D <depth>::
+	Follow merge ancestry and attempt to import trees that have been
+	merged from.  Specify a depth greater than 1 if patch logs have been
+	pruned.
+
+-a::
+	Attempt to auto-register archives at http://mirrors.sourcecontrol.net
+	This is particularly useful with the -D option.
+
 -t <tmpdir>::
 	Override the default tempdir.
 
diff --git a/Documentation/git-check-ref-format.txt b/Documentation/git-check-ref-format.txt
index 636e951..f7f84c6 100644
--- a/Documentation/git-check-ref-format.txt
+++ b/Documentation/git-check-ref-format.txt
@@ -26,13 +26,15 @@
 
 . It cannot have ASCII control character (i.e. bytes whose
   values are lower than \040, or \177 `DEL`), space, tilde `~`,
-  caret `{caret}`, or colon `:` anywhere;
+  caret `{caret}`, colon `:`, question-mark `?`, asterisk `*`,
+  or open bracket `[` anywhere;
 
 . It cannot end with a slash `/`.
 
 These rules makes it easy for shell script based tools to parse
-refnames, and also avoids ambiguities in certain refname
-expressions (see gitlink:git-rev-parse[1]).  Namely:
+refnames, pathname expansion by the shell when a refname is used
+unquoted (by mistake), and also avoids ambiguities in certain
+refname expressions (see gitlink:git-rev-parse[1]).  Namely:
 
 . double-dot `..` are often used as in `ref1..ref2`, and in some
   context this notation means `{caret}ref1 ref2` (i.e. not in
diff --git a/Documentation/git-clone-pack.txt b/Documentation/git-clone-pack.txt
index cfc7b62..39906fc 100644
--- a/Documentation/git-clone-pack.txt
+++ b/Documentation/git-clone-pack.txt
@@ -43,7 +43,11 @@
 	The heads to update.  This is relative to $GIT_DIR
 	(e.g. "HEAD", "refs/heads/master").  When unspecified,
 	all heads are updated to match the remote repository.
-
++
+Usually all the refs from existing repository are stored
+under the same name in the new repository.  Giving explicit
+<head> arguments instead writes the object names and refs to
+the standard output, just like get-fetch-pack does.
 
 Author
 ------
diff --git a/Documentation/git-commit.txt b/Documentation/git-commit.txt
index b92cf48..8b91f22 100644
--- a/Documentation/git-commit.txt
+++ b/Documentation/git-commit.txt
@@ -66,6 +66,10 @@
 	Update specified paths in the index file before committing.
 
 
+If you make a commit and then found a mistake immediately after
+that, you can recover from it with gitlink:git-reset[1].
+
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org> and
diff --git a/Documentation/git-fetch-pack.txt b/Documentation/git-fetch-pack.txt
index ea6faab..b507e9b 100644
--- a/Documentation/git-fetch-pack.txt
+++ b/Documentation/git-fetch-pack.txt
@@ -8,7 +8,7 @@
 
 SYNOPSIS
 --------
-git-fetch-pack [-q] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
+git-fetch-pack [-q] [-k] [--exec=<git-upload-pack>] [<host>:]<directory> [<refs>...]
 
 DESCRIPTION
 -----------
@@ -29,6 +29,11 @@
 	Pass '-q' flag to 'git-unpack-objects'; this makes the
 	cloning process less verbose.
 
+-k::
+	Do not invoke 'git-unpack-objects' on received data, but
+	create a single packfile out of it instead, and store it
+	in the object database.
+
 --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.
diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index 0cac563..4ce799b 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -37,6 +37,11 @@
 include::merge-strategies.txt[]
 
 
+If you tried a merge which resulted in a complex conflicts and
+would want to start over, you can recover with
+gitlink:git-reset[1].
+
+
 HOW MERGE WORKS
 ---------------
 
diff --git a/Documentation/git-octopus.txt b/Documentation/git-octopus.txt
deleted file mode 100644
index 6e32ea3..0000000
--- a/Documentation/git-octopus.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-git-octopus(1)
-==============
-
-NAME
-----
-git-octopus - Merge more than two commits.
-
-
-SYNOPSIS
---------
-'git-octopus'
-
-DESCRIPTION
------------
-After running 'git fetch', $GIT_DIR/FETCH_HEAD contains the
-following information, one line per remote ref:
-
-------------------------------------------------
-<object name>	<ref name> from <repository>
-------------------------------------------------
-
-Using this information, create and commit an Octopus merge on
-top of the current HEAD.
-
-
-Author
-------
-Written by Junio C Hamano <junkio@cox.net>
-
-
-Documentation
---------------
-Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
-
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index c65ca9a..3a7d385 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -104,6 +104,11 @@
 local `master` branch.
 
 
+If you tried a pull which resulted in a complex conflicts and
+would want to start over, you can recover with
+gitlink:git-reset[1].
+
+
 SEE ALSO
 --------
 gitlink:git-fetch[1], gitlink:git-merge[1]
diff --git a/Documentation/git-reset.txt b/Documentation/git-reset.txt
index 0204891..c6a269b 100644
--- a/Documentation/git-reset.txt
+++ b/Documentation/git-reset.txt
@@ -111,6 +111,39 @@
 changes still in the working tree.
 ------------
 
+Undo a merge or pull::
++
+------------
+$ git pull <1>
+Trying really trivial in-index merge...
+fatal: Merge requires file-level merging
+Nope.
+...
+Auto-merging nitfol
+CONFLICT (content): Merge conflict in nitfol
+Automatic merge failed/prevented; fix up by hand
+$ git reset --hard <2>
+
+<1> try to update from the upstream resulted in a lot of
+conflicts; you were not ready to spend a lot of time merging
+right now, so you decide to do that later.
+<2> "pull" has not made merge commit, so "git reset --hard"
+which is a synonym for "git reset --hard HEAD" clears the mess
+from the index file and the working tree.
+
+$ git pull . topic/branch <3>
+Updating from 41223... to 13134...
+Fast forward
+$ git reset --hard ORIG_HEAD <4>
+
+<3> merge a topic branch into the current branch, which resulted
+in a fast forward.
+<4> but you decided that the topic branch is not ready for public
+consumption yet.  "pull" or "merge" always leaves the original
+tip of the current branch in ORIG_HEAD, so resetting hard to it
+brings your index file and the working tree back to that state,
+and resets the tip of the branch to that commit.
+------------
 
 Author
 ------
diff --git a/Documentation/git-update-server-info.txt b/Documentation/git-update-server-info.txt
index 527fb30..88a03c7 100644
--- a/Documentation/git-update-server-info.txt
+++ b/Documentation/git-update-server-info.txt
@@ -12,11 +12,11 @@
 
 DESCRIPTION
 -----------
-A dumb server that does not do on-the-fly pack generations can
+A dumb server that does not do on-the-fly pack generations must
 have some auxiliary information files in $GIT_DIR/info and
 $GIT_OBJECT_DIRECTORY/info directories to help clients discover
-what references and packs the server has and make optimized
-pull decisions.  This command generates such auxiliary files.
+what references and packs the server has.  This command
+generates such auxiliary files.
 
 
 OPTIONS
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 482eba7..5f068c2 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -297,9 +297,6 @@
 gitlink:git-mv[1]::
 	Move or rename a file, a directory, or a symlink.
 
-gitlink:git-octopus[1]::
-	Merge more than two commits.
-
 gitlink:git-pull[1]::
 	Fetch from and merge with a remote repository.
 
diff --git a/Documentation/hooks.txt b/Documentation/hooks.txt
index 7ee3571..4ad1920 100644
--- a/Documentation/hooks.txt
+++ b/Documentation/hooks.txt
@@ -111,6 +111,10 @@
 implement access control which is finer grained than the one
 based on filesystem group.
 
+The standard output of this hook is sent to /dev/null; if you
+want to report something to the git-send-pack on the other end,
+you can redirect your output to your stderr.
+
 post-update
 -----------
 
@@ -125,3 +129,7 @@
 The default post-update hook, when enabled, runs
 `git-update-server-info` to keep the information used by dumb
 transport up-to-date.
+
+The standard output of this hook is sent to /dev/null; if you
+want to report something to the git-send-pack on the other end,
+you can redirect your output to your stderr.
diff --git a/Documentation/howto/rebuild-from-update-hook.txt b/Documentation/howto/rebuild-from-update-hook.txt
index ebd025d..02621b5 100644
--- a/Documentation/howto/rebuild-from-update-hook.txt
+++ b/Documentation/howto/rebuild-from-update-hook.txt
@@ -10,7 +10,7 @@
 are built from Documentation/ directory of the git.git project
 and needed to be kept up-to-date.  The www.kernel.org/ servers
 are mirrored and I was told that the origin of the mirror is on
-the machine master.kernel.org, on which I was given an account
+the machine $some.kernel.org, on which I was given an account
 when I took over git maintainership from Linus.
 
 The directories relevant to this how-to are these two:
@@ -63,7 +63,7 @@
     EOF
     $ chmod +x /pub/scm/git/git.git/hooks/post-update
 
-There are three things worth mentioning:
+There are four things worth mentioning:
 
  - The update-hook is run after the repository accepts a "git
    push", under my user privilege.  It is given the full names
@@ -77,6 +77,10 @@
    pull" it does into $HOME/doc-git/docgen/ repository would not
    work correctly.
 
+ - The stdout of update hook script is not connected to git
+   push; I run the heavy part of the command inside "at", to
+   receive the execution report via e-mail.
+
  - This is still crude and does not protect against simultaneous
    make invocations stomping on each other.  I would need to add
    some locking mechanism for this.
diff --git a/Documentation/howto/using-topic-branches.txt b/Documentation/howto/using-topic-branches.txt
index 4944297..b3d592f 100644
--- a/Documentation/howto/using-topic-branches.txt
+++ b/Documentation/howto/using-topic-branches.txt
@@ -42,8 +42,7 @@
 
 First create your work tree by cloning Linus's public tree:
 
- $ git clone \
- master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work
+ $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git work
 
 Change directory into the cloned tree you just created
 
@@ -53,7 +52,7 @@
 branch into a local branch named "linus":
 
  $ cat > .git/remotes/linus
- URL: master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
+ URL: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
  Pull: master:linus
  ^D
 
diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt
index a61b824..3a5c56e 100644
--- a/Documentation/tutorial.txt
+++ b/Documentation/tutorial.txt
@@ -27,6 +27,12 @@
 [NOTE]
 And those "too deep" descriptions are often marked as Note.
 
+[NOTE]
+If you are already familiar with another version control system,
+like CVS, you may want to take a look at
+link:everyday.html[Everyday GIT in 20 commands or so] first
+before reading this.
+
 
 Creating a git repository
 -------------------------
@@ -1085,9 +1091,10 @@
 HTTP(S)::
 	`http://remote.machine/path/to/repo.git/`
 +
-HTTP and HTTPS transport are used only for downloading.  They
-first obtain the topmost commit object name from the remote site
-by looking at `repo.git/info/refs` file, tries to obtain the
+Downloader from http and https URL
+first obtains the topmost commit object name from the remote site
+by looking at the specified refname under `repo.git/refs/` directory,
+and then tries to obtain the
 commit object by downloading from `repo.git/objects/xx/xxx\...`
 using the object name of that commit object.  Then it reads the
 commit object to find out its parent commits and the associate
@@ -1098,7 +1105,9 @@
 The 'commit walkers' are sometimes also called 'dumb
 transports', because they do not require any git aware smart
 server like git Native transport does.  Any stock HTTP server
-would suffice.
+that does not even support directory index would suffice.  But
+you must prepare your repository with `git-update-server-info`
+to help dumb transport downloaders.
 +
 There are (confusingly enough) `git-ssh-fetch` and `git-ssh-upload`
 programs, which are 'commit walkers'; they outlived their
@@ -1511,12 +1520,13 @@
 2. Prepare a public repository accessible to others.
 +
 If other people are pulling from your repository over dumb
-transport protocols, you need to keep this repository 'dumb
-transport friendly'.  After `git init-db`,
+transport protocols (HTTP), you need to keep this repository
+'dumb transport friendly'.  After `git init-db`,
 `$GIT_DIR/hooks/post-update` copied from the standard templates
 would contain a call to `git-update-server-info` but the
 `post-update` hook itself is disabled by default -- enable it
-with `chmod +x post-update`.
+with `chmod +x post-update`.  This makes sure `git-update-server-info`
+keeps the necessary files up-to-date.
 
 3. Push into the public repository from your primary
    repository.
@@ -1615,7 +1625,9 @@
 For this, set up a public repository on a machine that is
 reachable via SSH by people with "commit privileges".  Put the
 committers in the same user group and make the repository
-writable by that group.
+writable by that group.  Make sure their umasks are set up to
+allow group members to write into directories other members
+have created.
 
 You, as an individual committer, then:
 
diff --git a/Makefile b/Makefile
index 92cfee4..e9bf860 100644
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,7 @@
 # Define USE_STDEV below if you want git to care about the underlying device
 # change being considered an inode change from the update-cache perspective.
 
-GIT_VERSION = 0.99.9n
+GIT_VERSION = 1.0.0
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
@@ -89,7 +89,7 @@
 	git-cherry.sh git-clone.sh git-commit.sh \
 	git-count-objects.sh git-diff.sh git-fetch.sh \
 	git-format-patch.sh git-log.sh git-ls-remote.sh \
-	git-merge-one-file.sh git-octopus.sh git-parse-remote.sh \
+	git-merge-one-file.sh git-parse-remote.sh \
 	git-prune.sh git-pull.sh git-push.sh git-rebase.sh \
 	git-repack.sh git-request-pull.sh git-reset.sh \
 	git-resolve.sh git-revert.sh git-sh-setup.sh git-status.sh \
@@ -175,6 +175,7 @@
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
 	tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
+	fetch-clone.o \
 	$(DIFF_OBJS)
 
 LIBS = $(LIB_FILE)
@@ -497,7 +498,7 @@
 	rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o $(LIB_FILE)
 	rm -f $(PROGRAMS) $(SIMPLE_PROGRAMS) git$X
 	rm -f $(filter-out gitk,$(SCRIPTS))
-	rm -f *.spec *.pyc *.pyo
+	rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo
 	rm -rf $(GIT_TARNAME)
 	rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
 	rm -f git-core_$(GIT_VERSION)-*.dsc
@@ -505,3 +506,4 @@
 	$(MAKE) -C Documentation/ clean
 	$(MAKE) -C templates clean
 	$(MAKE) -C t/ clean
+
diff --git a/apply.c b/apply.c
index 1742ab2..d5e7bfd 100644
--- a/apply.c
+++ b/apply.c
@@ -84,14 +84,11 @@
 			buffer = xrealloc(buffer, alloc);
 			nr = alloc - size;
 		}
-		nr = read(fd, buffer + size, nr);
+		nr = xread(fd, buffer + size, nr);
 		if (!nr)
 			break;
-		if (nr < 0) {
-			if (errno == EAGAIN)
-				continue;
+		if (nr < 0)
 			die("git-apply: read returned %s", strerror(errno));
-		}
 		size += nr;
 	}
 	*sizep = size;
@@ -1006,13 +1003,8 @@
 			return error("unable to open %s", path);
 		got = 0;
 		for (;;) {
-			int ret = read(fd, buf + got, size - got);
-			if (ret < 0) {
-				if (errno == EAGAIN)
-					continue;
-				break;
-			}
-			if (!ret)
+			int ret = xread(fd, buf + got, size - got);
+			if (ret <= 0)
 				break;
 			got += ret;
 		}
@@ -1600,12 +1592,9 @@
 	if (fd < 0)
 		return -1;
 	while (size) {
-		int written = write(fd, buf, size);
-		if (written < 0) {
-			if (errno == EINTR || errno == EAGAIN)
-				continue;
+		int written = xwrite(fd, buf, size);
+		if (written < 0)
 			die("writing file %s: %s", path, strerror(errno));
-		}
 		if (!written)
 			die("out of space writing file %s", path);
 		buf += written;
diff --git a/cache.h b/cache.h
index c78d8ae..cb87bec 100644
--- a/cache.h
+++ b/cache.h
@@ -338,4 +338,9 @@
 extern char git_commit_encoding[MAX_ENCODING_LENGTH];
 
 extern int copy_fd(int ifd, int ofd);
+
+/* Finish off pack transfer receiving end */
+extern int receive_unpack_pack(int fd[2], const char *me, int quiet);
+extern int receive_keep_pack(int fd[2], const char *me);
+
 #endif /* CACHE_H */
diff --git a/cat-file.c b/cat-file.c
index 7594108..96d66b4 100644
--- a/cat-file.c
+++ b/cat-file.c
@@ -55,10 +55,8 @@
 		die("git-cat-file %s: bad file", argv[2]);
 
 	while (size > 0) {
-		long ret = write(1, buf, size);
+		long ret = xwrite(1, buf, size);
 		if (ret < 0) {
-			if (errno == EAGAIN)
-				continue;
 			/* Ignore epipe */
 			if (errno == EPIPE)
 				break;
diff --git a/clone-pack.c b/clone-pack.c
index a99a95c..f634431 100644
--- a/clone-pack.c
+++ b/clone-pack.c
@@ -1,7 +1,6 @@
 #include "cache.h"
 #include "refs.h"
 #include "pkt-line.h"
-#include <sys/wait.h>
 
 static const char clone_pack_usage[] =
 "git-clone-pack [--exec=<git-upload-pack>] [<host>:]<directory> [<heads>]*";
@@ -112,139 +111,6 @@
 	free(head_path);
 }
 
-static int finish_pack(const char *pack_tmp_name)
-{
-	int pipe_fd[2];
-	pid_t pid;
-	char idx[PATH_MAX];
-	char final[PATH_MAX];
-	char hash[41];
-	unsigned char sha1[20];
-	char *cp;
-	int err = 0;
-
-	if (pipe(pipe_fd) < 0)
-		die("git-clone-pack: unable to set up pipe");
-
-	strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
-	cp = strrchr(idx, '/');
-	memcpy(cp, "/pidx", 5);
-
-	pid = fork();
-	if (pid < 0)
-		die("git-clone-pack: unable to fork off git-index-pack");
-	if (!pid) {
-		close(0);
-		dup2(pipe_fd[1], 1);
-		close(pipe_fd[0]);
-		close(pipe_fd[1]);
-		execlp("git-index-pack","git-index-pack",
-		       "-o", idx, pack_tmp_name, NULL);
-		error("cannot exec git-index-pack <%s> <%s>",
-		      idx, pack_tmp_name);
-		exit(1);
-	}
-	close(pipe_fd[1]);
-	if (read(pipe_fd[0], hash, 40) != 40) {
-		error("git-clone-pack: unable to read from git-index-pack");
-		err = 1;
-	}
-	close(pipe_fd[0]);
-
-	for (;;) {
-		int status, code;
-		int retval = waitpid(pid, &status, 0);
-
-		if (retval < 0) {
-			if (errno == EINTR)
-				continue;
-			error("waitpid failed (%s)", strerror(retval));
-			goto error_die;
-		}
-		if (WIFSIGNALED(status)) {
-			int sig = WTERMSIG(status);
-			error("git-index-pack died of signal %d", sig);
-			goto error_die;
-		}
-		if (!WIFEXITED(status)) {
-			error("git-index-pack died of unnatural causes %d",
-			      status);
-			goto error_die;
-		}
-		code = WEXITSTATUS(status);
-		if (code) {
-			error("git-index-pack died with error code %d", code);
-			goto error_die;
-		}
-		if (err)
-			goto error_die;
-		break;
-	}
-	hash[40] = 0;
-	if (get_sha1_hex(hash, sha1)) {
-		error("git-index-pack reported nonsense '%s'", hash);
-		goto error_die;
-	}
-	/* Now we have pack in pack_tmp_name[], and
-	 * idx in idx[]; rename them to their final names.
-	 */
-	snprintf(final, sizeof(final),
-		 "%s/pack/pack-%s.pack", get_object_directory(), hash);
-	move_temp_to_file(pack_tmp_name, final);
-	chmod(final, 0444);
-	snprintf(final, sizeof(final),
-		 "%s/pack/pack-%s.idx", get_object_directory(), hash);
-	move_temp_to_file(idx, final);
-	chmod(final, 0444);
-	return 0;
-
- error_die:
-	unlink(idx);
-	unlink(pack_tmp_name);
-	exit(1);
-}
-
-static int clone_without_unpack(int fd[2])
-{
-	char tmpfile[PATH_MAX];
-	int ofd, ifd;
-
-	ifd = fd[0];
-	snprintf(tmpfile, sizeof(tmpfile),
-		 "%s/pack/tmp-XXXXXX", get_object_directory());
-	ofd = mkstemp(tmpfile);
-	if (ofd < 0)
-		return error("unable to create temporary file %s", tmpfile);
-
-	while (1) {
-		char buf[8192];
-		ssize_t sz, wsz, pos;
-		sz = read(ifd, buf, sizeof(buf));
-		if (sz == 0)
-			break;
-		if (sz < 0) {
-			error("error reading pack (%s)", strerror(errno));
-			close(ofd);
-			unlink(tmpfile);
-			return -1;
-		}
-		pos = 0;
-		while (pos < sz) {
-			wsz = write(ofd, buf + pos, sz - pos);
-			if (wsz < 0) {
-				error("error writing pack (%s)",
-				      strerror(errno));
-				close(ofd);
-				unlink(tmpfile);
-				return -1;
-			}
-			pos += wsz;
-		}
-	}
-	close(ofd);
-	return finish_pack(tmpfile);
-}
-
 static int clone_pack(int fd[2], int nr_match, char **match)
 {
 	struct ref *refs;
@@ -257,10 +123,19 @@
 	}
 	clone_handshake(fd, refs);
 
-	status = clone_without_unpack(fd);
+	status = receive_keep_pack(fd, "git-clone-pack");
 
-	if (!status)
-		write_refs(refs);
+	if (!status) {
+		if (nr_match == 0)
+			write_refs(refs);
+		else
+			while (refs) {
+				printf("%s %s\n",
+				       sha1_to_hex(refs->old_sha1),
+				       refs->name);
+				refs = refs->next;
+			}
+	}
 	return status;
 }
 
@@ -285,8 +160,6 @@
 				exec = arg + 7;
 				continue;
 			}
-			if (!strcmp("--keep", arg))
-				continue;
 			usage(clone_pack_usage);
 		}
 		dest = arg;
diff --git a/cmd-rename.sh b/cmd-rename.sh
deleted file mode 100755
index 992493d..0000000
--- a/cmd-rename.sh
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/bin/sh
-#
-# If you installed git by hand previously, you may find this
-# script useful to remove the symbolic links that we shipped
-# for backward compatibility.
-#
-# Running this script with the previous installation directory
-# like this:
-#
-# $ cmd-rename.sh /usr/local/bin/
-#
-# would clean them.
-
-d="$1"
-test -d "$d" || exit
-while read old new
-do
-	rm -f "$d/$old"
-done <<\EOF
-git-add-script	git-add
-git-archimport-script	git-archimport
-git-bisect-script	git-bisect
-git-branch-script	git-branch
-git-checkout-script	git-checkout
-git-cherry-pick-script	git-cherry-pick
-git-clone-script	git-clone
-git-commit-script	git-commit
-git-count-objects-script	git-count-objects
-git-cvsimport-script	git-cvsimport
-git-diff-script	git-diff
-git-send-email-script	git-send-email
-git-fetch-script	git-fetch
-git-format-patch-script	git-format-patch
-git-log-script	git-log
-git-ls-remote-script	git-ls-remote
-git-merge-one-file-script	git-merge-one-file
-git-octopus-script	git-octopus
-git-parse-remote-script	git-parse-remote
-git-prune-script	git-prune
-git-pull-script	git-pull
-git-push-script	git-push
-git-rebase-script	git-rebase
-git-relink-script	git-relink
-git-rename-script	git-rename
-git-repack-script	git-repack
-git-request-pull-script	git-request-pull
-git-reset-script	git-reset
-git-resolve-script	git-resolve
-git-revert-script	git-revert
-git-sh-setup-script	git-sh-setup
-git-status-script	git-status
-git-tag-script	git-tag
-git-verify-tag-script	git-verify-tag
-git-http-pull	git-http-fetch
-git-local-pull	git-local-fetch
-git-checkout-cache	git-checkout-index
-git-diff-cache	git-diff-index
-git-merge-cache	git-merge-index
-git-update-cache	git-update-index
-git-convert-cache	git-convert-objects
-git-fsck-cache	git-fsck-objects
-EOF
diff --git a/copy.c b/copy.c
index e1cd5d0..7100eed 100644
--- a/copy.c
+++ b/copy.c
@@ -6,32 +6,27 @@
 		int len;
 		char buffer[8192];
 		char *buf = buffer;
-		len = read(ifd, buffer, sizeof(buffer));
+		len = xread(ifd, buffer, sizeof(buffer));
 		if (!len)
 			break;
 		if (len < 0) {
 			int read_error;
-			if (errno == EAGAIN)
-				continue;
 			read_error = errno;
 			close(ifd);
 			return error("copy-fd: read returned %s",
 				     strerror(read_error));
 		}
-		while (1) {
-			int written = write(ofd, buf, len);
+		while (len) {
+			int written = xwrite(ofd, buf, len);
 			if (written > 0) {
 				buf += written;
 				len -= written;
-				if (!len)
-					break;
 			}
-			if (!written)
+			else if (!written)
 				return error("copy-fd: write returned 0");
-			if (errno == EAGAIN || errno == EINTR)
-				continue;
-			return error("copy-fd: write returned %s",
-				     strerror(errno));
+			else
+				return error("copy-fd: write returned %s",
+					     strerror(errno));
 		}
 	}
 	close(ifd);
diff --git a/csum-file.c b/csum-file.c
index c66b9eb..5f9249a 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -15,7 +15,7 @@
 	void *buf = f->buffer;
 
 	for (;;) {
-		int ret = write(f->fd, buf, count);
+		int ret = xwrite(f->fd, buf, count);
 		if (ret > 0) {
 			buf += ret;
 			count -= ret;
@@ -25,8 +25,6 @@
 		}
 		if (!ret)
 			die("sha1 file '%s' write error. Out of diskspace", f->name);
-		if (errno == EAGAIN || errno == EINTR)
-			continue;
 		die("sha1 file '%s' write error (%s)", f->name, strerror(errno));
 	}
 }
diff --git a/debian/changelog b/debian/changelog
index d36904c..4fa6c16 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+git-core (1.0.0-0) unstable; urgency=low
+
+  * GIT 1.0.0
+
+ -- Junio C Hamano <junkio@cox.net>  Wed, 21 Dec 2005 00:01:00 -0800
+
 git-core (0.99.9n-0) unstable; urgency=low
 
   * GIT 0.99.9n aka 1.0rc6
diff --git a/diff-delta.c b/diff-delta.c
index b2ae7b5..890986e 100644
--- a/diff-delta.c
+++ b/diff-delta.c
@@ -84,20 +84,15 @@
 } chanode_t;
 
 typedef struct s_chastore {
-	chanode_t *head, *tail;
 	int isize, nsize;
 	chanode_t *ancur;
-	chanode_t *sncur;
-	int scurr;
 } chastore_t;
 
 static void cha_init(chastore_t *cha, int isize, int icount)
 {
-	cha->head = cha->tail = NULL;
 	cha->isize = isize;
 	cha->nsize = icount * isize;
-	cha->ancur = cha->sncur = NULL;
-	cha->scurr = 0;
+	cha->ancur = NULL;
 }
 
 static void *cha_alloc(chastore_t *cha)
@@ -111,12 +106,7 @@
 		if (!ancur)
 			return NULL;
 		ancur->icurr = 0;
-		ancur->next = NULL;
-		if (cha->tail)
-			cha->tail->next = ancur;
-		if (!cha->head)
-			cha->head = ancur;
-		cha->tail = ancur;
+		ancur->next = cha->ancur;
 		cha->ancur = ancur;
 	}
 
@@ -127,7 +117,7 @@
 
 static void cha_free(chastore_t *cha)
 {
-	chanode_t *cur = cha->head;
+	chanode_t *cur = cha->ancur;
 	while (cur) {
 		chanode_t *tmp = cur;
 		cur = cur->next;
@@ -142,7 +132,6 @@
 } bdrecord_t;
 
 typedef struct s_bdfile {
-	const unsigned char *data, *top;
 	chastore_t cha;
 	unsigned int fphbits;
 	bdrecord_t **fphash;
@@ -152,7 +141,7 @@
 {
 	unsigned int fphbits;
 	int i, hsize;
-	const unsigned char *base, *data, *top;
+	const unsigned char *data, *top;
 	bdrecord_t *brec;
 	bdrecord_t **fphash;
 
@@ -165,13 +154,12 @@
 		fphash[i] = NULL;
 	cha_init(&bdf->cha, sizeof(bdrecord_t), hsize / 4 + 1);
 
-	bdf->data = data = base = buf;
-	bdf->top = top = buf + bufsize;
-	data += (bufsize / BLK_SIZE) * BLK_SIZE;
+	top = buf + bufsize;
+	data = buf + (bufsize / BLK_SIZE) * BLK_SIZE;
 	if (data == top)
 		data -= BLK_SIZE;
 
-	for ( ; data >= base; data -= BLK_SIZE) {
+	for ( ; data >= buf; data -= BLK_SIZE) {
 		brec = cha_alloc(&bdf->cha);
 		if (!brec) {
 			cha_free(&bdf->cha);
@@ -208,7 +196,7 @@
 {
 	int i, outpos, outsize, inscnt, csize, msize, moff;
 	unsigned int fp;
-	const unsigned char *data, *top, *ptr1, *ptr2;
+	const unsigned char *ref_data, *ref_top, *data, *top, *ptr1, *ptr2;
 	unsigned char *out, *orig;
 	bdrecord_t *brec;
 	bdfile_t bdf;
@@ -224,6 +212,8 @@
 		return NULL;
 	}
 
+	ref_data = from_buf;
+	ref_top = from_buf + from_size;
 	data = to_buf;
 	top = to_buf + to_size;
 
@@ -253,7 +243,7 @@
 		i = HASH(fp, bdf.fphbits);
 		for (brec = bdf.fphash[i]; brec; brec = brec->next) {
 			if (brec->fp == fp) {
-				csize = bdf.top - brec->ptr;
+				csize = ref_top - brec->ptr;
 				if (csize > top - data)
 					csize = top - data;
 				for (ptr1 = brec->ptr, ptr2 = data; 
@@ -262,7 +252,7 @@
 
 				csize = ptr1 - brec->ptr;
 				if (csize > msize) {
-					moff = brec->ptr - bdf.data;
+					moff = brec->ptr - ref_data;
 					msize = csize;
 					if (msize >= 0x10000) {
 						msize = 0x10000;
diff --git a/diff-tree.c b/diff-tree.c
index d56d921..efa2b94 100644
--- a/diff-tree.c
+++ b/diff-tree.c
@@ -14,11 +14,6 @@
 
 static struct diff_options diff_options;
 
-static void call_diff_setup_done(void)
-{
-	diff_setup_done(&diff_options);
-}
-
 static int call_diff_flush(void)
 {
 	diffcore_std(&diff_options);
@@ -43,7 +38,6 @@
 {
 	int ret;
 
-	call_diff_setup_done();
 	ret = diff_tree_sha1(old, new, base, &diff_options);
 	call_diff_flush();
 	return ret;
@@ -55,7 +49,6 @@
 	void *tree;
 	struct tree_desc empty, real;
 
-	call_diff_setup_done();
 	tree = read_object_with_reference(new, "tree", &real.size, NULL);
 	if (!tree)
 		die("unable to read root tree (%s)", sha1_to_hex(new));
@@ -69,18 +62,29 @@
 	return retval;
 }
 
-static const char *generate_header(const char *commit, const char *parent, const char *msg)
+static const char *generate_header(const unsigned char *commit_sha1,
+				   const unsigned char *parent_sha1,
+				   const char *msg)
 {
 	static char this_header[16384];
 	int offset;
 	unsigned long len;
+	int abbrev = diff_options.abbrev;
 
 	if (!verbose_header)
-		return commit;
+		return sha1_to_hex(commit_sha1);
 
 	len = strlen(msg);
-	offset = sprintf(this_header, "%s%s (from %s)\n", header_prefix, commit, parent);
-	offset += pretty_print_commit(commit_format, msg, len, this_header + offset, sizeof(this_header) - offset);
+
+	offset = sprintf(this_header, "%s%s ",
+			 header_prefix,
+			 diff_unique_abbrev(commit_sha1, abbrev));
+	offset += sprintf(this_header + offset, "(from %s)\n",
+			 parent_sha1 ?
+			 diff_unique_abbrev(parent_sha1, abbrev) : "root");
+	offset += pretty_print_commit(commit_format, msg, len,
+				      this_header + offset,
+				      sizeof(this_header) - offset);
 	return this_header;
 }
 
@@ -99,18 +103,18 @@
 	
 	/* Root commit? */
 	if (show_root_diff && !commit->parents) {
-		header = generate_header(name, "root", commit->buffer);
+		header = generate_header(sha1, NULL, commit->buffer);
 		diff_root_tree(commit_sha1, "");
 	}
 
 	/* More than one parent? */
 	if (ignore_merges && commit->parents && commit->parents->next)
-			return 0;
+		return 0;
 
 	for (parents = commit->parents; parents; parents = parents->next) {
 		struct commit *parent = parents->item;
-		header = generate_header(name,
-					 sha1_to_hex(parent->object.sha1),
+		header = generate_header(sha1,
+					 parent->object.sha1,
 					 commit->buffer);
 		diff_tree_sha1_top(parent->object.sha1, commit_sha1, "");
 		if (!header && verbose_header) {
@@ -129,6 +133,7 @@
 	int len = strlen(line);
 	unsigned char commit[20], parent[20];
 	static char this_header[1000];
+	int abbrev = diff_options.abbrev;
 
 	if (!len || line[len-1] != '\n')
 		return -1;
@@ -138,7 +143,9 @@
 	if (isspace(line[40]) && !get_sha1_hex(line+41, parent)) {
 		line[40] = 0;
 		line[81] = 0;
-		sprintf(this_header, "%s (from %s)\n", line, line+41);
+		sprintf(this_header, "%s (from %s)\n",
+			diff_unique_abbrev(commit, abbrev),
+			diff_unique_abbrev(parent, abbrev));
 		header = this_header;
 		return diff_tree_sha1_top(parent, commit, "");
 	}
@@ -239,6 +246,7 @@
 		diff_options.recursive = 1;
 
 	diff_tree_setup_paths(get_pathspec(prefix, argv));
+	diff_setup_done(&diff_options);
 
 	switch (nr_sha1) {
 	case 0:
diff --git a/diff.c b/diff.c
index 2e0797b..c815918 100644
--- a/diff.c
+++ b/diff.c
@@ -723,11 +723,13 @@
 
 	if (memcmp(one->sha1, two->sha1, 20)) {
 		char one_sha1[41];
-		const char *index_fmt = o->full_index ? "index %s..%s" : "index %.7s..%.7s";
+		int abbrev = o->full_index ? 40 : DIFF_DEFAULT_INDEX_ABBREV;
 		memcpy(one_sha1, sha1_to_hex(one->sha1), 41);
 
 		len += snprintf(msg + len, sizeof(msg) - len,
-				index_fmt, one_sha1, sha1_to_hex(two->sha1));
+				"index %.*s..%.*s",
+				abbrev, one_sha1, abbrev,
+				sha1_to_hex(two->sha1));
 		if (one->mode == two->mode)
 			len += snprintf(msg + len, sizeof(msg) - len,
 					" %06o", one->mode);
@@ -791,6 +793,8 @@
 	}
 	if (options->setup & DIFF_SETUP_USE_SIZE_CACHE)
 		use_size_cache = 1;
+	if (options->abbrev <= 0 || 40 < options->abbrev)
+		options->abbrev = 40; /* full */
 
 	return 0;
 }
@@ -841,6 +845,10 @@
 	}
 	else if (!strcmp(arg, "--find-copies-harder"))
 		options->find_copies_harder = 1;
+	else if (!strcmp(arg, "--abbrev"))
+		options->abbrev = DIFF_DEFAULT_ABBREV;
+	else if (!strncmp(arg, "--abbrev=", 9))
+		options->abbrev = strtoul(arg + 9, NULL, 10);
 	else
 		return 0;
 	return 1;
@@ -947,14 +955,49 @@
 	free(p);
 }
 
+/* This is different from find_unique_abbrev() in that
+ * it needs to deal with 0{40} SHA1.
+ */
+const char *diff_unique_abbrev(const unsigned char *sha1, int len)
+{
+	int abblen;
+	const char *abbrev;
+	if (len == 40)
+		return sha1_to_hex(sha1);
+
+	abbrev = find_unique_abbrev(sha1, len);
+	if (!abbrev) {
+		if (!memcmp(sha1, null_sha1, 20)) {
+			char *buf = sha1_to_hex(null_sha1);
+			if (len < 37)
+				strcpy(buf + len, "...");
+			return buf;
+		}
+		else 
+			return sha1_to_hex(sha1);
+	}
+	abblen = strlen(abbrev);
+	if (abblen < 37) {
+		static char hex[41];
+		if (len < abblen && abblen <= len + 2)
+			sprintf(hex, "%s%.*s", abbrev, len+3-abblen, "..");
+		else
+			sprintf(hex, "%s...", abbrev);
+		return hex;
+	}
+	return sha1_to_hex(sha1);
+}
+
 static void diff_flush_raw(struct diff_filepair *p,
 			   int line_termination,
 			   int inter_name_termination,
-			   int output_format)
+			   struct diff_options *options)
 {
 	int two_paths;
 	char status[10];
+	int abbrev = options->abbrev;
 	const char *path_one, *path_two;
+	int output_format = options->output_format;
 
 	path_one = p->one->path;
 	path_two = p->two->path;
@@ -985,8 +1028,10 @@
 	}
 	if (output_format != DIFF_FORMAT_NAME_STATUS) {
 		printf(":%06o %06o %s ",
-		       p->one->mode, p->two->mode, sha1_to_hex(p->one->sha1));
-		printf("%s ", sha1_to_hex(p->two->sha1));
+		       p->one->mode, p->two->mode,
+		       diff_unique_abbrev(p->one->sha1, abbrev));
+		printf("%s ",
+		       diff_unique_abbrev(p->two->sha1, abbrev));
 	}
 	printf("%s%c%s", status, inter_name_termination, path_one);
 	if (two_paths)
@@ -1194,7 +1239,7 @@
 		case DIFF_FORMAT_NAME_STATUS:
 			diff_flush_raw(p, line_termination,
 				       inter_name_termination,
-				       diff_output_format);
+				       options);
 			break;
 		case DIFF_FORMAT_NAME:
 			diff_flush_name(p,
diff --git a/diff.h b/diff.h
index 32b4780..5696f2a 100644
--- a/diff.h
+++ b/diff.h
@@ -44,6 +44,7 @@
 	int reverse_diff;
 	int rename_limit;
 	int setup;
+	int abbrev;
 
 	change_fn_t change;
 	add_remove_fn_t add_remove;
@@ -87,6 +88,9 @@
 
 #define DIFF_PICKAXE_ALL	1
 
+#define DIFF_DEFAULT_INDEX_ABBREV	7 /* hex digits */
+#define DIFF_DEFAULT_ABBREV	7 /* hex digits */
+
 extern void diffcore_std(struct diff_options *);
 
 extern void diffcore_std_no_resolve(struct diff_options *);
@@ -98,7 +102,8 @@
 "  -u            synonym for -p.\n" \
 "  --name-only   show only names of changed files.\n" \
 "  --name-status show names and status of changed files.\n" \
-"  --full-index  show full object name on index ines.\n" \
+"  --full-index  show full object name on index lines.\n" \
+"  --abbrev=<n>  abbreviate object names in diff-tree header and diff-raw.\n" \
 "  -R            swap input file pairs.\n" \
 "  -B            detect complete rewrites.\n" \
 "  -M            detect renames.\n" \
@@ -137,4 +142,6 @@
 #define DIFF_STATUS_FILTER_AON		'*'
 #define DIFF_STATUS_FILTER_BROKEN	'B'
 
+extern const char *diff_unique_abbrev(const unsigned char *, int);
+
 #endif /* DIFF_H */
diff --git a/fetch-clone.c b/fetch-clone.c
new file mode 100644
index 0000000..2b2aa15
--- /dev/null
+++ b/fetch-clone.c
@@ -0,0 +1,172 @@
+#include "cache.h"
+#include <sys/wait.h>
+
+static int finish_pack(const char *pack_tmp_name, const char *me)
+{
+	int pipe_fd[2];
+	pid_t pid;
+	char idx[PATH_MAX];
+	char final[PATH_MAX];
+	char hash[41];
+	unsigned char sha1[20];
+	char *cp;
+	int err = 0;
+
+	if (pipe(pipe_fd) < 0)
+		die("%s: unable to set up pipe", me);
+
+	strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
+	cp = strrchr(idx, '/');
+	memcpy(cp, "/pidx", 5);
+
+	pid = fork();
+	if (pid < 0)
+		die("git-clone-pack: unable to fork off git-index-pack");
+	if (!pid) {
+		close(0);
+		dup2(pipe_fd[1], 1);
+		close(pipe_fd[0]);
+		close(pipe_fd[1]);
+		execlp("git-index-pack","git-index-pack",
+		       "-o", idx, pack_tmp_name, NULL);
+		error("cannot exec git-index-pack <%s> <%s>",
+		      idx, pack_tmp_name);
+		exit(1);
+	}
+	close(pipe_fd[1]);
+	if (read(pipe_fd[0], hash, 40) != 40) {
+		error("%s: unable to read from git-index-pack", me);
+		err = 1;
+	}
+	close(pipe_fd[0]);
+
+	for (;;) {
+		int status, code;
+		int retval = waitpid(pid, &status, 0);
+
+		if (retval < 0) {
+			if (errno == EINTR)
+				continue;
+			error("waitpid failed (%s)", strerror(retval));
+			goto error_die;
+		}
+		if (WIFSIGNALED(status)) {
+			int sig = WTERMSIG(status);
+			error("git-index-pack died of signal %d", sig);
+			goto error_die;
+		}
+		if (!WIFEXITED(status)) {
+			error("git-index-pack died of unnatural causes %d",
+			      status);
+			goto error_die;
+		}
+		code = WEXITSTATUS(status);
+		if (code) {
+			error("git-index-pack died with error code %d", code);
+			goto error_die;
+		}
+		if (err)
+			goto error_die;
+		break;
+	}
+	hash[40] = 0;
+	if (get_sha1_hex(hash, sha1)) {
+		error("git-index-pack reported nonsense '%s'", hash);
+		goto error_die;
+	}
+	/* Now we have pack in pack_tmp_name[], and
+	 * idx in idx[]; rename them to their final names.
+	 */
+	snprintf(final, sizeof(final),
+		 "%s/pack/pack-%s.pack", get_object_directory(), hash);
+	move_temp_to_file(pack_tmp_name, final);
+	chmod(final, 0444);
+	snprintf(final, sizeof(final),
+		 "%s/pack/pack-%s.idx", get_object_directory(), hash);
+	move_temp_to_file(idx, final);
+	chmod(final, 0444);
+	return 0;
+
+ error_die:
+	unlink(idx);
+	unlink(pack_tmp_name);
+	exit(1);
+}
+
+int receive_unpack_pack(int fd[2], const char *me, int quiet)
+{
+	int status;
+	pid_t pid;
+
+	pid = fork();
+	if (pid < 0)
+		die("%s: unable to fork off git-unpack-objects", me);
+	if (!pid) {
+		dup2(fd[0], 0);
+		close(fd[0]);
+		close(fd[1]);
+		execlp("git-unpack-objects", "git-unpack-objects",
+		       quiet ? "-q" : NULL, NULL);
+		die("git-unpack-objects exec failed");
+	}
+	close(fd[0]);
+	close(fd[1]);
+	while (waitpid(pid, &status, 0) < 0) {
+		if (errno != EINTR)
+			die("waiting for git-unpack-objects: %s",
+			    strerror(errno));
+	}
+	if (WIFEXITED(status)) {
+		int code = WEXITSTATUS(status);
+		if (code)
+			die("git-unpack-objects died with error code %d",
+			    code);
+		return 0;
+	}
+	if (WIFSIGNALED(status)) {
+		int sig = WTERMSIG(status);
+		die("git-unpack-objects died of signal %d", sig);
+	}
+	die("git-unpack-objects died of unnatural causes %d", status);
+}
+
+int receive_keep_pack(int fd[2], const char *me)
+{
+	char tmpfile[PATH_MAX];
+	int ofd, ifd;
+
+	ifd = fd[0];
+	snprintf(tmpfile, sizeof(tmpfile),
+		 "%s/pack/tmp-XXXXXX", get_object_directory());
+	ofd = mkstemp(tmpfile);
+	if (ofd < 0)
+		return error("unable to create temporary file %s", tmpfile);
+
+	while (1) {
+		char buf[8192];
+		ssize_t sz, wsz, pos;
+		sz = read(ifd, buf, sizeof(buf));
+		if (sz == 0)
+			break;
+		if (sz < 0) {
+			error("error reading pack (%s)", strerror(errno));
+			close(ofd);
+			unlink(tmpfile);
+			return -1;
+		}
+		pos = 0;
+		while (pos < sz) {
+			wsz = write(ofd, buf + pos, sz - pos);
+			if (wsz < 0) {
+				error("error writing pack (%s)",
+				      strerror(errno));
+				close(ofd);
+				unlink(tmpfile);
+				return -1;
+			}
+			pos += wsz;
+		}
+	}
+	close(ofd);
+	return finish_pack(tmpfile, me);
+}
diff --git a/fetch-pack.c b/fetch-pack.c
index 58ba209..d34f322 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -3,13 +3,12 @@
 #include "pkt-line.h"
 #include "commit.h"
 #include "tag.h"
-#include <time.h>
-#include <sys/wait.h>
 
+static int keep_pack;
 static int quiet;
 static int verbose;
 static const char fetch_pack_usage[] =
-"git-fetch-pack [-q] [-v] [--exec=upload-pack] [host:]directory <refs>...";
+"git-fetch-pack [-q] [-v] [-k] [--exec=upload-pack] [host:]directory <refs>...";
 static const char *exec = "git-upload-pack";
 
 #define COMPLETE	(1U << 0)
@@ -363,7 +362,6 @@
 	struct ref *ref;
 	unsigned char sha1[20];
 	int status;
-	pid_t pid;
 
 	get_remote_heads(fd[0], &ref, 0, NULL, 0);
 	if (server_supports("multi_ack")) {
@@ -381,40 +379,22 @@
 	}
 	if (find_common(fd, sha1, ref) < 0)
 		fprintf(stderr, "warning: no common commits\n");
-	pid = fork();
-	if (pid < 0)
-		die("git-fetch-pack: unable to fork off git-unpack-objects");
-	if (!pid) {
-		dup2(fd[0], 0);
-		close(fd[0]);
-		close(fd[1]);
-		execlp("git-unpack-objects", "git-unpack-objects",
-		       quiet ? "-q" : NULL, NULL);
-		die("git-unpack-objects exec failed");
+
+	if (keep_pack)
+		status = receive_keep_pack(fd, "git-fetch-pack");
+	else
+		status = receive_unpack_pack(fd, "git-fetch-pack", quiet);
+
+	if (status)
+		die("git-fetch-pack: fetch failed.");
+
+ all_done:
+	while (ref) {
+		printf("%s %s\n",
+		       sha1_to_hex(ref->old_sha1), ref->name);
+		ref = ref->next;
 	}
-	close(fd[0]);
-	close(fd[1]);
-	while (waitpid(pid, &status, 0) < 0) {
-		if (errno != EINTR)
-			die("waiting for git-unpack-objects: %s", strerror(errno));
-	}
-	if (WIFEXITED(status)) {
-		int code = WEXITSTATUS(status);
-		if (code)
-			die("git-unpack-objects died with error code %d", code);
-all_done:
-		while (ref) {
-			printf("%s %s\n",
-			       sha1_to_hex(ref->old_sha1), ref->name);
-			ref = ref->next;
-		}
-		return 0;
-	}
-	if (WIFSIGNALED(status)) {
-		int sig = WTERMSIG(status);
-		die("git-unpack-objects died of signal %d", sig);
-	}
-	die("Sherlock Holmes! git-unpack-objects died of unnatural causes %d!", status);
+	return 0;
 }
 
 int main(int argc, char **argv)
@@ -436,10 +416,14 @@
 				exec = arg + 7;
 				continue;
 			}
-			if (!strcmp("-q", arg)) {
+			if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
 				quiet = 1;
 				continue;
 			}
+			if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
+				keep_pack = 1;
+				continue;
+			}
 			if (!strcmp("-v", arg)) {
 				verbose = 1;
 				continue;
diff --git a/git-am.sh b/git-am.sh
index 1a114bc..731ab1ff 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -211,6 +211,7 @@
 if test "$skip" = t
 then
 	this=`expr "$this" + 1`
+	resume=
 fi
 
 if test "$this" -gt "$last"
@@ -225,6 +226,7 @@
 	msgnum=`printf "%0${prec}d" $this`
 	next=`expr "$this" + 1`
 	test -f "$dotest/$msgnum" || {
+		resume=
 		go_next
 		continue
 	}
diff --git a/git-applypatch.sh b/git-applypatch.sh
index e8ba34a..12cab1e 100755
--- a/git-applypatch.sh
+++ b/git-applypatch.sh
@@ -14,7 +14,7 @@
 USAGE='<msg> <patch> <info> [<signoff>]'
 . git-sh-setup
 
-case "$#" in 3|4) usage ;; esac
+case "$#" in 3|4) ;; *) usage ;; esac
 
 final=.dotest/final-commit
 ##
diff --git a/git-archimport.perl b/git-archimport.perl
index aab4e38..841738d 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -9,7 +9,8 @@
 
 =head1 Invocation
 
-    git-archimport [ -h ] [ -v ] [ -T ] [ -t tempdir ] <archive>/<branch> [ <archive>/<branch> ]
+    git-archimport [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ] 
+    	[ -D depth] [ -t tempdir ] <archive>/<branch> [ <archive>/<branch> ]
 
 Imports a project from one or more Arch repositories. It will follow branches
 and repositories within the namespaces defined by the <archive/branch>
@@ -74,7 +75,7 @@
 sub usage() {
     print STDERR <<END;
 Usage: ${\basename $0}     # fetch/update GIT from Arch
-       [ -f ] [ -o ] [ -h ] [ -v ] [ -T ] [ -a ] [ -D depth  ] [ -t tempdir ]
+       [ -h ] [ -v ] [ -o ] [ -a ] [ -f ] [ -T ] [ -D depth ] [ -t tempdir ]
        repository/arch-branch [ repository/arch-branch] ...
 END
     exit(1);
diff --git a/git-branch.sh b/git-branch.sh
index 0266f462..b0e54ed 100755
--- a/git-branch.sh
+++ b/git-branch.sh
@@ -32,11 +32,11 @@
 	    case " $mbs " in
 	    *' '$branch' '*)
 		# the merge base of branch and HEAD contains branch --
-		# which means that the HEAD contains everything in the HEAD.
+		# which means that the HEAD contains everything in both.
 		;;
 	    *)
 		echo >&2 "The branch '$branch_name' is not a strict subset of your current HEAD.
-    If you are sure you want to delete it, run 'git branch -D $branch_name'."
+If you are sure you want to delete it, run 'git branch -D $branch_name'."
 		exit 1
 		;;
 	    esac
diff --git a/git-checkout.sh b/git-checkout.sh
index f241d4b..36308d2 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -116,7 +116,7 @@
 fi
 
 # 
-# Switch the HEAD pointer to the new branch if it we
+# Switch the HEAD pointer to the new branch if we
 # checked out a branch head, and remove any potential
 # old MERGE_HEAD's (subsequent commits will clearly not
 # be based on them, since we re-set the index)
diff --git a/git-compat-util.h b/git-compat-util.h
index ead0ede..0c98c99 100644
--- a/git-compat-util.h
+++ b/git-compat-util.h
@@ -84,6 +84,28 @@
 	return ret;
 }
 
+static inline ssize_t xread(int fd, void *buf, size_t len)
+{
+	ssize_t nr;
+	while (1) {
+		nr = read(fd, buf, len);
+		if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
+			continue;
+		return nr;
+	}
+}
+
+static inline ssize_t xwrite(int fd, const void *buf, size_t len)
+{
+	ssize_t nr;
+	while (1) {
+		nr = write(fd, buf, len);
+		if ((nr < 0) && (errno == EAGAIN || errno == EINTR))
+			continue;
+		return nr;
+	}
+}
+
 /* Sane ctype - no locale, and works with signed chars */
 #undef isspace
 #undef isdigit
diff --git a/git-diff.sh b/git-diff.sh
index b62e583..4812ae4 100755
--- a/git-diff.sh
+++ b/git-diff.sh
@@ -3,15 +3,14 @@
 # Copyright (c) 2005 Linus Torvalds
 # Copyright (c) 2005 Junio C Hamano
 
+USAGE='[ --diff-options ] <ent>{0,2} [<path>...]'
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
+
 rev=$(git-rev-parse --revs-only --no-flags --sq "$@") || exit
 flags=$(git-rev-parse --no-revs --flags --sq "$@")
 files=$(git-rev-parse --no-revs --no-flags --sq "$@")
 
-die () {
-    echo >&2 "$*"
-    exit 1
-}
-
 # I often say 'git diff --cached -p' and get scolded by git-diff-files, but
 # obviously I mean 'git diff --cached -p HEAD' in that case.
 case "$rev" in
@@ -40,8 +39,7 @@
 
 case "$rev" in
 ?*' '?*' '?*)
-	echo >&2 "I don't understand"
-	exit 1
+	usage
 	;;
 ?*' '^?*)
 	begin=$(expr "$rev" : '.*^.\([0-9a-f]*\).*') &&
@@ -58,7 +56,7 @@
 	cmd="git-diff-files $flags -- $files"
 	;;
 *)
-	die "I don't understand $*"
+	usage
 	;;
 esac
 
diff --git a/git-format-patch.sh b/git-format-patch.sh
index 01508e3..daa3cae 100755
--- a/git-format-patch.sh
+++ b/git-format-patch.sh
@@ -210,6 +210,8 @@
 	}
 
 	mailScript="$mailScript"'
+	a\
+
 	: body
 	p
 	n
diff --git a/git-log.sh b/git-log.sh
index b36c4e9..c2ea71c 100755
--- a/git-log.sh
+++ b/git-log.sh
@@ -3,13 +3,13 @@
 # Copyright (c) 2005 Linus Torvalds
 #
 
-# This one uses only subdirectory-aware commands, so no need to
-# include sh-setup-script.
+USAGE='[--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [git-rev-list options]'
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
 
 revs=$(git-rev-parse --revs-only --no-flags --default HEAD "$@") || exit
 [ "$revs" ] || {
-	echo >&2 "No HEAD ref"
-	exit 1
+	die "No HEAD ref"
 }
 git-rev-list --pretty $(git-rev-parse --default HEAD "$@") |
 LESS=-S ${PAGER:-less}
diff --git a/git-octopus.sh b/git-octopus.sh
deleted file mode 100755
index 2edbf52..0000000
--- a/git-octopus.sh
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Junio C Hamano
-#
-# Resolve two or more trees recorded in $GIT_DIR/FETCH_HEAD.
-#
-. git-sh-setup
-
-usage () {
-    die "usage: git octopus"
-}
-
-# Sanity check the heads early.
-while read SHA1 REPO
-do
-	test $(git-cat-file -t $SHA1) = "commit" ||
-		die "$REPO given to octopus is not a commit"
-done <"$GIT_DIR/FETCH_HEAD"
-
-head=$(git-rev-parse --verify HEAD) || exit
-
-git-update-index --refresh ||
-	die "Your working tree is dirty."
-test "$(git-diff-index --cached "$head")" = "" ||
-	die "Your working tree does not match HEAD."
-
-# MRC is the current "merge reference commit"
-# MRT is the current "merge result tree"
-
-MRC=$head PARENT="-p $head"
-MRT=$(git-write-tree)
-CNT=1 ;# counting our head
-NON_FF_MERGE=0
-while read SHA1 REPO
-do
-	common=$(git-merge-base $MRC $SHA1) ||
-		die "Unable to find common commit with $SHA1 from $REPO"
-
-	if test "$common" = $SHA1
-	then
-		echo "Already up-to-date: $REPO"
-		continue
-	fi
-
-	CNT=`expr $CNT + 1`
-	PARENT="$PARENT -p $SHA1"
-
-	if test "$common,$NON_FF_MERGE" = "$MRC,0"
-	then
-		# The first head being merged was a fast-forward.
-		# Advance MRC to the head being merged, and use that
-		# tree as the intermediate result of the merge.
-		# We still need to count this as part of the parent set.
-
-		echo "Fast forwarding to: $REPO"
-		git-read-tree -u -m $head $SHA1 || exit
-		MRC=$SHA1 MRT=$(git-write-tree)
-		continue
-	fi
-
-	NON_FF_MERGE=1
-
-	echo "Trying simple merge with $REPO"
-	git-read-tree -u -m $common $MRT $SHA1 || exit
-	next=$(git-write-tree 2>/dev/null)
-	if test $? -ne 0
-	then
-		echo "Simple merge did not work, trying automatic merge."
-		git-merge-index -o git-merge-one-file -a || {
-		git-read-tree --reset "$head"
-		git-checkout-index -f -q -u -a
-		die "Automatic merge failed; should not be doing Octopus"
-		}
-		next=$(git-write-tree 2>/dev/null)
-	fi
-	MRC=$common
-	MRT=$next
-done <"$GIT_DIR/FETCH_HEAD"
-
-# Just to be careful in case the user feeds nonsense to us.
-case "$CNT" in
-1)
-	echo "No changes."
-	exit 0 ;;
-esac
-result_commit=$(git-fmt-merge-msg <"$GIT_DIR/FETCH_HEAD" |
-		git-commit-tree $MRT $PARENT)
-echo "Committed merge $result_commit"
-git-update-ref HEAD $result_commit $head
-git-diff-tree -p $head $result_commit | git-apply --stat
diff --git a/git-svnimport.perl b/git-svnimport.perl
index 65868a9..cb241d1 100755
--- a/git-svnimport.perl
+++ b/git-svnimport.perl
@@ -736,6 +736,13 @@
 }
 
 $opt_l = $svn->{'maxrev'} if not defined $opt_l or $opt_l > $svn->{'maxrev'};
+
+if ($svn->{'maxrev'} < $current_rev) {
+    print "Up to date: no new revisions to fetch!\n" if $opt_v;
+    unlink("$git_dir/SVN2GIT_HEAD");
+    exit;
+}
+
 print "Fetching from $current_rev to $opt_l ...\n" if $opt_v;
 
 my $pool=SVN::Pool->new;
diff --git a/git-whatchanged.sh b/git-whatchanged.sh
index 85a49fc..b170f74 100755
--- a/git-whatchanged.sh
+++ b/git-whatchanged.sh
@@ -1,4 +1,9 @@
 #!/bin/sh
+
+USAGE='[-p] [--max-count=<n>] [<since>..<limit>] [--pretty=<format>] [-m] [git-diff-tree options] [git-rev-list options]'
+SUBDIRECTORY_OK='Yes'
+. git-sh-setup
+
 rev_list_args=$(git-rev-parse --sq --default HEAD --revs-only "$@") &&
 diff_tree_args=$(git-rev-parse --sq --no-revs "$@") &&
 
diff --git a/git.c b/git.c
index c26cac6..0fd95bf 100644
--- a/git.c
+++ b/git.c
@@ -8,6 +8,7 @@
 #include <errno.h>
 #include <limits.h>
 #include <stdarg.h>
+#include <sys/ioctl.h>
 #include "git-compat-util.h"
 
 #ifndef PATH_MAX
@@ -26,6 +27,16 @@
 	if (col_string && (n_cols = atoi(col_string)) > 0)
 		return n_cols;
 
+#ifdef TIOCGWINSZ
+	{
+		struct winsize ws;
+		if (!ioctl(1, TIOCGWINSZ, &ws)) {
+			if (ws.ws_col)
+				return ws.ws_col;
+		}
+	}
+#endif
+
 	return 80;
 }
 
@@ -74,25 +85,28 @@
 
 static void pretty_print_string_list(struct cmdname **cmdname, int longest)
 {
-	int cols = 1;
+	int cols = 1, rows;
 	int space = longest + 1; /* min 1 SP between words */
 	int max_cols = term_columns() - 1; /* don't print *on* the edge */
-	int i;
+	int i, j;
 
 	if (space < max_cols)
 		cols = max_cols / space;
+	rows = (cmdname_cnt + cols - 1) / cols;
 
 	qsort(cmdname, cmdname_cnt, sizeof(*cmdname), cmdname_compare);
 
-	for (i = 0; i < cmdname_cnt; ) {
-		int c;
+	for (i = 0; i < rows; i++) {
 		printf("  ");
 
-		for (c = cols; c && i < cmdname_cnt; i++) {
-			printf("%s", cmdname[i]->name);
-
-			if (--c)
-				mput_char(' ', space - cmdname[i]->len);
+		for (j = 0; j < cols; j++) {
+			int n = j * rows + i;
+			int size = space;
+			if (n >= cmdname_cnt)
+				break;
+			if (j == cols-1 || n + rows >= cmdname_cnt)
+				size = 1;
+			printf("%-*s", size, cmdname[n]->name);
 		}
 		putchar('\n');
 	}
diff --git a/mktag.c b/mktag.c
index 97e270a..fc6a9bf 100644
--- a/mktag.c
+++ b/mktag.c
@@ -116,14 +116,9 @@
 	// Read the signature
 	size = 0;
 	for (;;) {
-		int ret = read(0, buffer + size, MAXSIZE - size);
-		if (!ret)
+		int ret = xread(0, buffer + size, MAXSIZE - size);
+		if (ret <= 0)
 			break;
-		if (ret < 0) {
-			if (errno == EAGAIN)
-				continue;
-			break;
-		}
 		size += ret;
 	}
 
diff --git a/pkt-line.c b/pkt-line.c
index 6947304..bb3bab0 100644
--- a/pkt-line.c
+++ b/pkt-line.c
@@ -19,7 +19,7 @@
 static void safe_write(int fd, const void *buf, unsigned n)
 {
 	while (n) {
-		int ret = write(fd, buf, n);
+		int ret = xwrite(fd, buf, n);
 		if (ret > 0) {
 			buf += ret;
 			n -= ret;
@@ -27,8 +27,6 @@
 		}
 		if (!ret)
 			die("write error (disk full?)");
-		if (errno == EAGAIN || errno == EINTR)
-			continue;
 		die("write error (%s)", strerror(errno));
 	}
 }
@@ -68,12 +66,9 @@
 	int n = 0;
 
 	while (n < size) {
-		int ret = read(fd, buffer + n, size - n);
-		if (ret < 0) {
-			if (errno == EINTR || errno == EAGAIN)
-				continue;
+		int ret = xread(fd, buffer + n, size - n);
+		if (ret < 0)
 			die("read error (%s)", strerror(errno));
-		}
 		if (!ret)
 			die("unexpected EOF");
 		n += ret;
diff --git a/read-cache.c b/read-cache.c
index 6932736..c5474d4 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -6,6 +6,7 @@
 #include "cache.h"
 
 struct cache_entry **active_cache = NULL;
+static time_t index_file_timestamp;
 unsigned int active_nr = 0, active_alloc = 0, active_cache_changed = 0;
 
 /*
@@ -28,7 +29,65 @@
 	ce->ce_size = htonl(st->st_size);
 }
 
-int ce_match_stat(struct cache_entry *ce, struct stat *st)
+static int ce_compare_data(struct cache_entry *ce, struct stat *st)
+{
+	int match = -1;
+	int fd = open(ce->name, O_RDONLY);
+
+	if (fd >= 0) {
+		unsigned char sha1[20];
+		if (!index_fd(sha1, fd, st, 0, NULL))
+			match = memcmp(sha1, ce->sha1, 20);
+		close(fd);
+	}
+	return match;
+}
+
+static int ce_compare_link(struct cache_entry *ce, unsigned long expected_size)
+{
+	int match = -1;
+	char *target;
+	void *buffer;
+	unsigned long size;
+	char type[10];
+	int len;
+
+	target = xmalloc(expected_size);
+	len = readlink(ce->name, target, expected_size);
+	if (len != expected_size) {
+		free(target);
+		return -1;
+	}
+	buffer = read_sha1_file(ce->sha1, type, &size);
+	if (!buffer) {
+		free(target);
+		return -1;
+	}
+	if (size == expected_size)
+		match = memcmp(buffer, target, size);
+	free(buffer);
+	free(target);
+	return match;
+}
+
+static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
+{
+	switch (st->st_mode & S_IFMT) {
+	case S_IFREG:
+		if (ce_compare_data(ce, st))
+			return DATA_CHANGED;
+		break;
+	case S_IFLNK:
+		if (ce_compare_link(ce, st->st_size))
+			return DATA_CHANGED;
+		break;
+	default:
+		return TYPE_CHANGED;
+	}
+	return 0;
+}
+
+static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
 {
 	unsigned int changed = 0;
 
@@ -83,57 +142,44 @@
 
 	if (ce->ce_size != htonl(st->st_size))
 		changed |= DATA_CHANGED;
+
 	return changed;
 }
 
-static int ce_compare_data(struct cache_entry *ce, struct stat *st)
+int ce_match_stat(struct cache_entry *ce, struct stat *st)
 {
-	int match = -1;
-	int fd = open(ce->name, O_RDONLY);
+	unsigned int changed = ce_match_stat_basic(ce, st);
 
-	if (fd >= 0) {
-		unsigned char sha1[20];
-		if (!index_fd(sha1, fd, st, 0, NULL))
-			match = memcmp(sha1, ce->sha1, 20);
-		close(fd);
-	}
-	return match;
-}
+	/*
+	 * Within 1 second of this sequence:
+	 * 	echo xyzzy >file && git-update-index --add file
+	 * running this command:
+	 * 	echo frotz >file
+	 * would give a falsely clean cache entry.  The mtime and
+	 * length match the cache, and other stat fields do not change.
+	 *
+	 * We could detect this at update-index time (the cache entry
+	 * being registered/updated records the same time as "now")
+	 * and delay the return from git-update-index, but that would
+	 * effectively mean we can make at most one commit per second,
+	 * which is not acceptable.  Instead, we check cache entries
+	 * whose mtime are the same as the index file timestamp more
+	 * careful than others.
+	 */
+	if (!changed &&
+	    index_file_timestamp &&
+	    index_file_timestamp <= ntohl(ce->ce_mtime.sec))
+		changed |= ce_modified_check_fs(ce, st);
 
-static int ce_compare_link(struct cache_entry *ce, unsigned long expected_size)
-{
-	int match = -1;
-	char *target;
-	void *buffer;
-	unsigned long size;
-	char type[10];
-	int len;
-
-	target = xmalloc(expected_size);
-	len = readlink(ce->name, target, expected_size);
-	if (len != expected_size) {
-		free(target);
-		return -1;
-	}
-	buffer = read_sha1_file(ce->sha1, type, &size);
-	if (!buffer) {
-		free(target);
-		return -1;
-	}
-	if (size == expected_size)
-		match = memcmp(buffer, target, size);
-	free(buffer);
-	free(target);
-	return match;
+	return changed;
 }
 
 int ce_modified(struct cache_entry *ce, struct stat *st)
 {
-	int changed;
+	int changed, changed_fs;
 	changed = ce_match_stat(ce, st);
 	if (!changed)
 		return 0;
-
 	/*
 	 * If the mode or type has changed, there's no point in trying
 	 * to refresh the entry - it's not going to match
@@ -148,18 +194,9 @@
 	if ((changed & DATA_CHANGED) && ce->ce_size != htonl(0))
 		return changed;
 
-	switch (st->st_mode & S_IFMT) {
-	case S_IFREG:
-		if (ce_compare_data(ce, st))
-			return changed | DATA_CHANGED;
-		break;
-	case S_IFLNK:
-		if (ce_compare_link(ce, st->st_size))
-			return changed | DATA_CHANGED;
-		break;
-	default:
-		return changed | TYPE_CHANGED;
-	}
+	changed_fs = ce_modified_check_fs(ce, st);
+	if (changed_fs)
+		return changed | changed_fs;
 	return 0;
 }
 
@@ -471,6 +508,7 @@
 		return active_nr;
 
 	errno = ENOENT;
+	index_file_timestamp = 0;
 	fd = open(get_index_file(), O_RDONLY);
 	if (fd < 0) {
 		if (errno == ENOENT)
@@ -504,6 +542,7 @@
 		offset = offset + ce_size(ce);
 		active_cache[i] = ce;
 	}
+	index_file_timestamp = st.st_mtime;
 	return active_nr;
 
 unmap:
@@ -562,6 +601,50 @@
 	return 0;
 }
 
+static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
+{
+	/*
+	 * The only thing we care about in this function is to smudge the
+	 * falsely clean entry due to touch-update-touch race, so we leave
+	 * everything else as they are.  We are called for entries whose
+	 * ce_mtime match the index file mtime.
+	 */
+	struct stat st;
+
+	if (lstat(ce->name, &st) < 0)
+		return;
+	if (ce_match_stat_basic(ce, &st))
+		return;
+	if (ce_modified_check_fs(ce, &st)) {
+		/* This is "racily clean"; smudge it.  Note that this
+		 * is a tricky code.  At first glance, it may appear
+		 * that it can break with this sequence:
+		 *
+		 * $ echo xyzzy >frotz
+		 * $ git-update-index --add frotz
+		 * $ : >frotz
+		 * $ sleep 3
+		 * $ echo filfre >nitfol
+		 * $ git-update-index --add nitfol
+		 *
+		 * but it does not.  Whe the second update-index runs,
+		 * it notices that the entry "frotz" has the same timestamp
+		 * as index, and if we were to smudge it by resetting its
+		 * size to zero here, then the object name recorded
+		 * in index is the 6-byte file but the cached stat information
+		 * becomes zero --- which would then match what we would
+		 * obtain from the filesystem next time we stat("frotz"). 
+		 *
+		 * However, the second update-index, before calling
+		 * this function, notices that the cached size is 6
+		 * bytes and what is on the filesystem is an empty
+		 * file, and never calls us, so the cached size information
+		 * for "frotz" stays 6 which does not match the filesystem.
+		 */
+		ce->ce_size = htonl(0);
+	}
+}
+
 int write_cache(int newfd, struct cache_entry **cache, int entries)
 {
 	SHA_CTX c;
@@ -584,6 +667,9 @@
 		struct cache_entry *ce = cache[i];
 		if (!ce->ce_mode)
 			continue;
+		if (index_file_timestamp &&
+		    index_file_timestamp <= ntohl(ce->ce_mtime.sec))
+			ce_smudge_racily_clean_entry(ce);
 		if (ce_write(&c, newfd, ce, ce_size(ce)) < 0)
 			return -1;
 	}
diff --git a/refs.c b/refs.c
index d2aec73..c33729c 100644
--- a/refs.c
+++ b/refs.c
@@ -313,7 +313,9 @@
 static inline int bad_ref_char(int ch)
 {
 	return (((unsigned) ch) <= ' ' ||
-		ch == '~' || ch == '^' || ch == ':');
+		ch == '~' || ch == '^' || ch == ':' ||
+		/* 2.13 Pattern Matching Notation */
+		ch == '?' || ch == '*' || ch == '[');
 }
 
 int check_ref_format(const char *ref)
diff --git a/rev-list.c b/rev-list.c
index 8020d97..d060966 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -850,7 +850,8 @@
 		handle_one_commit(commit, &list);
 	}
 
-	if (!list)
+	if (!list &&
+	    (!(tag_objects||tree_objects||blob_objects) && !pending_objects))
 		usage(rev_list_usage);
 
 	paths = get_pathspec(prefix, argv + i);
diff --git a/send-pack.c b/send-pack.c
index 6ce0d9f..a41bbe5 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -8,6 +8,7 @@
 "git-send-pack [--all] [--exec=git-receive-pack] <remote> [<head>...]\n"
 "  --all and explicit <head> specification are mutually exclusive.";
 static const char *exec = "git-receive-pack";
+static int verbose = 0;
 static int send_all = 0;
 static int force_update = 0;
 
@@ -206,7 +207,8 @@
 		if (!ref->peer_ref)
 			continue;
 		if (!memcmp(ref->old_sha1, ref->peer_ref->new_sha1, 20)) {
-			fprintf(stderr, "'%s': up-to-date\n", ref->name);
+			if (verbose)
+				fprintf(stderr, "'%s': up-to-date\n", ref->name);
 			continue;
 		}
 
@@ -270,6 +272,8 @@
 	packet_flush(out);
 	if (new_refs)
 		pack_objects(out, remote_refs);
+	else
+		fprintf(stderr, "Everything up-to-date\n");
 	close(out);
 	return ret;
 }
@@ -301,6 +305,10 @@
 				force_update = 1;
 				continue;
 			}
+			if (!strcmp(arg, "--verbose")) {
+				verbose = 1;
+				continue;
+			}
 			usage(send_pack_usage);
 		}
 		if (!dest) {
diff --git a/sha1_name.c b/sha1_name.c
index faac158..b13ed78 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -188,7 +188,10 @@
 {
 	int status;
 	static char hex[41];
+
 	memcpy(hex, sha1_to_hex(sha1), 40);
+	if (len == 40)
+		return hex;
 	while (len < 40) {
 		unsigned char sha1_ret[20];
 		status = get_short_sha1(hex, len, sha1_ret, 1);
@@ -203,11 +206,12 @@
 	return NULL;
 }
 
-static int ambiguous_path(const char *path)
+static int ambiguous_path(const char *path, int len)
 {
 	int slash = 1;
+	int cnt;
 
-	for (;;) {
+	for (cnt = 0; cnt < len; cnt++) {
 		switch (*path++) {
 		case '\0':
 			break;
@@ -222,8 +226,9 @@
 			slash = 0;
 			continue;
 		}
-		return slash;
+		break;
 	}
+	return slash;
 }
 
 static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
@@ -236,31 +241,19 @@
 		NULL
 	};
 	const char **p;
-	int found = 0;
 
 	if (len == 40 && !get_sha1_hex(str, sha1))
 		return 0;
 
 	/* Accept only unambiguous ref paths. */
-	if (ambiguous_path(str))
+	if (ambiguous_path(str, len))
 		return -1;
 
 	for (p = prefix; *p; p++) {
 		char *pathname = git_path("%s/%.*s", *p, len, str);
-		if (!read_ref(pathname, sha1)) {
-			/* Must be unique; i.e. when heads/foo and
-			 * tags/foo are both present, reject "foo".
-			 * Note that read_ref() eventually calls
-			 * get_sha1_hex() which can smudge initial
-			 * part of the buffer even if what is read
-			 * is found to be invalid halfway.
-			 */
-			if (1 < found++)
-				return -1;
-		}
+		if (!read_ref(pathname, sha1))
+			return 0;
 	}
-	if (found == 1)
-		return 0;
 	return -1;
 }
 
diff --git a/show-branch.c b/show-branch.c
index ab158eb..c742246 100644
--- a/show-branch.c
+++ b/show-branch.c
@@ -450,6 +450,8 @@
 		if (saved_matches == ref_name_cnt &&
 		    ref_name_cnt < MAX_REVS)
 			error("no matching refs with %s", av);
+		if (saved_matches + 1 < ref_name_cnt)
+			sort_ref_range(saved_matches, ref_name_cnt);
 		return;
 	}
 	die("bad sha1 reference %s", av);
diff --git a/t/t0010-racy-git.sh b/t/t0010-racy-git.sh
new file mode 100755
index 0000000..e45a9e4
--- /dev/null
+++ b/t/t0010-racy-git.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+test_description='racy GIT'
+
+. ./test-lib.sh
+
+# This test can give false success if your machine is sufficiently
+# slow or your trial happened to happen on second boundary.
+
+for trial in 0 1 2 3 4
+do
+	rm -f .git/index
+	echo frotz >infocom
+	git update-index --add infocom
+	echo xyzzy >infocom
+
+	files=`git diff-files -p`
+	test_expect_success \
+	"Racy GIT trial #$trial part A" \
+	'test "" != "$files"'
+
+	sleep 1
+	echo xyzzy >cornerstone
+	git update-index --add cornerstone
+
+	files=`git diff-files -p`
+	test_expect_success \
+	"Racy GIT trial #$trial part B" \
+	'test "" != "$files"'
+
+done
+
+test_done
diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
old mode 100644
new mode 100755
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
old mode 100644
new mode 100755
diff --git a/t/t3101-ls-tree-dirname.sh b/t/t3101-ls-tree-dirname.sh
old mode 100644
new mode 100755
diff --git a/t/t4103-apply-binary.sh b/t/t4103-apply-binary.sh
old mode 100644
new mode 100755
diff --git a/t/t4109-apply-multifrag.sh b/t/t4109-apply-multifrag.sh
old mode 100644
new mode 100755
diff --git a/t/t4110-apply-scan.sh b/t/t4110-apply-scan.sh
old mode 100644
new mode 100755
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
old mode 100644
new mode 100755
diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh
old mode 100644
new mode 100755
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 2819bef..a97d259 100755
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -18,6 +18,7 @@
 unset GIT_AUTHOR_DATE
 unset GIT_AUTHOR_EMAIL
 unset GIT_AUTHOR_NAME
+unset GIT_COMMITTER_DATE
 unset GIT_COMMITTER_EMAIL
 unset GIT_COMMITTER_NAME
 unset GIT_DIFF_OPTS
diff --git a/tar-tree.c b/tar-tree.c
index bacb23a..96bd143 100644
--- a/tar-tree.c
+++ b/tar-tree.c
@@ -34,10 +34,8 @@
 static void reliable_write(void *buf, unsigned long size)
 {
 	while (size > 0) {
-		long ret = write(1, buf, size);
+		long ret = xwrite(1, buf, size);
 		if (ret < 0) {
-			if (errno == EAGAIN)
-				continue;
 			if (errno == EPIPE)
 				exit(0);
 			die("git-tar-tree: %s", strerror(errno));
diff --git a/unpack-objects.c b/unpack-objects.c
index cfd61ae..5c5cb12 100644
--- a/unpack-objects.c
+++ b/unpack-objects.c
@@ -31,12 +31,10 @@
 		offset = 0;
 	}
 	do {
-		int ret = read(0, buffer + len, sizeof(buffer) - len);
+		int ret = xread(0, buffer + len, sizeof(buffer) - len);
 		if (ret <= 0) {
 			if (!ret)
 				die("early EOF");
-			if (errno == EAGAIN || errno == EINTR)
-				continue;
 			die("read error on input: %s", strerror(errno));
 		}
 		len += ret;
@@ -299,14 +297,9 @@
 
 	/* Write the last part of the buffer to stdout */
 	while (len) {
-		int ret = write(1, buffer + offset, len);
-		if (!ret)
+		int ret = xwrite(1, buffer + offset, len);
+		if (ret <= 0)
 			break;
-		if (ret < 0) {
-			if (errno == EAGAIN || errno == EINTR)
-				continue;
-			break;
-		}
 		len -= ret;
 		offset += ret;
 	}