Merge fixes up to GIT 1.1.3
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 1fe8423..e624d3d 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -24,6 +24,9 @@
 	flag lets all tags and their associated objects be
 	downloaded.
 
+-k, \--keep::
+	Keep downloaded pack.
+
 -u, \--update-head-ok::
 	By default `git-fetch` refuses to update the head which
 	corresponds to the current branch.  This flag disables the
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index 9442c66..df9a618 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -7,7 +7,7 @@
 
 SYNOPSIS
 --------
-'git-checkout' [-f] [-b <new_branch>] [<branch>] [<paths>...]
+'git-checkout' [-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]
 
 DESCRIPTION
 -----------
@@ -34,6 +34,19 @@
 -b::
 	Create a new branch and start it at <branch>.
 
+-m::
+	If you have local modifications to a file that is
+	different between the current branch and the branch you
+	are switching to, the command refuses to switch
+	branches, to preserve your modifications in context.
+	With this option, a three-way merge between the current
+	branch, your working tree contents, and the new branch
+	is done, and you will be on the new branch.
++
+When a merge conflict happens, the index entries for conflicting
+paths are left unmerged, and you need to resolve the conflicts
+and mark the resolved paths with `git update-index`.
+
 <new_branch>::
 	Name for the new branch.
 
@@ -42,13 +55,13 @@
 	commit. Defaults to HEAD.
 
 
-EXAMPLE
--------
+EXAMPLES
+--------
 
-The following sequence checks out the `master` branch, reverts
+. The following sequence checks out the `master` branch, reverts
 the `Makefile` to two revisions back, deletes hello.c by
 mistake, and gets it back from the index.
-
++
 ------------
 $ git checkout master <1>
 $ git checkout master~2 Makefile <2>
@@ -59,15 +72,64 @@
 <2> take out a file out of other commit
 <3> or "git checkout -- hello.c", as in the next example.
 ------------
-
++
 If you have an unfortunate branch that is named `hello.c`, the
 last step above would be confused as an instruction to switch to
 that branch.  You should instead write:
-
++
 ------------
 $ git checkout -- hello.c
 ------------
 
+. After working in a wrong branch, switching to the correct
+branch you would want to is done with:
++
+------------
+$ git checkout mytopic
+------------
++
+However, your "wrong" branch and correct "mytopic" branch may
+differ in files that you have locally modified, in which case,
+the above checkout would fail like this:
++
+------------
+$ git checkout mytopic
+fatal: Entry 'frotz' not uptodate. Cannot merge.
+------------
++
+You can give the `-m` flag to the command, which would try a
+three-way merge:
++
+------------
+$ git checkout -m mytopic
+Auto-merging frotz
+------------
++
+After this three-way merge, the local modifications are _not_
+registered in your index file, so `git diff` would show you what
+changes you made since the tip of the new branch.
+
+. When a merge conflict happens during switching branches with
+the `-m` option, you would see something like this:
++
+------------
+$ git checkout -m mytopic
+Auto-merging frotz
+merge: warning: conflicts during merge
+ERROR: Merge conflict in frotz
+fatal: merge program failed
+------------
++
+At this point, `git diff` shows the changes cleanly merged as in
+the previous example, as well as the changes in the conflicted
+files.  Edit and resolve the conflict and mark it resolved with
+`git update-index` as usual:
++
+------------
+$ edit frotz
+$ git update-index frotz
+------------
+
 
 Author
 ------
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 790b87b..8488202 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -9,7 +9,7 @@
 SYNOPSIS
 --------
 [verse]
-'git-clone' [-l [-s]] [-q] [-n] [-o <name>] [-u <upload-pack>]
+'git-clone' [-l [-s]] [-q] [-n] [--naked] [-o <name>] [-u <upload-pack>]
 	  <repository> [<directory>]
 
 DESCRIPTION
@@ -58,6 +58,12 @@
 -n::
 	No checkout of HEAD is performed after the clone is complete.
 
+--naked::
+	Make a 'naked' GIT repository.  That is, instead of
+	creating `<directory>` and placing the administrative
+	files in `<directory>/.git`, make the `<directory>`
+	itself the `$GIT_DIR`. This implies `-n` option.
+
 -o <name>::
 	Instead of using the branch name 'origin' to keep track
 	of the upstream repository, use <name> instead.  Note
@@ -103,6 +109,22 @@
 $ git show-branch
 ------------
 
+
+Create a naked repository to publish your changes to the public::
++
+------------
+$ git clone --naked -l /home/proj/.git /pub/scm/proj.git
+------------
+
+
+Create a repository on the kernel.org machine that borrows from Linus::
++
+------------
+$ git clone --naked -l -s /pub/scm/.../torvalds/linux-2.6.git \
+    /pub/scm/.../me/subsys-2.6.git
+------------
+
+
 Author
 ------
 Written by Linus Torvalds <torvalds@osdl.org>
diff --git a/Documentation/git-cvsimport.txt b/Documentation/git-cvsimport.txt
index 01ca7ef..dfe86ce 100644
--- a/Documentation/git-cvsimport.txt
+++ b/Documentation/git-cvsimport.txt
@@ -89,6 +89,26 @@
 -s <subst>::
 	Substitute the character "/" in branch names with <subst>
 
+-A <author-conv-file>::
+	CVS by default uses the unix username when writing its
+	commit logs. Using this option and an author-conv-file
+	in this format
+
+	exon=Andreas Ericsson <ae@op5.se>
+	spawn=Simon Pawn <spawn@frog-pond.org>
+
+	git-cvsimport will make it appear as those authors had
+	their GIT_AUTHOR_NAME and GIT_AUTHOR_EMAIL set properly
+	all along.
+
+	For convenience, this data is saved to $GIT_DIR/cvs-authors
+	each time the -A option is provided and read from that same
+	file each time git-cvsimport is run.
+
+	It is not recommended to use this feature if you intend to
+	export changes back to CVS again later with
+	git-link[1]::git-cvsexportcommit.
+
 OUTPUT
 ------
 If '-v' is specified, the script reports what it is doing.
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index 5b76f3b..7b1a9c9 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -7,7 +7,10 @@
 
 SYNOPSIS
 --------
-'git-show-branch [--all] [--heads] [--tags] [--topo-order] [--more=<n> | --list | --independent | --merge-base] [--no-name | --sha1-name] [<rev> | <glob>]...'
+[verse]
+git-show-branch [--all] [--heads] [--tags] [--topo-order] [--current]
+	[--more=<n> | --list | --independent | --merge-base]
+	[--no-name | --sha1-name] [<rev> | <glob>]...
 
 DESCRIPTION
 -----------
@@ -18,6 +21,9 @@
 
 It cannot show more than 29 branches and commits at a time.
 
+It uses `showbranch.default` multi-valued configuration items if
+no <rev> nor <glob> is given on the command line.
+
 
 OPTIONS
 -------
@@ -35,6 +41,11 @@
 	Show all refs under $GIT_DIR/refs, $GIT_DIR/refs/heads,
 	and $GIT_DIR/refs/tags, respectively.
 
+--current::
+	With this option, the command includes the current
+	branch to the list of revs to be shown when it is not
+	given on the command line.
+
 --topo-order::
         By default, the branches and their commits are shown in
         reverse chronological order.  This option makes them
@@ -50,7 +61,7 @@
 	tree.
 
 --list::
-	Synomym to `--more=-1`
+	Synonym to `--more=-1`
 
 --merge-base::
 	Instead of showing the commit list, just act like the
@@ -78,13 +89,14 @@
 ------
 Given N <references>, the first N lines are the one-line
 description from their commit message.  The branch head that is
-pointed at by $GIT_DIR/HEAD is prefixed with an asterisk '*'
-character while other heads are prefixed with a '!' character.
+pointed at by $GIT_DIR/HEAD is prefixed with an asterisk `*`
+character while other heads are prefixed with a `!` character.
 
 Following these N lines, one-line log for each commit is
 displayed, indented N places.  If a commit is on the I-th
-branch, the I-th indentation character shows a '+' sign;
-otherwise it shows a space.  Each commit shows a short name that
+branch, the I-th indentation character shows a `+` sign;
+otherwise it shows a space.  Merge commits are denoted by
+a `-` sign.  Each commit shows a short name that
 can be used as an extended SHA1 to name that commit.
 
 The following example shows three branches, "master", "fixes"
