Commits

Junio C Hamano  committed 423325a Merge

GIT 0.99.9l aka 1.0rc4

  • Participants
  • Parent commits 93dcab2, d79374c
  • Tags v0.99.9l, v1.0rc4

Comments (0)

Files changed (90)

File Documentation/fetch-options.txt

 	option old data in `.git/FETCH_HEAD` will be overwritten.
 
 -f, \--force::
+	When `git-fetch` is used with `<rbranch>:<lbranch>`
+	refspec, it refuses to update the local branch
+	`<lbranch>` unless the remote branch `<rbranch>` it
+	fetches is a descendant of `<lbranch>`.  This option
+	overrides that check.
 
 -t, \--tags::
 	By default, the git core utilities will not fetch and store

File Documentation/git-bisect.txt

 
 SYNOPSIS
 --------
-'git bisect' start
-'git bisect' bad <rev>
-'git bisect' good <rev>
-'git bisect' reset [<branch>]
-'git bisect' visualize
-'git bisect' replay <logfile>
-'git bisect' log
+ 'git bisect' start
+ 'git bisect' bad <rev>
+ 'git bisect' good <rev>
+ 'git bisect' reset [<branch>]
+ 'git bisect' visualize
+ 'git bisect' replay <logfile>
+ 'git bisect' log
 
 DESCRIPTION
 -----------

File Documentation/git-cat-file.txt

 
 SYNOPSIS
 --------
-'git-cat-file' (-t | -s | <type>) <object>
+'git-cat-file' (-t | -s | -e | <type>) <object>
 
 DESCRIPTION
 -----------
 	Instead of the content, show the object size identified by
 	<object>.
 
+-e::
+	Suppress all output; instead exit with zero status if <object>
+	exists and is a valid object.
+
 <type>::
 	Typically this matches the real type of <object> but asking
 	for a type that can trivially be dereferenced from the given
 
 OUTPUT
 ------
-If '-t' is specified, one of the <type>.  If '-s' is specified,
-the size of the <object> in bytes.
+If '-t' is specified, one of the <type>.
+
+If '-s' is specified, the size of the <object> in bytes.
+
+If '-e' is specified, no output.
 
 Otherwise the raw (though uncompressed) contents of the <object> will
 be returned.

File Documentation/git-diff-files.txt

 -------
 include::diff-options.txt[]
 
+-1 -2 -3 or --base --ours --theirs, and -0::
+	Diff against the "base" version, "our branch" or "their
+	branch" respectively.  With these options, diffs for
+	merged entries are not shown.
++
+The default is to diff against our branch (-2) and the 
+cleanly resolved paths.  The option -0 can be given to
+omit diff output for unmerged entries and just show "Unmerged".
+
 -q::
 	Remain silent even on nonexisting files
 

File Documentation/git-mailinfo.txt

 
 SYNOPSIS
 --------
-'git-mailinfo' [-k] [-u] <msg> <patch>
+'git-mailinfo' [-k] [-u | --encoding=<encoding>] <msg> <patch>
 
 
 DESCRIPTION
 	author email are taken from the e-mail without any
 	charset conversion, after minimally decoding MIME
 	transfer encoding.  This flag causes the resulting
-	commit to be encoded in utf-8 by transliterating them.
+	commit to be encoded in the encoding specified by
+	i18n.commitencoding configuration (defaults to utf-8) by
+	transliterating them. 
 	Note that the patch is always used as is without charset
 	conversion, even with this flag.
 
+--encoding=<encoding>::
+	Similar to -u but if the local convention is different
+	from what is specified by i18n.commitencoding, this flag
+	can be used to override it.
+
 <msg>::
 	The commit log message extracted from e-mail, usually
 	except the title line which comes from e-mail Subject.

File Documentation/git-merge.txt

 include::merge-strategies.txt[]
 
 
+HOW MERGE WORKS
+---------------
+
+A merge is always between the current `HEAD` and one or more
+remote branch heads, and the index file must exactly match the
+tree of `HEAD` commit (i.e. the contents of the last commit) when
+it happens.  In other words, `git-diff --cached HEAD` must
+report no changes.
+
+[NOTE]
+This is a bit of lie.  In certain special cases, your index are
+allowed to be different from the tree of `HEAD` commit.  The most
+notable case is when your `HEAD` commit is already ahead of what
+is being merged, in which case your index can have arbitrary
+difference from your `HEAD` commit.  Otherwise, your index entries
+are allowed have differences from your `HEAD` commit that match
+the result of trivial merge (e.g. you received the same patch
+from external source to produce the same result as what you are
+merging).  For example, if a path did not exist in the common
+ancestor and your head commit but exists in the tree you are
+merging into your repository, and if you already happen to have
+that path exactly in your index, the merge does not have to
+fail.
+
+Otherwise, merge will refuse to do any harm to your repository
+(that is, it may fetch the objects from remote, and it may even
+update the local branch used to keep track of the remote branch
+with `git pull remote rbranch:lbranch`, but your working tree,
+`.git/HEAD` pointer and index file are left intact).
+
+You may have local modifications in the working tree files.  In
+other words, `git-diff` is allowed to report changes.
+However, the merge uses your working tree as the working area,
+and in order to prevent the merge operation from losing such
+changes, it makes sure that they do not interfere with the
+merge. Those complex tables in read-tree documentation define
+what it means for a path to "interfere with the merge".  And if
+your local modifications interfere with the merge, again, it
+stops before touching anything.
+
+So in the above two "failed merge" case, you do not have to
+worry about lossage of data --- you simply were not ready to do
+a merge, so no merge happened at all.  You may want to finish
+whatever you were in the middle of doing, and retry the same
+pull after you are done and ready.
+
+When things cleanly merge, these things happen:
+
+1. the results are updated both in the index file and in your
+   working tree,
+2. index file is written out as a tree,
+3. the tree gets committed, and 
+4. the `HEAD` pointer gets advanced.
+
+Because of 2., we require that the original state of the index
+file to match exactly the current `HEAD` commit; otherwise we
+will write out your local changes already registered in your
+index file along with the merge result, which is not good.
+Because 1. involves only the paths different between your
+branch and the remote branch you are pulling from during the
+merge (which is typically a fraction of the whole tree), you can
+have local modifications in your working tree as long as they do
+not overlap with what the merge updates.
+
+When there are conflicts, these things happen:
+
+1. `HEAD` stays the same.
+
+2. Cleanly merged paths are updated both in the index file and
+   in your working tree.
+
+3. For conflicting paths, the index file records up to three
+   versions; stage1 stores the version from the common ancestor,
+   stage2 from `HEAD`, and stage3 from the remote branch (you
+   can inspect the stages with `git-ls-files -u`).  The working
+   tree files have the result of "merge" program; i.e. 3-way
+   merge result with familiar conflict markers `<<< === >>>`.
+
+4. No other changes are done.  In particular, the local
+   modifications you had before you started merge will stay the
+   same and the index entries for them stay as they were,
+   i.e. matching `HEAD`.
+
+After seeing a conflict, you can do two things:
+
+ * Decide not to merge.  The only clean-up you need are to reset
+   the index file to the `HEAD` commit to reverse 2. and to clean
+   up working tree changes made by 2. and 3.; `git-reset` can
+   be used for this.
+
+ * Resolve the conflicts.  `git-diff` would report only the
+   conflicting paths because of the above 2. and 3..  Edit the
+   working tree files into a desirable shape, `git-update-index`
+   them, to make the index file contain what the merge result
+   should be, and run `git-commit` to commit the result.
+
+
 SEE ALSO
 --------
 gitlink:git-fmt-merge-msg[1], gitlink:git-pull[1]

File Documentation/git-mv.txt

 
 SYNOPSIS
 --------
