Git development
 help / color / mirror / Atom feed
* Re: Stacked GIT 0.3 (now more Quilt-like)
From: Junio C Hamano @ 2005-07-08  1:24 UTC (permalink / raw)
  To: Peter Osterlund; +Cc: Catalin Marinas, git
In-Reply-To: <m31x6acdcl.fsf@telia.com>

>>>>> "PO" == Peter Osterlund <petero2@telia.com> writes:

PO> I think it would be good if it was possible to include diffstat output
PO> in exported patches, something like this:

PO> Added possibility to include diffstat output in exported patches.

And you wuold want to do things similarly to what others have
already done.  git-resolve-script uses "git-apply --stat" there,
instead of "diffstat", so people without diffstat installed can
still get the same information.

Even if you want to stick to "diffstat", at least I would
suggest giving -p1, not -p0, to it; otherwise you would see b/
like what you have there.

PO>  b/stgit/git.py  |   22 ++++++++++++++++++++++
PO>  b/stgit/main.py |    2 ++
PO>  2 files changed, 24 insertions(+)

Further, using "git-apply --stat --summary" would be nicer; this
is something you cannot do with plain "diffstat".

^ permalink raw reply

* Re: Stacked GIT 0.3 (now more Quilt-like)
From: Peter Osterlund @ 2005-07-08  1:10 UTC (permalink / raw)
  To: Catalin Marinas; +Cc: GIT
In-Reply-To: <1119994003.9631.6.camel@localhost.localdomain>

Catalin Marinas <catalin.marinas@gmail.com> writes:

> A new StGIT release is available from http://procode.org/stgit/

I think it would be good if it was possible to include diffstat output
in exported patches, something like this:


Added possibility to include diffstat output in exported patches.

Signed-off-by: Peter Osterlund <petero2@telia.com>
---

 b/stgit/git.py  |   22 ++++++++++++++++++++++
 b/stgit/main.py |    2 ++
 2 files changed, 24 insertions(+)

diff --git a/stgit/git.py b/stgit/git.py
--- a/stgit/git.py
+++ b/stgit/git.py
@@ -345,6 +345,28 @@ def diff(files = [], rev1 = 'HEAD', rev2
                      % (rev1, files_str, extra_args)) != 0:
             raise GitException, 'git-diff-cache failed'
 
+def diffstat(files = [], rev1 = 'HEAD', rev2 = None):
+    """Return the diffstat between rev1 and rev2
+    """
+    files_str = reduce(lambda x, y: x + ' ' + y, files, '')
+
+    os.system('git-update-cache --refresh > /dev/null')
+
+    if rev2:
+        f = os.popen('git-diff-tree -p %s %s %s | diffstat -p0'
+                     % (rev1, rev2, files_str), 'r')
+        str = f.read()
+        if f.close():
+            raise GitException, 'git-diff-tree failed'
+        return str
+    else:
+        f = os.popen('git-diff-cache -p %s %s | diffstat -p0'
+                     % (rev1, files_str), 'r')
+        str = f.read()
+        if f.close():
+            raise GitException, 'git-diff-cache failed'
+        return str
+
 def checkout(files = [], force = False):
     """Check out the given or all files
     """
diff --git a/stgit/main.py b/stgit/main.py
--- a/stgit/main.py
+++ b/stgit/main.py
@@ -659,6 +659,8 @@ def export(parser, options, args):
         patch = crt_series.get_patch(p)
 
         tmpl_dict = {'description': patch.get_description().rstrip(),
+                     'diffstat': git.diffstat(rev1 = __git_id('%s/bottom' % p),
+                                              rev2 = __git_id('%s/top' % p)),
                      'authname': patch.get_authname(),
                      'authemail': patch.get_authemail(),
                      'authdate': patch.get_authdate(),

-- 
Peter Osterlund - petero2@telia.com
http://web.telia.com/~u89404340

^ permalink raw reply

* [PATCH] Give --full-objects flag to rev-list when preparing a dumb server.
From: Junio C Hamano @ 2005-07-08  1:03 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0507071657140.25104@g5.osdl.org>

>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:

LT> This is nasty - if you mis-spell "self-sufficient" (easy enough to do) 
LT> you'll never know the end result isn't what you expected. It won't warn 
LT> you in any way, it will just make a non-self-sufficient pack..

To match the change of flag name to --full-objects,...

------------
This adds --full flag to git-repack-script, and uses it when
preparing the dumb server material.

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

 git-repack-script             |   10 +++++++++-
 git-update-dumb-server-script |    2 +-
 2 files changed, 10 insertions(+), 2 deletions(-)

0617ae867e7e27a7b484827f882fe7b396bea004
diff --git a/git-repack-script b/git-repack-script
--- a/git-repack-script
+++ b/git-repack-script
@@ -1,8 +1,16 @@
 #!/bin/sh
 : ${GIT_DIR=.git}
 : ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
+
+case "$1" in
+--full)
+	objects=--full-objects ;;
+*)
+	objects=--objects ;;
+esac
+
 rm -f .tmp-pack-*