@@ -92,7 +104,7 @@
 
 ------------------------------------------------
 $ git show-branch master fixes mhf
-! [master] Add 'git show-branch'.
+* [master] Add 'git show-branch'.
  ! [fixes] Introduce "reset type" flag to "git reset"
   ! [mhf] Allow "+remote:local" refspec to cause --force when fetching.
 ---
@@ -106,13 +118,33 @@
   + [mhf~6] Retire git-parse-remote.
   + [mhf~7] Multi-head fetch.
   + [mhf~8] Start adding the $GIT_DIR/remotes/ support.
-+++ [master] Add 'git show-branch'.
+*++ [master] Add 'git show-branch'.
 ------------------------------------------------
 
 These three branches all forked from a common commit, [master],
 whose commit message is "Add 'git show-branch'.  "fixes" branch
 adds one commit 'Introduce "reset type"'.  "mhf" branch has many
-other commits.
+other commits.  The current branch is "master".
+
+
+EXAMPLE
+-------
+
+If you keep your primary branches immediately under
+`$GIT_DIR/refs/heads`, and topic branches in subdirectories of
+it, having the following in the configuration file may help:
+
+------------
+[showbranch]
+	default = --topo-order
+	default = heads/*
+
+------------
+
+With this,`git show-branch` without extra parameters would show
+only the primary branches.  In addition, if you happen to be on
+your topic branch, it is shown as well.
+
 
 
 Author
diff --git a/Documentation/howto/revert-branch-rebase.txt b/Documentation/howto/revert-branch-rebase.txt
index 5a7e0cf..d10476b 100644
--- a/Documentation/howto/revert-branch-rebase.txt
+++ b/Documentation/howto/revert-branch-rebase.txt
@@ -32,16 +32,16 @@
 
 ------------------------------------------------
 $ git show-branch --more=4 master master^2 | head
-! [master] Merge refs/heads/portable from http://www.cs.berkeley....
+* [master] Merge refs/heads/portable from http://www.cs.berkeley....
  ! [master^2] Replace C99 array initializers with code.
 --
-+  [master] Merge refs/heads/portable from http://www.cs.berkeley....
-++ [master^2] Replace C99 array initializers with code.
-++ [master^2~1] Replace unsetenv() and setenv() with older putenv().
-++ [master^2~2] Include sys/time.h in daemon.c.
-++ [master^2~3] Fix ?: statements.
-++ [master^2~4] Replace zero-length array decls with [].
-+  [master~1] tutorial note about git branch
+-  [master] Merge refs/heads/portable from http://www.cs.berkeley....
+*+ [master^2] Replace C99 array initializers with code.
+*+ [master^2~1] Replace unsetenv() and setenv() with older putenv().
+*+ [master^2~2] Include sys/time.h in daemon.c.
+*+ [master^2~3] Fix ?: statements.
+*+ [master^2~4] Replace zero-length array decls with [].
+*  [master~1] tutorial note about git branch
 ------------------------------------------------
 
 The '--more=4' above means "after we reach the merge base of refs,
@@ -193,8 +193,8 @@
  +  [pu~4] Document "git cherry-pick" and "git revert"
  +  [pu~5] Remove git-apply-patch-script.
  +  [pu~6] Redo "revert" using three-way merge machinery.
-  + [rc] Merge refs/heads/master from .
-+++ [master] Revert "Replace zero-length array decls with []."
-  + [rc~1] Merge refs/heads/master from .
-+++ [master~1] Merge refs/heads/portable from http://www.cs.berkeley....
+  - [rc] Merge refs/heads/master from .
+++* [master] Revert "Replace zero-length array decls with []."
+  - [rc~1] Merge refs/heads/master from .
+... [master~1] Merge refs/heads/portable from http://www.cs.berkeley....
 ------------------------------------------------
diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt
index edd91cb..b8fa299 100644
--- a/Documentation/tutorial.txt
+++ b/Documentation/tutorial.txt
@@ -968,8 +968,8 @@
 * [master] Merge work in mybranch
  ! [mybranch] Some work.
 --
-+  [master] Merge work in mybranch
-++ [mybranch] Some work.
+-  [master] Merge work in mybranch
+*+ [mybranch] Some work.
 ------------------------------------------------
 
 The first two lines indicate that it is showing the two branches
@@ -979,7 +979,8 @@
 the later output lines is used to show commits contained in the
 `master` branch, and the second column for the `mybranch`
 branch. Three commits are shown along with their log messages.
-All of them have plus `+` characters in the first column, which
+All of them have non blank characters in the first column (`*`
+shows an ordinary commit on the current branch, `.` is a merge commit), which
 means they are now part of the `master` branch. Only the "Some
 work" commit has the plus `+` character in the second column,
 because `mybranch` has not been merged to incorporate these
@@ -1024,7 +1025,7 @@
 ! [master] Merge work in mybranch
  * [mybranch] Merge work in mybranch
 --
-++ [master] Merge work in mybranch
+-- [master] Merge work in mybranch
 ------------------------------------------------
 
 
@@ -1199,9 +1200,9 @@
 ! [master] Merge work in mybranch
  * [mybranch] Merge work in mybranch
 --
-++ [master] Merge work in mybranch
-++ [master^2] Some work.
-++ [master^] Some fun.
+-- [master] Merge work in mybranch
++* [master^2] Some work.
++* [master^] Some fun.
 ------------
 
 Remember, before running `git merge`, our `master` head was at
@@ -1223,8 +1224,8 @@
  ! [mybranch] Some work.
 --
  + [mybranch] Some work.
-+  [master] Some fun.
-++ [mybranch^] New day.
+*  [master] Some fun.
+*+ [mybranch^] New day.
 ------------
 
 Now we are ready to experiment with the merge by hand.
@@ -1743,8 +1744,8 @@
  +  [diff-fix] Fix rename detection.
  +  [diff-fix~1] Better common substring algorithm.
 +   [commit-fix] Fix commit message normalization.
-  + [master] Release candidate #1
-+++ [diff-fix~2] Pretty-print messages.
+  * [master] Release candidate #1
+++* [diff-fix~2] Pretty-print messages.
 ------------
 
 Both fixes are tested well, and at this point, you want to merge
@@ -1764,13 +1765,13 @@
  ! [diff-fix] Fix rename detection.
   * [master] Merge fix in commit-fix
 ---
-  + [master] Merge fix in commit-fix
-+ + [commit-fix] Fix commit message normalization.
-  + [master~1] Merge fix in diff-fix
- ++ [diff-fix] Fix rename detection.
- ++ [diff-fix~1] Better common substring algorithm.
-  + [master~2] Release candidate #1
-+++ [master~3] Pretty-print messages.
+  - [master] Merge fix in commit-fix
++ * [commit-fix] Fix commit message normalization.
+  - [master~1] Merge fix in diff-fix
+ +* [diff-fix] Fix rename detection.
+ +* [diff-fix~1] Better common substring algorithm.
+  * [master~2] Release candidate #1
+++* [master~3] Pretty-print messages.
 ------------
 
 However, there is no particular reason to merge in one branch
@@ -1797,12 +1798,12 @@
  ! [diff-fix] Fix rename detection.
   * [master] Octopus merge of branches 'diff-fix' and 'commit-fix'
 ---
-  + [master] Octopus merge of branches 'diff-fix' and 'commit-fix'
-+ + [commit-fix] Fix commit message normalization.
- ++ [diff-fix] Fix rename detection.
- ++ [diff-fix~1] Better common substring algorithm.
-  + [master~1] Release candidate #1
-+++ [master~2] Pretty-print messages.
+  - [master] Octopus merge of branches 'diff-fix' and 'commit-fix'
++ * [commit-fix] Fix commit message normalization.
+ +* [diff-fix] Fix rename detection.
+ +* [diff-fix~1] Better common substring algorithm.
+  * [master~1] Release candidate #1
+++* [master~2] Pretty-print messages.
 ------------
 
 Note that you should not do Octopus because you can.  An octopus
diff --git a/Makefile b/Makefile
index fa0cd83..f6d9e0a 100644
--- a/Makefile
+++ b/Makefile
@@ -65,9 +65,11 @@
 LDFLAGS =
 ALL_CFLAGS = $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)
+STRIP ?= strip
 
 prefix = $(HOME)
 bindir = $(prefix)/bin
+gitexecdir = $(prefix)/bin
 template_dir = $(prefix)/share/git-core/templates/
 GIT_PYTHON_DIR = $(prefix)/share/git-core/python
 # DESTDIR=
@@ -112,14 +114,14 @@
 SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH)) \
 	  $(patsubst %.perl,%,$(SCRIPT_PERL)) \
 	  $(patsubst %.py,%,$(SCRIPT_PYTHON)) \
-	  gitk git-cherry-pick
+	  git-cherry-pick
 
 # The ones that do not have to link with lcrypto nor lz.
 SIMPLE_PROGRAMS = \
 	git-get-tar-commit-id$X git-mailinfo$X git-mailsplit$X \
 	git-stripspace$X git-daemon$X
 
-# ... and all the rest
+# ... and all the rest that could be moved out of bindir to gitexecdir
 PROGRAMS = \
 	git-apply$X git-cat-file$X \
 	git-checkout-index$X git-clone-pack$X git-commit-tree$X \
@@ -140,8 +142,8 @@
 	git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X \
 	git-describe$X
 
-# what 'all' will build and 'install' will install.
-ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS) git$X
+# what 'all' will build and 'install' will install, in gitexecdir
+ALL_PROGRAMS = $(PROGRAMS) $(SIMPLE_PROGRAMS) $(SCRIPTS)
 
 # Backward compatibility -- to be removed after 1.0
 PROGRAMS += git-ssh-pull$X git-ssh-push$X
@@ -173,7 +175,7 @@
 
 LIB_OBJS = \
 	blob.o commit.o connect.o count-delta.o csum-file.o \
-	date.o diff-delta.o entry.o ident.o index.o \
+	date.o diff-delta.o entry.o exec_cmd.o ident.o index.o \
 	object.o pack-check.o patch-delta.o path.o pkt-line.o \
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
@@ -366,13 +368,16 @@
 export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
 ### Build rules
 
-all: $(ALL_PROGRAMS)
+all: $(ALL_PROGRAMS) git$X gitk
 
 all:
 	$(MAKE) -C templates
 
+strip: $(PROGRAMS) git$X
+	$(STRIP) $(STRIP_OPTS) $(PROGRAMS) git$X
+
 git$X: git.c $(LIB_FILE)
-	$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
+	$(CC) -DGIT_VERSION='"$(GIT_VERSION)"' \
 		$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE)
 
 $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
@@ -412,6 +417,8 @@
 %.o: %.S
 	$(CC) -o $*.o -c $(ALL_CFLAGS) $<
 
+exec_cmd.o: ALL_CFLAGS += -DGIT_EXEC_PATH=\"$(gitexecdir)\"
+
 git-%$X: %.o $(LIB_FILE)
 	$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 
@@ -468,7 +475,9 @@
 
 install: all
 	$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(bindir))
-	$(INSTALL) $(ALL_PROGRAMS) $(call shellquote,$(DESTDIR)$(bindir))
+	$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(gitexecdir))
+	$(INSTALL) $(ALL_PROGRAMS) $(call shellquote,$(DESTDIR)$(gitexecdir))
+	$(INSTALL) git$X gitk $(call shellquote,$(DESTDIR)$(bindir))
 	$(MAKE) -C templates install
 	$(INSTALL) -d -m755 $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
 	$(INSTALL) $(PYMODULES) $(call shellquote,$(DESTDIR)$(GIT_PYTHON_DIR))
@@ -502,8 +511,7 @@
 
 clean:
 	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 $(ALL_PROGRAMS) git$X
 	rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo
 	rm -rf $(GIT_TARNAME)
 	rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
@@ -512,6 +520,6 @@
 	$(MAKE) -C t/ clean
 	rm -f GIT-VERSION-FILE
 
-.PHONY: all install clean
+.PHONY: all install clean strip
 .PHONY: .FORCE-GIT-VERSION-FILE
 
diff --git a/daemon.c b/daemon.c
index 3bd1426..bb014fa 100644
--- a/daemon.c
+++ b/daemon.c
@@ -9,6 +9,7 @@
 #include <syslog.h>
 #include "pkt-line.h"
 #include "cache.h"
+#include "exec_cmd.h"
 
 static int log_syslog;
 static int verbose;
@@ -227,7 +228,7 @@
 	snprintf(timeout_buf, sizeof timeout_buf, "--timeout=%u", timeout);
 
 	/* git-upload-pack only ever reads stuff, so this is safe */
-	execlp("git-upload-pack", "git-upload-pack", "--strict", timeout_buf, ".", NULL);
+	execl_git_cmd("upload-pack", "--strict", timeout_buf, ".", NULL);
 	return -1;
 }
 
diff --git a/describe.c b/describe.c
index cc95eb0..4866510 100644
--- a/describe.c
+++ b/describe.c
@@ -98,12 +98,20 @@
 	return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
 }
 
-static void describe(struct commit *cmit, int last_one)
+static void describe(char *arg, int last_one)
 {
+	unsigned char sha1[20];
+	struct commit *cmit;
 	struct commit_list *list;
 	static int initialized = 0;
 	struct commit_name *n;
 
+	if (get_sha1(arg, sha1) < 0)
+		usage(describe_usage);
+	cmit = lookup_commit_reference(sha1);
+	if (!cmit)
+		usage(describe_usage);
+
 	if (!initialized) {
 		initialized = 1;
 		for_each_ref(get_name);
@@ -138,29 +146,29 @@
 
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
-		unsigned char sha1[20];
-		struct commit *cmit;
 
-		if (!strcmp(arg, "--all")) {
+		if (*arg != '-')
+			break;
+		else if (!strcmp(arg, "--all"))
 			all = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--tags")) {
+		else if (!strcmp(arg, "--tags"))
 			tags = 1;
-			continue;
-		}
-		if (!strncmp(arg, "--abbrev=", 9)) {
+		else if (!strncmp(arg, "--abbrev=", 9)) {
 			abbrev = strtoul(arg + 9, NULL, 10);
 			if (abbrev < 4 || 40 <= abbrev)
 				abbrev = DEFAULT_ABBREV;
-			continue;
 		}
-		if (get_sha1(arg, sha1) < 0)
+		else
 			usage(describe_usage);
-		cmit = lookup_commit_reference(sha1);
-		if (!cmit)
-			usage(describe_usage);
-		describe(cmit, i == argc - 1);
 	}
+
+	if (i == argc)
+		describe("HEAD", 1);
+	else
+		while (i < argc) {
+			describe(argv[i], (i == argc - 1));
+			i++;
+		}
+
 	return 0;
 }
diff --git a/exec_cmd.c b/exec_cmd.c
new file mode 100644
index 0000000..55af33b
--- /dev/null
+++ b/exec_cmd.c
@@ -0,0 +1,117 @@
+#include "cache.h"
+#include "exec_cmd.h"
+#define MAX_ARGS	32
+
+extern char **environ;
+static const char *builtin_exec_path = GIT_EXEC_PATH;
+static const char *current_exec_path = NULL;
+
+void git_set_exec_path(const char *exec_path)
+{
+	current_exec_path = exec_path;
+}
+
+
+/* Returns the highest-priority, location to look for git programs. */
+const char *git_exec_path()
+{
+	const char *env;
+
+	if (current_exec_path)
+		return current_exec_path;
+
+	env = getenv("GIT_EXEC_PATH");
+	if (env) {
+		return env;
+	}
+
+	return builtin_exec_path;
+}
+
+
+int execv_git_cmd(char **argv)
+{
+	char git_command[PATH_MAX + 1];
+	char *tmp;
+	int len, err, i;
+	const char *paths[] = { current_exec_path,
+				getenv("GIT_EXEC_PATH"),
+				builtin_exec_path };
+
+	for (i = 0; i < sizeof(paths)/sizeof(paths[0]); ++i) {
+		const char *exec_dir = paths[i];
+		if (!exec_dir) continue;
+
+		if (*exec_dir != '/') {
+			if (!getcwd(git_command, sizeof(git_command))) {
+				fprintf(stderr, "git: cannot determine "
+					"current directory\n");
+				exit(1);
+			}
+			len = strlen(git_command);
+
+			/* Trivial cleanup */
+			while (!strncmp(exec_dir, "./", 2)) {
+				exec_dir += 2;
+				while (*exec_dir == '/')
+					exec_dir++;
+			}
+			snprintf(git_command + len, sizeof(git_command) - len,
+				 "/%s", exec_dir);
+		} else {
+			strcpy(git_command, exec_dir);
+		}
+
+		len = strlen(git_command);
+		len += snprintf(git_command + len, sizeof(git_command) - len,
+				"/git-%s", argv[0]);
+
+		if (sizeof(git_command) <= len) {
+			fprintf(stderr,
+				"git: command name given is too long.\n");
+			break;
+		}
+
+		/* argv[0] must be the git command, but the argv array
+		 * belongs to the caller, and my be reused in
+		 * subsequent loop iterations. Save argv[0] and
+		 * restore it on error.
+		 */
+
+		tmp = argv[0];
+		argv[0] = git_command;
+
+		/* execve() can only ever return if it fails */
+		execve(git_command, argv, environ);
+
+		err = errno;
+
+		argv[0] = tmp;
+	}
+	return -1;
+
+}
+
+
+int execl_git_cmd(char *cmd,...)
+{
+	int argc;
+	char *argv[MAX_ARGS + 1];
+	char *arg;
+	va_list param;
+
+	va_start(param, cmd);
+	argv[0] = cmd;
+	argc = 1;
+	while (argc < MAX_ARGS) {
+		arg = argv[argc++] = va_arg(param, char *);
+		if (!arg)
+			break;
+	}
+	va_end(param);
+	if (MAX_ARGS <= argc)
+		return error("too many args to run %s", cmd);
+
+	argv[argc] = NULL;
+	return execv_git_cmd(argv);
+}
diff --git a/exec_cmd.h b/exec_cmd.h
new file mode 100644
index 0000000..5150ee2
--- /dev/null
+++ b/exec_cmd.h
@@ -0,0 +1,10 @@
+#ifndef __GIT_EXEC_CMD_H_
+#define __GIT_EXEC_CMD_H_
+
+extern void git_set_exec_path(const char *exec_path);
+extern const char* git_exec_path(void);
+extern int execv_git_cmd(char **argv); /* NULL terminated */
+extern int execl_git_cmd(char *cmd, ...);
+
+
+#endif /* __GIT_EXEC_CMD_H_ */
diff --git a/fetch-clone.c b/fetch-clone.c
index f46fe6e..859f400 100644
--- a/fetch-clone.c
+++ b/fetch-clone.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "exec_cmd.h"
 #include <sys/wait.h>
 
 static int finish_pack(const char *pack_tmp_name, const char *me)
@@ -27,8 +28,7 @@
 		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);
+		execl_git_cmd("index-pack", "-o", idx, pack_tmp_name, NULL);
 		error("cannot exec git-index-pack <%s> <%s>",
 		      idx, pack_tmp_name);
 		exit(1);
@@ -105,8 +105,7 @@
 		dup2(fd[0], 0);
 		close(fd[0]);
 		close(fd[1]);
-		execlp("git-unpack-objects", "git-unpack-objects",
-		       quiet ? "-q" : NULL, NULL);
+		execl_git_cmd("unpack-objects", quiet ? "-q" : NULL, NULL);
 		die("git-unpack-objects exec failed");
 	}
 	close(fd[0]);
diff --git a/git-checkout.sh b/git-checkout.sh
index 3bbd111..d99688f 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-USAGE='[-f] [-b <new_branch>] [<branch>] [<paths>...]'
+USAGE='[-f] [-b <new_branch>] [-m] [<branch>] [<paths>...]'
 SUBDIRECTORY_OK=Sometimes
 . git-sh-setup
 
@@ -9,6 +9,7 @@
 force=
 branch=
 newbranch=
+merge=
 while [ "$#" != "0" ]; do
     arg="$1"
     shift
@@ -26,6 +27,9 @@
 	"-f")
 		force=1
 		;;
+	-m)
+		merge=1
+		;;
 	--)
 		break
 		;;
@@ -71,7 +75,7 @@
 
 if test "$#" -ge 1
 then
-	if test '' != "$newbranch$force"
+	if test '' != "$newbranch$force$merge"
 	then
 		die "updating paths and switching branches or forcing are incompatible."
 	fi
@@ -121,7 +125,48 @@
 	git-checkout-index -q -f -u -a
 else
     git-update-index --refresh >/dev/null
-    git-read-tree -m -u $old $new
+    merge_error=$(git-read-tree -m -u $old $new 2>&1) || (
+	case "$merge" in
+	'')
+		echo >&2 "$merge_error"
+		exit 1 ;;
+	esac
+
+	# Match the index to the working tree, and do a three-way.
+    	git diff-files --name-only | git update-index --remove --stdin &&
+	work=`git write-tree` &&
+	git read-tree --reset $new &&
+	git checkout-index -f -u -q -a &&
+	git read-tree -m -u $old $new $work || exit
+
+	if result=`git write-tree 2>/dev/null`
+	then
+	    echo >&2 "Trivially automerged."
+	else
+	    git merge-index -o git-merge-one-file -a
+	fi
+
+	# Do not register the cleanly merged paths in the index yet.
+	# this is not a real merge before committing, but just carrying
+	# the working tree changes along.
+	unmerged=`git ls-files -u`
+	git read-tree --reset $new
+	case "$unmerged" in
+	'')	;;
+	*)
+		(
+			z40=0000000000000000000000000000000000000000
+			echo "$unmerged" |
+			sed -e 's/^[0-7]* [0-9a-f]* /'"0 $z40 /"
+			echo "$unmerged"
+		) | git update-index --index-info
+		;;
+	esac
+	exit 0
+    )
+    saved_err=$?
+    git diff-files --name-status
+    (exit $saved_err)
 fi
 
 # 
diff --git a/git-clone.sh b/git-clone.sh
index 377d59e..168eb96 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -9,7 +9,7 @@
 unset CDPATH
 
 usage() {
-	echo >&2 "Usage: $0 [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]"
+	echo >&2 "Usage: $0 [--naked] [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]"
 	exit 1
 }
 
@@ -53,11 +53,15 @@
 local_shared=no
 no_checkout=
 upload_pack=
+naked=
 origin=origin
 while
 	case "$#,$1" in
 	0,*) break ;;
-	*,-n) no_checkout=yes ;;
+	*,-n|*,--no|*,--no-|*,--no-c|*,--no-ch|*,--no-che|*,--no-chec|\
+	*,--no-check|*,--no-checko|*,--no-checkou|*,--no-checkout)
+	  no_checkout=yes ;;
+	*,--na|*,--nak|*,--nake|*,--naked) naked=yes ;;
 	*,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) use_local=yes ;;
         *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) 
           local_shared=yes; use_local=yes ;;
@@ -81,6 +85,9 @@
 	shift
 done
 
+# --naked implies --no-checkout
+test -z "$naked" || no_checkout=yes
+
 # Turn the source into an absolute path if
 # it is local
 repo="$1"
@@ -95,10 +102,17 @@
 [ -z "$dir" ] && dir=$(echo "$repo" | sed -e 's|/$||' -e 's|:*/*\.git$||' -e 's|.*/||g')
 [ -e "$dir" ] && echo "$dir already exists." && usage
 mkdir -p "$dir" &&
-D=$(
-	(cd "$dir" && git-init-db && pwd)
-) &&
-test -d "$D" || usage
+D=$(cd "$dir" && pwd) &&
+case "$naked" in
+yes) GIT_DIR="$D" ;;
+*) GIT_DIR="$D/.git" ;;
+esac && export GIT_DIR && git-init-db || usage
+case "$naked" in
+yes)
+	GIT_DIR="$D" ;;
+*)
+	GIT_DIR="$D/.git" ;;
+esac
 
 # We do local magic only when the user tells us to.
 case "$local,$use_local" in
@@ -118,21 +132,21 @@
 	    test -f "$repo/$sample_file" || exit
 
 	    l=
-	    if ln "$repo/$sample_file" "$D/.git/objects/sample" 2>/dev/null
+	    if ln "$repo/$sample_file" "$GIT_DIR/objects/sample" 2>/dev/null
 	    then
 		    l=l
 	    fi &&
-	    rm -f "$D/.git/objects/sample" &&
+	    rm -f "$GIT_DIR/objects/sample" &&
 	    cd "$repo" &&
-	    find objects -depth -print | cpio -puamd$l "$D/.git/" || exit 1
+	    find objects -depth -print | cpio -puamd$l "$GIT_DIR/" || exit 1
 	    ;;
 	yes)
-	    mkdir -p "$D/.git/objects/info"
+	    mkdir -p "$GIT_DIR/objects/info"
 	    {
 		test -f "$repo/objects/info/alternates" &&
 		cat "$repo/objects/info/alternates";
 		echo "$repo/objects"
-	    } >"$D/.git/objects/info/alternates"
+	    } >"$GIT_DIR/objects/info/alternates"
 	    ;;
 	esac
 
@@ -143,27 +157,27 @@
 		HEAD=HEAD
 	fi
 	(cd "$repo" && tar cf - refs $HEAD) |
-	(cd "$D/.git" && tar xf -) || exit 1
+	(cd "$GIT_DIR" && tar xf -) || exit 1
 	;;
 *)
 	case "$repo" in
 	rsync://*)
 		rsync $quiet -av --ignore-existing  \
-			--exclude info "$repo/objects/" "$D/.git/objects/" &&
+			--exclude info "$repo/objects/" "$GIT_DIR/objects/" &&
 		rsync $quiet -av --ignore-existing  \
-			--exclude info "$repo/refs/" "$D/.git/refs/" || exit
+			--exclude info "$repo/refs/" "$GIT_DIR/refs/" || exit
 
 		# Look at objects/info/alternates for rsync -- http will
 		# support it natively and git native ones will do it on the
 		# remote end.  Not having that file is not a crime.
 		rsync -q "$repo/objects/info/alternates" \
-			"$D/.git/TMP_ALT" 2>/dev/null ||
-			rm -f "$D/.git/TMP_ALT"
-		if test -f "$D/.git/TMP_ALT"
+			"$GIT_DIR/TMP_ALT" 2>/dev/null ||
+			rm -f "$GIT_DIR/TMP_ALT"
+		if test -f "$GIT_DIR/TMP_ALT"
 		then
 		    ( cd "$D" &&
 		      . git-parse-remote &&
-		      resolve_alternates "$repo" <"./.git/TMP_ALT" ) |
+		      resolve_alternates "$repo" <"$GIT_DIR/TMP_ALT" ) |
 		    while read alt
 		    do
 			case "$alt" in 'bad alternate: '*) die "$alt";; esac
@@ -171,9 +185,9 @@
 			'')	echo >&2 "Getting alternate: $alt" ;;
 			esac
 			rsync $quiet -av --ignore-existing  \
-			    --exclude info "$alt" "$D/.git/objects" || exit
+			    --exclude info "$alt" "$GIT_DIR/objects" || exit
 		    done
-		    rm -f "$D/.git/TMP_ALT"
+		    rm -f "$GIT_DIR/TMP_ALT"
 		fi
 		;;
 	http://*)
@@ -194,25 +208,25 @@
 
 cd "$D" || exit
 