-'git-mv' [-f] [-n] <source> <destination>
-'git-mv' [-f] [-k] [-n] <source> ... <destination directory>
+ 'git-mv' [-f] [-n] <source> <destination>
+ 'git-mv' [-f] [-n] [-k] <source> ... <destination directory>
 
 DESCRIPTION
 -----------
 This script is used to move or rename a file, directory or symlink.
 In the first form, it renames <source>, which must exist and be either
-a file, symlink or directory, to <destination>, which must not exist.
+a file, symlink or directory, to <destination>.
 In the second form, the last argument has to be an existing
 directory; the given sources will be moved into this directory.
 
 OPTIONS
 -------
 -f::
-	Force renaming or moving even targets exist
+	Force renaming or moving of a file even if the target exists
 -k::
         Skip move or rename actions which would lead to an error
 	condition. An error happens when a source is neither existing nor

File Documentation/git-read-tree.txt

 OPTIONS
 -------
 -m::
-	Perform a merge, not just a read.
+	Perform a merge, not just a read.  The command will
+	refuse to run if your index file has unmerged entries,
+	indicating that you have not finished previous merge you
+	started.
 
 --reset::
-
-        Same as -m except that unmerged entries will be silently ignored.
+        Same as -m, except that unmerged entries are discarded
+        instead of failing.
 
 -u::
 	After a successful merge, update the files in the work
 	trees that are not directly related to the current
 	working tree status into a temporary index file.
 
-
 <tree-ish#>::
 	The id of the tree object(s) to be read/merged.
 

File Documentation/git-svnimport.txt

 SYNOPSIS
 --------
 'git-svnimport' [ -o <branch-for-HEAD> ] [ -h ] [ -v ] [ -d | -D ]
-			[ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_nr_changes]
+			[ -C <GIT_repository> ] [ -i ] [ -u ] [-l limit_rev]
 			[ -b branch_subdir ] [ -t trunk_subdir ] [ -T tag_subdir ]
 			[ -s start_chg ] [ -m ] [ -M regex ]
 			<SVN_repository_URL> [ <path> ]
 	regex. It can be used with -m to also see the default regexes.
 	You must escape forward slashes.
 
--l <max_num_changes>::
-	Limit the number of SVN changesets we pull before quitting.
-	This option is necessary because the SVN library has serious memory
-	leaks; the recommended value for nontrivial imports is 100.
+-l <max_rev>::
+	Specify a maximum revision number to pull.
 
-	git-svnimport will still exit with a zero exit code. You can check
-	the size of the file ".git/svn2git" to determine whether to call
-	the importer again.
+	Formerly, this option controlled how many revisions to pull, due to
+	SVN memory leaks. (These have been worked around.)
 
 -v::
 	Verbosity: let 'svnimport' report what it is doing.

File Documentation/git-tag.txt

 --------
 'git-tag' [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <name> [<head>]
 
+OPTIONS
+-------
+-a::
+	Make an unsigned, annotated tag object
+
+-s::
+	Make a GPG-signed tag, using the default e-mail address's key
+
+-u <key-id>::
+	Make a GPG-signed tag, using the given key
+
+-f::
+	Replace an existing tag with the given name (instead of failing)
+
+-d::
+	Delete an existing tag with the given name
+
+-m <msg>::
+	Use the given tag message (instead of prompting)
+
 DESCRIPTION
 -----------
 Adds a 'tag' reference in .git/refs/tags/
 in the tag message.
 
 Otherwise just the SHA1 object name of the commit object is
-written (i.e. an lightweight tag).
+written (i.e. a lightweight tag).
 
 A GnuPG signed tag object will be created when `-s` or `-u
 <key-id>` is used.  When `-u <key-id>` is not used, the

File Documentation/pull-fetch-param.txt

 - ssh://host.xz/~/path/to/repo.git
 ===============================================================
 +
-	SSH Is the default transport protocol and also supports an
-	scp-like syntax.  Both syntaxes support username expansion,
-	as does the native git protocol. The following three are
-	identical to the last three above, respectively:
+SSH Is the default transport protocol and also supports an
+scp-like syntax.  Both syntaxes support username expansion,
+as does the native git protocol. The following three are
+identical to the last three above, respectively:
 +
 ===============================================================
 - host.xz:/path/to/repo.git/
 - host.xz:path/to/repo.git
 ===============================================================
 +
-       To sync with a local directory, use:
-
+To sync with a local directory, use:
++
 ===============================================================
 - /path/to/repo.git/
 ===============================================================
 `git pull . remote-B`, while you are on `my-B` branch.
 The common `Pull: master:origin` mapping of a remote `master`
 branch to a local `origin` branch, which is then merged to a
-ocal development branch, again typically named `master`, is made
+local development branch, again typically named `master`, is made
 when you run `git clone` for you to follow this pattern.
 +
 [NOTE]

File Documentation/tutorial.txt

 	fatal: Merge requires file-level merging
 	Nope.
 	...
-	merge: warning: conflicts during merge
-	ERROR: Merge conflict in hello.
-	fatal: merge program failed
+	Auto-merging hello 
+	CONFLICT (content): Merge conflict in hello 
 	Automatic merge failed/prevented; fix up by hand
 ----------------
 
 
 ------------------------------------------------
 $ git show-branch master mybranch
-* [master] Merged "mybranch" changes.
+* [master] Merge work in mybranch
  ! [mybranch] Some work.
 --
-+  [master] Merged "mybranch" changes.
++  [master] Merge work in mybranch
 ++ [mybranch] Some work.
 ------------------------------------------------
 
 
 ------------------------------------------------
 $ git show-branch master mybranch
-! [master] Merged "mybranch" changes.
- * [mybranch] Merged "mybranch" changes.
+! [master] Merge work in mybranch
+ * [mybranch] Merge work in mybranch
 --
-++ [master] Merged "mybranch" changes.
+++ [master] Merge work in mybranch
 ------------------------------------------------
 
 
+# The default target of this Makefile is...
+all:
+
 # Define MOZILLA_SHA1 environment variable when running make to make use of
 # a bundled SHA1 routine coming from Mozilla. It is GPL'd and should be fast
 # on non-x86 architectures (e.g. PowerPC), while the OpenSSL version (default
 #
 # Define NO_STRCASESTR if you don't have strcasestr.
 #
+# Define NO_SETENV if you don't have setenv in the C library.
+#
 # Define PPC_SHA1 environment variable when running make to make use of
 # a bundled SHA1 routine optimized for PowerPC.
 #
 # Define USE_STDEV below if you want git to care about the underlying device
 # change being considered an inode change from the update-cache perspective.
 
-GIT_VERSION = 0.99.9k
+GIT_VERSION = 0.99.9l
 
 # CFLAGS and LDFLAGS are for the users to override from the command line.
 
 # Backward compatibility -- to be removed after 1.0
 PROGRAMS += git-ssh-pull$X git-ssh-push$X
 
-GIT_LIST_TWEAK =
-
 # Set paths to tools early so that they can be used for version tests.
 ifndef SHELL_PATH
 	SHELL_PATH = /bin/sh
 PYMODULES = \
 	gitMergeCommon.py
 
-ifdef WITH_OWN_SUBPROCESS_PY
-	PYMODULES += compat/subprocess.py
-else
-	ifneq ($(shell $(PYTHON_PATH) -c 'import subprocess;print"OK"' 2>/dev/null),OK)
-		PYMODULES += compat/subprocess.py
-	endif
-endif
-
-ifdef WITH_SEND_EMAIL
-	SCRIPT_PERL += git-send-email.perl
-else
-	GIT_LIST_TWEAK += -e '/^send-email$$/d'
-endif
-
 LIB_FILE=libgit.a
 
 LIB_H = \
 uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
 uname_M := $(shell sh -c 'uname -m 2>/dev/null || echo not')
 uname_O := $(shell sh -c 'uname -o 2>/dev/null || echo not')
+uname_R := $(shell sh -c 'uname -r 2>/dev/null || echo not')
 
 ifeq ($(uname_S),Darwin)
 	NEEDS_SSL_WITH_CRYPTO = YesPlease
 	NEEDS_LIBICONV = YesPlease
 	SHELL_PATH = /bin/bash
 	NO_STRCASESTR = YesPlease
+	ifeq ($(uname_R),5.8)
+		NO_SETENV = YesPlease
+	endif
 	INSTALL = ginstall
 	TAR = gtar
 	ALL_CFLAGS += -D__EXTENSIONS__
 
 -include config.mak
 
+ifdef WITH_OWN_SUBPROCESS_PY
+	PYMODULES += compat/subprocess.py
+else
+	ifneq ($(shell $(PYTHON_PATH) -c 'import subprocess;print"OK"' 2>/dev/null),OK)
+		PYMODULES += compat/subprocess.py
+	endif
+endif
+
+ifdef WITH_SEND_EMAIL
+	SCRIPT_PERL += git-send-email.perl
+endif
+
 ifndef NO_CURL
 	ifdef CURLDIR
 		# This is still problematic -- gcc does not always want -R.
 	SIMPLE_LIB += -lnsl
 endif
 ifdef NO_STRCASESTR
-	ALL_CFLAGS += -Dstrcasestr=gitstrcasestr -DNO_STRCASESTR=1
-	LIB_OBJS += compat/strcasestr.o
+	COMPAT_CFLAGS += -Dstrcasestr=gitstrcasestr -DNO_STRCASESTR=1
+	COMPAT_OBJS += compat/strcasestr.o
+endif
+ifdef NO_SETENV
+	COMPAT_CFLAGS += -Dsetenv=gitsetenv -DNO_SETENV=1
+	COMPAT_OBJS += compat/setenv.o
 endif
 ifdef NO_MMAP
-	ALL_CFLAGS += -Dmmap=gitfakemmap -Dmunmap=gitfakemunmap -DNO_MMAP
-	LIB_OBJS += compat/mmap.o
+	COMPAT_CFLAGS += -Dmmap=gitfakemmap -Dmunmap=gitfakemunmap -DNO_MMAP
+	COMPAT_OBJS += compat/mmap.o
 endif
 ifdef NO_IPV6
 	ALL_CFLAGS += -DNO_IPV6 -Dsockaddr_storage=sockaddr_in
 endif
 endif
 
-ALL_CFLAGS += -DSHA1_HEADER=$(call shellquote,$(SHA1_HEADER))
-
+ALL_CFLAGS += -DSHA1_HEADER=$(call shellquote,$(SHA1_HEADER)) $(COMPAT_CFLAGS)
+LIB_OBJS += $(COMPAT_OBJS)
 export prefix TAR INSTALL DESTDIR SHELL_PATH template_dir
 ### Build rules
 
 all:
 	$(MAKE) -C templates
 
-# Only use $(CFLAGS). We don't need anything else.
-git$(X): git.c Makefile
+git$(X): git.c $(COMPAT_OBJS) Makefile
 	$(CC) -DGIT_EXEC_PATH='"$(bindir)"' -DGIT_VERSION='"$(GIT_VERSION)"' \
-		$(CFLAGS) $< -o $@
+		$(CFLAGS) $(COMPAT_CFLAGS) -o $@ $(filter %.c,$^) $(filter %.o,$^)
 
 $(patsubst %.sh,%,$(SCRIPT_SH)) : % : %.sh
 	rm -f $@
 //  --numstat does numeric diffstat, and doesn't actually apply
 //  --index-info shows the old and new index info for paths if available.
 //
+static const char *prefix;
+static int prefix_length = -1;
+
 static int allow_binary_replacement = 0;
 static int check_index = 0;
 static int write_index = 0;
 			return 0;
 		x = x->next;
 	}