-packname=$(git-rev-list --unpacked --objects $(git-rev-parse --all) |
+packname=$(git-rev-list --unpacked $objects $(git-rev-parse --all) |
 	git-pack-objects --non-empty --incremental .tmp-pack) ||
 	exit 1
 if [ -z "$packname" ]; then
diff --git a/git-update-dumb-server-script b/git-update-dumb-server-script
--- a/git-update-dumb-server-script
+++ b/git-update-dumb-server-script
@@ -26,7 +26,7 @@ plain_size=$(
 
 if test $max_plain_size -lt $plain_size >/dev/null
 then
-	git-repack-script && git-prune-packed
+	git-repack-script --full && git-prune-packed
 fi &&
 
 git-update-dumb-server &&
------------

^ permalink raw reply

* [PATCH] rev-list: add "--full-objects" flag.
From: Junio C Hamano @ 2005-07-08  1:02 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0507071657140.25104@g5.osdl.org>

>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:

LT> This is nasty - if you mis-spell "self-sufficient" (easy enough to do) 
LT> you'll never know the end result isn't what you expected. It won't warn 
LT> you in any way, it will just make a non-self-sufficient pack..

Again you are right.  How about --full-objects instead?

------------
When --full-objects is specified instead of usual "--objects",
rev-list shows all objects reachable from trees associated with
the commits in its output.  This can be used to ensure that a
single pack can be used to recreate the tree associated with
every commit in it.

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

 rev-list.c                 |   13 +++++-
 t/t6100-rev-list-object.sh |   98 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+), 2 deletions(-)
 create mode 100644 t/t6100-rev-list-object.sh

24c31c0417a54a6ca6dc1b86267bccbbfe87c7d8
diff --git a/rev-list.c b/rev-list.c
--- a/rev-list.c
+++ b/rev-list.c
@@ -17,6 +17,7 @@ static const char rev_list_usage[] =
 		      "  --min-age=epoch\n"
 		      "  --bisect\n"
 		      "  --objects\n"
+		      "  --full-objects\n"
 		      "  --unpacked\n"
 		      "  --header\n"
 		      "  --pretty\n"
@@ -27,6 +28,7 @@ static int bisect_list = 0;
 static int tag_objects = 0;
 static int tree_objects = 0;
 static int blob_objects = 0;
+static int objects_self_sufficient = 0;
 static int verbose_header = 0;
 static int show_parents = 0;
 static int hdr_termination = 0;
@@ -198,7 +200,7 @@ static void mark_tree_uninteresting(stru
 	struct object *obj = &tree->object;
 	struct tree_entry_list *entry;
 
-	if (!tree_objects)
+	if (!tree_objects || objects_self_sufficient)
 		return;
 	if (obj->flags & UNINTERESTING)
 		return;
@@ -448,7 +450,14 @@ int main(int argc, char **argv)
 			bisect_list = 1;
 			continue;
 		}
-		if (!strcmp(arg, "--objects")) {
+		if (!strncmp(arg, "--objects", 9)) {
+			tag_objects = 1;
+			tree_objects = 1;
+			blob_objects = 1;
+			continue;
+		}
+		if (!strncmp(arg, "--full-objects", 9)) {
+			objects_self_sufficient = 1;
 			tag_objects = 1;
 			tree_objects = 1;
 			blob_objects = 1;
diff --git a/t/t6100-rev-list-object.sh b/t/t6100-rev-list-object.sh
new file mode 100644
--- /dev/null
+++ b/t/t6100-rev-list-object.sh
@@ -0,0 +1,98 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+
+test_description='git-rev-list --objects test.
+
+'
+. ./test-lib.sh
+
+GIT_AUTHOR_DATE='+0000 946684801'
+GIT_AUTHOR_NAME=none
+GIT_AUTHOR_EMAIL=none@none
+GIT_COMMITTER_DATE='+0000 946684801'
+GIT_COMMITTER_NAME=none
+GIT_COMMITTER_EMAIL=none@none
+export GIT_AUTHOR_DATE GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL \
+       GIT_COMMITTER_DATE GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
+
+_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
+_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
+sedScript='s/^\('"$_x40"' [^ ]*\) .*/\1/p'
+
+test_expect_success setup '
+    for i in frotz nitfol
+    do
+	    echo $i >$i &&
+	    git-update-cache --add $i || exit
+    done &&
+    tree0=$(git-write-tree) &&
+    commit0=$(git-commit-tree $tree0) &&
+    echo $tree0 &&
+    echo $commit0 &&
+    git-ls-tree -r $tree0 &&
+    echo nitfol nitfol >nitfol &&
+    rm -f frotz &&
+    git-update-cache --add nitfol --remove frotz &&
+    tree1=$(git-write-tree) &&
+    commit1=$(git-commit-tree $tree1 -p $commit0) &&
+    echo $tree1 &&
+    echo $commit1 &&
+    git-ls-tree -r $tree1    
+' </dev/null
+
+test_expect_success 'pack #0' '
+    name0=$(git-rev-list --objects $commit0 | \
+            git-pack-objects pk0) &&
+    ls pk0-* &&
+    git-verify-pack -v pk0-$name0.idx |
+    sed -ne "$sedScript" | sort >contents.0
+'
+
+test_expect_success 'pack #1 (commit 1 except commit 0)' '
+    name1=$(git-rev-list --objects $commit1 ^$commit0 | \
+            git-pack-objects pk1) &&
+    ls pk1-* &&
+    git-verify-pack -v pk1-$name1.idx |
+    sed -ne "$sedScript" | sort >contents.1
+'
+
+test_expect_success 'there should not be any overlaps' '
+    case $(comm -12 contents.0 contents.1 | wc -l) in
+    0) ;;
+    *) false ;;
+    esac
+'
+
+test_expect_success 'pack #2 (commit 1 unpacked only)' '
+    ln pk0-* .git/objects/pack/. &&
+    name2=$(git-rev-list --objects --unpacked $commit1 | \
+            git-pack-objects pk2) &&
+    ls pk2-* &&
+    git-verify-pack -v pk1-$name2.idx |
+    sed -ne "$sedScript" | sort >contents.2
+'
+
+test_expect_success 'pack #1 and #2 should be the same' '
+    diff contents.1 contents.2
+'
+
+test_expect_success 'pack #3 (commit 1 except commit 0, self-sufficient)' '
+    name3=$(git-rev-list --full-objects $commit1 ^$commit0 | \
+            git-pack-objects pk3) &&
+    ls pk3-* &&
+    git-verify-pack -v pk3-$name3.idx |
+    sed -ne "$sedScript" | sort >contents.3
+'
+
+ls_tree_to_invent='s/^[0-9]* \([^ ]*\) \('"$_x40"'\)	.*/\2 \1/'
+test_expect_success 'make sure pack #3 is not missing anything from commit1' '
+    (
+	echo "$tree1 tree"
+	echo "$commit1 commit"
+	git-ls-tree "$tree1" | sed -e "$ls_tree_to_invent"
+    ) | sort >tree-contents.1 &&
+    comm -23 tree-contents.1 contents.3 >missing.3 &&
+    diff /dev/null missing.3
+'
------------

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Linus Torvalds @ 2005-07-08  0:23 UTC (permalink / raw)
  To: Tony Luck; +Cc: Petr Baudis, Junio C Hamano, git
In-Reply-To: <12c511ca050707170964a2cc92@mail.gmail.com>



On Thu, 7 Jul 2005, Tony Luck wrote:
> 
> This is what happens ("linus" is a local branch just pulled from kernel.org,
> so it just contains one pack file and its index).
> 
> $ cg-update linus
> `/home/aegl/GIT/linus/.git/refs/heads/master' -> `.git/refs/heads/linus'
> does not exist /home/aegl/GIT/linus/.git/objects/04/3d051615aa5da09a7e44f1edbb69
> 798458e067
> Cannot obtain needed object 043d051615aa5da09a7e44f1edbb69798458e067
> while processing commit 0000000000000000000000000000000000000000.
> cg-pull: objects pull failed

Ok. The immediate fix is to just unpack the pack:

	mv .git/objects/pack/* .git/
	for i in .git/*.pack; do git-unpack-objects < $i; done

(or similar - the above is untested, but I think it should be obvious 
enough what I'm trying to do).

> If I try it again, it thinks things are up to date (since it mistakenly
> updated the .git/refs/heads/linus), but then fails to apply (since it
> doesn't have the objects it needs).

Ok, that's a worse bug, it really shouldn't update the head until _after_ 
the pull has succeeded.

		Linus

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Linus Torvalds @ 2005-07-08  0:09 UTC (permalink / raw)
  To: Tony Luck; +Cc: Petr Baudis, Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.58.0507071658460.25104@g5.osdl.org>



On Thu, 7 Jul 2005, Linus Torvalds wrote:
> > 
> > cg-update from a local repo that contains packs is broken though :-(
> 
> Is this with cg-0.12? The most recent release should be happy with packs.

Ahh, I see it. It's because it uses "git-local-pull", and yes, 
git-local-pull does the old filename assumption. Right?

Ho humm.. That's a bug in local-pull.c, although I'm not sure how to fix
it best. One option is to just not use it (as in "use git-fetch-pack
instead"), and another is to use GIT_ALTERNATE_OBJECT_DIRECTORIES and just
pick up the files that way. Yet another one is to actually copy over (or
link) the pack-file, but that's likely the least preferable one.

The _simplest_ fix is to use git-fetch-pack. It doesn't give you the 
convenient hard-linking, though.

		Linus

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Tony Luck @ 2005-07-08  0:09 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Petr Baudis, Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.58.0507071658460.25104@g5.osdl.org>

> > cg-update from a local repo that contains packs is broken though :-(
> 
> Is this with cg-0.12? The most recent release should be happy with packs.

Yes ... I pulled, built and installed the latest cogito this afternoon
before trying
to touch anything involving packs.  cg-version says:

cogito-0.12 (b21855b8734ca76ea08c0c17e4a204191b6e3add)

This is what happens ("linus" is a local branch just pulled from kernel.org,
so it just contains one pack file and its index).

$ cg-update linus
`/home/aegl/GIT/linus/.git/refs/heads/master' -> `.git/refs/heads/linus'
does not exist /home/aegl/GIT/linus/.git/objects/04/3d051615aa5da09a7e44f1edbb69
798458e067
Cannot obtain needed object 043d051615aa5da09a7e44f1edbb69798458e067
while processing commit 0000000000000000000000000000000000000000.
cg-pull: objects pull failed

If I try it again, it thinks things are up to date (since it
mistakenly updated the
.git/refs/heads/linus), but then fails to apply (since it doesn't have
the objects
it needs).

-Tony

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Linus Torvalds @ 2005-07-07 23:59 UTC (permalink / raw)
  To: Tony Luck; +Cc: Petr Baudis, Junio C Hamano, git
In-Reply-To: <12c511ca05070716526954edd@mail.gmail.com>



On Thu, 7 Jul 2005, Tony Luck wrote:
>
> > > So, what _is_ then the way to pull now, actually? If we use rsync, won't
> > > we end up with having the objects we previous had twice now?
> > 
> > Rsync works fine. You can either unpack the pack you get, or, if you
> > prefer, just run
> > 
> >         git-prune-packed
> 
> cg-update from a local repo that contains packs is broken though :-(

Is this with cg-0.12? The most recent release should be happy with packs.

> Also "git-fsck-cache" in a repo that is fully packed complains:
> 
>    fatal: No default references

Ahh, that's true. I knew about it, and forgot. Will fix,

		Linus

^ permalink raw reply

* Re: [PATCH] rev-list: add "--objects=self-sufficient" flag.
From: Linus Torvalds @ 2005-07-07 23:58 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vfyuqfa6r.fsf_-_@assigned-by-dhcp.cox.net>



On Thu, 7 Jul 2005, Junio C Hamano wrote:
>
> -		if (!strcmp(arg, "--objects")) {
> +		if (!strncmp(arg, "--objects", 9)) {
> +			if (!strcmp(arg+9, "=self-sufficient"))
> +				objects_self_sufficient = 1;

This is nasty - if you mis-spell "self-sufficient" (easy enough to do) 
you'll never know the end result isn't what you expected. It won't warn 
you in any way, it will just make a non-self-sufficient pack..

		Linus

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Junio C Hamano @ 2005-07-07 23:54 UTC (permalink / raw)
  To: Tony Luck; +Cc: git
In-Reply-To: <12c511ca05070716526954edd@mail.gmail.com>

>>>>> "TL" == Tony Luck <tony.luck@gmail.com> writes:

TL> Also "git-fsck-cache" in a repo that is fully packed complains:

TL>    fatal: No default references

"git-fsck-cache --full", perhaps?

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Tony Luck @ 2005-07-07 23:52 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Petr Baudis, Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.58.0507071549330.25104@g5.osdl.org>

> > So, what _is_ then the way to pull now, actually? If we use rsync, won't
> > we end up with having the objects we previous had twice now?
> 
> Rsync works fine. You can either unpack the pack you get, or, if you
> prefer, just run
> 
>         git-prune-packed

cg-update from a local repo that contains packs is broken though :-(

Also "git-fsck-cache" in a repo that is fully packed complains:

   fatal: No default references

-Tony

^ permalink raw reply

* [PATCH] Use --objects=self-sufficient flag to rev-list.
From: Junio C Hamano @ 2005-07-07 23:50 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7vll4ifbq8.fsf_-_@assigned-by-dhcp.cox.net>

This adds --self-sufficient flag to git-repack-script, and uses
it when preparing the dumb server material.

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

*** This makes things easier for the dumb puller because
*** self-sufficient pack means less falling back on traditional
*** http-pull.

 git-repack-script             |   10 +++++++++-
 git-update-dumb-server-script |    2 +-
 2 files changed, 10 insertions(+), 2 deletions(-)

6b0568181ede5540706bcdf69868102f554a2f8a
diff --git a/git-repack-script b/git-repack-script
--- a/git-repack-script
+++ b/git-repack-script
@@ -1,8 +1,16 @@
 #!/bin/sh
 : ${GIT_DIR=.git}
 : ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
+
+case "$1" in
+--self-sufficient)
+	objects=--objects=self-sufficient ;;
+*)
+	objects=--objects ;;
+esac
+
 rm -f .tmp-pack-*
-packname=$(git-rev-list --unpacked --objects $(git-rev-parse --all) |
+packname=$(git-rev-list --unpacked $objects $(git-rev-parse --all) |
 	git-pack-objects --non-empty --incremental .tmp-pack) ||
 	exit 1
 if [ -z "$packname" ]; then
diff --git a/git-update-dumb-server-script b/git-update-dumb-server-script
--- a/git-update-dumb-server-script
+++ b/git-update-dumb-server-script
@@ -26,7 +26,7 @@ plain_size=$(
 
 if test $max_plain_size -lt $plain_size >/dev/null
 then
-	git-repack-script && git-prune-packed
+	git-repack-script --self-sufficient && git-prune-packed
 fi &&
 
 git-update-dumb-server &&
------------

^ permalink raw reply

* [PATCH] rev-list: add "--objects=self-sufficient" flag.
From: Junio C Hamano @ 2005-07-07 23:50 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7vll4ifbq8.fsf_-_@assigned-by-dhcp.cox.net>

When --objects=self-sufficient is specified instead of usual
"--objects", rev-list shows all objects reachable from trees
associated with the commits in its output.  This can be used to
ensure that a single pack can be used to recreate the tree
associated with every commit in it.

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

*** This makes things easier for the dumb puller because
*** self-sufficient pack means less falling back on traditional
*** http-pull.

 rev-list.c                 |    7 ++-
 t/t6100-rev-list-object.sh |   97 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 102 insertions(+), 2 deletions(-)
 create mode 100644 t/t6100-rev-list-object.sh

60563326cea81f89098a88ab716fb4f02e326b43
diff --git a/rev-list.c b/rev-list.c
--- a/rev-list.c
+++ b/rev-list.c
@@ -27,6 +27,7 @@ static int bisect_list = 0;
 static int tag_objects = 0;
 static int tree_objects = 0;
 static int blob_objects = 0;
+static int objects_self_sufficient = 0;
 static int verbose_header = 0;
 static int show_parents = 0;
 static int hdr_termination = 0;
@@ -198,7 +199,7 @@ static void mark_tree_uninteresting(stru
 	struct object *obj = &tree->object;
 	struct tree_entry_list *entry;
 
-	if (!tree_objects)
+	if (!tree_objects || objects_self_sufficient)
 		return;
 	if (obj->flags & UNINTERESTING)
 		return;
@@ -448,7 +449,9 @@ int main(int argc, char **argv)
 			bisect_list = 1;
 			continue;
 		}
-		if (!strcmp(arg, "--objects")) {
+		if (!strncmp(arg, "--objects", 9)) {
+			if (!strcmp(arg+9, "=self-sufficient"))
+				objects_self_sufficient = 1;
 			tag_objects = 1;
 			tree_objects = 1;
 			blob_objects = 1;
diff --git a/t/t6100-rev-list-object.sh b/t/t6100-rev-list-object.sh
new file mode 100644
--- /dev/null
+++ b/t/t6100-rev-list-object.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+#
+# Copyright (c) 2005 Junio C Hamano
+#
+
+test_description='git-rev-list --objects test.
+
+'
+. ./test-lib.sh
+
+GIT_AUTHOR_DATE='+0000 946684801'
+GIT_AUTHOR_NAME=none
+GIT_AUTHOR_EMAIL=none@none
+GIT_COMMITTER_DATE='+0000 946684801'
+GIT_COMMITTER_NAME=none
+GIT_COMMITTER_EMAIL=none@none
+export GIT_AUTHOR_DATE GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL \
+       GIT_COMMITTER_DATE GIT_COMMITTER_NAME GIT_COMMITTER_EMAIL
+
+_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
+_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
+sedScript='s/^\('"$_x40"' [^ ]*\) .*/\1/p'
+
+test_expect_success setup '
+    for i in frotz nitfol
+    do
+	    echo $i >$i &&
+	    git-update-cache --add $i || exit
+    done &&
+    tree0=$(git-write-tree) &&
+    commit0=$(git-commit-tree $tree0) &&
+    echo $tree0 &&
+    echo $commit0 &&
+    git-ls-tree -r $tree0 &&
+    echo nitfol nitfol >nitfol &&
+    git-update-cache --add nitfol &&
+    tree1=$(git-write-tree) &&
+    commit1=$(git-commit-tree $tree1 -p $commit0) &&
+    echo $tree1 &&
+    echo $commit1 &&
+    git-ls-tree -r $tree1    
+' </dev/null
+
+test_expect_success 'pack #0' '
+    name0=$(git-rev-list --objects $commit0 | \
+            git-pack-objects pk0) &&
+    ls pk0-* &&
+    git-verify-pack -v pk0-$name0.idx |
+    sed -ne "$sedScript" | sort >contents.0
+'
+
+test_expect_success 'pack #1 (commit 1 except commit 0)' '
+    name1=$(git-rev-list --objects $commit1 ^$commit0 | \
+            git-pack-objects pk1) &&
+    ls pk1-* &&
+    git-verify-pack -v pk1-$name1.idx |
+    sed -ne "$sedScript" | sort >contents.1
+'
+
+test_expect_success 'there should not be any overlaps' '
+    case $(comm -12 contents.0 contents.1 | wc -l) in
+    0) ;;
+    *) false ;;
+    esac
+'
+
+test_expect_success 'pack #2 (commit 1 unpacked only)' '
+    ln pk0-* .git/objects/pack/. &&
+    name2=$(git-rev-list --objects --unpacked $commit1 | \
+            git-pack-objects pk2) &&
+    ls pk2-* &&
+    git-verify-pack -v pk1-$name2.idx |
+    sed -ne "$sedScript" | sort >contents.2
+'
+
+test_expect_success 'pack #1 and #2 should be the same' '
+    diff contents.1 contents.2
+'
+
+test_expect_success 'pack #3 (commit 1 except commit 0, self-sufficient)' '
+    name3=$(git-rev-list --objects=self-sufficient $commit1 ^$commit0 | \
+            git-pack-objects pk3) &&
+    ls pk3-* &&
+    git-verify-pack -v pk3-$name3.idx |
+    sed -ne "$sedScript" | sort >contents.3
+'
+
+ls_tree_to_invent='s/^[0-9]* \([^ ]*\) \('"$_x40"'\)	.*/\2 \1/'
+test_expect_success 'make sure pack #3 is not missing anything from commit1' '
+    (
+	echo "$tree1 tree"
+	echo "$commit1 commit"
+	git-ls-tree "$tree1" | sed -e "$ls_tree_to_invent"
+    ) | sort >tree-contents.1 &&
+    comm -23 tree-contents.1 contents.3 >missing.3 &&
+    diff /dev/null missing.3
+'
------------

