Git development
 help / color / mirror / Atom feed
* [PATCH v4 1/2] rev-parse: add option --resolve-git-dir <path>
From: Fredrik Gustafsson @ 2011-08-15 21:17 UTC (permalink / raw)
  To: git; +Cc: gitster, jens.lehmann, hvoigt, iveqy
In-Reply-To: <1313443067-2642-1-git-send-email-iveqy@iveqy.com>

Check if <path> is a valid git-dir or a valid git-file that points
to a valid git-dir.

We want tests to be independent from the fact that a git-dir may
be a git-file. Thus we changed tests to use this feature.

Signed-off-by: Fredrik Gustafsson <iveqy@iveqy.com>
Mentored-by: Jens Lehmann <Jens.Lehmann@web.de>
Mentored-by: Heiko Voigt <hvoigt@hvoigt.net>
---
 Documentation/git-rev-parse.txt |    4 ++
 builtin/rev-parse.c             |    8 +++
 cache.h                         |    1 +
 setup.c                         |    7 +++
 t/t7400-submodule-basic.sh      |    4 +-
 t/t7403-submodule-sync.sh       |    5 +-
 t/t7407-submodule-foreach.sh    |  103 ++++++++++++++++++++-------------------
 7 files changed, 78 insertions(+), 54 deletions(-)

diff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt
index 42c9676..8023dc0 100644
--- a/Documentation/git-rev-parse.txt
+++ b/Documentation/git-rev-parse.txt
@@ -180,6 +180,10 @@ print a message to stderr and exit with nonzero status.
 <args>...::
 	Flags and parameters to be parsed.
 
+--resolve-git-dir <path>::
+	Check if <path> is a valid git-dir or a git-file pointing to a valid
+	git-dir. If <path> is a valid git-dir the resolved path to git-dir will
+	be printed.
 
 include::revisions.txt[]
 
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 4c19f84..98d1cbe 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -468,6 +468,14 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
 		return 0;
 	}
 
+	if (argc > 2 && !strcmp(argv[1], "--resolve-git-dir")) {
+		const char *gitdir = resolve_gitdir(argv[2]);
+		if (!gitdir)
+			die("not a gitdir '%s'", argv[2]);
+		puts(gitdir);
+		return 0;
+	}
+
 	if (argc > 1 && !strcmp("-h", argv[1]))
 		usage(builtin_rev_parse_usage);
 
diff --git a/cache.h b/cache.h
index 9e12d55..550f632 100644
--- a/cache.h
+++ b/cache.h
@@ -436,6 +436,7 @@ extern char *get_graft_file(void);
 extern int set_git_dir(const char *path);
 extern const char *get_git_work_tree(void);
 extern const char *read_gitfile_gently(const char *path);
+extern const char *resolve_gitdir(const char *suspect);
 extern void set_git_work_tree(const char *tree);
 
 #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
diff --git a/setup.c b/setup.c
index 5ea5502..efad002 100644
--- a/setup.c
+++ b/setup.c
@@ -808,3 +808,10 @@ const char *setup_git_directory(void)
 {
 	return setup_git_directory_gently(NULL);
 }
+
+const char *resolve_gitdir(const char *suspect)
+{
+	if (is_git_directory(suspect))
+		return suspect;
+	return read_gitfile_gently(suspect);
+}
diff --git a/t/t7400-submodule-basic.sh b/t/t7400-submodule-basic.sh
index 14dc927..270a7d5 100755
--- a/t/t7400-submodule-basic.sh
+++ b/t/t7400-submodule-basic.sh
@@ -360,10 +360,10 @@ test_expect_success 'update --init' '
 	git submodule update init > update.out &&
 	cat update.out &&
 	test_i18ngrep "not initialized" update.out &&
-	! test -d init/.git &&
+	test_must_fail git rev-parse --resolve-git-dir init/.git &&
 
 	git submodule update --init init &&
-	test -d init/.git
+	git rev-parse --resolve-git-dir init/.git
 '
 
 test_expect_success 'do not add files from a submodule' '
diff --git a/t/t7403-submodule-sync.sh b/t/t7403-submodule-sync.sh
index 95ffe34..3620215 100755
--- a/t/t7403-submodule-sync.sh
+++ b/t/t7403-submodule-sync.sh
@@ -56,8 +56,9 @@ test_expect_success '"git submodule sync" should update submodule URLs' '
 	 git pull --no-recurse-submodules &&
 	 git submodule sync
 	) &&
-	test -d "$(git config -f super-clone/submodule/.git/config \
-	                        remote.origin.url)" &&
+	test -d "$(cd super-clone/submodule &&
+	 git config remote.origin.url
+	)" &&
 	(cd super-clone/submodule &&
 	 git checkout master &&
 	 git pull
diff --git a/t/t7407-submodule-foreach.sh b/t/t7407-submodule-foreach.sh
index be745fb..9b69fe2 100755
--- a/t/t7407-submodule-foreach.sh
+++ b/t/t7407-submodule-foreach.sh
@@ -118,19 +118,19 @@ test_expect_success 'use "submodule foreach" to checkout 2nd level submodule' '
 	git clone super clone2 &&
 	(
 		cd clone2 &&
-		test ! -d sub1/.git &&
-		test ! -d sub2/.git &&
-		test ! -d sub3/.git &&
-		test ! -d nested1/.git &&
+		test_must_fail git rev-parse --resolve-git-dir sub1/.git &&
+		test_must_fail git rev-parse --resolve-git-dir sub2/.git &&
+		test_must_fail git rev-parse --resolve-git-dir sub3/.git &&
+		test_must_fail git rev-parse --resolve-git-dir nested1/.git &&
 		git submodule update --init &&
-		test -d sub1/.git &&
-		test -d sub2/.git &&
-		test -d sub3/.git &&
-		test -d nested1/.git &&
-		test ! -d nested1/nested2/.git &&
+		git rev-parse --resolve-git-dir sub1/.git &&
+		git rev-parse --resolve-git-dir sub2/.git &&
+		git rev-parse --resolve-git-dir sub3/.git &&
+		git rev-parse --resolve-git-dir nested1/.git &&
+		test_must_fail git rev-parse --resolve-git-dir nested1/nested2/.git &&
 		git submodule foreach "git submodule update --init" &&
-		test -d nested1/nested2/.git &&
-		test ! -d nested1/nested2/nested3/.git
+		git rev-parse --resolve-git-dir nested1/nested1/nested2/.git
+		test_must_fail git rev-parse --resolve-git-dir nested1/nested2/nested3/.git
 	)
 '
 
@@ -138,8 +138,8 @@ test_expect_success 'use "foreach --recursive" to checkout all submodules' '
 	(
 		cd clone2 &&
 		git submodule foreach --recursive "git submodule update --init" &&
-		test -d nested1/nested2/nested3/.git &&
-		test -d nested1/nested2/nested3/submodule/.git
+		git rev-parse --resolve-git-dir nested1/nested2/nested3/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git
 	)
 '
 
@@ -183,18 +183,18 @@ test_expect_success 'use "update --recursive" to checkout all submodules' '
 	git clone super clone3 &&
 	(
 		cd clone3 &&
-		test ! -d sub1/.git &&
-		test ! -d sub2/.git &&
-		test ! -d sub3/.git &&
-		test ! -d nested1/.git &&
+		test_must_fail git rev-parse --resolve-git-dir sub1/.git &&
+		test_must_fail git rev-parse --resolve-git-dir sub2/.git &&
+		test_must_fail git rev-parse --resolve-git-dir sub3/.git &&
+		test_must_fail git rev-parse --resolve-git-dir nested1/.git &&
 		git submodule update --init --recursive &&
-		test -d sub1/.git &&
-		test -d sub2/.git &&
-		test -d sub3/.git &&
-		test -d nested1/.git &&
-		test -d nested1/nested2/.git &&
-		test -d nested1/nested2/nested3/.git &&
-		test -d nested1/nested2/nested3/submodule/.git
+		git rev-parse --resolve-git-dir sub1/.git &&
+		git rev-parse --resolve-git-dir sub2/.git &&
+		git rev-parse --resolve-git-dir sub3/.git &&
+		git rev-parse --resolve-git-dir nested1/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/nested3/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git
 	)
 '
 
@@ -247,14 +247,17 @@ test_expect_success 'ensure "status --cached --recursive" preserves the --cached
 
 test_expect_success 'use "git clone --recursive" to checkout all submodules' '
 	git clone --recursive super clone4 &&
-	test -d clone4/.git &&
-	test -d clone4/sub1/.git &&
-	test -d clone4/sub2/.git &&
-	test -d clone4/sub3/.git &&
-	test -d clone4/nested1/.git &&
-	test -d clone4/nested1/nested2/.git &&
-	test -d clone4/nested1/nested2/nested3/.git &&
-	test -d clone4/nested1/nested2/nested3/submodule/.git
+	(
+		cd clone4 &&
+		git rev-parse --resolve-git-dir .git &&
+		git rev-parse --resolve-git-dir sub1/.git &&
+		git rev-parse --resolve-git-dir sub2/.git &&
+		git rev-parse --resolve-git-dir sub3/.git &&
+		git rev-parse --resolve-git-dir nested1/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/nested3/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git
+	)
 '
 
 test_expect_success 'test "update --recursive" with a flag with spaces' '
@@ -262,14 +265,14 @@ test_expect_success 'test "update --recursive" with a flag with spaces' '
 	git clone super clone5 &&
 	(
 		cd clone5 &&
-		test ! -d nested1/.git &&
+		test_must_fail git rev-parse --resolve-git-dir d nested1/.git &&
 		git submodule update --init --recursive --reference="$(dirname "$PWD")/common objects" &&
-		test -d nested1/.git &&
-		test -d nested1/nested2/.git &&
-		test -d nested1/nested2/nested3/.git &&
-		test -f nested1/.git/objects/info/alternates &&
-		test -f nested1/nested2/.git/objects/info/alternates &&
-		test -f nested1/nested2/nested3/.git/objects/info/alternates
+		git rev-parse --resolve-git-dir nested1/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/nested3/.git &&
+		test -f .git/modules/nested1/objects/info/alternates &&
+		test -f .git/modules/nested1/modules/nested2/objects/info/alternates &&
+		test -f .git/modules/nested1/modules/nested2/modules/nested3/objects/info/alternates
 	)
 '
 
@@ -277,18 +280,18 @@ test_expect_success 'use "update --recursive nested1" to checkout all submodules
 	git clone super clone6 &&
 	(
 		cd clone6 &&
-		test ! -d sub1/.git &&
-		test ! -d sub2/.git &&
-		test ! -d sub3/.git &&
-		test ! -d nested1/.git &&
+		test_must_fail git rev-parse --resolve-git-dir sub1/.git &&
+		test_must_fail git rev-parse --resolve-git-dir sub2/.git &&
+		test_must_fail git rev-parse --resolve-git-dir sub3/.git &&
+		test_must_fail git rev-parse --resolve-git-dir nested1/.git &&
 		git submodule update --init --recursive -- nested1 &&
-		test ! -d sub1/.git &&
-		test ! -d sub2/.git &&
-		test ! -d sub3/.git &&
-		test -d nested1/.git &&
-		test -d nested1/nested2/.git &&
-		test -d nested1/nested2/nested3/.git &&
-		test -d nested1/nested2/nested3/submodule/.git
+		test_must_fail git rev-parse --resolve-git-dir sub1/.git &&
+		test_must_fail git rev-parse --resolve-git-dir sub2/.git &&
+		test_must_fail git rev-parse --resolve-git-dir sub3/.git &&
+		git rev-parse --resolve-git-dir nested1/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/nested3/.git &&
+		git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git
 	)
 '
 
-- 
1.7.6.398.gb3f84

^ permalink raw reply related

* [PATCH v4 2/2] Move git-dir for submodules
From: Fredrik Gustafsson @ 2011-08-15 21:17 UTC (permalink / raw)
  To: git; +Cc: gitster, jens.lehmann, hvoigt, iveqy
In-Reply-To: <1313443067-2642-1-git-send-email-iveqy@iveqy.com>

Move git-dir for submodules into $GIT_DIR/modules/[name_of_submodule] of
the superproject. This is a step towards being able to delete submodule
directories without loosing the information from their .git directory
as that is now stored outside the submodules work tree.

This is done relying on the already existent .git-file functionality.
When adding or updating a submodule whose git directory is found under
$GIT_DIR/modules/[name_of_submodule], don't clone it again but simply
point the .git-file to it and remove the now stale index file from it.
The index will be recreated by the following checkout.

This patch will not affect already cloned submodules at all.

Tests that rely on .git being a directory have been fixed.

Signed-off-by: Fredrik Gustafsson <iveqy@iveqy.com>
Mentored-by: Jens Lehmann <Jens.Lehmann@web.de>
Mentored-by: Heiko Voigt <hvoigt@hvoigt.net>
---
 git-submodule.sh               |   49 ++++++++++++++++--
 t/t7406-submodule-update.sh    |  107 ++++++++++++++++++++++++++++++++++++++++
 t/t7408-submodule-reference.sh |    4 +-
 3 files changed, 153 insertions(+), 7 deletions(-)

diff --git a/git-submodule.sh b/git-submodule.sh
index bc1d3fa..ace6c1d 100755
--- a/git-submodule.sh
+++ b/git-submodule.sh
@@ -122,14 +122,53 @@ module_clone()
 	path=$1
 	url=$2
 	reference="$3"
+	gitdir=
+	gitdir_base=
+	name=$(module_name "$path")
+	if test -z "$name"
+	then
+		name="$path"
+	fi
+	base_path=$(dirname "$path")
+
+	gitdir=$(git rev-parse --git-dir)
+	gitdir_base="$gitdir/modules/$base_path"
+	gitdir="$gitdir/modules/$path"
+
+	case $gitdir in
+	/*)
+		a="$(cd_to_toplevel && pwd)/"
+		b=$gitdir
+		while [ "$b" ] && [ "${a%%/*}" = "${b%%/*}" ]
+		do
+			a=${a#*/} b=${b#*/};
+		done
+
+		rel="$a$name"
+		rel=`echo $rel | sed -e 's|[^/]*|..|g'`
+		rel_gitdir="$rel/$b"
+		;;
+	*)
+		rel=`echo $name | sed -e 's|[^/]*|..|g'`
+		rel_gitdir="$rel/$gitdir"
+		;;
+	esac
 
