Git development
 help / color / mirror / Atom feed
* Re: [ANNOUNCE] Git homepage change
From: Mike Hommey @ 2009-01-05 19:40 UTC (permalink / raw)
  To: Petr Baudis; +Cc: Scott Chacon, git
In-Reply-To: <20090105164001.GA12275@machine.or.cz>

On Mon, Jan 05, 2009 at 05:40:01PM +0100, Petr Baudis wrote:
>   Hi,
> 
>   thanks for the changes, Scott!
> 
>   Based on the previous feedback of other developers and my last review
> of git-scm.com, I have changed git.or.cz to redirect to git-scm.com.
> 
>   The wiki is still hosted at the original place for the time being, as
> well as the man/ gitbot redirect. To reach the original manpage, use
> http://git.or.cz/index.html.

FWIW, I think the "mascot" or whatever it is supposed to be, on the
top right end, is "safe", trademark/copyright-wise. It looks too much
like どーもくん(Dômo-kun), the NHK mascot.
http://images.google.co.jp/images?q=%E3%81%A9%E3%83%BC%E3%82%82%E3%81%8F%E3%82%93&ie=UTF-8&oe=UTF-8&hl=en&um=1&sa=N&tab=wi

Mike

^ permalink raw reply

* Re: [PATCH v2] parse-opt: migrate builtin-apply.
From: Pierre Habouzit @ 2009-01-05 19:12 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Miklos Vajna, git
In-Reply-To: <7vvdt5cmu6.fsf@gitster.siamese.dyndns.org>

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

On Sat, Dec 27, 2008 at 09:47:13PM +0000, Junio C Hamano wrote:
> Miklos Vajna <vmiklos@frugalware.org> writes:
> 
> > +static int option_parse_inaccurate(const struct option *opt,
> > +				   const char *arg, int unset)
> > +{
> > +	options |= INACCURATE_EOF;
> > +	return 0;
> > +}
> > +
> > +static int option_parse_recount(const struct option *opt,
> > +				const char *arg, int unset)
> > +{
> > +	options |= RECOUNT;
> > +	return 0;
> > +}
> 
> I still haven't applied and ran the testsuite myself, but these makes me
> wonder if there isn't a built-in "bit" type support in parse_options().

There is.
-- 
·O·  Pierre Habouzit
··O                                                madcoder@debian.org
OOO                                                http://www.madism.org

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

^ permalink raw reply

* [PATCH] stgit namelength is an integer
From: Pete Wyckoff @ 2009-01-05 19:03 UTC (permalink / raw)
  To: git

Interpret stgit namelength as an integer, else the use of
name_len will fail with

  File "/usr/lib/python2.5/site-packages/stgit/utils.py", line 206, in patch_name_from_msg
    return re.sub('[\W]+', '-', subject_line).strip('-')[:name_len]
TypeError: slice indices must be integers or None or have an __index__ method

Signed-off-by: Pete Wyckoff <pw@padd.com>
---
 stgit/utils.py |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/stgit/utils.py b/stgit/utils.py
index 81035a5..1fa96c2 100644
--- a/stgit/utils.py
+++ b/stgit/utils.py
@@ -215,7 +215,7 @@ def patch_name_from_msg(msg):
     if not msg:
         return None
 
-    name_len = config.get('stgit.namelength')
+    name_len = config.getint('stgit.namelength')
     if not name_len:
         name_len = 30
 
-- 
1.6.0.6

^ permalink raw reply related

* Re: [ANNOUNCE] Git homepage change
From: Miklos Vajna @ 2009-01-05 19:03 UTC (permalink / raw)
  To: Scott Chacon; +Cc: Petr Baudis, git
In-Reply-To: <20090105185737.GV21154@genesis.frugalware.org>

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

On Mon, Jan 05, 2009 at 07:57:37PM +0100, Miklos Vajna <vmiklos@frugalware.org> wrote:
> --- a/script/get_authors.sh
> +++ b/script/get_authors.sh
> @@ -1,3 +1,3 @@
>  export GIT_DIR=/Users/schacon/projects/git/.git
>  cd /Users/schacon/projects/git
> -git log --pretty=short --no-merges | git shortlog -n | grep -v -e '^ ' | grep ':' > ../gitscm/config/authors.txt
> +git shortlog -s -n > ../gitscm/config/authors.txt

Err, --no-merges still makes sense, so probably this one would be
better:

diff --git a/script/get_authors.sh b/script/get_authors.sh
index 9aa8c6b..1656da4 100755
--- a/script/get_authors.sh
+++ b/script/get_authors.sh
@@ -1,3 +1,3 @@
 export GIT_DIR=/Users/schacon/projects/git/.git
 cd /Users/schacon/projects/git
-git log --pretty=short --no-merges | git shortlog -n | grep -v -e '^ ' | grep ':' > ../gitscm/config/authors.txt
+git shortlog --no-merges -s -n > ../gitscm/config/authors.txt

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

^ permalink raw reply related

* Re: [ANNOUNCE] Git homepage change
From: Miklos Vajna @ 2009-01-05 18:57 UTC (permalink / raw)
  To: Scott Chacon; +Cc: Petr Baudis, git
In-Reply-To: <20090105164001.GA12275@machine.or.cz>

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

On Mon, Jan 05, 2009 at 05:40:01PM +0100, Petr Baudis <pasky@suse.cz> wrote:
>   Based on the previous feedback of other developers and my last review
> of git-scm.com, I have changed git.or.cz to redirect to git-scm.com.

Just wondering, why don't you use the -s option of git shortlog in
./script/get_authors.sh?

I mean:

diff --git a/script/get_authors.sh b/script/get_authors.sh
index 9aa8c6b..89948e2 100755
--- a/script/get_authors.sh
+++ b/script/get_authors.sh
@@ -1,3 +1,3 @@
 export GIT_DIR=/Users/schacon/projects/git/.git
 cd /Users/schacon/projects/git
-git log --pretty=short --no-merges | git shortlog -n | grep -v -e '^ ' | grep ':' > ../gitscm/config/authors.txt
+git shortlog -s -n > ../gitscm/config/authors.txt

I suppose fixing up the ruby part after this is not that hard, sadly I
don't speak Ruby myself, so I have no idea where and what to touch. ;-)

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

^ permalink raw reply related

* Re: [PATCH 2/2] Be consistent in switch usage for tar
From: Alexander Potashev @ 2009-01-05 18:19 UTC (permalink / raw)
  To: henrik; +Cc: git
In-Reply-To: <1231169137-32653-3-git-send-email-henrik@austad.us>

On 16:25 Mon 05 Jan     , henrik@austad.us wrote:
> From: Henrik Austad <henrik@austad.us>
> 
> tar handles switches with and witouth preceding '-', but the documentation should be

s/witouth/without

> consistent nonetheless.
> 
> Signed-off-by: Henrik Austad <henrik@austad.us>
> ---
>  Documentation/user-manual.txt |    2 +-
>  1 files changed, 1 insertions(+), 1 deletions(-)
> 
> diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
> index 5242a7e..19f571a 100644
> --- a/Documentation/user-manual.txt
> +++ b/Documentation/user-manual.txt
> @@ -1009,7 +1009,7 @@ $ git init
>  If you have some initial content (say, a tarball):
>  
>  -------------------------------------------------
> -$ tar -xzvf project.tar.gz
> +$ tar xzvf project.tar.gz

Btw, tar manpage uses dashed options in usage examples:

	tar -xvf foo.tar
		verbosely extract foo.tar
	...


>  $ cd project
>  $ git init
>  $ git add . # include everything below ./ in the first commit:
> -- 
> 1.6.1.36.g8430e

^ permalink raw reply

* Re: [BUG] unable to checkout branch with a clean worktree
From: Anders Melchiorsen @ 2009-01-05 17:54 UTC (permalink / raw)
  To: Clemens Buchacher; +Cc: git
In-Reply-To: <20090105160527.GA7718@localhost>

Clemens Buchacher <drizzd@aon.at> writes:

> On Mon, Jan 05, 2009 at 04:42:48PM +0100, Anders Melchiorsen wrote:
>> Git v1.6.1: The final checkout fails with an error about merge conflicts.
>
> This is fixed by the recent patches for verify_absent. (Actually,
> just PATCH 2/3 should be enough to fix this issue.)
>
> http://article.gmane.org/gmane.comp.version-control.git/104317