^ permalink raw reply

* [PATCH] Pull efficiently from a dumb git store.
From: Junio C Hamano @ 2005-07-07 23:16 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Petr Baudis, git
In-Reply-To: <Pine.LNX.4.58.0507071549330.25104@g5.osdl.org>

The git-update-dumb-server-script command statically prepares
additional information to describe what the server side has, so
that a smart client can pull things efficiently even via a
transport such as static-file-only HTTP.

The files prepared by the command is $GIT_DIR/info/server, which
is a tar archive that contains the following files:

    rev-cache   -- commit ancestry chain, append only to help
	           rsync mirroring.
    inventory   -- list of refs and their SHA1.
    pack        -- list of available prepackaged packs.
    server.sha1 -- sha1sum output for the above three files (optional).

A smart client git-dumb-pull-script works in the following way:

 - First it slurps these files, and then .idx files that
   corresponds to the packs described in "pack".

 - Then it finds the commits that it wants from the server by
   looking at "inventory" to find various heads, and "rev-cache" to
   find commits that is missing from the client, and "pack" to
   figure out downloading which packs is the most efficient way to
   fill what is missing from its repository.  This is done with
   the help of the git-dumb-pull-resolve command.

 - Then it slurps the pack files.

 - The git-http-pull / git-local-pull command walks the commit
   chain in an old-fashioned way and downloads unpacked objects
   to fill the rest.

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

 Makefile                      |   10 +
 dumb-pull-resolve.c           |  239 +++++++++++++++++++++++++++++++++
 git-dumb-pull-script          |  129 ++++++++++++++++++
 git-update-dumb-server-script |   47 ++++++
 rev-cache.c                   |  300 +++++++++++++++++++++++++++++++++++++++++
 rev-cache.h                   |   31 ++++
 show-rev-cache.c              |   18 ++
 update-dumb-server.c          |  153 +++++++++++++++++++++
 8 files changed, 925 insertions(+), 2 deletions(-)
 create mode 100644 dumb-pull-resolve.c
 create mode 100755 git-dumb-pull-script
 create mode 100755 git-update-dumb-server-script
 create mode 100644 rev-cache.c
 create mode 100644 rev-cache.h
 create mode 100644 show-rev-cache.c
 create mode 100644 update-dumb-server.c

a880bc7300f070aca3a255828b48390cb9793245
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -31,7 +31,8 @@ SCRIPTS=git git-apply-patch-script git-m
 	git-fetch-script git-status-script git-commit-script \
 	git-log-script git-shortlog git-cvsimport-script git-diff-script \
 	git-reset-script git-add-script git-checkout-script git-clone-script \
-	gitk git-cherry git-rebase-script git-relink-script git-repack-script
+	gitk git-cherry git-rebase-script git-relink-script git-repack-script \
+	git-dumb-pull-script git-update-dumb-server-script
 
 PROG=   git-update-cache git-diff-files git-init-db git-write-tree \
 	git-read-tree git-commit-tree git-cat-file git-fsck-cache \