+	if (0 < prefix_length) {
+		int pathlen = strlen(pathname);
+		if (pathlen <= prefix_length ||
+		    memcmp(prefix, pathname, prefix_length))
+			return 0;
+	}
 	return 1;
 }
 
 			line_termination = 0;
 			continue;
 		}
+
+		if (check_index && prefix_length < 0) {
+			prefix = setup_git_directory();
+			prefix_length = prefix ? strlen(prefix) : 0;
+			git_config(git_default_config);
+		}
+		if (0 < prefix_length)
+			arg = prefix_filename(prefix, prefix_length, arg);
+
 		fd = open(arg, O_RDONLY);
 		if (fd < 0)
 			usage(apply_usage);
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
 
 extern const char **get_pathspec(const char *prefix, const char **pathspec);
+extern const char *setup_git_directory_gently(int *);
 extern const char *setup_git_directory(void);
 extern const char *prefix_path(const char *prefix, int len, const char *path);
+extern const char *prefix_filename(const char *prefix, int len, const char *path);
 
 #define alloc_nr(x) (((x)+16)*3/2)
 
 extern int only_use_symrefs;
 extern int diff_rename_limit_default;
 
+#define GIT_REPO_VERSION 0
+extern int repository_format_version;
+extern int check_repository_format(void);
+
 #define MTIME_CHANGED	0x0001
 #define CTIME_CHANGED	0x0002
 #define OWNER_CHANGED	0x0004
 
 typedef int (*config_fn_t)(const char *, const char *);
 extern int git_default_config(const char *, const char *);
+extern int git_config_from_file(config_fn_t fn, const char *);
 extern int git_config(config_fn_t fn);
 extern int git_config_int(const char *, const char *);
 extern int git_config_bool(const char *, const char *);
 extern int git_config_set(const char *, const char *);
 extern int git_config_set_multivar(const char *, const char *, const char *, int);
+extern int check_repository_format_version(const char *var, const char *value);
 
 #define MAX_GITNAME (1000)
 extern char git_default_email[MAX_GITNAME];
 extern char git_default_name[MAX_GITNAME];
 
+#define MAX_ENCODING_LENGTH 64
+extern char git_commit_encoding[MAX_ENCODING_LENGTH];
+
 /* Sane ctype - no locale, and works with signed chars */
 #undef isspace
 #undef isdigit
 	char type[20];
 	void *buf;
 	unsigned long size;
+	int opt;
 
 	setup_git_directory();
 	if (argc != 3 || get_sha1(argv[2], sha1))
-		usage("git-cat-file [-t | -s | <type>] <sha1>");
-
-	if (!strcmp("-t", argv[1]) || !strcmp("-s", argv[1])) {
-		if (!sha1_object_info(sha1, type,
-				      argv[1][1] == 's' ? &size : NULL)) {
-			switch (argv[1][1]) {
-			case 't':
-				printf("%s\n", type);
-				break;
-			case 's':
-				printf("%lu\n", size);
-				break;
-			}
+		usage("git-cat-file [-t|-s|-e|<type>] <sha1>");
+
+	opt = 0;
+	if ( argv[1][0] == '-' ) {
+		opt = argv[1][1];
+		if ( !opt || argv[1][2] )
+			opt = -1; /* Not a single character option */
+	}
+
+	buf = NULL;
+	switch (opt) {
+	case 't':
+		if (!sha1_object_info(sha1, type, NULL)) {
+			printf("%s\n", type);
 			return 0;
 		}
-		buf = NULL;
-	} else {
+		break;
+
+	case 's':
+		if (!sha1_object_info(sha1, type, &size)) {
+			printf("%lu\n", size);
+			return 0;
+		}
+		break;
+
+	case 'e':
+		return !has_sha1_file(sha1);
+
+	case 0:
 		buf = read_object_with_reference(sha1, argv[1], &size, NULL);
+		break;
+
+	default:
+		die("git-cat-file: unknown option: %s\n", argv[1]);
 	}
 
 	if (!buf)

File checkout-index.c

  */
 #include "cache.h"
 
+static const char *prefix;
+static int prefix_length;
+
 static struct checkout state = {
 	.base_dir = "",
 	.base_dir_len = 0,
 		struct cache_entry *ce = active_cache[i];
 		if (ce_stage(ce))
 			continue;
+		if (prefix && *prefix &&
+		    ( ce_namelen(ce) <= prefix_length ||
+		      memcmp(prefix, ce->name, prefix_length) ))
+			continue;
 		if (checkout_entry(ce, &state) < 0)
 			errs++;
 	}
 	int newfd = -1;
 	int all = 0;
 
+	prefix = setup_git_directory();
+	prefix_length = prefix ? strlen(prefix) : 0;
+
 	if (read_cache() < 0) {
 		die("invalid cache");
 	}
 
 		if (all)
 			die("git-checkout-index: don't mix '--all' and explicit filenames");
-		checkout_file(arg);
+		checkout_file(prefix_path(prefix, prefix_length, arg));
 	}
 
 	if (all)

File clone-pack.c

 	int fd[2];
 	pid_t pid;
 
+	setup_git_directory();
+
 	nr_heads = 0;
 	heads = NULL;
 	for (i = 1; i < argc; i++) {

File commit-tree.c

 	if (argc < 2 || get_sha1_hex(argv[1], tree_sha1) < 0)
 		usage(commit_tree_usage);
 
+	setup_git_directory();
+
 	check_valid(tree_sha1, "tree");
 	for (i = 2; i < argc; i += 2) {
 		char *a, *b;

File compat/setenv.c

+#include <stdlib.h>
+#include <string.h>
+
+int gitsetenv(const char *name, const char *value, int replace)
+{
+	int out;
+	size_t namelen, valuelen;
+	char *envstr;
+
+	if (!name || !value) return -1;
+	if (!replace) {
+		char *oldval = NULL;
+		oldval = getenv(name);
+		if (oldval) return 0;
+	}
+
+	namelen = strlen(name);
+	valuelen = strlen(value);
+	envstr = malloc((namelen + valuelen + 2) * sizeof(char));
+	if (!envstr) return -1;
+
+	memcpy(envstr, name, namelen);
+	envstr[namelen] = '=';
+	memcpy(envstr + namelen + 1, value, valuelen);
+	envstr[namelen + valuelen + 1] = 0;
+
+	out = putenv(envstr);
+
+	free(envstr);
+	return out;
+}
 #define MAXNAME (256)
 
 static FILE *config_file;
+static const char *config_file_name;
 static int config_linenr;
 static int get_next_char(void)
 {
 		if (get_value(fn, var, baselen+1) < 0)
 			break;
 	}
-	die("bad config file line %d", config_linenr);
+	die("bad config file line %d in %s", config_linenr, config_file_name);
 }
 
 int git_config_int(const char *name, const char *value)
 		if (!*end)
 			return val;
 	}
-	die("bad config value for '%s'", name);
+	die("bad config value for '%s' in %s", name, config_file_name);
 }
 
 int git_config_bool(const char *name, const char *value)
 		return 0;
 	}
 
+	if (!strcmp(var, "i18n.commitencoding")) {
+		strncpy(git_commit_encoding, value, sizeof(git_commit_encoding));
+		return 0;
+	}
+
 	/* Add other config variables here.. */
 	return 0;
 }
 
-int git_config(config_fn_t fn)
+int git_config_from_file(config_fn_t fn, const char *filename)
 {
 	int ret;
-	FILE *f = fopen(git_path("config"), "r");
+	FILE *f = fopen(filename, "r");
 
 	ret = -1;
 	if (f) {
 		config_file = f;
+		config_file_name = filename;
 		config_linenr = 1;
 		ret = git_parse_file(fn);
 		fclose(f);
+		config_file_name = NULL;
 	}
 	return ret;
 }
 
+int git_config(config_fn_t fn)
+{
+	return git_config_from_file(fn, git_path("config"));
+}
+
 /*
  * Find all the stuff for git_config_set() below.
  */

File convert-objects.c

 	unsigned char sha1[20];
 	struct entry *entry;
 
+	setup_git_directory();
+
 	if (argc != 2 || get_sha1(argv[1], sha1))
 		usage("git-convert-objects <sha1>");
 
 	va_end(params);
 }
 
+static int avoid_alias(char *p)
+{
+	int sl, ndot;
+
+	/* 
+	 * This resurrects the belts and suspenders paranoia check by HPA
+	 * done in <435560F7.4080006@zytor.com> thread, now enter_repo()
+	 * does not do getcwd() based path canonicalizations.
+	 *
+	 * sl becomes true immediately after seeing '/' and continues to
+	 * be true as long as dots continue after that without intervening
+	 * non-dot character.
+	 */
+	if (!p || (*p != '/' && *p != '~'))
+		return -1;
+	sl = 1; ndot = 0;
+	p++;
+
+	while (1) {
+		char ch = *p++;
+		if (sl) {
+			if (ch == '.')
+				ndot++;
+			else if (ch == '/') {
+				if (ndot < 3)
+					/* reject //, /./ and /../ */
+					return -1;
+				ndot = 0;
+			}
+			else if (ch == 0) {
+				if (0 < ndot && ndot < 3)
+					/* reject /.$ and /..$ */
+					return -1;
+				return 0;
+			}
+			else
+				sl = ndot = 0;
+		}
+		else if (ch == 0)
+			return 0;
+		else if (ch == '/') {
+			sl = 1;
+			ndot = 0;
+		}
+	}
+}
+
 static char *path_ok(char *dir)
 {
-	char *path = enter_repo(dir, strict_paths);
+	char *path;
+
+	if (avoid_alias(dir)) {
+		logerror("'%s': aliased", dir);
+		return NULL;
+	}
+
+	path = enter_repo(dir, strict_paths);
 
 	if (!path) {
 		logerror("'%s': unable to chdir or not a git archive", dir);
 		int pathlen = strlen(path);
 
 		/* The validation is done on the paths after enter_repo
-		 * canonicalization, so whitelist should be written in
-		 * terms of real pathnames (i.e. after ~user is expanded
-		 * and symlinks resolved).
+		 * appends optional {.git,.git/.git} and friends, but 
+		 * it does not use getcwd().  So if your /pub is
+		 * a symlink to /mnt/pub, you can whitelist /pub and
+		 * do not have to say /mnt/pub.
+		 * Do not say /pub/.
 		 */
 		for ( pp = ok_paths ; *pp ; pp++ ) {
 			int len = strlen(*pp);

File debian/changelog

+git-core (0.99.9l-0) unstable; urgency=low
+
+  * GIT 0.99.9l aka 1.0rc4
+
+ -- Junio C Hamano <junkio@cox.net>  Sat,  3 Dec 2005 23:45:23 -0800
+
 git-core (0.99.9k-0) unstable; urgency=low
 
   * GIT 0.99.9k but not 1.0rc yet.

File diff-files.c

 #include "diff.h"
 
 static const char diff_files_usage[] =
-"git-diff-files [-q] "
-"[<common diff options>] [<path>...]"
+"git-diff-files [-q] [-0/-1/2/3] [<common diff options>] [<path>...]"
 COMMON_DIFF_OPTIONS_HELP;
 
 static struct diff_options diff_options;
 static int silent = 0;
+static int diff_unmerged_stage = 2;
 
 static void show_unmerge(const char *path)
 {
 			argc--;
 			break;
 		}
-		if (!strcmp(argv[1], "-q"))
+		if (!strcmp(argv[1], "-0"))
+			diff_unmerged_stage = 0;
+		else if (!strcmp(argv[1], "-1"))
+			diff_unmerged_stage = 1;
+		else if (!strcmp(argv[1], "-2"))
+			diff_unmerged_stage = 2;
+		else if (!strcmp(argv[1], "-3"))
+			diff_unmerged_stage = 3;
+		else if (!strcmp(argv[1], "--base"))
+			diff_unmerged_stage = 1;
+		else if (!strcmp(argv[1], "--ours"))
+			diff_unmerged_stage = 2;
+		else if (!strcmp(argv[1], "--theirs"))
+			diff_unmerged_stage = 3;
+		else if (!strcmp(argv[1], "-q"))
 			silent = 1;
 		else if (!strcmp(argv[1], "-r"))
 			; /* no-op */
 
 		if (ce_stage(ce)) {
 			show_unmerge(ce->name);
-			while (i < entries &&
-			       !strcmp(ce->name, active_cache[i]->name))
+			while (i < entries) {
+				struct cache_entry *nce = active_cache[i];
+
+				if (strcmp(ce->name, nce->name))
+					break;
+				/* diff against the proper unmerged stage */
+				if (ce_stage(nce) == diff_unmerged_stage)
+					ce = nce;
 				i++;
-			i--; /* compensate for loop control increments */
-			continue;
+			}
+			/*
+			 * Compensate for loop update
+			 */
+			i--;
+			/*
+			 * Show the diff for the 'ce' if we found the one
+			 * from the desired stage.
+			 */
+			if (ce_stage(ce) != diff_unmerged_stage)
+				continue;
 		}
 
 		if (lstat(ce->name, &st) < 0) {

File environment.c

 char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
 int only_use_symrefs = 0;
+int repository_format_version = 0;
+char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
 
 static char *git_dir, *git_object_dir, *git_index_file, *git_refs_dir,
 	*git_graft_file;

File fetch-pack.c

 	int fd[2];
 	pid_t pid;
 
+	setup_git_directory();
+
 	nr_heads = 0;
 	heads = NULL;
 	for (i = 1; i < argc; i++) {

File fsck-objects.c

 {
 	int i, heads;
 
+	setup_git_directory();
+
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 
 #!/bin/sh
 
+die () {
+    echo >&2 "$*"
+    exit 1
+}
+
 usage() {
     die "usage: git add [-n] [-v] <file>..."
 }

File git-applymbox.sh

 	-k)	keep_subject=-k ;;
 	-q)	query_apply=t ;;
 	-c)	continue="$2"; resume=f; shift ;;
-	-m)	fallback_3way=t ;;
+	-m)	fall_back_3way=t ;;
 	-*)	usage ;;
 	*)	break ;;
 	esac

File git-applypatch.sh

 	O_OBJECT=`cd "$GIT_OBJECT_DIRECTORY" && pwd`
 	rm -fr .patch-merge-*
 
+	if git-apply -z --index-info "$PATCHFILE" \
+		>.patch-merge-index-info 2>/dev/null &&
+		GIT_INDEX_FILE=.patch-merge-tmp-index \
+		git-update-index -z --index-info <.patch-merge-index-info &&
+		GIT_INDEX_FILE=.patch-merge-tmp-index \
+		git-write-tree >.patch-merge-tmp-base &&
+		(
+			mkdir .patch-merge-tmp-dir &&
+			cd .patch-merge-tmp-dir &&
+			GIT_INDEX_FILE="../.patch-merge-tmp-index" \
+			GIT_OBJECT_DIRECTORY="$O_OBJECT" \
+			git-apply $binary --index
+		) <"$PATCHFILE"
+	then
+		echo Using index info to reconstruct a base tree...
+		mv .patch-merge-tmp-base .patch-merge-base
+		mv .patch-merge-tmp-index .patch-merge-index
+	else
 	(
 		N=10
 
-		# if the patch records the base tree...
-		sed -ne '
-			/^diff /q
-			/^applies-to: \([0-9a-f]*\)$/{
-				s//\1/p
-				q
-			}
-		' "$PATCHFILE"
-
-		# or hoping the patch is against our recent commits...
+		# Otherwise, try nearby trees that can be used to apply the
+		# patch.
 		git-rev-list --max-count=$N HEAD
 
 		# or hoping the patch is against known tags...
 		git-ls-remote --tags .
 	) |
-	while read base junk
-	do
+	    while read base junk
+	    do
 		# Try it if we have it as a tree.
 		git-cat-file tree "$base" >/dev/null 2>&1 || continue
 
 			mv ../.patch-merge-tmp-index ../.patch-merge-index &&
 			echo "$base" >../.patch-merge-base
 		) <"$PATCHFILE"  2>/dev/null && break
-	done
+	    done
+	fi
 
 	test -f .patch-merge-index &&
 	his_tree=$(GIT_INDEX_FILE=.patch-merge-index git-write-tree) &&

File git-bisect.sh

 #!/bin/sh
 . git-sh-setup
 
+sq() {
+	perl -e '
+		for (@ARGV) {
+			s/'\''/'\'\\\\\'\''/g;
+			print " '\''$_'\''";
+		}
+		print "\n";
+	' "$@"
+}
+
 usage() {
     echo >&2 'usage: git bisect [start|bad|good|next|reset|visualize]
-git bisect start		reset bisect state and start bisection.
+git bisect start [<pathspec>]	reset bisect state and start bisection.
 git bisect bad [<rev>]		mark <rev> a known-bad revision.
 git bisect good [<rev>...]	mark <rev>... known-good revisions.
 git bisect next			find next bisection to test and check it out.
 }
 
 bisect_start() {
-        case "$#" in 0) ;; *) usage ;; esac
 	#
 	# Verify HEAD. If we were bisecting before this, reset to the
 	# top-of-line master first!
 	rm -f "$GIT_DIR/refs/heads/bisect"
 	rm -rf "$GIT_DIR/refs/bisect/"
 	mkdir "$GIT_DIR/refs/bisect"
-	echo "git-bisect start" >"$GIT_DIR/BISECT_LOG"
+	{
+	    echo -n "git-bisect start"
+	    sq "$@"
+	} >"$GIT_DIR/BISECT_LOG"
+	sq "$@" >"$GIT_DIR/BISECT_NAMES"
 }
 
 bisect_bad() {
 	bad=$(git-rev-parse --verify refs/bisect/bad) &&
 	good=$(git-rev-parse --sq --revs-only --not \
 		$(cd "$GIT_DIR" && ls refs/bisect/good-*)) &&
-	rev=$(eval "git-rev-list --bisect $good $bad") || exit
+	rev=$(eval "git-rev-list --bisect $good $bad -- $(cat $GIT_DIR/BISECT_NAMES)") || exit
 	if [ -z "$rev" ]; then
 	    echo "$bad was both good and bad"
 	    exit 1
 	    git-diff-tree --pretty $rev
 	    exit 0
 	fi
-	nr=$(eval "git-rev-list $rev $good" | wc -l) || exit
+	nr=$(eval "git-rev-list $rev $good -- $(cat $GIT_DIR/BISECT_NAMES)" | wc -l) || exit
 	echo "Bisecting: $nr revisions left to test after this"
 	echo "$rev" > "$GIT_DIR/refs/heads/new-bisect"
 	git checkout new-bisect || exit
 
 bisect_visualize() {
 	bisect_next_check fail
-	gitk bisect/bad --not `cd "$GIT_DIR/refs" && echo bisect/good-*`
+	not=`cd "$GIT_DIR/refs" && echo bisect/good-*`
+	eval gitk bisect/bad --not $not -- $(cat "$GIT_DIR/BISECT_NAMES")
 }
 
 bisect_reset() {
 		test "$bisect" = "git-bisect" || continue
 		case "$command" in
 		start)
-			bisect_start
+			cmd="bisect_start $rev"
+			eval "$cmd"
 			;;
 		good)
 			echo "$rev" >"$GIT_DIR/refs/bisect/good-$rev"

File git-branch.sh

 #!/bin/sh
 
-. git-sh-setup
+GIT_DIR=`git-rev-parse --git-dir` || exit $?
+
+die () {
+    echo >&2 "$*"
+    exit 1
+}
 
 usage () {
     echo >&2 "usage: $(basename $0)"' [-d <branch>] | [[-f] <branch> [start-point]]
     exit 1
 }
 
-headref=$(GIT_DIR="$GIT_DIR" git-symbolic-ref HEAD |
-	sed -e 's|^refs/heads/||')
+headref=$(git-symbolic-ref HEAD | sed -e 's|^refs/heads/||')
 
 delete_branch () {
     option="$1"
 	fi
 fi
 git update-ref "refs/heads/$branchname" $rev
-

File git-clone.sh

 	*,-n) no_checkout=yes ;;
 	*,-l|*,--l|*,--lo|*,--loc|*,--loca|*,--local) use_local=yes ;;
         *,-s|*,--s|*,--sh|*,--sha|*,--shar|*,--share|*,--shared) 
-          local_shared=yes ;;
+          local_shared=yes; use_local=yes ;;
 	*,-q|*,--quiet) quiet=-q ;;
 	1,-u|1,--upload-pack) usage ;;
 	*,-u|*,--upload-pack)

File git-count-objects.sh

 # Copyright (c) 2005 Junio C Hamano
 #
 
-. git-sh-setup
+GIT_DIR=`git-rev-parse --git-dir` || exit $?
 
 dc </dev/null 2>/dev/null || {
 	# This is not a real DC at all -- it just knows how
 flags=$(git-rev-parse --no-revs --flags --sq "$@")
 files=$(git-rev-parse --no-revs --no-flags --sq "$@")
 
-: ${flags:="'-M' '-p'"}
+die () {
+    echo >&2 "$*"
+    exit 1
+}
 
 # I often say 'git diff --cached -p' and get scolded by git-diff-files, but
 # obviously I mean 'git diff --cached -p HEAD' in that case.
 	esac
 esac
 
+# If we do not have --name-status, --name-only nor -r, default to -p.
+# If we do not have -B nor -C, default to -M.
+case " $flags " in
+*" '--name-status' "* | *" '--name-only' "* | *" '-r' "* )
+	;;
+*)
+	flags="$flags'-p' " ;;
+esac
+case " $flags " in
+*" '-"[BCM]* | *" '--find-copies-harder' "*)
+	;; # something like -M50.
+*)
+	flags="$flags'-M' " ;;
+esac
+
 case "$rev" in
 ?*' '?*' '?*)
 	echo >&2 "I don't understand"

File git-format-patch.sh

 
 . git-sh-setup
 
+# Force diff to run in C locale.
+LANG=C LC_ALL=C
+export LANG LC_ALL
+
 usage () {
     echo >&2 "usage: $0"' [-n] [-o dir | --stdout] [--keep-subject] [--mbox]
     [--check] [--signoff] [-<diff options>...]
 	    ;;
 	esac
 
-	eval "$(LANG=C LC_ALL=C sed -ne "$whosepatchScript" $commsg)"
+	eval "$(sed -ne "$whosepatchScript" $commsg)"
 	test "$author,$au" = ",$me" || {
 		mailScript="$mailScript"'
 	a\
 	echo
 	git-diff-tree -p $diff_opts "$commit" | git-apply --stat --summary
 	echo
-	git-cat-file commit "$commit^" | sed -e 's/^tree /applies-to: /' -e q
 	git-diff-tree -p $diff_opts "$commit"
-	echo "---"
+	echo "-- "
 	echo "@@GIT_VERSION@@"
 
 	case "$mbox" in
     file=`printf '%04d-%stxt' $i "$title"`
     if test '' = "$stdout"
     then
-	    echo "* $file"
+	    echo "$file"
 	    process_one >"$outdir$file"
 	    if test t = "$check"
 	    then
 		:
 	    fi
     else
-	    echo >&2 "* $file"
+	    echo >&2 "$file"
 	    process_one
     fi
     i=`expr "$i" + 1`

File git-lost-found.sh

 #!/bin/sh
 
-. git-sh-setup
-
+GIT_DIR=`git-rev-parse --git-dir` || exit $?
 laf="$GIT_DIR/lost-found"
 rm -fr "$laf" && mkdir -p "$laf/commit" "$laf/other" || exit
 

File git-ls-remote.sh

     exit 1;
 }
 
+die () {
+    echo >&2 "$*"
+    exit 1
+}
+
 while case "$#" in 0) break;; esac
 do
   case "$1" in

File git-merge-octopus.sh

 LF='
 '
 
+die () {
+    echo >&2 "$*"
+    exit 1
+}
+
 # The first parameters up to -- are merge bases; the rest are heads.
 bases= head= remotes= sep_seen=
 for arg

File git-merge-one-file.sh

 	fi
 	if test -f "$4"; then
 		rm -f -- "$4" &&
-		rmdir -p "$(expr "$4" : '\(.*\)/')" 2>/dev/null
+		rmdir -p "$(expr "$4" : '\(.*\)/')" 2>/dev/null || :
 	fi &&
 		exec git-update-index --remove -- "$4"
 	;;
 # Modified in both, but differently.
 #
 "$1$2$3" | ".$2$3")
+
+	case ",$6,$7," in
+	*,120000,*)
+		echo "ERROR: $4: Not merging symbolic link changes."
+		exit 1
+		;;
+	esac
+
 	src2=`git-unpack-file $3`
 	case "$1" in
 	'')
 		;;
 	esac
 
-	# We reset the index to the first branch, making
-	# git-diff-file useful
-	git-update-index --add --cacheinfo "$6" "$2" "$4"
-		git-checkout-index -u -f -- "$4" &&
+	# Create the working tree file, with the correct permission bits.
+	# we can not rely on the fact that our tree has the path, because
+	# we allow the merge to be done in an unchecked-out working tree.
+	rm -f "$4" &&
+		git-cat-file blob "$2" >"$4" &&
+		case "$6" in *7??) chmod +x "$4" ;; esac &&
 		merge "$4" "$orig" "$src2"
 	ret=$?
 	rm -f -- "$orig" "$src2"

File git-merge-recursive.py

 def getFilesAndDirs(tree):
     files = Set()
     dirs = Set()
-    out = runProgram(['git-ls-tree', '-r', '-z', tree])
+    out = runProgram(['git-ls-tree', '-r', '-z', '-t', tree])
     for l in out.split('\0'):
         m = getFilesRE.match(l)
         if m:
             if cacheOnly:
                 updateFile(False, sha, mode, path)
             else:
-                updateFileExt(aSha, aMode, path,
-                              updateCache=True, updateWd=False)
                 updateFileExt(sha, mode, path, updateCache=False, updateWd=True)
     else:
         die("ERROR: Fatal merge failure, shouldn't happen.")

File git-merge.sh

 case "$best_strategy" in
 '')
 	restorestate
-	die "No merge strategy handled the merge."
+	echo >&2 "No merge strategy handled the merge."
+	exit 2
 	;;
 "$wt_strategy")
 	# We already have its result in the working tree.
 
 sub usage() {
 	print <<EOT;
-$0 [-f] [-n] <source> <dest>
-$0 [-f] [-k] [-n] <source> ... <dest directory>
-
-In the first form, source must exist and be either a file,
-symlink or directory, dest must not exist. It renames source to dest.
-In the second form, the last argument has to be an existing
-directory; the given sources will be moved into this directory.
-
-Updates the git cache to reflect the change.
-Use "git commit" to make the change permanently.
-
-Options:
-  -f   Force renaming/moving, even if target exists
-  -k   Continue on error by skipping
-       not-existing or not revision-controlled source
-  -n   Do nothing; show what would happen
+$0 [-f] [-n] <source> <destination>
+$0 [-f] [-n] [-k] <source> ... <destination directory>
 EOT
 	exit(1);
 }
 
-# Sanity checks:
-my $GIT_DIR = $ENV{'GIT_DIR'} || ".git";
-
-unless ( -d $GIT_DIR && -d $GIT_DIR . "/objects" && 
-	-d $GIT_DIR . "/objects/" && -d $GIT_DIR . "/refs") {
-    print "Git repository not found.";
-    usage();
-}
-
+my $GIT_DIR = `git rev-parse --git-dir`;
+exit 1 if $?; # rev-parse would have given "not a git dir" message.
+chomp($GIT_DIR);
 
 our ($opt_n, $opt_f, $opt_h, $opt_k, $opt_v);
 getopts("hnfkv") || usage;
 	print "Error: moving to directory '"
 	    . $ARGV[$argCount-1]
 	    . "' not possible; not exisiting\n";
-	usage;
+	exit(1);
     }
     @srcArgs = ($ARGV[0]);
     @dstArgs = ($ARGV[1]);
 	}
     }
     
-    if (($bad eq "") && ($src eq $dstDir)) {
+    if (($bad eq "") && ($dst =~ /^$safesrc\//)) {
 	$bad = "can not move directory '$src' into itself";
     }
 
 	    next;
 	}
 	print "Error: $bad\n";
-	usage();
+	exit(1);
     }
     push @srcs, $src;
     push @dsts, $dst;
 
 # Final pass: rename/move
 my (@deletedfiles,@addedfiles,@changedfiles);
+$bad = "";
 while(scalar @srcs > 0) {
     $src = shift @srcs;
     $dst = shift @dsts;
 
     if ($opt_n || $opt_v) { print "Renaming $src to $dst\n"; }
     if (!$opt_n) {
-	rename($src,$dst)
-	    or die "rename failed: $!";
+	if (!rename($src,$dst)) {
+	    $bad = "renaming '$src' failed: $!";
+	    if ($opt_k) {
+		print "Warning: skipped: $bad\n";
+		$bad = "";
+		next;
+	    }
+	    last;
+	}
     }
 
     $safesrc = quotemeta($src);
 }
 
 if ($opt_n) {
+    if (@changedfiles) {
 	print "Changed  : ". join(", ", @changedfiles) ."\n";
+    }
+    if (@addedfiles) {
 	print "Adding   : ". join(", ", @addedfiles) ."\n";
+    }
+    if (@deletedfiles) {
 	print "Deleting : ". join(", ", @deletedfiles) ."\n";
-	exit(1);
+    }
 }
-	
-my $rc;
-if (scalar @changedfiles >0) {
-	$rc = system("git-update-index","--",@changedfiles);
-	die "git-update-index failed to update changed files with code $?\n" if $rc;
+else {
+    if (@changedfiles) {
+	open(H, "| git-update-index -z --stdin")
+		or die "git-update-index failed to update changed files with code $!\n";
+	foreach my $fileName (@changedfiles) {
+		print H "$fileName\0";
+	}
+	close(H);
+    }
+    if (@addedfiles) {
+	open(H, "| git-update-index --add -z --stdin")
+		or die "git-update-index failed to add new names with code $!\n";
+	foreach my $fileName (@addedfiles) {
+		print H "$fileName\0";
+	}
+	close(H);
+    }
+    if (@deletedfiles) {
+	open(H, "| git-update-index --remove -z --stdin")
+		or die "git-update-index failed to remove old names with code $!\n";
+	foreach my $fileName (@deletedfiles) {
+		print H "$fileName\0";
+	}
+	close(H);
+    }
 }
-if (scalar @addedfiles >0) {
-	$rc = system("git-update-index","--add","--",@addedfiles);
-	die "git-update-index failed to add new names with code $?\n" if $rc;
+
+if ($bad ne "") {
+    print "Error: $bad\n";
+    exit(1);
 }
-$rc = system("git-update-index","--remove","--",@deletedfiles);
-die "git-update-index failed to remove old names with code $?\n" if $rc;

File git-rebase.sh

 
 . git-sh-setup
 
-# The other head is given
+# Make sure we do not have .dotest
+if mkdir .dotest
+then
+	rmdir .dotest
+else
+	echo >&2 '
+It seems that I cannot create a .dotest directory, and I wonder if you
+are in the middle of patch application or another rebase.  If that is not
+the case, please rm -fr .dotest and run me again.  I am stopping in case
+you still have something valuable there.'
+	exit 1
+fi
+
+# The other head is given.  Make sure it is valid.
 other=$(git-rev-parse --verify "$1^0") || exit
 
+# Make sure we have HEAD that is valid.
+head=$(git-rev-parse --verify "HEAD^0") || exit
+
 # The tree must be really really clean.
 git-update-index --refresh || exit
 diff=$(git-diff-index --cached --name-status -r HEAD)
 	git-checkout "$2" || exit
 esac
 
+# If the HEAD is a proper descendant of $other, we do not even need
+# to rebase.  Make sure we do not do needless rebase.  In such a
+# case, merge-base should be the same as "$other".
+mb=$(git-merge-base "$other" "$head")
+if test "$mb" = "$other"
+then
+	echo >&2 "Current branch `git-symbolic-ref HEAD` is up to date."
+	exit 0
+fi
+
 # Rewind the head to "$other"
 git-reset --hard "$other"
 git-format-patch -k --stdout --full-index "$other" ORIG_HEAD |

File git-svnimport.perl

 sub usage() {
 	print STDERR <<END;
 Usage: ${\basename $0}     # fetch/update GIT from SVN
-       [-o branch-for-HEAD] [-h] [-v] [-l max_num_changes]
+       [-o branch-for-HEAD] [-h] [-v] [-l max_rev]
        [-C GIT_repository] [-t tagname] [-T trunkname] [-b branchname]
        [-d|-D] [-i] [-u] [-s start_chg] [-m] [-M regex] [SVN_URL]
 END
 package main;
 use URI;
 
-my $svn = $svn_url;
+our $svn = $svn_url;
 $svn .= "/$svn_dir" if defined $svn_dir;
+my $svn2 = SVNconn->new($svn);
 $svn = SVNconn->new($svn);
 
 my $lwp_ua;
 my $maxnum = 0;
 my $last_rev = "";
 my $last_branch;
-my $current_rev = $opt_s-1;
+my $current_rev = $opt_s || 1;
 unless(-d $git_dir) {
 	system("git-init-db");
 	die "Cannot init the GIT db at $git_tree: $?\n" if $?;
 		my($num,$branch,$ref) = split;
 		$branches{$branch}{$num} = $ref;
 		$branches{$branch}{"LAST"} = $ref;
-		$current_rev = $num if $current_rev < $num;
+		$current_rev = $num+1 if $current_rev <= $num;
 	}
 	close($B);
 }
 	print "DONE: $revision $dest $cid\n" if $opt_v;
 }
 
-my ($changed_paths, $revision, $author, $date, $message, $pool) = @_;
-sub _commit_all {
-	($changed_paths, $revision, $author, $date, $message, $pool) = @_;
+sub commit_all {
+	# Recursive use of the SVN connection does not work
+	local $svn = $svn2;
+
+	my ($changed_paths, $revision, $author, $date, $message, $pool) = @_;
 	my %p;
 	while(my($path,$action) = each %$changed_paths) {
 		$p{$path} = [ $action->action,$action->copyfrom_path, $action->copyfrom_rev, $path ];
 	}
 	$changed_paths = \%p;
-}
 
-sub commit_all {
 	my %done;
 	my @col;
 	my $pref;
 	}
 }
 
-while(++$current_rev <= $svn->{'maxrev'}) {
-	if (defined $opt_l) {
-		$opt_l--;
-		if ($opt_l < 0) {
-			last;
-		}
-	}
-	my $pool=SVN::Pool->new;
-	$svn->{'svn'}->get_log("/",$current_rev,$current_rev,1,1,1,\&_commit_all,$pool);
-	$pool->clear;
-	commit_all();
-}
+$opt_l = $svn->{'maxrev'} if not defined $opt_l or $opt_l > $svn->{'maxrev'};
+print "Fetching from $current_rev to $opt_l ...\n" if $opt_v;
+
+my $pool=SVN::Pool->new;
+$svn->{'svn'}->get_log("/",$current_rev,$opt_l,0,1,1,\&commit_all,$pool);
+$pool->clear;
 
 
 unlink($git_index);
 #!/bin/sh
 # Copyright (c) 2005 Linus Torvalds
 
-. git-sh-setup
+GIT_DIR=`git-rev-parse --git-dir` || exit $?
 
 usage () {
     echo >&2 "Usage: git-tag [-a | -s | -u <key-id>] [-f | -d] [-m <msg>] <tagname> [<head>]"
     exit 1
 }
 
+die () {
+    echo >&2 "$*"
+    exit 1
+}
+
 annotate=
 signed=
 force=

File git-verify-tag.sh

 #!/bin/sh
-. git-sh-setup
+
+GIT_DIR=`git-rev-parse --git-dir` || exit $?
+
+die () {
+    echo >&2 "$*"
+    exit 1
+}
 
 type="$(git-cat-file -t "$1" 2>/dev/null)" ||
 	die "$1: no such object."
 test "$type" = tag ||
 	die "$1: cannot verify a non-tag object of type $type."
 
-git-cat-file tag "$1" > .tmp-vtag || exit 1
-cat .tmp-vtag | sed '/-----BEGIN PGP/Q' | gpg --verify .tmp-vtag - || exit 1
-rm -f .tmp-vtag
+git-cat-file tag "$1" >"$GIT_DIR/.tmp-vtag" || exit 1
+cat "$GIT_DIR/.tmp-vtag" |
+sed '/-----BEGIN PGP/Q' |
+gpg --verify "$GIT_DIR/.tmp-vtag" - || exit 1
+rm -f "$GIT_DIR/.tmp-vtag"
+
 # define PATH_MAX 4096
 #endif
 
+#ifdef NO_SETENV
+extern int gitsetenv(char *name, char *value, int overwrite);
+#endif
+
 static const char git_usage[] =
 	"Usage: git [--version] [--exec-path[=GIT_EXEC_PATH]] [--help] COMMAND [ ARGS ]";
 
 	len = strlen(git_command);
 	prepend_to_path(git_command, len);
 
-	strncat(&git_command[len], "/git-", sizeof(git_command) - len);
-	len += 5;
-	strncat(&git_command[len], argv[i], sizeof(git_command) - len);
-
-	if (access(git_command, X_OK))
-		usage(exec_path, "'%s' is not a git-command", argv[i]);
+	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 (%d)\n", len);
+		exit(1);
+	}
 
 	/* execve() can only ever return if it fails */
 	execve(git_command, &argv[i], envp);