Right, I can confirm that the patch [2/3] fixes this, also in the repo
where the issue originally turned up.


Thanks,
Anders.

^ permalink raw reply

* [PATCH v3.2] rebase: learn to rebase root commit
From: Thomas Rast @ 2009-01-05 17:35 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <1230939915-3638-1-git-send-email-trast@student.ethz.ch>

Teach git-rebase a new option --root, which instructs it to rebase the
entire history leading up to <branch>.  This option must be used with
--onto <newbase>, and causes commits that already exist in <newbase>
to be skipped.  (Normal operation skips commits that already exist in
<upstream> instead.)

The main use-case is with git-svn: suppose you start hacking (perhaps
offline) on a new project, but later notice you want to commit this
work to SVN.  You will have to rebase the entire history, including
the root commit, on a (possibly empty) commit coming from git-svn, to
establish a history connection.  This previously had to be done by
cherry-picking the root commit manually.

Signed-off-by: Thomas Rast <trast@student.ethz.ch>

---

Since this is still in 'pu', can you replace it again?  The test case
I designed for v3, to check that it also skips identical commits,
actually makes the _root_ commit a duplicate.  I could sleep better at
night if the root commit was actually part of the rebase :-)

3/4 is not affected patch-wise, though it of course inherits the same
test history.

Thanks!


Interdiff:

>> diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
>> index 1978512..dd91910 100755
>> --- a/t/t3412-rebase-root.sh
>> +++ b/t/t3412-rebase-root.sh
>> @@ -15,12 +15,12 @@ test_expect_success 'prepare repository' '
>>         git commit -m 2 &&
>>         git symbolic-ref HEAD refs/heads/other &&
>>         rm .git/index &&
>> -       echo 1 > A &&
>> -       git add A &&
>> -       git commit -m 1b &&
>>         echo 3 > B &&
>>         git add B &&
>>         git commit -m 3 &&
>> +       echo 1 > A &&
>> +       git add A &&
>> +       git commit -m 1b &&
>>         echo 4 > B &&
>>         git add B &&
>>         git commit -m 4


 git-rebase.sh          |   52 ++++++++++++++++++++--------
 t/t3412-rebase-root.sh |   86 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+), 15 deletions(-)

diff --git a/git-rebase.sh b/git-rebase.sh
index ebd4df3..d1083f1 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -3,7 +3,7 @@
 # Copyright (c) 2005 Junio C Hamano.
 #
 
-USAGE='[--interactive | -i] [-v] [--onto <newbase>] <upstream> [<branch>]'
+USAGE='[--interactive | -i] [-v] [--onto <newbase>] [<upstream>|--root] [<branch>]'
 LONG_USAGE='git-rebase replaces <branch> with a new branch of the
 same name.  When the --onto option is provided the new branch starts
 out with a HEAD equal to <newbase>, otherwise it is equal to <upstream>
@@ -47,6 +47,7 @@ dotest="$GIT_DIR"/rebase-merge
 prec=4
 verbose=
 git_am_opt=
+rebase_root=
 
 continue_merge () {
 	test -n "$prev_head" || die "prev_head must be defined"
@@ -297,6 +298,9 @@ do
 	-C*)
 		git_am_opt="$git_am_opt $1"
 		;;
+	--root)
+		rebase_root=t
+		;;
 	-*)
 		usage
 		;;
@@ -344,17 +348,28 @@ case "$diff" in
 	;;
 esac
 
+if test -z "$rebase_root"; then
 # The upstream head must be given.  Make sure it is valid.
-upstream_name="$1"
-upstream=`git rev-parse --verify "${upstream_name}^0"` ||
-    die "invalid upstream $upstream_name"
+	upstream_name="$1"
+	shift
+	upstream=`git rev-parse --verify "${upstream_name}^0"` ||
+	die "invalid upstream $upstream_name"
+	unset root_flag
+	upstream_arg="$upstream_name"
+else
+	test -z "$newbase" && die "--root must be used with --onto"
+	unset upstream_name
+	unset upstream
+	root_flag="--root"
+	upstream_arg="$root_flag"
+fi
 
 # Make sure the branch to rebase onto is valid.
 onto_name=${newbase-"$upstream_name"}
 onto=$(git rev-parse --verify "${onto_name}^0") || exit
 
 # If a hook exists, give it a chance to interrupt
-run_pre_rebase_hook ${1+"$@"}
+run_pre_rebase_hook "$upstream_arg" "$@"
 
 # If the branch to rebase is given, that is the branch we will rebase
 # $branch_name -- branch being rebased, or HEAD (already detached)
@@ -362,16 +377,16 @@ run_pre_rebase_hook ${1+"$@"}
 # $head_name -- refs/heads/<that-branch> or "detached HEAD"
 switch_to=
 case "$#" in
-2)
+1)
 	# Is it "rebase other $branchname" or "rebase other $commit"?
-	branch_name="$2"
-	switch_to="$2"
+	branch_name="$1"
+	switch_to="$1"
 
-	if git show-ref --verify --quiet -- "refs/heads/$2" &&
-	   branch=$(git rev-parse -q --verify "refs/heads/$2")
+	if git show-ref --verify --quiet -- "refs/heads/$1" &&
+	   branch=$(git rev-parse -q --verify "refs/heads/$1")
 	then
-		head_name="refs/heads/$2"
-	elif branch=$(git rev-parse -q --verify "$2")
+		head_name="refs/heads/$1"
+	elif branch=$(git rev-parse -q --verify "$1")
 	then
 		head_name="detached HEAD"
 	else
@@ -393,7 +408,8 @@ case "$#" in
 esac
 orig_head=$branch
 
-# Now we are rebasing commits $upstream..$branch on top of $onto
+# Now we are rebasing commits $upstream..$branch (or with --root,
+# everything leading up to $branch) on top of $onto
 
 # Check if we are already based on $onto with linear history,
 # but this should be done only when upstream and onto are the same.
@@ -429,10 +445,16 @@ then
 	exit 0
 fi
 
+if test ! -z "$rebase_root"; then
+	revisions="$onto..$orig_head"
+else
+	revisions="$upstream..$orig_head"
+fi
+
 if test -z "$do_merge"
 then
 	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-		"$upstream..$orig_head" |
+		$root_flag "$revisions" |
 	git am $git_am_opt --rebasing --resolvemsg="$RESOLVEMSG" &&
 	move_to_original_branch
 	ret=$?
@@ -455,7 +477,7 @@ echo "$orig_head" > "$dotest/orig-head"
 echo "$head_name" > "$dotest/head-name"
 
 msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$upstream..$orig_head"`
+for cmt in `git rev-list --reverse --no-merges "$revisions"`
 do
 	msgnum=$(($msgnum + 1))
 	echo "$cmt" > "$dotest/cmt.$msgnum"