@@ -44,7 +45,8 @@ PROG=   git-update-cache git-diff-files 
 	git-diff-stages git-rev-parse git-patch-id git-pack-objects \
 	git-unpack-objects git-verify-pack git-receive-pack git-send-pack \
 	git-prune-packed git-fetch-pack git-upload-pack git-clone-pack \
-	git-show-index
+	git-show-index git-update-dumb-server git-show-rev-cache \
+	git-dumb-pull-resolve
 
 all: $(PROG)
 
@@ -58,6 +60,9 @@ LIB_FILE=libgit.a
 LIB_H=cache.h object.h blob.h tree.h commit.h tag.h delta.h epoch.h csum-file.h \
 	pack.h pkt-line.h refs.h
 
+LIB_H += rev-cache.h
+LIB_OBJS += rev-cache.o
+
 LIB_H += strbuf.h
 LIB_OBJS += strbuf.o
 
@@ -153,6 +158,7 @@ object.o: $(LIB_H)
 read-cache.o: $(LIB_H)
 sha1_file.o: $(LIB_H)
 usage.o: $(LIB_H)
+rev-cache.o: $(LIB_H)
 strbuf.o: $(LIB_H)
 gitenv.o: $(LIB_H)
 entry.o: $(LIB_H)
diff --git a/dumb-pull-resolve.c b/dumb-pull-resolve.c
new file mode 100644
--- /dev/null
+++ b/dumb-pull-resolve.c
@@ -0,0 +1,239 @@
+#include "cache.h"
+#include "rev-cache.h"
+
+static const char *dumb_pull_resolve_usage =
+"git-dumb_pull_resolve <tmpdir> (<remote> <local>)...";
+
+static struct inventory {
+	struct inventory *next;
+	unsigned char sha1[20];
+	char name[1]; /* more; 1 is for terminating NUL */
+} *inventory;
+
+static struct inventory *find_inventory(const char *name)
+{
+	struct inventory *e = inventory;
+	while (e && strcmp(e->name, name))
+		e = e->next;
+	return e;
+}
+
+static void read_inventory(const char *path)
+{
+	FILE *fp;
+	char buf[1024];
+
+	fp = fopen(path, "r");
+	if (!fp)
+		die("cannot open %s", path);
+	while (fgets(buf, sizeof(buf), fp)) {
+		struct inventory *e; 
+		int len = strlen(buf);
+		if (buf[len-1] != '\n')
+			die("malformed inventory file");
+		buf[--len] = 0;
+		e = xmalloc(sizeof(*e) + len - 41);
+		strcpy(e->name, buf + 41);
+		get_sha1_hex(buf, e->sha1);
+		e->next = inventory;
+		inventory = e;
+	}
+	fclose(fp);
+}
+
+#define MAX_PACKS 0
+static struct pack {
+	struct pack *next;
+	unsigned int *map;
+	unsigned long pack_size;
+	unsigned long index_size;
+	unsigned char ix;
+	unsigned long fill;
+	char name[1]; /* more; 1 is for terminating NUL */
+} *pack;
+
+static void map_pack_idx(const char *path, const char *tmpdir)
+{
+	FILE *fp;
+	char buf[1024];
+	int num_pack = 0;
+
+	fp = fopen(path, "r");
+	if (!fp)
+		die("cannot open %s", path);
+	while (fgets(buf, sizeof(buf), fp)) {
+		struct pack *e;
+		int len;
+		int fd;
+		struct stat st;
+		char path[PATH_MAX];
+		char *cp;
+
+		cp = strchr(buf, ' ');
+		if (!cp || !*++cp)
+			die("malformed pack file");
+
+		len = strlen(cp);
+		if (cp[len-1] != '\n')
+			die("malformed pack file");
+		cp[--len] = 0;
+		
+		if (MAX_PACKS && MAX_PACKS < num_pack) {
+			error("cannot handle too many packs.  ignoring %s",
+			      cp);
+			continue;
+		}
+
+		e = xmalloc(sizeof(*e) + len);
+		strcpy(e->name, cp);
+		e->pack_size = strtoul(buf, NULL, 10);
+
+		sprintf(path, "%s/%s", tmpdir, cp);
+		len = strlen(path);
+		strcpy(path + len - 5, ".idx");
+		fd = open(path, O_RDONLY);
+		if (fd < 0)
+			goto ignore_entry;
+		if (fstat(fd, &st)) {
+			close(fd);
+			goto ignore_entry;
+		}
+		e->index_size = st.st_size;
+		e->map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+		close(fd);
+		if (e->map == MAP_FAILED)
+			die("cannot map %s", path);
+		e->next = pack;
+		e->ix = num_pack++;
+		pack = e;
+		continue;
+	ignore_entry:
+		free(e);
+	}
+	fclose(fp);
+}
+
+static int find_in_pack_idx(const unsigned char *sha1, struct pack *e)
+{
+	unsigned int *level1_ofs = e->map;
+	int hi = ntohl(level1_ofs[*sha1]);
+	int lo = ((*sha1 == 0x0) ? 0 : ntohl(level1_ofs[*sha1 - 1]));
+	void *index = e->map + 256;
+
+	do {
+		int mi = (lo + hi) / 2;
+		int cmp = memcmp(index + 24 * mi + 4, sha1, 20);
+		if (!cmp)
+			return 1;
+		if (0 < cmp)
+			hi = mi;
+		else
+			lo = mi+1;
+	} while (lo < hi);
+	return 0;
+}
+
+static void mark_needed(const unsigned char *sha1)
+{
+	struct rev_cache *rc;
+	struct rev_list_elem *rle;
+	int pos;
+
+	if (has_sha1_file(sha1))
+		return;
+	pos = find_rev_cache(sha1);
+	if (pos < 0)
+		die("rev-cache does not match inventory");
+	rc = rev_cache[pos];
+	rc->work = 1;
+	for (rle = rc->parents; rle; rle= rle->next)
+		mark_needed(rle->ri->sha1);
+}
+
+static struct rev_cache *needed;
+static unsigned long num_needed;
+
+static void link_needed(void)
+{
+	/* Link needed ones for quick traversal */
+	int i;
+	num_needed = 0;
+	for (i = 0; i < nr_revs; i++) {
+		struct rev_cache *rc = rev_cache[i];
+		if (rc->work) {
+			rc->work_ptr = needed;
+			needed = rc;
+			num_needed++;
+		}
+	}
+}
+
+/* Currently this part is stupid, FIXME */
+static void find_optimum_packs(void)
+{
+	struct rev_cache *rc;
+	struct pack *e;
+	unsigned long hits, total;
+
+	hits = total = 0;
+	for (rc = needed; rc; rc = rc->work_ptr)
+		rc->work = 0;
+
+	for (e = pack; e; e = e->next) {
+		e->fill = 0;
+		for (rc = needed; rc; rc = rc->work_ptr)
+			if (!rc->work && find_in_pack_idx(rc->sha1, e)) {
+				rc->work = 1<<(e->ix);
+				e->fill++;
+				hits++;
+			}
+		if (e->fill) {
+			fprintf(stderr, "use %s to fill %lu\n",
+				e->name, e->fill);
+			total += e->pack_size;
+		}
+	}
+
+	fprintf(stderr, "# needed %lu, hits %lu, total %lu\n",
+		num_needed, hits, total);
+	for (e = pack; e; e = e->next)
+		if (e->fill)
+			printf("%s\n", e->name);
+}
+
+int main(int ac, char **av)
+{
+	int i;
+	char path[PATH_MAX];
+	const char *tmpdir;
+
+	if (ac < 4 || ac % 2)
+		usage(dumb_pull_resolve_usage);
+
+	tmpdir = av[1];
+	ac--; av++;
+
+	sprintf(path, "%s/inventory", tmpdir);
+	read_inventory(path);
+
+	sprintf(path, "%s/rev-cache", tmpdir);
+	read_rev_cache(path, NULL, 0);
+
+	for (i = 1; i < ac; i += 2) {
+		/* av[i] is a remote branch name */
+		struct inventory *e = find_inventory(av[i]);
+		if (!e) {
+			error("cannot find branch %s", av[i]);
+			continue;
+		}
+		mark_needed(e->sha1);
+	}
+
+	link_needed();
+
+	sprintf(path, "%s/pack", tmpdir);
+	map_pack_idx(path, tmpdir);
+
+	find_optimum_packs();
+	return 0;
+}
diff --git a/git-dumb-pull-script b/git-dumb-pull-script
new file mode 100755
--- /dev/null
+++ b/git-dumb-pull-script
@@ -0,0 +1,129 @@
+#!/bin/sh
+
+: ${GIT_DIR=.git}
+: ${GIT_OBJECT_DIRECTORY="${GIT_DIR}/objects"}
+
+usage () {
+	echo >&2 "* git dumb-pull <url> ( <remote-name> <local-name> ) ..."
+	exit 1
+}
+
+error () {
+	echo >&2 "* git-dumb-pull: $*"
+	exit 1
+}
+
+download_one() {
+	# $1 - URL
+	# $2 - Local target
+	case "$1" in
+	file://* )
+		path=/$(expr "$1" : 'file:/*\(.*\)')
+		cp "$path" "$2" || rm -f "$2"
+		;;
+	http://* | https://* )
+		wget -O "$2" "$1" || rm -f "$2"
+		;;
+	esac
+}
+
+case "$#" in
+0)
+	usage;;
+esac
+url="$1"; shift
+
+case "$url" in
+http://* | https://*)
+	use_url="$url"
+	cmd='git-http-pull -a -v'
+	;;
+file://*)
+	use_url=/$(expr "$url" : 'file:/*\(.*\)')
+	cmd='git-local-pull -a -l -v'
+	;;
+*)
+	error "Unknown url scheme $url"
+	;;
+esac
+
+# The rest of arguments are remote and local names
+case $#,$(expr "$#" % 2) in
+0,* | 1,* | *,1)
+	error "Need one or more branch name pairs." ;;
+esac
+
+tmp=.git-dumb-pull-$$
+mkdir "$tmp" || error "cannot create temporary directory"
+trap "rm -fr $tmp" 0 1 2 3 15
+
+# Failing to download is not fatal.  It just means the server is
+# dumber than we thought ;-)
+if download_one "$url/info/server" $tmp/server
+then
+	infofiles='inventory pack rev-cache'
+	(
+	  cd $tmp &&
+	  tar xvf server $infofiles || exit 1
+	  if tar xf server server.sha1
+	  then
+		sha1sum -c server.sha1 || {
+		    # did we fail because we did not have sha1sum command?
+		    case "$?" in
+		    127)
+		        : ;; # the command did not exist.
+		    *)
+		        false ;;
+		    esac
+		}
+	  else
+	  	echo >&2 "* warning: server file lacks sha1 checksum"
+	  fi &&
+	  rm -f server.sha1
+	) || exit
+fi
+
+if test -f $tmp/pack
+then
+	while read pack_size pack
+	do
+		case "$pack" in
+		*/*)
+			echo >&2 "* malformed pack $pack"
+			continue
+			;;
+		esac
+
+		idx=$(expr "$pack" : '\(.*\)\.pack$').idx
+		# It is possible, even likely, that we already have that
+		# index file and associated pack file.
+		if test -f "${GIT_OBJECT_DIRECTORY}/pack/$pack" &&
+		   test -f "${GIT_OBJECT_DIRECTORY}/pack/$idx"
+		then
+			continue
+		fi
+		download_one "$url/objects/pack/$idx" "$tmp/$idx"
+	done <$tmp/pack
+
+	git-dumb-pull-resolve $tmp "$@" |
+	while read pack
+	do
+		echo >&2 "* $pack"
+		download_one "$url/objects/pack/$pack" "$tmp/$pack"
+		if test -f "$tmp/$pack" && git-verify-pack "$tmp/$pack"
+		then
+			idx=$(expr "$pack" : '\(.*\)\.pack$').idx
+			mv "$tmp/$pack" "$tmp/$idx" \
+				"${GIT_OBJECT_DIRECTORY}/pack/"
+		fi
+	done
+fi
+
+while case "$#" in 0) break ;; esac
+do
+	remote="$1" local="$2"
+	$cmd -w "$local" "$remote" "$use_url"
+
+	shift
+	shift
+done
diff --git a/git-update-dumb-server-script b/git-update-dumb-server-script
new file mode 100755
--- /dev/null
+++ b/git-update-dumb-server-script
@@ -0,0 +1,47 @@
+#!/bin/sh
+#
+# Copyright (c) 2005, Junio C Hamano
+#
+
+: ${GIT_DIR=.git}
+: ${GIT_OBJECT_DIRECTORY="$GIT_DIR/objects"}
+export GIT_DIR GIT_OBJECT_DIRECTORY
+
+infofiles='inventory pack rev-cache'
+
+usage () {
+	echo >&2 "* git update-dumb-server"
+	exit 1
+}
+
+# Allow 10MB plain SHA1 files to be accumulated before we repack.
+max_plain_size=10240
+
+plain_size=$(
+{
+	du -sk "$GIT_OBJECT_DIRECTORY/" "$GIT_OBJECT_DIRECTORY/pack/" |
+	sed -e 's/^[ 	]*\([0-9][0-9]*\)[ 	].*/\1/'
+	echo ' - p'
+} | dc) &&
+
+if test $max_plain_size -lt $plain_size >/dev/null
+then
+	git-repack-script && git-prune-packed
+fi &&
+
+git-update-dumb-server &&
+
+files=$infofiles
+cd "$GIT_DIR/info" &&
+if sha1sum $infofiles >server.sha1
+then
+	files="$files server.sha1"
+else
+	rm -f server.sha1
+	echo >&2 "* warning: creating server file without sha1sum"
+fi &&
+tar cf server $files &&
+
+# We leave rev-cache there for later runs.
+rm -f server.sha1 inventory pack
+
diff --git a/rev-cache.c b/rev-cache.c
new file mode 100644
--- /dev/null
+++ b/rev-cache.c
@@ -0,0 +1,300 @@
+#include "refs.h"
+#include "cache.h"
+#include "rev-cache.h"
+
+struct rev_cache **rev_cache;
+int nr_revs, alloc_revs;
+
+struct rev_list_elem *rle_free;
+
+#define BATCH_SIZE 512
+
+int find_rev_cache(const unsigned char *sha1)
+{
+	int lo = 0, hi = nr_revs;
+	while (lo < hi) {
+		int mi = (lo + hi) / 2;
+		struct rev_cache *ri = rev_cache[mi];
+		int cmp = memcmp(sha1, ri->sha1, 20);
+		if (!cmp)
+			return mi;
+		if (cmp < 0)
+			hi = mi;
+		else
+			lo = mi + 1;
+	}
+	return -lo - 1;
+}
+
+static struct rev_list_elem *alloc_list_elem(void)
+{
+	struct rev_list_elem *rle;
+	if (!rle_free) {
+		int i;
+
+		rle = xmalloc(sizeof(*rle) * BATCH_SIZE);
+		for (i = 0; i < BATCH_SIZE - 1; i++) {
+			rle[i].ri = NULL;
+			rle[i].next = &rle[i + 1];
+		}
+		rle[BATCH_SIZE - 1].ri = NULL; 
+		rle[BATCH_SIZE - 1].next = NULL; 
+		rle_free = rle;
+	}
+	rle = rle_free;
+	rle_free = rle->next;
+	return rle;
+}
+
+static struct rev_cache *create_rev_cache(const unsigned char *sha1)
+{
+	struct rev_cache *ri;
+	int pos = find_rev_cache(sha1);
+
+	if (0 <= pos)
+		return rev_cache[pos];
+	pos = -pos - 1;
+	if (alloc_revs <= ++nr_revs) {
+		alloc_revs = alloc_nr(alloc_revs);
+		rev_cache = xrealloc(rev_cache, sizeof(ri) * alloc_revs);
+	}
+	if (pos < nr_revs)
+		memmove(rev_cache + pos + 1, rev_cache + pos,
+			(nr_revs - pos - 1) * sizeof(ri));
+	ri = xcalloc(1, sizeof(*ri));
+	memcpy(ri->sha1, sha1, 20);
+	rev_cache[pos] = ri;
+	return ri;
+}
+
+static unsigned char last_sha1[20];
+
+static void write_one_rev_cache(FILE *rev_cache_file, struct rev_cache *ri)
+{
+	unsigned char flag;
+	struct rev_list_elem *rle;
+
+	if (ri->written)
+		return;
+
+	if (ri->parsed) {
+
+		/* We use last_sha1 compression only for the first parent;
+		 * otherwise the resulting rev-cache would lose the parent
+		 * order information.
+		 */
+		if (ri->parents &&
+		    !memcmp(ri->parents->ri->sha1, last_sha1, 20))
+			flag = (ri->num_parents - 1) | 0x80;
+		else
+			flag = ri->num_parents;
+
+		fwrite(ri->sha1, 20, 1, rev_cache_file);
+		fwrite(&flag, 1, 1, rev_cache_file);
+		for (rle = ri->parents; rle; rle = rle->next) {
+			if (flag & 0x80 && rle == ri->parents)
+				continue;
+			fwrite(rle->ri->sha1, 20, 1, rev_cache_file);
+		}
+		memcpy(last_sha1, ri->sha1, 20);
+		ri->written = 1;
+	}
+	/* recursively write children depth first */
+	for (rle = ri->children; rle; rle = rle->next)
+		write_one_rev_cache(rev_cache_file, rle->ri);
+}
+
+void write_rev_cache(const char *path)
+{
+	/* write the following commit ancestry information in
+	 * $GIT_DIR/info/rev-cache.
+	 *
+	 * The format is:
+	 * 20-byte SHA1 (commit ID)
+	 * 1-byte flag:
+	 * - bit 0-6 records "number of parent commit SHA1s to
+	 *   follow" (i.e. up to 127 children can be listed).
+	 * - when the bit 7 is on, then "the entry immediately
+	 *   before this entry is one of the parents of this
+         *   commit".
+	 * N x 20-byte SHA1 (parent commit IDs)
+	 */
+	FILE *rev_cache_file;
+	int i;
+	struct rev_cache *ri;
+
+	rev_cache_file = fopen(path, "a");
+	if (!rev_cache_file)
+		die("cannot append to rev cache file.");
+
+	memset(last_sha1, 0, 20);
+
+	/* Go through available rev_cache structures, starting from
+	 * parentless ones first, so that we would get most out of
+	 * last_sha1 optimization by the depth first behaviour of
+	 * write_one_rev_cache().
+	 */
+	for (i = 0; i < nr_revs; i++) {
+		ri = rev_cache[i];
+		if (ri->num_parents)
+			continue;
+		write_one_rev_cache(rev_cache_file, ri);
+	}
+	/* Then the rest */
+	for (i = 0; i < nr_revs; i++) {
+		ri = rev_cache[i];
+		write_one_rev_cache(rev_cache_file, ri);
+	}
+
+	fclose(rev_cache_file);
+}
+
+static void add_parent(struct rev_cache *child,
+		       const unsigned char *parent_sha1)
+{
+	struct rev_cache *parent = create_rev_cache(parent_sha1);
+	struct rev_list_elem *e = alloc_list_elem();
+
+	/* Keep the parent list ordered in the same way the commit
+	 * object records them.
+	 */
+	e->ri = parent;
+	e->next = NULL;
+	if (!child->parents_tail)
+		child->parents = e;
+	else
+		child->parents_tail->next = e;
+	child->parents_tail = e;
+	child->num_parents++;
+	
+	/* There is no inherent order of the children so we just
+	 * LIFO them together.
+	 */
+	e = alloc_list_elem();
+	e->next = parent->children;
+	parent->children = e;
+	e->ri = child;
+	parent->num_children++;
+}
+
+int read_rev_cache(const char *path, FILE *dumpfile, int dry_run)
+{
+	unsigned char *map;
+	int fd;
+	struct stat st;
+	unsigned long ofs, len;
+	struct rev_cache *ri = NULL;
+
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return 0;
+	if (fstat(fd, &st)) {
+		close(fd);
+		return -1;
+	}
+	map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (map == MAP_FAILED) {
+		close(fd);
+		return -1;
+	}
+	close(fd);
+
+	memset(last_sha1, 0, 20);
+	ofs = 0;
+	len = st.st_size;
+	while (ofs < len) {
+		unsigned char sha1[20];
+		int flag, cnt, i;
+		if (len < ofs + 21)
+			die("rev-cache too short"); 
+		memcpy(sha1, map + ofs, 20);
+		flag = map[ofs + 20];
+		ofs += 21;
+		cnt = (flag & 0x7f) + ((flag & 0x80) != 0);
+		if (len < ofs + (flag & 0x7f) * 20)
+			die("rev-cache too short to have %d more parents",
+			    (flag & 0x7f));
+		if (dumpfile)
+			fprintf(dumpfile, "%s", sha1_to_hex(sha1));
+		if (!dry_run) {
+			ri = create_rev_cache(sha1);
+			ri->written = 1;
+			ri->parsed = 1;
+			if (!ri)
+				die("cannot create rev-cache for %s",
+				    sha1_to_hex(sha1));
+		}
+		i = 0;
+		if (flag & 0x80) {
+			if (!dry_run)
+				add_parent(ri, last_sha1);
+			if (dumpfile)
+				fprintf(dumpfile, " %s",
+					sha1_to_hex(last_sha1));
+			i++;
+		}
+		while (i++ < cnt) {
+			if (!dry_run)
+				add_parent(ri, map + ofs);
+			if (dumpfile)
+				fprintf(dumpfile, " %s",
+					sha1_to_hex(last_sha1));
+			ofs += 20;
+		}
+		if (dumpfile)
+			fprintf(dumpfile, "\n");
+		memcpy(last_sha1, sha1, 20);
+	}
+	if (ofs != len)
+		die("rev-cache truncated?");
+	munmap(map, len);
+	return 0;
+}
+
+int record_rev_cache(const unsigned char *sha1)
+{
+	unsigned char parent[20];
+	char type[20];
+	unsigned long size, ofs;
+	unsigned int cnt, i;
+	void *buf;
+	struct rev_cache *ri;
+
+	buf = read_sha1_file(sha1, type, &size);
+	if (!buf)
+		return 1; /* unavailable */
+	if (strcmp(type, "commit")) {
+		/* could be a tag or tree */
+		free(buf);
+		return 1;
+	}
+	ri = create_rev_cache(sha1);
+	if (ri->parsed)
+		return 0;
+
+	cnt = 0;
+	ofs = 46; /* "tree " + hex-sha1 + "\n" */
+	while (!memcmp(buf + ofs, "parent ", 7) &&
+	       !get_sha1_hex(buf + ofs + 7, parent)) {
+		ofs += 48;
+		cnt++;
+	}
+	if (cnt * 48 + 46 != ofs) {
+		free(buf);
+		return error("internal error in record_rev_cache");
+	}
+
+	ri = create_rev_cache(sha1);
+	ri->parsed = 1;
+
+	for (i = 0; i < cnt; i++) {
+		unsigned char parent_sha1[20];
+		
+		ofs = 46 + i * 48 + 7;
+		get_sha1_hex(buf + ofs, parent_sha1);
+		add_parent(ri, parent_sha1);
+		record_rev_cache(parent_sha1);
+	}
+	free(buf);
+	return 0;
+}
diff --git a/rev-cache.h b/rev-cache.h
new file mode 100644
--- /dev/null
+++ b/rev-cache.h
@@ -0,0 +1,31 @@
+#ifndef REV_CACHE_H
+#define REV_CACHE_H
+
+#define REV_CACHE_PATH "info/rev-cache"
+
+extern struct rev_cache {
+	struct rev_cache *head_list;
+	struct rev_list_elem *children;
+	struct rev_list_elem *parents;
+	struct rev_list_elem *parents_tail;
+	unsigned short num_parents;
+	unsigned short num_children;
+	unsigned int written : 1;
+	unsigned int parsed : 1;
+	unsigned int work : 30;
+	void *work_ptr;
+	unsigned char sha1[20];
+} **rev_cache;
+extern int nr_revs, alloc_revs;
+
+struct rev_list_elem {
+	struct rev_list_elem *next;
+	struct rev_cache *ri;
+};
+
+extern int find_rev_cache(const unsigned char *);
+extern int read_rev_cache(const char *, FILE *, int);
+extern int record_rev_cache(const unsigned char *);
+extern void write_rev_cache(const char *);
+
+#endif
diff --git a/show-rev-cache.c b/show-rev-cache.c
new file mode 100644
--- /dev/null
+++ b/show-rev-cache.c
@@ -0,0 +1,18 @@
+#include "cache.h"
+#include "rev-cache.h"
+
+static char *dump_rev_cache_usage =
+"git-dump-rev-cache <rev-cache-file>";
+
+int main(int ac, char **av)
+{
+	while (1 < ac && av[0][1] == '-') {
+		/* do flags here */
+		break;
+		ac--; av++;
+	}
+	if (ac != 2)
+		usage(dump_rev_cache_usage);
+
+	return read_rev_cache(av[1], stdout, 1);
+}
diff --git a/update-dumb-server.c b/update-dumb-server.c
new file mode 100644
--- /dev/null
+++ b/update-dumb-server.c
@@ -0,0 +1,153 @@
+#include "refs.h"
+#include "cache.h"
+#include "rev-cache.h"
+
+static FILE *inventory_file;
+static int verbose = 0;
+
+static int do_refs(const char *path, const unsigned char *sha1)
+{
+	/* path is like .git/refs/heads/master */
+	int pfxlen = 10; /* strlen(".git/refs/") */
+	fprintf(inventory_file, "%s %s\n", sha1_to_hex(sha1), path + pfxlen);
+	if (verbose)
+		fprintf(stderr, "inventory %s %s\n",
+			sha1_to_hex(sha1), path + pfxlen);
+	record_rev_cache(sha1);
+	return 0;
+}
+
+static int inventory(void)
+{
+	/* write names of $GIT_DIR/refs/?*?/?* files in
+	 * $GIT_DIR/info/inventory, and find the ancestry
+	 * information.
+	 */
+	char path[PATH_MAX];
+
+	strcpy(path, git_path("info/inventory"));
+	safe_create_leading_directories(path);
+	inventory_file = fopen(path, "w");
+	if (!inventory_file)
+		die("cannot create inventory file.");
+	for_each_ref(do_refs);
+	fclose(inventory_file);
+	return 0;
+}
+
+static int compare_pack_size(const void *a_, const void *b_)
+{
+	struct packed_git *const*a = a_;
+	struct packed_git *const*b = b_;
+	if ((*a)->pack_size < (*b)->pack_size)
+		return 1;
+	else if ((*a)->pack_size == (*b)->pack_size)
+		return 0;
+	return -1;
+}
+
+static int write_packs(void)
+{
+	/* write names of pack files under $GIT_OBJECT_DIRECTORY/pack
+	 * into $GIT_DIR/info/packs.
+	 */
+	struct packed_git *p;
+	char path[PATH_MAX];
+	FILE *packs_file;
+	int pfxlen = strlen(".git/objects/pack/");
+	struct packed_git **list;
+	int cnt, i;
+
+	for (cnt = 0, p = packed_git; p; p = p->next)
+		cnt++;
+	list = xmalloc(sizeof(*list) * cnt);
+	for (i = 0, p = packed_git; p; p = p->next)
+		list[i++] = p;
+	qsort(list, cnt, sizeof(*list), compare_pack_size);
+
+	strcpy(path, git_path("info/pack"));
+	safe_create_leading_directories(path);
+	packs_file = fopen(path, "w");
+	if (!packs_file)
+		return -1;
+	for (i = 0; i < cnt; i++) {
+		p = list[i];
+		fprintf(packs_file, "%lu %s\n",
+			p->pack_size, p->pack_name + pfxlen);
+		if (verbose)
+			fprintf(stderr, "pack %lu %s\n",
+				p->pack_size,
+				p->pack_name + pfxlen);
+	}
+	free(list);
+	fclose(packs_file);
+	return 0;
+}
+
+static int inventory_packs(void)
+{
+	struct packed_git *p;
+
+	for (p = packed_git; p; p = p->next) {
+		int nth, lim;
+		lim = num_packed_objects(p);
+		for (nth = 0; nth < lim; nth++) {
+			unsigned char sha1[20];
+			char type[20];
+			if (nth_packed_object_sha1(p, nth, sha1)) {
+				error("cannot read %dth object from pack %s",
+				      nth, p->pack_name);
+				continue;
+			}
+			if (sha1_object_info(sha1, type, NULL)) {
+				error("cannot find type of %s", sha1_to_hex(sha1));
+				continue;
+			}
+			if (strcmp(type, "commit"))
+				continue;
+			record_rev_cache(sha1);
+		}
+	}
+	return 0;
+}
+
+static const char *update_dumb_server_usage =
+"git-update-dumb-server [-v] [-a]";
+
+int main(int ac, char **av)
+{
+	char path[PATH_MAX];
+	int all_commits = 0;
+
+	while (1 < ac && av[1][0] == '-') {
+		if (!strcmp(av[1], "-v"))
+			verbose = 1;
+		else if (!strcmp(av[1], "-a"))
+			all_commits = 1;
+		else
+			usage(update_dumb_server_usage);
+		ac--; av++;
+	}
+
+	/* read existing rev-cache if any */
+	strcpy(path, git_path(REV_CACHE_PATH));
+	read_rev_cache(path, verbose ? stderr : NULL, 0);
+
+	/* read refs directory and find commit ancentry information */
+	inventory();
+
+	/* 
+	 * prepare info/pack file.
+	 * Note that we do prepare_packed_git() in case we ran in
+	 * an headless repository.
+	 */
+	prepare_packed_git();
+	write_packs();
+
+	if (all_commits)
+		inventory_packs();
+
+	/* update the rev-cache database by appending newly found one to it */
+	write_rev_cache(path);
+	return 0;
+}
------------

^ permalink raw reply

* Cogito-0.12: problem with local clone
From: Wolfgang Denk @ 2005-07-07 23:00 UTC (permalink / raw)
  To: Petr Baudis; +Cc: git

Hello,

I have problems with Cogito-0.12 when trying to clone a "local" tree:

My "original" tree is in /git/u-boot-denx (imported from CVS); "/git"
is a directory mounted over NFS; all this is under Fedora Core  4  in
case it matters:

	-> cd /git/u-boot-denx
	-> cg-tag-ls
	/git/u-boot-denx/.git/refs/tags
	LABEL_2002_11_05_0120   405f4884816e733f8ba3675d2ead1b44fd4a2ad2
	LABEL_2002_11_05_1735   a21c24faf81d6e2c2cf21bc856b97994a7fb0950
	LABEL_2002_11_10_2310   90e51a047bc112515e1257077b4c898bedf29e69
	...
	U-Boot-1_1_1    eaa609e49846203434aa3b20e7084c79e89ea952
	U-Boot-1_1_2    3621a36bfb037a47a59b0c02d3686522c8d895bf
	U_BOOT_0_1_0    dc9791586a71cb80c255a830a38d4a2b092398c3
	-> cg-tag-ls | wc -l
	131

When I try to create a local clone I get lots of error messages:

	-> mkdir git-local
	-> cd git-local
	-> cg-clone /git/u-boot-denx 
	/home/wd/git/u-boot-denx
	defaulting to local storage area
	`/git/u-boot-denx/.git/refs/heads/master' -> `.git/refs/heads/origin'
	copy 9f94f652ff7a5be5263ca0ef35a512ac7f29be98
	copy db88a44625a80f558bcde5aeda291c54c737b573
	copy 30a7a8a8d49f7069403895f326de4905f63d8855
	...
	copy 9c2deccb2acfb1d0d77b733a3f19d12ea9d58ca2
	copy f548442a0fe39729a11b1d384708c7cc3b6bed20
	copy 2183da96d548c02bd4f99b05e673395f81212878
	`/git/u-boot-denx/.git/refs/tags/U_BOOT_0_1_0' -> `.git/refs/tags/U_BOOT_0_1_0'
	cp: cannot create link `.git/refs/tags/U_BOOT_0_1_0': Invalid cross-device link
	`/git/u-boot-denx/.git/refs/tags/LABEL_2002_11_05_0120' -> `.git/refs/tags/LABEL_2002_11_05_0120'
	cp: cannot create link `.git/refs/tags/LABEL_2002_11_05_0120': Invalid cross-device link
	`/git/u-boot-denx/.git/refs/tags/LABEL_2002_11_05_1735' -> `.git/refs/tags/LABEL_2002_11_05_1735'
	cp: cannot create link `.git/refs/tags/LABEL_2002_11_05_1735': Invalid cross-device link
	...
	`/git/u-boot-denx/.git/refs/tags/LABEL_2005_06_20_2345' -> `.git/refs/tags/LABEL_2005_06_20_2345'
	cp: cannot create link `.git/refs/tags/LABEL_2005_06_20_2345': Invalid cross-device link
	`/git/u-boot-denx/.git/refs/tags/LABEL_2005_07_04_0202' -> `.git/refs/tags/LABEL_2005_07_04_0202'
	cp: cannot create link `.git/refs/tags/LABEL_2005_07_04_0202': Invalid cross-device link
	unable to get tags list (non-fatal)
	/home/wd/git/u-boot-denx/.git/refs/tags
	New branch: 9f94f652ff7a5be5263ca0ef35a512ac7f29be98
	Cloned (origin /git/u-boot-denx available as branch "origin")
	Cloned to u-boot-denx/ (origin /git/u-boot-denx available as branch "origin")

And the resulting tree is indeed missing lots of tags:

	-> cg-tag-ls
	/home/wd/git/u-boot-denx.OLD/.git/refs/tags
	LABEL_2003_06_28_0050-stable    f50d58228a5be736e6ed0f8dd3202b9ea26169bf
	LABEL_2003_06_28_0130-stable    d8a9a48da39a79497d752d34d30b5edf3e3162a8
	LABEL_2003_06_28_1800-stable    b82064a05f9c88a6144dc8f894f9e312e134b6b3
	U_BOOT_0_1_0    d4e4163d86db0238264b7d06d9f023c16f1e371a
	-> cg-tag-ls | wc -l
	5
	-> 


Am I doing something wrong?
	

Best regards,

Wolfgang Denk

-- 
Software Engineering:  Embedded and Realtime Systems,  Embedded Linux
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd@denx.de
Include the success of others in your dreams for your own success.

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Linus Torvalds @ 2005-07-07 22:52 UTC (permalink / raw)
  To: Petr Baudis; +Cc: Junio C Hamano, git
In-Reply-To: <20050707221443.GB7151@pasky.ji.cz>



On Fri, 8 Jul 2005, Petr Baudis wrote:

> Let me join the sceptics camp. :-)
> 
> Dear diary, on Thu, Jul 07, 2005 at 09:04:58PM CEST, I got a letter
> where Linus Torvalds <torvalds@osdl.org> told me that...
> > Note that I just re-packed the kernel archive on kernel.org, and removed 
> > _all_ unpacked files. Once that percolates to the mirrors, the http 
> > protocol will be useless without anything like this.
> 
> *grumble*
> 
> So, what _is_ then the way to pull now, actually? If we use rsync, won't
> we end up with having the objects we previous had twice now?

Rsync works fine. You can either unpack the pack you get, or, if you 
prefer, just run

	git-prune-packed

which will remove the stand-alone object that it finds in packs. Now 
you're no longer duplicating data, and your repository is smaller than it 
used to be anyway.

Of course, that requires that you trust the packs 100%. It seems to be 
stable, and I've packed the whole kernel repo, but I actually keep my 
private tree unpacked still just in case.

> I think it would be actually simplest (for the user) to have a trivial
> CGI script on the other side which will do the git-upload-pack stuff.

Well, git-upload-pack expects the other end to follow the proper protocol, 
but yes, you can certainly expose it through a web interface and a 
specialized client that way.

		Linus

^ permalink raw reply

* Re: [PATCH] Prevent t6000 series from dropping useless sed.script in t/
From: Jon Seymour @ 2005-07-07 22:40 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Linus Torvalds, Git Mailing List
In-Reply-To: <7vd5pusbox.fsf@assigned-by-dhcp.cox.net>

Ack - sorry I didn't notice that side effect.

jon.

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Linus Torvalds @ 2005-07-07 22:23 UTC (permalink / raw)
  To: Eric W. Biederman; +Cc: Junio C Hamano, Petr Baudis, git
In-Reply-To: <m1vf3muwxw.fsf@ebiederm.dsl.xmission.com>



On Thu, 7 Jul 2005, Eric W. Biederman wrote:
>
> For optimizing network bandwidth that sounds like the way to go.  For
> adhoc development I don't know.  For a central sever you still need
> an authenticated way to push content, which makes it another dimension
> of the problem.

I'm convinced that "ssh" is the only sane way for pushing. If you don't 
trust somebody enough to give him ssh access, you shouldn't trust him with 
write access to your project in the first place.

git can actually do ssh with a _very_ restricted shell, if people are 
worried about shell access. In fact, the _only_ think the shell needs to 
be able to do is execute one of two programs, so you could have something 
_really_ trivial in your /etc/passwd as the login shell that doesn't allow 
anything else. But you'd still use ssh as the authentication protocol.

So I don't worry about pushing. I think we've got that covered. It's 
really the anonymous pulling that needs something.

		Linus

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Eric W. Biederman @ 2005-07-07 21:29 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Junio C Hamano, Petr Baudis, git
In-Reply-To: <Pine.LNX.4.58.0507071158220.3293@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> That said, I really think the dumb protocols are useless anyway. No other 
> system supports pure static object pulling anyway, and as far as I'm 
> concerned, I want "rsync" to kind of work (but it won't be optimal, since 
> re-packing will delete all the old objects and replace it with the new 
> pack that is downloaded anew). But plain http? I'm not convinced.

Have you not looked at tla/arch? tla does supports dumb servers.
It's job is a little easier as it has one file per atomic commit
I suspect once packs start working well that should not be an
issue for git either.

For small projects this is a major benefit, as they can just push
their files to a convenient http or ftp server.

> I'd much rather have a "stupid server" that just listens to a port, and
> basically forks off and executes "git-upload-pack" when it's connected to
> (perhaps reading the directory name first).  Nothing else. Then we can do 
> a security analysis of upload-pack, which should be fairly easy since it's 
> not actually ever _writing_ anything.
>
> At that point, you can do
>
> 	git pull git://www.kernel.org/pub/scm/git/..
>
> and it would just connect to some default "git port", pass off the 
> directory name, and be done with it - exact same discovery protocol that 
> now use for ssh. And "git clone" would also automatically work.

For optimizing network bandwidth that sounds like the way to go.  For
adhoc development I don't know.  For a central sever you still need
an authenticated way to push content, which makes it another dimension
of the problem.  So it is mostly a question of what is the sanest way
to mirror/publish data.  http is used a lot for publishing data and
practically everyone has access to a http server that can host
content, so I think supporting http makes git a lot more accessible
to people.  The only thing more accessible seems to be email, and
email is terrible for publish small projects.

Eric

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Junio C Hamano @ 2005-07-07 22:10 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Petr Baudis, git
In-Reply-To: <Pine.LNX.4.58.0507071456570.25104@g5.osdl.org>

>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:

>> (2) When "showing --objects", it lists the top-level tree node
>> with no name, which makes it indistinguishable from commit
>> objects by pack-objects, probably impacting the delta logic.
>> Would something like the following patch make sense, to name
>> such node "."; giving full-path not just the basename to
>> all named nodes would be even better, though.

LT> It doesn't impact the delta algorithm, because the objects are sorted by 
LT> type first, so it never mixes up trees and commits.

You are correct.  I forgot that it does sorting by type.

What do you think about giving full-path so that Makefiles in
different directories would get different name hashes?

^ permalink raw reply

* [PATCH] Typofix an error message in pack-check.c
From: Junio C Hamano @ 2005-07-07 22:12 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git

The current error message does not make any sense.

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

 pack-check.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

c3818dc056d1a603e15fe3f862849eddaee2a7c3
diff --git a/pack-check.c b/pack-check.c
--- a/pack-check.c
+++ b/pack-check.c
@@ -58,7 +58,7 @@ static int verify_packfile(struct packed
 			continue;
 		}
 		if (check_sha1_signature(sha1, data, size, type)) {
-			err = error("cannot packed %s from %s corrupt",
+			err = error("packed %s from %s is corrupt",
 				    sha1_to_hex(sha1), p->pack_name);
 			free(data);
 			continue;
------------

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Petr Baudis @ 2005-07-07 22:14 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.58.0507071158220.3293@g5.osdl.org>

Let me join the sceptics camp. :-)

Dear diary, on Thu, Jul 07, 2005 at 09:04:58PM CEST, I got a letter
where Linus Torvalds <torvalds@osdl.org> told me that...
> Note that I just re-packed the kernel archive on kernel.org, and removed 
> _all_ unpacked files. Once that percolates to the mirrors, the http 
> protocol will be useless without anything like this.

*grumble*

So, what _is_ then the way to pull now, actually? If we use rsync, won't
we end up with having the objects we previous had twice now?

> That said, I really think the dumb protocols are useless anyway. No other 
> system supports pure static object pulling anyway, and as far as I'm 
> concerned, I want "rsync" to kind of work (but it won't be optimal, since 
> re-packing will delete all the old objects and replace it with the new 
> pack that is downloaded anew). But plain http? I'm not convinced.

You can always just spider the repository which will work just as well
as rsync in the git case. ;-)

I think it would be actually simplest (for the user) to have a trivial
CGI script on the other side which will do the git-upload-pack stuff.
Minimal extra administrative overhead, flexibility, works through
proxies, and stuff.  People can rewrite it in Perl or PHorridP if they
wish and use it on webhosting servers not allowing much else.

That's not to say a dedicated server wouldn't have its place too, and
that's what's now probably simplest for us. ;-)

Now we are in a situation when there's actually no way to pull from your
kernel repository without throwing own repository to mess and
duplicating data, AFAICS.

> I'd much rather have a "stupid server" that just listens to a port, and
> basically forks off and executes "git-upload-pack" when it's connected to
> (perhaps reading the directory name first).  Nothing else. Then we can do 
> a security analysis of upload-pack, which should be fairly easy since it's 
> not actually ever _writing_ anything.
> 
> At that point, you can do
> 
> 	git pull git://www.kernel.org/pub/scm/git/..
> 
> and it would just connect to some default "git port", pass off the 
> directory name, and be done with it - exact same discovery protocol that 
> now use for ssh. And "git clone" would also automatically work.

Eek. Could you please make it at least pretend to be extensible? Compare
git-upload-pack with git-ssh-pu* - the second one prepends letters to
the data it sends so that if you add a new type of stuff to send (say
for authentication or some smart tags stuff), you could extend it in a
sensible way. What about dividing the communication to "blocks"
separated by a newline? Each block would have its first word on the
first line saying what kind of block it is - "refs", "have", "want", or
"pack" (for simplicity, the pack block might have additional restriction
that it's always the last one).  If you hit unknown block, you should
respond back by something like "huh" and ignore the rest of it.

-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
<Espy> be careful, some twit might quote you out of context..

^ permalink raw reply

* Re: [ANNOUNCE] Cogito-0.12
From: Linus Torvalds @ 2005-07-07 21:58 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Petr Baudis, git
In-Reply-To: <7vbr5ejso2.fsf@assigned-by-dhcp.cox.net>



On Thu, 7 Jul 2005, Junio C Hamano wrote:
> 
> (1) Would it make sense to have an extra flag to "rev-list
>     --objects" to make it list all the objects reachable from
>     commits listed in its output, even when some of them are
>     unchanged from UNINTERESTING commits?  Right now, a pack
>     produced from "rev-list --objects A ^B" does not have enough
>     information to reproduce the tree associated with commit A.

Well, that would certainly be possible. Just having a flag that disables 
"mark_tree_uninteresting()" would do it.

> (2) When "showing --objects", it lists the top-level tree node
>     with no name, which makes it indistinguishable from commit
>     objects by pack-objects, probably impacting the delta logic.
>     Would something like the following patch make sense, to name
>     such node "."; giving full-path not just the basename to
>     all named nodes would be even better, though.

It doesn't impact the delta algorithm, because the objects are sorted by 
type first, so it never mixes up trees and commits.

But if you wanted to, something like this would be cleaner than your 
suggestion..

		Linus

diff --git a/rev-list.c b/rev-list.c
--- a/rev-list.c
+++ b/rev-list.c
@@ -154,7 +154,7 @@ static void show_commit_list(struct comm
 	while (list) {
 		struct commit *commit = pop_most_recent_commit(&list, SEEN);
 
-		p = process_tree(commit->tree, p, "");
+		p = process_tree(commit->tree, p, "tree");
 		if (process_commit(commit) == STOP)
 			break;
 	}
@@ -386,7 +386,7 @@ static struct commit *get_commit_referen
 			mark_tree_uninteresting(tree);
 			return NULL;
 		}
-		add_pending_object(object, "");
+		add_pending_object(object, "tree");
 		return NULL;
 	}
 
@@ -401,7 +401,7 @@ static struct commit *get_commit_referen
 			mark_blob_uninteresting(blob);
 			return NULL;
 		}
-		add_pending_object(object, "");
+		add_pending_object(object, "blob");
 		return NULL;
 	}
 	die("%s is unknown object", name);

^ permalink raw reply

* Re: Stacked GIT 0.3 (now more Quilt-like)
From: Catalin Marinas @ 2005-07-07 21:22 UTC (permalink / raw)
  To: Peter Osterlund; +Cc: GIT
In-Reply-To: <m38y0ictno.fsf@telia.com>

On Thu, 2005-07-07 at 21:17 +0200, Peter Osterlund wrote:
> I've found an unrelated problem. If I export patches with "stg export
> dirname", there are no diffs included in the patches. The patch
> description is all that is generated. If I omit the dirname parameter,
> the export works correctly though.

OK, thanks. Fixed in the today's snapshot. I also added a 'resolved'
command to mark a solved conflict. 'stg status' also shows the conflicts
and 'refresh', 'push', 'pop' fail if there are unresolved conflicts. You
can override this by setting 'autoresolved: yes' in the stgitrc file and
a 'refresh' command marks all the conflicts as solved automatically (I
still need to find some time to write a tutorial for StGIT).

Catalin

^ permalink raw reply

* Re: Where'd my GIT tree go?
From: Thomas Gleixner @ 2005-07-07 20:48 UTC (permalink / raw)
  To: Tony Luck; +Cc: jon, git
In-Reply-To: <12c511ca0507062148679af4da@mail.gmail.com>

On Wed, 2005-07-06 at 21:48 -0700, Tony Luck wrote:
> Groan ... as well you should.
> 
> My tree has re-appeared now.  Thanks to whoever fixed it.

I noticed similar effects recently. Its related to the mirroring of
master.kernel.org to the public server. At some point you have only the
half of updates at the public site and obviously the git webscript
refuses to show your tree when HEAD is updated, but the referenced
commit blob is missing.

I guess that the mirroring is not aware of the update order (objects
first, HEAD last) which would prevent such oddities.

tglx

^ permalink raw reply


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