-	printf("Failed to run command '%s': %s\n", git_command, strerror(errno));
+
+	if (errno == ENOENT)
+		usage(exec_path, "'%s' is not a git-command", argv[i]);
+
+	fprintf(stderr, "Failed to run command '%s': %s\n",
+		git_command, strerror(errno));
 
 	return 1;
 }
 proc getcommits {rargs} {
     global commits commfd phase canv mainfont env
     global startmsecs nextupdate ncmupdate
-    global ctext maincursor textcursor leftover
+    global ctext maincursor textcursor leftover gitencoding
 
     # check that we can find a .git directory somewhere...
     set gitdir [gitdir]
     set commits {}
     set phase getcommits
     set startmsecs [clock clicks -milliseconds]
-    set nextupdate [expr $startmsecs + 100]
+    set nextupdate [expr {$startmsecs + 100}]
     set ncmupdate 1
     if [catch {
 	set parse_args [concat --default HEAD $rargs]
 	exit 1
     }
     set leftover {}
-    fconfigure $commfd -blocking 0 -translation lf
+    fconfigure $commfd -blocking 0 -translation lf -encoding $gitencoding
     fileevent $commfd readable [list getcommitlines $commfd]
     $canv delete all
     $canv create text 3 3 -anchor nw -text "Reading commits..." \
 	}
 	if {[string range $err 0 4] == "usage"} {
 	    set err \
-{Gitk: error reading commits: bad arguments to git-rev-list.
-(Note: arguments to gitk are passed to git-rev-list
-to allow selection of commits to be displayed.)}
+		"Gitk: error reading commits: bad arguments to git-rev-list.\
+		(Note: arguments to gitk are passed to git-rev-list\
+		to allow selection of commits to be displayed.)"
 	} else {
 	    set err "Error reading commits: $err"
 	}
     global findtype findtypemenu findloc findstring fstring geometry
     global entries sha1entry sha1string sha1but
     global maincursor textcursor curtextcursor
-    global rowctxmenu gaudydiff mergemax
+    global rowctxmenu mergemax
 
     menu .bar
     .bar add cascade -label "File" -menu .bar.file
     menu .bar.file
     .bar.file add command -label "Reread references" -command rereadrefs
     .bar.file add command -label "Quit" -command doquit
+    menu .bar.edit
+    .bar add cascade -label "Edit" -menu .bar.edit
+    .bar.edit add command -label "Preferences" -command doprefs
     menu .bar.help
     .bar add cascade -label "Help" -menu .bar.help
     .bar.help add command -label "About gitk" -command about
     . configure -menu .bar
 
     if {![info exists geometry(canv1)]} {
-	set geometry(canv1) [expr 45 * $charspc]
-	set geometry(canv2) [expr 30 * $charspc]
-	set geometry(canv3) [expr 15 * $charspc]
-	set geometry(canvh) [expr 25 * $linespc + 4]
+	set geometry(canv1) [expr {45 * $charspc}]
+	set geometry(canv2) [expr {30 * $charspc}]
+	set geometry(canv3) [expr {15 * $charspc}]
+	set geometry(canvh) [expr {25 * $linespc + 4}]
 	set geometry(ctextw) 80
 	set geometry(ctexth) 30
 	set geometry(cflistw) 30
     .ctop.cdet add .ctop.cdet.left
 
     $ctext tag conf filesep -font [concat $textfont bold] -back "#aaaaaa"
-    if {$gaudydiff} {
-	$ctext tag conf hunksep -back blue -fore white
-	$ctext tag conf d0 -back "#ff8080"
-	$ctext tag conf d1 -back green
-    } else {
-	$ctext tag conf hunksep -fore blue
-	$ctext tag conf d0 -fore red
-	$ctext tag conf d1 -fore "#00a000"
-	$ctext tag conf m0 -fore red
-	$ctext tag conf m1 -fore blue
-	$ctext tag conf m2 -fore green
-	$ctext tag conf m3 -fore purple
-	$ctext tag conf m4 -fore brown
-	$ctext tag conf mmax -fore darkgrey
-	set mergemax 5
-	$ctext tag conf mresult -font [concat $textfont bold]
-	$ctext tag conf msep -font [concat $textfont bold]
-	$ctext tag conf found -back yellow
-    }
+    $ctext tag conf hunksep -fore blue
+    $ctext tag conf d0 -fore red
+    $ctext tag conf d1 -fore "#00a000"
+    $ctext tag conf m0 -fore red
+    $ctext tag conf m1 -fore blue
+    $ctext tag conf m2 -fore green
+    $ctext tag conf m3 -fore purple
+    $ctext tag conf m4 -fore brown
+    $ctext tag conf mmax -fore darkgrey
+    set mergemax 5
+    $ctext tag conf mresult -font [concat $textfont bold]
+    $ctext tag conf msep -font [concat $textfont bold]
+    $ctext tag conf found -back yellow
 
     frame .ctop.cdet.right
     set cflist .ctop.cdet.right.cfiles
 
 proc savestuff {w} {
     global canv canv2 canv3 ctext cflist mainfont textfont
-    global stuffsaved findmergefiles gaudydiff maxgraphpct
+    global stuffsaved findmergefiles maxgraphpct