diff --git a/t/t3412-rebase-root.sh b/t/t3412-rebase-root.sh
new file mode 100755
index 0000000..dd91910
--- /dev/null
+++ b/t/t3412-rebase-root.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+test_description='git rebase --root
+
+Tests if git rebase --root --onto <newparent> can rebase the root commit.
+'
+. ./test-lib.sh
+
+test_expect_success 'prepare repository' '
+	echo 1 > A &&
+	git add A &&
+	git commit -m 1 &&
+	echo 2 > A &&
+	git add A &&
+	git commit -m 2 &&
+	git symbolic-ref HEAD refs/heads/other &&
+	rm .git/index &&
+	echo 3 > B &&
+	git add B &&
+	git commit -m 3 &&
+	echo 1 > A &&
+	git add A &&
+	git commit -m 1b &&
+	echo 4 > B &&
+	git add B &&
+	git commit -m 4
+'
+
+test_expect_success 'rebase --root expects --onto' '
+	test_must_fail git rebase --root
+'
+
+test_expect_success 'setup pre-rebase hook' '
+	mkdir -p .git/hooks &&
+	cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+echo "\$1,\$2" >.git/PRE-REBASE-INPUT
+EOF
+	chmod +x .git/hooks/pre-rebase
+'
+cat > expect <<EOF
+4
+3
+2
+1
+EOF
+
+test_expect_success 'rebase --root --onto <newbase>' '
+	git checkout -b work &&
+	git rebase --root --onto master &&
+	git log --pretty=tformat:"%s" > rebased &&
+	test_cmp expect rebased
+'
+
+test_expect_success 'pre-rebase got correct input (1)' '
+	test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,
+'
+
+test_expect_success 'rebase --root --onto <newbase> <branch>' '
+	git branch work2 other &&
+	git rebase --root --onto master work2 &&
+	git log --pretty=tformat:"%s" > rebased2 &&
+	test_cmp expect rebased2
+'
+
+test_expect_success 'pre-rebase got correct input (2)' '
+	test "z$(cat .git/PRE-REBASE-INPUT)" = z--root,work2
+'
+
+test_expect_success 'setup pre-rebase hook that fails' '
+	mkdir -p .git/hooks &&
+	cat >.git/hooks/pre-rebase <<EOF &&
+#!$SHELL_PATH
+false
+EOF
+	chmod +x .git/hooks/pre-rebase
+'
+
+test_expect_success 'pre-rebase hook stops rebase' '
+	git checkout -b stops1 other &&
+	GIT_EDITOR=: test_must_fail git rebase --root --onto master &&
+	test "z$(git symbolic-ref HEAD)" = zrefs/heads/stops1
+	test 0 = $(git rev-list other...stops1 | wc -l)
+'
+
+test_done
-- 
tg: (f62b77f..) t/rr-normal (depends on: origin/master t/rebase-hook-order)

^ permalink raw reply related

* Consistency patches for Documentation/
From: henrik @ 2009-01-05 15:25 UTC (permalink / raw)
  To: git


The following 2 patches are rather pedantic, but should be corrected. 
Sorry if the way I've sent these are wrong :)

^ permalink raw reply

* [ANNOUNCE] Git homepage change
From: Petr Baudis @ 2009-01-05 16:40 UTC (permalink / raw)
  To: Scott Chacon; +Cc: git
In-Reply-To: <d411cc4a0901011040h4ab97aag20de54a6e138a4ec@mail.gmail.com>

  Hi,

  thanks for the changes, Scott!

  Based on the previous feedback of other developers and my last review
of git-scm.com, I have changed git.or.cz to redirect to git-scm.com.

  The wiki is still hosted at the original place for the time being, as
well as the man/ gitbot redirect. To reach the original manpage, use
http://git.or.cz/index.html.

  Have a fun year,

-- 
				Petr "Pasky" Baudis
The average, healthy, well-adjusted adult gets up at seven-thirty
in the morning feeling just terrible. -- Jean Kerr

^ permalink raw reply

* [PATCH 1/2] Use capitalized names where appropriate
From: henrik @ 2009-01-05 15:25 UTC (permalink / raw)
  To: git; +Cc: Henrik Austad
In-Reply-To: <1231169137-32653-1-git-send-email-henrik@austad.us>

From: Henrik Austad <henrik@austad.us>

The Linux kernel and Emacs are both spelled capitalized

Signed-off-by: Henrik Austad <henrik@austad.us>
---
 Documentation/gittutorial.txt |    4 ++--
 Documentation/user-manual.txt |    4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/Documentation/gittutorial.txt b/Documentation/gittutorial.txt
index 7892244..458fafd 100644
--- a/Documentation/gittutorial.txt
+++ b/Documentation/gittutorial.txt
@@ -590,7 +590,7 @@ list.  When the history has lines of development that diverged and
 then merged back together, the order in which 'git-log' presents
 those commits is meaningless.
 