-	if test -n "$reference"
+	if test -d "$gitdir"
 	then
-		git-clone "$reference" -n "$url" "$path"
+		mkdir -p "$path"
+		echo "gitdir: $rel_gitdir" >"$path/.git"
+		rm -f "$gitdir/index"
 	else
-		git-clone -n "$url" "$path"
-	fi ||
-	die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
+		mkdir -p "$gitdir_base"
+		if test -n "$reference"
+		then
+			git-clone "$reference" -n "$url" "$path" --separate-git-dir "$gitdir"
+		else
+			git-clone -n "$url" "$path" --separate-git-dir "$gitdir"
+		fi ||
+		die "$(eval_gettext "Clone of '\$url' into submodule path '\$path' failed")"
+	fi
 }
 
 #
diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh
index c679f36..1ae6b4e 100755
--- a/t/t7406-submodule-update.sh
+++ b/t/t7406-submodule-update.sh
@@ -408,6 +408,7 @@ test_expect_success 'submodule update exit immediately in case of merge conflict
 	 test_cmp expect actual
 	)
 '
+
 test_expect_success 'submodule update exit immediately after recursive rebase error' '
 	(cd super &&
 	 git checkout master &&
@@ -442,4 +443,110 @@ test_expect_success 'submodule update exit immediately after recursive rebase er
 	 test_cmp expect actual
 	)
 '
+
+test_expect_success 'add different submodules to the same path' '
+	(cd super &&
+	 git submodule add ../submodule s1 &&
+	 test_must_fail git submodule add ../merging s1
+	)
+'
+
+test_expect_success 'submodule add places git-dir in superprojects git-dir' '
+	(cd super &&
+	 mkdir deeper &&
+	 git submodule add ../submodule deeper/submodule &&
+	 (cd deeper/submodule &&
+	  git log > ../../expected
+	 ) &&
+	 (cd .git/modules/deeper/submodule &&
+	  git log > ../../../../actual
+	 ) &&
+	 test_cmp actual expected
+	)
+'
+
+test_expect_success 'submodule update places git-dir in superprojects git-dir' '
+	(cd super &&
+	 git commit -m "added submodule"
+	) &&
+	git clone super super2 &&
+	(cd super2 &&
+	 git submodule init deeper/submodule &&
+	 git submodule update &&
+	 (cd deeper/submodule &&
+	  git log > ../../expected
+	 ) &&
+	 (cd .git/modules/deeper/submodule &&
+	  git log > ../../../../actual
+	 ) &&
+	 test_cmp actual expected
+	)
+'
+
+test_expect_success 'submodule add places git-dir in superprojects git-dir recursive' '
+	(cd super2 &&
+	 (cd deeper/submodule &&
+	  git submodule add ../submodule subsubmodule &&
+	  (cd subsubmodule &&
+	   git log > ../../../expected
+	  ) &&
+	  git commit -m "added subsubmodule" &&
+	  git push
+	 ) &&
+	 (cd .git/modules/deeper/submodule/modules/subsubmodule &&
+	  git log > ../../../../../actual
+	 ) &&
+	 git add deeper/submodule &&
+	 git commit -m "update submodule" &&
+	 git push &&
+	 test_cmp actual expected
+	)
+'
+
+test_expect_success 'submodule update places git-dir in superprojects git-dir recursive' '
+	mkdir super_update_r &&
+	(cd super_update_r &&
+	 git init --bare
+	) &&
+	mkdir subsuper_update_r &&
+	(cd subsuper_update_r &&
+	 git init --bare
+	) &&
+	mkdir subsubsuper_update_r &&
+	(cd subsubsuper_update_r &&
+	 git init --bare
+	) &&
+	git clone subsubsuper_update_r subsubsuper_update_r2 &&
+	(cd subsubsuper_update_r2 &&
+	 test_commit "update_subsubsuper" file &&
+	 git push origin master
+	) &&
+	git clone subsuper_update_r subsuper_update_r2 &&
+	(cd subsuper_update_r2 &&
+	 test_commit "update_subsuper" file &&
+	 git submodule add ../subsubsuper_update_r subsubmodule &&
+	 git commit -am "subsubmodule" &&
+	 git push origin master
+	) &&
+	git clone super_update_r super_update_r2 &&
+	(cd super_update_r2 &&
+	 test_commit "update_super" file &&
+	 git submodule add ../subsuper_update_r submodule &&
+	 git commit -am "submodule" &&
+	 git push origin master
+	) &&
+	rm -rf super_update_r2 &&
+	git clone super_update_r super_update_r2 &&
+	(cd super_update_r2 &&
+	 git submodule update --init --recursive &&
+	 (cd submodule/subsubmodule &&
+	  git log > ../../expected
+	 ) &&
+	 (cd .git/modules/submodule/modules/subsubmodule
+	  git log > ../../../../../actual
+	 )
+	 test_cmp actual expected
+	)
+'
+
 test_done
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index cc16d3f..ab37c36 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -43,7 +43,7 @@ git commit -m B-super-added'
 cd "$base_dir"
 
 test_expect_success 'after add: existence of info/alternates' \
-'test `wc -l <super/sub/.git/objects/info/alternates` = 1'
+'test `wc -l <super/.git/modules/sub/objects/info/alternates` = 1'
 
 cd "$base_dir"
 
@@ -66,7 +66,7 @@ test_expect_success 'update with reference' \
 cd "$base_dir"
 
 test_expect_success 'after update: existence of info/alternates' \
-'test `wc -l <super-clone/sub/.git/objects/info/alternates` = 1'
+'test `wc -l <super-clone/.git/modules/sub/objects/info/alternates` = 1'
 
 cd "$base_dir"
 
-- 
1.7.6.398.gb3f84

^ permalink raw reply related

* [PATCH v4 0/2] submodule: move gitdir into superproject
From: Fredrik Gustafsson @ 2011-08-15 21:17 UTC (permalink / raw)
  To: git; +Cc: gitster, jens.lehmann, hvoigt, iveqy

Move git-dir for submodules into $GIT_DIR/modules/[name_of_submodule] of
the superproject. This is a step towards being able to delete submodule
directories without loosing the information from their .git directory
as that is now stored outside the submodules work tree.

This is done relying on the already existent .git-file functionality.
Tests that rely on .git being a directory have been fixed.

This is the forth iteration of this patchseries.

The first can be found here:
http://thread.gmane.org/gmane.comp.version-control.git/177582

The second can be found here:
http://thread.gmane.org/gmane.comp.version-control.git/178970/focus=179153

The third can be found here:
http://thread.gmane.org/gmane.comp.version-control.git/179243/focus=179244


Fredrik Gustafsson (2):
  rev-parse: add option --resolve-git-dir <path>
  Move git-dir for submodules

 Documentation/git-rev-parse.txt |    4 ++
 builtin/rev-parse.c             |    8 +++
 cache.h                         |    1 +
 git-submodule.sh                |   49 ++++++++++++++++--
 setup.c                         |    7 +++
 t/t7400-submodule-basic.sh      |    4 +-
 t/t7403-submodule-sync.sh       |    5 +-
 t/t7406-submodule-update.sh     |  107 +++++++++++++++++++++++++++++++++++++++
 t/t7407-submodule-foreach.sh    |  103 +++++++++++++++++++------------------
 t/t7408-submodule-reference.sh  |    4 +-
 10 files changed, 231 insertions(+), 61 deletions(-)

-- 
1.7.6.398.gb3f84

^ permalink raw reply

* Re: [PATCH v4 0/2] submodule: move gitdir into superproject
From: Junio C Hamano @ 2011-08-15 22:23 UTC (permalink / raw)
  To: Fredrik Gustafsson; +Cc: git, jens.lehmann, hvoigt
In-Reply-To: <1313443067-2642-1-git-send-email-iveqy@iveqy.com>

Nicely done; will queue. Thanks.

^ permalink raw reply

* Re: shallow clone not very shallow due to tags
From: Philip Oakley @ 2011-08-15 23:00 UTC (permalink / raw)
  To: Shawn Pearce, Nguyen Thai Ngoc Duy; +Cc: git
In-Reply-To: <CAJo=hJv_NnZyGnedTQBL_mj3baS8O5Z2wiEbZCvv8305No4ehA@mail.gmail.com>

Monday, August 15, 2011 6:16 PM "Shawn Pearce" <spearce@spearce.org>
> On Mon, Aug 15, 2011 at 07:03, Nguyen Thai Ngoc Duy <pclouds@gmail.com> 
> wrote:
>> On Mon, Aug 15, 2011 at 6:58 AM, Shawn Pearce <spearce@spearce.org> 
>> wrote:
>>> Uhm. That is not a very shallow clone. The clone copied 20234 objects
>>> at 9.15 MiB... so its ~20 MiB lighter than a full clone. But nearly
>>> all of the tags exist, because the clone client is declaring want
>>> lines for them, making the server generate up to 1 commit back from
>>> the wanted tag. I know shallow support is the feature nobody wants to
>>> think about, but this just seems broken to me. Clients performing a
>>> shallow clone shouldn't be asking for tags... but they should be using
>>> the include-tag protocol option so that if they do happen to receive a
>>> tagged commit, the tag object will also be sent.
>>
>> The same would apply if the repo in question has many branches. Should
>> we fetch only master (or a user-specified set of refs) in shallow
>> clone?
>
> Yes, I think a user who is making a shallow clone should only get the
> HEAD branch to the depth specified, nothing else. If they want
> additional branches, they should either pass them on the command line
> to a new flag for clone, or modify their fetch configuration
> after-the-fact and fetch those separately.
>
> From what I can gather from some users I have talked to, the primary
> usage of shallow clone is to try and (sort of) quickly grab a branch,
> make a change, and post that change to the maintainers for review and
> acceptance. E.g. correcting a spelling typo. Relatively simple changes
> that can be built on a specific branch, and don't really require all
> of the history.
>
> And if a repository does have more than one branch, but is shallow
> cloned at say depth of 1, the user probably doesn't get the merge
> bases between them, so the value of the other branches is greatly
> reduced. You can't make a merge between these, and a new developer
> getting involved in the project cannot see how the branches relate to
> each other. So there isn't a lot of value in sucking down those
> additional branches during clone.
>
The shallow clone problem came up a few times recently on StackOverflow. One 
usage is to create an orphan branch, but the manual doesn't point the user 
to that option. When I first read the man page I expected that any clone 
would be from a fixed point in history, rather than a point that may move 
(as extra commits are made to the remote). It maybe that what is needed is 
an option that will clone from a fixed commit point, so that there is no 
confusion as to the 'current depth'. 

^ permalink raw reply

* rejecting patches that have an offset
From: Eric Blake @ 2011-08-15 23:16 UTC (permalink / raw)
  To: bug-patch-mXXj517/zsQ, Git Mailing List

I ran into a case that cost me several hours today, while building an 
rpm file for libvirt.  I have a context patch that only adds lines (no 
deletions), and which had multiple places in the destination file where 
the patch would match context and still apply, although only one of 
those places will compile as correct.  However, the patch file was 
inadvertently generated by git against the wrong version of the 
destination, so the line numbers in the patch did not match the version 
of the file that I was trying to apply it to, and 'patch -p1 --fuzz=0 
-s' ended up triggering patch's sliding algorithm where it applied the 
patch with an offset of 11 lines.  Meanwhile, running the same patch 
through git applied the patch in a different offset: git found the 
offset that matched the function name in the @@ line, which was more 
than 11 lines away, but actually matched the intent of the patch better.

The problem is that the difference in choice between patch and git 
resulted in a patch series that works or fails according to which tool 
you pass it through.  But the whole point of an rpm file is that if the 
patches were generated correctly, none of them should ever have any 
offset - an rpm should be tool-independent.

It would have saved me a lot of time if both 'patch' and 'git apply' 
could be taught a mode of operation where they explicitly reject a patch 
that cannot be applied without relying on an offset.  That is, 'patch 
--fuzz=0' is too weak, and the fact that 'patch -s' squelched the error 
message meant that I had nothing to alert me to the fact that an offset 
even took place.  And no, I don't want to filterdiff from patchutils to 
convert the patch from context-diff over to ed-script-diff just to 
benefit from the fact that patch does not do offset detection on 
ed-script-patches.

If it were possible to optionally reject patches with offsets, then 
building rpm files could use this mode to insist that all patches apply 
offset-free, making for a more robust patch chain (of course, the 
default should remain that the offset algorithm is still applied, and 
only suppressed by explicit request, as the use of offsets is normally a 
very useful feature - my point is that rpm patch chains are an exception 
for the rule where offsets normally make life easier).

It might also be nice if patch could learn the algorithm that appears to 
match the git behavior, where when there are multiple points with 
identical context (viewing just the context in isolation), but where 
those locations differ in function location (as learned by the @@ header 
line in the patch file), then the preferred offset is the one in the 
named function, even if that is not the closes context match to the line 
number given in the patch file.

-- 
Eric Blake   eblake-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

^ permalink raw reply

* Re: git_checkattr() is inefficient when repeated [Re: [PATCH 00/11] Micro-optimizing lookup_object()]
From: Junio C Hamano @ 2011-08-15 23:19 UTC (permalink / raw)
  To: Thomas Rast; +Cc: git
In-Reply-To: <201108121759.24884.trast@student.ethz.ch>

Thomas Rast <trast@student.ethz.ch> writes:

> Which would be a 4.5% speedup.  Obviously that won't quite be
> attainable since we want the attributes mechanism to work, but we
> still shouldn't have to open 4398 .gitattributes files when there are
> only 8 .gitattributes plus one .git/info/attributes.

True. At runtime, the attribute mechanism wants a stack of per-directory
attributes it can walk up to find the applicable ones maintained for the
directory it currently is looking at, and the elements near the leaf are
popped from the stack to be discarded when the caller goes on to inspect
paths in a different directory (IOW the machinery is optimized for callers
that walk the paths in order, without randomly jumping around).

But at least within a process like pack-objects that are known to be long
lived, we should be able to instead _keep_ the elements that are popped
when we leave directories at deeper levels, and bring them back to the
stack when the caller asks for a path in that directory later, without
going back to the filesystem.

^ permalink raw reply

* Re: "git apply --check" successes but git am says "does not match index"
From: Jeff King @ 2011-08-15 23:23 UTC (permalink / raw)
  To: Zemacsh; +Cc: git
In-Reply-To: <loom.20110814T113311-277@post.gmane.org>

On Sun, Aug 14, 2011 at 09:36:30AM +0000, Zemacsh wrote:

> Before applying a mbox patch, "git apply --check" reports OK. Then, I run 'git 
> am', however, it complains "does not match index". Actually, both working tree 
> and index are clean. what might be the problem?
> 
> If I run "git am --abort" now, and re-turn "git am". To my surprise, everything 
> goes well.

Hmm. I don't think this has anything to do with the "apply --check". But
rather the problem is that "git am" doesn't ever refresh the index. For
example:

  git init repo &&
  cd repo &&
  echo one >file && git add . && git commit -m one &&
  echo two >file && git add . && git commit -m two &&
  git format-patch -1 --stdout >patch &&
  git reset --hard HEAD^ &&
  sleep 1 &&
  touch file &&
  git am patch

This fails with:

  Applying: two
  error: file: does not match index
  Patch failed at 0001 two

Running "git am --abort" resets the index, which freshens it, and then a
further "git am" works:

  $ git am --abort
  $ git am patch
  Applying: two

We should perhaps call "update-index --refresh" at the start to avoid
these sorts of false positives. Probably it should happen whenever we
"git am --continue", as well. But for efficiency reasons, not between
each patch.

I dunno. Do people want to call "git am" in a tight loop, where the
index refresh would be a problem? I would think they should instead feed
a whole mbox in one go.

-Peff

^ permalink raw reply

* Re: [PATCH] Utilize config variable pager.stash in stash list command
From: Jeff King @ 2011-08-15 23:47 UTC (permalink / raw)
  To: Ingo Brückl; +Cc: git
In-Reply-To: <4e47dcf9.55313988.bm000@wupperonline.de>

On Sun, Aug 14, 2011 at 04:31:49PM +0200, Ingo Brückl wrote:

> Signed-off-by: Ingo Brückl <ib@wupperonline.de>
> ---
>  By now stash list ignores it.
> 
>  git-stash.sh |    3 ++-
>  1 files changed, 2 insertions(+), 1 deletions(-)
> 
> diff --git a/git-stash.sh b/git-stash.sh
> index f4e6f05..7bb0856 100755
> --- a/git-stash.sh
> +++ b/git-stash.sh
> @@ -264,7 +264,8 @@ have_stash () {
> 
>  list_stash () {
>  	have_stash || return 0
> -	git log --format="%gd: %gs" -g "$@" $ref_stash --
> +	test "$(git config --get pager.stash)" = "false" && no_pager=--no-pager
> +	git $no_pager log --format="%gd: %gs" -g "$@" $ref_stash --
>  }

It's not quite as simple as this these days. The pager.* variables can
also point to a program to run as a pager for this specific command.

This stuff is supposed to be handled by the "git" wrapper itself, which
will either run the pager (if the config is boolean true, or a specific
command), or will set an environment variable to avoid running one for
any subcommand (if it's boolean false).

However, we don't respect pager.* config for external commands there at
all. I think this was due to some initialization-order bugs that made it
hard for us to look at config before exec'ing external commands. But
perhaps they are gone, as the patch below[1] seems to work OK for me.

---
 git.c |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/git.c b/git.c
index 8828c18..47a6d3d 100644
--- a/git.c
+++ b/git.c
@@ -459,6 +459,8 @@ static void execv_dashed_external(const char **argv)
 	const char *tmp;
 	int status;
 
+	if (use_pager == -1)
+		use_pager = check_pager_config(argv[0]);
 	commit_pager_choice();
 
 	strbuf_addf(&cmd, "git-%s", argv[0]);

-Peff

[1] I posted this in a similar discussion several months ago:

    http://thread.gmane.org/gmane.comp.version-control.git/161756/focus=161771

I think what it really needs is more testing to see if looking at the
config then has any unintended side effects.

^ permalink raw reply related

* Re: "git apply --check" successes but git am says "does not match index"
From: Junio C Hamano @ 2011-08-15 23:52 UTC (permalink / raw)
  To: Jeff King; +Cc: Zemacsh, git
In-Reply-To: <20110815232318.GA4699@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> We should perhaps call "update-index --refresh" at the start to avoid
> these sorts of false positives. Probably it should happen whenever we
> "git am --continue", as well. But for efficiency reasons, not between
> each patch.
>
> I dunno. Do people want to call "git am" in a tight loop, where the
> index refresh would be a problem? I would think they should instead feed
> a whole mbox in one go.

I am kind of surprised that we have not done the 'refresh once upfront'
already and nobody ever run into this for the past 5 years. It seems that
I inherited that behaviour from git-applymbox ;-)

It is sensible to refresh once at the beginning and also when restarting
with "am --resolved".

^ permalink raw reply

* Re: "git apply --check" successes but git am says "does not match index"
From: Jeff King @ 2011-08-16  0:13 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Zemacsh, git
In-Reply-To: <7vhb5ijkq0.fsf@alter.siamese.dyndns.org>

On Mon, Aug 15, 2011 at 04:52:55PM -0700, Junio C Hamano wrote:

> I am kind of surprised that we have not done the 'refresh once upfront'
> already and nobody ever run into this for the past 5 years. It seems that
> I inherited that behaviour from git-applymbox ;-)

It's a pretty rare set of circumstances:

  1. You make a file stat-dirty, but don't actually change its contents.

  2. You don't run any index-refreshing porcelains.

  3. You apply a patch that touches that file.

> It is sensible to refresh once at the beginning and also when restarting
> with "am --resolved".

The patch below does this. I think this makes the "update-index" call in
git-rebase.sh:522 redundant when the "am" backend is used. But it is
still needed for the other backends. I wonder if "git rebase" actually
suffers from the same problem, since it seems to refresh only on
--continue, but not at the beginning.

-- >8 --
Subject: [PATCH] am: refresh the index at start and --resolved

If a file is unchanged but stat-dirty, we may erroneously
fail to apply patches, thinking that they conflict with a
dirty working tree.

This patch adds a call to "update-index --refresh". It comes
as late as possible, so that we don't bother with it for
thinks like "git rebase --abort", or when mbox-splitting
fails. However, it does come before we actually start
applying patches, meaning we will only call it once when we
start applying patches (or any time we return to "am" after
having resolved conflicts), and not once per patch.

Signed-off-by: Jeff King <peff@peff.net>
---
 git-am.sh |    2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/git-am.sh b/git-am.sh
index 463c741..6592424 100755
--- a/git-am.sh
+++ b/git-am.sh
@@ -511,6 +511,8 @@ else
 	fi
 fi
 
+git update-index -q --refresh
+
 case "$resolved" in
 '')
 	case "$HAS_HEAD" in
-- 
1.7.6.10.g62f04

^ permalink raw reply related

* Git-Labs at FrOSCon, August 20th/21st 2011, St. Augustin/Germany
From: Christian Thaeter @ 2011-08-16  1:03 UTC (permalink / raw)
  To: git-u79uwXL29TY76Z2rM5mHXA; +Cc: lumiera-aLEFhgZF4x639dL7tAm8iNi2O/JbrIOy

We, the Lumiera.org developers will host an open Git-Workshop at
FrOSCon (http://froscon.org/) this year.

Lumiera using git since its very beginning as core of its open
infrastructure with the goal to lower the entry barrier to the
project. Our Workshop aims to give beginners a introduction
to Git 'in practice' as well as discuss and discover tricks and
workflows with advanced users and to exchange experiences.

The whole workshop is open, interested people can just step by to ask
and watch. In particular we will meet just after (Saturday 16:20) Scotts
"Wrangling Git" Talk (15:15 HS1/2) in our workshop room to try out what
we've just learned.

In case anyone developed interesting new ways to use Git we'd like to
invite him to show these. Also any professional is welcome to join us
in helping at our workshop showing Git to others.

	See you,
		Christian

_______________________________________________
Lumiera mailing list
Lumiera-aLEFhgZF4x639dL7tAm8iNi2O/JbrIOy@public.gmane.org
http://lists.lumiera.org/cgi-bin/mailman/listinfo/lumiera
http://lumiera.org/donations.html

^ permalink raw reply

* Re: git diff is slow (--patience is fast)
From: Tay Ray Chuan @ 2011-08-16  3:01 UTC (permalink / raw)
  To: Marat Radchenko; +Cc: git
In-Reply-To: <loom.20110809T133735-979@post.gmane.org>

On Tue, Aug 9, 2011 at 7:39 PM, Marat Radchenko <marat@slonopotamus.org> wrote:
> Good idea.
>
> New steps to reproduce:
> ~ $ git clone git://slonopotamus.org/git-diff
> Cloning into git-diff...

Thanks.

I traced this to a O(n*m) spot in
xdiff/xprepare.c::xdl_classify_record(). Patch coming up.

-- 
Cheers,
Ray Chuan

^ permalink raw reply

* [PATCH] xdiff/xprepare: improve O(n*m) performance in xdl_cleanup_records()
From: Tay Ray Chuan @ 2011-08-16  3:11 UTC (permalink / raw)
  To: Git Mailing List; +Cc: Junio C Hamano, Marat Radchenko
In-Reply-To: <loom.20110809T093124-847@post.gmane.org>

In xdl_cleanup_records(), we see O(n*m) performance, where n is the
number of records from xdf->dstart to xdf->dend, and m is the size of a
bucket in xdf->rhash (<= by mlim).

Here, we improve this to O(n) by pre-computing nm (in rcrec->len(1|2))
in xdl_classify_record().

Reported-by: Marat Radchenko <marat@slonopotamus.org>
Signed-off-by: Tay Ray Chuan <rctay89@gmail.com>
---

On my msysgit machine:
  
  rctay@TEST-123 /tmp/slono
  $ time git show >/dev/null
  
  real    0m8.538s
  user    0m0.000s
  sys     0m0.031s
  
  rctay@TEST-123 /tmp/slono
  $ time /git/git show >/dev/null
  
  real    0m0.672s
  user    0m0.031s
  sys     0m0.031s


 xdiff/xprepare.c |   87 +++++++++++++++++++++++++++++++-----------------------
 1 files changed, 50 insertions(+), 37 deletions(-)

diff --git a/xdiff/xprepare.c b/xdiff/xprepare.c
index 620fc9a..1043fb7 100644
--- a/xdiff/xprepare.c
+++ b/xdiff/xprepare.c
@@ -36,6 +36,7 @@ typedef struct s_xdlclass {
 	char const *line;
 	long size;
 	long idx;
+	long len1, len2;
 } xdlclass_t;
 
 typedef struct s_xdlclassifier {
@@ -43,6 +44,8 @@ typedef struct s_xdlclassifier {
 	long hsize;
 	xdlclass_t **rchash;
 	chastore_t ncha;
+	xdlclass_t **rcrecs;
+	long alloc;
 	long count;
 	long flags;
 } xdlclassifier_t;
@@ -52,15 +55,15 @@ typedef struct s_xdlclassifier {
 
 static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags);
 static void xdl_free_classifier(xdlclassifier_t *cf);
-static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned int hbits,
-			       xrecord_t *rec);
-static int xdl_prepare_ctx(mmfile_t *mf, long narec, xpparam_t const *xpp,
+static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash,
+			       unsigned int hbits, xrecord_t *rec);
+static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
 			   xdlclassifier_t *cf, xdfile_t *xdf);
 static void xdl_free_ctx(xdfile_t *xdf);
 static int xdl_clean_mmatch(char const *dis, long i, long s, long e);
-static int xdl_cleanup_records(xdfile_t *xdf1, xdfile_t *xdf2);
+static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
 static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2);
-static int xdl_optimize_ctxs(xdfile_t *xdf1, xdfile_t *xdf2);
+static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
 
 
 
@@ -82,6 +85,14 @@ static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) {
 	}
 	memset(cf->rchash, 0, cf->hsize * sizeof(xdlclass_t *));
 
+	cf->alloc = size;
+	if (!(cf->rcrecs = (xdlclass_t **) xdl_malloc(cf->alloc * sizeof(xdlclass_t *)))) {
+
+		xdl_free(cf->rchash);
+		xdl_cha_free(&cf->ncha);
+		return -1;
+	}
+
 	cf->count = 0;
 
 	return 0;
@@ -95,11 +106,12 @@ static void xdl_free_classifier(xdlclassifier_t *cf) {
 }
 
 
-static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned int hbits,
-			       xrecord_t *rec) {
+static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash,
+			       unsigned int hbits, xrecord_t *rec) {
 	long hi;
 	char const *line;
 	xdlclass_t *rcrec;
+	xdlclass_t **rcrecs;
 
 	line = rec->ptr;
 	hi = (long) XDL_HASHLONG(rec->ha, cf->hbits);
@@ -115,13 +127,25 @@ static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned
 			return -1;
 		}
 		rcrec->idx = cf->count++;
+		if (cf->count > cf->alloc) {
+			cf->alloc *= 2;
+			if (!(rcrecs = (xdlclass_t **) xdl_realloc(cf->rcrecs, cf->alloc * sizeof(xdlclass_t *)))) {
+
+				return -1;
+			}
+			cf->rcrecs = rcrecs;
+		}
+		cf->rcrecs[rcrec->idx] = rcrec;
 		rcrec->line = line;
 		rcrec->size = rec->size;
 		rcrec->ha = rec->ha;
+		rcrec->len1 = rcrec->len2 = 0;
 		rcrec->next = cf->rchash[hi];
 		cf->rchash[hi] = rcrec;
 	}
 
+	(pass == 1) ? rcrec->len1++ : rcrec->len2++;
+
 	rec->ha = (unsigned long) rcrec->idx;
 
 	hi = (long) XDL_HASHLONG(rec->ha, hbits);
@@ -132,7 +156,7 @@ static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned
 }
 
 
-static int xdl_prepare_ctx(mmfile_t *mf, long narec, xpparam_t const *xpp,
+static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
 			   xdlclassifier_t *cf, xdfile_t *xdf) {
 	unsigned int hbits;
 	long nrec, hsize, bsize;
@@ -185,7 +209,7 @@ static int xdl_prepare_ctx(mmfile_t *mf, long narec, xpparam_t const *xpp,
 			recs[nrec++] = crec;
 
 			if (!(xpp->flags & XDF_HISTOGRAM_DIFF) &&
-				xdl_classify_record(cf, rhash, hbits, crec) < 0)
+				xdl_classify_record(pass, cf, rhash, hbits, crec) < 0)
 				goto abort;
 		}
 	}
@@ -257,30 +281,30 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
 		return -1;
 	}
 
-	if (xdl_prepare_ctx(mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
+	if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
 
 		xdl_free_classifier(&cf);
 		return -1;
 	}
-	if (xdl_prepare_ctx(mf2, enl2, xpp, &cf, &xe->xdf2) < 0) {
+	if (xdl_prepare_ctx(2, mf2, enl2, xpp, &cf, &xe->xdf2) < 0) {
 
 		xdl_free_ctx(&xe->xdf1);
 		xdl_free_classifier(&cf);
 		return -1;
 	}
 
-	if (!(xpp->flags & XDF_HISTOGRAM_DIFF))
-		xdl_free_classifier(&cf);
-
 	if (!(xpp->flags & XDF_PATIENCE_DIFF) &&
 			!(xpp->flags & XDF_HISTOGRAM_DIFF) &&
-			xdl_optimize_ctxs(&xe->xdf1, &xe->xdf2) < 0) {
+			xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) {
 
 		xdl_free_ctx(&xe->xdf2);
 		xdl_free_ctx(&xe->xdf1);
 		return -1;
 	}
 
+	if (!(xpp->flags & XDF_HISTOGRAM_DIFF))
+		xdl_free_classifier(&cf);
+
 	return 0;
 }
 
@@ -355,11 +379,10 @@ static int xdl_clean_mmatch(char const *dis, long i, long s, long e) {
  * matches on the other file. Also, lines that have multiple matches
  * might be potentially discarded if they happear in a run of discardable.
  */
-static int xdl_cleanup_records(xdfile_t *xdf1, xdfile_t *xdf2) {
-	long i, nm, rhi, nreff, mlim;
-	unsigned long hav;
+static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) {
+	long i, nm, nreff;
 	xrecord_t **recs;
-	xrecord_t *rec;
+	xdlclass_t *rcrec;
 	char *dis, *dis1, *dis2;
 
 	if (!(dis = (char *) xdl_malloc(xdf1->nrec + xdf2->nrec + 2))) {
@@ -370,26 +393,16 @@ static int xdl_cleanup_records(xdfile_t *xdf1, xdfile_t *xdf2) {
 	dis1 = dis;
 	dis2 = dis1 + xdf1->nrec + 1;
 
-	if ((mlim = xdl_bogosqrt(xdf1->nrec)) > XDL_MAX_EQLIMIT)
-		mlim = XDL_MAX_EQLIMIT;
 	for (i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) {
-		hav = (*recs)->ha;
-		rhi = (long) XDL_HASHLONG(hav, xdf2->hbits);
-		for (nm = 0, rec = xdf2->rhash[rhi]; rec; rec = rec->next)
-			if (rec->ha == hav && ++nm == mlim)
-				break;
-		dis1[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
+		rcrec = cf->rcrecs[(*recs)->ha];
+		nm = rcrec ? rcrec->len2 : 0;
+		dis1[i] = (nm == 0) ? 0: 1;
 	}
 
-	if ((mlim = xdl_bogosqrt(xdf2->nrec)) > XDL_MAX_EQLIMIT)
-		mlim = XDL_MAX_EQLIMIT;
 	for (i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) {
-		hav = (*recs)->ha;
-		rhi = (long) XDL_HASHLONG(hav, xdf1->hbits);
-		for (nm = 0, rec = xdf1->rhash[rhi]; rec; rec = rec->next)
-			if (rec->ha == hav && ++nm == mlim)
-				break;
-		dis2[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
+		rcrec = cf->rcrecs[(*recs)->ha];
+		nm = rcrec ? rcrec->len1 : 0;
+		dis2[i] = (nm == 0) ? 0: 1;
 	}
 
 	for (nreff = 0, i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart];
@@ -451,10 +464,10 @@ static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2) {
 }
 
 
-static int xdl_optimize_ctxs(xdfile_t *xdf1, xdfile_t *xdf2) {
+static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) {
 
 	if (xdl_trim_ends(xdf1, xdf2) < 0 ||
-	    xdl_cleanup_records(xdf1, xdf2) < 0) {
+	    xdl_cleanup_records(cf, xdf1, xdf2) < 0) {
 
 		return -1;
 	}
-- 
1.7.6

^ permalink raw reply related

* Re: [PATCH] xdiff/xprepare: improve O(n*m) performance in xdl_cleanup_records()
From: Tay Ray Chuan @ 2011-08-16  3:37 UTC (permalink / raw)
  To: Tay Ray Chuan; +Cc: Git Mailing List, Junio C Hamano, Marat Radchenko
In-Reply-To: <1313464312-5132-1-git-send-email-rctay89@gmail.com>

>From 0da9ec94604978f877e7f7c00d307b5cdbb22b29 Mon Sep 17 00:00:00 2001
From: Tay Ray Chuan <rctay89@gmail.com>
Date: Tue, 16 Aug 2011 11:35:28 +0800
Subject: [PATCH] xdiff/xprepare: improve O(n*m) performance in
 xdl_cleanup_records()

In xdl_cleanup_records(), we see O(n*m) performance, where n is the
number of records from xdf->dstart to xdf->dend, and m is the size of a
bucket in xdf->rhash (<= by mlim).

Here, we improve this to O(n) by pre-computing nm (in rcrec->len(1|2))
in xdl_classify_record().

Reported-by: Marat Radchenko <marat@slonopotamus.org>
Signed-off-by: Tay Ray Chuan <rctay89@gmail.com>
---

Junio, this one is rebased on v1.7.6, instead of rc/histogram-diff.

 xdiff/xprepare.c |   85 +++++++++++++++++++++++++++++++-----------------------
 1 files changed, 49 insertions(+), 36 deletions(-)

diff --git a/xdiff/xprepare.c b/xdiff/xprepare.c
index 1689085..ebbec19 100644
--- a/xdiff/xprepare.c
+++ b/xdiff/xprepare.c
@@ -34,6 +34,7 @@ typedef struct s_xdlclass {
 	char const *line;
 	long size;
 	long idx;
+	long len1, len2;
 } xdlclass_t;
 
 typedef struct s_xdlclassifier {
@@ -41,6 +42,8 @@ typedef struct s_xdlclassifier {
 	long hsize;
 	xdlclass_t **rchash;
 	chastore_t ncha;
+	xdlclass_t **rcrecs;
+	long alloc;
 	long count;
 	long flags;
 } xdlclassifier_t;
@@ -50,15 +53,15 @@ typedef struct s_xdlclassifier {
 
 static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags);
 static void xdl_free_classifier(xdlclassifier_t *cf);
-static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned int hbits,
-			       xrecord_t *rec);
-static int xdl_prepare_ctx(mmfile_t *mf, long narec, xpparam_t const *xpp,
+static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash,
+			       unsigned int hbits, xrecord_t *rec);
+static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
 			   xdlclassifier_t *cf, xdfile_t *xdf);
 static void xdl_free_ctx(xdfile_t *xdf);
 static int xdl_clean_mmatch(char const *dis, long i, long s, long e);
-static int xdl_cleanup_records(xdfile_t *xdf1, xdfile_t *xdf2);
+static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
 static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2);
-static int xdl_optimize_ctxs(xdfile_t *xdf1, xdfile_t *xdf2);
+static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2);
 
 
 
@@ -83,6 +86,14 @@ static int xdl_init_classifier(xdlclassifier_t *cf, long size, long flags) {
 	for (i = 0; i < cf->hsize; i++)
 		cf->rchash[i] = NULL;
 
+	cf->alloc = size;
+	if (!(cf->rcrecs = (xdlclass_t **) xdl_malloc(cf->alloc * sizeof(xdlclass_t *)))) {
+
+		xdl_free(cf->rchash);
+		xdl_cha_free(&cf->ncha);
+		return -1;
+	}
+
 	cf->count = 0;
 
 	return 0;
@@ -96,11 +107,12 @@ static void xdl_free_classifier(xdlclassifier_t *cf) {
 }
 
 
-static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned int hbits,
-			       xrecord_t *rec) {
+static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t **rhash,
+			       unsigned int hbits, xrecord_t *rec) {
 	long hi;
 	char const *line;
 	xdlclass_t *rcrec;
+	xdlclass_t **rcrecs;
 
 	line = rec->ptr;
 	hi = (long) XDL_HASHLONG(rec->ha, cf->hbits);
@@ -116,13 +128,25 @@ static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned
 			return -1;
 		}
 		rcrec->idx = cf->count++;
+		if (cf->count > cf->alloc) {
+			cf->alloc *= 2;
+			if (!(rcrecs = (xdlclass_t **) xdl_realloc(cf->rcrecs, cf->alloc * sizeof(xdlclass_t *)))) {
+
+				return -1;
+			}
+			cf->rcrecs = rcrecs;
+		}
+		cf->rcrecs[rcrec->idx] = rcrec;
 		rcrec->line = line;
 		rcrec->size = rec->size;
 		rcrec->ha = rec->ha;
+		rcrec->len1 = rcrec->len2 = 0;
 		rcrec->next = cf->rchash[hi];
 		cf->rchash[hi] = rcrec;
 	}
 
+	(pass == 1) ? rcrec->len1++ : rcrec->len2++;
+
 	rec->ha = (unsigned long) rcrec->idx;
 
 	hi = (long) XDL_HASHLONG(rec->ha, hbits);
@@ -133,7 +157,7 @@ static int xdl_classify_record(xdlclassifier_t *cf, xrecord_t **rhash, unsigned
 }
 
 
-static int xdl_prepare_ctx(mmfile_t *mf, long narec, xpparam_t const *xpp,
+static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_t const *xpp,
 			   xdlclassifier_t *cf, xdfile_t *xdf) {
 	unsigned int hbits;
 	long i, nrec, hsize, bsize;
@@ -200,7 +224,7 @@ static int xdl_prepare_ctx(mmfile_t *mf, long narec, xpparam_t const *xpp,
 			crec->ha = hav;
 			recs[nrec++] = crec;
 
-			if (xdl_classify_record(cf, rhash, hbits, crec) < 0) {
+			if (xdl_classify_record(pass, cf, rhash, hbits, crec) < 0) {
 
 				xdl_free(rhash);
 				xdl_free(recs);
@@ -276,28 +300,28 @@ int xdl_prepare_env(mmfile_t *mf1, mmfile_t *mf2, xpparam_t const *xpp,
 		return -1;
 	}
 
-	if (xdl_prepare_ctx(mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
+	if (xdl_prepare_ctx(1, mf1, enl1, xpp, &cf, &xe->xdf1) < 0) {
 
 		xdl_free_classifier(&cf);
 		return -1;
 	}
-	if (xdl_prepare_ctx(mf2, enl2, xpp, &cf, &xe->xdf2) < 0) {
+	if (xdl_prepare_ctx(2, mf2, enl2, xpp, &cf, &xe->xdf2) < 0) {
 
 		xdl_free_ctx(&xe->xdf1);
 		xdl_free_classifier(&cf);
 		return -1;
 	}
 
-	xdl_free_classifier(&cf);
-
 	if (!(xpp->flags & XDF_PATIENCE_DIFF) &&
-			xdl_optimize_ctxs(&xe->xdf1, &xe->xdf2) < 0) {
+			xdl_optimize_ctxs(&cf, &xe->xdf1, &xe->xdf2) < 0) {
 
 		xdl_free_ctx(&xe->xdf2);
 		xdl_free_ctx(&xe->xdf1);
 		return -1;
 	}
 
+	xdl_free_classifier(&cf);
+
 	return 0;
 }
 
@@ -372,11 +396,10 @@ static int xdl_clean_mmatch(char const *dis, long i, long s, long e) {
  * matches on the other file. Also, lines that have multiple matches
  * might be potentially discarded if they happear in a run of discardable.
  */
-static int xdl_cleanup_records(xdfile_t *xdf1, xdfile_t *xdf2) {
-	long i, nm, rhi, nreff, mlim;
-	unsigned long hav;
+static int xdl_cleanup_records(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) {
+	long i, nm, nreff;
 	xrecord_t **recs;
-	xrecord_t *rec;
+	xdlclass_t *rcrec;
 	char *dis, *dis1, *dis2;
 
 	if (!(dis = (char *) xdl_malloc(xdf1->nrec + xdf2->nrec + 2))) {
@@ -387,26 +410,16 @@ static int xdl_cleanup_records(xdfile_t *xdf1, xdfile_t *xdf2) {
 	dis1 = dis;
 	dis2 = dis1 + xdf1->nrec + 1;
 
-	if ((mlim = xdl_bogosqrt(xdf1->nrec)) > XDL_MAX_EQLIMIT)
-		mlim = XDL_MAX_EQLIMIT;
 	for (i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart]; i <= xdf1->dend; i++, recs++) {
-		hav = (*recs)->ha;
-		rhi = (long) XDL_HASHLONG(hav, xdf2->hbits);
-		for (nm = 0, rec = xdf2->rhash[rhi]; rec; rec = rec->next)
-			if (rec->ha == hav && ++nm == mlim)
-				break;
-		dis1[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
+		rcrec = cf->rcrecs[(*recs)->ha];
+		nm = rcrec ? rcrec->len2 : 0;
+		dis1[i] = (nm == 0) ? 0: 1;
 	}
 
-	if ((mlim = xdl_bogosqrt(xdf2->nrec)) > XDL_MAX_EQLIMIT)
-		mlim = XDL_MAX_EQLIMIT;
 	for (i = xdf2->dstart, recs = &xdf2->recs[xdf2->dstart]; i <= xdf2->dend; i++, recs++) {
-		hav = (*recs)->ha;
-		rhi = (long) XDL_HASHLONG(hav, xdf1->hbits);
-		for (nm = 0, rec = xdf1->rhash[rhi]; rec; rec = rec->next)
-			if (rec->ha == hav && ++nm == mlim)
-				break;
-		dis2[i] = (nm == 0) ? 0: (nm >= mlim) ? 2: 1;
+		rcrec = cf->rcrecs[(*recs)->ha];
+		nm = rcrec ? rcrec->len1 : 0;
+		dis2[i] = (nm == 0) ? 0: 1;
 	}
 
 	for (nreff = 0, i = xdf1->dstart, recs = &xdf1->recs[xdf1->dstart];
@@ -468,10 +481,10 @@ static int xdl_trim_ends(xdfile_t *xdf1, xdfile_t *xdf2) {
 }
 
 
-static int xdl_optimize_ctxs(xdfile_t *xdf1, xdfile_t *xdf2) {
+static int xdl_optimize_ctxs(xdlclassifier_t *cf, xdfile_t *xdf1, xdfile_t *xdf2) {
 
 	if (xdl_trim_ends(xdf1, xdf2) < 0 ||
-	    xdl_cleanup_records(xdf1, xdf2) < 0) {
+	    xdl_cleanup_records(cf, xdf1, xdf2) < 0) {
 
 		return -1;
 	}
-- 
1.7.6

^ permalink raw reply related

* Re: "git apply --check" successes but git am says "does not match index"
From: Junio C Hamano @ 2011-08-16  4:10 UTC (permalink / raw)
  To: Jeff King; +Cc: Zemacsh, git
In-Reply-To: <20110816001306.GA23695@sigill.intra.peff.net>

Jeff King <peff@peff.net> writes:

> ... I wonder if "git rebase" actually
> suffers from the same problem,...

Doesn't it require a spiffy clean work tree before even starting?

^ permalink raw reply

* Re: "git apply --check" successes but git am says "does not match index"
From: Jeff King @ 2011-08-16  4:14 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Zemacsh, git
In-Reply-To: <7vd3g6j8sc.fsf@alter.siamese.dyndns.org>

On Mon, Aug 15, 2011 at 09:10:43PM -0700, Junio C Hamano wrote:

> Jeff King <peff@peff.net> writes:
> 
> > ... I wonder if "git rebase" actually
> > suffers from the same problem,...
> 
> Doesn't it require a spiffy clean work tree before even starting?

Ah, you're right. I was confused that the continue case called
update-index, but the regular case did not. But it calls
require_clean_work_tree, which refreshes the index (in addition to
checking the dirty state, of course). So it's fine.

-Peff

^ permalink raw reply

* [PATCH] bash-completion: Make use of git status
From: Ron Panduwana @ 2011-08-16  6:09 UTC (permalink / raw)
  To: git; +Cc: Shawn O. Pearce, Junio C Hamano, Lee Marlow, Ron Panduwana

When autocompleting git add, rm, checkout --, and reset HEAD; Make it so they use git status to offer suitable files.

Signed-off-by: Ron Panduwana <panduwana@gmail.com>
---
Hello,

I made some little improvements to the bash autocompletion script for git add, rm, checkout --, and reset HEAD.
It's because sometimes after doing "git status" I need to do one/some of the commands and hope the autocompletion can make use the status info git already knows.
For example:

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#	new file:   path/to/deeply/located/added-file
#	modified:   path/to/deeply/located/old-file
#	deleted:    path/to/deeply/located/removed-file
#
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	deleted:    path/to/deeply/located/deleted-file
#	modified:   path/to/deeply/located/modified-file
#	deleted:    path/to/deeply/located/old-file
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	path/to/deeply/located/new-file


If I need to do one of the commands, I'd like my autocompletion to work like these:

$ git add [TAB]path/to/deeply/located/[TAB][TAB]
path/to/deeply/located/modified-file   path/to/deeply/located/new-file

$ git rm [TAB]path/to/deeply/located/[TAB][TAB]
path/to/deeply/located/deleted-file   path/to/deeply/located/old-file

$ git checkout -- [TAB]path/to/deeply/located/[TAB][TAB]
path/to/deeply/located/deleted-file    path/to/deeply/located/modified-file   path/to/deeply/located/old-file

$ git reset HEAD [TAB]path/to/deeply/located/[TAB][TAB]
path/to/deeply/located/added-file     path/to/deeply/located/old-file       path/to/deeply/located/removed-file


I think it's a good thing to be included as default, so here I send the diff of my modification of the autocompletion script.

PS: for the modification I've taken into account:
- has_doubledash
- when we meant to autocomplete the --switches
- for git rm, whether --cached presents
- for git checkout, only if it starts with "git checkout -- "
- for git reset, only if it starts with "git reset HEAD "
- (ie. when we meant to autocomplete git_refs)

Hope it'd be useful.

 contrib/completion/git-completion.bash |   76 ++++++++++++++++++++------------
 1 files changed, 48 insertions(+), 28 deletions(-)

diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash
index 5a83090..233bdbb 100755
--- a/contrib/completion/git-completion.bash
+++ b/contrib/completion/git-completion.bash
@@ -1010,6 +1010,12 @@ __git_has_doubledash ()
 	return 1
 }

+# __git_files_having_status requires 1 argument
+__git_files_having_status ()
+{
+	echo "$(git status -uall --porcelain . 2>/dev/null | egrep "^$1" | cut -c4-)"
+}
+
 __git_whitespacelist="nowarn warn error error-all fix"

 _git_am ()
@@ -1058,17 +1064,17 @@ _git_apply ()

 _git_add ()
 {
-	__git_has_doubledash && return
-
-	case "$cur" in
-	--*)
-		__gitcomp "
-			--interactive --refresh --patch --update --dry-run
-			--ignore-errors --intent-to-add
-			"
-		return
-	esac
-	COMPREPLY=()
+	if ! __git_has_doubledash; then
+		case "$cur" in
+		--*)
+			__gitcomp "
+				--interactive --refresh --patch --update --dry-run
+				--ignore-errors --intent-to-add
+				"
+			return
+		esac
+	fi
+	__gitcomp "$(__git_files_having_status "(.[MAU]|UD|\?\?)")"
 }

 _git_archive ()
@@ -1171,7 +1177,12 @@ _git_bundle ()

 _git_checkout ()
 {
-	__git_has_doubledash && return
+	if __git_has_doubledash; then
+		if [[ ${words[2]} = "--" ]]; then
+			__gitcomp "$(__git_files_having_status ".[MD]")"
+		fi
+		return
+	fi

 	case "$cur" in
 	--conflict=*)
@@ -2313,14 +2324,18 @@ _git_replace ()

 _git_reset ()
 {
-	__git_has_doubledash && return
-
-	case "$cur" in
-	--*)
-		__gitcomp "--merge --mixed --hard --soft --patch"
+	if ! __git_has_doubledash; then
+		case "$cur" in
+		--*)
+			__gitcomp "--merge --mixed --hard --soft --patch"
+			return
+			;;
+		esac
+	fi
+	if [[ ${words[2]} = "HEAD" ]]; then
+		__gitcomp "$(__git_files_having_status "[ADM].")"
 		return
-		;;
-	esac
+	fi
 	__gitcomp "$(__git_refs)"
 }

@@ -2337,15 +2352,20 @@ _git_revert ()

 _git_rm ()
 {
-	__git_has_doubledash && return
-
-	case "$cur" in
-	--*)
-		__gitcomp "--cached --dry-run --ignore-unmatch --quiet"
-		return
-		;;
-	esac
-	COMPREPLY=()
+	if ! __git_has_doubledash; then
+		case "$cur" in
+		--*)
+			__gitcomp "--cached --dry-run --ignore-unmatch --quiet"
+			return
+			;;
+		esac
+	fi
+	# check if --cached was specified
+	if [ "$(__git_find_on_cmdline "--cached")" ]; then
+		COMPREPLY=()
+	else
+		__gitcomp "$(__git_files_having_status "(.D|DU|UA)")"
+	fi
 }

 _git_shortlog ()
--
1.7.1

^ permalink raw reply related

* Re: GitTogether 2011
From: David Barr @ 2011-08-16  8:25 UTC (permalink / raw)
  To: Shawn O. Pearce, Junio C Hamano
  Cc: Sverre Rabbelier, David Bainbridge, Scott Chacon, Dave Borowitz,
	git@vger.kernel.org
In-Reply-To: <CAP2yMaK_bd05v_jWdh2Xbat96OB8OuPQKOwEh8JD9TrsqmAMmA@mail.gmail.com>

On Fri, Jul 29, 2011 at 3:14 AM, Scott Chacon <schacon@gmail.com> wrote:
> Hey,
>
> On Thu, Jul 28, 2011 at 10:02 AM, Sverre Rabbelier <srabbelier@gmail.com> wrote:
>>> We have been watching eagerly for an announcement relating to GitTogether 2011 but we have seen nothing so far.
>>>
>>> Does anyone know what is happening?
>>
>> In previous years Shawn has organized it, but I don't know if he has
>> time this year. If not, perhaps that Junio or Dave are interested.
>
> Generally Shawn has coordinated it through Google right around the
> GSoC stuff.  Junio works there now too, so I assume one of them would
> want to but if they're swamped or something, I would be happy to set
> it up at a nearby place.  The mentor summit is 22 & 23 October, so
> right after is the time we would normally do it (24/25).

Any news on the GitTogether front?

--
David Barr

^ permalink raw reply

* Двери любые супер не дорого  4 95 74-09022
From: Aleksashin @ 2011-08-16  8:41 UTC (permalink / raw)
  To: git, git

Двери входные для любых помещений
очень не дорого до 50 скидка


926 тел 011-32-44

http://u.to/Zn4gAQ

^ permalink raw reply

* Загран двери не верь проверь денег не надо почти 740-90-44 в 495
From: Arabov Gennady @ 2011-08-16 10:17 UTC (permalink / raw)
  To: git, git

Помещения двери вход
почти бесплатно


4 95 74-09022

http://b23.ru/nos6

^ permalink raw reply

* [PATCH v3 00/10] vcs-svn,svn-fe add a couple of options
From: Dmitry Ivankov @ 2011-08-16  9:54 UTC (permalink / raw)
  To: git; +Cc: Jonathan Nieder, David Barr, Ramkumar Ramachandra, Dmitry Ivankov

This is a next iteration of [1].

Most Noticeable changes since [1] are:
1) squash [2/11] and [4/11] into [3/10] "use parse-options"
2) replace [11/11] with a lesser patch that just adds api for
writing notes in vcs-svn/ but doesn't yet uses it. So that the
series is more stable, while exact notes usage can be adjusted
and played with a bit more separately.
3) applied most of suggestions from [1] with minor edits

The patch base is svn-fe branch at git://repo.or.cz/git/jrn.git

[1] http://thread.gmane.org/gmane.comp.version-control.git/177025

Dmitry Ivankov (10):
  svn-fe: add man target to Makefile
  svn-fe: add EXTLIBS needed for parse-options
  svn-fe,test-svn-fe: use parse-options
  vcs-svn: make svndump_init parameters a struct
  vcs-svn: move commit parameters logic to svndump.c
  vcs-svn,svn-fe: allow to specify dump destination ref
  vcs-svn,svn-fe: convert REPORT_FILENO to an option
  vcs-svn,svn-fe: allow to disable 'progress' lines
  vcs-svn,svn-fe: add --incremental option
  vcs-svn: add fast_export_note to create notes

 contrib/svn-fe/Makefile   |   18 ++++----
 contrib/svn-fe/svn-fe.c   |   45 ++++++++++++++++--
 contrib/svn-fe/svn-fe.txt |   38 +++++++++++++--
 t/t9010-svn-fe.sh         |  118 ++++++++++++++++++++++++++++++++++++++-------
 test-svn-fe.c             |   57 ++++++++++++++++------
 vcs-svn/fast_export.c     |   60 ++++++++++-------------
 vcs-svn/fast_export.h     |   10 ++--
 vcs-svn/svndump.c         |   79 ++++++++++++++++++++++++------
 vcs-svn/svndump.h         |   14 +++++-
 9 files changed, 332 insertions(+), 107 deletions(-)

-- 
1.7.3.4

^ permalink raw reply

* [PATCH v3 01/10] svn-fe: add man target to Makefile
From: Dmitry Ivankov @ 2011-08-16  9:54 UTC (permalink / raw)
  To: git; +Cc: Jonathan Nieder, David Barr, Ramkumar Ramachandra, Dmitry Ivankov
In-Reply-To: <1313488495-2203-1-git-send-email-divanorama@gmail.com>

There already is a svn-fe.1 target. But 'man' being a standard
target is easier to discover or type. It can also be reused if
more manpages arise here.

Signed-off-by: Dmitry Ivankov <divanorama@gmail.com>
---
 contrib/svn-fe/Makefile |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/contrib/svn-fe/Makefile b/contrib/svn-fe/Makefile
index 360d8da..bc03a3e 100644
--- a/contrib/svn-fe/Makefile
+++ b/contrib/svn-fe/Makefile
@@ -33,6 +33,8 @@ ifndef V
 endif
 endif
 
+man: svn-fe.1
+
 svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(GIT_LIB)
 	$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ svn-fe.o \
 		$(ALL_LDFLAGS) $(LIBS)
@@ -60,4 +62,4 @@ svn-fe.1: svn-fe.txt
 clean:
 	$(RM) svn-fe$X svn-fe.o svn-fe.html svn-fe.xml svn-fe.1
 
-.PHONY: all clean FORCE
+.PHONY: all man clean FORCE
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v3 03/10] svn-fe,test-svn-fe: use parse-options
From: Dmitry Ivankov @ 2011-08-16  9:54 UTC (permalink / raw)
  To: git; +Cc: Jonathan Nieder, David Barr, Ramkumar Ramachandra, Dmitry Ivankov
In-Reply-To: <1313488495-2203-1-git-send-email-divanorama@gmail.com>

There was custom options parsing. As more options arise it will
be easier to add and document new options with parse-options api.

Use parse-options api in svn-fe and test-svn-fe. This implies adding
help messages. And by the way clarify the "url" parameter meaning,
renaming it to git-svn-id-url and updating svn-fe.txt. Also allow a
--git-svn-id-url=url way of specifying it.

$ svn-fe --git-svn-id-url=url
does the same thing as
$ svn-fe url
i.e., url is used to generate git-svn-id: lines, if url is set.

Signed-off-by: Dmitry Ivankov <divanorama@gmail.com>
Reviewed-by: Jonathan Nieder <jrnieder@gmail.com>
---
 contrib/svn-fe/Makefile   |    2 +-
 contrib/svn-fe/svn-fe.c   |   32 +++++++++++++++++++++++++++++---
 contrib/svn-fe/svn-fe.txt |   17 +++++++++++++----
 test-svn-fe.c             |   43 +++++++++++++++++++++++++++++--------------
 4 files changed, 72 insertions(+), 22 deletions(-)

diff --git a/contrib/svn-fe/Makefile b/contrib/svn-fe/Makefile
index 8b12df1..15ba24d 100644
--- a/contrib/svn-fe/Makefile
+++ b/contrib/svn-fe/Makefile
@@ -41,7 +41,7 @@ svn-fe$X: svn-fe.o $(VCSSVN_LIB) $(GIT_LIB)
 		$(ALL_LDFLAGS) $(LIBS)
 
 svn-fe.o: svn-fe.c ../../vcs-svn/svndump.h
-	$(QUIET_CC)$(CC) -I../../vcs-svn -o $*.o -c $(ALL_CFLAGS) $<
+	$(QUIET_CC)$(CC) -I../../vcs-svn -I../.. -o $*.o -c $(ALL_CFLAGS) $<
 
 svn-fe.html: svn-fe.txt
 	$(QUIET_SUBDIR0)../../Documentation $(QUIET_SUBDIR1) \
diff --git a/contrib/svn-fe/svn-fe.c b/contrib/svn-fe/svn-fe.c
index 35db24f..a95e72f 100644
--- a/contrib/svn-fe/svn-fe.c
+++ b/contrib/svn-fe/svn-fe.c
@@ -3,14 +3,40 @@
  * You may freely use, modify, distribute, and relicense it.
  */
 
-#include <stdlib.h>
+#include "git-compat-util.h"
+#include "parse-options.h"
 #include "svndump.h"
 
-int main(int argc, char **argv)
+static const char * const svn_fe_usage[] = {
+	"svn-fe [options] [git-svn-id-url] < dump | fast-import-backend",
+	NULL
+};
+
+static const char *url;
+
+static struct option svn_fe_options[] = {
+	OPT_STRING(0, "git-svn-id-url", &url, "url",
+		"add git-svn-id line to log messages, imitating git-svn"),
+	OPT_END()
+};
+
+int main(int argc, const char **argv)
 {
+	argc = parse_options(argc, argv, NULL, svn_fe_options,
+						svn_fe_usage, 0);
+	if (argc > 1)
+		usage_with_options(svn_fe_usage, svn_fe_options);
+
+	if (argc == 1) {
+		if (url)
+			usage_msg_opt("git-svn-id-url is set twice: as a "
+					"--parameter and as a [parameter]",
+					svn_fe_usage, svn_fe_options);
+		url = argv[0];
+	}
 	if (svndump_init(NULL))
 		return 1;
-	svndump_read((argc > 1) ? argv[1] : NULL);
+	svndump_read(url);
 	svndump_deinit();
 	svndump_reset();
 	return 0;
diff --git a/contrib/svn-fe/svn-fe.txt b/contrib/svn-fe/svn-fe.txt
index 2dd27ce..8c6d347 100644
--- a/contrib/svn-fe/svn-fe.txt
+++ b/contrib/svn-fe/svn-fe.txt
@@ -10,7 +10,7 @@ SYNOPSIS
 [verse]
 mkfifo backchannel &&
 svnadmin dump --deltas REPO |
-	svn-fe [url] 3<backchannel |
+	svn-fe [options] [git-svn-id-url] 3<backchannel |
 	git fast-import --cat-blob-fd=3 3>backchannel
 
 DESCRIPTION
@@ -25,6 +25,14 @@ command.
 Note: this tool is very young.  The details of its commandline
 interface may change in backward incompatible ways.
 
+OPTIONS
+-------
+
+--git-svn-id-url=<url>::
+	Url to be used in git-svn-id: lines in git-svn
+	metadata lines format. See NOTES for more detailed
+	description.
+
 INPUT FORMAT
 ------------
 Subversion's repository dump format is documented in full in
@@ -50,9 +58,10 @@ user <user@UUID>
 as committer, where 'user' is the value of the `svn:author` property
 and 'UUID' the repository's identifier.
 
-To support incremental imports, 'svn-fe' puts a `git-svn-id` line at
-the end of each commit log message if passed an url on the command
-line.  This line has the form `git-svn-id: URL@REVNO UUID`.
+'svn-fe' can be used in preparing a repository for 'git-svn' as follows.
+If `git-svn-id-url` is specified, 'svn-fe' will put `git-svn-id` line at
+the end of each commit log message.
+This line has the form `git-svn-id: URL@REVNO UUID`.
 
 The resulting repository will generally require further processing
 to put each project in its own repository and to separate the history
diff --git a/test-svn-fe.c b/test-svn-fe.c
index 332a5f7..c10d3ca 100644
--- a/test-svn-fe.c
+++ b/test-svn-fe.c
@@ -3,28 +3,39 @@
  */
 
 #include "git-compat-util.h"
+#include "parse-options.h"
 #include "vcs-svn/svndump.h"
 #include "vcs-svn/svndiff.h"
 #include "vcs-svn/sliding_window.h"
 #include "vcs-svn/line_buffer.h"
 
-static const char test_svnfe_usage[] =
-	"test-svn-fe (<dumpfile> | [-d] <preimage> <delta> <len>)";
+static const char * const test_svnfe_usage[] = {
+	"test-svn-fe <dumpfile>",
+	"test-svn-fe -d <preimage> <delta> <len>",
+	NULL
+};
 
-static int apply_delta(int argc, char *argv[])
+static int delta_test;
+
+static struct option test_svnfe_options[] = {
+	OPT_SET_INT('d', "apply-delta", &delta_test, "test apply_delta", 1),
+	OPT_END()
+};
+
+static int apply_delta(int argc, const char *argv[])
 {
 	struct line_buffer preimage = LINE_BUFFER_INIT;
 	struct line_buffer delta = LINE_BUFFER_INIT;
 	struct sliding_view preimage_view = SLIDING_VIEW_INIT(&preimage, -1);
 
-	if (argc != 5)
-		usage(test_svnfe_usage);
+	if (argc != 3)
+		usage_with_options(test_svnfe_usage, test_svnfe_options);
 
-	if (buffer_init(&preimage, argv[2]))
+	if (buffer_init(&preimage, argv[0]))
 		die_errno("cannot open preimage");
-	if (buffer_init(&delta, argv[3]))
+	if (buffer_init(&delta, argv[1]))
 		die_errno("cannot open delta");
-	if (svndiff0_apply(&delta, (off_t) strtoull(argv[4], NULL, 0),
+	if (svndiff0_apply(&delta, (off_t) strtoull(argv[2], NULL, 0),
 					&preimage_view, stdout))
 		return 1;
 	if (buffer_deinit(&preimage))
@@ -37,10 +48,16 @@ static int apply_delta(int argc, char *argv[])
 	return 0;
 }
 
-int main(int argc, char *argv[])
+int main(int argc, const char *argv[])
 {
-	if (argc == 2) {
-		if (svndump_init(argv[1]))
+	argc = parse_options(argc, argv, NULL, test_svnfe_options,
+						test_svnfe_usage, 0);
+
+	if (delta_test)
+		return apply_delta(argc, argv);
+
+	if (argc == 1) {
+		if (svndump_init(argv[0]))
 			return 1;
 		svndump_read(NULL);
 		svndump_deinit();
@@ -48,7 +65,5 @@ int main(int argc, char *argv[])
 		return 0;
 	}
 
-	if (argc >= 2 && !strcmp(argv[1], "-d"))
-		return apply_delta(argc, argv);
-	usage(test_svnfe_usage);
+	usage_with_options(test_svnfe_usage, test_svnfe_options);
 }
-- 
1.7.3.4

^ permalink raw reply related

* [PATCH v3 02/10] svn-fe: add EXTLIBS needed for parse-options
From: Dmitry Ivankov @ 2011-08-16  9:54 UTC (permalink / raw)
  To: git; +Cc: Jonathan Nieder, David Barr, Ramkumar Ramachandra, Dmitry Ivankov
In-Reply-To: <1313488495-2203-1-git-send-email-divanorama@gmail.com>

Currently parse-options.o pull quite a big bunch of dependencies
that are neither pulled in by svn-fe Makefile nor included in libgit.a.

Use a temporary hack: put hardcoded EXTLIBS, this may not work in all
setups because /Makefile logic is not repeated. The list of extlibs
is likely to be exhaustive, but one may need to adjust it.

-lcrypto is needed for SHA-1 routines unless NO_OPENSSL or BLK_SHA1
is set, -lpcre is for grep if USE_LIBPCRE is set, and -lz is needed
throughout.

In the future, none of these should be needed, after a little
rearranging to ensure that parse-options.o has no references to
translation units that need to access the object db.

Signed-off-by: Dmitry Ivankov <divanorama@gmail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
 contrib/svn-fe/Makefile |   12 +++++-------
 1 files changed, 5 insertions(+), 7 deletions(-)

diff --git a/contrib/svn-fe/Makefile b/contrib/svn-fe/Makefile
index bc03a3e..8b12df1 100644
--- a/contrib/svn-fe/Makefile
+++ b/contrib/svn-fe/Makefile
@@ -8,11 +8,12 @@ CFLAGS = -g -O2 -Wall
 LDFLAGS =
 ALL_CFLAGS = $(CFLAGS)
 ALL_LDFLAGS = $(LDFLAGS)
-EXTLIBS =
+EXTLIBS = -lssl -lcrypto -lpcre -lz -lpthread
 
 GIT_LIB = ../../libgit.a
 VCSSVN_LIB = ../../vcs-svn/lib.a
-LIBS = $(VCSSVN_LIB) $(GIT_LIB) $(EXTLIBS)
+XDIFF_LIB = ../../xdiff/lib.a
+LIBS = $(VCSSVN_LIB) $(GIT_LIB) $(XDIFF_LIB) $(EXTLIBS)
 
 QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir
 QUIET_SUBDIR1 =
@@ -53,11 +54,8 @@ svn-fe.1: svn-fe.txt
 		../contrib/svn-fe/$@
 	$(MV) ../../Documentation/svn-fe.1 .
 
-../../vcs-svn/lib.a: FORCE
-	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) vcs-svn/lib.a
-
-../../libgit.a: FORCE
-	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) libgit.a
+$(VCSSVN_LIB) $(GIT_LIB) $(XDIFF_LIB): ../../%.a: FORCE
+	$(QUIET_SUBDIR0)../.. $(QUIET_SUBDIR1) $*.a
 
 clean:
 	$(RM) svn-fe$X svn-fe.o svn-fe.html svn-fe.xml svn-fe.1
-- 
1.7.3.4

^ 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