-if test -f ".git/HEAD"
+if test -f "$GIT_DIR/HEAD"
 then
 	head_points_at=`git-symbolic-ref HEAD`
 	case "$head_points_at" in
 	refs/heads/*)
 		head_points_at=`expr "$head_points_at" : 'refs/heads/\(.*\)'`
-		mkdir -p .git/remotes &&
-		echo >.git/remotes/origin \
+		mkdir -p "$GIT_DIR/remotes" &&
+		echo >"$GIT_DIR/remotes/origin" \
 		"URL: $repo
 Pull: $head_points_at:$origin" &&
 		git-update-ref "refs/heads/$origin" $(git-rev-parse HEAD) &&
-		find .git/refs/heads -type f -print |
+		(cd "$GIT_DIR" && find "refs/heads" -type f -print) |
 		while read ref
 		do
-			head=`expr "$ref" : '.git/refs/heads/\(.*\)'` &&
+			head=`expr "$ref" : 'refs/heads/\(.*\)'` &&
 			test "$head_points_at" = "$head" ||
 			test "$origin" = "$head" ||
 			echo "Pull: ${head}:${head}"
-		done >>.git/remotes/origin
+		done >>"$GIT_DIR/remotes/origin"
 	esac
 
 	case "$no_checkout" in
diff --git a/git-cvsimport.perl b/git-cvsimport.perl
index 8619e7d..fc207fc 100755
--- a/git-cvsimport.perl
+++ b/git-cvsimport.perl
@@ -29,19 +29,63 @@
 $SIG{'PIPE'}="IGNORE";
 $ENV{'TZ'}="UTC";
 
-our($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,$opt_M);
+our($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,$opt_M,$opt_A);
+my (%conv_author_name, %conv_author_email);
 
 sub usage() {
 	print STDERR <<END;
 Usage: ${\basename $0}     # fetch/update GIT from CVS
-       [-o branch-for-HEAD] [-h] [-v] [-d CVSROOT]
-       [-p opts-for-cvsps] [-C GIT_repository] [-z fuzz]
-       [-i] [-k] [-u] [-s subst] [-m] [-M regex] [CVS_module]
+       [-o branch-for-HEAD] [-h] [-v] [-d CVSROOT] [-A author-conv-file]
+       [-p opts-for-cvsps] [-C GIT_repository] [-z fuzz] [-i] [-k] [-u]
+       [-s subst] [-m] [-M regex] [CVS_module]
 END
 	exit(1);
 }
 
-getopts("hivmkuo:d:p:C:z:s:M:P:") or usage();
+sub read_author_info($) {
+	my ($file) = @_;
+	my $user;
+	open my $f, '<', "$file" or die("Failed to open $file: $!\n");
+
+	while (<$f>) {
+		# Expected format is this:
+		#   exon=Andreas Ericsson <ae@op5.se>
+		if (m/^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/) {
+			$user = $1;
+			$conv_author_name{$user} = $2;
+			$conv_author_email{$user} = $3;
+		}
+		# However, we also read from CVSROOT/users format
+		# to ease migration.
+		elsif (/^(\w+):(['"]?)(.+?)\2\s*$/) {
+			my $mapped;
+			($user, $mapped) = ($1, $3);
+			if ($mapped =~ /^\s*(.*?)\s*<(.*)>\s*$/) {
+				$conv_author_name{$user} = $1;
+				$conv_author_email{$user} = $2;
+			}
+			elsif ($mapped =~ /^<?(.*)>?$/) {
+				$conv_author_name{$user} = $user;
+				$conv_author_email{$user} = $1;
+			}
+		}
+		# NEEDSWORK: Maybe warn on unrecognized lines?
+	}
+	close ($f);
+}
+
+sub write_author_info($) {
+	my ($file) = @_;
+	open my $f, '>', $file or
+	  die("Failed to open $file for writing: $!");
+
+	foreach (keys %conv_author_name) {
+		print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>\n";
+	}
+	close ($f);
+}
+
+getopts("hivmkuo:d:p:C:z:s:M:P:A:") or usage();
 usage if $opt_h;
 
 @ARGV <= 1 or usage();
@@ -453,7 +497,7 @@
 Make sure your working directory corresponds to HEAD and remove CVS2GIT_HEAD.
 You may need to run
 
-    git-read-tree -m -u CVS2GIT_HEAD HEAD
+    git read-tree -m -u CVS2GIT_HEAD HEAD
 EOM
 	}
 	system('cp', "$git_dir/HEAD", "$git_dir/CVS2GIT_HEAD");
@@ -489,6 +533,14 @@
 -d $git_dir
 	or die "Could not create git subdir ($git_dir).\n";
 
+# now we read (and possibly save) author-info as well
+-f "$git_dir/cvs-authors" and
+  read_author_info("$git_dir/cvs-authors");
+if ($opt_A) {
+	read_author_info($opt_A);
+	write_author_info("$git_dir/cvs-authors");
+}
+
 my $pid = open(CVS,"-|");
 die "Cannot fork: $!\n" unless defined $pid;
 unless($pid) {
@@ -702,6 +754,9 @@
 		s/\s+$//;
 		if (/^(.*?)\s+<(.*)>/) {
 		    ($author_name, $author_email) = ($1, $2);
+		} elsif ($conv_author_name{$_}) {
+			$author_name = $conv_author_name{$_};
+			$author_email = $conv_author_email{$_};
 		} else {
 		    $author_name = $author_email = $_;
 		}
diff --git a/git-fetch.sh b/git-fetch.sh
index 73e57bd..4a0cb32 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -40,6 +40,9 @@
 	-v|--verbose)
 		verbose=Yes
 		;;
+	-k|--k|--ke|--kee|--keep)
+		keep=--keep
+		;;
 	-*)
 		usage
 		;;
@@ -309,7 +312,7 @@
     ( : subshell because we muck with IFS
       IFS=" 	$LF"
       (
-	  git-fetch-pack "$remote" $rref || echo failed "$remote"
+	  git-fetch-pack $keep "$remote" $rref || echo failed "$remote"
       ) |
       while read sha1 remote_name
       do
diff --git a/git-format-patch.sh b/git-format-patch.sh
index d3979d7..7e67c4e 100755
--- a/git-format-patch.sh
+++ b/git-format-patch.sh
@@ -34,14 +34,12 @@
 while case "$#" in 0) break;; esac
 do
     case "$1" in
-    -a|--a|--au|--aut|--auth|--autho|--author)
-    author=t ;;
     -c|--c|--ch|--che|--chec|--check)
     check=t ;;
-    -d|--d|--da|--dat|--date)
-    date=t ;;
-    -m|--m|--mb|--mbo|--mbox)
-    date=t author=t mbox=t ;;
+    -a|--a|--au|--aut|--auth|--autho|--author|\
+    -d|--d|--da|--dat|--date|\
+    -m|--m|--mb|--mbo|--mbox) # now noop
+    ;;
     -k|--k|--ke|--kee|--keep|--keep-|--keep-s|--keep-su|--keep-sub|\
     --keep-subj|--keep-subje|--keep-subjec|--keep-subject)
     keep_subject=t ;;
@@ -173,80 +171,89 @@
 	q
 '
 
-whosepatchScript='
-/^author /{
-	s/'\''/'\''\\'\'\''/g
-	s/author \(.*>\) \(.*\)$/au='\''\1'\'' ad='\''\2'\''/p
-	q
-}'
-
 process_one () {
-	mailScript='
-	/./d
-	/^$/n'
-	case "$keep_subject" in
-	t)  ;;
-	*)
-	    mailScript="$mailScript"'
-	    s|^\[PATCH[^]]*\] *||
-	    s|^|[PATCH'"$num"'] |'
-	    ;;
-	esac
-	mailScript="$mailScript"'
-	s|^|Subject: |'
-	case "$mbox" in
-	t)
-	    echo 'From nobody Mon Sep 17 00:00:00 2001' ;# UNIX "From" line
-	    ;;
-	esac
+	perl -w -e '
+my ($keep_subject, $num, $signoff, $commsg) = @ARGV;
+my ($signoff_pattern, $done_header, $done_subject, $signoff_seen,
+    $last_was_signoff);
 
-	eval "$(sed -ne "$whosepatchScript" $commsg)"
-	test "$author,$au" = ",$me" || {
-		mailScript="$mailScript"'
-	a\
-From: '"$au"
+if ($signoff) {
+	$signoff = `git-var GIT_COMMITTER_IDENT`;
+	$signoff =~ s/>.*/>/;
+	$signoff_pattern = quotemeta($signoff);
+}
+
+my @weekday_names = qw(Sun Mon Tue Wed Thu Fri Sat);
+my @month_names = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
+
+sub show_date {
+    my ($time, $tz) = @_;
+    my $minutes = abs($tz);
+    $minutes = ($minutes / 100) * 60 + ($minutes % 100);
+    if ($tz < 0) {
+        $minutes = -$minutes;
+    }
+    my $t = $time + $minutes * 60;
+    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime($t);
+    return sprintf("%s %s %d %02d:%02d:%02d %d %+05d",
+		   $weekday_names[$wday],
+		   $month_names[$mon],
+		   $mday, $hour, $min, $sec,
+		   $year+1900, $tz);
+}
+
+print "From nobody Mon Sep 17 00:00:00 2001\n";
+open FH, "git stripspace <$commsg |" or die "open $commsg pipe";
+while (<FH>) {
+    unless ($done_header) {
+	if (/^$/) {
+	    $done_header = 1;
 	}
-	test "$date,$au" = ",$me" || {
-		mailScript="$mailScript"'
-	a\
-Date: '"$ad"
+	elsif (/^author (.*>) (.*)$/) {
+	    my ($author_ident, $author_date) = ($1, $2);
+	    my ($utc, $off) = ($author_date =~ /^(\d+) ([-+]?\d+)$/);
+	    $author_date = show_date($utc, $off);
+
+	    print "From: $author_ident\n";
+	    print "Date: $author_date\n";
 	}
-
-	mailScript="$mailScript"'
-	a\
-
-	: body
-	p
-	n
-	b body'
-
-	(cat $commsg ; echo; echo) |
-	sed -ne "$mailScript" |
-	git-stripspace
-
-	test "$signoff" = "t" && {
-		offsigner=`git-var GIT_COMMITTER_IDENT | sed -e 's/>.*/>/'`
-		line="Signed-off-by: $offsigner"
-		grep -q "^$line\$" $commsg || {
-			echo
-			echo "$line"
-			echo
-		}
+	next;
+    }
+    unless ($done_subject) {
+	unless ($keep_subject) {
+	    s/^\[PATCH[^]]*\]\s*//;
+	    s/^/[PATCH$num] /;
 	}
-	echo
-	echo '---'
-	echo
+        print "Subject: $_";
+	$done_subject = 1;
+	next;
+    }
+
+    $last_was_signoff = 0;
+    if (/Signed-off-by:/i) {
+        if ($signoff ne "" && /Signed-off-by:\s*$signoff_pattern$/i) {
+	    $signoff_seen = 1;
+	}
+    }
+    print $_;
+}
+if (!$signoff_seen && $signoff ne "") {
+    if (!$last_was_signoff) {
+        print "\n";
+    }
+    print "$signoff\n";
+}
+print "\n---\n\n";
+close FH or die "close $commsg pipe";
+' "$keep_subject" "$num" "$signoff" $commsg
+
 	git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
 	echo
 	git-diff-tree -p $diff_opts "$commit"
 	echo "-- "
 	echo "@@GIT_VERSION@@"
 
-	case "$mbox" in
-	t)
-		echo
-		;;
-	esac
+	echo
 }
 
 total=`wc -l <$series | tr -dc "[0-9]"`
diff --git a/git-merge-octopus.sh b/git-merge-octopus.sh
index 7adffdc..eb74f96 100755
--- a/git-merge-octopus.sh
+++ b/git-merge-octopus.sh
@@ -48,16 +48,24 @@
 MRT=$(git-write-tree)
 CNT=1 ;# counting our head
 NON_FF_MERGE=0
+OCTOPUS_FAILURE=0
 for SHA1 in $remotes
 do
+	case "$OCTOPUS_FAILURE" in
+	1)
+		# We allow only last one to have a hand-resolvable
+		# conflicts.  Last round failed and we still had
+		# a head to merge.
+		echo "Automated merge did not work."
+		echo "Should not be doing an Octopus."
+		exit 2
+	esac
+
 	common=$(git-merge-base --all $MRC $SHA1) ||
 		die "Unable to find common commit with $SHA1"
 
-	case "$common" in
-	?*"$LF"?*)
-		die "Not trivially mergeable."
-		;;
-	$SHA1)
+	case "$LF$common$LF" in
+	*"$LF$SHA1$LF"*)
 		echo "Already up-to-date with $SHA1"
 		continue
 		;;
@@ -88,7 +96,7 @@
 	then
 		echo "Simple merge did not work, trying automatic merge."
 		git-merge-index -o git-merge-one-file -a ||
-		exit 2 ; # Automatic merge failed; should not be doing Octopus
+		OCTOPUS_FAILURE=1
 		next=$(git-write-tree 2>/dev/null)
 	fi
 
@@ -103,4 +111,4 @@
 	MRT=$next
 done
 
-exit 0
+exit "$OCTOPUS_FAILURE"
diff --git a/git-push.sh b/git-push.sh
index 1c5cf80..136093b 100755
--- a/git-push.sh
+++ b/git-push.sh
@@ -9,12 +9,15 @@
 has_force=
 has_exec=
 remote=
+do_tags=
 
 while case "$#" in 0) break ;; esac
 do
 	case "$1" in
 	--all)
 		has_all=--all ;;
+	--tags)
+		do_tags=yes ;;
 	--force)
 		has_force=--force ;;
 	--exec=*)
@@ -33,6 +36,10 @@
 	echo "Where would you want to push today?"
         usage ;;
 esac
+if test ",$has_all,$do_tags," = ",--all,yes,"
+then
+	do_tags=
+fi
 
 . git-parse-remote
 remote=$(get_remote_url "$@")
@@ -42,6 +49,20 @@
 esac
 shift
 
+case "$do_tags" in
+yes)
+	set "$@" $(cd "$GIT_DIR/refs" && find tags -type f -print) ;;
+esac
+
+# Now we have explicit refs from the command line or from remotes/
+# shorthand, or --tags.  Falling back on the current branch if we still
+# do not have any may be an alternative, but prevent mistakes for now.
+
+case "$#,$has_all" in
+0,)
+	die "No refs given to be pushed." ;;
+esac
+
 case "$remote" in
 git://*)
 	die "Cannot use READ-ONLY transport to push to $remote" ;;
diff --git a/git.c b/git.c
index 5e7da74..4616df6 100644
--- a/git.c
+++ b/git.c
@@ -10,6 +10,7 @@
 #include <stdarg.h>
 #include <sys/ioctl.h>
 #include "git-compat-util.h"
+#include "exec_cmd.h"
 
 #ifndef PATH_MAX
 # define PATH_MAX 4096
