git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download mbox.gz: |
* Git-aware Darcs: a tutorial
@ 2005-05-09 16:29  2% Juliusz Chroboczek
  0 siblings, 0 replies; 200+ results
From: Juliusz Chroboczek @ 2005-05-09 16:29 UTC (permalink / raw)
  To: darcs-devel; +Cc: darcs-users, Git Mailing List

0. What is Darcs-git

Darcs-git is a branch of Darcs that can work with Git repositories.

Darcs-git is deliberately Darcs, not Git.  All commands either work in
the same way on Git repositories as on Darcs repositories, or they
fail.  If you're a Darcs user, you'll like darcs-git.  If you're a Git
user, you'll probably find it infuriating.

On the other hand, Darcs-git uses stock Git repositories; a Darcs
command either works as-is on a Git repository, or fails.


1. What you can expect

The following should work reasonably well on Git repositories:

  darcs changes
  darcs whatsnew
  darcs pull
  darcs send
  darcs record

The following commands work, but have serious performance problems:

  darcs diff
  darcs changes with a file argument

The following commands should in principle work but haven't been tested:

  darcs add
  darcs remove
  darcs dist
  darcs trackdown

The following commands don't work because I'm lazy::

  darcs push
  darcs unrecord
  darcs unpull
  darcs amend-record
  darcs annotate
  darcs rollback

The following commands only work on native Darcs repositories, either
because they don't make sense on Git repositories, or because there
are perfectly good native Git tools to perform their function:

  darcs initialize
  darcs get/put
  darcs check
  darcs repair
  darcs optimize
  darcs mv
  darcs replace
  darcs resolve
  darcs tag
  darcs setpref

Remote Git repositories are not supported.


2. A tutorial

(0) Build darcs-git

  $ darcs get --partial http://www.pps.jussieu.fr/~jch/software/repos/darcs-git
  $ cd darcs-git
  $ make darcs
  $ make Context.hs
  $ make darcs
  $ cp darcs ~/bin/

(1) Get a copy of the Linux Git repository:

  $ cd /usr/local/src
  $ mkdir linux-2.6
  $ cd linux-2.6
  $ rsync -r rsync://rsync.kernel.org/pub/linux/kernel/people/torvalds/linux-2.6.git .git
  $ curl http://rsync.kernel.org/pub/linux/kernel/people/torvalds/linux-2.6.git/HEAD > .git/HEAD

We still need to bring the cache and working directory into a state
that Darcs will be happy with.  While this could in principle be done
with Darcs itself, it will be faster to do it with Git:

  $ read-tree `cat .git/HEAD`
  $ checkout-cache -a
  $ update-cache --refresh

(2) Check what the friendly Linux hackers have been up to:

  $ darcs changes | more
  $ darcs changes -s | more

(3) Create a local clone of the Linux repository:

  $ cd ..
  $ mkdir linux-2.6-local
  $ mkdir linux-2.6-local/.git
  $ ln -s `pwd`/linux-2.6/.git/objects linux-2.6-local/.git
  $ cp linux-2.6/.git/HEAD linux-2.6-local/.git
  $ cd linux-2.6-local
  $ read-tree `cat .git/HEAD`
  $ checkout-cache -a
  $ update-cache --refresh

(4) Commit some work

First, check that Darcs is happy with the new repository.

  $ darcs whatsnew

This should take a few seconds at most; if it takes minutes instead,
try running ``update-cache --refresh''.

Okay, let's add myself to the list of Linux maintainers.

  $ echo 'P:    Juliusz Chroboczek' >> MAINTAINERS

Let's see if Darcs agrees.

  $ darcs whatsnew -s
  $ darcs whatsnew

Everything looks fine, let's record (commit) this patch.

  $ darcs record -a
  $ darcs changes | more
  $ darcs changes -s | more

(5) Send it upstream

If Linus were using Darcs, we could just send him a Darcs patch, which
is a patch-like data structure that contains just enough context
information to allow Darcs to perform a history-sensitive merge:

  $ darcs send ../linux-2.6

However, until Linus switches to Darcs, we're stuck with old-fashioned
patches.

  $ darcs diff -u --patch='.' | mail bill@microsoft.com

Unfortunately, until I've spent some time optimising ``darcs diff'',
the above won't terminate on a repository the size of Linux'.


3. Caveats

There is little input validation.  In particular, if you enter an
e-mail address that doesn't end in ``>'', Darcs will write a commit
that neither Git nor Darcs itself will be able to parse.

Darcs never updates the Git cache.  If you perform many commits using
Darcs, you'll need to manually run ``update-cache --refresh''.

Darcs treats Git merges by reverse-engineering a Darcs merge (thanks
to David Roundy for outlining how that can be done).  In practice,
this means that Darcs will collapse as soon as it sees a nontrivial
Git merge.

^ permalink raw reply	[relevance 2%]

* Re: [PATCH] rev-list: add "--full-objects" flag.
  @ 2005-07-11 16:38  1%                                 ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-07-11 16:38 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Junio C Hamano, git



On Mon, 11 Jul 2005, Eric W. Biederman wrote:
> 
> I guess I was expecting to pull from one tree into another unrelated
> tree.  Getting a tree with two heads and then be able to merge them
> together.

You can do it, but you have to do it by hand. It's a valid operation, but 
it's not an operation I want people to do by mistake, so it's not 
something the trivial helper scripts help with.

The way to do it by hand is to just use something stupid that doesn't
understand what it's doing anyway, and just copy the files over. "cp -a" 
or "rsync" works fine. Then just do "git resolve" by hand. It's not very 
hard at all, but it's definitely something that should be a special case.

> A couple of questions.
> 
> 1) Does git-clone-script when packed copy the entire repository
>    or just take a couple of slices of the tree where you have
>    references?

It only gets the objects needed for the references, nothing more.

So if you only get one branch, it will leave the objects that are specific 
to other branches alone.

> 2) Is there a way for a pack to create deltas against objects
>    that are not in the tree?  For a dumb repository making incremental
>    changes this is ideal.

A pack can only have deltas against objects in that pack. It caan't even 
have deltas to other objects in the same tree, it literally is only 
_within_ a pack. This is so that each pack is totally independent: you can 
always unpack (and verify) the objects in a pack _without_ having anything 
else (of course, the end result is often not a full project, and you won't 
have any references, but at least the _objects_ are valid).

I don't want to have deltas to outside the pack, because while it's 
obviously very nice from a size packing standpoint, it's totally horrid 
from an infrastructure standpoint. It would make it possible to have 
circular dependencies (ie deltas against each other) that could only be 
resolved by having a third pack (or the unpacked object).

It would also means that you may have to have two packs mapped at the same
time to unpack them, which was very much against what I was aiming for: I
think that in the long run, for truly huge projects, you'd want to have a
history of packs, each maybe a gigabyte in size, and you may be in the 
situation that you simply cannot have two packs mapped at the same time 
because you don't have enough virtual memory for it.

So then inter-pack deltas would mean that you'd have to have "partial pack 
mapping" etc horrid special case logic. Right now, because a pack is 
always self-sufficient, you know that in order to unpack an object, if you 
find it in the index file, you will be able to unpack it by just mapping 
that pack and going off..

So the rule is: don't pack too often. The unpacked objects are actually 
working really really well as long as you don't have tens of thousands of 
them. Having a few hundred (or even a few thousand) unpacked objects is 
not a problem at all. Then you do a "git repack" when it starts getting 
uncomfortable, and you you continue.

			Linus

^ permalink raw reply	[relevance 1%]

* [PATCH] fetch/pull: short-hand notation for remote repositories.
  @ 2005-07-16  7:16  3%       ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-07-16  7:16 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Since pull and fetch are done often against the same remote
repository repeatedly, keeping the URL to pull from along with
the name of the head to use in $GIT_DIR/branches/$name makes a
lot of sense.  Adopt that convention from Cogito, and try to be
compatible when possible; storing a partial URL and completing
it with a trailing path may not be understood by Cogito.

While we are at it, fix pulling a tag.  Earlier, we updated only
refs/tags/$tag without updating FETCH_HEAD, and called
resolve-script using a stale (or absent) FETCH_HEAD.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 Makefile         |    2 +
 git-fetch-script |   36 ++++++++++++++-----------
 git-parse-remote |   79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 git-pull-script  |   19 ++-----------
 4 files changed, 104 insertions(+), 32 deletions(-)
 create mode 100755 git-parse-remote

431b72ee18b73aac44048ac6c4cb62e0618c6f6e
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -36,7 +36,7 @@ SCRIPTS=git git-apply-patch-script git-m
 	git-reset-script git-add-script git-checkout-script git-clone-script \
 	gitk git-cherry git-rebase-script git-relink-script git-repack-script \
 	git-format-patch-script git-sh-setup-script git-push-script \
-	git-branch-script
+	git-branch-script git-parse-remote
 
 PROG=   git-update-cache git-diff-files git-init-db git-write-tree \
 	git-read-tree git-commit-tree git-cat-file git-fsck-cache \
diff --git a/git-fetch-script b/git-fetch-script
--- a/git-fetch-script
+++ b/git-fetch-script
@@ -1,33 +1,39 @@
 #!/bin/sh
 #
-destination=FETCH_HEAD
-
-merge_repo=$1
-merge_name=${2:-HEAD}
-if [ "$2" = "tag" ]; then
-	merge_name="refs/tags/$3"
-	destination="$merge_name"
-fi
-
 . git-sh-setup-script || die "Not a git archive"
+. git-parse-remote "$@"
+merge_repo="$_remote_repo"
+merge_head="$_remote_head"
+merge_store="$_remote_store"
 
 TMP_HEAD="$GIT_DIR/TMP_HEAD"
 
 case "$merge_repo" in
 http://*)
-	head=$(wget -q -O - "$merge_repo/$merge_name") || exit 1
-	echo Fetching $head using http
-	git-http-pull -v -a "$head" "$merge_repo/"
+	head=$(wget -q -O - "$merge_repo/$merge_head") || exit 1
+	echo Fetching "$merge_head" using http
+	git-http-pull -v -a "$merge_head" "$merge_repo/"
 	;;
 rsync://*)
-	rsync -L "$merge_repo/$merge_name" "$TMP_HEAD" || exit 1
+	rsync -L "$merge_repo/$merge_head" "$TMP_HEAD" || exit 1
 	head=$(git-rev-parse TMP_HEAD)
 	rm -f "$TMP_HEAD"
 	rsync -avz --ignore-existing "$merge_repo/objects/" "$GIT_OBJECT_DIRECTORY/"
 	;;
 *)
-	head=$(git-fetch-pack "$merge_repo" "$merge_name")
+	head=$(git-fetch-pack "$merge_repo" "$merge_head")
 	;;
 esac || exit 1
+
 git-rev-parse --verify "$head" > /dev/null || exit 1
-echo "$head" > "$GIT_DIR/$destination"
+
+case "$merge_store" in
+'')
+	echo "$head" > "$GIT_DIR/$merge_store"
+esac &&
+
+# FETCH_HEAD is fed to git-resolve-script which will eventually be
+# passed to git-commit-tree as one of the parents.  Make sure we do
+# not give a tag object ID.
+
+git-rev-parse "$head^0" >"$GIT_DIR/FETCH_HEAD"
diff --git a/git-parse-remote b/git-parse-remote
new file mode 100755
--- /dev/null
+++ b/git-parse-remote
@@ -0,0 +1,79 @@
+: To be included in git-pull and git-fetch scripts.
+
+# A remote repository can be specified on the command line
+# in one of the following formats:
+#
+#	<repo>
+#	<repo> <head>
+#	<repo> tag <tag>
+#
+# where <repo> could be one of:
+#
+#	a URL (including absolute or local pathname)
+#	a short-hand
+#	a short-hand followed by a trailing path
+#
+# A short-hand <name> has a corresponding file $GIT_DIR/branches/<name>,
+# whose contents is a URL, possibly followed by a URL fragment #<head>
+# to name the default branch on the remote side to fetch from.
+
+_remote_repo= _remote_store= _remote_head= _remote_name=
+
+case "$1" in
+*:* | /* | ../* | ./* )
+	_remote_repo="$1"
+	;;
+* )
+	# otherwise, it is a short hand.
+	case "$1" in
+	*/*)
+		# a short-hand followed by a trailing path
+		_token=$(expr "$1" : '\([^/]*\)/')
+		_rest=$(expr "$1" : '[^/]*\(/.*\)$')
+		;;
+	*)
+		_token="$1"
+		_rest=
+		_remote_store="refs/heads/$_token"
+		;;
+	esac
+	test -f "$GIT_DIR/branches/$_token" ||
+	die "No such remote branch: $_token"
+
+	_remote_repo=$(cat "$GIT_DIR/branches/$_token")"$_rest"
+	;;
+esac
+
+case "$_remote_repo" in
+*"#"*)
+	_remote_head=`expr "$_remote_repo" : '.*#\(.*\)$'`
+	_remote_repo=`expr "$_remote_repo" : '\(.*\)#'`
+	;;
+esac
+
+_remote_name=$(echo "$_remote_repo" | sed 's|\.git/*$||')
+
+case "$2" in
+tag)
+	_remote_name="tag '$3' of $_remote_name"
+	_remote_head="refs/tags/$3"
+	_remote_store="$_remote_head"
+	;;
+?*)
+	# command line specified a head explicitly; do not
+	# store the fetched head as a branch head.
+	_remote_name="head '$2' of $_remote_name"
+	_remote_head="refs/heads/$2"
+	_remote_store=''
+	;;
+'')
+	case "$_remote_head" in
+	'')
+		_remote_head=HEAD ;;
+	*)
+		_remote_head="refs/heads/$_remote_head"
+		_remote_name="head '$_remote_head' of $_remote_name"
+		;;
+	esac
+	;;
+esac
diff --git a/git-pull-script b/git-pull-script
--- a/git-pull-script
+++ b/git-pull-script
@@ -1,23 +1,10 @@
 #!/bin/sh
 #
 . git-sh-setup-script || die "Not a git archive"
+. git-parse-remote "$@"
+merge_name="$_remote_name"
 
-merge_repo=$1
-
-merge_name=$(echo "$1" | sed 's:\.git/*$::')
-merge_head=HEAD
-type=head
-if [ "$2" = "tag" ]; then
-   type=tag
-   shift
-fi
-if [ "$2" ]
-then
-   merge_name="$type '$2' of $merge_name"
-   merge_head="refs/${type}s/$2"
-fi
-
-git-fetch-script "$merge_repo" "$merge_head" || exit 1
+git-fetch-script "$@" || exit 1
 
 git-resolve-script \
 	"$(cat "$GIT_DIR"/HEAD)" \

^ permalink raw reply	[relevance 3%]

* [PATCH 1/3] Start adding the $GIT_DIR/remotes/ support.
  @ 2005-08-18  7:39  6% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-08-18  7:39 UTC (permalink / raw)
  To: GIT mailing list; +Cc: Junio C Hamano

All the necessary parsing code is in git-parse-remote-script;
update git-push-script to use it.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---

 Makefile                |    2 -
 git-parse-remote-script |  122 +++++++++++++++++++++++++++++++++++++++++++++++
 git-push-script         |   28 ++---------
 3 files changed, 129 insertions(+), 23 deletions(-)
 create mode 100755 git-parse-remote-script

f8892bf17675056cd18a252d3bc4e4ba381fb3bc
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -64,7 +64,7 @@ SCRIPTS=git git-apply-patch-script git-m
 	git-reset-script git-add-script git-checkout-script git-clone-script \
 	gitk git-cherry git-rebase-script git-relink-script git-repack-script \
 	git-format-patch-script git-sh-setup-script git-push-script \
-	git-branch-script git-parse-remote git-verify-tag-script \
+	git-branch-script git-parse-remote git-parse-remote-script git-verify-tag-script \
 	git-ls-remote-script git-clone-dumb-http git-rename-script \
 	git-request-pull-script git-bisect-script
 
diff --git a/git-parse-remote-script b/git-parse-remote-script
new file mode 100755
--- /dev/null
+++ b/git-parse-remote-script
@@ -0,0 +1,122 @@
+#!/bin/sh
+
+. git-sh-setup-script || die "Not a git archive"
+
+get_data_source () {
+	case "$1" in
+	*/*)
+		# Not so fast.  This could be the partial URL shorthand...
+		token=$(expr "$1" : '\([^/]*\)/')
+		remainder=$(expr "$1" : '[^/]*/\(.*\)')
+		if test -f "$GIT_DIR/branches/$token"
+		then
+			echo branches-partial
+		else
+			echo ''
+		fi
+		;;
+	*)
+		if test -f "$GIT_DIR/remotes/$1"
+		then
+			echo remotes
+		elif test -f "$GIT_DIR/branches/$1"
+		then
+			echo branches
+		else
+			echo ''
+		fi ;;
+	esac
+}
+
+get_remote_url () {
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'')
+		echo "$1" ;;
+	remotes)
+		sed -ne '/^URL: */{
+			s///p
+			q
+		}' "$GIT_DIR/remotes/$1" ;;
+	branches)
+		sed -e 's/#.*//' "$GIT_DIR/branches/$1" ;;
+	branches-partial)
+		token=$(expr "$1" : '\([^/]*\)/')
+		remainder=$(expr "$1" : '[^/]*/\(.*\)')
+		url=$(sed -e 's/#.*//' "$GIT_DIR/branches/$token")
+		echo "$url/$remainder"
+		;;
+	*)
+		die "internal error: get-remote-url $1" ;;
+	esac
+}
+
+get_remote_default_refs_for_push () {
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'' | branches | branches-partial)
+		;; # no default push mapping, just send matching refs.
+	remotes)
+		sed -ne '/^Push: */{
+			s///p
+		}' "$GIT_DIR/remotes/$1" ;;
+	*)
+		die "internal error: get-remote-default-ref-for-push $1" ;;
+	esac
+}
+
+# Subroutine to caninicalize remote:local notation
+canon_refs_list_for_fetch () {
+	for ref
+	do
+		expr "$ref" : '.*:' >/dev/null || ref="${ref}:"
+		remote=$(expr "$ref" : '\([^:]*\):')
+		local=$(expr "$ref" : '[^:]*:\(.*\)')
+		case "$remote" in
+		'') remote=HEAD ;;
+		*) remote="refs/heads/$remote" ;;
+		esac
+		case "$local" in
+		'') local= ;;
+		*) local="refs/heads/$local" ;;
+		esac
+		echo "${remote}:${local}"
+	done
+}
+
+# Returns list of src: (no store), or src:dst (store)
+get_remote_default_refs_for_fetch () {
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'' | branches-partial)
+		echo "HEAD:" ;;
+	branches)
+		remote_branch=$(sed -ne '/#/s/.*#//p' "$GIT_DIR/branches/$1")
+		case "$remote_branch" in '') remote_branch=master ;; esac
+		echo "refs/heads/${remote_branch}:refs/heads/$1"
+		;;
+	remotes)
+		canon_refs_list_for_fetch $(sed -ne '/^Pull: */{
+						s///p
+					}' "$GIT_DIR/remotes/$1")
+		;;
+	*)
+		die "internal error: get-remote-default-ref-for-push $1" ;;
+	esac
+}
+
+get_remote_refs_for_push () {
+	case "$#" in
+	0) die "internal error: get-remote-refs-for-push." ;;
+	1) get_remote_default_refs_for_push "$@" ;;
+	*) shift; echo "$@" ;;
+	esac
+}
+
+get_remote_refs_for_fetch () {
+	case "$#" in
+	0) die "internal error: get-remote-refs-for-fetch." ;;
+	1) get_remote_default_refs_for_fetch "$@" ;;
+	*) shift; canon_refs_list_for_fetch "$@" ;;
+	esac
+}
diff --git a/git-push-script b/git-push-script
--- a/git-push-script
+++ b/git-push-script
@@ -20,8 +20,6 @@ do
 	-*)
 		die "Unknown parameter $1" ;;
         *)
-		remote="$1"
-		shift
 		set x "$@"
 		shift
 		break ;;
@@ -29,27 +27,13 @@ do
 	shift
 done
 
-case "$remote" in
-*:* | /* | ../* | ./* )
-	# An URL, host:/path/to/git, absolute and relative paths.
-	;;
-* )
-	# Shorthand
-	if expr "$remote" : '..*/..*' >/dev/null
-	then
-		# a short-hand followed by a trailing path
-		shorthand=$(expr "$remote" : '\([^/]*\)')
-		remainder=$(expr "$remote" : '[^/]*\(/.*\)$')
-	else
-		shorthand="$remote"
-		remainder=
-	fi
-	remote=$(sed -e 's/#.*//' "$GIT_DIR/branches/$remote") &&
-	expr "$remote" : '..*:' >/dev/null &&
-	remote="$remote$remainder" ||
-	die "Cannot parse remote $remote"
-	;;
+. git-parse-remote-script
+remote=$(get_remote_url "$@")
+case "$has_all" in
+--all) set x ;;
+'')    set x $(get_remote_refs_for_push "$@") ;;
 esac
+shift
 
 case "$remote" in
 http://* | https://* | git://* | rsync://* )

^ permalink raw reply	[relevance 6%]

* [PATCH] Start adding the $GIT_DIR/remotes/ support.
  @ 2005-08-20 18:22  6% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-08-20 18:22 UTC (permalink / raw)
  To: git

All the necessary parsing code is in git-parse-remote-script;
update git-push-script to use it.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

    ** sorry I made a mistake of letting git send-email to
    ** send nonsense messages ...

 Makefile                |    2 -
 git-parse-remote-script |  144 +++++++++++++++++++++++++++++++++++++++++++++++
 git-push-script         |   28 ++-------
 3 files changed, 151 insertions(+), 23 deletions(-)
 create mode 100755 git-parse-remote-script

284ba9655aedbdaaa897fdcc6aabae97de8d99d1
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -64,7 +64,7 @@ SCRIPTS=git git-apply-patch-script git-m
 	git-reset-script git-add-script git-checkout-script git-clone-script \
 	gitk git-cherry git-rebase-script git-relink-script git-repack-script \
 	git-format-patch-script git-sh-setup-script git-push-script \
-	git-branch-script git-parse-remote git-verify-tag-script \
+	git-branch-script git-parse-remote git-parse-remote-script git-verify-tag-script \
 	git-ls-remote-script git-clone-dumb-http git-rename-script \
 	git-request-pull-script git-bisect-script
 
diff --git a/git-parse-remote-script b/git-parse-remote-script
new file mode 100755
--- /dev/null
+++ b/git-parse-remote-script
@@ -0,0 +1,144 @@
+#!/bin/sh
+
+. git-sh-setup-script || die "Not a git archive"
+
+get_data_source () {
+	case "$1" in
+	*/*)
+		# Not so fast.  This could be the partial URL shorthand...
+		token=$(expr "$1" : '\([^/]*\)/')
+		remainder=$(expr "$1" : '[^/]*/\(.*\)')
+		if test -f "$GIT_DIR/branches/$token"
+		then
+			echo branches-partial
+		else
+			echo ''
+		fi
+		;;
+	*)
+		if test -f "$GIT_DIR/remotes/$1"
+		then
+			echo remotes
+		elif test -f "$GIT_DIR/branches/$1"
+		then
+			echo branches
+		else
+			echo ''
+		fi ;;
+	esac
+}
+
+get_remote_url () {
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'')
+		echo "$1" ;;
+	remotes)
+		sed -ne '/^URL: */{
+			s///p
+			q
+		}' "$GIT_DIR/remotes/$1" ;;
+	branches)
+		sed -e 's/#.*//' "$GIT_DIR/branches/$1" ;;
+	branches-partial)
+		token=$(expr "$1" : '\([^/]*\)/')
+		remainder=$(expr "$1" : '[^/]*/\(.*\)')
+		url=$(sed -e 's/#.*//' "$GIT_DIR/branches/$token")
+		echo "$url/$remainder"
+		;;
+	*)
+		die "internal error: get-remote-url $1" ;;
+	esac
+}
+
+get_remote_default_refs_for_push () {
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'' | branches | branches-partial)
+		;; # no default push mapping, just send matching refs.
+	remotes)
+		sed -ne '/^Push: */{
+			s///p
+		}' "$GIT_DIR/remotes/$1" ;;
+	*)
+		die "internal error: get-remote-default-ref-for-push $1" ;;
+	esac
+}
+
+# Subroutine to canonicalize remote:local notation
+canon_refs_list_for_fetch () {
+	for ref
+	do
+		expr "$ref" : '.*:' >/dev/null || ref="${ref}:"
+		remote=$(expr "$ref" : '\([^:]*\):')
+		local=$(expr "$ref" : '[^:]*:\(.*\)')
+		case "$remote" in
+		'') remote=HEAD ;;
+		*) remote="refs/heads/$remote" ;;
+		esac
+		case "$local" in
+		'') local= ;;
+		*) local="refs/heads/$local" ;;
+		esac
+		echo "${remote}:${local}"
+	done
+}
+
+# Returns list of src: (no store), or src:dst (store)
+get_remote_default_refs_for_fetch () {
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'' | branches-partial)
+		echo "HEAD:" ;;
+	branches)
+		remote_branch=$(sed -ne '/#/s/.*#//p' "$GIT_DIR/branches/$1")
+		case "$remote_branch" in '') remote_branch=master ;; esac
+		echo "refs/heads/${remote_branch}:refs/heads/$1"
+		;;
+	remotes)
+		canon_refs_list_for_fetch $(sed -ne '/^Pull: */{
+						s///p
+					}' "$GIT_DIR/remotes/$1")
+		;;
+	*)
+		die "internal error: get-remote-default-ref-for-push $1" ;;
+	esac
+}
+
+get_remote_refs_for_push () {
+	case "$#" in
+	0) die "internal error: get-remote-refs-for-push." ;;
+	1) get_remote_default_refs_for_push "$@" ;;
+	*) shift; echo "$@" ;;
+	esac
+}
+
+get_remote_refs_for_fetch () {
+	case "$#" in
+	0)
+	    die "internal error: get-remote-refs-for-fetch." ;;
+	1)
+	    get_remote_default_refs_for_fetch "$@" ;;
+	*)
+	    shift
+	    tag_just_seen=
+	    for ref
+	    do
+		if test "$tag_just_seen"
+		then
+		    echo "refs/tags/${ref}:refs/tags/${ref}"
+		    tag_just_seen=
+		    continue
+		else
+		    case "$ref" in
+		    tag)
+		        tag_just_seen=yes
+			continue
+			;;
+		    esac
+		fi
+	        canon_refs_list_for_fetch "$ref"
+	    done
+	    ;;
+	esac
+}
diff --git a/git-push-script b/git-push-script
--- a/git-push-script
+++ b/git-push-script
@@ -20,8 +20,6 @@ do
 	-*)
 		die "Unknown parameter $1" ;;
         *)
-		remote="$1"
-		shift
 		set x "$@"
 		shift
 		break ;;
@@ -29,27 +27,13 @@ do
 	shift
 done
 
-case "$remote" in
-*:* | /* | ../* | ./* )
-	# An URL, host:/path/to/git, absolute and relative paths.
-	;;
-* )
-	# Shorthand
-	if expr "$remote" : '..*/..*' >/dev/null
-	then
-		# a short-hand followed by a trailing path
-		shorthand=$(expr "$remote" : '\([^/]*\)')
-		remainder=$(expr "$remote" : '[^/]*\(/.*\)$')
-	else
-		shorthand="$remote"
-		remainder=
-	fi
-	remote=$(sed -e 's/#.*//' "$GIT_DIR/branches/$remote") &&
-	expr "$remote" : '..*:' >/dev/null &&
-	remote="$remote$remainder" ||
-	die "Cannot parse remote $remote"
-	;;
+. git-parse-remote-script
+remote=$(get_remote_url "$@")
+case "$has_all" in
+--all) set x ;;
+'')    set x $(get_remote_refs_for_push "$@") ;;
 esac
+shift
 
 case "$remote" in
 http://* | https://* | git://* | rsync://* )

^ permalink raw reply	[relevance 6%]

* Re: [BUG] git-show-branch cant show --more
  @ 2005-09-19  8:12  3% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-09-19  8:12 UTC (permalink / raw)
  To: Jon Loeliger; +Cc: git

Jon Loeliger <jdl@freescale.com> writes:

> I realize I probably dumbly expected more history out
> of a partial git repository than is actually present,
> but a segmentation fault wasn't a nice way to tell me. :-)
>
> Start with just Paul's repo over here:
>
> rsync://rsync.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc-merge.git

Hmph.  That repository does not look partial to me, although it
seems to use alternates to borrow heavily from Linus.

  $ git clone rsync://rsync.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc-merge.git ppc-merge
  $ git show-branch --more=10
  [master] ppc32: Allow user to individual select CHRP/PMAC/PREP config
  [master~1] powerpc: Merge simplified sections.h into asm-powerpc
  [master~2] powerpc: Remove section free() and linker script bits
  [master~3] powerpc: Remove sections use from ppc64 and drivers
  [master~4] powerpc: Remove sections use from ppc
  [master~5] ppc32: Removed non-inlined versions of local_irq* functions
  [master~6] powerpc: Merged ppc_asm.h
  [master~7] powerpc: Merge kmap_types.h
  [master~8] [NETFILTER]: Solve Kconfig dependency problem
  [master~9] [IPV6]: Check connect(2) status for IPv6 UDP socket (Re: xfrm_lookup)
  [master~10] [BOND]: Fix bond_init() error path handling.
  $ git --version
  git version 0.99.7

But in any case you are right.  We should barf a bit nicely when
we encounter an corrupt repository.  How about something like
this (not fully tested)?

------------
[PATCH] Be nice when running in a corrupt repository.

We may end up trying to print a commit we do not have but only
whose existence is known to us because another commit we have
refer to it.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
diff --git a/show-branch.c b/show-branch.c
--- a/show-branch.c
+++ b/show-branch.c
@@ -196,8 +196,11 @@ static void show_one_commit(struct commi
 {
 	char pretty[128], *cp;
 	struct commit_name *name = commit->object.util;
-	pretty_print_commit(CMIT_FMT_ONELINE, commit->buffer, ~0,
-			    pretty, sizeof(pretty));
+	if (commit->object.parsed)
+		pretty_print_commit(CMIT_FMT_ONELINE, commit->buffer, ~0,
+				    pretty, sizeof(pretty));
+	else
+		strcpy(pretty, "(unavailable)");
 	if (!strncmp(pretty, "[PATCH] ", 8))
 		cp = pretty + 8;
 	else

^ permalink raw reply	[relevance 3%]

* Re: Cogito: cg-clone doesn't like packed tag objects
  @ 2005-09-27 17:56  3%                     ` Linus Torvalds
  2005-09-27 18:36  2%                       ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Linus Torvalds @ 2005-09-27 17:56 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Petr Baudis, Tom Prince, git



On Tue, 27 Sep 2005, Junio C Hamano wrote:
> 
> This is a bit hard and needs some thinking to do cleanly,
> because what is in info/refs is what is sent from the publisher
> side over git-native protocol at the beginning of the handshake,
> and it is not easy to add that to git-native protocol cleanly
> and backward-compatibly (I think I know how without breaking
> existing clients, but it is not clean).

Argh.

"git-upload-pack" very much on purpose never sends partial object stores: 
it really doesn't want to send a tag-object for you to even _look_ at 
unless it also sends all the objects that you are missing that the tag 
refers to.

I'd really be much happier with the tag fetching being separate.

For example, making

	git fetch --tags <dest>

fetch all tags _and_ the objects that they depend on would seem a _lot_ 
more appropriate.

The thing is, tags really may be totally private. For example, it makes 
sense to fetch tags when you pull an official tree (ie my kernel tree, or 
your git tree), but it does NOT make sense for me to fetch tags 
(automatically or not) when I pull from a developers tree.

That's why git fetch doesn't get the tags by default. It's WRONG. 

But we could certainly make it _easier_ to get tags when you want them. 
"git-ls-remote" already helps you, and

	git-ls-remote ... | cut -f2 | grep '^refs/tags/'

completes the picture. No protocol changes necessary, just some added 
magic to git-fetch.sh.

Actually, here's a simple and stupid patch.

Untested as usual, but hey, how hard can it be?

		Linus

----
diff --git a/git-fetch.sh b/git-fetch.sh
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -5,6 +5,7 @@
 _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
 _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
 
+tags=
 append=
 force=
 update_head_ok=
@@ -17,6 +18,9 @@ do
 	-f|--f|--fo|--for|--forc|--force)
 		force=t
 		;;
+	--tags)
+		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)
@@ -151,7 +155,12 @@ case "$update_head_ok" in
 	;;
 esac
 
-for ref in $(get_remote_refs_for_fetch "$@")
+taglist=
+if [ "$tags" ]; then
+	taglist=$(git-ls-remote "$remote" | awk '/refs\/tags/ { print $2":"$2 }')
+fi
+
+for ref in $(get_remote_refs_for_fetch "$@" $taglist)
 do
     refs="$refs $ref"
 

^ permalink raw reply	[relevance 3%]

* Re: Cogito: cg-clone doesn't like packed tag objects
  2005-09-27 17:56  3%                     ` Linus Torvalds
@ 2005-09-27 18:36  2%                       ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-09-27 18:36 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Petr Baudis, Tom Prince, git

Linus Torvalds <torvalds@osdl.org> writes:

> On Tue, 27 Sep 2005, Junio C Hamano wrote:
>> 
>> This is a bit hard and needs some thinking to do cleanly,
>> because what is in info/refs is what is sent from the publisher
>> side over git-native protocol at the beginning of the handshake,
>> and it is not easy to add that to git-native protocol cleanly
>> and backward-compatibly (I think I know how without breaking
>> existing clients, but it is not clean).
>
> Argh.
>
> "git-upload-pack" very much on purpose never sends partial object stores: 
> it really doesn't want to send a tag-object for you to even _look_ at 
> unless it also sends all the objects that you are missing that the tag 
> refers to.
>
> I'd really be much happier with the tag fetching being separate.

What Pasky wants to do, which I misunderstood first and gave
essentially the same response to, is to help this senario:

    User tracks git.git#master and nothing else, i.e. she pulls
    from my master branch from time to time.  The tool notices
    that I tagged a commit on the master branch (not necessarily
    the tip at the time of pulling) with v0.99.8 tag, which she
    has not have, and fetches v0.99.8 tag and stores it under
    .git/refs/.  Currently Cogito does not let her specify
    where on the receiving end to place that tag and always
    places it in .git/refs/tags/v0.99.8, but that can be fixed
    later.

The current ls-remote (or underlying fetch-pack protocol) does
not help this because the SHA1 given to Cogito is the object
name of the tag, and without fetching the tag object and looking
at what it refers to, Pasky cannot say "Oh, this new v0.99.8 tag
is the commit on the branch being tracked".

The protocol extension I had in mind, which I said is not clean,
is from upload_pack(), in addition to the existing send_ref()
call which sends "object-name refname" list like this:

4899334e96a076bb8780968c5075b214aa80fab9	HEAD
d5bc7eecbbb0b9f6122708bf5cd62f78ebdaafd8	refs/heads/maint
3cc35e29ec252d0dca1139106fbaa70cb9ad6ef1	refs/heads/master
4899334e96a076bb8780968c5075b214aa80fab9	refs/heads/pu
348c4c66dacb1810a9bcd592e72f98a465233488	refs/heads/rc
0918385dbd9656cab0d1d81ba7453d49bbc16250	refs/tags/junio-gpg-pub
d6602ec5194c87b0fc87103ca4d67251c76f233a	refs/tags/v0.99
f25a265a342aed6041ab0cc484224d9ca54b6f41	refs/tags/v0.99.1
...

we could send phony entries like this:

b92c9c07fe2d0d89c4f692573583c4753b5355d2	deref/tags/junio-gpg-pub
a3eb250f996bf5e12376ec88622c4ccaabf20ea8	deref/tags/v0.99
78d9d414123ad6f4f522ffecbcd9e4a7562948fd	deref/tags/v0.99.1

These phony entries tell the receiver what the tags eventually
resolve to.  Pasky could use this to see if he has the named
object from the usual fetch path, and if he finds matches,
ask git-fetch-pack to get them.

We would need to teach git-clone and git-fetch to ignore deref/
if they do not already do so.

^ permalink raw reply	[relevance 2%]

* GIT 0.99.8
@ 2005-10-03  0:12  3% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-10-03  0:12 UTC (permalink / raw)
  To: git

Here is 0.99.8.  GIT has been doing everything I personally
wanted it to do since mid 0.99.7, and now it has almost
everything I want it to contain, except for a couple of minor
points.  I feel that we are ready to finish the last mile for
1.0.  Many thanks to everybody who contributed the comments,
eyeballs, and code.


Done in 0.99.8
==============

New Features, Commands, and Enhancements
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* 'git pull' now uses 'git-merge' instead of 'git-resolve', so you can
  specify alternative merge strategy to use on its command line.

* 'git pull -s recursive' has been taught about renaming merges,
  which may deal with HPA's klibc vs klibc-kbuild situation better.

* Symbolic refs -- instead of using symlinks to express .git/HEAD,
  you can have a regular file that stores a single line
  'ref: refs/heads/master' in it.

  git-update-ref is the preferred way to write into .git/HEAD,
  not "echo >.git/HEAD".  git-symbolic-ref is the preferred way
  to check which underlying ref a symbolic ref .git/HEAD refers
  to, not "readlink .git/HEAD".

* A couple of new diff options (-l<num> and --name-status).

* Commit walker over http acquired more SSL options.

* 'git clone' checks out the working tree by default.


Fixes
~~~~~

* Removed unused commands (diff-helper, rev-tree, and export).

* Platforms with only Python 2.3 installed can use recursive merge
  strategy.

* Octopus documented.

* Merge is more careful noticing potentially ambiguous situation. 

* Git pull does not blindly do Octopus when Pull: lines in remotes
  file specifies more than one remote branches.

* Commit walker got safer to use after interrupted downloads.

* Commit walker over http can resume partial downloads.

* More portability fixes for BSD and Solaris.

^ permalink raw reply	[relevance 3%]

* [WIP] Implement a test for git-fetch-pack
@ 2005-10-25 21:34  7% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2005-10-25 21:34 UTC (permalink / raw)
  To: git

It does some basic things right now, but I'll add more.

---

 t/t5500-fetch-pack.sh |  142 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 142 insertions(+), 0 deletions(-)

diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
new file mode 100755
index 0000000..a5d3a25
--- /dev/null
+++ b/t/t5500-fetch-pack.sh
@@ -0,0 +1,142 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Johannes Schindelin
+#
+
+test_description='Testing multi_ack pack fetching
+
+'
+. ./test-lib.sh
+
+# Test fetching for an empty, a partial, a full copy, and for a repository,
+# which is not empty but has no common commits (think coolest merge ever).
+
+function add () {
+	local name=$1
+	local branch=$(expr $name : '\(.\)')
+	local text="$@"
+	local parents=""
+
+	shift
+	while test $1; do
+		local sha1=$(eval echo \$$1)
+		test -z "$sha1" && sha1=$1
+		parents="$parents -p $sha1"
+		shift
+	done
+
+	echo "$text" > test.txt
+	git-update-index --add test.txt
+	tree=$(git-write-tree)
+	commit=$(echo "$text" | git-commit-tree $tree $parents 2>/dev/null)
+	export $name=$commit
+	echo $commit > .git/refs/heads/$branch
+	git-symbolic-ref HEAD refs/heads/$branch 2>/dev/null
+}
+
+function tag () {
+	local name=$1
+	local commit=$(eval echo \$$2)
+	local text="$@"
+
+	git-tag -m "$text" $name $commit
+}
+
+function count_objects () {
+	local line="$(git-count-objects)"
+	expr "$line" : '\([^ ]*\)'
+}
+
+function test_expect_object_count () {
+	local repository=$1
+	local count=$2
+
+	expect="$count objects, $count kilobytes"
+	output="$(git-count-objects)"
+	test_expect_success "$repository repository is valid" \
+		"test \"$output\" = \"$expect\""
+}
+
+function check_rep () {
+	local rep=$1
+	local count=$2
+
+	cd $rep
+	test_expect_success "fetch from upstream into $rep" \
+		'git-fetch-pack -v .. A B C 2> log.txt'
+	git-update-ref HEAD $A46
+	test_expect_success "fsck $rep" 'git-fsck-objects --full'
+	test_expect_object_count $rep $count
+	cd ..
+}
+
+# A1 - A2 - A3 - A4 - A5 - .. - A47
+#    \    \     /   /
+# B1 - B2 ------ B3 - B4 - B5
+#         \   /     \
+#           C1 - C2 - C3
+
+# the partial copy is cloned at A1-B3-C2 time.
+
+(
+	mkdir empty &&
+	cd empty &&
+	git-init-db 2>/dev/null
+)
+
+add B1
+
+pre_tag_count=$(count_objects)
+
+i=1; while [ $i -le 40 ]; do
+	tag T$i B1
+	i=$(expr $i + 1)
+done
+
+post_tag_count=$(count_objects)
+
+add A1
+add B2 B1 A1
+add B3 B2
+add C1 B2
+add C2 C1
+
+# clone
+git-clone . partial 2>/dev/null
+
+partial_count=$(count_objects)
+
+add A2 A1
+add A3 A2
+add A4 A3 C1
+add C3 C2 B3
+add A5 A4 B3
+add B4 B3
+add B5 B4
+i=5
+while [ $i -le 46 ]; do
+	next=$(expr $i + 1)
+	add A$next A$i
+	i=$next
+done
+
+total_count=$(count_objects)
+
+git-clone . full 2>/dev/null
+
+# let the testing begin
+
+test_expect_success 'precalculated counts' \
+	"test $post_tag_count:$partial_count:$total_count = 43:58:205"
+
+tag_count=$(expr $post_tag_count - $pre_tag_count)
+empty_diff=$(expr $total_count - $tag_count)
+partial_diff=$(expr $total_count - $partial_count)
+
+check_rep empty $empty_diff
+check_rep partial $partial_diff
+check_rep full 0
+
+#gitk --all
+
+test_done

^ permalink raw reply related	[relevance 7%]

* Re: git push sends more objects than it needs to
  @ 2005-10-31 19:36  2%   ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2005-10-31 19:36 UTC (permalink / raw)
  To: Luck, Tony; +Cc: git



On Mon, 31 Oct 2005, Linus Torvalds wrote:
> > 
> > Now the "unpack" on kernel.org did the right thing and noticed
> > that over 9000 of the objects were already in the packfile.  But
> > I wonder if it couldn't have been smarter and not sent them?
> 
> It should have been smarter, but I suspect you got caught by the fact that 
> kernel.org by default has git-0.99.8f on it, which has the old 
> pre-multi_ack code to figure out what the common commit was.

Oh, actually, I take that back.

This is not the multi-ack code at all, I suspect.

The problem is totally different: you copied the new pack to your 
master.kernel.org repository, but you never updated any branches there.

So you had the objects, but git had no way of knowing. The pack generation 
doesn't look at what _objects_ you have, it looks at what _refs_ you have. 
And your refs were all to the old state.

So git actually did everything right (you can never rely on objects: you 
may have a partial object list due to some earlier incomplete pull/push). 

This is actually easy enough to fix up in one of several ways:

 a) The "don't do that then" approach:

    Don't go behind git's back and add objects on your own, and expect git 
    to realize what you did. ;^p

 b) The "live with it" approach:

    You copied the pack by hand, and that will keep git-unpack-objects 
    from duplicating the objects, but you'll still waste time and network 
    when trying pushing the objects (just once, though).

    Ie this is what happened this time: nothing really lost, and the end 
    result is fine. Now you know why it happened, and you're fine.

 c) The "I'm smarter than git" approach:

    When you copy my objects, copy my reference to the top-of-tree too 
    (and rename it). NOTE! Now you need to be really careful, and you need 
    to make sure you copy _all_ the objects, because if you screw this up, 
    your repo will be missing objects that you claim are there, and it 
    will be all your fault.

    I really don't advocate this approach at all. It's certainly doable, 
    but it's also the only approach where you can really screw up.

 d) Just let git do it for you.

    Copy the pack-files, or add my object directory as an "alternates" for 
    your object directory, do the "git prune-objects", and then _locally_ 
    on master.kernel.org just do something like

	git fetch ..linus-directory.. master:linus

    which will still create the unnecessary pack-file and unpack it into 
    nothingness (since you have the objects in the pack-file you copied by 
    hand), but at least it won't eat any network bandwidth, and it will do 
    the right thing if it turns out that I've pushed something after doing 
    the pack-file, and fetch those individual objects in _addition_ to the 
    pack-file you snarfed by hand. It will also obviously update a ref in
    your tree (the "linus" branch), so now when you send stuff later, it 
    will know all about the objects you already have.

 e) Re-create the tree entirely

    Blow away your tree on master entirely, just re-create it locally with 
    "git clone -l -s" from my tree (which will do all the "alternates" 
    object files for you), and then populate the result with a simple push
    from your home tree.

 f) any number of variations on a theme. IOW, there are endless ways to do 
    this. 

Hmm?

		Linus

^ permalink raw reply	[relevance 2%]

* Re: hgmq vs. StGIT
  @ 2005-11-10 16:20  3%                   ` Catalin Marinas
  0 siblings, 0 replies; 200+ results
From: Catalin Marinas @ 2005-11-10 16:20 UTC (permalink / raw)
  To: Petr Baudis
  Cc: Chris Mason, Chuck Lever, Theodore Ts'o, Joel Becker,
	Junio C Hamano, pavel, git

On 09/11/05, Petr Baudis <pasky@suse.cz> wrote:
> A night city, the snow slowly falling. Approaching the roofs covered in
> white and illuminated by the yellow street lighting, dark windows - but
> one dimly glowing, a computer screen inside. Close-up on a hacker:
> $EDITOR opened, lost deep in hack mode, fingers dancing over the
> keyboard.  Dreamy-monumental music in the background.

I agree with Pavel here :-)

> StGIT user, only part of the patches in stack, and the rest depends on
> the one currently edited, and I want to record my work on this one.
> I can either:
>
> (i) Just keep per-patch history only.

That's probably the simplest.

> (ii) Keep _both_ per-patch and per-stack history (since I don't want to
> record the stack when I have to keep some patches out of it - the
> history would look like randomly removing and adding tons of patches,
> and jumping around would be difficult because of this too).

It happens to me to keep some patches popped which aren't really part
of the stack (i.e. splitting a big patch, I still keep it in the
unapplied patches to push it later and check what was left after
splitting). From this point of view, (ii) would be better but with the
drawback that you need to have a valid stack with all the patches
pushed.

> (iii) Keep per-patchlist history - do not actually record only our
> current stack, but all the patches StGIT knows about. The patches
> depending on the one currently being changed will not be in consistent
> state, but that's tough. Actually, this seems to be the most viable
> strategy. One question is whether to record if some patch is actually
> applied right now or not (I'd say don't record it since you again have
> the "bouncing problem" otherwise).

(iii) is the most comprehensive method and, as Pavel said, we should
record what patches were applied or not and reproduce them exactly
when retrieving a different state.

Another big problem is the base of the stack, which can change. Would
retrieving an old state of the stack also restore the old the base? I
think it should and its up to the user to rebase it.

A simple way to partially achieve (iii) is to extend the existing
'branch' command to clone the whole series into a new one, including
all the patches. The problem with this approach is that there is no
temporal relation between branches.

How would you expect to switch between different states of the stack?
As Chris Mason mentioned, once you start doing this people might ask
for full SCM features (like diffs between revisions) where the objects
are stack states. This would complicate StGIT quite a lot.

--
Catalin

^ permalink raw reply	[relevance 3%]

* Re: [QUESTION] Access to a huge GIT repository.
  @ 2005-11-22  9:50  3%                     ` Junio C Hamano
  2005-11-22 10:40  0%                       ` Franck
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2005-11-22  9:50 UTC (permalink / raw)
  To: Franck; +Cc: git

Franck <vagabon.xyz@gmail.com> writes:

> 2005/11/21, Junio C Hamano <junkio@cox.net>:
>> Franck <vagabon.xyz@gmail.com> writes:
>>
>> > ... But since I used grafting to "cut"
>> > my light repo and .git/info/grafts file is not copied during
>> > push/pull/clone operations it's not going to work. Is it a scheme that
>> > could work ?
>>
>> If you tell your downloaders that your repository is incomplete
>> and they need to have at least up to such and such commits from
>> another repository, they should be able to slurp from you.

I was not talking about _your_ case specifically.  If you happen
to have based your partial history on top of a single commit
then the set of "such and such commits" might be only one, but
you could for example clone from Linus tip, merge in a couple of
jgarzik branch heads, put your own commits on top of them and
then cauterize your history, stopping at those foreign commits.
In such a case you obviously need to tell others where you
chopped your history off.

^ permalink raw reply	[relevance 3%]

* Re: [QUESTION] Access to a huge GIT repository.
  2005-11-22  9:50  3%                     ` Junio C Hamano
@ 2005-11-22 10:40  0%                       ` Franck
  0 siblings, 0 replies; 200+ results
From: Franck @ 2005-11-22 10:40 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

2005/11/22, Junio C Hamano <junkio@cox.net>:
> I was not talking about _your_ case specifically.  If you happen
> to have based your partial history on top of a single commit
> then the set of "such and such commits" might be only one, but
> you could for example clone from Linus tip, merge in a couple of
> jgarzik branch heads, put your own commits on top of them and
> then cauterize your history, stopping at those foreign commits.
> In such a case you obviously need to tell others where you
> chopped your history off.
>

I built the lite repository and got an error depending on which
original repo I used to push the lite one. Here is the history:

--------------------------------------------------------------
#
# building my pub repo from the "lite" repository
#

$ git checkout -b lite

$ git-show-branch
* [lite] Merge with Linux 2.6.14.
 ! [master] Merge with Linux 2.6.14.
  ! [origin] Merge with db93a82fa9d8b4d6e31c227922eaae829253bb88.
---

# push the initial commit object

$ git push /home/franck/pub/linux/git/linux-lite.git lite
updating 'refs/heads/lite'
  from 0000000000000000000000000000000000000000
  to   8643db584b46a61c968ae230897869f789bae020
Packing 19558 objects
Unpacking 19558 objects
 100% (19558/19558) done
refs/heads/lite: 0000000000000000000000000000000000000000 ->
8643db584b46a61c968ae230897869f789bae020

#
# push first changes from lite repositoy -> KO
#
$ making some hard work

$ git commit -m "Did some hard work"
$ git push /home/franck/pub/linux/git/linux-lite.git lite
updating 'refs/heads/lite'
  from 8643db584b46a61c968ae230897869f789bae020
  to   730518eea7523afd5b7891bb7849973cab52d963
Packing 0 objects
Unpacking 0 objects

error: unpack should have generated
730518eea7523afd5b7891bb7849973cab52d963, but I can't find it!
$

#
# push first changes from "full" repository -> OK
#

# go to full repository and checkout linux.2.6.14

$ git commit -m "Did some hard work"
$ git push /home/franck/pub/linux/git/linux-lite.git lite
updating 'refs/heads/lite'
  from 8643db584b46a61c968ae230897869f789bae020
  to   067d05600fe7251b8c923fbeb9ba0068ee272110
Packing 108 objects
Unpacking 108 objects
 100% (108/108) done
refs/heads/lite: 8643db584b46a61c968ae230897869f789bae020 ->
067d05600fe7251b8c923fbeb9ba0068ee272110
--------------------------------------------------------------

It seems that the "lite" repository can't be used as a working
repository. And If I use the last method to push some work, I can only
pull that changes from a full repository. From a lite one (without any
changes of course) I get this error:

$ git pull /home/franck/pub/linux/git/linux-lite.git lite
Packing 108 objects
Unpacking 108 objects
 100% (108/108) done
Merging HEAD with f42aaff3bf8041c2d43f1ff6fdfe5df6e8a5b00b
Merging:
8643db584b46a61c968ae230897869f789bae020 Merge with Linux 2.6.14.
f42aaff3bf8041c2d43f1ff6fdfe5df6e8a5b00b Did some hard work
found 0 common ancestor(s):
Traceback (most recent call last):
  File "/home/fbuihuu/bin/git-merge-recursive", line 870, in ?
    firstBranch, secondBranch, graph)
  File "/home/fbuihuu/bin/git-merge-recursive", line 67, in merge
    mergedCA = ca[0]
IndexError: list index out of range
No merge strategy handled the merge.

Do you have any clues ?

Thanks
--
               Franck

^ permalink raw reply	[relevance 0%]

* as promised, docs: git for the confused
  @ 2005-12-08  6:34  1% ` linux
  0 siblings, 0 replies; 200+ results
From: linux @ 2005-12-08  6:34 UTC (permalink / raw)
  To: git; +Cc: linux

As I mentioned with all my questions, I was writing up the answers
I got.  Here's the current status.  If anyone would like to comment on
its accuracy or usefulness, feedback is appreciated.

I've tried to omit or skim very lightly over subjects I think
are adequately explained in existing docs, unless that would
leave an uncomfortable hole in the explanation.

TODO: Describe the config file.  It's a recent invention, and I
haven't found a good description of its contents.


		"I Don't Git It"
		Git for the confused

Git is hardly lacking in documentation, but coming at it fresh, I found
it somewhat confusing.

Git is a toolkit in the Unix tradition.  There are a number of primitives
written in C, which are made friendly by a layer of shell scripts.
These are known in git-speak, as the "plumbing" and the "porcelain",
respectively.  The porcelain should work and look nice.  The plumbing
should just deal with lots of crap efficiently.

Much of git's documentation was first written to explain the plumbing to
the people writing the porcelain.  Since then, although the essentials
haven't changed, porcelain has been added and conventions have been
established that make it a lot more pleasant to deal with.  Some commands
have been changed or replaced, and it's not quite the same.

Using the original low-level commands is now most likely more difficult
than necessary, unless you want to do something not supported by the
existing porcelain.

This document retraces (with fewer false turns) how I learned my
way around git.  There are some concepts I didn't understand so well
the first time through, and an overview of all the git commands, grouped
by application.


A good rule of thumb is that the commands with one-word names (git-diff,
git-commit, git-merge, git-push, git-pull, git-status, git-tag, etc.) are
designed for end-user use.  Multi-word names (git-count-objects,
git-write-tree, git-cat-file) are generally designed for use from
a script.

This isn't ironclad.  The first command to start using git is git-init-db,
and git-show-branch is pure porcelain, while git-mktag is a primitive.
And you don't often run git-daemon by hand.  But still, it's a useful
guideline.


* Background material.

To start with, read "man git".  Or Documentation/git.txt in the git
source tree, which is the same thing.  Particularly note the description
of the index, which is where all the action in git happens.

One thing that's confusing is why git allows you to have one version of
a file in the current HEAD, a second version in the index, and possibly a
third in the working directory.  Why doesn't the index just contain a copy
of the current HEAD until you commit a new one?  The answer is merging,
which does all its work in the index.  Neither the object database nor
the working directory let you have multiple files with the same name.

The index is really very simple.  It's a series of structures, each
describing one file.  There's an object ID (SHA1) of the contents,
some file metadata to detect changes (time-stamps, inode number, size,
permissions, owner, etc.), and the path name relative to the root of
the working directory.  It's always stored sorted by path name, for
efficient merging.

At (almost) any time, you can take a snapshot of the index and write
it as a tree object.

The only interesting feature is that each entry has a 2-bit stage number.
Normally, this is always zero, but each path name is allowed up to three
different versions (object IDs) in the index at once.  This is used to
represent an incomplete merge, and an unmerged index entry (with more
than one version) prevents committing the index to the object database.


* Terminology - heads, branches, refs, and revisions

(This is a supplement to what's already in "man git".)

The most common object needed by git primitives is a tree.  Since a
commit points to a tree and a tag points to a commit, both of these are
acceptable "tree-ish" objects and can be used interchangeably.  Likewise,
a tag is "commit-ish" and can be used where a commit is required.

As soon as you get to the porcelain, the most commonly used object is
a commit.  Also known as a revision, this is a tree plus a history.

While you can always use the full object ID, you can also use a reference.
A reference is a file that contains a 40-character hex SHA1 object ID
(and a trailing newline).  When you specify the name of a reference,
it is searched for in one of the directories:
	.git/			(or $GIT_DIR)
	.git/refs/		(or $GIT_DIR/refs/)
	.git/refs/heads/	(or $GIT_DIR/refs/heads/)
	.git/refs/tags/		(or $GIT_DIR/refs/tags/)

You may use subdirectories by including slashes in the reference name.
There is no search order; if searching the above four path prefixes
produces more than one match for the reference name (it's ambiguous),
then the name is not valid.

There is additional syntax (which looks like "commit~3^2~17") for
specifying an ancestor of a given commit (or tag).  This is documented
in detail in the documentation for git-rev-parse.  Briefly, commit^
is the parent of the given commit.  commit^^ is the grandparent, etc..
If there is more than one ancestor (a merge), then they can be referenced
as commit^1 (a synonym for commit^), commit^2, commit^3, etc.  (commit^0
gives the commit object itself.  A no-op if you're starting from a commit,
but it lets you get the commit object from a tag object.)

As long strings of ^ can be annoying, they can be abbreviated using ~
syntax.  commit^^^ is the same as commit~3, ^^^^ is the same as ~4, etc.
You can see lots of examples in the output of "git-show-branch".


Now, the although the most primitive git tools don't care, a convention
among all the porcelain is that the current head of development is
.git/HEAD, a symbolic link to a reference under refs/heads/.

git-init-db creates HEAD pointing to refs/heads/master, and that is
traditionally the name used for the "main trunk" of development.
Note that initially refs/heads/master doesn't exist - HEAD is a
dangling symlink!  This is okay, and will cause the initial commit
to have zero parents.

A "head" is mostly synonymous with a "branch", but the terms have
different emphasis.  The "head" is particularly the tip of the branch,
where future development will be appended.  A "branch" is the entire
development history leading to the head.  However, as far as git is
concerned, they're both references to commit objects, referred to from
refs/heads/.

When you actually do more (with git-commit, or git-merge), then the
current HEAD reference is overwritten with the new commit's id, and
the old HEAD becomes HEAD^.  Since HEAD is a symlink, it's the file
in refs/heads/ that's actually overwritten.  (See the git-update-ref
documentation for further details.)

The git-checkout command actually changes the HEAD symlink.  git-checkout
enforces the rule that it will only check out a branch under refs/heads.
You can use refs/tags as a source for git-diff or any other command that
only examines the revision, but if you want to check it out, you have
to copy it to refs/heads.


* Resetting

The "undo" command for commits to the object database is git-reset.
Like all deletion-type commands, be careful or you'll hurt yourself.
Given a commit (using any of the syntaxes mentioned above), this
sets the current HEAD to refer to the given commit.

This does NOT alter the HEAD symlink (as git-checkout <branch> will
do), but actually changes the reference pointed to by HEAD
(e.g. refs/heads/master) to contain a new object ID.

The classic example is to undo an erroneous commit, use
"git-reset HEAD^".

There are actually three kinds of git-reset:
git-reset --soft: Only overwrite the reference.  If you can find the
	old object ID, you can put everything back with a second
	git-reset --soft OLD_HEAD.
git-reset --mixed: This is the default, which I always think of
	as "--medium".  Overwrite the reference, and (using
	git-read-tree) read the commit into the index.  The
	working directory is unchanged.
git-reset --hard: Do everything --mixed does, and also check out
	the index into the working directory.  This really erases
	all traces of the previous version.  (One caveat: this
	will not delete any files in the working directory that
	were added as part of the changes being undone.)

The space taken up by the abandoned commit won't actually be
reclaimed until you collect garbage with git-prune.

git-reset with no commit specified is "git-reset HEAD", which is much
safer because the object reference is not actually changed.  This can
be used to undo changes in the index or working directory that you did
not intend.  Note, however, that it is not selective.  "git-commit"
has options for doing this selectively.

Like being sure what directory you're in when typing "rm -r", think
carefully about what branch you're on when typing "git-reset <commit>".

There is an undelete: git-reset stores the previous HEAD commit
in OLD_HEAD.  And git-lost-found can find leftover commits
until you do a git-prune.


* Merging

Merging is central to git operations.  Indeed, a big difference between
git and other version control systems is that git assumes that a change
will be merged more often than it's written, as it's passed around
different developers' repositories.  Even "git checkout" is a merge.

The heart of merging is git-read-tree, but if you can understand it from
the man page, you're doing better than me.

As mentioned, the index and the working directory versions of a file
could both be different from the HEAD.  Git lets you merge "under" your
current working directory edits, as long as the merge doesn't change
the files you're editing.

There are some special cases of merging, but let me start with the
procedure for the general 3-way merge case: merging branch B into branch A
(the current HEAD).

1) Given two commits, find a common ancestor O to server as the origin
   of the merge.  The basic "resolve" algorithm uses git-merge-base for
   the task, but the "recursive" merge strategy gets more clever in the
   case where there are multiple candidates.  I won't got into what it
   does, but it does a pretty good job.

2) Add all three input trees (the Origin, A, and B) to the index by
   "git-read-tree -m O A B".  The index now contains up to three copies
   of every file.  (Four, including the original, but that is discarded
   before git-read-tree returns.)

   Then, for each file in the index, git-read-tree does the following:

   2a) For each file, git-merge-tree tries to collapse the various
       versions into one using the "trivial in-index merge".  This just
       uses the file blob object names to see if the file contents
       are identical, and if two or more of the three trees contain an
       identical copy of this file, it is merged.  A missing (deleted)
       file matches another missing file.

       Note that this is NOT a majority vote.  If A and B agree on the
       contents of the file, that's what is used.  (Whether O agrees is
       irrelevant in this case.)  But if O and A agree, then the change
       made in B is taken as the final value.  Likewise, if O and B agree,
       then A is used.

   2b) If this is possible, then a check is made to see if the merge would
       conflict with any uncommitted work in the index or change the index
       out from under a modified working directory file.  If either of
       those cases happen, the entire merge is backed out and fails.

       (In the git source, the test "t/t1000-read-tree-m-3way.sh" has
       a particularly detailed description of the various cases.)

       If the merge is possible and safe, the versions are collapsed
       into one final result version.

   2c) If all three versions differ, the trivial in-index merge is
       not possible, and the three source versions are left in the
       index unmerged.  Again, if there was uncommitted work in the
       index or the working directory, the entire merge fails.

3) Use git-merge-index to iterate over the remaining unmerged files, and
   apply an intra-file merge.  The intra-file merge is usually done with
   git-merge-one-file, which does a standard RCS-style three-way merge
   (see "man merge").

4) Check out all the successfully merged files into the working directory.

5) If automatic merging was successful on every file, commit the merged
   version immediately and stop.

6) If automatic merging was not complete, then replace the working
   directory copies of any remaining unmerged files with a merged copy
   with conflict markers (again, just like RCS or CVS) in the working
   directory.  All three source versions are available in the index for
   diffing against.

   (We have not destroyed anything, because in step 2c), we checked to make
   sure the working directory file didn't have anything not in the
   repository.)

7) Manually edit the conflicts and resolve the merge.  As long as an
   unmerged, multi-version file exists in the index, committing the
   index is forbidden.  (You can use the options to git-diff to
   see the changes.)

8) Commit the final merged version of the conflicting file(s), replacing
   the unmerged versions with the single finished version.

Note that if the merge is simple, with no one file edited on both
branches, git never has to open a single file.  It reads three tree
objects (recursively) and stat(2)s some working directory files to
verify that they haven't changed.

Also note that this aborts and backs out rather than overwrite
anything not committed.  You can merge "under" uncommitted edits
only if those edits are to files not affected by the merge.


* 2-way merging

A "2-way merge" is basically a 3-way merge with the contents of the
index as the "current HEAD", and the original HEAD as the Origin.
However, this merge is designed only for simple cases and only supports
the "trivial merge" cases.  It does not fall back to an intra-file merge.

[[ I'm not sure why it couldn't, I confess.  For reversibility?  Or
just because it's likely to be too confusing.  ]]

This merge is used by git-checkout to switch between two branches,
while preserving any changes in the working directory and index.

Like the 3-way case, if a particular file hasn't changed between
the two heads, then git will preserve any uncommitted edits.
If the file has changed in any way, git doesn't try to perform
any sort of intra-file merge, it just fails.

* 1-way merging

This is not actually used by the git-core porcelain, and so is only
useful to someone writing more porcelain, but I'll describe it for
completeness.

Plain (non-merging) git-read-tree will overwrite the index entries with
those from the tree.  This invalidates the cached stat data, causing
git to think all the working directory files are "potentially changed"
until you do a git-update-index --refresh.

By specifying a 1-way merge, any index entry whose contents (object ID)
matches the incoming tree will have its cached stat data preserved.
Thus, git will know if the working directory file is not changed, and
will not overwrite if you execute git-checkout-index.

This is purely an efficiency hack.


* Special merges - already up to date, and fast-forward

There are two cases of 3-way or 2-way merging that are special.
Recall that the basic merge pattern is

   B--------> A+B
  /        /
 /        /
O -----> A

The two special cases arise if one of A or B is a direct ancestor of
the other.  In that case, the common ancestor of both A and B is the
older of the two commits.  And the merged result is simply the
newer of the two, unchanged.

Recalling that we are merging B into A, if B is a direct ancestor of A,
then A already includes all of B.  A is "already up to date" and not
changed at all by the merge.

The other case you'll hear mentioned, because it happens a lot when
pulling, is when A is a direct ancestor of B.  In this case, the
result of the merge is a "fast-forward" to B.

Both of these cases are handled very efficiently by the in-index merge
done by git-read-tree.


* Deleted files during merges

There is one small wrinkle in git's merge algorithm that will probably
never bite you, but I ought to explain anyway, just because it's so rare
that it's difficult to discover it by experiment.

The index contains a list of all files that git is tracking.  If the
index file is empty or missing and you do a commit, you write an empty
tree with no files.

When merging, if git finds no pre-existing index entry for a path it is
trying to merge, it considers that to mean "status unknown" rather than
"modified by being deleted".  Thus, this is not uncommitted work
in the index file, and does not block the merge.  Instead, the
file will reappear in the merge.

This is because it is possible to blow away the index file (rm .git/index
will do it quite nicely), and if this was considered a modification to
be preserved, it would cause all sorts of conflicts.

So the one change to the index that will NOT be preserved by a merge is
the removal of a file.  A missing index entry is treated the same as an
unmodified index entry.  The index will be updated, and when you check
out the revision, the working directory file will be (re-)created.

Note that none of this affects you in the usual case where you make
changes in the working directory only, and leave the index equal to HEAD
until you're ready to commit.


* Packs

Originally, git stored every object in its own file, and used rsync
to share repositories.  It was quickly discovered that this brought
mighty servers to their knees.  It's great for retrieving a small
subset of the database the way git usually does, but rsync scans the
whole .git/objects tree every time.

So packs were developed.  A pack is a file, built all at once, which
contains many delta-compressed objects.  With each .pack file,
there's an accompanying .idx file that indexes the pack so that
individual objects can be retrieved quickly.

You can reduce the disk space used by your repositories by periodically
repacking them with git-repack.  Normally, this makes a new incremental
pack of everything not already packed.  With the -a flag, this repacks
everything for even greater compression (but takes longer).

The git wire protocol basically consists of negotiation over what
objects needs to be transferred followed by sending a custom-built pack.
The .idx file can be reconstructed from the .pack file, so it's
never transferred.

[[ Is once every few hundred commits a good rule of thumb for repacking?
When .git/objects/?? reaches X megabytes?  I think too many packs is
itself a bad thing, since they all have to be searched. ]]


* Raw diffs

A major source of git's speed is that it tries to avoid accessing files
unnecessarily.  In particular, files can be compared based on their
object IDs without needing to open and read them.  As part of this,
the responsibility for finding file differences (printing diffs) is
divided into finding what files have changed, and finding the changes
within those files.

This is all explained in the Documentation/diffcore.txt in the git
distribution, but the basics is that many of the primitives spit out a
line like this:
:100755 100755 68838f3fad1d22ab4f14977434e9ce73365fb304 0000000000000000000000000000000000000000 M	git-bisect.sh
when asked for a diff.  This is known as a "raw diff".  They can be
told to generate a human-readable diff with the "-p" (patch) flag.
The git-diff command includes this by default.


* Advice on using git

If you're used to CVS, where branches and merges are "advanced" features
that you can go a long time, you need to learn to use branches in git a
lot more.  Branch early and often.  Every time you think about developing
a feature or fixing a bug, create a branch to do it on.

In fact, avoid doing any development on the master branch.  Merges only.

A branch is the git equivalent of a patch, and merging a branch is the
equivalent of applying that patch.  A branch gives it a name that
you can use to refer to it.  This is particularly useful if you're
sharing your changes.

Once you're done with a branch, you can delete it.  This is basically
just removing the refs/heads/<branch> file, but "git-branch -d" adds a
few extra safety checks.  Assuming you merged the branch in, you can
still find all the commits in the history, it's just the name that's
been deleted.

You can also rename a branch by renaming the refs/heads/branch file.
There's no git command to do this, but as long as you update
the HEAD symlink if necessary, you don't need one.

Periodically merge all of the branches you're working on into a testing
branch to see if everything works.  Blow away and re-create the
testing branch whenever you do this.  When you like the result,
merge them into the master.


* The .git directory

There are a number of files in the .git directory used by the
porcelain.  In case you're curious (I was), this is what they are:

index
- The actual index file.

objects/
- The object database.  Can be overridden by $GIT_OBJECT_DIRECTORY

hooks/
- where the hook scripts are kept.  The standard git template includes
  examples, but disabled by being marked non-executable.

info/exclude
- Default project-wide list of file patterns to exclude from notice.
  To this is added the per-directory list in .gitignore.
  See the git-ls-files docs for full details.

refs/
- References to development heads (branches) and tags.

remotes/
- Short names of remote repositories we pull from or push to.
  Details are in the "git-fetch" man page.

HEAD
- The current default development head.
- Created by git-init-db and never deleted
- Changed by git-checkout
- Used by git-commit and any other command that commits changes.
- May be a dangling pointer, in which case git-commit
  does an "initial checkin" with no parent.

COMMIT_EDITMSG
- Temp used by git-commit to edit a commit message.
COMMIT_MSG
- Temp used by git-commit to form a commit message,
  post-processed from COMMIT_EDITMSG.

FETCH_HEAD
- Just-fetched commits, to be merged into the local trunk.
- Created by git-fetch.
- Used by git-pull as the source of data to merge.

MERGE_HEAD
- Keeps track of what heads are currently being merged into HEAD.
- Created by git-merge --no-commit with the heads used 
- Deleted by git-checkout and git-reset (since you're abandoning
  the merge)
- Used by git-commit to supply additional parents to the current commit.
  (And deleted when done.)

MERGE_MSG
- Generated by git-merge --no-commit.
- Used by git-commit as the commit message for a merge
  (If present, git-commit doesn't prompt.)

MERGE_SAVE
- cpio archive of all locally modified files created by
  "git-merge" before starting to do anything, if multiple
  merge strategies are being attempted.
  Used to rewind the tree in case a merge fails.

ORIG_HEAD
- Previous HEAD commit prior to a merge or reset operation.

LAST_MERGE
- Set by the "resolve" strategy to the most recently merged-in branch.
  Basically, a copy of MERGE_HEAD.  Not used by the other merge strategies,
  and resolve is no longer the default, so its utility is very limited.

BISECT_LOG
- History of a git-bisect operation.
- Can be replayed (or, more usefully, a prefix can) by "git-bisect replay"
BISECT_NAMES
- The list of files to be modified by git-bisect.
- Set by "git-bisect start"

TMP_HEAD (used by git-fetch)
TMP_ALT (used by git-fetch)


* Git command summary

There are slightly over a hundred git commands.  This section tries to
classify them by purpose, so you can know which commands are intended to
be used for what.  You can always use the low-level plumbing directly,
but that's inconvenient and error-prone.

Helper programs (not for direct use) for a specific utility are shown
indented under the program they help.

Note that all of these can be invoked using the "git" wrapper by replacing
the leading "git-" with "git ".  The results are exactly the same.
There is a suggestion to reduce the clutter in /usr/bin and move all
the git binaries to their own directory, leaving just the git wrapper
in /usr/bin. so you'll have to use it or adjust your $PATH.  But that
hasn't happened yet.  In the meantime, including the hyphen makes
tab-completion work.

I include ".sh", ".perl", etc. suffixes to show what the programs are
written in, so you can read those scripts written in languages you're
familiar with.  These are the names in the git source tree, but the
suffix is not included in the /usr/bin copies.

+ Administrative commands
git-init-db

+ Object database maintenance:
git-convert-objects
git-fsck-objects
git-lost-found.sh
git-prune.sh
git-relink.perl

+ Pack maintenance
git-count-objects.sh
git-index-pack
git-pack-objects
git-pack-redundant
git-prune-packed
git-repack.sh
git-show-index
git-unpack-objects
git-verify-pack

+ Important primitives
git-commit-tree
git-rev-list
git-rev-parse

+ Useful primitives
git-ls-files
git-update-index

+ General script helpers (used only by scripts)
git-cat-file
git-check-ref-format
git-checkout-index
git-fmt-merge-msg.perl
git-hash-object
git-ls-tree
git-repo-config
git-unpack-file
git-update-ref
git-sh-setup.sh
git-stripspace
git-symbolic-ref
git-var
git-write-tree

+ Oddballs
git-mv.perl

+ Code browsing
git-diff.sh
  git-diff-files
  git-diff-index
  git-diff-tree
  git-diff-stages
git-grep.sh
git-log.sh
git-name-rev
git-shortlog.perl
git-show-branch
git-whatchanged.sh

+ Making local changes
git-add.sh
git-bisect.sh
git-branch.sh
git-checkout.sh
git-commit.sh
git-reset.sh
git-status.sh

+ Cherry-picking
git-cherry.sh
  git-patch-id
git-cherry-pick.sh
git-rebase.sh
git-revert.sh

+ Accepting changes by e-mail
git-apply
git-am.sh
  git-mailinfo
  git-mailsplit
  git-applypatch.sh
git-applymbox.sh

+ Publishing changes by e-mail
git-format-patch.sh
git-send-email.perl

+ Merging
git-merge.sh
  git-merge-base
  git-merge-index
    git-merge-one-file.sh
  git-merge-octopus.sh
  git-merge-ours.sh
  git-merge-recursive.py
  git-merge-resolve.sh
  git-merge-stupid.sh
git-read-tree
git-resolve.sh
git-octopus.sh

+ Making releases
git-get-tar-commit-id
git-tag.sh
  git-mktag
git-tar-tree
git-verify-tag.sh

+ Accepting changes by network
git-clone.sh
  git-clone-pack
git-fetch.sh
  git-fetch-pack
  git-local-fetch
  git-http-fetch
  git-ssh-fetch
git-ls-remote.sh
  git-peek-remote
git-parse-remote.sh
git-pull.sh
  git-ssh-pull
git-shell
  git-receive-pack

+ Publishing changes by network
git-daemon

git-push.sh
  git-http-push
  git-ssh-push
  git-ssh-upload
git-request-pull.sh
git-send-pack
git-update-server-info
git-upload-pack

All of the basic git commands are designed to be scripted.  When
scripting, use the "--" option to ensure that files beginning with
"-" won't be interpreted as options, and the "-z" option to output
NUL-terminated file names so embedded newlines won't break things.

(A person who'd do either of these on purpose is probably crazy, but
it's not actually illegal.)

Looking at existing shell scripts can be very informative.



* Detailed list

Here's a repeat, including descriptions.  I don't try to include
every detail you can find on the man page, but to explain when
you'd want to use a command.

+ Administrative commands
git-init-db
	This creates an empty git repository in ./.git (or $GIT_DIR if
	that is non-null) using a system-wide template.
	It won't hurt an existing repository.

+ Object database maintenance:
git-convert-objects
	You will *never* need to use this command.
	The git repository format has undergone some revision since its
	first release.  If you have an ancient and crufty git repository
	from the very very early days, this will convert it for you.
	But as you're new to git, it doesn't apply.
git-fsck-objects
	Validate the object database.  Checks that all references
	point somewhere, all the SHA1 hashes are correct, and that
	sort of thing.

	This walks the entire repository, uncompressing and hashing
	every object, so it takes a while.  Note that by default,
	it skips over packs, which can make it seem misleadingly fast.
git-lost-found.sh
	Find (using git-fsck-objects) any unreferenced commits and
	tags in the object database, and place them in a .git/lost-found
	directory.  This can be used to recover from accidentally
	deleting a tag or branch reference that you wanted to keep.

	This is the opposite of git-prune.
git-prune.sh
	Delete all unreachable objects from the object database.
	It deletes useless packs, but does not remove useless
	objects from the middle of partially useful packs.

	Git leaks objects in a number of cases, such as unsuccessful
	merges.  The leak rate is generally a small fraction of
	the rate at which the desired history grows, so it's not
	very alarming, but occasionally running git-prune will
	eliminate the 

	If you deliberately throw away a development branch, you
	will need to run this command to fully reclaim the disk space.

	On something like the full Linux repository, this takes
	a while.
git-relink.perl
	Merge the objects stores of multiple git repositories by
	making hard links between them.  Useful to save space if
	duplicate copies are accidentally created on one machine.

+ Pack maintenance
	The classic git format is to compress and store each object
	separately.  This is still used for all newly created changes.
	However, objects can also be stored en masse in "packs" which
	contain many objects and tan take advantage of delta-compressing.
	Repacking your repositories periodically can save space.
	(Repacking is pretty quick but not quick enough to be
	comfortable doing every commit.)
git-count-objects.sh
	Print the number and total size of unpacked objects in the
	repository, to help you decide when is a good time to repack.
git-index-pack
	A pack file has an accompanying .idx file to allow rapid lookup.
	This regenerates the .idx file from the .pack.  This is almost never
	needed directly, but can be used after transferring a .pack file
	between machines.
git-pack-objects
	Given a list of objects on stdin, build a pack file.  This is
	a helper used by the various network communication scripts.
git-pack-redundant
	Produce a list of redundant packs, for feeding to "xargs rm".
	A helper for git-prune.
git-prune-packed
	Delete unpacked object files that are duplicated in packs.
	(With -n, only lists them.)  A helper for git-prune.
git-repack.sh
	Make a new pack with all the unpacked objects.
	With -a, include already-packed objects in the new pack.
	With -d as well, deletes all the old packs thereby made redundant.
git-show-index
	Dump the contents of a pack's .idx file.  Mostly for
	debugging git itself.
git-unpack-objects
	Unpack a .pack file, the opposite of git-pack-objects.	With -n,
	doesn't actually create the files.  With -q, suppresses the
	progress indicator.
git-verify-pack
	Validate a pack file.  Useful when debugging git, and when
	downloading from a remote source.  A helper for git-clone.

+ Important primitives
	Although these primitives are not used directly very frequently,
	understanding them will help you understand other git commands
	that wrap them.
git-commit-tree
	Create a new commit object from a tree and a list of parent
	commits.  This is the primitive that's the heart of git-commit.
	(It's also used by git-am, git-applypatch, git-merge, etc.)
git-rev-list
	Print a list of commits (revisions), in reverse chronological
	order.  This is the heart of git-log and other history examination
	commands, and the options for specifying parts of history are
	shared by all of them.

	In particular, it takes an arbitrary number of revisions as
	arguments, some of which may be prefixed with ^ to negate them.
	These make up "include" and "exclude" sets.  git-rev-list
	lists all revisions that are ancestors of the "include" set
	but not ancestors of the "exclude" set.
	
	For this purpose, a revision is considered an ancestor of itself.
	Thus, "git-rev-list ^v1.1 v1.2" will list all revisions from
	the v1.2 release back to (but not including) the v1.1 release.

	Because this is so convenient, a special syntax, "v1.1..v1.2"
	is allowed as an equivalent.  However, occasionally the general
	form is useful.  For example, adding ^branch will show the trunk
	(including merges from the branch), but exclude the branch itself.

	Similarly, "branch ^trunk", a.k.a. trunk..branch, will show
	all work on the branch that hasn't been merged to the trunk.
	This works even though trunk is not a direct ancestor of branch.
	
	Git-rev-list has a variety of flags to control it output format.
	The default is to just print the raw SHA1 object IDs of the
	commits, but --pretty produces a human-readable log.

	You can also specify a set of files names (or directories),
	in which case output will be limited to commits that modified
	those files.

	This command is used extensively by the git:// protocol to compute
	a set of objects to send to update a repository.
git-rev-parse
	This is a very widely used command line canonicalizer for git
	scripts.  It converts relative commit references (e.g. master~3)
	to absolute SHA1 hashes, and can also pass through arguments
	not recognizable as references, so the script can interpret them.

	It is important because it defines the <rev> syntax.

	This takes a variety of options to specify how to prepare the
	command line for the script's use.  --verify is a particularly
	important one.

+ Useful primitives
	These primitives are potentially useful directly.
git-ls-files
	List files in the index and/or working directory.  A variety of
	options control which files to list, based on whether they
	are the same in both places or have been modified.  This command
	is the start of most check-in scripts.
git-update-index
	Copy the given files from the working directory into the index.
	This create the blob objects, but no trees yet.  (Note that
	editing a file executing this multiple times without creating a
	commit will generate orphaned objects.  Harmless.)

	One common safe option is "git-update-index --refresh".  This
	looks for files whose metadata (modification time etc.) has
	changed, but not their contents, and updates the metadata in the
	index so the file contents won't have to be examined again.

+ General script helpers (used only by scripts)
	These are almost exclusively helpers for use in porcelain
	scripts and have little use by themselves from the command line.
git-cat-file
	Extract a file from the object database.  You can ask for
	an object's type or size given only an object ID, but
	to get its contents, you have to specify the type.  This
	is a deliberate safety measure.
git-check-ref-format
	Verify that the reference specified on the command line is
	syntactically valid for a new reference name under $GIT_DIR/refs.
	A number of characters (^, ~, :, and ..) are reserved; see the man
	page for the full list of rules.
git-checkout-index
	Copy files from the index to the working directory, or to a
	specified directory.  Most important as a helper for git-checkout,
	this is also used by git-merge and git-reset.
git-fmt-merge-msg.perl
	Generate a reasonable default commit message for a merge.
	Used by git-pull and git-octopus.
git-hash-object
	Very primitive helper to turn an arbitrary file into an object,
	returning just the ID or actually adding it to the database.
	Used by the cvs-to-git and svn-to-git import filters.
git-ls-tree
	List the contents of a tree object.  Will tell you all the files
	in a commit.  Used by the checkout scripts git-checkout and git-reset.
git-repo-config
	Get and set options in .git/config.  The .git/config format
	is designed to be human-readable.  This gives programmatic
	access to the settings.  This currently has a lot of overlap
	with the function of git-var.
git-unpack-file
	Write the contents of the given block to a temporary file,
	and return the name of that temp file.  Used most often
	by merging scripts.
git-update-ref
	Rewrite a reference (in .git/refs/) to point to a new object.
	"echo $sha1 > $file" is mostly equivalent, but this adds locking
	so two people don't update the same reference at once.
git-sh-setup.sh
	This is a general prefix script that sets up
	$GIT_DIR and $GIT_OBJECT_DIRECTORY for a script,
	or errors out if the git control files can't be found.
git-stripspace
	Remove unnecessary whitespace.  Used mostly on commit messages
	received by e-mail.
git-symbolic-ref
	This queries or creates symlinks to references such as HEAD.
	Basically equivalent to readlink(1) or ln -s, this also works
	on platforms that don't have symlinks.  See the man page.
git-var
	Provide access to the GIT_AUTHOR_IDENT and/or GIT_COMMITTER_IDENT
	values, used in various commit scripts.  This currently has a
	lot of overlap with the function of git-repo-config.
git-write-tree
	Generate a tree object reflecting the current index.  The output
	is the tree object; if you don't remember it somewhere (usually,
	pass it to git-commit-tree), it'll be lost.

	This requires that the index be fully merged.  If any incomplete
	merges are present in the index (files in stages 1, 2 or 3),
	git-write-tree will fail.

+ Oddballs
git-mv.perl
	I have to admit, I'm not quite sure what advantages this is
	supposed to have over plain "mv" followed by "git-update-index",
	or why it's complex enough to need perl.

	Basically, this renames a file, deleting its old name and adding
	its new name to the index.  Otherwise, it's a two-step process
	to rename a file:
	- Rename the file
	- git-add the new name
	Followed by which you must commit both the old and new names

+ Code browsing
git-diff.sh
	Show changes between various trees.  Takes up to two tree
	specifications, and shows the difference between the versions.
	Zero arguments: index vs. working directory (git-diff-files)
	One: tree vs. working directory (git-diff-index)
	One, --cached: tree vs. index (git-diff-index)
	Two: tree vs. tree (git-diff-tree)

	This wrapper always produces human-readable patch output.
	The helpers all produce "diff-raw" format unless you supply
	the -p option.

	There are some interesting options.  Unfortunately, the git-diff
	man page is annoyingly sparse, and refers to the helper scripts'
	documentation rather than describing the many useful options
	they all have in common.  Please do read the man pages of the
	helpers to see what's available.
	
	In particular, although git does not explicitly record file
	renames, it has some pretty good heuristics to notice things.
	-M tries to detect renamed files by matching up deleted files
	with similar newly created files.  -C tries to detect copies
	as well.  By default, -C only looks among the modified files for
	the copy source.  For common cases like splitting a file in two,
	this works well.  The --find-copies-harder searches ALL files
	in the tree for the copy source.  This can be slow on large trees!

	See Documentation/diffcore.txt for an explanation of how all
	this works.
  git-diff-files
	Compare the index and the working directory.
  git-diff-index
	Compare the working directory and a given tree.  This is the
	git equivalent of the single-operand form of "cvs diff".
	If "--cached" is specified, uses the index rather than the working
	directory.
  git-diff-tree
	Compare two trees.  This is the git equivalent of the two-operand
	form of "cvs diff".  This command is sometimes useful by itself
	to see the changes made by a single commit.  If you give it
	only one commit on the command line, it shows the diff between
	that commit and its first parent.  If the commit specification
	is long and awkward to type, using "git-diff-tree -p <commit>"
	can be easier than "git-diff <commit>^ <commit>".
  git-diff-stages
	Although not called by git-diff, there is a fourth diff helper
	routine, used to compare the various versions of an unmerged
	file in the index.  It is intended for use by merging porcelain.
git-grep.sh
	A very simple wrapper that runs git-ls-files and greps the
	output looking for a file name.  Does nothing fancy except
	saves typing.
git-log.sh
	Wrapper around git-rev-list --pretty.  Shows a history
	of changes made to the repository.  Takes all of git-rev-list's
	options for specifying which revisions to list.
git-name-rev
	Find a symbolic name for the commit specified on the
	command line, and returns a symbolic name of the form
	"maint~404^2~7".  Basically, this does a breadth-first search
	from all the heads in .git/refs looking for the given commit.
git-shortlog.perl
	This is a filter for the output of "git-log --pretty=short"
	to generate a one-line-per-change "shortlog" as Linus likes.
git-show-branch
	Visually show the merge history of the references given as
	arguments.  Prints one column per reference and one line per
	commit showing whether that commit is an ancestor of each
	reference.
git-whatchanged.sh
	A simple wrapper around git-rev-list and git-diff-tree,
	this shows the change history of a repository.  Specify a
	directory or file on the command line to limit the
	output to changes affecting those files.  This isn't
	the same as "cvs annotate", but it serves a similar purpose
	among git folks.

	You can add the -p option to include patches as well as log
	comments.  You can also add the -M or -C option to follow
	history back through file renames.

	-S is interesting: it's the "pickaxe" option.  Given a string,
	this limits the output to changes that make that string appear
	or disappear.  This is for "digging through history" to see when
	a piece of code was introduced.  The string may (and often does)
	contain embedded newlines.  See Documentation/cvs-migration.txt.

+ Making local changes
	All of these are examples of "porcelain" scripts.  Reading the
	scripts themselves can be informative; they're generally not
	too confusing.
git-add.sh
	A simple wrapper around "git-ls-files | git-update-index --add"
	to add new files to the index.   You may specify directories.
	You need to invoke this for every new file you want git to
	track.
git-bisect.sh
	Utility to do a binary search to find the change that broke something.
	The heart of this is in "git-rev-list --bisect"
	A very handy little utility!  Kernel developers love it
	when you tell them exactly which patch broke something.
	NOTE: this uses the head named "bisect", and will blow
	away any existing branch by that name.  Try not to
	create a branch with that name.

	There are three steps:
	git-bisect start [<files>]
		- Reset to start bisecting.  If any files are specified,
		  only they will be checked out as bisection proceeds.
	git-bisect good [<revision>]
		- Record the revision as "good".  The change being sought
		  must be after this revision.
	git-bisect bad [<revision>]
		- Record the revision as "bad".  The change being sought
		  must be before or equal to this revision.
	As soon as you have specified one good version and one bad version,
	git-bisect will find a halfway point and check out that
	revision.  Build and test it, then report it as good or bad,
	and git-bisect will narrow the search.  Finally, git-bisect
	will tell you exactly which change caused the problem.
	git-bisect log
		- Show a history of revisions.
	git-bisect replay
		- Replay (part of) a git-bisect log.  Generally used
		  to recover from a mistake, you can truncate the log
		  before the mistake and replay it to continue.
	If git-bisect chooses a version that cannot build, or you
	are otherwise unable to determine whether it is good or bad,
	you can change revisions with "git-reset --hard <revision>"
	to another checkout between the current good and bad limits, and
	continue from there.  "git-reset --hard <revision>" is generally
	dangerous, but you are on a scratch branch.

	This can, of course, be used to look for any change, even
	one for the better, if you can avoid being confused by the
	terms "good" and "bad".
git-branch.sh
	Most commonly used bare, to show the available branches.
	Show, create, or delete a branch.  The current branches
	are simply the contents of .git/refs/heads/.
	Note that this does NOT switch to the created branch!
	For the common case of creating a branch and immediately
	switching to it, "git-checkout -b <branch>" is simpler.
git-checkout.sh
	This does two superficially similar but very different things
	depending on whether any files or paths are specified on the
	command line.

	git-checkout [-f] [-b <new-branch>] <branch>
		This switches (changes the HEAD symlink to) the specified
		branch, updating the index and working directory to
		reflect the change.  This preserves changes in the
		working directory unless -f is specified.
		If -b is specified, a new branch is started from the
		specified point and switched to.  If <branch> is omitted,
		it defaults to HEAD.  This is the usual way to start a
		new branch.

	git-checkout [<branch>] [--] <paths>...
		This replaces the files specified by the given paths with
		the versions from the index or the specified branch.
		It does NOT affect the HEAD symlink, just replaces the
		specified paths.  This form is like a selective form of
		"git-reset".  Normally, this can guess whether the first
		argument is a branch name or a path, but you can use
		"--" to force the latter interpretation.

	With no branch, this is used to revert a botched edit of a
	particular file.

	Both forms use git-read-tree internally, but the net effect is
	quite different.
git-commit.sh
	Commit changes to the revision history.  In terms of primitives,
	this does three things:
	1) Updates the index file with the working directory files
	   specified on the command line, or -a for all
	   (using git-diff-files --name-only | git-update_index),
	2) Prompts for or generates a commit message, and then
	3) Creates a commit object with the current index contents.

	This also executes the pre-commit, commit-msg, and
	post-commit hooks if present.

	This will remove deleted files from the index, but will not
	add new files to the index, even if explicitly specified on the
	command line; you must use git-add for that.
git-reset.sh
	Explained in detail in "resetting", above.  This modifies the
	current branch head reference (as pointed to by .git/HEAD)
	to refer to the given commit.  It does not modify .git/HEAD 
	Reset the current HEAD to the specified commit, so that future
	checkins will be relative to it.  There are three
	variations:
	--soft: Just move the HEAD link.  The index is unchanged.
	--mixed (default): Move the HEAD link and update the index file.
		Any local changes will appear not checked in.
	--hard: Move the HEAD links, update the index file, and
		check out the index, overwriting the working
		directory.  Like "cvs update -C".
	In case of accidents, this copies the previous head
	object ID to ORIG_HEAD (which is NOT a symlink).
git-status.sh
	Show all files in the directory not current with respect
	to the git HEAD.  The basic categories are:
	1) Changed in the index, will be included in the next commit.
	2) Changed in the working directory but NOT in the index; will
	   be committed only if added via git-update-index or the
	   git-commit command line.
	3) Not tracked by git.

+ Cherry-picking
	Cherry-picking is the process of taking part of the changes
	introduced on one tree and applying those changes to another.
	This doesn't produce a parent/descendant relationship in the
	commit history.

	To produce that relationship, there's a special type of merge you
	can do if you've taken everything you want off a branch and
	want to show it in the merge history without actually importing
	any changes from it: ours.  "git-merge -s ours" will generate a
	commit that shows some branches were merged in, but not
	actually alter the current HEAD source code in any way.

	One thing cherry-picking is sometimes used for is taking a
	development branch and re-organizing the changes into a patch
	series for submission to the Linux kernel.
git-cherry.sh
	This searches a branch for patches which have not been applied
	to another.  Basically, it finds the unpicked cherries.
	It searches back to the common ancestor of the named branch and
	the current head using git-patch-id to identify similarity
	in patches.
  git-patch-id
	Generate a hash of a patch, ignoring whitespace and line numbers
	so that "the same" patch, even relative to a different code base,
	probably has the same hash, and different patches probably have
	different ones.  git-cherry looks for patch hashes which 
	are present on the branch (source branch) that are not present
	on the trunk (destination branch).
git-cherry-pick.sh
	Given a commit (on a different branch), compute a diff between
	it and its immediate parent, and apply it to the current HEAD.  
	This is actually the same script as "git revert", but
	works forward.  git-cherry finds the patches, this merges them.
	Handles failures gracefully.
git-rebase.sh
	Move a branch to a more recent "base" release.	This just extracts
	all the patches applied on the local head since the last merge
	with upstream (using git-format-patch) and re-applies them
	relative to the current upstream with git-am (explained under
	"accepting changes by e-mail").  Finally, it deletes the old
	branch and gives its name to the new one, so your branch now
	contains all the same changes, but relative to a different base.
	Basically the same as cherry-picking an entire branch.
git-revert.sh
	Undo a commit.	Basically "patch -R" followed by a commit.
	This is actually the same script as "git-cherry-pick", just
	applies the patch in reverse, undoing a change that you don't
	wish to back up to using git-reset.  Handles failures gracefully
	by telling the user what to do.

+ Accepting changes by e-mail
git-apply
	Apply a (git-style extended) patch to the current index
	and working directory.
git-am.sh
	The new and improved "apply an mbox" script.  Takes an
	mbox-style concatenation of e-mails as input and batch-applies
	them, generating one commit per message.  Can resume after
	stopping on a patch problem.
	(Invoke it as "git-am --skip" or "git-am --resolved" to
	deal with the problematic patch and continue.)
  git-mailinfo
	Given a single mail message on stdin (in the Linux standard
	SubmittingPatches format), extract a commit message and
	the patch proper.
  git-mailsplit
	Split an mbox into separate files.
  git-applypatch.sh
	Tries simple git-apply, then tries a few other clever merge
	strategies to get a patch to apply.  Used in the main loop
	of git-am and git-applymbox.
git-applymbox.sh
	This is Linus's original apply-mbox script.  Mostly superseded by
	git-am (which is friendlier and has more features), but he still
	uses it, so it's maintained.  This is so old it was originally
	a test of the git core called "dotest", and that name is still
	lurking in the temp file names.

+ Publishing changes by e-mail
git-format-patch.sh
	Generate a series of patches, in the preferred Linux kernel
	(Documentation/SubmittingPatches) format, for posting to lkml
	or the like.  This formats every commit on a branch as a separate
	patch.
git-send-email.perl
	Actually e-mail the output of git-format-patch.
	(This uses direct SMTP, a matter of some controversy.  Others feel
	that /bin/mail is the correct local mail-sending interface.)

+ Merging
git-merge.sh
	Merge one or more "remote" heads into the current head.
	Some changes, when there has been change only on one branch or
	the same change has been made to all branches, can be resolved
	by the "trivial in-index" merge done by git-read-tree.	For more
	complex cases, git provides a number of different merge strategies
	(with reasonable defaults).

	Note that merges are done on a filename basis.	While git tries
	to detect renames when generating diffs, most merge strategies
	don't track them by renaming.  (The "recursive" strategy, which
	recently became the default, is a notable exception.)
  git-merge-base
	Finds a common ancestor to use when comparing the changes made
	on two branches.  The simple case is straightforward, but if
	there have been cross-merges between the branches, it gets
	somewhat hairy.  The algorithm is not 100% final yet.
	(There's also --all, which lists all candidates.)
  git-merge-index
	This is the outer merging loop.  It takes the name of a one-file
	merge executable as an argument, and runs it for every incomplete
	merge.
    git-merge-one-file.sh
	This is the standard git-merge-index helper, that tries to
	resolve a 3-way merge.  A helper used by all the merge strategies.
	(Except "recursive" which has its own equivalent.)
  git-merge-octopus.sh
	Many-way merge.  Overlaps should be negligible.
  git-merge-ours.sh
	A "dummy" merge strategy helper.  Claims that we did the merge, but
	actually takes the current tree unmodified.  This is used to
	cleanly terminate side branches that heve been cherry-picked in.
  git-merge-recursive.py
	A somewhat fancier 3-way merge.   This handles multiple cross-merges
	better by using multiple common ancestors.
  git-merge-resolve.sh
  git-merge-stupid.sh
	Not actually used by git-merge, this is a simple example
	merge strategy.
git-read-tree
	Read the given tree into the index.  This is the difference
	between the "--soft" and "--mixed" modes of git-reset, but the
	important thing this command does is simple merging.
	If -m is specified, this can take up to three trees as arguments.
git-resolve.sh
	OBSOLETE.  Perform a merge using the "resolve" strategy.
	Has been superseded by the "-s resolve" option to git-merge
	and git-pull.
git-octopus.sh
	OBSOLETE.   Perform a merge using the "octopus" strategy.
	Has been superseded by the "-s octopus" option to git-merge
	and git-pull.

+ Making releases
git-get-tar-commit-id
	Reads out the commit ID that git-tar-tree puts in its output.
	(Or fails if this isn't a git-generated tar file.)
git-tag.sh
	Create a tag in the refs/tags directory.  There are two kinds:
	"lightweight tags" are just references to commits.  More
	serious tags are GPG-signed tag objects, and people receiving
	the git tree can verify that it is the version that you released.
  git-mktag
	Creates a tag object.  Verifies syntactic correctness of its
	input.  (If you want to cheat, use git-hash-object.)
git-tar-tree
	Generate a tar archive of the named tree.  Because git does NOT
	track file timestamps, this uses the timestamp of the commit,
	or the current time if you specify a tree.
	Also stores the commit ID in an extended tar header.
git-verify-tag.sh
	Given a tag object, GPG-verify the embedded signature.

+ Accepting changes by network
	Pulling consists of two steps: retrieving the remote commit
	objects and everything they point to (including ancestors),
	then merging that into the desired tree.  There are still
	separate fetch and merge commands, but it's more commonly done
	with a single "git-pull" command.  git-fetch leaves the commit
	objects, one per line, in .git/FETCH_HEAD.  git-merge will
	merge those in if that file exists when it is run.

	References to remote repositories can be made with long URLs,
	or with files in the .git/remotes/ directory.  The latter
	also specifies the local branches to merge the fetched data into,
	making it very easy to track a remote repository.
git-clone.sh
	Create a new local clone of a remote repository.
	(Can do a couple of space-sharing hacks when "remote" is on
	a local machine.)

	You only do this once.
  git-clone-pack
	Runs git-upload-pack remotely and places the resultant pack
	into the local repository.  Supports a variety of network
	protocols, but "remote" can also be a different directory on
	the current machine.
git-fetch.sh
	Fetch the named refs and all linked objects from a remote repository.
	The resultant refs (tags and commits) are stored in .git/FETCH_HEAD,
	which is used by a later git-resolve or git octopus.

	This is the first half of a "git pull" operation.
  git-fetch-pack
	Retrieve missing objects from a remote repository.
  git-local-fetch
	Duplicates a git repository from the local system.
	(Er... is this used anywhere???)
  git-http-fetch
	Do a fetch via http.  Http requires some kludgery on the
	server (see git-update-server-info), but it works.
  git-ssh-fetch
	Do a fetch via ssh.
git-ls-remote.sh
	Show the contents of the refs/heads/ and/or refs/tags/ directories
	of a remote repository.  Useful to see what's available.
  git-peek-remote
	Helper C program for the git-ls-remote script.  Implements the
	git protocol form of it.
git-parse-remote.sh
	Helper script to parse a .git/remotes/ file.  Used by a number
	of these programs.
git-pull.sh
	Fetches specific commits from the given remote repository,
	and merges everything into the current branch.	If a remote
	commit is named as src:dst, this merges the remote head "src"
	into the branch "dst" as well as the trunk.  Typically, the "dst"
	branch is not modified locally, but is kept as a pristine copy
	of the remote branch.

	One very standard example of this contention is that
	a repository that is tracking another specifies "master:origin"
	to provide a pristine local copy of the remote "master"
	branch in the local branch named "origin".
  git-ssh-pull
	A helper program that pulls over ssh.
git-shell
	A shell that can be used for git-only users.  Allows git
	push (git-receive-pack) and pull (git-upload-pack) only.
  git-receive-pack
	Receive a pack from git-send-pack, validate it, and add it to
	the repository.  Adding just the bare objects has no security
	implications, but this can also update branches and tags, which
	does have an effect.
	Runs pre-update and post-update hooks; the former may do
	permissions checking and disallow the upload.
	This is the command run remotely via ssh by git-push.

+ Publishing changes by network
git-daemon
	A daemon that serves up the git native protocol so anonymous
	clients can fetch data.  For it to allow export of a directory,
	the magic file name "git-daemon-export-ok" must exist in it.

	This does not accept (receive) data under any circumstances.
git-push.sh
	Git-pull, only backwards.  Send local changes to a remote
	repository.  The same .git/remotes/ short-cuts can be used,
	and the same src:dst syntax.  (But this time, the src is local
	and the dst is remote.)
  git-http-push
	A helper to git-push to implement the http: protocol.
  git-ssh-push
	A helper to git-push to push over ssh.
  git-ssh-upload
	Another helper.  This just does the equivalent of "fetch"
	("throw"?) and doesn't actually merge the result.  Obsolete?
git-request-pull.sh
	Generate an e-mail summarizing the changes between two commits,
	and request that the recipient pull them from your repository.
	Just a little helper to generate a consistent and informative
	format.
git-send-pack
	Pack together a pile of objects missing at the destination and
	send them.  This is the sending half that talks to a remote
	git-receive-pack.
git-update-server-info
	To run git over http, auxiliary info files are required that
	describes what objects are in the repository (since git-upload-pack
	can't generate this on the fly).  If you want to publish a
	repository via http, run this after every commit.  (Typically
	via the hooks/post-update script.)
git-upload-pack
	Like git-send-pack, but this is invoked by a remote git-fetch-pack.

^ permalink raw reply	[relevance 1%]

* Re: as promised, docs: git for the confused
       [not found]     <7vbqzrcmgr.fsf@assigned-by-dhcp.cox.net>
@ 2005-12-09  5:44  1% ` linux
  0 siblings, 0 replies; 200+ results
From: linux @ 2005-12-09  5:44 UTC (permalink / raw)
  To: git; +Cc: linux

The revised version, with the changes previously noted.


TODO: Describe the config file.  It's a recent invention, and I
haven't found a good description of its contents.


		"I Don't Git It"
		Git for the confused

Git is hardly lacking in documentation, but coming at it fresh, I found
it somewhat confusing.

Git is a toolkit in the Unix tradition.  There are a number of primitives
written in C, which are made friendly by a layer of shell scripts.
These are known in git-speak, as the "plumbing" and the "porcelain",
respectively.  The porcelain should work and look nice.  The plumbing
should just deal with lots of crap efficiently.

Much of git's documentation was first written to explain the plumbing to
the people writing the porcelain.  Since then, although the essentials
haven't changed, porcelain has been added and conventions have been
established that make it a lot more pleasant to deal with.  Some commands
have been changed or replaced, and it's not quite the same.

Using the original low-level commands is now most likely more difficult
than necessary, unless you want to do something not supported by the
existing porcelain.

This document retraces (with fewer false turns) how I learned my way
around git.  There are some concepts I didn't understand so well the
first time through, and an overview of all the git commands, grouped
by application.


A good rule of thumb is that the commands with one-word names (git-diff,
git-commit, git-merge, git-push, git-pull, git-status, git-tag, etc.) are
designed for end-user use.  Multi-word names (git-count-objects,
git-write-tree, git-update-index) are generally designed for use from
a script.

This isn't ironclad.  The first command to start using git is git-init-db,
and git-show-branch is pure porcelain, while git-mktag is a primitive.
And you don't often run git-daemon by hand.  But still, it's a useful
guideline.



* Background material.

To start with, read "man git".  Or Documentation/git.txt in the git
source tree, which is the same thing.  Particularly note the description
of the index, which is where all the action in git happens.
This document is to supplement that, not replace it.

Like other version control systems, git has a current version (referred
to as HEAD) in its object database, you make changes in the working
directory, and then commit them, which appends a new version and makes
that the new HEAD.

However, there's also this "index" thing interposed.  As "man git"
explains, you can have one version of the file in the HEAD, a second
in the index, and a third in the working directory.  That's weird
and confusing - why does git allow that?  Why isn't the index just an
implementation detail that caches the HEAD until you commit a new one?

The answer is merging, which does all its work in the index.  Being a
toolkit, git has to pass partial merges around between its various
tools, which means keeping track of multiple files all competing for
the same name.  Neither the object database nor the working directory
let you have multiple files with the same name.

The index is really very simple.  It's a series of structures, each
describing one file.  There's an object ID (SHA1) of the contents,
some file metadata to detect changes (time-stamps, inode number, size,
permissions, owner, etc.), and the path name relative to the root of the
working directory.  It's always stored sorted by path name, for efficient
merging.  By watching for metadata changes, git can efficiently detect
that a a file may have changed, and only open and examine those files.

At (almost) any time, you can take a snapshot of the index and write
it as a tree object.

The only interesting feature is that each entry has a 2-bit stage number.
Normally, this is always zero, but each path name is allowed up to three
different versions (object IDs) in the index at once.  This is used to
represent an incomplete merge, and an unmerged index entry (with more
than one version) prevents committing the index to the object database.


Some porcelain layers, such as cogito, work to hide the index and this
potential confusion, but core git (shich is being described here) exposes
it.


* Terminology - heads, branches, refs, and revisions

(This is a supplement to what's already in "man git".)

The most common object needed by git primitives is a tree.  Since every
commit or tag refers to a unique tree, both of these are acceptable
"tree-ish" objects and can be used basically anywhere a tree is required.
Likewise, a tag almost always refers to a commit, so is "commit-ish"
and can be used where a commit is required.

(I'd say a tag *always* points to a commit, but it's possible to tag
a tree directly.  Probably the only time you will ever see this is
the v2.6.11 tag in the Linux history, because git was still under
heavy development and Linus was still making up the rules as he went
along.)

As soon as you get to the porcelain, the most commonly used object is
a commit.  Also known as a revision, this is a tree plus a history.

While you can always use the full object ID, you can also use a reference.
A reference is a file that contains a 40-character hex SHA1 object ID
(and a trailing newline).  When you specify the name of a reference,
it is searched for in one of the directories:
	.git/			(or $GIT_DIR)
	.git/refs/		(or $GIT_DIR/refs/)
	.git/refs/heads/	(or $GIT_DIR/refs/heads/)
	.git/refs/tags/		(or $GIT_DIR/refs/tags/)

You may use subdirectories by including slashes in the reference name.
There is no search order; if searching the above four path prefixes
produces more than one match for the reference name (it's ambiguous),
then the name is not valid.

There is additional syntax (which looks like "commit~3^2~17") for
specifying an ancestor of a given commit (or tag).  This is documented
in detail in the documentation for git-rev-parse.  Briefly, commit^
is the parent of the given commit.  commit^^ is the grandparent, etc..
If there is more than one ancestor (a merge), then they can be referenced
as commit^1 (a synonym for commit^), commit^2, commit^3, etc.  (commit^0
gives the commit object itself.  A no-op if you're starting from a commit,
but it lets you get the commit object from a tag object.)

As long strings of ^ can be annoying, they can be abbreviated using ~
syntax.  commit^^^ is the same as commit~3, ^^^^ is the same as ~4, etc.
You can see lots of examples in the output of "git-show-branch".


Now, the although the most primitive git tools don't care, a convention
among all the porcelain is that the current head of development is
.git/HEAD, a symbolic link to a reference under refs/heads/.

git-init-db creates HEAD pointing to refs/heads/master, and that is
traditionally the name used for the "main trunk" of development.
Note that initially refs/heads/master doesn't exist - HEAD is a
dangling symlink!  This is okay, and will cause the initial commit
to have zero parents.

A "head" is mostly synonymous with a "branch", but the terms have
different emphasis.  The "head" is particularly the tip of the branch,
where future development will be appended.  A "branch" is the entire
development history leading to the head.  However, as far as git is
concerned, they're both references to commit objects, referred to from
refs/heads/.

When you actually do more (with git-commit, or git-merge), then the
current HEAD reference is overwritten with the new commit's id, and
the old HEAD becomes HEAD^.  Since HEAD is a symlink, it's the file
in refs/heads/ that's actually overwritten.  (See the git-update-ref
documentation for further details.)

The git-checkout command actually changes the HEAD symlink.  git-checkout
enforces the rule that it will only check out a branch under refs/heads.
You can use refs/tags as a source for git-diff or any other command that
only examines the revision, but if you want to check it out, you have
to copy it to refs/heads.


* The git command

Git commands are generally separate executables or scripts, named with
a common "git-" prefix.  There's also a small wrapper called simply
"git" which converts a command like "git commit file.c" into "git-commit
file.c".  This usage resembles CVS and many other version control systems.

People vary in which form they prefer to use.  I use the git- prefixed
commands, because you have to ask for the man pages by those names,
and you can get tab-completion of the command names in the shell.
(With no special effort; yes, I know it can be done in many shells.)

However, there are plans for change here.  Due to the large number of git
commands (many of which are helpers not designed for interactive use),
there have been complaints about the clutter in /usr/bin.  There has
been motion towards putting the git-* commands in their own directory,
to be invoked by the /usr/bin/git wrapper.

In this case, you'll have to leave out the initial hyphen, or add the
git binary directory to your $PATH.


* Resetting

The "undo" command for commits to the object database is git-reset.
Like all deletion-type commands, be careful or you'll hurt yourself.
Given a commit (using any of the syntaxes mentioned above), this
sets the current HEAD to refer to the given commit.

This does NOT alter the HEAD symlink (as git-checkout <branch> will
do), but actually changes the reference pointed to by HEAD
(e.g. refs/heads/master) to contain a new object ID.

The classic example is to undo an erroneous commit, use
"git-reset HEAD^".

There are actually three kinds of git-reset:
git-reset --soft: Only overwrite the reference.  If you need to, you
	can put everything back with a second git-reset --soft OLD_HEAD.
git-reset --mixed: This is the default, which I always think of as
	"--medium".  Overwrite the reference, and (using git-read-tree)
	read the commit into the index.  The working directory is unchanged.
git-reset --hard: Do everything --mixed does, and also check out the index
	into the working directory, and delete any working directory
	files whose names were in the old version but not in the new.
	This really erases all traces of the previous version.

The space taken up by the abandoned commit won't actually be
reclaimed until you collect garbage with git-prune.

git-reset with no commit specified is "git-reset HEAD", which is much
safer because the object reference is not actually changed.  This can be
used to undo changes in the index (or, with --hard, working directory)
that you did not intend.  Note, however, that it is not selective.
"git-checkout" has options for doing this selectively.

Like being sure what directory you're in when typing "rm -r", think
carefully about what branch you're on when typing "git-reset <commit>".

There is an undelete: git-reset stores the previous HEAD commit in
OLD_HEAD.  And git-lost-found can find leftover commits until you do
a git-prune.


* Merging

Merging is central to git operations.  Indeed, a big difference between
git and other version control systems is that git assumes that a change
will be merged more often than it's written, as it's passed around
different developers' repositories.  Even "git checkout" is a specialized
sort of merge.

The heart of merging is git-read-tree, but if you can understand it from
the man page, you're doing better than me.

As mentioned, the index and the working directory versions of a file
could both be different from the HEAD.  Git lets you merge "under" your
current working directory edits, as long as the merge doesn't change
the files you're editing.

There are some special cases of merging, but let me start with the
procedure for the general 3-way merge case: merging branch B into branch A
(the current HEAD).

1) Given two commits, find a common ancestor O to server as the origin
   of the merge.  The basic "resolve" algorithm uses git-merge-base for
   the task, but the "recursive" merge strategy gets more clever in the
   case where there are multiple candidates.  I won't got into what it
   does, but it does a pretty good job.

2) Add all three input trees (the Origin, A, and B) to the index by
   "git-read-tree -m O A B".  The index now contains up to three copies
   of every file.  (Four, including the original, but that is discarded
   before git-read-tree returns.)

   Then, for each file in the index, git-read-tree does the following:

   2a) For each file, git-merge-tree tries to collapse the various
       versions into one using the "trivial in-index merge".  This just
       uses the file blob object names to see if the file contents
       are identical, and if two or more of the three trees contain an
       identical copy of this file, it is merged.  A missing (deleted)
       file matches another missing file.

       Note that this is NOT a majority vote.  If A and B agree on the
       contents of the file, that's what is used.  (Whether O agrees is
       irrelevant in this case.)  But if O and A agree, then the change
       made in B is taken as the final value.  Likewise, if O and B agree,
       then A is used.

   2b) If this is possible, then a check is made to see if the merge would
       conflict with any uncommitted work in the index or change the index
       out from under a modified working directory file.  If either of
       those cases happen, the entire merge is backed out and fails.

       (In the git source, the test "t/t1000-read-tree-m-3way.sh" has
       a particularly detailed description of the various cases.)

       If the merge is possible and safe, the versions are collapsed
       into one final result version.

   2c) If all three versions differ, the trivial in-index merge is
       not possible, and the three source versions are left in the
       index unmerged.  Again, if there was uncommitted work in the
       index or the working directory, the entire merge fails.

3) Use git-merge-index to iterate over the remaining unmerged files, and
   apply an intra-file merge.  The intra-file merge is usually done with
   git-merge-one-file, which does a standard RCS-style three-way merge
   (see "man merge").

4) Check out all the successfully merged files into the working directory.

5) If automatic merging was successful on every file, commit the merged
   version immediately and stop.

6) If automatic merging was not complete, then replace the working
   directory copies of any remaining unmerged files with a merged copy
   with conflict markers (again, just like RCS or CVS) in the working
   directory.  All three source versions are available in the index for
   diffing against.

   (We have not destroyed anything, because in step 2c), we checked to make
   sure the working directory file didn't have anything not in the
   repository.)

7) Manually edit the conflicts and resolve the merge.  As long as an
   unmerged, multi-version file exists in the index, committing the
   index is forbidden.  (You can use the options to git-diff to
   see the changes.)

8) Commit the final merged version of the conflicting file(s), replacing
   the unmerged versions with the single finished version.

Note that if the merge is simple, with no one file edited on both
branches, git never has to open a single file.  It reads three tree
objects (recursively) and stat(2)s some working directory files to
verify that they haven't changed.

Also note that this aborts and backs out rather than overwrite
anything not committed.  You can merge "under" uncommitted edits
only if those edits are to files not affected by the merge.

There's one special case to the rule that "you can't merge a file with
uncommitted changes in the index": if the changes match what the merge
would produce anyway (the patch from branch B has already been applied),
the merge succeeds.  There's no point in making you undo a change just
so the merge can redo it.


* 2-way merging

This merge is used by git-checkout to switch between two branches,
while preserving any changes in the working directory and index.

A "2-way merge" is actually a 3-way merge with the contents of the
index as the "current HEAD", and the original HEAD as the Origin.
However, this merge is designed only for simple cases and only supports
the "trivial merge" cases.  It does not fall back to an intra-file merge.

Like the 3-way case, if a particular file hasn't changed between
the previous and new two heads, then git will preserve any uncommitted
edits, in both the index and the working directory.

If the file has changed in any way, git doesn't try to perform
any sort of intra-file merge, it just fails.
(Exception: like the 3-way merge, if the uncommitted change makes the
file the same as in the new head, the merge will succeed.)

* 1-way merging

This is only used by git-reset, and is just an optimization over
plain git-read-tree, but still it's interesting.

Plain (non-merging) git-read-tree will overwrite the index entries with
those from the tree.  This invalidates the cached stat data, causing
git to think all the working directory files are "potentially changed"
until you do a git-update-index --refresh.

In particular, this means that a subsequenct git-checkout-index,
such as "git-reset --hard" performs, would overwrite every file
in the working directory, even if only with a copy of itself,
causing a lot of extra work next time you run make.

By specifying a 1-way merge, any index entry whose contents (object ID)
matches the incoming tree will have its cached stat data preserved.
Thus, git will know if the working directory file is not changed, and
will not overwrite if you execute git-checkout-index.

This is just an efficiency hack, so it's not terribly important
to remember.


* Special merges - already up to date, and fast-forward

There are two cases of 3-way or 2-way merging that are special.
Recall that the basic merge pattern is

   B--------> A+B
  /        /
 /        /
O -----> A

The two special cases arise if one of A or B is a direct ancestor of
the other.  In that case, the common ancestor of both A and B is the
older of the two commits.  And the merged result is simply the
newer of the two, unchanged.

Recalling that we are merging B into A, if B is a direct ancestor of A,
then A already includes all of B.  A is "already up to date" and not
changed at all by the merge.

The other case you'll hear mentioned, because it happens a lot when
pulling, is when A is a direct ancestor of B.  In this case, the
result of the merge is a "fast-forward" to B.

Both of these cases are handled very efficiently by the in-index merge
done by git-read-tree.


* Deleted files during merges

There is one small wrinkle in git's merge algorithm that will probably
never bite you, but I ought to explain anyway, just because it's so rare
that it's difficult to discover it by experiment.

The index contains a list of all files that git is tracking.  If the
index file is empty or missing and you do a commit, you write an empty
tree with no files.

When merging, if git finds no pre-existing index entry for a path it is
trying to merge, it considers that to mean "status unknown" rather than
"modified by being deleted".  Thus, this is not uncommitted work
in the index file, and does not block the merge.  Instead, the
file will reappear in the merge.

This is because it is possible to blow away the index file (rm .git/index
will do it quite nicely), and if this was considered a modification to
be preserved, it would cause all sorts of conflicts.

So the one change to the index that will NOT be preserved by a merge is
the removal of a file.  A missing index entry is treated the same as an
unmodified index entry.  The index will be updated, and when you check
out the revision, the working directory file will be (re-)created.

Note that none of this affects you in the usual case where you make
changes in the working directory only, and leave the index equal to HEAD
until you're ready to commit.


* Packs

Originally, git stored every object in its own file, and used rsync
to share repositories.  It was quickly discovered that this brought
mighty servers to their knees.  It's great for retrieving a small
subset of the database the way git usually does, but rsync scans the
whole .git/objects tree every time.

So packs were developed.  A pack is a file, built all at once, which
contains many delta-compressed objects.  With each .pack file,
there's an accompanying .idx file that indexes the pack so that
individual objects can be retrieved quickly.

You can reduce the disk space used by your repositories by periodically
repacking them with git-repack.  Normally, this makes a new incremental
pack of everything not already packed.  With the -a flag, this repacks
everything for even greater compression (but takes longer).

The git wire protocol basically consists of negotiation over what
objects needs to be transferred followed by sending a custom-built pack.
The .idx file can be reconstructed from the .pack file, so it's
never transferred.

[[ Is once every few hundred commits a good rule of thumb for repacking?
When .git/objects/?? reaches X megabytes?  I think too many packs is
itself a bad thing, since they all have to be searched. ]]


* Raw diffs

A major source of git's speed is that it tries to avoid accessing files
unnecessarily.  In particular, files can be compared based on their
object IDs without needing to open and read them.  As part of this,
the responsibility for finding file differences (printing diffs) is
divided into finding what files have changed, and finding the changes
within those files.

This is all explained in the Documentation/diffcore.txt in the git
distribution, but the basics is that many of the primitives spit out a
line like this:
:100755 100755 68838f3fad1d22ab4f14977434e9ce73365fb304 0000000000000000000000000000000000000000 M	git-bisect.sh
when asked for a diff.  This is known as a "raw diff".  They can be
told to generate a human-readable diff with the "-p" (patch) flag.
The git-diff command includes this by default.


* Advice on using git

If you're used to CVS, where branches and merges are "advanced" features
that you can go a long time, you need to learn to use branches in git a
lot more.  Branch early and often.  Every time you think about developing
a feature or fixing a bug, create a branch to do it on.

In fact, avoid doing any development on the master branch.  Merges only.

A branch is the git equivalent of a patch, and merging a branch is the
equivalent of applying that patch.  A branch gives it a name that
you can use to refer to it.  This is particularly useful if you're
sharing your changes.

Once you're done with a branch, you can delete it.  This is basically
just removing the refs/heads/<branch> file, but "git-branch -d" adds a
few extra safety checks.  Assuming you merged the branch in, you can
still find all the commits in the history, it's just the name that's
been deleted.

You can also rename a branch by renaming the refs/heads/branch file.
There's no git command to do this, but as long as you update
the HEAD symlink if necessary, you don't need one.

Periodically merge all of the branches you're working on into a testing
branch to see if everything works.  Blow away and re-create the
testing branch whenever you do this.  When you like the result,
merge them into the master.


* The .git directory

There are a number of files in the .git directory used by the
porcelain.  In case you're curious (I was), this is what they are:

index
- The actual index file.

objects/
- The object database.  Can be overridden by $GIT_OBJECT_DIRECTORY

hooks/
- where the hook scripts are kept.  The standard git template includes
  examples, but disabled by being marked non-executable.

info/exclude
- Default project-wide list of file patterns to exclude from notice.
  To this is added the per-directory list in .gitignore.
  See the git-ls-files docs for full details.

refs/
- References to development heads (branches) and tags.

remotes/
- Short names of remote repositories we pull from or push to.
  Details are in the "git-fetch" man page.

HEAD
- The current default development head.
- Created by git-init-db and never deleted
- Changed by git-checkout
- Used by git-commit and any other command that commits changes.
- May be a dangling pointer, in which case git-commit
  does an "initial checkin" with no parent.

COMMIT_EDITMSG
- Temp used by git-commit to edit a commit message.
COMMIT_MSG
- Temp used by git-commit to form a commit message,
  post-processed from COMMIT_EDITMSG.

FETCH_HEAD
- Just-fetched commits, to be merged into the local trunk.
- Created by git-fetch.
- Used by git-pull as the source of data to merge.

MERGE_HEAD
- Keeps track of what heads are currently being merged into HEAD.
- Created by git-merge --no-commit with the heads used 
- Deleted by git-checkout and git-reset (since you're abandoning
  the merge)
- Used by git-commit to supply additional parents to the current commit.
  (And deleted when done.)

MERGE_MSG
- Generated by git-merge --no-commit.
- Used by git-commit as the commit message for a merge
  (If present, git-commit doesn't prompt.)

MERGE_SAVE
- cpio archive of all locally modified files created by
  "git-merge" before starting to do anything, if multiple
  merge strategies are being attempted.
  Used to rewind the tree in case a merge fails.

ORIG_HEAD
- Previous HEAD commit prior to a merge or reset operation.

LAST_MERGE
- Set by the "resolve" strategy to the most recently merged-in branch.
  Basically, a copy of MERGE_HEAD.  Not used by the other merge strategies,
  and resolve is no longer the default, so its utility is very limited.

BISECT_LOG
- History of a git-bisect operation.
- Can be replayed (or, more usefully, a prefix can) by "git-bisect replay"
BISECT_NAMES
- The list of files to be modified by git-bisect.
- Set by "git-bisect start"

TMP_HEAD (used by git-fetch)
TMP_ALT (used by git-fetch)


* Git command summary

There are slightly over a hundred git commands.  This section tries to
classify them by purpose, so you can know which commands are intended to
be used for what.  You can always use the low-level plumbing directly,
but that's inconvenient and error-prone.

Helper programs (not for direct use) for a specific utility are shown
indented under the program they help.

Note that all of these can be invoked using the "git" wrapper by replacing
the leading "git-" with "git ".  The results are exactly the same.
There is a suggestion to reduce the clutter in /usr/bin and move all
the git binaries to their own directory, leaving just the git wrapper
in /usr/bin. so you'll have to use it or adjust your $PATH.  But that
hasn't happened yet.  In the meantime, including the hyphen makes
tab-completion work.

I include ".sh", ".perl", etc. suffixes to show what the programs are
written in, so you can read those scripts written in languages you're
familiar with.  These are the names in the git source tree, but the
suffix is not included in the /usr/bin copies.

+ Administrative commands
git-init-db

+ Object database maintenance:
git-convert-objects
git-fsck-objects
git-lost-found.sh
git-prune.sh
git-relink.perl

+ Pack maintenance
git-count-objects.sh
git-index-pack
git-pack-objects
git-pack-redundant
git-prune-packed
git-repack.sh
git-show-index
git-unpack-objects
git-verify-pack

+ Important primitives
git-commit-tree
git-rev-list
git-rev-parse

+ Useful primitives
git-ls-files
git-update-index

+ General script helpers (used only by scripts)
git-cat-file
git-check-ref-format
git-checkout-index
git-fmt-merge-msg.perl
git-hash-object
git-ls-tree
git-repo-config
git-unpack-file
git-update-ref
git-sh-setup.sh
git-stripspace
git-symbolic-ref
git-var
git-write-tree

+ Oddballs
git-mv.perl

+ Code browsing
git-diff.sh
  git-diff-files
  git-diff-index
  git-diff-tree
  git-diff-stages
git-grep.sh
git-log.sh
git-name-rev
git-shortlog.perl
git-show-branch
git-whatchanged.sh

+ Making local changes
git-add.sh
git-bisect.sh
git-branch.sh
git-checkout.sh
git-commit.sh
git-reset.sh
git-status.sh

+ Cherry-picking
git-cherry.sh
  git-patch-id
git-cherry-pick.sh
git-rebase.sh
git-revert.sh

+ Accepting changes by e-mail
git-apply
git-am.sh
  git-mailinfo
  git-mailsplit
  git-applypatch.sh
git-applymbox.sh

+ Publishing changes by e-mail
git-format-patch.sh
git-send-email.perl

+ Merging
git-merge.sh
  git-merge-base
  git-merge-index
    git-merge-one-file.sh
  git-merge-octopus.sh
  git-merge-ours.sh
  git-merge-recursive.py
  git-merge-resolve.sh
  git-merge-stupid.sh
git-read-tree
git-resolve.sh
git-octopus.sh

+ Making releases
git-get-tar-commit-id
git-tag.sh
  git-mktag
git-tar-tree
git-verify-tag.sh

+ Accepting changes by network
git-clone.sh
  git-clone-pack
git-fetch.sh
  git-fetch-pack
  git-local-fetch
  git-http-fetch
  git-ssh-fetch
git-ls-remote.sh
  git-peek-remote
git-parse-remote.sh
git-pull.sh
  git-ssh-pull
git-shell
  git-receive-pack

+ Publishing changes by network
git-daemon

git-push.sh
  git-http-push
  git-ssh-push
  git-ssh-upload
git-request-pull.sh
git-send-pack
git-update-server-info
git-upload-pack

All of the basic git commands are designed to be scripted.  When
scripting, use the "--" option to ensure that files beginning with
"-" won't be interpreted as options, and the "-z" option to output
NUL-terminated file names so embedded newlines won't break things.

(A person who'd do either of these on purpose is probably crazy, but
it's not actually illegal.)

Looking at existing shell scripts can be very informative.



* Detailed list

Here's a repeat, including descriptions.  I don't try to include
every detail you can find on the man page, but to explain when
you'd want to use a command.

+ Administrative commands
git-init-db
	This creates an empty git repository in ./.git (or $GIT_DIR if
	that is non-null) using a system-wide template.
	It won't hurt an existing repository.

+ Object database maintenance:
git-convert-objects
	You will *never* need to use this command.
	The git repository format has undergone some revision since its
	first release.  If you have an ancient and crufty git repository
	from the very very early days, this will convert it for you.
	But as you're new to git, it doesn't apply.
git-fsck-objects
	Validate the object database.  Checks that all references
	point somewhere, all the SHA1 hashes are correct, and that
	sort of thing.

	This walks the entire repository, uncompressing and hashing
	every object, so it takes a while.  Note that by default,
	it skips over packs, which can make it seem misleadingly fast.
git-lost-found.sh
	Find (using git-fsck-objects) any unreferenced commits and
	tags in the object database, and place them in a .git/lost-found
	directory.  This can be used to recover from accidentally
	deleting a tag or branch reference that you wanted to keep.

	This is the opposite of git-prune.
git-prune.sh
	Delete all unreachable objects from the object database.
	It deletes useless packs, but does not remove useless
	objects from the middle of partially useful packs.

	Git leaks objects in a number of cases, such as unsuccessful
	merges.  The leak rate is generally a small fraction of
	the rate at which the desired history grows, so it's not
	very alarming, but occasionally running git-prune will
	eliminate the 

	If you deliberately throw away a development branch, you
	will need to run this command to fully reclaim the disk space.

	On something like the full Linux repository, this takes
	a while.
git-relink.perl
	Merge the objects stores of multiple git repositories by
	making hard links between them.  Useful to save space if
	duplicate copies are accidentally created on one machine.

+ Pack maintenance
	The classic git format is to compress and store each object
	separately.  This is still used for all newly created changes.
	However, objects can also be stored en masse in "packs" which
	contain many objects and tan take advantage of delta-compressing.
	Repacking your repositories periodically can save space.
	(Repacking is pretty quick but not quick enough to be
	comfortable doing every commit.)
git-count-objects.sh
	Print the number and total size of unpacked objects in the
	repository, to help you decide when is a good time to repack.
git-index-pack
	A pack file has an accompanying .idx file to allow rapid lookup.
	This regenerates the .idx file from the .pack.  This is almost never
	needed directly, but can be used after transferring a .pack file
	between machines.
git-pack-objects
	Given a list of objects on stdin, build a pack file.  This is
	a helper used by the various network communication scripts.
git-pack-redundant
	Produce a list of redundant packs, for feeding to "xargs rm".
	A helper for git-prune.
git-prune-packed
	Delete unpacked object files that are duplicated in packs.
	(With -n, only lists them.)  A helper for git-prune.
git-repack.sh
	Make a new pack with all the unpacked objects.
	With -a, include already-packed objects in the new pack.
	With -d as well, deletes all the old packs thereby made redundant.
git-show-index
	Dump the contents of a pack's .idx file.  Mostly for
	debugging git itself.
git-unpack-objects
	Unpack a .pack file, the opposite of git-pack-objects.	With -n,
	doesn't actually create the files.  With -q, suppresses the
	progress indicator.
git-verify-pack
	Validate a pack file.  Useful when debugging git, and when
	downloading from a remote source.  A helper for git-clone.

+ Important primitives
	Although these primitives are not used directly very frequently,
	understanding them will help you understand other git commands
	that wrap them.
git-commit-tree
	Create a new commit object from a tree and a list of parent
	commits.  This is the primitive that's the heart of git-commit.
	(It's also used by git-am, git-applypatch, git-merge, etc.)
git-rev-list
	Print a list of commits (revisions), in reverse chronological
	order.  This is the heart of git-log and other history examination
	commands, and the options for specifying parts of history are
	shared by all of them.

	In particular, it takes an arbitrary number of revisions as
	arguments, some of which may be prefixed with ^ to negate them.
	These make up "include" and "exclude" sets.  git-rev-list
	lists all revisions that are ancestors of the "include" set
	but not ancestors of the "exclude" set.
	
	For this purpose, a revision is considered an ancestor of itself.
	Thus, "git-rev-list ^v1.1 v1.2" will list all revisions from
	the v1.2 release back to (but not including) the v1.1 release.

	Because this is so convenient, a special syntax, "v1.1..v1.2"
	is allowed as an equivalent.  However, occasionally the general
	form is useful.  For example, adding ^branch will show the trunk
	(including merges from the branch), but exclude the branch itself.

	Similarly, "branch ^trunk", a.k.a. trunk..branch, will show
	all work on the branch that hasn't been merged to the trunk.
	This works even though trunk is not a direct ancestor of branch.
	
	Git-rev-list has a variety of flags to control it output format.
	The default is to just print the raw SHA1 object IDs of the
	commits, but --pretty produces a human-readable log.

	You can also specify a set of files names (or directories),
	in which case output will be limited to commits that modified
	those files.

	This command is used extensively by the git:// protocol to compute
	a set of objects to send to update a repository.
git-rev-parse
	This is a very widely used command line canonicalizer for git
	scripts.  It converts relative commit references (e.g. master~3)
	to absolute SHA1 hashes, and can also pass through arguments
	not recognizable as references, so the script can interpret them.

	It is important because it defines the <rev> syntax.

	This takes a variety of options to specify how to prepare the
	command line for the script's use.  --verify is a particularly
	important one.

+ Useful primitives
	These primitives are potentially useful directly.
git-ls-files
	List files in the index and/or working directory.  A variety of
	options control which files to list, based on whether they
	are the same in both places or have been modified.  This command
	is the start of most check-in scripts.
git-update-index
	Copy the given files from the working directory into the index.
	This create the blob objects, but no trees yet.  (Note that
	editing a file executing this multiple times without creating a
	commit will generate orphaned objects.  Harmless.)

	A lot of early git documentation emphasizes this command,
	since you need to have modified files in the index before you
	can generate tree and commit objects.  But this is done by
	git-commit, and you rarely want to invoke git-update-index
	directly any more.

	One common safe option is "git-update-index --refresh".  This
	looks for files whose metadata (modification time etc.) has
	changed, but not their contents, and updates the metadata in the
	index so the file contents won't have to be examined again.

+ General script helpers (used only by scripts)
	These are almost exclusively helpers for use in porcelain
	scripts and have little use by themselves from the command line.
git-cat-file
	Extract a file from the object database.  You can ask for
	an object's type or size given only an object ID, but
	to get its contents, you have to specify the type.  This
	is a deliberate safety measure.
git-check-ref-format
	Verify that the reference specified on the command line is
	syntactically valid for a new reference name under $GIT_DIR/refs.
	A number of characters (^, ~, :, and ..) are reserved; see the man
	page for the full list of rules.
git-checkout-index
	Copy files from the index to the working directory, or to a
	specified directory.  Most important as a helper for git-checkout,
	this is also used by git-merge and git-reset.
git-fmt-merge-msg.perl
	Generate a reasonable default commit message for a merge.
	Used by git-pull and git-octopus.
git-hash-object
	Very primitive helper to turn an arbitrary file into an object,
	returning just the ID or actually adding it to the database.
	Used by the cvs-to-git and svn-to-git import filters.
git-ls-tree
	List the contents of a tree object.  Will tell you all the files
	in a commit.  Used by the checkout scripts git-checkout and git-reset.
git-repo-config
	Get and set options in .git/config.  The .git/config format
	is designed to be human-readable.  This gives programmatic
	access to the settings.  This currently has a lot of overlap
	with the function of git-var.
git-unpack-file
	Write the contents of the given block to a temporary file,
	and return the name of that temp file.  Used most often
	by merging scripts.
git-update-ref
	Rewrite a reference (in .git/refs/) to point to a new object.
	"echo $sha1 > $file" is mostly equivalent, but this adds locking
	so two people don't update the same reference at once.
git-sh-setup.sh
	This is a general prefix script that sets up
	$GIT_DIR and $GIT_OBJECT_DIRECTORY for a script,
	or errors out if the git control files can't be found.
git-stripspace
	Remove unnecessary whitespace.  Used mostly on commit messages
	received by e-mail.
git-symbolic-ref
	This queries or creates symlinks to references such as HEAD.
	Basically equivalent to readlink(1) or ln -s, this also works
	on platforms that don't have symlinks.  See the man page.
git-var
	Provide access to the GIT_AUTHOR_IDENT and/or GIT_COMMITTER_IDENT
	values, used in various commit scripts.  This currently has a
	lot of overlap with the function of git-repo-config.
git-write-tree
	Generate a tree object reflecting the current index.  The output
	is the tree object; if you don't remember it somewhere (usually,
	pass it to git-commit-tree), it'll be lost.

	This requires that the index be fully merged.  If any incomplete
	merges are present in the index (files in stages 1, 2 or 3),
	git-write-tree will fail.

+ Oddballs
git-mv.perl
	I have to admit, I'm not quite sure what great advantages this is
	supposed to have over plain "mv" followed by "git-update-index",
	or why it's complex enough to need perl.

	Basically, this renames a file, deleting its old name and adding
	its new name to the index.  Git doesn't have the concept of a
	permanent file ID tracked across renames, so there's no need to
	use a special tool, but it is a two-step process to rename a file:
	- Rename the file
	- git-add the new name
	Followed by which you must commit both the old and new names.

	I suppose if you have a mixture of version-controlled and
	non-version-controlled files with similar names, the fact that
	git-mv knows not to touch the latter could be useful.

+ Code browsing
git-diff.sh
	Show changes between various trees.  Takes up to two tree
	specifications, and shows the difference between the versions.
	Zero arguments: index vs. working directory (git-diff-files)
	One: tree vs. working directory (git-diff-index)
	One, --cached: tree vs. index (git-diff-index)
	Two: tree vs. tree (git-diff-tree)

	This wrapper always produces human-readable patch output.
	The helpers all produce "diff-raw" format unless you supply
	the -p option.

	There are some interesting options.  Unfortunately, the git-diff
	man page is annoyingly sparse, and refers to the helper scripts'
	documentation rather than describing the many useful options
	they all have in common.  Please do read the man pages of the
	helpers to see what's available.
	
	In particular, although git does not explicitly record file
	renames, it has some pretty good heuristics to notice things.
	-M tries to detect renamed files by matching up deleted files
	with similar newly created files.  -C tries to detect copies
	as well.  By default, -C only looks among the modified files for
	the copy source.  For common cases like splitting a file in two,
	this works well.  The --find-copies-harder searches ALL files
	in the tree for the copy source.  This can be slow on large trees!

	See Documentation/diffcore.txt for an explanation of how all
	this works.
  git-diff-files
	Compare the index and the working directory.
  git-diff-index
	Compare the working directory and a given tree.  This is the
	git equivalent of the single-operand form of "cvs diff".
	If "--cached" is specified, uses the index rather than the working
	directory.
  git-diff-tree
	Compare two trees.  This is the git equivalent of the two-operand
	form of "cvs diff".  This command is sometimes useful by itself
	to see the changes made by a single commit.  If you give it
	only one commit on the command line, it shows the diff between
	that commit and its first parent.  If the commit specification
	is long and awkward to type, using "git-diff-tree -p <commit>"
	can be easier than "git-diff <commit>^ <commit>".
  git-diff-stages
	Although not called by git-diff, there is a fourth diff helper
	routine, used to compare the various versions of an unmerged
	file in the index.  It is intended for use by merging porcelain.
git-grep.sh
	A very simple wrapper that runs git-ls-files and greps the
	output looking for a file name.  Does nothing fancy except
	saves typing.
git-log.sh
	Wrapper around git-rev-list --pretty.  Shows a history
	of changes made to the repository.  Takes all of git-rev-list's
	options for specifying which revisions to list.
git-name-rev
	Find a symbolic name for the commit specified on the
	command line, and returns a symbolic name of the form
	"maint~404^2~7".  Basically, this does a breadth-first search
	from all the heads in .git/refs looking for the given commit.
git-shortlog.perl
	This is a filter for the output of "git-log --pretty=short"
	to generate a one-line-per-change "shortlog" as Linus likes.
git-show-branch
	Visually show the merge history of the references given as
	arguments.  Prints one column per reference and one line per
	commit showing whether that commit is an ancestor of each
	reference.
git-whatchanged.sh
	A simple wrapper around git-rev-list and git-diff-tree,
	this shows the change history of a repository.  Specify a
	directory or file on the command line to limit the
	output to changes affecting those files.  This isn't
	the same as "cvs annotate", but it serves a similar purpose
	among git folks.

	You can add the -p option to include patches as well as log
	comments.  You can also add the -M or -C option to follow
	history back through file renames.

	-S is interesting: it's the "pickaxe" option.  Given a string,
	this limits the output to changes that make that string appear
	or disappear.  This is for "digging through history" to see when
	a piece of code was introduced.  The string may (and often does)
	contain embedded newlines.  See Documentation/cvs-migration.txt.

+ Making local changes
	All of these are examples of "porcelain" scripts.  Reading the
	scripts themselves can be informative; they're generally not
	too confusing.
git-add.sh
	A simple wrapper around "git-ls-files | git-update-index --add"
	to add new files to the index.   You may specify directories.
	You need to invoke this for every new file you want git to
	track.
git-bisect.sh
	Utility to do a binary search to find the change that broke something.
	The heart of this is in "git-rev-list --bisect"
	A very handy little utility!  Kernel developers love it
	when you tell them exactly which patch broke something.
	NOTE: this uses the head named "bisect", and will blow
	away any existing branch by that name.  Try not to
	create a branch with that name.

	There are three steps:
	git-bisect start [<files>]
		- Reset to start bisecting.  If any files are specified,
		  only they will be checked out as bisection proceeds.
	git-bisect good [<revision>]
		- Record the revision as "good".  The change being sought
		  must be after this revision.
	git-bisect bad [<revision>]
		- Record the revision as "bad".  The change being sought
		  must be before or equal to this revision.
	As soon as you have specified one good version and one bad version,
	git-bisect will find a halfway point and check out that
	revision.  Build and test it, then report it as good or bad,
	and git-bisect will narrow the search.  Finally, git-bisect
	will tell you exactly which change caused the problem.
	git-bisect log
		- Show a history of revisions.
	git-bisect replay
		- Replay (part of) a git-bisect log.  Generally used
		  to recover from a mistake, you can truncate the log
		  before the mistake and replay it to continue.
	If git-bisect chooses a version that cannot build, or you
	are otherwise unable to determine whether it is good or bad,
	you can change revisions with "git-reset --hard <revision>"
	to another checkout between the current good and bad limits, and
	continue from there.  "git-reset --hard <revision>" is generally
	dangerous, but you are on a scratch branch.

	This can, of course, be used to look for any change, even
	one for the better, if you can avoid being confused by the
	terms "good" and "bad".
git-branch.sh
	Most commonly used bare, to show the available branches.
	Show, create, or delete a branch.  The current branches
	are simply the contents of .git/refs/heads/.
	Note that this does NOT switch to the created branch!
	For the common case of creating a branch and immediately
	switching to it, "git-checkout -b <branch>" is simpler.
git-checkout.sh
	This does two superficially similar but very different things
	depending on whether any files or paths are specified on the
	command line.

	git-checkout [-f] [-b <new-branch>] <branch>
		This switches (changes the HEAD symlink to) the specified
		branch, updating the index and working directory to
		reflect the change.  This preserves changes in the
		working directory unless -f is specified.
		If -b is specified, a new branch is started from the
		specified point and switched to.  If <branch> is omitted,
		it defaults to HEAD.  This is the usual way to start a
		new branch.

	git-checkout [<branch>] [--] <paths>...
		This replaces the files specified by the given paths with
		the versions from the index or the specified branch.
		It does NOT affect the HEAD symlink, just replaces the
		specified paths.  This form is like a selective form of
		"git-reset".  Normally, this can guess whether the first
		argument is a branch name or a path, but you can use
		"--" to force the latter interpretation.

	With no branch, this is used to revert a botched edit of a
	particular file.

	Both forms use git-read-tree internally, but the net effect is
	quite different.
git-commit.sh
	Commit changes to the revision history.  In terms of primitives,
	this does three things:
	1) Updates the index file with the working directory files
	   specified on the command line, or -a for all (using
	   git-diff-files --name-only | git-update_index),
	2) Prompts for or generates a commit message, and then
	3) Creates a commit object with the current index contents.

	The prompt for a commit message includes the output of git-status,
	so you can see what changes are being committed.

	This also executes the pre-commit, commit-msg, and
	post-commit hooks if present.

	Files deleted from the working tree will be removed from the
	index, but newly added files will not be automatically added,
	even if explicitly specified on the command line; you must use
	git-add for that.

	Note that the default action, with no command line arguments,
	is to commit only what's already in the index.  The equivalent
	of "cvs commit" is "git-commit -a".
git-reset.sh
	Explained in detail in "resetting", above.  This modifies the
	current branch head reference (as pointed to by .git/HEAD)
	to refer to the given commit.  It does not modify .git/HEAD 
	Reset the current HEAD to the specified commit, so that future
	checkins will be relative to it.  There are three
	variations:
	--soft: Just move the HEAD link.  The index is unchanged.
	--mixed (default): Move the HEAD link and update the index file.
		Any local changes will appear not checked in.
	--hard: Move the HEAD links, update the index file, and
		check out the index, overwriting the working
		directory.  Like "cvs update -C".
	In case of accidents, this copies the previous head
	object ID to ORIG_HEAD (which is NOT a symlink).
git-status.sh
	Show all the files in the working directory and index that have
	been changed since the current HEAD.  The basic categories are:
	1) Changed in the index, will be included in the next commit.
	2) Changed in the working directory but NOT in the index; will
	   be committed only if mentioned on the git-commit command line
	   (or added manually via git-update-index)
	3) Not tracked by git, but not explicitly ignored, either.


+ Cherry-picking
	Cherry-picking is the process of taking part of the changes
	introduced on one tree and applying those changes to another.
	This doesn't produce a parent/descendant relationship in the
	commit history.

	To produce that relationship, there's a special type of merge you
	can do if you've taken everything you want off a branch and
	want to show it in the merge history without actually importing
	any changes from it: ours.  "git-merge -s ours" will generate a
	commit that shows some branches were merged in, but not
	actually alter the current HEAD source code in any way.

	One thing cherry-picking is sometimes used for is taking a
	development branch and re-organizing the changes into a patch
	series for submission to the Linux kernel.
git-cherry.sh
	This searches a branch for patches which have not been applied
	to another.  Basically, it finds the unpicked cherries.
	It searches back to the common ancestor of the named branch and
	the current head using git-patch-id to identify similarity
	in patches.
  git-patch-id
	Generate a hash of a patch, ignoring whitespace and line numbers
	so that "the same" patch, even relative to a different code base,
	probably has the same hash, and different patches almost certainly
	have different ones.  git-cherry looks for patch hashes which
	are present on the branch (source branch) that are not present
	on the trunk (destination branch).
git-cherry-pick.sh
	Given a commit (on a different branch), compute a diff between
	it and its immediate parent, and apply it to the current HEAD.
	This is actually the same script as "git revert", but works
	forward.  git-cherry finds the patches, this merges them.
	Handles failures gracefully.
git-rebase.sh
	Move a branch to a more recent "base" release.	This just extracts
	all the patches applied on the local head since the last merge
	with upstream (using git-format-patch) and re-applies them
	relative to the current upstream with git-am (explained under
	"accepting changes by e-mail").  Finally, it deletes the old
	branch and gives its name to the new one, so your branch now
	contains all the same changes, but relative to a different base.
	Basically the same as cherry-picking an entire branch.
	(This uses git-cherry to find the patches, so is able to cope
	with patches that were applied to the base.)
git-revert.sh
	Undo a commit.	Basically "patch -R" followed by a commit.
	This is actually the same script as "git-cherry-pick", just
	applies the patch in reverse, undoing a change that you don't
	wish to back up to using git-reset.  Handles failures gracefully
	by telling the user what to do.
	This reversion will create a commit in the history; it is
	not like git-reset which erases history.

+ Accepting changes by e-mail
git-apply
	Apply a (git-style extended) patch to the current index
	and working directory.
git-am.sh
	The new and improved "apply an mbox" script.  Takes an
	mbox-style concatenation of e-mails as input and batch-applies
	them, generating one commit per message.  Can resume after
	stopping on a patch problem.
	(Invoke it as "git-am --skip" or "git-am --resolved" to
	deal with the problematic patch and continue.)
  git-mailinfo
	Given a single mail message on stdin (in the Linux standard
	SubmittingPatches format), extract a commit message and
	the patch proper.
  git-mailsplit
	Split an mbox into separate files.
  git-applypatch.sh
	Tries simple git-apply, then tries a few other clever merge
	strategies to get a patch to apply.  Used in the main loop
	of git-am and git-applymbox.
git-applymbox.sh
	This is Linus's original apply-mbox script.  Mostly superseded by
	git-am (which is friendlier and has more features), but he still
	uses it, so it's maintained.  This is so old it was originally
	a test of the git core called "dotest", and that name is still
	lurking in the temp file names.

+ Publishing changes by e-mail
git-format-patch.sh
	Generate a series of patches, in the preferred Linux kernel
	(Documentation/SubmittingPatches) format, for posting to lkml
	or the like.  This formats every commit on a branch as a separate
	patch.
git-send-email.perl
	Actually e-mail the output of git-format-patch.
	(This uses direct SMTP, a matter of some controversy.  Others feel
	that /bin/mail is the correct local mail-sending interface.)

+ Merging
git-merge.sh
	Merge one or more "remote" heads into the current head.
	Some changes, when there has been change only on one branch or
	the same change has been made to all branches, can be resolved
	by the "trivial in-index" merge done by git-read-tree.	For more
	complex cases, git provides a number of different merge strategies
	(with reasonable defaults).

	Note that merges are done on a filename basis.	While git tries
	to detect renames when generating diffs, most merge strategies
	don't track them by renaming.  (The "recursive" strategy, which
	recently became the default, is a notable exception.)
  git-merge-base
	Finds a common ancestor to use when comparing the changes made
	on two branches.  The simple case is straightforward, but if
	there have been cross-merges between the branches, it gets
	somewhat hairy.  The algorithm is not 100% final yet.
	(There's also --all, which lists all candidates.)
  git-merge-index
	This is the outer merging loop.  It takes the name of a one-file
	merge executable as an argument, and runs it for every incomplete
	merge.
    git-merge-one-file.sh
	This is the standard git-merge-index helper, that tries to
	resolve a 3-way merge.  A helper used by all the merge strategies.
	(Except "recursive" which has its own equivalent.)
  git-merge-octopus.sh
	Many-way merge.  Overlaps should be negligible.
  git-merge-ours.sh
	A "dummy" merge strategy helper.  Claims that we did the merge, but
	actually takes the current tree unmodified.  This is used to
	cleanly terminate side branches that heve been cherry-picked in.
  git-merge-recursive.py
	A somewhat fancier 3-way merge.   This handles multiple cross-merges
	better by using multiple common ancestors.
  git-merge-resolve.sh
  git-merge-stupid.sh
	Not actually used by git-merge, this is a simple example
	merge strategy.
git-read-tree
	Read the given tree into the index.  This is the difference
	between the "--soft" and "--mixed" modes of git-reset, but the
	important thing this command does is simple merging.
	If -m is specified, this can take up to three trees as arguments.
git-resolve.sh
	OBSOLETE.  Perform a merge using the "resolve" strategy.
	Has been superseded by the "-s resolve" option to git-merge
	and git-pull.
git-octopus.sh
	OBSOLETE.   Perform a merge using the "octopus" strategy.
	Has been superseded by the "-s octopus" option to git-merge
	and git-pull.

+ Making releases
git-get-tar-commit-id
	Reads out the commit ID that git-tar-tree puts in its output.
	(Or fails if this isn't a git-generated tar file.)
git-tag.sh
	Create a tag in the refs/tags directory.  There are two kinds:
	"lightweight tags" are just references to commits.  More
	serious tags are GPG-signed tag objects, and people receiving
	the git tree can verify that it is the version that you released.
  git-mktag
	Creates a tag object.  Verifies syntactic correctness of its
	input.  (If you want to cheat, use git-hash-object.)
git-tar-tree
	Generate a tar archive of the named tree.  Because git does NOT
	track file timestamps, this uses the timestamp of the commit,
	or the current time if you specify a tree.
	Also stores the commit ID in an extended tar header.
git-verify-tag.sh
	Given a tag object, GPG-verify the embedded signature.

+ Accepting changes by network
	Pulling consists of two steps: retrieving the remote commit
	objects and everything they point to (including ancestors),
	then merging that into the desired tree.  There are still
	separate fetch and merge commands, but it's more commonly done
	with a single "git-pull" command.  git-fetch leaves the commit
	objects, one per line, in .git/FETCH_HEAD.  git-merge will
	merge those in if that file exists when it is run.

	References to remote repositories can be made with long URLs,
	or with files in the .git/remotes/ directory.  The latter
	also specifies the local branches to merge the fetched data into,
	making it very easy to track a remote repository.
git-clone.sh
	Create a new local clone of a remote repository.
	(Can do a couple of space-sharing hacks when "remote" is on
	a local machine.)

	You only do this once.
  git-clone-pack
	Runs git-upload-pack remotely and places the resultant pack
	into the local repository.  Supports a variety of network
	protocols, but "remote" can also be a different directory on
	the current machine.
git-fetch.sh
	Fetch the named refs and all linked objects from a remote repository.
	The resultant refs (tags and commits) are stored in .git/FETCH_HEAD,
	which is used by a later git-resolve or git octopus.

	This is the first half of a "git pull" operation.
  git-fetch-pack
	Retrieve missing objects from a remote repository.
  git-local-fetch
	Duplicates a git repository from the local system.
	(Er... is this used anywhere???)
  git-http-fetch
	Do a fetch via http.  Http requires some kludgery on the
	server (see git-update-server-info), but it works.
  git-ssh-fetch
	Do a fetch via ssh.
git-ls-remote.sh
	Show the contents of the refs/heads/ and/or refs/tags/ directories
	of a remote repository.  Useful to see what's available.
  git-peek-remote
	Helper C program for the git-ls-remote script.  Implements the
	git protocol form of it.
git-parse-remote.sh
	Helper script to parse a .git/remotes/ file.  Used by a number
	of these programs.
git-pull.sh
	Fetches specific commits from the given remote repository,
	and merges everything into the current branch.	If a remote
	commit is named as src:dst, this merges the remote head "src"
	into the branch "dst" as well as the trunk.  Typically, the "dst"
	branch is not modified locally, but is kept as a pristine copy
	of the remote branch.

	One very standard example of this contention is that
	a repository that is tracking another specifies "master:origin"
	to provide a pristine local copy of the remote "master"
	branch in the local branch named "origin".
  git-ssh-pull
	A helper program that pulls over ssh.
git-shell
	A shell that can be used for git-only users.  Allows git
	push (git-receive-pack) and pull (git-upload-pack) only.
  git-receive-pack
	Receive a pack from git-send-pack, validate it, and add it to
	the repository.  Adding just the bare objects has no security
	implications, but this can also update branches and tags, which
	does have an effect.
	Runs pre-update and post-update hooks; the former may do
	permissions checking and disallow the upload.
	This is the command run remotely via ssh by git-push.

+ Publishing changes by network
git-daemon
	A daemon that serves up the git native protocol so anonymous
	clients can fetch data.  For it to allow export of a directory,
	the magic file name "git-daemon-export-ok" must exist in it.

	This does not accept (receive) data under any circumstances.
git-push.sh
	Git-pull, only backwards.  Send local changes to a remote
	repository.  The same .git/remotes/ short-cuts can be used,
	and the same src:dst syntax.  (But this time, the src is local
	and the dst is remote.)
  git-http-push
	A helper to git-push to implement the http: protocol.
  git-ssh-push
	A helper to git-push to push over ssh.
  git-ssh-upload
	Another helper.  This just does the equivalent of "fetch"
	("throw"?) and doesn't actually merge the result.  Obsolete?
git-request-pull.sh
	Generate an e-mail summarizing the changes between two commits,
	and request that the recipient pull them from your repository.
	Just a little helper to generate a consistent and informative
	format.
git-send-pack
	Pack together a pile of objects missing at the destination and
	send them.  This is the sending half that talks to a remote
	git-receive-pack.
git-update-server-info
	To run git over http, auxiliary info files are required that
	describes what objects are in the repository (since git-upload-pack
	can't generate this on the fly).  If you want to publish a
	repository via http, run this after every commit.  (Typically
	via the hooks/post-update script.)
git-upload-pack
	Like git-send-pack, but this is invoked by a remote git-fetch-pack.

^ permalink raw reply	[relevance 1%]

* Re: How to clone-pack the HEAD?
  @ 2005-12-15  5:29  8%         ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2005-12-15  5:29 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git

Junio C Hamano <junkio@cox.net> writes:

> Not really.  I take this back.  What you want to do I did not
> understand well enough.
>
> HEAD is kinda special.  A hack I can think of is to do ls-remote
> first and do the guess clone-pack does for full clone case, and
> then give a specific branch name to clone.  That might work.

... and another way would be to do this; I'll put this (with
fixes if there is some needed) in "master" tonight.

Also I might want to give --keep option to fetch-pack as well;
clone-pack has some static functions that we can extract out to
a common file to link to both.

-- >8 --
Subject: [PATCH] clone-pack: make it usable for partial branch cloning.

clone-pack had some logic to accept subset of remote refs from
the command line and clone from there.  However, it was never
used in practice and its problems were not found out so far.

This commit changes the command to output the object names of
refs to the standard output instead of making a clone of the
remote repository when explicit <head> parameters are given; the
output format is the same as fetch-pack.

The traditional behaviour of cloning the whole repository by
giving no explicit <head> parameters stays the same.

Signed-off-by: Junio C Hamano <junkio@cox.net>

---

 Documentation/git-clone-pack.txt |    6 +++++-
 clone-pack.c                     |   13 +++++++++++--
 2 files changed, 16 insertions(+), 3 deletions(-)

31ec6abf887ec95642cbe82fe61076e975494ab0
diff --git a/Documentation/git-clone-pack.txt b/Documentation/git-clone-pack.txt
index cfc7b62..39906fc 100644
--- a/Documentation/git-clone-pack.txt
+++ b/Documentation/git-clone-pack.txt
@@ -43,7 +43,11 @@ OPTIONS
 	The heads to update.  This is relative to $GIT_DIR
 	(e.g. "HEAD", "refs/heads/master").  When unspecified,
 	all heads are updated to match the remote repository.
-
++
+Usually all the refs from existing repository are stored
+under the same name in the new repository.  Giving explicit
+<head> arguments instead writes the object names and refs to
+the standard output, just like get-fetch-pack does.
 
 Author
 ------
diff --git a/clone-pack.c b/clone-pack.c
index a99a95c..b5ce5d3 100644
--- a/clone-pack.c
+++ b/clone-pack.c
@@ -259,8 +259,17 @@ static int clone_pack(int fd[2], int nr_
 
 	status = clone_without_unpack(fd);
 
-	if (!status)
-		write_refs(refs);
+	if (!status) {
+		if (nr_match == 0)
+			write_refs(refs);
+		else
+			while (refs) {
+				printf("%s %s\n",
+				       sha1_to_hex(refs->old_sha1),
+				       refs->name);
+				refs = refs->next;
+			}
+	}
 	return status;
 }
 
-- 
0.99.9n

^ permalink raw reply related	[relevance 8%]

* [RFC] shallow clone
@ 2006-01-30  7:18  4% Junio C Hamano
       [not found]     ` <43DF1F1D.1060704@innova-card.com>
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2006-01-30  7:18 UTC (permalink / raw)
  To: git

Shallow History Cloning
=======================

One good thing about git repository is that each clone is a
freestanding and complete entity, and you can keep developing in
it offline, without talking to the outside world, knowing that
you can sync with them later when online.

It is also a bad thing.  It gives people working on projects
with long development history stored in CVS a heart attack when
we tell them that their clones need to store the whole history.

There was a suggestion by Linus to allow a partial clone using a
syntax like this:

	$ git clone --since=v2.6.14 git://.../linux-2.6/ master

Here is an outline of what changes are needed to the current
core to do this.


Strategy
--------

We have `info/grafts` mechanism to fake parent information for
commit objects.  Using this facility, we could roughly do:

. Download the full tree for v2.6.14 commit and store its
  objects locally.

. Set up `info/grafts` to lie to the local git that Linux kernel
  history began at v2.6.14 version.

. Run `git fetch git://.../linux-2.6 master`, with a local ref
  pointing at v2.6.14 commit, to pretend that we have everything
  up to v2.6.14 to `upload-pack` running on the other end.

. Update the `origin` branch with the master commit object name
  we just fetched from Linus.

There are some issues.

. In the fetch above to obtain everything after v2.6.14, and
  future runs of `git fetch origin`, if a blob that is in the
  commit being fetched happens to match what used to be in a
  commit that is older than v2.6.14 (e.g. a patch was reverted),
  `upload-pack` running on the other end is free to omit sending
  it, because we are telling it that we are up to date with
  respect to v2.6.14.  Although I think the current `rev-list
  --objects` implementation does not always do such a revert
  optimization if the revert is to a blob in a revision that is
  sufficiently old, it is free to optimize more aggressively in
  the future.

. Later when the user decides to fetch older history, the
  operation can become a bit cumbersome.

I think the latter one is cumbersome but is doable -- we could
do the equivalent of:

	$ git clone --since=v2.6.13 origin v2.6.14

place all the objects obtained by such a clone/fetch operation
and remember that now we have history beginning at v2.6.13.  So
let's worry about that later.

For the first issue, we need to have the other end cooperate
while fetching from it.  If the other end also thinks the
development started at v2.6.14, even if we tell that we have the
history up to v2.6.14 (or a commit we obtained since then),
there is no way for `upload-pack` running there to optimize too
agressively and assume we have a blob that appeared in v2.6.13.
More simply, we do not have to tell them we have anything -- if
the other end thinks the epoch is at v2.6.14, only commits that
comes later will be sent to us.


Design
------

First, to bootstrap the process, we would need to add a way to
obtain all objects associated with a commit.  We could do a new
program, or we could implement this as a protocol extension to
`upload-pack`.  My current inclination is the latter.

When talking with `upload-pack` that supports this extension,
the downloader can give one commit object name and get a pack
that contains all the objects in the tree associated with that
commit, plus the commit object itself.  This is a rough
equivalent of running the commit walker with the `-t` flag.

Another functionality we would need is to tell `upload-pack` to
use `info/grafts` of downloader's choice.  With this, after
fetching the objects for v2.6.14 commit, the downloader can set
up its own grafts file to cauterize the development history at
v2.6.14, and tell the `upload-pack` to pretend the kernel
history starts at that commit, while sending the tip of Linus'
development track to us.

Using the extended protocol (let's call it 'shallow' extension),
a clone to create a repository that has only recent kernel
history since v2.6.14 goes like this:

The first client is to fetch the v2.6.14 itself.

[NOTE]
Most likely this is not directly run by the user but is run as
the first command invoked by the shallow clone script.

1. The `fetch-pack` command acquires a new option, `--single`:

	$ git-fetch-pack --single git://.../linux-2.6/ v2.6.14

   This talks with `upload-pack` on the kernel.org server via
   `git-daemon`.

2. `upload-pack` tells the fetcher what commits it has,
   what their refs are, and what protocol extensions it
   supports, as usual.

3. If it does not see `shallow` extension supported, there is no
   way to get a single tree, so things fail here.  Otherwise, it
   sends `single X{40}\0` request, instead of the usual `want`
   line.  The object name sent here is the desired commit.

4. `upload-pack` notices this is a single commit request, and
   sends an ACK if it can satisfy the request (or a NAK if it
   can't, e.g. it does not have the asked commit).  Instead of
   doing the usual `get_common_commits` followed by
   `create_pack_file`, it does:

	$ git rev-list -n1 --objects $commit | git pack-object

   and sends the result out.

5. The fetcher checks the ACK and receives the objects.

After the above exchange, we have downloaded v2.6.14 commit and
its objects but not its history.  `git-fetch-pack` would output
the tag object name for `v2.6.14` and we would stash it away in
`$GIT_DIR/FETCH_HEAD` as usual.  Then we set up `info/grafts`
with this:

	$ git rev-parse FETCH_HEAD^{commit} >"$GIT_DIR/info/grafts"

This cauterizes the history on our end.

The second phase of the shallow clone is to fetch the history
since v2.6.14 to the tip.

1. The `fetch-pack` command is run as usual.  Most likely the
   command line run by the shallow clone script would be:

	$ git fetch-pack git://.../linux-2.6/ master

   Notice there is nothing magical about it.  It is just the
   business as usual.

2. `upload-pack` does its usual greeting to the downloader.

3. We notice `shallow` extension again, and first send out
   `graft X{40}\0` request.  The syntax of graft request would
   be `graft ` followed by one or more commit object names on a
   line separated with SP.  After sending out all the needed
   graft requests (in this example there is only one, to
   cauterize the history at v2.6.14), it does the usual `want
   X{40}\0multi_ack` and a flush.

4. `upload-pack` notices graft requests, reinitializes its graft
   information with what it receives from the other end, and
   then records `want`.

5. After the above steps, the usual `upload-pack` vs
   `fetch-pack` exchange continues and objects needed to
   complete the Linus' tip of development trail for somebody who
   has v2.6.14 are sent in a pack.  The difference from the
   usual operation is that `upload-pack` during this run thinks
   v2.6.14 commit does not have any parent.

The exact sequence from the second part of the initial "shallow
clone" can be used for further updates.

There is a small issue about the actual implementation.  In the
above description I pretended that `upload-pack` can be told to
use phony grafts information, but in the current implementation
the program that needs to use phony grafts information is
`rev-list` spawned from it.  We _could_ point GIT_GRAFT_FILE
environment variable point at a temporary file while we do so,
but I'd like to avoid using a temporary file if possible, given
that `upload-pack` is run from `git-daemon`.  Maybe we could
give --read-graft-from-stdin flag to `rev-list` for this
purpose.


Anybody want to try?

^ permalink raw reply	[relevance 4%]

* Re: [RFC] shallow clone
       [not found]     ` <43DF1F1D.1060704@innova-card.com>
@ 2006-01-31  9:00  1%   ` Franck
  0 siblings, 0 replies; 200+ results
From: Franck @ 2006-01-31  9:00 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List

2006/1/31, Franck Bui-Huu <fbh.work@gmail.com>:
> Junio C Hamano wrote:
> > Shallow History Cloning
> > =======================
> >
> > One good thing about git repository is that each clone is a
> > freestanding and complete entity, and you can keep developing in
> > it offline, without talking to the outside world, knowing that
> > you can sync with them later when online.
> >

could we be able to make a public repository from such repo ?

> > It is also a bad thing.  It gives people working on projects
> > with long development history stored in CVS a heart attack when
> > we tell them that their clones need to store the whole history.
> >

yeah and I haven't survive :)
I didn't notice that other people were asking for this feature, that's great !

> > There was a suggestion by Linus to allow a partial clone using a
> > syntax like this:

[snip]

> >
> > There are some issues.
> >
> > . In the fetch above to obtain everything after v2.6.14, and
> >   future runs of `git fetch origin`, if a blob that is in the
> >   commit being fetched happens to match what used to be in a
> >   commit that is older than v2.6.14 (e.g. a patch was reverted),
> >   `upload-pack` running on the other end is free to omit sending
> >   it, because we are telling it that we are up to date with
> >   respect to v2.6.14.  Although I think the current `rev-list
> >   --objects` implementation does not always do such a revert
> >   optimization if the revert is to a blob in a revision that is
> >   sufficiently old, it is free to optimize more aggressively in
> >   the future.
> >

oops, I wasn't aware of that. I still can resolve this issue by hand, no ?

> > . Later when the user decides to fetch older history, the
> >   operation can become a bit cumbersome.
> >

[snip]

> >
> > Design
> > ------
> >
> > First, to bootstrap the process, we would need to add a way to
> > obtain all objects associated with a commit.  We could do a new
> > program, or we could implement this as a protocol extension to
> > `upload-pack`.  My current inclination is the latter.

is the document in "Documentation/technical/pack-protocol.txt"
uptodate ? I can't find anything on multi_ack for example.

> >
> > When talking with `upload-pack` that supports this extension,
> > the downloader can give one commit object name and get a pack
> > that contains all the objects in the tree associated with that
> > commit, plus the commit object itself.  This is a rough
> > equivalent of running the commit walker with the `-t` flag.

[snip]

> >
> >
> > Anybody want to try?
> >

well, you made almost the job with your analysis, but I've never took
a look to git deep internals and with my lack of time, it would take
too much time...

Thanks
--
               Franck

^ permalink raw reply	[relevance 1%]

* Re: Make "git clone" less of a deathly quiet experience
  @ 2006-02-11  7:35  4%   ` Craig Schlenter
  2006-02-11  8:44  1%     ` Radoslaw Szkodzinski
  0 siblings, 1 reply; 200+ results
From: Craig Schlenter @ 2006-02-11  7:35 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List

On 11 Feb 2006, at 7:48 AM, Junio C Hamano wrote:
[snip]
> The real improvement, independent of this client-side patch,
> would be to reuse recently generated packs, but that needs
> writable cache directory on the server side.

Speaking of improvements, I've noticed that my attempts to track
the 2.6 kernel via the git protocol result in inefficiencies from time
to time when the connection hangs or is terminated when my
flakey wireless link goes down. When I restart the pull, the data
that has already been downloaded is lost and things start from
scratch which is painful if it's a big update.

It would be nice if the "partial pack" or whatever that has been
downloaded at the time of the breakage could be re-used and
things could start "from that point onwards" or the bits that were
already received could be unpacked. Comments?

Thank you,

--Craig

^ permalink raw reply	[relevance 4%]

* Re: Make "git clone" less of a deathly quiet experience
  2006-02-11  7:35  4%   ` Craig Schlenter
@ 2006-02-11  8:44  1%     ` Radoslaw Szkodzinski
  2006-02-11 13:05  2%       ` Petr Baudis
  0 siblings, 1 reply; 200+ results
From: Radoslaw Szkodzinski @ 2006-02-11  8:44 UTC (permalink / raw)
  To: Craig Schlenter; +Cc: Junio C Hamano, Git Mailing List

[-- Attachment #1: Type: text/plain, Size: 573 bytes --]

Craig Schlenter wrote:
> On 11 Feb 2006, at 7:48 AM, Junio C Hamano wrote:
> It would be nice if the "partial pack" or whatever that has been
> downloaded at the time of the breakage could be re-used and
> things could start "from that point onwards" or the bits that were
> already received could be unpacked. Comments?

It even already works on plain http repos with git fetch.
(e.g. WineHQ repository)
Why git protocol doesn't support it?

+10

-- 
GPG Key id:  0xD1F10BA2
Fingerprint: 96E2 304A B9C4 949A 10A0  9105 9543 0453 D1F1 0BA2

AstralStorm


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 252 bytes --]

^ permalink raw reply	[relevance 1%]

* Re: Make "git clone" less of a deathly quiet experience
  2006-02-11  8:44  1%     ` Radoslaw Szkodzinski
@ 2006-02-11 13:05  2%       ` Petr Baudis
  0 siblings, 0 replies; 200+ results
From: Petr Baudis @ 2006-02-11 13:05 UTC (permalink / raw)
  To: Radoslaw Szkodzinski; +Cc: Craig Schlenter, Junio C Hamano, Git Mailing List

Dear diary, on Sat, Feb 11, 2006 at 09:44:00AM CET, I got a letter
where Radoslaw Szkodzinski <astralstorm@gorzow.mm.pl> said that...
> Craig Schlenter wrote:
> > On 11 Feb 2006, at 7:48 AM, Junio C Hamano wrote:
> > It would be nice if the "partial pack" or whatever that has been
> > downloaded at the time of the breakage could be re-used and
> > things could start "from that point onwards" or the bits that were
> > already received could be unpacked. Comments?
> 
> It even already works on plain http repos with git fetch.
> (e.g. WineHQ repository)
> Why git protocol doesn't support it?

Because it works totally different. When downloading from plain HTTP
repos, you are just downloading files from the remote repository and it
is easy to pick up wherever you left (and last night, I just added a
possibility to Cogito to resume an interrupted cg-clone by just cd'ing
inside and running cg-fetch, as is; it's pretty neat) - you just resume
downloading of the file you downloaded last, and don't download again
the files you already have.

But the native git protocol works completely differently - you tell the
server "give me all objects you have between object X and head", the
object will generate a completely custom pack just for you and send it
over the network. The next time you fetch, you just ask for a pack
between object X and head again, but the head can be already totally
different. What we would have to do is to check for interrupted
packfiles before fetching, attempt to fix them (cutting out the
incomplete objects and broken delta chains, if applicable), and then
tell the remote side to skip those objects; but that may not be easy
because there can be a lot of "loose fibres". Another way would be to
just tell the server "if head is still Y, start sending the pack only
after N bytes". *shudder*

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Of the 3 great composers Mozart tells us what it's like to be human,
Beethoven tells us what it's like to be Beethoven and Bach tells us
what it's like to be the universe.  -- Douglas Adams

^ permalink raw reply	[relevance 2%]

* Re: several quick questions
  @ 2006-02-15  8:21  3%               ` Carl Worth
  0 siblings, 0 replies; 200+ results
From: Carl Worth @ 2006-02-15  8:21 UTC (permalink / raw)
  To: Keith Packard
  Cc: Martin Langhoff, Linus Torvalds, Nicolas Vilz 'niv', git


[-- Attachment #1.1: Type: text/plain, Size: 2040 bytes --]

On Tue, 14 Feb 2006 21:25:45 -0800, Keith Packard wrote:
> On Wed, 2006-02-15 at 17:11 +1300, Martin Langhoff wrote:
> 
> > Did that lead to finding any problems with the import? Can I get my
> > hands on that script you've written to run the comparison?
> 
> The only issues we had were with manual changes to the repository;

For anyone interested, here are the problems our script found after
importing cairo with git-cvsimport:

1) Some "future" files existed at old tags since we had copied ,v
   files to preserve per-file history. This one was no surprise.

2) We had a couple tags in CVS that didn't tag the current head,
   (instead a file had been manually reverted before the tag). In the
   git checkout of the same tag name, we got the results as if HEAD
   had been tagged.

Those two weren't too surprising. We remembered quite clearly what had
happened as soon as we saw the results. I've fixed these up
post-import by making git commits to fix the problems and then moving
the tags.

3) There are some sub-tree tags in cairo's CVS tree as
   well. Obviously, those aren't very interesting for direct
   comparison.

Also not surprising. For these, I just modified the script to
whitelist the tags I actually cared about checking.

4) There was a branch that diverged from the main line two commits
   "late" in the git history.

I'm not sure what caused this, but it's obviously happening in the
cvsps output. I fixed the problem by capturing the cvsps output into a
file, reordering the branching patchset up two positions in the list,
then feeding the result into git-cvsimport with its -P option.

I've attached the script I used to do the git and cvs comparisons. I
was getting perfect results with a local rsync of cairo's CVS
repository. The version here does a pserver checkout instead. When I
run this I'm apparently getting different substitution of some of
those annoying RCS $Id:...$ strings. Looks like the formatting of the
date is different. So your mileage may vary.

But here it is if its of any interest.


[-- Attachment #1.2: git-cvs-compare --]
[-- Type: application/octet-stream, Size: 1976 bytes --]

#!/bin/sh
set -e

CVSROOT=:pserver:anoncvs@cairographics.org:/cvs/cairo
GITMASTER=git://git.cairographics.org/cairo

if [ ! -e cairo-cvs ]; then
    echo -n "Performing CVS checkout to cairo-cvs..."
    cvs -d $CVSROOT co -d cairo-cvs cairo > /dev/null
    echo "done."
fi

if [ ! -e cairo-git ]; then
    echo -n "Cloning git repository to cairo-git..."
    git clone $GITMASTER cairo-git
    echo "done."
fi

# This is what you probably want to check all tags
#for tag in $(ls cairo-git/.git/refs/tags); do

# Instead, for cairo we whitelist the tags to check since there are
# some bogus partial-tree tags that just aren't interesting.
for tag in SNAPSHOT_0_1_16 SNAPSHOT_0_1_20 SNAPSHOT_0_1_21 SNAPSHOT_0_1_22 SNAPSHOT_0_1_23 LGPL_CHANGE_BEFORE LGPL_CHANGE_AFTER SNAPSHOT_0_2_0 SNAPSHOT_0_3_0 SNAPSHOT_0_4_0 SNAPSHOT_0_5_0 SNAPSHOT_0_5_1 SNAPSHOT_0_5_2 SNAPSHOT_0_6_0 RELEASE_0_9_0 RELEASE_0_9_2 RELEASE_1_0_0 RELEASE_1_0_2; do

    echo -n "Performing cvs update to $tag..."
    (cd cairo-cvs; cvs -Q update -r $tag > /dev/null)
    echo "done."

    echo -n "Performing git checkout of $tag..."

    # Linus says this is the most efficient way to do this, but it
    # seems to leave some empty directories around that shouldn't be
    # there.
    # (cd cairo-git; git checkout -b cvs-compare >& /dev/null || true; git checkout cvs-compare; git reset --hard $tag)

    # This might be slower, but it's plenty fast still and it does the right thing
    (cd cairo-git; git checkout master; git branch -D cvs-compare >& /dev/null || true; git checkout -b cvs-compare $tag)

    echo "done."

    echo -n "Comparing cvs and git trees for $tag..."
    if diff -r -x CVS -x .git cairo-cvs cairo-git >& cairo.diff; then
	echo "perfect."
	rm cairo.diff
    else
	echo "different. :("
	echo "	Saving trees to cairo-git-$tag & cairo-cvs-$tag and diff to cairo-$tag.diff"
	cp -a cairo-git cairo-git-$tag
	cp -a cairo-cvs cairo-cvs-$tag
	mv cairo.diff cairo-$tag.diff
    fi

done

[-- Attachment #1.3: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[relevance 3%]

* What's in git.git
@ 2006-02-16  6:57  3% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-02-16  6:57 UTC (permalink / raw)
  To: git

* Master branch has these since 1.2.1 maintenance release.

  - documentation fixes:
    git-commit: Now --only semantics is the default.

  - usability:
    - rebase aquired a hook to refuse rebasing.
    - commit and add detects misspelled pathspec while making a partial commit.
    - git-svnimport: -r adds svn revision number to commit messages
    - properly git-bisect reset after bisecting from non-master head
    - send-email: Add some options for controlling how addresses
      are automatically added to the cc: list.
    - send-email: Add --cc

* Next branch has these, that are not in master.  If you feel
  you would benefit from these, testing and feedback is greatly
  appreciated.

 - "Assume unchanged git" series (7 commits):

   This was done in response to people on filesystems with slow
   lstat(2).  I do not have such an environment, so I cannot say
   I tested it that much.

 - "Rebase to different branch" (1 commit):

   This was previously discussed on the list.  With this command
   line:

    	$ git rebase --onto master~1 master topic
    
   would rebase this ancestry graph to:
    
              A---B---C topic
             /
        D---E---F---G master
    
    
   another graph that looks like this:
    
                  A'--B'--C' topic
                 /
        D---E---F---G master

   Earlier, you couldn't rebase to anywhere other than on top of
   "the other branch".


* Proposed updates "pu" branch has these, not in "next".  Some
  of them are of iffy nature, and without further work will not
  go anywhere.

 - "merge-tree" series by Linus (2 commits).

   I haven't spent enough time looking at and thinking about
   this yet.

 - "reuse pack data" (1 commit).

   I still haven't seen data corruption with this one, which is
   a good sign, but would like to keep beating it privately for
   a while.  Perhaps will graduate to "next" by next week.

 - "bind commit" series (6 commits).

   I think the core-side is more or less done with this one.
   Anybody interested in doing Porcelain side?

 - "shallow clone" series (1 commit).

   I should drop this one for now and perhaps when enough people
   are interested reopen the issue.

^ permalink raw reply	[relevance 3%]

* [ANNOUNCE] git-svn - bidirection operations between svn and git
@ 2006-02-16  7:38  1% Eric Wong
    0 siblings, 1 reply; 200+ results
From: Eric Wong @ 2006-02-16  7:38 UTC (permalink / raw)
  To: git list

[-- Attachment #1: Type: text/plain, Size: 2171 bytes --]

Hello, I've written a simple tool for interoperating between git and
svn.  I wrote this so I could use git to work on projects where other
developers use Subversion.  I really hate using svn, but some projects I
work on require it, and svk isn't nearly as fast nor simple as git.

git-svn does not replace git-svnimport, git-svnimport handles branches
and tags automatically, but is too inflexible about repository layouts
to be useful for a good number of projects I follow, and of course
git-svnimport can't commit to Subversion repositories :)

git-svn only cares about a single branch/trunk in SVN[1], but you can
use as many branches in git as you want.  This makes it much easier to
use and allows it to handle just about any repository layout, not just
those recommended in the SVN book/developers.

Although importing changesets from SVN is mostly a linear affair,
committing to SVN is the opposite.  You may commit git tree objects in
any order you want.  It simply clobbers the existing svn tree as
'git-checkout -f' would, but tags file renames/copies carefully so users
on the SVN side can see them.  You can even do some wacky things with
patch reordering.

Basic day-to-day usage is pretty simple, and is designed to work with
and also work like normal git commands:

# Initialize a tree (like git init-db)::
	git-svn init http://svn.foo.org/project/trunk

# Fetch remote revisions::
	git-svn fetch

# Create your own branch to hack on::
	git checkout -b my-branch git-svn-HEAD

# Commit only the git commits you want to SVN::
	git-svn commit <tree-ish> [<tree-ish_2> ...] 

# Commit all the git commits from my-branch that don't exist in SVN::
	git rev-list --pretty=oneline git-svn-HEAD..my-branch | git-svn commit

# Something is committed to SVN, pull the latest into your branch::
	git-svn fetch && git pull . git-svn-HEAD

@ Junio: Is there room for this in the git distribution alongside
git-svnimport?

Thanks for reading,

[1] - there are some a hacks that lets you handle branches and tags, but
it's not automated in any way, requires a bit of imagination to use to
its full potential, and is very much a hack.  See the man page :)

-- 
Eric Wong

[-- Attachment #2: git-svn --]
[-- Type: text/plain, Size: 21108 bytes --]

#!/usr/bin/env perl
use warnings;
use strict;
use vars qw/	$AUTHOR $VERSION
		$SVN_URL $SVN_INFO $SVN_WC
		$GIT_SVN_INDEX $GIT_SVN
		$GIT_DIR $REV_DIR/;
$AUTHOR = 'Eric Wong <normalperson@yhbt.net>';
$VERSION = '0.9.0';
$GIT_DIR = $ENV{GIT_DIR} || "$ENV{PWD}/.git";
$GIT_SVN = $ENV{GIT_SVN_ID} || 'git-svn';
$GIT_SVN_INDEX = "$GIT_DIR/$GIT_SVN/index";
$ENV{GIT_DIR} ||= $GIT_DIR;
$SVN_URL = undef;
$REV_DIR = "$GIT_DIR/$GIT_SVN/revs";
$SVN_WC = "$GIT_DIR/$GIT_SVN/tree";

# make sure the svn binary gives consistent output between locales and TZs:
$ENV{TZ} = 'UTC';
$ENV{LC_ALL} = 'C';

# If SVN:: library support is added, please make the dependencies
# optional and preserve the capability to use the command-line client.
# See what I do with XML::Simple to make the dependency optional.
use Carp qw/croak/;
use IO::File qw//;
use File::Basename qw/dirname basename/;
use File::Path qw/mkpath/;
use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev/;
use File::Spec qw//;
my $sha1 = qr/[a-f\d]{40}/;
my $sha1_short = qr/[a-f\d]{6,40}/;
my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit);

GetOptions(	'revision|r=s' => \$_revision,
		'no-ignore-externals' => \$_no_ignore_ext,
		'stdin|' => \$_stdin,
		'edit|e' => \$_edit,
		'rmdir' => \$_rmdir,
		'help|H|h' => \$_help,
		'no-stop-copy' => \$_no_stop_copy );
my %cmd = (
	fetch => [ \&fetch, "Download new revisions from SVN" ],
	init => [ \&init, "Initialize and fetch (import)"],
	commit => [ \&commit, "Commit git revisions to SVN" ],
	rebuild => [ \&rebuild, "Rebuild git-svn metadata (after git clone)" ],
	help => [ \&usage, "Show help" ],
);
my $cmd;
for (my $i = 0; $i < @ARGV; $i++) {
	if (defined $cmd{$ARGV[$i]}) {
		$cmd = $ARGV[$i];
		splice @ARGV, $i, 1;
		last;
	}
};

# we may be called as git-svn-(command), or git-svn(command).
foreach (keys %cmd) {
	if (/git\-svn\-?($_)(?:\.\w+)?$/) {
		$cmd = $1;
		last;
	}
}
usage(0) if $_help;
usage(1) unless (defined $cmd);
svn_check_ignore_externals();
$cmd{$cmd}->[0]->(@ARGV);
exit 0;

####################### primary functions ######################
sub usage {
	my $exit = shift || 0;
	my $fd = $exit ? \*STDERR : \*STDOUT;
	print $fd <<"";
git-svn - bidirectional operations between a single Subversion tree and git
Usage: $0 <command> [options] [arguments]\n
Available commands:

	foreach (sort keys %cmd) {
		print $fd '  ',pack('A10',$_),$cmd{$_}->[1],"\n";
	}
	print $fd <<"";
\nGIT_SVN_ID may be set in the environment to an arbitrary identifier if
you're tracking multiple SVN branches/repositories in one git repository
and want to keep them separate.

	exit $exit;
}

sub rebuild {
	$SVN_URL = shift or undef;
	my $repo_uuid;
	my $newest_rev = 0;
	
	my $pid = open(my $rev_list,'-|');
	defined $pid or croak $!;
	if ($pid == 0) {
		exec("git-rev-list","$GIT_SVN-HEAD") or croak $!;
	}
	my $first;
	while (<$rev_list>) {
		chomp;
		my $c = $_;
		croak "Non-SHA1: $c\n" unless $c =~ /^$sha1$/o;
		my @commit = grep(/^git-svn-id: /,`git-cat-file commit $c`);
		next if (!@commit); # skip merges
		my $id = $commit[$#commit];
		my ($url, $rev, $uuid) = ($id =~ /^git-svn-id:\s(\S+?)\@(\d+)
						\s([a-f\d\-]+)$/x);
		if (!$rev || !$uuid || !$url) {
			# some of the original repositories I made had
			# indentifiers like this:
			($rev, $uuid) = ($id =~/^git-svn-id:\s(\d+)
							\@([a-f\d\-]+)/x);
			if (!$rev || !$uuid) {
				croak "Unable to extract revision or UUID from ",
					"$c, $id\n";
			}
		}
		print "r$rev = $c\n";
		unless (defined $first) {
			if (!$SVN_URL && !$url) {
				croak "SVN repository location required: $url\n";
			}
			$SVN_URL ||= $url;
			$repo_uuid = setup_git_svn();
			$first = $rev;
		}
		if ($uuid ne $repo_uuid) {
			croak "Repository UUIDs do not match!\ngot: $uuid\n",
						"expected: $repo_uuid\n";
		}
		assert_revision_eq_or_unknown($rev, $c);
		sys('git-update-ref',"$GIT_SVN/revs/$rev",$c);
		$newest_rev = $rev if ($rev > $newest_rev);
	}
	close $rev_list or croak $?;
	if (!chdir $SVN_WC) {
		my @svn_co = ('svn','co',"-r$first");
		push @svn_co, '--ignore-externals' unless $_no_ignore_ext;
		sys(@svn_co, $SVN_URL, $SVN_WC);
		chdir $SVN_WC or croak $!;
	}
	
	$pid = fork;
	defined $pid or croak $!;
	if ($pid == 0) {
		my @svn_up = qw(svn up);
		push @svn_up, '--ignore-externals' unless $_no_ignore_ext;
		sys(@svn_up,"-r$newest_rev");
		$ENV{GIT_INDEX_FILE} = $GIT_SVN_INDEX; 
		git_addremove();
		exec('git-write-tree');
	}
	waitpid $pid, 0;
}

sub init {
	$SVN_URL = shift or croak "SVN repository location required\n";
	unless (-d $GIT_DIR) {
		sys('git-init-db');
	}
	setup_git_svn();
}

sub fetch {
	my (@parents) = @_;
	$SVN_URL ||= file_to_s("$GIT_DIR/$GIT_SVN/info/url");
	my @log_args = -d $SVN_WC ? ($SVN_WC) : ($SVN_URL);
	if (-d $SVN_WC && !$_revision) {
		$_revision = 'BASE:HEAD';
	}
	push @log_args, "-r$_revision" if $_revision;
	push @log_args, '--stop-on-copy' unless $_no_stop_copy;

	eval { require XML::Simple or croak $! };
	my $svn_log = $@ ? svn_log_raw(@log_args) : svn_log_xml(@log_args);
	
	my $base = shift @$svn_log or croak "No base revision!\n";
	my $last_commit = undef;
	unless (-d $SVN_WC) {
		my @svn_co = ('svn','co',"-r$base->{revision}");
		push @svn_co,'--ignore-externals' unless $_no_ignore_ext;
		sys(@svn_co, $SVN_URL, $SVN_WC);
		chdir $SVN_WC or croak $!;
		$last_commit = git_commit($base, @parents);
		unless (-f "$GIT_DIR/refs/heads/master") {
			sys(qw(git-update-ref refs/heads/master),$last_commit);
		}
		assert_svn_wc_clean($base->{revision}, $last_commit);
	} else {
		chdir $SVN_WC or croak $!;
		$last_commit = file_to_s("$REV_DIR/$base->{revision}");
	}
	my @svn_up = qw(svn up);
	push @svn_up, '--ignore-externals' unless $_no_ignore_ext;
	my $last_rev = $base->{revision};
	foreach my $log_msg (@$svn_log) {
		assert_svn_wc_clean($last_rev, $last_commit);
		$last_rev = $log_msg->{revision};
		sys(@svn_up,"-r$last_rev");
		$last_commit = git_commit($log_msg, $last_commit, @parents);
	}
	assert_svn_wc_clean($last_rev, $last_commit);
	return pop @$svn_log;
}

sub commit {
	my (@commits) = @_;
	if ($_stdin || !@commits) {
		print "Reading from stdin...\n";
		@commits = ();
		while (<STDIN>) {
			if (/^([a-f\d]{6,40})\b/) {
				unshift @commits, $1;
			}
		}
	}
	my @revs;
	foreach (@commits) {
		push @revs, (safe_qx('git-rev-parse',$_));
	}
	chomp @revs;
	
	fetch();
	chdir $SVN_WC or croak $!;
	my $svn_current_rev =  svn_info('.')->{'Last Changed Rev'};
	foreach my $c (@revs) {
		print "Committing $c\n";
		svn_checkout_tree($svn_current_rev, $c);
		$svn_current_rev = svn_commit_tree($svn_current_rev, $c);
	}
	print "Done committing ",scalar @revs," revisions to SVN\n";
		
}

########################### utility functions #########################

sub setup_git_svn {
	defined $SVN_URL or croak "SVN repository location required\n";
	unless (-d $GIT_DIR) {
		croak "GIT_DIR=$GIT_DIR does not exist!\n";
	}
	mkpath(["$GIT_DIR/$GIT_SVN"]);
	mkpath(["$GIT_DIR/$GIT_SVN/info"]);
	mkpath([$REV_DIR]);
	s_to_file($SVN_URL,"$GIT_DIR/$GIT_SVN/info/url");
	my $uuid = svn_info($SVN_URL)->{'Repository UUID'} or
					croak "Repository UUID unreadable\n";
	s_to_file($uuid,"$GIT_DIR/$GIT_SVN/info/uuid");

	open my $fd, '>>', "$GIT_DIR/$GIT_SVN/info/exclude" or croak $!;
	print $fd '.svn',"\n";
	close $fd or croak $!;
	return $uuid;
}

sub assert_svn_wc_clean {
	my ($svn_rev, $commit) = @_;
	croak "$svn_rev is not an integer!\n" unless ($svn_rev =~ /^\d+$/);
	croak "$commit is not a sha1!\n" unless ($commit =~ /^$sha1$/o);
	my $svn_info = svn_info('.');
	if ($svn_rev != $svn_info->{'Last Changed Rev'}) {
		croak "Expected r$svn_rev, got r",
				$svn_info->{'Last Changed Rev'},"\n";
	}
	my @status = grep(!/^Performing status on external/,(`svn status`));
	@status = grep(!/^\s*$/,@status);
	if (scalar @status) {
		print STDERR "Tree ($SVN_WC) is not clean:\n";
		print STDERR $_ foreach @status;
		croak;
	}
	my ($tree_a) = grep(/^tree $sha1$/o,`git-cat-file commit $commit`);
	$tree_a =~ s/^tree //;
	chomp $tree_a;
	chomp(my $tree_b = `GIT_INDEX_FILE=$GIT_SVN_INDEX git-write-tree`);
	if ($tree_a ne $tree_b) {
		croak "$svn_rev != $commit, $tree_a != $tree_b\n";
	}
}

sub parse_diff_tree {
	my $diff_fh = shift;
	local $/ = "\0";
	my $state = 'meta';
	my @mods;
	while (<$diff_fh>) {
		chomp $_; # this gets rid of the trailing "\0"
		print $_,"\n";
		if ($state eq 'meta' && /^:(\d{6})\s(\d{6})\s
					$sha1\s($sha1)\s([MTCRAD])\d*$/xo) {
			push @mods, {	mode_a => $1, mode_b => $2,
					sha1_b => $3, chg => $4 };
			if ($4 =~ /^(?:C|R)$/) {
				$state = 'file_a';
			} else {
				$state = 'file_b';
			}
		} elsif ($state eq 'file_a') {
			my $x = $mods[$#mods] or croak __LINE__,": Empty array\n";
			if ($x->{chg} !~ /^(?:C|R)$/) {
				croak __LINE__,": Error parsing $_, $x->{chg}\n";
			}
			$x->{file_a} = $_;
			$state = 'file_b';
		} elsif ($state eq 'file_b') {
			my $x = $mods[$#mods] or croak __LINE__,": Empty array\n";
			if (exists $x->{file_a} && $x->{chg} !~ /^(?:C|R)$/) {
				croak __LINE__,": Error parsing $_, $x->{chg}\n";
			}
			if (!exists $x->{file_a} && $x->{chg} =~ /^(?:C|R)$/) {
				croak __LINE__,": Error parsing $_, $x->{chg}\n";
			}
			$x->{file_b} = $_;
			$state = 'meta';
		} else {
			croak __LINE__,": Error parsing $_\n";
		}
	}
	close $diff_fh or croak $!;
	return \@mods;
}

sub svn_check_prop_executable {
	my $m = shift;
	if ($m->{mode_b} =~ /755$/ && $m->{mode_a} !~ /755$/) {
		sys(qw(svn propset svn:executable 1), $m->{file_b});
	} elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) {
		sys(qw(svn propdel svn:executable), $m->{file_b});
	}
}

sub svn_ensure_parent_path {
	my $dir_b = dirname(shift);
	svn_ensure_parent_path($dir_b) if ($dir_b ne File::Spec->curdir);
	mkpath([$dir_b]) unless (-d $dir_b);
	sys(qw(svn add -N), $dir_b) unless (-d "$dir_b/.svn");
}

sub svn_checkout_tree {
	my ($svn_rev, $commit) = @_;
	my $from = file_to_s("$REV_DIR/$svn_rev");
	assert_svn_wc_clean($svn_rev,$from);
	print "diff-tree '$from' '$commit'\n";
	my $pid = open my $diff_fh, '-|';
	defined $pid or croak $!;
	if ($pid == 0) {
		exec(qw(git-diff-tree -z -r -C), $from, $commit) or croak $!;
	}
	my $mods = parse_diff_tree($diff_fh);
	unless (@$mods) {
		# git can do empty commits, SVN doesn't allow it...
		return $svn_rev;
	}
	my %rm;
	foreach my $m (@$mods) {
		if ($m->{chg} eq 'C') {
			svn_ensure_parent_path( $m->{file_b} );
			sys(qw(svn cp),		$m->{file_a}, $m->{file_b});
			blob_to_file(		$m->{sha1_b}, $m->{file_b});
			svn_check_prop_executable($m);
		} elsif ($m->{chg} eq 'D') {
			$rm{dirname $m->{file_b}}->{basename $m->{file_b}} = 1;
			sys(qw(svn rm --force), $m->{file_b});
		} elsif ($m->{chg} eq 'R') {
			svn_ensure_parent_path( $m->{file_b} );
			sys(qw(svn mv --force), $m->{file_a}, $m->{file_b});
			blob_to_file(		$m->{sha1_b}, $m->{file_b});
			svn_check_prop_executable($m);
			$rm{dirname $m->{file_a}}->{basename $m->{file_a}} = 1;
		} elsif ($m->{chg} eq 'M') {
			if ($m->{mode_b} =~ /^120/ && $m->{mode_a} =~ /^120/) {
				unlink $m->{file_b} or croak $!;
				blob_to_symlink($m->{sha1_b}, $m->{file_b});
			} else {
				blob_to_file($m->{sha1_b}, $m->{file_b});
			}
			svn_check_prop_executable($m);
		} elsif ($m->{chg} eq 'T') {
			sys(qw(svn rm --force),$m->{file_b});
			if ($m->{mode_b} =~ /^120/ && $m->{mode_a} =~ /^100/) {
				blob_to_symlink($m->{sha1_b}, $m->{file_b});
			} else {
				blob_to_file($m->{sha1_b}, $m->{file_b});
			}
			svn_check_prop_executable($m);
			sys(qw(svn add --force), $m->{file_b});
		} elsif ($m->{chg} eq 'A') {
			svn_ensure_parent_path( $m->{file_b} );
			blob_to_file(		$m->{sha1_b}, $m->{file_b});
			if ($m->{mode_b} =~ /755$/) {
				chmod 0755, $m->{file_b};
			}
			sys(qw(svn add --force), $m->{file_b});
		} else {
			croak "Invalid chg: $m->{chg}\n";
		}
	}
	if ($_rmdir) {
		my $old_index = $ENV{GIT_INDEX_FILE};
		$ENV{GIT_INDEX_FILE} = $GIT_SVN_INDEX;
		foreach my $dir (keys %rm) {
			my $files = $rm{$dir};
			my @files;
			foreach (safe_qx('svn','ls',$dir)) {
				chomp;
				push @files, $_ unless $files->{$_};
			}
			sys(qw(svn rm),$dir) unless @files;
		}
		if ($old_index) {
			$ENV{GIT_INDEX_FILE} = $old_index;
		} else {
			delete $ENV{GIT_INDEX_FILE};
		}
	}
}

sub svn_commit_tree {
	my ($svn_rev, $commit) = @_;
	my $commit_msg = "$GIT_DIR/$GIT_SVN/.svn-commit.tmp.$$";
	open my $msg, '>', $commit_msg  or croak $!;
	
	chomp(my $type = `git-cat-file -t $commit`);
	if ($type eq 'commit') {
		my $pid = open my $msg_fh, '-|';
		defined $pid or croak $!;

		if ($pid == 0) {
			exec(qw(git-cat-file commit), $commit) or croak $!;
		}
		my $in_msg = 0;
		while (<$msg_fh>) {
			if (!$in_msg) {
				$in_msg = 1 if (/^\s*$/);
			} else {
				print $msg $_ or croak $!;
			}
		}
		close $msg_fh or croak $!;
	}
	close $msg or croak $!;

	if ($_edit || ($type eq 'tree')) {
		my $editor = $ENV{VISUAL} || $ENV{EDITOR} || 'vi';
		system($editor, $commit_msg);
	}
	my @ci_output = safe_qx(qw(svn commit -F),$commit_msg);
	my ($committed) = grep(/^Committed revision \d+\./,@ci_output);
	unlink $commit_msg;
	defined $committed or croak
			"Commit output failed to parse committed revision!\n",
			join("\n",@ci_output),"\n";
	my ($rev_committed) = ($committed =~ /^Committed revision (\d+)\./);

	# resync immediately
	my @svn_up = (qw(svn up), "-r$svn_rev");
	push @svn_up, '--ignore-externals' unless $_no_ignore_ext;
	sys(@svn_up);
	return fetch("$rev_committed=$commit")->{revision};
}

sub svn_log_xml {
	my (@log_args) = @_;
	my $log_fh = IO::File->new_tmpfile or croak $!;
	
	my $pid = fork;
	defined $pid or croak $!;
	
	if ($pid == 0) {
		open STDOUT, '>&', $log_fh or croak $!;
		exec (qw(svn log --xml), @log_args) or croak $!
	}
	
	waitpid $pid, 0;
	croak $? if $?;

	seek $log_fh, 0, 0;
	my @svn_log;
	my $log = XML::Simple::XMLin( $log_fh,
				ForceArray => ['path','revision','logentry'],
				KeepRoot => 0,
				KeyAttr => {	logentry => '+revision',
						paths => '+path' },
			)->{logentry};
	foreach my $r (sort {$a <=> $b} keys %$log) {
		my $log_msg = $log->{$r};
		my ($Y,$m,$d,$H,$M,$S) = ($log_msg->{date} =~
					/(\d{4})\-(\d\d)\-(\d\d)T
					 (\d\d)\:(\d\d)\:(\d\d)\.\d+Z$/x)
					 or croak "Failed to parse date: ",
						 $log->{$r}->{date};
		$log_msg->{date} = "+0000 $Y-$m-$d $H:$M:$S";

		# XML::Simple can't handle <msg></msg> as a string:
		if (ref $log_msg->{msg} eq 'HASH') {
			$log_msg->{msg} = "\n";
		} else {
			$log_msg->{msg} .= "\n";
		}
		push @svn_log, $log->{$r};
	}
	return \@svn_log;
}

sub svn_log_raw {
	my (@log_args) = @_;
	my $pid = open my $log_fh,'-|';
	defined $pid or croak $!;
	
	if ($pid == 0) {
		exec (qw(svn log), @log_args) or croak $!
	}
	
	my @svn_log;
	my $state;
	while (<$log_fh>) {
		chomp;
		if (/^\-{72}$/) {
			$state = 'rev';
			
			# if we have an empty log message, put something there:
			if (@svn_log) {
				$svn_log[0]->{msg} ||= "\n";
			}
			next;
		}
		if ($state eq 'rev' && s/^r(\d+)\s*\|\s*//) {
			my $rev = $1;
			my ($author, $date) = split(/\s*\|\s*/, $_, 2);
			my ($Y,$m,$d,$H,$M,$S,$tz) = ($date =~
					/(\d{4})\-(\d\d)\-(\d\d)\s
					 (\d\d)\:(\d\d)\:(\d\d)\s([\-\+]\d+)/x)
					 or croak "Failed to parse date: $date\n";
			my %log_msg = (	revision => $rev,
					date => "$tz $Y-$m-$d $H:$M:$S",
					author => $author,
					msg => '' );
			unshift @svn_log, \%log_msg;
			$state = 'msg_start';
			next;
		}
		# skip the first blank line of the message:
		if ($state eq 'msg_start' && /^$/) {
			$state = 'msg';
		} elsif ($state eq 'msg') {
			$svn_log[0]->{msg} .= $_."\n";
		}
	}
	close $log_fh or croak $?;
	return \@svn_log;
}

sub svn_info {
	my $url = shift || $SVN_URL;

	my $pid = open my $info_fh, '-|';
	defined $pid or croak $!;
	
	if ($pid == 0) {
		exec(qw(svn info),$url) or croak $!;
	}
	
	my $ret = {};
	# only single-lines seem to exist in svn info output
	while (<$info_fh>) {
		chomp $_;
		if (m#^([^:]+)\s*:\s*(\S*)$#) {
			$ret->{$1} = $2;
			push @{$ret->{-order}}, $1;
		}
	}
	close $info_fh or croak $!;
	return $ret;
}

sub sys { system(@_) == 0 or croak $? }

sub git_addremove {
	system(	"git-ls-files -z --others ".
			"'--exclude-from=$GIT_DIR/$GIT_SVN/info/exclude'".
				"| git-update-index --add -z --stdin; ".
		"git-ls-files -z --deleted ".
				"| git-update-index --remove -z --stdin; ".
		"git-ls-files -z --modified".
				"| git-update-index -z --stdin") == 0 or croak $?
}

sub s_to_file {
	my ($str, $file, $mode) = @_;
	open my $fd,'>',$file or croak $!;
	print $fd $str,"\n" or croak $!;
	close $fd or croak $!;
	chmod ($mode &~ umask, $file) if (defined $mode);
}

sub file_to_s {
	my $file = shift;
	open my $fd,'<',$file or croak "$!: file: $file\n";
	local $/;
	my $ret = <$fd>;
	close $fd or croak $!;
 	$ret =~ s/\s*$//s;
	return $ret;
}

sub assert_revision_unknown {
	my $revno = shift;
	if (-f "$REV_DIR/$revno") {
		croak "$REV_DIR/$revno already exists! ",
				"Why are we refetching it?";
	}
}

sub assert_revision_eq_or_unknown {
	my ($revno, $commit) = @_;
	if (-f "$REV_DIR/$revno") {
		my $current = file_to_s("$REV_DIR/$revno");
		if ($commit ne $current) {
			croak "$REV_DIR/$revno already exists!\n",
				"current: $current\nexpected: $commit\n";
		}
		return;
	}
}

sub git_commit {
	my ($log_msg, @parents) = @_;
	assert_revision_unknown($log_msg->{revision});
	my $out_fh = IO::File->new_tmpfile or croak $!;
	my $info = svn_info('.');
	my $uuid = $info->{'Repository UUID'};
	defined $uuid or croak "Unable to get Repository UUID\n";

	# commit parents can be conditionally bound to a particular
	# svn revision via: "svn_revno=commit_sha1", filter them out here:
	my @exec_parents;
	foreach my $p (@parents) {
		next unless defined $p;
		if ($p =~ /^(\d+)=($sha1_short)$/o) {
			if ($1 == $log_msg->{revision}) {
				push @exec_parents, $2;
			}
		} else {
			push @exec_parents, $p if $p =~ /$sha1_short/o;
		}
	}

	my $pid = fork;
	defined $pid or croak $!;
	if ($pid == 0) {
		$ENV{GIT_INDEX_FILE} = $GIT_SVN_INDEX;
		git_addremove();
		chomp(my $tree = `git-write-tree`);
		croak if $?;
		my $msg_fh = IO::File->new_tmpfile or croak $!;
		print $msg_fh $log_msg->{msg}, "\ngit-svn-id: ", 
					"$SVN_URL\@$log_msg->{revision}",
					" $uuid\n" or croak $!;
		$msg_fh->flush == 0 or croak $!;
		seek $msg_fh, 0, 0 or croak $!;

		$ENV{GIT_AUTHOR_NAME} = $ENV{GIT_COMMITTER_NAME} =
						$log_msg->{author};
		$ENV{GIT_AUTHOR_EMAIL} = $ENV{GIT_COMMITTER_EMAIL} =
						$log_msg->{author}."\@$uuid";
		$ENV{GIT_AUTHOR_DATE} = $ENV{GIT_COMMITTER_DATE} =
						$log_msg->{date};
		my @exec = ('git-commit-tree',$tree);
		push @exec, '-p', $_  foreach @exec_parents;
		open STDIN, '<&', $msg_fh or croak $!;
		open STDOUT, '>&', $out_fh or croak $!;
		exec @exec or croak $!;
	}
	waitpid($pid,0);
	croak if $?;

	$out_fh->flush == 0 or croak $!;
	seek $out_fh, 0, 0 or croak $!;
	chomp(my $commit = do { local $/; <$out_fh> });
	if ($commit !~ /^$sha1$/o) {
		croak "Failed to commit, invalid sha1: $commit\n";
	}
	my @update_ref = ('git-update-ref',"refs/heads/$GIT_SVN-HEAD",$commit);
	if (my $primary_parent = shift @exec_parents) {
		push @update_ref, $primary_parent;
	}
	sys(@update_ref);
	sys('git-update-ref',"$GIT_SVN/revs/$log_msg->{revision}",$commit);
	print "r$log_msg->{revision} = $commit\n";
	return $commit;
}

sub blob_to_symlink {
	my ($blob, $link) = @_;
	defined $link or croak "\$link not defined!\n";
	croak "Not a sha1: $blob\n" unless $blob =~ /^$sha1$/o;
	my $dest = `git-cat-file blob $blob`; # no newline, so no chomp
	symlink $dest, $link or croak $!;
}

sub blob_to_file {
	my ($blob, $file) = @_;
	defined $file or croak "\$file not defined!\n";
	croak "Not a sha1: $blob\n" unless $blob =~ /^$sha1$/o;
	open my $blob_fh, '>', $file or croak "$!: $file\n";
	my $pid = fork;
	defined $pid or croak $!;

	if ($pid == 0) {
		open STDOUT, '>&', $blob_fh or croak $!;
		exec('git-cat-file','blob',$blob);
	}
	waitpid $pid, 0;
	croak $? if $?;
	
	close $blob_fh or croak $!;
}

sub safe_qx {
	my $pid = open my $child, '-|';
	defined $pid or croak $!;
	if ($pid == 0) {
		exec(@_) or croak $?;
	}
	my @ret = (<$child>);
	close $child or croak $?;
	die $? if $?; # just in case close didn't error out
	return wantarray ? @ret : join('',@ret);
}

sub svn_check_ignore_externals {
	return if $_no_ignore_ext;
	unless (grep /ignore-externals/,(safe_qx(qw(svn co -h)))) {
		print STDERR "W: Installed svn version does not support ",
				"--ignore-externals\n";
		$_no_ignore_ext = 1;
	}
}
__END__

Data structures:

@svn_log = array of log_msg hashes

$log_msg hash 
{ 
	msg => 'whitespace-formatted log entry
',						# trailing newline is preserved
	revision => '8',			# integer
	date => '2004-02-24T17:01:44.108345Z',	# commit date
	author => 'committer name' 
};


@mods = array of diff-index line hashes, each element represents one line
	of diff-index output

diff-index line ($m hash)
{
	mode_a => first column of diff-index output, no leading ':',
	mode_b => second column of diff-index output,
	sha1_b => sha1sum of the final blob,
	chg => change type [MCRAD],
	file_a => original file name of a file (iff chg is 'C' or 'R')
	file_b => new/current file name of a file (any chg)
}
;

[-- Attachment #3: git-svn.txt --]
[-- Type: text/plain, Size: 7405 bytes --]

git-svn(1)
==========

NAME
----
git-svn - bidirectional operation between a single Subversion branch and git

SYNOPSIS
--------
'git-svn' <command> [options] [arguments]

DESCRIPTION
-----------
git-svn is a simple conduit for changesets between a single Subversion
branch and git.

git-svn is not to be confused with git-svnimport.  The were designed
with very different goals in mind.

git-svn is designed for an individual developer who wants a
bidirectional flow of changesets between a single branch in Subversion
and an arbitrary number of branches in git.  git-svnimport is designed
for read-only operation on repositories that match a particular layout
(albeit the recommended one by SVN developers).

For importing svn, git-svnimport is potentially more powerful when
operating on repositories organized under the recommended
trunk/branch/tags structure, and should be faster, too.

git-svn completely ignores the very limited view of branching that
Subversion has.  This allows git-svn to be much easier to use,
especially on repositories that are not organized in a manner that
git-svnimport is designed for.

COMMANDS
--------
init::
	Creates an empty git repository with additional metadata
	directories for git-svn.  The SVN_URL must be specified
	at this point.

fetch::
	Fetch unfetched revisions from the SVN_URL we are tracking.
	refs/heads/git-svn-HEAD will be updated to the latest revision.
	
commit::
	Commit specified commit or tree objects to SVN.  This relies on
	your imported fetch data being up-to-date.  This makes
	absolutely no attempts to do patching when committing to SVN, it
	simply overwrites files with those specified in the tree or
	commit.  All merging is assumed to have taken place
	independently of git-svn functions.

rebuild::
	Not a part of daily usage, but this is a useful command if
	you've just cloned a repository (using git-clone) that was
	tracked with git-svn.  Unfortunately, git-clone does not clone
	git-svn metadata and the svn working tree that git-svn uses for
	its operations.  This rebuilds the metadata so git-svn can
	resume fetch operations.  SVN_URL may be optionally specified if
	the directory/repository you're tracking has moved or changed
	protocols.

OPTIONS
-------
-r <ARG>::
--revision <ARG>::
	Only used with the 'fetch' command.

	Takes any valid -r<argument> svn would accept and passes it
	directly to svn. -r<ARG1>:<ARG2> ranges and "{" DATE "}" syntax
	is also supported.  This is passed directly to svn, see svn
	documentation for more details.

	This can allow you to make partial mirrors when running fetch.

-::
--stdin::
	Only used with the 'commit' command.
	
	Read a list of commits from stdin and commit them in reverse
	order.  Only the leading sha1 is read from each line, so
	git-rev-list --pretty=oneline output can be used.

--rmdir::
	Only used with the 'commit' command.

	Remove directories from the SVN tree if there are no files left
	behind.  SVN can version empty directories, and they are not
	removed by default if there are no files left in them.  git
	cannot version empty directories.  Enabling this flag will make
	the commit to SVN act like git.

-e::
--edit::
	Only used with the 'commit' command.
	
	Edit the commit message before committing to SVN.  This is off by
	default for objects that are commits, and forced on when committing
	tree objects.

COMPATIBILITY OPTIONS
---------------------
--no-ignore-externals::
	Only used with the 'fetch' and 'rebuild' command.

	By default, git-svn passes --ignore-externals to svn to avoid
	fetching svn:external trees into git.  Pass this flag to enable
	externals tracking directly via git.

	Versions of svn that do not support --ignore-externals are
	automatically detected and this flag will be automatically
	enabled for them.

	Otherwise, do not enable this flag unless you know what you're
	doing.

--no-stop-on-copy::
	Only used with the 'fetch' command.

	By default, git-svn passes --stop-on-copy to avoid dealing with
	the copied/renamed branch directory problem entirely.  A
	copied/renamed branch is the result of a <SVN_URL> being created
	in the past from a different source.  These are problematic to
	deal with even when working purely with svn if you work inside
	subdirectories.

	Do not use this flag unless you know exactly what you're getting
	yourself into.  You have been warned.

Examples
~~~~~~~~

Tracking and contributing to an Subversion managed-project:

# Initialize a tree (like git init-db)::
	git-svn init http://svn.foo.org/project/trunk
# Fetch remote revisions::
	git-svn fetch
# Create your own branch to hack on::
	git checkout -b my-branch git-svn-HEAD
# Commit only the git commits you want to SVN::
	git-svn commit <tree-ish> [<tree-ish_2> ...] 
# Commit all the git commits from my-branch that don't exist in SVN::
	git rev-list --pretty=oneline git-svn-HEAD..my-branch | git-svn commit
# Something is committed to SVN, pull the latest into your branch::
	git-svn fetch && git pull . git-svn-HEAD

DESIGN PHILOSOPHY
-----------------
Merge tracking in Subversion is lacking and doing branched development
with Subversion is cumbersome as a result.  git-svn completely forgoes
any automated merge/branch tracking on the Subversion side and leaves it
entirely up to the user on the git side.  It's simply not worth it to do
a useful translation when the the original signal is weak.

TRACKING MULTIPLE REPOSITORIES OR BRANCHES
------------------------------------------
This is for advanced users, most users should ignore this section.

Because git-svn does not care about relationships between different
branches or directories in a Subversion repository, git-svn has a simple
hack to allow it to track an arbitrary number of related _or_ unrelated
SVN repositories via one git repository.  Simply set the GIT_SVN_ID
environment variable to a name other other than "git-svn" (the default)
and git-svn will ignore the contents of the $GIT_DIR/git-svn directory
and instead do all of its work in $GIT_DIR/$GIT_SVN_ID for that
invocation.

ADDITIONAL FETCH ARGUMENTS
--------------------------
This is for advanced users, most users should ignore this section.

Unfetched SVN revisions may be imported as children of existing commits
by specifying additional arguments to 'fetch'.  Additional parents may
optionally be specified in the form of sha1 hex sums at the
command-line.  Unfetched SVN revisions may also be tied to particular
git commits with the following syntax:
		
	svn_revision_number=git_commit_sha1

This allows you to tie unfetched SVN revision 375 to your current HEAD::

	git-svn fetch 375=$(git-rev-parse HEAD)

BUGS
----
If somebody commits a conflicting changeset to SVN at a bad moment
(right before you commit) causing a conflict and your commit to fail,
your svn working tree ($GIT_DIR/git-svn/tree) may be dirtied.  The
easiest thing to do is probably just to rm -rf $GIT_DIR/git-svn/tree and
run 'rebuild'.

We ignore all SVN properties except svn:executable.  Too difficult to
map them since we rely heavily on git write-tree being _exactly_ the
same on both the SVN and git working trees and I prefer not to clutter
working trees with metadata files.

svn:keywords can't be ignored in Subversion (at least I don't know of
a way to ignore them).

Author
------
Written by Eric Wong <normalperson@yhbt.net>.

Documentation
-------------
Written by Eric Wong <normalperson@yhbt.net>.

^ permalink raw reply	[relevance 1%]

* Re: [ANNOUNCE] git-svn - bidirection operations between svn and git
  @ 2006-02-16 19:25  2%   ` Eric Wong
  0 siblings, 0 replies; 200+ results
From: Eric Wong @ 2006-02-16 19:25 UTC (permalink / raw)
  To: Eduardo Pereira Habkost; +Cc: git list

Eduardo Pereira Habkost <ehabkost@mandriva.com> wrote:
> On Wed, Feb 15, 2006 at 11:38:26PM -0800, Eric Wong wrote:
> > Hello, I've written a simple tool for interoperating between git and
> > svn.  I wrote this so I could use git to work on projects where other
> > developers use Subversion.  I really hate using svn, but some projects I
> > work on require it, and svk isn't nearly as fast nor simple as git.
> 
> Great, I was doing some testing with git-svnimport for this, but I missed
> a tool to automatically commit to svn what I have in my GIT tree.
> 
> > 
> > git-svn does not replace git-svnimport, git-svnimport handles branches
> > and tags automatically, but is too inflexible about repository layouts
> > to be useful for a good number of projects I follow, and of course
> > git-svnimport can't commit to Subversion repositories :)
> 
> I am already using git-svnimport to keep a "mirror" of some subversion
> repositories, here (automatically udpated on crontab). Do you plan to
> allow "integration" with repositories that are just clones of
> git-svnimport'ed repositories?

It's possible, just not very obvious at the moment.  git-svn was written
as quickly as possible without regard to svnimport compatibility since I
had some repos that didn't work with svnimport to begin with.

The 'ADDITIONAL FETCH ARGUMENTS' part of the manpage is worth reading
for you.  Basically, you can define equalities
"(svn revision number)=(git commit)" as arguments to git-svn fetch to 
add parents for all the revisions it imports.

If I were you, I'd only want git-svn to care about partial history,
since you already have the rest of it from git-svnimport.  You can do
this:

	svn_revno=<last svn revision number you imported from git-svnimport>
	git_commit=<equivalent commit sha1 name of svn_revno above>
	git-svn fetch --revision $svn_revno:HEAD $svn_revno=$git_commit

> I plan to keep using git-svnimport and the standard git tools to work
> using the "svn mirror on git" as the main repository, but I plan to use
> "git-svn commit" to commit to the SVN repositories. I want this "commit
> tool" to not affect the current repository in any way, just like git-push:
> only send the commits to the remote repository and don't change anything
> in the local repository.
 
> However, it seems that "git-svn commit" does some tasks assuming we
> are on a "git-svn aware" repository (e.g. the "resyncing" just after
> the commit). Would you accept patches to allow using "git-svn commit"
> to commit changes from any GIT repository (i.e. not "svn-git aware"
> repositories) to any SVN repository, just like "git-push" would work
> for a GIT repository?
>
> However, I am not sure if the easier way would be changing git-svn to
> do this for me or writing a different script just for this task.

You should be 95% there just by exporting the svn_checkout_tree()
function to the command-line.  Perhaps automating reading of the
$svn_rev variable can be in order.

-- 
Eric Wong

^ permalink raw reply	[relevance 2%]

* [PATCH] First cut at libifying revlist generation
@ 2006-02-26  0:19  1% Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2006-02-26  0:19 UTC (permalink / raw)
  To: Junio C Hamano, Git Mailing List


This really just splits things up partially, and creates the
interface to set things up by parsign the command line.

No real code changes so far, although the parsing of filenames is a bit 
stricter. In particular, if there is a "--", then we do not accept any 
filenames before it, and if there isn't any "--", then we check that _all_ 
paths listed are valid, not just the first one.

The new argument parsing automatically also gives us "--default" and 
"--not" handling as in git-rev-parse.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>
---

The path checking just makes sense. 

This also makes git-rev-list handle "--all" and "--not" correctly (before, 
it wouldn't handle "--not"), and teaches it to handle "--default". I 
didn't do "--since" and "--before", but I will eventually. The final end 
result is that we won't need git-rev-parse for most things.

But basically there should be no code changes, and this is just a mid-way 
point where a _partial_ set of routines from "git-rev-list" has been moved 
into a library files - revision.c. The half-way point has some ugly 
interfaces, but I don't want to do it all in one go.

The _plan_ is to:

 - move the actual history traversal into revision.c too

 - leave all the git-rev-list -specific stuff (the "--bisect" logic, 
   the print-out logic etc) in rev-list.c

 - make it trivial to make a small C version of "git diff" that just uses 
   the same "setup_revisions()" interface and then looks at 
   "revs->commits" to see what revisions were passed in (the library 
   interface is already at the point where that should work)

 - when the actual history _traversal_ is moved into "revision.c" too, it 
   should then be possible to make an equally small "git log" and friends 
   (whatchanged etc) into C using the revision.c code.

Comments? I think this is safe to apply, because I've done a diff of the 
old non-split rev-list.c against both the new rev-list.c and revision.c, 
and all the changes _look_ like just moving things around and taking the 
new "struct rev_info" into account.

It also passes all the tests, and in general seems straightforward enough. 
HOEVER, I'd still like to point out that I could have screwed something 
up, and this is just about the most core program in all of git, so it 
would make a lot of sense if more people double-checked my "trivial" 
split-up.

		Linus


diff --git a/Makefile b/Makefile
index 6c59cee..3575489 100644
--- a/Makefile
+++ b/Makefile
@@ -192,7 +192,7 @@ LIB_FILE=libgit.a
 LIB_H = \
 	blob.h cache.h commit.h count-delta.h csum-file.h delta.h \
 	diff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \
-	run-command.h strbuf.h tag.h tree.h git-compat-util.h
+	run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h
 
 DIFF_OBJS = \
 	diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \
@@ -205,7 +205,7 @@ LIB_OBJS = \
 	quote.o read-cache.o refs.o run-command.o \
 	server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \
 	tag.o tree.o usage.o config.o environment.o ctype.o copy.o \
-	fetch-clone.o \
+	fetch-clone.o revision.o \
 	$(DIFF_OBJS)
 
 LIBS = $(LIB_FILE)
diff --git a/epoch.c b/epoch.c
index 3a76748..0f37492 100644
--- a/epoch.c
+++ b/epoch.c
@@ -15,6 +15,7 @@
 
 #include "cache.h"
 #include "commit.h"
+#include "revision.h"
 #include "epoch.h"
 
 struct fraction {
diff --git a/epoch.h b/epoch.h
index 7493d5a..3756009 100644
--- a/epoch.h
+++ b/epoch.h
@@ -11,7 +11,6 @@ typedef int (*emitter_func) (struct comm
 int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter);
 
 /* Low bits are used by rev-list */
-#define UNINTERESTING   (1u<<10)
 #define BOUNDARY        (1u<<11)
 #define VISITED         (1u<<12)
 #define DISCONTINUITY   (1u<<13)
diff --git a/rev-list.c b/rev-list.c
index 67d2a48..d1c52a6 100644
--- a/rev-list.c
+++ b/rev-list.c
@@ -6,9 +6,10 @@
 #include "blob.h"
 #include "epoch.h"
 #include "diff.h"
+#include "revision.h"
+
+/* bits #0 and #1 in revision.h */
 
-#define SEEN		(1u << 0)
-#define INTERESTING	(1u << 1)
 #define COUNTED		(1u << 2)
 #define SHOWN		(1u << 3)
 #define TREECHANGE	(1u << 4)
@@ -38,60 +39,20 @@ static const char rev_list_usage[] =
 "    --bisect"
 ;
 
-static int dense = 1;
+struct rev_info revs;
+
 static int unpacked = 0;
 static int bisect_list = 0;
-static int tag_objects = 0;
-static int tree_objects = 0;
-static int blob_objects = 0;
-static int edge_hint = 0;
 static int verbose_header = 0;
 static int abbrev = DEFAULT_ABBREV;
 static int show_parents = 0;
 static int hdr_termination = 0;
 static const char *commit_prefix = "";
-static unsigned long max_age = -1;
-static unsigned long min_age = -1;
-static int max_count = -1;
 static enum cmit_fmt commit_format = CMIT_FMT_RAW;
 static int merge_order = 0;
 static int show_breaks = 0;
 static int stop_traversal = 0;
-static int topo_order = 0;
-static int lifo = 1;
 static int no_merges = 0;
-static const char **paths = NULL;
-static int remove_empty_trees = 0;
-
-struct name_path {
-	struct name_path *up;
-	int elem_len;
-	const char *elem;
-};
-
-static char *path_name(struct name_path *path, const char *name)
-{
-	struct name_path *p;
-	char *n, *m;
-	int nlen = strlen(name);
-	int len = nlen + 1;
-
-	for (p = path; p; p = p->up) {
-		if (p->elem_len)
-			len += p->elem_len + 1;
-	}
-	n = xmalloc(len);
-	m = n + len - (nlen + 1);
-	strcpy(m, name);
-	for (p = path; p; p = p->up) {
-		if (p->elem_len) {
-			m -= p->elem_len + 1;
-			memcpy(m, p->elem, p->elem_len);
-			m[p->elem_len] = '/';
-		}
-	}
-	return n;
-}
 
 static void show_commit(struct commit *commit)
 {
@@ -168,15 +129,15 @@ static int filter_commit(struct commit *
 		return STOP;
 	if (commit->object.flags & (UNINTERESTING|SHOWN))
 		return CONTINUE;
-	if (min_age != -1 && (commit->date > min_age))
+	if (revs.min_age != -1 && (commit->date > revs.min_age))
 		return CONTINUE;
-	if (max_age != -1 && (commit->date < max_age)) {
+	if (revs.max_age != -1 && (commit->date < revs.max_age)) {
 		stop_traversal=1;
 		return CONTINUE;
 	}
 	if (no_merges && (commit->parents && commit->parents->next))
 		return CONTINUE;
-	if (paths && dense) {
+	if (revs.paths && revs.dense) {
 		if (!(commit->object.flags & TREECHANGE))
 			return CONTINUE;
 		rewrite_parents(commit);
@@ -196,7 +157,7 @@ static int process_commit(struct commit 
 		return CONTINUE;
 	}
 
-	if (max_count != -1 && !max_count--)
+	if (revs.max_count != -1 && !revs.max_count--)
 		return STOP;
 
 	show_commit(commit);
@@ -204,19 +165,6 @@ static int process_commit(struct commit 
 	return CONTINUE;
 }
 
-static struct object_list **add_object(struct object *obj,
-				       struct object_list **p,
-				       struct name_path *path,
-				       const char *name)
-{
-	struct object_list *entry = xmalloc(sizeof(*entry));
-	entry->item = obj;
-	entry->next = *p;
-	entry->name = path_name(path, name);
-	*p = entry;
-	return &entry->next;
-}
-
 static struct object_list **process_blob(struct blob *blob,
 					 struct object_list **p,
 					 struct name_path *path,
@@ -224,7 +172,7 @@ static struct object_list **process_blob
 {
 	struct object *obj = &blob->object;
 
-	if (!blob_objects)
+	if (!revs.blob_objects)
 		return p;
 	if (obj->flags & (UNINTERESTING | SEEN))
 		return p;
@@ -241,7 +189,7 @@ static struct object_list **process_tree
 	struct tree_entry_list *entry;
 	struct name_path me;
 
-	if (!tree_objects)
+	if (!revs.tree_objects)
 		return p;
 	if (obj->flags & (UNINTERESTING | SEEN))
 		return p;
@@ -314,75 +262,6 @@ static void show_commit_list(struct comm
 	}
 }
 
-static void mark_blob_uninteresting(struct blob *blob)
-{
-	if (!blob_objects)
-		return;
-	if (blob->object.flags & UNINTERESTING)
-		return;
-	blob->object.flags |= UNINTERESTING;
-}
-
-static void mark_tree_uninteresting(struct tree *tree)
-{
-	struct object *obj = &tree->object;
-	struct tree_entry_list *entry;
-
-	if (!tree_objects)
-		return;
-	if (obj->flags & UNINTERESTING)
-		return;
-	obj->flags |= UNINTERESTING;
-	if (!has_sha1_file(obj->sha1))
-		return;
-	if (parse_tree(tree) < 0)
-		die("bad tree %s", sha1_to_hex(obj->sha1));
-	entry = tree->entries;
-	tree->entries = NULL;
-	while (entry) {
-		struct tree_entry_list *next = entry->next;
-		if (entry->directory)
-			mark_tree_uninteresting(entry->item.tree);
-		else
-			mark_blob_uninteresting(entry->item.blob);
-		free(entry);
-		entry = next;
-	}
-}
-
-static void mark_parents_uninteresting(struct commit *commit)
-{
-	struct commit_list *parents = commit->parents;
-
-	while (parents) {
-		struct commit *commit = parents->item;
-		commit->object.flags |= UNINTERESTING;
-
-		/*
-		 * Normally we haven't parsed the parent
-		 * yet, so we won't have a parent of a parent
-		 * here. However, it may turn out that we've
-		 * reached this commit some other way (where it
-		 * wasn't uninteresting), in which case we need
-		 * to mark its parents recursively too..
-		 */
-		if (commit->parents)
-			mark_parents_uninteresting(commit);
-
-		/*
-		 * A missing commit is ok iff its parent is marked 
-		 * uninteresting.
-		 *
-		 * We just mark such a thing parsed, so that when
-		 * it is popped next time around, we won't be trying
-		 * to parse it and get an error.
-		 */
-		if (!has_sha1_file(commit->object.sha1))
-			commit->object.parsed = 1;
-		parents = parents->next;
-	}
-}
-
 static int everybody_uninteresting(struct commit_list *orig)
 {
 	struct commit_list *list = orig;
@@ -413,7 +292,7 @@ static int count_distance(struct commit_
 
 		if (commit->object.flags & (UNINTERESTING | COUNTED))
 			break;
-		if (!paths || (commit->object.flags & TREECHANGE))
+		if (!revs.paths || (commit->object.flags & TREECHANGE))
 			nr++;
 		commit->object.flags |= COUNTED;
 		p = commit->parents;
@@ -447,7 +326,7 @@ static struct commit_list *find_bisectio
 	nr = 0;
 	p = list;
 	while (p) {
-		if (!paths || (p->item->object.flags & TREECHANGE))
+		if (!revs.paths || (p->item->object.flags & TREECHANGE))
 			nr++;
 		p = p->next;
 	}
@@ -457,7 +336,7 @@ static struct commit_list *find_bisectio
 	for (p = list; p; p = p->next) {
 		int distance;
 
-		if (paths && !(p->item->object.flags & TREECHANGE))
+		if (revs.paths && !(p->item->object.flags & TREECHANGE))
 			continue;
 
 		distance = count_distance(p);
@@ -483,7 +362,7 @@ static void mark_edge_parents_uninterest
 		if (!(parent->object.flags & UNINTERESTING))
 			continue;
 		mark_tree_uninteresting(parent->tree);
-		if (edge_hint && !(parent->object.flags & SHOWN)) {
+		if (revs.edge_hint && !(parent->object.flags & SHOWN)) {
 			parent->object.flags |= SHOWN;
 			printf("-%s\n", sha1_to_hex(parent->object.sha1));
 		}
@@ -613,7 +492,7 @@ static void try_to_simplify_commit(struc
 			return;
 
 		case TREE_NEW:
-			if (remove_empty_trees && same_tree_as_empty(p->tree)) {
+			if (revs.remove_empty_trees && same_tree_as_empty(p->tree)) {
 				*pp = parent->next;
 				continue;
 			}
@@ -664,7 +543,7 @@ static void add_parents_to_list(struct c
 	 * simplify the commit history and find the parent
 	 * that has no differences in the path set if one exists.
 	 */
-	if (paths)
+	if (revs.paths)
 		try_to_simplify_commit(commit);
 
 	parent = commit->parents;
@@ -693,7 +572,7 @@ static struct commit_list *limit_list(st
 		list = list->next;
 		free(entry);
 
-		if (max_age != -1 && (commit->date < max_age))
+		if (revs.max_age != -1 && (commit->date < revs.max_age))
 			obj->flags |= UNINTERESTING;
 		if (unpacked && has_sha1_pack(obj->sha1))
 			obj->flags |= UNINTERESTING;
@@ -704,155 +583,40 @@ static struct commit_list *limit_list(st
 				break;
 			continue;
 		}
-		if (min_age != -1 && (commit->date > min_age))
+		if (revs.min_age != -1 && (commit->date > revs.min_age))
 			continue;
 		p = &commit_list_insert(commit, p)->next;
 	}
-	if (tree_objects)
+	if (revs.tree_objects)
 		mark_edges_uninteresting(newlist);
 	if (bisect_list)
 		newlist = find_bisection(newlist);
 	return newlist;
 }
 
-static void add_pending_object(struct object *obj, const char *name)
-{
-	add_object(obj, &pending_objects, NULL, name);
-}
-
-static struct commit *get_commit_reference(const char *name, const unsigned char *sha1, unsigned int flags)
-{
-	struct object *object;
-
-	object = parse_object(sha1);
-	if (!object)
-		die("bad object %s", name);
-
-	/*
-	 * Tag object? Look what it points to..
-	 */
-	while (object->type == tag_type) {
-		struct tag *tag = (struct tag *) object;
-		object->flags |= flags;
-		if (tag_objects && !(object->flags & UNINTERESTING))
-			add_pending_object(object, tag->tag);
-		object = parse_object(tag->tagged->sha1);
-		if (!object)
-			die("bad object %s", sha1_to_hex(tag->tagged->sha1));
-	}
-
-	/*
-	 * Commit object? Just return it, we'll do all the complex
-	 * reachability crud.
-	 */
-	if (object->type == commit_type) {
-		struct commit *commit = (struct commit *)object;
-		object->flags |= flags;
-		if (parse_commit(commit) < 0)
-			die("unable to parse commit %s", name);
-		if (flags & UNINTERESTING)
-			mark_parents_uninteresting(commit);
-		return commit;
-	}
-
-	/*
-	 * Tree object? Either mark it uniniteresting, or add it
-	 * to the list of objects to look at later..
-	 */
-	if (object->type == tree_type) {
-		struct tree *tree = (struct tree *)object;
-		if (!tree_objects)
-			return NULL;
-		if (flags & UNINTERESTING) {
-			mark_tree_uninteresting(tree);
-			return NULL;
-		}
-		add_pending_object(object, "");
-		return NULL;
-	}
-
-	/*
-	 * Blob object? You know the drill by now..
-	 */
-	if (object->type == blob_type) {
-		struct blob *blob = (struct blob *)object;
-		if (!blob_objects)
-			return NULL;
-		if (flags & UNINTERESTING) {
-			mark_blob_uninteresting(blob);
-			return NULL;
-		}
-		add_pending_object(object, "");
-		return NULL;
-	}
-	die("%s is unknown object", name);
-}
-
-static void handle_one_commit(struct commit *com, struct commit_list **lst)
-{
-	if (!com || com->object.flags & SEEN)
-		return;
-	com->object.flags |= SEEN;
-	commit_list_insert(com, lst);
-}
-
-/* for_each_ref() callback does not allow user data -- Yuck. */
-static struct commit_list **global_lst;
-
-static int include_one_commit(const char *path, const unsigned char *sha1)
-{
-	struct commit *com = get_commit_reference(path, sha1, 0);
-	handle_one_commit(com, global_lst);
-	return 0;
-}
-
-static void handle_all(struct commit_list **lst)
-{
-	global_lst = lst;
-	for_each_ref(include_one_commit);
-	global_lst = NULL;
-}
-
 int main(int argc, const char **argv)
 {
-	const char *prefix = setup_git_directory();
-	struct commit_list *list = NULL;
+	struct commit_list *list;
 	int i, limited = 0;
 
+	argc = setup_revisions(argc, argv, &revs);
+
 	for (i = 1 ; i < argc; i++) {
-		int flags;
 		const char *arg = argv[i];
-		char *dotdot;
-		struct commit *commit;
-		unsigned char sha1[20];
 
 		/* accept -<digit>, like traditilnal "head" */
 		if ((*arg == '-') && isdigit(arg[1])) {
-			max_count = atoi(arg + 1);
+			revs.max_count = atoi(arg + 1);
 			continue;
 		}
 		if (!strcmp(arg, "-n")) {
 			if (++i >= argc)
 				die("-n requires an argument");
-			max_count = atoi(argv[i]);
+			revs.max_count = atoi(argv[i]);
 			continue;
 		}
 		if (!strncmp(arg,"-n",2)) {
-			max_count = atoi(arg + 2);
-			continue;
-		}
-		if (!strncmp(arg, "--max-count=", 12)) {
-			max_count = atoi(arg + 12);
-			continue;
-		}
-		if (!strncmp(arg, "--max-age=", 10)) {
-			max_age = atoi(arg + 10);
-			limited = 1;
-			continue;
-		}
-		if (!strncmp(arg, "--min-age=", 10)) {
-			min_age = atoi(arg + 10);
-			limited = 1;
+			revs.max_count = atoi(arg + 2);
 			continue;
 		}
 		if (!strcmp(arg, "--header")) {
@@ -893,23 +657,6 @@ int main(int argc, const char **argv)
 			bisect_list = 1;
 			continue;
 		}
-		if (!strcmp(arg, "--all")) {
-			handle_all(&list);
-			continue;
-		}
-		if (!strcmp(arg, "--objects")) {
-			tag_objects = 1;
-			tree_objects = 1;
-			blob_objects = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--objects-edge")) {
-			tag_objects = 1;
-			tree_objects = 1;
-			blob_objects = 1;
-			edge_hint = 1;
-			continue;
-		}
 		if (!strcmp(arg, "--unpacked")) {
 			unpacked = 1;
 			limited = 1;
@@ -923,100 +670,42 @@ int main(int argc, const char **argv)
 			show_breaks = 1;
 			continue;
 		}
-		if (!strcmp(arg, "--topo-order")) {
-		        topo_order = 1;
-			lifo = 1;
-		        limited = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--date-order")) {
-		        topo_order = 1;
-			lifo = 0;
-		        limited = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--dense")) {
-			dense = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--sparse")) {
-			dense = 0;
-			continue;
-		}
-		if (!strcmp(arg, "--remove-empty")) {
-			remove_empty_trees = 1;
-			continue;
-		}
-		if (!strcmp(arg, "--")) {
-			i++;
-			break;
-		}
-
-		if (show_breaks && !merge_order)
-			usage(rev_list_usage);
+		usage(rev_list_usage);
 
-		flags = 0;
-		dotdot = strstr(arg, "..");
-		if (dotdot) {
-			unsigned char from_sha1[20];
-			char *next = dotdot + 2;
-			*dotdot = 0;
-			if (!*next)
-				next = "HEAD";
-			if (!get_sha1(arg, from_sha1) && !get_sha1(next, sha1)) {
-				struct commit *exclude;
-				struct commit *include;
-				
-				exclude = get_commit_reference(arg, from_sha1, UNINTERESTING);
-				include = get_commit_reference(next, sha1, 0);
-				if (!exclude || !include)
-					die("Invalid revision range %s..%s", arg, next);
-				limited = 1;
-				handle_one_commit(exclude, &list);
-				handle_one_commit(include, &list);
-				continue;
-			}
-			*dotdot = '.';
-		}
-		if (*arg == '^') {
-			flags = UNINTERESTING;
-			arg++;
-			limited = 1;
-		}
-		if (get_sha1(arg, sha1) < 0) {
-			struct stat st;
-			if (lstat(arg, &st) < 0)
-				die("'%s': %s", arg, strerror(errno));
-			break;
-		}
-		commit = get_commit_reference(arg, sha1, flags);
-		handle_one_commit(commit, &list);
 	}
 
+	list = revs.commits;
+	if (list && list->next)
+		limited = 1;
+
+	if (revs.topo_order)
+		limited = 1;
+
 	if (!list &&
-	    (!(tag_objects||tree_objects||blob_objects) && !pending_objects))
+	    (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending_objects))
 		usage(rev_list_usage);
 
-	paths = get_pathspec(prefix, argv + i);
-	if (paths) {
+	if (revs.paths) {
 		limited = 1;
-		diff_tree_setup_paths(paths);
+		diff_tree_setup_paths(revs.paths);
 	}
+	if (revs.max_age || revs.min_age)
+		limited = 1;
 
 	save_commit_buffer = verbose_header;
 	track_object_refs = 0;
 
 	if (!merge_order) {		
 		sort_by_date(&list);
-		if (list && !limited && max_count == 1 &&
-		    !tag_objects && !tree_objects && !blob_objects) {
+		if (list && !limited && revs.max_count == 1 &&
+		    !revs.tag_objects && !revs.tree_objects && !revs.blob_objects) {
 			show_commit(list->item);
 			return 0;
 		}
 	        if (limited)
 			list = limit_list(list);
-		if (topo_order)
-			sort_in_topological_order(&list, lifo);
+		if (revs.topo_order)
+			sort_in_topological_order(&list, revs.lifo);
 		show_commit_list(list);
 	} else {
 #ifndef NO_OPENSSL
diff --git a/revision.c b/revision.c
new file mode 100644
index 0000000..17dbf9a
--- /dev/null
+++ b/revision.c
@@ -0,0 +1,370 @@
+#include "cache.h"
+#include "tag.h"
+#include "blob.h"
+#include "tree.h"
+#include "commit.h"
+#include "refs.h"
+#include "revision.h"
+
+static char *path_name(struct name_path *path, const char *name)
+{
+	struct name_path *p;
+	char *n, *m;
+	int nlen = strlen(name);
+	int len = nlen + 1;
+
+	for (p = path; p; p = p->up) {
+		if (p->elem_len)
+			len += p->elem_len + 1;
+	}
+	n = xmalloc(len);
+	m = n + len - (nlen + 1);
+	strcpy(m, name);
+	for (p = path; p; p = p->up) {
+		if (p->elem_len) {
+			m -= p->elem_len + 1;
+			memcpy(m, p->elem, p->elem_len);
+			m[p->elem_len] = '/';
+		}
+	}
+	return n;
+}
+
+struct object_list **add_object(struct object *obj,
+				       struct object_list **p,
+				       struct name_path *path,
+				       const char *name)
+{
+	struct object_list *entry = xmalloc(sizeof(*entry));
+	entry->item = obj;
+	entry->next = *p;
+	entry->name = path_name(path, name);
+	*p = entry;
+	return &entry->next;
+}
+
+static void mark_blob_uninteresting(struct blob *blob)
+{
+	if (blob->object.flags & UNINTERESTING)
+		return;
+	blob->object.flags |= UNINTERESTING;
+}
+
+void mark_tree_uninteresting(struct tree *tree)
+{
+	struct object *obj = &tree->object;
+	struct tree_entry_list *entry;
+
+	if (obj->flags & UNINTERESTING)
+		return;
+	obj->flags |= UNINTERESTING;
+	if (!has_sha1_file(obj->sha1))
+		return;
+	if (parse_tree(tree) < 0)
+		die("bad tree %s", sha1_to_hex(obj->sha1));
+	entry = tree->entries;
+	tree->entries = NULL;
+	while (entry) {
+		struct tree_entry_list *next = entry->next;
+		if (entry->directory)
+			mark_tree_uninteresting(entry->item.tree);
+		else
+			mark_blob_uninteresting(entry->item.blob);
+		free(entry);
+		entry = next;
+	}
+}
+
+void mark_parents_uninteresting(struct commit *commit)
+{
+	struct commit_list *parents = commit->parents;
+
+	while (parents) {
+		struct commit *commit = parents->item;
+		commit->object.flags |= UNINTERESTING;
+
+		/*
+		 * Normally we haven't parsed the parent
+		 * yet, so we won't have a parent of a parent
+		 * here. However, it may turn out that we've
+		 * reached this commit some other way (where it
+		 * wasn't uninteresting), in which case we need
+		 * to mark its parents recursively too..
+		 */
+		if (commit->parents)
+			mark_parents_uninteresting(commit);
+
+		/*
+		 * A missing commit is ok iff its parent is marked 
+		 * uninteresting.
+		 *
+		 * We just mark such a thing parsed, so that when
+		 * it is popped next time around, we won't be trying
+		 * to parse it and get an error.
+		 */
+		if (!has_sha1_file(commit->object.sha1))
+			commit->object.parsed = 1;
+		parents = parents->next;
+	}
+}
+
+static void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)
+{
+	add_object(obj, &revs->pending_objects, NULL, name);
+}
+
+static struct commit *get_commit_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
+{
+	struct object *object;
+
+	object = parse_object(sha1);
+	if (!object)
+		die("bad object %s", name);
+
+	/*
+	 * Tag object? Look what it points to..
+	 */
+	while (object->type == tag_type) {
+		struct tag *tag = (struct tag *) object;
+		object->flags |= flags;
+		if (revs->tag_objects && !(object->flags & UNINTERESTING))
+			add_pending_object(revs, object, tag->tag);
+		object = parse_object(tag->tagged->sha1);
+		if (!object)
+			die("bad object %s", sha1_to_hex(tag->tagged->sha1));
+	}
+
+	/*
+	 * Commit object? Just return it, we'll do all the complex
+	 * reachability crud.
+	 */
+	if (object->type == commit_type) {
+		struct commit *commit = (struct commit *)object;
+		object->flags |= flags;
+		if (parse_commit(commit) < 0)
+			die("unable to parse commit %s", name);
+		if (flags & UNINTERESTING)
+			mark_parents_uninteresting(commit);
+		return commit;
+	}
+
+	/*
+	 * Tree object? Either mark it uniniteresting, or add it
+	 * to the list of objects to look at later..
+	 */
+	if (object->type == tree_type) {
+		struct tree *tree = (struct tree *)object;
+		if (!revs->tree_objects)
+			return NULL;
+		if (flags & UNINTERESTING) {
+			mark_tree_uninteresting(tree);
+			return NULL;
+		}
+		add_pending_object(revs, object, "");
+		return NULL;
+	}
+
+	/*
+	 * Blob object? You know the drill by now..
+	 */
+	if (object->type == blob_type) {
+		struct blob *blob = (struct blob *)object;
+		if (!revs->blob_objects)
+			return NULL;
+		if (flags & UNINTERESTING) {
+			mark_blob_uninteresting(blob);
+			return NULL;
+		}
+		add_pending_object(revs, object, "");
+		return NULL;
+	}
+	die("%s is unknown object", name);
+}
+
+static void add_one_commit(struct commit *commit, struct rev_info *revs)
+{
+	if (!commit || (commit->object.flags & SEEN))
+		return;
+	commit->object.flags |= SEEN;
+	commit_list_insert(commit, &revs->commits);
+}
+
+static int all_flags;
+static struct rev_info *all_revs;
+
+static int handle_one_ref(const char *path, const unsigned char *sha1)
+{
+	struct commit *commit = get_commit_reference(all_revs, path, sha1, all_flags);
+	add_one_commit(commit, all_revs);
+	return 0;
+}
+
+static void handle_all(struct rev_info *revs, unsigned flags)
+{
+	all_revs = revs;
+	all_flags = flags;
+	for_each_ref(handle_one_ref);
+}
+
+/*
+ * Parse revision information, filling in the "rev_info" structure,
+ * and removing the used arguments from the argument list.
+ *
+ * Returns the number of arguments left ("new argc").
+ */
+int setup_revisions(int argc, const char **argv, struct rev_info *revs)
+{
+	int i, flags, seen_dashdash;
+	const char *def = NULL;
+	const char **unrecognized = argv+1;
+	int left = 1;
+
+	memset(revs, 0, sizeof(*revs));
+	revs->lifo = 1;
+	revs->dense = 1;
+	revs->prefix = setup_git_directory();
+	revs->max_age = -1;
+	revs->min_age = -1;
+	revs->max_count = -1;
+
+	/* First, search for "--" */
+	seen_dashdash = 0;
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		if (strcmp(arg, "--"))
+			continue;
+		argv[i] = NULL;
+		argc = i;
+		revs->paths = get_pathspec(revs->prefix, argv + i + 1);
+		seen_dashdash = 1;
+		break;
+	}
+
+	flags = 0;
+	for (i = 1; i < argc; i++) {
+		struct commit *commit;
+		const char *arg = argv[i];
+		unsigned char sha1[20];
+		char *dotdot;
+		int local_flags;
+
+		if (*arg == '-') {
+			if (!strncmp(arg, "--max-count=", 12)) {
+				revs->max_count = atoi(arg + 12);
+				continue;
+			}
+			if (!strncmp(arg, "--max-age=", 10)) {
+				revs->max_age = atoi(arg + 10);
+				continue;
+			}
+			if (!strncmp(arg, "--min-age=", 10)) {
+				revs->min_age = atoi(arg + 10);
+				continue;
+			}
+			if (!strcmp(arg, "--all")) {
+				handle_all(revs, flags);
+				continue;
+			}
+			if (!strcmp(arg, "--not")) {
+				flags ^= UNINTERESTING;
+				continue;
+			}
+			if (!strcmp(arg, "--default")) {
+				if (++i >= argc)
+					die("bad --default argument");
+				def = argv[i];
+				continue;
+			}
+			if (!strcmp(arg, "--topo-order")) {
+				revs->topo_order = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--date-order")) {
+				revs->lifo = 0;
+				revs->topo_order = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--dense")) {
+				revs->dense = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--sparse")) {
+				revs->dense = 0;
+				continue;
+			}
+			if (!strcmp(arg, "--remove-empty")) {
+				revs->remove_empty_trees = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--objects")) {
+				revs->tag_objects = 1;
+				revs->tree_objects = 1;
+				revs->blob_objects = 1;
+				continue;
+			}
+			if (!strcmp(arg, "--objects-edge")) {
+				revs->tag_objects = 1;
+				revs->tree_objects = 1;
+				revs->blob_objects = 1;
+				revs->edge_hint = 1;
+				continue;
+			}
+			*unrecognized++ = arg;
+			left++;
+			continue;
+		}
+		dotdot = strstr(arg, "..");
+		if (dotdot) {
+			unsigned char from_sha1[20];
+			char *next = dotdot + 2;
+			*dotdot = 0;
+			if (!*next)
+				next = "HEAD";
+			if (!get_sha1(arg, from_sha1) && !get_sha1(next, sha1)) {
+				struct commit *exclude;
+				struct commit *include;
+
+				exclude = get_commit_reference(revs, arg, from_sha1, flags ^ UNINTERESTING);
+				include = get_commit_reference(revs, next, sha1, flags);
+				if (!exclude || !include)
+					die("Invalid revision range %s..%s", arg, next);
+				add_one_commit(exclude, revs);
+				add_one_commit(include, revs);
+				continue;
+			}
+			*dotdot = '.';
+		}
+		local_flags = 0;
+		if (*arg == '^') {
+			local_flags = UNINTERESTING;
+			arg++;
+		}
+		if (get_sha1(arg, sha1) < 0) {
+			struct stat st;
+			int j;
+
+			if (seen_dashdash || local_flags)
+				die("bad revision '%s'", arg);
+
+			/* If we didn't have a "--", all filenames must exist */
+			for (j = i; j < argc; j++) {
+				if (lstat(argv[j], &st) < 0)
+					die("'%s': %s", arg, strerror(errno));
+			}
+			revs->paths = get_pathspec(revs->prefix, argv + i);
+			break;
+		}
+		commit = get_commit_reference(revs, arg, sha1, flags ^ local_flags);
+		add_one_commit(commit, revs);
+	}
+	if (def && !revs->commits) {
+		unsigned char sha1[20];
+		struct commit *commit;
+		if (get_sha1(def, sha1) < 0)
+			die("bad default revision '%s'", def);
+		commit = get_commit_reference(revs, def, sha1, 0);
+		add_one_commit(commit, revs);
+	}
+	*unrecognized = NULL;
+	return left;
+}
diff --git a/revision.h b/revision.h
new file mode 100644
index 0000000..5170ac4
--- /dev/null
+++ b/revision.h
@@ -0,0 +1,48 @@
+#ifndef REVISION_H
+#define REVISION_H
+
+#define SEEN		(1u<<0)
+#define UNINTERESTING   (1u<<1)
+
+struct rev_info {
+	/* Starting list */
+	struct commit_list *commits;
+	struct object_list *pending_objects;
+
+	/* Basic information */
+	const char *prefix;
+	const char **paths;
+
+	/* Traversal flags */
+	unsigned int	dense:1,
+			remove_empty_trees:1,
+			lifo:1,
+			topo_order:1,
+			tag_objects:1,
+			tree_objects:1,
+			blob_objects:1,
+			edge_hint:1;
+
+	/* special limits */
+	int max_count;
+	unsigned long max_age;
+	unsigned long min_age;
+};
+
+/* revision.c */
+extern int setup_revisions(int argc, const char **argv, struct rev_info *revs);
+extern void mark_parents_uninteresting(struct commit *commit);
+extern void mark_tree_uninteresting(struct tree *tree);
+
+struct name_path {
+	struct name_path *up;
+	int elem_len;
+	const char *elem;
+};
+
+extern struct object_list **add_object(struct object *obj,
+				       struct object_list **p,
+				       struct name_path *path,
+				       const char *name);
+
+#endif

^ permalink raw reply related	[relevance 1%]

* Re: Solaris cloning woes partly diagnosed
  @ 2006-04-02 18:33  4% ` Linus Torvalds
  2006-04-02 19:18  1%   ` Linus Torvalds
  2006-04-04 18:21  1%   ` H. Peter Anvin
  0 siblings, 2 replies; 200+ results
From: Linus Torvalds @ 2006-04-02 18:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git



On Sun, 2 Apr 2006, Junio C Hamano wrote:
>
> We do two funky things when we have progress bar.  We play games
> with timer signal (setitimer(ITIMER_REAL) and signal(SIGALRM)),
> and we spit out messages to stderr.

I'd be willing to bet that it's the fact that we take signals.

Suddenly, some system calls will either return -1/EINTR, or they'll return 
partial reads or writes. 

We should be pretty good at handling that, but maybe some place forgets.

One thing to do might be to make the itimer use a much higher frequency, 
to trigger the problem more easily.

We do, for example, expect that regular file writing not do that. At least 
"write_sha1_from_fd()" will just do a "write()" without testing the error 
return, which is bad (it would silently create a truncated object if the 
/tmp filesystem filled up). If somebody has their filesystem over NFS 
mounted interruptible, partial writes could also happen.

Ho humm.

		Linus

^ permalink raw reply	[relevance 4%]

* Re: Solaris cloning woes partly diagnosed
  2006-04-02 18:33  4% ` Linus Torvalds
@ 2006-04-02 19:18  1%   ` Linus Torvalds
  2006-04-04 18:21  1%   ` H. Peter Anvin
  1 sibling, 0 replies; 200+ results
From: Linus Torvalds @ 2006-04-02 19:18 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git



On Sun, 2 Apr 2006, Linus Torvalds wrote:
> 
> Suddenly, some system calls will either return -1/EINTR, or they'll return 
> partial reads or writes. 

Hmm. If I read the IRC logs right, the bad pack is still a _valid_ pack, 
and passes git-verify-pack with flying colors.

That certainly implies that we had no problems with write-out: not only 
must the SHA1 of the resulting file match itself, but it must match the 
index too, and the number of objects there must match the index.

So the only way I see the pack being bad (if it does indeed pass 
git-verify-pack) is if the object list we generated was bad.

However, "-q" only affects git-pack-file itself, not the generation of the 
list. Which would imply that we have trouble _reading_ the list as it 
comes in through a pipe. Which is just insane, because we use just a 
bog-standard "fgets(... stdin)" for that. And no _way_ can stdio have 
problems with a few SIGALRM's, that would break a lot of other problems.

But Oeje1 seems to be saying (in http://pastebin.com/635566):

	git rev-list --objects --all | git pack-objects pack
	Generating pack...
	Done counting 15 objects.
	Deltifying 15 objects.
	 100% (15/15) done
	Writing 15 objects.
	 100% (15/15) done
	806439fdfa5e9990b03f9301bd68e243795fff50

where the result _should_ be 16385 objects, not 15.

And the thing is, the _only_ thing we do there is that

	while (fgets(line, sizeof(line), stdin) != NULL) {
		...
		add_object_entry(sha1, name_hash(NULL, line+41), 0);

so it really really looks like fgets() would have problems with a SIGALRM 
coming in and doesn't just re-try on EINTR. Can Solaris stdio _really_ be 
that broken? (Yeah, yeah, it may be "conforming". It's also so incredibly 
programmer-unfriendly that it's not even funny)

That would be truly insane. Can somebody with Solaris check what the 
following patch results in...

		Linus

----
diff --git a/pack-objects.c b/pack-objects.c
index ccfaa5f..daba5de 100644
--- a/pack-objects.c
+++ b/pack-objects.c
@@ -1099,8 +1099,18 @@ int main(int argc, char **argv)
 		fprintf(stderr, "Generating pack...\n");
 	}
 
-	while (fgets(line, sizeof(line), stdin) != NULL) {
+	for (;;) {
 		unsigned char sha1[20];
+
+		if (!fgets(line, sizeof(line), stdin)) {
+			if (feof(stdin))
+				break;
+			if (!ferror(stdin))
+				die("fgets returned NULL, not EOF, not error!");
+			if (errno == EINTR)
+				continue;
+			die("fgets: %s", strerror(errno));
+		}
 
 		if (line[0] == '-') {
 			if (get_sha1_hex(line+1, sha1))

^ permalink raw reply related	[relevance 1%]

* Re: Solaris cloning woes partly diagnosed
  @ 2006-04-02 19:22  4% ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2006-04-02 19:22 UTC (permalink / raw)
  To: Jason Riedy; +Cc: git



On Sun, 2 Apr 2006, Jason Riedy wrote:

> And Linus Torvalds writes:
>  - 
>  - I'd be willing to bet that it's the fact that we take signals.
> 
> Unfortunately, I'm too busy to check into this, but I've
> run into similar problems in the past.  Just takes a busy 
> file server.
> 
>  - We do, for example, expect that regular file writing not do that. At least 
>  - "write_sha1_from_fd()" will just do a "write()" without testing the error 
>  - return, [...]
> 
> There is an xwrite in git-compat-util.h...

Well, git itself is actually fairly good about these things. Right now I'm 
seriously suspecting Solaris stdio as being just horribly impolite.

git tends to not just use xwrite() in most places, but check the return 
value for partial sizes etc. I tried to grep for places where we were 
lazy, and there really seems to be just a very small handful, and they 
shouldn't impact this case at all (you have to have a seriously broken 
setup for them to matter, but we should fix them nonetheless.

		Linus

^ permalink raw reply	[relevance 4%]

* Re: Solaris cloning woes partly diagnosed
  2006-04-02 18:33  4% ` Linus Torvalds
  2006-04-02 19:18  1%   ` Linus Torvalds
@ 2006-04-04 18:21  1%   ` H. Peter Anvin
  1 sibling, 0 replies; 200+ results
From: H. Peter Anvin @ 2006-04-04 18:21 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Junio C Hamano, git

Linus Torvalds wrote:
> 
> One thing to do might be to make the itimer use a much higher frequency, 
> to trigger the problem more easily.
> 
> We do, for example, expect that regular file writing not do that. At least 
> "write_sha1_from_fd()" will just do a "write()" without testing the error 
> return, which is bad (it would silently create a truncated object if the 
> /tmp filesystem filled up). If somebody has their filesystem over NFS 
> mounted interruptible, partial writes could also happen.
> 

There seems to be a whole bunch of places where we use naked write()s 
where xwrite or fwrite would be a lot more appropriate.  The ssh-* files 
seem to be particularly offensive in that way.

There are also a number of places which call xwrite with the apparent 
belief that returning short is an error (e.g. blame.c).  This as far as 
I know the more common definition of xwrite(), but is *not* the one used 
in git -- the one in git only guarantees that at least one character is 
written.

	-hpa

^ permalink raw reply	[relevance 1%]

* [PATCH] Shell utilities: Guard against expr' magic tokens.
@ 2006-04-13 22:01  6% Mark Wooding
  0 siblings, 0 replies; 200+ results
From: Mark Wooding @ 2006-04-13 22:01 UTC (permalink / raw)
  To: git

From: Mark Wooding <mdw@distorted.org.uk>

Some words, e.g., `match', are special to expr(1), and cause strange
parsing effects.  Track down all uses of expr and mangle the arguments
so that this isn't a problem.

Signed-off-by: Mark Wooding <mdw@distorted.org.uk>
---
Amusing one, this.  I hacked on one of my projects, messing with a
simple glob matching function.  Being uncreative, I called my topic
branch `match'.  When I was ready, I switched back to my master branch
and said

  $ git pull . match
  Already up-to-date.

Oh.  I checked.  Nope, not up-to-date.  I tried 

  $ git merge fast HEAD match, and that

and that did the right thing.  But I was puzzled.  I fired up the
git-bisect machinery and tried to find a good version to no avail.  And
then, comparing `sh -x' traces of git-fetch, I noticed what had gone
wrong.

There's a line in git-parse-remote.sh, in canon_refs_list_for_fetch,
which says

  expr "$ref" : '.*:' >/dev/null || ref="${ref}:"

In my case, $ref is `match', so this expands to

  expr match : '.*:' >...

Unfortunately, GNU expr has a magic keyword `match'.  So what this does
is compare `:' to the regexp `.*:', which /succeeds/, even though POSIX
expr without the `match' keyword would do the right thing and fail.  So
$ref never has a `:' appended, which makes the later parsing fail, and
all sorts of strange things happen.

This patch puts magical extra characters in expr regexp calls
throughout the shell bits of GIT, to robustify them against this kind of
crapness.

There's a small chance I got something wrong while making this fix.  I
was fairly careful, though, and ran the test suite without any
problems.  I also checked Cogito, though that has no truck with expr.

---

 git-cherry.sh         |    2 +-
 git-clone.sh          |    6 +++---
 git-commit.sh         |    4 ++--
 git-fetch.sh          |   18 +++++++++---------
 git-format-patch.sh   |    4 ++--
 git-merge-one-file.sh |    2 +-
 git-parse-remote.sh   |   20 ++++++++++----------
 git-rebase.sh         |    2 +-
 git-tag.sh            |    2 +-
 9 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/git-cherry.sh b/git-cherry.sh
index 1a62320..f0e8831 100755
--- a/git-cherry.sh
+++ b/git-cherry.sh
@@ -20,7 +20,7 @@ case "$1" in -v) verbose=t; shift ;; esa
 
 case "$#,$1" in
 1,*..*)
-    upstream=$(expr "$1" : '\(.*\)\.\.') ours=$(expr "$1" : '.*\.\.\(.*\)$')
+    upstream=$(expr "z$1" : 'z\(.*\)\.\.') ours=$(expr "z$1" : '.*\.\.\(.*\)$')
     set x "$upstream" "$ours"
     shift ;;
 esac
diff --git a/git-clone.sh b/git-clone.sh
index c013e48..0805168 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -38,12 +38,12 @@ Perhaps git-update-server-info needs to 
 	}
 	while read sha1 refname
 	do
-		name=`expr "$refname" : 'refs/\(.*\)'` &&
+		name=`expr "z$refname" : 'zrefs/\(.*\)'` &&
 		case "$name" in
 		*^*)	continue;;
 		esac
 		if test -n "$use_separate_remote" &&
-		   branch_name=`expr "$name" : 'heads/\(.*\)'`
+		   branch_name=`expr "z$name" : 'zheads/\(.*\)'`
 		then
 			tname="remotes/$origin/$branch_name"
 		else
@@ -346,7 +346,7 @@ then
 		# new style repository with a symref HEAD).
 		# Ideally we should skip the guesswork but for now
 		# opt for minimum change.
-		head_sha1=`expr "$head_sha1" : 'ref: refs/heads/\(.*\)'`
+		head_sha1=`expr "z$head_sha1" : 'zref: refs/heads/\(.*\)'`
 		head_sha1=`cat "$GIT_DIR/$remote_top/$head_sha1"`
 		;;
 	esac
diff --git a/git-commit.sh b/git-commit.sh
index bd3dc71..01c73bd 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -549,8 +549,8 @@ fi >>"$GIT_DIR"/COMMIT_EDITMSG
 # Author
 if test '' != "$force_author"
 then
-	GIT_AUTHOR_NAME=`expr "$force_author" : '\(.*[^ ]\) *<.*'` &&
-	GIT_AUTHOR_EMAIL=`expr "$force_author" : '.*\(<.*\)'` &&
+	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
+	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
 	test '' != "$GIT_AUTHOR_NAME" &&
 	test '' != "$GIT_AUTHOR_EMAIL" ||
 	die "malformatted --author parameter"
diff --git a/git-fetch.sh b/git-fetch.sh
index 954901d..711650f 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -112,7 +112,7 @@ append_fetch_head () {
     *)
 	note_="$remote_name of " ;;
     esac
-    remote_1_=$(expr "$remote_" : '\(.*\)\.git/*$') &&
+    remote_1_=$(expr "z$remote_" : 'z\(.*\)\.git/*$') &&
 	remote_="$remote_1_"
     note_="$note_$remote_"
 
@@ -245,22 +245,22 @@ fetch_main () {
 
       # These are relative path from $GIT_DIR, typically starting at refs/
       # but may be HEAD
-      if expr "$ref" : '\.' >/dev/null
+      if expr "z$ref" : 'z\.' >/dev/null
       then
 	  not_for_merge=t
-	  ref=$(expr "$ref" : '\.\(.*\)')
+	  ref=$(expr "z$ref" : 'z\.\(.*\)')
       else
 	  not_for_merge=
       fi
-      if expr "$ref" : '\+' >/dev/null
+      if expr "z$ref" : 'z\+' >/dev/null
       then
 	  single_force=t
-	  ref=$(expr "$ref" : '\+\(.*\)')
+	  ref=$(expr "z$ref" : 'z\+\(.*\)')
       else
 	  single_force=
       fi
-      remote_name=$(expr "$ref" : '\([^:]*\):')
-      local_name=$(expr "$ref" : '[^:]*:\(.*\)')
+      remote_name=$(expr "z$ref" : 'z\([^:]*\):')
+      local_name=$(expr "z$ref" : 'z[^:]*:\(.*\)')
 
       rref="$rref$LF$remote_name"
 
@@ -276,7 +276,7 @@ fetch_main () {
 	      print "$u";
 	  ' "$remote_name")
 	  head=$(curl -nsfL $curl_extra_args "$remote/$remote_name_quoted") &&
-	  expr "$head" : "$_x40\$" >/dev/null ||
+	  expr "z$head" : "z$_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
@@ -362,7 +362,7 @@ fetch_main () {
 		  break ;;
 	      esac
 	  done
-	  local_name=$(expr "$found" : '[^:]*:\(.*\)')
+	  local_name=$(expr "z$found" : 'z[^:]*:\(.*\)')
 	  append_fetch_head "$sha1" "$remote" \
 		  "$remote_name" "$remote_nick" "$local_name" "$not_for_merge"
       done
diff --git a/git-format-patch.sh b/git-format-patch.sh
index 2ebf7e8..c7133bc 100755
--- a/git-format-patch.sh
+++ b/git-format-patch.sh
@@ -126,8 +126,8 @@ for revpair
 do
 	case "$revpair" in
 	?*..?*)
-		rev1=`expr "$revpair" : '\(.*\)\.\.'`
-		rev2=`expr "$revpair" : '.*\.\.\(.*\)'`
+		rev1=`expr "z$revpair" : 'z\(.*\)\.\.'`
+		rev2=`expr "z$revpair" : 'z.*\.\.\(.*\)'`
 		;;
 	*)
 		rev1="$revpair^"
diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh
index 5349a1c..5619409 100755
--- a/git-merge-one-file.sh
+++ b/git-merge-one-file.sh
@@ -26,7 +26,7 @@ #
 	fi
 	if test -f "$4"; then
 		rm -f -- "$4" &&
-		rmdir -p "$(expr "$4" : '\(.*\)/')" 2>/dev/null || :
+		rmdir -p "$(expr "z$4" : 'z\(.*\)/')" 2>/dev/null || :
 	fi &&
 		exec git-update-index --remove -- "$4"
 	;;
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 63f2281..65c66d5 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -8,8 +8,8 @@ get_data_source () {
 	case "$1" in
 	*/*)
 		# Not so fast.	This could be the partial URL shorthand...
-		token=$(expr "$1" : '\([^/]*\)/')
-		remainder=$(expr "$1" : '[^/]*/\(.*\)')
+		token=$(expr "z$1" : 'z\([^/]*\)/')
+		remainder=$(expr "z$1" : 'z[^/]*/\(.*\)')
 		if test -f "$GIT_DIR/branches/$token"
 		then
 			echo branches-partial
@@ -43,8 +43,8 @@ get_remote_url () {
 	branches)
 		sed -e 's/#.*//' "$GIT_DIR/branches/$1" ;;
 	branches-partial)
-		token=$(expr "$1" : '\([^/]*\)/')
-		remainder=$(expr "$1" : '[^/]*/\(.*\)')
+		token=$(expr "z$1" : 'z\([^/]*\)/')
+		remainder=$(expr "z$1" : 'z[^/]*/\(.*\)')
 		url=$(sed -e 's/#.*//' "$GIT_DIR/branches/$token")
 		echo "$url/$remainder"
 		;;
@@ -77,13 +77,13 @@ canon_refs_list_for_fetch () {
 		force=
 		case "$ref" in
 		+*)
-			ref=$(expr "$ref" : '\+\(.*\)')
+			ref=$(expr "z$ref" : 'z\+\(.*\)')
 			force=+
 			;;
 		esac
-		expr "$ref" : '.*:' >/dev/null || ref="${ref}:"
-		remote=$(expr "$ref" : '\([^:]*\):')
-		local=$(expr "$ref" : '[^:]*:\(.*\)')
+		expr "z$ref" : 'z.*:' >/dev/null || ref="${ref}:"
+		remote=$(expr "z$ref" : 'z\([^:]*\):')
+		local=$(expr "z$ref" : 'z[^:]*:\(.*\)')
 		case "$remote" in
 		'') remote=HEAD ;;
 		refs/heads/* | refs/tags/* | refs/remotes/*) ;;
@@ -97,7 +97,7 @@ canon_refs_list_for_fetch () {
 		*) local="refs/heads/$local" ;;
 		esac
 
-		if local_ref_name=$(expr "$local" : 'refs/\(.*\)')
+		if local_ref_name=$(expr "z$local" : 'zrefs/\(.*\)')
 		then
 		   git-check-ref-format "$local_ref_name" ||
 		   die "* refusing to create funny ref '$local_ref_name' locally"
@@ -171,7 +171,7 @@ get_remote_refs_for_fetch () {
 
 resolve_alternates () {
 	# original URL (xxx.git)
-	top_=`expr "$1" : '\([^:]*:/*[^/]*\)/'`
+	top_=`expr "z$1" : 'z\([^:]*:/*[^/]*\)/'`
 	while read path
 	do
 		case "$path" in
diff --git a/git-rebase.sh b/git-rebase.sh
index 5956f06..86dfe9c 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -94,7 +94,7 @@ case "$#" in
 	;;
 *)
 	branch_name=`git symbolic-ref HEAD` || die "No current branch"
-	branch_name=`expr "$branch_name" : 'refs/heads/\(.*\)'`
+	branch_name=`expr "z$branch_name" : 'zrefs/heads/\(.*\)'`
 	;;
 esac
 branch=$(git-rev-parse --verify "${branch_name}^0") || exit
diff --git a/git-tag.sh b/git-tag.sh
index 76e51ed..dc6aa95 100755
--- a/git-tag.sh
+++ b/git-tag.sh
@@ -75,7 +75,7 @@ git-check-ref-format "tags/$name" ||
 object=$(git-rev-parse --verify --default HEAD "$@") || exit 1
 type=$(git-cat-file -t $object) || exit 1
 tagger=$(git-var GIT_COMMITTER_IDENT) || exit 1
-: ${username:=$(expr "$tagger" : '\(.*>\)')}
+: ${username:=$(expr "z$tagger" : 'z\(.*>\)')}
 
 trap 'rm -f "$GIT_DIR"/TAG_TMP* "$GIT_DIR"/TAG_FINALMSG "$GIT_DIR"/TAG_EDITMSG' 0
 



-- [mdw]

^ permalink raw reply related	[relevance 6%]

* [Announce] GIT 1.3.0
@ 2006-04-18 21:55  1% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-04-18 21:55 UTC (permalink / raw)
  To: git; +Cc: linux-kernel

The latest feature release GIT 1.3.0 is available at the usual places:

	http://www.kernel.org/pub/software/scm/git/

	git-1.3.0.tar.{gz,bz2}			(tarball)
	RPMS/$arch/git-*-1.3.0-1.$arch.rpm	(RPM)


There are many fixes and enhancements all over the place, and here is
only a list of notable user-visible changes in 1.3.0 since 1.2.6:

 - git-cvsserver (Martin Langhoff).

   This allows you to make your git repo accessible from CVS clients.

 - Annotate/blame (Ryan Anderson and Fredrik Kuivinen).

   These are alternate implementations of cvs annotate
   equivalent.  One of them probably needs to be eventually
   retired, but for now they are kept while both of them
   still have room for improvements.

 - builtin diff generation is now truly built-in.  We do not
   rely on GNU diff anymore (Linus and Davide Libenzi).

   This unfortunately makes GIT_DIFF_OPTS less useful; it can
   only take -u<n> or --unified=<n> and nothing else.

 - diff family acquired --stat, --patch-with-stat and --patch-with-raw
   output formats (Johannes Schindelin, Petr Baudis).

 - git-log command now takes diff options to act as a
   replacement for git-whatchanged.

 - rename detector was simplified and got faster (Linus and me).

 - clone --use-separate-remote; a repository cloned with this
   flag will copy the upstream branch heads under .git/remotes/origin/,
   not .git/heads/.  You will get the default "master" branch
   that starts out as a copy of the upstream HEAD.

 - A lot lower start-up latency for git-log, even when limiting
   by paths (Linus).

 - "git-commit --amend" can be used to amend the tip commit of the
   current branch.

 - Human date parsing is a bit friendlier to our European friends by
   preferring dd.mm.yy format over mm.dd.yy.

 - contrib/ hierarchy.  Things that are not purely git proper
   but are "around git" are shipped with git.  Current
   piggybackers are:

   - Two Emacs interfaces (Alexandre Julliard)
   - Alternative SVN interface (Eric Wong)
   - Alternative repository viewer (Aneesh Kumar)

----------------------------------------------------------------
(Shortlog since v1.2.6)

A Large Angry SCM:
      Makefile fixups.

Alex Riesen:
      PATCH: simplify calls to git programs in git-fmt-merge-msg
      workaround fat/ntfs deficiencies for t3600-rm.sh (git-rm)

Alexandre Julliard:
      Add an Emacs interface in contrib.
      git-format-patch: Always add a blank line between headers and body.
      contrib/emacs: Add an Emacs VC backend.
      git.el: Portability fixes for XEmacs and Emacs CVS.
      git.el: Set default directory before running the status mode setup hooks.
      git.el: Automatically update .gitignore status.
      git.el: Added support for Signed-off-by.
      git.el: Added customize support for all parameters.
      ls-files: Don't require exclude files to end with a newline.
      git.el: More robust handling of subprocess errors when returning strings.
      git.el: Get the default user name and email from the repository config.
      git.el: Added a function to diff against the other heads in a merge.

Anand Kumria:
      git-svnimport: if a limit is specified, respect it

Aneesh Kumar K.V:
      Add contrib/gitview from Aneesh.
      Add a README for gitview
      gitview: typofix
      gitview: Read tag and branch information using git ls-remote
      gitview: Use monospace font to draw the branch and tag name
      gitview: Display the lines joining commit nodes clearly.
      gitview: Fix DeprecationWarning
      gitview: Bump the rev
      gitview: Code cleanup
      gitview: Fix the graph display .
      gitview: Fix the encoding related bug
      gitview: Remove trailing white space
      gitview: Some window layout changes.
      gitview: Set the default width of graph cell
      gitview: Use horizontal scroll bar in the tree view
      gitview: pass the missing argument _show_clicked_cb.

Carl Worth:
      git-rebase: Clarify usage statement and copy it into the actual documentation.
      New test to verify that when git-clone fails it cleans up the new directory.
      git-ls-files: Fix, document, and add test for --error-unmatch option.
      Add new git-rm command with documentation
      git-rm: Fix to properly handle files with spaces, tabs, newlines, etc.

Davide Libenzi:
      Clean-up trivially redundant diff.
      xdiff: post-process hunks to make them consistent.

Dennis Stosberg:
      Solaris 9 also wants our own unsetenv/setenv.
      Replace index() with strchr().

Dmitry V. Levin:
      git/Documentation: fix SYNOPSIS style bugs

Eric W. Biederman:
      Implement limited context matching in git-apply.

Eric Wong:
      Introducing contrib/git-svn.
      git-svn: fix revision order when XML::Simple is not loaded
      git-svn: ensure fetch always works chronologically.
      git-svn: remove files from the index before adding/updating
      git-svn: fix a typo in defining the --no-stop-on-copy option
      git-svn: allow --find-copies-harder and -l<num> to be passed on commit
      git-svn: Allow for more argument types for commit (from..to)
      git-svn: remove any need for the XML::Simple dependency
      git-svn: change ; to && in addremove()
      contrib/git-svn.txt: add a note about renamed/copied directory support
      git-svn: fix several corner-case and rare bugs with 'commit'
      contrib/git-svn: add Makefile, test, and associated ignores
      git-svn: 0.9.1: add --version and copyright/license (GPL v2+) information
      contrib/git-svn: add show-ignore command
      contrib/git-svn: optimize sequential commits to svn
      contrib/git-svn: version 0.10.0
      contrib/git-svn: tell the user to not modify git-svn-HEAD directly
      contrib/git-svn: correct commit example in manpage
      contrib/git-svn: use refs/remotes/git-svn instead of git-svn-HEAD
      git-branch: add -r switch to list refs/remotes/*
      contrib/git-svn: add -b/--branch switch for branch detection
      contrib/git-svn: several small bug fixes and changes
      contrib/git-svn: strip 'git-svn-id:' when commiting to SVN
      contrib/git-svn: allow --authors-file to be specified
      contrib/git-svn: cleanup option parsing
      contrib/git-svn: create a more recent master if one does not exist
      contrib/git-svn: avoid re-reading the repository uuid, it never changes
      contrib/git-svn: add --id/-i=$GIT_SVN_ID command-line switch
      contrib/git-svn: better documenting of CLI switches
      send-email: accept --no-signed-off-by-cc as the documentation states
      contrib/git-svn: fix a copied-tree bug in an overzealous assertion
      contrib/git-svn: fix svn compat and fetch args
      contrib/git-svn: remove the --no-stop-on-copy flag
      contrib/git-svn: fix a harmless warning on rebuild (with old repos)
      fetch,parse-remote,fmt-merge-msg: refs/remotes/* support
      ls-tree: add --abbrev[=<n>] option
      ls-files: add --abbrev[=<n>] option
      contrib/git-svn: allow rebuild to work on non-linear remote heads
      send-email: use built-in time() instead of /bin/date '+%s'
      send-email: Change from Mail::Sendmail to Net::SMTP
      send-email: try to order messages in email clients more correctly
      send-email: lazy-load Email::Valid and make it optional
      contrib/git-svn: stabilize memory usage for big fetches
      contrib/git-svn: force GIT_DIR to an absolute path
      contrib/git-svn: accept configuration via repo-config
      contrib/git-svn: documentation updates
      contrib/git-svn: ensure repo-config returns a value before using it
      contrib/git-svn: make sure our git-svn is up-to-date for test
      contrib/git-svn: handle array values correctly

Fernando J. Pereda:
      Allow building Git in systems without iconv

Francis Daly:
      AsciiDoc fix for tutorial
      Tweak asciidoc output to work with broken docbook-xsl
      Fix multi-paragraph list items in OPTIONS section
      Format tweaks for asciidoc.
      Tweaks to make asciidoc play nice.

Fredrik Kuivinen:
      Add git-blame, a tool for assigning blame.
      git-blame, take 2
      git-blame: Make the output human readable
      git-blame: Use the same tests for git-blame as for git-annotate
      Fix some inconsistencies in the docs
      Remove trailing dot after short description
      Nicer output from 'git'
      Make it possible to not clobber object.util in sort_in_topological_order (take 2)
      rev-lib: Make it easy to do rename tracking (take 2)
      blame: Rename detection (take 2)
      blame: Nicer output
      blame: Fix git-blame <directory>
      Makefile: Add TAGS and tags targets

Herbert Valerio Riedel:
      git-svnimport symlink support

J. Bruce Fields:
      Document git-rebase behavior on conflicts.
      Documentation: revise top of git man page

Jason Riedy:
      Fix typo in git-rebase.sh.
      Add ALL_LDFLAGS to the git target.

Jeff Muizelaar:
      cosmetics: change from 'See-Also' to 'See Also'
      documentation: add 'see also' sections to git-rm and git-add

Jim Radford:
      fix repacking with lots of tags

Johannes Schindelin:
      Fix cpio call
      Optionally support old diffs
      Support Irix
      Optionally work without python
      Fixes for ancient versions of GNU make
      avoid makefile override warning
      Really honour NO_PYTHON
      Fix "gmake -j"
      Use Ryan's git-annotate instead of jsannotate
      Warn about invalid refs
      Fix test case for some sed
      imap-send: Add missing #include for macosx
      Remove dependency on a file named "-lz"
      cvsimport: use git-update-ref when updating
      On some platforms, certain headers need to be included before regex.h
      Fix compile with expat, but an old curl version
      diff-options: add --stat (take 2)
      diff-options: add --stat (take 2)
      diff-options: add --patch-with-stat
      pager: do not fork a pager if PAGER is set to empty.

Jon Loeliger:
      Add git-show reference
      Call out the two different uses of git-branch and fix a typo.
      Document the default source of template files.
      Clarify git-rebase example commands.
      Reference git-commit-tree for env vars.
      Fix minor typo.
      Rewrite synopsis to clarify the two primary uses of git-checkout.
      Clarify and expand some hook documentation.
      Removed bogus "<snap>" identifier.
      Added Packing Heursitics IRC writeup.

Jonas Fonseca:
      manpages: insert two missing [verse] markers for multi-line SYNOPSIS
      repo-config: give value_ a sane default so regexec won't segfault
      Add git-annotate(1) and git-blame(1)

Josef Weidendorfer:
      git-mv: fix moves into a subdir from outside

Junio C Hamano:
      "Assume unchanged" git
      "Assume unchanged" git: do not set CE_VALID with --refresh
      ls-files: debugging aid for CE_VALID changes.
      "Assume unchanged" git: --really-refresh fix.
      ls-files: split "show-valid-bit" into a different option.
      "assume unchanged" git: documentation.
      cache_name_compare() compares name and stage, nothing else.
      git-commit: Now --only semantics is the default.
      rebase: allow a hook to refuse rebasing.
      commit: detect misspelled pathspec while making a partial commit.
      rebase: allow rebasing onto different base.
      ls-files --error-unmatch pathspec error reporting fix.
      Detect misspelled pathspec to git-add
      packed objects: minor cleanup
      topo-order: make --date-order optional.
      pack-objects: reuse data from existing packs.
      pack-objects: finishing touches.
      git-repack: allow passing a couple of flags to pack-objects.
      git-tag: -l to list tags (usability).
      Add contrib/README.
      SubmittingPatches: note on whitespaces
      pack-objects: avoid delta chains that are too long.
      Make "empty ident" error message a bit more helpful.
      Delay "empty ident" errors until they really matter.
      Keep Porcelainish from failing by broken ident after making changes.
      fmt-merge-msg: say which branch things were merged into unless 'master'
      Allow git-mv to accept ./ in paths.
      Documentation: fix typo in rev-parse --short option description.
      fmt-merge-msg: do not add excess newline at the end.
      rev-list --objects-edge
      Thin pack - create packfile with missing delta base.
      send-pack --thin: use "thin pack" delta transfer.
      Add git-push --thin.
      Use thin pack transfer in "git fetch".
      fmt-merge-msg: avoid open "-|" list form for Perl 5.6
      rerere: avoid open "-|" list form for Perl 5.6
      send-email: avoid open "-|" list form for Perl 5.6
      svnimport: avoid open "-|" list form for Perl 5.6
      cvsimport: avoid open "-|" list form for Perl 5.6
      Fix fmt-merge-msg counting.
      cherry-pick/revert: error-help message rewording.
      git-mktree: reverse of git-ls-tree.
      rev-list.c: fix non-grammatical comments.
      send-pack: do not give up when remote has insanely large number of refs.
      gitview: ls-remote invocation shellquote safety.
      pack-objects: thin pack micro-optimization.
      pack-objects: use full pathname to help hashing with "thin" pack.
      count-delta: tweak counting of copied source material.
      count-delta: fix counting of copied source.
      Tweak break/merge score to adjust to the new delta generation code.
      pack-objects: allow "thin" packs to exceed depth limits
      rev-list --objects-edge: remove duplicated edge commit output.
      rev-list --objects: use full pathname to help hashing.
      pack-objects: hash basename and direname a bit differently.
      Revert "diff-delta: produce optimal pack data"
      Build and install git-mailinfo.
      rev-list split: minimum fixup.
      apply --whitespace fixes and enhancements.
      apply: squelch excessive errors and --whitespace=error-all
      apply --whitespace: configuration option.
      git-apply --whitespace=nowarn
      Revert "Revert "diff-delta: produce optimal pack data""
      git-apply: war on whitespace -- finishing touches.
      diffcore-break: micro-optimize by avoiding delta between identical files.
      diffcore-rename: split out the delta counting code.
      diffcore-delta: stop using deltifier for packing.
      git-am: --whitespace=x option.
      diff-delta: cull collided hash bucket more aggressively.
      git-log (internal): add approxidate.
      git-log (internal): more options.
      Pretty-print tagger dates.
      war on whitespaces: documentation.
      Documentation: read-tree --aggressive
      Documentation: rev-list --objects-edge
      annotate: resurrect raw timestamps.
      setup_revisions(): handle -n<n> and -<n> internally.
      GIT-VERSION-GEN: squelch unneeded error from "cat version"
      show-branch --topics
      git-commit --amend
      git-commit: make sure we protect against races.
      diffcore-rename: similarity estimator fix.
      show-branch --topics: omit more uninteresting commits.
      count-delta: no need for this anymore.
      diffcore-break: similarity estimator fix.
      diffcore-delta: make change counter to byte oriented again.
      git-commit --amend: allow empty commit.
      Const tightening.
      verify-pack -v: show delta-chain histogram.
      blame: avoid -lm by not using log().
      blame and annotate: show localtime with timezone.
      blame: avoid "diff -u0".
      annotate/blame tests updates.
      annotate-blame test: don't "source", but say "."
      annotate-blame test: add evil merge.
      blame: unbreak "diff -U 0".
      annotate-blame: tests incomplete lines.
      pack-objects: simplify "thin" pack.
      Use #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
      refs.c::do_for_each_ref(): Finish error message lines with "\n"
      fsck-objects: Remove --standalone
      Fix t1200 test for breakage caused by removal of full-stop at the end of fast-forward message.
      try_to_simplify_commit(): do not skip inspecting tree change at boundary.
      repack: prune loose objects when -d is given
      git-diff: -p disables rename detection.
      diffcore-rename: somewhat optimized.
      revision traversal: --remove-empty fix.
      revision traversal: --remove-empty fix (take #2).
      diffcore-delta: make the hash a bit denser.
      diffcore-delta: tweak hashbase value.
      cvsimport: honor -i and non -i upon subsequent imports
      fetch: exit non-zero when fast-forward check fails.
      cvsimport: fix reading from rev-parse
      git-pull: run repo-config with dash form.
      unpack_delta_entry(): reduce memory footprint.
      generate-cmdlist: style cleanups.
      revamp git-clone.
      git-merge knows some strategies want to skip trivial merges
      http-fetch: nicer warning for a server with unreliable 404 status
      core.warnambiguousrefs: warns when "name" is used and both "name" branch and tag exists.
      revamp git-clone (take #2).
      get_sha1_basic(): try refs/... and finally refs/remotes/$foo/HEAD
      clone: record the remote primary branch with remotes/$origin/HEAD
      http-push.c: squelch C90 warnings.
      git-apply: do not barf when updating an originally empty file.
      rev-list --timestamp
      git-clone: typofix.
      git-pull: further safety while on tracking branch.
      git-pull: reword "impossible to fast-forward" message.
      sha1_name: warning ambiguous refs.
      sha1_name: make core.warnambiguousrefs the default.
      send-email: Identify author at the top when sending e-mail
      commit-tree: check return value from write_sha1_file()
      built-in diff: minimum tweaks
      true built-in diff: run everything in-core.
      git-push: make --thin pack transfer the default.
      add clean and ignore rules for xdiff/
      GIT 1.3.0 rc1
      rev-list --no-merges: argument parsing fix.
      rev-list: memory usage reduction.
      rev-list --boundary
      revision arguments: ..B means HEAD..B, just like A.. means A..HEAD
      revision.c "..B" syntax: constness fix
      assume unchanged git: diff-index fix.
      tree/diff header cleanup.
      rev-list --boundary: fix re-injecting boundary commits.
      Makefile: many programs now depend on xdiff/lib.a having been built.
      revision: --topo-order and --unpacked
      revision: simplify argument parsing.
      revision: --max-age alone does not need limit_list() anymore.
      git-clone: fix handling of upsteram whose HEAD does not point at master.
      GIT 1.3.0-rc2
      combine-diff: use built-in xdiff.
      combine-diff: refactor built-in xdiff interface.
      combine-diff: move the code to parse hunk-header into common library.
      blame: use built-in xdiff
      date parsing: be friendlier to our European friends.
      blame.c: fix completely broken ancestry traversal.
      Match ofs/cnt types in diff interface.
      blame -S <ancestry-file>
      Add Documentation/technical/pack-format.txt
      Thin pack generation: optimization.
      rev-list --abbrev-commit
      count-delta: match get_delta_hdr_size() changes.
      GIT 1.3.0-rc3
      git-log: match rev-list --abbrev and --abbrev-commit
      diff: fix output of total-rewrite diff.
      diffcore-rename: fix merging back a broken pair.
      log-tree: separate major part of diff-tree.
      git log [diff-tree options]...
      Retire diffcore-pathspec.
      tree-diff: do not assume we use only one pathspec
      git log --full-diff
      Retire git-log.sh
      blame and friends: adjust to multiple pathspec change.
      Retire git-log.sh (take#2)
      diff-* --patch-with-raw
      Retire git-log.sh (take #3)
      combine-diff: do not lose hunks with only deletion at end.
      combine-diff: fix hunks at the end (take #2).
      Retire t5501-old-fetch-and-upload test.
      git-commit: do not muck with commit message when no_edit is set.
      stripspace: make sure not to leave an incomplete line.
      combine-diff: type fix.
      Documentation: add a couple of missing docs.
      Makefile: $(MAKE) check-docs
      git-log: do not output excess blank line between commits
      t3600-rm: skip failed-remove test when we cannot make an unremovable file.
      Fix-up previous expr changes.
      diff --stat: no need to ask funcnames nor context.
      t5500: test fix
      stripspace: incomplete line fix (take #2)
      Retire git-log.sh (take #4)
      git-log <diff-options> <paths> documentation
      "git cmd -h" for shell scripts.
      rev-list --bisect: limit list before bisecting.
      GIT v1.3.0-rc4
      diff-tree: typefix.
      diff --stat: do not do its own three-dashes.
      diff-files --stat: do not dump core with unmerged index.
      reading $GIT_DIR/info/graft - skip comments correctly.
      rev-list --boundary: show boundary commits even when limited otherwise.
      packed_object_info_detail(): check for corrupt packfile.
      diff --stat: make sure to set recursive.
      GIT 1.3.0

Karl Hasselström:
      git-svnimport: -r adds svn revision number to commit messages
      svnimport: Mention -r in usage summary
      svnimport: Convert executable flag
      svnimport: Convert the svn:ignore property
      svnimport: Read author names and emails from a file
      Let git-svnimport's author file use same syntax as git-cvsimport's
      Save username -> Full Name <email@addr.es> map file
      git-svnimport: Don't assume that copied files haven't changed

Keith Packard:
      Provide configurable UI font for gitk

Linus Torvalds:
      Handling large files with GIT
      Handling large files with GIT
      git-merge-tree: generalize the "traverse <n> trees in sync" functionality
      Teach the "git" command to handle some commands internally
      First cut at libifying revlist generation
      Make git diff-generation use a simpler spawn-like interface
      The war on trailing whitespace
      Splitting rev-list into revisions lib, end of beginning.
      git-rev-list libification: rev-list walking
      Introduce trivial new pager.c helper infrastructure
      Tie it all together: "git log"
      Rip out merge-order and make "git log <paths>..." work again.
      get_revision(): do not dig deeper when we know we are at the end.
      git-fmt-merge-msg cleanup
      Fix up diffcore-rename scoring
      diffcore-delta: 64-byte-or-EOL ultrafast replacement.
      diffcore-delta: 64-byte-or-EOL ultrafast replacement (hash fix).
      git-apply: safety fixes
      Use a *real* built-in diff generator
      builtin-diff: \No newline at end of file.
      Fix error handling for nonexistent names
      Move "--parent" parsing into generic revision.c library code
      Make path-limiting be incremental when possible.
      revision: Fix --topo-order and --max-age with reachability limiting.
      Make "--parents" logs also be incremental
      When showing a commit message, do not lose an incomplete line.
      Use less memory in "git log"
      Clean up trailing whitespace when pretty-printing commits
      Support "git cmd --help" syntax

Lukas Sandström:
      git-fetch: print the new and old ref when fast-forwarding

Marco Costalba:
      Add a Documentation/git-tools.txt

Marco Roeland:
      imap-send: cleanup execl() call to use NULL sentinel instead of 0
      git-commit: document --amend
      xdiff/xdiffi.c: fix warnings about possibly uninitialized variables

Mark Hollomon:
      Let merge set the default strategy.

Mark Wooding:
      combine-diff: Honour --full-index.
      combine-diff: Honour -z option correctly.
      Documentation/Makefile: Some `git-*.txt' files aren't manpages.
      gitignore: Ignore some more boring things.
      contrib/emacs/Makefile: Provide tool for byte-compiling files.
      annotate-tests: override VISUAL when running tests.
      xdiff: Show function names in hunk headers.
      gitk: Use git wrapper to run git-ls-remote.
      Shell utilities: Guard against expr' magic tokens.

Martin Langhoff:
      Introducing git-cvsserver -- a CVS emulator for git.
      cvsserver: add notes on how to get a checkout under Eclipse
      cvsserver: Eclipse compat fixes - implement Questionable, alias rlog, add a space after the U
      cvsserver: Eclipse compat - browsing 'modules' (heads in our case) works
      cvsserver: add notes on how to get a checkout under Eclipse
      cvsserver: Eclipse compat fixes - implement Questionable, alias rlog, add a space after the U
      cvsserver: Eclipse compat - browsing 'modules' (heads in our case) works
      cvsserver: Checkout correctly on Eclipse
      annotate: fix -S parameter to take a string
      cvsserver: Eclipse compat -- now "compare with latest from HEAD" works
      cvsserver: checkout faster by sending files in a sensible order
      cvsserver: fix checkouts with -d <somedir>
      cvsserver: checkout faster by sending files in a sensible order
      cvsserver: fix checkouts with -d <somedir>
      cvsserver: nested directory creation fixups for Eclipse clients
      cvsserver: better error messages
      cvsserver: anonymous cvs via pserver support
      cvsserver: updated documentation

Martin Mares:
      gitk: Make error_popup react to Return

Matthias Urlichs:
      cvsimport: Remove master-updating code
      Don't recurse into parents marked uninteresting.

Mike McCormack:
      Allow adding arbitary lines in the mail header generated by format-patch.
      Allow format-patch to attach patches
      Document the --attach flag.
      Describe how to add extra mail header lines in mail generated by git-format-patch.
      Add git-imap-send, derived from isync 1.0.1.
      Avoid a divide by zero if there's no messages to send.
      Avoid a crash if realloc returns a different pointer.
      Add documentation for git-imap-send.

Nick Hengeveld:
      Update http-push functionality
      http-push: fix revision walk
      HTTP slot reuse fixes
      http-push: refactor remote file/directory processing
      http-push: improve remote lock management
      http-push: support for updating remote info/refs
      http-push: cleanup
      Fix broken slot reuse when fetching alternates
      http-push: add support for deleting remote branches
      http-push: don't assume char is signed
      git-ls-remote: send no-cache header when fetching info/refs
      Set HTTP user agent to git/GIT_VERSION
      http-fetch: add optional DAV-based pack list

Nicolas Pitre:
      relax delta selection filtering in pack-objects
      diff-delta: fold two special tests into one plus cleanups
      diff-delta: produce optimal pack data
      diff-delta: big code simplification
      diff-delta: bound hash list length to avoid O(m*n) behavior
      diff-delta: produce optimal pack data
      diff-delta: bound hash list length to avoid O(m*n) behavior
      diff-delta: allow reusing of the reference buffer index
      test-delta needs zlib to compile
      diff-delta: bound hash list length to avoid O(m*n) behavior
      3% tighter packs for free

Olaf Hering:
      allow double click on current HEAD id after git-pull

Paul Jakma:
      Makefile tweaks: Solaris 9+ dont need iconv / move up uname variables

Paul Mackerras:
      gitk: Make "find" on "Files" work again.
      gitk: New improved gitk
      gitk: Fix clicks on arrows on line ends
      gitk: Fix Update menu item
      gitk: Various speed improvements
      gitk: Further speedups
      gitk: Fix a bug in drawing the selected line as a thick line
      gitk: Fix display of diff lines beginning with --- or +++
      gitk: Make commitdata an array rather than a list
      gitk: Don't change cursor at end of layout if find in progress
      gitk: Make downward-pointing arrows end in vertical line segment
      gitk: Improve appearance of first child links
      gitk: Fix two bugs reported by users
      gitk: Use the new --boundary flag to git-rev-list
      gitk: Show diffs for boundary commits
      gitk: Prevent parent link from overwriting commit headline
      gitk: Allow top panes to scroll horizontally with mouse button 2
      gitk: Better workaround for arrows on diagonal line segments
      gitk: replace parent and children arrays with lists
      gitk: Add a help menu item to display key bindings
      gitk: Fix incorrect invocation of getmergediffline
      gitk: Fix bug caused by missing commitlisted elements

Pavel Roskin:
      gitview: Select the text color based on whether the entry in highlighted. Use standard font.
      Add git-clean command
      gitk: Fix searching for filenames in gitk

Peter Eriksen:
      Use blob_, commit_, tag_, and tree_type throughout.
      Replace xmalloc+memset(0) with xcalloc.

Petr Baudis:
      Properly git-bisect reset after bisecting from non-master head
      Optionally do not list empty directories in git-ls-files --others
      Support for pickaxe matching regular expressions
      Improve the git-diff-tree -c/-cc documentation
      Document --patch-with-raw
      Separate the raw diff and patch with a newline

Randal L. Schwartz:
      fix imap-send for OSX

Rene Scharfe:
      tar-tree: Use SHA1 of root tree for the basedir
      tar-tree: Introduce write_entry()
      tar-tree: Use write_entry() to write the archive contents
      tar-tree: Remove obsolete code
      tar-tree: Use the prefix field of a tar header
      Remove useless pointer update
      Fix sparse warnings about usage of 0 instead of NULL
      Fix sparse warnings about non-ANSI function prototypes

Rutger Nijlunsing:
      gitk: add key bindings for selecting first and last commit

Ryan Anderson:
      send-email: Add some options for controlling how addresses are automatically added to the cc: list.
      send-email: Add --cc
      Add git-annotate, a tool for assigning blame.
      annotate: Handle dirty state and arbitrary revisions.
      annotate: Convert all -| calls to use a helper open_pipe().
      annotate: Use qx{} for pipes on activestate.
      annotate: handle \No newline at end of file.
      annotate: Add a basic set of test cases.
      annotate: Support annotation of files on other revisions.

Sean Estabrooks:
      annotate.perl triggers rpm bug

Serge E. Hallyn:
      cleanups: Fix potential bugs in connect.c
      cleanups: Remove unused vars from combine-diff.c
      cleanups: Remove impossible case in quote.c
      cleanups: prevent leak of two strduped strings in config.c
      cleanups: remove unused variable from exec_cmd.c

Shawn Pearce:
      git ls files recursively show ignored files
      Add missing programs to ignore list
      Darwin: Ignore missing /sw/lib
      Teach git-checkout-index to read filenames from stdin.
      Prevent --index-info from ignoring -z.
      Add --temp and --stage=all options to checkout-index.
      Add missing semicolon to sed command.

Stephen Rothwell:
      gitk: allow goto heads

Timo Hirvonen:
      Use setenv(), fix warnings

Tony Luck:
      fix warning from pack-objects.c
      Re-fix compilation warnings.
      annotate should number lines starting with 1
      fix field width/precision warnings in blame.c

Yann Dirson:
      Allow empty lines in info/grafts

Yasushi SHOJI:
      Be verbose when !initial commit
      Make git-clone to take long double-dashed origin option (--origin)
      git-clone: exit early if repo isn't specified

^ permalink raw reply	[relevance 1%]

* PATCH: New diff-delta.c implementation (updated)
@ 2006-04-28  1:59  1% Geert Bosch
  0 siblings, 0 replies; 200+ results
From: Geert Bosch @ 2006-04-28  1:59 UTC (permalink / raw)
  To: git

Even though the previous version did really well on large files
with many changes, performance was lacking for the many small
files with very few changes that are so common for a VCS.

For example, it turns out that, for packing the 17005 objects in
my git.git repository, diff_delta processes 240 MB worth of target
data in about 12s on my powerbook. (There's even a little more
source data, and the 12s includes compression/decompression time.)

So the fancy fingerprint calculations really take too much time.
Fortunately, it turns out that of the 240M, 120M matches directly
at the start or the end of the source data. After this trivial
matching, most remaining matches are quite small. The overhead
of setting up buffers, computing longest runs of the same character
and computing 64-bit fingerprints becomes very noticeable and
can't be regained later.

As a result I implemented special indexing and matching routines
for "small" files. Here a fixed hash table size and index step
are used. The fingerprint window has been reduced to be equal to
the step size, which essentially gets rid of computation for
characters leaving the window. Finally, the fingerprint size
has been reduced to 32 bits with polynome of 31st degree.

The result has been only a slight increase in delta size for
very large test cases (but with better performance), and
both smaller deltas and faster execution speed for repacking
git.git. I had trouble cloning the Linux kernel repository,
but am now reasonably confident this will outperform the
existing algorithm pretty consistently.

On PPC, the trivial matching in head and tail, and for long
matching runs now shows up high in the profile. On x86,
byte operations are very fast, so I think things should
be at least equally good there.

Please play around with this and let me know of any results.

   -Geert

Signed-off-by: Geert Bosch <bosch@gnat.com>

#include <unistd.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <sys/types.h>

#undef assert
#define assert(x) do { } while (0)

/*
  * MIN_HTAB_SIZE is fixed amount to be added to the size of the hash table
  * used for indexing and must be a power of two. This allows for small files
  * to have a sparse hash table, since in that case it's cheap.
  * Hash table sizes are rounded up to a power of two to avoid integer division.
  */
#define MIN_HTAB_SIZE 8192
#define MAX_HTAB_SIZE (1024*1024*1024)
#define SMALL_HTAB_SIZE 8192
#define SMALL_INDEX_STEP 16

/*
  * Diffing files of gigabyte range is impractical with the current
  * algorithm, so we're assuming 32-bit sizes everywhere.
  * Size leaves some room for expansion when diffing random files.
  */
#define MAX_SIZE (0x7eff0000)

/* For small files, indices are represented in 16 bits.
  * Since indices are always a multiple of the index_step, they
  * can be shifted right a few bits to accommodate files larger than 64K
  */
#define SMALL_SHIFT 4
#define MAX_SMALL_SIZE (0xff00<<SMALL_SHIFT)

/* Initial size of copies table, dynamically extended as needed. */
#define MAX_COPIES 512

/*
  * Matching is done using a sliding window for which a Rabin
  * polynomial is computed. The advantage of such polynomials is
  * that they can efficiently be updated at every position.
  * The tables needed for this are precomputed, as it is desirable
  * to use the same polynomial all the time for repeatable results.
  * The 16 byte window is convenient for indexing with index_step 16.
  * In that special case, the U table is not needed during indexing.
  * The 32-bit hash helps on register-starved 32-bit architectures.
  */

#define RABIN_POLY 0xf3a03ce5
#define RABIN_DEGREE 31
#define RABIN_SHIFT 23
#define RABIN_WINDOW_SIZE 16

unsigned T[256] =
{ 0x00000000, 0xf3a03ce5, 0x14e0452f,
   0xe74079ca, 0x29c08a5e, 0xda60b6bb, 0x3d20cf71, 0xce80f394, 0x538114bc,
   0xa0212859, 0x47615193, 0xb4c16d76, 0x7a419ee2, 0x89e1a207, 0x6ea1dbcd,
   0x9d01e728, 0x54a2159d, 0xa7022978, 0x404250b2, 0xb3e26c57, 0x7d629fc3,
   0x8ec2a326, 0x6982daec, 0x9a22e609, 0x07230121, 0xf4833dc4, 0x13c3440e,
   0xe06378eb, 0x2ee38b7f, 0xdd43b79a, 0x3a03ce50, 0xc9a3f2b5, 0x5ae417df,
   0xa9442b3a, 0x4e0452f0, 0xbda46e15, 0x73249d81, 0x8084a164, 0x67c4d8ae,
   0x9464e44b, 0x09650363, 0xfac53f86, 0x1d85464c, 0xee257aa9, 0x20a5893d,
   0xd305b5d8, 0x3445cc12, 0xc7e5f0f7, 0x0e460242, 0xfde63ea7, 0x1aa6476d,
   0xe9067b88, 0x2786881c, 0xd426b4f9, 0x3366cd33, 0xc0c6f1d6, 0x5dc716fe,
   0xae672a1b, 0x492753d1, 0xba876f34, 0x74079ca0, 0x87a7a045, 0x60e7d98f,
   0x9347e56a, 0x4668135b, 0xb5c82fbe, 0x52885674, 0xa1286a91, 0x6fa89905,
   0x9c08a5e0, 0x7b48dc2a, 0x88e8e0cf, 0x15e907e7, 0xe6493b02, 0x010942c8,
   0xf2a97e2d, 0x3c298db9, 0xcf89b15c, 0x28c9c896, 0xdb69f473, 0x12ca06c6,
   0xe16a3a23, 0x062a43e9, 0xf58a7f0c, 0x3b0a8c98, 0xc8aab07d, 0x2feac9b7,
   0xdc4af552, 0x414b127a, 0xb2eb2e9f, 0x55ab5755, 0xa60b6bb0, 0x688b9824,
   0x9b2ba4c1, 0x7c6bdd0b, 0x8fcbe1ee, 0x1c8c0484, 0xef2c3861, 0x086c41ab,
   0xfbcc7d4e, 0x354c8eda, 0xc6ecb23f, 0x21accbf5, 0xd20cf710, 0x4f0d1038,
   0xbcad2cdd, 0x5bed5517, 0xa84d69f2, 0x66cd9a66, 0x956da683, 0x722ddf49,
   0x818de3ac, 0x482e1119, 0xbb8e2dfc, 0x5cce5436, 0xaf6e68d3, 0x61ee9b47,
   0x924ea7a2, 0x750ede68, 0x86aee28d, 0x1baf05a5, 0xe80f3940, 0x0f4f408a,
   0xfcef7c6f, 0x326f8ffb, 0xc1cfb31e, 0x268fcad4, 0xd52ff631, 0x7f701a53,
   0x8cd026b6, 0x6b905f7c, 0x98306399, 0x56b0900d, 0xa510ace8, 0x4250d522,
   0xb1f0e9c7, 0x2cf10eef, 0xdf51320a, 0x38114bc0, 0xcbb17725, 0x053184b1,
   0xf691b854, 0x11d1c19e, 0xe271fd7b, 0x2bd20fce, 0xd872332b, 0x3f324ae1,
   0xcc927604, 0x02128590, 0xf1b2b975, 0x16f2c0bf, 0xe552fc5a, 0x78531b72,
   0x8bf32797, 0x6cb35e5d, 0x9f1362b8, 0x5193912c, 0xa233adc9, 0x4573d403,
   0xb6d3e8e6, 0x25940d8c, 0xd6343169, 0x317448a3, 0xc2d47446, 0x0c5487d2,
   0xfff4bb37, 0x18b4c2fd, 0xeb14fe18, 0x76151930, 0x85b525d5, 0x62f55c1f,
   0x915560fa, 0x5fd5936e, 0xac75af8b, 0x4b35d641, 0xb895eaa4, 0x71361811,
   0x829624f4, 0x65d65d3e, 0x967661db, 0x58f6924f, 0xab56aeaa, 0x4c16d760,
   0xbfb6eb85, 0x22b70cad, 0xd1173048, 0x36574982, 0xc5f77567, 0x0b7786f3,
   0xf8d7ba16, 0x1f97c3dc, 0xec37ff39, 0x39180908, 0xcab835ed, 0x2df84c27,
   0xde5870c2, 0x10d88356, 0xe378bfb3, 0x0438c679, 0xf798fa9c, 0x6a991db4,
   0x99392151, 0x7e79589b, 0x8dd9647e, 0x435997ea, 0xb0f9ab0f, 0x57b9d2c5,
   0xa419ee20, 0x6dba1c95, 0x9e1a2070, 0x795a59ba, 0x8afa655f, 0x447a96cb,
   0xb7daaa2e, 0x509ad3e4, 0xa33aef01, 0x3e3b0829, 0xcd9b34cc, 0x2adb4d06,
   0xd97b71e3, 0x17fb8277, 0xe45bbe92, 0x031bc758, 0xf0bbfbbd, 0x63fc1ed7,
   0x905c2232, 0x771c5bf8, 0x84bc671d, 0x4a3c9489, 0xb99ca86c, 0x5edcd1a6,
   0xad7ced43, 0x307d0a6b, 0xc3dd368e, 0x249d4f44, 0xd73d73a1, 0x19bd8035,
   0xea1dbcd0, 0x0d5dc51a, 0xfefdf9ff, 0x375e0b4a, 0xc4fe37af, 0x23be4e65,
   0xd01e7280, 0x1e9e8114, 0xed3ebdf1, 0x0a7ec43b, 0xf9def8de, 0x64df1ff6,
   0x977f2313, 0x703f5ad9, 0x839f663c, 0x4d1f95a8, 0xbebfa94d, 0x59ffd087,
   0xaa5fec62
};

unsigned U[256] =
{ 0x00000000, 0x302a7c89, 0x6054f912,
   0x507e859b, 0x3309cec1, 0x0323b248, 0x535d37d3, 0x63774b5a, 0x66139d82,
   0x5639e10b, 0x06476490, 0x366d1819, 0x551a5343, 0x65302fca, 0x354eaa51,
   0x0564d6d8, 0x3f8707e1, 0x0fad7b68, 0x5fd3fef3, 0x6ff9827a, 0x0c8ec920,
   0x3ca4b5a9, 0x6cda3032, 0x5cf04cbb, 0x59949a63, 0x69bee6ea, 0x39c06371,
   0x09ea1ff8, 0x6a9d54a2, 0x5ab7282b, 0x0ac9adb0, 0x3ae3d139, 0x7f0e0fc2,
   0x4f24734b, 0x1f5af6d0, 0x2f708a59, 0x4c07c103, 0x7c2dbd8a, 0x2c533811,
   0x1c794498, 0x191d9240, 0x2937eec9, 0x79496b52, 0x496317db, 0x2a145c81,
   0x1a3e2008, 0x4a40a593, 0x7a6ad91a, 0x40890823, 0x70a374aa, 0x20ddf131,
   0x10f78db8, 0x7380c6e2, 0x43aaba6b, 0x13d43ff0, 0x23fe4379, 0x269a95a1,
   0x16b0e928, 0x46ce6cb3, 0x76e4103a, 0x15935b60, 0x25b927e9, 0x75c7a272,
   0x45eddefb, 0x0dbc2361, 0x3d965fe8, 0x6de8da73, 0x5dc2a6fa, 0x3eb5eda0,
   0x0e9f9129, 0x5ee114b2, 0x6ecb683b, 0x6bafbee3, 0x5b85c26a, 0x0bfb47f1,
   0x3bd13b78, 0x58a67022, 0x688c0cab, 0x38f28930, 0x08d8f5b9, 0x323b2480,
   0x02115809, 0x526fdd92, 0x6245a11b, 0x0132ea41, 0x311896c8, 0x61661353,
   0x514c6fda, 0x5428b902, 0x6402c58b, 0x347c4010, 0x04563c99, 0x672177c3,
   0x570b0b4a, 0x07758ed1, 0x375ff258, 0x72b22ca3, 0x4298502a, 0x12e6d5b1,
   0x22cca938, 0x41bbe262, 0x71919eeb, 0x21ef1b70, 0x11c567f9, 0x14a1b121,
   0x248bcda8, 0x74f54833, 0x44df34ba, 0x27a87fe0, 0x17820369, 0x47fc86f2,
   0x77d6fa7b, 0x4d352b42, 0x7d1f57cb, 0x2d61d250, 0x1d4baed9, 0x7e3ce583,
   0x4e16990a, 0x1e681c91, 0x2e426018, 0x2b26b6c0, 0x1b0cca49, 0x4b724fd2,
   0x7b58335b, 0x182f7801, 0x28050488, 0x787b8113, 0x4851fd9a, 0x1b7846c2,
   0x2b523a4b, 0x7b2cbfd0, 0x4b06c359, 0x28718803, 0x185bf48a, 0x48257111,
   0x780f0d98, 0x7d6bdb40, 0x4d41a7c9, 0x1d3f2252, 0x2d155edb, 0x4e621581,
   0x7e486908, 0x2e36ec93, 0x1e1c901a, 0x24ff4123, 0x14d53daa, 0x44abb831,
   0x7481c4b8, 0x17f68fe2, 0x27dcf36b, 0x77a276f0, 0x47880a79, 0x42ecdca1,
   0x72c6a028, 0x22b825b3, 0x1292593a, 0x71e51260, 0x41cf6ee9, 0x11b1eb72,
   0x219b97fb, 0x64764900, 0x545c3589, 0x0422b012, 0x3408cc9b, 0x577f87c1,
   0x6755fb48, 0x372b7ed3, 0x0701025a, 0x0265d482, 0x324fa80b, 0x62312d90,
   0x521b5119, 0x316c1a43, 0x014666ca, 0x5138e351, 0x61129fd8, 0x5bf14ee1,
   0x6bdb3268, 0x3ba5b7f3, 0x0b8fcb7a, 0x68f88020, 0x58d2fca9, 0x08ac7932,
   0x388605bb, 0x3de2d363, 0x0dc8afea, 0x5db62a71, 0x6d9c56f8, 0x0eeb1da2,
   0x3ec1612b, 0x6ebfe4b0, 0x5e959839, 0x16c465a3, 0x26ee192a, 0x76909cb1,
   0x46bae038, 0x25cdab62, 0x15e7d7eb, 0x45995270, 0x75b32ef9, 0x70d7f821,
   0x40fd84a8, 0x10830133, 0x20a97dba, 0x43de36e0, 0x73f44a69, 0x238acff2,
   0x13a0b37b, 0x29436242, 0x19691ecb, 0x49179b50, 0x793de7d9, 0x1a4aac83,
   0x2a60d00a, 0x7a1e5591, 0x4a342918, 0x4f50ffc0, 0x7f7a8349, 0x2f0406d2,
   0x1f2e7a5b, 0x7c593101, 0x4c734d88, 0x1c0dc813, 0x2c27b49a, 0x69ca6a61,
   0x59e016e8, 0x099e9373, 0x39b4effa, 0x5ac3a4a0, 0x6ae9d829, 0x3a975db2,
   0x0abd213b, 0x0fd9f7e3, 0x3ff38b6a, 0x6f8d0ef1, 0x5fa77278, 0x3cd03922,
   0x0cfa45ab, 0x5c84c030, 0x6caebcb9, 0x564d6d80, 0x66671109, 0x36199492,
   0x0633e81b, 0x6544a341, 0x556edfc8, 0x05105a53, 0x353a26da, 0x305ef002,
   0x00748c8b, 0x500a0910, 0x60207599, 0x03573ec3, 0x337d424a, 0x6303c7d1,
   0x5329bb58
};


static unsigned char rabin_window[RABIN_WINDOW_SIZE];
static unsigned rabin_pos = 0;

#ifndef MIN
#define MIN(x,y) ((y)<(x) ? (y) : (x))
#endif
#ifndef MAX
#define MAX(x,y) ((y)>(x) ? (y) : (x))
#endif

/*
  * The copies array is the central data structure for diff generation.
  * Data statements are implicit, for ranges not covered by any copy command.
  *
  * The sum of tgt and length for each entry must be monotonically increasing,
  * and data ranges must be non-overlapping. This is accomplished by not
  * extending matches backwards during initial matching.
  *
  * Copies may have zero length, to make it quick to delete copies during
  * optimization. However, the last copy in the list must always be a
  * non-trivial copy.
  *
  * Before committing copies, an important optimization is performed: during
  * a backward pass through the copies array, each entry is extended backwards,
  * and redundant copies are eliminated.
  *
  * If each match were extended backwards on insertion, the same data may be
  * matched an arbitrary number of times, resulting in potentially quadratic
  * time behavior.
  */

typedef struct copyinfo {
 	unsigned src;
 	unsigned tgt;
 	unsigned length;
} CopyInfo;

static CopyInfo *copies;
static int copy_count = 0;
static unsigned max_copies = 0; /* Dynamically increased */

static unsigned *idx;
static unsigned idx_size;
static unsigned char *idx_data;
static unsigned idx_data_len;

typedef unsigned poly_t;

static void rabin_reset(void)
{
 	memset(rabin_window, 0, sizeof(rabin_window));
}

static poly_t rabin_slide (poly_t fp, unsigned char m)
{
 	unsigned char om;
 	if (++rabin_pos == RABIN_WINDOW_SIZE) rabin_pos = 0;
 	om = rabin_window[rabin_pos];
 	fp ^= U[om];
 	rabin_window[rabin_pos] = m;
 	fp = ((fp << 8) | m) ^ T[fp >> RABIN_SHIFT];
 	return fp;
}

static int add_copy (unsigned src, unsigned tgt, unsigned length)
{
 	if (copy_count == max_copies) {
 		max_copies *= 2;

 		if (!max_copies) {
 			max_copies = MAX_COPIES;
 			copies = malloc (max_copies * sizeof (CopyInfo));
 		} else
 			copies = realloc(copies,
 			   max_copies * sizeof (CopyInfo));
 		if (!copies)
 			return 0;
 	}

 	copies[copy_count].src = src;
 	copies[copy_count].tgt = tgt;
 	copies[copy_count].length = length;
 	return ++copy_count;
}

static unsigned maxofs[256];
static unsigned maxlen[256];
static unsigned maxfp[256];

static const unsigned small_idx_size = SMALL_HTAB_SIZE;
static short unsigned small_idx[SMALL_HTAB_SIZE];

static void small_init_idx (unsigned char * data, unsigned len,
                      	    unsigned head, unsigned tail)
{
 	const unsigned index_step = SMALL_INDEX_STEP;
 	unsigned j = head - head % index_step;
 	unsigned k;

 	if (len < index_step) return;

 	idx_data = data;
 	idx_data_len = len;
 	len -= MIN (len, tail + (index_step - 1));

 	memset (small_idx, 0, sizeof(small_idx));

 	while (j < len) {
 		poly_t fp = 0;
 		do
 			fp = ((fp << 8) | data[j++]) ^ T[fp >> RABIN_SHIFT];
 		while (j % index_step);
 		small_idx[fp % small_idx_size] = j >> SMALL_SHIFT;
 	}
}

static void init_idx (unsigned char *data, unsigned len, int level,
 		      unsigned head, unsigned tail)
{
 	unsigned index_step
 	  = RABIN_WINDOW_SIZE / sizeof(unsigned) * sizeof(unsigned);
 	unsigned j, k;
 	unsigned char ch = 0;
 	unsigned runlen = 0;
 	poly_t fp = 0;

 	/* Special case small files at low optimization levels */
 	if (level <= 1 && len < MAX_SMALL_SIZE
 	  && len - head - tail < (SMALL_HTAB_SIZE * SMALL_INDEX_STEP)) {
 		small_init_idx(data, len, head, tail);
 		return;
 	}

 	assert (len <= MAX_SIZE);
 	assert (head < len);
 	assert (level >= 0 && level <= 9);
 	memset(maxofs, 0, sizeof(maxofs));
 	memset(maxlen, 0, sizeof(maxlen));
 	memset(maxfp, 0, sizeof(maxfp));

 	/* Smaller step size for higher optimization levels.
 	   The index_step must be a multiple of the word size */
 	if (level >= 1)
 		index_step = MIN(index_step, 4 * sizeof (unsigned));
 	if (level >= 3)
 		index_step = MIN (index_step, 3 * sizeof (unsigned));
 	if (level >= 4)
 		index_step = MIN (index_step, 2 * sizeof (unsigned));
 	if (level >= 6)
 		index_step = MIN (index_step, 1 * sizeof (unsigned));
 	assert (index_step && !(index_step % sizeof (unsigned)));

 	/* Add fixed amount to hash table size, as small files will benefit
 	   a lot without using significantly more memory or time. */
 	idx_size = (level + 1) * ((len - head - tail) / index_step) / 2;
 	idx_size = MIN (idx_size + MIN_HTAB_SIZE, MAX_HTAB_SIZE - 1);

 	/* Round up to next power of two, but limit to MAX_HTAB_SIZE. */
 	{
 		unsigned s = MIN_HTAB_SIZE;
 		while (s < idx_size) s += s;
 		idx_size = s;
 	}

 	idx_data = data;
 	idx_data_len = len;
 	idx = calloc(idx_size, sizeof(unsigned));

 	/* It is tempting to first index higher addresses, so hashes of lower
 	   addresses will get preference in the hash table. However, for
 	   repetitive patterns with a period that is a divisor of the
 	   fingerprint window, this may mean the match is not anchored at
 	   the end. Furthermore, even when using a window length that is
 	   prime, the benefits are small and the irregularity of the first
 	   matches being more important is not worth it. */

 	rabin_reset();

 	ch = 0;
 	runlen = 0;

 	if (head < RABIN_WINDOW_SIZE + index_step)
 		head = 0;
 	else {
 		head -= head % index_step;
 		for (j = head - RABIN_WINDOW_SIZE + 1; j < head; j++)
 			fp = rabin_slide (fp, data[j]);
 	}

 	for (j = head; j + index_step < len - tail; j += index_step) {
 		unsigned char pch = 0;
 		unsigned hash;

 		for (k = 0; k < index_step; k++) {
 			pch = ch;
 			ch = data[j + k];
 			if (ch != pch)
 				runlen = 0;
 			runlen++;
 			fp = rabin_slide(fp, ch);
 		}

 		/* See if there is a word-aligned window-sized run of
 		   equal characters */
 		if (runlen >= RABIN_WINDOW_SIZE + sizeof(unsigned) - 1) {
 			/* Skip ahead to end of run */
 			while (j + k < len && data[j + k] == ch) {
 				k++;
 				runlen++;
 			}

 			/* Although matches are usually anchored at the end,
 			   in the case of extended runs of equal characters
 			   it is better to anchor after the first
 			   RABIN_WINDOW_SIZE bytes. This allows for quick
 			   skip ahead while matching such runs, avoiding
 			   unneeded fingerprint calculations.
 			   Also, when anchoring at the end, matches will be
 			   generated after every word, because the fingerprint
 			   stays constant. Even though all matches would get
 			   combined during match optimization, it wastes time
 			   and space. */
 			if (runlen > maxlen[pch] + 4) {
 				unsigned ofs;
 				/* ofs points RABIN_WINDOW_SIZE bytes after
 				   the start of the run, rounded up to the
 				   next word */
 				ofs = j + k - runlen + RABIN_WINDOW_SIZE
 				   + (sizeof (unsigned) - 1);
 				ofs -= ofs % sizeof(unsigned);
 				maxofs[pch] = ofs;
 				maxlen [pch] = runlen;
 				assert(maxfp[pch] == 0
 				  || maxfp[pch] == (unsigned)fp);
 				maxfp[pch] = (unsigned)fp;
 			}
 			/* Keep input aligned as if no special run
 			   processing had taken place */
 			j += k - (k % index_step) - index_step;
 			k = index_step;
 		}

 		/* Testing showed that avoiding collisions using secondary
 		   hashing, or hash chaining had little effect and is not
 		   worth the time. */
 		hash = ((unsigned)fp) & (idx_size - 1);
 		idx[hash] = j + k;
 	}

 	/* Lastly, index the longest runs of equal characters found before.
 	   This ensures we always match the longerst such runs available.  */
 	for (j = 0; j < 256; j++)
 		if (maxlen[j])
 			idx[maxfp[j] % idx_size] = maxofs[j];
}

/* Match data against the current index and record all possible copies */
static int small_find_copies(unsigned char *data, unsigned len, unsigned head)
{
 	unsigned j = head < RABIN_WINDOW_SIZE ? 0 : head - RABIN_WINDOW_SIZE;
 	poly_t fp = 0;

 	while (j < MAX (head, RABIN_WINDOW_SIZE) && j < len)
 		fp = ((fp << 8) | data[j++]) ^ T[fp >> RABIN_SHIFT];

 	while (j < len) {
 		unsigned ofs, src, tgt, runlen, maxrun;

 		fp ^= U[data[j - RABIN_WINDOW_SIZE]];
 		fp = ((fp << 8) | data[j++]) ^ T[fp >> RABIN_SHIFT];

 		ofs = small_idx[fp & (small_idx_size - 1)] << SMALL_SHIFT;

 		/* Invariant:
 		   data[0] .. data[j-1] has been processed
 		   fp is fingerprint of sliding window ending at j-1
 		   ofs is zero or points just past tentative match
 		   ofs is a multiple of index_step */

 		if (!ofs)
 			continue;

 		runlen = 0;
 		tgt = j - 4;
 		src = ofs - 4;
 		maxrun = MIN(idx_data_len - src, len - tgt);

 		/* Hot loop */
 		while (runlen < maxrun &&
 		       data[tgt + runlen] == idx_data[src + runlen])
 			runlen++;
 		if (runlen < 4)
 			continue;

 		if (!add_copy(src, tgt, runlen)) return 0;

 		/* For runs extending more than RABIN_WINDOW_SIZE bytes past j,
 		   skip ahead to prevent useless fingerprint computations. */
 		if (tgt + runlen > j + RABIN_WINDOW_SIZE)
 		{
 			fp = 0;
 			j = tgt + runlen - RABIN_WINDOW_SIZE;
 			while (j < tgt + runlen)
 				fp = ((fp << 8) | data[j++])
 				      ^ T[fp >> RABIN_SHIFT];
 		}

 		/* Quickly scan ahead without looking for matches
 		   until the end of this run */
 		while (j < tgt + runlen) {
 			fp ^= U[data[j - RABIN_WINDOW_SIZE]];
 			fp = ((fp << 8) | data[j++]) ^ T[fp >> RABIN_SHIFT];
 		}
 	}

 	return 1;
}

/* Match data against the current index and record all possible copies */
static int find_copies(unsigned char *data, unsigned len, unsigned head)
{
 	unsigned j = head < RABIN_WINDOW_SIZE ? 0 : head - RABIN_WINDOW_SIZE;
 	poly_t fp = 0;

 	assert (idx_data);

 	if (!idx) return small_find_copies (data, len, head);

 	rabin_reset();

 	while (j < head + RABIN_WINDOW_SIZE && j < len)
 		fp = rabin_slide(fp, data[j++]);

 	while (j < len) {
 		unsigned ofs, src, tgt, runlen, maxrun;

 		fp = rabin_slide(fp, data[j++]);
 		ofs = idx[fp & (idx_size - 1)];

 		/* Invariant:
 		   data[0] .. data[j-1] has been processed
 		   fp is fingerprint of sliding window ending at j-1
 		   ofs is zero or points just past tentative match
 		   ofs is a multiple of index_step */

 		if (!ofs)
 			continue;

 		runlen = 0;
 		tgt = j - 4;
 		src = ofs - 4;
 		maxrun = MIN(idx_data_len - src, len - tgt);

 		/* Hot loop */
 		while (runlen < maxrun &&
 		       data[tgt + runlen] == idx_data[src + runlen])
 			runlen++;
 		if (runlen < 4)
 			continue;

 		if (!add_copy(src, tgt, runlen)) return 0;

 		/* For runs extending more than RABIN_WINDOW_SIZE bytes past j,
 		   skip ahead to prevent useless fingerprint computations. */
 		if (tgt + runlen > j + RABIN_WINDOW_SIZE)
 			j = tgt + runlen - RABIN_WINDOW_SIZE;

 		/* Quickly scan ahead without looking for matches
 		   until the end of this run */
 		while (j < tgt + runlen)
 			fp = rabin_slide(fp, data[j++]);
 	}

 	return 1;
}

static unsigned header_length(unsigned srclen, unsigned tgtlen)
{
 	unsigned len = 0;
 	assert (srclen <= MAX_SIZE && tgtlen <= MAX_SIZE);

 	/* GIT headers start with the length of the source and target,
 	   with 7 bits per byte, least significant byte first, and
 	   the high bit indicating continuation. */
 	do { len++; srclen >>= 7; } while (srclen);
 	do { len++; tgtlen >>= 7; } while (tgtlen);

 	return len;
}

static unsigned char *
write_header(unsigned char *patch, unsigned srclen, unsigned tgtlen)
{
 	assert (srclen <= MAX_SIZE && tgtlen <= MAX_SIZE);

 	while (srclen >= 0x80) {
 		*patch++ = srclen | 0x80;
 		srclen >>= 7;
 	}
 	*patch++ = srclen;

 	while (tgtlen >= 0x80) {
 		*patch++ = tgtlen | 0x80;
 		tgtlen >>= 7;
 	}
 	*patch++ = tgtlen;

 	return patch;
}

static unsigned data_length(unsigned length)
{
 	/* Can only include 0x7f data bytes per command */
 	unsigned partial = length % 0x7f;
 	assert (length > 0 && length <= MAX_SIZE);
 	if (partial) partial++;
 	return partial + (length / 0x7f) * 0x80;
}

static unsigned char *
write_data(unsigned char *patch, unsigned char *data, unsigned size)
{
 	assert (size > 0 && size < MAX_SIZE);
 	/* The return value must be equal to patch + data_length (patch, size).
 	   This correspondence is essential for calculating the patch size.  */

 	/* GIT has no data commands for large data, rest is same as GDIFF */
 	do {
 		unsigned s = size;
 		if (s > 0x7f)
 			s = 0x7f;
 		*patch++ = s;
 		memcpy(patch, data, s);
 		data += s;
 		patch += s;
 		size -= s;
 	} while (size);

 	return patch;
}

static unsigned copy_length (unsigned offset, unsigned length)
{
 	unsigned size = 0;

 	assert (offset < MAX_SIZE && length < MAX_SIZE);

 	/* For now we only copy a maximum of 0x10000 bytes per command.
 	   Longer copies are broken into pieces of that size. */
 	do {
 		signed s = length;
 		if (s > 0x10000)
 			s = 0x10000;
 		size += !!(s & 0xff) + !!(s & 0xff00);
 		size += !!(offset & 0xff) + !!(offset & 0xff00) +
 			!!(offset & 0xff0000) + !!(offset & 0xff000000);
 		size += 1;
 		offset += s;
 		length -= s;
 	} while (length);

 	return size;
}

static unsigned char *
write_copy(unsigned char *patch, unsigned offset, unsigned size)
{
 	/* The return value must be equal to patch + copy_length
 	   (patch, offset, size). This correspondence is essential
 	   for calculating the patch size.  */

 	do {
 		unsigned char c = 0x80, *cmd = patch++;
 		unsigned v, s = size;
 		if (s > 0x10000)
 			s = 0x10000;

 		v = offset;
 		if (v & 0xff) c |= 0x01, *patch++ = v;
 		v >>= 8;
 		if (v & 0xff) c |= 0x02, *patch++ = v;
 		v >>= 8;
 		if (v & 0xff) c |= 0x04, *patch++ = v;
 		v >>= 8;
 		if (v & 0xff) c |= 0x08, *patch++ = v;

 		v = s;
 		if (v & 0xff) c |= 0x10, *patch++ = v;
 		v >>= 8;
 		if (v & 0xff) c |= 0x20, *patch++ = v;

 		*cmd = c;
 		offset += s;
 		size -= s;
 	} while (size);

 	return patch;
}

static unsigned
process_copies (unsigned char *data, unsigned length, unsigned maxlen)
{
 	int j;
 	unsigned ptr = length;
 	unsigned patch_bytes = header_length(idx_data_len, length);

 	/* Work through the copies backwards, extending each one backwards. */
 	for (j = copy_count - 1; j >= 0; j--) {
 		CopyInfo *copy = copies+j;
 		unsigned src = copy->src;
 		unsigned tgt = copy->tgt;
 		unsigned len = copy->length;
 		int data_follows;

 		if (tgt + len > ptr) {
 			/* Part of copy already covered by later one,
 			   so shorten copy. */
 			if (ptr < tgt) {
 				/* Copy completely disappeared, but guess
 				   that a backward extension might still be
 				   useful. This extension is non-contiguous,
 				   as it is irrelevant whether the skipped
 				   data would have matched or not. Be careful
 				   to not extend past the beginning of
 				   the source. */
 				unsigned adjust = tgt - ptr;

 				tgt = ptr;
 				src = (src < adjust) ? 0 : src - adjust;

 				copy->tgt = tgt;
 				copy->src = src;
 			}

 			len = ptr - tgt;
 		}

 		while (src && tgt && idx_data[src - 1] == data[tgt - 1]) {
 			src--;
 			tgt--;
 		}
 		len += copy->tgt - tgt;

 		data_follows = (tgt + len < ptr);

 		/* A short copy may cost as much as 6 bytes for the copy and
 		   5 as result of an extra data command. It's not worth
 		   having extra copies in order to just save a byte or two.
 		   Being too smart here may hurt later compression as well. */
 		if (len < (data_follows ? 16 : 10))
 			len = 0;

 		/* Some target data is not covered by the copies, account for
 		   the DATA command that will follow the copy. */
 		if (len && data_follows)
 			patch_bytes += data_length(ptr - (tgt + len));

 		/* Everything about the copy is known and will not change.
 		   Write back the new information and update the patch size
 		   with the size of the copy instruction. */
 		copy->length = len;
 		copy->src = src;
 		copy->tgt = tgt;

 		if (len) {
 			/* update patch size for copy command */
 			patch_bytes += copy_length (src, len);
 			ptr = tgt;
 		} else if (j == copy_count - 1) {
 			/* Remove empty copies at end of list. */
 			copy_count--;
 		}

 		if (patch_bytes > maxlen)
 			return 0;
 	}

 	/* Account for data before first copy */
 	if (ptr != 0)
 		patch_bytes += data_length(ptr);

 	if (patch_bytes > maxlen)
 		return 0;
 	return patch_bytes;
}

static void *
create_delta (unsigned char *data, unsigned len,
 	      unsigned char *delta, unsigned delta_size)
{
 	unsigned char *ptr = delta;
 	unsigned offset = 0;
 	int j;

 	ptr = write_header(ptr, idx_data_len, len);

 	for (j = 0; j < copy_count; j++) {
 		CopyInfo *copy = copies + j;
 		unsigned copylen = copy->length;

 		if (!copylen)
 			continue;

 		if (copy->tgt > offset) {
 			ptr = write_data(ptr, data + offset,
 			   copy->tgt - offset);
 		}

 		ptr = write_copy(ptr, copy->src, copylen);
 		offset = copy->tgt + copylen;
 	}

 	if (offset < len)
 		ptr = write_data(ptr, data + offset, len - offset);

 	assert(ptr - delta == delta_size);

 	return delta;
}

static void finalize_idx()
{
 	if (max_copies > 8 * MAX_COPIES) {
 		free(copies);
 		copies = 0;
 		max_copies = 0;
 	}
 	copy_count = 0;
 	if (idx) free(idx);
 	idx = 0;
 	idx_size = 0;
 	idx_data = 0;
 	idx_data_len = 0;
}

static unsigned
match_head (unsigned char *from, unsigned char *to, unsigned size)
{
 	unsigned head = 0;
 	while (head < size && from[head] == to[head]) head++;
 	return head;
}

static unsigned
match_tail (unsigned char *from, unsigned char *to, unsigned size)
{
 	unsigned tail = 0;
 	while (tail < size && *(from - tail) == *(to - tail)) tail++;
 	return tail;
}

void *diff_delta(void *from_buf, unsigned long from_size,
 		 void *to_buf, unsigned long to_size,
 		 unsigned long *delta_size, unsigned long max_size)
{
 	unsigned char *delta = 0;
 	unsigned dsize;
         unsigned head = 0;
         unsigned tail = 0;

 	assert (from_size <= MAX_SIZE && to_size <= MAX_SIZE);

 	/* The following actually takes care of about half of all target
 	   data. This is performance critical, and may need some work. */
         head = match_head(from_buf, to_buf, MIN(from_size, to_size));
 	tail = match_tail(from_buf + (from_size - 1), to_buf + (to_size - 1),
 	                  MIN(from_size, to_size - head));

 	if (head <= RABIN_WINDOW_SIZE) head = 0;
 	if (tail <= RABIN_WINDOW_SIZE) tail = 0;

 	if (!max_size)
 		max_size = from_size;

 	init_idx (from_buf, from_size, 1, head, tail);

 	if (head) add_copy (0, 0, head);

 	if (head + tail + RABIN_WINDOW_SIZE < from_size) {
 		if (!find_copies(to_buf, to_size - tail, head))
 			return 0;
 	}
 	if (tail) add_copy (from_size - tail, to_size - tail, tail);

 	dsize = process_copies(to_buf, to_size, max_size);
 	if (dsize)
 	{
 		delta = malloc (dsize);
 		delta = create_delta (to_buf, to_size, delta, dsize);
 	}
 	finalize_idx ();
 	if (delta)
 		*delta_size = dsize;
 	return delta;
}

^ permalink raw reply	[relevance 1%]

* [REGRESSION] Interrupted clone/fetch leaves .lock files around
@ 2006-06-06 18:51  5% Jonas Fonseca
  0 siblings, 0 replies; 200+ results
From: Jonas Fonseca @ 2006-06-06 18:51 UTC (permalink / raw)
  To: git

Hi,

It used to be possible to continue an interrupted clone when using
cg-clone, by cding into the partial repo and run cg-fetch. However, it
seems that the recent changes in the ref locking code ends up leaving
.lock files around when interrupted.

$ cg clone http://elinks.cz/elinks.git
defaulting to local storage area
Fetching head...
Fetching objects...
...
Getting pack c0e265dab40fa34912c3ee6e02ba29686ab84a7b
 which contains 16f85ec5043966c69e2142198c52e12494dcfc76
progress: 22 objects, 939754 bytes, now fetching c0e265dab40f... (657678 bytes)
cg-clone: interrupted
$ cd elinks
$ cg fetch
Recovering from a previously interrupted initial clone...
Fetching head...
Fetching objects...
error: Couldn't open lock file .git/refs/heads/origin.lock: File exists
error: Can't lock ref heads/origin
progress: 0 objects, 0 bytes
cg-fetch: objects fetch failed

Below is my feeble attempt at a (tested) fix.

diff --git a/fetch.c b/fetch.c
index e040ef9..861dc60 100644
--- a/fetch.c
+++ b/fetch.c
@@ -1,3 +1,5 @@
+#include <signal.h>
+
 #include "fetch.h"
 
 #include "cache.h"
@@ -214,9 +216,19 @@ static int mark_complete(const char *pat
 	return 0;
 }
 
+static struct ref_lock *lock = NULL;
+
+static void remove_lockfile_on_signal(int signo)
+{
+	if (lock)
+		unlock_ref(lock);
+	lock = NULL;
+	signal(SIGINT, SIG_DFL);
+	raise(signo);
+}
+
 int pull(char *target)
 {
-	struct ref_lock *lock = NULL;
 	unsigned char sha1[20];
 	char *msg;
 	int ret;
@@ -229,6 +241,7 @@ int pull(char *target)
 			error("Can't lock ref %s", write_ref);
 			return -1;
 		}
+		signal(SIGINT, remove_lockfile_on_signal);
 	}
 
 	if (!get_recover)
@@ -236,22 +249,11 @@ int pull(char *target)
 
 	if (interpret_target(target, sha1)) {
 		error("Could not interpret %s as something to pull", target);
-		if (lock)
-			unlock_ref(lock);
-		return -1;
-	}
-	if (process(lookup_unknown_object(sha1))) {
-		if (lock)
-			unlock_ref(lock);
-		return -1;
-	}
-	if (loop()) {
-		if (lock)
-			unlock_ref(lock);
-		return -1;
-	}
 
-	if (write_ref) {
+	} else if (process(lookup_unknown_object(sha1)) || loop()) {
+		; /* unlock */
+
+	} else if (write_ref) {
 		if (write_ref_log_details) {
 			msg = xmalloc(strlen(write_ref_log_details) + 12);
 			sprintf(msg, "fetch from %s", write_ref_log_details);
@@ -261,6 +263,10 @@ int pull(char *target)
 		if (msg)
 			free(msg);
 		return ret;
+	} else {
+		return 0;
 	}
-	return 0;
+
+	remove_lockfile_on_signal(0);
+	return -1;
 }

-- 
Jonas Fonseca

^ permalink raw reply related	[relevance 5%]

* Re: Figured out how to get Mozilla into git
  @ 2006-06-09 15:01  3%       ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2006-06-09 15:01 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git



On Fri, 9 Jun 2006, Jakub Narebski wrote:
> Jon Smirl wrote:
> 
> >> git-repack -a -d but it OOMs on my 2GB+2GBswap machine :(
> > 
> > We are all having problems getting this to run on 32 bit machines with
> > the 3-4GB process size limitations.
> 
> Is that expected (for 10GB repository if I remember correctly), or is there
> some way to avoid this OOM?

Well, to some degree, the VM limitations are inevitable with huge packs.

The original idea for packs was to avoid making one huge pack, partly 
because it was expected to be really really slow to generate (so 
incremental repacking was a much better strategy), but partly simply 
because trying to map one huge pack is really hard to do.

For various reasons, we ended up mostly using a single pack most of the 
time: it's the most efficient model when the project is reasonably sized, 
and it turns out that with the delta re-use, repacking even moderately 
large projects like the kernel doesn't actually take all that long.

But the fact that we ended up mostly using a single pack for the kernel, 
for example, doesn't mean that the fundamental reasons that git supports 
multiple packs would somehow have gone away. At some point, the project 
gets large enough that one single pack simply isn't reasonable.

So a single 2GB pack is already very much pushing it. It's really really 
hard to map in a 2GB file on a 32-bit platform: your VM is usually 
fragmented enough that it simply isn't practical. In fact, I think the 
limit for _practical_ usage of single packs is probably somewhere in the 
half-gig region, unless you just have 64-bit machines.

And yes, I realize that the "single pack" thing actually ends up having 
become a fact for cloning, for example. Originally, cloning would unpack 
on the receiving end, and leave the repacking to happen there, but that 
obviously sucked. So now when we clone, we always get a single pack. That 
can absolutely be a problem.

I don't know what the right solution is. Single packs _are_ very useful, 
especially after a clone. So it's possible that we should just make the 
pack-reading code be able to map partial packs. But the point is that 
there are certainly ways we can fix this - it's not _really_ fundamental.

It's going to complicate it a bit (damn, how I hate 32-bit VM 
limitations), but the good news is that the whole git model of "everything 
is an individual object" means that it's a very _local_ decision: it will 
probably be painful to re-do some of the pack reading code and have a LRU 
of pack _fragments_ instead of a LRU of packs, but it's only going to 
affect a small part of git, and everything else will never even see it.

So large packs are not really a fundamental problem, but right now we have 
some practical issues with them.

(It's not _just_ packs: running out of memory is also because of 
git-rev-list --objects being pretty memory hungry. I've improved the 
memory usage several times by over 50%, but people keep trying larger 
projects. It used to be that I considered the kernel a large history, now 
we're talking about things that have ten times the number of objects).

Martin - do you have some place to make that big mozilla repo available? 
It would be a good test-case.. 

			Linus

^ permalink raw reply	[relevance 3%]

* Re: Figured out how to get Mozilla into git
  @ 2006-06-09 20:17  3%       ` Jon Smirl
  2006-06-09 20:44  4%         ` Jakub Narebski
                           ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: Jon Smirl @ 2006-06-09 20:17 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Martin Langhoff, git

On 6/9/06, Linus Torvalds <torvalds@osdl.org> wrote:
>
>
> On Fri, 9 Jun 2006, Jon Smirl wrote:
> >
> > That looks too small. My svn git import is 2.7GB and the source CVS is
> > 3.0GB. The svn import wasn't finished when I stopped it.
>
> Git is much better at packing than either CVS or SVN. Get used to it ;)

The git tree that Martin got from cvsps is much smaller that the git
tree I got from going to svn then to git.  I don't why the trees are
700KB different, it may be different amounts of packing, or one of the
conversion tools is losing something.

Earlier he said:
>git-repack -a -d but it OOMs on my 2GB+2GBswap machine :(

> > My cvsps process is still running from last night. The error file is
> > 341MB. How big is it when the conversion is finished? My machine is
> > swapping to death.
>
> Do you have all the cvsps patches? There's a few important ones floating
> around, and David Mansfield never did a 2.2 release..

I am running cvsps-2.1-3.fc5 so I may be wasting my time. Error out is
535MB now.
He sent me some git patches, but none for cvsps.

> I'm pretty sure Martin doesn't run plain 2.1.

I haven't come up with anything that is likely to result in Mozilla
switching over to git. Right now it takes three days to convert the
tree. The tree will have to be run in parallel for a while to convince
everyone to switch. I don't have a solution to keeping it in sync in
near real time (commits would still go to CVS). Most Mozilla
developers are interested but the infrastructure needs some help.

Martin has also brought up the problem with needing a partial clone so
that everyone doesn't have to bring down the entire repository. A
trunk checkout is 340MB and Martin's git tree is 2GB (mine 2.7GB).  A
kernel tree is only 680M.

-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[relevance 3%]

* Re: Figured out how to get Mozilla into git
  2006-06-09 20:17  3%       ` Jon Smirl
@ 2006-06-09 20:44  4%         ` Jakub Narebski
  2006-06-09 21:05  0%         ` Nicolas Pitre
  2006-06-10  1:23  0%         ` Martin Langhoff
  2 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2006-06-09 20:44 UTC (permalink / raw)
  To: git

Jon Smirl wrote:

> Martin has also brought up the problem with needing a partial clone so
> that everyone doesn't have to bring down the entire repository. A
> trunk checkout is 340MB and Martin's git tree is 2GB (mine 2.7GB).  A
> kernel tree is only 680M.

Partial/shallow nor lazy clone we don't have (although there might be some
shallow clone partial solutions in topic branches and/or patches flying
around in git mailing list). Yet.

But you can do what was done for Linux kernel: split repository into current
and historical, and you can join them (join the history) if needed using
grafts. And even if one need historical repository, it is neede to
clone/copy only _once_. With alternatives (using historical repository as
one of alternatives for current repository) someone who has both
repositories does need only a little more space, I think, than if one used
single repository.

-- 
Jakub Narebski
Warsaw, Poland

^ permalink raw reply	[relevance 4%]

* Re: Figured out how to get Mozilla into git
  2006-06-09 20:17  3%       ` Jon Smirl
  2006-06-09 20:44  4%         ` Jakub Narebski
@ 2006-06-09 21:05  0%         ` Nicolas Pitre
  2006-06-09 21:46  0%           ` Jon Smirl
  2006-06-10  1:23  0%         ` Martin Langhoff
  2 siblings, 1 reply; 200+ results
From: Nicolas Pitre @ 2006-06-09 21:05 UTC (permalink / raw)
  To: Jon Smirl; +Cc: Linus Torvalds, Martin Langhoff, git

On Fri, 9 Jun 2006, Jon Smirl wrote:

> I haven't come up with anything that is likely to result in Mozilla
> switching over to git. Right now it takes three days to convert the
> tree. The tree will have to be run in parallel for a while to convince
> everyone to switch. I don't have a solution to keeping it in sync in
> near real time (commits would still go to CVS). Most Mozilla
> developers are interested but the infrastructure needs some help.

This is true.  GIT is still evolving and certainly needs work to cope 
with environments and datasets that were never tested before.  The 
Mozilla repo is one of those and we're certainly interested into making 
it work well.  GIT might not be right for it just yet, but if you could 
let us rsync your converted repo to play with that might help us work on 
proper fixes for that kind of repo.

> Martin has also brought up the problem with needing a partial clone so
> that everyone doesn't have to bring down the entire repository.

If it can be repacked into a single pack that size might get much 
smaller too.


Nicolas

^ permalink raw reply	[relevance 0%]

* Re: Figured out how to get Mozilla into git
  2006-06-09 21:05  0%         ` Nicolas Pitre
@ 2006-06-09 21:46  0%           ` Jon Smirl
  0 siblings, 0 replies; 200+ results
From: Jon Smirl @ 2006-06-09 21:46 UTC (permalink / raw)
  To: Nicolas Pitre; +Cc: Linus Torvalds, Martin Langhoff, git

On 6/9/06, Nicolas Pitre <nico@cam.org> wrote:
> On Fri, 9 Jun 2006, Jon Smirl wrote:
>
> > I haven't come up with anything that is likely to result in Mozilla
> > switching over to git. Right now it takes three days to convert the
> > tree. The tree will have to be run in parallel for a while to convince
> > everyone to switch. I don't have a solution to keeping it in sync in
> > near real time (commits would still go to CVS). Most Mozilla
> > developers are interested but the infrastructure needs some help.
>
> This is true.  GIT is still evolving and certainly needs work to cope
> with environments and datasets that were never tested before.  The
> Mozilla repo is one of those and we're certainly interested into making
> it work well.  GIT might not be right for it just yet, but if you could
> let us rsync your converted repo to play with that might help us work on
> proper fixes for that kind of repo.

I'm rebuilding it on my shared hosting account at dreamhost.com. I'll
see if I can get it built before they notice and kill my process. My
account there is on a 4GB quad xeon box so hopefully it can convert
the tree faster. My account has 1TB download per month so rsync will
be ok. Not bad for $12 the first year.

It would take over a day to rsync it off from my home machine.

> > Martin has also brought up the problem with needing a partial clone so
> > that everyone doesn't have to bring down the entire repository.
>
> If it can be repacked into a single pack that size might get much
> smaller too.
>
>
> Nicolas
>


-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[relevance 0%]

* Re: Figured out how to get Mozilla into git
  2006-06-09 20:17  3%       ` Jon Smirl
  2006-06-09 20:44  4%         ` Jakub Narebski
  2006-06-09 21:05  0%         ` Nicolas Pitre
@ 2006-06-10  1:23  0%         ` Martin Langhoff
  2 siblings, 0 replies; 200+ results
From: Martin Langhoff @ 2006-06-10  1:23 UTC (permalink / raw)
  To: Jon Smirl; +Cc: Linus Torvalds, git

On 6/10/06, Jon Smirl <jonsmirl@gmail.com> wrote:
> The git tree that Martin got from cvsps is much smaller that the git
> tree I got from going to svn then to git.  I don't why the trees are
> 700KB different, it may be different amounts of packing, or one of the
> conversion tools is losing something.

Don't read too much into that. Packing/repacking points make a _huge_
difference, and even if one of our trees is a bit corrupt, the
packsizes should be about the same.

(With the patches I sent you we _are_ choosing to ignore a few
branches that don't seem to make sense in cvsps output. These will
show up in the error output -- what I saw were very old, possibly
corrupt branches there, stuff I wouldn't shed a tear over, but it is
worth reviewing).

> I haven't come up with anything that is likely to result in Mozilla
> switching over to git. Right now it takes three days to convert the
> tree. The tree will have to be run in parallel for a while to convince
> everyone to switch. I don't have a solution to keeping it in sync in
> near real time (commits would still go to CVS). Most Mozilla
> developers are interested but the infrastructure needs some help.

Don't worry about the initial import time. Once you've done it, you
can run the incremental import (which will take a few minutes) even
hourly to keep 'in sync'.

> Martin has also brought up the problem with needing a partial clone so
> that everyone doesn't have to bring down the entire repository. A
> trunk checkout is 340MB and Martin's git tree is 2GB (mine 2.7GB).  A
> kernel tree is only 680M.

Now that I have managed to repack the repo, it is indeed back in the
600M range. Actually, I just re-repacked, it took under a minute, and
it shrank down to 607MB.

Yay.

I'm sure that if you git-repack -a -d on a machine with plenty of
memory once or twice, we'll have matching packs.

cheers,



martin

^ permalink raw reply	[relevance 0%]

* Lazy clone ideas
@ 2006-06-10  8:58  6% Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2006-06-10  8:58 UTC (permalink / raw)
  To: git

I've started new thread for lazy clone ideas,
splitting from "Figured out how to get Mozilla into git"

Rogan Dawes wrote:
> Here's an idea. How about separating trees and commits from the actual 
> blobs (e.g. in separate packs)? My reasoning is that the commits and 
> trees should only be a small portion of the overall repository size, and 
> should not be that expensive to transfer. (Of course, this is only a 
> guess, and needs some numbers to back it up.)
> 
> So, a shallow clone would receive all of the tree objects, and all of 
> the commit objects, and could then request a pack containing the blobs 
> represented by the current HEAD.

That would be _lazy_ clone (with on-demand pack downloading from "master"
full history repository), rather than shallow clone.

I had an idea for having all the commit objects (without all the tree
objects) below the soft-grafts line (beyond the line we cut-off full
history and start being lazy).
 
> In this way, the user has a history that will show all of the commit 
> messages, and would be able to see _which_ files have changed over time 
> e.g. gitk would still work - except for the actual file level diff, "git 
> log" should also still work, etc
> 
> This would also enable other optimisations.
> 
> For example, documentation people would only need to get the objects 
> under the doc/ tree, and would not need to actually check out the 
> source. Git could detect any actual changes by checking whether it has 
> the previous blob in its local repository, and whether the file exists 
> locally. Creating a patch would obviously require that the person checks 
> out the previous version, but one could theoretically commit a new blob 
> to a repo without having the previous one (not saying that this would be 
> a good idea, of course)

Something akin to CVS's modules, or rather to how CVS modules can be abused?
Something called, I think, partial checkout?

This is a separate idea and I think worth implementing even for full
repository.

> This would probably require Eric Biederman's "direct access to blob" 
> patches, I guess, in order to be feasible.

And it would need place to store URI from where to doenload objects
on-demand: perhaps 'remote alternatives'?

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[relevance 6%]

* [PATCH] The name of the hash is SHA-1, use it consistently in Documentation
@ 2006-06-11 20:37  1% Horst H. von Brand
  0 siblings, 0 replies; 200+ results
From: Horst H. von Brand @ 2006-06-11 20:37 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Signed-off-by: Horst H. von Brand <vonbrand@inf.utfsm.cl>
---
 Documentation/config.txt           |    2 +-
 Documentation/core-tutorial.txt    |    8 ++++----
 Documentation/diff-format.txt      |    8 ++++----
 Documentation/diffcore.txt         |    2 +-
 Documentation/git-branch.txt       |    2 +-
 Documentation/git-cat-file.txt     |    2 +-
 Documentation/git-checkout.txt     |    2 +-
 Documentation/git-cherry.txt       |    4 ++--
 Documentation/git-diff-index.txt   |    8 ++++----
 Documentation/git-fsck-objects.txt |    8 ++++----
 Documentation/git-init-db.txt      |    2 +-
 Documentation/git-ls-files.txt     |    2 +-
 Documentation/git-merge-index.txt  |    2 +-
 Documentation/git-mktag.txt        |    6 +++---
 Documentation/git-name-rev.txt     |    2 +-
 Documentation/git-patch-id.txt     |    2 +-
 Documentation/git-push.txt         |    2 +-
 Documentation/git-receive-pack.txt |    4 ++--
 Documentation/git-rev-parse.txt    |    8 ++++----
 Documentation/git-show-branch.txt  |    4 ++--
 Documentation/git-show-index.txt   |    2 +-
 Documentation/git-tag.txt          |    2 +-
 Documentation/git-unpack-file.txt  |    2 +-
 Documentation/git-update-index.txt |   14 +++++++-------
 Documentation/git-verify-pack.txt  |    4 ++--
 Documentation/git-verify-tag.txt   |    2 +-
 Documentation/git.txt              |    2 +-
 Documentation/glossary.txt         |    4 ++--
 Documentation/tutorial-2.txt       |   14 +++++++-------
 29 files changed, 63 insertions(+), 63 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index a04c5ad..169640a 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -72,7 +72,7 @@ core.preferSymlinkRefs::
 
 core.logAllRefUpdates::
 	If true, `git-update-ref` will append a line to
-	"$GIT_DIR/logs/<ref>" listing the new SHA1 and the date/time
+	"$GIT_DIR/logs/<ref>" listing the new SHA-1 and the date/time
 	of the update.	If the file does not exist it will be
 	created automatically.	This information can be used to
 	determine what commit was the tip of a branch "2 days ago".
diff --git a/Documentation/core-tutorial.txt b/Documentation/core-tutorial.txt
index 1185897..151434b 100644
--- a/Documentation/core-tutorial.txt
+++ b/Documentation/core-tutorial.txt
@@ -100,9 +100,9 @@ branch. A number of the git tools will a
 valid, though.
 
 [NOTE]
-An 'object' is identified by its 160-bit SHA1 hash, aka 'object name',
+An 'object' is identified by its 160-bit SHA-1 hash, aka 'object name',
 and a reference to an object is always the 40-byte hex
-representation of that SHA1 name. The files in the `refs`
+representation of that SHA-1 name. The files in the `refs`
 subdirectory are expected to contain these hex references
 (usually with a final `\'\n\'` at the end), and you should thus
 expect to see a number of 41-byte files containing these
@@ -772,7 +772,7 @@ already discussed, the `HEAD` branch is 
 these object pointers. 
 
 You can at any time create a new branch by just picking an arbitrary
-point in the project history, and just writing the SHA1 name of that
+point in the project history, and just writing the SHA-1 name of that
 object into a file under `.git/refs/heads/`. You can use any filename you
 want (and indeed, subdirectories), but the convention is that the
 "normal" branch is called `master`. That's just a convention, though,
@@ -1260,7 +1260,7 @@ file (the first tree goes to stage 1, th
 etc.).  After reading three trees into three stages, the paths
 that are the same in all three stages are 'collapsed' into stage
 0.  Also paths that are the same in two of three stages are
-collapsed into stage 0, taking the SHA1 from either stage 2 or
+collapsed into stage 0, taking the SHA-1 from either stage 2 or
 stage 3, whichever is different from stage 1 (i.e. only one side
 changed from the common ancestor).
 
diff --git a/Documentation/diff-format.txt b/Documentation/diff-format.txt
index 617d8f5..d0d08bb 100644
--- a/Documentation/diff-format.txt
+++ b/Documentation/diff-format.txt
@@ -35,9 +35,9 @@ That is, from the left to the right:
 . a space.
 . mode for "dst"; 000000 if deletion or unmerged.
 . a space.
-. sha1 for "src"; 0\{40\} if creation or unmerged.
+. SHA-1 for "src"; 0\{40\} if creation or unmerged.
 . a space.
-. sha1 for "dst"; 0\{40\} if creation, unmerged or "look at work tree".
+. SHA-1 for "dst"; 0\{40\} if creation, unmerged or "look at work tree".
 . a space.
 . status, followed by optional "score" number.
 . a tab or a NUL when '-z' option is used.
@@ -46,7 +46,7 @@ That is, from the left to the right:
 . path for "dst"; only exists for C or R.
 . an LF or a NUL when '-z' option is used, to terminate the record.
 
-<sha1> is shown as all 0's if a file is new on the filesystem
+<SHA-1> is shown as all 0's if a file is new on the filesystem
 and it is out of sync with the index.
 
 Example:
@@ -97,7 +97,7 @@ where:
 
      <old|new>-file:: are files GIT_EXTERNAL_DIFF can use to read the
 		      contents of <old|new>,
-     <old|new>-hex:: are the 40-hexdigit SHA1 hashes,
+     <old|new>-hex:: are the 40-hexdigit SHA-1 hashes,
      <old|new>-mode:: are the octal representation of the file modes.
 
 + 
diff --git a/Documentation/diffcore.txt b/Documentation/diffcore.txt
index cb4e562..984bb2b 100644
--- a/Documentation/diffcore.txt
+++ b/Documentation/diffcore.txt
@@ -115,7 +115,7 @@ it changes it to:
 For the purpose of breaking a filepair, diffcore-break examines
 the extent of changes between the contents of the files before
 and after modification (i.e. the contents that have "bcd1234..."
-and "0123456..." as their SHA1 content ID, in the above
+and "0123456..." as their SHA-1 content ID, in the above
 example).  The amount of deletion of original contents and
 insertion of new material are added together, and if it exceeds
 the "break score", the filepair is broken into two.  The break
diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index d43ef1d..e16944d 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -38,7 +38,7 @@ OPTIONS
 -l::
 	Create the branch's ref log.  This activates recording of
 	all changes to made the branch ref, enabling use of date
-	based sha1 expressions such as "<branchname>@{yesterday}".
+	based SHA-1 expressions such as "<branchname>@{yesterday}".
 
 -f::
 	Force the creation of a new branch even if it means deleting
diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt
index 5e9cbf8..8aa9fcb 100644
--- a/Documentation/git-cat-file.txt
+++ b/Documentation/git-cat-file.txt
@@ -19,7 +19,7 @@ or '-s' is used to find the object size.
 OPTIONS
 -------
 <object>::
-	The sha1 identifier of the object.
+	The SHA-1 identifier of the object.
 
 -t::
 	Instead of the content, show the object type identified by
diff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt
index fbdbadc..77db0b3 100644
--- a/Documentation/git-checkout.txt
+++ b/Documentation/git-checkout.txt
@@ -43,7 +43,7 @@ OPTIONS
 -l::
 	Create the new branch's ref log.  This activates recording of
 	all changes to made the branch ref, enabling use of date
-	based sha1 expressions such as "<branchname>@{yesterday}".
+	based SHA-1 expressions such as "<branchname>@{yesterday}".
 
 -m::
 	If you have local modifications to one or more files that
diff --git a/Documentation/git-cherry.txt b/Documentation/git-cherry.txt
index 893baaa..5c783d4 100644
--- a/Documentation/git-cherry.txt
+++ b/Documentation/git-cherry.txt
@@ -15,12 +15,12 @@ The changeset (or "diff") of each commit
 is compared against each commit between the fork-point and <upstream>.
 
 Every commit with a changeset that doesn't exist in the other branch
-has its id (sha1) reported, prefixed by a symbol.  Those existing only
+has its id (SHA-1) reported, prefixed by a symbol.  Those existing only
 in the <upstream> branch are prefixed with a minus (-) sign, and those
 that only exist in the <head> branch are prefixed with a plus (+) symbol.
 
 Because git-cherry compares the changeset rather than the commit id
-(sha1), you can use git-cherry to find out if a commit you made locally
+(SHA-1), you can use git-cherry to find out if a commit you made locally
 has been applied <upstream> under a different commit id.  For example,
 this will happen if you're feeding patches <upstream> via email rather
 than pushing or pulling commits directly.
diff --git a/Documentation/git-diff-index.txt b/Documentation/git-diff-index.txt
index 9cd43f1..750d646 100644
--- a/Documentation/git-diff-index.txt
+++ b/Documentation/git-diff-index.txt
@@ -93,7 +93,7 @@ you *could* commit. Again, the output ma
 output to a tee, but with a twist.
 
 The twist is that if some file doesn't match the index, we don't have
-a backing store thing for it, and we use the magic "all-zero" sha1 to
+a backing store thing for it, and we use the magic "all-zero" SHA-1 to
 show that. So let's say that you have edited `kernel/sched.c`, but
 have not actually done a "git-update-index" on it yet - there is no
 "object" associated with the new state, and you get:
@@ -102,7 +102,7 @@ have not actually done a "git-update-ind
   *100644->100664 blob    7476bb......->000000......      kernel/sched.c
 
 i.e., it shows that the tree has changed, and that `kernel/sched.c` has is
-not up-to-date and may contain new stuff. The all-zero sha1 means that to
+not up-to-date and may contain new stuff. The all-zero SHA-1 means that to
 get the real diff, you need to look at the object in the working directory
 directly rather than do an object-to-object diff.
 
@@ -115,8 +115,8 @@ touched it. In either case, it's a note 
 NOTE: You can have a mixture of files show up as "has been updated"
 and "is still dirty in the working directory" together. You can always
 tell which file is in which state, since the "has been updated" ones
-show a valid sha1, and the "not in sync with the index" ones will
-always have the special all-zero sha1.
+show a valid SHA-1, and the "not in sync with the index" ones will
+always have the special all-zero SHA-1.
 
 
 Author
diff --git a/Documentation/git-fsck-objects.txt b/Documentation/git-fsck-objects.txt
index d0af99d..78c6b59 100644
--- a/Documentation/git-fsck-objects.txt
+++ b/Documentation/git-fsck-objects.txt
@@ -22,7 +22,7 @@ OPTIONS
 	An object to treat as the head of an unreachability trace.
 +
 If no objects are given, git-fsck-objects defaults to using the
-index file and all SHA1 references in .git/refs/* as heads.
+index file and all SHA-1 references in .git/refs/* as heads.
 
 --unreachable::
 	Print out objects that exist but that aren't readable from any
@@ -55,7 +55,7 @@ index file and all SHA1 references in .g
 	objects that triggers this check, but it is recommended
 	to check new projects with this flag.
 
-It tests SHA1 and general object sanity, and it does full tracking of
+It tests SHA-1 and general object sanity, and it does full tracking of
 the resulting reachability and everything else. It prints out any
 corruption it finds (missing or bad objects), and if you use the
 '--unreachable' flag it will also print out objects that exist but
@@ -87,7 +87,7 @@ expect dangling commits - potential head
 	root nodes.
 
 missing sha1 directory '<dir>'::
-	The directory holding the sha1 objects is missing.
+	The directory holding the SHA-1 objects is missing.
 
 unreachable <type> <object>::
 	The <type> object <object>, isn't actually referred to directly
@@ -109,7 +109,7 @@ warning: git-fsck-objects: tree <tree> h
 	And it shouldn't...
 
 sha1 mismatch <object>::
-	The database has an object who's sha1 doesn't match the
+	The database has an object who's SHA-1 doesn't match the
 	database value.
 	This indicates a serious data integrity problem.
 
diff --git a/Documentation/git-init-db.txt b/Documentation/git-init-db.txt
index 8a150d8..9ebd7d2 100644
--- a/Documentation/git-init-db.txt
+++ b/Documentation/git-init-db.txt
@@ -39,7 +39,7 @@ If the `$GIT_DIR` environment variable i
 to use instead of `./.git` for the base of the repository.
 
 If the object storage directory is specified via the `$GIT_OBJECT_DIRECTORY`
-environment variable then the sha1 directories are created underneath -
+environment variable then the SHA-1 directories are created underneath -
 otherwise the default `$GIT_DIR/objects` directory is used.
 
 A shared repository allows users belonging to the same group to push into that
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt
index 4d8a2ad..be85561 100644
--- a/Documentation/git-ls-files.txt
+++ b/Documentation/git-ls-files.txt
@@ -123,7 +123,7 @@ which case it outputs:
 "git-ls-files --unmerged" and "git-ls-files --stage" can be used to examine
 detailed information on unmerged paths.
 
-For an unmerged path, instead of recording a single mode/SHA1 pair,
+For an unmerged path, instead of recording a single mode/SHA-1 pair,
 the dircache records up to three such pairs; one from tree O in stage
 1, A in stage 2, and B in stage 3.  This information can be used by
 the user (or the porcelain) to see what should eventually be recorded at the
diff --git a/Documentation/git-merge-index.txt b/Documentation/git-merge-index.txt
index 6cd0601..eb8e019 100644
--- a/Documentation/git-merge-index.txt
+++ b/Documentation/git-merge-index.txt
@@ -13,7 +13,7 @@ SYNOPSIS
 DESCRIPTION
 -----------
 This looks up the <file>(s) in the index and, if there are any merge
-entries, passes the SHA1 hash for those files as arguments 1, 2, 3 (empty
+entries, passes the SHA-1 hash for those files as arguments 1, 2, 3 (empty
 argument if no file), and <file> as argument 4.  File modes for the three
 files are passed as arguments 5, 6 and 7.
 
diff --git a/Documentation/git-mktag.txt b/Documentation/git-mktag.txt
index 2860a3d..d78d2dc 100644
--- a/Documentation/git-mktag.txt
+++ b/Documentation/git-mktag.txt
@@ -19,9 +19,9 @@ The output is the new tag's <object> ide
 
 Tag Format
 ----------
-A tag signature file has a very simple fixed format: three lines of
+A tag signature file has a very simple fixed format: Three lines of
 
-  object <sha1>
+  object <SHA-1>
   type <typename>
   tag <tagname>
 
@@ -30,7 +30,7 @@ doesn't care about, but that can be veri
 
 The size of the full object is artificially limited to 8kB.  (Just
 because I'm a lazy bastard, and if you can't fit a signature in that
-size, you're doing something wrong)
+size, you're doing something wrong.)
 
 
 Author
diff --git a/Documentation/git-name-rev.txt b/Documentation/git-name-rev.txt
index 39a1434..0c8e8e3 100644
--- a/Documentation/git-name-rev.txt
+++ b/Documentation/git-name-rev.txt
@@ -26,7 +26,7 @@ OPTIONS
 	List all commits reachable from all refs
 
 --stdin::
-	Read from stdin, append "(<rev_name>)" to all sha1's of name'able
+	Read from stdin, append "(<rev_name>)" to all SHA-1s of name'able
 	commits, and pass to stdout
 
 EXAMPLE
diff --git a/Documentation/git-patch-id.txt b/Documentation/git-patch-id.txt
index 5389097..f57d2b2 100644
--- a/Documentation/git-patch-id.txt
+++ b/Documentation/git-patch-id.txt
@@ -11,7 +11,7 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-A "patch ID" is nothing but a SHA1 of the diff associated with a patch, with
+A "patch ID" is nothing but a SHA-1 of the diff associated with a patch, with
 whitespace and line numbers ignored.  As such, it's "reasonably stable", but at
 the same time also reasonably unique, i.e., two patches that have the same "patch
 ID" are almost guaranteed to be the same thing.
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index d5b5ca1..3cb33d7 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt
@@ -34,7 +34,7 @@ OPTIONS
 	the destination ref.
 +
 The <src> side can be an
-arbitrary "SHA1 expression" that can be used as an
+arbitrary "SHA-1 expression" that can be used as an
 argument to `git-cat-file -t`.  E.g. `master~4` (push
 four parents before the current master head).
 +
diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt
index 60debca..ad91e24 100644
--- a/Documentation/git-receive-pack.txt
+++ b/Documentation/git-receive-pack.txt
@@ -21,7 +21,7 @@ program pair is meant to be used to push
 repository.  For pull operations, see 'git-fetch-pack' and
 'git-clone-pack'.
 
-The command allows for creation and fast forwarding of sha1 refs
+The command allows for creation and fast forwarding of SHA-1 refs
 (heads/tags) on the remote end (strictly speaking, it is the
 local end receive-pack runs, but to the user who is sitting at
 the send-pack end, it is updating the remote.  Confused?)
@@ -32,7 +32,7 @@ and executable, it is called with three 
        $GIT_DIR/hooks/update refname sha1-old sha1-new
 
 The refname parameter is relative to $GIT_DIR; e.g. for the
-master head this is "refs/heads/master".  Two sha1 are the
+master head this is "refs/heads/master".  Two SHA-1s are the
 object names for the refname before and after the update.  Note
 that the hook is called before the refname is updated, so either
 sha1-old is 0{40} (meaning there is no such ref yet), or it
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 627cde8..25098bd 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -59,7 +59,7 @@ OPTIONS
 	one.
 
 --symbolic::
-	Usually the object names are output in SHA1 form (with
+	Usually the object names are output in SHA-1 form (with
 	possible '{caret}' prefix); this option makes them output in a
 	form as close to the original input as possible.
 
@@ -90,7 +90,7 @@ OPTIONS
 	Show `$GIT_DIR` if defined else show the path to the .git directory.
 
 --short, --short=number::
-	Instead of outputting the full SHA1 values of object names try to
+	Instead of outputting the full SHA-1 values of object names try to
 	abbreviate them to a shorter unique name. When no length is specified
 	7 is used. The minimum length is 4.
 
@@ -110,10 +110,10 @@ SPECIFYING REVISIONS
 --------------------
 
 A revision parameter typically, but not necessarily, names a
-commit object.  They use what is called an 'extended SHA1'
+commit object.  They use what is called an 'extended SHA-1'
 syntax.
 
-* The full SHA1 object name (40-byte hexadecimal string), or
+* The full SHA-1 object name (40-byte hexadecimal string), or
   a substring of such that is unique within the repository.
   E.g. dae86e1950b1277e545cee180551750029cfe735 and dae86e both
   name the same commit object if there are no other object in
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index f115b45..8937428 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -28,7 +28,7 @@ no <rev> nor <glob> is given on the comm
 OPTIONS
 -------
 <rev>::
-	Arbitrary extended SHA1 expression (see `git-rev-parse`)
+	Arbitrary extended SHA-1 expression (see `git-rev-parse`)
 	that typically names a branch HEAD or a tag.
 
 <glob>::
@@ -97,7 +97,7 @@ displayed, indented N places.  If a comm
 branch, the I-th indentation character shows a `+` sign;
 otherwise it shows a space.  Merge commits are denoted by
 a `-` sign.  Each commit shows a short name that
-can be used as an extended SHA1 to name that commit.
+can be used as an extended SHA-1 to name that commit.
 
 The following example shows three branches, "master", "fixes"
 and "mhf":
diff --git a/Documentation/git-show-index.txt b/Documentation/git-show-index.txt
index be09b62..04f1d22 100644
--- a/Documentation/git-show-index.txt
+++ b/Documentation/git-show-index.txt
@@ -18,7 +18,7 @@ git-pack-objects command, and dumps its 
 
 The information it outputs is subset of what you can get from
 'git-verify-pack -v'; this command only shows the packfile
-offset and SHA1 of each object.
+offset and SHA-1 of each object.
 
 
 Author
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 45476c2..f0f7d8c 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -24,7 +24,7 @@ creates a 'tag' object, and requires the
 `-m <msg>` is given, an editor is started for the user to type
 in the tag message.
 
-Otherwise just the SHA1 object name of the commit object is
+Otherwise just the SHA-1 object name of the commit object is
 written (i.e. a lightweight tag).
 
 A GnuPG signed tag object will be created when `-s` or `-u
diff --git a/Documentation/git-unpack-file.txt b/Documentation/git-unpack-file.txt
index 213dc81..c7b3be1 100644
--- a/Documentation/git-unpack-file.txt
+++ b/Documentation/git-unpack-file.txt
@@ -13,7 +13,7 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Creates a file holding the contents of the blob specified by sha1. It
+Creates a file holding the contents of the blob specified by SHA-1. It
 returns the name of the temporary file in the following format:
 	.merge_file_XXXXX
 
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 3ae6e74..6135601 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -129,7 +129,7 @@ OPTIONS
 
 Using --refresh
 ---------------
-'--refresh' does not calculate a new sha1 file or bring the index
+'--refresh' does not calculate a new SHA-1 file or bring the index
 up-to-date for mode/content changes. But what it *does* do is to
 "re-match" the stat information of a file with the index, so that you
 can refresh the index for a file that hasn't been changed but where
@@ -144,10 +144,10 @@ Using --cacheinfo or --info-only
 current working directory.  This is useful for minimum-checkout
 merging.
 
-To pretend you have a file with mode and sha1 at path, say:
+To pretend you have a file with mode and SHA-1 at path, say:
 
 ----------------
-$ git-update-index --cacheinfo mode sha1 path
+$ git-update-index --cacheinfo mode SHA-1 path
 ----------------
 
 '--info-only' is used to register files without placing them in the object
@@ -167,19 +167,19 @@ Using --index-info
 multiple entry definitions from the standard input, and designed
 specifically for scripts.  It can take inputs of three formats:
 
-    . mode         SP sha1          TAB path
+    . mode         SP SHA-1          TAB path
 +
 The first format is what "git-apply --index-info"
 reports, and used to reconstruct a partial tree
 that is used for phony merge base tree when falling
 back on 3-way merge.
 
-    . mode SP type SP sha1          TAB path
+    . mode SP type SP SHA-1          TAB path
 +
 The second format is to stuff git-ls-tree output
 into the index file.
 
-    . mode         SP sha1 SP stage TAB path
+    . mode         SP SHA-1 SP stage TAB path
 +
 This format is to put higher order stages into the
 index file and matches git-ls-files --stage output.
@@ -205,7 +205,7 @@ you can feed the following input to `--i
 ------------
 
 The first line of the input feeds 0 as the mode to remove the
-path; the SHA1 does not matter as long as it is well formatted.
+path; the SHA-1 does not matter as long as it is well formatted.
 Then the second and third line feeds stage 1 and stage 2 entries
 for that path.  After the above, we would end up with this:
 
diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt
index 7a6132b..4fa5923 100644
--- a/Documentation/git-verify-pack.txt
+++ b/Documentation/git-verify-pack.txt
@@ -32,11 +32,11 @@ OUTPUT FORMAT
 -------------
 When specifying the -v option the format used is:
 
-	SHA1 type size offset-in-packfile
+	SHA-1 type size offset-in-packfile
 
 for objects that are not deltified in the pack, and
 
-	SHA1 type size offset-in-packfile depth base-SHA1
+	SHA-1 type size offset-in-packfile depth base-SHA1
 
 for objects that are deltified.
 
diff --git a/Documentation/git-verify-tag.txt b/Documentation/git-verify-tag.txt
index 0f9bdb5..d610a8b 100644
--- a/Documentation/git-verify-tag.txt
+++ b/Documentation/git-verify-tag.txt
@@ -16,7 +16,7 @@ Validates the gpg signature created by g
 OPTIONS
 -------
 <tag>::
-	SHA1 identifier of a git tag object.
+	SHA-1 identifier of a git tag object.
 
 Author
 ------
diff --git a/Documentation/git.txt b/Documentation/git.txt
index d4472b5..2d454f8 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -585,7 +585,7 @@ git so take care if using Cogito etc.
 
 'GIT_OBJECT_DIRECTORY'::
 	If the object storage directory is specified via this
-	environment variable then the sha1 directories are created
+	environment variable then the SHA-1 directories are created
 	underneath - otherwise the default `$GIT_DIR/objects`
 	directory is used.
 
diff --git a/Documentation/glossary.txt b/Documentation/glossary.txt
index 116ddb7..e83cd42 100644
--- a/Documentation/glossary.txt
+++ b/Documentation/glossary.txt
@@ -163,7 +163,7 @@ merge::
 
 object::
 	The unit of storage in git. It is uniquely identified by
-	the SHA1 of its contents. Consequently, an object can not
+	the SHA-1 of its contents. Consequently, an object can not
 	be changed.
 
 object database::
@@ -243,7 +243,7 @@ rebase::
 	changes from that branch.
 
 ref::
-	A 40-byte hex representation of a SHA1 or a name that denotes
+	A 40-byte hex representation of a SHA-1 or a name that denotes
 	a particular object. These may be stored in `$GIT_DIR/refs/`.
 
 refspec::
diff --git a/Documentation/tutorial-2.txt b/Documentation/tutorial-2.txt
index 894ca5e..0dc91e7 100644
--- a/Documentation/tutorial-2.txt
+++ b/Documentation/tutorial-2.txt
@@ -32,9 +32,9 @@ with?
 
 We saw in part one of the tutorial that commits have names like this.
 It turns out that every object in the git history is stored under
-such a 40-digit hex name.  That name is the SHA1 hash of the object's
+such a 40-digit hex name.  That name is the SHA-1 hash of the object's
 contents; among other things, this ensures that git will never store
-the same data twice (since identical data is given an identical SHA1
+the same data twice (since identical data is given an identical SHA-1
 name), and that the contents of a git object will never change (since
 that would change the object's name as well).
 
@@ -51,14 +51,14 @@ A tree can refer to one or more "blob" o
 a file.  In addition, a tree can also refer to other tree objects,
 thus creating a directory hierarchy.  You can examine the contents of
 any tree using ls-tree (remember that a long enough initial portion
-of the SHA1 will also work):
+of the SHA-1 will also work):
 
 ------------------------------------------------
 $ git ls-tree 92b8b694
 100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad    file.txt
 ------------------------------------------------
 
-Thus we see that this tree has one file in it.  The SHA1 hash is a
+Thus we see that this tree has one file in it.  The SHA-1 hash is a
 reference to that file's data:
 
 ------------------------------------------------
@@ -77,7 +77,7 @@ Note that this is the old file data; so 
 its response to the initial tree was a tree with a snapshot of the
 directory state that was recorded by the first commit.
 
-All of these objects are stored under their SHA1 names inside the git
+All of these objects are stored under their SHA-1 names inside the git
 directory:
 
 ------------------------------------------------
@@ -114,7 +114,7 @@ ref: refs/heads/master
 
 As you can see, this tells us which branch we're currently on, and it
 tells us this by naming a file under the .git directory, which itself
-contains a SHA1 name referring to a commit object, which we can
+contains a SHA-1 name referring to a commit object, which we can
 examine with cat-file:
 
 ------------------------------------------------
@@ -180,7 +180,7 @@ project's history:
 
 Note, by the way, that lots of commands take a tree as an argument.
 But as we can see above, a tree can be referred to in many different
-ways--by the SHA1 name for that tree, by the name of a commit that
+ways--by the SHA-1 name for that tree, by the name of a commit that
 refers to the tree, by the name of a branch whose head refers to that
 tree, etc.--and most such commands can accept any of these names.
 
-- 
1.4.0.g1b2d

^ permalink raw reply related	[relevance 1%]

* Re: [RFC] GIT user survey
  @ 2006-06-29  9:49  4%     ` Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2006-06-29  9:49 UTC (permalink / raw)
  To: git

Matthias Kestenholz <lists@spinlock.ch> wrote:
> Adrien Beau (adrienbeau@gmail.com) wrote:
>> 
>> The results of the Mercurial survey have been posted there:
>> http://www.selenic.com/mercurial/wiki/index.cgi/UserSurvey
>> 
>> An interesting read.
> 
> I find the answers to the question, what people most like to see
> improved interesting: The improvement which got mentioned most often
> was "merge across rename", something which git does already.
> 
> It seems, that partial checkouts and truncated history are the
> only things left to implement for git from this list.

I think that at least some of the infrastructure for partial checkouts
is in place due to preliminary work for subproject (gitlink or bind)
support in git: git-read-tree and git-write-tree --prefix=<prefix>/
option suppport. But I might be mistaken.

Truncating history "by hand" is possible even now, using graft file.
There is recurring talk about "shallow clones", lately about "lazy clones".
There were mentioned here also split-history idea and sparse clone idea.  

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[relevance 4%]

* Re: Java GIT/Eclipse GIT version 0.1.1
  @ 2006-07-28  6:49  1% ` Peter Baumann
  2006-07-28  7:08  1%   ` Pavel Roskin
  0 siblings, 1 reply; 200+ results
From: Peter Baumann @ 2006-07-28  6:49 UTC (permalink / raw)
  To: git

On 2006-07-28, Shawn Pearce <spearce@spearce.org> wrote:
> My Java GIT library and Eclipse GIT team provider is now at a point
> where it may be partially useful to someone else who is also trying
> to write something which interacts with GIT.  Or who might also
> be interested in seeing a pure-Java Eclipse team provider for GIT.
>
> So I've posted my repository (currently ~200 KB) on my website:
>
>   http://www.spearce.org/projects/scm/egit.git
>

Doesn't work for me.

devil:~/src git clone http://www.spearce.org/projects/scm/egit.git
error: File ac32c7cc2f7cf87a1ed80d0cdfca2af2a0385bb2 (http://www.spearce.org/projects/scm/egit.git/objects/ac/32c7cc2f7cf87a1ed80d0cdfca2af2a0385bb2) corrupt
Getting pack list for http://www.spearce.org/projects/scm/egit.git/
Getting alternates list for http://www.spearce.org/projects/scm/egit.git/
Also look at <html xmlns="http://www.w3.org/1999/
Also look at    <title>Insufficiently Random: The lonely musings of a loosely connected software developer.<
Also look at            @import url( http://www.spearce.org/wordpress/wp-content/themes/ir-classic/style
Also look at    <link rel="pingback" href="http://www.spearce.org/wordpress/xmlrpc.
Also look at            <link rel='archives' title='April 2006' href='http://www.spearce.org/2006/
Also look at    <link rel='archives' title='February 2006' href='http://www.spearce.org/2006/
[...]
Also look at <li><a href="feed:http://www.spearce.org/comments/feed/" title="The latest comments to all posts in RSS">Comments <abbr title="Really Simple Syndication">RSS</abbr></
*** glibc detected *** double free or corruption (!prev): 0x080933b0 ***
/usr/bin/git-clone: line 29: 10712 Aborted                 git-http-fetch -v -a -w "$tname" "$name" "$1/"

-Peter

^ permalink raw reply	[relevance 1%]

* Re: Java GIT/Eclipse GIT version 0.1.1
  2006-07-28  6:49  1% ` Peter Baumann
@ 2006-07-28  7:08  1%   ` Pavel Roskin
  2006-07-28  7:23  0%     ` Peter Baumann
  2006-07-29  3:32  1%     ` Shawn Pearce
  0 siblings, 2 replies; 200+ results
From: Pavel Roskin @ 2006-07-28  7:08 UTC (permalink / raw)
  To: Peter Baumann; +Cc: git

Quoting Peter Baumann <Peter.B.Baumann@stud.informatik.uni-erlangen.de>:

> On 2006-07-28, Shawn Pearce <spearce@spearce.org> wrote:
> > My Java GIT library and Eclipse GIT team provider is now at a point
> > where it may be partially useful to someone else who is also trying
> > to write something which interacts with GIT.  Or who might also
> > be interested in seeing a pure-Java Eclipse team provider for GIT.
> >
> > So I've posted my repository (currently ~200 KB) on my website:
> >
> >   http://www.spearce.org/projects/scm/egit.git
> >
>
> Doesn't work for me.

Neither does it for me:

$ git clone http://www.spearce.org/projects/scm/egit.git
error: File ac32c7cc2f7cf87a1ed80d0cdfca2af2a0385bb2
(http://www.spearce.org/projects/scm/egit.git/objects/ac/32c7cc2f7cf87a1ed80d0cdfca2af2a0385bb2)
corrupt
Getting pack list for http://www.spearce.org/projects/scm/egit.git/
error: XML error: not well-formed (invalid token)

> *** glibc detected *** double free or corruption (!prev): 0x080933b0 ***
> /usr/bin/git-clone: line 29: 10712 Aborted                 git-http-fetch -v
> -a -w "$tname" "$name" "$1/"

I'm not getting that.  I hope you are just using an obsolete version of git.

--
Regards,
Pavel Roskin

^ permalink raw reply	[relevance 1%]

* Re: Java GIT/Eclipse GIT version 0.1.1
  2006-07-28  7:08  1%   ` Pavel Roskin
@ 2006-07-28  7:23  0%     ` Peter Baumann
  2006-07-29  3:32  1%     ` Shawn Pearce
  1 sibling, 0 replies; 200+ results
From: Peter Baumann @ 2006-07-28  7:23 UTC (permalink / raw)
  To: git

On 2006-07-28, Pavel Roskin <proski@gnu.org> wrote:
> Quoting Peter Baumann <Peter.B.Baumann@stud.informatik.uni-erlangen.de>:
>
>> On 2006-07-28, Shawn Pearce <spearce@spearce.org> wrote:
>> > My Java GIT library and Eclipse GIT team provider is now at a point
>> > where it may be partially useful to someone else who is also trying
>> > to write something which interacts with GIT.  Or who might also
>> > be interested in seeing a pure-Java Eclipse team provider for GIT.
>> >
>> > So I've posted my repository (currently ~200 KB) on my website:
>> >
>> >   http://www.spearce.org/projects/scm/egit.git
>> >
>>
>> Doesn't work for me.
>
> Neither does it for me:
>
> $ git clone http://www.spearce.org/projects/scm/egit.git
> error: File ac32c7cc2f7cf87a1ed80d0cdfca2af2a0385bb2
> (http://www.spearce.org/projects/scm/egit.git/objects/ac/32c7cc2f7cf87a1ed80d0cdfca2af2a0385bb2)
> corrupt
> Getting pack list for http://www.spearce.org/projects/scm/egit.git/
> error: XML error: not well-formed (invalid token)
>
>> *** glibc detected *** double free or corruption (!prev): 0x080933b0 ***
>> /usr/bin/git-clone: line 29: 10712 Aborted                 git-http-fetch -v
>> -a -w "$tname" "$name" "$1/"
>
> I'm not getting that.  I hope you are just using an obsolete version of git.

Not _that_ old, me thinks. I'm using the debian unstable version.

devil:~ dpkg -l |grep git-core
ii  git-core       1.4.1-1        content addressable filesystem

(Yes, I'am aware that this version has the timing bug on the server
side, but I was just too lazy to compile git myself this time :-)

-Peter

^ permalink raw reply	[relevance 0%]

* Re: Java GIT/Eclipse GIT version 0.1.1
  2006-07-28  7:08  1%   ` Pavel Roskin
  2006-07-28  7:23  0%     ` Peter Baumann
@ 2006-07-29  3:32  1%     ` Shawn Pearce
  1 sibling, 0 replies; 200+ results
From: Shawn Pearce @ 2006-07-29  3:32 UTC (permalink / raw)
  To: Pavel Roskin; +Cc: Peter Baumann, git

Pavel Roskin <proski@gnu.org> wrote:
> Quoting Peter Baumann <Peter.B.Baumann@stud.informatik.uni-erlangen.de>:
> 
> > On 2006-07-28, Shawn Pearce <spearce@spearce.org> wrote:
> > > My Java GIT library and Eclipse GIT team provider is now at a point
> > > where it may be partially useful to someone else who is also trying
> > > to write something which interacts with GIT.  Or who might also
> > > be interested in seeing a pure-Java Eclipse team provider for GIT.
> > >
> > > So I've posted my repository (currently ~200 KB) on my website:
> > >
> > >   http://www.spearce.org/projects/scm/egit.git
> > >
> >
> > Doesn't work for me.
> 
> Neither does it for me:
> 
> $ git clone http://www.spearce.org/projects/scm/egit.git
> error: File ac32c7cc2f7cf87a1ed80d0cdfca2af2a0385bb2
> (http://www.spearce.org/projects/scm/egit.git/objects/ac/32c7cc2f7cf87a1ed80d0cdfca2af2a0385bb2)
> corrupt
> Getting pack list for http://www.spearce.org/projects/scm/egit.git/
> error: XML error: not well-formed (invalid token)

Hmm.  My website is known to return 200 OK status codes on missing
files with HTML pages rather than proper 404 Not Found.  I guess
I need to get that fixed.

I just compiled and installed `next` (1.4.2.rc1.g802da) and it can
clone this repository just fine over HTTP, despite my broken server.
So I'm not really sure what is going on.

I should look into fixing my server, but its low on my priority list.

-- 
Shawn.

^ permalink raw reply	[relevance 1%]

* [PATCH] Workaround for strange cmp bug
@ 2006-08-09 10:24  2% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2006-08-09 10:24 UTC (permalink / raw)
  To: git, junkio


The cmp(1) (cmp (GNU diffutils) 2.8.7) distributed with openSUSE 10.1 has
a subtle "shortcoming":

	$ echo a > a
	$ echo b > b
	$ cmp a b && echo nonono
	a b differ: char 1, line 1
	$ cmp a b >/dev/null && echo nonono
	nonono
	$ cmp -s a b >/dev/null && echo nonono

So, if cmp should _not_ be quiet, _and_ the output is redirected to
/dev/null, it has a bogus exit value. Our test suite redirects to
/dev/null, which triggers that bug. (Obviously, the tests pass when
running with '-v', which made that a real bugger to debug.)

Since we have all too many '&&' cascades in the test scripts, and you
have to run 'bash -x t*.sh' anyway, the output of cmp when running
the tests with '-v' is not too helpful. Therefore we can replace all
calls to cmp with 'cmp -s'.

This patch was produced by

	$ perl -i.bak -pe 's/cmp ([^-])/cmp -s $1/' t/*.sh

Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
 t/t1002-read-tree-m-u-2way.sh    |   32 +++++++++++++++---------------
 t/t1003-read-tree-prefix.sh      |    2 +-
 t/t1020-subdirectory.sh          |   16 ++++++++-------
 t/t1200-tutorial.sh              |   22 ++++++++++-----------
 t/t1300-repo-config.sh           |   40 +++++++++++++++++++-------------------
 t/t2101-update-index-reupdate.sh |   12 ++++++-----
 t/t3300-funny-names.sh           |    2 +-
 t/t4012-diff-binary.sh           |    4 ++--
 t/t4109-apply-multifrag.sh       |   12 ++++++-----
 t/t4110-apply-scan.sh            |    2 +-
 t/t5300-pack-object.sh           |   12 ++++++-----
 t/t5400-send-pack.sh             |    4 ++--
 t/t6021-merge-criss-cross.sh     |    2 +-
 t/t9101-git-svn-props.sh         |    2 +-
 t/t9105-git-svn-commit-diff.sh   |    2 +-
 15 files changed, 83 insertions(+), 83 deletions(-)

diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh
index da3c813..6be4ee2 100755
--- a/t/t1002-read-tree-m-u-2way.sh
+++ b/t/t1002-read-tree-m-u-2way.sh
@@ -59,9 +59,9 @@ test_expect_success \
      git-read-tree --reset -u $treeH &&
      git-read-tree -m -u $treeH $treeM &&
      git-ls-files --stage >1-3.out &&
-     cmp M.out 1-3.out &&
+     cmp -s M.out 1-3.out &&
      sum bozbar frotz nitfol >actual3.sum &&
-     cmp M.sum actual3.sum &&
+     cmp -s M.sum actual3.sum &&
      check_cache_at bozbar clean &&
      check_cache_at frotz clean &&
      check_cache_at nitfol clean'
@@ -79,7 +79,7 @@ test_expect_success \
      compare_change 4diff.out expected &&
      check_cache_at yomin clean &&
      sum bozbar frotz nitfol >actual4.sum &&
-     cmp M.sum actual4.sum &&
+     cmp -s M.sum actual4.sum &&
      echo yomin >yomin1 &&
      diff yomin yomin1 &&
      rm -f yomin1'
@@ -98,7 +98,7 @@ test_expect_success \
      compare_change 5diff.out expected &&
      check_cache_at yomin dirty &&
      sum bozbar frotz nitfol >actual5.sum &&
-     cmp M.sum actual5.sum &&
+     cmp -s M.sum actual5.sum &&
      : dirty index should have prevented -u from checking it out. &&
      echo yomin yomin >yomin1 &&
      diff yomin yomin1 &&
@@ -115,7 +115,7 @@ test_expect_success \
      diff -U0 M.out 6.out &&
      check_cache_at frotz clean &&
      sum bozbar frotz nitfol >actual3.sum &&
-     cmp M.sum actual3.sum &&
+     cmp -s M.sum actual3.sum &&
      echo frotz >frotz1 &&
      diff frotz frotz1 &&
      rm -f frotz1'
@@ -132,7 +132,7 @@ test_expect_success \
      diff -U0 M.out 7.out &&
      check_cache_at frotz dirty &&
      sum bozbar frotz nitfol >actual7.sum &&
-     if cmp M.sum actual7.sum; then false; else :; fi &&
+     if cmp -s M.sum actual7.sum; then false; else :; fi &&
      : dirty index should have prevented -u from checking it out. &&
      echo frotz frotz >frotz1 &&
      diff frotz frotz1 &&
@@ -163,9 +163,9 @@ test_expect_success \
      git-update-index --add rezrov &&
      git-read-tree -m -u $treeH $treeM &&
      git-ls-files --stage >10.out &&
-     cmp M.out 10.out &&
+     cmp -s M.out 10.out &&
      sum bozbar frotz nitfol >actual10.sum &&
-     cmp M.sum actual10.sum'
+     cmp -s M.sum actual10.sum'
 
 test_expect_success \
     '11 - dirty path removed.' \
@@ -210,9 +210,9 @@ test_expect_success \
      compare_change 14diff.out expected &&
      sum bozbar frotz >actual14.sum &&
      grep -v nitfol M.sum > expected14.sum &&
-     cmp expected14.sum actual14.sum &&
+     cmp -s expected14.sum actual14.sum &&
      sum bozbar frotz nitfol >actual14a.sum &&
-     if cmp M.sum actual14a.sum; then false; else :; fi &&
+     if cmp -s M.sum actual14a.sum; then false; else :; fi &&
      check_cache_at nitfol clean &&
      echo nitfol nitfol >nitfol1 &&
      diff nitfol nitfol1 &&
@@ -232,9 +232,9 @@ test_expect_success \
      check_cache_at nitfol dirty &&
      sum bozbar frotz >actual15.sum &&
      grep -v nitfol M.sum > expected15.sum &&
-     cmp expected15.sum actual15.sum &&
+     cmp -s expected15.sum actual15.sum &&
      sum bozbar frotz nitfol >actual15a.sum &&
-     if cmp M.sum actual15a.sum; then false; else :; fi &&
+     if cmp -s M.sum actual15a.sum; then false; else :; fi &&
      echo nitfol nitfol nitfol >nitfol1 &&
      diff nitfol nitfol1 &&
      rm -f nitfol1'
@@ -267,7 +267,7 @@ test_expect_success \
      diff -U0 M.out 18.out &&
      check_cache_at bozbar clean &&
      sum bozbar frotz nitfol >actual18.sum &&
-     cmp M.sum actual18.sum'
+     cmp -s M.sum actual18.sum'
 
 test_expect_success \
     '19 - local change already having a good result, further modified.' \
@@ -282,9 +282,9 @@ test_expect_success \
      check_cache_at bozbar dirty &&
      sum frotz nitfol >actual19.sum &&
      grep -v bozbar  M.sum > expected19.sum &&
-     cmp expected19.sum actual19.sum &&
+     cmp -s expected19.sum actual19.sum &&
      sum bozbar frotz nitfol >actual19a.sum &&
-     if cmp M.sum actual19a.sum; then false; else :; fi &&
+     if cmp -s M.sum actual19a.sum; then false; else :; fi &&
      echo gnusto gnusto >bozbar1 &&
      diff bozbar bozbar1 &&
      rm -f bozbar1'
@@ -300,7 +300,7 @@ test_expect_success \
      diff -U0 M.out 20.out &&
      check_cache_at bozbar clean &&
      sum bozbar frotz nitfol >actual20.sum &&
-     cmp M.sum actual20.sum'
+     cmp -s M.sum actual20.sum'
 
 test_expect_success \
     '21 - no local change, dirty cache.' \
diff --git a/t/t1003-read-tree-prefix.sh b/t/t1003-read-tree-prefix.sh
index 48ab117..a7156b2 100755
--- a/t/t1003-read-tree-prefix.sh
+++ b/t/t1003-read-tree-prefix.sh
@@ -21,7 +21,7 @@ two/one' >expect
 test_expect_success 'read-tree --prefix' '
 	git-read-tree --prefix=two/ $tree &&
 	git-ls-files >actual &&
-	cmp expect actual
+	cmp -s expect actual
 '
 
 test_done
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index 4409b87..8bd4174 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -46,10 +46,10 @@ test_expect_success 'cat-file' '
 	two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
 	echo "$two" &&
 	git-cat-file -p "$two" >actual &&
-	cmp dir/two actual &&
+	cmp -s dir/two actual &&
 	cd dir &&
 	git-cat-file -p "$two" >actual &&
-	cmp two actual
+	cmp -s two actual
 '
 rm -f actual dir/actual
 
@@ -86,10 +86,10 @@ test_expect_success 'write-tree' '
 test_expect_success 'checkout-index' '
 	cd $HERE &&
 	git-checkout-index -f -u one &&
-	cmp one original.one &&
+	cmp -s one original.one &&
 	cd dir &&
 	git-checkout-index -f -u two &&
-	cmp two ../original.two
+	cmp -s two ../original.two
 '
 
 test_expect_success 'read-tree' '
@@ -97,13 +97,13 @@ test_expect_success 'read-tree' '
 	rm -f one dir/two &&
 	tree=`git-write-tree` &&
 	git-read-tree --reset -u "$tree" &&
-	cmp one original.one &&
-	cmp dir/two original.two &&
+	cmp -s one original.one &&
+	cmp -s dir/two original.two &&
 	cd dir &&
 	rm -f two &&
 	git-read-tree --reset -u "$tree" &&
-	cmp two ../original.two &&
-	cmp ../one ../original.one
+	cmp -s two ../original.two &&
+	cmp -s ../one ../original.one
 '
 
 test_done
diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
index c7db20e..2e2a898 100755
--- a/t/t1200-tutorial.sh
+++ b/t/t1200-tutorial.sh
@@ -27,9 +27,9 @@ index 557db03..263414f 100644
 +It's a new day for git
 EOF
 git-diff-files -p > diff.output
-test_expect_success 'git-diff-files -p' 'cmp diff.expect diff.output'
+test_expect_success 'git-diff-files -p' 'cmp -s diff.expect diff.output'
 git diff > diff.output
-test_expect_success 'git diff' 'cmp diff.expect diff.output'
+test_expect_success 'git diff' 'cmp -s diff.expect diff.output'
 
 tree=$(git-write-tree 2>/dev/null)
 
@@ -40,10 +40,10 @@ output="$(echo "Initial commit" | git-co
 test_expect_success 'commit' "test 'Committing initial tree 8988da15d077d4829fc51d8544c097def6644dbb' = \"$output\""
 
 git-diff-index -p HEAD > diff.output
-test_expect_success 'git-diff-index -p HEAD' 'cmp diff.expect diff.output'
+test_expect_success 'git-diff-index -p HEAD' 'cmp -s diff.expect diff.output'
 
 git diff HEAD > diff.output
-test_expect_success 'git diff HEAD' 'cmp diff.expect diff.output'
+test_expect_success 'git diff HEAD' 'cmp -s diff.expect diff.output'
 
 #rm hello
 #test_expect_success 'git-read-tree --reset HEAD' "git-read-tree --reset HEAD ; test \"hello: needs update\" = \"$(git-update-index --refresh)\""
@@ -75,15 +75,15 @@ git-whatchanged -p --root | \
 	sed -e "1s/^\(.\{7\}\).\{40\}/\1VARIABLE/" \
 		-e "2,3s/^\(.\{8\}\).*$/\1VARIABLE/" \
 > whatchanged.output
-test_expect_success 'git-whatchanged -p --root' 'cmp whatchanged.expect whatchanged.output'
+test_expect_success 'git-whatchanged -p --root' 'cmp -s whatchanged.expect whatchanged.output'
 
 git tag my-first-tag
-test_expect_success 'git tag my-first-tag' 'cmp .git/refs/heads/master .git/refs/tags/my-first-tag'
+test_expect_success 'git tag my-first-tag' 'cmp -s .git/refs/heads/master .git/refs/tags/my-first-tag'
 
 # TODO: test git-clone
 
 git checkout -b mybranch
-test_expect_success 'git checkout -b mybranch' 'cmp .git/refs/heads/master .git/refs/heads/mybranch'
+test_expect_success 'git checkout -b mybranch' 'cmp -s .git/refs/heads/master .git/refs/heads/mybranch'
 
 cat > branch.expect <<EOF
   master
@@ -91,7 +91,7 @@ cat > branch.expect <<EOF
 EOF
 
 git branch > branch.output
-test_expect_success 'git branch' 'cmp branch.expect branch.output'
+test_expect_success 'git branch' 'cmp -s branch.expect branch.output'
 
 git checkout mybranch
 echo "Work, work, work" >>hello
@@ -125,7 +125,7 @@ cat > show-branch.expect << EOF
 EOF
 
 git show-branch --topo-order master mybranch > show-branch.output
-test_expect_success 'git show-branch' 'cmp show-branch.expect show-branch.output'
+test_expect_success 'git show-branch' 'cmp -s show-branch.expect show-branch.output'
 
 git checkout mybranch
 
@@ -138,7 +138,7 @@ EOF
 
 git resolve HEAD master "Merge upstream changes." | \
 	sed -e "1s/[0-9a-f]\{40\}/VARIABLE/g" > resolve.output
-test_expect_success 'git resolve' 'cmp resolve.expect resolve.output'
+test_expect_success 'git resolve' 'cmp -s resolve.expect resolve.output'
 
 cat > show-branch2.expect << EOF
 ! [master] Merged "mybranch" changes.
@@ -148,7 +148,7 @@ cat > show-branch2.expect << EOF
 EOF
 
 git show-branch --topo-order master mybranch > show-branch2.output
-test_expect_success 'git show-branch' 'cmp show-branch2.expect show-branch2.output'
+test_expect_success 'git show-branch' 'cmp -s show-branch2.expect show-branch2.output'
 
 # TODO: test git fetch
 
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 0de2497..5af856d 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -16,7 +16,7 @@ cat > expect << EOF
 	penguin = little blue
 EOF
 
-test_expect_success 'initial' 'cmp .git/config expect'
+test_expect_success 'initial' 'cmp -s .git/config expect'
 
 git-repo-config Core.Movie BadPhysics
 
@@ -26,7 +26,7 @@ cat > expect << EOF
 	Movie = BadPhysics
 EOF
 
-test_expect_success 'mixed case' 'cmp .git/config expect'
+test_expect_success 'mixed case' 'cmp -s .git/config expect'
 
 git-repo-config Cores.WhatEver Second
 
@@ -38,7 +38,7 @@ cat > expect << EOF
 	WhatEver = Second
 EOF
 
-test_expect_success 'similar section' 'cmp .git/config expect'
+test_expect_success 'similar section' 'cmp -s .git/config expect'
 
 git-repo-config CORE.UPPERCASE true
 
@@ -51,7 +51,7 @@ cat > expect << EOF
 	WhatEver = Second
 EOF
 
-test_expect_success 'similar section' 'cmp .git/config expect'
+test_expect_success 'similar section' 'cmp -s .git/config expect'
 
 test_expect_success 'replace with non-match' \
 	'git-repo-config core.penguin kingpin !blue'
@@ -69,7 +69,7 @@ cat > expect << EOF
 	WhatEver = Second
 EOF
 
-test_expect_success 'non-match result' 'cmp .git/config expect'
+test_expect_success 'non-match result' 'cmp -s .git/config expect'
 
 cat > .git/config << EOF
 [beta] ; silly comment # another comment
@@ -97,7 +97,7 @@ # empty line
 [nextSection] noNewline = ouch
 EOF
 
-test_expect_success 'multiple unset is correct' 'cmp .git/config expect'
+test_expect_success 'multiple unset is correct' 'cmp -s .git/config expect'
 
 mv .git/config2 .git/config
 
@@ -114,7 +114,7 @@ # empty line
 [nextSection] noNewline = ouch
 EOF
 
-test_expect_success 'all replaced' 'cmp .git/config expect'
+test_expect_success 'all replaced' 'cmp -s .git/config expect'
 
 git-repo-config beta.haha alpha
 
@@ -128,7 +128,7 @@ # empty line
 [nextSection] noNewline = ouch
 EOF
 
-test_expect_success 'really mean test' 'cmp .git/config expect'
+test_expect_success 'really mean test' 'cmp -s .git/config expect'
 
 git-repo-config nextsection.nonewline wow
 
@@ -143,7 +143,7 @@ # empty line
 	nonewline = wow
 EOF
 
-test_expect_success 'really really mean test' 'cmp .git/config expect'
+test_expect_success 'really really mean test' 'cmp -s .git/config expect'
 
 test_expect_success 'get value' 'test alpha = $(git-repo-config beta.haha)'
 git-repo-config --unset beta.haha
@@ -158,7 +158,7 @@ # empty line
 	nonewline = wow
 EOF
 
-test_expect_success 'unset' 'cmp .git/config expect'
+test_expect_success 'unset' 'cmp -s .git/config expect'
 
 git-repo-config nextsection.NoNewLine "wow2 for me" "for me$"
 
@@ -173,7 +173,7 @@ # empty line
 	NoNewLine = wow2 for me
 EOF
 
-test_expect_success 'multivar' 'cmp .git/config expect'
+test_expect_success 'multivar' 'cmp -s .git/config expect'
 
 test_expect_success 'non-match' \
 	'git-repo-config --get nextsection.nonewline !for'
@@ -200,7 +200,7 @@ # empty line
 	NoNewLine = wow2 for me
 EOF
 
-test_expect_success 'multivar replace' 'cmp .git/config expect'
+test_expect_success 'multivar replace' 'cmp -s .git/config expect'
 
 test_expect_failure 'ambiguous value' 'git-repo-config nextsection.nonewline'
 
@@ -222,7 +222,7 @@ # empty line
 	NoNewLine = wow2 for me
 EOF
 
-test_expect_success 'multivar unset' 'cmp .git/config expect'
+test_expect_success 'multivar unset' 'cmp -s .git/config expect'
 
 test_expect_failure 'invalid key' 'git-repo-config inval.2key blabla'
 
@@ -245,7 +245,7 @@ # empty line
 	Alpha = beta
 EOF
 
-test_expect_success 'hierarchical section value' 'cmp .git/config expect'
+test_expect_success 'hierarchical section value' 'cmp -s .git/config expect'
 
 cat > expect << EOF
 beta.noindent=sillyValue
@@ -255,7 +255,7 @@ version.1.2.3eX.alpha=beta
 EOF
 
 test_expect_success 'working --list' \
-	'git-repo-config --list > output && cmp output expect'
+	'git-repo-config --list > output && cmp -s output expect'
 
 cat > expect << EOF
 beta.noindent sillyValue
@@ -263,7 +263,7 @@ nextsection.nonewline wow2 for me
 EOF
 
 test_expect_success '--get-regexp' \
-	'git-repo-config --get-regexp in > output && cmp output expect'
+	'git-repo-config --get-regexp in > output && cmp -s output expect'
 
 cat > .git/config << EOF
 [novalue]
@@ -292,7 +292,7 @@ cat > expect << EOF
 	x = y
 EOF
 
-test_expect_success 'new section is partial match of another' 'cmp .git/config expect'
+test_expect_success 'new section is partial match of another' 'cmp -s .git/config expect'
 
 git-repo-config b.x y
 git-repo-config a.b c
@@ -307,7 +307,7 @@ cat > expect << EOF
 	x = y
 EOF
 
-test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect'
+test_expect_success 'new variable inserts into proper section' 'cmp -s .git/config expect'
 
 cat > other-config << EOF
 [ein]
@@ -320,7 +320,7 @@ EOF
 
 GIT_CONFIG=other-config git-repo-config -l > output
 
-test_expect_success 'alternative GIT_CONFIG' 'cmp output expect'
+test_expect_success 'alternative GIT_CONFIG' 'cmp -s output expect'
 
 GIT_CONFIG=other-config git-repo-config anwohner.park ausweis
 
@@ -331,7 +331,7 @@ cat > expect << EOF
 	park = ausweis
 EOF
 
-test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect'
+test_expect_success '--set in alternative GIT_CONFIG' 'cmp -s other-config expect'
 
 test_done
 
diff --git a/t/t2101-update-index-reupdate.sh b/t/t2101-update-index-reupdate.sh
index a78ea7f..bc452c4 100755
--- a/t/t2101-update-index-reupdate.sh
+++ b/t/t2101-update-index-reupdate.sh
@@ -17,7 +17,7 @@ test_expect_success 'update-index --add'
 	 echo goodbye people >file2 &&
 	 git-update-index --add file1 file2 &&
 	 git-ls-files -s >current &&
-	 cmp current expected'
+	 cmp -s current expected'
 
 test_expect_success 'update-index --again' \
 	'rm -f file1 &&
@@ -30,7 +30,7 @@ test_expect_success 'update-index --agai
 		echo happy - failed as expected
 	fi &&
 	 git-ls-files -s >current &&
-	 cmp current expected'
+	 cmp -s current expected'
 
 cat > expected <<\EOF
 100644 0f1ae1422c2bf43f117d3dbd715c988a9ed2103f 0	file2
@@ -38,7 +38,7 @@ EOF
 test_expect_success 'update-index --remove --again' \
 	'git-update-index --remove --again &&
 	 git-ls-files -s >current &&
-	 cmp current expected'
+	 cmp -s current expected'
 
 test_expect_success 'first commit' 'git-commit -m initial'
 
@@ -55,7 +55,7 @@ test_expect_success 'update-index again'
 	echo happy >dir1/file3 &&
 	git-update-index --again &&
 	git-ls-files -s >current &&
-	cmp current expected'
+	cmp -s current expected'
 
 cat > expected <<\EOF
 100644 d7fb3f695f06c759dbf3ab00046e7cc2da22d10f 0	dir1/file3
@@ -68,7 +68,7 @@ test_expect_success 'update-index --upda
 	git-update-index --again &&
 	cd .. &&
 	git-ls-files -s >current &&
-	cmp current expected'
+	cmp -s current expected'
 
 cat > expected <<\EOF
 100644 594fb5bb1759d90998e2bf2a38261ae8e243c760 0	dir1/file3
@@ -79,6 +79,6 @@ test_expect_success 'update-index --upda
 	cat file2 >dir1/file3 &&
 	git-update-index --again dir1/ &&
 	git-ls-files -s >current &&
-	cmp current expected'
+	cmp -s current expected'
 
 test_done
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index c12270e..d2c1af8 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -24,7 +24,7 @@ EOF
 cat >"$p1" "$p0"
 echo 'Foo Bar Baz' >"$p2"
 
-test -f "$p1" && cmp "$p0" "$p1" || {
+test -f "$p1" && cmp -s "$p0" "$p1" || {
 	# since FAT/NTFS does not allow tabs in filenames, skip this test
 	say 'Your filesystem does not allow tabs in filenames, test skipped.'
 	test_done
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index 323606c..0ff3c4d 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -25,11 +25,11 @@ cat > expected <<\EOF
 EOF
 test_expect_success 'diff without --binary' \
 	'git-diff | git-apply --stat --summary >current &&
-	 cmp current expected'
+	 cmp -s current expected'
 
 test_expect_success 'diff with --binary' \
 	'git-diff --binary | git-apply --stat --summary >current &&
-	 cmp current expected'
+	 cmp -s current expected'
 
 # apply needs to be able to skip the binary material correctly
 # in order to report the line number of a corrupt patch.
diff --git a/t/t4109-apply-multifrag.sh b/t/t4109-apply-multifrag.sh
index 5988e1a..85ef40e 100755
--- a/t/t4109-apply-multifrag.sh
+++ b/t/t4109-apply-multifrag.sh
@@ -145,8 +145,8 @@ mv main.c main.c.git
 test_expect_success "S = patch (1)" \
     'cat patch1.patch patch2.patch | patch -p1'
 
-test_expect_success "S = cmp (1)" \
-    'cmp main.c.git main.c'
+test_expect_success "S = cmp -s (1)" \
+    'cmp -s main.c.git main.c'
 
 rm -f main.c main.c.git
 
@@ -157,8 +157,8 @@ mv main.c main.c.git
 test_expect_success "S = patch (2)" \
     'cat patch1.patch patch2.patch patch3.patch | patch -p1'
 
-test_expect_success "S = cmp (2)" \
-    'cmp main.c.git main.c'
+test_expect_success "S = cmp -s (2)" \
+    'cmp -s main.c.git main.c'
 
 rm -f main.c main.c.git
 
@@ -169,8 +169,8 @@ mv main.c main.c.git
 test_expect_success "S = patch (3)" \
     'cat patch1.patch patch4.patch | patch -p1'
 
-test_expect_success "S = cmp (3)" \
-    'cmp main.c.git main.c'
+test_expect_success "S = cmp -s (3)" \
+    'cmp -s main.c.git main.c'
 
 test_done
 
diff --git a/t/t4110-apply-scan.sh b/t/t4110-apply-scan.sh
index 005f744..3c767a4 100755
--- a/t/t4110-apply-scan.sh
+++ b/t/t4110-apply-scan.sh
@@ -95,7 +95,7 @@ test_expect_success "S = patch scan" \
 mv new.txt patch.txt
 
 test_expect_success "S = cmp" \
-    'cmp apply.txt patch.txt'
+    'cmp -s apply.txt patch.txt'
 
 test_done
 
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index de45ac4..5564162 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -56,7 +56,7 @@ test_expect_success \
     '(cd ../.git && find objects -type f -print) |
      while read path
      do
-         cmp $path ../.git/$path || {
+         cmp -s $path ../.git/$path || {
 	     echo $path differs.
 	     return 1
 	 }
@@ -86,7 +86,7 @@ test_expect_success \
     '(cd ../.git && find objects -type f -print) |
      while read path
      do
-         cmp $path ../.git/$path || {
+         cmp -s $path ../.git/$path || {
 	     echo $path differs.
 	     return 1
 	 }
@@ -182,17 +182,17 @@ test_expect_success \
     'build pack index for an existing pack' \
     'cp test-1-${packname_1}.pack test-3.pack &&
      git-index-pack -o tmp.idx test-3.pack &&
-     cmp tmp.idx test-1-${packname_1}.idx &&
+     cmp -s tmp.idx test-1-${packname_1}.idx &&
 
      git-index-pack test-3.pack &&
-     cmp test-3.idx test-1-${packname_1}.idx &&
+     cmp -s test-3.idx test-1-${packname_1}.idx &&
 
      cp test-2-${packname_2}.pack test-3.pack &&
      git-index-pack -o tmp.idx test-2-${packname_2}.pack &&
-     cmp tmp.idx test-2-${packname_2}.idx &&
+     cmp -s tmp.idx test-2-${packname_2}.idx &&
 
      git-index-pack test-3.pack &&
-     cmp test-3.idx test-2-${packname_2}.idx &&
+     cmp -s test-3.idx test-2-${packname_2}.idx &&
 
      :'
 
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index f3694ac..cb32283 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -52,7 +52,7 @@ test_expect_success \
 		echo >&2 Thanks, it correctly failed.
 		true
 	fi &&
-	if cmp victim/.git/refs/heads/master .git/refs/heads/master
+	if cmp -s victim/.git/refs/heads/master .git/refs/heads/master
 	then
 		# should have been left as it was!
 		false
@@ -61,7 +61,7 @@ test_expect_success \
 	fi &&
 	# this should update
 	git-send-pack --force ./victim/.git/ master &&
-	cmp victim/.git/refs/heads/master .git/refs/heads/master
+	cmp -s victim/.git/refs/heads/master .git/refs/heads/master
 '
 
 test_done
diff --git a/t/t6021-merge-criss-cross.sh b/t/t6021-merge-criss-cross.sh
index 8f7366d..97e85b9 100755
--- a/t/t6021-merge-criss-cross.sh
+++ b/t/t6021-merge-criss-cross.sh
@@ -93,6 +93,6 @@ cat > file-expect <<EOF
 9
 EOF
 
-test_expect_success 'Criss-cross merge result' 'cmp file file-expect'
+test_expect_success 'Criss-cross merge result' 'cmp -s file file-expect'
 
 test_done
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index a5a235f..e19c3df 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -97,7 +97,7 @@ test_expect_success 'fetch and pull late
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
-	test_expect_success "Comparing $i" "cmp $i new_wc/$i"
+	test_expect_success "Comparing $i" "cmp -s $i new_wc/$i"
 done
 
 
diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh
index f994b72..315bdd3 100755
--- a/t/t9105-git-svn-commit-diff.sh
+++ b/t/t9105-git-svn-commit-diff.sh
@@ -35,7 +35,7 @@ test_expect_success 'test the commit-dif
 	test -n '$prev' && test -n '$head' &&
 	git-svn commit-diff '$prev' '$head' '$svnrepo' &&
 	svn co $svnrepo wc &&
-	cmp readme wc/readme
+	cmp -s readme wc/readme
 	"
 
 test_done
-- 
1.4.2.rc3.ge5673-dirty

^ permalink raw reply related	[relevance 2%]

* Re: Compression and dictionaries
  @ 2006-08-14 15:26  1%       ` Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2006-08-14 15:26 UTC (permalink / raw)
  To: Alex Riesen; +Cc: Jon Smirl, git

Hi,

On Mon, 14 Aug 2006, Alex Riesen wrote:

> On 8/14/06, Jon Smirl <jonsmirl@gmail.com> wrote:
> > Changing the probabilities probably won't help much, but there may be
> > good gains from partially eliminating 1M encoding maps.
> 
> will the old git installations, without the maps, still be able to decode the
> pack created this way?

Probably not. But then, I would _not_ want this in upload-pack, so it is a 
strictly local thing -- either you repacked with a dictionary yourself, or 
there would be no explicit dictionary.

However, as I said, I _think_ this discussion is moot. You'd probably be 
better off making the windows wider, activating stronger compression, 
basically investing more time for the repacker. Plus, this would benefit 
cloned repos as well.

Ciao,
Dscho

^ permalink raw reply	[relevance 1%]

* Re: git clone dies (large git repository)
  @ 2006-08-19 20:46  4% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-08-19 20:46 UTC (permalink / raw)
  To: Troy Telford; +Cc: git

"Troy Telford" <ttelford@linuxnetworx.com> writes:

> I originally had everything as loose objects.  I then ran 'git-repack
> -d' on occasion, so I had a combination of a large pack file, smaller
> pack  files, and loose objects.  Finally, I tried 'git repack -a -d'
> and  consolidated it all into a single 4GB pack file.  It didn't seem
> to make  much difference in the output.
>
> Am I bumping some sort of limitation within git, or have I uncovered a bug?

The former.  Unfortunately this comes from an old design
decision.

Fortunately this design decision is not something irreversible
(see Chapter 1 of Documentation/ManagementStyle in the kernel
repository ;-).

The packfile is a dual-use format.  When used for network
transfer, we only send the .pack file and have the recipient
reconstruct the corresponding .idx file.  When used locally, we
need both .pack and .idx file; .pack contains the meat of the
data, and .idx allows us random access to the objects stored in
the corresponding .pack file.

What is interesting is that .pack format does not have (as far
as I know) inherent size limitation.  However, .idx file has
hardcoded 32-bit offsets into .pack -- hence, in practice, you
cannot use a .pack that is over 4GB locally.

One crude workaround that would work _today_ for your situation
without changing file formats would be to use git-fetch into an
empty repository (and do ref cloning by hand) instead of using
git-clone.  git-fetch gets .pack data over the wire and explode
the objects contained in the stream into individual objects (as
opposed to git-clone gets .pack data, stores it as a .pack and
tries to create corresponding .idx which in your case would bust
the 32-bit limit and fail).

This is from a private note I sent to Linus on Jun 26 2005 when
pack & idx pairs were initially introduced.

 - Design decision.  As before, you have assumption that nothing
   is longer than 2^32 bytes.  I am not unhappy with that
   restriction with individual objects (even their uncompressed
   size limited below 4GB or even 2GB is fine --- after all we
   are talking about a source control system).  I am however
   wondering if we would regret it later to have a packed file
   also limited to 4GB by having object_entry.offset "unsigned
   long" (and fwrite htonl'ed 4 bytes).  I personally do not
   have problem with this, but I can easily see HPA frowning on
   us.  He didn't like it when I said "in GIT world, file sizes
   and offsets are of type 'unsigned long'" some time ago.

I do not have a copy of a response from Linus to this point, but
if I recall things correctly, since then, the plan always has
been (1) to limit the size of individual packfiles to fit within
the idx limit and/or (2) extend the idx format to be able to
express offset over 2^32.  The latter is possible because idx
file is a local matter, used only for local accesses and does
not get set over the wire.

However, even if we revise the .idx file format, we have another
practical problem to solve.  Currently we assume that we can mmap
one packfile as a whole and do a random access into it.  This
needs to be changed so that we (perhaps optionally, only when
dealing with a huge packfile) mmap part of a .pack at a time.

I recall more recently (as opposed to the heated discussion
immediately after packfile was introduced June last year) we had
another discussion about people not being able to mmap huge
packfiles, and partial mmapping was one of the things that were
discussed there.

^ permalink raw reply	[relevance 4%]

* [PATCH 7/7] git-svn(1): improve asciidoc markup
  @ 2006-08-25  1:07  7%               ` Jonas Fonseca
  0 siblings, 0 replies; 200+ results
From: Jonas Fonseca @ 2006-08-25  1:07 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Use list continuation to have better wrapping. This accounts for most of
the changes because it reindents a lot of text without applying other
changes.

Use cross-referencing for interlinking and the gitlink macro for pointing
to other tools in the git suite.

Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
---
 Documentation/git-svn.txt |  199 ++++++++++++++++++++++++++-------------------
 1 files changed, 114 insertions(+), 85 deletions(-)

diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index 7d86809..f21aced 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -12,10 +12,8 @@ SYNOPSIS
 DESCRIPTION
 -----------
 git-svn is a simple conduit for changesets between a single Subversion
-branch and git.
-
-git-svn is not to be confused with git-svnimport.  The were designed
-with very different goals in mind.
+branch and git. It is not to be confused with gitlink:git-svnimport[1].
+They were designed with very different goals in mind.
 
 git-svn is designed for an individual developer who wants a
 bidirectional flow of changesets between a single branch in Subversion
@@ -34,26 +32,29 @@ git-svnimport is designed for.
 
 COMMANDS
 --------
-init::
+--
+
+'init'::
 	Creates an empty git repository with additional metadata
 	directories for git-svn.  The Subversion URL must be specified
 	as a command-line argument.
 
-fetch::
-	Fetch unfetched revisions from the Subversion URL we are
-	tracking.  refs/remotes/git-svn will be updated to the
-	latest revision.
+'fetch'::
 
-	Note: You should never attempt to modify the remotes/git-svn
-	branch outside of git-svn.  Instead, create a branch from
-	remotes/git-svn and work on that branch.  Use the 'commit'
-	command (see below) to write git commits back to
-	remotes/git-svn.
+Fetch unfetched revisions from the Subversion URL we are
+tracking.  refs/remotes/git-svn will be updated to the
+latest revision.
 
-	See 'Additional Fetch Arguments' if you are interested in
-	manually joining branches on commit.
+Note: You should never attempt to modify the remotes/git-svn
+branch outside of git-svn.  Instead, create a branch from
+remotes/git-svn and work on that branch.  Use the 'commit'
+command (see below) to write git commits back to
+remotes/git-svn.
 
-commit::
+See '<<fetch-args,Additional Fetch Arguments>>' if you are interested in
+manually joining branches on commit.
+
+'commit'::
 	Commit specified commit or tree objects to SVN.  This relies on
 	your imported fetch data being up-to-date.  This makes
 	absolutely no attempts to do patching when committing to SVN, it
@@ -61,9 +62,9 @@ commit::
 	commit.  All merging is assumed to have taken place
 	independently of git-svn functions.
 
-rebuild::
+'rebuild'::
 	Not a part of daily usage, but this is a useful command if
-	you've just cloned a repository (using git-clone) that was
+	you've just cloned a repository (using gitlink:git-clone[1]) that was
 	tracked with git-svn.  Unfortunately, git-clone does not clone
 	git-svn metadata and the svn working tree that git-svn uses for
 	its operations.  This rebuilds the metadata so git-svn can
@@ -71,130 +72,152 @@ rebuild::
 	specified at the command-line if the directory/repository you're
 	tracking has moved or changed protocols.
 
-show-ignore::
+'show-ignore'::
 	Recursively finds and lists the svn:ignore property on
 	directories.  The output is suitable for appending to
 	the $GIT_DIR/info/exclude file.
 
+--
+
 OPTIONS
 -------
+--
+
 -r <ARG>::
 --revision <ARG>::
-	Only used with the 'fetch' command.
 
-	Takes any valid -r<argument> svn would accept and passes it
-	directly to svn. -r<ARG1>:<ARG2> ranges and "{" DATE "}" syntax
-	is also supported.  This is passed directly to svn, see svn
-	documentation for more details.
+Only used with the 'fetch' command.
 
-	This can allow you to make partial mirrors when running fetch.
+Takes any valid -r<argument> svn would accept and passes it
+directly to svn. -r<ARG1>:<ARG2> ranges and "{" DATE "}" syntax
+is also supported.  This is passed directly to svn, see svn
+documentation for more details.
+				
+This can allow you to make partial mirrors when running fetch.
 
 -::
 --stdin::
-	Only used with the 'commit' command.
 
-	Read a list of commits from stdin and commit them in reverse
-	order.  Only the leading sha1 is read from each line, so
-	git-rev-list --pretty=oneline output can be used.
+Only used with the 'commit' command.
+
+Read a list of commits from stdin and commit them in reverse
+order.  Only the leading sha1 is read from each line, so
+git-rev-list --pretty=oneline output can be used.
 
 --rmdir::
-	Only used with the 'commit' command.
 
-	Remove directories from the SVN tree if there are no files left
-	behind.  SVN can version empty directories, and they are not
-	removed by default if there are no files left in them.  git
-	cannot version empty directories.  Enabling this flag will make
-	the commit to SVN act like git.
+Only used with the 'commit' command.
 
-	repo-config key: svn.rmdir
+Remove directories from the SVN tree if there are no files left
+behind.  SVN can version empty directories, and they are not
+removed by default if there are no files left in them.  git
+cannot version empty directories.  Enabling this flag will make
+the commit to SVN act like git.
+
+repo-config key: svn.rmdir
 
 -e::
 --edit::
-	Only used with the 'commit' command.
 
-	Edit the commit message before committing to SVN.  This is off by
-	default for objects that are commits, and forced on when committing
-	tree objects.
+Only used with the 'commit' command.
+
+Edit the commit message before committing to SVN.  This is off by
+default for objects that are commits, and forced on when committing
+tree objects.
 
-	repo-config key: svn.edit
+repo-config key: svn.edit
 
 -l<num>::
 --find-copies-harder::
-	Both of these are only used with the 'commit' command.
 
-	They are both passed directly to git-diff-tree see
-	git-diff-tree(1) for more information.
+Both of these are only used with the 'commit' command.
 
-	repo-config key: svn.l
-	repo-config key: svn.findcopiesharder
+They are both passed directly to git-diff-tree see
+gitlink:git-diff-tree[1] for more information.
+
+[verse]
+repo-config key: svn.l 
+repo-config key: svn.findcopiesharder
 
 -A<filename>::
 --authors-file=<filename>::
 
-	Syntax is compatible with the files used by git-svnimport and
-	git-cvsimport:
+Syntax is compatible with the files used by git-svnimport and
+git-cvsimport:
 
 ------------------------------------------------------------------------
-loginname = Joe User <user@example.com>
+	loginname = Joe User <user@example.com>
 ------------------------------------------------------------------------
 
-	If this option is specified and git-svn encounters an SVN
-	committer name that does not exist in the authors-file, git-svn
-	will abort operation. The user will then have to add the
-	appropriate entry.  Re-running the previous git-svn command
-	after the authors-file is modified should continue operation.
+If this option is specified and git-svn encounters an SVN
+committer name that does not exist in the authors-file, git-svn
+will abort operation. The user will then have to add the
+appropriate entry.  Re-running the previous git-svn command
+after the authors-file is modified should continue operation.
+
+repo-config key: svn.authors-file
 
-	repo-config key: svn.authors-file
+--
 
 ADVANCED OPTIONS
 ----------------
+--
+
 -b<refname>::
 --branch <refname>::
-	Used with 'fetch' or 'commit'.
+Used with 'fetch' or 'commit'.
 
-	This can be used to join arbitrary git branches to remotes/git-svn
-	on new commits where the tree object is equivalent.
+This can be used to join arbitrary git branches to remotes/git-svn
+on new commits where the tree object is equivalent.
 
-	When used with different GIT_SVN_ID values, tags and branches in
-	SVN can be tracked this way, as can some merges where the heads
-	end up having completely equivalent content.  This can even be
-	used to track branches across multiple SVN _repositories_.
+When used with different GIT_SVN_ID values, tags and branches in
+SVN can be tracked this way, as can some merges where the heads
+end up having completely equivalent content.  This can even be
+used to track branches across multiple SVN _repositories_.
 
-	This option may be specified multiple times, once for each
-	branch.
+This option may be specified multiple times, once for each
+branch.
 
-	repo-config key: svn.branch
+repo-config key: svn.branch
 
 -i<GIT_SVN_ID>::
 --id <GIT_SVN_ID>::
-	This sets GIT_SVN_ID (instead of using the environment).  See
-	the section on "Tracking Multiple Repositories or Branches" for
-	more information on using GIT_SVN_ID.
+
+This sets GIT_SVN_ID (instead of using the environment).  See the
+section on
+'<<tracking-multiple-repos,Tracking Multiple Repositories or Branches>>'
+for more information on using GIT_SVN_ID.
+
+--
 
 COMPATIBILITY OPTIONS
 ---------------------
+--
+
 --upgrade::
-	Only used with the 'rebuild' command.
+Only used with the 'rebuild' command.
 
-	Run this if you used an old version of git-svn that used
-	"git-svn-HEAD" instead of "remotes/git-svn" as the branch
-	for tracking the remote.
+Run this if you used an old version of git-svn that used
+"git-svn-HEAD" instead of "remotes/git-svn" as the branch
+for tracking the remote.
 
 --no-ignore-externals::
-	Only used with the 'fetch' and 'rebuild' command.
+Only used with the 'fetch' and 'rebuild' command.
+
+By default, git-svn passes --ignore-externals to svn to avoid
+fetching svn:external trees into git.  Pass this flag to enable
+externals tracking directly via git.
 
-	By default, git-svn passes --ignore-externals to svn to avoid
-	fetching svn:external trees into git.  Pass this flag to enable
-	externals tracking directly via git.
+Versions of svn that do not support --ignore-externals are
+automatically detected and this flag will be automatically
+enabled for them.
 
-	Versions of svn that do not support --ignore-externals are
-	automatically detected and this flag will be automatically
-	enabled for them.
+Otherwise, do not enable this flag unless you know what you're
+doing.
 
-	Otherwise, do not enable this flag unless you know what you're
-	doing.
+repo-config key: svn.noignoreexternals
 
-	repo-config key: svn.noignoreexternals
+--
 
 Basic Examples
 ~~~~~~~~~~~~~~
@@ -226,6 +249,7 @@ any automated merge/branch tracking on t
 entirely up to the user on the git side.  It's simply not worth it to do
 a useful translation when the original signal is weak.
 
+[[tracking-multiple-repos]]
 TRACKING MULTIPLE REPOSITORIES OR BRANCHES
 ------------------------------------------
 This is for advanced users, most users should ignore this section.
@@ -241,6 +265,7 @@ invocation.  The interface branch will b
 remotes/git-svn.  Any remotes/$GIT_SVN_ID branch should never be modified
 by the user outside of git-svn commands.
 
+[[fetch-args]]
 ADDITIONAL FETCH ARGUMENTS
 --------------------------
 This is for advanced users, most users should ignore this section.
@@ -251,11 +276,15 @@ optionally be specified in the form of s
 command-line.  Unfetched SVN revisions may also be tied to particular
 git commits with the following syntax:
 
+------------------------------------------------
 	svn_revision_number=git_commit_sha1
+------------------------------------------------
 
-This allows you to tie unfetched SVN revision 375 to your current HEAD::
+This allows you to tie unfetched SVN revision 375 to your current HEAD:
 
-	`git-svn fetch 375=$(git-rev-parse HEAD)`
+------------------------------------------------
+	git-svn fetch 375=$(git-rev-parse HEAD)
+------------------------------------------------
 
 Advanced Example: Tracking a Reorganized Repository
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-- 
1.4.2.GIT

-- 
Jonas Fonseca

^ permalink raw reply related	[relevance 7%]

* Re: Mozilla version control requirements and git
  @ 2006-09-03  3:29  4%   ` Jon Smirl
  0 siblings, 0 replies; 200+ results
From: Jon Smirl @ 2006-09-03  3:29 UTC (permalink / raw)
  To: Martin Langhoff; +Cc: git

On 9/2/06, Martin Langhoff <martin.langhoff@gmail.com> wrote:
> On 9/3/06, Jon Smirl <jonsmirl@gmail.com> wrote:
> > The Mozilla people have a web page describing what they are looking
> > for in a new version control system. How does git stack up?
>
> Hi Jon,
>
> you've been playing with GIT quite a bit by now, so I guess you know
> the answer ;-) Is there anything in particular you are wondering
> about?

Shallow clones are a big problem. We have Mozilla down to 450MB is
git, but that is still gigantic for anyone doing an initial check out,
especially if they don't have good broadband. It is over 10x the data
that CVS brings down. Even without doing shallow clones git still
needs to be modified to restart an interrupted pack transfer.

>
> The one item that sticks out for me as not there is ACLs, but access
> controls can be implemented in hooks for direct pushes. Maintain an
> .htaccess-like file and have a perl script to check it on pushes to
> the repo.

I don't see ACLs as that big an issue. If you convert to model where
everyone has their own repo and you just push changesets at each
other, ACLs are much less important. You need ACLs when 2,000 people
have commit privs.

>
> Oh, and "partial tree pulls for localisers". Perhaps git-cvsserver can
> help there? Localisers can just use TortoiseCVS and get a checkout of
> the language pack subdir.

Partial repo pulls and an issue to. The mozilla repo has much more
than a browser in it, it also has a large mail/news program. A partial
repo pull may not be what is needed for git, instead git needs a
partial repo checkout.

-- 
Jon Smirl
jonsmirl@gmail.com

-- 
VGER BF report: U 0.827771

^ permalink raw reply	[relevance 4%]

* [PATCH 3/3] git-commit.sh: convert run_status to a C builtin
       [not found]     <64c62cc942e872b29d7225999e74a07be586674a.1157610743.git.peff@peff.net>
@ 2006-09-07  6:36  2% ` Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2006-09-07  6:36 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

This creates a new git-runstatus which should do roughly the same thing
as the run_status function from git-commit.sh. Except for color support,
the main focus has been to keep the output identical, so that it can be
verified as correct and then used as a C platform for other improvements to
the status printing code.
---
 .gitignore          |    1 
 Makefile            |    3 -
 builtin-runstatus.c |   34 ++++++
 builtin.h           |    1 
 dir.c               |    7 +
 dir.h               |    1 
 git-commit.sh       |  106 +------------------
 git.c               |    1 
 status.c            |  283 +++++++++++++++++++++++++++++++++++++++++++++++++++
 status.h            |   31 ++++++
 10 files changed, 368 insertions(+), 100 deletions(-)

diff --git a/.gitignore b/.gitignore
index 78cb671..f014ad3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,6 +94,7 @@ git-rev-list
 git-rev-parse
 git-revert
 git-rm
+git-runstatus
 git-send-email
 git-send-pack
 git-sh-setup
diff --git a/Makefile b/Makefile
index 78748cb..d0ba3b5 100644
--- a/Makefile
+++ b/Makefile
@@ -252,7 +252,7 @@ LIB_OBJS = \
 	fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
 	write_or_die.o trace.o \
 	alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
-	color.o
+	color.o status.o
 
 BUILTIN_OBJS = \
 	builtin-add.o \
@@ -286,6 +286,7 @@ BUILTIN_OBJS = \
 	builtin-rev-list.o \
 	builtin-rev-parse.o \
 	builtin-rm.o \
+	builtin-runstatus.o \
 	builtin-show-branch.o \
 	builtin-stripspace.o \
 	builtin-symbolic-ref.o \
diff --git a/builtin-runstatus.c b/builtin-runstatus.c
new file mode 100644
index 0000000..f3e44de
--- /dev/null
+++ b/builtin-runstatus.c
@@ -0,0 +1,34 @@
+#include "status.h"
+#include "cache.h"
+
+extern int status_use_color;
+
+static const char runstatus_usage[] =
+"git-runstatus [--color|--nocolor] [--amend] [--verbose]";
+
+int cmd_runstatus(int argc, const char **argv, const char *prefix)
+{
+	struct status s;
+	int i;
+
+	git_config(git_status_config);
+	status_prepare(&s);
+
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "--color"))
+			status_use_color = 1;
+		else if (!strcmp(argv[i], "--nocolor"))
+			status_use_color = 0;
+    else if (!strcmp(argv[i], "--amend")) {
+      s.amend = 1;
+      s.reference = "HEAD^1";
+    }
+    else if (!strcmp(argv[i], "--verbose"))
+      s.verbose = 1;
+		else
+			usage(runstatus_usage);
+	}
+
+	status_print(&s);
+  return s.commitable ? 0 : 1;
+}
diff --git a/builtin.h b/builtin.h
index 25431d7..53a896c 100644
--- a/builtin.h
+++ b/builtin.h
@@ -47,6 +47,7 @@ extern int cmd_repo_config(int argc, con
 extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
 extern int cmd_rm(int argc, const char **argv, const char *prefix);
+extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
 extern int cmd_show(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
diff --git a/dir.c b/dir.c
index 5a40d8f..e2f472b 100644
--- a/dir.c
+++ b/dir.c
@@ -397,3 +397,10 @@ int read_directory(struct dir_struct *di
 	qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
 	return dir->nr;
 }
+
+int
+file_exists(const char *f)
+{
+  struct stat sb;
+  return stat(f, &sb) == 0;
+}
diff --git a/dir.h b/dir.h
index 56a1b7f..313f8ab 100644
--- a/dir.h
+++ b/dir.h
@@ -47,5 +47,6 @@ extern int excluded(struct dir_struct *,
 extern void add_excludes_from_file(struct dir_struct *, const char *fname);
 extern void add_exclude(const char *string, const char *base,
 			int baselen, struct exclude_list *which);
+extern int file_exists(const char *);
 
 #endif
diff --git a/git-commit.sh b/git-commit.sh
index 4cf3fab..10c269a 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -60,26 +60,6 @@ #
 }
 
 run_status () {
-    (
-	# We always show status for the whole tree.
-	cd "$TOP"
-
-	IS_INITIAL="$initial_commit"
-	REFERENCE=HEAD
-	case "$amend" in
-	t)
-		# If we are amending the initial commit, there
-		# is no HEAD^1.
-		if git-rev-parse --verify "HEAD^1" >/dev/null 2>&1
-		then
-			REFERENCE="HEAD^1"
-			IS_INITIAL=
-		else
-			IS_INITIAL=t
-		fi
-		;;
-	esac
-
 	# If TMP_INDEX is defined, that means we are doing
 	# "--only" partial commit, and that index file is used
 	# to build the tree for the commit.  Otherwise, if
@@ -96,85 +76,13 @@ run_status () {
 	    export GIT_INDEX_FILE
 	fi
 
-	case "$branch" in
-	refs/heads/master) ;;
-	*)  echo "# On branch $branch" ;;
-	esac
-
-	if test -z "$IS_INITIAL"
-	then
-	    git-diff-index -M --cached --name-status \
-		--diff-filter=MDTCRA $REFERENCE |
-	    sed -e '
-		    s/\\/\\\\/g
-		    s/ /\\ /g
-	    ' |
-	    report "Updated but not checked in" "will commit"
-	    committable="$?"
-	else
-	    echo '#
-# Initial commit
-#'
-	    git-ls-files |
-	    sed -e '
-		    s/\\/\\\\/g
-		    s/ /\\ /g
-		    s/^/A /
-	    ' |
-	    report "Updated but not checked in" "will commit"
-
-	    committable="$?"
-	fi
-
-	git-diff-files  --name-status |
-	sed -e '
-		s/\\/\\\\/g
-		s/ /\\ /g
-	' |
-	report "Changed but not updated" \
-	    "use git-update-index to mark for commit"
-
-        option=""
-        if test -z "$untracked_files"; then
-            option="--directory --no-empty-directory"
-        fi
-	hdr_shown=
-	if test -f "$GIT_DIR/info/exclude"
-	then
-	    git-ls-files --others $option \
-		--exclude-from="$GIT_DIR/info/exclude" \
-		--exclude-per-directory=.gitignore
-	else
-	    git-ls-files --others $option \
-		--exclude-per-directory=.gitignore
-	fi |
-	while read line; do
-	    if [ -z "$hdr_shown" ]; then
-		echo '#'
-		echo '# Untracked files:'
-		echo '#   (use "git add" to add to commit)'
-		echo '#'
-		hdr_shown=1
-	    fi
-	    echo "#	$line"
-	done
-
-	if test -n "$verbose" -a -z "$IS_INITIAL"
-	then
-	    git-diff-index --cached -M -p --diff-filter=MDTCRA $REFERENCE
-	fi
-	case "$committable" in
-	0)
-		case "$amend" in
-		t)
-			echo "# No changes" ;;
-		*)
-			echo "nothing to commit" ;;
-		esac
-		exit 1 ;;
-	esac
-	exit 0
-    )
+  case "$status_only" in
+    t) color= ;;
+    *) color=--nocolor ;;
+  esac
+  git-runstatus ${color} \
+                ${verbose:+--verbose} \
+                ${amend:+--amend}
 }
 
 trap '
diff --git a/git.c b/git.c
index 335f405..495b39a 100644
--- a/git.c
+++ b/git.c
@@ -252,6 +252,7 @@ static void handle_internal_command(int 
 		{ "rev-list", cmd_rev_list, RUN_SETUP },
 		{ "rev-parse", cmd_rev_parse, RUN_SETUP },
 		{ "rm", cmd_rm, RUN_SETUP },
+		{ "runstatus", cmd_runstatus, RUN_SETUP },
 		{ "show-branch", cmd_show_branch, RUN_SETUP },
 		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
 		{ "stripspace", cmd_stripspace },
diff --git a/status.c b/status.c
new file mode 100644
index 0000000..82aa881
--- /dev/null
+++ b/status.c
@@ -0,0 +1,283 @@
+#include "status.h"
+#include "color.h"
+#include "cache.h"
+#include "object.h"
+#include "dir.h"
+#include "commit.h"
+#include "diff.h"
+#include "revision.h"
+#include "diffcore.h"
+
+int status_use_color = 0;
+static char status_colors[][COLOR_MAXLEN] = {
+	"",         /* STATUS_HEADER: normal */
+	"\033[32m", /* STATUS_UPDATED: green */
+	"\033[31m", /* STATUS_CHANGED: red */
+	"\033[31m", /* STATUS_UNTRACKED: red */
+};
+
+static int
+parse_status_slot(const char *var, int offset) {
+	if (!strcasecmp(var+offset, "header"))
+		return STATUS_HEADER;
+	if (!strcasecmp(var+offset, "updated"))
+		return STATUS_UPDATED;
+	if (!strcasecmp(var+offset, "changed"))
+		return STATUS_CHANGED;
+	if (!strcasecmp(var+offset, "untracked"))
+		return STATUS_UNTRACKED;
+	die("bad config variable '%s'", var);
+}
+
+static const char*
+color(int slot)
+{
+	return status_use_color ? status_colors[slot] : "";
+}
+
+void
+status_prepare(struct status *s)
+{
+	unsigned char sha1[20];
+	const char *head;
+
+	s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0;
+
+	head = resolve_ref(git_path("HEAD"), sha1, 0);
+	s->branch = head ?
+		    strdup(head + strlen(get_git_dir()) + 1) :
+		    NULL;
+
+	s->reference = "HEAD";
+	s->amend = 0;
+	s->verbose = 0;
+	s->commitable = 0;
+}
+
+static void
+status_print_header(const char *main, const char *sub)
+{
+	const char *c = color(STATUS_HEADER);
+	color_printf(c, "# %s:\n", main);
+	color_printf(c, "#   (%s)\n", sub);
+	color_printf(c, "#\n");
+}
+
+static void
+status_print_trailer(void)
+{
+	color_printf(color(STATUS_HEADER), "#\n");
+}
+
+static void
+status_print_filepair(int t, struct diff_filepair *p)
+{
+	const char *c = color(t);
+	color_printf(color(STATUS_HEADER), "#\t");
+	switch (p->status) {
+	case DIFF_STATUS_ADDED:
+		color_printf(c, "new file: %s\n", p->one->path); break;
+	case DIFF_STATUS_COPIED:
+		color_printf(c, "copied: %s -> %s\n",
+				p->one->path, p->two->path);
+		break;
+	case DIFF_STATUS_DELETED:
+		color_printf(c, "deleted: %s\n", p->one->path); break;
+	case DIFF_STATUS_MODIFIED:
+		color_printf(c, "modified: %s\n", p->one->path); break;
+	case DIFF_STATUS_RENAMED:
+		color_printf(c, "renamed: %s -> %s\n",
+				p->one->path, p->two->path);
+		break;
+	case DIFF_STATUS_TYPE_CHANGED:
+		color_printf(c, "typechange: %s\n", p->one->path); break;
+	case DIFF_STATUS_UNKNOWN:
+		color_printf(c, "unknown: %s\n", p->one->path); break;
+	case DIFF_STATUS_UNMERGED:
+		color_printf(c, "unmerged: %s\n", p->one->path); break;
+	default:
+		die("bug: unhandled diff status %c", p->status);
+	}
+}
+
+static void
+status_print_updated_cb(struct diff_queue_struct *q,
+                        struct diff_options *options,
+                        void *data)
+{
+	struct status *s = data;
+	int shown_header = 0;
+	int i;
+	if (q->nr) {
+	}
+	for (i = 0; i < q->nr; i++) {
+		if (q->queue[i]->status == 'U')
+			continue;
+		if (!shown_header) {
+			status_print_header("Updated but not checked in",
+					"will commit");
+			s->commitable = 1;
+		}
+		status_print_filepair(STATUS_UPDATED, q->queue[i]);
+	}
+	if (shown_header)
+		status_print_trailer();
+}
+
+static void
+status_print_changed_cb(struct diff_queue_struct *q,
+                        struct diff_options *options,
+                        void *data)
+{
+	int i;
+	if (q->nr)
+		status_print_header("Changed but not updated",
+				"use git-update-index to mark for commit");
+	for (i = 0; i < q->nr; i++)
+		status_print_filepair(STATUS_CHANGED, q->queue[i]);
+	if (q->nr)
+		status_print_trailer();
+}
+
+void
+status_print_initial(struct status *s)
+{
+	int i;
+	read_cache();
+	if (active_nr) {
+		s->commitable = 1;
+		status_print_header("Updated but not checked in",
+				"will commit");
+	}
+	for (i = 0; i < active_nr; i++) {
+		color_printf(color(STATUS_HEADER), "#\t");
+		color_printf(color(STATUS_UPDATED), "new file: %s\n",
+				active_cache[i]->name);
+	}
+	if (active_nr)
+		status_print_trailer();
+}
+
+static void
+status_print_updated(struct status *s)
+{
+	struct rev_info rev;
+	const char *argv[] = { NULL, NULL, NULL };
+	argv[1] = s->reference;
+	init_revisions(&rev, NULL);
+	setup_revisions(2, argv, &rev, NULL);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = status_print_updated_cb;
+	rev.diffopt.format_callback_data = s;
+	rev.diffopt.detect_rename = 1;
+	run_diff_index(&rev, 1);
+}
+
+static void
+status_print_changed(struct status *s)
+{
+	struct rev_info rev;
+	const char *argv[] = { NULL, NULL };
+	init_revisions(&rev, "");
+	setup_revisions(1, argv, &rev, NULL);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = status_print_changed_cb;
+	rev.diffopt.format_callback_data = s;
+	run_diff_files(&rev, 0);
+}
+
+static void
+status_print_untracked(const struct status *s)
+{
+	struct dir_struct dir;
+	const char *x;
+	int i;
+	int shown_header = 0;
+
+	memset(&dir, 0, sizeof(dir));
+
+	dir.exclude_per_dir = ".gitignore";
+	x = git_path("info/exclude");
+	if (file_exists(x))
+		add_excludes_from_file(&dir, x);
+
+	read_directory(&dir, ".", "", 0);
+	for(i = 0; i < dir.nr; i++) {
+		/* check for matching entry, which is unmerged; lifted from
+		 * builtin-ls-files:show_other_files */
+		struct dir_entry *ent = dir.entries[i];
+		int pos = cache_name_pos(ent->name, ent->len);
+		struct cache_entry *ce;
+		if (0 <= pos)
+			die("bug in status_print_untracked");
+		pos = -pos - 1;
+		if (pos < active_nr) {
+			ce = active_cache[pos];
+			if (ce_namelen(ce) == ent->len &&
+			    !memcmp(ce->name, ent->name, ent->len))
+				continue;
+		}
+		if (!shown_header) {
+			status_print_header("Untracked files",
+				"use \"git add\" to add to commit");
+			shown_header = 1;
+		}
+		color_printf(color(STATUS_HEADER), "#\t");
+		color_printf(color(STATUS_UNTRACKED), "%.*s\n",
+				ent->len, ent->name);
+	}
+}
+
+static void
+status_print_verbose(struct status *s)
+{
+	struct rev_info rev;
+	const char *argv[] = { NULL, NULL, NULL };
+	argv[1] = s->reference;
+	init_revisions(&rev, NULL);
+	setup_revisions(2, argv, &rev, NULL);
+	rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
+	rev.diffopt.detect_rename = 1;
+	run_diff_index(&rev, 1);
+}
+
+void
+status_print(struct status *s)
+{
+	if (s->branch && strcmp(s->branch, "refs/heads/master"))
+		color_printf(color(STATUS_HEADER),
+			"# On branch %s\n", s->branch);
+
+	if (s->is_initial) {
+		color_printf(color(STATUS_HEADER), "#\n");
+		color_printf(color(STATUS_HEADER), "# Initial commit\n");
+		color_printf(color(STATUS_HEADER), "#\n");
+		status_print_initial(s);
+	}
+	else {
+		status_print_updated(s);
+		discard_cache();
+	}
+
+	status_print_changed(s);
+	status_print_untracked(s);
+
+	if (s->verbose && !s->is_initial)
+		status_print_verbose(s);
+	if (!s->commitable)
+		printf("%s\n", s->amend ? "# No changes" : "nothing to commit");
+}
+
+int
+git_status_config(const char *k, const char *v)
+{
+	if (!strcmp(k, "status.color")) {
+		status_use_color = git_config_colorbool(k, v);
+		return 0;
+	}
+	if (!strncmp(k, "status.color.", 13)) {
+		int slot = parse_status_slot(k, 13);
+		color_parse(v, k, status_colors[slot]);
+	}
+	return git_default_config(k, v);
+}
diff --git a/status.h b/status.h
new file mode 100644
index 0000000..3e60146
--- /dev/null
+++ b/status.h
@@ -0,0 +1,31 @@
+#ifndef STATUS_H
+#define STATUS_H
+
+enum color_status {
+	STATUS_HEADER,
+	STATUS_UPDATED,
+	STATUS_CHANGED,
+	STATUS_UNTRACKED,
+};
+
+struct status {
+	int is_initial;
+	char *branch;
+	const char *reference;
+	int commitable;
+	int verbose;
+	int amend;
+};
+
+int git_status_config(const char *var, const char *value);
+void status_prepare(struct status *s);
+void status_print(struct status *s);
+
+struct cache_entry;
+typedef void (*status_cb)(struct cache_entry *);
+int status_foreach_cached(status_cb cb);
+int status_foreach_updated(status_cb cb);
+int status_foreach_changed(status_cb cb);
+int status_foreach_untracked(status_cb cb);
+
+#endif /* STATUS_H */
-- 
1.4.2.ge490e-dirty

^ permalink raw reply related	[relevance 2%]

* [PATCH] git-commit.sh: convert run_status to a C builtin
@ 2006-09-08  8:05  2% Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2006-09-08  8:05 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

This creates a new git-runstatus which should do roughly the same thing
as the run_status function from git-commit.sh. Except for color support,
the main focus has been to keep the output identical, so that it can be
verified as correct and then used as a C platform for other improvements to
the status printing code.

Signed-off-by: Jeff King <peff@peff.net>
---
This is a resend with:
 - formatting cleanups
 - s/status/wt_status/
 - avoid letting colored sections cross newlines

 .gitignore          |    1 
 Makefile            |    3 -
 builtin-runstatus.c |   34 ++++++
 builtin.h           |    1 
 dir.c               |    7 +
 dir.h               |    1 
 git-commit.sh       |  106 +-------------------
 git.c               |    1 
 wt-status.c         |  271 +++++++++++++++++++++++++++++++++++++++++++++++++++
 wt-status.h         |   24 +++++
 10 files changed, 349 insertions(+), 100 deletions(-)

diff --git a/.gitignore b/.gitignore
index 78cb671..f014ad3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -94,6 +94,7 @@ git-rev-list
 git-rev-parse
 git-revert
 git-rm
+git-runstatus
 git-send-email
 git-send-pack
 git-sh-setup
diff --git a/Makefile b/Makefile
index 78748cb..a9314ac 100644
--- a/Makefile
+++ b/Makefile
@@ -252,7 +252,7 @@ LIB_OBJS = \
 	fetch-clone.o revision.o pager.o tree-walk.o xdiff-interface.o \
 	write_or_die.o trace.o \
 	alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
-	color.o
+	color.o wt-status.o
 
 BUILTIN_OBJS = \
 	builtin-add.o \
@@ -286,6 +286,7 @@ BUILTIN_OBJS = \
 	builtin-rev-list.o \
 	builtin-rev-parse.o \
 	builtin-rm.o \
+	builtin-runstatus.o \
 	builtin-show-branch.o \
 	builtin-stripspace.o \
 	builtin-symbolic-ref.o \
diff --git a/builtin-runstatus.c b/builtin-runstatus.c
new file mode 100644
index 0000000..7979d61
--- /dev/null
+++ b/builtin-runstatus.c
@@ -0,0 +1,34 @@
+#include "wt-status.h"
+#include "cache.h"
+
+extern int wt_status_use_color;
+
+static const char runstatus_usage[] =
+"git-runstatus [--color|--nocolor] [--amend] [--verbose]";
+
+int cmd_runstatus(int argc, const char **argv, const char *prefix)
+{
+	struct wt_status s;
+	int i;
+
+	git_config(git_status_config);
+	wt_status_prepare(&s);
+
+	for (i = 1; i < argc; i++) {
+		if (!strcmp(argv[i], "--color"))
+			wt_status_use_color = 1;
+		else if (!strcmp(argv[i], "--nocolor"))
+			wt_status_use_color = 0;
+		else if (!strcmp(argv[i], "--amend")) {
+			s.amend = 1;
+			s.reference = "HEAD^1";
+		}
+		else if (!strcmp(argv[i], "--verbose"))
+			s.verbose = 1;
+		else
+			usage(runstatus_usage);
+	}
+
+	wt_status_print(&s);
+	return s.commitable ? 0 : 1;
+}
diff --git a/builtin.h b/builtin.h
index 25431d7..53a896c 100644
--- a/builtin.h
+++ b/builtin.h
@@ -47,6 +47,7 @@ extern int cmd_repo_config(int argc, con
 extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
 extern int cmd_rm(int argc, const char **argv, const char *prefix);
+extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
 extern int cmd_show(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
diff --git a/dir.c b/dir.c
index 5a40d8f..e2f472b 100644
--- a/dir.c
+++ b/dir.c
@@ -397,3 +397,10 @@ int read_directory(struct dir_struct *di
 	qsort(dir->entries, dir->nr, sizeof(struct dir_entry *), cmp_name);
 	return dir->nr;
 }
+
+int
+file_exists(const char *f)
+{
+  struct stat sb;
+  return stat(f, &sb) == 0;
+}
diff --git a/dir.h b/dir.h
index 56a1b7f..313f8ab 100644
--- a/dir.h
+++ b/dir.h
@@ -47,5 +47,6 @@ extern int excluded(struct dir_struct *,
 extern void add_excludes_from_file(struct dir_struct *, const char *fname);
 extern void add_exclude(const char *string, const char *base,
 			int baselen, struct exclude_list *which);
+extern int file_exists(const char *);
 
 #endif
diff --git a/git-commit.sh b/git-commit.sh
index 4cf3fab..10c269a 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -60,26 +60,6 @@ #
 }
 
 run_status () {
-    (
-	# We always show status for the whole tree.
-	cd "$TOP"
-
-	IS_INITIAL="$initial_commit"
-	REFERENCE=HEAD
-	case "$amend" in
-	t)
-		# If we are amending the initial commit, there
-		# is no HEAD^1.
-		if git-rev-parse --verify "HEAD^1" >/dev/null 2>&1
-		then
-			REFERENCE="HEAD^1"
-			IS_INITIAL=
-		else
-			IS_INITIAL=t
-		fi
-		;;
-	esac
-
 	# If TMP_INDEX is defined, that means we are doing
 	# "--only" partial commit, and that index file is used
 	# to build the tree for the commit.  Otherwise, if
@@ -96,85 +76,13 @@ run_status () {
 	    export GIT_INDEX_FILE
 	fi
 
-	case "$branch" in
-	refs/heads/master) ;;
-	*)  echo "# On branch $branch" ;;
-	esac
-
-	if test -z "$IS_INITIAL"
-	then
-	    git-diff-index -M --cached --name-status \
-		--diff-filter=MDTCRA $REFERENCE |
-	    sed -e '
-		    s/\\/\\\\/g
-		    s/ /\\ /g
-	    ' |
-	    report "Updated but not checked in" "will commit"
-	    committable="$?"
-	else
-	    echo '#
-# Initial commit
-#'
-	    git-ls-files |
-	    sed -e '
-		    s/\\/\\\\/g
-		    s/ /\\ /g
-		    s/^/A /
-	    ' |
-	    report "Updated but not checked in" "will commit"
-
-	    committable="$?"
-	fi
-
-	git-diff-files  --name-status |
-	sed -e '
-		s/\\/\\\\/g
-		s/ /\\ /g
-	' |
-	report "Changed but not updated" \
-	    "use git-update-index to mark for commit"
-
-        option=""
-        if test -z "$untracked_files"; then
-            option="--directory --no-empty-directory"
-        fi
-	hdr_shown=
-	if test -f "$GIT_DIR/info/exclude"
-	then
-	    git-ls-files --others $option \
-		--exclude-from="$GIT_DIR/info/exclude" \
-		--exclude-per-directory=.gitignore
-	else
-	    git-ls-files --others $option \
-		--exclude-per-directory=.gitignore
-	fi |
-	while read line; do
-	    if [ -z "$hdr_shown" ]; then
-		echo '#'
-		echo '# Untracked files:'
-		echo '#   (use "git add" to add to commit)'
-		echo '#'
-		hdr_shown=1
-	    fi
-	    echo "#	$line"
-	done
-
-	if test -n "$verbose" -a -z "$IS_INITIAL"
-	then
-	    git-diff-index --cached -M -p --diff-filter=MDTCRA $REFERENCE
-	fi
-	case "$committable" in
-	0)
-		case "$amend" in
-		t)
-			echo "# No changes" ;;
-		*)
-			echo "nothing to commit" ;;
-		esac
-		exit 1 ;;
-	esac
-	exit 0
-    )
+  case "$status_only" in
+    t) color= ;;
+    *) color=--nocolor ;;
+  esac
+  git-runstatus ${color} \
+                ${verbose:+--verbose} \
+                ${amend:+--amend}
 }
 
 trap '
diff --git a/git.c b/git.c
index 335f405..495b39a 100644
--- a/git.c
+++ b/git.c
@@ -252,6 +252,7 @@ static void handle_internal_command(int 
 		{ "rev-list", cmd_rev_list, RUN_SETUP },
 		{ "rev-parse", cmd_rev_parse, RUN_SETUP },
 		{ "rm", cmd_rm, RUN_SETUP },
+		{ "runstatus", cmd_runstatus, RUN_SETUP },
 		{ "show-branch", cmd_show_branch, RUN_SETUP },
 		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
 		{ "stripspace", cmd_stripspace },
diff --git a/wt-status.c b/wt-status.c
new file mode 100644
index 0000000..ec2c728
--- /dev/null
+++ b/wt-status.c
@@ -0,0 +1,271 @@
+#include "wt-status.h"
+#include "color.h"
+#include "cache.h"
+#include "object.h"
+#include "dir.h"
+#include "commit.h"
+#include "diff.h"
+#include "revision.h"
+#include "diffcore.h"
+
+int wt_status_use_color = 0;
+static char wt_status_colors[][COLOR_MAXLEN] = {
+	"",         /* WT_STATUS_HEADER: normal */
+	"\033[32m", /* WT_STATUS_UPDATED: green */
+	"\033[31m", /* WT_STATUS_CHANGED: red */
+	"\033[31m", /* WT_STATUS_UNTRACKED: red */
+};
+
+static int parse_status_slot(const char *var, int offset)
+{
+	if (!strcasecmp(var+offset, "header"))
+		return WT_STATUS_HEADER;
+	if (!strcasecmp(var+offset, "updated"))
+		return WT_STATUS_UPDATED;
+	if (!strcasecmp(var+offset, "changed"))
+		return WT_STATUS_CHANGED;
+	if (!strcasecmp(var+offset, "untracked"))
+		return WT_STATUS_UNTRACKED;
+	die("bad config variable '%s'", var);
+}
+
+static const char* color(int slot)
+{
+	return wt_status_use_color ? wt_status_colors[slot] : "";
+}
+
+void wt_status_prepare(struct wt_status *s)
+{
+	unsigned char sha1[20];
+	const char *head;
+
+	s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0;
+
+	head = resolve_ref(git_path("HEAD"), sha1, 0);
+	s->branch = head ?
+		    strdup(head + strlen(get_git_dir()) + 1) :
+		    NULL;
+
+	s->reference = "HEAD";
+	s->amend = 0;
+	s->verbose = 0;
+	s->commitable = 0;
+}
+
+static void wt_status_print_header(const char *main, const char *sub)
+{
+	const char *c = color(WT_STATUS_HEADER);
+	color_printf_ln(c, "# %s:", main);
+	color_printf_ln(c, "#   (%s)", sub);
+	color_printf_ln(c, "#");
+}
+
+static void wt_status_print_trailer(void)
+{
+	color_printf_ln(color(WT_STATUS_HEADER), "#");
+}
+
+static void wt_status_print_filepair(int t, struct diff_filepair *p)
+{
+	const char *c = color(t);
+	color_printf(color(WT_STATUS_HEADER), "#\t");
+	switch (p->status) {
+	case DIFF_STATUS_ADDED:
+		color_printf(c, "new file: %s", p->one->path); break;
+	case DIFF_STATUS_COPIED:
+		color_printf(c, "copied: %s -> %s",
+				p->one->path, p->two->path);
+		break;
+	case DIFF_STATUS_DELETED:
+		color_printf_ln(c, "deleted: %s", p->one->path); break;
+	case DIFF_STATUS_MODIFIED:
+		color_printf(c, "modified: %s", p->one->path); break;
+	case DIFF_STATUS_RENAMED:
+		color_printf(c, "renamed: %s -> %s",
+				p->one->path, p->two->path);
+		break;
+	case DIFF_STATUS_TYPE_CHANGED:
+		color_printf(c, "typechange: %s", p->one->path); break;
+	case DIFF_STATUS_UNKNOWN:
+		color_printf(c, "unknown: %s", p->one->path); break;
+	case DIFF_STATUS_UNMERGED:
+		color_printf(c, "unmerged: %s", p->one->path); break;
+	default:
+		die("bug: unhandled diff status %c", p->status);
+	}
+	printf("\n");
+}
+
+static void wt_status_print_updated_cb(struct diff_queue_struct *q,
+		struct diff_options *options,
+		void *data)
+{
+	struct wt_status *s = data;
+	int shown_header = 0;
+	int i;
+	if (q->nr) {
+	}
+	for (i = 0; i < q->nr; i++) {
+		if (q->queue[i]->status == 'U')
+			continue;
+		if (!shown_header) {
+			wt_status_print_header("Updated but not checked in",
+					"will commit");
+			s->commitable = 1;
+			shown_header = 1;
+		}
+		wt_status_print_filepair(WT_STATUS_UPDATED, q->queue[i]);
+	}
+	if (shown_header)
+		wt_status_print_trailer();
+}
+
+static void wt_status_print_changed_cb(struct diff_queue_struct *q,
+                        struct diff_options *options,
+                        void *data)
+{
+	int i;
+	if (q->nr)
+		wt_status_print_header("Changed but not updated",
+				"use git-update-index to mark for commit");
+	for (i = 0; i < q->nr; i++)
+		wt_status_print_filepair(WT_STATUS_CHANGED, q->queue[i]);
+	if (q->nr)
+		wt_status_print_trailer();
+}
+
+void wt_status_print_initial(struct wt_status *s)
+{
+	int i;
+	read_cache();
+	if (active_nr) {
+		s->commitable = 1;
+		wt_status_print_header("Updated but not checked in",
+				"will commit");
+	}
+	for (i = 0; i < active_nr; i++) {
+		color_printf(color(WT_STATUS_HEADER), "#\t");
+		color_printf_ln(color(WT_STATUS_UPDATED), "new file: %s",
+				active_cache[i]->name);
+	}
+	if (active_nr)
+		wt_status_print_trailer();
+}
+
+static void wt_status_print_updated(struct wt_status *s)
+{
+	struct rev_info rev;
+	const char *argv[] = { NULL, NULL, NULL };
+	argv[1] = s->reference;
+	init_revisions(&rev, NULL);
+	setup_revisions(2, argv, &rev, NULL);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = wt_status_print_updated_cb;
+	rev.diffopt.format_callback_data = s;
+	rev.diffopt.detect_rename = 1;
+	run_diff_index(&rev, 1);
+}
+
+static void wt_status_print_changed(struct wt_status *s)
+{
+	struct rev_info rev;
+	const char *argv[] = { NULL, NULL };
+	init_revisions(&rev, "");
+	setup_revisions(1, argv, &rev, NULL);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = wt_status_print_changed_cb;
+	rev.diffopt.format_callback_data = s;
+	run_diff_files(&rev, 0);
+}
+
+static void wt_status_print_untracked(const struct wt_status *s)
+{
+	struct dir_struct dir;
+	const char *x;
+	int i;
+	int shown_header = 0;
+
+	memset(&dir, 0, sizeof(dir));
+
+	dir.exclude_per_dir = ".gitignore";
+	x = git_path("info/exclude");
+	if (file_exists(x))
+		add_excludes_from_file(&dir, x);
+
+	read_directory(&dir, ".", "", 0);
+	for(i = 0; i < dir.nr; i++) {
+		/* check for matching entry, which is unmerged; lifted from
+		 * builtin-ls-files:show_other_files */
+		struct dir_entry *ent = dir.entries[i];
+		int pos = cache_name_pos(ent->name, ent->len);
+		struct cache_entry *ce;
+		if (0 <= pos)
+			die("bug in wt_status_print_untracked");
+		pos = -pos - 1;
+		if (pos < active_nr) {
+			ce = active_cache[pos];
+			if (ce_namelen(ce) == ent->len &&
+			    !memcmp(ce->name, ent->name, ent->len))
+				continue;
+		}
+		if (!shown_header) {
+			wt_status_print_header("Untracked files",
+				"use \"git add\" to add to commit");
+			shown_header = 1;
+		}
+		color_printf(color(WT_STATUS_HEADER), "#\t");
+		color_printf_ln(color(WT_STATUS_UNTRACKED), "%.*s",
+				ent->len, ent->name);
+	}
+}
+
+static void wt_status_print_verbose(struct wt_status *s)
+{
+	struct rev_info rev;
+	const char *argv[] = { NULL, NULL, NULL };
+	argv[1] = s->reference;
+	init_revisions(&rev, NULL);
+	setup_revisions(2, argv, &rev, NULL);
+	rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
+	rev.diffopt.detect_rename = 1;
+	run_diff_index(&rev, 1);
+}
+
+void wt_status_print(struct wt_status *s)
+{
+	if (s->branch && strcmp(s->branch, "refs/heads/master"))
+		color_printf_ln(color(WT_STATUS_HEADER),
+			"# On branch %s", s->branch);
+
+	if (s->is_initial) {
+		color_printf_ln(color(WT_STATUS_HEADER), "#");
+		color_printf_ln(color(WT_STATUS_HEADER), "# Initial commit");
+		color_printf_ln(color(WT_STATUS_HEADER), "#");
+		wt_status_print_initial(s);
+	}
+	else {
+		wt_status_print_updated(s);
+		discard_cache();
+	}
+
+	wt_status_print_changed(s);
+	wt_status_print_untracked(s);
+
+	if (s->verbose && !s->is_initial)
+		wt_status_print_verbose(s);
+	if (!s->commitable)
+		printf("%s\n", s->amend ? "# No changes" : "nothing to commit");
+}
+
+int git_status_config(const char *k, const char *v)
+{
+	if (!strcmp(k, "status.color")) {
+		wt_status_use_color = git_config_colorbool(k, v);
+		return 0;
+	}
+	if (!strncmp(k, "status.color.", 13)) {
+		int slot = parse_status_slot(k, 13);
+		color_parse(v, k, wt_status_colors[slot]);
+	}
+	return git_default_config(k, v);
+}
diff --git a/wt-status.h b/wt-status.h
new file mode 100644
index 0000000..75d3cfe
--- /dev/null
+++ b/wt-status.h
@@ -0,0 +1,24 @@
+#ifndef STATUS_H
+#define STATUS_H
+
+enum color_wt_status {
+	WT_STATUS_HEADER,
+	WT_STATUS_UPDATED,
+	WT_STATUS_CHANGED,
+	WT_STATUS_UNTRACKED,
+};
+
+struct wt_status {
+	int is_initial;
+	char *branch;
+	const char *reference;
+	int commitable;
+	int verbose;
+	int amend;
+};
+
+int git_status_config(const char *var, const char *value);
+void wt_status_prepare(struct wt_status *s);
+void wt_status_print(struct wt_status *s);
+
+#endif /* STATUS_H */
-- 
1.4.2.g5290b

^ permalink raw reply related	[relevance 2%]

* Re: Change set based shallow clone
  @ 2006-09-08 14:20  5%       ` Jon Smirl
    0 siblings, 1 reply; 200+ results
From: Jon Smirl @ 2006-09-08 14:20 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Martin Langhoff, git

On 9/8/06, Junio C Hamano <junkio@cox.net> wrote:
> [*4*] In git, there is no inherent server vs client or upstream
> vs downstream relationship between repositories.  You may be
> even fetching from many people and do not have a set upstream at
> all.  Or you are _the_ upstream, and your notebook has the
> latest devevelopment history, and after pushing that latest
> history to your mothership repository, you may decide you do not
> want ancient development history on a puny notebook, and locally
> cauterize the history on your notebook repository and prune
> ancient stuff.  The objects missing from the notebook repository
> are retrievable from your mothership repository again if/when
> needed and you as the user would know that (and if you are lucky
> you may even remember that a few months later), but git doesn't,
> and there is no reason for git to want to know it.  If we want
> to do "fault-in on demand", we need to add a way to say "it is
> Ok for this repository to be incomplete -- objects that are
> missing must be completed from that repository (or those
> repositories)".  But that's quite a special case of having a
> fixed upstream.

A 'not-present' object would be a normal git object, it would contain
a list of sha1s that it is stubbing for. These alias sha1s need to end
up somewhere where the git tools can find them. Maybe put all of the
'not-present' objects into their own pack and add the aliases to the
index. If the aliases point back the 'not-present' object everything
can be validated even if the alias sha1s don't match the one of the
object. This pack would be private and not sent to other repositories.

It would be useful to maintain a list of possible remote repositories
to search for the missing objects if needed. This list could be shared
with people that clone from you.

If you clone from a remote repository that is a partial copy you may
not be able to get all of the objects you want. The only choice here
is to point them to 'not-present' stub and try searching the
alternative repository list.

If you really want to build something for the future, have all of the
git repositories on the net talk to each other and use a distributed
hash scheme to spread redundant copies of the objects out over the
cloud of servers. This will have the effect of creating a global
namespace for all git projects.

-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[relevance 5%]

* Re: Change set based shallow clone
  @ 2006-09-08 23:09  6%     ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2006-09-08 23:09 UTC (permalink / raw)
  To: Jon Smirl; +Cc: linux@horizon.com, Git Mailing List, Paul Mackerras



On Fri, 8 Sep 2006, Jon Smirl wrote:
> 
> gitk would need to be modified to only run enough of the commit tree
> to draw what is displayed in the window.  As you page down it would
> retrive more commits if needed. There is no need for gitk to run 250K
> commits when I'm usually never going to look at them all. Of course
> this may mean some rework for gitk.

Actually, it's more than a little rework.

The _real_ problem is that gitk uses "--topo-order" to git-rev-list, which 
basically means that git-rev-list needs to parse EVERY SINGLE COMMIT.

So far, nobody has written a topological sort that can reasonably 
efficiently handle partial trees and automatically notice when there is no 
way that a DAG cannot have any more references to a commit any more (if 
you can show that the result would cause a cycle, you could output a 
partial topological tree early).

It's possible that no such topological sorting (ie the efficient kind, 
that can work with partial DAG's) even exists.

So if you want to be able to visualize a partial repository, you need to 
teach git to not need "--topo-order" first. That's likely the _big_ 
change. After that, the rest should be easy.

[ One way to do it might be: the normal ordering of revisions without 
  "--topo-order) is "_close_ to topological", and gitk could just decide 
  to re-compute the whole graph whenever it gets a commit that has a 
  parent that it has already graphed. Done right, it would probably almost 
  never actually generate re-computed graphs (if you only actually 
  generate the graph when the user scrolls down to it).

  Getting rid of the --topo-order requirement would speed up gitk 
  absolutely immensely, especially for unpacked cold-cache archives. So it 
  would probably be a good thing to do, regardless of any shallow clone 
  issues ]

Hmm?

		Linus

^ permalink raw reply	[relevance 6%]

* Re: Change set based shallow clone
  @ 2006-09-09  3:13  4%           ` Petr Baudis
  2006-09-09  8:39  3%             ` Jakub Narebski
  0 siblings, 1 reply; 200+ results
From: Petr Baudis @ 2006-09-09  3:13 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

Dear diary, on Fri, Sep 08, 2006 at 05:50:40PM CEST, I got a letter
where Jakub Narebski <jnareb@gmail.com> said that...
> My idea for lazy clone/fetch (lazy = on-demand) is via remote alternatives
> mechanism. We put URI for repository (repositories) that hosts the project,
> and we would need at start to download at least heads and tags, and only
> heads and tags.

  One thing to note is that you won't last very long without getting
at least basically all the commits from the history. git log, git
merge-base and such would either just suck them all, get partially moved
to the server side, or would undergo quite a painful and slooooooooow
process "get me commit X... thank you, sir. hmm, it appears that its
parent is commit Y.  could you get me commit Y, please...? thank you,
sir. hmm, it appears...".

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Snow falling on Perl. White noise covering line noise.
Hides all the bugs too. -- J. Putnam

^ permalink raw reply	[relevance 4%]

* Re: Change set based shallow clone
  2006-09-09  3:13  4%           ` Petr Baudis
@ 2006-09-09  8:39  3%             ` Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2006-09-09  8:39 UTC (permalink / raw)
  To: git

Petr Baudis wrote:

> Dear diary, on Fri, Sep 08, 2006 at 05:50:40PM CEST, I got a letter
> where Jakub Narebski <jnareb@gmail.com> said that...
>> My idea for lazy clone/fetch (lazy = on-demand) is via remote alternatives
>> mechanism. We put URI for repository (repositories) that hosts the project,
>> and we would need at start to download at least heads and tags, and only
>> heads and tags.
> 
>   One thing to note is that you won't last very long without getting
> at least basically all the commits from the history. git log, git
> merge-base and such would either just suck them all, get partially moved
> to the server side, or would undergo quite a painful and slooooooooow
> process "get me commit X... thank you, sir. hmm, it appears that its
> parent is commit Y.  could you get me commit Y, please...? thank you,
> sir. hmm, it appears...".

As I said there is load of troubles with lazy clone/fetch = remote 
alternatives I didn't thought about.

git log/git rev-list and git fsck-objects among them.
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[relevance 3%]

* [PATCH] branch: write branch properties
@ 2006-09-24 22:42  4% Santi Béjar
  2006-09-24 23:00  4% ` Santi Béjar
  0 siblings, 1 reply; 200+ results
From: Santi Béjar @ 2006-09-24 22:42 UTC (permalink / raw)
  To: git


If you want to work in the 'next' branch of git.git:

$ git clone --use-separate-remote git://git.kernel.org/pub/scm/git/git.git
$ cd git
$ git branch next origin next

Signed-off-by: Santi Béjar <sbejar@gmail.com>
---
 Documentation/git-branch.txt |    7 +++++--
 git-branch.sh                |   17 +++++++++++++++--
 git-parse-remote.sh          |   21 +++++++++++++++++++++
 3 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index d43ef1d..de2889d 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -9,7 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git-branch' [-r]
-'git-branch' [-l] [-f] <branchname> [<start-point>]
+'git-branch' [-l] [-f] <branchname> [<start-point> | <remote> <remotebranch>]
 'git-branch' (-d | -D) <branchname>...
 
 DESCRIPTION
@@ -18,9 +18,12 @@ With no arguments given (or just `-r`) a
 will be shown, the current branch will be highlighted with an asterisk.
 
 In its second form, a new branch named <branchname> will be created.
-It will start out with a head equal to the one given as <start-point>.
+It will start out with a head equal to the one given as <start-point>,
+or from branch <remotebranch> of the repository <remote>.
 If no <start-point> is given, the branch will be created with a head
 equal to that of the currently checked out branch.
+In the form <remote> <remotebranch> it will also record the branch
+properties `branch.<branchname>.remote` and `branch.<branchname>.merge`.
 
 With a `-d` or `-D` option, `<branchname>` will be deleted.  You may
 specify more than one branch for deletion.  If the branch currently
diff --git a/git-branch.sh b/git-branch.sh
index e0501ec..94dd157 100755
--- a/git-branch.sh
+++ b/git-branch.sh
@@ -1,9 +1,10 @@
 #!/bin/sh
 
-USAGE='[-l] [(-d | -D) <branchname>] | [[-f] <branchname> [<start-point>]] | -r'
+USAGE='[-l] [(-d | -D) <branchname>] | [[-f] <branchname> [<start-point> | <remote> <remotebranch>]] | -r'
 LONG_USAGE='If no arguments, show available branches and mark current branch with a star.
 If one argument, create a new branch <branchname> based off of current HEAD.
-If two arguments, create a new branch <branchname> based off of <start-point>.'
+If two arguments, create a new branch <branchname> based off of <start-point>.
+If three arguments, create a new branch <branchname> based off the branch <remotebranch> of the repository <remote>, writing the branch properties for fetch.'
 
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
@@ -104,6 +105,12 @@ case "$#" in
 	head=HEAD ;;
 2)
 	head="$2^0" ;;
+3)
+	remote="$2"
+	remote_branch="$3"
+	. ./git-parse-remote.sh
+	ref=$(get_ref_for_remote_branch "$2" "$3")
+	head="$ref^0";;
 esac
 branchname="$1"
 
@@ -128,3 +135,9 @@ then
 	touch "$GIT_DIR/logs/refs/heads/$branchname"
 fi
 git update-ref -m "branch: Created from $head" "refs/heads/$branchname" $rev
+
+if test -n "$ref"
+then
+	git repo-config branch."$branchname".remote "$remote"
+	git repo-config branch."$branchname".merge "$remote_branch"
+fi
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 187f088..51f3b9b 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -209,3 +209,24 @@ resolve_alternates () {
 		esac
 	done
 }
+
+get_ref_for_remote_branch (){
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'' | config-partial | branches | branches-partial)
+		;;
+	config)
+		ref=$(git-repo-config --get-all "remote.$1.fetch" |\
+			grep "^$2:")
+		expr "z$ref" : 'z[^:]*:\(.*\)'
+		;;
+	remotes)
+		ref=$(sed -ne '/^Pull: */{
+				s///p
+			}' "$GIT_DIR/remotes/$1" | grep "$2:")
+		expr "z$ref" : 'z[^:]*:\(.*\)'
+		;;
+	*)
+		die "internal error: get-ref-for-remote-branch $1 $2" ;;
+	esac
+}
-- 
1.4.2.1.g279b

^ permalink raw reply related	[relevance 4%]

* Re: [PATCH] branch: write branch properties
  2006-09-24 22:42  4% [PATCH] branch: write branch properties Santi Béjar
@ 2006-09-24 23:00  4% ` Santi Béjar
  2006-09-25  0:41  4%   ` Santi Béjar
  0 siblings, 1 reply; 200+ results
From: Santi Béjar @ 2006-09-24 23:00 UTC (permalink / raw)
  To: git

Santi Béjar <sbejar@gmail.com> writes:

> If you want to work in the 'next' branch of git.git:
>
> $ git clone --use-separate-remote git://git.kernel.org/pub/scm/git/git.git
> $ cd git
> $ git branch next origin next

this has to be: git branch next origin refs/heads/next

and then you work as usual with:

... work
$ git pull

and it does the right thing.

Please use this instead:

-- >8 --
[PATCH] branch: write branch properties

If you want to work in the 'next' branch of git.git:

$ git clone --use-separate-remote git://git.kernel.org/pub/scm/git/git.git
$ cd git
$ git branch next origin refs/heads/next
... work/edit/commit ...
$ git pull

and it merges from branch 'refs/heads/next' of origin.

Signed-off-by: Santi Béjar <sbejar@gmail.com>
---
 Documentation/git-branch.txt |    7 +++++--
 git-branch.sh                |   17 +++++++++++++++--
 git-parse-remote.sh          |   21 +++++++++++++++++++++
 3 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index d43ef1d..de2889d 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -9,7 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git-branch' [-r]
-'git-branch' [-l] [-f] <branchname> [<start-point>]
+'git-branch' [-l] [-f] <branchname> [<start-point> | <remote> <remotebranch>]
 'git-branch' (-d | -D) <branchname>...
 
 DESCRIPTION
@@ -18,9 +18,12 @@ With no arguments given (or just `-r`) a
 will be shown, the current branch will be highlighted with an asterisk.
 
 In its second form, a new branch named <branchname> will be created.
-It will start out with a head equal to the one given as <start-point>.
+It will start out with a head equal to the one given as <start-point>,
+or from branch <remotebranch> of the repository <remote>.
 If no <start-point> is given, the branch will be created with a head
 equal to that of the currently checked out branch.
+In the form <remote> <remotebranch> it will also record the branch
+properties `branch.<branchname>.remote` and `branch.<branchname>.merge`.
 
 With a `-d` or `-D` option, `<branchname>` will be deleted.  You may
 specify more than one branch for deletion.  If the branch currently
diff --git a/git-branch.sh b/git-branch.sh
index e0501ec..94dd157 100755
--- a/git-branch.sh
+++ b/git-branch.sh
@@ -1,9 +1,10 @@
 #!/bin/sh
 
-USAGE='[-l] [(-d | -D) <branchname>] | [[-f] <branchname> [<start-point>]] | -r'
+USAGE='[-l] [(-d | -D) <branchname>] | [[-f] <branchname> [<start-point> | <remote> <remotebranch>]] | -r'
 LONG_USAGE='If no arguments, show available branches and mark current branch with a star.
 If one argument, create a new branch <branchname> based off of current HEAD.
-If two arguments, create a new branch <branchname> based off of <start-point>.'
+If two arguments, create a new branch <branchname> based off of <start-point>.
+If three arguments, create a new branch <branchname> based off the branch <remotebranch> of the repository <remote>, writing the branch properties for fetch.'
 
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
@@ -104,6 +105,12 @@ case "$#" in
 	head=HEAD ;;
 2)
 	head="$2^0" ;;
+3)
+	remote="$2"
+	remote_branch="$3"
+	. ./git-parse-remote.sh
+	ref=$(get_ref_for_remote_branch "$2" "$3")
+	head="$ref^0";;
 esac
 branchname="$1"
 
@@ -128,3 +135,9 @@ then
 	touch "$GIT_DIR/logs/refs/heads/$branchname"
 fi
 git update-ref -m "branch: Created from $head" "refs/heads/$branchname" $rev
+
+if test -n "$ref"
+then
+	git repo-config branch."$branchname".remote "$remote"
+	git repo-config branch."$branchname".merge "$remote_branch"
+fi
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 187f088..51f3b9b 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -209,3 +209,24 @@ resolve_alternates () {
 		esac
 	done
 }
+
+get_ref_for_remote_branch (){
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'' | config-partial | branches | branches-partial)
+		;;
+	config)
+		ref=$(git-repo-config --get-all "remote.$1.fetch" |\
+			grep "^$2:")
+		expr "z$ref" : 'z[^:]*:\(.*\)'
+		;;
+	remotes)
+		ref=$(sed -ne '/^Pull: */{
+				s///p
+			}' "$GIT_DIR/remotes/$1" | grep "$2:")
+		expr "z$ref" : 'z[^:]*:\(.*\)'
+		;;
+	*)
+		die "internal error: get-ref-for-remote-branch $1 $2" ;;
+	esac
+}
-- 
1.4.2.1.g279b

^ permalink raw reply related	[relevance 4%]

* Re: [PATCH] branch: write branch properties
  2006-09-24 23:00  4% ` Santi Béjar
@ 2006-09-25  0:41  4%   ` Santi Béjar
  0 siblings, 0 replies; 200+ results
From: Santi Béjar @ 2006-09-25  0:41 UTC (permalink / raw)
  To: git

Hi *,

>
> Please use this instead:
>

or even this, sorry:

* . ./git-parse-remotes.sh?
* not a bug, but test for $remote and $remote_branch instead of $ref.

-- >8 --
[PATCH] branch: write branch properties

If you want to work in the 'next' branch of git.git:

$ git clone --use-separate-remote git://git.kernel.org/pub/scm/git/git.git
$ cd git
$ git branch next origin refs/heads/next
... work/edit/commit ...
$ git pull

and it merges from branch 'refs/heads/next' of origin.

Signed-off-by: Santi Béjar <sbejar@gmail.com>
---
 Documentation/git-branch.txt |    7 +++++--
 git-branch.sh                |   17 +++++++++++++++--
 git-parse-remote.sh          |   21 +++++++++++++++++++++
 3 files changed, 41 insertions(+), 4 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index d43ef1d..de2889d 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -9,7 +9,7 @@ SYNOPSIS
 --------
 [verse]
 'git-branch' [-r]
-'git-branch' [-l] [-f] <branchname> [<start-point>]
+'git-branch' [-l] [-f] <branchname> [<start-point> | <remote> <remotebranch>]
 'git-branch' (-d | -D) <branchname>...
 
 DESCRIPTION
@@ -18,9 +18,12 @@ With no arguments given (or just `-r`) a
 will be shown, the current branch will be highlighted with an asterisk.
 
 In its second form, a new branch named <branchname> will be created.
-It will start out with a head equal to the one given as <start-point>.
+It will start out with a head equal to the one given as <start-point>,
+or from branch <remotebranch> of the repository <remote>.
 If no <start-point> is given, the branch will be created with a head
 equal to that of the currently checked out branch.
+In the form <remote> <remotebranch> it will also record the branch
+properties `branch.<branchname>.remote` and `branch.<branchname>.merge`.
 
 With a `-d` or `-D` option, `<branchname>` will be deleted.  You may
 specify more than one branch for deletion.  If the branch currently
diff --git a/git-branch.sh b/git-branch.sh
index e0501ec..78e2c92 100755
--- a/git-branch.sh
+++ b/git-branch.sh
@@ -1,9 +1,10 @@
 #!/bin/sh
 
-USAGE='[-l] [(-d | -D) <branchname>] | [[-f] <branchname> [<start-point>]] | -r'
+USAGE='[-l] [(-d | -D) <branchname>] | [[-f] <branchname> [<start-point> | <remote> <remotebranch>]] | -r'
 LONG_USAGE='If no arguments, show available branches and mark current branch with a star.
 If one argument, create a new branch <branchname> based off of current HEAD.
-If two arguments, create a new branch <branchname> based off of <start-point>.'
+If two arguments, create a new branch <branchname> based off of <start-point>.
+If three arguments, create a new branch <branchname> based off the branch <remotebranch> of the repository <remote>, writing the branch properties for fetch.'
 
 SUBDIRECTORY_OK='Yes'
 . git-sh-setup
@@ -104,6 +105,12 @@ case "$#" in
 	head=HEAD ;;
 2)
 	head="$2^0" ;;
+3)
+	remote="$2"
+	remote_branch="$3"
+	. git-parse-remote
+	ref=$(get_ref_for_remote_branch "$2" "$3")
+	head="$ref^0";;
 esac
 branchname="$1"
 
@@ -128,3 +135,9 @@ then
 	touch "$GIT_DIR/logs/refs/heads/$branchname"
 fi
 git update-ref -m "branch: Created from $head" "refs/heads/$branchname" $rev
+
+if test -n "$remote" && test -n "$remote_branch"
+then
+	git repo-config branch."$branchname".remote "$remote"
+	git repo-config branch."$branchname".merge "$remote_branch"
+fi
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 187f088..51f3b9b 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -209,3 +209,24 @@ resolve_alternates () {
 		esac
 	done
 }
+
+get_ref_for_remote_branch (){
+	data_source=$(get_data_source "$1")
+	case "$data_source" in
+	'' | config-partial | branches | branches-partial)
+		;;
+	config)
+		ref=$(git-repo-config --get-all "remote.$1.fetch" |\
+			grep "^$2:")
+		expr "z$ref" : 'z[^:]*:\(.*\)'
+		;;
+	remotes)
+		ref=$(sed -ne '/^Pull: */{
+				s///p
+			}' "$GIT_DIR/remotes/$1" | grep "$2:")
+		expr "z$ref" : 'z[^:]*:\(.*\)'
+		;;
+	*)
+		die "internal error: get-ref-for-remote-branch $1 $2" ;;
+	esac
+}
-- 
1.4.2.1.gf2ca-dirty

^ permalink raw reply related	[relevance 4%]

* Re: VCS comparison table
    @ 2006-10-14 20:20  2% ` Jakub Narebski
  2006-10-14 23:06  0%   ` Jon Smirl
    2 siblings, 1 reply; 200+ results
From: Jakub Narebski @ 2006-10-14 20:20 UTC (permalink / raw)
  To: git

Jon Smirl wrote:

> I was reading Brendan's blog post about Mozilla 2
> http://weblogs.mozillazine.org/roadmap/archives/2006/10/mozilla_2.html

You mean:
 "Oh, and isn't it time that we get off of CVS? The best way to do that
  without throwing 1.9 into an uproar is to develop Mozilla 2 using a new
  Version Control System (VCS) that can merge with CVS (since we will want
  to track changes to files not being revamped at first, or at all; and
  we'll probably find bugs whose fixes should flow back into 1.9). The
  problem with VCSes is that there are too many to choose from now.
  Nevertheless, looking for mostly green columns in that chart should help
  us make a quick decision. We don't need "the best" or the "newest", but we
  do need better merging, branching, and renaming support."

There is work by Jon Smirl and Shawn Pearce on CVS to Git importer which can
manage large and complicated (read: f*cked-up) Mozilla CVS repository.
  http://git.or.cz/gitwiki/InterfacesFrontendsAndTools#cvs2git

By the way, I'd rather use SCM comparison table on neutral site, not on SCM
site.


I think that Mozilla project should come with it's own set of requirements
and weights for best SCM _for Mozilla project_.

1. Converting existing CVS repository. This should be without data loss...
well, beside data loss that stems from using CVS in first place. "Best" SCM
would have:
  * Tool to convert CVS repository, which can then incrementally import
    changes.
  * It would be nice to have tool to exchange commits between SCM and CVS,
    be it like Tailor/git-svn, or via incremental import and exporting
    commits to CVS like git-cvsexportcommit. This would ease changing SCM,
    as both new SCM and CVS could be deployed in parallel, for a short time
    of course.
  * It would be nice to have CVS emulation like git-cvsserver, so users
    accustomed to CVS could still use it.

2. Good support for system which most important developers use, and good
support for system which most contributors use. If MS Windows is included
in those, then Git perhaps wouldn't be the best choice.

3. Good support for the workflow used in the project. Is it exchanging
patches via email (hello, Git!), having ssh access to some central
repository with central repository to push changes to or net/mesh of
repositories exchanging information, posting patches on some bug tracking
software integrated with SCM. Is it using many branches (topic branches),
or is it using few branches and merging.

But it is equally important to realize what would be the best workflow to
use, not constraining itself to the workflow imposed by limitations of CVS.

4. Good support for _large_ project, with large history. Namely, that
developer wouldn't need to download many megabytes and/or wouldn't need
megabytes of working area. How that is solved, be it partial checkouts,
lazy/shallow/sparse clone, subprojects, splitting into
projects/repositories and having some superproject or build-time
superproject, splitting repository into current and historical... that of
course depends on SCM.

5. ....

and probably few more
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[relevance 2%]

* Re: VCS comparison table
  2006-10-14 20:20  2% ` Jakub Narebski
@ 2006-10-14 23:06  0%   ` Jon Smirl
                         ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: Jon Smirl @ 2006-10-14 23:06 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

On 10/14/06, Jakub Narebski <jnareb@gmail.com> wrote:
> Jon Smirl wrote:
>
> > I was reading Brendan's blog post about Mozilla 2
> > http://weblogs.mozillazine.org/roadmap/archives/2006/10/mozilla_2.html
>
> You mean:
>  "Oh, and isn't it time that we get off of CVS? The best way to do that
>   without throwing 1.9 into an uproar is to develop Mozilla 2 using a new
>   Version Control System (VCS) that can merge with CVS (since we will want
>   to track changes to files not being revamped at first, or at all; and
>   we'll probably find bugs whose fixes should flow back into 1.9). The
>   problem with VCSes is that there are too many to choose from now.
>   Nevertheless, looking for mostly green columns in that chart should help
>   us make a quick decision. We don't need "the best" or the "newest", but we
>   do need better merging, branching, and renaming support."
>
> There is work by Jon Smirl and Shawn Pearce on CVS to Git importer which can
> manage large and complicated (read: f*cked-up) Mozilla CVS repository.
>   http://git.or.cz/gitwiki/InterfacesFrontendsAndTools#cvs2git

I am still working with the developers of the cvs2svn import tool to
fix things so that Mozilla CVS can be correctly imported. There are
still outstanding bugs in cvs2svn preventing a correct import. MozCVS
can be imported, but the resulting repository is not entirely correct.

Once they get the base cvs2svn fixed I'll port my patches to turn it
into cvs2git again.

There is no existing CVS importer that will correctly import the
Mozilla CVS. I have tried them all.

> By the way, I'd rather use SCM comparison table on neutral site, not on SCM
> site.
>
>
> I think that Mozilla project should come with it's own set of requirements
> and weights for best SCM _for Mozilla project_.
>
> 1. Converting existing CVS repository. This should be without data loss...
> well, beside data loss that stems from using CVS in first place. "Best" SCM
> would have:
>   * Tool to convert CVS repository, which can then incrementally import
>     changes.
>   * It would be nice to have tool to exchange commits between SCM and CVS,
>     be it like Tailor/git-svn, or via incremental import and exporting
>     commits to CVS like git-cvsexportcommit. This would ease changing SCM,
>     as both new SCM and CVS could be deployed in parallel, for a short time
>     of course.

>From what Brendan wrote they are looking to continue 1.9 in CVS and
start 2.0 in a new SCM. This pretty much mandates tracking CVS into
the new SCM for a long period of time. Possibly as much as two years.
There does not appear to be a need to push 2.0 back into CVS.


>   * It would be nice to have CVS emulation like git-cvsserver, so users
>     accustomed to CVS could still use it.

This can also solve some of the problems with Windows support.

>
> 2. Good support for system which most important developers use, and good
> support for system which most contributors use. If MS Windows is included
> in those, then Git perhaps wouldn't be the best choice.

Better Windows support is needed to make git the first choice among
the various SCMs.

>
> 3. Good support for the workflow used in the project. Is it exchanging
> patches via email (hello, Git!), having ssh access to some central
> repository with central repository to push changes to or net/mesh of
> repositories exchanging information, posting patches on some bug tracking
> software integrated with SCM. Is it using many branches (topic branches),
> or is it using few branches and merging.
>
> But it is equally important to realize what would be the best workflow to
> use, not constraining itself to the workflow imposed by limitations of CVS.

A big problem for Mozilla is outside companies doing major work in a
local CVS. Since CVS is not decentralized these local repos drift away
from the main one over time making things hard to merge. Any new SCM
will have to be distributed.

> 4. Good support for _large_ project, with large history. Namely, that
> developer wouldn't need to download many megabytes and/or wouldn't need
> megabytes of working area. How that is solved, be it partial checkouts,
> lazy/shallow/sparse clone, subprojects, splitting into
> projects/repositories and having some superproject or build-time
> superproject, splitting repository into current and historical... that of
> course depends on SCM.

git has issues here. The smallest Mozilla download we have built so
far is 450MB for the initial checkout.

>
> 5. ....
>
> and probably few more


The three most complex repositories are the kernel, gcc and Mozilla.
Gcc is in SVN now. Mozilla CVS and the kernel git.

There are much larger repositories around for some of the distros, but
they are doing things like checking ISO images in to the repo which
just makes it big,, not complex.

Top two git issues effecting Mozilla choosing it
1) some way to avoid the initial 450MB download
2) better windows support


-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply	[relevance 0%]

* Re: VCS comparison table
  2006-10-14 23:06  0%   ` Jon Smirl
  @ 2006-10-15  0:53  1%     ` Jakub Narebski
  2006-10-15 18:23  0%     ` Petr Baudis
  2 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2006-10-15  0:53 UTC (permalink / raw)
  To: Jon Smirl; +Cc: git

Jon Smirl wrote:
> On 10/14/06, Jakub Narebski <jnareb@gmail.com> wrote:

>>   * It would be nice to have tool to exchange commits between SCM and CVS,
>>     be it like Tailor/git-svn, or via incremental import and exporting
>>     commits to CVS like git-cvsexportcommit. This would ease changing SCM,
>>     as both new SCM and CVS could be deployed in parallel, for a short time
>>     of course.
> 
> From what Brendan wrote they are looking to continue 1.9 in CVS and
> start 2.0 in a new SCM. This pretty much mandates tracking CVS into
> the new SCM for a long period of time. Possibly as much as two years.
> There does not appear to be a need to push 2.0 back into CVS.

That of course limits what we can do in 1.9 to what CVS supports.

> >   * It would be nice to have CVS emulation like git-cvsserver, so users
> >     accustomed to CVS could still use it.
> 
> This can also solve some of the problems with Windows support.

Well, git-cvsserver (perhaps with some improvements) could also serve as
CVS server for 1.9.
 
> > 4. Good support for _large_ project, with large history. Namely, that
> > developer wouldn't need to download many megabytes and/or wouldn't need
> > megabytes of working area. How that is solved, be it partial checkouts,
> > lazy/shallow/sparse clone, subprojects, splitting into
> > projects/repositories and having some superproject or build-time
> > superproject, splitting repository into current and historical... that of
> > course depends on SCM.
> 
> git has issues here. The smallest Mozilla download we have built so
> far is 450MB for the initial checkout.

One way to reduce repository size would be to split fairly independent
subprojects (inependent = independently testable) into separate repositories,
and perhaps use some kind of "super-repository" (common repository) to join
all the project in one single entity. The split can be done using
git-splitrepo (or something like that) which was posted on git mailing list
(most probably by some member of X.Org), or just cg-admin-rewritehist.
While at it we could split repository into current work and historical repo;
and clean up current work repository from the cruft accumulated (e.g. dead
branches, broken tags etc.).


Another way is to use grafts.

Linux kernel has it's current repository (starting somewhere 2.6.x),
and it's historical repository. I don't remember how they arrived at it
(and don't want to check KernelTrap articles), if the seed for current
work repository was simply project import at some state, or (very slow)
import of BitKeeper history. But if I remember correctly it was born split.
You can join both repositories into one (wrt. log and diff for example)
using grafts.

I'm not sure what happens if you pull from repository which has graft
file "cauterizing" history; would you get graft file and history up to
cutoff point? What would happen if your repository, repository you pull to
has cauterization graft file; would it get cut history? Of course
the problem (and the source of proposal and troubles with implementing
of shallow/sparse/lazy clone) lies if someone branches (in public repo)
from below cutoff point. But that is a matter of policy.

But it is true that the size of Mozilla repository is a challenge.
BTW. do you perchance know how other SCM dels with the repository
of that size?

-- 
Jakub Narebski
ShadeHawk on #git
Poland

^ permalink raw reply	[relevance 1%]

* Re: VCS comparison table
       [not found]             ` <20061014214452.8c2d2a5c.seanlkml@sympatico.ca>
@ 2006-10-15  1:44  1%           ` Sean
  0 siblings, 0 replies; 200+ results
From: Sean @ 2006-10-15  1:44 UTC (permalink / raw)
  To: Jon Smirl; +Cc: Jakub Narebski, git

On Sat, 14 Oct 2006 20:34:22 -0400
"Jon Smirl" <jonsmirl@gmail.com> wrote:

> That is possible but I wish git had tools supporting this. What do you
> do about core developers that want the full repo syncing to other
> developers that only have a partial copy?

I don't think that will be an issue at all.

As an example, take the current Linux kernel repo maintained by Linus,
and one of the repos containing old historic kernel data imported into
Git.  Graft in the old historic data into your clone of Linus' repo,
and you're done. Anyone can pull from you even if they don't have the
historic data themselves.

With a little work you could do the same thing with the Mozilla data.
After you decide where to make the split, you'd have to rewrite the
commit history for the "current" repository, so that it terminates
at an initial commit rather than having a direct connection to the
historic data.  After that, the repos could be used just as described
above, separately or graphed together.

As far as I know though, there is still no way to use the git protocol
for the initial pull of such a combined repository.  You have to pull
both repos separately and graft them together locally.  This sounds
harder than it is though and can be scripted easily.

Sean

^ permalink raw reply	[relevance 1%]

* Re: VCS comparison table
  2006-10-14 23:06  0%   ` Jon Smirl
    2006-10-15  0:53  1%     ` Jakub Narebski
@ 2006-10-15 18:23  0%     ` Petr Baudis
  2 siblings, 0 replies; 200+ results
From: Petr Baudis @ 2006-10-15 18:23 UTC (permalink / raw)
  To: Jon Smirl; +Cc: Jakub Narebski, git

Dear diary, on Sun, Oct 15, 2006 at 01:06:10AM CEST, I got a letter
where Jon Smirl <jonsmirl@gmail.com> said that...
> On 10/14/06, Jakub Narebski <jnareb@gmail.com> wrote:
> >There is work by Jon Smirl and Shawn Pearce on CVS to Git importer which 
> >can
> >manage large and complicated (read: f*cked-up) Mozilla CVS repository.
> >  http://git.or.cz/gitwiki/InterfacesFrontendsAndTools#cvs2git
> 
> I am still working with the developers of the cvs2svn import tool to
> fix things so that Mozilla CVS can be correctly imported. There are
> still outstanding bugs in cvs2svn preventing a correct import. MozCVS
> can be imported, but the resulting repository is not entirely correct.
> 
> Once they get the base cvs2svn fixed I'll port my patches to turn it
> into cvs2git again.

So what exactly is the cvs2git status now? AFAIU, there's a tool that
parses the CVS repository and that is then "piped" to git-fastimport?
git-fastimport is available somewhere (perhaps it would be interesting
to publish it at repo.or.cz or something), is the current cvs2git
version available as well?

> >2. Good support for system which most important developers use, and good
> >support for system which most contributors use. If MS Windows is included
> >in those, then Git perhaps wouldn't be the best choice.
> 
> Better Windows support is needed to make git the first choice among
> the various SCMs.

And this is probably not likely to happen soon.

Well, I'm enlisted in a "Programming in Windows" course at my university
now and I had this kind of thoughts, but I really can't promise
anything. :-)

> >4. Good support for _large_ project, with large history. Namely, that
> >developer wouldn't need to download many megabytes and/or wouldn't need
> >megabytes of working area. How that is solved, be it partial checkouts,
> >lazy/shallow/sparse clone, subprojects, splitting into
> >projects/repositories and having some superproject or build-time
> >superproject, splitting repository into current and historical... that of
> >course depends on SCM.
> 
> git has issues here. The smallest Mozilla download we have built so
> far is 450MB for the initial checkout.

(BTW, yes, grafting the old history could help this time, but it is a
hack and not a good long-term solution - it is just putting the real
solution away until the project history will re-grew. Periodical
regrafting is even worse hack, since at that moment you break
fast-forwarding and this kind of "restarting the history" breaks deep
into the Git distributiveness.)

> >5. ....
> >
> >and probably few more
> 
> 
> The three most complex repositories are the kernel, gcc and Mozilla.
> Gcc is in SVN now. Mozilla CVS and the kernel git.

I believe OpenOffice CVS probably beats all three hands down very
easily. KDE is also very big, and I don't think NetBSD is just ISO
images either (if it contains any at all).

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
$/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1
lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/)

^ permalink raw reply	[relevance 0%]

* Re: VCS comparison table
  @ 2006-10-20 22:50  3%     ` Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2006-10-20 22:50 UTC (permalink / raw)
  To: James Henstridge
  Cc: bazaar-ng, Linus Torvalds, Carl Worth, Andreas Ericsson, git

On 20-10-2006, James Henstridge wrote:
> On 20/10/06, Jakub Narebski <jnareb@gmail.com> wrote:
>> James Henstridge wrote:

>>> With the above layout, I would just type:
>>>     bzr branch http://server/repo/branch1
>>
>> With Cogito (you can think of it either as alternate Git UI, or as SCM
>> built on top of Git) you would use
>>
>>    $ cg clone http://server/repo#branch
>>
>> for example
>>
>>    $ cg clone git://git.kernel.org/pub/scm/git/git.git#next
>>
>> to clone _single_ branch (in bzr terminology, "heavy checkout" of branch).
> 
> My understanding of git is that this would be equivalent to the "bzr
> branch" command.  A checkout (heavy or lightweight) has the property
> that commits are made to the original branch.

Not exactly (my mistake in explaining it). "cg clone git://host/repo@branch"
clones only part of history DAG of commits reachable from given branch.
Still it is full repository. You can add branches to it later with
cg-branch-add and fetch changes with cg-fetch.

>> But you can also clone _whole_ repository, _all_ published branches with
>>
>>    $ cg clone git://git.kernel.org/pub/scm/git/git.git
> 
> I suppose that'd be useful if you want a copy of all the branches at
> once.  There is no builtin command in Bazaar to do that at present.

That is _very_ useful. And that is default option for Git. For
example with git.git repository I'm interested both in 'master'
branch (main line of development), and in 'next' branch (development
branch). For example I send some patches, based on 'master', they
get accepted but in 'next' (to cook for a while for example), and
I want to do further work in this direction I have to base my
new work on 'next' branch.

It looks like the Bazaar-NG "branches" are equivalent of the
one-branch-clone of Git.

And if there is no command to clone whole repository, how
you do public repository?

See below.

[...] 
> Two points:
> (1) if we are publishing branches, we wouldn't include working trees
> -- they are not needed to pull or merge from such a branch.

Same with Git. Public repositories are usually "bare" clones, i.e.
without working directory. We can clone/fetch from "clothed" repo
without problem - we just have to point to .git.

> (2) if we did have working trees, they'd be rooted at /repo/branch1
> and /repo/branch2 -- not at /repo (since /repo is not a branch).

That's explains it.

> In case (2) there is a potential for conflicts if you nest branches,
> but people don't generally trigger this problem with the way they use
> Bazaar.

There is no problem in Git to have git repository nested within
working area: of course you better ignore .git directory; you can
ignore files in this embedded repository or not.

[...]
>> How checked out working area looks like in Bazaar-NG?
> 
> The layout of a standalone branch would be:
>   .bzr/repository/ -- storage of trees and metadata
>   .bzr/branch/ -- branch metadagta (e.g. pointer to the head revision)
>   .bzr/checkout/ -- working tree book-keeping files
>   source code

The layout of git repository (git clone, as it is equivalent of bzr branch)
you have the following layout:
  .git/objects/ -- repository objects database
  .git/refs/ -- heads (branches) and tags
  .git/index -- staging area for commit (adding files, merge resolving)
  .git/HEAD -- which branch is current branch
  source code

> If we use a shared repository, the contained branches would lack the
> .bzr/repository/ directory.  The parent directory would instead have a
> .bzr/repository/, but usually wouldn't have .bzr/branch/ (unless there
> is a branch rooted at the base of the repository).

The equivalent of shared repository would be having .git/objects/
to be symlink to some directory which would serve as common area
to store object database.

You can use alternates file: .git/objects/info/alternates can have
list of absolute pathnames (one per line) where objects can be found
instead. If I understand correctly new objects gets commited to current
repository object database, therefore to have equivalent of symlinking
.git/objects directory you would have for every repository which you
want to share object database to have in alternates file all repositories
except self. 

Or you can use GIT_ALTERNATE_OBJECT_DIRECTORIES environmental variable.

Repository using any kind of alternates mechanism is not suitable
to publish using "dumb" (non-git-aware) transports.

> if we are publishing a branch to a web server, we'd skip the working
> tree, so the source code and .bzr/checkout/ directory would be
> missing.

For "bare" clone only 'source files' would be missing. Well, perhaps
also '.git/index' but I'm not sure.

> In the case of a checkout, the .bzr/branch/ directory has a special
> format and acts as a pointer to the original branch.  If the checkout
> is lightweight, the .bzr/repository/ directory would be missing, and
> bzr would need to contact the original branch for the data.

There is no equivalent for bzr "checkout" (and could you please use
other name for that, like "lazy branch"?) in Git. There was some talk
about how to do "lazy clone"/"remote alternates" in Git, but no consensus
was reached about how to do this effectively, and for both "dumb"
(http, https, ftp, rsync) transports and git-aware (local, git, ssh+git)
transports. From what I've read Bazaar-NG doesn't try the "effective"
part...

[...]
>> Yes, but using Git that way has serious disadvantages. For example
>> there is only one current branch pointer and only one index (dircache)
>> per git repository.
> 
> Okay.  So using Bazaar terminology, this seems to be an issue of the
> working tree being associated with the repository rather than the
> branch?
 
From the point of view of Git users, there is (in Bazaar-NG) an issue
of working tree being associated with the individual branch rather than
repository.

In git to work on some project you clone its repository; in bzr to
work on some project you get one of its branches.


IMVHO if "Cheap Branching Anywhere" was changed to "Lightweight Branches"
then Bazaar-NG would have to put "Partial" in there. Unless you setup
your branches to share data, branches are not cheap (in the sense of
disk space). That's probably the cause for _need_ for "checkouts".
Bazaar-NG doesn't encourage using temporary branches, with
lifespan no longer than day. Can you ever switch between branches
using only one working area; can you do it fast?

It looks somewhat like bzr started without permanent branches, and
they were added later (sharing repository data). But I might be mistaken.

P.S. what Git lacks at least now is a way to generate diff between
two different local repositories, but you can always setup alternates
file and fetch the other repository into some tag.
-- 
Jakub Narebski
Poland

^ permalink raw reply	[relevance 3%]

* Re: VCS comparison table
  @ 2006-10-21 18:58  3%             ` Jan Hudec
       [not found]                   ` <20061021150233.c29e11c5.seanlkml@sympatico.ca>
  0 siblings, 1 reply; 200+ results
From: Jan Hudec @ 2006-10-21 18:58 UTC (permalink / raw)
  To: Aaron Bentley; +Cc: Sean, Linus Torvalds, bazaar-ng, git, Jakub Narebski

On Tue, Oct 17, 2006 at 03:51:56PM -0400, Aaron Bentley wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Sean wrote:
> > On Tue, 17 Oct 2006 00:24:15 -0400
> > Aaron Bentley <aaron.bentley@utoronto.ca> wrote:
> >>- - you can use a checkout to maintain a local mirror of a read-only
> >>  branch (I do this with http://bazaar-vcs.com/bzr/bzr.dev).
> > 
> > 
> > I'm not sure what you mean here.  A bzr checkout doesn't have any history
> > does it?
> 
> By default, they do.  You must use a flag to get a checkout with no history.

If I can add some clarification: There is a lightweight checkout and
heavyweight checkout. The former contains no history and does everything
(except status and I am not sure about diff) by accessing the remote
data. The later contains mirror of the history data and does
write-through on commit (and otherwise behaves like normal branch with
repository)

What would be really useful would be a checkout, or even a branch (ie.
with ability to commit locally), that would only contain history data
since some point. This would allow downloading very little data when
branching, but than working locally as with normal repository clone.

In bzr this was already discussed and the storage supports so called
"ghost" revisions, whose existence is known, but not their data. There
are even repositories around that contain them (created by converting
data from arch), but to my best knowledge there is no user interface to
create branches or checkouts with partial data.

--------------------------------------------------------------------------------
                  				- Jan Hudec `Bulb' <bulb@ucw.cz>

^ permalink raw reply	[relevance 3%]

* Re: VCS comparison table
       [not found]                   ` <20061021150233.c29e11c5.seanlkml@sympatico.ca>
  2006-10-21 19:02  1%                 ` Sean
@ 2006-10-21 19:02  1%                 ` Sean
  1 sibling, 0 replies; 200+ results
From: Sean @ 2006-10-21 19:02 UTC (permalink / raw)
  To: Jan Hudec; +Cc: Aaron Bentley, Linus Torvalds, bazaar-ng, git, Jakub Narebski

On Sat, 21 Oct 2006 20:58:25 +0200
Jan Hudec <bulb@ucw.cz> wrote:

> In bzr this was already discussed and the storage supports so called
> "ghost" revisions, whose existence is known, but not their data. There
> are even repositories around that contain them (created by converting
> data from arch), but to my best knowledge there is no user interface to
> create branches or checkouts with partial data.

In Git the same functionality can be achieved with so called shallow-
clones.  Unfortunately, they've only been discussed and not yet
implemented.

Sean

^ permalink raw reply	[relevance 1%]

* Re: VCS comparison table
       [not found]                   ` <20061021150233.c29e11c5.seanlkml@sympatico.ca>
@ 2006-10-21 19:02  1%                 ` Sean
  2006-10-21 19:02  1%                 ` Sean
  1 sibling, 0 replies; 200+ results
From: Sean @ 2006-10-21 19:02 UTC (permalink / raw)
  To: Jan Hudec; +Cc: Linus Torvalds, bazaar-ng, git, Jakub Narebski

On Sat, 21 Oct 2006 20:58:25 +0200
Jan Hudec <bulb@ucw.cz> wrote:

> In bzr this was already discussed and the storage supports so called
> "ghost" revisions, whose existence is known, but not their data. There
> are even repositories around that contain them (created by converting
> data from arch), but to my best knowledge there is no user interface to
> create branches or checkouts with partial data.

In Git the same functionality can be achieved with so called shallow-
clones.  Unfortunately, they've only been discussed and not yet
implemented.

Sean

^ permalink raw reply	[relevance 1%]

* Re: VCS comparison table
  @ 2006-10-26 11:48  4%                       ` Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2006-10-26 11:48 UTC (permalink / raw)
  To: bazaar-ng; +Cc: git

Andreas Ericsson wrote:

> On a side-note, git has made my life easier, so I childishly want to 
> defend it and see it on top of every list in the world. Something I'm 
> sure I share with more people on this list and with some of the bazaar 
> users/devs. ;-)

Let's then us review what started this thread, namely comparison chart
between source control systems
  http://bazaar-vcs.org/RcsComparisons

1. Decentralized. O.K.

2. Disconnected Ops. O.K.

3. Simple Namespace. Should be named "Simple Rev Names" instead, Bazaar
should have note that revnos work only for specific workflows
(star-topology); for Git it should be perhaps "Somewhat" here, as <ref>~<n>
(or <ref>@{<n>} if reflog is enabled) _are_ simple (if volatile for branch
<refs>). $(git-merge-base <ref1> <ref2>), usually "hidden" in
<ref1>..<ref2> or <ref1>...<ref2> shortcut is also I think simple. There
was huge discussion here about revnos, revids, workflows (development
topology), fast-forwards, empty merges etc. Bazaar-NG and Git puts
emphasisis on other things. Additionally tags supports removes some of
perceived revnos advantages; tags are simple.

4. Supports Renames. I could agree with "Somewhat" because of not yet
implemented --follow option to git-rev-list (and therefore all porcelain).
Perhaps it would be closer to truth to leave the marker (background color)
as for "Somewhat" and write "N/A" with note that Git has contents and
pathname based heuristic detection of renames, or just put "Detect" or
"Detection" here.

I would certainly change description of what means that SCM doesn't "Support
Renames" or has it implemented partially. Current explanation relies
heavily on _implementation_. The correct wording of current definition
would be that SCM doesn't support renames if history of a file "as visible
to SCM" is broken into before rename and after rename part, and that SCM
support it partially if you can track history of renamed file from
post-rename name but there is left in void history of pre-rename file.
But with this definition Git _does_ "Supports Renames".

I'd rather split "Supports Renames" into engine part (does SCM
remember/detect that rename took place _as_ rename, not remember/detect it
as copiying+deletion; something other than rename) and user interface part:
can user easily deal with renames (this includes merging and viewing file
history).

5 and 6. Needs Repository/Supports Repository. The name is very, very
unclean and stems from branch-centricness of Bazaar. Git should probably
have "Yes" here, as for Git branch is just reference to its tip in
revisions DAG (plus optionally branch tip history in reflog). On the other
hand Git _can_ share object database like branches can be gathered together
to share data into repository. You can have one-branch repositories, you
can clone whole repositories (perhaps Bazaar should have "Somewhat" for
Supports Repository as it doesn't support cloning of whole repository...
bzt, wrong, there is example plugin for that), and you can clone (using
Cogito) only one branch of repository and you can fetch only selected
branches of repository.

Thinking more about it those items should probably read "Support Individual
Branches" (as: can you get only the branch you are interested in, can SCM
support one-branch workflow) and "Support Branch Grouping" or "Support Data
Sharing" (as: can you share DAG between branches, can you share DAG between
repositories).

7. Checkouts (as a noun). This probably read "Support Centralized and
Disconnected Centralized Workflow" but that is perhaps too wordy. Git would
have "No" for "Centralized" and "Somewhat" for "Disconnected Centralized"
meaning that you can set up Git repository to be equivalent of heavyweight
checkout, and push changes to some given repository on commit.

8. Partial Checkouts (as a verb). Here Git should have perhaps "Minimal", as
you can have partial checkouts but only with care (and you still need whole
repository). "No?" is also correct (?).

9. Atomic Commits. O.K. You have to remember that there are consequences
of having Atomic Commits on the details of Partial Checkouts.

10. Cheap Branching Anywhere. Git should probably have "Yes! Yes! Yes!"
here ;-)

11. Smart Merge. O.K. Should probably be explained what constitutes smart
merging. Perhaps instead of "Yes" there should be name of default/smartest
merge strategy used?

12. Cherrypicks. What constitutes "Yes" here? Why "Somewhat" for Git?
It does have git-cherry-pick command for cherry picking...

13. Plugins. I would put "Somewhat" here, or "Scriptable" in the "Somewhat"
or "?" background color for Git. And add note that it is easy to script up
porcelanish command, and to add another merge strategy. There also was
example plugin infrastructure for Cogito, so I'd opt for "Someahwt"
marking.

14. Has Special Server. O.K.

15. Req. Dedicated Server. O.K.

16. Good Windows support. I'd put "Cygwin" instead of "No" for Git, although
with the same marking. And perhaps add note that Git relies heavily on
POSIX.

17 and 18. Fast Local Performance and Fast Network Performance. O.K.

19. Ease of Use. Hmmm... I don't know for Git. I personally find it very
easy to use, but I have not much experiences with other SCM. I wonder why
Bazaar has "No" there...


Too much rewriting to correct the page...


^ permalink raw reply	[relevance 4%]

* [PATCH] enhance clone and fetch -k experience
@ 2006-10-27 19:42  5% Nicolas Pitre
  0 siblings, 0 replies; 200+ results
From: Nicolas Pitre @ 2006-10-27 19:42 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Now that index-pack can be streamed with a pack, it is probably a good 
idea to use it directly instead of creating a temporary file and running 
index-pack afterwards.  This way index-pack can abort early whenever a 
corruption is encountered even if the pack has not been fully 
downloaded, it can display a progress percentage as it knows how much to 
expects, and it is a bit faster since the pack indexing is partially 
done as data is received. Using fetch -k doesn't need to disable thin 
pack generation on the remote end either.

Signed-off-by: Nicolas Pitre <nico@cam.org>

---

diff --git a/fetch-clone.c b/fetch-clone.c
index 76b99af..96cdab4 100644
--- a/fetch-clone.c
+++ b/fetch-clone.c
@@ -3,97 +3,6 @@
 #include "pkt-line.h"
 #include "sideband.h"
 #include <sys/wait.h>
-#include <sys/time.h>
-
-static int finish_pack(const char *pack_tmp_name, const char *me)
-{
-	int pipe_fd[2];
-	pid_t pid;
-	char idx[PATH_MAX];
-	char final[PATH_MAX];
-	char hash[41];
-	unsigned char sha1[20];
-	char *cp;
-	int err = 0;
-
-	if (pipe(pipe_fd) < 0)
-		die("%s: unable to set up pipe", me);
-
-	strcpy(idx, pack_tmp_name); /* ".git/objects/pack-XXXXXX" */
-	cp = strrchr(idx, '/');
-	memcpy(cp, "/pidx", 5);
-
-	pid = fork();
-	if (pid < 0)
-		die("%s: unable to fork off git-index-pack", me);
-	if (!pid) {
-		close(0);
-		dup2(pipe_fd[1], 1);
-		close(pipe_fd[0]);
-		close(pipe_fd[1]);
-		execl_git_cmd("index-pack", "-o", idx, pack_tmp_name, NULL);
-		error("cannot exec git-index-pack <%s> <%s>",
-		      idx, pack_tmp_name);
-		exit(1);
-	}
-	close(pipe_fd[1]);
-	if (read(pipe_fd[0], hash, 40) != 40) {
-		error("%s: unable to read from git-index-pack", me);
-		err = 1;
-	}
-	close(pipe_fd[0]);
-
-	for (;;) {
-		int status, code;
-
-		if (waitpid(pid, &status, 0) < 0) {
-			if (errno == EINTR)
-				continue;
-			error("waitpid failed (%s)", strerror(errno));
-			goto error_die;
-		}
-		if (WIFSIGNALED(status)) {
-			int sig = WTERMSIG(status);
-			error("git-index-pack died of signal %d", sig);
-			goto error_die;
-		}
-		if (!WIFEXITED(status)) {
-			error("git-index-pack died of unnatural causes %d",
-			      status);
-			goto error_die;
-		}
-		code = WEXITSTATUS(status);
-		if (code) {
-			error("git-index-pack died with error code %d", code);
-			goto error_die;
-		}
-		if (err)
-			goto error_die;
-		break;
-	}
-	hash[40] = 0;
-	if (get_sha1_hex(hash, sha1)) {
-		error("git-index-pack reported nonsense '%s'", hash);
-		goto error_die;
-	}
-	/* Now we have pack in pack_tmp_name[], and
-	 * idx in idx[]; rename them to their final names.
-	 */
-	snprintf(final, sizeof(final),
-		 "%s/pack/pack-%s.pack", get_object_directory(), hash);
-	move_temp_to_file(pack_tmp_name, final);
-	chmod(final, 0444);
-	snprintf(final, sizeof(final),
-		 "%s/pack/pack-%s.idx", get_object_directory(), hash);
-	move_temp_to_file(idx, final);
-	chmod(final, 0444);
-	return 0;
-
- error_die:
-	unlink(idx);
-	unlink(pack_tmp_name);
-	exit(1);
-}
 
 static pid_t setup_sideband(int sideband, const char *me, int fd[2], int xd[2])
 {
@@ -128,7 +37,7 @@ static pid_t setup_sideband(int sideband
 	return side_pid;
 }
 
-int receive_unpack_pack(int xd[2], const char *me, int quiet, int sideband)
+static int get_pack(int xd[2], const char *me, int sideband, const char **argv)
 {
 	int status;
 	pid_t pid, side_pid;
@@ -142,135 +51,37 @@ int receive_unpack_pack(int xd[2], const
 		dup2(fd[0], 0);
 		close(fd[0]);
 		close(fd[1]);
-		execl_git_cmd("unpack-objects", quiet ? "-q" : NULL, NULL);
-		die("git-unpack-objects exec failed");
+		execv_git_cmd(argv);
+		die("%s exec failed", argv[0]);
 	}
 	close(fd[0]);
 	close(fd[1]);
 	while (waitpid(pid, &status, 0) < 0) {
 		if (errno != EINTR)
-			die("waiting for git-unpack-objects: %s",
-			    strerror(errno));
+			die("waiting for %s: %s", argv[0], strerror(errno));
 	}
 	if (WIFEXITED(status)) {
 		int code = WEXITSTATUS(status);
 		if (code)
-			die("git-unpack-objects died with error code %d",
-			    code);
+			die("%s died with error code %d", argv[0], code);
 		return 0;
 	}
 	if (WIFSIGNALED(status)) {
 		int sig = WTERMSIG(status);
-		die("git-unpack-objects died of signal %d", sig);
+		die("%s died of signal %d", argv[0], sig);
 	}
-	die("git-unpack-objects died of unnatural causes %d", status);
+	die("%s died of unnatural causes %d", argv[0], status);
 }
 
-/*
- * We average out the download speed over this many "events", where
- * an event is a minimum of about half a second. That way, we get
- * a reasonably stable number.
- */
-#define NR_AVERAGE (4)
-
-/*
- * A "binary msec" is a power-of-two-msec, aka 1/1024th of a second.
- * Keeping the time in that format means that "bytes / msecs" means
- * the same as kB/s (modulo rounding).
- *
- * 1000512 is a magic number (usecs in a second, rounded up by half
- * of 1024, to make "rounding" come out right ;)
- */
-#define usec_to_binarymsec(x) ((int)(x) / (1000512 >> 10))
+int receive_unpack_pack(int xd[2], const char *me, int quiet, int sideband)
+{
+	const char *argv[3] = { "unpack-objects", quiet ? "-q" : NULL, NULL };
+	return get_pack(xd, me, sideband, argv);
+}
 
 int receive_keep_pack(int xd[2], const char *me, int quiet, int sideband)
 {
-	char tmpfile[PATH_MAX];
-	int ofd, ifd, fd[2];
-	unsigned long total;
-	static struct timeval prev_tv;
-	struct average {
-		unsigned long bytes;
-		unsigned long time;
-	} download[NR_AVERAGE] = { {0, 0}, };
-	unsigned long avg_bytes, avg_time;
-	int idx = 0;
-
-	setup_sideband(sideband, me, fd, xd);
-
-	ifd = fd[0];
-	snprintf(tmpfile, sizeof(tmpfile),
-		 "%s/pack/tmp-XXXXXX", get_object_directory());
-	ofd = mkstemp(tmpfile);
-	if (ofd < 0)
-		return error("unable to create temporary file %s", tmpfile);
-
-	gettimeofday(&prev_tv, NULL);
-	total = 0;
-	avg_bytes = 0;
-	avg_time = 0;
-	while (1) {
-		char buf[8192];
-		ssize_t sz, wsz, pos;
-		sz = read(ifd, buf, sizeof(buf));
-		if (sz == 0)
-			break;
-		if (sz < 0) {
-			if (errno != EINTR && errno != EAGAIN) {
-				error("error reading pack (%s)", strerror(errno));
-				close(ofd);
-				unlink(tmpfile);
-				return -1;
-			}
-			sz = 0;
-		}
-		pos = 0;
-		while (pos < sz) {
-			wsz = write(ofd, buf + pos, sz - pos);
-			if (wsz < 0) {
-				error("error writing pack (%s)",
-				      strerror(errno));
-				close(ofd);
-				unlink(tmpfile);
-				return -1;
-			}
-			pos += wsz;
-		}
-		total += sz;
-		if (!quiet) {
-			static unsigned long last;
-			struct timeval tv;
-			unsigned long diff = total - last;
-			/* not really "msecs", but a power-of-two millisec (1/1024th of a sec) */
-			unsigned long msecs;
-
-			gettimeofday(&tv, NULL);
-			msecs = tv.tv_sec - prev_tv.tv_sec;
-			msecs <<= 10;
-			msecs += usec_to_binarymsec(tv.tv_usec - prev_tv.tv_usec);
-
-			if (msecs > 500) {
-				prev_tv = tv;
-				last = total;
-
-				/* Update averages ..*/
-				avg_bytes += diff;
-				avg_time += msecs;
-				avg_bytes -= download[idx].bytes;
-				avg_time -= download[idx].time;
-				download[idx].bytes = diff;
-				download[idx].time = msecs;
-				idx++;
-				if (idx >= NR_AVERAGE)
-					idx = 0;
-
-				fprintf(stderr, "%4lu.%03luMB  (%lu kB/s)      \r",
-					total >> 20,
-					1000*((total >> 10) & 1023)>>10,
-					avg_bytes / avg_time );
-			}
-		}
-	}
-	close(ofd);
-	return finish_pack(tmpfile, me);
+	const char *argv[5] = { "index-pack", "--stdin", "--fix-thin",
+				quiet ? NULL : "-v", NULL };
+	return get_pack(xd, me, sideband, argv);
 }
diff --git a/fetch-pack.c b/fetch-pack.c
index 90b7940..36ea092 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -518,8 +518,6 @@ int main(int argc, char **argv)
 	}
 	if (!dest)
 		usage(fetch_pack_usage);
-	if (keep_pack)
-		use_thin_pack = 0;
 	pid = git_connect(fd, dest, exec);
 	if (pid < 0)

^ permalink raw reply related	[relevance 5%]

* What's in git.git
@ 2006-11-02  0:53  1% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-11-02  0:53 UTC (permalink / raw)
  To: git

* The 'maint' branch has these fixes since the last announcement.

  We have one semantic fix in "maint".  To the revision traversal
  machinery, --unpacked used to mean that any commit that is in a
  pack is uninteresting and tainted its ancestors also
  uninteresting.  Updated semantics of --unpacked is just an
  output filter -- it traverses ancestry chain as usual, but does
  not show unpacked commits.  This made what "git repack" does
  actually make sense when the repository is partly packed in the
  half-way (the earlier logic worked fine only if all ancestors of
  a packed commit were all packed).

  A few minor "diff --cc" output fixes are also in "maint".  It
  now honours --no-commit-id option and shows function names on
  the @@@ ... @@@ line just like normal diffs do.


   Christian Couder (2):
      Documentation: add upload-archive service to git-daemon.
      Documentation: add git in /etc/services.

   Edgar Toernig (1):
      Use memmove instead of memcpy for overlapping areas

   Jakub Narebski (2):
      diff-format.txt: Correct information about pathnames quoting in
	patch format
      gitweb: Check git base URLs before generating URL from it

   Jan Harkes (1):
      Continue traversal when rev-list --unpacked finds a packed commit.

   Junio C Hamano (7):
      combine-diff: a few more finishing touches.
      combine-diff: fix hunk_comment_line logic.
      combine-diff: honour --no-commit-id
      Surround "#define DEBUG 0" with "#ifndef DEBUG..#endif"
      quote.c: ensure the same quoting across platforms.
      revision traversal: --unpacked does not limit commit list anymore.
      link_temp_to_file: don't leave the path truncated on
	adjust_shared_perm failure

   Nicolas Pitre (1):
      pack-objects doesn't create random pack names

   Rene Scharfe (1):
      git-cherry: document limit and add diagram


* The 'master' branch has these since the last announcement.

  Linus's packed-refs work with associated refs handling
  clean-ups are out on "master", but there is one disclaimer.
  Commit walkers cannot fetch from a repository whose refs are
  packed and then pruned yet, so people with public repositories
  that are expected to be fetched via http should not run
  git-pack-refs just yet.  I think it is probably just the
  matter of updating git-fetch.sh to run ls-remote against the
  repository upfront, and use the SHA-1 of wanted branch tip
  instead of the branch tip name when running the low-level
  git-http-fetch.

  git-branch and git-cherry are now built-in.

   Andy Parkins (1):
      Make filenames line up in git-status output

   Christian Couder (14):
      Add [-s|--hash] option to Linus' show-ref.
      Use Linus' show ref in "git-branch.sh".
      Document git-show-ref [-s|--hash] option.
      Fix show-ref usage for --dereference.
      Add pack-refs and show-ref test cases.
      When creating branch c/d check that branch c does not already exists.
      Uncomment test case: git branch c/d should barf if branch c exists.
      Fix a remove_empty_dir_recursive problem.
      Clean up "git-branch.sh" and add remove recursive dir test cases.
      Use git-update-ref to delete a tag instead of rm()ing the ref file.
      Check that a tag exists using show-ref instead of looking for the
	ref file.
      Do not create tag leading directories since git update-ref does it.
      Documentation: add upload-archive service to git-daemon.
      Documentation: add git in /etc/services.

   Dennis Stosberg (3):
      lock_ref_sha1_basic does not remove empty directories on BSD
      Remove bashism from t3210-pack-refs.sh
      Bash completion support for aliases

   Edgar Toernig (2):
      Use memmove instead of memcpy for overlapping areas
      Use memmove instead of memcpy for overlapping areas

   Jakub Narebski (8):
      gitweb: Use --no-commit-id in git_commit and git_commitdiff
      diff-format.txt: Correct information about pathnames quoting in
	patch format
      gitweb: Check git base URLs before generating URL from it
      Documentation: Update information about <format> in git-for-each-ref
      gitweb: Move git_get_last_activity subroutine earlier
      gitweb: Add "next" link to commitdiff view
      gitweb: Secure against commit-ish/tree-ish with the same name as path
      gitweb: Use 's' regexp modifier to secure against filenames with LF

   Jan Harkes (1):
      Continue traversal when rev-list --unpacked finds a packed commit.

   Jeff King (3):
      wt-status: use simplified resolve_ref to find current branch
      gitignore: git-pack-refs is a generated file.
      gitignore: git-show-ref is a generated file.

   Johannes Schindelin (2):
      Fix git-update-index --again
      show-branch: mark active branch with a '*' again

   Jonas Fonseca (1):
      Add man page for git-show-ref

   Junio C Hamano (42):
      Fix t1400-update-ref test minimally
      fsck-objects: adjust to resolve_ref() clean-up.
      symbolit-ref: fix resolve_ref conversion.
      Add callback data to for_each_ref() family.
      Tell between packed, unpacked and symbolic refs.
      pack-refs: do not pack symbolic refs.
      git-pack-refs --prune
      pack-refs: fix git_path() usage.
      lock_ref_sha1_basic: remove unused parameter "plen".
      Clean-up lock-ref implementation
      update-ref: -d flag and ref creation safety.
      update a few Porcelain-ish for ref lock safety.
      Teach receive-pack about ref-log
      receive-pack: call setup_ident before git_config
      ref locking: allow 'foo' when 'foo/bar' used to exist but not anymore.
      refs: minor restructuring of cached refs data.
      lock_ref_sha1(): do not sometimes error() and sometimes die().
      lock_ref_sha1(): check D/F conflict with packed ref when creating.
      delete_ref(): delete packed ref
      git-branch: remove D/F check done by hand.
      show-ref --hash=len, --abbrev=len, and --abbrev
      git-fetch: adjust to packed-refs.
      Fix refs.c;:repack_without_ref() clean-up path
      git-fetch: do not look into $GIT_DIR/refs to see if a tag exists.
      pack-refs: use lockfile as everybody else does.
      pack-refs: call fflush before fsync.
      ref-log: allow ref@{count} syntax.
      core.logallrefupdates create new log file only for branch heads.
      git-pack-refs --all
      core.logallrefupdates thinko-fix
      ref-log: fix D/F conflict coming from deleted refs.
      sha1_name.c: avoid compilation warnings.
      t3200: git-branch testsuite update
      combine-diff: fix hunk_comment_line logic.
      combine-diff: honour --no-commit-id
      tests: merge-recursive is usable without Python
      Documentation: fix git-format-patch mark-up and link it from git.txt
      Surround "#define DEBUG 0" with "#ifndef DEBUG..#endif"
      quote.c: ensure the same quoting across platforms.
      revision traversal: --unpacked does not limit commit list anymore.
      link_temp_to_file: don't leave the path truncated on
	adjust_shared_perm failure
      branch: work in subdirectories.

   Lars Hjemli (2):
      Make git-branch a builtin
      Fix show-ref usagestring

   Linus Torvalds (6):
      Add "git show-ref" builtin command
      Teach "git checkout" to use git-show-ref
      Start handling references internally as a sorted in-memory list
      Add support for negative refs
      Make ref resolution saner
      Enable the packed refs file format

   Luben Tuikov (2):
      git-revert with conflicts to behave as git-merge with conflicts
      gitweb: esc_html() author in blame

   Nicolas Pitre (1):
      pack-objects doesn't create random pack names

   Petr Baudis (3):
      Fix broken sha1 locking
      Fix buggy ref recording
      gitweb: Fix up bogus $stylesheet declarations

   Rene Scharfe (3):
      Built-in cherry
      Make git-cherry handle root trees
      git-cherry: document limit and add diagram

   Robin Rosenberg (2):
      Mention that pull can work locally in the synopsis
      Swap the porcelain and plumbing commands in the git man page

   Sasha Khapyorsky (1):
      git-svnimport: support for partial imports

   Sergey Vlasov (2):
      git-send-email: Document support for local sendmail instead of
	SMTP server
      git-send-email: Read the default SMTP server from the GIT config file

   Shawn Pearce (1):
      Move deny_non_fast_forwards handling completely into receive-pack.


* The 'next' branch, in addition, has these.

  The largest one is "pickaxe"; I think it is ready for wider
  testing if not for production use, and it is a new command so
  it should be relatively safe to push it out anytime on "master".

  Nico did a lot of work on index-pack and with help from Shawn
  pushing many objects without exploding them into loose objects
  at the other end is becoming reality.  The latest part of
  their series is not in "next" nor "pu" yet, though.

  Linus pointed out that when merging a branch based on an older
  codebase that used to have a path into your branch that does
  not have that path tracked anymore triggers a bogus safety
  valve; I've done both merge-resolve and merge-recursive to
  handle this situation but the result needs to be sanity
  checked.  We are _loosening_ safety valve and need to be extra
  cautious not to overloosen it.

   Junio C Hamano (28):
      upload-pack: stop the other side when they have more roots than we do.
      git-pickaxe: blame rewritten.
      git-pickaxe -M: blame line movements within a file.
      git-pickaxe -C: blame cut-and-pasted lines.
      git-pickaxe: pagenate output by default.
      git-pickaxe: fix nth_line()
      git-pickaxe: improve "best match" heuristics
      git-pickaxe: introduce heuristics to avoid "trivial" chunks
      git-pickaxe: do not keep commit buffer.
      git-pickaxe: do not confuse two origins that are the same.
      git-pickaxe: get rid of wasteful find_origin().
      git-pickaxe: swap comparison loop used for -C
      merge: loosen overcautious "working file will be lost" check.
      merge-recursive: use abbreviated commit object name.
      merge-recursive: make a few functions static.
      merge-recursive: adjust to loosened "working file clobbered" check
      t6022: ignoring untracked files by merge-recursive when they do not
	matter
      send-pack --keep: do not explode into loose objects on the receiving end.
      git-pickaxe: WIP to refcount origin structure.
      git-pickaxe: allow -Ln,m as well as -L n,m
      git-pickaxe: refcount origin correctly in find_copy_in_parent()
      git-pickaxe: tighten sanity checks.
      Revert "send-pack --keep: do not explode into loose objects on the
	receiving end."
      git-pickaxe: split find_origin() into find_rename() and find_origin().
      git-pickaxe: cache one already found path per commit.
      Introduce a new revision set operator <rev>^!

   Linus Torvalds (2):
      Allow '-' in config variable names
      git push: add verbose flag and allow overriding of default target
	repository

   Nicolas Pitre (8):
      enable index-pack streaming capability
      make index-pack able to complete thin packs.
      add progress status to index-pack
      mimic unpack-objects when --stdin is used with index-pack
      enhance clone and fetch -k experience
      index-pack: minor fixes to comment and function name
      missing small substitution
      make git-push a bit more verbose

   Petr Baudis (1):
      gitweb: Support for 'forks'

   Shawn Pearce (4):
      Allow short pack names to git-pack-objects --unpacked=.
      Only repack active packs by skipping over kept packs.
      Teach git-index-pack how to keep a pack file.
      Remove unused variable in receive-pack.


* The 'pu' branch, in addition, has these.

  Johannes's "shallow" was marked as "pu" material so I've based
  the series on the tip of "next" (which means we cannot
  directly merge that into "next" or "master" without rebasing
  it to "master" first) and parked it in "pu".  I have given
  only a cursory look to it but it looks promising.

  Nico's latest 6-series builds on top of what Shawn has here
  (the first two from Nico are the same), but I haven't gotten
  around to them yet.

   Johannes Schindelin (6):
      upload-pack: no longer call rev-list
      support fetching into a shallow repository
      allow cloning a repository "shallowly"
      allow deepening of a shallow repository
      add tests for shallow stuff
      Build in shortlog

   Junio C Hamano (4):
      rev-list --left-right
      git-diff/git-apply: make diff output a bit friendlier to GNU
	patch (part 2)
      para-walk: walk n trees, index and working tree in parallel
      git-commit: show --summary after successful commit.

   Shawn Pearce (2):
      Allow pack header preprocessing before unpack-objects/index-pack.
      Teach receive-pack how to keep pack files based on object count.


^ permalink raw reply	[relevance 1%]

* Re: What's in git.git
  @ 2006-11-08  4:13  2% ` David Lang
  2006-11-08 16:40  1%   ` Shallow clone [Was Re: What's in git.git ] Aneesh Kumar K.V
                     ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: David Lang @ 2006-11-08  4:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Tue, 7 Nov 2006, Junio C Hamano wrote:

> [pu]
>
>  Johannes's shallow clone work now should rebase cleanly on top
>  of 'master' although I haven't done so yet.  As he said
>  himself the series is waiting for people who have needs for
>  such a feature to raise hands.

I haven't been watching this recently, but if this is what I understand it to be 
(the ability to get a partial repository from upstream and work normally from 
there with the result of data-mineing tools sometimes reporting 'that's part of 
the truncated history' if they hit the cutoff) consider my hand raised.

there are a number of cases where I would be interested in following a project 
as it moves forwards, but do not have the need to have the full history (even 
with the good compression that a git pack provides, it's still a significant 
amount of disk space and download time for large projects)


^ permalink raw reply	[relevance 2%]

* Shallow clone [Was Re: What's in git.git ]
  2006-11-08  4:13  2% ` David Lang
@ 2006-11-08 16:40  1%   ` Aneesh Kumar K.V
  2006-11-08 17:59  1%     ` Aneesh Kumar K.V
  2006-11-09  2:28  0%   ` What's in git.git Horst H. von Brand
  2006-11-12 22:25  3%   ` Johannes Schindelin
  2 siblings, 1 reply; 200+ results
From: Aneesh Kumar K.V @ 2006-11-08 16:40 UTC (permalink / raw)
  Cc: git

David Lang wrote:
> On Tue, 7 Nov 2006, Junio C Hamano wrote:
> 
>> [pu]
>>
>>  Johannes's shallow clone work now should rebase cleanly on top
>>  of 'master' although I haven't done so yet.  As he said
>>  himself the series is waiting for people who have needs for
>>  such a feature to raise hands.
> 
> I haven't been watching this recently, but if this is what I understand 
> it to be (the ability to get a partial repository from upstream and work 
> normally from there with the result of data-mineing tools sometimes 
> reporting 'that's part of the truncated history' if they hit the cutoff) 
> consider my hand raised.
> 
> there are a number of cases where I would be interested in following a 
> project as it moves forwards, but do not have the need to have the full 
> history (even with the good compression that a git pack provides, it's 
> still a significant amount of disk space and download time for large 
> projects)
> 

I am trying to test this feature. Is there a documentation .git/shallow some where. Atleast what those entries
mean ? I know in the mail johannes mentioned only core git will touch this file. But it should be ok to be 
descriptive like other files. (FETCH_HEAD)

-aneesh 

^ permalink raw reply	[relevance 1%]

* Re: Shallow clone [Was Re: What's in git.git ]
  2006-11-08 16:40  1%   ` Shallow clone [Was Re: What's in git.git ] Aneesh Kumar K.V
@ 2006-11-08 17:59  1%     ` Aneesh Kumar K.V
    0 siblings, 1 reply; 200+ results
From: Aneesh Kumar K.V @ 2006-11-08 17:59 UTC (permalink / raw)
  To: Aneesh Kumar K.V; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 1291 bytes --]

Aneesh Kumar K.V wrote:
> David Lang wrote:
>> On Tue, 7 Nov 2006, Junio C Hamano wrote:
>>
>>> [pu]
>>>
>>>  Johannes's shallow clone work now should rebase cleanly on top
>>>  of 'master' although I haven't done so yet.  As he said
>>>  himself the series is waiting for people who have needs for
>>>  such a feature to raise hands.
>>
>> I haven't been watching this recently, but if this is what I 
>> understand it to be (the ability to get a partial repository from 
>> upstream and work normally from there with the result of data-mineing 
>> tools sometimes reporting 'that's part of the truncated history' if 
>> they hit the cutoff) consider my hand raised.
>>
>> there are a number of cases where I would be interested in following a 
>> project as it moves forwards, but do not have the need to have the 
>> full history (even with the good compression that a git pack provides, 
>> it's still a significant amount of disk space and download time for 
>> large projects)
>>
> 
> I am trying to test this feature. Is there a documentation .git/shallow 
> some where. Atleast what those entries
> mean ? I know in the mail johannes mentioned only core git will touch 
> this file. But it should be ok to be descriptive like other files. 
> (FETCH_HEAD)


How about this 

-aneesh 

[-- Attachment #2: repository-layout.txt.diff --]
[-- Type: text/x-patch, Size: 537 bytes --]

diff --git a/Documentation/repository-layout.txt b/Documentation/repository-layout.txt
index 275d18b..03a6f77 100644
--- a/Documentation/repository-layout.txt
+++ b/Documentation/repository-layout.txt
@@ -141,3 +141,9 @@ logs/refs/heads/`name`::
 
 logs/refs/tags/`name`::
 	Records all changes made to the tag named `name`.
+
+shallow::
+	Records the sha1 of the commits which is marked to have no
+	parents to represent a shallow repository.The commit object
+	will have the parent information present. It carry one
+	record per line.

^ permalink raw reply related	[relevance 1%]

* Re: What's in git.git
  2006-11-08  4:13  2% ` David Lang
  2006-11-08 16:40  1%   ` Shallow clone [Was Re: What's in git.git ] Aneesh Kumar K.V
@ 2006-11-09  2:28  0%   ` Horst H. von Brand
  2006-11-09  2:54  0%     ` Junio C Hamano
  2006-11-12 22:25  3%   ` Johannes Schindelin
  2 siblings, 1 reply; 200+ results
From: Horst H. von Brand @ 2006-11-09  2:28 UTC (permalink / raw)
  To: David Lang; +Cc: Junio C Hamano, git

David Lang <dlang@digitalinsight.com> wrote:
> On Tue, 7 Nov 2006, Junio C Hamano wrote:
> 
> > [pu]
> >
> >  Johannes's shallow clone work now should rebase cleanly on top
> >  of 'master' although I haven't done so yet.  As he said
> >  himself the series is waiting for people who have needs for
> >  such a feature to raise hands.
> 
> I haven't been watching this recently, but if this is what I
> understand it to be (the ability to get a partial repository from
> upstream and work normally from there with the result of data-mineing
> tools sometimes reporting 'that's part of the truncated history' if
> they hit the cutoff) consider my hand raised.

+1
-- 
Dr. Horst H. von Brand                   User #22616 counter.li.org
Departamento de Informatica                    Fono: +56 32 2654431
Universidad Tecnica Federico Santa Maria             +56 32 2654239
Casilla 110-V, Valparaiso, Chile               Fax:  +56 32 2797513

^ permalink raw reply	[relevance 0%]

* Re: What's in git.git
  2006-11-09  2:28  0%   ` What's in git.git Horst H. von Brand
@ 2006-11-09  2:54  0%     ` Junio C Hamano
  2006-11-09  3:45  0%       ` Dave Dillow
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2006-11-09  2:54 UTC (permalink / raw)
  To: Horst H. von Brand; +Cc: git

"Horst H. von Brand" <vonbrand@laptop13.inf.utfsm.cl> writes:

> David Lang <dlang@digitalinsight.com> wrote:
>> On Tue, 7 Nov 2006, Junio C Hamano wrote:
>> 
>> > [pu]
>> >
>> >  Johannes's shallow clone work now should rebase cleanly on top
>> >  of 'master' although I haven't done so yet.  As he said
>> >  himself the series is waiting for people who have needs for
>> >  such a feature to raise hands.
>> 
>> I haven't been watching this recently, but if this is what I
>> understand it to be (the ability to get a partial repository from
>> upstream and work normally from there with the result of data-mineing
>> tools sometimes reporting 'that's part of the truncated history' if
>> they hit the cutoff) consider my hand raised.
>
> +1

What does that plus one mean?  I do not know where people picked
up this annoying plus or minus one business, but could you all
stop that?

If you are volunteering to help debugging and feeding bugfixes
that is very much welcome and appreciated.

Thanks.

^ permalink raw reply	[relevance 0%]

* Re: What's in git.git
  2006-11-09  2:54  0%     ` Junio C Hamano
@ 2006-11-09  3:45  0%       ` Dave Dillow
  0 siblings, 0 replies; 200+ results
From: Dave Dillow @ 2006-11-09  3:45 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Horst H. von Brand, git

On Wed, 2006-11-08 at 18:54 -0800, Junio C Hamano wrote:
> "Horst H. von Brand" <vonbrand@laptop13.inf.utfsm.cl> writes:
> 
> > David Lang <dlang@digitalinsight.com> wrote:
> >> On Tue, 7 Nov 2006, Junio C Hamano wrote:
> >> 
> >> > [pu]
> >> >
> >> >  Johannes's shallow clone work now should rebase cleanly on top
> >> >  of 'master' although I haven't done so yet.  As he said
> >> >  himself the series is waiting for people who have needs for
> >> >  such a feature to raise hands.
> >> 
> >> I haven't been watching this recently, but if this is what I
> >> understand it to be (the ability to get a partial repository from
> >> upstream and work normally from there with the result of data-mineing
> >> tools sometimes reporting 'that's part of the truncated history' if
> >> they hit the cutoff) consider my hand raised.
> >
> > +1
> 
> What does that plus one mean?  I do not know where people picked
> up this annoying plus or minus one business, but could you all
> stop that?

Horst can speak for himself, but I'd wager he's using the Apache voting
conventions:


^ permalink raw reply	[relevance 0%]

* Re: Shallow clone
  @ 2006-11-12 17:59  5%             ` Sergey Vlasov
  2006-11-12 21:59  1%               ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Sergey Vlasov @ 2006-11-12 17:59 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Alexandre Julliard, Aneesh Kumar K.V, git

[-- Attachment #1: Type: text/plain, Size: 2619 bytes --]

On Sun, 12 Nov 2006 00:16:40 -0800 Junio C Hamano wrote:

> Alexandre Julliard <julliard@winehq.org> writes:
>
> > There's also a problem with the packing, a clone --depth 1 currently
> > results in a pack that's about 3 times as large as it should be.
>
> That's interesting.
>
>   : gitster; git clone -n --depth 1 git://127.0.0.1/git.git victim-001
[...]
>   -r--r--r-- 1 junio src 9.5M 2006-11-11 23:52 pack-f5f88d83....pack
>
> Repacking immediately after cloning brings it down to what is
> expected.
>
>   : gitster; git repack -a -d -f
[...]
>   -rw-rw-r-- 1 junio src 2.6M 2006-11-11 23:53 pack-f5f88d83....pack

This is due to optimization in builtin-pack-objects.c:try_delta():

	/*
	 * We do not bother to try a delta that we discarded
	 * on an earlier try, but only when reusing delta data.
	 */
	if (!no_reuse_delta && trg_entry->in_pack &&
	    trg_entry->in_pack == src_entry->in_pack)
		return 0;

After removing this part the shallow pack after clone is 2.6M, as it
should be.

The problem with this optimization is that it is only valid if we are
repacking either the same set of objects as we did earlier, or its
superset.  But if we are packing a subset of objects, there will be some
objects in that subset which were delta-compressed in the original pack,
but base objects for that deltas are not included in our subset -
therefore we will be unable to reuse existing deltas, and with that
optimization we will never try to use delta compression for these
objects.  (The optimization assumes that if we will try to use delta
compression, we will try mostly the same base objects as we have tried
when we made the existing pack, and therefore will likely get the same
result - which is close to the truth when we are doing "repack -a", but
is badly wrong when we are doing "git-upload-pack" with a large number
of common commits, and therefore are excluding a lot of objects.)

So any partial fetch (shallow or not) from a mostly packed repository
currently results in a suboptimal pack.  In fact, the fresh "repack -a
-d -f" is probably the worst case for subsequent fetch (not initial
clone) from that repository - objects for the most recent commit are
most likely to be stored without delta compression, and even if deltas
are used, they are likely in the wrong direction for someone who has an
older version and wants to update it.


> In any case, after this "shallow" stuff, repeated "fetch --depth
> 99" seems to fetch 0 object and 3400 objects alternately, and
> the shallow file alternates between 900 bytes and 11000 bytes.

I confirm this - different numbers, but the same problem...

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[relevance 5%]

* Re: should git download missing objects?
  @ 2006-11-12 19:41  2% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-11-12 19:41 UTC (permalink / raw)
  To: Anand Kumria; +Cc: git

"Anand Kumria" <wildfire@progsoc.org> writes:

> I did an initial clone of Linus' linux-2.6.git tree, via the git protocol,
> and then managed to accidently delete one of the .pack and
> corresponding .idx files.
>
> I thought that 'cg-fetch' would do the job of bring down the missing pack
> again, and all would be well. Alas this isn't the case.
>
> <http://pastebin.ca/246678>
>
> Pasky, on IRC, indicated that this might be because git-fetch-pack isn't
> downloading missing objects when the git:// protocol is being used.

There are the invariants between refs and objects:

 - objects that its refs (files under .git/refs/ hierarchy that
   record 40-byte hexadecimal object names) point at are never
   missing, or the repository is corrupt.

 - objects that are reachable via pointers in another object
   that is not missing (a tag points at another object, a commit
   points at its tree and its parent commits, and a tree points
   at its subtrees and blobs) are never missing, or the repository
   is corrupt.

Git tools first fetch missing objects and then update your refs
only when fetch succeeds completely, in order to maintain the
above invariants (a partial fetch does not update your refs).
And these invariants are why:

 - fsck-objects start reachability check from the refs;

 - commit walkers can stop at your existing refs;

 - git native protocols only need to tell the other end what
   refs you have, in order for the other end to exclude what you
   already have from the set of objects it sends you.

What's missing needs to be determined in a reasonably efficient
manner, and the above invariants allow us not have to do the
equivalent of fsck-objects every time.  Being able to trust refs
is fairly fundamental in the fetch operation of git.

I am not opposed to the idea of a new tool to fix a corrupted
repository that has broken the above invariants, perhaps caused
by accidental removal of objects and packs by end users.  What
it needs to do would be:

 - run fsck-objects to notice what are missing, by noting
   "broken link from foo to bar" output messages.  Object 'bar'
   is what you _ought_ to have according to your refs but you
   don't (because you removed the objects that should be there),
   and everything that is reachable from it from the other side
   needs to be retrieved.  Because you do not have 'bar', your
   end cannot determine what other objects you happen to have in
   your object store are reachable from it and would result in
   redundant download.

 - run fetch-pack equivalent to get everything reachable
   starting at the above missing objects, pretending you do not
   have any object, because your refs are not trustworthy.

 - run fsck-objects again to make sure that your refs can now be
   trusted again.

To implement the second step above, you need to implement a
modified fetch-pack that does not trust any of your refs.  It
also needs to ignore what are offered from the other end but
asks the objects you know are missing ('bar' in the above
example).  This program needs to talk to a modified upload-pack
running at the other end (let's call it upload-pack-recover),
because usual upload-pack does not serve starting from a random
object that happen to be in its repository, but only starting
from objects that are pointed by its own set of refs to ensure
integrity.

The upload-pack-recover program would need to start traversal
from object 'bar' in the above example, and when it does so, it
should not just run 'rev-list --objects' starting at 'bar'.  It
first needs to prove that its object store has everything that
is reachable from 'bar' (the recipient would still end up with
an incomplete repository if it didn't).

What this means is that it needs to prove some of its refs can
reach 'bar' (again, on the upstream end, only refs are trusted,
not mere existence of object is not enough) before sending
objects back.  Usual upload-pack do not have to do it because it
refuses to serve starting from anything but what its refs point
at (and by the invariants, the objects pointed at by refs are
guaranteed to be complete [an object is "complete" if no object
that can be reachable is not missing]).

This is needed because the repository might have discarded
branch that used to reach 'bar', and while the object 'bar' was
in a pack but some of its ancestors or component trees and/or
blobs were loose and subsequent git-prune have removed the
latter without removing 'bar'.  Mere existence of the object
'bar' does not mean 'bar' is complete.

So coming up with such a pair of programs is not a rocket
science, but it is fairly delicate.  I would rather have them as
specialized commands, not a part of everyday commands, even if
you were to implement it.

Since this is not everyday anyway, a far easier way would be to
clone-pack from the upstream into a new repository, take the
pack you downloaded from that new repository and mv it into your
corrupt repository.  You can run fsck-objects to see if you got
back everything you lost earlier.

^ permalink raw reply	[relevance 2%]

* Re: Shallow clone
  2006-11-12 17:59  5%             ` Sergey Vlasov
@ 2006-11-12 21:59  1%               ` Junio C Hamano
  2006-11-13  5:29  1%                 ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2006-11-12 21:59 UTC (permalink / raw)
  To: Sergey Vlasov; +Cc: Alexandre Julliard, Aneesh Kumar K.V, git

Sergey Vlasov <vsu@altlinux.ru> writes:

> This is due to optimization in builtin-pack-objects.c:try_delta():
>
> 	/*
> 	 * We do not bother to try a delta that we discarded
> 	 * on an earlier try, but only when reusing delta data.
> 	 */
> 	if (!no_reuse_delta && trg_entry->in_pack &&
> 	    trg_entry->in_pack == src_entry->in_pack)
> 		return 0;
>
> After removing this part the shallow pack after clone is 2.6M, as it
> should be.
>
> The problem with this optimization is that it is only valid if we are
> repacking either the same set of objects as we did earlier, or its
> superset.  But if we are packing a subset of objects, there will be some
> objects in that subset which were delta-compressed in the original pack,
> but base objects for that deltas are not included in our subset -
> therefore we will be unable to reuse existing deltas, and with that
> optimization we will never try to use delta compression for these
> objects.
> ...
> So any partial fetch (shallow or not) from a mostly packed repository
> currently results in a suboptimal pack.

That is correct.  How about something like this?

I think the determination of "repacking_superset" may need to be
tweaked because existing packs may have overlaps, and the patch
counts them once per pack.


diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 69e5dd3..fb25124 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -64,6 +64,7 @@ struct object_entry {
 static unsigned char object_list_sha1[20];
 static int non_empty;
 static int no_reuse_delta;
+static int repacking_superset;
 static int local;
 static int incremental;
 static int allow_ofs_delta;
@@ -1172,10 +1173,13 @@ static int try_delta(struct unpacked *tr
 		return -1;
 
 	/*
-	 * We do not bother to try a delta that we discarded
-	 * on an earlier try, but only when reusing delta data.
+	 * When we are packing the superset of objects we have already
+	 * packed, we do not bother to try a delta that we discarded
+	 * on an earlier try.  This heuristic of course should not
+	 * kick in when we are not reusing delta, or we know we are
+	 * sending a subset of objects from a repository.
 	 */
-	if (!no_reuse_delta && trg_entry->in_pack &&
+	if (!no_reuse_delta && repacking_superset && trg_entry->in_pack &&
 	    trg_entry->in_pack == src_entry->in_pack)
 		return 0;
 
@@ -1493,6 +1497,16 @@ static void get_object_list(int ac, cons
 	traverse_commit_list(&revs, show_commit, show_object);
 }
 
+static int count_packed_objects(void)
+{
+	struct packed_git *p;
+	int cnt = 0;
+
+	for (p = packed_git; p; p = p->next)
+		cnt += num_packed_objects(p);
+	return cnt;
+}
+
 int cmd_pack_objects(int argc, const char **argv, const char *prefix)
 {
 	SHA_CTX ctx;
@@ -1631,6 +1645,8 @@ int cmd_pack_objects(int argc, const cha
 	if (non_empty && !nr_result)
 		return 0;
 
+	repacking_superset = count_packed_objects() < nr_result;
+
 	SHA1_Init(&ctx);
 	list = sorted_by_sha;
 	for (i = 0; i < nr_result; i++) {


^ permalink raw reply related	[relevance 1%]

* Re: What's in git.git
  2006-11-08  4:13  2% ` David Lang
  2006-11-08 16:40  1%   ` Shallow clone [Was Re: What's in git.git ] Aneesh Kumar K.V
  2006-11-09  2:28  0%   ` What's in git.git Horst H. von Brand
@ 2006-11-12 22:25  3%   ` Johannes Schindelin
  2 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2006-11-12 22:25 UTC (permalink / raw)
  To: David Lang; +Cc: Junio C Hamano, git

Hi,

On Tue, 7 Nov 2006, David Lang wrote:

> On Tue, 7 Nov 2006, Junio C Hamano wrote:
> 
> > [pu]
> > 
> >  Johannes's shallow clone work now should rebase cleanly on top
> >  of 'master' although I haven't done so yet.  As he said
> >  himself the series is waiting for people who have needs for
> >  such a feature to raise hands.
> 
> I haven't been watching this recently, but if this is what I understand it to
> be (the ability to get a partial repository from upstream and work normally
> from there with the result of data-mineing tools sometimes reporting 'that's
> part of the truncated history' if they hit the cutoff) consider my hand
> raised.

For now, it does not say "part of the truncated history". But yes, shallow 
clones are partial copies of remote repositories, by making some commits 
"shallow", i.e. grafting an empty set of parents onto them (thereby 
pretending that these commits are root commits).

Telling the user that a commit is shallow should not be too hard.

Ciao,
Dscho

^ permalink raw reply	[relevance 3%]

* Re: Shallow clone
  2006-11-12 21:59  1%               ` Junio C Hamano
@ 2006-11-13  5:29  1%                 ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-11-13  5:29 UTC (permalink / raw)
  To: Sergey Vlasov; +Cc: git

Junio C Hamano <junkio@cox.net> writes:

> Sergey Vlasov <vsu@altlinux.ru> writes:
>
>> This is due to optimization in builtin-pack-objects.c:try_delta():
>>
>> 	/*
>> 	 * We do not bother to try a delta that we discarded
>> 	 * on an earlier try, but only when reusing delta data.
>> 	 */
>> 	if (!no_reuse_delta && trg_entry->in_pack &&
>> 	    trg_entry->in_pack == src_entry->in_pack)
>> 		return 0;
>>
>> After removing this part the shallow pack after clone is 2.6M, as it
>> should be.
>>
>> The problem with this optimization is that it is only valid if we are
>> repacking either the same set of objects as we did earlier, or its
>> superset.  But if we are packing a subset of objects, there will be some
>> objects in that subset which were delta-compressed in the original pack,
>> but base objects for that deltas are not included in our subset -
>> therefore we will be unable to reuse existing deltas, and with that
>> optimization we will never try to use delta compression for these
>> objects.
>> ...
>> So any partial fetch (shallow or not) from a mostly packed repository
>> currently results in a suboptimal pack.

What we tried to avoid with the original heuristics in commit
51d1e83f was to avoid wasting time on undeltifiable blobs, and
they would be stored as base in the original packs, so I think
the following would fly better (the patch is for maint, for
master we would also check for OBJ_REF_DELTA as well).

---

diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 96c069a..84a8749 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -1101,7 +1101,8 @@ static int try_delta(struct unpacked *tr
 	 * on an earlier try, but only when reusing delta data.
 	 */
 	if (!no_reuse_delta && trg_entry->in_pack &&
-	    trg_entry->in_pack == src_entry->in_pack)
+	    trg_entry->in_pack == src_entry->in_pack &&
+	    trg_entry->in_pack_type != OBJ_DELTA)
 		return 0;
 
 	/*




^ permalink raw reply related	[relevance 1%]

* [ANNOUNCE] GIT 1.4.4
@ 2006-11-15  7:43  1% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-11-15  7:43 UTC (permalink / raw)
  To: git; +Cc: linux-kernel

The latest feature release GIT 1.4.4 is available at the usual
places:

  http://www.kernel.org/pub/software/scm/git/

  git-1.4.4.tar.{gz,bz2}			(tarball)
  git-htmldocs-1.4.4.tar.{gz,bz2}		(preformatted docs)
  git-manpages-1.4.4.tar.{gz,bz2}		(preformatted docs)
  RPMS/$arch/git-*-1.4.4-1.$arch.rpm	(RPM)

Quite a lot of changes during the last month.

 - pack-refs, along with a lot of internal clean-up of the code
   that deal with refs, is in.  A repository with many tags
   would benefit from packing and pruning them.  Currently dumb
   transports are not capable of fetching from a repository that
   has packed and pruned its refs, so please keep that in mind.
   Hopefully we will get an update for dumb transports shortly.

 - git native transport can now keep transferred packs without
   exploding it into loose objects.  Also "git repack" can be
   told to keep "historical" packs from getting repacked by
   marking them with .keep file.  Docmentation update is
   probably needed.

 - git-blame can now detect line movements across files.  No, it
   is not called git-pickaxe.

 - a lot of gitweb and git-svn updates.

----------------------------------------------------------------

Changes since v1.4.3 are as follows:

Alan Chandler:
      Gitweb - provide site headers and footers

Alex Riesen:
      merge-recursive implicitely depends on trust_executable_bit

Alexandre Julliard:
      git.el: Added a function to open the current file in another window.
      git.el: Added functions for moving to the next/prev unmerged file.
      git.el: Include MERGE_MSG in the log-edit buffer even when not committing a merge.
      git.el: Move point after the log message header when entering log-edit mode.
      pack-refs: Store the full name of the ref even when packing only tags.
      prune-packed: Fix uninitialized variable.

Andy Parkins:
      git-clone documentation didn't mention --origin as equivalent of -o
      Make filenames line up in git-status output
      Minor grammar fixes for git-diff-index.txt
      Remove uneccessarily similar printf() from print_ref_list() in builtin-branch

Andy Whitcroft:
      cvsimport: move over to using git-for-each-ref to read refs.
      git-for-each-ref: improve the documentation on scripting modes

Aneesh Kumar K.V:
      gitweb: Remove extra "/" in path names for git_get_project_list

Christian Couder:
      Add pack-refs and show-ref test cases.
      Add [-s|--hash] option to Linus' show-ref.
      Check that a tag exists using show-ref instead of looking for the ref file.
      Clean up "git-branch.sh" and add remove recursive dir test cases.
      Documentation: add git in /etc/services.
      Documentation: add upload-archive service to git-daemon.
      Document git-show-ref [-s|--hash] option.
      Do not create tag leading directories since git update-ref does it.
      Fix a remove_empty_dir_recursive problem.
      Fix show-ref usage for --dereference.
      Remove --syslog in git-daemon inetd documentation examples.
      Uncomment test case: git branch c/d should barf if branch c exists.
      Use git-update-ref to delete a tag instead of rm()ing the ref file.
      Use Linus' show ref in "git-branch.sh".
      When creating branch c/d check that branch c does not already exists.

Dennis Stosberg:
      lock_ref_sha1_basic does not remove empty directories on BSD
      Remove bashism from t3210-pack-refs.sh
      Bash completion support for aliases

Dmitry V. Levin:
      git-clone: define die() and use it.

Edgar Toernig:
      Use memmove instead of memcpy for overlapping areas

Eric Wong:
      git-send-email: do not pass custom Date: header
      git-svn: avoid printing filenames of files we're not tracking
      git-svn: don't die on rebuild when --upgrade is specified
      git-svn: fix dcommit losing changes when out-of-date from svn
      git-svn: fix symlink-to-file changes when using command-line svn 1.4.0

Gerrit Pape:
      Set $HOME for selftests

J. Bruce Fields:
      Make prune also run prune-packed
      Documentation: updates to "Everyday GIT"

Jakub Narebski:
      diff-format.txt: Combined diff format documentation supplement
      diff-format.txt: Correct information about pathnames quoting in patch format
      Documentation: Transplanting branch with git-rebase --onto
      Documentation: Update information about <format> in git-for-each-ref
      gitweb: Add "next" link to commitdiff view
      gitweb: Add '..' (up directory) to tree view if applicable
      gitweb: Better git-unquoting and gitweb-quoting of pathnames
      gitweb: Better support for non-CSS aware web browsers
      gitweb: Check git base URLs before generating URL from it
      gitweb: Do not esc_html $basedir argument to git_print_tree_entry
      gitweb: Filter out commit ID from @difftree in git_commit and git_commitdiff
      gitweb: Get rid of git_print_simplified_log
      gitweb: Improve git_print_page_path
      gitweb: Move git_get_last_activity subroutine earlier
      gitweb: New improved patchset view
      gitweb: Output also empty patches in "commitdiff" view
      gitweb: Print commit message without title in commitdiff only if there is any
      gitweb: Secure against commit-ish/tree-ish with the same name as path
      gitweb: Use character or octal escape codes (and add span.cntrl) in esc_path
      gitweb: Use git-for-each-ref to generate list of heads and/or tags
      gitweb: Use --no-commit-id in git_commit and git_commitdiff
      gitweb: Use 's' regexp modifier to secure against filenames with LF
      gitweb: Whitespace cleanup - tabs are for indent, spaces are for align (2)

Jan Harkes:
      Continue traversal when rev-list --unpacked finds a packed commit.

Jeff King:
      wt-status: use simplified resolve_ref to find current branch
      gitignore: git-pack-refs is a generated file.
      gitignore: git-show-ref is a generated file.
      git-pickaxe: work properly in a subdirectory.
      Fix git-runstatus for repositories containing a file named HEAD

Jim Meyering:
      Don't use $author_name undefined when $from contains no /\s</.
      git-clone: honor --quiet
      xdiff/xemit.c (xdl_find_func): Elide trailing white space in a context header.

Johannes Schindelin:
      Fix git-update-index --again
      show-branch: mark active branch with a '*' again
      Turn on recursive with --summary
      link_temp_to_file: call adjust_shared_perm() only when we created the directory

Johannes Sixt:
      test-lib.sh: A command dying due to a signal is an unexpected failure.
      Catch errors when writing an index that contains invalid objects.

Jonas Fonseca:
      Add man page for git-show-ref
      git-update-index(1): fix use of quoting in section title

Junio C Hamano:
      Add callback data to for_each_ref() family.
      Add git-for-each-ref: helper for language bindings
      adjust_shared_perm: chmod() only when needed.
      apply: handle "traditional" creation/deletion diff correctly.
      blame.c: move code to output metainfo into a separate function.
      blame.c: whitespace and formatting clean-up.
      blame: Document and add help text for -f, -n, and -p
      branch: work in subdirectories.
      cherry is built-in, do not ship git-cherry.sh
      Clean-up lock-ref implementation
      combine-diff: a few more finishing touches.
      combine-diff: fix hunk_comment_line logic.
      combine-diff: honour --no-commit-id
      core.logallrefupdates create new log file only for branch heads.
      core.logallrefupdates thinko-fix
      daemon: do not die on older clients.
      delete_ref(): delete packed ref
      diff --numstat
      Documentation: clarify refname disambiguation rules.
      Documentation: fix git-format-patch mark-up and link it from git.txt
      Documentation: move blame examples
      Documentation: note about contrib/.
      Documentation/SubmittingPatches: 3+1 != 6
      Document git-pack-refs and link it to git(7).
      Fix refs.c;:repack_without_ref() clean-up path
      Fix t1400-update-ref test minimally
      for-each-ref: "creator" and "creatordate" fields
      fsck-objects: adjust to resolve_ref() clean-up.
      GIT 1.4.3-rc1
      GIT 1.4.4
      GIT 1.4.4-rc2
      git-annotate: fix -S on graft file with comments.
      git-annotate: no need to exec blame; it is built-in now.
      git-blame: add internal statistics to count read blobs.
      git-blame --porcelain
      git-blame: --show-name (and -f)
      git-blame: --show-number (and -n)
      git-branch: remove D/F check done by hand.
      git-cvsserver: read from git with -z to get non-ASCII pathnames.
      git-diff/git-apply: make diff output a bit friendlier to GNU patch (part 1)
      git-fetch: adjust to packed-refs.
      git-fetch: do not look into $GIT_DIR/refs to see if a tag exists.
      git-pack-refs --all
      git-pack-refs --prune
      git-pickaxe: allow -Ln,m as well as -L n,m
      git-pickaxe: allow "-L <something>,+N"
      git-pickaxe: blame rewritten.
      git-pickaxe: cache one already found path per commit.
      git-pickaxe -C: blame cut-and-pasted lines.
      git-pickaxe: do not confuse two origins that are the same.
      git-pickaxe: do not keep commit buffer.
      git-pickaxe: fix nth_line()
      git-pickaxe: fix origin refcounting
      git-pickaxe: get rid of wasteful find_origin().
      git-pickaxe: improve "best match" heuristics
      git-pickaxe: introduce heuristics to avoid "trivial" chunks
      git-pickaxe: -L /regexp/,/regexp/
      git-pickaxe -M: blame line movements within a file.
      git-pickaxe: optimize by avoiding repeated read_sha1_file().
      git-pickaxe: pagenate output by default.
      git-pickaxe: refcount origin correctly in find_copy_in_parent()
      git-pickaxe: rename detection optimization
      git-pickaxe: re-scan the blob after making progress with -C
      git-pickaxe: re-scan the blob after making progress with -M
      git-pickaxe: retire pickaxe
      git-pickaxe: simplify Octopus merges further
      git-pickaxe: split find_origin() into find_rename() and find_origin().
      git-pickaxe: swap comparison loop used for -C
      git-pickaxe: tighten sanity checks.
      git-pickaxe: WIP to refcount origin structure.
      git-repack: repo.usedeltabaseoffset
      git-send-email: do not drop custom headers the user prepared
      git-send-email: real name with period need to be dq-quoted on From: line
      git-status: quote LF in its output
      gitweb: do not give blame link unconditionally in diff-tree view
      gitweb: fix disabling of "forks"
      gitweb: fix unmatched div in commitdiff
      gitweb: make leftmost column of blame less cluttered.
      gitweb: minimally fix "fork" support.
      gitweb: prepare for repositories with packed refs.
      gitweb: protect blob and diff output lines from controls.
      gitweb: protect commit messages from controls.
      gitweb: spell "blame --porcelain" with -p
      gitweb: use blame --porcelain
      gitweb: use for-each-ref to show the latest activity across branches
      grep --all-match
      Introduce a new revision set operator <rev>^!
      link_temp_to_file: don't leave the path truncated on adjust_shared_perm failure
      lock_ref_sha1_basic: remove unused parameter "plen".
      lock_ref_sha1(): check D/F conflict with packed ref when creating.
      lock_ref_sha1(): do not sometimes error() and sometimes die().
      Make git-send-email detect mbox-style patches more readily
      merge: loosen overcautious "working file will be lost" check.
      merge-recursive: adjust to loosened "working file clobbered" check
      merge-recursive: make a few functions static.
      merge-recursive: use abbreviated commit object name.
      pack-objects: document --delta-base-offset option
      pack-refs: call fflush before fsync.
      pack-refs: do not pack symbolic refs.
      pack-refs: fix git_path() usage.
      pack-refs: use lockfile as everybody else does.
      pager: default to LESS=FRS
      pager: default to LESS=FRSX not LESS=FRS
      path-list: fix path-list-insert return value
      quote.c: ensure the same quoting across platforms.
      receive-pack: call setup_ident before git_config
      Refer to git-rev-parse:Specifying Revisions from git.txt
      ref locking: allow 'foo' when 'foo/bar' used to exist but not anymore.
      ref-log: allow ref@{count} syntax.
      ref-log: fix D/F conflict coming from deleted refs.
      refs: minor restructuring of cached refs data.
      Revert 954a6183756a073723a7c9fd8d2feb13132876b0
      Revert "send-pack --keep: do not explode into loose objects on the receiving end."
      revision traversal: --unpacked does not limit commit list anymore.
      RPM package re-classification.
      send-pack --keep: do not explode into loose objects on the receiving end.
      sha1_name.c: avoid compilation warnings.
      show-ref --hash=len, --abbrev=len, and --abbrev
      Surround "#define DEBUG 0" with "#ifndef DEBUG..#endif"
      symbolit-ref: fix resolve_ref conversion.
      t3200: git-branch testsuite update
      t6022: ignoring untracked files by merge-recursive when they do not matter
      Teach receive-pack about ref-log
      teach revision walker about --all-match.
      Tell between packed, unpacked and symbolic refs.
      tests: merge-recursive is usable without Python
      update a few Porcelain-ish for ref lock safety.
      Update cherry documentation.
      update-ref: -d flag and ref creation safety.

Karl Hasselström:
      git-vc: better installation instructions
      ignore-errors requires cl

Lars Hjemli:
      Fix typo in show-index.c
      Fix usagestring for git-branch
      Make git-branch a builtin
      Fix show-ref usagestring

Linus Torvalds:
      Add "git show-ref" builtin command
      Teach "git checkout" to use git-show-ref
      Start handling references internally as a sorted in-memory list
      Add support for negative refs
      Make ref resolution saner
      Enable the packed refs file format
      git-apply: prepare for upcoming GNU diff -u format change.
      Allow '-' in config variable names
      git push: add verbose flag and allow overriding of default target repository

Luben Tuikov:
      gitweb: blame: print commit-8 on the leading row of a commit-block
      gitweb: blame: Mouse-over commit-8 shows author and date
      gitweb: blame porcelain: lineno and orig lineno swapped
      git-revert with conflicts to behave as git-merge with conflicts
      gitweb: esc_html() author in blame

Martin Waitz:
      gitweb: start to generate PATH_INFO URLs.
      gitweb: warn if feature cannot be overridden.

Matthew Wilcox:
      Add --dry-run option to git-send-email

Nguyễn Thái Ngọc Duy:
      Reject hexstring longer than 40-bytes in get_short_sha1()
      Add revspec documentation for ':path', ':[0-3]:path' and git-describe

Nicolas Pitre:
      introduce delta objects with offset to base
      teach git-unpack-objects about deltas with offset to base
      teach git-index-pack about deltas with offset to base
      make git-pack-objects able to create deltas with offset to base
      make pack data reuse compatible with both delta types
      let the GIT native protocol use offsets to delta base when possible
      zap a debug remnant
      allow delta data reuse even if base object is a preferred base
      index-pack: compare only the first 20-bytes of the key.
      reduce delta head inflated size
      add the capability for index-pack to read from a stream
      enable index-pack streaming capability
      make index-pack able to complete thin packs.
      add progress status to index-pack
      mimic unpack-objects when --stdin is used with index-pack
      enhance clone and fetch -k experience
      index-pack: minor fixes to comment and function name
      missing small substitution
      pack-objects doesn't create random pack names
      make git-push a bit more verbose
      Allow pack header preprocessing before unpack-objects/index-pack.
      git-fetch can use both --thin and --keep with fetch-pack now
      improve fetch-pack's handling of kept packs
      have index-pack create .keep file more carefully
      remove .keep pack lock files when done with refs update
      git-pack-objects progress flag documentation and cleanup

OGAWA Hirofumi:
      gitk: Fix nextfile() and add prevfile()

Petr Baudis:
      Fix broken sha1 locking
      Fix buggy ref recording
      gitweb: Document features better
      gitweb: Fix search form when PATH_INFO is enabled
      bisect reset: Leave the tree in usable state if git-checkout failed
      gitweb: Fix setting $/ in parse_commit()
      gitweb: Restore object-named links in item lists
      gitweb: Make search type a popup menu
      gitweb: Do not automatically append " git" to custom site name
      gitweb: Show project's README.html if available
      xdiff: Match GNU diff behaviour when deciding hunk comment worthiness of lines
      gitweb: Support for 'forks'
      gitweb: Fix up bogus $stylesheet declarations
      Nicer error messages in case saving an object to db goes wrong

Rene Scharfe:
      git-archive --format=zip: use default version ID
      git-archive --format=zip: add symlink support
      git-merge: show usage if run without arguments
      Built-in cherry
      Make git-cherry handle root trees
      git-cherry: document limit and add diagram

Robert Shearman:
      git-rebase: Use --ignore-if-in-upstream option when executing git-format-patch.
      git-rebase: Add a -v option to show a diffstat of the changes upstream at the start of a rebase.
      git-rebase: Use --ignore-if-in-upstream option when executing git-format-patch.

Robin Rosenberg:
      Mention that pull can work locally in the synopsis
      Swap the porcelain and plumbing commands in the git man page
      Rework cvsexportcommit to handle binary files for all cases.

Ryan Anderson:
      Remove git-annotate.perl and create a builtin-alias for git-blame

Santi Béjar:
      fetch: Misc output cleanup
      merge and resolve: Output short hashes and .. in "Updating ..."
      Documentation for the [remote] config

Sasha Khapyorsky:
      git-svnimport.perl: copying directory from original SVN place
      git-svnimport: support for partial imports

Sean Estabrooks:
      Add --global option to git-repo-config.

Sergey Vlasov:
      git-send-email: Document support for local sendmail instead of SMTP server
      git-send-email: Read the default SMTP server from the GIT config file

Shawn Pearce:
      Added completion support for git-branch.exe.
      Added bash completion support for git-reset.
      Use ULONG_MAX rather than implicit cast of -1.
      Remove SIMPLE_PROGRAMS and make git-daemon a normal program.
      Remove unsupported C99 style struct initializers in git-archive.
      Added missing completions for show-branch and merge-base.
      Only load .exe suffix'd completions on Cygwin.
      Bash completion support for remotes in .git/config.
      Take --git-dir into consideration during bash completion.
      Support bash completion on symmetric difference operator.
      Remove more sed invocations from within bash completion.
      Use column indexes in git-cvsserver where necessary.
      Allow short pack names to git-pack-objects --unpacked=.
      Only repack active packs by skipping over kept packs.
      Teach git-index-pack how to keep a pack file.
      Remove unused variable in receive-pack.
      Move deny_non_fast_forwards handling completely into receive-pack.
      Teach receive-pack how to keep pack files based on object count.

Tero Roponen:
      remove an unneeded test

Tuncer Ayaz:
      git-fetch.sh printed protocol fix


^ permalink raw reply	[relevance 1%]

* Re: Cleaning up git user-interface warts
  @ 2006-11-15 20:51  2%           ` Carl Worth
  0 siblings, 0 replies; 200+ results
From: Carl Worth @ 2006-11-15 20:51 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Andy Whitcroft, Petr Baudis

[-- Attachment #1: Type: text/plain, Size: 6788 bytes --]

On Tue, 14 Nov 2006 16:31:50 -0800, Junio C Hamano wrote:
> I do not think the Porcelain-ish UI that is shipped with git
> should be taken with the same degree of "authority" as git
> Plumbing.

I think we should fix this. "This is great technology with a crap
interface on top" really isn't a good story. I don't actually agree
with that---I don't think the git interface is really all that bad,
it's just got a few little things that tend to trip up new users in my
experience.

And what git does really well, (history exploring, allowing for
pipeline on-liners to iterate over revisions in A..B), are things that
don't even exist in other tools, nor even in the "alternate"
porcelains for git. This stuff is where git's interface is really
fantastic, and it would be a shame to write it off.

>                                                        I think
> single isolated developers, contributors and CVS style shared
> repository usage could be a lot improved because neither of us
> were concentrating in their workflows.  This needs somebody
> motivated enough to improve things in that area.  For example,
> StGIT with its 'float' command is a great improvement over what
> rebase does for people in the contributor role.

Yes, there are some specific workflow-oriented operations that git
doesn't handle as well as it could. Things like commit --amend are
certainly improvements. One that is still totally broken is "follow
all the development in another repository" where clone followed by
repeated fetch doesn't do the job as soon as the remote adds or
deletes a branch.

> But making it more usable for whom is a big question.
>
> Quite frankly, I do not think there can be _the_ single UI that
> would satisfy different types of workflows for some of the
> commands.

I strongly disagree. Or at least, I don't think we've tried hard
enough yet that we should give up on this.

I do agree that people in different roles will have different lists of
"most used operations" and that some operations won't appear on some
users lists at all, (someone who's just "watching" development won't
commit or merge, for example---[or so they thing when they start]).

But I really don't think that for any given operation that different
roles impose a different desire on the behavior of the operation. We
have different people with different background and disagreement on
names and silly things like that, but I don't think that's related to
the roles in which they are working with the tool.

> For example, fetching and merging from many places without
> necessarily having corresponding tracking branches is a great
...

I don't think we've ever had this right in git. The new
--use-separate-remotes stuff or similar will start to help as it
becomes the default. I don't see how this won't benefit everybody.

> For another example, having a commit command to commit
> everything by default is disastrous for people who allow their
> workflows to often be interrupted.

Workflow-interruption is an important thing to support, but separating
update-index and commit really doesn't address it nearly as much as I
would like. The lack of really good workflow-interruption support has
been one of my longest-running annoyances with git, (perhaps because I
have a problem with trying to do too many things at once). Git can
create and change branches fast enough that it really should be able
to help me better with this. The only missing piece is being able to
stash the dirty stuff on the current branch, to be able to come back
to it later. I've talked a bit about what I would like in this area
before, and I really just need to code it up.

> It is not just command line syntax and the defaults, but
> concepts as well.  People in the integrator role often need to
> deal with merges and you would need to be aware of the role of
> the index and need to be able to manipulate the index, ...

Again, I think it's more that the specific operations bring in
concepts, (merge bringing in the index here). As such, someone never
doing a merge could easily get by not having to understand the index.

> A Porcelain that does a very similar thing in slightly different
> way is obviously a waste, but otherwise I do not think it is a
> problem to have different Porcelains.  StGIT does not compete
> with the "sucky" Porcelain-ish shipped with git but makes the
> user's life a lot more pleasant by complementing what the sucky
> one does not do well.  It is not very useful while I am playing
> the integrator role, but when I am doing my own thing it is a
> great addition to my toolchest.

But even here, there's a bunch of waste in StGit. For example, there
are a lot of commands in StGit whose only purpose is to translate back
and forth between the StGit and non-StGit views of the world, (init,
assimilate, commit, uncommit). Those could all be discarded if the
functionality of StGit were brought down into git itself. Then there
are a myriad of StGit commands which are basically just the same as
their git counterparts.

Now, StGit is a great tool, and I know that it works really well for
some people in the role of just maintaining a stack of changes against
some upstream, and can use StGit alone and never touch "git" the
command-line.

But for someone like me who already uses git regularly, and
occasionally just wants to pop back a few commits, amend it, and then
push again, StGit is not helpful, (the series of init, assimilate, and
uncommits just to get started is prohibitive compared to just working
out the awkward steps needed to make a temporary branch and
rebase). So I'd love to see just a couple of commands added to "git"
to support these kinds of operations more smoothly.

> I am from the camp that does _not_ want to hide the index, so
> obviously I do not see any value in its effort to hide the
> index.  But other aspects of it, most notably being friendly to
> simpler workflows, is a very good thing.

I don't think "hide or not-to-hide" is the right way to frame the
discussion about the index. I regularly use update-index to stage
partial commits, and I find that very useful. And obviously the index
is involved in resolving merge conflicts.

But I don't think the user-interface for either of those operations
(partial commit, resolve conflicts), is ideal, and the current
requirement to use either "update-index <paths>" or "commit -a" after
modifying a file for the first time is demonstrably a hangup for a lot
of new users. So I really think it's possible to address both of these
at once.

Anyone, that's enough generic rambling from me without any specific
content. I'll try to keep future messages focused on specific
desirable operations that have problematic interfaces in git right
now, along with proposals for improving them.

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[relevance 2%]

* What's in git.git
@ 2006-11-25 10:12  3% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-11-25 10:12 UTC (permalink / raw)
  To: git; +Cc: linux-kernel

Executive Summary
=================

The 'maint' branch still has a handful more post v1.4.4.1
fixes.

Aside from the usual gitweb and git-svn updates, the 'master'
branch has one notable change that everybody should hopefully
welcome.  separate-remote layout is now the default for newly
cloned repositories.  We would be needing documentation updates
and probably some more minor fixes for fallout from this, but I
do not expect anything majorly broken.

Cooking in 'next' are handful topics:

 * "git shortlog bottom..top" can be used instead of a pipeline
   "git log bottom..top | git shortlog".

 * "git merge -m message <commit>" is another natural way to
   perform a local merge, in addition to the traditional
   "git pull . <localbranch>".  The former is more powerful in
   that it can take arbitrary <committish>, not just a ref.

 * The new "--depth $n" parameter to git clone/fetch tries to
   limit the commit ancestry depth to $n.  This still has known
   issues (for example, shallowly cloning the git.git repository
   and then deepening the result with large --depth parameter
   later does not seem to make the resulting repository fully
   connected, and fsck-objects reports corruption), so please
   handle it with care.

 * "git show-ref", especially the "-d" variant, is much more
   efficient when used in a repository with pack-pruned refs.

 * "git fetch" can fetch from a repository with pack-pruned refs
   over dumb protocol transports.

 * "git push $URL '':$ref" can be used to delete an existing ref
   from the remote side.

 * A glob pattern "Pull: refs/heads/*:refs/remotes/origin/*" is
   allowed in the remotes file.  The fetch can be forced by
   prefixing the specification with a '+'.

Currently 'pu' does not have much to speak of.

This update has rather large impact so the kernel list is CC'ed.

----------------------------------------------------------------

* The 'maint' branch has these fixes since the last announcement.

   Andy Parkins (1):
      Increase length of function name buffer

   Eric Wong (3):
      git-svn: error out from dcommit on a parent-less commit
      git-svn: correctly handle revision 0 in SVN repositories
      git-svn: preserve uncommitted changes after dcommit

   René Scharfe (1):
      archive-zip: don't use sizeof(struct ...)


* The 'master' branch has these since the last announcement.

   Andy Parkins (3):
      Improve git-prune -n output
      Add support to git-branch to show local and remote branches
      Increase length of function name buffer

   Eric Wong (6):
      git-svn: error out from dcommit on a parent-less commit
      git-svn: correctly handle revision 0 in SVN repositories
      git-svn: preserve uncommitted changes after dcommit
      git-svn: handle authentication without relying on cached tokens on disk
      git-svn: correctly access repos when only given partial read permissions
      git-svn: exit with status 1 for test failures

   Iñaki Arenaza (1):
      git-cvsimport: add support for CVS pserver method HTTP/1.x proxying

   Jakub Narebski (8):
      gitweb: Protect against possible warning in git_commitdiff
      gitweb: Buffer diff header to deal with split patches + git_patchset_body refactoring
      gitweb: Default to $hash_base or HEAD for $hash in "commit" and "commitdiff"
      gitweb: New improved formatting of chunk header in diff
      gitweb: Add an option to href() to return full URL
      gitweb: Refactor feed generation, make output prettier, add Atom feed
      gitweb: Finish restoring "blob" links in git_difftree_body
      gitweb: Replace SPC with &nbsp; also in tag comment

   Junio C Hamano (9):
      upload-pack: stop the other side when they have more roots than we do.
      apply --numstat: mark binary diffstat with - -, not 0 0
      pack-objects: tweak "do not even attempt delta" heuristics
      refs outside refs/{heads,tags} match less strongly.
      Typefix builtin-prune.c::prune_object()
      gitweb: (style) use chomp without parentheses consistently.
      git-clone: stop dumb protocol from copying refs outside heads/ and tags/.
      git-branch -D: make it work even when on a yet-to-be-born branch
      git-fetch: exit with non-zero status when fast-forward check fails

   Lars Hjemli (1):
      Add -v and --abbrev options to git-branch

   Peter Baumann (1):
      config option log.showroot to show the diff of root commits

   Petr Baudis (1):
      Make git-clone --use-separate-remote the default

   René Scharfe (1):
      archive-zip: don't use sizeof(struct ...)


* The 'next' branch, in addition, has these.

   Alexandre Julliard (6):
      Shallow clone: do not ignore shallowness when following tags
      fetch-pack: Properly remove the shallow file when it becomes empty.
      upload-pack: Check for NOT_SHALLOW flag before sending a shallow to the client.
      git-fetch: Reset shallow_depth before auto-following tags.
      get_shallow_commits: Avoid memory leak if a commit has been reached already.
      fetch-pack: Do not fetch tags for shallow clones.

   Jakub Narebski (1):
      gitweb: Do not use esc_html in esc_path

   Johannes Schindelin (10):
      Build in shortlog
      shortlog: do not crash on parsing "[PATCH"
      shortlog: read mailmap from ./.mailmap again
      shortlog: handle email addresses case-insensitively
      shortlog: fix "-n"
      upload-pack: no longer call rev-list
      support fetching into a shallow repository
      allow cloning a repository "shallowly"
      allow deepening of a shallow repository
      add tests for shallow stuff

   Junio C Hamano (19):
      Store peeled refs in packed-refs file.
      remove merge-recursive-old
      git-merge: make it usable as the first class UI
      merge: allow merging into a yet-to-be-born branch.
      git-diff/git-apply: make diff output a bit friendlier to GNU patch (part 2)
      Store peeled refs in packed-refs (take 2).
      git-fetch: reuse ls-remote result.
      git-fetch: fix dumb protocol transport to fetch from pack-pruned ref
      git-fetch: allow glob pattern in refspec
      Allow git push to delete remote ref.
      We should make sure that the protocol is still extensible.
      Why does it mean we do not have to register shallow if we have one?
      Why didn't we mark want_obj as ~UNINTERESTING in the old code?
      shallow clone: unparse and reparse an unshallowed commit
      git-shortlog: fix common repository prefix abbreviation.
      git-shortlog: make common repository prefix configurable with .mailmap
      git-commit: show --summary after successful commit.
      git-fetch: allow forcing glob pattern in refspec
      fetch-pack: do not barf when duplicate re patterns are given

   Nicolas Pitre (1):
      builtin git-shortlog is broken


* The 'pu' branch, in addition, has these.

   Junio C Hamano (4):
      para-walk: walk n trees, index and working tree in parallel
      rev-list --left-right
      blame: --show-stats for easier optimization work.
      gitweb: steal loadavg throttle from kernel.org


^ permalink raw reply	[relevance 3%]

* [PATCH] (experimental) per-topic shortlog.
@ 2006-11-27  0:44  2% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2006-11-27  0:44 UTC (permalink / raw)
  To: git; +Cc: Johannes Schindelin

This implements an experimental "git log-fpc" command that shows
short-log style output sorted by topics.

A "topic" is identified by going through the first-parent
chains; this ignores the fast-forward case, but for a top-level
integrator it often is good enough.

For example, if the commit ancestry graph looks like this:

         x---x---x---X---o---*---o---o---o HEAD
          \                 /
           o---o---o---o---o

and the command line asks for

	git log-fpc --no-merges X..

It first finds all the commits 'o'.  Then it emits the four
commits on the upper line (assume the merge '*' has the commit
that is a child of X as its first parent in the picture).  When
it does so, it the list of authors for these four commits on one
line, followed by the title of these commits.  After that, it
does the same for the five commits on the lower line.

---

I initially wanted to do this inside Johannes's enhanced
shortlog, but ended up doing this as a pretty much independent
thing, because the shortlog implementation stringifies the
information from the commits too early to be easily enhanced for
this purpose.

If this turns out to be a better way to present shortlog,
however, this should become an option to git-shortlog.

A sample output from:

	git log-fpc --no-merges v1.4.4.1..f64d7fd2

looks like this (f64d7fd2 was the tip of master when the last
"What's in" message was sent out).  It shows that many "fixes"
and git-svn enhancements were directly done on "master" (that is
the first group), while many gitweb enhancements, changing the
output from "prune -n", "git branch" enhancements, etc. were
first cooked in separate topic branches and then later merged
into 'master'.

To this output, I can manually add a topic title to the
beginning of each group and it would make a better overview than
what I currently send out in "What's in" message which is
generated with shortlog.

----------------------------------------------------------------

Eric Wong (6), Junio C Hamano (5), Lars Hjemli, Jakub Narebski,
 Iñaki Arenaza, Petr Baudis, Andy Parkins, and René Scharfe
 git-fetch: exit with non-zero status when fast-forward check fails
 git-svn: exit with status 1 for test failures
 git-svn: correctly access repos when only given partial read permissions
 git-branch -D: make it work even when on a yet-to-be-born branch
 Add -v and --abbrev options to git-branch
 git-clone: stop dumb protocol from copying refs outside heads/ and tags/.
 gitweb: (style) use chomp without parentheses consistently.
 gitweb: Replace SPC with &nbsp; also in tag comment
 git-svn: handle authentication without relying on cached tokens on disk
 git-cvsimport: add support for CVS pserver method HTTP/1.x proxying
 Make git-clone --use-separate-remote the default
 refs outside refs/{heads,tags} match less strongly.
 Increase length of function name buffer
 git-svn: preserve uncommitted changes after dcommit
 git-svn: correctly handle revision 0 in SVN repositories
 git-svn: error out from dcommit on a parent-less commit
 archive-zip: don't use sizeof(struct ...)

Junio C Hamano and Andy Parkins
 Typefix builtin-prune.c::prune_object()
 Improve git-prune -n output

Peter Baumann
 config option log.showroot to show the diff of root commits

Andy Parkins
 Add support to git-branch to show local and remote branches

Jakub Narebski (7)
 gitweb: Finish restoring "blob" links in git_difftree_body
 gitweb: Refactor feed generation, make output prettier, add Atom feed
 gitweb: Add an option to href() to return full URL
 gitweb: New improved formatting of chunk header in diff
 gitweb: Default to $hash_base or HEAD for $hash in "commit" and "commitdiff"
 gitweb: Buffer diff header to deal with split patches + git_patchset_body refactoring
 gitweb: Protect against possible warning in git_commitdiff

----------------------------------------------------------------

 builtin-log.c |  177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 builtin.h     |    1 +
 git.c         |    1 +
 3 files changed, 179 insertions(+), 0 deletions(-)

diff --git a/builtin-log.c b/builtin-log.c
index 7acf5d3..1c2838c 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -99,6 +99,183 @@ int cmd_log(int argc, const char **argv, const char *prefix)
 	return cmd_log_walk(&rev);
 }
 
+/* bits #0..7 in revision.h, #8..11 in commit.c */
+#define FPC_RESULT (1u<<12)
+#define FPC_SHOWN  (1u<<13)
+
+struct author_record {
+	char *name;
+	int count;
+};
+struct author_count {
+	int nr, alloc;
+	struct author_record **au;
+};
+
+static int cmp_count(const void *a_, const void *b_)
+{
+	struct author_record **a = (struct author_record **) a_;
+	struct author_record **b = (struct author_record **) b_;
+	return (*b)->count - (*a)->count;
+}
+
+static void add_author(struct commit *c, struct author_count *ac)
+{
+	const char *buf = c->buffer;
+	char *au = strstr(buf, "\nauthor ");
+	char *eon;
+	struct author_record *ar;
+	int i;
+
+	if (!au)
+		return; /* oops */
+	au += 7;
+	while (*au && isspace(*au))
+		au++;
+	if (!*au)
+		return; /* oops */
+	eon = strchr(au, '<');
+	if (!eon)
+		return; /* oops */
+	while (au < --eon && isspace(*eon))
+		; /* back back back... */
+	eon++;
+	for (i = 0; i < ac->nr; i++)
+		if (!strncmp(ac->au[i]->name, au, eon-au) &&
+		    strlen(ac->au[i]->name) == eon - au) {
+			/* found it */
+			ac->au[i]->count++;
+			return;
+		}
+	if (ac->alloc <= ac->nr) {
+		ac->alloc = alloc_nr(ac->alloc);
+		ac->au = xrealloc(ac->au, sizeof(struct author_record *) *
+				  ac->alloc);
+	}
+	ar = xcalloc(1, sizeof(struct author_record));
+	ar->name = xmalloc(eon - au + 1);
+	memcpy(ar->name, au, eon - au);
+	ar->name[eon - au] = 0;
+	ar->count = 1;
+	ac->au[ac->nr++] = ar;
+}
+
+static void show_fpc(struct object_array *list)
+{
+	int i;
+	struct author_count ac;
+
+	if (!list->nr)
+		return;
+	memset(&ac, 0, sizeof(ac));
+	for (i = 0; i < list->nr; i++)
+		add_author((struct commit *) list->objects[i].item, &ac);
+	qsort(ac.au, ac.nr, sizeof(struct author_record *), cmp_count);
+
+	for (i = 0; i < ac.nr; i++) {
+		if (i) {
+			if (i < ac.nr - 1)
+				fputs(", ", stdout);
+			else if (ac.nr != 2)
+				fputs(", and ", stdout);
+			else
+				fputs(" and ", stdout);
+		}
+		if (ac.au[i]->count < 2)
+			printf("%s", ac.au[i]->name);
+		else
+			printf("%s (%d)", ac.au[i]->name, ac.au[i]->count);
+		free(ac.au[i]->name);
+		free(ac.au[i]);
+	}
+	free(ac.au);
+	putchar('\n');
+
+	for (i = 0; i < list->nr; i++) {
+		struct commit *c = (struct commit *) list->objects[i].item;
+		char *buf = c->buffer;
+		char *it = "<unnamed>";
+		int len = strlen(it);
+		buf = strstr(buf, "\n\n");
+		if (buf) {
+			char *lineend;
+			while (*buf && isspace(*buf))
+				buf++;
+			if (!*buf)
+				goto emit;
+			lineend = strchr(buf, '\n');
+			if (!lineend)
+				goto emit;
+			while (buf < lineend && isspace(*lineend))
+				lineend--;
+			len = lineend - buf + 1;
+			it = buf;
+		}
+	emit:
+		printf(" %.*s\n", len, it);
+	}
+	putchar('\n');
+}
+
+int cmd_log_fpc(int argc, const char **argv, const char *prefix)
+{
+	struct rev_info rev;
+	struct commit *c;
+	struct object_array result = { 0, 0, NULL };
+	int i;
+
+	git_config(git_log_config);
+	init_revisions(&rev, prefix);
+	rev.always_show_header = 1;
+	cmd_log_init(argc, argv, prefix, &rev);
+
+	prepare_revision_walk(&rev);
+	while ((c = get_revision(&rev)) != NULL)
+		add_object_array(&(c->object), NULL, &result);
+
+	/* clear flags and mark them "relevant" */
+	for (i = 0; i < result.nr; i++)
+		result.objects[i].item->flags |= FPC_RESULT;
+
+	for (;;) {
+		struct object_array current;
+
+		for (i = 0; i < result.nr; i++) {
+			if (!(result.objects[i].item->flags & FPC_SHOWN))
+				break;
+		}
+		if (i >= result.nr)
+			break;
+
+		memset(&current, 0, sizeof(current));
+		c = (struct commit *) result.objects[i].item;
+		while (c) {
+			int flags = c->object.flags;
+
+			if ((flags & (FPC_RESULT|FPC_SHOWN)) == FPC_RESULT) {
+				add_object_array(&(c->object), NULL, &current);
+				c->object.flags |= FPC_SHOWN;
+			}
+			if (!c->object.parsed)
+				parse_object(c->object.sha1);
+			if (!c->parents)
+				break;
+			c = c->parents->item;
+		}
+
+		/* Finally, show the series. */
+		show_fpc(&current);
+	}
+
+	/* free them */
+	for (i = 0; i < result.nr; i++) {
+		c = (struct commit *) result.objects[i].item;
+		free(c->buffer);
+		free_commit_list(c->parents);
+	}
+	return 0;
+}
+
 static int istitlechar(char c)
 {
 	return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
diff --git a/builtin.h b/builtin.h
index 43fed32..a94540d 100644
--- a/builtin.h
+++ b/builtin.h
@@ -38,6 +38,7 @@ extern int cmd_grep(int argc, const char **argv, const char *prefix);
 extern int cmd_help(int argc, const char **argv, const char *prefix);
 extern int cmd_init_db(int argc, const char **argv, const char *prefix);
 extern int cmd_log(int argc, const char **argv, const char *prefix);
+extern int cmd_log_fpc(int argc, const char **argv, const char *prefix);
 extern int cmd_ls_files(int argc, const char **argv, const char *prefix);
 extern int cmd_ls_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_mailinfo(int argc, const char **argv, const char *prefix);
diff --git a/git.c b/git.c
index 1aa07a5..65d98bd 100644
--- a/git.c
+++ b/git.c
@@ -243,6 +243,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
 		{ "help", cmd_help },
 		{ "init-db", cmd_init_db },
 		{ "log", cmd_log, RUN_SETUP | USE_PAGER },
+		{ "log-fpc", cmd_log_fpc, RUN_SETUP | USE_PAGER },
 		{ "ls-files", cmd_ls_files, RUN_SETUP },
 		{ "ls-tree", cmd_ls_tree, RUN_SETUP },
 		{ "mailinfo", cmd_mailinfo },
-- 
1.4.4.1.ge3fb


^ permalink raw reply related	[relevance 2%]

* Re: [RFC] Submodules in GIT
    @ 2006-12-01 22:26  4%       ` Linus Torvalds
    2006-12-01 22:55  1%         ` Josef Weidendorfer
  1 sibling, 2 replies; 200+ results
From: Linus Torvalds @ 2006-12-01 22:26 UTC (permalink / raw)
  To: Josef Weidendorfer; +Cc: sf, git, Martin Waitz



On Fri, 1 Dec 2006, Josef Weidendorfer wrote:
> > 
> > Well, I would actually argue that you may often want to have a supermodule 
> > and then at least have the _option_ to decide to not fetch all the 
> > submodules.
> 
> If you want to allow this, you have to be able to cut off fetching the
> objects of the supermodule at borders to given submodules, the ones you
> do not want to track. With "border" I mean the submodule commit in some
> tree of the supermodule.
>
> This looks a little bit like a shallow clone

No. 

I would say that it looks more like a "partial checkout" than a shallow 
clone.

A shallow clone limits the data in "time" - we have _some_ data, but we 
don't have all of the history of that data.

In contrast, a submodule that we don't fetch is an all-or-nothing 
situation: we simply don't have the data at all, and it's really a matter 
of simply not recursing into that submodule at all - much more like not 
checking out a particular part of the tree.

So if a shallow clone is a "limit in time", a lack of a module (or a lack 
of a checkout for a subtree in general - you could certainly imagine doing 
the same thing even _within_ a git repository, and indeed, we did discuss 
exactly that at one point in time) is more of a "limit in space".


^ permalink raw reply	[relevance 4%]

* Re: [RFC] Submodules in GIT
  @ 2006-12-01 22:40  2%           ` Martin Waitz
  0 siblings, 0 replies; 200+ results
From: Martin Waitz @ 2006-12-01 22:40 UTC (permalink / raw)
  To: Josef Weidendorfer; +Cc: Linus Torvalds, sf, git

[-- Attachment #1: Type: text/plain, Size: 1218 bytes --]

hoi :)

On Fri, Dec 01, 2006 at 11:26:22PM +0100, Josef Weidendorfer wrote:
> It's not about checking out part of the tree, it's about fetching only
> part of the objects: If you have a slow modem and want to clone a
> supermodule, you are not interested in fetching all the objects from
> some submodules.

So when you want to suppress one submodule, how is this not about only
checking out part of the tree?
Ok, you also want to avoid downloading the submodule, but you first have
to solve the partial checkout.

> BTW: In your submodule implementation, is the user allowed to change the
> relative path of the root of some submodule, e.g. with "git-mv" ?

In principle: yes.
However there are some links between both repositories that have to be
updated manually (for the shared object repository and for ignoring
submodule files in the supermodule).
But I expect that much of this configuration stuff will vanish when
submodules are better integrated in git.

Rename detection for submodules would be another interesting thing to
have. It should be much easier as for files because we can simply check
for common ancestors and do not have to guess based on the diff.

-- 
Martin Waitz

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[relevance 2%]

* Re: [RFC] Submodules in GIT
  2006-12-01 22:26  4%       ` Linus Torvalds
  @ 2006-12-01 22:55  1%         ` Josef Weidendorfer
  1 sibling, 0 replies; 200+ results
From: Josef Weidendorfer @ 2006-12-01 22:55 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: sf, git, Martin Waitz

On Friday 01 December 2006 23:26, Linus Torvalds wrote:
> 
> On Fri, 1 Dec 2006, Josef Weidendorfer wrote:
> > > 
> > > Well, I would actually argue that you may often want to have a supermodule 
> > > and then at least have the _option_ to decide to not fetch all the 
> > > submodules.
> > 
> > If you want to allow this, you have to be able to cut off fetching the
> > objects of the supermodule at borders to given submodules, the ones you
> > do not want to track. With "border" I mean the submodule commit in some
> > tree of the supermodule.
> >
> > This looks a little bit like a shallow clone
> 
> No. 
> 
> I would say that it looks more like a "partial checkout" than a shallow 
> clone.
> 
> A shallow clone limits the data in "time" - we have _some_ data, but we 
> don't have all of the history of that data.
> 
> In contrast, a submodule that we don't fetch is an all-or-nothing 
> situation: we simply don't have the data at all, and it's really a matter 
> of simply not recursing into that submodule at all - much more like not 
> checking out a particular part of the tree.

OK.

I still think it should be about "limit in space" regarding the
objects in the local repository.

For a project containing "gcc" as submodule, and I am not
interested in this submodule, there should be a way to not need
to fetch all the objects from the gcc submodule at clone time.


What about my other argument for a submodule namespace:
You want to be able to move the relative root path of a submodule
inside of your supermodule, but yet want to have a unique name
for the submodule:
- to be able to just clone a submodule without having to know
the current position in HEAD
- more practically, e.g. to be able to name a submodule
independent from any current commit you are on in the supermodule,
e.g. to be able to store some meta information about a submodule:
- "Where is the official upstream of this submodule?"
- "Should git allow to commit rewind actions of this submodule
   in the supermodule?" (which, AFAICS, exactly has the same
   problems as publishing a rewound branch: you will get into
   merge hell when you want to pull upstream changes into the
   supermodule)
- "Should this submodule be checked out?"
and so on.


^ permalink raw reply	[relevance 1%]

* Re: [RFC] Submodules in GIT
  @ 2006-12-01 23:49  3%             ` sf
  2006-12-02 18:57  1%               ` Torgil Svensson
  0 siblings, 1 reply; 200+ results
From: sf @ 2006-12-01 23:49 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: sf, git, Martin Waitz

Linus Torvalds wrote:
> 
> On Fri, 1 Dec 2006, sf wrote:
>> Linus Torvalds wrote:
>> ...
>>> In contrast, a submodule that we don't fetch is an all-or-nothing 
>>> situation: we simply don't have the data at all, and it's really a matter 
>>> of simply not recursing into that submodule at all - much more like not 
>>> checking out a particular part of the tree.
>> If you do not want to fetch all of the supermodule then do not fetch the
>> supermodule.
> 
> So why do you want to limit it? There's absolutely no cost to saying "I 
> want to see all the common shared infrastructure, but I'm actually only 
> interested in this one submodule that I work with".

If you need a common infrastructure to be able to work with the
submodule, then the submodule is not independent of of the supermodule.
I see a contradiction in your requirements.

> Also, anybody who works on just the build infrastructure simply may not 
> care about all the submodules. The submodules may add up to hundreds of 
> gigs of stuff. Not everybody wants them. But you may still want to get the 
> common build infrastructure.

See above.

> In other words, your "all or nothing" approach is
>  (a) not friendly
> and
>  (b) has no real advantages anyway, since modules have to be independent 
>      enough that you _can_ split them off for other reasons anyway.
> 
> So forcing that "you have to take everything" mentality onyl has 
> negatives, and no positives. Why do it?

(There have been lots of use cases for shallow clones but for a long
time git did not support them).

If you can extend this partial fetch feature to the non-subproject case
I would agree with your reasoning. What makes the subprojects so special
in this regard. Do I have to turn a plain tree into a subproject to be
able to ignore it? Once you can restrict fetches to parts of the
contents you get the ability to restrict fetches to the "common
infrastructure" and selected submodules for free.

Regards

Stephan

^ permalink raw reply	[relevance 3%]

* Re: [RFC] Submodules in GIT
  2006-12-01 23:49  3%             ` sf
@ 2006-12-02 18:57  1%               ` Torgil Svensson
    0 siblings, 1 reply; 200+ results
From: Torgil Svensson @ 2006-12-02 18:57 UTC (permalink / raw)
  To: sf-gmane, Linus Torvalds, sf, git, Martin Waitz

> If you need a common infrastructure to be able to work with the
> submodule, then the submodule is not independent of of the supermodule.
> I see a contradiction in your requirements.

Here's an real-world example that doesn't contradict:

http://amarok.kde.org/wiki/Installation_HowTo#From_Anonymous_SVN

"svn co -N svn://anonsvn.kde.org/home/kde/trunk/extragear/multimedia
cd multimedia
svn co svn://anonsvn.kde.org/home/kde/branches/KDE/3.5/kde-common/admin
svn up amarok

To compile the sources (from the multimedia directory):"

and there's probably very few people that want to clone the entire KDE
multimedia sub&super-module in this case.

//Torgil


On 12/2/06, sf <sf-gmane@stephan-feder.de> wrote:
> Linus Torvalds wrote:
> >
> > On Fri, 1 Dec 2006, sf wrote:
> >> Linus Torvalds wrote:
> >> ...
> >>> In contrast, a submodule that we don't fetch is an all-or-nothing
> >>> situation: we simply don't have the data at all, and it's really a matter
> >>> of simply not recursing into that submodule at all - much more like not
> >>> checking out a particular part of the tree.
> >> If you do not want to fetch all of the supermodule then do not fetch the
> >> supermodule.
> >
> > So why do you want to limit it? There's absolutely no cost to saying "I
> > want to see all the common shared infrastructure, but I'm actually only
> > interested in this one submodule that I work with".
>
> If you need a common infrastructure to be able to work with the
> submodule, then the submodule is not independent of of the supermodule.
> I see a contradiction in your requirements.
>
> > Also, anybody who works on just the build infrastructure simply may not
> > care about all the submodules. The submodules may add up to hundreds of
> > gigs of stuff. Not everybody wants them. But you may still want to get the
> > common build infrastructure.
>
> See above.
>
> > In other words, your "all or nothing" approach is
> >  (a) not friendly
> > and
> >  (b) has no real advantages anyway, since modules have to be independent
> >      enough that you _can_ split them off for other reasons anyway.
> >
> > So forcing that "you have to take everything" mentality onyl has
> > negatives, and no positives. Why do it?
>
> (There have been lots of use cases for shallow clones but for a long
> time git did not support them).
>
> If you can extend this partial fetch feature to the non-subproject case
> I would agree with your reasoning. What makes the subprojects so special
> in this regard. Do I have to turn a plain tree into a subproject to be
> able to ignore it? Once you can restrict fetches to parts of the
> contents you get the ability to restrict fetches to the "common
> infrastructure" and selected submodules for free.
>
> Regards
>
> Stephan
>
> -
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[relevance 1%]

* Re: [RFC] Submodules in GIT
  @ 2006-12-03 17:54  3%                     ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2006-12-03 17:54 UTC (permalink / raw)
  To: Torgil Svensson; +Cc: sf-gmane, sf, git, Martin Waitz



On Sun, 3 Dec 2006, Torgil Svensson wrote:
>
> On 12/2/06, Linus Torvalds <torvalds@osdl.org> wrote:
> > 
> > In other words, I don't think people expect or want something hugely more
> > complicated than the CVS/modules kind of file.
> 
> What about the case when you want _everything_, do you then have to
> know the names of all submodules, present and past?

Afaik, the way people do this historically is simply:

 - often have an alias for "everything" (eg "all" or "src" or "world"), 
   and if you want everything, you basically ask for it by checking out 
   the "src" module.

   Ie this is the "upstream" way to let downstream check out everything.

 - if you're downstream, and you have a partial repo, and you realize that 
   you want everything else, you just look at gitweb (assuming it is 
   extended to show module information, of course ;) or the .gitmodules 
   (or whatever it would be called) file to get the other pieces manually.

But hey, I also think it would be fine to have "git clone --allmodules" or 
something ("fetch" too). I think this whole question will depend more on 
how people end up _using_ module support than on any technical issues per 
se. Again, I suspect the people who now set up modules in CVS are likely 
to have a better idea than I do about how they usually do it (and why).

> If you have an old irrelevant submodule in the history that happens to
> have the same name as one of them you are interested in, do you get
> this as well?

I dunno. Details, details. I'm also not sure this is hugely important.

It could be "solved" by simply having the requirement that all modules 
need to be named differently (notice that "module name" is _not_ the same 
thing as "the directory name where the module shows up". That's not the 
case even in CVS modules, and with a "link" type in the git tree object, 
the directory where a module shows up would basically be totally 
independent of the "name" of the module).

> During a debugging session it might be convenient to do a "all but X"
> kind of fetch if you have a project dependent on several small modules
> and one of them is the big black sheep.

I suspect it's more common to name the modules you want to fetch 
explicitly, rather than make it a "negative" choice, but that sounds 
largely like just an interface issue.


^ permalink raw reply	[relevance 3%]

* Re: [RFC] Submodules in GIT
  @ 2006-12-05 11:09  5%     ` Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2006-12-05 11:09 UTC (permalink / raw)
  To: git

Andreas Ericsson wrote:

> Torgil Svensson wrote:
>> On 12/4/06, Linus Torvalds <torvalds@osdl.org> wrote:
>>>
>>> So yeah, it's a bit hacky, but for the reasons I've tried to outline, I
>>> actually think that users _want_ hacky. Exactly because "deep 
>>> integration"
>>> ends up having so many _bad_ features, so it's better to have a thin and
>>> simple layer that you can actually see past if you want to.
>> 
>> Thin and simple sounds very good. Let's try it with an example. Lets
>> say we have one apllication App1 and three librarys (Lib1, Lib2, Lib3)
>> with the following dependency-graph:
>> 
>>        App1
>>        /  \
>>       /    \
>>   Lib1   Lib2
>>       \    /
>>        \  /
>>        Lib3 (don't really needed for this example but looks nice)
>> 
>> All components can be used individually and have their own upstream,
>> maintainer etc.
>> 
>> To compile App1 however, I need some files from both Lib1 and Lib2
>> specifying it's API. To satisfy these dependencies, It sounds
>> reasonable to link Lib2 and Lib3 submodules from App1. In your
>> concept, can I construct a modules file to fetch the API files and
>> their history without checking out the whole Lib1 and Lib2 source?
> 
> I think not. Then it wouldn't be a submodule anymore, but just some 
> random sources from an upstream project. Not that it's an uncommon 
> workflow or anything, but it's sort of akin to just importing the SHA1 
> implementation (a few source-files with no real interest in the history 
> of those source-files) from openssl into a different project rather than 
> actually using the entire openssl lib (which would be nice to have as a 
> submodule).

Note that this is what partial checkouts (another great idea nobody
implemented yet[*1*]; you can do partial checkout but there is no UI for
this, and working with partial checkouts is bit hard) is about, although it
would buy you only working area space, and not repository (object database
storage) space.

For now, you can imitate this by having in in Lib1 and Lib2 the 'includes'
branch which would contain only the API (and which you would have to keep
up to date with 'master', but it should be fairly easy: just merge changes
into 'includes', perhaps with help of git-rerere, or [nonexisting]
git-rerere2).

[*1*] Although with our track[*2*] I guess it is reasonable to think it
would get implemented soon.
[*2*] Out of four "great ideas": shallow clone / sparse clone, submodules
support, lazy clone / remote alternates, two are in example-implementation
(submodules support) and beta work (shallow clone is in 'next').

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git


^ permalink raw reply	[relevance 5%]

* Re: [RFC] Two conceptually distinct commit commands
  @ 2006-12-06 23:29  1%       ` Carl Worth
  0 siblings, 0 replies; 200+ results
From: Carl Worth @ 2006-12-06 23:29 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Johannes Schindelin

[-- Attachment #1: Type: text/plain, Size: 12087 bytes --]

On Wed, 06 Dec 2006 10:31:21 -0800, Junio C Hamano wrote:
> I am not sure what needs to be commented on at this point, since
> it is not yet clear to me where you want your proposal to lead
> us.

Thanks for the comments you made here---that's the kind of thing I was
looking for.

As for where I'm trying to lead us, what I really want to do is to
help improve the learnability of git. A big part of that is about
improving the set of "use-oriented" documentation, (which describes
how to achieve tasks, as opposed to what might be termed "technically
oriented" documentation which describes how individual tools work). I
think too much of the existing documentation falls into the second
class.

A parallel thread is already talking about some of the important
organizational aspects of use-oriented documentation. And I agree with
that thread is that the short "attention span" is a primary
consideration for this kind of documentation. The user has a task to
be accomplish, and any text or concepts that aren't contributing to
the solution of that task should be eliminated.

Note that when I talk about eliminating unnecessary concepts, I do not
mean lying to the user about the underlying model or any concepts. We
can't have a sugar-coated tutorial that says one thing, and then
expect users to "unlearn" that if they go deeper into the reference
manual. That's a recipe for disaster.

Also, when I say "use-oriented" I'm not suggesting that the
documentation be shallow. It can go as deep as any workflow we care to
document and introduce whatever concepts of git are necessary to
support that workflow. (There is, though a level at which "technically
oriented" documentation is all that's needed, or even desired, and
that's when the documentation is targeting authors of interfaces that
build on top of git---not users trying to use git to get work done at
the command line).

OK, so if my concern is all about documentation, then what am I doing
proposing new commands or new ways of thinking about existing commands
rather than just sending documentation patches? The problem is that
the current semantics of the following variations of "git commit":

	git commit
	git commit -a
	git commit paths...

defeat the goal of writing good, clean use-oriented documentation. So
there's some adjustment that should be made first. And I don't even
care what the adjustment is, (for example, it doesn't have to be
"commit -a by default"), but please recognize the problem and help me
come up with an acceptable way to fix it.

To demonstrate, let's take the simplest of use cases and try to
document it in as clear a way as possible. Let's imagine we're in a
tutorial where we've just guided the user to making modifications to
several existing, tracked files, (starting from an initial clone, not
an init-db), and the next task to teach the user commit for the first
time. We would like to document both "commit a single modified file"
and "commit all modified files". Here are two approaches that I can
come up with:

1. Any commit involves first "add"ing together new content, and then
   committing the result. For example to commit a single file:

	git add file		# add new content from file
	git commit		# commit the result

   As a shortcut, "commit -a", (or --all) can be used to automatically
   "add" the content of all tracked files before the commit. So the
   common case of committing all tracked files is as easy as:

	git commit -a		# commit content of all tracked files

2. The new content of modified files can be committed by naming the
   files on the "git commit" command line. For example:

	git commit file		# commit new content of file

   As a shortcut, "commit -a", (or --all) can be used to commit the
   content of all tracked files:

	git commit -a		# commit content of all tracked files

Neither of the above is totally satisfactory.

In (1) the user is not presented with a framework that will make sense
of "git commit files...". The expansion of "-a" as "--all" could
easily give the user the impression that "git commit files..." is a
shortcut for "git add files...; git commit", but that's wrong and
could lead to unexpected results and confusion.

In (2) the user is not presented with a framework that will make sense
of "git commit" with no arguments. The user is left to wonder about
why the --all is needed and what it means exactly, (particularly since
"git commit" also commits the content of all tracked files.

Various fixes have been proposed for these potential confusions. For
example, making "git commit files..." default to the behavior of
--include instead of --only would eliminate the confusion I described
for (1). And making -a the default for "git commit" would eliminate
the confusion I described for (2).

However, actually implementing either of those fixes would then break
the initial "commit one file" example from the other approach. Because
of that, the conversation has often fallen into debate over whether
(1) or (2) is the "one true way" to describe git, and which one leads
the user to have an incorrect mental model.

But I think that debate is misguided since both descriptions are
worthwhile and valid. (1) is based around an explanation of what "git
commit" does, and (2) is based around an explanation of what "git
commit files..." does. And both of these commands are very useful
exactly how they are.

It's almost coincidental that "commit -a" fits in logically with
either description.

So what I was trying to get across in this latest thread is that git's
command-line interface already has two slightly different models for
what's going on in a commit. You don't agree with me on that point
yet, (more on that below in my reply).

I really don't care what the final fix is, but I would love to see
documentation with no more complexity than the above that accurately
captures the useful functionality.

And I don't actually have a concrete proposal for a fix yet---I was
just offering the commit-index-content and commit-working-tree-content
ideas as ways to think about the issue. Maybe the two documentation
blurbs above capture it in a better way.

Do you feel like you have a better understanding of what I'm trying to
do now?

> I do not agree with your "three commands" or "two semantics"
> characterization of the current way "git commit" works.  "git
> commit" without any optional argument already acts as if a
> sensible default arguments are given, that is "no funny business
> with additional paths, commit just what the user has staged
> already."

I agree that "git commit" does nothing funny by default. What I was
pointing out is that "git commit" and "git commit paths..." do not
have the same semantics. There's really nothing to debate about
there. There is no argument you can substitute for <paths...> to give
you identical behavior as "git commit". That's a fact.

> "git commit" is primarily about committing what has been staged
> in the index, and "--all" is just a type-saver short-hand (just
> like "--include" is) to perform update-index the last minute and
> nothing more.  In other words, "--all" is a variant of the
> pathname-less form "git commit".  It is not a variant of "git
> commit --only paths..." form, as you characterized.

I hope the documentation blurbs (1) and (2) above show how "commit -a"
can be seen as a variant of either "commit" or "commit files...",
(which themselves are both useful semantics, but demonstrably
distinct).

> The pathname form (the "--only" variant) on the surface seem to
> work differently, but when you think about it, it is not all
> that different from the normal commit.  We explain that it
> ignores index, but in the bigger picture, it does not really.

No, it really is different.

> the first commit does "jump" the changes already made to the
> index, but after it makes the commit, the index has the same
> contents as if you did "git update-index a b" where you ran that
> "git commit".  In other words, it is just a handy short-hand to
> pretend as if you did the above sequence in this order instead:

How could you document "git commit files..." as a shorthand? A
shorthand for what exactly? A shorthand for pretending you didn't just
type the commands you did type that got the index into its current
state, but had instead typed different commands before the commit and
other commands afterwards?

That's crazy. That's not a shorthand. That's just plain different
semantics. The current "git commit files..." command never does commit
the contents of "the" index as a concept presented by "git
commit". (This is independent of the fact that the implementation of
"git commit files..." certainly does use an index file somewhere and
uses it to create a commit object in the same way that "git commit"
uses "the" index).

> So I actually think it is a mistake to stress the fact that "git
> commit --only paths..." seems to act differently from the normal
> "git commit" too much.

I think that would be lying to the users and setting them up to get
confused later. I discussed this above as the confusion that can
result with the explanation of (1). If you teach "git commit" as
commiting "the" index, and de-emphasize that "git commit files..."
is semantically distinct, then how is a user ever supposed to learn
what it is that "git commit files..." is actually doing?

> In short, while I understand that your "proposal" shows your own
> way to summarize the semantics of "git commit", I am not seeing
> what it buys us, and I do not see the need to come up with a
> pair of new two commands for making commits (if that is what the
> proposal is about, that is, but it is not clear to me if that is
> what you are driving at).  I think it would only confuse users.

Forgive me again for being obtuse. I don't think we should necessarily
add two new commands. I was trying to illustrate a problem in the
existing command set, and propose a new way of thinking about the
tasks that the current commands help a user to perform, (committing
content from the working tree or committing content from the index). I
don't actually have a concrete proposal for how to take that way of
thinking and map it to a command set, (and one that would disrupt
current git users as little as possible). I'd love to have some help
with that part.

> Is it just me who finds the above a very much made-up example?

Fine. We can ignore that example.

> In any case, I should clarify my aversion to partial commits a
> bit.  What is more important is to notice that, while you cannot
> compile-and-run test what is in the index in isolation (without
> a fuse that exports the index contents as a virtual filesystem
> -- anybody interested?), you _can_ preview and verify the text
> that is going to be committed by comparing the index and the
> HEAD.  And for that, your "staging" action (i.e. Nico's "git
> add") needs to be a separate step from your "committing" action.

Yes, I often use the index as a place to preview things. And it is
true that I find myself using update-index when I could have used
"commit paths..." precisely because I can preview it once more. But I
do use the "commit paths..." form at times as well. If I have just
reviewed things in "git diff" and there are _really_ obviously
separable pieces I will commit them alone with staging into the index
and reviewing again.

It's probably the case that I skip the explicit staging and extra
preview when I can use a single pathname as the argument to "git
commit".

> In other words, I would even love Johannes's "per hunk commit"
> idea, at least if it had an option to preview the whole thing
> just one more time before committing, and I would love it better
> if it had an option for not committing but just updating.

Yes! I've wanted tools to help with per-hunk separation before, but
since I'm so likely to make mistakes while doing that I would only
want that to go into the index so that I could review it before
committing. I guess I might need a per-hunk way to fix up my mistakes
too if I put a hunk into the index that I didn't want to be there.

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[relevance 1%]

* globs in partial checkout?
  @ 2006-12-10 20:00  4% ` Michael S. Tsirkin
  2006-12-10 20:13  3%   ` Linus Torvalds
  0 siblings, 1 reply; 200+ results
From: Michael S. Tsirkin @ 2006-12-10 20:00 UTC (permalink / raw)
  To: Git Mailing List, Junio C Hamano

I'm trying to checkout some files after doing "clone -n".
Should using globs there work? It doesn't:

st@mst-lt:~/scm/wireless-dev$ git checkout master 'include/net/ieee80211*.h'
error: pathspec 'include/net/ieee80211*.h' did not match any file(s) known to
git.
Did you forget to 'git add'?
mst@mst-lt:~/scm/wireless-dev$ git ls-tree master -- include/net/ | grep iee
100644 blob b174ebb277a96668f058e469b0753503c34f164b include/net/ieee80211.h
100644 blob eb476414fd726701d032e9e517751b9d3f7e38df include/net/ieee80211_crypt.h
100644 blob 429b73892a5fc62f91e4a4b05da40859604fa791 include/net/ieee80211_radiotap.h
100644 blob 617b672b1132e7fa3ff5f9c940b1692520dc8483 include/net/ieee80211softmac.h
100644 blob 4ee3ad57283fa3370bd2d1f71cd6ae559b556dbc include/net/ieee80211softmac_wx.h
mst@mst-lt:~/scm/wireless-dev$ git checkout master include/net/ieee80211.h
include/net/ieee80211_crypt.h include/net/ieee80211_radiotap.h
include/net/ieee80211softmac.h include/net/ieee80211softmac_wx.h


-- 

^ permalink raw reply	[relevance 4%]

* Re: globs in partial checkout?
  2006-12-10 20:00  4% ` globs in partial checkout? Michael S. Tsirkin
@ 2006-12-10 20:13  3%   ` Linus Torvalds
  0 siblings, 0 replies; 200+ results
From: Linus Torvalds @ 2006-12-10 20:13 UTC (permalink / raw)
  To: Michael S. Tsirkin; +Cc: Git Mailing List, Junio C Hamano



On Sun, 10 Dec 2006, Michael S. Tsirkin wrote:
>
> I'm trying to checkout some files after doing "clone -n".
> Should using globs there work? It doesn't:

Not historically at all. "git checkout" needed exact filenames in older 
versions.

However, since about 1.4.4.1 or so, it now does the same filename 
expansion as "git add" etc does, which means that you can give it a 
directory name and it will check out everything under that directory, or 
you can give it a pattern, and it should glob it. But it sounds like you 
may have a slightly older version of git (the pathname matching really is 
fairly recent).


^ permalink raw reply	[relevance 3%]

* Re: [RFC] Submodules in GIT
  @ 2006-12-16  9:57  2%                 ` Jakub Narebski
  2006-12-16 15:05  2%                   ` Torgil Svensson
  0 siblings, 1 reply; 200+ results
From: Jakub Narebski @ 2006-12-16  9:57 UTC (permalink / raw)
  To: git

<opublikowany i wysłany>

Torgil Svensson wrote:

> On 12/16/06, Jakub Narebski <jnareb@gmail.com> wrote:

>>> Now it doesn't looks like trees/blobs anymore so maybe a link object
>>> is handy:
>>>  README
>>> 100644 blob <sha1 of blob>    REPORTING-BUGS
>>> 100644 link <sha1 of link>      AUTHORS
>>> 040000 tree <sha1 of tree>    arch
>>> 040000 tree <sha1 of tree>    block
>>> 040000 link <sha1 of link>     misc

This would be (using the submodule original proposal)

    140000 link <sha1 of link>     misc

>>> link-object:
>>> <sha1 of commit>
>>> <sha1 of tree/blob>
>>
>> What do you need <sha1 of tree/blob> for in link-object? Wouldn't you
>> use usually the sha1 of top tree of a commit, which is uniquely defined
>> by commit object, so you need only <sha1 of commit>?
>>
> 
> 1. "Sparse" repository's - In my example, I want to cherry-pick
> header-files or binary-files from different projects without fetching
> all, potentially huge, submodules in their entirety. Imaging having X,
> kernel, gcc, gtk and libc6 as sub-projects and you really only care
> about some header files.
> 
> 2. Super-module directory-hierarchy independent from submodules.
> Super-project want to have the header-files and binaries it's own way.
> This also gives version controlled file-collections, the "release
> case" in my example - collecting different binaries and header-files
> from different submodules together in a new directory-structure, add
> some documentation and configuration files and get the whole thing
> under strong version-control down to the beginning of time for each
> little component.

All fine, but this does not and I think cannot protect us from the
fact that we can have <sha1 of tree/blob> which doesn't match
<sha1 of commit>.

I think it would be better to have sparse/partial checkout first.
But that is just my idea. Because with <sha1 of tree/blob> which
is not sha1 of commit tree you might loose (I think) the ability
to merge, for example your changes to submodule with upstream.

> 3. Super-module development independent of submodules - If we have the
> tree/blob-object with all it contents in the database many
> git-operations can act as the link (commit) wasn't there since we have
> access to all relevant data to work with. This makes it easy to clone
> the super-project and work on it seamlessly without having to care
> about submodules or mapping up submodule repository's (unless you want
> to modify the links or the data underneath it of course).

This is I think irrelevant to the fact if we have only <sha1 of commit>,
or link object and also <sha1 of tree/blob>
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git


^ permalink raw reply	[relevance 2%]

* Re: [RFC] Submodules in GIT
  2006-12-16  9:57  2%                 ` Jakub Narebski
@ 2006-12-16 15:05  2%                   ` Torgil Svensson
  0 siblings, 0 replies; 200+ results
From: Torgil Svensson @ 2006-12-16 15:05 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: Josef Weidendorfer, R. Steve McKown, git, Linus Torvalds

On 12/16/06, Jakub Narebski <jnareb@gmail.com> wrote:
> All fine, but this does not and I think cannot protect us from the
> fact that we can have <sha1 of tree/blob> which doesn't match
> <sha1 of commit>.

True, that will be a real problem. Unless we have a bug in git, do you
see a scenario in which this is likely to happen?


> I think it would be better to have sparse/partial checkout first.
> But that is just my idea. Because with <sha1 of tree/blob> which
> is not sha1 of commit tree you might loose (I think) the ability
> to merge, for example your changes to submodule with upstream.

That's correct. I also want a sparse/partial checkout but I don't want
the full submodule path. I'm also perfectly fine (for my current
use-cases) with not being able to merge upstream unless we're tracking
the commit tree (here, we might not want to specify the tree SHA1).

I'm not trying to impose a technically fragile solution here [I don't
believe it is, but I'm not the most competent to say that either], I'm
trying to find solutions for my use cases and I had problems adapting
them to the current suggestion.


> > 3. Super-module development independent of submodules - If we have the
> > tree/blob-object with all it contents in the database many
> > git-operations can act as the link (commit) wasn't there since we have
> > access to all relevant data to work with. This makes it easy to clone
> > the super-project and work on it seamlessly without having to care
> > about submodules or mapping up submodule repository's (unless you want
> > to modify the links or the data underneath it of course).
>
> This is I think irrelevant to the fact if we have only <sha1 of commit>,
> or link object and also <sha1 of tree/blob>


^ permalink raw reply	[relevance 2%]

* Re: git-fetch fails with error code 128
  @ 2006-12-16 22:12  5%     ` Andy Parkins
  0 siblings, 0 replies; 200+ results
From: Andy Parkins @ 2006-12-16 22:12 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nicolas Pitre

On Friday 2006, December 15 21:55, Junio C Hamano wrote:

> Thanks --- very much appreciated.  When it comes to
> inter-repository object transfer, we take compatibility very
> seriously.

Okay.  Before I started bisecting I thought I'd do some other experiments.  
Having tested fetch from remote and a fetch from local and finding the same 
results, I've done all the tests locally.

So; here goes.  I've got these directories:

 linux-partial/   (this is every patch from v1.0.0 to v2.1.63)
 linux-full/      (this is every patch from v1.0.0 to v2.5.75)

linux-partial/ is the one I reported the original error on, later I confirmed 
that the same error happened with a local fetch from linux-full.  I cloned 
both of these.

 linux-partial-clone/  (made with git clone linux-partial linux-partial-clone)
 linux-full-clone/     (made with git clone linux-full linux-full-clone)

Tests:
 - A fetch from linux-full to linux-partial, this one failed with error 128
 - A fetch from linux-full-clone to linux-partial, this one failed with
   error 128
 - A fetch from linux-full to linux-partial-clone, this one succeeded
 - A fetch from linux-full-clone to linux-partial-clone, this one succeeded
   (unsurprisingly)

Next I ran git-prune in linux-partial.  The fetch then succeeded.  Bizarre.

So, the strange result is that it is a difference in the destination directory 
that is triggering the error, and whatever that fault is is fixed by 
git-cloning that destination repository, or git-pruning the destination.

Unfortunately I've now lost my test case, because the prune fixed it.  Bah.  
Oh well, this fault can be marked "on hold until I get it to fail again".



Andy

-- 
Dr Andrew Parkins, M Eng (Hons), AMIEE

^ permalink raw reply	[relevance 5%]

* Re: Subprojects tasks
  @ 2006-12-17 13:01  3%     ` Jakub Narebski
  2006-12-17 13:48  0%       ` Martin Waitz
  0 siblings, 1 reply; 200+ results
From: Jakub Narebski @ 2006-12-17 13:01 UTC (permalink / raw)
  To: Martin Waitz; +Cc: Josef Weidendorfer, git, Junio C Hamano

Martin Waitz wrote:
> On Sun, Dec 17, 2006 at 01:01:09AM +0100, Josef Weidendorfer wrote:

>> IMHO it simply is added flexibility to allow a checkout to be separate from
>> the .git/ directory, same as explicitly setting $GIT_DIR would do.
>> So this .gitlink file is on the one hand one kind of convenience for users
>> which want to keep their repository separate, yet do not want to specify
>> $GIT_DIR all the time in front of git commands.
>> The .gitlink file simply makes the linkage to the separate repository
>> persistent.
> 
> I can see the reason for wanting to use another object database,
> but HEAD and index should always be stored together with the
> checked out directory.  So perhaps we just need some smart way to
> search for the object database, but keep the .git directory.

Well, in the .gitlink proposal you could specify GIT_DIR for checkout,
or separately: GIT_OBJECT_DIRECTORY, GIT_INDEX_FILE, GIT_REFS_DIRECTORY
(does not exist yet), GIT_HEAD_FILE (does not exist yet, and I suppose
it wouldn't be easy to implement it). By the way, that's why I'm for
.gitlink name for the file, not .git -- this way .gitlink can "shadow"
what's in .git, for example specifying in a smart way where to search
(where to find) object database, but HEAD and index would be stored
together with the checked out directory in .git

By the way, I'm rather partial to supermodule following HEAD in submodule,
not specified branch. First, I think it is easier from implementation
point of view: you don't have to remember which branch supermodule should
take submodule commits from; and this cannot be fixed branch name like
'master'. For example 'maint' branch of supermodule could track 'maint'
branch of submodule, 'master' branch of supermodule track 'master'
branch of submodule, 'next' branch of supermodule tranck 'master' (!)
branch of submodule, 'pu' branch of supermodule track 'next' (!) branch
of submodule. 

Second, if you want to do some independent work on the module not related
to work on submodule you should really clone (clone -l -s) submodule
and work in separate checkout; the complaint that with tracking HEAD
you can check-in wrong version of submodule to supermodule commit
doesn't hold, because you still would have problem that _tree_
of supermodule would have wrong version of submodule. And moving to
using single defined branch of submodule brings multitude of other
problems: for example you might usually track 'master' version of
submodule, but for a short time need to track 'next' branch because
it has functionality you need; and another time you need to move
to 'maint' branch or even your own branch because 'master' version
breaks something in supermodule.

Hmmm... I wonder how planned allowing to checking out tags, non-head
branches (e.g. tracking/remote branches) and arbitrary commits but
forbidding committing when HEAD is not a refs/heads/ branch would
affect submodules / subprojects...

-- 
Jakub Narebski

^ permalink raw reply	[relevance 3%]

* Re: Subprojects tasks
  2006-12-17 13:01  3%     ` Jakub Narebski
@ 2006-12-17 13:48  0%       ` Martin Waitz
  0 siblings, 0 replies; 200+ results
From: Martin Waitz @ 2006-12-17 13:48 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: Josef Weidendorfer, git, Junio C Hamano

[-- Attachment #1: Type: text/plain, Size: 6154 bytes --]

hoi :)

On Sun, Dec 17, 2006 at 02:01:09PM +0100, Jakub Narebski wrote:
> Well, in the .gitlink proposal you could specify GIT_DIR for checkout,
> or separately: GIT_OBJECT_DIRECTORY, GIT_INDEX_FILE, GIT_REFS_DIRECTORY
> (does not exist yet), GIT_HEAD_FILE (does not exist yet, and I suppose
> it wouldn't be easy to implement it). By the way, that's why I'm for
> .gitlink name for the file, not .git -- this way .gitlink can "shadow"
> what's in .git, for example specifying in a smart way where to search
> (where to find) object database, but HEAD and index would be stored
> together with the checked out directory in .git

What about .git/link or something?
(Obviously without the capability to change GIT_DIR)

> By the way, I'm rather partial to supermodule following HEAD in submodule,
> not specified branch. First, I think it is easier from implementation
> point of view: you don't have to remember which branch supermodule should
> take submodule commits from; and this cannot be fixed branch name like
> 'master'. For example 'maint' branch of supermodule could track 'maint'
> branch of submodule, 'master' branch of supermodule track 'master'
> branch of submodule, 'next' branch of supermodule tranck 'master' (!)
> branch of submodule, 'pu' branch of supermodule track 'next' (!) branch
> of submodule. 

The version tracked by the supermodule is completely independent from
any branches you define in your submodule.
It is of course possible to use different versions of your submodule in
different branches of your supermodule.  But the supermodule does not
know the name of these branches.

In the setup you described a git-checkout in the supermodule would have
to switch to a different branch in the submodule, depending on the
branchname which would have to be stored in the supermodule.
This a lot more complex.

Your scenario can also be solved in this way:

	cd supermodule
	(cd sub && git-reset --hard origin/master)
	git add sub && git commit -m "track master of sub"
	git checkout next
	(cd sub && git-reset --hard origin/master)
	git add sub && git commit -m "track master of sub"
	git checkout pu
	(cd sub && git-reset --hard origin/next)
	git add sub && git commit -m "track next of sub"
	git checkout maint
	(cd sub && git-reset --hard origin/maint)
	git add sub && git commit -m "track maint of sub"

You only store a link to the commit of the current submodule version,
just like a normal ref.  The reference stored in the supermodule really
is equivalent to a normal ref, just that it is stored and updated
slightly different to a normal one.

So whenever you checkout a different version of the supermodule, the
submodule ref automatically gets the correct version.  In the example
above, when you checkout supermodules pu, your submodules branch will be
reset to its origin/next (to be more precise: to the commit which was at
the tip of origin/next at the time it was stored in the supermodule).

The fact that the reference to the current submodule commit does not
only exist in the supermodule tree but also as a physical ref in the
submodule is very similiar to normal files: you have one version stored
in the object database, one in the index and one as a real file in the
working directory (and this working file is the equivalent of the
submodule ref which is stored in submodule/.git/refs/whatever)

The reference in the submodule is just a way to be able to work on
the submodule.  Because well, refs are the kind of thing that is changed
by a commit.  And these submodule commits are exactly the kind of work
you want to store in the supermodule.  So the equivalent to a working
file is not the HEAD of the submodule, but the ref which gets all
changes which are intended for the supermodule.

The fact that the submodule repository still supports other branches has
nothing to do with submodule support.  These branches are totally
independent from the supermodule.

> Second, if you want to do some independent work on the module not related
> to work on submodule you should really clone (clone -l -s) submodule
> and work in separate checkout;

Yes.
But I really like the possibility to switch one module to a branch which
is not tracked by the parent, because it perhaps contains some debugging
code which is needed to debug some other submodule.  You can't move it
out because you need the common build infrastructure but you don't want
to branch the entire toplevel project because you don't want your
debugging changes to ever become visible at that level.

So by switching to a different branch you can effectivly say: this is
temporary, not meant for the superproject.
If you change your mind later you can always merge the submodule branch
back to master.

> the complaint that with tracking HEAD you can check-in wrong version
> of submodule to supermodule commit doesn't hold, because you still
> would have problem that _tree_ of supermodule would have wrong version
> of submodule.

Sorry, I don't understand you here.

> And moving to using single defined branch of submodule brings
> multitude of other problems: for example you might usually track
> 'master' version of submodule, but for a short time need to track
> 'next' branch because it has functionality you need; and another time
> you need to move to 'maint' branch or even your own branch because
> 'master' version breaks something in supermodule.

That is no problem.
The supermodule can track whatever _version_ it wants.  You can set
it to any version which is available in the repository, including all
those well known external branches.
But the supermodule itself does not know (and should not know) about
"maint" / "next" / whatever branch names in the submodule.

> Hmmm... I wonder how planned allowing to checking out tags, non-head
> branches (e.g. tracking/remote branches) and arbitrary commits but
> forbidding committing when HEAD is not a refs/heads/ branch would
> affect submodules / subprojects...

It only affects submodules if you really track HEAD directly.

-- 
Martin Waitz

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[relevance 0%]

* Draft v1.5.0 release notes
@ 2007-01-02  0:08  3% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2007-01-02  0:08 UTC (permalink / raw)
  To: git

The latest draft is kept as 'todo:v1.5.0.txt'.  Since I've
merged the shallow clone changes, I've added a few sentences for
the series as well.

--

GIT v1.5.0 Release Notes
========================

Old news
--------

This section is for people who are upgrading from ancient
versions of git.  Although all of the changes in this section
happened before the current v1.4.4 release, they are summarized
here in the v1.5.0 release notes for people who skipped earlier
versions.

In general, you should not have to worry about incompatibility,
and there is no need to perform "repository conversion" if you
are updating to v1.5.0.  However, some of the changes are
one-way street upgrades; once you use them your repository
can no longer be used with ancient git.

 - There is a configuration variable core.legacyheaders that
   changes the format of loose objects so that they are more
   efficient to pack and to send out of the repository over git
   native protocol, since v1.4.2.  However, this format cannot
   be read by git older than that version; people fetching from
   your repository using older clients over dumb transports
   (e.g. http) using older versions of git will also be
   affected.  This is not enabled by default.

 - Since v1.4.3, configuration repack.usedeltabaseoffset allows
   packfile to be created in more space efficient format, which
   cannot be read by git older than that version.  This is not
   enabled by default.

 - 'git pack-refs' appeared in v1.4.4; this command allows tags
   to be accessed much more efficiently than the traditional
   'one-file-per-tag' format.  Older git-native clients can
   still fetch from a repository that packed and pruned refs
   (the server side needs to run the up-to-date version of git),
   but older dumb transports cannot.  Packing of refs is done by
   an explicit user action, either by use of "git pack-refs
   --prune" command or by use of "git gc" command.

 - 'git -p' to paginate anything -- many commands do pagination
   by default on a tty.  Introduced between v1.4.1 and v1.4.2;
   this may surprise old timers.

 - 'git archive' superseded 'git tar' in v1.4.3;

 - 'git cvsserver' was new invention in v1.3.0;

 - 'git repo-config', 'git grep', 'git rebase' and 'gitk' were
   seriously enhanced during v1.4.0 timeperiod.

 - 'gitweb' became part of git.git during v1.4.0 timeperiod and
   seriously modified since then.

 - reflog is an v1.4.0 invention.  This alows you to name a
   revision that a branch used to be at (e.g. "git diff
   master@{yesterday} master" allows you to see changes since
   yesterday's tip of the branch).


Updates in v1.5.0 since v1.4.4 series
-------------------------------------

* Index manipulation

 - git-add is to add contents to the index (aka "staging area"
   for the next commit), whether the file the contents happen to
   be is an existing one or a newly created one.

 - git-add without any argument does not add everything
   anymore.  Use 'git-add .' instead.  Also you can add
   otherwise ignored files with an -f option.

 - git-add tries to be more friendly to users by offering an
   interactive mode.

 - git-commit <path> used to refuse to commit if <path> was
   different between HEAD and the index (i.e. update-index was
   used on it earlier).  This check was removed.

 - git-rm is much saner and safer.  It is used to remove paths
   from both the index file and the working tree, and makes sure
   you are not losing any local modification before doing so.

 - git-reset <tree> <paths>... can be used to revert index
   entries for selected paths.

 - git-update-index is much less visible.


* Repository layout and objects transfer

 - The data for origin repository is stored in the configuration
   file $GIT_DIR/config, not in $GIT_DIR/remotes/, for newly
   created clones.  The latter is still supported and there is
   no need to convert your existing repository if you are
   already comfortable with your workflow with the layout.

 - git-clone always uses what is known as "separate remote"
   layout for a newly created repository with a working tree;
   i.e. tracking branches in $GIT_DIR/refs/remotes/origin/ are
   used to track branches from the origin.  New branches that
   appear on the origin side after a clone is made are also
   tracked automatically.

 - git-branch and git-show-branch know remote tracking branches.

 - git-push can now be used to delete a remote branch or a tag.
   This requires the updated git on the remote side.

 - git-push more agressively keeps the transferred objects
   packed.  Earlier we recommended to monitor amount of loose
   objects and repack regularly, but you should repack when you
   accumulated too many small packs this way as well.  Updated
   git-count-objects helps you with this.


* Reflog

 - Reflog records the history of where the tip of each branch
   was at each moment.  This facility is enabled by default for
   repositories with working trees, and can be accessed with the
   "branch@{time}" and "branch@{Nth}" notation.

 - "git show-branch" learned showing the reflog data with the
   new --reflog option.

 - The commits referred to by reflog entries are now protected
   against pruning.  The new command "git reflog expire" can be
   used to truncate older reflog entries and entries that refer
   to commits that have been pruned away previously with older
   versions of git.

   Existing repositories that have been using reflog may get
   complaints from fsck-objects; please run "git reflog expire
   --all" first to remove reflog entries that refer to commits
   that are no longer in the repository before attempting to
   repack it.

 - git-branch knows how to rename branches and moves existing
   reflog data from the old branch to the new one.


* Packed refs

 - Repositories with hundreds of tags have been paying large
   overhead, both in storage and in runtime.  A new command,
   git-pack-refs, can be used to "pack" them in more efficient
   representation.

 - Clones and fetches over dumb transports are now aware of
   packed refs and can download from repositories that use
   them.


* Configuration

 - configuration related to colorize setting are consolidated
   under color.* namespace (older diff.color.*, status.color.*
   are still supported).


* Less external dependency

 - We no longer require the "merge" program from the RCS suite.
   All 3-way file-level merges are now done internally.

 - The original implementation of git-merge-recursive which was
   in Python has been removed; we have C implementation of it
   now.

 - git-shortlog is no longer a Perl script.  It no longer
   requires output piped from git-log; it can accept revision
   parameters directly on the command line.


* I18n

 - We have always encouraged the commit message to be encoded in
   UTF-8, but the users are allowed to use legacy encoding as
   appropriate for their projects.  This will continue to be the
   case.  However, a non UTF-8 commit encoding _must_ be
   explicitly set with i18n.commitencoding in the repository
   where a commit is made; otherwise git-commit-tree will
   complain if the log message does not look like a valid UTF-8
   string.

 - The value of i18n.commitencoding in the originating
   repository is recorded in the commit object on the "encoding"
   header, if it is not UTF-8.  git-log and friends notice this,
   and reencodes the message to the log output encoding when
   displaying, if they are different.  The log output encoding
   is determined by "git log --encoding=<encoding>",
   i18n.logoutputencoding configuration, or i18n.commitencoding
   configuration, in the decreasing order of preference, and
   defaults to UTF-8. 


* Foreign SCM interfaces

  - git-svn now requires the Perl SVN:: libraries, the
    command-line backend was too slow and limited.

  - the 'commit' command has been renamed to 'set-tree', and
    'dcommit' is the recommended replacement for day-to-day
    work.


* User support

 - Quite a lot of documentation updates.

 - Bash completion scripts have been updated heavily.

 - Better error messages for often used Porcelainish commands.


* Shallow clones

 - There is a partial support for 'shallow' repositories that
   keeps only recent history now.  A 'shallow clone' is created
   by specifying how deep that truncated history should be.

   Currently a shallow repository has number of limitations:

   - Cloning and fetching _from_ a shallow clone are not
     supported (nor tested -- so they might work by accident but
     they are not expected to).

   - Pushing from nor into a shallow clone are not expected to
     work.

   - Merging inside a shallow repository would work as long as a
     merge base is found in the recent history, but otherwise it
     will be like merging unrelated histories and may result in
     huge conflicts.

   but this would be more than adequate for people who want to
   look at near the tip of a big project with a deep history and
   send patches in e-mail format.

^ permalink raw reply	[relevance 3%]

* Re: An early draft of v1.5.0 release notes (3rd ed)
  @ 2007-01-10  7:58  6%   ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2007-01-10  7:58 UTC (permalink / raw)
  To: git

Instead of sending the full text, I'll send out the diff against
the one I sent out on the 27th last month.

 Highlights:

 * Introductory notes have been reworded heavily;

 * I intend to merge bare repository support and detached HEAD
   before v1.5.0, so a section each for them has been added;

 * Sliding mmap and shallow clone are also mentioned.

The full text is available as v1.5.0.txt in 'todo' branch.

--
 v1.5.0.txt |  180 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 149 insertions(+), 31 deletions(-)

diff --git a/v1.5.0.txt b/v1.5.0.txt
index 671c14b..9bbe825 100644
--- a/v1.5.0.txt
+++ b/v1.5.0.txt
@@ -1,37 +1,54 @@
-Major changes that are not news
--------------------------------
+GIT v1.5.0 Release Notes
+========================
 
-There were a handful big changes that happened before this major
-release.
+Old news
+--------
 
 This section is for people who are upgrading from ancient
-versions.  Some of them are one-way street upgrades -- once you
-use the feature your repository cannot be used with ancient git.
-
- - There is a new configuration variable core.legacyheaders that
-   changes the format of loose objects to more efficient to pack
-   and send out of the repository over git native protocol.
-   However, this format cannot be read by git older than v1.4.2;
-   people fetching from your repository using older clients over
-   dumb transports (e.g. http) will also be affected.  This is
-   not enabled by default.
-
- - Another configuration repack.usedeltabaseoffset further
-   allows packfile to be created in more space efficient format,
-   which cannot be read  by git older than v1.4.3.  This is not
-   enabled by default.
+versions of git.  Although all of the changes in this section
+happened before the current v1.4.4 release, they are summarized
+here in the v1.5.0 release notes for people who skipped earlier
+versions.
+
+In general, you should not have to worry about incompatibility,
+and there is no need to perform "repository conversion" if you
+are updating to v1.5.0.  However, some of the changes are
+one-way street upgrades; once you use them your repository
+can no longer be used with ancient git.
+
+ - There is a configuration variable core.legacyheaders that
+   changes the format of loose objects so that they are more
+   efficient to pack and to send out of the repository over git
+   native protocol, since v1.4.2.  However, loose objects
+   written in the new format cannot be read by git older than
+   that version; people fetching from your repository using
+   older clients over dumb transports (e.g. http) using older
+   versions of git will also be affected.
+
+ - Since v1.4.3, configuration repack.usedeltabaseoffset allows
+   packfile to be created in more space efficient format, which
+   cannot be read by git older than that version.
+
+The above two are not enabled by default and you explicitly have
+to ask for them, because these two features make repositories
+unreadable by older versions of git, and in v1.5.0 we still do
+not enable them by default for the same reason.  We will change
+this default probably 1 year after 1.4.2's release, when it is
+reasonable to expect everybody to have new enough version of
+git.
 
  - 'git pack-refs' appeared in v1.4.4; this command allows tags
    to be accessed much more efficiently than the traditional
-   'one-file-per-tag' format.  Older git-native client can fetch
-   from a repository that packed its tags, but older dumb
-   transports cannot.  This is done by an explicit user action,
-   either by use of "git pack-refs --prune" command or by use of
-   "git gc" command.
+   'one-file-per-tag' format.  Older git-native clients can
+   still fetch from a repository that packed and pruned refs
+   (the server side needs to run the up-to-date version of git),
+   but older dumb transports cannot.  Packing of refs is done by
+   an explicit user action, either by use of "git pack-refs
+   --prune" command or by use of "git gc" command.
 
  - 'git -p' to paginate anything -- many commands do pagination
    by default on a tty.  Introduced between v1.4.1 and v1.4.2;
-   this may surprise old timer users.
+   this may surprise old timers.
 
  - 'git archive' superseded 'git tar' in v1.4.3;
 
@@ -43,7 +60,10 @@ use the feature your repository cannot be used with ancient git.
  - 'gitweb' became part of git.git during v1.4.0 timeperiod and
    seriously modified since then.
 
- - reflog is an v1.4.0 invention.
+ - reflog is an v1.4.0 invention.  This allows you to name a
+   revision that a branch used to be at (e.g. "git diff
+   master@{yesterday} master" allows you to see changes since
+   yesterday's tip of the branch).
 
 
 Updates in v1.5.0 since v1.4.4 series
@@ -80,7 +100,9 @@ Updates in v1.5.0 since v1.4.4 series
 
  - The data for origin repository is stored in the configuration
    file $GIT_DIR/config, not in $GIT_DIR/remotes/, for newly
-   created clones (the latter is still supported).
+   created clones.  The latter is still supported and there is
+   no need to convert your existing repository if you are
+   already comfortable with your workflow with the layout.
 
  - git-clone always uses what is known as "separate remote"
    layout for a newly created repository with a working tree;
@@ -100,6 +122,26 @@ Updates in v1.5.0 since v1.4.4 series
    accumulated too many small packs this way as well.  Updated
    git-count-objects helps you with this.
 
+ - A new command, git-remote, can help you manage your remote
+   tracking branch definitions.
+
+
+* Bare repositories
+
+ - Certain commands change their behaviour in a bare repository
+   (i.e. a repository without associated working tree).  We use
+   a fairly conservative heuristic (if $GIT_DIR is ".git", or
+   ends with "/.git", the repository is not bare) to decide if a
+   repository is bare, but "core.bare" configuration variable
+   can be used to override the heuristic when it misidentifies
+   your repository.
+
+ - git-fetch used to complain updating the current branch but
+   this is now allowed for a bare repository.
+
+ - NEEDSWORK: We should disable Porcelain-ish commands that
+   require a working tree in a bare repository.
+
 
 * Reflog
 
@@ -118,15 +160,42 @@ Updates in v1.5.0 since v1.4.4 series
    versions of git.
 
    Existing repositories that have been using reflog may get
-   complaints from fsck-objects; please run "git reflog expire
-   --all" first to remove reflog entries that refer to commits
-   that are no longer in the repository before attempting to
-   repack it.
+   complaints from fsck-objects and may not be able to run
+   git-repack; please run "git reflog expire --all" first to
+   remove reflog entries that refer to commits that are no
+   longer in the repository when that happens.
 
  - git-branch knows how to rename branches and moves existing
    reflog data from the old branch to the new one.
 
 
+* Detached HEAD
+
+ - You can give non-branch to "git checkout" now.  This will
+   dissociate your HEAD from any of your branches.  A typical
+   use of this feature is to "look around".  E.g.
+
+	$ git checkout v2.6.16
+	... compile, test, etc.
+	$ git checkout v2.6.17
+	... compile, test, etc.
+
+ - After detaching your HEAD, you can go back to an existing
+   branch with usual "git checkout $branch".  Also you can
+   start a new branch using "git checkout -b $newbranch".
+
+ - You can even pull from other repositories, make merges and
+   commits while your HEAD is detached.  Also you can use "git
+   reset" to jump to arbitrary commit.
+
+   Going back to undetached state by "git checkout $branch" can
+   lose the current stat you arrived in these ways, and "git
+   checkout" refuses when the detached HEAD is not pointed by
+   any existing ref (an existing branch, a remote tracking
+   branch or a tag).  This safety can be overriden with "git
+   checout -f".
+
+
 * Packed refs
 
  - Repositories with hundreds of tags have been paying large
@@ -181,6 +250,24 @@ Updates in v1.5.0 since v1.4.4 series
    configuration, in the decreasing order of preference, and
    defaults to UTF-8. 
 
+ - Tools for e-mailed patch application now default to -u
+   behaviour; i.e. it always re-codes from the e-mailed encoding
+   to the encoding specified with i18n.commitencoding.  This
+   unfortunately forces projects that have happily using a
+   legacy encoding without setting i18n.commitencoding, but
+   taken with other improvement, please excuse us for this very
+   minor one-time inconvenience.
+
+
+* Foreign SCM interfaces
+
+  - git-svn now requires the Perl SVN:: libraries, the
+    command-line backend was too slow and limited.
+
+  - the 'commit' subcommand of git-svn has been renamed to
+    'set-tree', and 'dcommit' is the recommended replacement for
+    day-to-day work.
+
 
 * User support
 
@@ -191,4 +278,35 @@ Updates in v1.5.0 since v1.4.4 series
  - Better error messages for often used Porcelainish commands.
 
 
+* Sliding mmap
+
+ - We used to assume that we can mmap the whole packfile while
+   in use, but with a large project this consumes huge virtual
+   memory space and truly huge ones would not fit in the
+   userland address space on 32-bit platforms.  We now mmap huge
+   packfile in pieces to avoid this problem.
+
+
+* Shallow clones
+
+ - There is a partial support for 'shallow' repositories that
+   keeps only recent history now.  A 'shallow clone' is created
+   by specifying how deep that truncated history should be.
+
+   Currently a shallow repository has number of limitations:
+
+   - Cloning and fetching _from_ a shallow clone are not
+     supported (nor tested -- so they might work by accident but
+     they are not expected to).
+
+   - Pushing from nor into a shallow clone are not expected to
+     work.
+
+   - Merging inside a shallow repository would work as long as a
+     merge base is found in the recent history, but otherwise it
+     will be like merging unrelated histories and may result in
+     huge conflicts.
 
+   but this would be more than adequate for people who want to
+   look at near the tip of a big project with a deep history and
+   send patches in e-mail format.

^ permalink raw reply related	[relevance 6%]

* [PATCH] some doc updates
@ 2007-01-15  3:44  6% Nicolas Pitre
  0 siblings, 0 replies; 200+ results
From: Nicolas Pitre @ 2007-01-15  3:44 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

1) talk about "git merge" instead of "git pull ."

2) suggest "git repo-config" instead of directly editing config files

3) echo "URL: blah" > .git/remotes/foo is obsolete and should be
   "git repo-config remote.foo.url blah"

4) support for partial URL prefix has been removed (see commit
   ea560e6d64374ec1f6c163c276319a3da21a1345) so drop mention of it.

Signed-off-by: Nicolas Pitre <nico@cam.org>
---

diff --git a/Documentation/core-tutorial.txt b/Documentation/core-tutorial.txt
index 0cd33fb..51dd6c6 100644
--- a/Documentation/core-tutorial.txt
+++ b/Documentation/core-tutorial.txt
@@ -1129,46 +1129,26 @@ juggle multiple lines of development simultaneously. Of
 course, you will pay the price of more disk usage to hold
 multiple working trees, but disk space is cheap these days.
 
-[NOTE]
-You could even pull from your own repository by
-giving '.' as <remote-repository> parameter to `git pull`.  This
-is useful when you want to merge a local branch (or more, if you
-are making an Octopus) into the current branch.
-
 It is likely that you will be pulling from the same remote
 repository from time to time. As a short hand, you can store
-the remote repository URL in a file under .git/remotes/
-directory, like this:
-
-------------------------------------------------
-$ mkdir -p .git/remotes/
-$ cat >.git/remotes/linus <<\EOF
-URL: http://www.kernel.org/pub/scm/git/git.git/
-EOF
-------------------------------------------------
-
-and use the filename to `git pull` instead of the full URL.
-The URL specified in such file can even be a prefix
-of a full URL, like this:
+the remote repository URL in the local repository's config file
+like this:
 
 ------------------------------------------------
-$ cat >.git/remotes/jgarzik <<\EOF
-URL: http://www.kernel.org/pub/scm/linux/git/jgarzik/
-EOF
+$ git repo-config remote.linus.url http://www.kernel.org/pub/scm/git/git.git/
 ------------------------------------------------
 
+and use the "linus" keyword with `git pull` instead of the full URL.
 
 Examples.
 
 . `git pull linus`
 . `git pull linus tag v0.99.1`
-. `git pull jgarzik/netdev-2.6.git/ e100`
 
 the above are equivalent to:
 
 . `git pull http://www.kernel.org/pub/scm/git/git.git/ HEAD`
 . `git pull http://www.kernel.org/pub/scm/git/git.git/ tag v0.99.1`
-. `git pull http://www.kernel.org/pub/.../jgarzik/netdev-2.6.git e100`
 
 
 How does the merge work?
@@ -1546,7 +1526,8 @@ on that project and has an own "public repository" goes like this:
 
 1. Prepare your work repository, by `git clone` the public
    repository of the "project lead". The URL used for the
-   initial cloning is stored in `.git/remotes/origin`.
+   initial cloning is stored in the remote.origin.url
+   configuration variable.
 
 2. Prepare a public repository accessible to others, just like
    the "project lead" person does.
@@ -1586,14 +1567,15 @@ like this:
 1. Prepare your work repository, by `git clone` the public
    repository of the "project lead" (or a "subsystem
    maintainer", if you work on a subsystem). The URL used for
-   the initial cloning is stored in `.git/remotes/origin`.
+   the initial cloning is stored in the remote.origin.url
+   configuration variable.
 
 2. Do your work in your repository on 'master' branch.
 
 3. Run `git fetch origin` from the public repository of your
    upstream every once in a while. This does only the first
    half of `git pull` but does not merge. The head of the
-   public repository is stored in `.git/refs/heads/origin`.
+   public repository is stored in `.git/refs/remotes/origin/master`.
 
 4. Use `git cherry origin` to see which ones of your patches
    were accepted, and/or use `git rebase origin` to port your
@@ -1681,11 +1663,11 @@ $ git reset --hard master~2
 
 You can make sure 'git show-branch' matches the state before
 those two 'git merge' you just did.  Then, instead of running
-two 'git merge' commands in a row, you would pull these two
+two 'git merge' commands in a row, you would merge these two
 branch heads (this is known as 'making an Octopus'):
 
 ------------
-$ git pull . commit-fix diff-fix
+$ git merge commit-fix diff-fix
 $ git show-branch
 ! [commit-fix] Fix commit message normalization.
  ! [diff-fix] Fix rename detection.
@@ -1701,7 +1683,7 @@ $ git show-branch
 
 Note that you should not do Octopus because you can.  An octopus
 is a valid thing to do and often makes it easier to view the
-commit history if you are pulling more than two independent
+commit history if you are merging more than two independent
 changes at the same time.  However, if you have merge conflicts
 with any of the branches you are merging in and need to hand
 resolve, that is an indication that the development happened in
diff --git a/Documentation/everyday.txt b/Documentation/everyday.txt
index 4e83994..ca36a76 100644
--- a/Documentation/everyday.txt
+++ b/Documentation/everyday.txt
@@ -148,8 +148,7 @@ modification will be caught if you do `git commit -a` later.
 <8> redo the commit undone in the previous step, using the message
 you originally wrote.
 <9> switch to the master branch.
-<10> merge a topic branch into your master branch.  You can also use
-`git pull . alsa-audio`, i.e. pull from the local repository.
+<10> merge a topic branch into your master branch.
 <11> review commit logs; other forms to limit output can be
 combined and include `\--max-count=10` (show 10 commits),
 `\--until=2005-12-10`, etc.
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 13be992..a90b764 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -52,7 +52,8 @@ git pull origin next::
 
 git pull . fixes enhancements::
 	Bundle local branch `fixes` and `enhancements` on top of
-	the current branch, making an Octopus merge.
+	the current branch, making an Octopus merge.  This `git pull .`
+	syntax is equivalent to `git merge`.
 
 git pull -s ours . obsolete::
 	Merge local branch `obsolete` into the current branch,
diff --git a/Documentation/git-rerere.txt b/Documentation/git-rerere.txt
index b57a72b..08a0557 100644
--- a/Documentation/git-rerere.txt
+++ b/Documentation/git-rerere.txt
@@ -81,7 +81,7 @@ One way to do it is to pull master into the topic branch:
 
 ------------
 	$ git checkout topic
-	$ git pull . master
+	$ git merge master
 
               o---*---o---+ topic
              /           /
@@ -103,10 +103,10 @@ in which case the final commit graph would look like this:
 
 ------------
 	$ git checkout topic
-	$ git pull . master
+	$ git merge master
 	$ ... work on both topic and master branches
 	$ git checkout master
-	$ git pull . topic
+	$ git merge topic
 
               o---*---o---+---o---o topic
              /           /         \
@@ -126,11 +126,11 @@ top of the tip before the test merge:
 
 ------------
 	$ git checkout topic
-	$ git pull . master
+	$ git merge master
 	$ git reset --hard HEAD^ ;# rewind the test merge
 	$ ... work on both topic and master branches
 	$ git checkout master
-	$ git pull . topic
+	$ git merge topic
 
               o---*---o-------o---o topic
              /                     \
diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt
index d2bf0b9..8325c5e 100644
--- a/Documentation/tutorial.txt
+++ b/Documentation/tutorial.txt
@@ -11,15 +11,13 @@ diff" with:
 $ man git-diff
 ------------------------------------------------
 
-It is a good idea to introduce yourself to git before doing any
-operation.  The easiest way to do so is:
+It is a good idea to introduce yourself to git with your name and
+public email address before doing any operation.  The easiest
+way to do so is:
 
 ------------------------------------------------
-$ cat >~/.gitconfig <<\EOF
-[user]
-	name = Your Name Comes Here
-	email = you@yourdomain.example.com
-EOF
+$ git repo-config --global user.name "Your Name Comes Here"
+$ git repo-config --global user.email you@yourdomain.example.com
 ------------------------------------------------
 
 
@@ -211,7 +209,7 @@ at this point the two branches have diverged, with different changes
 made in each.  To merge the changes made in experimental into master, run
 
 ------------------------------------------------
-$ git pull . experimental
+$ git merge experimental
 ------------------------------------------------
 
 If the changes don't conflict, you're done.  If there are conflicts,
@@ -316,14 +314,14 @@ shows a list of all the changes that Bob made since he branched from
 Alice's master branch.
 
 After examining those changes, and possibly fixing things, Alice
-could pull the changes into her master branch:
+could merge the changes into her master branch:
 
 -------------------------------------
 $ git checkout master
-$ git pull . bob-incoming
+$ git merge bob-incoming
 -------------------------------------
 
-The last command is a pull from the "bob-incoming" branch in Alice's
+The last command is a merge from the "bob-incoming" branch in Alice's
 own repository.
 
 Alice could also perform both steps at once with:

^ permalink raw reply related	[relevance 6%]

* Re: Rebasing stgit stacks
  @ 2007-01-16 22:42  4%             ` Catalin Marinas
  2007-01-16 23:17  1%               ` Yann Dirson
  0 siblings, 1 reply; 200+ results
From: Catalin Marinas @ 2007-01-16 22:42 UTC (permalink / raw)
  To: Yann Dirson; +Cc: git, Guilhem Bonnefille

On 15/01/07, Yann Dirson <ydirson@altern.org> wrote:
> On Mon, Jan 15, 2007 at 10:46:37PM +0000, Catalin Marinas wrote:
> > >I have started work on implementing "stg pull --to <newbase>", but I'm
> > >facing some issues.
> >
> > I think the combination of 'pull' and '--to' is confusing (at least to
> > me) if you think of there English meaning.
>
> That's possible, I'm not a native english speater :)

I'm not either :-)

> The idea is that we pull our stack from one place (current base) to
> another.  Another possiblity would have been "stg rebase", but I'm not
> very keen on adding another command to do a very similar job.

Can you give a typical example of what <newbase> argument for --to is
and what you repository looks like? I just want make sure I correctly
understand the problem.

I see the 'pull' command as a way to fetch the latest remote changes
and merge them into the current branch (which would usually be a
fast-forward). This command was meant as a stgit-aware 'git pull'.

> > As Petr suggested at the OLS last year, I added the possibility to
> > configure the 'git pull' command so that people use whatever script
> > they like.
>
> Right.  Maybe different workflows should have this option set to
> different values in different repos ?  I'm merely trying to get the
> best default :)

But you want to replace the call to 'git pull' with 'git fetch'. I
think this is fine with my workflow but some people might actually
rely on calling 'git pull' (or cg-pull).

> > I was working on a set of patches (mainly picking from other
> > branches and minor modifications) and just committing them when
> > finishing. Further updates from kernel.org triggered full merges
> > with the base.
>
> But doing this means that you can end with a base that is not any more
> on the parent branch, but on a local merge, right ?  I'm not sure it
> is an easy thing to work with.

Yes, indeed, but this is probably the only way you can publish a
branch and still partially manage it with StGIT.

> On the StGIT front, we could have "stg clone" look at
> patches/<branch>/current or so, and then modify the
> remote.<name>.fetch entry accordingly.  Or do you think of any
> workflow that would break under this change ?

Currently, 'stg clone' just calls 'git clone' and initializes the
master branch. There is no patches/<branch>/current file as there is
no current patch.

> Even if we would not need it here, it would be good to have those 2
> parameters set when we can infer them.  That reminds me that "stg
> clone" does not appear to allow selecting a specific branch in the
> parent repo (which explains why the .merge parameter is not so
> crucially needed yet: we always clone the main branch).

I haven't looked at 'git clone' recently, can you select a specific branch?

-- 
Catalin

^ permalink raw reply	[relevance 4%]

* Re: Rebasing stgit stacks
  2007-01-16 22:42  4%             ` Catalin Marinas
@ 2007-01-16 23:17  1%               ` Yann Dirson
  0 siblings, 0 replies; 200+ results
From: Yann Dirson @ 2007-01-16 23:17 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: git, Guilhem Bonnefille

On Tue, Jan 16, 2007 at 10:42:17PM +0000, Catalin Marinas wrote:
> >The idea is that we pull our stack from one place (current base) to
> >another.  Another possiblity would have been "stg rebase", but I'm not
> >very keen on adding another command to do a very similar job.
> 
> Can you give a typical example of what <newbase> argument for --to is
> and what you repository looks like? I just want make sure I correctly
> understand the problem.

My example is quite similar to the one given by Guilhem: I had a git
branch coming from git-cvsimport, and my stgit stack forked atop that
branch.  At some point git-cvsimport fucked something, and I
regenerated a new mirror branch using it in a fresh repo.  Then I
wanted to rebase my stack on that new branch.


> I see the 'pull' command as a way to fetch the latest remote changes
> and merge them into the current branch (which would usually be a
> fast-forward). This command was meant as a stgit-aware 'git pull'.

Do you have an example of use where we would need a non-fast-forward
pull (supposing we have the "pull --to" functionality already, since I
shall find time to finish soon).


> >> As Petr suggested at the OLS last year, I added the possibility to
> >> configure the 'git pull' command so that people use whatever script
> >> they like.
> >
> >Right.  Maybe different workflows should have this option set to
> >different values in different repos ?  I'm merely trying to get the
> >best default :)
> 
> But you want to replace the call to 'git pull' with 'git fetch'. I
> think this is fine with my workflow but some people might actually
> rely on calling 'git pull' (or cg-pull).

Right, it may be possible (and I'd be interested in seeing such a
workflow).  Maybe we could keep support for git-pull as an
alternative.

This could be done, eg. by letting the user use "pullcmd=git-pull" and
introduce a new option like "fastforward=<bool>" triggering the
fast-forward needed after git-fetch, with the default being "true",
and the current behaviour being obtained by changing it to "false".

That would not add too much complexity, while setting the default to
what I believe to match the most common workflows, and allow anyone
relying on the current behaviour to get it back.


> >> I was working on a set of patches (mainly picking from other
> >> branches and minor modifications) and just committing them when
> >> finishing. Further updates from kernel.org triggered full merges
> >> with the base.
> >
> >But doing this means that you can end with a base that is not any more
> >on the parent branch, but on a local merge, right ?  I'm not sure it
> >is an easy thing to work with.
> 
> Yes, indeed, but this is probably the only way you can publish a
> branch and still partially manage it with StGIT.

Well, I'd think that automatic rebasing would be a more elegant
solution.

> >On the StGIT front, we could have "stg clone" look at
> >patches/<branch>/current or so, and then modify the
> >remote.<name>.fetch entry accordingly.  Or do you think of any
> >workflow that would break under this change ?
> 
> Currently, 'stg clone' just calls 'git clone' and initializes the
> master branch. There is no patches/<branch>/current file as there is
> no current patch.

I meant, the patches/<branch>/current in the remote repo.  If that one
exist, then we should pull it with "+" as we should do for any
rebasing remote branch.

> >Even if we would not need it here, it would be good to have those 2
> >parameters set when we can infer them.  That reminds me that "stg
> >clone" does not appear to allow selecting a specific branch in the
> >parent repo (which explains why the .merge parameter is not so
> >crucially needed yet: we always clone the main branch).
> 
> I haven't looked at 'git clone' recently, can you select a specific branch?

I had assumed so without looking, but it looks like you cannot select
much.  When using separate remotes, the HEAD in the clone is taken
from the HEAD in the remote, and bears the same name.  It is the only
ref created under heads/.

Would there be some missing functionnality in git-clone, or am I just
missing something obvious ?

Best regards,
-- 
Yann.

^ permalink raw reply	[relevance 1%]

* Re: [Announce] GIT v1.5.0-rc2
  @ 2007-01-21 11:20  2% ` Junio C Hamano
  2007-01-21 19:46  0%   ` Horst H. von Brand
  2007-01-22 18:08  1%   ` Carl Worth
  0 siblings, 2 replies; 200+ results
From: Junio C Hamano @ 2007-01-21 11:20 UTC (permalink / raw)
  To: git; +Cc: linux-kernel

BTW, as the upcoming v1.5.0 release will introduce quite a bit of
surface changes (although at the really core it still is the old
git and old ways should continue to work), I am wondering if it
would help people to try out and find wrinkles before the real
thing for me to cut a tarball and a set of RPM packages.

Comments?

Also, in the same spirit of giving the release an early
exposure, here is the current draft of 1.5.0 release notes.

-- >8 -- cut here -- >8 --

GIT v1.5.0 Release Notes (draft)
================================

Old news
--------

This section is for people who are upgrading from ancient
versions of git.  Although all of the changes in this section
happened before the current v1.4.4 release, they are summarized
here in the v1.5.0 release notes for people who skipped earlier
versions.

In general, you should not have to worry about incompatibility,
and there is no need to perform "repository conversion" if you
are updating to v1.5.0.  However, some of the changes are
one-way street upgrades; once you use them your repository
can no longer be used with ancient git.

 - There is a configuration variable core.legacyheaders that
   changes the format of loose objects so that they are more
   efficient to pack and to send out of the repository over git
   native protocol, since v1.4.2.  However, loose objects
   written in the new format cannot be read by git older than
   that version; people fetching from your repository using
   older clients over dumb transports (e.g. http) using older
   versions of git will also be affected.

 - Since v1.4.3, configuration repack.usedeltabaseoffset allows
   packfile to be created in more space efficient format, which
   cannot be read by git older than that version.

The above two are not enabled by default and you explicitly have
to ask for them, because these two features make repositories
unreadable by older versions of git, and in v1.5.0 we still do
not enable them by default for the same reason.  We will change
this default probably 1 year after 1.4.2's release, when it is
reasonable to expect everybody to have new enough version of
git.

 - 'git pack-refs' appeared in v1.4.4; this command allows tags
   to be accessed much more efficiently than the traditional
   'one-file-per-tag' format.  Older git-native clients can
   still fetch from a repository that packed and pruned refs
   (the server side needs to run the up-to-date version of git),
   but older dumb transports cannot.  Packing of refs is done by
   an explicit user action, either by use of "git pack-refs
   --prune" command or by use of "git gc" command.

 - 'git -p' to paginate anything -- many commands do pagination
   by default on a tty.  Introduced between v1.4.1 and v1.4.2;
   this may surprise old timers.

 - 'git archive' superseded 'git tar-tree' in v1.4.3;

 - 'git cvsserver' was new invention in v1.3.0;

 - 'git repo-config', 'git grep', 'git rebase' and 'gitk' were
   seriously enhanced during v1.4.0 timeperiod.

 - 'gitweb' became part of git.git during v1.4.0 timeperiod and
   seriously modified since then.

 - reflog is an v1.4.0 invention.  This allows you to name a
   revision that a branch used to be at (e.g. "git diff
   master@{yesterday} master" allows you to see changes since
   yesterday's tip of the branch).


Updates in v1.5.0 since v1.4.4 series
-------------------------------------

* Index manipulation

 - git-add is to add contents to the index (aka "staging area"
   for the next commit), whether the file the contents happen to
   be is an existing one or a newly created one.

 - git-add without any argument does not add everything
   anymore.  Use 'git-add .' instead.  Also you can add
   otherwise ignored files with an -f option.

 - git-add tries to be more friendly to users by offering an
   interactive mode.

 - git-commit <path> used to refuse to commit if <path> was
   different between HEAD and the index (i.e. update-index was
   used on it earlier).  This check was removed.

 - git-rm is much saner and safer.  It is used to remove paths
   from both the index file and the working tree, and makes sure
   you are not losing any local modification before doing so.

 - git-reset <tree> <paths>... can be used to revert index
   entries for selected paths.

 - git-update-index is much less visible.


* Repository layout and objects transfer

 - The data for origin repository is stored in the configuration
   file $GIT_DIR/config, not in $GIT_DIR/remotes/, for newly
   created clones.  The latter is still supported and there is
   no need to convert your existing repository if you are
   already comfortable with your workflow with the layout.

 - git-clone always uses what is known as "separate remote"
   layout for a newly created repository with a working tree;
   i.e. tracking branches in $GIT_DIR/refs/remotes/origin/ are
   used to track branches from the origin.  

 - New branches that appear on the origin side after a clone is
   made are also tracked automatically.  This is done with an
   wildcard refspec "refs/heads/*:refs/remotes/origin/*", which
   older git does not understand, so if you clone with 1.5.0,
   you would need to downgrade remote.*.fetch in the
   configuration file to specify each branch you are interested
   in individually if you plan to fetch into the repository with
   older versions of git (but why would you?).

 - git-branch and git-show-branch know remote tracking branches.

 - git-push can now be used to delete a remote branch or a tag.
   This requires the updated git on the remote side.

 - git-push more agressively keeps the transferred objects
   packed.  Earlier we recommended to monitor amount of loose
   objects and repack regularly, but you should repack when you
   accumulated too many small packs this way as well.  Updated
   git-count-objects helps you with this.

 - A new command, git-remote, can help you manage your remote
   tracking branch definitions.


* Bare repositories

 - Certain commands change their behaviour in a bare repository
   (i.e. a repository without associated working tree).  We use
   a fairly conservative heuristic (if $GIT_DIR is ".git", or
   ends with "/.git", the repository is not bare) to decide if a
   repository is bare, but "core.bare" configuration variable
   can be used to override the heuristic when it misidentifies
   your repository.

 - git-fetch used to complain updating the current branch but
   this is now allowed for a bare repository.  So is the use of
   'git-branch -f' to update the current branch.

 - Porcelain-ish commands that require a working tree refuses to
   work in a bare repository.


* Reflog

 - Reflog records the history of where the tip of each branch
   was at each moment.  This facility is enabled by default for
   repositories with working trees, and can be accessed with the
   "branch@{time}" and "branch@{Nth}" notation.

 - "git show-branch" learned showing the reflog data with the
   new --reflog option.  "git log" has --walk-reflogs option to
   view reflog entries in a more verbose manner.

 - git-branch knows how to rename branches and moves existing
   reflog data from the old branch to the new one.

 - The commits referred to by reflog entries are now protected
   against pruning.  The new command "git reflog expire" can be
   used to truncate older reflog entries and entries that refer
   to commits that have been pruned away previously with older
   versions of git.

   Existing repositories that have been using reflog may get
   complaints from fsck-objects and may not be able to run
   git-repack, if you had run git-prune from older git; please
   run "git reflog expire --stale-fix --all" first to remove
   reflog entries that refer to commits that are no longer in
   the repository when that happens.


* Crufts removal

 - We used to say "old commits are retrievable using reflog and
   'master@{yesterday}' syntax as long as you haven't run
   git-prune".  We no longer have to say the latter half of the
   above sentence, as git-prune does not remove things reachable
   from reflog entries.

 - 'git-prune' by default does not remove _everything_
   unreachable, as there is a one-day grace period built-in.

 - There is a toplevel garbage collector script, 'git-gc', that
   is an easy way to run 'git-repack -a -d', 'git-reflog gc',
   and 'git-prune'.


* Detached HEAD

 - You can give non-branch to "git checkout" now.  This will
   dissociate your HEAD from any of your branches.  A typical
   use of this feature is to "look around".  E.g.

	$ git checkout v2.6.16
	... compile, test, etc.
	$ git checkout v2.6.17
	... compile, test, etc.

 - After detaching your HEAD, you can go back to an existing
   branch with usual "git checkout $branch".  Also you can
   start a new branch using "git checkout -b $newbranch".

 - You can even pull from other repositories, make merges and
   commits while your HEAD is detached.  Also you can use "git
   reset" to jump to arbitrary commit.

   Going back to undetached state by "git checkout $branch" can
   lose the current stat you arrived in these ways, and "git
   checkout" refuses when the detached HEAD is not pointed by
   any existing ref (an existing branch, a remote tracking
   branch or a tag).  This safety can be overriden with "git
   checkout -f $branch".


* Packed refs

 - Repositories with hundreds of tags have been paying large
   overhead, both in storage and in runtime, due to the
   traditional one-ref-per-file format.  A new command,
   git-pack-refs, can be used to "pack" them in more efficient
   representation.

 - Clones and fetches over dumb transports are now aware of
   packed refs and can download from repositories that use
   them.


* Configuration

 - configuration related to color setting are consolidated under
   color.* namespace (older diff.color.*, status.color.* are
   still supported).


* Less external dependency

 - We no longer require the "merge" program from the RCS suite.
   All 3-way file-level merges are now done internally.

 - The original implementation of git-merge-recursive which was
   in Python has been removed; we have C implementation of it
   now.

 - git-shortlog is no longer a Perl script.  It no longer
   requires output piped from git-log; it can accept revision
   parameters directly on the command line.


* I18n

 - We have always encouraged the commit message to be encoded in
   UTF-8, but the users are allowed to use legacy encoding as
   appropriate for their projects.  This will continue to be the
   case.  However, a non UTF-8 commit encoding _must_ be
   explicitly set with i18n.commitencoding in the repository
   where a commit is made; otherwise git-commit-tree will
   complain if the log message does not look like a valid UTF-8
   string.

 - The value of i18n.commitencoding in the originating
   repository is recorded in the commit object on the "encoding"
   header, if it is not UTF-8.  git-log and friends notice this,
   and reencodes the message to the log output encoding when
   displaying, if they are different.  The log output encoding
   is determined by "git log --encoding=<encoding>",
   i18n.logoutputencoding configuration, or i18n.commitencoding
   configuration, in the decreasing order of preference, and
   defaults to UTF-8. 

 - Tools for e-mailed patch application now default to -u
   behaviour; i.e. it always re-codes from the e-mailed encoding
   to the encoding specified with i18n.commitencoding.  This
   unfortunately forces projects that have happily been using a
   legacy encoding without setting i18n.commitencoding to set
   the configuration, but taken with other improvement, please
   excuse us for this very minor one-time inconvenience.


* e-mailed patches

 - See the above I18n section.

 - git-format-patch now enables --binary without being asked.
   git-am does _not_ default to it, as sending binary patch via
   e-mail is unusual and is harder to review than textual
   patches and it is prudent to require the person who is
   applying the patch to explicitly ask for it.

 - The default suffix for git-format-patch output is now ".patch",
   not ".txt".  This can be changed with --suffix=.txt option,
   or "format.suffix = .txt" in the configuration.


* Foreign SCM interfaces

  - git-svn now requires the Perl SVN:: libraries, the
    command-line backend was too slow and limited.

  - the 'commit' subcommand of git-svn has been renamed to
    'set-tree', and 'dcommit' is the recommended replacement for
    day-to-day work.


* User support

 - Quite a lot of documentation updates.

 - Bash completion scripts have been updated heavily.

 - Better error messages for often used Porcelainish commands.


* Sliding mmap

 - We used to assume that we can mmap the whole packfile while
   in use, but with a large project this consumes huge virtual
   memory space and truly huge ones would not fit in the
   userland address space on 32-bit platforms.  We now mmap huge
   packfile in pieces to avoid this problem.


* Shallow clones

 - There is a partial support for 'shallow' repositories that
   keeps only recent history.  A 'shallow clone' is created by
   specifying how deep that truncated history should be.

   Currently a shallow repository has number of limitations:

   - Cloning and fetching _from_ a shallow clone are not
     supported (nor tested -- so they might work by accident but
     they are not expected to).

   - Pushing from nor into a shallow clone are not expected to
     work.

   - Merging inside a shallow repository would work as long as a
     merge base is found in the recent history, but otherwise it
     will be like merging unrelated histories and may result in
     huge conflicts.

   but this would be more than adequate for people who want to
   look at near the tip of a big project with a deep history and
   send patches in e-mail format.

^ permalink raw reply	[relevance 2%]

* Re: [Announce] GIT v1.5.0-rc2
  2007-01-21 11:20  2% ` Junio C Hamano
@ 2007-01-21 19:46  0%   ` Horst H. von Brand
  2007-01-22 18:08  1%   ` Carl Worth
  1 sibling, 0 replies; 200+ results
From: Horst H. von Brand @ 2007-01-21 19:46 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, linux-kernel

Junio C Hamano <junkio@cox.net> wrote:
> BTW, as the upcoming v1.5.0 release will introduce quite a bit of
> surface changes (although at the really core it still is the old
> git and old ways should continue to work), I am wondering if it
> would help people to try out and find wrinkles before the real
> thing for me to cut a tarball and a set of RPM packages.
> 
> Comments?
> 
> Also, in the same spirit of giving the release an early
> exposure, here is the current draft of 1.5.0 release notes.
> 
> -- >8 -- cut here -- >8 --
> 
> GIT v1.5.0 Release Notes (draft)
> ================================
> 
> Old news
> --------

[...]

>  - There is a configuration variable core.legacyheaders that
>    changes the format of loose objects so that they are more
>    efficient to pack and to send out of the repository over git
>    native protocol, since v1.4.2.  However, loose objects
>    written in the new format cannot be read by git older than
>    that version; people fetching from your repository using
>    older clients over dumb transports (e.g. http) using older
>    versions of git will also be affected.

Huh?

What are possible values of that variable? What happens if it is set/unset?
I'd suppose that if it is set, you get the old format, but that isn't clear.

>  - Since v1.4.3, configuration repack.usedeltabaseoffset allows
>    packfile to be created in more space efficient format, which
>    cannot be read by git older than that version.

Same as above.

> The above two are not enabled by default and you explicitly have
> to ask for them, because these two features make repositories
> unreadable by older versions of git, and in v1.5.0 we still do
> not enable them by default for the same reason.  We will change
> this default probably 1 year after 1.4.2's release, when it is
> reasonable to expect everybody to have new enough version of
> git.

I don't see an upgrade path here that doesn't involve keeping cruft "new
feature is on" variables around indefinitely... Why not just a repository
version?

[...]

> Updates in v1.5.0 since v1.4.4 series
> -------------------------------------
> 
> * Index manipulation

[...]

>  - git-add without any argument does not add everything
>    anymore.  Use 'git-add .' instead.  Also you can add
>    otherwise ignored files with an -f option.

I suppose "git add ." works for 'adding everything' only at the top?

>  - git-add tries to be more friendly to users by offering an
>    interactive mode.

Why not tell about "git add -i"?

[...]

> * Detached HEAD

[...]

>  - After detaching your HEAD, you can go back to an existing
>    branch with usual "git checkout $branch".  Also you can
>    start a new branch using "git checkout -b $newbranch".

Where is such a branch rooted?

>  - You can even pull from other repositories, make merges and
>    commits while your HEAD is detached.  Also you can use "git
>    reset" to jump to arbitrary commit.

Does this leave you on that branch, or still in limbo?

>    Going back to undetached state by "git checkout $branch" can

s/undetached/attached/

>    lose the current stat you arrived in these ways, and "git
>    checkout" refuses when the detached HEAD is not pointed by
>    any existing ref (an existing branch, a remote tracking
>    branch or a tag).  This safety can be overriden with "git
>    checkout -f $branch".

What happens if there are changes in the tracked files?

[...]

> * Shallow clones
> 
>  - There is a partial support for 'shallow' repositories that
>    keeps only recent history.  A 'shallow clone' is created by
>    specifying how deep that truncated history should be.

A bit of detail on how to specify shallowness would be nice here...


Very nice work, thanks!
-- 
Dr. Horst H. von Brand                   User #22616 counter.li.org
Departamento de Informatica                    Fono: +56 32 2654431
Universidad Tecnica Federico Santa Maria             +56 32 2654239
Casilla 110-V, Valparaiso, Chile               Fax:  +56 32 2797513

^ permalink raw reply	[relevance 0%]

* Re: [Announce] GIT v1.5.0-rc2
  2007-01-21 11:20  2% ` Junio C Hamano
  2007-01-21 19:46  0%   ` Horst H. von Brand
@ 2007-01-22 18:08  1%   ` Carl Worth
  1 sibling, 0 replies; 200+ results
From: Carl Worth @ 2007-01-22 18:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 4897 bytes --]

On Sun, 21 Jan 2007 03:20:06 -0800, Junio C Hamano wrote:
> Also, in the same spirit of giving the release an early
> exposure, here is the current draft of 1.5.0 release notes.

Thanks, these are very good and really show how much great progress
has gone into git recently. Congratulations to everyone who has helped
with this!

A few comments:

> In general, you should not have to worry about incompatibility,
> and there is no need to perform "repository conversion" if you
> are updating to v1.5.0.  However, some of the changes are
> one-way street upgrades; once you use them your repository
> can no longer be used with ancient git.

This "one-way street upgrades" sentence makes the upgrade to 1.5 sound
scarier than it really is. It's only after two more paragraphs of
fairly dense technical content that the reader is told that none of
this stuff is enabled by default yet.

Maybe replace the second sentence with something like:

	As of git v1.5.0 there are some optional changes to the
	repository that allow data to be stored and transferred more
	efficiently. These changes are not enabled by default as they
	will make the repository unusable with git versions before
	v1.4.2. Specifically the available options are:

or something along those lines.

>  - git-update-index is much less visible.

It's not clear what this sentence means. Perhaps add something like:

	, (many mentions of update-index in git output and
	documentation have now been replaced by simpler commands such
	as "git add" or "git rm").

>  - git-clone always uses what is known as "separate remote"
>    layout for a newly created repository with a working tree;
>    i.e. tracking branches in $GIT_DIR/refs/remotes/origin/ are
>    used to track branches from the origin.

This change has some workflow impact that is not at all obvious from
the above description. For example, after cloning git.git, things that
used to work like "git checkout -b my-next next" now no longer work,
(needing to use "origin/next" instead). And these branches also won't
appear in "git branch" output, (without the new -r option).

I think the release notes should spend a little more attention on an
issue like this. Maybe a separate section on changes to existing
interfaces, (as opposed to most of the other changes which are
improvements in the implementation of existing interfaces or just
plain new interfaces such as "git remote", "git gc", etc.)

If there is a new section, the previous paragraphs describing the move
of cloned origin information from .git/remotes/origin to .git/config
might belong there as well, (depending on whether you consider those
file contents a user-visible interface or not).

>  - git-branch and git-show-branch know remote tracking branches.

Should mention "-r" here.

>  - git-push can now be used to delete a remote branch or a tag.
>    This requires the updated git on the remote side.

What's the syntax for this? I know you don't want to turn the release
notes into a user manual, but it'd be nice to have brief mentions of
the new interfaces, (like the nice mention of "git add -i" for
example). Even with a quick skim through the git-push documentation,
I'm not immediately seeing how to delete a remote branch or tag.

>  - There is a toplevel garbage collector script, 'git-gc', that
>    is an easy way to run 'git-repack -a -d', 'git-reflog gc',
>    and 'git-prune'.

I think it's definitely worthwhile to note the fix of race conditions,
etc. here. It would be nice to have some short rule such as:

	"git gc" is free from any known race conditions with
	simultaneous git processes modifying the repository. So it's
	perfectly safe to run "git gc" from a cron job.

Or a similarly succinct rule that's actually true, (I think the recent
thread suggested "git gc" would only be safe with an extra
option---I'd much rather see it be safe by default and make the user
ask for extra unsafe pruning with an option).

>  - You can give non-branch to "git checkout" now.

Rather than "non-branch" I think it would be nice to say something
that mentioned tags. Maybe something like:

	You can now use 'git checkout' to checkout tags or any other
	revision, rather than just named branches."

>  - Repositories with hundreds of tags have been paying large
>    overhead, both in storage and in runtime, due to the
>    traditional one-ref-per-file format.  A new command,
>    git-pack-refs, can be used to "pack" them in more efficient
>    representation.

Is git-gc doing this housekeeping? If not, should it be? If so, should
it be mentioned here (and in the description of git-gc above)?

>  - There is a partial support for 'shallow' repositories that
>    keeps only recent history.  A 'shallow clone' is created by
>    specifying how deep that truncated history should be.

Here's another description that could definitely benefit from a very
short example command.

-Carl

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[relevance 1%]

* [PATCH] Hash name is SHA-1
  @ 2007-01-25 12:50  1% ` Horst H. von Brand
  0 siblings, 0 replies; 200+ results
From: Horst H. von Brand @ 2007-01-25 12:50 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Horst H. von Brand

From: Horst H. von Brand <vonbrand@inf.utfsm.cl> - unquoted

Signed-off-by: Horst H. von Brand <vonbrand@inf.utfsm.cl>
---
 Documentation/git-receive-pack.txt |   14 ++++++------
 Documentation/git-rev-parse.txt    |    8 +++---
 Documentation/git-show-branch.txt  |    4 +-
 Documentation/git-show-index.txt   |    2 +-
 Documentation/git-show-ref.txt     |    4 +-
 Documentation/git-svn.txt          |    6 ++--
 Documentation/git-tag.txt          |    2 +-
 Documentation/git-unpack-file.txt  |    2 +-
 Documentation/git-update-index.txt |   14 ++++++------
 Documentation/git-verify-pack.txt  |    4 +-
 Documentation/git-verify-tag.txt   |    2 +-
 Documentation/git.txt              |    4 +-
 Documentation/glossary.txt         |    8 +++---
 Documentation/pretty-formats.txt   |   16 +++++++-------
 Documentation/tutorial-2.txt       |   16 +++++++-------
 builtin-apply.c                    |   18 ++++++++++------
 builtin-blame.c                    |   20 ++++++++++++------
 builtin-cat-file.c                 |    5 ++-
 builtin-commit-tree.c              |    3 +-
 builtin-describe.c                 |    3 +-
 builtin-diff-tree.c                |    9 ++++---
 builtin-diff.c                     |    6 +++-
 builtin-for-each-ref.c             |    6 +++-
 builtin-init-db.c                  |    2 +-
 builtin-log.c                      |    5 ++-
 builtin-name-rev.c                 |    2 +-
 builtin-pack-objects.c             |   21 +++++++++++--------
 builtin-prune.c                    |    2 +-
 builtin-push.c                     |    4 ++-
 builtin-read-tree.c                |    6 ++++-
 builtin-reflog.c                   |    3 +-
 builtin-rev-list.c                 |    6 +++-
 builtin-rm.c                       |    8 ++++--
 builtin-shortlog.c                 |    2 +-
 builtin-show-branch.c              |   19 ++++++++++++-----
 builtin-show-ref.c                 |    8 +++++-
 builtin-unpack-objects.c           |    2 +-
 builtin-update-index.c             |   37 +++++++++++++++++++++++------------
 builtin-update-ref.c               |    4 +-
 builtin-write-tree.c               |    3 +-
 cache-tree.c                       |    9 +++++--
 cache.h                            |    2 +-
 combine-diff.c                     |    2 +-
 commit.c                           |    2 +-
 connect.c                          |    3 +-
 convert-objects.c                  |    6 ++--
 csum-file.c                        |    8 +++---
 csum-file.h                        |    2 +-
 diff-lib.c                         |    6 +++-
 diff.c                             |   35 ++++++++++++++++++++++-----------
 diffcore-break.c                   |    3 +-
 diffcore.h                         |    6 +++-
 fetch-pack.c                       |    3 +-
 fetch.h                            |    4 +-
 fsck-objects.c                     |    4 +-
 git-archimport.perl                |    4 +-
 git-merge-one-file.sh              |    6 ++--
 git-svn.perl                       |    6 ++--
 http-fetch.c                       |    8 ++++--
 http-push.c                        |    7 +++--
 index-pack.c                       |   22 ++++++++++----------
 merge-tree.c                       |    8 +++---
 mktag.c                            |    6 ++--
 mktree.c                           |    7 +++--
 object.c                           |    2 +-
 pack-check.c                       |    8 +++---
 patch-id.c                         |    2 +-
 read-cache.c                       |    6 ++--
 receive-pack.c                     |    2 +-
 refs.c                             |    2 +-
 setup.c                            |    2 +-
 sha1_file.c                        |   16 +++++++-------
 sha1_name.c                        |    2 +-
 upload-pack.c                      |    4 +-
 74 files changed, 303 insertions(+), 222 deletions(-)

diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt
index 10e8c46..2fafc79 100644
--- a/Documentation/git-receive-pack.txt
+++ b/Documentation/git-receive-pack.txt
@@ -20,7 +20,7 @@ The UI for the protocol is on the 'git-send-pack' side, and the
 program pair is meant to be used to push updates to remote
 repository.  For pull operations, see 'git-fetch-pack'.
 
-The command allows for creation and fast forwarding of sha1 refs
+The command allows for creation and fast forwarding of SHA-1 refs
 (heads/tags) on the remote end (strictly speaking, it is the
 local end receive-pack runs, but to the user who is sitting at
 the send-pack end, it is updating the remote.  Confused?)
@@ -30,12 +30,12 @@ and executable, it is called with three parameters:
 
        $GIT_DIR/hooks/update refname sha1-old sha1-new
 
-The refname parameter is relative to $GIT_DIR; e.g. for the
-master head this is "refs/heads/master".  Two sha1 are the
-object names for the refname before and after the update.  Note
-that the hook is called before the refname is updated, so either
-sha1-old is 0{40} (meaning there is no such ref yet), or it
-should match what is recorded in refname.
+The refname parameter is relative to $GIT_DIR; e.g. for the master
+head this is "refs/heads/master".  The two sha1 are the object names
+for the refname before and after the update.  Note that the hook is
+called before the refname is updated, so either sha1-old is 0{40}
+(meaning there is no such ref yet), or it should match what is
+recorded in refname.
 
 The hook should exit with non-zero status if it wants to
 disallow updating the named ref.  Otherwise it should exit with
diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index aeb37b6..9363257 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -59,7 +59,7 @@ OPTIONS
 	one.
 
 --symbolic::
-	Usually the object names are output in SHA1 form (with
+	Usually the object names are output in SHA-1 form (with
 	possible '{caret}' prefix); this option makes them output in a
 	form as close to the original input as possible.
 
@@ -90,7 +90,7 @@ OPTIONS
 	Show `$GIT_DIR` if defined else show the path to the .git directory.
 
 --short, --short=number::
-	Instead of outputting the full SHA1 values of object names try to
+	Instead of outputting the full SHA-1 values of object names try to
 	abbreviate them to a shorter unique name. When no length is specified
 	7 is used. The minimum length is 4.
 
@@ -110,12 +110,12 @@ SPECIFYING REVISIONS
 --------------------
 
 A revision parameter typically, but not necessarily, names a
-commit object.  They use what is called an 'extended SHA1'
+commit object.  They use what is called an 'extended SHA-1'
 syntax.  Here are various ways to spell object names.  The
 ones listed near the end of this list are to name trees and
 blobs contained in a commit.
 
-* The full SHA1 object name (40-byte hexadecimal string), or
+* The full SHA-1 object name (40-byte hexadecimal string), or
   a substring of such that is unique within the repository.
   E.g. dae86e1950b1277e545cee180551750029cfe735 and dae86e both
   name the same commit object if there are no other object in
diff --git a/Documentation/git-show-branch.txt b/Documentation/git-show-branch.txt
index 529f3a6..5807884 100644
--- a/Documentation/git-show-branch.txt
+++ b/Documentation/git-show-branch.txt
@@ -29,7 +29,7 @@ no <rev> nor <glob> is given on the command line.
 OPTIONS
 -------
 <rev>::
-	Arbitrary extended SHA1 expression (see `git-rev-parse`)
+	Arbitrary extended SHA-1 expression (see `git-rev-parse`)
 	that typically names a branch HEAD or a tag.
 
 <glob>::
@@ -119,7 +119,7 @@ displayed, indented N places.  If a commit is on the I-th
 branch, the I-th indentation character shows a `+` sign;
 otherwise it shows a space.  Merge commits are denoted by
 a `-` sign.  Each commit shows a short name that
-can be used as an extended SHA1 to name that commit.
+can be used as an extended SHA-1 to name that commit.
 
 The following example shows three branches, "master", "fixes"
 and "mhf":
diff --git a/Documentation/git-show-index.txt b/Documentation/git-show-index.txt
index be09b62..04f1d22 100644
--- a/Documentation/git-show-index.txt
+++ b/Documentation/git-show-index.txt
@@ -18,7 +18,7 @@ git-pack-objects command, and dumps its contents.
 
 The information it outputs is subset of what you can get from
 'git-verify-pack -v'; this command only shows the packfile
-offset and SHA1 of each object.
+offset and SHA-1 of each object.
 
 
 Author
diff --git a/Documentation/git-show-ref.txt b/Documentation/git-show-ref.txt
index 5973a82..85aa106 100644
--- a/Documentation/git-show-ref.txt
+++ b/Documentation/git-show-ref.txt
@@ -42,8 +42,8 @@ OPTIONS
 
 -s, --hash::
 
-	Only show the SHA1 hash, not the reference name. When also using
-	--dereference the dereferenced tag will still be shown after the SHA1.
+	Only show the SHA-1 hash, not the reference name. When also using
+	--dereference the dereferenced tag will still be shown after the SHA-1.
 
 --verify::
 
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index b95ff1d..b4aeb5b 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -82,7 +82,7 @@ manually joining branches on commit.
 
 	New features:
 
-	--show-commit        - shows the git commit sha1, as well
+	--show-commit        - shows the git commit SHA-1, as well
 	--oneline            - our version of --pretty=oneline
 
 	Any other arguments are passed directly to `git log'
@@ -191,7 +191,7 @@ This can allow you to make partial mirrors when running fetch.
 Only used with the 'set-tree' command.
 
 Read a list of commits from stdin and commit them in reverse
-order.  Only the leading sha1 is read from each line, so
+order.  Only the leading SHA-1 is read from each line, so
 git-rev-list --pretty=oneline output can be used.
 
 --rmdir::
@@ -450,7 +450,7 @@ This is for advanced users, most users should ignore this section.
 
 Unfetched SVN revisions may be imported as children of existing commits
 by specifying additional arguments to 'fetch'.  Additional parents may
-optionally be specified in the form of sha1 hex sums at the
+optionally be specified in the form of SHA-1 hex sums at the
 command-line.  Unfetched SVN revisions may also be tied to particular
 git commits with the following syntax:
 
diff --git a/Documentation/git-tag.txt b/Documentation/git-tag.txt
index 13c7aef..d3e01fe 100644
--- a/Documentation/git-tag.txt
+++ b/Documentation/git-tag.txt
@@ -25,7 +25,7 @@ creates a 'tag' object, and requires the tag message.  Unless
 `-m <msg>` is given, an editor is started for the user to type
 in the tag message.
 
-Otherwise just the SHA1 object name of the commit object is
+Otherwise just the SHA-1 object name of the commit object is
 written (i.e. a lightweight tag).
 
 A GnuPG signed tag object will be created when `-s` or `-u
diff --git a/Documentation/git-unpack-file.txt b/Documentation/git-unpack-file.txt
index 213dc81..c7b3be1 100644
--- a/Documentation/git-unpack-file.txt
+++ b/Documentation/git-unpack-file.txt
@@ -13,7 +13,7 @@ SYNOPSIS
 
 DESCRIPTION
 -----------
-Creates a file holding the contents of the blob specified by sha1. It
+Creates a file holding the contents of the blob specified by SHA-1. It
 returns the name of the temporary file in the following format:
 	.merge_file_XXXXX
 
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 5bbae42..9244460 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -129,7 +129,7 @@ OPTIONS
 
 Using --refresh
 ---------------
-'--refresh' does not calculate a new sha1 file or bring the index
+'--refresh' does not calculate a new SHA-1 file or bring the index
 up-to-date for mode/content changes. But what it *does* do is to
 "re-match" the stat information of a file with the index, so that you
 can refresh the index for a file that hasn't been changed but where
@@ -144,10 +144,10 @@ Using --cacheinfo or --info-only
 current working directory.  This is useful for minimum-checkout
 merging.
 
-To pretend you have a file with mode and sha1 at path, say:
+To pretend you have a file with mode and SHA-1 at path, say:
 
 ----------------
-$ git-update-index --cacheinfo mode sha1 path
+$ git-update-index --cacheinfo mode SHA-1 path
 ----------------
 
 '--info-only' is used to register files without placing them in the object
@@ -167,19 +167,19 @@ Using --index-info
 multiple entry definitions from the standard input, and designed
 specifically for scripts.  It can take inputs of three formats:
 
-    . mode         SP sha1          TAB path
+    . mode         SP SHA-1         TAB path
 +
 The first format is what "git-apply --index-info"
 reports, and used to reconstruct a partial tree
 that is used for phony merge base tree when falling
 back on 3-way merge.
 
-    . mode SP type SP sha1          TAB path
+    . mode SP type SP SHA-1         TAB path
 +
 The second format is to stuff git-ls-tree output
 into the index file.
 
-    . mode         SP sha1 SP stage TAB path
+    . mode         SP SHA-1 SP stage TAB path
 +
 This format is to put higher order stages into the
 index file and matches git-ls-files --stage output.
@@ -205,7 +205,7 @@ $ git update-index --index-info
 ------------
 
 The first line of the input feeds 0 as the mode to remove the
-path; the SHA1 does not matter as long as it is well formatted.
+path; the SHA-1 does not matter as long as it is well formatted.
 Then the second and third line feeds stage 1 and stage 2 entries
 for that path.  After the above, we would end up with this:
 
diff --git a/Documentation/git-verify-pack.txt b/Documentation/git-verify-pack.txt
index 7a6132b..8eb8226 100644
--- a/Documentation/git-verify-pack.txt
+++ b/Documentation/git-verify-pack.txt
@@ -32,11 +32,11 @@ OUTPUT FORMAT
 -------------
 When specifying the -v option the format used is:
 
-	SHA1 type size offset-in-packfile
+	SHA-1 type size offset-in-packfile
 
 for objects that are not deltified in the pack, and
 
-	SHA1 type size offset-in-packfile depth base-SHA1
+	SHA-1 type size offset-in-packfile depth base-SHA-1
 
 for objects that are deltified.
 
diff --git a/Documentation/git-verify-tag.txt b/Documentation/git-verify-tag.txt
index 0f9bdb5..d610a8b 100644
--- a/Documentation/git-verify-tag.txt
+++ b/Documentation/git-verify-tag.txt
@@ -16,7 +16,7 @@ Validates the gpg signature created by git-tag.
 OPTIONS
 -------
 <tag>::
-	SHA1 identifier of a git tag object.
+	SHA-1 identifier of a git tag object.
 
 Author
 ------
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 9761de3..f359cf1 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -272,7 +272,7 @@ git so take care if using Cogito etc.
 
 'GIT_OBJECT_DIRECTORY'::
 	If the object storage directory is specified via this
-	environment variable then the sha1 directories are created
+	environment variable then the SHA-1 directories are created
 	underneath - otherwise the default `$GIT_DIR/objects`
 	directory is used.
 
@@ -317,7 +317,7 @@ where:
 
 	<old|new>-file:: are files GIT_EXTERNAL_DIFF can use to read the
                          contents of <old|new>,
-	<old|new>-hex:: are the 40-hexdigit SHA1 hashes,
+	<old|new>-hex:: are the 40-hexdigit SHA-1 hashes,
 	<old|new>-mode:: are the octal representation of the file modes.
 
 +
diff --git a/Documentation/glossary.txt b/Documentation/glossary.txt
index d20eb62..9cf8b19 100644
--- a/Documentation/glossary.txt
+++ b/Documentation/glossary.txt
@@ -163,7 +163,7 @@ merge::
 
 object::
 	The unit of storage in git. It is uniquely identified by
-	the SHA1 of its contents. Consequently, an object can not
+	the SHA-1 of its contents. Consequently, an object can not
 	be changed.
 
 object database::
@@ -247,7 +247,7 @@ rebase::
 	changes from that branch.
 
 ref::
-	A 40-byte hex representation of a SHA1 or a name that denotes
+	A 40-byte hex representation of a SHA-1 or a name that denotes
 	a particular object. These may be stored in `$GIT_DIR/refs/`.
 
 refspec::
@@ -283,7 +283,7 @@ rewind::
 SCM::
 	Source code management (tool).
 
-SHA1::
+SHA-1::
 	Synonym for object name.
 
 shallow repository::
@@ -299,7 +299,7 @@ shallow repository::
 	history can be later deepened with gitlink:git-fetch[1].
 
 symref::
-	Symbolic reference: instead of containing the SHA1 id itself, it
+	Symbolic reference: instead of containing the SHA-1 id itself, it
 	is of the format 'ref: refs/some/thing' and when referenced, it
 	recursively dereferences to this reference. 'HEAD' is a prime
 	example of a symref. Symbolic references are manipulated with
diff --git a/Documentation/pretty-formats.txt b/Documentation/pretty-formats.txt
index fb0b0b9..563f935 100644
--- a/Documentation/pretty-formats.txt
+++ b/Documentation/pretty-formats.txt
@@ -5,7 +5,7 @@
 	If the commit is a merge, and if the pretty-format
         is not 'oneline', 'email' or 'raw', an additional line is
         inserted before the 'Author:' line.  This line begins with
-        "Merge: " and the sha1s of ancestral commits are printed,
+        "Merge: " and the SHA-1s of ancestral commits are printed,
         separated by spaces.  Note that the listed commits may not
         necessarily be the list of the *direct* parent commits if you
         have limited your view of history: for example, if you are
@@ -14,20 +14,20 @@
 
         * 'oneline'
 
-	  <sha1> <title line>
+	  <SHA-1> <title line>
 +
 This is designed to be as compact as possible.
 
         * 'short'
 
-	  commit <sha1>
+	  commit <SHA-1>
 	  Author: <author>
 
 	      <title line>
 
         * 'medium'
 
-	  commit <sha1>
+	  commit <SHA-1>
 	  Author: <author>
 	  Date: <date>
 
@@ -37,7 +37,7 @@ This is designed to be as compact as possible.
 
         * 'full'
 
-	  commit <sha1>
+	  commit <SHA-1>
 	  Author: <author>
 	  Commit: <committer>
 
@@ -47,7 +47,7 @@ This is designed to be as compact as possible.
 
         * 'fuller'
 
-	  commit <sha1>
+	  commit <SHA-1>
 	  Author: <author>
 	  AuthorDate: <date & time>
 	  Commit: <committer>
@@ -60,7 +60,7 @@ This is designed to be as compact as possible.
 
         * 'email'
 
-	  From <sha1> <date>
+	  From <SHA-1> <date>
 	  From: <author>
 	  Date: <date & time>
 	  Subject: [PATCH] <title line>
@@ -71,7 +71,7 @@ This is designed to be as compact as possible.
 	* 'raw'
 +
 The 'raw' format shows the entire commit exactly as
-stored in the commit object.  Notably, the SHA1s are
+stored in the commit object.  Notably, the SHA-1s are
 displayed in full, regardless of whether --abbrev or
 --no-abbrev are used, and 'parents' information show the
 true parent commits, without taking grafts nor history
diff --git a/Documentation/tutorial-2.txt b/Documentation/tutorial-2.txt
index f363d17..4b3f42d 100644
--- a/Documentation/tutorial-2.txt
+++ b/Documentation/tutorial-2.txt
@@ -33,14 +33,14 @@ What are the 40 digits of hex that git responded to the commit with?
 
 We saw in part one of the tutorial that commits have names like this.
 It turns out that every object in the git history is stored under
-such a 40-digit hex name.  That name is the SHA1 hash of the object's
+such a 40-digit hex name.  That name is the SHA-1 hash of the object's
 contents; among other things, this ensures that git will never store
-the same data twice (since identical data is given an identical SHA1
+the same data twice (since identical data is given an identical SHA-1
 name), and that the contents of a git object will never change (since
 that would change the object's name as well).
 
 It is expected that the content of the commit object you created while
-following the example above generates a different SHA1 hash than
+following the example above generates a different SHA-1 hash than
 the one shown above because the commit object records the time when
 it was created and the name of the person performing the commit.
 
@@ -64,14 +64,14 @@ A tree can refer to one or more "blob" objects, each corresponding to
 a file.  In addition, a tree can also refer to other tree objects,
 thus creating a directory hierarchy.  You can examine the contents of
 any tree using ls-tree (remember that a long enough initial portion
-of the SHA1 will also work):
+of the SHA-1 will also work):
 
 ------------------------------------------------
 $ git ls-tree 92b8b694
 100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad    file.txt
 ------------------------------------------------
 
-Thus we see that this tree has one file in it.  The SHA1 hash is a
+Thus we see that this tree has one file in it.  The SHA-1 hash is a
 reference to that file's data:
 
 ------------------------------------------------
@@ -90,7 +90,7 @@ Note that this is the old file data; so the object that git named in
 its response to the initial tree was a tree with a snapshot of the
 directory state that was recorded by the first commit.
 
-All of these objects are stored under their SHA1 names inside the git
+All of these objects are stored under their SHA-1 names inside the git
 directory:
 
 ------------------------------------------------
@@ -126,7 +126,7 @@ ref: refs/heads/master
 
 As you can see, this tells us which branch we're currently on, and it
 tells us this by naming a file under the .git directory, which itself
-contains a SHA1 name referring to a commit object, which we can
+contains a SHA-1 name referring to a commit object, which we can
 examine with cat-file:
 
 ------------------------------------------------
@@ -192,7 +192,7 @@ project's history:
 
 Note, by the way, that lots of commands take a tree as an argument.
 But as we can see above, a tree can be referred to in many different
-ways--by the SHA1 name for that tree, by the name of a commit that
+ways--by the SHA-1 name for that tree, by the name of a commit that
 refers to the tree, by the name of a branch whose head refers to that
 tree, etc.--and most such commands can accept any of these names.
 
diff --git a/builtin-apply.c b/builtin-apply.c
index 3fefdac..814f78f 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -1800,8 +1800,9 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
 	const char *name = patch->old_name ? patch->old_name : patch->new_name;
 	unsigned char sha1[20];
 
-	/* For safety, we require patch index line to contain
-	 * full 40-byte textual SHA1 for old and new, at least for now.
+	/* 
+	 * For safety, we require patch index line to contain
+	 * full 40-byte textual SHA-1 for old and new, at least for now.
 	 */
 	if (strlen(patch->old_sha1_prefix) != 40 ||
 	    strlen(patch->new_sha1_prefix) != 40 ||
@@ -1811,7 +1812,8 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
 			     "without full index line", name);
 
 	if (patch->old_name) {
-		/* See if the old one matches what the patch
+		/* 
+		 * See if the old one matches what the patch
 		 * applies to.
 		 */
 		hash_sha1_file(desc->buffer, desc->size, blob_type, sha1);
@@ -1850,7 +1852,8 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
 		desc->alloc = desc->size = size;
 	}
 	else {
-		/* We have verified desc matches the preimage;
+		/* 
+		 * We have verified desc matches the preimage;
 		 * apply the patch data to it, which is stored
 		 * in the patch->fragments->{patch,size}.
 		 */
@@ -2074,8 +2077,9 @@ static void show_index_list(struct patch *list)
 {
 	struct patch *patch;
 
-	/* Once we start supporting the reverse patch, it may be
-	 * worth showing the new sha1 prefix, but until then...
+	/*
+	 * Once we start supporting the reverse patch, it may be
+	 * worth showing the new SHA-1 prefix, but until then...
 	 */
 	for (patch = list; patch; patch = patch->next) {
 		const unsigned char *sha1_ptr;
@@ -2086,7 +2090,7 @@ static void show_index_list(struct patch *list)
 		if (0 < patch->is_new)
 			sha1_ptr = null_sha1;
 		else if (get_sha1(patch->old_sha1_prefix, sha1))
-			die("sha1 information is lacking or useless (%s).",
+			die("SHA-1 information is lacking or useless (%s).",
 			    name);
 		else
 			sha1_ptr = sha1;
diff --git a/builtin-blame.c b/builtin-blame.c
index 4a1accf..9120b08 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -19,7 +19,7 @@ static char blame_usage[] =
 "git-blame [-c] [-l] [-t] [-f] [-n] [-p] [-L n,m] [-S <revs-file>] [-M] [-C] [-C] [commit] [--] file\n"
 "  -c, --compatibility Use the same output mode as git-annotate (Default: off)\n"
 "  -b                  Show blank SHA-1 for boundary commits (Default: off)\n"
-"  -l, --long          Show long commit SHA1 (Default: off)\n"
+"  -l, --long          Show long commit SHA-1 (Default: off)\n"
 "  --root              Do not treat root commits as boundaries (Default: off)\n"
 "  -t, --time          Show raw timestamp (Default: off)\n"
 "  -f, --show-name     Show original filename (Default: auto)\n"
@@ -244,7 +244,8 @@ static struct origin *find_origin(struct scoreboard *sb,
 	const char *paths[2];
 
 	if (parent->util) {
-		/* This is a freestanding copy of origin and not
+		/* 
+		 * This is a freestanding copy of origin and not
 		 * refcounted.
 		 */
 		struct origin *cached = parent->util;
@@ -259,7 +260,8 @@ static struct origin *find_origin(struct scoreboard *sb,
 		parent->util = NULL;
 	}
 
-	/* See if the origin->path is different between parent
+	/* 
+	 * See if the origin->path is different between parent
 	 * and origin first.  Most of the time they are the
 	 * same and diff-tree is fairly efficient about this.
 	 */
@@ -278,7 +280,8 @@ static struct origin *find_origin(struct scoreboard *sb,
 		       "", &diff_opts);
 	diffcore_std(&diff_opts);
 
-	/* It is either one entry that says "modified", or "created",
+	/* 
+	 * It is either one entry that says "modified", or "created",
 	 * or nothing.
 	 */
 	if (!diff_queued_diff.nr) {
@@ -879,7 +882,8 @@ static int find_copy_in_parent(struct scoreboard *sb,
 	if (diff_setup_done(&diff_opts) < 0)
 		die("diff-setup");
 
-	/* Try "find copies harder" on new path if requested;
+	/* 
+	 * Try "find copies harder" on new path if requested;
 	 * we do not want to use diffcore_rename() actually to
 	 * match things up; find_copies_harder is set only to
 	 * force diff_tree_sha1() to feed all filepairs to diff_queue,
@@ -1205,7 +1209,8 @@ static void get_commit_info(struct commit *commit,
 	static char committer_buf[1024];
 	static char summary_buf[1024];
 
-	/* We've operated without save_commit_buffer, so
+	/* 
+	 * We've operated without save_commit_buffer, so
 	 * we now need to populate them for output.
 	 */
 	if (!commit->buffer) {
@@ -1863,7 +1868,8 @@ int cmd_blame(int argc, const char **argv, const char *prefix)
 		add_pending_object(&revs, &(sb.final->object), "HEAD");
 	}
 
-	/* If we have bottom, this will mark the ancestors of the
+	/* 
+	 * If we have bottom, this will mark the ancestors of the
 	 * bottom commits we would reach while traversing as
 	 * uninteresting.
 	 */
diff --git a/builtin-cat-file.c b/builtin-cat-file.c
index 6c16bfa..088cebf 100644
--- a/builtin-cat-file.c
+++ b/builtin-cat-file.c
@@ -66,7 +66,8 @@ static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long
 			/* end of header */
 			break;
 	}
-	/* At this point, we have copied out the header up to the end of
+	/* 
+	 * At this point, we have copied out the header up to the end of
 	 * the tagger line and cp points at one past \n.  It could be the
 	 * next header line after the tagger line, or it could be another
 	 * \n that marks the end of the headers.  We need to copy out the
@@ -86,7 +87,7 @@ int cmd_cat_file(int argc, const char **argv, const char *prefix)
 
 	git_config(git_default_config);
 	if (argc != 3)
-		usage("git-cat-file [-t|-s|-e|-p|<type>] <sha1>");
+		usage("git-cat-file [-t|-s|-e|-p|<type>] <SHA-1>");
 	if (get_sha1(argv[2], sha1))
 		die("Not a valid object name %s", argv[2]);
 
diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c
index 0651e59..8375395 100644
--- a/builtin-commit-tree.c
+++ b/builtin-commit-tree.c
@@ -63,7 +63,8 @@ static void check_valid(unsigned char *sha1, const char *expect)
 #define MAXPARENT (16)
 static unsigned char parent_sha1[MAXPARENT][20];
 
-static const char commit_tree_usage[] = "git-commit-tree <sha1> [-p <sha1>]* < changelog";
+static const char commit_tree_usage[] = 
+       "git-commit-tree <sha1> [-p <sha1>]* < changelog";
 
 static int new_parent(int idx)
 {
diff --git a/builtin-describe.c b/builtin-describe.c
index e7b8f95..e2f97d6 100644
--- a/builtin-describe.c
+++ b/builtin-describe.c
@@ -48,7 +48,8 @@ static int get_name(const char *path, const unsigned char *sha1, int flag, void
 	if (!commit)
 		return 0;
 	object = parse_object(sha1);
-	/* If --all, then any refs are used.
+	/* 
+	 * If --all, then any refs are used.
 	 * If --tags, then any tags are used.
 	 * Otherwise only annotated tags are used.
 	 */
diff --git a/builtin-diff-tree.c b/builtin-diff-tree.c
index 24cb2d7..339a1ff 100644
--- a/builtin-diff-tree.c
+++ b/builtin-diff-tree.c
@@ -53,10 +53,11 @@ static int diff_tree_stdin(char *line)
 }
 
 static const char diff_tree_usage[] =
-"git-diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] [--pretty] [-t] [-r] [--root] "
-"[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n"
-"  -r            diff recursively\n"
-"  --root        include the initial commit as diff against /dev/null\n"
+       "git-diff-tree [--stdin] [-m] [-c] [--cc] [-s] [-v] "
+       "[--pretty] [-t] [-r] [--root] "
+       "[<common diff options>] <tree-ish> [<tree-ish>] [<path>...]\n"
+       "  -r            diff recursively\n"
+       "  --root        include the initial commit as diff against /dev/null\n"
 COMMON_DIFF_OPTIONS_HELP;
 
 int cmd_diff_tree(int argc, const char **argv, const char *prefix)
diff --git a/builtin-diff.c b/builtin-diff.c
index a659020..c1a5f05 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -13,7 +13,8 @@
 #include "log-tree.h"
 #include "builtin.h"
 
-/* NEEDSWORK: struct object has place for name but we _do_
+/* 
+ * NEEDSWORK: struct object has place for name but we _do_
  * know mode when we extracted the blob out of a tree, which
  * we currently lose.
  */
@@ -164,7 +165,8 @@ static int builtin_diff_tree(struct rev_info *revs,
 	if (argc > 1)
 		usage(builtin_diff_usage);
 
-	/* We saw two trees, ent[0] and ent[1].
+	/* 
+	 * We saw two trees, ent[0] and ent[1].
 	 * if ent[1] is uninteresting, they are swapped
 	 */
 	if (ent[1].item->flags & UNINTERESTING)
diff --git a/builtin-for-each-ref.c b/builtin-for-each-ref.c
index af72a12..ddaa95c 100644
--- a/builtin-for-each-ref.c
+++ b/builtin-for-each-ref.c
@@ -579,7 +579,8 @@ static void populate_value(struct refinfo *ref)
 	 */
 	tagged = ((struct tag *)obj)->tagged->sha1;
 
-	/* NEEDSWORK: This derefs tag only once, which
+	/* 
+	 * NEEDSWORK: This derefs tag only once, which
 	 * is good to deal with chains of trust, but
 	 * is not consistent with what deref_tag() does
 	 * which peels the onion to the core.
@@ -645,7 +646,8 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f
 			return 0;
 	}
 
-	/* We do not open the object yet; sort may only need refname
+	/* 
+	 * We do not open the object yet; sort may only need refname
 	 * to do its job and the resulting list may yet to be pruned
 	 * by maxcount logic.
 	 */
diff --git a/builtin-init-db.c b/builtin-init-db.c
index 8e7540b..a169b4f 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -267,7 +267,7 @@ static const char init_db_usage[] =
 
 /*
  * If you want to, you can share the DB area with any number of branches.
- * That has advantages: you can save space by sharing all the SHA1 objects.
+ * That has advantages: you can save space by sharing all the SHA-1 objects.
  * On the other hand, it might just make lookup slower and messier. You
  * be the judge.  The default case is to have one DB per managed directory.
  */
diff --git a/builtin-log.c b/builtin-log.c
index 503cd1e..55d6a13 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -396,7 +396,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	/*
 	 * Parse the arguments before setup_revisions(), or something
 	 * like "git fmt-patch -o a123 HEAD^.." may fail; a123 is
-	 * possibly a valid SHA1.
+	 * possibly a valid SHA-1.
 	 */
 	for (i = 1, j = 1; i < argc; i++) {
 		if (!strcmp(argv[i], "--stdout"))
@@ -547,7 +547,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 		free(commit->buffer);
 		commit->buffer = NULL;
 
-		/* We put one extra blank line between formatted
+		/* 
+		 * We put one extra blank line between formatted
 		 * patches and this flag is used by log-tree code
 		 * to see if it needs to emit a LF before showing
 		 * the log; when using one file per patch, we do
diff --git a/builtin-name-rev.c b/builtin-name-rev.c
index b4f15cc..c46eaf1 100644
--- a/builtin-name-rev.c
+++ b/builtin-name-rev.c
@@ -165,7 +165,7 @@ int cmd_name_rev(int argc, const char **argv, const char *prefix)
 		}
 
 		if (get_sha1(*argv, sha1)) {
-			fprintf(stderr, "Could not get sha1 for %s. Skipping.\n",
+			fprintf(stderr, "Could not get SHA-1 for %s. Skipping.\n",
 					*argv);
 			continue;
 		}
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 3824ee3..35d6bee 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -91,14 +91,14 @@ static int object_ix_hashsz;
  * corresponding pack file where each object's data starts, but the entries
  * do not store the size of the compressed representation (uncompressed
  * size is easily available by examining the pack entry header).  It is
- * also rather expensive to find the sha1 for an object given its offset.
+ * also rather expensive to find the SHA-1 for an object given its offset.
  *
  * We build a hashtable of existing packs (pack_revindex), and keep reverse
  * index here -- pack index file is sorted by object name mapping to offset;
  * this pack_revindex[].revindex array is a list of offset/index_nr pairs
  * ordered by offset, so if you know the offset of an object, next offset
  * is where its packed representation ends and the index_nr can be used to
- * get the object sha1 from the main index.
+ * get the object SHA-1 from the main index.
  */
 struct revindex_entry {
 	unsigned int offset;
@@ -451,7 +451,7 @@ static unsigned long write_object(struct sha1file *f,
 		} else if (obj_type == OBJ_REF_DELTA) {
 			/*
 			 * Deltas with a base reference contain
-			 * an additional 20 bytes for the base sha1.
+			 * an additional 20 bytes for the base SHA-1.
 			 */
 			sha1write(f, entry->delta->sha1, 20);
 			hdrlen += 20;
@@ -590,7 +590,7 @@ static void write_index_file(void)
 	sha1write(f, array, 256 * 4);
 
 	/*
-	 * Write the actual SHA1 entries..
+	 * Write the actual SHA-1 entries..
 	 */
 	list = sorted_by_sha;
 	for (i = 0; i < nr_result; i++) {
@@ -752,7 +752,8 @@ static int pbase_tree_cache_ix_incr(int ix)
 
 static struct pbase_tree {
 	struct pbase_tree *next;
-	/* This is a phony "cache" entry; we are not
+	/* 
+	 * This is a phony "cache" entry; we are not
 	 * going to evict it nor find it through _get()
 	 * mechanism -- this is for the toplevel node that
 	 * would almost always change with any commit.
@@ -770,7 +771,8 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
 	int my_ix = pbase_tree_cache_ix(sha1);
 	int available_ix = -1;
 
-	/* pbase-tree-cache acts as a limited hashtable.
+	/* 
+	 * pbase-tree-cache acts as a limited hashtable.
 	 * your object will be found at your index or within a few
 	 * slots after that slot if it is cached.
 	 */
@@ -789,7 +791,8 @@ static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
 		my_ix = pbase_tree_cache_ix_incr(my_ix);
 	}
 
-	/* Did not find one.  Either we got a bogus request or
+	/* 
+	 * Did not find one.  Either we got a bogus request or
 	 * we need to read and perhaps cache.
 	 */
 	data = read_sha1_file(sha1, type, &size);
@@ -1477,13 +1480,13 @@ static void read_object_list_from_stdin(void)
 		}
 		if (line[0] == '-') {
 			if (get_sha1_hex(line+1, sha1))
-				die("expected edge sha1, got garbage:\n %s",
+				die("expected edge SHA-1, got garbage:\n %s",
 				    line);
 			add_preferred_base(sha1);
 			continue;
 		}
 		if (get_sha1_hex(line, sha1))
-			die("expected sha1, got garbage:\n %s", line);
+			die("expected SHA-1, got garbage:\n %s", line);
 
 		hash = name_hash(line+41);
 		add_preferred_base_object(line+41, hash);
diff --git a/builtin-prune.c b/builtin-prune.c
index 6f0ba0d..fbbf9e5 100644
--- a/builtin-prune.c
+++ b/builtin-prune.c
@@ -63,7 +63,7 @@ static int prune_dir(int i, char *path)
 			prune_object(path, de->d_name, sha1);
 			continue;
 		}
-		fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
+		fprintf(stderr, "bad SHA-1 file: %s/%s\n", path, de->d_name);
 	}
 	closedir(dir);
 	return 0;
diff --git a/builtin-push.c b/builtin-push.c
index 5f4d7d3..3a98474 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -8,7 +8,9 @@
 
 #define MAX_URI (16)
 
-static const char push_usage[] = "git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] [--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
+static const char push_usage[] = 
+	"git-push [--all] [--tags] [--receive-pack=<git-receive-pack>] "
+	"[--repo=all] [-f | --force] [-v] [<repository> <refspec>...]";
 
 static int all, tags, force, thin = 1, verbose;
 static const char *receivepack;
diff --git a/builtin-read-tree.c b/builtin-read-tree.c
index 8ba436d..db18a80 100644
--- a/builtin-read-tree.c
+++ b/builtin-read-tree.c
@@ -85,7 +85,11 @@ static void prime_cache_tree(void)
 
 }
 
-static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] <sha1> [<sha2> [<sha3>]])";
+static const char read_tree_usage[] = 
+       "git-read-tree (<sha> | "
+       "[[-m [--aggressive] | --reset | --prefix=<prefix>] "
+       "[-u | -i]] [--exclude-per-directory=<gitignore>] "
+       "<sha1> [<sha2> [<sha3>]])";
 
 static struct lock_file lock_file;
 
diff --git a/builtin-reflog.c b/builtin-reflog.c
index b443ed9..c24716b 100644
--- a/builtin-reflog.c
+++ b/builtin-reflog.c
@@ -249,7 +249,8 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
 		return error("not a ref '%s'", ref);
 
 	memset(&cb, 0, sizeof(cb));
-	/* we take the lock for the ref itself to prevent it from
+	/* 
+	 * We take the lock for the ref itself to prevent it from
 	 * getting updated.
 	 */
 	lock = lock_ref_sha1(ref + 5, sha1);
diff --git a/builtin-rev-list.c b/builtin-rev-list.c
index 1bb3a06..b23707b 100644
--- a/builtin-rev-list.c
+++ b/builtin-rev-list.c
@@ -75,7 +75,8 @@ static void show_commit(struct commit *commit)
 			printf(" %s", sha1_to_hex(o->sha1));
 			o->flags |= TMP_MARK;
 		}
-		/* TMP_MARK is a general purpose flag that can
+		/* 
+		 * TMP_MARK is a general purpose flag that can
 		 * be used locally, but the user should clean
 		 * things up after it is done with them.
 		 */
@@ -107,7 +108,8 @@ static void show_commit(struct commit *commit)
 
 static void show_object(struct object_array_entry *p)
 {
-	/* An object with name "foo\n0000000..." can be used to
+	/* 
+	 * An object with name "foo\n0000000..." can be used to
 	 * confuse downstream git-pack-objects very badly.
 	 */
 	const char *ep = strchr(p->name, '\n');
diff --git a/builtin-rm.c b/builtin-rm.c
index 00dbe39..78bd2f0 100644
--- a/builtin-rm.c
+++ b/builtin-rm.c
@@ -10,7 +10,7 @@
 #include "tree-walk.h"
 
 static const char builtin_rm_usage[] =
-"git-rm [-f] [-n] [-r] [--cached] [--] <file>...";
+       "git-rm [-f] [-n] [-r] [--cached] [--] <file>...";
 
 static struct {
 	int nr, alloc;
@@ -48,7 +48,8 @@ static int remove_file(const char *name)
 
 static int check_local_mod(unsigned char *head)
 {
-	/* items in list are already sorted in the cache order,
+	/* 
+	 * Items in list are already sorted in the cache order,
 	 * so we could do this a lot more efficiently by using
 	 * tree_desc based traversal if we wanted to, but I am
 	 * lazy, and who cares if removal of files is a tad
@@ -79,7 +80,8 @@ static int check_local_mod(unsigned char *head)
 			continue;
 		}
 		else if (S_ISDIR(st.st_mode)) {
-			/* if a file was removed and it is now a
+			/*
+			 * If a file was removed and it is now a
 			 * directory, that is the same as ENOENT as
 			 * far as git is concerned; we do not track
 			 * directories.
diff --git a/builtin-shortlog.c b/builtin-shortlog.c
index edb4042..19cf5b7 100644
--- a/builtin-shortlog.c
+++ b/builtin-shortlog.c
@@ -6,7 +6,7 @@
 #include "revision.h"
 
 static const char shortlog_usage[] =
-"git-shortlog [-n] [-s] [<commit-id>... ]";
+       "git-shortlog [-n] [-s] [<commit-id>... ]";
 
 static char *common_repo_prefix;
 
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index b54c410..91e0e81 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -4,9 +4,13 @@
 #include "builtin.h"
 
 static const char show_branch_usage[] =
-"git-show-branch [--sparse] [--current] [--all] [--remotes] [--topo-order] [--more=count | --list | --independent | --merge-base ] [--topics] [<refs>...] | --reflog[=n[,b]] <branch>";
+       "git-show-branch [--sparse] [--current] [--all] [--remotes] "
+       "[--topo-order] "
+       "[--more=count | --list | --independent | --merge-base ] "
+       "[--topics] [<refs>...] | --reflog[=n[,b]] <branch>";
 static const char show_branch_usage_reflog[] =
-"--reflog is incompatible with --all, --remotes, --independent or --merge-base";
+       "--reflog is incompatible with --all, --remotes, "
+       "--independent or --merge-base";
 
 static int default_num;
 static int default_alloc;
@@ -380,7 +384,8 @@ static int append_head_ref(const char *refname, const unsigned char *sha1, int f
 	int ofs = 11;
 	if (strncmp(refname, "refs/heads/", ofs))
 		return 0;
-	/* If both heads/foo and tags/foo exists, get_sha1 would
+	/* 
+	 * If both heads/foo and tags/foo exists, get_sha1 would
 	 * get confused.
 	 */
 	if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
@@ -394,7 +399,8 @@ static int append_remote_ref(const char *refname, const unsigned char *sha1, int
 	int ofs = 13;
 	if (strncmp(refname, "refs/remotes/", ofs))
 		return 0;
-	/* If both heads/foo and tags/foo exists, get_sha1 would
+	/* 
+	 * If both heads/foo and tags/foo exists, get_sha1 would
 	 * get confused.
 	 */
 	if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
@@ -422,7 +428,8 @@ static int count_slash(const char *s)
 
 static int append_matching_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
-	/* we want to allow pattern hold/<asterisk> to show all
+	/* 
+	 * We want to allow pattern hold/<asterisk> to show all
 	 * branches under refs/heads/hold/, and v0.99.9? to show
 	 * refs/tags/v0.99.9a and friends.
 	 */
@@ -528,7 +535,7 @@ static void append_one_rev(const char *av)
 			sort_ref_range(saved_matches, ref_name_cnt);
 		return;
 	}
-	die("bad sha1 reference %s", av);
+	die("bad SHA-1 reference %s", av);
 }
 
 static int git_show_branch_config(const char *var, const char *value)
diff --git a/builtin-show-ref.c b/builtin-show-ref.c
index 853f13f..d7b9d8d 100644
--- a/builtin-show-ref.c
+++ b/builtin-show-ref.c
@@ -4,7 +4,10 @@
 #include "tag.h"
 #include "path-list.h"
 
-static const char show_ref_usage[] = "git show-ref [-q|--quiet] [--verify] [-h|--head] [-d|--dereference] [-s|--hash[=<length>]] [--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*] < ref-list";
+static const char show_ref_usage[] = 
+	"git show-ref [-q|--quiet] [--verify] [-h|--head] "
+	"[-d|--dereference] [-s|--hash[=<length>]] "
+	"[--abbrev[=<length>]] [--tags] [--heads] [--] [pattern*] < ref-list";
 
 static int deref_tags = 0, show_head = 0, tags_only = 0, heads_only = 0,
 	found_match = 0, verify = 0, quiet = 0, hash_only = 0, abbrev = 0;
@@ -56,7 +59,8 @@ static int show_ref(const char *refname, const unsigned char *sha1, int flag, vo
 match:
 	found_match++;
 
-	/* This changes the semantics slightly that even under quiet we
+	/* 
+	 * This changes the semantics slightly that even under quiet we
 	 * detect and return error if the repository is corrupt and
 	 * ref points at a nonexistent object.
 	 */
diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c
index d351e02..9a47437 100644
--- a/builtin-unpack-objects.c
+++ b/builtin-unpack-objects.c
@@ -395,7 +395,7 @@ int cmd_unpack_objects(int argc, const char **argv, const char *prefix)
 	SHA1_Update(&ctx, buffer, offset);
 	SHA1_Final(sha1, &ctx);
 	if (hashcmp(fill(20), sha1))
-		die("final sha1 did not match");
+		die("final SHA-1 did not match");
 	use(20);
 
 	/* Write the last part of the buffer to stdout */
diff --git a/builtin-update-index.c b/builtin-update-index.c
index 182331d..10ed20b 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -111,7 +111,8 @@ static int add_file_to_cache(const char *path)
 
 	ce->ce_mode = create_ce_mode(st.st_mode);
 	if (!trust_executable_bit) {
-		/* If there is an existing entry, pick the mode bits
+		/* 
+		 * If there is an existing entry, pick the mode bits
 		 * from it, otherwise assume unexecutable.
 		 */
 		int pos = cache_name_pos(path, namelen);
@@ -228,19 +229,20 @@ static void read_index_info(int line_termination)
 		unsigned int mode;
 		int stage;
 
-		/* This reads lines formatted in one of three formats:
+		/* 
+		 * This reads lines formatted in one of three formats:
 		 *
-		 * (1) mode         SP sha1          TAB path
+		 * (1) mode         SP SHA-1          TAB path
 		 * The first format is what "git-apply --index-info"
 		 * reports, and used to reconstruct a partial tree
 		 * that is used for phony merge base tree when falling
 		 * back on 3-way merge.
 		 *
-		 * (2) mode SP type SP sha1          TAB path
+		 * (2) mode SP type SP SHA-1          TAB path
 		 * The second format is to stuff git-ls-tree output
 		 * into the index file.
 		 *
-		 * (3) mode         SP sha1 SP stage TAB path
+		 * (3) mode         SP SHA-1 SP stage TAB path
 		 * This format is to put higher order stages into the
 		 * index file and matches git-ls-files --stage output.
 		 */
@@ -289,9 +291,10 @@ static void read_index_info(int line_termination)
 				    ptr);
 		}
 		else {
-			/* mode ' ' sha1 '\t' name
+			/* 
+			 * mode ' ' SHA-1 '\t' name
 			 * ptr[-1] points at tab,
-			 * ptr[-41] is at the beginning of sha1
+			 * ptr[-41] is at the beginning of SHA-1
 			 */
 			ptr[-42] = ptr[-1] = 0;
 			if (add_cacheinfo(mode, sha1, path_name, stage))
@@ -308,7 +311,11 @@ static void read_index_info(int line_termination)
 }
 
 static const char update_index_usage[] =
-"git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
+        "git-update-index [-q] [--add] [--replace] [--remove] "
+	"[--unmerged] [--refresh] [--really-refresh] [--cacheinfo] "
+	"[--chmod=(+|-)x] [--assume-unchanged] [--info-only] "
+	"[--force-remove] [--stdin] [--index-info] [--unresolve] "
+	"[--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
 
 static unsigned char head_sha1[20];
 static unsigned char merge_head_sha1[20];
@@ -369,7 +376,8 @@ static int unresolve_one(const char *path)
 		}
 	}
 
-	/* Grab blobs from given path from HEAD and MERGE_HEAD,
+	/* 
+	 * Grab blobs from given path from HEAD and MERGE_HEAD,
 	 * stuff HEAD version in stage #2,
 	 * stuff MERGE_HEAD version in stage #3.
 	 */
@@ -438,7 +446,8 @@ static int do_unresolve(int ac, const char **av,
 static int do_reupdate(int ac, const char **av,
 		       const char *prefix, int prefix_length)
 {
-	/* Read HEAD and run update-index on paths that are
+	/* 
+	 * Read HEAD and run update-index on paths that are
 	 * merged and already different between index and HEAD.
 	 */
 	int pos;
@@ -446,7 +455,8 @@ static int do_reupdate(int ac, const char **av,
 	const char **pathspec = get_pathspec(prefix, av + 1);
 
 	if (read_ref("HEAD", head_sha1))
-		/* If there is no HEAD, that means it is an initial
+		/* 
+		 * If there is no HEAD, that means it is an initial
 		 * commit.  Update everything in the index.
 		 */
 		has_head = 0;
@@ -466,7 +476,8 @@ static int do_reupdate(int ac, const char **av,
 			free(old);
 			continue; /* unchanged */
 		}
-		/* Be careful.  The working tree may not have the
+		/* 
+		 * Be careful.  The working tree may not have the
 		 * path anymore, in which case, under 'allow_remove',
 		 * or worse yet 'allow_replace', active_nr may decrease.
 		 */
@@ -540,7 +551,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 				unsigned int mode;
 
 				if (i+3 >= argc)
-					die("git-update-index: --cacheinfo <mode> <sha1> <path>");
+					die("git-update-index: --cacheinfo <mode> <SHA-1> <path>");
 
 				if ((sscanf(argv[i+1], "%o", &mode) != 1) ||
 				    get_sha1_hex(argv[i+2], sha1) ||
diff --git a/builtin-update-ref.c b/builtin-update-ref.c
index b34e598..ebd2a91 100644
--- a/builtin-update-ref.c
+++ b/builtin-update-ref.c
@@ -48,7 +48,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
 		usage(git_update_ref_usage);
 
 	if (get_sha1(value, sha1))
-		die("%s: not a valid SHA1", value);
+		die("%s: not a valid SHA-1", value);
 
 	if (delete) {
 		if (oldval)
@@ -58,7 +58,7 @@ int cmd_update_ref(int argc, const char **argv, const char *prefix)
 
 	hashclr(oldsha1);
 	if (oldval && *oldval && get_sha1(oldval, oldsha1))
-		die("%s: not a valid old SHA1", oldval);
+		die("%s: not a valid old SHA-1", oldval);
 
 	lock = lock_any_ref_for_update(refname, oldval ? oldsha1 : NULL);
 	if (!lock)
diff --git a/builtin-write-tree.c b/builtin-write-tree.c
index 50670dc..7e58045 100644
--- a/builtin-write-tree.c
+++ b/builtin-write-tree.c
@@ -39,7 +39,8 @@ int write_tree(unsigned char *sha1, int missing_ok, const char *prefix)
 					&& !close(newfd))
 				commit_lock_file(lock_file);
 		}
-		/* Not being able to write is fine -- we are only interested
+		/*
+		 * Not being able to write is fine -- we are only interested
 		 * in updating the cache-tree part, and if the next caller
 		 * ends up using the old index with unupdated cache-tree part
 		 * it misses the work we did here, but that is just a
diff --git a/cache-tree.c b/cache-tree.c
index 9b73c86..91da11d 100644
--- a/cache-tree.c
+++ b/cache-tree.c
@@ -167,13 +167,15 @@ static int verify_cache(struct cache_entry **cache,
 	if (funny)
 		return -1;
 
-	/* Also verify that the cache does not have path and path/file
+	/* 
+	 * Also verify that the cache does not have path and path/file
 	 * at the same time.  At this point we know the cache has only
 	 * stage 0 entries.
 	 */
 	funny = 0;
 	for (i = 0; i < entries - 1; i++) {
-		/* path/file always comes after path because of the way
+		/* 
+		 * path/file always comes after path because of the way
 		 * the cache is sorted.  Also path can appear only once,
 		 * which means conflicting one would immediately follow.
 		 */
@@ -387,7 +389,8 @@ static void *write_one(struct cache_tree *it,
 {
 	int i;
 
-	/* One "cache-tree" entry consists of the following:
+	/*
+	 * One "cache-tree" entry consists of the following:
 	 * path (NUL terminated)
 	 * entry_count, subtree_nr ("%d %d\n")
 	 * tree-sha1 (missing if invalid)
diff --git a/cache.h b/cache.h
index 473197d..fd2a659 100644
--- a/cache.h
+++ b/cache.h
@@ -214,7 +214,7 @@ extern int check_repository_format(void);
 #define DATA_CHANGED    0x0020
 #define TYPE_CHANGED    0x0040
 
-/* Return a statically allocated filename matching the sha1 signature */
+/* Return a statically allocated filename matching the SHA-1 signature */
 extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 extern char *sha1_file_name(const unsigned char *sha1);
diff --git a/combine-diff.c b/combine-diff.c
index 29d0c9c..8ddee2f 100644
--- a/combine-diff.c
+++ b/combine-diff.c
@@ -835,7 +835,7 @@ static void show_raw_diff(struct combine_diff_path *p, int num_parent, struct re
 		}
 		printf("%s%06o", prefix, p->mode);
 
-		/* Show sha1's */
+		/* Show SHA-1's */
 		for (i = 0; i < num_parent; i++)
 			printf(" %s", diff_unique_abbrev(p->parent[i].sha1,
 							 opt->abbrev));
diff --git a/commit.c b/commit.c
index 9b2b842..14b05a1 100644
--- a/commit.c
+++ b/commit.c
@@ -292,7 +292,7 @@ int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
 	item->tree = lookup_tree(parent);
 	if (item->tree)
 		n_refs++;
-	bufptr += 46; /* "tree " + "hex sha1" + "\n" */
+	bufptr += 46; /* "tree " + "hex SHA-1" + "\n" */
 	pptr = &item->parents;
 
 	graft = lookup_commit_graft(item->object.sha1);
diff --git a/connect.c b/connect.c
index 7844888..51598f0 100644
--- a/connect.c
+++ b/connect.c
@@ -263,7 +263,8 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
 		case 1:
 			break;
 		case 0:
-			/* The source could be in the get_sha1() format
+			/*
+			 * The source could be in the get_sha1() format
 			 * not a reference name.  :refs/other is a
 			 * way to delete 'other' ref at the remote end.
 			 */
diff --git a/convert-objects.c b/convert-objects.c
index a630132..1e02ffe 100644
--- a/convert-objects.c
+++ b/convert-objects.c
@@ -238,13 +238,13 @@ static void convert_date(void *buffer, unsigned long size, unsigned char *result
 	char *new = xmalloc(size + 100);
 	unsigned long newlen = 0;
 
-	/* "tree <sha1>\n" */
+	/* "tree <SHA-1>\n" */
 	memcpy(new + newlen, buffer, 46);
 	newlen += 46;
 	buffer = (char *) buffer + 46;
 	size -= 46;
 
-	/* "parent <sha1>\n" */
+	/* "parent <SHA-1>\n" */
 	while (!memcmp(buffer, "parent ", 7)) {
 		memcpy(new + newlen, buffer, 48);
 		newlen += 48;
@@ -273,7 +273,7 @@ static void convert_commit(void *buffer, unsigned long size, unsigned char *resu
 	if (memcmp(buffer, "tree ", 5))
 		die("Bad commit '%s'", (char*) buffer);
 	convert_ascii_sha1((char *) buffer + 5);
-	buffer = (char *) buffer + 46;    /* "tree " + "hex sha1" + "\n" */
+	buffer = (char *) buffer + 46;    /* "tree " + "hex SHA-1" + "\n" */
 	while (!memcmp(buffer, "parent ", 7)) {
 		convert_ascii_sha1((char *) buffer + 7);
 		buffer = (char *) buffer + 48;
diff --git a/csum-file.c b/csum-file.c
index b7174c6..a3fbecd 100644
--- a/csum-file.c
+++ b/csum-file.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2005 Linus Torvalds
  *
- * Simple file write infrastructure for writing SHA1-summed
+ * Simple file write infrastructure for writing SHA-1-summed
  * files. Useful when you write a file that you want to be
  * able to verify hasn't been messed with afterwards.
  */
@@ -24,8 +24,8 @@ static void sha1flush(struct sha1file *f, unsigned int count)
 			return;
 		}
 		if (!ret)
-			die("sha1 file '%s' write error. Out of diskspace", f->name);
-		die("sha1 file '%s' write error (%s)", f->name, strerror(errno));
+			die("SHA-1 file '%s' write error. Out of diskspace", f->name);
+		die("SHA-1 file '%s' write error (%s)", f->name, strerror(errno));
 	}
 }
 
@@ -42,7 +42,7 @@ int sha1close(struct sha1file *f, unsigned char *result, int update)
 	if (update)
 		sha1flush(f, 20);
 	if (close(f->fd))
-		die("%s: sha1 file error on close (%s)", f->name, strerror(errno));
+		die("%s: SHA-1 file error on close (%s)", f->name, strerror(errno));
 	free(f);
 	return 0;
 }
diff --git a/csum-file.h b/csum-file.h
index 3ad1a99..4f2b7ec 100644
--- a/csum-file.h
+++ b/csum-file.h
@@ -1,7 +1,7 @@
 #ifndef CSUM_FILE_H
 #define CSUM_FILE_H
 
-/* A SHA1-protected file */
+/* A SHA-1-protected file */
 struct sha1file {
 	int fd, error;
 	unsigned int offset, namelen;
diff --git a/diff-lib.c b/diff-lib.c
index 2c9be60..8877649 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -188,7 +188,8 @@ static void show_new_file(struct rev_info *revs,
 	unsigned char *sha1;
 	unsigned int mode;
 
-	/* New file in the index: it might actually be different in
+	/* 
+         * New file in the index: it might actually be different in
 	 * the working copy.
 	 */
 	if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0)
@@ -283,7 +284,8 @@ static int diff_cache(struct rev_info *revs,
 						     ce->sha1, ce->ce_mode);
 				break;
 			}
-			/* We come here with ce pointing at stage 1
+			/* 
+			 * We come here with ce pointing at stage 1
 			 * (original tree) and ac[1] pointing at stage
 			 * 3 (unmerged).  show-modified with
 			 * report-missing set to false does not say the
diff --git a/diff.c b/diff.c
index ad476f7..745bbc9 100644
--- a/diff.c
+++ b/diff.c
@@ -1196,7 +1196,8 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
 	struct stat st;
 	int pos, len;
 
-	/* We do not read the cache ourselves here, because the
+	/* 
+	 * We do not read the cache ourselves here, because the
 	 * benchmark with my previous version that always reads cache
 	 * shows that it makes things worse for diff-tree comparing
 	 * two linux-2.6 kernel trees in an already checked out work
@@ -1211,7 +1212,8 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
 	if (!active_cache)
 		return 0;
 
-	/* We want to avoid the working directory if our caller
+	/* 
+	 * We want to avoid the working directory if our caller
 	 * doesn't need the data in a normal file, this system
 	 * is rather slow with its stat/open/mmap/close syscalls,
 	 * and the object is contained in a pack file.  The pack
@@ -1233,7 +1235,8 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
 	    ce_match_stat(ce, &st, 0) ||
 	    hashcmp(sha1, ce->sha1))
 		return 0;
-	/* we return 1 only when we can stat, it is a regular file,
+	/* 
+	 * We return 1 only when we can stat, it is a regular file,
 	 * stat information matches, and sha1 recorded in the cache
 	 * matches.  I.e. we know the file in the work tree really is
 	 * the same as the <name, sha1> pair.
@@ -1442,7 +1445,8 @@ static void prepare_temp_file(const char *name,
 				strcpy(temp->hex, sha1_to_hex(null_sha1));
 			else
 				strcpy(temp->hex, sha1_to_hex(one->sha1));
-			/* Even though we may sometimes borrow the
+			/* 
+			 * Even though we may sometimes borrow the
 			 * contents from the work tree, we always want
 			 * one->mode.  mode is trustworthy even when
 			 * !(one->sha1_valid), as long as
@@ -1498,7 +1502,8 @@ static int spawn_prog(const char *pgm, const char **arg)
 		return -1;
 	}
 
-	/* Earlier we did not check the exit status because
+	/* 
+	 * Earlier we did not check the exit status because
 	 * diff exits non-zero if files are different, and
 	 * we are not interested in knowing that.  It was a
 	 * mistake which made it harder to quit a diff-*
@@ -1512,7 +1517,8 @@ static int spawn_prog(const char *pgm, const char **arg)
 	return -1;
 }
 
-/* An external diff command takes:
+/* 
+ * An external diff command takes:
  *
  * diff-cmd name infile1 infile1-sha1 infile1-mode \
  *               infile2 infile2-sha1 infile2-mode [ rename-to ]
@@ -2204,7 +2210,8 @@ static void diff_flush_name(struct diff_filepair *p, int line_termination)
 
 int diff_unmodified_pair(struct diff_filepair *p)
 {
-	/* This function is written stricter than necessary to support
+	/* 
+	 * This function is written stricter than necessary to support
 	 * the currently implemented transformers, but the idea is to
 	 * let transformers to produce diff_filepairs any way they want,
 	 * and filter and clean them up here before producing the output.
@@ -2217,7 +2224,8 @@ int diff_unmodified_pair(struct diff_filepair *p)
 	one = p->one;
 	two = p->two;
 
-	/* deletion, addition, mode or type change
+	/*
+	 * deletion, addition, mode or type change
 	 * and rename are all interesting.
 	 */
 	if (DIFF_FILE_VALID(one) != DIFF_FILE_VALID(two) ||
@@ -2225,7 +2233,8 @@ int diff_unmodified_pair(struct diff_filepair *p)
 	    strcmp(one->path, two->path))
 		return 0;
 
-	/* both are valid and point at the same path.  that is, we are
+	/* 
+	 * both are valid and point at the same path.  that is, we are
 	 * dealing with a change.
 	 */
 	if (one->sha1_valid && two->sha1_valid &&
@@ -2372,7 +2381,8 @@ static void diff_resolve_rename_copy(void)
 			 p->one->mode != p->two->mode)
 			p->status = DIFF_STATUS_MODIFIED;
 		else {
-			/* This is a "no-change" entry and should not
+			/* 
+			 * This is a "no-change" entry and should not
 			 * happen anymore, but prepare for broken callers.
 			 */
 			error("feeding unmodified %s to diffcore",
@@ -2510,7 +2520,7 @@ static void patch_id_consume(void *priv, char *line, unsigned long len)
 	struct patch_id_t *data = priv;
 	int new_len;
 
-	/* Ignore line numbers when computing the SHA1 of the patch */
+	/* Ignore line numbers when computing the SHA-1 of the patch */
 	if (!strncmp(line, "@@ -", 4))
 		return;
 
@@ -2818,7 +2828,8 @@ void diff_addremove(struct diff_options *options,
 	char concatpath[PATH_MAX];
 	struct diff_filespec *one, *two;
 
-	/* This may look odd, but it is a preparation for
+	/*
+	 * This may look odd, but it is a preparation for
 	 * feeding "there are unchanged files which should
 	 * not produce diffs, but when you are doing copy
 	 * detection you would need them, so here they are"
diff --git a/diffcore-break.c b/diffcore-break.c
index acb18db..eacc9d0 100644
--- a/diffcore-break.c
+++ b/diffcore-break.c
@@ -10,7 +10,8 @@ static int should_break(struct diff_filespec *src,
 			int break_score,
 			int *merge_score_p)
 {
-	/* dst is recorded as a modification of src.  Are they so
+	/* 
+         * dst is recorded as a modification of src.  Are they so
 	 * different that we are better off recording this as a pair
 	 * of delete and create?
 	 *
diff --git a/diffcore.h b/diffcore.h
index 1ea8067..fc71323 100644
--- a/diffcore.h
+++ b/diffcore.h
@@ -4,12 +4,14 @@
 #ifndef _DIFFCORE_H_
 #define _DIFFCORE_H_
 
-/* This header file is internal between diff.c and its diff transformers
+/* 
+ * This header file is internal between diff.c and its diff transformers
  * (e.g. diffcore-rename, diffcore-pickaxe).  Never include this header
  * in anything else.
  */
 
-/* We internally use unsigned short as the score value,
+/* 
+ * We internally use unsigned short as the score value,
  * and rely on an int capable to hold 32-bits.  -B can take
  * -Bmerge_score/break_score format and the two scores are
  * passed around in one int (high 16-bit for merge and low 16-bit
diff --git a/fetch-pack.c b/fetch-pack.c
index 726140a..fc48577 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -584,7 +584,8 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
 	}
 	if (find_common(fd, sha1, ref) < 0)
 		if (keep_pack != 1)
-			/* When cloning, it is not unusual to have
+			/* 
+                         * When cloning, it is not unusual to have
 			 * no common commit.
 			 */
 			fprintf(stderr, "warning: no common commits\n");
diff --git a/fetch.h b/fetch.h
index be48c6f..ee8a5d8 100644
--- a/fetch.h
+++ b/fetch.h
@@ -2,7 +2,7 @@
 #define PULL_H
 
 /*
- * Fetch object given SHA1 from the remote, and store it locally under
+ * Fetch object given SHA-1 from the remote, and store it locally under
  * GIT_OBJECT_DIRECTORY.  Return 0 on success, -1 on failure.  To be
  * provided by the particular implementation.
  */
@@ -17,7 +17,7 @@ extern void prefetch(unsigned char *sha1);
 
 /*
  * Fetch ref (relative to $GIT_DIR/refs) from the remote, and store
- * the 20-byte SHA1 in sha1.  Return 0 on success, -1 on failure.  To
+ * the 20-byte SHA-1 in sha1.  Return 0 on success, -1 on failure.  To
  * be provided by the particular implementation.
  */
 extern int fetch_ref(char *ref, unsigned char *sha1);
diff --git a/fsck-objects.c b/fsck-objects.c
index ecfb014..cc17788 100644
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -449,7 +449,7 @@ static void fsck_dir(int i, char *path)
 			add_sha1_list(sha1, DIRENT_SORT_HINT(de));
 			continue;
 		}
-		fprintf(stderr, "bad sha1 file: %s/%s\n", path, de->d_name);
+		fprintf(stderr, "bad SHA-1 file: %s/%s\n", path, de->d_name);
 	}
 	closedir(dir);
 }
@@ -656,7 +656,7 @@ int main(int argc, char **argv)
 			heads++;
 			continue;
 		}
-		error("invalid parameter: expected sha1, got '%s'", arg);
+		error("invalid parameter: expected SHA-1, got '%s'", arg);
 	}
 
 	/*
diff --git a/git-archimport.perl b/git-archimport.perl
index 2e15781..a24ec8f 100755
--- a/git-archimport.perl
+++ b/git-archimport.perl
@@ -105,7 +105,7 @@ my %stats  = (			# Track which strategy we used to import:
 );
 
 my %rptags = ();                # my reverse private tags
-                                # to map a SHA1 to a commitid
+                                # to map a SHA-1 to a commitid
 my $TLA = $ENV{'ARCH_CLIENT'} || 'tla';
 
 sub do_abrowse {
@@ -1013,7 +1013,7 @@ sub git_rev_parse {
     return $val;
 }
 
-# resolve a SHA1 to a known patchset
+# resolve a SHA-1 to a known patchset
 sub commitid2pset {
     my $commitid = shift;
     chomp $commitid;
diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh
index 7d62d79..f134d02 100755
--- a/git-merge-one-file.sh
+++ b/git-merge-one-file.sh
@@ -4,9 +4,9 @@
 #
 # This is the git per-file merge script, called with
 #
-#   $1 - original file SHA1 (or empty)
-#   $2 - file in branch1 SHA1 (or empty)
-#   $3 - file in branch2 SHA1 (or empty)
+#   $1 - original file SHA-1 (or empty)
+#   $2 - file in branch1 SHA-1 (or empty)
+#   $3 - file in branch2 SHA-1 (or empty)
 #   $4 - pathname in repository
 #   $5 - original file mode (or empty)
 #   $6 - file in branch1 mode (or empty)
diff --git a/git-svn.perl b/git-svn.perl
index 83ec03d..d27a90b 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -240,7 +240,7 @@ sub rebuild {
 	while (<$rev_list>) {
 		chomp;
 		my $c = $_;
-		croak "Non-SHA1: $c\n" unless $c =~ /^$sha1$/o;
+		croak "Non-SHA-1: $c\n" unless $c =~ /^$sha1$/o;
 		my @commit = grep(/^git-svn-id: /,
 		                  command(qw/cat-file commit/, $c));
 		next if (!@commit); # skip merges
@@ -2534,7 +2534,7 @@ sub libsvn_skip_unknown_revs {
 # And yes, it's still pretty fast (faster than Tie::File).
 sub revdb_set {
 	my ($file, $rev, $commit) = @_;
-	length $commit == 40 or croak "arg3 must be a full SHA1 hexsum\n";
+	length $commit == 40 or croak "arg3 must be a full SHA-1 hexsum\n";
 	open my $fh, '+<', $file or croak $!;
 	my $offset = $rev * 41;
 	# assume that append is the common case:
@@ -2754,7 +2754,7 @@ sub close_file {
 		chomp($hash = do { local $/; <$out> });
 		close $out or croak $!;
 		close $fh or croak $!;
-		$hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n";
+		$hash =~ /^[a-f\d]{40}$/ or die "not a SHA-1: $hash\n";
 		close $fb->{base} or croak $!;
 	} else {
 		$hash = $fb->{blob} or die "no blob information\n";
diff --git a/http-fetch.c b/http-fetch.c
index 67dfb0a..bafb0be 100644
--- a/http-fetch.c
+++ b/http-fetch.c
@@ -191,7 +191,7 @@ static void start_object_request(struct object_request *obj_req)
 	}
 	unlink(prevfile);
 
-	/* Reset inflate/SHA1 if there was an error reading the previous temp
+	/* Reset inflate/SHA-1 if there was an error reading the previous temp
 	   file; also rewind to the beginning of the local file. */
 	if (prev_read == -1) {
 		memset(&obj_req->stream, 0, sizeof(obj_req->stream));
@@ -417,8 +417,10 @@ static int fetch_index(struct alt_base *repo, unsigned char *sha1)
 	curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
 	slot->local = indexfile;
 
-	/* If there is data present from a previous transfer attempt,
-	   resume where it left off */
+	/* 
+         * If there is data present from a previous transfer attempt,
+         * resume where it left off 
+         */
 	prev_posn = ftell(indexfile);
 	if (prev_posn>0) {
 		if (get_verbosely)
diff --git a/http-push.c b/http-push.c
index 0a15f53..387c849 100644
--- a/http-push.c
+++ b/http-push.c
@@ -304,7 +304,7 @@ static void start_fetch_loose(struct transfer_request *request)
 	}
 	unlink(prevfile);
 
-	/* Reset inflate/SHA1 if there was an error reading the previous temp
+	/* Reset inflate/SHA-1 if there was an error reading the previous temp
 	   file; also rewind to the beginning of the local file. */
 	if (prev_read == -1) {
 		memset(&request->stream, 0, sizeof(request->stream));
@@ -2167,7 +2167,7 @@ static void fetch_symref(const char *path, char **symref, unsigned char *sha1)
 	if (buffer.posn == 0)
 		return;
 
-	/* If it's a symref, set the refname; otherwise try for a sha1 */
+	/* If it's a symref, set the refname; otherwise try for a SHA-1 */
 	if (!strncmp((char *)buffer.buffer, "ref: ", 5)) {
 		*symref = xmalloc(buffer.posn - 5);
 		strlcpy(*symref, (char *)buffer.buffer + 5, buffer.posn - 5);
@@ -2426,7 +2426,8 @@ int main(int argc, char **argv)
 			if (!has_sha1_file(ref->old_sha1) ||
 			    !ref_newer(ref->peer_ref->new_sha1,
 				       ref->old_sha1)) {
-				/* We do not have the remote ref, or
+				/*
+				 * We do not have the remote ref, or
 				 * we know that the remote ref is not
 				 * an ancestor of what we are trying to
 				 * push.  Either way this can be losing
diff --git a/index-pack.c b/index-pack.c
index 72e0962..f718439 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -413,7 +413,7 @@ static int compare_delta_entry(const void *a, const void *b)
 	return memcmp(&delta_a->base, &delta_b->base, UNION_BASE_SZ);
 }
 
-/* Parse all objects and return the pack content SHA1 hash */
+/* Parse all objects and return the pack content SHA-1 hash */
 static void parse_pack_objects(unsigned char *sha1)
 {
 	int i, percent = -1;
@@ -424,8 +424,8 @@ static void parse_pack_objects(unsigned char *sha1)
 	/*
 	 * First pass:
 	 * - find locations of all objects;
-	 * - calculate SHA1 of all non-delta objects;
-	 * - remember base (SHA1 or offset) for all deltas.
+	 * - calculate SHA-1 of all non-delta objects;
+	 * - remember base (SHA-1 or offset) for all deltas.
 	 */
 	if (verbose)
 		fprintf(stderr, "Indexing %d objects.\n", nr_objects);
@@ -451,7 +451,7 @@ static void parse_pack_objects(unsigned char *sha1)
 	flush();
 	SHA1_Final(sha1, &input_ctx);
 	if (hashcmp(fill(20), sha1))
-		die("pack is corrupted (SHA1 mismatch)");
+		die("pack is corrupted (SHA-1 mismatch)");
 	use(20);
 
 	/* If input_fd is a file, we should have reached its end now. */
@@ -463,7 +463,7 @@ static void parse_pack_objects(unsigned char *sha1)
 	if (!nr_deltas)
 		return;
 
-	/* Sort deltas by base SHA1/offset for fast searching */
+	/* Sort deltas by base SHA-1/offset for fast searching */
 	qsort(deltas, nr_deltas, sizeof(struct delta_entry),
 	      compare_delta_entry);
 
@@ -647,7 +647,7 @@ static void readjust_pack_header_and_sha1(unsigned char *sha1)
 	if (lseek(output_fd, 0, SEEK_SET) != 0)
 		die("cannot seek back: %s", strerror(errno));
 
-	/* Recompute and store the new pack's SHA1 */
+	/* Recompute and store the new pack's SHA-1 */
 	SHA1_Init(&ctx);
 	do {
 		unsigned char *buf[4096];
@@ -668,8 +668,8 @@ static int sha1_compare(const void *_a, const void *_b)
 }
 
 /*
- * On entry *sha1 contains the pack content SHA1 hash, on exit it is
- * the SHA1 hash of sorted object names.
+ * On entry *sha1 contains the pack content SHA-1 hash, on exit it is
+ * the SHA-1 hash of sorted object names.
  */
 static const char *write_index_file(const char *index_name, unsigned char *sha1)
 {
@@ -725,13 +725,13 @@ static const char *write_index_file(const char *index_name, unsigned char *sha1)
 	}
 	sha1write(f, array, 256 * sizeof(int));
 
-	/* recompute the SHA1 hash of sorted object names.
+	/* recompute the SHA-1 hash of sorted object names.
 	 * currently pack-objects does not do this, but that
 	 * can be fixed.
 	 */
 	SHA1_Init(&ctx);
 	/*
-	 * Write the actual SHA1 entries..
+	 * Write the actual SHA-1 entries..
 	 */
 	list = sorted_by_sha;
 	for (i = 0; i < nr_objects; i++) {
@@ -931,7 +931,7 @@ int main(int argc, char **argv)
 			die("pack has %d unresolved deltas",
 			    nr_deltas - nr_resolved_deltas);
 	} else {
-		/* Flush remaining pack final 20-byte SHA1. */
+		/* Flush remaining pack final 20-byte SHA-1. */
 		flush();
 	}
 	free(deltas);
diff --git a/merge-tree.c b/merge-tree.c
index 692ede0..72c9835 100644
--- a/merge-tree.c
+++ b/merge-tree.c
@@ -274,14 +274,14 @@ static void unresolved(const char *base, struct name_entry n[3])
  *
  * The output will be either:
  *  - successful merge
- *	 "0 mode sha1 filename"
+ *	 "0 mode SHA-1 filename"
  *    NOTE NOTE NOTE! FIXME! We really really need to walk the index
  *    in parallel with this too!
  *
  *  - conflict:
- *	"1 mode sha1 filename"
- *	"2 mode sha1 filename"
- *	"3 mode sha1 filename"
+ *	"1 mode SHA-1 filename"
+ *	"2 mode SHA-1 filename"
+ *	"3 mode SHA-1 filename"
  *    where not all of the 1/2/3 lines may exist, of course.
  *
  * The successful merge rules are the same as for the three-way merge
diff --git a/mktag.c b/mktag.c
index 3448a5d..d9ae24c 100644
--- a/mktag.c
+++ b/mktag.c
@@ -3,13 +3,13 @@
 
 /*
  * A signature file has a very simple fixed format: four lines
- * of "object <sha1>" + "type <typename>" + "tag <tagname>" +
+ * of "object <SHA-1>" + "type <typename>" + "tag <tagname>" +
  * "tagger <committer>", followed by a blank line, a free-form tag
  * message and a signature block that git itself doesn't care about,
  * but that can be verified with gpg or similar.
  *
  * The first three lines are guaranteed to be at least 63 bytes:
- * "object <sha1>\n" is 48 bytes, "type tag\n" at 9 bytes is the
+ * "object <SHA-1>\n" is 48 bytes, "type tag\n" at 9 bytes is the
  * shortest possible type-line, and "tag .\n" at 6 bytes is the
  * shortest single-character-tag line. 
  *
@@ -133,7 +133,7 @@ int main(int argc, char **argv)
 	}
 
 	/* Verify it for some basic sanity: it needs to start with
-	   "object <sha1>\ntype\ntagger " */
+	   "object <SHA-1>\ntype\ntagger " */
 	if (verify_tag(buffer, size) < 0)
 		die("invalid tag signature file");
 
diff --git a/mktree.c b/mktree.c
index 56205d1..08de0d0 100644
--- a/mktree.c
+++ b/mktree.c
@@ -103,8 +103,9 @@ int main(int ac, char **av)
 			break;
 		len = sb.len;
 		ptr = sb.buf;
-		/* Input is non-recursive ls-tree output format
-		 * mode SP type SP sha1 TAB name
+		/* 
+                 * Input is non-recursive ls-tree output format
+		 * mode SP type SP SHA-1 TAB name
 		 */
 		mode = strtoul(ptr, &ntr, 8);
 		if (ptr == ntr || !ntr || *ntr != ' ')
@@ -117,7 +118,7 @@ int main(int ac, char **av)
 			die("input format error: %s", sb.buf);
 		if (sha1_object_info(sha1, type, NULL))
 			die("object %s unavailable", sha1_to_hex(sha1));
-		*ntr++ = 0; /* now at the beginning of SHA1 */
+		*ntr++ = 0; /* now at the beginning of SHA-1 */
 		if (strcmp(ptr, type))
 			die("object type %s mismatch (%s)", ptr, type);
 		ntr += 41; /* at the beginning of name */
diff --git a/object.c b/object.c
index de244e2..05afc52 100644
--- a/object.c
+++ b/object.c
@@ -183,7 +183,7 @@ struct object *parse_object(const unsigned char *sha1)
 	if (buffer) {
 		struct object *obj;
 		if (check_sha1_signature(sha1, buffer, size, type) < 0)
-			printf("sha1 mismatch %s\n", sha1_to_hex(sha1));
+			printf("SHA-1 mismatch %s\n", sha1_to_hex(sha1));
 
 		obj = parse_object_buffer(sha1, type, size, buffer, &eaten);
 		if (!eaten)
diff --git a/pack-check.c b/pack-check.c
index 08a9fd8..d735d8b 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -28,10 +28,10 @@ static int verify_packfile(struct packed_git *p,
 	}
 	SHA1_Final(sha1, &ctx);
 	if (hashcmp(sha1, use_pack(p, w_curs, pack_sig, NULL)))
-		return error("Packfile %s SHA1 mismatch with itself",
+		return error("Packfile %s SHA-1 mismatch with itself",
 			     p->pack_name);
 	if (hashcmp(sha1, (unsigned char *)index_base + index_size - 40))
-		return error("Packfile %s SHA1 mismatch with idx",
+		return error("Packfile %s SHA-1 mismatch with idx",
 			     p->pack_name);
 	unuse_pack(w_curs);
 
@@ -130,12 +130,12 @@ int verify_pack(struct packed_git *p, int verbose)
 	int ret;
 
 	ret = 0;
-	/* Verify SHA1 sum of the index file */
+	/* Verify SHA-1 sum of the index file */
 	SHA1_Init(&ctx);
 	SHA1_Update(&ctx, index_base, index_size - 20);
 	SHA1_Final(sha1, &ctx);
 	if (hashcmp(sha1, (unsigned char *)index_base + index_size - 20))
-		ret = error("Packfile index for %s SHA1 mismatch",
+		ret = error("Packfile index for %s SHA-1 mismatch",
 			    p->pack_name);
 
 	if (!ret) {
diff --git a/patch-id.c b/patch-id.c
index 086d2d9..f036c78 100644
--- a/patch-id.c
+++ b/patch-id.c
@@ -60,7 +60,7 @@ static void generate_id_list(void)
 		if (!memcmp(line, "index ", 6))
 			continue;
 
-		/* Ignore line numbers when computing the SHA1 of the patch */
+		/* Ignore line numbers when computing the SHA-1 of the patch */
 		if (!memcmp(line, "@@ -", 4))
 			continue;
 
diff --git a/read-cache.c b/read-cache.c
index c54a611..2647e96 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -227,7 +227,7 @@ int ce_modified(struct cache_entry *ce, struct stat *st, int really)
 
 	/* Immediately after read-tree or update-index --cacheinfo,
 	 * the length field is zero.  For other cases the ce_size
-	 * should match the SHA1 recorded in the index entry.
+	 * should match the SHA-1 recorded in the index entry.
 	 */
 	if ((changed & DATA_CHANGED) && ce->ce_size != htonl(0))
 		return changed;
@@ -630,7 +630,7 @@ int add_cache_entry(struct cache_entry *ce, int option)
 }
 
 /*
- * "refresh" does not calculate a new sha1 file or bring the
+ * "refresh" does not calculate a new SHA-1 file or bring the
  * cache up-to-date for mode/content changes. But what it
  * _does_ do is to "re-match" the stat information of a file
  * with the cache, so that you can refresh the cache for a
@@ -924,7 +924,7 @@ static int ce_flush(SHA_CTX *context, int fd)
 		left = 0;
 	}
 
-	/* Append the SHA1 signature at the end */
+	/* Append the SHA-1 signature at the end */
 	SHA1_Final(write_buffer + left, context);
 	left += 20;
 	return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0;
diff --git a/receive-pack.c b/receive-pack.c
index 6333f00..301738c 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -340,7 +340,7 @@ static const char *unpack(void)
 		/*
 		 * The first thing we expects from index-pack's output
 		 * is "pack\t%40s\n" or "keep\t%40s\n" (46 bytes) where
-		 * %40s is the newly created pack SHA1 name.  In the "keep"
+		 * %40s is the newly created pack SHA-1 name.  In the "keep"
 		 * case, we need it to remove the corresponding .keep file
 		 * later on.  If we don't get that then tough luck with it.
 		 */
diff --git a/refs.c b/refs.c
index 8117328..85a0a42 100644
--- a/refs.c
+++ b/refs.c
@@ -20,7 +20,7 @@ static const char *parse_ref_line(char *line, unsigned char *sha1)
 	 * 42: the answer to everything.
 	 *
 	 * In this case, it happens to be the answer to
-	 *  40 (length of sha1 hex representation)
+	 *  40 (length of SHA-1 hex representation)
 	 *  +1 (space in between hex and name)
 	 *  +1 (newline at the end of the line)
 	 */
diff --git a/setup.c b/setup.c
index e9d3f5a..47872f3 100644
--- a/setup.c
+++ b/setup.c
@@ -141,7 +141,7 @@ const char **get_pathspec(const char *prefix, const char **pathspec)
  *  - a refs/ directory
  *  - either a HEAD symlink or a HEAD file that is formatted as
  *    a proper "ref:", or a regular file HEAD that has a properly
- *    formatted sha1 object name.
+ *    formatted SHA-1 object name.
  */
 static int is_git_directory(const char *suspect)
 {
diff --git a/sha1_file.c b/sha1_file.c
index 43ff402..443174d 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -3,7 +3,7 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  *
- * This handles basic git sha1 object files - packing, unpacking,
+ * This handles basic git SHA-1 object files - packing, unpacking,
  * creation etc.
  */
 #include "cache.h"
@@ -149,7 +149,7 @@ static void fill_sha1_path(char *pathbuf, const unsigned char *sha1)
  * filename.
  *
  * Also note that this returns the location for creating.  Reading
- * SHA1 file can happen from any alternate directory listed in the
+ * SHA-1 file can happen from any alternate directory listed in the
  * DB_ENVIRONMENT environment variable if it is not found in
  * the primary object database.
  */
@@ -238,7 +238,7 @@ static void read_info_alternates(const char * alternates, int depth);
  * contains "/the/directory/corresponding/to/.git/objects/...", while
  * its name points just after the slash at the end of ".git/objects/"
  * in the example above, and has enough space to hold 40-byte hex
- * SHA1, an extra slash for the first level indirection, and the
+ * SHA-1, an extra slash for the first level indirection, and the
  * terminating NUL.
  */
 static int link_alt_odb_entry(const char * entry, int len, const char * relative_base, int depth)
@@ -480,8 +480,8 @@ static int check_packed_git_idx(const char *path, unsigned long *idx_size_,
 	 * Total size:
 	 *  - 256 index entries 4 bytes each
 	 *  - 24-byte entries * nr (20-byte sha1 + 4-byte offset)
-	 *  - 20-byte SHA1 of the packfile
-	 *  - 20-byte SHA1 file checksum
+	 *  - 20-byte SHA-1 of the packfile
+	 *  - 20-byte SHA-1 file checksum
 	 */
 	if (idx_size != 4*256 + nr * 24 + 20 + 20)
 		return error("wrong index file size in %s", path);
@@ -1618,7 +1618,7 @@ int move_temp_to_file(const char *tmpfile, const char *filename)
 	unlink(tmpfile);
 	if (ret) {
 		if (ret != EEXIST) {
-			return error("unable to write sha1 filename %s: %s\n", filename, strerror(ret));
+			return error("unable to write SHA-1 filename %s: %s\n", filename, strerror(ret));
 		}
 		/* FIXME!!! Collision check here ? */
 	}
@@ -1753,7 +1753,7 @@ int write_sha1_file(void *buf, unsigned long len, const char *type, unsigned cha
 	size = stream.total_out;
 
 	if (write_buffer(fd, compressed, size) < 0)
-		die("unable to write sha1 file");
+		die("unable to write SHA-1 file");
 	fchmod(fd, 0444);
 	close(fd);
 	free(compressed);
@@ -1869,7 +1869,7 @@ int write_sha1_from_fd(const unsigned char *sha1, int fd, char *buffer,
 					    stream.avail_out);
 			} while (stream.avail_in && ret == Z_OK);
 			if (write_buffer(local, buffer, *bufposn - stream.avail_in) < 0)
-				die("unable to write sha1 file");
+				die("unable to write SHA-1 file");
 			memmove(buffer, buffer + *bufposn - stream.avail_in,
 				stream.avail_in);
 			*bufposn = stream.avail_in;
diff --git a/sha1_name.c b/sha1_name.c
index 9dfb3ac..b4bf045 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -182,7 +182,7 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,
 
 	status = find_unique_short_object(i, canonical, res, sha1);
 	if (!quietly && (status == SHORT_NAME_AMBIGUOUS))
-		return error("short SHA1 %.*s is ambiguous.", len, canonical);
+		return error("short SHA-1 %.*s is ambiguous.", len, canonical);
 	return status;
 }
 
diff --git a/upload-pack.c b/upload-pack.c
index 3648aae..ba3faae 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -343,7 +343,7 @@ static int got_sha1(char *hex, unsigned char *sha1)
 	int we_knew_they_have = 0;
 
 	if (get_sha1_hex(hex, sha1))
-		die("git-upload-pack: expected SHA1 object, got '%s'", hex);
+		die("git-upload-pack: expected SHA-1 object, got '%s'", hex);
 	if (!has_sha1_file(sha1))
 		return -1;
 
@@ -484,7 +484,7 @@ static int get_common_commits(void)
 			packet_write(1, "NAK\n");
 			return -1;
 		}
-		die("git-upload-pack: expected SHA1 list, got '%s'", line);
+		die("git-upload-pack: expected SHA-1 list, got '%s'", line);
 	}
 }
 
-- 
1.5.0.rc2

^ permalink raw reply related	[relevance 1%]

* Re: [PATCH] user-manual: set user.name and user.email with repo-config
  @ 2007-01-28  2:40  2%         ` Tom Prince
  0 siblings, 0 replies; 200+ results
From: Tom Prince @ 2007-01-28  2:40 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git, J. Bruce Fields, Junio C Hamano

On Sat, Jan 27, 2007 at 05:47:49PM -0800, Linus Torvalds wrote:
> Btw, one thing I don't like about "git-repo-config" is the name.
>
> Many people thought "git init-db" was confusing, and now we call it just
> "git init".
>
> Can I vote for doing that for "git repo-config" too? Is there something
> wrong with just calling it "git config"?
>
> Especially as it's not even repo-specific. Use "--global", and it has
> almost nothing at all to do with the particular "repo" you're working
> with.
>
> What would also mean that we'd have the man-page with a simple
>
>       man git-config
>
> which makes tons of sense if it documents both the config file *and* the
> "git config" program.
>
> Or is that too sneaky?
>
>               Linus
---
 .gitignore                                         |    1 +
 Documentation/cmd-list.perl                        |    2 +-
 Documentation/config.txt                           |    2 +-
 Documentation/core-tutorial.txt                    |    2 +-
 Documentation/cvs-migration.txt                    |    2 +-
 Documentation/everyday.txt                         |    4 +-
 Documentation/git-config.txt                       |  227 ++++++++++++++++++++
 Documentation/git-pull.txt                         |    4 +-
 Documentation/git-remote.txt                       |    4 +-
 Documentation/git-repo-config.txt                  |  227 --------------------
 Documentation/git-svn.txt                          |   20 +-
 Documentation/git-update-index.txt                 |    4 +-
 Documentation/git-var.txt                          |    4 +-
 Documentation/git.txt                              |    2 +-
 Documentation/howto/setup-git-server-over-http.txt |    4 +-
 Documentation/tutorial.txt                         |    8 +-
 Makefile                                           |    4 +-
 builtin-config.c                                   |  220 +++++++++++++++++++
 builtin-repo-config.c                              |  220 -------------------
 builtin.h                                          |    2 +-
 contrib/completion/git-completion.bash             |   15 +-
 contrib/emacs/git.el                               |    8 +-
 contrib/gitview/gitview                            |    2 +-
 contrib/remotes2config.sh                          |    4 +-
 git-clone.sh                                       |   10 +-
 git-commit.sh                                      |    4 +-
 git-cvsserver.perl                                 |    6 +-
 git-fetch.sh                                       |    2 +-
 git-instaweb.sh                                    |   10 +-
 git-ls-remote.sh                                   |    2 +-
 git-merge.sh                                       |    4 +-
 git-p4import.py                                    |    4 +-
 git-parse-remote.sh                                |   14 +-
 git-remote.perl                                    |    8 +-
 git-repack.sh                                      |    2 +-
 git-revert.sh                                      |    2 +-
 git-sh-setup.sh                                    |    2 +-
 git-svn.perl                                       |   20 +-
 git.c                                              |    3 +-
 gitk                                               |    2 +-
 gitweb/gitweb.perl                                 |    2 +-
 ident.c                                            |    4 +-
 perl/Git.pm                                        |    8 +-
 t/t1300-repo-config.sh                             |  102 +++++-----
 t/t1400-update-ref.sh                              |    4 +-
 t/t1410-reflog.sh                                  |    2 +-
 t/t3200-branch.sh                                  |    6 +-
 t/t3700-add.sh                                     |    6 +-
 t/t3900-i18n-commit.sh                             |   24 +-
 t/t3901-i18n-patch.sh                              |   58 +++---
 t/t4000-diff-format.sh                             |    2 +-
 t/t4006-diff-mode.sh                               |    2 +-
 t/t4013-diff-various.sh                            |    2 +-
 t/t4102-apply-rename.sh                            |    2 +-
 t/t5301-sliding-window.sh                          |   14 +-
 t/t5400-send-pack.sh                               |    2 +-
 t/t5500-fetch-pack.sh                              |    2 +-
 t/t5510-fetch.sh                                   |   10 +-
 t/t6200-fmt-merge-msg.sh                           |    6 +-
 59 files changed, 674 insertions(+), 671 deletions(-)
 create mode 100644 Documentation/git-config.txt
 delete mode 100644 Documentation/git-repo-config.txt
 create mode 100644 builtin-config.c
 delete mode 100644 builtin-repo-config.c

diff --git a/.gitignore b/.gitignore
index 6da1cdb..b4dccd7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,7 @@ git-clean
 git-clone
 git-commit
 git-commit-tree
+git-config
 git-convert-objects
 git-count-objects
 git-cvsexportcommit
diff --git a/Documentation/cmd-list.perl b/Documentation/cmd-list.perl
index 744db82..8244625 100755
--- a/Documentation/cmd-list.perl
+++ b/Documentation/cmd-list.perl
@@ -144,7 +144,7 @@ git-receive-pack                        synchelpers
 git-reflog                              ancillarymanipulators
 git-relink                              ancillarymanipulators
 git-repack                              ancillarymanipulators
-git-repo-config                         ancillarymanipulators
+git-config                              ancillarymanipulators
 git-request-pull                        foreignscminterface
 git-rerere                              ancillaryinterrogators
 git-reset                               mainporcelain
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 3f2fa09..4897c55 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -62,7 +62,7 @@ The values following the equals sign in variable assign are all either
 a string, an integer, or a boolean.  Boolean values may be given as yes/no,
 0/1 or true/false.  Case is not significant in boolean values, when
 converting value to the canonical form using '--bool' type specifier;
-`git-repo-config` will ensure that the output is "true" or "false".
+`git-config` will ensure that the output is "true" or "false".
 
 String values may be entirely or partially enclosed in double quotes.
 You need to enclose variable value in double quotes if you want to
diff --git a/Documentation/core-tutorial.txt b/Documentation/core-tutorial.txt
index 7317489..86a9c75 100644
--- a/Documentation/core-tutorial.txt
+++ b/Documentation/core-tutorial.txt
@@ -1130,7 +1130,7 @@ the remote repository URL in the local repository's config file
 like this:
 
 ------------------------------------------------
-$ git repo-config remote.linus.url http://www.kernel.org/pub/scm/git/git.git/
+$ git config remote.linus.url http://www.kernel.org/pub/scm/git/git.git/
 ------------------------------------------------
 
 and use the "linus" keyword with `git pull` instead of the full URL.
diff --git a/Documentation/cvs-migration.txt b/Documentation/cvs-migration.txt
index 775bf42..764cc56 100644
--- a/Documentation/cvs-migration.txt
+++ b/Documentation/cvs-migration.txt
@@ -36,7 +36,7 @@ them first before running git pull.
 ================================
 The `pull` command knows where to get updates from because of certain
 configuration variables that were set by the first `git clone`
-command; see `git repo-config -l` and the gitlink:git-repo-config[1] man
+command; see `git config -l` and the gitlink:git-config[1] man
 page for details.
 ================================
 
diff --git a/Documentation/everyday.txt b/Documentation/everyday.txt
index ca36a76..fbbbc92 100644
--- a/Documentation/everyday.txt
+++ b/Documentation/everyday.txt
@@ -212,12 +212,12 @@ Push into another repository.::
 ------------
 satellite$ git clone mothership:frotz frotz <1>
 satellite$ cd frotz
-satellite$ git repo-config --get-regexp '^(remote|branch)\.' <2>
+satellite$ git config --get-regexp '^(remote|branch)\.' <2>
 remote.origin.url mothership:frotz
 remote.origin.fetch refs/heads/*:refs/remotes/origin/*
 branch.master.remote origin
 branch.master.merge refs/heads/master
-satellite$ git repo-config remote.origin.push \
+satellite$ git config remote.origin.push \
            master:refs/remotes/satellite/master <3>
 satellite$ edit/compile/test/commit
 satellite$ git push origin <4>
diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt
new file mode 100644
index 0000000..b0dbfb2
--- /dev/null
+++ b/Documentation/git-config.txt
@@ -0,0 +1,227 @@
+git-config(1)
+==================
+
+NAME
+----
+git-config - Get and set repository or global options
+
+
+SYNOPSIS
+--------
+[verse]
+'git-config' [--global] [type] name [value [value_regex]]
+'git-config' [--global] [type] --add name value
+'git-config' [--global] [type] --replace-all name [value [value_regex]]
+'git-config' [--global] [type] --get name [value_regex]
+'git-config' [--global] [type] --get-all name [value_regex]
+'git-config' [--global] [type] --unset name [value_regex]
+'git-config' [--global] [type] --unset-all name [value_regex]
+'git-config' [--global] -l | --list
+
+DESCRIPTION
+-----------
+You can query/set/replace/unset options with this command. The name is
+actually the section and the key separated by a dot, and the value will be
+escaped.
+
+Multiple lines can be added to an option by using the '--add' option.
+If you want to update or unset an option which can occur on multiple
+lines, a POSIX regexp `value_regex` needs to be given.  Only the
+existing values that match the regexp are updated or unset.  If
+you want to handle the lines that do *not* match the regex, just
+prepend a single exclamation mark in front (see EXAMPLES).
+
+The type specifier can be either '--int' or '--bool', which will make
+'git-config' ensure that the variable(s) are of the given type and
+convert the value to the canonical form (simple decimal number for int,
+a "true" or "false" string for bool). If no type specifier is passed,
+no checks or transformations are performed on the value.
+
+This command will fail if:
+
+. The .git/config file is invalid,
+. Can not write to .git/config,
+. no section was provided,
+. the section or key is invalid,
+. you try to unset an option which does not exist,
+. you try to unset/set an option for which multiple lines match, or
+. you use --global option without $HOME being properly set.
+
+
+OPTIONS
+-------
+
+--replace-all::
+	Default behavior is to replace at most one line. This replaces
+	all lines matching the key (and optionally the value_regex).
+
+--add::
+	Adds a new line to the option without altering any existing
+	values.  This is the same as providing '^$' as the value_regex.
+
+--get::
+	Get the value for a given key (optionally filtered by a regex
+	matching the value). Returns error code 1 if the key was not
+	found and error code 2 if multiple key values were found.
+
+--get-all::
+	Like get, but does not fail if the number of values for the key
+	is not exactly one.
+
+--get-regexp::
+	Like --get-all, but interprets the name as a regular expression.
+
+--global::
+	Use global ~/.gitconfig file rather than the repository .git/config.
+
+--unset::
+	Remove the line matching the key from config file.
+
+--unset-all::
+	Remove all matching lines from config file.
+
+-l, --list::
+	List all variables set in config file.
+
+--bool::
+	git-config will ensure that the output is "true" or "false"
+
+--int::
+	git-config will ensure that the output is a simple
+	decimal number.  An optional value suffix of 'k', 'm', or 'g'
+	in the config file will cause the value to be multiplied
+	by 1024, 1048576, or 1073741824 prior to output.
+
+
+ENVIRONMENT
+-----------
+
+GIT_CONFIG::
+	Take the configuration from the given file instead of .git/config.
+	Using the "--global" option forces this to ~/.gitconfig.
+
+GIT_CONFIG_LOCAL::
+	Currently the same as $GIT_CONFIG; when Git will support global
+	configuration files, this will cause it to take the configuration
+	from the global configuration file in addition to the given file.
+
+
+EXAMPLE
+-------
+
+Given a .git/config like this:
+
+	#
+	# This is the config file, and
+	# a '#' or ';' character indicates
+	# a comment
+	#
+
+	; core variables
+	[core]
+		; Don't trust file modes
+		filemode = false
+
+	; Our diff algorithm
+	[diff]
+		external = "/usr/local/bin/gnu-diff -u"
+		renames = true
+
+	; Proxy settings
+	[core]
+		gitproxy="ssh" for "ssh://kernel.org/"
+		gitproxy="proxy-command" for kernel.org
+		gitproxy="myprotocol-command" for "my://"
+		gitproxy=default-proxy ; for all the rest
+
+you can set the filemode to true with
+
+------------
+% git config core.filemode true
+------------
+
+The hypothetical proxy command entries actually have a postfix to discern
+what URL they apply to. Here is how to change the entry for kernel.org
+to "ssh".
+
+------------
+% git config core.gitproxy '"ssh" for kernel.org' 'for kernel.org$'
+------------
+
+This makes sure that only the key/value pair for kernel.org is replaced.
+
+To delete the entry for renames, do
+
+------------
+% git config --unset diff.renames
+------------
+
+If you want to delete an entry for a multivar (like core.gitproxy above),
+you have to provide a regex matching the value of exactly one line.
+
+To query the value for a given key, do
+
+------------
+% git config --get core.filemode
+------------
+
+or
+
+------------
+% git config core.filemode
+------------
+
+or, to query a multivar:
+
+------------
+% git config --get core.gitproxy "for kernel.org$"
+------------
+
+If you want to know all the values for a multivar, do:
+
+------------
+% git config --get-all core.gitproxy
+------------
+
+If you like to live dangerous, you can replace *all* core.gitproxy by a
+new one with
+
+------------
+% git config --replace-all core.gitproxy ssh
+------------
+
+However, if you really only want to replace the line for the default proxy,
+i.e. the one without a "for ..." postfix, do something like this:
+
+------------
+% git config core.gitproxy ssh '! for '
+------------
+
+To actually match only values with an exclamation mark, you have to
+
+------------
+% git config section.key value '[!]'
+------------
+
+To add a new proxy, without altering any of the existing ones, use
+
+------------
+% git config core.gitproxy '"proxy" for example.com'
+------------
+
+
+include::config.txt[]
+
+
+Author
+------
+Written by Johannes Schindelin <Johannes.Schindelin@gmx.de>
+
+Documentation
+--------------
+Documentation by Johannes Schindelin, Petr Baudis and the git-list <git@vger.kernel.org>.
+
+GIT
+---
+Part of the gitlink:git[7] suite
+
diff --git a/Documentation/git-pull.txt b/Documentation/git-pull.txt
index 3e5f115..a81d68c 100644
--- a/Documentation/git-pull.txt
+++ b/Documentation/git-pull.txt
@@ -42,7 +42,7 @@ git pull, git pull origin::
 	current branch.  Normally the branch merged in is
 	the HEAD of the remote repository, but the choice is
 	determined by the branch.<name>.remote and
-	branch.<name>.merge options; see gitlink:git-repo-config[1]
+	branch.<name>.merge options; see gitlink:git-config[1]
 	for details.
 
 git pull origin next::
@@ -94,7 +94,7 @@ gitlink:git-reset[1].
 
 SEE ALSO
 --------
-gitlink:git-fetch[1], gitlink:git-merge[1], gitlink:git-repo-config[1]
+gitlink:git-fetch[1], gitlink:git-merge[1], gitlink:git-config[1]
 
 
 Author
diff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt
index 5b93a8c..358c1ac 100644
--- a/Documentation/git-remote.txt
+++ b/Documentation/git-remote.txt
@@ -28,7 +28,7 @@ In the third form, gives some information about the remote <name>.
 
 The remote configuration is achieved using the `remote.origin.url` and
 `remote.origin.fetch` configuration variables.  (See
-gitlink:git-repo-config[1]).
+gitlink:git-config[1]).
 
 Examples
 --------
@@ -58,7 +58,7 @@ See Also
 --------
 gitlink:git-fetch[1]
 gitlink:git-branch[1]
-gitlink:git-repo-config[1]
+gitlink:git-config[1]
 
 Author
 ------
diff --git a/Documentation/git-repo-config.txt b/Documentation/git-repo-config.txt
deleted file mode 100644
index 9db3d30..0000000
--- a/Documentation/git-repo-config.txt
+++ /dev/null
@@ -1,227 +0,0 @@
-git-repo-config(1)
-==================
-
-NAME
-----
-git-repo-config - Get and set repository or global options
-
-
-SYNOPSIS
---------
-[verse]
-'git-repo-config' [--global] [type] name [value [value_regex]]
-'git-repo-config' [--global] [type] --add name value
-'git-repo-config' [--global] [type] --replace-all name [value [value_regex]]
-'git-repo-config' [--global] [type] --get name [value_regex]
-'git-repo-config' [--global] [type] --get-all name [value_regex]
-'git-repo-config' [--global] [type] --unset name [value_regex]
-'git-repo-config' [--global] [type] --unset-all name [value_regex]
-'git-repo-config' [--global] -l | --list
-
-DESCRIPTION
------------
-You can query/set/replace/unset options with this command. The name is
-actually the section and the key separated by a dot, and the value will be
-escaped.
-
-Multiple lines can be added to an option by using the '--add' option.
-If you want to update or unset an option which can occur on multiple
-lines, a POSIX regexp `value_regex` needs to be given.  Only the
-existing values that match the regexp are updated or unset.  If
-you want to handle the lines that do *not* match the regex, just
-prepend a single exclamation mark in front (see EXAMPLES).
-
-The type specifier can be either '--int' or '--bool', which will make
-'git-repo-config' ensure that the variable(s) are of the given type and
-convert the value to the canonical form (simple decimal number for int,
-a "true" or "false" string for bool). If no type specifier is passed,
-no checks or transformations are performed on the value.
-
-This command will fail if:
-
-. The .git/config file is invalid,
-. Can not write to .git/config,
-. no section was provided,
-. the section or key is invalid,
-. you try to unset an option which does not exist,
-. you try to unset/set an option for which multiple lines match, or
-. you use --global option without $HOME being properly set.
-
-
-OPTIONS
--------
-
---replace-all::
-	Default behavior is to replace at most one line. This replaces
-	all lines matching the key (and optionally the value_regex).
-
---add::
-	Adds a new line to the option without altering any existing
-	values.  This is the same as providing '^$' as the value_regex.
-
---get::
-	Get the value for a given key (optionally filtered by a regex
-	matching the value). Returns error code 1 if the key was not
-	found and error code 2 if multiple key values were found.
-
---get-all::
-	Like get, but does not fail if the number of values for the key
-	is not exactly one.
-
---get-regexp::
-	Like --get-all, but interprets the name as a regular expression.
-
---global::
-	Use global ~/.gitconfig file rather than the repository .git/config.
-
---unset::
-	Remove the line matching the key from config file.
-
---unset-all::
-	Remove all matching lines from config file.
-
--l, --list::
-	List all variables set in config file.
-
---bool::
-	git-repo-config will ensure that the output is "true" or "false"
-
---int::
-	git-repo-config will ensure that the output is a simple
-	decimal number.  An optional value suffix of 'k', 'm', or 'g'
-	in the config file will cause the value to be multiplied
-	by 1024, 1048576, or 1073741824 prior to output.
-
-
-ENVIRONMENT
------------
-
-GIT_CONFIG::
-	Take the configuration from the given file instead of .git/config.
-	Using the "--global" option forces this to ~/.gitconfig.
-
-GIT_CONFIG_LOCAL::
-	Currently the same as $GIT_CONFIG; when Git will support global
-	configuration files, this will cause it to take the configuration
-	from the global configuration file in addition to the given file.
-
-
-EXAMPLE
--------
-
-Given a .git/config like this:
-
-	#
-	# This is the config file, and
-	# a '#' or ';' character indicates
-	# a comment
-	#
-
-	; core variables
-	[core]
-		; Don't trust file modes
-		filemode = false
-
-	; Our diff algorithm
-	[diff]
-		external = "/usr/local/bin/gnu-diff -u"
-		renames = true
-
-	; Proxy settings
-	[core]
-		gitproxy="ssh" for "ssh://kernel.org/"
-		gitproxy="proxy-command" for kernel.org
-		gitproxy="myprotocol-command" for "my://"
-		gitproxy=default-proxy ; for all the rest
-
-you can set the filemode to true with
-
-------------
-% git repo-config core.filemode true
-------------
-
-The hypothetical proxy command entries actually have a postfix to discern
-what URL they apply to. Here is how to change the entry for kernel.org
-to "ssh".
-
-------------
-% git repo-config core.gitproxy '"ssh" for kernel.org' 'for kernel.org$'
-------------
-
-This makes sure that only the key/value pair for kernel.org is replaced.
-
-To delete the entry for renames, do
-
-------------
-% git repo-config --unset diff.renames
-------------
-
-If you want to delete an entry for a multivar (like core.gitproxy above),
-you have to provide a regex matching the value of exactly one line.
-
-To query the value for a given key, do
-
-------------
-% git repo-config --get core.filemode
-------------
-
-or
-
-------------
-% git repo-config core.filemode
-------------
-
-or, to query a multivar:
-
-------------
-% git repo-config --get core.gitproxy "for kernel.org$"
-------------
-
-If you want to know all the values for a multivar, do:
-
-------------
-% git repo-config --get-all core.gitproxy
-------------
-
-If you like to live dangerous, you can replace *all* core.gitproxy by a
-new one with
-
-------------
-% git repo-config --replace-all core.gitproxy ssh
-------------
-
-However, if you really only want to replace the line for the default proxy,
-i.e. the one without a "for ..." postfix, do something like this:
-
-------------
-% git repo-config core.gitproxy ssh '! for '
-------------
-
-To actually match only values with an exclamation mark, you have to
-
-------------
-% git repo-config section.key value '[!]'
-------------
-
-To add a new proxy, without altering any of the existing ones, use
-
-------------
-% git repo-config core.gitproxy '"proxy" for example.com'
-------------
-
-
-include::config.txt[]
-
-
-Author
-------
-Written by Johannes Schindelin <Johannes.Schindelin@gmx.de>
-
-Documentation
---------------
-Documentation by Johannes Schindelin, Petr Baudis and the git-list <git@vger.kernel.org>.
-
-GIT
----
-Part of the gitlink:git[7] suite
-
diff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt
index b95ff1d..aea4a6b 100644
--- a/Documentation/git-svn.txt
+++ b/Documentation/git-svn.txt
@@ -204,7 +204,7 @@ removed by default if there are no files left in them.  git
 cannot version empty directories.  Enabling this flag will make
 the commit to SVN act like git.
 
-repo-config key: svn.rmdir
+config key: svn.rmdir
 
 -e::
 --edit::
@@ -215,7 +215,7 @@ Edit the commit message before committing to SVN.  This is off by
 default for objects that are commits, and forced on when committing
 tree objects.
 
-repo-config key: svn.edit
+config key: svn.edit
 
 -l<num>::
 --find-copies-harder::
@@ -226,8 +226,8 @@ They are both passed directly to git-diff-tree see
 gitlink:git-diff-tree[1] for more information.
 
 [verse]
-repo-config key: svn.l
-repo-config key: svn.findcopiesharder
+config key: svn.l
+config key: svn.findcopiesharder
 
 -A<filename>::
 --authors-file=<filename>::
@@ -245,7 +245,7 @@ will abort operation. The user will then have to add the
 appropriate entry.  Re-running the previous git-svn command
 after the authors-file is modified should continue operation.
 
-repo-config key: svn.authorsfile
+config key: svn.authorsfile
 
 -q::
 --quiet::
@@ -262,8 +262,8 @@ repo-config key: svn.authorsfile
 
 	--repack-flags are passed directly to gitlink:git-repack[1].
 
-repo-config key: svn.repack
-repo-config key: svn.repackflags
+config key: svn.repack
+config key: svn.repackflags
 
 -m::
 --merge::
@@ -304,7 +304,7 @@ used to track branches across multiple SVN _repositories_.
 This option may be specified multiple times, once for each
 branch.
 
-repo-config key: svn.branch
+config key: svn.branch
 
 -i<GIT_SVN_ID>::
 --id <GIT_SVN_ID>::
@@ -320,7 +320,7 @@ for more information on using GIT_SVN_ID.
 	started tracking a branch and never tracked the trunk it was
 	descended from.
 
-repo-config key: svn.followparent
+config key: svn.followparent
 
 --no-metadata::
 	This gets rid of the git-svn-id: lines at the end of every commit.
@@ -332,7 +332,7 @@ repo-config key: svn.followparent
 	The 'git-svn log' command will not work on repositories using this,
 	either.
 
-repo-config key: svn.nometadata
+config key: svn.nometadata
 
 --
 
diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index 5bbae42..b161c8b 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -289,7 +289,7 @@ Configuration
 
 The command honors `core.filemode` configuration variable.  If
 your repository is on an filesystem whose executable bits are
-unreliable, this should be set to 'false' (see gitlink:git-repo-config[1]).
+unreliable, this should be set to 'false' (see gitlink:git-config[1]).
 This causes the command to ignore differences in file modes recorded
 in the index and the file mode on the filesystem if they differ only on
 executable bit.   On such an unfortunate filesystem, you may
@@ -301,7 +301,7 @@ The command looks at `core.ignorestat` configuration variable.  See
 
 See Also
 --------
-gitlink:git-repo-config[1]
+gitlink:git-config[1]
 
 
 Author
diff --git a/Documentation/git-var.txt b/Documentation/git-var.txt
index 8a50638..9b0de1c 100644
--- a/Documentation/git-var.txt
+++ b/Documentation/git-var.txt
@@ -20,7 +20,7 @@ OPTIONS
 	Cause the logical variables to be listed. In addition, all the
 	variables of the git configuration file .git/config are listed
 	as well. (However, the configuration variables listing functionality
-	is deprecated in favor of `git-repo-config -l`.)
+	is deprecated in favor of `git-config -l`.)
 
 EXAMPLE
 --------
@@ -49,7 +49,7 @@ See Also
 --------
 gitlink:git-commit-tree[1]
 gitlink:git-tag[1]
-gitlink:git-repo-config[1]
+gitlink:git-config[1]
 
 Author
 ------
diff --git a/Documentation/git.txt b/Documentation/git.txt
index 9761de3..7cd3467 100644
--- a/Documentation/git.txt
+++ b/Documentation/git.txt
@@ -24,7 +24,7 @@ link:everyday.html[Everyday Git] for a useful minimum set of commands, and
 also want to read link:cvs-migration.html[CVS migration].
 
 The COMMAND is either a name of a Git command (see below) or an alias
-as defined in the configuration file (see gitlink:git-repo-config[1]).
+as defined in the configuration file (see gitlink:git-config[1]).
 
 OPTIONS
 -------
diff --git a/Documentation/howto/setup-git-server-over-http.txt b/Documentation/howto/setup-git-server-over-http.txt
index a202f3a..8eadc20 100644
--- a/Documentation/howto/setup-git-server-over-http.txt
+++ b/Documentation/howto/setup-git-server-over-http.txt
@@ -205,7 +205,7 @@ To check whether all is OK, do:
 Now, add the remote in your existing repository which contains the project
 you want to export:
 
-   $ git-repo-config remote.upload.url \
+   $ git-config remote.upload.url \
        http://<username>@<servername>/my-new-repo.git/
 
 It is important to put the last '/'; Without it, the server will send
@@ -222,7 +222,7 @@ From your client repository, do
 
 This pushes branch 'master' (which is assumed to be the branch you
 want to export) to repository called 'upload', which we previously
-defined with git-repo-config.
+defined with git-config.
 
 
 Troubleshooting:
diff --git a/Documentation/tutorial.txt b/Documentation/tutorial.txt
index c27a450..adb1e32 100644
--- a/Documentation/tutorial.txt
+++ b/Documentation/tutorial.txt
@@ -16,8 +16,8 @@ public email address before doing any operation.  The easiest
 way to do so is:
 
 ------------------------------------------------
-$ git repo-config --global user.name "Your Name Comes Here"
-$ git repo-config --global user.email you@yourdomain.example.com
+$ git config --global user.name "Your Name Comes Here"
+$ git config --global user.email you@yourdomain.example.com
 ------------------------------------------------
 
 
@@ -353,12 +353,12 @@ repository in the repository configuration, and that location is
 used for pulls:
 
 -------------------------------------
-$ git repo-config --get remote.origin.url
+$ git config --get remote.origin.url
 /home/bob/myrepo
 -------------------------------------
 
 (The complete configuration created by git-clone is visible using
-"git repo-config -l", and the gitlink:git-repo-config[1] man page
+"git config -l", and the gitlink:git-config[1] man page
 explains the meaning of each option.)
 
 Git also keeps a pristine copy of Alice's master branch under the
diff --git a/Makefile b/Makefile
index 07246f3..fd8a522 100644
--- a/Makefile
+++ b/Makefile
@@ -213,7 +213,7 @@ EXTRA_PROGRAMS =
 
 BUILT_INS = \
 	git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
-	git-get-tar-commit-id$X git-init$X \
+	git-get-tar-commit-id$X git-init$X git-repo-config$X \
 	$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
 
 # what 'all' will build and 'install' will install, in gitexecdir
@@ -299,7 +299,7 @@ BUILTIN_OBJS = \
 	builtin-push.o \
 	builtin-read-tree.o \
 	builtin-reflog.o \
-	builtin-repo-config.o \
+	builtin-config.o \
 	builtin-rerere.o \
 	builtin-rev-list.o \
 	builtin-rev-parse.o \
diff --git a/builtin-config.c b/builtin-config.c
new file mode 100644
index 0000000..3c3860f
--- /dev/null
+++ b/builtin-config.c
@@ -0,0 +1,220 @@
+#include "builtin.h"
+#include "cache.h"
+
+static const char git_config_set_usage[] =
+"git-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --list";
+
+static char *key;
+static regex_t *key_regexp;
+static regex_t *regexp;
+static int show_keys;
+static int use_key_regexp;
+static int do_all;
+static int do_not_match;
+static int seen;
+static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
+
+static int show_all_config(const char *key_, const char *value_)
+{
+	if (value_)
+		printf("%s=%s\n", key_, value_);
+	else
+		printf("%s\n", key_);
+	return 0;
+}
+
+static int show_config(const char* key_, const char* value_)
+{
+	char value[256];
+	const char *vptr = value;
+	int dup_error = 0;
+
+	if (!use_key_regexp && strcmp(key_, key))
+		return 0;
+	if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
+		return 0;
+	if (regexp != NULL &&
+			 (do_not_match ^
+			  regexec(regexp, (value_?value_:""), 0, NULL, 0)))
+		return 0;
+
+	if (show_keys)
+		printf("%s ", key_);
+	if (seen && !do_all)
+		dup_error = 1;
+	if (type == T_INT)
+		sprintf(value, "%d", git_config_int(key_, value_?value_:""));
+	else if (type == T_BOOL)
+		vptr = git_config_bool(key_, value_) ? "true" : "false";
+	else
+		vptr = value_?value_:"";
+	seen++;
+	if (dup_error) {
+		error("More than one value for the key %s: %s",
+				key_, vptr);
+	}
+	else
+		printf("%s\n", vptr);
+
+	return 0;
+}
+
+static int get_value(const char* key_, const char* regex_)
+{
+	int ret = -1;
+	char *tl;
+	char *global = NULL, *config = NULL;
+	const char *local;
+
+	local = getenv(CONFIG_ENVIRONMENT);
+	if (!local) {
+		const char *home = getenv("HOME");
+		local = getenv(CONFIG_LOCAL_ENVIRONMENT);
+		if (!local)
+			local = config = xstrdup(git_path("config"));
+		if (home)
+			global = xstrdup(mkpath("%s/.gitconfig", home));
+	}
+
+	key = xstrdup(key_);
+	for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
+		*tl = tolower(*tl);
+	for (tl=key; *tl && *tl != '.'; ++tl)
+		*tl = tolower(*tl);
+
+	if (use_key_regexp) {
+		key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
+		if (regcomp(key_regexp, key, REG_EXTENDED)) {
+			fprintf(stderr, "Invalid key pattern: %s\n", key_);
+			goto free_strings;
+		}
+	}
+
+	if (regex_) {
+		if (regex_[0] == '!') {
+			do_not_match = 1;
+			regex_++;
+		}
+
+		regexp = (regex_t*)xmalloc(sizeof(regex_t));
+		if (regcomp(regexp, regex_, REG_EXTENDED)) {
+			fprintf(stderr, "Invalid pattern: %s\n", regex_);
+			goto free_strings;
+		}
+	}
+
+	if (do_all && global)
+		git_config_from_file(show_config, global);
+	git_config_from_file(show_config, local);
+	if (!do_all && !seen && global)
+		git_config_from_file(show_config, global);
+
+	free(key);
+	if (regexp) {
+		regfree(regexp);
+		free(regexp);
+	}
+
+	if (do_all)
+		ret = !seen;
+	else
+		ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
+
+free_strings:
+	free(config);
+	free(global);
+	return ret;
+}
+
+int cmd_config(int argc, const char **argv, const char *prefix)
+{
+	int nongit = 0;
+	setup_git_directory_gently(&nongit);
+
+	while (1 < argc) {
+		if (!strcmp(argv[1], "--int"))
+			type = T_INT;
+		else if (!strcmp(argv[1], "--bool"))
+			type = T_BOOL;
+		else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
+			return git_config(show_all_config);
+		else if (!strcmp(argv[1], "--global")) {
+			char *home = getenv("HOME");
+			if (home) {
+				char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
+				setenv("GIT_CONFIG", user_config, 1);
+				free(user_config);
+			} else {
+				die("$HOME not set");
+			}
+		} else if (!strcmp(argv[1], "--rename-section")) {
+			int ret;
+			if (argc != 4)
+				usage(git_config_set_usage);
+			ret = git_config_rename_section(argv[2], argv[3]);
+			if (ret < 0)
+				return ret;
+			if (ret == 0) {
+				fprintf(stderr, "No such section!\n");
+				return 1;
+			}
+			return 0;
+		} else
+			break;
+		argc--;
+		argv++;
+	}
+
+	switch (argc) {
+	case 2:
+		return get_value(argv[1], NULL);
+	case 3:
+		if (!strcmp(argv[1], "--unset"))
+			return git_config_set(argv[2], NULL);
+		else if (!strcmp(argv[1], "--unset-all"))
+			return git_config_set_multivar(argv[2], NULL, NULL, 1);
+		else if (!strcmp(argv[1], "--get"))
+			return get_value(argv[2], NULL);
+		else if (!strcmp(argv[1], "--get-all")) {
+			do_all = 1;
+			return get_value(argv[2], NULL);
+		} else if (!strcmp(argv[1], "--get-regexp")) {
+			show_keys = 1;
+			use_key_regexp = 1;
+			do_all = 1;
+			return get_value(argv[2], NULL);
+		} else
+
+			return git_config_set(argv[1], argv[2]);
+	case 4:
+		if (!strcmp(argv[1], "--unset"))
+			return git_config_set_multivar(argv[2], NULL, argv[3], 0);
+		else if (!strcmp(argv[1], "--unset-all"))
+			return git_config_set_multivar(argv[2], NULL, argv[3], 1);
+		else if (!strcmp(argv[1], "--get"))
+			return get_value(argv[2], argv[3]);
+		else if (!strcmp(argv[1], "--get-all")) {
+			do_all = 1;
+			return get_value(argv[2], argv[3]);
+		} else if (!strcmp(argv[1], "--get-regexp")) {
+			show_keys = 1;
+			use_key_regexp = 1;
+			do_all = 1;
+			return get_value(argv[2], argv[3]);
+		} else if (!strcmp(argv[1], "--add"))
+			return git_config_set_multivar(argv[2], argv[3], "^$", 0);
+		else if (!strcmp(argv[1], "--replace-all"))
+
+			return git_config_set_multivar(argv[2], argv[3], NULL, 1);
+		else
+
+			return git_config_set_multivar(argv[1], argv[2], argv[3], 0);
+	case 5:
+		if (!strcmp(argv[1], "--replace-all"))
+			return git_config_set_multivar(argv[2], argv[3], argv[4], 1);
+	case 1:
+	default:
+		usage(git_config_set_usage);
+	}
+	return 0;
+}
diff --git a/builtin-repo-config.c b/builtin-repo-config.c
deleted file mode 100644
index 9063311..0000000
--- a/builtin-repo-config.c
+++ /dev/null
@@ -1,220 +0,0 @@
-#include "builtin.h"
-#include "cache.h"
-
-static const char git_config_set_usage[] =
-"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --list";
-
-static char *key;
-static regex_t *key_regexp;
-static regex_t *regexp;
-static int show_keys;
-static int use_key_regexp;
-static int do_all;
-static int do_not_match;
-static int seen;
-static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;
-
-static int show_all_config(const char *key_, const char *value_)
-{
-	if (value_)
-		printf("%s=%s\n", key_, value_);
-	else
-		printf("%s\n", key_);
-	return 0;
-}
-
-static int show_config(const char* key_, const char* value_)
-{
-	char value[256];
-	const char *vptr = value;
-	int dup_error = 0;
-
-	if (!use_key_regexp && strcmp(key_, key))
-		return 0;
-	if (use_key_regexp && regexec(key_regexp, key_, 0, NULL, 0))
-		return 0;
-	if (regexp != NULL &&
-			 (do_not_match ^
-			  regexec(regexp, (value_?value_:""), 0, NULL, 0)))
-		return 0;
-
-	if (show_keys)
-		printf("%s ", key_);
-	if (seen && !do_all)
-		dup_error = 1;
-	if (type == T_INT)
-		sprintf(value, "%d", git_config_int(key_, value_?value_:""));
-	else if (type == T_BOOL)
-		vptr = git_config_bool(key_, value_) ? "true" : "false";
-	else
-		vptr = value_?value_:"";
-	seen++;
-	if (dup_error) {
-		error("More than one value for the key %s: %s",
-				key_, vptr);
-	}
-	else
-		printf("%s\n", vptr);
-
-	return 0;
-}
-
-static int get_value(const char* key_, const char* regex_)
-{
-	int ret = -1;
-	char *tl;
-	char *global = NULL, *repo_config = NULL;
-	const char *local;
-
-	local = getenv(CONFIG_ENVIRONMENT);
-	if (!local) {
-		const char *home = getenv("HOME");
-		local = getenv(CONFIG_LOCAL_ENVIRONMENT);
-		if (!local)
-			local = repo_config = xstrdup(git_path("config"));
-		if (home)
-			global = xstrdup(mkpath("%s/.gitconfig", home));
-	}
-
-	key = xstrdup(key_);
-	for (tl=key+strlen(key)-1; tl >= key && *tl != '.'; --tl)
-		*tl = tolower(*tl);
-	for (tl=key; *tl && *tl != '.'; ++tl)
-		*tl = tolower(*tl);
-
-	if (use_key_regexp) {
-		key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
-		if (regcomp(key_regexp, key, REG_EXTENDED)) {
-			fprintf(stderr, "Invalid key pattern: %s\n", key_);
-			goto free_strings;
-		}
-	}
-
-	if (regex_) {
-		if (regex_[0] == '!') {
-			do_not_match = 1;
-			regex_++;
-		}
-
-		regexp = (regex_t*)xmalloc(sizeof(regex_t));
-		if (regcomp(regexp, regex_, REG_EXTENDED)) {
-			fprintf(stderr, "Invalid pattern: %s\n", regex_);
-			goto free_strings;
-		}
-	}
-
-	if (do_all && global)
-		git_config_from_file(show_config, global);
-	git_config_from_file(show_config, local);
-	if (!do_all && !seen && global)
-		git_config_from_file(show_config, global);
-
-	free(key);
-	if (regexp) {
-		regfree(regexp);
-		free(regexp);
-	}
-
-	if (do_all)
-		ret = !seen;
-	else
-		ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
-
-free_strings:
-	free(repo_config);
-	free(global);
-	return ret;
-}
-
-int cmd_repo_config(int argc, const char **argv, const char *prefix)
-{
-	int nongit = 0;
-	setup_git_directory_gently(&nongit);
-
-	while (1 < argc) {
-		if (!strcmp(argv[1], "--int"))
-			type = T_INT;
-		else if (!strcmp(argv[1], "--bool"))
-			type = T_BOOL;
-		else if (!strcmp(argv[1], "--list") || !strcmp(argv[1], "-l"))
-			return git_config(show_all_config);
-		else if (!strcmp(argv[1], "--global")) {
-			char *home = getenv("HOME");
-			if (home) {
-				char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
-				setenv("GIT_CONFIG", user_config, 1);
-				free(user_config);
-			} else {
-				die("$HOME not set");
-			}
-		} else if (!strcmp(argv[1], "--rename-section")) {
-			int ret;
-			if (argc != 4)
-				usage(git_config_set_usage);
-			ret = git_config_rename_section(argv[2], argv[3]);
-			if (ret < 0)
-				return ret;
-			if (ret == 0) {
-				fprintf(stderr, "No such section!\n");
-				return 1;
-			}
-			return 0;
-		} else
-			break;
-		argc--;
-		argv++;
-	}
-
-	switch (argc) {
-	case 2:
-		return get_value(argv[1], NULL);
-	case 3:
-		if (!strcmp(argv[1], "--unset"))
-			return git_config_set(argv[2], NULL);
-		else if (!strcmp(argv[1], "--unset-all"))
-			return git_config_set_multivar(argv[2], NULL, NULL, 1);
-		else if (!strcmp(argv[1], "--get"))
-			return get_value(argv[2], NULL);
-		else if (!strcmp(argv[1], "--get-all")) {
-			do_all = 1;
-			return get_value(argv[2], NULL);
-		} else if (!strcmp(argv[1], "--get-regexp")) {
-			show_keys = 1;
-			use_key_regexp = 1;
-			do_all = 1;
-			return get_value(argv[2], NULL);
-		} else
-
-			return git_config_set(argv[1], argv[2]);
-	case 4:
-		if (!strcmp(argv[1], "--unset"))
-			return git_config_set_multivar(argv[2], NULL, argv[3], 0);
-		else if (!strcmp(argv[1], "--unset-all"))
-			return git_config_set_multivar(argv[2], NULL, argv[3], 1);
-		else if (!strcmp(argv[1], "--get"))
-			return get_value(argv[2], argv[3]);
-		else if (!strcmp(argv[1], "--get-all")) {
-			do_all = 1;
-			return get_value(argv[2], argv[3]);
-		} else if (!strcmp(argv[1], "--get-regexp")) {
-			show_keys = 1;
-			use_key_regexp = 1;
-			do_all = 1;
-			return get_value(argv[2], argv[3]);
-		} else if (!strcmp(argv[1], "--add"))
-			return git_config_set_multivar(argv[2], argv[3], "^$", 0);
-		else if (!strcmp(argv[1], "--replace-all"))
-
-			return git_config_set_multivar(argv[2], argv[3], NULL, 1);
-		else
-
-			return git_config_set_multivar(argv[1], argv[2], argv[3], 0);
-	case 5:
-		if (!strcmp(argv[1], "--replace-all"))
-			return git_config_set_multivar(argv[2], argv[3], argv[4], 1);
-	case 1:
-	default:
-		usage(git_config_set_usage);
-	}
-	return 0;
-}
diff --git a/builtin.h b/builtin.h
index 0b3c9f6..cfe5990 100644
--- a/builtin.h
+++ b/builtin.h
@@ -53,7 +53,7 @@ extern int cmd_prune_packed(int argc, const char **argv, const char *prefix);
 extern int cmd_push(int argc, const char **argv, const char *prefix);
 extern int cmd_read_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_reflog(int argc, const char **argv, const char *prefix);
-extern int cmd_repo_config(int argc, const char **argv, const char *prefix);
+extern int cmd_config(int argc, const char **argv, const char *prefix);
 extern int cmd_rerere(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 7c7520e..83c69ec 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -145,7 +145,7 @@ __git_remotes ()
 		echo ${i#$d/remotes/}
 	done
 	[ "$ngoff" ] && shopt -u nullglob
-	for i in $(git --git-dir="$d" repo-config --list); do
+	for i in $(git --git-dir="$d" config --list); do
 		case "$i" in
 		remote.*.url=*)
 			i="${i#remote.}"
@@ -286,7 +286,7 @@ __git_commandlist="$(__git_commands 2>/dev/null)"
 __git_aliases ()
 {
 	local i IFS=$'\n'
-	for i in $(git --git-dir="$(__gitdir)" repo-config --list); do
+	for i in $(git --git-dir="$(__gitdir)" config --list); do
 		case "$i" in
 		alias.*)
 			i="${i#alias.}"
@@ -299,7 +299,7 @@ __git_aliases ()
 __git_aliased_command ()
 {
 	local word cmdline=$(git --git-dir="$(__gitdir)" \
-		repo-config --get "alias.$1")
+		config --get "alias.$1")
 	for word in $cmdline; do
 		if [ "${word##-*}" ]; then
 			echo $word
@@ -629,7 +629,7 @@ _git_rebase ()
 	COMPREPLY=($(compgen -W "$(__git_refs)" -- "$cur"))
 }
 
-_git_repo_config ()
+_git_config ()
 {
 	local cur="${COMP_WORDS[COMP_CWORD]}"
 	local prv="${COMP_WORDS[COMP_CWORD-1]}"
@@ -806,6 +806,7 @@ _git ()
 	checkout)    _git_checkout ;;
 	cherry-pick) _git_cherry_pick ;;
 	commit)      _git_commit ;;
+	config)      _git_config ;;
 	diff)        _git_diff ;;
 	diff-tree)   _git_diff_tree ;;
 	fetch)       _git_fetch ;;
@@ -819,7 +820,7 @@ _git ()
 	pull)        _git_pull ;;
 	push)        _git_push ;;
 	rebase)      _git_rebase ;;
-	repo-config) _git_repo_config ;;
+	repo-config) _git_config ;;
 	reset)       _git_reset ;;
 	show)        _git_show ;;
 	show-branch) _git_log ;;
@@ -856,7 +857,7 @@ complete -o default            -F _git_name_rev git-name-rev
 complete -o default -o nospace -F _git_pull git-pull
 complete -o default -o nospace -F _git_push git-push
 complete -o default            -F _git_rebase git-rebase
-complete -o default            -F _git_repo_config git-repo-config
+complete -o default            -F _git_config git-config
 complete -o default            -F _git_reset git-reset
 complete -o default -o nospace -F _git_show git-show
 complete -o default -o nospace -F _git_log git-show-branch
@@ -879,7 +880,7 @@ complete -o default -o nospace -F _git_ls_tree git-ls-tree.exe
 complete -o default            -F _git_merge_base git-merge-base.exe
 complete -o default            -F _git_name_rev git-name-rev.exe
 complete -o default -o nospace -F _git_push git-push.exe
-complete -o default            -F _git_repo_config git-repo-config
+complete -o default            -F _git_config git-config
 complete -o default -o nospace -F _git_show git-show.exe
 complete -o default -o nospace -F _git_log git-show-branch.exe
 complete -o default -o nospace -F _git_log git-whatchanged.exe
diff --git a/contrib/emacs/git.el b/contrib/emacs/git.el
index d90ba81..24629eb 100644
--- a/contrib/emacs/git.el
+++ b/contrib/emacs/git.el
@@ -222,7 +222,7 @@ and returns the process output as a string."
   "Return the name to use as GIT_COMMITTER_NAME."
   ; copied from log-edit
   (or git-committer-name
-      (git-repo-config "user.name")
+      (git-config "user.name")
       (and (boundp 'add-log-full-name) add-log-full-name)
       (and (fboundp 'user-full-name) (user-full-name))
       (and (boundp 'user-full-name) user-full-name)))
@@ -231,7 +231,7 @@ and returns the process output as a string."
   "Return the email address to use as GIT_COMMITTER_EMAIL."
   ; copied from log-edit
   (or git-committer-email
-      (git-repo-config "user.email")
+      (git-config "user.email")
       (and (boundp 'add-log-mailing-address) add-log-mailing-address)
       (and (fboundp 'user-mail-address) (user-mail-address))
       (and (boundp 'user-mail-address) user-mail-address)))
@@ -298,9 +298,9 @@ and returns the process output as a string."
   (git-get-string-sha1
    (git-call-process-env-string nil "rev-parse" rev)))
 
-(defun git-repo-config (key)
+(defun git-config (key)
   "Retrieve the value associated to KEY in the git repository config file."
-  (let ((str (git-call-process-env-string nil "repo-config" key)))
+  (let ((str (git-call-process-env-string nil "config" key)))
     (and str (car (split-string str "\n")))))
 
 (defun git-symbolic-ref (ref)
diff --git a/contrib/gitview/gitview b/contrib/gitview/gitview
index 3b6bdce..521b2fc 100755
--- a/contrib/gitview/gitview
+++ b/contrib/gitview/gitview
@@ -497,7 +497,7 @@ class GitView:
 		fp.close()
 
 	def get_encoding(self):
-		fp = os.popen("git repo-config --get i18n.commitencoding")
+		fp = os.popen("git config --get i18n.commitencoding")
 		self.encoding=string.strip(fp.readline())
 		fp.close()
 		if (self.encoding == ""):
diff --git a/contrib/remotes2config.sh b/contrib/remotes2config.sh
index b996996..dc09eae 100644
--- a/contrib/remotes2config.sh
+++ b/contrib/remotes2config.sh
@@ -26,8 +26,8 @@ if [ -d "$GIT_DIR"/remotes ]; then
 				mv "$GIT_DIR"/remotes "$GIT_DIR"/remotes.old
 			fi ;;
 		*)
-			echo "git-repo-config $key "$value" $regex"
-			git-repo-config $key "$value" $regex || error=1 ;;
+			echo "git-config $key "$value" $regex"
+			git-config $key "$value" $regex || error=1 ;;
 		esac
 	done
 fi
diff --git a/git-clone.sh b/git-clone.sh
index ced7dfb..1531da5 100755
--- a/git-clone.sh
+++ b/git-clone.sh
@@ -36,7 +36,7 @@ clone_dumb_http () {
 	clone_tmp="$GIT_DIR/clone-tmp" &&
 	mkdir -p "$clone_tmp" || exit 1
 	if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
-		"`git-repo-config --bool http.noEPSV`" = true ]; then
+		"`git-config --bool http.noEPSV`" = true ]; then
 		curl_extra_args="${curl_extra_args} --disable-epsv"
 	fi
 	http_fetch "$1/info/refs" "$clone_tmp/refs" ||
@@ -386,17 +386,17 @@ then
 		git-update-ref HEAD "$head_sha1" &&
 
 		# Upstream URL
-		git-repo-config remote."$origin".url "$repo" &&
+		git-config remote."$origin".url "$repo" &&
 
 		# Set up the mappings to track the remote branches.
-		git-repo-config remote."$origin".fetch \
+		git-config remote."$origin".fetch \
 			"+refs/heads/*:$remote_top/*" '^$' &&
 		rm -f "refs/remotes/$origin/HEAD"
 		git-symbolic-ref "refs/remotes/$origin/HEAD" \
 			"refs/remotes/$origin/$head_points_at" &&
 
-		git-repo-config branch."$head_points_at".remote "$origin" &&
-		git-repo-config branch."$head_points_at".merge "refs/heads/$head_points_at"
+		git-config branch."$head_points_at".remote "$origin" &&
+		git-config branch."$head_points_at".merge "refs/heads/$head_points_at"
 	esac
 
 	case "$no_checkout" in
diff --git a/git-commit.sh b/git-commit.sh
index d8c236b..85c278a 100755
--- a/git-commit.sh
+++ b/git-commit.sh
@@ -429,7 +429,7 @@ then
 	fi
 elif test "$use_commit" != ""
 then
-	encoding=$(git repo-config i18n.commitencoding || echo UTF-8)
+	encoding=$(git config i18n.commitencoding || echo UTF-8)
 	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
 	sed -e '1,/^$/d' -e 's/^    //'
 elif test -f "$GIT_DIR/MERGE_MSG"
@@ -485,7 +485,7 @@ then
 		q
 	}
 	'
-	encoding=$(git repo-config i18n.commitencoding || echo UTF-8)
+	encoding=$(git config i18n.commitencoding || echo UTF-8)
 	set_author_env=`git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
 	LANG=C LC_ALL=C sed -ne "$pick_author_script"`
 	eval "$set_author_env"
diff --git a/git-cvsserver.perl b/git-cvsserver.perl
index e18e901..9371788 100755
--- a/git-cvsserver.perl
+++ b/git-cvsserver.perl
@@ -172,11 +172,11 @@ sub req_Root
        return 0;
     }
 
-    my @gitvars = `git-repo-config -l`;
+    my @gitvars = `git-config -l`;
     if ($?) {
-       print "E problems executing git-repo-config on the server -- this is not a git repository or the PATH is not set correctly.\n";
+       print "E problems executing git-config on the server -- this is not a git repository or the PATH is not set correctly.\n";
         print "E \n";
-        print "error 1 - problem executing git-repo-config\n";
+        print "error 1 - problem executing git-config\n";
        return 0;
     }
     foreach my $line ( @gitvars )
diff --git a/git-fetch.sh b/git-fetch.sh
index 61c8cf4..c1f6e1e 100755
--- a/git-fetch.sh
+++ b/git-fetch.sh
@@ -321,7 +321,7 @@ fetch_main () {
 	      curl_extra_args="-k"
 	  fi
 	  if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
-		"`git-repo-config --bool http.noEPSV`" = true ]; then
+		"`git-config --bool http.noEPSV`" = true ]; then
 	      noepsv_opt="--disable-epsv"
 	  fi
 
diff --git a/git-instaweb.sh b/git-instaweb.sh
index 80adc83..cbc7418 100755
--- a/git-instaweb.sh
+++ b/git-instaweb.sh
@@ -15,11 +15,11 @@ case "$GIT_DIR" in
 	fqgitdir="$PWD/$GIT_DIR" ;;
 esac
 
-local="`git repo-config --bool --get instaweb.local`"
-httpd="`git repo-config --get instaweb.httpd`"
-browser="`git repo-config --get instaweb.browser`"
-port=`git repo-config --get instaweb.port`
-module_path="`git repo-config --get instaweb.modulepath`"
+local="`git config --bool --get instaweb.local`"
+httpd="`git config --get instaweb.httpd`"
+browser="`git config --get instaweb.browser`"
+port=`git config --get instaweb.port`
+module_path="`git config --get instaweb.modulepath`"
 
 conf=$GIT_DIR/gitweb/httpd.conf
 
diff --git a/git-ls-remote.sh b/git-ls-remote.sh
index dd22783..e6f574b 100755
--- a/git-ls-remote.sh
+++ b/git-ls-remote.sh
@@ -58,7 +58,7 @@ http://* | https://* | ftp://* )
             curl_extra_args="-k"
         fi
 	if [ -n "$GIT_CURL_FTP_NO_EPSV" -o \
-		"`git-repo-config --bool http.noEPSV`" = true ]; then
+		"`git-config --bool http.noEPSV`" = true ]; then
 		curl_extra_args="${curl_extra_args} --disable-epsv"
 	fi
 	curl -nsf $curl_extra_args --header "Pragma: no-cache" "$peek_repo/info/refs" ||
diff --git a/git-merge.sh b/git-merge.sh
index 7b59026..e5d6229 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -233,7 +233,7 @@ case "$use_strategies" in
 '')
 	case "$#" in
 	1)
-		var="`git-repo-config --get pull.twohead`"
+		var="`git-config --get pull.twohead`"
 		if test -n "$var"
 		then
 			use_strategies="$var"
@@ -241,7 +241,7 @@ case "$use_strategies" in
 			use_strategies="$default_twohead_strategies"
 		fi ;;
 	*)
-		var="`git-repo-config --get pull.octopus`"
+		var="`git-config --get pull.octopus`"
 		if test -n "$var"
 		then
 			use_strategies="$var"
diff --git a/git-p4import.py b/git-p4import.py
index 5c56cac..60a758b 100644
--- a/git-p4import.py
+++ b/git-p4import.py
@@ -193,13 +193,13 @@ class git_command:
 
     def get_config(self, variable):
         try:
-            return self.git("repo-config --get %s" % variable)[0].rstrip()
+            return self.git("config --get %s" % variable)[0].rstrip()
         except:
             return None
 
     def set_config(self, variable, value):
         try:
-            self.git("repo-config %s %s"%(variable, value) )
+            self.git("config %s %s"%(variable, value) )
         except:
             die("Could not set %s to " % variable, value)
 
diff --git a/git-parse-remote.sh b/git-parse-remote.sh
index 1122c83..87864fb 100755
--- a/git-parse-remote.sh
+++ b/git-parse-remote.sh
@@ -10,7 +10,7 @@ get_data_source () {
 		echo ''
 		;;
 	*)
-		if test "$(git-repo-config --get "remote.$1.url")"
+		if test "$(git-config --get "remote.$1.url")"
 		then
 			echo config
 		elif test -f "$GIT_DIR/remotes/$1"
@@ -32,7 +32,7 @@ get_remote_url () {
 		echo "$1"
 		;;
 	config)
-		git-repo-config --get "remote.$1.url"
+		git-config --get "remote.$1.url"
 		;;
 	remotes)
 		sed -ne '/^URL: */{
@@ -50,7 +50,7 @@ get_remote_url () {
 
 get_default_remote () {
 	curr_branch=$(git-symbolic-ref -q HEAD | sed -e 's|^refs/heads/||')
-	origin=$(git-repo-config --get "branch.$curr_branch.remote")
+	origin=$(git-config --get "branch.$curr_branch.remote")
 	echo ${origin:-origin}
 }
 
@@ -60,7 +60,7 @@ get_remote_default_refs_for_push () {
 	'' | branches)
 		;; # no default push mapping, just send matching refs.
 	config)
-		git-repo-config --get-all "remote.$1.push" ;;
+		git-config --get-all "remote.$1.push" ;;
 	remotes)
 		sed -ne '/^Push: */{
 			s///p
@@ -139,7 +139,7 @@ canon_refs_list_for_fetch () {
 		then
 			curr_branch=$(git-symbolic-ref -q HEAD | \
 			    sed -e 's|^refs/heads/||')
-			merge_branches=$(git-repo-config \
+			merge_branches=$(git-config \
 			    --get-all "branch.${curr_branch}.merge")
 		fi
 		if test -z "$merge_branches" && test $is_explicit != explicit
@@ -205,7 +205,7 @@ get_remote_default_refs_for_fetch () {
 		echo "HEAD:" ;;
 	config)
 		canon_refs_list_for_fetch -d "$1" \
-			$(git-repo-config --get-all "remote.$1.fetch") ;;
+			$(git-config --get-all "remote.$1.fetch") ;;
 	branches)
 		remote_branch=$(sed -ne '/#/s/.*#//p' "$GIT_DIR/branches/$1")
 		case "$remote_branch" in '') remote_branch=master ;; esac
@@ -284,7 +284,7 @@ get_uploadpack () {
 	data_source=$(get_data_source "$1")
 	case "$data_source" in
 	config)
-		uplp=$(git-repo-config --get "remote.$1.uploadpack")
+		uplp=$(git-config --get "remote.$1.uploadpack")
 		echo ${uplp:-git-upload-pack}
 		;;
 	*)
diff --git a/git-remote.perl b/git-remote.perl
index fc055b6..c813fe1 100755
--- a/git-remote.perl
+++ b/git-remote.perl
@@ -64,7 +64,7 @@ sub list_remote {
 	my ($git) = @_;
 	my %seen = ();
 	my @remotes = eval {
-		$git->command(qw(repo-config --get-regexp), '^remote\.');
+		$git->command(qw(config --get-regexp), '^remote\.');
 	};
 	for (@remotes) {
 		if (/^remote\.([^.]*)\.(\S*)\s+(.*)$/) {
@@ -103,7 +103,7 @@ sub list_branch {
 	my ($git) = @_;
 	my %seen = ();
 	my @branches = eval {
-		$git->command(qw(repo-config --get-regexp), '^branch\.');
+		$git->command(qw(config --get-regexp), '^branch\.');
 	};
 	for (@branches) {
 		if (/^branch\.([^.]*)\.(\S*)\s+(.*)$/) {
@@ -238,8 +238,8 @@ sub add_remote {
 		print STDERR "remote $name already exists.\n";
 		exit(1);
 	}
-	$git->command('repo-config', "remote.$name.url", $url);
-	$git->command('repo-config', "remote.$name.fetch",
+	$git->command('config', "remote.$name.url", $url);
+	$git->command('config', "remote.$name.fetch",
 		      "+refs/heads/*:refs/remotes/$name/*");
 }
 
diff --git a/git-repack.sh b/git-repack.sh
index da8e67f..ddfa8b4 100755
--- a/git-repack.sh
+++ b/git-repack.sh
@@ -28,7 +28,7 @@ done
 # Later we will default repack.UseDeltaBaseOffset to true
 default_dbo=false
 
-case "`git repo-config --bool repack.usedeltabaseoffset ||
+case "`git config --bool repack.usedeltabaseoffset ||
        echo $default_dbo`" in
 true)
 	extra="$extra --delta-base-offset" ;;
diff --git a/git-revert.sh b/git-revert.sh
index bb8f1ca..866d622 100755
--- a/git-revert.sh
+++ b/git-revert.sh
@@ -81,7 +81,7 @@ prev=$(git-rev-parse --verify "$commit^1" 2>/dev/null) ||
 git-rev-parse --verify "$commit^2" >/dev/null 2>&1 &&
 	die "Cannot run $me a multi-parent commit."
 
-encoding=$(git repo-config i18n.commitencoding || echo UTF-8)
+encoding=$(git config i18n.commitencoding || echo UTF-8)
 
 # "commit" is an existing commit.  We would want to apply
 # the difference it introduces since its first parent "prev"
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index 6b1c142..b4aa4b2 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -29,7 +29,7 @@ set_reflog_action() {
 }
 
 is_bare_repository () {
-	git-repo-config --bool --get core.bare ||
+	git-config --bool --get core.bare ||
 	case "$GIT_DIR" in
 	.git | */.git) echo false ;;
 	*) echo true ;;
diff --git a/git-svn.perl b/git-svn.perl
index 83ec03d..68156fc 100755
--- a/git-svn.perl
+++ b/git-svn.perl
@@ -593,7 +593,7 @@ sub multi_init {
 				      "$trunk_url ($_trunk)\n";
 			}
 			init($trunk_url);
-			command_noisy('repo-config', 'svn.trunk', $trunk_url);
+			command_noisy('config', 'svn.trunk', $trunk_url);
 		}
 	}
 	$_prefix = '' unless defined $_prefix;
@@ -772,22 +772,22 @@ sub log_use_color {
 	return 1 if $_color;
 	my ($dc, $dcvar);
 	$dcvar = 'color.diff';
-	$dc = `git-repo-config --get $dcvar`;
+	$dc = `git-config --get $dcvar`;
 	if ($dc eq '') {
 		# nothing at all; fallback to "diff.color"
 		$dcvar = 'diff.color';
-		$dc = `git-repo-config --get $dcvar`;
+		$dc = `git-config --get $dcvar`;
 	}
 	chomp($dc);
 	if ($dc eq 'auto') {
 		my $pc;
-		$pc = `git-repo-config --get color.pager`;
+		$pc = `git-config --get color.pager`;
 		if ($pc eq '') {
 			# does not have it -- fallback to pager.color
-			$pc = `git-repo-config --bool --get pager.color`;
+			$pc = `git-config --bool --get pager.color`;
 		}
 		else {
-			$pc = `git-repo-config --bool --get color.pager`;
+			$pc = `git-config --bool --get color.pager`;
 			if ($?) {
 				$pc = 'false';
 			}
@@ -800,7 +800,7 @@ sub log_use_color {
 	}
 	return 0 if $dc eq 'never';
 	return 1 if $dc eq 'always';
-	chomp($dc = `git-repo-config --bool --get $dcvar`);
+	chomp($dc = `git-config --bool --get $dcvar`);
 	return ($dc eq 'true');
 }
 
@@ -919,7 +919,7 @@ sub complete_url_ls_init {
 	waitpid $pid, 0;
 	croak $? if $?;
 	my ($n) = ($switch =~ /^--(\w+)/);
-	command_noisy('repo-config', "svn.$n", $full_url);
+	command_noisy('config', "svn.$n", $full_url);
 }
 
 sub common_prefix {
@@ -1594,7 +1594,7 @@ sub init_vars {
 	%tree_map = ();
 }
 
-# convert GetOpt::Long specs for use by git-repo-config
+# convert GetOpt::Long specs for use by git-config
 sub read_repo_config {
 	return unless -d $GIT_DIR;
 	my $opts = shift;
@@ -1602,7 +1602,7 @@ sub read_repo_config {
 		my $v = $opts->{$o};
 		my ($key) = ($o =~ /^([a-z\-]+)/);
 		$key =~ s/-//g;
-		my $arg = 'git-repo-config';
+		my $arg = 'git-config';
 		$arg .= ' --int' if ($o =~ /[:=]i$/);
 		$arg .= ' --bool' if ($o !~ /[:=][sfi]$/);
 		if (ref $v eq 'ARRAY') {
diff --git a/git.c b/git.c
index 530e99f..ec91acd 100644
--- a/git.c
+++ b/git.c
@@ -224,6 +224,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
 		{ "check-ref-format", cmd_check_ref_format },
 		{ "cherry", cmd_cherry, RUN_SETUP },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
+		{ "config", cmd_config },
 		{ "count-objects", cmd_count_objects, RUN_SETUP },
 		{ "describe", cmd_describe, RUN_SETUP },
 		{ "diff", cmd_diff, RUN_SETUP | USE_PAGER },
@@ -254,7 +255,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
 		{ "push", cmd_push, RUN_SETUP },
 		{ "read-tree", cmd_read_tree, RUN_SETUP },
 		{ "reflog", cmd_reflog, RUN_SETUP },
-		{ "repo-config", cmd_repo_config },
+		{ "repo-config", cmd_config },
 		{ "rerere", cmd_rerere, RUN_SETUP },
 		{ "rev-list", cmd_rev_list, RUN_SETUP },
 		{ "rev-parse", cmd_rev_parse, RUN_SETUP },
diff --git a/gitk b/gitk
index 031c829..31d0aad 100755
--- a/gitk
+++ b/gitk
@@ -6193,7 +6193,7 @@ set wrcomcmd "git diff-tree --stdin -p --pretty"
 
 set gitencoding {}
 catch {
-    set gitencoding [exec git repo-config --get i18n.commitencoding]
+    set gitencoding [exec git config --get i18n.commitencoding]
 }
 if {$gitencoding == ""} {
     set gitencoding "utf-8"
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 88af2e6..b606c1d 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -986,7 +986,7 @@ sub git_get_project_config {
 	$key =~ s/^gitweb\.//;
 	return if ($key =~ m/\W/);
 
-	my @x = (git_cmd(), 'repo-config');
+	my @x = (git_cmd(), 'config');
 	if (defined $type) { push @x, $type; }
 	push @x, "--get";
 	push @x, "gitweb.$key";
diff --git a/ident.c b/ident.c
index 6ad8fed..92d34e0 100644
--- a/ident.c
+++ b/ident.c
@@ -160,8 +160,8 @@ static const char *env_hint =
 "\n"
 "Run\n"
 "\n"
-"  git repo-config user.email \"you@email.com\"\n"
-"  git repo-config user.name \"Your Name\"\n"
+"  git config user.email \"you@email.com\"\n"
+"  git config user.name \"Your Name\"\n"
 "\n"
 "To set the identity in this repository.\n"
 "Add --global to set your account\'s default\n"
diff --git a/perl/Git.pm b/perl/Git.pm
index c1729ba..5d1ccaa 100644
--- a/perl/Git.pm
+++ b/perl/Git.pm
@@ -482,14 +482,14 @@ sub wc_chdir {
 
 =item config ( VARIABLE )
 
-Retrieve the configuration C<VARIABLE> in the same manner as C<repo-config>
+Retrieve the configuration C<VARIABLE> in the same manner as C<config>
 does. In scalar context requires the variable to be set only one time
 (exception is thrown otherwise), in array context returns allows the
 variable to be set multiple times and returns all the values.
 
 Must be called on a repository instance.
 
-This currently wraps command('repo-config') so it is not so fast.
+This currently wraps command('config') so it is not so fast.
 
 =cut
 
@@ -500,9 +500,9 @@ sub config {
 
 	try {
 		if (wantarray) {
-			return $self->command('repo-config', '--get-all', $var);
+			return $self->command('config', '--get-all', $var);
 		} else {
-			return $self->command_oneline('repo-config', '--get', $var);
+			return $self->command_oneline('config', '--get', $var);
 		}
 	} catch Git::Error::Command with {
 		my $E = shift;
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 0e4f32d..49b5666 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -3,13 +3,13 @@
 # Copyright (c) 2005 Johannes Schindelin
 #
 
-test_description='Test git-repo-config in different settings'
+test_description='Test git-config in different settings'
 
 . ./test-lib.sh
 
 test -f .git/config && rm .git/config
 
-git-repo-config core.penguin "little blue"
+git-config core.penguin "little blue"
 
 cat > expect << EOF
 [core]
@@ -18,7 +18,7 @@ EOF
 
 test_expect_success 'initial' 'cmp .git/config expect'
 
-git-repo-config Core.Movie BadPhysics
+git-config Core.Movie BadPhysics
 
 cat > expect << EOF
 [core]
@@ -28,7 +28,7 @@ EOF
 
 test_expect_success 'mixed case' 'cmp .git/config expect'
 
-git-repo-config Cores.WhatEver Second
+git-config Cores.WhatEver Second
 
 cat > expect << EOF
 [core]
@@ -40,7 +40,7 @@ EOF
 
 test_expect_success 'similar section' 'cmp .git/config expect'
 
-git-repo-config CORE.UPPERCASE true
+git-config CORE.UPPERCASE true
 
 cat > expect << EOF
 [core]
@@ -54,10 +54,10 @@ EOF
 test_expect_success 'similar section' 'cmp .git/config expect'
 
 test_expect_success 'replace with non-match' \
-	'git-repo-config core.penguin kingpin !blue'
+	'git-config core.penguin kingpin !blue'
 
 test_expect_success 'replace with non-match (actually matching)' \
-	'git-repo-config core.penguin "very blue" !kingpin'
+	'git-config core.penguin "very blue" !kingpin'
 
 cat > expect << EOF
 [core]
@@ -86,7 +86,7 @@ EOF
 cp .git/config .git/config2
 
 test_expect_success 'multiple unset' \
-	'git-repo-config --unset-all beta.haha'
+	'git-config --unset-all beta.haha'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -102,7 +102,7 @@ test_expect_success 'multiple unset is correct' 'cmp .git/config expect'
 mv .git/config2 .git/config
 
 test_expect_success '--replace-all' \
-	'git-repo-config --replace-all beta.haha gamma'
+	'git-config --replace-all beta.haha gamma'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -116,7 +116,7 @@ EOF
 
 test_expect_success 'all replaced' 'cmp .git/config expect'
 
-git-repo-config beta.haha alpha
+git-config beta.haha alpha
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -130,7 +130,7 @@ EOF
 
 test_expect_success 'really mean test' 'cmp .git/config expect'
 
-git-repo-config nextsection.nonewline wow
+git-config nextsection.nonewline wow
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -145,8 +145,8 @@ EOF
 
 test_expect_success 'really really mean test' 'cmp .git/config expect'
 
-test_expect_success 'get value' 'test alpha = $(git-repo-config beta.haha)'
-git-repo-config --unset beta.haha
+test_expect_success 'get value' 'test alpha = $(git-config beta.haha)'
+git-config --unset beta.haha
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -160,7 +160,7 @@ EOF
 
 test_expect_success 'unset' 'cmp .git/config expect'
 
-git-repo-config nextsection.NoNewLine "wow2 for me" "for me$"
+git-config nextsection.NoNewLine "wow2 for me" "for me$"
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -176,18 +176,18 @@ EOF
 test_expect_success 'multivar' 'cmp .git/config expect'
 
 test_expect_success 'non-match' \
-	'git-repo-config --get nextsection.nonewline !for'
+	'git-config --get nextsection.nonewline !for'
 
 test_expect_success 'non-match value' \
-	'test wow = $(git-repo-config --get nextsection.nonewline !for)'
+	'test wow = $(git-config --get nextsection.nonewline !for)'
 
 test_expect_failure 'ambiguous get' \
-	'git-repo-config --get nextsection.nonewline'
+	'git-config --get nextsection.nonewline'
 
 test_expect_success 'get multivar' \
-	'git-repo-config --get-all nextsection.nonewline'
+	'git-config --get-all nextsection.nonewline'
 
-git-repo-config nextsection.nonewline "wow3" "wow$"
+git-config nextsection.nonewline "wow3" "wow$"
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -202,15 +202,15 @@ EOF
 
 test_expect_success 'multivar replace' 'cmp .git/config expect'
 
-test_expect_failure 'ambiguous value' 'git-repo-config nextsection.nonewline'
+test_expect_failure 'ambiguous value' 'git-config nextsection.nonewline'
 
 test_expect_failure 'ambiguous unset' \
-	'git-repo-config --unset nextsection.nonewline'
+	'git-config --unset nextsection.nonewline'
 
 test_expect_failure 'invalid unset' \
-	'git-repo-config --unset somesection.nonewline'
+	'git-config --unset somesection.nonewline'
 
-git-repo-config --unset nextsection.nonewline "wow3$"
+git-config --unset nextsection.nonewline "wow3$"
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -224,12 +224,12 @@ EOF
 
 test_expect_success 'multivar unset' 'cmp .git/config expect'
 
-test_expect_failure 'invalid key' 'git-repo-config inval.2key blabla'
+test_expect_failure 'invalid key' 'git-config inval.2key blabla'
 
-test_expect_success 'correct key' 'git-repo-config 123456.a123 987'
+test_expect_success 'correct key' 'git-config 123456.a123 987'
 
 test_expect_success 'hierarchical section' \
-	'git-repo-config Version.1.2.3eX.Alpha beta'
+	'git-config Version.1.2.3eX.Alpha beta'
 
 cat > expect << EOF
 [beta] ; silly comment # another comment
@@ -255,7 +255,7 @@ version.1.2.3eX.alpha=beta
 EOF
 
 test_expect_success 'working --list' \
-	'git-repo-config --list > output && cmp output expect'
+	'git-config --list > output && cmp output expect'
 
 cat > expect << EOF
 beta.noindent sillyValue
@@ -263,9 +263,9 @@ nextsection.nonewline wow2 for me
 EOF
 
 test_expect_success '--get-regexp' \
-	'git-repo-config --get-regexp in > output && cmp output expect'
+	'git-config --get-regexp in > output && cmp output expect'
 
-git-repo-config --add nextsection.nonewline "wow4 for you"
+git-config --add nextsection.nonewline "wow4 for you"
 
 cat > expect << EOF
 wow2 for me
@@ -273,7 +273,7 @@ wow4 for you
 EOF
 
 test_expect_success '--add' \
-	'git-repo-config --get-all nextsection.nonewline > output && cmp output expect'
+	'git-config --get-all nextsection.nonewline > output && cmp output expect'
 
 cat > .git/config << EOF
 [novalue]
@@ -281,9 +281,9 @@ cat > .git/config << EOF
 EOF
 
 test_expect_success 'get variable with no value' \
-	'git-repo-config --get novalue.variable ^$'
+	'git-config --get novalue.variable ^$'
 
-git-repo-config > output 2>&1
+git-config > output 2>&1
 
 test_expect_success 'no arguments, but no crash' \
 	"test $? = 129 && grep usage output"
@@ -293,7 +293,7 @@ cat > .git/config << EOF
 	c = d
 EOF
 
-git-repo-config a.x y
+git-config a.x y
 
 cat > expect << EOF
 [a.b]
@@ -304,8 +304,8 @@ EOF
 
 test_expect_success 'new section is partial match of another' 'cmp .git/config expect'
 
-git-repo-config b.x y
-git-repo-config a.b c
+git-config b.x y
+git-config a.b c
 
 cat > expect << EOF
 [a.b]
@@ -328,11 +328,11 @@ cat > expect << EOF
 ein.bahn=strasse
 EOF
 
-GIT_CONFIG=other-config git-repo-config -l > output
+GIT_CONFIG=other-config git-config -l > output
 
 test_expect_success 'alternative GIT_CONFIG' 'cmp output expect'
 
-GIT_CONFIG=other-config git-repo-config anwohner.park ausweis
+GIT_CONFIG=other-config git-config anwohner.park ausweis
 
 cat > expect << EOF
 [ein]
@@ -355,7 +355,7 @@ weird
 EOF
 
 test_expect_success "rename section" \
-	"git-repo-config --rename-section branch.eins branch.zwei"
+	"git-config --rename-section branch.eins branch.zwei"
 
 cat > expect << EOF
 # Hallo
@@ -371,12 +371,12 @@ EOF
 test_expect_success "rename succeeded" "diff -u expect .git/config"
 
 test_expect_failure "rename non-existing section" \
-	'git-repo-config --rename-section branch."world domination" branch.drei'
+	'git-config --rename-section branch."world domination" branch.drei'
 
 test_expect_success "rename succeeded" "diff -u expect .git/config"
 
 test_expect_success "rename another section" \
-	'git-repo-config --rename-section branch."1 234 blabl/a" branch.drei'
+	'git-config --rename-section branch."1 234 blabl/a" branch.drei'
 
 cat > expect << EOF
 # Hallo
@@ -393,20 +393,20 @@ test_expect_success "rename succeeded" "diff -u expect .git/config"
 
 test_expect_success numbers '
 
-	git-repo-config kilo.gram 1k &&
-	git-repo-config mega.ton 1m &&
-	k=$(git-repo-config --int --get kilo.gram) &&
+	git-config kilo.gram 1k &&
+	git-config mega.ton 1m &&
+	k=$(git-config --int --get kilo.gram) &&
 	test z1024 = "z$k" &&
-	m=$(git-repo-config --int --get mega.ton) &&
+	m=$(git-config --int --get mega.ton) &&
 	test z1048576 = "z$m"
 '
 
 rm .git/config
 
-git-repo-config quote.leading " test"
-git-repo-config quote.ending "test "
-git-repo-config quote.semicolon "test;test"
-git-repo-config quote.hash "test#test"
+git-config quote.leading " test"
+git-config quote.ending "test "
+git-config quote.semicolon "test;test"
+git-config quote.hash "test#test"
 
 cat > expect << EOF
 [quote]
@@ -418,10 +418,10 @@ EOF
 
 test_expect_success 'quoting' 'cmp .git/config expect'
 
-test_expect_failure 'key with newline' 'git repo-config key.with\\\
+test_expect_failure 'key with newline' 'git config key.with\\\
 newline 123'
 
-test_expect_success 'value with newline' 'git repo-config key.sub value.with\\\
+test_expect_success 'value with newline' 'git config key.sub value.with\\\
 newline'
 
 cat > .git/config <<\EOF
@@ -440,7 +440,7 @@ section.noncont=not continued
 section.quotecont=cont;inued
 EOF
 
-git repo-config --list > result
+git config --list > result
 
 test_expect_success 'value continued on next line' 'cmp result expect'
 
diff --git a/t/t1400-update-ref.sh b/t/t1400-update-ref.sh
index e48e2b7..d0aba2c 100755
--- a/t/t1400-update-ref.sh
+++ b/t/t1400-update-ref.sh
@@ -93,8 +93,8 @@ rm -rf .git/$m .git/logs expect
 
 test_expect_success \
 	'enable core.logAllRefUpdates' \
-	'git-repo-config core.logAllRefUpdates true &&
-	 test true = $(git-repo-config --bool --get core.logAllRefUpdates)'
+	'git-config core.logAllRefUpdates true &&
+	 test true = $(git-config --bool --get core.logAllRefUpdates)'
 
 test_expect_success \
 	"create $m (logged by config)" \
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index 8e8d526..47d1247 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -71,7 +71,7 @@ test_expect_success setup '
 	check_fsck &&
 
 	chmod +x C &&
-	( test "`git repo-config --bool core.filemode`" != false ||
+	( test "`git config --bool core.filemode`" != false ||
 	  echo executable >>C ) &&
 	git add C &&
 	test_tick && git commit -m dragon &&
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index bb80e42..5565c27 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -94,7 +94,7 @@ test_expect_failure \
          git-branch r &&
          git-branch -m q r/q'
 
-git-repo-config branch.s/s.dummy Hello
+git-config branch.s/s.dummy Hello
 
 test_expect_success \
     'git branch -m s/s s should work when s/t is deleted' \
@@ -107,8 +107,8 @@ test_expect_success \
         test -f .git/logs/refs/heads/s'
 
 test_expect_success 'config information was renamed, too' \
-	"test $(git-repo-config branch.s.dummy) = Hello &&
-	 ! git-repo-config branch.s/s/dummy"
+	"test $(git-config branch.s.dummy) = Hello &&
+	 ! git-config branch.s/s/dummy"
 
 test_expect_failure \
     'git-branch -m u v should fail when the reflog for u is a symlink' \
diff --git a/t/t3700-add.sh b/t/t3700-add.sh
index e98786d..caaab26 100755
--- a/t/t3700-add.sh
+++ b/t/t3700-add.sh
@@ -21,7 +21,7 @@ test_expect_success \
 
 test_expect_success \
 	'git-add: Test that executable bit is not used if core.filemode=0' \
-	'git repo-config core.filemode 0 &&
+	'git config core.filemode 0 &&
 	 echo foo >xfoo1 &&
 	 chmod 755 xfoo1 &&
 	 git-add xfoo1 &&
@@ -32,7 +32,7 @@ test_expect_success \
 
 test_expect_success \
 	'git-update-index --add: Test that executable bit is not used...' \
-	'git repo-config core.filemode 0 &&
+	'git config core.filemode 0 &&
 	 echo foo >xfoo2 &&
 	 chmod 755 xfoo2 &&
 	 git-update-index --add xfoo2 &&
@@ -43,7 +43,7 @@ test_expect_success \
 
 test_expect_success \
 	'git-update-index --add: Test that executable bit is not used...' \
-	'git repo-config core.filemode 0 &&
+	'git config core.filemode 0 &&
 	 ln -s xfoo2 xfoo3 &&
 	 git-update-index --add xfoo3 &&
 	 case "`git-ls-files --stage xfoo3`" in
diff --git a/t/t3900-i18n-commit.sh b/t/t3900-i18n-commit.sh
index 6714b0d..e54fe0f 100755
--- a/t/t3900-i18n-commit.sh
+++ b/t/t3900-i18n-commit.sh
@@ -29,7 +29,7 @@ test_expect_success 'no encoding header for base case' '
 for H in ISO-8859-1 EUCJP ISO-2022-JP
 do
 	test_expect_success "$H setup" '
-		git-repo-config i18n.commitencoding $H &&
+		git-config i18n.commitencoding $H &&
 		git-checkout -b $H C0 &&
 		echo $H >F &&
 		git-commit -a -F ../t3900/$H.txt
@@ -44,16 +44,16 @@ do
 	'
 done
 
-test_expect_success 'repo-config to remove customization' '
-	git-repo-config --unset-all i18n.commitencoding &&
-	if Z=$(git-repo-config --get-all i18n.commitencoding)
+test_expect_success 'config to remove customization' '
+	git-config --unset-all i18n.commitencoding &&
+	if Z=$(git-config --get-all i18n.commitencoding)
 	then
 		echo Oops, should have failed.
 		false
 	else
 		test z = "z$Z"
 	fi &&
-	git-repo-config i18n.commitencoding utf-8
+	git-config i18n.commitencoding utf-8
 '
 
 test_expect_success 'ISO-8859-1 should be shown in UTF-8 now' '
@@ -67,9 +67,9 @@ do
 	'
 done
 
-test_expect_success 'repo-config to add customization' '
-	git-repo-config --unset-all i18n.commitencoding &&
-	if Z=$(git-repo-config --get-all i18n.commitencoding)
+test_expect_success 'config to add customization' '
+	git-config --unset-all i18n.commitencoding &&
+	if Z=$(git-config --get-all i18n.commitencoding)
 	then
 		echo Oops, should have failed.
 		false
@@ -81,13 +81,13 @@ test_expect_success 'repo-config to add customization' '
 for H in ISO-8859-1 EUCJP ISO-2022-JP
 do
 	test_expect_success "$H should be shown in itself now" '
-		git-repo-config i18n.commitencoding '$H' &&
+		git-config i18n.commitencoding '$H' &&
 		compare_with '$H' ../t3900/'$H'.txt
 	'
 done
 
-test_expect_success 'repo-config to tweak customization' '
-	git-repo-config i18n.logoutputencoding utf-8
+test_expect_success 'config to tweak customization' '
+	git-config i18n.logoutputencoding utf-8
 '
 
 test_expect_success 'ISO-8859-1 should be shown in UTF-8 now' '
@@ -103,7 +103,7 @@ done
 
 for J in EUCJP ISO-2022-JP
 do
-	git-repo-config i18n.logoutputencoding $J
+	git-config i18n.logoutputencoding $J
 	for H in EUCJP ISO-2022-JP
 	do
 		test_expect_success "$H should be shown in $J now" '
diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index eda0e2d..a881797 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -31,7 +31,7 @@ check_encoding () {
 }
 
 test_expect_success setup '
-	git-repo-config i18n.commitencoding UTF-8 &&
+	git-config i18n.commitencoding UTF-8 &&
 
 	# use UTF-8 in author and committer name to match the
 	# i18n.commitencoding settings
@@ -55,7 +55,7 @@ test_expect_success setup '
 	git commit -s -m "Second on side" &&
 
 	# the second one on the side branch is ISO-8859-1
-	git-repo-config i18n.commitencoding ISO-8859-1 &&
+	git-config i18n.commitencoding ISO-8859-1 &&
 	# use author and committer name in ISO-8859-1 to match it.
 	. ../t3901-8859-1.txt &&
 	test_tick &&
@@ -64,11 +64,11 @@ test_expect_success setup '
 	git commit -s -m "Third on side" &&
 
 	# Back to default
-	git-repo-config i18n.commitencoding UTF-8
+	git-config i18n.commitencoding UTF-8
 '
 
 test_expect_success 'format-patch output (ISO-8859-1)' '
-	git-repo-config i18n.logoutputencoding ISO-8859-1 &&
+	git-config i18n.logoutputencoding ISO-8859-1 &&
 
 	git format-patch --stdout master..HEAD^ >out-l1 &&
 	git format-patch --stdout HEAD^ >out-l2 &&
@@ -79,7 +79,7 @@ test_expect_success 'format-patch output (ISO-8859-1)' '
 '
 
 test_expect_success 'format-patch output (UTF-8)' '
-	git repo-config i18n.logoutputencoding UTF-8 &&
+	git config i18n.logoutputencoding UTF-8 &&
 
 	git format-patch --stdout master..HEAD^ >out-u1 &&
 	git format-patch --stdout HEAD^ >out-u2 &&
@@ -91,13 +91,13 @@ test_expect_success 'format-patch output (UTF-8)' '
 
 test_expect_success 'rebase (U/U)' '
 	# We want the result of rebase in UTF-8
-	git-repo-config i18n.commitencoding UTF-8 &&
+	git-config i18n.commitencoding UTF-8 &&
 
 	# The test is about logoutputencoding not affecting the
 	# final outcome -- it is used internally to generate the
 	# patch and the log.
 
-	git repo-config i18n.logoutputencoding UTF-8 &&
+	git config i18n.logoutputencoding UTF-8 &&
 
 	# The result will be committed by GIT_COMMITTER_NAME --
 	# we want UTF-8 encoded name.
@@ -109,8 +109,8 @@ test_expect_success 'rebase (U/U)' '
 '
 
 test_expect_success 'rebase (U/L)' '
-	git-repo-config i18n.commitencoding UTF-8 &&
-	git repo-config i18n.logoutputencoding ISO-8859-1 &&
+	git-config i18n.commitencoding UTF-8 &&
+	git config i18n.logoutputencoding ISO-8859-1 &&
 	. ../t3901-utf8.txt &&
 
 	git reset --hard side &&
@@ -121,8 +121,8 @@ test_expect_success 'rebase (U/L)' '
 
 test_expect_success 'rebase (L/L)' '
 	# In this test we want ISO-8859-1 encoded commits as the result
-	git-repo-config i18n.commitencoding ISO-8859-1 &&
-	git repo-config i18n.logoutputencoding ISO-8859-1 &&
+	git-config i18n.commitencoding ISO-8859-1 &&
+	git config i18n.logoutputencoding ISO-8859-1 &&
 	. ../t3901-8859-1.txt &&
 
 	git reset --hard side &&
@@ -134,8 +134,8 @@ test_expect_success 'rebase (L/L)' '
 test_expect_success 'rebase (L/U)' '
 	# This is pathological -- use UTF-8 as intermediate form
 	# to get ISO-8859-1 results.
-	git-repo-config i18n.commitencoding ISO-8859-1 &&
-	git repo-config i18n.logoutputencoding UTF-8 &&
+	git-config i18n.commitencoding ISO-8859-1 &&
+	git config i18n.logoutputencoding UTF-8 &&
 	. ../t3901-8859-1.txt &&
 
 	git reset --hard side &&
@@ -147,8 +147,8 @@ test_expect_success 'rebase (L/U)' '
 test_expect_success 'cherry-pick(U/U)' '
 	# Both the commitencoding and logoutputencoding is set to UTF-8.
 
-	git-repo-config i18n.commitencoding UTF-8 &&
-	git repo-config i18n.logoutputencoding UTF-8 &&
+	git-config i18n.commitencoding UTF-8 &&
+	git config i18n.logoutputencoding UTF-8 &&
 	. ../t3901-utf8.txt &&
 
 	git reset --hard master &&
@@ -162,8 +162,8 @@ test_expect_success 'cherry-pick(U/U)' '
 test_expect_success 'cherry-pick(L/L)' '
 	# Both the commitencoding and logoutputencoding is set to ISO-8859-1
 
-	git-repo-config i18n.commitencoding ISO-8859-1 &&
-	git repo-config i18n.logoutputencoding ISO-8859-1 &&
+	git-config i18n.commitencoding ISO-8859-1 &&
+	git config i18n.logoutputencoding ISO-8859-1 &&
 	. ../t3901-8859-1.txt &&
 
 	git reset --hard master &&
@@ -177,8 +177,8 @@ test_expect_success 'cherry-pick(L/L)' '
 test_expect_success 'cherry-pick(U/L)' '
 	# Commitencoding is set to UTF-8 but logoutputencoding is ISO-8859-1
 
-	git-repo-config i18n.commitencoding UTF-8 &&
-	git repo-config i18n.logoutputencoding ISO-8859-1 &&
+	git-config i18n.commitencoding UTF-8 &&
+	git config i18n.logoutputencoding ISO-8859-1 &&
 	. ../t3901-utf8.txt &&
 
 	git reset --hard master &&
@@ -193,8 +193,8 @@ test_expect_success 'cherry-pick(L/U)' '
 	# Again, the commitencoding is set to ISO-8859-1 but
 	# logoutputencoding is set to UTF-8.
 
-	git-repo-config i18n.commitencoding ISO-8859-1 &&
-	git repo-config i18n.logoutputencoding UTF-8 &&
+	git-config i18n.commitencoding ISO-8859-1 &&
+	git config i18n.logoutputencoding UTF-8 &&
 	. ../t3901-8859-1.txt &&
 
 	git reset --hard master &&
@@ -206,8 +206,8 @@ test_expect_success 'cherry-pick(L/U)' '
 '
 
 test_expect_success 'rebase --merge (U/U)' '
-	git-repo-config i18n.commitencoding UTF-8 &&
-	git repo-config i18n.logoutputencoding UTF-8 &&
+	git-config i18n.commitencoding UTF-8 &&
+	git config i18n.logoutputencoding UTF-8 &&
 	. ../t3901-utf8.txt &&
 
 	git reset --hard side &&
@@ -217,8 +217,8 @@ test_expect_success 'rebase --merge (U/U)' '
 '
 
 test_expect_success 'rebase --merge (U/L)' '
-	git-repo-config i18n.commitencoding UTF-8 &&
-	git repo-config i18n.logoutputencoding ISO-8859-1 &&
+	git-config i18n.commitencoding UTF-8 &&
+	git config i18n.logoutputencoding ISO-8859-1 &&
 	. ../t3901-utf8.txt &&
 
 	git reset --hard side &&
@@ -229,8 +229,8 @@ test_expect_success 'rebase --merge (U/L)' '
 
 test_expect_success 'rebase --merge (L/L)' '
 	# In this test we want ISO-8859-1 encoded commits as the result
-	git-repo-config i18n.commitencoding ISO-8859-1 &&
-	git repo-config i18n.logoutputencoding ISO-8859-1 &&
+	git-config i18n.commitencoding ISO-8859-1 &&
+	git config i18n.logoutputencoding ISO-8859-1 &&
 	. ../t3901-8859-1.txt &&
 
 	git reset --hard side &&
@@ -242,8 +242,8 @@ test_expect_success 'rebase --merge (L/L)' '
 test_expect_success 'rebase --merge (L/U)' '
 	# This is pathological -- use UTF-8 as intermediate form
 	# to get ISO-8859-1 results.
-	git-repo-config i18n.commitencoding ISO-8859-1 &&
-	git repo-config i18n.logoutputencoding UTF-8 &&
+	git-config i18n.commitencoding ISO-8859-1 &&
+	git config i18n.logoutputencoding UTF-8 &&
 	. ../t3901-8859-1.txt &&
 
 	git reset --hard side &&
diff --git a/t/t4000-diff-format.sh b/t/t4000-diff-format.sh
index 67b9681..9c58d77 100755
--- a/t/t4000-diff-format.sh
+++ b/t/t4000-diff-format.sh
@@ -28,7 +28,7 @@ test_expect_success \
     'git-diff-files -p >current'
 
 # that's as far as it comes
-if [ "$(git repo-config --get core.filemode)" = false ]
+if [ "$(git config --get core.filemode)" = false ]
 then
 	say 'filemode disabled on the filesystem'
 	test_done
diff --git a/t/t4006-diff-mode.sh b/t/t4006-diff-mode.sh
index 8ad69d1..ca342f4 100755
--- a/t/t4006-diff-mode.sh
+++ b/t/t4006-diff-mode.sh
@@ -15,7 +15,7 @@ test_expect_success \
      tree=`git-write-tree` &&
      echo $tree'
 
-if [ "$(git repo-config --get core.filemode)" = false ]
+if [ "$(git config --get core.filemode)" = false ]
 then
 	say 'filemode disabled on the filesystem, using update-index --chmod=+x'
 	test_expect_success \
diff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh
index ed37141..3d85cea 100755
--- a/t/t4013-diff-various.sh
+++ b/t/t4013-diff-various.sh
@@ -73,7 +73,7 @@ test_expect_success setup '
 	for i in 1 2; do echo $i; done >>dir/sub &&
 	git update-index file0 dir/sub &&
 
-	git repo-config log.showroot false &&
+	git config log.showroot false &&
 	git commit --amend &&
 	git show-branch
 '
diff --git a/t/t4102-apply-rename.sh b/t/t4102-apply-rename.sh
index 22da6a0..b4662b0 100755
--- a/t/t4102-apply-rename.sh
+++ b/t/t4102-apply-rename.sh
@@ -31,7 +31,7 @@ test_expect_success setup \
 test_expect_success apply \
     'git-apply --index --stat --summary --apply test-patch'
 
-if [ "$(git repo-config --get core.filemode)" = false ]
+if [ "$(git config --get core.filemode)" = false ]
 then
 	say 'filemode disabled on the filesystem'
 else
diff --git a/t/t5301-sliding-window.sh b/t/t5301-sliding-window.sh
index 5a7232a..a6dbb04 100755
--- a/t/t5301-sliding-window.sh
+++ b/t/t5301-sliding-window.sh
@@ -30,19 +30,19 @@ test_expect_success \
 
 test_expect_success \
     'verify-pack -v, packedGitWindowSize == 1 page' \
-    'git-repo-config core.packedGitWindowSize 512 &&
+    'git-config core.packedGitWindowSize 512 &&
      git-verify-pack -v "$pack1"'
 
 test_expect_success \
     'verify-pack -v, packedGit{WindowSize,Limit} == 1 page' \
-    'git-repo-config core.packedGitWindowSize 512 &&
-     git-repo-config core.packedGitLimit 512 &&
+    'git-config core.packedGitWindowSize 512 &&
+     git-config core.packedGitLimit 512 &&
      git-verify-pack -v "$pack1"'
 
 test_expect_success \
     'repack -a -d, packedGit{WindowSize,Limit} == 1 page' \
-    'git-repo-config core.packedGitWindowSize 512 &&
-     git-repo-config core.packedGitLimit 512 &&
+    'git-config core.packedGitWindowSize 512 &&
+     git-config core.packedGitLimit 512 &&
      commit2=`git-commit-tree $tree -p $commit1 </dev/null` &&
      git-update-ref HEAD $commit2 &&
      git-repack -a -d &&
@@ -53,8 +53,8 @@ test_expect_success \
 
 test_expect_success \
     'verify-pack -v, defaults' \
-    'git-repo-config --unset core.packedGitWindowSize &&
-     git-repo-config --unset core.packedGitLimit &&
+    'git-config --unset core.packedGitWindowSize &&
+     git-config --unset core.packedGitLimit &&
      git-verify-pack -v "$pack2"'
 
 test_done
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 2c15191..7d93d0d 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -106,7 +106,7 @@ export HOME ;# this way we force the victim/.git/config to be used.
 test_expect_success \
         'pushing with --force should be denied with denyNonFastforwards' '
 	cd victim &&
-	git-repo-config receive.denyNonFastforwards true &&
+	git-config receive.denyNonFastforwards true &&
 	cd .. &&
 	git-update-ref refs/heads/master master^ &&
 	git-send-pack --force ./victim/.git/ master &&
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 058cce0..e35d60f 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -98,7 +98,7 @@ pull_to_client () {
 	mkdir client &&
 	cd client &&
 	git-init 2>> log2.txt &&
-	git repo-config transfer.unpacklimit 0
+	git config transfer.unpacklimit 0
 )
 
 add A1
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 3ce9446..50c6485 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -22,14 +22,14 @@ test_expect_success "clone and setup child repos" '
 	cd .. &&
 	git clone . two &&
 	cd two &&
-	git repo-config branch.master.remote one &&
-	git repo-config remote.one.url ../one/.git/ &&
-	git repo-config remote.one.fetch refs/heads/master:refs/heads/one &&
+	git config branch.master.remote one &&
+	git config remote.one.url ../one/.git/ &&
+	git config remote.one.fetch refs/heads/master:refs/heads/one &&
 	cd .. &&
 	git clone . three &&
 	cd three &&
-	git repo-config branch.master.remote two &&
-	git repo-config branch.master.merge refs/heads/one &&
+	git config branch.master.remote two &&
+	git config branch.master.merge refs/heads/one &&
 	mkdir -p .git/remotes &&
 	{
 		echo "URL: ../two/.git/"
diff --git a/t/t6200-fmt-merge-msg.sh b/t/t6200-fmt-merge-msg.sh
index 63e49f3..ea14023 100755
--- a/t/t6200-fmt-merge-msg.sh
+++ b/t/t6200-fmt-merge-msg.sh
@@ -108,7 +108,7 @@ EOF
 
 test_expect_success 'merge-msg test #3' '
 
-	git repo-config merge.summary true &&
+	git config merge.summary true &&
 
 	git checkout master &&
 	setdate &&
@@ -138,7 +138,7 @@ EOF
 
 test_expect_success 'merge-msg test #4' '
 
-	git repo-config merge.summary true &&
+	git config merge.summary true &&
 
 	git checkout master &&
 	setdate &&
@@ -150,7 +150,7 @@ test_expect_success 'merge-msg test #4' '
 
 test_expect_success 'merge-msg test #5' '
 
-	git repo-config merge.summary yes &&
+	git config merge.summary yes &&
 
 	git checkout master &&
 	setdate &&
-- 
1.5.0.rc2.g5355

^ permalink raw reply related	[relevance 2%]

* Re: newbie questions about git design and features (some wrt hg)
  @ 2007-01-30 16:55  2% ` Shawn O. Pearce
  0 siblings, 0 replies; 200+ results
From: Shawn O. Pearce @ 2007-01-30 16:55 UTC (permalink / raw)
  To: Mike Coleman; +Cc: git

Mike Coleman <tutufan@gmail.com> wrote:
> 1.  As of today, is there any real safety concern with either tool's
> repo format?  Is either tool significantly better in this regard?
> (Keith Packard's post hints at a problem here, but doesn't really make
> the case.)

I think the Git format is tighter in terms of compression,
and simpler in terms of understanding and writing code.  I have
personally written the code to read and write the Git repository
format in both C and Java, and in both cases it falls out in just
a few hundred lines of code (assuming you have libz handy to do
the compression/decompression for you).

The Git format is completely safe with regards to parallel
modification of a repository, which is good for shared repositories
that might have multiple people pushing into it at once.

Git's format is also safe with regards to *any* update.
You literally cannot destroy the repository during an update.
Its impossible.  You'd have to physically destroy the storage device.
(OK, that's overstating it a bit, but it is really hard.)

The point Keith was making was the Git format is "add-only".
Once something has been stored, we NEVER modify it again.  This
bypasses any sort of possible problems that can occur with partial
modifications caused by a process aborting in the middle of a change.

I think hg modifies files as it goes, which could cause some issues
when a writer is aborted.  I'm sure they have thought about the
problem and tried to make it safe, but there isn't anything safer
than just leaving the damn thing alone.  :)
 
> 2.  Does the git packed object format solve the performance problem
> alluded to in posts from a year or two ago?

Yes.  By a huge margin.  Git's *fast*.  Ignore anything from a year
or two ago.
 
> 3.  Someone mentioned that git bisect can work between any two
> commits, not necessarily just one that happens to be an ancestor of
> the other.  This sounds really cool.  Can hg's bisect do this, too?

No clue.
 
> 4.  What is git's index good for?  I find that I like the idea of it,
> but I'm not sure I could justify it's presence to someone else, as
> opposed to having it hidden in the way that hg's dircache (?) is.  Can
> anyone think of a good scenario where it's a pretty obvious benefit?

Its a good way to stage the stuff in your next commit.  By that I
mean you edit some code.  Then you look at what differs between the
index and your working directory.  You decide "this hunk is good, it
passed the tests, I want to commit that, so toss it into the index".
Now that hunk isn't different anymore.

When it comes time to commit, all of your already reviewed stuff is
staged in the index.  You just need to issue a commit and supply
the message.  But you can leave modified stuff in the working
directory, even for files that were alerady updated in the index.

This really helps during a merge.  Only the stuff which Git could
not merge for you is seen as different between the index and the
working directory; all of the stuff that Git merged for you is
already staged in the index.  So you can focus on the conflicts,
and stage their resolutions into the index as you go.  This makes
it easier to work through larger merges where more than 1 or 2
files contains conflicts.

> 5.  I think I read that there'd been just one incompatible change over
> time in the git repo format.  What was it?

A LONG time ago, like in the very first version Linus offered out
to the public, we computed the identity of an object using the
SHA-1 hash of the *compressed* data.  This is sensitive to the
compression settings used, and was not the best idea as a result.

It was very quickly changed to compute the identity of the object
using the SHA-1 has of the raw (user) data, removing any dependence
on the compression routine to always yield the same result for the
same input.

We haven't had a change since then.  We have added some new
compression options which are just that, options.  If you use them
older Git binaries won't necessarily recognize the repository data,
but these are off by default and can be enabled on a per-repository
basis.  E.g. if you are only using newer Git on a given system you
can enable the newer compression features on all of the repositories
on that system.
 
> 6.  Does either tool use hard links?  This matters to me because I do
> development on a connected machine and a disconnected machine, using a
> usb drive to rsync between.  (Perhaps there'll be some way to transfer
> changes using git or hg instead of rsync, but I haven't figured that
> out yet.)

Git can use hardlinks if you ask it to.  We only use them for the
repository files, not for the user's actual source files.

Git has its own native transport (git-push, git-fetch) which can
move data between two Git repositories via local filesystem access,
SSH, HTTP, FTP, and rsync (latter two are read-only transports).
 
> 7.  I'm a fan of Python, and I'm really a fan of using high-level
> languages with performance-critical parts in a lower-level language,
> so in that regard, I really like hg's implementation.  If someone
> wanted to do it, is a Python clone of git conceivable?  Is there
> something about it that just requires C?

Yes, a Python clone of Git is conceivable.  Indeed, there is a
pure Java clone in process (jgit) for an Eclipse plugin (egit).
If you wanted to rewrite Git in Python, knock yourself out.
But we've ported all of our Python to C, as its just faster.
 
> 8.  It feels like hg is not really comfortable with parallel
> development over time on different heads within a single repo.
> Rather, it seems that multiple repos are supposed to be used for this.
> Does this lead to any problems?  For example, is it harder or
> different to merge two heads if they're in different repo than if
> they're in the same repo?

No clue.  I know multiple heads in one Git repository works
*awesome*.  Especially on large repositories (>10k files) as the time
required to start a new branch is only the time needed to update the
files in the working directory which don't have the correct version.
Usually that's a small percentage (<200) of the files and thus its
very fast to switch to a new branch of development, and switch back.

On a decent UNIX system (and my Mac OS X PowerBook doesn't really
count) flipping branches in git-gui is almost immediate.  You pick
the branch in the menu and *wham* its switched.  And that's my
PowerBook, which as I said, doesn't quite count as good UNIX
system...

-- 
Shawn.

^ permalink raw reply	[relevance 2%]

* Re: restriction of pulls
  @ 2007-02-09 15:32  2%   ` Rogan Dawes
  2007-02-09 16:19  5%     ` Andy Parkins
    0 siblings, 2 replies; 200+ results
From: Rogan Dawes @ 2007-02-09 15:32 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Christoph Duelli, git

Johannes Schindelin wrote:
> Hi,
> 
> On Fri, 9 Feb 2007, Christoph Duelli wrote:
> 
>> Is it possible to restrict a chechout, clone or a later pull to some 
>> subdirectory of a repository?
> 
> No. In git, a revision really is a revision, and not a group of file 
> revisions.
> 
> Ciao,
> Dscho
> 

I thought about how this might be implemented, although I'm not entirely 
sure how efficient this will be.

One obstacle to implementing partial checkouts is that one does not know 
which objects have changed or been deleted. One way of addressing this 
is to keep a record of the hashes of all the objects that were NOT 
checked out. (If one does not check out part of a directory, simply 
store the hash of the top level, and you do not need to store the child 
hashes.) This record would be a kind of "negative index".

When deciding what to check in, or which files are modified, one would 
check the "negative index" first to see if an entry exists. If not, only 
then would you check the filesystem to see if modification times have 
changed. With the "negative index", and the files in the file system, 
one would be able to construct new commits, without any problem.

It would also require an updated transfer protocol, which would allow 
the client to specify a tag/commit, then walk the tree that it points to 
to find the portion that the client is looking for, then pull only those 
objects (and possibly their history). This is likely to be VERY 
inefficient in terms of round trips, at least initially.

This might be able to benefit from the shallow checkout support that was 
recently implemented.

Comments?

Rogan

^ permalink raw reply	[relevance 2%]

* Re: restriction of pulls
  2007-02-09 15:32  2%   ` Rogan Dawes
@ 2007-02-09 16:19  5%     ` Andy Parkins
    1 sibling, 0 replies; 200+ results
From: Andy Parkins @ 2007-02-09 16:19 UTC (permalink / raw)
  To: git; +Cc: Rogan Dawes, Johannes Schindelin, Christoph Duelli

On Friday 2007 February 09 15:32, Rogan Dawes wrote:

> One obstacle to implementing partial checkouts is that one does not know
> which objects have changed or been deleted. One way of addressing this

Why would you want to do a partial checkout.  I used subversion for a long 
time before git, which does to partial checkouts and it's a nightmare.

Things like this

 cd dir1/
 edit files
 cd ../dir2
 edit files
 svn commit
 * committed revision 100

KABLAM!  Disaster.  Revision 100 no longer compiles/runs.  The changes in dir1 
and dir2 were complimentary changes (say like renaming a function and then 
the places that call that function).

I didn't even notice how awful it was until I started using git and had a VCS 
that did the right thing.

In every way that matters you can do a partial checkout - I can pull any 
version of any file out of the repository.  However, it should certainly not 
be the case that git records that fact.

I think what you're actually after (from your description) is a shallow clone.  
I believe that went in a while ago from Dscho.

 $ git clone --depth=5 <someurl>

Will fetch only the last 5 revisions from the remote.  The other half to that 
is a shallow-by-tree clone; that is anathema to git as there is no such thing 
as a partial tree.  Submodule support is what you want, but that's still in 
development.

The only piece that (I think) is missing to get the functionality you want is 
a kind of lazy transfer mode.  For something like, say, the kde repository 
you can do

 svn checkout svn://svn.kde.org/kde/some/deep/path/in/the/project

And just get that directory - i.e. you don't have to pay the cost of 
downloading the whole of KDE.  Git can't do that; however, I think one day it 
will be able to by choosing not to download every object from the remote.


Andy
-- 
Dr Andy Parkins, M Eng (hons), MIEE
andyparkins@gmail.com

^ permalink raw reply	[relevance 5%]

* Re: restriction of pulls
  @ 2007-02-12 13:58  3%       ` Rogan Dawes
    0 siblings, 1 reply; 200+ results
From: Rogan Dawes @ 2007-02-12 13:58 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Rogan Dawes, Christoph Duelli, git

Johannes Schindelin wrote:
> Hi,
> 
> On Fri, 9 Feb 2007, Rogan Dawes wrote:
> 
>> Johannes Schindelin wrote:
>>> On Fri, 9 Feb 2007, Christoph Duelli wrote:
>>>
>>>> Is it possible to restrict a chechout, clone or a later pull to some 
>>>> subdirectory of a repository?
>>> No. In git, a revision really is a revision, and not a group of file 
>>> revisions.
>> I thought about how this might be implemented, although I'm not entirely 
>> sure how efficient this will be.
> 
> There are basically three ways I can think of:
> 
> - rewrite the commit objects on the fly. You might want to avoid the use 
> of the pack protocol here (i.e. use HTTP or FTP transport).
> 
> - try to teach git a way to ignore certain missing objects and 
> directories. This might be involved, but you could extend upload-pack 
> easily with a new extension for that.
> 
> (my favourite:)
> - use git-split to create a new branch, which only contains doc/. Do work 
> only on that branch, and merge into mainline from time to time.
> 
> If you don't need the history, you don't need to git-split the branch.
> 
> You only need to make sure that the newly created branch is _not_ branched 
> off of mainline, since the next merge would _delete_ all files outside of 
> doc/ (merge would see that the files exist in mainline, and existed in the 
> common ancestor, too, so would think that the files were deleted in the 
> doc branch).
> 
> Ciao,
> Dscho
> 

Your third option sounds quite clever, apart from the problem of 
attributing a commit and a commit message to someone, when the actual 
commit doesn't match what they actually did :-(

As well as wondering what happens when they check out a few more files. 
Do we rewrite those commits as well? What happens if the user has made 
some commits already? What happens if they have already sent those 
upstream? etc.

I think the best solution is ultimately to make git able to cope with 
certain missing objects.

I started writing this in response to another message, but it will do 
fine here, too:

The description I give here will likely horrify people in terms of 
communications inefficiency, but I'm sure that can be improved.

Scenario:

A user sees a documentation bug in a git-managed project, and decides 
that she wants to do something about it. Since she is not on the fastest 
of connections, she'd like to reduce the checkout to a reasonable 
minimum, while still working with the git tools.

Viewing the repo layout using gitweb, she sees that all the 
documentation is stored in the docs/ directory from the root.

So, she creates a local repo to work in:

$ git init-db

She configures her local repo to reference the source one:

(Hypothetical syntax)
$ git clone --reference http://example.com/project.git \
     http://example.com/project.git

Since the reference and repo are the same (and non-local), git doesn't 
actually download anything, other than the current heads (and maybe tags).

She then does a partial checkout of the master branch, but only the 
docs/ directory:

$ git checkout -p master docs/

The -p flag indicates that this is a partial checkout of master. Git 
records that the current HEAD is "master", checks out the docs/ 
directory, and removes any other files in the working directory (that it 
knew about from the existing index, if any - I'm not suggesting that it 
should arbitrarily delete files!)

The checkout process goes as follows: Resolve the <treeish> that HEAD 
points to, and retrieve it from the upstream repo if it does not exist 
locally. Continue requesting only the necessary tree and blob objects to 
satisfy the requested checkout. i.e. From the first tree, identify the 
docs/ directory. Then request only that tree object. Continue to 
download tree and blob objects until the entire docs/ directory can be 
created in the working directory.

This will likely require a new index file format, that simply stores the 
hashes of objects (blobs or trees) that have not been checked out, as 
well as the current file's stat information.

Now create a "negative index" (pindex?) that has details about the other 
files and directories that were not checked out. Obviously, this does 
not need to recurse into directories that were not checked out. Simply 
having the hash of the parent directory in the pindex is sufficient 
information to reconstruct a new index. (This might require a new index 
format that does not include all known files, but simply stores the hash 
of the unchecked-out tree or blob.)

Then creating a new commit would require creating the necessary blobs 
for changed files, new tree objects for trees that change, and a commit 
object.

As far as I can tell, that could then be pushed/pulled/merged using the 
existing tools, without any problems.

Rogan

^ permalink raw reply	[relevance 3%]

* Re: restriction of pulls
  @ 2007-02-12 14:29  4%           ` Rogan Dawes
  0 siblings, 0 replies; 200+ results
From: Rogan Dawes @ 2007-02-12 14:29 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Christoph Duelli, git

Johannes Schindelin wrote:
> Hi,
> 
> On Mon, 12 Feb 2007, Rogan Dawes wrote:
> 
>> Johannes Schindelin wrote:
>>> (my favourite:)
>>> - use git-split to create a new branch, which only contains doc/. Do work
>>> only on that branch, and merge into mainline from time to time.
>> Your third option sounds quite clever, apart from the problem of attributing a
>> commit and a commit message to someone, when the actual commit doesn't match
>> what they actually did :-(
> 
> This problem is not related to subprojects at all. If the commit message 
> does not match the patch, you are always fscked.

Well, I was thinking about the fact that the files originally checked in 
will not match the files "checked in" in the rewritten commit.

>> As well as wondering what happens when they check out a few more files. Do we
>> rewrite those commits as well? What happens if the user has made some commits
>> already? What happens if they have already sent those upstream? etc.
> 
> I think you misunderstood. My favourite option would make docs a 
> _separate_ project, with its own history. It just happens to be pulled 
> from time to time, just like git-gui, gitk and git-fast-import in git.git.

I see. However, that does not allow for the random single-file checkout 
scenario I sketched out. Which may or may not be common/desirable, but 
it is an extreme case of the partial checkout, without fixed delineation.

>> I think the best solution is ultimately to make git able to cope with 
>> certain missing objects.
> 
> Hmm. I am not convinced. On nice thing about git is its level of 
> integrity. Which means that no random objects are missing.

Good point. :-(

>> I started writing this in response to another message, but it will do fine
>> here, too:
>>
>> The description I give here will likely horrify people in terms of
>> communications inefficiency, but I'm sure that can be improved.
>>
>> [goes on... and describes the lazy clone!]
 >
> AFAICT this really is the lazy clone. And it was already determined that 
> it is all to easy to pull in all commit objects by accident. Which boils 
> down to a substantial chunk of the repository.
>

Not so much a lazy clone as a partial clone. It is only in the "clone", 
"fetch" or "checkout" code paths that new objects will be retrieved from 
the source repo. Things like "git log"/"git show" would not do so, and 
would be required to handle missing objects gracefully.

> But if you want to play with it: by all means, go ahead. It might just be 
> that you overcome the fundamental difficulties, and we get something nice 
> out of it.
> 
> Ciao,
> Dscho
> 

Maybe ;-) We'll see if I get any time for it.

Rogan

^ permalink raw reply	[relevance 4%]

* [ANNOUNCE] GIT 1.5.0
@ 2007-02-14  3:14  2% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2007-02-14  3:14 UTC (permalink / raw)
  To: git; +Cc: linux-kernel


The latest feature release GIT 1.5.0 is available at the usual places:

  http://www.kernel.org/pub/software/scm/git/

  git-1.5.0.tar.{gz,bz2}			(tarball)
  git-htmldocs-1.5.0.tar.{gz,bz2}		(preformatted docs)
  git-manpages-1.5.0.tar.{gz,bz2}		(preformatted docs)
  RPMS/$arch/git-*-1.5.0-1.$arch.rpm	(RPM)

----------------------------------------------------------------

GIT v1.5.0 Release Notes
========================

Old news
--------

This section is for people who are upgrading from ancient
versions of git.  Although all of the changes in this section
happened before the current v1.4.4 release, they are summarized
here in the v1.5.0 release notes for people who skipped earlier
versions.

As of git v1.5.0 there are some optional features that changes
the repository to allow data to be stored and transferred more
efficiently.  These features are not enabled by default, as they
will make the repository unusable with older versions of git.
Specifically, the available options are:

 - There is a configuration variable core.legacyheaders that
   changes the format of loose objects so that they are more
   efficient to pack and to send out of the repository over git
   native protocol, since v1.4.2.  However, loose objects
   written in the new format cannot be read by git older than
   that version; people fetching from your repository using
   older clients over dumb transports (e.g. http) using older
   versions of git will also be affected.

 - Since v1.4.3, configuration repack.usedeltabaseoffset allows
   packfile to be created in more space efficient format, which
   cannot be read by git older than that version.

The above two are not enabled by default and you explicitly have
to ask for them, because these two features make repositories
unreadable by older versions of git, and in v1.5.0 we still do
not enable them by default for the same reason.  We will change
this default probably 1 year after 1.4.2's release, when it is
reasonable to expect everybody to have new enough version of
git.

 - 'git pack-refs' appeared in v1.4.4; this command allows tags
   to be accessed much more efficiently than the traditional
   'one-file-per-tag' format.  Older git-native clients can
   still fetch from a repository that packed and pruned refs
   (the server side needs to run the up-to-date version of git),
   but older dumb transports cannot.  Packing of refs is done by
   an explicit user action, either by use of "git pack-refs
   --prune" command or by use of "git gc" command.

 - 'git -p' to paginate anything -- many commands do pagination
   by default on a tty.  Introduced between v1.4.1 and v1.4.2;
   this may surprise old timers.

 - 'git archive' superseded 'git tar-tree' in v1.4.3;

 - 'git cvsserver' was new invention in v1.3.0;

 - 'git repo-config', 'git grep', 'git rebase' and 'gitk' were
   seriously enhanced during v1.4.0 timeperiod.

 - 'gitweb' became part of git.git during v1.4.0 timeperiod and
   seriously modified since then.

 - reflog is an v1.4.0 invention.  This allows you to name a
   revision that a branch used to be at (e.g. "git diff
   master@{yesterday} master" allows you to see changes since
   yesterday's tip of the branch).


Updates in v1.5.0 since v1.4.4 series
-------------------------------------

* Index manipulation

 - git-add is to add contents to the index (aka "staging area"
   for the next commit), whether the file the contents happen to
   be is an existing one or a newly created one.

 - git-add without any argument does not add everything
   anymore.  Use 'git-add .' instead.  Also you can add
   otherwise ignored files with an -f option.

 - git-add tries to be more friendly to users by offering an
   interactive mode ("git-add -i").

 - git-commit <path> used to refuse to commit if <path> was
   different between HEAD and the index (i.e. update-index was
   used on it earlier).  This check was removed.

 - git-rm is much saner and safer.  It is used to remove paths
   from both the index file and the working tree, and makes sure
   you are not losing any local modification before doing so.

 - git-reset <tree> <paths>... can be used to revert index
   entries for selected paths.

 - git-update-index is much less visible.  Many suggestions to
  use the command in git output and documentation have now been
  replaced by simpler commands such as "git add" or "git rm".


* Repository layout and objects transfer

 - The data for origin repository is stored in the configuration
   file $GIT_DIR/config, not in $GIT_DIR/remotes/, for newly
   created clones.  The latter is still supported and there is
   no need to convert your existing repository if you are
   already comfortable with your workflow with the layout.

 - git-clone always uses what is known as "separate remote"
   layout for a newly created repository with a working tree.

   A repository with the separate remote layout starts with only
   one default branch, 'master', to be used for your own
   development.  Unlike the traditional layout that copied all
   the upstream branches into your branch namespace (while
   renaming their 'master' to your 'origin'), the new layout
   puts upstream branches into local "remote-tracking branches"
   with their own namespace. These can be referenced with names
   such as "origin/$upstream_branch_name" and are stored in
   .git/refs/remotes rather than .git/refs/heads where normal
   branches are stored.

   This layout keeps your own branch namespace less cluttered,
   avoids name collision with your upstream, makes it possible
   to automatically track new branches created at the remote
   after you clone from it, and makes it easier to interact with
   more than one remote repository (you can use "git remote" to
   add other repositories to track).  There might be some
   surprises:

   * 'git branch' does not show the remote tracking branches.
     It only lists your own branches.  Use '-r' option to view
     the tracking branches.

   * If you are forking off of a branch obtained from the
     upstream, you would have done something like 'git branch
     my-next next', because traditional layout dropped the
     tracking branch 'next' into your own branch namespace.
     With the separate remote layout, you say 'git branch next
     origin/next', which allows you to use the matching name
     'next' for your own branch.  It also allows you to track a
     remote other than 'origin' (i.e. where you initially cloned
     from) and fork off of a branch from there the same way
     (e.g. "git branch mingw j6t/master").

   Repositories initialized with the traditional layout continue
   to work.

 - New branches that appear on the origin side after a clone is
   made are also tracked automatically.  This is done with an
   wildcard refspec "refs/heads/*:refs/remotes/origin/*", which
   older git does not understand, so if you clone with 1.5.0,
   you would need to downgrade remote.*.fetch in the
   configuration file to specify each branch you are interested
   in individually if you plan to fetch into the repository with
   older versions of git (but why would you?).

 - Similarly, wildcard refspec "refs/heads/*:refs/remotes/me/*"
   can be given to "git-push" command to update the tracking
   branches that is used to track the repository you are pushing
   from on the remote side.

 - git-branch and git-show-branch know remote tracking branches
   (use the command line switch "-r" to list only tracked branches).

 - git-push can now be used to delete a remote branch or a tag.
   This requires the updated git on the remote side (use "git
   push <remote> :refs/heads/<branch>" to delete "branch").

 - git-push more aggressively keeps the transferred objects
   packed.  Earlier we recommended to monitor amount of loose
   objects and repack regularly, but you should repack when you
   accumulated too many small packs this way as well.  Updated
   git-count-objects helps you with this.

 - git-fetch also more aggressively keeps the transferred objects
   packed.  This behavior of git-push and git-fetch can be
   tweaked with a single configuration transfer.unpacklimit (but
   usually there should not be any need for a user to tweak it).

 - A new command, git-remote, can help you manage your remote
   tracking branch definitions.

 - You may need to specify explicit paths for upload-pack and/or
   receive-pack due to your ssh daemon configuration on the
   other end.  This can now be done via remote.*.uploadpack and
   remote.*.receivepack configuration.


* Bare repositories

 - Certain commands change their behavior in a bare repository
   (i.e. a repository without associated working tree).  We use
   a fairly conservative heuristic (if $GIT_DIR is ".git", or
   ends with "/.git", the repository is not bare) to decide if a
   repository is bare, but "core.bare" configuration variable
   can be used to override the heuristic when it misidentifies
   your repository.

 - git-fetch used to complain updating the current branch but
   this is now allowed for a bare repository.  So is the use of
   'git-branch -f' to update the current branch.

 - Porcelain-ish commands that require a working tree refuses to
   work in a bare repository.


* Reflog

 - Reflog records the history from the view point of the local
   repository. In other words, regardless of the real history,
   the reflog shows the history as seen by one particular
   repository (this enables you to ask "what was the current
   revision in _this_ repository, yesterday at 1pm?").  This
   facility is enabled by default for repositories with working
   trees, and can be accessed with the "branch@{time}" and
   "branch@{Nth}" notation.

 - "git show-branch" learned showing the reflog data with the
   new -g option.  "git log" has -s option to view reflog
   entries in a more verbose manner.

 - git-branch knows how to rename branches and moves existing
   reflog data from the old branch to the new one.

 - In addition to the reflog support in v1.4.4 series, HEAD
   reference maintains its own log.  "HEAD@{5.minutes.ago}"
   means the commit you were at 5 minutes ago, which takes
   branch switching into account.  If you want to know where the
   tip of your current branch was at 5 minutes ago, you need to
   explicitly say its name (e.g. "master@{5.minutes.ago}") or
   omit the refname altogether i.e. "@{5.minutes.ago}".

 - The commits referred to by reflog entries are now protected
   against pruning.  The new command "git reflog expire" can be
   used to truncate older reflog entries and entries that refer
   to commits that have been pruned away previously with older
   versions of git.

   Existing repositories that have been using reflog may get
   complaints from fsck-objects and may not be able to run
   git-repack, if you had run git-prune from older git; please
   run "git reflog expire --stale-fix --all" first to remove
   reflog entries that refer to commits that are no longer in
   the repository when that happens.


* Crufts removal

 - We used to say "old commits are retrievable using reflog and
   'master@{yesterday}' syntax as long as you haven't run
   git-prune".  We no longer have to say the latter half of the
   above sentence, as git-prune does not remove things reachable
   from reflog entries.

 - 'git-prune' by default does not remove _everything_
   unreachable, as there is a one-day grace period built-in.

 - There is a toplevel garbage collector script, 'git-gc', that
   runs periodic cleanup functions, including 'git-repack -a -d',
   'git-reflog expire', 'git-pack-refs --prune', and 'git-rerere
   gc'.

 - The output from fsck ("fsck-objects" is called just "fsck"
   now, but the old name continues to work) was needlessly
   alarming in that it warned missing objects that are reachable
   only from dangling objects.  This has been corrected and the
   output is much more useful.


* Detached HEAD

 - You can use 'git-checkout' to check out an arbitrary revision
   or a tag as well, instead of named branches.  This will
   dissociate your HEAD from the branch you are currently on.

   A typical use of this feature is to "look around".  E.g.

	$ git checkout v2.6.16
	... compile, test, etc.
	$ git checkout v2.6.17
	... compile, test, etc.

 - After detaching your HEAD, you can go back to an existing
   branch with usual "git checkout $branch".  Also you can
   start a new branch using "git checkout -b $newbranch" to
   start a new branch at that commit.

 - You can even pull from other repositories, make merges and
   commits while your HEAD is detached.  Also you can use "git
   reset" to jump to arbitrary commit, while still keeping your
   HEAD detached.

   Going back to attached state (i.e. on a particular branch) by
   "git checkout $branch" can lose the current stat you arrived
   in these ways, and "git checkout" refuses when the detached
   HEAD is not pointed by any existing ref (an existing branch,
   a remote tracking branch or a tag).  This safety can be
   overridden with "git checkout -f $branch".


* Packed refs

 - Repositories with hundreds of tags have been paying large
   overhead, both in storage and in runtime, due to the
   traditional one-ref-per-file format.  A new command,
   git-pack-refs, can be used to "pack" them in more efficient
   representation (you can let git-gc do this for you).

 - Clones and fetches over dumb transports are now aware of
   packed refs and can download from repositories that use
   them.


* Configuration

 - configuration related to color setting are consolidated under
   color.* namespace (older diff.color.*, status.color.* are
   still supported).

 - 'git-repo-config' command is accessible as 'git-config' now.


* Updated features

 - git-describe uses better criteria to pick a base ref.  It
   used to pick the one with the newest timestamp, but now it
   picks the one that is topologically the closest (that is,
   among ancestors of commit C, the ref T that has the shortest
   output from "git-rev-list T..C" is chosen).

 - git-describe gives the number of commits since the base ref
   between the refname and the hash suffix.  E.g. the commit one
   before v2.6.20-rc6 in the kernel repository is:

	v2.6.20-rc5-306-ga21b069

   which tells you that its object name begins with a21b069,
   v2.6.20-rc5 is an ancestor of it (meaning, the commit
   contains everything -rc5 has), and there are 306 commits
   since v2.6.20-rc5.

 - git-describe with --abbrev=0 can be used to show only the
   name of the base ref.

 - git-blame learned a new option, --incremental, that tells it
   to output the blames as they are assigned.  A sample script
   to use it is also included as contrib/blameview.

 - git-blame starts annotating from the working tree by default.


* Less external dependency

 - We no longer require the "merge" program from the RCS suite.
   All 3-way file-level merges are now done internally.

 - The original implementation of git-merge-recursive which was
   in Python has been removed; we have a C implementation of it
   now.

 - git-shortlog is no longer a Perl script.  It no longer
   requires output piped from git-log; it can accept revision
   parameters directly on the command line.


* I18n

 - We have always encouraged the commit message to be encoded in
   UTF-8, but the users are allowed to use legacy encoding as
   appropriate for their projects.  This will continue to be the
   case.  However, a non UTF-8 commit encoding _must_ be
   explicitly set with i18n.commitencoding in the repository
   where a commit is made; otherwise git-commit-tree will
   complain if the log message does not look like a valid UTF-8
   string.

 - The value of i18n.commitencoding in the originating
   repository is recorded in the commit object on the "encoding"
   header, if it is not UTF-8.  git-log and friends notice this,
   and reencodes the message to the log output encoding when
   displaying, if they are different.  The log output encoding
   is determined by "git log --encoding=<encoding>",
   i18n.logoutputencoding configuration, or i18n.commitencoding
   configuration, in the decreasing order of preference, and
   defaults to UTF-8.

 - Tools for e-mailed patch application now default to -u
   behavior; i.e. it always re-codes from the e-mailed encoding
   to the encoding specified with i18n.commitencoding.  This
   unfortunately forces projects that have happily been using a
   legacy encoding without setting i18n.commitencoding to set
   the configuration, but taken with other improvement, please
   excuse us for this very minor one-time inconvenience.


* e-mailed patches

 - See the above I18n section.

 - git-format-patch now enables --binary without being asked.
   git-am does _not_ default to it, as sending binary patch via
   e-mail is unusual and is harder to review than textual
   patches and it is prudent to require the person who is
   applying the patch to explicitly ask for it.

 - The default suffix for git-format-patch output is now ".patch",
   not ".txt".  This can be changed with --suffix=.txt option,
   or setting the config variable "format.suffix" to ".txt".


* Foreign SCM interfaces

  - git-svn now requires the Perl SVN:: libraries, the
    command-line backend was too slow and limited.

  - the 'commit' subcommand of git-svn has been renamed to
    'set-tree', and 'dcommit' is the recommended replacement for
    day-to-day work.

  - git fast-import backend.


* User support

 - Quite a lot of documentation updates.

 - Bash completion scripts have been updated heavily.

 - Better error messages for often used Porcelainish commands.

 - Git GUI.  This is a simple Tk based graphical interface for
   common Git operations.


* Sliding mmap

 - We used to assume that we can mmap the whole packfile while
   in use, but with a large project this consumes huge virtual
   memory space and truly huge ones would not fit in the
   userland address space on 32-bit platforms.  We now mmap huge
   packfile in pieces to avoid this problem.


* Shallow clones

 - There is a partial support for 'shallow' repositories that
   keeps only recent history.  A 'shallow clone' is created by
   specifying how deep that truncated history should be
   (e.g. "git clone --depth=5 git://some.where/repo.git").

   Currently a shallow repository has number of limitations:

   - Cloning and fetching _from_ a shallow clone are not
     supported (nor tested -- so they might work by accident but
     they are not expected to).

   - Pushing from nor into a shallow clone are not expected to
     work.

   - Merging inside a shallow repository would work as long as a
     merge base is found in the recent history, but otherwise it
     will be like merging unrelated histories and may result in
     huge conflicts.

   but this would be more than adequate for people who want to
   look at near the tip of a big project with a deep history and
   send patches in e-mail format.

^ permalink raw reply	[relevance 2%]

* [PATCH] git-clone: Sync documentation to usage note.
@ 2007-02-15 22:13 16% Christian Schlotter
  0 siblings, 0 replies; 200+ results
From: Christian Schlotter @ 2007-02-15 22:13 UTC (permalink / raw)
  To: git; +Cc: Christian Schlotter

Documentation advertises the new `--depth <n>' parameter with an equal
sign, while the usage notes (shown after `git-clone --help') do not.  If I
understood git-clone's source code correctly, the version without the
equal sign is correct, which is why this patch syncs documentation to the
usage note.

Please note that I was not able to test the new shallow clone feature, as
both
    git clone --depth=5 git://git2.kernel.org/pub/scm/git/git.git
and
    git clone --depth 5 git://git2.kernel.org/pub/scm/git/git.git
do not seem to work.  The former correctly produces the usage note, while
the latter prints

    Initialized empty Git repository in /home/cs/tmp2/git/.git/
    fatal: read error (Connection reset by peer)
    fetch-pack from 'git://git2.kernel.org/pub/scm/git/git.git' failed.

Is this a problem on my end?

Signed-off-by: Christian Schlotter <schlotter@users.sourceforge.net>
---
 Documentation/RelNotes-1.5.0.txt |    2 +-
 Documentation/git-clone.txt      |    4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/RelNotes-1.5.0.txt b/Documentation/RelNotes-1.5.0.txt
index 599efb8..daf4bdb 100644
--- a/Documentation/RelNotes-1.5.0.txt
+++ b/Documentation/RelNotes-1.5.0.txt
@@ -448,7 +448,7 @@ Updates in v1.5.0 since v1.4.4 series
  - There is a partial support for 'shallow' repositories that
    keeps only recent history.  A 'shallow clone' is created by
    specifying how deep that truncated history should be
-   (e.g. "git clone --depth=5 git://some.where/repo.git").
+   (e.g. "git clone --depth 5 git://some.where/repo.git").
 
    Currently a shallow repository has number of limitations:
 
diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index 707376f..6d32c49 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -11,7 +11,7 @@ SYNOPSIS
 [verse]
 'git-clone' [--template=<template_directory>] [-l [-s]] [-q] [-n] [--bare]
 	  [-o <name>] [-u <upload-pack>] [--reference <repository>]
-	  [--depth=<depth>] <repository> [<directory>]
+	  [--depth <depth>] <repository> [<directory>]
 
 DESCRIPTION
 -----------
@@ -96,7 +96,7 @@ OPTIONS
 	if unset the templates are taken from the installation
 	defined default, typically `/usr/share/git-core/templates`.
 
---depth=<depth>::
+--depth <depth>::
 	Create a 'shallow' clone with a history truncated to the
 	specified number of revs.  A shallow repository has
 	number of limitations (you cannot clone or fetch from
-- 
1.5.0

^ permalink raw reply related	[relevance 16%]

* Re: StGIT discards local commits on "stg pull"
  @ 2007-02-19 20:47  1%       ` Yann Dirson
  0 siblings, 0 replies; 200+ results
From: Yann Dirson @ 2007-02-19 20:47 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: Pavel Roskin, git

On Tue, Feb 13, 2007 at 10:48:11PM +0000, Catalin Marinas wrote:
> On 13/02/07, Pavel Roskin <proski@gnu.org> wrote:
> >On Mon, 2007-02-12 at 09:31 +0000, Catalin Marinas wrote:
> >> On 12/02/07, Pavel Roskin <proski@gnu.org> wrote:
> >
> >> > The example below shows that git-pull keeps my commit, but "stg pull"
> >> > discards it by rebasing back to the remote ID.
> >>
> >> I think this is a "feature" but we should've probably leave the
> >> original behaviour as the default. Maybe we should also have this
> >> per-branch rather than per-repository.
> >
> >I don't know the original motivation behind effectively reimplementing
> >"git pull" in StGIT, but it's clear that the StGIT's own implementation
> >needs some polish.

The primary motivation was to allow some sort of distributed handling
of a stack.  That is, I publish an stgit-managed branch, you "stg
clone" it, you create your own patches on top of that, and when I
refresh my stack, you can just "stg pull" it as you would do if my
published work was a standard non-rewinding git branch.


> >I think it's always wrong to lose local commits.  I think StGIT should
> >refuse to rebase if a merge would be needed

Right, we should make it so losing local commits cannot be done by
error.  However, we cannot rely on the branch topology at the time
we're rebasing.  Consider those 2 use cases:

- my stack forks off a non-rewinding branch, and I "stg commit" part
of it, then "stg pull"

- my stack forks off a rewinding branch, and I use "git fetch" to look
at what's new upstream, then I decide it's a good time to rebase, and
run "stg pull" (or preferably "stg rebase" to avoid fetching more
recent commits by error)

In the 2 cases "git pull" would do a merge.  One crucial thing
distinguishes the 2 cases, is that in the 1st case we have "manually"
messed with the stack base.  By "manually", I mean we changed the
stack base by other means than pulling/rebasing, but this notion
possibly needs some tuning.  "stg commit" is an example, "stg
uncommit" is another, and both would cause "git pull" to do a merge
*because rebasing would not be what you want*, whereas in the
rewinding-branch use-case *what you is precisely rebasing*.

What we could do then, is having "rebase" and "pull" record an
orig-base ref as a "backup copy" of the the new base, and first refuse
to do the job (unless --force'd) if the base does not match its backup
(that is, if the user used "commit" or "uncommit").

> >or the rebase would go back in history (in other words, if
> >git-pull would not go to the remote revision).

I'm less sure about the use-case you're trying to address here.  Could
you please give more details ?  The only case I can think of would be
that of a rewinding branch that would have been just that, rewinded,
so it should be handled differently than when any new commit would
exist on top of this ancestor commit.


> >If we look at it from the user standpoint, the branches could be
> >distinguished by the use model:
> >
> >1) Tracking branch: pull is OK, commit is not OK, push is not OK.  All
> >development is done in StGIT patches and sent to others.
> >
> >2) Development branch: commit is OK, push is OK, pull is OK but no
> >merges by default.

Right, those ones are probably the most used.

> >3) Merge branch: pull is OK, even with automatic merge, commit is OK,
> >merge is OK.

This one I'm not sure to understand well.  Could you please describe
it in more details, perhaps in terms of the relation with other repos,
and of the most distinctive local operations ?

> I probably have another situation - a branch managed partially with
> StGIT but GIT commits (or 'stg commit') used and pulling would lead to
> a merge of the base, followed by patch pushing. This would work if we
> use git-pull rather than git-fetch.

You mean, a branch to which possibly several devs would commit (or to
which you want to commit multiple topic branches yourself), and where
you want to keep track of merges between these branches (as opposed to
rebasing), while still using stgit locally ?


> >> The solution would be to define the following in your gitconfig file
> >> (either ~/.gitconfig or .git/config; a full example in StGIT's
> >> examples/gitconfig):
> >>
> >> [stgit]
> >>       pullcmd = git-pull
> >>       pull-does-rebase = no
> >>
> >> The last line would tell StGIT not to do the rebasing and let git-pull
> >> handle it.
> >
> >It's actually my deliberate choice to subject myself to the pains of the
> >default configuration.  I don't want to live in backwards compatible
> >environment until it rots away.  I'll rather eat the dogfood we are
> >offering to others :)
> 
> I don't consider this as a backward-compatibility feature. It simply
> targets a different workflow and it would be even better if we have it
> per-branch. The default should be the current fetch+rebase (as the
> most common case would be to use StGIT commands only) but with a
> warning if stack base fast-forwarding is not possible.

One way to handle different workflows could be to define a particular
workflow with a set of settings such as pullcmd and pull-does-rebase.
That way, we could say eg. "stg branch --workflow=<id>" to set the
vars in one run.

Best regards,
-- 
Yann.

^ permalink raw reply	[relevance 1%]

* [PATCH 8/8] convert remaining users of "cmp" to "git diff"
@ 2007-02-25 22:38  2% Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2007-02-25 22:38 UTC (permalink / raw)
  To: git, junkio


This is really

$ perl -pi.bak -e \
  "s/(^\s*|'|\"|^\s*if |&&\s*)cmp /\1git diff /" t/*.sh

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---

	BTW all tests pass with this series...

 t/t1002-read-tree-m-u-2way.sh    |   32 +++++++++++++-------------
 t/t1003-read-tree-prefix.sh      |    2 +-
 t/t1020-subdirectory.sh          |   16 ++++++------
 t/t1200-tutorial.sh              |   22 +++++++++---------
 t/t1300-repo-config.sh           |   46 +++++++++++++++++++-------------------
 t/t2101-update-index-reupdate.sh |   12 +++++-----
 t/t3300-funny-names.sh           |    2 +-
 t/t4012-diff-binary.sh           |    4 +-
 t/t4109-apply-multifrag.sh       |    6 ++--
 t/t4110-apply-scan.sh            |    2 +-
 t/t5300-pack-object.sh           |   12 +++++-----
 t/t5400-send-pack.sh             |    4 +-
 t/t6021-merge-criss-cross.sh     |    2 +-
 t/t9101-git-svn-props.sh         |    4 +-
 t/t9105-git-svn-commit-diff.sh   |    4 +-
 t/t9107-git-svn-migrate.sh       |    2 +-
 t/t9108-git-svn-glob.sh          |    4 +-
 17 files changed, 88 insertions(+), 88 deletions(-)

diff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh
index 87fe993..2a70ee9 100755
--- a/t/t1002-read-tree-m-u-2way.sh
+++ b/t/t1002-read-tree-m-u-2way.sh
@@ -59,9 +59,9 @@ test_expect_success \
      git-read-tree --reset -u $treeH &&
      git-read-tree -m -u $treeH $treeM &&
      git-ls-files --stage >1-3.out &&
-     cmp M.out 1-3.out &&
+     git diff M.out 1-3.out &&
      sum bozbar frotz nitfol >actual3.sum &&
-     cmp M.sum actual3.sum &&
+     git diff M.sum actual3.sum &&
      check_cache_at bozbar clean &&
      check_cache_at frotz clean &&
      check_cache_at nitfol clean'
@@ -79,7 +79,7 @@ test_expect_success \
      compare_change 4diff.out expected &&
      check_cache_at yomin clean &&
      sum bozbar frotz nitfol >actual4.sum &&
-     cmp M.sum actual4.sum &&
+     git diff M.sum actual4.sum &&
      echo yomin >yomin1 &&
      diff yomin yomin1 &&
      rm -f yomin1'
@@ -98,7 +98,7 @@ test_expect_success \
      compare_change 5diff.out expected &&
      check_cache_at yomin dirty &&
      sum bozbar frotz nitfol >actual5.sum &&
-     cmp M.sum actual5.sum &&
+     git diff M.sum actual5.sum &&
      : dirty index should have prevented -u from checking it out. &&
      echo yomin yomin >yomin1 &&
      diff yomin yomin1 &&
@@ -115,7 +115,7 @@ test_expect_success \
      diff -U0 M.out 6.out &&
      check_cache_at frotz clean &&
      sum bozbar frotz nitfol >actual3.sum &&
-     cmp M.sum actual3.sum &&
+     git diff M.sum actual3.sum &&
      echo frotz >frotz1 &&
      diff frotz frotz1 &&
      rm -f frotz1'
@@ -132,7 +132,7 @@ test_expect_success \
      diff -U0 M.out 7.out &&
      check_cache_at frotz dirty &&
      sum bozbar frotz nitfol >actual7.sum &&
-     if cmp M.sum actual7.sum; then false; else :; fi &&
+     if git diff M.sum actual7.sum; then false; else :; fi &&
      : dirty index should have prevented -u from checking it out. &&
      echo frotz frotz >frotz1 &&
      diff frotz frotz1 &&
@@ -163,9 +163,9 @@ test_expect_success \
      git-update-index --add rezrov &&
      git-read-tree -m -u $treeH $treeM &&
      git-ls-files --stage >10.out &&
-     cmp M.out 10.out &&
+     git diff M.out 10.out &&
      sum bozbar frotz nitfol >actual10.sum &&
-     cmp M.sum actual10.sum'
+     git diff M.sum actual10.sum'
 
 test_expect_success \
     '11 - dirty path removed.' \
@@ -210,9 +210,9 @@ test_expect_success \
      compare_change 14diff.out expected &&
      sum bozbar frotz >actual14.sum &&
      grep -v nitfol M.sum > expected14.sum &&
-     cmp expected14.sum actual14.sum &&
+     git diff expected14.sum actual14.sum &&
      sum bozbar frotz nitfol >actual14a.sum &&
-     if cmp M.sum actual14a.sum; then false; else :; fi &&
+     if git diff M.sum actual14a.sum; then false; else :; fi &&
      check_cache_at nitfol clean &&
      echo nitfol nitfol >nitfol1 &&
      diff nitfol nitfol1 &&
@@ -232,9 +232,9 @@ test_expect_success \
      check_cache_at nitfol dirty &&
      sum bozbar frotz >actual15.sum &&
      grep -v nitfol M.sum > expected15.sum &&
-     cmp expected15.sum actual15.sum &&
+     git diff expected15.sum actual15.sum &&
      sum bozbar frotz nitfol >actual15a.sum &&
-     if cmp M.sum actual15a.sum; then false; else :; fi &&
+     if git diff M.sum actual15a.sum; then false; else :; fi &&
      echo nitfol nitfol nitfol >nitfol1 &&
      diff nitfol nitfol1 &&
      rm -f nitfol1'
@@ -267,7 +267,7 @@ test_expect_success \
      diff -U0 M.out 18.out &&
      check_cache_at bozbar clean &&
      sum bozbar frotz nitfol >actual18.sum &&
-     cmp M.sum actual18.sum'
+     git diff M.sum actual18.sum'
 
 test_expect_success \
     '19 - local change already having a good result, further modified.' \
@@ -282,9 +282,9 @@ test_expect_success \
      check_cache_at bozbar dirty &&
      sum frotz nitfol >actual19.sum &&
      grep -v bozbar  M.sum > expected19.sum &&
-     cmp expected19.sum actual19.sum &&
+     git diff expected19.sum actual19.sum &&
      sum bozbar frotz nitfol >actual19a.sum &&
-     if cmp M.sum actual19a.sum; then false; else :; fi &&
+     if git diff M.sum actual19a.sum; then false; else :; fi &&
      echo gnusto gnusto >bozbar1 &&
      diff bozbar bozbar1 &&
      rm -f bozbar1'
@@ -300,7 +300,7 @@ test_expect_success \
      diff -U0 M.out 20.out &&
      check_cache_at bozbar clean &&
      sum bozbar frotz nitfol >actual20.sum &&
-     cmp M.sum actual20.sum'
+     git diff M.sum actual20.sum'
 
 test_expect_success \
     '21 - no local change, dirty cache.' \
diff --git a/t/t1003-read-tree-prefix.sh b/t/t1003-read-tree-prefix.sh
index 48ab117..4029f57 100755
--- a/t/t1003-read-tree-prefix.sh
+++ b/t/t1003-read-tree-prefix.sh
@@ -21,7 +21,7 @@ two/one' >expect
 test_expect_success 'read-tree --prefix' '
 	git-read-tree --prefix=two/ $tree &&
 	git-ls-files >actual &&
-	cmp expect actual
+	git diff expect actual
 '
 
 test_done
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index 1e8f9e5..22588bb 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -46,10 +46,10 @@ test_expect_success 'cat-file' '
 	two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
 	echo "$two" &&
 	git-cat-file -p "$two" >actual &&
-	cmp dir/two actual &&
+	git diff dir/two actual &&
 	cd dir &&
 	git-cat-file -p "$two" >actual &&
-	cmp two actual
+	git diff two actual
 '
 rm -f actual dir/actual
 
@@ -86,10 +86,10 @@ test_expect_success 'write-tree' '
 test_expect_success 'checkout-index' '
 	cd $HERE &&
 	git-checkout-index -f -u one &&
-	cmp one original.one &&
+	git diff one original.one &&
 	cd dir &&
 	git-checkout-index -f -u two &&
-	cmp two ../original.two
+	git diff two ../original.two
 '
 
 test_expect_success 'read-tree' '
@@ -97,13 +97,13 @@ test_expect_success 'read-tree' '
 	rm -f one dir/two &&
 	tree=`git-write-tree` &&
 	git-read-tree --reset -u "$tree" &&
-	cmp one original.one &&
-	cmp dir/two original.two &&
+	git diff one original.one &&
+	git diff dir/two original.two &&
 	cd dir &&
 	rm -f two &&
 	git-read-tree --reset -u "$tree" &&
-	cmp two ../original.two &&
-	cmp ../one ../original.one
+	git diff two ../original.two &&
+	git diff ../one ../original.one
 '
 
 test_expect_success 'no file/rev ambiguity check inside .git' '
diff --git a/t/t1200-tutorial.sh b/t/t1200-tutorial.sh
index ca2c30f..a3c2650 100755
--- a/t/t1200-tutorial.sh
+++ b/t/t1200-tutorial.sh
@@ -27,9 +27,9 @@ index 557db03..263414f 100644
 +It's a new day for git
 EOF
 git-diff-files -p > diff.output
-test_expect_success 'git-diff-files -p' 'cmp diff.expect diff.output'
+test_expect_success 'git-diff-files -p' 'git diff diff.expect diff.output'
 git diff > diff.output
-test_expect_success 'git diff' 'cmp diff.expect diff.output'
+test_expect_success 'git diff' 'git diff diff.expect diff.output'
 
 tree=$(git-write-tree 2>/dev/null)
 
@@ -38,10 +38,10 @@ test_expect_success 'tree' "test 8988da15d077d4829fc51d8544c097def6644dbb = $tre
 output="$(echo "Initial commit" | git-commit-tree $(git-write-tree) 2>&1 > .git/refs/heads/master)"
 
 git-diff-index -p HEAD > diff.output
-test_expect_success 'git-diff-index -p HEAD' 'cmp diff.expect diff.output'
+test_expect_success 'git-diff-index -p HEAD' 'git diff diff.expect diff.output'
 
 git diff HEAD > diff.output
-test_expect_success 'git diff HEAD' 'cmp diff.expect diff.output'
+test_expect_success 'git diff HEAD' 'git diff diff.expect diff.output'
 
 #rm hello
 #test_expect_success 'git-read-tree --reset HEAD' "git-read-tree --reset HEAD ; test \"hello: needs update\" = \"$(git-update-index --refresh)\""
@@ -73,15 +73,15 @@ git-whatchanged -p --root | \
 	sed -e "1s/^\(.\{7\}\).\{40\}/\1VARIABLE/" \
 		-e "2,3s/^\(.\{8\}\).*$/\1VARIABLE/" \
 > whatchanged.output
-test_expect_success 'git-whatchanged -p --root' 'cmp whatchanged.expect whatchanged.output'
+test_expect_success 'git-whatchanged -p --root' 'git diff whatchanged.expect whatchanged.output'
 
 git tag my-first-tag
-test_expect_success 'git tag my-first-tag' 'cmp .git/refs/heads/master .git/refs/tags/my-first-tag'
+test_expect_success 'git tag my-first-tag' 'git diff .git/refs/heads/master .git/refs/tags/my-first-tag'
 
 # TODO: test git-clone
 
 git checkout -b mybranch
-test_expect_success 'git checkout -b mybranch' 'cmp .git/refs/heads/master .git/refs/heads/mybranch'
+test_expect_success 'git checkout -b mybranch' 'git diff .git/refs/heads/master .git/refs/heads/mybranch'
 
 cat > branch.expect <<EOF
   master
@@ -89,7 +89,7 @@ cat > branch.expect <<EOF
 EOF
 
 git branch > branch.output
-test_expect_success 'git branch' 'cmp branch.expect branch.output'
+test_expect_success 'git branch' 'git diff branch.expect branch.output'
 
 git checkout mybranch
 echo "Work, work, work" >>hello
@@ -125,7 +125,7 @@ cat > show-branch.expect << EOF
 EOF
 
 git show-branch --topo-order master mybranch > show-branch.output
-test_expect_success 'git show-branch' 'cmp show-branch.expect show-branch.output'
+test_expect_success 'git show-branch' 'git diff show-branch.expect show-branch.output'
 
 git checkout mybranch
 
@@ -138,7 +138,7 @@ EOF
 
 git merge -s "Merge upstream changes." master | \
 	sed -e "1s/[0-9a-f]\{40\}/VARIABLE/g" >resolve.output
-test_expect_success 'git resolve' 'cmp resolve.expect resolve.output'
+test_expect_success 'git resolve' 'git diff resolve.expect resolve.output'
 
 cat > show-branch2.expect << EOF
 ! [master] Merged "mybranch" changes.
@@ -148,7 +148,7 @@ cat > show-branch2.expect << EOF
 EOF
 
 git show-branch --topo-order master mybranch > show-branch2.output
-test_expect_success 'git show-branch' 'cmp show-branch2.expect show-branch2.output'
+test_expect_success 'git show-branch' 'git diff show-branch2.expect show-branch2.output'
 
 # TODO: test git fetch
 
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 84a5939..3753e9f 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -16,7 +16,7 @@ cat > expect << EOF
 	penguin = little blue
 EOF
 
-test_expect_success 'initial' 'cmp .git/config expect'
+test_expect_success 'initial' 'git diff .git/config expect'
 
 git-config Core.Movie BadPhysics
 
@@ -26,7 +26,7 @@ cat > expect << EOF
 	Movie = BadPhysics
 EOF
 
-test_expect_success 'mixed case' 'cmp .git/config expect'
+test_expect_success 'mixed case' 'git diff .git/config expect'
 
 git-config Cores.WhatEver Second
 
@@ -38,7 +38,7 @@ cat > expect << EOF
 	WhatEver = Second
 EOF
 
-test_expect_success 'similar section' 'cmp .git/config expect'
+test_expect_success 'similar section' 'git diff .git/config expect'
 
 git-config CORE.UPPERCASE true
 
@@ -51,7 +51,7 @@ cat > expect << EOF
 	WhatEver = Second
 EOF
 
-test_expect_success 'similar section' 'cmp .git/config expect'
+test_expect_success 'similar section' 'git diff .git/config expect'
 
 test_expect_success 'replace with non-match' \
 	'git-config core.penguin kingpin !blue'
@@ -69,7 +69,7 @@ cat > expect << EOF
 	WhatEver = Second
 EOF
 
-test_expect_success 'non-match result' 'cmp .git/config expect'
+test_expect_success 'non-match result' 'git diff .git/config expect'
 
 cat > .git/config << EOF
 [beta] ; silly comment # another comment
@@ -97,7 +97,7 @@ noIndent= sillyValue ; 'nother silly comment
 [nextSection] noNewline = ouch
 EOF
 
-test_expect_success 'multiple unset is correct' 'cmp .git/config expect'
+test_expect_success 'multiple unset is correct' 'git diff .git/config expect'
 
 mv .git/config2 .git/config
 
@@ -114,7 +114,7 @@ noIndent= sillyValue ; 'nother silly comment
 [nextSection] noNewline = ouch
 EOF
 
-test_expect_success 'all replaced' 'cmp .git/config expect'
+test_expect_success 'all replaced' 'git diff .git/config expect'
 
 git-config beta.haha alpha
 
@@ -128,7 +128,7 @@ noIndent= sillyValue ; 'nother silly comment
 [nextSection] noNewline = ouch
 EOF
 
-test_expect_success 'really mean test' 'cmp .git/config expect'
+test_expect_success 'really mean test' 'git diff .git/config expect'
 
 git-config nextsection.nonewline wow
 
@@ -143,7 +143,7 @@ noIndent= sillyValue ; 'nother silly comment
 	nonewline = wow
 EOF
 
-test_expect_success 'really really mean test' 'cmp .git/config expect'
+test_expect_success 'really really mean test' 'git diff .git/config expect'
 
 test_expect_success 'get value' 'test alpha = $(git-config beta.haha)'
 git-config --unset beta.haha
@@ -158,7 +158,7 @@ noIndent= sillyValue ; 'nother silly comment
 	nonewline = wow
 EOF
 
-test_expect_success 'unset' 'cmp .git/config expect'
+test_expect_success 'unset' 'git diff .git/config expect'
 
 git-config nextsection.NoNewLine "wow2 for me" "for me$"
 
@@ -173,7 +173,7 @@ noIndent= sillyValue ; 'nother silly comment
 	NoNewLine = wow2 for me
 EOF
 
-test_expect_success 'multivar' 'cmp .git/config expect'
+test_expect_success 'multivar' 'git diff .git/config expect'
 
 test_expect_success 'non-match' \
 	'git-config --get nextsection.nonewline !for'
@@ -200,7 +200,7 @@ noIndent= sillyValue ; 'nother silly comment
 	NoNewLine = wow2 for me
 EOF
 
-test_expect_success 'multivar replace' 'cmp .git/config expect'
+test_expect_success 'multivar replace' 'git diff .git/config expect'
 
 test_expect_failure 'ambiguous value' 'git-config nextsection.nonewline'
 
@@ -222,7 +222,7 @@ noIndent= sillyValue ; 'nother silly comment
 	NoNewLine = wow2 for me
 EOF
 
-test_expect_success 'multivar unset' 'cmp .git/config expect'
+test_expect_success 'multivar unset' 'git diff .git/config expect'
 
 test_expect_failure 'invalid key' 'git-config inval.2key blabla'
 
@@ -245,7 +245,7 @@ noIndent= sillyValue ; 'nother silly comment
 	Alpha = beta
 EOF
 
-test_expect_success 'hierarchical section value' 'cmp .git/config expect'
+test_expect_success 'hierarchical section value' 'git diff .git/config expect'
 
 cat > expect << EOF
 beta.noindent=sillyValue
@@ -255,7 +255,7 @@ version.1.2.3eX.alpha=beta
 EOF
 
 test_expect_success 'working --list' \
-	'git-config --list > output && cmp output expect'
+	'git-config --list > output && git diff output expect'
 
 cat > expect << EOF
 beta.noindent sillyValue
@@ -263,7 +263,7 @@ nextsection.nonewline wow2 for me
 EOF
 
 test_expect_success '--get-regexp' \
-	'git-config --get-regexp in > output && cmp output expect'
+	'git-config --get-regexp in > output && git diff output expect'
 
 git-config --add nextsection.nonewline "wow4 for you"
 
@@ -273,7 +273,7 @@ wow4 for you
 EOF
 
 test_expect_success '--add' \
-	'git-config --get-all nextsection.nonewline > output && cmp output expect'
+	'git-config --get-all nextsection.nonewline > output && git diff output expect'
 
 cat > .git/config << EOF
 [novalue]
@@ -302,7 +302,7 @@ cat > expect << EOF
 	x = y
 EOF
 
-test_expect_success 'new section is partial match of another' 'cmp .git/config expect'
+test_expect_success 'new section is partial match of another' 'git diff .git/config expect'
 
 git-config b.x y
 git-config a.b c
@@ -317,7 +317,7 @@ cat > expect << EOF
 	x = y
 EOF
 
-test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect'
+test_expect_success 'new variable inserts into proper section' 'git diff .git/config expect'
 
 cat > other-config << EOF
 [ein]
@@ -330,7 +330,7 @@ EOF
 
 GIT_CONFIG=other-config git-config -l > output
 
-test_expect_success 'alternative GIT_CONFIG' 'cmp output expect'
+test_expect_success 'alternative GIT_CONFIG' 'git diff output expect'
 
 GIT_CONFIG=other-config git-config anwohner.park ausweis
 
@@ -341,7 +341,7 @@ cat > expect << EOF
 	park = ausweis
 EOF
 
-test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect'
+test_expect_success '--set in alternative GIT_CONFIG' 'git diff other-config expect'
 
 cat > .git/config << EOF
 # Hallo
@@ -416,7 +416,7 @@ cat > expect << EOF
 	hash = "test#test"
 EOF
 
-test_expect_success 'quoting' 'cmp .git/config expect'
+test_expect_success 'quoting' 'git diff .git/config expect'
 
 test_expect_failure 'key with newline' 'git config key.with\\\
 newline 123'
@@ -442,7 +442,7 @@ EOF
 
 git config --list > result
 
-test_expect_success 'value continued on next line' 'cmp result expect'
+test_expect_success 'value continued on next line' 'git diff result expect'
 
 test_done
 
diff --git a/t/t2101-update-index-reupdate.sh b/t/t2101-update-index-reupdate.sh
index a78ea7f..723a682 100755
--- a/t/t2101-update-index-reupdate.sh
+++ b/t/t2101-update-index-reupdate.sh
@@ -17,7 +17,7 @@ test_expect_success 'update-index --add' \
 	 echo goodbye people >file2 &&
 	 git-update-index --add file1 file2 &&
 	 git-ls-files -s >current &&
-	 cmp current expected'
+	 git diff current expected'
 
 test_expect_success 'update-index --again' \
 	'rm -f file1 &&
@@ -30,7 +30,7 @@ test_expect_success 'update-index --again' \
 		echo happy - failed as expected
 	fi &&
 	 git-ls-files -s >current &&
-	 cmp current expected'
+	 git diff current expected'
 
 cat > expected <<\EOF
 100644 0f1ae1422c2bf43f117d3dbd715c988a9ed2103f 0	file2
@@ -38,7 +38,7 @@ EOF
 test_expect_success 'update-index --remove --again' \
 	'git-update-index --remove --again &&
 	 git-ls-files -s >current &&
-	 cmp current expected'
+	 git diff current expected'
 
 test_expect_success 'first commit' 'git-commit -m initial'
 
@@ -55,7 +55,7 @@ test_expect_success 'update-index again' \
 	echo happy >dir1/file3 &&
 	git-update-index --again &&
 	git-ls-files -s >current &&
-	cmp current expected'
+	git diff current expected'
 
 cat > expected <<\EOF
 100644 d7fb3f695f06c759dbf3ab00046e7cc2da22d10f 0	dir1/file3
@@ -68,7 +68,7 @@ test_expect_success 'update-index --update from subdir' \
 	git-update-index --again &&
 	cd .. &&
 	git-ls-files -s >current &&
-	cmp current expected'
+	git diff current expected'
 
 cat > expected <<\EOF
 100644 594fb5bb1759d90998e2bf2a38261ae8e243c760 0	dir1/file3
@@ -79,6 +79,6 @@ test_expect_success 'update-index --update with pathspec' \
 	cat file2 >dir1/file3 &&
 	git-update-index --again dir1/ &&
 	git-ls-files -s >current &&
-	cmp current expected'
+	git diff current expected'
 
 test_done
diff --git a/t/t3300-funny-names.sh b/t/t3300-funny-names.sh
index b5a1400..5913152 100755
--- a/t/t3300-funny-names.sh
+++ b/t/t3300-funny-names.sh
@@ -24,7 +24,7 @@ EOF
 cat >"$p1" "$p0"
 echo 'Foo Bar Baz' >"$p2"
 
-test -f "$p1" && cmp "$p0" "$p1" || {
+test -f "$p1" && git diff "$p0" "$p1" || {
 	# since FAT/NTFS does not allow tabs in filenames, skip this test
 	say 'Your filesystem does not allow tabs in filenames, test skipped.'
 	test_done
diff --git a/t/t4012-diff-binary.sh b/t/t4012-diff-binary.sh
index 323606c..c5f530f 100755
--- a/t/t4012-diff-binary.sh
+++ b/t/t4012-diff-binary.sh
@@ -25,11 +25,11 @@ cat > expected <<\EOF
 EOF
 test_expect_success 'diff without --binary' \
 	'git-diff | git-apply --stat --summary >current &&
-	 cmp current expected'
+	 git diff current expected'
 
 test_expect_success 'diff with --binary' \
 	'git-diff --binary | git-apply --stat --summary >current &&
-	 cmp current expected'
+	 git diff current expected'
 
 # apply needs to be able to skip the binary material correctly
 # in order to report the line number of a corrupt patch.
diff --git a/t/t4109-apply-multifrag.sh b/t/t4109-apply-multifrag.sh
index 5988e1a..180febc 100755
--- a/t/t4109-apply-multifrag.sh
+++ b/t/t4109-apply-multifrag.sh
@@ -146,7 +146,7 @@ test_expect_success "S = patch (1)" \
     'cat patch1.patch patch2.patch | patch -p1'
 
 test_expect_success "S = cmp (1)" \
-    'cmp main.c.git main.c'
+    'git diff main.c.git main.c'
 
 rm -f main.c main.c.git
 
@@ -158,7 +158,7 @@ test_expect_success "S = patch (2)" \
     'cat patch1.patch patch2.patch patch3.patch | patch -p1'
 
 test_expect_success "S = cmp (2)" \
-    'cmp main.c.git main.c'
+    'git diff main.c.git main.c'
 
 rm -f main.c main.c.git
 
@@ -170,7 +170,7 @@ test_expect_success "S = patch (3)" \
     'cat patch1.patch patch4.patch | patch -p1'
 
 test_expect_success "S = cmp (3)" \
-    'cmp main.c.git main.c'
+    'git diff main.c.git main.c'
 
 test_done
 
diff --git a/t/t4110-apply-scan.sh b/t/t4110-apply-scan.sh
index 005f744..ec00ed6 100755
--- a/t/t4110-apply-scan.sh
+++ b/t/t4110-apply-scan.sh
@@ -95,7 +95,7 @@ test_expect_success "S = patch scan" \
 mv new.txt patch.txt
 
 test_expect_success "S = cmp" \
-    'cmp apply.txt patch.txt'
+    'git diff apply.txt patch.txt'
 
 test_done
 
diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh
index f511547..522d7b2 100755
--- a/t/t5300-pack-object.sh
+++ b/t/t5300-pack-object.sh
@@ -56,7 +56,7 @@ test_expect_success \
     '(cd ../.git && find objects -type f -print) |
      while read path
      do
-         cmp $path ../.git/$path || {
+         git diff $path ../.git/$path || {
 	     echo $path differs.
 	     return 1
 	 }
@@ -86,7 +86,7 @@ test_expect_success \
     '(cd ../.git && find objects -type f -print) |
      while read path
      do
-         cmp $path ../.git/$path || {
+         git diff $path ../.git/$path || {
 	     echo $path differs.
 	     return 1
 	 }
@@ -182,17 +182,17 @@ test_expect_success \
     'build pack index for an existing pack' \
     'cp test-1-${packname_1}.pack test-3.pack &&
      git-index-pack -o tmp.idx test-3.pack &&
-     cmp tmp.idx test-1-${packname_1}.idx &&
+     git diff tmp.idx test-1-${packname_1}.idx &&
 
      git-index-pack test-3.pack &&
-     cmp test-3.idx test-1-${packname_1}.idx &&
+     git diff test-3.idx test-1-${packname_1}.idx &&
 
      cp test-2-${packname_2}.pack test-3.pack &&
      git-index-pack -o tmp.idx test-2-${packname_2}.pack &&
-     cmp tmp.idx test-2-${packname_2}.idx &&
+     git diff tmp.idx test-2-${packname_2}.idx &&
 
      git-index-pack test-3.pack &&
-     cmp test-3.idx test-2-${packname_2}.idx &&
+     git diff test-3.idx test-2-${packname_2}.idx &&
 
      :'
 
diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index fc4a126..03c2692 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -77,7 +77,7 @@ test_expect_success \
 		echo >&2 Thanks, it correctly failed.
 		true
 	fi &&
-	if cmp victim/.git/refs/heads/master .git/refs/heads/master
+	if git diff victim/.git/refs/heads/master .git/refs/heads/master
 	then
 		# should have been left as it was!
 		false
@@ -86,7 +86,7 @@ test_expect_success \
 	fi &&
 	# this should update
 	git-send-pack --force ./victim/.git/ master &&
-	cmp victim/.git/refs/heads/master .git/refs/heads/master
+	git diff victim/.git/refs/heads/master .git/refs/heads/master
 '
 
 test_expect_success \
diff --git a/t/t6021-merge-criss-cross.sh b/t/t6021-merge-criss-cross.sh
index 499cafb..c9d43dd 100755
--- a/t/t6021-merge-criss-cross.sh
+++ b/t/t6021-merge-criss-cross.sh
@@ -87,6 +87,6 @@ cat > file-expect <<EOF
 9
 EOF
 
-test_expect_success 'Criss-cross merge result' 'cmp file file-expect'
+test_expect_success 'Criss-cross merge result' 'git diff file file-expect'
 
 test_done
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index 622ea1c..28738d7 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -96,7 +96,7 @@ test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
-	test_expect_success "Comparing $i" "cmp $i new_wc/$i"
+	test_expect_success "Comparing $i" "git diff $i new_wc/$i"
 done
 
 
@@ -144,7 +144,7 @@ test_expect_success 'test show-ignore' "
 	svn commit -m 'propset svn:ignore'
 	cd .. &&
 	git-svn show-ignore > show-ignore.got &&
-	cmp show-ignore.expect show-ignore.got
+	git diff show-ignore.expect show-ignore.got
 	"
 
 test_done
diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh
index c668dd1..082785e 100755
--- a/t/t9105-git-svn-commit-diff.sh
+++ b/t/t9105-git-svn-commit-diff.sh
@@ -28,7 +28,7 @@ test_expect_success 'test the commit-diff command' "
 	test -n '$prev' && test -n '$head' &&
 	git-svn commit-diff -r1 '$prev' '$head' '$svnrepo' &&
 	svn co $svnrepo wc &&
-	cmp readme wc/readme
+	git diff readme wc/readme
 	"
 
 test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
@@ -37,7 +37,7 @@ test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
 	git-svn fetch &&
 	git-svn commit-diff -r3 '$prev' '$head' &&
 	svn cat $svnrepo/subdir/readme > readme.2 &&
-	cmp readme readme.2
+	git diff readme readme.2
 	"
 
 test_done
diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index dc2afda..37ae559 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -105,7 +105,7 @@ test_expect_success  ".rev_db auto-converted to .rev_db.UUID" "
 	git-svn fetch -i trunk &&
 	test -L $GIT_DIR/svn/trunk/.rev_db &&
 	test -f \$expect &&
-	cmp \$expect $GIT_DIR/svn/trunk/.rev_db
+	git diff \$expect $GIT_DIR/svn/trunk/.rev_db
 	"
 
 test_done
diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh
index db4344c..83b94ed 100755
--- a/t/t9108-git-svn-glob.sh
+++ b/t/t9108-git-svn-glob.sh
@@ -48,7 +48,7 @@ test_expect_success 'test refspec globbing' "
 	git-svn multi-fetch &&
 	git log --pretty=oneline refs/remotes/tags/end | \
 	    sed -e 's/^.\{41\}//' > output.end &&
-	cmp expect.end output.end &&
+	git diff expect.end output.end &&
 	test \"\`git rev-parse refs/remotes/tags/end~1\`\" = \
 		\"\`git rev-parse refs/remotes/branches/start\`\" &&
 	test \"\`git rev-parse refs/remotes/branches/start~2\`\" = \
@@ -80,7 +80,7 @@ test_expect_success 'test left-hand-side only globbing' "
 	     \`git rev-parse refs/remotes/two/branches/start\` &&
 	git log --pretty=oneline refs/remotes/two/tags/end | \
 	    sed -e 's/^.\{41\}//' > output.two &&
-	cmp expect.two output.two
+	git diff expect.two output.two
 	"
 
 test_done
-- 
1.5.0.1.788.g8ca52

^ permalink raw reply related	[relevance 2%]

* Re: Google Summer of Code 2007
  @ 2007-03-01  2:08  3% ` Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2007-03-01  2:08 UTC (permalink / raw)
  To: git

Shawn O. Pearce wrote:

> ShadeHawk and robinr brought up Google's Summer of Code on #git the
> other day.  I had also been thinking about seeing if we cannot get
> Git involved with SoC, so here goes... ;-)
> 
> The application deadline for organizations is March 12th.
> The earliest that we can submit an application is March 5th, so we
> still have time to kick ideas around and see if the community is
> interested in participating in SoC.

Well, certainly there is a number of areas to work on. This includes:
 * much talked on (and even with two different independent
   implementations) _subproject (submodule) support_, which would
   certainly help using git for large modular projects like KDE,
   Mozilla or distributions.
 * lightweight checkout aka. .gitlink idea, to have file which
   would point to object directory, refs directory, index file
   and current branch file. It could help submodule support.
 * partial/sparse checkouts, where you can checkout for example
   only Documentation directory, work on it, but commit full tree.
   Sometimes it better suits than using submodules
 * gitweb caching and other gitweb improvements: bringing together
   all gitweb implementations. Perhaps gitweb maintainer could
   come of it. Or at least gitweb admin for kernel.org
 * builtinification and libification
 * lazy clone aka remote alternates, if it can be done at all...
 
> Google's FAQ has a lot of details, but the important part which
> lists what should be included in an application can be found here:
> 
>   http://code.google.com/support/bin/answer.py?answer=60303&topic=10727
> 
> I don't know how the great SoC filter works for organizations,
> but last year's list (found at http://code.google.com/soc/) has a
> number of projects listed on it that are actively using Git for their
> version control.  It would be nice if the SoC program was able to
> benefit multiple projects in one shot, by helping to improve Git. :)

The other SCM which participated in SOC2006, Subversion and Monotone,
both are backed by organizations. Mercurial didn't participate, but has
a page with ideas for SOC2006.

If Eclipse is to participate, perhaps one of Eclipse projects could be
git plugin for Eclipse, or Java implementation of Git (perhaps with some
Java improvements :-), or perhaps some generic distributed SCM plugin
framework.

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply	[relevance 3%]

* GIT v1.5.1-rc1
  @ 2007-03-19 10:53  1%       ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2007-03-19 10:53 UTC (permalink / raw)
  To: git

Some 1000 messages ago, I sent out a short-term release plan and
listed the topics that we would want to have in 1.5.1.  As of
last week, all of them have been cooked enough in 'next' and now
are in 'master'.

The last round to reach 1.5.0 took painfully long.  While it was
worth it, considering that 1.5.0 is a big departure from 1.4.4
series and satisfied our "usability and teachability" goal, I
think we should slow down and make smaller releases a bit more
often.  So I tagged the tip of the 'master' with -rc1 tag, after
fixing one issue that has been nagging me while it was in 'next'.

So from now on until the final, which I am hoping to do before
the end of month, please concentrate on fixes and "obviously
low-impact" improvements.

With the system we have in place that uses two primary
integration branches to manage git.git project, earth-shattering
enhancements or new commands could still be cooked in 'pu', or
theoretically even in 'next' without causing problems to the
stabilization effort, but I'd rather see people's attention on
perfecting what will be in 1.5.1 before starting anything new.
I expect to spend much less time looking at any material that
are not meant for 'master' until the end of the month, so please
consider that the chance of getting things in 'next' is very
slim from now on.  I might queue new stuff in 'pu' only to give
a distribution point that is easier to access for everybody to
test, but I won't guarantee that the branch will even compile.

Having said that, there always are exceptions to the rule.

Some of the things we have reviewed and discussed on the list
for the past several days might have been good for 'next' (or
even 'master').  I did not have enough time to look at them
fully, I might have missed them, and/or I commented on them with
intention to cook them in 'next' but might have forgotten to
apply.  If they are reasonably well isolated new features
(e.g. "remote show showing push entries") I would not mind
applying them, but please make convincing sales talk to explain
why your new feature is useful to users.  If it is something so
commonly useful to be placed on "Everyday GIT", or tutorial,
adding a paragraph to these documents to show why it is a *must*
*have* is a good way to sell your ware, for example.

Also I might have dropped a handful patches to non-core area,
e.g. contrib/emacs/ and cvs interface.  Please remind me of them
if they should be in 1.5.1 by cheering them on with your Acks,
resends, and follow-up patches.

Even though it is rather core area, I suspect that it wouldn't
be a change with huge impact to exploit what Linus did today to
allow optimizing pathspec pruning in tree_entry_interesting().
If such a change is done obviously correctly, I think it is Ok
to have it in 'next' and make it graduate to 'master' before
1.5.1 final.

Although we've talked about it for a while, the more I look at
the current code, the more I feel that resolving the issue of
"read-tree -m" gotcha that causes switching between branches
that have file (or symlink) A and a directory A would be quite
high impact, so unless there is an obviously correct fix, I'd
like to defer it post 1.5.1.

Finally, here is to review what we have so far to be in the
upcoming 1.5.1.  Patches to Documentation/RelNotes-1.5.1.txt to
fill items I missed, older than ceb8442a, are very much
appreciated.


GIT v1.5.1 Release Notes (draft)
========================

Updates since v1.5.0
--------------------

* Deprecated commands and options.

  - git-diff-stages and git-resolve have been removed.

* New commands and options.

  - "git log" and friends take --reverse.  This makes output
    that typically goes reverse order in chronological order.
    "git shortlog" usually lists commits in chronological order,
    but with "--reverse", they are shown in reverse
    chronological order.

  - "git diff" learned --ignore-space-at-eol.  This is a weaker
    form of --ignore-space-change.

  - "git diff --no-index pathA pathB" can be used as diff
    replacement with git specific enhancements.

  - "git diff --pretty=format:<string>" to allow more flexible
    custom log output.

  - "git diff --no-index" can read from '-' (standard input).

  - "git diff" also learned --exit-code to exit with non-zero
    status when it found differences.  In the future we might
    want to make this the default but that would be a rather big
    backward incompatible change; it will stay as an option for
    now.

  - "git branch --track" can be used to set up configuration
    variables to help it easier to base your work on branches
    you track from a remote site.

  - "git format-patch --attach" now emits attachments.  Use
    --inline to get an inlined multipart/mixed.

  - "git name-rev" learned --refs=<pattern>, to limit the tags
    used for naming the given revisions only to the ones
    matching the given pattern.

  - "git remote update" is to run "git fetch" for defined remotes
    to update tracking branches.

  - "git cvsimport" can now take '-d' to talk with a CVS
    repository different from what are recorded in CVS/Root
    (overriding it with environment CVSROOT does not work).

  - "git bundle" can help sneaker-netting your changes between
    repositories.

  - "git mergetool" can help 3-way file-level conflict
    resolution with your favorite graphical merge tools.

  - A new configuration "core.symlinks" can be used to disable
    symlinks on filesystems that do not support them; they are
    checked out as regular files instead.


* Updated behaviour of existing commands.

  - "git fsck" does not barf on corrupt loose objects.

  - "git archimport" allows remapping when coming up with git
    branch names from arch names.

  - git-svn got almost a rewrite.

  - core.autocrlf configuration, when set to 'true', makes git
    to convert CRLF at the end of lines in text files to LF when
    reading from the filesystem, and convert in reverse when
    writing to the filesystem.  The variable can be set to
    'input', in which case the conversion happens only while
    reading from the filesystem but files are written out with
    LF at the end of lines.  Currently, which paths to consider
    'text' (i.e. be subjected to the autocrlf mechanism) is
    decided purely based on the contents, but the plan is to
    allow users to explicitly override this heuristic based on
    paths.

  - The behaviour of 'git-apply', when run in a subdirectory,
    without --index nor --cached were inconsistent with that of
    the command with these options.  This was fixed to match the
    behaviour with --index.  A patch that is meant to be applied
    with -p1 from the toplevel of the project tree can be
    applied with any custom -p<n> option.  A patch that is not
    relative to the toplevel needs to be applied with -p<n>
    option with or without --index (or --cached).

  - "git diff" outputs a trailing HT when pathnames have embedded
    SP on +++/--- header lines, in order to help "GNU patch" to
    parse its output.  "git apply" was already updated to accept
    this modified output format since ce74618d (Sep 22, 2006).

  - "git cvsserver" runs hooks/update and honors its exit status.

  - "git cvsserver" can be told to send everything with -kb.

  - "git diff --check" also honors the --color output option.

  - "git name-rev" used to stress the fact that a ref is a tag too
    much, by saying something like "v1.2.3^0~22".  It now says
    "v1.2.3~22" in such a case (it still says "v1.2.3^0" if it does
    not talk about an ancestor of the commit that is tagged, which
    makes sense).

  - "git rev-list --boundary" now shows boundary markers for the
    commits omitted by --max-age and --max-count condition.

  - The configuration mechanism now reads $(prefix)/etc/gitconfig.

  - "git apply --verbose" shows what preimage lines were wanted
    when it couldn't find them.

  - "git status" in a read-only repository got a bit saner.

  - "git fetch" (hence "git clone" and "git pull") are less
    noisy when the output does not go to tty.

  - "git fetch" between repositories with many refs were slow
    even when there are not many changes that needed
    transferring.  This has been sped up by partially rewriting
    the heaviest parts in C.

  - "git mailinfo" which splits an e-mail into a patch and the
    metainformation was rewritten, thanks to Don Zickus.  It
    handles nested multipart better.

  - send-email learned configurable bcc and chain-reply-to.

  - Using objects from packs is now seriouly optimized by clever
    use of a cache.  This should be most noticeable in git-log
    family of commands that involve reading many tree objects.
    In addition, traversing revisions while filtering changes
    with pathspecs is made faster by terminating the comparison
    between the trees as early as possible.


* Hooks

  - The sample update hook to show how to send out notification
    e-mail was updated to show only new commits that appeared in
    the repository.  Earlier, it showed new commits that appeared
    on the branch.


* Others

  - git-revert, git-gc and git-cherry-pick are now built-ins.

^ permalink raw reply	[relevance 1%]

* Re: .gitlink for Summer of Code
  @ 2007-03-27 23:20  4%       ` David Lang
  0 siblings, 0 replies; 200+ results
From: David Lang @ 2007-03-27 23:20 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

On Wed, 28 Mar 2007, Jakub Narebski wrote:

>> if I'm working on the 'ubuntu superproject' it would be nice to be able to find
>> what is different between the 'Jan 2007' and 'April 2007' versions. one could
>> have the 2.6.19 kernel and the other would have 2.6.20. I don't care about all
>> the individual changes between these two states of the kernel, but I need to be
>> able to compile either one as part of my testing. If I bisect the in the
>> superproject to the commit that updated the kernel, then I would consider
>> getting the 'kernel subproject' history to be able to bisect the bug further (or
>> I may just report it to the kernel maintainers for them to check.
>
> I'd rather call this idea _sparse_ clone (not shallow), as you have only
> some points in the history, but they don't need to be top 'n' ones.

Ok I can see the difference in the definition of the two, the ideal would 
probably be to have sparse and shallow clones be different instances of the same 
mechanism.

  sparse being specific points in the history, shallow being a range.

  allow for multiple ranges, and the ability to 'fill in the blanks' later so 
that points can become ranges and ranges can merge.

also having the server say 'it would only be XMB more to pull everything you 
don't have, do you want to do this?' would cause more load on the server for 
each of the partial pulls, but would encourage people to fill out partial 
repositories instead of hitting the servers repeatedly.

David Lang

^ permalink raw reply	[relevance 4%]

* [ANNOUNCE] GIT 1.5.1
@ 2007-04-04  9:12  1% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2007-04-04  9:12 UTC (permalink / raw)
  To: git; +Cc: linux-kernel

The latest feature release GIT 1.5.1 is available at the usual
places:

  http://www.kernel.org/pub/software/scm/git/

  git-1.5.1.tar.{gz,bz2}			(tarball)
  git-htmldocs-1.5.1.tar.{gz,bz2}		(preformatted docs)
  git-manpages-1.5.1.tar.{gz,bz2}		(preformatted docs)
  RPMS/$arch/git-*-1.5.1-1.$arch.rpm	(RPM)

----------------------------------------------------------------
GIT v1.5.1 Release Notes
========================

Updates since v1.5.0
--------------------

* Deprecated commands and options.

  - git-diff-stages and git-resolve have been removed.

* New commands and options.

  - "git log" and friends take --reverse, which instructs them
    to give their output in the order opposite from their usual.
    They typically output from new to old, but with this option
    their output would read from old to new.  "git shortlog"
    usually lists older commits first, but with this option,
    they are shown from new to old.

  - "git log --pretty=format:<string>" to allow more flexible
    custom log output.

  - "git diff" learned --ignore-space-at-eol.  This is a weaker
    form of --ignore-space-change.

  - "git diff --no-index pathA pathB" can be used as diff
    replacement with git specific enhancements.

  - "git diff --no-index" can read from '-' (standard input).

  - "git diff" also learned --exit-code to exit with non-zero
    status when it found differences.  In the future we might
    want to make this the default but that would be a rather big
    backward incompatible change; it will stay as an option for
    now.

  - "git diff --quiet" is --exit-code with output turned off,
    meant for scripted use to quickly determine if there is any
    tree-level difference.

  - Textual patch generation with "git diff" without -w/-b
    option has been significantly optimized.  "git blame" got
    faster because of the same change.

  - "git log" and "git rev-list" has been optimized
    significantly when they are used with pathspecs.

  - "git branch --track" can be used to set up configuration
    variables to help it easier to base your work on branches
    you track from a remote site.

  - "git format-patch --attach" now emits attachments.  Use
    --inline to get an inlined multipart/mixed.

  - "git name-rev" learned --refs=<pattern>, to limit the tags
    used for naming the given revisions only to the ones
    matching the given pattern.

  - "git remote update" is to run "git fetch" for defined remotes
    to update tracking branches.

  - "git cvsimport" can now take '-d' to talk with a CVS
    repository different from what are recorded in CVS/Root
    (overriding it with environment CVSROOT does not work).

  - "git bundle" can help sneaker-netting your changes between
    repositories.

  - "git mergetool" can help 3-way file-level conflict
    resolution with your favorite graphical merge tools.

  - A new configuration "core.symlinks" can be used to disable
    symlinks on filesystems that do not support them; they are
    checked out as regular files instead.

  - You can name a commit object with its first line of the
    message.  The syntax to use is ':/message text'.  E.g.

    $ git show ":/object name: introduce ':/<oneline prefix>' notation"

    means the same thing as:

    $ git show 28a4d940443806412effa246ecc7768a21553ec7

  - "git bisect" learned a new command "run" that takes a script
    to run after each revision is checked out to determine if it
    is good or bad, to automate the bisection process.

  - "git log" family learned a new traversal option --first-parent,
    which does what the name suggests.


* Updated behavior of existing commands.

  - "git-merge-recursive" used to barf when there are more than
    one common ancestors for the merge, and merging them had a
    rename/rename conflict.  This has been fixed.

  - "git fsck" does not barf on corrupt loose objects.

  - "git rm" does not remove newly added files without -f.

  - "git archimport" allows remapping when coming up with git
    branch names from arch names.

  - git-svn got almost a rewrite.

  - core.autocrlf configuration, when set to 'true', makes git
    to convert CRLF at the end of lines in text files to LF when
    reading from the filesystem, and convert in reverse when
    writing to the filesystem.  The variable can be set to
    'input', in which case the conversion happens only while
    reading from the filesystem but files are written out with
    LF at the end of lines.  Currently, which paths to consider
    'text' (i.e. be subjected to the autocrlf mechanism) is
    decided purely based on the contents, but the plan is to
    allow users to explicitly override this heuristic based on
    paths.

  - The behavior of 'git-apply', when run in a subdirectory,
    without --index nor --cached were inconsistent with that of
    the command with these options.  This was fixed to match the
    behavior with --index.  A patch that is meant to be applied
    with -p1 from the toplevel of the project tree can be
    applied with any custom -p<n> option.  A patch that is not
    relative to the toplevel needs to be applied with -p<n>
    option with or without --index (or --cached).

  - "git diff" outputs a trailing HT when pathnames have embedded
    SP on +++/--- header lines, in order to help "GNU patch" to
    parse its output.  "git apply" was already updated to accept
    this modified output format since ce74618d (Sep 22, 2006).

  - "git cvsserver" runs hooks/update and honors its exit status.

  - "git cvsserver" can be told to send everything with -kb.

  - "git diff --check" also honors the --color output option.

  - "git name-rev" used to stress the fact that a ref is a tag too
    much, by saying something like "v1.2.3^0~22".  It now says
    "v1.2.3~22" in such a case (it still says "v1.2.3^0" if it does
    not talk about an ancestor of the commit that is tagged, which
    makes sense).

  - "git rev-list --boundary" now shows boundary markers for the
    commits omitted by --max-age and --max-count condition.

  - The configuration mechanism now reads $(prefix)/etc/gitconfig.

  - "git apply --verbose" shows what preimage lines were wanted
    when it couldn't find them.

  - "git status" in a read-only repository got a bit saner.

  - "git fetch" (hence "git clone" and "git pull") are less
    noisy when the output does not go to tty.

  - "git fetch" between repositories with many refs were slow
    even when there are not many changes that needed
    transferring.  This has been sped up by partially rewriting
    the heaviest parts in C.

  - "git mailinfo" which splits an e-mail into a patch and the
    meta-information was rewritten, thanks to Don Zickus.  It
    handles nested multipart better.  The command was broken for
    a brief period on 'master' branch since 1.5.0 but the
    breakage is fixed now.

  - send-email learned configurable bcc and chain-reply-to.

  - "git remote show $remote" also talks about branches that
    would be pushed if you run "git push remote".

  - Using objects from packs is now seriously optimized by clever
    use of a cache.  This should be most noticeable in git-log
    family of commands that involve reading many tree objects.
    In addition, traversing revisions while filtering changes
    with pathspecs is made faster by terminating the comparison
    between the trees as early as possible.


* Hooks

  - The part to send out notification e-mails was removed from
    the sample update hook, as it was not an appropriate place
    to do so.  The proper place to do this is the new post-receive
    hook.  An example hook has been added to contrib/hooks/.


* Others

  - git-revert, git-gc and git-cherry-pick are now built-ins.

Fixes since v1.5.0
------------------

These are all in v1.5.0.x series.

* Documentation updates

  - Clarifications and corrections to 1.5.0 release notes.

  - The main documentation did not link to git-remote documentation.

  - Clarified introductory text of git-rebase documentation.

  - Converted remaining mentions of update-index on Porcelain
    documents to git-add/git-rm.

  - Some i18n.* configuration variables were incorrectly
    described as core.*; fixed.

  - added and clarified core.bare, core.legacyheaders configurations.

  - updated "git-clone --depth" documentation.

  - user-manual updates.

  - Options to 'git remote add' were described insufficiently.

  - Configuration format.suffix was not documented.

  - Other formatting and spelling fixes.

  - user-manual has better cross references.

  - gitweb installation/deployment procedure is now documented.


* Bugfixes

  - git-upload-pack closes unused pipe ends; earlier this caused
    many zombies to hang around.

  - git-rerere was recording the contents of earlier hunks
    duplicated in later hunks.  This prevented resolving the same
    conflict when performing the same merge the other way around.

  - git-add and git-update-index on a filesystem on which
    executable bits are unreliable incorrectly reused st_mode
    bits even when the path changed between symlink and regular
    file.

  - git-daemon marks the listening sockets with FD_CLOEXEC so
    that it won't be leaked into the children.

  - segfault from git-blame when the mandatory pathname
    parameter was missing was fixed; usage() message is given
    instead.

  - git-rev-list did not read $GIT_DIR/config file, which means
    that did not honor i18n.logoutputencoding correctly.

  - Automated merge conflict handling when changes to symbolic
    links conflicted were completely broken.  The merge-resolve
    strategy created a regular file with conflict markers in it
    in place of the symbolic link.  The default strategy,
    merge-recursive was even more broken.  It removed the path
    that was pointed at by the symbolic link.  Both of these
    problems have been fixed.

  - 'git diff maint master next' did not correctly give combined
    diff across three trees.

  - 'git fast-import' portability fix for Solaris.

  - 'git show-ref --verify' without arguments did not error out
    but segfaulted.

  - 'git diff :tracked-file `pwd`/an-untracked-file' gave an extra
    slashes after a/ and b/.

  - 'git format-patch' produced too long filenames if the commit
    message had too long line at the beginning.

  - Running 'make all' and then without changing anything
    running 'make install' still rebuilt some files.  This
    was inconvenient when building as yourself and then
    installing as root (especially problematic when the source
    directory is on NFS and root is mapped to nobody).

  - 'git-rerere' failed to deal with two unconflicted paths that
    sorted next to each other.

  - 'git-rerere' attempted to open(2) a symlink and failed if
    there was a conflict.  Since a conflicting change to a
    symlink would not benefit from rerere anyway, the command
    now ignores conflicting changes to symlinks.

  - 'git-repack' did not like to pass more than 64 arguments
    internally to underlying 'rev-list' logic, which made it
    impossible to repack after accumulating many (small) packs
    in the repository.

  - 'git-diff' to review the combined diff during a conflicted
    merge were not reading the working tree version correctly
    when changes to a symbolic link conflicted.  It should have
    read the data using readlink(2) but read from the regular
    file the symbolic link pointed at.

  - 'git-remote' did not like period in a remote's name.

  - 'git.el' honors the commit coding system from the configuration.

  - 'blameview' in contrib/ correctly digs deeper when a line is
    clicked.

  - 'http-push' correctly makes sure the remote side has leading
    path.  Earlier it started in the middle of the path, and
    incorrectly.

  - 'git-merge' did not exit with non-zero status when the
    working tree was dirty and cannot fast forward.  It does
    now.

  - 'cvsexportcommit' does not lose yet-to-be-used message file.

  - int-vs-size_t typefix when running combined diff on files
    over 2GB long.

  - 'git apply --whitespace=strip' should not touch unmodified
    lines.

  - 'git-mailinfo' choke when a logical header line was too long.

  - 'git show A..B' did not error out.  Negative ref ("not A" in
    this example) does not make sense for the purpose of the
    command, so now it errors out.

  - 'git fmt-merge-msg --file' without file parameter did not
    correctly error out.

  - 'git archimport' barfed upon encountering a commit without
    summary.

  - 'git index-pack' did not protect itself from getting a short
    read out of pread(2).

  - 'git http-push' had a few buffer overruns.

  - Build dependency fixes to rebuild fetch.o when other headers
    change.

  - git.el does not add duplicate sign-off lines.

  - git-commit shows the full stat of the resulting commit, not
    just about the files in the current directory, when run from
    a subdirectory.

  - "git-checkout -m '@{8 hours ago}'" had a funny failure from
    eval; fixed.

  - git-merge (hence git-pull) did not refuse fast-forwarding
    when the working tree had local changes that would have
    conflicted with it.

  - a handful small fixes to gitweb.

  - build procedure for user-manual is fixed not to require locally
    installed stylesheets.

  - "git commit $paths" on paths whose earlier contents were
    already updated in the index were failing out.


* Tweaks

  - sliding mmap() inefficiently mmaped the same region of a
    packfile with an access pattern that used objects in the
    reverse order.  This has been made more efficient.

^ permalink raw reply	[relevance 1%]

* Re: [PATCH 5/6] Teach "fsck" not to follow subproject links
  @ 2007-04-12 18:32  1%           ` Dana How
  0 siblings, 0 replies; 200+ results
From: Dana How @ 2007-04-12 18:32 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: David Lang, Sam Vilain, Git Mailing List, Junio C Hamano, danahow

On 4/11/07, Linus Torvalds <torvalds@linux-foundation.org> wrote:
> On Wed, 11 Apr 2007, David Lang wrote:
> > this is why I was suggesting a --multiple-project option to let you tell fsck
> > about all of the repositories that it needs to look for refs in.
>
> Well, just from a personal observation:
>  - I would *personally* actually refuse to share objects with anybody
>    else.
>
> I just find the idea too scary. Somebody doing something bad to their
> object store by mistake (running "git prune" without realizing that there
> are *my* objects there too, or just deciding that they want to play with
> the object directory by hand, or running a new fancy experimental importer
> that has a subtle bug wrt object handling or anything like that).
>
> I'll endorse use "alternates" files, but partly because I know the main
> project is safe (any alternates usage is in the "satellite" clones anyway,
> and they will never write to the alternate object directory), and partly
> because at least for the kernel, we don't have branches that get reset in
> the main project, so there's no reason to fear that a "git repack -a -d"
> will ever screw up any of the satellite repositories even by mistake.
>
> But for git projects, even alternates isn't safe, in case somebody bases
> their own work on a version of "pu" that eventually goes away (even with
> reflogs, pruning *eventually* takes place).
>
> So I tend to think that alternates and shared object directories are
> really for "temporary" stuff, or for *managed* repositories that are at
> git *hosting* sites (eg repo.or.cz), and where there is some other safety
> involved, ie users don't actually access the object directories directly
> in any way.
>
> So I've at least personally come to the conclusion that for a *developer*
> (as opposed to a hosting site!), shared object directories just never make
> sense. The downsides are just too big. Even alternates is something where
> you just need to be fairly careful!

These arguments all seem pretty convincing to me --
maybe the problem is that I'm not a "*developer*" right now.
Instead I'm part of a multi-developer *site*.
Below I talk about a possible way we could use git
without changing it (since I recognize this would be a minority usage pattern).

We use perforce to manage a mixed hardware/software project
(I'm the 55GB check-out guy, remember?).  We have at least 3 different
kinds of data with different usage patterns, and using perforce for
everything in one centralized server was not the best solution.

Each user ("client") has their own worktree and the perforce
repository is on a shared central server.  You can consider perforce
to have the equivalent of git's index, but it is stored on the server,
in one file ("db.have") covering all clients.  Obviously that becomes a
bottleneck -- and recently db.have got larger than the total cache RAM on
the server, which really slowed things down until we moved to a larger
server.  But repository architecture aside,  the real problem has been
perforce's usability.  Frequently one contributor,  having gotten ahead
of the team,  needs to share this more recent work with only a few
people.  This could be done with p4 branching,  but this is really clunky.
So instead the work is pushed out (submitted) to everyone, causing
instability; this is partially remedied by doing it in smaller chunks.
Another perforce problem is that tagging consumes a lot of server
space (and may slow things down as well).

Some of this data will stay in perforce, some will move into revision
control built-in to some of our other tools, and I'd like to try to move some
of it into git.  The main attraction for the last group is the lightweight
branching that would allow early/tentative work to be easily shared.
I think the subproject work currently being discussed is going to
be very helpful as well -- the perforce equivalent is chaotic.

We could give each user a work tree and an object repository,
and then have a "release" repository.  Unfortunately,  this would be
slower to use than the current perforce "solution": users would check
in to their local repository, at the speed of gzip, anyone checking
it out would do so at the speed of gzip, and all work would need
to be resubmitted (using perforce jargon here) to the central repo,
again at the speed of gzip.  Currently, people either submit or
check out from the central repo, and it's all done at the speed of
a network copy.  This speed issue is important because of
the size of a commit we'd like to share (but not yet release):
about 40 files, half of them control files of several KB each, 1/4 of them
design files of several MB each, and the last 1/4 detailed design
files 100X larger.  These 40 files will reference (include) 50 others
of several KB each sprinkled through-out the hierarchy, a few of which
might have changed.  And yes, almost all of these are generated files,
but the generation time, and the instability of the tool and script environment,
preclude forcing the other users to regenerate them, like you would
with a .o file.

So, there are 2 alternative set-ups. In one, everyone uses a shared
object repository (everyone's .git/objects is a symlink to it). In this
repository, objects/. , objects/?? , objects/pack , and objects/info all
have "sticky" set, and we do the appropriate machinations to make
all files read-only. There would be an additional phantom user "git"
who owns the shared object repository (the only user whose .git/objects
is not a symlink).  Users would commit to their own repositories,
which would write data to the shared object repository and
update their refs (e.g. HEAD). To "release", push to the ~git repository.
This push would be like a current push -- fast-forward only, figure out the list
of objects that need to be transmitted -- but instead of transmitting the
objects, change their ownership to ~git and then update ~git's refs.
Since users can share local commits, maybe the ~git ownership
change should happen at commit time.  This all seems do-able
without change in git; instead I'd add a few bash wrapper scripts
(and see below for fsck and pack/prune).

Another setup is like the previous, but make the central repo have
its own hidden object repository. You would push to it using the
standard git command.

Finally, users could run git-fsck [with misleading output];
they could run git-prune{,-packed}, but these commands wouldn't
be able to delete anything.  If we don't want users to pack,
then ~git/.git/objects/pack would be writable only by ~git.
So basically, normal people wouldn't do the things in this paragraph.

To do meaningful and safe fsck/prune on the shared repository
as ~git,  I'd add some scripting.  If you require all users'
GIT_DIR's to look like /home/USER/*/.git , then you can get all
their refs and do a meaningful fsck.  If not, you could do a fsck
--unreachable as ~git and filter the result by date and/or type.
(This sort of corresponds to abandoned changesets in perforce.)
Once you have an fsck method you like, its filtered output (i.e.,
--unreachable objects you want to keep) can be fed to git-prune.

Care would also be required with git-repack/git-prune-packed,
but it seems mostly addressable with scheduling.

If I proceed down this path,  I'd like to implement this procedure
without any change in git's .c or .sh files.  It's clear this is a
minority use and should not depend on anything being maintained
for it inside git.  I would write a few bash scripts and a README/HOWTO
for possible inclusion in contrib.

BTW,
has anyone ever thought of writing an "Administrator's Manual" for git?

Thanks,
-- 
Dana L. How  danahow@gmail.com  +1 650 804 5991 cell

^ permalink raw reply	[relevance 1%]

* Re: GIT vs Other: Need argument
  @ 2007-04-19 12:57  3%     ` Andy Parkins
  0 siblings, 0 replies; 200+ results
From: Andy Parkins @ 2007-04-19 12:57 UTC (permalink / raw)
  To: git; +Cc: Marcin Kasperski

On Thursday 2007 April 19 12:59, Marcin Kasperski wrote:
> > but git is definitely no harder to learn
> > than anything else.  I browsed through the mecurial tutorial
> > yesterday - and as well as being significantly less powerful than git,
> > it's no easier.
>
> Mercurial is easier to learn, because it has better docs and slightly
> simpler command line (all those -a, -p, ... options which one always
> forgets to add). I tried it.
> In fact, I did the experiment about month ago. I wanted to give a try
> to distributed vc tool. I started from GIT, played a bit with it, and
> abandoned it because a) I did not know whether I am expected to use git,
> or cg, b) While reading docs many times I had the feeling that something
> strange and unclear is going behind the hood.

In terms of normal operation, there aren't many switches one actually needs to 
remember.  The only one I can think of is "-a" for commit - however, that's 
just to make it work like mercurial - a seasoned git user won't use many 
switches.  My daily grind consists of

 git add file.c
 git commit
 git add file.c
 git commit
 git add -i
 git commit

(Interactive mode for git-add is a joy to use - I don't know if Mercurial has 
anything similar).

Now, to your point.  I think you're right.  What I said was that git actually 
is easier; however if you looked at some of the documentation you would 
incorrectly assume that that was not the case.

> > (I can't believe this one - if you want to branch a mercurial repository
> > you have to have another complete checkout.  Erm... the checkout takes
> > up more space than the repository - why do I need another copy? Anyway,
> > git is no harder than Mercurial here)
>
> AFAIK you are wrong, they are able to link some files while cloning, so

Can't be.  I'm talking about the working directory not the repository - if the 
files are linked back to the originals, then it's not a separately editable 
set of files is it?

> you loose space only if you switch machine or filesystem. Also, recent
> mercurial has initial within-repo branches support. But I am not really
> the best person to conduct git-vs-hg discussion.

I'm glad that Mercurial is getting in-repo branches, they're great.  I really 
wouldn't want to live without them now I have them.

> > "(Note for Windows users: Mercurial is missing a merge program" - that
> > Windows support isn't looking quite so hot now.
>
> Mercurial on windows works well with kdiff3 or tortoisemerge, you must
> only install one of them.

Aren't they manual merge tools?  I think "merge" is for merging automatically, 
and moaning about conflicts if they turn up - /then/ you go to tortoisemerge.

> As I said, I am not conducting hg-vs-git discussion. I just happened
> to introduce and manage VC system in corporate environment, so I am able
> to point that this is important feature.

I appreciate that - I don't want to start a fight.  My point should probably 
have been more directly focussed on git (which was what I wanted to do) - 
it's my opinion that git is in fact easier than Mercurial; however, it's 
public face is not letting people see that.

> > As for permissions, well Shawn has often spoken of his hook scripts that
> > implement very strong permissions (and he has done so again in this
> > thread).
>
> I am not quite sure how can you forbid johny to see the code
> in ./secret, while johny must checkout whole repo...

Me either - the only permissions that could have been relevant are those 
needed to push to the central repository.  As I said, git can cope there 
without trouble.

> Permissions are not only about writing.

That one is true - perhaps one day git will get partial clone support to match 
it's shallow clones - then it would be possible to put permissions on the 
read of a central repository.  Can Mercurial do that?

> > Depends what you want - I installed cygwin
>
> This is really not an option for typical windows user. Believe me.
> Maybe it could be, if cygwin managed to create normal setup program
> one day...

I'm not an expert in Windows by any means - all I did was run setup.exe and 
picked git and ssh from the list.  It doesn't get much easier.

> Let me retype it: I am not complaining. GIT developers are not forced to
> think about win users, or about corporate needs. But if they are, it is
> reasonable to know the problems.

Absolutely - I certainly haven't taken anything you've written as a complaint.  
If anything I find it interesting because I think it confirms what I 
thought - git is not short on features or usability, it's just got a PR 
problem.


Andy
-- 
Dr Andy Parkins, M Eng (hons), MIET
andyparkins@gmail.com

^ permalink raw reply	[relevance 3%]

* Git benchmarks at OpenOffice.org wiki
@ 2007-05-01 21:46  2% Jakub Narebski
  2007-05-01 22:27  3% ` Junio C Hamano
  2007-05-02 14:24  0% ` Jan Holesovsky
  0 siblings, 2 replies; 200+ results
From: Jakub Narebski @ 2007-05-01 21:46 UTC (permalink / raw)
  To: git; +Cc: releases, Jan Holesovsky

OpenOffice.org is looking for a new SCM (Software Configuration 
Management) tool, or at least was on Friday, 19 Jan 2007;
see: http://blogs.sun.com/GullFOSS/entry/openoffice_org_scm

One of the SCMs considered is Git. One of others is Subversion.
There is a functional git tree with the entire OOo history for testing 
purposes that can be found at: http://go-oo.org/git.

What I am concerned about is some of git benchmark results at Git page 
on OpenOffice.org wiki:
  http://wiki.services.openoffice.org/wiki/Git#Comparison
Actually it is comparison with CVS and Subversion, although most 
benchmarks are done only for git.


In 'Size of data on the server' git has CVS beat hands down: 1.3G vs 
8.5G for sources, 591M vs 1.1G for third party. I think it is similar
for Subversion. I hope that repository is fully packed: IIRC the Mozilla
CVS repository import was about 0.6GB pack file, not 1.3GB.


The problem is with 'Size of checkout': to start working in repository
one needs 1.4G (sources) and 98M (third party) for CVS checkout (it is
1.5G for sources for Subversion checkout). Ordinary for distributed SCM
you would need size of repository + size of sources (working area), 
which is 2.8G for sources and 688M for third party stuff files you can 
hack on + the history]. This makes some prefer to go centralized SCM 
route, i.e. Subversion as replacement for CVS (+ CWS, ChildWorkSpace).

What might help here is splitting repository into current (e.g. from
OOo 2.0) and historical part, and / or using shallow clone. Implementing 
partial checkouts, i.e. checking out only part of working area (and 
using 'theirs' strategy for merging not-checked-out part for merges) 
would help. Splitting repository into submodules, and submodule
support -- it depends on organization of OOo sources, would certainly 
help for third party stuff repository.

'Checkout time' (which should be renamed to 'Initial checkout time'),
in which git also loses with 130 minutes (Linux, 2MBit DSL) [from 
go-oo.org], 100min (Linux, 2MBit DSL, Wireless, no proxy) [from 
go-oo.org] versus 117 minutes (Linux, 2MBit DSL), 26 minutes (Linux, 
2MBit DSL, with compression (-z 6)) for CVS, and  60 Minutes (Windows, 
34Mbit Line) for Subversion, would also be helped by the above.


What I'm really concerned about is branch switch and merging branches,
when one of the branches is an old one (e.g. unxsplash branch), which 
takes 3min (!) according to the benchmark. 13-25sec for commit is also 
bit long, but BRANCH SWITCHING which takes 3 MINUTES!? There is no 
comparison benchmark for CVS or Subversion, though...

Comparison / benchmark lacks some crucial info, like what computer was 
used (CPU, RAM, HDD), what filesystem was used, git version etc. It 
does have commands used for tests (benchmarks).

Could you confirm (or deny) those results? go-oo.org uses git 1.4.3.4;
was there some improvement or bugfix related to the speed of checkout?

-- 
Jakub Narebski
ShadeHawk on #git
Poland

^ permalink raw reply	[relevance 2%]

* Re: Git benchmarks at OpenOffice.org wiki
  2007-05-01 21:46  2% Git benchmarks at OpenOffice.org wiki Jakub Narebski
@ 2007-05-01 22:27  3% ` Junio C Hamano
  2007-05-02 14:24  0% ` Jan Holesovsky
  1 sibling, 0 replies; 200+ results
From: Junio C Hamano @ 2007-05-01 22:27 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git, releases, Jan Holesovsky

Jakub Narebski <jnareb@gmail.com> writes:

> What might help here is splitting repository into current (e.g. from
> OOo 2.0) and historical part, and / or using shallow clone.

Yes, depending on where you cut off and how reasonable the
project history is.

> Implementing 
> partial checkouts, i.e. checking out only part of working area (and 
> using 'theirs' strategy for merging not-checked-out part for merges) 
> would help.

Partial checkouts, perhaps, "theirs", NO.

Consider that you are working on the tip with partial checkout.
Somebody has a bugfix that is applicable to all of ancient, old,
maintenance and current codebase.  Naturally you would want the
bugfix to be applied to ancient, merge it to old, and then
maintenance and then current (the last one is what you are
working on).

What happens if you actually pull ancient when you are partially
checked out and use "theirs"?

> Splitting repository into submodules, and submodule
> support -- it depends on organization of OOo sources, would certainly 
> help for third party stuff repository.

This is probably the most sane way.

^ permalink raw reply	[relevance 3%]

* Re: Git benchmarks at OpenOffice.org wiki
  2007-05-01 21:46  2% Git benchmarks at OpenOffice.org wiki Jakub Narebski
  2007-05-01 22:27  3% ` Junio C Hamano
@ 2007-05-02 14:24  0% ` Jan Holesovsky
  2007-05-02 23:30  4%   ` Jakub Narebski
  1 sibling, 1 reply; 200+ results
From: Jan Holesovsky @ 2007-05-02 14:24 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git, releases

Hi Jakub,

On Tuesday 01 May 2007 23:46, Jakub Narebski wrote:

> OpenOffice.org is looking for a new SCM (Software Configuration
> Management) tool, or at least was on Friday, 19 Jan 2007;
> see: http://blogs.sun.com/GullFOSS/entry/openoffice_org_scm
>
> One of the SCMs considered is Git. One of others is Subversion.
> There is a functional git tree with the entire OOo history for testing
> purposes that can be found at: http://go-oo.org/git.
>
> What I am concerned about is some of git benchmark results at Git page
> on OpenOffice.org wiki:
>   http://wiki.services.openoffice.org/wiki/Git#Comparison
> Actually it is comparison with CVS and Subversion, although most
> benchmarks are done only for git.

I did the git numbers, so if they are wrong - blame me :-)  I am also curious
about the SVN numbers, because the SVN conversion [from my point of view]
cheats a lot.  From what I know, it does not contain the historical branches
(yes, the >3000 of them that are in the git tree), and if I understood that
correctly, instead of history in the branches, they commit just
'integration commits' [one commit for all the changes in the branch] which
breaks 'svn blame' completely.

Unfortunately, I did not have a chance to try the SVN tree yet to see it
myself to prove this true or false :-(

> In 'Size of data on the server' git has CVS beat hands down: 1.3G vs
> 8.5G for sources, 591M vs 1.1G for third party. I think it is similar
> for Subversion. I hope that repository is fully packed: IIRC the Mozilla
> CVS repository import was about 0.6GB pack file, not 1.3GB.
>
> The problem is with 'Size of checkout': to start working in repository
> one needs 1.4G (sources) and 98M (third party) for CVS checkout (it is
> 1.5G for sources for Subversion checkout). Ordinary for distributed SCM
> you would need size of repository + size of sources (working area),
> which is 2.8G for sources and 688M for third party stuff files you can
> hack on + the history]. This makes some prefer to go centralized SCM
> route, i.e. Subversion as replacement for CVS (+ CWS, ChildWorkSpace).

Considering the size OOo needs for build (>8G without languages),
the ~1.4G overhead for history is very well bearable.  I am surprised about
the 100M overhead for SVN as well - from my experience it is usually about
the size of the project itself; but maybe they improved something in SVN
in the meantime.

> What might help here is splitting repository into current (e.g. from
> OOo 2.0) and historical part,

No, I don't want this ;-)

> and / or using shallow clone. Implementing 
> partial checkouts, i.e. checking out only part of working area (and
> using 'theirs' strategy for merging not-checked-out part for merges)
> would help. Splitting repository into submodules, and submodule
> support -- it depends on organization of OOo sources, would certainly
> help for third party stuff repository.

We should better split the OOo sources; it's a process that already started
[UNO runtime environment vs. OOo without URE], and I proposed some more
changes already.

> 'Checkout time' (which should be renamed to 'Initial checkout time'),
> in which git also loses with 130 minutes (Linux, 2MBit DSL) [from
> go-oo.org], 100min (Linux, 2MBit DSL, Wireless, no proxy) [from
> go-oo.org] versus 117 minutes (Linux, 2MBit DSL), 26 minutes (Linux,
> 2MBit DSL, with compression (-z 6)) for CVS, and  60 Minutes (Windows,
> 34Mbit Line) for Subversion, would also be helped by the above.

Good point, and I already changed the page in the morning.  I also added the
checkout time that I got over a fast line [it was 44min].

> What I'm really concerned about is branch switch and merging branches,
> when one of the branches is an old one (e.g. unxsplash branch), which
> takes 3min (!) according to the benchmark. 13-25sec for commit is also
> bit long, but BRANCH SWITCHING which takes 3 MINUTES!? There is no
> comparison benchmark for CVS or Subversion, though...

I am really curious about the SVN tree.  As I said, I did not see it yet.
There is just some info about it here:
http://wiki.services.openoffice.org/wiki/SVNMigration, but I cannot check it
now, the Wiki is down :-(

> Comparison / benchmark lacks some crucial info, like what computer was
> used (CPU, RAM, HDD), what filesystem was used, git version etc. It
> does have commands used for tests (benchmarks).

For the git tests, it was:

CPU: AMD Athlon(tm) 64 Processor 3200+

RAM: 1G RAM

Disk (info from bonnie):
              ---Sequential Output (nosync)--- ---Sequential Input-- --Rnd Seek-
              -Per Char- --Block--- -Rewrite-- -Per Char- --Block--- --04k (03)-
Machine    MB K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU K/sec %CPU   /sec %CPU
one    1*2000 37819 77.6 44296 16.8 16982  5.1 35203 63.9 45915  6.6  152.4  0.4

Filesystem: ext3

> Could you confirm (or deny) those results? go-oo.org uses git 1.4.3.4;
> was there some improvement or bugfix related to the speed of checkout?

Regards,
Jan


^ permalink raw reply	[relevance 0%]

* Re: Git benchmarks at OpenOffice.org wiki
  2007-05-02 14:24  0% ` Jan Holesovsky
@ 2007-05-02 23:30  4%   ` Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2007-05-02 23:30 UTC (permalink / raw)
  To: Jan Holesovsky, git; +Cc: dev

Jan Holesovsky wrote:
> On Tuesday 01 May 2007 23:46, Jakub Narebski wrote:
> 
>> What I am concerned about is some of git benchmark results at Git page
>> on OpenOffice.org wiki:
>>   http://wiki.services.openoffice.org/wiki/Git#Comparison

>> The problem is with 'Size of checkout': to start working in repository
>> one needs 1.4G (sources) and 98M (third party) for CVS checkout (it is
>> 1.5G for sources for Subversion checkout). Ordinary for distributed SCM
>> you would need size of repository + size of sources (working area),
>> which is 2.8G for sources and 688M for third party stuff files you can
>> hack on + the history]. This makes some prefer to go centralized SCM
>> route, i.e. Subversion as replacement for CVS (+ CWS, ChildWorkSpace).
> 
> Considering the size OOo needs for build (>8G without languages),
> the ~1.4G overhead for history is very well bearable.  I am surprised about
> the 100M overhead for SVN as well - from my experience it is usually about
> the size of the project itself; but maybe they improved something in SVN
> in the meantime.

I think the supposition that SVN uses hardlinks for pristine copy
of sources (HEAD version) seems probable; then there it is 100M overhead
plus size of changed files, and of course this tricks works only on
filesystems which support hardlinks, and assumes either hardlinks being
COW-links (copy-on-write) or editor behaving.
 
>> What might help here is splitting repository into current (e.g. from
>> OOo 2.0) and historical part,
> 
> No, I don't want this ;-)

I forgot to add there is possible to graft historical repository to the
current work repository, resulting in full history available. For example
Linux kernel repository has backported from BK historical repository, and
there is grafts file which connect those two repositories.

>> and / or using shallow clone. 

git-clone(1):

--depth <depth>::
        Create a 'shallow' clone with a history truncated to the
        specified number of revs.  A shallow repository has
        number of limitations (you cannot clone or fetch from
        it, nor push from nor into it), but is adequate if you
        want to only look at near the tip of a large project
        with a long history, and would want to send in a fixes
        as patches.

It is possible that those limitations will be lifted in the future
(if possible), so there is alternate possibility to reduce needed
disk space for git checkout. But certainly this is not for everybody.

>> Implementing  
>> partial checkouts, i.e. checking out only part of working area (...)

The problem with implementing this feature (you can do partial checkout
using low level commands, but this feature is not implemented [yet?]
per se) is with doing merge on part which is not checked out. Might
not be a problem for OOo; but this might be also not needed for OOo.
Sometimes submodules are better, sometimes partial checkout is the
only way: see below.

>> Splitting repository into submodules, and submodule 
>> support -- it depends on organization of OOo sources, would certainly
>> help for third party stuff repository.
> 
> We should better split the OOo sources; it's a process that already started
> [UNO runtime environment vs. OOo without URE], and I proposed some more
> changes already.

In my opinion each submodule should be able to compile and test by
itself. You can go X.Org route with splitting sources into modules...
or you can make use of the new submodules support (currently plumbing
level, i.e. low level commands), aka. gitlinks.

The submodules support makes it possible to split sources into
independent modules (parts), which can be developed independently,
and which you can download (clone, fetch) or not, while making it
possible to bind it all together into one superproject.

See (somewhat not up to date) http://git.or.cz/gitwiki/SubprojectSupport
page on git wiki.

>> What I'm really concerned about is branch switch and merging branches,
>> when one of the branches is an old one (e.g. unxsplash branch), which
>> takes 3min (!) according to the benchmark. 13-25sec for commit is also
>> bit long, but BRANCH SWITCHING which takes 3 MINUTES!? There is no
>> comparison benchmark for CVS or Subversion, though...

By the way, the time to switch branch should be proportional to number
of changed files, which you can get with "git diff --summary unxsplash
HEAD". Or to be more realistic to checkout some old version
(some old tag), as usually branches which got merged in are deleted
(or even never got published). For example when bisecting some bug:
Subversion doesn't have bisect, does it?

I wonder if running "git pack-refs" would help this benchmark...

-- 
Jakub Narebski
Poland

^ permalink raw reply	[relevance 4%]

* svn user trying to recover from brain damage
@ 2007-05-09 15:30  2% Joshua Ball
  2007-05-09 16:22  1% ` Petr Baudis
  0 siblings, 1 reply; 200+ results
From: Joshua Ball @ 2007-05-09 15:30 UTC (permalink / raw)
  To: git

Hi all,

The git page says that this mailing list is for "bug reports, feature
requests, comments and patches". Is there a mailing list for new users
crying out for help? If so, forward me there.

OK, I'm feeling very frustrated right now, so let me just say that git
documentation sucks. All the documentation I can find anywhere falls
into two categories:

1. Tutorials for people brand new to version control, with just enough
information for them to "obey the rules", but completely empty of any
information that could help them exploit the real power of
decentralized version control.
2. Technical documentation which assumes pre-obtained knowledge.

Now that I've insulted you and am probably not on your good side...

What the heck do these terms mean? The glossary on the Git wiki was
unhelpful (I'll explain later). BTW, what is wrong with the wiki?
(Particularly the excessive [grayed-out text [no match, add rest:
"used by any common UNIX command. The fact that it is a
mispronunciation of "]]. Is this some new kind of spam, or a buggy
wiki feature?)

HEAD
HEAD REF
working tree
object
branch
merge
master
commit (as in the phrase "bring the working tree to a given commit")

While the Git wiki does in fact define all of these, it doesn't answer
any of my questions about those terms:

Is there a difference between HEAD and the working tree?
Does HEAD change when I cg-switch/git-checkout?
What is an object? Is it a set of patches? A tree snapshot?
What the heck is a branch? (Why does it have so many different
definitions? I feel like every time I come across "branch" in the man
pages, it means something different.)

More on branches: The wiki says that a group of commits linked
together form a DAG. Does that mean every fork/clone/branch-create
possibly doubles the number of branches. So if I fork and then
remerge, do I have two branches?

A -> B -> D
A -> C -> D

Would D be the head of this branch? If so, then heads do not uniquely
identify a branch?

Is there a standard revision notation? (Where my definition of
"revision" is a tree snapshot. In SVN, it would be identified by a
number.) `cg-diff -r A..B` works fine if A and B are branches, but how
do I diff from an older revision to a newer revision? Can I diff
between two revisions which haven't shared the same parent since 2006?

What about the master branch? Is there anything special about it? By
special I mean, do any of the git or cogito commands implicitly assume
that you are working with master? If git is truly decentralized, then
wouldn't master be on an equal footing with all other branches?

What is a merge? My understanding of merge comes from the SVN book,
where it was described as diff+apply. Diff takes 2 arguments, and
apply takes a 1 argument (if the patch is implicit). However, cg-merge
only appears to take one branch. (There again a use of the word
branch! Wouldn't commit or revision be a more accurate term?) Why does
cg-merge only take one argument? Even if I use the -b switch, I'm
still only up to two arguments. Where is the hidden argument?

Lastly, the most important question of all, which may answer many of
the questions above:

Can you fill in the missing pieces, making corrections where
necessary? (recommend unispace font)

Command     |   Reads               |   Writes
cg-fetch    | remote branch         | corresponding branch in local respository
cg-commit   | working copy          | HEAD
cg-update   | remote branch         | working copy AND HEAD
cg-merge    | branch & working copy | working copy
cg-diff     | arguments             | STDOUT
cg-push     |                       | remote branch (usually origin)
cg-pull     | remote branch         |
cg-restore  |                       |

Perhaps the Reads column should be split into two, like ReadInfo and ReadSafety.
ReadInfo would say which revision/branch/commit/object is being read for actual
content, while ReadSafety is only read to make sure that nothing will be lost
after running the command. (e.g., cg-update reads the working copy to make sure
that you are not in a partial merge, but once it knows that it is safe, it
ignores the contents of working directory. I may have this totally wrong.)

On cg-fetch, is the remote branch necessarily remote? Or can you fetch
from local
cg-switch-branches? What does "corresponding branch in local
repository" mean? Does cg-fetch touch your working copy?

What is the difference between cg-restore and cg-seek?

Please reply even if you can only answer one of my many questions! If
I can grab just one fact and say about it, "This is truth", then it
gives me a rock to stand on amidst all the term-mashing out there.

In the words of Dijkstra, "Since breaking out of bad habits, rather
than acquiring new ones, is the toughest part of learning, we must
expect from that system permanent mental damage for most ... exposed
to it."

May you lead me to a quick recovery. Hail to decentralized version control.

Josh "Ua" Ball

^ permalink raw reply	[relevance 2%]

* Re: svn user trying to recover from brain damage
  2007-05-09 15:30  2% svn user trying to recover from brain damage Joshua Ball
@ 2007-05-09 16:22  1% ` Petr Baudis
  0 siblings, 0 replies; 200+ results
From: Petr Baudis @ 2007-05-09 16:22 UTC (permalink / raw)
  To: Joshua Ball; +Cc: git

  Hi,

On Wed, May 09, 2007 at 05:30:18PM CEST, Joshua Ball wrote:
> The git page says that this mailing list is for "bug reports, feature
> requests, comments and patches". Is there a mailing list for new users
> crying out for help? If so, forward me there.

  I think it fits in the "comments" category. :-)

> OK, I'm feeling very frustrated right now, so let me just say that git
> documentation sucks. All the documentation I can find anywhere falls
> into two categories:
> 
> 1. Tutorials for people brand new to version control, with just enough
> information for them to "obey the rules", but completely empty of any
> information that could help them exploit the real power of
> decentralized version control.
> 2. Technical documentation which assumes pre-obtained knowledge.
> 
> Now that I've insulted you and am probably not on your good side...
> 
> What the heck do these terms mean? The glossary on the Git wiki was
> unhelpful (I'll explain later). BTW, what is wrong with the wiki?
> (Particularly the excessive [grayed-out text [no match, add rest:
> "used by any common UNIX command. The fact that it is a
> mispronunciation of "]]. Is this some new kind of spam, or a buggy
> wiki feature?)

  Sorry, it was a bug-ridden wiki. I was desperately trying to debug
some weird behaviour, few moments ago I've finally nailed it down and
all should be fine now.

> HEAD
> HEAD REF
> working tree
> object
> branch
> merge
> master
> commit (as in the phrase "bring the working tree to a given commit")
> 
> While the Git wiki does in fact define all of these, it doesn't answer
> any of my questions about those terms:
> 
> Is there a difference between HEAD and the working tree?

  This is (unfortunately) case-sensitive:

  HEAD identifies the commit (our slightly confusing name for a
revision) that corresponds to your working tree - usually the latest
commit in your current branch (by default 'master').

  head is just the latest commit in a branch, any branch.

> Does HEAD change when I cg-switch/git-checkout?

  Yes, HEAD changes (starts pointing to your new branch) when you
cg-switch or git-checkout -b.

> What is an object? Is it a set of patches? A tree snapshot?

  Object is the basic unit of stored data Git works with. object may be
either:

	"blob" - file at a particular point of time
	"tree" - list of files, corresponding to a particular directory
	         (again at a particular point of time)
	"commit" - one revision in the project history; contains
	           information about the parent commit(s), who did
	           the commit, the commit message and link to the
	           corresponding root tree object
	"tag" - links to another object, with additional information
	        like who/when made the tag and the tag comment

  Git does not store patches on a conceptual level, only snapshots. (At
the implementation level, Git uses "patches" for more optimized storage,
but that's not so important.)

> What the heck is a branch? (Why does it have so many different
> definitions? I feel like every time I come across "branch" in the man
> pages, it means something different.)

  Because it's hard to define. :-)

  To make a cyclical definition, branch is the set of commits
referenced by a given head. Hmm, I'll have to think out some cute
non-confusing definition of branch, I'll follow up unless someone beats
me to it.

> More on branches: The wiki says that a group of commits linked
> together form a DAG. Does that mean every fork/clone/branch-create
> possibly doubles the number of branches. So if I fork and then
> remerge, do I have two branches?
> 
> A -> B -> D
> A -> C -> D
> 
> Would D be the head of this branch? If so, then heads do not uniquely
> identify a branch?

  Branch is a much looser concept than you seem to assume. Branch is
really just a fancy name for a 'head', so let's redefine 'head'. Let's
just say for now that 'head' is a named commit reference.

  This means that when you create a "new branch" 'foo' from branch
'master', the _only_ thing you really did was to copy the commit
reference 'master.

> Is there a standard revision notation? (Where my definition of
> "revision" is a tree snapshot. In SVN, it would be identified by a
> number.) `cg-diff -r A..B` works fine if A and B are branches, but how
> do I diff from an older revision to a newer revision? Can I diff
> between two revisions which haven't shared the same parent since 2006?

  You can diff between any two revisions. The ultimately "standard"
notation is to use the id of the revision (the long string of
hexadecimal digits), but the syntax is quite rich - see SPECIFYING
REVISIONS section of git-rev-parse(1).

  If you specify a branch where revision is expected, it means that the
latest commit (revision) on the branch is used.

> What about the master branch? Is there anything special about it? By
> special I mean, do any of the git or cogito commands implicitly assume
> that you are working with master? If git is truly decentralized, then
> wouldn't master be on an equal footing with all other branches?

  'master' is just the default name for the first branch in a
repository, but in theory you can name it any way you wish and use as
many branches as you want, all are equal.

  When fetching from a remote repository, some commands might assume in
certain conditions that 'master' is the primary branch of the remote
repository, but I'm not sure about the details and in which cases does
this still hold true.

> What is a merge? My understanding of merge comes from the SVN book,
> where it was described as diff+apply. Diff takes 2 arguments, and
> apply takes a 1 argument (if the patch is implicit). However, cg-merge
> only appears to take one branch. (There again a use of the word
> branch! Wouldn't commit or revision be a more accurate term?) Why does
> cg-merge only take one argument? Even if I use the -b switch, I'm
> still only up to two arguments. Where is the hidden argument?

  The hidden argument is your current branch. So cg-merge x will merge
the branch 'x' to your current branch: symbolically, kind of

	base=-b argument | base(HEAD, x)
	apply(HEAD, diff(base, x))

  The word 'branch' is used in an attempt to make it all less confusing
:-). But in fact, you can give cg-merge just id of a commit, it does not
have to be branch name.

> Lastly, the most important question of all, which may answer many of
> the questions above:
> 
> Can you fill in the missing pieces, making corrections where
> necessary? (recommend unispace font)
> 
> Command     |   Reads               |   Writes
> cg-fetch    | remote branch         | corresponding branch in local respository
> cg-commit   | working copy          | HEAD
> cg-update   | remote branch         | working copy AND HEAD
> cg-merge    | branch & working copy | working copy
> cg-diff     | arguments             | STDOUT
> cg-push     |                       | remote branch (usually origin)
> cg-pull     | remote branch         |
> cg-restore  |                       |

  Yes, mostly right. cg-merge calls cg-commit unless there are
conflicts, so it should be "working copy AND HEAD" too. cg-push reads
local branch (HEAD or -r argument). There is no cg-pull since people
coming from different VCSes have different ideas about what pull is; git
pull is equivalent to cg-update.

> Perhaps the Reads column should be split into two, like ReadInfo and 
> ReadSafety.
> ReadInfo would say which revision/branch/commit/object is being read for 
> actual
> content, while ReadSafety is only read to make sure that nothing will be 
> lost
> after running the command. (e.g., cg-update reads the working copy to make 
> sure
> that you are not in a partial merge, but once it knows that it is safe, it
> ignores the contents of working directory. I may have this totally wrong.)

  It actually does some magic so that you can do a merge while having
uncommitted changes in your working tree. ;-)

> On cg-fetch, is the remote branch necessarily remote? Or can you fetch
> from local
> cg-switch-branches? What does "corresponding branch in local
> repository" mean? Does cg-fetch touch your working copy?

  Fetch means that a remote branch's content is transferred to the local
repository; furthermore, all the remote branches have their local
counterparts that "reflect" how the branch looked in the remote
repository at a particular point of time. So e.g. when you clone a
repository, the remote default branch is mirrored locally as branch
'origin' - you can't switch to it (technically you could but that would
be very confusing), but you can merge it.

> What is the difference between cg-restore and cg-seek?

  cg-seek will temporarily bring your tree to a different commit to
explore the state back then, but you cannot make commits in this state;
your HEAD points to the seeked commit. On the other hand, cg-restore
only changes files in your working tree - it works on the individual
files, does not touch HEAD and does not make the tree "read-only".

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Ever try. Ever fail. No matter. // Try again. Fail again. Fail better.
		-- Samuel Beckett

^ permalink raw reply	[relevance 1%]

* Partial removal of fetching from git-clone
@ 2007-05-20 17:57  6% skimo
  0 siblings, 0 replies; 200+ results
From: skimo @ 2007-05-20 17:57 UTC (permalink / raw)
  To: git, Junio C Hamano

From: Sven Verdoolaege <skimo@kotnet.org>

This was needed for doing submodules in git-fetch,
but since I moved the cloning of submodules to git-checkout,
I no longer need these changes.
Still, I know Junio wants something like this, so they
could be used as a starting point for completely
removing all fetching from git-clone.

skimo

^ permalink raw reply	[relevance 6%]

* [PATCH] Implement git commit as a builtin.
@ 2007-07-18 19:19  1% Kristian Høgsberg
  0 siblings, 0 replies; 200+ results
From: Kristian Høgsberg @ 2007-07-18 19:19 UTC (permalink / raw)
  To: git; +Cc: Kristian Høgsberg

---
Here's another update on the work in progress.  At this point, the C
version is almost complete, there's only a few issues left (look for
FIXME in builtin-commit.c).  I've added a commit test case which should
be split out in a patch on its own, but the good news is that it
successfully exercises most of the command line options and the C version
passes.

My plan for the remainder of the work is still to wrap up the last few
pieces of functionality and then start taking this big patch apart in a
number of more manageable pieces.  However, the bulk of this work will
still be a big patch that removes git-commit.sh and adds builtin-commit
in one swoop.

Kristian


 Makefile              |    9 +-
 builtin-add.c         |   14 +-
 builtin-commit-tree.c |  120 +++++---
 builtin-commit.c      |  746 +++++++++++++++++++++++++++++++++++++++++++++++++
 builtin.h             |    3 +-
 cache.h               |    3 +-
 color.c               |   18 +-
 color.h               |    4 +-
 commit.h              |    9 +
 git-commit.sh         |  658 -------------------------------------------
 git.c                 |    3 +-
 mktag.c               |    8 +-
 sha1_file.c           |   44 ++-
 t/t7800-commit.sh     |  126 +++++++++
 wt-status.c           |   86 +++---
 wt-status.h           |    4 +
 16 files changed, 1066 insertions(+), 789 deletions(-)
 create mode 100644 builtin-commit.c
 delete mode 100755 git-commit.sh
 create mode 100644 t/t7800-commit.sh

diff --git a/Makefile b/Makefile
index 0f75955..967d5a5 100644
--- a/Makefile
+++ b/Makefile
@@ -198,7 +198,7 @@ BASIC_LDFLAGS =
 
 SCRIPT_SH = \
 	git-bisect.sh git-checkout.sh \
-	git-clean.sh git-clone.sh git-commit.sh \
+	git-clean.sh git-clone.sh \
 	git-fetch.sh \
 	git-ls-remote.sh \
 	git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
@@ -257,7 +257,7 @@ EXTRA_PROGRAMS =
 BUILT_INS = \
 	git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
 	git-get-tar-commit-id$X git-init$X git-repo-config$X \
-	git-fsck-objects$X git-cherry-pick$X \
+	git-fsck-objects$X git-cherry-pick$X git-status$X\
 	$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
 
 # what 'all' will build and 'install' will install, in gitexecdir
@@ -332,6 +332,7 @@ BUILTIN_OBJS = \
 	builtin-check-attr.o \
 	builtin-checkout-index.o \
 	builtin-check-ref-format.o \
+	builtin-commit.o \
 	builtin-commit-tree.o \
 	builtin-count-objects.o \
 	builtin-describe.o \
@@ -367,7 +368,6 @@ BUILTIN_OBJS = \
 	builtin-rev-parse.o \
 	builtin-revert.o \
 	builtin-rm.o \
-	builtin-runstatus.o \
 	builtin-shortlog.o \
 	builtin-show-branch.o \
 	builtin-stripspace.o \
@@ -791,9 +791,6 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
 	chmod +x $@+ && \
 	mv $@+ $@
 
-git-status: git-commit
-	$(QUIET_GEN)cp $< $@+ && mv $@+ $@
-
 gitweb/gitweb.cgi: gitweb/gitweb.perl
 	$(QUIET_GEN)rm -f $@ $@+ && \
 	sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
diff --git a/builtin-add.c b/builtin-add.c
index 1591171..bcd796d 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -8,6 +8,7 @@
 #include "dir.h"
 #include "exec_cmd.h"
 #include "cache-tree.h"
+#include "run-command.h"
 #include "diff.h"
 #include "diffcore.h"
 #include "commit.h"
@@ -148,6 +149,13 @@ static int git_add_config(const char *var, const char *value)
 	return git_default_config(var, value);
 }
 
+int interactive_add(void)
+{
+	const char *argv[2] = { "add--interactive", NULL };
+
+	return run_command_v_opt(argv, RUN_GIT_CMD);
+}
+
 static struct lock_file lock_file;
 
 static const char ignore_warning[] =
@@ -167,11 +175,9 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 			add_interactive++;
 	}
 	if (add_interactive) {
-		const char *args[] = { "add--interactive", NULL };
-
-		if (add_interactive != 1 || argc != 2)
+		if (argc != 2)
 			die("add --interactive does not take any parameters");
-		execv_git_cmd(args);
+		interactive_add();
 		exit(1);
 	}
 
diff --git a/builtin-commit-tree.c b/builtin-commit-tree.c
index ccbcbe3..bb20470 100644
--- a/builtin-commit-tree.c
+++ b/builtin-commit-tree.c
@@ -20,17 +20,11 @@ static void init_buffer(char **bufp, unsigned int *sizep)
 	*sizep = 0;
 }
 
-static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
+static void add_chunk(char **bufp, unsigned int *sizep, const char *data, int len)
 {
-	char one_line[2048];
-	va_list args;
-	int len;
 	unsigned long alloc, size, newsize;
 	char *buf;
 
-	va_start(args, fmt);
-	len = vsnprintf(one_line, sizeof(one_line), fmt, args);
-	va_end(args);
 	size = *sizep;
 	newsize = size + len + 1;
 	alloc = (size + 32767) & ~32767;
@@ -41,7 +35,19 @@ static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
 		*bufp = buf;
 	}
 	*sizep = newsize - 1;
-	memcpy(buf + size, one_line, len);
+	memcpy(buf + size, data, len);
+}
+
+static void add_buffer(char **bufp, unsigned int *sizep, const char *fmt, ...)
+{
+	char one_line[2048];
+	va_list args;
+	int len;
+
+	va_start(args, fmt);
+	len = vsnprintf(one_line, sizeof(one_line), fmt, args);
+	va_end(args);
+	add_chunk(bufp, sizep, one_line, len);
 }
 
 static void check_valid(unsigned char *sha1, enum object_type expect)
@@ -81,39 +87,16 @@ static const char commit_utf8_warn[] =
 "You may want to amend it after fixing the message, or set the config\n"
 "variable i18n.commitencoding to the encoding your project uses.\n";
 
-int cmd_commit_tree(int argc, const char **argv, const char *prefix)
+const unsigned char *
+create_commit(const unsigned char *tree_sha1,
+	      unsigned char parent_sha1[][20], int parents,
+	      const char *author_info, const char *committer_info,
+	      const char *message, int length)
 {
-	int i;
-	int parents = 0;
-	unsigned char tree_sha1[20];
-	unsigned char commit_sha1[20];
-	char comment[1000];
+	static unsigned char commit_sha1[20];
+	int encoding_is_utf8, i;
 	char *buffer;
 	unsigned int size;
-	int encoding_is_utf8;
-
-	git_config(git_default_config);
-
-	if (argc < 2)
-		usage(commit_tree_usage);
-	if (get_sha1(argv[1], tree_sha1))
-		die("Not a valid object name %s", argv[1]);
-
-	check_valid(tree_sha1, OBJ_TREE);
-	for (i = 2; i < argc; i += 2) {
-		const char *a, *b;
-		a = argv[i]; b = argv[i+1];
-		if (!b || strcmp(a, "-p"))
-			usage(commit_tree_usage);
-
-		if (parents >= MAXPARENT)
-			die("Too many parents (%d max)", MAXPARENT);
-		if (get_sha1(b, parent_sha1[parents]))
-			die("Not a valid object name %s", b);
-		check_valid(parent_sha1[parents], OBJ_COMMIT);
-		if (new_parent(parents))
-			parents++;
-	}
 
 	/* Not having i18n.commitencoding is the same as having utf-8 */
 	encoding_is_utf8 = is_encoding_utf8(git_commit_encoding);
@@ -130,26 +113,71 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)
 		add_buffer(&buffer, &size, "parent %s\n", sha1_to_hex(parent_sha1[i]));
 
 	/* Person/date information */
-	add_buffer(&buffer, &size, "author %s\n", git_author_info(1));
-	add_buffer(&buffer, &size, "committer %s\n", git_committer_info(1));
+	add_buffer(&buffer, &size, "author %s\n", author_info);
+	add_buffer(&buffer, &size, "committer %s\n", committer_info);
 	if (!encoding_is_utf8)
 		add_buffer(&buffer, &size,
 				"encoding %s\n", git_commit_encoding);
 	add_buffer(&buffer, &size, "\n");
 
 	/* And add the comment */
-	while (fgets(comment, sizeof(comment), stdin) != NULL)
-		add_buffer(&buffer, &size, "%s", comment);
+	add_chunk(&buffer, &size, message, length);
 
 	/* And check the encoding */
 	buffer[size] = '\0';
 	if (encoding_is_utf8 && !is_utf8(buffer))
 		fprintf(stderr, commit_utf8_warn);
 
-	if (!write_sha1_file(buffer, size, commit_type, commit_sha1)) {
-		printf("%s\n", sha1_to_hex(commit_sha1));
-		return 0;
+	if (!write_sha1_file(buffer, size, commit_type, commit_sha1))
+		return commit_sha1;
+
+	return NULL;
+}
+
+int cmd_commit_tree(int argc, const char **argv, const char *prefix)
+{
+	int i;
+	int parents = 0;
+	unsigned char tree_sha1[20];
+	char *buffer;
+	const unsigned char *commit_sha1;
+	unsigned long length;
+
+	git_config(git_default_config);
+
+	if (argc < 2)
+		usage(commit_tree_usage);
+	if (get_sha1(argv[1], tree_sha1))
+		die("Not a valid object name %s", argv[1]);
+
+	check_valid(tree_sha1, OBJ_TREE);
+	for (i = 2; i < argc; i += 2) {
+		const char *a, *b;
+		a = argv[i]; b = argv[i+1];
+		if (!b || strcmp(a, "-p"))
+			usage(commit_tree_usage);
+
+		if (parents >= MAXPARENT)
+			die("Too many parents (%d max)", MAXPARENT);
+		if (get_sha1(b, parent_sha1[parents]))
+			die("Not a valid object name %s", b);
+		check_valid(parent_sha1[parents], OBJ_COMMIT);
+		if (new_parent(parents))
+			parents++;
 	}
-	else
+
+	if (read_fd(0, &buffer, &length))
+		die("Could not read commit message from standard input");
+
+	commit_sha1 = create_commit(tree_sha1,
+				    parent_sha1, parents,
+				    git_author_info(1),	    
+				    git_committer_info(1),	    
+				    buffer, length);
+
+	if (!commit_sha1)
 		return 1;
+
+	printf("%s\n", sha1_to_hex(commit_sha1));
+	return 0;
 }
diff --git a/builtin-commit.c b/builtin-commit.c
new file mode 100644
index 0000000..198d5af
--- /dev/null
+++ b/builtin-commit.c
@@ -0,0 +1,746 @@
+/*
+ * Builtin "git commit"
+ *
+ * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
+ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "cache.h"
+#include "cache-tree.h"
+#include "builtin.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "commit.h"
+#include "revision.h"
+#include "wt-status.h"
+#include "run-command.h"
+#include "refs.h"
+#include "log-tree.h"
+
+static const char builtin_commit_usage[] =
+	"[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [[-i | -o] <path>...]";
+
+static unsigned char head_sha1[20], merge_head_sha1[20];
+static struct commit *use_message_commit;
+static const char commit_editmsg[] = "COMMIT_EDITMSG";
+static struct lock_file lock_file;
+
+enum option_type {
+    OPTION_NONE,
+    OPTION_STRING,
+    OPTION_INTEGER,
+    OPTION_LAST,
+};
+
+struct option {
+    enum option_type type;
+    const char *long_name;
+    char short_name;
+    void *value;
+};
+
+static int scan_options(const char ***argv, struct option *options)
+{
+	const char *value, *eq;
+	int i;
+
+	if (**argv == NULL)
+		return 0;
+	if ((**argv)[0] != '-')
+		return 0;
+	if (!strcmp(**argv, "--"))
+		return 0;
+
+	value = NULL;
+	for (i = 0; options[i].type != OPTION_LAST; i++) {
+		if ((**argv)[1] == '-') {
+			if (!prefixcmp(options[i].long_name, **argv + 2)) {
+				if (options[i].type != OPTION_NONE)
+					value = *++(*argv);
+				goto match;
+			}
+
+			eq = strchr(**argv + 2, '=');
+			if (eq && options[i].type != OPTION_NONE &&
+			    !strncmp(**argv + 2, 
+				     options[i].long_name, eq - **argv - 2)) {
+				value = eq + 1;
+				goto match;
+			}
+		}
+
+		if ((**argv)[1] == options[i].short_name) {
+			if ((**argv)[2] == '\0') {
+				if (options[i].type != OPTION_NONE)
+					value = *++(*argv);
+				goto match;
+			}
+
+			if (options[i].type != OPTION_NONE) {
+				value = **argv + 2;
+				goto match;
+			}
+		}
+	}
+
+	usage(builtin_commit_usage);
+
+ match:
+	switch (options[i].type) {
+	case OPTION_NONE:
+		*(int *)options[i].value = 1;
+		break;
+	case OPTION_STRING:
+		if (value == NULL)
+			die("option %s requires a value.", (*argv)[-1]);
+		*(const char **)options[i].value = value;
+		break;
+	case OPTION_INTEGER:
+		if (value == NULL)
+			die("option %s requires a value.", (*argv)[-1]);
+		*(int *)options[i].value = atoi(value);
+		break;
+	default:
+		assert(0);
+	}
+
+	(*argv)++;
+
+	return 1;
+}
+
+static char *logfile, *force_author, *message;
+static char *edit_message, *use_message;
+static int all, edit_flag, also, interactive, only, no_verify, amend, signoff;
+static int quiet, verbose, untracked_files;
+
+static int no_edit, initial_commit, in_merge;
+const char *only_include_assumed;
+
+static struct option commit_options[] = {
+	{ OPTION_STRING, "file", 'F', (void *) &logfile },
+	{ OPTION_NONE, "all", 'a', &all },
+	{ OPTION_STRING, "author", 0, (void *) &force_author },
+	{ OPTION_NONE, "edit", 0, &edit_flag },
+	{ OPTION_NONE, "include", 'i', &also },
+	{ OPTION_NONE, "interactive", 0, &interactive },
+	{ OPTION_NONE, "only", 'o', &only },
+	{ OPTION_STRING, "message", 'm', &message },
+	{ OPTION_NONE, "no-verify", 'n', &no_verify },
+	{ OPTION_NONE, "amend", 0, &amend },
+	{ OPTION_STRING, "reedit-message", 'c', &edit_message },
+	{ OPTION_STRING, "reuse-message", 'C', &use_message },
+	{ OPTION_NONE, "signoff", 's', &signoff },
+	{ OPTION_NONE, "quiet", 'q', &quiet },
+	{ OPTION_NONE, "verbose", 'v', &verbose },
+	{ OPTION_NONE, "untracked-files", 0, &untracked_files },
+	{ OPTION_LAST },
+};
+
+/* FIXME: Taken from builtin-add, should be shared. */
+
+static void update_callback(struct diff_queue_struct *q,
+			    struct diff_options *opt, void *cbdata)
+{
+	int i, verbose;
+
+	verbose = *((int *)cbdata);
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p = q->queue[i];
+		const char *path = p->one->path;
+		switch (p->status) {
+		default:
+			die("unexpacted diff status %c", p->status);
+		case DIFF_STATUS_UNMERGED:
+		case DIFF_STATUS_MODIFIED:
+			add_file_to_cache(path, verbose);
+			break;
+		case DIFF_STATUS_DELETED:
+			remove_file_from_cache(path);
+			if (verbose)
+				printf("remove '%s'\n", path);
+			break;
+		}
+	}
+}
+
+static void
+add_files_to_cache(int fd, const char **files, const char *prefix)
+{
+	struct rev_info rev;
+
+	init_revisions(&rev, "");
+	setup_revisions(0, NULL, &rev, NULL);
+	rev.prune_data = get_pathspec(prefix, files);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = update_callback;
+	rev.diffopt.format_callback_data = &verbose;
+
+	run_diff_files(&rev, 0);
+
+	if (write_cache(fd, active_cache, active_nr) || close(fd))
+		die("unable to write new index file");
+}
+
+static char *
+prepare_index(const char **files, const char *prefix)
+{
+	int fd;
+	struct tree *tree;
+	struct lock_file *next_index_lock;
+
+	fd = hold_locked_index(&lock_file, 1);
+	if (read_cache() < 0)
+		die("index file corrupt");
+
+	if (all) {
+		add_files_to_cache(fd, files, NULL);
+		return lock_file.filename;
+	} else if (also) {
+		add_files_to_cache(fd, files, prefix);
+		return lock_file.filename;
+	}
+
+	if (interactive)
+		interactive_add();
+
+	if (*files == NULL) {
+		/* Commit index as-is. */
+		rollback_lock_file(&lock_file);
+		return get_index_file();
+	}
+
+	/*
+	 * FIXME: Warn on unknown files.  Shell script does
+	 *
+	 *   commit_only=`git-ls-files --error-unmatch -- "$@"`
+	 */
+
+	/*
+	 * FIXME: shell script does
+	 *
+	 *   git-read-tree --index-output="$TMP_INDEX" -i -m HEAD
+	 *
+	 * which warns about unmerged files in the index.
+	 */
+
+	/* update the user index file */
+	add_files_to_cache(fd, files, prefix);
+
+	tree = parse_tree_indirect(head_sha1);
+	if (!tree)
+		die("failed to unpack HEAD tree object");
+	if (read_tree(tree, 0, NULL))
+		die("failed to read HEAD tree object");
+
+	/* Uh oh, abusing lock_file to create a garbage collected file */
+	next_index_lock = xmalloc(sizeof(*next_index_lock));
+	fd = hold_lock_file_for_update(next_index_lock,
+				       git_path("next-index-%d", getpid()), 1);
+	add_files_to_cache(fd, files, prefix);
+
+	return next_index_lock->filename;
+}
+
+static int strip_lines(char *buffer, int len)
+{
+	int blank_lines, i, j;
+	char *eol;
+
+	blank_lines = 1;
+	for (i = 0, j = 0; i < len; i++) {
+		if (blank_lines > 0 && buffer[i] == '#') {
+			eol = strchr(buffer + i, '\n');
+			if (!eol)
+				break;
+
+			i = eol - buffer;
+			continue;
+		}
+
+		if (buffer[i] == '\n') {
+			blank_lines++;
+			if (blank_lines > 1)
+				continue;
+		} else {
+			if (blank_lines > 2)
+				buffer[j++] = '\n';
+			blank_lines = 0;
+		}
+
+		buffer[j++] = buffer[i];
+	}
+
+	if (buffer[j - 1] != '\n')
+               buffer[j++] = '\n';
+
+	return j;
+}
+
+static int run_status(FILE *fp, const char *index_file)
+{
+	struct wt_status s;
+
+	wt_status_prepare(&s);
+
+	if (amend) {
+		s.amend = 1;
+		s.reference = "HEAD^1";
+	}
+	s.verbose = verbose;
+	s.untracked = untracked_files;
+	s.index_file = index_file;
+	s.fp = fp;
+
+	wt_status_print(&s);
+
+	return s.commitable;
+}
+
+static const char sign_off_header[] = "Signed-off-by: ";
+
+static int prepare_log_message(const char *index_file)
+{
+	char *buffer = NULL;
+	struct stat statbuf;
+	int commitable;
+	unsigned long len;
+	FILE *fp;
+
+	if (message) {
+		buffer = message;
+		len = strlen(message);
+	} else if (logfile && !strcmp(logfile, "-")) {
+		if (isatty(0))
+			fprintf(stderr, "(reading log message from standard input)\n");
+		if (read_fd(0, &buffer, &len))
+			die("could not read log from standard input");
+	} else if (logfile) {
+		if (read_path(logfile, &buffer, &len))
+			die("could not read log file '%s': %s",
+			    logfile, strerror(errno));
+	} else if (use_message) {
+		/* FIXME: encoding */
+		buffer = strstr(use_message_commit->buffer, "\n\n");
+		if (!buffer || buffer[2] == '\0')
+			die("commit has empty message");
+		buffer += 2;
+		len = strlen(buffer);
+	} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
+		if (read_path(git_path("MERGE_MSG"), &buffer, &len))
+			die("could not read MERGE_MSG: %s", strerror(errno));
+	} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
+		if (read_path(git_path("SQUASH_MSG"), &buffer, &len))
+			die("could not read SQUASH_MSG: %s", strerror(errno));
+	}
+
+	fp = fopen(git_path(commit_editmsg), "w");
+	if (fp == NULL)
+		die("could not open %s\n", git_path(commit_editmsg));
+		
+	if (buffer) {
+		len = strip_lines(buffer, len);
+
+		if (fwrite(buffer, 1, len, fp) < len)
+			die("could not write commit template: %s\n",
+			    strerror(errno));
+	}
+
+	if (signoff) {
+		const char *info, *bol;
+
+		info = git_committer_info(1);
+		if (buffer) {
+			bol = strrchr(buffer + len - 1, '\n');
+			if (!bol || prefixcmp(bol, sign_off_header))
+				fprintf(fp, "\n");
+		}
+		fprintf(fp, "Signed-off-by: %s\n", git_committer_info(1));
+	}
+
+	if (in_merge && !no_edit) {
+		fprintf(fp,
+			"#\n"
+			"# It looks like you may be committing a MERGE.\n"
+			"# If this is not correct, please remove the file\n"
+			"#	%s\n"
+			"# and try again.\n"
+			"#\n",
+			git_path("MERGE_HEAD"));
+	}
+
+	fprintf(fp,
+		"\n"
+		"# Please enter the commit message for your changes.\n"
+		"# (Comment lines starting with '#' will not be included)\n");
+	if (only_include_assumed)
+		fprintf(fp, "# %s\n", only_include_assumed);
+
+	commitable = run_status(fp, index_file);
+
+	fclose(fp);
+
+	return commitable;
+}
+
+struct commit_info_strings {
+	const char *header, *name_env, *email_env, *date_env;
+} author_info_strings = {
+	"\nauthor ",
+	"GIT_AUTHOR_NAME", "GIT_AUTHOR_EMAIL", "GIT_AUTHOR_DATE"
+}, committer_info_strings = {
+	"\ncommitter ",
+	"GIT_COMMITTER_NAME", "GIT_COMMITER_EMAIL", "GIT_COMMITTER_DATE"
+};
+
+static char *determine_info(struct commit_info_strings *strings)
+{
+	char *p, *eol;
+	char *name = NULL, *email = NULL, *date = NULL;
+
+	if (use_message) {
+		p = strstr(use_message_commit->buffer, strings->header);
+		if (!p)
+			die("invalid commit: %s\n", use_message);
+		p += strlen(strings->header);
+		eol = strchr(p, '\n');
+		if (!eol)
+			die("invalid commit: %s\n", use_message);
+
+		return xstrndup(p, eol - p);
+	} else if (force_author && strings == &author_info_strings) {
+		const char *eoname = strstr(force_author, " <");
+		const char *eomail = strchr(force_author, '>');
+
+		if (!eoname || !eomail)
+			die("malformed --author parameter\n");
+		name = xstrndup(force_author, eoname - force_author);
+		email = xstrndup(eoname + 2, eomail - eoname - 2);
+	}
+
+	if (name == NULL)
+		name = getenv(strings->name_env);
+	if (email == NULL)
+		email = getenv(strings->email_env);
+	if (date == NULL)
+		date = getenv(strings->date_env);
+
+	return xstrdup(fmt_ident(name, email, date, 1));
+}
+
+static void parse_and_validate_options(const char ***argv)
+{
+	int f = 0;
+
+	git_config(git_status_config);
+
+	(*argv)++;
+	while (scan_options(argv, commit_options))
+		;
+
+	if (logfile || message || use_message)
+		no_edit = 1;
+
+	if (get_sha1("HEAD", head_sha1))
+		initial_commit = 1;
+
+	if (!get_sha1("MERGE_HEAD", merge_head_sha1))
+		in_merge = 1;
+
+	/* Sanity check options */
+	if (amend && initial_commit)
+		die("You have nothing to amend.");
+	if (amend && in_merge)
+		die("You are in the middle of a merger -- cannot amend.");
+
+	if (use_message)
+		f++;
+	if (edit_message)
+		f++;
+	if (logfile)
+		f++;
+	if (amend)
+		f++;
+	if (f > 1)
+		die("Only one of -c/-C/-F/--amend can be used.");
+	if (message && f > 0)
+		die("Option -m cannot be combined with -c/-C/-F/--amend.");
+	if (edit_message)
+		use_message = edit_message;
+	if (amend)
+		use_message = "HEAD";
+	if (use_message) {
+		unsigned char sha1[20];
+
+		if (get_sha1(use_message, sha1))
+			die("could not lookup commit %s", use_message);
+		use_message_commit = lookup_commit(sha1);
+		if (!use_message_commit || parse_commit(use_message_commit))
+			die("could not parse commit %s", use_message);
+	}
+
+	if (also && only)
+		die("Only one of --include/--only can be used.");
+	if (!*argv && (also || (only && !amend)))
+		die("No paths with --include/--only does not make sense.");
+	if (!*argv && only && amend)
+		only_include_assumed = "Clever... amending the last one with dirty index.";
+	if (*argv && !also && !only) {
+		only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
+		also = 0;
+	}
+
+	if (all && interactive)
+		die("Cannot use -a, --interactive or -i at the same time.");
+	else if (all && **argv)
+		die("Paths with -a does not make sense.");
+	else if (interactive && **argv)
+		die("Paths with --interactive does not make sense.");
+}
+
+int cmd_status(int argc, const char **argv, const char *prefix)
+{
+	const char *index_file;
+	int commitable;
+
+	parse_and_validate_options(&argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	commitable = run_status(stdout, index_file);
+
+	rollback_lock_file(&lock_file);
+
+	return commitable ? 0 : 1;
+}
+
+static void launch_editor(const char *path)
+{
+	const char *editor, *terminal;
+	struct child_process child;
+	const char *args[3];
+
+	editor = getenv("VISUAL");
+	if (!editor)
+		editor = getenv("EDITOR");
+
+	terminal = getenv("TERM");
+	if (!editor && (!terminal || !strcmp(terminal, "dumb"))) {
+		fprintf(stderr, 
+			"Terminal is dumb but no VISUAL nor EDITOR defined.\n"
+			"Please supply the commit log message using either\n"
+			"-m or -F option.  A boilerplate log message has\n"
+			"been prepared in $GIT_DIR/COMMIT_EDITMSG\n");
+		exit(1);
+	}
+
+	if (!editor)
+		editor = "vi";
+	    
+	memset(&child, 0, sizeof(child));
+	child.argv = args;
+	args[0] = editor;
+	args[1] = path;
+	args[2] = NULL;
+
+	if (run_command(&child))
+		die("could not launch editor %s.", editor);
+}
+
+static int message_is_empty(const char *buffer, int len)
+{
+	static const char signed_off_by[] = "Signed-off-by: ";
+	const char *nl;
+	int eol, i;
+
+	for (i = 0; i < len; i++) {
+		nl = memchr(buffer + i, '\n', len - i);
+		if (nl)
+			eol = nl - buffer;
+		else
+			eol = len;
+
+		if (strlen(signed_off_by) <= eol - i &&
+		    !prefixcmp(buffer + i, signed_off_by)) {
+			i = eol;
+			continue;
+		}
+		while (i < eol)
+			if (!isspace(buffer[i++]))
+			    return 0;
+	}
+
+	return 1;
+}
+
+static int run_hook(const char *index_file, const char *name, const char *arg)
+{
+	struct child_process hook;
+	const char *argv[3], *env[2];
+	char index[PATH_MAX];
+
+	argv[0] = git_path("hooks/%s", name);
+	argv[1] = arg;
+	argv[2] = NULL;
+	snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
+	env[0] = index;
+	env[1] = NULL;
+
+	if (access(argv[0], X_OK) < 0)
+		return 0;
+
+	memset(&hook, 0, sizeof(hook));
+	hook.argv = argv;
+	hook.no_stdin = 1;
+	hook.stdout_to_stderr = 1;
+	hook.env = env;
+
+	return run_command(&hook);
+}
+
+static void print_summary(const char *prefix, const unsigned char *sha1)
+{
+	struct rev_info rev;
+	struct commit *commit;
+
+	commit = lookup_commit(sha1);
+	if (!commit)
+		die("couldn't look up newly created commit\n");
+	if (!commit || parse_commit(commit))
+		die("could not parse newly created commit");
+
+	init_revisions(&rev, prefix);
+	setup_revisions(0, NULL, &rev, NULL);
+
+	rev.abbrev = 0;
+	rev.diff = 1;
+	rev.diffopt.output_format =
+		DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
+
+	rev.verbose_header = 1;
+	rev.show_root_diff = 1;
+	rev.commit_format = get_commit_format("format:%h: %s");
+	rev.always_show_header = 1;
+		
+	printf("Created %scommit ", initial_commit ? "initial " : "");
+
+	log_tree_commit(&rev, commit);
+}
+
+#define MAXPARENT (16)
+static unsigned char parent_sha1[MAXPARENT][20];
+
+int cmd_commit(int argc, const char **argv, const char *prefix)
+{
+	int parent_count = 0;
+	unsigned long len;
+	char *buffer;
+	const char *index_file, *reflog_msg;
+	const unsigned char *commit_sha1;
+	struct ref_lock *ref_lock;
+
+	parse_and_validate_options(&argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	if (run_hook(index_file, "pre-commit", NULL))
+		exit(1);
+
+	if (!prepare_log_message(index_file)) {
+		run_status(stdout, index_file);
+		unlink(commit_editmsg);
+		return 1;
+	}
+
+	if (!no_edit)
+		launch_editor(git_path(commit_editmsg));
+
+	if (run_hook(index_file, "commit-msg", commit_editmsg))
+		exit(1);
+
+	if (read_path(git_path(commit_editmsg), &buffer, &len))
+		die("could not read commit message file '%s': %s",
+		    git_path(commit_editmsg), strerror(errno));
+
+	len = strip_lines(buffer, len);
+
+	if (message_is_empty(buffer, len))
+		die("* no commit message?  aborting commit.");
+
+	/* Determine parents */
+	if (initial_commit) {
+		reflog_msg = "commit (initial)"; 
+		parent_count = 0;
+	} else if (amend) {
+		struct commit_list *c;
+		struct commit *commit;
+		int i = 0;
+
+		reflog_msg = "commit (amend)";
+		commit = lookup_commit(head_sha1);
+		if (!commit || parse_commit(commit))
+			die("could not parse HEAD commit");
+
+		for (c = commit->parents; c; c = c->next) {
+			hashcpy(parent_sha1[i++], c->item->object.sha1);
+			if (i == MAXPARENT)
+				die("Too many parents (%d max)", MAXPARENT);
+		}
+		parent_count = i;
+	} else if (in_merge) {
+		/* FIXME: how are merges with more than two parents handled? */
+		reflog_msg = "commit (merge)";
+		hashcpy(parent_sha1[0], head_sha1);
+		hashcpy(parent_sha1[1], merge_head_sha1);
+		parent_count = 2;
+	} else {
+		reflog_msg = "commit";
+		hashcpy(parent_sha1[0], head_sha1);
+		parent_count = 1;
+	}
+
+	read_cache_from(index_file);
+	active_cache_tree = cache_tree();
+	if (cache_tree_update(active_cache_tree,
+			      active_cache, active_nr, 0, 0) < 0)
+		die("Error building trees");
+
+	commit_sha1 = create_commit(active_cache_tree->sha1,
+				    parent_sha1, parent_count,
+				    determine_info(&author_info_strings),
+				    determine_info(&committer_info_strings),
+				    buffer, len);
+		       
+	ref_lock = lock_any_ref_for_update("HEAD",
+					   initial_commit ? NULL : head_sha1,
+					   0);
+	if (!ref_lock)
+		die("cannot lock HEAD ref");
+	if (write_ref_sha1(ref_lock, commit_sha1, reflog_msg) < 0)
+		die("cannot update HEAD ref");
+
+	unlink(git_path("MERGE_HEAD"));
+	unlink(git_path("MERGE_MSG"));
+
+	if (lock_file.filename[0] && commit_locked_index(&lock_file))
+		die("failed to write new index");
+
+	/*
+	 * FIXME:
+	 *	if test -d "$GIT_DIR/rr-cache"
+	 *	then
+	 *		git-rerere
+	 *	fi
+	 */
+
+	run_hook(index_file, "post-commit", NULL);
+
+	if (!quiet)
+		print_summary(prefix, commit_sha1);
+
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index da4834c..7f395da 100644
--- a/builtin.h
+++ b/builtin.h
@@ -23,6 +23,7 @@ extern int cmd_check_attr(int argc, const char **argv, const char *prefix);
 extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
+extern int cmd_commit(int argc, const char **argv, const char *prefix);
 extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_describe(int argc, const char **argv, const char *prefix);
@@ -63,10 +64,10 @@ extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
 extern int cmd_revert(int argc, const char **argv, const char *prefix);
 extern int cmd_rm(int argc, const char **argv, const char *prefix);
-extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
 extern int cmd_shortlog(int argc, const char **argv, const char *prefix);
 extern int cmd_show(int argc, const char **argv, const char *prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
+extern int cmd_status(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
 extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_tar_tree(int argc, const char **argv, const char *prefix);
diff --git a/cache.h b/cache.h
index 5e7381e..0403ada 100644
--- a/cache.h
+++ b/cache.h
@@ -245,7 +245,8 @@ extern int ie_match_stat(struct index_state *, struct cache_entry *, struct stat
 extern int ie_modified(struct index_state *, struct cache_entry *, struct stat *, int);
 extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);
 extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);
-extern int read_pipe(int fd, char** return_buf, unsigned long* return_size);
+extern int read_fd(int fd, char** return_buf, unsigned long* return_size);
+extern int read_path(const char *path, char** return_buf, unsigned long* return_size);
 extern int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object);
 extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);
 extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
diff --git a/color.c b/color.c
index 09d82ee..124ba33 100644
--- a/color.c
+++ b/color.c
@@ -135,39 +135,39 @@ int git_config_colorbool(const char *var, const char *value)
 	return git_config_bool(var, value);
 }
 
-static int color_vprintf(const char *color, const char *fmt,
+static int color_vfprintf(FILE *fp, const char *color, const char *fmt,
 		va_list args, const char *trail)
 {
 	int r = 0;
 
 	if (*color)
-		r += printf("%s", color);
-	r += vprintf(fmt, args);
+		r += fprintf(fp, "%s", color);
+	r += vfprintf(fp, fmt, args);
 	if (*color)
-		r += printf("%s", COLOR_RESET);
+		r += fprintf(fp, "%s", COLOR_RESET);
 	if (trail)
-		r += printf("%s", trail);
+		r += fprintf(fp, "%s", trail);
 	return r;
 }
 
 
 
-int color_printf(const char *color, const char *fmt, ...)
+int color_fprintf(FILE *fp, const char *color, const char *fmt, ...)
 {
 	va_list args;
 	int r;
 	va_start(args, fmt);
-	r = color_vprintf(color, fmt, args, NULL);
+	r = color_vfprintf(fp, color, fmt, args, NULL);
 	va_end(args);
 	return r;
 }
 
-int color_printf_ln(const char *color, const char *fmt, ...)
+int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...)
 {
 	va_list args;
 	int r;
 	va_start(args, fmt);
-	r = color_vprintf(color, fmt, args, "\n");
+	r = color_vfprintf(fp, color, fmt, args, "\n");
 	va_end(args);
 	return r;
 }
diff --git a/color.h b/color.h
index 88bb8ff..6809800 100644
--- a/color.h
+++ b/color.h
@@ -6,7 +6,7 @@
 
 int git_config_colorbool(const char *var, const char *value);
 void color_parse(const char *var, const char *value, char *dst);
-int color_printf(const char *color, const char *fmt, ...);
-int color_printf_ln(const char *color, const char *fmt, ...);
+int color_fprintf(FILE *fp, const char *color, const char *fmt, ...);
+int color_fprintf_ln(FILE *fp, const char *color, const char *fmt, ...);
 
 #endif /* COLOR_H */
diff --git a/commit.h b/commit.h
index a313b53..a07e379 100644
--- a/commit.h
+++ b/commit.h
@@ -122,4 +122,13 @@ extern struct commit_list *get_shallow_commits(struct object_array *heads,
 		int depth, int shallow_flag, int not_shallow_flag);
 
 int in_merge_bases(struct commit *, struct commit **, int);
+
+const unsigned char *
+create_commit(const unsigned char *tree_sha1,
+	      unsigned char parent_sha1[][20], int parents,
+	      const char *author_info, const char *committer_info,
+	      const char *message, int length);
+
+int interactive_add(void);
+
 #endif /* COMMIT_H */
diff --git a/git-commit.sh b/git-commit.sh
deleted file mode 100755
index 5547a02..0000000
--- a/git-commit.sh
+++ /dev/null
@@ -1,658 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Linus Torvalds
-# Copyright (c) 2006 Junio C Hamano
-
-USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [[-i | -o] <path>...]'
-SUBDIRECTORY_OK=Yes
-. git-sh-setup
-require_work_tree
-
-git-rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
-
-case "$0" in
-*status)
-	status_only=t
-	;;
-*commit)
-	status_only=
-	;;
-esac
-
-refuse_partial () {
-	echo >&2 "$1"
-	echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
-	exit 1
-}
-
-THIS_INDEX="$GIT_DIR/index"
-NEXT_INDEX="$GIT_DIR/next-index$$"
-rm -f "$NEXT_INDEX"
-save_index () {
-	cp -p "$THIS_INDEX" "$NEXT_INDEX"
-}
-
-run_status () {
-	# If TMP_INDEX is defined, that means we are doing
-	# "--only" partial commit, and that index file is used
-	# to build the tree for the commit.  Otherwise, if
-	# NEXT_INDEX exists, that is the index file used to
-	# make the commit.  Otherwise we are using as-is commit
-	# so the regular index file is what we use to compare.
-	if test '' != "$TMP_INDEX"
-	then
-		GIT_INDEX_FILE="$TMP_INDEX"
-		export GIT_INDEX_FILE
-	elif test -f "$NEXT_INDEX"
-	then
-		GIT_INDEX_FILE="$NEXT_INDEX"
-		export GIT_INDEX_FILE
-	fi
-
-	case "$status_only" in
-	t) color= ;;
-	*) color=--nocolor ;;
-	esac
-	git-runstatus ${color} \
-		${verbose:+--verbose} \
-		${amend:+--amend} \
-		${untracked_files:+--untracked}
-}
-
-trap '
-	test -z "$TMP_INDEX" || {
-		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
-	}
-	rm -f "$NEXT_INDEX"
-' 0
-
-################################################################
-# Command line argument parsing and sanity checking
-
-all=
-also=
-interactive=
-only=
-logfile=
-use_commit=
-amend=
-edit_flag=
-no_edit=
-log_given=
-log_message=
-verify=t
-quiet=
-verbose=
-signoff=
-force_author=
-only_include_assumed=
-untracked_files=
-while case "$#" in 0) break;; esac
-do
-	case "$1" in
-	-F|--F|-f|--f|--fi|--fil|--file)
-		case "$#" in 1) usage ;; esac
-		shift
-		no_edit=t
-		log_given=t$log_given
-		logfile="$1"
-		shift
-		;;
-	-F*|-f*)
-		no_edit=t
-		log_given=t$log_given
-		logfile=`expr "z$1" : 'z-[Ff]\(.*\)'`
-		shift
-		;;
-	--F=*|--f=*|--fi=*|--fil=*|--file=*)
-		no_edit=t
-		log_given=t$log_given
-		logfile=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		shift
-		;;
-	-a|--a|--al|--all)
-		all=t
-		shift
-		;;
-	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
-		force_author=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		shift
-		;;
-	--au|--aut|--auth|--autho|--author)
-		case "$#" in 1) usage ;; esac
-		shift
-		force_author="$1"
-		shift
-		;;
-	-e|--e|--ed|--edi|--edit)
-		edit_flag=t
-		shift
-		;;
-	-i|--i|--in|--inc|--incl|--inclu|--includ|--include)
-		also=t
-		shift
-		;;
-	--int|--inte|--inter|--intera|--interac|--interact|--interacti|\
-	--interactiv|--interactive)
-		interactive=t
-		shift
-		;;
-	-o|--o|--on|--onl|--only)
-		only=t
-		shift
-		;;
-	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=m$log_given
-		if test "$log_message" = ''
-		then
-		    log_message="$1"
-		else
-		    log_message="$log_message
-
-$1"
-		fi
-		no_edit=t
-		shift
-		;;
-	-m*)
-		log_given=m$log_given
-		if test "$log_message" = ''
-		then
-		    log_message=`expr "z$1" : 'z-m\(.*\)'`
-		else
-		    log_message="$log_message
-
-`expr "z$1" : 'z-m\(.*\)'`"
-		fi
-		no_edit=t
-		shift
-		;;
-	--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
-		log_given=m$log_given
-		if test "$log_message" = ''
-		then
-		    log_message=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		else
-		    log_message="$log_message
-
-`expr "z$1" : 'zq-[^=]*=\(.*\)'`"
-		fi
-		no_edit=t
-		shift
-		;;
-	-n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
-	--no-verify)
-		verify=
-		shift
-		;;
-	--a|--am|--ame|--amen|--amend)
-		amend=t
-		log_given=t$log_given
-		use_commit=HEAD
-		shift
-		;;
-	-c)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		shift
-		;;
-	--ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
-	--reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
-	--reedit-messag=*|--reedit-message=*)
-		log_given=t$log_given
-		use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		no_edit=
-		shift
-		;;
-	--ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
-	--reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
-	--reedit-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		shift
-		;;
-	-C)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		shift
-		;;
-	--reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
-	--reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
-	--reuse-message=*)
-		log_given=t$log_given
-		use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		no_edit=t
-		shift
-		;;
-	--reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
-	--reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		shift
-		;;
-	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
-		signoff=t
-		shift
-		;;
-	-q|--q|--qu|--qui|--quie|--quiet)
-		quiet=t
-		shift
-		;;
-	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
-		verbose=t
-		shift
-		;;
-	-u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
-	--untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
-	--untracked-file|--untracked-files)
-		untracked_files=t
-		shift
-		;;
-	--)
-		shift
-		break
-		;;
-	-*)
-		usage
-		;;
-	*)
-		break
-		;;
-	esac
-done
-case "$edit_flag" in t) no_edit= ;; esac
-
-################################################################
-# Sanity check options
-
-case "$amend,$initial_commit" in
-t,t)
-	die "You do not have anything to amend." ;;
-t,)
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		die "You are in the middle of a merge -- cannot amend."
-	fi ;;
-esac
-
-case "$log_given" in
-tt*)
-	die "Only one of -c/-C/-F/--amend can be used." ;;
-*tm*|*mt*)
-	die "Option -m cannot be combined with -c/-C/-F/--amend." ;;
-esac
-
-case "$#,$also,$only,$amend" in
-*,t,t,*)
-	die "Only one of --include/--only can be used." ;;
-0,t,,* | 0,,t,)
-	die "No paths with --include/--only does not make sense." ;;
-0,,t,t)
-	only_include_assumed="# Clever... amending the last one with dirty index." ;;
-0,,,*)
-	;;
-*,,,*)
-	only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
-	also=
-	;;
-esac
-unset only
-case "$all,$interactive,$also,$#" in
-*t,*t,*)
-	die "Cannot use -a, --interactive or -i at the same time." ;;
-t,,[1-9]*)
-	die "Paths with -a does not make sense." ;;
-,t,[1-9]*)
-	die "Paths with --interactive does not make sense." ;;
-,,t,0)
-	die "No paths with -i does not make sense." ;;
-esac
-
-################################################################
-# Prepare index to have a tree to be committed
-
-case "$all,$also" in
-t,)
-	if test ! -f "$THIS_INDEX"
-	then
-		die 'nothing to commit (use "git add file1 file2" to include for commit)'
-	fi
-	save_index &&
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git-diff-files --name-only -z |
-		git-update-index --remove -z --stdin
-	) || exit
-	;;
-,t)
-	save_index &&
-	git-ls-files --error-unmatch -- "$@" >/dev/null || exit
-
-	git-diff-files --name-only -z -- "$@"  |
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git-update-index --remove -z --stdin
-	) || exit
-	;;
-,)
-	if test "$interactive" = t; then
-		git add --interactive || exit
-	fi
-	case "$#" in
-	0)
-		;; # commit as-is
-	*)
-		if test -f "$GIT_DIR/MERGE_HEAD"
-		then
-			refuse_partial "Cannot do a partial commit during a merge."
-		fi
-		TMP_INDEX="$GIT_DIR/tmp-index$$"
-		commit_only=`git-ls-files --error-unmatch -- "$@"` || exit
-
-		# Build a temporary index and update the real index
-		# the same way.
-		if test -z "$initial_commit"
-		then
-			GIT_INDEX_FILE="$THIS_INDEX" \
-			git-read-tree --index-output="$TMP_INDEX" -i -m HEAD
-		else
-			rm -f "$TMP_INDEX"
-		fi || exit
-
-		printf '%s\n' "$commit_only" |
-		GIT_INDEX_FILE="$TMP_INDEX" \
-		git-update-index --add --remove --stdin &&
-
-		save_index &&
-		printf '%s\n' "$commit_only" |
-		(
-			GIT_INDEX_FILE="$NEXT_INDEX"
-			export GIT_INDEX_FILE
-			git-update-index --remove --stdin
-		) || exit
-		;;
-	esac
-	;;
-esac
-
-################################################################
-# If we do as-is commit, the index file will be THIS_INDEX,
-# otherwise NEXT_INDEX after we make this commit.  We leave
-# the index as is if we abort.
-
-if test -f "$NEXT_INDEX"
-then
-	USE_INDEX="$NEXT_INDEX"
-else
-	USE_INDEX="$THIS_INDEX"
-fi
-
-case "$status_only" in
-t)
-	# This will silently fail in a read-only repository, which is
-	# what we want.
-	GIT_INDEX_FILE="$USE_INDEX" git-update-index -q --unmerged --refresh
-	run_status
-	exit $?
-	;;
-'')
-	GIT_INDEX_FILE="$USE_INDEX" git-update-index -q --refresh || exit
-	;;
-esac
-
-################################################################
-# Grab commit message, write out tree and make commit.
-
-if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
-then
-	if test "$TMP_INDEX"
-	then
-		GIT_INDEX_FILE="$TMP_INDEX" "$GIT_DIR"/hooks/pre-commit
-	else
-		GIT_INDEX_FILE="$USE_INDEX" "$GIT_DIR"/hooks/pre-commit
-	fi || exit
-fi
-
-if test "$log_message" != ''
-then
-	printf '%s\n' "$log_message"
-elif test "$logfile" != ""
-then
-	if test "$logfile" = -
-	then
-		test -t 0 &&
-		echo >&2 "(reading log message from standard input)"
-		cat
-	else
-		cat <"$logfile"
-	fi
-elif test "$use_commit" != ""
-then
-	encoding=$(git config i18n.commitencoding || echo UTF-8)
-	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
-	sed -e '1,/^$/d' -e 's/^    //'
-elif test -f "$GIT_DIR/MERGE_MSG"
-then
-	cat "$GIT_DIR/MERGE_MSG"
-elif test -f "$GIT_DIR/SQUASH_MSG"
-then
-	cat "$GIT_DIR/SQUASH_MSG"
-fi | git-stripspace >"$GIT_DIR"/COMMIT_EDITMSG
-
-case "$signoff" in
-t)
-	need_blank_before_signoff=
-	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-	grep 'Signed-off-by:' >/dev/null || need_blank_before_signoff=yes
-	{
-		test -z "$need_blank_before_signoff" || echo
-		git-var GIT_COMMITTER_IDENT | sed -e '
-			s/>.*/>/
-			s/^/Signed-off-by: /
-		'
-	} >>"$GIT_DIR"/COMMIT_EDITMSG
-	;;
-esac
-
-if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
-	echo "#"
-	echo "# It looks like you may be committing a MERGE."
-	echo "# If this is not correct, please remove the file"
-	printf '%s\n' "#	$GIT_DIR/MERGE_HEAD"
-	echo "# and try again"
-	echo "#"
-fi >>"$GIT_DIR"/COMMIT_EDITMSG
-
-# Author
-if test '' != "$use_commit"
-then
-	pick_author_script='
-	/^author /{
-		s/'\''/'\''\\'\'\''/g
-		h
-		s/^author \([^<]*\) <[^>]*> .*$/\1/
-		s/'\''/'\''\'\'\''/g
-		s/.*/GIT_AUTHOR_NAME='\''&'\''/p
-
-		g
-		s/^author [^<]* <\([^>]*\)> .*$/\1/
-		s/'\''/'\''\'\'\''/g
-		s/.*/GIT_AUTHOR_EMAIL='\''&'\''/p
-
-		g
-		s/^author [^<]* <[^>]*> \(.*\)$/\1/
-		s/'\''/'\''\'\'\''/g
-		s/.*/GIT_AUTHOR_DATE='\''&'\''/p
-
-		q
-	}
-	'
-	encoding=$(git config i18n.commitencoding || echo UTF-8)
-	set_author_env=`git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
-	LANG=C LC_ALL=C sed -ne "$pick_author_script"`
-	eval "$set_author_env"
-	export GIT_AUTHOR_NAME
-	export GIT_AUTHOR_EMAIL
-	export GIT_AUTHOR_DATE
-fi
-if test '' != "$force_author"
-then
-	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
-	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
-	test '' != "$GIT_AUTHOR_NAME" &&
-	test '' != "$GIT_AUTHOR_EMAIL" ||
-	die "malformed --author parameter"
-	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
-fi
-
-PARENTS="-p HEAD"
-if test -z "$initial_commit"
-then
-	rloga='commit'
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		rloga='commit (merge)'
-		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
-	elif test -n "$amend"; then
-		rloga='commit (amend)'
-		PARENTS=$(git-cat-file commit HEAD |
-			sed -n -e '/^$/q' -e 's/^parent /-p /p')
-	fi
-	current="$(git-rev-parse --verify HEAD)"
-else
-	if [ -z "$(git-ls-files)" ]; then
-		echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
-		exit 1
-	fi
-	PARENTS=""
-	rloga='commit (initial)'
-	current=''
-fi
-set_reflog_action "$rloga"
-
-if test -z "$no_edit"
-then
-	{
-		echo ""
-		echo "# Please enter the commit message for your changes."
-		echo "# (Comment lines starting with '#' will not be included)"
-		test -z "$only_include_assumed" || echo "$only_include_assumed"
-		run_status
-	} >>"$GIT_DIR"/COMMIT_EDITMSG
-else
-	# we need to check if there is anything to commit
-	run_status >/dev/null
-fi
-if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" -a -z "$amend" ]
-then
-	rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-	run_status
-	exit 1
-fi
-
-case "$no_edit" in
-'')
-	case "${VISUAL:-$EDITOR},$TERM" in
-	,dumb)
-		echo >&2 "Terminal is dumb but no VISUAL nor EDITOR defined."
-		echo >&2 "Please supply the commit log message using either"
-		echo >&2 "-m or -F option.  A boilerplate log message has"
-		echo >&2 "been prepared in $GIT_DIR/COMMIT_EDITMSG"
-		exit 1
-		;;
-	esac
-	git-var GIT_AUTHOR_IDENT > /dev/null  || die
-	git-var GIT_COMMITTER_IDENT > /dev/null  || die
-	${VISUAL:-${EDITOR:-vi}} "$GIT_DIR/COMMIT_EDITMSG"
-	;;
-esac
-
-case "$verify" in
-t)
-	if test -x "$GIT_DIR"/hooks/commit-msg
-	then
-		"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
-	fi
-esac
-
-if test -z "$no_edit"
-then
-    sed -e '
-        /^diff --git a\/.*/{
-	    s///
-	    q
-	}
-	/^#/d
-    ' "$GIT_DIR"/COMMIT_EDITMSG
-else
-    cat "$GIT_DIR"/COMMIT_EDITMSG
-fi |
-git-stripspace >"$GIT_DIR"/COMMIT_MSG
-
-if cnt=`grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
-	git-stripspace |
-	wc -l` &&
-   test 0 -lt $cnt
-then
-	if test -z "$TMP_INDEX"
-	then
-		tree=$(GIT_INDEX_FILE="$USE_INDEX" git-write-tree)
-	else
-		tree=$(GIT_INDEX_FILE="$TMP_INDEX" git-write-tree) &&
-		rm -f "$TMP_INDEX"
-	fi &&
-	commit=$(cat "$GIT_DIR"/COMMIT_MSG | git-commit-tree $tree $PARENTS) &&
-	rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
-	git-update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
-	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
-	if test -f "$NEXT_INDEX"
-	then
-		mv "$NEXT_INDEX" "$THIS_INDEX"
-	else
-		: ;# happy
-	fi
-else
-	echo >&2 "* no commit message?  aborting commit."
-	false
-fi
-ret="$?"
-rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-
-cd_to_toplevel
-
-if test -d "$GIT_DIR/rr-cache"
-then
-	git-rerere
-fi
-
-if test "$ret" = 0
-then
-	if test -x "$GIT_DIR"/hooks/post-commit
-	then
-		"$GIT_DIR"/hooks/post-commit
-	fi
-	if test -z "$quiet"
-	then
-		commit=`git-diff-tree --always --shortstat --pretty="format:%h: %s"\
-		       --summary --root HEAD --`
-		echo "Created${initial_commit:+ initial} commit $commit"
-	fi
-fi
-
-exit "$ret"
diff --git a/git.c b/git.c
index 29b55a1..4018e3c 100644
--- a/git.c
+++ b/git.c
@@ -237,6 +237,7 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
 		{ "check-attr", cmd_check_attr, RUN_SETUP | NOT_BARE },
 		{ "cherry", cmd_cherry, RUN_SETUP },
 		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NOT_BARE },
+		{ "commit", cmd_commit, RUN_SETUP },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
 		{ "config", cmd_config },
 		{ "count-objects", cmd_count_objects, RUN_SETUP },
@@ -279,10 +280,10 @@ static void handle_internal_command(int argc, const char **argv, char **envp)
 		{ "rev-parse", cmd_rev_parse, RUN_SETUP },
 		{ "revert", cmd_revert, RUN_SETUP | NOT_BARE },
 		{ "rm", cmd_rm, RUN_SETUP | NOT_BARE },
-		{ "runstatus", cmd_runstatus, RUN_SETUP | NOT_BARE },
 		{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
 		{ "show-branch", cmd_show_branch, RUN_SETUP },
 		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
+		{ "status", cmd_status, RUN_SETUP | NOT_BARE },
 		{ "stripspace", cmd_stripspace },
 		{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 		{ "tar-tree", cmd_tar_tree },
diff --git a/mktag.c b/mktag.c
index b82e377..26b9ebf 100644
--- a/mktag.c
+++ b/mktag.c
@@ -111,8 +111,8 @@ static int verify_tag(char *buffer, unsigned long size)
 
 int main(int argc, char **argv)
 {
-	unsigned long size = 4096;
-	char *buffer = xmalloc(size);
+	unsigned long size;
+	char *buffer;
 	unsigned char result_sha1[20];
 
 	if (argc != 1)
@@ -120,10 +120,8 @@ int main(int argc, char **argv)
 
 	setup_git_directory();
 
-	if (read_pipe(0, &buffer, &size)) {
-		free(buffer);
+	if (read_fd(0, &buffer, &size))
 		die("could not read from stdin");
-	}
 
 	/* Verify it for some basic sanity: it needs to start with
 	   "object <sha1>\ntype\ntagger " */
diff --git a/sha1_file.c b/sha1_file.c
index 2b86086..91e8854 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -2286,18 +2286,17 @@ int has_sha1_file(const unsigned char *sha1)
 }
 
 /*
- * reads from fd as long as possible into a supplied buffer of size bytes.
- * If necessary the buffer's size is increased using realloc()
+ * reads from fd as long as possible and allocates a buffer to hold
+ * the contents.  The buffer and size of the contents is returned in
+ * *return_buf and *return_size.  In case of failure, the allocated
+ * buffers are freed, otherwise, the buffer must be freed using xfree.
  *
  * returns 0 if anything went fine and -1 otherwise
- *
- * NOTE: both buf and size may change, but even when -1 is returned
- * you still have to free() it yourself.
  */
-int read_pipe(int fd, char** return_buf, unsigned long* return_size)
+int read_fd(int fd, char** return_buf, unsigned long* return_size)
 {
-	char* buf = *return_buf;
-	unsigned long size = *return_size;
+	unsigned long size = 4096;
+	char* buf = xmalloc(size);
 	ssize_t iret;
 	unsigned long off = 0;
 
@@ -2315,21 +2314,38 @@ int read_pipe(int fd, char** return_buf, unsigned long* return_size)
 	*return_buf = buf;
 	*return_size = off;
 
-	if (iret < 0)
+	if (iret < 0) {
+		free(buf);
+		return -1;
+	}
+
+	return 0;
+}
+
+int read_path(const char *path, char** return_buf, unsigned long* return_size)
+{
+	int fd; 
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return -1;
+	if (read_fd(fd, return_buf, return_size)) {
+		close(fd);
 		return -1;
+	}
+	close(fd);
+
 	return 0;
 }
 
 int index_pipe(unsigned char *sha1, int fd, const char *type, int write_object)
 {
-	unsigned long size = 4096;
-	char *buf = xmalloc(size);
+	unsigned long size;
+	char *buf;
 	int ret;
 
-	if (read_pipe(fd, &buf, &size)) {
-		free(buf);
+	if (read_fd(fd, &buf, &size))
 		return -1;
-	}
 
 	if (!type)
 		type = blob_type;
diff --git a/t/t7800-commit.sh b/t/t7800-commit.sh
new file mode 100644
index 0000000..1f97caa
--- /dev/null
+++ b/t/t7800-commit.sh
@@ -0,0 +1,126 @@
+#!/bin/sh
+#
+# Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
+#
+
+# FIXME: Test the various index usages, -i and -o, test reflog,
+# signoff, hooks
+
+test_description='git-commit'
+. ./test-lib.sh
+
+# Pick a date so we get consistent commits. 7/7/07 means good luck!
+export GIT_AUTHOR_DATE="July 7, 2007"
+export GIT_COMMITTER_DATE="July 7, 2007"
+
+echo "bongo bongo" >file
+test_expect_success \
+	"initial status" \
+	"git-add file && \
+	 git-status | grep 'Initial commit'"
+
+test_expect_failure \
+	"fail initial amend" \
+	"git-commit -m initial --amend"
+
+test_expect_success \
+	"initial commit" \
+	"git-commit -m initial"
+
+test_expect_failure \
+	"testing nothing to commit" \
+	"git-commit -m initial"
+
+echo "bongo bongo bongo" >file
+
+test_expect_success \
+	"next commit" \
+	"git-commit -m next -a"
+
+echo "more bongo: bongo bongo bongo bongo" >file
+
+test_expect_failure \
+	"commit message from non-existing file" \
+	"git-commit -F gah -a"
+
+cat >msg <<EOF
+		
+
+  
+Signed-off-by: hula
+EOF
+test_expect_failure \
+	"empty commit message" \
+	"git-commit -F msg -a"
+
+echo "this is the commit message, coming from a file" >msg
+test_expect_success \
+	"commit message from file" \
+	"git-commit -F msg -a"
+
+cat >editor <<\EOF
+#!/bin/sh
+sed -i -e "s/a file/an amend commit/g" $1
+EOF
+chmod 755 editor
+
+test_expect_success \
+	"amend commit" \
+	"VISUAL=./editor git-commit --amend"
+
+echo "enough with the bongos" >file
+test_expect_failure \
+	"passing --amend and -F" \
+	"git-commit -F msg --amend ."
+
+test_expect_success \
+	"using message from other commit" \
+	"git-commit -C HEAD^ ."
+
+cat >editor <<\EOF
+#!/bin/sh
+sed -i -e "s/amend/older/g" $1
+EOF
+chmod 755 editor
+
+echo "hula hula" >file
+test_expect_success \
+	"editing message from other commit" \
+	"VISUAL=./editor git-commit -c HEAD^ -a"
+
+echo "silly new contents" >file
+test_expect_success \
+	"message from stdin" \
+	"echo commit message from stdin | git-commit -F - -a"
+
+echo "gak" >file
+test_expect_success \
+	"overriding author from command line" \
+	"git-commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a"
+
+test_expect_success \
+	"interactive add" \
+	"echo 7 | git-commit --interactive | grep 'What now'"
+
+test_expect_success \
+	"showing committed revisions" \
+	"git-rev-list HEAD >current"
+
+# We could just check the head sha1, but checking each commit makes it
+# easier to isolate bugs.
+
+cat >expected <<\EOF
+9a7ad90c32f43aecc081722a72f26ead981bd6fa
+d5c6c34f0361d64d3d1b1f26736b1ae98e2baa90
+ca0ddb06fc90f3f857dd623f8418804aad75d9fa
+9cc5d9b9e5a29f1c46d0d0cf2dd716fb8241316a
+ca750e97c137587aa181b6b9526b3b04fb9db667
+4515202a60be41cb1b8f6b89edb3f6948130ac1c
+7cc9a125522fe28b84cd3f6c7aeef6e5c62b3f8b
+EOF
+
+test_expect_success \
+    'validate git-rev-list output.' \
+    'diff current expected'
+
+test_done
diff --git a/wt-status.c b/wt-status.c
index 5205420..5bf800a 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -54,29 +54,30 @@ void wt_status_prepare(struct wt_status *s)
 	s->reference = "HEAD";
 }
 
-static void wt_status_print_cached_header(const char *reference)
+static void wt_status_print_cached_header(struct wt_status *s)
 {
 	const char *c = color(WT_STATUS_HEADER);
-	color_printf_ln(c, "# Changes to be committed:");
-	if (reference) {
-		color_printf_ln(c, "#   (use \"git reset %s <file>...\" to unstage)", reference);
+	color_fprintf_ln(s->fp, c, "# Changes to be committed:");
+	if (s->reference) {
+		color_fprintf_ln(s->fp, c, "#   (use \"git reset %s <file>...\" to unstage)", s->reference);
 	} else {
-		color_printf_ln(c, "#   (use \"git rm --cached <file>...\" to unstage)");
+		color_fprintf_ln(s->fp, c, "#   (use \"git rm --cached <file>...\" to unstage)");
 	}
-	color_printf_ln(c, "#");
+	color_fprintf_ln(s->fp, c, "#");
 }
 
-static void wt_status_print_header(const char *main, const char *sub)
+static void wt_status_print_header(struct wt_status *s,
+				   const char *main, const char *sub)
 {
 	const char *c = color(WT_STATUS_HEADER);
-	color_printf_ln(c, "# %s:", main);
-	color_printf_ln(c, "#   (%s)", sub);
-	color_printf_ln(c, "#");
+	color_fprintf_ln(s->fp, c, "# %s:", main);
+	color_fprintf_ln(s->fp, c, "#   (%s)", sub);
+	color_fprintf_ln(s->fp, c, "#");
 }
 
-static void wt_status_print_trailer(void)
+static void wt_status_print_trailer(struct wt_status *s)
 {
-	color_printf_ln(color(WT_STATUS_HEADER), "#");
+	color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
 }
 
 static const char *quote_crlf(const char *in, char *buf, size_t sz)
@@ -108,7 +109,8 @@ static const char *quote_crlf(const char *in, char *buf, size_t sz)
 	return ret;
 }
 
-static void wt_status_print_filepair(int t, struct diff_filepair *p)
+static void wt_status_print_filepair(struct wt_status *s,
+				     int t, struct diff_filepair *p)
 {
 	const char *c = color(t);
 	const char *one, *two;
@@ -117,36 +119,36 @@ static void wt_status_print_filepair(int t, struct diff_filepair *p)
 	one = quote_crlf(p->one->path, onebuf, sizeof(onebuf));
 	two = quote_crlf(p->two->path, twobuf, sizeof(twobuf));
 
-	color_printf(color(WT_STATUS_HEADER), "#\t");
+	color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
 	switch (p->status) {
 	case DIFF_STATUS_ADDED:
-		color_printf(c, "new file:   %s", one);
+		color_fprintf(s->fp, c, "new file:   %s", one);
 		break;
 	case DIFF_STATUS_COPIED:
-		color_printf(c, "copied:     %s -> %s", one, two);
+		color_fprintf(s->fp, c, "copied:     %s -> %s", one, two);
 		break;
 	case DIFF_STATUS_DELETED:
-		color_printf(c, "deleted:    %s", one);
+		color_fprintf(s->fp, c, "deleted:    %s", one);
 		break;
 	case DIFF_STATUS_MODIFIED:
-		color_printf(c, "modified:   %s", one);
+		color_fprintf(s->fp, c, "modified:   %s", one);
 		break;
 	case DIFF_STATUS_RENAMED:
-		color_printf(c, "renamed:    %s -> %s", one, two);
+		color_fprintf(s->fp, c, "renamed:    %s -> %s", one, two);
 		break;
 	case DIFF_STATUS_TYPE_CHANGED:
-		color_printf(c, "typechange: %s", one);
+		color_fprintf(s->fp, c, "typechange: %s", one);
 		break;
 	case DIFF_STATUS_UNKNOWN:
-		color_printf(c, "unknown:    %s", one);
+		color_fprintf(s->fp, c, "unknown:    %s", one);
 		break;
 	case DIFF_STATUS_UNMERGED:
-		color_printf(c, "unmerged:   %s", one);
+		color_fprintf(s->fp, c, "unmerged:   %s", one);
 		break;
 	default:
 		die("bug: unhandled diff status %c", p->status);
 	}
-	printf("\n");
+	fprintf(s->fp, "\n");
 }
 
 static void wt_status_print_updated_cb(struct diff_queue_struct *q,
@@ -160,14 +162,14 @@ static void wt_status_print_updated_cb(struct diff_queue_struct *q,
 		if (q->queue[i]->status == 'U')
 			continue;
 		if (!shown_header) {
-			wt_status_print_cached_header(s->reference);
+			wt_status_print_cached_header(s);
 			s->commitable = 1;
 			shown_header = 1;
 		}
-		wt_status_print_filepair(WT_STATUS_UPDATED, q->queue[i]);
+		wt_status_print_filepair(s, WT_STATUS_UPDATED, q->queue[i]);
 	}
 	if (shown_header)
-		wt_status_print_trailer();
+		wt_status_print_trailer(s);
 }
 
 static void wt_status_print_changed_cb(struct diff_queue_struct *q,
@@ -184,18 +186,18 @@ static void wt_status_print_changed_cb(struct diff_queue_struct *q,
 				msg = use_add_rm_msg;
 				break;
 			}
-		wt_status_print_header("Changed but not updated", msg);
+		wt_status_print_header(s, "Changed but not updated", msg);
 	}
 	for (i = 0; i < q->nr; i++)
-		wt_status_print_filepair(WT_STATUS_CHANGED, q->queue[i]);
+		wt_status_print_filepair(s, WT_STATUS_CHANGED, q->queue[i]);
 	if (q->nr)
-		wt_status_print_trailer();
+		wt_status_print_trailer(s);
 }
 
 static void wt_read_cache(struct wt_status *s)
 {
 	discard_cache();
-	read_cache();
+	read_cache_from(s->index_file);
 }
 
 static void wt_status_print_initial(struct wt_status *s)
@@ -206,16 +208,16 @@ static void wt_status_print_initial(struct wt_status *s)
 	wt_read_cache(s);
 	if (active_nr) {
 		s->commitable = 1;
-		wt_status_print_cached_header(NULL);
+		wt_status_print_cached_header(s);
 	}
 	for (i = 0; i < active_nr; i++) {
-		color_printf(color(WT_STATUS_HEADER), "#\t");
-		color_printf_ln(color(WT_STATUS_UPDATED), "new file: %s",
+		color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
+		color_fprintf_ln(s->fp, color(WT_STATUS_UPDATED), "new file: %s",
 				quote_crlf(active_cache[i]->name,
 					   buf, sizeof(buf)));
 	}
 	if (active_nr)
-		wt_status_print_trailer();
+		wt_status_print_trailer(s);
 }
 
 static void wt_status_print_updated(struct wt_status *s)
@@ -281,12 +283,12 @@ static void wt_status_print_untracked(struct wt_status *s)
 		}
 		if (!shown_header) {
 			s->workdir_untracked = 1;
-			wt_status_print_header("Untracked files",
+			wt_status_print_header(s, "Untracked files",
 					       use_add_to_include_msg);
 			shown_header = 1;
 		}
-		color_printf(color(WT_STATUS_HEADER), "#\t");
-		color_printf_ln(color(WT_STATUS_UNTRACKED), "%.*s",
+		color_fprintf(s->fp, color(WT_STATUS_HEADER), "#\t");
+		color_fprintf_ln(s->fp, color(WT_STATUS_UNTRACKED), "%.*s",
 				ent->len, ent->name);
 	}
 }
@@ -316,14 +318,14 @@ void wt_status_print(struct wt_status *s)
 			branch_name = "";
 			on_what = "Not currently on any branch.";
 		}
-		color_printf_ln(color(WT_STATUS_HEADER),
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER),
 			"# %s%s", on_what, branch_name);
 	}
 
 	if (s->is_initial) {
-		color_printf_ln(color(WT_STATUS_HEADER), "#");
-		color_printf_ln(color(WT_STATUS_HEADER), "# Initial commit");
-		color_printf_ln(color(WT_STATUS_HEADER), "#");
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "# Initial commit");
+		color_fprintf_ln(s->fp, color(WT_STATUS_HEADER), "#");
 		wt_status_print_initial(s);
 	}
 	else {
@@ -337,7 +339,7 @@ void wt_status_print(struct wt_status *s)
 		wt_status_print_verbose(s);
 	if (!s->commitable) {
 		if (s->amend)
-			printf("# No changes\n");
+			fprintf(s->fp, "# No changes\n");
 		else if (s->workdir_dirty)
 			printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n");
 		else if (s->workdir_untracked)
diff --git a/wt-status.h b/wt-status.h
index cfea4ae..7744932 100644
--- a/wt-status.h
+++ b/wt-status.h
@@ -1,6 +1,8 @@
 #ifndef STATUS_H
 #define STATUS_H
 
+#include <stdio.h>
+
 enum color_wt_status {
 	WT_STATUS_HEADER,
 	WT_STATUS_UPDATED,
@@ -19,6 +21,8 @@ struct wt_status {
 	int commitable;
 	int workdir_dirty;
 	int workdir_untracked;
+	const char *index_file;
+	FILE *fp;
 };
 
 int git_status_config(const char *var, const char *value);
-- 
1.5.2.GIT

^ permalink raw reply related	[relevance 1%]

* Re: index-pack died on pread
  @ 2007-07-25 23:15  2%   ` Robin Rosenberg
  0 siblings, 0 replies; 200+ results
From: Robin Rosenberg @ 2007-07-25 23:15 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Michal Rokos, GIT

måndag 23 juli 2007 skrev Linus Torvalds:
> 
> On Mon, 23 Jul 2007, Michal Rokos wrote:
> >
> > fatal: cannot pread pack file: No such file or directory (n=0,
> > errno=2, fd=3, ptr=40452958, len=428, rdy=0, off=123601)
> 
> Ok, that's bogus. When "n" is zero, the errno (and thus the error string) 
> is not changed by pread, so that's a very misleading error report.
> 
> So what seems to have happened is that the pack-file is too short, so we 
> got a return value of 0, and then reported it as if it had an errno.
> 
> The reason for returning zero from pread would be:
> 
>  - broken pread. I don't think HPUX should be a problem, so that's 
>    probably not it.
> 
>  - the pack-file got truncated
> 
>  - the offset is corrupt, and points to beyond the size of the packfile.
> 
> In this case, since the offset is just 123601, I suspect it's a truncation 
> issue, and your pack-file is simply corrupt. Either because of some 
> problem with receiving it, or because of problems on the remote side.
> 
> > fetch-pack from 'git://git.kernel.org/pub/scm/git/git' failed.
> 
> One thing to look out for is that the "git.kernel.org" machines aren't the 
> "primary" ones, and the data gets mirrored from other machines. If the 
> mirroring is incomplete, I could imagine that the remote side simply ended 
> up terminating the connection, and you ended up with a partial pack-file.
> 
> Some of the kernel.org machines ran out of disk space the other day, so 
> maybe you happened to hit it in an unlucky window. Does it still happen?

Does cygwin have the same pread problem then.. ? after make NO_PREAD=1 with 1.5.2.4
clone works.

Here is my output with pread. Note that I'm cloning from or.cz, not kernel.org .

$ git clone git://repo.or.cz/git.git GIT 
Initialized empty Git repository in /roro/GIT/.git/ 
remote: Generating pack... 
remote: Done counting 56038 objects. 
remote: Deltifying 56038 objects... 
remote:  100% (56038/56038) done 
Indexing 56038 objects... 
remote: Total 56038 (delta 39190), reused 52555 (delta 36164) 
 100% (56038/56038) done 
Resolving 39190 deltas... 
fatal: cannot pread pack file: No such file or directory 
fatal: index-pack died with error code 128 
fetch-pack from 'git://repo.or.cz/git.git' failed.

-- robin

^ permalink raw reply	[relevance 2%]

* Re: People unaware of the importance of "git gc"?
  @ 2007-09-05 21:07  3% ` Alex Riesen
  0 siblings, 0 replies; 200+ results
From: Alex Riesen @ 2007-09-05 21:07 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Git Mailing List

Linus Torvalds, Wed, Sep 05, 2007 09:09:27 +0200:
> I personally repack everything way more often than is necessary, and I had 
> kind of assumed that people did it that way, but I was apparently wrong. 
> Comments?

I do it from time to time. Seldom in working repositories, because
they usually come and go before they have a chance to accumulate
enough of loose objects. I do a partial repack (git repack -d) after
every import from p4 repo, because every snapshot of it is an ugly
mess changing files all over the tree. Sometimes, after I merged a big
chunk with the p4 repo and sent it over (the process involves rebase).

It is usually concious decision when to do a repack or gc. The repack
time is seldom a problem: it is fast enough even on windows (and I do
have big repos and binary objects). The gc causes my machines to swap,
though. Some of them heavily, so there my repos stay longer partially
packed. I do use .keep packs for this reason (and because windows or
cygwin or both have more problems with big files the they have with
small).

I used to clone repos with "-s", but quickly stopped after a few
broken histories.  This also tought me to think before running
"git gc" or "git repack -a -d".

On a rare occurance I even use "git repack -a -d -l" and "git
pack-refs" separately.

This was all specific to my day-job. At home, on linux systems I just
run git-gc whenever I please, without even thinking why. It finishes
mostly in less than a minute (the kernel: ~40-50 sec on my P4 2.6GHz, 1Gb).

^ permalink raw reply	[relevance 3%]

* [PATCH 9/9] Implement git commit as a builtin command.
  @ 2007-09-06  0:23  2%               ` Kristian Høgsberg
  0 siblings, 0 replies; 200+ results
From: Kristian Høgsberg @ 2007-09-06  0:23 UTC (permalink / raw)
  To: git; +Cc: Kristian Høgsberg

Move git-commit.sh to contrib/examples.

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
 Makefile                       |    9 +-
 builtin-commit.c               |  742 ++++++++++++++++++++++++++++++++++++++++
 builtin.h                      |    3 +-
 contrib/examples/git-commit.sh |  665 +++++++++++++++++++++++++++++++++++
 git-commit.sh                  |  665 -----------------------------------
 git.c                          |    3 +-
 6 files changed, 1414 insertions(+), 673 deletions(-)
 create mode 100644 builtin-commit.c
 create mode 100755 contrib/examples/git-commit.sh
 delete mode 100755 git-commit.sh

diff --git a/Makefile b/Makefile
index 4eb4637..beb3cbb 100644
--- a/Makefile
+++ b/Makefile
@@ -201,7 +201,7 @@ BASIC_LDFLAGS =
 
 SCRIPT_SH = \
 	git-bisect.sh git-checkout.sh \
-	git-clean.sh git-clone.sh git-commit.sh \
+	git-clean.sh git-clone.sh \
 	git-fetch.sh \
 	git-ls-remote.sh \
 	git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
@@ -250,7 +250,7 @@ EXTRA_PROGRAMS =
 BUILT_INS = \
 	git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
 	git-get-tar-commit-id$X git-init$X git-repo-config$X \
-	git-fsck-objects$X git-cherry-pick$X \
+	git-fsck-objects$X git-cherry-pick$X git-status$X\
 	$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
 
 # what 'all' will build and 'install' will install, in gitexecdir
@@ -322,6 +322,7 @@ BUILTIN_OBJS = \
 	builtin-check-attr.o \
 	builtin-checkout-index.o \
 	builtin-check-ref-format.o \
+	builtin-commit.o \
 	builtin-commit-tree.o \
 	builtin-count-objects.o \
 	builtin-describe.o \
@@ -357,7 +358,6 @@ BUILTIN_OBJS = \
 	builtin-rev-parse.o \
 	builtin-revert.o \
 	builtin-rm.o \
-	builtin-runstatus.o \
 	builtin-shortlog.o \
 	builtin-show-branch.o \
 	builtin-stripspace.o \
@@ -797,9 +797,6 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
 	chmod +x $@+ && \
 	mv $@+ $@
 
-git-status: git-commit
-	$(QUIET_GEN)cp $< $@+ && mv $@+ $@
-
 gitweb/gitweb.cgi: gitweb/gitweb.perl
 	$(QUIET_GEN)$(RM) $@ $@+ && \
 	sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
diff --git a/builtin-commit.c b/builtin-commit.c
new file mode 100644
index 0000000..aca5ff8
--- /dev/null
+++ b/builtin-commit.c
@@ -0,0 +1,742 @@
+/*
+ * Builtin "git commit"
+ *
+ * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
+ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "cache.h"
+#include "cache-tree.h"
+#include "builtin.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "commit.h"
+#include "revision.h"
+#include "wt-status.h"
+#include "run-command.h"
+#include "refs.h"
+#include "log-tree.h"
+#include "strbuf.h"
+#include "utf8.h"
+
+void launch_editor(const char *path, struct strbuf *sb);
+int rerere(void);
+
+static const char builtin_commit_usage[] =
+	"[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]";
+
+static unsigned char head_sha1[20], merge_head_sha1[20];
+static char *use_message_buffer;
+static const char commit_editmsg[] = "COMMIT_EDITMSG";
+static struct lock_file lock_file;
+
+enum option_type {
+    OPTION_NONE,
+    OPTION_STRING,
+    OPTION_INTEGER,
+    OPTION_LAST,
+};
+
+struct option {
+    enum option_type type;
+    const char *long_name;
+    char short_name;
+    void *value;
+};
+
+static int scan_options(const char ***argv, struct option *options)
+{
+	const char *value, *eq;
+	int i;
+
+	if (**argv == NULL)
+		return 0;
+	if ((**argv)[0] != '-')
+		return 0;
+	if (!strcmp(**argv, "--"))
+		return 0;
+
+	value = NULL;
+	for (i = 0; options[i].type != OPTION_LAST; i++) {
+		if ((**argv)[1] == '-') {
+			if (!prefixcmp(options[i].long_name, **argv + 2)) {
+				if (options[i].type != OPTION_NONE)
+					value = *++(*argv);
+				goto match;
+			}
+
+			eq = strchr(**argv + 2, '=');
+			if (eq && options[i].type != OPTION_NONE &&
+			    !strncmp(**argv + 2, 
+				     options[i].long_name, eq - **argv - 2)) {
+				value = eq + 1;
+				goto match;
+			}
+		}
+
+		if ((**argv)[1] == options[i].short_name) {
+			if ((**argv)[2] == '\0') {
+				if (options[i].type != OPTION_NONE)
+					value = *++(*argv);
+				goto match;
+			}
+
+			if (options[i].type != OPTION_NONE) {
+				value = **argv + 2;
+				goto match;
+			}
+		}
+	}
+
+	usage(builtin_commit_usage);
+
+ match:
+	switch (options[i].type) {
+	case OPTION_NONE:
+		*(int *)options[i].value = 1;
+		break;
+	case OPTION_STRING:
+		if (value == NULL)
+			die("option %s requires a value.", (*argv)[-1]);
+		*(const char **)options[i].value = value;
+		break;
+	case OPTION_INTEGER:
+		if (value == NULL)
+			die("option %s requires a value.", (*argv)[-1]);
+		*(int *)options[i].value = atoi(value);
+		break;
+	default:
+		assert(0);
+	}
+
+	(*argv)++;
+
+	return 1;
+}
+
+static char *logfile, *force_author, *message, *template_file;
+static char *edit_message, *use_message;
+static int all, edit_flag, also, interactive, only, no_verify, amend, signoff;
+static int quiet, verbose, untracked_files;
+
+static int no_edit, initial_commit, in_merge;
+const char *only_include_assumed;
+
+static struct option commit_options[] = {
+	{ OPTION_STRING, "file", 'F', (void *) &logfile },
+	{ OPTION_NONE, "all", 'a', &all },
+	{ OPTION_STRING, "author", 0, (void *) &force_author },
+	{ OPTION_NONE, "edit", 'e', &edit_flag },
+	{ OPTION_NONE, "include", 'i', &also },
+	{ OPTION_NONE, "interactive", 0, &interactive },
+	{ OPTION_NONE, "only", 'o', &only },
+	{ OPTION_STRING, "message", 'm', &message },
+	{ OPTION_NONE, "no-verify", 'n', &no_verify },
+	{ OPTION_NONE, "amend", 0, &amend },
+	{ OPTION_STRING, "reedit-message", 'c', &edit_message },
+	{ OPTION_STRING, "reuse-message", 'C', &use_message },
+	{ OPTION_NONE, "signoff", 's', &signoff },
+	{ OPTION_NONE, "quiet", 'q', &quiet },
+	{ OPTION_NONE, "verbose", 'v', &verbose },
+	{ OPTION_NONE, "untracked-files", 0, &untracked_files },
+	{ OPTION_STRING, "template", 't', &template_file },
+	{ OPTION_LAST },
+};
+
+/* FIXME: Taken from builtin-add, should be shared. */
+
+static void update_callback(struct diff_queue_struct *q,
+			    struct diff_options *opt, void *cbdata)
+{
+	int i, verbose;
+
+	verbose = *((int *)cbdata);
+	for (i = 0; i < q->nr; i++) {
+		struct diff_filepair *p = q->queue[i];
+		const char *path = p->one->path;
+		switch (p->status) {
+		default:
+			die("unexpacted diff status %c", p->status);
+		case DIFF_STATUS_UNMERGED:
+		case DIFF_STATUS_MODIFIED:
+		case DIFF_STATUS_TYPE_CHANGED:
+			add_file_to_cache(path, verbose);
+			break;
+		case DIFF_STATUS_DELETED:
+			remove_file_from_cache(path);
+			cache_tree_invalidate_path(active_cache_tree, path);
+			if (verbose)
+				printf("remove '%s'\n", path);
+			break;
+		}
+	}
+}
+
+static void
+add_files_to_cache(int fd, const char **files, const char *prefix)
+{
+	struct rev_info rev;
+
+	init_revisions(&rev, "");
+	setup_revisions(0, NULL, &rev, NULL);
+	rev.prune_data = get_pathspec(prefix, files);
+	rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
+	rev.diffopt.format_callback = update_callback;
+	rev.diffopt.format_callback_data = &verbose;
+
+	run_diff_files(&rev, 0);
+	refresh_cache(REFRESH_QUIET);
+
+	if (write_cache(fd, active_cache, active_nr) || close(fd))
+		die("unable to write new index file");
+}
+
+static char *
+prepare_index(const char **files, const char *prefix)
+{
+	int fd;
+	struct tree *tree;
+	struct lock_file *next_index_lock;
+
+	fd = hold_locked_index(&lock_file, 1);
+	if (read_cache() < 0)
+		die("index file corrupt");
+
+	if (all) {
+		add_files_to_cache(fd, files, NULL);
+		return lock_file.filename;
+	} else if (also) {
+		add_files_to_cache(fd, files, prefix);
+		return lock_file.filename;
+	}
+
+	if (interactive)
+		interactive_add();
+
+	if (*files == NULL) {
+		/* Commit index as-is. */
+		rollback_lock_file(&lock_file);
+		return get_index_file();
+	}
+
+	/*
+	 * FIXME: Warn on unknown files.  Shell script does
+	 *
+	 *   commit_only=`git-ls-files --error-unmatch -- "$@"`
+	 */
+
+	/*
+	 * FIXME: shell script does
+	 *
+	 *   git-read-tree --index-output="$TMP_INDEX" -i -m HEAD
+	 *
+	 * which warns about unmerged files in the index.
+	 */
+
+	/* update the user index file */
+	add_files_to_cache(fd, files, prefix);
+
+	if (!initial_commit) {
+		tree = parse_tree_indirect(head_sha1);
+		if (!tree)
+			die("failed to unpack HEAD tree object");
+		if (read_tree(tree, 0, NULL))
+			die("failed to read HEAD tree object");
+	}
+
+	/* Uh oh, abusing lock_file to create a garbage collected file */
+	next_index_lock = xmalloc(sizeof(*next_index_lock));
+	fd = hold_lock_file_for_update(next_index_lock,
+				       git_path("next-index-%d", getpid()), 1);
+	add_files_to_cache(fd, files, prefix);
+
+	return next_index_lock->filename;
+}
+
+static int run_status(FILE *fp, const char *index_file)
+{
+	struct wt_status s;
+
+	wt_status_prepare(&s);
+
+	if (amend) {
+		s.amend = 1;
+		s.reference = "HEAD^1";
+	}
+	s.verbose = verbose;
+	s.untracked = untracked_files;
+	s.index_file = index_file;
+	s.fp = fp;
+
+	wt_status_print(&s);
+
+	return s.commitable;
+}
+
+static const char sign_off_header[] = "Signed-off-by: ";
+
+static int prepare_log_message(const char *index_file)
+{
+	struct stat statbuf;
+	int commitable;
+	struct strbuf sb;
+	char *buffer;
+	FILE *fp;
+
+	strbuf_init(&sb);
+	if (message) {
+		strbuf_add(&sb, message, strlen(message));
+	} else if (logfile && !strcmp(logfile, "-")) {
+		if (isatty(0))
+			fprintf(stderr, "(reading log message from standard input)\n");
+		if (strbuf_read_fd(&sb, 0) < 0)
+			die("could not read log from standard input");
+	} else if (logfile) {
+		if (strbuf_read_path(&sb, logfile) < 0)
+			die("could not read log file '%s': %s",
+			    logfile, strerror(errno));
+	} else if (use_message) {
+		buffer = strstr(use_message_buffer, "\n\n");
+		if (!buffer || buffer[2] == '\0')
+			die("commit has empty message");
+		strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
+	} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
+		if (strbuf_read_path(&sb, git_path("MERGE_MSG")) < 0)
+			die("could not read MERGE_MSG: %s", strerror(errno));
+	} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
+		if (strbuf_read_path(&sb, git_path("SQUASH_MSG")) < 0)
+			die("could not read SQUASH_MSG: %s", strerror(errno));
+	} else if (!stat(template_file, &statbuf)) {
+		if (strbuf_read_path(&sb, template_file) < 0)
+			die("could not read %s: %s",
+			    template_file, strerror(errno));
+	}
+
+	fp = fopen(git_path(commit_editmsg), "w");
+	if (fp == NULL)
+		die("could not open %s\n", git_path(commit_editmsg));
+		
+	stripspace(&sb, 0);
+	if (fwrite(sb.buf, 1, sb.len, fp) < sb.len)
+		die("could not write commit template: %s\n",
+		    strerror(errno));
+
+	if (signoff) {
+		const char *info, *bol;
+
+		info = git_committer_info(1);
+		strbuf_add_char(&sb, '\0');
+		bol = strrchr(sb.buf + sb.len - 1, '\n');
+		if (!bol || prefixcmp(bol, sign_off_header))
+			fprintf(fp, "\n");
+		fprintf(fp, "Signed-off-by: %s\n", git_committer_info(1));
+	}
+
+	strbuf_release(&sb);
+
+	if (in_merge && !no_edit) {
+		fprintf(fp,
+			"#\n"
+			"# It looks like you may be committing a MERGE.\n"
+			"# If this is not correct, please remove the file\n"
+			"#	%s\n"
+			"# and try again.\n"
+			"#\n",
+			git_path("MERGE_HEAD"));
+	}
+
+	fprintf(fp,
+		"\n"
+		"# Please enter the commit message for your changes.\n"
+		"# (Comment lines starting with '#' will not be included)\n");
+	if (only_include_assumed)
+		fprintf(fp, "# %s\n", only_include_assumed);
+
+	commitable = run_status(fp, index_file);
+
+	fclose(fp);
+
+	return commitable;
+}
+
+/* Find out if the message starting at position 'start' in the strbuf
+ * contains only whitespace and Signed-off-by lines. */
+static int message_is_empty(struct strbuf *sb, int start)
+{
+	static const char signed_off_by[] = "Signed-off-by: ";
+	struct strbuf tmpl;
+	const char *nl;
+	int eol, i;
+
+	/* See if the template is just a prefix of the message. */
+	strbuf_init(&tmpl);
+	if (template_file && strbuf_read_path(&tmpl, template_file) > 0) {
+		stripspace(&tmpl, 1);
+		if (start + tmpl.len <= sb->len &&
+		    memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0)
+			start += tmpl.len;
+	}
+	strbuf_release(&tmpl);
+
+	/* Check if the rest is just whitespace and Signed-of-by's. */
+	for (i = start; i < sb->len; i++) {
+		nl = memchr(sb->buf + i, '\n', sb->len - i);
+		if (nl)
+			eol = nl - sb->buf;
+		else
+			eol = sb->len;
+
+		if (strlen(signed_off_by) <= eol - i &&
+		    !prefixcmp(sb->buf + i, signed_off_by)) {
+			i = eol;
+			continue;
+		}
+		while (i < eol)
+			if (!isspace(sb->buf[i++]))
+				return 0;
+	}
+
+	return 1;
+}
+
+static void determine_author_info(struct strbuf *sb)
+{
+	char *p, *eol;
+	char *name = NULL, *email = NULL;
+
+	if (use_message) {
+		p = strstr(use_message_buffer, "\nauthor");
+		if (!p)
+			die("invalid commit: %s\n", use_message);
+		p++;
+		eol = strchr(p, '\n');
+		if (!eol)
+			die("invalid commit: %s\n", use_message);
+
+		strbuf_add(sb, p, eol + 1 - p);
+	} else if (force_author) {
+		const char *eoname = strstr(force_author, " <");
+		const char *eomail = strchr(force_author, '>');
+
+		if (!eoname || !eomail)
+			die("malformed --author parameter\n");
+		name = xstrndup(force_author, eoname - force_author);
+		email = xstrndup(eoname + 2, eomail - eoname - 2);
+		strbuf_printf(sb, "author %s\n",
+			      fmt_ident(name, email, 
+					getenv("GIT_AUTHOR_DATE"), 1));
+		free(name);
+		free(email);
+	} else {
+		strbuf_printf(sb, "author %s\n", git_author_info(1));
+	}
+}
+
+static void parse_and_validate_options(const char ***argv)
+{
+	int f = 0;
+
+	(*argv)++;
+	while (scan_options(argv, commit_options))
+		;
+
+	if (logfile || message || use_message)
+		no_edit = 1;
+	if (edit_flag)
+		no_edit = 0;
+
+	if (get_sha1("HEAD", head_sha1))
+		initial_commit = 1;
+
+	if (!get_sha1("MERGE_HEAD", merge_head_sha1))
+		in_merge = 1;
+
+	/* Sanity check options */
+	if (amend && initial_commit)
+		die("You have nothing to amend.");
+	if (amend && in_merge)
+		die("You are in the middle of a merger -- cannot amend.");
+
+	if (use_message)
+		f++;
+	if (edit_message)
+		f++;
+	if (logfile)
+		f++;
+	if (f > 1)
+		die("Only one of -c/-C/-F can be used.");
+	if (message && f > 0)
+		die("Option -m cannot be combined with -c/-C/-F.");
+	if (edit_message)
+		use_message = edit_message;
+	if (amend)
+		use_message = "HEAD";
+	if (use_message) {
+		unsigned char sha1[20];
+		static char utf8[] = "UTF-8";
+		char *enc, *end, *out_enc;
+		struct commit *commit;
+
+		if (get_sha1(use_message, sha1))
+			die("could not lookup commit %s", use_message);
+		commit = lookup_commit(sha1);
+		if (!commit || parse_commit(commit))
+			die("could not parse commit %s", use_message);
+
+		enc = strstr(commit->buffer, "\nencoding");
+		if (enc) {
+			end = strchr(enc + 10, '\n');
+			enc = xstrndup(enc + 10, end - (enc + 10));
+		} else {
+			enc = utf8;
+		}
+		out_enc = git_commit_encoding ? git_commit_encoding : utf8;
+
+		use_message_buffer =
+			reencode_string(commit->buffer, out_enc, enc);
+		if (enc != utf8)
+			free(enc);
+	}
+
+	if (also && only)
+		die("Only one of --include/--only can be used.");
+	if (!*argv && (also || (only && !amend)))
+		die("No paths with --include/--only does not make sense.");
+	if (!*argv && only && amend)
+		only_include_assumed = "Clever... amending the last one with dirty index.";
+	if (*argv && !also && !only) {
+		only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
+		also = 0;
+	}
+
+	if (all && interactive)
+		die("Cannot use -a, --interactive or -i at the same time.");
+	else if (all && **argv)
+		die("Paths with -a does not make sense.");
+	else if (interactive && **argv)
+		die("Paths with --interactive does not make sense.");
+}
+
+int cmd_status(int argc, const char **argv, const char *prefix)
+{
+	const char *index_file;
+	int commitable;
+
+	git_config(git_status_config);
+
+	parse_and_validate_options(&argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	commitable = run_status(stdout, index_file);
+
+	rollback_lock_file(&lock_file);
+
+	return commitable ? 0 : 1;
+}
+
+static int run_hook(const char *index_file, const char *name, const char *arg)
+{
+	struct child_process hook;
+	const char *argv[3], *env[2];
+	char index[PATH_MAX];
+
+	argv[0] = git_path("hooks/%s", name);
+	argv[1] = arg;
+	argv[2] = NULL;
+	snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
+	env[0] = index;
+	env[1] = NULL;
+
+	if (access(argv[0], X_OK) < 0)
+		return 0;
+
+	memset(&hook, 0, sizeof(hook));
+	hook.argv = argv;
+	hook.no_stdin = 1;
+	hook.stdout_to_stderr = 1;
+	hook.env = env;
+
+	return run_command(&hook);
+}
+
+static void print_summary(const char *prefix, const unsigned char *sha1)
+{
+	struct rev_info rev;
+	struct commit *commit;
+
+	commit = lookup_commit(sha1);
+	if (!commit)
+		die("couldn't look up newly created commit\n");
+	if (!commit || parse_commit(commit))
+		die("could not parse newly created commit");
+
+	init_revisions(&rev, prefix);
+	setup_revisions(0, NULL, &rev, NULL);
+
+	rev.abbrev = 0;
+	rev.diff = 1;
+	rev.diffopt.output_format =
+		DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
+
+	rev.verbose_header = 1;
+	rev.show_root_diff = 1;
+	rev.commit_format = get_commit_format("format:%h: %s");
+	rev.always_show_header = 1;
+		
+	printf("Created %scommit ", initial_commit ? "initial " : "");
+
+	log_tree_commit(&rev, commit);
+}
+
+int git_commit_config(const char *k, const char *v)
+{
+	if (!strcmp(k, "commit.template")) {
+		template_file = xstrdup(v);
+		return 0;
+	}
+
+	return git_status_config(k, v);
+}
+
+static const char commit_utf8_warn[] =
+"Warning: commit message does not conform to UTF-8.\n"
+"You may want to amend it after fixing the message, or set the config\n"
+"variable i18n.commitencoding to the encoding your project uses.\n";
+
+int cmd_commit(int argc, const char **argv, const char *prefix)
+{
+	int header_len, parent_count = 0;
+	struct strbuf sb;
+	const char *index_file, *reflog_msg;
+	char *nl, *header_line;
+	unsigned char commit_sha1[20];
+	struct ref_lock *ref_lock;
+
+	git_config(git_commit_config);
+
+	parse_and_validate_options(&argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	if (run_hook(index_file, "pre-commit", NULL))
+		exit(1);
+
+	if (!prepare_log_message(index_file)) {
+		run_status(stdout, index_file);
+		unlink(commit_editmsg);
+		return 1;
+	}
+
+	strbuf_init(&sb);
+
+	/* Start building up the commit header */
+	read_cache_from(index_file);
+	active_cache_tree = cache_tree();
+	if (cache_tree_update(active_cache_tree,
+			      active_cache, active_nr, 0, 0) < 0)
+		die("Error building trees");
+	strbuf_printf(&sb, "tree %s\n",
+		      sha1_to_hex(active_cache_tree->sha1));
+
+	/* Determine parents */
+	if (initial_commit) {
+		reflog_msg = "commit (initial)"; 
+		parent_count = 0;
+	} else if (amend) {
+		struct commit_list *c;
+		struct commit *commit;
+
+		reflog_msg = "commit (amend)";
+		commit = lookup_commit(head_sha1);
+		if (!commit || parse_commit(commit))
+			die("could not parse HEAD commit");
+
+		for (c = commit->parents; c; c = c->next)
+			strbuf_printf(&sb, "parent %s\n",
+				      sha1_to_hex(c->item->object.sha1));
+	} else if (in_merge) {
+		struct strbuf m;
+		FILE *fp;
+
+		reflog_msg = "commit (merge)";
+		strbuf_printf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+		strbuf_init(&m);
+		fp = fopen(git_path("MERGE_HEAD"), "r");
+		if (fp == NULL)
+			die("could not open %s for reading: %s",
+			    git_path("MERGE_HEAD"), strerror(errno));
+		while (!m.eof) {
+			read_line(&m, fp, '\n');
+			if (!m.eof)
+				strbuf_printf(&sb, "parent %s\n", m.buf);
+		}
+		fclose(fp);
+		strbuf_release(&m);
+	} else {
+		reflog_msg = "commit";
+		strbuf_printf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+	}
+
+	determine_author_info(&sb);
+	strbuf_printf(&sb, "committer %s\n", git_committer_info(1));
+	if (!is_encoding_utf8(git_commit_encoding))
+		strbuf_printf(&sb, "encoding %s\n", git_commit_encoding);
+	strbuf_add_char(&sb, '\n');
+
+	/* Get the commit message and validate it */
+	header_len = sb.len;
+	if (!no_edit) {
+		fprintf(stderr, "launching editor, log %s\n", logfile);
+		launch_editor(git_path(commit_editmsg), &sb);
+	}
+	else if (strbuf_read_path(&sb, git_path(commit_editmsg)) < 0)
+		die("could not read commit message\n");
+	if (run_hook(index_file, "commit-msg", commit_editmsg))
+		exit(1);
+	if (stripspace(&sb, 1) < header_len ||
+	    message_is_empty(&sb, header_len))
+		die("* no commit message?  aborting commit.");
+	strbuf_add_char(&sb, '\0');
+	if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf))
+		fprintf(stderr, commit_utf8_warn);
+
+	if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1))
+		die("failed to write commit object");
+		       
+	ref_lock = lock_any_ref_for_update("HEAD",
+					   initial_commit ? NULL : head_sha1,
+					   0);
+
+	nl = strchr(sb.buf + header_len, '\n');
+	header_line = xstrndup(sb.buf + header_len,
+			       nl - (sb.buf + header_len));
+	strbuf_release(&sb);
+	strbuf_printf(&sb, "%s: %s\n", reflog_msg, header_line);
+	strbuf_add_char(&sb, '\0');
+	free(header_line);
+
+	if (!ref_lock)
+		die("cannot lock HEAD ref");
+	if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0)
+		die("cannot update HEAD ref");
+
+	unlink(git_path("MERGE_HEAD"));
+	unlink(git_path("MERGE_MSG"));
+
+	if (lock_file.filename[0] && commit_locked_index(&lock_file))
+		die("failed to write new index");
+
+	rerere();
+
+	run_hook(index_file, "post-commit", NULL);
+
+	if (!quiet)
+		print_summary(prefix, commit_sha1);
+
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index 91bc595..c23cd6d 100644
--- a/builtin.h
+++ b/builtin.h
@@ -23,6 +23,7 @@ extern int cmd_check_attr(int argc, const char **argv, const char *prefix);
 extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
+extern int cmd_commit(int argc, const char **argv, const char *prefix);
 extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_describe(int argc, const char **argv, const char *prefix);
@@ -63,10 +64,10 @@ extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
 extern int cmd_revert(int argc, const char **argv, const char *prefix);
 extern int cmd_rm(int argc, const char **argv, const char *prefix);
-extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
 extern int cmd_shortlog(int argc, const char **argv, const char *prefix);
 extern int cmd_show(int argc, const char **argv, const char *prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
+extern int cmd_status(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
 extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_tag(int argc, const char **argv, const char *prefix);
diff --git a/contrib/examples/git-commit.sh b/contrib/examples/git-commit.sh
new file mode 100755
index 0000000..d7e7028
--- /dev/null
+++ b/contrib/examples/git-commit.sh
@@ -0,0 +1,665 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Linus Torvalds
+# Copyright (c) 2006 Junio C Hamano
+
+USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
+SUBDIRECTORY_OK=Yes
+. git-sh-setup
+require_work_tree
+
+git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
+
+case "$0" in
+*status)
+	status_only=t
+	;;
+*commit)
+	status_only=
+	;;
+esac
+
+refuse_partial () {
+	echo >&2 "$1"
+	echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
+	exit 1
+}
+
+THIS_INDEX="$GIT_DIR/index"
+NEXT_INDEX="$GIT_DIR/next-index$$"
+rm -f "$NEXT_INDEX"
+save_index () {
+	cp -p "$THIS_INDEX" "$NEXT_INDEX"
+}
+
+run_status () {
+	# If TMP_INDEX is defined, that means we are doing
+	# "--only" partial commit, and that index file is used
+	# to build the tree for the commit.  Otherwise, if
+	# NEXT_INDEX exists, that is the index file used to
+	# make the commit.  Otherwise we are using as-is commit
+	# so the regular index file is what we use to compare.
+	if test '' != "$TMP_INDEX"
+	then
+		GIT_INDEX_FILE="$TMP_INDEX"
+		export GIT_INDEX_FILE
+	elif test -f "$NEXT_INDEX"
+	then
+		GIT_INDEX_FILE="$NEXT_INDEX"
+		export GIT_INDEX_FILE
+	fi
+
+	case "$status_only" in
+	t) color= ;;
+	*) color=--nocolor ;;
+	esac
+	git runstatus ${color} \
+		${verbose:+--verbose} \
+		${amend:+--amend} \
+		${untracked_files:+--untracked}
+}
+
+trap '
+	test -z "$TMP_INDEX" || {
+		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
+	}
+	rm -f "$NEXT_INDEX"
+' 0
+
+################################################################
+# Command line argument parsing and sanity checking
+
+all=
+also=
+interactive=
+only=
+logfile=
+use_commit=
+amend=
+edit_flag=
+no_edit=
+log_given=
+log_message=
+verify=t
+quiet=
+verbose=
+signoff=
+force_author=
+only_include_assumed=
+untracked_files=
+templatefile="`git config commit.template`"
+while case "$#" in 0) break;; esac
+do
+	case "$1" in
+	-F|--F|-f|--f|--fi|--fil|--file)
+		case "$#" in 1) usage ;; esac
+		shift
+		no_edit=t
+		log_given=t$log_given
+		logfile="$1"
+		shift
+		;;
+	-F*|-f*)
+		no_edit=t
+		log_given=t$log_given
+		logfile=`expr "z$1" : 'z-[Ff]\(.*\)'`
+		shift
+		;;
+	--F=*|--f=*|--fi=*|--fil=*|--file=*)
+		no_edit=t
+		log_given=t$log_given
+		logfile=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+		shift
+		;;
+	-a|--a|--al|--all)
+		all=t
+		shift
+		;;
+	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
+		force_author=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+		shift
+		;;
+	--au|--aut|--auth|--autho|--author)
+		case "$#" in 1) usage ;; esac
+		shift
+		force_author="$1"
+		shift
+		;;
+	-e|--e|--ed|--edi|--edit)
+		edit_flag=t
+		shift
+		;;
+	-i|--i|--in|--inc|--incl|--inclu|--includ|--include)
+		also=t
+		shift
+		;;
+	--int|--inte|--inter|--intera|--interac|--interact|--interacti|\
+	--interactiv|--interactive)
+		interactive=t
+		shift
+		;;
+	-o|--o|--on|--onl|--only)
+		only=t
+		shift
+		;;
+	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=m$log_given
+		if test "$log_message" = ''
+		then
+		    log_message="$1"
+		else
+		    log_message="$log_message
+
+$1"
+		fi
+		no_edit=t
+		shift
+		;;
+	-m*)
+		log_given=m$log_given
+		if test "$log_message" = ''
+		then
+		    log_message=`expr "z$1" : 'z-m\(.*\)'`
+		else
+		    log_message="$log_message
+
+`expr "z$1" : 'z-m\(.*\)'`"
+		fi
+		no_edit=t
+		shift
+		;;
+	--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
+		log_given=m$log_given
+		if test "$log_message" = ''
+		then
+		    log_message=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+		else
+		    log_message="$log_message
+
+`expr "z$1" : 'zq-[^=]*=\(.*\)'`"
+		fi
+		no_edit=t
+		shift
+		;;
+	-n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
+	--no-verify)
+		verify=
+		shift
+		;;
+	--a|--am|--ame|--amen|--amend)
+		amend=t
+		use_commit=HEAD
+		shift
+		;;
+	-c)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=
+		shift
+		;;
+	--ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
+	--reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
+	--reedit-messag=*|--reedit-message=*)
+		log_given=t$log_given
+		use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+		no_edit=
+		shift
+		;;
+	--ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
+	--reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
+	--reedit-message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=
+		shift
+		;;
+	-C)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=t
+		shift
+		;;
+	--reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
+	--reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
+	--reuse-message=*)
+		log_given=t$log_given
+		use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
+		no_edit=t
+		shift
+		;;
+	--reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
+	--reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=t
+		shift
+		;;
+	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
+		signoff=t
+		shift
+		;;
+	-t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
+		case "$#" in 1) usage ;; esac
+		shift
+		templatefile="$1"
+		no_edit=
+		shift
+		;;
+	-q|--q|--qu|--qui|--quie|--quiet)
+		quiet=t
+		shift
+		;;
+	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
+		verbose=t
+		shift
+		;;
+	-u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
+	--untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
+	--untracked-file|--untracked-files)
+		untracked_files=t
+		shift
+		;;
+	--)
+		shift
+		break
+		;;
+	-*)
+		usage
+		;;
+	*)
+		break
+		;;
+	esac
+done
+case "$edit_flag" in t) no_edit= ;; esac
+
+################################################################
+# Sanity check options
+
+case "$amend,$initial_commit" in
+t,t)
+	die "You do not have anything to amend." ;;
+t,)
+	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+		die "You are in the middle of a merge -- cannot amend."
+	fi ;;
+esac
+
+case "$log_given" in
+tt*)
+	die "Only one of -c/-C/-F can be used." ;;
+*tm*|*mt*)
+	die "Option -m cannot be combined with -c/-C/-F." ;;
+esac
+
+case "$#,$also,$only,$amend" in
+*,t,t,*)
+	die "Only one of --include/--only can be used." ;;
+0,t,,* | 0,,t,)
+	die "No paths with --include/--only does not make sense." ;;
+0,,t,t)
+	only_include_assumed="# Clever... amending the last one with dirty index." ;;
+0,,,*)
+	;;
+*,,,*)
+	only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
+	also=
+	;;
+esac
+unset only
+case "$all,$interactive,$also,$#" in
+*t,*t,*)
+	die "Cannot use -a, --interactive or -i at the same time." ;;
+t,,[1-9]*)
+	die "Paths with -a does not make sense." ;;
+,t,[1-9]*)
+	die "Paths with --interactive does not make sense." ;;
+,,t,0)
+	die "No paths with -i does not make sense." ;;
+esac
+
+if test ! -z "$templatefile" -a -z "$log_given"
+then
+	if test ! -f "$templatefile"
+	then
+		die "Commit template file does not exist."
+	fi
+fi
+
+################################################################
+# Prepare index to have a tree to be committed
+
+case "$all,$also" in
+t,)
+	if test ! -f "$THIS_INDEX"
+	then
+		die 'nothing to commit (use "git add file1 file2" to include for commit)'
+	fi
+	save_index &&
+	(
+		cd_to_toplevel &&
+		GIT_INDEX_FILE="$NEXT_INDEX" &&
+		export GIT_INDEX_FILE &&
+		git diff-files --name-only -z |
+		git update-index --remove -z --stdin
+	) || exit
+	;;
+,t)
+	save_index &&
+	git ls-files --error-unmatch -- "$@" >/dev/null || exit
+
+	git diff-files --name-only -z -- "$@"  |
+	(
+		cd_to_toplevel &&
+		GIT_INDEX_FILE="$NEXT_INDEX" &&
+		export GIT_INDEX_FILE &&
+		git update-index --remove -z --stdin
+	) || exit
+	;;
+,)
+	if test "$interactive" = t; then
+		git add --interactive || exit
+	fi
+	case "$#" in
+	0)
+		;; # commit as-is
+	*)
+		if test -f "$GIT_DIR/MERGE_HEAD"
+		then
+			refuse_partial "Cannot do a partial commit during a merge."
+		fi
+		TMP_INDEX="$GIT_DIR/tmp-index$$"
+		commit_only=`git ls-files --error-unmatch -- "$@"` || exit
+
+		# Build a temporary index and update the real index
+		# the same way.
+		if test -z "$initial_commit"
+		then
+			GIT_INDEX_FILE="$THIS_INDEX" \
+			git read-tree --index-output="$TMP_INDEX" -i -m HEAD
+		else
+			rm -f "$TMP_INDEX"
+		fi || exit
+
+		printf '%s\n' "$commit_only" |
+		GIT_INDEX_FILE="$TMP_INDEX" \
+		git update-index --add --remove --stdin &&
+
+		save_index &&
+		printf '%s\n' "$commit_only" |
+		(
+			GIT_INDEX_FILE="$NEXT_INDEX"
+			export GIT_INDEX_FILE
+			git update-index --remove --stdin
+		) || exit
+		;;
+	esac
+	;;
+esac
+
+################################################################
+# If we do as-is commit, the index file will be THIS_INDEX,
+# otherwise NEXT_INDEX after we make this commit.  We leave
+# the index as is if we abort.
+
+if test -f "$NEXT_INDEX"
+then
+	USE_INDEX="$NEXT_INDEX"
+else
+	USE_INDEX="$THIS_INDEX"
+fi
+
+case "$status_only" in
+t)
+	# This will silently fail in a read-only repository, which is
+	# what we want.
+	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
+	run_status
+	exit $?
+	;;
+'')
+	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
+	;;
+esac
+
+################################################################
+# Grab commit message, write out tree and make commit.
+
+if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
+then
+	if test "$TMP_INDEX"
+	then
+		GIT_INDEX_FILE="$TMP_INDEX" "$GIT_DIR"/hooks/pre-commit
+	else
+		GIT_INDEX_FILE="$USE_INDEX" "$GIT_DIR"/hooks/pre-commit
+	fi || exit
+fi
+
+if test "$log_message" != ''
+then
+	printf '%s\n' "$log_message"
+elif test "$logfile" != ""
+then
+	if test "$logfile" = -
+	then
+		test -t 0 &&
+		echo >&2 "(reading log message from standard input)"
+		cat
+	else
+		cat <"$logfile"
+	fi
+elif test "$use_commit" != ""
+then
+	encoding=$(git config i18n.commitencoding || echo UTF-8)
+	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
+	sed -e '1,/^$/d' -e 's/^    //'
+elif test -f "$GIT_DIR/MERGE_MSG"
+then
+	cat "$GIT_DIR/MERGE_MSG"
+elif test -f "$GIT_DIR/SQUASH_MSG"
+then
+	cat "$GIT_DIR/SQUASH_MSG"
+elif test "$templatefile" != ""
+then
+	cat "$templatefile"
+fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
+
+case "$signoff" in
+t)
+	sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
+		s/>.*/>/
+		s/^/Signed-off-by: /
+		')
+	blank_before_signoff=
+	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+	grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
+'
+	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+	grep "$sign"$ >/dev/null ||
+	printf '%s%s\n' "$blank_before_signoff" "$sign" \
+		>>"$GIT_DIR"/COMMIT_EDITMSG
+	;;
+esac
+
+if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
+	echo "#"
+	echo "# It looks like you may be committing a MERGE."
+	echo "# If this is not correct, please remove the file"
+	printf '%s\n' "#	$GIT_DIR/MERGE_HEAD"
+	echo "# and try again"
+	echo "#"
+fi >>"$GIT_DIR"/COMMIT_EDITMSG
+
+# Author
+if test '' != "$use_commit"
+then
+	eval "$(get_author_ident_from_commit "$use_commit")"
+	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
+fi
+if test '' != "$force_author"
+then
+	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
+	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
+	test '' != "$GIT_AUTHOR_NAME" &&
+	test '' != "$GIT_AUTHOR_EMAIL" ||
+	die "malformed --author parameter"
+	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
+fi
+
+PARENTS="-p HEAD"
+if test -z "$initial_commit"
+then
+	rloga='commit'
+	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+		rloga='commit (merge)'
+		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
+	elif test -n "$amend"; then
+		rloga='commit (amend)'
+		PARENTS=$(git cat-file commit HEAD |
+			sed -n -e '/^$/q' -e 's/^parent /-p /p')
+	fi
+	current="$(git rev-parse --verify HEAD)"
+else
+	if [ -z "$(git ls-files)" ]; then
+		echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
+		exit 1
+	fi
+	PARENTS=""
+	rloga='commit (initial)'
+	current=''
+fi
+set_reflog_action "$rloga"
+
+if test -z "$no_edit"
+then
+	{
+		echo ""
+		echo "# Please enter the commit message for your changes."
+		echo "# (Comment lines starting with '#' will not be included)"
+		test -z "$only_include_assumed" || echo "$only_include_assumed"
+		run_status
+	} >>"$GIT_DIR"/COMMIT_EDITMSG
+else
+	# we need to check if there is anything to commit
+	run_status >/dev/null
+fi
+if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" -a -z "$amend" ]
+then
+	rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+	run_status
+	exit 1
+fi
+
+case "$no_edit" in
+'')
+	git-var GIT_AUTHOR_IDENT > /dev/null  || die
+	git-var GIT_COMMITTER_IDENT > /dev/null  || die
+	git_editor "$GIT_DIR/COMMIT_EDITMSG"
+	;;
+esac
+
+case "$verify" in
+t)
+	if test -x "$GIT_DIR"/hooks/commit-msg
+	then
+		"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
+	fi
+esac
+
+if test -z "$no_edit"
+then
+    sed -e '
+        /^diff --git a\/.*/{
+	    s///
+	    q
+	}
+	/^#/d
+    ' "$GIT_DIR"/COMMIT_EDITMSG
+else
+    cat "$GIT_DIR"/COMMIT_EDITMSG
+fi |
+git stripspace >"$GIT_DIR"/COMMIT_MSG
+
+# Test whether the commit message has any content we didn't supply.
+have_commitmsg=
+grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
+	git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
+
+# Is the commit message totally empty?
+if test -s "$GIT_DIR"/COMMIT_BAREMSG
+then
+	if test "$templatefile" != ""
+	then
+		# Test whether this is just the unaltered template.
+		if cnt=`sed -e '/^#/d' < "$templatefile" |
+			git stripspace |
+			diff "$GIT_DIR"/COMMIT_BAREMSG - |
+			wc -l` &&
+		   test 0 -lt $cnt
+		then
+			have_commitmsg=t
+		fi
+	else
+		# No template, so the content in the commit message must
+		# have come from the user.
+		have_commitmsg=t
+	fi
+fi
+
+rm -f "$GIT_DIR"/COMMIT_BAREMSG
+
+if test "$have_commitmsg" = "t"
+then
+	if test -z "$TMP_INDEX"
+	then
+		tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
+	else
+		tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
+		rm -f "$TMP_INDEX"
+	fi &&
+	commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
+	rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
+	git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
+	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
+	if test -f "$NEXT_INDEX"
+	then
+		mv "$NEXT_INDEX" "$THIS_INDEX"
+	else
+		: ;# happy
+	fi
+else
+	echo >&2 "* no commit message?  aborting commit."
+	false
+fi
+ret="$?"
+rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+
+cd_to_toplevel
+
+git rerere
+
+if test "$ret" = 0
+then
+	if test -x "$GIT_DIR"/hooks/post-commit
+	then
+		"$GIT_DIR"/hooks/post-commit
+	fi
+	if test -z "$quiet"
+	then
+		commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
+		       --summary --root HEAD --`
+		echo "Created${initial_commit:+ initial} commit $commit"
+	fi
+fi
+
+exit "$ret"
diff --git a/git-commit.sh b/git-commit.sh
deleted file mode 100755
index d7e7028..0000000
--- a/git-commit.sh
+++ /dev/null
@@ -1,665 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Linus Torvalds
-# Copyright (c) 2006 Junio C Hamano
-
-USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
-SUBDIRECTORY_OK=Yes
-. git-sh-setup
-require_work_tree
-
-git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
-
-case "$0" in
-*status)
-	status_only=t
-	;;
-*commit)
-	status_only=
-	;;
-esac
-
-refuse_partial () {
-	echo >&2 "$1"
-	echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
-	exit 1
-}
-
-THIS_INDEX="$GIT_DIR/index"
-NEXT_INDEX="$GIT_DIR/next-index$$"
-rm -f "$NEXT_INDEX"
-save_index () {
-	cp -p "$THIS_INDEX" "$NEXT_INDEX"
-}
-
-run_status () {
-	# If TMP_INDEX is defined, that means we are doing
-	# "--only" partial commit, and that index file is used
-	# to build the tree for the commit.  Otherwise, if
-	# NEXT_INDEX exists, that is the index file used to
-	# make the commit.  Otherwise we are using as-is commit
-	# so the regular index file is what we use to compare.
-	if test '' != "$TMP_INDEX"
-	then
-		GIT_INDEX_FILE="$TMP_INDEX"
-		export GIT_INDEX_FILE
-	elif test -f "$NEXT_INDEX"
-	then
-		GIT_INDEX_FILE="$NEXT_INDEX"
-		export GIT_INDEX_FILE
-	fi
-
-	case "$status_only" in
-	t) color= ;;
-	*) color=--nocolor ;;
-	esac
-	git runstatus ${color} \
-		${verbose:+--verbose} \
-		${amend:+--amend} \
-		${untracked_files:+--untracked}
-}
-
-trap '
-	test -z "$TMP_INDEX" || {
-		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
-	}
-	rm -f "$NEXT_INDEX"
-' 0
-
-################################################################
-# Command line argument parsing and sanity checking
-
-all=
-also=
-interactive=
-only=
-logfile=
-use_commit=
-amend=
-edit_flag=
-no_edit=
-log_given=
-log_message=
-verify=t
-quiet=
-verbose=
-signoff=
-force_author=
-only_include_assumed=
-untracked_files=
-templatefile="`git config commit.template`"
-while case "$#" in 0) break;; esac
-do
-	case "$1" in
-	-F|--F|-f|--f|--fi|--fil|--file)
-		case "$#" in 1) usage ;; esac
-		shift
-		no_edit=t
-		log_given=t$log_given
-		logfile="$1"
-		shift
-		;;
-	-F*|-f*)
-		no_edit=t
-		log_given=t$log_given
-		logfile=`expr "z$1" : 'z-[Ff]\(.*\)'`
-		shift
-		;;
-	--F=*|--f=*|--fi=*|--fil=*|--file=*)
-		no_edit=t
-		log_given=t$log_given
-		logfile=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		shift
-		;;
-	-a|--a|--al|--all)
-		all=t
-		shift
-		;;
-	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
-		force_author=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		shift
-		;;
-	--au|--aut|--auth|--autho|--author)
-		case "$#" in 1) usage ;; esac
-		shift
-		force_author="$1"
-		shift
-		;;
-	-e|--e|--ed|--edi|--edit)
-		edit_flag=t
-		shift
-		;;
-	-i|--i|--in|--inc|--incl|--inclu|--includ|--include)
-		also=t
-		shift
-		;;
-	--int|--inte|--inter|--intera|--interac|--interact|--interacti|\
-	--interactiv|--interactive)
-		interactive=t
-		shift
-		;;
-	-o|--o|--on|--onl|--only)
-		only=t
-		shift
-		;;
-	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=m$log_given
-		if test "$log_message" = ''
-		then
-		    log_message="$1"
-		else
-		    log_message="$log_message
-
-$1"
-		fi
-		no_edit=t
-		shift
-		;;
-	-m*)
-		log_given=m$log_given
-		if test "$log_message" = ''
-		then
-		    log_message=`expr "z$1" : 'z-m\(.*\)'`
-		else
-		    log_message="$log_message
-
-`expr "z$1" : 'z-m\(.*\)'`"
-		fi
-		no_edit=t
-		shift
-		;;
-	--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
-		log_given=m$log_given
-		if test "$log_message" = ''
-		then
-		    log_message=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		else
-		    log_message="$log_message
-
-`expr "z$1" : 'zq-[^=]*=\(.*\)'`"
-		fi
-		no_edit=t
-		shift
-		;;
-	-n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
-	--no-verify)
-		verify=
-		shift
-		;;
-	--a|--am|--ame|--amen|--amend)
-		amend=t
-		use_commit=HEAD
-		shift
-		;;
-	-c)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		shift
-		;;
-	--ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
-	--reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
-	--reedit-messag=*|--reedit-message=*)
-		log_given=t$log_given
-		use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		no_edit=
-		shift
-		;;
-	--ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
-	--reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
-	--reedit-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		shift
-		;;
-	-C)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		shift
-		;;
-	--reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
-	--reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
-	--reuse-message=*)
-		log_given=t$log_given
-		use_commit=`expr "z$1" : 'z-[^=]*=\(.*\)'`
-		no_edit=t
-		shift
-		;;
-	--reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
-	--reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		shift
-		;;
-	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
-		signoff=t
-		shift
-		;;
-	-t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
-		case "$#" in 1) usage ;; esac
-		shift
-		templatefile="$1"
-		no_edit=
-		shift
-		;;
-	-q|--q|--qu|--qui|--quie|--quiet)
-		quiet=t
-		shift
-		;;
-	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
-		verbose=t
-		shift
-		;;
-	-u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
-	--untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
-	--untracked-file|--untracked-files)
-		untracked_files=t
-		shift
-		;;
-	--)
-		shift
-		break
-		;;
-	-*)
-		usage
-		;;
-	*)
-		break
-		;;
-	esac
-done
-case "$edit_flag" in t) no_edit= ;; esac
-
-################################################################
-# Sanity check options
-
-case "$amend,$initial_commit" in
-t,t)
-	die "You do not have anything to amend." ;;
-t,)
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		die "You are in the middle of a merge -- cannot amend."
-	fi ;;
-esac
-
-case "$log_given" in
-tt*)
-	die "Only one of -c/-C/-F can be used." ;;
-*tm*|*mt*)
-	die "Option -m cannot be combined with -c/-C/-F." ;;
-esac
-
-case "$#,$also,$only,$amend" in
-*,t,t,*)
-	die "Only one of --include/--only can be used." ;;
-0,t,,* | 0,,t,)
-	die "No paths with --include/--only does not make sense." ;;
-0,,t,t)
-	only_include_assumed="# Clever... amending the last one with dirty index." ;;
-0,,,*)
-	;;
-*,,,*)
-	only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
-	also=
-	;;
-esac
-unset only
-case "$all,$interactive,$also,$#" in
-*t,*t,*)
-	die "Cannot use -a, --interactive or -i at the same time." ;;
-t,,[1-9]*)
-	die "Paths with -a does not make sense." ;;
-,t,[1-9]*)
-	die "Paths with --interactive does not make sense." ;;
-,,t,0)
-	die "No paths with -i does not make sense." ;;
-esac
-
-if test ! -z "$templatefile" -a -z "$log_given"
-then
-	if test ! -f "$templatefile"
-	then
-		die "Commit template file does not exist."
-	fi
-fi
-
-################################################################
-# Prepare index to have a tree to be committed
-
-case "$all,$also" in
-t,)
-	if test ! -f "$THIS_INDEX"
-	then
-		die 'nothing to commit (use "git add file1 file2" to include for commit)'
-	fi
-	save_index &&
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git diff-files --name-only -z |
-		git update-index --remove -z --stdin
-	) || exit
-	;;
-,t)
-	save_index &&
-	git ls-files --error-unmatch -- "$@" >/dev/null || exit
-
-	git diff-files --name-only -z -- "$@"  |
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git update-index --remove -z --stdin
-	) || exit
-	;;
-,)
-	if test "$interactive" = t; then
-		git add --interactive || exit
-	fi
-	case "$#" in
-	0)
-		;; # commit as-is
-	*)
-		if test -f "$GIT_DIR/MERGE_HEAD"
-		then
-			refuse_partial "Cannot do a partial commit during a merge."
-		fi
-		TMP_INDEX="$GIT_DIR/tmp-index$$"
-		commit_only=`git ls-files --error-unmatch -- "$@"` || exit
-
-		# Build a temporary index and update the real index
-		# the same way.
-		if test -z "$initial_commit"
-		then
-			GIT_INDEX_FILE="$THIS_INDEX" \
-			git read-tree --index-output="$TMP_INDEX" -i -m HEAD
-		else
-			rm -f "$TMP_INDEX"
-		fi || exit
-
-		printf '%s\n' "$commit_only" |
-		GIT_INDEX_FILE="$TMP_INDEX" \
-		git update-index --add --remove --stdin &&
-
-		save_index &&
-		printf '%s\n' "$commit_only" |
-		(
-			GIT_INDEX_FILE="$NEXT_INDEX"
-			export GIT_INDEX_FILE
-			git update-index --remove --stdin
-		) || exit
-		;;
-	esac
-	;;
-esac
-
-################################################################
-# If we do as-is commit, the index file will be THIS_INDEX,
-# otherwise NEXT_INDEX after we make this commit.  We leave
-# the index as is if we abort.
-
-if test -f "$NEXT_INDEX"
-then
-	USE_INDEX="$NEXT_INDEX"
-else
-	USE_INDEX="$THIS_INDEX"
-fi
-
-case "$status_only" in
-t)
-	# This will silently fail in a read-only repository, which is
-	# what we want.
-	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
-	run_status
-	exit $?
-	;;
-'')
-	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
-	;;
-esac
-
-################################################################
-# Grab commit message, write out tree and make commit.
-
-if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
-then
-	if test "$TMP_INDEX"
-	then
-		GIT_INDEX_FILE="$TMP_INDEX" "$GIT_DIR"/hooks/pre-commit
-	else
-		GIT_INDEX_FILE="$USE_INDEX" "$GIT_DIR"/hooks/pre-commit
-	fi || exit
-fi
-
-if test "$log_message" != ''
-then
-	printf '%s\n' "$log_message"
-elif test "$logfile" != ""
-then
-	if test "$logfile" = -
-	then
-		test -t 0 &&
-		echo >&2 "(reading log message from standard input)"
-		cat
-	else
-		cat <"$logfile"
-	fi
-elif test "$use_commit" != ""
-then
-	encoding=$(git config i18n.commitencoding || echo UTF-8)
-	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
-	sed -e '1,/^$/d' -e 's/^    //'
-elif test -f "$GIT_DIR/MERGE_MSG"
-then
-	cat "$GIT_DIR/MERGE_MSG"
-elif test -f "$GIT_DIR/SQUASH_MSG"
-then
-	cat "$GIT_DIR/SQUASH_MSG"
-elif test "$templatefile" != ""
-then
-	cat "$templatefile"
-fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
-
-case "$signoff" in
-t)
-	sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
-		s/>.*/>/
-		s/^/Signed-off-by: /
-		')
-	blank_before_signoff=
-	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-	grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
-'
-	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-	grep "$sign"$ >/dev/null ||
-	printf '%s%s\n' "$blank_before_signoff" "$sign" \
-		>>"$GIT_DIR"/COMMIT_EDITMSG
-	;;
-esac
-
-if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
-	echo "#"
-	echo "# It looks like you may be committing a MERGE."
-	echo "# If this is not correct, please remove the file"
-	printf '%s\n' "#	$GIT_DIR/MERGE_HEAD"
-	echo "# and try again"
-	echo "#"
-fi >>"$GIT_DIR"/COMMIT_EDITMSG
-
-# Author
-if test '' != "$use_commit"
-then
-	eval "$(get_author_ident_from_commit "$use_commit")"
-	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
-fi
-if test '' != "$force_author"
-then
-	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
-	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
-	test '' != "$GIT_AUTHOR_NAME" &&
-	test '' != "$GIT_AUTHOR_EMAIL" ||
-	die "malformed --author parameter"
-	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
-fi
-
-PARENTS="-p HEAD"
-if test -z "$initial_commit"
-then
-	rloga='commit'
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		rloga='commit (merge)'
-		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
-	elif test -n "$amend"; then
-		rloga='commit (amend)'
-		PARENTS=$(git cat-file commit HEAD |
-			sed -n -e '/^$/q' -e 's/^parent /-p /p')
-	fi
-	current="$(git rev-parse --verify HEAD)"
-else
-	if [ -z "$(git ls-files)" ]; then
-		echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
-		exit 1
-	fi
-	PARENTS=""
-	rloga='commit (initial)'
-	current=''
-fi
-set_reflog_action "$rloga"
-
-if test -z "$no_edit"
-then
-	{
-		echo ""
-		echo "# Please enter the commit message for your changes."
-		echo "# (Comment lines starting with '#' will not be included)"
-		test -z "$only_include_assumed" || echo "$only_include_assumed"
-		run_status
-	} >>"$GIT_DIR"/COMMIT_EDITMSG
-else
-	# we need to check if there is anything to commit
-	run_status >/dev/null
-fi
-if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" -a -z "$amend" ]
-then
-	rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-	run_status
-	exit 1
-fi
-
-case "$no_edit" in
-'')
-	git-var GIT_AUTHOR_IDENT > /dev/null  || die
-	git-var GIT_COMMITTER_IDENT > /dev/null  || die
-	git_editor "$GIT_DIR/COMMIT_EDITMSG"
-	;;
-esac
-
-case "$verify" in
-t)
-	if test -x "$GIT_DIR"/hooks/commit-msg
-	then
-		"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
-	fi
-esac
-
-if test -z "$no_edit"
-then
-    sed -e '
-        /^diff --git a\/.*/{
-	    s///
-	    q
-	}
-	/^#/d
-    ' "$GIT_DIR"/COMMIT_EDITMSG
-else
-    cat "$GIT_DIR"/COMMIT_EDITMSG
-fi |
-git stripspace >"$GIT_DIR"/COMMIT_MSG
-
-# Test whether the commit message has any content we didn't supply.
-have_commitmsg=
-grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
-	git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
-
-# Is the commit message totally empty?
-if test -s "$GIT_DIR"/COMMIT_BAREMSG
-then
-	if test "$templatefile" != ""
-	then
-		# Test whether this is just the unaltered template.
-		if cnt=`sed -e '/^#/d' < "$templatefile" |
-			git stripspace |
-			diff "$GIT_DIR"/COMMIT_BAREMSG - |
-			wc -l` &&
-		   test 0 -lt $cnt
-		then
-			have_commitmsg=t
-		fi
-	else
-		# No template, so the content in the commit message must
-		# have come from the user.
-		have_commitmsg=t
-	fi
-fi
-
-rm -f "$GIT_DIR"/COMMIT_BAREMSG
-
-if test "$have_commitmsg" = "t"
-then
-	if test -z "$TMP_INDEX"
-	then
-		tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
-	else
-		tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
-		rm -f "$TMP_INDEX"
-	fi &&
-	commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
-	rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
-	git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
-	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
-	if test -f "$NEXT_INDEX"
-	then
-		mv "$NEXT_INDEX" "$THIS_INDEX"
-	else
-		: ;# happy
-	fi
-else
-	echo >&2 "* no commit message?  aborting commit."
-	false
-fi
-ret="$?"
-rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-
-cd_to_toplevel
-
-git rerere
-
-if test "$ret" = 0
-then
-	if test -x "$GIT_DIR"/hooks/post-commit
-	then
-		"$GIT_DIR"/hooks/post-commit
-	fi
-	if test -z "$quiet"
-	then
-		commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
-		       --summary --root HEAD --`
-		echo "Created${initial_commit:+ initial} commit $commit"
-	fi
-fi
-
-exit "$ret"
diff --git a/git.c b/git.c
index cab0e72..62859a2 100644
--- a/git.c
+++ b/git.c
@@ -321,6 +321,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
 		{ "cherry", cmd_cherry, RUN_SETUP },
 		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
+		{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
 		{ "config", cmd_config },
 		{ "count-objects", cmd_count_objects, RUN_SETUP },
@@ -363,10 +364,10 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "rev-parse", cmd_rev_parse, RUN_SETUP },
 		{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
 		{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
-		{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
 		{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
 		{ "show-branch", cmd_show_branch, RUN_SETUP },
 		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
+		{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
 		{ "stripspace", cmd_stripspace },
 		{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 		{ "tag", cmd_tag, RUN_SETUP },
-- 
1.5.2.GIT

^ permalink raw reply related	[relevance 2%]

* [ANNOUNCE] GIT 1.5.3.2
@ 2007-09-19 19:01  2% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2007-09-19 19:01 UTC (permalink / raw)
  To: git; +Cc: linux-kernel

The latest maintenance release GIT 1.5.3.2 is available at the
usual places:

  http://www.kernel.org/pub/software/scm/git/

  git-1.5.3.2.tar.{gz,bz2}			(tarball)
  git-htmldocs-1.5.3.2.tar.{gz,bz2}		(preformatted docs)
  git-manpages-1.5.3.2.tar.{gz,bz2}		(preformatted docs)
  RPMS/$arch/git-*-1.5.3.2-1.$arch.rpm	(RPM)


GIT v1.5.3.2 Release Notes
==========================

Fixes since v1.5.3.1
--------------------

 * git-push sent thin packs by default, which was not good for
   the public distribution server (no point in saving transfer
   while pushing; no point in making the resulting pack less
   optimum).

 * git-svn sometimes terminated with "Malformed network data" when
   talking over svn:// protocol.

 * git-send-email re-issued the same message-id about 10% of the
   time if you fired off 30 messages within a single second.

 * git-stash was not terminating the log message of commits it
   internally creates with LF.

 * git-apply failed to check the size of the patch hunk when its
   beginning part matched the remainder of the preimage exactly,
   even though the preimage recorded in the hunk was much larger
   (therefore the patch should not have applied), leading to a
   segfault.

 * "git rm foo && git commit foo" complained that 'foo' needs to
   be added first, instead of committing the removal, which was a
   nonsense.

 * git grep -c said "/dev/null: 0".

 * git-add -u failed to recognize a blob whose type changed
   between the index and the work tree.

 * The limit to rename detection has been tightened a lot to
   reduce performance problems with a huge change.

 * cvsimport and svnimport barfed when the input tried to move
   a tag.

 * "git apply -pN" did not chop the right number of directories.

 * "git svnimport" did not like SVN tags with funny characters in them.

 * git-gui 0.8.3, with assorted fixes, including:

   - font-chooser on X11 was unusable with large number of fonts;
   - a diff that contained a deleted symlink made it barf;
   - an untracked symbolic link to a directory made it fart;
   - a file with % in its name made it vomit;


Documentation updates
---------------------

User manual has been somewhat restructured.  I think the new
organization is much easier to read.


----------------------------------------------------------------

Changes since v1.5.3.1 are as follows:

Alexandre Julliard (1):
      hooks--update: Explicitly check for all zeros for a deleted ref.

Benoit Sigoure (1):
      Add test to check recent fix to "git add -u"

Carlos Rica (1):
      git-tag -s must fail if gpg cannot sign the tag.

David Kastrup (1):
      git-send-email.perl: Add angle brackets to In-Reply-To if necessary

Dmitry V. Levin (2):
      Makefile: Add cache-tree.h to the headers list
      git-commit: Disallow amend if it is going to produce an empty non-merge commit

Eric Wong (3):
      git-svn: fix "Malformed network data" with svn:// servers
      git-svn: understand grafts when doing dcommit
      Documentation/git-svn: updated design philosophy notes

Gerrit Pape (2):
      git-gui: lib/index.tcl: handle files with % in the filename properly
      git-clone: improve error message if curl program is missing or not executable

J. Bruce Fields (13):
      user-manual: adjust section levels in "git internals"
      user-manual: move object format details to hacking-git chapter
      user-manual: rename "git internals" to "git concepts"
      user-manual: create new "low-level git operations" chapter
      user-manual: rewrite index discussion
      user-manual: reorder commit, blob, tree discussion
      user-manual: rewrite object database discussion
      user-manual: move packfile and dangling object discussion
      user-manual: fix introduction to packfiles
      user-manual: todo updates and cleanup
      documentation: replace Discussion section by link to user-manual chapter
      core-tutorial: minor cleanup
      git-apply: fix whitespace stripping

Jari Aalto (1):
      Documentation/git-archive.txt: a couple of clarifications.

Jean-Luc Herren (1):
      stash: end index commit log with a newline

Jeff King (1):
      git-push: documentation and tests for pushing only branches

Johannes Schindelin (2):
      revision walker: --cherry-pick is a limited operation
      apply --index-info: fall back to current index for mode changes

Junio C Hamano (13):
      git-apply: do not read past the end of buffer
      git-add -u: do not barf on type changes
      git-format-patch --in-reply-to: accept <message@id> with angle brackets
      diff --no-index: do not forget to run diff_setup_done()
      Documentation/git-config.txt: AsciiDoc tweak to avoid leading dot
      Split grep arguments in a way that does not requires to add /dev/null.
      git-sh-setup: typofix in comments
      send-email: make message-id generation a bit more robust
      git-commit: Allow partial commit of file removal.
      git-commit: partial commit of paths only removed from the index
      Document ls-files --with-tree=<tree-ish>
      t/t4014: test "am -3" with mode-only change.
      GIT 1.5.3.2

Linus Torvalds (1):
      Fix the rename detection limit checking

Matthias Urlichs (1):
      git-svnimport: Use separate arguments in the pipe for git-rev-parse

Michael Smith (1):
      (cvs|svn)import: Ask git-tag to overwrite old tags.

Michele Ballabio (2):
      git-gui: show unstaged symlinks in diff viewer
      git-gui: handle "deleted symlink" diff marker

Mike Ralphson (1):
      Documentation / grammer nit

Nicolas Pitre (1):
      fix doc for --compression argument to pack-objects

Pierre Habouzit (1):
      Fix lapsus in builtin-apply.c

Ramsay Allan Jones (1):
      Fix a test failure (t9500-*.sh) on cygwin

Shawn O. Pearce (17):
      git-gui: Correct starting of git-remote to handle -w option
      git-gui: Fix detaching current branch during checkout
      git-gui: Properly set the state of "Stage/Unstage Hunk" action
      Don't allow contrib/workdir/git-new-workdir to trash existing dirs
      Cleanup unnecessary file modifications in t1400-update-ref
      Include a git-push example for creating a remote branch
      git-gui: Disable Tk send in all git-gui sessions
      git-gui: Avoid use of libdir in Makefile
      git-gui: Assume untracked directories are Git submodules
      git-gui: Trim trailing slashes from untracked submodule names
      Make --no-thin the default in git-push to save server resources
      git-gui: Don't delete send on Windows as it doesn't exist
      git-gui: Make backporting changes from i18n version easier
      git-gui: Font chooser to handle a large number of font families
      git-gui: Provide 'uninstall' Makefile target to undo an installation
      git-gui: Paper bag fix "Commit->Revert" format arguments
      git-gui: Disable native platform text selection in "lists"

Sven Verdoolaege (1):
      git-diff: don't squelch the new SHA1 in submodule diffs

Ulrik Sverdrup (1):
      Remove duplicate note about removing commits with git-filter-branch

Väinö Järvelä (1):
      Fixed update-hook example allow-users format.

^ permalink raw reply	[relevance 2%]

* [PATCH] user-manual: Explain what submodules are good for.
  @ 2007-09-24  3:14 11% ` Michael Smith
  0 siblings, 0 replies; 200+ results
From: Michael Smith @ 2007-09-24  3:14 UTC (permalink / raw)
  To: git; +Cc: J. Bruce Fields, Miklos Vajna, Michael Smith

Rework the introduction to the Submodules section to explain why
someone would use them, and fix up submodule references from the
tree-object and todo sections.

Signed-off-by: Michael Smith <msmith@cbnco.com>
---
 Documentation/user-manual.txt |   25 ++++++++++++++-----------
 1 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index a085ca1..bd77e62 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -2856,8 +2856,7 @@ between two related tree objects, since it can ignore any entries with
 identical object names.
 
 (Note: in the presence of submodules, trees may also have commits as
-entries.   See gitlink:git-submodule[1] and gitlink:gitmodules.txt[1]
-for partial documentation.)
+entries.  See <<submodules>> for documentation.)
 
 Note that the files all have mode 644 or 755: git actually only pays
 attention to the executable bit.
@@ -3163,12 +3162,18 @@ information as long as you have the name of the tree that it described.
 Submodules
 ==========
 
-This tutorial explains how to create and publish a repository with submodules
-using the gitlink:git-submodule[1] command.
+Some large projects are composed of smaller, self-contained parts.  For
+example, an embedded Linux distribution's source tree would include every
+piece of software in the distribution; a movie player might need to build
+against a specific, known-working version of a decompression library;
+several independent programs might all share the same build scripts.
 
-Submodules maintain their own identity; the submodule support just stores the
-submodule repository location and commit ID, so other developers who clone the
-superproject can easily clone all the submodules at the same revision.
+Git's submodule support allows a repository to contain, as a subdirectory, a
+checkout of an external project.  Submodules maintain their own identity;
+the submodule support just stores the submodule repository location and
+commit ID, so other developers who clone the superproject can easily clone
+all the submodules at the same revision.  The gitlink:git-submodule[1]
+command manages submodules.
 
 To see how submodule support works, create (for example) four example
 repositories that can be used later as a submodule:
@@ -3213,8 +3218,8 @@ The `git submodule add` command does a couple of things:
 
 - It clones the submodule under the current directory and by default checks out
   the master branch.
-- It adds the submodule's clone path to the `.gitmodules` file and adds this
-  file to the index, ready to be committed.
+- It adds the submodule's clone path to the gitlink:gitmodules[5] file and
+  adds this file to the index, ready to be committed.
 - It adds the submodule's current commit ID to the index, ready to be
   committed.
 
@@ -4277,5 +4282,3 @@ Write a chapter on using plumbing and writing scripts.
 Alternates, clone -reference, etc.
 
 git unpack-objects -r for recovery
-
-submodules
-- 
1.5.3

^ permalink raw reply related	[relevance 11%]

* [PATCH] user-manual: Explain what submodules are good for.
  @ 2007-09-25 12:44 14% ` Michael Smith
  2007-09-25 16:09  0%   ` J. Bruce Fields
  0 siblings, 1 reply; 200+ results
From: Michael Smith @ 2007-09-25 12:44 UTC (permalink / raw)
  To: J. Bruce Fields; +Cc: Miklos Vajna, git, Michael Smith

Rework the introduction to the Submodules section to explain why
someone would use them, and fix up submodule references from the
tree-object and todo sections.

Signed-off-by: Michael Smith <msmith@cbnco.com>
---
 Documentation/user-manual.txt |   54 +++++++++++++++++++++++++++++++---------
 1 files changed, 42 insertions(+), 12 deletions(-)

diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index a085ca1..c7fdf25 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -2856,8 +2856,7 @@ between two related tree objects, since it can ignore any entries with
 identical object names.
 
 (Note: in the presence of submodules, trees may also have commits as
-entries.   See gitlink:git-submodule[1] and gitlink:gitmodules.txt[1]
-for partial documentation.)
+entries.  See <<submodules>> for documentation.)
 
 Note that the files all have mode 644 or 755: git actually only pays
 attention to the executable bit.
@@ -3163,12 +3162,45 @@ information as long as you have the name of the tree that it described.
 Submodules
 ==========
 
-This tutorial explains how to create and publish a repository with submodules
-using the gitlink:git-submodule[1] command.
-
-Submodules maintain their own identity; the submodule support just stores the
-submodule repository location and commit ID, so other developers who clone the
-superproject can easily clone all the submodules at the same revision.
+Large projects are often composed of smaller, self-contained modules.  For
+example, an embedded Linux distribution's source tree would include every
+piece of software in the distribution with some local modifications; a movie
+player might need to build against a specific, known-working version of a
+decompression library; several independent programs might all share the same
+build scripts.
+
+With centralized revision control systems this is often accomplished by
+including every module in one single repository.  Developers can check out
+all modules or only the modules they need to work with.  They can even modify
+files across several modules in a single commit while moving things around
+or updating APIs and translations.
+
+Git does not allow partial checkouts, so duplicating this approach in Git
+would force developers to keep a local copy of modules they are not
+interested in touching.  Commits in an enormous checkout would be slower
+than you'd expect as Git would have to scan every directory for changes.
+If modules have a lot of local history, clones would take forever.
+
+On the plus side, distributed revision control systems can much better
+integrate with external sources.  In a centralized model, a single arbitrary
+snapshot of the external project is exported from its own revision control
+and then imported into the local revision control on a vendor branch.  All
+the history is hidden.  With distributed revision control you can clone the
+entire external history and much more easily follow development and re-merge
+local changes.
+
+Git's submodule support allows a repository to contain, as a subdirectory, a
+checkout of an external project.  Submodules maintain their own identity;
+the submodule support just stores the submodule repository location and
+commit ID, so other developers who clone the containing project
+("superproject") can easily clone all the submodules at the same revision.
+Partial checkouts of the superproject are possible: you can tell Git to
+clone none, some or all of the submodules.
+
+The gitlink:git-submodule[1] command is available since Git 1.5.3.  Users
+with Git 1.5.2 can look up the submodule commits in the repository and
+manually check them out; earlier versions won't recognize the submodules at
+all.
 
 To see how submodule support works, create (for example) four example
 repositories that can be used later as a submodule:
@@ -3213,8 +3245,8 @@ The `git submodule add` command does a couple of things:
 
 - It clones the submodule under the current directory and by default checks out
   the master branch.
-- It adds the submodule's clone path to the `.gitmodules` file and adds this
-  file to the index, ready to be committed.
+- It adds the submodule's clone path to the gitlink:gitmodules[5] file and
+  adds this file to the index, ready to be committed.
 - It adds the submodule's current commit ID to the index, ready to be
   committed.
 
@@ -4277,5 +4309,3 @@ Write a chapter on using plumbing and writing scripts.
 Alternates, clone -reference, etc.
 
 git unpack-objects -r for recovery
-
-submodules
-- 
1.5.3

^ permalink raw reply related	[relevance 14%]

* Re: [PATCH] user-manual: Explain what submodules are good for.
  2007-09-25 12:44 14% ` Michael Smith
@ 2007-09-25 16:09  0%   ` J. Bruce Fields
  0 siblings, 0 replies; 200+ results
From: J. Bruce Fields @ 2007-09-25 16:09 UTC (permalink / raw)
  To: Michael Smith; +Cc: Miklos Vajna, git

On Tue, Sep 25, 2007 at 08:44:38AM -0400, Michael Smith wrote:
> Rework the introduction to the Submodules section to explain why
> someone would use them, and fix up submodule references from the
> tree-object and todo sections.

Looks good to me; thanks!

Acked-by: J. Bruce Fields <bfields@citi.umich.edu>

--b.

> Signed-off-by: Michael Smith <msmith@cbnco.com>
> ---
>  Documentation/user-manual.txt |   54 +++++++++++++++++++++++++++++++---------
>  1 files changed, 42 insertions(+), 12 deletions(-)
> 
> diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
> index a085ca1..c7fdf25 100644
> --- a/Documentation/user-manual.txt
> +++ b/Documentation/user-manual.txt
> @@ -2856,8 +2856,7 @@ between two related tree objects, since it can ignore any entries with
>  identical object names.
>  
>  (Note: in the presence of submodules, trees may also have commits as
> -entries.   See gitlink:git-submodule[1] and gitlink:gitmodules.txt[1]
> -for partial documentation.)
> +entries.  See <<submodules>> for documentation.)
>  
>  Note that the files all have mode 644 or 755: git actually only pays
>  attention to the executable bit.
> @@ -3163,12 +3162,45 @@ information as long as you have the name of the tree that it described.
>  Submodules
>  ==========
>  
> -This tutorial explains how to create and publish a repository with submodules
> -using the gitlink:git-submodule[1] command.
> -
> -Submodules maintain their own identity; the submodule support just stores the
> -submodule repository location and commit ID, so other developers who clone the
> -superproject can easily clone all the submodules at the same revision.
> +Large projects are often composed of smaller, self-contained modules.  For
> +example, an embedded Linux distribution's source tree would include every
> +piece of software in the distribution with some local modifications; a movie
> +player might need to build against a specific, known-working version of a
> +decompression library; several independent programs might all share the same
> +build scripts.
> +
> +With centralized revision control systems this is often accomplished by
> +including every module in one single repository.  Developers can check out
> +all modules or only the modules they need to work with.  They can even modify
> +files across several modules in a single commit while moving things around
> +or updating APIs and translations.
> +
> +Git does not allow partial checkouts, so duplicating this approach in Git
> +would force developers to keep a local copy of modules they are not
> +interested in touching.  Commits in an enormous checkout would be slower
> +than you'd expect as Git would have to scan every directory for changes.
> +If modules have a lot of local history, clones would take forever.
> +
> +On the plus side, distributed revision control systems can much better
> +integrate with external sources.  In a centralized model, a single arbitrary
> +snapshot of the external project is exported from its own revision control
> +and then imported into the local revision control on a vendor branch.  All
> +the history is hidden.  With distributed revision control you can clone the
> +entire external history and much more easily follow development and re-merge
> +local changes.
> +
> +Git's submodule support allows a repository to contain, as a subdirectory, a
> +checkout of an external project.  Submodules maintain their own identity;
> +the submodule support just stores the submodule repository location and
> +commit ID, so other developers who clone the containing project
> +("superproject") can easily clone all the submodules at the same revision.
> +Partial checkouts of the superproject are possible: you can tell Git to
> +clone none, some or all of the submodules.
> +
> +The gitlink:git-submodule[1] command is available since Git 1.5.3.  Users
> +with Git 1.5.2 can look up the submodule commits in the repository and
> +manually check them out; earlier versions won't recognize the submodules at
> +all.
>  
>  To see how submodule support works, create (for example) four example
>  repositories that can be used later as a submodule:
> @@ -3213,8 +3245,8 @@ The `git submodule add` command does a couple of things:
>  
>  - It clones the submodule under the current directory and by default checks out
>    the master branch.
> -- It adds the submodule's clone path to the `.gitmodules` file and adds this
> -  file to the index, ready to be committed.
> +- It adds the submodule's clone path to the gitlink:gitmodules[5] file and
> +  adds this file to the index, ready to be committed.
>  - It adds the submodule's current commit ID to the index, ready to be
>    committed.
>  
> @@ -4277,5 +4309,3 @@ Write a chapter on using plumbing and writing scripts.
>  Alternates, clone -reference, etc.
>  
>  git unpack-objects -r for recovery
> -
> -submodules
> -- 
> 1.5.3
> 

^ permalink raw reply	[relevance 0%]

* [PATCH 3/4] Implement git commit as a builtin command.
  @ 2007-09-27  4:50  2%   ` Kristian Høgsberg
  0 siblings, 0 replies; 200+ results
From: Kristian Høgsberg @ 2007-09-27  4:50 UTC (permalink / raw)
  To: gitster; +Cc: git, Kristian Høgsberg

Move git-commit.sh to contrib/examples.

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---
 Makefile                       |    9 +-
 builtin-commit.c               |  611 +++++++++++++++++++++++++++++++++++++++
 builtin-tag.c                  |    3 +-
 builtin.h                      |    3 +-
 contrib/examples/git-commit.sh |  627 ++++++++++++++++++++++++++++++++++++++++
 git-commit.sh                  |  627 ----------------------------------------
 git.c                          |    3 +-
 strbuf.h                       |    1 +
 t/t3501-revert-cherry-pick.sh  |    4 +-
 t/t3901-i18n-patch.sh          |    8 +-
 t/test-lib.sh                  |    4 +-
 11 files changed, 1255 insertions(+), 645 deletions(-)
 create mode 100644 builtin-commit.c
 create mode 100755 contrib/examples/git-commit.sh
 delete mode 100755 git-commit.sh

diff --git a/Makefile b/Makefile
index d90e959..6172589 100644
--- a/Makefile
+++ b/Makefile
@@ -206,7 +206,7 @@ BASIC_LDFLAGS =
 
 SCRIPT_SH = \
 	git-bisect.sh git-checkout.sh \
-	git-clean.sh git-clone.sh git-commit.sh \
+	git-clean.sh git-clone.sh \
 	git-ls-remote.sh \
 	git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
 	git-pull.sh git-rebase.sh git-rebase--interactive.sh \
@@ -254,7 +254,7 @@ EXTRA_PROGRAMS =
 BUILT_INS = \
 	git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
 	git-get-tar-commit-id$X git-init$X git-repo-config$X \
-	git-fsck-objects$X git-cherry-pick$X \
+	git-fsck-objects$X git-cherry-pick$X git-status$X\
 	$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
 
 # what 'all' will build and 'install' will install, in gitexecdir
@@ -324,6 +324,7 @@ BUILTIN_OBJS = \
 	builtin-check-attr.o \
 	builtin-checkout-index.o \
 	builtin-check-ref-format.o \
+	builtin-commit.o \
 	builtin-commit-tree.o \
 	builtin-count-objects.o \
 	builtin-describe.o \
@@ -362,7 +363,6 @@ BUILTIN_OBJS = \
 	builtin-rev-parse.o \
 	builtin-revert.o \
 	builtin-rm.o \
-	builtin-runstatus.o \
 	builtin-shortlog.o \
 	builtin-show-branch.o \
 	builtin-stripspace.o \
@@ -822,9 +822,6 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
 	chmod +x $@+ && \
 	mv $@+ $@
 
-git-status: git-commit
-	$(QUIET_GEN)cp $< $@+ && mv $@+ $@
-
 gitweb/gitweb.cgi: gitweb/gitweb.perl
 	$(QUIET_GEN)$(RM) $@ $@+ && \
 	sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
diff --git a/builtin-commit.c b/builtin-commit.c
new file mode 100644
index 0000000..69e8b19
--- /dev/null
+++ b/builtin-commit.c
@@ -0,0 +1,611 @@
+/*
+ * Builtin "git commit"
+ *
+ * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
+ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
+ */
+
+#include "cache.h"
+#include "cache-tree.h"
+#include "builtin.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "commit.h"
+#include "revision.h"
+#include "wt-status.h"
+#include "run-command.h"
+#include "refs.h"
+#include "log-tree.h"
+#include "strbuf.h"
+#include "utf8.h"
+#include "parse-options.h"
+
+static const char builtin_commit_usage[] =
+	"[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]";
+
+static unsigned char head_sha1[20], merge_head_sha1[20];
+static char *use_message_buffer;
+static const char commit_editmsg[] = "COMMIT_EDITMSG";
+static struct lock_file lock_file;
+
+static char *logfile, *force_author, *message, *template_file;
+static char *edit_message, *use_message;
+static int all, edit_flag, also, interactive, only, no_verify, amend, signoff;
+static int quiet, verbose, untracked_files;
+
+static int no_edit, initial_commit, in_merge;
+const char *only_include_assumed;
+
+static struct option commit_options[] = {
+	{ OPTION_STRING, "file", 'F', (void *) &logfile },
+	{ OPTION_BOOLEAN, "all", 'a', &all },
+	{ OPTION_STRING, "author", 0, (void *) &force_author },
+	{ OPTION_BOOLEAN, "edit", 'e', &edit_flag },
+	{ OPTION_BOOLEAN, "include", 'i', &also },
+	{ OPTION_BOOLEAN, "interactive", 0, &interactive },
+	{ OPTION_BOOLEAN, "only", 'o', &only },
+	{ OPTION_STRING, "message", 'm', &message },
+	{ OPTION_BOOLEAN, "no-verify", 'n', &no_verify },
+	{ OPTION_BOOLEAN, "amend", 0, &amend },
+	{ OPTION_STRING, "reedit-message", 'c', &edit_message },
+	{ OPTION_STRING, "reuse-message", 'C', &use_message },
+	{ OPTION_BOOLEAN, "signoff", 's', &signoff },
+	{ OPTION_BOOLEAN, "quiet", 'q', &quiet },
+	{ OPTION_BOOLEAN, "verbose", 'v', &verbose },
+	{ OPTION_BOOLEAN, "untracked-files", 0, &untracked_files },
+	{ OPTION_STRING, "template", 't', &template_file },
+	{ OPTION_LAST },
+};
+
+static char *
+prepare_index(const char **files, const char *prefix)
+{
+	int fd;
+	struct tree *tree;
+	struct lock_file *next_index_lock;
+
+	fd = hold_locked_index(&lock_file, 1);
+	if (read_cache() < 0)
+		die("index file corrupt");
+
+	if (all) {
+		add_files_to_cache(0, prefix, files);
+		if (write_cache(fd, active_cache, active_nr) || close(fd))
+			die("unable to write new index file");
+		return lock_file.filename;
+	} else if (also) {
+		add_files_to_cache(fd, prefix, files);
+		if (write_cache(fd, active_cache, active_nr) || close(fd))
+			die("unable to write new index file");
+		return lock_file.filename;
+	}
+
+	if (interactive)
+		interactive_add();
+
+	if (*files == NULL) {
+		/* Commit index as-is. */
+		rollback_lock_file(&lock_file);
+		return get_index_file();
+	}
+
+	/*
+	 * FIXME: Warn on unknown files.  Shell script does
+	 *
+	 *   commit_only=`git-ls-files --error-unmatch -- "$@"`
+	 */
+
+	/*
+	 * FIXME: shell script does
+	 *
+	 *   git-read-tree --index-output="$TMP_INDEX" -i -m HEAD
+	 *
+	 * which warns about unmerged files in the index.
+	 */
+
+	/* update the user index file */
+	add_files_to_cache(0, prefix, files);
+	if (write_cache(fd, active_cache, active_nr) || close(fd))
+		die("unable to write new index file");
+
+	if (!initial_commit) {
+		tree = parse_tree_indirect(head_sha1);
+		if (!tree)
+			die("failed to unpack HEAD tree object");
+		if (read_tree(tree, 0, NULL))
+			die("failed to read HEAD tree object");
+	}
+
+	/* Uh oh, abusing lock_file to create a garbage collected file */
+	next_index_lock = xmalloc(sizeof(*next_index_lock));
+	fd = hold_lock_file_for_update(next_index_lock,
+				       git_path("next-index-%d", getpid()), 1);
+	add_files_to_cache(0, prefix, files);
+	if (write_cache(fd, active_cache, active_nr) || close(fd))
+		die("unable to write new index file");
+
+	return next_index_lock->filename;
+}
+
+static int run_status(FILE *fp, const char *index_file)
+{
+	struct wt_status s;
+
+	wt_status_prepare(&s);
+
+	if (amend) {
+		s.amend = 1;
+		s.reference = "HEAD^1";
+	}
+	s.verbose = verbose;
+	s.untracked = untracked_files;
+	s.index_file = index_file;
+	s.fp = fp;
+
+	wt_status_print(&s);
+
+	return s.commitable;
+}
+
+static const char sign_off_header[] = "Signed-off-by: ";
+
+static int prepare_log_message(const char *index_file)
+{
+	struct stat statbuf;
+	int commitable;
+	struct strbuf sb;
+	char *buffer;
+	FILE *fp;
+
+	strbuf_init(&sb, 0);
+	if (message) {
+		strbuf_add(&sb, message, strlen(message));
+	} else if (logfile && !strcmp(logfile, "-")) {
+		if (isatty(0))
+			fprintf(stderr, "(reading log message from standard input)\n");
+		if (strbuf_read(&sb, 0, 0) < 0)
+			die("could not read log from standard input");
+	} else if (logfile) {
+		if (strbuf_read_file(&sb, logfile) < 0)
+			die("could not read log file '%s': %s",
+			    logfile, strerror(errno));
+	} else if (use_message) {
+		buffer = strstr(use_message_buffer, "\n\n");
+		if (!buffer || buffer[2] == '\0')
+			die("commit has empty message");
+		strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
+	} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
+		if (strbuf_read_file(&sb, git_path("MERGE_MSG")) < 0)
+			die("could not read MERGE_MSG: %s", strerror(errno));
+	} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
+		if (strbuf_read_file(&sb, git_path("SQUASH_MSG")) < 0)
+			die("could not read SQUASH_MSG: %s", strerror(errno));
+	} else if (!stat(template_file, &statbuf)) {
+		if (strbuf_read_file(&sb, template_file) < 0)
+			die("could not read %s: %s",
+			    template_file, strerror(errno));
+	}
+
+	fp = fopen(git_path(commit_editmsg), "w");
+	if (fp == NULL)
+		die("could not open %s\n", git_path(commit_editmsg));
+
+	stripspace(&sb, 0);
+	if (fwrite(sb.buf, 1, sb.len, fp) < sb.len)
+		die("could not write commit template: %s\n",
+		    strerror(errno));
+
+	if (signoff) {
+		const char *info, *bol;
+
+		info = git_committer_info(1);
+		strbuf_addch(&sb, '\0');
+		bol = strrchr(sb.buf + sb.len - 1, '\n');
+		if (!bol || prefixcmp(bol, sign_off_header))
+			fprintf(fp, "\n");
+		fprintf(fp, "%s%s\n", sign_off_header, git_committer_info(1));
+	}
+
+	strbuf_release(&sb);
+
+	if (in_merge && !no_edit) {
+		fprintf(fp,
+			"#\n"
+			"# It looks like you may be committing a MERGE.\n"
+			"# If this is not correct, please remove the file\n"
+			"#	%s\n"
+			"# and try again.\n"
+			"#\n",
+			git_path("MERGE_HEAD"));
+	}
+
+	fprintf(fp,
+		"\n"
+		"# Please enter the commit message for your changes.\n"
+		"# (Comment lines starting with '#' will not be included)\n");
+	if (only_include_assumed)
+		fprintf(fp, "# %s\n", only_include_assumed);
+
+	commitable = run_status(fp, index_file);
+
+	fclose(fp);
+
+	return commitable;
+}
+
+/* Find out if the message starting at position 'start' in the strbuf
+ * contains only whitespace and Signed-off-by lines. */
+static int message_is_empty(struct strbuf *sb, int start)
+{
+	struct strbuf tmpl;
+	const char *nl;
+	int eol, i;
+
+	/* See if the template is just a prefix of the message. */
+	strbuf_init(&tmpl, 0);
+	if (template_file && strbuf_read_file(&tmpl, template_file) > 0) {
+		stripspace(&tmpl, 1);
+		if (start + tmpl.len <= sb->len &&
+		    memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0)
+			start += tmpl.len;
+	}
+	strbuf_release(&tmpl);
+
+	/* Check if the rest is just whitespace and Signed-of-by's. */
+	for (i = start; i < sb->len; i++) {
+		nl = memchr(sb->buf + i, '\n', sb->len - i);
+		if (nl)
+			eol = nl - sb->buf;
+		else
+			eol = sb->len;
+
+		if (strlen(sign_off_header) <= eol - i &&
+		    !prefixcmp(sb->buf + i, sign_off_header)) {
+			i = eol;
+			continue;
+		}
+		while (i < eol)
+			if (!isspace(sb->buf[i++]))
+				return 0;
+	}
+
+	return 1;
+}
+
+static void determine_author_info(struct strbuf *sb)
+{
+	char *p, *eol;
+	char *name = NULL, *email = NULL;
+
+	if (use_message) {
+		p = strstr(use_message_buffer, "\nauthor");
+		if (!p)
+			die("invalid commit: %s\n", use_message);
+		p++;
+		eol = strchr(p, '\n');
+		if (!eol)
+			die("invalid commit: %s\n", use_message);
+
+		strbuf_add(sb, p, eol + 1 - p);
+	} else if (force_author) {
+		const char *eoname = strstr(force_author, " <");
+		const char *eomail = strchr(force_author, '>');
+
+		if (!eoname || !eomail)
+			die("malformed --author parameter\n");
+		name = xstrndup(force_author, eoname - force_author);
+		email = xstrndup(eoname + 2, eomail - eoname - 2);
+		strbuf_addf(sb, "author %s\n",
+			    fmt_ident(name, email,
+				      getenv("GIT_AUTHOR_DATE"), 1));
+		free(name);
+		free(email);
+	} else {
+		strbuf_addf(sb, "author %s\n", git_author_info(1));
+	}
+}
+
+static void parse_and_validate_options(const char ***argv)
+{
+	int f = 0;
+
+	(*argv)++;
+	while (parse_options(argv, commit_options, ARRAY_SIZE(commit_options),
+			     builtin_commit_usage))
+		;
+
+	if (logfile || message || use_message)
+		no_edit = 1;
+	if (edit_flag)
+		no_edit = 0;
+
+	if (get_sha1("HEAD", head_sha1))
+		initial_commit = 1;
+
+	if (!get_sha1("MERGE_HEAD", merge_head_sha1))
+		in_merge = 1;
+
+	/* Sanity check options */
+	if (amend && initial_commit)
+		die("You have nothing to amend.");
+	if (amend && in_merge)
+		die("You are in the middle of a merger -- cannot amend.");
+
+	if (use_message)
+		f++;
+	if (edit_message)
+		f++;
+	if (logfile)
+		f++;
+	if (f > 1)
+		die("Only one of -c/-C/-F can be used.");
+	if (message && f > 0)
+		die("Option -m cannot be combined with -c/-C/-F.");
+	if (edit_message)
+		use_message = edit_message;
+	if (amend)
+		use_message = "HEAD";
+	if (use_message) {
+		unsigned char sha1[20];
+		static char utf8[] = "UTF-8";
+		const char *out_enc;
+		char *enc, *end;
+		struct commit *commit;
+
+		if (get_sha1(use_message, sha1))
+			die("could not lookup commit %s", use_message);
+		commit = lookup_commit(sha1);
+		if (!commit || parse_commit(commit))
+			die("could not parse commit %s", use_message);
+
+		enc = strstr(commit->buffer, "\nencoding");
+		if (enc) {
+			end = strchr(enc + 10, '\n');
+			enc = xstrndup(enc + 10, end - (enc + 10));
+		} else {
+			enc = utf8;
+		}
+		out_enc = git_commit_encoding ? git_commit_encoding : utf8;
+
+		use_message_buffer =
+			reencode_string(commit->buffer, out_enc, enc);
+		if (enc != utf8)
+			free(enc);
+	}
+
+	if (also && only)
+		die("Only one of --include/--only can be used.");
+	if (!*argv && (also || (only && !amend)))
+		die("No paths with --include/--only does not make sense.");
+	if (!*argv && only && amend)
+		only_include_assumed = "Clever... amending the last one with dirty index.";
+	if (*argv && !also && !only) {
+		only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
+		also = 0;
+	}
+
+	if (all && interactive)
+		die("Cannot use -a, --interactive or -i at the same time.");
+	else if (all && **argv)
+		die("Paths with -a does not make sense.");
+	else if (interactive && **argv)
+		die("Paths with --interactive does not make sense.");
+}
+
+int cmd_status(int argc, const char **argv, const char *prefix)
+{
+	const char *index_file;
+	int commitable;
+
+	git_config(git_status_config);
+
+	parse_and_validate_options(&argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	commitable = run_status(stdout, index_file);
+
+	rollback_lock_file(&lock_file);
+
+	return commitable ? 0 : 1;
+}
+
+static int run_hook(const char *index_file, const char *name, const char *arg)
+{
+	struct child_process hook;
+	const char *argv[3], *env[2];
+	char index[PATH_MAX];
+
+	argv[0] = git_path("hooks/%s", name);
+	argv[1] = arg;
+	argv[2] = NULL;
+	snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
+	env[0] = index;
+	env[1] = NULL;
+
+	if (access(argv[0], X_OK) < 0)
+		return 0;
+
+	memset(&hook, 0, sizeof(hook));
+	hook.argv = argv;
+	hook.no_stdin = 1;
+	hook.stdout_to_stderr = 1;
+	hook.env = env;
+
+	return run_command(&hook);
+}
+
+static void print_summary(const char *prefix, const unsigned char *sha1)
+{
+	struct rev_info rev;
+	struct commit *commit;
+
+	commit = lookup_commit(sha1);
+	if (!commit)
+		die("couldn't look up newly created commit\n");
+	if (!commit || parse_commit(commit))
+		die("could not parse newly created commit");
+
+	init_revisions(&rev, prefix);
+	setup_revisions(0, NULL, &rev, NULL);
+
+	rev.abbrev = 0;
+	rev.diff = 1;
+	rev.diffopt.output_format =
+		DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
+
+	rev.verbose_header = 1;
+	rev.show_root_diff = 1;
+	rev.commit_format = get_commit_format("format:%h: %s");
+	rev.always_show_header = 1;
+
+	printf("Created %scommit ", initial_commit ? "initial " : "");
+
+	log_tree_commit(&rev, commit);
+}
+
+int git_commit_config(const char *k, const char *v)
+{
+	if (!strcmp(k, "commit.template")) {
+		template_file = xstrdup(v);
+		return 0;
+	}
+
+	return git_status_config(k, v);
+}
+
+static const char commit_utf8_warn[] =
+"Warning: commit message does not conform to UTF-8.\n"
+"You may want to amend it after fixing the message, or set the config\n"
+"variable i18n.commitencoding to the encoding your project uses.\n";
+
+int cmd_commit(int argc, const char **argv, const char *prefix)
+{
+	int header_len, parent_count = 0;
+	struct strbuf sb;
+	const char *index_file, *reflog_msg;
+	char *nl, *header_line;
+	unsigned char commit_sha1[20];
+	struct ref_lock *ref_lock;
+
+	git_config(git_commit_config);
+
+	parse_and_validate_options(&argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	if (run_hook(index_file, "pre-commit", NULL))
+		exit(1);
+
+	if (!prepare_log_message(index_file) && !in_merge) {
+		run_status(stdout, index_file);
+		unlink(commit_editmsg);
+		return 1;
+	}
+
+	strbuf_init(&sb, 0);
+
+	/* Start building up the commit header */
+	read_cache_from(index_file);
+	active_cache_tree = cache_tree();
+	if (cache_tree_update(active_cache_tree,
+			      active_cache, active_nr, 0, 0) < 0)
+		die("Error building trees");
+	strbuf_addf(&sb, "tree %s\n",
+		    sha1_to_hex(active_cache_tree->sha1));
+
+	/* Determine parents */
+	if (initial_commit) {
+		reflog_msg = "commit (initial)";
+		parent_count = 0;
+	} else if (amend) {
+		struct commit_list *c;
+		struct commit *commit;
+
+		reflog_msg = "commit (amend)";
+		commit = lookup_commit(head_sha1);
+		if (!commit || parse_commit(commit))
+			die("could not parse HEAD commit");
+
+		for (c = commit->parents; c; c = c->next)
+			strbuf_addf(&sb, "parent %s\n",
+				      sha1_to_hex(c->item->object.sha1));
+	} else if (in_merge) {
+		struct strbuf m;
+		FILE *fp;
+
+		reflog_msg = "commit (merge)";
+		strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+		strbuf_init(&m, 0);
+		fp = fopen(git_path("MERGE_HEAD"), "r");
+		if (fp == NULL)
+			die("could not open %s for reading: %s",
+			    git_path("MERGE_HEAD"), strerror(errno));
+		while (strbuf_getline(&m, fp, '\n') != EOF)
+			strbuf_addf(&sb, "parent %s\n", m.buf);
+		fclose(fp);
+		strbuf_release(&m);
+	} else {
+		reflog_msg = "commit";
+		strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+	}
+
+	determine_author_info(&sb);
+	strbuf_addf(&sb, "committer %s\n", git_committer_info(1));
+	if (!is_encoding_utf8(git_commit_encoding))
+		strbuf_addf(&sb, "encoding %s\n", git_commit_encoding);
+	strbuf_addch(&sb, '\n');
+
+	/* Get the commit message and validate it */
+	header_len = sb.len;
+	if (!no_edit) {
+		fprintf(stderr, "launching editor, log %s\n", logfile);
+		launch_editor(git_path(commit_editmsg), &sb);
+	}
+	else if (strbuf_read_file(&sb, git_path(commit_editmsg)) < 0)
+		die("could not read commit message\n");
+	if (run_hook(index_file, "commit-msg", commit_editmsg))
+		exit(1);
+	stripspace(&sb, 1);
+	if (sb.len < header_len ||
+	    message_is_empty(&sb, header_len))
+		die("* no commit message?  aborting commit.");
+	strbuf_addch(&sb, '\0');
+	if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf))
+		fprintf(stderr, commit_utf8_warn);
+
+	if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1))
+		die("failed to write commit object");
+
+	ref_lock = lock_any_ref_for_update("HEAD",
+					   initial_commit ? NULL : head_sha1,
+					   0);
+
+	nl = strchr(sb.buf + header_len, '\n');
+	header_line = xstrndup(sb.buf + header_len,
+			       nl - (sb.buf + header_len));
+	strbuf_release(&sb);
+	strbuf_addf(&sb, "%s: %s\n", reflog_msg, header_line);
+	strbuf_addch(&sb, '\0');
+	free(header_line);
+
+	if (!ref_lock)
+		die("cannot lock HEAD ref");
+	if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0)
+		die("cannot update HEAD ref");
+
+	unlink(git_path("MERGE_HEAD"));
+	unlink(git_path("MERGE_MSG"));
+
+	if (lock_file.filename[0] && commit_locked_index(&lock_file))
+		die("failed to write new index");
+
+	rerere();
+
+	run_hook(index_file, "post-commit", NULL);
+
+	if (!quiet)
+		print_summary(prefix, commit_sha1);
+
+	return 0;
+}
diff --git a/builtin-tag.c b/builtin-tag.c
index a1a2cf0..0a36a5d 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -17,12 +17,11 @@ static const char builtin_tag_usage[] =
 
 static char signingkey[1000];
 
-static void launch_editor(const char *path, struct strbuf *buffer)
+void launch_editor(const char *path, struct strbuf *buffer)
 {
 	const char *editor, *terminal;
 	struct child_process child;
 	const char *args[3];
-	int fd;
 
 	editor = getenv("GIT_EDITOR");
 	if (!editor && editor_program)
diff --git a/builtin.h b/builtin.h
index 65cc0fb..470a788 100644
--- a/builtin.h
+++ b/builtin.h
@@ -23,6 +23,7 @@ extern int cmd_check_attr(int argc, const char **argv, const char *prefix);
 extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
+extern int cmd_commit(int argc, const char **argv, const char *prefix);
 extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_describe(int argc, const char **argv, const char *prefix);
@@ -67,10 +68,10 @@ extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
 extern int cmd_revert(int argc, const char **argv, const char *prefix);
 extern int cmd_rm(int argc, const char **argv, const char *prefix);
-extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
 extern int cmd_shortlog(int argc, const char **argv, const char *prefix);
 extern int cmd_show(int argc, const char **argv, const char *prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
+extern int cmd_status(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
 extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_tag(int argc, const char **argv, const char *prefix);
diff --git a/contrib/examples/git-commit.sh b/contrib/examples/git-commit.sh
new file mode 100755
index 0000000..44ccc44
--- /dev/null
+++ b/contrib/examples/git-commit.sh
@@ -0,0 +1,627 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Linus Torvalds
+# Copyright (c) 2006 Junio C Hamano
+
+USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
+SUBDIRECTORY_OK=Yes
+. git-sh-setup
+require_work_tree
+
+git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
+
+case "$0" in
+*status)
+	status_only=t
+	;;
+*commit)
+	status_only=
+	;;
+esac
+
+refuse_partial () {
+	echo >&2 "$1"
+	echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
+	exit 1
+}
+
+THIS_INDEX="$GIT_DIR/index"
+NEXT_INDEX="$GIT_DIR/next-index$$"
+rm -f "$NEXT_INDEX"
+save_index () {
+	cp -p "$THIS_INDEX" "$NEXT_INDEX"
+}
+
+run_status () {
+	# If TMP_INDEX is defined, that means we are doing
+	# "--only" partial commit, and that index file is used
+	# to build the tree for the commit.  Otherwise, if
+	# NEXT_INDEX exists, that is the index file used to
+	# make the commit.  Otherwise we are using as-is commit
+	# so the regular index file is what we use to compare.
+	if test '' != "$TMP_INDEX"
+	then
+		GIT_INDEX_FILE="$TMP_INDEX"
+		export GIT_INDEX_FILE
+	elif test -f "$NEXT_INDEX"
+	then
+		GIT_INDEX_FILE="$NEXT_INDEX"
+		export GIT_INDEX_FILE
+	fi
+
+	if test "$status_only" = "t" -o "$use_status_color" = "t"; then
+		color=
+	else
+		color=--nocolor
+	fi
+	git runstatus ${color} \
+		${verbose:+--verbose} \
+		${amend:+--amend} \
+		${untracked_files:+--untracked}
+}
+
+trap '
+	test -z "$TMP_INDEX" || {
+		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
+	}
+	rm -f "$NEXT_INDEX"
+' 0
+
+################################################################
+# Command line argument parsing and sanity checking
+
+all=
+also=
+interactive=
+only=
+logfile=
+use_commit=
+amend=
+edit_flag=
+no_edit=
+log_given=
+log_message=
+verify=t
+quiet=
+verbose=
+signoff=
+force_author=
+only_include_assumed=
+untracked_files=
+templatefile="`git config commit.template`"
+while test $# != 0
+do
+	case "$1" in
+	-F|--F|-f|--f|--fi|--fil|--file)
+		case "$#" in 1) usage ;; esac
+		shift
+		no_edit=t
+		log_given=t$log_given
+		logfile="$1"
+		;;
+	-F*|-f*)
+		no_edit=t
+		log_given=t$log_given
+		logfile="${1#-[Ff]}"
+		;;
+	--F=*|--f=*|--fi=*|--fil=*|--file=*)
+		no_edit=t
+		log_given=t$log_given
+		logfile="${1#*=}"
+		;;
+	-a|--a|--al|--all)
+		all=t
+		;;
+	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
+		force_author="${1#*=}"
+		;;
+	--au|--aut|--auth|--autho|--author)
+		case "$#" in 1) usage ;; esac
+		shift
+		force_author="$1"
+		;;
+	-e|--e|--ed|--edi|--edit)
+		edit_flag=t
+		;;
+	-i|--i|--in|--inc|--incl|--inclu|--includ|--include)
+		also=t
+		;;
+	--int|--inte|--inter|--intera|--interac|--interact|--interacti|\
+	--interactiv|--interactive)
+		interactive=t
+		;;
+	-o|--o|--on|--onl|--only)
+		only=t
+		;;
+	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=m$log_given
+		log_message="${log_message:+${log_message}
+
+}$1"
+		no_edit=t
+		;;
+	-m*)
+		log_given=m$log_given
+		log_message="${log_message:+${log_message}
+
+}${1#-m}"
+		no_edit=t
+		;;
+	--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
+		log_given=m$log_given
+		log_message="${log_message:+${log_message}
+
+}${1#*=}"
+		no_edit=t
+		;;
+	-n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
+	--no-verify)
+		verify=
+		;;
+	--a|--am|--ame|--amen|--amend)
+		amend=t
+		use_commit=HEAD
+		;;
+	-c)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=
+		;;
+	--ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
+	--reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
+	--reedit-messag=*|--reedit-message=*)
+		log_given=t$log_given
+		use_commit="${1#*=}"
+		no_edit=
+		;;
+	--ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
+	--reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
+	--reedit-message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=
+		;;
+	-C)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=t
+		;;
+	--reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
+	--reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
+	--reuse-message=*)
+		log_given=t$log_given
+		use_commit="${1#*=}"
+		no_edit=t
+		;;
+	--reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
+	--reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=t
+		;;
+	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
+		signoff=t
+		;;
+	-t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
+		case "$#" in 1) usage ;; esac
+		shift
+		templatefile="$1"
+		no_edit=
+		;;
+	-q|--q|--qu|--qui|--quie|--quiet)
+		quiet=t
+		;;
+	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
+		verbose=t
+		;;
+	-u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
+	--untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
+	--untracked-file|--untracked-files)
+		untracked_files=t
+		;;
+	--)
+		shift
+		break
+		;;
+	-*)
+		usage
+		;;
+	*)
+		break
+		;;
+	esac
+	shift
+done
+case "$edit_flag" in t) no_edit= ;; esac
+
+################################################################
+# Sanity check options
+
+case "$amend,$initial_commit" in
+t,t)
+	die "You do not have anything to amend." ;;
+t,)
+	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+		die "You are in the middle of a merge -- cannot amend."
+	fi ;;
+esac
+
+case "$log_given" in
+tt*)
+	die "Only one of -c/-C/-F can be used." ;;
+*tm*|*mt*)
+	die "Option -m cannot be combined with -c/-C/-F." ;;
+esac
+
+case "$#,$also,$only,$amend" in
+*,t,t,*)
+	die "Only one of --include/--only can be used." ;;
+0,t,,* | 0,,t,)
+	die "No paths with --include/--only does not make sense." ;;
+0,,t,t)
+	only_include_assumed="# Clever... amending the last one with dirty index." ;;
+0,,,*)
+	;;
+*,,,*)
+	only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
+	also=
+	;;
+esac
+unset only
+case "$all,$interactive,$also,$#" in
+*t,*t,*)
+	die "Cannot use -a, --interactive or -i at the same time." ;;
+t,,[1-9]*)
+	die "Paths with -a does not make sense." ;;
+,t,[1-9]*)
+	die "Paths with --interactive does not make sense." ;;
+,,t,0)
+	die "No paths with -i does not make sense." ;;
+esac
+
+if test ! -z "$templatefile" -a -z "$log_given"
+then
+	if test ! -f "$templatefile"
+	then
+		die "Commit template file does not exist."
+	fi
+fi
+
+################################################################
+# Prepare index to have a tree to be committed
+
+case "$all,$also" in
+t,)
+	if test ! -f "$THIS_INDEX"
+	then
+		die 'nothing to commit (use "git add file1 file2" to include for commit)'
+	fi
+	save_index &&
+	(
+		cd_to_toplevel &&
+		GIT_INDEX_FILE="$NEXT_INDEX" &&
+		export GIT_INDEX_FILE &&
+		git diff-files --name-only -z |
+		git update-index --remove -z --stdin
+	) || exit
+	;;
+,t)
+	save_index &&
+	git ls-files --error-unmatch -- "$@" >/dev/null || exit
+
+	git diff-files --name-only -z -- "$@"  |
+	(
+		cd_to_toplevel &&
+		GIT_INDEX_FILE="$NEXT_INDEX" &&
+		export GIT_INDEX_FILE &&
+		git update-index --remove -z --stdin
+	) || exit
+	;;
+,)
+	if test "$interactive" = t; then
+		git add --interactive || exit
+	fi
+	case "$#" in
+	0)
+		;; # commit as-is
+	*)
+		if test -f "$GIT_DIR/MERGE_HEAD"
+		then
+			refuse_partial "Cannot do a partial commit during a merge."
+		fi
+
+		TMP_INDEX="$GIT_DIR/tmp-index$$"
+		W=
+		test -z "$initial_commit" && W=--with-tree=HEAD
+		commit_only=`git ls-files --error-unmatch $W -- "$@"` || exit
+
+		# Build a temporary index and update the real index
+		# the same way.
+		if test -z "$initial_commit"
+		then
+			GIT_INDEX_FILE="$THIS_INDEX" \
+			git read-tree --index-output="$TMP_INDEX" -i -m HEAD
+		else
+			rm -f "$TMP_INDEX"
+		fi || exit
+
+		printf '%s\n' "$commit_only" |
+		GIT_INDEX_FILE="$TMP_INDEX" \
+		git update-index --add --remove --stdin &&
+
+		save_index &&
+		printf '%s\n' "$commit_only" |
+		(
+			GIT_INDEX_FILE="$NEXT_INDEX"
+			export GIT_INDEX_FILE
+			git update-index --add --remove --stdin
+		) || exit
+		;;
+	esac
+	;;
+esac
+
+################################################################
+# If we do as-is commit, the index file will be THIS_INDEX,
+# otherwise NEXT_INDEX after we make this commit.  We leave
+# the index as is if we abort.
+
+if test -f "$NEXT_INDEX"
+then
+	USE_INDEX="$NEXT_INDEX"
+else
+	USE_INDEX="$THIS_INDEX"
+fi
+
+case "$status_only" in
+t)
+	# This will silently fail in a read-only repository, which is
+	# what we want.
+	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
+	run_status
+	exit $?
+	;;
+'')
+	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
+	;;
+esac
+
+################################################################
+# Grab commit message, write out tree and make commit.
+
+if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
+then
+    GIT_INDEX_FILE="${TMP_INDEX:-${USE_INDEX}}" "$GIT_DIR"/hooks/pre-commit \
+    || exit
+fi
+
+if test "$log_message" != ''
+then
+	printf '%s\n' "$log_message"
+elif test "$logfile" != ""
+then
+	if test "$logfile" = -
+	then
+		test -t 0 &&
+		echo >&2 "(reading log message from standard input)"
+		cat
+	else
+		cat <"$logfile"
+	fi
+elif test "$use_commit" != ""
+then
+	encoding=$(git config i18n.commitencoding || echo UTF-8)
+	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
+	sed -e '1,/^$/d' -e 's/^    //'
+elif test -f "$GIT_DIR/MERGE_MSG"
+then
+	cat "$GIT_DIR/MERGE_MSG"
+elif test -f "$GIT_DIR/SQUASH_MSG"
+then
+	cat "$GIT_DIR/SQUASH_MSG"
+elif test "$templatefile" != ""
+then
+	cat "$templatefile"
+fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
+
+case "$signoff" in
+t)
+	sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
+		s/>.*/>/
+		s/^/Signed-off-by: /
+		')
+	blank_before_signoff=
+	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+	grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
+'
+	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+	grep "$sign"$ >/dev/null ||
+	printf '%s%s\n' "$blank_before_signoff" "$sign" \
+		>>"$GIT_DIR"/COMMIT_EDITMSG
+	;;
+esac
+
+if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
+	echo "#"
+	echo "# It looks like you may be committing a MERGE."
+	echo "# If this is not correct, please remove the file"
+	printf '%s\n' "#	$GIT_DIR/MERGE_HEAD"
+	echo "# and try again"
+	echo "#"
+fi >>"$GIT_DIR"/COMMIT_EDITMSG
+
+# Author
+if test '' != "$use_commit"
+then
+	eval "$(get_author_ident_from_commit "$use_commit")"
+	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
+fi
+if test '' != "$force_author"
+then
+	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
+	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
+	test '' != "$GIT_AUTHOR_NAME" &&
+	test '' != "$GIT_AUTHOR_EMAIL" ||
+	die "malformed --author parameter"
+	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
+fi
+
+PARENTS="-p HEAD"
+if test -z "$initial_commit"
+then
+	rloga='commit'
+	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+		rloga='commit (merge)'
+		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
+	elif test -n "$amend"; then
+		rloga='commit (amend)'
+		PARENTS=$(git cat-file commit HEAD |
+			sed -n -e '/^$/q' -e 's/^parent /-p /p')
+	fi
+	current="$(git rev-parse --verify HEAD)"
+else
+	if [ -z "$(git ls-files)" ]; then
+		echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
+		exit 1
+	fi
+	PARENTS=""
+	rloga='commit (initial)'
+	current=''
+fi
+set_reflog_action "$rloga"
+
+if test -z "$no_edit"
+then
+	{
+		echo ""
+		echo "# Please enter the commit message for your changes."
+		echo "# (Comment lines starting with '#' will not be included)"
+		test -z "$only_include_assumed" || echo "$only_include_assumed"
+		run_status
+	} >>"$GIT_DIR"/COMMIT_EDITMSG
+else
+	# we need to check if there is anything to commit
+	run_status >/dev/null
+fi
+if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ]
+then
+	rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+	use_status_color=t
+	run_status
+	exit 1
+fi
+
+case "$no_edit" in
+'')
+	git-var GIT_AUTHOR_IDENT > /dev/null  || die
+	git-var GIT_COMMITTER_IDENT > /dev/null  || die
+	git_editor "$GIT_DIR/COMMIT_EDITMSG"
+	;;
+esac
+
+case "$verify" in
+t)
+	if test -x "$GIT_DIR"/hooks/commit-msg
+	then
+		"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
+	fi
+esac
+
+if test -z "$no_edit"
+then
+    sed -e '
+        /^diff --git a\/.*/{
+	    s///
+	    q
+	}
+	/^#/d
+    ' "$GIT_DIR"/COMMIT_EDITMSG
+else
+    cat "$GIT_DIR"/COMMIT_EDITMSG
+fi |
+git stripspace >"$GIT_DIR"/COMMIT_MSG
+
+# Test whether the commit message has any content we didn't supply.
+have_commitmsg=
+grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
+	git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
+
+# Is the commit message totally empty?
+if test -s "$GIT_DIR"/COMMIT_BAREMSG
+then
+	if test "$templatefile" != ""
+	then
+		# Test whether this is just the unaltered template.
+		if cnt=`sed -e '/^#/d' < "$templatefile" |
+			git stripspace |
+			diff "$GIT_DIR"/COMMIT_BAREMSG - |
+			wc -l` &&
+		   test 0 -lt $cnt
+		then
+			have_commitmsg=t
+		fi
+	else
+		# No template, so the content in the commit message must
+		# have come from the user.
+		have_commitmsg=t
+	fi
+fi
+
+rm -f "$GIT_DIR"/COMMIT_BAREMSG
+
+if test "$have_commitmsg" = "t"
+then
+	if test -z "$TMP_INDEX"
+	then
+		tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
+	else
+		tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
+		rm -f "$TMP_INDEX"
+	fi &&
+	commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
+	rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
+	git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
+	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
+	if test -f "$NEXT_INDEX"
+	then
+		mv "$NEXT_INDEX" "$THIS_INDEX"
+	else
+		: ;# happy
+	fi
+else
+	echo >&2 "* no commit message?  aborting commit."
+	false
+fi
+ret="$?"
+rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+
+cd_to_toplevel
+
+git rerere
+
+if test "$ret" = 0
+then
+	git gc --auto
+	if test -x "$GIT_DIR"/hooks/post-commit
+	then
+		"$GIT_DIR"/hooks/post-commit
+	fi
+	if test -z "$quiet"
+	then
+		commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
+		       --summary --root HEAD --`
+		echo "Created${initial_commit:+ initial} commit $commit"
+	fi
+fi
+
+exit "$ret"
diff --git a/git-commit.sh b/git-commit.sh
deleted file mode 100755
index 44ccc44..0000000
--- a/git-commit.sh
+++ /dev/null
@@ -1,627 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Linus Torvalds
-# Copyright (c) 2006 Junio C Hamano
-
-USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
-SUBDIRECTORY_OK=Yes
-. git-sh-setup
-require_work_tree
-
-git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
-
-case "$0" in
-*status)
-	status_only=t
-	;;
-*commit)
-	status_only=
-	;;
-esac
-
-refuse_partial () {
-	echo >&2 "$1"
-	echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
-	exit 1
-}
-
-THIS_INDEX="$GIT_DIR/index"
-NEXT_INDEX="$GIT_DIR/next-index$$"
-rm -f "$NEXT_INDEX"
-save_index () {
-	cp -p "$THIS_INDEX" "$NEXT_INDEX"
-}
-
-run_status () {
-	# If TMP_INDEX is defined, that means we are doing
-	# "--only" partial commit, and that index file is used
-	# to build the tree for the commit.  Otherwise, if
-	# NEXT_INDEX exists, that is the index file used to
-	# make the commit.  Otherwise we are using as-is commit
-	# so the regular index file is what we use to compare.
-	if test '' != "$TMP_INDEX"
-	then
-		GIT_INDEX_FILE="$TMP_INDEX"
-		export GIT_INDEX_FILE
-	elif test -f "$NEXT_INDEX"
-	then
-		GIT_INDEX_FILE="$NEXT_INDEX"
-		export GIT_INDEX_FILE
-	fi
-
-	if test "$status_only" = "t" -o "$use_status_color" = "t"; then
-		color=
-	else
-		color=--nocolor
-	fi
-	git runstatus ${color} \
-		${verbose:+--verbose} \
-		${amend:+--amend} \
-		${untracked_files:+--untracked}
-}
-
-trap '
-	test -z "$TMP_INDEX" || {
-		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
-	}
-	rm -f "$NEXT_INDEX"
-' 0
-
-################################################################
-# Command line argument parsing and sanity checking
-
-all=
-also=
-interactive=
-only=
-logfile=
-use_commit=
-amend=
-edit_flag=
-no_edit=
-log_given=
-log_message=
-verify=t
-quiet=
-verbose=
-signoff=
-force_author=
-only_include_assumed=
-untracked_files=
-templatefile="`git config commit.template`"
-while test $# != 0
-do
-	case "$1" in
-	-F|--F|-f|--f|--fi|--fil|--file)
-		case "$#" in 1) usage ;; esac
-		shift
-		no_edit=t
-		log_given=t$log_given
-		logfile="$1"
-		;;
-	-F*|-f*)
-		no_edit=t
-		log_given=t$log_given
-		logfile="${1#-[Ff]}"
-		;;
-	--F=*|--f=*|--fi=*|--fil=*|--file=*)
-		no_edit=t
-		log_given=t$log_given
-		logfile="${1#*=}"
-		;;
-	-a|--a|--al|--all)
-		all=t
-		;;
-	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
-		force_author="${1#*=}"
-		;;
-	--au|--aut|--auth|--autho|--author)
-		case "$#" in 1) usage ;; esac
-		shift
-		force_author="$1"
-		;;
-	-e|--e|--ed|--edi|--edit)
-		edit_flag=t
-		;;
-	-i|--i|--in|--inc|--incl|--inclu|--includ|--include)
-		also=t
-		;;
-	--int|--inte|--inter|--intera|--interac|--interact|--interacti|\
-	--interactiv|--interactive)
-		interactive=t
-		;;
-	-o|--o|--on|--onl|--only)
-		only=t
-		;;
-	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=m$log_given
-		log_message="${log_message:+${log_message}
-
-}$1"
-		no_edit=t
-		;;
-	-m*)
-		log_given=m$log_given
-		log_message="${log_message:+${log_message}
-
-}${1#-m}"
-		no_edit=t
-		;;
-	--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
-		log_given=m$log_given
-		log_message="${log_message:+${log_message}
-
-}${1#*=}"
-		no_edit=t
-		;;
-	-n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
-	--no-verify)
-		verify=
-		;;
-	--a|--am|--ame|--amen|--amend)
-		amend=t
-		use_commit=HEAD
-		;;
-	-c)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		;;
-	--ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
-	--reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
-	--reedit-messag=*|--reedit-message=*)
-		log_given=t$log_given
-		use_commit="${1#*=}"
-		no_edit=
-		;;
-	--ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
-	--reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
-	--reedit-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		;;
-	-C)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		;;
-	--reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
-	--reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
-	--reuse-message=*)
-		log_given=t$log_given
-		use_commit="${1#*=}"
-		no_edit=t
-		;;
-	--reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
-	--reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		;;
-	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
-		signoff=t
-		;;
-	-t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
-		case "$#" in 1) usage ;; esac
-		shift
-		templatefile="$1"
-		no_edit=
-		;;
-	-q|--q|--qu|--qui|--quie|--quiet)
-		quiet=t
-		;;
-	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
-		verbose=t
-		;;
-	-u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
-	--untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
-	--untracked-file|--untracked-files)
-		untracked_files=t
-		;;
-	--)
-		shift
-		break
-		;;
-	-*)
-		usage
-		;;
-	*)
-		break
-		;;
-	esac
-	shift
-done
-case "$edit_flag" in t) no_edit= ;; esac
-
-################################################################
-# Sanity check options
-
-case "$amend,$initial_commit" in
-t,t)
-	die "You do not have anything to amend." ;;
-t,)
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		die "You are in the middle of a merge -- cannot amend."
-	fi ;;
-esac
-
-case "$log_given" in
-tt*)
-	die "Only one of -c/-C/-F can be used." ;;
-*tm*|*mt*)
-	die "Option -m cannot be combined with -c/-C/-F." ;;
-esac
-
-case "$#,$also,$only,$amend" in
-*,t,t,*)
-	die "Only one of --include/--only can be used." ;;
-0,t,,* | 0,,t,)
-	die "No paths with --include/--only does not make sense." ;;
-0,,t,t)
-	only_include_assumed="# Clever... amending the last one with dirty index." ;;
-0,,,*)
-	;;
-*,,,*)
-	only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
-	also=
-	;;
-esac
-unset only
-case "$all,$interactive,$also,$#" in
-*t,*t,*)
-	die "Cannot use -a, --interactive or -i at the same time." ;;
-t,,[1-9]*)
-	die "Paths with -a does not make sense." ;;
-,t,[1-9]*)
-	die "Paths with --interactive does not make sense." ;;
-,,t,0)
-	die "No paths with -i does not make sense." ;;
-esac
-
-if test ! -z "$templatefile" -a -z "$log_given"
-then
-	if test ! -f "$templatefile"
-	then
-		die "Commit template file does not exist."
-	fi
-fi
-
-################################################################
-# Prepare index to have a tree to be committed
-
-case "$all,$also" in
-t,)
-	if test ! -f "$THIS_INDEX"
-	then
-		die 'nothing to commit (use "git add file1 file2" to include for commit)'
-	fi
-	save_index &&
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git diff-files --name-only -z |
-		git update-index --remove -z --stdin
-	) || exit
-	;;
-,t)
-	save_index &&
-	git ls-files --error-unmatch -- "$@" >/dev/null || exit
-
-	git diff-files --name-only -z -- "$@"  |
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git update-index --remove -z --stdin
-	) || exit
-	;;
-,)
-	if test "$interactive" = t; then
-		git add --interactive || exit
-	fi
-	case "$#" in
-	0)
-		;; # commit as-is
-	*)
-		if test -f "$GIT_DIR/MERGE_HEAD"
-		then
-			refuse_partial "Cannot do a partial commit during a merge."
-		fi
-
-		TMP_INDEX="$GIT_DIR/tmp-index$$"
-		W=
-		test -z "$initial_commit" && W=--with-tree=HEAD
-		commit_only=`git ls-files --error-unmatch $W -- "$@"` || exit
-
-		# Build a temporary index and update the real index
-		# the same way.
-		if test -z "$initial_commit"
-		then
-			GIT_INDEX_FILE="$THIS_INDEX" \
-			git read-tree --index-output="$TMP_INDEX" -i -m HEAD
-		else
-			rm -f "$TMP_INDEX"
-		fi || exit
-
-		printf '%s\n' "$commit_only" |
-		GIT_INDEX_FILE="$TMP_INDEX" \
-		git update-index --add --remove --stdin &&
-
-		save_index &&
-		printf '%s\n' "$commit_only" |
-		(
-			GIT_INDEX_FILE="$NEXT_INDEX"
-			export GIT_INDEX_FILE
-			git update-index --add --remove --stdin
-		) || exit
-		;;
-	esac
-	;;
-esac
-
-################################################################
-# If we do as-is commit, the index file will be THIS_INDEX,
-# otherwise NEXT_INDEX after we make this commit.  We leave
-# the index as is if we abort.
-
-if test -f "$NEXT_INDEX"
-then
-	USE_INDEX="$NEXT_INDEX"
-else
-	USE_INDEX="$THIS_INDEX"
-fi
-
-case "$status_only" in
-t)
-	# This will silently fail in a read-only repository, which is
-	# what we want.
-	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
-	run_status
-	exit $?
-	;;
-'')
-	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
-	;;
-esac
-
-################################################################
-# Grab commit message, write out tree and make commit.
-
-if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
-then
-    GIT_INDEX_FILE="${TMP_INDEX:-${USE_INDEX}}" "$GIT_DIR"/hooks/pre-commit \
-    || exit
-fi
-
-if test "$log_message" != ''
-then
-	printf '%s\n' "$log_message"
-elif test "$logfile" != ""
-then
-	if test "$logfile" = -
-	then
-		test -t 0 &&
-		echo >&2 "(reading log message from standard input)"
-		cat
-	else
-		cat <"$logfile"
-	fi
-elif test "$use_commit" != ""
-then
-	encoding=$(git config i18n.commitencoding || echo UTF-8)
-	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
-	sed -e '1,/^$/d' -e 's/^    //'
-elif test -f "$GIT_DIR/MERGE_MSG"
-then
-	cat "$GIT_DIR/MERGE_MSG"
-elif test -f "$GIT_DIR/SQUASH_MSG"
-then
-	cat "$GIT_DIR/SQUASH_MSG"
-elif test "$templatefile" != ""
-then
-	cat "$templatefile"
-fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
-
-case "$signoff" in
-t)
-	sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
-		s/>.*/>/
-		s/^/Signed-off-by: /
-		')
-	blank_before_signoff=
-	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-	grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
-'
-	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-	grep "$sign"$ >/dev/null ||
-	printf '%s%s\n' "$blank_before_signoff" "$sign" \
-		>>"$GIT_DIR"/COMMIT_EDITMSG
-	;;
-esac
-
-if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
-	echo "#"
-	echo "# It looks like you may be committing a MERGE."
-	echo "# If this is not correct, please remove the file"
-	printf '%s\n' "#	$GIT_DIR/MERGE_HEAD"
-	echo "# and try again"
-	echo "#"
-fi >>"$GIT_DIR"/COMMIT_EDITMSG
-
-# Author
-if test '' != "$use_commit"
-then
-	eval "$(get_author_ident_from_commit "$use_commit")"
-	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
-fi
-if test '' != "$force_author"
-then
-	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
-	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
-	test '' != "$GIT_AUTHOR_NAME" &&
-	test '' != "$GIT_AUTHOR_EMAIL" ||
-	die "malformed --author parameter"
-	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
-fi
-
-PARENTS="-p HEAD"
-if test -z "$initial_commit"
-then
-	rloga='commit'
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		rloga='commit (merge)'
-		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
-	elif test -n "$amend"; then
-		rloga='commit (amend)'
-		PARENTS=$(git cat-file commit HEAD |
-			sed -n -e '/^$/q' -e 's/^parent /-p /p')
-	fi
-	current="$(git rev-parse --verify HEAD)"
-else
-	if [ -z "$(git ls-files)" ]; then
-		echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
-		exit 1
-	fi
-	PARENTS=""
-	rloga='commit (initial)'
-	current=''
-fi
-set_reflog_action "$rloga"
-
-if test -z "$no_edit"
-then
-	{
-		echo ""
-		echo "# Please enter the commit message for your changes."
-		echo "# (Comment lines starting with '#' will not be included)"
-		test -z "$only_include_assumed" || echo "$only_include_assumed"
-		run_status
-	} >>"$GIT_DIR"/COMMIT_EDITMSG
-else
-	# we need to check if there is anything to commit
-	run_status >/dev/null
-fi
-if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ]
-then
-	rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-	use_status_color=t
-	run_status
-	exit 1
-fi
-
-case "$no_edit" in
-'')
-	git-var GIT_AUTHOR_IDENT > /dev/null  || die
-	git-var GIT_COMMITTER_IDENT > /dev/null  || die
-	git_editor "$GIT_DIR/COMMIT_EDITMSG"
-	;;
-esac
-
-case "$verify" in
-t)
-	if test -x "$GIT_DIR"/hooks/commit-msg
-	then
-		"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
-	fi
-esac
-
-if test -z "$no_edit"
-then
-    sed -e '
-        /^diff --git a\/.*/{
-	    s///
-	    q
-	}
-	/^#/d
-    ' "$GIT_DIR"/COMMIT_EDITMSG
-else
-    cat "$GIT_DIR"/COMMIT_EDITMSG
-fi |
-git stripspace >"$GIT_DIR"/COMMIT_MSG
-
-# Test whether the commit message has any content we didn't supply.
-have_commitmsg=
-grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
-	git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
-
-# Is the commit message totally empty?
-if test -s "$GIT_DIR"/COMMIT_BAREMSG
-then
-	if test "$templatefile" != ""
-	then
-		# Test whether this is just the unaltered template.
-		if cnt=`sed -e '/^#/d' < "$templatefile" |
-			git stripspace |
-			diff "$GIT_DIR"/COMMIT_BAREMSG - |
-			wc -l` &&
-		   test 0 -lt $cnt
-		then
-			have_commitmsg=t
-		fi
-	else
-		# No template, so the content in the commit message must
-		# have come from the user.
-		have_commitmsg=t
-	fi
-fi
-
-rm -f "$GIT_DIR"/COMMIT_BAREMSG
-
-if test "$have_commitmsg" = "t"
-then
-	if test -z "$TMP_INDEX"
-	then
-		tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
-	else
-		tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
-		rm -f "$TMP_INDEX"
-	fi &&
-	commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
-	rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
-	git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
-	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
-	if test -f "$NEXT_INDEX"
-	then
-		mv "$NEXT_INDEX" "$THIS_INDEX"
-	else
-		: ;# happy
-	fi
-else
-	echo >&2 "* no commit message?  aborting commit."
-	false
-fi
-ret="$?"
-rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-
-cd_to_toplevel
-
-git rerere
-
-if test "$ret" = 0
-then
-	git gc --auto
-	if test -x "$GIT_DIR"/hooks/post-commit
-	then
-		"$GIT_DIR"/hooks/post-commit
-	fi
-	if test -z "$quiet"
-	then
-		commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
-		       --summary --root HEAD --`
-		echo "Created${initial_commit:+ initial} commit $commit"
-	fi
-fi
-
-exit "$ret"
diff --git a/git.c b/git.c
index d7c6bca..9565555 100644
--- a/git.c
+++ b/git.c
@@ -320,6 +320,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
 		{ "cherry", cmd_cherry, RUN_SETUP },
 		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
+		{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
 		{ "config", cmd_config },
 		{ "count-objects", cmd_count_objects, RUN_SETUP },
@@ -368,10 +369,10 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "rev-parse", cmd_rev_parse, RUN_SETUP },
 		{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
 		{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
-		{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
 		{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
 		{ "show-branch", cmd_show_branch, RUN_SETUP },
 		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
+		{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
 		{ "stripspace", cmd_stripspace },
 		{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 		{ "tag", cmd_tag, RUN_SETUP },
diff --git a/strbuf.h b/strbuf.h
index 5657e3d..eef4e6d 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -113,5 +113,6 @@ extern int strbuf_read_file(struct strbuf *sb, const char *path);
 extern int strbuf_getline(struct strbuf *, FILE *, int);
 
 extern void stripspace(struct strbuf *buf, int skip_comments);
+extern void launch_editor(const char *path, struct strbuf *buffer);
 
 #endif /* STRBUF_H */
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 552af1c..2dbe04f 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -44,7 +44,7 @@ test_expect_success setup '
 test_expect_success 'cherry-pick after renaming branch' '
 
 	git checkout rename2 &&
-	EDITOR=: VISUAL=: git cherry-pick added &&
+	git cherry-pick added &&
 	test -f opos &&
 	grep "Add extra line at the end" opos
 
@@ -53,7 +53,7 @@ test_expect_success 'cherry-pick after renaming branch' '
 test_expect_success 'revert after renaming branch' '
 
 	git checkout rename1 &&
-	EDITOR=: VISUAL=: git revert added &&
+	git revert added &&
 	test -f spoo &&
 	! grep "Add extra line at the end" spoo
 
diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 28e9e37..235f372 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -154,7 +154,7 @@ test_expect_success 'cherry-pick(U/U)' '
 	git reset --hard master &&
 	git cherry-pick side^ &&
 	git cherry-pick side &&
-	EDITOR=: VISUAL=: git revert HEAD &&
+	git revert HEAD &&
 
 	check_encoding 3
 '
@@ -169,7 +169,7 @@ test_expect_success 'cherry-pick(L/L)' '
 	git reset --hard master &&
 	git cherry-pick side^ &&
 	git cherry-pick side &&
-	EDITOR=: VISUAL=: git revert HEAD &&
+	git revert HEAD &&
 
 	check_encoding 3 8859
 '
@@ -184,7 +184,7 @@ test_expect_success 'cherry-pick(U/L)' '
 	git reset --hard master &&
 	git cherry-pick side^ &&
 	git cherry-pick side &&
-	EDITOR=: VISUAL=: git revert HEAD &&
+	git revert HEAD &&
 
 	check_encoding 3
 '
@@ -200,7 +200,7 @@ test_expect_success 'cherry-pick(L/U)' '
 	git reset --hard master &&
 	git cherry-pick side^ &&
 	git cherry-pick side &&
-	EDITOR=: VISUAL=: git revert HEAD &&
+	git revert HEAD &&
 
 	check_encoding 3 8859
 '
diff --git a/t/test-lib.sh b/t/test-lib.sh
index cc1253c..a232bd6 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -9,8 +9,8 @@ LC_ALL=C
 PAGER=cat
 TZ=UTC
 export LANG LC_ALL PAGER TZ
-EDITOR=:
-VISUAL=:
+EDITOR=/bin/true
+VISUAL=/bin/true
 unset GIT_EDITOR
 unset AUTHOR_DATE
 unset AUTHOR_EMAIL
-- 
1.5.2.GIT

^ permalink raw reply related	[relevance 2%]

* Git User's Survey 2007 unfinished summary (long)
@ 2007-10-04  9:12  2% Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2007-10-04  9:12 UTC (permalink / raw)
  To: git

This is partial summary of Git User's Survey 2007,
ending at state from 28 September 2007.

The survey can be found here:
  http://www.survey.net.nz/survey.php?94e135ff41e871a1ea5bcda3ee1856d9
  http://tinyurl.com/26774s

----
There were 683 individual responses

About you
~~~~~~~~~

01. What country are you in?

  Answer                         | Count
  ------------------------------------------
  Algeria                        | 1
  Argentina                      | 3
  Australia                      | 25
  Austria                        | 9
  Belgium                        | 5
  Brazil                         | 20
  Bulgaria                       | 1
  Canada                         | 44
  Chile                          | 2
  China                          | 4
  Colombia                       | 2
  Czech Republic                 | 10
  Denmark                        | 7
  Ecuador                        | 1
  Estonia                        | 1
  European Union                 | 1
  Finland                        | 23
  France                         | 36
  Germany                        | 64
  Greece                         | 3
  Hungary                        | 2
  India                          | 13
  Ireland                        | 2
  Israel                         | 6
  Italy                          | 14
  Japan                          | 4
  Jersey                         | 1
  Latvia                         | 1
  Malaysia                       | 1
  Mexico                         | 1
  Netherlands                    | 15
  New Zealand                    | 5
  Norway                         | 14
  Philippines                    | 3
  Poland                         | 6
  Portugal                       | 2
  Puerto Rico                    | 1
  Romania                        | 1
  Russian Federation             | 6
  Samoa                          | 1
  Serbia                         | 1
  Singapore                      | 2
  Slovak Republic                | 1
  Slovenia                       | 2
  South Africa                   | 4
  Spain                          | 11
  Sri Lanka                      | 1
  Sweden                         | 14
  Switzerland                    | 15
  UK / US                        | 1
  United Kingdom                 | 40
  United States of America       | 218
  Venezuela                      | 1
  Vietnam                        | 1
  ------------------------------------------
  Base                           | 673 / 683
  Total (sum)                    | 673

England and Scotland counts as United Kingdom here.
Table is sorted in alphabetical order.

As one can easily see, slightly less than third of GIT users
are in the USA (those who answered this survey).


02. What is your preferred non-programming language?

This is multiple answers question, although most people
gave only one preferred language.

  Answer                         | Count
  ------------------------------------------
  Afrikaans                      | 1
  Bulgarian                      | 1
  Castellano                     | 2
  Catalan                        | 1
  Chinese                        | 2
  Czech                          | 10
  Danish                         | 6
  Dutch                          | 12
  English                        | 416
  Finnish                        | 16
  French                         | 33
  Galician                       | 1
  German                         | 58
  Greek                          | 2
  Hebrew                         | 1
  HibernoEnglish                 | 1
  Hungarian                      | 3
  Italian                        | 9
  Japanese                       | 1
  LSF (French sign language)     | 1
  Norwegian                      | 4
  Polish                         | 5
  Portuguese                     | 11
  Romanian                       | 1
  Russian                        | 13
  Serbian                        | 1
  Slovenian                      | 2
  Spanish                        | 13
  Swedish                        | 13
  Swiss                          | 1
  Ukrainian                      | 1
  Vietnamese                     | 1
  ------------------------------------------
  invalid (computer language)    | 37
  not understood                 | 4
  ------------------------------------------
  Base                           | 662 / 683
  Total (sum)                    | 684

The question itself is not well formulated, as one can see from the
number of answers with computer language, and "not understood"
answers.  I am not native English speaker, but there were suggestions
to use "natural language" instead of "non-programming language".

Around two third of git users prefer English language, at least for
dealing with computers.


03. How old are you?

  Answer                         | Count
  ------------------------------------------
   < 18                          | 11
  18-21                          | 75
  22-25                          | 174
  26-30                          | 203
  31-40                          | 146
  41-50                          | 45
  51-75                          | 13
  76+                            | 0
  ------------------------------------------
  Base                           | 667 / 683
  Total (sum)                    | 667

Youngest git user who answered this survey is 14 years old,
oldest is 74 years old. This is quite a span, I'd say,  The age of 25
got most count (51 answers).


04. Which programming languages you are proficient with?

  Answer                         | Count
  ------------------------------------------
  C                              | 582
  shell                          | 449
  Perl                           | 244
  Python                         | 316
  Tcl/Tk                         | 26
  ------------------------------------------
  Base                           | 648 / 683
  Total (sum)                    | 1617

The choices include programming languages used by git.  This is
multiple choice question (you can be proficient in more than one
programming language).

It look like there is only around 3/4 people proficient in Perl as
compared to Python; it looks like Python is more popular. C is most
popular; shell is more popular than Perl or Python.  The fewest people
are proficient in Tcl/Tk. I'm sorry, git-gui and gitk guys; it looks
like not many developers... around 4% of git users.


Getting started with GIT
~~~~~~~~~~~~~~~~~~~~~~~~

05. How did you hear about GIT?

  Answer                         | Count
  ------------------------------------------
  LKML                           | 109
  LWN (Linux Weekly News)        | 39
  KernelTrap                     | 15
  KernelTraffic                  | 1
  kernel.org                     | 9
  freedesktop.org                | 5
  Linus presentation at Google   | 48
  Slashdot                       | 28
  blog                           | 19
  community site[*1*]            | 12
  news site                      | 34

  searching Internet[*2*]        | 6
  other SCM / SCM research[*3*]  | 20
  Internet                       | 32
  IRC                            | 6

  Linux kernel uses it           | 73
  some project uses git          | 47

  developer by name[*4*]         | 21
  friend                         | 39
  word of mouth                  | 15
  work / coworker                | 22

  initial GIT announcement       | 12
  BitKeeper news                 | 24
  ------------------------------------------
  don't remember                 | 13
  other / uncategorized          | 44
  ------------------------------------------
  Base                           | 658 / 683
  Total (sum)                    | 693

[*1*] Community site are sites like Digg, Reddit and "planet" sites.
[*2*] This includes answer of "Google"
[*3*] This includes some other SCM mailing list, VCS comparison,
      and searching for an SCM.
[*4*] Linus Torvalds, Carl Worth, Keith Packard, Randal Schwartz,...

This was free-form question, and tabularizing answers was quite a work.
It is taken as multiple choice question (for example link to Linus
presentation at Google found at Slashdot).

Other / uncategorized includes for example GoogleTalk IM, 3 answers
IIRC.

Note that Linus Torvalds presentation at Google / YouTube got it's
own category, and generated quite a bit of git users.


06. Did you find GIT easy to learn?

  Answer                         | Count
  ------------------------------------------
  very easy                      | 38
  easy                           | 136
  reasonably                     | 318
  hard                           | 131
  very hard                      | 33
  ------------------------------------------
  Base                           | 656 / 683
  Total (sum)                    | 656

Nice gaussian curve. Most users find it reasonably easy to use.
On the other hand git is not considered easy...


07. What helped you most in learning to use it?

  TO DO
  646 / 683 non-empty responses


08. What did you find hardest?

  TO DO
  596 / 683 non-empty responses


09. When did you start using git? From which version?

  Answer                         | Count
  ------------------------------------------
  (no version string)            | 165
  0.99x                          | 26
  0.x                            | 12
  1.0x                           | 31
  1.1x                           | 9
  1.2x                           | 12
  1.3x                           | 22
  1.4x                           | 147
  1.5x                           | 198
  ------------------------------------------
  Base                           | 626 / 683
  Total (sum)                    | 626

NOTE! This table shows _only_ answers in which there was given git
version explicitely. Some people gave date, some people wrote how long
they have used git. Those answers needs also processing; they are
skipped here.

It looks like the git users community is divided into part of users
who started using it from beginning, or almost from beginning, and
users which started using git post v1.3.0 (post e.g. making separate
remotes the default layout of branches).


Other SCMs
~~~~~~~~~~

10. What other SCMs did/do you use?

This question is not well thought, as it gathers together (in the
free-form which is not easy to tabularize with large number of
responses we got) SCMs which one used and no longer uses, SCMs which
are used in parallel with git, and SCMs which are used instead of git
(which are chosen as main SCM for a project). Nevertheless it shows
with which VCS, and its conceps, are users familiar with.

  Answer                         | Count
  ------------------------------------------
  AccuRev                        | 3
  Aegis                          | 1
  Bazaar                         | 19
  Bazaar-NG                      | 50
  BitKeeper                      | 27
  CCC                            | 1
  CMS (Digital)                  | 1
  CMS (VAX)                      | 1
  CMS (VMS)                      | 1
  CVCS                           | 1
  CVS                            | 454
  ClearCase                      | 43
  CodeMgr                        | 1
  Continuus                      | 1
  Darcs                          | 78
  DesignSync                     | 1
  GNU Arch                       | 57
  Mercurial                      | 92
  Monotone                       | 31
  Omniworks                      | 1
  OpenCM                         | 1
  PRCS                           | 1
  PVCS                           | 12
  Perforce                       | 50
  Quilt                          | 2
  RCS                            | 61
  SCCS                           | 18
  SCM                            | 1
  SCSS                           | 1
  SVK                            | 19
  Serena Version Manager         | 1
  SourceForge                    | 1
  Sourcerer's Apprentice         | 1
  StarTeam                       | 4
  Subversion                     | 524
  Sun NSE                        | 2
  Sun TeamWare                   | 4
  VCS                            | 1
  VMS                            | 1
  VSS                            | 26
  'cp -a'                        | 1
  akpm patch scripts             | 1
  custom in-house tools          | 1
  diff patch                     | 2
  none                           | 9
  notes-on-paper-made-by-hand    | 1
  really horrible stuff          | 1
  scripts for 'shadow trees'     | 1
  tarballs                       | 1
  tlib                           | 1
  undisclosed                    | 1
  ------------------------------------------
  Base                           | 654 / 683
  Total (sum)                    | 1615

The above table is in alphabetical order. It was generated from
free-form answers, tabularized as multiple choice answer.

Note that this question does not distinguish between SCMs/VCSs which
were used prior to Git and used no longer, SCMs which are used beside
(in parallel) to Git perhaps interacting with Git, and SCMs which are
used instead of Git. Also note that this is _Git User's_ survey, so it
those number for example do not represent number of e.g. users of
Mercurial as compared to e.g. users of Subversion.

Below there is table of SCM used, sorted by the number of responses.
Note that annotations (like "a little CVS") were not weighted here.
Only SCMs which has count more that 10 are shown. One person can (and
usually did) chose more than one SCM.

  Answer                         | Count
  ------------------------------------------
  Subversion                     | 524
  CVS                            | 454
  Mercurial                      | 92
  Darcs                          | 78
  RCS                            | 61
  GNU Arch                       | 57
  Bazaar-NG                      | 50
  Perforce                       | 50
  ClearCase                      | 43
  Monotone                       | 31
  BitKeeper                      | 27
  VSS (MS Visual SourceSafe)     | 26
  Bazaar                         | 19
  SVK                            | 19
  SCCS                           | 18
  PVCS                           | 12

  tla+baz+bzr                    | 129
  ------------------------------------------
  Base                           | 654 / 683

As you can see two most popular SCMs are Subversion ('svn') and CVS,
with Subversion being a bit more popular. Among distributed SCMs
with most count are Mercurial ('hg') and Arch and its descendants
('tla', 'baz', 'bzr'). From proprietary (non-OSS) revision control
systems Perforce ('p4'), ClearCase (and ClearCase UCM), BitKeeper ('bk')
and Visual SourceSafe (aka. that awful M$ one ;-) got most count.

Note that the count for given version control system does not reflect
_preferences_ of git users. One can be forced to use specified SCM.

See also question 35: "How does GIT compare to other SCM?".


11. Why did you choose GIT?

  TO DO
  643 / 683 non-empty responses


12. Why did you choose other SCMs?

  TO DO
  606 / 683 non-empty responses


13. What would you require from GIT to enable you to change,
    if you use other SCM for your project?

  TO DO
  474 / 683 non-empty responses


14. Did you import your repository from foreign SCM? What SCM?

  Answer                         | Count
  ------------------------------------------
  N/A                            | 15
  No                             | 169
  Yes                            | 372
  ------------------------------------------
  Base                           | 556 / 683
  Total (sum)                    | 556

This is anly partial analysis, as it deals only with first part of
question (which, because of second part, has free-form structure and
needed processing).

One can see that around half of git users have imported (at least one
project) from foreign SCM.


15. What tool did you use for import?

  Answer                         | Count
  ------------------------------------------
  by hand                        | 7
  custom script                  | 21
  fast-import script             | 3

  Tailor                         | 28
  -------------------------------------------
  git-cvsimport                  | 81
  parsecvs                       | 12
  fromcvs                        | 2
  cvs2git                        | 1
  cvstogit                       | 1

  git-svn                        | 150
  git-svnimport                  | 66

  git-archimport                 | 15
  bk2git (customized)            | 1
  darcs2git                      | 4
  git-p4                         | 4
  git-p4import                   | 1
  git-ucmimport                  | 1
  hg-to-git                      | 2
  hg2git                         | 2
  hgpullsvn                      | 1
  hgsvn                          | 1
  moin2git                       | 1
  ------------------------------------------
  unspecified                    | 18
  N/A                            | 114
  ------------------------------------------
  Base                           | 467 / 683
  Total (sum)                    | 538


16. Do your GIT repository interact with other SCM? Which SCM?

  Answer                         | Count
  ------------------------------------------
  N/A                            | 35
  No                             | 228
  Yes                            | 228
  ------------------------------------------
  Base                           | 491 / 683
  Total (sum)                    | 491

This is anly partial analysis, as it deals only with first part of
question (which, because of second part, has free-form structure and
needed processing).

One can see that around third of git users interacts (for at least one
project) with foreign SCM, as compared to half of git users which have
imported other SCM.


17. What tool did/do you use to interact?

  Answer                         | Count
  ------------------------------------------
  by hand                        | 10
  custom script                  | 16

  Tailor                         | 4
  convert-repo                   | 1

  fromcvs                        | 1
  git-cvsexportcommit            | 8
  git-cvsimport                  | 19
  git-cvsserver                  | 2

  git-svn                        | 164
  git-svnimport                  | 2

  git-p4                         | 4
  git-p4import                   | 1
  -----------------------------------------
  unspecified                    | 2
  N/A                            | 153
  ------------------------------------------
  Base                           | 385 / 683
  Total (sum)                    | 388

The only tool which really allows to interact (two-way) with other SCM
is git-svn (164 / 232).


How you use GIT
~~~~~~~~~~~~~~~

18. Do you use GIT for work, unpaid projects, or both?

  Answer                         | Count
  ------------------------------------------
  work                           | 56
  unpaid projects                | 212
  both                           | 377

  work + both                    | 433
  ------------------------------------------
  Base                           | 645 / 683
  Total (sum)                    | 645

Around two third of people use git at work, or for work.

See also question 55: "Would commerical (paid) support from a support
vendor be of interest to you/your organization?"


19. How do you obtain GIT?

  Answer                         | Count
  ------------------------------------------
  binary package                 | 283
  source tarball                 | 210
  pull from main repository      | 153
  ------------------------------------------
  Base                           | 646 / 683
  Total (sum)                    | 646

Around half more people use binary packages than source tarball (or
source package, I think). More than half of people compile its own git
(pull is also followed by compilation).

In earlier partial survey summary, from 27-08-2004 (a month earlier)
there were twice as many people installing git from binary packages.


20. What hardware platforms do you use GIT on?
    (on Unices: result of "uname -i")

Note: 'uname -i' does not work on all Unices. I'm sorry for this
mistake.

  Answer                         | Count
  ------------------------------------------
  Intel                          | 73
  Athlon                         | 2
  i386                           | 171
  i586                           | 9
  i686                           | 60
  IA-32                          | 6
  IA-64                          | 8
  AMD                            | 35
  amd64                          | 48
  x86                            | 156
  x86-64                         | 112

  Apple                          | 8
  iMac                           | 1
  MacBook                        | 7
  PowerBook                      | 10
  PPC                            | 52
  ppc64                          | 7

  ARM                            | 6
  Alpha                          | 2
  PA-RISC                        | 1
  parisc64                       | 1
  MIPS                           | 1
  mips64                         | 1
  mipsel                         | 2
  SPARC                          | 8
  sparc64                        | 6
  SUNW                           | 6
  Sun-Fire                       | 4
  sun4u                          | 3
  sun4v                          | 1
  k8                             | 1
  ------------------------------------------
  unknown                        | 67
  ------------------------------------------
  Base                           | 637 / 683
  Total (sum)                    | 875

The above table is in some arbitrary order. It was generated from
free-form answers, tabularized as multiple choice answer, as one
person can use git on more than one architecture.

Those results probably needs further processing to reduce number of
choices, by gathering architectures.

"Unknown" usually means that something else instead of architecture
was given (like operating system), or architecture was too generic,
like "PC".


21. What OS (please include the version) do you use GIT on?

  Answer                         | Count
  ------------------------------------------
  AIX                            | 1
  FreeBSD                        | 16
  OpenBSD                        | 3
  HP-UX                          | 1
  Linux                          | 582
  MS Windows (Cygwin)            | 22
  MS Windows (msys)              | 1
  MS Windows (unsp.)             | 35
  MacOS X / Darwin               | 94
  Solaris                        | 11
  SunOS                          | 5
  UNIX (unsp.)                   | 1
  too many to list               | 1
  ------------------------------------------
  MS Windows (together)          | 58
  FreeBSD / OpenBSD              | 19
  Unices (together)              | 19
  ------------------------------------------
  Base                           | 645 / 683
  Total (sum)                    | 775

The above was generated from free-form answers, tabularized as
multiple choice answer, as one person can use git on more than one
operating system.

This is only rough analysis, because it does not include operating
system version, or for Linux distribution(s) used.


22. What projects do you track (or download) using GIT (or git web interface)?

  TO TABULARIZE
  560 / 683 non-empty responses


23. How many people do you collaborate with using GIT?

  TO TABULARIZE
  575 / 683 non-empty responses

What ranges should be used here: 1, 2-9, 10-99, 100-999, 1000+ or
perhaps 1, 2-5, 6-15, 16-25, 26-50, 50-100, 100-1000, 1000+, or yet
another?


24. How big are the repositories that you work on?

  TO DO
  525 / 683 non-empty responses

Some git repositories have more than 50k files, more than 150k
commits, more than 100mb largest file (although not single directory
has all those).


25. How many different projects do you manage using GIT?

  TO TABULARIZE
  577 / 683 non-empty responses


26. Which porcelains do you use?

Multiple answers (one can use more than one porcelain).

  Answer (multiple choice)       | Count
  ------------------------------------------
  core-git                       | 558
  cogito (deprecated)            | 56

  Patch management interface:    : 57
  ...........................................
  StGIT                          | 41
  Guilt (formerly gq)            | 13
  pg (deprecated)                | 3

  own scripts                    | 95
  other                          | 14
  ------------------------------------------
  Base                           | 593 / 683
  Total (sum)                    | 780

Those 14 "other" answers make me wish to have provided "if other,
what it was?" (sub)question; actually not only for this question.


It is understandable that Cogito still has some users, even though it is
deprecated, and [I think] all of its functionality can be found in
git-core porcelain. It was meant as SCM / porcelain layer when git-core
didn't have it and consisted almost only of plumbing commands.

Quite a bit of people use patch management interface: StGIT, Guilt,
even deprecated and abandoned pg (Patchy Git). StGIT has more users
than Guilt (formerly gq), although that might be caused by the fact
that StGIT was here longer... Some say that it is because of Guilt
having non-standalone documentation; it needs reading hgbook, as Guilt
concepts are based on mq (Mercurial [patch] queues) extension.

Large number of users use their own scripts, more than any
non-standard porcelain. One wonders if this is a result of good
git scriptability.

14 users choose other... and there is no "what other" question,
unfortunately...

If you are reading this: what were those other porcelains?


27. Which git GUI do you use?

Multiple answers (one can use more than one GUI). Note that for the
first week and a bit of survey "CLI" answer had no explanation that it
means command line interface, so results might be bit skewed.

  Answer (multiple choice)       | Count
  ------------------------------------------
  CLI (command line)             | 398
  gitk                           | 347
  git-gui                        | 123
  qgit                           | 82
  gitview                        | 15
  giggle                         | 48
  tig                            | 41
  instaweb                       | 16
  (h)gct                         | 3
  qct                            | 3
  KGit                           | 6
  git.el                         | 31
  other                          | 15

  giggle + gitview               | 63
  ------------------------------------------
  Base                           | 572 / 683
  Total (sum)                    | 1128

As one can see almost as many people use gitk as CLI. Most used GUI
are gitk and git-gui, most probably because they are distributed with
git, and because they are portable. QGit is also quite popular,
although GTK+ viewers, namely giggle and gitview are also quite
popular (note that there might be instances of users using both giggle
and gitview). I am a bit suprised about popularity of Giggle, I'd say.

Tig (text-mode interface for git) and git.el (GIT mode for Emacs) are
also quite popular.

I wonder what are those 15 other GUI. Why oh why there were no "What
is this 'other GUI'?" question.


28. Which (main) git web interface do you use for your projects?

  Answer                         | Count
  ------------------------------------------
  gitweb                         | 382
  cgit                           | 7
  wit (Ruby)                     | 5
  git-php                        | 1
  other                          | 27
  ------------------------------------------
  Base                           | 422 / 683
  Total (sum)                    | 422

Around two third (closer to 4/7) of git users use some kind of web
interface for their projects.

Most use gitweb (which is distributed with git), 7 use cgit, 5 wit
(Ruby), most probably projects sharing site with XMMS2, 1 git-php
(I wonder who...), and there are 27 "other" answers, which I am most
curious about. What are they?

Some answered "other" as "N/A" (meaning they do not use web interface)
instead, what it is not obvious, not answering this question. The
explanation that this is possible was added later during duration of
survey.


29. How do you publish/propagate your changes?

Multiple choices, as one can use different methods for different
projects, for example pushing to public repo for a project maintained,
and sending patches via email to participate in third person project
development.

  Answer                         | Count
  ------------------------------------------
  push                           | 456
  pull                           | 220
  format-patch + email           | 172
  pull request                   | 65
  bundle                         | 13

  other                          | 70
  ------------------------------------------
  Base                           | 589 / 683
  Total (sum)                    | 996

Here "other" means just not listed workflow, although it would be also
interesting to know details.

Most popular is push, I guess to public "publishing" repository
(and/or probably to mirror repositories). It is twice as popular
as next method, gathering more than 3/4 of users.

Pull was supposed to mean logging to public server and pulling
changes from private repo, not pulling someone other changes.
It is second most popular method.

Sending patches via email is two to three times as popular
as sending pull request.


30. Does git.git repository include code produced by you?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 99
  No                             | 512
  ------------------------------------------
  Base                           | 611 / 683
  Total (sum)                    | 611

As it can be seen, only (or perhaps it is that many?) around
a 6th to 7th of git users participate in its development by
providing code.


Internationalization
~~~~~~~~~~~~~~~~~~~~

31. Is translating GIT required for wider adoption?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 49
  No                             | 383
  Somewhat                       | 158
  ------------------------------------------
  Base                           | 590 / 683
  Total (sum)                    | 590

More than half of responders doesn't think that translating GIT
is required for wider adoption.


32. What do you need translated?

  TO TABULARIZE
  172 / 683 non-empty responses


33. For what language do you need translation for?

In alphabetic order, free-form question, treated as multiple choice.

  Answer                         | Count
  ------------------------------------------
  Afrikaans                      | 1
  Belorussian                    | 1
  Chinese                        | 5
  Dutch                          | 2
  English[*1*]                   | 3
  Filipino                       | 1
  Finnish                        | 3
  French                         | 21
  German                         | 17
  Greek                          | 1
  Hebrew                         | 1
  Hindi                          | 1
  Hungarian                      | 1
  Italian                        | 4
  Japanese                       | 5
  Mandarin                       | 1
  Norwegian                      | 2
  Polish                         | 2
  Portuguese                     | 6
  Russian                        | 6
  Serbian                        | 2
  Slovenian                      | 1
  Spanish                        | 9
  Swedish                        | 2
  Tagalog                        | 1
  Ukrainian                      | 1
  ------------------------------------------
  Base                           | 143 / 683
  Total (sum) [*2*]              | 100

[*1*] Git messages and documentation _is_ in English
[*2*] Some answers were: "do not translate".

German and French are most popular. Spanish, Portuguese, Russian,
Chinese + Mandarin and Japanese have count 5 or more.


What you think of GIT
~~~~~~~~~~~~~~~~~~~~~

34. Overall, how happy are you with GIT?

  Answer                         | Count
  ------------------------------------------
  unhappy                        | 13
  not so happy                   | 36
  happy                          | 179
  very happy                     | 302
  completely ecstatic            | 112
  ------------------------------------------
  Base                           | 642 / 683
  Total (sum)                    | 642

Nice, git users are mostly very happy with git.
13 grumpy users, hmmm...


35. How does GIT compare to other SCM tools you have used?

  Answer                         | Count
  ------------------------------------------
  Better                         | 505
  Equal (comparable)             | 96
  Worse                          | 30

  N/A                            | 52
  ------------------------------------------
  Base                           | 631 / 683
  Total (sum)                    | 631

Clearly Git is superior SCM! (In the minds of Git users at least) ;-)
Seriously, one should take into consideration that those results are
biased, because it is _Git User's_ Survey, and people usually choose
SCM because they think it is best choice.

No answer (null answer) might mean that responder does not use and did
not use other SCMs to compare, or at least think that he/she does not
have sufficient basis for a comparison.

NOTE: I have to check if number of non-empty responses is calculated
properly. I think it is, but I will make sure.


36. What do you like about using GIT?

  TO DO
  578 / 683 non-empty responses

No full analysis yet, and no count of answers, but it seems that the
following are encountered most often (or at least those I remember
best):
 * clean design
 * performance (speed)
 * size of repository
 * reliability, robustness, data integrity
 * flexibility, scriptable
 * command set, features (git-bisect)
 * history rewriting (amend, rebase, interactive rebase, reset)
 * history viewers, searching and browsing history
 * distributed nature, offline work, full history locally,
   "local commits"
 * easy and in-place branching
 * easy merging, includes renames detection
 * push/pull via ssh, pull via plain http -- no server needed
 * easy to install: few dependencies, portable, lightweight


37. What would you most like to see improved about GIT?
    (features, bugs, plug-ins, documentation, ...)

  TO DO
  512 / 683 non-empty responses

So many suggestions...

First, some of suggestions are actually implemented already, for
example git development Changelog (present in the form of RelNotes),
shallow clone support, submodules support. This means that new
features are not very well announced (which was one of comments here,
too).

Some of features and improvements mentioned:
 * generic behavior:
   - less chatter, clean distinction between success or fail
     (it it was about git-pull, it is addressed already)
   - better, more verbose error messages, with link to documentation
   - diagnostic output in case of problems;
     something like git-explain / git-state
   - more universal undo / continue
   - command line consistency, option consistency: getopt / gitopt
 * documentation:
   - unified, organized, searchable documentation
   - The Git Book (c.f. cvs/svn/hgbook);
     tutorial leading to advanced concepts like rebase, filter-branch,
     grafts, submodules, gitattributes
   - Git Cookbook / Git Recipies;
     best practices document, usage scenarios, workflows used, HOWTO
   - Git for Dummies (for people who haven't used SCM at all)
   - more hooks and hook examples
   - mid-level (script / plugin writer leve) docs
   - git1line docs a la sed1line.txt
   - "git <cmd> --help" returning one page of short command summary,
     not manpage; "git help --all --summary" for all command with
     oneline description
 * other SCMs:
   - cogito migration guide / tutorial (!)
   - other SCM to git (concept, commands) cheat sheet
   - git-bzr (and other SCMs) two-way integration
   - git-svnserve: git functioning as Subversion server
 * git-svn:
   - automatic handling svn:externals using submodules and vice versa
   - svnmerge and svk merge markers tracking/marking of merges
 * more --interactive:
   - git add --interactive in git-gui: allow to divide hunks
   - git rebase -interactive: graphical interactive rebase in git-gui
   - ncurses-based remote editing
 * tools:
   - better Emacs support; Vim plugin; IDE plugins (Eclipse, KDevelop,
     IntelliJ IDEA,...)
   - MS Windows explorer shell integration; filemanagers integration
     (Nautilus, Konqueror)
   - side by side diffs in gitweb, a la KDiff3/Meld/ediff etc.
 * code:
   - port scripts to C (builtinification)
   - git library (libification)
   - gitbox: single static, pre-packaged binary
 * other:
   - bisect dunno / skip / next
   - partial checkout
   - light working copies; multiple working copies per repo
   - git-notes, to annotate commit messages
   - push over sftp
   - option to track empty directories
   - option to track permissions and metainfo: ACL, EA, forks
   - rebase and blame merge strategies
   - merge / rebase into dirty tree
   - resumable git-clone; faster and less CPU hungry git-clone
   - checkout/merge/diff/hunk header handlers in distribution for
     ChangeLog, XML, odf, jar and xul, po files

This is only [large] excerpt, not a list of all requested features.
As one can see tabularizing (dividing into categories) this data will
be not an easy task.


38. If you want to see GIT more widely used, what do you think
    we could do to make this happen?

  TO DO
  459 / 683 non-empty responses

So many suggestions...
One of the more striking (and funny):

 * Big fat posters world-wide with Catherine Zeta-Jones stating how
   happy she is since she switched to git ;-)

   She can actually write C-code.

 * Offer Git stickers to put on laptops and such


Changes in GIT (since year ago, or since you started using it)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

39. Did you participate in previous Git User's Survey?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 51
  No                             | 583
  ------------------------------------------
  Base                           | 634 / 683
  Total (sum)                    | 634

51 people did out of 634 who answered this question, out of 115 (?)
who did participate in the previous survey. Around half. Bit curious.


40. What improvements you wanted got implemented?

  TO TABULARIZE
  129 / 683 non-empty responses


41. What improvements you wanted didn't get implemented?

  TO TABULARIZE
  104 / 683 non-empty responses


42. How do you compare current version with version from year ago?

Should be: from year ago, or since you started using this.
No responses (303 / 683) migh be caused by the fact that one
do not use git for a year, so he/she doesn't know what git
looked like year ago.

  Answer                         | Count
  ------------------------------------------
  Better                         | 319
  No changes                     | 60
  Worse                          | 1
  ------------------------------------------
  Base                           | 380 / 683
  Total (sum)                    | 380

Most think that git has improved. One user thinks that it is worse
than year ago; I wonder why...


43. Which of the new features do you use?

Multiple choice; the list does not include all new features.
Some new features are not visible at first glance, and one
uses them without conscious choice.

  Answer                         | Count
  ------------------------------------------
  git-gui                        | 103
  blame improvements             | 74
  detached HEAD                  | 71
  stash                          | 68
  mergetool                      | 67
  interactive rebase             | 66
  reflog                         | 54
  submodules                     | 52
  shallow clone                  | 31
  commit template                | 24
  eol conversion                 | 22
  gitattributes                  | 21
  bundle                         | 17
  worktree                       | 17
  ------------------------------------------
  Base                           | 259 / 683
  Total (sum)                    | 687

This table is sorted by count.

Detached HEAD support and stash command were long requested;
no wonder they are popular.


Documentation
~~~~~~~~~~~~~

  Usefulness of      | Yes / Some / No  | Base
  ----------------------------------------------
  GIT wiki           | 191 /  69  / 198 | 458
  on-line help       | 377 / 172  /  28 | 577
  distributed help   | 425 / 154  /  22 | 601
  ----------------------------------------------
                   individual responses : 683


44. Do you use the GIT wiki?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 316
  No                             | 300
  ------------------------------------------
  Base                           | 616 / 683
  Total (sum)                    | 616


45. Do you find GIT wiki useful?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 191
  No                             |  69
  Somewhat                       | 198
  ------------------------------------------
  Base                           | 458 / 683
  Total (sum)                    | 458


46. Do you contribute to GIT wiki?

  Answer                         | Count
  ------------------------------------------
  Yes                            |  17
  No                             | 460
  Corrections and removing spam  |  45

  Some contribution              |  62
  ------------------------------------------
  Base                           | 522 / 683
  Total (sum)                    | 522


47. Do you find GIT's on-line help (homepage, documentation) useful?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 377
  No                             |  28
  Somewhat                       | 172
  ------------------------------------------
  Base                           | 577 / 683
  Total (sum)                    | 577


48. Do you find help distributed with GIT useful
    (manpages, manual, tutorial, HOWTO, release notes)?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 425
  No                             | 22
  Somewhat                       | 154
  ------------------------------------------
  Base                           | 601 / 683
  Total (sum)                    | 601


49. Did/Do you contribute to GIT documentation?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 43
  No                             | 551
  ------------------------------------------
  Base                           | 594 / 683
  Total (sum)                    | 594


50. What could be improved on the GIT homepage?

  TO DO
  171 / 683 non-empty responses


51. What topics would you like to have on GIT wiki?

  TO DO
  134 / 683 non-empty responses


52. What could be improved in GIT documentation?

  TO DO
  190 / 683 non-empty responses


Getting help, staying in touch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  Do you use                | Yes / No  | Base
  ----------------------------------------------
  GIT wiki                  | 316 / 300 | 616
  mailing list              | 204 / 406 | 610
  IRC channel               | 182 / 376 | 558
  ----------------------------------------------

  Usefulness of      | Yes / Some / No  | Base
  ----------------------------------------------
  GIT wiki           | 191 /  69  / 198 | 458
  mailing list       | 146 /  79  /  34 | 259
  IRC channel        | 127 /  59  /  26 | 212
  ----------------------------------------------
                   individual responses : 683

As one can see mailing list is the primary medium for git,
and IRC secondary one.


53. Have you tried to get GIT help from other people?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 357
  No                             | 261
  ------------------------------------------
  Base                           | 618 / 683
  Total (sum)                    | 618

It might be that Git is not documented enough; it might be that
version control is not an easy task.


54. If yes, did you get these problems resolved quickly
    and to your liking?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 326
  No                             | 53
  ------------------------------------------
  Base                           | 379 / 683
  Total (sum)                    | 379

That is I think very good (around 86%) percentage.


55. Would commerical (paid) support from a support vendor
    be of interest to you/your organization?

  Answer                         | Count
  ------------------------------------------
  Not Applicable                 | 203
  Yes                            | 69
  No                             | 322

  Yes + No                       | 391
  ------------------------------------------
  Base                           | 594 / 683
  Total (sum)                    | 594

Only 69 (12%) answers yes, 322 no, 203 not applicable (which meant
to encompass people who do not use git at and for work).

433 = 56 + 377 people participating in this survey use git for work,
or for both work and unpaid projects (as compared to 391 who answered
this question not with N/A).

Note that Git is GPLv2, and it will probably stay that forever, so you
are _free_ to start a commercial support scheme for Git, but others
are free not to choose it. This question is to get to know if there is
sufficient demand for commercial Git support for it to be viable.


56. Do you read the mailing list?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 204
  No                             | 406
  ------------------------------------------
  Base                           | 610 / 683
  Total (sum)                    | 610

The fact that only one third of git users are reading mailing list
(which is nevertheless quite large percentage) means that features
_have_ to be documented somewhere besides mailing list archive and
logs (commit messages).


57. If yes, do you find the mailing list useful?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 146
  No                             | 34
  Somewhat                       | 79
  ------------------------------------------
  Base                           | 259 / 683
  Total (sum)                    | 259


58. Do you find traffic levels on GIT mailing list OK?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 193
  No                             | 50
  ------------------------------------------
  Base                           | 243 / 683
  Total (sum)                    | 243


59. Do you use the IRC channel (#git on irc.freenode.net)?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 182
  No                             | 376
  ------------------------------------------
  Base                           | 558 / 683
  Total (sum)                    | 558


60. If yes, do you find IRC channel useful?

  Answer                         | Count
  ------------------------------------------
  Yes                            | 127
  No                             | 26
  Somewhat                       | 59
  ------------------------------------------
  Base                           | 212 / 683
  Total (sum)                    | 212


61. Did you have problems getting GIT help on mailing list
    or on IRC channel? What were it? What could be improved?

  TO TABULARIZE
  99 / 683 non-empty responses


Open forum
~~~~~~~~~~

62. What other comments or suggestions do you have, that are not
    covered by the questions above?

  TO DO
  141 / 683 non-empty responses

-- 
Jakub Narebski

^ permalink raw reply	[relevance 2%]

* Re: Trying to use git-filter-branch to compress history by removing large, obsolete binary files
  @ 2007-10-08  2:28  2%                 ` Sam Vilain
  0 siblings, 0 replies; 200+ results
From: Sam Vilain @ 2007-10-08  2:28 UTC (permalink / raw)
  To: Elijah Newren; +Cc: Johannes Schindelin, Frank Lichtenheld, git

Elijah Newren wrote:
> On 10/7/07, Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:
>> It should be as easy as git filter-branch and git clone.
> 
> Yes, a git filter-branch, git clone, AND git gc in the clone avoids
> all those funny ref editing commands.  However, cloning a 5.6GB repo
> (the size of one of the real repos I'm dealing with) will likely take
> a long time (and may push me past the limits of disk space), so using
> other steps to avoid the need to clone actually seems nicer.

You can just delete the logs and references that you don't want and run
git gc --prune.

However.

git gc creates a new pack before deleting the old one.  Garbage
collection usually does this; make a copy of everything to a new place
and then free all of the old space.  If *that* is a problem, ie you
don't have enough space for two copies of the repository and the junk,
you'll have to do a partial import, leave the junk you don't want
unpacked, cleanup and prune, then finish the import.  Which sounds like
a lot of hassle when you should really just find a place with more space
to work with!

Sam.

^ permalink raw reply	[relevance 2%]

* [PATCH] Fixing path quoting issues
@ 2007-10-10 21:22 11% maillist
  0 siblings, 0 replies; 200+ results
From: maillist @ 2007-10-10 21:22 UTC (permalink / raw)
  To: git; +Cc: Jonathan del Strother

From: Jonathan del Strother <jon.delStrother@bestbefore.tv>

git-rebase and a number of tests didn't properly quote paths, leading to problems when run from a path with a space in.

Signed-off-by: Jonathan del Strother <jon.delStrother@bestbefore.tv>
---
 git-rebase.sh                            |   26 +++++-----
 t/t1020-subdirectory.sh                  |   22 ++++----
 t/t3050-subprojects-fetch.sh             |    2 +-
 t/t3404-rebase-interactive.sh            |    2 +-
 t/t5500-fetch-pack.sh                    |    2 +-
 t/t5700-clone-reference.sh               |    2 +-
 t/t7003-filter-branch.sh                 |    2 +-
 t/t7501-commit.sh                        |   74 +++++++++++++++---------------
 t/t9100-git-svn-basic.sh                 |   18 ++++----
 t/t9101-git-svn-props.sh                 |    6 +-
 t/t9102-git-svn-deep-rmdir.sh            |    6 +-
 t/t9104-git-svn-follow-parent.sh         |   50 ++++++++++----------
 t/t9105-git-svn-commit-diff.sh           |   10 ++--
 t/t9106-git-svn-commit-diff-clobber.sh   |   14 +++---
 t/t9107-git-svn-migrate.sh               |   40 ++++++++--------
 t/t9108-git-svn-glob.sh                  |    8 ++--
 t/t9110-git-svn-use-svm-props.sh         |    8 ++--
 t/t9111-git-svn-use-svnsync-props.sh     |    8 ++--
 t/t9112-git-svn-md5less-file.sh          |    4 +-
 t/t9113-git-svn-dcommit-new-file.sh      |    6 +-
 t/t9114-git-svn-dcommit-merge.sh         |    4 +-
 t/t9115-git-svn-dcommit-funky-renames.sh |    4 +-
 t/t9116-git-svn-log.sh                   |    4 +-
 t/test-lib.sh                            |    2 +-
 24 files changed, 162 insertions(+), 162 deletions(-)

diff --git a/git-rebase.sh b/git-rebase.sh
index 1583402..b48397e 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -59,7 +59,7 @@ continue_merge () {
 		die "$RESOLVEMSG"
 	fi
 
-	cmt=`cat $dotest/current`
+	cmt=`cat "$dotest/current"`
 	if ! git diff-index --quiet HEAD
 	then
 		if ! git-commit -C "$cmt"
@@ -84,14 +84,14 @@ continue_merge () {
 }
 
 call_merge () {
-	cmt="$(cat $dotest/cmt.$1)"
+	cmt="$(cat "$dotest/cmt.$1")"
 	echo "$cmt" > "$dotest/current"
 	hd=$(git rev-parse --verify HEAD)
 	cmt_name=$(git symbolic-ref HEAD)
-	msgnum=$(cat $dotest/msgnum)
-	end=$(cat $dotest/end)
+	msgnum=$(cat "$dotest/msgnum")
+	end=$(cat "$dotest/end")
 	eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
-	eval GITHEAD_$hd='"$(cat $dotest/onto_name)"'
+	eval GITHEAD_$hd='"$(cat \"$dotest/onto_name\")"'
 	export GITHEAD_$cmt GITHEAD_$hd
 	git-merge-$strategy "$cmt^" -- "$hd" "$cmt"
 	rv=$?
@@ -140,10 +140,10 @@ do
 		}
 		if test -d "$dotest"
 		then
-			prev_head="`cat $dotest/prev_head`"
-			end="`cat $dotest/end`"
-			msgnum="`cat $dotest/msgnum`"
-			onto="`cat $dotest/onto`"
+			prev_head="`cat \"$dotest/prev_head\"`"
+			end="`cat \"$dotest/end\"`"
+			msgnum="`cat \"$dotest/msgnum\"`"
+			onto="`cat \"$dotest/onto\"`"
 			continue_merge
 			while test "$msgnum" -le "$end"
 			do
@@ -160,11 +160,11 @@ do
 		if test -d "$dotest"
 		then
 			git rerere clear
-			prev_head="`cat $dotest/prev_head`"
-			end="`cat $dotest/end`"
-			msgnum="`cat $dotest/msgnum`"
+			prev_head="`cat \"$dotest/prev_head\"`"
+			end="`cat \"$dotest/end\"`"
+			msgnum="`cat \"$dotest/msgnum\"`"
 			msgnum=$(($msgnum + 1))
-			onto="`cat $dotest/onto`"
+			onto="`cat \"$dotest/onto\"`"
 			while test "$msgnum" -le "$end"
 			do
 				call_merge "$msgnum"
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index b9cef34..5ed7fa4 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -21,7 +21,7 @@ LF='
 '
 
 test_expect_success 'update-index and ls-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git update-index --add one &&
 	case "`git ls-files`" in
 	one) echo ok one ;;
@@ -41,7 +41,7 @@ test_expect_success 'update-index and ls-files' '
 '
 
 test_expect_success 'cat-file' '
-	cd $HERE &&
+	cd "$HERE" &&
 	two=`git ls-files -s dir/two` &&
 	two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
 	echo "$two" &&
@@ -54,7 +54,7 @@ test_expect_success 'cat-file' '
 rm -f actual dir/actual
 
 test_expect_success 'diff-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	echo a >>one &&
 	echo d >>dir/two &&
 	case "`git diff-files --name-only`" in
@@ -74,7 +74,7 @@ test_expect_success 'diff-files' '
 '
 
 test_expect_success 'write-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	top=`git write-tree` &&
 	echo $top &&
 	cd dir &&
@@ -84,7 +84,7 @@ test_expect_success 'write-tree' '
 '
 
 test_expect_success 'checkout-index' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git checkout-index -f -u one &&
 	cmp one original.one &&
 	cd dir &&
@@ -93,7 +93,7 @@ test_expect_success 'checkout-index' '
 '
 
 test_expect_success 'read-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -f one dir/two &&
 	tree=`git write-tree` &&
 	git read-tree --reset -u "$tree" &&
@@ -107,27 +107,27 @@ test_expect_success 'read-tree' '
 '
 
 test_expect_success 'no file/rev ambiguity check inside .git' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git commit -a -m 1 &&
-	cd $HERE/.git &&
+	cd "$HERE/.git" &&
 	git show -s HEAD
 '
 
 test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && GIT_DIR=. git show -s HEAD
 '
 
 # This still does not work as it should...
 : test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && git show -s HEAD
 '
 
 test_expect_success 'detection should not be fooled by a symlink' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -fr foo.git &&
 	git clone -s .git another &&
 	ln -s another yetanother &&
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 34f26a8..4b74cc6 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -20,7 +20,7 @@ test_expect_success setup '
 '
 
 test_expect_success clone '
-	git clone file://`pwd`/.git cloned &&
+	git clone "file://`pwd`/.git" cloned &&
 	(git rev-parse HEAD; git ls-files -s) >expected &&
 	(
 		cd cloned &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 1113904..f321787 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -92,7 +92,7 @@ done
 EOF
 
 chmod a+x fake-editor.sh
-VISUAL="$(pwd)/fake-editor.sh"
+VISUAL="'$(pwd)/fake-editor.sh'"
 export VISUAL
 
 test_expect_success 'no changes are a nop' '
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 7b6798d..5489ffe 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -129,7 +129,7 @@ pull_to_client 2nd "B" $((64*3))
 
 pull_to_client 3rd "A" $((1*3)) # old fails
 
-test_expect_success "clone shallow" "git-clone --depth 2 file://`pwd`/. shallow"
+test_expect_success "clone shallow" "git-clone --depth 2 \"file://`pwd`/.\" shallow"
 
 (cd shallow; git count-objects -v) > count.shallow
 
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index 4e93aaa..8bb34f9 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -51,7 +51,7 @@ diff expected current'
 cd "$base_dir"
 
 test_expect_success 'cloning with reference (no -l -s)' \
-'git clone --reference B file://`pwd`/A D'
+'git clone --reference B "file://`pwd`/A" D'
 
 cd "$base_dir"
 
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index e935b20..1ab5392 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -107,7 +107,7 @@ test_expect_success 'use index-filter to move into a subdirectory' '
 		 "git ls-files -s | sed \"s-\\t-&newsubdir/-\" |
 	          GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
 			git update-index --index-info &&
-		  mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
+		  mv \"\$GIT_INDEX_FILE.new\" \"\$GIT_INDEX_FILE\"" directorymoved &&
 	test -z "$(git diff HEAD directorymoved:newsubdir)"'
 
 test_expect_success 'stops when msg filter fails' '
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index b151b51..f3d0ab9 100644
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -69,7 +69,7 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -i -e "s/a file/an amend commit/g" $1
+sed -i -e "s/a file/an amend commit/g" "$1"
 EOF
 chmod 755 editor
 
@@ -80,40 +80,40 @@ test_expect_success \
 test_expect_failure \
 	"passing -m and -F" \
 	"echo 'enough with the bongos' >file && \
-	 git-commit -F msg -m amending ."
+	git-commit -F msg -m amending ."
 
 test_expect_success \
-	"using message from other commit" \
-	"git-commit -C HEAD^ ."
+	 "using message from other commit" \
+	 "git-commit -C HEAD^ ."
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -i -e "s/amend/older/g" $1
+sed -i -e "s/amend/older/g" "$1"
 EOF
 chmod 755 editor
 
 test_expect_success \
-	"editing message from other commit" \
-	"echo 'hula hula' >file && \
-	 VISUAL=./editor git-commit -c HEAD^ -a"
+	 "editing message from other commit" \
+	 "echo 'hula hula' >file && \
+	  VISUAL=./editor git-commit -c HEAD^ -a"
 
 test_expect_success \
-	"message from stdin" \
-	"echo 'silly new contents' >file && \
-	 echo commit message from stdin | git-commit -F - -a"
+	 "message from stdin" \
+	 "echo 'silly new contents' >file && \
+	  echo commit message from stdin | git-commit -F - -a"
 
 test_expect_success \
-	"overriding author from command line" \
-	"echo 'gak' >file && \
-	 git-commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a"
+	 "overriding author from command line" \
+	 "echo 'gak' >file && \
+	  git-commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a"
 
 test_expect_success \
-	"interactive add" \
-	"echo 7 | git-commit --interactive | grep 'What now'"
+	 "interactive add" \
+	 "echo 7 | git-commit --interactive | grep 'What now'"
 
 test_expect_success \
-	"showing committed revisions" \
-	"git-rev-list HEAD >current"
+	 "showing committed revisions" \
+	 "git-rev-list HEAD >current"
 
 # We could just check the head sha1, but checking each commit makes it
 # easier to isolate bugs.
@@ -128,38 +128,38 @@ d381ac431806e53f3dd7ac2f1ae0534f36d738b9
 EOF
 
 test_expect_success \
-    'validate git-rev-list output.' \
-    'diff current expected'
+	'validate git-rev-list output.' \
+	'diff current expected'
 
 test_expect_success 'partial commit that involves removal (1)' '
 
-	git rm --cached file &&
-	mv file elif &&
-	git add elif &&
-	git commit -m "Partial: add elif" elif &&
-	git diff-tree --name-status HEAD^ HEAD >current &&
-	echo "A	elif" >expected &&
-	diff expected current
+	 git rm --cached file &&
+	 mv file elif &&
+	 git add elif &&
+	 git commit -m "Partial: add elif" elif &&
+	 git diff-tree --name-status HEAD^ HEAD >current &&
+	 echo "A elif" >expected &&
+	 diff -b expected current
 
 '
 
 test_expect_success 'partial commit that involves removal (2)' '
 
-	git commit -m "Partial: remove file" file &&
-	git diff-tree --name-status HEAD^ HEAD >current &&
-	echo "D	file" >expected &&
-	diff expected current
+	 git commit -m "Partial: remove file" file &&
+	 git diff-tree --name-status HEAD^ HEAD >current &&
+	 echo "D file" >expected &&
+	 diff -b expected current
 
 '
 
 test_expect_success 'partial commit that involves removal (3)' '
 
-	git rm --cached elif &&
-	echo elif >elif &&
-	git commit -m "Partial: modify elif" elif &&
-	git diff-tree --name-status HEAD^ HEAD >current &&
-	echo "M	elif" >expected &&
-	diff expected current
+	 git rm --cached elif &&
+	 echo elif >elif &&
+	 git commit -m "Partial: modify elif" elif &&
+	 git diff-tree --name-status HEAD^ HEAD >current &&
+	 echo "M elif" >expected &&
+	 diff -b expected current
 
 '
 
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 614cf50..c3585da 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -31,16 +31,16 @@ test_expect_success \
 	echo 'zzz' > bar/zzz &&
 	echo '#!/bin/sh' > exec.sh &&
 	chmod +x exec.sh &&
-	svn import -m 'import for git-svn' . $svnrepo >/dev/null &&
+	svn import -m 'import for git-svn' . '$svnrepo' >/dev/null &&
 	cd .. &&
 	rm -rf import &&
-	git-svn init $svnrepo"
+	git-svn init '$svnrepo'"
 
 test_expect_success \
     'import an SVN revision into git' \
     'git-svn fetch'
 
-test_expect_success "checkout from svn" "svn co $svnrepo '$SVN_TREE'"
+test_expect_success "checkout from svn" "svn co '$svnrepo' '$SVN_TREE'"
 
 name='try a deep --rmdir with a commit'
 test_expect_success "$name" "
@@ -169,7 +169,7 @@ test_expect_success "$name" "
 	svn up '$SVN_TREE' &&
 	test -f '$SVN_TREE'/exec-2.sh &&
 	test ! -L '$SVN_TREE'/exec-2.sh &&
-	git diff help $SVN_TREE/exec-2.sh"
+	git diff help '$SVN_TREE/exec-2.sh'"
 
 if test "$have_utf8" = t
 then
@@ -190,7 +190,7 @@ name='test fetch functionality (svn => git) with alternate GIT_SVN_ID'
 GIT_SVN_ID=alt
 export GIT_SVN_ID
 test_expect_success "$name" \
-    "git-svn init $svnrepo && git-svn fetch &&
+    "git-svn init '$svnrepo' && git-svn fetch &&
      git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a &&
      git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
      git diff a b"
@@ -220,16 +220,16 @@ test_expect_failure 'exit if remote refs are ambigious' "
         "
 
 test_expect_failure 'exit if init-ing a would clobber a URL' "
-        svnadmin create ${PWD}/svnrepo2 &&
-        svn mkdir -m 'mkdir bar' ${svnrepo}2/bar &&
+        svnadmin create '${PWD}/svnrepo2' &&
+        svn mkdir -m 'mkdir bar' '${svnrepo}2/bar' &&
         git config --unset svn-remote.svn.fetch \
                                 '^bar:refs/remotes/git-svn$' &&
-        git-svn init ${svnrepo}2/bar
+        git-svn init '${svnrepo}2/bar'
         "
 
 test_expect_success \
   'init allows us to connect to another directory in the same repo' "
-        git-svn init --minimize-url -i bar $svnrepo/bar &&
+        git-svn init --minimize-url -i bar '$svnrepo/bar' &&
         git config --get svn-remote.svn.fetch \
                               '^bar:refs/remotes/bar$' &&
         git config --get svn-remote.svn.fetch \
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index 5aac644..a1c85e0 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -52,7 +52,7 @@ EOF
 cd ..
 
 rm -rf import
-test_expect_success 'checkout working copy from svn' "svn co $svnrepo test_wc"
+test_expect_success 'checkout working copy from svn' "svn co '$svnrepo' test_wc"
 test_expect_success 'setup some commits to svn' \
 	'cd test_wc &&
 		echo Greetings >> kw.c &&
@@ -66,7 +66,7 @@ test_expect_success 'setup some commits to svn' \
 		svn commit -m "Propset Id" &&
 	cd ..'
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init '$svnrepo'"
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 
 name='test svn:keywords ignoring'
@@ -92,7 +92,7 @@ test_expect_success "propset CR on crlf files" \
 test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
 	"git-svn fetch &&
 	 git pull . remotes/git-svn &&
-	 svn co $svnrepo new_wc"
+	 svn co '$svnrepo' new_wc"
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh
index 4e08083..99c8840 100755
--- a/t/t9102-git-svn-deep-rmdir.sh
+++ b/t/t9102-git-svn-deep-rmdir.sh
@@ -9,12 +9,12 @@ test_expect_success 'initialize repo' "
 	mkdir -p deeply/nested/directory/number/2 &&
 	echo foo > deeply/nested/directory/number/1/file &&
 	echo foo > deeply/nested/directory/number/2/another &&
-	svn import -m 'import for git-svn' . $svnrepo &&
+	svn import -m 'import for git-svn' . '$svnrepo' &&
 	cd ..
 	"
 
 test_expect_success 'mirror via git-svn' "
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
 	git checkout -f -b test-rmdir remotes/git-svn
 	"
@@ -23,7 +23,7 @@ test_expect_success 'Try a commit on rmdir' "
 	git rm -f deeply/nested/directory/number/2/another &&
 	git commit -a -m 'remove another' &&
 	git-svn set-tree --rmdir HEAD &&
-	svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1
+	svn ls -R '$svnrepo' | grep ^deeply/nested/directory/number/1
 	"
 
 
diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 7ba7630..aa2bfe2 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -11,9 +11,9 @@ test_expect_success 'initialize repo' "
 	cd import &&
 	mkdir -p trunk &&
 	echo hello > trunk/readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
-	svn co $svnrepo wc &&
+	svn co '$svnrepo' wc &&
 	cd wc &&
 	echo world >> trunk/readme &&
 	poke trunk/readme &&
@@ -27,7 +27,7 @@ test_expect_success 'initialize repo' "
 	"
 
 test_expect_success 'init and fetch a moved directory' "
-	git-svn init --minimize-url -i thunk $svnrepo/thunk &&
+	git-svn init --minimize-url -i thunk '$svnrepo/thunk' &&
 	git-svn fetch -i thunk &&
 	test \"\`git rev-parse --verify refs/remotes/thunk@2\`\" \
            = \"\`git rev-parse --verify refs/remotes/thunk~1\`\" &&
@@ -38,7 +38,7 @@ test_expect_success 'init and fetch a moved directory' "
 	"
 
 test_expect_success 'init and fetch from one svn-remote' "
-        git config svn-remote.svn.url $svnrepo &&
+        git config svn-remote.svn.url '$svnrepo' &&
         git config --add svn-remote.svn.fetch \
           trunk:refs/remotes/svn/trunk &&
         git config --add svn-remote.svn.fetch \
@@ -52,9 +52,9 @@ test_expect_success 'init and fetch from one svn-remote' "
 
 test_expect_success 'follow deleted parent' "
         (svn cp -m 'resurrecting trunk as junk' \
-               $svnrepo/trunk@2 $svnrepo/junk ||
+               '$svnrepo/trunk@2' '$svnrepo'/junk ||
          svn cp -m 'resurrecting trunk as junk' \
-               -r2 $svnrepo/trunk $svnrepo/junk) &&
+               -r2 '$svnrepo/trunk' '$svnrepo/junk') &&
         git config --add svn-remote.svn.fetch \
           junk:refs/remotes/svn/junk &&
         git-svn fetch -i svn/thunk &&
@@ -67,10 +67,10 @@ test_expect_success 'follow deleted parent' "
 test_expect_success 'follow larger parent' "
         mkdir -p import/trunk/thunk/bump/thud &&
         echo hi > import/trunk/thunk/bump/thud/file &&
-        svn import -m 'import a larger parent' import $svnrepo/larger-parent &&
-        svn cp -m 'hi' $svnrepo/larger-parent $svnrepo/another-larger &&
+        svn import -m 'import a larger parent' import '$svnrepo/larger-parent' &&
+        svn cp -m 'hi' '$svnrepo/larger-parent' '$svnrepo/another-larger' &&
         git-svn init --minimize-url -i larger \
-          $svnrepo/another-larger/trunk/thunk/bump/thud &&
+          '$svnrepo/another-larger/trunk/thunk/bump/thud' &&
         git-svn fetch -i larger &&
         git rev-parse --verify refs/remotes/larger &&
         git rev-parse --verify \
@@ -83,23 +83,23 @@ test_expect_success 'follow larger parent' "
         "
 
 test_expect_success 'follow higher-level parent' "
-        svn mkdir -m 'follow higher-level parent' $svnrepo/blob &&
-        svn co $svnrepo/blob blob &&
+        svn mkdir -m 'follow higher-level parent' '$svnrepo/blob' &&
+        svn co '$svnrepo/blob' blob &&
         cd blob &&
                 echo hi > hi &&
                 svn add hi &&
                 svn commit -m 'hihi' &&
                 cd ..
-        svn mkdir -m 'new glob at top level' $svnrepo/glob &&
-        svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
-        git-svn init --minimize-url -i blob $svnrepo/glob/blob &&
+        svn mkdir -m 'new glob at top level' '$svnrepo/glob' &&
+        svn mv -m 'move blob down a level' '$svnrepo/blob' '$svnrepo/glob/blob' &&
+        git-svn init --minimize-url -i blob '$svnrepo/glob/blob' &&
         git-svn fetch -i blob
         "
 
 test_expect_success 'follow deleted directory' "
-	svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye &&
-	svn rm -m 'remove glob' $svnrepo/glob &&
-	git-svn init --minimize-url -i glob $svnrepo/glob &&
+	svn mv -m 'bye!' '$svnrepo/glob/blob/hi' '$svnrepo/glob/blob/bye' &&
+	svn rm -m 'remove glob' '$svnrepo/glob' &&
+	git-svn init --minimize-url -i glob '$svnrepo/glob' &&
 	git-svn fetch -i glob &&
 	test \"\`git cat-file blob refs/remotes/glob:blob/bye\`\" = hi &&
 	test \"\`git ls-tree refs/remotes/glob | wc -l \`\" -eq 1
@@ -118,9 +118,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  echo 'bad delete test 2' > \
 	   import/trunk/subversion/bindings/swig/perl/another-larger &&
 	cd import &&
-	  svn import -m 'r9270 test' . $svnrepo/r9270 &&
+	  svn import -m 'r9270 test' . '$svnrepo/r9270' &&
 	cd .. &&
-	svn co $svnrepo/r9270/trunk/subversion/bindings/swig/perl r9270 &&
+	svn co '$svnrepo/r9270/trunk/subversion/bindings/swig/perl' r9270 &&
 	cd r9270 &&
 	  svn mkdir native &&
 	  svn mv t native/t &&
@@ -130,7 +130,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  svn commit -m 'reorg test' &&
 	cd .. &&
 	git-svn init --minimize-url -i r9270-t \
-	  $svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t &&
+	  '$svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t' &&
 	git-svn fetch -i r9270-t &&
 	test \`git rev-list r9270-t | wc -l\` -eq 2 &&
 	test \"\`git ls-tree --name-only r9270-t~1\`\" = \
@@ -138,9 +138,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	"
 
 test_expect_success "track initial change if it was only made to parent" "
-	svn cp -m 'wheee!' $svnrepo/r9270/trunk $svnrepo/r9270/drunk &&
+	svn cp -m 'wheee!' '$svnrepo/r9270/trunk' '$svnrepo/r9270/drunk' &&
 	git-svn init --minimize-url -i r9270-d \
-	  $svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t &&
+	  '$svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t' &&
 	git-svn fetch -i r9270-d &&
 	test \`git rev-list r9270-d | wc -l\` -eq 3 &&
 	test \"\`git ls-tree --name-only r9270-t\`\" = \
@@ -150,7 +150,7 @@ test_expect_success "track initial change if it was only made to parent" "
 	"
 
 test_expect_success "track multi-parent paths" "
-	svn cp -m 'resurrect /glob' $svnrepo/r9270 $svnrepo/glob &&
+	svn cp -m 'resurrect /glob' '$svnrepo/r9270' '$svnrepo/glob' &&
 	git-svn multi-fetch &&
 	test \`git cat-file commit refs/remotes/glob | \
 	       grep '^parent ' | wc -l\` -eq 2
@@ -161,8 +161,8 @@ test_expect_success "multi-fetch continues to work" "
 	"
 
 test_expect_success "multi-fetch works off a 'clean' repository" "
-	rm -r $GIT_DIR/svn $GIT_DIR/refs/remotes $GIT_DIR/logs &&
-	mkdir $GIT_DIR/svn &&
+	rm -r '$GIT_DIR/svn' '$GIT_DIR/refs/remotes' '$GIT_DIR/logs' &&
+	mkdir '$GIT_DIR/svn' &&
 	git-svn multi-fetch
 	"
 
diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh
index 318e172..2e1eb75 100755
--- a/t/t9105-git-svn-commit-diff.sh
+++ b/t/t9105-git-svn-commit-diff.sh
@@ -8,7 +8,7 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo hello > readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
 	echo hello > readme &&
 	git update-index --add readme &&
@@ -27,16 +27,16 @@ prev=`git rev-parse --verify HEAD^1`
 test_expect_success 'test the commit-diff command' "
 	test -n '$prev' && test -n '$head' &&
 	git-svn commit-diff -r1 '$prev' '$head' '$svnrepo' &&
-	svn co $svnrepo wc &&
+	svn co '$svnrepo' wc &&
 	cmp readme wc/readme
 	"
 
 test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
-	svn import -m 'sub-directory' import $svnrepo/subdir &&
-	git-svn init --minimize-url $svnrepo/subdir &&
+	svn import -m 'sub-directory' import '$svnrepo/subdir' &&
+	git-svn init --minimize-url '$svnrepo/subdir' &&
 	git-svn fetch &&
 	git-svn commit-diff -r3 '$prev' '$head' &&
-	svn cat $svnrepo/subdir/readme > readme.2 &&
+	svn cat '$svnrepo/subdir/readme' > readme.2 &&
 	cmp readme readme.2
 	"
 
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index 79b7968..bb42339 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -8,14 +8,14 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo initial > file &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
 	echo initial > file &&
 	git update-index --add file &&
 	git commit -a -m 'initial'
 	"
 test_expect_success 'commit change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 	echo second line from svn >> file &&
 	poke file &&
@@ -27,7 +27,7 @@ test_expect_success 'commit change from svn side' "
 test_expect_failure 'commit conflicting change from git' "
 	echo second line from git >> file &&
 	git commit -a -m 'second line from git' &&
-	git-svn commit-diff -r1 HEAD~1 HEAD $svnrepo
+	git-svn commit-diff -r1 HEAD~1 HEAD '$svnrepo'
 	" || true
 
 test_expect_success 'commit complementing change from git' "
@@ -36,14 +36,14 @@ test_expect_success 'commit complementing change from git' "
 	git commit -a -m 'second line from svn' &&
 	echo third line from git >> file &&
 	git commit -a -m 'third line from git' &&
-	git-svn commit-diff -r2 HEAD~1 HEAD $svnrepo
+	git-svn commit-diff -r2 HEAD~1 HEAD '$svnrepo'
 	"
 
 test_expect_failure 'dcommit fails to commit because of conflict' "
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
 	git reset --hard refs/remotes/git-svn &&
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 	echo fourth line from svn >> file &&
 	poke file &&
@@ -67,7 +67,7 @@ test_expect_success 'dcommit does the svn equivalent of an index merge' "
 	"
 
 test_expect_success 'commit another change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 		echo third line from svn >> file &&
 		poke file &&
diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index 67fdf70..90bf786 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -4,7 +4,7 @@ test_description='git-svn metadata migrations from previous versions'
 . ./lib-git-svn.sh
 
 test_expect_success 'setup old-looking metadata' "
-	cp $GIT_DIR/config $GIT_DIR/config-old-git-svn &&
+	cp '$GIT_DIR/config' '$GIT_DIR/config-old-git-svn' &&
 	mkdir import &&
 	cd import &&
 		for i in trunk branches/a branches/b \
@@ -12,13 +12,13 @@ test_expect_success 'setup old-looking metadata' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . '$svnrepo'
 		cd .. &&
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
-	mv $GIT_DIR/svn/* $GIT_DIR/ &&
-	mv $GIT_DIR/svn/.metadata $GIT_DIR/ &&
-	rmdir $GIT_DIR/svn &&
+	mv '$GIT_DIR'/svn/* '$GIT_DIR/' &&
+	mv '$GIT_DIR/svn/.metadata' '$GIT_DIR/' &&
+	rmdir '$GIT_DIR/svn' &&
 	git update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn &&
 	git update-ref refs/heads/svn-HEAD refs/remotes/git-svn &&
 	git update-ref -d refs/remotes/git-svn refs/remotes/git-svn
@@ -28,20 +28,20 @@ head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
 test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
 
 test_expect_success 'initialize old-style (v0) git-svn layout' "
-	mkdir -p $GIT_DIR/git-svn/info $GIT_DIR/svn/info &&
-	echo $svnrepo > $GIT_DIR/git-svn/info/url &&
-	echo $svnrepo > $GIT_DIR/svn/info/url &&
+	mkdir -p '$GIT_DIR/git-svn/info' '$GIT_DIR/svn/info' &&
+	echo '$svnrepo' > '$GIT_DIR/git-svn/info/url' &&
+	echo '$svnrepo' > '$GIT_DIR/svn/info/url' &&
 	git-svn migrate &&
-	! test -d $GIT_DIR/git-svn &&
+	! test -d '$GIT_DIR/git-svn' &&
 	git rev-parse --verify refs/remotes/git-svn^0 &&
 	git rev-parse --verify refs/remotes/svn^0 &&
-	test \`git config --get svn-remote.svn.url\` = '$svnrepo' &&
+	test \"\`git config --get svn-remote.svn.url\`\" = \"$svnrepo\" &&
 	test \`git config --get svn-remote.svn.fetch\` = \
              ':refs/remotes/git-svn'
 	"
 
 test_expect_success 'initialize a multi-repository repo' "
-	git-svn init $svnrepo -T trunk -t tags -b branches &&
+	git-svn init '$svnrepo' -T trunk -t tags -b branches &&
 	git config --get-all svn-remote.svn.fetch > fetch.out &&
 	grep '^trunk:refs/remotes/trunk$' fetch.out &&
 	test -n \"\`git config --get svn-remote.svn.branches \
@@ -76,14 +76,14 @@ test_expect_success 'multi-fetch works on partial urls + paths' "
 test_expect_success 'migrate --minimize on old inited layout' "
 	git config --unset-all svn-remote.svn.fetch &&
 	git config --unset-all svn-remote.svn.url &&
-	rm -rf $GIT_DIR/svn &&
+	rm -rf '$GIT_DIR/svn' &&
 	for i in \`cat fetch.out\`; do
 		path=\`expr \$i : '\\([^:]*\\):.*$'\`
 		ref=\`expr \$i : '[^:]*:refs/remotes/\\(.*\\)$'\`
 		if test -z \"\$ref\"; then continue; fi
 		if test -n \"\$path\"; then path=\"/\$path\"; fi
-		( mkdir -p $GIT_DIR/svn/\$ref/info/ &&
-		echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
+		( mkdir -p '$GIT_DIR'/svn/\$ref/info/ &&
+		echo '$svnrepo'\$path > '$GIT_DIR'/svn/\$ref/info/url ) || exit 1;
 	done &&
 	git-svn migrate --minimize &&
 	test -z \"\`git config -l |grep -v '^svn-remote\.git-svn\.'\`\" &&
@@ -99,13 +99,13 @@ test_expect_success 'migrate --minimize on old inited layout' "
 
 test_expect_success  ".rev_db auto-converted to .rev_db.UUID" "
 	git-svn fetch -i trunk &&
-	expect=$GIT_DIR/svn/trunk/.rev_db.* &&
+	expect=\"\`find \"\$GIT_DIR\"/svn/trunk/ -name '.rev_db.*'\`\" &&
 	test -n \"\$expect\" &&
-	mv \$expect $GIT_DIR/svn/trunk/.rev_db &&
+	mv \"\$expect\" \"\$GIT_DIR\"/svn/trunk/.rev_db &&
 	git-svn fetch -i trunk &&
-	test -L $GIT_DIR/svn/trunk/.rev_db &&
-	test -f \$expect &&
-	cmp \$expect $GIT_DIR/svn/trunk/.rev_db
+	test -L \"\$GIT_DIR\"/svn/trunk/.rev_db &&
+	test -f \"\$expect\" &&
+	cmp \"\$expect\" \"\$GIT_DIR\"/svn/trunk/.rev_db
 	"
 
 test_done
diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh
index db4344c..c6dc0ef 100755
--- a/t/t9108-git-svn-glob.sh
+++ b/t/t9108-git-svn-glob.sh
@@ -14,8 +14,8 @@ test_expect_success 'test refspec globbing' "
 	mkdir -p trunk/src/a trunk/src/b trunk/doc &&
 	echo 'hello world' > trunk/src/a/readme &&
 	echo 'goodbye world' > trunk/src/b/readme &&
-	svn import -m 'initial' trunk $svnrepo/trunk &&
-	svn co $svnrepo tmp &&
+	svn import -m 'initial' trunk '$svnrepo/trunk' &&
+	svn co '$svnrepo' tmp &&
 	cd tmp &&
 		mkdir branches tags &&
 		svn add branches tags &&
@@ -38,7 +38,7 @@ test_expect_success 'test refspec globbing' "
 		poke tags/end/src/b/readme &&
 		svn commit -m 'nothing to see here'
 		cd .. &&
-	git config --add svn-remote.svn.url $svnrepo &&
+	git config --add svn-remote.svn.url '$svnrepo' &&
 	git config --add svn-remote.svn.fetch \
 	                 'trunk/src/a:refs/remotes/trunk' &&
 	git config --add svn-remote.svn.branches \
@@ -60,7 +60,7 @@ echo nothing to see here >> expect.two
 cat expect.end >> expect.two
 
 test_expect_success 'test left-hand-side only globbing' "
-	git config --add svn-remote.two.url $svnrepo &&
+	git config --add svn-remote.two.url '$svnrepo' &&
 	git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
 	git config --add svn-remote.two.branches \
 	                 'branches/*:refs/remotes/two/branches/*' &&
diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh
index 6235af4..d4ab01f 100755
--- a/t/t9110-git-svn-use-svm-props.sh
+++ b/t/t9110-git-svn-use-svm-props.sh
@@ -8,11 +8,11 @@ test_description='git-svn useSvmProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svm repo' "
-	svnadmin load -q $rawsvnrepo < ../t9110/svm.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/mirror/arr &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/mirror/argh &&
+	svnadmin load -q '$rawsvnrepo' < ../t9110/svm.dump &&
+	git-svn init --minimize-url -R arr -i bar '$svnrepo/mirror/arr' &&
+	git-svn init --minimize-url -R argh -i dir '$svnrepo/mirror/argh' &&
 	git-svn init --minimize-url -R argh -i e \
-	  $svnrepo/mirror/argh/a/b/c/d/e &&
+	  '$svnrepo/mirror/argh/a/b/c/d/e' &&
 	git config svn.useSvmProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9111-git-svn-use-svnsync-props.sh b/t/t9111-git-svn-use-svnsync-props.sh
index ec7dedd..936f023 100755
--- a/t/t9111-git-svn-use-svnsync-props.sh
+++ b/t/t9111-git-svn-use-svnsync-props.sh
@@ -8,10 +8,10 @@ test_description='git-svn useSvnsyncProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svnsync repo' "
-	svnadmin load -q $rawsvnrepo < ../t9111/svnsync.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/bar &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/dir &&
-	git-svn init --minimize-url -R argh -i e $svnrepo/dir/a/b/c/d/e &&
+	svnadmin load -q '$rawsvnrepo' < ../t9111/svnsync.dump &&
+	git-svn init --minimize-url -R arr -i bar '$svnrepo/bar' &&
+	git-svn init --minimize-url -R argh -i dir '$svnrepo/dir' &&
+	git-svn init --minimize-url -R argh -i e '$svnrepo/dir/a/b/c/d/e' &&
 	git config svn.useSvnsyncProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh
index 08313bb..b095583 100755
--- a/t/t9112-git-svn-md5less-file.sh
+++ b/t/t9112-git-svn-md5less-file.sh
@@ -38,8 +38,8 @@ PROPS-END
 
 EOF
 
-test_expect_success 'load svn dumpfile' "svnadmin load $rawsvnrepo < dumpfile.svn"
+test_expect_success 'load svn dumpfile' "svnadmin load '$rawsvnrepo' < dumpfile.svn"
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init '$svnrepo'"
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 test_done
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
index 9ef0db9..0088c75 100755
--- a/t/t9113-git-svn-dcommit-new-file.sh
+++ b/t/t9113-git-svn-dcommit-new-file.sh
@@ -15,14 +15,14 @@ test_description='git-svn dcommit new files over svn:// test'
 
 start_svnserve () {
 	svnserve --listen-port $SVNSERVE_PORT \
-	         --root $rawsvnrepo \
+	         --root '$rawsvnrepo' \
 	         --listen-once \
 	         --listen-host 127.0.0.1 &
 }
 
 test_expect_success 'start tracking an empty repo' "
-	svn mkdir -m 'empty dir' $svnrepo/empty-dir &&
-	echo anon-access = write >> $rawsvnrepo/conf/svnserve.conf &&
+	svn mkdir -m 'empty dir' '$svnrepo/empty-dir' &&
+	echo anon-access = write >> '$rawsvnrepo/conf/svnserve.conf' &&
 	start_svnserve &&
 	git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
 	git svn fetch
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
index d6ca955..64ec7fd 100755
--- a/t/t9114-git-svn-dcommit-merge.sh
+++ b/t/t9114-git-svn-dcommit-merge.sh
@@ -35,7 +35,7 @@ EOF
 }
 
 test_expect_success 'setup svn repository' "
-	svn co $svnrepo mysvnwork &&
+	svn co '$svnrepo' mysvnwork &&
 	mkdir -p mysvnwork/trunk &&
 	cd mysvnwork &&
 		big_text_block >> trunk/README &&
@@ -45,7 +45,7 @@ test_expect_success 'setup svn repository' "
 	"
 
 test_expect_success 'setup git mirror and merge' "
-	git svn init $svnrepo -t tags -T trunk -b branches &&
+	git svn init '$svnrepo' -t tags -T trunk -b branches &&
 	git svn fetch &&
 	git checkout --track -b svn remotes/trunk &&
 	git checkout -b merge &&
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 182299c..653578d 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -8,12 +8,12 @@ test_description='git-svn dcommit can commit renames of files with ugly names'
 . ./lib-git-svn.sh
 
 test_expect_success 'load repository with strange names' "
-	svnadmin load -q $rawsvnrepo < ../t9115/funky-names.dump &&
+	svnadmin load -q '$rawsvnrepo' < ../t9115/funky-names.dump &&
 	start_httpd
 	"
 
 test_expect_success 'init and fetch repository' "
-	git svn init $svnrepo &&
+	git svn init '$svnrepo' &&
 	git svn fetch &&
 	git reset --hard git-svn
 	"
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index 0d4e6b3..70c0c5f 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -14,9 +14,9 @@ test_expect_success 'setup repository and import' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . '$svnrepo'
 		cd .. &&
-	git-svn init $svnrepo -T trunk -b branches -t tags &&
+	git-svn init '$svnrepo' -T trunk -b branches -t tags &&
 	git-svn fetch &&
 	git reset --hard trunk &&
 	echo bye >> README &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index cc1253c..a68415f 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -229,7 +229,7 @@ test_create_repo () {
 	repo="$1"
 	mkdir "$repo"
 	cd "$repo" || error "Cannot setup test environment"
-	"$GIT_EXEC_PATH/git" init --template=$GIT_EXEC_PATH/templates/blt/ >/dev/null 2>&1 ||
+	"$GIT_EXEC_PATH/git" init --template="$GIT_EXEC_PATH/templates/blt/" >/dev/null 2>&1 ||
 	error "cannot run git init -- have you built things yet?"
 	mv .git/hooks .git/hooks-disabled
 	cd "$owd"
-- 
1.5.3.1

^ permalink raw reply related	[relevance 11%]

* [PATCH] Fixing path quoting issues
@ 2007-10-10 21:13 11% Jonathan del Strother
  0 siblings, 0 replies; 200+ results
From: Jonathan del Strother @ 2007-10-10 21:13 UTC (permalink / raw)
  To: git, gitster; +Cc: Jonathan del Strother

git-rebase and a number of tests didn't properly quote paths, leading to problems when run from a path with a space in.

Signed-off-by: Jonathan del Strother <jon.delStrother@bestbefore.tv>
---
 git-rebase.sh                            |   26 +++++-----
 t/t1020-subdirectory.sh                  |   22 ++++----
 t/t3050-subprojects-fetch.sh             |    2 +-
 t/t3404-rebase-interactive.sh            |    2 +-
 t/t5500-fetch-pack.sh                    |    2 +-
 t/t5700-clone-reference.sh               |    2 +-
 t/t7003-filter-branch.sh                 |    2 +-
 t/t7501-commit.sh                        |   74 +++++++++++++++---------------
 t/t9100-git-svn-basic.sh                 |   18 ++++----
 t/t9101-git-svn-props.sh                 |    6 +-
 t/t9102-git-svn-deep-rmdir.sh            |    6 +-
 t/t9104-git-svn-follow-parent.sh         |   50 ++++++++++----------
 t/t9105-git-svn-commit-diff.sh           |   10 ++--
 t/t9106-git-svn-commit-diff-clobber.sh   |   14 +++---
 t/t9107-git-svn-migrate.sh               |   40 ++++++++--------
 t/t9108-git-svn-glob.sh                  |    8 ++--
 t/t9110-git-svn-use-svm-props.sh         |    8 ++--
 t/t9111-git-svn-use-svnsync-props.sh     |    8 ++--
 t/t9112-git-svn-md5less-file.sh          |    4 +-
 t/t9113-git-svn-dcommit-new-file.sh      |    6 +-
 t/t9114-git-svn-dcommit-merge.sh         |    4 +-
 t/t9115-git-svn-dcommit-funky-renames.sh |    4 +-
 t/t9116-git-svn-log.sh                   |    4 +-
 t/test-lib.sh                            |    2 +-
 24 files changed, 162 insertions(+), 162 deletions(-)

diff --git a/git-rebase.sh b/git-rebase.sh
index 1583402..b48397e 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -59,7 +59,7 @@ continue_merge () {
 		die "$RESOLVEMSG"
 	fi
 
-	cmt=`cat $dotest/current`
+	cmt=`cat "$dotest/current"`
 	if ! git diff-index --quiet HEAD
 	then
 		if ! git-commit -C "$cmt"
@@ -84,14 +84,14 @@ continue_merge () {
 }
 
 call_merge () {
-	cmt="$(cat $dotest/cmt.$1)"
+	cmt="$(cat "$dotest/cmt.$1")"
 	echo "$cmt" > "$dotest/current"
 	hd=$(git rev-parse --verify HEAD)
 	cmt_name=$(git symbolic-ref HEAD)
-	msgnum=$(cat $dotest/msgnum)
-	end=$(cat $dotest/end)
+	msgnum=$(cat "$dotest/msgnum")
+	end=$(cat "$dotest/end")
 	eval GITHEAD_$cmt='"${cmt_name##refs/heads/}~$(($end - $msgnum))"'
-	eval GITHEAD_$hd='"$(cat $dotest/onto_name)"'
+	eval GITHEAD_$hd='"$(cat \"$dotest/onto_name\")"'
 	export GITHEAD_$cmt GITHEAD_$hd
 	git-merge-$strategy "$cmt^" -- "$hd" "$cmt"
 	rv=$?
@@ -140,10 +140,10 @@ do
 		}
 		if test -d "$dotest"
 		then
-			prev_head="`cat $dotest/prev_head`"
-			end="`cat $dotest/end`"
-			msgnum="`cat $dotest/msgnum`"
-			onto="`cat $dotest/onto`"
+			prev_head="`cat \"$dotest/prev_head\"`"
+			end="`cat \"$dotest/end\"`"
+			msgnum="`cat \"$dotest/msgnum\"`"
+			onto="`cat \"$dotest/onto\"`"
 			continue_merge
 			while test "$msgnum" -le "$end"
 			do
@@ -160,11 +160,11 @@ do
 		if test -d "$dotest"
 		then
 			git rerere clear
-			prev_head="`cat $dotest/prev_head`"
-			end="`cat $dotest/end`"
-			msgnum="`cat $dotest/msgnum`"
+			prev_head="`cat \"$dotest/prev_head\"`"
+			end="`cat \"$dotest/end\"`"
+			msgnum="`cat \"$dotest/msgnum\"`"
 			msgnum=$(($msgnum + 1))
-			onto="`cat $dotest/onto`"
+			onto="`cat \"$dotest/onto\"`"
 			while test "$msgnum" -le "$end"
 			do
 				call_merge "$msgnum"
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index b9cef34..5ed7fa4 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -21,7 +21,7 @@ LF='
 '
 
 test_expect_success 'update-index and ls-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git update-index --add one &&
 	case "`git ls-files`" in
 	one) echo ok one ;;
@@ -41,7 +41,7 @@ test_expect_success 'update-index and ls-files' '
 '
 
 test_expect_success 'cat-file' '
-	cd $HERE &&
+	cd "$HERE" &&
 	two=`git ls-files -s dir/two` &&
 	two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
 	echo "$two" &&
@@ -54,7 +54,7 @@ test_expect_success 'cat-file' '
 rm -f actual dir/actual
 
 test_expect_success 'diff-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	echo a >>one &&
 	echo d >>dir/two &&
 	case "`git diff-files --name-only`" in
@@ -74,7 +74,7 @@ test_expect_success 'diff-files' '
 '
 
 test_expect_success 'write-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	top=`git write-tree` &&
 	echo $top &&
 	cd dir &&
@@ -84,7 +84,7 @@ test_expect_success 'write-tree' '
 '
 
 test_expect_success 'checkout-index' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git checkout-index -f -u one &&
 	cmp one original.one &&
 	cd dir &&
@@ -93,7 +93,7 @@ test_expect_success 'checkout-index' '
 '
 
 test_expect_success 'read-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -f one dir/two &&
 	tree=`git write-tree` &&
 	git read-tree --reset -u "$tree" &&
@@ -107,27 +107,27 @@ test_expect_success 'read-tree' '
 '
 
 test_expect_success 'no file/rev ambiguity check inside .git' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git commit -a -m 1 &&
-	cd $HERE/.git &&
+	cd "$HERE/.git" &&
 	git show -s HEAD
 '
 
 test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && GIT_DIR=. git show -s HEAD
 '
 
 # This still does not work as it should...
 : test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && git show -s HEAD
 '
 
 test_expect_success 'detection should not be fooled by a symlink' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -fr foo.git &&
 	git clone -s .git another &&
 	ln -s another yetanother &&
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 34f26a8..4b74cc6 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -20,7 +20,7 @@ test_expect_success setup '
 '
 
 test_expect_success clone '
-	git clone file://`pwd`/.git cloned &&
+	git clone "file://`pwd`/.git" cloned &&
 	(git rev-parse HEAD; git ls-files -s) >expected &&
 	(
 		cd cloned &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 1113904..f321787 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -92,7 +92,7 @@ done
 EOF
 
 chmod a+x fake-editor.sh
-VISUAL="$(pwd)/fake-editor.sh"
+VISUAL="'$(pwd)/fake-editor.sh'"
 export VISUAL
 
 test_expect_success 'no changes are a nop' '
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 7b6798d..5489ffe 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -129,7 +129,7 @@ pull_to_client 2nd "B" $((64*3))
 
 pull_to_client 3rd "A" $((1*3)) # old fails
 
-test_expect_success "clone shallow" "git-clone --depth 2 file://`pwd`/. shallow"
+test_expect_success "clone shallow" "git-clone --depth 2 \"file://`pwd`/.\" shallow"
 
 (cd shallow; git count-objects -v) > count.shallow
 
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index 4e93aaa..8bb34f9 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -51,7 +51,7 @@ diff expected current'
 cd "$base_dir"
 
 test_expect_success 'cloning with reference (no -l -s)' \
-'git clone --reference B file://`pwd`/A D'
+'git clone --reference B "file://`pwd`/A" D'
 
 cd "$base_dir"
 
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index e935b20..1ab5392 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -107,7 +107,7 @@ test_expect_success 'use index-filter to move into a subdirectory' '
 		 "git ls-files -s | sed \"s-\\t-&newsubdir/-\" |
 	          GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
 			git update-index --index-info &&
-		  mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
+		  mv \"\$GIT_INDEX_FILE.new\" \"\$GIT_INDEX_FILE\"" directorymoved &&
 	test -z "$(git diff HEAD directorymoved:newsubdir)"'
 
 test_expect_success 'stops when msg filter fails' '
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index b151b51..f3d0ab9 100644
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -69,7 +69,7 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -i -e "s/a file/an amend commit/g" $1
+sed -i -e "s/a file/an amend commit/g" "$1"
 EOF
 chmod 755 editor
 
@@ -80,40 +80,40 @@ test_expect_success \
 test_expect_failure \
 	"passing -m and -F" \
 	"echo 'enough with the bongos' >file && \
-	 git-commit -F msg -m amending ."
+	git-commit -F msg -m amending ."
 
 test_expect_success \
-	"using message from other commit" \
-	"git-commit -C HEAD^ ."
+	 "using message from other commit" \
+	 "git-commit -C HEAD^ ."
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -i -e "s/amend/older/g" $1
+sed -i -e "s/amend/older/g" "$1"
 EOF
 chmod 755 editor
 
 test_expect_success \
-	"editing message from other commit" \
-	"echo 'hula hula' >file && \
-	 VISUAL=./editor git-commit -c HEAD^ -a"
+	 "editing message from other commit" \
+	 "echo 'hula hula' >file && \
+	  VISUAL=./editor git-commit -c HEAD^ -a"
 
 test_expect_success \
-	"message from stdin" \
-	"echo 'silly new contents' >file && \
-	 echo commit message from stdin | git-commit -F - -a"
+	 "message from stdin" \
+	 "echo 'silly new contents' >file && \
+	  echo commit message from stdin | git-commit -F - -a"
 
 test_expect_success \
-	"overriding author from command line" \
-	"echo 'gak' >file && \
-	 git-commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a"
+	 "overriding author from command line" \
+	 "echo 'gak' >file && \
+	  git-commit -m 'author' --author 'Rubber Duck <rduck@convoy.org>' -a"
 
 test_expect_success \
-	"interactive add" \
-	"echo 7 | git-commit --interactive | grep 'What now'"
+	 "interactive add" \
+	 "echo 7 | git-commit --interactive | grep 'What now'"
 
 test_expect_success \
-	"showing committed revisions" \
-	"git-rev-list HEAD >current"
+	 "showing committed revisions" \
+	 "git-rev-list HEAD >current"
 
 # We could just check the head sha1, but checking each commit makes it
 # easier to isolate bugs.
@@ -128,38 +128,38 @@ d381ac431806e53f3dd7ac2f1ae0534f36d738b9
 EOF
 
 test_expect_success \
-    'validate git-rev-list output.' \
-    'diff current expected'
+	'validate git-rev-list output.' \
+	'diff current expected'
 
 test_expect_success 'partial commit that involves removal (1)' '
 
-	git rm --cached file &&
-	mv file elif &&
-	git add elif &&
-	git commit -m "Partial: add elif" elif &&
-	git diff-tree --name-status HEAD^ HEAD >current &&
-	echo "A	elif" >expected &&
-	diff expected current
+	 git rm --cached file &&
+	 mv file elif &&
+	 git add elif &&
+	 git commit -m "Partial: add elif" elif &&
+	 git diff-tree --name-status HEAD^ HEAD >current &&
+	 echo "A elif" >expected &&
+	 diff -b expected current
 
 '
 
 test_expect_success 'partial commit that involves removal (2)' '
 
-	git commit -m "Partial: remove file" file &&
-	git diff-tree --name-status HEAD^ HEAD >current &&
-	echo "D	file" >expected &&
-	diff expected current
+	 git commit -m "Partial: remove file" file &&
+	 git diff-tree --name-status HEAD^ HEAD >current &&
+	 echo "D file" >expected &&
+	 diff -b expected current
 
 '
 
 test_expect_success 'partial commit that involves removal (3)' '
 
-	git rm --cached elif &&
-	echo elif >elif &&
-	git commit -m "Partial: modify elif" elif &&
-	git diff-tree --name-status HEAD^ HEAD >current &&
-	echo "M	elif" >expected &&
-	diff expected current
+	 git rm --cached elif &&
+	 echo elif >elif &&
+	 git commit -m "Partial: modify elif" elif &&
+	 git diff-tree --name-status HEAD^ HEAD >current &&
+	 echo "M elif" >expected &&
+	 diff -b expected current
 
 '
 
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 614cf50..c3585da 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -31,16 +31,16 @@ test_expect_success \
 	echo 'zzz' > bar/zzz &&
 	echo '#!/bin/sh' > exec.sh &&
 	chmod +x exec.sh &&
-	svn import -m 'import for git-svn' . $svnrepo >/dev/null &&
+	svn import -m 'import for git-svn' . '$svnrepo' >/dev/null &&
 	cd .. &&
 	rm -rf import &&
-	git-svn init $svnrepo"
+	git-svn init '$svnrepo'"
 
 test_expect_success \
     'import an SVN revision into git' \
     'git-svn fetch'
 
-test_expect_success "checkout from svn" "svn co $svnrepo '$SVN_TREE'"
+test_expect_success "checkout from svn" "svn co '$svnrepo' '$SVN_TREE'"
 
 name='try a deep --rmdir with a commit'
 test_expect_success "$name" "
@@ -169,7 +169,7 @@ test_expect_success "$name" "
 	svn up '$SVN_TREE' &&
 	test -f '$SVN_TREE'/exec-2.sh &&
 	test ! -L '$SVN_TREE'/exec-2.sh &&
-	git diff help $SVN_TREE/exec-2.sh"
+	git diff help '$SVN_TREE/exec-2.sh'"
 
 if test "$have_utf8" = t
 then
@@ -190,7 +190,7 @@ name='test fetch functionality (svn => git) with alternate GIT_SVN_ID'
 GIT_SVN_ID=alt
 export GIT_SVN_ID
 test_expect_success "$name" \
-    "git-svn init $svnrepo && git-svn fetch &&
+    "git-svn init '$svnrepo' && git-svn fetch &&
      git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a &&
      git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
      git diff a b"
@@ -220,16 +220,16 @@ test_expect_failure 'exit if remote refs are ambigious' "
         "
 
 test_expect_failure 'exit if init-ing a would clobber a URL' "
-        svnadmin create ${PWD}/svnrepo2 &&
-        svn mkdir -m 'mkdir bar' ${svnrepo}2/bar &&
+        svnadmin create '${PWD}/svnrepo2' &&
+        svn mkdir -m 'mkdir bar' '${svnrepo}2/bar' &&
         git config --unset svn-remote.svn.fetch \
                                 '^bar:refs/remotes/git-svn$' &&
-        git-svn init ${svnrepo}2/bar
+        git-svn init '${svnrepo}2/bar'
         "
 
 test_expect_success \
   'init allows us to connect to another directory in the same repo' "
-        git-svn init --minimize-url -i bar $svnrepo/bar &&
+        git-svn init --minimize-url -i bar '$svnrepo/bar' &&
         git config --get svn-remote.svn.fetch \
                               '^bar:refs/remotes/bar$' &&
         git config --get svn-remote.svn.fetch \
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index 5aac644..a1c85e0 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -52,7 +52,7 @@ EOF
 cd ..
 
 rm -rf import
-test_expect_success 'checkout working copy from svn' "svn co $svnrepo test_wc"
+test_expect_success 'checkout working copy from svn' "svn co '$svnrepo' test_wc"
 test_expect_success 'setup some commits to svn' \
 	'cd test_wc &&
 		echo Greetings >> kw.c &&
@@ -66,7 +66,7 @@ test_expect_success 'setup some commits to svn' \
 		svn commit -m "Propset Id" &&
 	cd ..'
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init '$svnrepo'"
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 
 name='test svn:keywords ignoring'
@@ -92,7 +92,7 @@ test_expect_success "propset CR on crlf files" \
 test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
 	"git-svn fetch &&
 	 git pull . remotes/git-svn &&
-	 svn co $svnrepo new_wc"
+	 svn co '$svnrepo' new_wc"
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh
index 4e08083..99c8840 100755
--- a/t/t9102-git-svn-deep-rmdir.sh
+++ b/t/t9102-git-svn-deep-rmdir.sh
@@ -9,12 +9,12 @@ test_expect_success 'initialize repo' "
 	mkdir -p deeply/nested/directory/number/2 &&
 	echo foo > deeply/nested/directory/number/1/file &&
 	echo foo > deeply/nested/directory/number/2/another &&
-	svn import -m 'import for git-svn' . $svnrepo &&
+	svn import -m 'import for git-svn' . '$svnrepo' &&
 	cd ..
 	"
 
 test_expect_success 'mirror via git-svn' "
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
 	git checkout -f -b test-rmdir remotes/git-svn
 	"
@@ -23,7 +23,7 @@ test_expect_success 'Try a commit on rmdir' "
 	git rm -f deeply/nested/directory/number/2/another &&
 	git commit -a -m 'remove another' &&
 	git-svn set-tree --rmdir HEAD &&
-	svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1
+	svn ls -R '$svnrepo' | grep ^deeply/nested/directory/number/1
 	"
 
 
diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 7ba7630..aa2bfe2 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -11,9 +11,9 @@ test_expect_success 'initialize repo' "
 	cd import &&
 	mkdir -p trunk &&
 	echo hello > trunk/readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
-	svn co $svnrepo wc &&
+	svn co '$svnrepo' wc &&
 	cd wc &&
 	echo world >> trunk/readme &&
 	poke trunk/readme &&
@@ -27,7 +27,7 @@ test_expect_success 'initialize repo' "
 	"
 
 test_expect_success 'init and fetch a moved directory' "
-	git-svn init --minimize-url -i thunk $svnrepo/thunk &&
+	git-svn init --minimize-url -i thunk '$svnrepo/thunk' &&
 	git-svn fetch -i thunk &&
 	test \"\`git rev-parse --verify refs/remotes/thunk@2\`\" \
            = \"\`git rev-parse --verify refs/remotes/thunk~1\`\" &&
@@ -38,7 +38,7 @@ test_expect_success 'init and fetch a moved directory' "
 	"
 
 test_expect_success 'init and fetch from one svn-remote' "
-        git config svn-remote.svn.url $svnrepo &&
+        git config svn-remote.svn.url '$svnrepo' &&
         git config --add svn-remote.svn.fetch \
           trunk:refs/remotes/svn/trunk &&
         git config --add svn-remote.svn.fetch \
@@ -52,9 +52,9 @@ test_expect_success 'init and fetch from one svn-remote' "
 
 test_expect_success 'follow deleted parent' "
         (svn cp -m 'resurrecting trunk as junk' \
-               $svnrepo/trunk@2 $svnrepo/junk ||
+               '$svnrepo/trunk@2' '$svnrepo'/junk ||
          svn cp -m 'resurrecting trunk as junk' \
-               -r2 $svnrepo/trunk $svnrepo/junk) &&
+               -r2 '$svnrepo/trunk' '$svnrepo/junk') &&
         git config --add svn-remote.svn.fetch \
           junk:refs/remotes/svn/junk &&
         git-svn fetch -i svn/thunk &&
@@ -67,10 +67,10 @@ test_expect_success 'follow deleted parent' "
 test_expect_success 'follow larger parent' "
         mkdir -p import/trunk/thunk/bump/thud &&
         echo hi > import/trunk/thunk/bump/thud/file &&
-        svn import -m 'import a larger parent' import $svnrepo/larger-parent &&
-        svn cp -m 'hi' $svnrepo/larger-parent $svnrepo/another-larger &&
+        svn import -m 'import a larger parent' import '$svnrepo/larger-parent' &&
+        svn cp -m 'hi' '$svnrepo/larger-parent' '$svnrepo/another-larger' &&
         git-svn init --minimize-url -i larger \
-          $svnrepo/another-larger/trunk/thunk/bump/thud &&
+          '$svnrepo/another-larger/trunk/thunk/bump/thud' &&
         git-svn fetch -i larger &&
         git rev-parse --verify refs/remotes/larger &&
         git rev-parse --verify \
@@ -83,23 +83,23 @@ test_expect_success 'follow larger parent' "
         "
 
 test_expect_success 'follow higher-level parent' "
-        svn mkdir -m 'follow higher-level parent' $svnrepo/blob &&
-        svn co $svnrepo/blob blob &&
+        svn mkdir -m 'follow higher-level parent' '$svnrepo/blob' &&
+        svn co '$svnrepo/blob' blob &&
         cd blob &&
                 echo hi > hi &&
                 svn add hi &&
                 svn commit -m 'hihi' &&
                 cd ..
-        svn mkdir -m 'new glob at top level' $svnrepo/glob &&
-        svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
-        git-svn init --minimize-url -i blob $svnrepo/glob/blob &&
+        svn mkdir -m 'new glob at top level' '$svnrepo/glob' &&
+        svn mv -m 'move blob down a level' '$svnrepo/blob' '$svnrepo/glob/blob' &&
+        git-svn init --minimize-url -i blob '$svnrepo/glob/blob' &&
         git-svn fetch -i blob
         "
 
 test_expect_success 'follow deleted directory' "
-	svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye &&
-	svn rm -m 'remove glob' $svnrepo/glob &&
-	git-svn init --minimize-url -i glob $svnrepo/glob &&
+	svn mv -m 'bye!' '$svnrepo/glob/blob/hi' '$svnrepo/glob/blob/bye' &&
+	svn rm -m 'remove glob' '$svnrepo/glob' &&
+	git-svn init --minimize-url -i glob '$svnrepo/glob' &&
 	git-svn fetch -i glob &&
 	test \"\`git cat-file blob refs/remotes/glob:blob/bye\`\" = hi &&
 	test \"\`git ls-tree refs/remotes/glob | wc -l \`\" -eq 1
@@ -118,9 +118,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  echo 'bad delete test 2' > \
 	   import/trunk/subversion/bindings/swig/perl/another-larger &&
 	cd import &&
-	  svn import -m 'r9270 test' . $svnrepo/r9270 &&
+	  svn import -m 'r9270 test' . '$svnrepo/r9270' &&
 	cd .. &&
-	svn co $svnrepo/r9270/trunk/subversion/bindings/swig/perl r9270 &&
+	svn co '$svnrepo/r9270/trunk/subversion/bindings/swig/perl' r9270 &&
 	cd r9270 &&
 	  svn mkdir native &&
 	  svn mv t native/t &&
@@ -130,7 +130,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  svn commit -m 'reorg test' &&
 	cd .. &&
 	git-svn init --minimize-url -i r9270-t \
-	  $svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t &&
+	  '$svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t' &&
 	git-svn fetch -i r9270-t &&
 	test \`git rev-list r9270-t | wc -l\` -eq 2 &&
 	test \"\`git ls-tree --name-only r9270-t~1\`\" = \
@@ -138,9 +138,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	"
 
 test_expect_success "track initial change if it was only made to parent" "
-	svn cp -m 'wheee!' $svnrepo/r9270/trunk $svnrepo/r9270/drunk &&
+	svn cp -m 'wheee!' '$svnrepo/r9270/trunk' '$svnrepo/r9270/drunk' &&
 	git-svn init --minimize-url -i r9270-d \
-	  $svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t &&
+	  '$svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t' &&
 	git-svn fetch -i r9270-d &&
 	test \`git rev-list r9270-d | wc -l\` -eq 3 &&
 	test \"\`git ls-tree --name-only r9270-t\`\" = \
@@ -150,7 +150,7 @@ test_expect_success "track initial change if it was only made to parent" "
 	"
 
 test_expect_success "track multi-parent paths" "
-	svn cp -m 'resurrect /glob' $svnrepo/r9270 $svnrepo/glob &&
+	svn cp -m 'resurrect /glob' '$svnrepo/r9270' '$svnrepo/glob' &&
 	git-svn multi-fetch &&
 	test \`git cat-file commit refs/remotes/glob | \
 	       grep '^parent ' | wc -l\` -eq 2
@@ -161,8 +161,8 @@ test_expect_success "multi-fetch continues to work" "
 	"
 
 test_expect_success "multi-fetch works off a 'clean' repository" "
-	rm -r $GIT_DIR/svn $GIT_DIR/refs/remotes $GIT_DIR/logs &&
-	mkdir $GIT_DIR/svn &&
+	rm -r '$GIT_DIR/svn' '$GIT_DIR/refs/remotes' '$GIT_DIR/logs' &&
+	mkdir '$GIT_DIR/svn' &&
 	git-svn multi-fetch
 	"
 
diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh
index 318e172..2e1eb75 100755
--- a/t/t9105-git-svn-commit-diff.sh
+++ b/t/t9105-git-svn-commit-diff.sh
@@ -8,7 +8,7 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo hello > readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
 	echo hello > readme &&
 	git update-index --add readme &&
@@ -27,16 +27,16 @@ prev=`git rev-parse --verify HEAD^1`
 test_expect_success 'test the commit-diff command' "
 	test -n '$prev' && test -n '$head' &&
 	git-svn commit-diff -r1 '$prev' '$head' '$svnrepo' &&
-	svn co $svnrepo wc &&
+	svn co '$svnrepo' wc &&
 	cmp readme wc/readme
 	"
 
 test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
-	svn import -m 'sub-directory' import $svnrepo/subdir &&
-	git-svn init --minimize-url $svnrepo/subdir &&
+	svn import -m 'sub-directory' import '$svnrepo/subdir' &&
+	git-svn init --minimize-url '$svnrepo/subdir' &&
 	git-svn fetch &&
 	git-svn commit-diff -r3 '$prev' '$head' &&
-	svn cat $svnrepo/subdir/readme > readme.2 &&
+	svn cat '$svnrepo/subdir/readme' > readme.2 &&
 	cmp readme readme.2
 	"
 
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index 79b7968..bb42339 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -8,14 +8,14 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo initial > file &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
 	echo initial > file &&
 	git update-index --add file &&
 	git commit -a -m 'initial'
 	"
 test_expect_success 'commit change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 	echo second line from svn >> file &&
 	poke file &&
@@ -27,7 +27,7 @@ test_expect_success 'commit change from svn side' "
 test_expect_failure 'commit conflicting change from git' "
 	echo second line from git >> file &&
 	git commit -a -m 'second line from git' &&
-	git-svn commit-diff -r1 HEAD~1 HEAD $svnrepo
+	git-svn commit-diff -r1 HEAD~1 HEAD '$svnrepo'
 	" || true
 
 test_expect_success 'commit complementing change from git' "
@@ -36,14 +36,14 @@ test_expect_success 'commit complementing change from git' "
 	git commit -a -m 'second line from svn' &&
 	echo third line from git >> file &&
 	git commit -a -m 'third line from git' &&
-	git-svn commit-diff -r2 HEAD~1 HEAD $svnrepo
+	git-svn commit-diff -r2 HEAD~1 HEAD '$svnrepo'
 	"
 
 test_expect_failure 'dcommit fails to commit because of conflict' "
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
 	git reset --hard refs/remotes/git-svn &&
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 	echo fourth line from svn >> file &&
 	poke file &&
@@ -67,7 +67,7 @@ test_expect_success 'dcommit does the svn equivalent of an index merge' "
 	"
 
 test_expect_success 'commit another change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 		echo third line from svn >> file &&
 		poke file &&
diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index 67fdf70..90bf786 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -4,7 +4,7 @@ test_description='git-svn metadata migrations from previous versions'
 . ./lib-git-svn.sh
 
 test_expect_success 'setup old-looking metadata' "
-	cp $GIT_DIR/config $GIT_DIR/config-old-git-svn &&
+	cp '$GIT_DIR/config' '$GIT_DIR/config-old-git-svn' &&
 	mkdir import &&
 	cd import &&
 		for i in trunk branches/a branches/b \
@@ -12,13 +12,13 @@ test_expect_success 'setup old-looking metadata' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . '$svnrepo'
 		cd .. &&
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
-	mv $GIT_DIR/svn/* $GIT_DIR/ &&
-	mv $GIT_DIR/svn/.metadata $GIT_DIR/ &&
-	rmdir $GIT_DIR/svn &&
+	mv '$GIT_DIR'/svn/* '$GIT_DIR/' &&
+	mv '$GIT_DIR/svn/.metadata' '$GIT_DIR/' &&
+	rmdir '$GIT_DIR/svn' &&
 	git update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn &&
 	git update-ref refs/heads/svn-HEAD refs/remotes/git-svn &&
 	git update-ref -d refs/remotes/git-svn refs/remotes/git-svn
@@ -28,20 +28,20 @@ head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
 test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
 
 test_expect_success 'initialize old-style (v0) git-svn layout' "
-	mkdir -p $GIT_DIR/git-svn/info $GIT_DIR/svn/info &&
-	echo $svnrepo > $GIT_DIR/git-svn/info/url &&
-	echo $svnrepo > $GIT_DIR/svn/info/url &&
+	mkdir -p '$GIT_DIR/git-svn/info' '$GIT_DIR/svn/info' &&
+	echo '$svnrepo' > '$GIT_DIR/git-svn/info/url' &&
+	echo '$svnrepo' > '$GIT_DIR/svn/info/url' &&
 	git-svn migrate &&
-	! test -d $GIT_DIR/git-svn &&
+	! test -d '$GIT_DIR/git-svn' &&
 	git rev-parse --verify refs/remotes/git-svn^0 &&
 	git rev-parse --verify refs/remotes/svn^0 &&
-	test \`git config --get svn-remote.svn.url\` = '$svnrepo' &&
+	test \"\`git config --get svn-remote.svn.url\`\" = \"$svnrepo\" &&
 	test \`git config --get svn-remote.svn.fetch\` = \
              ':refs/remotes/git-svn'
 	"
 
 test_expect_success 'initialize a multi-repository repo' "
-	git-svn init $svnrepo -T trunk -t tags -b branches &&
+	git-svn init '$svnrepo' -T trunk -t tags -b branches &&
 	git config --get-all svn-remote.svn.fetch > fetch.out &&
 	grep '^trunk:refs/remotes/trunk$' fetch.out &&
 	test -n \"\`git config --get svn-remote.svn.branches \
@@ -76,14 +76,14 @@ test_expect_success 'multi-fetch works on partial urls + paths' "
 test_expect_success 'migrate --minimize on old inited layout' "
 	git config --unset-all svn-remote.svn.fetch &&
 	git config --unset-all svn-remote.svn.url &&
-	rm -rf $GIT_DIR/svn &&
+	rm -rf '$GIT_DIR/svn' &&
 	for i in \`cat fetch.out\`; do
 		path=\`expr \$i : '\\([^:]*\\):.*$'\`
 		ref=\`expr \$i : '[^:]*:refs/remotes/\\(.*\\)$'\`
 		if test -z \"\$ref\"; then continue; fi
 		if test -n \"\$path\"; then path=\"/\$path\"; fi
-		( mkdir -p $GIT_DIR/svn/\$ref/info/ &&
-		echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
+		( mkdir -p '$GIT_DIR'/svn/\$ref/info/ &&
+		echo '$svnrepo'\$path > '$GIT_DIR'/svn/\$ref/info/url ) || exit 1;
 	done &&
 	git-svn migrate --minimize &&
 	test -z \"\`git config -l |grep -v '^svn-remote\.git-svn\.'\`\" &&
@@ -99,13 +99,13 @@ test_expect_success 'migrate --minimize on old inited layout' "
 
 test_expect_success  ".rev_db auto-converted to .rev_db.UUID" "
 	git-svn fetch -i trunk &&
-	expect=$GIT_DIR/svn/trunk/.rev_db.* &&
+	expect=\"\`find \"\$GIT_DIR\"/svn/trunk/ -name '.rev_db.*'\`\" &&
 	test -n \"\$expect\" &&
-	mv \$expect $GIT_DIR/svn/trunk/.rev_db &&
+	mv \"\$expect\" \"\$GIT_DIR\"/svn/trunk/.rev_db &&
 	git-svn fetch -i trunk &&
-	test -L $GIT_DIR/svn/trunk/.rev_db &&
-	test -f \$expect &&
-	cmp \$expect $GIT_DIR/svn/trunk/.rev_db
+	test -L \"\$GIT_DIR\"/svn/trunk/.rev_db &&
+	test -f \"\$expect\" &&
+	cmp \"\$expect\" \"\$GIT_DIR\"/svn/trunk/.rev_db
 	"
 
 test_done
diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh
index db4344c..c6dc0ef 100755
--- a/t/t9108-git-svn-glob.sh
+++ b/t/t9108-git-svn-glob.sh
@@ -14,8 +14,8 @@ test_expect_success 'test refspec globbing' "
 	mkdir -p trunk/src/a trunk/src/b trunk/doc &&
 	echo 'hello world' > trunk/src/a/readme &&
 	echo 'goodbye world' > trunk/src/b/readme &&
-	svn import -m 'initial' trunk $svnrepo/trunk &&
-	svn co $svnrepo tmp &&
+	svn import -m 'initial' trunk '$svnrepo/trunk' &&
+	svn co '$svnrepo' tmp &&
 	cd tmp &&
 		mkdir branches tags &&
 		svn add branches tags &&
@@ -38,7 +38,7 @@ test_expect_success 'test refspec globbing' "
 		poke tags/end/src/b/readme &&
 		svn commit -m 'nothing to see here'
 		cd .. &&
-	git config --add svn-remote.svn.url $svnrepo &&
+	git config --add svn-remote.svn.url '$svnrepo' &&
 	git config --add svn-remote.svn.fetch \
 	                 'trunk/src/a:refs/remotes/trunk' &&
 	git config --add svn-remote.svn.branches \
@@ -60,7 +60,7 @@ echo nothing to see here >> expect.two
 cat expect.end >> expect.two
 
 test_expect_success 'test left-hand-side only globbing' "
-	git config --add svn-remote.two.url $svnrepo &&
+	git config --add svn-remote.two.url '$svnrepo' &&
 	git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
 	git config --add svn-remote.two.branches \
 	                 'branches/*:refs/remotes/two/branches/*' &&
diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh
index 6235af4..d4ab01f 100755
--- a/t/t9110-git-svn-use-svm-props.sh
+++ b/t/t9110-git-svn-use-svm-props.sh
@@ -8,11 +8,11 @@ test_description='git-svn useSvmProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svm repo' "
-	svnadmin load -q $rawsvnrepo < ../t9110/svm.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/mirror/arr &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/mirror/argh &&
+	svnadmin load -q '$rawsvnrepo' < ../t9110/svm.dump &&
+	git-svn init --minimize-url -R arr -i bar '$svnrepo/mirror/arr' &&
+	git-svn init --minimize-url -R argh -i dir '$svnrepo/mirror/argh' &&
 	git-svn init --minimize-url -R argh -i e \
-	  $svnrepo/mirror/argh/a/b/c/d/e &&
+	  '$svnrepo/mirror/argh/a/b/c/d/e' &&
 	git config svn.useSvmProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9111-git-svn-use-svnsync-props.sh b/t/t9111-git-svn-use-svnsync-props.sh
index ec7dedd..936f023 100755
--- a/t/t9111-git-svn-use-svnsync-props.sh
+++ b/t/t9111-git-svn-use-svnsync-props.sh
@@ -8,10 +8,10 @@ test_description='git-svn useSvnsyncProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svnsync repo' "
-	svnadmin load -q $rawsvnrepo < ../t9111/svnsync.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/bar &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/dir &&
-	git-svn init --minimize-url -R argh -i e $svnrepo/dir/a/b/c/d/e &&
+	svnadmin load -q '$rawsvnrepo' < ../t9111/svnsync.dump &&
+	git-svn init --minimize-url -R arr -i bar '$svnrepo/bar' &&
+	git-svn init --minimize-url -R argh -i dir '$svnrepo/dir' &&
+	git-svn init --minimize-url -R argh -i e '$svnrepo/dir/a/b/c/d/e' &&
 	git config svn.useSvnsyncProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh
index 08313bb..b095583 100755
--- a/t/t9112-git-svn-md5less-file.sh
+++ b/t/t9112-git-svn-md5less-file.sh
@@ -38,8 +38,8 @@ PROPS-END
 
 EOF
 
-test_expect_success 'load svn dumpfile' "svnadmin load $rawsvnrepo < dumpfile.svn"
+test_expect_success 'load svn dumpfile' "svnadmin load '$rawsvnrepo' < dumpfile.svn"
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init '$svnrepo'"
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 test_done
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
index 9ef0db9..0088c75 100755
--- a/t/t9113-git-svn-dcommit-new-file.sh
+++ b/t/t9113-git-svn-dcommit-new-file.sh
@@ -15,14 +15,14 @@ test_description='git-svn dcommit new files over svn:// test'
 
 start_svnserve () {
 	svnserve --listen-port $SVNSERVE_PORT \
-	         --root $rawsvnrepo \
+	         --root '$rawsvnrepo' \
 	         --listen-once \
 	         --listen-host 127.0.0.1 &
 }
 
 test_expect_success 'start tracking an empty repo' "
-	svn mkdir -m 'empty dir' $svnrepo/empty-dir &&
-	echo anon-access = write >> $rawsvnrepo/conf/svnserve.conf &&
+	svn mkdir -m 'empty dir' '$svnrepo/empty-dir' &&
+	echo anon-access = write >> '$rawsvnrepo/conf/svnserve.conf' &&
 	start_svnserve &&
 	git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
 	git svn fetch
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
index d6ca955..64ec7fd 100755
--- a/t/t9114-git-svn-dcommit-merge.sh
+++ b/t/t9114-git-svn-dcommit-merge.sh
@@ -35,7 +35,7 @@ EOF
 }
 
 test_expect_success 'setup svn repository' "
-	svn co $svnrepo mysvnwork &&
+	svn co '$svnrepo' mysvnwork &&
 	mkdir -p mysvnwork/trunk &&
 	cd mysvnwork &&
 		big_text_block >> trunk/README &&
@@ -45,7 +45,7 @@ test_expect_success 'setup svn repository' "
 	"
 
 test_expect_success 'setup git mirror and merge' "
-	git svn init $svnrepo -t tags -T trunk -b branches &&
+	git svn init '$svnrepo' -t tags -T trunk -b branches &&
 	git svn fetch &&
 	git checkout --track -b svn remotes/trunk &&
 	git checkout -b merge &&
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 182299c..653578d 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -8,12 +8,12 @@ test_description='git-svn dcommit can commit renames of files with ugly names'
 . ./lib-git-svn.sh
 
 test_expect_success 'load repository with strange names' "
-	svnadmin load -q $rawsvnrepo < ../t9115/funky-names.dump &&
+	svnadmin load -q '$rawsvnrepo' < ../t9115/funky-names.dump &&
 	start_httpd
 	"
 
 test_expect_success 'init and fetch repository' "
-	git svn init $svnrepo &&
+	git svn init '$svnrepo' &&
 	git svn fetch &&
 	git reset --hard git-svn
 	"
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index 0d4e6b3..70c0c5f 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -14,9 +14,9 @@ test_expect_success 'setup repository and import' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . '$svnrepo'
 		cd .. &&
-	git-svn init $svnrepo -T trunk -b branches -t tags &&
+	git-svn init '$svnrepo' -T trunk -b branches -t tags &&
 	git-svn fetch &&
 	git reset --hard trunk &&
 	echo bye >> README &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index cc1253c..a68415f 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -229,7 +229,7 @@ test_create_repo () {
 	repo="$1"
 	mkdir "$repo"
 	cd "$repo" || error "Cannot setup test environment"
-	"$GIT_EXEC_PATH/git" init --template=$GIT_EXEC_PATH/templates/blt/ >/dev/null 2>&1 ||
+	"$GIT_EXEC_PATH/git" init --template="$GIT_EXEC_PATH/templates/blt/" >/dev/null 2>&1 ||
 	error "cannot run git init -- have you built things yet?"
 	mv .git/hooks .git/hooks-disabled
 	cd "$owd"
-- 
1.5.3.1

^ permalink raw reply related	[relevance 11%]

* Git User's Survey 2007 summary - comparison with previous survey
@ 2007-10-12 22:07  1% Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2007-10-12 22:07 UTC (permalink / raw)
  To: git

It's been more than a year since last Git User's Survey. It would be
interesting to find what changed since then. Therefore the idea to
have another survey.

This is partial comparison of Git User's Survey 2007,
(ending at state from 28 September 2007) with previous
survey.

The current survey can be found here:
  http://www.survey.net.nz/survey.php?94e135ff41e871a1ea5bcda3ee1856d9
  http://tinyurl.com/26774s

The data for current, 2007 survey can be found here:

The data for previous, 2006 survey was taken from following wiki page
  http://git.or.cz/gitwiki/GitSurvey2006

---
There were 683 individual responses in 2007 survey.
There were around 117 responses in 2006 survey.

There are 62 questions in 2007 survey, and 31 questions (half of
the number) in 2006 survey.


About you
~~~~~~~~~

01. What country are you in?

  Answer                         | Old | Count
  ------------------------------------------------
  Algeria                        |     | 1
  Argentina                      |     | 3
  Australia                      | 3   | 25
  Austria                        | 2   | 9
  Belarus                        | 1   |
  Belgium                        |     | 5
  Brazil                         | 2   | 20
  Bulgaria                       |     | 1
  Canada                         | 3   | 44
  Chile                          | 1   | 2
  China                          | 2   | 4
  Colombia                       |     | 2
  Czech Republic                 | 2   | 10
  Denmark                        | 4   | 7
  Ecuador                        |     | 1
  Estonia                        | 1   | 1
  Europe                         | 1   | 1
  Finland                        | 5   | 23
  France                         | 6   | 36
  Germany                        | 14  | 64
  Greece                         |     | 3
  Hungary                        |     | 2
  India                          | 1   | 13
  Ireland                        |     | 2
  Israel                         |     | 6
  Italy                          | 3   | 14
  Japan                          |     | 4
  Jersey                         |     | 1
  Latvia                         |     | 1
  Lithuania                      | 1   |
  Malaysia                       |     | 1
  Mexico                         |     | 1
  Netherlands                    | 3   | 15
  New Zealand                    |     | 5
  Norway                         | 1   | 14
  Philippines                    | 1   | 3
  Poland                         | 3   | 6
  Portugal                       |     | 2
  Puerto Rico                    |     | 1
  Romania                        |     | 1
  Russian Federation             | 2   | 6
  Samoa                          |     | 1
  Serbia                         |     | 1
  Singapore                      |     | 2
  Slovak Republic                |     | 1
  Slovenia                       |     | 2
  South Africa                   | 1   | 4
  Spain                          | 2   | 11
  Sri Lanka                      |     | 1
  Sweden                         | 6   | 14
  Switzerland                    | 1   | 15
  UAE                            | 1   |
  UK / US                        |     | 1
  United Kingdom                 | 8   | 40
  United States of America       | 35  | 218
  Venezuela                      |     | 1
  Vietnam                        | 1   | 1
  ------------------------------------------------
  Base                           |     | 673 / 683
  Total (sum)                    | 117 | 673

England, Scotland and British Isles counts as United Kingdom here.
Table is sorted in alphabetical order.

As before most Git users are in the USA.

There are quite a bit of new countries, only two vanished.  Note that
current survey has much more responses, so it is expected.


02. What is your preferred non-programming language?

This is multiple answers question, although most people
gave only one preferred language.

  Answer                         | Old | Count
  ------------------------------------------------
  Afrikaans                      |     | 1
  Belarusian                     | 1   |
  Bulgarian                      |     | 1
  Castellano                     |     | 2
  Catalan                        |     | 1
  Chinese                        | 1   | 2
  Czech                          | 2   | 10
  Danish                         | 5   | 6
  Dutch                          | 4   | 12
  English                        | 71  | 416
  Estonian                       | 1   |
  Finnish                        | 4   | 16
  French                         | 5   | 33
  Galician                       |     | 1
  German                         | 12  | 58
  Greek                          |     | 2
  Hebrew                         |     | 1
  HibernoEnglish                 |     | 1
  Hungarian                      |     | 3
  Italian                        | 3   | 9
  Japanese                       | 1   | 1
  LSF (French sign language)     |     | 1
  Norwegian                      |     | 4
  Polish                         | 3   | 5
  Portuguese                     |     | 10
  Romanian                       |     | 1
  Russian                        | 4   | 13
  Serbian                        |     | 1
  Slovenian                      |     | 2
  Spanish                        | 4   | 13
  Swedish                        | 5   | 13
  Swiss                          |     | 1
  Ukrainian                      |     | 1
  Vietnamese                     | 1   | 1

  invalid (computer language)    | ?   | 37
  not understood                 | ?   | 4
  ------------------------------------------------
  Base                           |     | 662 / 683
  Total (sum)                    | 127 | 683

Most of git users prefer English language, at least for dealing with
computers, the same as before.

In previous survey summary the invalid responses were not enumerated.

The question itself is not well formulated, as one can see from the
number of answers with computer language, and "not understood"
answers.  I am not native English speaker, but there were suggestions
to use "natural language" instead of "non-programming language".  The
question is formulated the same as in previous survey.


03. How old are you?
04. Which programming languages you are proficient with?

Those are new questions, which were not present in previous survey.


Getting started with GIT
~~~~~~~~~~~~~~~~~~~~~~~~

05. How did you hear about GIT?

This question is present in both current (2007) and previous (2006)
survey.  But because it uses free-form answer, and tabularization
(dividing data in categories and generating histogram / counting
occurences) is quite different it is not easy to compare results.

In Git User's Survey 2006 (prevuius survey) the dominant source was
LKML (Linux Kernel Mailing List) with 74 / 115 responses, with LWN
leading the rest with 11 / 115 count.

Although LKML still dominates the table for current survey, it is not
by such a wide margin (109/658 = 17% as compared to 74/115 = 64% in
previous one).  Many people heard about git because Linux kernel uses
it; Linus Torvalds presentation (talk) at Google (Google Video and
YouTube) got also high count, bit higher than LWN.

But there was no "I wrote it" response in current survey, though...


06. Did you find GIT easy to learn?

  Answer                         | Old | Count
  ------------------------------------------------
  very easy                      | 6   | 38
  easy                           | 21  | 136
  reasonably                     | 64  | 318
  hard                           | 23  | 131
  very hard                      | 3   | 33
  ------------------------------------------------
  Base                           |     | 656 / 683
  Total (sum)                    | 117 | 656

Nice gaussian curve both for current survey, and previous year survey
data.  Most users find GIT reasonably easy to use.


07. What helped you most in learning to use it?

TO DO. This again is a free-form question, present in both surveys.
For current (2007) survey data is not even tabularized yet, although
(some) of responses got listed (without a count).  I don't think
comparison with previous result is any interesting, but previous year
data can provide at least some hint on how to divide answers into
categories.


08. What did you find hardest?

TO DO. Yet another free-form question, present in both surveys.
Tabularized for 2006 survey, listed without count for 2007 survey, as
for previous question.


09. When did you start using git? From which version?

TO DO. Again free-form question.  Note that in previous survey this
question consisted only of the first part, and read "When did you
start using git?", so it is date that got tabularized, not git version
(mostly).  Analysis of current survey data is unfinished, and only
answers in which there was given git version explicitely got
tabularized.  For comparison we would need analysis of answers giving
date; and even then I don't think it would be especially useful,
unless very coarse-grained (which year for example).


Other SCMs
~~~~~~~~~~

10. What other SCMs did/do you use?
11. Why did you choose GIT?
12. Why did you choose other SCMs?
13. What would you require from GIT to enable you to change,
    if you use other SCM for your project?
14. Did you import your repository from foreign SCM? What SCM?
15. What tool did you use for import?
16. Do your GIT repository interact with other SCM? Which SCM?
17. What tool did/do you use to interact?

This whole section is new, and was not present in previous survey.


How you use GIT
~~~~~~~~~~~~~~~

18. Do you use GIT for work, unpaid projects, or both?

This question had slightly different wording in 2006 survey:
"How you use GIT? Do you use GIT for ...".

  Answer / Purpose               | Old | Count
  ------------------------------------------------
  work                           | 14  | 56
  unpaid projects                | 50  | 212
  both                           | 53  | 377
  ------------------------------------------------
  Base                           |     | 645 / 683
  Total (sum)                    | 117 | 645

In the previous survey unpaid projects (only unpaid) were slightly
less than half of answers (43 %), while current survey shows that
[only] around a third of git users use it only for unpaid projects.
So we see more git used for work.


19. How do you obtain GIT?

  Answer                         | Old | Count
  ------------------------------------------------
  binary package                 | 31  | 283
  source tarball                 | 33  | 210
  pull from main repository      | 53  | 153
  ------------------------------------------------
  Base                           |     | 646 / 683
  Total (sum)                    | 117 | 646

As one can see a year ago pull from main repository dominated, while
now binary package dominates, and pull is least used.  At least among
people who answered Git User's Survey; the difference might be caused
by the fact that previous survey was distributed mainly among readers
of git mailing list, who run latest 'master' or even 'next' version,
and often contribute to git (see also question 30, "Does git.git
repository include code produced by you?").

On the other hand the difference might be caused by the fact that more
distributions have got git, or that git is more mature and there is no
need to run development version and/or the fact that x.y.z is now
development version following 'master' and not 'maint', and includes
new features.


20. What hardware platforms do you use GIT on?

This is free-form question, tabularized for both current and previous
survey, but tabularized (slightly) differently.  It is not suprising,
as extracting architecture and dividing into categories was doneby two
different people:  Paolo Ciarrocchi (if I remember correctly) for 2006
survey, and Jakub Narebski (me) for 2007.

Moreover I guess that the _comparison_ is not very interesting; the
current data is.

Hardware platfrom tables should relly be generated by someone better
versed in computer architecture.


21. What OS (please include the version) do you use GIT on?

This question is also free-form.  For 2006 survey there is generic
count, and two tables: for Linux (distribution or kernel), and for
other operating systems.  The table for 2007 survey is slightly less
generic than the 2006 count, but there are no OS version tables.
There is much more data, and more data without version number.

Perhaps we should have provided examples of answers to this
question...

  Answer                         | Old  | Count
  ---------------------------------------------
  AIX                            | 1    | 1
  FreeBSD                        | 4    | 16
  OpenBSD                        | -    | 3
  NetBSD                         | 1    | -
  HP-UX                          | 1    | 1
  IRIX                           | 1    | -
  Linux                          | 167? | 582
  MS Windows (Cygwin)            | 14   | 22
  MS Windows (other)             |      | 36
  MacOS X / Darwin               | 11   | 94
  Solaris                        | 3    | 11
  SunOS                          | -    | 5
  ---------------------------------------------

Note that one person can use git on more than one operating system.
The number for Linux from 2006 survey is taken as total for Linux
table. "MS Windows (other)" means msys (native) version, or
unspecified whether Cygwin or MinGW/MSys.  If I remember correctly
there were no native Windows version (which is currently under
development) during previous survey.

Most is Linux, as before.  MacOS X is quite a percentage in current
survey, and dominates among non-Linux OS, coming before MS Windows.


22. What projects do you track (or download) using GIT
    (or git web interface)?

This question was not present in previous survey.


23. How many people do you collaborate with using GIT?

TO DO. This is free-form question; analysis for current survey is not
done yet.  The answer is not always simple number, but even those
answers which are limited to simple number (or contain simple number)
are not done yet.

I have posted question if first post in the thread about what ranges
(what categories) should be used here.  I haven't received any answer
yet.

Previous survey have table in two parts: first histogram of simple
number of people, second with names of communities (Cairo, Linux
kernel, U-Boot,...).

24. How big are the repositories that you work on?

TO DO. To be done *both* for 2007 (current) survey, and for 2006 one.


25. How many different projects do you manage using GIT?

This question was not present in previous survey.

Previous survey has empty question in this place, between those
questions.


26. Which porcelains do you use?
27. Which git GUI do you use?
28. Which (main) git web interface do you use for your projects?

The list of porcelains is different for previous and current
survey.  Git GUIs were moved to the next question in the 2007 survey,
and web interfaces to second next.

Note that there is some ambiguity concerning git-gui: it was put in
current survey in the GUI question only, while some people consider it
[also] porcelain (and put is as 'other' in porcelain).

Multiple answers (one can use more than one porcelain).

  Answer (multiple choice)       | Old | Count
  ----------------------------------------------
  core-git                       | 62  | 558
  cogito                         | 22  | 56

  Patch management interface:    : 13  : 57
  ..............................................
  StGIT                          | 11  | 41
  Guilt (formerly gq)            | n/a | 13
  pg (deprecated)                | 2   | 3
  ----------------------------------------------

One has to take into account the fact that neither Cogito nor pg
(Patchy GIT) were deprecated during previous survey.  Cogito got
deprecated because all of its functionality got moved in some way to
core git, while Petr 'Pasky' Baudis, main Cogito developer, didn't
have time for catching up to new git features.

Guilt is so new that it just simply was not yet created during
previous survey.


29. How do you publish/propagate your changes?

This question was not present in previous survey.


30. Does git.git repository include code produced by you?

(Previous survey had bad English here: "Is the git.git repository
including codes produced by you?")

  Answer                         | Old | Count
  ------------------------------------------------
  Yes                            | 73  | 99
  No                             | 34  | 512
  ------------------------------------------------
  Base                           |     | 611 / 683
  Total (sum)                    | 107 | 611

Complete reversion: from most survey participants having their
code in git.git (around 70%) a year ago to around a small amount
(around 16%) currently (!).

This might be cause by the fact that (I think) previous survey was
known mostly to people reading git mailing list, who often send their
own patches to this list.  Therefore there it would be nice to have
"How did you heard about this survey?" question.  (It would also help
finding where it is worth to send notice if/when we would want to make
another survey.)

Note also the following little fact:

  $ git shortlog -s --all --before="01-08-2006" | wc -l
  119 (and around 117 individual responses in 2006 survey)
  $ git shortlog -s --all --before="01-10-2007" | wc -l
  215 (and 683 individual responses in 2007 survey)

So it is simply not possible to have the same percentage of git
developers among git users (or rather git survey participants): 70%
out of 683 users is more than 465, which is more than git.git has
developers.


Internationalization
~~~~~~~~~~~~~~~~~~~~

31. Is translating GIT required for wider adoption?
32. What do you need translated?
33. For what language do you need translation for?

This whole section is new, and was not present in previous survey.


What you think of GIT
~~~~~~~~~~~~~~~~~~~~~

34. Overall, how happy are you with GIT?

  Answer                         | Old | Count
  ------------------------------------------------
  unhappy                        | 1   | 13
  not so happy                   | 19  | 36
  happy                          | 53  | 179
  very happy                     | 41  | 302
  completely ecstatic            | 1   | 112
  ------------------------------------------------
  Base                           |     | 642 / 683
  Total (sum)                    | 115 | 642

During the year the balance shifted slightly in the positive
direction: from mostly happy to very happy, to mostly very happy
leaning to happy.  And we have much more percentage of completely
ecstatic.

Good work!


35. How does GIT compare to other SCM tools you have used?

  Answer                         | Old | Count
  ------------------------------------------------
  Better                         | 80  | 505
  Equal (comparable)             | 20  | 96
  Worse                          | 8   | 30
  ------------------------------------------------
  Base                           |     | 631 / 683
  Total (sum)                    | 108 | 631

Here not much changed. The shape of this histogram is almost the same,
with slight shift towards "better than other SCMs used".

Note that 2006 survey has "Equal (or uncomparable)" instead of
"Equal (comparable)" as it is now.


36. What do you like about using GIT?

TO DO. Yet another free-form question. Tabularized for 2006 survey,
most encountered answers listed without count for 2007 survey.


37. What would you most like to see improved about GIT?
    (features, bugs, plug-ins, documentation, ...)

TO DO. As above: tabularized somewhat for previous survey, with the
list of ideas (divided broadly into categories) below the table; with
some ideas dropped.  For current survey there is only list of most
commonly encountered, and most interesting ideas.

Some of the 2006 ideas got implemented, or are being implemented, like
better documentation (Git User's Manual, documenting options), shallow
clones, win32 native binaries (via MinGS, in development), subproject
support (plumbing and beginnings of porcelain), libification and
builtinification (GSoC projects), increased verbosity when needed and
making error messages more helpful, graphical merges (git-mergetool:
interface to file-level graphical mergers like Meld, KDiff3 etc.), per
user configuration (~/.gitconfig rather that ~/.gitrc, and there is
even system wide configuration).  Some of ideas are repeated (like
"The Git Book" idea, although "Git User's Manual" fills it somewhat),
some ideas provided too hard (e.g. lazy clone aka remote alternates)
or without someone to implement them.  Some got abandoned, some will
probably never get implemented.

Even some suggestions in 2007 survey are actually implemented already,
for example git development Changelog (present in the form of
RelNotes), shallow clone support, submodules support. This means that
new features are not very well announced (which was also one of
comments in current survey).


38. If you want to see GIT more widely used, what do you think
     we could do to make this happen?

TO DO. List of suggestions for 2006 survey; for current 2007 survey
only two most striking.


Changes in GIT (since year ago, or since you started using it)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

39. Did you participate in previous Git User's Survey?
40. What improvements you wanted got implemented?
41. What improvements you wanted didn't get implemented?
42. How do you compare current version with version from year ago?
43. Which of the new features do you use?

This whole section is of course new (Git User's Survey 2006 was first
git survey ever; git is not very much older than that), and was not
present in previous survey.


Documentation
~~~~~~~~~~~~~

44. Do you use the GIT wiki?
45. Do you find GIT wiki useful?

Previous survey has two questions in one here: "Do you use the GIT
wiki? If yes, do you find it useful?".  This made it hard to
distinguish if "no" means "no I don't use GIT wiki" or "no it is not
useful".

This was one of the improvements over previous version of survey.


46. Do you contribute to GIT wiki?

This question was not present in previous survey.


47. Do you find GIT's on-line help (homepage, documentation) useful?

In 2007 survey there is additional "somewhat useful" answer, which was
not present in the 2006 survey.

  Answer                         | Old | Count
  --------------------------------------------
  Yes                            | 88  | 377
  No                             | 20  | 28
  Somewhat                       | -   | 172
  ------------------------------------------
  Base                           |     | 577 / 683
  Total (sum)                    | 108 | 577

The results are similar: most users find online help useful.


47b. What is your favourite user documentation for any software
     projects or products you have used?

This question is present in 2006 survey, and was removed in current
one. The idea behind question was I guess to have the results in hand
if git ever was to change documentation format. Most likely current
format of documentation (AsciiDoc), or at least idea behind it
(it should be possible to read sources, editing sources without
specialized editor support should be easy even for people who don't
know the format) is here to stay.


48. Do you find help distributed with GIT useful
    (manpages, manual, tutorial, HOWTO, release notes)?
49. Did/Do you contribute to GIT documentation?

Those questions were not present in previous survey.


50. What could be improved on the GIT homepage?

TO DO. List of suggestions for 2006 survey, nothing yet for 2007
survey.


51. What topics would you like to have on GIT wiki?
52. What could be improved in GIT documentation?

Those questions were not present in previous survey.


Getting help, staying in touch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

53. Have you tried to get GIT help from other people?

  Answer                         | Old | Count
  ------------------------------------------------
  Yes                            | 68  | 357
  No                             | 45  | 261
  ------------------------------------------------
  Base                           |     | 618 / 683
  Total (sum)                    | 113 | 618

Around 60% of people tried to get GIT help from other people,
for both current (2007) and previous (2006) survey.


54. If yes, did you get these problems resolved quickly
    and to your liking?

  Answer                         | Old | Count
  --------------------------------------------
  Yes                            | 68  | 326
  No                             | 45  | 53
  ------------------------------------------
  Base                           |     | 379 / 683
  Total (sum)                    | 113 | 379

The precentage was a bit worse during earlier survey (around 60%) than
for corrent one (around 86%).

This might be caused by the fact that git is now more userfriendly,
and has more features, and problems are easier to resolve.


55. Would commerical (paid) support from a support vendor
    be of interest to you/your organization?

This question was not present in previous survey. It was requested
during an RFC for this year (2007) survey.


56. Do you read the mailing list?

  Answer                         | Old | Count
  ------------------------------------------------
  Yes                            | 67  | 204
  No                             | 50  | 406
  ------------------------------------------------
  Base                           |     | 610 / 683
  Total (sum)                    | 117 | 610

Note that 2006 version had "subscribe" instead of "read" in this
question.  Even despite that the number of people reading git mailing
list decreased from more than half (around 57%) to around third
(around 33%).  This might be caused by the fact that notice / info
about Git User's Survey 2006 was distributed mainly among git mailing
list and among mailing lists for projects which use git (see also
commets to questions 19 and 30).

The fact that only one third of git users are reading mailing list
(which is nevertheless quite large percentage) means that features
_have_ to be documented somewhere besides mailing list archive and
logs (commit messages).


57. If yes, do you find the mailing list useful?
58. Do you find traffic levels on GIT mailing list OK?

Previous survey has two questions in one here: "If yes, do you find it
useful, and traffic levels OK?".  They were split in current survey.


59. Do you use the IRC channel (#git on irc.freenode.net)?

  Answer                         | Old | Count
  ------------------------------------------------
  Yes                            | 23  | 182
  No                             | 93  | 376
  ------------------------------------------------
  Base                           |     | 558 / 683
  Total (sum)                    | 116 | 558

More people use #git channel now (33% as compared to 20% before).
Nevertheless relatively few people use this form of comminication and
getting help.


60. If yes, do you find IRC channel useful?

This question was not present in previous survey. It nicely follows in
the series of questions about git wiki and git mailing list (do you
use? is it useful?).


61. Did you have problems getting GIT help on mailing list
    or on IRC channel? What were it? What could be improved?

This question was not present in previous survey.


Open forum
~~~~~~~~~~

62. What other comments or suggestions do you have
    that are not covered by the questions above?

TO DO. There is list of responses for 2006 survey; the 141 responses
in current (2007) survey are not yet analysed.

-- 
Jakub Narebski
(currently away from net)

^ permalink raw reply	[relevance 1%]

* Git User's Survey 2007 unfinished summary continued
  @ 2007-10-12 22:08  2% ` Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2007-10-12 22:08 UTC (permalink / raw)
  To: git

This is continuation of partial summary of Git User's Survey 2007,
ending at state from 28 September 2007.
(response ident "46f95167c967b").

The survey can be found here:
  http://www.survey.net.nz/survey.php?94e135ff41e871a1ea5bcda3ee1856d9
  http://tinyurl.com/26774s

The data this summary is base on can be found here:


----
There were 683 individual responses


Other SCMs
~~~~~~~~~~

13. What would you require from GIT to enable you to change,
    if you use other SCM for your project?

  TO DO
  474 / 683 non-empty responses

List of answers, without count (which for this question is, I think,
less important), divided into broad categories, is shown below

Generic
 * being more user-friendly, easier to use
   more friendly output from commands
   better and clearer error messages
   stable command semantics
 * reduced number of (visible) commands
   clear separation of plumbing and porcelain
 * consistent set of commands
   consistency if command flags
 * easier to learn (easier learning curve)
 * more stability
 * support UTF-16

 * A clearer UI. Read the monotone list archive. 70% of the mails are
   UI related. The result is an clear and easy to use intuitive UI
   that does what you expect in most cases.

Performance
 * better performance on massive trees (FreeBSD)
 * good speed on NTFS (MS WIndows)

Documentation
 * a good documentation
   user/installation documentation
   troubleshooting guide
   'Git For Dummies', 'The Git Book'
 * documented workflows (including centralized repo workflow, or at
   least documenting how and why replace it with better workflow)
 * development model tutorials
   more example usage
   best practices
   case studies
 * guide for designing a branch policy for a shared repository
 * screencasts
 * documentation in one's native language
 * good in-depth administative documentation
 * maybe git-tutor program

Specific features
 * partial-tree checkouts (partial checkout)
   checking out arbitrary subdirectories
 * granular permissions (ACL) within the tree
   e.g. restricting translators to the po/ subdirectory
 * shallow clone from a given commit: git clone --depth <commit>
 * automatic (re)packing
 * lightweight working copies
 * better and well documented submodule support
 * multi-project support / multiple sandboxes support
 * git-bind/unbind (like in bzr)
 * git-sync
 * cvs-compatible syntax as an option
 * tracking empty directories
 * more friendliness with corporate firewalls
 * ability to preserve permissions/modes/EA of files and directories
   access control features /  visibility access control
   disabling some users from accessing certain parts of the repository
 * being able to merge directories (instead of branches)
 * FastCGI gitweb
 * some embedded keyword capabilities similar to those provided by CVS
   and Subversion
 * ignore files during merge
 * R/W git server (allow push), with NIS, LDAP support
 * pull/rebase into dirty tree
 * clearcase dynamic view-like support (externally?)
 * better http(s) push via WebDAV: hooks
   working and easy to setup push over https
 * plain simple FTP upload (push) and download (clone, fetch)
 * better working through corporate firewalls

Portability
 * native MS Windows support, easy installer package
   even better support for all platforms
   easier setup on Solaris and AIX
 * pre-prepared _static_ binaries for FreeBSD, MacOS X, MS Windows
 * less dependencies
 * support for more platforms
 * a portable version of git, one binary + library (gitbox)
 * Windows version(s) mentioned on homepage

GUI
 * better (G)UI
   TortoiseGit for MS Windows, or other Windows front-end
   good, advanced GTK+ 2.x tool to visualize git
 * history graph conected to file tree in GUIs
 * easier management of remotes using GUI
 * better diff viewing tools (side-by-side, like KDiff3)

Other SCMs
 * seamless import
   BitKeeper / ClearCase import/sync
   tool to import TeamWare history into Git
   better SCM interop
 * SCM rosetta / "Git for <SCM> users" documentation
 * import/export tools supporting incremental import and export
 * 100% subversion interoperability
 * git update (stash, fetch, rebase, unstash) a la CVS
 * git-svnserve
 * svn:externals support

Tools
 * improved administrative tools
 * reasonable plugins for IDE (e.g. Visual Studio, KDevelop, NetBeans)
   full Eclipse / NetBeans / IntelliJ support
 * good integration with apps like Trac and Bugzilla
   work with continuous integration tools (cruise control etc...)
 * Git+Launchpad
 * libification (for tools support)

Other
 * SourceForge / Gna! / Google Projects support
   (free) hosting with git facilities
   FOSS hosting sites supporting git
 * commercial support / corporate backing
   contractual service
 * number of users, to convince my co-workers that they're not
   a silly minority
   popularity
 * projects switching to git
 * user education
 * marketing, advocacy videos
 * convincing coworkers / other members / boss
   willingness of the other developers to learn to use it
 * training/certification
 * a stop to the constant bashing of other SCMs - this doesn't get you
   any friends drop the arrogant attitude, work with the rest of the
   community and try to make something people can understand in an
   hour

 * http://wiki.FreeBSD.org/VersionControl

 * At work it'd require some kind of miracle. Huge Perforce repository
   of highly interrelated stuff in which people can make sweeping
   changes in a single changelist. Lots of tools that access Perforce.
   Slow as hell.



Getting help, staying in touch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

61. Did you have problems getting GIT help on mailing list
    or on IRC channel? What were it? What could be improved?

  TO TABULARIZE
  99 / 683 non-empty responses


Problems and suggestion for mailing list:

 * I answered my own question and no one even commented it. User and
   development discussion should be separated. Just release
   announcements in the user list.

   You need another mailing list for users. The current mailing list
   is very developer centric.

   The mailing list feels like it's more for developers rather than
   users and it's a little intimidating to ask newbie questions there.
   Maybe separate git-users and git-dev lists would make sense.

   Git mailing list needs a users and developers list. Mixing up the
   two is intimidating with all the traffic and the number of patches
   and advanced topics that shoot around.

   Having separate git-users and git-devel lists would be nice. I
   might read both but I hate to ask a newbie question on a list where
   50% of the submissions contain patches.

   (Other users find mailing list very responsive. Splitting the list
   into either git-devel and git-users, or git and git-announce has
   its advantages and disadvantages. You can always filter out patch
   submission and comments on patches thanks to the "[PATCH .*]"
   prefix convention present on mailing list.)

 * A question or two with no response at all. In hindsight my query
   was way too long-winded but it's still frustrating to be ignored.

   I answered my own question and no one even commented it.

   (See above)

 * The git mailing list is too high traffic to remain on. Maybe split
   it into a few lower traffic versions?

   Biggest problem is that smaller problems are getting lost in the
   growing size of the mailing list.

   The sheer amount of traffic makes the mailing list hard to deal
   with sometimes.  Getting your email tools set up correctly can help
   (i.e. auto tag+archive in GMail), but ultimately you still have to
   wade around in hundreds of emails you don't care about in order to
   find the ones you do care about.

   (Most people find traffic levels on git mailing list OK, see
   question 58.)

 * Will not go through corporate firewall.

   (I think it was about mailing list, but perhaps it was about IRC)

   I no longer subscribe to the GIT mailing list as ML subscription is
   forbidden at my new job, and I have no time at home to read it all.

   (You can read git mailing list through many archives / web
   interfaces, including MARC and GMane ones, and throught NNTP
   (aka. Usenet, aka news) interface on GMane. You don't need to be
   subscribed to git mailing list to post.)

 * People responded quickly to mailing list queries usually helpfully.
   However there was occasionally a touch of annoying 'groupthink' to
   the responses; sometimes new users are just confused and really
   would be better served by just changing their working habits, but
   other times there appeared to be a bit of tunnel-vision on the part
   of the longtime git users.

 * Trolls could be thrown out ;-) Seriously we had only a few there,
   but they are mighty annoying.

 * Mostly no. But little help on applying email-patches in win32 using
   GMail.  I'll get there though :)

   (Late addition of smtpserver (with ability to select port number),
   smtpuser, smtppass and smtpssl configuration variables / options to
   git-send-email should help with _sending_ patches using GMail. As
   to applying email-patches, git-am understand both mbox and maildir
   formats, not that it help much with win32 mail programs; but you
   can always try to save email in raw format from GMail WWW
   interface)


Problems and suggestions for IRC:

 * The IRC channel has too few people who know answers to questions;
   if you're there at the wrong time of day when none of them happen
   to be around it's useless. But if you're there at the right time
   it's pretty good.

 * IRC channel seems to respond to newbie git users quite well, but
   mid-level experience often gets no response.

 * Traffic on the IRC channel is a bit high. It may need to be split
   into a few different high-level topics in the near future.

   (IRC channel or git mailing list? I don't remember IRC channel
   having high traffic...)

 * It's hard to improve IRC. It's such a poor medium for understanding
   the communication going on.

   (On the other hand it is responsive. I think pastebins helps to
   sidestep limitations of the medium. Nevertheless the main medium of
   communication is git mailing list, not #git channel.)

 * IRC is blocked from work :-( I may try it by tunneling out.

   (Any suggestions here?)


Generic problems and suggestions:

 * Sometimes you get no answer (on git mailing list or #git channel)
   but that happens

 * People seem to think the problem isn't with git, and yet I find git
   extremely buggy and non-intuitive. Your "Git in 5 minutes" doesn't
   even include +x a hook or mention of hooks; neither does linus
   speech. If you don't +x a hook, try to figure out what is going
   on. I dare you. Git fails silently a bunch, maybe half of the time
   by design. Which shouldn't be acceptable.

   Try addressing an ssh address in url format: it isn't consistent
   and it will fail in half the apps. Same thing with git-ls-remote:
   it might have an --upload-pack that works, but this isn't across
   the board! From my own debugging none of the shell scripts have an
   --upload-pack option that work.

   (Not here. This is question about getting help from people, not
   about documentation or what you find hardest in GIT.)

 * After the last thread the GIT FAQ is almost begging for a 'Please
   don't ask about C++' section.

   (Truly, Git FAQ (which resides on Git wiki, but perhaps we should
   consider extracting it and adding to distribution tarballs) needs
   maintenance, updating and adding new frequently asked
   questions. Currently there is no FAQ maintainer.)


The other side: getting help success stories:

 * Quite the contrary. When Source Mage GNU/Linux switched to using
   GIT our developers spent a considerable amount of time asking
   questions and discussing features and bugs on #git. The feedback
   that we got was fabulous: the GIT developers were helpful
   interested in our needs and productive when it came to fixing
   bugs. One bug we discovered was even handled by Linus Torvalds
   himself and in just a matter of hours! In our eyes the GIT
   development community gained rightful reputation as one of the most
   friendly and helpful communities there is.

 * No, the mailing list has been very responsive. I have never asked a
   question on IRC but I sometimes answer newbie questions.

 * Mailing list is very interesting especially as I'm working on
   egit. IRC is more immediately helpful.

 * I'd like to say that I consider #git to be the most useful IRC
   channel I've ever been to when it came to getting answers to my
   questions. Thanks guys!

   The IRC channel is wonderful. The people there do a good job with
   questions.

 * No problems. In fact the mailing list/IRC could substitute the
   documentation but I guess that
     (1) does not work in offline mode
     (2) _is_ going to get on peoples nerves after a while
	 (recurring questions)



Open forum
~~~~~~~~~~

62. What other comments or suggestions do you have, that are not
    covered by the questions above?

  TO DO
  141 / 683 non-empty responses

There are many "keep up the great work!" (and equivalent) as answers
to this questions, and a few "worst SCM I've used". Those are excluded
from the lists below.


Suggestions for git:

 * One of the biggest complaints I hear is that mercurial's UI is much
   more 'intuitive' and user friendly.  Perhaps looking at it's
   operation and comparing/contrasting would be good.

   (Note that changing names of commands for example might be
   impossible because of historical reasons and large usebase.
   On the other hand perhaps this is just a steep learning curve,
   unavoidable for a power tool)

 * Mercurial has an excellent tutorial which had my team up and
   running in less than a hour after a week struggling to make git do
   anything useful.

   (I hope that late work on "Git User's Manual" helps here)

 * Handling of Unicode (UTF-16 encoded) files is a big pain with git.
   Even SVN can do a diff of them.

   (The idea that blob is just a bag of bytes will not change; but we
   have input/output filters, and soon before-diff filters, connected
   with gitattributes)

 * I like how in Subversion the commands work relative to the current
   directory. With Git I always seem to be dealing with longer paths
   and/or have to change to the root.

   (Running git from within directory deep within repository structure
   should 'just work'. If not, then it is an error... unless in
   situation like referring to tree-ish, where path is almost always
   relative to project root).

 * Keep up the UI simplification and make sure the docs start off with
   usage somewhat similar to CVS/SVN. I think many users are scared by
   Git because they see the more powerful commands thrown around too
   early and get scared.

   Git is just too complicated for a typical project. I understand
   it's probably great for the Linux kernel but for a smaller project
   like mine (Mesa) it's overkill and a frustration. (...)  With git
   everything seems hard. (...)  I've _wasted_ hours trying to figure
   out git. That alone is a huge issue. I guess I could go into
   specific details about my problems with git but I've already spent
   enough time on this survey.

   Figure out why people find git hard to learn and eliminate those
   barriers to entry.  Make git more task-oriented rather than
   data-model-oriented the way it is now.

   It's a great idea and a powerful tool but it's got a long way to go
   before it reaches wider adoption because it's so damn hard to use.

   (...) I'm evaluating Mercurial despite its being based on Python
   because it feels cleaner and simpler to use. I would prefer to use
   Git.

   (I think the 1.4 and 1.5 series is a good step in simplifying git
   for simple tasks and ordinary user. Core git porcelain improved
   much, and now there is no need to use plumbing for every-day tasks)

 * No one-pager cheat sheet with the 6 most basic commands on it so
   people can go use git.

   (This got corrected. There is git cheat sheet on the Internet;
   there is link on GitWiki to it)

 * Having a git library where other apps can integrate git, along with
   bindings for Python would be great.

   Make it easier to use by graphical clients like KGit.

   (The libification projects from Google Summer of Code would help
   there, I think)

 * I think that moving away from shell scripts to builtins is a
   necessary step but I don't really like it. It would help if you
   kept them around, perhaps in contrib/, so that others can learn how
   to use the plumbing (I learned a lot about git from reading these
   shell scripts).

   (Doing it: shell scripts which are moved to builtin are retired to
   contrib/examples/ directory).

 * Building git is a pain. (SHA1 sources being a problem). Can't git
   use autoconf? Also I've heard people have issues with git's
   portability (for example some BSD variant). Shell scrips weren't
   portable to non bash IIRC and often relied on GNU extensions in
   some programs. Native Windows port is also important.

   Probably the toughest challenge for Git IMO is that Mercurial,
   Darcs and Bazaar are good and similar. Lack of Windows support
   makes some people rule out Git altogether even though it may be
   better overall.

   I'd like to just stress support for windows and central
   repositories. (...) In fact most of my friends really wanted to use
   git but they wanted a solid native port.

   I think key to the adoption of git is that it is made to run on
   Windows as well as the other major OSes.

   (Git tries to use autoconf in a way that is totally optional, to do
   detection and write options for Makefile; you are welcome to
   contribute to configure.ac.  People work on making git more
   portable, for example trying to make it work with dash, defining
   in the meantime minimal POSIX-like shell compatibility required.
   Native MinGW Windows port is in the development)

 * I think that it is very nice that git is in the native OS
   repositories for Fedora. The Debian version needs updating.

   (git Makefile has rpm target, and git.spec target; perhaps this is
   the cause)

 * git-blame is manageable (with gc and reduced history etc) but that
   slowness still seems to be a negative point for many of my peers. I
   wouldn't mind better performance there either. Maybe some kind of
   optional indexing for those who want fast blame?

   (I recall there were some ideas about how to make git-blame faster
   on git mailing list.  Making it interactive for graphical blame
   tools reduced latency; there is I think a bit place for easy
   improvement for reblaming.  Maybe packv4 would help with blame
   performance...  What is I think unchangeable is the fact that
   snapshot driven / whole history driven SCMs _always_ would be
   slower at least a bit than single-file based SCMs.  This tradeoff
   is not possible to avoid.  But don't forget that git has other
   tools for examining history, like path (subsystem) limiting,
   searching commit messages, pickaxe search and graphical history
   browsing tools like gitk or qgit)

 * Get a mascot perhaps O'Reilly animal for O'Reilly GitBook
   (Git User's Manual) like the svnbook.

   (What animal could Git use for O'Reilly? Herd of horses, or a
   pony?)

 * I'm wondering what the overall goal is - git's origin as a neutral
   ground was fine but it hasn't seemed to take off as a viable
   alternative for general use.  Do you care about that?  Is it ok
   that git is it's own little niche?

   (Junio, Linus?)


Suggestions about git mailing list:

 * Git adoption will be limited by the actions and attitudes of those
   on the mailing list. 'If you can't say anything nice...'

   (We are nice, I think... to a point)

 * The ML had way too much traffic. I think there should be at least a
   git-patches@ where people submit there patches and git@ remains for
   user/dev discussions.

   (Most users find level of traffic on git mailing list O.K. It is
   not that hard to separate patch submission and their discussion
   from the rest of traffic thanks to [PATCH] prefix convention used.)


Suggestions and comments about this survey:

 * Various questions need 'other' options such as the programming
   language question. Various questions that already have 'other' as a
   possible choice need a text box to fill in the specifics.

   (I am not sure if it is possible mixing radiobutton/checkbox with
   text field with currently used free survey service, survey.net.nz)

 * The text fields (and text areas) of this survey are way too small!

   (I am not sure if changing this is possible with currently used
   free survey service, survey.net.nz)

 * You should do a survey of feature requests.

   (See questions 13, 38, 41 and especially 37)

 * Shorten survey length. This survey is too damn long. Make the
   survey shorter!

   Cut down the number of questions on this survey by a factor of 4.

   (I think removing the questions which asks very similar question
   but in different context be a good start. But that aside: which
   questions should be dropped, which concatenated (and which split);
   which are useful and which are not?)

 * Questions not asked: what can be improved on GitWiki, workflows
   used and tools used, kind of repository hosting used for project,
   programming experience level and version control experience, using
   git for non-programming repositories like ikiwiki or documents,
   perceived git stability and number of bugs.

   (The surveys is very long as it is now. Those questions are nice,
   but it would make survey too long I think.)

 * The survey asks about new features that are not in a stable version
   of git yet. git-stash comes to mind. This is silly. Not everybody
   will track your development branch. I certainly don't. I don't for
   other SCMs I use either.

   (I tried to put only features which are in released, i.e. numbered,
   version. git-stash is in 1.5.3, see Documentation/RelNotes-1.5.3.txt)

 * Regarding Q19 (How do you obtain GIT?). I actually use all three
   forms on different systems.
     Mac: pull from MacPorts
     Ubuntu: from git.git
     remote systems: tar balls.

   (Should it be made multiple choice question, then?)


Some other comments:

 * I've been so busy with other projects. I didn't realize so many
   interfaces exist.  Thanks to this survey I'll spend some time
   checking out the wiki for the other interfaces.

   I didn't even know about any of the new git features listed in
   question 43.

   I need to get an up to date version as there are things mentioned
   in this survey that I don't know about.

 * At the 'Solutions Linux 2007' exhibition in Paris I have been
   looking for a service provider that could propose some training
   sessions for Git. I couldn't find one. Maybe in 2008...

-- 
Jakub Narebski
(away from Internet)

^ permalink raw reply	[relevance 2%]

* [PATCH 2/3] Quoting paths in tests
  @ 2007-10-15 13:13  7% ` Jonathan del Strother
  0 siblings, 0 replies; 200+ results
From: Jonathan del Strother @ 2007-10-15 13:13 UTC (permalink / raw)
  To: git; +Cc: Jonathan del Strother

From: Jonathan del Strother <jon.delStrother@bestbefore.tv>

Add quoting to various test paths so they can be run from a path with a space in

Signed-off-by: Jonathan del Strother <jon.delStrother@bestbefore.tv>
---
 t/lib-git-svn.sh                         |    2 +-
 t/t1020-subdirectory.sh                  |   22 ++++++------
 t/t3050-subprojects-fetch.sh             |    2 +-
 t/t3404-rebase-interactive.sh            |    2 +-
 t/t5500-fetch-pack.sh                    |    2 +-
 t/t5700-clone-reference.sh               |    2 +-
 t/t7003-filter-branch.sh                 |    2 +-
 t/t7501-commit.sh                        |    4 +-
 t/t9100-git-svn-basic.sh                 |   18 +++++-----
 t/t9101-git-svn-props.sh                 |    6 ++--
 t/t9102-git-svn-deep-rmdir.sh            |    6 ++--
 t/t9104-git-svn-follow-parent.sh         |   50 +++++++++++++++---------------
 t/t9105-git-svn-commit-diff.sh           |   10 +++---
 t/t9106-git-svn-commit-diff-clobber.sh   |   14 ++++----
 t/t9107-git-svn-migrate.sh               |   40 ++++++++++++------------
 t/t9108-git-svn-glob.sh                  |    8 ++--
 t/t9110-git-svn-use-svm-props.sh         |    8 ++--
 t/t9111-git-svn-use-svnsync-props.sh     |    8 ++--
 t/t9112-git-svn-md5less-file.sh          |    4 +-
 t/t9113-git-svn-dcommit-new-file.sh      |    6 ++--
 t/t9114-git-svn-dcommit-merge.sh         |    4 +-
 t/t9115-git-svn-dcommit-funky-renames.sh |    4 +-
 t/t9116-git-svn-log.sh                   |    4 +-
 t/t9500-gitweb-standalone-no-errors.sh   |    4 +-
 t/test-lib.sh                            |    2 +-
 25 files changed, 117 insertions(+), 117 deletions(-)

diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh
index 8d4a447..cde3053 100644
--- a/t/lib-git-svn.sh
+++ b/t/lib-git-svn.sh
@@ -25,7 +25,7 @@ perl -w -e "
 use SVN::Core;
 use SVN::Repos;
 \$SVN::Core::VERSION gt '1.1.0' or exit(42);
-system(qw/svnadmin create --fs-type fsfs/, '$svnrepo') == 0 or exit(41);
+system(qw/svnadmin create --fs-type fsfs/, \"$svnrepo\") == 0 or exit(41);
 " >&3 2>&4
 x=$?
 if test $x -ne 0
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index b9cef34..5ed7fa4 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -21,7 +21,7 @@ LF='
 '
 
 test_expect_success 'update-index and ls-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git update-index --add one &&
 	case "`git ls-files`" in
 	one) echo ok one ;;
@@ -41,7 +41,7 @@ test_expect_success 'update-index and ls-files' '
 '
 
 test_expect_success 'cat-file' '
-	cd $HERE &&
+	cd "$HERE" &&
 	two=`git ls-files -s dir/two` &&
 	two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
 	echo "$two" &&
@@ -54,7 +54,7 @@ test_expect_success 'cat-file' '
 rm -f actual dir/actual
 
 test_expect_success 'diff-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	echo a >>one &&
 	echo d >>dir/two &&
 	case "`git diff-files --name-only`" in
@@ -74,7 +74,7 @@ test_expect_success 'diff-files' '
 '
 
 test_expect_success 'write-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	top=`git write-tree` &&
 	echo $top &&
 	cd dir &&
@@ -84,7 +84,7 @@ test_expect_success 'write-tree' '
 '
 
 test_expect_success 'checkout-index' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git checkout-index -f -u one &&
 	cmp one original.one &&
 	cd dir &&
@@ -93,7 +93,7 @@ test_expect_success 'checkout-index' '
 '
 
 test_expect_success 'read-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -f one dir/two &&
 	tree=`git write-tree` &&
 	git read-tree --reset -u "$tree" &&
@@ -107,27 +107,27 @@ test_expect_success 'read-tree' '
 '
 
 test_expect_success 'no file/rev ambiguity check inside .git' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git commit -a -m 1 &&
-	cd $HERE/.git &&
+	cd "$HERE/.git" &&
 	git show -s HEAD
 '
 
 test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && GIT_DIR=. git show -s HEAD
 '
 
 # This still does not work as it should...
 : test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && git show -s HEAD
 '
 
 test_expect_success 'detection should not be fooled by a symlink' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -fr foo.git &&
 	git clone -s .git another &&
 	ln -s another yetanother &&
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 34f26a8..4b74cc6 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -20,7 +20,7 @@ test_expect_success setup '
 '
 
 test_expect_success clone '
-	git clone file://`pwd`/.git cloned &&
+	git clone "file://`pwd`/.git" cloned &&
 	(git rev-parse HEAD; git ls-files -s) >expected &&
 	(
 		cd cloned &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 1113904..aa86042 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -92,7 +92,7 @@ done
 EOF
 
 chmod a+x fake-editor.sh
-VISUAL="$(pwd)/fake-editor.sh"
+VISUAL="\"$(pwd)/fake-editor.sh\""
 export VISUAL
 
 test_expect_success 'no changes are a nop' '
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 7b6798d..5489ffe 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -129,7 +129,7 @@ pull_to_client 2nd "B" $((64*3))
 
 pull_to_client 3rd "A" $((1*3)) # old fails
 
-test_expect_success "clone shallow" "git-clone --depth 2 file://`pwd`/. shallow"
+test_expect_success "clone shallow" "git-clone --depth 2 \"file://`pwd`/.\" shallow"
 
 (cd shallow; git count-objects -v) > count.shallow
 
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index 4e93aaa..8bb34f9 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -51,7 +51,7 @@ diff expected current'
 cd "$base_dir"
 
 test_expect_success 'cloning with reference (no -l -s)' \
-'git clone --reference B file://`pwd`/A D'
+'git clone --reference B "file://`pwd`/A" D'
 
 cd "$base_dir"
 
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index e935b20..1ab5392 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -107,7 +107,7 @@ test_expect_success 'use index-filter to move into a subdirectory' '
 		 "git ls-files -s | sed \"s-\\t-&newsubdir/-\" |
 	          GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
 			git update-index --index-info &&
-		  mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
+		  mv \"\$GIT_INDEX_FILE.new\" \"\$GIT_INDEX_FILE\"" directorymoved &&
 	test -z "$(git diff HEAD directorymoved:newsubdir)"'
 
 test_expect_success 'stops when msg filter fails' '
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index b151b51..e97e756 100644
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -69,7 +69,7 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -i -e "s/a file/an amend commit/g" $1
+sed -i -e "s/a file/an amend commit/g" "$1"
 EOF
 chmod 755 editor
 
@@ -88,7 +88,7 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -i -e "s/amend/older/g" $1
+sed -i -e "s/amend/older/g" "$1"
 EOF
 chmod 755 editor
 
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 614cf50..c3585da 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -31,16 +31,16 @@ test_expect_success \
 	echo 'zzz' > bar/zzz &&
 	echo '#!/bin/sh' > exec.sh &&
 	chmod +x exec.sh &&
-	svn import -m 'import for git-svn' . $svnrepo >/dev/null &&
+	svn import -m 'import for git-svn' . '$svnrepo' >/dev/null &&
 	cd .. &&
 	rm -rf import &&
-	git-svn init $svnrepo"
+	git-svn init '$svnrepo'"
 
 test_expect_success \
     'import an SVN revision into git' \
     'git-svn fetch'
 
-test_expect_success "checkout from svn" "svn co $svnrepo '$SVN_TREE'"
+test_expect_success "checkout from svn" "svn co '$svnrepo' '$SVN_TREE'"
 
 name='try a deep --rmdir with a commit'
 test_expect_success "$name" "
@@ -169,7 +169,7 @@ test_expect_success "$name" "
 	svn up '$SVN_TREE' &&
 	test -f '$SVN_TREE'/exec-2.sh &&
 	test ! -L '$SVN_TREE'/exec-2.sh &&
-	git diff help $SVN_TREE/exec-2.sh"
+	git diff help '$SVN_TREE/exec-2.sh'"
 
 if test "$have_utf8" = t
 then
@@ -190,7 +190,7 @@ name='test fetch functionality (svn => git) with alternate GIT_SVN_ID'
 GIT_SVN_ID=alt
 export GIT_SVN_ID
 test_expect_success "$name" \
-    "git-svn init $svnrepo && git-svn fetch &&
+    "git-svn init '$svnrepo' && git-svn fetch &&
      git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a &&
      git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
      git diff a b"
@@ -220,16 +220,16 @@ test_expect_failure 'exit if remote refs are ambigious' "
         "
 
 test_expect_failure 'exit if init-ing a would clobber a URL' "
-        svnadmin create ${PWD}/svnrepo2 &&
-        svn mkdir -m 'mkdir bar' ${svnrepo}2/bar &&
+        svnadmin create '${PWD}/svnrepo2' &&
+        svn mkdir -m 'mkdir bar' '${svnrepo}2/bar' &&
         git config --unset svn-remote.svn.fetch \
                                 '^bar:refs/remotes/git-svn$' &&
-        git-svn init ${svnrepo}2/bar
+        git-svn init '${svnrepo}2/bar'
         "
 
 test_expect_success \
   'init allows us to connect to another directory in the same repo' "
-        git-svn init --minimize-url -i bar $svnrepo/bar &&
+        git-svn init --minimize-url -i bar '$svnrepo/bar' &&
         git config --get svn-remote.svn.fetch \
                               '^bar:refs/remotes/bar$' &&
         git config --get svn-remote.svn.fetch \
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index 5aac644..a1c85e0 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -52,7 +52,7 @@ EOF
 cd ..
 
 rm -rf import
-test_expect_success 'checkout working copy from svn' "svn co $svnrepo test_wc"
+test_expect_success 'checkout working copy from svn' "svn co '$svnrepo' test_wc"
 test_expect_success 'setup some commits to svn' \
 	'cd test_wc &&
 		echo Greetings >> kw.c &&
@@ -66,7 +66,7 @@ test_expect_success 'setup some commits to svn' \
 		svn commit -m "Propset Id" &&
 	cd ..'
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init '$svnrepo'"
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 
 name='test svn:keywords ignoring'
@@ -92,7 +92,7 @@ test_expect_success "propset CR on crlf files" \
 test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
 	"git-svn fetch &&
 	 git pull . remotes/git-svn &&
-	 svn co $svnrepo new_wc"
+	 svn co '$svnrepo' new_wc"
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh
index 4e08083..99c8840 100755
--- a/t/t9102-git-svn-deep-rmdir.sh
+++ b/t/t9102-git-svn-deep-rmdir.sh
@@ -9,12 +9,12 @@ test_expect_success 'initialize repo' "
 	mkdir -p deeply/nested/directory/number/2 &&
 	echo foo > deeply/nested/directory/number/1/file &&
 	echo foo > deeply/nested/directory/number/2/another &&
-	svn import -m 'import for git-svn' . $svnrepo &&
+	svn import -m 'import for git-svn' . '$svnrepo' &&
 	cd ..
 	"
 
 test_expect_success 'mirror via git-svn' "
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
 	git checkout -f -b test-rmdir remotes/git-svn
 	"
@@ -23,7 +23,7 @@ test_expect_success 'Try a commit on rmdir' "
 	git rm -f deeply/nested/directory/number/2/another &&
 	git commit -a -m 'remove another' &&
 	git-svn set-tree --rmdir HEAD &&
-	svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1
+	svn ls -R '$svnrepo' | grep ^deeply/nested/directory/number/1
 	"
 
 
diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 7ba7630..aa2bfe2 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -11,9 +11,9 @@ test_expect_success 'initialize repo' "
 	cd import &&
 	mkdir -p trunk &&
 	echo hello > trunk/readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
-	svn co $svnrepo wc &&
+	svn co '$svnrepo' wc &&
 	cd wc &&
 	echo world >> trunk/readme &&
 	poke trunk/readme &&
@@ -27,7 +27,7 @@ test_expect_success 'initialize repo' "
 	"
 
 test_expect_success 'init and fetch a moved directory' "
-	git-svn init --minimize-url -i thunk $svnrepo/thunk &&
+	git-svn init --minimize-url -i thunk '$svnrepo/thunk' &&
 	git-svn fetch -i thunk &&
 	test \"\`git rev-parse --verify refs/remotes/thunk@2\`\" \
            = \"\`git rev-parse --verify refs/remotes/thunk~1\`\" &&
@@ -38,7 +38,7 @@ test_expect_success 'init and fetch a moved directory' "
 	"
 
 test_expect_success 'init and fetch from one svn-remote' "
-        git config svn-remote.svn.url $svnrepo &&
+        git config svn-remote.svn.url '$svnrepo' &&
         git config --add svn-remote.svn.fetch \
           trunk:refs/remotes/svn/trunk &&
         git config --add svn-remote.svn.fetch \
@@ -52,9 +52,9 @@ test_expect_success 'init and fetch from one svn-remote' "
 
 test_expect_success 'follow deleted parent' "
         (svn cp -m 'resurrecting trunk as junk' \
-               $svnrepo/trunk@2 $svnrepo/junk ||
+               '$svnrepo/trunk@2' '$svnrepo'/junk ||
          svn cp -m 'resurrecting trunk as junk' \
-               -r2 $svnrepo/trunk $svnrepo/junk) &&
+               -r2 '$svnrepo/trunk' '$svnrepo/junk') &&
         git config --add svn-remote.svn.fetch \
           junk:refs/remotes/svn/junk &&
         git-svn fetch -i svn/thunk &&
@@ -67,10 +67,10 @@ test_expect_success 'follow deleted parent' "
 test_expect_success 'follow larger parent' "
         mkdir -p import/trunk/thunk/bump/thud &&
         echo hi > import/trunk/thunk/bump/thud/file &&
-        svn import -m 'import a larger parent' import $svnrepo/larger-parent &&
-        svn cp -m 'hi' $svnrepo/larger-parent $svnrepo/another-larger &&
+        svn import -m 'import a larger parent' import '$svnrepo/larger-parent' &&
+        svn cp -m 'hi' '$svnrepo/larger-parent' '$svnrepo/another-larger' &&
         git-svn init --minimize-url -i larger \
-          $svnrepo/another-larger/trunk/thunk/bump/thud &&
+          '$svnrepo/another-larger/trunk/thunk/bump/thud' &&
         git-svn fetch -i larger &&
         git rev-parse --verify refs/remotes/larger &&
         git rev-parse --verify \
@@ -83,23 +83,23 @@ test_expect_success 'follow larger parent' "
         "
 
 test_expect_success 'follow higher-level parent' "
-        svn mkdir -m 'follow higher-level parent' $svnrepo/blob &&
-        svn co $svnrepo/blob blob &&
+        svn mkdir -m 'follow higher-level parent' '$svnrepo/blob' &&
+        svn co '$svnrepo/blob' blob &&
         cd blob &&
                 echo hi > hi &&
                 svn add hi &&
                 svn commit -m 'hihi' &&
                 cd ..
-        svn mkdir -m 'new glob at top level' $svnrepo/glob &&
-        svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
-        git-svn init --minimize-url -i blob $svnrepo/glob/blob &&
+        svn mkdir -m 'new glob at top level' '$svnrepo/glob' &&
+        svn mv -m 'move blob down a level' '$svnrepo/blob' '$svnrepo/glob/blob' &&
+        git-svn init --minimize-url -i blob '$svnrepo/glob/blob' &&
         git-svn fetch -i blob
         "
 
 test_expect_success 'follow deleted directory' "
-	svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye &&
-	svn rm -m 'remove glob' $svnrepo/glob &&
-	git-svn init --minimize-url -i glob $svnrepo/glob &&
+	svn mv -m 'bye!' '$svnrepo/glob/blob/hi' '$svnrepo/glob/blob/bye' &&
+	svn rm -m 'remove glob' '$svnrepo/glob' &&
+	git-svn init --minimize-url -i glob '$svnrepo/glob' &&
 	git-svn fetch -i glob &&
 	test \"\`git cat-file blob refs/remotes/glob:blob/bye\`\" = hi &&
 	test \"\`git ls-tree refs/remotes/glob | wc -l \`\" -eq 1
@@ -118,9 +118,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  echo 'bad delete test 2' > \
 	   import/trunk/subversion/bindings/swig/perl/another-larger &&
 	cd import &&
-	  svn import -m 'r9270 test' . $svnrepo/r9270 &&
+	  svn import -m 'r9270 test' . '$svnrepo/r9270' &&
 	cd .. &&
-	svn co $svnrepo/r9270/trunk/subversion/bindings/swig/perl r9270 &&
+	svn co '$svnrepo/r9270/trunk/subversion/bindings/swig/perl' r9270 &&
 	cd r9270 &&
 	  svn mkdir native &&
 	  svn mv t native/t &&
@@ -130,7 +130,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  svn commit -m 'reorg test' &&
 	cd .. &&
 	git-svn init --minimize-url -i r9270-t \
-	  $svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t &&
+	  '$svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t' &&
 	git-svn fetch -i r9270-t &&
 	test \`git rev-list r9270-t | wc -l\` -eq 2 &&
 	test \"\`git ls-tree --name-only r9270-t~1\`\" = \
@@ -138,9 +138,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	"
 
 test_expect_success "track initial change if it was only made to parent" "
-	svn cp -m 'wheee!' $svnrepo/r9270/trunk $svnrepo/r9270/drunk &&
+	svn cp -m 'wheee!' '$svnrepo/r9270/trunk' '$svnrepo/r9270/drunk' &&
 	git-svn init --minimize-url -i r9270-d \
-	  $svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t &&
+	  '$svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t' &&
 	git-svn fetch -i r9270-d &&
 	test \`git rev-list r9270-d | wc -l\` -eq 3 &&
 	test \"\`git ls-tree --name-only r9270-t\`\" = \
@@ -150,7 +150,7 @@ test_expect_success "track initial change if it was only made to parent" "
 	"
 
 test_expect_success "track multi-parent paths" "
-	svn cp -m 'resurrect /glob' $svnrepo/r9270 $svnrepo/glob &&
+	svn cp -m 'resurrect /glob' '$svnrepo/r9270' '$svnrepo/glob' &&
 	git-svn multi-fetch &&
 	test \`git cat-file commit refs/remotes/glob | \
 	       grep '^parent ' | wc -l\` -eq 2
@@ -161,8 +161,8 @@ test_expect_success "multi-fetch continues to work" "
 	"
 
 test_expect_success "multi-fetch works off a 'clean' repository" "
-	rm -r $GIT_DIR/svn $GIT_DIR/refs/remotes $GIT_DIR/logs &&
-	mkdir $GIT_DIR/svn &&
+	rm -r '$GIT_DIR/svn' '$GIT_DIR/refs/remotes' '$GIT_DIR/logs' &&
+	mkdir '$GIT_DIR/svn' &&
 	git-svn multi-fetch
 	"
 
diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh
index 318e172..2e1eb75 100755
--- a/t/t9105-git-svn-commit-diff.sh
+++ b/t/t9105-git-svn-commit-diff.sh
@@ -8,7 +8,7 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo hello > readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
 	echo hello > readme &&
 	git update-index --add readme &&
@@ -27,16 +27,16 @@ prev=`git rev-parse --verify HEAD^1`
 test_expect_success 'test the commit-diff command' "
 	test -n '$prev' && test -n '$head' &&
 	git-svn commit-diff -r1 '$prev' '$head' '$svnrepo' &&
-	svn co $svnrepo wc &&
+	svn co '$svnrepo' wc &&
 	cmp readme wc/readme
 	"
 
 test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
-	svn import -m 'sub-directory' import $svnrepo/subdir &&
-	git-svn init --minimize-url $svnrepo/subdir &&
+	svn import -m 'sub-directory' import '$svnrepo/subdir' &&
+	git-svn init --minimize-url '$svnrepo/subdir' &&
 	git-svn fetch &&
 	git-svn commit-diff -r3 '$prev' '$head' &&
-	svn cat $svnrepo/subdir/readme > readme.2 &&
+	svn cat '$svnrepo/subdir/readme' > readme.2 &&
 	cmp readme readme.2
 	"
 
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index 79b7968..bb42339 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -8,14 +8,14 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo initial > file &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
 	echo initial > file &&
 	git update-index --add file &&
 	git commit -a -m 'initial'
 	"
 test_expect_success 'commit change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 	echo second line from svn >> file &&
 	poke file &&
@@ -27,7 +27,7 @@ test_expect_success 'commit change from svn side' "
 test_expect_failure 'commit conflicting change from git' "
 	echo second line from git >> file &&
 	git commit -a -m 'second line from git' &&
-	git-svn commit-diff -r1 HEAD~1 HEAD $svnrepo
+	git-svn commit-diff -r1 HEAD~1 HEAD '$svnrepo'
 	" || true
 
 test_expect_success 'commit complementing change from git' "
@@ -36,14 +36,14 @@ test_expect_success 'commit complementing change from git' "
 	git commit -a -m 'second line from svn' &&
 	echo third line from git >> file &&
 	git commit -a -m 'third line from git' &&
-	git-svn commit-diff -r2 HEAD~1 HEAD $svnrepo
+	git-svn commit-diff -r2 HEAD~1 HEAD '$svnrepo'
 	"
 
 test_expect_failure 'dcommit fails to commit because of conflict' "
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
 	git reset --hard refs/remotes/git-svn &&
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 	echo fourth line from svn >> file &&
 	poke file &&
@@ -67,7 +67,7 @@ test_expect_success 'dcommit does the svn equivalent of an index merge' "
 	"
 
 test_expect_success 'commit another change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 		echo third line from svn >> file &&
 		poke file &&
diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index 67fdf70..90bf786 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -4,7 +4,7 @@ test_description='git-svn metadata migrations from previous versions'
 . ./lib-git-svn.sh
 
 test_expect_success 'setup old-looking metadata' "
-	cp $GIT_DIR/config $GIT_DIR/config-old-git-svn &&
+	cp '$GIT_DIR/config' '$GIT_DIR/config-old-git-svn' &&
 	mkdir import &&
 	cd import &&
 		for i in trunk branches/a branches/b \
@@ -12,13 +12,13 @@ test_expect_success 'setup old-looking metadata' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . '$svnrepo'
 		cd .. &&
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
-	mv $GIT_DIR/svn/* $GIT_DIR/ &&
-	mv $GIT_DIR/svn/.metadata $GIT_DIR/ &&
-	rmdir $GIT_DIR/svn &&
+	mv '$GIT_DIR'/svn/* '$GIT_DIR/' &&
+	mv '$GIT_DIR/svn/.metadata' '$GIT_DIR/' &&
+	rmdir '$GIT_DIR/svn' &&
 	git update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn &&
 	git update-ref refs/heads/svn-HEAD refs/remotes/git-svn &&
 	git update-ref -d refs/remotes/git-svn refs/remotes/git-svn
@@ -28,20 +28,20 @@ head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
 test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
 
 test_expect_success 'initialize old-style (v0) git-svn layout' "
-	mkdir -p $GIT_DIR/git-svn/info $GIT_DIR/svn/info &&
-	echo $svnrepo > $GIT_DIR/git-svn/info/url &&
-	echo $svnrepo > $GIT_DIR/svn/info/url &&
+	mkdir -p '$GIT_DIR/git-svn/info' '$GIT_DIR/svn/info' &&
+	echo '$svnrepo' > '$GIT_DIR/git-svn/info/url' &&
+	echo '$svnrepo' > '$GIT_DIR/svn/info/url' &&
 	git-svn migrate &&
-	! test -d $GIT_DIR/git-svn &&
+	! test -d '$GIT_DIR/git-svn' &&
 	git rev-parse --verify refs/remotes/git-svn^0 &&
 	git rev-parse --verify refs/remotes/svn^0 &&
-	test \`git config --get svn-remote.svn.url\` = '$svnrepo' &&
+	test \"\`git config --get svn-remote.svn.url\`\" = \"$svnrepo\" &&
 	test \`git config --get svn-remote.svn.fetch\` = \
              ':refs/remotes/git-svn'
 	"
 
 test_expect_success 'initialize a multi-repository repo' "
-	git-svn init $svnrepo -T trunk -t tags -b branches &&
+	git-svn init '$svnrepo' -T trunk -t tags -b branches &&
 	git config --get-all svn-remote.svn.fetch > fetch.out &&
 	grep '^trunk:refs/remotes/trunk$' fetch.out &&
 	test -n \"\`git config --get svn-remote.svn.branches \
@@ -76,14 +76,14 @@ test_expect_success 'multi-fetch works on partial urls + paths' "
 test_expect_success 'migrate --minimize on old inited layout' "
 	git config --unset-all svn-remote.svn.fetch &&
 	git config --unset-all svn-remote.svn.url &&
-	rm -rf $GIT_DIR/svn &&
+	rm -rf '$GIT_DIR/svn' &&
 	for i in \`cat fetch.out\`; do
 		path=\`expr \$i : '\\([^:]*\\):.*$'\`
 		ref=\`expr \$i : '[^:]*:refs/remotes/\\(.*\\)$'\`
 		if test -z \"\$ref\"; then continue; fi
 		if test -n \"\$path\"; then path=\"/\$path\"; fi
-		( mkdir -p $GIT_DIR/svn/\$ref/info/ &&
-		echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
+		( mkdir -p '$GIT_DIR'/svn/\$ref/info/ &&
+		echo '$svnrepo'\$path > '$GIT_DIR'/svn/\$ref/info/url ) || exit 1;
 	done &&
 	git-svn migrate --minimize &&
 	test -z \"\`git config -l |grep -v '^svn-remote\.git-svn\.'\`\" &&
@@ -99,13 +99,13 @@ test_expect_success 'migrate --minimize on old inited layout' "
 
 test_expect_success  ".rev_db auto-converted to .rev_db.UUID" "
 	git-svn fetch -i trunk &&
-	expect=$GIT_DIR/svn/trunk/.rev_db.* &&
+	expect=\"\`find \"\$GIT_DIR\"/svn/trunk/ -name '.rev_db.*'\`\" &&
 	test -n \"\$expect\" &&
-	mv \$expect $GIT_DIR/svn/trunk/.rev_db &&
+	mv \"\$expect\" \"\$GIT_DIR\"/svn/trunk/.rev_db &&
 	git-svn fetch -i trunk &&
-	test -L $GIT_DIR/svn/trunk/.rev_db &&
-	test -f \$expect &&
-	cmp \$expect $GIT_DIR/svn/trunk/.rev_db
+	test -L \"\$GIT_DIR\"/svn/trunk/.rev_db &&
+	test -f \"\$expect\" &&
+	cmp \"\$expect\" \"\$GIT_DIR\"/svn/trunk/.rev_db
 	"
 
 test_done
diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh
index db4344c..c6dc0ef 100755
--- a/t/t9108-git-svn-glob.sh
+++ b/t/t9108-git-svn-glob.sh
@@ -14,8 +14,8 @@ test_expect_success 'test refspec globbing' "
 	mkdir -p trunk/src/a trunk/src/b trunk/doc &&
 	echo 'hello world' > trunk/src/a/readme &&
 	echo 'goodbye world' > trunk/src/b/readme &&
-	svn import -m 'initial' trunk $svnrepo/trunk &&
-	svn co $svnrepo tmp &&
+	svn import -m 'initial' trunk '$svnrepo/trunk' &&
+	svn co '$svnrepo' tmp &&
 	cd tmp &&
 		mkdir branches tags &&
 		svn add branches tags &&
@@ -38,7 +38,7 @@ test_expect_success 'test refspec globbing' "
 		poke tags/end/src/b/readme &&
 		svn commit -m 'nothing to see here'
 		cd .. &&
-	git config --add svn-remote.svn.url $svnrepo &&
+	git config --add svn-remote.svn.url '$svnrepo' &&
 	git config --add svn-remote.svn.fetch \
 	                 'trunk/src/a:refs/remotes/trunk' &&
 	git config --add svn-remote.svn.branches \
@@ -60,7 +60,7 @@ echo nothing to see here >> expect.two
 cat expect.end >> expect.two
 
 test_expect_success 'test left-hand-side only globbing' "
-	git config --add svn-remote.two.url $svnrepo &&
+	git config --add svn-remote.two.url '$svnrepo' &&
 	git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
 	git config --add svn-remote.two.branches \
 	                 'branches/*:refs/remotes/two/branches/*' &&
diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh
index 6235af4..d4ab01f 100755
--- a/t/t9110-git-svn-use-svm-props.sh
+++ b/t/t9110-git-svn-use-svm-props.sh
@@ -8,11 +8,11 @@ test_description='git-svn useSvmProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svm repo' "
-	svnadmin load -q $rawsvnrepo < ../t9110/svm.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/mirror/arr &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/mirror/argh &&
+	svnadmin load -q '$rawsvnrepo' < ../t9110/svm.dump &&
+	git-svn init --minimize-url -R arr -i bar '$svnrepo/mirror/arr' &&
+	git-svn init --minimize-url -R argh -i dir '$svnrepo/mirror/argh' &&
 	git-svn init --minimize-url -R argh -i e \
-	  $svnrepo/mirror/argh/a/b/c/d/e &&
+	  '$svnrepo/mirror/argh/a/b/c/d/e' &&
 	git config svn.useSvmProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9111-git-svn-use-svnsync-props.sh b/t/t9111-git-svn-use-svnsync-props.sh
index ec7dedd..936f023 100755
--- a/t/t9111-git-svn-use-svnsync-props.sh
+++ b/t/t9111-git-svn-use-svnsync-props.sh
@@ -8,10 +8,10 @@ test_description='git-svn useSvnsyncProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svnsync repo' "
-	svnadmin load -q $rawsvnrepo < ../t9111/svnsync.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/bar &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/dir &&
-	git-svn init --minimize-url -R argh -i e $svnrepo/dir/a/b/c/d/e &&
+	svnadmin load -q '$rawsvnrepo' < ../t9111/svnsync.dump &&
+	git-svn init --minimize-url -R arr -i bar '$svnrepo/bar' &&
+	git-svn init --minimize-url -R argh -i dir '$svnrepo/dir' &&
+	git-svn init --minimize-url -R argh -i e '$svnrepo/dir/a/b/c/d/e' &&
 	git config svn.useSvnsyncProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh
index 08313bb..b095583 100755
--- a/t/t9112-git-svn-md5less-file.sh
+++ b/t/t9112-git-svn-md5less-file.sh
@@ -38,8 +38,8 @@ PROPS-END
 
 EOF
 
-test_expect_success 'load svn dumpfile' "svnadmin load $rawsvnrepo < dumpfile.svn"
+test_expect_success 'load svn dumpfile' "svnadmin load '$rawsvnrepo' < dumpfile.svn"
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init '$svnrepo'"
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 test_done
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
index 9ef0db9..0088c75 100755
--- a/t/t9113-git-svn-dcommit-new-file.sh
+++ b/t/t9113-git-svn-dcommit-new-file.sh
@@ -15,14 +15,14 @@ test_description='git-svn dcommit new files over svn:// test'
 
 start_svnserve () {
 	svnserve --listen-port $SVNSERVE_PORT \
-	         --root $rawsvnrepo \
+	         --root '$rawsvnrepo' \
 	         --listen-once \
 	         --listen-host 127.0.0.1 &
 }
 
 test_expect_success 'start tracking an empty repo' "
-	svn mkdir -m 'empty dir' $svnrepo/empty-dir &&
-	echo anon-access = write >> $rawsvnrepo/conf/svnserve.conf &&
+	svn mkdir -m 'empty dir' '$svnrepo/empty-dir' &&
+	echo anon-access = write >> '$rawsvnrepo/conf/svnserve.conf' &&
 	start_svnserve &&
 	git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
 	git svn fetch
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
index d6ca955..64ec7fd 100755
--- a/t/t9114-git-svn-dcommit-merge.sh
+++ b/t/t9114-git-svn-dcommit-merge.sh
@@ -35,7 +35,7 @@ EOF
 }
 
 test_expect_success 'setup svn repository' "
-	svn co $svnrepo mysvnwork &&
+	svn co '$svnrepo' mysvnwork &&
 	mkdir -p mysvnwork/trunk &&
 	cd mysvnwork &&
 		big_text_block >> trunk/README &&
@@ -45,7 +45,7 @@ test_expect_success 'setup svn repository' "
 	"
 
 test_expect_success 'setup git mirror and merge' "
-	git svn init $svnrepo -t tags -T trunk -b branches &&
+	git svn init '$svnrepo' -t tags -T trunk -b branches &&
 	git svn fetch &&
 	git checkout --track -b svn remotes/trunk &&
 	git checkout -b merge &&
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 182299c..653578d 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -8,12 +8,12 @@ test_description='git-svn dcommit can commit renames of files with ugly names'
 . ./lib-git-svn.sh
 
 test_expect_success 'load repository with strange names' "
-	svnadmin load -q $rawsvnrepo < ../t9115/funky-names.dump &&
+	svnadmin load -q '$rawsvnrepo' < ../t9115/funky-names.dump &&
 	start_httpd
 	"
 
 test_expect_success 'init and fetch repository' "
-	git svn init $svnrepo &&
+	git svn init '$svnrepo' &&
 	git svn fetch &&
 	git reset --hard git-svn
 	"
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index 0d4e6b3..70c0c5f 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -14,9 +14,9 @@ test_expect_success 'setup repository and import' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . '$svnrepo'
 		cd .. &&
-	git-svn init $svnrepo -T trunk -b branches -t tags &&
+	git-svn init '$svnrepo' -T trunk -b branches -t tags &&
 	git-svn fetch &&
 	git reset --hard trunk &&
 	echo bye >> README &&
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 642b836..b90e78c 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -45,13 +45,13 @@ gitweb_run () {
 	export QUERY_STRING=""$1""
 	export PATH_INFO=""$2""
 
-	export GITWEB_CONFIG=$(pwd)/gitweb_config.perl
+	export GITWEB_CONFIG="$(pwd)/gitweb_config.perl"
 
 	# some of git commands write to STDERR on error, but this is not
 	# written to web server logs, so we are not interested in that:
 	# we are interested only in properly formatted errors/warnings
 	rm -f gitweb.log &&
-	perl -- $(pwd)/../../gitweb/gitweb.perl \
+	perl -- "$(pwd)/../../gitweb/gitweb.perl" \
 		>/dev/null 2>gitweb.log &&
 	if grep -q -s "^[[]" gitweb.log >/dev/null; then false; else true; fi
 
diff --git a/t/test-lib.sh b/t/test-lib.sh
index cc1253c..a68415f 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -229,7 +229,7 @@ test_create_repo () {
 	repo="$1"
 	mkdir "$repo"
 	cd "$repo" || error "Cannot setup test environment"
-	"$GIT_EXEC_PATH/git" init --template=$GIT_EXEC_PATH/templates/blt/ >/dev/null 2>&1 ||
+	"$GIT_EXEC_PATH/git" init --template="$GIT_EXEC_PATH/templates/blt/" >/dev/null 2>&1 ||
 	error "cannot run git init -- have you built things yet?"
 	mv .git/hooks .git/hooks-disabled
 	cd "$owd"
-- 
1.5.3.1

^ permalink raw reply related	[relevance 7%]

* RE: Is there any plan to support partial checkout or submoudule improvement?
  @ 2007-10-16  9:56  4% ` franky
  0 siblings, 0 replies; 200+ results
From: franky @ 2007-10-16  9:56 UTC (permalink / raw)
  To: 'Lars Hjemli'; +Cc: git

> Well, there is always
> 
> $ git archive --remote=<repo> <revspec> <path> | tar -x
> 
> This is effectively a partial checkout of an arbitrary revision from a
> remote repo.
> 
> --
That's actually "a single command", but a little complex. And there still
are some problems with this single command

1. each time is full checkout (not incremental), so bad performance for
large bin directory
2. I can't know deployment version easily and I can't use "git-log" to see
the log and to decide which version to back to when necessary.

I just find an ugly resolution:
1. git-clone host:project.git project
Cloned project is as follows (src, bin are subdir instead of submodule)
project
    src
    bin
    .git

2. cd project && rm -rf src
3. when project.git changed, then
   git-fetch && git-checkout origin/master bin

Unfortulately, it's annoying when I run git-status which complains "deleted:
src ". And "git-log" will not show the newest log since git-checkout doesn't
update the index file

So, the alternative for the 3rd step is
	git-pull && rm src

It's so ugly!

Suggestion 1: how about adding a paths option for git-status just like
git-diff and git-log
Suggestion 2: how about changes the default paths for "git-diff", "git-log"
and so on from the "top dir with .git" to "the current dir"? So when I'm in
bin directory and run "git-log", it will only report log or diff in bin
directory.
franky

^ permalink raw reply	[relevance 4%]

* [PATCH 2/2] Quoting paths in tests
  @ 2007-10-17  9:31  6%     ` Jonathan del Strother
  0 siblings, 0 replies; 200+ results
From: Jonathan del Strother @ 2007-10-17  9:31 UTC (permalink / raw)
  To: git; +Cc: Jonathan del Strother

From: Jonathan del Strother <jon.delStrother@bestbefore.tv>

Double-quoting all paths so the tests can be run from inside directories with spaces and apostrophes

Signed-off-by: Jonathan del Strother <jon.delStrother@bestbefore.tv>
---
 t/lib-git-svn.sh                         |    2 +-
 t/t1020-subdirectory.sh                  |   22 ++++++------
 t/t3050-subprojects-fetch.sh             |    2 +-
 t/t3404-rebase-interactive.sh            |    2 +-
 t/t5500-fetch-pack.sh                    |    2 +-
 t/t5700-clone-reference.sh               |    2 +-
 t/t7003-filter-branch.sh                 |    2 +-
 t/t7501-commit.sh                        |    4 +-
 t/t9100-git-svn-basic.sh                 |   54 +++++++++++++++---------------
 t/t9101-git-svn-props.sh                 |    6 ++--
 t/t9102-git-svn-deep-rmdir.sh            |    6 ++--
 t/t9104-git-svn-follow-parent.sh         |   50 ++++++++++++++--------------
 t/t9105-git-svn-commit-diff.sh           |   12 +++---
 t/t9106-git-svn-commit-diff-clobber.sh   |   14 ++++----
 t/t9107-git-svn-migrate.sh               |   40 +++++++++++-----------
 t/t9108-git-svn-glob.sh                  |    8 ++--
 t/t9110-git-svn-use-svm-props.sh         |    8 ++--
 t/t9111-git-svn-use-svnsync-props.sh     |    8 ++--
 t/t9112-git-svn-md5less-file.sh          |    4 +-
 t/t9113-git-svn-dcommit-new-file.sh      |    6 ++--
 t/t9114-git-svn-dcommit-merge.sh         |    4 +-
 t/t9115-git-svn-dcommit-funky-renames.sh |    4 +-
 t/t9116-git-svn-log.sh                   |    4 +-
 t/t9500-gitweb-standalone-no-errors.sh   |    4 +-
 t/test-lib.sh                            |    2 +-
 25 files changed, 136 insertions(+), 136 deletions(-)

diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh
index 8d4a447..cde3053 100644
--- a/t/lib-git-svn.sh
+++ b/t/lib-git-svn.sh
@@ -25,7 +25,7 @@ perl -w -e "
 use SVN::Core;
 use SVN::Repos;
 \$SVN::Core::VERSION gt '1.1.0' or exit(42);
-system(qw/svnadmin create --fs-type fsfs/, '$svnrepo') == 0 or exit(41);
+system(qw/svnadmin create --fs-type fsfs/, \"$svnrepo\") == 0 or exit(41);
 " >&3 2>&4
 x=$?
 if test $x -ne 0
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index b9cef34..5ed7fa4 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -21,7 +21,7 @@ LF='
 '
 
 test_expect_success 'update-index and ls-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git update-index --add one &&
 	case "`git ls-files`" in
 	one) echo ok one ;;
@@ -41,7 +41,7 @@ test_expect_success 'update-index and ls-files' '
 '
 
 test_expect_success 'cat-file' '
-	cd $HERE &&
+	cd "$HERE" &&
 	two=`git ls-files -s dir/two` &&
 	two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
 	echo "$two" &&
@@ -54,7 +54,7 @@ test_expect_success 'cat-file' '
 rm -f actual dir/actual
 
 test_expect_success 'diff-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	echo a >>one &&
 	echo d >>dir/two &&
 	case "`git diff-files --name-only`" in
@@ -74,7 +74,7 @@ test_expect_success 'diff-files' '
 '
 
 test_expect_success 'write-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	top=`git write-tree` &&
 	echo $top &&
 	cd dir &&
@@ -84,7 +84,7 @@ test_expect_success 'write-tree' '
 '
 
 test_expect_success 'checkout-index' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git checkout-index -f -u one &&
 	cmp one original.one &&
 	cd dir &&
@@ -93,7 +93,7 @@ test_expect_success 'checkout-index' '
 '
 
 test_expect_success 'read-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -f one dir/two &&
 	tree=`git write-tree` &&
 	git read-tree --reset -u "$tree" &&
@@ -107,27 +107,27 @@ test_expect_success 'read-tree' '
 '
 
 test_expect_success 'no file/rev ambiguity check inside .git' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git commit -a -m 1 &&
-	cd $HERE/.git &&
+	cd "$HERE/.git" &&
 	git show -s HEAD
 '
 
 test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && GIT_DIR=. git show -s HEAD
 '
 
 # This still does not work as it should...
 : test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && git show -s HEAD
 '
 
 test_expect_success 'detection should not be fooled by a symlink' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -fr foo.git &&
 	git clone -s .git another &&
 	ln -s another yetanother &&
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 34f26a8..4b74cc6 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -20,7 +20,7 @@ test_expect_success setup '
 '
 
 test_expect_success clone '
-	git clone file://`pwd`/.git cloned &&
+	git clone "file://`pwd`/.git" cloned &&
 	(git rev-parse HEAD; git ls-files -s) >expected &&
 	(
 		cd cloned &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 1113904..aa86042 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -92,7 +92,7 @@ done
 EOF
 
 chmod a+x fake-editor.sh
-VISUAL="$(pwd)/fake-editor.sh"
+VISUAL="\"$(pwd)/fake-editor.sh\""
 export VISUAL
 
 test_expect_success 'no changes are a nop' '
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 7b6798d..5489ffe 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -129,7 +129,7 @@ pull_to_client 2nd "B" $((64*3))
 
 pull_to_client 3rd "A" $((1*3)) # old fails
 
-test_expect_success "clone shallow" "git-clone --depth 2 file://`pwd`/. shallow"
+test_expect_success "clone shallow" "git-clone --depth 2 \"file://`pwd`/.\" shallow"
 
 (cd shallow; git count-objects -v) > count.shallow
 
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index 4e93aaa..8bb34f9 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -51,7 +51,7 @@ diff expected current'
 cd "$base_dir"
 
 test_expect_success 'cloning with reference (no -l -s)' \
-'git clone --reference B file://`pwd`/A D'
+'git clone --reference B "file://`pwd`/A" D'
 
 cd "$base_dir"
 
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index e935b20..1ab5392 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -107,7 +107,7 @@ test_expect_success 'use index-filter to move into a subdirectory' '
 		 "git ls-files -s | sed \"s-\\t-&newsubdir/-\" |
 	          GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
 			git update-index --index-info &&
-		  mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
+		  mv \"\$GIT_INDEX_FILE.new\" \"\$GIT_INDEX_FILE\"" directorymoved &&
 	test -z "$(git diff HEAD directorymoved:newsubdir)"'
 
 test_expect_success 'stops when msg filter fails' '
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index b151b51..e97e756 100644
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -69,7 +69,7 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -i -e "s/a file/an amend commit/g" $1
+sed -i -e "s/a file/an amend commit/g" "$1"
 EOF
 chmod 755 editor
 
@@ -88,7 +88,7 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -i -e "s/amend/older/g" $1
+sed -i -e "s/amend/older/g" "$1"
 EOF
 chmod 755 editor
 
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 614cf50..1d802a8 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -31,16 +31,16 @@ test_expect_success \
 	echo 'zzz' > bar/zzz &&
 	echo '#!/bin/sh' > exec.sh &&
 	chmod +x exec.sh &&
-	svn import -m 'import for git-svn' . $svnrepo >/dev/null &&
+	svn import -m 'import for git-svn' . \"$svnrepo\" >/dev/null &&
 	cd .. &&
 	rm -rf import &&
-	git-svn init $svnrepo"
+	git-svn init \"$svnrepo\""
 
 test_expect_success \
     'import an SVN revision into git' \
     'git-svn fetch'
 
-test_expect_success "checkout from svn" "svn co $svnrepo '$SVN_TREE'"
+test_expect_success "checkout from svn" "svn co \"$svnrepo\" \"$SVN_TREE\""
 
 name='try a deep --rmdir with a commit'
 test_expect_success "$name" "
@@ -51,8 +51,8 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch &&
-	svn up '$SVN_TREE' &&
-	test -d '$SVN_TREE'/dir && test ! -d '$SVN_TREE'/dir/a"
+	svn up \"$SVN_TREE\" &&
+	test -d \"$SVN_TREE\"/dir && test ! -d \"$SVN_TREE\"/dir/a"
 
 
 name='detect node change from file to directory #1'
@@ -69,7 +69,7 @@ test_expect_failure "$name" "
 
 name='detect node change from directory to file #1'
 test_expect_failure "$name" "
-	rm -rf dir '$GIT_DIR'/index &&
+	rm -rf dir \"$GIT_DIR\"/index &&
 	git checkout -f -b mybranch2 remotes/git-svn &&
 	mv bar/zzz zzz &&
 	rm -rf bar &&
@@ -83,7 +83,7 @@ test_expect_failure "$name" "
 
 name='detect node change from file to directory #2'
 test_expect_failure "$name" "
-	rm -f '$GIT_DIR'/index &&
+	rm -f \"$GIT_DIR\"/index &&
 	git checkout -f -b mybranch3 remotes/git-svn &&
 	rm bar/zzz &&
 	git update-index --remove bar/zzz &&
@@ -97,7 +97,7 @@ test_expect_failure "$name" "
 
 name='detect node change from directory to file #2'
 test_expect_failure "$name" "
-	rm -f '$GIT_DIR'/index &&
+	rm -f \"$GIT_DIR\"/index &&
 	git checkout -f -b mybranch4 remotes/git-svn &&
 	rm -rf dir &&
 	git update-index --remove -- dir/file &&
@@ -111,15 +111,15 @@ test_expect_failure "$name" "
 
 name='remove executable bit from a file'
 test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+	rm -f \"$GIT_DIR\"/index &&
 	git checkout -f -b mybranch5 remotes/git-svn &&
 	chmod -x exec.sh &&
 	git update-index exec.sh &&
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test ! -x '$SVN_TREE'/exec.sh"
+	svn up \"$SVN_TREE\" &&
+	test ! -x \"$SVN_TREE\"/exec.sh"
 
 
 name='add executable bit back file'
@@ -129,8 +129,8 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -x '$SVN_TREE'/exec.sh"
+	svn up \"$SVN_TREE\" &&
+	test -x \"$SVN_TREE\"/exec.sh"
 
 
 name='executable file becomes a symlink to bar/zzz (file)'
@@ -141,8 +141,8 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -L '$SVN_TREE'/exec.sh"
+	svn up \"$SVN_TREE\" &&
+	test -L \"$SVN_TREE\"/exec.sh"
 
 name='new symlink is added to a file that was also just made executable'
 
@@ -153,9 +153,9 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -x '$SVN_TREE'/bar/zzz &&
-	test -L '$SVN_TREE'/exec-2.sh"
+	svn up \"$SVN_TREE\" &&
+	test -x \"$SVN_TREE\"/bar/zzz &&
+	test -L \"$SVN_TREE\"/exec-2.sh"
 
 name='modify a symlink to become a file'
 test_expect_success "$name" "
@@ -166,10 +166,10 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -f '$SVN_TREE'/exec-2.sh &&
-	test ! -L '$SVN_TREE'/exec-2.sh &&
-	git diff help $SVN_TREE/exec-2.sh"
+	svn up \"$SVN_TREE\" &&
+	test -f \"$SVN_TREE\"/exec-2.sh &&
+	test ! -L \"$SVN_TREE\"/exec-2.sh &&
+	git diff help \"$SVN_TREE\"/exec-2.sh"
 
 if test "$have_utf8" = t
 then
@@ -190,7 +190,7 @@ name='test fetch functionality (svn => git) with alternate GIT_SVN_ID'
 GIT_SVN_ID=alt
 export GIT_SVN_ID
 test_expect_success "$name" \
-    "git-svn init $svnrepo && git-svn fetch &&
+    "git-svn init \"$svnrepo\" && git-svn fetch &&
      git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a &&
      git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
      git diff a b"
@@ -220,16 +220,16 @@ test_expect_failure 'exit if remote refs are ambigious' "
         "
 
 test_expect_failure 'exit if init-ing a would clobber a URL' "
-        svnadmin create ${PWD}/svnrepo2 &&
-        svn mkdir -m 'mkdir bar' ${svnrepo}2/bar &&
+        svnadmin create \"${PWD}/svnrepo2\" &&
+        svn mkdir -m 'mkdir bar' \"${svnrepo}2/bar\" &&
         git config --unset svn-remote.svn.fetch \
                                 '^bar:refs/remotes/git-svn$' &&
-        git-svn init ${svnrepo}2/bar
+        git-svn init \"${svnrepo}2/bar\"
         "
 
 test_expect_success \
   'init allows us to connect to another directory in the same repo' "
-        git-svn init --minimize-url -i bar $svnrepo/bar &&
+        git-svn init --minimize-url -i bar \"$svnrepo/bar\" &&
         git config --get svn-remote.svn.fetch \
                               '^bar:refs/remotes/bar$' &&
         git config --get svn-remote.svn.fetch \
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index 5aac644..e741bfe 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -52,7 +52,7 @@ EOF
 cd ..
 
 rm -rf import
-test_expect_success 'checkout working copy from svn' "svn co $svnrepo test_wc"
+test_expect_success 'checkout working copy from svn' "svn co \"$svnrepo\" test_wc"
 test_expect_success 'setup some commits to svn' \
 	'cd test_wc &&
 		echo Greetings >> kw.c &&
@@ -66,7 +66,7 @@ test_expect_success 'setup some commits to svn' \
 		svn commit -m "Propset Id" &&
 	cd ..'
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init \"$svnrepo\""
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 
 name='test svn:keywords ignoring'
@@ -92,7 +92,7 @@ test_expect_success "propset CR on crlf files" \
 test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
 	"git-svn fetch &&
 	 git pull . remotes/git-svn &&
-	 svn co $svnrepo new_wc"
+	 svn co \"$svnrepo\" new_wc"
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh
index 4e08083..e3af319 100755
--- a/t/t9102-git-svn-deep-rmdir.sh
+++ b/t/t9102-git-svn-deep-rmdir.sh
@@ -9,12 +9,12 @@ test_expect_success 'initialize repo' "
 	mkdir -p deeply/nested/directory/number/2 &&
 	echo foo > deeply/nested/directory/number/1/file &&
 	echo foo > deeply/nested/directory/number/2/another &&
-	svn import -m 'import for git-svn' . $svnrepo &&
+	svn import -m 'import for git-svn' . \"$svnrepo\" &&
 	cd ..
 	"
 
 test_expect_success 'mirror via git-svn' "
-	git-svn init $svnrepo &&
+	git-svn init \"$svnrepo\" &&
 	git-svn fetch &&
 	git checkout -f -b test-rmdir remotes/git-svn
 	"
@@ -23,7 +23,7 @@ test_expect_success 'Try a commit on rmdir' "
 	git rm -f deeply/nested/directory/number/2/another &&
 	git commit -a -m 'remove another' &&
 	git-svn set-tree --rmdir HEAD &&
-	svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1
+	svn ls -R \"$svnrepo\" | grep ^deeply/nested/directory/number/1
 	"
 
 
diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 7ba7630..a422afa 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -11,9 +11,9 @@ test_expect_success 'initialize repo' "
 	cd import &&
 	mkdir -p trunk &&
 	echo hello > trunk/readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . \"$svnrepo\" &&
 	cd .. &&
-	svn co $svnrepo wc &&
+	svn co \"$svnrepo\" wc &&
 	cd wc &&
 	echo world >> trunk/readme &&
 	poke trunk/readme &&
@@ -27,7 +27,7 @@ test_expect_success 'initialize repo' "
 	"
 
 test_expect_success 'init and fetch a moved directory' "
-	git-svn init --minimize-url -i thunk $svnrepo/thunk &&
+	git-svn init --minimize-url -i thunk \"$svnrepo/thunk\" &&
 	git-svn fetch -i thunk &&
 	test \"\`git rev-parse --verify refs/remotes/thunk@2\`\" \
            = \"\`git rev-parse --verify refs/remotes/thunk~1\`\" &&
@@ -38,7 +38,7 @@ test_expect_success 'init and fetch a moved directory' "
 	"
 
 test_expect_success 'init and fetch from one svn-remote' "
-        git config svn-remote.svn.url $svnrepo &&
+        git config svn-remote.svn.url \"$svnrepo\" &&
         git config --add svn-remote.svn.fetch \
           trunk:refs/remotes/svn/trunk &&
         git config --add svn-remote.svn.fetch \
@@ -52,9 +52,9 @@ test_expect_success 'init and fetch from one svn-remote' "
 
 test_expect_success 'follow deleted parent' "
         (svn cp -m 'resurrecting trunk as junk' \
-               $svnrepo/trunk@2 $svnrepo/junk ||
+               \"$svnrepo/trunk@2\" \"$svnrepo\"/junk ||
          svn cp -m 'resurrecting trunk as junk' \
-               -r2 $svnrepo/trunk $svnrepo/junk) &&
+               -r2 \"$svnrepo/trunk\" \"$svnrepo/junk\") &&
         git config --add svn-remote.svn.fetch \
           junk:refs/remotes/svn/junk &&
         git-svn fetch -i svn/thunk &&
@@ -67,10 +67,10 @@ test_expect_success 'follow deleted parent' "
 test_expect_success 'follow larger parent' "
         mkdir -p import/trunk/thunk/bump/thud &&
         echo hi > import/trunk/thunk/bump/thud/file &&
-        svn import -m 'import a larger parent' import $svnrepo/larger-parent &&
-        svn cp -m 'hi' $svnrepo/larger-parent $svnrepo/another-larger &&
+        svn import -m 'import a larger parent' import \"$svnrepo/larger-parent\" &&
+        svn cp -m 'hi' \"$svnrepo/larger-parent\" \"$svnrepo/another-larger\" &&
         git-svn init --minimize-url -i larger \
-          $svnrepo/another-larger/trunk/thunk/bump/thud &&
+          \"$svnrepo/another-larger/trunk/thunk/bump/thud\" &&
         git-svn fetch -i larger &&
         git rev-parse --verify refs/remotes/larger &&
         git rev-parse --verify \
@@ -83,23 +83,23 @@ test_expect_success 'follow larger parent' "
         "
 
 test_expect_success 'follow higher-level parent' "
-        svn mkdir -m 'follow higher-level parent' $svnrepo/blob &&
-        svn co $svnrepo/blob blob &&
+        svn mkdir -m 'follow higher-level parent' \"$svnrepo/blob\" &&
+        svn co \"$svnrepo/blob\" blob &&
         cd blob &&
                 echo hi > hi &&
                 svn add hi &&
                 svn commit -m 'hihi' &&
                 cd ..
-        svn mkdir -m 'new glob at top level' $svnrepo/glob &&
-        svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
-        git-svn init --minimize-url -i blob $svnrepo/glob/blob &&
+        svn mkdir -m 'new glob at top level' \"$svnrepo/glob\" &&
+        svn mv -m 'move blob down a level' \"$svnrepo/blob\" \"$svnrepo/glob/blob\" &&
+        git-svn init --minimize-url -i blob \"$svnrepo/glob/blob\" &&
         git-svn fetch -i blob
         "
 
 test_expect_success 'follow deleted directory' "
-	svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye &&
-	svn rm -m 'remove glob' $svnrepo/glob &&
-	git-svn init --minimize-url -i glob $svnrepo/glob &&
+	svn mv -m 'bye!' \"$svnrepo/glob/blob/hi\" \"$svnrepo/glob/blob/bye\" &&
+	svn rm -m 'remove glob' \"$svnrepo/glob\" &&
+	git-svn init --minimize-url -i glob \"$svnrepo/glob\" &&
 	git-svn fetch -i glob &&
 	test \"\`git cat-file blob refs/remotes/glob:blob/bye\`\" = hi &&
 	test \"\`git ls-tree refs/remotes/glob | wc -l \`\" -eq 1
@@ -118,9 +118,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  echo 'bad delete test 2' > \
 	   import/trunk/subversion/bindings/swig/perl/another-larger &&
 	cd import &&
-	  svn import -m 'r9270 test' . $svnrepo/r9270 &&
+	  svn import -m 'r9270 test' . \"$svnrepo/r9270\" &&
 	cd .. &&
-	svn co $svnrepo/r9270/trunk/subversion/bindings/swig/perl r9270 &&
+	svn co \"$svnrepo/r9270/trunk/subversion/bindings/swig/perl\" r9270 &&
 	cd r9270 &&
 	  svn mkdir native &&
 	  svn mv t native/t &&
@@ -130,7 +130,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  svn commit -m 'reorg test' &&
 	cd .. &&
 	git-svn init --minimize-url -i r9270-t \
-	  $svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t &&
+	  \"$svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t\" &&
 	git-svn fetch -i r9270-t &&
 	test \`git rev-list r9270-t | wc -l\` -eq 2 &&
 	test \"\`git ls-tree --name-only r9270-t~1\`\" = \
@@ -138,9 +138,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	"
 
 test_expect_success "track initial change if it was only made to parent" "
-	svn cp -m 'wheee!' $svnrepo/r9270/trunk $svnrepo/r9270/drunk &&
+	svn cp -m 'wheee!' \"$svnrepo/r9270/trunk\" \"$svnrepo/r9270/drunk\" &&
 	git-svn init --minimize-url -i r9270-d \
-	  $svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t &&
+	  \"$svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t\" &&
 	git-svn fetch -i r9270-d &&
 	test \`git rev-list r9270-d | wc -l\` -eq 3 &&
 	test \"\`git ls-tree --name-only r9270-t\`\" = \
@@ -150,7 +150,7 @@ test_expect_success "track initial change if it was only made to parent" "
 	"
 
 test_expect_success "track multi-parent paths" "
-	svn cp -m 'resurrect /glob' $svnrepo/r9270 $svnrepo/glob &&
+	svn cp -m 'resurrect /glob' \"$svnrepo/r9270\" \"$svnrepo/glob\" &&
 	git-svn multi-fetch &&
 	test \`git cat-file commit refs/remotes/glob | \
 	       grep '^parent ' | wc -l\` -eq 2
@@ -161,8 +161,8 @@ test_expect_success "multi-fetch continues to work" "
 	"
 
 test_expect_success "multi-fetch works off a 'clean' repository" "
-	rm -r $GIT_DIR/svn $GIT_DIR/refs/remotes $GIT_DIR/logs &&
-	mkdir $GIT_DIR/svn &&
+	rm -r \"$GIT_DIR/svn\" \"$GIT_DIR/refs/remotes\" \"$GIT_DIR/logs\" &&
+	mkdir \"$GIT_DIR/svn\" &&
 	git-svn multi-fetch
 	"
 
diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh
index 318e172..9cc38d3 100755
--- a/t/t9105-git-svn-commit-diff.sh
+++ b/t/t9105-git-svn-commit-diff.sh
@@ -8,7 +8,7 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo hello > readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . \"$svnrepo\" &&
 	cd .. &&
 	echo hello > readme &&
 	git update-index --add readme &&
@@ -26,17 +26,17 @@ prev=`git rev-parse --verify HEAD^1`
 
 test_expect_success 'test the commit-diff command' "
 	test -n '$prev' && test -n '$head' &&
-	git-svn commit-diff -r1 '$prev' '$head' '$svnrepo' &&
-	svn co $svnrepo wc &&
+	git-svn commit-diff -r1 '$prev' '$head' \"$svnrepo\" &&
+	svn co \"$svnrepo\" wc &&
 	cmp readme wc/readme
 	"
 
 test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
-	svn import -m 'sub-directory' import $svnrepo/subdir &&
-	git-svn init --minimize-url $svnrepo/subdir &&
+	svn import -m 'sub-directory' import \"$svnrepo/subdir\" &&
+	git-svn init --minimize-url \"$svnrepo/subdir\" &&
 	git-svn fetch &&
 	git-svn commit-diff -r3 '$prev' '$head' &&
-	svn cat $svnrepo/subdir/readme > readme.2 &&
+	svn cat \"$svnrepo/subdir/readme\" > readme.2 &&
 	cmp readme readme.2
 	"
 
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index 79b7968..892ca55 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -8,14 +8,14 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo initial > file &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . \"$svnrepo\" &&
 	cd .. &&
 	echo initial > file &&
 	git update-index --add file &&
 	git commit -a -m 'initial'
 	"
 test_expect_success 'commit change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co \"$svnrepo\" t.svn &&
 	cd t.svn &&
 	echo second line from svn >> file &&
 	poke file &&
@@ -27,7 +27,7 @@ test_expect_success 'commit change from svn side' "
 test_expect_failure 'commit conflicting change from git' "
 	echo second line from git >> file &&
 	git commit -a -m 'second line from git' &&
-	git-svn commit-diff -r1 HEAD~1 HEAD $svnrepo
+	git-svn commit-diff -r1 HEAD~1 HEAD \"$svnrepo\"
 	" || true
 
 test_expect_success 'commit complementing change from git' "
@@ -36,14 +36,14 @@ test_expect_success 'commit complementing change from git' "
 	git commit -a -m 'second line from svn' &&
 	echo third line from git >> file &&
 	git commit -a -m 'third line from git' &&
-	git-svn commit-diff -r2 HEAD~1 HEAD $svnrepo
+	git-svn commit-diff -r2 HEAD~1 HEAD \"$svnrepo\"
 	"
 
 test_expect_failure 'dcommit fails to commit because of conflict' "
-	git-svn init $svnrepo &&
+	git-svn init \"$svnrepo\" &&
 	git-svn fetch &&
 	git reset --hard refs/remotes/git-svn &&
-	svn co $svnrepo t.svn &&
+	svn co \"$svnrepo\" t.svn &&
 	cd t.svn &&
 	echo fourth line from svn >> file &&
 	poke file &&
@@ -67,7 +67,7 @@ test_expect_success 'dcommit does the svn equivalent of an index merge' "
 	"
 
 test_expect_success 'commit another change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co \"$svnrepo\" t.svn &&
 	cd t.svn &&
 		echo third line from svn >> file &&
 		poke file &&
diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index 67fdf70..59e8f0d 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -4,7 +4,7 @@ test_description='git-svn metadata migrations from previous versions'
 . ./lib-git-svn.sh
 
 test_expect_success 'setup old-looking metadata' "
-	cp $GIT_DIR/config $GIT_DIR/config-old-git-svn &&
+	cp \"$GIT_DIR/config\" \"$GIT_DIR/config-old-git-svn\" &&
 	mkdir import &&
 	cd import &&
 		for i in trunk branches/a branches/b \
@@ -12,13 +12,13 @@ test_expect_success 'setup old-looking metadata' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . \"$svnrepo\"
 		cd .. &&
-	git-svn init $svnrepo &&
+	git-svn init \"$svnrepo\" &&
 	git-svn fetch &&
-	mv $GIT_DIR/svn/* $GIT_DIR/ &&
-	mv $GIT_DIR/svn/.metadata $GIT_DIR/ &&
-	rmdir $GIT_DIR/svn &&
+	mv \"$GIT_DIR\"/svn/* \"$GIT_DIR/\" &&
+	mv \"$GIT_DIR/svn/.metadata\" \"$GIT_DIR/\" &&
+	rmdir \"$GIT_DIR/svn\" &&
 	git update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn &&
 	git update-ref refs/heads/svn-HEAD refs/remotes/git-svn &&
 	git update-ref -d refs/remotes/git-svn refs/remotes/git-svn
@@ -28,20 +28,20 @@ head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
 test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
 
 test_expect_success 'initialize old-style (v0) git-svn layout' "
-	mkdir -p $GIT_DIR/git-svn/info $GIT_DIR/svn/info &&
-	echo $svnrepo > $GIT_DIR/git-svn/info/url &&
-	echo $svnrepo > $GIT_DIR/svn/info/url &&
+	mkdir -p \"$GIT_DIR/git-svn/info\" \"$GIT_DIR/svn/info\" &&
+	echo \"$svnrepo\" > \"$GIT_DIR/git-svn/info/url\" &&
+	echo \"$svnrepo\" > \"$GIT_DIR/svn/info/url\" &&
 	git-svn migrate &&
-	! test -d $GIT_DIR/git-svn &&
+	! test -d \"$GIT_DIR/git-svn\" &&
 	git rev-parse --verify refs/remotes/git-svn^0 &&
 	git rev-parse --verify refs/remotes/svn^0 &&
-	test \`git config --get svn-remote.svn.url\` = '$svnrepo' &&
+	test \"\`git config --get svn-remote.svn.url\`\" = \"$svnrepo\" &&
 	test \`git config --get svn-remote.svn.fetch\` = \
              ':refs/remotes/git-svn'
 	"
 
 test_expect_success 'initialize a multi-repository repo' "
-	git-svn init $svnrepo -T trunk -t tags -b branches &&
+	git-svn init \"$svnrepo\" -T trunk -t tags -b branches &&
 	git config --get-all svn-remote.svn.fetch > fetch.out &&
 	grep '^trunk:refs/remotes/trunk$' fetch.out &&
 	test -n \"\`git config --get svn-remote.svn.branches \
@@ -76,14 +76,14 @@ test_expect_success 'multi-fetch works on partial urls + paths' "
 test_expect_success 'migrate --minimize on old inited layout' "
 	git config --unset-all svn-remote.svn.fetch &&
 	git config --unset-all svn-remote.svn.url &&
-	rm -rf $GIT_DIR/svn &&
+	rm -rf \"$GIT_DIR/svn\" &&
 	for i in \`cat fetch.out\`; do
 		path=\`expr \$i : '\\([^:]*\\):.*$'\`
 		ref=\`expr \$i : '[^:]*:refs/remotes/\\(.*\\)$'\`
 		if test -z \"\$ref\"; then continue; fi
 		if test -n \"\$path\"; then path=\"/\$path\"; fi
-		( mkdir -p $GIT_DIR/svn/\$ref/info/ &&
-		echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
+		( mkdir -p \"$GIT_DIR\"/svn/\$ref/info/ &&
+		echo \"$svnrepo\"\$path > \"$GIT_DIR\"/svn/\$ref/info/url ) || exit 1;
 	done &&
 	git-svn migrate --minimize &&
 	test -z \"\`git config -l |grep -v '^svn-remote\.git-svn\.'\`\" &&
@@ -99,13 +99,13 @@ test_expect_success 'migrate --minimize on old inited layout' "
 
 test_expect_success  ".rev_db auto-converted to .rev_db.UUID" "
 	git-svn fetch -i trunk &&
-	expect=$GIT_DIR/svn/trunk/.rev_db.* &&
+	expect=\"\`find \"\$GIT_DIR\"/svn/trunk/ -name '.rev_db.*'\`\" &&
 	test -n \"\$expect\" &&
-	mv \$expect $GIT_DIR/svn/trunk/.rev_db &&
+	mv \"\$expect\" \"\$GIT_DIR\"/svn/trunk/.rev_db &&
 	git-svn fetch -i trunk &&
-	test -L $GIT_DIR/svn/trunk/.rev_db &&
-	test -f \$expect &&
-	cmp \$expect $GIT_DIR/svn/trunk/.rev_db
+	test -L \"\$GIT_DIR\"/svn/trunk/.rev_db &&
+	test -f \"\$expect\" &&
+	cmp \"\$expect\" \"\$GIT_DIR\"/svn/trunk/.rev_db
 	"
 
 test_done
diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh
index db4344c..eb039ef 100755
--- a/t/t9108-git-svn-glob.sh
+++ b/t/t9108-git-svn-glob.sh
@@ -14,8 +14,8 @@ test_expect_success 'test refspec globbing' "
 	mkdir -p trunk/src/a trunk/src/b trunk/doc &&
 	echo 'hello world' > trunk/src/a/readme &&
 	echo 'goodbye world' > trunk/src/b/readme &&
-	svn import -m 'initial' trunk $svnrepo/trunk &&
-	svn co $svnrepo tmp &&
+	svn import -m 'initial' trunk \"$svnrepo/trunk\" &&
+	svn co \"$svnrepo\" tmp &&
 	cd tmp &&
 		mkdir branches tags &&
 		svn add branches tags &&
@@ -38,7 +38,7 @@ test_expect_success 'test refspec globbing' "
 		poke tags/end/src/b/readme &&
 		svn commit -m 'nothing to see here'
 		cd .. &&
-	git config --add svn-remote.svn.url $svnrepo &&
+	git config --add svn-remote.svn.url \"$svnrepo\" &&
 	git config --add svn-remote.svn.fetch \
 	                 'trunk/src/a:refs/remotes/trunk' &&
 	git config --add svn-remote.svn.branches \
@@ -60,7 +60,7 @@ echo nothing to see here >> expect.two
 cat expect.end >> expect.two
 
 test_expect_success 'test left-hand-side only globbing' "
-	git config --add svn-remote.two.url $svnrepo &&
+	git config --add svn-remote.two.url \"$svnrepo\" &&
 	git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
 	git config --add svn-remote.two.branches \
 	                 'branches/*:refs/remotes/two/branches/*' &&
diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh
index 6235af4..9df60ba 100755
--- a/t/t9110-git-svn-use-svm-props.sh
+++ b/t/t9110-git-svn-use-svm-props.sh
@@ -8,11 +8,11 @@ test_description='git-svn useSvmProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svm repo' "
-	svnadmin load -q $rawsvnrepo < ../t9110/svm.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/mirror/arr &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/mirror/argh &&
+	svnadmin load -q \"$rawsvnrepo\" < ../t9110/svm.dump &&
+	git-svn init --minimize-url -R arr -i bar \"$svnrepo/mirror/arr\" &&
+	git-svn init --minimize-url -R argh -i dir \"$svnrepo/mirror/argh\" &&
 	git-svn init --minimize-url -R argh -i e \
-	  $svnrepo/mirror/argh/a/b/c/d/e &&
+	  \"$svnrepo/mirror/argh/a/b/c/d/e\" &&
 	git config svn.useSvmProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9111-git-svn-use-svnsync-props.sh b/t/t9111-git-svn-use-svnsync-props.sh
index ec7dedd..e3693eb 100755
--- a/t/t9111-git-svn-use-svnsync-props.sh
+++ b/t/t9111-git-svn-use-svnsync-props.sh
@@ -8,10 +8,10 @@ test_description='git-svn useSvnsyncProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svnsync repo' "
-	svnadmin load -q $rawsvnrepo < ../t9111/svnsync.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/bar &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/dir &&
-	git-svn init --minimize-url -R argh -i e $svnrepo/dir/a/b/c/d/e &&
+	svnadmin load -q \"$rawsvnrepo\" < ../t9111/svnsync.dump &&
+	git-svn init --minimize-url -R arr -i bar \"$svnrepo/bar\" &&
+	git-svn init --minimize-url -R argh -i dir \"$svnrepo/dir\" &&
+	git-svn init --minimize-url -R argh -i e \"$svnrepo/dir/a/b/c/d/e\" &&
 	git config svn.useSvnsyncProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh
index 08313bb..124120c 100755
--- a/t/t9112-git-svn-md5less-file.sh
+++ b/t/t9112-git-svn-md5less-file.sh
@@ -38,8 +38,8 @@ PROPS-END
 
 EOF
 
-test_expect_success 'load svn dumpfile' "svnadmin load $rawsvnrepo < dumpfile.svn"
+test_expect_success 'load svn dumpfile' "svnadmin load \"$rawsvnrepo\" < dumpfile.svn"
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init \"$svnrepo\""
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 test_done
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
index 9ef0db9..150d7f0 100755
--- a/t/t9113-git-svn-dcommit-new-file.sh
+++ b/t/t9113-git-svn-dcommit-new-file.sh
@@ -15,14 +15,14 @@ test_description='git-svn dcommit new files over svn:// test'
 
 start_svnserve () {
 	svnserve --listen-port $SVNSERVE_PORT \
-	         --root $rawsvnrepo \
+	         --root "$rawsvnrepo" \
 	         --listen-once \
 	         --listen-host 127.0.0.1 &
 }
 
 test_expect_success 'start tracking an empty repo' "
-	svn mkdir -m 'empty dir' $svnrepo/empty-dir &&
-	echo anon-access = write >> $rawsvnrepo/conf/svnserve.conf &&
+	svn mkdir -m 'empty dir' \"$svnrepo/empty-dir\" &&
+	echo anon-access = write >> \"$rawsvnrepo/conf/svnserve.conf\" &&
 	start_svnserve &&
 	git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
 	git svn fetch
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
index d6ca955..ffe8859 100755
--- a/t/t9114-git-svn-dcommit-merge.sh
+++ b/t/t9114-git-svn-dcommit-merge.sh
@@ -35,7 +35,7 @@ EOF
 }
 
 test_expect_success 'setup svn repository' "
-	svn co $svnrepo mysvnwork &&
+	svn co \"$svnrepo\" mysvnwork &&
 	mkdir -p mysvnwork/trunk &&
 	cd mysvnwork &&
 		big_text_block >> trunk/README &&
@@ -45,7 +45,7 @@ test_expect_success 'setup svn repository' "
 	"
 
 test_expect_success 'setup git mirror and merge' "
-	git svn init $svnrepo -t tags -T trunk -b branches &&
+	git svn init \"$svnrepo\" -t tags -T trunk -b branches &&
 	git svn fetch &&
 	git checkout --track -b svn remotes/trunk &&
 	git checkout -b merge &&
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 182299c..0681ffa 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -8,12 +8,12 @@ test_description='git-svn dcommit can commit renames of files with ugly names'
 . ./lib-git-svn.sh
 
 test_expect_success 'load repository with strange names' "
-	svnadmin load -q $rawsvnrepo < ../t9115/funky-names.dump &&
+	svnadmin load -q \"$rawsvnrepo\" < ../t9115/funky-names.dump &&
 	start_httpd
 	"
 
 test_expect_success 'init and fetch repository' "
-	git svn init $svnrepo &&
+	git svn init \"$svnrepo\" &&
 	git svn fetch &&
 	git reset --hard git-svn
 	"
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index 0d4e6b3..890b5f1 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -14,9 +14,9 @@ test_expect_success 'setup repository and import' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . \"$svnrepo\"
 		cd .. &&
-	git-svn init $svnrepo -T trunk -b branches -t tags &&
+	git-svn init \"$svnrepo\" -T trunk -b branches -t tags &&
 	git-svn fetch &&
 	git reset --hard trunk &&
 	echo bye >> README &&
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 642b836..b90e78c 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -45,13 +45,13 @@ gitweb_run () {
 	export QUERY_STRING=""$1""
 	export PATH_INFO=""$2""
 
-	export GITWEB_CONFIG=$(pwd)/gitweb_config.perl
+	export GITWEB_CONFIG="$(pwd)/gitweb_config.perl"
 
 	# some of git commands write to STDERR on error, but this is not
 	# written to web server logs, so we are not interested in that:
 	# we are interested only in properly formatted errors/warnings
 	rm -f gitweb.log &&
-	perl -- $(pwd)/../../gitweb/gitweb.perl \
+	perl -- "$(pwd)/../../gitweb/gitweb.perl" \
 		>/dev/null 2>gitweb.log &&
 	if grep -q -s "^[[]" gitweb.log >/dev/null; then false; else true; fi
 
diff --git a/t/test-lib.sh b/t/test-lib.sh
index cc1253c..a68415f 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -229,7 +229,7 @@ test_create_repo () {
 	repo="$1"
 	mkdir "$repo"
 	cd "$repo" || error "Cannot setup test environment"
-	"$GIT_EXEC_PATH/git" init --template=$GIT_EXEC_PATH/templates/blt/ >/dev/null 2>&1 ||
+	"$GIT_EXEC_PATH/git" init --template="$GIT_EXEC_PATH/templates/blt/" >/dev/null 2>&1 ||
 	error "cannot run git init -- have you built things yet?"
 	mv .git/hooks .git/hooks-disabled
 	cd "$owd"
-- 
1.5.3.1

^ permalink raw reply related	[relevance 6%]

* stgit restrictions on patch names
@ 2007-10-25 19:48  4% Yann Dirson
  2007-10-29 16:14  0% ` Catalin Marinas
  0 siblings, 1 reply; 200+ results
From: Yann Dirson @ 2007-10-25 19:48 UTC (permalink / raw)
  To: Catalin Marinas, Karl Hasselström; +Cc: GIT list

Looks like stgit is now more picky on patch names than in used to be:

$ stg branch --clone v2.0.6-debian
Checking for changes in the working directory ... done
Cloning current branch to "v2.0.6-debian" ...
  No log for 01_springelectrical
stg branch: Invalid patch name: "10_g++4.0_build_failures"
$


=> the result of the cloning operation is a partial clone.  Do we want to:

- implement a mechanism for checking beforehand that the operation
will not fail ?  Seems awkward to duplicate checks already found
elsewhere.

- wait for proper transactions so we can rollback on error ?

- on clone error, delete the newly-created stack ?  I'd vote for this
one, until the previous one gets done.


=> is there any particular reason why we would refuse "+" ?

^ permalink raw reply	[relevance 4%]

* Re: stgit restrictions on patch names
  2007-10-25 19:48  4% stgit restrictions on patch names Yann Dirson
@ 2007-10-29 16:14  0% ` Catalin Marinas
  0 siblings, 0 replies; 200+ results
From: Catalin Marinas @ 2007-10-29 16:14 UTC (permalink / raw)
  To: Yann Dirson; +Cc: Karl Hasselström, GIT list

On 25/10/2007, Yann Dirson <ydirson@altern.org> wrote:
> Looks like stgit is now more picky on patch names than in used to be:

It's not that we explicitly disallows "+" but I think I tried to avoid
some wrong patch names but was too lazy to create a better regexp.

As a quick fix, we could re-generate a patch name if it is invalid.

> => the result of the cloning operation is a partial clone.  Do we want to:
>
> - implement a mechanism for checking beforehand that the operation
> will not fail ?  Seems awkward to duplicate checks already found
> elsewhere.
>
> - wait for proper transactions so we can rollback on error ?
>
> - on clone error, delete the newly-created stack ?  I'd vote for this
> one, until the previous one gets done.

I think the last one is the simplest to implement, while the second is
nicer, I've never found the time to investigate it properly.

-- 
Catalin

^ permalink raw reply	[relevance 0%]

* [PATCH] Updated russian translation of git-gui
@ 2007-10-31 21:16  3% Alex Riesen
  0 siblings, 0 replies; 200+ results
From: Alex Riesen @ 2007-10-31 21:16 UTC (permalink / raw)
  To: git; +Cc: Shawn O. Pearce

Fixed some spelling mistakes.
---
 po/ru.po |  516 +++++++++++++++++++++++++++++++++++---------------------------
 1 files changed, 292 insertions(+), 224 deletions(-)

diff --git a/po/ru.po b/po/ru.po
index b8e9447..6727a83 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -7,7 +7,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: git-gui\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-10-10 04:04-0400\n"
+"POT-Creation-Date: 2007-10-31 21:23+0100\n"
 "PO-Revision-Date: 2007-10-22 22:30-0200\n"
 "Last-Translator: Alex Riesen <raa.lkml@gmail.com>\n"
 "Language-Team: Russian Translation <git@vger.kernel.org>\n"
@@ -15,33 +15,33 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 
-#: git-gui.sh:41 git-gui.sh:634 git-gui.sh:648 git-gui.sh:661 git-gui.sh:744
-#: git-gui.sh:763
+#: git-gui.sh:41 git-gui.sh:597 git-gui.sh:611 git-gui.sh:624 git-gui.sh:707
+#: git-gui.sh:726
 msgid "git-gui: fatal error"
 msgstr "git-gui: критическая ошибка"
 
-#: git-gui.sh:595
+#: git-gui.sh:558
 #, tcl-format
 msgid "Invalid font specified in %s:"
 msgstr "В %s установлен неверный шрифт:"
 
-#: git-gui.sh:620
+#: git-gui.sh:583
 msgid "Main Font"
 msgstr "Шрифт интерфейса"
 
-#: git-gui.sh:621
+#: git-gui.sh:584
 msgid "Diff/Console Font"
 msgstr "Шрифт консоли и изменений (diff)"
 
-#: git-gui.sh:635
+#: git-gui.sh:598
 msgid "Cannot find git in PATH."
 msgstr "git не найден в PATH."
 
-#: git-gui.sh:662
+#: git-gui.sh:625
 msgid "Cannot parse Git version string:"
 msgstr "Невозможно распознать строку версии Git: "
 
-#: git-gui.sh:680
+#: git-gui.sh:643
 #, tcl-format
 msgid ""
 "Git version cannot be determined.\n"
@@ -59,79 +59,79 @@ msgstr ""
 "\n"
 "Принять '%s' как версию 1.5.0?\n"
 
-#: git-gui.sh:853
+#: git-gui.sh:881
 msgid "Git directory not found:"
 msgstr "Каталог Git не найден:"
 
-#: git-gui.sh:860
+#: git-gui.sh:888
 msgid "Cannot move to top of working directory:"
 msgstr "Невозможно перейти к корню рабочего каталога репозитория: "
 
-#: git-gui.sh:867
+#: git-gui.sh:895
 msgid "Cannot use funny .git directory:"
 msgstr "Каталог.git испорчен: "
 
-#: git-gui.sh:872
+#: git-gui.sh:900
 msgid "No working directory"
 msgstr "Отсутствует рабочий каталог"
 
-#: git-gui.sh:1019
+#: git-gui.sh:1047
 msgid "Refreshing file status..."
 msgstr "Обновление информации о состоянии файлов..."
 
-#: git-gui.sh:1084
+#: git-gui.sh:1112
 msgid "Scanning for modified files ..."
 msgstr "Поиск измененных файлов..."
 
-#: git-gui.sh:1259 lib/browser.tcl:245
+#: git-gui.sh:1287 lib/browser.tcl:245
 msgid "Ready."
 msgstr "Готово."
 
-#: git-gui.sh:1525
+#: git-gui.sh:1553
 msgid "Unmodified"
 msgstr "Не изменено"
 
-#: git-gui.sh:1527
+#: git-gui.sh:1555
 msgid "Modified, not staged"
 msgstr "Изменено, не подготовлено"
 
-#: git-gui.sh:1528 git-gui.sh:1533
+#: git-gui.sh:1556 git-gui.sh:1561
 msgid "Staged for commit"
 msgstr "Подготовлено для сохранения"
 
-#: git-gui.sh:1529 git-gui.sh:1534
+#: git-gui.sh:1557 git-gui.sh:1562
 msgid "Portions staged for commit"
 msgstr "Части, подготовленные для сохранения"
 
-#: git-gui.sh:1530 git-gui.sh:1535
+#: git-gui.sh:1558 git-gui.sh:1563
 msgid "Staged for commit, missing"
 msgstr "Подготовлено для сохранения, отсутствует"
 
-#: git-gui.sh:1532
+#: git-gui.sh:1560
 msgid "Untracked, not staged"
 msgstr "Не отслеживается, не подготовлено"
 
-#: git-gui.sh:1537
+#: git-gui.sh:1565
 msgid "Missing"
 msgstr "Отсутствует"
 
-#: git-gui.sh:1538
+#: git-gui.sh:1566
 msgid "Staged for removal"
 msgstr "Подготовлено для удаления"
 
-#: git-gui.sh:1539
+#: git-gui.sh:1567
 msgid "Staged for removal, still present"
 msgstr "Подготовлено для удаления, еще не удалено"
 
-#: git-gui.sh:1541 git-gui.sh:1542 git-gui.sh:1543 git-gui.sh:1544
+#: git-gui.sh:1569 git-gui.sh:1570 git-gui.sh:1571 git-gui.sh:1572
 msgid "Requires merge resolution"
 msgstr "Требуется разрешение конфликта при объединении"
 
-#: git-gui.sh:1579
+#: git-gui.sh:1607
 msgid "Starting gitk... please wait..."
 msgstr "Запускается gitk... пожалуйста, ждите..."
 
-#: git-gui.sh:1588
+#: git-gui.sh:1616
 #, tcl-format
 msgid ""
 "Unable to start gitk:\n"
@@ -142,296 +142,295 @@ msgstr ""
 "\n"
 "%s не существует"
 
-#: git-gui.sh:1788 lib/choose_repository.tcl:32
+#: git-gui.sh:1816 lib/choose_repository.tcl:35
 msgid "Repository"
 msgstr "Репозиторий"
 
-#: git-gui.sh:1789
+#: git-gui.sh:1817
 msgid "Edit"
 msgstr "Редактировать"
 
-#: git-gui.sh:1791 lib/choose_rev.tcl:560
+#: git-gui.sh:1819 lib/choose_rev.tcl:560
 msgid "Branch"
 msgstr "Ветвь"
 
-#: git-gui.sh:1794 lib/choose_rev.tcl:547
+#: git-gui.sh:1822 lib/choose_rev.tcl:547
 msgid "Commit@@noun"
 msgstr "Состояние"
 
-#: git-gui.sh:1797 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168
+#: git-gui.sh:1825 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168
 msgid "Merge"
 msgstr "Объединить"
 
-#: git-gui.sh:1798 lib/choose_rev.tcl:556
+#: git-gui.sh:1826 lib/choose_rev.tcl:556
 msgid "Remote"
 msgstr "Внешние репозитории"
 
-#: git-gui.sh:1807
+#: git-gui.sh:1835
 msgid "Browse Current Branch's Files"
 msgstr "Просмотреть файлы текущей ветви"
 
-#: git-gui.sh:1811
+#: git-gui.sh:1839
 msgid "Browse Branch Files..."
 msgstr "Показать файлы ветви..."
 
-#: git-gui.sh:1816
+#: git-gui.sh:1844
 msgid "Visualize Current Branch's History"
 msgstr "История текущей ветви наглядно"
 
-#: git-gui.sh:1820
+#: git-gui.sh:1848
 msgid "Visualize All Branch History"
 msgstr "История всех ветвей наглядно"
 
-#: git-gui.sh:1827
+#: git-gui.sh:1855
 #, tcl-format
 msgid "Browse %s's Files"
 msgstr "Показать файлы ветви %s"
 
-#: git-gui.sh:1829
+#: git-gui.sh:1857
 #, tcl-format
 msgid "Visualize %s's History"
 msgstr "История ветви %s наглядно"
 
-#: git-gui.sh:1834 lib/database.tcl:27 lib/database.tcl:67
+#: git-gui.sh:1862 lib/database.tcl:27 lib/database.tcl:67
 msgid "Database Statistics"
 msgstr "Статистика базы данных"
 
-#: git-gui.sh:1837 lib/database.tcl:34
+#: git-gui.sh:1865 lib/database.tcl:34
 msgid "Compress Database"
 msgstr "Сжать базу данных"
 
-#: git-gui.sh:1840
+#: git-gui.sh:1868
 msgid "Verify Database"
 msgstr "Проверить базу данных"
 
-#: git-gui.sh:1847 git-gui.sh:1851 git-gui.sh:1855 lib/shortcut.tcl:9
-#: lib/shortcut.tcl:45 lib/shortcut.tcl:84
+#: git-gui.sh:1875 git-gui.sh:1879 git-gui.sh:1883 lib/shortcut.tcl:7
+#: lib/shortcut.tcl:39 lib/shortcut.tcl:71
 msgid "Create Desktop Icon"
 msgstr "Создать ярлык на рабочем столе"
 
-#: git-gui.sh:1860 lib/choose_repository.tcl:36 lib/choose_repository.tcl:95
+#: git-gui.sh:1888 lib/choose_repository.tcl:176 lib/choose_repository.tcl:184
 msgid "Quit"
 msgstr "Выход"
 
-#: git-gui.sh:1867
+#: git-gui.sh:1895
 msgid "Undo"
 msgstr "Отменить"
 
-#: git-gui.sh:1870
+#: git-gui.sh:1898
 msgid "Redo"
 msgstr "Повторить"
 
-#: git-gui.sh:1874 git-gui.sh:2366
+#: git-gui.sh:1902 git-gui.sh:2395
 msgid "Cut"
 msgstr "Вырезать"
 
-#: git-gui.sh:1877 git-gui.sh:2369 git-gui.sh:2440 git-gui.sh:2512
+#: git-gui.sh:1905 git-gui.sh:2398 git-gui.sh:2469 git-gui.sh:2541
 #: lib/console.tcl:67
 msgid "Copy"
 msgstr "Копировать"
 
-#: git-gui.sh:1880 git-gui.sh:2372
+#: git-gui.sh:1908 git-gui.sh:2401
 msgid "Paste"
 msgstr "Вставить"
 
-#: git-gui.sh:1883 git-gui.sh:2375 lib/branch_delete.tcl:26
+#: git-gui.sh:1911 git-gui.sh:2404 lib/branch_delete.tcl:26
 #: lib/remote_branch_delete.tcl:38
 msgid "Delete"
 msgstr "Удалить"
 
-#: git-gui.sh:1887 git-gui.sh:2379 git-gui.sh:2516 lib/console.tcl:69
+#: git-gui.sh:1915 git-gui.sh:2408 git-gui.sh:2545 lib/console.tcl:69
 msgid "Select All"
 msgstr "Выделить все"
 
-#: git-gui.sh:1896
+#: git-gui.sh:1924
 msgid "Create..."
 msgstr "Создать..."
 
-#: git-gui.sh:1902
+#: git-gui.sh:1930
 msgid "Checkout..."
 msgstr "Перейти..."
 
-#: git-gui.sh:1908
+#: git-gui.sh:1936
 msgid "Rename..."
 msgstr "Переименовать..."
 
-#: git-gui.sh:1913 git-gui.sh:2012
+#: git-gui.sh:1941 git-gui.sh:2040
 msgid "Delete..."
 msgstr "Удалить..."
 
-#: git-gui.sh:1918
+#: git-gui.sh:1946
 msgid "Reset..."
 msgstr "Сбросить..."
 
-#: git-gui.sh:1930 git-gui.sh:2313
+#: git-gui.sh:1958 git-gui.sh:2342
 msgid "New Commit"
 msgstr "Новое состояние"
 
-#: git-gui.sh:1938 git-gui.sh:2320
+#: git-gui.sh:1966 git-gui.sh:2349
 msgid "Amend Last Commit"
 msgstr "Исправить последнее состояние"
 
-#: git-gui.sh:1947 git-gui.sh:2280 lib/remote_branch_delete.tcl:99
+#: git-gui.sh:1975 git-gui.sh:2309 lib/remote_branch_delete.tcl:99
 msgid "Rescan"
 msgstr "Перечитать"
 
-#: git-gui.sh:1953
+#: git-gui.sh:1981
 msgid "Stage To Commit"
 msgstr "Подготовить для сохранения"
 
-#: git-gui.sh:1958
+#: git-gui.sh:1986
 msgid "Stage Changed Files To Commit"
 msgstr "Подготовить измененные файлы для сохранения"
 
-#: git-gui.sh:1964
+#: git-gui.sh:1992
 msgid "Unstage From Commit"
 msgstr "Убрать из подготовленного"
 
-#: git-gui.sh:1969 lib/index.tcl:352
+#: git-gui.sh:1997 lib/index.tcl:393
 msgid "Revert Changes"
 msgstr "Отменить изменения"
 
-#: git-gui.sh:1976 git-gui.sh:2292 git-gui.sh:2390
+#: git-gui.sh:2004 git-gui.sh:2321 git-gui.sh:2419
 msgid "Sign Off"
 msgstr "Подписать"
 
-#: git-gui.sh:1980 git-gui.sh:2296
+#: git-gui.sh:2008 git-gui.sh:2325
 msgid "Commit@@verb"
 msgstr "Сохранить"
 
-#: git-gui.sh:1991
+#: git-gui.sh:2019
 msgid "Local Merge..."
 msgstr "Локальное объединение..."
 
-#: git-gui.sh:1996
+#: git-gui.sh:2024
 msgid "Abort Merge..."
 msgstr "Прервать объединение..."
 
-#: git-gui.sh:2008
+#: git-gui.sh:2036
 msgid "Push..."
 msgstr "Отправить..."
 
-#: git-gui.sh:2019 lib/choose_repository.tcl:41
-#, fuzzy
+#: git-gui.sh:2047 lib/choose_repository.tcl:40
 msgid "Apple"
 msgstr ""
 
-#: git-gui.sh:2022 git-gui.sh:2044 lib/about.tcl:13
-#: lib/choose_repository.tcl:44 lib/choose_repository.tcl:50
+#: git-gui.sh:2050 git-gui.sh:2072 lib/about.tcl:13
+#: lib/choose_repository.tcl:43 lib/choose_repository.tcl:49
 #, tcl-format
 msgid "About %s"
 msgstr "О %s"
 
-#: git-gui.sh:2026
+#: git-gui.sh:2054
 msgid "Preferences..."
 msgstr "Настройки..."
 
-#: git-gui.sh:2034 git-gui.sh:2558
+#: git-gui.sh:2062 git-gui.sh:2587
 msgid "Options..."
 msgstr "Настройки..."
 
-#: git-gui.sh:2040 lib/choose_repository.tcl:47
+#: git-gui.sh:2068 lib/choose_repository.tcl:46
 msgid "Help"
 msgstr "Помощь"
 
-#: git-gui.sh:2081
+#: git-gui.sh:2109
 msgid "Online Documentation"
 msgstr "Документация в интернете"
 
-#: git-gui.sh:2165
+#: git-gui.sh:2193
 #, tcl-format
 msgid "fatal: cannot stat path %s: No such file or directory"
 msgstr "критическая ошибка: %s: нет такого файла или каталога"
 
-#: git-gui.sh:2198
+#: git-gui.sh:2226
 msgid "Current Branch:"
 msgstr "Текущая ветвь:"
 
-#: git-gui.sh:2219
+#: git-gui.sh:2247
 msgid "Staged Changes (Will Commit)"
 msgstr "Подготовлено (будет сохранено)"
 
-#: git-gui.sh:2239
+#: git-gui.sh:2266
 msgid "Unstaged Changes"
 msgstr "Изменено (не будет сохранено)"
 
-#: git-gui.sh:2286
+#: git-gui.sh:2315
 msgid "Stage Changed"
 msgstr "Подготовить все"
 
-#: git-gui.sh:2302 lib/transport.tcl:93 lib/transport.tcl:182
+#: git-gui.sh:2331 lib/transport.tcl:93 lib/transport.tcl:182
 msgid "Push"
 msgstr "Отправить"
 
-#: git-gui.sh:2332
+#: git-gui.sh:2361
 msgid "Initial Commit Message:"
 msgstr "Комментарий к первому состоянию:"
 
-#: git-gui.sh:2333
+#: git-gui.sh:2362
 msgid "Amended Commit Message:"
 msgstr "Комментарий к исправленному состоянию:"
 
-#: git-gui.sh:2334
+#: git-gui.sh:2363
 msgid "Amended Initial Commit Message:"
 msgstr "Комментарий к исправленному первоначальному состоянию:"
 
-#: git-gui.sh:2335
+#: git-gui.sh:2364
 msgid "Amended Merge Commit Message:"
 msgstr "Комментарий к исправленному объединению:"
 
-#: git-gui.sh:2336
+#: git-gui.sh:2365
 msgid "Merge Commit Message:"
 msgstr "Комментарий к объединению:"
 
-#: git-gui.sh:2337
+#: git-gui.sh:2366
 msgid "Commit Message:"
 msgstr "Комментарий к состоянию:"
 
-#: git-gui.sh:2382 git-gui.sh:2520 lib/console.tcl:71
+#: git-gui.sh:2411 git-gui.sh:2549 lib/console.tcl:71
 msgid "Copy All"
 msgstr "Копировать все"
 
-#: git-gui.sh:2406 lib/blame.tcl:104
+#: git-gui.sh:2435 lib/blame.tcl:104
 msgid "File:"
 msgstr "Файл:"
 
-#: git-gui.sh:2508
+#: git-gui.sh:2537
 msgid "Refresh"
 msgstr "Обновить"
 
-#: git-gui.sh:2529
+#: git-gui.sh:2558
 msgid "Apply/Reverse Hunk"
 msgstr "Применить/Убрать изменение"
 
-#: git-gui.sh:2535
+#: git-gui.sh:2564
 msgid "Decrease Font Size"
 msgstr "Уменьшить размер шрифта"
 
-#: git-gui.sh:2539
+#: git-gui.sh:2568
 msgid "Increase Font Size"
 msgstr "Увеличить размер шрифта"
 
-#: git-gui.sh:2544
+#: git-gui.sh:2573
 msgid "Show Less Context"
 msgstr "Меньше контекста"
 
-#: git-gui.sh:2551
+#: git-gui.sh:2580
 msgid "Show More Context"
 msgstr "Больше контекста"
 
-#: git-gui.sh:2565
+#: git-gui.sh:2594
 msgid "Unstage Hunk From Commit"
 msgstr "Не сохранять часть"
 
-#: git-gui.sh:2567
+#: git-gui.sh:2596
 msgid "Stage Hunk For Commit"
 msgstr "Подготовить часть для сохранения"
 
-#: git-gui.sh:2586
+#: git-gui.sh:2615
 msgid "Initializing..."
 msgstr "Инициализация..."
 
-#: git-gui.sh:2677
+#: git-gui.sh:2706
 #, tcl-format
 msgid ""
 "Possible environment issues exist.\n"
@@ -448,7 +447,7 @@ msgstr ""
 "запущенными из %s\n"
 "\n"
 
-#: git-gui.sh:2707
+#: git-gui.sh:2736
 msgid ""
 "\n"
 "This is due to a known issue with the\n"
@@ -458,7 +457,7 @@ msgstr ""
 "Это известная проблема с Tcl,\n"
 "распространяемым Cygwin."
 
-#: git-gui.sh:2712
+#: git-gui.sh:2741
 #, tcl-format
 msgid ""
 "\n"
@@ -579,7 +578,7 @@ msgstr "Создание ветви"
 msgid "Create New Branch"
 msgstr "Создать новую ветвь"
 
-#: lib/branch_create.tcl:31 lib/choose_repository.tcl:199
+#: lib/branch_create.tcl:31 lib/choose_repository.tcl:375
 msgid "Create"
 msgstr "Создать"
 
@@ -732,9 +731,9 @@ msgstr "[На уровень выше]"
 msgid "Browse Branch Files"
 msgstr "Показать файлы ветви"
 
-#: lib/browser.tcl:277 lib/choose_repository.tcl:215
-#: lib/choose_repository.tcl:305 lib/choose_repository.tcl:315
-#: lib/choose_repository.tcl:811
+#: lib/browser.tcl:277 lib/choose_repository.tcl:391
+#: lib/choose_repository.tcl:482 lib/choose_repository.tcl:492
+#: lib/choose_repository.tcl:989
 msgid "Browse"
 msgstr "Показать"
 
@@ -788,7 +787,8 @@ msgstr "Рабочая область заблокирована другим п
 msgid ""
 "Last scanned state does not match repository state.\n"
 "\n"
-"Another Git program has modified this repository since the last scan.  A rescan must be performed before the current branch can be changed.\n"
+"Another Git program has modified this repository since the last scan.  A "
+"rescan must be performed before the current branch can be changed.\n"
 "\n"
 "The rescan will be automatically started now.\n"
 msgstr ""
@@ -822,11 +822,13 @@ msgstr "Ветвь '%s' остается текущей."
 msgid ""
 "You are no longer on a local branch.\n"
 "\n"
-"If you wanted to be on a branch, create one now starting from 'This Detached Checkout'."
+"If you wanted to be on a branch, create one now starting from 'This Detached "
+"Checkout'."
 msgstr ""
 "Вы находитесь не в локальной ветви.\n"
 "\n"
-"Если вы хотите снова вернуться к какой-нибудь ветви, создайте ее сейчас, начиная с 'Текущего отсоединенного состояния'."
+"Если вы хотите снова вернуться к какой-нибудь ветви, создайте ее сейчас, "
+"начиная с 'Текущего отсоединенного состояния'."
 
 #: lib/checkout_op.tcl:446
 #, tcl-format
@@ -856,19 +858,21 @@ msgstr "Наглядно"
 msgid ""
 "Failed to set current branch.\n"
 "\n"
-"This working directory is only partially switched.  We successfully updated your files, but failed to update an internal Git file.\n"
+"This working directory is only partially switched.  We successfully updated "
+"your files, but failed to update an internal Git file.\n"
 "\n"
 "This should not have occurred.  %s will now close and give up."
 msgstr ""
 "Не удалось установить текущую ветвь.\n"
 "\n"
-"Ваш рабочий каталог обновлен только частично. Были обновлены все файлы кроме служебных файлов Git. \n"
+"Ваш рабочий каталог обновлен только частично. Были обновлены все файлы кроме "
+"служебных файлов Git. \n"
 "\n"
 "Этого не должно было произойти. %s завершается."
 
 #: lib/choose_font.tcl:39
 msgid "Select"
-msgstr "Выделить все"
+msgstr "Выбрать"
 
 #: lib/choose_font.tcl:53
 msgid "Font Family"
@@ -890,210 +894,226 @@ msgstr ""
 "Это пример текста.\n"
 "Если Вам нравится этот текст, это может быть Ваш шрифт."
 
-#: lib/choose_repository.tcl:25
+#: lib/choose_repository.tcl:27
 msgid "Git Gui"
 msgstr ""
 
-#: lib/choose_repository.tcl:69 lib/choose_repository.tcl:204
+#: lib/choose_repository.tcl:80 lib/choose_repository.tcl:380
 msgid "Create New Repository"
 msgstr "Создать новый репозиторий"
 
-#: lib/choose_repository.tcl:74 lib/choose_repository.tcl:291
+#: lib/choose_repository.tcl:86
+msgid "New..."
+msgstr "Новый..."
+
+#: lib/choose_repository.tcl:93 lib/choose_repository.tcl:468
 msgid "Clone Existing Repository"
 msgstr "Склонировать существующий репозиторий"
 
-#: lib/choose_repository.tcl:79 lib/choose_repository.tcl:800
+#: lib/choose_repository.tcl:99
+msgid "Clone..."
+msgstr "Склонировать..."
+
+#: lib/choose_repository.tcl:106 lib/choose_repository.tcl:978
 msgid "Open Existing Repository"
 msgstr "Выбрать существующий репозиторий"
 
-#: lib/choose_repository.tcl:91
-msgid "Next >"
-msgstr "Дальше >"
+#: lib/choose_repository.tcl:112
+msgid "Open..."
+msgstr "Открыть..."
 
-#: lib/choose_repository.tcl:152
+#: lib/choose_repository.tcl:125
+msgid "Recent Repositories"
+msgstr "Недавние репозитории"
+
+#: lib/choose_repository.tcl:131
+msgid "Open Recent Repository:"
+msgstr "Открыть последний репозиторий"
+
+#: lib/choose_repository.tcl:294
 #, tcl-format
 msgid "Location %s already exists."
 msgstr "Путь '%s' уже существует."
 
-#: lib/choose_repository.tcl:158 lib/choose_repository.tcl:165
-#: lib/choose_repository.tcl:172
+#: lib/choose_repository.tcl:300 lib/choose_repository.tcl:307
+#: lib/choose_repository.tcl:314
 #, tcl-format
 msgid "Failed to create repository %s:"
 msgstr "Не удалось создать репозиторий %s:"
 
-#: lib/choose_repository.tcl:209 lib/choose_repository.tcl:309
+#: lib/choose_repository.tcl:385 lib/choose_repository.tcl:486
 msgid "Directory:"
 msgstr "Каталог:"
 
-#: lib/choose_repository.tcl:238 lib/choose_repository.tcl:363
-#: lib/choose_repository.tcl:834
+#: lib/choose_repository.tcl:415 lib/choose_repository.tcl:544
+#: lib/choose_repository.tcl:1013
 msgid "Git Repository"
 msgstr "Репозиторий"
 
-#: lib/choose_repository.tcl:253 lib/choose_repository.tcl:260
+#: lib/choose_repository.tcl:430 lib/choose_repository.tcl:437
 #, tcl-format
 msgid "Directory %s already exists."
 msgstr "Каталог '%s' уже существует."
 
-#: lib/choose_repository.tcl:265
+#: lib/choose_repository.tcl:442
 #, tcl-format
 msgid "File %s already exists."
 msgstr "Файл '%s' уже существует."
 
-#: lib/choose_repository.tcl:286
+#: lib/choose_repository.tcl:463
 msgid "Clone"
 msgstr "Склонировать"
 
-#: lib/choose_repository.tcl:299
+#: lib/choose_repository.tcl:476
 msgid "URL:"
 msgstr "Ссылка:"
 
-#: lib/choose_repository.tcl:319
+#: lib/choose_repository.tcl:496
 msgid "Clone Type:"
 msgstr "Тип клона:"
 
-#: lib/choose_repository.tcl:325
+#: lib/choose_repository.tcl:502
 msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
 msgstr "Стандартный (Быстрый, полуизбыточный, \"жесткие\" ссылки)"
 
-#: lib/choose_repository.tcl:331
+#: lib/choose_repository.tcl:508
 msgid "Full Copy (Slower, Redundant Backup)"
 msgstr "Полная копия (Медленный, создает резервную копию)"
 
-#: lib/choose_repository.tcl:337
+#: lib/choose_repository.tcl:514
 msgid "Shared (Fastest, Not Recommended, No Backup)"
 msgstr "Общий (Самый быстрый, не рекомендуется, без резервной копии)"
 
-#: lib/choose_repository.tcl:369 lib/choose_repository.tcl:418
-#: lib/choose_repository.tcl:560 lib/choose_repository.tcl:630
-#: lib/choose_repository.tcl:840 lib/choose_repository.tcl:848
+#: lib/choose_repository.tcl:550 lib/choose_repository.tcl:597
+#: lib/choose_repository.tcl:738 lib/choose_repository.tcl:808
+#: lib/choose_repository.tcl:1019 lib/choose_repository.tcl:1027
 #, tcl-format
 msgid "Not a Git repository: %s"
 msgstr "Каталог не является репозиторием: %s"
 
-#: lib/choose_repository.tcl:405
+#: lib/choose_repository.tcl:586
 msgid "Standard only available for local repository."
 msgstr "Стандартный клон возможен только для локального репозитория."
 
-#: lib/choose_repository.tcl:409
+#: lib/choose_repository.tcl:590
 msgid "Shared only available for local repository."
 msgstr "Общий клон возможен только для локального репозитория."
 
-#: lib/choose_repository.tcl:439
+#: lib/choose_repository.tcl:617
 msgid "Failed to configure origin"
 msgstr "Не могу сконфигурировать исходный репозиторий."
 
-#: lib/choose_repository.tcl:451
+#: lib/choose_repository.tcl:629
 msgid "Counting objects"
 msgstr "Считаю объекты"
 
-#: lib/choose_repository.tcl:452
-#, fuzzy
+#: lib/choose_repository.tcl:630
 msgid "buckets"
 msgstr ""
 
-#: lib/choose_repository.tcl:476
+#: lib/choose_repository.tcl:654
 #, tcl-format
 msgid "Unable to copy objects/info/alternates: %s"
 msgstr "Не могу скопировать objects/info/alternates: %s"
 
-#: lib/choose_repository.tcl:512
+#: lib/choose_repository.tcl:690
 #, tcl-format
 msgid "Nothing to clone from %s."
 msgstr "Нечего клонировать с %s."
 
-#: lib/choose_repository.tcl:514 lib/choose_repository.tcl:728
-#: lib/choose_repository.tcl:740
+#: lib/choose_repository.tcl:692 lib/choose_repository.tcl:906
+#: lib/choose_repository.tcl:918
 msgid "The 'master' branch has not been initialized."
 msgstr "Не инициализирована ветвь 'master'."
 
-#: lib/choose_repository.tcl:527
+#: lib/choose_repository.tcl:705
 msgid "Hardlinks are unavailable.  Falling back to copying."
 msgstr "\"Жесткие ссылки\" не доступны. Буду использовать копирование."
 
-#: lib/choose_repository.tcl:539
+#: lib/choose_repository.tcl:717
 #, tcl-format
 msgid "Cloning from %s"
 msgstr "Клонирование %s"
 
-#: lib/choose_repository.tcl:570
+#: lib/choose_repository.tcl:748
 msgid "Copying objects"
 msgstr "Копирование objects"
 
-#: lib/choose_repository.tcl:571
+#: lib/choose_repository.tcl:749
 msgid "KiB"
 msgstr "КБ"
 
-#: lib/choose_repository.tcl:595
+#: lib/choose_repository.tcl:773
 #, tcl-format
 msgid "Unable to copy object: %s"
 msgstr "Не могу скопировать объект: %s"
 
-#: lib/choose_repository.tcl:605
+#: lib/choose_repository.tcl:783
 msgid "Linking objects"
 msgstr "Создание ссылок на objects"
 
-#: lib/choose_repository.tcl:606
+#: lib/choose_repository.tcl:784
 msgid "objects"
 msgstr "объекты"
 
-#: lib/choose_repository.tcl:614
+#: lib/choose_repository.tcl:792
 #, tcl-format
 msgid "Unable to hardlink object: %s"
 msgstr "Не могу \"жестко связать\" объект: %s"
 
-#: lib/choose_repository.tcl:669
+#: lib/choose_repository.tcl:847
 msgid "Cannot fetch branches and objects.  See console output for details."
-msgstr "Не могу получить ветви и объекты. Дополнительная информация на консоли."
+msgstr ""
+"Не могу получить ветви и объекты. Дополнительная информация на консоли."
 
-#: lib/choose_repository.tcl:680
+#: lib/choose_repository.tcl:858
 msgid "Cannot fetch tags.  See console output for details."
 msgstr "Не могу получить метки. Дополнительная информация на консоли."
 
-#: lib/choose_repository.tcl:704
+#: lib/choose_repository.tcl:882
 msgid "Cannot determine HEAD.  See console output for details."
 msgstr "Не могу определить HEAD. Дополнительная информация на консоли."
 
-#: lib/choose_repository.tcl:713
+#: lib/choose_repository.tcl:891
 #, tcl-format
 msgid "Unable to cleanup %s"
 msgstr "Не могу очистить %s"
 
-#: lib/choose_repository.tcl:719
+#: lib/choose_repository.tcl:897
 msgid "Clone failed."
 msgstr "Клонирование не удалось."
 
-#: lib/choose_repository.tcl:726
+#: lib/choose_repository.tcl:904
 msgid "No default branch obtained."
 msgstr "Не было получено ветви по умолчанию."
 
-#: lib/choose_repository.tcl:737
+#: lib/choose_repository.tcl:915
 #, tcl-format
 msgid "Cannot resolve %s as a commit."
 msgstr "Не могу распознать %s как состояние."
 
-#: lib/choose_repository.tcl:749
+#: lib/choose_repository.tcl:927
 msgid "Creating working directory"
 msgstr "Создаю рабочий каталог"
 
-#: lib/choose_repository.tcl:750 lib/index.tcl:15 lib/index.tcl:80
-#: lib/index.tcl:149
+#: lib/choose_repository.tcl:928 lib/index.tcl:65 lib/index.tcl:127
+#: lib/index.tcl:193
 msgid "files"
 msgstr "файлов"
 
-#: lib/choose_repository.tcl:779
+#: lib/choose_repository.tcl:957
 msgid "Initial file checkout failed."
 msgstr "Не удалось получить начальное состояние файлов репозитория."
 
-#: lib/choose_repository.tcl:795
+#: lib/choose_repository.tcl:973
 msgid "Open"
 msgstr "Открыть"
 
-#: lib/choose_repository.tcl:805
+#: lib/choose_repository.tcl:983
 msgid "Repository:"
 msgstr "Репозиторий:"
 
-#: lib/choose_repository.tcl:854
+#: lib/choose_repository.tcl:1033
 #, tcl-format
 msgid "Failed to open repository %s:"
 msgstr "Не удалось открыть репозиторий %s:"
@@ -1116,7 +1136,7 @@ msgstr "Ветвь слежения"
 
 #: lib/choose_rev.tcl:84 lib/choose_rev.tcl:537
 msgid "Tag"
-msgstr "Метка"
+msgstr "Таг"
 
 #: lib/choose_rev.tcl:317
 #, tcl-format
@@ -1143,7 +1163,8 @@ msgstr "Ссылка"
 msgid ""
 "There is nothing to amend.\n"
 "\n"
-"You are about to create the initial commit.  There is no commit before this to amend.\n"
+"You are about to create the initial commit.  There is no commit before this "
+"to amend.\n"
 msgstr ""
 "Отсутствует состояние для исправления.\n"
 "\n"
@@ -1153,11 +1174,14 @@ msgstr ""
 msgid ""
 "Cannot amend while merging.\n"
 "\n"
-"You are currently in the middle of a merge that has not been fully completed.  You cannot amend the prior commit unless you first abort the current merge activity.\n"
+"You are currently in the middle of a merge that has not been fully "
+"completed.  You cannot amend the prior commit unless you first abort the "
+"current merge activity.\n"
 msgstr ""
 "Невозможно исправить состояние во время объединения.\n"
 "\n"
-"Текущее объединение не завершено. Невозможно исправить предыдущее сохраненное состояние не прерывая текущее объединение.\n"
+"Текущее объединение не завершено. Невозможно исправить предыдущее "
+"сохраненное состояние не прерывая текущее объединение.\n"
 
 #: lib/commit.tcl:49
 msgid "Error loading commit data for amend:"
@@ -1169,19 +1193,21 @@ msgstr "Невозможно получить информацию об авто
 
 #: lib/commit.tcl:81
 msgid "Invalid GIT_COMMITTER_IDENT:"
-msgstr "Неверная GIT_COMMITTER_IDENT:"
+msgstr "Неверный GIT_COMMITTER_IDENT:"
 
 #: lib/commit.tcl:133
 msgid ""
 "Last scanned state does not match repository state.\n"
 "\n"
-"Another Git program has modified this repository since the last scan.  A rescan must be performed before another commit can be created.\n"
+"Another Git program has modified this repository since the last scan.  A "
+"rescan must be performed before another commit can be created.\n"
 "\n"
 "The rescan will be automatically started now.\n"
 msgstr ""
 "Последнее прочитанное состояние репозитория не соответствует текущему.\n"
 "\n"
-"С момента последней проверки репозиторий был изменен другой программой Git. Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь. \n"
+"С момента последней проверки репозиторий был изменен другой программой Git. "
+"Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь. \n"
 "\n"
 "Это будет сделано сейчас автоматически.\n"
 
@@ -1190,11 +1216,13 @@ msgstr ""
 msgid ""
 "Unmerged files cannot be committed.\n"
 "\n"
-"File %s has merge conflicts.  You must resolve them and stage the file before committing.\n"
+"File %s has merge conflicts.  You must resolve them and stage the file "
+"before committing.\n"
 msgstr ""
 "Нельзя сохранить необъединенные файлы.\n"
 "\n"
-"Для файла %s возник конфликт объединения. Разрешите конфликт и добавьте к подготовленным файлам перед сохранением.\n"
+"Для файла %s возник конфликт объединения. Разрешите конфликт и добавьте к "
+"подготовленным файлам перед сохранением.\n"
 
 #: lib/commit.tcl:162
 #, tcl-format
@@ -1333,13 +1361,15 @@ msgstr "Проверка базы объектов при помощи fsck"
 msgid ""
 "This repository currently has approximately %i loose objects.\n"
 "\n"
-"To maintain optimal performance it is strongly recommended that you compress the database when more than %i loose objects exist.\n"
+"To maintain optimal performance it is strongly recommended that you compress "
+"the database when more than %i loose objects exist.\n"
 "\n"
 "Compress the database now?"
 msgstr ""
 "Этот репозиторий сейчас содержит примерно %i свободных объектов\n"
 "\n"
-"Для лучшей производительности рекомендуется сжать базу данных, когда есть более %i несвязанных объектов.\n"
+"Для лучшей производительности рекомендуется сжать базу данных, когда есть "
+"более %i несвязанных объектов.\n"
 "\n"
 "Сжать базу данных сейчас?"
 
@@ -1355,15 +1385,18 @@ msgid ""
 "\n"
 "%s has no changes.\n"
 "\n"
-"The modification date of this file was updated by another application, but the content within the file was not changed.\n"
+"The modification date of this file was updated by another application, but "
+"the content within the file was not changed.\n"
 "\n"
-"A rescan will be automatically started to find other files which may have the same state."
+"A rescan will be automatically started to find other files which may have "
+"the same state."
 msgstr ""
 "Изменений не обнаружено.\n"
 "\n"
 "в %s отутствуют изменения.\n"
 "\n"
-"Дата изменения файла была обновлена другой программой, но содержимое файла осталось прежним.\n"
+"Дата изменения файла была обновлена другой программой, но содержимое файла "
+"осталось прежним.\n"
 "\n"
 "Сейчас будет запущено перечитывание репозитория, чтобы найти подобные файлы."
 
@@ -1413,32 +1446,57 @@ msgstr "предупреждение"
 msgid "You must correct the above errors before committing."
 msgstr "Прежде чем сохранить, исправьте вышеуказанные ошибки."
 
-#: lib/index.tcl:241
+#: lib/index.tcl:6
+msgid "Unable to unlock the index."
+msgstr "Не удалось разблокировать индекс"
+
+#: lib/index.tcl:15
+msgid "Index Error"
+msgstr "Ошибка индекса"
+
+#: lib/index.tcl:21
+msgid ""
+"Updating the Git index failed.  A rescan will be automatically started to "
+"resynchronize git-gui."
+msgstr ""
+"Не удалось обновить индекс Git. Состояние репозитория будет"
+"перечитано автоматически."
+
+#: lib/index.tcl:27
+msgid "Continue"
+msgstr "Продолжить"
+
+#: lib/index.tcl:31
+msgid "Unlock Index"
+msgstr "Разблокировать индекс"
+
+#: lib/index.tcl:282
 #, tcl-format
 msgid "Unstaging %s from commit"
 msgstr "Удаление %s из подготовленного"
 
-#: lib/index.tcl:285
+#: lib/index.tcl:326
 #, tcl-format
 msgid "Adding %s"
 msgstr "Добавление %s..."
 
-#: lib/index.tcl:340
+#: lib/index.tcl:381
 #, tcl-format
 msgid "Revert changes in file %s?"
 msgstr "Отменить изменения в файле %s?"
 
-#: lib/index.tcl:342
+#: lib/index.tcl:383
 #, tcl-format
 msgid "Revert changes in these %i files?"
 msgstr "Отменить изменения в %i файле(-ах)?"
 
-#: lib/index.tcl:348
+#: lib/index.tcl:389
 msgid "Any unstaged changes will be permanently lost by the revert."
 msgstr ""
-"Любые изменения, не подготовленные к сохранению, будут потеряны при данной операции."
+"Любые изменения, не подготовленные к сохранению, будут потеряны при данной "
+"операции."
 
-#: lib/index.tcl:351
+#: lib/index.tcl:392
 msgid "Do Nothing"
 msgstr "Ничего не делать"
 
@@ -1450,19 +1508,22 @@ msgid ""
 msgstr ""
 "Невозможно выполнить объединение во время исправления.\n"
 "\n"
-"Завершите исправление данного состояния перед выполнением операции объединения.\n"
+"Завершите исправление данного состояния перед выполнением операции "
+"объединения.\n"
 
 #: lib/merge.tcl:27
 msgid ""
 "Last scanned state does not match repository state.\n"
 "\n"
-"Another Git program has modified this repository since the last scan.  A rescan must be performed before a merge can be performed.\n"
+"Another Git program has modified this repository since the last scan.  A "
+"rescan must be performed before a merge can be performed.\n"
 "\n"
 "The rescan will be automatically started now.\n"
 msgstr ""
 "Последнее прочитанное состояние репозитория не соответствует текущему.\n"
 "\n"
-"С момента последней проверки репозиторий был изменен другой программой Git. Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь.\n"
+"С момента последней проверки репозиторий был изменен другой программой Git. "
+"Необходимо перечитать репозиторий, прежде чем изменять текущую ветвь.\n"
 "\n"
 "Это будет сделано сейчас автоматически.\n"
 
@@ -1473,12 +1534,15 @@ msgid ""
 "\n"
 "File %s has merge conflicts.\n"
 "\n"
-"You must resolve them, stage the file, and commit to complete the current merge.  Only then can you begin another merge.\n"
+"You must resolve them, stage the file, and commit to complete the current "
+"merge.  Only then can you begin another merge.\n"
 msgstr ""
 "Предыдущее объединение не завершено из-за конфликта.\n"
 "\n"
 "Для файла %s возник конфликт объединения.\n"
-"Разрешите конфликт, подготовьте файл и сохраните. Только после этого можно начать следующее объединение.\n"
+"\n"
+"Разрешите конфликт, подготовьте файл и сохраните. Только после этого можно "
+"начать следующее объединение.\n"
 
 #: lib/merge.tcl:54
 #, tcl-format
@@ -1487,13 +1551,15 @@ msgid ""
 "\n"
 "File %s is modified.\n"
 "\n"
-"You should complete the current commit before starting a merge.  Doing so will help you abort a failed merge, should the need arise.\n"
+"You should complete the current commit before starting a merge.  Doing so "
+"will help you abort a failed merge, should the need arise.\n"
 msgstr ""
 "Изменения не сохранены.\n"
 "\n"
-"Файл  %s изменен.\n"
+"Файл %s изменен.\n"
 "\n"
-"Подготовьте и сохраните измения перед началом объединения. В случае необходимости это позволит прервать операцию объединения.\n"
+"Подготовьте и сохраните измения перед началом объединения. В случае "
+"необходимости это позволит прервать операцию объединения.\n"
 
 #: lib/merge.tcl:106
 #, tcl-format
@@ -1631,7 +1697,7 @@ msgstr "Шаблон для имени новой ветви"
 
 #: lib/option.tcl:176
 msgid "Change Font"
-msgstr "Шрифт интерфейса"
+msgstr "Изменить шрифт"
 
 #: lib/option.tcl:180
 #, tcl-format
@@ -1640,7 +1706,6 @@ msgstr "Выберите %s"
 
 # carbon copy
 #: lib/option.tcl:186
-#, fuzzy
 msgid "pt."
 msgstr ""
 
@@ -1652,18 +1717,6 @@ msgstr "Настройки"
 msgid "Failed to completely save options:"
 msgstr "Не удалось полностью сохранить настройки:"
 
-#: lib/remote.tcl:165
-msgid "Prune from"
-msgstr "Чистка"
-
-#: lib/remote.tcl:170
-msgid "Fetch from"
-msgstr "Получение из"
-
-#: lib/remote.tcl:213
-msgid "Push to"
-msgstr "Отправить"
-
 #: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
 msgid "Delete Remote Branch"
 msgstr "Удалить внешнюю ветвь"
@@ -1707,16 +1760,17 @@ msgid ""
 "\n"
 " - %s"
 msgstr ""
-"Следующие ветви объединены с %s не полностью:"
-"\n"
+"Следующие ветви объединены с %s не полностью:\n"
 " - %s"
 
 #: lib/remote_branch_delete.tcl:189
 #, tcl-format
-msgid "One or more of the merge tests failed because you have not fetched the necessary commits.  Try fetching from %s first."
+msgid ""
+"One or more of the merge tests failed because you have not fetched the "
+"necessary commits.  Try fetching from %s first."
 msgstr ""
-"Один или несколько тестов на объединение не прошли, потому что "
-"Вы не получили необходимые состояния. Попробуйте сначала получить их из %s."
+"Один или несколько тестов на объединение не прошли, потому что Вы не "
+"получили необходимые состояния. Попытайтесь получить их из %s."
 
 #: lib/remote_branch_delete.tcl:207
 msgid "Please select one or more branches to delete."
@@ -1746,11 +1800,23 @@ msgstr "Не указан репозиторий."
 msgid "Scanning %s..."
 msgstr "Перечитывание %s... "
 
-#: lib/shortcut.tcl:26 lib/shortcut.tcl:74
-msgid "Cannot write script:"
-msgstr "Невозможно записать скрипт:"
+#: lib/remote.tcl:165
+msgid "Prune from"
+msgstr "Чистка"
+
+#: lib/remote.tcl:170
+msgid "Fetch from"
+msgstr "Получение из"
+
+#: lib/remote.tcl:213
+msgid "Push to"
+msgstr "Отправить"
+
+#: lib/shortcut.tcl:20 lib/shortcut.tcl:61
+msgid "Cannot write shortcut:"
+msgstr "Невозможно записать ссылку:"
 
-#: lib/shortcut.tcl:149
+#: lib/shortcut.tcl:136
 msgid "Cannot write icon:"
 msgstr "Невозможно записать значок:"
 
@@ -1821,5 +1887,7 @@ msgstr "Использовать thin pack (для медленных сетев
 
 #: lib/transport.tcl:168
 msgid "Include tags"
-msgstr "Включить метки"
+msgstr "Передать таги"
 
+#~ msgid "Next >"
+#~ msgstr "Дальше >"
-- 
1.5.3.4.500.g3a531f

^ permalink raw reply related	[relevance 3%]

* [PATCH] Implement git commit as a builtin command.
@ 2007-11-01 19:09  2% Kristian Høgsberg
  0 siblings, 0 replies; 200+ results
From: Kristian Høgsberg @ 2007-11-01 19:09 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Kristian Høgsberg

Move git-commit.sh to contrib/examples.

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---

Here's the builtin-commit patch again, this time updated to build
against the in-tree strbuf and option parser.  Now that Pierre has
done all the work of getting those pieces upstream, I notice that the
C version ends up 20 lines shorter than the shell script :)

There's a couple of changes to the test suite at the end, which
removes some EDITOR=: VISUAL=: hard-coding in a few tests and then
sets the default editor to /bin/true.  This is to address the problem
that the C version of launch editor doesn't support any kind of shell
qouting or built-ins.  Should we just use system(3) here?

cheers,
Kristian

 Makefile                       |    9 +-
 builtin-commit.c               |  608 ++++++++++++++++++++++++++++++++++++++
 builtin-tag.c                  |    2 +-
 builtin.h                      |    3 +-
 contrib/examples/git-commit.sh |  628 ++++++++++++++++++++++++++++++++++++++++
 git-commit.sh                  |  628 ----------------------------------------
 git.c                          |    3 +-
 strbuf.h                       |    1 +
 t/t3501-revert-cherry-pick.sh  |    4 +-
 t/t3901-i18n-patch.sh          |    8 +-
 t/test-lib.sh                  |    4 +-
 11 files changed, 1253 insertions(+), 645 deletions(-)
 create mode 100644 builtin-commit.c
 create mode 100755 contrib/examples/git-commit.sh
 delete mode 100755 git-commit.sh

diff --git a/Makefile b/Makefile
index 042f79e..689eb33 100644
--- a/Makefile
+++ b/Makefile
@@ -209,7 +209,7 @@ BASIC_LDFLAGS =
 
 SCRIPT_SH = \
 	git-bisect.sh git-checkout.sh \
-	git-clean.sh git-clone.sh git-commit.sh \
+	git-clean.sh git-clone.sh \
 	git-ls-remote.sh \
 	git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
 	git-pull.sh git-rebase.sh git-rebase--interactive.sh \
@@ -256,7 +256,7 @@ EXTRA_PROGRAMS =
 BUILT_INS = \
 	git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
 	git-get-tar-commit-id$X git-init$X git-repo-config$X \
-	git-fsck-objects$X git-cherry-pick$X \
+	git-fsck-objects$X git-cherry-pick$X git-status$X\
 	$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
 
 # what 'all' will build and 'install' will install, in gitexecdir
@@ -326,6 +326,7 @@ BUILTIN_OBJS = \
 	builtin-check-attr.o \
 	builtin-checkout-index.o \
 	builtin-check-ref-format.o \
+	builtin-commit.o \
 	builtin-commit-tree.o \
 	builtin-count-objects.o \
 	builtin-describe.o \
@@ -364,7 +365,6 @@ BUILTIN_OBJS = \
 	builtin-rev-parse.o \
 	builtin-revert.o \
 	builtin-rm.o \
-	builtin-runstatus.o \
 	builtin-shortlog.o \
 	builtin-show-branch.o \
 	builtin-stripspace.o \
@@ -830,9 +830,6 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
 	chmod +x $@+ && \
 	mv $@+ $@
 
-git-status: git-commit
-	$(QUIET_GEN)cp $< $@+ && mv $@+ $@
-
 gitweb/gitweb.cgi: gitweb/gitweb.perl
 	$(QUIET_GEN)$(RM) $@ $@+ && \
 	sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
diff --git a/builtin-commit.c b/builtin-commit.c
new file mode 100644
index 0000000..56c7427
--- /dev/null
+++ b/builtin-commit.c
@@ -0,0 +1,608 @@
+/*
+ * Builtin "git commit"
+ *
+ * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
+ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "cache.h"
+#include "cache-tree.h"
+#include "builtin.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "commit.h"
+#include "revision.h"
+#include "wt-status.h"
+#include "run-command.h"
+#include "refs.h"
+#include "log-tree.h"
+#include "strbuf.h"
+#include "utf8.h"
+#include "parse-options.h"
+
+static const char * const builtin_commit_usage[] = {
+	"git-commit [options] [--] <filepattern>...",
+	NULL
+};
+
+static unsigned char head_sha1[20], merge_head_sha1[20];
+static char *use_message_buffer;
+static const char commit_editmsg[] = "COMMIT_EDITMSG";
+static struct lock_file lock_file;
+
+static char *logfile, *force_author, *message, *template_file;
+static char *edit_message, *use_message;
+static int all, edit_flag, also, interactive, only, amend, signoff;
+static int quiet, verbose, untracked_files, no_verify;
+
+static int no_edit, initial_commit, in_merge;
+const char *only_include_assumed;
+
+static struct option builtin_commit_options[] = {
+	OPT__QUIET(&quiet),
+	OPT__VERBOSE(&verbose),
+	OPT_GROUP("Commit message options"),
+
+	OPT_STRING('F', "file", &logfile, "FILE", "read log from file"),
+	OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"),
+	OPT_STRING('m', "message", &message, "MESSAGE", "specify commit message"),
+	OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "),
+	OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"),
+	OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by: header"),
+	OPT_STRING('t', "template", &template_file, "FILE", "use specified template file"),
+	OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
+
+	OPT_GROUP("Commit contents options"),
+	OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
+	OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
+	OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
+	OPT_BOOLEAN('o', "only", &only, ""),
+	OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
+	OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
+	OPT_BOOLEAN(0, "untracked-files", &untracked_files, "show all untracked files"),
+
+	OPT_END()
+};
+
+static char *
+prepare_index(const char **files, const char *prefix)
+{
+	int fd;
+	struct tree *tree;
+	struct lock_file *next_index_lock;
+
+	fd = hold_locked_index(&lock_file, 1);
+	if (read_cache() < 0)
+		die("index file corrupt");
+
+	if (all) {
+		add_files_to_cache(verbose, NULL, files);
+		if (write_cache(fd, active_cache, active_nr) || close(fd))
+			die("unable to write new_index file");
+		return lock_file.filename;
+	} else if (also) {
+		add_files_to_cache(verbose, prefix, files);
+		if (write_cache(fd, active_cache, active_nr) || close(fd))
+			die("unable to write new_index file");
+		return lock_file.filename;
+	}
+
+	if (interactive)
+		interactive_add();
+
+	if (*files == NULL) {
+		/* Commit index as-is. */
+		rollback_lock_file(&lock_file);
+		return get_index_file();
+	}
+
+	/* update the user index file */
+	add_files_to_cache(verbose, prefix, files);
+	if (write_cache(fd, active_cache, active_nr) || close(fd))
+		die("unable to write new_index file");
+
+	if (!initial_commit) {
+		tree = parse_tree_indirect(head_sha1);
+		if (!tree)
+			die("failed to unpack HEAD tree object");
+		if (read_tree(tree, 0, NULL))
+			die("failed to read HEAD tree object");
+	}
+
+	/* Uh oh, abusing lock_file to create a garbage collected file */
+	next_index_lock = xmalloc(sizeof(*next_index_lock));
+	fd = hold_lock_file_for_update(next_index_lock,
+				       git_path("next-index-%d", getpid()), 1);
+	add_files_to_cache(verbose, prefix, files);
+	if (write_cache(fd, active_cache, active_nr) || close(fd))
+		die("unable to write new_index file");
+
+	return next_index_lock->filename;
+}
+
+static int run_status(FILE *fp, const char *index_file)
+{
+	struct wt_status s;
+
+	wt_status_prepare(&s);
+
+	if (amend) {
+		s.amend = 1;
+		s.reference = "HEAD^1";
+	}
+	s.verbose = verbose;
+	s.untracked = untracked_files;
+	s.index_file = index_file;
+	s.fp = fp;
+
+	wt_status_print(&s);
+
+	return s.commitable;
+}
+
+static const char sign_off_header[] = "Signed-off-by: ";
+
+static int prepare_log_message(const char *index_file)
+{
+	struct stat statbuf;
+	int commitable;
+	struct strbuf sb;
+	char *buffer;
+	FILE *fp;
+
+	strbuf_init(&sb, 0);
+	if (message) {
+		strbuf_add(&sb, message, strlen(message));
+	} else if (logfile && !strcmp(logfile, "-")) {
+		if (isatty(0))
+			fprintf(stderr, "(reading log message from standard input)\n");
+		if (strbuf_read(&sb, 0, 0) < 0)
+			die("could not read log from standard input");
+	} else if (logfile) {
+		if (strbuf_read_file(&sb, logfile, 0) < 0)
+			die("could not read log file '%s': %s",
+			    logfile, strerror(errno));
+	} else if (use_message) {
+		buffer = strstr(use_message_buffer, "\n\n");
+		if (!buffer || buffer[2] == '\0')
+			die("commit has empty message");
+		strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
+	} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
+		if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
+			die("could not read MERGE_MSG: %s", strerror(errno));
+	} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
+		if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
+			die("could not read SQUASH_MSG: %s", strerror(errno));
+	} else if (!stat(template_file, &statbuf)) {
+		if (strbuf_read_file(&sb, template_file, 0) < 0)
+			die("could not read %s: %s",
+			    template_file, strerror(errno));
+	}
+
+	fp = fopen(git_path(commit_editmsg), "w");
+	if (fp == NULL)
+		die("could not open %s\n", git_path(commit_editmsg));
+		
+	stripspace(&sb, 0);
+	if (fwrite(sb.buf, 1, sb.len, fp) < sb.len)
+		die("could not write commit template: %s\n",
+		    strerror(errno));
+
+	if (signoff) {
+		const char *info, *bol;
+
+		info = git_committer_info(1);
+		strbuf_addch(&sb, '\0');
+		bol = strrchr(sb.buf + sb.len - 1, '\n');
+		if (!bol || prefixcmp(bol, sign_off_header))
+			fprintf(fp, "\n");
+		fprintf(fp, "%s%s\n", sign_off_header, git_committer_info(1));
+	}
+
+	strbuf_release(&sb);
+
+	if (in_merge && !no_edit) {
+		fprintf(fp,
+			"#\n"
+			"# It looks like you may be committing a MERGE.\n"
+			"# If this is not correct, please remove the file\n"
+			"#	%s\n"
+			"# and try again.\n"
+			"#\n",
+			git_path("MERGE_HEAD"));
+	}
+
+	fprintf(fp,
+		"\n"
+		"# Please enter the commit message for your changes.\n"
+		"# (Comment lines starting with '#' will not be included)\n");
+	if (only_include_assumed)
+		fprintf(fp, "# %s\n", only_include_assumed);
+
+	commitable = run_status(fp, index_file);
+
+	fclose(fp);
+
+	return commitable;
+}
+
+/* Find out if the message starting at position 'start' in the strbuf
+ * contains only whitespace and Signed-off-by lines. */
+static int message_is_empty(struct strbuf *sb, int start)
+{
+	struct strbuf tmpl;
+	const char *nl;
+	int eol, i;
+
+	/* See if the template is just a prefix of the message. */
+	strbuf_init(&tmpl, 0);
+	if (template_file && strbuf_read_file(&tmpl, template_file, 0) > 0) {
+		stripspace(&tmpl, 1);
+		if (start + tmpl.len <= sb->len &&
+		    memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0)
+			start += tmpl.len;
+	}
+	strbuf_release(&tmpl);
+
+	/* Check if the rest is just whitespace and Signed-of-by's. */
+	for (i = start; i < sb->len; i++) {
+		nl = memchr(sb->buf + i, '\n', sb->len - i);
+		if (nl)
+			eol = nl - sb->buf;
+		else
+			eol = sb->len;
+
+		if (strlen(sign_off_header) <= eol - i &&
+		    !prefixcmp(sb->buf + i, sign_off_header)) {
+			i = eol;
+			continue;
+		}
+		while (i < eol)
+			if (!isspace(sb->buf[i++]))
+				return 0;
+	}
+
+	return 1;
+}
+
+static void determine_author_info(struct strbuf *sb)
+{
+	char *p, *eol;
+	char *name = NULL, *email = NULL;
+
+	if (use_message) {
+		p = strstr(use_message_buffer, "\nauthor");
+		if (!p)
+			die("invalid commit: %s\n", use_message);
+		p++;
+		eol = strchr(p, '\n');
+		if (!eol)
+			die("invalid commit: %s\n", use_message);
+
+		strbuf_add(sb, p, eol + 1 - p);
+	} else if (force_author) {
+		const char *eoname = strstr(force_author, " <");
+		const char *eomail = strchr(force_author, '>');
+
+		if (!eoname || !eomail)
+			die("malformed --author parameter\n");
+		name = xstrndup(force_author, eoname - force_author);
+		email = xstrndup(eoname + 2, eomail - eoname - 2);
+		strbuf_addf(sb, "author %s\n",
+			    fmt_ident(name, email, 
+				      getenv("GIT_AUTHOR_DATE"), 1));
+		free(name);
+		free(email);
+	} else {
+		strbuf_addf(sb, "author %s\n", git_author_info(1));
+	}
+}
+
+static int parse_and_validate_options(int argc, const char *argv[])
+{
+	int f = 0;
+
+	argc = parse_options(argc, argv, builtin_commit_options,
+			     builtin_commit_usage, 0);
+
+	if (logfile || message || use_message)
+		no_edit = 1;
+	if (edit_flag)
+		no_edit = 0;
+
+	if (get_sha1("HEAD", head_sha1))
+		initial_commit = 1;
+
+	if (!get_sha1("MERGE_HEAD", merge_head_sha1))
+		in_merge = 1;
+
+	/* Sanity check options */
+	if (amend && initial_commit)
+		die("You have nothing to amend.");
+	if (amend && in_merge)
+		die("You are in the middle of a merger -- cannot amend.");
+
+	if (use_message)
+		f++;
+	if (edit_message)
+		f++;
+	if (logfile)
+		f++;
+	if (f > 1)
+		die("Only one of -c/-C/-F can be used.");
+	if (message && f > 0)
+		die("Option -m cannot be combined with -c/-C/-F.");
+	if (edit_message)
+		use_message = edit_message;
+	if (amend)
+		use_message = "HEAD";
+	if (use_message) {
+		unsigned char sha1[20];
+		static char utf8[] = "UTF-8";
+		const char *out_enc;
+		char *enc, *end;
+		struct commit *commit;
+
+		if (get_sha1(use_message, sha1))
+			die("could not lookup commit %s", use_message);
+		commit = lookup_commit(sha1);
+		if (!commit || parse_commit(commit))
+			die("could not parse commit %s", use_message);
+
+		enc = strstr(commit->buffer, "\nencoding");
+		if (enc) {
+			end = strchr(enc + 10, '\n');
+			enc = xstrndup(enc + 10, end - (enc + 10));
+		} else {
+			enc = utf8;
+		}
+		out_enc = git_commit_encoding ? git_commit_encoding : utf8;
+
+		use_message_buffer =
+			reencode_string(commit->buffer, out_enc, enc);
+		if (enc != utf8)
+			free(enc);
+	}
+
+	if (also && only)
+		die("Only one of --include/--only can be used.");
+	if (!*argv && (also || (only && !amend)))
+		die("No paths with --include/--only does not make sense.");
+	if (!*argv && only && amend)
+		only_include_assumed = "Clever... amending the last one with dirty index.";
+	if (*argv && !also && !only) {
+		only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
+		also = 0;
+	}
+
+	if (all && interactive)
+		die("Cannot use -a, --interactive or -i at the same time.");
+	else if (all && argc > 0)
+		die("Paths with -a does not make sense.");
+	else if (interactive && **argv)
+		die("Paths with --interactive does not make sense.");
+
+	return argc;
+}
+
+int cmd_status(int argc, const char **argv, const char *prefix)
+{
+	const char *index_file;
+	int commitable;
+
+	git_config(git_status_config);
+
+	argc = parse_and_validate_options(argc, argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	commitable = run_status(stdout, index_file);
+
+	rollback_lock_file(&lock_file);
+
+	return commitable ? 0 : 1;
+}
+
+static int run_hook(const char *index_file, const char *name, const char *arg)
+{
+	struct child_process hook;
+	const char *argv[3], *env[2];
+	char index[PATH_MAX];
+
+	argv[0] = git_path("hooks/%s", name);
+	argv[1] = arg;
+	argv[2] = NULL;
+	snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
+	env[0] = index;
+	env[1] = NULL;
+
+	if (access(argv[0], X_OK) < 0)
+		return 0;
+
+	memset(&hook, 0, sizeof(hook));
+	hook.argv = argv;
+	hook.no_stdin = 1;
+	hook.stdout_to_stderr = 1;
+	hook.env = env;
+
+	return run_command(&hook);
+}
+
+static void print_summary(const char *prefix, const unsigned char *sha1)
+{
+	struct rev_info rev;
+	struct commit *commit;
+
+	commit = lookup_commit(sha1);
+	if (!commit)
+		die("couldn't look up newly created commit\n");
+	if (!commit || parse_commit(commit))
+		die("could not parse newly created commit");
+
+	init_revisions(&rev, prefix);
+	setup_revisions(0, NULL, &rev, NULL);
+
+	rev.abbrev = 0;
+	rev.diff = 1;
+	rev.diffopt.output_format =
+		DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
+
+	rev.verbose_header = 1;
+	rev.show_root_diff = 1;
+	rev.commit_format = get_commit_format("format:%h: %s");
+	rev.always_show_header = 1;
+		
+	printf("Created %scommit ", initial_commit ? "initial " : "");
+
+	log_tree_commit(&rev, commit);
+}
+
+int git_commit_config(const char *k, const char *v)
+{
+	if (!strcmp(k, "commit.template")) {
+		template_file = xstrdup(v);
+		return 0;
+	}
+
+	return git_status_config(k, v);
+}
+
+static const char commit_utf8_warn[] =
+"Warning: commit message does not conform to UTF-8.\n"
+"You may want to amend it after fixing the message, or set the config\n"
+"variable i18n.commitencoding to the encoding your project uses.\n";
+
+int cmd_commit(int argc, const char **argv, const char *prefix)
+{
+	int header_len, parent_count = 0;
+	struct strbuf sb;
+	const char *index_file, *reflog_msg;
+	char *nl, *header_line;
+	unsigned char commit_sha1[20];
+	struct ref_lock *ref_lock;
+
+	git_config(git_commit_config);
+
+	argc = parse_and_validate_options(argc, argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	if (!no_verify && run_hook(index_file, "pre-commit", NULL))
+		exit(1);
+
+	if (!prepare_log_message(index_file) && !in_merge) {
+		run_status(stdout, index_file);
+		unlink(commit_editmsg);
+		return 1;
+	}
+
+	strbuf_init(&sb, 0);
+
+	/* Start building up the commit header */
+	read_cache_from(index_file);
+	active_cache_tree = cache_tree();
+	if (cache_tree_update(active_cache_tree,
+			      active_cache, active_nr, 0, 0) < 0)
+		die("Error building trees");
+	strbuf_addf(&sb, "tree %s\n",
+		    sha1_to_hex(active_cache_tree->sha1));
+
+	/* Determine parents */
+	if (initial_commit) {
+		reflog_msg = "commit (initial)"; 
+		parent_count = 0;
+	} else if (amend) {
+		struct commit_list *c;
+		struct commit *commit;
+
+		reflog_msg = "commit (amend)";
+		commit = lookup_commit(head_sha1);
+		if (!commit || parse_commit(commit))
+			die("could not parse HEAD commit");
+
+		for (c = commit->parents; c; c = c->next)
+			strbuf_addf(&sb, "parent %s\n",
+				      sha1_to_hex(c->item->object.sha1));
+	} else if (in_merge) {
+		struct strbuf m;
+		FILE *fp;
+
+		reflog_msg = "commit (merge)";
+		strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+		strbuf_init(&m, 0);
+		fp = fopen(git_path("MERGE_HEAD"), "r");
+		if (fp == NULL)
+			die("could not open %s for reading: %s",
+			    git_path("MERGE_HEAD"), strerror(errno));
+		while (strbuf_getline(&m, fp, '\n') != EOF)
+			strbuf_addf(&sb, "parent %s\n", m.buf);
+		fclose(fp);
+		strbuf_release(&m);
+	} else {
+		reflog_msg = "commit";
+		strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+	}
+
+	determine_author_info(&sb);
+	strbuf_addf(&sb, "committer %s\n", git_committer_info(1));
+	if (!is_encoding_utf8(git_commit_encoding))
+		strbuf_addf(&sb, "encoding %s\n", git_commit_encoding);
+	strbuf_addch(&sb, '\n');
+
+	/* Get the commit message and validate it */
+	header_len = sb.len;
+	if (!no_edit) {
+		fprintf(stderr, "launching editor, log %s\n", logfile);
+		launch_editor(git_path(commit_editmsg), &sb);
+	}
+	else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0)
+		die("could not read commit message\n");
+	if (run_hook(index_file, "commit-msg", commit_editmsg))
+		exit(1);
+	stripspace(&sb, 1);
+	if (sb.len < header_len ||
+	    message_is_empty(&sb, header_len))
+		die("* no commit message?  aborting commit.");
+	strbuf_addch(&sb, '\0');
+	if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf))
+		fprintf(stderr, commit_utf8_warn);
+
+	if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1))
+		die("failed to write commit object");
+		       
+	ref_lock = lock_any_ref_for_update("HEAD",
+					   initial_commit ? NULL : head_sha1,
+					   0);
+
+	nl = strchr(sb.buf + header_len, '\n');
+	header_line = xstrndup(sb.buf + header_len,
+			       nl - (sb.buf + header_len));
+	strbuf_release(&sb);
+	strbuf_addf(&sb, "%s: %s\n", reflog_msg, header_line);
+	strbuf_addch(&sb, '\0');
+	free(header_line);
+
+	if (!ref_lock)
+		die("cannot lock HEAD ref");
+	if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0)
+		die("cannot update HEAD ref");
+
+	unlink(git_path("MERGE_HEAD"));
+	unlink(git_path("MERGE_MSG"));
+
+	if (lock_file.filename[0] && commit_locked_index(&lock_file))
+		die("failed to write new index");
+
+	rerere();
+
+	run_hook(index_file, "post-commit", NULL);
+
+	if (!quiet)
+		print_summary(prefix, commit_sha1);
+
+	return 0;
+}
diff --git a/builtin-tag.c b/builtin-tag.c
index 66e5a58..e6bae69 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -17,7 +17,7 @@ static const char builtin_tag_usage[] =
 
 static char signingkey[1000];
 
-static void launch_editor(const char *path, struct strbuf *buffer)
+void launch_editor(const char *path, struct strbuf *buffer)
 {
 	const char *editor, *terminal;
 	struct child_process child;
diff --git a/builtin.h b/builtin.h
index 9a6213a..0f8456c 100644
--- a/builtin.h
+++ b/builtin.h
@@ -24,6 +24,7 @@ extern int cmd_check_attr(int argc, const char **argv, const char *prefix);
 extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
+extern int cmd_commit(int argc, const char **argv, const char *prefix);
 extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_describe(int argc, const char **argv, const char *prefix);
@@ -68,10 +69,10 @@ extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
 extern int cmd_revert(int argc, const char **argv, const char *prefix);
 extern int cmd_rm(int argc, const char **argv, const char *prefix);
-extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
 extern int cmd_shortlog(int argc, const char **argv, const char *prefix);
 extern int cmd_show(int argc, const char **argv, const char *prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
+extern int cmd_status(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
 extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_tag(int argc, const char **argv, const char *prefix);
diff --git a/contrib/examples/git-commit.sh b/contrib/examples/git-commit.sh
new file mode 100755
index 0000000..fcb8443
--- /dev/null
+++ b/contrib/examples/git-commit.sh
@@ -0,0 +1,628 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Linus Torvalds
+# Copyright (c) 2006 Junio C Hamano
+
+USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
+SUBDIRECTORY_OK=Yes
+. git-sh-setup
+require_work_tree
+
+git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
+
+case "$0" in
+*status)
+	status_only=t
+	;;
+*commit)
+	status_only=
+	;;
+esac
+
+refuse_partial () {
+	echo >&2 "$1"
+	echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
+	exit 1
+}
+
+TMP_INDEX=
+THIS_INDEX="$GIT_DIR/index"
+NEXT_INDEX="$GIT_DIR/next-index$$"
+rm -f "$NEXT_INDEX"
+save_index () {
+	cp -p "$THIS_INDEX" "$NEXT_INDEX"
+}
+
+run_status () {
+	# If TMP_INDEX is defined, that means we are doing
+	# "--only" partial commit, and that index file is used
+	# to build the tree for the commit.  Otherwise, if
+	# NEXT_INDEX exists, that is the index file used to
+	# make the commit.  Otherwise we are using as-is commit
+	# so the regular index file is what we use to compare.
+	if test '' != "$TMP_INDEX"
+	then
+		GIT_INDEX_FILE="$TMP_INDEX"
+		export GIT_INDEX_FILE
+	elif test -f "$NEXT_INDEX"
+	then
+		GIT_INDEX_FILE="$NEXT_INDEX"
+		export GIT_INDEX_FILE
+	fi
+
+	if test "$status_only" = "t" -o "$use_status_color" = "t"; then
+		color=
+	else
+		color=--nocolor
+	fi
+	git runstatus ${color} \
+		${verbose:+--verbose} \
+		${amend:+--amend} \
+		${untracked_files:+--untracked}
+}
+
+trap '
+	test -z "$TMP_INDEX" || {
+		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
+	}
+	rm -f "$NEXT_INDEX"
+' 0
+
+################################################################
+# Command line argument parsing and sanity checking
+
+all=
+also=
+interactive=
+only=
+logfile=
+use_commit=
+amend=
+edit_flag=
+no_edit=
+log_given=
+log_message=
+verify=t
+quiet=
+verbose=
+signoff=
+force_author=
+only_include_assumed=
+untracked_files=
+templatefile="`git config commit.template`"
+while test $# != 0
+do
+	case "$1" in
+	-F|--F|-f|--f|--fi|--fil|--file)
+		case "$#" in 1) usage ;; esac
+		shift
+		no_edit=t
+		log_given=t$log_given
+		logfile="$1"
+		;;
+	-F*|-f*)
+		no_edit=t
+		log_given=t$log_given
+		logfile="${1#-[Ff]}"
+		;;
+	--F=*|--f=*|--fi=*|--fil=*|--file=*)
+		no_edit=t
+		log_given=t$log_given
+		logfile="${1#*=}"
+		;;
+	-a|--a|--al|--all)
+		all=t
+		;;
+	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
+		force_author="${1#*=}"
+		;;
+	--au|--aut|--auth|--autho|--author)
+		case "$#" in 1) usage ;; esac
+		shift
+		force_author="$1"
+		;;
+	-e|--e|--ed|--edi|--edit)
+		edit_flag=t
+		;;
+	-i|--i|--in|--inc|--incl|--inclu|--includ|--include)
+		also=t
+		;;
+	--int|--inte|--inter|--intera|--interac|--interact|--interacti|\
+	--interactiv|--interactive)
+		interactive=t
+		;;
+	-o|--o|--on|--onl|--only)
+		only=t
+		;;
+	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=m$log_given
+		log_message="${log_message:+${log_message}
+
+}$1"
+		no_edit=t
+		;;
+	-m*)
+		log_given=m$log_given
+		log_message="${log_message:+${log_message}
+
+}${1#-m}"
+		no_edit=t
+		;;
+	--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
+		log_given=m$log_given
+		log_message="${log_message:+${log_message}
+
+}${1#*=}"
+		no_edit=t
+		;;
+	-n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
+	--no-verify)
+		verify=
+		;;
+	--a|--am|--ame|--amen|--amend)
+		amend=t
+		use_commit=HEAD
+		;;
+	-c)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=
+		;;
+	--ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
+	--reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
+	--reedit-messag=*|--reedit-message=*)
+		log_given=t$log_given
+		use_commit="${1#*=}"
+		no_edit=
+		;;
+	--ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
+	--reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
+	--reedit-message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=
+		;;
+	-C)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=t
+		;;
+	--reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
+	--reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
+	--reuse-message=*)
+		log_given=t$log_given
+		use_commit="${1#*=}"
+		no_edit=t
+		;;
+	--reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
+	--reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=t
+		;;
+	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
+		signoff=t
+		;;
+	-t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
+		case "$#" in 1) usage ;; esac
+		shift
+		templatefile="$1"
+		no_edit=
+		;;
+	-q|--q|--qu|--qui|--quie|--quiet)
+		quiet=t
+		;;
+	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
+		verbose=t
+		;;
+	-u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
+	--untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
+	--untracked-file|--untracked-files)
+		untracked_files=t
+		;;
+	--)
+		shift
+		break
+		;;
+	-*)
+		usage
+		;;
+	*)
+		break
+		;;
+	esac
+	shift
+done
+case "$edit_flag" in t) no_edit= ;; esac
+
+################################################################
+# Sanity check options
+
+case "$amend,$initial_commit" in
+t,t)
+	die "You do not have anything to amend." ;;
+t,)
+	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+		die "You are in the middle of a merge -- cannot amend."
+	fi ;;
+esac
+
+case "$log_given" in
+tt*)
+	die "Only one of -c/-C/-F can be used." ;;
+*tm*|*mt*)
+	die "Option -m cannot be combined with -c/-C/-F." ;;
+esac
+
+case "$#,$also,$only,$amend" in
+*,t,t,*)
+	die "Only one of --include/--only can be used." ;;
+0,t,,* | 0,,t,)
+	die "No paths with --include/--only does not make sense." ;;
+0,,t,t)
+	only_include_assumed="# Clever... amending the last one with dirty index." ;;
+0,,,*)
+	;;
+*,,,*)
+	only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
+	also=
+	;;
+esac
+unset only
+case "$all,$interactive,$also,$#" in
+*t,*t,*)
+	die "Cannot use -a, --interactive or -i at the same time." ;;
+t,,[1-9]*)
+	die "Paths with -a does not make sense." ;;
+,t,[1-9]*)
+	die "Paths with --interactive does not make sense." ;;
+,,t,0)
+	die "No paths with -i does not make sense." ;;
+esac
+
+if test ! -z "$templatefile" -a -z "$log_given"
+then
+	if test ! -f "$templatefile"
+	then
+		die "Commit template file does not exist."
+	fi
+fi
+
+################################################################
+# Prepare index to have a tree to be committed
+
+case "$all,$also" in
+t,)
+	if test ! -f "$THIS_INDEX"
+	then
+		die 'nothing to commit (use "git add file1 file2" to include for commit)'
+	fi
+	save_index &&
+	(
+		cd_to_toplevel &&
+		GIT_INDEX_FILE="$NEXT_INDEX" &&
+		export GIT_INDEX_FILE &&
+		git diff-files --name-only -z |
+		git update-index --remove -z --stdin
+	) || exit
+	;;
+,t)
+	save_index &&
+	git ls-files --error-unmatch -- "$@" >/dev/null || exit
+
+	git diff-files --name-only -z -- "$@"  |
+	(
+		cd_to_toplevel &&
+		GIT_INDEX_FILE="$NEXT_INDEX" &&
+		export GIT_INDEX_FILE &&
+		git update-index --remove -z --stdin
+	) || exit
+	;;
+,)
+	if test "$interactive" = t; then
+		git add --interactive || exit
+	fi
+	case "$#" in
+	0)
+		;; # commit as-is
+	*)
+		if test -f "$GIT_DIR/MERGE_HEAD"
+		then
+			refuse_partial "Cannot do a partial commit during a merge."
+		fi
+
+		TMP_INDEX="$GIT_DIR/tmp-index$$"
+		W=
+		test -z "$initial_commit" && W=--with-tree=HEAD
+		commit_only=`git ls-files --error-unmatch $W -- "$@"` || exit
+
+		# Build a temporary index and update the real index
+		# the same way.
+		if test -z "$initial_commit"
+		then
+			GIT_INDEX_FILE="$THIS_INDEX" \
+			git read-tree --index-output="$TMP_INDEX" -i -m HEAD
+		else
+			rm -f "$TMP_INDEX"
+		fi || exit
+
+		printf '%s\n' "$commit_only" |
+		GIT_INDEX_FILE="$TMP_INDEX" \
+		git update-index --add --remove --stdin &&
+
+		save_index &&
+		printf '%s\n' "$commit_only" |
+		(
+			GIT_INDEX_FILE="$NEXT_INDEX"
+			export GIT_INDEX_FILE
+			git update-index --add --remove --stdin
+		) || exit
+		;;
+	esac
+	;;
+esac
+
+################################################################
+# If we do as-is commit, the index file will be THIS_INDEX,
+# otherwise NEXT_INDEX after we make this commit.  We leave
+# the index as is if we abort.
+
+if test -f "$NEXT_INDEX"
+then
+	USE_INDEX="$NEXT_INDEX"
+else
+	USE_INDEX="$THIS_INDEX"
+fi
+
+case "$status_only" in
+t)
+	# This will silently fail in a read-only repository, which is
+	# what we want.
+	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
+	run_status
+	exit $?
+	;;
+'')
+	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
+	;;
+esac
+
+################################################################
+# Grab commit message, write out tree and make commit.
+
+if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
+then
+    GIT_INDEX_FILE="${TMP_INDEX:-${USE_INDEX}}" "$GIT_DIR"/hooks/pre-commit \
+    || exit
+fi
+
+if test "$log_message" != ''
+then
+	printf '%s\n' "$log_message"
+elif test "$logfile" != ""
+then
+	if test "$logfile" = -
+	then
+		test -t 0 &&
+		echo >&2 "(reading log message from standard input)"
+		cat
+	else
+		cat <"$logfile"
+	fi
+elif test "$use_commit" != ""
+then
+	encoding=$(git config i18n.commitencoding || echo UTF-8)
+	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
+	sed -e '1,/^$/d' -e 's/^    //'
+elif test -f "$GIT_DIR/MERGE_MSG"
+then
+	cat "$GIT_DIR/MERGE_MSG"
+elif test -f "$GIT_DIR/SQUASH_MSG"
+then
+	cat "$GIT_DIR/SQUASH_MSG"
+elif test "$templatefile" != ""
+then
+	cat "$templatefile"
+fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
+
+case "$signoff" in
+t)
+	sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
+		s/>.*/>/
+		s/^/Signed-off-by: /
+		')
+	blank_before_signoff=
+	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+	grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
+'
+	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+	grep "$sign"$ >/dev/null ||
+	printf '%s%s\n' "$blank_before_signoff" "$sign" \
+		>>"$GIT_DIR"/COMMIT_EDITMSG
+	;;
+esac
+
+if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
+	echo "#"
+	echo "# It looks like you may be committing a MERGE."
+	echo "# If this is not correct, please remove the file"
+	printf '%s\n' "#	$GIT_DIR/MERGE_HEAD"
+	echo "# and try again"
+	echo "#"
+fi >>"$GIT_DIR"/COMMIT_EDITMSG
+
+# Author
+if test '' != "$use_commit"
+then
+	eval "$(get_author_ident_from_commit "$use_commit")"
+	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
+fi
+if test '' != "$force_author"
+then
+	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
+	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
+	test '' != "$GIT_AUTHOR_NAME" &&
+	test '' != "$GIT_AUTHOR_EMAIL" ||
+	die "malformed --author parameter"
+	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
+fi
+
+PARENTS="-p HEAD"
+if test -z "$initial_commit"
+then
+	rloga='commit'
+	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+		rloga='commit (merge)'
+		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
+	elif test -n "$amend"; then
+		rloga='commit (amend)'
+		PARENTS=$(git cat-file commit HEAD |
+			sed -n -e '/^$/q' -e 's/^parent /-p /p')
+	fi
+	current="$(git rev-parse --verify HEAD)"
+else
+	if [ -z "$(git ls-files)" ]; then
+		echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
+		exit 1
+	fi
+	PARENTS=""
+	rloga='commit (initial)'
+	current=''
+fi
+set_reflog_action "$rloga"
+
+if test -z "$no_edit"
+then
+	{
+		echo ""
+		echo "# Please enter the commit message for your changes."
+		echo "# (Comment lines starting with '#' will not be included)"
+		test -z "$only_include_assumed" || echo "$only_include_assumed"
+		run_status
+	} >>"$GIT_DIR"/COMMIT_EDITMSG
+else
+	# we need to check if there is anything to commit
+	run_status >/dev/null
+fi
+if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ]
+then
+	rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+	use_status_color=t
+	run_status
+	exit 1
+fi
+
+case "$no_edit" in
+'')
+	git-var GIT_AUTHOR_IDENT > /dev/null  || die
+	git-var GIT_COMMITTER_IDENT > /dev/null  || die
+	git_editor "$GIT_DIR/COMMIT_EDITMSG"
+	;;
+esac
+
+case "$verify" in
+t)
+	if test -x "$GIT_DIR"/hooks/commit-msg
+	then
+		"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
+	fi
+esac
+
+if test -z "$no_edit"
+then
+    sed -e '
+        /^diff --git a\/.*/{
+	    s///
+	    q
+	}
+	/^#/d
+    ' "$GIT_DIR"/COMMIT_EDITMSG
+else
+    cat "$GIT_DIR"/COMMIT_EDITMSG
+fi |
+git stripspace >"$GIT_DIR"/COMMIT_MSG
+
+# Test whether the commit message has any content we didn't supply.
+have_commitmsg=
+grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
+	git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
+
+# Is the commit message totally empty?
+if test -s "$GIT_DIR"/COMMIT_BAREMSG
+then
+	if test "$templatefile" != ""
+	then
+		# Test whether this is just the unaltered template.
+		if cnt=`sed -e '/^#/d' < "$templatefile" |
+			git stripspace |
+			diff "$GIT_DIR"/COMMIT_BAREMSG - |
+			wc -l` &&
+		   test 0 -lt $cnt
+		then
+			have_commitmsg=t
+		fi
+	else
+		# No template, so the content in the commit message must
+		# have come from the user.
+		have_commitmsg=t
+	fi
+fi
+
+rm -f "$GIT_DIR"/COMMIT_BAREMSG
+
+if test "$have_commitmsg" = "t"
+then
+	if test -z "$TMP_INDEX"
+	then
+		tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
+	else
+		tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
+		rm -f "$TMP_INDEX"
+	fi &&
+	commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
+	rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
+	git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
+	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
+	if test -f "$NEXT_INDEX"
+	then
+		mv "$NEXT_INDEX" "$THIS_INDEX"
+	else
+		: ;# happy
+	fi
+else
+	echo >&2 "* no commit message?  aborting commit."
+	false
+fi
+ret="$?"
+rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+
+cd_to_toplevel
+
+git rerere
+
+if test "$ret" = 0
+then
+	git gc --auto
+	if test -x "$GIT_DIR"/hooks/post-commit
+	then
+		"$GIT_DIR"/hooks/post-commit
+	fi
+	if test -z "$quiet"
+	then
+		commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
+		       --summary --root HEAD --`
+		echo "Created${initial_commit:+ initial} commit $commit"
+	fi
+fi
+
+exit "$ret"
diff --git a/git-commit.sh b/git-commit.sh
deleted file mode 100755
index fcb8443..0000000
--- a/git-commit.sh
+++ /dev/null
@@ -1,628 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Linus Torvalds
-# Copyright (c) 2006 Junio C Hamano
-
-USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
-SUBDIRECTORY_OK=Yes
-. git-sh-setup
-require_work_tree
-
-git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
-
-case "$0" in
-*status)
-	status_only=t
-	;;
-*commit)
-	status_only=
-	;;
-esac
-
-refuse_partial () {
-	echo >&2 "$1"
-	echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
-	exit 1
-}
-
-TMP_INDEX=
-THIS_INDEX="$GIT_DIR/index"
-NEXT_INDEX="$GIT_DIR/next-index$$"
-rm -f "$NEXT_INDEX"
-save_index () {
-	cp -p "$THIS_INDEX" "$NEXT_INDEX"
-}
-
-run_status () {
-	# If TMP_INDEX is defined, that means we are doing
-	# "--only" partial commit, and that index file is used
-	# to build the tree for the commit.  Otherwise, if
-	# NEXT_INDEX exists, that is the index file used to
-	# make the commit.  Otherwise we are using as-is commit
-	# so the regular index file is what we use to compare.
-	if test '' != "$TMP_INDEX"
-	then
-		GIT_INDEX_FILE="$TMP_INDEX"
-		export GIT_INDEX_FILE
-	elif test -f "$NEXT_INDEX"
-	then
-		GIT_INDEX_FILE="$NEXT_INDEX"
-		export GIT_INDEX_FILE
-	fi
-
-	if test "$status_only" = "t" -o "$use_status_color" = "t"; then
-		color=
-	else
-		color=--nocolor
-	fi
-	git runstatus ${color} \
-		${verbose:+--verbose} \
-		${amend:+--amend} \
-		${untracked_files:+--untracked}
-}
-
-trap '
-	test -z "$TMP_INDEX" || {
-		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
-	}
-	rm -f "$NEXT_INDEX"
-' 0
-
-################################################################
-# Command line argument parsing and sanity checking
-
-all=
-also=
-interactive=
-only=
-logfile=
-use_commit=
-amend=
-edit_flag=
-no_edit=
-log_given=
-log_message=
-verify=t
-quiet=
-verbose=
-signoff=
-force_author=
-only_include_assumed=
-untracked_files=
-templatefile="`git config commit.template`"
-while test $# != 0
-do
-	case "$1" in
-	-F|--F|-f|--f|--fi|--fil|--file)
-		case "$#" in 1) usage ;; esac
-		shift
-		no_edit=t
-		log_given=t$log_given
-		logfile="$1"
-		;;
-	-F*|-f*)
-		no_edit=t
-		log_given=t$log_given
-		logfile="${1#-[Ff]}"
-		;;
-	--F=*|--f=*|--fi=*|--fil=*|--file=*)
-		no_edit=t
-		log_given=t$log_given
-		logfile="${1#*=}"
-		;;
-	-a|--a|--al|--all)
-		all=t
-		;;
-	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
-		force_author="${1#*=}"
-		;;
-	--au|--aut|--auth|--autho|--author)
-		case "$#" in 1) usage ;; esac
-		shift
-		force_author="$1"
-		;;
-	-e|--e|--ed|--edi|--edit)
-		edit_flag=t
-		;;
-	-i|--i|--in|--inc|--incl|--inclu|--includ|--include)
-		also=t
-		;;
-	--int|--inte|--inter|--intera|--interac|--interact|--interacti|\
-	--interactiv|--interactive)
-		interactive=t
-		;;
-	-o|--o|--on|--onl|--only)
-		only=t
-		;;
-	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=m$log_given
-		log_message="${log_message:+${log_message}
-
-}$1"
-		no_edit=t
-		;;
-	-m*)
-		log_given=m$log_given
-		log_message="${log_message:+${log_message}
-
-}${1#-m}"
-		no_edit=t
-		;;
-	--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
-		log_given=m$log_given
-		log_message="${log_message:+${log_message}
-
-}${1#*=}"
-		no_edit=t
-		;;
-	-n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
-	--no-verify)
-		verify=
-		;;
-	--a|--am|--ame|--amen|--amend)
-		amend=t
-		use_commit=HEAD
-		;;
-	-c)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		;;
-	--ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
-	--reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
-	--reedit-messag=*|--reedit-message=*)
-		log_given=t$log_given
-		use_commit="${1#*=}"
-		no_edit=
-		;;
-	--ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
-	--reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
-	--reedit-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		;;
-	-C)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		;;
-	--reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
-	--reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
-	--reuse-message=*)
-		log_given=t$log_given
-		use_commit="${1#*=}"
-		no_edit=t
-		;;
-	--reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
-	--reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		;;
-	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
-		signoff=t
-		;;
-	-t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
-		case "$#" in 1) usage ;; esac
-		shift
-		templatefile="$1"
-		no_edit=
-		;;
-	-q|--q|--qu|--qui|--quie|--quiet)
-		quiet=t
-		;;
-	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
-		verbose=t
-		;;
-	-u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
-	--untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
-	--untracked-file|--untracked-files)
-		untracked_files=t
-		;;
-	--)
-		shift
-		break
-		;;
-	-*)
-		usage
-		;;
-	*)
-		break
-		;;
-	esac
-	shift
-done
-case "$edit_flag" in t) no_edit= ;; esac
-
-################################################################
-# Sanity check options
-
-case "$amend,$initial_commit" in
-t,t)
-	die "You do not have anything to amend." ;;
-t,)
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		die "You are in the middle of a merge -- cannot amend."
-	fi ;;
-esac
-
-case "$log_given" in
-tt*)
-	die "Only one of -c/-C/-F can be used." ;;
-*tm*|*mt*)
-	die "Option -m cannot be combined with -c/-C/-F." ;;
-esac
-
-case "$#,$also,$only,$amend" in
-*,t,t,*)
-	die "Only one of --include/--only can be used." ;;
-0,t,,* | 0,,t,)
-	die "No paths with --include/--only does not make sense." ;;
-0,,t,t)
-	only_include_assumed="# Clever... amending the last one with dirty index." ;;
-0,,,*)
-	;;
-*,,,*)
-	only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
-	also=
-	;;
-esac
-unset only
-case "$all,$interactive,$also,$#" in
-*t,*t,*)
-	die "Cannot use -a, --interactive or -i at the same time." ;;
-t,,[1-9]*)
-	die "Paths with -a does not make sense." ;;
-,t,[1-9]*)
-	die "Paths with --interactive does not make sense." ;;
-,,t,0)
-	die "No paths with -i does not make sense." ;;
-esac
-
-if test ! -z "$templatefile" -a -z "$log_given"
-then
-	if test ! -f "$templatefile"
-	then
-		die "Commit template file does not exist."
-	fi
-fi
-
-################################################################
-# Prepare index to have a tree to be committed
-
-case "$all,$also" in
-t,)
-	if test ! -f "$THIS_INDEX"
-	then
-		die 'nothing to commit (use "git add file1 file2" to include for commit)'
-	fi
-	save_index &&
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git diff-files --name-only -z |
-		git update-index --remove -z --stdin
-	) || exit
-	;;
-,t)
-	save_index &&
-	git ls-files --error-unmatch -- "$@" >/dev/null || exit
-
-	git diff-files --name-only -z -- "$@"  |
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git update-index --remove -z --stdin
-	) || exit
-	;;
-,)
-	if test "$interactive" = t; then
-		git add --interactive || exit
-	fi
-	case "$#" in
-	0)
-		;; # commit as-is
-	*)
-		if test -f "$GIT_DIR/MERGE_HEAD"
-		then
-			refuse_partial "Cannot do a partial commit during a merge."
-		fi
-
-		TMP_INDEX="$GIT_DIR/tmp-index$$"
-		W=
-		test -z "$initial_commit" && W=--with-tree=HEAD
-		commit_only=`git ls-files --error-unmatch $W -- "$@"` || exit
-
-		# Build a temporary index and update the real index
-		# the same way.
-		if test -z "$initial_commit"
-		then
-			GIT_INDEX_FILE="$THIS_INDEX" \
-			git read-tree --index-output="$TMP_INDEX" -i -m HEAD
-		else
-			rm -f "$TMP_INDEX"
-		fi || exit
-
-		printf '%s\n' "$commit_only" |
-		GIT_INDEX_FILE="$TMP_INDEX" \
-		git update-index --add --remove --stdin &&
-
-		save_index &&
-		printf '%s\n' "$commit_only" |
-		(
-			GIT_INDEX_FILE="$NEXT_INDEX"
-			export GIT_INDEX_FILE
-			git update-index --add --remove --stdin
-		) || exit
-		;;
-	esac
-	;;
-esac
-
-################################################################
-# If we do as-is commit, the index file will be THIS_INDEX,
-# otherwise NEXT_INDEX after we make this commit.  We leave
-# the index as is if we abort.
-
-if test -f "$NEXT_INDEX"
-then
-	USE_INDEX="$NEXT_INDEX"
-else
-	USE_INDEX="$THIS_INDEX"
-fi
-
-case "$status_only" in
-t)
-	# This will silently fail in a read-only repository, which is
-	# what we want.
-	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
-	run_status
-	exit $?
-	;;
-'')
-	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
-	;;
-esac
-
-################################################################
-# Grab commit message, write out tree and make commit.
-
-if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
-then
-    GIT_INDEX_FILE="${TMP_INDEX:-${USE_INDEX}}" "$GIT_DIR"/hooks/pre-commit \
-    || exit
-fi
-
-if test "$log_message" != ''
-then
-	printf '%s\n' "$log_message"
-elif test "$logfile" != ""
-then
-	if test "$logfile" = -
-	then
-		test -t 0 &&
-		echo >&2 "(reading log message from standard input)"
-		cat
-	else
-		cat <"$logfile"
-	fi
-elif test "$use_commit" != ""
-then
-	encoding=$(git config i18n.commitencoding || echo UTF-8)
-	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
-	sed -e '1,/^$/d' -e 's/^    //'
-elif test -f "$GIT_DIR/MERGE_MSG"
-then
-	cat "$GIT_DIR/MERGE_MSG"
-elif test -f "$GIT_DIR/SQUASH_MSG"
-then
-	cat "$GIT_DIR/SQUASH_MSG"
-elif test "$templatefile" != ""
-then
-	cat "$templatefile"
-fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
-
-case "$signoff" in
-t)
-	sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
-		s/>.*/>/
-		s/^/Signed-off-by: /
-		')
-	blank_before_signoff=
-	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-	grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
-'
-	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-	grep "$sign"$ >/dev/null ||
-	printf '%s%s\n' "$blank_before_signoff" "$sign" \
-		>>"$GIT_DIR"/COMMIT_EDITMSG
-	;;
-esac
-
-if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
-	echo "#"
-	echo "# It looks like you may be committing a MERGE."
-	echo "# If this is not correct, please remove the file"
-	printf '%s\n' "#	$GIT_DIR/MERGE_HEAD"
-	echo "# and try again"
-	echo "#"
-fi >>"$GIT_DIR"/COMMIT_EDITMSG
-
-# Author
-if test '' != "$use_commit"
-then
-	eval "$(get_author_ident_from_commit "$use_commit")"
-	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
-fi
-if test '' != "$force_author"
-then
-	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
-	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
-	test '' != "$GIT_AUTHOR_NAME" &&
-	test '' != "$GIT_AUTHOR_EMAIL" ||
-	die "malformed --author parameter"
-	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
-fi
-
-PARENTS="-p HEAD"
-if test -z "$initial_commit"
-then
-	rloga='commit'
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		rloga='commit (merge)'
-		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
-	elif test -n "$amend"; then
-		rloga='commit (amend)'
-		PARENTS=$(git cat-file commit HEAD |
-			sed -n -e '/^$/q' -e 's/^parent /-p /p')
-	fi
-	current="$(git rev-parse --verify HEAD)"
-else
-	if [ -z "$(git ls-files)" ]; then
-		echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
-		exit 1
-	fi
-	PARENTS=""
-	rloga='commit (initial)'
-	current=''
-fi
-set_reflog_action "$rloga"
-
-if test -z "$no_edit"
-then
-	{
-		echo ""
-		echo "# Please enter the commit message for your changes."
-		echo "# (Comment lines starting with '#' will not be included)"
-		test -z "$only_include_assumed" || echo "$only_include_assumed"
-		run_status
-	} >>"$GIT_DIR"/COMMIT_EDITMSG
-else
-	# we need to check if there is anything to commit
-	run_status >/dev/null
-fi
-if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ]
-then
-	rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-	use_status_color=t
-	run_status
-	exit 1
-fi
-
-case "$no_edit" in
-'')
-	git-var GIT_AUTHOR_IDENT > /dev/null  || die
-	git-var GIT_COMMITTER_IDENT > /dev/null  || die
-	git_editor "$GIT_DIR/COMMIT_EDITMSG"
-	;;
-esac
-
-case "$verify" in
-t)
-	if test -x "$GIT_DIR"/hooks/commit-msg
-	then
-		"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
-	fi
-esac
-
-if test -z "$no_edit"
-then
-    sed -e '
-        /^diff --git a\/.*/{
-	    s///
-	    q
-	}
-	/^#/d
-    ' "$GIT_DIR"/COMMIT_EDITMSG
-else
-    cat "$GIT_DIR"/COMMIT_EDITMSG
-fi |
-git stripspace >"$GIT_DIR"/COMMIT_MSG
-
-# Test whether the commit message has any content we didn't supply.
-have_commitmsg=
-grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
-	git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
-
-# Is the commit message totally empty?
-if test -s "$GIT_DIR"/COMMIT_BAREMSG
-then
-	if test "$templatefile" != ""
-	then
-		# Test whether this is just the unaltered template.
-		if cnt=`sed -e '/^#/d' < "$templatefile" |
-			git stripspace |
-			diff "$GIT_DIR"/COMMIT_BAREMSG - |
-			wc -l` &&
-		   test 0 -lt $cnt
-		then
-			have_commitmsg=t
-		fi
-	else
-		# No template, so the content in the commit message must
-		# have come from the user.
-		have_commitmsg=t
-	fi
-fi
-
-rm -f "$GIT_DIR"/COMMIT_BAREMSG
-
-if test "$have_commitmsg" = "t"
-then
-	if test -z "$TMP_INDEX"
-	then
-		tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
-	else
-		tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
-		rm -f "$TMP_INDEX"
-	fi &&
-	commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
-	rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
-	git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
-	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
-	if test -f "$NEXT_INDEX"
-	then
-		mv "$NEXT_INDEX" "$THIS_INDEX"
-	else
-		: ;# happy
-	fi
-else
-	echo >&2 "* no commit message?  aborting commit."
-	false
-fi
-ret="$?"
-rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-
-cd_to_toplevel
-
-git rerere
-
-if test "$ret" = 0
-then
-	git gc --auto
-	if test -x "$GIT_DIR"/hooks/post-commit
-	then
-		"$GIT_DIR"/hooks/post-commit
-	fi
-	if test -z "$quiet"
-	then
-		commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
-		       --summary --root HEAD --`
-		echo "Created${initial_commit:+ initial} commit $commit"
-	fi
-fi
-
-exit "$ret"
diff --git a/git.c b/git.c
index 4e10581..8522095 100644
--- a/git.c
+++ b/git.c
@@ -298,6 +298,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
 		{ "cherry", cmd_cherry, RUN_SETUP },
 		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
+		{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
 		{ "config", cmd_config },
 		{ "count-objects", cmd_count_objects, RUN_SETUP },
@@ -346,10 +347,10 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "rev-parse", cmd_rev_parse, RUN_SETUP },
 		{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
 		{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
-		{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
 		{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
 		{ "show-branch", cmd_show_branch, RUN_SETUP },
 		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
+		{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
 		{ "stripspace", cmd_stripspace },
 		{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 		{ "tag", cmd_tag, RUN_SETUP },
diff --git a/strbuf.h b/strbuf.h
index 9b9e861..9720826 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -113,5 +113,6 @@ extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
 extern int strbuf_getline(struct strbuf *, FILE *, int);
 
 extern void stripspace(struct strbuf *buf, int skip_comments);
+extern void launch_editor(const char *path, struct strbuf *buffer);
 
 #endif /* STRBUF_H */
diff --git a/t/t3501-revert-cherry-pick.sh b/t/t3501-revert-cherry-pick.sh
index 552af1c..2dbe04f 100755
--- a/t/t3501-revert-cherry-pick.sh
+++ b/t/t3501-revert-cherry-pick.sh
@@ -44,7 +44,7 @@ test_expect_success setup '
 test_expect_success 'cherry-pick after renaming branch' '
 
 	git checkout rename2 &&
-	EDITOR=: VISUAL=: git cherry-pick added &&
+	git cherry-pick added &&
 	test -f opos &&
 	grep "Add extra line at the end" opos
 
@@ -53,7 +53,7 @@ test_expect_success 'cherry-pick after renaming branch' '
 test_expect_success 'revert after renaming branch' '
 
 	git checkout rename1 &&
-	EDITOR=: VISUAL=: git revert added &&
+	git revert added &&
 	test -f spoo &&
 	! grep "Add extra line at the end" spoo
 
diff --git a/t/t3901-i18n-patch.sh b/t/t3901-i18n-patch.sh
index 28e9e37..235f372 100755
--- a/t/t3901-i18n-patch.sh
+++ b/t/t3901-i18n-patch.sh
@@ -154,7 +154,7 @@ test_expect_success 'cherry-pick(U/U)' '
 	git reset --hard master &&
 	git cherry-pick side^ &&
 	git cherry-pick side &&
-	EDITOR=: VISUAL=: git revert HEAD &&
+	git revert HEAD &&
 
 	check_encoding 3
 '
@@ -169,7 +169,7 @@ test_expect_success 'cherry-pick(L/L)' '
 	git reset --hard master &&
 	git cherry-pick side^ &&
 	git cherry-pick side &&
-	EDITOR=: VISUAL=: git revert HEAD &&
+	git revert HEAD &&
 
 	check_encoding 3 8859
 '
@@ -184,7 +184,7 @@ test_expect_success 'cherry-pick(U/L)' '
 	git reset --hard master &&
 	git cherry-pick side^ &&
 	git cherry-pick side &&
-	EDITOR=: VISUAL=: git revert HEAD &&
+	git revert HEAD &&
 
 	check_encoding 3
 '
@@ -200,7 +200,7 @@ test_expect_success 'cherry-pick(L/U)' '
 	git reset --hard master &&
 	git cherry-pick side^ &&
 	git cherry-pick side &&
-	EDITOR=: VISUAL=: git revert HEAD &&
+	git revert HEAD &&
 
 	check_encoding 3 8859
 '
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 714de6e..51cbcc1 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -9,8 +9,8 @@ LC_ALL=C
 PAGER=cat
 TZ=UTC
 export LANG LC_ALL PAGER TZ
-EDITOR=:
-VISUAL=:
+EDITOR=/bin/true
+VISUAL=/bin/true
 unset GIT_EDITOR
 unset AUTHOR_DATE
 unset AUTHOR_EMAIL
-- 
1.5.3.4.206.g58ba4

^ permalink raw reply related	[relevance 2%]

* [PATCH] Port git commit to C.
@ 2007-11-08 16:59  2% Kristian Høgsberg
  0 siblings, 0 replies; 200+ results
From: Kristian Høgsberg @ 2007-11-08 16:59 UTC (permalink / raw)
  To: gitster; +Cc: git, Kristian Høgsberg

This makes git commit a builtin and moves git-commit.sh to
contrib/examples.  This also removes the git-runstatus
helper, which was mostly just a git-status.sh implementation detail.

Signed-off-by: Kristian Høgsberg <krh@redhat.com>
---

This has Johannes' updates and Bjoerns command line parsing fixes.
Also fixes the author date problem on amend commits, so this replaces
Johannes' recent [PATCH 3/3] author fix.

cheers,
Kristian

 Makefile                       |    9 +-
 builtin-commit.c               |  615 +++++++++++++++++++++++++++++++++++++++
 builtin.h                      |    3 +-
 contrib/examples/git-commit.sh |  628 ++++++++++++++++++++++++++++++++++++++++
 git-commit.sh                  |  628 ----------------------------------------
 git.c                          |    3 +-
 strbuf.h                       |    1 +
 7 files changed, 1251 insertions(+), 636 deletions(-)
 create mode 100644 builtin-commit.c
 create mode 100755 contrib/examples/git-commit.sh
 delete mode 100755 git-commit.sh

diff --git a/Makefile b/Makefile
index 3ec1876..e4c51c6 100644
--- a/Makefile
+++ b/Makefile
@@ -209,7 +209,7 @@ BASIC_LDFLAGS =
 
 SCRIPT_SH = \
 	git-bisect.sh git-checkout.sh \
-	git-clean.sh git-clone.sh git-commit.sh \
+	git-clean.sh git-clone.sh \
 	git-ls-remote.sh \
 	git-merge-one-file.sh git-mergetool.sh git-parse-remote.sh \
 	git-pull.sh git-rebase.sh git-rebase--interactive.sh \
@@ -256,7 +256,7 @@ EXTRA_PROGRAMS =
 BUILT_INS = \
 	git-format-patch$X git-show$X git-whatchanged$X git-cherry$X \
 	git-get-tar-commit-id$X git-init$X git-repo-config$X \
-	git-fsck-objects$X git-cherry-pick$X \
+	git-fsck-objects$X git-cherry-pick$X git-status$X\
 	$(patsubst builtin-%.o,git-%$X,$(BUILTIN_OBJS))
 
 # what 'all' will build and 'install' will install, in gitexecdir
@@ -326,6 +326,7 @@ BUILTIN_OBJS = \
 	builtin-check-attr.o \
 	builtin-checkout-index.o \
 	builtin-check-ref-format.o \
+	builtin-commit.o \
 	builtin-commit-tree.o \
 	builtin-count-objects.o \
 	builtin-describe.o \
@@ -366,7 +367,6 @@ BUILTIN_OBJS = \
 	builtin-rev-parse.o \
 	builtin-revert.o \
 	builtin-rm.o \
-	builtin-runstatus.o \
 	builtin-shortlog.o \
 	builtin-show-branch.o \
 	builtin-stripspace.o \
@@ -832,9 +832,6 @@ $(patsubst %.perl,%,$(SCRIPT_PERL)): % : %.perl
 	chmod +x $@+ && \
 	mv $@+ $@
 
-git-status: git-commit
-	$(QUIET_GEN)cp $< $@+ && mv $@+ $@
-
 gitweb/gitweb.cgi: gitweb/gitweb.perl
 	$(QUIET_GEN)$(RM) $@ $@+ && \
 	sed -e '1s|#!.*perl|#!$(PERL_PATH_SQ)|' \
diff --git a/builtin-commit.c b/builtin-commit.c
new file mode 100644
index 0000000..ae4ca4e
--- /dev/null
+++ b/builtin-commit.c
@@ -0,0 +1,615 @@
+/*
+ * Builtin "git commit"
+ *
+ * Copyright (c) 2007 Kristian Høgsberg <krh@redhat.com>
+ * Based on git-commit.sh by Junio C Hamano and Linus Torvalds
+ */
+
+#include "git-compat-util.h"
+
+#include "cache.h"
+#include "cache-tree.h"
+#include "builtin.h"
+#include "diff.h"
+#include "diffcore.h"
+#include "commit.h"
+#include "revision.h"
+#include "wt-status.h"
+#include "run-command.h"
+#include "refs.h"
+#include "log-tree.h"
+#include "strbuf.h"
+#include "utf8.h"
+#include "parse-options.h"
+
+static const char * const builtin_commit_usage[] = {
+	"git-commit [options] [--] <filepattern>...",
+	NULL
+};
+
+static unsigned char head_sha1[20], merge_head_sha1[20];
+static char *use_message_buffer;
+static const char commit_editmsg[] = "COMMIT_EDITMSG";
+static struct lock_file lock_file;
+
+static char *logfile, *force_author, *message, *template_file;
+static char *edit_message, *use_message;
+static int all, edit_flag, also, interactive, only, amend, signoff;
+static int quiet, verbose, untracked_files, no_verify;
+
+static int no_edit, initial_commit, in_merge;
+const char *only_include_assumed;
+
+static struct option builtin_commit_options[] = {
+	OPT__QUIET(&quiet),
+	OPT__VERBOSE(&verbose),
+	OPT_GROUP("Commit message options"),
+
+	OPT_STRING('F', "file", &logfile, "FILE", "read log from file"),
+	OPT_STRING(0, "author", &force_author, "AUTHOR", "override author for commit"),
+	OPT_STRING('m', "message", &message, "MESSAGE", "specify commit message"),
+	OPT_STRING('c', "reedit-message", &edit_message, "COMMIT", "reuse and edit message from specified commit "),
+	OPT_STRING('C', "reuse-message", &use_message, "COMMIT", "reuse message from specified commit"),
+	OPT_BOOLEAN('s', "signoff", &signoff, "add Signed-off-by: header"),
+	OPT_STRING('t', "template", &template_file, "FILE", "use specified template file"),
+	OPT_BOOLEAN('e', "edit", &edit_flag, "force edit of commit"),
+
+	OPT_GROUP("Commit contents options"),
+	OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
+	OPT_BOOLEAN('i', "include", &also, "add specified files to index for commit"),
+	OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
+	OPT_BOOLEAN('o', "only", &only, ""),
+	OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
+	OPT_BOOLEAN(0, "amend", &amend, "amend previous commit"),
+	OPT_BOOLEAN(0, "untracked-files", &untracked_files, "show all untracked files"),
+
+	OPT_END()
+};
+
+static char *
+prepare_index(const char **files, const char *prefix)
+{
+	int fd;
+	struct tree *tree;
+	struct lock_file *next_index_lock;
+
+	if (interactive) {
+		interactive_add();
+		return get_index_file();
+	}
+
+	fd = hold_locked_index(&lock_file, 1);
+	if (read_cache() < 0)
+		die("index file corrupt");
+
+	if (all || also) {
+		add_files_to_cache(verbose, also ? prefix : NULL, files);
+		if (write_cache(fd, active_cache, active_nr) || close(fd))
+			die("unable to write new_index file");
+		return lock_file.filename;
+	}
+
+	if (*files == NULL) {
+		/* Commit index as-is. */
+		rollback_lock_file(&lock_file);
+		return get_index_file();
+	}
+
+	/* update the user index file */
+	add_files_to_cache(verbose, prefix, files);
+	if (write_cache(fd, active_cache, active_nr) || close(fd))
+		die("unable to write new_index file");
+
+	if (!initial_commit) {
+		tree = parse_tree_indirect(head_sha1);
+		if (!tree)
+			die("failed to unpack HEAD tree object");
+		if (read_tree(tree, 0, NULL))
+			die("failed to read HEAD tree object");
+	}
+
+	/* Use a lock file to garbage collect the temporary index file. */
+	next_index_lock = xmalloc(sizeof(*next_index_lock));
+	fd = hold_lock_file_for_update(next_index_lock,
+				       git_path("next-index-%d", getpid()), 1);
+	add_files_to_cache(verbose, prefix, files);
+	if (write_cache(fd, active_cache, active_nr) || close(fd))
+		die("unable to write new_index file");
+
+	return next_index_lock->filename;
+}
+
+static int run_status(FILE *fp, const char *index_file)
+{
+	struct wt_status s;
+
+	wt_status_prepare(&s);
+
+	if (amend) {
+		s.amend = 1;
+		s.reference = "HEAD^1";
+	}
+	s.verbose = verbose;
+	s.untracked = untracked_files;
+	s.index_file = index_file;
+	s.fp = fp;
+
+	wt_status_print(&s);
+
+	return s.commitable;
+}
+
+static const char sign_off_header[] = "Signed-off-by: ";
+
+static int prepare_log_message(const char *index_file)
+{
+	struct stat statbuf;
+	int commitable;
+	struct strbuf sb;
+	char *buffer;
+	FILE *fp;
+
+	strbuf_init(&sb, 0);
+	if (message) {
+		strbuf_add(&sb, message, strlen(message));
+	} else if (logfile && !strcmp(logfile, "-")) {
+		if (isatty(0))
+			fprintf(stderr, "(reading log message from standard input)\n");
+		if (strbuf_read(&sb, 0, 0) < 0)
+			die("could not read log from standard input");
+	} else if (logfile) {
+		if (strbuf_read_file(&sb, logfile, 0) < 0)
+			die("could not read log file '%s': %s",
+			    logfile, strerror(errno));
+	} else if (use_message) {
+		buffer = strstr(use_message_buffer, "\n\n");
+		if (!buffer || buffer[2] == '\0')
+			die("commit has empty message");
+		strbuf_add(&sb, buffer + 2, strlen(buffer + 2));
+	} else if (!stat(git_path("MERGE_MSG"), &statbuf)) {
+		if (strbuf_read_file(&sb, git_path("MERGE_MSG"), 0) < 0)
+			die("could not read MERGE_MSG: %s", strerror(errno));
+	} else if (!stat(git_path("SQUASH_MSG"), &statbuf)) {
+		if (strbuf_read_file(&sb, git_path("SQUASH_MSG"), 0) < 0)
+			die("could not read SQUASH_MSG: %s", strerror(errno));
+	} else if (template_file && !stat(template_file, &statbuf)) {
+		if (strbuf_read_file(&sb, template_file, 0) < 0)
+			die("could not read %s: %s",
+			    template_file, strerror(errno));
+	}
+
+	fp = fopen(git_path(commit_editmsg), "w");
+	if (fp == NULL)
+		die("could not open %s\n", git_path(commit_editmsg));
+		
+	stripspace(&sb, 0);
+	if (fwrite(sb.buf, 1, sb.len, fp) < sb.len)
+		die("could not write commit template: %s\n",
+		    strerror(errno));
+
+	if (signoff) {
+		const char *info, *bol;
+
+		info = git_committer_info(1);
+		strbuf_addch(&sb, '\0');
+		bol = strrchr(sb.buf + sb.len - 1, '\n');
+		if (!bol || prefixcmp(bol, sign_off_header))
+			fprintf(fp, "\n");
+		fprintf(fp, "%s%s\n", sign_off_header, git_committer_info(1));
+	}
+
+	strbuf_release(&sb);
+
+	if (in_merge && !no_edit) {
+		fprintf(fp,
+			"#\n"
+			"# It looks like you may be committing a MERGE.\n"
+			"# If this is not correct, please remove the file\n"
+			"#	%s\n"
+			"# and try again.\n"
+			"#\n",
+			git_path("MERGE_HEAD"));
+	}
+
+	fprintf(fp,
+		"\n"
+		"# Please enter the commit message for your changes.\n"
+		"# (Comment lines starting with '#' will not be included)\n");
+	if (only_include_assumed)
+		fprintf(fp, "# %s\n", only_include_assumed);
+
+	commitable = run_status(fp, index_file);
+
+	fclose(fp);
+
+	return commitable;
+}
+
+/* Find out if the message starting at position 'start' in the strbuf
+ * contains only whitespace and Signed-off-by lines. */
+static int message_is_empty(struct strbuf *sb, int start)
+{
+	struct strbuf tmpl;
+	const char *nl;
+	int eol, i;
+
+	/* See if the template is just a prefix of the message. */
+	strbuf_init(&tmpl, 0);
+	if (template_file && strbuf_read_file(&tmpl, template_file, 0) > 0) {
+		stripspace(&tmpl, 1);
+		if (start + tmpl.len <= sb->len &&
+		    memcmp(tmpl.buf, sb->buf + start, tmpl.len) == 0)
+			start += tmpl.len;
+		strbuf_release(&tmpl);
+	}
+
+	/* Check if the rest is just whitespace and Signed-of-by's. */
+	for (i = start; i < sb->len; i++) {
+		nl = memchr(sb->buf + i, '\n', sb->len - i);
+		if (nl)
+			eol = nl - sb->buf;
+		else
+			eol = sb->len;
+
+		if (strlen(sign_off_header) <= eol - i &&
+		    !prefixcmp(sb->buf + i, sign_off_header)) {
+			i = eol;
+			continue;
+		}
+		while (i < eol)
+			if (!isspace(sb->buf[i++]))
+				return 0;
+	}
+
+	return 1;
+}
+
+static void determine_author_info(struct strbuf *sb)
+{
+	char *name, *email, *date;
+
+	name = getenv("GIT_AUTHOR_NAME");
+	email = getenv("GIT_AUTHOR_EMAIL");
+	date = getenv("GIT_AUTHOR_DATE");
+
+	if (use_message) {
+		const char *a, *lb, *rb, *eol;
+
+		a = strstr(use_message_buffer, "\nauthor ");
+		if (!a)
+			die("invalid commit: %s\n", use_message);
+
+		lb = strstr(a + 8, " <");
+		rb = strstr(a + 8, "> ");
+		eol = strchr(a + 8, '\n');
+		if (!lb || !rb || !eol)
+			die("invalid commit: %s\n", use_message);
+
+		name = xstrndup(a + 8, lb - (a + 8));
+		email = xstrndup(lb + 2, rb - (lb + 2));
+		date = xstrndup(rb + 2, eol - (rb + 2));
+	} 
+
+	if (force_author) {
+		const char *lb = strstr(force_author, " <");
+		const char *rb = strchr(force_author, '>');
+
+		if (!lb || !rb)
+			die("malformed --author parameter\n");
+		name = xstrndup(force_author, lb - force_author);
+		email = xstrndup(lb + 2, rb - (lb + 2));
+	}
+
+	strbuf_addf(sb, "author %s\n", fmt_ident(name, email, date, 1));
+}
+
+static int parse_and_validate_options(int argc, const char *argv[])
+{
+	int f = 0;
+
+	argc = parse_options(argc, argv, builtin_commit_options,
+			     builtin_commit_usage, 0);
+
+	if (logfile || message || use_message)
+		no_edit = 1;
+	if (edit_flag)
+		no_edit = 0;
+
+	if (get_sha1("HEAD", head_sha1))
+		initial_commit = 1;
+
+	if (!get_sha1("MERGE_HEAD", merge_head_sha1))
+		in_merge = 1;
+
+	/* Sanity check options */
+	if (amend && initial_commit)
+		die("You have nothing to amend.");
+	if (amend && in_merge)
+		die("You are in the middle of a merger -- cannot amend.");
+
+	if (use_message)
+		f++;
+	if (edit_message)
+		f++;
+	if (logfile)
+		f++;
+	if (f > 1)
+		die("Only one of -c/-C/-F can be used.");
+	if (message && f > 0)
+		die("Option -m cannot be combined with -c/-C/-F.");
+	if (edit_message)
+		use_message = edit_message;
+	if (amend)
+		use_message = "HEAD";
+	if (use_message) {
+		unsigned char sha1[20];
+		static char utf8[] = "UTF-8";
+		const char *out_enc;
+		char *enc, *end;
+		struct commit *commit;
+
+		if (get_sha1(use_message, sha1))
+			die("could not lookup commit %s", use_message);
+		commit = lookup_commit(sha1);
+		if (!commit || parse_commit(commit))
+			die("could not parse commit %s", use_message);
+
+		enc = strstr(commit->buffer, "\nencoding");
+		if (enc) {
+			end = strchr(enc + 10, '\n');
+			enc = xstrndup(enc + 10, end - (enc + 10));
+		} else {
+			enc = utf8;
+		}
+		out_enc = git_commit_encoding ? git_commit_encoding : utf8;
+
+		if (strcmp(out_enc, enc))
+			use_message_buffer =
+				reencode_string(commit->buffer, out_enc, enc);
+
+		/* If we failed to reencode the buffer, just copy it
+		 * byte for byte so the user can try to fix it up.
+		 * This also handles the case where input and output
+		 * encodings are identical. */
+		if (use_message_buffer == NULL)
+			use_message_buffer = xstrdup(commit->buffer);
+		if (enc != utf8)
+			free(enc);
+	}
+
+	if (!!also + !!only + !!all + !!interactive > 1)
+		die("Only one of --include/--only/--all/--interactive can be used.");
+	if (argc == 0 && (also || (only && !amend)))
+		die("No paths with --include/--only does not make sense.");
+	if (argc == 0 && only && amend)
+		only_include_assumed = "Clever... amending the last one with dirty index.";
+	if (argc > 0 && !also && !only) {
+		only_include_assumed = "Explicit paths specified without -i nor -o; assuming --only paths...";
+		also = 0;
+	}
+
+	if (all && argc > 0)
+		die("Paths with -a does not make sense.");
+	else if (interactive && argc > 0)
+		die("Paths with --interactive does not make sense.");
+
+	return argc;
+}
+
+int cmd_status(int argc, const char **argv, const char *prefix)
+{
+	const char *index_file;
+	int commitable;
+
+	git_config(git_status_config);
+
+	argc = parse_and_validate_options(argc, argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	commitable = run_status(stdout, index_file);
+
+	rollback_lock_file(&lock_file);
+
+	return commitable ? 0 : 1;
+}
+
+static int run_hook(const char *index_file, const char *name, const char *arg)
+{
+	struct child_process hook;
+	const char *argv[3], *env[2];
+	char index[PATH_MAX];
+
+	argv[0] = git_path("hooks/%s", name);
+	argv[1] = arg;
+	argv[2] = NULL;
+	snprintf(index, sizeof(index), "GIT_INDEX_FILE=%s", index_file);
+	env[0] = index;
+	env[1] = NULL;
+
+	if (access(argv[0], X_OK) < 0)
+		return 0;
+
+	memset(&hook, 0, sizeof(hook));
+	hook.argv = argv;
+	hook.no_stdin = 1;
+	hook.stdout_to_stderr = 1;
+	hook.env = env;
+
+	return run_command(&hook);
+}
+
+static void print_summary(const char *prefix, const unsigned char *sha1)
+{
+	struct rev_info rev;
+	struct commit *commit;
+
+	commit = lookup_commit(sha1);
+	if (!commit)
+		die("couldn't look up newly created commit\n");
+	if (!commit || parse_commit(commit))
+		die("could not parse newly created commit");
+
+	init_revisions(&rev, prefix);
+	setup_revisions(0, NULL, &rev, NULL);
+
+	rev.abbrev = 0;
+	rev.diff = 1;
+	rev.diffopt.output_format =
+		DIFF_FORMAT_SHORTSTAT | DIFF_FORMAT_SUMMARY;
+
+	rev.verbose_header = 1;
+	rev.show_root_diff = 1;
+	rev.commit_format = get_commit_format("format:%h: %s");
+	rev.always_show_header = 1;
+		
+	printf("Created %scommit ", initial_commit ? "initial " : "");
+
+	log_tree_commit(&rev, commit);
+}
+
+int git_commit_config(const char *k, const char *v)
+{
+	if (!strcmp(k, "commit.template")) {
+		template_file = xstrdup(v);
+		return 0;
+	}
+
+	return git_status_config(k, v);
+}
+
+static const char commit_utf8_warn[] =
+"Warning: commit message does not conform to UTF-8.\n"
+"You may want to amend it after fixing the message, or set the config\n"
+"variable i18n.commitencoding to the encoding your project uses.\n";
+
+int cmd_commit(int argc, const char **argv, const char *prefix)
+{
+	int header_len, parent_count = 0;
+	struct strbuf sb;
+	const char *index_file, *reflog_msg;
+	char *nl, *header_line;
+	unsigned char commit_sha1[20];
+	struct ref_lock *ref_lock;
+
+	git_config(git_commit_config);
+
+	argc = parse_and_validate_options(argc, argv);
+
+	index_file = prepare_index(argv, prefix);
+
+	if (!no_verify && run_hook(index_file, "pre-commit", NULL))
+		exit(1);
+
+	if (!prepare_log_message(index_file) && !in_merge) {
+		run_status(stdout, index_file);
+		unlink(commit_editmsg);
+		return 1;
+	}
+
+	strbuf_init(&sb, 0);
+
+	/* Start building up the commit header */
+	read_cache_from(index_file);
+	active_cache_tree = cache_tree();
+	if (cache_tree_update(active_cache_tree,
+			      active_cache, active_nr, 0, 0) < 0)
+		die("Error building trees");
+	strbuf_addf(&sb, "tree %s\n",
+		    sha1_to_hex(active_cache_tree->sha1));
+
+	/* Determine parents */
+	if (initial_commit) {
+		reflog_msg = "commit (initial)"; 
+		parent_count = 0;
+	} else if (amend) {
+		struct commit_list *c;
+		struct commit *commit;
+
+		reflog_msg = "commit (amend)";
+		commit = lookup_commit(head_sha1);
+		if (!commit || parse_commit(commit))
+			die("could not parse HEAD commit");
+
+		for (c = commit->parents; c; c = c->next)
+			strbuf_addf(&sb, "parent %s\n",
+				      sha1_to_hex(c->item->object.sha1));
+	} else if (in_merge) {
+		struct strbuf m;
+		FILE *fp;
+
+		reflog_msg = "commit (merge)";
+		strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+		strbuf_init(&m, 0);
+		fp = fopen(git_path("MERGE_HEAD"), "r");
+		if (fp == NULL)
+			die("could not open %s for reading: %s",
+			    git_path("MERGE_HEAD"), strerror(errno));
+		while (strbuf_getline(&m, fp, '\n') != EOF)
+			strbuf_addf(&sb, "parent %s\n", m.buf);
+		fclose(fp);
+		strbuf_release(&m);
+	} else {
+		reflog_msg = "commit";
+		strbuf_addf(&sb, "parent %s\n", sha1_to_hex(head_sha1));
+	}
+
+	determine_author_info(&sb);
+	strbuf_addf(&sb, "committer %s\n", git_committer_info(1));
+	if (!is_encoding_utf8(git_commit_encoding))
+		strbuf_addf(&sb, "encoding %s\n", git_commit_encoding);
+	strbuf_addch(&sb, '\n');
+
+	/* Get the commit message and validate it */
+	header_len = sb.len;
+	if (!no_edit) {
+		fprintf(stderr, "launching editor, log %s\n", logfile);
+		launch_editor(git_path(commit_editmsg), &sb);
+	}
+	else if (strbuf_read_file(&sb, git_path(commit_editmsg), 0) < 0)
+		die("could not read commit message\n");
+	if (run_hook(index_file, "commit-msg", commit_editmsg))
+		exit(1);
+	stripspace(&sb, 1);
+	if (sb.len < header_len ||
+	    message_is_empty(&sb, header_len))
+		die("* no commit message?  aborting commit.");
+	strbuf_addch(&sb, '\0');
+	if (is_encoding_utf8(git_commit_encoding) && !is_utf8(sb.buf))
+		fprintf(stderr, commit_utf8_warn);
+
+	if (write_sha1_file(sb.buf, sb.len - 1, commit_type, commit_sha1))
+		die("failed to write commit object");
+		       
+	ref_lock = lock_any_ref_for_update("HEAD",
+					   initial_commit ? NULL : head_sha1,
+					   0);
+
+	nl = strchr(sb.buf + header_len, '\n');
+	header_line = xstrndup(sb.buf + header_len,
+			       nl - (sb.buf + header_len));
+	strbuf_release(&sb);
+	strbuf_addf(&sb, "%s: %s\n", reflog_msg, header_line);
+	strbuf_addch(&sb, '\0');
+	free(header_line);
+
+	if (!ref_lock)
+		die("cannot lock HEAD ref");
+	if (write_ref_sha1(ref_lock, commit_sha1, sb.buf) < 0)
+		die("cannot update HEAD ref");
+
+	unlink(git_path("MERGE_HEAD"));
+	unlink(git_path("MERGE_MSG"));
+
+	if (lock_file.filename[0] && commit_locked_index(&lock_file))
+		die("failed to write new index");
+
+	rerere();
+
+	run_hook(index_file, "post-commit", NULL);
+
+	if (!quiet)
+		print_summary(prefix, commit_sha1);
+
+	return 0;
+}
diff --git a/builtin.h b/builtin.h
index 2335c01..3d2de27 100644
--- a/builtin.h
+++ b/builtin.h
@@ -24,6 +24,7 @@ extern int cmd_check_attr(int argc, const char **argv, const char *prefix);
 extern int cmd_check_ref_format(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry(int argc, const char **argv, const char *prefix);
 extern int cmd_cherry_pick(int argc, const char **argv, const char *prefix);
+extern int cmd_commit(int argc, const char **argv, const char *prefix);
 extern int cmd_commit_tree(int argc, const char **argv, const char *prefix);
 extern int cmd_count_objects(int argc, const char **argv, const char *prefix);
 extern int cmd_describe(int argc, const char **argv, const char *prefix);
@@ -69,11 +70,11 @@ extern int cmd_rev_list(int argc, const char **argv, const char *prefix);
 extern int cmd_rev_parse(int argc, const char **argv, const char *prefix);
 extern int cmd_revert(int argc, const char **argv, const char *prefix);
 extern int cmd_rm(int argc, const char **argv, const char *prefix);
-extern int cmd_runstatus(int argc, const char **argv, const char *prefix);
 extern int cmd_send_pack(int argc, const char **argv, const char *prefix);
 extern int cmd_shortlog(int argc, const char **argv, const char *prefix);
 extern int cmd_show(int argc, const char **argv, const char *prefix);
 extern int cmd_show_branch(int argc, const char **argv, const char *prefix);
+extern int cmd_status(int argc, const char **argv, const char *prefix);
 extern int cmd_stripspace(int argc, const char **argv, const char *prefix);
 extern int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
 extern int cmd_tag(int argc, const char **argv, const char *prefix);
diff --git a/contrib/examples/git-commit.sh b/contrib/examples/git-commit.sh
new file mode 100755
index 0000000..fcb8443
--- /dev/null
+++ b/contrib/examples/git-commit.sh
@@ -0,0 +1,628 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Linus Torvalds
+# Copyright (c) 2006 Junio C Hamano
+
+USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
+SUBDIRECTORY_OK=Yes
+. git-sh-setup
+require_work_tree
+
+git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
+
+case "$0" in
+*status)
+	status_only=t
+	;;
+*commit)
+	status_only=
+	;;
+esac
+
+refuse_partial () {
+	echo >&2 "$1"
+	echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
+	exit 1
+}
+
+TMP_INDEX=
+THIS_INDEX="$GIT_DIR/index"
+NEXT_INDEX="$GIT_DIR/next-index$$"
+rm -f "$NEXT_INDEX"
+save_index () {
+	cp -p "$THIS_INDEX" "$NEXT_INDEX"
+}
+
+run_status () {
+	# If TMP_INDEX is defined, that means we are doing
+	# "--only" partial commit, and that index file is used
+	# to build the tree for the commit.  Otherwise, if
+	# NEXT_INDEX exists, that is the index file used to
+	# make the commit.  Otherwise we are using as-is commit
+	# so the regular index file is what we use to compare.
+	if test '' != "$TMP_INDEX"
+	then
+		GIT_INDEX_FILE="$TMP_INDEX"
+		export GIT_INDEX_FILE
+	elif test -f "$NEXT_INDEX"
+	then
+		GIT_INDEX_FILE="$NEXT_INDEX"
+		export GIT_INDEX_FILE
+	fi
+
+	if test "$status_only" = "t" -o "$use_status_color" = "t"; then
+		color=
+	else
+		color=--nocolor
+	fi
+	git runstatus ${color} \
+		${verbose:+--verbose} \
+		${amend:+--amend} \
+		${untracked_files:+--untracked}
+}
+
+trap '
+	test -z "$TMP_INDEX" || {
+		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
+	}
+	rm -f "$NEXT_INDEX"
+' 0
+
+################################################################
+# Command line argument parsing and sanity checking
+
+all=
+also=
+interactive=
+only=
+logfile=
+use_commit=
+amend=
+edit_flag=
+no_edit=
+log_given=
+log_message=
+verify=t
+quiet=
+verbose=
+signoff=
+force_author=
+only_include_assumed=
+untracked_files=
+templatefile="`git config commit.template`"
+while test $# != 0
+do
+	case "$1" in
+	-F|--F|-f|--f|--fi|--fil|--file)
+		case "$#" in 1) usage ;; esac
+		shift
+		no_edit=t
+		log_given=t$log_given
+		logfile="$1"
+		;;
+	-F*|-f*)
+		no_edit=t
+		log_given=t$log_given
+		logfile="${1#-[Ff]}"
+		;;
+	--F=*|--f=*|--fi=*|--fil=*|--file=*)
+		no_edit=t
+		log_given=t$log_given
+		logfile="${1#*=}"
+		;;
+	-a|--a|--al|--all)
+		all=t
+		;;
+	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
+		force_author="${1#*=}"
+		;;
+	--au|--aut|--auth|--autho|--author)
+		case "$#" in 1) usage ;; esac
+		shift
+		force_author="$1"
+		;;
+	-e|--e|--ed|--edi|--edit)
+		edit_flag=t
+		;;
+	-i|--i|--in|--inc|--incl|--inclu|--includ|--include)
+		also=t
+		;;
+	--int|--inte|--inter|--intera|--interac|--interact|--interacti|\
+	--interactiv|--interactive)
+		interactive=t
+		;;
+	-o|--o|--on|--onl|--only)
+		only=t
+		;;
+	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=m$log_given
+		log_message="${log_message:+${log_message}
+
+}$1"
+		no_edit=t
+		;;
+	-m*)
+		log_given=m$log_given
+		log_message="${log_message:+${log_message}
+
+}${1#-m}"
+		no_edit=t
+		;;
+	--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
+		log_given=m$log_given
+		log_message="${log_message:+${log_message}
+
+}${1#*=}"
+		no_edit=t
+		;;
+	-n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
+	--no-verify)
+		verify=
+		;;
+	--a|--am|--ame|--amen|--amend)
+		amend=t
+		use_commit=HEAD
+		;;
+	-c)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=
+		;;
+	--ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
+	--reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
+	--reedit-messag=*|--reedit-message=*)
+		log_given=t$log_given
+		use_commit="${1#*=}"
+		no_edit=
+		;;
+	--ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
+	--reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
+	--reedit-message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=
+		;;
+	-C)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=t
+		;;
+	--reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
+	--reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
+	--reuse-message=*)
+		log_given=t$log_given
+		use_commit="${1#*=}"
+		no_edit=t
+		;;
+	--reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
+	--reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
+		case "$#" in 1) usage ;; esac
+		shift
+		log_given=t$log_given
+		use_commit="$1"
+		no_edit=t
+		;;
+	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
+		signoff=t
+		;;
+	-t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
+		case "$#" in 1) usage ;; esac
+		shift
+		templatefile="$1"
+		no_edit=
+		;;
+	-q|--q|--qu|--qui|--quie|--quiet)
+		quiet=t
+		;;
+	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
+		verbose=t
+		;;
+	-u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
+	--untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
+	--untracked-file|--untracked-files)
+		untracked_files=t
+		;;
+	--)
+		shift
+		break
+		;;
+	-*)
+		usage
+		;;
+	*)
+		break
+		;;
+	esac
+	shift
+done
+case "$edit_flag" in t) no_edit= ;; esac
+
+################################################################
+# Sanity check options
+
+case "$amend,$initial_commit" in
+t,t)
+	die "You do not have anything to amend." ;;
+t,)
+	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+		die "You are in the middle of a merge -- cannot amend."
+	fi ;;
+esac
+
+case "$log_given" in
+tt*)
+	die "Only one of -c/-C/-F can be used." ;;
+*tm*|*mt*)
+	die "Option -m cannot be combined with -c/-C/-F." ;;
+esac
+
+case "$#,$also,$only,$amend" in
+*,t,t,*)
+	die "Only one of --include/--only can be used." ;;
+0,t,,* | 0,,t,)
+	die "No paths with --include/--only does not make sense." ;;
+0,,t,t)
+	only_include_assumed="# Clever... amending the last one with dirty index." ;;
+0,,,*)
+	;;
+*,,,*)
+	only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
+	also=
+	;;
+esac
+unset only
+case "$all,$interactive,$also,$#" in
+*t,*t,*)
+	die "Cannot use -a, --interactive or -i at the same time." ;;
+t,,[1-9]*)
+	die "Paths with -a does not make sense." ;;
+,t,[1-9]*)
+	die "Paths with --interactive does not make sense." ;;
+,,t,0)
+	die "No paths with -i does not make sense." ;;
+esac
+
+if test ! -z "$templatefile" -a -z "$log_given"
+then
+	if test ! -f "$templatefile"
+	then
+		die "Commit template file does not exist."
+	fi
+fi
+
+################################################################
+# Prepare index to have a tree to be committed
+
+case "$all,$also" in
+t,)
+	if test ! -f "$THIS_INDEX"
+	then
+		die 'nothing to commit (use "git add file1 file2" to include for commit)'
+	fi
+	save_index &&
+	(
+		cd_to_toplevel &&
+		GIT_INDEX_FILE="$NEXT_INDEX" &&
+		export GIT_INDEX_FILE &&
+		git diff-files --name-only -z |
+		git update-index --remove -z --stdin
+	) || exit
+	;;
+,t)
+	save_index &&
+	git ls-files --error-unmatch -- "$@" >/dev/null || exit
+
+	git diff-files --name-only -z -- "$@"  |
+	(
+		cd_to_toplevel &&
+		GIT_INDEX_FILE="$NEXT_INDEX" &&
+		export GIT_INDEX_FILE &&
+		git update-index --remove -z --stdin
+	) || exit
+	;;
+,)
+	if test "$interactive" = t; then
+		git add --interactive || exit
+	fi
+	case "$#" in
+	0)
+		;; # commit as-is
+	*)
+		if test -f "$GIT_DIR/MERGE_HEAD"
+		then
+			refuse_partial "Cannot do a partial commit during a merge."
+		fi
+
+		TMP_INDEX="$GIT_DIR/tmp-index$$"
+		W=
+		test -z "$initial_commit" && W=--with-tree=HEAD
+		commit_only=`git ls-files --error-unmatch $W -- "$@"` || exit
+
+		# Build a temporary index and update the real index
+		# the same way.
+		if test -z "$initial_commit"
+		then
+			GIT_INDEX_FILE="$THIS_INDEX" \
+			git read-tree --index-output="$TMP_INDEX" -i -m HEAD
+		else
+			rm -f "$TMP_INDEX"
+		fi || exit
+
+		printf '%s\n' "$commit_only" |
+		GIT_INDEX_FILE="$TMP_INDEX" \
+		git update-index --add --remove --stdin &&
+
+		save_index &&
+		printf '%s\n' "$commit_only" |
+		(
+			GIT_INDEX_FILE="$NEXT_INDEX"
+			export GIT_INDEX_FILE
+			git update-index --add --remove --stdin
+		) || exit
+		;;
+	esac
+	;;
+esac
+
+################################################################
+# If we do as-is commit, the index file will be THIS_INDEX,
+# otherwise NEXT_INDEX after we make this commit.  We leave
+# the index as is if we abort.
+
+if test -f "$NEXT_INDEX"
+then
+	USE_INDEX="$NEXT_INDEX"
+else
+	USE_INDEX="$THIS_INDEX"
+fi
+
+case "$status_only" in
+t)
+	# This will silently fail in a read-only repository, which is
+	# what we want.
+	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
+	run_status
+	exit $?
+	;;
+'')
+	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
+	;;
+esac
+
+################################################################
+# Grab commit message, write out tree and make commit.
+
+if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
+then
+    GIT_INDEX_FILE="${TMP_INDEX:-${USE_INDEX}}" "$GIT_DIR"/hooks/pre-commit \
+    || exit
+fi
+
+if test "$log_message" != ''
+then
+	printf '%s\n' "$log_message"
+elif test "$logfile" != ""
+then
+	if test "$logfile" = -
+	then
+		test -t 0 &&
+		echo >&2 "(reading log message from standard input)"
+		cat
+	else
+		cat <"$logfile"
+	fi
+elif test "$use_commit" != ""
+then
+	encoding=$(git config i18n.commitencoding || echo UTF-8)
+	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
+	sed -e '1,/^$/d' -e 's/^    //'
+elif test -f "$GIT_DIR/MERGE_MSG"
+then
+	cat "$GIT_DIR/MERGE_MSG"
+elif test -f "$GIT_DIR/SQUASH_MSG"
+then
+	cat "$GIT_DIR/SQUASH_MSG"
+elif test "$templatefile" != ""
+then
+	cat "$templatefile"
+fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
+
+case "$signoff" in
+t)
+	sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
+		s/>.*/>/
+		s/^/Signed-off-by: /
+		')
+	blank_before_signoff=
+	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+	grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
+'
+	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
+	grep "$sign"$ >/dev/null ||
+	printf '%s%s\n' "$blank_before_signoff" "$sign" \
+		>>"$GIT_DIR"/COMMIT_EDITMSG
+	;;
+esac
+
+if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
+	echo "#"
+	echo "# It looks like you may be committing a MERGE."
+	echo "# If this is not correct, please remove the file"
+	printf '%s\n' "#	$GIT_DIR/MERGE_HEAD"
+	echo "# and try again"
+	echo "#"
+fi >>"$GIT_DIR"/COMMIT_EDITMSG
+
+# Author
+if test '' != "$use_commit"
+then
+	eval "$(get_author_ident_from_commit "$use_commit")"
+	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
+fi
+if test '' != "$force_author"
+then
+	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
+	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
+	test '' != "$GIT_AUTHOR_NAME" &&
+	test '' != "$GIT_AUTHOR_EMAIL" ||
+	die "malformed --author parameter"
+	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
+fi
+
+PARENTS="-p HEAD"
+if test -z "$initial_commit"
+then
+	rloga='commit'
+	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
+		rloga='commit (merge)'
+		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
+	elif test -n "$amend"; then
+		rloga='commit (amend)'
+		PARENTS=$(git cat-file commit HEAD |
+			sed -n -e '/^$/q' -e 's/^parent /-p /p')
+	fi
+	current="$(git rev-parse --verify HEAD)"
+else
+	if [ -z "$(git ls-files)" ]; then
+		echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
+		exit 1
+	fi
+	PARENTS=""
+	rloga='commit (initial)'
+	current=''
+fi
+set_reflog_action "$rloga"
+
+if test -z "$no_edit"
+then
+	{
+		echo ""
+		echo "# Please enter the commit message for your changes."
+		echo "# (Comment lines starting with '#' will not be included)"
+		test -z "$only_include_assumed" || echo "$only_include_assumed"
+		run_status
+	} >>"$GIT_DIR"/COMMIT_EDITMSG
+else
+	# we need to check if there is anything to commit
+	run_status >/dev/null
+fi
+if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ]
+then
+	rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+	use_status_color=t
+	run_status
+	exit 1
+fi
+
+case "$no_edit" in
+'')
+	git-var GIT_AUTHOR_IDENT > /dev/null  || die
+	git-var GIT_COMMITTER_IDENT > /dev/null  || die
+	git_editor "$GIT_DIR/COMMIT_EDITMSG"
+	;;
+esac
+
+case "$verify" in
+t)
+	if test -x "$GIT_DIR"/hooks/commit-msg
+	then
+		"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
+	fi
+esac
+
+if test -z "$no_edit"
+then
+    sed -e '
+        /^diff --git a\/.*/{
+	    s///
+	    q
+	}
+	/^#/d
+    ' "$GIT_DIR"/COMMIT_EDITMSG
+else
+    cat "$GIT_DIR"/COMMIT_EDITMSG
+fi |
+git stripspace >"$GIT_DIR"/COMMIT_MSG
+
+# Test whether the commit message has any content we didn't supply.
+have_commitmsg=
+grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
+	git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
+
+# Is the commit message totally empty?
+if test -s "$GIT_DIR"/COMMIT_BAREMSG
+then
+	if test "$templatefile" != ""
+	then
+		# Test whether this is just the unaltered template.
+		if cnt=`sed -e '/^#/d' < "$templatefile" |
+			git stripspace |
+			diff "$GIT_DIR"/COMMIT_BAREMSG - |
+			wc -l` &&
+		   test 0 -lt $cnt
+		then
+			have_commitmsg=t
+		fi
+	else
+		# No template, so the content in the commit message must
+		# have come from the user.
+		have_commitmsg=t
+	fi
+fi
+
+rm -f "$GIT_DIR"/COMMIT_BAREMSG
+
+if test "$have_commitmsg" = "t"
+then
+	if test -z "$TMP_INDEX"
+	then
+		tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
+	else
+		tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
+		rm -f "$TMP_INDEX"
+	fi &&
+	commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
+	rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
+	git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
+	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
+	if test -f "$NEXT_INDEX"
+	then
+		mv "$NEXT_INDEX" "$THIS_INDEX"
+	else
+		: ;# happy
+	fi
+else
+	echo >&2 "* no commit message?  aborting commit."
+	false
+fi
+ret="$?"
+rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
+
+cd_to_toplevel
+
+git rerere
+
+if test "$ret" = 0
+then
+	git gc --auto
+	if test -x "$GIT_DIR"/hooks/post-commit
+	then
+		"$GIT_DIR"/hooks/post-commit
+	fi
+	if test -z "$quiet"
+	then
+		commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
+		       --summary --root HEAD --`
+		echo "Created${initial_commit:+ initial} commit $commit"
+	fi
+fi
+
+exit "$ret"
diff --git a/git-commit.sh b/git-commit.sh
deleted file mode 100755
index fcb8443..0000000
--- a/git-commit.sh
+++ /dev/null
@@ -1,628 +0,0 @@
-#!/bin/sh
-#
-# Copyright (c) 2005 Linus Torvalds
-# Copyright (c) 2006 Junio C Hamano
-
-USAGE='[-a | --interactive] [-s] [-v] [--no-verify] [-m <message> | -F <logfile> | (-C|-c) <commit> | --amend] [-u] [-e] [--author <author>] [--template <file>] [[-i | -o] <path>...]'
-SUBDIRECTORY_OK=Yes
-. git-sh-setup
-require_work_tree
-
-git rev-parse --verify HEAD >/dev/null 2>&1 || initial_commit=t
-
-case "$0" in
-*status)
-	status_only=t
-	;;
-*commit)
-	status_only=
-	;;
-esac
-
-refuse_partial () {
-	echo >&2 "$1"
-	echo >&2 "You might have meant to say 'git commit -i paths...', perhaps?"
-	exit 1
-}
-
-TMP_INDEX=
-THIS_INDEX="$GIT_DIR/index"
-NEXT_INDEX="$GIT_DIR/next-index$$"
-rm -f "$NEXT_INDEX"
-save_index () {
-	cp -p "$THIS_INDEX" "$NEXT_INDEX"
-}
-
-run_status () {
-	# If TMP_INDEX is defined, that means we are doing
-	# "--only" partial commit, and that index file is used
-	# to build the tree for the commit.  Otherwise, if
-	# NEXT_INDEX exists, that is the index file used to
-	# make the commit.  Otherwise we are using as-is commit
-	# so the regular index file is what we use to compare.
-	if test '' != "$TMP_INDEX"
-	then
-		GIT_INDEX_FILE="$TMP_INDEX"
-		export GIT_INDEX_FILE
-	elif test -f "$NEXT_INDEX"
-	then
-		GIT_INDEX_FILE="$NEXT_INDEX"
-		export GIT_INDEX_FILE
-	fi
-
-	if test "$status_only" = "t" -o "$use_status_color" = "t"; then
-		color=
-	else
-		color=--nocolor
-	fi
-	git runstatus ${color} \
-		${verbose:+--verbose} \
-		${amend:+--amend} \
-		${untracked_files:+--untracked}
-}
-
-trap '
-	test -z "$TMP_INDEX" || {
-		test -f "$TMP_INDEX" && rm -f "$TMP_INDEX"
-	}
-	rm -f "$NEXT_INDEX"
-' 0
-
-################################################################
-# Command line argument parsing and sanity checking
-
-all=
-also=
-interactive=
-only=
-logfile=
-use_commit=
-amend=
-edit_flag=
-no_edit=
-log_given=
-log_message=
-verify=t
-quiet=
-verbose=
-signoff=
-force_author=
-only_include_assumed=
-untracked_files=
-templatefile="`git config commit.template`"
-while test $# != 0
-do
-	case "$1" in
-	-F|--F|-f|--f|--fi|--fil|--file)
-		case "$#" in 1) usage ;; esac
-		shift
-		no_edit=t
-		log_given=t$log_given
-		logfile="$1"
-		;;
-	-F*|-f*)
-		no_edit=t
-		log_given=t$log_given
-		logfile="${1#-[Ff]}"
-		;;
-	--F=*|--f=*|--fi=*|--fil=*|--file=*)
-		no_edit=t
-		log_given=t$log_given
-		logfile="${1#*=}"
-		;;
-	-a|--a|--al|--all)
-		all=t
-		;;
-	--au=*|--aut=*|--auth=*|--autho=*|--author=*)
-		force_author="${1#*=}"
-		;;
-	--au|--aut|--auth|--autho|--author)
-		case "$#" in 1) usage ;; esac
-		shift
-		force_author="$1"
-		;;
-	-e|--e|--ed|--edi|--edit)
-		edit_flag=t
-		;;
-	-i|--i|--in|--inc|--incl|--inclu|--includ|--include)
-		also=t
-		;;
-	--int|--inte|--inter|--intera|--interac|--interact|--interacti|\
-	--interactiv|--interactive)
-		interactive=t
-		;;
-	-o|--o|--on|--onl|--only)
-		only=t
-		;;
-	-m|--m|--me|--mes|--mess|--messa|--messag|--message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=m$log_given
-		log_message="${log_message:+${log_message}
-
-}$1"
-		no_edit=t
-		;;
-	-m*)
-		log_given=m$log_given
-		log_message="${log_message:+${log_message}
-
-}${1#-m}"
-		no_edit=t
-		;;
-	--m=*|--me=*|--mes=*|--mess=*|--messa=*|--messag=*|--message=*)
-		log_given=m$log_given
-		log_message="${log_message:+${log_message}
-
-}${1#*=}"
-		no_edit=t
-		;;
-	-n|--n|--no|--no-|--no-v|--no-ve|--no-ver|--no-veri|--no-verif|\
-	--no-verify)
-		verify=
-		;;
-	--a|--am|--ame|--amen|--amend)
-		amend=t
-		use_commit=HEAD
-		;;
-	-c)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		;;
-	--ree=*|--reed=*|--reedi=*|--reedit=*|--reedit-=*|--reedit-m=*|\
-	--reedit-me=*|--reedit-mes=*|--reedit-mess=*|--reedit-messa=*|\
-	--reedit-messag=*|--reedit-message=*)
-		log_given=t$log_given
-		use_commit="${1#*=}"
-		no_edit=
-		;;
-	--ree|--reed|--reedi|--reedit|--reedit-|--reedit-m|--reedit-me|\
-	--reedit-mes|--reedit-mess|--reedit-messa|--reedit-messag|\
-	--reedit-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=
-		;;
-	-C)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		;;
-	--reu=*|--reus=*|--reuse=*|--reuse-=*|--reuse-m=*|--reuse-me=*|\
-	--reuse-mes=*|--reuse-mess=*|--reuse-messa=*|--reuse-messag=*|\
-	--reuse-message=*)
-		log_given=t$log_given
-		use_commit="${1#*=}"
-		no_edit=t
-		;;
-	--reu|--reus|--reuse|--reuse-|--reuse-m|--reuse-me|--reuse-mes|\
-	--reuse-mess|--reuse-messa|--reuse-messag|--reuse-message)
-		case "$#" in 1) usage ;; esac
-		shift
-		log_given=t$log_given
-		use_commit="$1"
-		no_edit=t
-		;;
-	-s|--s|--si|--sig|--sign|--signo|--signof|--signoff)
-		signoff=t
-		;;
-	-t|--t|--te|--tem|--temp|--templ|--templa|--templat|--template)
-		case "$#" in 1) usage ;; esac
-		shift
-		templatefile="$1"
-		no_edit=
-		;;
-	-q|--q|--qu|--qui|--quie|--quiet)
-		quiet=t
-		;;
-	-v|--v|--ve|--ver|--verb|--verbo|--verbos|--verbose)
-		verbose=t
-		;;
-	-u|--u|--un|--unt|--untr|--untra|--untrac|--untrack|--untracke|\
-	--untracked|--untracked-|--untracked-f|--untracked-fi|--untracked-fil|\
-	--untracked-file|--untracked-files)
-		untracked_files=t
-		;;
-	--)
-		shift
-		break
-		;;
-	-*)
-		usage
-		;;
-	*)
-		break
-		;;
-	esac
-	shift
-done
-case "$edit_flag" in t) no_edit= ;; esac
-
-################################################################
-# Sanity check options
-
-case "$amend,$initial_commit" in
-t,t)
-	die "You do not have anything to amend." ;;
-t,)
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		die "You are in the middle of a merge -- cannot amend."
-	fi ;;
-esac
-
-case "$log_given" in
-tt*)
-	die "Only one of -c/-C/-F can be used." ;;
-*tm*|*mt*)
-	die "Option -m cannot be combined with -c/-C/-F." ;;
-esac
-
-case "$#,$also,$only,$amend" in
-*,t,t,*)
-	die "Only one of --include/--only can be used." ;;
-0,t,,* | 0,,t,)
-	die "No paths with --include/--only does not make sense." ;;
-0,,t,t)
-	only_include_assumed="# Clever... amending the last one with dirty index." ;;
-0,,,*)
-	;;
-*,,,*)
-	only_include_assumed="# Explicit paths specified without -i nor -o; assuming --only paths..."
-	also=
-	;;
-esac
-unset only
-case "$all,$interactive,$also,$#" in
-*t,*t,*)
-	die "Cannot use -a, --interactive or -i at the same time." ;;
-t,,[1-9]*)
-	die "Paths with -a does not make sense." ;;
-,t,[1-9]*)
-	die "Paths with --interactive does not make sense." ;;
-,,t,0)
-	die "No paths with -i does not make sense." ;;
-esac
-
-if test ! -z "$templatefile" -a -z "$log_given"
-then
-	if test ! -f "$templatefile"
-	then
-		die "Commit template file does not exist."
-	fi
-fi
-
-################################################################
-# Prepare index to have a tree to be committed
-
-case "$all,$also" in
-t,)
-	if test ! -f "$THIS_INDEX"
-	then
-		die 'nothing to commit (use "git add file1 file2" to include for commit)'
-	fi
-	save_index &&
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git diff-files --name-only -z |
-		git update-index --remove -z --stdin
-	) || exit
-	;;
-,t)
-	save_index &&
-	git ls-files --error-unmatch -- "$@" >/dev/null || exit
-
-	git diff-files --name-only -z -- "$@"  |
-	(
-		cd_to_toplevel &&
-		GIT_INDEX_FILE="$NEXT_INDEX" &&
-		export GIT_INDEX_FILE &&
-		git update-index --remove -z --stdin
-	) || exit
-	;;
-,)
-	if test "$interactive" = t; then
-		git add --interactive || exit
-	fi
-	case "$#" in
-	0)
-		;; # commit as-is
-	*)
-		if test -f "$GIT_DIR/MERGE_HEAD"
-		then
-			refuse_partial "Cannot do a partial commit during a merge."
-		fi
-
-		TMP_INDEX="$GIT_DIR/tmp-index$$"
-		W=
-		test -z "$initial_commit" && W=--with-tree=HEAD
-		commit_only=`git ls-files --error-unmatch $W -- "$@"` || exit
-
-		# Build a temporary index and update the real index
-		# the same way.
-		if test -z "$initial_commit"
-		then
-			GIT_INDEX_FILE="$THIS_INDEX" \
-			git read-tree --index-output="$TMP_INDEX" -i -m HEAD
-		else
-			rm -f "$TMP_INDEX"
-		fi || exit
-
-		printf '%s\n' "$commit_only" |
-		GIT_INDEX_FILE="$TMP_INDEX" \
-		git update-index --add --remove --stdin &&
-
-		save_index &&
-		printf '%s\n' "$commit_only" |
-		(
-			GIT_INDEX_FILE="$NEXT_INDEX"
-			export GIT_INDEX_FILE
-			git update-index --add --remove --stdin
-		) || exit
-		;;
-	esac
-	;;
-esac
-
-################################################################
-# If we do as-is commit, the index file will be THIS_INDEX,
-# otherwise NEXT_INDEX after we make this commit.  We leave
-# the index as is if we abort.
-
-if test -f "$NEXT_INDEX"
-then
-	USE_INDEX="$NEXT_INDEX"
-else
-	USE_INDEX="$THIS_INDEX"
-fi
-
-case "$status_only" in
-t)
-	# This will silently fail in a read-only repository, which is
-	# what we want.
-	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --unmerged --refresh
-	run_status
-	exit $?
-	;;
-'')
-	GIT_INDEX_FILE="$USE_INDEX" git update-index -q --refresh || exit
-	;;
-esac
-
-################################################################
-# Grab commit message, write out tree and make commit.
-
-if test t = "$verify" && test -x "$GIT_DIR"/hooks/pre-commit
-then
-    GIT_INDEX_FILE="${TMP_INDEX:-${USE_INDEX}}" "$GIT_DIR"/hooks/pre-commit \
-    || exit
-fi
-
-if test "$log_message" != ''
-then
-	printf '%s\n' "$log_message"
-elif test "$logfile" != ""
-then
-	if test "$logfile" = -
-	then
-		test -t 0 &&
-		echo >&2 "(reading log message from standard input)"
-		cat
-	else
-		cat <"$logfile"
-	fi
-elif test "$use_commit" != ""
-then
-	encoding=$(git config i18n.commitencoding || echo UTF-8)
-	git show -s --pretty=raw --encoding="$encoding" "$use_commit" |
-	sed -e '1,/^$/d' -e 's/^    //'
-elif test -f "$GIT_DIR/MERGE_MSG"
-then
-	cat "$GIT_DIR/MERGE_MSG"
-elif test -f "$GIT_DIR/SQUASH_MSG"
-then
-	cat "$GIT_DIR/SQUASH_MSG"
-elif test "$templatefile" != ""
-then
-	cat "$templatefile"
-fi | git stripspace >"$GIT_DIR"/COMMIT_EDITMSG
-
-case "$signoff" in
-t)
-	sign=$(git-var GIT_COMMITTER_IDENT | sed -e '
-		s/>.*/>/
-		s/^/Signed-off-by: /
-		')
-	blank_before_signoff=
-	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-	grep 'Signed-off-by:' >/dev/null || blank_before_signoff='
-'
-	tail -n 1 "$GIT_DIR"/COMMIT_EDITMSG |
-	grep "$sign"$ >/dev/null ||
-	printf '%s%s\n' "$blank_before_signoff" "$sign" \
-		>>"$GIT_DIR"/COMMIT_EDITMSG
-	;;
-esac
-
-if test -f "$GIT_DIR/MERGE_HEAD" && test -z "$no_edit"; then
-	echo "#"
-	echo "# It looks like you may be committing a MERGE."
-	echo "# If this is not correct, please remove the file"
-	printf '%s\n' "#	$GIT_DIR/MERGE_HEAD"
-	echo "# and try again"
-	echo "#"
-fi >>"$GIT_DIR"/COMMIT_EDITMSG
-
-# Author
-if test '' != "$use_commit"
-then
-	eval "$(get_author_ident_from_commit "$use_commit")"
-	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL GIT_AUTHOR_DATE
-fi
-if test '' != "$force_author"
-then
-	GIT_AUTHOR_NAME=`expr "z$force_author" : 'z\(.*[^ ]\) *<.*'` &&
-	GIT_AUTHOR_EMAIL=`expr "z$force_author" : '.*\(<.*\)'` &&
-	test '' != "$GIT_AUTHOR_NAME" &&
-	test '' != "$GIT_AUTHOR_EMAIL" ||
-	die "malformed --author parameter"
-	export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
-fi
-
-PARENTS="-p HEAD"
-if test -z "$initial_commit"
-then
-	rloga='commit'
-	if [ -f "$GIT_DIR/MERGE_HEAD" ]; then
-		rloga='commit (merge)'
-		PARENTS="-p HEAD "`sed -e 's/^/-p /' "$GIT_DIR/MERGE_HEAD"`
-	elif test -n "$amend"; then
-		rloga='commit (amend)'
-		PARENTS=$(git cat-file commit HEAD |
-			sed -n -e '/^$/q' -e 's/^parent /-p /p')
-	fi
-	current="$(git rev-parse --verify HEAD)"
-else
-	if [ -z "$(git ls-files)" ]; then
-		echo >&2 'nothing to commit (use "git add file1 file2" to include for commit)'
-		exit 1
-	fi
-	PARENTS=""
-	rloga='commit (initial)'
-	current=''
-fi
-set_reflog_action "$rloga"
-
-if test -z "$no_edit"
-then
-	{
-		echo ""
-		echo "# Please enter the commit message for your changes."
-		echo "# (Comment lines starting with '#' will not be included)"
-		test -z "$only_include_assumed" || echo "$only_include_assumed"
-		run_status
-	} >>"$GIT_DIR"/COMMIT_EDITMSG
-else
-	# we need to check if there is anything to commit
-	run_status >/dev/null
-fi
-if [ "$?" != "0" -a ! -f "$GIT_DIR/MERGE_HEAD" ]
-then
-	rm -f "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-	use_status_color=t
-	run_status
-	exit 1
-fi
-
-case "$no_edit" in
-'')
-	git-var GIT_AUTHOR_IDENT > /dev/null  || die
-	git-var GIT_COMMITTER_IDENT > /dev/null  || die
-	git_editor "$GIT_DIR/COMMIT_EDITMSG"
-	;;
-esac
-
-case "$verify" in
-t)
-	if test -x "$GIT_DIR"/hooks/commit-msg
-	then
-		"$GIT_DIR"/hooks/commit-msg "$GIT_DIR"/COMMIT_EDITMSG || exit
-	fi
-esac
-
-if test -z "$no_edit"
-then
-    sed -e '
-        /^diff --git a\/.*/{
-	    s///
-	    q
-	}
-	/^#/d
-    ' "$GIT_DIR"/COMMIT_EDITMSG
-else
-    cat "$GIT_DIR"/COMMIT_EDITMSG
-fi |
-git stripspace >"$GIT_DIR"/COMMIT_MSG
-
-# Test whether the commit message has any content we didn't supply.
-have_commitmsg=
-grep -v -i '^Signed-off-by' "$GIT_DIR"/COMMIT_MSG |
-	git stripspace > "$GIT_DIR"/COMMIT_BAREMSG
-
-# Is the commit message totally empty?
-if test -s "$GIT_DIR"/COMMIT_BAREMSG
-then
-	if test "$templatefile" != ""
-	then
-		# Test whether this is just the unaltered template.
-		if cnt=`sed -e '/^#/d' < "$templatefile" |
-			git stripspace |
-			diff "$GIT_DIR"/COMMIT_BAREMSG - |
-			wc -l` &&
-		   test 0 -lt $cnt
-		then
-			have_commitmsg=t
-		fi
-	else
-		# No template, so the content in the commit message must
-		# have come from the user.
-		have_commitmsg=t
-	fi
-fi
-
-rm -f "$GIT_DIR"/COMMIT_BAREMSG
-
-if test "$have_commitmsg" = "t"
-then
-	if test -z "$TMP_INDEX"
-	then
-		tree=$(GIT_INDEX_FILE="$USE_INDEX" git write-tree)
-	else
-		tree=$(GIT_INDEX_FILE="$TMP_INDEX" git write-tree) &&
-		rm -f "$TMP_INDEX"
-	fi &&
-	commit=$(git commit-tree $tree $PARENTS <"$GIT_DIR/COMMIT_MSG") &&
-	rlogm=$(sed -e 1q "$GIT_DIR"/COMMIT_MSG) &&
-	git update-ref -m "$GIT_REFLOG_ACTION: $rlogm" HEAD $commit "$current" &&
-	rm -f -- "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/MERGE_MSG" &&
-	if test -f "$NEXT_INDEX"
-	then
-		mv "$NEXT_INDEX" "$THIS_INDEX"
-	else
-		: ;# happy
-	fi
-else
-	echo >&2 "* no commit message?  aborting commit."
-	false
-fi
-ret="$?"
-rm -f "$GIT_DIR/COMMIT_MSG" "$GIT_DIR/COMMIT_EDITMSG" "$GIT_DIR/SQUASH_MSG"
-
-cd_to_toplevel
-
-git rerere
-
-if test "$ret" = 0
-then
-	git gc --auto
-	if test -x "$GIT_DIR"/hooks/post-commit
-	then
-		"$GIT_DIR"/hooks/post-commit
-	fi
-	if test -z "$quiet"
-	then
-		commit=`git diff-tree --always --shortstat --pretty="format:%h: %s"\
-		       --summary --root HEAD --`
-		echo "Created${initial_commit:+ initial} commit $commit"
-	fi
-fi
-
-exit "$ret"
diff --git a/git.c b/git.c
index 19a2172..1016e04 100644
--- a/git.c
+++ b/git.c
@@ -298,6 +298,7 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "check-attr", cmd_check_attr, RUN_SETUP | NEED_WORK_TREE },
 		{ "cherry", cmd_cherry, RUN_SETUP },
 		{ "cherry-pick", cmd_cherry_pick, RUN_SETUP | NEED_WORK_TREE },
+		{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
 		{ "commit-tree", cmd_commit_tree, RUN_SETUP },
 		{ "config", cmd_config },
 		{ "count-objects", cmd_count_objects, RUN_SETUP },
@@ -347,11 +348,11 @@ static void handle_internal_command(int argc, const char **argv)
 		{ "rev-parse", cmd_rev_parse, RUN_SETUP },
 		{ "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
 		{ "rm", cmd_rm, RUN_SETUP | NEED_WORK_TREE },
-		{ "runstatus", cmd_runstatus, RUN_SETUP | NEED_WORK_TREE },
 		{ "send-pack", cmd_send_pack, RUN_SETUP },
 		{ "shortlog", cmd_shortlog, RUN_SETUP | USE_PAGER },
 		{ "show-branch", cmd_show_branch, RUN_SETUP },
 		{ "show", cmd_show, RUN_SETUP | USE_PAGER },
+		{ "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
 		{ "stripspace", cmd_stripspace },
 		{ "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 		{ "tag", cmd_tag, RUN_SETUP },
diff --git a/strbuf.h b/strbuf.h
index 9b9e861..9720826 100644
--- a/strbuf.h
+++ b/strbuf.h
@@ -113,5 +113,6 @@ extern int strbuf_read_file(struct strbuf *sb, const char *path, size_t hint);
 extern int strbuf_getline(struct strbuf *, FILE *, int);
 
 extern void stripspace(struct strbuf *buf, int skip_comments);
+extern void launch_editor(const char *path, struct strbuf *buffer);
 
 #endif /* STRBUF_H */
-- 
1.5.3.4

^ permalink raw reply related	[relevance 2%]

* Re: Cloning from kernel.org, then switching to another repo
  @ 2007-11-13  4:14  4%               ` Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2007-11-13  4:14 UTC (permalink / raw)
  To: Jon Smirl; +Cc: Johannes Schindelin, Git Mailing List

On Mon, Nov 12, 2007 at 12:28:28PM -0500, Jon Smirl wrote:

> Actually, fetching from kernel.org first and then switching the origin
> isn't helping. The host is http only since I can't get access to the
> git network port. When I pushed up my local repo it ends up in one big
> pack.
> 
> I do this:
> git clone kernel.org
> move the origin
> git pull
> -- it still pulls down the entire pack and takes an hour

Yep, the http fetch code doesn't understand about fetching parts of
packs (there was some discussion about using partial HTTP transfers, but
nobody seems to have cared enough to implement it).

> Will this fix it?
> at my remote host, first clone from kernel.org
> then push my local changes?

Yes, it should. The goal is to not put your changes and the upstream
commits in the same pack. You could also push _just_ the upstream
commits first, then in a different push, send your local changes. But
when they get pushed together, they all end up in the same pack.

-Peff

^ permalink raw reply	[relevance 4%]

* Re: [PATCH] Improved and extended t5404
    @ 2007-11-14 21:52  3%           ` Junio C Hamano
  2007-11-14 22:49  3%             ` [PATCH] Add test that checks diverse aspects of updating remote and tracking branches Alex Riesen
  2007-11-14 21:52  3%           ` [PATCH] Improved and extended t5404 Junio C Hamano
  2 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2007-11-14 21:52 UTC (permalink / raw)
  To: Alex Riesen; +Cc: git, Jeff King

Alex Riesen <raa.lkml@gmail.com> writes:

> Ignore exit code of git push in t5404, as it is not relevant for the
> test: it already checks whether the references updated correctly.

I think the Subject: goes a lot better with a description like this:

	Add test that checks the case where X does Y and make
	sure Z happens.

	Because we haven't settled on what the exit status from
	"git push" command itself should be in such a partial
	failure case, do not check the exit status from it for
	now.

> diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
> index 20718d4..a51bbdc 100755
> --- a/t/t5404-tracking-branches.sh
> +++ b/t/t5404-tracking-branches.sh
> @@ -10,6 +10,7 @@ test_expect_success 'setup' '
>  	git commit -m 1 &&
>  	git branch b1 &&
>  	git branch b2 &&
> +	git branch b3 &&
>  	git clone . aa &&
>  	git checkout b1 &&
> ...

So it makes another ref "b3" point at the initial commit,... 

> ...
>  test_expect_success 'check tracking branches updated correctly after push' '
>  	cd aa &&
>  	b1=$(git rev-parse origin/b1) &&
>  	b2=$(git rev-parse origin/b2) &&
> +	b3=$(git rev-parse origin/b3) &&
>  	git checkout -b b1 origin/b1 &&
>  	echo aa-b1 >>file &&
>  	git commit -a -m aa-b1 &&

... then records what was cloned,...

> @@ -32,9 +36,28 @@ test_expect_success 'check tracking branches updated correctly after push' '
>  	git checkout master &&
>  	echo aa-master >>file &&
>  	git commit -a -m aa-master &&
> +	{
> +		git push
> +		test "$(git rev-parse origin/b1)" = "$b1" &&
> +		test "$(git rev-parse origin/b2)" = "$b2" &&
> +		test "$(git rev-parse origin/b3)" = "$b3" &&
> +		test "$(git rev-parse origin/master)" = \
> +		"$(git rev-parse master)"
> +	}
> +'

... and checks that untouched "b3" stays the same (iow, tests
up-to-date case).

> +
> +test_expect_success 'delete remote branch' '
> +	git push origin :refs/heads/b3
> +	{
> +		git rev-parse origin/b3
> +		test $? != 0 || \
> +		say "Hmm... Maybe tracking ref should be deleted?"
> +        } &&

Ah, you meant that tracking should be deleted so this should be
fixed in the code but the test is disabled for now.  Let's be a
bit more explicit about such a temporary disabled test, like
this:

	git push origin :refs/heads/b3

	# The remote-tracking branch origin/b3 should be deleted;
        # we need to update the code and enable this test.
        : git rev-parse --verify origin/b3 &&

> +	cd "$start_dir" &&
> +	{
> +		git rev-parse refs/heads/b3
> +		test $? != 0
> +        }
>  '

^ permalink raw reply	[relevance 3%]

* Re: [PATCH] Improved and extended t5404
      2007-11-14 21:52  3%           ` [PATCH] Improved and extended t5404 Junio C Hamano
@ 2007-11-14 21:52  3%           ` Junio C Hamano
  2 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2007-11-14 21:52 UTC (permalink / raw)
  To: Alex Riesen; +Cc: git, Jeff King

Alex Riesen <raa.lkml@gmail.com> writes:

> Ignore exit code of git push in t5404, as it is not relevant for the
> test: it already checks whether the references updated correctly.

I think the Subject: goes a lot better with a description like this:

	Enhance the test to check the case where X does Y and to
	make sure Z happens.

	Because we haven't settled on what the exit status from
	"git push" command itself should be in such a partial
	failure case, do not check the exit status from it for
	now.

> diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
> index 20718d4..a51bbdc 100755
> --- a/t/t5404-tracking-branches.sh
> +++ b/t/t5404-tracking-branches.sh
> @@ -10,6 +10,7 @@ test_expect_success 'setup' '
>  	git commit -m 1 &&
>  	git branch b1 &&
>  	git branch b2 &&
> +	git branch b3 &&
>  	git clone . aa &&
>  	git checkout b1 &&
> ...

So it makes another ref "b3" point at the initial commit,... 

> ...
>  test_expect_success 'check tracking branches updated correctly after push' '
>  	cd aa &&
>  	b1=$(git rev-parse origin/b1) &&
>  	b2=$(git rev-parse origin/b2) &&
> +	b3=$(git rev-parse origin/b3) &&
>  	git checkout -b b1 origin/b1 &&
>  	echo aa-b1 >>file &&
>  	git commit -a -m aa-b1 &&

... then records what was cloned,...

> @@ -32,9 +36,28 @@ test_expect_success 'check tracking branches updated correctly after push' '
>  	git checkout master &&
>  	echo aa-master >>file &&
>  	git commit -a -m aa-master &&
> +	{
> +		git push
> +		test "$(git rev-parse origin/b1)" = "$b1" &&
> +		test "$(git rev-parse origin/b2)" = "$b2" &&
> +		test "$(git rev-parse origin/b3)" = "$b3" &&
> +		test "$(git rev-parse origin/master)" = \
> +		"$(git rev-parse master)"
> +	}
> +'

... and checks that untouched "b3" stays the same (iow, tests
up-to-date case).

> +
> +test_expect_success 'delete remote branch' '
> +	git push origin :refs/heads/b3
> +	{
> +		git rev-parse origin/b3
> +		test $? != 0 || \
> +		say "Hmm... Maybe tracking ref should be deleted?"
> +        } &&

Ah, you meant that tracking should be deleted so this should be
fixed in the code but the test is disabled for now.  Let's be a
bit more explicit about such a temporary disabled test, like
this:

	git push origin :refs/heads/b3

	# The remote-tracking branch origin/b3 should be deleted;
        # we need to update the code and enable this test.
        : git rev-parse --verify origin/b3 &&

> +	cd "$start_dir" &&
> +	{
> +		git rev-parse refs/heads/b3
> +		test $? != 0
> +        }
>  '

^ permalink raw reply	[relevance 3%]

* [PATCH] Add test that checks diverse aspects of updating remote and tracking branches
  2007-11-14 21:52  3%           ` [PATCH] Improved and extended t5404 Junio C Hamano
@ 2007-11-14 22:49  3%             ` Alex Riesen
  0 siblings, 0 replies; 200+ results
From: Alex Riesen @ 2007-11-14 22:49 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git, Jeff King, Johannes Schindelin

Because we haven't settled on what the exit status from
"git push" command itself should be in such a partial
failure case, do not check the exit status from it for
now.

Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---

Junio C Hamano, Wed, Nov 14, 2007 22:52:19 +0100:
> Alex Riesen <raa.lkml@gmail.com> writes:
> 
> > Ignore exit code of git push in t5404, as it is not relevant for the
> > test: it already checks whether the references updated correctly.
> 
> I think the Subject: goes a lot better with a description like this:
> 
> 	Add test that checks the case where X does Y and make
> 	sure Z happens.

Add test that checks diverse aspects of updating remote and tracking
branches.

> 	Because we haven't settled on what the exit status from
> 	"git push" command itself should be in such a partial
> 	failure case, do not check the exit status from it for
> 	now.

This I'll leave as is.

> > +	git branch b3 &&
> 
> So it makes another ref "b3" point at the initial commit,... 

Right

> > +	b3=$(git rev-parse origin/b3) &&
> 
> ... then records what was cloned,...

Precisely

> > +		test "$(git rev-parse origin/b3)" = "$b3" &&
> 
> ... and checks that untouched "b3" stays the same (iow, tests
> up-to-date case).

Yep.

> > +
> > +test_expect_success 'delete remote branch' '
> > +	git push origin :refs/heads/b3
> > +	{
> > +		git rev-parse origin/b3
> > +		test $? != 0 || \
> > +		say "Hmm... Maybe tracking ref should be deleted?"
> > +        } &&
> 
> Ah, you meant that tracking should be deleted so this should be
> fixed in the code but the test is disabled for now.  Let's be a
> bit more explicit about such a temporary disabled test, like
> this:
> 
> 	git push origin :refs/heads/b3
> 
> 	# The remote-tracking branch origin/b3 should be deleted;
>         # we need to update the code and enable this test.
>         : git rev-parse --verify origin/b3 &&

Nice, will take this. Except we have to check for absence of the
tracking branch. git-rev-parse must fail.

 t/t5404-tracking-branches.sh |   64 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 64 insertions(+), 0 deletions(-)
 create mode 100755 t/t5404-tracking-branches.sh

diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
new file mode 100755
index 0000000..d861a14
--- /dev/null
+++ b/t/t5404-tracking-branches.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+test_description='tracking branch update checks for git push'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	echo 1 >file &&
+	git add file &&
+	git commit -m 1 &&
+	git branch b1 &&
+	git branch b2 &&
+	git branch b3 &&
+	git clone . aa &&
+	git checkout b1 &&
+	echo b1 >>file &&
+	git commit -a -m b1 &&
+	git checkout b2 &&
+	echo b2 >>file &&
+	git commit -a -m b2
+'
+
+start_dir="$(pwd)"
+
+test_expect_success 'check tracking branches updated correctly after push' '
+	cd aa &&
+	b1=$(git rev-parse origin/b1) &&
+	b2=$(git rev-parse origin/b2) &&
+	b3=$(git rev-parse origin/b3) &&
+	git checkout -b b1 origin/b1 &&
+	echo aa-b1 >>file &&
+	git commit -a -m aa-b1 &&
+	git checkout -b b2 origin/b2 &&
+	echo aa-b2 >>file &&
+	git commit -a -m aa-b2 &&
+	git checkout master &&
+	echo aa-master >>file &&
+	git commit -a -m aa-master &&
+	{
+		git push
+		test "$(git rev-parse origin/b1)" = "$b1" &&
+		test "$(git rev-parse origin/b2)" = "$b2" &&
+		test "$(git rev-parse origin/b3)" = "$b3" &&
+		test "$(git rev-parse origin/master)" = \
+		"$(git rev-parse master)"
+	}
+'
+
+test_expect_success 'delete remote branch' '
+	git push origin :refs/heads/b3
+	{
+	# The remote-tracking branch origin/b3 should be deleted;
+	# we need to update the code and enable this test.
+		: git rev-parse --verify origin/b3
+		: test $? != 0
+        } &&
+	cd "$start_dir" &&
+	{
+		git rev-parse refs/heads/b3
+		test $? != 0
+        }
+'
+
+test_done
-- 
1.5.3.5.692.ge1737

^ permalink raw reply related	[relevance 3%]

* [PATCH] Add test that checks diverse aspects of updating remote and tracking branches
  @ 2007-11-15 20:46  3%               ` Alex Riesen
  0 siblings, 0 replies; 200+ results
From: Alex Riesen @ 2007-11-15 20:46 UTC (permalink / raw)
  To: Jeff King; +Cc: git, Junio C Hamano

Because we haven't settled on what the exit status from
"git push" command itself should be in such a partial
failure case, do not check the exit status from it for
now.

Signed-off-by: Alex Riesen <raa.lkml@gmail.com>
---

Jeff King, Thu, Nov 15, 2007 05:26:26 +0100:
> On Tue, Nov 13, 2007 at 06:10:48PM -0500, Jeff King wrote:
> 
> > > This one is on top of what is in next. It also include the check for
> > > deleting remote braches I sent before. Regarding this one: if a remote
> > > branch is deleted, shouldn't the matching tracking branch be removed
> > > as well? The code in master seem to do that.
> > 
> > Yes, it should (the code in update_tracking_ref seems to handle that
> > case, but I haven't tested, so I may have bungled something). I am
> > literally walking out the door, now, though, so I will be out of touch
> > for at least a day.
> 
> After I became disconnected, I looked at my 'next', and the reason for
> the failure to delete the ref seems to be your is_null_sha1
> error-checking patch, which Junio put in next. But maybe you have
> figured that out in the intervening time. :)

I didn't. But Junio already has all your patches in pu, so I activated
the deletion test and rebased it on top of your patches in his tree
(jk/send-pack, according to merge commit). Tried: works.

 t/t5404-tracking-branches.sh |   28 +++++++++++++++++++++++++---
 1 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/t/t5404-tracking-branches.sh b/t/t5404-tracking-branches.sh
index 20718d4..a6f60ac 100755
--- a/t/t5404-tracking-branches.sh
+++ b/t/t5404-tracking-branches.sh
@@ -10,6 +10,7 @@ test_expect_success 'setup' '
 	git commit -m 1 &&
 	git branch b1 &&
 	git branch b2 &&
+	git branch b3 &&
 	git clone . aa &&
 	git checkout b1 &&
 	echo b1 >>file &&
@@ -19,10 +20,13 @@ test_expect_success 'setup' '
 	git commit -a -m b2
 '
 
+start_dir="$(pwd)"
+
 test_expect_success 'check tracking branches updated correctly after push' '
 	cd aa &&
 	b1=$(git rev-parse origin/b1) &&
 	b2=$(git rev-parse origin/b2) &&
+	b3=$(git rev-parse origin/b3) &&
 	git checkout -b b1 origin/b1 &&
 	echo aa-b1 >>file &&
 	git commit -a -m aa-b1 &&
@@ -32,9 +36,27 @@ test_expect_success 'check tracking branches updated correctly after push' '
 	git checkout master &&
 	echo aa-master >>file &&
 	git commit -a -m aa-master &&
-	git push &&
-	test "$(git rev-parse origin/b1)" = "$b1" &&
-	test "$(git rev-parse origin/b2)" = "$b2"
+	{
+		git push
+		test "$(git rev-parse origin/b1)" = "$b1" &&
+		test "$(git rev-parse origin/b2)" = "$b2" &&
+		test "$(git rev-parse origin/b3)" = "$b3" &&
+		test "$(git rev-parse origin/master)" = \
+		"$(git rev-parse master)"
+	}
+'
+
+test_expect_success 'delete remote branch' '
+	git push origin :refs/heads/b3
+	{
+		git rev-parse --verify origin/b3
+		test $? != 0
+        } &&
+	cd "$start_dir" &&
+	{
+		git rev-parse refs/heads/b3
+		test $? != 0
+        }
 '
 
 test_done
-- 
1.5.3.5.692.ge1737

^ permalink raw reply related	[relevance 3%]

* What's cooking in git.git (topics)
  @ 2007-11-17 20:51  1%             ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2007-11-17 20:51 UTC (permalink / raw)
  To: git

Here are the topics that have been cooking.  Commits prefixed
with '-' are only in 'pu' while commits prefixed with '+' are
in 'next'.  The topics list the commits in reverse chronological
order.

----------------------------------------------------------------
[New Topics]

* jc/move-gitk (Sat Nov 17 10:51:16 2007 -0800) 1 commit
 - Move gitk to its own subdirectory

----------------------------------------------------------------
[Will cook further in 'next' and then merge to 'master' soon]

* sh/p4 (Thu Nov 15 10:38:45 2007 +0100) 1 commit
 + git-p4: Fix direct import from perforce after fetching changes
   through git from origin

* lt/rev-list-interactive (Mon Nov 12 23:16:08 2007 -0800) 5 commits
 + Fix parent rewriting in --early-output
 + revision walker: mini clean-up
 + Enhance --early-output format
 + Add "--early-output" log flag for interactive GUI use
 + Simplify topo-sort logic

* lt/rev-list-gitlink (Sun Nov 11 23:35:23 2007 +0000) 1 commit
 + Fix rev-list when showing objects involving submodules

This fix from Dscho and Linus will need to be cherry-picked to
'maint' as well.

* ds/checkout-upper (Fri Nov 9 20:12:28 2007 +1100) 2 commits
 + git-checkout: Test for relative path use.
 + git-checkout: Support relative paths containing "..".

This will allow you to stay in a subdirectory and check out
paths in directories outside.  With Dscho's "git status" that
shows relatives paths (in kh/commit series), this would make
cutting and pasting paths you forgot to "git add" easier.

* ph/parseopt-sh (Mon Nov 12 12:07:40 2007 +0000) 17 commits
 + git-quiltimport.sh fix --patches handling
 + git-am: -i does not take a string parameter.
 + sh-setup: don't let eval output to be shell-expanded.
 + git-sh-setup: fix parseopt `eval` string underquoting
 + Give git-am back the ability to add Signed-off-by lines.
 + git-rev-parse --parseopt
 + scripts: Add placeholders for OPTIONS_SPEC
 + Migrate git-repack.sh to use git-rev-parse --parseopt
 + Migrate git-quiltimport.sh to use git-rev-parse --parseopt
 + Migrate git-checkout.sh to use git-rev-parse --parseopt --keep-
   dashdash
 + Migrate git-instaweb.sh to use git-rev-parse --parseopt
 + Migrate git-merge.sh to use git-rev-parse --parseopt
 + Migrate git-am.sh to use git-rev-parse --parseopt
 + Migrate git-clone to use git-rev-parse --parseopt
 + Migrate git-clean.sh to use git-rev-parse --parseopt.
 + Update git-sh-setup(1) to allow transparent use of git-rev-parse -
   -parseopt
 + Add a parseopt mode to git-rev-parse to bring parse-options to
   shell scripts.

The rate of incoming fix with this topic has slowed down, which
is a good indication that this is getting ready.

* js/mingw-fallouts (Thu Nov 15 12:24:17 2007 -0500) 12 commits
 + rehabilitate some t5302 tests on 32-bit off_t machines
 + Allow ETC_GITCONFIG to be a relative path.
 + Introduce git_etc_gitconfig() that encapsulates access of
   ETC_GITCONFIG.
 + Allow a relative builtin template directory.
 + Close files opened by lock_file() before unlinking.
 + builtin run_command: do not exit with -1.
 + Move #include <sys/select.h> and <sys/ioctl.h> to git-compat-
   util.h.
 + Use is_absolute_path() in sha1_file.c.
 + Skip t3902-quoted.sh if the file system does not support funny
   names.
 + t5302-pack-index: Skip tests of 64-bit offsets if necessary.
 + t7501-commit.sh: Not all seds understand option -i
 + t5300-pack-object.sh: Split the big verify-pack test into smaller
   parts.

A set of good general clean-up patches.

* ph/diffopts (Wed Nov 7 11:20:32 2007 +0100) 6 commits
 + Reorder diff_opt_parse options more logically per topics.
 + Make the diff_options bitfields be an unsigned with explicit
   masks.
 + Use OPT_BIT in builtin-pack-refs
 + Use OPT_BIT in builtin-for-each-ref
 + Use OPT_SET_INT and OPT_BIT in builtin-branch
 + parse-options new features.

Further code clean-ups.

* cc/bisect (Sat Nov 17 14:35:25 2007 +0100) 5 commits
 + Bisect visualize: use "for-each-ref" to list all good refs.
 + git-bisect: modernize branch shuffling hack
 + git-bisect: use update-ref to mark good/bad commits
 + git-bisect: war on "sed"
 + Bisect reset: remove bisect refs that may have been packed.

----------------------------------------------------------------
[Actively cooking]

* jk/send-pack (Sat Nov 17 07:56:03 2007 -0500) 24 commits
 + send-pack: assign remote errors to each ref
 + send-pack: check ref->status before updating tracking refs
 + send-pack: track errors for each ref
 + Merge branch 'aw/mirror-push' into jk/send-pack
 + Merge branch 'ar/send-pack-remote-track' into jk/send-pack
 + Merge branch 'db/remote-builtin' into jk/send-pack
 + git-push: add documentation for the newly added --mirror mode
 + Add tests for git push'es mirror mode
 + Update the tracking references only if they were succesfully
   updated on remote
 + Add a test checking if send-pack updated local tracking branches
   correctly
 + git-push: plumb in --mirror mode
 + Teach send-pack a mirror mode
 + Merge master into aw/mirror-push
 + Merge branch 'jk/terse-push' into aw/mirror-push
 + send-pack: segfault fix on forced push
 + Reteach builtin-ls-remote to understand remotes
 + send-pack: require --verbose to show update of tracking refs
 + receive-pack: don't mention successful updates
 + more terse push output
 + Build in ls-remote
 + Build-in send-pack, with an API for other programs to call.
 + Use built-in send-pack.
 + Build-in peek-remote, using transport infrastructure.
 + Miscellaneous const changes and utilities

Looking good.

* jc/spht (Fri Nov 2 17:46:55 2007 -0700) 3 commits
 + core.whitespace: add test for diff whitespace error highlighting
 + git-diff: complain about >=8 consecutive spaces in initial indent
 + War on whitespace: first, a bit of retreat.

Teaching "git apply --whitespace=[warn|strip]" to honor the same
configuration would be a good addition, but this could go to
'master' as is.

* js/reflog-delete (Wed Oct 17 02:50:45 2007 +0100) 1 commit
 + Teach "git reflog" a subcommand to delete single entries

* tt/help (Sun Nov 11 19:57:57 2007 -0500) 2 commits
 + Remove hint to use "git help -a"
 + Make the list of common commands more exclusive

Some people on the list may find the exact list of commands
somewhat debatable.  We can fine-tune that in-tree ('pu' does
not count as "in-tree").

----------------------------------------------------------------
[Approaching 'next']

* kh/commit (Sat Nov 17 00:46:33 2007 -0800) 16 commits
 - PARK: cruft next-index clean-up
 - Replace "runstatus" with "status" in the tests
 - t7501-commit: Add test for git commit <file> with dirty index.
 - builtin-commit: Clean up an unused variable and a debug fprintf().
 - Call refresh_cache() when updating the user index for --only
   commits.
 - builtin-commit: Add newline when showing which commit was created
 - builtin-commit: resurrect behavior for multiple -m options
 - builtin-commit --s: add a newline if the last line was not a S-o-b
 - builtin-commit: fix --signoff
 - git status: show relative paths when run in a subdirectory
 - builtin-commit: Refresh cache after adding files.
 - builtin-commit: fix reflog message generation
 - launch_editor(): read the file, even when EDITOR=:
 - Port git commit to C.
 - Export launch_editor() and make it accept ':' as a no-op editor.
 - Add testcase for amending and fixing author in git commit.

Dscho fixed a few obvious glitches, but indicated he has a
handful more issues with the series.  Partial commit is
seriously broken.

* sp/refspec-match (Sun Nov 11 15:01:48 2007 +0100) 4 commits
 - refactor fetch's ref matching to use refname_match()
 - push: use same rules as git-rev-parse to resolve refspecs
 - add refname_match()
 - push: support pushing HEAD to real branch name

This changes the semantics slightly but I think it is a move in
the right direction.

* sb/clean (Wed Nov 14 23:00:54 2007 -0600) 3 commits
 - Teach git clean to use setup_standard_excludes()
 - git-clean: Fix error message if clean.requireForce is not set.
 - Make git-clean a builtin

It has a subtle change in behaviour but it does not quite
qualify as a regression.  Will merge to "next" shortly.  We can
fix the corner case semantics in-tree.  I also adjusted the
error message to match the fix from Hannes on 'master'.

----------------------------------------------------------------
[Stalled]

* mh/rebase-skip-hard (Thu Nov 8 08:03:06 2007 +0100) 1 commit
 - Do git reset --hard HEAD when using git rebase --skip

Some people on the list may find this debatable.  Opinions?

* cr/tag-options (Fri Nov 9 14:42:56 2007 +0100) 1 commit
 - Make builtin-tag.c use parse_options.

This changes the handling of multiple -m options without much
good reason.  It should be a simple fix, once we know what we
want.  I think the existing behaviour of refusing multiple -m
is probably the most sane at this point.

* dz/color-addi (Sat Nov 10 18:03:44 2007 -0600) 3 commits
 - Added diff hunk coloring to git-add--interactive
 - Let git-add--interactive read colors from .gitconfig
 - Added basic color support to git add --interactive

This series has improved quite a bit since the last round, but
another round was requested from the list.  Waiting for
refinements.

* nd/maint-work-tree-fix (Sat Nov 3 20:18:06 2007 +0700) 1 commit
 + Add missing inside_work_tree setting in setup_git_directory_gently

There was an additional patch, which still had issues Dscho
pointed out.  Waiting for refinements.

* ss/dirty-rebase (Thu Nov 1 22:30:24 2007 +0100) 3 commits
 - Make git-svn rebase --dirty pass along --dirty to git-rebase.
 - Implement --dirty for git-rebase--interactive.
 - Introduce --dirty option to git-rebase, allowing you to start from
   a dirty state.

This seems to be optimized for the --dirty case too much.  I'd
prefer an implementation that make rebases without --dirty to
pay no penalty (if that is possible, otherwise "as little as
possible").

----------------------------------------------------------------
[Others]

* jc/branch-contains (Wed Nov 7 14:58:09 2007 -0800) 1 commit
 - git-branch --with=commit

I did this just for my own fun.  --contains might be more
consistent with git-describe but --with is shorter to type ;-)

Besides, it needs documentation and tests.

* jc/maint-format-patch-encoding (Fri Nov 2 17:55:31 2007 -0700) 2 commits
 - test format-patch -s: make sure MIME content type is shown as
   needed
 - format-patch -s: add MIME encoding header if signer's name
   requires so

This is to apply to 'maint' later; the equivalent fix is already
in 'master'.

* lt/maint-rev-list-gitlink (Sun Nov 11 23:35:23 2007 +0000) 1 commit
 - Fix rev-list when showing objects involving submodules

This is to apply to 'maint' later; the equivalent fix is already
in 'next' and will be merged to 'master' soon.

* jc/pathspec (Thu Sep 13 13:38:19 2007 -0700) 3 commits
 - pathspec_can_match(): move it from builtin-ls-tree.c to tree.c
 - ls-tree.c: refactor show_recursive() and rename it.
 - tree-diff.c: split out a function to match a single pattern.

* jk/rename (Tue Oct 30 00:24:42 2007 -0400) 3 commits
 - handle renames using similarity engine
 - introduce generic similarity library
 - change hash table calling conventions

* jc/cherry-pick (Tue Nov 13 12:38:51 2007 -0800) 1 commit
 - revert/cherry-pick: start refactoring call to merge_recursive

* jc/nu (Sun Oct 14 22:07:34 2007 -0700) 3 commits
 - merge-nu: a new merge backend without using unpack_trees()
 - read_tree: take an explicit index structure
 - gcc 4.2.1 -Werror -Wall -ansi -pedantic -std=c99: minimum fix

^ permalink raw reply	[relevance 1%]

* Re: Adding Git to Better SCM Initiative : Comparison
  @ 2007-11-29  1:48  3% ` Robin Rosenberg
  0 siblings, 0 replies; 200+ results
From: Robin Rosenberg @ 2007-11-29  1:48 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git

onsdag 28 november 2007 skrev Jakub Narebski:
> I'd like to add Git to comparison table of SCMs at Better SCM
> Initiative site:
>   http://better-scm.berlios.de
> 
> To do that, I need to fill in infomration about Git.  Most
> of questions / items didn't give much problem, but there
> are a few on which I would like your input.
> 
> (Yes, I know that such SCM comparisons are usually biased towards the
> idea of what are most important features of a version control system.
> Nevertheless...)
[...]
> 4. Repository Permissions
> 
>    Is it possible to define permissions on access to different
>    parts of a remote repository? Or is access open for all?
> 
> "Partial (?). It is possible to lock down repository
>  (access to branches and tags) using hooks."
> 
> I don't know if it is possible to do finer level ACLs, i.e. if it
> is possible to lock subdirectories or files in Git.  Although for
> distributed SCMs ACL doesn't matter much: check diffstat and merge or
> not from trusted people.  We have "network of trust" (BTW. Karl Fogel
> in OSSBook recommends 'soft' control of access control to repository,
> on social rather than on technical level).

I think what is most interesting here is access to content for which git has
just about nothing worth mentioning, Just admit it. "Truth in advertising".

I did start doing this so here's my version (pre-msysgit). Please try to bring up the defintion
of "atomic" again with the author. I did complain a little but nothing happened. The issue is
that Clearcase is listed as having "atomic" commits which is not true for any usable definition
of atomic in SCM context. With the definition in use there I think CVS should be considered
having atomic commits too, at least I've never seen a half-committed file there.

% svn diff
Index: src/comparison/scm-comparison.xml
===================================================================
--- src/comparison/scm-comparison.xml	(revision 290)
+++ src/comparison/scm-comparison.xml	(arbetskopia)
@@ -71,6 +71,9 @@
             <impl id="ls-sync">
                 <name>LibreSource Synchronizer</name>
             </impl>
+            <impl id="git">
+                <name>Git</name>
+            </impl>
         </implementations>
         <timestamp>
             $Id$
@@ -182,6 +185,13 @@
                     needs to be up-to-date before doing a rename/move operation. 
                     This operation will be committed directly.
                 </s>
+                <s id="git">
+                    Yes (or no depending on interpretation). Git typically detects
+		    renames and copies based on content regardless of whether the
+		    committer indicated the fact. The detection is content based
+		    rather than file-id based. There is explicit rename too, but
+		    it is not used much.
+                </s>
            </compare>
         </section>
         <section id="copy">
@@ -236,6 +246,10 @@
                   limitations in Windows environments)
                 </s>
                 <s id="ls-sync">No, copies will start there own history.</s>
+                <s id="git">Yes(or no depending on interpretation). Git detects
+			copies and moves based on content. It does not track
+			history on a file-id based scheme.
+                </s>
            </compare>
         </section>
         <section id="repos_clone">
@@ -288,6 +302,11 @@
                   Yes, but is not documented and its based on the dataflow feature of the
                   LibreSource Synchronizer.
                 </s>
+                <s id="git">
+                  Yes. This is a fundamental part of using Git. A Git user typically always
+		  has a full copy of the entire repostory (well compressed) that is initialized
+		  using a clone command.
+                </s>
             </compare>
         </section>
         <section id="push">
@@ -331,6 +350,7 @@
                 <s id="cmsynergy">Yes, as long as you have the (more expensive) Distributed package.</s>
                 <s id="clearcase">Yes, using Clearcase Multisite.</s>
                 <s id="ls-sync">Yes, it's what we call a dataflow.</s>
+                <s id="git">Yes. This is a fundamental part of using Git.</s>
             </compare>
         </section>
         <section id="permissions">
@@ -417,7 +437,8 @@
                   multi-platform environments.
                 </s>
                 <s id="ls-sync">Permissions are set for the whole repository or branch.</s>
-            </compare>
+                <s id="git">No, but bad changes can be reverted before they are published.</s>
+	</compare>
         </section>
         <section id="changesets">
             <title>Changesets' Support</title>
@@ -490,6 +511,11 @@
                   Partial support. There are implicit changeset that are generated on
                   each commit.
                 </s>
+            	<s id="git">Yes. Actually Git is snapshot based which means Git records
+			the full state in every commit, which means that any two
+			commits can be compared directly very quickly, although the
+			repository is typically browsed as a series of change sets.
+                </s>
            </compare>
         </section>
         <section id="annotate">
@@ -534,6 +560,9 @@
                     Yes locally without any server connection with the standard graphical
                     Java client.
                 </s>
+            	<s id="git">Yes. It can also detect the origin of copied and moved source
+			lines.
+                </s>
            </compare>
         </section>
     </section>
@@ -610,6 +639,12 @@
                    It is possible to commit only a certain directory. However, one must
                    check out the entire repository as a whole.
                 </s>
+            	<s id="git">No. However it is possible to commit only selected 
+			changes in the working tree rather than everything. Subproject
+			support makes it possible to split large projects into several
+			repositories and link them. Related repositories need not be
+			checked out or cloned.
+                </s>
            </compare>
         </section>
         <section id="tracking_uncommited_changes">
@@ -659,6 +694,10 @@
                   Yes, with the Synchronizer Studio (default Java client) or with the
                   standard diff command (diff -r . .so6/xxx/REFCOPY/)
                 </s>
+            	<s id="git">Yes. In addition commits are local and will not be seen
+			until he/she decides to publish them making it possible to
+			track multiple versions locally before publishing.
+                </s>
             </compare>
         </section>
         <section id="per_file_commit_messages">
@@ -714,6 +753,7 @@
                   for a per-changeset message.
                 </s>
                 <s id="ls-sync">No. Commit messages are per changeset.</s>
+                <s id="git">No. The same message applies the the commit as a whole.</s>
            </compare>
         </section>
     </section>
@@ -828,6 +868,11 @@
                   documentation. Installing and getting started with the GUI is very easy
                   though. (update/commit-next-next-next-finished)
                 </s>
+            	<s id="git">
+		  There a good tutorials manual pages and a supportive community.
+		  Basic usage is simple, but advanced usage requires understanding of
+		  what makes git different.
+                </s>
             </compare>
         </section>
         <section id="ease_of_deployment">
@@ -950,6 +995,10 @@
                   LibreSource repository web page. 
                   (links: create workspace, update, commit, studio...)
                 </s>
+            	<s id="git">
+		  Very simple to deploy on Unix-like systems. Windows installs
+		  is not fully developed yet. Installing in cygwin is simple though.
+                </s>
            </compare>
         </section>
         <section id="command_set">
@@ -1048,6 +1097,13 @@
                   Basic commands available (commit/update), but it's really simple to
                   use the GUI. Ant task are also available.
                 </s>
+            	<s id="git">Basic usage could be considered similar, but trying
+			to use Git like CVS would be counterproductive since many
+			cases of CVS usage is by design not possible in Git. The
+			number of command is large. ~140 but only ~20 commands
+			are typically used and less than ten will do for casual
+			users.
+                </s>
            </compare>
         </section>
         <section id="networking">
@@ -1152,6 +1208,13 @@
                 <s id="ls-sync">
                   Good. Use of HTTP to get through firwalls. 
                 </s>
+            	<s id="git">
+		  Excellent. Normal usage is off-line, but networking is
+		  used for sharing changes Networking including ssh, 
+		  a special git protocol http and mail can be used to share
+		  changes, both incoming and outgoing. Mail can be used
+		  via IMAP and mbox files.
+                </s>
             </compare>
         </section>
         <section id="portability">
@@ -1249,6 +1312,11 @@
                   Excellent. Clients and servers work on any Java 1.5-compatible
                   platform. (Windows, Linux and Mac OS X )
                 </s>
+            	<s id="git">
+		  Very good for POSIX compatible environments. A non-cygwin
+		  port for windows is underway. There are some graphical
+		  tools available for windows in cygwin.
+                </s>
             </compare>
         </section>
     </section>
@@ -1323,6 +1391,7 @@
                   Yes, without diff features but with a better awareness support.
                   (allow to know at any time on each version each one is working on) 
                 </s>
+                <s id="git">Yes. gitweb</s>
             </compare>
         </section>
         <section id="availability_of_guis">
@@ -1421,6 +1490,10 @@
                   is automatically launched from the repository web page and 
                   another one which is an Eclipse plugin.
                 </s>
+                <s id="git">
+		  A number of good GUI's are availble for basic usage, 
+		  but typical usage is command based.
+                </s>
            </compare>
         </section>
     </section>
@@ -1501,7 +1574,8 @@
               additional licensing.
             </s>
             <s id="ls-sync">QPL - The Qt Public License (OpenSource)</s>
-        </compare>
+            <s id="git">GPL</s>
+       </compare>
     </section>
 </section>
     </contents>


-- robin

^ permalink raw reply	[relevance 3%]

* Building git-1.5.3.7 on HP-UX 11.00
@ 2007-12-04 13:09  2% H.Merijn Brand
  0 siblings, 0 replies; 200+ results
From: H.Merijn Brand @ 2007-12-04 13:09 UTC (permalink / raw)
  To: git; +Cc: Sam Vilain

1. It won't compile at all with HP C-ANSI-C, so I have to use gcc-3.4.6

I added this to Makefile to get it compiled

ifeq ($(uname_S),HP-UX)
	# HP-UX
	BASIC_LDFLAGS += -L/usr/local/ssl/lib -L/usr/local/lib
	EXTLIBS += -ldce
	NO_HSTRERROR = YesPlease
	NO_ICONV = YesPlease
	NO_INET_NTOP = YesPlease
	NO_INET_PTON = YesPlease
endif

make test then fails:

/pro/3gl/LINUX/git-1.5.3.7 178 > make test
    LINK git-convert-objects
    LINK git
    BUILTIN git-format-patch
    BUILTIN git-show
    BUILTIN git-whatchanged
    BUILTIN git-cherry
    BUILTIN git-get-tar-commit-id
    BUILTIN git-init
    BUILTIN git-repo-config
    BUILTIN git-fsck-objects
    BUILTIN git-cherry-pick
    BUILTIN git-add
    BUILTIN git-annotate
    BUILTIN git-apply
    BUILTIN git-archive
    BUILTIN git-blame
    BUILTIN git-branch
    BUILTIN git-bundle
    BUILTIN git-cat-file
    BUILTIN git-check-attr
    BUILTIN git-checkout-index
    BUILTIN git-check-ref-format
    BUILTIN git-commit-tree
    BUILTIN git-count-objects
    BUILTIN git-describe
    BUILTIN git-diff
    BUILTIN git-diff-files
    BUILTIN git-diff-index
    BUILTIN git-diff-tree
    BUILTIN git-fetch--tool
    BUILTIN git-fmt-merge-msg
    BUILTIN git-for-each-ref
    BUILTIN git-fsck
    BUILTIN git-gc
    BUILTIN git-grep
    BUILTIN git-init-db
    BUILTIN git-log
    BUILTIN git-ls-files
    BUILTIN git-ls-tree
    BUILTIN git-mailinfo
    BUILTIN git-mailsplit
    BUILTIN git-merge-base
    BUILTIN git-merge-file
    BUILTIN git-mv
    BUILTIN git-name-rev
    BUILTIN git-pack-objects
    BUILTIN git-prune
    BUILTIN git-prune-packed
    BUILTIN git-push
    BUILTIN git-read-tree
    BUILTIN git-reflog
    BUILTIN git-config
    BUILTIN git-rerere
    BUILTIN git-rev-list
    BUILTIN git-rev-parse
    BUILTIN git-revert
    BUILTIN git-rm
    BUILTIN git-runstatus
    BUILTIN git-shortlog
    BUILTIN git-show-branch
    BUILTIN git-stripspace
    BUILTIN git-symbolic-ref
    BUILTIN git-tag
    BUILTIN git-tar-tree
    BUILTIN git-unpack-objects
    BUILTIN git-update-index
    BUILTIN git-update-ref
    BUILTIN git-upload-archive
    BUILTIN git-verify-pack
    BUILTIN git-verify-tag
    BUILTIN git-write-tree
    BUILTIN git-show-ref
    BUILTIN git-pack-refs
    SUBDIR git-gui
    INDEX lib/
    SUBDIR perl
    SUBDIR templates
make -C t/ all
make[1]: Entering directory `/pro/3gl/LINUX/git-1.5.3.7/t'
*** t0000-basic.sh ***
*   ok 1: .git/objects should be empty after git init in an empty repo.
*   ok 2: .git/objects should have 3 subdirectories.
*   ok 3: git update-index without --add should fail adding.
*   ok 4: git update-index with --add should succeed.
*   ok 5: writing tree out with git write-tree
*   ok 6: validate object ID of a known tree.
*   ok 7: git update-index without --remove should fail removing.
*   ok 8: git update-index with --remove should be able to remove.
*   ok 9: git write-tree should be able to write an empty tree.
*   ok 10: validate object ID of a known tree.
*   ok 11: adding various types of objects with git update-index --add.
*   ok 12: showing stage with git ls-files --stage
*   ok 13: validate git ls-files output for a known tree.
*   ok 14: writing tree out with git write-tree.
*   ok 15: validate object ID for a known tree.
*   ok 16: showing tree with git ls-tree
*   ok 17: git ls-tree output for a known tree.
*   ok 18: showing tree with git ls-tree -r
*   ok 19: git ls-tree -r output for a known tree.
*   ok 20: showing tree with git ls-tree -r -t
*   ok 21: git ls-tree -r output for a known tree.
*   ok 22: writing partial tree out with git write-tree --prefix.
*   ok 23: validate object ID for a known tree.
*   ok 24: writing partial tree out with git write-tree --prefix.
*   ok 25: validate object ID for a known tree.
*   ok 26: put invalid objects into the index.
*   ok 27: writing this tree without --missing-ok.
*   ok 28: writing this tree with --missing-ok.
*   ok 29: git read-tree followed by write-tree should be idempotent.
*   ok 30: validate git diff-files output for a know cache/work tree state.
*   ok 31: git update-index --refresh should succeed.
*   ok 32: no diff after checkout and git update-index --refresh.
*   ok 33: git commit-tree records the correct tree in a commit.
*   ok 34: git commit-tree records the correct parent in a commit.
*   ok 35: git commit-tree omits duplicated parent in a commit.
*   ok 36: update-index D/F conflict
*   ok 37: absolute path works as expected
* passed all 37 test(s)
*** t0001-init.sh ***
* FAIL 1: plain

                (
                        unset GIT_DIR GIT_WORK_TREE &&
                        mkdir plain &&
                        cd plain &&
                        git init
                ) &&
                check_config plain/.git false unset

*   ok 2: plain with GIT_WORK_TREE
* FAIL 3: plain bare

                (
                        unset GIT_DIR GIT_WORK_TREE GIT_CONFIG &&
                        mkdir plain-bare-1 &&
                        cd plain-bare-1 &&
                        git --bare init
                ) &&
                check_config plain-bare-1 true unset

*   ok 4: plain bare with GIT_WORK_TREE
*   ok 5: GIT_DIR bare
*   ok 6: GIT_DIR non-bare
*   ok 7: GIT_DIR & GIT_WORK_TREE (1)
*   ok 8: GIT_DIR & GIT_WORK_TREE (2)
* failed 2 among 8 test(s)
make[1]: *** [t0001-init.sh] Error 1
make[1]: Leaving directory `/pro/3gl/LINUX/git-1.5.3.7/t'
make: *** [test] Error 2
Exit 2


and make install probably expects a broken^Wdifferent install than HP-UX has:

/pro/3gl/LINUX/git-1.5.3.7 181 > make install
    SUBDIR git-gui
    INDEX lib/
    SUBDIR perl
    SUBDIR templates
install -d -m755 '/pro/local/bin'
rm: /pro/local/bin/ directory
Usage: mv [-f] [-i] [-e warn|force|ignore] f1 f2
       mv [-f] [-i] [-e warn|force|ignore] f1 ... fn d1
       mv [-f] [-i] [-e warn|force|ignore] d1 d2
install -d -m755 '/pro/local/bin'
rm: /pro/local/bin/ directory
Usage: mv [-f] [-i] [-e warn|force|ignore] f1 f2
       mv [-f] [-i] [-e warn|force|ignore] f1 ... fn d1
       mv [-f] [-i] [-e warn|force|ignore] d1 d2
install git-convert-objects git-fetch-pack git-hash-object git-index-pack git-local-fetch git-fast-import git-daemon git-merge-index git-mktag git-mktree git-patch-id git-peek-remote git-receive-pack git-send-pack git-shell git-show-index git-ssh-fetch git-ssh-upload git-unpack-file git-update-server-info git-upload-pack git-pack-redundant git-var git-merge-tree git-imap-send git-merge-recursive  git-ssh-pull git-ssh-push git-bisect git-checkout git-clean git-clone git-commit git-fetch git-ls-remote git-merge-one-file git-mergetool git-parse-remote git-pull git-rebase git-rebase--interactive git-repack git-request-pull git-reset git-sh-setup git-am git-merge git-merge-stupid git-merge-octopus git-merge-resolve git-merge-ours git-lost-found git-quiltimport git-submodule git-filter-branch gi
 t-stash git-add--interactive git-archimport git-cvsimport git-relink git-cvsserver git-remote git-svnimport git-cvsexportcommit git-send-email git-svn git-status git-instaweb git-merge-subt!
 ree '/pro/local/bin'
install git '/pro/local/bin'
make -C templates DESTDIR='' install
make[1]: Entering directory `/pro/3gl/LINUX/git-1.5.3.7/templates'
install -d -m755 '/pro/local/share/git-core/templates/'
Usage: mv [-f] [-i] [-e warn|force|ignore] f1 f2
       mv [-f] [-i] [-e warn|force|ignore] f1 ... fn d1
       mv [-f] [-i] [-e warn|force|ignore] d1 d2
(cd blt && tar cf - .) | \
(cd '/pro/local/share/git-core/templates/' && tar xf -)
/bin/sh: /pro/local/share/git-core/templates/:  not found.
make[1]: *** [install] Error 1
make[1]: Leaving directory `/pro/3gl/LINUX/git-1.5.3.7/templates'
make: *** [install] Error 2
Exit 2

I have two:

  14241 100555 -r-x    1      bin      1888  12 Jun 2002 10:58 /opt/imake/bin/install
    634 100555 -r-x    1      bin      5147   7 Nov 1997 09:00 /usr/sbin/install

-- 
H.Merijn Brand         Amsterdam Perl Mongers (http://amsterdam.pm.org/)
using & porting perl 5.6.2, 5.8.x, 5.10.x  on HP-UX 10.20, 11.00, 11.11,
& 11.23, SuSE 10.1 & 10.2, AIX 5.2, and Cygwin.       http://qa.perl.org
http://mirrors.develooper.com/hpux/            http://www.test-smoke.org
                        http://www.goldmark.org/jeff/stupid-disclaimers/

^ permalink raw reply	[relevance 2%]

* Git and securing a repository
@ 2008-01-02  7:13  3% Gonzalo Garramuño
  2008-01-02  6:34  2% ` Felipe Balbi
  2008-01-02 16:18  1% ` Daniel Barkalow
  0 siblings, 2 replies; 200+ results
From: Gonzalo Garramuño @ 2008-01-02  7:13 UTC (permalink / raw)
  To: git


I've been using git for some time and love it.  For open source projects 
there's clearly nothing currently better.

However, I am now using git for proprietary elements, which in the 
future I may need or want to partially restrict access to.  The idea 
being that at my company some (junior) developers should not be given 
access to some elements.  That means either that some full git 
repository should be password protected or even portions of the same 
repository.

Another desirable way to protect elements might be only giving 
clone/pull access to a repository (or portion of it) but not permissions 
to push in changes.

I have not seen or read much about how git deals with accesses and 
permissions.  Can anyone point me to some documentation if some or all 
of this is possible?


-- 
Gonzalo Garramuño
ggarra@advancedsl.com.ar

AMD4400 - ASUS48N-E
GeForce7300GT
Xubuntu Gutsy

^ permalink raw reply	[relevance 3%]

* Re: Git and securing a repository
  2008-01-02  7:13  3% Git and securing a repository Gonzalo Garramuño
@ 2008-01-02  6:34  2% ` Felipe Balbi
  2008-01-02 16:18  1% ` Daniel Barkalow
  1 sibling, 0 replies; 200+ results
From: Felipe Balbi @ 2008-01-02  6:34 UTC (permalink / raw)
  To: Gonzalo Garramuño; +Cc: git

On Jan 2, 2008 2:13 AM, Gonzalo Garramuño <ggarra@advancedsl.com.ar> wrote:
>
> I've been using git for some time and love it.  For open source projects
> there's clearly nothing currently better.
>
> However, I am now using git for proprietary elements, which in the
> future I may need or want to partially restrict access to.  The idea
> being that at my company some (junior) developers should not be given
> access to some elements.  That means either that some full git
> repository should be password protected or even portions of the same
> repository.
>
> Another desirable way to protect elements might be only giving
> clone/pull access to a repository (or portion of it) but not permissions
> to push in changes.

push access is only available through ssh, so if your developer
doesn't have a ssh account on the server, he can't push code to it

>
> I have not seen or read much about how git deals with accesses and
> permissions.  Can anyone point me to some documentation if some or all
> of this is possible?

it's easy on the full repository case, create different groups and
share git repositories by groups, after that chmod o-rwx -R
/path/to/repository.git.

If a user is not the owner nor is part of that group in particular, it
wouldn't be able to push any code to the repository.

btw, if you don't start git-daemon you could use ssh to pull code as well.

thinking on the partial repository access, maybe git submodule would
help, but i've never used it.

-- 
Best Regards,

Felipe Balbi
felipebalbi@users.sourceforge.net

^ permalink raw reply	[relevance 2%]

* Re: Git and securing a repository
  2008-01-02  7:13  3% Git and securing a repository Gonzalo Garramuño
  2008-01-02  6:34  2% ` Felipe Balbi
@ 2008-01-02 16:18  1% ` Daniel Barkalow
  1 sibling, 0 replies; 200+ results
From: Daniel Barkalow @ 2008-01-02 16:18 UTC (permalink / raw)
  To: Gonzalo Garramuño; +Cc: git

[-- Attachment #1: Type: TEXT/PLAIN, Size: 2124 bytes --]

On Wed, 2 Jan 2008, Gonzalo Garramuño wrote:

> I've been using git for some time and love it.  For open source projects
> there's clearly nothing currently better.
> 
> However, I am now using git for proprietary elements, which in the future I
> may need or want to partially restrict access to.  The idea being that at my
> company some (junior) developers should not be given access to some elements.
> That means either that some full git repository should be password protected
> or even portions of the same repository.
> 
> Another desirable way to protect elements might be only giving clone/pull
> access to a repository (or portion of it) but not permissions to push in
> changes.

In order to understand the security model, you have to remember that git 
is designed as a distributed system. Authorization is fundamentally not at 
a project level, but rather at a repository level, and clones are all 
different repositories. This makes portability of the mechanism less 
important, because a particular set of authorization rules only applies to 
a particular repository, which is going to be on some single system.

For that matter, git doesn't run with any special privileges in general; 
if a user can affect the repository with git operations, that user can 
affect the repository by hand, so git-specific rules aren't helpful. 
(Although I suppose it would be theoretically useful to make git-shell, 
the shell that only runs git programs, able to apply restrictions, since 
it is used in a context where the user doesn't have any other access to 
the filesystem.)

For read access restrictions, you want to use submodules (or entirely 
separate projects); git is fundamentally unhappy running with less than 
all of the project accessible, except for when a project references 
another project with submodules. And, of course, if the code base is such 
that users can do useful work without any access to some of the files, 
those files must be optional and somewhat separate from the necessary 
portions, and it makes sense to handle them separately anyway.

	-Daniel
*This .sig left intentionally blank*

^ permalink raw reply	[relevance 1%]

* Re: valgrind test script integration
  @ 2008-01-12 11:36  2%           ` Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2008-01-12 11:36 UTC (permalink / raw)
  To: git

On Sat, Jan 12, 2008 at 06:10:44AM -0500, Jeff King wrote:

>  - We only catch calls to 'git', not 'git-foo' (and in fact for that
>    reason this doesn't catch the t7300 bug by itself, since that uses
>    git-clean). A follow-on patch will deal with this.

And here it is.

This replaces all usage of "git-foo" with "git foo" in the
test scripts. The replacement was done semi-manually; a
fully automatic replacement won't work because the pattern
"git-" appears in several other contexts (e.g.,
"--git-dir=", ref names, filenames, etc).

Obviously another route would be intercepting git-* calls,
as well, but my impression is that we are ultimately heading
towards a "git foo is the right way" situation, in which
case this cleanup is eventually necessary anyway.

[the original got eaten by the list since the patch is almost 150K;
 the diffstat is below, and I am making the patch available at

   git://repo.or.cz/git/peff.git master
]

 t/t1400-update-ref.sh                  |   10 +-
 t/t2005-checkout-index-symlinks.sh     |    4 +-
 t/t2050-git-dir-relative.sh            |    4 +-
 t/t2102-update-index-symlinks.sh       |    2 +-
 t/t2200-add-update.sh                  |   12 +-
 t/t3020-ls-files-error-unmatch.sh      |    2 +-
 t/t3030-merge-recursive.sh             |   14 +-
 t/t3200-branch.sh                      |   16 +-
 t/t3210-pack-refs.sh                   |    4 +-
 t/t3400-rebase.sh                      |    6 +-
 t/t3401-rebase-partial.sh              |   20 +-
 t/t3500-cherry.sh                      |   12 +-
 t/t3600-rm.sh                          |    4 +-
 t/t3800-mktag.sh                       |    8 +-
 t/t3900-i18n-commit.sh                 |    6 +-
 t/t3901-i18n-patch.sh                  |   16 +-
 t/t4012-diff-binary.sh                 |    2 +-
 t/t4103-apply-binary.sh                |   26 ++--
 t/t5300-pack-object.sh                 |   14 +-
 t/t5301-sliding-window.sh              |    4 +-
 t/t5302-pack-index.sh                  |   10 +-
 t/t5400-send-pack.sh                   |   30 ++--
 t/t5401-update-hooks.sh                |    4 +-
 t/t5402-post-merge-hook.sh             |    4 +-
 t/t5403-post-checkout-hook.sh          |    4 +-
 t/t5500-fetch-pack.sh                  |    4 +-
 t/t5510-fetch.sh                       |    2 +-
 t/t5530-upload-pack-error.sh           |    4 +-
 t/t5600-clone-fail-cleanup.sh          |    6 +-
 t/t6006-rev-list-format.sh             |    6 +-
 t/t6025-merge-symlinks.sh              |   32 ++--
 t/t6026-merge-attr.sh                  |   12 +-
 t/t6030-bisect-porcelain.sh            |    2 +-
 t/t6120-describe.sh                    |   30 ++--
 t/t6300-for-each-ref.sh                |   28 ++--
 t/t7001-mv.sh                          |   12 +-
 t/t7003-filter-branch.sh               |   18 +-
 t/t7004-tag.sh                         |  316 ++++++++++++++++----------------
 t/t7101-reset.sh                       |    6 +-
 t/t7300-clean.sh                       |   38 ++--
 t/t7400-submodule-basic.sh             |   46 +++---
 t/t7501-commit.sh                      |   44 +++---
 t/t9100-git-svn-basic.sh               |   44 +++---
 t/t9101-git-svn-props.sh               |   62 +++---
 t/t9102-git-svn-deep-rmdir.sh          |    6 +-
 t/t9104-git-svn-follow-parent.sh       |   36 ++--
 t/t9105-git-svn-commit-diff.sh         |    8 +-
 t/t9106-git-svn-commit-diff-clobber.sh |   12 +-
 t/t9107-git-svn-migrate.sh             |   16 +-
 t/t9108-git-svn-glob.sh                |    4 +-
 t/t9110-git-svn-use-svm-props.sh       |    8 +-
 t/t9111-git-svn-use-svnsync-props.sh   |    8 +-
 t/t9112-git-svn-md5less-file.sh        |    4 +-
 t/t9116-git-svn-log.sh                 |    4 +-
 t/t9119-git-svn-info.sh                |  120 ++++++------
 t/t9200-git-cvsexportcommit.sh         |   10 +-
 t/t9300-fast-import.sh                 |   64 ++++----
 t/t9400-git-cvsserver-server.sh        |   30 ++--
 58 files changed, 640 insertions(+), 640 deletions(-)

^ permalink raw reply	[relevance 2%]

* Git Gui: initial french translation: fr.po
@ 2008-01-15  5:24  1% Christian Couder
  0 siblings, 0 replies; 200+ results
From: Christian Couder @ 2008-01-15  5:24 UTC (permalink / raw)
  To: Shawn O. Pearce, Junio Hamano; +Cc: git

[-- Attachment #1: Type: text/plain, Size: 609 bytes --]

Here are some of the choices made to translate Git Gui to french:

- commit         -> "commit" (noun) or "commiter" (verb)
- stage (index)  -> "pré-commit" (noun) or "pré-commiter" (verb)
- (re)scan       -> "(re)synchroniser"
- reset          -> "réinitialiser"
- checkout       -> "emprunt" (noun) or "emprunter" (verb)
- revision expression -> "expression de révison"

I am not completely happy with these, but it's a start...

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---

I just attached the file instead of sending the patch because I fear
some encoding breakages.



[-- Attachment #2: fr.po --]
[-- Type: application/octet-stream, Size: 47936 bytes --]

# translation of fr.po to French
# Translation of git-gui to French.
# Copyright (C) 2008 Shawn Pearce, et al.
# This file is distributed under the same license as the git package.
#
# Christian Couder <chriscool@tuxfamily.org>, 2008.
msgid ""
msgstr ""
"Project-Id-Version: fr\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2007-11-24 10:36+0100\n"
"PO-Revision-Date: 2008-01-14 21:08+0100\n"
"Last-Translator: Christian Couder <chriscool@tuxfamily.org>\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: KBabel 1.11.4\n"
"Plural-Forms:  nplurals=2; plural=(n > 1);\n"

#: git-gui.sh:41 git-gui.sh:604 git-gui.sh:618 git-gui.sh:631 git-gui.sh:714
#: git-gui.sh:733
msgid "git-gui: fatal error"
msgstr "git-gui: erreur fatale"

#: git-gui.sh:565
#, tcl-format
msgid "Invalid font specified in %s:"
msgstr "Invalide fonte spécifiée dans %s :"

#: git-gui.sh:590
msgid "Main Font"
msgstr "Fonte principale"

#: git-gui.sh:591
msgid "Diff/Console Font"
msgstr "Fonte diff/console"

#: git-gui.sh:605
msgid "Cannot find git in PATH."
msgstr "Impossible de trouver git dans PATH."

#: git-gui.sh:632
msgid "Cannot parse Git version string:"
msgstr "Impossible de parser la version de Git :"

#: git-gui.sh:650
#, tcl-format
msgid ""
"Git version cannot be determined.\n"
"\n"
"%s claims it is version '%s'.\n"
"\n"
"%s requires at least Git 1.5.0 or later.\n"
"\n"
"Assume '%s' is version 1.5.0?\n"
msgstr ""
"Impossible de déterminer la version de Git.\n"
"\n"
"%s affirme qu'il s'agit de la version '%s'.\n"
"\n"
"%s nécessite au moins Git 1.5.0.\n"
"\n"
"Peut'on considérer que '%s' est en version 1.5.0 ?\n"

#: git-gui.sh:888
msgid "Git directory not found:"
msgstr "Impossible de trouver le répertoire de Git :"

#: git-gui.sh:895
msgid "Cannot move to top of working directory:"
msgstr "Impossible d'aller à la racine du répertoire de travail :"

#: git-gui.sh:902
msgid "Cannot use funny .git directory:"
msgstr "Impossible d'utiliser un drôle de répertoire git :"

#: git-gui.sh:907
msgid "No working directory"
msgstr "Pas de répertoire de travail"

#: git-gui.sh:1054
msgid "Refreshing file status..."
msgstr "Rafraichissement du status des fichiers..."

#: git-gui.sh:1119
msgid "Scanning for modified files ..."
msgstr "Recherche de fichiers modifiés..."

#: git-gui.sh:1294 lib/browser.tcl:245
msgid "Ready."
msgstr "Prêt."

#: git-gui.sh:1560
msgid "Unmodified"
msgstr "Non modifié"

#: git-gui.sh:1562
msgid "Modified, not staged"
msgstr "Modifié, non pré-commité"

#: git-gui.sh:1563 git-gui.sh:1568
msgid "Staged for commit"
msgstr "Pré-commité"

#: git-gui.sh:1564 git-gui.sh:1569
msgid "Portions staged for commit"
msgstr "En partie pré-commité"

#: git-gui.sh:1565 git-gui.sh:1570
msgid "Staged for commit, missing"
msgstr "Pré-commité, manquant"

#: git-gui.sh:1567
msgid "Untracked, not staged"
msgstr "Non suivi, non pré-commité"

#: git-gui.sh:1572
msgid "Missing"
msgstr "Manquant"

#: git-gui.sh:1573
msgid "Staged for removal"
msgstr "Pré-commité pour suppression"

#: git-gui.sh:1574
msgid "Staged for removal, still present"
msgstr "Pré-commité pour suppression, toujours présent"

#: git-gui.sh:1576 git-gui.sh:1577 git-gui.sh:1578 git-gui.sh:1579
msgid "Requires merge resolution"
msgstr "Nécessite la résolution d'une fusion"

#: git-gui.sh:1614
msgid "Starting gitk... please wait..."
msgstr "Lancement de gitk... merci de patienter..."

#: git-gui.sh:1623
#, tcl-format
msgid ""
"Unable to start gitk:\n"
"\n"
"%s does not exist"
msgstr ""
"Impossible de lancer gitk :\n"
"\n"
"%s inexistant"

#: git-gui.sh:1823 lib/choose_repository.tcl:35
msgid "Repository"
msgstr "Référentiel"

#: git-gui.sh:1824
msgid "Edit"
msgstr "Editer"

#: git-gui.sh:1826 lib/choose_rev.tcl:560
msgid "Branch"
msgstr "Branche"

#: git-gui.sh:1829 lib/choose_rev.tcl:547
msgid "Commit@@noun"
msgstr "Commit"

#: git-gui.sh:1832 lib/merge.tcl:121 lib/merge.tcl:150 lib/merge.tcl:168
msgid "Merge"
msgstr "Fusionner"

#: git-gui.sh:1833 lib/choose_rev.tcl:556
msgid "Remote"
msgstr "Référentiel distant"

#: git-gui.sh:1842
msgid "Browse Current Branch's Files"
msgstr "Visionner fichiers dans branche courante"

#: git-gui.sh:1846
msgid "Browse Branch Files..."
msgstr "Visionner fichiers de branche"

#: git-gui.sh:1851
msgid "Visualize Current Branch's History"
msgstr "Visualiser historique branche courante"

#: git-gui.sh:1855
msgid "Visualize All Branch History"
msgstr "Visualiser historique toutes branches"

#: git-gui.sh:1862
#, tcl-format
msgid "Browse %s's Files"
msgstr "Visionner fichiers de %s"

#: git-gui.sh:1864
#, tcl-format
msgid "Visualize %s's History"
msgstr "Visualiser historique de %s"

#: git-gui.sh:1869 lib/database.tcl:27 lib/database.tcl:67
msgid "Database Statistics"
msgstr "Statistiques base de donnée"

#: git-gui.sh:1872 lib/database.tcl:34
msgid "Compress Database"
msgstr "Comprimer base de donnée"

#: git-gui.sh:1875
msgid "Verify Database"
msgstr "Vérifier base de donnée"

#: git-gui.sh:1882 git-gui.sh:1886 git-gui.sh:1890 lib/shortcut.tcl:7
#: lib/shortcut.tcl:39 lib/shortcut.tcl:71
msgid "Create Desktop Icon"
msgstr "Créer icône sur bureau"

#: git-gui.sh:1895 lib/choose_repository.tcl:176 lib/choose_repository.tcl:184
msgid "Quit"
msgstr "Quitter"

#: git-gui.sh:1902
msgid "Undo"
msgstr "Défaire"

#: git-gui.sh:1905
msgid "Redo"
msgstr "Refaire"

#: git-gui.sh:1909 git-gui.sh:2403
msgid "Cut"
msgstr "Couper"

#: git-gui.sh:1912 git-gui.sh:2406 git-gui.sh:2477 git-gui.sh:2549
#: lib/console.tcl:67
msgid "Copy"
msgstr "Copier"

#: git-gui.sh:1915 git-gui.sh:2409
msgid "Paste"
msgstr "Coller"

#: git-gui.sh:1918 git-gui.sh:2412 lib/branch_delete.tcl:26
#: lib/remote_branch_delete.tcl:38
msgid "Delete"
msgstr "Supprimer"

#: git-gui.sh:1922 git-gui.sh:2416 git-gui.sh:2553 lib/console.tcl:69
msgid "Select All"
msgstr "Tout sélectionner"

#: git-gui.sh:1931
msgid "Create..."
msgstr "Créer..."

#: git-gui.sh:1937
msgid "Checkout..."
msgstr "Emprunter... "

#: git-gui.sh:1943
msgid "Rename..."
msgstr "Renommer..."

#: git-gui.sh:1948 git-gui.sh:2048
msgid "Delete..."
msgstr "Supprimer..."

#: git-gui.sh:1953
msgid "Reset..."
msgstr "Réinitialiser..."

#: git-gui.sh:1965 git-gui.sh:2350
msgid "New Commit"
msgstr "Nouveau commit"

#: git-gui.sh:1973 git-gui.sh:2357
msgid "Amend Last Commit"
msgstr "Corriger dernier commit"

#: git-gui.sh:1982 git-gui.sh:2317 lib/remote_branch_delete.tcl:99
msgid "Rescan"
msgstr "Resynchroniser"

#: git-gui.sh:1988
msgid "Stage To Commit"
msgstr "Commiter un pré-commit"

#: git-gui.sh:1994
msgid "Stage Changed Files To Commit"
msgstr "Commiter fichiers modifiés dans pré-commit"

#: git-gui.sh:2000
msgid "Unstage From Commit"
msgstr "Commit vers pré-commit"

#: git-gui.sh:2005 lib/index.tcl:393
msgid "Revert Changes"
msgstr "Inverser modification"

#: git-gui.sh:2012 git-gui.sh:2329 git-gui.sh:2427
msgid "Sign Off"
msgstr "Se désinscrire"

#: git-gui.sh:2016 git-gui.sh:2333
msgid "Commit@@verb"
msgstr "Commiter"

#: git-gui.sh:2027
msgid "Local Merge..."
msgstr "Fusion locale..."

#: git-gui.sh:2032
msgid "Abort Merge..."
msgstr "Abandonner fusion..."

#: git-gui.sh:2044
msgid "Push..."
msgstr "Pousser..."

#: git-gui.sh:2055 lib/choose_repository.tcl:40
msgid "Apple"
msgstr "Pomme"

#: git-gui.sh:2058 git-gui.sh:2080 lib/about.tcl:13
#: lib/choose_repository.tcl:43 lib/choose_repository.tcl:49
#, tcl-format
msgid "About %s"
msgstr "A propos de %s"

#: git-gui.sh:2062
msgid "Preferences..."
msgstr "Préférences..."

#: git-gui.sh:2070 git-gui.sh:2595
msgid "Options..."
msgstr "Options..."

#: git-gui.sh:2076 lib/choose_repository.tcl:46
msgid "Help"
msgstr "Aide"

#: git-gui.sh:2117
msgid "Online Documentation"
msgstr "Documentation en ligne"

#: git-gui.sh:2201
#, tcl-format
msgid "fatal: cannot stat path %s: No such file or directory"
msgstr "fatale : pas d'infos sur le chemin %s : Fichier ou répertoire inexistant"

#: git-gui.sh:2234
msgid "Current Branch:"
msgstr "Branche courante :"

#: git-gui.sh:2255
msgid "Staged Changes (Will Commit)"
msgstr "Modifications pré-commitées"

#: git-gui.sh:2274
msgid "Unstaged Changes"
msgstr "Modifications non pré-commitées"

#: git-gui.sh:2323
msgid "Stage Changed"
msgstr "Pré-commit modifié"

#: git-gui.sh:2339 lib/transport.tcl:93 lib/transport.tcl:182
msgid "Push"
msgstr "Pousser"

#: git-gui.sh:2369
msgid "Initial Commit Message:"
msgstr "Message de commit initial :"

#: git-gui.sh:2370
msgid "Amended Commit Message:"
msgstr "Message de commit corrigé :"

#: git-gui.sh:2371
msgid "Amended Initial Commit Message:"
msgstr "Message de commit initial corrigé :"

#: git-gui.sh:2372
msgid "Amended Merge Commit Message:"
msgstr "Message de commit de fusion corrigé :"

#: git-gui.sh:2373
msgid "Merge Commit Message:"
msgstr "Message de commit de fusion :"

#: git-gui.sh:2374
msgid "Commit Message:"
msgstr "Message de commit :"

#: git-gui.sh:2419 git-gui.sh:2557 lib/console.tcl:71
msgid "Copy All"
msgstr "Copier tout"

#: git-gui.sh:2443 lib/blame.tcl:104
msgid "File:"
msgstr "Fichier :"

#: git-gui.sh:2545
msgid "Refresh"
msgstr "Rafraichir"

#: git-gui.sh:2566
msgid "Apply/Reverse Hunk"
msgstr "Appliquer/Inverser section"

#: git-gui.sh:2572
msgid "Decrease Font Size"
msgstr "Réduire fonte"

#: git-gui.sh:2576
msgid "Increase Font Size"
msgstr "Agrandir fonte"

#: git-gui.sh:2581
msgid "Show Less Context"
msgstr "Montrer moins de contexte"

#: git-gui.sh:2588
msgid "Show More Context"
msgstr "Montrer plus de contexte"

#: git-gui.sh:2602
msgid "Unstage Hunk From Commit"
msgstr "Enlever section pré-commitée"

#: git-gui.sh:2604
msgid "Stage Hunk For Commit"
msgstr "Pré-commiter section"

#: git-gui.sh:2623
msgid "Initializing..."
msgstr "Initialisation..."

#: git-gui.sh:2718
#, tcl-format
msgid ""
"Possible environment issues exist.\n"
"\n"
"The following environment variables are probably\n"
"going to be ignored by any Git subprocess run\n"
"by %s:\n"
"\n"
msgstr ""
"Des problèmes d'environnement sont possibles.\n"
"\n"
"Les variables d'environnement suivantes seront\n"
"probablement ignorées par tous les\n"
"sous-processus de Git lancés par %s\n"
"\n"

#: git-gui.sh:2748
msgid ""
"\n"
"This is due to a known issue with the\n"
"Tcl binary distributed by Cygwin."
msgstr ""
"\n"
"Ceci est du à un problème connu avec\n"
"le binaire Tcl distribué par Cygwin."

#: git-gui.sh:2753
#, tcl-format
msgid ""
"\n"
"\n"
"A good replacement for %s\n"
"is placing values for the user.name and\n"
"user.email settings into your personal\n"
"~/.gitconfig file.\n"
msgstr ""
"\n"
"\n"
"Un bon remplacement pour %s\n"
"est de mettre les valeurs pour 'user.name' (nom\n"
"de l'utilisateur) et 'user.email' (addresse email\n"
"de l'utilisateur) dans votre fichier '~/.gitconfig'."

#: lib/about.tcl:25
msgid "git-gui - a graphical user interface for Git."
msgstr "git-gui - une interface graphique utilisateur pour Git"

#: lib/blame.tcl:77
msgid "File Viewer"
msgstr "Visionneur de fichier"

#: lib/blame.tcl:81
msgid "Commit:"
msgstr "Commit :"

#: lib/blame.tcl:249
msgid "Copy Commit"
msgstr "Copier commit"

#: lib/blame.tcl:369
#, tcl-format
msgid "Reading %s..."
msgstr "Lecture de %s..."

#: lib/blame.tcl:473
msgid "Loading copy/move tracking annotations..."
msgstr "Chargement des annotations de suivi des copies/déplacements..."

#: lib/blame.tcl:493
msgid "lines annotated"
msgstr "lignes annotées"

#: lib/blame.tcl:674
msgid "Loading original location annotations..."
msgstr "Chargement des annotations d'emplacement original"

#: lib/blame.tcl:677
msgid "Annotation complete."
msgstr "Annotation terminée."

#: lib/blame.tcl:731
msgid "Loading annotation..."
msgstr "Chargement des annotations..."

#: lib/blame.tcl:787
msgid "Author:"
msgstr "Auteur :"

#: lib/blame.tcl:791
msgid "Committer:"
msgstr "Commiteur :"

#: lib/blame.tcl:796
msgid "Original File:"
msgstr "Fichier original :"

#: lib/blame.tcl:910
msgid "Originally By:"
msgstr "A l'origine par :"

#: lib/blame.tcl:916
msgid "In File:"
msgstr "Dans le fichier :"

#: lib/blame.tcl:921
msgid "Copied Or Moved Here By:"
msgstr "Copié ou déplacé ici par :"

#: lib/branch_checkout.tcl:14 lib/branch_checkout.tcl:19
msgid "Checkout Branch"
msgstr "Emprunter branche"

#: lib/branch_checkout.tcl:23
msgid "Checkout"
msgstr "Emprunter"

#: lib/branch_checkout.tcl:27 lib/branch_create.tcl:35
#: lib/branch_delete.tcl:32 lib/branch_rename.tcl:30 lib/browser.tcl:281
#: lib/checkout_op.tcl:522 lib/choose_font.tcl:43 lib/merge.tcl:172
#: lib/option.tcl:90 lib/remote_branch_delete.tcl:42 lib/transport.tcl:97
msgid "Cancel"
msgstr "Annuler"

#: lib/branch_checkout.tcl:32 lib/browser.tcl:286
msgid "Revision"
msgstr "Révision"

#: lib/branch_checkout.tcl:36 lib/branch_create.tcl:69 lib/option.tcl:202
msgid "Options"
msgstr "Options"

#: lib/branch_checkout.tcl:39 lib/branch_create.tcl:92
msgid "Fetch Tracking Branch"
msgstr "Branche suivant récupération"

#: lib/branch_checkout.tcl:44
msgid "Detach From Local Branch"
msgstr "Détacher de branche locale"

#: lib/branch_create.tcl:22
msgid "Create Branch"
msgstr "Créer branche"

#: lib/branch_create.tcl:27
msgid "Create New Branch"
msgstr "Créer nouvelle branche"

#: lib/branch_create.tcl:31 lib/choose_repository.tcl:375
msgid "Create"
msgstr "Créer"

#: lib/branch_create.tcl:40
msgid "Branch Name"
msgstr "Nom de branche"

#: lib/branch_create.tcl:43
msgid "Name:"
msgstr "Nom :"

#: lib/branch_create.tcl:58
msgid "Match Tracking Branch Name"
msgstr "Trouver nom de branche de suivi"

#: lib/branch_create.tcl:66
msgid "Starting Revision"
msgstr "Début de révision"

#: lib/branch_create.tcl:72
msgid "Update Existing Branch:"
msgstr "Mettre à jour branche existante :"

#: lib/branch_create.tcl:75
msgid "No"
msgstr "Non"

#: lib/branch_create.tcl:80
msgid "Fast Forward Only"
msgstr "Avance rapide seulement"

#: lib/branch_create.tcl:85 lib/checkout_op.tcl:514
msgid "Reset"
msgstr "Réinitialiser"

#: lib/branch_create.tcl:97
msgid "Checkout After Creation"
msgstr "Emprunt après création"

#: lib/branch_create.tcl:131
msgid "Please select a tracking branch."
msgstr "Merci de choisir une branche de suivi"

#: lib/branch_create.tcl:140
#, tcl-format
msgid "Tracking branch %s is not a branch in the remote repository."
msgstr "La branche de suivi %s n'est pas une branche dans le référentiel distant."

#: lib/branch_create.tcl:153 lib/branch_rename.tcl:86
msgid "Please supply a branch name."
msgstr "Merci de fournir un nom de branche."

#: lib/branch_create.tcl:164 lib/branch_rename.tcl:106
#, tcl-format
msgid "'%s' is not an acceptable branch name."
msgstr "'%s' n'est pas un nom de branche acceptable."

#: lib/branch_delete.tcl:15
msgid "Delete Branch"
msgstr "Supprimer branche"

#: lib/branch_delete.tcl:20
msgid "Delete Local Branch"
msgstr "Supprimer branche locale"

#: lib/branch_delete.tcl:37
msgid "Local Branches"
msgstr "Branches locales"

#: lib/branch_delete.tcl:52
msgid "Delete Only If Merged Into"
msgstr "Supprimer ssi fusion dedans"

#: lib/branch_delete.tcl:54
msgid "Always (Do not perform merge test.)"
msgstr "Toujours (Ne pas faire de test de fusion.)"

#: lib/branch_delete.tcl:103
#, tcl-format
msgid "The following branches are not completely merged into %s:"
msgstr "Les branches suivantes ne sont pas complètement fusionnées dans %s :"

#: lib/branch_delete.tcl:115
msgid ""
"Recovering deleted branches is difficult. \n"
"\n"
" Delete the selected branches?"
msgstr ""
"Récupérer des branches supprimées est difficile.\n"
"\n"
"Supprimer les branches sélectionnées ?"

#: lib/branch_delete.tcl:141
#, tcl-format
msgid ""
"Failed to delete branches:\n"
"%s"
msgstr ""
"La suppression des branches suivantes a échouée :\n"
"%s"

#: lib/branch_rename.tcl:14 lib/branch_rename.tcl:22
msgid "Rename Branch"
msgstr "Renommer branche"

#: lib/branch_rename.tcl:26
msgid "Rename"
msgstr "Renommer"

#: lib/branch_rename.tcl:36
msgid "Branch:"
msgstr "Branche :"

#: lib/branch_rename.tcl:39
msgid "New Name:"
msgstr "Nouveau nom :"

#: lib/branch_rename.tcl:75
msgid "Please select a branch to rename."
msgstr "Merci de sélectionner une branche à renommer."

#: lib/branch_rename.tcl:96 lib/checkout_op.tcl:179
#, tcl-format
msgid "Branch '%s' already exists."
msgstr "La branche '%s' existe déjà."

#: lib/branch_rename.tcl:117
#, tcl-format
msgid "Failed to rename '%s'."
msgstr "Le renommage de '%s' a échoué."

#: lib/browser.tcl:17
msgid "Starting..."
msgstr "Lancement..."

#: lib/browser.tcl:26
msgid "File Browser"
msgstr "Visionneur de fichier"

#: lib/browser.tcl:125 lib/browser.tcl:142
#, tcl-format
msgid "Loading %s..."
msgstr "Chargement de %s..."

#: lib/browser.tcl:186
msgid "[Up To Parent]"
msgstr "[Jusqu'au parent]"

#: lib/browser.tcl:266 lib/browser.tcl:272
msgid "Browse Branch Files"
msgstr "Visionner fichiers de branches"

#: lib/browser.tcl:277 lib/choose_repository.tcl:391
#: lib/choose_repository.tcl:482 lib/choose_repository.tcl:492
#: lib/choose_repository.tcl:989
msgid "Browse"
msgstr "Visionner"

#: lib/checkout_op.tcl:79
#, tcl-format
msgid "Fetching %s from %s"
msgstr "Récupération de %s à partir de %s"

#: lib/checkout_op.tcl:127
#, tcl-format
msgid "fatal: Cannot resolve %s"
msgstr "Erreur fatale : Impossible de résoudre %s"

#: lib/checkout_op.tcl:140 lib/console.tcl:79 lib/database.tcl:31
msgid "Close"
msgstr "Fermer"

#: lib/checkout_op.tcl:169
#, tcl-format
msgid "Branch '%s' does not exist."
msgstr "La branche '%s' n'existe pas."

#: lib/checkout_op.tcl:206
#, tcl-format
msgid ""
"Branch '%s' already exists.\n"
"\n"
"It cannot fast-forward to %s.\n"
"A merge is required."
msgstr ""
"La branche '%s' existe déjà.\n"
"\n"
"Impossible d'avancer rapidement à %s.\n"
"Une fusion est nécessaire."

#: lib/checkout_op.tcl:220
#, tcl-format
msgid "Merge strategy '%s' not supported."
msgstr "La stratégie de fusion '%s' n'est pas supportée."

#: lib/checkout_op.tcl:239
#, tcl-format
msgid "Failed to update '%s'."
msgstr "La mise à jour de '%s' a échouée."

#: lib/checkout_op.tcl:251
msgid "Staging area (index) is already locked."
msgstr "L'espace de pré-commit ('index' ou 'staging') est déjà vérouillé."

#: lib/checkout_op.tcl:266
msgid ""
"Last scanned state does not match repository state.\n"
"\n"
"Another Git program has modified this repository since the last scan.  A "
"rescan must be performed before the current branch can be changed.\n"
"\n"
"The rescan will be automatically started now.\n"
msgstr ""
"L'état lors de la dernière synchronisation ne correspond plus à l'état du référentiel.\n"
"\n"
"Un autre programme Git a modifié ce référentiel depuis la dernière synchronisation. Une resynchronisation doit être effectuée avant de pouvoir modifier la branche courante.\n"
"\n"
"Cela va être fait tout de suite automatiquement.\n"

#: lib/checkout_op.tcl:322
#, tcl-format
msgid "Updating working directory to '%s'..."
msgstr "Mise à jour du répertoire courant avec '%s'..."

#: lib/checkout_op.tcl:353
#, tcl-format
msgid "Aborted checkout of '%s' (file level merging is required)."
msgstr "Emprunt de '%s' abandonné. (Il est nécessaire de fusionner des fichiers.)"

#: lib/checkout_op.tcl:354
msgid "File level merge required."
msgstr "Il est nécessaire de fusionner des fichiers."

#: lib/checkout_op.tcl:358
#, tcl-format
msgid "Staying on branch '%s'."
msgstr "Le répertoire de travail reste sur la branche '%s'."

#: lib/checkout_op.tcl:429
msgid ""
"You are no longer on a local branch.\n"
"\n"
"If you wanted to be on a branch, create one now starting from 'This Detached "
"Checkout'."
msgstr ""
"Vous n'êtes plus ur une branche locale.\n"
"\n"
"Si vous vouliez être sur une branche, créez en une maintenant en partant de 'Cet emprunt détaché'."

#: lib/checkout_op.tcl:446
#, tcl-format
msgid "Checked out '%s'."
msgstr "'%s' emprunté."

#: lib/checkout_op.tcl:478
#, tcl-format
msgid "Resetting '%s' to '%s' will lose the following commits:"
msgstr "Réinitialiser '%s' à '%s' va faire perdre les commits suivants :"

#: lib/checkout_op.tcl:500
msgid "Recovering lost commits may not be easy."
msgstr "Récupérer les commits perdus ne sera peut être pas facile."

#: lib/checkout_op.tcl:505
#, tcl-format
msgid "Reset '%s'?"
msgstr "Réinitialiser '%s' ?"

#: lib/checkout_op.tcl:510 lib/merge.tcl:164
msgid "Visualize"
msgstr "Visualiser"

#: lib/checkout_op.tcl:578
#, tcl-format
msgid ""
"Failed to set current branch.\n"
"\n"
"This working directory is only partially switched.  We successfully updated "
"your files, but failed to update an internal Git file.\n"
"\n"
"This should not have occurred.  %s will now close and give up."
msgstr ""
"Le changement de la branche courante a échoué.\n"
"\n"
"Le répertoire courant n'est que partiellement modifié. Les fichiers ont été mis à jour avec succès, mais la mise à jour d'un fichier interne à Git a échouée.\n"
"\n"
"Cela n'aurait pas du se produire. %s va abandonner et se terminer."

#: lib/choose_font.tcl:39
msgid "Select"
msgstr "Sélectionner"

#: lib/choose_font.tcl:53
msgid "Font Family"
msgstr "Famille de fonte"

#: lib/choose_font.tcl:73
msgid "Font Size"
msgstr "Taille de fonte"

#: lib/choose_font.tcl:90
msgid "Font Example"
msgstr "Exemple de fonte"

#: lib/choose_font.tcl:101
msgid ""
"This is example text.\n"
"If you like this text, it can be your font."
msgstr ""
"C'est un texte d'exemple.\n"
"Si vous aimez ce texte, vous pouvez choisir cette fonte."

#: lib/choose_repository.tcl:27
msgid "Git Gui"
msgstr "Git Gui"

#: lib/choose_repository.tcl:80 lib/choose_repository.tcl:380
msgid "Create New Repository"
msgstr "Créer nouveau référentiel"

#: lib/choose_repository.tcl:86
msgid "New..."
msgstr "Nouveau..."

#: lib/choose_repository.tcl:93 lib/choose_repository.tcl:468
msgid "Clone Existing Repository"
msgstr "Cloner référentiel existant"

#: lib/choose_repository.tcl:99
msgid "Clone..."
msgstr "Cloner..."

#: lib/choose_repository.tcl:106 lib/choose_repository.tcl:978
msgid "Open Existing Repository"
msgstr "Ouvrir référentiel existant"

#: lib/choose_repository.tcl:112
msgid "Open..."
msgstr "Ouvrir..."

#: lib/choose_repository.tcl:125
msgid "Recent Repositories"
msgstr "Référentiels récents"

#: lib/choose_repository.tcl:131
msgid "Open Recent Repository:"
msgstr "Ouvrir référentiel récent :"

#: lib/choose_repository.tcl:294
#, tcl-format
msgid "Location %s already exists."
msgstr "L'emplacement %s existe déjà."

#: lib/choose_repository.tcl:300 lib/choose_repository.tcl:307
#: lib/choose_repository.tcl:314
#, tcl-format
msgid "Failed to create repository %s:"
msgstr "La création du référentiel %s a échouée :"

#: lib/choose_repository.tcl:385 lib/choose_repository.tcl:486
msgid "Directory:"
msgstr "Répertoire :"

#: lib/choose_repository.tcl:415 lib/choose_repository.tcl:544
#: lib/choose_repository.tcl:1013
msgid "Git Repository"
msgstr "Référentiel Git"

#: lib/choose_repository.tcl:430 lib/choose_repository.tcl:437
#, tcl-format
msgid "Directory %s already exists."
msgstr "Le répertoire %s existe déjà."

#: lib/choose_repository.tcl:442
#, tcl-format
msgid "File %s already exists."
msgstr "Le fichier %s existe déjà."

#: lib/choose_repository.tcl:463
msgid "Clone"
msgstr "Cloner"

#: lib/choose_repository.tcl:476
msgid "URL:"
msgstr "URL :"

#: lib/choose_repository.tcl:496
msgid "Clone Type:"
msgstr "Type de clonage :"

#: lib/choose_repository.tcl:502
msgid "Standard (Fast, Semi-Redundant, Hardlinks)"
msgstr "Standard (rapide, semi-redondant, liens durs)"

#: lib/choose_repository.tcl:508
msgid "Full Copy (Slower, Redundant Backup)"
msgstr "Copy complète (plus lent, sauvegarde redondante)"

#: lib/choose_repository.tcl:514
msgid "Shared (Fastest, Not Recommended, No Backup)"
msgstr "Partagé (le plus rapide, non recommandé, pas de sauvegarde)"

#: lib/choose_repository.tcl:550 lib/choose_repository.tcl:597
#: lib/choose_repository.tcl:738 lib/choose_repository.tcl:808
#: lib/choose_repository.tcl:1019 lib/choose_repository.tcl:1027
#, tcl-format
msgid "Not a Git repository: %s"
msgstr "'%s' n'est pas un référentiel Git."

#: lib/choose_repository.tcl:586
msgid "Standard only available for local repository."
msgstr "Standard n'est disponible que pour un référentiel local."

#: lib/choose_repository.tcl:590
msgid "Shared only available for local repository."
msgstr "Partagé n'est disponible que pour un référentiel local."

#: lib/choose_repository.tcl:617
msgid "Failed to configure origin"
msgstr "La configuration de l'origine a échouée."

#: lib/choose_repository.tcl:629
msgid "Counting objects"
msgstr "Comptage des objets"

#: lib/choose_repository.tcl:630
msgid "buckets"
msgstr "paniers"

#: lib/choose_repository.tcl:654
#, tcl-format
msgid "Unable to copy objects/info/alternates: %s"
msgstr "Impossible de copier 'objects/info/alternates' : %s"

#: lib/choose_repository.tcl:690
#, tcl-format
msgid "Nothing to clone from %s."
msgstr "Il n'y a rien à cloner depuis %s."

#: lib/choose_repository.tcl:692 lib/choose_repository.tcl:906
#: lib/choose_repository.tcl:918
msgid "The 'master' branch has not been initialized."
msgstr "Cette branche 'master' n'a pas été initialisée."

#: lib/choose_repository.tcl:705
msgid "Hardlinks are unavailable.  Falling back to copying."
msgstr "Les liens durs ne sont pas disponibles. On se résoud à copier."

#: lib/choose_repository.tcl:717
#, tcl-format
msgid "Cloning from %s"
msgstr "Clonage depuis %s"

#: lib/choose_repository.tcl:748
msgid "Copying objects"
msgstr "Copie des objets"

#: lib/choose_repository.tcl:749
msgid "KiB"
msgstr "KiB"

#: lib/choose_repository.tcl:773
#, tcl-format
msgid "Unable to copy object: %s"
msgstr "Impossible de copier l'objet : %s"

#: lib/choose_repository.tcl:783
msgid "Linking objects"
msgstr "Liaison des objets"

#: lib/choose_repository.tcl:784
msgid "objects"
msgstr "objets"

#: lib/choose_repository.tcl:792
#, tcl-format
msgid "Unable to hardlink object: %s"
msgstr "Impossible créer un lien dur pour l'objet : %s"

#: lib/choose_repository.tcl:847
msgid "Cannot fetch branches and objects.  See console output for details."
msgstr "Impossible de récupérer les branches et objets. Voir la sortie console pour plus de détails."

#: lib/choose_repository.tcl:858
msgid "Cannot fetch tags.  See console output for details."
msgstr "Impossible de récupérer les marques. Voir la sortie console pour plus de détails."

#: lib/choose_repository.tcl:882
msgid "Cannot determine HEAD.  See console output for details."
msgstr "Impossible de déterminer HEAD. Voir la sortie console pour plus de détails."

#: lib/choose_repository.tcl:891
#, tcl-format
msgid "Unable to cleanup %s"
msgstr "Impossible de nettoyer %s"

#: lib/choose_repository.tcl:897
msgid "Clone failed."
msgstr "Le clonage a échoué."

#: lib/choose_repository.tcl:904
msgid "No default branch obtained."
msgstr "Aucune branche par défaut n'a été obtenue."

#: lib/choose_repository.tcl:915
#, tcl-format
msgid "Cannot resolve %s as a commit."
msgstr "Impossible de résoudre %s comme commit."

#: lib/choose_repository.tcl:927
msgid "Creating working directory"
msgstr "Création du répertoire de travail"

#: lib/choose_repository.tcl:928 lib/index.tcl:65 lib/index.tcl:127
#: lib/index.tcl:193
msgid "files"
msgstr "fichiers"

#: lib/choose_repository.tcl:957
msgid "Initial file checkout failed."
msgstr "L'emprunt initial de fichier a échoué."

#: lib/choose_repository.tcl:973
msgid "Open"
msgstr "Ouvrir"

#: lib/choose_repository.tcl:983
msgid "Repository:"
msgstr "Référentiel :"

#: lib/choose_repository.tcl:1033
#, tcl-format
msgid "Failed to open repository %s:"
msgstr "Impossible d'ouvrir le référentiel %s :"

#: lib/choose_rev.tcl:53
msgid "This Detached Checkout"
msgstr "Cet emprunt détaché"

#: lib/choose_rev.tcl:60
msgid "Revision Expression:"
msgstr "Expression de révision :"

#: lib/choose_rev.tcl:74
msgid "Local Branch"
msgstr "Branche locale"

#: lib/choose_rev.tcl:79
msgid "Tracking Branch"
msgstr "Suivi de branche"

#: lib/choose_rev.tcl:84 lib/choose_rev.tcl:537
msgid "Tag"
msgstr "Marque"

#: lib/choose_rev.tcl:317
#, tcl-format
msgid "Invalid revision: %s"
msgstr "Révision invalide : %s"

#: lib/choose_rev.tcl:338
msgid "No revision selected."
msgstr "Pas de révision selectionnée."

#: lib/choose_rev.tcl:346
msgid "Revision expression is empty."
msgstr "L'expression de révision est vide."

#: lib/choose_rev.tcl:530
msgid "Updated"
msgstr "Misa à jour"

#: lib/choose_rev.tcl:558
msgid "URL"
msgstr "URL"

#: lib/commit.tcl:9
msgid ""
"There is nothing to amend.\n"
"\n"
"You are about to create the initial commit.  There is no commit before this "
"to amend.\n"
msgstr ""
"Il n'y a rien à corriger.\n"
"\n"
"Vous allez créer le commit initial. Il n'y a pas de commit avant celui-ci à corriger.\n"

#: lib/commit.tcl:18
msgid ""
"Cannot amend while merging.\n"
"\n"
"You are currently in the middle of a merge that has not been fully "
"completed.  You cannot amend the prior commit unless you first abort the "
"current merge activity.\n"
msgstr ""
"Impossible de corriger pendant une fusion.\n"
"\n"
"Vous êtes actuellement au milieu d'une fusion qui n'a pas été completement terminée. Vous ne pouvez pas corriger le commit précédant sauf si vous abandonnez la fusion courante.\n"

#: lib/commit.tcl:49
msgid "Error loading commit data for amend:"
msgstr "Erreur lors du chargement des données de commit pour correction :"

#: lib/commit.tcl:76
msgid "Unable to obtain your identity:"
msgstr "Impossible d'obtenir votre identité :"

#: lib/commit.tcl:81
msgid "Invalid GIT_COMMITTER_IDENT:"
msgstr "GIT_COMMITTER_IDENT invalide :"

#: lib/commit.tcl:133
msgid ""
"Last scanned state does not match repository state.\n"
"\n"
"Another Git program has modified this repository since the last scan.  A "
"rescan must be performed before another commit can be created.\n"
"\n"
"The rescan will be automatically started now.\n"
msgstr ""
"L'état lors de la dernière synchronisation ne correspond plus à l'état du référentiel.\n"
"\n"
"Un autre programme Git a modifié ce référentiel depuis la dernière synchronisation. Une resynshronisation doit être effectuée avant de pouvoir créer un nouveau commit.\n"
"\n"
"Cela va être fait tout de suite automatiquement.\n"

#: lib/commit.tcl:154
#, tcl-format
msgid ""
"Unmerged files cannot be committed.\n"
"\n"
"File %s has merge conflicts.  You must resolve them and stage the file "
"before committing.\n"
msgstr ""
"Des fichiers non fusionnés ne peuvent être commités.\n"
"\n"
"Le fichier %s a des conflicts de fusion. Vous devez les résoudre et pré-commiter le fichier avant de pouvoir commiter.\n"

#: lib/commit.tcl:162
#, tcl-format
msgid ""
"Unknown file state %s detected.\n"
"\n"
"File %s cannot be committed by this program.\n"
msgstr ""
"Un état de fichier inconnu %s a été détecté.\n"
"\n"
"Le fichier %s ne peut pas être commité par ce programme.\n"

#: lib/commit.tcl:170
msgid ""
"No changes to commit.\n"
"\n"
"You must stage at least 1 file before you can commit.\n"
msgstr ""
"Pas de modification à commiter.\n"
"\n"
"Vous devez pré-commiter au moins 1 fichier avant de pouvoir commiter.\n"

#: lib/commit.tcl:183
msgid ""
"Please supply a commit message.\n"
"\n"
"A good commit message has the following format:\n"
"\n"
"- First line: Describe in one sentence what you did.\n"
"- Second line: Blank\n"
"- Remaining lines: Describe why this change is good.\n"
msgstr ""
"Merci de fournir un message de commit.\n"
"\n"
"Un bon message de commit a le format suivant :\n"
"\n"
"- Première ligne : décrire en une phrase ce que vous avez fait.\n"
"- Deuxième ligne : rien.\n"
"- Lignes suivantes : Décrire pourquoi ces modifications sont bonnes.\n"

#: lib/commit.tcl:257
msgid "write-tree failed:"
msgstr "write-tree a échoué :"

#: lib/commit.tcl:275
#, tcl-format
msgid "Commit %s appears to be corrupt"
msgstr "Le commit %s semble être corrompu"

#: lib/commit.tcl:279
msgid ""
"No changes to commit.\n"
"\n"
"No files were modified by this commit and it was not a merge commit.\n"
"\n"
"A rescan will be automatically started now.\n"
msgstr ""
"Pas de modification à commiter.\n"
"\n"
"Aucun fichier n'a été modifié par ce commit et il ne s'agit pas d'un commit de fusion.\n"
"\n"
"Une resynchronisation va être lancée tout de suite automatiquement.\n"

#: lib/commit.tcl:286
msgid "No changes to commit."
msgstr "Pas de modifications à commiter."

#: lib/commit.tcl:303
#, tcl-format
msgid "warning: Tcl does not support encoding '%s'."
msgstr "attention : Tcl ne supporte pas l'encodage '%s'."

#: lib/commit.tcl:317
msgid "commit-tree failed:"
msgstr "commit-tree a échoué :"

#: lib/commit.tcl:339
msgid "update-ref failed:"
msgstr "update-ref a échoué"

#: lib/commit.tcl:430
#, tcl-format
msgid "Created commit %s: %s"
msgstr "Commit créé %s : %s"

#: lib/console.tcl:57
msgid "Working... please wait..."
msgstr "Travail en cours... merci de patienter..."

#: lib/console.tcl:183
msgid "Success"
msgstr "Succès"

#: lib/console.tcl:196
msgid "Error: Command Failed"
msgstr "Erreur : échec de la commande"

#: lib/database.tcl:43
msgid "Number of loose objects"
msgstr "Nombre d'objets en fichier particulier"

#: lib/database.tcl:44
msgid "Disk space used by loose objects"
msgstr "Espace disque utilisé par les fichiers particuliers"

#: lib/database.tcl:45
msgid "Number of packed objects"
msgstr "Nombre d'objets empaquetés"

#: lib/database.tcl:46
msgid "Number of packs"
msgstr "Nombre de paquets d'objets"

#: lib/database.tcl:47
msgid "Disk space used by packed objects"
msgstr "Espace disque utilisé par les objets empaquetés"

#: lib/database.tcl:48
msgid "Packed objects waiting for pruning"
msgstr "Objets empaquetés attendant d'être supprimés"

#: lib/database.tcl:49
msgid "Garbage files"
msgstr "Fichiers poubelle"

#: lib/database.tcl:72ets
msgid "Compressing the object database"
msgstr "Compression de la base des objets"

#: lib/database.tcl:83
msgid "Verifying the object database with fsck-objects"
msgstr "Vérification de la base des objets avec fsck-objects"

#: lib/database.tcl:108
#, tcl-format
msgid ""
"This repository currently has approximately %i loose objects.\n"
"\n"
"To maintain optimal performance it is strongly recommended that you compress "
"the database when more than %i loose objects exist.\n"
"\n"
"Compress the database now?"
msgstr ""
"Ce référentiel comprend actuellement environ %i objets ayant leur fichier particulier.\n"
"\n"
"Pour conserver une performance optimale, il est fortement recommandé de comprimer la base quand plus de %i objets ayant leur fichier particulier existent.\n"
"\n"
"Comprimer la base maintenant ?"

#: lib/date.tcl:25
#, tcl-format
msgid "Invalid date from Git: %s"
msgstr "Date invalide de Git : %s"

#: lib/diff.tcl:42
#, tcl-format
msgid ""
"No differences detected.\n"
"\n"
"%s has no changes.\n"
"\n"
"The modification date of this file was updated by another application, but "
"the content within the file was not changed.\n"
"\n"
"A rescan will be automatically started to find other files which may have "
"the same state."
msgstr ""
"Aucune différence détectée.\n"
"\n"
"%s ne comporte aucune modification.\n"
"\n"
"La date de modification de ce fichier a été mise à jour par une autre application, mais le contenu du fichier n'a pas changé.\n"
"\n"
"Une resynchronisation va être lancée automatiquement pour trouver d'autres fichiers qui pourraient se trouver dans le même état."

#: lib/diff.tcl:81
#, tcl-format
msgid "Loading diff of %s..."
msgstr "Chargement des différences de %s..."

#: lib/diff.tcl:114 lib/diff.tcl:184
#, tcl-format
msgid "Unable to display %s"
msgstr "Impossible d'afficher %s"

#: lib/diff.tcl:115
msgid "Error loading file:"
msgstr "Erreur lors du chargement du fichier :"

#: lib/diff.tcl:122
msgid "Git Repository (subproject)"
msgstr "Référentiel Git (sous projet)"

#: lib/diff.tcl:134
msgid "* Binary file (not showing content)."
msgstr "* Fichier binaire (pas d'apperçu du contenu)."

#: lib/diff.tcl:185
msgid "Error loading diff:"
msgstr "Erreur lors du chargement des différences :"

#: lib/diff.tcl:302
msgid "Failed to unstage selected hunk."
msgstr "La suppression dans le pré-commit de la section sélectionnée a échouée."

#: lib/diff.tcl:309
msgid "Failed to stage selected hunk."
msgstr "Le pré-commit de la section sélectionnée a échoué."

#: lib/error.tcl:12 lib/error.tcl:102
msgid "error"
msgstr "erreur"

#: lib/error.tcl:28
msgid "warning"
msgstr "attention"

#: lib/error.tcl:81
msgid "You must correct the above errors before committing."
msgstr "Vous devez corriger les erreurs suivantes avant de pouvoir commiter."

#: lib/index.tcl:6
msgid "Unable to unlock the index."
msgstr "Impossible de dévérouiller le pré-commit."

#: lib/index.tcl:15
msgid "Index Error"
msgstr "Erreur de pré-commit"

#: lib/index.tcl:21
msgid ""
"Updating the Git index failed.  A rescan will be automatically started to "
"resynchronize git-gui."
msgstr "Le pré-commit a échoué. Une resynchronisation va être lancée automatiquement."

#: lib/index.tcl:27
msgid "Continue"
msgstr "Continuer"

#: lib/index.tcl:31
msgid "Unlock Index"
msgstr "Dévérouiller le pré-commit"

#: lib/index.tcl:282
#, tcl-format
msgid "Unstaging %s from commit"
msgstr "Supprimer %s du commit"

#: lib/index.tcl:326
#, tcl-format
msgid "Adding %s"
msgstr "Ajouter %s"

#: lib/index.tcl:381
#, tcl-format
msgid "Revert changes in file %s?"
msgstr "Inverser les modifications dans le fichier %s ? "

#: lib/index.tcl:383
#, tcl-format
msgid "Revert changes in these %i files?"
msgstr "Inverser les modifications dans ces %i fichiers ?"

#: lib/index.tcl:389
msgid "Any unstaged changes will be permanently lost by the revert."
msgstr "Toutes les modifications non pré-commitées seront définitivement perdues lors de l'inversion."

#: lib/index.tcl:392
msgid "Do Nothing"
msgstr "Ne rien faire"

#: lib/merge.tcl:13
msgid ""
"Cannot merge while amending.\n"
"\n"
"You must finish amending this commit before starting any type of merge.\n"
msgstr ""
"Impossible de fucionner pendant une correction.\n"
"\n"
"Vous devez finir de corriger ce commit avant de lancer une quelconque fusion.\n"

#: lib/merge.tcl:27
msgid ""
"Last scanned state does not match repository state.\n"
"\n"
"Another Git program has modified this repository since the last scan.  A "
"rescan must be performed before a merge can be performed.\n"
"\n"
"The rescan will be automatically started now.\n"
msgstr ""
"L'état lors de la dernière synchronisation ne correspond plus à l'état du référentiel.\n"
"\n"
"Un autre programme Git a modifié ce référentiel depuis la dernière synchronisation. Une resynchronisation doit être effectuée avant de pouvoir fusionner de nouveau.\n"
"\n"
"Cela va être fait tout de suite automatiquement\n"

#: lib/merge.tcl:44
#, tcl-format
msgid ""
"You are in the middle of a conflicted merge.\n"
"\n"
"File %s has merge conflicts.\n"
"\n"
"You must resolve them, stage the file, and commit to complete the current "
"merge.  Only then can you begin another merge.\n"
msgstr ""
"Vous êtes au milieu d'une fusion conflictuelle.\n"
"\n"
"Le fichier %s a des conflicts de fusion.\n"
"\n"
"Vous devez les résoudre, puis pré-commiter le fichier, et enfin commiter pour terminer la fusion courante. Seulementà ce moment là, il sera possible d'effectuer une nouvelle fusion.\n"

#: lib/merge.tcl:54
#, tcl-format
msgid ""
"You are in the middle of a change.\n"
"\n"
"File %s is modified.\n"
"\n"
"You should complete the current commit before starting a merge.  Doing so "
"will help you abort a failed merge, should the need arise.\n"
msgstr ""
"Vous êtes au milieu d'une modification.\n"
"\n"
"Le fichier %s est modifié.\n"
"\n"
"Vous devriez terminer le commit courant avant de lancer une fusion. En faisait comme cela, vous éviterez de devoir éventuellement abandonner une fusion ayant échouée.\n"

#: lib/merge.tcl:106
#, tcl-format
msgid "%s of %s"
msgstr "%s de %s"

#: lib/merge.tcl:119
#, tcl-format
msgid "Merging %s and %s"
msgstr "Fusion de %s et %s"

#: lib/merge.tcl:131
msgid "Merge completed successfully."
msgstr "La fusion s'est faite avec succès."

#: lib/merge.tcl:133
msgid "Merge failed.  Conflict resolution is required."
msgstr "La fusion a echouée. Il est nécessaire de résoudre les conflicts."

#: lib/merge.tcl:158
#, tcl-format
msgid "Merge Into %s"
msgstr "Fusion dans %s"

#: lib/merge.tcl:177
msgid "Revision To Merge"
msgstr "Révision à fusionner"

#: lib/merge.tcl:212
msgid ""
"Cannot abort while amending.\n"
"\n"
"You must finish amending this commit.\n"
msgstr ""
"Impossible d'abandonner en cours de correction.\n"
"\n"
"Vous devez finir de corriger ce commit.\n"

#: lib/merge.tcl:222
msgid ""
"Abort merge?\n"
"\n"
"Aborting the current merge will cause *ALL* uncommitted changes to be lost.\n"
"\n"
"Continue with aborting the current merge?"
msgstr ""
"Abandonner la fusion ?\n"
"\n"
"Abandonner la fusion courante entrainera la perte de TOUTES les modifications non commitées.\n"
"\n"
"Abandonner quand même la fusion courante ?"

#: lib/merge.tcl:228
msgid ""
"Reset changes?\n"
"\n"
"Resetting the changes will cause *ALL* uncommitted changes to be lost.\n"
"\n"
"Continue with resetting the current changes?"
msgstr ""
"Réinitialiser les modifications ?\n"
"\n"
"Réinitialiser les modifications va faire perdre TOUTES les modifications non commitées.\n"
"\n"
"Réinitialiser quand même les modifications courantes ?"

#: lib/merge.tcl:239
msgid "Aborting"
msgstr "Abandon"

#: lib/merge.tcl:266
msgid "Abort failed."
msgstr "L'abandon a échoué."

#: lib/merge.tcl:268
msgid "Abort completed.  Ready."
msgstr "Abandon teminé. Prêt."

#: lib/option.tcl:82
msgid "Restore Defaults"
msgstr "Remettre les valeurs par défaut"

#: lib/option.tcl:86
msgid "Save"
msgstr "Sauvegarder"

#: lib/option.tcl:96
#, tcl-format
msgid "%s Repository"
msgstr "Référentiel de %s"

#: lib/option.tcl:97
msgid "Global (All Repositories)"
msgstr "Globales (tous les référentiels)"

#: lib/option.tcl:103
msgid "User Name"
msgstr "Nom d'utilisateur"

#: lib/option.tcl:104
msgid "Email Address"
msgstr "Adresse email"

#: lib/option.tcl:106
msgid "Summarize Merge Commits"
msgstr "Résumer les commits de fusion"

#: lib/option.tcl:107
msgid "Merge Verbosity"
msgstr "Fusion bavarde"

#: lib/option.tcl:108
msgid "Show Diffstat After Merge"
msgstr "Montrer statistiques de diff après fusion"

#: lib/option.tcl:110
msgid "Trust File Modification Timestamps"
msgstr "Faire confiance aux dates de modification de fichiers "

#: lib/option.tcl:111
msgid "Prune Tracking Branches During Fetch"
msgstr "Nettoyer les branches de suivi pendant la récupération"

#: lib/option.tcl:112
msgid "Match Tracking Branches"
msgstr "Faire correspondre les branches de suivi"

#: lib/option.tcl:113
msgid "Number of Diff Context Lines"
msgstr "Nombre de lignes de contexte dans les diffs"

#: lib/option.tcl:114
msgid "New Branch Name Template"
msgstr "Nouveau modèle de nom de branche"

#: lib/option.tcl:176
msgid "Change Font"
msgstr "Modifier les fontes"

#: lib/option.tcl:180
#, tcl-format
msgid "Choose %s"
msgstr "Choisir %s"

#: lib/option.tcl:186
msgid "pt."
msgstr "pt."

#: lib/option.tcl:200
msgid "Preferences"
msgstr "Préférences"

#: lib/option.tcl:235
msgid "Failed to completely save options:"
msgstr "La sauvegarde complète des options a échouée :"

#: lib/remote_branch_delete.tcl:29 lib/remote_branch_delete.tcl:34
msgid "Delete Remote Branch"
msgstr "Supprimer branche distante"

#: lib/remote_branch_delete.tcl:47
msgid "From Repository"
msgstr "Référentiel"

#: lib/remote_branch_delete.tcl:50 lib/transport.tcl:123
msgid "Remote:"
msgstr "Branche distante :"

#: lib/remote_branch_delete.tcl:66 lib/transport.tcl:138
msgid "Arbitrary URL:"
msgstr "URL arbitraire :"

#: lib/remote_branch_delete.tcl:84
msgid "Branches"
msgstr "Branches"

#: lib/remote_branch_delete.tcl:109
msgid "Delete Only If"
msgstr "Supprimer seulement si"

#: lib/remote_branch_delete.tcl:111
msgid "Merged Into:"
msgstr "Fusionné dans :"

#: lib/remote_branch_delete.tcl:119
msgid "Always (Do not perform merge checks)"
msgstr "Toujours (ne pas vérifier les fusions)"

#: lib/remote_branch_delete.tcl:152
msgid "A branch is required for 'Merged Into'."
msgstr "Une branche est nécessaire pour 'Fusionné dans'."

#: lib/remote_branch_delete.tcl:184
#, tcl-format
msgid ""
"The following branches are not completely merged into %s:\n"
"\n"
" - %s"
msgstr ""
"Les branches suivantes ne sont pas complètement fusionnées dans %s :\n"
"\n"
" - %s"

#: lib/remote_branch_delete.tcl:189
#, tcl-format
msgid ""
"One or more of the merge tests failed because you have not fetched the "
"necessary commits.  Try fetching from %s first."
msgstr "Une ou plusieurs des tests de fusion ont échoués parce que vous n'avez pas récupéré les commits nécessaires. Essayez de récupéré à partir de %s d'abord."

#: lib/remote_branch_delete.tcl:207
msgid "Please select one or more branches to delete."
msgstr "Merci de sélectionner une ou plusieurs branches à supprimer."

#: lib/remote_branch_delete.tcl:216
msgid ""
"Recovering deleted branches is difficult.\n"
"\n"
"Delete the selected branches?"
msgstr ""
"Récupérer des branches supprimées est difficile.\n"
"\n"
"Souhaitez vous supprimer les branches sélectionnées ?"

#: lib/remote_branch_delete.tcl:226
#, tcl-format
msgid "Deleting branches from %s"
msgstr "Supprimer les branches de %s"

#: lib/remote_branch_delete.tcl:286
msgid "No repository selected."
msgstr "Aucun référentiel n'est sélectionné."

#: lib/remote_branch_delete.tcl:291
#, tcl-format
msgid "Scanning %s..."
msgstr "Synchronisation de %s..."

#: lib/remote.tcl:165
msgid "Prune from"
msgstr "Nettoyer de"

#: lib/remote.tcl:170
msgid "Fetch from"
msgstr "Récupérer de"

#: lib/remote.tcl:213
msgid "Push to"
msgstr "Pousser vers"

#: lib/shortcut.tcl:20 lib/shortcut.tcl:61
msgid "Cannot write shortcut:"
msgstr "Impossible d'écrire le raccourcis :"

#: lib/shortcut.tcl:136
msgid "Cannot write icon:"
msgstr "Impossible d'écrire l'icône :"

#: lib/status_bar.tcl:83
#, tcl-format
msgid "%s ... %*i of %*i %s (%3i%%)"
msgstr "%s ... %*i de %*i %s (%3i%%)"

#: lib/transport.tcl:6
#, tcl-format
msgid "fetch %s"
msgstr "récupérer %s"

#: lib/transport.tcl:7
#, tcl-format
msgid "Fetching new changes from %s"
msgstr "Récupération des dernières modifications de %s"

#: lib/transport.tcl:18
#, tcl-format
msgid "remote prune %s"
msgstr "nettoyer à distance %s"

#: lib/transport.tcl:19
#, tcl-format
msgid "Pruning tracking branches deleted from %s"
msgstr "Nettoyer les branches de suivi supprimées de %s"

#: lib/transport.tcl:25 lib/transport.tcl:71
#, tcl-format
msgid "push %s"
msgstr "pousser %s"

#: lib/transport.tcl:26
#, tcl-format
msgid "Pushing changes to %s"
msgstr "Les modifications sont poussées vers %s"

#: lib/transport.tcl:72
#, tcl-format
msgid "Pushing %s %s to %s"
msgstr "Pousse %s %s vers %s"

#: lib/transport.tcl:89
msgid "Push Branches"
msgstr "Pousser branches"

#: lib/transport.tcl:103
msgid "Source Branches"
msgstr "Branches source"

#: lib/transport.tcl:120
msgid "Destination Repository"
msgstr "Référentiel de destination"

#: lib/transport.tcl:158
msgid "Transfer Options"
msgstr "Transférer options"

#: lib/transport.tcl:160
msgid "Force overwrite existing branch (may discard changes)"
msgstr "Forcer l'écrasement d'une branche existante (peut supprimer des modifications)"

#: lib/transport.tcl:164
msgid "Use thin pack (for slow network connections)"
msgstr "Utiliser des petits paquets (pour les connexions lentes)"

#: lib/transport.tcl:168
msgid "Include tags"
msgstr "Inclure les marques"


^ permalink raw reply	[relevance 1%]

* Re: [PATCH] http-push: making HTTP push more robust and more user-friendly
  @ 2008-01-19 15:21  2%   ` Grégoire Barbier
  0 siblings, 0 replies; 200+ results
From: Grégoire Barbier @ 2008-01-19 15:21 UTC (permalink / raw)
  To: Junio C Hamano, Johannes Schindelin; +Cc: git, Mike Hommey

Hi Junio, Hi Johannes,

I recently sent three patches about http-push:
>  $gmane/70406 <1200250979-19604-1-git-send-email-gb@gbarbier.org>
>  $gmane/70407 <1200250979-19604-2-git-send-email-gb@gbarbier.org>
>  $gmane/70405 <1200250979-19604-3-git-send-email-gb@gbarbier.org>

I saw that Junio has already applied one of them (the one that disable 
http-push without USE_CURL_MULTI).

I wont talk about the second one "fix webdav lock leak" in the present 
mail but in another one, since Johannes has found severe bugs in it. I 
prefer to make them separate subjects.

As for the third patch ("making HTTP push more robust and more 
user-friendly"), I recall the commit message here:

>  Grégoire Barbier <gb@gbarbier.org> writes:
> > Fail when info/refs exists and is already locked (avoiding strange
> > behaviour and errors, and maybe avoiding some repository
> > corruption).
> >
> > Warn if the URL does not end with '/' (since 302 is not yet
> > handled)
> >
> > More explicit error message when the URL or password is not set
> > correctly (instead of "no DAV locking support").
> >
> > DAV locking time of 1 minute instead of 10 minutes (avoid waiting
> > 10 minutes for a orphan lock to expire before anyone can do a push
> > on the repo).

I agree that it should be improved seriously in several ways. I will 
submit the patch again with following improvements.

1) I will split the patch into several ones, to enable Junio to apply it 
partially.

Junio C Hamano a écrit :
>  there is no correct timeout that is good for everybody, the last item
>  might be contentious.

2) I won't change the timeout to avoid possible side effects for other 
things I don't know about since I'm rather new to git.

Johannes Schindelin a écrit :
>  This patch makes http-push Warn if URL does not end if "/", but it
>  would be even better to just handle it... we know exactly that HTTP
>  URLs _must_ end in a slash.

3) Rather than warning if the URL does not end with a slash, I will add 
the slash, so that this will work, even without having to handle 
HTTP/302 in curl calls. BTW I will do the same for http-fetch either.

Johannes Schindelin a écrit :
>  It gives a better warning if the URL cannot be accessed, alright. But
>  I hate the fact that it introduces yet another function which does a
>  bunch of curl_easy_setopt()s only to start an active slot and check
>  for errors.
>
>  Currently, I am not familiar enough with http-push.c to suggest a
>  proper alternative, but I suspect that the return values of the
>  _existing_ calls to curl should know precisely why the requests
>  failed, and _this_ should be reported.

Mike Hommey a écrit :
 > FWIW, I have a work in progress refactoring the http code, avoiding a
 > great amount of curl_easy_setopt()s and simplifying the whole thing.
 > It's been sitting on my hard drive during my (quite long) vacation. I
 > will probably start working again on this soonish.

4) I agree with Johannes. However I am not familiar enough with curl to 
write the proper alternative. I create the new function by copy/paste of 
an existing one. I'm not 100% sure that it  has no resource leaks or 
other bugs, but it's called only once at http-push start, and thus is 
likely not to do heavy damage...

As a rationale: I've tried to make several developers use git over http, 
including push, and they made all the same beginner mistakes on the 
command line, all leading to that stupid error message about locking not 
available, and I think that making a clearer error message is an 
important improvement to make not-so-skilled developers using git when 
neither ssh nor git protocols are available.

Therefore I think that applying my patch, even if it's far from being 
perfect, is the lesser of two evils.

Then, for instance during 1.5.5 development cycle, I would be happy to 
help Mike if I can, to clean my new code that he is likelly not to have 
cleaned up on his hard disk during his vacation...
For instance I may look at his patches and take them in example to clean 
up my code.


Apart from the discussion on the source code, I would like to reply to 
Junio about the patch disabling http-push without USE_CURL_MULTI:
Junio C Hamano a écrit :
>  Also http-push being unusable without CURL_MULTI was also a news to
>  me.  Is this something that came up on #git perhaps?
>
>  This change means people need curl 7.10 or newer (post May 2003, that
>  is).  I do not think it is too new a version to require, but then it
>  makes me wonder if it makes much sense for us to keep supporting non
>  CURL_MULTI build these days.  Perhaps we should schedule such a move
>  to drop non MULTI build in the future?

I don't know if USE_CURL_MULTI works well for other git binaries than 
http-push (although I've used it successfully two or three times with 
clone and fetch).

If yes, I think that the release notes, or whatever information channel 
you can have with the various distribution maintainers, should advice to 
compile with USE_CURL_MULTI. Or we can make it the default compilation 
option in a future release (> 1.5.4 I think).

If USE_CURL_MULTI is not safe for other binaries than http-push, I think 
I should manage to make a new patch, let's say for git-1.5.5, that would 
change the makefile to use CURL_MULTI by default on http-push (for 
example without -DNEVER_USE_CURL_MULTI) and leave alone other binaries 
as they are (CURL_MULTI disabled without -DUSE_CURL_MULTI).

I want to insist that the present patch for 1.5.4 (which you've already 
applied to git.git), does not introduce by itself a dependence or a 
regression, it only disables unwarned users to call a function that does 
not work, but pretends to work and by the way corrupts the remote 
repository.

I thank you very much for the time you spent reviewing my patches and 
more generally for the work you do. I'll try to improve the way I submit 
patches to make them take you less time to review.

-- 
Grégoire Barbier - gb à gbarbier.org - +33 6 21 35 73 49

^ permalink raw reply	[relevance 2%]

* Re: [PATCH] RFC: git lazy clone proof-of-concept
    @ 2008-02-08 20:16  4% ` Johannes Schindelin
    2 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2008-02-08 20:16 UTC (permalink / raw)
  To: Jan Holesovsky; +Cc: git, gitster

Hi,

2nd part of my review:

On Fri, 8 Feb 2008, Jan Holesovsky wrote:

> +static void read_from_stdin(int *num, char ***records)
> +{
> +	char buffer[4096];
> +	size_t records_num, leftover;
> +	ssize_t ret;
> +
> +	*num = 0;
> +	leftover = 0;
> +
> +	records_num = 4096;
> +	(*records) = xmalloc(records_num * sizeof(char *));
> +
> +	do {
> +		char *p, *last;
> +
> +		ret = xread(0 /*stdin*/, buffer + leftover,
> +				sizeof(buffer) - leftover);
> +		if (ret < 0)
> +			die("read error on input: %s", strerror(errno));
> +
> +		last = buffer;
> +		for (p = buffer; p < buffer + leftover + ret; p++)
> +			if ((!*p || *p == '\n') && (p != last)) {
> +				if (*num >= records_num) {
> +					records_num *= 2;
> +					(*records) = xrealloc(*records,
> +							      records_num * sizeof(char*));
> +				}
> +
> +				if (p - last > 0) {
> +					(*records)[*num] =
> +						strndup(last, p - last);
> +					(*num)++;
> +				}
> +				last = p + 1;
> +			}
> +		memmove(buffer, last, leftover);
> +	} while (ret > 0);
> +
> +	if (leftover) {
> +		if (*num >= records_num) {
> +			records_num *= 2;
> +			(*records) = xrealloc(*records,
> +					      records_num * sizeof(char*));
> +		}
> +
> +		(*records)[*num] = strndup(buffer, leftover);
> +		(*num)++;
> +	}
> +}

I thought about this function again.  It seems we have something similar 
in builtin-pack-objects.c, which is easier to read.  The equivalent would 
be:

static void read_from_stdin(int *num, char ***records)
{
	char line[4096];
	int alloc = 0;

	*num = 0;
	*records = NULL;
	for (;;) {
		if (!fgets(line, sizeof(line), stdin)) {
			if (feof(stdin))
				break;
			if (!ferror(stdin))
				die("fgets returned NULL, not EOF, nor error!");
			if (errno != EINTR)
				die("fgets: %s", strerror(errno));
			clearerr(stdin);
			continue;
		}
		if (!line[0])
			continue;
		ALLOC_GROW(*records, *num + 1, alloc);
		(*records)[(*num)++] = xstrdup(line);
	}
}		

> diff --git a/git-clone.sh b/git-clone.sh
> index b4e858c..208e9fc 100755
> --- a/git-clone.sh
> +++ b/git-clone.sh
> @@ -115,7 +115,7 @@ Perhaps git-update-server-info needs to be run there?"
>  quiet=
>  local=no
>  use_local_hardlink=yes
> -local_shared=no
> +shared=no
>  unset template
>  no_checkout=
>  upload_pack=
> @@ -143,7 +143,7 @@ do
>  	--no-hardlinks)
>  		use_local_hardlink=no ;;
>  	-s|--shared)
> -		local_shared=yes ;;
> +		shared=yes ;;
>  	--template)
>  		shift; template="--template=$1" ;;
>  	-q|--quiet)
> @@ -288,7 +288,7 @@ yes)
>  	( cd "$repo/objects" ) ||
>  		die "cannot chdir to local '$repo/objects'."
>  
> -	if test "$local_shared" = yes
> +	if test "$shared" = yes
>  	then
>  		mkdir -p "$GIT_DIR/objects/info"
>  		echo "$repo/objects" >>"$GIT_DIR/objects/info/alternates"
> @@ -364,11 +364,22 @@ yes)
>  		fi
>  		;;
>  	*)
> +		commits_only=
> +		if test "$shared" = yes
> +		then
> +			commits_only="--commits-only"
> +		fi
>  		case "$upload_pack" in
> -		'') git-fetch-pack --all -k $quiet $depth $no_progress "$repo";;
> -		*) git-fetch-pack --all -k $quiet "$upload_pack" $depth $no_progress "$repo" ;;
> +		'') git-fetch-pack --all -k $quiet $depth $no_progress $commits_only "$repo";;
> +		*) git-fetch-pack --all -k $quiet "$upload_pack" $depth $no_progress $commits_only "$repo" ;;
>  		esac >"$GIT_DIR/CLONE_HEAD" ||
>  			die "fetch-pack from '$repo' failed."
> +		if test "$shared" = yes
> +		then
> +			# Must be done after the fetch
> +			mkdir -p "$GIT_DIR/objects/info"
> +			echo "$repo" >> "$GIT_DIR/objects/info/remote_alternates"
> +		fi
>  		;;
>  	esac
>  	;;

Please have a different option than --shared for lazy clones.  Maybe 
--lazy?  ;-)

I can see why you reused --shared, though.  But let's make this more 
fool-proof: a user should explicitely ask for a lazy clone.

> diff --git a/index-pack.c b/index-pack.c
> index 9fd6982..f2e6b7a 100644
> --- a/index-pack.c
> +++ b/index-pack.c
> @@ -9,7 +9,7 @@
>  #include "progress.h"
>  
>  static const char index_pack_usage[] =
> -"git-index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
> +"git-index-pack [-v] [-o <index-file>] [{ ---keep | --keep=<msg> }] [--ignore-remote-alternates] { <pack-file> | --stdin [--fix-thin] [<pack-file>] }";
>  
>  struct object_entry
>  {
> @@ -746,6 +746,8 @@ int main(int argc, char **argv)
>  					pack_idx_off32_limit = strtoul(c+1, &c, 0);
>  				if (*c || pack_idx_off32_limit & 0x80000000)
>  					die("bad %s", arg);
> +			} else if (!strcmp(arg, "--ignore-remote-alternates")) {
> +				disable_remote_alternates();
>  			} else
>  				usage(index_pack_usage);
>  			continue;

I might be missing something, but I do not believe this is necessary.  
index-pack only works on packs anyway.  Am I wrong?

> diff --git a/sha1_file.c b/sha1_file.c
> index 66a4e00..7d60be0 100644
> --- a/sha1_file.c
> +++ b/sha1_file.c
> @@ -14,6 +14,7 @@
>  #include "tag.h"
>  #include "tree.h"
>  #include "refs.h"
> +#include "run-command.h"
>  
>  #ifndef O_NOATIME
>  #if defined(__linux__) && (defined(__i386__) || defined(__PPC__))
> @@ -411,6 +412,205 @@ static char *find_sha1_file(const unsigned char *sha1, struct stat *st)
>  	return NULL;
>  }
>  
> +static char *remote_alternates = NULL;
> +static int has_remote_alt_feature = -1;
> +
> +void disable_remote_alternates(void)
> +{
> +	has_remote_alt_feature = 0;
> +}
> +
> +static int has_remote_alternates(void)
> +{
> +	/* FIXME: does it make sense to support more URLs inside
> +	 * remote_alternates? */

I think it would make sense.  For example if you have a local machine 
which has most, but maybe not all, of the remote objects.

> +	struct stat st;
> +	const char remote_alt_file_name[] = "info/remote_alternates";

<bikeshedding>maybe remote-alternates (note the dash instead 
of the underscore)</bikeshedding>

> +	char path[PATH_MAX + 1 + sizeof remote_alt_file_name];
> +	int fd;
> +	char *map, *p;
> +	size_t mapsz;
> +
> +	if (has_remote_alt_feature != -1)
> +		return has_remote_alt_feature;
> +
> +	has_remote_alt_feature = 0;
> +
> +	sprintf(path, "%s/%s", get_object_directory(),
> +			remote_alt_file_name);
> +	fd = open(path, O_RDONLY);
> +	if (fd < 0)
> +		return has_remote_alt_feature;
> +	else if (fstat(fd, &st) || (st.st_size == 0)) {
> +		close(fd);
> +		return has_remote_alt_feature;
> +	}
> +
> +	mapsz = xsize_t(st.st_size);
> +	map = xmmap(NULL, mapsz, PROT_READ, MAP_PRIVATE, fd, 0);
> +	close(fd);
> +
> +	/* we support just one remote alternate for now,
> +	 * so read just the first entry */
> +	for (p = map; (p < map + mapsz) && (*p != '\n'); p++)
> +		;
> +
> +	remote_alternates = strndup(map, p - map);

Seems that you do something like the read_from_stdin() here, only from a 
file.  It appears to me as if the function wants to be a library function 
(taking a FILE * parameter, and maybe closing it after use, or even 
taking a filename parameter, which signifies stdin when NULL).

> +struct sha1_list {
> +	unsigned char sha1[20];
> +	struct sha1_list *next;
> +};

It'd be probably better to make this an array which uses ALLOC_GROW() in 
order to avoid memory fragmentation/allocation overhead.

> +	memset(&fetch_pack, 0, sizeof(fetch_pack));
> +	fetch_pack.in = dump_objects.out;
> +	fetch_pack.out = 1;
> +	fetch_pack.err = 2;
> +	fetch_pack.git_cmd = 1;
> +	fetch_pack.argv = argv;
> +
> +	err = run_command(&fetch_pack);
> +
> +	/* TODO better error handling - is the object really missing, or
> +	 * was it just a temporary network error? */
> +	if (err) {
> +		fprintf(stderr, "error %d while calling fetch-pack\n", err);
> +		return 0;

That is a

		return error("Error %d while calling fetch-pack", err);

And it does not really matter what type of error it is: you must report 
the error and continue without this object.

> +static int fill_remote_list(const unsigned char *sha1,
> +		const char *base, int baselen,
> +		const char *pathname, unsigned mode, int stage)
> +{
> +	if (!has_sha1_file_locally(sha1)) {
> +		struct sha1_list *item;
> +
> +		item = xmalloc(sizeof(*item));
> +		hashcpy(item->sha1, sha1);
> +		item->next = remote_list;
> +
> +		remote_list = item;
> +	}
> +
> +	return 0;
> +}
> +
> +static int fetch_remote_sha1s_recursive(struct sha1_list *objects)
> +{
> +	struct sha1_list *list;
> +	int ret = 0;
> +
> +	/* first of all, fetch the missing objects */
> +	if (!fetch_remote_sha1s(objects))
> +		return 0;
> +
> +	remote_list = NULL;
> +
> +	list = objects;
> +	while (list) {
> +		struct tree *tree;
> +
> +		tree = parse_tree_indirect(list->sha1);
> +		if (tree) {
> +			read_tree_recursive(tree, "", 0, 0, NULL,
> +					fill_remote_list);
> +		}

The curly brackets are not necessary.  Plus, with fill_remote_list() as 
you defined it, it will break down with submodules (see 481f0ee6(Fix 
rev-list when showing objects involving submodules) for inspiration).

> +
> +		list = list->next;
> +	}
> +
> +	list = remote_list;
> +	if (!list)
> +		return 1; /* hooray, we have everything */
> +
> +	ret = fetch_remote_sha1s_recursive(list);

This just cries out loud for a non-recursive approach: have two arrays, 
clear the second, fetch the objects in the first array, then fill the 
second with the objects referred to by the first array's objects.  Then 
swap the arrays.  Loop.

> @@ -2316,6 +2532,18 @@ int has_sha1_file(const unsigned char *sha1)
>  	return find_sha1_file(sha1, &st) ? 1 : 0;
>  }
>  
> +int has_sha1_file(const unsigned char *sha1)
> +{
> +	if (has_sha1_file_locally(sha1))
> +		return 1;
> +
> +	/* download it if necessary */
> +	if (has_remote_alternates() && download_remote_sha1(sha1))

Maybe it would be nicer to have the has_remote_alternates() check only in 
download_remote_sha1()?  Same applies to read_sha1_file().

> @@ -106,9 +106,15 @@ static int do_rev_list(int fd, void *create_full_pack)
>  	if (create_full_pack)
>  		use_thin_pack = 0; /* no point doing it */
>  	init_revisions(&revs, NULL);
> -	revs.tag_objects = 1;
> -	revs.tree_objects = 1;
> -	revs.blob_objects = 1;
> +	if (!commits_only) {
> +		revs.tag_objects = 1;
> +		revs.tree_objects = 1;
> +		revs.blob_objects = 1;
> +	} else {
> +		revs.tag_objects = 0;
> +		revs.tree_objects = 0;
> +		revs.blob_objects = 0;
> +	}

Or

	revs.tag_objects = revs.tree_objects = revs.blob_objects
		= !commits_only;


> @@ -498,9 +525,15 @@ static void receive_needs(void)
>  		 * asks for something like "master~10" (symbolic)...
>  		 * would it make sense?  I don't know.
>  		 */
> -		o = lookup_object(sha1_buf);
> -		if (!o || !(o->flags & OUR_REF))
> -			die("git-upload-pack: not our ref %s", line+5);
> +		if (!exact_objects) {
> +			o = lookup_object(sha1_buf);
> +			if (!o || !(o->flags & OUR_REF))
> +				die("git-upload-pack: not our ref %s", line+5);
> +		} else {
> +			o = lookup_unknown_object(sha1_buf);
> +			if (!o)
> +				die("git-upload-pack: not an object %s", line+5);
> +		}

Hmm... AFAICT lookup_unknown_object() does not return NULL.  It creates a 
"none" object if it did not find anything under that sha1.

I think you'd rather want

 		o = lookup_object(sha1_buf);
-		if (!o || !(o->flags & OUR_REF))
+		if (!o || (!exact_objects && !(o->flags & OUR_REF)))
 			die("git-upload-pack: not our ref %s", line+5);

Puh.  What a big patch!  But as I said, it is nice to know somebody is 
working on this.  (I do not necessarily see possibilities to break it 
down into smaller chunks, though.)

But I think that your needs can be satisfied with partial shallow clones, 
too: e.g.

	$ mkdir my-new-workdir
	$ cd my-new-workdir
	$ git init
	$ git remote add -t master origin <url>
	$ git fetch --depth 1 origin
	$ git checkout -b master origin/master

I cannot think of a proper place to make this a one-shot command.

As you probably know, I am a strong believer in semantics, so I would hate 
"git clone" being taught to not clone the whole repository, but only a 
single branch.

But hey, I have been wrong before.

Ciao,
Dscho

^ permalink raw reply	[relevance 4%]

* Re: [PATCH] RFC: git lazy clone proof-of-concept
  @ 2008-02-11  1:20  4%     ` Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2008-02-11  1:20 UTC (permalink / raw)
  To: Jan Holesovsky; +Cc: git, Junio C Hamano

Hi, Jan!

On Sat, 9 Feb 2008, Jan Holesovsky wrote:
> On Friday 08 February 2008 20:00, Jakub Narebski wrote:
> 
>> It was not implemented because it was thought to be hard; git assumes
>> in many places that if it has an object, it has all objects referenced
>> by it.
>>
>> But it is very nice of you to [try to] implement 'lazy clone'/'remote
>> alternates'.
>>
>> Could you provide some benchmarks (time, network throughtput, latency)
>> for your implementation?
> 
> Unfortunately not yet :-(  The only data I have that clone done on 
> git://localhost/ooo.git took 10 minutes without the lazy clone, and 7.5 
> minutes with it - and then I sent the patch for review here ;-)  The deadline 
> for our SVN vs. git comparison for OOo is the next Friday, so I'll definitely 
> have some better data by then.

Here perhaps another optimization which wasn't done because git is
fast enough on moderately-sized repositories, namely that IIRC git-clone
(and git-fetch for sure) over native (smart) protocol recreates pack,
even if sometimes better and simplier would be to just copy (transfer)
existing pack.

But this would need multi-pack "extension". (it should work just now
without transport protocol extension, receiver must only be aware
of the need to split resulting pack, and index them all).

>> Both Mozilla import, and GCC import were packed below 0.5 GB. Warning:
>> you would need machine with large amount of memory to repack it
>> tightly in sensible time!
> 
> As I answered elsewhere, unfortunately it goes out of memory even on 8G 
> machine (x86-64), so...  But still trying.

I hope that would work better...

>>> Shallow clone is not a possibility - we don't get patches through
>>> mailing lists, so we need the pull/push, and also thanks to the OOo
>>> development cycle, we have too many living heads which causes the
>>> shallow clone to download about 1.5G even with --depth 1.
>>
>> Wouldn't be easier to try to fix shallow clone implementation to allow
>> for pushing from shallow to full clone (fetching from full to shallow
>> is implemented), and perhaps also push/pull between two shallow
>> clones?
> 
> I tried to look into it a bit, but unfortunately did not see a clear way how 
> to do it transparently for the user - say you pull a branch that is based off 
> a commit you do not have.  But of course, I could have missed something ;-)

If I remember correctly fetching _into_ shallow clone works correctly,
as deepening depth of shallow clone. What is not implemented AFAIK, but
should be not too hard would be to allow to push from shallow clone
to full clone. This way the network of full clones (functioning as
centres to publish your work) and shallow + few branches repos (working
repositories).

I don't know if that would be enough.

For better support git would need to exchange graft-like information,
and use union of restrictions to get correct commits.


Perhaps it would be best to mail 'shallow clone' author...

>> As to many living heads: first, you don't need to fetch all
>> heads. Currently git-clone has no option to select subset of heads to
>> clone, but you can always use git-init + hand configuration +
>> git-remote and git-fetch for actual fetching.
> 
> Right, might be interesting as well.  But still the missing push/pull is 
> problematic for us [or at least I see it as a problem ;-)].

You can configure separate 'remote's for the same repository
with different heads. This would work both for pull and for push.


I think the solution proposed by Marco Costalba, namely of creating
"archive" repository, and "live" repository, joining them if needed
by grafts, similarly to how linux kernel has live repo, and historical
import repo, would be good alternative to shallow or lazy clone.

There would be "archive" repo (or repos), read only, with whole history,
very tightly packed with kept packs, with all branches and all tags,
and "live" repo, with only current history (a year, or since major
API change, or from today, or something like that), with only important
branches (or repos, each containg important for a team set of branches).
There would be prepared graft file to join two histories, if you have
to examine full history. Hopefully repo would be smaller.

>> By the way, did you try to split OpenOffice.org repository at the
>> components boundary into submodules (subprojects)? This would also
>> limit amount of needed download, as you don't neeed to download and
>> checkout all subprojects.
> 
> Yes, and got to much nicer repositories by that ;-) - by only moving some 
> binary stuff out of the CVS to a separate tree.  The problem is that the deal 
> is to compare the same stuff in SVN and git - so no choice for me in fact.

Sidenote: due to (from what I have read) heavy use of topic branches
in OOo development, Subversion would have to be used with svnmerge
extension, or together with SVK, to make work with it not complete
pain.

In CVS you could have ad-hoc modules, and ad-hoc partial checkouts
(so called 'modules'), but that plays merry hell with whole tree,
atomic, recoverable state commits. In Git you have to plan carefully
boundaries between submodules / subprojects. Additional advantage
is that you would have boundaries more clear, and better modularity
usually leads to better code.

Comparing directly Subversion and Git is a bit stupid: they promote
different workflows. From what I've read Git with its ability to very
easily create branches, with easy _merging_ of branches, and ability
to easily create _private_ branches (testing branches) have much
common witch chosen OOo SCM workflow. Playing to strentghs of
Subversion because that is why you used because of limits of previously
used tools is not smart.

But if you have to, then you have to. Git would hopefully get lazy
clone support from your effort. But perhaps it would be possible
(if additional work) to prepare two repositories: first the same
as Subversion (and same as now in CVS), second one "how it should
be done with Git".

>> The problem of course is _how_ to split repository into
>> submodules. Submodules should be enough self contained so the
>> whole-tree commit is alsays (or almost always) only about submodule.
> 
> I hope it will be doable _if_ the git wins & will be chosen for OOo.

I hope that ability to work with submodules (with ability to not
clone / checkout modules if not needed), i.e. "svn:externals
done right" to para[hrase SVN slogan, would be one of reasons to
chose Git over Subversion.

>>> Lazy clone sounded like the right idea to me.  With this
>>> proof-of-concept implementation, just about 550M from the 2.5G is
>>> downloaded, which is still about twice as much in comparison with
>>> downloading a tarball, but bearable.
>>
>> Do you have any numbers for OOo repository like number of revisions,
>> depth of DAG of commits (maximum number of revisions in one line of
>> commits), number of files, size of checkout, average size of file,
>> etc.?
> 
> I'll try to provide the data ASAP.

For example what is the size of full checkout (all version-control
managed files). Of for example it is 0.5 GB it would be hard to go
to less that 0.5GB or so with pack size, even with compression
of objects themselves in pack file.


Such large repositories, like Mozilla, GCC, or now OpenOffice.org
tests the limits of Git. Perhaps snapshot-based distributed SCMs
cannot deal sensibly with such large projects; I hope this is not
the case.

I wonder if packv4 improvements, which development stalled because
(if I understand correctly) because it didn't brough as much
improvements, and what is now was good enough for up-till-now
projects, would help with OpenOffice.org repository...


P.S. From what I have read OOo uses CVS + some branch DB; does
your importer make use of this branch info database?

-- 
Jakub Narebski
Poland

^ permalink raw reply	[relevance 4%]

* Re: [PATCH] RFC: git lazy clone proof-of-concept
  @ 2008-02-14 21:59  5%     ` Jakub Narebski
  2008-02-14 23:38  4%       ` Johannes Schindelin
  2008-02-15  9:43  1%       ` Jan Holesovsky
  0 siblings, 2 replies; 200+ results
From: Jakub Narebski @ 2008-02-14 21:59 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Brandon Casey, Nicolas Pitre, Jan Holesovsky, git, Junio C Hamano,
	Brian Downing

Johannes Schindelin wrote:
> On Thu, 14 Feb 2008, Jakub Narebski wrote:

>> Perhaps you could try running contrib/stats/packinfo.pl on this pack to 
>> examine it to get to know what takes most space.
> 
> $ ~/git/contrib/stats/packinfo.pl < \
> objects/pack/pack-e4dc6da0a10888ec4345490575efc587b7523b45.pack 2>&1 | \
> tee packinfo.txt
> Illegal division by zero at /home/imaging/git/contrib/stats/packinfo.pl 
> line 141, <STDIN> line 6330855.

Errr... sorry, I should have been more explicit. What I meant here
is the result of

$ git verify-pack -v <packfile> | \
  ~/git/contrib/stats/packinfo.pl


>> What is the size of checkout, by the way?
> 
> I work on a bare repository, but:
> 
> $ git archive origin/master | wc -c
> 2010060800
> 
> Or more precisely:
> 
> $ echo $(($(git ls-tree -l -r origin/master | sed -n 's/^[^ ]* [^ ]* [^ ]*  
> *\([0-9]*\).*$/\1/p' | tr '\012' +)0))
> 1947839459
> 
> So yes, we still have the crown of the _whole_ repository being _smaller_ 
> than a single checkout.
> 
> Yeah!


Brandon Casey wrote:
> Jakub Narebski wrote:
>> 
>> What is the size of checkout, by the way?
> 
> 2.4G

That's huuuuge tree. Compared to that 1.6G (or 1.4G) packfile doesn't
look large.

I wonder if proper subdivision into submodules (which should encourage
better code by the way, see TAOUP), and perhaps partial checkouts
wouldn't be better solution than lazy clone. But it is nice to have
long discussed about feature, even if at RFC stage, but with some code.

-- 
Jakub Narebski
Poland

^ permalink raw reply	[relevance 5%]

* Re: [PATCH] RFC: git lazy clone proof-of-concept
  2008-02-14 21:59  5%     ` Jakub Narebski
@ 2008-02-14 23:38  4%       ` Johannes Schindelin
  2008-02-15  1:07  5%         ` Jakub Narebski
  2008-02-15  9:43  1%       ` Jan Holesovsky
  1 sibling, 1 reply; 200+ results
From: Johannes Schindelin @ 2008-02-14 23:38 UTC (permalink / raw)
  To: Jakub Narebski
  Cc: Brandon Casey, Nicolas Pitre, Jan Holesovsky, git, Junio C Hamano,
	Brian Downing

Hi,

On Thu, 14 Feb 2008, Jakub Narebski wrote:

> Johannes Schindelin wrote:
> > On Thu, 14 Feb 2008, Jakub Narebski wrote:
> 
> >> Perhaps you could try running contrib/stats/packinfo.pl on this pack 
> >> to examine it to get to know what takes most space.
> > 
> > $ ~/git/contrib/stats/packinfo.pl < \
> > objects/pack/pack-e4dc6da0a10888ec4345490575efc587b7523b45.pack 2>&1 | \
> > tee packinfo.txt
> > Illegal division by zero at /home/imaging/git/contrib/stats/packinfo.pl 
> > line 141, <STDIN> line 6330855.
> 
> Errr... sorry, I should have been more explicit. What I meant here is 
> the result of
> 
> $ git verify-pack -v <packfile> | \
>   ~/git/contrib/stats/packinfo.pl

Heh.  I was too lazy to look up the usage, so I just did what I thought 
would make sense...

So here it goes:

$ git verify-pack -v 
objects/pack/pack-e4dc6da0a10888ec4345490575efc587b7523b45.pack | 
~/git/contrib/stats/packinfo.pl | tee packinfo.txt
      all sizes: count 601473 total 2855826280 min 0 max 62173032 mean 
4748.05 median 232 std_dev 221254.37
 all path sizes: count 601473 total 2855826280 min 0 max 62173032 mean 
4748.05 median 232 std_dev 221254.37
     tree sizes: count 601473 total 2855826280 min 0 max 62173032 mean 
4748.05 median 232 std_dev 221254.37
tree path sizes: count 601473 total 2855826280 min 0 max 62173032 mean 
4748.05 median 232 std_dev 221254.37
         depths: count 2477715 total 70336238 min 0 max 250 mean 28.39 
median 4 std_dev 55.49

Something in my gut tells me that those four repetitive lines are not 
meant to look like they do...

> > 2.4G
>
> That's huuuuge tree. Compared to that 1.6G (or 1.4G) packfile doesn't 
> look large.
> 
> I wonder if proper subdivision into submodules (which should encourage 
> better code by the way, see TAOUP), and perhaps partial checkouts 
> wouldn't be better solution than lazy clone. But it is nice to have long 
> discussed about feature, even if at RFC stage, but with some code.

I think partial checkouts are wrong.  If you can work on partial 
checkouts, chances are that what you work on should be a submodule.

Having said that, I can understand if some people do not want to have the 
hassle of test^H^H^H^Husing submodules...

Ciao,
Dscho

^ permalink raw reply	[relevance 4%]

* Re: [PATCH] RFC: git lazy clone proof-of-concept
  2008-02-14 23:38  4%       ` Johannes Schindelin
@ 2008-02-15  1:07  5%         ` Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2008-02-15  1:07 UTC (permalink / raw)
  To: Johannes Schindelin
  Cc: Brandon Casey, Nicolas Pitre, Jan Holesovsky, git, Junio C Hamano,
	Brian Downing

Dnia piątek 15. lutego 2008 00:38, Johannes Schindelin napisał:
> Hi,
> 
> On Thu, 14 Feb 2008, Jakub Narebski wrote:
>
>> I wonder if proper subdivision into submodules (which should
>> encourage better code by the way, see TAOUP), and perhaps
>> _partial checkouts_ wouldn't be better solution than _lazy clone_.
>> But it is nice to have long discussed about feature, even if at
>> RFC stage, but with some code. 
> 
> I think partial checkouts are wrong.  If you can work on partial 
> checkouts, chances are that what you work on should be a submodule.
> 
> Having said that, I can understand if some people do not want to have
> the hassle of test^H^H^H^Husing submodules...

IMHO there is place for submodules, there is place for partial 
checkouts, and perhaps there is even place for the combination of two.

For example while Documentation/ isn't a good candidate for a submodule, 
because as you add new feature yuou want to add to documentation, if 
you change some feature you want to change documentation: there are 
whole-tree commits which contain changes outside Documentation/.
Nevertheless there are some people (technical writers) which are 
interested only in Documentation; perhaps only in few files there.
They would want to have partial checkout, I guess.

On the other hand cgit and msysgit use submodules, and I think it is 
good solution. I wonder if Sourcemage Linux distro uses submodules... 
In the case of cgit I think having git.git or its clone/fork as 
submodule is a good idea, but perhaps even better would be to checkout 
only part of it: libgit or libgitthin

-- 
Jakub Narebski
Poland

^ permalink raw reply	[relevance 5%]

* Re: [PATCH] RFC: git lazy clone proof-of-concept
  2008-02-14 21:59  5%     ` Jakub Narebski
  2008-02-14 23:38  4%       ` Johannes Schindelin
@ 2008-02-15  9:43  1%       ` Jan Holesovsky
  1 sibling, 0 replies; 200+ results
From: Jan Holesovsky @ 2008-02-15  9:43 UTC (permalink / raw)
  To: Jakub Narebski
  Cc: Johannes Schindelin, Brandon Casey, Nicolas Pitre, git,
	Junio C Hamano, Brian Downing

Hi Jakub,

On Thursday 14 of February 2008, Jakub Narebski wrote:

> >> What is the size of checkout, by the way?
> >
> > 2.4G
>
> That's huuuuge tree. Compared to that 1.6G (or 1.4G) packfile doesn't
> look large.
>
> I wonder if proper subdivision into submodules (which should encourage
> better code by the way, see TAOUP), and perhaps partial checkouts
> wouldn't be better solution than lazy clone. But it is nice to have
> long discussed about feature, even if at RFC stage, but with some code.

Yes, I'd love to see the OOo tree split into several parts, I've already 
proposed a division (http://www.nabble.com/OOo-source-split-td13096065.html), 
but it'll take some more time I'm afraid :-(

Regards,
Jan

^ permalink raw reply	[relevance 1%]

* What's in git.git (stable)
  @ 2008-02-17  3:56  2%   ` Junio C Hamano
  2008-02-21  4:16  2%     ` Junio C Hamano
  0 siblings, 1 reply; 200+ results
From: Junio C Hamano @ 2008-02-17  3:56 UTC (permalink / raw)
  To: git

I'll hopefully soon apply the RPM spec patch from Kristian
Høgsberg to 'maint' and cut 1.5.4.2.  It will have bunch of
config parser related fixes among others.

On the 'master' front, a handful topics have graduated:

 - Brian Downing's compat/qsort;
 - Crhstian Couder's browser wrapper;
 - Paolo Bonzini's prepare-commit-msg hook;
 - Steffen Prohaska's safe-crlf;
 - "foo/" in .gitignore matches directory "foo".

Also, updated versions of gitk and git-gui are included.

Have fun.

----------------------------------------------------------------

* The 'maint' branch has these fixes since the last announcement.

Christian Couder (8):
  config: add test cases for empty value and no value config variables.
  diff.c: replace a 'strdup' with 'xstrdup'.
  diff.c: remove useless check for value != NULL
  config: add 'git_config_string' to refactor string config variables.
  Add "const" qualifier to "char *pager_program".
  Add "const" qualifier to "char *editor_program".
  Add "const" qualifier to "char *excludes_file".
  diff.c: add "const" qualifier to "char *cmd" member of "struct
    ll_diff_driver"

Daniel Barkalow (1):
  Validate nicknames of remote branches to prohibit confusing ones

Gerrit Pape (1):
  cvsimport: have default merge regex also match beginning of commit
    message

Jay Soffian (1):
  mailinfo: feed only one line to handle_filter() for QP input

Jeff King (2):
  status: suggest "git rm --cached" to unstage for initial commit
  commit: discard index after setting up partial commit

Johannes Schindelin (1):
  bisect: use verbatim commit subject in the bisect log

Johannes Sixt (1):
  upload-pack: Initialize the exec-path.

Junio C Hamano (6):
  Revert "pack-objects: only throw away data during memory pressure"
  Protect get_author_ident_from_commit() from filenames in work tree
  diff.c: fixup garding of config parser from value=NULL
  diff: Fix miscounting of --check output
  filter-branch: handle filenames that need quoting
  Documentation/git-reset:

Miklos Vajna (1):
  git clone -s documentation: force a new paragraph for the NOTE

Pieter de Bie (2):
  Documentation/git-reset: don't mention --mixed for selected-paths reset
  Documentation/git-reset: Add an example of resetting selected paths

Sergei Organov (1):
  git-cvsimport.txt: fix '-M' description.

Shawn O. Pearce (1):
  fast-import: check return value from unpack_entry()

Stelian Pop (1):
  hg-to-git: fix parent analysis

----------------------------------------------------------------

* The 'master' branch has these since the last announcement
  in addition to the above.

Brian Downing (1):
  compat: Add simplified merge sort implementation from glibc

Christian Couder (7):
  help: make 'git-help--browse' usable outside 'git-help'.
  help--browse: add '--config' option to check a config option for a
    browser.
  Rename 'git-help--browse.sh' to 'git-web--browse.sh'.
  instaweb: use 'git-web--browse' to launch browser.
  Documentation: instaweb: add 'git-web--browse' information.
  web--browse: Add a few quotes in 'init_browser_path'.
  Documentation: add 'git-web--browse.txt' and simplify other docs.

Christian Stimming (2):
  git-gui: (i18n) Fix a bunch of still untranslated strings.
  git-gui: Update German translation.

Dmitry Potapov (1):
  git-web--browse: do not start the browser with nohup

Gerrit Pape (1):
  gitk: properly deal with tag names containing / (slash)

Jay Soffian (3):
  git-gui: support Git Gui.app under OS X 10.5
  git-help--browse: improve browser support under OS X
  git-web--browse: fix misplaced quote in init_browser_path()

Jeff King (2):
  allow suppressing of global and system config
  fix config reading in tests

Johan Herland (2):
  Add testcase for 'git cvsexportcommit -w $cvsdir ...' with relative
    $GIT_DIR
  Fix 'git cvsexportcommit -w $cvsdir ...' when used with relative $GIT_DIR

Johannes Schindelin (1):
  Adjust .gitignore for 5884f1(Rename 'git-help--browse.sh'...)

Johannes Sixt (1):
  gitk: Heed the lines of context in merge commits

Junio C Hamano (7):
  Documentation/SubmittingPatches: Instruct how to use [PATCH] Subject
    header
  Documentation/SubmittingPatches: discuss first then submit
  Documentation/SubmittingPatches: What's Acked-by and Tested-by?
  gitignore(5): Allow "foo/" in ignore list to match directory "foo"
  gitignore: lazily find dtype
  .mailmap: adjust to a recent patch application glitch.
  Documentation/SubmittingPatches - a suggested patch flow

Linus Torvalds (1):
  gitk: learn --show-all output

Michele Ballabio (1):
  gitk: Fix "Key bindings" message

Paolo Bonzini (4):
  git-commit: support variable number of hook arguments
  git-commit: set GIT_EDITOR=: if editor will not be launched
  git-commit: Refactor creation of log message.
  git-commit: add a prepare-commit-msg hook

Shawn O. Pearce (7):
  git-gui: Automatically spell check commit messages as the user types
  git-gui: Paper bag fix bad string length call in spellchecker
  git-gui: Correct size of dictionary name widget in options dialog
  Include annotated tags in fast-import crash reports
  Include the fast-import marks table in crash reports
  Finish current packfile during fast-import crash handler
  Update fast-import documentation to discuss crash reports

Steffen Prohaska (2):
  safecrlf: Add mechanism to warn about irreversible crlf conversions
  gitk: Add checkbutton to ignore space changes

^ permalink raw reply	[relevance 2%]

* [ANNOUNCE] GIT 1.5.4.2
  @ 2008-02-17  9:14  2% ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2008-02-17  9:14 UTC (permalink / raw)
  To: git; +Cc: linux-kernel

The latest maintenance release GIT 1.5.4.2 is available at the
usual places:

  http://www.kernel.org/pub/software/scm/git/

  git-1.5.4.2.tar.{gz,bz2}			(tarball)
  git-htmldocs-1.5.4.2.tar.{gz,bz2}		(preformatted docs)
  git-manpages-1.5.4.2.tar.{gz,bz2}		(preformatted docs)
  RPMS/$arch/git-*-1.5.4.2-1.$arch.rpm	(RPM)

----------------------------------------------------------------

GIT v1.5.4.2 Release Notes
==========================

Fixes since v1.5.4
------------------

 * The configuration parser was not prepared to see string
   valued variables misspelled as boolean and segfaulted.

 * Temporary files left behind due to interrupted object
   transfers were not cleaned up with "git prune".

 * "git config --unset" was confused when the unset variables
   were spelled with continuation lines in the config file.

 * The merge message detection in "git cvsimport" did not catch
   a message that began with "Merge...".

 * "git status" suggests "git rm --cached" for unstaging the
   earlier "git add" before the initial commit.

 * "git status" output was incorrect during a partial commit.

 * "git bisect" refused to start when the HEAD was detached.

 * "git bisect" allowed a wildcard character in the commit
   message expanded while writing its log file.

 * Manual pages were not formatted correctly with docbook xsl
   1.72; added a workaround.

 * "git-commit -C $tag" used to work but rewrite in C done in
   1.5.4 broke it.  This was fixed in 1.5.4.1.

 * An entry in the .gitattributes file that names a pattern in a
   subdirectory of the directory it is in did not match
   correctly (e.g. pattern "b/*.c" in "a/.gitattributes" should
   match "a/b/foo.c" but it didn't).  This was fixed in 1.5.4.1.

 * Customized color specification was parsed incorrectly when
   numeric color values are used.  This was fixed in 1.5.4.1.

 * http transport misbehaved when linked with curl-gnutls.

----------------------------------------------------------------

Changes since v1.5.4.1 are as follows:

Christian Couder (8):
      config: add test cases for empty value and no value config variables.
      diff.c: replace a 'strdup' with 'xstrdup'.
      diff.c: remove useless check for value != NULL
      config: add 'git_config_string' to refactor string config variables.
      Add "const" qualifier to "char *pager_program".
      Add "const" qualifier to "char *editor_program".
      Add "const" qualifier to "char *excludes_file".
      diff.c: add "const" qualifier to "char *cmd" member of "struct ll_diff_driver"

Daniel Barkalow (1):
      Validate nicknames of remote branches to prohibit confusing ones

David Steven Tweed (1):
      Make git prune remove temporary packs that look like write failures

Frank Lichtenheld (1):
      config: Fix --unset for continuation lines

Gerrit Pape (2):
      builtin-commit: remove .git/SQUASH_MSG upon successful commit
      cvsimport: have default merge regex also match beginning of commit message

James Bowes (1):
      Add a BuildRequires for gettext in the spec file.

Jay Soffian (1):
      mailinfo: feed only one line to handle_filter() for QP input

Jeff King (2):
      status: suggest "git rm --cached" to unstage for initial commit
      commit: discard index after setting up partial commit

Johannes Schindelin (3):
      bisect: allow starting with a detached HEAD
      Document that the default of branch.autosetupmerge is true
      bisect: use verbatim commit subject in the bisect log

Johannes Sixt (1):
      upload-pack: Initialize the exec-path.

Jonas Fonseca (1):
      man pages are littered with .ft C and others

Junio C Hamano (31):
      git-pull documentation: fix markup
      archive-tar.c: guard config parser from value=NULL
      Add config_error_nonbool() helper function
      builtin-apply.c: guard config parser from value=NULL
      builtin-branch.c: guard config parser from value=NULL
      builtin-commit.c: guard config parser from value=NULL
      builtin-config.c: guard config parser from value=NULL
      builtin-log.c: guard config parser from value=NULL
      builtin-reflog.c: guard config parser from value=NULL
      builtin-show-branch.c: guard config parser from value=NULL
      builtin-tag.c: guard config parser from value=NULL
      connect.c: guard config parser from value=NULL
      convert.c: guard config parser from value=NULL
      diff.c: guard config parser from value=NULL
      git.c: guard config parser from value=NULL
      help.c: guard config parser from value=NULL
      http.c: guard config parser from value=NULL
      merge-recursive.c: guard config parser from value=NULL
      remote.c: guard config parser from value=NULL
      setup.c: guard config parser from value=NULL
      wt-status.c: guard config parser from value=NULL
      imap-send.c: guard config parser from value=NULL
      builtin-log.c: guard config parser from value=NULL
      config.c: guard config parser from value=NULL
      Revert "pack-objects: only throw away data during memory pressure"
      Protect get_author_ident_from_commit() from filenames in work tree
      diff.c: fixup garding of config parser from value=NULL
      diff: Fix miscounting of --check output
      filter-branch: handle filenames that need quoting
      Documentation/git-reset:
      GIT 1.5.4.2

Martin Koegler (1):
      pack-objects: only throw away data during memory pressure

Mike Hommey (1):
      Work around curl-gnutls not liking to be reinitialized

Miklos Vajna (2):
      builtin-gc.c: guard config parser from value=NULL
      git clone -s documentation: force a new paragraph for the NOTE

Pieter de Bie (2):
      Documentation/git-reset: don't mention --mixed for selected-paths reset
      Documentation/git-reset: Add an example of resetting selected paths

Sergei Organov (1):
      git-cvsimport.txt: fix '-M' description.

Shawn O. Pearce (1):
      fast-import: check return value from unpack_entry()

Stelian Pop (1):
      hg-to-git: fix parent analysis

Uwe Kleine-K旦nig (1):
      rebase -i: accept -m as advertised in the man page

^ permalink raw reply	[relevance 2%]

* What's in git.git (stable)
  2008-02-17  3:56  2%   ` What's in git.git (stable) Junio C Hamano
@ 2008-02-21  4:16  2%     ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2008-02-21  4:16 UTC (permalink / raw)
  To: git

With a handful of fixes and RPM specfile updates, we would
probably want to do 1.5.4.3 in a week or so from 'maint'.

A handful of new topics are now on 'master', and the ones still
on 'next' are maturing with necessary fixes.  I think we have
enough material for 1.5.5 when they graduate, and I am hoping to
do an rc1 sometime early to mid next month.  We'll see.

* The 'maint' branch has these fixes since the last announcement.

Gerrit Pape (1):
  git-clone.sh: properly configure remote even if remote's head is dangling

Jay Soffian (1):
  send-email: squelch warning due to comparing undefined $_ to ""

Jeff King (3):
  push: indicate partialness of error message
  Documentation/push: clarify matching refspec behavior
  push: document the status output

Junio C Hamano (1):
  GIT 1.5.4.2

Kristian Høgsberg (1):
  Rename git-core rpm to just git and rename the meta-pacakge to git-all.

Miklos Vajna (1):
  Documentation/git-stash: document options for git stash list

Pekka Kaitaniemi (1):
  Clarified the meaning of git-add -u in the documentation


* The 'master' branch has these since the last announcement
  in addition to the above.

Brandon Casey (1):
  Add compat/fopen.c which returns NULL on attempt to open directory

Bruno Ribas (1):
  gitweb: Use the config file to set repository owner's name.

Christian Couder (1):
  help.c: use 'git_config_string' to get 'help_default_format'.

Daniel Barkalow (1):
  API documentation for remote.h

David Kågedal (1):
  git.el: Set process-environment instead of invoking env

Jakub Narebski (3):
  gitweb: Fix displaying unchopped argument in chop_and_escape_str
  gitweb: Add new option -nohtml to quot_xxx subroutines
  gitweb: Fix bug in href(..., -replay=>1) when using 'pathinfo' form

Jay Soffian (1):
  Correct git-pull documentation

Jeff King (2):
  hard-code the empty tree object
  add--interactive: handle initial commit better

Johannes Schindelin (5):
  http-push: avoid invalid memory accesses
  http-push: do not get confused by submodules
  http-push: avoid a needless goto
  bisect view: check for MinGW32 and MacOSX in addition to X11
  cvsexportcommit: be graceful when "cvs status" reorders the arguments

Johannes Sixt (1):
  Technical documentation of the run-command API.

Junio C Hamano (5):
  setup: sanitize absolute and funny paths in get_pathspec()
  git-add: adjust to the get_pathspec() changes.
  builtin-mv: minimum fix to avoid losing files
  Sync with 1.5.4.2 and start 1.5.5 Release Notes
  sending errors to stdout under $PAGER

Lars Hjemli (1):
  Simplify setup of $GIT_DIR in git-sh-setup.sh

Linus Torvalds (1):
  Add "--show-all" revision walker flag for debugging

Marco Costalba (1):
  Avoid a useless prefix lookup in strbuf_expand()

Martin Koegler (15):
  deref_tag: handle return value NULL
  deref_tag: handle tag->tagged = NULL
  check return code of prepare_revision_walk
  read_object_with_reference: don't read beyond the buffer
  get_sha1_oneline: check return value of parse_object
  mark_blob/tree_uninteresting: check for NULL
  reachable.c::add_one_tree: handle NULL from lookup_tree
  list-objects.c::process_tree/blob: check for NULL
  check results of parse_commit in merge_bases
  process_tag: handle tag->tagged == NULL
  reachable.c::process_tree/blob: check for NULL
  revision.c: handle tag->tagged == NULL
  parse_commit: don't fail, if object is NULL
  check return value from parse_commit() in various functions
  peel_onion: handle NULL

Matthias Kestenholz (1):
  Add color.ui variable which globally enables colorization if set

Robin Rosenberg (1):
  Make blame accept absolute paths

^ permalink raw reply	[relevance 2%]

* Re: [PATCH 0/3] solaris test results
  @ 2008-02-22  5:26  1%     ` Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2008-02-22  5:26 UTC (permalink / raw)
  To: Jeff King; +Cc: Whit Armstrong, git

Jeff King <peff@peff.net> writes:

> On Wed, Feb 20, 2008 at 04:34:25PM -0800, Junio C Hamano wrote:
>
>> >   - Sun's diff doesn't understand "-u". I was able to use GNU diff.
>> >     Since comparing actual and expected output is so common, we could
>> >     potentially abstract this with a "test_cmp()" function and use
>> >     something platform specific. It's probably not worth the trouble, as
>> >     it impacts only the test suite, and only on systems with a totally
>> >     broken diff.
>> 
>> It is unfair to call diff without -u "totally broken".  It is
>> not even in POSIX yet IIRC.
>
> Fair enough (and you are right that it is not even POSIX). Is it
> something we want to work around? We "diff -u" quite a bit in the test
> suite.

Here is a possible solution.

This is a fairly mechanical substitution (grepping for "git diff -u"
and "diff -u", and replacing them with test_compare_expect.

Some tests get the order of comparison wrong (should always be
"diff expect current" to make the error stand out in -v output),
but I did not update them.  That would be for later rounds,
perhaps, if we decide to do this.

-- >8 --
Subject: [PATCH] tests: test_compare_expect helper function

We tend to use "diff -u" for comparing expected output from
actual, but diff on some platforms lack "-u" (it is not in POSIX
yet).

This mechanically replaces "diff -u expected actual" with
test_compare_expect helper function.

Test scripts can be run with --no-diff-u option, to use "git
diff -u --no-index" for comparison instead.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 t/t0003-attributes.sh              |    2 +-
 t/t0022-crlf-rename.sh             |    2 +-
 t/t1300-repo-config.sh             |    2 +-
 t/t2200-add-update.sh              |    2 +-
 t/t3001-ls-files-others-exclude.sh |    2 +-
 t/t3030-merge-recursive.sh         |   42 ++++++++++++++++++------------------
 t/t3050-subprojects-fetch.sh       |    4 +-
 t/t3060-ls-files-with-tree.sh      |    2 +-
 t/t3201-branch-contains.sh         |    6 ++--
 t/t3404-rebase-interactive.sh      |    4 +-
 t/t3405-rebase-malformed.sh        |    4 +-
 t/t3406-rebase-message.sh          |    2 +-
 t/t3701-add-interactive.sh         |    4 +-
 t/t3902-quoted.sh                  |   16 ++++++------
 t/t3903-stash.sh                   |    2 +-
 t/t4023-diff-rename-typechange.sh  |    6 ++--
 t/t4024-diff-optimize-common.sh    |    2 +-
 t/t4025-hunk-header.sh             |    2 +-
 t/t4201-shortlog.sh                |    2 +-
 t/t5505-remote.sh                  |    6 ++--
 t/t5510-fetch.sh                   |    2 +-
 t/t5512-ls-remote.sh               |    8 +++---
 t/t5515-fetch-merge-logic.sh       |    2 +-
 t/t6004-rev-list-path-optim.sh     |    2 +-
 t/t6009-rev-list-parent.sh         |    2 +-
 t/t6027-merge-binary.sh            |    4 +-
 t/t7010-setup.sh                   |   18 +++++++-------
 t/t7501-commit.sh                  |   14 ++++++------
 t/t7502-commit.sh                  |   14 ++++++------
 t/t7502-status.sh                  |    2 +-
 t/t7600-merge.sh                   |    2 +-
 t/t8003-blame.sh                   |    4 +-
 t/t9001-send-email.sh              |    2 +-
 t/t9116-git-svn-log.sh             |   24 ++++++++++----------
 t/t9200-git-cvsexportcommit.sh     |   14 ++++++------
 t/t9300-fast-import.sh             |    2 +-
 t/test-lib.sh                      |   27 +++++++++++++++++++++++
 37 files changed, 142 insertions(+), 115 deletions(-)

diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index 47f08a4..8d85acb 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -11,7 +11,7 @@ attr_check () {
 
 	git check-attr test -- "$path" >actual &&
 	echo "$path: test: $2" >expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 }
 
diff --git a/t/t0022-crlf-rename.sh b/t/t0022-crlf-rename.sh
index 430a1d1..651ce2f 100755
--- a/t/t0022-crlf-rename.sh
+++ b/t/t0022-crlf-rename.sh
@@ -26,7 +26,7 @@ test_expect_success 'diff -M' '
 	git diff-tree -M -r --name-status HEAD^ HEAD |
 	sed -e "s/R[0-9]*/RNUM/" >actual &&
 	echo "RNUM	sample	elpmas" >expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh
index 4928a57..e0e95ce 100755
--- a/t/t1300-repo-config.sh
+++ b/t/t1300-repo-config.sh
@@ -465,7 +465,7 @@ weird
 EOF
 
 test_expect_success "section was removed properly" \
-	"git diff -u expect .git/config"
+	"test_compare_expect expect .git/config"
 
 rm .git/config
 
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index 24f892f..75abda1 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -62,7 +62,7 @@ test_expect_success 'cache tree has not been corrupted' '
 	sed -e "s/ 0	/	/" >expect &&
 	git ls-tree -r $(git write-tree) |
 	sed -e "s/ blob / /" >current &&
-	diff -u expect current
+	test_compare_expect expect current
 
 '
 
diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh
index b4297ba..0b9d2ea 100755
--- a/t/t3001-ls-files-others-exclude.sh
+++ b/t/t3001-ls-files-others-exclude.sh
@@ -97,7 +97,7 @@ cat > expect << EOF
 EOF
 
 test_expect_success 'git-status honours core.excludesfile' \
-	'diff -u expect output'
+	'test_compare_expect expect output'
 
 test_expect_success 'trailing slash in exclude allows directory match(1)' '
 
diff --git a/t/t3030-merge-recursive.sh b/t/t3030-merge-recursive.sh
index 607f57f..edfdbfd 100755
--- a/t/t3030-merge-recursive.sh
+++ b/t/t3030-merge-recursive.sh
@@ -43,7 +43,7 @@ test_expect_success 'setup 1' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 '
 
 test_expect_success 'setup 2' '
@@ -61,7 +61,7 @@ test_expect_success 'setup 2' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_compare_expect expected actual &&
 
 	echo goodbye >>a &&
 	o2=$(git hash-object a) &&
@@ -82,7 +82,7 @@ test_expect_success 'setup 2' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 '
 
 test_expect_success 'setup 3' '
@@ -100,7 +100,7 @@ test_expect_success 'setup 3' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_compare_expect expected actual &&
 
 	rm -f b && mkdir b && echo df-1 >b/c && git add b/c &&
 	o3=$(git hash-object b/c) &&
@@ -119,7 +119,7 @@ test_expect_success 'setup 3' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 '
 
 test_expect_success 'setup 4' '
@@ -137,7 +137,7 @@ test_expect_success 'setup 4' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_compare_expect expected actual &&
 
 	rm -f a && mkdir a && echo df-2 >a/c && git add a/c &&
 	o4=$(git hash-object a/c) &&
@@ -156,7 +156,7 @@ test_expect_success 'setup 4' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 '
 
 test_expect_success 'setup 5' '
@@ -174,7 +174,7 @@ test_expect_success 'setup 5' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_compare_expect expected actual &&
 
 	rm -f b &&
 	echo remove-conflict >a &&
@@ -195,7 +195,7 @@ test_expect_success 'setup 5' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -214,7 +214,7 @@ test_expect_success 'setup 6' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o0 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_compare_expect expected actual &&
 
 	rm -fr d && echo df-3 >d && git add d &&
 	o6=$(git hash-object d) &&
@@ -233,7 +233,7 @@ test_expect_success 'setup 6' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o6 0	d"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 '
 
 test_expect_success 'merge-recursive simple' '
@@ -265,7 +265,7 @@ test_expect_success 'merge-recursive result' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -297,7 +297,7 @@ test_expect_success 'merge-recursive remove conflict' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -318,7 +318,7 @@ test_expect_success 'merge-recursive result' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -352,7 +352,7 @@ test_expect_success 'merge-recursive d/f conflict result' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -386,7 +386,7 @@ test_expect_success 'merge-recursive d/f conflict result the other way' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -420,7 +420,7 @@ test_expect_success 'merge-recursive d/f conflict result' '
 		echo "100644 $o0 1	d/e"
 		echo "100644 $o1 2	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -454,7 +454,7 @@ test_expect_success 'merge-recursive d/f conflict result' '
 		echo "100644 $o0 1	d/e"
 		echo "100644 $o1 3	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -480,7 +480,7 @@ test_expect_success 'reset and bind merge' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual &&
+	test_compare_expect expected actual &&
 
 	git read-tree --prefix=a1/ master &&
 	git ls-files -s >actual &&
@@ -498,7 +498,7 @@ test_expect_success 'reset and bind merge' '
 		echo "100644 $o0 0	c"
 		echo "100644 $o1 0	d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 
 	git read-tree --prefix=z/ master &&
 	git ls-files -s >actual &&
@@ -520,7 +520,7 @@ test_expect_success 'reset and bind merge' '
 		echo "100644 $o0 0	z/c"
 		echo "100644 $o1 0	z/d/e"
 	) >expected &&
-	git diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 34f26a8..15fbdf3 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -26,7 +26,7 @@ test_expect_success clone '
 		cd cloned &&
 		(git rev-parse HEAD; git ls-files -s) >../actual
 	) &&
-	diff -u expected actual
+	test_compare_expect expected actual
 '
 
 test_expect_success advance '
@@ -46,7 +46,7 @@ test_expect_success fetch '
 		git pull &&
 		(git rev-parse HEAD; git ls-files -s) >../actual
 	) &&
-	diff -u expected actual
+	test_compare_expect expected actual
 '
 
 test_done
diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh
index 68eb266..ece38d0 100755
--- a/t/t3060-ls-files-with-tree.sh
+++ b/t/t3060-ls-files-with-tree.sh
@@ -66,6 +66,6 @@ test_expect_success 'git -ls-files --with-tree should succeed from subdir' '
 cd ..
 test_expect_success \
     'git -ls-files --with-tree should add entries from named tree.' \
-    'diff -u expected output'
+    'test_compare_expect expected output'
 
 test_done
diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh
index 9ef593f..a711f54 100755
--- a/t/t3201-branch-contains.sh
+++ b/t/t3201-branch-contains.sh
@@ -31,7 +31,7 @@ test_expect_success 'branch --contains=master' '
 	{
 		echo "  master" && echo "* side"
 	} >expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
@@ -41,7 +41,7 @@ test_expect_success 'branch --contains master' '
 	{
 		echo "  master" && echo "* side"
 	} >expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
@@ -51,7 +51,7 @@ test_expect_success 'branch --contains=side' '
 	{
 		echo "* side"
 	} >expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 62e65d7..76927f8 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -146,8 +146,8 @@ EOF
 test_expect_success 'stop on conflicting pick' '
 	git tag new-branch1 &&
 	! git rebase -i master &&
-	diff -u expect .git/.dotest-merge/patch &&
-	diff -u expect2 file1 &&
+	test_compare_expect expect .git/.dotest-merge/patch &&
+	test_compare_expect expect2 file1 &&
 	test 4 = $(grep -v "^#" < .git/.dotest-merge/done | wc -l) &&
 	test 0 = $(grep -ve "^#" -e "^$" < .git/.dotest-merge/git-rebase-todo |
 		wc -l)
diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh
index e4e2e64..8bb412e 100755
--- a/t/t3405-rebase-malformed.sh
+++ b/t/t3405-rebase-malformed.sh
@@ -41,8 +41,8 @@ test_expect_success rebase '
 	git rebase master side &&
 	git cat-file commit HEAD | sed -e "1,/^\$/d" >F1 &&
 
-	diff -u F0 F1 &&
-	diff -u F F0
+	test_compare_expect F0 F1 &&
+	test_compare_expect F F0
 '
 
 test_done
diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh
index 332b2b2..9753939 100755
--- a/t/t3406-rebase-message.sh
+++ b/t/t3406-rebase-message.sh
@@ -37,7 +37,7 @@ test_expect_success 'rebase -m' '
 	git rebase -m master >report &&
 	sed -n -e "/^Already applied: /p" \
 		-e "/^Committed: /p" report >actual &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index c8dc1ac..1bb2aae 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -24,7 +24,7 @@ EOF
 test_expect_success 'diff works (initial)' '
 	(echo d; echo 1) | git add -i >output &&
 	sed -ne "/new file/,/content/p" <output >diff &&
-	diff -u expected diff
+	test_compare_expect expected diff
 '
 test_expect_success 'revert works (initial)' '
 	git add file &&
@@ -57,7 +57,7 @@ EOF
 test_expect_success 'diff works (commit)' '
 	(echo d; echo 1) | git add -i >output &&
 	sed -ne "/^index/,/content/p" <output >diff &&
-	diff -u expected diff
+	test_compare_expect expected diff
 '
 test_expect_success 'revert works (commit)' '
 	git add file &&
diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh
index 73da45f..02eb9ff 100755
--- a/t/t3902-quoted.sh
+++ b/t/t3902-quoted.sh
@@ -78,28 +78,28 @@ EOF
 
 test_expect_success 'check fully quoted output from ls-files' '
 
-	git ls-files >current && diff -u expect.quoted current
+	git ls-files >current && test_compare_expect expect.quoted current
 
 '
 
 test_expect_success 'check fully quoted output from diff-files' '
 
 	git diff --name-only >current &&
-	diff -u expect.quoted current
+	test_compare_expect expect.quoted current
 
 '
 
 test_expect_success 'check fully quoted output from diff-index' '
 
 	git diff --name-only HEAD >current &&
-	diff -u expect.quoted current
+	test_compare_expect expect.quoted current
 
 '
 
 test_expect_success 'check fully quoted output from diff-tree' '
 
 	git diff --name-only HEAD^ HEAD >current &&
-	diff -u expect.quoted current
+	test_compare_expect expect.quoted current
 
 '
 
@@ -111,28 +111,28 @@ test_expect_success 'setting core.quotepath' '
 
 test_expect_success 'check fully quoted output from ls-files' '
 
-	git ls-files >current && diff -u expect.raw current
+	git ls-files >current && test_compare_expect expect.raw current
 
 '
 
 test_expect_success 'check fully quoted output from diff-files' '
 
 	git diff --name-only >current &&
-	diff -u expect.raw current
+	test_compare_expect expect.raw current
 
 '
 
 test_expect_success 'check fully quoted output from diff-index' '
 
 	git diff --name-only HEAD >current &&
-	diff -u expect.raw current
+	test_compare_expect expect.raw current
 
 '
 
 test_expect_success 'check fully quoted output from diff-tree' '
 
 	git diff --name-only HEAD^ HEAD >current &&
-	diff -u expect.raw current
+	test_compare_expect expect.raw current
 
 '
 
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index 9a9a250..4f5e579 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -34,7 +34,7 @@ EOF
 test_expect_success 'parents of stash' '
 	test $(git rev-parse stash^) = $(git rev-parse HEAD) &&
 	git diff stash^2..stash > output &&
-	diff -u output expect
+	test_compare_expect output expect
 '
 
 test_expect_success 'apply needs clean working directory' '
diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh
index 255604e..177e78a 100755
--- a/t/t4023-diff-rename-typechange.sh
+++ b/t/t4023-diff-rename-typechange.sh
@@ -57,7 +57,7 @@ test_expect_success 'cross renames to be detected for regular files' '
 		echo "R100	foo	bar"
 		echo "R100	bar	foo"
 	} | sort >expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
@@ -68,7 +68,7 @@ test_expect_success 'cross renames to be detected for typechange' '
 		echo "R100	foo	bar"
 		echo "R100	bar	foo"
 	} | sort >expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
@@ -79,7 +79,7 @@ test_expect_success 'moves and renames' '
 		echo "R100	foo	bar"
 		echo "T100	foo"
 	} | sort >expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
diff --git a/t/t4024-diff-optimize-common.sh b/t/t4024-diff-optimize-common.sh
index 3c66102..318ce54 100755
--- a/t/t4024-diff-optimize-common.sh
+++ b/t/t4024-diff-optimize-common.sh
@@ -150,7 +150,7 @@ test_expect_success 'diff -U0' '
 	do
 		git diff -U0 file-?$n
 	done | zc >actual &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
diff --git a/t/t4025-hunk-header.sh b/t/t4025-hunk-header.sh
index 9ba06b7..542bf30 100755
--- a/t/t4025-hunk-header.sh
+++ b/t/t4025-hunk-header.sh
@@ -37,7 +37,7 @@ test_expect_success 'hunk header truncation with an overly long line' '
 		echo " A $N$N$N$N$N$N$N$N$N2"
 		echo " L  $N$N$N$N$N$N$N$N$N1"
 	) >expected &&
-	diff -u actual expected
+	test_compare_expect actual expected
 
 '
 
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 6d12efb..f9859bc 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -45,6 +45,6 @@ A U Thor (5):
 
 EOF
 
-test_expect_success 'shortlog wrapping' 'diff -u expect out'
+test_expect_success 'shortlog wrapping' 'test_compare_expect expect out'
 
 test_done
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 636aec2..cf20ec4 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -25,7 +25,7 @@ setup_repository () {
 tokens_match () {
 	echo "$1" | tr ' ' '\012' | sort | sed -e '/^$/d' >expect &&
 	echo "$2" | tr ' ' '\012' | sort | sed -e '/^$/d' >actual &&
-	diff -u expect actual
+	test_compare_expect expect actual
 }
 
 check_remote_track () {
@@ -74,7 +74,7 @@ test_expect_success 'add another remote' '
 	sed -e "/^refs\/remotes\/origin\//d" \
 	    -e "/^refs\/remotes\/second\//d" >actual &&
 	>expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 )
 '
 
@@ -93,7 +93,7 @@ test_expect_success 'remove remote' '
 	git for-each-ref "--format=%(refname)" refs/remotes |
 	sed -e "/^refs\/remotes\/origin\//d" >actual &&
 	>expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 )
 '
 
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 9b948c1..17add89 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -249,7 +249,7 @@ test_expect_success 'bundle should record HEAD correctly' '
 	do
 		echo "$(git rev-parse --verify $h) $h"
 	done >expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 6ec5f7c..60def72 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -24,28 +24,28 @@ test_expect_success setup '
 test_expect_success 'ls-remote --tags .git' '
 
 	git ls-remote --tags .git >actual &&
-	diff -u expected.tag actual
+	test_compare_expect expected.tag actual
 
 '
 
 test_expect_success 'ls-remote .git' '
 
 	git ls-remote .git >actual &&
-	diff -u expected.all actual
+	test_compare_expect expected.all actual
 
 '
 
 test_expect_success 'ls-remote --tags self' '
 
 	git ls-remote --tags self >actual &&
-	diff -u expected.tag actual
+	test_compare_expect expected.tag actual
 
 '
 
 test_expect_success 'ls-remote self' '
 
 	git ls-remote self >actual &&
-	diff -u expected.all actual
+	test_compare_expect expected.all actual
 
 '
 
diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh
index 31c1081..85ff226 100755
--- a/t/t5515-fetch-merge-logic.sh
+++ b/t/t5515-fetch-merge-logic.sh
@@ -148,7 +148,7 @@ do
 		} >"$actual" &&
 		if test -f "$expect"
 		then
-			git diff -u "$expect" "$actual" &&
+			test_compare_expect "$expect" "$actual" &&
 			rm -f "$actual"
 		else
 			# this is to help developing new tests.
diff --git a/t/t6004-rev-list-path-optim.sh b/t/t6004-rev-list-path-optim.sh
index 80d7198..0624cc4 100755
--- a/t/t6004-rev-list-path-optim.sh
+++ b/t/t6004-rev-list-path-optim.sh
@@ -45,7 +45,7 @@ test_expect_success 'further setup' '
 test_expect_success 'path optimization 2' '
 	( echo "$side"; echo "$initial" ) >expected &&
 	git rev-list HEAD -- a >actual &&
-	diff -u expected actual
+	test_compare_expect expected actual
 '
 
 test_done
diff --git a/t/t6009-rev-list-parent.sh b/t/t6009-rev-list-parent.sh
index be3d238..763934a 100755
--- a/t/t6009-rev-list-parent.sh
+++ b/t/t6009-rev-list-parent.sh
@@ -31,7 +31,7 @@ test_expect_failure 'one is ancestor of others and should not be shown' '
 
 	git rev-list one --not four >result &&
 	>expect &&
-	diff -u expect result
+	test_compare_expect expect result
 
 '
 
diff --git a/t/t6027-merge-binary.sh b/t/t6027-merge-binary.sh
index a7358f7..0731022 100755
--- a/t/t6027-merge-binary.sh
+++ b/t/t6027-merge-binary.sh
@@ -45,7 +45,7 @@ test_expect_success resolve '
 		false
 	else
 		git ls-files -s >current
-		diff -u current expect
+		test_compare_expect current expect
 	fi
 '
 
@@ -60,7 +60,7 @@ test_expect_success recursive '
 		false
 	else
 		git ls-files -s >current
-		diff -u current expect
+		test_compare_expect current expect
 	fi
 '
 
diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh
index e809e0e..8351841 100755
--- a/t/t7010-setup.sh
+++ b/t/t7010-setup.sh
@@ -18,7 +18,7 @@ test_expect_success 'git add (absolute)' '
 	git add "$D/a/b/c/d" &&
 	git ls-files >current &&
 	echo a/b/c/d >expect &&
-	diff -u expect current
+	test_compare_expect expect current
 
 '
 
@@ -32,7 +32,7 @@ test_expect_success 'git add (funny relative)' '
 	) &&
 	git ls-files >current &&
 	echo a/e/f >expect &&
-	diff -u expect current
+	test_compare_expect expect current
 
 '
 
@@ -43,7 +43,7 @@ test_expect_success 'git rm (absolute)' '
 	git rm -f --cached "$D/a/b/c/d" &&
 	git ls-files >current &&
 	echo a/e/f >expect &&
-	diff -u expect current
+	test_compare_expect expect current
 
 '
 
@@ -57,7 +57,7 @@ test_expect_success 'git rm (funny relative)' '
 	) &&
 	git ls-files >current &&
 	echo a/b/c/d >expect &&
-	diff -u expect current
+	test_compare_expect expect current
 
 '
 
@@ -67,7 +67,7 @@ test_expect_success 'git ls-files (absolute)' '
 	git add a &&
 	git ls-files "$D/a/e/../b" >current &&
 	echo a/b/c/d >expect &&
-	diff -u expect current
+	test_compare_expect expect current
 
 '
 
@@ -80,7 +80,7 @@ test_expect_success 'git ls-files (relative #1)' '
 		git ls-files "../b/c"
 	)  >current &&
 	echo c/d >expect &&
-	diff -u expect current
+	test_compare_expect expect current
 
 '
 
@@ -93,7 +93,7 @@ test_expect_success 'git ls-files (relative #2)' '
 		git ls-files --full-name "../e/f"
 	)  >current &&
 	echo a/e/f >expect &&
-	diff -u expect current
+	test_compare_expect expect current
 
 '
 
@@ -126,13 +126,13 @@ test_expect_success 'log using absolute path names' '
 
 	git log a/b/c/d >f1.txt &&
 	git log "$(pwd)/a/b/c/d" >f2.txt &&
-	diff -u f1.txt f2.txt
+	test_compare_expect f1.txt f2.txt
 '
 
 test_expect_success 'blame using absolute path names' '
 	git blame a/b/c/d >f1.txt &&
 	git blame "$(pwd)/a/b/c/d" >f2.txt &&
-	diff -u f1.txt f2.txt
+	test_compare_expect f1.txt f2.txt
 '
 
 test_expect_success 'setup deeper work tree' '
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index 361886c..f2d89c0 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -203,7 +203,7 @@ test_expect_success 'sign off (1)' '
 		git var GIT_COMMITTER_IDENT |
 		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
 	) >expected &&
-	diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -223,7 +223,7 @@ $existing" &&
 		git var GIT_COMMITTER_IDENT |
 		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
 	) >expected &&
-	diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -240,7 +240,7 @@ test_expect_success 'multiple -m' '
 		echo
 		echo three
 	) >expected &&
-	diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -301,12 +301,12 @@ test_expect_success 'same tree (merge and amend merge)' '
 	git merge -s ours side -m "empty ok" &&
 	git diff HEAD^ HEAD >actual &&
 	: >expected &&
-	diff -u expected actual &&
+	test_compare_expect expected actual &&
 
 	git commit --amend -m "empty really ok" &&
 	git diff HEAD^ HEAD >actual &&
 	: >expected &&
-	diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -323,7 +323,7 @@ test_expect_success 'amend using the message from another commit' '
 	git commit --allow-empty --amend -C "$old" &&
 	git show --pretty="format:%ad %s" "$old" >expected &&
 	git show --pretty="format:%ad %s" HEAD >actual &&
-	diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
@@ -341,7 +341,7 @@ test_expect_success 'amend using the message from a commit named with tag' '
 	git commit --allow-empty --amend -C tagged-old &&
 	git show --pretty="format:%ad %s" "$old" >expected &&
 	git show --pretty="format:%ad %s" HEAD >actual &&
-	diff -u expected actual
+	test_compare_expect expected actual
 
 '
 
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index b780fdd..f9616bf 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -85,7 +85,7 @@ test_expect_success 'verbose' '
 	git add negative &&
 	git status -v | sed -ne "/^diff --git /p" >actual &&
 	echo "diff --git a/negative b/negative" >expect &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
@@ -95,7 +95,7 @@ test_expect_success 'cleanup commit messages (verbatim,-t)' '
 	{ echo;echo "# text";echo; } >expect &&
 	git commit --cleanup=verbatim -t expect -a &&
 	git cat-file -p HEAD |sed -e "1,/^\$/d" |head -n 3 >actual &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
@@ -104,7 +104,7 @@ test_expect_success 'cleanup commit messages (verbatim,-F)' '
 	echo >>negative &&
 	git commit --cleanup=verbatim -F expect -a &&
 	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
@@ -113,7 +113,7 @@ test_expect_success 'cleanup commit messages (verbatim,-m)' '
 	echo >>negative &&
 	git commit --cleanup=verbatim -m "$(cat expect)" -a &&
 	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
@@ -124,7 +124,7 @@ test_expect_success 'cleanup commit messages (whitespace,-F)' '
 	echo "# text" >expect &&
 	git commit --cleanup=whitespace -F text -a &&
 	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
@@ -135,7 +135,7 @@ test_expect_success 'cleanup commit messages (strip,-F)' '
 	echo sample >expect &&
 	git commit --cleanup=strip -F text -a &&
 	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
@@ -150,7 +150,7 @@ test_expect_success 'cleanup commit messages (strip,-F,-e)' '
 	{ echo;echo sample;echo; } >text &&
 	git commit -e -F text -a &&
 	head -n 4 .git/COMMIT_EDITMSG >actual &&
-	diff -u expect actual
+	test_compare_expect expect actual
 
 '
 
diff --git a/t/t7502-status.sh b/t/t7502-status.sh
index e006074..9b9c7a7 100755
--- a/t/t7502-status.sh
+++ b/t/t7502-status.sh
@@ -146,7 +146,7 @@ cat <<EOF >expect
 EOF
 test_expect_success 'status of partial commit excluding new file in index' '
 	git status dir1/modified >output &&
-	diff -u expect output
+	test_compare_expect expect output
 '
 
 test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 50c51c8..15efd65 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -108,7 +108,7 @@ create_merge_msgs() {
 }
 
 verify_diff() {
-	if ! diff -u "$1" "$2"
+	if ! test_compare_expect "$1" "$2"
 	then
 		echo "$3"
 		false
diff --git a/t/t8003-blame.sh b/t/t8003-blame.sh
index db51b3a..153f3e2 100755
--- a/t/t8003-blame.sh
+++ b/t/t8003-blame.sh
@@ -112,7 +112,7 @@ test_expect_success 'blame wholesale copy' '
 		echo mouse-Second
 		echo mouse-Third
 	} >expected &&
-	diff -u expected current
+	test_compare_expect expected current
 
 '
 
@@ -125,7 +125,7 @@ test_expect_success 'blame wholesale copy and more' '
 		echo cow-Fifth
 		echo mouse-Third
 	} >expected &&
-	diff -u expected current
+	test_compare_expect expected current
 
 '
 
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index 2efaed4..7342780 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -75,7 +75,7 @@ test_expect_success 'Show all headers' '
 		-e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
 		-e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
 		>actual-show-all-headers &&
-	diff -u expected-show-all-headers actual-show-all-headers
+	test_compare_expect expected-show-all-headers actual-show-all-headers
 '
 
 z8=zzzzzzzz
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index 902ed41..80f3b39 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -55,74 +55,74 @@ printf 'r1 \nr2 \nr4 \n' > expected-range-r1-r2-r4
 
 test_expect_success 'test ascending revision range' "
 	git reset --hard trunk &&
-	git svn log -r 1:4 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r1-r2-r4 -
+	git svn log -r 1:4 | grep '^r[0-9]' | cut -d'|' -f1 | test_compare_expect expected-range-r1-r2-r4 -
 	"
 
 printf 'r4 \nr2 \nr1 \n' > expected-range-r4-r2-r1
 
 test_expect_success 'test descending revision range' "
 	git reset --hard trunk &&
-	git svn log -r 4:1 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4-r2-r1 -
+	git svn log -r 4:1 | grep '^r[0-9]' | cut -d'|' -f1 | test_compare_expect expected-range-r4-r2-r1 -
 	"
 
 printf 'r1 \nr2 \n' > expected-range-r1-r2
 
 test_expect_success 'test ascending revision range with unreachable revision' "
 	git reset --hard trunk &&
-	git svn log -r 1:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r1-r2 -
+	git svn log -r 1:3 | grep '^r[0-9]' | cut -d'|' -f1 | test_compare_expect expected-range-r1-r2 -
 	"
 
 printf 'r2 \nr1 \n' > expected-range-r2-r1
 
 test_expect_success 'test descending revision range with unreachable revision' "
 	git reset --hard trunk &&
-	git svn log -r 3:1 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2-r1 -
+	git svn log -r 3:1 | grep '^r[0-9]' | cut -d'|' -f1 | test_compare_expect expected-range-r2-r1 -
 	"
 
 printf 'r2 \n' > expected-range-r2
 
 test_expect_success 'test ascending revision range with unreachable upper boundary revision and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 2:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2 -
+	git svn log -r 2:3 | grep '^r[0-9]' | cut -d'|' -f1 | test_compare_expect expected-range-r2 -
 	"
 
 test_expect_success 'test descending revision range with unreachable upper boundary revision and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 3:2 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2 -
+	git svn log -r 3:2 | grep '^r[0-9]' | cut -d'|' -f1 | test_compare_expect expected-range-r2 -
 	"
 
 printf 'r4 \n' > expected-range-r4
 
 test_expect_success 'test ascending revision range with unreachable lower boundary revision and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 3:4 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+	git svn log -r 3:4 | grep '^r[0-9]' | cut -d'|' -f1 | test_compare_expect expected-range-r4 -
 	"
 
 test_expect_success 'test descending revision range with unreachable lower boundary revision and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 4:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+	git svn log -r 4:3 | grep '^r[0-9]' | cut -d'|' -f1 | test_compare_expect expected-range-r4 -
 	"
 
 printf -- '------------------------------------------------------------------------\n' > expected-separator
 
 test_expect_success 'test ascending revision range with unreachable boundary revisions and no commits' "
 	git reset --hard trunk &&
-	git svn log -r 5:6 | diff -u expected-separator -
+	git svn log -r 5:6 | test_compare_expect expected-separator -
 	"
 
 test_expect_success 'test descending revision range with unreachable boundary revisions and no commits' "
 	git reset --hard trunk &&
-	git svn log -r 6:5 | diff -u expected-separator -
+	git svn log -r 6:5 | test_compare_expect expected-separator -
 	"
 
 test_expect_success 'test ascending revision range with unreachable boundary revisions and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 3:5 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+	git svn log -r 3:5 | grep '^r[0-9]' | cut -d'|' -f1 | test_compare_expect expected-range-r4 -
 	"
 
 test_expect_success 'test descending revision range with unreachable boundary revisions and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 5:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+	git svn log -r 5:3 | grep '^r[0-9]' | cut -d'|' -f1 | test_compare_expect expected-range-r4 -
 	"
 
 test_done
diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh
index 58c59ed..2677799 100755
--- a/t/t9200-git-cvsexportcommit.sh
+++ b/t/t9200-git-cvsexportcommit.sh
@@ -37,7 +37,7 @@ check_entries () {
 	else
 		printf '%s\n' "$2" | tr '|' '\012' >expected
 	fi
-	diff -u expected actual
+	test_compare_expect expected actual
 }
 
 test_expect_success \
@@ -257,8 +257,8 @@ test_expect_success '-w option should work with relative GIT_DIR' '
       (cd "$GIT_DIR" &&
       GIT_DIR=. git cvsexportcommit -w "$CVSWORK" -c $id &&
       check_entries "$CVSWORK/W" "file1.txt/1.1/|file2.txt/1.1/" &&
-      diff -u "$CVSWORK/W/file1.txt" ../W/file1.txt &&
-      diff -u "$CVSWORK/W/file2.txt" ../W/file2.txt
+      test_compare_expect "$CVSWORK/W/file1.txt" ../W/file1.txt &&
+      test_compare_expect "$CVSWORK/W/file2.txt" ../W/file2.txt
       )
 '
 
@@ -279,9 +279,9 @@ test_expect_success 'check files before directories' '
 	git cvsexportcommit -w "$CVSWORK" -c $id &&
 	check_entries "$CVSWORK/E" "DS/1.1/|newfile5.txt/1.1/" &&
 	check_entries "$CVSWORK" "DS/1.1/|release-notes/1.2/" &&
-	diff -u "$CVSWORK/DS" DS &&
-	diff -u "$CVSWORK/E/DS" E/DS &&
-	diff -u "$CVSWORK/release-notes" release-notes
+	test_compare_expect "$CVSWORK/DS" DS &&
+	test_compare_expect "$CVSWORK/E/DS" E/DS &&
+	test_compare_expect "$CVSWORK/release-notes" release-notes
 
 '
 
@@ -293,7 +293,7 @@ test_expect_success 'commit a file with leading spaces in the name' '
 	id=$(git rev-parse HEAD) &&
 	git cvsexportcommit -w "$CVSWORK" -c $id &&
 	check_entries "$CVSWORK" " space/1.1/|DS/1.1/|release-notes/1.2/" &&
-	diff -u "$CVSWORK/ space" " space"
+	test_compare_expect "$CVSWORK/ space" " space"
 
 '
 
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index cceedbb..5b5ef19 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -117,7 +117,7 @@ test_expect_success \
 		--import-marks=marks.out \
 		--export-marks=marks.new \
 		</dev/null &&
-	git diff -u expect marks.new'
+	test_compare_expect expect marks.new'
 
 test_tick
 cat >input <<INPUT_END
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 83889c4..73cc867 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -52,6 +52,9 @@ case $(echo $GIT_TRACE |tr "[A-Z]" "[a-z]") in
 		;;
 esac
 
+test_use_diff_u=t
+test_compare_stdin_file_=
+
 # Each test should start with something like this, after copyright notices:
 #
 # test_description='Description of this test...
@@ -79,6 +82,8 @@ do
 		verbose=t; shift ;;
 	-q|--q|--qu|--qui|--quie|--quiet)
 		quiet=t; shift ;;
+	--no-diff-u)
+		test_use_diff_u=; shift ;;
 	--no-color)
 	    color=; shift ;;
 	--no-python)
@@ -270,6 +275,24 @@ test_expect_code () {
 	echo >&3 ""
 }
 
+# Compare expected output and actual one.  The latter can be
+# '-' to compare the expected with the standard input
+test_compare_expect () {
+	case "$test_use_diff_u" in
+	t)
+		diff -u "$1" "$2" ;;
+	*)
+		case "$test_compare_stdin_file_" in
+		'')
+			test_compare_stdin_file_=/tmp/gittest.$$
+		esac
+		cat "$1" >"$test_compare_stdin_file_.1"
+		cat "$2" >"$test_compare_stdin_file_.2"
+		git diff -u --no-index \
+		"$test_compare_stdin_file_.1" "$test_compare_stdin_file_.2" ;;
+	esac
+}
+
 # Most tests can use the created repository, but some may need to create more.
 # Usage: test_create_repo <directory>
 test_create_repo () {
@@ -288,6 +311,10 @@ test_create_repo () {
 test_done () {
 	trap - exit
 
+	if test -n "$test_compare_stdin_file_"
+	then
+		rm -f "$test_compare_stdin_file_.[12]"
+	fi
 	if test "$test_fixed" != 0
 	then
 		say_color pass "fixed $test_fixed known breakage(s)"
-- 
1.5.4.2.261.g851a5

^ permalink raw reply related	[relevance 1%]

* [ANNOUNCE] GIT 1.5.4.3
@ 2008-02-23 21:07  3% Junio C Hamano
  0 siblings, 0 replies; 200+ results
From: Junio C Hamano @ 2008-02-23 21:07 UTC (permalink / raw)
  To: git; +Cc: linux-kernel

The latest maintenance release GIT 1.5.4.3 is available at the
usual places:

  http://www.kernel.org/pub/software/scm/git/

  git-1.5.4.3.tar.{gz,bz2}			(tarball)
  git-htmldocs-1.5.4.3.tar.{gz,bz2}		(preformatted docs)
  git-manpages-1.5.4.3.tar.{gz,bz2}		(preformatted docs)
  RPMS/$arch/git-*-1.5.4.3-1.$arch.rpm	(RPM)

Largest user visible change in this is RPM packaging updates by
Kristian Høgsberg.  'git-core' will only be pure git without
pulling foreign SCM packages in as its dependencies anymore when
you do "yum install git-core".

----------------------------------------------------------------

GIT v1.5.4.3 Release Notes
==========================

Fixes since v1.5.4.2
--------------------

 * RPM spec used to pull in everything with 'git'.  This has been
   changed so that 'git' package contains just the core parts,
   and we now supply 'git-all' metapackage to slurp in everything.
   This should match end user's expectation better.

 * When some refs failed to update, git-push reported "failure"
   which was unclear if some other refs were updated or all of
   them failed atomically (the answer is the former).  Reworded
   the message to clarify this.

 * "git clone" from a repository whose HEAD was misconfigured
   did not set up the remote properly.  Now it tries to do
   better.

 * Updated git-push documentation to clarify what "matching"
   means, in order to reduce user confusion.

 * Updated git-add documentation to clarify "add -u" operates in
   the current subdirectory you are in, just like other commands.

 * git-gui updates to work on OSX and Windows better.

----------------------------------------------------------------

Changes since v1.5.4.2 are as follows:

Gerrit Pape (1):
      git-clone.sh: properly configure remote even if remote's head is dangling

Jay Soffian (2):
      git-gui: support Git Gui.app under OS X 10.5
      send-email: squelch warning due to comparing undefined $_ to ""

Jeff King (4):
      push: indicate partialness of error message
      Documentation/push: clarify matching refspec behavior
      push: document the status output
      hash: fix lookup_hash semantics

Junio C Hamano (1):
      GIT 1.5.4.3

Kristian H淡gsberg (1):
      Rename git-core rpm to just git and rename the meta-pacakge to git-all.

Miklos Vajna (1):
      Documentation/git-stash: document options for git stash list

Pekka Kaitaniemi (1):
      Clarified the meaning of git-add -u in the documentation

Shawn O. Pearce (5):
      git-gui: Ensure error dialogs always appear over all other windows
      git-gui: Paper bag fix error dialogs opening over the main window
      git-gui: Default TCL_PATH to same location as TCLTK_PATH
      git-gui: Avoid hardcoded Windows paths in Cygwin package files
      git-gui: Focus insertion point at end of strings in repository chooser

Wincent Colaiuta (1):
      git-gui: relax "dirty" version detection

^ permalink raw reply	[relevance 3%]

* Re: on subtree checkout
  @ 2008-02-24 15:59  5%       ` Matthieu Moy
  2008-02-24 17:22  2%         ` Robin Rosenberg
  0 siblings, 1 reply; 200+ results
From: Matthieu Moy @ 2008-02-24 15:59 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: Nguyen Thai Ngoc Duy, git mailing list

Jakub Narebski <jnareb@gmail.com> writes:

> Nguyen Thai Ngoc Duy wrote:
>> On Sun, Feb 24, 2008 at 5:03 PM, Jakub Narebski <jnareb@gmail.com> wrote:
>>>
>>> "Nguyen Thai Ngoc Duy" <pclouds@gmail.com> writes:
>>>
>>>> I'm going to implement subtree checkout. [...]
>>>
>>>  As far as I can see the problem lies in merging...
>> 
>> Can you elaborate? I'm really noob at merging.
>
> What to do if when merging, or rebasing, there is conflict _outside_
> checked out subtree?

I suppose you have to forbid merges where anything non-trivial happens
outside the tree (i.e. allow it only if the set of renamed or changed
files is disjoint outside the tree, or only if only one of the
branches to merge have changes outside the tree).

That's probably not such a big limitation in practice for the user,
since by definition the user won't modify the files outside its tree,
so he can at least still merge with the branch he branched from.

I can see another problem: partial checkout is really interesting only
if you can do a partial clone ("partial" here in the sense "subtree").
Otherwise, your .git/ still eats your disk space and "clone" still
needs your bandwidth for something you won't use.

-- 
Matthieu

^ permalink raw reply	[relevance 5%]

* Re: on subtree checkout
  2008-02-24 15:59  5%       ` Matthieu Moy
@ 2008-02-24 17:22  2%         ` Robin Rosenberg
  0 siblings, 0 replies; 200+ results
From: Robin Rosenberg @ 2008-02-24 17:22 UTC (permalink / raw)
  To: Matthieu Moy; +Cc: Jakub Narebski, Nguyen Thai Ngoc Duy, git mailing list

söndagen den 24 februari 2008 skrev Matthieu Moy:
> I suppose you have to forbid merges where anything non-trivial happens
> outside the tree (i.e. allow it only if the set of renamed or changed
> files is disjoint outside the tree, or only if only one of the
> branches to merge have changes outside the tree).
One still has to allow it, maybe forcing a bigger checkout in those
cases.

> That's probably not such a big limitation in practice for the user,
> since by definition the user won't modify the files outside its tree,
> so he can at least still merge with the branch he branched from.
Partial checkout is for convenience and speed of worktree operations as 
I see it. Other people could have other reasons for it. Branch switching takes a lot of time with big repos, same thing with git status, add -u etc. Restricting the worktree scan for uninteresting parts speeds things up.

> I can see another problem: partial checkout is really interesting only
> if you can do a partial clone ("partial" here in the sense "subtree").
> Otherwise, your .git/ still eats your disk space and "clone" still
> needs your bandwidth for something you won't use.

Better and more of "global" operations on repos with submodules might make them more bearable, and maybe even convenient, for example doing a git diff
over a set of submodules detecting renames between submodules.

-- robin

^ permalink raw reply	[relevance 2%]

* Re: on subtree checkout
  @ 2008-02-26  2:30  3%   ` David Symonds
  2008-02-26 11:23  2%     ` Johannes Schindelin
  0 siblings, 1 reply; 200+ results
From: David Symonds @ 2008-02-26  2:30 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Nguyen Thai Ngoc Duy, git mailing list

On Mon, Feb 25, 2008 at 5:59 PM, Johannes Schindelin
<Johannes.Schindelin@gmx.de> wrote:
> Hi,
>
>
>  On Sun, 24 Feb 2008, Nguyen Thai Ngoc Duy wrote:
>
>  > I'm going to implement subtree checkout. The plan is to save "index
>  > prefix" in GIT_DIR/prefix and update git commands to use index prefix
>  > when accessing the index. If I'm heading a wrong way, stop me now.
>
>  As I wrote a long time ago already, I think the correct approach would be
>  to reuse the code for the core.ignoreStat feature.
>
>  But I agree with others that you should think about sane implementations
>  of rebase/merge with partial checkouts.

I, too, was shortly going to attempt a partial checkout/clone
implementation. The intended context of my implementation was similar
to the KDE scenario in that you might only care about /pkgA and /pkgB,
so changes to /pkgC are usually irrelevant and independent to your
work-flow, so I was planning to assume a simplistic "theirs" merge
strategy for /pkgC, etc.


Dave.

^ permalink raw reply	[relevance 3%]

* Re: on subtree checkout
  2008-02-26  2:30  3%   ` David Symonds
@ 2008-02-26 11:23  2%     ` Johannes Schindelin
  0 siblings, 0 replies; 200+ results
From: Johannes Schindelin @ 2008-02-26 11:23 UTC (permalink / raw)
  To: David Symonds; +Cc: Nguyen Thai Ngoc Duy, git mailing list

Hi,

On Mon, 25 Feb 2008, David Symonds wrote:

> On Mon, Feb 25, 2008 at 5:59 PM, Johannes Schindelin 
> <Johannes.Schindelin@gmx.de> wrote:
> >
> > But I agree with others that you should think about sane 
> > implementations of rebase/merge with partial checkouts.
> 
> I, too, was shortly going to attempt a partial checkout/clone 
> implementation. The intended context of my implementation was similar to 
> the KDE scenario in that you might only care about /pkgA and /pkgB, so 
> changes to /pkgC are usually irrelevant and independent to your 
> work-flow, so I was planning to assume a simplistic "theirs" merge 
> strategy for /pkgC, etc.

That might work for the people who have partial checkouts.  But I see a 
lot of problems looming there: just imagine a documenter rebased on top of 
'master', and _then_ on top of a branch by another documenter, which is 
newer with respect to documentation, but older with respect to the code.

It is _really_ easy to break code if you have no intention to test the 
result of a merge, _especially_ so when it is a "theirs" strategy.

Ciao,
Dscho

^ permalink raw reply	[relevance 2%]

* Re: Google Summer of Code 2008
  @ 2008-02-29 12:04  4%     ` Jakub Narebski
  0 siblings, 0 replies; 200+ results
From: Jakub Narebski @ 2008-02-29 12:04 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Shawn O. Pearce, Robin Rosenberg, git, John Hawley

On Thu, 28 Feb 2008, Johannes Schindelin wrote:
> Do go ahead!  I started the page
> 
>         http://git.or.cz/gitwiki/SoC2008Ideas
> 
> which is utterly incomplete.  I just took the ideas of 2007 that I am 
> still interested in,

By the way, when looking at 2007 GSoC ideas one can see that some of 
them got implemented already outside of GSoC, and are no longer valid; 
well, perhaps as "improve <sth>" ideas. 

Subproject/submodule support got implemented, Mozilla has decided to use 
Mecurial instead of Git (but there are other large-scale imports: 
OpenOffice.org, GCC) and cvs2svn supports fast-import output which 
means export to git, gitattributes support got much extended.

> and removed other people from the Mentor list,  
> because I do not want to force them.  So please, if you are interested
> in mentoring one of the existing projects, just add yourself.
> 
> And of course add all those cool projects you have in mind.

I have some interesting ideas for GSoC, but unfortunately none (with 
perhaps single exception) that I could mentor. So I think I'd list them 
here for now, and later I'd add it to SoC2008Ideas page.

Here they are.

First, a few ideas which got partially implemented already, or are 
implemented and need improvements. I don't know if current contributors 
would want to be mentors, or would they want to submit their work under 
GSoC as participants.

* Lazy clone / remote alternates

  The idea here is to be able to remotely access objects from a network
  based object server, as neededm rather than having them all local.

  Goal: A working lazy clone prototype implementation that could be
  considered for inclusion, in a nice series of commits (separate
  branch/fork)
  Language: C
  Suggested mentor: Jan Holesovsky, who submitted proof-of-concept
  patch for lazy clone

* Partial (subtree) checkout, or its generalization: sparse checkout

  The idea is to checkout for example only Documentation subdirectory,
  work on it, but commit full tree. Some workflows may be better suited
  to this type of usage than using submodules. Optionally should include
  partial clone (not needed objects not in repository).

  Goal: A working partial checkout prototype implementation, with
  technical documentation.
  Language: C
  Suggested mentors: 
    gitzilla (sent proposal), 
    Nguyen Thai Ngoc Duy (pclouds), proposed to implements it

* Gitweb caching

  Implementing very smart caching in gitweb, to avoid the thundering
  herd problem on kernel.org whenever a repository gets updated, or at
  least support for caching engines in the form of generating proper
  Last-Modified: and ETag: headers, and responding to If-Modified-Since:
  and If-None-Match: requests, cheaply. 

  Perhaps becoming the gitweb maintainer could come of it, or at least
  the gitweb admin for kernel.org (sorely needed).

  Goal: At minimum, port kernel.org's caching to mainline (git's) gitweb
  Language: Perl, HTML, perhaps JavaScript
  Suggested mentors:
    John 'Warthog9' Hawley (wrote caching for kernel.org's gitweb)
    Petr Baudis (repo.or.cz admin)
    Lars Hjemli (cgit author, git web interface in C, with caching)
    Jakub Narebski (gitweb contributor)

Then, a few ideas which were proposed for GSoC 2007, but never 
implemented, and wasn't mentioned in this thread or on wiki for
GSoC 2008 yet

* Git / Subversion Interoperability

  The idea here is implement something in Git that speaks the Subversion
  protocol on the wire, but uses Git as the backend storage. (This would
  be like the existing git-cvsserver.)

  There are two potential approaches:

   1. git-svnserver
   2. write a backend for Subversion

  Goal: To be able to access git repository, at minimum read-only, from
  a Subversion client, at least svn CLI.
  Language: Open for proposal.
  Suggested mentors: 
    Eric Wong (git-svn author)
    Matthias Urlichs (git-svnimport author)
  Notes: I don't think we could pass it as Subversion SoC project, but
  I guess that we could ask for co-mentor for the Subversion protocol,
  or Subversion backend part of this task.

I'd send other ideas (including new ones, like translating svn:externals 
into git submodules in git-svn; or making git mode for Emacs have all 
features of tig, git-gui and gitk; or improving shallow clone support)
in a later post.

> Shawn, do we have to do the same again, as on this page?
> 
>         http://git.or.cz/gitwiki/Soc2007Application

A few things changes for us: we have participated in GSoC 2007; we need 
to find backup organization administrator (was: Martin Langhoff for 
GSoC2007), list of mentors would change most probably.

As far as I've checked the application form for organizations didn't 
change...
-- 
Jakub Narebski
Poland

^ permalink raw reply	[relevance 4%]

* Re: [QUESTION] Selective fetch possible?
  @ 2008-03-10 23:34  2%   ` Jakub Narebski
  2008-03-11  7:26  0%     ` Rogan Dawes
  0 siblings, 1 reply; 200+ results
From: Jakub Narebski @ 2008-03-10 23:34 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Filippo Zangheri, git

"Shawn O. Pearce" <spearce@spearce.org> writes:

> Filippo Zangheri <filippo.zangheri@yahoo.it> wrote:
> >
> > Is it possible to git-fetch only a portion of the tree
> > of the specified repository, say, fetch only one directory or a
> > subset of files matching some regular expression? This is currently
> > - to my knowledge - only possible via wget iff the GIT repository
> > has gitweb enabled. But that's just a workaround.
> 
> No.
> 
> You can use a shallow clone to fetch only X commits back into
> history on any branch, and you can also manually configure the
> fetch specification in .git/config to only fetch specific branches,
> but you must fetch the entire tree to get any of the files in it.
> 
> If the repository is available by git:// protocol you may be able
> to use git-archive to obtain a tarfile for just the directory you
> want (service has to be enabled on the remote side) but that is
> just a raw UNIX tar; there is no Git repository and no ability to
> commit/fetch/push/diff/apply/log/etc.

Note that what you wanted is, I guess, something called partial
checkout or subtree checkout.  This feature appears now and then in
feature requests; lately Nguyen Thai Ngoc Duy (pclouds) offered to do
this in "on subtree checkout" thread:
  http://thread.gmane.org/gmane.comp.version-control.git/74915

The problem is twofold, as far as I understand it.  First, what to do
if there is merge conflicts outside checked out (selected) directory?
Second, how to make repository contain only relevant objects: git in
many places assumes full connectivity, and that if it has an object it
hass all objects depending on it.

-- 
Jakub Narebski
Poland
ShadeHawk on #git

^ permalink raw reply	[relevance 2%]

* Re: [QUESTION] Selective fetch possible?
  2008-03-10 23:34  2%   ` Jakub Narebski
@ 2008-03-11  7:26  0%     ` Rogan Dawes
    0 siblings, 1 reply; 200+ results
From: Rogan Dawes @ 2008-03-11  7:26 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: Shawn O. Pearce, Filippo Zangheri, git

Jakub Narebski wrote:
> "Shawn O. Pearce" <spearce@spearce.org> writes:
> 
>> Filippo Zangheri <filippo.zangheri@yahoo.it> wrote:
>>> Is it possible to git-fetch only a portion of the tree
>>> of the specified repository, say, fetch only one directory or a
>>> subset of files matching some regular expression? This is currently
>>> - to my knowledge - only possible via wget iff the GIT repository
>>> has gitweb enabled. But that's just a workaround.
>> No.
>>
>> You can use a shallow clone to fetch only X commits back into
>> history on any branch, and you can also manually configure the
>> fetch specification in .git/config to only fetch specific branches,
>> but you must fetch the entire tree to get any of the files in it.
>>
>> If the repository is available by git:// protocol you may be able
>> to use git-archive to obtain a tarfile for just the directory you
>> want (service has to be enabled on the remote side) but that is
>> just a raw UNIX tar; there is no Git repository and no ability to
>> commit/fetch/push/diff/apply/log/etc.
> 
> Note that what you wanted is, I guess, something called partial
> checkout or subtree checkout.  This feature appears now and then in
> feature requests; lately Nguyen Thai Ngoc Duy (pclouds) offered to do
> this in "on subtree checkout" thread:
>   http://thread.gmane.org/gmane.comp.version-control.git/74915

I still believe that it could be done fairly easily by simply recording 
the SHA1's of the files and directories that are *not* checked out 
somewhere in the .git directory, and just reusing those when checking 
the working tree. i.e. rather than stat-ing a tree that was never 
checked out, get the known SHA1 for that tree from where it was recorded 
on checkout.

> The problem is twofold, as far as I understand it.  First, what to do
> if there is merge conflicts outside checked out (selected) directory?

This is something that has been repeated many times, and I fail to see 
how it can be an issue. How can there be a conflict in a directory that 
is not, and never has been, checked out, and therefore cannot have been 
modified?

The only possibility that I can see is if the directory has been renamed 
elsewhere, but in that case, it *is* effectively checked out (just with 
a different directory name).

> Second, how to make repository contain only relevant objects: git in
> many places assumes full connectivity, and that if it has an object it
> hass all objects depending on it.
> 

Yes, this is the big problem as I see it.

Rogan

^ permalink raw reply	[relevance 0%]

* Re: [QUESTION] Selective fetch possible?
  @ 2008-03-11  9:07  3%         ` Rogan Dawes
  0 siblings, 0 replies; 200+ results
From: Rogan Dawes @ 2008-03-11  9:07 UTC (permalink / raw)
  To: Shawn O. Pearce; +Cc: Jakub Narebski, Filippo Zangheri, git

Shawn O. Pearce wrote:
> Rogan Dawes <lists@dawes.za.net> wrote:
>> Jakub Narebski wrote:
>>> "Shawn O. Pearce" <spearce@spearce.org> writes:
>>>
>>>> Filippo Zangheri <filippo.zangheri@yahoo.it> wrote:
>>>>> Is it possible to git-fetch only a portion of the tree
>>>>> of the specified repository, say, fetch only one directory or a
>>>>> subset of files matching some regular expression?
>>> The problem is twofold, as far as I understand it.  First, what to do
>>> if there is merge conflicts outside checked out (selected) directory?
>> This is something that has been repeated many times, and I fail to see 
>> how it can be an issue. How can there be a conflict in a directory that 
>> is not, and never has been, checked out, and therefore cannot have been 
>> modified?
> 
> Given two branches:
> 
> 	code
> 	docs
> 
> and the code people checkout the "src/" subdirectory and the docs
> people checkout the "Documentation/" subdirectory, and they *only*
> every work in that subdirectory, things are fine.
> 
> Until one day some developer also checks out "Documentation/" and
> fixes something in the documentation as part of the same commit
> that makes a code change.  The push this to the code branch.
> 
> Someday in the future a documentation writer merges the code branch
> over to the docs branch, "just keeping it current".
> 
> Now there arises a possiblity of a merge conflict in a part of the
> tree that you do not have checked out.
> 
> 
> If you want to say "don't ever modify stuff outside of your branch's
> purpose" then why aren't you just using submodules (one for docs and
> one for code) and using a supermodule to tie everything together into
> a "release package"?

Ok, fair enough. Thanks for the example.

I think that one should not *expect* to be able to complete merges with 
only a partial checkout, though. It *may* work in cases where there are 
no conflicts, but I think it would be a perfectly valid error path to 
fail if there is a conflicting merge in a part of the tree that has not 
been checked out.

So, for a user working on partial trees, they would be able to modify 
their partial tree, and check in their changes, but merges would have to 
be done by someone with a complete checkout. For the given examples 
where partial trees make sense (documentation workers), this seems like 
a reasonable compromise.

>>> Second, how to make repository contain only relevant objects: git in
>>> many places assumes full connectivity, and that if it has an object it
>>> hass all objects depending on it.
>>>
>> Yes, this is the big problem as I see it.
> 
> This is easy enough that if the above problem could be resolved
> sufficiently to the git gurus' satisfaction you would be able
> to get some advice on how to solve it.  Its not difficult, just
> damn annoying.  We already do it (to some extent) with grafts and
> shallow clones.

How's my suggestion above?

Rogan

^ permalink raw reply	[relevance 3%]

* [PATCH 06/16] add test_cmp function for test scripts
       [not found]     <cover.1205356737.git.peff@peff.net>
@ 2008-03-12 21:36  1% ` Jeff King
  0 siblings, 0 replies; 200+ results
From: Jeff King @ 2008-03-12 21:36 UTC (permalink / raw)
  To: Whit Armstrong; +Cc: Junio C Hamano, git

Many scripts compare actual and expected output using
"diff -u". This is nicer than "cmp" because the output shows
how the two differ. However, not all versions of diff
understand -u, leading to unnecessary test failure.

This adds a test_cmp function to the test scripts and
switches all "diff -u" invocations to use it. The function
uses the contents of "$GIT_TEST_CMP" to compare its
arguments; the default is "diff -u".

On systems with a less-capable diff, you can do:

  GIT_TEST_CMP=cmp make test

Signed-off-by: Jeff King <peff@peff.net>
---
The replacements were done mechanically with:

  perl -pi -e 's/(?<!git.)diff -u/test_cmp/' t/*.sh

Perhaps this should be a command-line option instead of an environment
variable? Maybe it should be auto-detected or set up in the Makefile?

 t/t0003-attributes.sh              |    2 +-
 t/t0022-crlf-rename.sh             |    2 +-
 t/t1005-read-tree-reset.sh         |    2 +-
 t/t2200-add-update.sh              |    2 +-
 t/t3001-ls-files-others-exclude.sh |    2 +-
 t/t3050-subprojects-fetch.sh       |    4 ++--
 t/t3060-ls-files-with-tree.sh      |    2 +-
 t/t3201-branch-contains.sh         |    6 +++---
 t/t3404-rebase-interactive.sh      |    4 ++--
 t/t3405-rebase-malformed.sh        |    4 ++--
 t/t3406-rebase-message.sh          |    2 +-
 t/t3701-add-interactive.sh         |    4 ++--
 t/t3902-quoted.sh                  |   16 ++++++++--------
 t/t3903-stash.sh                   |    2 +-
 t/t4023-diff-rename-typechange.sh  |    6 +++---
 t/t4024-diff-optimize-common.sh    |    2 +-
 t/t4025-hunk-header.sh             |    2 +-
 t/t4027-diff-submodule.sh          |    6 +++---
 t/t4105-apply-fuzz.sh              |    2 +-
 t/t4125-apply-ws-fuzz.sh           |    8 ++++----
 t/t4150-am-subdir.sh               |   10 +++++-----
 t/t4201-shortlog.sh                |    2 +-
 t/t5505-remote.sh                  |    6 +++---
 t/t5510-fetch.sh                   |    2 +-
 t/t5512-ls-remote.sh               |    8 ++++----
 t/t6004-rev-list-path-optim.sh     |    2 +-
 t/t6009-rev-list-parent.sh         |    2 +-
 t/t6027-merge-binary.sh            |    4 ++--
 t/t6029-merge-subtree.sh           |    2 +-
 t/t7010-setup.sh                   |   18 +++++++++---------
 t/t7201-co.sh                      |   18 +++++++++---------
 t/t7501-commit.sh                  |   14 +++++++-------
 t/t7502-commit.sh                  |   14 +++++++-------
 t/t7502-status.sh                  |    2 +-
 t/t7600-merge.sh                   |    2 +-
 t/t8003-blame.sh                   |    4 ++--
 t/t9001-send-email.sh              |    2 +-
 t/t9116-git-svn-log.sh             |   24 ++++++++++++------------
 t/t9200-git-cvsexportcommit.sh     |   14 +++++++-------
 t/test-lib.sh                      |   18 ++++++++++++++++++
 40 files changed, 133 insertions(+), 115 deletions(-)

diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
index 47f08a4..3faf135 100755
--- a/t/t0003-attributes.sh
+++ b/t/t0003-attributes.sh
@@ -11,7 +11,7 @@ attr_check () {
 
 	git check-attr test -- "$path" >actual &&
 	echo "$path: test: $2" >expect &&
-	diff -u expect actual
+	test_cmp expect actual
 
 }
 
diff --git a/t/t0022-crlf-rename.sh b/t/t0022-crlf-rename.sh
index 430a1d1..7d1ce2d 100755
--- a/t/t0022-crlf-rename.sh
+++ b/t/t0022-crlf-rename.sh
@@ -26,7 +26,7 @@ test_expect_success 'diff -M' '
 	git diff-tree -M -r --name-status HEAD^ HEAD |
 	sed -e "s/R[0-9]*/RNUM/" >actual &&
 	echo "RNUM	sample	elpmas" >expect &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
diff --git a/t/t1005-read-tree-reset.sh b/t/t1005-read-tree-reset.sh
index 8c45564..b0d31f5 100755
--- a/t/t1005-read-tree-reset.sh
+++ b/t/t1005-read-tree-reset.sh
@@ -24,7 +24,7 @@ test_expect_success 'setup' '
 test_expect_success 'reset should work' '
   git read-tree -u --reset HEAD^ &&
   git ls-files >actual &&
-  diff -u expect actual
+  test_cmp expect actual
 '
 
 test_done
diff --git a/t/t2200-add-update.sh b/t/t2200-add-update.sh
index 24f892f..b664341 100755
--- a/t/t2200-add-update.sh
+++ b/t/t2200-add-update.sh
@@ -62,7 +62,7 @@ test_expect_success 'cache tree has not been corrupted' '
 	sed -e "s/ 0	/	/" >expect &&
 	git ls-tree -r $(git write-tree) |
 	sed -e "s/ blob / /" >current &&
-	diff -u expect current
+	test_cmp expect current
 
 '
 
diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh
index b4297ba..55f057c 100755
--- a/t/t3001-ls-files-others-exclude.sh
+++ b/t/t3001-ls-files-others-exclude.sh
@@ -97,7 +97,7 @@ cat > expect << EOF
 EOF
 
 test_expect_success 'git-status honours core.excludesfile' \
-	'diff -u expect output'
+	'test_cmp expect output'
 
 test_expect_success 'trailing slash in exclude allows directory match(1)' '
 
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 34f26a8..2b21b10 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -26,7 +26,7 @@ test_expect_success clone '
 		cd cloned &&
 		(git rev-parse HEAD; git ls-files -s) >../actual
 	) &&
-	diff -u expected actual
+	test_cmp expected actual
 '
 
 test_expect_success advance '
@@ -46,7 +46,7 @@ test_expect_success fetch '
 		git pull &&
 		(git rev-parse HEAD; git ls-files -s) >../actual
 	) &&
-	diff -u expected actual
+	test_cmp expected actual
 '
 
 test_done
diff --git a/t/t3060-ls-files-with-tree.sh b/t/t3060-ls-files-with-tree.sh
index 68eb266..3ce501b 100755
--- a/t/t3060-ls-files-with-tree.sh
+++ b/t/t3060-ls-files-with-tree.sh
@@ -66,6 +66,6 @@ test_expect_success 'git -ls-files --with-tree should succeed from subdir' '
 cd ..
 test_expect_success \
     'git -ls-files --with-tree should add entries from named tree.' \
-    'diff -u expected output'
+    'test_cmp expected output'
 
 test_done
diff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh
index 9ef593f..b4cf628 100755
--- a/t/t3201-branch-contains.sh
+++ b/t/t3201-branch-contains.sh
@@ -31,7 +31,7 @@ test_expect_success 'branch --contains=master' '
 	{
 		echo "  master" && echo "* side"
 	} >expect &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
@@ -41,7 +41,7 @@ test_expect_success 'branch --contains master' '
 	{
 		echo "  master" && echo "* side"
 	} >expect &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
@@ -51,7 +51,7 @@ test_expect_success 'branch --contains=side' '
 	{
 		echo "* side"
 	} >expect &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 9c0acc5..9cf873f 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -146,8 +146,8 @@ EOF
 test_expect_success 'stop on conflicting pick' '
 	git tag new-branch1 &&
 	! git rebase -i master &&
-	diff -u expect .git/.dotest-merge/patch &&
-	diff -u expect2 file1 &&
+	test_cmp expect .git/.dotest-merge/patch &&
+	test_cmp expect2 file1 &&
 	test 4 = $(grep -v "^#" < .git/.dotest-merge/done | wc -l) &&
 	test 0 = $(grep -c "^[^#]" < .git/.dotest-merge/git-rebase-todo)
 '
diff --git a/t/t3405-rebase-malformed.sh b/t/t3405-rebase-malformed.sh
index e4e2e64..e5ad67c 100755
--- a/t/t3405-rebase-malformed.sh
+++ b/t/t3405-rebase-malformed.sh
@@ -41,8 +41,8 @@ test_expect_success rebase '
 	git rebase master side &&
 	git cat-file commit HEAD | sed -e "1,/^\$/d" >F1 &&
 
-	diff -u F0 F1 &&
-	diff -u F F0
+	test_cmp F0 F1 &&
+	test_cmp F F0
 '
 
 test_done
diff --git a/t/t3406-rebase-message.sh b/t/t3406-rebase-message.sh
index 332b2b2..5391080 100755
--- a/t/t3406-rebase-message.sh
+++ b/t/t3406-rebase-message.sh
@@ -37,7 +37,7 @@ test_expect_success 'rebase -m' '
 	git rebase -m master >report &&
 	sed -n -e "/^Already applied: /p" \
 		-e "/^Committed: /p" report >actual &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
diff --git a/t/t3701-add-interactive.sh b/t/t3701-add-interactive.sh
index c8dc1ac..77c90f6 100755
--- a/t/t3701-add-interactive.sh
+++ b/t/t3701-add-interactive.sh
@@ -24,7 +24,7 @@ EOF
 test_expect_success 'diff works (initial)' '
 	(echo d; echo 1) | git add -i >output &&
 	sed -ne "/new file/,/content/p" <output >diff &&
-	diff -u expected diff
+	test_cmp expected diff
 '
 test_expect_success 'revert works (initial)' '
 	git add file &&
@@ -57,7 +57,7 @@ EOF
 test_expect_success 'diff works (commit)' '
 	(echo d; echo 1) | git add -i >output &&
 	sed -ne "/^index/,/content/p" <output >diff &&
-	diff -u expected diff
+	test_cmp expected diff
 '
 test_expect_success 'revert works (commit)' '
 	git add file &&
diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh
index 73da45f..fe4fb51 100755
--- a/t/t3902-quoted.sh
+++ b/t/t3902-quoted.sh
@@ -78,28 +78,28 @@ EOF
 
 test_expect_success 'check fully quoted output from ls-files' '
 
-	git ls-files >current && diff -u expect.quoted current
+	git ls-files >current && test_cmp expect.quoted current
 
 '
 
 test_expect_success 'check fully quoted output from diff-files' '
 
 	git diff --name-only >current &&
-	diff -u expect.quoted current
+	test_cmp expect.quoted current
 
 '
 
 test_expect_success 'check fully quoted output from diff-index' '
 
 	git diff --name-only HEAD >current &&
-	diff -u expect.quoted current
+	test_cmp expect.quoted current
 
 '
 
 test_expect_success 'check fully quoted output from diff-tree' '
 
 	git diff --name-only HEAD^ HEAD >current &&
-	diff -u expect.quoted current
+	test_cmp expect.quoted current
 
 '
 
@@ -111,28 +111,28 @@ test_expect_success 'setting core.quotepath' '
 
 test_expect_success 'check fully quoted output from ls-files' '
 
-	git ls-files >current && diff -u expect.raw current
+	git ls-files >current && test_cmp expect.raw current
 
 '
 
 test_expect_success 'check fully quoted output from diff-files' '
 
 	git diff --name-only >current &&
-	diff -u expect.raw current
+	test_cmp expect.raw current
 
 '
 
 test_expect_success 'check fully quoted output from diff-index' '
 
 	git diff --name-only HEAD >current &&
-	diff -u expect.raw current
+	test_cmp expect.raw current
 
 '
 
 test_expect_success 'check fully quoted output from diff-tree' '
 
 	git diff --name-only HEAD^ HEAD >current &&
-	diff -u expect.raw current
+	test_cmp expect.raw current
 
 '
 
diff --git a/t/t3903-stash.sh b/t/t3903-stash.sh
index aa282e1..2d3ee3b 100755
--- a/t/t3903-stash.sh
+++ b/t/t3903-stash.sh
@@ -34,7 +34,7 @@ EOF
 test_expect_success 'parents of stash' '
 	test $(git rev-parse stash^) = $(git rev-parse HEAD) &&
 	git diff stash^2..stash > output &&
-	diff -u output expect
+	test_cmp output expect
 '
 
 test_expect_success 'apply needs clean working directory' '
diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh
index 255604e..4dbfc6e 100755
--- a/t/t4023-diff-rename-typechange.sh
+++ b/t/t4023-diff-rename-typechange.sh
@@ -57,7 +57,7 @@ test_expect_success 'cross renames to be detected for regular files' '
 		echo "R100	foo	bar"
 		echo "R100	bar	foo"
 	} | sort >expect &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
@@ -68,7 +68,7 @@ test_expect_success 'cross renames to be detected for typechange' '
 		echo "R100	foo	bar"
 		echo "R100	bar	foo"
 	} | sort >expect &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
@@ -79,7 +79,7 @@ test_expect_success 'moves and renames' '
 		echo "R100	foo	bar"
 		echo "T100	foo"
 	} | sort >expect &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
diff --git a/t/t4024-diff-optimize-common.sh b/t/t4024-diff-optimize-common.sh
index 3c66102..c4d733f 100755
--- a/t/t4024-diff-optimize-common.sh
+++ b/t/t4024-diff-optimize-common.sh
@@ -150,7 +150,7 @@ test_expect_success 'diff -U0' '
 	do
 		git diff -U0 file-?$n
 	done | zc >actual &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
diff --git a/t/t4025-hunk-header.sh b/t/t4025-hunk-header.sh
index 9ba06b7..7a3dbc1 100755
--- a/t/t4025-hunk-header.sh
+++ b/t/t4025-hunk-header.sh
@@ -37,7 +37,7 @@ test_expect_success 'hunk header truncation with an overly long line' '
 		echo " A $N$N$N$N$N$N$N$N$N2"
 		echo " L  $N$N$N$N$N$N$N$N$N1"
 	) >expected &&
-	diff -u actual expected
+	test_cmp actual expected
 
 '
 
diff --git a/t/t4027-diff-submodule.sh b/t/t4027-diff-submodule.sh
index 3d2d081..1fd3fb7 100755
--- a/t/t4027-diff-submodule.sh
+++ b/t/t4027-diff-submodule.sh
@@ -37,17 +37,17 @@ test_expect_success setup '
 
 test_expect_success 'git diff --raw HEAD' '
 	git diff --raw --abbrev=40 HEAD >actual &&
-	diff -u expect actual
+	test_cmp expect actual
 '
 
 test_expect_success 'git diff-index --raw HEAD' '
 	git diff-index --raw HEAD >actual.index &&
-	diff -u expect actual.index
+	test_cmp expect actual.index
 '
 
 test_expect_success 'git diff-files --raw' '
 	git diff-files --raw >actual.files &&
-	diff -u expect actual.files
+	test_cmp expect actual.files
 '
 
 test_done
diff --git a/t/t4105-apply-fuzz.sh b/t/t4105-apply-fuzz.sh
index 0e8d25f..3266e39 100755
--- a/t/t4105-apply-fuzz.sh
+++ b/t/t4105-apply-fuzz.sh
@@ -9,7 +9,7 @@ dotest () {
 	test_expect_success "$name" "
 		git checkout-index -f -q -u file &&
 		git apply $* &&
-		diff -u expect file
+		test_cmp expect file
 	"
 }
 
diff --git a/t/t4125-apply-ws-fuzz.sh b/t/t4125-apply-ws-fuzz.sh
index d6f15be..3b471b6 100755
--- a/t/t4125-apply-ws-fuzz.sh
+++ b/t/t4125-apply-ws-fuzz.sh
@@ -56,7 +56,7 @@ test_expect_success nofix '
 	git apply --whitespace=nowarn patch-1 &&
 
 	# The result should obviously match.
-	diff -u file-1 file
+	test_cmp file-1 file
 '
 
 test_expect_success 'withfix (forward)' '
@@ -70,7 +70,7 @@ test_expect_success 'withfix (forward)' '
 	git apply --whitespace=fix patch-0 &&
 	git apply --whitespace=fix patch-1 &&
 
-	diff -u file-fixed file
+	test_cmp file-fixed file
 '
 
 test_expect_success 'withfix (backward)' '
@@ -91,12 +91,12 @@ test_expect_success 'withfix (backward)' '
 
 	sed -e /h/d file-fixed >fixed-head &&
 	sed -e /h/d file >file-head &&
-	diff -u fixed-head file-head &&
+	test_cmp fixed-head file-head &&
 
 	sed -n -e /h/p file-fixed >fixed-tail &&
 	sed -n -e /h/p file >file-tail &&
 
-	! diff -u fixed-tail file-tail
+	! test_cmp fixed-tail file-tail
 
 '
 
diff --git a/t/t4150-am-subdir.sh b/t/t4150-am-subdir.sh
index 929d2cb..52069b4 100755
--- a/t/t4150-am-subdir.sh
+++ b/t/t4150-am-subdir.sh
@@ -22,14 +22,14 @@ test_expect_success 'am regularly from stdin' '
 	git checkout initial &&
 	git am <patchfile &&
 	git diff master >actual &&
-	diff -u expect actual
+	test_cmp expect actual
 '
 
 test_expect_success 'am regularly from file' '
 	git checkout initial &&
 	git am patchfile &&
 	git diff master >actual &&
-	diff -u expect actual
+	test_cmp expect actual
 '
 
 test_expect_success 'am regularly from stdin in subdirectory' '
@@ -41,7 +41,7 @@ test_expect_success 'am regularly from stdin in subdirectory' '
 		git am <../patchfile
 	) &&
 	git diff master>actual &&
-	diff -u expect actual
+	test_cmp expect actual
 '
 
 test_expect_success 'am regularly from file in subdirectory' '
@@ -53,7 +53,7 @@ test_expect_success 'am regularly from file in subdirectory' '
 		git am ../patchfile
 	) &&
 	git diff master >actual &&
-	diff -u expect actual
+	test_cmp expect actual
 '
 
 test_expect_success 'am regularly from file in subdirectory with full path' '
@@ -66,7 +66,7 @@ test_expect_success 'am regularly from file in subdirectory with full path' '
 		git am "$P/patchfile"
 	) &&
 	git diff master >actual &&
-	diff -u expect actual
+	test_cmp expect actual
 '
 
 test_done
diff --git a/t/t4201-shortlog.sh b/t/t4201-shortlog.sh
index 6d12efb..91ea696 100755
--- a/t/t4201-shortlog.sh
+++ b/t/t4201-shortlog.sh
@@ -45,6 +45,6 @@ A U Thor (5):
 
 EOF
 
-test_expect_success 'shortlog wrapping' 'diff -u expect out'
+test_expect_success 'shortlog wrapping' 'test_cmp expect out'
 
 test_done
diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh
index 2822a65..ecfc999 100755
--- a/t/t5505-remote.sh
+++ b/t/t5505-remote.sh
@@ -24,7 +24,7 @@ setup_repository () {
 tokens_match () {
 	echo "$1" | tr ' ' '\012' | sort | sed -e '/^$/d' >expect &&
 	echo "$2" | tr ' ' '\012' | sort | sed -e '/^$/d' >actual &&
-	diff -u expect actual
+	test_cmp expect actual
 }
 
 check_remote_track () {
@@ -73,7 +73,7 @@ test_expect_success 'add another remote' '
 	sed -e "/^refs\/remotes\/origin\//d" \
 	    -e "/^refs\/remotes\/second\//d" >actual &&
 	>expect &&
-	diff -u expect actual
+	test_cmp expect actual
 )
 '
 
@@ -93,7 +93,7 @@ test_expect_success 'remove remote' '
 	git for-each-ref "--format=%(refname)" refs/remotes |
 	sed -e "/^refs\/remotes\/origin\//d" >actual &&
 	>expect &&
-	diff -u expect actual
+	test_cmp expect actual
 )
 '
 
diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh
index 9b948c1..6946557 100755
--- a/t/t5510-fetch.sh
+++ b/t/t5510-fetch.sh
@@ -249,7 +249,7 @@ test_expect_success 'bundle should record HEAD correctly' '
 	do
 		echo "$(git rev-parse --verify $h) $h"
 	done >expect &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index 6ec5f7c..c0dc949 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -24,28 +24,28 @@ test_expect_success setup '
 test_expect_success 'ls-remote --tags .git' '
 
 	git ls-remote --tags .git >actual &&
-	diff -u expected.tag actual
+	test_cmp expected.tag actual
 
 '
 
 test_expect_success 'ls-remote .git' '
 
 	git ls-remote .git >actual &&
-	diff -u expected.all actual
+	test_cmp expected.all actual
 
 '
 
 test_expect_success 'ls-remote --tags self' '
 
 	git ls-remote --tags self >actual &&
-	diff -u expected.tag actual
+	test_cmp expected.tag actual
 
 '
 
 test_expect_success 'ls-remote self' '
 
 	git ls-remote self >actual &&
-	diff -u expected.all actual
+	test_cmp expected.all actual
 
 '
 
diff --git a/t/t6004-rev-list-path-optim.sh b/t/t6004-rev-list-path-optim.sh
index 80d7198..5dabf1c 100755
--- a/t/t6004-rev-list-path-optim.sh
+++ b/t/t6004-rev-list-path-optim.sh
@@ -45,7 +45,7 @@ test_expect_success 'further setup' '
 test_expect_success 'path optimization 2' '
 	( echo "$side"; echo "$initial" ) >expected &&
 	git rev-list HEAD -- a >actual &&
-	diff -u expected actual
+	test_cmp expected actual
 '
 
 test_done
diff --git a/t/t6009-rev-list-parent.sh b/t/t6009-rev-list-parent.sh
index be3d238..f248a32 100755
--- a/t/t6009-rev-list-parent.sh
+++ b/t/t6009-rev-list-parent.sh
@@ -31,7 +31,7 @@ test_expect_failure 'one is ancestor of others and should not be shown' '
 
 	git rev-list one --not four >result &&
 	>expect &&
-	diff -u expect result
+	test_cmp expect result
 
 '
 
diff --git a/t/t6027-merge-binary.sh b/t/t6027-merge-binary.sh
index a7358f7..92ca1f0 100755
--- a/t/t6027-merge-binary.sh
+++ b/t/t6027-merge-binary.sh
@@ -45,7 +45,7 @@ test_expect_success resolve '
 		false
 	else
 		git ls-files -s >current
-		diff -u current expect
+		test_cmp current expect
 	fi
 '
 
@@ -60,7 +60,7 @@ test_expect_success recursive '
 		false
 	else
 		git ls-files -s >current
-		diff -u current expect
+		test_cmp current expect
 	fi
 '
 
diff --git a/t/t6029-merge-subtree.sh b/t/t6029-merge-subtree.sh
index 35d66e8..43f5459 100755
--- a/t/t6029-merge-subtree.sh
+++ b/t/t6029-merge-subtree.sh
@@ -25,7 +25,7 @@ test_expect_success 'subtree available and works like recursive' '
 
 	git merge -s subtree side &&
 	for i in mundo $s world; do echo $i; done >expect &&
-	diff -u expect hello
+	test_cmp expect hello
 
 '
 
diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh
index bc8ab6a..02cf7c5 100755
--- a/t/t7010-setup.sh
+++ b/t/t7010-setup.sh
@@ -18,7 +18,7 @@ test_expect_success 'git add (absolute)' '
 	git add "$D/a/b/c/d" &&
 	git ls-files >current &&
 	echo a/b/c/d >expect &&
-	diff -u expect current
+	test_cmp expect current
 
 '
 
@@ -32,7 +32,7 @@ test_expect_success 'git add (funny relative)' '
 	) &&
 	git ls-files >current &&
 	echo a/e/f >expect &&
-	diff -u expect current
+	test_cmp expect current
 
 '
 
@@ -43,7 +43,7 @@ test_expect_success 'git rm (absolute)' '
 	git rm -f --cached "$D/a/b/c/d" &&
 	git ls-files >current &&
 	echo a/e/f >expect &&
-	diff -u expect current
+	test_cmp expect current
 
 '
 
@@ -57,7 +57,7 @@ test_expect_success 'git rm (funny relative)' '
 	) &&
 	git ls-files >current &&
 	echo a/b/c/d >expect &&
-	diff -u expect current
+	test_cmp expect current
 
 '
 
@@ -67,7 +67,7 @@ test_expect_success 'git ls-files (absolute)' '
 	git add a &&
 	git ls-files "$D/a/e/../b" >current &&
 	echo a/b/c/d >expect &&
-	diff -u expect current
+	test_cmp expect current
 
 '
 
@@ -80,7 +80,7 @@ test_expect_success 'git ls-files (relative #1)' '
 		git ls-files "../b/c"
 	)  >current &&
 	echo c/d >expect &&
-	diff -u expect current
+	test_cmp expect current
 
 '
 
@@ -93,7 +93,7 @@ test_expect_success 'git ls-files (relative #2)' '
 		git ls-files --full-name "../e/f"
 	)  >current &&
 	echo a/e/f >expect &&
-	diff -u expect current
+	test_cmp expect current
 
 '
 
@@ -126,13 +126,13 @@ test_expect_success 'log using absolute path names' '
 
 	git log a/b/c/d >f1.txt &&
 	git log "$(pwd)/a/b/c/d" >f2.txt &&
-	diff -u f1.txt f2.txt
+	test_cmp f1.txt f2.txt
 '
 
 test_expect_success 'blame using absolute path names' '
 	git blame a/b/c/d >f1.txt &&
 	git blame "$(pwd)/a/b/c/d" >f2.txt &&
-	diff -u f1.txt f2.txt
+	test_cmp f1.txt f2.txt
 '
 
 test_expect_success 'setup deeper work tree' '
diff --git a/t/t7201-co.sh b/t/t7201-co.sh
index 63915cd..3111baa 100755
--- a/t/t7201-co.sh
+++ b/t/t7201-co.sh
@@ -83,13 +83,13 @@ test_expect_success "checkout with unrelated dirty tree without -m" '
 	fill 0 1 2 3 4 5 6 7 8 >same &&
 	cp same kept
 	git checkout side >messages &&
-	diff -u same kept
+	test_cmp same kept
 	(cat > messages.expect <<EOF
 M	same
 EOF
 ) &&
 	touch messages.expect &&
-	diff -u messages.expect messages
+	test_cmp messages.expect messages
 '
 
 test_expect_success "checkout -m with dirty tree" '
@@ -106,19 +106,19 @@ test_expect_success "checkout -m with dirty tree" '
 M	one
 EOF
 ) &&
-	diff -u expect.messages messages &&
+	test_cmp expect.messages messages &&
 
 	fill "M	one" "A	three" "D	two" >expect.master &&
 	git diff --name-status master >current.master &&
-	diff -u expect.master current.master &&
+	test_cmp expect.master current.master &&
 
 	fill "M	one" >expect.side &&
 	git diff --name-status side >current.side &&
-	diff -u expect.side current.side &&
+	test_cmp expect.side current.side &&
 
 	: >expect.index &&
 	git diff --cached >current.index &&
-	diff -u expect.index current.index
+	test_cmp expect.index current.index
 '
 
 test_expect_success "checkout -m with dirty tree, renamed" '
@@ -136,7 +136,7 @@ test_expect_success "checkout -m with dirty tree, renamed" '
 
 	git checkout -m renamer &&
 	fill 1 3 4 5 7 8 >expect &&
-	diff -u expect uno &&
+	test_cmp expect uno &&
 	! test -f one &&
 	git diff --cached >current &&
 	! test -s current
@@ -161,7 +161,7 @@ test_expect_success 'checkout -m with merge conflict' '
 	git diff master:one :3:uno |
 	sed -e "1,/^@@/d" -e "/^ /d" -e "s/^-/d/" -e "s/^+/a/" >current &&
 	fill d2 aT d7 aS >expect &&
-	diff -u current expect &&
+	test_cmp current expect &&
 	git diff --cached two >current &&
 	! test -s current
 '
@@ -178,7 +178,7 @@ If you want to create a new branch from this checkout, you may do so
 HEAD is now at 7329388... Initial A one, A two
 EOF
 ) &&
-	diff -u messages.expect messages &&
+	test_cmp messages.expect messages &&
 	H=$(git rev-parse --verify HEAD) &&
 	M=$(git show-ref -s --verify refs/heads/master) &&
 	test "z$H" = "z$M" &&
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index 361886c..c0288f3 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -203,7 +203,7 @@ test_expect_success 'sign off (1)' '
 		git var GIT_COMMITTER_IDENT |
 		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
 	) >expected &&
-	diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -223,7 +223,7 @@ $existing" &&
 		git var GIT_COMMITTER_IDENT |
 		sed -e "s/>.*/>/" -e "s/^/Signed-off-by: /"
 	) >expected &&
-	diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -240,7 +240,7 @@ test_expect_success 'multiple -m' '
 		echo
 		echo three
 	) >expected &&
-	diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -301,12 +301,12 @@ test_expect_success 'same tree (merge and amend merge)' '
 	git merge -s ours side -m "empty ok" &&
 	git diff HEAD^ HEAD >actual &&
 	: >expected &&
-	diff -u expected actual &&
+	test_cmp expected actual &&
 
 	git commit --amend -m "empty really ok" &&
 	git diff HEAD^ HEAD >actual &&
 	: >expected &&
-	diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -323,7 +323,7 @@ test_expect_success 'amend using the message from another commit' '
 	git commit --allow-empty --amend -C "$old" &&
 	git show --pretty="format:%ad %s" "$old" >expected &&
 	git show --pretty="format:%ad %s" HEAD >actual &&
-	diff -u expected actual
+	test_cmp expected actual
 
 '
 
@@ -341,7 +341,7 @@ test_expect_success 'amend using the message from a commit named with tag' '
 	git commit --allow-empty --amend -C tagged-old &&
 	git show --pretty="format:%ad %s" "$old" >expected &&
 	git show --pretty="format:%ad %s" HEAD >actual &&
-	diff -u expected actual
+	test_cmp expected actual
 
 '
 
diff --git a/t/t7502-commit.sh b/t/t7502-commit.sh
index b780fdd..284c941 100755
--- a/t/t7502-commit.sh
+++ b/t/t7502-commit.sh
@@ -85,7 +85,7 @@ test_expect_success 'verbose' '
 	git add negative &&
 	git status -v | sed -ne "/^diff --git /p" >actual &&
 	echo "diff --git a/negative b/negative" >expect &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
@@ -95,7 +95,7 @@ test_expect_success 'cleanup commit messages (verbatim,-t)' '
 	{ echo;echo "# text";echo; } >expect &&
 	git commit --cleanup=verbatim -t expect -a &&
 	git cat-file -p HEAD |sed -e "1,/^\$/d" |head -n 3 >actual &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
@@ -104,7 +104,7 @@ test_expect_success 'cleanup commit messages (verbatim,-F)' '
 	echo >>negative &&
 	git commit --cleanup=verbatim -F expect -a &&
 	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
@@ -113,7 +113,7 @@ test_expect_success 'cleanup commit messages (verbatim,-m)' '
 	echo >>negative &&
 	git commit --cleanup=verbatim -m "$(cat expect)" -a &&
 	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
@@ -124,7 +124,7 @@ test_expect_success 'cleanup commit messages (whitespace,-F)' '
 	echo "# text" >expect &&
 	git commit --cleanup=whitespace -F text -a &&
 	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
@@ -135,7 +135,7 @@ test_expect_success 'cleanup commit messages (strip,-F)' '
 	echo sample >expect &&
 	git commit --cleanup=strip -F text -a &&
 	git cat-file -p HEAD |sed -e "1,/^\$/d">actual &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
@@ -150,7 +150,7 @@ test_expect_success 'cleanup commit messages (strip,-F,-e)' '
 	{ echo;echo sample;echo; } >text &&
 	git commit -e -F text -a &&
 	head -n 4 .git/COMMIT_EDITMSG >actual &&
-	diff -u expect actual
+	test_cmp expect actual
 
 '
 
diff --git a/t/t7502-status.sh b/t/t7502-status.sh
index 70b802b..cd08516 100755
--- a/t/t7502-status.sh
+++ b/t/t7502-status.sh
@@ -146,7 +146,7 @@ cat <<EOF >expect
 EOF
 test_expect_success 'status of partial commit excluding new file in index' '
 	git status dir1/modified >output &&
-	diff -u expect output
+	test_cmp expect output
 '
 
 test_done
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 219411f..56869ac 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -108,7 +108,7 @@ create_merge_msgs() {
 }
 
 verify_diff() {
-	if ! diff -u "$1" "$2"
+	if ! test_cmp "$1" "$2"
 	then
 		echo "$3"
 		false
diff --git a/t/t8003-blame.sh b/t/t8003-blame.sh
index db51b3a..966bb0a 100755
--- a/t/t8003-blame.sh
+++ b/t/t8003-blame.sh
@@ -112,7 +112,7 @@ test_expect_success 'blame wholesale copy' '
 		echo mouse-Second
 		echo mouse-Third
 	} >expected &&
-	diff -u expected current
+	test_cmp expected current
 
 '
 
@@ -125,7 +125,7 @@ test_expect_success 'blame wholesale copy and more' '
 		echo cow-Fifth
 		echo mouse-Third
 	} >expected &&
-	diff -u expected current
+	test_cmp expected current
 
 '
 
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index cbbfa9c..c0973b4 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -81,7 +81,7 @@ test_expect_success 'Show all headers' '
 		-e "s/^\(Message-Id:\).*/\1 MESSAGE-ID-STRING/" \
 		-e "s/^\(X-Mailer:\).*/\1 X-MAILER-STRING/" \
 		>actual-show-all-headers &&
-	diff -u expected-show-all-headers actual-show-all-headers
+	test_cmp expected-show-all-headers actual-show-all-headers
 '
 
 z8=zzzzzzzz
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index 902ed41..e1e8bdf 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -55,74 +55,74 @@ printf 'r1 \nr2 \nr4 \n' > expected-range-r1-r2-r4
 
 test_expect_success 'test ascending revision range' "
 	git reset --hard trunk &&
-	git svn log -r 1:4 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r1-r2-r4 -
+	git svn log -r 1:4 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r1-r2-r4 -
 	"
 
 printf 'r4 \nr2 \nr1 \n' > expected-range-r4-r2-r1
 
 test_expect_success 'test descending revision range' "
 	git reset --hard trunk &&
-	git svn log -r 4:1 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4-r2-r1 -
+	git svn log -r 4:1 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r4-r2-r1 -
 	"
 
 printf 'r1 \nr2 \n' > expected-range-r1-r2
 
 test_expect_success 'test ascending revision range with unreachable revision' "
 	git reset --hard trunk &&
-	git svn log -r 1:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r1-r2 -
+	git svn log -r 1:3 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r1-r2 -
 	"
 
 printf 'r2 \nr1 \n' > expected-range-r2-r1
 
 test_expect_success 'test descending revision range with unreachable revision' "
 	git reset --hard trunk &&
-	git svn log -r 3:1 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2-r1 -
+	git svn log -r 3:1 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r2-r1 -
 	"
 
 printf 'r2 \n' > expected-range-r2
 
 test_expect_success 'test ascending revision range with unreachable upper boundary revision and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 2:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2 -
+	git svn log -r 2:3 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r2 -
 	"
 
 test_expect_success 'test descending revision range with unreachable upper boundary revision and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 3:2 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r2 -
+	git svn log -r 3:2 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r2 -
 	"
 
 printf 'r4 \n' > expected-range-r4
 
 test_expect_success 'test ascending revision range with unreachable lower boundary revision and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 3:4 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+	git svn log -r 3:4 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r4 -
 	"
 
 test_expect_success 'test descending revision range with unreachable lower boundary revision and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 4:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+	git svn log -r 4:3 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r4 -
 	"
 
 printf -- '------------------------------------------------------------------------\n' > expected-separator
 
 test_expect_success 'test ascending revision range with unreachable boundary revisions and no commits' "
 	git reset --hard trunk &&
-	git svn log -r 5:6 | diff -u expected-separator -
+	git svn log -r 5:6 | test_cmp expected-separator -
 	"
 
 test_expect_success 'test descending revision range with unreachable boundary revisions and no commits' "
 	git reset --hard trunk &&
-	git svn log -r 6:5 | diff -u expected-separator -
+	git svn log -r 6:5 | test_cmp expected-separator -
 	"
 
 test_expect_success 'test ascending revision range with unreachable boundary revisions and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 3:5 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+	git svn log -r 3:5 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r4 -
 	"
 
 test_expect_success 'test descending revision range with unreachable boundary revisions and 1 commit' "
 	git reset --hard trunk &&
-	git svn log -r 5:3 | grep '^r[0-9]' | cut -d'|' -f1 | diff -u expected-range-r4 -
+	git svn log -r 5:3 | grep '^r[0-9]' | cut -d'|' -f1 | test_cmp expected-range-r4 -
 	"
 
 test_done
diff --git a/t/t9200-git-cvsexportcommit.sh b/t/t9200-git-cvsexportcommit.sh
index 58c59ed..42b144b 100755
--- a/t/t9200-git-cvsexportcommit.sh
+++ b/t/t9200-git-cvsexportcommit.sh
@@ -37,7 +37,7 @@ check_entries () {
 	else
 		printf '%s\n' "$2" | tr '|' '\012' >expected
 	fi
-	diff -u expected actual
+	test_cmp expected actual
 }
 
 test_expect_success \
@@ -257,8 +257,8 @@ test_expect_success '-w option should work with relative GIT_DIR' '
       (cd "$GIT_DIR" &&
       GIT_DIR=. git cvsexportcommit -w "$CVSWORK" -c $id &&
       check_entries "$CVSWORK/W" "file1.txt/1.1/|file2.txt/1.1/" &&
-      diff -u "$CVSWORK/W/file1.txt" ../W/file1.txt &&
-      diff -u "$CVSWORK/W/file2.txt" ../W/file2.txt
+      test_cmp "$CVSWORK/W/file1.txt" ../W/file1.txt &&
+      test_cmp "$CVSWORK/W/file2.txt" ../W/file2.txt
       )
 '
 
@@ -279,9 +279,9 @@ test_expect_success 'check files before directories' '
 	git cvsexportcommit -w "$CVSWORK" -c $id &&
 	check_entries "$CVSWORK/E" "DS/1.1/|newfile5.txt/1.1/" &&
 	check_entries "$CVSWORK" "DS/1.1/|release-notes/1.2/" &&
-	diff -u "$CVSWORK/DS" DS &&
-	diff -u "$CVSWORK/E/DS" E/DS &&
-	diff -u "$CVSWORK/release-notes" release-notes
+	test_cmp "$CVSWORK/DS" DS &&
+	test_cmp "$CVSWORK/E/DS" E/DS &&
+	test_cmp "$CVSWORK/release-notes" release-notes
 
 '
 
@@ -293,7 +293,7 @@ test_expect_success 'commit a file with leading spaces in the name' '
 	id=$(git rev-parse HEAD) &&
 	git cvsexportcommit -w "$CVSWORK" -c $id &&
 	check_entries "$CVSWORK" " space/1.1/|DS/1.1/|release-notes/1.2/" &&
-	diff -u "$CVSWORK/ space" " space"
+	test_cmp "$CVSWORK/ space" " space"
 
 '
 
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 6aea0ea..268b26c 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -42,6 +42,7 @@ export GIT_MERGE_VERBOSITY
 export GIT_AUTHOR_EMAIL GIT_AUTHOR_NAME
 export GIT_COMMITTER_EMAIL GIT_COMMITTER_NAME
 export EDITOR VISUAL
+GIT_TEST_CMP=${GIT_TEST_CMP:-diff -u}
 
 # Protect ourselves from common misconfiguration to export
 # CDPATH into the environment
@@ -302,6 +303,23 @@ test_must_fail () {
 	test $? -gt 0 -a $? -le 128
 }
 
+# test_cmp is a helper function to compare actual and expected output.
+# You can use it like:
+#
+#	test_expect_success 'foo works' '
+#		echo expected >expected &&
+#		foo >actual &&
+#		test_cmp expected actual
+#	'
+#
+# This could be written as either "cmp" or "diff -u", but:
+# - cmp's output is not nearly as easy to read as diff -u
+# - not all diff versions understand "-u"
+
+test_cmp() {
+	$GIT_TEST_CMP "$@"
+}
+
 # Most tests can use the created repository, but some may need to create more.
 # Usage: test_create_repo <directory>
 test_create_repo () {
-- 
1.5.4.4.543.g30fdd.dirty

^ permalink raw reply related	[relevance 1%]

* Re: git-submodule getting submodules from the parent repository
  @ 2008-04-01 23:10  3%     ` Sam Vilain
  0 siblings, 0 replies; 200+ results
From: Sam Vilain @ 2008-04-01 23:10 UTC (permalink / raw)
  To: Avery Pennarun; +Cc: git

Avery Pennarun wrote:
>>  Well, that would create a lot of unnecessary work when cloning.
>>  Partitioning by project is a natural way to divide the projects up.
> 
> What unnecessary work do you mean?

A full clone takes a few shortcuts, especially over dumb transports like
HTTP.  I think there might be shortcuts in the git-daemon code as well.
 Forcing these to be partial might make these full fetches involve more
time.

>>  However, what you are suggesting should IMHO be allowed to work.  In
>>  particular, if the submodule path is ".", then I think there's a good
>>  case that they should come from within the same project.  If it's a
>>  relative URL, it should initialize based on the remote URL that was used
>>  for the original fetch (or, rather, the remote URL for the current branch).
> I agree, there's no reason to take away the existing functionality of
> allowing split repos.  I was more suggesting a new functionality so
> that splitting isn't *required*.

Yes - I look forward to a patch.

>>  This push failure thing is regrettable; however it's not clear which
>>  branch name the submodules should get.  A given commit might exist on
>>  several branches, which one do you choose to name it?
> One option is to make a simple "git push origin" operation fail if
> you're not on any branch; iirc, if you try that now, it just silently
> *succeeds* without uploading anything at all, which is one reason I so
> frequently screw it up.

Sounds workable.

> Alternatively, is there a reason I can't
> upload an object *without* giving it a branch name?  I guess that
> would cause problems with garbage collection.

You've answered your own question there.

>>  There is also a Google Summer of Code project for this - see
>>  http://git.or.cz/gitwiki/SoC2008Ideas#head-9215572f23513542a23d3555aa72775bc4b91038
> 
> ok.  I was hoping it wouldn't be so hard as to require an entire SoC
> project, since using --alternate when checking out the child repo
> shouldn't be too hard.

If you think it is simpler, then I'm sure that submodules users would
appreciate you sharing your ideas as a patch.  Sorry if I am starting to
sound like a parrot ;-).

Sam.

^ permalink raw reply	[relevance 3%]

* Re: Achieving efficient storage of weirdly structured repos
  @ 2008-04-03 21:11  3% ` Linus Torvalds
  2008-04-04 23:30  1%   ` Roman Shaposhnik
  0 siblings, 1 reply; 200+ results
From: Linus Torvalds @ 2008-04-03 21:11 UTC (permalink / raw)
  To: Roman Shaposhnik; +Cc: git



On Thu, 3 Apr 2008, Roman Shaposhnik wrote:
> 
> The repository was created using hg2git (the one based on git-fast-import)
> and it was GC'ed and REPACK'ed just in case.

Before going any further - exactly _how_ was it repacked?

In particular, when using importers that do partial packing on their own 
(and any "git-fastimport" user is that by definition - and I think 
hg2git does that), at the end of it all you have to make sure to repack in 
a way where the repacking will totally discard the import-time packfiles.

IOW, that's one of the very few times you should use "-f" to git repack.

It's usually also a good place to make sure that since you ignore the old 
packing information, it's best to also make sure that the new packing info 
is good by using a bigger window (and perhaps a bigger depth). That makes 
the packing much slower, of course, but this is meant to be a one-time 
event.

So try something like

	git repack -a -d -f --depth=100 --window=100

if you have a good CPU and plenty of memory.

> The last item (trees) also seem to take the most space and the most 
> reasonable explanation that I can offer is that NetBeans repository has 
> a really weird structure where they have approximately 700 (yes, seven 
> hundred!) top-level subdirectories there. They are clearly 
> Submodules-shy, but that's another issue that I will need to address 
> with them.

Trees taking the biggest amount of space is not unheard of, and it may 
also be that the name heuristics (for finding good packing partners) could 
be failign, which would result in a much bigger pack than necessary. 

So if you already did an aggressive repack like the above, I'd happily 
take a look at whether maybe it's bad heuristics for finding tree objects 
to pair up for delta-compression. Do you have a place where you can put 
that repo for people to clone and look at? 

			Linus

^ permalink raw reply	[relevance 3%]

* Re: Achieving efficient storage of weirdly structured repos
  2008-04-03 21:11  3% ` Linus Torvalds
@ 2008-04-04 23:30  1%   ` Roman Shaposhnik
  0 siblings, 0 replies; 200+ results
From: Roman Shaposhnik @ 2008-04-04 23:30 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

Hi Linus!

On Thu, 2008-04-03 at 14:11 -0700, Linus Torvalds wrote:
> 
> On Thu, 3 Apr 2008, Roman Shaposhnik wrote:
> > 
> > The repository was created using hg2git (the one based on git-fast-import)
> > and it was GC'ed and REPACK'ed just in case.
> 
> Before going any further - exactly _how_ was it repacked?

I believe it was the following two steps:
   $ git gc --aggressive
   $ git repack

> In particular, when using importers that do partial packing on their own 
> (and any "git-fastimport" user is that by definition - and I think 
> hg2git does that), at the end of it all you have to make sure to repack in 
> a way where the repacking will totally discard the import-time packfiles.

Good point. Speaking of which: do you have an FAQ for importers? The
entries in the official FAQ (http://git.or.cz/gitwiki/GitFaq#head-929a8825d04dde226c2530f5337d3b3ed8dcc7ce)
seem a bit stale for such an important issue. After all, importing from
an existing SCM is what usually forms a first time impression of Git's
effectiveness.

> IOW, that's one of the very few times you should use "-f" to git repack.

Got it!

> It's usually also a good place to make sure that since you ignore the old 
> packing information, it's best to also make sure that the new packing info 
> is good by using a bigger window (and perhaps a bigger depth). That makes 
> the packing much slower, of course, but this is meant to be a one-time 
> event.
> 
> So try something like
> 
> 	git repack -a -d -f --depth=100 --window=100
> 
> if you have a good CPU and plenty of memory.

That turned out to be a perfect suggestion. Thank you. I'm now the
happiest camper ever. And I'm also also pretty dumbfounded ;-)

Here's what happened. 

I started with a a repository filled with "loose" (one object per file)
objects (the reason I needed it was for the ease of sleuthing through
individual objects and it was created by git-unpack-objects from that
initial 1.1Gb pack). And I tried to pack it exactly like you
suggested:
   $ git-pack-objects --depth=100 --window=100 --delta-base-offset --progress pack < objects
   Generating pack...
   Counting objects: 1096305
   Done counting 1159628 objects.
   Deltifying 1159628 objects...
      100% (1159628/1159628) done
   Writing 1159628 objects...
   dd134c407324dc55b0cd2aa3a9e1b3420c2bba3f

   Total 1159628 (delta 386980), reused 0 (delta 0)

and it payed off reasonably well:
    $ du -s NB-clone
    670M NB-clone

It still was bigger than the Mercurial repository but at least it got
2 times smaller than the original result of hg2git. Now, if it wasn't
for a friend of mine, I probably would've stopped there. But he
showed up and saved the day ;-) His comments made me try something
that I didn't consider to be of any use -- repacking a freshly packed
pack with the *same* --depth=100 --window=100:
    $ git repack -a  -f --window=100 --depth=100 
    Generating pack...
    Counting objects: 1056829
    Done counting 1159628 objects.
    Deltifying 1159628 objects...
       100% (1159628/1159628) done
    Writing 1159628 objects...
       100% (1159628/1159628) done
    Total 1159628 (delta 614516), reused 0 (delta 0)
    Pack pack-dd134c407324dc55b0cd2aa3a9e1b3420c2bba3f created.
And then, a miracle occurred:
     $ du -sh NB-small 
     268M NB-small

Now, don't get me wrong: I'm as happy as a clam. The repository is now
*smaller* than the Mercurial's and because the structure of the
tree is so weird Git gets major points here. The only question that
is still bothering me is: how did it happen? Why did repacking 
a repository with exactly the same set of objects and the only
difference being where these objects resided (former case filesystem,
the later case an intermediate pack) made so huge a difference?

Please help!

> > The last item (trees) also seem to take the most space and the most 
> > reasonable explanation that I can offer is that NetBeans repository has 
> > a really weird structure where they have approximately 700 (yes, seven 
> > hundred!) top-level subdirectories there. They are clearly 
> > Submodules-shy, but that's another issue that I will need to address 
> > with them.
> 
> Trees taking the biggest amount of space is not unheard of, and it may 
> also be that the name heuristics (for finding good packing partners) could 
> be failign, which would result in a much bigger pack than necessary. 

Is there any documentation that describes the heuristics involved in
creating a pack?

> So if you already did an aggressive repack like the above, I'd happily 
> take a look at whether maybe it's bad heuristics for finding tree objects 
> to pair up for delta-compression. Do you have a place where you can put 
> that repo for people to clone and look at?

Unfortunately I don't. The only thing I can do is I can always create
a *.tar.bz2 and put and on  Sun's ftp server. Actually, that makes me
wonder: is there any public Git hosting available such that publishing
a hefty repository for the forensic purposes only wouldn't violate their
terms of use?

Thanks,
Roman.

P.S. Oh, and here's one extra tiny question that I also have: what
does the output:
   Total 1159628 (delta 614516), reused 0 (delta 0)
really mean?

^ permalink raw reply	[relevance 1%]

* [PATCH 8/8] Fix tests breaking when checkout path contains shell metacharacters
  @ 2008-04-09  1:30 10%               ` Bryan Donlan
  0 siblings, 0 replies; 200+ results
From: Bryan Donlan @ 2008-04-09  1:30 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Adam Roben, gitster, Bryan Donlan

This fixes the remainder of the issues where the test script itself is at
fault for failing when the git checkout path contains whitespace or other
shell metacharacters.

Signed-off-by: Bryan Donlan <bdonlan@fushizen.net>
---
 t/t0000-basic.sh                              |    4 +-
 t/t0001-init.sh                               |    2 +-
 t/t1020-subdirectory.sh                       |   24 +++++-----
 t/t1501-worktree.sh                           |   14 +++---
 t/t3050-subprojects-fetch.sh                  |    2 +-
 t/t3404-rebase-interactive.sh                 |    3 +-
 t/t5500-fetch-pack.sh                         |    2 +-
 t/t5512-ls-remote.sh                          |    2 +-
 t/t5516-fetch-push.sh                         |    8 ++--
 t/t5700-clone-reference.sh                    |    4 +-
 t/t5710-info-alternate.sh                     |    4 +-
 t/t7003-filter-branch.sh                      |    4 +-
 t/t7010-setup.sh                              |    2 +-
 t/t7300-clean.sh                              |    2 +-
 t/t7501-commit.sh                             |    8 ++--
 t/t7504-commit-msg-hook.sh                    |   20 +++++-----
 t/t7505-prepare-commit-msg-hook.sh            |   14 +++---
 t/t9100-git-svn-basic.sh                      |   54 ++++++++++++------------
 t/t9101-git-svn-props.sh                      |    6 +-
 t/t9102-git-svn-deep-rmdir.sh                 |    6 +-
 t/t9103-git-svn-tracked-directory-removed.sh  |   30 +++++++-------
 t/t9104-git-svn-follow-parent.sh              |   50 +++++++++++-----------
 t/t9105-git-svn-commit-diff.sh                |   12 +++---
 t/t9106-git-svn-commit-diff-clobber.sh        |   14 +++---
 t/t9106-git-svn-dcommit-clobber-series.sh     |    6 +-
 t/t9107-git-svn-migrate.sh                    |   48 +++++++++++-----------
 t/t9108-git-svn-glob.sh                       |    8 ++--
 t/t9110-git-svn-use-svm-props.sh              |    8 ++--
 t/t9111-git-svn-use-svnsync-props.sh          |    8 ++--
 t/t9112-git-svn-md5less-file.sh               |    4 +-
 t/t9113-git-svn-dcommit-new-file.sh           |    6 +-
 t/t9114-git-svn-dcommit-merge.sh              |    4 +-
 t/t9115-git-svn-dcommit-funky-renames.sh      |    4 +-
 t/t9116-git-svn-log.sh                        |    4 +-
 t/t9117-git-svn-init-clone.sh                 |   10 ++--
 t/t9118-git-svn-funky-branch-names.sh         |   12 +++---
 t/t9120-git-svn-clone-with-percent-escapes.sh |    2 +-
 t/t9500-gitweb-standalone-no-errors.sh        |   13 +++---
 38 files changed, 214 insertions(+), 214 deletions(-)

diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 27b54cb..690f80a 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -305,10 +305,10 @@ test_expect_success 'absolute path works as expected' '
 	file="$dir"/index &&
 	test "$file" = "$(test-absolute-path $dir2/index)" &&
 	basename=blub &&
-	test "$dir/$basename" = $(cd .git && test-absolute-path $basename) &&
+	test "$dir/$basename" = "$(cd .git && test-absolute-path "$basename")" &&
 	ln -s ../first/file .git/syml &&
 	sym="$(cd first; pwd -P)"/file &&
-	test "$sym" = "$(test-absolute-path $dir2/syml)"
+	test "$sym" = "$(test-absolute-path "$dir2/syml")"
 '
 
 test_expect_success 'very long name in the index handled sanely' '
diff --git a/t/t0001-init.sh b/t/t0001-init.sh
index b0289e3..22eb735 100755
--- a/t/t0001-init.sh
+++ b/t/t0001-init.sh
@@ -95,7 +95,7 @@ test_expect_success 'GIT_DIR & GIT_WORK_TREE (1)' '
 	(
 		unset GIT_CONFIG
 		mkdir git-dir-wt-1.git &&
-		GIT_WORK_TREE=$(pwd) GIT_DIR=git-dir-wt-1.git git init
+		GIT_WORK_TREE="$(pwd)" GIT_DIR=git-dir-wt-1.git git init
 	) &&
 	check_config git-dir-wt-1.git false "$(pwd)"
 '
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index b9cef34..20a1e82 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -16,12 +16,12 @@ test_expect_success setup '
 	cp one original.one &&
 	cp dir/two original.two
 '
-HERE=`pwd`
+HERE="$(pwd)"
 LF='
 '
 
 test_expect_success 'update-index and ls-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git update-index --add one &&
 	case "`git ls-files`" in
 	one) echo ok one ;;
@@ -41,7 +41,7 @@ test_expect_success 'update-index and ls-files' '
 '
 
 test_expect_success 'cat-file' '
-	cd $HERE &&
+	cd "$HERE" &&
 	two=`git ls-files -s dir/two` &&
 	two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
 	echo "$two" &&
@@ -54,7 +54,7 @@ test_expect_success 'cat-file' '
 rm -f actual dir/actual
 
 test_expect_success 'diff-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	echo a >>one &&
 	echo d >>dir/two &&
 	case "`git diff-files --name-only`" in
@@ -74,7 +74,7 @@ test_expect_success 'diff-files' '
 '
 
 test_expect_success 'write-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	top=`git write-tree` &&
 	echo $top &&
 	cd dir &&
@@ -84,7 +84,7 @@ test_expect_success 'write-tree' '
 '
 
 test_expect_success 'checkout-index' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git checkout-index -f -u one &&
 	cmp one original.one &&
 	cd dir &&
@@ -93,7 +93,7 @@ test_expect_success 'checkout-index' '
 '
 
 test_expect_success 'read-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -f one dir/two &&
 	tree=`git write-tree` &&
 	git read-tree --reset -u "$tree" &&
@@ -107,27 +107,27 @@ test_expect_success 'read-tree' '
 '
 
 test_expect_success 'no file/rev ambiguity check inside .git' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git commit -a -m 1 &&
-	cd $HERE/.git &&
+	cd "$HERE"/.git &&
 	git show -s HEAD
 '
 
 test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && GIT_DIR=. git show -s HEAD
 '
 
 # This still does not work as it should...
 : test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && git show -s HEAD
 '
 
 test_expect_success 'detection should not be fooled by a symlink' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -fr foo.git &&
 	git clone -s .git another &&
 	ln -s another yetanother &&
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index 7ee3820..ffb77b6 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -48,8 +48,8 @@ test_rev_parse 'subdirectory' false false true sub/dir/
 cd ../../.. || exit 1
 
 say "core.worktree = absolute path"
-export GIT_DIR=$(pwd)/repo.git
-export GIT_CONFIG=$GIT_DIR/config
+export GIT_DIR="$(pwd)/repo.git"
+export GIT_CONFIG="$GIT_DIR/config"
 git config core.worktree "$(pwd)/work"
 test_rev_parse 'outside'      false false false
 cd work || exit 1
@@ -59,8 +59,8 @@ test_rev_parse 'subdirectory' false false true sub/dir/
 cd ../../.. || exit 1
 
 say "GIT_WORK_TREE=relative path (override core.worktree)"
-export GIT_DIR=$(pwd)/repo.git
-export GIT_CONFIG=$GIT_DIR/config
+export GIT_DIR="$(pwd)/repo.git"
+export GIT_CONFIG="$GIT_DIR/config"
 git config core.worktree non-existent
 export GIT_WORK_TREE=work
 test_rev_parse 'outside'      false false false
@@ -75,9 +75,9 @@ cd ../../.. || exit 1
 mv work repo.git/work
 
 say "GIT_WORK_TREE=absolute path, work tree below git dir"
-export GIT_DIR=$(pwd)/repo.git
-export GIT_CONFIG=$GIT_DIR/config
-export GIT_WORK_TREE=$(pwd)/repo.git/work
+export GIT_DIR="$(pwd)/repo.git"
+export GIT_CONFIG="$GIT_DIR/config"
+export GIT_WORK_TREE="$(pwd)/repo.git/work"
 test_rev_parse 'outside'              false false false
 cd repo.git || exit 1
 test_rev_parse 'in repo.git'              false true  false
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 2b21b10..4261e96 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -20,7 +20,7 @@ test_expect_success setup '
 '
 
 test_expect_success clone '
-	git clone file://`pwd`/.git cloned &&
+	git clone "file://$(pwd)/.git" cloned &&
 	(git rev-parse HEAD; git ls-files -s) >expected &&
 	(
 		cd cloned &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 9cf873f..b9e3dbd 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -91,9 +91,8 @@ for line in $FAKE_LINES; do
 done
 EOF
 
+test_set_editor "$(pwd)/fake-editor.sh"
 chmod a+x fake-editor.sh
-VISUAL="$(pwd)/fake-editor.sh"
-export VISUAL
 
 test_expect_success 'no changes are a nop' '
 	git rebase -i F &&
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 788b4a5..c52707b 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -129,7 +129,7 @@ pull_to_client 2nd "B" $((64*3))
 
 pull_to_client 3rd "A" $((1*3)) # old fails
 
-test_expect_success "clone shallow" "git-clone --depth 2 file://`pwd`/. shallow"
+test_expect_success "clone shallow" 'git-clone --depth 2 "file://$(pwd)/." shallow'
 
 (cd shallow; git count-objects -v) > count.shallow
 
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index c0dc949..1dd8eed 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -17,7 +17,7 @@ test_expect_success setup '
 		git show-ref -d	| sed -e "s/ /	/"
 	) >expected.all &&
 
-	git remote add self $(pwd)/.git
+	git remote add self "$(pwd)/.git"
 
 '
 
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 793ffc6..6e8cb9e 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -103,9 +103,9 @@ test_expect_success 'fetch with wildcard' '
 test_expect_success 'fetch with insteadOf' '
 	mk_empty &&
 	(
-		TRASH=$(pwd) &&
+		TRASH="$(pwd)" &&
 		cd testrepo &&
-		git config url./$TRASH/.insteadOf trash/
+		git config "url./$TRASH/.insteadOf" trash/ &&
 		git config remote.up.url trash/. &&
 		git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" &&
 		git fetch up &&
@@ -145,8 +145,8 @@ test_expect_success 'push with wildcard' '
 
 test_expect_success 'push with insteadOf' '
 	mk_empty &&
-	TRASH=$(pwd) &&
-	git config url./$TRASH/.insteadOf trash/ &&
+	TRASH="$(pwd)" &&
+	git config "url./$TRASH/.insteadOf" trash/ &&
 	git push trash/testrepo refs/heads/master:refs/remotes/origin/master &&
 	(
 		cd testrepo &&
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index b6a5486..82ef023 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -6,7 +6,7 @@
 test_description='test clone --reference'
 . ./test-lib.sh
 
-base_dir=`pwd`
+base_dir="$(pwd)"
 
 test_expect_success 'preparing first repository' \
 'test_create_repo A && cd A &&
@@ -51,7 +51,7 @@ diff expected current'
 cd "$base_dir"
 
 test_expect_success 'cloning with reference (no -l -s)' \
-'git clone --reference B file://`pwd`/A D'
+'git clone --reference B "file://$(pwd)/A" D'
 
 cd "$base_dir"
 
diff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh
index 910ccb4..8f26999 100755
--- a/t/t5710-info-alternate.sh
+++ b/t/t5710-info-alternate.sh
@@ -21,7 +21,7 @@ test_valid_repo() {
 	test `wc -l < fsck.log` = 0
 }
 
-base_dir=`pwd`
+base_dir="$(pwd)"
 
 test_expect_success 'preparing first repository' \
 'test_create_repo A && cd A &&
@@ -81,7 +81,7 @@ test_valid_repo'
 cd "$base_dir"
 
 test_expect_success 'breaking of loops' \
-"echo '$base_dir/B/.git/objects' >> '$base_dir'/A/.git/objects/info/alternates&&
+"echo \"\$base_dir\"/B/.git/objects >> \"\$base_dir\"/A/.git/objects/info/alternates&&
 cd C &&
 test_valid_repo"
 
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index efd658a..abe3d83 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -123,9 +123,9 @@ test_expect_success 'use index-filter to move into a subdirectory' '
 	git branch directorymoved &&
 	git-filter-branch -f --index-filter \
 		 "git ls-files -s | sed \"s-\\t-&newsubdir/-\" |
-	          GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
+	          GIT_INDEX_FILE=\"\$GIT_INDEX_FILE.new\" \
 			git update-index --index-info &&
-		  mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
+		  mv \"\$GIT_INDEX_FILE.new\" \"\$GIT_INDEX_FILE\"" directorymoved &&
 	test -z "$(git diff HEAD directorymoved:newsubdir)"'
 
 test_expect_success 'stops when msg filter fails' '
diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh
index 02cf7c5..d8a7c79 100755
--- a/t/t7010-setup.sh
+++ b/t/t7010-setup.sh
@@ -122,7 +122,7 @@ test_expect_success 'commit using absolute path names' '
 
 test_expect_success 'log using absolute path names' '
 	echo bb >>a/b/c/d &&
-	git commit -m "bb" $(pwd)/a/b/c/d &&
+	git commit -m "bb" "$(pwd)/a/b/c/d" &&
 
 	git log a/b/c/d >f1.txt &&
 	git log "$(pwd)/a/b/c/d" >f2.txt &&
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index afccfc9..54b1352 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -111,7 +111,7 @@ test_expect_success 'git-clean with absolute path' '
 	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
 	would_clean=$(
 		cd docs &&
-		git clean -n $(pwd)/../src |
+		git clean -n "$(pwd)/../src" |
 		sed -n -e "s|^Would remove ||p"
 	) &&
 	test "$would_clean" = ../src/part3.c || {
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index c0288f3..e5fdb63 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -79,8 +79,8 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -e "s/a file/an amend commit/g" < $1 > $1-
-mv $1- $1
+sed -e "s/a file/an amend commit/g" < "$1" > "$1-"
+mv "$1-" "$1"
 EOF
 chmod 755 editor
 
@@ -99,8 +99,8 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -e "s/amend/older/g"  < $1 > $1-
-mv $1- $1
+sed -e "s/amend/older/g"  < "$1" > "$1-"
+mv "$1-" "$1"
 EOF
 chmod 755 editor
 
diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh
index eff36aa..24f6b2e 100755
--- a/t/t7504-commit-msg-hook.sh
+++ b/t/t7504-commit-msg-hook.sh
@@ -27,7 +27,7 @@ test_expect_success 'with no hook (editor)' '
 	echo "more foo" >> file &&
 	git add file &&
 	echo "more foo" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit
 
 '
 
@@ -44,7 +44,7 @@ test_expect_success '--no-verify with no hook (editor)' '
 	echo "more bar" > file &&
 	git add file &&
 	echo "more bar" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -71,7 +71,7 @@ test_expect_success 'with succeeding hook (editor)' '
 	echo "more more" >> file &&
 	git add file &&
 	echo "more more" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit
 
 '
 
@@ -88,7 +88,7 @@ test_expect_success '--no-verify with succeeding hook (editor)' '
 	echo "even more more" >> file &&
 	git add file &&
 	echo "even more more" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -111,7 +111,7 @@ test_expect_success 'with failing hook (editor)' '
 	echo "more another" >> file &&
 	git add file &&
 	echo "more another" > FAKE_MSG &&
-	! (GIT_EDITOR="$FAKE_EDITOR" git commit)
+	! (GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit)
 
 '
 
@@ -128,7 +128,7 @@ test_expect_success '--no-verify with failing hook (editor)' '
 	echo "more stuff" >> file &&
 	git add file &&
 	echo "more stuff" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -146,7 +146,7 @@ test_expect_success 'with non-executable hook (editor)' '
 	echo "content again" >> file &&
 	git add file &&
 	echo "content again" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -m "content again"
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -m "content again"
 
 '
 
@@ -163,7 +163,7 @@ test_expect_success '--no-verify with non-executable hook (editor)' '
 	echo "even more content" >> file &&
 	git add file &&
 	echo "even more content" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -193,7 +193,7 @@ test_expect_success 'hook edits commit message (editor)' '
 	echo "additional content" >> file &&
 	git add file &&
 	echo "additional content" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit &&
 	commit_msg_is "new message"
 
 '
@@ -212,7 +212,7 @@ test_expect_success "hook doesn't edit commit message (editor)" '
 	echo "more plus" >> file &&
 	git add file &&
 	echo "more plus" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify &&
 	commit_msg_is "more plus"
 
 '
diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh
index 802aa62..bc2bad9 100755
--- a/t/t7505-prepare-commit-msg-hook.sh
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -58,7 +58,7 @@ test_expect_success 'with hook (-m editor)' '
 
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -e -m "more more" &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -m "more more" &&
 	test "`git log -1 --pretty=format:%s`" = message
 
 '
@@ -85,7 +85,7 @@ test_expect_success 'with hook (-F editor)' '
 
 	echo "more" >> file &&
 	git add file &&
-	(echo more more | GIT_EDITOR="$FAKE_EDITOR" git commit -e -F -) &&
+	(echo more more | GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -F -) &&
 	test "`git log -1 --pretty=format:%s`" = message
 
 '
@@ -104,7 +104,7 @@ test_expect_success 'with hook (editor)' '
 
 	echo "more more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit &&
 	test "`git log -1 --pretty=format:%s`" = default
 
 '
@@ -114,7 +114,7 @@ test_expect_success 'with hook (--amend)' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --amend &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --amend &&
 	test "`git log -1 --pretty=format:%s`" = "$head"
 
 '
@@ -124,7 +124,7 @@ test_expect_success 'with hook (-c)' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -c $head &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head &&
 	test "`git log -1 --pretty=format:%s`" = "$head"
 
 '
@@ -139,7 +139,7 @@ test_expect_success 'with failing hook' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	! GIT_EDITOR="$FAKE_EDITOR" git commit -c $head
+	! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head
 
 '
 
@@ -148,7 +148,7 @@ test_expect_success 'with failing hook (--no-verify)' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	! GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify -c $head
+	! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify -c $head
 
 '
 
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 4e24ab3..528c0a9 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -31,16 +31,16 @@ test_expect_success \
 	echo 'zzz' > bar/zzz &&
 	echo '#!/bin/sh' > exec.sh &&
 	chmod +x exec.sh &&
-	svn import -m 'import for git-svn' . $svnrepo >/dev/null &&
+	svn import -m 'import for git-svn' . \"\$svnrepo\" >/dev/null &&
 	cd .. &&
 	rm -rf import &&
-	git-svn init $svnrepo"
+	git-svn init \"\$svnrepo\""
 
 test_expect_success \
     'import an SVN revision into git' \
     'git-svn fetch'
 
-test_expect_success "checkout from svn" "svn co $svnrepo '$SVN_TREE'"
+test_expect_success "checkout from svn" "svn co \"\$svnrepo\" \"\$SVN_TREE\""
 
 name='try a deep --rmdir with a commit'
 test_expect_success "$name" "
@@ -51,8 +51,8 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch &&
-	svn up '$SVN_TREE' &&
-	test -d '$SVN_TREE'/dir && test ! -d '$SVN_TREE'/dir/a"
+	svn up \"\$SVN_TREE\" &&
+	test -d \"\$SVN_TREE\"/dir && test ! -d \"\$SVN_TREE\"/dir/a"
 
 
 name='detect node change from file to directory #1'
@@ -69,7 +69,7 @@ test_expect_success "$name" "
 
 name='detect node change from directory to file #1'
 test_expect_success "$name" "
-	rm -rf dir '$GIT_DIR'/index &&
+	rm -rf dir \"\$GIT_DIR\"/index &&
 	git checkout -f -b mybranch2 remotes/git-svn &&
 	mv bar/zzz zzz &&
 	rm -rf bar &&
@@ -83,7 +83,7 @@ test_expect_success "$name" "
 
 name='detect node change from file to directory #2'
 test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+	rm -f \"\$GIT_DIR\"/index &&
 	git checkout -f -b mybranch3 remotes/git-svn &&
 	rm bar/zzz &&
 	git update-index --remove bar/zzz &&
@@ -97,7 +97,7 @@ test_expect_success "$name" "
 
 name='detect node change from directory to file #2'
 test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+	rm -f \"\$GIT_DIR\"/index &&
 	git checkout -f -b mybranch4 remotes/git-svn &&
 	rm -rf dir &&
 	git update-index --remove -- dir/file &&
@@ -111,15 +111,15 @@ test_expect_success "$name" "
 
 name='remove executable bit from a file'
 test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+	rm -f \"\$GIT_DIR\"/index &&
 	git checkout -f -b mybranch5 remotes/git-svn &&
 	chmod -x exec.sh &&
 	git update-index exec.sh &&
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test ! -x '$SVN_TREE'/exec.sh"
+	svn up \"\$SVN_TREE\" &&
+	test ! -x \"\$SVN_TREE\"/exec.sh"
 
 
 name='add executable bit back file'
@@ -129,8 +129,8 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -x '$SVN_TREE'/exec.sh"
+	svn up \"\$SVN_TREE\" &&
+	test -x \"\$SVN_TREE\"/exec.sh"
 
 
 name='executable file becomes a symlink to bar/zzz (file)'
@@ -141,8 +141,8 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -L '$SVN_TREE'/exec.sh"
+	svn up \"\$SVN_TREE\" &&
+	test -L \"\$SVN_TREE\"/exec.sh"
 
 name='new symlink is added to a file that was also just made executable'
 
@@ -153,9 +153,9 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -x '$SVN_TREE'/bar/zzz &&
-	test -L '$SVN_TREE'/exec-2.sh"
+	svn up \"\$SVN_TREE\" &&
+	test -x \"\$SVN_TREE\"/bar/zzz &&
+	test -L \"\$SVN_TREE\"/exec-2.sh"
 
 name='modify a symlink to become a file'
 test_expect_success "$name" "
@@ -166,10 +166,10 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -f '$SVN_TREE'/exec-2.sh &&
-	test ! -L '$SVN_TREE'/exec-2.sh &&
-	git diff help $SVN_TREE/exec-2.sh"
+	svn up \"\$SVN_TREE\" &&
+	test -f \"\$SVN_TREE\"/exec-2.sh &&
+	test ! -L \"\$SVN_TREE\"/exec-2.sh &&
+	git diff help \"\$SVN_TREE\"/exec-2.sh"
 
 if test "$have_utf8" = t
 then
@@ -190,7 +190,7 @@ name='test fetch functionality (svn => git) with alternate GIT_SVN_ID'
 GIT_SVN_ID=alt
 export GIT_SVN_ID
 test_expect_success "$name" \
-    "git-svn init $svnrepo && git-svn fetch &&
+    "git-svn init \"\$svnrepo\" && git-svn fetch &&
      git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a &&
      git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
      git diff a b"
@@ -220,16 +220,16 @@ test_expect_success 'exit if remote refs are ambigious' "
 "
 
 test_expect_success 'exit if init-ing a would clobber a URL' "
-        svnadmin create ${PWD}/svnrepo2 &&
-        svn mkdir -m 'mkdir bar' ${svnrepo}2/bar &&
+        svnadmin create \"\${PWD}/svnrepo2\" &&
+        svn mkdir -m 'mkdir bar' \"\${svnrepo}2/bar\" &&
         git config --unset svn-remote.svn.fetch \
                                 '^bar:refs/remotes/git-svn$' &&
-	! git-svn init ${svnrepo}2/bar
+	! git-svn init \"\${svnrepo}2/bar\"
         "
 
 test_expect_success \
   'init allows us to connect to another directory in the same repo' "
-        git-svn init --minimize-url -i bar $svnrepo/bar &&
+        git-svn init --minimize-url -i bar \"\$svnrepo/bar\" &&
         git config --get svn-remote.svn.fetch \
                               '^bar:refs/remotes/bar$' &&
         git config --get svn-remote.svn.fetch \
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index d7a7047..fa8b7ee 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -52,7 +52,7 @@ EOF
 cd ..
 
 rm -rf import
-test_expect_success 'checkout working copy from svn' "svn co $svnrepo test_wc"
+test_expect_success 'checkout working copy from svn' "svn co \"\$svnrepo\" test_wc"
 test_expect_success 'setup some commits to svn' \
 	'cd test_wc &&
 		echo Greetings >> kw.c &&
@@ -66,7 +66,7 @@ test_expect_success 'setup some commits to svn' \
 		svn commit -m "Propset Id" &&
 	cd ..'
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init \"\$svnrepo\""
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 
 name='test svn:keywords ignoring'
@@ -92,7 +92,7 @@ test_expect_success "propset CR on crlf files" \
 test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
 	"git-svn fetch &&
 	 git pull . remotes/git-svn &&
-	 svn co $svnrepo new_wc"
+	 svn co \"\$svnrepo\" new_wc"
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh
index 4e08083..8eaf7d3 100755
--- a/t/t9102-git-svn-deep-rmdir.sh
+++ b/t/t9102-git-svn-deep-rmdir.sh
@@ -9,12 +9,12 @@ test_expect_success 'initialize repo' "
 	mkdir -p deeply/nested/directory/number/2 &&
 	echo foo > deeply/nested/directory/number/1/file &&
 	echo foo > deeply/nested/directory/number/2/another &&
-	svn import -m 'import for git-svn' . $svnrepo &&
+	svn import -m 'import for git-svn' . \"\$svnrepo\" &&
 	cd ..
 	"
 
 test_expect_success 'mirror via git-svn' "
-	git-svn init $svnrepo &&
+	git-svn init \"\$svnrepo\" &&
 	git-svn fetch &&
 	git checkout -f -b test-rmdir remotes/git-svn
 	"
@@ -23,7 +23,7 @@ test_expect_success 'Try a commit on rmdir' "
 	git rm -f deeply/nested/directory/number/2/another &&
 	git commit -a -m 'remove another' &&
 	git-svn set-tree --rmdir HEAD &&
-	svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1
+	svn ls -R \"\$svnrepo\" | grep ^deeply/nested/directory/number/1
 	"
 
 
diff --git a/t/t9103-git-svn-tracked-directory-removed.sh b/t/t9103-git-svn-tracked-directory-removed.sh
index 0f0b0fd..c7734e6 100755
--- a/t/t9103-git-svn-tracked-directory-removed.sh
+++ b/t/t9103-git-svn-tracked-directory-removed.sh
@@ -6,34 +6,34 @@
 test_description='git-svn tracking removed top-level path'
 . ./lib-git-svn.sh
 
-test_expect_success 'make history for tracking' '
+test_expect_success 'make history for tracking' "
 	mkdir import &&
 	mkdir import/trunk &&
 	echo hello >> import/trunk/README &&
-	svn import -m initial import $svnrepo &&
+	svn import -m initial import \"\$svnrepo\" &&
 	rm -rf import &&
-	svn co $svnrepo/trunk trunk &&
+	svn co \"\$svnrepo\"/trunk trunk &&
 	echo bye bye >> trunk/README &&
-	svn rm -m "gone" $svnrepo/trunk &&
+	svn rm -m 'gone' \"\$svnrepo\"/trunk &&
 	rm -rf trunk &&
 	mkdir trunk &&
-	echo "new" > trunk/FOLLOWME &&
-	svn import -m "new trunk" trunk $svnrepo/trunk
-'
+	echo 'new' > trunk/FOLLOWME &&
+	svn import -m 'new trunk' trunk \"\$svnrepo\"/trunk
+"
 
-test_expect_success 'clone repo with git' '
-	git svn clone -s $svnrepo x &&
+test_expect_success 'clone repo with git' "
+	git svn clone -s \"\$svnrepo\" x &&
 	test -f x/FOLLOWME &&
 	test ! -f x/README
-'
+"
 
-test_expect_success 'make sure r2 still has old file' '
+test_expect_success 'make sure r2 still has old file' "
 	cd x &&
-		test -n "$(git svn find-rev r1)" &&
-		git reset --hard $(git svn find-rev r1) &&
+		test -n \"\$(git svn find-rev r1)\" &&
+		git reset --hard \$(git svn find-rev r1) &&
 		test -f README &&
 		test ! -f FOLLOWME &&
-		test x$(git svn find-rev r2) = x
-'
+		test x\$(git svn find-rev r2) = x
+"
 
 test_done
diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 7ba7630..56b1704 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -11,9 +11,9 @@ test_expect_success 'initialize repo' "
 	cd import &&
 	mkdir -p trunk &&
 	echo hello > trunk/readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . \"\$svnrepo\" &&
 	cd .. &&
-	svn co $svnrepo wc &&
+	svn co \"\$svnrepo\" wc &&
 	cd wc &&
 	echo world >> trunk/readme &&
 	poke trunk/readme &&
@@ -27,7 +27,7 @@ test_expect_success 'initialize repo' "
 	"
 
 test_expect_success 'init and fetch a moved directory' "
-	git-svn init --minimize-url -i thunk $svnrepo/thunk &&
+	git-svn init --minimize-url -i thunk \"\$svnrepo\"/thunk &&
 	git-svn fetch -i thunk &&
 	test \"\`git rev-parse --verify refs/remotes/thunk@2\`\" \
            = \"\`git rev-parse --verify refs/remotes/thunk~1\`\" &&
@@ -38,7 +38,7 @@ test_expect_success 'init and fetch a moved directory' "
 	"
 
 test_expect_success 'init and fetch from one svn-remote' "
-        git config svn-remote.svn.url $svnrepo &&
+        git config svn-remote.svn.url \"\$svnrepo\" &&
         git config --add svn-remote.svn.fetch \
           trunk:refs/remotes/svn/trunk &&
         git config --add svn-remote.svn.fetch \
@@ -52,9 +52,9 @@ test_expect_success 'init and fetch from one svn-remote' "
 
 test_expect_success 'follow deleted parent' "
         (svn cp -m 'resurrecting trunk as junk' \
-               $svnrepo/trunk@2 $svnrepo/junk ||
+               \"\$svnrepo\"/trunk@2 \"\$svnrepo\"/junk ||
          svn cp -m 'resurrecting trunk as junk' \
-               -r2 $svnrepo/trunk $svnrepo/junk) &&
+               -r2 \"\$svnrepo\"/trunk \"\$svnrepo\"/junk) &&
         git config --add svn-remote.svn.fetch \
           junk:refs/remotes/svn/junk &&
         git-svn fetch -i svn/thunk &&
@@ -67,10 +67,10 @@ test_expect_success 'follow deleted parent' "
 test_expect_success 'follow larger parent' "
         mkdir -p import/trunk/thunk/bump/thud &&
         echo hi > import/trunk/thunk/bump/thud/file &&
-        svn import -m 'import a larger parent' import $svnrepo/larger-parent &&
-        svn cp -m 'hi' $svnrepo/larger-parent $svnrepo/another-larger &&
+        svn import -m 'import a larger parent' import \"\$svnrepo\"/larger-parent &&
+        svn cp -m 'hi' \"\$svnrepo\"/larger-parent \"\$svnrepo\"/another-larger &&
         git-svn init --minimize-url -i larger \
-          $svnrepo/another-larger/trunk/thunk/bump/thud &&
+          \"\$svnrepo\"/another-larger/trunk/thunk/bump/thud &&
         git-svn fetch -i larger &&
         git rev-parse --verify refs/remotes/larger &&
         git rev-parse --verify \
@@ -83,23 +83,23 @@ test_expect_success 'follow larger parent' "
         "
 
 test_expect_success 'follow higher-level parent' "
-        svn mkdir -m 'follow higher-level parent' $svnrepo/blob &&
-        svn co $svnrepo/blob blob &&
+        svn mkdir -m 'follow higher-level parent' \"\$svnrepo\"/blob &&
+        svn co \"\$svnrepo\"/blob blob &&
         cd blob &&
                 echo hi > hi &&
                 svn add hi &&
                 svn commit -m 'hihi' &&
                 cd ..
-        svn mkdir -m 'new glob at top level' $svnrepo/glob &&
-        svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
-        git-svn init --minimize-url -i blob $svnrepo/glob/blob &&
+        svn mkdir -m 'new glob at top level' \"\$svnrepo\"/glob &&
+        svn mv -m 'move blob down a level' \"\$svnrepo\"/blob \"\$svnrepo\"/glob/blob &&
+        git-svn init --minimize-url -i blob \"\$svnrepo\"/glob/blob &&
         git-svn fetch -i blob
         "
 
 test_expect_success 'follow deleted directory' "
-	svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye &&
-	svn rm -m 'remove glob' $svnrepo/glob &&
-	git-svn init --minimize-url -i glob $svnrepo/glob &&
+	svn mv -m 'bye!' \"\$svnrepo\"/glob/blob/hi \"\$svnrepo\"/glob/blob/bye &&
+	svn rm -m 'remove glob' \"\$svnrepo\"/glob &&
+	git-svn init --minimize-url -i glob \"\$svnrepo\"/glob &&
 	git-svn fetch -i glob &&
 	test \"\`git cat-file blob refs/remotes/glob:blob/bye\`\" = hi &&
 	test \"\`git ls-tree refs/remotes/glob | wc -l \`\" -eq 1
@@ -118,9 +118,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  echo 'bad delete test 2' > \
 	   import/trunk/subversion/bindings/swig/perl/another-larger &&
 	cd import &&
-	  svn import -m 'r9270 test' . $svnrepo/r9270 &&
+	  svn import -m 'r9270 test' . \"\$svnrepo\"/r9270 &&
 	cd .. &&
-	svn co $svnrepo/r9270/trunk/subversion/bindings/swig/perl r9270 &&
+	svn co \"\$svnrepo\"/r9270/trunk/subversion/bindings/swig/perl r9270 &&
 	cd r9270 &&
 	  svn mkdir native &&
 	  svn mv t native/t &&
@@ -130,7 +130,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  svn commit -m 'reorg test' &&
 	cd .. &&
 	git-svn init --minimize-url -i r9270-t \
-	  $svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t &&
+	  \"\$svnrepo\"/r9270/trunk/subversion/bindings/swig/perl/native/t &&
 	git-svn fetch -i r9270-t &&
 	test \`git rev-list r9270-t | wc -l\` -eq 2 &&
 	test \"\`git ls-tree --name-only r9270-t~1\`\" = \
@@ -138,9 +138,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	"
 
 test_expect_success "track initial change if it was only made to parent" "
-	svn cp -m 'wheee!' $svnrepo/r9270/trunk $svnrepo/r9270/drunk &&
+	svn cp -m 'wheee!' \"\$svnrepo\"/r9270/trunk \"\$svnrepo\"/r9270/drunk &&
 	git-svn init --minimize-url -i r9270-d \
-	  $svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t &&
+	  \"\$svnrepo\"/r9270/drunk/subversion/bindings/swig/perl/native/t &&
 	git-svn fetch -i r9270-d &&
 	test \`git rev-list r9270-d | wc -l\` -eq 3 &&
 	test \"\`git ls-tree --name-only r9270-t\`\" = \
@@ -150,7 +150,7 @@ test_expect_success "track initial change if it was only made to parent" "
 	"
 
 test_expect_success "track multi-parent paths" "
-	svn cp -m 'resurrect /glob' $svnrepo/r9270 $svnrepo/glob &&
+	svn cp -m 'resurrect /glob' \"\$svnrepo\"/r9270 \"\$svnrepo\"/glob &&
 	git-svn multi-fetch &&
 	test \`git cat-file commit refs/remotes/glob | \
 	       grep '^parent ' | wc -l\` -eq 2
@@ -161,8 +161,8 @@ test_expect_success "multi-fetch continues to work" "
 	"
 
 test_expect_success "multi-fetch works off a 'clean' repository" "
-	rm -r $GIT_DIR/svn $GIT_DIR/refs/remotes $GIT_DIR/logs &&
-	mkdir $GIT_DIR/svn &&
+	rm -r \"\$GIT_DIR/svn\" \"\$GIT_DIR/refs/remotes\" \"\$GIT_DIR/logs\" &&
+	mkdir \"\$GIT_DIR/svn\" &&
 	git-svn multi-fetch
 	"
 
diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh
index 318e172..4f7f9cc 100755
--- a/t/t9105-git-svn-commit-diff.sh
+++ b/t/t9105-git-svn-commit-diff.sh
@@ -8,7 +8,7 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo hello > readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . \"\$svnrepo\" &&
 	cd .. &&
 	echo hello > readme &&
 	git update-index --add readme &&
@@ -26,17 +26,17 @@ prev=`git rev-parse --verify HEAD^1`
 
 test_expect_success 'test the commit-diff command' "
 	test -n '$prev' && test -n '$head' &&
-	git-svn commit-diff -r1 '$prev' '$head' '$svnrepo' &&
-	svn co $svnrepo wc &&
+	git-svn commit-diff -r1 '$prev' '$head' \"\$svnrepo\" &&
+	svn co \"\$svnrepo\" wc &&
 	cmp readme wc/readme
 	"
 
 test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
-	svn import -m 'sub-directory' import $svnrepo/subdir &&
-	git-svn init --minimize-url $svnrepo/subdir &&
+	svn import -m 'sub-directory' import \"\$svnrepo\"/subdir &&
+	git-svn init --minimize-url \"\$svnrepo\"/subdir &&
 	git-svn fetch &&
 	git-svn commit-diff -r3 '$prev' '$head' &&
-	svn cat $svnrepo/subdir/readme > readme.2 &&
+	svn cat \"\$svnrepo\"/subdir/readme > readme.2 &&
 	cmp readme readme.2
 	"
 
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index f74ab12..bb544f6 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -8,14 +8,14 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo initial > file &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . \"\$svnrepo\" &&
 	cd .. &&
 	echo initial > file &&
 	git update-index --add file &&
 	git commit -a -m 'initial'
 	"
 test_expect_success 'commit change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co \"\$svnrepo\" t.svn &&
 	cd t.svn &&
 	echo second line from svn >> file &&
 	poke file &&
@@ -27,7 +27,7 @@ test_expect_success 'commit change from svn side' "
 test_expect_success 'commit conflicting change from git' "
 	echo second line from git >> file &&
 	git commit -a -m 'second line from git' &&
-	! git-svn commit-diff -r1 HEAD~1 HEAD $svnrepo
+	! git-svn commit-diff -r1 HEAD~1 HEAD \"\$svnrepo\"
 "
 
 test_expect_success 'commit complementing change from git' "
@@ -36,14 +36,14 @@ test_expect_success 'commit complementing change from git' "
 	git commit -a -m 'second line from svn' &&
 	echo third line from git >> file &&
 	git commit -a -m 'third line from git' &&
-	git-svn commit-diff -r2 HEAD~1 HEAD $svnrepo
+	git-svn commit-diff -r2 HEAD~1 HEAD \"\$svnrepo\"
 	"
 
 test_expect_success 'dcommit fails to commit because of conflict' "
-	git-svn init $svnrepo &&
+	git-svn init \"\$svnrepo\" &&
 	git-svn fetch &&
 	git reset --hard refs/remotes/git-svn &&
-	svn co $svnrepo t.svn &&
+	svn co \"\$svnrepo\" t.svn &&
 	cd t.svn &&
 	echo fourth line from svn >> file &&
 	poke file &&
@@ -67,7 +67,7 @@ test_expect_success 'dcommit does the svn equivalent of an index merge' "
 	"
 
 test_expect_success 'commit another change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co \"\$svnrepo\" t.svn &&
 	cd t.svn &&
 		echo third line from svn >> file &&
 		poke file &&
diff --git a/t/t9106-git-svn-dcommit-clobber-series.sh b/t/t9106-git-svn-dcommit-clobber-series.sh
index ca8a00e..477755a 100755
--- a/t/t9106-git-svn-dcommit-clobber-series.sh
+++ b/t/t9106-git-svn-dcommit-clobber-series.sh
@@ -8,9 +8,9 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	awk 'BEGIN { for (i = 1; i < 64; i++) { print i } }' > file
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . \"\$svnrepo\" &&
 	cd .. &&
-	git svn init $svnrepo &&
+	git svn init \"\$svnrepo\" &&
 	git svn fetch &&
 	test -e file
 	"
@@ -18,7 +18,7 @@ test_expect_success 'initialize repo' "
 test_expect_success '(supposedly) non-conflicting change from SVN' "
 	test x\"\`sed -n -e 58p < file\`\" = x58 &&
 	test x\"\`sed -n -e 61p < file\`\" = x61 &&
-	svn co $svnrepo tmp &&
+	svn co \"\$svnrepo\" tmp &&
 	cd tmp &&
 		perl -i -p -e 's/^58\$/5588/' file &&
 		perl -i -p -e 's/^61\$/6611/' file &&
diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index 0a41d52..9ab7074 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -4,7 +4,7 @@ test_description='git-svn metadata migrations from previous versions'
 . ./lib-git-svn.sh
 
 test_expect_success 'setup old-looking metadata' "
-	cp $GIT_DIR/config $GIT_DIR/config-old-git-svn &&
+	cp \"\$GIT_DIR\"/config \"\$GIT_DIR\"/config-old-git-svn &&
 	mkdir import &&
 	cd import &&
 		for i in trunk branches/a branches/b \
@@ -12,13 +12,13 @@ test_expect_success 'setup old-looking metadata' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . \"\$svnrepo\"
 		cd .. &&
-	git-svn init $svnrepo &&
+	git-svn init \"\$svnrepo\" &&
 	git-svn fetch &&
-	mv $GIT_DIR/svn/* $GIT_DIR/ &&
-	mv $GIT_DIR/svn/.metadata $GIT_DIR/ &&
-	rmdir $GIT_DIR/svn &&
+	mv \"\$GIT_DIR\"/svn/* \"\$GIT_DIR\"/ &&
+	mv \"\$GIT_DIR\"/svn/.metadata \"\$GIT_DIR\"/ &&
+	rmdir \"\$GIT_DIR\"/svn &&
 	git update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn &&
 	git update-ref refs/heads/svn-HEAD refs/remotes/git-svn &&
 	git update-ref -d refs/remotes/git-svn refs/remotes/git-svn
@@ -28,20 +28,20 @@ head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
 test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
 
 test_expect_success 'initialize old-style (v0) git-svn layout' "
-	mkdir -p $GIT_DIR/git-svn/info $GIT_DIR/svn/info &&
-	echo $svnrepo > $GIT_DIR/git-svn/info/url &&
-	echo $svnrepo > $GIT_DIR/svn/info/url &&
+	mkdir -p \"\$GIT_DIR\"/git-svn/info \"\$GIT_DIR\"/svn/info &&
+	echo \"\$svnrepo\" > \"\$GIT_DIR\"/git-svn/info/url &&
+	echo \"\$svnrepo\" > \"\$GIT_DIR\"/svn/info/url &&
 	git-svn migrate &&
-	! test -d $GIT_DIR/git-svn &&
+	! test -d \"\$GIT_DIR\"/git-svn &&
 	git rev-parse --verify refs/remotes/git-svn^0 &&
 	git rev-parse --verify refs/remotes/svn^0 &&
-	test \`git config --get svn-remote.svn.url\` = '$svnrepo' &&
+	test \"\$(git config --get svn-remote.svn.url)\" = \"\$svnrepo\" &&
 	test \`git config --get svn-remote.svn.fetch\` = \
              ':refs/remotes/git-svn'
 	"
 
 test_expect_success 'initialize a multi-repository repo' "
-	git-svn init $svnrepo -T trunk -t tags -b branches &&
+	git-svn init \"\$svnrepo\" -T trunk -t tags -b branches &&
 	git config --get-all svn-remote.svn.fetch > fetch.out &&
 	grep '^trunk:refs/remotes/trunk$' fetch.out &&
 	test -n \"\`git config --get svn-remote.svn.branches \
@@ -76,14 +76,14 @@ test_expect_success 'multi-fetch works on partial urls + paths' "
 test_expect_success 'migrate --minimize on old inited layout' "
 	git config --unset-all svn-remote.svn.fetch &&
 	git config --unset-all svn-remote.svn.url &&
-	rm -rf $GIT_DIR/svn &&
+	rm -rf \"\$GIT_DIR\"/svn &&
 	for i in \`cat fetch.out\`; do
 		path=\`expr \$i : '\\([^:]*\\):.*$'\`
 		ref=\`expr \$i : '[^:]*:refs/remotes/\\(.*\\)$'\`
 		if test -z \"\$ref\"; then continue; fi
 		if test -n \"\$path\"; then path=\"/\$path\"; fi
-		( mkdir -p $GIT_DIR/svn/\$ref/info/ &&
-		echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
+		( mkdir -p \"\$GIT_DIR\"/svn/\$ref/info/ &&
+		echo \"\$svnrepo\"\$path > \"\$GIT_DIR\"/svn/\$ref/info/url ) || exit 1;
 	done &&
 	git-svn migrate --minimize &&
 	test -z \"\`git config -l |grep -v '^svn-remote\.git-svn\.'\`\" &&
@@ -99,17 +99,17 @@ test_expect_success 'migrate --minimize on old inited layout' "
 
 test_expect_success  ".rev_db auto-converted to .rev_map.UUID" "
 	git-svn fetch -i trunk &&
-	test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
-	expect=\"\$(ls $GIT_DIR/svn/trunk/.rev_map.*)\" &&
+	test -z \"\$(ls \"\$GIT_DIR\"/svn/trunk/.rev_db.* 2>/dev/null)\" &&
+	expect=\"\$(ls \"\$GIT_DIR\"/svn/trunk/.rev_map.*)\" &&
 	test -n \"\$expect\" &&
-	rev_db=\$(echo \$expect | sed -e 's,_map,_db,') &&
-	convert_to_rev_db \$expect \$rev_db &&
-	rm -f \$expect &&
-	test -f \$rev_db &&
+	rev_db=\"\$(echo \$expect | sed -e 's,_map,_db,')\" &&
+	convert_to_rev_db \"\$expect\" \"\$rev_db\" &&
+	rm -f \"\$expect\" &&
+	test -f \"\$rev_db\" &&
 	git-svn fetch -i trunk &&
-	test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
-	test ! -e $GIT_DIR/svn/trunk/.rev_db &&
-	test -f \$expect
+	test -z \"\$(ls \"\$GIT_DIR\"/svn/trunk/.rev_db.* 2>/dev/null)\" &&
+	test ! -e \"\$GIT_DIR\"/svn/trunk/.rev_db &&
+	test -f \"\$expect\"
 	"
 
 test_done
diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh
index db4344c..8f03f2d 100755
--- a/t/t9108-git-svn-glob.sh
+++ b/t/t9108-git-svn-glob.sh
@@ -14,8 +14,8 @@ test_expect_success 'test refspec globbing' "
 	mkdir -p trunk/src/a trunk/src/b trunk/doc &&
 	echo 'hello world' > trunk/src/a/readme &&
 	echo 'goodbye world' > trunk/src/b/readme &&
-	svn import -m 'initial' trunk $svnrepo/trunk &&
-	svn co $svnrepo tmp &&
+	svn import -m 'initial' trunk \"\$svnrepo\"/trunk &&
+	svn co \"\$svnrepo\" tmp &&
 	cd tmp &&
 		mkdir branches tags &&
 		svn add branches tags &&
@@ -38,7 +38,7 @@ test_expect_success 'test refspec globbing' "
 		poke tags/end/src/b/readme &&
 		svn commit -m 'nothing to see here'
 		cd .. &&
-	git config --add svn-remote.svn.url $svnrepo &&
+	git config --add svn-remote.svn.url \"\$svnrepo\" &&
 	git config --add svn-remote.svn.fetch \
 	                 'trunk/src/a:refs/remotes/trunk' &&
 	git config --add svn-remote.svn.branches \
@@ -60,7 +60,7 @@ echo nothing to see here >> expect.two
 cat expect.end >> expect.two
 
 test_expect_success 'test left-hand-side only globbing' "
-	git config --add svn-remote.two.url $svnrepo &&
+	git config --add svn-remote.two.url \"\$svnrepo\" &&
 	git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
 	git config --add svn-remote.two.branches \
 	                 'branches/*:refs/remotes/two/branches/*' &&
diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh
index 6235af4..d9ac558 100755
--- a/t/t9110-git-svn-use-svm-props.sh
+++ b/t/t9110-git-svn-use-svm-props.sh
@@ -8,11 +8,11 @@ test_description='git-svn useSvmProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svm repo' "
-	svnadmin load -q $rawsvnrepo < ../t9110/svm.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/mirror/arr &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/mirror/argh &&
+	svnadmin load -q \"\$rawsvnrepo\" < ../t9110/svm.dump &&
+	git-svn init --minimize-url -R arr -i bar \"\$svnrepo\"/mirror/arr &&
+	git-svn init --minimize-url -R argh -i dir \"\$svnrepo\"/mirror/argh &&
 	git-svn init --minimize-url -R argh -i e \
-	  $svnrepo/mirror/argh/a/b/c/d/e &&
+	  \"\$svnrepo\"/mirror/argh/a/b/c/d/e &&
 	git config svn.useSvmProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9111-git-svn-use-svnsync-props.sh b/t/t9111-git-svn-use-svnsync-props.sh
index ec7dedd..77185bc 100755
--- a/t/t9111-git-svn-use-svnsync-props.sh
+++ b/t/t9111-git-svn-use-svnsync-props.sh
@@ -8,10 +8,10 @@ test_description='git-svn useSvnsyncProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svnsync repo' "
-	svnadmin load -q $rawsvnrepo < ../t9111/svnsync.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/bar &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/dir &&
-	git-svn init --minimize-url -R argh -i e $svnrepo/dir/a/b/c/d/e &&
+	svnadmin load -q \"\$rawsvnrepo\" < ../t9111/svnsync.dump &&
+	git-svn init --minimize-url -R arr -i bar \"\$svnrepo\"/bar &&
+	git-svn init --minimize-url -R argh -i dir \"\$svnrepo\"/dir &&
+	git-svn init --minimize-url -R argh -i e \"\$svnrepo\"/dir/a/b/c/d/e &&
 	git config svn.useSvnsyncProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh
index 646a5f0..fb1491d 100755
--- a/t/t9112-git-svn-md5less-file.sh
+++ b/t/t9112-git-svn-md5less-file.sh
@@ -40,8 +40,8 @@ PROPS-END
 
 EOF
 
-test_expect_success 'load svn dumpfile' "svnadmin load $rawsvnrepo < dumpfile.svn"
+test_expect_success 'load svn dumpfile' "svnadmin load \"\$rawsvnrepo\" < dumpfile.svn"
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init \"\$svnrepo\""
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 test_done
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
index 9ef0db9..b92a64e 100755
--- a/t/t9113-git-svn-dcommit-new-file.sh
+++ b/t/t9113-git-svn-dcommit-new-file.sh
@@ -15,14 +15,14 @@ test_description='git-svn dcommit new files over svn:// test'
 
 start_svnserve () {
 	svnserve --listen-port $SVNSERVE_PORT \
-	         --root $rawsvnrepo \
+	         --root "$rawsvnrepo" \
 	         --listen-once \
 	         --listen-host 127.0.0.1 &
 }
 
 test_expect_success 'start tracking an empty repo' "
-	svn mkdir -m 'empty dir' $svnrepo/empty-dir &&
-	echo anon-access = write >> $rawsvnrepo/conf/svnserve.conf &&
+	svn mkdir -m 'empty dir' \"\$svnrepo\"/empty-dir &&
+	echo anon-access = write >> \"\$rawsvnrepo\"/conf/svnserve.conf &&
 	start_svnserve &&
 	git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
 	git svn fetch
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
index 225060b..74b971c 100755
--- a/t/t9114-git-svn-dcommit-merge.sh
+++ b/t/t9114-git-svn-dcommit-merge.sh
@@ -35,7 +35,7 @@ EOF
 }
 
 test_expect_success 'setup svn repository' "
-	svn co $svnrepo mysvnwork &&
+	svn co \"\$svnrepo\" mysvnwork &&
 	mkdir -p mysvnwork/trunk &&
 	cd mysvnwork &&
 		big_text_block >> trunk/README &&
@@ -45,7 +45,7 @@ test_expect_success 'setup svn repository' "
 	"
 
 test_expect_success 'setup git mirror and merge' "
-	git svn init $svnrepo -t tags -T trunk -b branches &&
+	git svn init \"\$svnrepo\" -t tags -T trunk -b branches &&
 	git svn fetch &&
 	git checkout --track -b svn remotes/trunk &&
 	git checkout -b merge &&
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 182299c..f83f4f9 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -8,12 +8,12 @@ test_description='git-svn dcommit can commit renames of files with ugly names'
 . ./lib-git-svn.sh
 
 test_expect_success 'load repository with strange names' "
-	svnadmin load -q $rawsvnrepo < ../t9115/funky-names.dump &&
+	svnadmin load -q \"\$rawsvnrepo\" < ../t9115/funky-names.dump &&
 	start_httpd
 	"
 
 test_expect_success 'init and fetch repository' "
-	git svn init $svnrepo &&
+	git svn init \"\$svnrepo\" &&
 	git svn fetch &&
 	git reset --hard git-svn
 	"
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index e1e8bdf..13081b8 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -14,9 +14,9 @@ test_expect_success 'setup repository and import' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . \"\$svnrepo\"
 		cd .. &&
-	git-svn init $svnrepo -T trunk -b branches -t tags &&
+	git-svn init \"\$svnrepo\" -T trunk -b branches -t tags &&
 	git-svn fetch &&
 	git reset --hard trunk &&
 	echo bye >> README &&
diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh
index d482b40..c924915 100755
--- a/t/t9117-git-svn-init-clone.sh
+++ b/t/t9117-git-svn-init-clone.sh
@@ -16,13 +16,13 @@ cd tmp
 test_expect_success 'setup svnrepo' "
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project $svnrepo/project &&
+	svn import -m '$test_description' project \"\$svnrepo\"/project &&
 	rm -rf project
 	"
 
 test_expect_success 'basic clone' "
 	test ! -d trunk &&
-	git svn clone $svnrepo/project/trunk &&
+	git svn clone \"\$svnrepo\"/project/trunk &&
 	test -d trunk/.git/svn &&
 	test -e trunk/foo &&
 	rm -rf trunk
@@ -30,7 +30,7 @@ test_expect_success 'basic clone' "
 
 test_expect_success 'clone to target directory' "
 	test ! -d target &&
-	git svn clone $svnrepo/project/trunk target &&
+	git svn clone \"\$svnrepo\"/project/trunk target &&
 	test -d target/.git/svn &&
 	test -e target/foo &&
 	rm -rf target
@@ -38,7 +38,7 @@ test_expect_success 'clone to target directory' "
 
 test_expect_success 'clone with --stdlayout' "
 	test ! -d project &&
-	git svn clone -s $svnrepo/project &&
+	git svn clone -s \"\$svnrepo\"/project &&
 	test -d project/.git/svn &&
 	test -e project/foo &&
 	rm -rf project
@@ -46,7 +46,7 @@ test_expect_success 'clone with --stdlayout' "
 
 test_expect_success 'clone to target directory with --stdlayout' "
 	test ! -d target &&
-	git svn clone -s $svnrepo/project target &&
+	git svn clone -s \"\$svnrepo\"/project target &&
 	test -d target/.git/svn &&
 	test -e target/foo &&
 	rm -rf target
diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh
index 640bb06..0f107fc 100755
--- a/t/t9118-git-svn-funky-branch-names.sh
+++ b/t/t9118-git-svn-funky-branch-names.sh
@@ -9,17 +9,17 @@ test_description='git-svn funky branch names'
 test_expect_success 'setup svnrepo' "
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project \"$svnrepo/pr ject\" &&
+	svn import -m '\$test_description' project \"\$svnrepo/pr ject\" &&
 	rm -rf project &&
-	svn cp -m 'fun' \"$svnrepo/pr ject/trunk\" \
-	                \"$svnrepo/pr ject/branches/fun plugin\" &&
-	svn cp -m 'more fun!' \"$svnrepo/pr ject/branches/fun plugin\" \
-	                      \"$svnrepo/pr ject/branches/more fun plugin!\" &&
+	svn cp -m 'fun' \"\$svnrepo/pr ject/trunk\" \
+	                \"\$svnrepo/pr ject/branches/fun plugin\" &&
+	svn cp -m 'more fun!' \"\$svnrepo/pr ject/branches/fun plugin\" \
+	                      \"\$svnrepo/pr ject/branches/more fun plugin!\" &&
 	start_httpd
 	"
 
 test_expect_success 'test clone with funky branch names' "
-	git svn clone -s \"$svnrepo/pr ject\" project &&
+	git svn clone -s \"\$svnrepo/pr ject\" project &&
 	cd project &&
 		git rev-parse 'refs/remotes/fun%20plugin' &&
 		git rev-parse 'refs/remotes/more%20fun%20plugin!' &&
diff --git a/t/t9120-git-svn-clone-with-percent-escapes.sh b/t/t9120-git-svn-clone-with-percent-escapes.sh
index 9a4eabe..1414c0f 100755
--- a/t/t9120-git-svn-clone-with-percent-escapes.sh
+++ b/t/t9120-git-svn-clone-with-percent-escapes.sh
@@ -9,7 +9,7 @@ test_description='git-svn clone with percent escapes'
 test_expect_success 'setup svnrepo' "
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project '$svnrepo/pr ject' &&
+	svn import -m \"\$test_description\" project \"\$svnrepo/pr ject\" &&
 	rm -rf project &&
 	start_httpd
 "
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 796cd7d..0f36e6c 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -10,6 +10,7 @@ commandline, and checks that it would not write any errors
 or warnings to log.'
 
 gitweb_init () {
+	safe_pwd="$(perl -MPOSIX=getcwd -e 'print quotemeta(getcwd)')"
 	cat >gitweb_config.perl <<EOF
 #!/usr/bin/perl
 
@@ -17,16 +18,16 @@ gitweb_init () {
 
 our \$version = "current";
 our \$GIT = "git";
-our \$projectroot = "$(pwd)";
+our \$projectroot = "$safe_pwd";
 our \$project_maxdepth = 8;
 our \$home_link_str = "projects";
 our \$site_name = "[localhost]";
 our \$site_header = "";
 our \$site_footer = "";
 our \$home_text = "indextext.html";
-our @stylesheets = ("file:///$(pwd)/../../gitweb/gitweb.css");
-our \$logo = "file:///$(pwd)/../../gitweb/git-logo.png";
-our \$favicon = "file:///$(pwd)/../../gitweb/git-favicon.png";
+our @stylesheets = ("file:///$safe_pwd/../../gitweb/gitweb.css");
+our \$logo = "file:///$safe_pwd/../../gitweb/git-logo.png";
+our \$favicon = "file:///$safe_pwd/../../gitweb/git-favicon.png";
 our \$projects_list = "";
 our \$export_ok = "";
 our \$strict_export = "";
@@ -45,13 +46,13 @@ gitweb_run () {
 	export QUERY_STRING=""$1""
 	export PATH_INFO=""$2""
 
-	export GITWEB_CONFIG=$(pwd)/gitweb_config.perl
+	export GITWEB_CONFIG="$(pwd)/gitweb_config.perl"
 
 	# some of git commands write to STDERR on error, but this is not
 	# written to web server logs, so we are not interested in that:
 	# we are interested only in properly formatted errors/warnings
 	rm -f gitweb.log &&
-	perl -- $(pwd)/../../gitweb/gitweb.perl \
+	perl -- "$(pwd)/../../gitweb/gitweb.perl" \
 		>/dev/null 2>gitweb.log &&
 	if grep -q -s "^[[]" gitweb.log >/dev/null; then false; else true; fi
 
-- 
1.5.5.8.gbbd98

^ permalink raw reply related	[relevance 10%]

* [PATCH v2 09/10] Fix tests breaking when checkout path contains shell metacharacters
  @ 2008-04-10  6:50 10%                   ` Bryan Donlan
  0 siblings, 0 replies; 200+ results
From: Bryan Donlan @ 2008-04-10  6:50 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Adam Roben, gitster, Bryan Donlan

This fixes the remainder of the issues where the test script itself is at
fault for failing when the git checkout path contains whitespace or other
shell metacharacters.

Signed-off-by: Bryan Donlan <bdonlan@fushizen.net>
---
 t/t0000-basic.sh                              |    4 +-
 t/t1020-subdirectory.sh                       |   22 +++++-----
 t/t3050-subprojects-fetch.sh                  |    2 +-
 t/t3404-rebase-interactive.sh                 |    3 +-
 t/t5500-fetch-pack.sh                         |    2 +-
 t/t5512-ls-remote.sh                          |    2 +-
 t/t5516-fetch-push.sh                         |    4 +-
 t/t5700-clone-reference.sh                    |    2 +-
 t/t5710-info-alternate.sh                     |    2 +-
 t/t7003-filter-branch.sh                      |    2 +-
 t/t7010-setup.sh                              |    2 +-
 t/t7300-clean.sh                              |    2 +-
 t/t7501-commit.sh                             |    8 ++--
 t/t7504-commit-msg-hook.sh                    |   23 ++++++-----
 t/t7505-prepare-commit-msg-hook.sh            |   17 +++++---
 t/t9100-git-svn-basic.sh                      |   54 ++++++++++++------------
 t/t9101-git-svn-props.sh                      |    6 +-
 t/t9102-git-svn-deep-rmdir.sh                 |    6 +-
 t/t9103-git-svn-tracked-directory-removed.sh  |   30 +++++++-------
 t/t9104-git-svn-follow-parent.sh              |   50 +++++++++++-----------
 t/t9105-git-svn-commit-diff.sh                |   12 +++---
 t/t9106-git-svn-commit-diff-clobber.sh        |   14 +++---
 t/t9106-git-svn-dcommit-clobber-series.sh     |    6 +-
 t/t9107-git-svn-migrate.sh                    |   48 +++++++++++-----------
 t/t9108-git-svn-glob.sh                       |    8 ++--
 t/t9110-git-svn-use-svm-props.sh              |    8 ++--
 t/t9111-git-svn-use-svnsync-props.sh          |    8 ++--
 t/t9112-git-svn-md5less-file.sh               |    4 +-
 t/t9113-git-svn-dcommit-new-file.sh           |    6 +-
 t/t9114-git-svn-dcommit-merge.sh              |    4 +-
 t/t9115-git-svn-dcommit-funky-renames.sh      |    4 +-
 t/t9116-git-svn-log.sh                        |    4 +-
 t/t9117-git-svn-init-clone.sh                 |   10 ++--
 t/t9118-git-svn-funky-branch-names.sh         |   12 +++---
 t/t9120-git-svn-clone-with-percent-escapes.sh |    2 +-
 t/t9500-gitweb-standalone-no-errors.sh        |   11 +++--
 36 files changed, 205 insertions(+), 199 deletions(-)

diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 27b54cb..690f80a 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -305,10 +305,10 @@ test_expect_success 'absolute path works as expected' '
 	file="$dir"/index &&
 	test "$file" = "$(test-absolute-path $dir2/index)" &&
 	basename=blub &&
-	test "$dir/$basename" = $(cd .git && test-absolute-path $basename) &&
+	test "$dir/$basename" = "$(cd .git && test-absolute-path "$basename")" &&
 	ln -s ../first/file .git/syml &&
 	sym="$(cd first; pwd -P)"/file &&
-	test "$sym" = "$(test-absolute-path $dir2/syml)"
+	test "$sym" = "$(test-absolute-path "$dir2/syml")"
 '
 
 test_expect_success 'very long name in the index handled sanely' '
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index b9cef34..fc386ba 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -21,7 +21,7 @@ LF='
 '
 
 test_expect_success 'update-index and ls-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git update-index --add one &&
 	case "`git ls-files`" in
 	one) echo ok one ;;
@@ -41,7 +41,7 @@ test_expect_success 'update-index and ls-files' '
 '
 
 test_expect_success 'cat-file' '
-	cd $HERE &&
+	cd "$HERE" &&
 	two=`git ls-files -s dir/two` &&
 	two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
 	echo "$two" &&
@@ -54,7 +54,7 @@ test_expect_success 'cat-file' '
 rm -f actual dir/actual
 
 test_expect_success 'diff-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	echo a >>one &&
 	echo d >>dir/two &&
 	case "`git diff-files --name-only`" in
@@ -74,7 +74,7 @@ test_expect_success 'diff-files' '
 '
 
 test_expect_success 'write-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	top=`git write-tree` &&
 	echo $top &&
 	cd dir &&
@@ -84,7 +84,7 @@ test_expect_success 'write-tree' '
 '
 
 test_expect_success 'checkout-index' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git checkout-index -f -u one &&
 	cmp one original.one &&
 	cd dir &&
@@ -93,7 +93,7 @@ test_expect_success 'checkout-index' '
 '
 
 test_expect_success 'read-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -f one dir/two &&
 	tree=`git write-tree` &&
 	git read-tree --reset -u "$tree" &&
@@ -107,27 +107,27 @@ test_expect_success 'read-tree' '
 '
 
 test_expect_success 'no file/rev ambiguity check inside .git' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git commit -a -m 1 &&
-	cd $HERE/.git &&
+	cd "$HERE"/.git &&
 	git show -s HEAD
 '
 
 test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && GIT_DIR=. git show -s HEAD
 '
 
 # This still does not work as it should...
 : test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && git show -s HEAD
 '
 
 test_expect_success 'detection should not be fooled by a symlink' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -fr foo.git &&
 	git clone -s .git another &&
 	ln -s another yetanother &&
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 2b21b10..4261e96 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -20,7 +20,7 @@ test_expect_success setup '
 '
 
 test_expect_success clone '
-	git clone file://`pwd`/.git cloned &&
+	git clone "file://$(pwd)/.git" cloned &&
 	(git rev-parse HEAD; git ls-files -s) >expected &&
 	(
 		cd cloned &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 9cf873f..b9e3dbd 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -91,9 +91,8 @@ for line in $FAKE_LINES; do
 done
 EOF
 
+test_set_editor "$(pwd)/fake-editor.sh"
 chmod a+x fake-editor.sh
-VISUAL="$(pwd)/fake-editor.sh"
-export VISUAL
 
 test_expect_success 'no changes are a nop' '
 	git rebase -i F &&
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 1700d07..140e874 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -129,7 +129,7 @@ pull_to_client 2nd "B" $((64*3))
 
 pull_to_client 3rd "A" $((1*3)) # old fails
 
-test_expect_success "clone shallow" "git-clone --depth 2 file://`pwd`/. shallow"
+test_expect_success "clone shallow" 'git-clone --depth 2 "file://$(pwd)/." shallow'
 
 (cd shallow; git count-objects -v) > count.shallow
 
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index c0dc949..1dd8eed 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -17,7 +17,7 @@ test_expect_success setup '
 		git show-ref -d	| sed -e "s/ /	/"
 	) >expected.all &&
 
-	git remote add self $(pwd)/.git
+	git remote add self "$(pwd)/.git"
 
 '
 
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 793ffc6..2b2b2ef 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -105,7 +105,7 @@ test_expect_success 'fetch with insteadOf' '
 	(
 		TRASH=$(pwd) &&
 		cd testrepo &&
-		git config url./$TRASH/.insteadOf trash/
+		git config "url./$TRASH/.insteadOf" trash/ &&
 		git config remote.up.url trash/. &&
 		git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" &&
 		git fetch up &&
@@ -146,7 +146,7 @@ test_expect_success 'push with wildcard' '
 test_expect_success 'push with insteadOf' '
 	mk_empty &&
 	TRASH=$(pwd) &&
-	git config url./$TRASH/.insteadOf trash/ &&
+	git config "url./$TRASH/.insteadOf" trash/ &&
 	git push trash/testrepo refs/heads/master:refs/remotes/origin/master &&
 	(
 		cd testrepo &&
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index b6a5486..e5619a9 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -51,7 +51,7 @@ diff expected current'
 cd "$base_dir"
 
 test_expect_success 'cloning with reference (no -l -s)' \
-'git clone --reference B file://`pwd`/A D'
+'git clone --reference B "file://$(pwd)/A" D'
 
 cd "$base_dir"
 
diff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh
index 910ccb4..1abf1a2 100755
--- a/t/t5710-info-alternate.sh
+++ b/t/t5710-info-alternate.sh
@@ -81,7 +81,7 @@ test_valid_repo'
 cd "$base_dir"
 
 test_expect_success 'breaking of loops' \
-"echo '$base_dir/B/.git/objects' >> '$base_dir'/A/.git/objects/info/alternates&&
+"echo \"\$base_dir\"/B/.git/objects >> \"\$base_dir\"/A/.git/objects/info/alternates&&
 cd C &&
 test_valid_repo"
 
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index efd658a..fd09030 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -125,7 +125,7 @@ test_expect_success 'use index-filter to move into a subdirectory' '
 		 "git ls-files -s | sed \"s-\\t-&newsubdir/-\" |
 	          GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
 			git update-index --index-info &&
-		  mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
+		  mv \"\$GIT_INDEX_FILE.new\" \"\$GIT_INDEX_FILE\"" directorymoved &&
 	test -z "$(git diff HEAD directorymoved:newsubdir)"'
 
 test_expect_success 'stops when msg filter fails' '
diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh
index 02cf7c5..d8a7c79 100755
--- a/t/t7010-setup.sh
+++ b/t/t7010-setup.sh
@@ -122,7 +122,7 @@ test_expect_success 'commit using absolute path names' '
 
 test_expect_success 'log using absolute path names' '
 	echo bb >>a/b/c/d &&
-	git commit -m "bb" $(pwd)/a/b/c/d &&
+	git commit -m "bb" "$(pwd)/a/b/c/d" &&
 
 	git log a/b/c/d >f1.txt &&
 	git log "$(pwd)/a/b/c/d" >f2.txt &&
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index afccfc9..54b1352 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -111,7 +111,7 @@ test_expect_success 'git-clean with absolute path' '
 	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
 	would_clean=$(
 		cd docs &&
-		git clean -n $(pwd)/../src |
+		git clean -n "$(pwd)/../src" |
 		sed -n -e "s|^Would remove ||p"
 	) &&
 	test "$would_clean" = ../src/part3.c || {
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index c0288f3..e5fdb63 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -79,8 +79,8 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -e "s/a file/an amend commit/g" < $1 > $1-
-mv $1- $1
+sed -e "s/a file/an amend commit/g" < "$1" > "$1-"
+mv "$1-" "$1"
 EOF
 chmod 755 editor
 
@@ -99,8 +99,8 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -e "s/amend/older/g"  < $1 > $1-
-mv $1- $1
+sed -e "s/amend/older/g"  < "$1" > "$1-"
+mv "$1-" "$1"
 EOF
 chmod 755 editor
 
diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh
index eff36aa..88577af 100755
--- a/t/t7504-commit-msg-hook.sh
+++ b/t/t7504-commit-msg-hook.sh
@@ -19,6 +19,9 @@ cp FAKE_MSG "$1"
 exit 0
 EOF
 chmod +x fake-editor
+
+## Not using test_set_editor here so we can easily ensure the editor variable
+## is only set for the editor tests
 FAKE_EDITOR="$(pwd)/fake-editor"
 export FAKE_EDITOR
 
@@ -27,7 +30,7 @@ test_expect_success 'with no hook (editor)' '
 	echo "more foo" >> file &&
 	git add file &&
 	echo "more foo" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit
 
 '
 
@@ -44,7 +47,7 @@ test_expect_success '--no-verify with no hook (editor)' '
 	echo "more bar" > file &&
 	git add file &&
 	echo "more bar" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -71,7 +74,7 @@ test_expect_success 'with succeeding hook (editor)' '
 	echo "more more" >> file &&
 	git add file &&
 	echo "more more" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit
 
 '
 
@@ -88,7 +91,7 @@ test_expect_success '--no-verify with succeeding hook (editor)' '
 	echo "even more more" >> file &&
 	git add file &&
 	echo "even more more" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -111,7 +114,7 @@ test_expect_success 'with failing hook (editor)' '
 	echo "more another" >> file &&
 	git add file &&
 	echo "more another" > FAKE_MSG &&
-	! (GIT_EDITOR="$FAKE_EDITOR" git commit)
+	! (GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit)
 
 '
 
@@ -128,7 +131,7 @@ test_expect_success '--no-verify with failing hook (editor)' '
 	echo "more stuff" >> file &&
 	git add file &&
 	echo "more stuff" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -146,7 +149,7 @@ test_expect_success 'with non-executable hook (editor)' '
 	echo "content again" >> file &&
 	git add file &&
 	echo "content again" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -m "content again"
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -m "content again"
 
 '
 
@@ -163,7 +166,7 @@ test_expect_success '--no-verify with non-executable hook (editor)' '
 	echo "even more content" >> file &&
 	git add file &&
 	echo "even more content" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -193,7 +196,7 @@ test_expect_success 'hook edits commit message (editor)' '
 	echo "additional content" >> file &&
 	git add file &&
 	echo "additional content" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit &&
 	commit_msg_is "new message"
 
 '
@@ -212,7 +215,7 @@ test_expect_success "hook doesn't edit commit message (editor)" '
 	echo "more plus" >> file &&
 	git add file &&
 	echo "more plus" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify &&
 	commit_msg_is "more plus"
 
 '
diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh
index 802aa62..cd6c7c8 100755
--- a/t/t7505-prepare-commit-msg-hook.sh
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -18,6 +18,9 @@ cat > fake-editor <<'EOF'
 exit 0
 EOF
 chmod +x fake-editor
+
+## Not using test_set_editor here so we can easily ensure the editor variable
+## is only set for the editor tests
 FAKE_EDITOR="$(pwd)/fake-editor"
 export FAKE_EDITOR
 
@@ -58,7 +61,7 @@ test_expect_success 'with hook (-m editor)' '
 
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -e -m "more more" &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -m "more more" &&
 	test "`git log -1 --pretty=format:%s`" = message
 
 '
@@ -85,7 +88,7 @@ test_expect_success 'with hook (-F editor)' '
 
 	echo "more" >> file &&
 	git add file &&
-	(echo more more | GIT_EDITOR="$FAKE_EDITOR" git commit -e -F -) &&
+	(echo more more | GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -F -) &&
 	test "`git log -1 --pretty=format:%s`" = message
 
 '
@@ -104,7 +107,7 @@ test_expect_success 'with hook (editor)' '
 
 	echo "more more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit &&
 	test "`git log -1 --pretty=format:%s`" = default
 
 '
@@ -114,7 +117,7 @@ test_expect_success 'with hook (--amend)' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --amend &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --amend &&
 	test "`git log -1 --pretty=format:%s`" = "$head"
 
 '
@@ -124,7 +127,7 @@ test_expect_success 'with hook (-c)' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -c $head &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head &&
 	test "`git log -1 --pretty=format:%s`" = "$head"
 
 '
@@ -139,7 +142,7 @@ test_expect_success 'with failing hook' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	! GIT_EDITOR="$FAKE_EDITOR" git commit -c $head
+	! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head
 
 '
 
@@ -148,7 +151,7 @@ test_expect_success 'with failing hook (--no-verify)' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	! GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify -c $head
+	! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify -c $head
 
 '
 
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 4e24ab3..528c0a9 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -31,16 +31,16 @@ test_expect_success \
 	echo 'zzz' > bar/zzz &&
 	echo '#!/bin/sh' > exec.sh &&
 	chmod +x exec.sh &&
-	svn import -m 'import for git-svn' . $svnrepo >/dev/null &&
+	svn import -m 'import for git-svn' . \"\$svnrepo\" >/dev/null &&
 	cd .. &&
 	rm -rf import &&
-	git-svn init $svnrepo"
+	git-svn init \"\$svnrepo\""
 
 test_expect_success \
     'import an SVN revision into git' \
     'git-svn fetch'
 
-test_expect_success "checkout from svn" "svn co $svnrepo '$SVN_TREE'"
+test_expect_success "checkout from svn" "svn co \"\$svnrepo\" \"\$SVN_TREE\""
 
 name='try a deep --rmdir with a commit'
 test_expect_success "$name" "
@@ -51,8 +51,8 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch &&
-	svn up '$SVN_TREE' &&
-	test -d '$SVN_TREE'/dir && test ! -d '$SVN_TREE'/dir/a"
+	svn up \"\$SVN_TREE\" &&
+	test -d \"\$SVN_TREE\"/dir && test ! -d \"\$SVN_TREE\"/dir/a"
 
 
 name='detect node change from file to directory #1'
@@ -69,7 +69,7 @@ test_expect_success "$name" "
 
 name='detect node change from directory to file #1'
 test_expect_success "$name" "
-	rm -rf dir '$GIT_DIR'/index &&
+	rm -rf dir \"\$GIT_DIR\"/index &&
 	git checkout -f -b mybranch2 remotes/git-svn &&
 	mv bar/zzz zzz &&
 	rm -rf bar &&
@@ -83,7 +83,7 @@ test_expect_success "$name" "
 
 name='detect node change from file to directory #2'
 test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+	rm -f \"\$GIT_DIR\"/index &&
 	git checkout -f -b mybranch3 remotes/git-svn &&
 	rm bar/zzz &&
 	git update-index --remove bar/zzz &&
@@ -97,7 +97,7 @@ test_expect_success "$name" "
 
 name='detect node change from directory to file #2'
 test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+	rm -f \"\$GIT_DIR\"/index &&
 	git checkout -f -b mybranch4 remotes/git-svn &&
 	rm -rf dir &&
 	git update-index --remove -- dir/file &&
@@ -111,15 +111,15 @@ test_expect_success "$name" "
 
 name='remove executable bit from a file'
 test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+	rm -f \"\$GIT_DIR\"/index &&
 	git checkout -f -b mybranch5 remotes/git-svn &&
 	chmod -x exec.sh &&
 	git update-index exec.sh &&
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test ! -x '$SVN_TREE'/exec.sh"
+	svn up \"\$SVN_TREE\" &&
+	test ! -x \"\$SVN_TREE\"/exec.sh"
 
 
 name='add executable bit back file'
@@ -129,8 +129,8 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -x '$SVN_TREE'/exec.sh"
+	svn up \"\$SVN_TREE\" &&
+	test -x \"\$SVN_TREE\"/exec.sh"
 
 
 name='executable file becomes a symlink to bar/zzz (file)'
@@ -141,8 +141,8 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -L '$SVN_TREE'/exec.sh"
+	svn up \"\$SVN_TREE\" &&
+	test -L \"\$SVN_TREE\"/exec.sh"
 
 name='new symlink is added to a file that was also just made executable'
 
@@ -153,9 +153,9 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -x '$SVN_TREE'/bar/zzz &&
-	test -L '$SVN_TREE'/exec-2.sh"
+	svn up \"\$SVN_TREE\" &&
+	test -x \"\$SVN_TREE\"/bar/zzz &&
+	test -L \"\$SVN_TREE\"/exec-2.sh"
 
 name='modify a symlink to become a file'
 test_expect_success "$name" "
@@ -166,10 +166,10 @@ test_expect_success "$name" "
 	git commit -m '$name' &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -f '$SVN_TREE'/exec-2.sh &&
-	test ! -L '$SVN_TREE'/exec-2.sh &&
-	git diff help $SVN_TREE/exec-2.sh"
+	svn up \"\$SVN_TREE\" &&
+	test -f \"\$SVN_TREE\"/exec-2.sh &&
+	test ! -L \"\$SVN_TREE\"/exec-2.sh &&
+	git diff help \"\$SVN_TREE\"/exec-2.sh"
 
 if test "$have_utf8" = t
 then
@@ -190,7 +190,7 @@ name='test fetch functionality (svn => git) with alternate GIT_SVN_ID'
 GIT_SVN_ID=alt
 export GIT_SVN_ID
 test_expect_success "$name" \
-    "git-svn init $svnrepo && git-svn fetch &&
+    "git-svn init \"\$svnrepo\" && git-svn fetch &&
      git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a &&
      git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
      git diff a b"
@@ -220,16 +220,16 @@ test_expect_success 'exit if remote refs are ambigious' "
 "
 
 test_expect_success 'exit if init-ing a would clobber a URL' "
-        svnadmin create ${PWD}/svnrepo2 &&
-        svn mkdir -m 'mkdir bar' ${svnrepo}2/bar &&
+        svnadmin create \"\${PWD}/svnrepo2\" &&
+        svn mkdir -m 'mkdir bar' \"\${svnrepo}2/bar\" &&
         git config --unset svn-remote.svn.fetch \
                                 '^bar:refs/remotes/git-svn$' &&
-	! git-svn init ${svnrepo}2/bar
+	! git-svn init \"\${svnrepo}2/bar\"
         "
 
 test_expect_success \
   'init allows us to connect to another directory in the same repo' "
-        git-svn init --minimize-url -i bar $svnrepo/bar &&
+        git-svn init --minimize-url -i bar \"\$svnrepo/bar\" &&
         git config --get svn-remote.svn.fetch \
                               '^bar:refs/remotes/bar$' &&
         git config --get svn-remote.svn.fetch \
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index d7a7047..fa8b7ee 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -52,7 +52,7 @@ EOF
 cd ..
 
 rm -rf import
-test_expect_success 'checkout working copy from svn' "svn co $svnrepo test_wc"
+test_expect_success 'checkout working copy from svn' "svn co \"\$svnrepo\" test_wc"
 test_expect_success 'setup some commits to svn' \
 	'cd test_wc &&
 		echo Greetings >> kw.c &&
@@ -66,7 +66,7 @@ test_expect_success 'setup some commits to svn' \
 		svn commit -m "Propset Id" &&
 	cd ..'
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init \"\$svnrepo\""
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 
 name='test svn:keywords ignoring'
@@ -92,7 +92,7 @@ test_expect_success "propset CR on crlf files" \
 test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
 	"git-svn fetch &&
 	 git pull . remotes/git-svn &&
-	 svn co $svnrepo new_wc"
+	 svn co \"\$svnrepo\" new_wc"
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh
index 4e08083..8eaf7d3 100755
--- a/t/t9102-git-svn-deep-rmdir.sh
+++ b/t/t9102-git-svn-deep-rmdir.sh
@@ -9,12 +9,12 @@ test_expect_success 'initialize repo' "
 	mkdir -p deeply/nested/directory/number/2 &&
 	echo foo > deeply/nested/directory/number/1/file &&
 	echo foo > deeply/nested/directory/number/2/another &&
-	svn import -m 'import for git-svn' . $svnrepo &&
+	svn import -m 'import for git-svn' . \"\$svnrepo\" &&
 	cd ..
 	"
 
 test_expect_success 'mirror via git-svn' "
-	git-svn init $svnrepo &&
+	git-svn init \"\$svnrepo\" &&
 	git-svn fetch &&
 	git checkout -f -b test-rmdir remotes/git-svn
 	"
@@ -23,7 +23,7 @@ test_expect_success 'Try a commit on rmdir' "
 	git rm -f deeply/nested/directory/number/2/another &&
 	git commit -a -m 'remove another' &&
 	git-svn set-tree --rmdir HEAD &&
-	svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1
+	svn ls -R \"\$svnrepo\" | grep ^deeply/nested/directory/number/1
 	"
 
 
diff --git a/t/t9103-git-svn-tracked-directory-removed.sh b/t/t9103-git-svn-tracked-directory-removed.sh
index 0f0b0fd..c7734e6 100755
--- a/t/t9103-git-svn-tracked-directory-removed.sh
+++ b/t/t9103-git-svn-tracked-directory-removed.sh
@@ -6,34 +6,34 @@
 test_description='git-svn tracking removed top-level path'
 . ./lib-git-svn.sh
 
-test_expect_success 'make history for tracking' '
+test_expect_success 'make history for tracking' "
 	mkdir import &&
 	mkdir import/trunk &&
 	echo hello >> import/trunk/README &&
-	svn import -m initial import $svnrepo &&
+	svn import -m initial import \"\$svnrepo\" &&
 	rm -rf import &&
-	svn co $svnrepo/trunk trunk &&
+	svn co \"\$svnrepo\"/trunk trunk &&
 	echo bye bye >> trunk/README &&
-	svn rm -m "gone" $svnrepo/trunk &&
+	svn rm -m 'gone' \"\$svnrepo\"/trunk &&
 	rm -rf trunk &&
 	mkdir trunk &&
-	echo "new" > trunk/FOLLOWME &&
-	svn import -m "new trunk" trunk $svnrepo/trunk
-'
+	echo 'new' > trunk/FOLLOWME &&
+	svn import -m 'new trunk' trunk \"\$svnrepo\"/trunk
+"
 
-test_expect_success 'clone repo with git' '
-	git svn clone -s $svnrepo x &&
+test_expect_success 'clone repo with git' "
+	git svn clone -s \"\$svnrepo\" x &&
 	test -f x/FOLLOWME &&
 	test ! -f x/README
-'
+"
 
-test_expect_success 'make sure r2 still has old file' '
+test_expect_success 'make sure r2 still has old file' "
 	cd x &&
-		test -n "$(git svn find-rev r1)" &&
-		git reset --hard $(git svn find-rev r1) &&
+		test -n \"\$(git svn find-rev r1)\" &&
+		git reset --hard \$(git svn find-rev r1) &&
 		test -f README &&
 		test ! -f FOLLOWME &&
-		test x$(git svn find-rev r2) = x
-'
+		test x\$(git svn find-rev r2) = x
+"
 
 test_done
diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 7ba7630..56b1704 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -11,9 +11,9 @@ test_expect_success 'initialize repo' "
 	cd import &&
 	mkdir -p trunk &&
 	echo hello > trunk/readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . \"\$svnrepo\" &&
 	cd .. &&
-	svn co $svnrepo wc &&
+	svn co \"\$svnrepo\" wc &&
 	cd wc &&
 	echo world >> trunk/readme &&
 	poke trunk/readme &&
@@ -27,7 +27,7 @@ test_expect_success 'initialize repo' "
 	"
 
 test_expect_success 'init and fetch a moved directory' "
-	git-svn init --minimize-url -i thunk $svnrepo/thunk &&
+	git-svn init --minimize-url -i thunk \"\$svnrepo\"/thunk &&
 	git-svn fetch -i thunk &&
 	test \"\`git rev-parse --verify refs/remotes/thunk@2\`\" \
            = \"\`git rev-parse --verify refs/remotes/thunk~1\`\" &&
@@ -38,7 +38,7 @@ test_expect_success 'init and fetch a moved directory' "
 	"
 
 test_expect_success 'init and fetch from one svn-remote' "
-        git config svn-remote.svn.url $svnrepo &&
+        git config svn-remote.svn.url \"\$svnrepo\" &&
         git config --add svn-remote.svn.fetch \
           trunk:refs/remotes/svn/trunk &&
         git config --add svn-remote.svn.fetch \
@@ -52,9 +52,9 @@ test_expect_success 'init and fetch from one svn-remote' "
 
 test_expect_success 'follow deleted parent' "
         (svn cp -m 'resurrecting trunk as junk' \
-               $svnrepo/trunk@2 $svnrepo/junk ||
+               \"\$svnrepo\"/trunk@2 \"\$svnrepo\"/junk ||
          svn cp -m 'resurrecting trunk as junk' \
-               -r2 $svnrepo/trunk $svnrepo/junk) &&
+               -r2 \"\$svnrepo\"/trunk \"\$svnrepo\"/junk) &&
         git config --add svn-remote.svn.fetch \
           junk:refs/remotes/svn/junk &&
         git-svn fetch -i svn/thunk &&
@@ -67,10 +67,10 @@ test_expect_success 'follow deleted parent' "
 test_expect_success 'follow larger parent' "
         mkdir -p import/trunk/thunk/bump/thud &&
         echo hi > import/trunk/thunk/bump/thud/file &&
-        svn import -m 'import a larger parent' import $svnrepo/larger-parent &&
-        svn cp -m 'hi' $svnrepo/larger-parent $svnrepo/another-larger &&
+        svn import -m 'import a larger parent' import \"\$svnrepo\"/larger-parent &&
+        svn cp -m 'hi' \"\$svnrepo\"/larger-parent \"\$svnrepo\"/another-larger &&
         git-svn init --minimize-url -i larger \
-          $svnrepo/another-larger/trunk/thunk/bump/thud &&
+          \"\$svnrepo\"/another-larger/trunk/thunk/bump/thud &&
         git-svn fetch -i larger &&
         git rev-parse --verify refs/remotes/larger &&
         git rev-parse --verify \
@@ -83,23 +83,23 @@ test_expect_success 'follow larger parent' "
         "
 
 test_expect_success 'follow higher-level parent' "
-        svn mkdir -m 'follow higher-level parent' $svnrepo/blob &&
-        svn co $svnrepo/blob blob &&
+        svn mkdir -m 'follow higher-level parent' \"\$svnrepo\"/blob &&
+        svn co \"\$svnrepo\"/blob blob &&
         cd blob &&
                 echo hi > hi &&
                 svn add hi &&
                 svn commit -m 'hihi' &&
                 cd ..
-        svn mkdir -m 'new glob at top level' $svnrepo/glob &&
-        svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
-        git-svn init --minimize-url -i blob $svnrepo/glob/blob &&
+        svn mkdir -m 'new glob at top level' \"\$svnrepo\"/glob &&
+        svn mv -m 'move blob down a level' \"\$svnrepo\"/blob \"\$svnrepo\"/glob/blob &&
+        git-svn init --minimize-url -i blob \"\$svnrepo\"/glob/blob &&
         git-svn fetch -i blob
         "
 
 test_expect_success 'follow deleted directory' "
-	svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye &&
-	svn rm -m 'remove glob' $svnrepo/glob &&
-	git-svn init --minimize-url -i glob $svnrepo/glob &&
+	svn mv -m 'bye!' \"\$svnrepo\"/glob/blob/hi \"\$svnrepo\"/glob/blob/bye &&
+	svn rm -m 'remove glob' \"\$svnrepo\"/glob &&
+	git-svn init --minimize-url -i glob \"\$svnrepo\"/glob &&
 	git-svn fetch -i glob &&
 	test \"\`git cat-file blob refs/remotes/glob:blob/bye\`\" = hi &&
 	test \"\`git ls-tree refs/remotes/glob | wc -l \`\" -eq 1
@@ -118,9 +118,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  echo 'bad delete test 2' > \
 	   import/trunk/subversion/bindings/swig/perl/another-larger &&
 	cd import &&
-	  svn import -m 'r9270 test' . $svnrepo/r9270 &&
+	  svn import -m 'r9270 test' . \"\$svnrepo\"/r9270 &&
 	cd .. &&
-	svn co $svnrepo/r9270/trunk/subversion/bindings/swig/perl r9270 &&
+	svn co \"\$svnrepo\"/r9270/trunk/subversion/bindings/swig/perl r9270 &&
 	cd r9270 &&
 	  svn mkdir native &&
 	  svn mv t native/t &&
@@ -130,7 +130,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  svn commit -m 'reorg test' &&
 	cd .. &&
 	git-svn init --minimize-url -i r9270-t \
-	  $svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t &&
+	  \"\$svnrepo\"/r9270/trunk/subversion/bindings/swig/perl/native/t &&
 	git-svn fetch -i r9270-t &&
 	test \`git rev-list r9270-t | wc -l\` -eq 2 &&
 	test \"\`git ls-tree --name-only r9270-t~1\`\" = \
@@ -138,9 +138,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	"
 
 test_expect_success "track initial change if it was only made to parent" "
-	svn cp -m 'wheee!' $svnrepo/r9270/trunk $svnrepo/r9270/drunk &&
+	svn cp -m 'wheee!' \"\$svnrepo\"/r9270/trunk \"\$svnrepo\"/r9270/drunk &&
 	git-svn init --minimize-url -i r9270-d \
-	  $svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t &&
+	  \"\$svnrepo\"/r9270/drunk/subversion/bindings/swig/perl/native/t &&
 	git-svn fetch -i r9270-d &&
 	test \`git rev-list r9270-d | wc -l\` -eq 3 &&
 	test \"\`git ls-tree --name-only r9270-t\`\" = \
@@ -150,7 +150,7 @@ test_expect_success "track initial change if it was only made to parent" "
 	"
 
 test_expect_success "track multi-parent paths" "
-	svn cp -m 'resurrect /glob' $svnrepo/r9270 $svnrepo/glob &&
+	svn cp -m 'resurrect /glob' \"\$svnrepo\"/r9270 \"\$svnrepo\"/glob &&
 	git-svn multi-fetch &&
 	test \`git cat-file commit refs/remotes/glob | \
 	       grep '^parent ' | wc -l\` -eq 2
@@ -161,8 +161,8 @@ test_expect_success "multi-fetch continues to work" "
 	"
 
 test_expect_success "multi-fetch works off a 'clean' repository" "
-	rm -r $GIT_DIR/svn $GIT_DIR/refs/remotes $GIT_DIR/logs &&
-	mkdir $GIT_DIR/svn &&
+	rm -r \"\$GIT_DIR/svn\" \"\$GIT_DIR/refs/remotes\" \"\$GIT_DIR/logs\" &&
+	mkdir \"\$GIT_DIR/svn\" &&
 	git-svn multi-fetch
 	"
 
diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh
index 318e172..4f7f9cc 100755
--- a/t/t9105-git-svn-commit-diff.sh
+++ b/t/t9105-git-svn-commit-diff.sh
@@ -8,7 +8,7 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo hello > readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . \"\$svnrepo\" &&
 	cd .. &&
 	echo hello > readme &&
 	git update-index --add readme &&
@@ -26,17 +26,17 @@ prev=`git rev-parse --verify HEAD^1`
 
 test_expect_success 'test the commit-diff command' "
 	test -n '$prev' && test -n '$head' &&
-	git-svn commit-diff -r1 '$prev' '$head' '$svnrepo' &&
-	svn co $svnrepo wc &&
+	git-svn commit-diff -r1 '$prev' '$head' \"\$svnrepo\" &&
+	svn co \"\$svnrepo\" wc &&
 	cmp readme wc/readme
 	"
 
 test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
-	svn import -m 'sub-directory' import $svnrepo/subdir &&
-	git-svn init --minimize-url $svnrepo/subdir &&
+	svn import -m 'sub-directory' import \"\$svnrepo\"/subdir &&
+	git-svn init --minimize-url \"\$svnrepo\"/subdir &&
 	git-svn fetch &&
 	git-svn commit-diff -r3 '$prev' '$head' &&
-	svn cat $svnrepo/subdir/readme > readme.2 &&
+	svn cat \"\$svnrepo\"/subdir/readme > readme.2 &&
 	cmp readme readme.2
 	"
 
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index f74ab12..bb544f6 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -8,14 +8,14 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo initial > file &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . \"\$svnrepo\" &&
 	cd .. &&
 	echo initial > file &&
 	git update-index --add file &&
 	git commit -a -m 'initial'
 	"
 test_expect_success 'commit change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co \"\$svnrepo\" t.svn &&
 	cd t.svn &&
 	echo second line from svn >> file &&
 	poke file &&
@@ -27,7 +27,7 @@ test_expect_success 'commit change from svn side' "
 test_expect_success 'commit conflicting change from git' "
 	echo second line from git >> file &&
 	git commit -a -m 'second line from git' &&
-	! git-svn commit-diff -r1 HEAD~1 HEAD $svnrepo
+	! git-svn commit-diff -r1 HEAD~1 HEAD \"\$svnrepo\"
 "
 
 test_expect_success 'commit complementing change from git' "
@@ -36,14 +36,14 @@ test_expect_success 'commit complementing change from git' "
 	git commit -a -m 'second line from svn' &&
 	echo third line from git >> file &&
 	git commit -a -m 'third line from git' &&
-	git-svn commit-diff -r2 HEAD~1 HEAD $svnrepo
+	git-svn commit-diff -r2 HEAD~1 HEAD \"\$svnrepo\"
 	"
 
 test_expect_success 'dcommit fails to commit because of conflict' "
-	git-svn init $svnrepo &&
+	git-svn init \"\$svnrepo\" &&
 	git-svn fetch &&
 	git reset --hard refs/remotes/git-svn &&
-	svn co $svnrepo t.svn &&
+	svn co \"\$svnrepo\" t.svn &&
 	cd t.svn &&
 	echo fourth line from svn >> file &&
 	poke file &&
@@ -67,7 +67,7 @@ test_expect_success 'dcommit does the svn equivalent of an index merge' "
 	"
 
 test_expect_success 'commit another change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co \"\$svnrepo\" t.svn &&
 	cd t.svn &&
 		echo third line from svn >> file &&
 		poke file &&
diff --git a/t/t9106-git-svn-dcommit-clobber-series.sh b/t/t9106-git-svn-dcommit-clobber-series.sh
index ca8a00e..477755a 100755
--- a/t/t9106-git-svn-dcommit-clobber-series.sh
+++ b/t/t9106-git-svn-dcommit-clobber-series.sh
@@ -8,9 +8,9 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	awk 'BEGIN { for (i = 1; i < 64; i++) { print i } }' > file
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . \"\$svnrepo\" &&
 	cd .. &&
-	git svn init $svnrepo &&
+	git svn init \"\$svnrepo\" &&
 	git svn fetch &&
 	test -e file
 	"
@@ -18,7 +18,7 @@ test_expect_success 'initialize repo' "
 test_expect_success '(supposedly) non-conflicting change from SVN' "
 	test x\"\`sed -n -e 58p < file\`\" = x58 &&
 	test x\"\`sed -n -e 61p < file\`\" = x61 &&
-	svn co $svnrepo tmp &&
+	svn co \"\$svnrepo\" tmp &&
 	cd tmp &&
 		perl -i -p -e 's/^58\$/5588/' file &&
 		perl -i -p -e 's/^61\$/6611/' file &&
diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index 0a41d52..9ab7074 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -4,7 +4,7 @@ test_description='git-svn metadata migrations from previous versions'
 . ./lib-git-svn.sh
 
 test_expect_success 'setup old-looking metadata' "
-	cp $GIT_DIR/config $GIT_DIR/config-old-git-svn &&
+	cp \"\$GIT_DIR\"/config \"\$GIT_DIR\"/config-old-git-svn &&
 	mkdir import &&
 	cd import &&
 		for i in trunk branches/a branches/b \
@@ -12,13 +12,13 @@ test_expect_success 'setup old-looking metadata' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . \"\$svnrepo\"
 		cd .. &&
-	git-svn init $svnrepo &&
+	git-svn init \"\$svnrepo\" &&
 	git-svn fetch &&
-	mv $GIT_DIR/svn/* $GIT_DIR/ &&
-	mv $GIT_DIR/svn/.metadata $GIT_DIR/ &&
-	rmdir $GIT_DIR/svn &&
+	mv \"\$GIT_DIR\"/svn/* \"\$GIT_DIR\"/ &&
+	mv \"\$GIT_DIR\"/svn/.metadata \"\$GIT_DIR\"/ &&
+	rmdir \"\$GIT_DIR\"/svn &&
 	git update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn &&
 	git update-ref refs/heads/svn-HEAD refs/remotes/git-svn &&
 	git update-ref -d refs/remotes/git-svn refs/remotes/git-svn
@@ -28,20 +28,20 @@ head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
 test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
 
 test_expect_success 'initialize old-style (v0) git-svn layout' "
-	mkdir -p $GIT_DIR/git-svn/info $GIT_DIR/svn/info &&
-	echo $svnrepo > $GIT_DIR/git-svn/info/url &&
-	echo $svnrepo > $GIT_DIR/svn/info/url &&
+	mkdir -p \"\$GIT_DIR\"/git-svn/info \"\$GIT_DIR\"/svn/info &&
+	echo \"\$svnrepo\" > \"\$GIT_DIR\"/git-svn/info/url &&
+	echo \"\$svnrepo\" > \"\$GIT_DIR\"/svn/info/url &&
 	git-svn migrate &&
-	! test -d $GIT_DIR/git-svn &&
+	! test -d \"\$GIT_DIR\"/git-svn &&
 	git rev-parse --verify refs/remotes/git-svn^0 &&
 	git rev-parse --verify refs/remotes/svn^0 &&
-	test \`git config --get svn-remote.svn.url\` = '$svnrepo' &&
+	test \"\$(git config --get svn-remote.svn.url)\" = \"\$svnrepo\" &&
 	test \`git config --get svn-remote.svn.fetch\` = \
              ':refs/remotes/git-svn'
 	"
 
 test_expect_success 'initialize a multi-repository repo' "
-	git-svn init $svnrepo -T trunk -t tags -b branches &&
+	git-svn init \"\$svnrepo\" -T trunk -t tags -b branches &&
 	git config --get-all svn-remote.svn.fetch > fetch.out &&
 	grep '^trunk:refs/remotes/trunk$' fetch.out &&
 	test -n \"\`git config --get svn-remote.svn.branches \
@@ -76,14 +76,14 @@ test_expect_success 'multi-fetch works on partial urls + paths' "
 test_expect_success 'migrate --minimize on old inited layout' "
 	git config --unset-all svn-remote.svn.fetch &&
 	git config --unset-all svn-remote.svn.url &&
-	rm -rf $GIT_DIR/svn &&
+	rm -rf \"\$GIT_DIR\"/svn &&
 	for i in \`cat fetch.out\`; do
 		path=\`expr \$i : '\\([^:]*\\):.*$'\`
 		ref=\`expr \$i : '[^:]*:refs/remotes/\\(.*\\)$'\`
 		if test -z \"\$ref\"; then continue; fi
 		if test -n \"\$path\"; then path=\"/\$path\"; fi
-		( mkdir -p $GIT_DIR/svn/\$ref/info/ &&
-		echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
+		( mkdir -p \"\$GIT_DIR\"/svn/\$ref/info/ &&
+		echo \"\$svnrepo\"\$path > \"\$GIT_DIR\"/svn/\$ref/info/url ) || exit 1;
 	done &&
 	git-svn migrate --minimize &&
 	test -z \"\`git config -l |grep -v '^svn-remote\.git-svn\.'\`\" &&
@@ -99,17 +99,17 @@ test_expect_success 'migrate --minimize on old inited layout' "
 
 test_expect_success  ".rev_db auto-converted to .rev_map.UUID" "
 	git-svn fetch -i trunk &&
-	test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
-	expect=\"\$(ls $GIT_DIR/svn/trunk/.rev_map.*)\" &&
+	test -z \"\$(ls \"\$GIT_DIR\"/svn/trunk/.rev_db.* 2>/dev/null)\" &&
+	expect=\"\$(ls \"\$GIT_DIR\"/svn/trunk/.rev_map.*)\" &&
 	test -n \"\$expect\" &&
-	rev_db=\$(echo \$expect | sed -e 's,_map,_db,') &&
-	convert_to_rev_db \$expect \$rev_db &&
-	rm -f \$expect &&
-	test -f \$rev_db &&
+	rev_db=\"\$(echo \$expect | sed -e 's,_map,_db,')\" &&
+	convert_to_rev_db \"\$expect\" \"\$rev_db\" &&
+	rm -f \"\$expect\" &&
+	test -f \"\$rev_db\" &&
 	git-svn fetch -i trunk &&
-	test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
-	test ! -e $GIT_DIR/svn/trunk/.rev_db &&
-	test -f \$expect
+	test -z \"\$(ls \"\$GIT_DIR\"/svn/trunk/.rev_db.* 2>/dev/null)\" &&
+	test ! -e \"\$GIT_DIR\"/svn/trunk/.rev_db &&
+	test -f \"\$expect\"
 	"
 
 test_done
diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh
index db4344c..8f03f2d 100755
--- a/t/t9108-git-svn-glob.sh
+++ b/t/t9108-git-svn-glob.sh
@@ -14,8 +14,8 @@ test_expect_success 'test refspec globbing' "
 	mkdir -p trunk/src/a trunk/src/b trunk/doc &&
 	echo 'hello world' > trunk/src/a/readme &&
 	echo 'goodbye world' > trunk/src/b/readme &&
-	svn import -m 'initial' trunk $svnrepo/trunk &&
-	svn co $svnrepo tmp &&
+	svn import -m 'initial' trunk \"\$svnrepo\"/trunk &&
+	svn co \"\$svnrepo\" tmp &&
 	cd tmp &&
 		mkdir branches tags &&
 		svn add branches tags &&
@@ -38,7 +38,7 @@ test_expect_success 'test refspec globbing' "
 		poke tags/end/src/b/readme &&
 		svn commit -m 'nothing to see here'
 		cd .. &&
-	git config --add svn-remote.svn.url $svnrepo &&
+	git config --add svn-remote.svn.url \"\$svnrepo\" &&
 	git config --add svn-remote.svn.fetch \
 	                 'trunk/src/a:refs/remotes/trunk' &&
 	git config --add svn-remote.svn.branches \
@@ -60,7 +60,7 @@ echo nothing to see here >> expect.two
 cat expect.end >> expect.two
 
 test_expect_success 'test left-hand-side only globbing' "
-	git config --add svn-remote.two.url $svnrepo &&
+	git config --add svn-remote.two.url \"\$svnrepo\" &&
 	git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
 	git config --add svn-remote.two.branches \
 	                 'branches/*:refs/remotes/two/branches/*' &&
diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh
index 6235af4..d9ac558 100755
--- a/t/t9110-git-svn-use-svm-props.sh
+++ b/t/t9110-git-svn-use-svm-props.sh
@@ -8,11 +8,11 @@ test_description='git-svn useSvmProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svm repo' "
-	svnadmin load -q $rawsvnrepo < ../t9110/svm.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/mirror/arr &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/mirror/argh &&
+	svnadmin load -q \"\$rawsvnrepo\" < ../t9110/svm.dump &&
+	git-svn init --minimize-url -R arr -i bar \"\$svnrepo\"/mirror/arr &&
+	git-svn init --minimize-url -R argh -i dir \"\$svnrepo\"/mirror/argh &&
 	git-svn init --minimize-url -R argh -i e \
-	  $svnrepo/mirror/argh/a/b/c/d/e &&
+	  \"\$svnrepo\"/mirror/argh/a/b/c/d/e &&
 	git config svn.useSvmProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9111-git-svn-use-svnsync-props.sh b/t/t9111-git-svn-use-svnsync-props.sh
index ec7dedd..77185bc 100755
--- a/t/t9111-git-svn-use-svnsync-props.sh
+++ b/t/t9111-git-svn-use-svnsync-props.sh
@@ -8,10 +8,10 @@ test_description='git-svn useSvnsyncProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svnsync repo' "
-	svnadmin load -q $rawsvnrepo < ../t9111/svnsync.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/bar &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/dir &&
-	git-svn init --minimize-url -R argh -i e $svnrepo/dir/a/b/c/d/e &&
+	svnadmin load -q \"\$rawsvnrepo\" < ../t9111/svnsync.dump &&
+	git-svn init --minimize-url -R arr -i bar \"\$svnrepo\"/bar &&
+	git-svn init --minimize-url -R argh -i dir \"\$svnrepo\"/dir &&
+	git-svn init --minimize-url -R argh -i e \"\$svnrepo\"/dir/a/b/c/d/e &&
 	git config svn.useSvnsyncProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh
index 646a5f0..fb1491d 100755
--- a/t/t9112-git-svn-md5less-file.sh
+++ b/t/t9112-git-svn-md5less-file.sh
@@ -40,8 +40,8 @@ PROPS-END
 
 EOF
 
-test_expect_success 'load svn dumpfile' "svnadmin load $rawsvnrepo < dumpfile.svn"
+test_expect_success 'load svn dumpfile' "svnadmin load \"\$rawsvnrepo\" < dumpfile.svn"
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init \"\$svnrepo\""
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 test_done
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
index 9ef0db9..b92a64e 100755
--- a/t/t9113-git-svn-dcommit-new-file.sh
+++ b/t/t9113-git-svn-dcommit-new-file.sh
@@ -15,14 +15,14 @@ test_description='git-svn dcommit new files over svn:// test'
 
 start_svnserve () {
 	svnserve --listen-port $SVNSERVE_PORT \
-	         --root $rawsvnrepo \
+	         --root "$rawsvnrepo" \
 	         --listen-once \
 	         --listen-host 127.0.0.1 &
 }
 
 test_expect_success 'start tracking an empty repo' "
-	svn mkdir -m 'empty dir' $svnrepo/empty-dir &&
-	echo anon-access = write >> $rawsvnrepo/conf/svnserve.conf &&
+	svn mkdir -m 'empty dir' \"\$svnrepo\"/empty-dir &&
+	echo anon-access = write >> \"\$rawsvnrepo\"/conf/svnserve.conf &&
 	start_svnserve &&
 	git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
 	git svn fetch
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
index 225060b..74b971c 100755
--- a/t/t9114-git-svn-dcommit-merge.sh
+++ b/t/t9114-git-svn-dcommit-merge.sh
@@ -35,7 +35,7 @@ EOF
 }
 
 test_expect_success 'setup svn repository' "
-	svn co $svnrepo mysvnwork &&
+	svn co \"\$svnrepo\" mysvnwork &&
 	mkdir -p mysvnwork/trunk &&
 	cd mysvnwork &&
 		big_text_block >> trunk/README &&
@@ -45,7 +45,7 @@ test_expect_success 'setup svn repository' "
 	"
 
 test_expect_success 'setup git mirror and merge' "
-	git svn init $svnrepo -t tags -T trunk -b branches &&
+	git svn init \"\$svnrepo\" -t tags -T trunk -b branches &&
 	git svn fetch &&
 	git checkout --track -b svn remotes/trunk &&
 	git checkout -b merge &&
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 182299c..f83f4f9 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -8,12 +8,12 @@ test_description='git-svn dcommit can commit renames of files with ugly names'
 . ./lib-git-svn.sh
 
 test_expect_success 'load repository with strange names' "
-	svnadmin load -q $rawsvnrepo < ../t9115/funky-names.dump &&
+	svnadmin load -q \"\$rawsvnrepo\" < ../t9115/funky-names.dump &&
 	start_httpd
 	"
 
 test_expect_success 'init and fetch repository' "
-	git svn init $svnrepo &&
+	git svn init \"\$svnrepo\" &&
 	git svn fetch &&
 	git reset --hard git-svn
 	"
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index e1e8bdf..13081b8 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -14,9 +14,9 @@ test_expect_success 'setup repository and import' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . \"\$svnrepo\"
 		cd .. &&
-	git-svn init $svnrepo -T trunk -b branches -t tags &&
+	git-svn init \"\$svnrepo\" -T trunk -b branches -t tags &&
 	git-svn fetch &&
 	git reset --hard trunk &&
 	echo bye >> README &&
diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh
index d482b40..c924915 100755
--- a/t/t9117-git-svn-init-clone.sh
+++ b/t/t9117-git-svn-init-clone.sh
@@ -16,13 +16,13 @@ cd tmp
 test_expect_success 'setup svnrepo' "
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project $svnrepo/project &&
+	svn import -m '$test_description' project \"\$svnrepo\"/project &&
 	rm -rf project
 	"
 
 test_expect_success 'basic clone' "
 	test ! -d trunk &&
-	git svn clone $svnrepo/project/trunk &&
+	git svn clone \"\$svnrepo\"/project/trunk &&
 	test -d trunk/.git/svn &&
 	test -e trunk/foo &&
 	rm -rf trunk
@@ -30,7 +30,7 @@ test_expect_success 'basic clone' "
 
 test_expect_success 'clone to target directory' "
 	test ! -d target &&
-	git svn clone $svnrepo/project/trunk target &&
+	git svn clone \"\$svnrepo\"/project/trunk target &&
 	test -d target/.git/svn &&
 	test -e target/foo &&
 	rm -rf target
@@ -38,7 +38,7 @@ test_expect_success 'clone to target directory' "
 
 test_expect_success 'clone with --stdlayout' "
 	test ! -d project &&
-	git svn clone -s $svnrepo/project &&
+	git svn clone -s \"\$svnrepo\"/project &&
 	test -d project/.git/svn &&
 	test -e project/foo &&
 	rm -rf project
@@ -46,7 +46,7 @@ test_expect_success 'clone with --stdlayout' "
 
 test_expect_success 'clone to target directory with --stdlayout' "
 	test ! -d target &&
-	git svn clone -s $svnrepo/project target &&
+	git svn clone -s \"\$svnrepo\"/project target &&
 	test -d target/.git/svn &&
 	test -e target/foo &&
 	rm -rf target
diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh
index 640bb06..0f107fc 100755
--- a/t/t9118-git-svn-funky-branch-names.sh
+++ b/t/t9118-git-svn-funky-branch-names.sh
@@ -9,17 +9,17 @@ test_description='git-svn funky branch names'
 test_expect_success 'setup svnrepo' "
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project \"$svnrepo/pr ject\" &&
+	svn import -m '\$test_description' project \"\$svnrepo/pr ject\" &&
 	rm -rf project &&
-	svn cp -m 'fun' \"$svnrepo/pr ject/trunk\" \
-	                \"$svnrepo/pr ject/branches/fun plugin\" &&
-	svn cp -m 'more fun!' \"$svnrepo/pr ject/branches/fun plugin\" \
-	                      \"$svnrepo/pr ject/branches/more fun plugin!\" &&
+	svn cp -m 'fun' \"\$svnrepo/pr ject/trunk\" \
+	                \"\$svnrepo/pr ject/branches/fun plugin\" &&
+	svn cp -m 'more fun!' \"\$svnrepo/pr ject/branches/fun plugin\" \
+	                      \"\$svnrepo/pr ject/branches/more fun plugin!\" &&
 	start_httpd
 	"
 
 test_expect_success 'test clone with funky branch names' "
-	git svn clone -s \"$svnrepo/pr ject\" project &&
+	git svn clone -s \"\$svnrepo/pr ject\" project &&
 	cd project &&
 		git rev-parse 'refs/remotes/fun%20plugin' &&
 		git rev-parse 'refs/remotes/more%20fun%20plugin!' &&
diff --git a/t/t9120-git-svn-clone-with-percent-escapes.sh b/t/t9120-git-svn-clone-with-percent-escapes.sh
index 9a4eabe..1414c0f 100755
--- a/t/t9120-git-svn-clone-with-percent-escapes.sh
+++ b/t/t9120-git-svn-clone-with-percent-escapes.sh
@@ -9,7 +9,7 @@ test_description='git-svn clone with percent escapes'
 test_expect_success 'setup svnrepo' "
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project '$svnrepo/pr ject' &&
+	svn import -m \"\$test_description\" project \"\$svnrepo/pr ject\" &&
 	rm -rf project &&
 	start_httpd
 "
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index e7b911e..405bad5 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -10,6 +10,7 @@ commandline, and checks that it would not write any errors
 or warnings to log.'
 
 gitweb_init () {
+	safe_pwd="$(perl -MPOSIX=getcwd -e 'print quotemeta(getcwd)')"
 	cat >gitweb_config.perl <<EOF
 #!/usr/bin/perl
 
@@ -17,16 +18,16 @@ gitweb_init () {
 
 our \$version = "current";
 our \$GIT = "git";
-our \$projectroot = "$(pwd)";
+our \$projectroot = "$safe_pwd";
 our \$project_maxdepth = 8;
 our \$home_link_str = "projects";
 our \$site_name = "[localhost]";
 our \$site_header = "";
 our \$site_footer = "";
 our \$home_text = "indextext.html";
-our @stylesheets = ("file:///$(pwd)/../../gitweb/gitweb.css");
-our \$logo = "file:///$(pwd)/../../gitweb/git-logo.png";
-our \$favicon = "file:///$(pwd)/../../gitweb/git-favicon.png";
+our @stylesheets = ("file:///$safe_pwd/../../gitweb/gitweb.css");
+our \$logo = "file:///$safe_pwd/../../gitweb/git-logo.png";
+our \$favicon = "file:///$safe_pwd/../../gitweb/git-favicon.png";
 our \$projects_list = "";
 our \$export_ok = "";
 our \$strict_export = "";
@@ -53,7 +54,7 @@ gitweb_run () {
 	# written to web server logs, so we are not interested in that:
 	# we are interested only in properly formatted errors/warnings
 	rm -f gitweb.log &&
-	perl -- $(pwd)/../../gitweb/gitweb.perl \
+	perl -- "$(pwd)/../../gitweb/gitweb.perl" \
 		>/dev/null 2>gitweb.log &&
 	if grep -q -s "^[[]" gitweb.log >/dev/null; then false; else true; fi
 
-- 
1.5.5.33.gc0a39.dirty

^ permalink raw reply related	[relevance 10%]

* [PATCH] Have tests and programs understand paths containing spaces
@ 2008-04-22 21:28  9% Arjen Laarhoven
  0 siblings, 0 replies; 200+ results
From: Arjen Laarhoven @ 2008-04-22 21:28 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Junio C Hamano

A lot of tests and some core programs didn't work when used in a path
containing whitespace.  Correct the quoting of all affected programs to
fix this.

Signed-off-by: Arjen Laarhoven <arjen@yaph.org>
---
 builtin-tag.c                                |    2 +-
 git-rebase.sh                                |    2 +-
 git-send-email.perl                          |    2 +-
 git-sh-setup.sh                              |    2 +-
 t/lib-git-svn.sh                             |    8 ++--
 t/t0000-basic.sh                             |    2 +-
 t/t1020-subdirectory.sh                      |   22 ++++++------
 t/t3050-subprojects-fetch.sh                 |    2 +-
 t/t3404-rebase-interactive.sh                |    2 +-
 t/t5500-fetch-pack.sh                        |    2 +-
 t/t5512-ls-remote.sh                         |    2 +-
 t/t5516-fetch-push.sh                        |   10 +++---
 t/t5700-clone-reference.sh                   |    4 +-
 t/t7003-filter-branch.sh                     |    4 +-
 t/t7005-editor.sh                            |    4 +-
 t/t7010-setup.sh                             |    2 +-
 t/t7300-clean.sh                             |    2 +-
 t/t7501-commit.sh                            |    8 ++--
 t/t9001-send-email.sh                        |    4 +-
 t/t9100-git-svn-basic.sh                     |   26 +++++++-------
 t/t9101-git-svn-props.sh                     |    6 ++--
 t/t9102-git-svn-deep-rmdir.sh                |    6 ++--
 t/t9103-git-svn-tracked-directory-removed.sh |   10 +++---
 t/t9104-git-svn-follow-parent.sh             |   50 +++++++++++++-------------
 t/t9105-git-svn-commit-diff.sh               |   10 +++---
 t/t9106-git-svn-commit-diff-clobber.sh       |   14 ++++----
 t/t9106-git-svn-dcommit-clobber-series.sh    |    6 ++--
 t/t9107-git-svn-migrate.sh                   |   48 ++++++++++++------------
 t/t9108-git-svn-glob.sh                      |    8 ++--
 t/t9110-git-svn-use-svm-props.sh             |    8 ++--
 t/t9111-git-svn-use-svnsync-props.sh         |    8 ++--
 t/t9112-git-svn-md5less-file.sh              |    4 +-
 t/t9113-git-svn-dcommit-new-file.sh          |    6 ++--
 t/t9114-git-svn-dcommit-merge.sh             |    4 +-
 t/t9115-git-svn-dcommit-funky-renames.sh     |    4 +-
 t/t9116-git-svn-log.sh                       |    4 +-
 t/t9117-git-svn-init-clone.sh                |   10 +++---
 t/t9121-git-svn-fetch-renamed-dir.sh         |    4 +-
 t/t9400-git-cvsserver-server.sh              |   20 +++++-----
 t/t9500-gitweb-standalone-no-errors.sh       |    4 +-
 t/t9600-cvsimport.sh                         |    6 ++--
 t/test-lib.sh                                |   10 +++---
 42 files changed, 181 insertions(+), 181 deletions(-)

diff --git a/builtin-tag.c b/builtin-tag.c
index 129ff57..2d04d4f 100644
--- a/builtin-tag.c
+++ b/builtin-tag.c
@@ -55,7 +55,7 @@ void launch_editor(const char *path, struct strbuf *buffer, const char *const *e
 		strbuf_init(&arg0, 0);
 		if (strcspn(editor, "$ \t'") != len) {
 			/* there are specials */
-			strbuf_addf(&arg0, "%s \"$@\"", editor);
+			strbuf_addf(&arg0, "'%s' \"$@\"", editor);
 			args[i++] = "sh";
 			args[i++] = "-c";
 			args[i++] = arg0.buf;
diff --git a/git-rebase.sh b/git-rebase.sh
index 9b13b83..c43afe5 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -214,7 +214,7 @@ do
 		else
 			die "No rebase in progress?"
 		fi
-		git reset --hard $(cat $dotest/orig-head)
+		git reset --hard $(cat "$dotest/orig-head")
 		rm -r "$dotest"
 		exit
 		;;
diff --git a/git-send-email.perl b/git-send-email.perl
index 9e568bf..40a521a 100755
--- a/git-send-email.perl
+++ b/git-send-email.perl
@@ -512,7 +512,7 @@ EOT
 	close(C);
 
 	my $editor = $ENV{GIT_EDITOR} || Git::config(@repo, "core.editor") || $ENV{VISUAL} || $ENV{EDITOR} || "vi";
-	system('sh', '-c', '$0 $@', $editor, $compose_filename);
+	system('sh', '-c', '"$0" $@', $editor, $compose_filename);
 
 	open(C2,">",$compose_filename . ".final")
 		or die "Failed to open $compose_filename.final : " . $!;
diff --git a/git-sh-setup.sh b/git-sh-setup.sh
index a44b1c7..a8a024b 100755
--- a/git-sh-setup.sh
+++ b/git-sh-setup.sh
@@ -73,7 +73,7 @@ git_editor() {
 		exit 1
 		;;
 	esac
-	eval "${GIT_EDITOR:=vi}" '"$@"'
+	eval '"${GIT_EDITOR:=vi}"' '"$@"'
 }
 
 is_bare_repository () {
diff --git a/t/lib-git-svn.sh b/t/lib-git-svn.sh
index 9decd2e..f6645f9 100644
--- a/t/lib-git-svn.sh
+++ b/t/lib-git-svn.sh
@@ -7,9 +7,9 @@ then
 	exit
 fi
 
-GIT_DIR=$PWD/.git
-GIT_SVN_DIR=$GIT_DIR/svn/git-svn
-SVN_TREE=$GIT_SVN_DIR/svn-tree
+GIT_DIR="$PWD/.git"
+GIT_SVN_DIR="$GIT_DIR/svn/git-svn"
+SVN_TREE="$GIT_SVN_DIR/svn-tree"
 
 svn >/dev/null 2>&1
 if test $? -ne 1
@@ -19,7 +19,7 @@ then
     exit
 fi
 
-svnrepo=$PWD/svnrepo
+svnrepo="$PWD/svnrepo"
 
 perl -w -e "
 use SVN::Core;
diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 27b54cb..e6fa7de 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -305,7 +305,7 @@ test_expect_success 'absolute path works as expected' '
 	file="$dir"/index &&
 	test "$file" = "$(test-absolute-path $dir2/index)" &&
 	basename=blub &&
-	test "$dir/$basename" = $(cd .git && test-absolute-path $basename) &&
+	test "$dir/$basename" = "$(cd .git && test-absolute-path $basename)" &&
 	ln -s ../first/file .git/syml &&
 	sym="$(cd first; pwd -P)"/file &&
 	test "$sym" = "$(test-absolute-path $dir2/syml)"
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index b9cef34..5ed7fa4 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -21,7 +21,7 @@ LF='
 '
 
 test_expect_success 'update-index and ls-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git update-index --add one &&
 	case "`git ls-files`" in
 	one) echo ok one ;;
@@ -41,7 +41,7 @@ test_expect_success 'update-index and ls-files' '
 '
 
 test_expect_success 'cat-file' '
-	cd $HERE &&
+	cd "$HERE" &&
 	two=`git ls-files -s dir/two` &&
 	two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
 	echo "$two" &&
@@ -54,7 +54,7 @@ test_expect_success 'cat-file' '
 rm -f actual dir/actual
 
 test_expect_success 'diff-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	echo a >>one &&
 	echo d >>dir/two &&
 	case "`git diff-files --name-only`" in
@@ -74,7 +74,7 @@ test_expect_success 'diff-files' '
 '
 
 test_expect_success 'write-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	top=`git write-tree` &&
 	echo $top &&
 	cd dir &&
@@ -84,7 +84,7 @@ test_expect_success 'write-tree' '
 '
 
 test_expect_success 'checkout-index' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git checkout-index -f -u one &&
 	cmp one original.one &&
 	cd dir &&
@@ -93,7 +93,7 @@ test_expect_success 'checkout-index' '
 '
 
 test_expect_success 'read-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -f one dir/two &&
 	tree=`git write-tree` &&
 	git read-tree --reset -u "$tree" &&
@@ -107,27 +107,27 @@ test_expect_success 'read-tree' '
 '
 
 test_expect_success 'no file/rev ambiguity check inside .git' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git commit -a -m 1 &&
-	cd $HERE/.git &&
+	cd "$HERE/.git" &&
 	git show -s HEAD
 '
 
 test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && GIT_DIR=. git show -s HEAD
 '
 
 # This still does not work as it should...
 : test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && git show -s HEAD
 '
 
 test_expect_success 'detection should not be fooled by a symlink' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -fr foo.git &&
 	git clone -s .git another &&
 	ln -s another yetanother &&
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 2b21b10..4261e96 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -20,7 +20,7 @@ test_expect_success setup '
 '
 
 test_expect_success clone '
-	git clone file://`pwd`/.git cloned &&
+	git clone "file://$(pwd)/.git" cloned &&
 	(git rev-parse HEAD; git ls-files -s) >expected &&
 	(
 		cd cloned &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 9cf873f..e619a29 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -174,7 +174,7 @@ test_expect_success 'squash' '
 	test_tick &&
 	GIT_AUTHOR_NAME="Nitfol" git commit -m "nitfol" file7 &&
 	echo "******************************" &&
-	FAKE_LINES="1 squash 2" git rebase -i --onto master HEAD~2 &&
+	FAKE_LINES="1 squash 2" git rebase -v -i --onto master HEAD~2 &&
 	test B = $(cat file7) &&
 	test $(git rev-parse HEAD^) = $(git rev-parse master)
 '
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 788b4a5..c52707b 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -129,7 +129,7 @@ pull_to_client 2nd "B" $((64*3))
 
 pull_to_client 3rd "A" $((1*3)) # old fails
 
-test_expect_success "clone shallow" "git-clone --depth 2 file://`pwd`/. shallow"
+test_expect_success "clone shallow" 'git-clone --depth 2 "file://$(pwd)/." shallow'
 
 (cd shallow; git count-objects -v) > count.shallow
 
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index c0dc949..e3df3ed 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -17,7 +17,7 @@ test_expect_success setup '
 		git show-ref -d	| sed -e "s/ /	/"
 	) >expected.all &&
 
-	git remote add self $(pwd)/.git
+	git remote add self "$(pwd)"/.git
 
 '
 
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 6d7e738..a86042e 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -4,7 +4,7 @@ test_description='fetching and pushing, with or without wildcard'
 
 . ./test-lib.sh
 
-D=`pwd`
+D=$(pwd)
 
 mk_empty () {
 	rm -fr testrepo &&
@@ -103,9 +103,9 @@ test_expect_success 'fetch with wildcard' '
 test_expect_success 'fetch with insteadOf' '
 	mk_empty &&
 	(
-		TRASH=$(pwd)/ &&
+		TRASH="$(pwd)"/ &&
 		cd testrepo &&
-		git config url.$TRASH.insteadOf trash/
+		git config url."$TRASH".insteadOf trash/
 		git config remote.up.url trash/. &&
 		git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" &&
 		git fetch up &&
@@ -145,8 +145,8 @@ test_expect_success 'push with wildcard' '
 
 test_expect_success 'push with insteadOf' '
 	mk_empty &&
-	TRASH=$(pwd)/ &&
-	git config url.$TRASH.insteadOf trash/ &&
+	TRASH="$(pwd)"/ &&
+	git config url."$TRASH".insteadOf trash/ &&
 	git push trash/testrepo refs/heads/master:refs/remotes/origin/master &&
 	(
 		cd testrepo &&
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index b6a5486..b6905c1 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -6,7 +6,7 @@
 test_description='test clone --reference'
 . ./test-lib.sh
 
-base_dir=`pwd`
+base_dir="$(pwd)"
 
 test_expect_success 'preparing first repository' \
 'test_create_repo A && cd A &&
@@ -51,7 +51,7 @@ diff expected current'
 cd "$base_dir"
 
 test_expect_success 'cloning with reference (no -l -s)' \
-'git clone --reference B file://`pwd`/A D'
+'git clone --reference B file://"$(pwd)"/A D'
 
 cd "$base_dir"
 
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index efd658a..5863cc2 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -123,9 +123,9 @@ test_expect_success 'use index-filter to move into a subdirectory' '
 	git branch directorymoved &&
 	git-filter-branch -f --index-filter \
 		 "git ls-files -s | sed \"s-\\t-&newsubdir/-\" |
-	          GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
+	          GIT_INDEX_FILE=\"\$GIT_INDEX_FILE\".new \
 			git update-index --index-info &&
-		  mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
+		  mv \"\$GIT_INDEX_FILE\".new \"\$GIT_INDEX_FILE\"" directorymoved &&
 	test -z "$(git diff HEAD directorymoved:newsubdir)"'
 
 test_expect_success 'stops when msg filter fails' '
diff --git a/t/t7005-editor.sh b/t/t7005-editor.sh
index 2d919d6..2bf6a55 100755
--- a/t/t7005-editor.sh
+++ b/t/t7005-editor.sh
@@ -92,7 +92,7 @@ test_expect_success 'editor with a space' '
 	if echo "echo space > \"\$1\"" > "e space.sh"
 	then
 		chmod a+x "e space.sh" &&
-		GIT_EDITOR="./e\ space.sh" git commit --amend &&
+		GIT_EDITOR="./e space.sh" git commit --amend &&
 		test space = "$(git show -s --pretty=format:%s)"
 	else
 		say "Skipping; FS does not support spaces in filenames"
@@ -105,7 +105,7 @@ test_expect_success 'core.editor with a space' '
 
 	if test -f "e space.sh"
 	then
-		git config core.editor \"./e\ space.sh\" &&
+		git config core.editor "./e space.sh" &&
 		git commit --amend &&
 		test space = "$(git show -s --pretty=format:%s)"
 	else
diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh
index 02cf7c5..d8a7c79 100755
--- a/t/t7010-setup.sh
+++ b/t/t7010-setup.sh
@@ -122,7 +122,7 @@ test_expect_success 'commit using absolute path names' '
 
 test_expect_success 'log using absolute path names' '
 	echo bb >>a/b/c/d &&
-	git commit -m "bb" $(pwd)/a/b/c/d &&
+	git commit -m "bb" "$(pwd)/a/b/c/d" &&
 
 	git log a/b/c/d >f1.txt &&
 	git log "$(pwd)/a/b/c/d" >f2.txt &&
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index a50492f..4c9701f 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -112,7 +112,7 @@ test_expect_success 'git-clean with absolute path' '
 	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
 	would_clean=$(
 		cd docs &&
-		git clean -n $(pwd)/../src |
+		git clean -n "$(pwd)"/../src |
 		sed -n -e "s|^Would remove ||p"
 	) &&
 	test "$would_clean" = ../src/part3.c || {
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index c0288f3..4e5418a 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -79,8 +79,8 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -e "s/a file/an amend commit/g" < $1 > $1-
-mv $1- $1
+sed -e "s/a file/an amend commit/g" < "$1" > "$1"-
+mv "$1"- "$1"
 EOF
 chmod 755 editor
 
@@ -99,8 +99,8 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -e "s/amend/older/g"  < $1 > $1-
-mv $1- $1
+sed -e "s/amend/older/g"  < "$1" > "$1"-
+mv "$1"- "$1"
 EOF
 chmod 755 editor
 
diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh
index c0973b4..5047708 100755
--- a/t/t9001-send-email.sh
+++ b/t/t9001-send-email.sh
@@ -32,7 +32,7 @@ clean_fake_sendmail() {
 }
 
 test_expect_success 'Extract patches' '
-    patches=`git format-patch -n HEAD^1`
+    patches=$(git format-patch -n HEAD^1)
 '
 
 test_expect_success 'Send patches' '
@@ -147,7 +147,7 @@ test_expect_success 'setup fake editor' '
 test_expect_success '--compose works' '
 	clean_fake_sendmail &&
 	echo y | \
-		GIT_EDITOR=$(pwd)/fake-editor \
+		GIT_EDITOR="$(pwd)/fake-editor" \
 		GIT_SEND_EMAIL_NOTTY=1 \
 		git send-email \
 		--compose --subject foo \
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 4e24ab3..8f93821 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -20,27 +20,27 @@ esac
 echo 'define NO_SVN_TESTS to skip git-svn tests'
 
 test_expect_success \
-    'initialize git-svn' "
+    'initialize git-svn' '
 	mkdir import &&
 	cd import &&
 	echo foo > foo &&
 	ln -s foo foo.link
 	mkdir -p dir/a/b/c/d/e &&
-	echo 'deep dir' > dir/a/b/c/d/e/file &&
+	echo "deep dir" > dir/a/b/c/d/e/file &&
 	mkdir bar &&
-	echo 'zzz' > bar/zzz &&
-	echo '#!/bin/sh' > exec.sh &&
+	echo "zzz" > bar/zzz &&
+	echo "#!/bin/sh" > exec.sh &&
 	chmod +x exec.sh &&
-	svn import -m 'import for git-svn' . $svnrepo >/dev/null &&
+	svn import -m "import for git-svn" . "$svnrepo" >/dev/null &&
 	cd .. &&
 	rm -rf import &&
-	git-svn init $svnrepo"
+	git-svn init "$svnrepo"'
 
 test_expect_success \
     'import an SVN revision into git' \
     'git-svn fetch'
 
-test_expect_success "checkout from svn" "svn co $svnrepo '$SVN_TREE'"
+test_expect_success "checkout from svn" "svn co '$svnrepo' '$SVN_TREE'"
 
 name='try a deep --rmdir with a commit'
 test_expect_success "$name" "
@@ -169,7 +169,7 @@ test_expect_success "$name" "
 	svn up '$SVN_TREE' &&
 	test -f '$SVN_TREE'/exec-2.sh &&
 	test ! -L '$SVN_TREE'/exec-2.sh &&
-	git diff help $SVN_TREE/exec-2.sh"
+	git diff help '$SVN_TREE'/exec-2.sh"
 
 if test "$have_utf8" = t
 then
@@ -190,7 +190,7 @@ name='test fetch functionality (svn => git) with alternate GIT_SVN_ID'
 GIT_SVN_ID=alt
 export GIT_SVN_ID
 test_expect_success "$name" \
-    "git-svn init $svnrepo && git-svn fetch &&
+    "git-svn init '$svnrepo' && git-svn fetch &&
      git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a &&
      git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
      git diff a b"
@@ -220,16 +220,16 @@ test_expect_success 'exit if remote refs are ambigious' "
 "
 
 test_expect_success 'exit if init-ing a would clobber a URL' "
-        svnadmin create ${PWD}/svnrepo2 &&
-        svn mkdir -m 'mkdir bar' ${svnrepo}2/bar &&
+        svnadmin create '${PWD}/svnrepo2' &&
+        svn mkdir -m 'mkdir bar' '${svnrepo}2/bar' &&
         git config --unset svn-remote.svn.fetch \
                                 '^bar:refs/remotes/git-svn$' &&
-	! git-svn init ${svnrepo}2/bar
+	! git-svn init '${svnrepo}2/bar'
         "
 
 test_expect_success \
   'init allows us to connect to another directory in the same repo' "
-        git-svn init --minimize-url -i bar $svnrepo/bar &&
+        git-svn init --minimize-url -i bar '$svnrepo/bar' &&
         git config --get svn-remote.svn.fetch \
                               '^bar:refs/remotes/bar$' &&
         git config --get svn-remote.svn.fetch \
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index d7a7047..2616df6 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -52,7 +52,7 @@ EOF
 cd ..
 
 rm -rf import
-test_expect_success 'checkout working copy from svn' "svn co $svnrepo test_wc"
+test_expect_success 'checkout working copy from svn' "svn co '$svnrepo' test_wc"
 test_expect_success 'setup some commits to svn' \
 	'cd test_wc &&
 		echo Greetings >> kw.c &&
@@ -66,7 +66,7 @@ test_expect_success 'setup some commits to svn' \
 		svn commit -m "Propset Id" &&
 	cd ..'
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init '$svnrepo'"
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 
 name='test svn:keywords ignoring'
@@ -92,7 +92,7 @@ test_expect_success "propset CR on crlf files" \
 test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
 	"git-svn fetch &&
 	 git pull . remotes/git-svn &&
-	 svn co $svnrepo new_wc"
+	 svn co '$svnrepo' new_wc"
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh
index 4e08083..99c8840 100755
--- a/t/t9102-git-svn-deep-rmdir.sh
+++ b/t/t9102-git-svn-deep-rmdir.sh
@@ -9,12 +9,12 @@ test_expect_success 'initialize repo' "
 	mkdir -p deeply/nested/directory/number/2 &&
 	echo foo > deeply/nested/directory/number/1/file &&
 	echo foo > deeply/nested/directory/number/2/another &&
-	svn import -m 'import for git-svn' . $svnrepo &&
+	svn import -m 'import for git-svn' . '$svnrepo' &&
 	cd ..
 	"
 
 test_expect_success 'mirror via git-svn' "
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
 	git checkout -f -b test-rmdir remotes/git-svn
 	"
@@ -23,7 +23,7 @@ test_expect_success 'Try a commit on rmdir' "
 	git rm -f deeply/nested/directory/number/2/another &&
 	git commit -a -m 'remove another' &&
 	git-svn set-tree --rmdir HEAD &&
-	svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1
+	svn ls -R '$svnrepo' | grep ^deeply/nested/directory/number/1
 	"
 
 
diff --git a/t/t9103-git-svn-tracked-directory-removed.sh b/t/t9103-git-svn-tracked-directory-removed.sh
index 0f0b0fd..a85050a 100755
--- a/t/t9103-git-svn-tracked-directory-removed.sh
+++ b/t/t9103-git-svn-tracked-directory-removed.sh
@@ -10,19 +10,19 @@ test_expect_success 'make history for tracking' '
 	mkdir import &&
 	mkdir import/trunk &&
 	echo hello >> import/trunk/README &&
-	svn import -m initial import $svnrepo &&
+	svn import -m initial import "$svnrepo" &&
 	rm -rf import &&
-	svn co $svnrepo/trunk trunk &&
+	svn co "$svnrepo/trunk" trunk &&
 	echo bye bye >> trunk/README &&
-	svn rm -m "gone" $svnrepo/trunk &&
+	svn rm -m "gone" "$svnrepo/trunk" &&
 	rm -rf trunk &&
 	mkdir trunk &&
 	echo "new" > trunk/FOLLOWME &&
-	svn import -m "new trunk" trunk $svnrepo/trunk
+	svn import -m "new trunk" trunk "$svnrepo/trunk"
 '
 
 test_expect_success 'clone repo with git' '
-	git svn clone -s $svnrepo x &&
+	git svn clone -s "$svnrepo" x &&
 	test -f x/FOLLOWME &&
 	test ! -f x/README
 '
diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 7ba7630..499d9e6 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -11,9 +11,9 @@ test_expect_success 'initialize repo' "
 	cd import &&
 	mkdir -p trunk &&
 	echo hello > trunk/readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
-	svn co $svnrepo wc &&
+	svn co '$svnrepo' wc &&
 	cd wc &&
 	echo world >> trunk/readme &&
 	poke trunk/readme &&
@@ -27,7 +27,7 @@ test_expect_success 'initialize repo' "
 	"
 
 test_expect_success 'init and fetch a moved directory' "
-	git-svn init --minimize-url -i thunk $svnrepo/thunk &&
+	git-svn init --minimize-url -i thunk '$svnrepo/thunk' &&
 	git-svn fetch -i thunk &&
 	test \"\`git rev-parse --verify refs/remotes/thunk@2\`\" \
            = \"\`git rev-parse --verify refs/remotes/thunk~1\`\" &&
@@ -38,7 +38,7 @@ test_expect_success 'init and fetch a moved directory' "
 	"
 
 test_expect_success 'init and fetch from one svn-remote' "
-        git config svn-remote.svn.url $svnrepo &&
+        git config svn-remote.svn.url '$svnrepo' &&
         git config --add svn-remote.svn.fetch \
           trunk:refs/remotes/svn/trunk &&
         git config --add svn-remote.svn.fetch \
@@ -52,9 +52,9 @@ test_expect_success 'init and fetch from one svn-remote' "
 
 test_expect_success 'follow deleted parent' "
         (svn cp -m 'resurrecting trunk as junk' \
-               $svnrepo/trunk@2 $svnrepo/junk ||
+               '$svnrepo/trunk@2' '$svnrepo/junk' ||
          svn cp -m 'resurrecting trunk as junk' \
-               -r2 $svnrepo/trunk $svnrepo/junk) &&
+               -r2 '$svnrepo/trunk' '$svnrepo/junk') &&
         git config --add svn-remote.svn.fetch \
           junk:refs/remotes/svn/junk &&
         git-svn fetch -i svn/thunk &&
@@ -67,10 +67,10 @@ test_expect_success 'follow deleted parent' "
 test_expect_success 'follow larger parent' "
         mkdir -p import/trunk/thunk/bump/thud &&
         echo hi > import/trunk/thunk/bump/thud/file &&
-        svn import -m 'import a larger parent' import $svnrepo/larger-parent &&
-        svn cp -m 'hi' $svnrepo/larger-parent $svnrepo/another-larger &&
+        svn import -m 'import a larger parent' import '$svnrepo/larger-parent' &&
+        svn cp -m 'hi' '$svnrepo/larger-parent' '$svnrepo/another-larger' &&
         git-svn init --minimize-url -i larger \
-          $svnrepo/another-larger/trunk/thunk/bump/thud &&
+          '$svnrepo/another-larger/trunk/thunk/bump/thud' &&
         git-svn fetch -i larger &&
         git rev-parse --verify refs/remotes/larger &&
         git rev-parse --verify \
@@ -83,23 +83,23 @@ test_expect_success 'follow larger parent' "
         "
 
 test_expect_success 'follow higher-level parent' "
-        svn mkdir -m 'follow higher-level parent' $svnrepo/blob &&
-        svn co $svnrepo/blob blob &&
+        svn mkdir -m 'follow higher-level parent' '$svnrepo/blob' &&
+        svn co '$svnrepo/blob' blob &&
         cd blob &&
                 echo hi > hi &&
                 svn add hi &&
                 svn commit -m 'hihi' &&
                 cd ..
-        svn mkdir -m 'new glob at top level' $svnrepo/glob &&
-        svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
-        git-svn init --minimize-url -i blob $svnrepo/glob/blob &&
+        svn mkdir -m 'new glob at top level' '$svnrepo/glob' &&
+        svn mv -m 'move blob down a level' '$svnrepo/blob' '$svnrepo/glob/blob' &&
+        git-svn init --minimize-url -i blob '$svnrepo/glob/blob' &&
         git-svn fetch -i blob
         "
 
 test_expect_success 'follow deleted directory' "
-	svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye &&
-	svn rm -m 'remove glob' $svnrepo/glob &&
-	git-svn init --minimize-url -i glob $svnrepo/glob &&
+	svn mv -m 'bye!' '$svnrepo/glob/blob/hi' '$svnrepo/glob/blob/bye' &&
+	svn rm -m 'remove glob' '$svnrepo/glob' &&
+	git-svn init --minimize-url -i glob '$svnrepo/glob' &&
 	git-svn fetch -i glob &&
 	test \"\`git cat-file blob refs/remotes/glob:blob/bye\`\" = hi &&
 	test \"\`git ls-tree refs/remotes/glob | wc -l \`\" -eq 1
@@ -118,9 +118,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  echo 'bad delete test 2' > \
 	   import/trunk/subversion/bindings/swig/perl/another-larger &&
 	cd import &&
-	  svn import -m 'r9270 test' . $svnrepo/r9270 &&
+	  svn import -m 'r9270 test' . '$svnrepo/r9270' &&
 	cd .. &&
-	svn co $svnrepo/r9270/trunk/subversion/bindings/swig/perl r9270 &&
+	svn co '$svnrepo/r9270/trunk/subversion/bindings/swig/perl' r9270 &&
 	cd r9270 &&
 	  svn mkdir native &&
 	  svn mv t native/t &&
@@ -130,7 +130,7 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	  svn commit -m 'reorg test' &&
 	cd .. &&
 	git-svn init --minimize-url -i r9270-t \
-	  $svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t &&
+	  '$svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t' &&
 	git-svn fetch -i r9270-t &&
 	test \`git rev-list r9270-t | wc -l\` -eq 2 &&
 	test \"\`git ls-tree --name-only r9270-t~1\`\" = \
@@ -138,9 +138,9 @@ test_expect_success 'follow-parent avoids deleting relevant info' "
 	"
 
 test_expect_success "track initial change if it was only made to parent" "
-	svn cp -m 'wheee!' $svnrepo/r9270/trunk $svnrepo/r9270/drunk &&
+	svn cp -m 'wheee!' '$svnrepo/r9270/trunk' '$svnrepo/r9270/drunk' &&
 	git-svn init --minimize-url -i r9270-d \
-	  $svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t &&
+	  '$svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t' &&
 	git-svn fetch -i r9270-d &&
 	test \`git rev-list r9270-d | wc -l\` -eq 3 &&
 	test \"\`git ls-tree --name-only r9270-t\`\" = \
@@ -150,7 +150,7 @@ test_expect_success "track initial change if it was only made to parent" "
 	"
 
 test_expect_success "track multi-parent paths" "
-	svn cp -m 'resurrect /glob' $svnrepo/r9270 $svnrepo/glob &&
+	svn cp -m 'resurrect /glob' '$svnrepo/r9270' '$svnrepo/glob' &&
 	git-svn multi-fetch &&
 	test \`git cat-file commit refs/remotes/glob | \
 	       grep '^parent ' | wc -l\` -eq 2
@@ -161,8 +161,8 @@ test_expect_success "multi-fetch continues to work" "
 	"
 
 test_expect_success "multi-fetch works off a 'clean' repository" "
-	rm -r $GIT_DIR/svn $GIT_DIR/refs/remotes $GIT_DIR/logs &&
-	mkdir $GIT_DIR/svn &&
+	rm -r '$GIT_DIR/svn' '$GIT_DIR/refs/remotes' '$GIT_DIR/logs' &&
+	mkdir '$GIT_DIR/svn' &&
 	git-svn multi-fetch
 	"
 
diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh
index 318e172..2e1eb75 100755
--- a/t/t9105-git-svn-commit-diff.sh
+++ b/t/t9105-git-svn-commit-diff.sh
@@ -8,7 +8,7 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo hello > readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
 	echo hello > readme &&
 	git update-index --add readme &&
@@ -27,16 +27,16 @@ prev=`git rev-parse --verify HEAD^1`
 test_expect_success 'test the commit-diff command' "
 	test -n '$prev' && test -n '$head' &&
 	git-svn commit-diff -r1 '$prev' '$head' '$svnrepo' &&
-	svn co $svnrepo wc &&
+	svn co '$svnrepo' wc &&
 	cmp readme wc/readme
 	"
 
 test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
-	svn import -m 'sub-directory' import $svnrepo/subdir &&
-	git-svn init --minimize-url $svnrepo/subdir &&
+	svn import -m 'sub-directory' import '$svnrepo/subdir' &&
+	git-svn init --minimize-url '$svnrepo/subdir' &&
 	git-svn fetch &&
 	git-svn commit-diff -r3 '$prev' '$head' &&
-	svn cat $svnrepo/subdir/readme > readme.2 &&
+	svn cat '$svnrepo/subdir/readme' > readme.2 &&
 	cmp readme readme.2
 	"
 
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index f74ab12..5125ed0 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -8,14 +8,14 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	echo initial > file &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
 	echo initial > file &&
 	git update-index --add file &&
 	git commit -a -m 'initial'
 	"
 test_expect_success 'commit change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 	echo second line from svn >> file &&
 	poke file &&
@@ -27,7 +27,7 @@ test_expect_success 'commit change from svn side' "
 test_expect_success 'commit conflicting change from git' "
 	echo second line from git >> file &&
 	git commit -a -m 'second line from git' &&
-	! git-svn commit-diff -r1 HEAD~1 HEAD $svnrepo
+	! git-svn commit-diff -r1 HEAD~1 HEAD '$svnrepo'
 "
 
 test_expect_success 'commit complementing change from git' "
@@ -36,14 +36,14 @@ test_expect_success 'commit complementing change from git' "
 	git commit -a -m 'second line from svn' &&
 	echo third line from git >> file &&
 	git commit -a -m 'third line from git' &&
-	git-svn commit-diff -r2 HEAD~1 HEAD $svnrepo
+	git-svn commit-diff -r2 HEAD~1 HEAD '$svnrepo'
 	"
 
 test_expect_success 'dcommit fails to commit because of conflict' "
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
 	git reset --hard refs/remotes/git-svn &&
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 	echo fourth line from svn >> file &&
 	poke file &&
@@ -67,7 +67,7 @@ test_expect_success 'dcommit does the svn equivalent of an index merge' "
 	"
 
 test_expect_success 'commit another change from svn side' "
-	svn co $svnrepo t.svn &&
+	svn co '$svnrepo' t.svn &&
 	cd t.svn &&
 		echo third line from svn >> file &&
 		poke file &&
diff --git a/t/t9106-git-svn-dcommit-clobber-series.sh b/t/t9106-git-svn-dcommit-clobber-series.sh
index ca8a00e..fb4b67a 100755
--- a/t/t9106-git-svn-dcommit-clobber-series.sh
+++ b/t/t9106-git-svn-dcommit-clobber-series.sh
@@ -8,9 +8,9 @@ test_expect_success 'initialize repo' "
 	mkdir import &&
 	cd import &&
 	awk 'BEGIN { for (i = 1; i < 64; i++) { print i } }' > file
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m 'initial' . '$svnrepo' &&
 	cd .. &&
-	git svn init $svnrepo &&
+	git svn init '$svnrepo' &&
 	git svn fetch &&
 	test -e file
 	"
@@ -18,7 +18,7 @@ test_expect_success 'initialize repo' "
 test_expect_success '(supposedly) non-conflicting change from SVN' "
 	test x\"\`sed -n -e 58p < file\`\" = x58 &&
 	test x\"\`sed -n -e 61p < file\`\" = x61 &&
-	svn co $svnrepo tmp &&
+	svn co '$svnrepo' tmp &&
 	cd tmp &&
 		perl -i -p -e 's/^58\$/5588/' file &&
 		perl -i -p -e 's/^61\$/6611/' file &&
diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index 0a41d52..545a08a 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -4,7 +4,7 @@ test_description='git-svn metadata migrations from previous versions'
 . ./lib-git-svn.sh
 
 test_expect_success 'setup old-looking metadata' "
-	cp $GIT_DIR/config $GIT_DIR/config-old-git-svn &&
+	cp '$GIT_DIR/config' '$GIT_DIR/config-old-git-svn' &&
 	mkdir import &&
 	cd import &&
 		for i in trunk branches/a branches/b \
@@ -12,13 +12,13 @@ test_expect_success 'setup old-looking metadata' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . '$svnrepo'
 		cd .. &&
-	git-svn init $svnrepo &&
+	git-svn init '$svnrepo' &&
 	git-svn fetch &&
-	mv $GIT_DIR/svn/* $GIT_DIR/ &&
-	mv $GIT_DIR/svn/.metadata $GIT_DIR/ &&
-	rmdir $GIT_DIR/svn &&
+	mv '$GIT_DIR/svn/'* '$GIT_DIR/' &&
+	mv '$GIT_DIR/svn/.metadata' '$GIT_DIR/' &&
+	rmdir '$GIT_DIR/svn' &&
 	git update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn &&
 	git update-ref refs/heads/svn-HEAD refs/remotes/git-svn &&
 	git update-ref -d refs/remotes/git-svn refs/remotes/git-svn
@@ -28,20 +28,20 @@ head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
 test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
 
 test_expect_success 'initialize old-style (v0) git-svn layout' "
-	mkdir -p $GIT_DIR/git-svn/info $GIT_DIR/svn/info &&
-	echo $svnrepo > $GIT_DIR/git-svn/info/url &&
-	echo $svnrepo > $GIT_DIR/svn/info/url &&
+	mkdir -p '$GIT_DIR/git-svn/info' '$GIT_DIR/svn/info' &&
+	echo '$svnrepo' > '$GIT_DIR/git-svn/info/url' &&
+	echo '$svnrepo' > '$GIT_DIR/svn/info/url' &&
 	git-svn migrate &&
-	! test -d $GIT_DIR/git-svn &&
+	! test -d '$GIT_DIR/git-svn' &&
 	git rev-parse --verify refs/remotes/git-svn^0 &&
 	git rev-parse --verify refs/remotes/svn^0 &&
-	test \`git config --get svn-remote.svn.url\` = '$svnrepo' &&
-	test \`git config --get svn-remote.svn.fetch\` = \
+	test '$(git config --get svn-remote.svn.url)' = '$svnrepo' &&
+	test '$(git config --get svn-remote.svn.fetch)' = \
              ':refs/remotes/git-svn'
 	"
 
 test_expect_success 'initialize a multi-repository repo' "
-	git-svn init $svnrepo -T trunk -t tags -b branches &&
+	git-svn init '$svnrepo' -T trunk -t tags -b branches &&
 	git config --get-all svn-remote.svn.fetch > fetch.out &&
 	grep '^trunk:refs/remotes/trunk$' fetch.out &&
 	test -n \"\`git config --get svn-remote.svn.branches \
@@ -76,14 +76,14 @@ test_expect_success 'multi-fetch works on partial urls + paths' "
 test_expect_success 'migrate --minimize on old inited layout' "
 	git config --unset-all svn-remote.svn.fetch &&
 	git config --unset-all svn-remote.svn.url &&
-	rm -rf $GIT_DIR/svn &&
+	rm -rf '$GIT_DIR/svn' &&
 	for i in \`cat fetch.out\`; do
 		path=\`expr \$i : '\\([^:]*\\):.*$'\`
 		ref=\`expr \$i : '[^:]*:refs/remotes/\\(.*\\)$'\`
 		if test -z \"\$ref\"; then continue; fi
 		if test -n \"\$path\"; then path=\"/\$path\"; fi
-		( mkdir -p $GIT_DIR/svn/\$ref/info/ &&
-		echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
+		( mkdir -p '$GIT_DIR'/svn/\$ref/info/ &&
+		echo '$svnrepo'\$path > '$GIT_DIR'/svn/\$ref/info/url ) || exit 1;
 	done &&
 	git-svn migrate --minimize &&
 	test -z \"\`git config -l |grep -v '^svn-remote\.git-svn\.'\`\" &&
@@ -99,17 +99,17 @@ test_expect_success 'migrate --minimize on old inited layout' "
 
 test_expect_success  ".rev_db auto-converted to .rev_map.UUID" "
 	git-svn fetch -i trunk &&
-	test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
-	expect=\"\$(ls $GIT_DIR/svn/trunk/.rev_map.*)\" &&
+	test -z \"\$(ls '$GIT_DIR'/svn/trunk/.rev_db.* 2>/dev/null)\" &&
+	expect=\"\$(ls '$GIT_DIR'/svn/trunk/.rev_map.*)\" &&
 	test -n \"\$expect\" &&
 	rev_db=\$(echo \$expect | sed -e 's,_map,_db,') &&
-	convert_to_rev_db \$expect \$rev_db &&
-	rm -f \$expect &&
-	test -f \$rev_db &&
+	convert_to_rev_db \"\$expect\" \"\$rev_db\" &&j
+	rm -f \"\$expect\" &&
+	test -f \"\$rev_db\" &&
 	git-svn fetch -i trunk &&
-	test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
-	test ! -e $GIT_DIR/svn/trunk/.rev_db &&
-	test -f \$expect
+	test -z \"\$(ls '$GIT_DIR'/svn/trunk/.rev_db.* 2>/dev/null)\" &&
+	test ! -e '$GIT_DIR'/svn/trunk/.rev_db &&
+	test -f \"\$expect\"
 	"
 
 test_done
diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh
index db4344c..c6dc0ef 100755
--- a/t/t9108-git-svn-glob.sh
+++ b/t/t9108-git-svn-glob.sh
@@ -14,8 +14,8 @@ test_expect_success 'test refspec globbing' "
 	mkdir -p trunk/src/a trunk/src/b trunk/doc &&
 	echo 'hello world' > trunk/src/a/readme &&
 	echo 'goodbye world' > trunk/src/b/readme &&
-	svn import -m 'initial' trunk $svnrepo/trunk &&
-	svn co $svnrepo tmp &&
+	svn import -m 'initial' trunk '$svnrepo/trunk' &&
+	svn co '$svnrepo' tmp &&
 	cd tmp &&
 		mkdir branches tags &&
 		svn add branches tags &&
@@ -38,7 +38,7 @@ test_expect_success 'test refspec globbing' "
 		poke tags/end/src/b/readme &&
 		svn commit -m 'nothing to see here'
 		cd .. &&
-	git config --add svn-remote.svn.url $svnrepo &&
+	git config --add svn-remote.svn.url '$svnrepo' &&
 	git config --add svn-remote.svn.fetch \
 	                 'trunk/src/a:refs/remotes/trunk' &&
 	git config --add svn-remote.svn.branches \
@@ -60,7 +60,7 @@ echo nothing to see here >> expect.two
 cat expect.end >> expect.two
 
 test_expect_success 'test left-hand-side only globbing' "
-	git config --add svn-remote.two.url $svnrepo &&
+	git config --add svn-remote.two.url '$svnrepo' &&
 	git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
 	git config --add svn-remote.two.branches \
 	                 'branches/*:refs/remotes/two/branches/*' &&
diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh
index 6235af4..d4ab01f 100755
--- a/t/t9110-git-svn-use-svm-props.sh
+++ b/t/t9110-git-svn-use-svm-props.sh
@@ -8,11 +8,11 @@ test_description='git-svn useSvmProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svm repo' "
-	svnadmin load -q $rawsvnrepo < ../t9110/svm.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/mirror/arr &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/mirror/argh &&
+	svnadmin load -q '$rawsvnrepo' < ../t9110/svm.dump &&
+	git-svn init --minimize-url -R arr -i bar '$svnrepo/mirror/arr' &&
+	git-svn init --minimize-url -R argh -i dir '$svnrepo/mirror/argh' &&
 	git-svn init --minimize-url -R argh -i e \
-	  $svnrepo/mirror/argh/a/b/c/d/e &&
+	  '$svnrepo/mirror/argh/a/b/c/d/e' &&
 	git config svn.useSvmProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9111-git-svn-use-svnsync-props.sh b/t/t9111-git-svn-use-svnsync-props.sh
index ec7dedd..936f023 100755
--- a/t/t9111-git-svn-use-svnsync-props.sh
+++ b/t/t9111-git-svn-use-svnsync-props.sh
@@ -8,10 +8,10 @@ test_description='git-svn useSvnsyncProps test'
 . ./lib-git-svn.sh
 
 test_expect_success 'load svnsync repo' "
-	svnadmin load -q $rawsvnrepo < ../t9111/svnsync.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/bar &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/dir &&
-	git-svn init --minimize-url -R argh -i e $svnrepo/dir/a/b/c/d/e &&
+	svnadmin load -q '$rawsvnrepo' < ../t9111/svnsync.dump &&
+	git-svn init --minimize-url -R arr -i bar '$svnrepo/bar' &&
+	git-svn init --minimize-url -R argh -i dir '$svnrepo/dir' &&
+	git-svn init --minimize-url -R argh -i e '$svnrepo/dir/a/b/c/d/e' &&
 	git config svn.useSvnsyncProps true &&
 	git-svn fetch --all
 	"
diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh
index 646a5f0..d6a5a5b 100755
--- a/t/t9112-git-svn-md5less-file.sh
+++ b/t/t9112-git-svn-md5less-file.sh
@@ -40,8 +40,8 @@ PROPS-END
 
 EOF
 
-test_expect_success 'load svn dumpfile' "svnadmin load $rawsvnrepo < dumpfile.svn"
+test_expect_success 'load svn dumpfile' "svnadmin load '$rawsvnrepo' < dumpfile.svn"
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' "git-svn init '$svnrepo'"
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 test_done
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
index 9ef0db9..b84a21e 100755
--- a/t/t9113-git-svn-dcommit-new-file.sh
+++ b/t/t9113-git-svn-dcommit-new-file.sh
@@ -15,14 +15,14 @@ test_description='git-svn dcommit new files over svn:// test'
 
 start_svnserve () {
 	svnserve --listen-port $SVNSERVE_PORT \
-	         --root $rawsvnrepo \
+	         --root "$rawsvnrepo" \
 	         --listen-once \
 	         --listen-host 127.0.0.1 &
 }
 
 test_expect_success 'start tracking an empty repo' "
-	svn mkdir -m 'empty dir' $svnrepo/empty-dir &&
-	echo anon-access = write >> $rawsvnrepo/conf/svnserve.conf &&
+	svn mkdir -m 'empty dir' '$svnrepo/empty-dir' &&
+	echo 'anon-access = write' >> '$rawsvnrepo/conf/svnserve.conf' &&
 	start_svnserve &&
 	git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
 	git svn fetch
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
index 225060b..9d9e34c 100755
--- a/t/t9114-git-svn-dcommit-merge.sh
+++ b/t/t9114-git-svn-dcommit-merge.sh
@@ -35,7 +35,7 @@ EOF
 }
 
 test_expect_success 'setup svn repository' "
-	svn co $svnrepo mysvnwork &&
+	svn co '$svnrepo' mysvnwork &&
 	mkdir -p mysvnwork/trunk &&
 	cd mysvnwork &&
 		big_text_block >> trunk/README &&
@@ -45,7 +45,7 @@ test_expect_success 'setup svn repository' "
 	"
 
 test_expect_success 'setup git mirror and merge' "
-	git svn init $svnrepo -t tags -T trunk -b branches &&
+	git svn init '$svnrepo' -t tags -T trunk -b branches &&
 	git svn fetch &&
 	git checkout --track -b svn remotes/trunk &&
 	git checkout -b merge &&
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 182299c..653578d 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -8,12 +8,12 @@ test_description='git-svn dcommit can commit renames of files with ugly names'
 . ./lib-git-svn.sh
 
 test_expect_success 'load repository with strange names' "
-	svnadmin load -q $rawsvnrepo < ../t9115/funky-names.dump &&
+	svnadmin load -q '$rawsvnrepo' < ../t9115/funky-names.dump &&
 	start_httpd
 	"
 
 test_expect_success 'init and fetch repository' "
-	git svn init $svnrepo &&
+	git svn init '$svnrepo' &&
 	git svn fetch &&
 	git reset --hard git-svn
 	"
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index e1e8bdf..ab46903 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -14,9 +14,9 @@ test_expect_success 'setup repository and import' "
 			mkdir -p \$i && \
 			echo hello >> \$i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . '$svnrepo'
 		cd .. &&
-	git-svn init $svnrepo -T trunk -b branches -t tags &&
+	git-svn init '$svnrepo' -T trunk -b branches -t tags &&
 	git-svn fetch &&
 	git reset --hard trunk &&
 	echo bye >> README &&
diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh
index d482b40..aa1b167 100755
--- a/t/t9117-git-svn-init-clone.sh
+++ b/t/t9117-git-svn-init-clone.sh
@@ -16,13 +16,13 @@ cd tmp
 test_expect_success 'setup svnrepo' "
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project $svnrepo/project &&
+	svn import -m '$test_description' project '$svnrepo/project' &&
 	rm -rf project
 	"
 
 test_expect_success 'basic clone' "
 	test ! -d trunk &&
-	git svn clone $svnrepo/project/trunk &&
+	git svn clone '$svnrepo/project/trunk' &&
 	test -d trunk/.git/svn &&
 	test -e trunk/foo &&
 	rm -rf trunk
@@ -30,7 +30,7 @@ test_expect_success 'basic clone' "
 
 test_expect_success 'clone to target directory' "
 	test ! -d target &&
-	git svn clone $svnrepo/project/trunk target &&
+	git svn clone '$svnrepo/project/trunk' target &&
 	test -d target/.git/svn &&
 	test -e target/foo &&
 	rm -rf target
@@ -38,7 +38,7 @@ test_expect_success 'clone to target directory' "
 
 test_expect_success 'clone with --stdlayout' "
 	test ! -d project &&
-	git svn clone -s $svnrepo/project &&
+	git svn clone -s '$svnrepo/project' &&
 	test -d project/.git/svn &&
 	test -e project/foo &&
 	rm -rf project
@@ -46,7 +46,7 @@ test_expect_success 'clone with --stdlayout' "
 
 test_expect_success 'clone to target directory with --stdlayout' "
 	test ! -d target &&
-	git svn clone -s $svnrepo/project target &&
+	git svn clone -s '$svnrepo/project' target &&
 	test -d target/.git/svn &&
 	test -e target/foo &&
 	rm -rf target
diff --git a/t/t9121-git-svn-fetch-renamed-dir.sh b/t/t9121-git-svn-fetch-renamed-dir.sh
index 5143ed6..f6a5d64 100755
--- a/t/t9121-git-svn-fetch-renamed-dir.sh
+++ b/t/t9121-git-svn-fetch-renamed-dir.sh
@@ -8,11 +8,11 @@ test_description='git-svn can fetch renamed directories'
 . ./lib-git-svn.sh
 
 test_expect_success 'load repository with renamed directory' "
-	svnadmin load -q $rawsvnrepo < ../t9121/renamed-dir.dump
+	svnadmin load -q '$rawsvnrepo' < ../t9121/renamed-dir.dump
 	"
 
 test_expect_success 'init and fetch repository' "
-	git svn init $svnrepo/newname &&
+	git svn init '$svnrepo/newname' &&
 	git svn fetch
 	"
 
diff --git a/t/t9400-git-cvsserver-server.sh b/t/t9400-git-cvsserver-server.sh
index 166b43f..57cba8b 100755
--- a/t/t9400-git-cvsserver-server.sh
+++ b/t/t9400-git-cvsserver-server.sh
@@ -24,8 +24,8 @@ perl -e 'use DBI; use DBD::SQLite' >/dev/null 2>&1 || {
 }
 
 unset GIT_DIR GIT_CONFIG
-WORKDIR=$(pwd)
-SERVERDIR=$(pwd)/gitcvs.git
+WORKDIR="$(pwd)"
+SERVERDIR="$(pwd)/gitcvs.git"
 git_config="$SERVERDIR/config"
 CVSROOT=":fork:$SERVERDIR"
 CVSWORK="$(pwd)/cvswork"
@@ -153,21 +153,21 @@ test_expect_success 'req_Root failure (conflicting roots)' \
    tail log | grep "^error 1 Conflicting roots specified$"'
 
 test_expect_success 'req_Root (strict paths)' \
-  'cat request-anonymous | git-cvsserver --strict-paths pserver $SERVERDIR >log 2>&1 &&
+  'cat request-anonymous | git-cvsserver --strict-paths pserver "$SERVERDIR" >log 2>&1 &&
    sed -ne \$p log | grep "^I LOVE YOU$"'
 
 test_expect_success 'req_Root failure (strict-paths)' '
     ! cat request-anonymous |
-    git-cvsserver --strict-paths pserver $WORKDIR >log 2>&1
+    git-cvsserver --strict-paths pserver "$WORKDIR" >log 2>&1
 '
 
 test_expect_success 'req_Root (w/o strict-paths)' \
-  'cat request-anonymous | git-cvsserver pserver $WORKDIR/ >log 2>&1 &&
+  'cat request-anonymous | git-cvsserver pserver "$WORKDIR"/ >log 2>&1 &&
    sed -ne \$p log | grep "^I LOVE YOU$"'
 
 test_expect_success 'req_Root failure (w/o strict-paths)' '
     ! cat request-anonymous |
-    git-cvsserver pserver $WORKDIR/gitcvs >log 2>&1
+    git-cvsserver pserver "$WORKDIR"/gitcvs >log 2>&1
 '
 
 cat >request-base  <<EOF
@@ -180,25 +180,25 @@ Root /gitcvs.git
 EOF
 
 test_expect_success 'req_Root (base-path)' \
-  'cat request-base | git-cvsserver --strict-paths --base-path $WORKDIR/ pserver $SERVERDIR >log 2>&1 &&
+  'cat request-base | git-cvsserver --strict-paths --base-path "$WORKDIR"/ pserver "$SERVERDIR" >log 2>&1 &&
    sed -ne \$p log | grep "^I LOVE YOU$"'
 
 test_expect_success 'req_Root failure (base-path)' '
     ! cat request-anonymous |
-    git-cvsserver --strict-paths --base-path $WORKDIR pserver $SERVERDIR >log 2>&1
+    git-cvsserver --strict-paths --base-path "$WORKDIR" pserver "$SERVERDIR" >log 2>&1
 '
 
 GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled false || exit 1
 
 test_expect_success 'req_Root (export-all)' \
-  'cat request-anonymous | git-cvsserver --export-all pserver $WORKDIR >log 2>&1 &&
+  'cat request-anonymous | git-cvsserver --export-all pserver "$WORKDIR" >log 2>&1 &&
    sed -ne \$p log | grep "^I LOVE YOU$"'
 
 test_expect_success 'req_Root failure (export-all w/o whitelist)' \
   '! (cat request-anonymous | git-cvsserver --export-all pserver >log 2>&1 || false)'
 
 test_expect_success 'req_Root (everything together)' \
-  'cat request-base | git-cvsserver --export-all --strict-paths --base-path $WORKDIR/ pserver $SERVERDIR >log 2>&1 &&
+  'cat request-base | git-cvsserver --export-all --strict-paths --base-path "$WORKDIR"/ pserver "$SERVERDIR" >log 2>&1 &&
    sed -ne \$p log | grep "^I LOVE YOU$"'
 
 GIT_DIR="$SERVERDIR" git config --bool gitcvs.enabled true || exit 1
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 061a259..5e486c7 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -45,13 +45,13 @@ gitweb_run () {
 	export QUERY_STRING=""$1""
 	export PATH_INFO=""$2""
 
-	export GITWEB_CONFIG=$(pwd)/gitweb_config.perl
+	export GITWEB_CONFIG="$(pwd)"/gitweb_config.perl
 
 	# some of git commands write to STDERR on error, but this is not
 	# written to web server logs, so we are not interested in that:
 	# we are interested only in properly formatted errors/warnings
 	rm -f gitweb.log &&
-	perl -- $(pwd)/../../gitweb/gitweb.perl \
+	perl -- "$(pwd)"/../../gitweb/gitweb.perl \
 		>/dev/null 2>gitweb.log &&
 	if grep -q -s "^[[]" gitweb.log >/dev/null; then false; else true; fi
 
diff --git a/t/t9600-cvsimport.sh b/t/t9600-cvsimport.sh
index 00a74ee..a65147b 100755
--- a/t/t9600-cvsimport.sh
+++ b/t/t9600-cvsimport.sh
@@ -3,10 +3,10 @@
 test_description='git-cvsimport basic tests'
 . ./test-lib.sh
 
-CVSROOT=$(pwd)/cvsroot
+CVSROOT="$(pwd)"/cvsroot
 export CVSROOT
 # for clean cvsps cache
-HOME=$(pwd)
+HOME="$(pwd)"
 export HOME
 
 if ! type cvs >/dev/null 2>&1
@@ -36,7 +36,7 @@ test_expect_success 'setup cvsroot' 'cvs init'
 
 test_expect_success 'setup a cvs module' '
 
-	mkdir $CVSROOT/module &&
+	mkdir "$CVSROOT"/module &&
 	cvs co -d module-cvs module &&
 	cd module-cvs &&
 	cat <<EOF >o_fortuna &&
diff --git a/t/test-lib.sh b/t/test-lib.sh
index 7c2a8ba..8065776 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -329,7 +329,7 @@ test_create_repo () {
 	repo="$1"
 	mkdir "$repo"
 	cd "$repo" || error "Cannot setup test environment"
-	"$GIT_EXEC_PATH/git" init --template=$GIT_EXEC_PATH/templates/blt/ >/dev/null 2>&1 ||
+	"$GIT_EXEC_PATH"/git init --template="$GIT_EXEC_PATH"/templates/blt/ >/dev/null 2>&1 ||
 	error "cannot run git init -- have you built things yet?"
 	mv .git/hooks .git/hooks-disabled
 	cd "$owd"
@@ -371,16 +371,16 @@ test_done () {
 
 # Test the binaries we have just built.  The tests are kept in
 # t/ subdirectory and are run in trash subdirectory.
-PATH=$(pwd)/..:$PATH
-GIT_EXEC_PATH=$(pwd)/..
-GIT_TEMPLATE_DIR=$(pwd)/../templates/blt
+PATH="$(pwd)"/..:$PATH
+GIT_EXEC_PATH="$(pwd)"/..
+GIT_TEMPLATE_DIR="$(pwd)"/../templates/blt
 unset GIT_CONFIG
 unset GIT_CONFIG_LOCAL
 GIT_CONFIG_NOSYSTEM=1
 GIT_CONFIG_NOGLOBAL=1
 export PATH GIT_EXEC_PATH GIT_TEMPLATE_DIR GIT_CONFIG_NOSYSTEM GIT_CONFIG_NOGLOBAL
 
-GITPERLLIB=$(pwd)/../perl/blib/lib:$(pwd)/../perl/blib/arch/auto/Git
+GITPERLLIB="$(pwd)"/../perl/blib/lib:"$(pwd)"/../perl/blib/arch/auto/Git
 export GITPERLLIB
 test -d ../templates/blt || {
 	error "You haven't built things yet, have you?"
-- 
1.5.5.67.g9a49

^ permalink raw reply related	[relevance 9%]

* [PATCH v3 09/10] Fix tests breaking when checkout path contains shell metacharacters
  @ 2008-05-04  5:37  8%                     ` Bryan Donlan
  0 siblings, 0 replies; 200+ results
From: Bryan Donlan @ 2008-05-04  5:37 UTC (permalink / raw)
  To: git; +Cc: Johannes Sixt, Adam Roben, gitster, Bryan Donlan

This fixes the remainder of the issues where the test script itself is at
fault for failing when the git checkout path contains whitespace or other
shell metacharacters.

Signed-off-by: Bryan Donlan <bdonlan@fushizen.net>
---
 t/t0000-basic.sh                              |    4 +-
 t/t1020-subdirectory.sh                       |   22 ++--
 t/t3050-subprojects-fetch.sh                  |    2 +-
 t/t3404-rebase-interactive.sh                 |    3 +-
 t/t5500-fetch-pack.sh                         |    2 +-
 t/t5512-ls-remote.sh                          |    2 +-
 t/t5516-fetch-push.sh                         |    6 +-
 t/t5700-clone-reference.sh                    |    2 +-
 t/t5710-info-alternate.sh                     |    4 +-
 t/t7003-filter-branch.sh                      |    2 +-
 t/t7010-setup.sh                              |    2 +-
 t/t7300-clean.sh                              |    2 +-
 t/t7501-commit.sh                             |    8 +-
 t/t7504-commit-msg-hook.sh                    |   23 ++--
 t/t7505-prepare-commit-msg-hook.sh            |   17 ++-
 t/t9100-git-svn-basic.sh                      |  120 +++++++++---------
 t/t9101-git-svn-props.sh                      |    8 +-
 t/t9102-git-svn-deep-rmdir.sh                 |   20 ++--
 t/t9103-git-svn-tracked-directory-removed.sh  |   20 ++--
 t/t9104-git-svn-follow-parent.sh              |  172 ++++++++++++------------
 t/t9105-git-svn-commit-diff.sh                |   32 +++---
 t/t9106-git-svn-commit-diff-clobber.sh        |   56 ++++----
 t/t9106-git-svn-dcommit-clobber-series.sh     |   30 ++--
 t/t9107-git-svn-migrate.sh                    |  124 +++++++++---------
 t/t9108-git-svn-glob.sh                       |   76 ++++++------
 t/t9110-git-svn-use-svm-props.sh              |   12 +-
 t/t9111-git-svn-use-svnsync-props.sh          |   12 +-
 t/t9112-git-svn-md5less-file.sh               |    4 +-
 t/t9113-git-svn-dcommit-new-file.sh           |   10 +-
 t/t9114-git-svn-dcommit-merge.sh              |   22 ++--
 t/t9115-git-svn-dcommit-funky-renames.sh      |   12 +-
 t/t9116-git-svn-log.sh                        |   12 +-
 t/t9117-git-svn-init-clone.sh                 |   30 ++--
 t/t9118-git-svn-funky-branch-names.sh         |   24 ++--
 t/t9120-git-svn-clone-with-percent-escapes.sh |    6 +-
 t/t9500-gitweb-standalone-no-errors.sh        |   11 +-
 36 files changed, 460 insertions(+), 454 deletions(-)

diff --git a/t/t0000-basic.sh b/t/t0000-basic.sh
index 27b54cb..690f80a 100755
--- a/t/t0000-basic.sh
+++ b/t/t0000-basic.sh
@@ -305,10 +305,10 @@ test_expect_success 'absolute path works as expected' '
 	file="$dir"/index &&
 	test "$file" = "$(test-absolute-path $dir2/index)" &&
 	basename=blub &&
-	test "$dir/$basename" = $(cd .git && test-absolute-path $basename) &&
+	test "$dir/$basename" = "$(cd .git && test-absolute-path "$basename")" &&
 	ln -s ../first/file .git/syml &&
 	sym="$(cd first; pwd -P)"/file &&
-	test "$sym" = "$(test-absolute-path $dir2/syml)"
+	test "$sym" = "$(test-absolute-path "$dir2/syml")"
 '
 
 test_expect_success 'very long name in the index handled sanely' '
diff --git a/t/t1020-subdirectory.sh b/t/t1020-subdirectory.sh
index b9cef34..fc386ba 100755
--- a/t/t1020-subdirectory.sh
+++ b/t/t1020-subdirectory.sh
@@ -21,7 +21,7 @@ LF='
 '
 
 test_expect_success 'update-index and ls-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git update-index --add one &&
 	case "`git ls-files`" in
 	one) echo ok one ;;
@@ -41,7 +41,7 @@ test_expect_success 'update-index and ls-files' '
 '
 
 test_expect_success 'cat-file' '
-	cd $HERE &&
+	cd "$HERE" &&
 	two=`git ls-files -s dir/two` &&
 	two=`expr "$two" : "[0-7]* \\([0-9a-f]*\\)"` &&
 	echo "$two" &&
@@ -54,7 +54,7 @@ test_expect_success 'cat-file' '
 rm -f actual dir/actual
 
 test_expect_success 'diff-files' '
-	cd $HERE &&
+	cd "$HERE" &&
 	echo a >>one &&
 	echo d >>dir/two &&
 	case "`git diff-files --name-only`" in
@@ -74,7 +74,7 @@ test_expect_success 'diff-files' '
 '
 
 test_expect_success 'write-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	top=`git write-tree` &&
 	echo $top &&
 	cd dir &&
@@ -84,7 +84,7 @@ test_expect_success 'write-tree' '
 '
 
 test_expect_success 'checkout-index' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git checkout-index -f -u one &&
 	cmp one original.one &&
 	cd dir &&
@@ -93,7 +93,7 @@ test_expect_success 'checkout-index' '
 '
 
 test_expect_success 'read-tree' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -f one dir/two &&
 	tree=`git write-tree` &&
 	git read-tree --reset -u "$tree" &&
@@ -107,27 +107,27 @@ test_expect_success 'read-tree' '
 '
 
 test_expect_success 'no file/rev ambiguity check inside .git' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git commit -a -m 1 &&
-	cd $HERE/.git &&
+	cd "$HERE"/.git &&
 	git show -s HEAD
 '
 
 test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && GIT_DIR=. git show -s HEAD
 '
 
 # This still does not work as it should...
 : test_expect_success 'no file/rev ambiguity check inside a bare repo' '
-	cd $HERE &&
+	cd "$HERE" &&
 	git clone -s --bare .git foo.git &&
 	cd foo.git && git show -s HEAD
 '
 
 test_expect_success 'detection should not be fooled by a symlink' '
-	cd $HERE &&
+	cd "$HERE" &&
 	rm -fr foo.git &&
 	git clone -s .git another &&
 	ln -s another yetanother &&
diff --git a/t/t3050-subprojects-fetch.sh b/t/t3050-subprojects-fetch.sh
index 2b21b10..4261e96 100755
--- a/t/t3050-subprojects-fetch.sh
+++ b/t/t3050-subprojects-fetch.sh
@@ -20,7 +20,7 @@ test_expect_success setup '
 '
 
 test_expect_success clone '
-	git clone file://`pwd`/.git cloned &&
+	git clone "file://$(pwd)/.git" cloned &&
 	(git rev-parse HEAD; git ls-files -s) >expected &&
 	(
 		cd cloned &&
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 9cf873f..b9e3dbd 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -91,9 +91,8 @@ for line in $FAKE_LINES; do
 done
 EOF
 
+test_set_editor "$(pwd)/fake-editor.sh"
 chmod a+x fake-editor.sh
-VISUAL="$(pwd)/fake-editor.sh"
-export VISUAL
 
 test_expect_success 'no changes are a nop' '
 	git rebase -i F &&
diff --git a/t/t5500-fetch-pack.sh b/t/t5500-fetch-pack.sh
index 1700d07..140e874 100755
--- a/t/t5500-fetch-pack.sh
+++ b/t/t5500-fetch-pack.sh
@@ -129,7 +129,7 @@ pull_to_client 2nd "B" $((64*3))
 
 pull_to_client 3rd "A" $((1*3)) # old fails
 
-test_expect_success "clone shallow" "git-clone --depth 2 file://`pwd`/. shallow"
+test_expect_success "clone shallow" 'git-clone --depth 2 "file://$(pwd)/." shallow'
 
 (cd shallow; git count-objects -v) > count.shallow
 
diff --git a/t/t5512-ls-remote.sh b/t/t5512-ls-remote.sh
index c0dc949..1dd8eed 100755
--- a/t/t5512-ls-remote.sh
+++ b/t/t5512-ls-remote.sh
@@ -17,7 +17,7 @@ test_expect_success setup '
 		git show-ref -d	| sed -e "s/ /	/"
 	) >expected.all &&
 
-	git remote add self $(pwd)/.git
+	git remote add self "$(pwd)/.git"
 
 '
 
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index 0a757d5..3af03d4 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -105,7 +105,7 @@ test_expect_success 'fetch with insteadOf' '
 	(
 		TRASH=$(pwd)/ &&
 		cd testrepo &&
-		git config url.$TRASH.insteadOf trash/
+		git config "url.$TRASH.insteadOf" trash/ &&
 		git config remote.up.url trash/. &&
 		git config remote.up.fetch "refs/heads/*:refs/remotes/origin/*" &&
 		git fetch up &&
@@ -145,8 +145,8 @@ test_expect_success 'push with wildcard' '
 
 test_expect_success 'push with insteadOf' '
 	mk_empty &&
-	TRASH=$(pwd)/ &&
-	git config url.$TRASH.insteadOf trash/ &&
+	TRASH="$(pwd)/" &&
+	git config "url./$TRASH/.insteadOf" trash/ &&
 	git push trash/testrepo refs/heads/master:refs/remotes/origin/master &&
 	(
 		cd testrepo &&
diff --git a/t/t5700-clone-reference.sh b/t/t5700-clone-reference.sh
index b6a5486..e5619a9 100755
--- a/t/t5700-clone-reference.sh
+++ b/t/t5700-clone-reference.sh
@@ -51,7 +51,7 @@ diff expected current'
 cd "$base_dir"
 
 test_expect_success 'cloning with reference (no -l -s)' \
-'git clone --reference B file://`pwd`/A D'
+'git clone --reference B "file://$(pwd)/A" D'
 
 cd "$base_dir"
 
diff --git a/t/t5710-info-alternate.sh b/t/t5710-info-alternate.sh
index 910ccb4..ef7127c 100755
--- a/t/t5710-info-alternate.sh
+++ b/t/t5710-info-alternate.sh
@@ -81,9 +81,9 @@ test_valid_repo'
 cd "$base_dir"
 
 test_expect_success 'breaking of loops' \
-"echo '$base_dir/B/.git/objects' >> '$base_dir'/A/.git/objects/info/alternates&&
+'echo "$base_dir"/B/.git/objects >> "$base_dir"/A/.git/objects/info/alternates&&
 cd C &&
-test_valid_repo"
+test_valid_repo'
 
 cd "$base_dir"
 
diff --git a/t/t7003-filter-branch.sh b/t/t7003-filter-branch.sh
index efd658a..fd09030 100755
--- a/t/t7003-filter-branch.sh
+++ b/t/t7003-filter-branch.sh
@@ -125,7 +125,7 @@ test_expect_success 'use index-filter to move into a subdirectory' '
 		 "git ls-files -s | sed \"s-\\t-&newsubdir/-\" |
 	          GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
 			git update-index --index-info &&
-		  mv \$GIT_INDEX_FILE.new \$GIT_INDEX_FILE" directorymoved &&
+		  mv \"\$GIT_INDEX_FILE.new\" \"\$GIT_INDEX_FILE\"" directorymoved &&
 	test -z "$(git diff HEAD directorymoved:newsubdir)"'
 
 test_expect_success 'stops when msg filter fails' '
diff --git a/t/t7010-setup.sh b/t/t7010-setup.sh
index 02cf7c5..d8a7c79 100755
--- a/t/t7010-setup.sh
+++ b/t/t7010-setup.sh
@@ -122,7 +122,7 @@ test_expect_success 'commit using absolute path names' '
 
 test_expect_success 'log using absolute path names' '
 	echo bb >>a/b/c/d &&
-	git commit -m "bb" $(pwd)/a/b/c/d &&
+	git commit -m "bb" "$(pwd)/a/b/c/d" &&
 
 	git log a/b/c/d >f1.txt &&
 	git log "$(pwd)/a/b/c/d" >f2.txt &&
diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh
index a50492f..bd77239 100755
--- a/t/t7300-clean.sh
+++ b/t/t7300-clean.sh
@@ -112,7 +112,7 @@ test_expect_success 'git-clean with absolute path' '
 	touch a.out src/part3.c docs/manual.txt obj.o build/lib.so &&
 	would_clean=$(
 		cd docs &&
-		git clean -n $(pwd)/../src |
+		git clean -n "$(pwd)/../src" |
 		sed -n -e "s|^Would remove ||p"
 	) &&
 	test "$would_clean" = ../src/part3.c || {
diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh
index c0288f3..e5fdb63 100755
--- a/t/t7501-commit.sh
+++ b/t/t7501-commit.sh
@@ -79,8 +79,8 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -e "s/a file/an amend commit/g" < $1 > $1-
-mv $1- $1
+sed -e "s/a file/an amend commit/g" < "$1" > "$1-"
+mv "$1-" "$1"
 EOF
 chmod 755 editor
 
@@ -99,8 +99,8 @@ test_expect_success \
 
 cat >editor <<\EOF
 #!/bin/sh
-sed -e "s/amend/older/g"  < $1 > $1-
-mv $1- $1
+sed -e "s/amend/older/g"  < "$1" > "$1-"
+mv "$1-" "$1"
 EOF
 chmod 755 editor
 
diff --git a/t/t7504-commit-msg-hook.sh b/t/t7504-commit-msg-hook.sh
index eff36aa..88577af 100755
--- a/t/t7504-commit-msg-hook.sh
+++ b/t/t7504-commit-msg-hook.sh
@@ -19,6 +19,9 @@ cp FAKE_MSG "$1"
 exit 0
 EOF
 chmod +x fake-editor
+
+## Not using test_set_editor here so we can easily ensure the editor variable
+## is only set for the editor tests
 FAKE_EDITOR="$(pwd)/fake-editor"
 export FAKE_EDITOR
 
@@ -27,7 +30,7 @@ test_expect_success 'with no hook (editor)' '
 	echo "more foo" >> file &&
 	git add file &&
 	echo "more foo" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit
 
 '
 
@@ -44,7 +47,7 @@ test_expect_success '--no-verify with no hook (editor)' '
 	echo "more bar" > file &&
 	git add file &&
 	echo "more bar" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -71,7 +74,7 @@ test_expect_success 'with succeeding hook (editor)' '
 	echo "more more" >> file &&
 	git add file &&
 	echo "more more" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit
 
 '
 
@@ -88,7 +91,7 @@ test_expect_success '--no-verify with succeeding hook (editor)' '
 	echo "even more more" >> file &&
 	git add file &&
 	echo "even more more" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -111,7 +114,7 @@ test_expect_success 'with failing hook (editor)' '
 	echo "more another" >> file &&
 	git add file &&
 	echo "more another" > FAKE_MSG &&
-	! (GIT_EDITOR="$FAKE_EDITOR" git commit)
+	! (GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit)
 
 '
 
@@ -128,7 +131,7 @@ test_expect_success '--no-verify with failing hook (editor)' '
 	echo "more stuff" >> file &&
 	git add file &&
 	echo "more stuff" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -146,7 +149,7 @@ test_expect_success 'with non-executable hook (editor)' '
 	echo "content again" >> file &&
 	git add file &&
 	echo "content again" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -m "content again"
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -m "content again"
 
 '
 
@@ -163,7 +166,7 @@ test_expect_success '--no-verify with non-executable hook (editor)' '
 	echo "even more content" >> file &&
 	git add file &&
 	echo "even more content" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify
 
 '
 
@@ -193,7 +196,7 @@ test_expect_success 'hook edits commit message (editor)' '
 	echo "additional content" >> file &&
 	git add file &&
 	echo "additional content" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit &&
 	commit_msg_is "new message"
 
 '
@@ -212,7 +215,7 @@ test_expect_success "hook doesn't edit commit message (editor)" '
 	echo "more plus" >> file &&
 	git add file &&
 	echo "more plus" > FAKE_MSG &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify &&
 	commit_msg_is "more plus"
 
 '
diff --git a/t/t7505-prepare-commit-msg-hook.sh b/t/t7505-prepare-commit-msg-hook.sh
index 802aa62..cd6c7c8 100755
--- a/t/t7505-prepare-commit-msg-hook.sh
+++ b/t/t7505-prepare-commit-msg-hook.sh
@@ -18,6 +18,9 @@ cat > fake-editor <<'EOF'
 exit 0
 EOF
 chmod +x fake-editor
+
+## Not using test_set_editor here so we can easily ensure the editor variable
+## is only set for the editor tests
 FAKE_EDITOR="$(pwd)/fake-editor"
 export FAKE_EDITOR
 
@@ -58,7 +61,7 @@ test_expect_success 'with hook (-m editor)' '
 
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -e -m "more more" &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -m "more more" &&
 	test "`git log -1 --pretty=format:%s`" = message
 
 '
@@ -85,7 +88,7 @@ test_expect_success 'with hook (-F editor)' '
 
 	echo "more" >> file &&
 	git add file &&
-	(echo more more | GIT_EDITOR="$FAKE_EDITOR" git commit -e -F -) &&
+	(echo more more | GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -e -F -) &&
 	test "`git log -1 --pretty=format:%s`" = message
 
 '
@@ -104,7 +107,7 @@ test_expect_success 'with hook (editor)' '
 
 	echo "more more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit &&
 	test "`git log -1 --pretty=format:%s`" = default
 
 '
@@ -114,7 +117,7 @@ test_expect_success 'with hook (--amend)' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit --amend &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --amend &&
 	test "`git log -1 --pretty=format:%s`" = "$head"
 
 '
@@ -124,7 +127,7 @@ test_expect_success 'with hook (-c)' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	GIT_EDITOR="$FAKE_EDITOR" git commit -c $head &&
+	GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head &&
 	test "`git log -1 --pretty=format:%s`" = "$head"
 
 '
@@ -139,7 +142,7 @@ test_expect_success 'with failing hook' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	! GIT_EDITOR="$FAKE_EDITOR" git commit -c $head
+	! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit -c $head
 
 '
 
@@ -148,7 +151,7 @@ test_expect_success 'with failing hook (--no-verify)' '
 	head=`git rev-parse HEAD` &&
 	echo "more" >> file &&
 	git add file &&
-	! GIT_EDITOR="$FAKE_EDITOR" git commit --no-verify -c $head
+	! GIT_EDITOR="\"\$FAKE_EDITOR\"" git commit --no-verify -c $head
 
 '
 
diff --git a/t/t9100-git-svn-basic.sh b/t/t9100-git-svn-basic.sh
index 4e24ab3..bdf29c1 100755
--- a/t/t9100-git-svn-basic.sh
+++ b/t/t9100-git-svn-basic.sh
@@ -20,39 +20,39 @@ esac
 echo 'define NO_SVN_TESTS to skip git-svn tests'
 
 test_expect_success \
-    'initialize git-svn' "
+    'initialize git-svn' '
 	mkdir import &&
 	cd import &&
 	echo foo > foo &&
 	ln -s foo foo.link
 	mkdir -p dir/a/b/c/d/e &&
-	echo 'deep dir' > dir/a/b/c/d/e/file &&
+	echo "deep dir" > dir/a/b/c/d/e/file &&
 	mkdir bar &&
-	echo 'zzz' > bar/zzz &&
-	echo '#!/bin/sh' > exec.sh &&
+	echo "zzz" > bar/zzz &&
+	echo "#!/bin/sh" > exec.sh &&
 	chmod +x exec.sh &&
-	svn import -m 'import for git-svn' . $svnrepo >/dev/null &&
+	svn import -m "import for git-svn" . "$svnrepo" >/dev/null &&
 	cd .. &&
 	rm -rf import &&
-	git-svn init $svnrepo"
+	git-svn init "$svnrepo"'
 
 test_expect_success \
     'import an SVN revision into git' \
     'git-svn fetch'
 
-test_expect_success "checkout from svn" "svn co $svnrepo '$SVN_TREE'"
+test_expect_success "checkout from svn" 'svn co "$svnrepo" "$SVN_TREE"'
 
 name='try a deep --rmdir with a commit'
-test_expect_success "$name" "
+test_expect_success "$name" '
 	git checkout -f -b mybranch remotes/git-svn &&
 	mv dir/a/b/c/d/e/file dir/file &&
 	cp dir/file file &&
 	git update-index --add --remove dir/a/b/c/d/e/file dir/file file &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch &&
-	svn up '$SVN_TREE' &&
-	test -d '$SVN_TREE'/dir && test ! -d '$SVN_TREE'/dir/a"
+	svn up "$SVN_TREE" &&
+	test -d "$SVN_TREE"/dir && test ! -d "$SVN_TREE"/dir/a'
 
 
 name='detect node change from file to directory #1'
@@ -68,108 +68,108 @@ test_expect_success "$name" "
 
 
 name='detect node change from directory to file #1'
-test_expect_success "$name" "
-	rm -rf dir '$GIT_DIR'/index &&
+test_expect_success "$name" '
+	rm -rf dir "$GIT_DIR"/index &&
 	git checkout -f -b mybranch2 remotes/git-svn &&
 	mv bar/zzz zzz &&
 	rm -rf bar &&
 	mv zzz bar &&
 	git update-index --remove -- bar/zzz &&
 	git update-index --add -- bar &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	! git-svn set-tree --find-copies-harder --rmdir \
-		remotes/git-svn..mybranch2" || true
+		remotes/git-svn..mybranch2' || true
 
 
 name='detect node change from file to directory #2'
-test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+test_expect_success "$name" '
+	rm -f "$GIT_DIR"/index &&
 	git checkout -f -b mybranch3 remotes/git-svn &&
 	rm bar/zzz &&
 	git update-index --remove bar/zzz &&
 	mkdir bar/zzz &&
 	echo yyy > bar/zzz/yyy &&
 	git update-index --add bar/zzz/yyy &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	! git-svn set-tree --find-copies-harder --rmdir \
-		remotes/git-svn..mybranch3" || true
+		remotes/git-svn..mybranch3' || true
 
 
 name='detect node change from directory to file #2'
-test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+test_expect_success "$name" '
+	rm -f "$GIT_DIR"/index &&
 	git checkout -f -b mybranch4 remotes/git-svn &&
 	rm -rf dir &&
 	git update-index --remove -- dir/file &&
 	touch dir &&
 	echo asdf > dir &&
 	git update-index --add -- dir &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	! git-svn set-tree --find-copies-harder --rmdir \
-		remotes/git-svn..mybranch4" || true
+		remotes/git-svn..mybranch4' || true
 
 
 name='remove executable bit from a file'
-test_expect_success "$name" "
-	rm -f '$GIT_DIR'/index &&
+test_expect_success "$name" '
+	rm -f "$GIT_DIR"/index &&
 	git checkout -f -b mybranch5 remotes/git-svn &&
 	chmod -x exec.sh &&
 	git update-index exec.sh &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test ! -x '$SVN_TREE'/exec.sh"
+	svn up "$SVN_TREE" &&
+	test ! -x "$SVN_TREE"/exec.sh'
 
 
 name='add executable bit back file'
-test_expect_success "$name" "
+test_expect_success "$name" '
 	chmod +x exec.sh &&
 	git update-index exec.sh &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -x '$SVN_TREE'/exec.sh"
+	svn up "$SVN_TREE" &&
+	test -x "$SVN_TREE"/exec.sh'
 
 
 name='executable file becomes a symlink to bar/zzz (file)'
-test_expect_success "$name" "
+test_expect_success "$name" '
 	rm exec.sh &&
 	ln -s bar/zzz exec.sh &&
 	git update-index exec.sh &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -L '$SVN_TREE'/exec.sh"
+	svn up "$SVN_TREE" &&
+	test -L "$SVN_TREE"/exec.sh'
 
 name='new symlink is added to a file that was also just made executable'
 
-test_expect_success "$name" "
+test_expect_success "$name" '
 	chmod +x bar/zzz &&
 	ln -s bar/zzz exec-2.sh &&
 	git update-index --add bar/zzz exec-2.sh &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -x '$SVN_TREE'/bar/zzz &&
-	test -L '$SVN_TREE'/exec-2.sh"
+	svn up "$SVN_TREE" &&
+	test -x "$SVN_TREE"/bar/zzz &&
+	test -L "$SVN_TREE"/exec-2.sh'
 
 name='modify a symlink to become a file'
-test_expect_success "$name" "
+test_expect_success "$name" '
 	echo git help > help || true &&
 	rm exec-2.sh &&
 	cp help exec-2.sh &&
 	git update-index exec-2.sh &&
-	git commit -m '$name' &&
+	git commit -m "$name" &&
 	git-svn set-tree --find-copies-harder --rmdir \
 		remotes/git-svn..mybranch5 &&
-	svn up '$SVN_TREE' &&
-	test -f '$SVN_TREE'/exec-2.sh &&
-	test ! -L '$SVN_TREE'/exec-2.sh &&
-	git diff help $SVN_TREE/exec-2.sh"
+	svn up "$SVN_TREE" &&
+	test -f "$SVN_TREE"/exec-2.sh &&
+	test ! -L "$SVN_TREE"/exec-2.sh &&
+	git diff help "$SVN_TREE"/exec-2.sh'
 
 if test "$have_utf8" = t
 then
@@ -190,10 +190,10 @@ name='test fetch functionality (svn => git) with alternate GIT_SVN_ID'
 GIT_SVN_ID=alt
 export GIT_SVN_ID
 test_expect_success "$name" \
-    "git-svn init $svnrepo && git-svn fetch &&
+    'git-svn init "$svnrepo" && git-svn fetch &&
      git rev-list --pretty=raw remotes/git-svn | grep ^tree | uniq > a &&
      git rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&
-     git diff a b"
+     git diff a b'
 
 name='check imported tree checksums expected tree checksums'
 rm -f expected
@@ -219,22 +219,22 @@ test_expect_success 'exit if remote refs are ambigious' "
 	! git-svn migrate
 "
 
-test_expect_success 'exit if init-ing a would clobber a URL' "
-        svnadmin create ${PWD}/svnrepo2 &&
-        svn mkdir -m 'mkdir bar' ${svnrepo}2/bar &&
+test_expect_success 'exit if init-ing a would clobber a URL' '
+        svnadmin create "${PWD}/svnrepo2" &&
+        svn mkdir -m "mkdir bar" "${svnrepo}2/bar" &&
         git config --unset svn-remote.svn.fetch \
-                                '^bar:refs/remotes/git-svn$' &&
-	! git-svn init ${svnrepo}2/bar
-        "
+                                "^bar:refs/remotes/git-svn$" &&
+	! git-svn init "${svnrepo}2/bar"
+        '
 
 test_expect_success \
-  'init allows us to connect to another directory in the same repo' "
-        git-svn init --minimize-url -i bar $svnrepo/bar &&
+  'init allows us to connect to another directory in the same repo' '
+        git-svn init --minimize-url -i bar "$svnrepo/bar" &&
         git config --get svn-remote.svn.fetch \
-                              '^bar:refs/remotes/bar$' &&
+                              "^bar:refs/remotes/bar$" &&
         git config --get svn-remote.svn.fetch \
-                              '^:refs/remotes/git-svn$'
-        "
+                              "^:refs/remotes/git-svn$"
+        '
 
 test_expect_success 'able to dcommit to a subdirectory' "
 	git-svn fetch -i bar &&
diff --git a/t/t9101-git-svn-props.sh b/t/t9101-git-svn-props.sh
index d7a7047..f420796 100755
--- a/t/t9101-git-svn-props.sh
+++ b/t/t9101-git-svn-props.sh
@@ -52,7 +52,7 @@ EOF
 cd ..
 
 rm -rf import
-test_expect_success 'checkout working copy from svn' "svn co $svnrepo test_wc"
+test_expect_success 'checkout working copy from svn' 'svn co "$svnrepo" test_wc'
 test_expect_success 'setup some commits to svn' \
 	'cd test_wc &&
 		echo Greetings >> kw.c &&
@@ -66,7 +66,7 @@ test_expect_success 'setup some commits to svn' \
 		svn commit -m "Propset Id" &&
 	cd ..'
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' 'git-svn init "$svnrepo"'
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 
 name='test svn:keywords ignoring'
@@ -90,9 +90,9 @@ test_expect_success "propset CR on crlf files" \
 	 cd ..'
 
 test_expect_success 'fetch and pull latest from svn and checkout a new wc' \
-	"git-svn fetch &&
+	'git-svn fetch &&
 	 git pull . remotes/git-svn &&
-	 svn co $svnrepo new_wc"
+	 svn co "$svnrepo" new_wc'
 
 for i in crlf ne_crlf lf ne_lf cr ne_cr empty_cr empty_lf empty empty_crlf
 do
diff --git a/t/t9102-git-svn-deep-rmdir.sh b/t/t9102-git-svn-deep-rmdir.sh
index 4e08083..0e7ce34 100755
--- a/t/t9102-git-svn-deep-rmdir.sh
+++ b/t/t9102-git-svn-deep-rmdir.sh
@@ -2,29 +2,29 @@
 test_description='git-svn rmdir'
 . ./lib-git-svn.sh
 
-test_expect_success 'initialize repo' "
+test_expect_success 'initialize repo' '
 	mkdir import &&
 	cd import &&
 	mkdir -p deeply/nested/directory/number/1 &&
 	mkdir -p deeply/nested/directory/number/2 &&
 	echo foo > deeply/nested/directory/number/1/file &&
 	echo foo > deeply/nested/directory/number/2/another &&
-	svn import -m 'import for git-svn' . $svnrepo &&
+	svn import -m "import for git-svn" . "$svnrepo" &&
 	cd ..
-	"
+	'
 
-test_expect_success 'mirror via git-svn' "
-	git-svn init $svnrepo &&
+test_expect_success 'mirror via git-svn' '
+	git-svn init "$svnrepo" &&
 	git-svn fetch &&
 	git checkout -f -b test-rmdir remotes/git-svn
-	"
+	'
 
-test_expect_success 'Try a commit on rmdir' "
+test_expect_success 'Try a commit on rmdir' '
 	git rm -f deeply/nested/directory/number/2/another &&
-	git commit -a -m 'remove another' &&
+	git commit -a -m "remove another" &&
 	git-svn set-tree --rmdir HEAD &&
-	svn ls -R $svnrepo | grep ^deeply/nested/directory/number/1
-	"
+	svn ls -R "$svnrepo" | grep ^deeply/nested/directory/number/1
+	'
 
 
 test_done
diff --git a/t/t9103-git-svn-tracked-directory-removed.sh b/t/t9103-git-svn-tracked-directory-removed.sh
index 0f0b0fd..9ffd845 100755
--- a/t/t9103-git-svn-tracked-directory-removed.sh
+++ b/t/t9103-git-svn-tracked-directory-removed.sh
@@ -10,30 +10,30 @@ test_expect_success 'make history for tracking' '
 	mkdir import &&
 	mkdir import/trunk &&
 	echo hello >> import/trunk/README &&
-	svn import -m initial import $svnrepo &&
+	svn import -m initial import "$svnrepo" &&
 	rm -rf import &&
-	svn co $svnrepo/trunk trunk &&
+	svn co "$svnrepo"/trunk trunk &&
 	echo bye bye >> trunk/README &&
-	svn rm -m "gone" $svnrepo/trunk &&
+	svn rm -m "gone" "$svnrepo"/trunk &&
 	rm -rf trunk &&
 	mkdir trunk &&
 	echo "new" > trunk/FOLLOWME &&
-	svn import -m "new trunk" trunk $svnrepo/trunk
+	svn import -m "new trunk" trunk "$svnrepo"/trunk
 '
 
 test_expect_success 'clone repo with git' '
-	git svn clone -s $svnrepo x &&
+	git svn clone -s "$svnrepo" x &&
 	test -f x/FOLLOWME &&
 	test ! -f x/README
 '
 
-test_expect_success 'make sure r2 still has old file' '
+test_expect_success 'make sure r2 still has old file' "
 	cd x &&
-		test -n "$(git svn find-rev r1)" &&
-		git reset --hard $(git svn find-rev r1) &&
+		test -n \"\$(git svn find-rev r1)\" &&
+		git reset --hard \$(git svn find-rev r1) &&
 		test -f README &&
 		test ! -f FOLLOWME &&
-		test x$(git svn find-rev r2) = x
-'
+		test x\$(git svn find-rev r2) = x
+"
 
 test_done
diff --git a/t/t9104-git-svn-follow-parent.sh b/t/t9104-git-svn-follow-parent.sh
index 7ba7630..4d964e2 100755
--- a/t/t9104-git-svn-follow-parent.sh
+++ b/t/t9104-git-svn-follow-parent.sh
@@ -6,165 +6,165 @@
 test_description='git-svn fetching'
 . ./lib-git-svn.sh
 
-test_expect_success 'initialize repo' "
+test_expect_success 'initialize repo' '
 	mkdir import &&
 	cd import &&
 	mkdir -p trunk &&
 	echo hello > trunk/readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m "initial" . "$svnrepo" &&
 	cd .. &&
-	svn co $svnrepo wc &&
+	svn co "$svnrepo" wc &&
 	cd wc &&
 	echo world >> trunk/readme &&
 	poke trunk/readme &&
-	svn commit -m 'another commit' &&
+	svn commit -m "another commit" &&
 	svn up &&
 	svn mv trunk thunk &&
 	echo goodbye >> thunk/readme &&
 	poke thunk/readme &&
-	svn commit -m 'bye now' &&
+	svn commit -m "bye now" &&
 	cd ..
-	"
+	'
 
-test_expect_success 'init and fetch a moved directory' "
-	git-svn init --minimize-url -i thunk $svnrepo/thunk &&
+test_expect_success 'init and fetch a moved directory' '
+	git-svn init --minimize-url -i thunk "$svnrepo"/thunk &&
 	git-svn fetch -i thunk &&
-	test \"\`git rev-parse --verify refs/remotes/thunk@2\`\" \
-           = \"\`git rev-parse --verify refs/remotes/thunk~1\`\" &&
-        test \"\`git cat-file blob refs/remotes/thunk:readme |\
-                 sed -n -e '3p'\`\" = goodbye &&
-	test -z \"\`git config --get svn-remote.svn.fetch \
-	         '^trunk:refs/remotes/thunk@2$'\`\"
-	"
+	test "`git rev-parse --verify refs/remotes/thunk@2`" \
+           = "`git rev-parse --verify refs/remotes/thunk~1`" &&
+        test "`git cat-file blob refs/remotes/thunk:readme |\
+                 sed -n -e "3p"`" = goodbye &&
+	test -z "`git config --get svn-remote.svn.fetch \
+	         "^trunk:refs/remotes/thunk@2$"`"
+	'
 
-test_expect_success 'init and fetch from one svn-remote' "
-        git config svn-remote.svn.url $svnrepo &&
+test_expect_success 'init and fetch from one svn-remote' '
+        git config svn-remote.svn.url "$svnrepo" &&
         git config --add svn-remote.svn.fetch \
           trunk:refs/remotes/svn/trunk &&
         git config --add svn-remote.svn.fetch \
           thunk:refs/remotes/svn/thunk &&
         git-svn fetch -i svn/thunk &&
-	test \"\`git rev-parse --verify refs/remotes/svn/trunk\`\" \
-           = \"\`git rev-parse --verify refs/remotes/svn/thunk~1\`\" &&
-        test \"\`git cat-file blob refs/remotes/svn/thunk:readme |\
-                 sed -n -e '3p'\`\" = goodbye
-        "
+	test "`git rev-parse --verify refs/remotes/svn/trunk`" \
+           = "`git rev-parse --verify refs/remotes/svn/thunk~1`" &&
+        test "`git cat-file blob refs/remotes/svn/thunk:readme |\
+                 sed -n -e "3p"`" = goodbye
+        '
 
-test_expect_success 'follow deleted parent' "
-        (svn cp -m 'resurrecting trunk as junk' \
-               $svnrepo/trunk@2 $svnrepo/junk ||
-         svn cp -m 'resurrecting trunk as junk' \
-               -r2 $svnrepo/trunk $svnrepo/junk) &&
+test_expect_success 'follow deleted parent' '
+        (svn cp -m "resurrecting trunk as junk" \
+               "$svnrepo"/trunk@2 "$svnrepo"/junk ||
+         svn cp -m "resurrecting trunk as junk" \
+               -r2 "$svnrepo"/trunk "$svnrepo"/junk) &&
         git config --add svn-remote.svn.fetch \
           junk:refs/remotes/svn/junk &&
         git-svn fetch -i svn/thunk &&
         git-svn fetch -i svn/junk &&
-        test -z \"\`git diff svn/junk svn/trunk\`\" &&
-        test \"\`git merge-base svn/junk svn/trunk\`\" \
-           = \"\`git rev-parse svn/trunk\`\"
-        "
+        test -z "`git diff svn/junk svn/trunk`" &&
+        test "`git merge-base svn/junk svn/trunk`" \
+           = "`git rev-parse svn/trunk`"
+        '
 
-test_expect_success 'follow larger parent' "
+test_expect_success 'follow larger parent' '
         mkdir -p import/trunk/thunk/bump/thud &&
         echo hi > import/trunk/thunk/bump/thud/file &&
-        svn import -m 'import a larger parent' import $svnrepo/larger-parent &&
-        svn cp -m 'hi' $svnrepo/larger-parent $svnrepo/another-larger &&
+        svn import -m "import a larger parent" import "$svnrepo"/larger-parent &&
+        svn cp -m "hi" "$svnrepo"/larger-parent "$svnrepo"/another-larger &&
         git-svn init --minimize-url -i larger \
-          $svnrepo/another-larger/trunk/thunk/bump/thud &&
+          "$svnrepo"/another-larger/trunk/thunk/bump/thud &&
         git-svn fetch -i larger &&
         git rev-parse --verify refs/remotes/larger &&
         git rev-parse --verify \
            refs/remotes/larger-parent/trunk/thunk/bump/thud &&
-        test \"\`git merge-base \
+        test "`git merge-base \
                  refs/remotes/larger-parent/trunk/thunk/bump/thud \
-                 refs/remotes/larger\`\" = \
-             \"\`git rev-parse refs/remotes/larger\`\"
+                 refs/remotes/larger`" = \
+             "`git rev-parse refs/remotes/larger`"
         true
-        "
+        '
 
-test_expect_success 'follow higher-level parent' "
-        svn mkdir -m 'follow higher-level parent' $svnrepo/blob &&
-        svn co $svnrepo/blob blob &&
+test_expect_success 'follow higher-level parent' '
+        svn mkdir -m "follow higher-level parent" "$svnrepo"/blob &&
+        svn co "$svnrepo"/blob blob &&
         cd blob &&
                 echo hi > hi &&
                 svn add hi &&
-                svn commit -m 'hihi' &&
+                svn commit -m "hihi" &&
                 cd ..
-        svn mkdir -m 'new glob at top level' $svnrepo/glob &&
-        svn mv -m 'move blob down a level' $svnrepo/blob $svnrepo/glob/blob &&
-        git-svn init --minimize-url -i blob $svnrepo/glob/blob &&
+        svn mkdir -m "new glob at top level" "$svnrepo"/glob &&
+        svn mv -m "move blob down a level" "$svnrepo"/blob "$svnrepo"/glob/blob &&
+        git-svn init --minimize-url -i blob "$svnrepo"/glob/blob &&
         git-svn fetch -i blob
-        "
+        '
 
-test_expect_success 'follow deleted directory' "
-	svn mv -m 'bye!' $svnrepo/glob/blob/hi $svnrepo/glob/blob/bye &&
-	svn rm -m 'remove glob' $svnrepo/glob &&
-	git-svn init --minimize-url -i glob $svnrepo/glob &&
+test_expect_success 'follow deleted directory' '
+	svn mv -m "bye!" "$svnrepo"/glob/blob/hi "$svnrepo"/glob/blob/bye &&
+	svn rm -m "remove glob" "$svnrepo"/glob &&
+	git-svn init --minimize-url -i glob "$svnrepo"/glob &&
 	git-svn fetch -i glob &&
-	test \"\`git cat-file blob refs/remotes/glob:blob/bye\`\" = hi &&
-	test \"\`git ls-tree refs/remotes/glob | wc -l \`\" -eq 1
-	"
+	test "`git cat-file blob refs/remotes/glob:blob/bye`" = hi &&
+	test "`git ls-tree refs/remotes/glob | wc -l `" -eq 1
+	'
 
 # ref: r9270 of the Subversion repository: (http://svn.collab.net/repos/svn)
 # in trunk/subversion/bindings/swig/perl
-test_expect_success 'follow-parent avoids deleting relevant info' "
+test_expect_success 'follow-parent avoids deleting relevant info' '
 	mkdir -p import/trunk/subversion/bindings/swig/perl/t &&
 	for i in a b c ; do \
-	  echo \$i > import/trunk/subversion/bindings/swig/perl/\$i.pm &&
-	  echo _\$i > import/trunk/subversion/bindings/swig/perl/t/\$i.t; \
+	  echo $i > import/trunk/subversion/bindings/swig/perl/$i.pm &&
+	  echo _$i > import/trunk/subversion/bindings/swig/perl/t/$i.t; \
 	done &&
-	  echo 'bad delete test' > \
+	  echo "bad delete test" > \
 	   import/trunk/subversion/bindings/swig/perl/t/larger-parent &&
-	  echo 'bad delete test 2' > \
+	  echo "bad delete test 2" > \
 	   import/trunk/subversion/bindings/swig/perl/another-larger &&
 	cd import &&
-	  svn import -m 'r9270 test' . $svnrepo/r9270 &&
+	  svn import -m "r9270 test" . "$svnrepo"/r9270 &&
 	cd .. &&
-	svn co $svnrepo/r9270/trunk/subversion/bindings/swig/perl r9270 &&
+	svn co "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl r9270 &&
 	cd r9270 &&
 	  svn mkdir native &&
 	  svn mv t native/t &&
-	  for i in a b c; do svn mv \$i.pm native/\$i.pm; done &&
+	  for i in a b c; do svn mv $i.pm native/$i.pm; done &&
 	  echo z >> native/t/c.t &&
 	  poke native/t/c.t &&
-	  svn commit -m 'reorg test' &&
+	  svn commit -m "reorg test" &&
 	cd .. &&
 	git-svn init --minimize-url -i r9270-t \
-	  $svnrepo/r9270/trunk/subversion/bindings/swig/perl/native/t &&
+	  "$svnrepo"/r9270/trunk/subversion/bindings/swig/perl/native/t &&
 	git-svn fetch -i r9270-t &&
-	test \`git rev-list r9270-t | wc -l\` -eq 2 &&
-	test \"\`git ls-tree --name-only r9270-t~1\`\" = \
-	     \"\`git ls-tree --name-only r9270-t\`\"
-	"
+	test `git rev-list r9270-t | wc -l` -eq 2 &&
+	test "`git ls-tree --name-only r9270-t~1`" = \
+	     "`git ls-tree --name-only r9270-t`"
+	'
 
-test_expect_success "track initial change if it was only made to parent" "
-	svn cp -m 'wheee!' $svnrepo/r9270/trunk $svnrepo/r9270/drunk &&
+test_expect_success "track initial change if it was only made to parent" '
+	svn cp -m "wheee!" "$svnrepo"/r9270/trunk "$svnrepo"/r9270/drunk &&
 	git-svn init --minimize-url -i r9270-d \
-	  $svnrepo/r9270/drunk/subversion/bindings/swig/perl/native/t &&
+	  "$svnrepo"/r9270/drunk/subversion/bindings/swig/perl/native/t &&
 	git-svn fetch -i r9270-d &&
-	test \`git rev-list r9270-d | wc -l\` -eq 3 &&
-	test \"\`git ls-tree --name-only r9270-t\`\" = \
-	     \"\`git ls-tree --name-only r9270-d\`\" &&
-	test \"\`git rev-parse r9270-t\`\" = \
-	     \"\`git rev-parse r9270-d~1\`\"
-	"
+	test `git rev-list r9270-d | wc -l` -eq 3 &&
+	test "`git ls-tree --name-only r9270-t`" = \
+	     "`git ls-tree --name-only r9270-d`" &&
+	test "`git rev-parse r9270-t`" = \
+	     "`git rev-parse r9270-d~1`"
+	'
 
-test_expect_success "track multi-parent paths" "
-	svn cp -m 'resurrect /glob' $svnrepo/r9270 $svnrepo/glob &&
+test_expect_success "track multi-parent paths" '
+	svn cp -m "resurrect /glob" "$svnrepo"/r9270 "$svnrepo"/glob &&
 	git-svn multi-fetch &&
-	test \`git cat-file commit refs/remotes/glob | \
-	       grep '^parent ' | wc -l\` -eq 2
-	"
+	test `git cat-file commit refs/remotes/glob | \
+	       grep "^parent " | wc -l` -eq 2
+	'
 
 test_expect_success "multi-fetch continues to work" "
 	git-svn multi-fetch
 	"
 
-test_expect_success "multi-fetch works off a 'clean' repository" "
-	rm -r $GIT_DIR/svn $GIT_DIR/refs/remotes $GIT_DIR/logs &&
-	mkdir $GIT_DIR/svn &&
+test_expect_success "multi-fetch works off a 'clean' repository" '
+	rm -r "$GIT_DIR/svn" "$GIT_DIR/refs/remotes" "$GIT_DIR/logs" &&
+	mkdir "$GIT_DIR/svn" &&
 	git-svn multi-fetch
-	"
+	'
 
 test_debug 'gitk --all &'
 
diff --git a/t/t9105-git-svn-commit-diff.sh b/t/t9105-git-svn-commit-diff.sh
index 318e172..6323036 100755
--- a/t/t9105-git-svn-commit-diff.sh
+++ b/t/t9105-git-svn-commit-diff.sh
@@ -4,18 +4,18 @@
 test_description='git-svn commit-diff'
 . ./lib-git-svn.sh
 
-test_expect_success 'initialize repo' "
+test_expect_success 'initialize repo' '
 	mkdir import &&
 	cd import &&
 	echo hello > readme &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m "initial" . "$svnrepo" &&
 	cd .. &&
 	echo hello > readme &&
 	git update-index --add readme &&
-	git commit -a -m 'initial' &&
+	git commit -a -m "initial" &&
 	echo world >> readme &&
-	git commit -a -m 'another'
-	"
+	git commit -a -m "another"
+	'
 
 head=`git rev-parse --verify HEAD^0`
 prev=`git rev-parse --verify HEAD^1`
@@ -24,20 +24,20 @@ prev=`git rev-parse --verify HEAD^1`
 # commit, so only a basic test of functionality is needed since we've
 # already tested commit extensively elsewhere
 
-test_expect_success 'test the commit-diff command' "
-	test -n '$prev' && test -n '$head' &&
-	git-svn commit-diff -r1 '$prev' '$head' '$svnrepo' &&
-	svn co $svnrepo wc &&
+test_expect_success 'test the commit-diff command' '
+	test -n "$prev" && test -n "$head" &&
+	git-svn commit-diff -r1 "$prev" "$head" "$svnrepo" &&
+	svn co "$svnrepo" wc &&
 	cmp readme wc/readme
-	"
+	'
 
-test_expect_success 'commit-diff to a sub-directory (with git-svn config)' "
-	svn import -m 'sub-directory' import $svnrepo/subdir &&
-	git-svn init --minimize-url $svnrepo/subdir &&
+test_expect_success 'commit-diff to a sub-directory (with git-svn config)' '
+	svn import -m "sub-directory" import "$svnrepo"/subdir &&
+	git-svn init --minimize-url "$svnrepo"/subdir &&
 	git-svn fetch &&
-	git-svn commit-diff -r3 '$prev' '$head' &&
-	svn cat $svnrepo/subdir/readme > readme.2 &&
+	git-svn commit-diff -r3 "$prev" "$head" &&
+	svn cat "$svnrepo"/subdir/readme > readme.2 &&
 	cmp readme readme.2
-	"
+	'
 
 test_done
diff --git a/t/t9106-git-svn-commit-diff-clobber.sh b/t/t9106-git-svn-commit-diff-clobber.sh
index f74ab12..58a3a7b 100755
--- a/t/t9106-git-svn-commit-diff-clobber.sh
+++ b/t/t9106-git-svn-commit-diff-clobber.sh
@@ -4,56 +4,56 @@
 test_description='git-svn commit-diff clobber'
 . ./lib-git-svn.sh
 
-test_expect_success 'initialize repo' "
+test_expect_success 'initialize repo' '
 	mkdir import &&
 	cd import &&
 	echo initial > file &&
-	svn import -m 'initial' . $svnrepo &&
+	svn import -m "initial" . "$svnrepo" &&
 	cd .. &&
 	echo initial > file &&
 	git update-index --add file &&
-	git commit -a -m 'initial'
-	"
-test_expect_success 'commit change from svn side' "
-	svn co $svnrepo t.svn &&
+	git commit -a -m "initial"
+	'
+test_expect_success 'commit change from svn side' '
+	svn co "$svnrepo" t.svn &&
 	cd t.svn &&
 	echo second line from svn >> file &&
 	poke file &&
-	svn commit -m 'second line from svn' &&
+	svn commit -m "second line from svn" &&
 	cd .. &&
 	rm -rf t.svn
-	"
+	'
 
-test_expect_success 'commit conflicting change from git' "
+test_expect_success 'commit conflicting change from git' '
 	echo second line from git >> file &&
-	git commit -a -m 'second line from git' &&
-	! git-svn commit-diff -r1 HEAD~1 HEAD $svnrepo
-"
+	git commit -a -m "second line from git" &&
+	! git-svn commit-diff -r1 HEAD~1 HEAD "$svnrepo"
+'
 
-test_expect_success 'commit complementing change from git' "
+test_expect_success 'commit complementing change from git' '
 	git reset --hard HEAD~1 &&
 	echo second line from svn >> file &&
-	git commit -a -m 'second line from svn' &&
+	git commit -a -m "second line from svn" &&
 	echo third line from git >> file &&
-	git commit -a -m 'third line from git' &&
-	git-svn commit-diff -r2 HEAD~1 HEAD $svnrepo
-	"
+	git commit -a -m "third line from git" &&
+	git-svn commit-diff -r2 HEAD~1 HEAD "$svnrepo"
+	'
 
-test_expect_success 'dcommit fails to commit because of conflict' "
-	git-svn init $svnrepo &&
+test_expect_success 'dcommit fails to commit because of conflict' '
+	git-svn init "$svnrepo" &&
 	git-svn fetch &&
 	git reset --hard refs/remotes/git-svn &&
-	svn co $svnrepo t.svn &&
+	svn co "$svnrepo" t.svn &&
 	cd t.svn &&
 	echo fourth line from svn >> file &&
 	poke file &&
-	svn commit -m 'fourth line from svn' &&
+	svn commit -m "fourth line from svn" &&
 	cd .. &&
 	rm -rf t.svn &&
-	echo 'fourth line from git' >> file &&
-	git commit -a -m 'fourth line from git' &&
+	echo "fourth line from git" >> file &&
+	git commit -a -m "fourth line from git" &&
 	! git-svn dcommit
-	"
+	'
 
 test_expect_success 'dcommit does the svn equivalent of an index merge' "
 	git reset --hard refs/remotes/git-svn &&
@@ -66,15 +66,15 @@ test_expect_success 'dcommit does the svn equivalent of an index merge' "
 	git-svn dcommit
 	"
 
-test_expect_success 'commit another change from svn side' "
-	svn co $svnrepo t.svn &&
+test_expect_success 'commit another change from svn side' '
+	svn co "$svnrepo" t.svn &&
 	cd t.svn &&
 		echo third line from svn >> file &&
 		poke file &&
-		svn commit -m 'third line from svn' &&
+		svn commit -m "third line from svn" &&
 	cd .. &&
 	rm -rf t.svn
-	"
+	'
 
 test_expect_success 'multiple dcommit from git-svn will not clobber svn' "
 	git reset --hard refs/remotes/git-svn &&
diff --git a/t/t9106-git-svn-dcommit-clobber-series.sh b/t/t9106-git-svn-dcommit-clobber-series.sh
index ca8a00e..a400dc7 100755
--- a/t/t9106-git-svn-dcommit-clobber-series.sh
+++ b/t/t9106-git-svn-dcommit-clobber-series.sh
@@ -4,30 +4,30 @@
 test_description='git-svn dcommit clobber series'
 . ./lib-git-svn.sh
 
-test_expect_success 'initialize repo' "
+test_expect_success 'initialize repo' '
 	mkdir import &&
 	cd import &&
-	awk 'BEGIN { for (i = 1; i < 64; i++) { print i } }' > file
-	svn import -m 'initial' . $svnrepo &&
+	awk "BEGIN { for (i = 1; i < 64; i++) { print i } }" > file
+	svn import -m "initial" . "$svnrepo" &&
 	cd .. &&
-	git svn init $svnrepo &&
+	git svn init "$svnrepo" &&
 	git svn fetch &&
 	test -e file
-	"
+	'
 
-test_expect_success '(supposedly) non-conflicting change from SVN' "
-	test x\"\`sed -n -e 58p < file\`\" = x58 &&
-	test x\"\`sed -n -e 61p < file\`\" = x61 &&
-	svn co $svnrepo tmp &&
+test_expect_success '(supposedly) non-conflicting change from SVN' '
+	test x"`sed -n -e 58p < file`" = x58 &&
+	test x"`sed -n -e 61p < file`" = x61 &&
+	svn co "$svnrepo" tmp &&
 	cd tmp &&
-		perl -i -p -e 's/^58\$/5588/' file &&
-		perl -i -p -e 's/^61\$/6611/' file &&
+		perl -i -p -e "s/^58$/5588/" file &&
+		perl -i -p -e "s/^61$/6611/" file &&
 		poke file &&
-		test x\"\`sed -n -e 58p < file\`\" = x5588 &&
-		test x\"\`sed -n -e 61p < file\`\" = x6611 &&
-		svn commit -m '58 => 5588, 61 => 6611' &&
+		test x"`sed -n -e 58p < file`" = x5588 &&
+		test x"`sed -n -e 61p < file`" = x6611 &&
+		svn commit -m "58 => 5588, 61 => 6611" &&
 		cd ..
-	"
+	'
 
 test_expect_success 'some unrelated changes to git' "
 	echo hi > life &&
diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
index 0a41d52..d9b553a 100755
--- a/t/t9107-git-svn-migrate.sh
+++ b/t/t9107-git-svn-migrate.sh
@@ -3,61 +3,61 @@
 test_description='git-svn metadata migrations from previous versions'
 . ./lib-git-svn.sh
 
-test_expect_success 'setup old-looking metadata' "
-	cp $GIT_DIR/config $GIT_DIR/config-old-git-svn &&
+test_expect_success 'setup old-looking metadata' '
+	cp "$GIT_DIR"/config "$GIT_DIR"/config-old-git-svn &&
 	mkdir import &&
 	cd import &&
 		for i in trunk branches/a branches/b \
 		         tags/0.1 tags/0.2 tags/0.3; do
-			mkdir -p \$i && \
-			echo hello >> \$i/README || exit 1
+			mkdir -p $i && \
+			echo hello >> $i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . "$svnrepo"
 		cd .. &&
-	git-svn init $svnrepo &&
+	git-svn init "$svnrepo" &&
 	git-svn fetch &&
-	mv $GIT_DIR/svn/* $GIT_DIR/ &&
-	mv $GIT_DIR/svn/.metadata $GIT_DIR/ &&
-	rmdir $GIT_DIR/svn &&
+	mv "$GIT_DIR"/svn/* "$GIT_DIR"/ &&
+	mv "$GIT_DIR"/svn/.metadata "$GIT_DIR"/ &&
+	rmdir "$GIT_DIR"/svn &&
 	git update-ref refs/heads/git-svn-HEAD refs/remotes/git-svn &&
 	git update-ref refs/heads/svn-HEAD refs/remotes/git-svn &&
 	git update-ref -d refs/remotes/git-svn refs/remotes/git-svn
-	"
+	'
 
 head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
 test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
 
-test_expect_success 'initialize old-style (v0) git-svn layout' "
-	mkdir -p $GIT_DIR/git-svn/info $GIT_DIR/svn/info &&
-	echo $svnrepo > $GIT_DIR/git-svn/info/url &&
-	echo $svnrepo > $GIT_DIR/svn/info/url &&
+test_expect_success 'initialize old-style (v0) git-svn layout' '
+	mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info &&
+	echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url &&
+	echo "$svnrepo" > "$GIT_DIR"/svn/info/url &&
 	git-svn migrate &&
-	! test -d $GIT_DIR/git-svn &&
+	! test -d "$GIT_DIR"/git-svn &&
 	git rev-parse --verify refs/remotes/git-svn^0 &&
 	git rev-parse --verify refs/remotes/svn^0 &&
-	test \`git config --get svn-remote.svn.url\` = '$svnrepo' &&
-	test \`git config --get svn-remote.svn.fetch\` = \
-             ':refs/remotes/git-svn'
-	"
+	test "$(git config --get svn-remote.svn.url)" = "$svnrepo" &&
+	test `git config --get svn-remote.svn.fetch` = \
+             ":refs/remotes/git-svn"
+	'
 
-test_expect_success 'initialize a multi-repository repo' "
-	git-svn init $svnrepo -T trunk -t tags -b branches &&
+test_expect_success 'initialize a multi-repository repo' '
+	git-svn init "$svnrepo" -T trunk -t tags -b branches &&
 	git config --get-all svn-remote.svn.fetch > fetch.out &&
-	grep '^trunk:refs/remotes/trunk$' fetch.out &&
-	test -n \"\`git config --get svn-remote.svn.branches \
-	            '^branches/\*:refs/remotes/\*$'\`\" &&
-	test -n \"\`git config --get svn-remote.svn.tags \
-	            '^tags/\*:refs/remotes/tags/\*$'\`\" &&
+	grep "^trunk:refs/remotes/trunk$" fetch.out &&
+	test -n "`git config --get svn-remote.svn.branches \
+	            "^branches/\*:refs/remotes/\*$"`" &&
+	test -n "`git config --get svn-remote.svn.tags \
+	            "^tags/\*:refs/remotes/tags/\*$"`" &&
 	git config --unset svn-remote.svn.branches \
-	                        '^branches/\*:refs/remotes/\*$' &&
+	                        "^branches/\*:refs/remotes/\*$" &&
 	git config --unset svn-remote.svn.tags \
-	                        '^tags/\*:refs/remotes/tags/\*$' &&
-	git config --add svn-remote.svn.fetch 'branches/a:refs/remotes/a' &&
-	git config --add svn-remote.svn.fetch 'branches/b:refs/remotes/b' &&
+	                        "^tags/\*:refs/remotes/tags/\*$" &&
+	git config --add svn-remote.svn.fetch "branches/a:refs/remotes/a" &&
+	git config --add svn-remote.svn.fetch "branches/b:refs/remotes/b" &&
 	for i in tags/0.1 tags/0.2 tags/0.3; do
 		git config --add svn-remote.svn.fetch \
-		                 \$i:refs/remotes/\$i || exit 1; done
-	"
+		                 $i:refs/remotes/$i || exit 1; done
+	'
 
 # refs should all be different, but the trees should all be the same:
 test_expect_success 'multi-fetch works on partial urls + paths' "
@@ -73,43 +73,43 @@ test_expect_success 'multi-fetch works on partial urls + paths' "
 	                         refs/remotes/\$j\`\" ||exit 1; done; done
 	"
 
-test_expect_success 'migrate --minimize on old inited layout' "
+test_expect_success 'migrate --minimize on old inited layout' '
 	git config --unset-all svn-remote.svn.fetch &&
 	git config --unset-all svn-remote.svn.url &&
-	rm -rf $GIT_DIR/svn &&
-	for i in \`cat fetch.out\`; do
-		path=\`expr \$i : '\\([^:]*\\):.*$'\`
-		ref=\`expr \$i : '[^:]*:refs/remotes/\\(.*\\)$'\`
-		if test -z \"\$ref\"; then continue; fi
-		if test -n \"\$path\"; then path=\"/\$path\"; fi
-		( mkdir -p $GIT_DIR/svn/\$ref/info/ &&
-		echo $svnrepo\$path > $GIT_DIR/svn/\$ref/info/url ) || exit 1;
+	rm -rf "$GIT_DIR"/svn &&
+	for i in `cat fetch.out`; do
+		path=`expr $i : "\([^:]*\):.*$"`
+		ref=`expr $i : "[^:]*:refs/remotes/\(.*\)$"`
+		if test -z "$ref"; then continue; fi
+		if test -n "$path"; then path="/$path"; fi
+		( mkdir -p "$GIT_DIR"/svn/$ref/info/ &&
+		echo "$svnrepo"$path > "$GIT_DIR"/svn/$ref/info/url ) || exit 1;
 	done &&
 	git-svn migrate --minimize &&
-	test -z \"\`git config -l |grep -v '^svn-remote\.git-svn\.'\`\" &&
+	test -z "`git config -l |grep -v "^svn-remote\.git-svn\."`" &&
 	git config --get-all svn-remote.svn.fetch > fetch.out &&
-	grep '^trunk:refs/remotes/trunk$' fetch.out &&
-	grep '^branches/a:refs/remotes/a$' fetch.out &&
-	grep '^branches/b:refs/remotes/b$' fetch.out &&
-	grep '^tags/0\.1:refs/remotes/tags/0\.1$' fetch.out &&
-	grep '^tags/0\.2:refs/remotes/tags/0\.2$' fetch.out &&
-	grep '^tags/0\.3:refs/remotes/tags/0\.3$' fetch.out
-	grep '^:refs/remotes/git-svn' fetch.out
-	"
+	grep "^trunk:refs/remotes/trunk$" fetch.out &&
+	grep "^branches/a:refs/remotes/a$" fetch.out &&
+	grep "^branches/b:refs/remotes/b$" fetch.out &&
+	grep "^tags/0\.1:refs/remotes/tags/0\.1$" fetch.out &&
+	grep "^tags/0\.2:refs/remotes/tags/0\.2$" fetch.out &&
+	grep "^tags/0\.3:refs/remotes/tags/0\.3$" fetch.out
+	grep "^:refs/remotes/git-svn" fetch.out
+	'
 
-test_expect_success  ".rev_db auto-converted to .rev_map.UUID" "
+test_expect_success  ".rev_db auto-converted to .rev_map.UUID" '
 	git-svn fetch -i trunk &&
-	test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
-	expect=\"\$(ls $GIT_DIR/svn/trunk/.rev_map.*)\" &&
-	test -n \"\$expect\" &&
-	rev_db=\$(echo \$expect | sed -e 's,_map,_db,') &&
-	convert_to_rev_db \$expect \$rev_db &&
-	rm -f \$expect &&
-	test -f \$rev_db &&
+	test -z "$(ls "$GIT_DIR"/svn/trunk/.rev_db.* 2>/dev/null)" &&
+	expect="$(ls "$GIT_DIR"/svn/trunk/.rev_map.*)" &&
+	test -n "$expect" &&
+	rev_db="$(echo $expect | sed -e "s,_map,_db,")" &&
+	convert_to_rev_db "$expect" "$rev_db" &&
+	rm -f "$expect" &&
+	test -f "$rev_db" &&
 	git-svn fetch -i trunk &&
-	test -z \"\$(ls $GIT_DIR/svn/trunk/.rev_db.* 2>/dev/null)\" &&
-	test ! -e $GIT_DIR/svn/trunk/.rev_db &&
-	test -f \$expect
-	"
+	test -z "$(ls "$GIT_DIR"/svn/trunk/.rev_db.* 2>/dev/null)" &&
+	test ! -e "$GIT_DIR"/svn/trunk/.rev_db &&
+	test -f "$expect"
+	'
 
 test_done
diff --git a/t/t9108-git-svn-glob.sh b/t/t9108-git-svn-glob.sh
index db4344c..f6f71d0 100755
--- a/t/t9108-git-svn-glob.sh
+++ b/t/t9108-git-svn-glob.sh
@@ -10,77 +10,77 @@ start a new branch
 initial
 EOF
 
-test_expect_success 'test refspec globbing' "
+test_expect_success 'test refspec globbing' '
 	mkdir -p trunk/src/a trunk/src/b trunk/doc &&
-	echo 'hello world' > trunk/src/a/readme &&
-	echo 'goodbye world' > trunk/src/b/readme &&
-	svn import -m 'initial' trunk $svnrepo/trunk &&
-	svn co $svnrepo tmp &&
+	echo "hello world" > trunk/src/a/readme &&
+	echo "goodbye world" > trunk/src/b/readme &&
+	svn import -m "initial" trunk "$svnrepo"/trunk &&
+	svn co "$svnrepo" tmp &&
 	cd tmp &&
 		mkdir branches tags &&
 		svn add branches tags &&
 		svn cp trunk branches/start &&
-		svn commit -m 'start a new branch' &&
+		svn commit -m "start a new branch" &&
 		svn up &&
-		echo 'hi' >> branches/start/src/b/readme &&
+		echo "hi" >> branches/start/src/b/readme &&
 		poke branches/start/src/b/readme &&
-		echo 'hey' >> branches/start/src/a/readme &&
+		echo "hey" >> branches/start/src/a/readme &&
 		poke branches/start/src/a/readme &&
-		svn commit -m 'hi' &&
+		svn commit -m "hi" &&
 		svn up &&
 		svn cp branches/start tags/end &&
-		echo 'bye' >> tags/end/src/b/readme &&
+		echo "bye" >> tags/end/src/b/readme &&
 		poke tags/end/src/b/readme &&
-		echo 'aye' >> tags/end/src/a/readme &&
+		echo "aye" >> tags/end/src/a/readme &&
 		poke tags/end/src/a/readme &&
-		svn commit -m 'the end' &&
-		echo 'byebye' >> tags/end/src/b/readme &&
+		svn commit -m "the end" &&
+		echo "byebye" >> tags/end/src/b/readme &&
 		poke tags/end/src/b/readme &&
-		svn commit -m 'nothing to see here'
+		svn commit -m "nothing to see here"
 		cd .. &&
-	git config --add svn-remote.svn.url $svnrepo &&
+	git config --add svn-remote.svn.url "$svnrepo" &&
 	git config --add svn-remote.svn.fetch \
-	                 'trunk/src/a:refs/remotes/trunk' &&
+	                 "trunk/src/a:refs/remotes/trunk" &&
 	git config --add svn-remote.svn.branches \
-	                 'branches/*/src/a:refs/remotes/branches/*' &&
+	                 "branches/*/src/a:refs/remotes/branches/*" &&
 	git config --add svn-remote.svn.tags\
-	                 'tags/*/src/a:refs/remotes/tags/*' &&
+	                 "tags/*/src/a:refs/remotes/tags/*" &&
 	git-svn multi-fetch &&
 	git log --pretty=oneline refs/remotes/tags/end | \
-	    sed -e 's/^.\{41\}//' > output.end &&
+	    sed -e "s/^.\{41\}//" > output.end &&
 	cmp expect.end output.end &&
-	test \"\`git rev-parse refs/remotes/tags/end~1\`\" = \
-		\"\`git rev-parse refs/remotes/branches/start\`\" &&
-	test \"\`git rev-parse refs/remotes/branches/start~2\`\" = \
-		\"\`git rev-parse refs/remotes/trunk\`\"
-	"
+	test "`git rev-parse refs/remotes/tags/end~1`" = \
+		"`git rev-parse refs/remotes/branches/start`" &&
+	test "`git rev-parse refs/remotes/branches/start~2`" = \
+		"`git rev-parse refs/remotes/trunk`"
+	'
 
 echo try to try > expect.two
 echo nothing to see here >> expect.two
 cat expect.end >> expect.two
 
-test_expect_success 'test left-hand-side only globbing' "
-	git config --add svn-remote.two.url $svnrepo &&
+test_expect_success 'test left-hand-side only globbing' '
+	git config --add svn-remote.two.url "$svnrepo" &&
 	git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
 	git config --add svn-remote.two.branches \
-	                 'branches/*:refs/remotes/two/branches/*' &&
+	                 "branches/*:refs/remotes/two/branches/*" &&
 	git config --add svn-remote.two.tags \
-	                 'tags/*:refs/remotes/two/tags/*' &&
+	                 "tags/*:refs/remotes/two/tags/*" &&
 	cd tmp &&
-		echo 'try try' >> tags/end/src/b/readme &&
+		echo "try try" >> tags/end/src/b/readme &&
 		poke tags/end/src/b/readme &&
-		svn commit -m 'try to try'
+		svn commit -m "try to try"
 		cd .. &&
 	git-svn fetch two &&
-	test \`git rev-list refs/remotes/two/tags/end | wc -l\` -eq 6 &&
-	test \`git rev-list refs/remotes/two/branches/start | wc -l\` -eq 3 &&
-	test \`git rev-parse refs/remotes/two/branches/start~2\` = \
-	     \`git rev-parse refs/remotes/two/trunk\` &&
-	test \`git rev-parse refs/remotes/two/tags/end~3\` = \
-	     \`git rev-parse refs/remotes/two/branches/start\` &&
+	test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 &&
+	test `git rev-list refs/remotes/two/branches/start | wc -l` -eq 3 &&
+	test `git rev-parse refs/remotes/two/branches/start~2` = \
+	     `git rev-parse refs/remotes/two/trunk` &&
+	test `git rev-parse refs/remotes/two/tags/end~3` = \
+	     `git rev-parse refs/remotes/two/branches/start` &&
 	git log --pretty=oneline refs/remotes/two/tags/end | \
-	    sed -e 's/^.\{41\}//' > output.two &&
+	    sed -e "s/^.\{41\}//" > output.two &&
 	cmp expect.two output.two
-	"
+	'
 
 test_done
diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh
index 6235af4..047659f 100755
--- a/t/t9110-git-svn-use-svm-props.sh
+++ b/t/t9110-git-svn-use-svm-props.sh
@@ -7,15 +7,15 @@ test_description='git-svn useSvmProps test'
 
 . ./lib-git-svn.sh
 
-test_expect_success 'load svm repo' "
-	svnadmin load -q $rawsvnrepo < ../t9110/svm.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/mirror/arr &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/mirror/argh &&
+test_expect_success 'load svm repo' '
+	svnadmin load -q "$rawsvnrepo" < ../t9110/svm.dump &&
+	git-svn init --minimize-url -R arr -i bar "$svnrepo"/mirror/arr &&
+	git-svn init --minimize-url -R argh -i dir "$svnrepo"/mirror/argh &&
 	git-svn init --minimize-url -R argh -i e \
-	  $svnrepo/mirror/argh/a/b/c/d/e &&
+	  "$svnrepo"/mirror/argh/a/b/c/d/e &&
 	git config svn.useSvmProps true &&
 	git-svn fetch --all
-	"
+	'
 
 uuid=161ce429-a9dd-4828-af4a-52023f968c89
 
diff --git a/t/t9111-git-svn-use-svnsync-props.sh b/t/t9111-git-svn-use-svnsync-props.sh
index ec7dedd..a8d74dc 100755
--- a/t/t9111-git-svn-use-svnsync-props.sh
+++ b/t/t9111-git-svn-use-svnsync-props.sh
@@ -7,14 +7,14 @@ test_description='git-svn useSvnsyncProps test'
 
 . ./lib-git-svn.sh
 
-test_expect_success 'load svnsync repo' "
-	svnadmin load -q $rawsvnrepo < ../t9111/svnsync.dump &&
-	git-svn init --minimize-url -R arr -i bar $svnrepo/bar &&
-	git-svn init --minimize-url -R argh -i dir $svnrepo/dir &&
-	git-svn init --minimize-url -R argh -i e $svnrepo/dir/a/b/c/d/e &&
+test_expect_success 'load svnsync repo' '
+	svnadmin load -q "$rawsvnrepo" < ../t9111/svnsync.dump &&
+	git-svn init --minimize-url -R arr -i bar "$svnrepo"/bar &&
+	git-svn init --minimize-url -R argh -i dir "$svnrepo"/dir &&
+	git-svn init --minimize-url -R argh -i e "$svnrepo"/dir/a/b/c/d/e &&
 	git config svn.useSvnsyncProps true &&
 	git-svn fetch --all
-	"
+	'
 
 uuid=161ce429-a9dd-4828-af4a-52023f968c89
 
diff --git a/t/t9112-git-svn-md5less-file.sh b/t/t9112-git-svn-md5less-file.sh
index 646a5f0..d470a92 100755
--- a/t/t9112-git-svn-md5less-file.sh
+++ b/t/t9112-git-svn-md5less-file.sh
@@ -40,8 +40,8 @@ PROPS-END
 
 EOF
 
-test_expect_success 'load svn dumpfile' "svnadmin load $rawsvnrepo < dumpfile.svn"
+test_expect_success 'load svn dumpfile' 'svnadmin load "$rawsvnrepo" < dumpfile.svn'
 
-test_expect_success 'initialize git-svn' "git-svn init $svnrepo"
+test_expect_success 'initialize git-svn' 'git-svn init "$svnrepo"'
 test_expect_success 'fetch revisions from svn' 'git-svn fetch'
 test_done
diff --git a/t/t9113-git-svn-dcommit-new-file.sh b/t/t9113-git-svn-dcommit-new-file.sh
index 9ef0db9..31c929b 100755
--- a/t/t9113-git-svn-dcommit-new-file.sh
+++ b/t/t9113-git-svn-dcommit-new-file.sh
@@ -15,18 +15,18 @@ test_description='git-svn dcommit new files over svn:// test'
 
 start_svnserve () {
 	svnserve --listen-port $SVNSERVE_PORT \
-	         --root $rawsvnrepo \
+	         --root "$rawsvnrepo" \
 	         --listen-once \
 	         --listen-host 127.0.0.1 &
 }
 
-test_expect_success 'start tracking an empty repo' "
-	svn mkdir -m 'empty dir' $svnrepo/empty-dir &&
-	echo anon-access = write >> $rawsvnrepo/conf/svnserve.conf &&
+test_expect_success 'start tracking an empty repo' '
+	svn mkdir -m "empty dir" "$svnrepo"/empty-dir &&
+	echo anon-access = write >> "$rawsvnrepo"/conf/svnserve.conf &&
 	start_svnserve &&
 	git svn init svn://127.0.0.1:$SVNSERVE_PORT &&
 	git svn fetch
-	"
+	'
 
 test_expect_success 'create files in new directory with dcommit' "
 	mkdir git-new-dir &&
diff --git a/t/t9114-git-svn-dcommit-merge.sh b/t/t9114-git-svn-dcommit-merge.sh
index 225060b..61d7781 100755
--- a/t/t9114-git-svn-dcommit-merge.sh
+++ b/t/t9114-git-svn-dcommit-merge.sh
@@ -34,35 +34,35 @@ cat << EOF
 EOF
 }
 
-test_expect_success 'setup svn repository' "
-	svn co $svnrepo mysvnwork &&
+test_expect_success 'setup svn repository' '
+	svn co "$svnrepo" mysvnwork &&
 	mkdir -p mysvnwork/trunk &&
 	cd mysvnwork &&
 		big_text_block >> trunk/README &&
 		svn add trunk &&
-		svn ci -m 'first commit' trunk &&
+		svn ci -m "first commit" trunk &&
 		cd ..
-	"
+	'
 
-test_expect_success 'setup git mirror and merge' "
-	git svn init $svnrepo -t tags -T trunk -b branches &&
+test_expect_success 'setup git mirror and merge' '
+	git svn init "$svnrepo" -t tags -T trunk -b branches &&
 	git svn fetch &&
 	git checkout --track -b svn remotes/trunk &&
 	git checkout -b merge &&
 	echo new file > new_file &&
 	git add new_file &&
-	git commit -a -m 'New file' &&
+	git commit -a -m "New file" &&
 	echo hello >> README &&
-	git commit -a -m 'hello' &&
+	git commit -a -m "hello" &&
 	echo add some stuff >> new_file &&
-	git commit -a -m 'add some stuff' &&
+	git commit -a -m "add some stuff" &&
 	git checkout svn &&
 	mv -f README tmp &&
 	echo friend > README &&
 	cat tmp >> README &&
-	git commit -a -m 'friend' &&
+	git commit -a -m "friend" &&
 	git pull . merge
-	"
+	'
 
 test_debug 'gitk --all & sleep 1'
 
diff --git a/t/t9115-git-svn-dcommit-funky-renames.sh b/t/t9115-git-svn-dcommit-funky-renames.sh
index 182299c..298445f 100755
--- a/t/t9115-git-svn-dcommit-funky-renames.sh
+++ b/t/t9115-git-svn-dcommit-funky-renames.sh
@@ -7,16 +7,16 @@ test_description='git-svn dcommit can commit renames of files with ugly names'
 
 . ./lib-git-svn.sh
 
-test_expect_success 'load repository with strange names' "
-	svnadmin load -q $rawsvnrepo < ../t9115/funky-names.dump &&
+test_expect_success 'load repository with strange names' '
+	svnadmin load -q "$rawsvnrepo" < ../t9115/funky-names.dump &&
 	start_httpd
-	"
+	'
 
-test_expect_success 'init and fetch repository' "
-	git svn init $svnrepo &&
+test_expect_success 'init and fetch repository' '
+	git svn init "$svnrepo" &&
 	git svn fetch &&
 	git reset --hard git-svn
-	"
+	'
 
 test_expect_success 'create file in existing ugly and empty dir' '
 	mkdir "#{bad_directory_name}" &&
diff --git a/t/t9116-git-svn-log.sh b/t/t9116-git-svn-log.sh
index e1e8bdf..4b2cc87 100755
--- a/t/t9116-git-svn-log.sh
+++ b/t/t9116-git-svn-log.sh
@@ -6,17 +6,17 @@
 test_description='git-svn log tests'
 . ./lib-git-svn.sh
 
-test_expect_success 'setup repository and import' "
+test_expect_success 'setup repository and import' '
 	mkdir import &&
 	cd import &&
 		for i in trunk branches/a branches/b \
 		         tags/0.1 tags/0.2 tags/0.3; do
-			mkdir -p \$i && \
-			echo hello >> \$i/README || exit 1
+			mkdir -p $i && \
+			echo hello >> $i/README || exit 1
 		done && \
-		svn import -m test . $svnrepo
+		svn import -m test . "$svnrepo"
 		cd .. &&
-	git-svn init $svnrepo -T trunk -b branches -t tags &&
+	git-svn init "$svnrepo" -T trunk -b branches -t tags &&
 	git-svn fetch &&
 	git reset --hard trunk &&
 	echo bye >> README &&
@@ -37,7 +37,7 @@ test_expect_success 'setup repository and import' "
 	echo try >> README &&
 	git commit -a -m try &&
 	git svn dcommit
-	"
+	'
 
 test_expect_success 'run log' "
 	git reset --hard a &&
diff --git a/t/t9117-git-svn-init-clone.sh b/t/t9117-git-svn-init-clone.sh
index d482b40..7a689bb 100755
--- a/t/t9117-git-svn-init-clone.sh
+++ b/t/t9117-git-svn-init-clone.sh
@@ -13,43 +13,43 @@ rm -r .git
 mkdir tmp
 cd tmp
 
-test_expect_success 'setup svnrepo' "
+test_expect_success 'setup svnrepo' '
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project $svnrepo/project &&
+	svn import -m "$test_description" project "$svnrepo"/project &&
 	rm -rf project
-	"
+	'
 
-test_expect_success 'basic clone' "
+test_expect_success 'basic clone' '
 	test ! -d trunk &&
-	git svn clone $svnrepo/project/trunk &&
+	git svn clone "$svnrepo"/project/trunk &&
 	test -d trunk/.git/svn &&
 	test -e trunk/foo &&
 	rm -rf trunk
-	"
+	'
 
-test_expect_success 'clone to target directory' "
+test_expect_success 'clone to target directory' '
 	test ! -d target &&
-	git svn clone $svnrepo/project/trunk target &&
+	git svn clone "$svnrepo"/project/trunk target &&
 	test -d target/.git/svn &&
 	test -e target/foo &&
 	rm -rf target
-	"
+	'
 
-test_expect_success 'clone with --stdlayout' "
+test_expect_success 'clone with --stdlayout' '
 	test ! -d project &&
-	git svn clone -s $svnrepo/project &&
+	git svn clone -s "$svnrepo"/project &&
 	test -d project/.git/svn &&
 	test -e project/foo &&
 	rm -rf project
-	"
+	'
 
-test_expect_success 'clone to target directory with --stdlayout' "
+test_expect_success 'clone to target directory with --stdlayout' '
 	test ! -d target &&
-	git svn clone -s $svnrepo/project target &&
+	git svn clone -s "$svnrepo"/project target &&
 	test -d target/.git/svn &&
 	test -e target/foo &&
 	rm -rf target
-	"
+	'
 
 test_done
diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh
index 640bb06..3281cbd 100755
--- a/t/t9118-git-svn-funky-branch-names.sh
+++ b/t/t9118-git-svn-funky-branch-names.sh
@@ -6,25 +6,25 @@
 test_description='git-svn funky branch names'
 . ./lib-git-svn.sh
 
-test_expect_success 'setup svnrepo' "
+test_expect_success 'setup svnrepo' '
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project \"$svnrepo/pr ject\" &&
+	svn import -m "$test_description" project "$svnrepo/pr ject" &&
 	rm -rf project &&
-	svn cp -m 'fun' \"$svnrepo/pr ject/trunk\" \
-	                \"$svnrepo/pr ject/branches/fun plugin\" &&
-	svn cp -m 'more fun!' \"$svnrepo/pr ject/branches/fun plugin\" \
-	                      \"$svnrepo/pr ject/branches/more fun plugin!\" &&
+	svn cp -m "fun" "$svnrepo/pr ject/trunk" \
+	                "$svnrepo/pr ject/branches/fun plugin" &&
+	svn cp -m "more fun!" "$svnrepo/pr ject/branches/fun plugin" \
+	                      "$svnrepo/pr ject/branches/more fun plugin!" &&
 	start_httpd
-	"
+	'
 
-test_expect_success 'test clone with funky branch names' "
-	git svn clone -s \"$svnrepo/pr ject\" project &&
+test_expect_success 'test clone with funky branch names' '
+	git svn clone -s "$svnrepo/pr ject" project &&
 	cd project &&
-		git rev-parse 'refs/remotes/fun%20plugin' &&
-		git rev-parse 'refs/remotes/more%20fun%20plugin!' &&
+		git rev-parse "refs/remotes/fun%20plugin" &&
+		git rev-parse "refs/remotes/more%20fun%20plugin!" &&
 	cd ..
-	"
+	'
 
 test_expect_success 'test dcommit to funky branch' "
 	cd project &&
diff --git a/t/t9120-git-svn-clone-with-percent-escapes.sh b/t/t9120-git-svn-clone-with-percent-escapes.sh
index 9a4eabe..5979e13 100755
--- a/t/t9120-git-svn-clone-with-percent-escapes.sh
+++ b/t/t9120-git-svn-clone-with-percent-escapes.sh
@@ -6,13 +6,13 @@
 test_description='git-svn clone with percent escapes'
 . ./lib-git-svn.sh
 
-test_expect_success 'setup svnrepo' "
+test_expect_success 'setup svnrepo' '
 	mkdir project project/trunk project/branches project/tags &&
 	echo foo > project/trunk/foo &&
-	svn import -m '$test_description' project '$svnrepo/pr ject' &&
+	svn import -m "$test_description" project "$svnrepo/pr ject" &&
 	rm -rf project &&
 	start_httpd
-"
+'
 
 if test "$SVN_HTTPD_PORT" = ""
 then
diff --git a/t/t9500-gitweb-standalone-no-errors.sh b/t/t9500-gitweb-standalone-no-errors.sh
index 3dc261d..ae7082b 100755
--- a/t/t9500-gitweb-standalone-no-errors.sh
+++ b/t/t9500-gitweb-standalone-no-errors.sh
@@ -10,6 +10,7 @@ commandline, and checks that it would not write any errors
 or warnings to log.'
 
 gitweb_init () {
+	safe_pwd="$(perl -MPOSIX=getcwd -e 'print quotemeta(getcwd)')"
 	cat >gitweb_config.perl <<EOF
 #!/usr/bin/perl
 
@@ -17,16 +18,16 @@ gitweb_init () {
 
 our \$version = "current";
 our \$GIT = "git";
-our \$projectroot = "$(pwd)";
+our \$projectroot = "$safe_pwd";
 our \$project_maxdepth = 8;
 our \$home_link_str = "projects";
 our \$site_name = "[localhost]";
 our \$site_header = "";
 our \$site_footer = "";
 our \$home_text = "indextext.html";
-our @stylesheets = ("file:///$(pwd)/../../gitweb/gitweb.css");
-our \$logo = "file:///$(pwd)/../../gitweb/git-logo.png";
-our \$favicon = "file:///$(pwd)/../../gitweb/git-favicon.png";
+our @stylesheets = ("file:///$safe_pwd/../../gitweb/gitweb.css");
+our \$logo = "file:///$safe_pwd/../../gitweb/git-logo.png";
+our \$favicon = "file:///$safe_pwd/../../gitweb/git-favicon.png";
 our \$projects_list = "";
 our \$export_ok = "";
 our \$strict_export = "";
@@ -53,7 +54,7 @@ gitweb_run () {
 	# written to web server logs, so we are not interested in that:
 	# we are interested only in properly formatted errors/warnings
 	rm -f gitweb.log &&
-	perl -- $(pwd)/../../gitweb/gitweb.perl \
+	perl -- "$(pwd)/../../gitweb/gitweb.perl" \
 		>/dev/null 2>gitweb.log &&
 	if grep -q -s "^[[]" gitweb.log >/dev/null; then false; else true; fi
 
-- 
1.5.5.1.128.g03a943

^ permalink raw reply related	[relevance 8%]

Results 1-200 of ~5000   | reverse | options above
-- pct% links below jump to the message on this page, permalinks otherwise --
2005-05-09 16:29  2% Git-aware Darcs: a tutorial Juliusz Chroboczek
2005-07-03 23:46     [ANNOUNCE] Cogito-0.12 Petr Baudis
2005-07-06 12:01     ` Brian Gerst
2005-07-07 14:45       ` Petr Baudis
2005-07-07 17:21         ` Junio C Hamano
2005-07-07 19:04           ` Linus Torvalds
2005-07-07 22:14             ` Petr Baudis
2005-07-07 22:52               ` Linus Torvalds
2005-07-07 23:16                 ` [PATCH] Pull efficiently from a dumb git store Junio C Hamano
2005-07-07 23:50                   ` [PATCH] rev-list: add "--objects=self-sufficient" flag Junio C Hamano
2005-07-07 23:58                     ` Linus Torvalds
2005-07-08  1:02                       ` [PATCH] rev-list: add "--full-objects" flag Junio C Hamano
2005-07-08  1:46                         ` Linus Torvalds
2005-07-08  2:17                           ` Junio C Hamano
2005-07-08  2:39                             ` Linus Torvalds
2005-07-09 21:09                               ` Eric W. Biederman
2005-07-10 22:36                                 ` Linus Torvalds
2005-07-11 15:19                                   ` Eric W. Biederman
2005-07-11 16:38  1%                                 ` Linus Torvalds
2005-07-14  7:08     [PATCH] Documentation: packed GIT support commands Junio C Hamano
2005-07-15  7:59     ` [PATCH] Documentation: update tutorial to talk about push Junio C Hamano
2005-07-15 21:40       ` [PATCH] fetch/pull: support Cogito-style remote branch information Junio C Hamano
2005-07-15 22:42         ` Linus Torvalds
2005-07-16  7:16  3%       ` [PATCH] fetch/pull: short-hand notation for remote repositories Junio C Hamano
2005-08-18  7:24     Multi-head pulling series Junio C Hamano
2005-08-18  7:39  6% ` [PATCH 1/3] Start adding the $GIT_DIR/remotes/ support Junio C Hamano
2005-08-20 18:13     Updated multi-head downloads and " Junio C Hamano
2005-08-20 18:22  6% ` [PATCH] Start adding the " Junio C Hamano
2005-09-19  3:18     [BUG] git-show-branch cant show --more Jon Loeliger
2005-09-19  8:12  3% ` Junio C Hamano
2005-09-26 22:23     Cogito: cg-clone doesn't like packed tag objects Junio C Hamano
2005-09-26 22:37     ` Junio C Hamano
2005-09-23 22:24       ` H. Peter Anvin
2005-09-24  1:18         ` Petr Baudis
2005-09-26 21:25           ` Petr Baudis
2005-09-26 22:29             ` Petr Baudis
2005-09-27  4:46               ` Junio C Hamano
2005-09-27  5:02                 ` Tom Prince
2005-09-27  5:28                   ` Junio C Hamano
2005-09-27  9:40                     ` Petr Baudis
2005-09-27 17:07                       ` Junio C Hamano
2005-09-27 17:56  3%                     ` Linus Torvalds
2005-09-27 18:36  2%                       ` Junio C Hamano
2005-10-03  0:12  3% GIT 0.99.8 Junio C Hamano
2005-10-25 21:34  7% [WIP] Implement a test for git-fetch-pack Johannes Schindelin
2005-10-31 18:23     git push sends more objects than it needs to Luck, Tony
2005-10-31 18:44     ` Linus Torvalds
2005-10-31 19:36  2%   ` Linus Torvalds
2005-11-01  0:25     git versus CVS (versus bk) Theodore Ts'o
2005-11-01  9:23     ` hgmq vs. StGIT Catalin Marinas
2005-11-01 15:20       ` Chuck Lever
2005-11-01 15:36         ` Chris Mason
2005-11-01 17:18           ` Catalin Marinas
2005-11-01 18:13             ` Chris Mason
2005-11-01 21:30               ` Catalin Marinas
2005-11-02 15:41                 ` Chris Mason
2005-11-05 20:23                   ` Catalin Marinas
2005-11-09 23:32                     ` Petr Baudis
2005-11-10 16:20  3%                   ` Catalin Marinas
2005-11-16 12:24     [QUESTION] Access to a huge GIT repository Franck
2005-11-17 10:36     ` Franck
2005-11-17 16:23       ` Linus Torvalds
2005-11-17 21:47         ` Franck
2005-11-17 22:44           ` Linus Torvalds
2005-11-19 12:23             ` Franck
2005-11-19 17:56               ` Linus Torvalds
2005-11-19 19:52                 ` Junio C Hamano
2005-11-21 20:11                   ` Franck
2005-11-21 20:45                     ` Junio C Hamano
2005-11-22  9:22                       ` Franck
2005-11-22  9:50  3%                     ` Junio C Hamano
2005-11-22 10:40  0%                       ` Franck
2005-12-04 21:34     git-name-rev off-by-one bug Petr Baudis
2005-12-08  6:34  1% ` as promised, docs: git for the confused linux
     [not found]     <7vbqzrcmgr.fsf@assigned-by-dhcp.cox.net>
2005-12-09  5:44  1% ` linux
2005-12-15  0:44     How to clone-pack the HEAD? Petr Baudis
2005-12-15  1:20     ` Junio C Hamano
2005-12-15  1:32       ` Petr Baudis
2005-12-15  1:45         ` Junio C Hamano
2005-12-15  1:53           ` Junio C Hamano
2005-12-15  5:29  8%         ` Junio C Hamano
2006-01-30  7:18  4% [RFC] shallow clone Junio C Hamano
     [not found]     ` <43DF1F1D.1060704@innova-card.com>
2006-01-31  9:00  1%   ` Franck
2006-02-11  4:31     Make "git clone" less of a deathly quiet experience Linus Torvalds
2006-02-11  5:48     ` Junio C Hamano
2006-02-11  7:35  4%   ` Craig Schlenter
2006-02-11  8:44  1%     ` Radoslaw Szkodzinski
2006-02-11 13:05  2%       ` Petr Baudis
2006-02-14 16:28     several quick questions Nicolas Vilz 'niv'
2006-02-14 17:05     ` Linus Torvalds
2006-02-14 18:10       ` Carl Worth
2006-02-14 18:55         ` Keith Packard
2006-02-14 19:04           ` Linus Torvalds
2006-02-14 19:39             ` Keith Packard
2006-02-15  4:11               ` Martin Langhoff
2006-02-15  5:25                 ` Keith Packard
2006-02-15  8:21  3%               ` Carl Worth
2006-02-16  6:57  3% What's in git.git Junio C Hamano
2006-02-16  7:38  1% [ANNOUNCE] git-svn - bidirection operations between svn and git Eric Wong
2006-02-16 13:42     ` Eduardo Pereira Habkost
2006-02-16 19:25  2%   ` Eric Wong
2006-02-26  0:19  1% [PATCH] First cut at libifying revlist generation Linus Torvalds
2006-04-02 10:41     Solaris cloning woes partly diagnosed Junio C Hamano
2006-04-02 18:33  4% ` Linus Torvalds
2006-04-02 19:18  1%   ` Linus Torvalds
2006-04-04 18:21  1%   ` H. Peter Anvin
2006-04-02 19:10     Jason Riedy
2006-04-02 19:22  4% ` Linus Torvalds
2006-04-13 22:01  6% [PATCH] Shell utilities: Guard against expr' magic tokens Mark Wooding
2006-04-18 21:55  1% [Announce] GIT 1.3.0 Junio C Hamano
2006-04-28  1:59  1% PATCH: New diff-delta.c implementation (updated) Geert Bosch
2006-06-06 18:51  5% [REGRESSION] Interrupted clone/fetch leaves .lock files around Jonas Fonseca
2006-06-09  2:17     Figured out how to get Mozilla into git Jon Smirl
2006-06-09  3:06     ` Martin Langhoff
2006-06-09  3:28       ` Jon Smirl
2006-06-09  7:17         ` Jakub Narebski
2006-06-09 15:01  3%       ` Linus Torvalds
2006-06-09 18:13       ` Jon Smirl
2006-06-09 19:00         ` Linus Torvalds
2006-06-09 20:17  3%       ` Jon Smirl
2006-06-09 20:44  4%         ` Jakub Narebski
2006-06-09 21:05  0%         ` Nicolas Pitre
2006-06-09 21:46  0%           ` Jon Smirl
2006-06-10  1:23  0%         ` Martin Langhoff
2006-06-10  8:58  6% Lazy clone ideas Jakub Narebski
2006-06-11 20:37  1% [PATCH] The name of the hash is SHA-1, use it consistently in Documentation Horst H. von Brand
2006-06-24 16:18     [RFC] GIT user survey Paolo Ciarrocchi
2006-06-24 21:55     ` Adrien Beau
2006-06-24 22:15       ` Matthias Kestenholz
2006-06-29  9:49  4%     ` Jakub Narebski
2006-07-28  6:36     Java GIT/Eclipse GIT version 0.1.1 Shawn Pearce
2006-07-28  6:49  1% ` Peter Baumann
2006-07-28  7:08  1%   ` Pavel Roskin
2006-07-28  7:23  0%     ` Peter Baumann
2006-07-29  3:32  1%     ` Shawn Pearce
2006-08-09 10:24  2% [PATCH] Workaround for strange cmp bug Johannes Schindelin
2006-08-14  3:37     Compression and dictionaries Jon Smirl
2006-08-14 12:33     ` Johannes Schindelin
2006-08-14 14:08       ` Jon Smirl
2006-08-14 15:14         ` Alex Riesen
2006-08-14 15:26  1%       ` Johannes Schindelin
2006-08-18  8:45     [PATCH] git-apply: document remaining options in the man page Jonas Fonseca
2006-08-18  9:43     ` Junio C Hamano
2006-08-25  0:56       ` [PATCH 1/7] git-apply(1): document missing options and improve existing ones Jonas Fonseca
2006-08-25  0:58         ` [PATCH 2/7] git-ls-remote(1): document --upload-pack Jonas Fonseca
2006-08-25  1:01           ` [PATCH 3/7] git-blame(1): mention options in the synopsis and advertise pickaxe Jonas Fonseca
2006-08-25  1:04             ` [PATCH 4/7] gitk(1): expand the manpage to look less like a template Jonas Fonseca
2006-08-25  1:05               ` [PATCH 5/7] git(7): put the synopsis in a verse style paragraph Jonas Fonseca
2006-08-25  1:06                 ` [PATCH 6/7] gitview.txt: improve asciidoc markup Jonas Fonseca
2006-08-25  1:07  7%               ` [PATCH 7/7] git-svn(1): " Jonas Fonseca
2006-08-18 22:42     git clone dies (large git repository) Troy Telford
2006-08-19 20:46  4% ` Junio C Hamano
2006-09-02 14:31     Mozilla version control requirements and git Jon Smirl
2006-09-03  1:19     ` Martin Langhoff
2006-09-03  3:29  4%   ` Jon Smirl
     [not found]     <64c62cc942e872b29d7225999e74a07be586674a.1157610743.git.peff@peff.net>
2006-09-07  6:36  2% ` [PATCH 3/3] git-commit.sh: convert run_status to a C builtin Jeff King
2006-09-07 19:52     Change set based shallow clone Jon Smirl
2006-09-07 22:07     ` Junio C Hamano
2006-09-08  3:54       ` Martin Langhoff
2006-09-08  5:30         ` Junio C Hamano
2006-09-08 14:20  5%       ` Jon Smirl
2006-09-08 15:50             ` Jakub Narebski
2006-09-09  3:13  4%           ` Petr Baudis
2006-09-09  8:39  3%             ` Jakub Narebski
2006-09-08  2:23     Jon Smirl
2006-09-08 18:42     ` linux
2006-09-08 21:13       ` Jon Smirl
2006-09-08 23:09  6%     ` Linus Torvalds
2006-09-08  8:05  2% [PATCH] git-commit.sh: convert run_status to a C builtin Jeff King
2006-09-24 22:42  4% [PATCH] branch: write branch properties Santi Béjar
2006-09-24 23:00  4% ` Santi Béjar
2006-09-25  0:41  4%   ` Santi Béjar
2006-10-14 15:07     VCS comparison table Jon Smirl
2006-10-14 16:40     ` Jakub Narebski
2006-10-16 22:26       ` Aaron Bentley
2006-10-16 23:35         ` Linus Torvalds
2006-10-17  4:24           ` Aaron Bentley
2006-10-17 10:23             ` Sean
2006-10-17 19:51               ` Aaron Bentley
2006-10-21 18:58  3%             ` Jan Hudec
     [not found]                   ` <20061021150233.c29e11c5.seanlkml@sympatico.ca>
2006-10-21 19:02  1%                 ` Sean
2006-10-21 19:02  1%                 ` Sean
2006-10-14 20:20  2% ` Jakub Narebski
2006-10-14 23:06  0%   ` Jon Smirl
2006-10-15  0:03         ` Sean
2006-10-15  0:34           ` Jon Smirl
     [not found]             ` <20061014214452.8c2d2a5c.seanlkml@sympatico.ca>
2006-10-15  1:44  1%           ` Sean
2006-10-15  0:53  1%     ` Jakub Narebski
2006-10-15 18:23  0%     ` Petr Baudis
2006-10-20 13:17     ` Jakub Narebski
2006-10-20 14:59       ` James Henstridge
2006-10-20 22:50  3%     ` Jakub Narebski
2006-10-22 18:53     Matthew D. Fuller
2006-10-23 17:29     ` Linus Torvalds
2006-10-23 22:21       ` Matthew D. Fuller
2006-10-23 22:44         ` Linus Torvalds
2006-10-24  0:26           ` Matthew D. Fuller
2006-10-24 15:58             ` David Lang
2006-10-24 16:34               ` Matthew D. Fuller
2006-10-24 18:03                 ` David Lang
2006-10-25  0:27                   ` Matthew D. Fuller
2006-10-25 22:40                     ` David Lang
2006-10-25 23:53                       ` Matthew D. Fuller
2006-10-26 10:13                         ` Andreas Ericsson
2006-10-26 11:48  4%                       ` Jakub Narebski
2006-10-27 19:42  5% [PATCH] enhance clone and fetch -k experience Nicolas Pitre
2006-11-02  0:53  1% What's in git.git Junio C Hamano
2006-11-08  3:21     Junio C Hamano
2006-11-08  4:13  2% ` David Lang
2006-11-08 16:40  1%   ` Shallow clone [Was Re: What's in git.git ] Aneesh Kumar K.V
2006-11-08 17:59  1%     ` Aneesh Kumar K.V
2006-11-09  4:04           ` Shallow clone Junio C Hamano
2006-11-11 13:57             ` Alexandre Julliard
2006-11-12  8:16               ` Junio C Hamano
2006-11-12 17:59  5%             ` Sergey Vlasov
2006-11-12 21:59  1%               ` Junio C Hamano
2006-11-13  5:29  1%                 ` Junio C Hamano
2006-11-09  2:28  0%   ` What's in git.git Horst H. von Brand
2006-11-09  2:54  0%     ` Junio C Hamano
2006-11-09  3:45  0%       ` Dave Dillow
2006-11-12 22:25  3%   ` Johannes Schindelin
2006-11-12 15:44     should git download missing objects? Anand Kumria
2006-11-12 19:41  2% ` Junio C Hamano
2006-11-14 16:42     [PATCH] commit: Steer new users toward "git commit -a" rather than update-index Carl Worth
2006-11-14 18:55     ` Andy Whitcroft
2006-11-14 19:22       ` Cleaning up git user-interface warts Carl Worth
2006-11-14 19:47         ` Petr Baudis
2006-11-14 20:56           ` Carl Worth
2006-11-15  0:31             ` Junio C Hamano
2006-11-15 20:51  2%           ` Carl Worth
2006-11-15  7:43  1% [ANNOUNCE] GIT 1.4.4 Junio C Hamano
2006-11-25 10:12  3% What's in git.git Junio C Hamano
2006-11-27  0:44  2% [PATCH] (experimental) per-topic shortlog Junio C Hamano
2006-11-30 17:06     [RFC] Submodules in GIT Martin Waitz
2006-12-01 17:08     ` sf
2006-12-01 20:13       ` Linus Torvalds
2006-12-01 22:06         ` Josef Weidendorfer
2006-12-01 22:12           ` Martin Waitz
2006-12-01 22:26             ` Josef Weidendorfer
2006-12-01 22:40  2%           ` Martin Waitz
2006-12-01 22:26  4%       ` Linus Torvalds
2006-12-01 22:41             ` sf
2006-12-01 23:09               ` Linus Torvalds
2006-12-01 23:49  3%             ` sf
2006-12-02 18:57  1%               ` Torgil Svensson
2006-12-02 19:41                     ` Linus Torvalds
2006-12-03  9:19                       ` Torgil Svensson
2006-12-03 17:54  3%                     ` Linus Torvalds
2006-12-01 22:55  1%         ` Josef Weidendorfer
2006-12-14 23:07     ` Josef Weidendorfer
2006-12-15 17:43       ` Torgil Svensson
2006-12-15 21:42         ` Josef Weidendorfer
2006-12-15 23:43           ` Torgil Svensson
2006-12-16  1:13             ` Torgil Svensson
2006-12-16  1:20               ` Torgil Svensson
2006-12-16  1:34                 ` Jakub Narebski
2006-12-16  8:40                   ` Torgil Svensson
2006-12-16  9:57  2%                 ` Jakub Narebski
2006-12-16 15:05  2%                   ` Torgil Svensson
2006-12-04 19:08     [RFC] Two conceptually distinct commit commands Carl Worth
2006-12-06  1:13     ` Junio C Hamano
2006-12-06  4:53       ` Carl Worth
2006-12-06 18:31         ` Junio C Hamano
2006-12-06 23:29  1%       ` Carl Worth
2006-12-04 20:41     [RFC] Submodules in GIT Linus Torvalds
2006-12-04 21:36     ` Torgil Svensson
2006-12-05 10:42       ` Andreas Ericsson
2006-12-05 11:09  5%     ` Jakub Narebski
2006-12-10 19:51     [RFC \ WISH] Add -o option to git-rev-list Marco Costalba
2006-12-10 20:00  4% ` globs in partial checkout? Michael S. Tsirkin
2006-12-10 20:13  3%   ` Linus Torvalds
2006-12-14 23:08     git-fetch fails with error code 128 Andy Parkins
2006-12-15  9:46     ` Andy Parkins
2006-12-15 21:55       ` Junio C Hamano
2006-12-16 22:12  5%     ` Andy Parkins
2006-12-16 18:32     Subprojects tasks Junio C Hamano
2006-12-17  0:01     ` Josef Weidendorfer
2006-12-17 11:45       ` Martin Waitz
2006-12-17 13:01  3%     ` Jakub Narebski
2006-12-17 13:48  0%       ` Martin Waitz
2006-12-27  7:39     [RFH] An early draft of v1.5.0 release notes Junio C Hamano
2006-12-28  1:45     ` An early draft of v1.5.0 release notes (2nd ed) Junio C Hamano
2007-01-10  7:58  6%   ` An early draft of v1.5.0 release notes (3rd ed) Junio C Hamano
2007-01-02  0:08  3% Draft v1.5.0 release notes Junio C Hamano
2007-01-09 21:35     Howto use StGit and git-svn at same time Guilhem Bonnefille
2007-01-09 21:41     ` Guilhem Bonnefille
2007-01-09 22:41       ` Yann Dirson
2007-01-15 13:26         ` Guilhem Bonnefille
2007-01-15 20:24           ` Rebasing stgit stacks Yann Dirson
2007-01-15 22:46             ` Catalin Marinas
2007-01-15 23:39               ` Yann Dirson
2007-01-16 22:42  4%             ` Catalin Marinas
2007-01-16 23:17  1%               ` Yann Dirson
2007-01-15  3:44  6% [PATCH] some doc updates Nicolas Pitre
2007-01-21  8:56     [Announce] GIT v1.5.0-rc2 Junio C Hamano
2007-01-21 11:20  2% ` Junio C Hamano
2007-01-21 19:46  0%   ` Horst H. von Brand
2007-01-22 18:08  1%   ` Carl Worth
2007-01-25 12:50     Some cleanups Horst H. von Brand
2007-01-25 12:50  1% ` [PATCH] Hash name is SHA-1 Horst H. von Brand
2007-01-27  6:28     git user's manual J. Bruce Fields
2007-01-28  0:22     ` [PATCH] user-manual: set user.name and user.email with repo-config Matthias Lederhofer
2007-01-28  0:32       ` Linus Torvalds
2007-01-28  1:34         ` Matthias Lederhofer
2007-01-28  1:47           ` Linus Torvalds
2007-01-28  2:40  2%         ` Tom Prince
2007-01-30 16:20     newbie questions about git design and features (some wrt hg) Mike Coleman
2007-01-30 16:55  2% ` Shawn O. Pearce
2007-02-09 10:49     restriction of pulls Christoph Duelli
2007-02-09 14:54     ` Johannes Schindelin
2007-02-09 15:32  2%   ` Rogan Dawes
2007-02-09 16:19  5%     ` Andy Parkins
2007-02-10 14:50         ` Johannes Schindelin
2007-02-12 13:58  3%       ` Rogan Dawes
2007-02-12 14:13             ` Johannes Schindelin
2007-02-12 14:29  4%           ` Rogan Dawes
2007-02-12  7:26     StGIT discards local commits on "stg pull" Pavel Roskin
2007-02-12  9:31     ` Catalin Marinas
2007-02-13  0:20       ` Pavel Roskin
2007-02-13 22:48         ` Catalin Marinas
2007-02-19 20:47  1%       ` Yann Dirson
2007-02-14  3:14  2% [ANNOUNCE] GIT 1.5.0 Junio C Hamano
2007-02-15 22:13 16% [PATCH] git-clone: Sync documentation to usage note Christian Schlotter
2007-02-25  7:59     Google Summer of Code 2007 Shawn O. Pearce
2007-03-01  2:08  3% ` Jakub Narebski
2007-02-25 22:38  2% [PATCH 8/8] convert remaining users of "cmp" to "git diff" Johannes Schindelin
2007-03-06  6:35     [PATCH] Make 'make' quieter while building git Shawn O. Pearce
2007-03-06  7:03     ` Junio C Hamano
2007-03-06  7:16       ` Shawn O. Pearce
2007-03-06 10:53         ` Short term release plans Junio C Hamano
2007-03-19 10:53  1%       ` GIT v1.5.1-rc1 Junio C Hamano
2007-03-25 12:30     .gitlink for Summer of Code Eric Lesh
2007-03-27 21:11     ` Linus Torvalds
2007-03-27 20:54       ` David Lang
2007-03-27 23:31         ` Jakub Narebski
2007-03-27 23:20  4%       ` David Lang
2007-04-04  9:12  1% [ANNOUNCE] GIT 1.5.1 Junio C Hamano
2007-04-10  4:12     [PATCH 0/6] Initial subproject support (RFC?) Linus Torvalds
2007-04-11 22:48     ` [PATCH 5/6] Teach "fsck" not to follow subproject links Linus Torvalds
2007-04-11 23:16       ` Linus Torvalds
2007-04-11 23:53         ` Linus Torvalds
2007-04-11 23:30           ` David Lang
2007-04-12  2:14             ` Linus Torvalds
2007-04-12 18:32  1%           ` Dana How
2007-04-17  9:02     GIT vs Other: Need argument Pietro Mascagni
     [not found]     ` <200704172239.20124.andyparkins@gmail.com>
2007-04-19 11:59       ` Marcin Kasperski
2007-04-19 12:57  3%     ` Andy Parkins
2007-05-01 21:46  2% Git benchmarks at OpenOffice.org wiki Jakub Narebski
2007-05-01 22:27  3% ` Junio C Hamano
2007-05-02 14:24  0% ` Jan Holesovsky
2007-05-02 23:30  4%   ` Jakub Narebski
2007-05-09 15:30  2% svn user trying to recover from brain damage Joshua Ball
2007-05-09 16:22  1% ` Petr Baudis
2007-05-20 17:57  6% Partial removal of fetching from git-clone skimo
2007-07-18 19:19  1% [PATCH] Implement git commit as a builtin Kristian Høgsberg
2007-07-23 12:52     index-pack died on pread Michal Rokos
2007-07-23 17:04     ` Linus Torvalds
2007-07-25 23:15  2%   ` Robin Rosenberg
2007-09-05  7:09     People unaware of the importance of "git gc"? Linus Torvalds
2007-09-05 21:07  3% ` Alex Riesen
2007-09-06  0:23     [PATCH 1/9] Enable wt-status output to a given FILE pointer Kristian Høgsberg
2007-09-06  0:23     ` [PATCH 2/9] Enable wt-status to run against non-standard index file Kristian Høgsberg
2007-09-06  0:23       ` [PATCH 3/9] Add strbuf_printf() to do formatted printing to a strbuf Kristian Høgsberg
2007-09-06  0:23         ` [PATCH 4/9] Introduce entry point for launching add--interactive Kristian Høgsberg
2007-09-06  0:23           ` [PATCH 5/9] Introduce strbuf_read_fd() Kristian Høgsberg
2007-09-06  0:23             ` [PATCH 6/9] Rewrite launch_editor, create_tag and stripspace to use strbufs Kristian Høgsberg
2007-09-06  0:23               ` [PATCH 7/9] Add strbuf_read_path() Kristian Høgsberg
2007-09-06  0:23                 ` [PATCH 8/9] Export rerere() and launch_editor() Kristian Høgsberg
2007-09-06  0:23  2%               ` [PATCH 9/9] Implement git commit as a builtin command Kristian Høgsberg
2007-09-19 19:01  2% [ANNOUNCE] GIT 1.5.3.2 Junio C Hamano
2007-09-23 17:27     user-manual changes J. Bruce Fields
2007-09-24  3:14 11% ` [PATCH] user-manual: Explain what submodules are good for Michael Smith
2007-09-25 12:44     Michael Smith
2007-09-25 12:44 14% ` Michael Smith
2007-09-25 16:09  0%   ` J. Bruce Fields
2007-09-27  4:50     [PATCH 1/4] Add a simple option parser for use by builtin-commit.c Kristian Høgsberg
2007-09-27  4:50     ` [PATCH 2/4] This exports the update() function from builtin-add.c as Kristian Høgsberg
2007-09-27  4:50  2%   ` [PATCH 3/4] Implement git commit as a builtin command Kristian Høgsberg
2007-10-04  9:12  2% Git User's Survey 2007 unfinished summary (long) Jakub Narebski
2007-10-07 21:23     Trying to use git-filter-branch to compress history by removing large, obsolete binary files Elijah Newren
2007-10-07 21:38     ` Frank Lichtenheld
2007-10-07 22:00       ` Elijah Newren
2007-10-07 23:19         ` Johannes Schindelin
2007-10-07 23:24           ` Elijah Newren
2007-10-07 23:28             ` Johannes Schindelin
2007-10-07 23:38               ` Elijah Newren
2007-10-08  0:34                 ` Johannes Schindelin
2007-10-08  0:47                   ` Elijah Newren
2007-10-08  2:28  2%                 ` Sam Vilain
2007-10-08 20:55     Git User's Survey 2007 unfinished summary continued Jakub Narebski
2007-10-12 22:08  2% ` Jakub Narebski
2007-10-10 21:13 11% [PATCH] Fixing path quoting issues Jonathan del Strother
2007-10-10 21:22 11% maillist
2007-10-12 22:07  1% Git User's Survey 2007 summary - comparison with previous survey Jakub Narebski
2007-10-13 22:36     [PATCH] Fixing path quoting issues Andreas Ericsson
2007-10-15 13:13  7% ` [PATCH 2/3] Quoting paths in tests Jonathan del Strother
2007-10-16  8:42     Is there any plan to support partial checkout or submoudule improvement? Lars Hjemli
2007-10-16  9:56  4% ` franky
2007-10-17  9:14     [PATCH 1/3] Fixing path quoting in git-rebase Jonathan del Strother
2007-10-17  9:31     ` [PATCH] Quoting paths, take 3 Jonathan del Strother
2007-10-17  9:31       ` [PATCH 1/2] Fixing path quoting in git-rebase Jonathan del Strother
2007-10-17  9:31  6%     ` [PATCH 2/2] Quoting paths in tests Jonathan del Strother
2007-10-22  6:32     What's cooking in git/spearce.git (topics) Shawn O. Pearce
2007-10-24 12:51     ` What's cooking in git.git (topics) Junio C Hamano
2007-11-01  5:41       ` Junio C Hamano
2007-11-04  4:14         ` Junio C Hamano
2007-11-08  8:08           ` Junio C Hamano
2007-11-12  7:09             ` Junio C Hamano
2007-11-15  0:18               ` Junio C Hamano
2007-11-17 20:51  1%             ` Junio C Hamano
2007-10-25 19:48  4% stgit restrictions on patch names Yann Dirson
2007-10-29 16:14  0% ` Catalin Marinas
2007-10-31 21:16  3% [PATCH] Updated russian translation of git-gui Alex Riesen
2007-11-01 19:09  2% [PATCH] Implement git commit as a builtin command Kristian Høgsberg
2007-11-08 16:59  2% [PATCH] Port git commit to C Kristian Høgsberg
2007-11-12 13:57     Cloning from kernel.org, then switching to another repo Jon Smirl
2007-11-12 14:13     ` Johannes Schindelin
2007-11-12 15:36       ` Jon Smirl
2007-11-12 16:16         ` Johannes Schindelin
2007-11-12 16:22           ` Jon Smirl
2007-11-12 16:36             ` Johannes Schindelin
2007-11-12 17:21               ` Jon Smirl
2007-11-12 17:28                 ` Jon Smirl
2007-11-13  4:14  4%               ` Jeff King
2007-11-12 21:38     [PATCH] Add a test checking if send-pack updated local tracking branches correctly Alex Riesen
2007-11-12 21:39     ` [PATCH] Update the tracking references only if they were succesfully updated on remote Alex Riesen
2007-11-13  7:52       ` Jeff King
2007-11-13 19:47         ` Alex Riesen
2007-11-13 19:49           ` [PATCH] Add a test for deleting remote branches Alex Riesen
2007-11-13 23:02             ` [PATCH] Improved and extended t5404 Alex Riesen
2007-11-13 23:10               ` Jeff King
2007-11-15  4:26                 ` Jeff King
2007-11-15 20:46  3%               ` [PATCH] Add test that checks diverse aspects of updating remote and tracking branches Alex Riesen
2007-11-14 21:52  3%           ` [PATCH] Improved and extended t5404 Junio C Hamano
2007-11-14 22:49  3%             ` [PATCH] Add test that checks diverse aspects of updating remote and tracking branches Alex Riesen
2007-11-14 21:52  3%           ` [PATCH] Improved and extended t5404 Junio C Hamano
2007-11-28 22:39     Adding Git to Better SCM Initiative : Comparison Jakub Narebski
2007-11-29  1:48  3% ` Robin Rosenberg
2007-12-04 13:09  2% Building git-1.5.3.7 on HP-UX 11.00 H.Merijn Brand
2008-01-02  7:13  3% Git and securing a repository Gonzalo Garramuño
2008-01-02  6:34  2% ` Felipe Balbi
2008-01-02 16:18  1% ` Daniel Barkalow
2008-01-12  7:11     [ANNOUNCE] GIT 1.5.4-rc3 Junio C Hamano
2008-01-12  7:26     ` Ismail Dönmez
2008-01-12  7:34       ` Junio C Hamano
2008-01-12  7:47         ` Ismail Dönmez
2008-01-12  9:04           ` Jeff King
2008-01-12 11:10             ` valgrind test script integration Jeff King
2008-01-12 11:36  2%           ` Jeff King
2008-01-13 19:02     [PATCH] http-push: making HTTP push more robust and more user-friendly Grégoire Barbier
2008-01-13 23:01     ` Junio C Hamano
2008-01-19 15:21  2%   ` Grégoire Barbier
2008-01-15  5:24  1% Git Gui: initial french translation: fr.po Christian Couder
2008-01-30  8:32     What's in git.git (stable frozen) Junio C Hamano
2008-02-12  7:25     ` What's in git.git Junio C Hamano
2008-02-17  3:56  2%   ` What's in git.git (stable) Junio C Hamano
2008-02-21  4:16  2%     ` Junio C Hamano
2008-02-08 17:28     [PATCH] RFC: git lazy clone proof-of-concept Jan Holesovsky
2008-02-08 19:00     ` Jakub Narebski
2008-02-09 15:27       ` Jan Holesovsky
2008-02-11  1:20  4%     ` Jakub Narebski
2008-02-08 20:16  4% ` Johannes Schindelin
2008-02-14 20:05     ` Jakub Narebski
2008-02-14 21:04       ` Johannes Schindelin
2008-02-14 21:59  5%     ` Jakub Narebski
2008-02-14 23:38  4%       ` Johannes Schindelin
2008-02-15  1:07  5%         ` Jakub Narebski
2008-02-15  9:43  1%       ` Jan Holesovsky
2008-02-10 10:47     [ANNOUNCE] GIT 1.5.4.1 Junio C Hamano
2008-02-17  9:14  2% ` [ANNOUNCE] GIT 1.5.4.2 Junio C Hamano
2008-02-20 23:59     [PATCH 0/3] solaris test results Jeff King
2008-02-21  0:34     ` Junio C Hamano
2008-02-21  0:41       ` Jeff King
2008-02-22  5:26  1%     ` Junio C Hamano
2008-02-23 21:07  3% [ANNOUNCE] GIT 1.5.4.3 Junio C Hamano
2008-02-24  9:34     on subtree checkout Nguyen Thai Ngoc Duy
2008-02-24 10:03     ` Jakub Narebski
2008-02-24 15:12       ` Nguyen Thai Ngoc Duy
2008-02-24 15:45         ` Jakub Narebski
2008-02-24 15:59  5%       ` Matthieu Moy
2008-02-24 17:22  2%         ` Robin Rosenberg
2008-02-26  1:59     ` Johannes Schindelin
2008-02-26  2:30  3%   ` David Symonds
2008-02-26 11:23  2%     ` Johannes Schindelin
2008-02-26 22:56     Google Summer of Code 2008 Jakub Narebski
2008-02-28  6:36     ` Shawn O. Pearce
2008-02-28 10:27       ` Johannes Schindelin
2008-02-29 12:04  4%     ` Jakub Narebski
2008-03-10 22:02     [QUESTION] Selective fetch possible? Filippo Zangheri
2008-03-10 22:53     ` Shawn O. Pearce
2008-03-10 23:34  2%   ` Jakub Narebski
2008-03-11  7:26  0%     ` Rogan Dawes
2008-03-11  7:50           ` Shawn O. Pearce
2008-03-11  9:07  3%         ` Rogan Dawes
     [not found]     <cover.1205356737.git.peff@peff.net>
2008-03-12 21:36  1% ` [PATCH 06/16] add test_cmp function for test scripts Jeff King
2008-03-29 22:35     git-submodule getting submodules from the parent repository Avery Pennarun
2008-03-29 23:22     ` Sam Vilain
2008-03-30 23:00       ` Avery Pennarun
2008-04-01 23:10  3%     ` Sam Vilain
2008-04-03 19:42     Achieving efficient storage of weirdly structured repos Roman Shaposhnik
2008-04-03 21:11  3% ` Linus Torvalds
2008-04-04 23:30  1%   ` Roman Shaposhnik
2008-04-09  1:29     [PATCH 0/8] Fix git's test suite to pass when the path contains spaces Bryan Donlan
2008-04-09  1:29     ` [PATCH 1/8] git-rebase.sh: Fix --merge --abort failures when path contains whitespace Bryan Donlan
2008-04-09  1:29       ` [PATCH 2/8] config.c: Escape backslashes in section names properly Bryan Donlan
2008-04-09  1:29         ` [PATCH 3/8] git-send-email.perl: Handle shell metacharacters in $EDITOR properly Bryan Donlan
2008-04-09  1:30           ` [PATCH 4/8] test-lib.sh: Fix some missing path quoting Bryan Donlan
2008-04-09  1:30             ` [PATCH 5/8] test-lib.sh: Add a test_set_editor function to safely set $VISUAL Bryan Donlan
2008-04-09  1:30               ` [PATCH 6/8] lib-git-svn.sh: Fix quoting issues with paths containing shell metacharacters Bryan Donlan
2008-04-09  1:30                 ` [PATCH 7/8] Use test_set_editor in t9001-send-email.sh Bryan Donlan
2008-04-09  1:30 10%               ` [PATCH 8/8] Fix tests breaking when checkout path contains shell metacharacters Bryan Donlan
2008-04-10  6:50     ` [PATCH v2 00/10] Fix git's test suite to pass when the path contains spaces Bryan Donlan
2008-04-10  6:50       ` [PATCH v2 01/10] git-rebase.sh: Fix --merge --abort failures when path contains whitespace Bryan Donlan
2008-04-10  6:50         ` [PATCH v2 02/10] config.c: Escape backslashes in section names properly Bryan Donlan
2008-04-10  6:50           ` [PATCH v2 03/10] git-send-email.perl: Handle shell metacharacters in $EDITOR properly Bryan Donlan
2008-04-10  6:50             ` [PATCH v2 04/10] test-lib.sh: Add a test_set_editor function to safely set $VISUAL Bryan Donlan
2008-04-10  6:50               ` [PATCH v2 05/10] Use test_set_editor in t9001-send-email.sh Bryan Donlan
2008-04-10  6:50                 ` [PATCH v2 06/10] test-lib.sh: Fix some missing path quoting Bryan Donlan
2008-04-10  6:50                   ` [PATCH v2 07/10] lib-git-svn.sh: Fix quoting issues with paths containing shell metacharacters Bryan Donlan
2008-04-10  6:50                     ` [PATCH v2 08/10] Don't use the export NAME=value form in the test scripts Bryan Donlan
2008-04-10  6:50 10%                   ` [PATCH v2 09/10] Fix tests breaking when checkout path contains shell metacharacters Bryan Donlan
2008-05-04  5:37       ` [PATCH v3 00/10] Fix git's test suite to pass when the path contains spaces Bryan Donlan
2008-05-04  5:37         ` [PATCH v3 01/10] git-rebase.sh: Fix --merge --abort failures when path contains whitespace Bryan Donlan
2008-05-04  5:37           ` [PATCH v3 02/10] config.c: Escape backslashes in section names properly Bryan Donlan
2008-05-04  5:37             ` [PATCH v3 03/10] git-send-email.perl: Handle shell metacharacters in $EDITOR properly Bryan Donlan
2008-05-04  5:37               ` [PATCH v3 04/10] test-lib.sh: Add a test_set_editor function to safely set $VISUAL Bryan Donlan
2008-05-04  5:37                 ` [PATCH v3 05/10] Use test_set_editor in t9001-send-email.sh Bryan Donlan
2008-05-04  5:37                   ` [PATCH v3 06/10] test-lib.sh: Fix some missing path quoting Bryan Donlan
2008-05-04  5:37                     ` [PATCH v3 07/10] lib-git-svn.sh: Fix quoting issues with paths containing shell metacharacters Bryan Donlan
2008-05-04  5:37                       ` [PATCH v3 08/10] Don't use the export NAME=value form in the test scripts Bryan Donlan
2008-05-04  5:37  8%                     ` [PATCH v3 09/10] Fix tests breaking when checkout path contains shell metacharacters Bryan Donlan
2008-04-22 21:28  9% [PATCH] Have tests and programs understand paths containing spaces Arjen Laarhoven

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).