-Most projects with multiple contributors (such as the linux kernel,
+Most projects with multiple contributors (such as the Linux kernel,
 or git itself) have frequent merges, and 'gitk' does a better job of
 visualizing their history.  For example,
 
@@ -642,7 +642,7 @@ digressions that may be interesting at this point are:
 
   * linkgit:git-format-patch[1], linkgit:git-am[1]: These convert
     series of git commits into emailed patches, and vice versa,
-    useful for projects such as the linux kernel which rely heavily
+    useful for projects such as the Linux kernel which rely heavily
     on emailed patches.
 
   * linkgit:git-bisect[1]: When there is a regression in your
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index d4b1e90..5242a7e 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -59,7 +59,7 @@ project in mind, here are some interesting examples:
 ------------------------------------------------
 	# git itself (approx. 10MB download):
 $ git clone git://git.kernel.org/pub/scm/git/git.git
-	# the linux kernel (approx. 150MB download):
+	# the Linux kernel (approx. 150MB download):
 $ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
 ------------------------------------------------
 
@@ -1340,7 +1340,7 @@ These will display all commits which exist only on HEAD or on
 MERGE_HEAD, and which touch an unmerged file.
 
 You may also use linkgit:git-mergetool[1], which lets you merge the
-unmerged files using external tools such as emacs or kdiff3.
+unmerged files using external tools such as Emacs or kdiff3.
 
 Each time you resolve the conflicts in a file and update the index:
 
-- 
1.6.1.36.g8430e

^ permalink raw reply related

* [PATCH 2/2] Be consistent in switch usage for tar
From: henrik @ 2009-01-05 15:25 UTC (permalink / raw)
  To: git; +Cc: Henrik Austad
In-Reply-To: <1231169137-32653-2-git-send-email-henrik@austad.us>

From: Henrik Austad <henrik@austad.us>

tar handles switches with and witouth preceding '-', but the documentation should be
consistent nonetheless.

Signed-off-by: Henrik Austad <henrik@austad.us>
---
 Documentation/user-manual.txt |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 5242a7e..19f571a 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -1009,7 +1009,7 @@ $ git init
 If you have some initial content (say, a tarball):
 
 -------------------------------------------------
-$ tar -xzvf project.tar.gz
+$ tar xzvf project.tar.gz
 $ cd project
 $ git init
 $ git add . # include everything below ./ in the first commit:
-- 
1.6.1.36.g8430e

^ permalink raw reply related

* Re: [BUG] unable to checkout branch with a clean worktree
From: Clemens Buchacher @ 2009-01-05 16:05 UTC (permalink / raw)
  To: Anders Melchiorsen; +Cc: git
In-Reply-To: <35079.bFoQE3daRhY=.1231170168.squirrel@webmail.hotelhot.dk>

On Mon, Jan 05, 2009 at 04:42:48PM +0100, Anders Melchiorsen wrote:
> Git v1.6.1: The final checkout fails with an error about merge conflicts.
> However, the worktree is clean, and I am not trying to do a merge.
> 
> Is this a known issue? If so, what is the particular issue that we should
> avoid?

This is fixed by the recent patches for verify_absent. (Actually, just PATCH
2/3 should be enough to fix this issue.)

http://article.gmane.org/gmane.comp.version-control.git/104317

^ permalink raw reply

* Re: a few Topgit patches
From: martin f krafft @ 2009-01-05 15:49 UTC (permalink / raw)
  To: Uwe Kleine-König, git, Petr Baudis
In-Reply-To: <20090104130532.GA1055@pengutronix.de>

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

also sprach Uwe Kleine-König <u.kleine-koenig@pengutronix.de> [2009.01.04.1405 +0100]:
> This is done.  Now I even changed '-n' to '--numbered' and changed the
> commit log accordingly.  Are there still concerns about my patches?
> Should I resend the current version?
> 
> The patches are still available in my topgit repo at
> 
> 	git://git.pengutronix.de/git/ukl/topgit.git master

I pulled and pushed them. Thanks.

-- 
 .''`.   martin f. krafft <madduck@d.o>      Related projects:
: :'  :  proud Debian developer               http://debiansystem.info
`. `'`   http://people.debian.org/~madduck    http://vcs-pkg.org
  `-  Debian - when you have better things to do than fixing systems
 
sed -e '/^[when][coders]/!d' \
    -e '/^...[discover].$/d' \
    -e '/^..[real].[code]$/!d' \
    /usr/share/dict/words

[-- Attachment #2: Digital signature (see http://martin-krafft.net/gpg/) --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* Re: [PATCH (topgit) 0/2] tg-completion.bash update
From: martin f krafft @ 2009-01-05 15:49 UTC (permalink / raw)
  To: Kirill Smelkov, git; +Cc: pasky
In-Reply-To: <cover.1231167904.git.kirr@landau.phys.spbu.ru>

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

also sprach Kirill Smelkov <kirr@landau.phys.spbu.ru> [2009.01.05.1608 +0100]:
> Kirill Smelkov (2):
>   tg-completion: complete options for `tg summary`
>   tg-completion: complete options for `tg remote`

Pushed; thanks.

-- 
martin | http://madduck.net/ | http://two.sentenc.es/
 
"alles sollte so einfach, wie möglich gemacht sein,
 aber nicht einfacher."
                                                    -- albert einstein
 
spamtraps: madduck.bogus@madduck.net

[-- Attachment #2: Digital signature (see http://martin-krafft.net/gpg/) --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* [BUG] unable to checkout branch with a clean worktree
From: Anders Melchiorsen @ 2009-01-05 15:42 UTC (permalink / raw)
  To: git

Git v1.6.1: The final checkout fails with an error about merge conflicts.
However, the worktree is clean, and I am not trying to do a merge.

Is this a known issue? If so, what is the particular issue that we should
avoid?


Regards,
Anders.


cd $(mktemp -d repo.XXXXXX)
git init

echo init >start
git add start
git commit -m A

git branch parallel

mkdir a b
echo x >a/one
echo y >a/two
echo z >b/three
git add .
git commit -m B

git checkout parallel
mkdir -p a/one a/two b
echo xx >a/one/cat
echo yy >a/two/cow
echo zz >b/unrelated
git add .
git commit -m C

# This fails:
git checkout master

^ permalink raw reply

* [PATCH (topgit) 0/2] tg-completion.bash update
From: Kirill Smelkov @ 2009-01-05 15:08 UTC (permalink / raw)
  To: git; +Cc: Kirill Smelkov

Kirill Smelkov (2):
  tg-completion: complete options for `tg summary`
  tg-completion: complete options for `tg remote`

 contrib/tg-completion.bash |   15 ++++++++++++++-
 1 files changed, 14 insertions(+), 1 deletions(-)

^ permalink raw reply

* [PATCH (topgit) 2/2] tg-completion: complete options for `tg remote`
From: Kirill Smelkov @ 2009-01-05 15:08 UTC (permalink / raw)
  To: git; +Cc: Kirill Smelkov
In-Reply-To: <cover.1231167904.git.kirr@landau.phys.spbu.ru>

Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
---
 contrib/tg-completion.bash |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)

diff --git a/contrib/tg-completion.bash b/contrib/tg-completion.bash
index 4d69c05..9641d04 100755
--- a/contrib/tg-completion.bash
+++ b/contrib/tg-completion.bash
@@ -369,6 +369,11 @@ _tg_remote ()
 	local cur="${COMP_WORDS[COMP_CWORD]}"
 
 	case "$cur" in
+	-*)
+		__tgcomp "
+			--populate
+		"
+		;;
 	*)
 		__tgcomp "$(__tg_remotes)"
 	esac
-- 
1.6.1.40.g8ea6a

^ permalink raw reply related

* [PATCH (topgit) 1/2] tg-completion: complete options for `tg summary`
From: Kirill Smelkov @ 2009-01-05 15:08 UTC (permalink / raw)
  To: git; +Cc: Kirill Smelkov
In-Reply-To: <cover.1231167904.git.kirr@landau.phys.spbu.ru>

Signed-off-by: Kirill Smelkov <kirr@landau.phys.spbu.ru>
---
 contrib/tg-completion.bash |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/contrib/tg-completion.bash b/contrib/tg-completion.bash
index 67f820e..4d69c05 100755
--- a/contrib/tg-completion.bash
+++ b/contrib/tg-completion.bash
@@ -376,7 +376,15 @@ _tg_remote ()
 
 _tg_summary ()
 {
-	COMPREPLY=()
+	local cur="${COMP_WORDS[COMP_CWORD]}"
+
+	case "$cur" in
+	*)
+		__tgcomp "
+			--graphviz
+			-t
+		"
+	esac
 }
 
 _tg_update ()
-- 
1.6.1.40.g8ea6a

^ permalink raw reply related

* [PATCH/RFC 4/4] remove the old 'has_symlink_leading_path()' function
From: Kjetil Barvik @ 2009-01-05 13:10 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds, Junio C Hamano, Kjetil Barvik
In-Reply-To: <1231161001-32599-1-git-send-email-barvik@broadpark.no>

It has been replaced by the more cache effective 'lstat_cache()'
function.  see lstat_cache.c

Signed-off-by: Kjetil Barvik <barvik@broadpark.no>
---
:100644 100644 7449b10... edd4798... M	Makefile
:100644 100644 8d0228c... dc5c383... M	cache.h
:100644 000000 5a5e781... 0000000... D	symlinks.c
 Makefile   |    1 -
 cache.h    |    1 -
 symlinks.c |   64 ------------------------------------------------------------
 3 files changed, 0 insertions(+), 66 deletions(-)
 delete mode 100644 symlinks.c

diff --git a/Makefile b/Makefile
index 7449b105b03e862d53244d50ed035b4ddabef028..edd4798429ad3828f5b9dcff20f73c6a7269520e 100644
--- a/Makefile
+++ b/Makefile
@@ -483,7 +483,6 @@ LIB_OBJS += sha1_name.o
 LIB_OBJS += shallow.o
 LIB_OBJS += sideband.o
 LIB_OBJS += strbuf.o
-LIB_OBJS += symlinks.o
 LIB_OBJS += tag.o
 LIB_OBJS += trace.o
 LIB_OBJS += transport.o
diff --git a/cache.h b/cache.h
index 8d0228c857ab9d8e31585ad5aa6838403adef3a2..dc5c3833d789a6012f9ce05522c8840f01ddc027 100644
--- a/cache.h
+++ b/cache.h
@@ -720,7 +720,6 @@ struct checkout {
 
 extern void clear_created_dirs_cache(void);
 extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
-extern int has_symlink_leading_path(int len, const char *name);
 
 #define LSTAT_DIR       (1u << 0)
 #define LSTAT_NOTDIR    (1u << 1)
diff --git a/symlinks.c b/symlinks.c
deleted file mode 100644
index 5a5e781a15d7d9cb60797958433eca896b31ec85..0000000000000000000000000000000000000000
--- a/symlinks.c
+++ /dev/null
@@ -1,64 +0,0 @@
-#include "cache.h"
-
-struct pathname {
-	int len;
-	char path[PATH_MAX];
-};
-
-/* Return matching pathname prefix length, or zero if not matching */
-static inline int match_pathname(int len, const char *name, struct pathname *match)
-{
-	int match_len = match->len;
-	return (len > match_len &&
-		name[match_len] == '/' &&
-		!memcmp(name, match->path, match_len)) ? match_len : 0;
-}
-
-static inline void set_pathname(int len, const char *name, struct pathname *match)
-{
-	if (len < PATH_MAX) {
-		match->len = len;
-		memcpy(match->path, name, len);
-		match->path[len] = 0;
-	}
-}
-
-int has_symlink_leading_path(int len, const char *name)
-{
-	static struct pathname link, nonlink;
-	char path[PATH_MAX];
-	struct stat st;
-	char *sp;
-	int known_dir;
-
-	/*
-	 * See if the last known symlink cache matches.
-	 */
-	if (match_pathname(len, name, &link))
-		return 1;
-
-	/*
-	 * Get rid of the last known directory part
-	 */
-	known_dir = match_pathname(len, name, &nonlink);
-
-	while ((sp = strchr(name + known_dir + 1, '/')) != NULL) {
-		int thislen = sp - name ;
-		memcpy(path, name, thislen);
-		path[thislen] = 0;
-
-		if (lstat(path, &st))
-			return 0;
-		if (S_ISDIR(st.st_mode)) {
-			set_pathname(thislen, path, &nonlink);
-			known_dir = thislen;
-			continue;
-		}
-		if (S_ISLNK(st.st_mode)) {
-			set_pathname(thislen, path, &link);
-			return 1;
-		}
-		break;
-	}
-	return 0;
-}
-- 
1.6.1.rc1.49.g7f705

^ permalink raw reply related

* [PATCH/RFC 3/4] create_directories() inside entry.c: only check each directory once!
From: Kjetil Barvik @ 2009-01-05 13:10 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds, Junio C Hamano, Kjetil Barvik
In-Reply-To: <1231161001-32599-1-git-send-email-barvik@broadpark.no>

When we do an 'git checkout' after some time we end up in the
'checkout_entry()' function inside entry.c, and from here we call the
'create_directories()' function to make sure the all the directories
exists for the possible new file or entry.

The 'create_directories()' function happily started to check that all
path component exists.  This resulted in tons and tons of calls to
lstat() or stat() when we checkout files nested deep inside a
directory.

We try to avoid this by remembering the last checked and possible
newly created directory.

Signed-off-by: Kjetil Barvik <barvik@broadpark.no>
---
:100644 100644 7c246a4... 8d0228c... M	cache.h
:100644 100644 aa2ee46... 666a8ce... M	entry.c
:100644 100644 93923db... 7a2219d... M	unpack-trees.c
 cache.h        |    1 +
 entry.c        |   86 ++++++++++++++++++++++++++++++++++++++++++++------------
 unpack-trees.c |    1 +
 3 files changed, 70 insertions(+), 18 deletions(-)

diff --git a/cache.h b/cache.h
index 7c246a42df3d60ac2c0f7431ff29ee8fb70235ce..8d0228c857ab9d8e31585ad5aa6838403adef3a2 100644
--- a/cache.h
+++ b/cache.h
@@ -718,6 +718,7 @@ struct checkout {
 		 refresh_cache:1;
 };
 
+extern void clear_created_dirs_cache(void);
 extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
 extern int has_symlink_leading_path(int len, const char *name);
 
diff --git a/entry.c b/entry.c
index aa2ee46a84033585d8e07a585610c5a697af82c2..666a8ce3a132e85a45b0828521f3c2119c77833e 100644
--- a/entry.c
+++ b/entry.c
@@ -1,33 +1,76 @@
 #include "cache.h"
 #include "blob.h"
 
-static void create_directories(const char *path, const struct checkout *state)
+static char dirs_path[PATH_MAX];
+static int  dirs_len = 0;
+
+static inline int
+greatest_common_created_dirs_prefix(int len, const char *name)
 {
-	int len = strlen(path);
-	char *buf = xmalloc(len + 1);
-	const char *slash = path;
+	int max_len, match_len = 0, i = 0;
 
-	while ((slash = strchr(slash+1, '/')) != NULL) {
-		struct stat st;
-		int stat_status;
+	max_len = len < dirs_len ? len : dirs_len;
+	while (i < max_len && name[i] == dirs_path[i]) {
+		if (name[i] == '/') match_len = i;
+		i++;
+	}
+	if (i == dirs_len && len > dirs_len && name[dirs_len] == '/')
+		match_len = dirs_len;
+	return match_len;
+}
+
+static inline void
+update_created_dirs_cache(int last_slash)
+{
+	if (last_slash > 0 && last_slash < PATH_MAX) {
+		dirs_len = last_slash;
+	} else {
+		dirs_len = 0;
+	}
+}
 
-		len = slash - path;
-		memcpy(buf, path, len);
-		buf[len] = 0;
+void clear_created_dirs_cache(void)
+{
+	dirs_len = 0;
+}
+
+static void
+create_directories(int len, const char *path, const struct checkout *state)
+{
+	int i, max_len, last_slash, stat_status;
+	struct stat st;
+
+	/* Check the cache for previously checked or created
+	 * directories (and components) within this function.  There
+	 * is no need to check or re-create directory components more
+	 * than once!
+	 */
+	max_len = len < PATH_MAX ? len : PATH_MAX;
+	i = last_slash = greatest_common_created_dirs_prefix(max_len, path);
 
-		if (len <= state->base_dir_len)
+	while (i < max_len) {
+		do {
+			dirs_path[i] = path[i];
+			i++;
+		} while (i < max_len && path[i] != '/');
+		if (i >= max_len)
+			break;
+		last_slash = i;
+		dirs_path[last_slash] = '\0';
+
+		if (last_slash <= state->base_dir_len)
 			/*
 			 * checkout-index --prefix=<dir>; <dir> is
 			 * allowed to be a symlink to an existing
 			 * directory.
 			 */
-			stat_status = stat(buf, &st);
+			stat_status = stat(dirs_path, &st);
 		else
 			/*
 			 * if there currently is a symlink, we would
 			 * want to replace it with a real directory.
 			 */
-			stat_status = lstat(buf, &st);
+			stat_status = lstat(dirs_path, &st);
 
 		if (!stat_status && S_ISDIR(st.st_mode))
 			continue; /* ok, it is already a directory. */
@@ -38,14 +81,14 @@ static void create_directories(const char *path, const struct checkout *state)
 		 * error codepath; we do not care, as we unlink and
 		 * mkdir again in such a case.
 		 */
-		if (mkdir(buf, 0777)) {
+		if (mkdir(dirs_path, 0777)) {
 			if (errno == EEXIST && state->force &&
-			    !unlink(buf) && !mkdir(buf, 0777))
+			    !unlink(dirs_path) && !mkdir(dirs_path, 0777))
 				continue;
-			die("cannot create directory at %s", buf);
+			die("cannot create directory at %s", dirs_path);
 		}
 	}
-	free(buf);
+	update_created_dirs_cache(last_slash);
 }
 
 static void remove_subtree(const char *path)
@@ -55,6 +98,11 @@ static void remove_subtree(const char *path)
 	char pathbuf[PATH_MAX];
 	char *name;
 
+	/* To be utterly safe we invalidate the cache of the
+	 * previously created directories.
+	 */
+	clear_created_dirs_cache();
+
 	if (!dir)
 		die("cannot opendir %s (%s)", path, strerror(errno));
 	strcpy(pathbuf, path);
@@ -195,12 +243,14 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
 	static char path[PATH_MAX + 1];
 	struct stat st;
 	int len = state->base_dir_len;
+	int path_len;
 
 	if (topath)
 		return write_entry(ce, topath, state, 1);
 
 	memcpy(path, state->base_dir, len);
 	strcpy(path + len, ce->name);
+	path_len = len + ce_namelen(ce);
 
 	if (!lstat(path, &st)) {
 		unsigned changed = ce_match_stat(ce, &st, CE_MATCH_IGNORE_VALID);
@@ -229,6 +279,6 @@ int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *t
 			return error("unable to unlink old '%s' (%s)", path, strerror(errno));
 	} else if (state->not_new)
 		return 0;
-	create_directories(path, state);
+	create_directories(path_len, path, state);
 	return write_entry(ce, path, state, 0);
 }
diff --git a/unpack-trees.c b/unpack-trees.c
index 93923dbbc6ab80deadfd737aa9975f6e5a4d1e89..7a2219d14d19b80e67c01d051e57c341f60f455c 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -121,6 +121,7 @@ static int check_updates(struct unpack_trees_options *o)
 		}
 	}
 
+	clear_created_dirs_cache();
 	for (i = 0; i < index->cache_nr; i++) {
 		struct cache_entry *ce = index->cache[i];
 
-- 
1.6.1.rc1.49.g7f705

^ permalink raw reply related

* [PATCH/RFC 2/4] Use 'lstat_cache()' instead of 'has_symlink_leading_path()'
From: Kjetil Barvik @ 2009-01-05 13:09 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds, Junio C Hamano, Kjetil Barvik
In-Reply-To: <1231161001-32599-1-git-send-email-barvik@broadpark.no>

Start using the optimised, faster and more effective symlink/directory
cache.  The previously used call:

   has_symlink_leading_path(len, name);

should be identically with the following call to lstat_cache():

   lstat_cache(len, name,
               LSTAT_SYMLINK|LSTAT_DIR,
               LSTAT_SYMLINK);

The primary reason for the new name of the function (instead of using
the old name and add 2 extra arguments), is that it is now more
general, for instance, it now also can cache the fact that a directory
does not exists.

I noticed that inside the unlink_entry() function in unpack-trees.c,
one could often end up calling rmdir() lots and lots of times on
none-empty directories.  Maybe one should schedule each directory for
removal by an appropriate function, and then at the end call a new
function to clean all the directories at once?

Signed-off-by: Kjetil Barvik <barvik@broadpark.no>
---
:100644 100644 719de8b... 152c52c... M	builtin-add.c
:100644 100644 a8f75ed... 0eb2b21... M	builtin-apply.c
:100644 100644 65d5775... fa7d994... M	builtin-update-index.c
:100644 100644 ae96c64... 127bdf2... M	diff-lib.c
:100644 100644 0131983... 9f2a1b1... M	dir.c
:100644 100644 54f301d... 93923db... M	unpack-trees.c
 builtin-add.c          |    5 ++++-
 builtin-apply.c        |    5 ++++-
 builtin-update-index.c |    5 ++++-
 diff-lib.c             |    5 ++++-
 dir.c                  |    4 +++-
 unpack-trees.c         |    9 +++++++--
 6 files changed, 26 insertions(+), 7 deletions(-)

diff --git a/builtin-add.c b/builtin-add.c
index 719de8b0f2d2d831f326d948aa18700e5c474950..152c52c0f22b3e71931b2a5629e1472602817785 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -121,7 +121,9 @@ static const char **validate_pathspec(int argc, const char **argv, const char *p
 	if (pathspec) {
 		const char **p;
 		for (p = pathspec; *p; p++) {
-			if (has_symlink_leading_path(strlen(*p), *p)) {
+			if (lstat_cache(strlen(*p), *p,
+					LSTAT_SYMLINK|LSTAT_DIR,
+					LSTAT_SYMLINK)) {
 				int len = prefix ? strlen(prefix) : 0;
 				die("'%s' is beyond a symbolic link", *p + len);
 			}
@@ -225,6 +227,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
 
 	argc = parse_options(argc, argv, builtin_add_options,
 			  builtin_add_usage, 0);
+	clear_lstat_cache();
 	if (patch_interactive)
 		add_interactive = 1;
 	if (add_interactive)
diff --git a/builtin-apply.c b/builtin-apply.c
index a8f75ed3ed411d8cf7a3ec9dfefef7407c50f447..0eb2b21ee245919189c780a64cc494ca35f7934a 100644
--- a/builtin-apply.c
+++ b/builtin-apply.c
@@ -2354,7 +2354,9 @@ static int check_to_create_blob(const char *new_name, int ok_if_exists)
 		 * In such a case, path "new_name" does not exist as
 		 * far as git is concerned.
 		 */
-		if (has_symlink_leading_path(strlen(new_name), new_name))
+		if (lstat_cache(strlen(new_name), new_name,
+				LSTAT_SYMLINK|LSTAT_DIR,
+				LSTAT_SYMLINK))
 			return 0;
 
 		return error("%s: already exists in working directory", new_name);
@@ -3154,6 +3156,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
 	if (apply_default_whitespace)
 		parse_whitespace_option(apply_default_whitespace);
 
+	clear_lstat_cache();
 	for (i = 1; i < argc; i++) {
 		const char *arg = argv[i];
 		char *end;
diff --git a/builtin-update-index.c b/builtin-update-index.c
index 65d5775107f9013526cc5b288a80a00b449e8814..fa7d994b3cfe7343c1a181f4c6f6a4c6ee6cea75 100644
--- a/builtin-update-index.c
+++ b/builtin-update-index.c
@@ -195,7 +195,9 @@ static int process_path(const char *path)
 	struct stat st;
 
 	len = strlen(path);
-	if (has_symlink_leading_path(len, path))
+	if (lstat_cache(len, path,
+			LSTAT_SYMLINK|LSTAT_DIR,
+			LSTAT_SYMLINK))
 		return error("'%s' is beyond a symbolic link", path);
 
 	/*
@@ -581,6 +583,7 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
 	if (entries < 0)
 		die("cache corrupted");
 
+	clear_lstat_cache();
 	for (i = 1 ; i < argc; i++) {
 		const char *path = argv[i];
 		const char *p;
diff --git a/diff-lib.c b/diff-lib.c
index ae96c64ca209f4df9008198e8a04b160bed618c7..127bdf2dfbeb3538fa01e500ed8bcd3f4c8d422b 100644
--- a/diff-lib.c
+++ b/diff-lib.c
@@ -31,7 +31,9 @@ static int check_removed(const struct cache_entry *ce, struct stat *st)
 			return -1;
 		return 1;
 	}
-	if (has_symlink_leading_path(ce_namelen(ce), ce->name))
+	if (lstat_cache(ce_namelen(ce), ce->name,
+			LSTAT_SYMLINK|LSTAT_NOTDIR|LSTAT_DIR,
+			LSTAT_SYMLINK))
 		return 1;
 	if (S_ISDIR(st->st_mode)) {
 		unsigned char sub[20];
@@ -69,6 +71,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
 		diff_unmerged_stage = 2;
 	entries = active_nr;
 	symcache[0] = '\0';
+	clear_lstat_cache();
 	for (i = 0; i < entries; i++) {
 		struct stat st;
 		unsigned int oldmode, newmode;
diff --git a/dir.c b/dir.c
index 0131983dfbc143ce5dae77e067663bb2e7d5f126..9f2a1b1f245c3f1d4f12d54d45bb193c53fa15b5 100644
--- a/dir.c
+++ b/dir.c
@@ -719,7 +719,9 @@ int read_directory(struct dir_struct *dir, const char *path, const char *base, i
 {
 	struct path_simplify *simplify;
 
-	if (has_symlink_leading_path(strlen(path), path))
+	if (lstat_cache(strlen(path), path,
+			LSTAT_SYMLINK|LSTAT_DIR,
+			LSTAT_SYMLINK))
 		return dir->nr;
 
 	simplify = create_simplify(pathspec);
diff --git a/unpack-trees.c b/unpack-trees.c
index 54f301da67be879c80426bc21776427fdd38c02e..93923dbbc6ab80deadfd737aa9975f6e5a4d1e89 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -61,7 +61,9 @@ static void unlink_entry(struct cache_entry *ce)
 	char *cp, *prev;
 	char *name = ce->name;
 
-	if (has_symlink_leading_path(ce_namelen(ce), ce->name))
+	if (lstat_cache(ce_namelen(ce), ce->name,
+			LSTAT_SYMLINK|LSTAT_NOTDIR|LSTAT_DIR,
+			LSTAT_SYMLINK|LSTAT_NOTDIR))
 		return;
 	if (unlink(name))
 		return;
@@ -105,6 +107,7 @@ static int check_updates(struct unpack_trees_options *o)
 		cnt = 0;
 	}
 
+	clear_lstat_cache();
 	for (i = 0; i < index->cache_nr; i++) {
 		struct cache_entry *ce = index->cache[i];
 
@@ -584,7 +587,9 @@ static int verify_absent(struct cache_entry *ce, const char *action,
 	if (o->index_only || o->reset || !o->update)
 		return 0;
 
-	if (has_symlink_leading_path(ce_namelen(ce), ce->name))
+	if (lstat_cache(ce_namelen(ce), ce->name,
+			LSTAT_SYMLINK|LSTAT_NOTDIR|LSTAT_DIR,
+			LSTAT_SYMLINK|LSTAT_NOTDIR))
 		return 0;
 
 	if (!lstat(ce->name, &st)) {
-- 
1.6.1.rc1.49.g7f705

^ permalink raw reply related

* [PATCH/RFC 1/4] Optimised, faster, more effective symlink/directory detection
From: Kjetil Barvik @ 2009-01-05 13:09 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds, Junio C Hamano, Kjetil Barvik
In-Reply-To: <1231161001-32599-1-git-send-email-barvik@broadpark.no>

This patch is work based on the following 2 commits:

Linus Torvalds: c40641b77b0274186fd1b327d5dc3246f814aaaf
Junio C Hamano: f859c846e90b385c7ef873df22403529208ade50

Changes includes the following:

- The cache functionality is more effective.  Previously when A/B/C/D
  was in the cache and A/B/C/E/file.c was called for, there was no
  match at all from the cache.  Now we use the fact that the paths
  "A", "A/B" and "A/B/C" is already tested, and we only need to do an
  lstat() call on "A/B/C/E".

- We only cache/store the last path regardless of it's type.  Since the
  cache functionality is always used with alphabetically sorted names
  (at least it seams so for me), there is no need to store both the
  last symlink-leading path and the last real-directory path.  Note
  that if the cache is not called with (mostly) alphabetically sorted
  names, neither the old, nor this new one, would be very effective.

- We also can cache the fact that a directory does not exist.
  Previously we could end up doing lots of lstat() calls for a removed
  directory which previously contained lots of files.  Since we
  already have simplified the cache functionality and only store the
  last path (see above), this new functionality was easy to add.

- Avoid copying the first path components of the name 2 zillions times
  when we tests new path components.  Since we always cache/store the
  last path, we can copy each component as we test those directly into
  the cache.  Previously we ended up doing a memcpy() for the full
  path/name right before each lstat() call, and when updating the
  cache for each time we have tested an new path component.

- We also use less memory, that is PATH_MAX bytes less memory on the
  stack and PATH_MAX bytes less memory on the heap.

- Introduce a 3rd argument, 'unsigned int track_flags', to the
  cache-test function, check_lstat_cache().  This new argument can be
  used to tell the cache functionality which types of directories
  should be cached.

- Also introduce a 'void clear_lstat_cache(void)' function, which
  should be used to clean the cache before usage.  If for instance,
  you have changed the types of directories which should be cached,
  the cache could contain a path which was not wanted.

Signed-off-by: Kjetil Barvik <barvik@broadpark.no>
---
:100644 100644 aabf013... 7449b10... M	Makefile
:100644 100644 231c06d... 7c246a4... M	cache.h
:000000 100644 0000000... 34f4e9a... A	lstat_cache.c
 Makefile      |    1 +
 cache.h       |   15 ++++++++
 lstat_cache.c |  105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 121 insertions(+), 0 deletions(-)
 create mode 100644 lstat_cache.c

diff --git a/Makefile b/Makefile
index aabf0130b99bee5204c8e668ba8f40caea77dae2..7449b105b03e862d53244d50ed035b4ddabef028 100644
--- a/Makefile
+++ b/Makefile
@@ -446,6 +446,7 @@ LIB_OBJS += list-objects.o
 LIB_OBJS += ll-merge.o
 LIB_OBJS += lockfile.o
 LIB_OBJS += log-tree.o
+LIB_OBJS += lstat_cache.o
 LIB_OBJS += mailmap.o
 LIB_OBJS += match-trees.o
 LIB_OBJS += merge-file.o
diff --git a/cache.h b/cache.h
index 231c06d7726b575f6e522d5b0c0fe43557e8c651..7c246a42df3d60ac2c0f7431ff29ee8fb70235ce 100644
--- a/cache.h
+++ b/cache.h
@@ -721,6 +721,21 @@ struct checkout {
 extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
 extern int has_symlink_leading_path(int len, const char *name);
 
+#define LSTAT_DIR       (1u << 0)
+#define LSTAT_NOTDIR    (1u << 1)
+#define LSTAT_SYMLINK   (1u << 2)
+#define LSTAT_LSTATERR  (1u << 3)
+#define LSTAT_ERR       (1u << 4)
+extern unsigned int check_lstat_cache(int len, const char *name,
+				      unsigned int track_flags);
+static inline unsigned int lstat_cache(int len, const char *name,
+				       unsigned int track_flags,
+				       unsigned int mask_flags)
+{
+	return check_lstat_cache(len, name, track_flags) & mask_flags;
+}
+extern void clear_lstat_cache(void);
+
 extern struct alternate_object_database {
 	struct alternate_object_database *next;
 	char *name;
diff --git a/lstat_cache.c b/lstat_cache.c
new file mode 100644
index 0000000000000000000000000000000000000000..34f4e9a003905323f45a4f739d2a354e02dbbe93
--- /dev/null
+++ b/lstat_cache.c
@@ -0,0 +1,105 @@
+#include "cache.h"
+
+static char         cache_path[PATH_MAX];
+static int          cache_len   = 0;
+static unsigned int cache_flags = 0;
+
+static inline int
+greatest_common_path_cache_prefix(int len, const char *name)
+{
+	int max_len, match_len = 0, i = 0;
+
+	max_len = len < cache_len ? len : cache_len;
+	while (i < max_len && name[i] == cache_path[i]) {
+		if (name[i] == '/') match_len = i;
+		i++;
+	}
+	if (i == cache_len && len > cache_len && name[cache_len] == '/')
+		match_len = cache_len;
+	return match_len;
+}
+
+static inline void
+update_path_cache(unsigned int ret_flags, unsigned int track_flags,
+		  int last_slash)
+{
+	/* Max 3 different path types can be cached for the moment! */
+	unsigned int save_flags =
+		ret_flags & track_flags & (LSTAT_DIR|
+					   LSTAT_NOTDIR|
+					   LSTAT_SYMLINK);
+	if (save_flags && last_slash > 0 && last_slash < PATH_MAX) {
+		cache_flags = save_flags;
+		cache_len   = last_slash;
+	} else {
+		cache_flags = 0;
+		cache_len   = 0;
+	}
+}
+
+/*
+ * Check if name 'name' of length 'len' has a symlink leading
+ * component, or if the directory exists and is real, or not.
+ *
+ * To speed up the check, some information is allowed to be cached.
+ * This is indicated by the 'track_flags' argument.
+ */
+unsigned int
+check_lstat_cache(int len, const char *name, unsigned int track_flags)
+{
+	int match_len, last_slash, max_len;
+	unsigned int match_flags, ret_flags;
+	struct stat st;
+
+	/* Check if match from the cache for 2 "excluding" path types.
+	 */
+	match_len = last_slash =
+		greatest_common_path_cache_prefix(len, name);
+	match_flags =
+		cache_flags & track_flags & (LSTAT_NOTDIR|
+					     LSTAT_SYMLINK);
+	if (match_flags && match_len == cache_len)
+		return match_flags;
+
+	/* Okay, no match from the cache so far, so now we have to
+	 * check the rest of the path components and update the cache.
+	 */
+	ret_flags = LSTAT_DIR;
+	max_len = len < PATH_MAX ? len : PATH_MAX;
+	while (match_len < max_len) {
+		do {
+			cache_path[match_len] = name[match_len];
+			match_len++;
+		} while (match_len < max_len && name[match_len] != '/');
+		if (match_len >= max_len)
+			break;
+		last_slash = match_len;
+		cache_path[last_slash] = '\0';
+
+		if (lstat(cache_path, &st)) {
+			ret_flags = LSTAT_LSTATERR;
+			if (errno == ENOENT || errno == ENOTDIR)
+				ret_flags |= LSTAT_NOTDIR;
+		} else if (S_ISDIR(st.st_mode)) {
+			continue;
+		} else if (S_ISLNK(st.st_mode)) {
+			ret_flags = LSTAT_SYMLINK;
+		} else {
+			ret_flags = LSTAT_ERR;
+		}
+		break;
+	}
+	update_path_cache(ret_flags, track_flags, last_slash);
+	return ret_flags;
+}
+
+/*
+ * Before usage of the check_lstat_cache() function one should call
+ * clear_lstat_cache() (at an appropriate place) to make sure that the
+ * cache is clean before first call to check_lstat_cache().
+ */
+void clear_lstat_cache(void)
+{
+	cache_flags = 0;
+	cache_len   = 0;
+}
-- 
1.6.1.rc1.49.g7f705

^ permalink raw reply related

* [PATCH/RFC 0/4] git checkout: optimise away lots of lstat() calls
From: Kjetil Barvik @ 2009-01-05 13:09 UTC (permalink / raw)
  To: git; +Cc: Linus Torvalds, Junio C Hamano, Kjetil Barvik

I have just started to clone some interesting Linux git trees to watch
the development more closely, and therefore also started to use git. I
noticed that 'git checkout' takes some time, and especially that the
'git checkout' command does lots and lots of lstat() calls.

After some more investigation and thinking, I have made 4 patches and
been able to optimise away over 42% of all lstat() calls in some cases
for the 'git checkout' command.  I have not tested other git porcelain
commands for reduced lstat() calls, but I would guess that the more
effective 'lstat_cache()' compared to 'has_leading_symlink_cache()',
should also give better numbers in other cases.

All the 4 patches is against git master, and the git 'make test'
test suite still passes after each patch.

To document the improvement, below is some numbers, which compares
before and after all 4 patches. To reproduce the numbers:

- git clone the Linux git tree to be able to get the Linux tags
  'v2.6.25' and 'v2.6.27'.
- git checkout -b my-v2.6.27 v2.6.27
- git checkout -b my-v2.6.25 v2.6.25

Then, when the current branch is 'my-v2.6.25' do:

  strace -o strace_to27 -T git checkout -q my-v2.6.27

And then you pretty print and collect stats from the 'strace_to27'
file.  If someone wants a copy of the strace_stat.pl script, which I
made/used to do the pretty printing, then give me a hint.

Below is the stats/numbers from the current git version (before the 4
patches).  Notice that we do an lstat() call on the "arch" directory
over 6000 times!

TOTAL      185151 100.000% OK:165544 NOT: 19607  11.136001 sec   60 usec/call
lstat64    120954  65.327% OK:107013 NOT: 13941   5.388727 sec   45 usec/call
  strings  120954 tot  30163 uniq   4.010 /uniq   5.388727 sec   45 usec/call
  files     61491 tot  28712 uniq   2.142 /uniq   2.740520 sec   45 usec/call
  dirs      45522 tot   1436 uniq  31.701 /uniq   1.994448 sec   44 usec/call
  errors    13941 tot   5189 uniq   2.687 /uniq   0.653759 sec   47 usec/call
             6297   5.206% OK:  6297 NOT:     0  "arch"
             4544   3.757% OK:  4544 NOT:     0  "drivers"
             1816   1.501% OK:  1816 NOT:     0  "arch/arm"
             1499   1.239% OK:  1499 NOT:     0  "include"
              912   0.754% OK:   912 NOT:     0  "arch/powerpc"
              764   0.632% OK:   764 NOT:     0  "fs"
              746   0.617% OK:   746 NOT:     0  "drivers/net"
              662   0.547% OK:   662 NOT:     0  "net"
              652   0.539% OK:   325 NOT:   327  "arch/sparc/include"
              636   0.526% OK:   636 NOT:     0  "drivers/media"
              606   0.501% OK:   606 NOT:     0  "include/linux"
              533   0.441% OK:   533 NOT:     0  "arch/sh"
              522   0.432% OK:   260 NOT:   262  "arch/powerpc/include"
              488   0.403% OK:   243 NOT:   245  "arch/sh/include"
              413   0.341% OK:   413 NOT:     0  "arch/sparc"
              390   0.322% OK:   390 NOT:     0  "arch/x86"
              383   0.317% OK:   383 NOT:     0  "Documentation"
              370   0.306% OK:   184 NOT:   186  "arch/ia64/include"
              366   0.303% OK:   366 NOT:     0  "drivers/media/video"
              348   0.288% OK:   173 NOT:   175  "arch/arm/include"

Here is the stats/numbers after applying the 4 patches.  Notice how
nice the top 20 entries list now looks!

TOTAL      133655 100.000% OK:121615 NOT: 12040  10.429999 sec   78 usec/call
lstat64     69603  52.077% OK: 63218 NOT:  6385   3.419920 sec   49 usec/call
  strings   69603 tot  30163 uniq   2.308 /uniq   3.419920 sec   49 usec/call
  files     61491 tot  28712 uniq   2.142 /uniq   3.034869 sec   49 usec/call
  dirs       1727 tot   1164 uniq   1.484 /uniq   0.075681 sec   44 usec/call
  errors     6385 tot   5189 uniq   1.230 /uniq   0.309370 sec   48 usec/call
                4   0.006% OK:     4 NOT:     0  ".gitignore"
                4   0.006% OK:     4 NOT:     0  ".mailmap"
                4   0.006% OK:     4 NOT:     0  "CREDITS"
                4   0.006% OK:     4 NOT:     0  "Documentation/00-INDEX"
                4   0.006% OK:     4 NOT:     0  "Documentation/ABI/testing/sysfs-block"
                4   0.006% OK:     4 NOT:     0  "Documentation/ABI/testing/sysfs-firmware-acpi"
                4   0.006% OK:     4 NOT:     0  "Documentation/CodingStyle"
                4   0.006% OK:     4 NOT:     0  "Documentation/DMA-API.txt"
                4   0.006% OK:     4 NOT:     0  "Documentation/DMA-mapping.txt"
                4   0.006% OK:     4 NOT:     0  "Documentation/DocBook/Makefile"
                4   0.006% OK:     4 NOT:     0  "Documentation/DocBook/gadget.tmpl"
                4   0.006% OK:     4 NOT:     0  "Documentation/DocBook/kernel-api.tmpl"
                4   0.006% OK:     4 NOT:     0  "Documentation/DocBook/kernel-locking.tmpl"
                4   0.006% OK:     4 NOT:     0  "Documentation/DocBook/procfs-guide.tmpl"
                4   0.006% OK:     4 NOT:     0  "Documentation/DocBook/procfs_example.c"
                4   0.006% OK:     4 NOT:     0  "Documentation/DocBook/rapidio.tmpl"
                4   0.006% OK:     4 NOT:     0  "Documentation/DocBook/s390-drivers.tmpl"
                4   0.006% OK:     4 NOT:     0  "Documentation/DocBook/uio-howto.tmpl"
                4   0.006% OK:     4 NOT:     0  "Documentation/DocBook/videobook.tmpl"
                4   0.006% OK:     4 NOT:     0  "Documentation/DocBook/writing_usb_driver.tmpl"

Note that the overall used system time as recorded from 'strace -T',
does not drop so much that the reduced lstat() time should indicate
for _this_ particular test run.  This is because now each unlink()
call takes much more time, at least for me on an slow ide disk (using
ext3) on a laptop.

A simple test gives me an overall improvement of 2.937 seconds: real
time drops from 28.195s (best of 5 runs with 'time git ...'), to
25.381s (best of 5 runs).

Comments?

Kjetil Barvik (4):
  Optimised, faster, more effective symlink/directory detection
  Use 'lstat_cache()' instead of 'has_symlink_leading_path()'
  create_directories() inside entry.c: only check each directory once!
  remove the old 'has_symlink_leading_path()' function

 Makefile               |    2 +-
 builtin-add.c          |    5 ++-
 builtin-apply.c        |    5 ++-
 builtin-update-index.c |    5 ++-
 cache.h                |   17 +++++++-
 diff-lib.c             |    5 ++-
 dir.c                  |    4 +-
 entry.c                |   86 +++++++++++++++++++++++++++++++--------
 lstat_cache.c          |  105 ++++++++++++++++++++++++++++++++++++++++++++++++
 symlinks.c             |   64 -----------------------------
 unpack-trees.c         |   10 ++++-
 11 files changed, 217 insertions(+), 91 deletions(-)
 create mode 100644 lstat_cache.c
 delete mode 100644 symlinks.c

^ permalink raw reply

* [PATCH] Fix sourcing "test-lib.sh" using dash shell in "t3003-ls-files-narrow-match.sh"
From: Christian Couder @ 2009-01-05 13:30 UTC (permalink / raw)
  To: Junio C Hamano, Nguyen Thai Ngoc Duy; +Cc: git

dash barfs, on my old Ubuntu box, when "test-lib.sh" is sourced
without "./".

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
---
 t/t3003-ls-files-narrow-match.sh |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

	This patch applies to "pu".

diff --git a/t/t3003-ls-files-narrow-match.sh b/t/t3003-ls-files-narrow-match.sh
index 9879525..b576bca 100755
--- a/t/t3003-ls-files-narrow-match.sh
+++ b/t/t3003-ls-files-narrow-match.sh
@@ -2,7 +2,7 @@
 
 test_description='This test is for narrow spec matching'
 
-. test-lib.sh
+. ./test-lib.sh
 
 D="$(cd ..;pwd)"/t3003
 
-- 
1.6.1.143.gfd590.dirty

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox