GIT 1.1.3
diff --git a/.gitignore b/.gitignore
index dbbef06..5382e74 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+GIT-VERSION-FILE
 git
 git-add
 git-am
@@ -27,6 +28,7 @@
 git-diff-index
 git-diff-stages
 git-diff-tree
+git-describe
 git-fetch
 git-fetch-pack
 git-findtags
diff --git a/Documentation/fetch-options.txt b/Documentation/fetch-options.txt
index 200c9b2..1fe8423 100644
--- a/Documentation/fetch-options.txt
+++ b/Documentation/fetch-options.txt
@@ -10,15 +10,23 @@
 	fetches is a descendant of `<lbranch>`.  This option
 	overrides that check.
 
+\--no-tags::
+	By default, `git-fetch` fetches tags that point at
+	objects that are downloaded from the remote repository
+	and stores them locally.  This option disables this
+	automatic tag following.
+
 -t, \--tags::
-	By default, the git core utilities will not fetch and store
-	tags under the same name as the remote repository;  ask it
-	to do so using `--tags`.  Using this option will bound the
-	list of objects pulled to the remote tags.  Commits in branches
-	beyond the tags will be ignored.
+	Most of the tags are fetched automatically as branch
+	heads are downloaded, but tags that do not point at
+	objects reachable from the branch heads that are being
+	tracked will not be fetched by this mechanism.  This
+	flag lets all tags and their associated objects be
+	downloaded.
 
 -u, \--update-head-ok::
 	By default `git-fetch` refuses to update the head which
 	corresponds to the current branch.  This flag disables the
 	check.  Note that fetching into the current branch will not
 	update the index and working directory, so use it with care.
+
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index ffa4fb0..790b87b 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -9,7 +9,7 @@
 SYNOPSIS
 --------
 [verse]
-'git-clone' [-l [-s]] [-q] [-n] [-u <upload-pack>]
+'git-clone' [-l [-s]] [-q] [-n] [-o <name>] [-u <upload-pack>]
 	  <repository> [<directory>]
 
 DESCRIPTION
@@ -58,6 +58,13 @@
 -n::
 	No checkout of HEAD is performed after the clone is complete.
 
+-o <name>::
+	Instead of using the branch name 'origin' to keep track
+	of the upstream repository, use <name> instead.  Note
+	that the shorthand name stored in `remotes/origin` is
+	not affected, but the local branch name to pull the
+	remote `master` branch into is.
+
 --upload-pack <upload-pack>::
 -u <upload-pack>::
 	When given, and the repository to clone from is handled
diff --git a/Documentation/git-daemon.txt b/Documentation/git-daemon.txt
index 33f3320..a20e053 100644
--- a/Documentation/git-daemon.txt
+++ b/Documentation/git-daemon.txt
@@ -9,7 +9,8 @@
 --------
 [verse]
 'git-daemon' [--verbose] [--syslog] [--inetd | --port=n] [--export-all]
-           [--timeout=n] [--init-timeout=n] [--strict-paths] [directory...]
+             [--timeout=n] [--init-timeout=n] [--strict-paths]
+             [--base-path=path] [directory...]
 
 DESCRIPTION
 -----------
@@ -36,6 +37,14 @@
 	git-daemon will refuse to start when this option is enabled and no
 	whitelist is specified.
 
+--base-path::
+	Remap all the path requests as relative to the given path.
+	This is sort of "GIT root" - if you run git-daemon with
+	'--base-path=/srv/git' on example.com, then if you later try to pull
+	'git://example.com/hello.git', `git-daemon` will interpret the path
+	as '/srv/git/hello.git'. Home directories (the '~login' notation)
+	access is disabled.
+
 --export-all::
 	Allow pulling from all directories that look like GIT repositories
 	(have the 'objects' and 'refs' subdirectories), even if they
diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
new file mode 100644
index 0000000..0efe82a
--- /dev/null
+++ b/Documentation/git-describe.txt
@@ -0,0 +1,79 @@
+git-describe(1)
+===============
+
+NAME
+----
+git-describe - Show the most recent tag that is reachable from a commit.
+
+
+SYNOPSIS
+--------
+'git-describe' [--all] [--tags] [--abbrev=<n>] <committish>...
+
+DESCRIPTION
+-----------
+The command finds the most recent tag that is reachable from a
+commit, and if the commit itself is pointed at by the tag, shows
+the tag.  Otherwise, it suffixes the tag name with abbreviated
+object name of the commit.
+
+
+OPTIONS
+-------
+<committish>::
+	The object name of the comittish. 
+
+--all::
+	Instead of using only the annotated tags, use any ref
+	found in `.git/refs/`.
+
+--tags::
+	Instead of using only the annotated tags, use any tag
+	found in `.git/refs/tags`.
+
+--abbrev=<n>::
+	Instead of using the default 8 hexadecimal digits as the
+	abbreviated object name, use <n> digits.
+
+
+EXAMPLES
+--------
+
+With something like git.git current tree, I get:
+
+	[torvalds@g5 git]$ git-describe parent
+	v1.0.4-g2414721b
+
+i.e. the current head of my "parent" branch is based on v1.0.4,
+but since it has a few commits on top of that, it has added the
+git hash of the thing to the end: "-g" + 8-char shorthand for
+the commit `2414721b194453f058079d897d13c4e377f92dc6`.
+
+Doing a "git-describe" on a tag-name will just show the tag name:
+
+	[torvalds@g5 git]$ git-describe v1.0.4
+	v1.0.4
+
+With --all, the command can use branch heads as references, so
+the output shows the reference path as well:
+
+	[torvalds@g5 git]$ git describe --all --abbrev=4 v1.0.5^2
+	tags/v1.0.0-g975b
+
+	[torvalds@g5 git]$ git describe --all HEAD^
+	heads/lt/describe-g975b
+
+
+Author
+------
+Written by Linus Torvalds <torvalds@osdl.org>, but somewhat
+butchered by Junio C Hamano <junkio@cox.net>
+
+Documentation
+--------------
+Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 431b8f6..d638bfc 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -68,10 +68,15 @@
 	Show all refs found in `$GIT_DIR/refs`.
 
 --show-prefix::
-	When the command is invoked from a directory show the
+	When the command is invoked from a subdirectory, show the
 	path of the current directory relative to the top-level
 	directory.
 
+--show-cdup::
+	When the command is invoked from a subdirectory, show the
+	path of the top-level directory relative to the current
+	directory (typically a sequence of "../", or an empty string).
+
 --since=datestring, --after=datestring::
 	Parses the date string, and outputs corresponding
 	--max-age= parameter for git-rev-list command.
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 875d4877..92cfe0e 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -139,6 +139,9 @@
 gitlink:git-cat-file[1]::
 	Provide content or type/size information for repository objects.
 
+gitlink:git-describe[1]::
+	Show the most recent tag that is reachable from a commit.
+
 gitlink:git-diff-index[1]::
 	Compares content and mode of blobs between the index and repository.
 
diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt
index 3a5c56e..edd91cb 100644
--- a/Documentation/tutorial.txt
+++ b/Documentation/tutorial.txt
@@ -1695,6 +1695,24 @@
 and put them in the same group.  Make sure that the repository
 shared among these developers is writable by that group.
 
+. Initializing the shared repository with `git-init-db --shared`
+helps somewhat.
+
+. Run the following in the shared repository:
++
+------------
+$ chgrp -R $group repo.git
+$ find repo.git -type d -print | xargs chmod ug+rwx,g+s
+$ GIT_DIR=repo.git git repo-config core.sharedrepository true
+------------
+
+The above measures make sure that directories lazily created in
+`$GIT_DIR` are writable by group members.  You, as the
+repository administrator, are still responsible to make sure
+your developers belong to that shared repository group and set
+their umask to a value no stricter than 027 (i.e. at least allow
+reading and searching by group members).
+
 You can implement finer grained branch policies using update
 hooks.  There is a document ("control access to branches") in
 Documentation/howto by Carl Baldwin and JC outlining how to (1)
diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN
new file mode 100755
index 0000000..73aaff0
--- /dev/null
+++ b/GIT-VERSION-GEN
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+GVF=GIT-VERSION-FILE
+DEF_VER=v1.1.GIT
+
+# First try git-describe, then see if there is a version file
+# (included in release tarballs), then default
+VN=$(git-describe --abbrev=4 HEAD 2>/dev/null) ||
+VN=$(cat version) ||
+VN="$DEF_VER"
+
+VN=$(expr "$VN" : v*'\(.*\)')
+
+dirty=$(sh -c 'git-diff-index --name-only HEAD' 2>/dev/null) || dirty=
+case "$dirty" in
+'')
+	;;
+*)
+	VN="$VN-dirty" ;;
+esac
+
+if test -r $GVF
+then
+	VC=$(sed -e 's/^GIT_VERSION = //' <$GVF)
+else
+	VC=unset
+fi
+test "$VN" = "$VC" || {
+	echo >&2 "GIT_VERSION = $VN"
+	echo "GIT_VERSION = $VN" >$GVF
+}
+
+
diff --git a/Makefile b/Makefile
index 56505b4..fa0cd83 100644
--- a/Makefile
+++ b/Makefile
@@ -55,7 +55,9 @@
 # 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 = 1.0.11
+GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
+	@sh ./GIT-VERSION-GEN
+-include GIT-VERSION-FILE
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
@@ -135,7 +137,8 @@
 	git-unpack-objects$X git-update-index$X git-update-server-info$X \
 	git-upload-pack$X git-verify-pack$X git-write-tree$X \
 	git-update-ref$X git-symbolic-ref$X git-check-ref-format$X \
-	git-name-rev$X git-pack-redundant$X git-repo-config$X git-var$X
+	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
@@ -368,7 +371,7 @@
 all:
 	$(MAKE) -C templates
 
-git$X: git.c $(LIB_FILE) Makefile
+git$X: git.c $(LIB_FILE)
 	$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
 		$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(LIB_FILE)
 
@@ -397,8 +400,12 @@
 git-cherry-pick: git-revert
 	cp $< $@
 
-# format-patch records GIT_VERSION
-git-format-patch: Makefile
+# These can record GIT_VERSION
+git$X git.spec \
+	$(patsubst %.sh,%,$(SCRIPT_SH)) \
+	$(patsubst %.perl,%,$(SCRIPT_PERL)) \
+	$(patsubst %.py,%,$(SCRIPT_PYTHON)) \
+	: GIT-VERSION-FILE
 
 %.o: %.c
 	$(CC) -o $*.o -c $(ALL_CFLAGS) $<
@@ -474,7 +481,7 @@
 
 ### Maintainer's dist rules
 
-git.spec: git.spec.in Makefile
+git.spec: git.spec.in
 	sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@
 
 GIT_TARNAME=git-$(GIT_VERSION)
@@ -482,7 +489,9 @@
 	./git-tar-tree HEAD $(GIT_TARNAME) > $(GIT_TARNAME).tar
 	@mkdir -p $(GIT_TARNAME)
 	@cp git.spec $(GIT_TARNAME)
-	$(TAR) rf $(GIT_TARNAME).tar $(GIT_TARNAME)/git.spec
+	@echo $(GIT_VERSION) > $(GIT_TARNAME)/version
+	$(TAR) rf $(GIT_TARNAME).tar \
+		$(GIT_TARNAME)/git.spec $(GIT_TARNAME)/version
 	@rm -rf $(GIT_TARNAME)
 	gzip -f -9 $(GIT_TARNAME).tar
 
@@ -501,4 +510,8 @@
 	$(MAKE) -C Documentation/ clean
 	$(MAKE) -C templates clean
 	$(MAKE) -C t/ clean
+	rm -f GIT-VERSION-FILE
+
+.PHONY: all install clean
+.PHONY: .FORCE-GIT-VERSION-FILE
 
diff --git a/cache.h b/cache.h
index 5fd2687..29c9e81 100644
--- a/cache.h
+++ b/cache.h
@@ -159,6 +159,7 @@
 extern int trust_executable_bit;
 extern int only_use_symrefs;
 extern int diff_rename_limit_default;
+extern int shared_repository;
 
 #define GIT_REPO_VERSION 0
 extern int repository_format_version;
@@ -183,6 +184,7 @@
 
 int git_mkstemp(char *path, size_t n, const char *template);
 
+int adjust_shared_perm(const char *path);
 int safe_create_leading_directories(char *path);
 char *safe_strncpy(char *, const char *, size_t);
 char *enter_repo(char *path, int strict);
diff --git a/commit.c b/commit.c
index fb02ba6..b8bf35e 100644
--- a/commit.c
+++ b/commit.c
@@ -352,6 +352,21 @@
 	return ret;
 }
 
+void clear_commit_marks(struct commit *commit, unsigned int mark)
+{
+	struct commit_list *parents;
+
+	parents = commit->parents;
+	commit->object.flags &= ~mark;
+	while (parents) {
+		struct commit *parent = parents->item;
+		if (parent && parent->object.parsed &&
+		    (parent->object.flags & mark))
+			clear_commit_marks(parent, mark);
+		parents = parents->next;
+	}
+}
+
 /*
  * Generic support for pretty-printing the header
  */
diff --git a/commit.h b/commit.h
index 6738a69..9c4a244 100644
--- a/commit.h
+++ b/commit.h
@@ -58,6 +58,8 @@
 
 struct commit *pop_commit(struct commit_list **stack);
 
+void clear_commit_marks(struct commit *commit, unsigned int mark);
+
 int count_parents(struct commit * commit);
 
 /*
diff --git a/connect.c b/connect.c
index 93f6f80..d6f4e4c 100644
--- a/connect.c
+++ b/connect.c
@@ -34,10 +34,6 @@
 			die("protocol error: expected sha/ref, got '%s'", buffer);
 		name = buffer + 41;
 
-		if (ignore_funny && 45 < len && !memcmp(name, "refs/", 5) &&
-		    check_ref_format(name + 5))
-			continue;
-
 		name_len = strlen(name);
 		if (len != name_len + 41) {
 			if (server_capabilities)
@@ -45,6 +41,10 @@
 			server_capabilities = strdup(name + name_len + 1);
 		}
 
+		if (ignore_funny && 45 < len && !memcmp(name, "refs/", 5) &&
+		    check_ref_format(name + 5))
+			continue;
+
 		if (nr_match && !path_match(name, nr_match, match))
 			continue;
 		ref = xcalloc(1, sizeof(*ref) + len - 40);
@@ -561,7 +561,8 @@
 {
 	char command[1024];
 	char *host, *path = url;
-	char *colon = NULL;
+	char *end;
+	int c;
 	int pipefd[2][2];
 	pid_t pid;
 	enum protocol protocol = PROTO_LOCAL;
@@ -571,15 +572,30 @@
 		*host = '\0';
 		protocol = get_protocol(url);
 		host += 3;
-		path = strchr(host, '/');
-	}
-	else {
+		c = '/';
+	} else {
 		host = url;
-		if ((colon = strchr(host, ':'))) {
+		c = ':';
+	}
+
+	if (host[0] == '[') {
+		end = strchr(host + 1, ']');
+		if (end) {
+			*end = 0;
+			end++;
+			host++;
+		} else
+			end = host;
+	} else
+		end = host;
+
+	path = strchr(end, c);
+	if (c == ':') {
+		if (path) {
 			protocol = PROTO_SSH;
-			*colon = '\0';
-			path = colon + 1;
-		}
+			*path++ = '\0';
+		} else
+			path = host;
 	}
 
 	if (!path || !*path)
diff --git a/daemon.c b/daemon.c
index 539f6e8..3bd1426 100644
--- a/daemon.c
+++ b/daemon.c
@@ -15,7 +15,8 @@
 
 static const char daemon_usage[] =
 "git-daemon [--verbose] [--syslog] [--inetd | --port=n] [--export-all]\n"
-"           [--timeout=n] [--init-timeout=n] [--strict-paths] [directory...]";
+"           [--timeout=n] [--init-timeout=n] [--strict-paths]\n"
+"           [--base-path=path] [directory...]";
 
 /* List of acceptable pathname prefixes */
 static char **ok_paths = NULL;
@@ -24,6 +25,9 @@
 /* If this is set, git-daemon-export-ok is not required */
 static int export_all_trees = 0;
 
+/* Take all paths relative to this one if non-NULL */
+static char *base_path = NULL;
+
 /* Timeout, and initial timeout */
 static unsigned int timeout = 0;
 static unsigned int init_timeout = 0;
@@ -138,6 +142,17 @@
 		return NULL;
 	}
 
+	if (base_path) {
+		static char rpath[PATH_MAX];
+		if (*dir != '/') {
+			/* Forbid possible base-path evasion using ~paths. */
+			logerror("'%s': Non-absolute path denied (base-path active)");
+			return NULL;
+		}
+		snprintf(rpath, PATH_MAX, "%s%s", base_path, dir);
+		dir = rpath;
+	}
+
 	path = enter_repo(dir, strict_paths);
 
 	if (!path) {
@@ -639,6 +654,10 @@
 			strict_paths = 1;
 			continue;
 		}
+		if (!strncmp(arg, "--base-path=", 12)) {
+			base_path = arg+12;
+			continue;
+		}
 		if (!strcmp(arg, "--")) {
 			ok_paths = &argv[i+1];
 			break;
diff --git a/describe.c b/describe.c
new file mode 100644
index 0000000..cc95eb0
--- /dev/null
+++ b/describe.c
@@ -0,0 +1,166 @@
+#include "cache.h"
+#include "commit.h"
+#include "tag.h"
+#include "refs.h"
+
+#define SEEN (1u << 0)
+
+static const char describe_usage[] =
+"git-describe [--all] [--tags] [--abbrev=<n>] <committish>*";
+
+static int all = 0;	/* Default to annotated tags only */
+static int tags = 0;	/* But allow any tags if --tags is specified */
+
+#define DEFAULT_ABBREV 8 /* maybe too many */
+static int abbrev = DEFAULT_ABBREV;
+
+static int names = 0, allocs = 0;
+static struct commit_name {
+	const struct commit *commit;
+	int prio; /* annotated tag = 2, tag = 1, head = 0 */
+	char path[FLEX_ARRAY]; /* more */
+} **name_array = NULL;
+
+static struct commit_name *match(struct commit *cmit)
+{
+	int i = names;
+	struct commit_name **p = name_array;
+
+	while (i-- > 0) {
+		struct commit_name *n = *p++;
+		if (n->commit == cmit)
+			return n;
+	}
+	return NULL;
+}
+
+static void add_to_known_names(const char *path,
+			       const struct commit *commit,
+			       int prio)
+{
+	int idx;
+	int len = strlen(path)+1;
+	struct commit_name *name = xmalloc(sizeof(struct commit_name) + len);
+
+	name->commit = commit;
+	name->prio = prio; 
+	memcpy(name->path, path, len);
+	idx = names;
+	if (idx >= allocs) {
+		allocs = (idx + 50) * 3 / 2;
+		name_array = xrealloc(name_array, allocs*sizeof(*name_array));
+	}
+	name_array[idx] = name;
+	names = ++idx;
+}
+
+static int get_name(const char *path, const unsigned char *sha1)
+{
+	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
+	struct object *object;
+	int prio;
+
+	if (!commit)
+		return 0;
+	object = parse_object(sha1);
+	/* If --all, then any refs are used.
+	 * If --tags, then any tags are used.
+	 * Otherwise only annotated tags are used.
+	 */
+	if (!strncmp(path, "refs/tags/", 10)) {
+		if (object->type == tag_type)
+			prio = 2;
+		else
+			prio = 1;
+	}
+	else
+		prio = 0;
+
+	if (!all) {
+		if (!prio)
+			return 0;
+		if (!tags && prio < 2)
+			return 0;
+	}
+	add_to_known_names(all ? path + 5 : path + 10, commit, prio);
+	return 0;
+}
+
+static int compare_names(const void *_a, const void *_b)
+{
+	struct commit_name *a = *(struct commit_name **)_a;
+	struct commit_name *b = *(struct commit_name **)_b;
+	unsigned long a_date = a->commit->date;
+	unsigned long b_date = b->commit->date;
+
+	if (a->prio != b->prio)
+		return b->prio - a->prio;
+	return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
+}
+
+static void describe(struct commit *cmit, int last_one)
+{
+	struct commit_list *list;
+	static int initialized = 0;
+	struct commit_name *n;
+
+	if (!initialized) {
+		initialized = 1;
+		for_each_ref(get_name);
+		qsort(name_array, names, sizeof(*name_array), compare_names);
+	}
+
+	n = match(cmit);
+	if (n) {
+		printf("%s\n", n->path);
+		return;
+	}
+
+	list = NULL;
+	commit_list_insert(cmit, &list);
+	while (list) {
+		struct commit *c = pop_most_recent_commit(&list, SEEN);
+		n = match(c);
+		if (n) {
+			printf("%s-g%s\n", n->path,
+			       find_unique_abbrev(cmit->object.sha1, abbrev));
+			if (!last_one)
+				clear_commit_marks(cmit, SEEN);
+			return;
+		}
+	}
+	die("cannot describe '%s'", sha1_to_hex(cmit->object.sha1));
+}
+
+int main(int argc, char **argv)
+{
+	int i;
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		unsigned char sha1[20];
+		struct commit *cmit;
+
+		if (!strcmp(arg, "--all")) {
+			all = 1;
+			continue;
+		}
+		if (!strcmp(arg, "--tags")) {
+			tags = 1;
+			continue;
+		}
+		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)
+			usage(describe_usage);
+		cmit = lookup_commit_reference(sha1);
+		if (!cmit)
+			usage(describe_usage);
+		describe(cmit, i == argc - 1);
+	}
+	return 0;
+}
diff --git a/environment.c b/environment.c
index 0886ad3..0596fc6 100644
--- a/environment.c
+++ b/environment.c
@@ -15,6 +15,7 @@
 int only_use_symrefs = 0;
 int repository_format_version = 0;
 char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
+int shared_repository = 0;
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
 	*git_graft_file;
diff --git a/git-checkout.sh b/git-checkout.sh
index 36308d2..3bbd111 100755
--- a/git-checkout.sh
+++ b/git-checkout.sh
@@ -1,6 +1,7 @@
 #!/bin/sh
 
 USAGE='[-f] [-b <new_branch>] [<branch>] [<paths>...]'
+SUBDIRECTORY_OK=Sometimes
 . git-sh-setup
 
 old=$(git-rev-parse HEAD)
@@ -79,7 +80,7 @@
 		# from a specific tree-ish; note that this is for
 		# rescuing paths and is never meant to remove what
 		# is not in the named tree-ish.
-		git-ls-tree -r "$new" "$@" |
+		git-ls-tree --full-name -r "$new" "$@" |
 		git-update-index --index-info || exit $?
 	fi
 	git-checkout-index -f -u -- "$@"
@@ -95,6 +96,14 @@
 	fi
 fi
 
+# We are switching branches and checking out trees, so
+# we *NEED* to be at the toplevel.
+cdup=$(git-rev-parse --show-cdup)
+if test ! -z "$cdup"
+then
+	cd "$cdup"
+fi
+
 [ -z "$new" ] && new=$old
 
 # If we don't have an old branch that we're switching to,
diff --git a/git-cherry.sh b/git-cherry.sh
index 5e9bd0c..1a62320 100755
--- a/git-cherry.sh
+++ b/git-cherry.sh
@@ -3,17 +3,17 @@
 # Copyright (c) 2005 Junio C Hamano.
 #
 
-USAGE='[-v] <upstream> [<head>]'
+USAGE='[-v] <upstream> [<head>] [<limit>]'
 LONG_USAGE='             __*__*__*__*__> <upstream>
             /
   fork-point
             \__+__+__+__+__+__+__+__> <head>
 
-Each commit between the fork-point and <head> is examined, and
-compared against the change each commit between the fork-point and
-<upstream> introduces.  If the change seems to be in the upstream,
-it is shown on the standard output with prefix "+".  Otherwise
-it is shown with prefix "-".'
+Each commit between the fork-point (or <limit> if given) and <head> is
+examined, and compared against the change each commit between the
+fork-point and <upstream> introduces.  If the change seems to be in
+the upstream, it is shown on the standard output with prefix "+".
+Otherwise it is shown with prefix "-".'
 . git-sh-setup
 
 case "$1" in -v) verbose=t; shift ;; esac 
@@ -28,9 +28,15 @@
 case "$#" in
 1) upstream=`git-rev-parse --verify "$1"` &&
    ours=`git-rev-parse --verify HEAD` || exit
+   limit="$upstream"
    ;;
 2) upstream=`git-rev-parse --verify "$1"` &&
    ours=`git-rev-parse --verify "$2"` || exit
+   limit="$upstream"
+   ;;
+3) upstream=`git-rev-parse --verify "$1"` &&
+   ours=`git-rev-parse --verify "$2"` &&
+   limit=`git-rev-parse --verify "$3"` || exit
    ;;
 *) usage ;;
 esac
@@ -38,7 +44,7 @@
 # Note that these list commits in reverse order;
 # not that the order in inup matters...
 inup=`git-rev-list ^$ours $upstream` &&
-ours=`git-rev-list $ours ^$upstream` || exit
+ours=`git-rev-list $ours ^$limit` || exit
 
 tmp=.cherry-tmp$$
 patch=$tmp-patch
diff --git a/git-clone.sh b/git-clone.sh
index 280cc2e..377d59e 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>] [-n] <repo> [<dir>]"
+	echo >&2 "Usage: $0 [-l [-s]] [-q] [-u <upload-pack>] [-o <name>] [-n] <repo> [<dir>]"
 	exit 1
 }
 
@@ -31,25 +31,11 @@
 	cd "$2" &&
 	clone_tmp='.git/clone-tmp' &&
 	mkdir -p "$clone_tmp" || exit 1
-	http_fetch "$1/info/refs" "$clone_tmp/refs" &&
-	http_fetch "$1/objects/info/packs" "$clone_tmp/packs" || {
+	http_fetch "$1/info/refs" "$clone_tmp/refs" || {
 		echo >&2 "Cannot get remote repository information.
 Perhaps git-update-server-info needs to be run there?"
 		exit 1;
 	}
-	while read type name
-	do
-		case "$type" in
-		P) ;;
-		*) continue ;;
-		esac &&
-
-		idx=`expr "$name" : '\(.*\)\.pack'`.idx
-		http_fetch "$1/objects/pack/$name" ".git/objects/pack/$name" &&
-		http_fetch "$1/objects/pack/$idx" ".git/objects/pack/$idx" &&
-		git-verify-pack ".git/objects/pack/$idx" || exit 1
-	done <"$clone_tmp/packs"
-
 	while read sha1 refname
 	do
 		name=`expr "$refname" : 'refs/\(.*\)'` &&
@@ -67,6 +53,7 @@
 local_shared=no
 no_checkout=
 upload_pack=
+origin=origin
 while
 	case "$#,$1" in
 	0,*) break ;;
@@ -75,6 +62,14 @@
         *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) 
           local_shared=yes; use_local=yes ;;
 	*,-q|*,--quiet) quiet=-q ;;
+	1,-o) usage;;
+	*,-o)
+		git-check-ref-format "$2" || {
+		    echo >&2 "'$2' is not suitable for a branch name"
+		    exit 1
+		}
+		origin="$2"; shift
+		;;
 	1,-u|1,--upload-pack) usage ;;
 	*,-u|*,--upload-pack)
 		shift
@@ -208,14 +203,14 @@
 		mkdir -p .git/remotes &&
 		echo >.git/remotes/origin \
 		"URL: $repo
-Pull: $head_points_at:origin" &&
-		cp ".git/refs/heads/$head_points_at" .git/refs/heads/origin &&
+Pull: $head_points_at:$origin" &&
+		git-update-ref "refs/heads/$origin" $(git-rev-parse HEAD) &&
 		find .git/refs/heads -type f -print |
 		while read ref
 		do
 			head=`expr "$ref" : '.git/refs/heads/\(.*\)'` &&
 			test "$head_points_at" = "$head" ||
-			test "origin" = "$head" ||
+			test "$origin" = "$head" ||
 			echo "Pull: ${head}:${head}"
 		done >>.git/remotes/origin
 	esac
diff --git a/git-fetch.sh b/git-fetch.sh
index b46b3e5..73e57bd 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -11,6 +11,7 @@
 '
 IFS="$LF"
 
+no_tags=
 tags=
 append=
 force=
@@ -28,6 +29,9 @@
 	-t|--t|--ta|--tag|--tags)
 		tags=t
 		;;
+	-n|--n|--no|--no-|--no-t|--no-ta|--no-tag|--no-tags)
+		no_tags=t
+		;;
 	-u|--u|--up|--upd|--upda|--updat|--update|--update-|--update-h|\
 	--update-he|--update-hea|--update-head|--update-head-|\
 	--update-head-o|--update-head-ok)
@@ -212,133 +216,166 @@
 	fi
 fi
 
-for ref in $reflist
-do
-    refs="$refs$LF$ref"
+fetch_main () {
+  reflist="$1"
+  refs=
 
-    # These are relative path from $GIT_DIR, typically starting at refs/
-    # but may be HEAD
-    if expr "$ref" : '\.' >/dev/null
-    then
-	not_for_merge=t
-	ref=$(expr "$ref" : '\.\(.*\)')
-    else
-	not_for_merge=
-    fi
-    if expr "$ref" : '\+' >/dev/null
-    then
-	single_force=t
-	ref=$(expr "$ref" : '\+\(.*\)')
-    else
-	single_force=
-    fi
-    remote_name=$(expr "$ref" : '\([^:]*\):')
-    local_name=$(expr "$ref" : '[^:]*:\(.*\)')
+  for ref in $reflist
+  do
+      refs="$refs$LF$ref"
 
-    rref="$rref$LF$remote_name"
+      # These are relative path from $GIT_DIR, typically starting at refs/
+      # but may be HEAD
+      if expr "$ref" : '\.' >/dev/null
+      then
+	  not_for_merge=t
+	  ref=$(expr "$ref" : '\.\(.*\)')
+      else
+	  not_for_merge=
+      fi
+      if expr "$ref" : '\+' >/dev/null
+      then
+	  single_force=t
+	  ref=$(expr "$ref" : '\+\(.*\)')
+      else
+	  single_force=
+      fi
+      remote_name=$(expr "$ref" : '\([^:]*\):')
+      local_name=$(expr "$ref" : '[^:]*:\(.*\)')
 
-    # There are transports that can fetch only one head at a time...
-    case "$remote" in
-    http://* | https://*)
-	if [ -n "$GIT_SSL_NO_VERIFY" ]; then
-	    curl_extra_args="-k"
-	fi
-	remote_name_quoted=$(perl -e '
-	    my $u = $ARGV[0];
-	    $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg;
-	    print "$u";
-	' "$remote_name")
-	head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted") &&
-	expr "$head" : "$_x40\$" >/dev/null ||
-		die "Failed to fetch $remote_name from $remote"
-	echo >&2 Fetching "$remote_name from $remote" using http
-	git-http-fetch -v -a "$head" "$remote/" || exit
-	;;
-    rsync://*)
-	TMP_HEAD="$GIT_DIR/TMP_HEAD"
-	rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
-	head=$(git-rev-parse --verify TMP_HEAD)
-	rm -f "$TMP_HEAD"
-	test "$rsync_slurped_objects" || {
-	    rsync -av --ignore-existing --exclude info \
-		"$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
+      rref="$rref$LF$remote_name"
 
-	    # 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 "$remote/objects/info/alternates" \
-		"$GIT_DIR/TMP_ALT" 2>/dev/null ||
-		rm -f "$GIT_DIR/TMP_ALT"
-	    if test -f "$GIT_DIR/TMP_ALT"
-	    then
-		resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" |
-		while read alt
-		do
-		    case "$alt" in 'bad alternate: '*) die "$alt";; esac
-		    echo >&2 "Getting alternate: $alt"
-		    rsync -av --ignore-existing --exclude info \
-		    "$alt" "$GIT_OBJECT_DIRECTORY/" || exit
-		done
-		rm -f "$GIT_DIR/TMP_ALT"
-	    fi
-	    rsync_slurped_objects=t
-	}
-	;;
-    *)
-	# We will do git native transport with just one call later.
-	continue ;;
-    esac
+      # There are transports that can fetch only one head at a time...
+      case "$remote" in
+      http://* | https://*)
+	  if [ -n "$GIT_SSL_NO_VERIFY" ]; then
+	      curl_extra_args="-k"
+	  fi
+	  remote_name_quoted=$(perl -e '
+	      my $u = $ARGV[0];
+	      $u =~ s{([^-a-zA-Z0-9/.])}{sprintf"%%%02x",ord($1)}eg;
+	      print "$u";
+	  ' "$remote_name")
+	  head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted") &&
+	  expr "$head" : "$_x40\$" >/dev/null ||
+		  die "Failed to fetch $remote_name from $remote"
+	  echo >&2 Fetching "$remote_name from $remote" using http
+	  git-http-fetch -v -a "$head" "$remote/" || exit
+	  ;;
+      rsync://*)
+	  TMP_HEAD="$GIT_DIR/TMP_HEAD"
+	  rsync -L -q "$remote/$remote_name" "$TMP_HEAD" || exit 1
+	  head=$(git-rev-parse --verify TMP_HEAD)
+	  rm -f "$TMP_HEAD"
+	  test "$rsync_slurped_objects" || {
+	      rsync -av --ignore-existing --exclude info \
+		  "$remote/objects/" "$GIT_OBJECT_DIRECTORY/" || exit
 
-    append_fetch_head "$head" "$remote" \
-    	"$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
+	      # 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 "$remote/objects/info/alternates" \
+		  "$GIT_DIR/TMP_ALT" 2>/dev/null ||
+		  rm -f "$GIT_DIR/TMP_ALT"
+	      if test -f "$GIT_DIR/TMP_ALT"
+	      then
+		  resolve_alternates "$remote" <"$GIT_DIR/TMP_ALT" |
+		  while read alt
+		  do
+		      case "$alt" in 'bad alternate: '*) die "$alt";; esac
+		      echo >&2 "Getting alternate: $alt"
+		      rsync -av --ignore-existing --exclude info \
+		      "$alt" "$GIT_OBJECT_DIRECTORY/" || exit
+		  done
+		  rm -f "$GIT_DIR/TMP_ALT"
+	      fi
+	      rsync_slurped_objects=t
+	  }
+	  ;;
+      *)
+	  # We will do git native transport with just one call later.
+	  continue ;;
+      esac
 
-done
+      append_fetch_head "$head" "$remote" \
+	  "$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
 
-case "$remote" in
-http://* | https://* | rsync://* )
-    ;; # we are already done.
-*)
-    IFS=" 	$LF"
-    (
-	git-fetch-pack "$remote" $rref || echo failed "$remote"
-    ) |
-    while read sha1 remote_name
-    do
-	case "$sha1" in
-	failed)
-		echo >&2 "Fetch failure: $remote"
-		exit 1 ;;
-	esac
-	found=
-	single_force=
-	for ref in $refs
+  done
+
+  case "$remote" in
+  http://* | https://* | rsync://* )
+      ;; # we are already done.
+  *)
+    ( : subshell because we muck with IFS
+      IFS=" 	$LF"
+      (
+	  git-fetch-pack "$remote" $rref || echo failed "$remote"
+      ) |
+      while read sha1 remote_name
+      do
+	  case "$sha1" in
+	  failed)
+		  echo >&2 "Fetch failure: $remote"
+		  exit 1 ;;
+	  esac
+	  found=
+	  single_force=
+	  for ref in $refs
+	  do
+	      case "$ref" in
+	      +$remote_name:*)
+		  single_force=t
+		  not_for_merge=
+		  found="$ref"
+		  break ;;
+	      .+$remote_name:*)
+		  single_force=t
+		  not_for_merge=t
+		  found="$ref"
+		  break ;;
+	      .$remote_name:*)
+		  not_for_merge=t
+		  found="$ref"
+		  break ;;
+	      $remote_name:*)
+		  not_for_merge=
+		  found="$ref"
+		  break ;;
+	      esac
+	  done
+	  local_name=$(expr "$found" : '[^:]*:\(.*\)')
+	  append_fetch_head "$sha1" "$remote" \
+		  "$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
+      done
+    ) || exit ;;
+  esac
+
+}
+
+fetch_main "$reflist"
+
+# automated tag following
+case "$no_tags$tags" in
+'')
+	taglist=$(IFS=" " &&
+    	git-ls-remote --tags "$remote" |
+	sed -ne 's|^\([0-9a-f]*\)[ 	]\(refs/tags/.*\)^{}$|\1 \2|p' |
+	while read sha1 name
 	do
-	    case "$ref" in
-	    +$remote_name:*)
-		single_force=t
-		not_for_merge=
-		found="$ref"
-		break ;;
-	    .+$remote_name:*)
-		single_force=t
-		not_for_merge=t
-		found="$ref"
-		break ;;
-	    .$remote_name:*)
-	        not_for_merge=t
-		found="$ref"
-		break ;;
-	    $remote_name:*)
-	    	not_for_merge=
-		found="$ref"
-		break ;;
-	    esac
-	done
-	local_name=$(expr "$found" : '[^:]*:\(.*\)')
-	append_fetch_head "$sha1" "$remote" \
-		"$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
-    done || exit
-    ;;
+		test -f "$GIT_DIR/$name" && continue
+	  	git-check-ref-format "$name" || {
+			echo >&2 "warning: tag ${name} ignored"
+			continue
+		}
+		git-cat-file -t "$sha1" >/dev/null 2>&1 || continue
+		echo >&2 "Auto-following $name"
+		echo ".${name}:${name}"
+	done)
+	case "$taglist" in
+	'') ;;
+	?*)
+		fetch_main "$taglist" ;;
+	esac
 esac
 
 # If the original head was empty (i.e. no "master" yet), or
diff --git a/git-merge-recursive.py b/git-merge-recursive.py
index f1320a6..56c3641 100755
--- a/git-merge-recursive.py
+++ b/git-merge-recursive.py
@@ -283,12 +283,20 @@
 def setIndexStages(path,
                    oSHA1, oMode,
                    aSHA1, aMode,
-                   bSHA1, bMode):
+                   bSHA1, bMode,
+                   clear=True):
+    istring = []
+    if clear:
+        istring.append("0 " + ("0" * 40) + "\t" + path + "\0")
+    if oMode:
+        istring.append("%o %s %d\t%s\0" % (oMode, oSHA1, 1, path))
+    if aMode:
+        istring.append("%o %s %d\t%s\0" % (aMode, aSHA1, 2, path))
+    if bMode:
+        istring.append("%o %s %d\t%s\0" % (bMode, bSHA1, 3, path))
+
     runProgram(['git-update-index', '-z', '--index-info'],
-               input="0 " + ("0" * 40) + "\t" + path + "\0" + \
-               "%o %s %d\t%s\0" % (oMode, oSHA1, 1, path) + \
-               "%o %s %d\t%s\0" % (aMode, aSHA1, 2, path) + \
-               "%o %s %d\t%s\0" % (bMode, bSHA1, 3, path))
+               input="".join(istring))
 
 def removeFile(clean, path):
     updateCache = cacheOnly or clean
@@ -570,7 +578,7 @@
             continue
 
         ren1.processed = True
-        removeFile(True, ren1.srcName)
+
         if ren2:
             # Renamed in 1 and renamed in 2
             assert(ren1.srcName == ren2.srcName)
@@ -598,13 +606,19 @@
                            'adding as', dstName2, 'instead.')
                     removeFile(False, ren2.dstName)
                 else:
-                    dstName2 = ren1.dstName
+                    dstName2 = ren2.dstName
+                setIndexStages(dstName1,
+                               None, None,
+                               ren1.dstSha, ren1.dstMode,
+			       None, None)
+                setIndexStages(dstName2,
+                               None, None,
+                               None, None,
+                               ren2.dstSha, ren2.dstMode)
 
-                # NEEDSWORK: place dstNameA at stage 2 and dstNameB at stage 3
-                # What about other stages???
-                updateFile(False, ren1.dstSha, ren1.dstMode, dstName1)
-                updateFile(False, ren2.dstSha, ren2.dstMode, dstName2)
             else:
+                removeFile(True, ren1.srcName)
+
                 [resSha, resMode, clean, merge] = \
                          mergeFile(ren1.srcName, ren1.srcSha, ren1.srcMode,
                                    ren1.dstName, ren1.dstSha, ren1.dstMode,
@@ -630,6 +644,8 @@
 
                 updateFile(clean, resSha, resMode, ren1.dstName)
         else:
+            removeFile(True, ren1.srcName)
+
             # Renamed in 1, maybe changed in 2
             if renamesA == renames1:
                 stage = 3
diff --git a/git-status.sh b/git-status.sh
index 50ccd24..10d781c 100755
--- a/git-status.sh
+++ b/git-status.sh
@@ -83,11 +83,11 @@
 
 if test -f "$GIT_DIR/info/exclude"
 then
-    git-ls-files -z --others \
+    git-ls-files -z --others --directory \
 	--exclude-from="$GIT_DIR/info/exclude" \
         --exclude-per-directory=.gitignore
 else
-    git-ls-files -z --others \
+    git-ls-files -z --others --directory \
         --exclude-per-directory=.gitignore
 fi |
 perl -e '$/ = "\0";
diff --git a/git-whatchanged.sh b/git-whatchanged.sh
index b170f74..80e2500 100755
--- a/git-whatchanged.sh
+++ b/git-whatchanged.sh
@@ -4,9 +4,15 @@
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
 
+diff_tree_flags=$(git-rev-parse --sq --no-revs --flags "$@")
+test -z "$diff_tree_flags" &&
+	diff_tree_flags=$(git-repo-config --get whatchanged.difftree)
+test -z "$diff_tree_flags" &&
+	diff_tree_flags='-M --abbrev'
+
 rev_list_args=$(git-rev-parse --sq --default HEAD --revs-only "$@") &&
-diff_tree_args=$(git-rev-parse --sq --no-revs "$@") &&
+diff_tree_args=$(git-rev-parse --sq --no-revs --no-flags "$@") &&
 
 eval "git-rev-list $rev_list_args" |
-eval "git-diff-tree --stdin --pretty -r $diff_tree_args" |
+eval "git-diff-tree --stdin --pretty -r $diff_tree_flags $diff_tree_args" |
 LESS="$LESS -S" ${PAGER:-less}
diff --git a/init-db.c b/init-db.c
index ead37b5..ff29496 100644
--- a/init-db.c
+++ b/init-db.c
@@ -9,7 +9,7 @@
 #define DEFAULT_GIT_TEMPLATE_DIR "/usr/share/git-core/templates/"
 #endif
 
-static void safe_create_dir(const char *dir)
+static void safe_create_dir(const char *dir, int share)
 {
 	if (mkdir(dir, 0777) < 0) {
 		if (errno != EEXIST) {
@@ -17,6 +17,8 @@
 			exit(1);
 		}
 	}
+	else if (share && adjust_shared_perm(dir))
+		die("Could not make %s writable by group\n", dir);
 }
 
 static int copy_file(const char *dst, const char *src, int mode)
@@ -32,6 +34,10 @@
 	}
 	status = copy_fd(fdi, fdo);
 	close(fdo);
+
+	if (!status && adjust_shared_perm(dst))
+		return -1;
+
 	return status;
 }
 
@@ -48,7 +54,7 @@
 	 * with the way the namespace under .git/ is organized, should
 	 * be really carefully chosen.
 	 */
-	safe_create_dir(path);
+	safe_create_dir(path, 1);
 	while ((de = readdir(dir)) != NULL) {
 		struct stat st_git, st_template;
 		int namelen;
@@ -176,11 +182,11 @@
 	 * Create .git/refs/{heads,tags}
 	 */
 	strcpy(path + len, "refs");
-	safe_create_dir(path);
+	safe_create_dir(path, 1);
 	strcpy(path + len, "refs/heads");
-	safe_create_dir(path);
+	safe_create_dir(path, 1);
 	strcpy(path + len, "refs/tags");
-	safe_create_dir(path);
+	safe_create_dir(path, 1);
 
 	/* First copy the templates -- we might have the default
 	 * config file there, in which case we would want to read
@@ -220,7 +226,7 @@
 }
 
 static const char init_db_usage[] =
-"git-init-db [--template=<template-directory>]";
+"git-init-db [--template=<template-directory>] [--shared]";
 
 /*
  * If you want to, you can share the DB area with any number of branches.
@@ -239,6 +245,8 @@
 		char *arg = argv[1];
 		if (!strncmp(arg, "--template=", 11))
 			template_dir = arg+11;
+		else if (!strcmp(arg, "--shared"))
+			shared_repository = 1;
 		else
 			die(init_db_usage);
 	}
@@ -251,7 +259,7 @@
 		git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
 		fprintf(stderr, "defaulting to local storage area\n");
 	}
-	safe_create_dir(git_dir);
+	safe_create_dir(git_dir, 0);
 
 	/* Check to see if the repository version is right.
 	 * Note that a newly created repository does not have
@@ -270,10 +278,14 @@
 	path = xmalloc(len + 40);
 	memcpy(path, sha1_dir, len);
 
-	safe_create_dir(sha1_dir);
+	safe_create_dir(sha1_dir, 1);
 	strcpy(path+len, "/pack");
-	safe_create_dir(path);
+	safe_create_dir(path, 1);
 	strcpy(path+len, "/info");
-	safe_create_dir(path);
+	safe_create_dir(path, 1);
+
+	if (shared_repository)
+		git_config_set("core.sharedRepository", "true");
+
 	return 0;
 }
diff --git a/ls-files.c b/ls-files.c
index 74ec8c0..6af3b09 100644
--- a/ls-files.c
+++ b/ls-files.c
@@ -19,6 +19,7 @@
 static int show_unmerged = 0;
 static int show_modified = 0;
 static int show_killed = 0;
+static int show_other_directories = 0;
 static int line_terminator = '\n';
 
 static int prefix_len = 0, prefix_offset = 0;
@@ -233,6 +234,17 @@
 	dir[nr_dir++] = ent;
 }
 
+static int dir_exists(const char *dirname, int len)
+{
+	int pos = cache_name_pos(dirname, len);
+	if (pos >= 0)
+		return 1;
+	pos = -pos-1;
+	if (pos >= active_nr) /* can't */
+		return 0;
+	return !strncmp(active_cache[pos]->name, dirname, len);
+}
+
 /*
  * Read a directory tree. We currently ignore anything but
  * directories, regular files and symlinks. That's because git
@@ -281,8 +293,12 @@
 				/* fallthrough */
 			case DT_DIR:
 				memcpy(fullname + baselen + len, "/", 2);
+				len++;
+				if (show_other_directories &&
+				    !dir_exists(fullname, baselen + len))
+					break;
 				read_directory(fullname, fullname,
-					       baselen + len + 1);
+					       baselen + len);
 				continue;
 			case DT_REG:
 			case DT_LNK:
@@ -622,6 +638,10 @@
 			show_killed = 1;
 			continue;
 		}
+		if (!strcmp(arg, "--directory")) {
+			show_other_directories = 1;
+			continue;
+		}
 		if (!strcmp(arg, "-u") || !strcmp(arg, "--unmerged")) {
 			/* There's no point in showing unmerged unless
 			 * you also show the stage information.
diff --git a/ls-tree.c b/ls-tree.c
index dae377d..d585b6f 100644
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -15,9 +15,11 @@
 #define LS_NAME_ONLY 8
 static int ls_options = 0;
 const char **pathspec;
+static int chomp_prefix = 0;
+static const char *prefix;
 
 static const char ls_tree_usage[] =
-	"git-ls-tree [-d] [-r] [-t] [-z] [--name-only] [--name-status] <tree-ish> [path...]";
+	"git-ls-tree [-d] [-r] [-t] [-z] [--name-only] [--name-status] [--full-name] <tree-ish> [path...]";
 
 static int show_recursive(const char *base, int baselen, const char *pathname)
 {
@@ -49,7 +51,8 @@
 	}
 }
 
-static int show_tree(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)
+static int show_tree(unsigned char *sha1, const char *base, int baselen,
+		     const char *pathname, unsigned mode, int stage)
 {
 	int retval = 0;
 	const char *type = "blob";
@@ -65,21 +68,28 @@
 	else if (ls_options & LS_TREE_ONLY)
 		return 0;
 
+	if (chomp_prefix &&
+	    (baselen < chomp_prefix || memcmp(prefix, base, chomp_prefix)))
+		return 0;
+
 	if (!(ls_options & LS_NAME_ONLY))
 		printf("%06o %s %s\t", mode, type, sha1_to_hex(sha1));
-	write_name_quoted(base, baselen, pathname, line_termination, stdout);
+	write_name_quoted(base + chomp_prefix, baselen - chomp_prefix,
+			  pathname,
+			  line_termination, stdout);
 	putchar(line_termination);
 	return retval;
 }
 
 int main(int argc, const char **argv)
 {
-	const char *prefix;
 	unsigned char sha1[20];
 	char *buf;
 	unsigned long size;
 
 	prefix = setup_git_directory();
+	if (prefix && *prefix)
+		chomp_prefix = strlen(prefix);
 	while (1 < argc && argv[1][0] == '-') {
 		switch (argv[1][1]) {
 		case 'z':
@@ -100,6 +110,10 @@
 				ls_options |= LS_NAME_ONLY;
 				break;
 			}
+			if (!strcmp(argv[1]+2, "full-name")) {
+				chomp_prefix = 0;
+				break;
+			}
 			/* otherwise fallthru */
 		default:
 			usage(ls_tree_usage);
diff --git a/pack-redundant.c b/pack-redundant.c
index 0a43278..1869b38 100644
--- a/pack-redundant.c
+++ b/pack-redundant.c
@@ -8,6 +8,8 @@
 
 #include "cache.h"
 
+#define BLKSIZE 512
+
 static const char pack_redundant_usage[] =
 "git-pack-redundant [ --verbose ] [ --alt-odb ] < --all | <.pack filename> ...>";
 
@@ -33,29 +35,32 @@
 struct pll {
 	struct pll *next;
 	struct pack_list *pl;
-	size_t pl_size;
 };
 
 static struct llist_item *free_nodes = NULL;
 
+static inline void llist_item_put(struct llist_item *item)
+{
+	item->next = free_nodes;
+	free_nodes = item;
+}
+
 static inline struct llist_item *llist_item_get()
 {
 	struct llist_item *new;
 	if ( free_nodes ) {
 		new = free_nodes;
 		free_nodes = free_nodes->next;
-	} else
-		new = xmalloc(sizeof(struct llist_item));
-
+	} else {
+		int i = 1;
+		new = xmalloc(sizeof(struct llist_item) * BLKSIZE);
+		for(;i < BLKSIZE; i++) {
+			llist_item_put(&new[i]);
+		}
+	}
 	return new;
 }
 
-static inline void llist_item_put(struct llist_item *item)
-{
-	item->next = free_nodes;
-	free_nodes = item;
-}
-
 static void llist_free(struct llist *list)
 {
 	while((list->back = list->front)) {
@@ -270,77 +275,58 @@
 	}
 }
 
-static void pll_insert(struct pll **pll, struct pll **hint_table)
+void pll_free(struct pll *l)
 {
-	struct pll *prev;
-	int i = (*pll)->pl_size - 1;
+	struct pll *old;
+	struct pack_list *opl;
 
-	if (hint_table[i] == NULL) {
-		hint_table[i--] = *pll;
-		for (; i >= 0; --i) {
-			if (hint_table[i] != NULL)
-				break;
+	while (l) {
+		old = l;
+		while (l->pl) {
+			opl = l->pl;
+			l->pl = opl->next;
+			free(opl);
 		}
-		if (hint_table[i] == NULL) /* no elements in list */
-			die("Why did this happen?");
+		l = l->next;
+		free(old);
 	}
-
-	prev = hint_table[i];
-	while (prev->next && prev->next->pl_size < (*pll)->pl_size)
-		prev = prev->next;
-
-	(*pll)->next = prev->next;
-	prev->next = *pll;
 }
 
 /* all the permutations have to be free()d at the same time,
  * since they refer to each other
  */
-static struct pll * get_all_permutations(struct pack_list *list)
+static struct pll * get_permutations(struct pack_list *list, int n)
 {
-	struct pll *subset, *pll, *new_pll = NULL; /*silence warning*/
-	static struct pll **hint = NULL;
-	if (hint == NULL)
-		hint = xcalloc(pack_list_size(list), sizeof(struct pll *));
-		
-	if (list == NULL)
+	struct pll *subset, *ret = NULL, *new_pll = NULL, *pll;
+
+	if (list == NULL || pack_list_size(list) < n || n == 0)
 		return NULL;
 
-	if (list->next == NULL) {
-		new_pll = xmalloc(sizeof(struct pll));
-		hint[0] = new_pll;
-		new_pll->next = NULL;
-		new_pll->pl = list;
-		new_pll->pl_size = 1;
-		return new_pll;
-	}
-
-	pll = subset = get_all_permutations(list->next);
-	while (pll) {
-		if (pll->pl->pack == list->pack) {
-			pll = pll->next;
-			continue;
+	if (n == 1) {
+		while (list) {
+			new_pll = xmalloc(sizeof(pll));
+			new_pll->pl = NULL;
+			pack_list_insert(&new_pll->pl, list);
+			new_pll->next = ret;
+			ret = new_pll;
+			list = list->next;
 		}
-		new_pll = xmalloc(sizeof(struct pll));
-
-		new_pll->pl = xmalloc(sizeof(struct pack_list));
-		memcpy(new_pll->pl, list, sizeof(struct pack_list));
-		new_pll->pl->next = pll->pl;
-		new_pll->pl_size = pll->pl_size + 1;
-		
-		pll_insert(&new_pll, hint);
-
-		pll = pll->next;
+		return ret;
 	}
-	/* add ourself */
-	new_pll = xmalloc(sizeof(struct pll));
-	new_pll->pl = xmalloc(sizeof(struct pack_list));
-	memcpy(new_pll->pl, list, sizeof(struct pack_list));
-	new_pll->pl->next = NULL;
-	new_pll->pl_size = 1;
-	pll_insert(&new_pll, hint);
 
-	return hint[0];
+	while (list->next) {
+		subset = get_permutations(list->next, n - 1);
+		while (subset) {
+			new_pll = xmalloc(sizeof(pll));
+			new_pll->pl = subset->pl;
+			pack_list_insert(&new_pll->pl, list);
+			new_pll->next = ret;
+			ret = new_pll;
+			subset = subset->next;
+		}
+		list = list->next;
+	}
+	return ret;
 }
 
 static int is_superset(struct pack_list *pl, struct llist *list)
@@ -428,6 +414,7 @@
 	struct pll *perm, *perm_all, *perm_ok = NULL, *new_perm;
 	struct llist *missing;
 	size_t min_perm_size = (size_t)-1, perm_size;
+	int n;
 
 	pl = local_packs;
 	while (pl) {
@@ -441,8 +428,7 @@
 	missing = llist_copy(all_objects);
 	pl = unique;
 	while (pl) {
-		llist_sorted_difference_inplace(missing,
-						pl->all_objects);
+		llist_sorted_difference_inplace(missing, pl->all_objects);
 		pl = pl->next;
 	}
 
@@ -453,19 +439,21 @@
 	}
 
 	/* find the permutations which contain all missing objects */
-	perm_all = perm = get_all_permutations(non_unique);
-	while (perm) {
-		if (perm_ok && perm->pl_size > perm_ok->pl_size)
-			break; /* ignore all larger permutations */
-		if (is_superset(perm->pl, missing)) {
-			new_perm = xmalloc(sizeof(struct pll));
-			memcpy(new_perm, perm, sizeof(struct pll));
-			new_perm->next = perm_ok;
-			perm_ok = new_perm;
+	for (n = 1; n <= pack_list_size(non_unique) && !perm_ok; n++) {
+		perm_all = perm = get_permutations(non_unique, n);
+		while (perm) {
+			if (is_superset(perm->pl, missing)) {
+				new_perm = xmalloc(sizeof(struct pll));
+				memcpy(new_perm, perm, sizeof(struct pll));
+				new_perm->next = perm_ok;
+				perm_ok = new_perm;
+			}
+			perm = perm->next;
 		}
-		perm = perm->next;
+		if (perm_ok)
+			break;
+		pll_free(perm_all);
 	}
-	
 	if (perm_ok == NULL)
 		die("Internal error: No complete sets found!\n");
 
@@ -537,6 +525,7 @@
 							alt->all_objects);
 			local = local->next;
 		}
+		llist_sorted_difference_inplace(all_objects, alt->all_objects);
 		alt = alt->next;
 	}
 }
diff --git a/receive-pack.c b/receive-pack.c
index ce986fe..f847ec2 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -8,20 +8,33 @@
 
 static const char unpacker[] = "git-unpack-objects";
 
+static int report_status = 0;
+
+static char capabilities[] = "report-status";
+static int capabilities_sent = 0;
+
 static int show_ref(const char *path, const unsigned char *sha1)
 {
-	packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
+	if (capabilities_sent)
+		packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
+	else
+		packet_write(1, "%s %s%c%s\n",
+			     sha1_to_hex(sha1), path, 0, capabilities);
+	capabilities_sent = 1;
 	return 0;
 }
 
 static void write_head_info(void)
 {
 	for_each_ref(show_ref);
+	if (!capabilities_sent)
+		show_ref("capabilities^{}", null_sha1);
+
 }
 
 struct command {
 	struct command *next;
-	unsigned char updated;
+	const char *error_string;
 	unsigned char old_sha1[20];
 	unsigned char new_sha1[20];
 	char ref_name[FLEX_ARRAY]; /* more */
@@ -71,33 +84,37 @@
 	case 0:
 		return 0;
 	case -ERR_RUN_COMMAND_FORK:
-		die("hook fork failed");
+		return error("hook fork failed");
 	case -ERR_RUN_COMMAND_EXEC:
-		die("hook execute failed");
+		return error("hook execute failed");
 	case -ERR_RUN_COMMAND_WAITPID:
-		die("waitpid failed");
+		return error("waitpid failed");
 	case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
-		die("waitpid is confused");
+		return error("waitpid is confused");
 	case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
-		fprintf(stderr, "%s died of signal\n", update_hook);
-		return -1;
+		return error("%s died of signal\n", update_hook);
 	case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
-		die("%s died strangely", update_hook);
+		return error("%s died strangely", update_hook);
 	default:
 		error("%s exited with error code %d", update_hook, -code);
 		return -code;
 	}
 }
 
-static int update(const char *name,
-		  unsigned char *old_sha1, unsigned char *new_sha1)
+static int update(struct command *cmd)
 {
+	const char *name = cmd->ref_name;
+	unsigned char *old_sha1 = cmd->old_sha1;
+	unsigned char *new_sha1 = cmd->new_sha1;
 	char new_hex[60], *old_hex, *lock_name;
 	int newfd, namelen, written;
 
-	if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5))
+	cmd->error_string = NULL;
+	if (!strncmp(name, "refs/", 5) && check_ref_format(name + 5)) {
+		cmd->error_string = "funny refname";
 		return error("refusing to create funny ref '%s' locally",
 			     name);
+	}
 
 	namelen = strlen(name);
 	lock_name = xmalloc(namelen + 10);
@@ -106,16 +123,19 @@
 
 	strcpy(new_hex, sha1_to_hex(new_sha1));
 	old_hex = sha1_to_hex(old_sha1);
-	if (!has_sha1_file(new_sha1))
+	if (!has_sha1_file(new_sha1)) {
+		cmd->error_string = "bad pack";
 		return error("unpack should have generated %s, "
 			     "but I can't find it!", new_hex);
-
+	}
 	safe_create_leading_directories(lock_name);
 
 	newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
-	if (newfd < 0)
+	if (newfd < 0) {
+		cmd->error_string = "can't lock";
 		return error("unable to create %s (%s)",
 			     lock_name, strerror(errno));
+	}
 
 	/* Write the ref with an ending '\n' */
 	new_hex[40] = '\n';
@@ -127,18 +147,22 @@
 	close(newfd);
 	if (written != 41) {
 		unlink(lock_name);
+		cmd->error_string = "can't write";
 		return error("unable to write %s", lock_name);
 	}
 	if (verify_old_ref(name, old_hex) < 0) {
 		unlink(lock_name);
+		cmd->error_string = "raced";
 		return error("%s changed during push", name);
 	}
 	if (run_update_hook(name, old_hex, new_hex)) {
 		unlink(lock_name);
+		cmd->error_string = "hook declined";
 		return error("hook declined to update %s\n", name);
 	}
 	else if (rename(lock_name, name) < 0) {
 		unlink(lock_name);
+		cmd->error_string = "can't rename";
 		return error("unable to replace %s", name);
 	}
 	else {
@@ -158,7 +182,7 @@
 	if (access(update_post_hook, X_OK) < 0)
 		return;
 	for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
-		if (!cmd_p->updated)
+		if (cmd_p->error_string)
 			continue;
 		argc++;
 	}
@@ -166,7 +190,7 @@
 	argv[0] = update_post_hook;
 
 	for (argc = 1, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
-		if (!cmd_p->updated)
+		if (cmd_p->error_string)
 			continue;
 		argv[argc] = xmalloc(strlen(cmd_p->ref_name) + 1);
 		strcpy(argv[argc], cmd_p->ref_name);
@@ -185,8 +209,7 @@
 	struct command *cmd = commands;
 
 	while (cmd) {
-		cmd->updated = !update(cmd->ref_name,
-				       cmd->old_sha1, cmd->new_sha1);
+		update(cmd);
 		cmd = cmd->next;
 	}
 	run_update_post_hook(commands);
@@ -199,7 +222,8 @@
 		static char line[1000];
 		unsigned char old_sha1[20], new_sha1[20];
 		struct command *cmd;
-		int len;
+		char *refname;
+		int len, reflen;
 
 		len = packet_read_line(0, line, sizeof(line));
 		if (!len)
@@ -211,40 +235,68 @@
 		    line[81] != ' ' ||
 		    get_sha1_hex(line, old_sha1) ||
 		    get_sha1_hex(line + 41, new_sha1))
-			die("protocol error: expected old/new/ref, got '%s'", line);
+			die("protocol error: expected old/new/ref, got '%s'",
+			    line);
+
+		refname = line + 82;
+		reflen = strlen(refname);
+		if (reflen + 82 < len) {
+			if (strstr(refname + reflen + 1, "report-status"))
+				report_status = 1;
+		}
 		cmd = xmalloc(sizeof(struct command) + len - 80);
 		memcpy(cmd->old_sha1, old_sha1, 20);
 		memcpy(cmd->new_sha1, new_sha1, 20);
 		memcpy(cmd->ref_name, line + 82, len - 81);
+		cmd->error_string = "n/a (unpacker error)";
 		cmd->next = NULL;
 		*p = cmd;
 		p = &cmd->next;
 	}
 }
 
-static void unpack(void)
+static const char *unpack(int *error_code)
 {
 	int code = run_command(unpacker, NULL);
+
+	*error_code = 0;
 	switch (code) {
 	case 0:
-		return;
+		return NULL;
 	case -ERR_RUN_COMMAND_FORK:
-		die("unpack fork failed");
+		return "unpack fork failed";
 	case -ERR_RUN_COMMAND_EXEC:
-		die("unpack execute failed");
+		return "unpack execute failed";
 	case -ERR_RUN_COMMAND_WAITPID:
-		die("waitpid failed");
+		return "waitpid failed";
 	case -ERR_RUN_COMMAND_WAITPID_WRONG_PID:
-		die("waitpid is confused");
+		return "waitpid is confused";
 	case -ERR_RUN_COMMAND_WAITPID_SIGNAL:
-		die("%s died of signal", unpacker);
+		return "unpacker died of signal";
 	case -ERR_RUN_COMMAND_WAITPID_NOEXIT:
-		die("%s died strangely", unpacker);
+		return "unpacker died strangely";
 	default:
-		die("%s exited with error code %d", unpacker, -code);
+		*error_code = -code;
+		return "unpacker exited with error code";
 	}
 }
 
+static void report(const char *unpack_status)
+{
+	struct command *cmd;
+	packet_write(1, "unpack %s\n",
+		     unpack_status ? unpack_status : "ok");
+	for (cmd = commands; cmd; cmd = cmd->next) {
+		if (!cmd->error_string)
+			packet_write(1, "ok %s\n",
+				     cmd->ref_name);
+		else
+			packet_write(1, "ng %s %s\n",
+				     cmd->ref_name, cmd->error_string);
+	}
+	packet_flush(1);
+}
+
 int main(int argc, char **argv)
 {
 	int i;
@@ -275,8 +327,12 @@
 
 	read_head_info();
 	if (commands) {
-		unpack();
-		execute_commands();
+		int code;
+		const char *unpack_status = unpack(&code);
+		if (!unpack_status)
+			execute_commands();
+		if (report_status)
+			report(unpack_status);
 	}
 	return 0;
 }
diff --git a/rev-parse.c b/rev-parse.c
index bb4949a..0c951af 100644
--- a/rev-parse.c
+++ b/rev-parse.c
@@ -216,6 +216,18 @@
 					puts(prefix);
 				continue;
 			}
+			if (!strcmp(arg, "--show-cdup")) {
+				const char *pfx = prefix;
+				while (pfx) {
+					pfx = strchr(pfx, '/');
+					if (pfx) {
+						pfx++;
+						printf("../");
+					}
+				}
+				putchar('\n');
+				continue;
+			}
 			if (!strcmp(arg, "--git-dir")) {
 				const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
 				static char cwd[PATH_MAX];
diff --git a/send-pack.c b/send-pack.c
index 0d41f9a..cd36193 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -176,16 +176,53 @@
 	for_each_ref(one_local_ref);
 }
 
+static int receive_status(int in)
+{
+	char line[1000];
+	int ret = 0;
+	int len = packet_read_line(in, line, sizeof(line));
+	if (len < 10 || memcmp(line, "unpack ", 7)) {
+		fprintf(stderr, "did not receive status back\n");
+		return -1;
+	}
+	if (memcmp(line, "unpack ok\n", 10)) {
+		fputs(line, stderr);
+		ret = -1;
+	}
+	while (1) {
+		len = packet_read_line(in, line, sizeof(line));
+		if (!len)
+			break;
+		if (len < 3 ||
+		    (memcmp(line, "ok", 2) && memcmp(line, "ng", 2))) {
+			fprintf(stderr, "protocol error: %s\n", line);
+			ret = -1;
+			break;
+		}
+		if (!memcmp(line, "ok", 2))
+			continue;
+		fputs(line, stderr);
+		ret = -1;
+	}
+	return ret;
+}
+
 static int send_pack(int in, int out, int nr_refspec, char **refspec)
 {
 	struct ref *ref;
 	int new_refs;
 	int ret = 0;
+	int ask_for_status_report = 0;
+	int expect_status_report = 0;
 
 	/* No funny business with the matcher */
 	remote_tail = get_remote_heads(in, &remote_refs, 0, NULL, 1);
 	get_local_heads();
 
+	/* Does the other end support the reporting? */
+	if (server_supports("report-status"))
+		ask_for_status_report = 1;
+
 	/* match them up */
 	if (!remote_tail)
 		remote_tail = &remote_refs;
@@ -260,7 +297,17 @@
 		new_refs++;
 		strcpy(old_hex, sha1_to_hex(ref->old_sha1));
 		new_hex = sha1_to_hex(ref->new_sha1);
-		packet_write(out, "%s %s %s", old_hex, new_hex, ref->name);
+
+		if (ask_for_status_report) {
+			packet_write(out, "%s %s %s%c%s",
+				     old_hex, new_hex, ref->name, 0,
+				     "report-status");
+			ask_for_status_report = 0;
+			expect_status_report = 1;
+		}
+		else
+			packet_write(out, "%s %s %s",
+				     old_hex, new_hex, ref->name);
 		fprintf(stderr, "updating '%s'", ref->name);
 		if (strcmp(ref->name, ref->peer_ref->name))
 			fprintf(stderr, " using '%s'", ref->peer_ref->name);
@@ -270,9 +317,15 @@
 	packet_flush(out);
 	if (new_refs)
 		pack_objects(out, remote_refs);
-	else if (ret == 0)
-		fprintf(stderr, "Everything up-to-date\n");
 	close(out);
+
+	if (expect_status_report) {
+		if (receive_status(in))
+			ret = -4;
+	}
+
+	if (!new_refs && ret == 0)
+		fprintf(stderr, "Everything up-to-date\n");
 	return ret;
 }
 
diff --git a/setup.c b/setup.c
index d3556ed..36ede3d 100644
--- a/setup.c
+++ b/setup.c
@@ -180,6 +180,8 @@
 {
        if (strcmp(var, "core.repositoryformatversion") == 0)
                repository_format_version = git_config_int(var, value);
+	else if (strcmp(var, "core.sharedrepository") == 0)
+		shared_repository = git_config_bool(var, value);
        return 0;
 }
 
diff --git a/sha1_file.c b/sha1_file.c
index 6b7577d..8bebbb2 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -48,6 +48,29 @@
 	return 0;
 }
 
+int adjust_shared_perm(const char *path)
+{
+	struct stat st;
+	int mode;
+
+	if (!shared_repository)
+		return 0;
+	if (lstat(path, &st) < 0)
+		return -1;
+	mode = st.st_mode;
+	if (mode & S_IRUSR)
+		mode |= S_IRGRP;
+	if (mode & S_IWUSR)
+		mode |= S_IWGRP;
+	if (mode & S_IXUSR)
+		mode |= S_IXGRP;
+	if (S_ISDIR(mode))
+		mode |= S_ISGID;
+	if (chmod(path, mode) < 0)
+		return -2;
+	return 0;
+}
+
 int safe_create_leading_directories(char *path)
 {
 	char *pos = path;
@@ -59,11 +82,16 @@
 		if (!pos)
 			break;
 		*pos = 0;
-		if (mkdir(path, 0777) < 0)
+		if (mkdir(path, 0777) < 0) {
 			if (errno != EEXIST) {
 				*pos = '/';
 				return -1;
 			}
+		}
+		else if (adjust_shared_perm(path)) {
+			*pos = '/';
+			return -2;
+		}
 		*pos++ = '/';
 	}
 	return 0;
@@ -1255,6 +1283,8 @@
 		if (dir) {
 			*dir = 0;
 			mkdir(filename, 0777);
+			if (adjust_shared_perm(filename))
+				return -2;
 			*dir = '/';
 			if (!link(tmpfile, filename))
 				return 0;
diff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh
index 1f461e3..adcbe03 100755
--- a/t/t3000-ls-files-others.sh
+++ b/t/t3000-ls-files-others.sh
@@ -11,24 +11,46 @@
     path0       - a file
     path1	- a symlink
     path2/file2 - a file in a directory
+    path3-junk  - a file to confuse things
+    path3/file3 - a file in a directory
 '
 . ./test-lib.sh
 
 date >path0
 ln -s xyzzy path1
-mkdir path2
+mkdir path2 path3
 date >path2/file2
-test_expect_success \
-    'git-ls-files --others to show output.' \
-    'git-ls-files --others >output'
-cat >expected <<EOF
+date >path2-junk
+date >path3/file3
+date >path3-junk
+git-update-index --add path3-junk path3/file3
+
+cat >expected1 <<EOF
+expected1
+expected2
 output
 path0
 path1
+path2-junk
 path2/file2
 EOF
+sed -e 's|path2/file2|path2/|' <expected1 >expected2
+
+test_expect_success \
+    'git-ls-files --others to show output.' \
+    'git-ls-files --others >output'
 
 test_expect_success \
     'git-ls-files --others should pick up symlinks.' \
-    'diff output expected'
+    'diff output expected1'
+
+test_expect_success \
+    'git-ls-files --others --directory to show output.' \
+    'git-ls-files --others --directory >output'
+
+
+test_expect_success \
+    'git-ls-files --others --directory should not get confused.' \
+    'diff output expected2'
+
 test_done
diff --git a/t/t3401-rebase-partial.sh b/t/t3401-rebase-partial.sh
new file mode 100755
index 0000000..32dc9c5
--- /dev/null
+++ b/t/t3401-rebase-partial.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Yann Dirson, based on t3400 by Amos Waterland
+#
+
+test_description='git rebase should detect patches integrated upstream
+
+This test cherry-picks one local change of two into master branch, and
+checks that git rebase succeeds with only the second patch in the
+local branch.
+'
+. ./test-lib.sh
+
+test_expect_success \
+    'prepare repository with topic branch' \
+    'echo First > A &&
+     git-update-index --add A &&
+     git-commit -m "Add A." &&
+
+     git-checkout -b my-topic-branch &&
+
+     echo Second > B &&
+     git-update-index --add B &&
+     git-commit -m "Add B." &&
+
+     echo AnotherSecond > C &&
+     git-update-index --add C &&
+     git-commit -m "Add C." &&
+
+     git-checkout -f master &&
+
+     echo Third >> A &&
+     git-update-index A &&
+     git-commit -m "Modify A."
+'
+
+test_expect_success \
+    'pick top patch from topic branch into master' \
+    'git-cherry-pick my-topic-branch^0 &&
+     git-checkout -f my-topic-branch
+'
+
+test_debug \
+    'git-cherry master &&
+     git-format-patch -k --stdout --full-index master >/dev/null &&
+     gitk --all & sleep 1
+'
+
+test_expect_success \
+    'rebase topic branch against new master and check git-am did not get halted' \
+    'git-rebase master && test ! -d .dotest'
+
+test_done
diff --git a/t/t3500-cherry.sh b/t/t3500-cherry.sh
new file mode 100755
index 0000000..b141f89
--- /dev/null
+++ b/t/t3500-cherry.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Yann Dirson, based on t3400 by Amos Waterland
+#
+
+test_description='git-cherry should detect patches integrated upstream
+
+This test cherry-picks one local change of two into master branch, and
+checks that git-cherry only returns the second patch in the local branch
+'
+. ./test-lib.sh
+
+export GIT_AUTHOR_EMAIL=bogus_email_address
+
+test_expect_success \
+    'prepare repository with topic branch, and check cherry finds the 2 patches from there' \
+    'echo First > A &&
+     git-update-index --add A &&
+     git-commit -m "Add A." &&
+
+     git-checkout -b my-topic-branch &&
+
+     echo Second > B &&
+     git-update-index --add B &&
+     git-commit -m "Add B." &&
+
+     sleep 2 &&
+     echo AnotherSecond > C &&
+     git-update-index --add C &&
+     git-commit -m "Add C." &&
+
+     git-checkout -f master &&
+
+     echo Third >> A &&
+     git-update-index A &&
+     git-commit -m "Modify A." &&
+
+     expr "$(echo $(git-cherry master my-topic-branch) )" : "+ [^ ]* + .*"
+'
+
+test_expect_success \
+    'check that cherry with limit returns only the top patch'\
+    'expr "$(echo $(git-cherry master my-topic-branch my-topic-branch^1) )" : "+ [^ ]*"
+'
+
+test_expect_success \
+    'cherry-pick one of the 2 patches, and check cherry recognized one and only one as new' \
+    'git-cherry-pick my-topic-branch^0 &&
+     echo $(git-cherry master my-topic-branch) &&
+     expr "$(echo $(git-cherry master my-topic-branch) )" : "+ [^ ]* - .*"
+'
+
+test_done
diff --git a/t/t6022-merge-rename.sh b/t/t6022-merge-rename.sh
index 153b9e4..1292caf 100755
--- a/t/t6022-merge-rename.sh
+++ b/t/t6022-merge-rename.sh
@@ -161,4 +161,41 @@
 	}
 '
 
+test_expect_success 'pull conflicting renames' \
+'
+	git reset --hard
+	git show-branch
+	git pull . blue && {
+		echo "BAD: should have conflicted"
+		exit 1
+	}
+	test "$(git ls-files -u A | wc -l)" -eq 1 || {
+		echo "BAD: should have left a stage"
+		exit 1	
+	}
+	test "$(git ls-files -u B | wc -l)" -eq 1 || {
+		echo "BAD: should have left a stage"
+		exit 1	
+	}
+	test "$(git ls-files -u C | wc -l)" -eq 1 || {
+		echo "BAD: should have left a stage"
+		exit 1	
+	}
+	test "$(git ls-files -s N | wc -l)" -eq 1 || {
+		echo "BAD: should have merged N"
+		exit 1	
+	}
+	sed -ne "/^g/{
+	p
+	q
+	}" B | grep red || {
+		echo "BAD: should have listed our change first"
+		exit 1
+	}
+	test "$(git diff white N | wc -l)" -eq 0 || {
+		echo "BAD: should have taken colored branch"
+		exit 1
+	}
+'
+
 test_done