@@ -233,14 +234,11 @@
 {
 	char git_command[PATH_MAX + 1];
 	char wd[PATH_MAX + 1];
-	int i, len, show_help = 0;
-	char *exec_path = getenv("GIT_EXEC_PATH");
+	int i, show_help = 0;
+	const char *exec_path;
 
 	getcwd(wd, PATH_MAX);
 
-	if (!exec_path)
-		exec_path = GIT_EXEC_PATH;
-
 	for (i = 1; i < argc; i++) {
 		char *arg = argv[i];
 
@@ -256,10 +254,11 @@
 
 		if (!strncmp(arg, "exec-path", 9)) {
 			arg += 9;
-			if (*arg == '=')
+			if (*arg == '=') {
 				exec_path = arg + 1;
-			else {
-				puts(exec_path);
+				git_set_exec_path(exec_path);
+			} else {
+				puts(git_exec_path());
 				exit(0);
 			}
 		}
@@ -275,42 +274,15 @@
 
 	if (i >= argc || show_help) {
 		if (i >= argc)
-			cmd_usage(exec_path, NULL);
+			cmd_usage(git_exec_path(), NULL);
 
 		show_man_page(argv[i]);
 	}
 
-	if (*exec_path != '/') {
-		if (!getcwd(git_command, sizeof(git_command))) {
-			fprintf(stderr,
-				"git: cannot determine current directory\n");
-			exit(1);
-		}
-		len = strlen(git_command);
+	exec_path = git_exec_path();
+	prepend_to_path(exec_path, strlen(exec_path));
 
-		/* Trivial cleanup */
-		while (!strncmp(exec_path, "./", 2)) {
-			exec_path += 2;
-			while (*exec_path == '/')
-				exec_path++;
-		}
-		snprintf(git_command + len, sizeof(git_command) - len,
-			 "/%s", exec_path);
-	}
-	else
-		strcpy(git_command, exec_path);
-	len = strlen(git_command);
-	prepend_to_path(git_command, len);
-
-	len += snprintf(git_command + len, sizeof(git_command) - len,
-			"/git-%s", argv[i]);
-	if (sizeof(git_command) <= len) {
-		fprintf(stderr, "git: command name given is too long.\n");
-		exit(1);
-	}
-
-	/* execve() can only ever return if it fails */
-	execve(git_command, &argv[i], envp);
+	execv_git_cmd(argv + i);
 
 	if (errno == ENOENT)
 		cmd_usage(exec_path, "'%s' is not a git-command", argv[i]);
diff --git a/receive-pack.c b/receive-pack.c
index f847ec2..eae31e3 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -6,7 +6,7 @@
 
 static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
 
-static const char unpacker[] = "git-unpack-objects";
+static char *unpacker[] = { "unpack-objects", NULL };
 
 static int report_status = 0;
 
@@ -257,7 +257,7 @@
 
 static const char *unpack(int *error_code)
 {
-	int code = run_command(unpacker, NULL);
+	int code = run_command_v_opt(1, unpacker, RUN_GIT_CMD);
 
 	*error_code = 0;
 	switch (code) {
diff --git a/run-command.c b/run-command.c
index 8bf5922..b3d287e 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1,6 +1,7 @@
 #include "cache.h"
 #include "run-command.h"
 #include <sys/wait.h>
+#include "exec_cmd.h"
 
 int run_command_v_opt(int argc, char **argv, int flags)
 {
@@ -13,9 +14,13 @@
 			int fd = open("/dev/null", O_RDWR);
 			dup2(fd, 0);
 			dup2(fd, 1);
-			close(fd);			
+			close(fd);
 		}
-		execvp(argv[0], (char *const*) argv);
+		if (flags & RUN_GIT_CMD) {
+			execv_git_cmd(argv);
+		} else {
+			execvp(argv[0], (char *const*) argv);
+		}
 		die("exec %s failed.", argv[0]);
 	}
 	for (;;) {
diff --git a/run-command.h b/run-command.h
index 2469eea..ef3ee05 100644
--- a/run-command.h
+++ b/run-command.h
@@ -12,7 +12,7 @@
 };
 
 #define RUN_COMMAND_NO_STDIO 1
-
+#define RUN_GIT_CMD	     2	/*If this is to be git sub-command */
 int run_command_v_opt(int argc, char **argv, int opt);
 int run_command_v(int argc, char **argv);
 int run_command(const char *cmd, ...);
diff --git a/send-pack.c b/send-pack.c
index cd36193..990be3f 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -3,6 +3,7 @@
 #include "tag.h"
 #include "refs.h"
 #include "pkt-line.h"
+#include "exec_cmd.h"
 
 static const char send_pack_usage[] =
 "git-send-pack [--all] [--exec=git-receive-pack] <remote> [<head>...]\n"
@@ -26,11 +27,11 @@
 static void exec_pack_objects(void)
 {
 	static char *args[] = {
-		"git-pack-objects",
+		"pack-objects",
 		"--stdout",
 		NULL
 	};
-	execvp("git-pack-objects", args);
+	execv_git_cmd(args);
 	die("git-pack-objects exec failed (%s)", strerror(errno));
 }
 
@@ -39,7 +40,7 @@
 	static char *args[1000];
 	int i = 0;
 
-	args[i++] = "git-rev-list";	/* 0 */
+	args[i++] = "rev-list";	/* 0 */
 	args[i++] = "--objects";	/* 1 */
 	while (refs) {
 		char *buf = malloc(100);
@@ -58,7 +59,7 @@
 		refs = refs->next;
 	}
 	args[i] = NULL;
-	execvp("git-rev-list", args);
+	execv_git_cmd(args);
 	die("git-rev-list exec failed (%s)", strerror(errno));
 }
 
diff --git a/shell.c b/shell.c
index cd31618..fc0c73c 100644
--- a/shell.c
+++ b/shell.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "quote.h"
+#include "exec_cmd.h"
 
 static int do_generic_cmd(const char *me, char *arg)
 {
@@ -7,12 +8,14 @@
 
 	if (!arg || !(arg = sq_dequote(arg)))
 		die("bad argument");
+	if (strncmp(me, "git-", 4))
+		die("bad command");
 
-	my_argv[0] = me;
+	my_argv[0] = me + 4;
 	my_argv[1] = arg;
 	my_argv[2] = NULL;
 
-	return execvp(me, (char**) my_argv);
+	return execv_git_cmd((char**) my_argv);
 }
 
 static struct commands {
diff --git a/show-branch.c b/show-branch.c
index 1935c44..7a0dcc6 100644
--- a/show-branch.c
+++ b/show-branch.c
@@ -5,7 +5,11 @@
 #include "refs.h"
 
 static const char show_branch_usage[] =
-"git-show-branch [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [<refs>...]";
+"git-show-branch [--current] [--all] [--heads] [--tags] [--topo-order] [--more=count | --list | --independent | --merge-base ] [<refs>...]";
+
+static int default_num = 0;
+static int default_alloc = 0;
+static char **default_arg = NULL;
 
 #define UNINTERESTING	01
 
@@ -431,12 +435,12 @@
 	}
 }
 
-static int rev_is_head(char *head_path, int headlen,
-		       char *name,
+static int rev_is_head(char *head_path, int headlen, char *name,
 		       unsigned char *head_sha1, unsigned char *sha1)
 {
 	int namelen;
-	if ((!head_path[0]) || memcmp(head_sha1, sha1, 20))
+	if ((!head_path[0]) ||
+	    (head_sha1 && sha1 && memcmp(head_sha1, sha1, 20)))
 		return 0;
 	namelen = strlen(name);
 	if ((headlen < namelen) ||
@@ -508,6 +512,21 @@
 	die("bad sha1 reference %s", av);
 }
 
+static int git_show_branch_config(const char *var, const char *value)
+{
+	if (!strcmp(var, "showbranch.default")) {
+		if (default_alloc <= default_num + 1) {
+			default_alloc = default_alloc * 3 / 2 + 20;
+			default_arg = xrealloc(default_arg, sizeof *default_arg * default_alloc);
+		}
+		default_arg[default_num++] = strdup(value);
+		default_arg[default_num] = NULL;
+		return 0;
+	}
+
+	return git_default_config(var, value);
+}
+
 int main(int ac, char **av)
 {
 	struct commit *rev[MAX_REVS], *commit;
@@ -526,12 +545,25 @@
 	int sha1_name = 0;
 	int shown_merge_point = 0;
 	int topo_order = 0;
+	int with_current_branch = 0;
+	int head_at = -1;
 
+	git_config(git_show_branch_config);
 	setup_git_directory();
 
+	/* If nothing is specified, try the default first */
+	if (ac == 1 && default_num) {
+		ac = default_num + 1;
+		av = default_arg - 1; /* ick; we would not address av[0] */
+	}
+
 	while (1 < ac && av[1][0] == '-') {
 		char *arg = av[1];
-		if (!strcmp(arg, "--all"))
+		if (!strcmp(arg, "--")) {
+			ac--; av++;
+			break;
+		}
+		else if (!strcmp(arg, "--all"))
 			all_heads = all_tags = 1;
 		else if (!strcmp(arg, "--heads"))
 			all_heads = 1;
@@ -543,6 +575,8 @@
 			extra = -1;
 		else if (!strcmp(arg, "--no-name"))
 			no_name = 1;
+		else if (!strcmp(arg, "--current"))
+			with_current_branch = 1;
 		else if (!strcmp(arg, "--sha1-name"))
 			sha1_name = 1;
 		else if (!strncmp(arg, "--more=", 7))
@@ -574,6 +608,34 @@
 		ac--; av++;
 	}
 
+	head_path_p = resolve_ref(git_path("HEAD"), head_sha1, 1);
+	if (head_path_p) {
+		head_path_len = strlen(head_path_p);
+		memcpy(head_path, head_path_p, head_path_len + 1);
+	}
+	else {
+		head_path_len = 0;
+		head_path[0] = 0;
+	}
+
+	if (with_current_branch && head_path_p) {
+		int has_head = 0;
+		for (i = 0; !has_head && i < ref_name_cnt; i++) {
+			/* We are only interested in adding the branch
+			 * HEAD points at.
+			 */
+			if (rev_is_head(head_path,
+					head_path_len,
+					ref_name[i],
+					head_sha1, NULL))
+				has_head++;
+		}
+		if (!has_head) {
+			int pfxlen = strlen(git_path("refs/heads/"));
+			append_one_rev(head_path + pfxlen);
+		}
+	}
+
 	if (!ref_name_cnt) {
 		fprintf(stderr, "No revs to be shown.\n");
 		exit(0);
@@ -609,16 +671,6 @@
 	if (0 <= extra)
 		join_revs(&list, &seen, num_rev, extra);
 
-	head_path_p = resolve_ref(git_path("HEAD"), head_sha1, 1);
-	if (head_path_p) {
-		head_path_len = strlen(head_path_p);
-		memcpy(head_path, head_path_p, head_path_len + 1);
-	}
-	else {
-		head_path_len = 0;
-		head_path[0] = 0;
-	}
-
 	if (merge_base)
 		return show_merge_base(seen, num_rev);
 
@@ -645,6 +697,8 @@
 			}
 			/* header lines never need name */
 			show_one_commit(rev[i], 1);
+			if (is_head)
+				head_at = i;
 		}
 		if (0 <= extra) {
 			for (i = 0; i < num_rev; i++)
@@ -673,9 +727,19 @@
 		shown_merge_point |= ((this_flag & all_revs) == all_revs);
 
 		if (1 < num_rev) {
-			for (i = 0; i < num_rev; i++)
-				putchar((this_flag & (1u << (i + REV_SHIFT)))
-					? '+' : ' ');
+			int is_merge = !!(commit->parents && commit->parents->next);
+			for (i = 0; i < num_rev; i++) {
+				int mark;
+				if (!(this_flag & (1u << (i + REV_SHIFT))))
+					mark = ' ';
+				else if (is_merge)
+					mark = '-';
+				else if (i == head_at)
+					mark = '*';
+				else
+					mark = '+';
+				putchar(mark);
+			}
 			putchar(' ');
 		}
 		show_one_commit(commit, no_name);
diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
index d7562e9..8ff5dd9 100755
--- a/t/t1200-tutorial.sh
+++ b/t/t1200-tutorial.sh
@@ -118,8 +118,8 @@
 * [master] Merged "mybranch" changes.
  ! [mybranch] Some work.
 --
-+  [master] Merged "mybranch" changes.
-++ [mybranch] Some work.
+-  [master] Merged "mybranch" changes.
+*+ [mybranch] Some work.
 EOF
 
 git show-branch --topo-order master mybranch > show-branch.output
@@ -142,7 +142,7 @@
 ! [master] Merged "mybranch" changes.
  * [mybranch] Merged "mybranch" changes.
 --
-++ [master] Merged "mybranch" changes.
+-- [master] Merged "mybranch" changes.
 EOF
 
 git show-branch --topo-order master mybranch > show-branch2.output
diff --git a/upload-pack.c b/upload-pack.c
index 1834b6b..d198055 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -4,6 +4,7 @@
 #include "tag.h"
 #include "object.h"
 #include "commit.h"
+#include "exec_cmd.h"
 
 static const char upload_pack_usage[] = "git-upload-pack [--strict] [--timeout=nn] <dir>";
 
@@ -60,7 +61,7 @@
 		close(0);
 		close(fd[0]);
 		close(fd[1]);
-		*p++ = "git-rev-list";
+		*p++ = "rev-list";
 		*p++ = "--objects";
 		if (create_full_pack || MAX_NEEDS <= nr_needs)
 			*p++ = "--all";
@@ -79,13 +80,13 @@
 				buf += 41;
 			}
 		*p++ = NULL;
-		execvp("git-rev-list", argv);
+		execv_git_cmd(argv);
 		die("git-upload-pack: unable to exec git-rev-list");
 	}
 	dup2(fd[0], 0);
 	close(fd[0]);
 	close(fd[1]);
-	execlp("git-pack-objects", "git-pack-objects", "--stdout", NULL);
+	execl_git_cmd("pack-objects", "--stdout", NULL);
 	die("git-upload-pack: unable to exec git-pack-objects");
 }