Git development
 help / color / mirror / Atom feed
* Re: git pull for update of netdev fails.
From: Johannes Schindelin @ 2006-09-21  9:14 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: git
In-Reply-To: <ees6hl$jdv$1@sea.gmane.org>

Hi,

On Wed, 20 Sep 2006, Jakub Narebski wrote:

> Petr Baudis wrote:
> 
> > Dear diary, on Wed, Sep 20, 2006 at 05:28:08PM CEST, I got a letter
> > where Linus Torvalds <torvalds@osdl.org> said that...
> 
> >> However, you can tell git that Jeff is being difficult by marking such 
> >> branches individually as being rebased.
> > 
> > This is really a wrong way of describing the problem - I'd say that Git
> > is being difficult here. The point is, the subsystem maintainers need to
> > maintain stacks of patches and rebase against the main kernel branch
> > regularily, and they want to still publish their current state. So it's
> > not really any of them being strange or difficult, but Git being so
> > because it has no seamless support for tracking those branches.
> 
> There was idea around moving remotes configuration to config file to have
> some per branch configureation, including readonly for protecting tracking
> branches, marking default branch for merge with (and which tracking
> branch(es) to merge)...

If you want it, go ahead, propose something.

> ...and that included marking branch _on the server side_ as being rebased,
> i.e. without preserved history. Unfortunately, the discussion petered out
> without changes to git.

Not true. We have the [branch "StrangeCase Sensitive/Name"] syntax as a 
consequence.

But I agree, nothing came out of the discussion about per-branch settings, 
maybe because nobody cared enough?

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Johannes Schindelin @ 2006-09-21  9:10 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git
In-Reply-To: <7vfyeld9c2.fsf@assigned-by-dhcp.cox.net>

Hi,

On Wed, 20 Sep 2006, Junio C Hamano wrote:

> I think the change to t/Makefile from 9c3796fc needs to be
> rethought.

I looked into 9c3796fc, and the change to t/Makefile is UTTER CRAP! What 
IDIOT has made that change? Oh wait, was me...

What about removing that creepy change to t/Makefile, and move your hack 
into test-lib.sh? It _should_ be safe, as _nothing_ in $HOME should affect 
the tests anyway.

Thoughts?

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Johannes Schindelin @ 2006-09-21  9:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Jeff King, git
In-Reply-To: <7vbqp9d8j2.fsf@assigned-by-dhcp.cox.net>

Hi,

On Wed, 20 Sep 2006, Junio C Hamano wrote:

> Jeff King <peff@peff.net> writes:
> 
> >>     X - a - b - c - Y
> >>   /           /
> >> o - d - e - f
> >
> > In your example, git-merge-base X Y returns X. In fact, I could only get
> > one merge base out of git-merge-base --all. I tried looking in the tests
> > to find a case that produced multiple merge bases, but I was unable to
> > find one. Is there an example floating around somewhere?
> 
> There are quite a few in git.git itself.  In the recent history,
> this counts 42, the answer to everything.
> 
> #!/bin/sh
> LF='
> '
> git rev-list --parents master..next |
> while read it p1 p2 octo
> do
> 	case "$p2" in '') continue ;; esac
>         mb=`git merge-base --all "$p1" "$p2"`

At this point you should also check if $p2 is in $mb.

> 	case "$mb" in ?*"$LF"?*) echo "$p1 $p2" : $mb ;;
>         esac
> done

The question was, if there is a fast-forward with more than one merge 
base, i.e. if the loop we jump^H^H^H^Hdo over bases is necessary.

And no, I am not aware of any such example.

Probably because X would mark all ancestors (_including_ all other 
possible merge bases) as uninteresting.

Therefore, I am convinced that there is no fast-forward returning more 
than one merge base. It is technically impossible. And thus, our loop is 
not necessary, but what the heck.

Ciao,
Dscho

^ permalink raw reply

* Re: [PATCH 1/2] gitweb: Always use git-peek-remote in git_get_references
From: Andreas Ericsson @ 2006-09-21  9:07 UTC (permalink / raw)
  To: Jakub Narebski; +Cc: Junio C Hamano, git
In-Reply-To: <200609202013.38457.jnareb@gmail.com>

Jakub Narebski wrote:
> 
> If there were post-commit hook, and it's contents was the default 
> post-update hook, info/refs would be never stale. And we could read
> from into/refs, and fallback to git-peek-remote if it doesn't exist...
> but we don't know if info/refs has current info.

ls -l .git/hooks/post-commit
-rw-r----- 1 exon exon 152 Sep 21 10:54 .git/hooks/post-commit


My post-update hook doesn't maintain info/refs for me. I'm sure that if 
someone set it up to do so they would also set the post-commit hook up 
to do the same.

-- 
Andreas Ericsson                   andreas.ericsson@op5.se
OP5 AB                             www.op5.se
Tel: +46 8-230225                  Fax: +46 8-230231

^ permalink raw reply

* Re: [PATCH] gitweb: fix display of trees via PATH_INFO.
From: Jakub Narebski @ 2006-09-21  8:56 UTC (permalink / raw)
  To: git
In-Reply-To: <20060921074821.GG31940@admingilde.org>

Martin Waitz wrote:

> When adding a / to the URL, git should display the corresponding
> tree object, but it has to remove the / first.

Hmm... I thought that gitweb works just fine with file_name ('f') parameter
with trailing '/'... I guessed wrong.

By the way, we should fix error when we try to "tree" display blob, or
"blob" display tree.
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* Re: [PATCH] gitweb: Fix showing of path in tree view
From: Jakub Narebski @ 2006-09-21  8:50 UTC (permalink / raw)
  To: git
In-Reply-To: <20060920234052.GO13132@pasky.or.cz>

Petr Baudis wrote:

> Dear diary, on Thu, Sep 21, 2006 at 01:32:42AM CEST, I got a letter
> where Junio C Hamano <junkio@cox.net> said that...

>> But I think the older one was visually nicer and more intuitive
>> in one very small detail that I think matters.  Slashes between
>> path components were not part of the anchor elements, so it was
>> clear that there were two links in "gitweb / gitweb.perl" page
>> title, not just one link.  Now it is not obvious that clicking
>> different parts of the path string in "/stgit/commands/mail.py"
>> would lead to different places.  And as you are aware, losing
>> the leading "/" would be nicer as well ;-).
> 
>   Well, this was the best I could come up without introducing "[root] /"
> or something in front of the path, which would be IMHO even uglier.
> Alternative ideas welcomed. :-)

"[$project] /", or "~ /" instead of "[root] /".

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git

^ permalink raw reply

* [PATCH] gitweb: fix display of trees via PATH_INFO.
From: Martin Waitz @ 2006-09-21  7:48 UTC (permalink / raw)
  To: git

When adding a / to the URL, git should display the corresponding
tree object, but it has to remove the / first.

Signed-off-by: Martin Waitz <tali@admingilde.org>
---
 gitweb/gitweb.perl |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index baadbe7..ea57717 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -300,6 +300,7 @@ sub evaluate_path_info {
 		$pathname =~ s,^/+,,;
 		if (!$pathname || substr($pathname, -1) eq "/") {
 			$action  ||= "tree";
+			$pathname =~ s,/$,,;
 		} else {
 			$action  ||= "blob_plain";
 		}
-- 
1.4.2.gb8b6b

-- 
Martin Waitz

^ permalink raw reply related

* Re: [PATCH] describe: fall back to 'HEAD' if no appropriate tag exists
From: Andy Whitcroft @ 2006-09-21  7:43 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Johannes Schindelin, git
In-Reply-To: <7v8xkef97b.fsf@assigned-by-dhcp.cox.net>

Junio C Hamano wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> 
>> Now, if no tag exists to say something like '<tag>-gfffffff', say
>> 'HEAD-gfffffff' instead of erroring out.
>>
>> Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
>> ---
>>  describe.c |    2 +-
>>  1 files changed, 1 insertions(+), 1 deletions(-)
>>
>> diff --git a/describe.c b/describe.c
>> index ab192f8..8b08a3f 100644
>> --- a/describe.c
>> +++ b/describe.c
>> @@ -136,7 +136,7 @@ static void describe(const char *arg, in
>>  			return;
>>  		}
>>  	}
>> -	die("cannot describe '%s'", sha1_to_hex(cmit->object.sha1));
>> +	printf("HEAD-g%s\n", find_unique_abbrev(cmit->object.sha1, abbrev));
>>  }
> 
> Hmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm.
> 
> At least with tags, the user can assume NAME-gREV means commit
> whose abbrev is REV that is descendant of NAME.  HEAD is not
> necessarily so.
> 
> Having said that, in order to avoid barfing, we have to have
> something there, and HEAD is already special in many aspects
> anyway (e.g. by only saying HEAD you cannot tell which branch's
> tip you are talking about), it might be good enough.
> 
> I am just wondering if there is some other obvious substitute
> that is better than HEAD.  "GIT-g%s" is not it ("g" already
> stands for GIT).
> 
> Another possibility is just to do
> 
>         puts(sha1_to_hex(cmit->object.sha1))
> 
> in this case.  I tend to like that better somehow; it makes
> things more explicit.

Heh, we've just been putting together 'versioner' for some software and
when git-describe fails we substitute in the complete sha1 at that
point.  Based mostly on the "who'd release something versioned without
tagging anyhow".  I think either the full sha1 or _just_ the gNNNNN
without prefix would be fine.

-apw

^ permalink raw reply

* [PATCH 5/5] git-pack-refs --prune
From: Junio C Hamano @ 2006-09-21  7:06 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7v64fhd7ns.fsf@assigned-by-dhcp.cox.net>

"git pack-refs --prune", after successfully packing the existing
refs, removes the loose ref files.  It tries to protect against
race by doing the usual lock_ref_sha1() which makes sure the
contents of the ref has not changed since we last looked at.

Also we do not bother trying to prune what was already packed, and
we do not try pruning symbolic refs.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 builtin-pack-refs.c |   84 ++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 75 insertions(+), 9 deletions(-)

diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c
index 0fc8a55..246dd63 100644
--- a/builtin-pack-refs.c
+++ b/builtin-pack-refs.c
@@ -2,6 +2,20 @@ #include "cache.h"
 #include "refs.h"
 
 static const char *result_path, *lock_path;
+static const char builtin_pack_refs_usage[] =
+"git-pack-refs [--prune]";
+
+struct ref_to_prune {
+	struct ref_to_prune *next;
+	unsigned char sha1[20];
+	char name[FLEX_ARRAY];
+};
+
+struct pack_refs_cb_data {
+	int prune;
+	struct ref_to_prune *ref_to_prune;
+	FILE *refs_file;
+};
 
 static void remove_lock_file(void)
 {
@@ -9,21 +23,70 @@ static void remove_lock_file(void)
 		unlink(lock_path);
 }
 
+static int do_not_prune(int flags)
+{
+	/* If it is already packed or if it is a symref,
+	 * do not prune it.
+	 */
+	return (flags & (REF_ISSYMREF|REF_ISPACKED));
+}
+
 static int handle_one_ref(const char *path, const unsigned char *sha1,
 			  int flags, void *cb_data)
 {
-	FILE *refs_file = cb_data;
+	struct pack_refs_cb_data *cb = cb_data;
 
 	/* Do not pack the symbolic refs */
 	if (!(flags & REF_ISSYMREF))
-		fprintf(refs_file, "%s %s\n", sha1_to_hex(sha1), path);
+		fprintf(cb->refs_file, "%s %s\n", sha1_to_hex(sha1), path);
+	if (cb->prune && !do_not_prune(flags)) {
+		int namelen = strlen(path) + 1;
+		struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen);
+		hashcpy(n->sha1, sha1);
+		strcpy(n->name, path);
+		n->next = cb->ref_to_prune;
+		cb->ref_to_prune = n;
+	}
 	return 0;
 }
 
+/* make sure nobody touched the ref, and unlink */
+static void prune_ref(struct ref_to_prune *r)
+{
+	struct ref_lock *lock = lock_ref_sha1(r->name + 5, r->sha1, 1);
+
+	if (lock) {
+		unlink(git_path(r->name));
+		unlock_ref(lock);
+	}
+}
+
+static void prune_refs(struct ref_to_prune *r)
+{
+	while (r) {
+		prune_ref(r);
+		r = r->next;
+	}
+}
+
 int cmd_pack_refs(int argc, const char **argv, const char *prefix)
 {
-	int fd;
-	FILE *refs_file;
+	int fd, i;
+	struct pack_refs_cb_data cbdata;
+
+	memset(&cbdata, 0, sizeof(cbdata));
+
+	for (i = 1; i < argc; i++) {
+		const char *arg = argv[i];
+		if (!strcmp(arg, "--prune")) {
+			cbdata.prune = 1;
+			continue;
+		}
+		/* perhaps other parameters later... */
+		break;
+	}
+	if (i != argc)
+		usage(builtin_pack_refs_usage);
 
 	result_path = xstrdup(git_path("packed-refs"));
 	lock_path = xstrdup(mkpath("%s.lock", result_path));
@@ -33,14 +96,17 @@ int cmd_pack_refs(int argc, const char *
 		die("unable to create new ref-pack file (%s)", strerror(errno));
 	atexit(remove_lock_file);
 
-	refs_file = fdopen(fd, "w");
-	if (!refs_file)
-		die("unable to create ref-pack file structure (%s)", strerror(errno));
-	for_each_ref(handle_one_ref, refs_file);
+	cbdata.refs_file = fdopen(fd, "w");
+	if (!cbdata.refs_file)
+		die("unable to create ref-pack file structure (%s)",
+		    strerror(errno));
+	for_each_ref(handle_one_ref, &cbdata);
 	fsync(fd);
-	fclose(refs_file);
+	fclose(cbdata.refs_file);
 	if (rename(lock_path, result_path) < 0)
 		die("unable to overwrite old ref-pack file (%s)", strerror(errno));
 	lock_path = NULL;
+	if (cbdata.prune)
+		prune_refs(cbdata.ref_to_prune);
 	return 0;
 }
-- 
1.4.2.1.g4dc7

^ permalink raw reply related

* [PATCH 2/5] Add callback data to for_each_ref() family.
From: Junio C Hamano @ 2006-09-21  7:06 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7v64fhd7ns.fsf@assigned-by-dhcp.cox.net>

This is a long overdue fix to the API for for_each_ref() family
of functions.  It allows the callers to specify a callback data
pointer, so that the caller does not have to use static
variables to communicate with the callback funciton.

The updated for_each_ref() family takes a function of type

	int (*fn)(const char *, const unsigned char *, void *)

and a void pointer as parameters, and calls the function with
the name of the ref and its SHA-1 with the caller-supplied void
pointer as parameters.

The commit updates two callers, builtin-name-rev.c and
builtin-pack-refs.c as an example.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 builtin-name-rev.c    |    8 ++++----
 builtin-pack-refs.c   |    8 +++++---
 builtin-prune.c       |    4 ++--
 builtin-push.c        |    4 ++--
 builtin-rev-parse.c   |   10 +++++-----
 builtin-show-branch.c |   26 +++++++++++++-------------
 describe.c            |    4 ++--
 fetch-pack.c          |    8 ++++----
 fetch.c               |    4 ++--
 fsck-objects.c        |    4 ++--
 http-push.c           |    4 ++--
 receive-pack.c        |    6 +++---
 refs.c                |   31 ++++++++++++++++++-------------
 refs.h                |   11 ++++++-----
 revision.c            |    4 ++--
 send-pack.c           |    4 ++--
 server-info.c         |    4 ++--
 upload-pack.c         |    6 +++---
 18 files changed, 79 insertions(+), 71 deletions(-)

diff --git a/builtin-name-rev.c b/builtin-name-rev.c
index 52886b6..9e3e537 100644
--- a/builtin-name-rev.c
+++ b/builtin-name-rev.c
@@ -75,11 +75,10 @@ copy_data:
 	}
 }
 
-static int tags_only;
-
-static int name_ref(const char *path, const unsigned char *sha1)
+static int name_ref(const char *path, const unsigned char *sha1, void *cb_data)
 {
 	struct object *o = parse_object(sha1);
+	int tags_only = *(int*)cb_data;
 	int deref = 0;
 
 	if (tags_only && strncmp(path, "refs/tags/", 10))
@@ -131,6 +130,7 @@ int cmd_name_rev(int argc, const char **
 {
 	struct object_array revs = { 0, 0, NULL };
 	int as_is = 0, all = 0, transform_stdin = 0;
+	int tags_only = 0;
 
 	git_config(git_default_config);
 
@@ -186,7 +186,7 @@ int cmd_name_rev(int argc, const char **
 		add_object_array((struct object *)commit, *argv, &revs);
 	}
 
-	for_each_ref(name_ref);
+	for_each_ref(name_ref, &tags_only);
 
 	if (transform_stdin) {
 		char buffer[2048];
diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c
index 0f5d827..b3d5470 100644
--- a/builtin-pack-refs.c
+++ b/builtin-pack-refs.c
@@ -1,7 +1,6 @@
 #include "cache.h"
 #include "refs.h"
 
-static FILE *refs_file;
 static const char *result_path, *lock_path;
 
 static void remove_lock_file(void)
@@ -10,8 +9,10 @@ static void remove_lock_file(void)
 		unlink(lock_path);
 }
 
-static int handle_one_ref(const char *path, const unsigned char *sha1)
+static int handle_one_ref(const char *path, const unsigned char *sha1, void *cb_data)
 {
+	FILE *refs_file = cb_data;
+
 	fprintf(refs_file, "%s %s\n", sha1_to_hex(sha1), path);
 	return 0;
 }
@@ -19,6 +20,7 @@ static int handle_one_ref(const char *pa
 int cmd_pack_refs(int argc, const char **argv, const char *prefix)
 {
 	int fd;
+	FILE *refs_file;
 
 	result_path = xstrdup(git_path("packed-refs"));
 	lock_path = xstrdup(mkpath("%s.lock", result_path));
@@ -31,7 +33,7 @@ int cmd_pack_refs(int argc, const char *
 	refs_file = fdopen(fd, "w");
 	if (!refs_file)
 		die("unable to create ref-pack file structure (%s)", strerror(errno));
-	for_each_ref(handle_one_ref);
+	for_each_ref(handle_one_ref, refs_file);
 	fsync(fd);
 	fclose(refs_file);
 	if (rename(lock_path, result_path) < 0)
diff --git a/builtin-prune.c b/builtin-prune.c
index 6228c79..e21c29b 100644
--- a/builtin-prune.c
+++ b/builtin-prune.c
@@ -174,7 +174,7 @@ static void walk_commit_list(struct rev_
 	}
 }
 
-static int add_one_ref(const char *path, const unsigned char *sha1)
+static int add_one_ref(const char *path, const unsigned char *sha1, void *cb_data)
 {
 	struct object *object = parse_object(sha1);
 	if (!object)
@@ -240,7 +240,7 @@ int cmd_prune(int argc, const char **arg
 	revs.tree_objects = 1;
 
 	/* Add all external refs */
-	for_each_ref(add_one_ref);
+	for_each_ref(add_one_ref, NULL);
 
 	/* Add all refs from the index file */
 	add_cache_refs();
diff --git a/builtin-push.c b/builtin-push.c
index c43f256..88fc8e2 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -27,7 +27,7 @@ static void add_refspec(const char *ref)
 	refspec_nr = nr;
 }
 
-static int expand_one_ref(const char *ref, const unsigned char *sha1)
+static int expand_one_ref(const char *ref, const unsigned char *sha1, void *cb_data)
 {
 	/* Ignore the "refs/" at the beginning of the refname */
 	ref += 5;
@@ -51,7 +51,7 @@ static void expand_refspecs(void)
 	}
 	if (!tags)
 		return;
-	for_each_ref(expand_one_ref);
+	for_each_ref(expand_one_ref, NULL);
 }
 
 static void set_refspecs(const char **refs, int nr)
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index fd3ccc8..c771274 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -137,7 +137,7 @@ static void show_default(void)
 	}
 }
 
-static int show_reference(const char *refname, const unsigned char *sha1)
+static int show_reference(const char *refname, const unsigned char *sha1, void *cb_data)
 {
 	show_rev(NORMAL, sha1, refname);
 	return 0;
@@ -299,19 +299,19 @@ int cmd_rev_parse(int argc, const char *
 				continue;
 			}
 			if (!strcmp(arg, "--all")) {
-				for_each_ref(show_reference);
+				for_each_ref(show_reference, NULL);
 				continue;
 			}
 			if (!strcmp(arg, "--branches")) {
-				for_each_branch_ref(show_reference);
+				for_each_branch_ref(show_reference, NULL);
 				continue;
 			}
 			if (!strcmp(arg, "--tags")) {
-				for_each_tag_ref(show_reference);
+				for_each_tag_ref(show_reference, NULL);
 				continue;
 			}
 			if (!strcmp(arg, "--remotes")) {
-				for_each_remote_ref(show_reference);
+				for_each_remote_ref(show_reference, NULL);
 				continue;
 			}
 			if (!strcmp(arg, "--show-prefix")) {
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index 4d8db0c..b3548ae 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -346,7 +346,7 @@ static void sort_ref_range(int bottom, i
 	      compare_ref_name);
 }
 
-static int append_ref(const char *refname, const unsigned char *sha1)
+static int append_ref(const char *refname, const unsigned char *sha1, void *cb_data)
 {
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 	int i;
@@ -369,7 +369,7 @@ static int append_ref(const char *refnam
 	return 0;
 }
 
-static int append_head_ref(const char *refname, const unsigned char *sha1)
+static int append_head_ref(const char *refname, const unsigned char *sha1, void *cb_data)
 {
 	unsigned char tmp[20];
 	int ofs = 11;
@@ -380,14 +380,14 @@ static int append_head_ref(const char *r
 	 */
 	if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
 		ofs = 5;
-	return append_ref(refname + ofs, sha1);
+	return append_ref(refname + ofs, sha1, cb_data);
 }
 
-static int append_tag_ref(const char *refname, const unsigned char *sha1)
+static int append_tag_ref(const char *refname, const unsigned char *sha1, void *cb_data)
 {
 	if (strncmp(refname, "refs/tags/", 10))
 		return 0;
-	return append_ref(refname + 5, sha1);
+	return append_ref(refname + 5, sha1, cb_data);
 }
 
 static const char *match_ref_pattern = NULL;
@@ -401,7 +401,7 @@ static int count_slash(const char *s)
 	return cnt;
 }
 
-static int append_matching_ref(const char *refname, const unsigned char *sha1)
+static int append_matching_ref(const char *refname, const unsigned char *sha1, void *cb_data)
 {
 	/* we want to allow pattern hold/<asterisk> to show all
 	 * branches under refs/heads/hold/, and v0.99.9? to show
@@ -417,22 +417,22 @@ static int append_matching_ref(const cha
 	if (fnmatch(match_ref_pattern, tail, 0))
 		return 0;
 	if (!strncmp("refs/heads/", refname, 11))
-		return append_head_ref(refname, sha1);
+		return append_head_ref(refname, sha1, cb_data);
 	if (!strncmp("refs/tags/", refname, 10))
-		return append_tag_ref(refname, sha1);
-	return append_ref(refname, sha1);
+		return append_tag_ref(refname, sha1, cb_data);
+	return append_ref(refname, sha1, cb_data);
 }
 
 static void snarf_refs(int head, int tag)
 {
 	if (head) {
 		int orig_cnt = ref_name_cnt;
-		for_each_ref(append_head_ref);
+		for_each_ref(append_head_ref, NULL);
 		sort_ref_range(orig_cnt, ref_name_cnt);
 	}
 	if (tag) {
 		int orig_cnt = ref_name_cnt;
-		for_each_ref(append_tag_ref);
+		for_each_ref(append_tag_ref, NULL);
 		sort_ref_range(orig_cnt, ref_name_cnt);
 	}
 }
@@ -487,7 +487,7 @@ static void append_one_rev(const char *a
 {
 	unsigned char revkey[20];
 	if (!get_sha1(av, revkey)) {
-		append_ref(av, revkey);
+		append_ref(av, revkey, NULL);
 		return;
 	}
 	if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) {
@@ -495,7 +495,7 @@ static void append_one_rev(const char *a
 		int saved_matches = ref_name_cnt;
 		match_ref_pattern = av;
 		match_ref_slash = count_slash(av);
-		for_each_ref(append_matching_ref);
+		for_each_ref(append_matching_ref, NULL);
 		if (saved_matches == ref_name_cnt &&
 		    ref_name_cnt < MAX_REVS)
 			error("no matching refs with %s", av);
diff --git a/describe.c b/describe.c
index ab192f8..ea0f2ce 100644
--- a/describe.c
+++ b/describe.c
@@ -53,7 +53,7 @@ static void add_to_known_names(const cha
 	names = ++idx;
 }
 
-static int get_name(const char *path, const unsigned char *sha1)
+static int get_name(const char *path, const unsigned char *sha1, void *cb_data)
 {
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 	struct object *object;
@@ -113,7 +113,7 @@ static void describe(const char *arg, in
 
 	if (!initialized) {
 		initialized = 1;
-		for_each_ref(get_name);
+		for_each_ref(get_name, NULL);
 		qsort(name_array, names, sizeof(*name_array), compare_names);
 	}
 
diff --git a/fetch-pack.c b/fetch-pack.c
index e8708aa..6264ea1 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -42,7 +42,7 @@ static void rev_list_push(struct commit 
 	}
 }
 
-static int rev_list_insert_ref(const char *path, const unsigned char *sha1)
+static int rev_list_insert_ref(const char *path, const unsigned char *sha1, void *cb_data)
 {
 	struct object *o = deref_tag(parse_object(sha1), path, 0);
 
@@ -143,7 +143,7 @@ static int find_common(int fd[2], unsign
 	unsigned in_vain = 0;
 	int got_continue = 0;
 
-	for_each_ref(rev_list_insert_ref);
+	for_each_ref(rev_list_insert_ref, NULL);
 
 	fetching = 0;
 	for ( ; refs ; refs = refs->next) {
@@ -253,7 +253,7 @@ done:
 
 static struct commit_list *complete;
 
-static int mark_complete(const char *path, const unsigned char *sha1)
+static int mark_complete(const char *path, const unsigned char *sha1, void *cb_data)
 {
 	struct object *o = parse_object(sha1);
 
@@ -365,7 +365,7 @@ static int everything_local(struct ref *
 		}
 	}
 
-	for_each_ref(mark_complete);
+	for_each_ref(mark_complete, NULL);
 	if (cutoff)
 		mark_recent_complete_commits(cutoff);
 
diff --git a/fetch.c b/fetch.c
index 34df8d3..36d1e76 100644
--- a/fetch.c
+++ b/fetch.c
@@ -201,7 +201,7 @@ static int interpret_target(char *target
 	return -1;
 }
 
-static int mark_complete(const char *path, const unsigned char *sha1)
+static int mark_complete(const char *path, const unsigned char *sha1, void *cb_data)
 {
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 	if (commit) {
@@ -274,7 +274,7 @@ int pull(int targets, char **target, con
 	}
 
 	if (!get_recover)
-		for_each_ref(mark_complete);
+		for_each_ref(mark_complete, NULL);
 
 	for (i = 0; i < targets; i++) {
 		if (interpret_target(target[i], &sha1[20 * i])) {
diff --git a/fsck-objects.c b/fsck-objects.c
index 456c17e..bb0c94e 100644
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -402,7 +402,7 @@ static void fsck_dir(int i, char *path)
 
 static int default_refs;
 
-static int fsck_handle_ref(const char *refname, const unsigned char *sha1)
+static int fsck_handle_ref(const char *refname, const unsigned char *sha1, void *cb_data)
 {
 	struct object *obj;
 
@@ -424,7 +424,7 @@ static int fsck_handle_ref(const char *r
 
 static void get_default_heads(void)
 {
-	for_each_ref(fsck_handle_ref);
+	for_each_ref(fsck_handle_ref, NULL);
 
 	/*
 	 * Not having any default heads isn't really fatal, but
diff --git a/http-push.c b/http-push.c
index 670ff00..460c9be 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1864,7 +1864,7 @@ static int update_remote(unsigned char *
 static struct ref *local_refs, **local_tail;
 static struct ref *remote_refs, **remote_tail;
 
-static int one_local_ref(const char *refname, const unsigned char *sha1)
+static int one_local_ref(const char *refname, const unsigned char *sha1, void *cb_data)
 {
 	struct ref *ref;
 	int len = strlen(refname) + 1;
@@ -1913,7 +1913,7 @@ static void one_remote_ref(char *refname
 static void get_local_heads(void)
 {
 	local_tail = &local_refs;
-	for_each_ref(one_local_ref);
+	for_each_ref(one_local_ref, NULL);
 }
 
 static void get_dav_remote_heads(void)
diff --git a/receive-pack.c b/receive-pack.c
index 78f75da..7abc921 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -12,7 +12,7 @@ static int report_status;
 static char capabilities[] = "report-status";
 static int capabilities_sent;
 
-static int show_ref(const char *path, const unsigned char *sha1)
+static int show_ref(const char *path, const unsigned char *sha1, void *cb_data)
 {
 	if (capabilities_sent)
 		packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
@@ -25,9 +25,9 @@ static int show_ref(const char *path, co
 
 static void write_head_info(void)
 {
-	for_each_ref(show_ref);
+	for_each_ref(show_ref, NULL);
 	if (!capabilities_sent)
-		show_ref("capabilities^{}", null_sha1);
+		show_ref("capabilities^{}", null_sha1, NULL);
 
 }
 
diff --git a/refs.c b/refs.c
index 7bd36e4..85564f0 100644
--- a/refs.c
+++ b/refs.c
@@ -275,7 +275,7 @@ int read_ref(const char *ref, unsigned c
 	return -1;
 }
 
-static int do_for_each_ref(const char *base, int (*fn)(const char *path, const unsigned char *sha1), int trim)
+static int do_for_each_ref(const char *base, each_ref_fn fn, int trim, void *cb_data)
 {
 	int retval;
 	struct ref_list *packed = get_packed_refs();
@@ -303,7 +303,7 @@ static int do_for_each_ref(const char *b
 			error("%s does not point to a valid object!", entry->name);
 			continue;
 		}
-		retval = fn(entry->name + trim, entry->sha1);
+		retval = fn(entry->name + trim, entry->sha1, cb_data);
 		if (retval)
 			return retval;
 	}
@@ -311,7 +311,7 @@ static int do_for_each_ref(const char *b
 	packed = packed ? packed : loose;
 	while (packed) {
 		if (!strncmp(base, packed->name, trim)) {
-			retval = fn(packed->name + trim, packed->sha1);
+			retval = fn(packed->name + trim, packed->sha1, cb_data);
 			if (retval)
 				return retval;
 		}
@@ -320,34 +320,39 @@ static int do_for_each_ref(const char *b
 	return 0;
 }
 
-int head_ref(int (*fn)(const char *path, const unsigned char *sha1))
+int head_ref(each_ref_fn fn, void *cb_data)
 {
 	unsigned char sha1[20];
 	if (!read_ref("HEAD", sha1))
-		return fn("HEAD", sha1);
+		return fn("HEAD", sha1, cb_data);
 	return 0;
 }
 
-int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1))
+int for_each_ref(each_ref_fn fn, void *cb_data)
 {
-	return do_for_each_ref("refs/", fn, 0);
+	return do_for_each_ref("refs/", fn, 0, cb_data);
 }
 
-int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1))
+int for_each_tag_ref(each_ref_fn fn, void *cb_data)
 {
-	return do_for_each_ref("refs/tags/", fn, 10);
+	return do_for_each_ref("refs/tags/", fn, 10, cb_data);
 }
 
-int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1))
+int for_each_branch_ref(each_ref_fn fn, void *cb_data)
 {
-	return do_for_each_ref("refs/heads/", fn, 11);
+	return do_for_each_ref("refs/heads/", fn, 11, cb_data);
 }
 
-int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1))
+int for_each_remote_ref(each_ref_fn fn, void *cb_data)
 {
-	return do_for_each_ref("refs/remotes/", fn, 13);
+	return do_for_each_ref("refs/remotes/", fn, 13, cb_data);
 }
 
+/* NEEDSWORK: This is only used by ssh-upload and it should go; the
+ * caller should do resolve_ref or read_ref like everybody else.  Or
+ * maybe everybody else should use get_ref_sha1() instead of doing
+ * read_ref().
+ */
 int get_ref_sha1(const char *ref, unsigned char *sha1)
 {
 	if (check_ref_format(ref))
diff --git a/refs.h b/refs.h
index af347e6..886c857 100644
--- a/refs.h
+++ b/refs.h
@@ -14,11 +14,12 @@ struct ref_lock {
  * Calls the specified function for each ref file until it returns nonzero,
  * and returns the value
  */
-extern int head_ref(int (*fn)(const char *path, const unsigned char *sha1));
-extern int for_each_ref(int (*fn)(const char *path, const unsigned char *sha1));
-extern int for_each_tag_ref(int (*fn)(const char *path, const unsigned char *sha1));
-extern int for_each_branch_ref(int (*fn)(const char *path, const unsigned char *sha1));
-extern int for_each_remote_ref(int (*fn)(const char *path, const unsigned char *sha1));
+typedef int each_ref_fn(const char *refname, const unsigned char *sha1, void *cb_data);
+extern int head_ref(each_ref_fn, void *);
+extern int for_each_ref(each_ref_fn, void *);
+extern int for_each_tag_ref(each_ref_fn, void *);
+extern int for_each_branch_ref(each_ref_fn, void *);
+extern int for_each_remote_ref(each_ref_fn, void *);
 
 /** Reads the refs file specified into sha1 **/
 extern int get_ref_sha1(const char *ref, unsigned char *sha1);
diff --git a/revision.c b/revision.c
index 6a2539b..0e84b8a 100644
--- a/revision.c
+++ b/revision.c
@@ -466,7 +466,7 @@ static void limit_list(struct rev_info *
 static int all_flags;
 static struct rev_info *all_revs;
 
-static int handle_one_ref(const char *path, const unsigned char *sha1)
+static int handle_one_ref(const char *path, const unsigned char *sha1, void *cb_data)
 {
 	struct object *object = get_reference(all_revs, path, sha1, all_flags);
 	add_pending_object(all_revs, object, "");
@@ -477,7 +477,7 @@ static void handle_all(struct rev_info *
 {
 	all_revs = revs;
 	all_flags = flags;
-	for_each_ref(handle_one_ref);
+	for_each_ref(handle_one_ref, NULL);
 }
 
 static int add_parents_only(struct rev_info *revs, const char *arg, int flags)
diff --git a/send-pack.c b/send-pack.c
index 5bb123a..ee13093 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -215,7 +215,7 @@ static int ref_newer(const unsigned char
 static struct ref *local_refs, **local_tail;
 static struct ref *remote_refs, **remote_tail;
 
-static int one_local_ref(const char *refname, const unsigned char *sha1)
+static int one_local_ref(const char *refname, const unsigned char *sha1, void *cb_data)
 {
 	struct ref *ref;
 	int len = strlen(refname) + 1;
@@ -230,7 +230,7 @@ static int one_local_ref(const char *ref
 static void get_local_heads(void)
 {
 	local_tail = &local_refs;
-	for_each_ref(one_local_ref);
+	for_each_ref(one_local_ref, NULL);
 }
 
 static int receive_status(int in)
diff --git a/server-info.c b/server-info.c
index 2fb8f57..7667b41 100644
--- a/server-info.c
+++ b/server-info.c
@@ -7,7 +7,7 @@ #include "tag.h"
 /* refs */
 static FILE *info_ref_fp;
 
-static int add_info_ref(const char *path, const unsigned char *sha1)
+static int add_info_ref(const char *path, const unsigned char *sha1, void *cb_data)
 {
 	struct object *o = parse_object(sha1);
 
@@ -34,7 +34,7 @@ static int update_info_refs(int force)
 	info_ref_fp = fopen(path1, "w");
 	if (!info_ref_fp)
 		return error("unable to update %s", path0);
-	for_each_ref(add_info_ref);
+	for_each_ref(add_info_ref, NULL);
 	fclose(info_ref_fp);
 	rename(path1, path0);
 	free(path0);
diff --git a/upload-pack.c b/upload-pack.c
index 189b239..10237eb 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -416,7 +416,7 @@ static void receive_needs(void)
 	}
 }
 
-static int send_ref(const char *refname, const unsigned char *sha1)
+static int send_ref(const char *refname, const unsigned char *sha1, void *cb_data)
 {
 	static const char *capabilities = "multi_ack thin-pack side-band side-band-64k";
 	struct object *o = parse_object(sha1);
@@ -444,8 +444,8 @@ static int send_ref(const char *refname,
 static void upload_pack(void)
 {
 	reset_timeout();
-	head_ref(send_ref);
-	for_each_ref(send_ref);
+	head_ref(send_ref, NULL);
+	for_each_ref(send_ref, NULL);
 	packet_flush(1);
 	receive_needs();
 	if (want_obj.nr) {
-- 
1.4.2.1.g4dc7

^ permalink raw reply related

* [PATCH 4/5] pack-refs: do not pack symbolic refs.
From: Junio C Hamano @ 2006-09-21  7:06 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7v64fhd7ns.fsf@assigned-by-dhcp.cox.net>

Now we can tell which one is symbolic and which one is not, it
is easy to do so.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 builtin-pack-refs.c |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c
index 9871089..0fc8a55 100644
--- a/builtin-pack-refs.c
+++ b/builtin-pack-refs.c
@@ -14,7 +14,9 @@ static int handle_one_ref(const char *pa
 {
 	FILE *refs_file = cb_data;
 
-	fprintf(refs_file, "%s %s\n", sha1_to_hex(sha1), path);
+	/* Do not pack the symbolic refs */
+	if (!(flags & REF_ISSYMREF))
+		fprintf(refs_file, "%s %s\n", sha1_to_hex(sha1), path);
 	return 0;
 }
 
-- 
1.4.2.1.g4dc7

^ permalink raw reply related

* [PATCH 3/5] Tell between packed, unpacked and symbolic refs.
From: Junio C Hamano @ 2006-09-21  7:06 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7v64fhd7ns.fsf@assigned-by-dhcp.cox.net>

This adds a "int *flag" parameter to resolve_ref() and makes
for_each_ref() family to call callback function with an extra
"int flag" parameter.  They are used to give two bits of
information (REF_ISSYMREF and REF_ISPACKED) about the ref.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 builtin-fmt-merge-msg.c |    2 +-
 builtin-name-rev.c      |    2 +-
 builtin-pack-refs.c     |    3 ++-
 builtin-prune.c         |    2 +-
 builtin-push.c          |    2 +-
 builtin-rev-parse.c     |    2 +-
 builtin-show-branch.c   |   22 +++++++++++-----------
 builtin-symbolic-ref.c  |    6 +++++-
 cache.h                 |    2 +-
 describe.c              |    2 +-
 fetch-pack.c            |    4 ++--
 fetch.c                 |    2 +-
 fsck-objects.c          |    7 ++++---
 http-push.c             |    2 +-
 receive-pack.c          |    4 ++--
 refs.c                  |   44 +++++++++++++++++++++++++++++++-------------
 refs.h                  |    4 +++-
 revision.c              |    2 +-
 send-pack.c             |    2 +-
 server-info.c           |    2 +-
 sha1_name.c             |    2 +-
 upload-pack.c           |    2 +-
 wt-status.c             |    2 +-
 23 files changed, 75 insertions(+), 49 deletions(-)

diff --git a/builtin-fmt-merge-msg.c b/builtin-fmt-merge-msg.c
index b93c17c..3d3097d 100644
--- a/builtin-fmt-merge-msg.c
+++ b/builtin-fmt-merge-msg.c
@@ -277,7 +277,7 @@ int cmd_fmt_merge_msg(int argc, const ch
 		usage(fmt_merge_msg_usage);
 
 	/* get current branch */
-	current_branch = resolve_ref("HEAD", head_sha1, 1);
+	current_branch = resolve_ref("HEAD", head_sha1, 1, NULL);
 	if (!strncmp(current_branch, "refs/heads/", 11))
 		current_branch += 11;
 
diff --git a/builtin-name-rev.c b/builtin-name-rev.c
index 9e3e537..618aa31 100644
--- a/builtin-name-rev.c
+++ b/builtin-name-rev.c
@@ -75,7 +75,7 @@ copy_data:
 	}
 }
 
-static int name_ref(const char *path, const unsigned char *sha1, void *cb_data)
+static int name_ref(const char *path, const unsigned char *sha1, int flags, void *cb_data)
 {
 	struct object *o = parse_object(sha1);
 	int tags_only = *(int*)cb_data;
diff --git a/builtin-pack-refs.c b/builtin-pack-refs.c
index b3d5470..9871089 100644
--- a/builtin-pack-refs.c
+++ b/builtin-pack-refs.c
@@ -9,7 +9,8 @@ static void remove_lock_file(void)
 		unlink(lock_path);
 }
 
-static int handle_one_ref(const char *path, const unsigned char *sha1, void *cb_data)
+static int handle_one_ref(const char *path, const unsigned char *sha1,
+			  int flags, void *cb_data)
 {
 	FILE *refs_file = cb_data;
 
diff --git a/builtin-prune.c b/builtin-prune.c
index e21c29b..e79b515 100644
--- a/builtin-prune.c
+++ b/builtin-prune.c
@@ -174,7 +174,7 @@ static void walk_commit_list(struct rev_
 	}
 }
 
-static int add_one_ref(const char *path, const unsigned char *sha1, void *cb_data)
+static int add_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct object *object = parse_object(sha1);
 	if (!object)
diff --git a/builtin-push.c b/builtin-push.c
index 88fc8e2..581c44b 100644
--- a/builtin-push.c
+++ b/builtin-push.c
@@ -27,7 +27,7 @@ static void add_refspec(const char *ref)
 	refspec_nr = nr;
 }
 
-static int expand_one_ref(const char *ref, const unsigned char *sha1, void *cb_data)
+static int expand_one_ref(const char *ref, const unsigned char *sha1, int flag, void *cb_data)
 {
 	/* Ignore the "refs/" at the beginning of the refname */
 	ref += 5;
diff --git a/builtin-rev-parse.c b/builtin-rev-parse.c
index c771274..3b716fb 100644
--- a/builtin-rev-parse.c
+++ b/builtin-rev-parse.c
@@ -137,7 +137,7 @@ static void show_default(void)
 	}
 }
 
-static int show_reference(const char *refname, const unsigned char *sha1, void *cb_data)
+static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
 	show_rev(NORMAL, sha1, refname);
 	return 0;
diff --git a/builtin-show-branch.c b/builtin-show-branch.c
index b3548ae..5d6ce56 100644
--- a/builtin-show-branch.c
+++ b/builtin-show-branch.c
@@ -346,7 +346,7 @@ static void sort_ref_range(int bottom, i
 	      compare_ref_name);
 }
 
-static int append_ref(const char *refname, const unsigned char *sha1, void *cb_data)
+static int append_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 	int i;
@@ -369,7 +369,7 @@ static int append_ref(const char *refnam
 	return 0;
 }
 
-static int append_head_ref(const char *refname, const unsigned char *sha1, void *cb_data)
+static int append_head_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
 	unsigned char tmp[20];
 	int ofs = 11;
@@ -380,14 +380,14 @@ static int append_head_ref(const char *r
 	 */
 	if (get_sha1(refname + ofs, tmp) || hashcmp(tmp, sha1))
 		ofs = 5;
-	return append_ref(refname + ofs, sha1, cb_data);
+	return append_ref(refname + ofs, sha1, flag, cb_data);
 }
 
-static int append_tag_ref(const char *refname, const unsigned char *sha1, void *cb_data)
+static int append_tag_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
 	if (strncmp(refname, "refs/tags/", 10))
 		return 0;
-	return append_ref(refname + 5, sha1, cb_data);
+	return append_ref(refname + 5, sha1, flag, cb_data);
 }
 
 static const char *match_ref_pattern = NULL;
@@ -401,7 +401,7 @@ static int count_slash(const char *s)
 	return cnt;
 }
 
-static int append_matching_ref(const char *refname, const unsigned char *sha1, void *cb_data)
+static int append_matching_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
 	/* we want to allow pattern hold/<asterisk> to show all
 	 * branches under refs/heads/hold/, and v0.99.9? to show
@@ -417,10 +417,10 @@ static int append_matching_ref(const cha
 	if (fnmatch(match_ref_pattern, tail, 0))
 		return 0;
 	if (!strncmp("refs/heads/", refname, 11))
-		return append_head_ref(refname, sha1, cb_data);
+		return append_head_ref(refname, sha1, flag, cb_data);
 	if (!strncmp("refs/tags/", refname, 10))
-		return append_tag_ref(refname, sha1, cb_data);
-	return append_ref(refname, sha1, cb_data);
+		return append_tag_ref(refname, sha1, flag, cb_data);
+	return append_ref(refname, sha1, flag, cb_data);
 }
 
 static void snarf_refs(int head, int tag)
@@ -487,7 +487,7 @@ static void append_one_rev(const char *a
 {
 	unsigned char revkey[20];
 	if (!get_sha1(av, revkey)) {
-		append_ref(av, revkey, NULL);
+		append_ref(av, revkey, 0, NULL);
 		return;
 	}
 	if (strchr(av, '*') || strchr(av, '?') || strchr(av, '[')) {
@@ -630,7 +630,7 @@ int cmd_show_branch(int ac, const char *
 		ac--; av++;
 	}
 
-	head_p = resolve_ref("HEAD", head_sha1, 1);
+	head_p = resolve_ref("HEAD", head_sha1, 1, NULL);
 	if (head_p) {
 		head_len = strlen(head_p);
 		memcpy(head, head_p, head_len + 1);
diff --git a/builtin-symbolic-ref.c b/builtin-symbolic-ref.c
index 13163ba..d8be052 100644
--- a/builtin-symbolic-ref.c
+++ b/builtin-symbolic-ref.c
@@ -1,5 +1,6 @@
 #include "builtin.h"
 #include "cache.h"
+#include "refs.h"
 
 static const char git_symbolic_ref_usage[] =
 "git-symbolic-ref name [ref]";
@@ -7,10 +8,13 @@ static const char git_symbolic_ref_usage
 static void check_symref(const char *HEAD)
 {
 	unsigned char sha1[20];
-	const char *refs_heads_master = resolve_ref(HEAD, sha1, 0);
+	int flag;
+	const char *refs_heads_master = resolve_ref(HEAD, sha1, 0, &flag);
 
 	if (!refs_heads_master)
 		die("No such ref: %s", HEAD);
+	else if (!(flag & REF_ISSYMREF))
+		die("ref %s is not a symbolic ref", HEAD);
 	puts(refs_heads_master);
 }
 
diff --git a/cache.h b/cache.h
index 282eed6..6def155 100644
--- a/cache.h
+++ b/cache.h
@@ -286,7 +286,7 @@ extern int get_sha1(const char *str, uns
 extern int get_sha1_hex(const char *hex, unsigned char *sha1);
 extern char *sha1_to_hex(const unsigned char *sha1);	/* static buffer result! */
 extern int read_ref(const char *filename, unsigned char *sha1);
-extern const char *resolve_ref(const char *path, unsigned char *sha1, int);
+extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);
 extern int create_symref(const char *ref, const char *refs_heads_master);
 extern int validate_symref(const char *ref);
 
diff --git a/describe.c b/describe.c
index ea0f2ce..f4029ee 100644
--- a/describe.c
+++ b/describe.c
@@ -53,7 +53,7 @@ static void add_to_known_names(const cha
 	names = ++idx;
 }
 
-static int get_name(const char *path, const unsigned char *sha1, void *cb_data)
+static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 	struct object *object;
diff --git a/fetch-pack.c b/fetch-pack.c
index 6264ea1..99ac08b 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -42,7 +42,7 @@ static void rev_list_push(struct commit 
 	}
 }
 
-static int rev_list_insert_ref(const char *path, const unsigned char *sha1, void *cb_data)
+static int rev_list_insert_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct object *o = deref_tag(parse_object(sha1), path, 0);
 
@@ -253,7 +253,7 @@ done:
 
 static struct commit_list *complete;
 
-static int mark_complete(const char *path, const unsigned char *sha1, void *cb_data)
+static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct object *o = parse_object(sha1);
 
diff --git a/fetch.c b/fetch.c
index 36d1e76..a2cbdfb 100644
--- a/fetch.c
+++ b/fetch.c
@@ -201,7 +201,7 @@ static int interpret_target(char *target
 	return -1;
 }
 
-static int mark_complete(const char *path, const unsigned char *sha1, void *cb_data)
+static int mark_complete(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct commit *commit = lookup_commit_reference_gently(sha1, 1);
 	if (commit) {
diff --git a/fsck-objects.c b/fsck-objects.c
index bb0c94e..46b628c 100644
--- a/fsck-objects.c
+++ b/fsck-objects.c
@@ -402,7 +402,7 @@ static void fsck_dir(int i, char *path)
 
 static int default_refs;
 
-static int fsck_handle_ref(const char *refname, const unsigned char *sha1, void *cb_data)
+static int fsck_handle_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct object *obj;
 
@@ -458,9 +458,10 @@ static void fsck_object_dir(const char *
 static int fsck_head_link(void)
 {
 	unsigned char sha1[20];
-	const char *head_points_at = resolve_ref("HEAD", sha1, 1);
+	int flag;
+	const char *head_points_at = resolve_ref("HEAD", sha1, 1, &flag);
 
-	if (!head_points_at)
+	if (!head_points_at || !(flag & REF_ISSYMREF))
 		return error("HEAD is not a symbolic ref");
 	if (strncmp(head_points_at, "refs/heads/", 11))
 		return error("HEAD points to something strange (%s)",
diff --git a/http-push.c b/http-push.c
index 460c9be..ecefdfd 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1864,7 +1864,7 @@ static int update_remote(unsigned char *
 static struct ref *local_refs, **local_tail;
 static struct ref *remote_refs, **remote_tail;
 
-static int one_local_ref(const char *refname, const unsigned char *sha1, void *cb_data)
+static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct ref *ref;
 	int len = strlen(refname) + 1;
diff --git a/receive-pack.c b/receive-pack.c
index 7abc921..abbcb6a 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -12,7 +12,7 @@ static int report_status;
 static char capabilities[] = "report-status";
 static int capabilities_sent;
 
-static int show_ref(const char *path, const unsigned char *sha1, void *cb_data)
+static int show_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
 	if (capabilities_sent)
 		packet_write(1, "%s %s\n", sha1_to_hex(sha1), path);
@@ -27,7 +27,7 @@ static void write_head_info(void)
 {
 	for_each_ref(show_ref, NULL);
 	if (!capabilities_sent)
-		show_ref("capabilities^{}", null_sha1, NULL);
+		show_ref("capabilities^{}", null_sha1, 0, NULL);
 
 }
 
diff --git a/refs.c b/refs.c
index 85564f0..40f16af 100644
--- a/refs.c
+++ b/refs.c
@@ -5,6 +5,7 @@ #include <errno.h>
 
 struct ref_list {
 	struct ref_list *next;
+	unsigned char flag; /* ISSYMREF? ISPACKED? */
 	unsigned char sha1[20];
 	char name[FLEX_ARRAY];
 };
@@ -36,7 +37,8 @@ static const char *parse_ref_line(char *
 	return line;
 }
 
-static struct ref_list *add_ref(const char *name, const unsigned char *sha1, struct ref_list *list)
+static struct ref_list *add_ref(const char *name, const unsigned char *sha1,
+				int flag, struct ref_list *list)
 {
 	int len;
 	struct ref_list **p = &list, *entry;
@@ -58,6 +60,7 @@ static struct ref_list *add_ref(const ch
 	entry = xmalloc(sizeof(struct ref_list) + len);
 	hashcpy(entry->sha1, sha1);
 	memcpy(entry->name, name, len);
+	entry->flag = flag;
 	entry->next = *p;
 	*p = entry;
 	return list;
@@ -78,7 +81,7 @@ static struct ref_list *get_packed_refs(
 				const char *name = parse_ref_line(refline, sha1);
 				if (!name)
 					continue;
-				list = add_ref(name, sha1, list);
+				list = add_ref(name, sha1, REF_ISPACKED, list);
 			}
 			fclose(f);
 			refs = list;
@@ -104,6 +107,7 @@ static struct ref_list *get_ref_dir(cons
 		while ((de = readdir(dir)) != NULL) {
 			unsigned char sha1[20];
 			struct stat st;
+			int flag;
 			int namelen;
 
 			if (de->d_name[0] == '.')
@@ -120,11 +124,11 @@ static struct ref_list *get_ref_dir(cons
 				list = get_ref_dir(ref, list);
 				continue;
 			}
-			if (read_ref(ref, sha1) < 0) {
+			if (!resolve_ref(ref, sha1, 1, &flag)) {
 				error("%s points nowhere!", ref);
 				continue;
 			}
-			list = add_ref(ref, sha1, list);
+			list = add_ref(ref, sha1, flag, list);
 		}
 		free(ref);
 		closedir(dir);
@@ -147,12 +151,15 @@ static struct ref_list *get_loose_refs(v
 /* We allow "recursive" symbolic refs. Only within reason, though */
 #define MAXDEPTH 5
 
-const char *resolve_ref(const char *ref, unsigned char *sha1, int reading)
+const char *resolve_ref(const char *ref, unsigned char *sha1, int reading, int *flag)
 {
 	int depth = MAXDEPTH, len;
 	char buffer[256];
 	static char ref_buffer[256];
 
+	if (flag)
+		*flag = 0;
+
 	for (;;) {
 		const char *path = git_path("%s", ref);
 		struct stat st;
@@ -174,6 +181,8 @@ const char *resolve_ref(const char *ref,
 			while (list) {
 				if (!strcmp(ref, list->name)) {
 					hashcpy(sha1, list->sha1);
+					if (flag)
+						*flag |= REF_ISPACKED;
 					return ref;
 				}
 				list = list->next;
@@ -191,6 +200,8 @@ const char *resolve_ref(const char *ref,
 				buffer[len] = 0;
 				strcpy(ref_buffer, buffer);
 				ref = ref_buffer;
+				if (flag)
+					*flag |= REF_ISSYMREF;
 				continue;
 			}
 		}
@@ -219,6 +230,8 @@ const char *resolve_ref(const char *ref,
 		buf[len] = 0;
 		memcpy(ref_buffer, buf, len + 1);
 		ref = ref_buffer;
+		if (flag)
+			*flag |= REF_ISSYMREF;
 	}
 	if (len < 40 || get_sha1_hex(buffer, sha1))
 		return NULL;
@@ -270,12 +283,13 @@ #endif
 
 int read_ref(const char *ref, unsigned char *sha1)
 {
-	if (resolve_ref(ref, sha1, 1))
+	if (resolve_ref(ref, sha1, 1, NULL))
 		return 0;
 	return -1;
 }
 
-static int do_for_each_ref(const char *base, each_ref_fn fn, int trim, void *cb_data)
+static int do_for_each_ref(const char *base, each_ref_fn fn, int trim,
+			   void *cb_data)
 {
 	int retval;
 	struct ref_list *packed = get_packed_refs();
@@ -303,7 +317,8 @@ static int do_for_each_ref(const char *b
 			error("%s does not point to a valid object!", entry->name);
 			continue;
 		}
-		retval = fn(entry->name + trim, entry->sha1, cb_data);
+		retval = fn(entry->name + trim, entry->sha1,
+			    entry->flag, cb_data);
 		if (retval)
 			return retval;
 	}
@@ -311,7 +326,8 @@ static int do_for_each_ref(const char *b
 	packed = packed ? packed : loose;
 	while (packed) {
 		if (!strncmp(base, packed->name, trim)) {
-			retval = fn(packed->name + trim, packed->sha1, cb_data);
+			retval = fn(packed->name + trim, packed->sha1,
+				    packed->flag, cb_data);
 			if (retval)
 				return retval;
 		}
@@ -323,8 +339,10 @@ static int do_for_each_ref(const char *b
 int head_ref(each_ref_fn fn, void *cb_data)
 {
 	unsigned char sha1[20];
-	if (!read_ref("HEAD", sha1))
-		return fn("HEAD", sha1, cb_data);
+	int flag;
+
+	if (resolve_ref("HEAD", sha1, 1, &flag))
+		return fn("HEAD", sha1, flag, cb_data);
 	return 0;
 }
 
@@ -415,7 +433,7 @@ int check_ref_format(const char *ref)
 static struct ref_lock *verify_lock(struct ref_lock *lock,
 	const unsigned char *old_sha1, int mustexist)
 {
-	if (!resolve_ref(lock->ref_name, lock->old_sha1, mustexist)) {
+	if (!resolve_ref(lock->ref_name, lock->old_sha1, mustexist, NULL)) {
 		error("Can't verify ref %s", lock->ref_name);
 		unlock_ref(lock);
 		return NULL;
@@ -441,7 +459,7 @@ static struct ref_lock *lock_ref_sha1_ba
 	lock = xcalloc(1, sizeof(struct ref_lock));
 	lock->lock_fd = -1;
 
-	ref = resolve_ref(ref, lock->old_sha1, mustexist);
+	ref = resolve_ref(ref, lock->old_sha1, mustexist, NULL);
 	if (!ref) {
 		int last_errno = errno;
 		error("unable to resolve reference %s: %s",
diff --git a/refs.h b/refs.h
index 886c857..305d408 100644
--- a/refs.h
+++ b/refs.h
@@ -14,7 +14,9 @@ struct ref_lock {
  * Calls the specified function for each ref file until it returns nonzero,
  * and returns the value
  */
-typedef int each_ref_fn(const char *refname, const unsigned char *sha1, void *cb_data);
+#define REF_ISSYMREF 01
+#define REF_ISPACKED 02
+typedef int each_ref_fn(const char *refname, const unsigned char *sha1, int flags, void *cb_data);
 extern int head_ref(each_ref_fn, void *);
 extern int for_each_ref(each_ref_fn, void *);
 extern int for_each_tag_ref(each_ref_fn, void *);
diff --git a/revision.c b/revision.c
index 0e84b8a..cb13b90 100644
--- a/revision.c
+++ b/revision.c
@@ -466,7 +466,7 @@ static void limit_list(struct rev_info *
 static int all_flags;
 static struct rev_info *all_revs;
 
-static int handle_one_ref(const char *path, const unsigned char *sha1, void *cb_data)
+static int handle_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct object *object = get_reference(all_revs, path, sha1, all_flags);
 	add_pending_object(all_revs, object, "");
diff --git a/send-pack.c b/send-pack.c
index ee13093..fbd792c 100644
--- a/send-pack.c
+++ b/send-pack.c
@@ -215,7 +215,7 @@ static int ref_newer(const unsigned char
 static struct ref *local_refs, **local_tail;
 static struct ref *remote_refs, **remote_tail;
 
-static int one_local_ref(const char *refname, const unsigned char *sha1, void *cb_data)
+static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct ref *ref;
 	int len = strlen(refname) + 1;
diff --git a/server-info.c b/server-info.c
index 7667b41..6cd38be 100644
--- a/server-info.c
+++ b/server-info.c
@@ -7,7 +7,7 @@ #include "tag.h"
 /* refs */
 static FILE *info_ref_fp;
 
-static int add_info_ref(const char *path, const unsigned char *sha1, void *cb_data)
+static int add_info_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data)
 {
 	struct object *o = parse_object(sha1);
 
diff --git a/sha1_name.c b/sha1_name.c
index b497528..84d24c6 100644
--- a/sha1_name.c
+++ b/sha1_name.c
@@ -276,7 +276,7 @@ static int get_sha1_basic(const char *st
 
 	for (p = fmt; *p; p++) {
 		this_result = refs_found ? sha1_from_ref : sha1;
-		ref = resolve_ref(mkpath(*p, len, str), this_result, 1);
+		ref = resolve_ref(mkpath(*p, len, str), this_result, 1, NULL);
 		if (ref) {
 			if (!refs_found++)
 				real_ref = xstrdup(ref);
diff --git a/upload-pack.c b/upload-pack.c
index 10237eb..9412a9b 100644
--- a/upload-pack.c
+++ b/upload-pack.c
@@ -416,7 +416,7 @@ static void receive_needs(void)
 	}
 }
 
-static int send_ref(const char *refname, const unsigned char *sha1, void *cb_data)
+static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
 {
 	static const char *capabilities = "multi_ack thin-pack side-band side-band-64k";
 	struct object *o = parse_object(sha1);
diff --git a/wt-status.c b/wt-status.c
index 050922d..d8e284c 100644
--- a/wt-status.c
+++ b/wt-status.c
@@ -41,7 +41,7 @@ void wt_status_prepare(struct wt_status 
 
 	s->is_initial = get_sha1("HEAD", sha1) ? 1 : 0;
 
-	head = resolve_ref("HEAD", sha1, 0);
+	head = resolve_ref("HEAD", sha1, 0, NULL);
 	s->branch = head ? xstrdup(head) : NULL;
 
 	s->reference = "HEAD";
-- 
1.4.2.1.g4dc7

^ permalink raw reply related

* [PATCH 1/5] symbolit-ref: fix resolve_ref conversion.
From: Junio C Hamano @ 2006-09-21  7:06 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <7v64fhd7ns.fsf@assigned-by-dhcp.cox.net>

An earlier conversion accidentally hardcoded "HEAD" to be passed to
resolve_ref(), thereby causing git-symbolic-ref command to always
report where the HEAD points at, ignoring the command line parameter.

Signed-off-by: Junio C Hamano <junkio@cox.net>
---
 builtin-symbolic-ref.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/builtin-symbolic-ref.c b/builtin-symbolic-ref.c
index 6f18db8..13163ba 100644
--- a/builtin-symbolic-ref.c
+++ b/builtin-symbolic-ref.c
@@ -7,7 +7,7 @@ static const char git_symbolic_ref_usage
 static void check_symref(const char *HEAD)
 {
 	unsigned char sha1[20];
-	const char *refs_heads_master = resolve_ref("HEAD", sha1, 0);
+	const char *refs_heads_master = resolve_ref(HEAD, sha1, 0);
 
 	if (!refs_heads_master)
 		die("No such ref: %s", HEAD);
-- 
1.4.2.1.g4dc7

^ permalink raw reply related

* Re: [RFC] git-pack-refs --prune
From: Junio C Hamano @ 2006-09-21  7:02 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0609180934360.4388@g5.osdl.org>

Linus Torvalds <torvalds@osdl.org> writes:

> On Mon, 18 Sep 2006, Junio C Hamano wrote:
>> 
>> I am not sure I got the locking right, hence this RFC.
>
> It looks correct (the important part to check is that the SHA1 of the ref 
> you remove still matches the SHA1 of the object you packed).
>
> That said, we should fix it up a bit, notably
>
>  - we should _not_ prune refs that are indirect.
>
>  - we should probably avoid even trying to prune stuff that was already 
>    packed.
>
> The way to fix both these problems at once would be to add a flag to the 
> "for_each_ref()", which says whether it followed a link, or whether it was 
> already packed, so that we wouldn't pack symlinks at all, and we wouldn't 
> add already-packed refs to the "keeprefs" list.
>
> But that requires a sligh semantic extension to "do_for_each_ref()" (and 
> "struct ref_list" needs a flag to say whether it was looked up through a 
> symlink).

Ok, so I did these and the result is a 4-patch series.

^ permalink raw reply

* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Junio C Hamano @ 2006-09-21  6:43 UTC (permalink / raw)
  To: Jeff King; +Cc: git
In-Reply-To: <20060921055252.GA29479@coredump.intra.peff.net>

Jeff King <peff@peff.net> writes:

>>     X - a - b - c - Y
>>   /           /
>> o - d - e - f
>
> In your example, git-merge-base X Y returns X. In fact, I could only get
> one merge base out of git-merge-base --all. I tried looking in the tests
> to find a case that produced multiple merge bases, but I was unable to
> find one. Is there an example floating around somewhere?

There are quite a few in git.git itself.  In the recent history,
this counts 42, the answer to everything.

#!/bin/sh
LF='
'
git rev-list --parents master..next |
while read it p1 p2 octo
do
	case "$p2" in '') continue ;; esac
        mb=`git merge-base --all "$p1" "$p2"`
	case "$mb" in ?*"$LF"?*) echo "$p1 $p2" : $mb ;;
        esac
done

^ permalink raw reply

* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Junio C Hamano @ 2006-09-21  6:26 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0609210208350.19042@wbgn013.biozentrum.uni-wuerzburg.de>

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
> index f3694ac..6be3c80 100755
> --- a/t/t5400-send-pack.sh
> +++ b/t/t5400-send-pack.sh
> @@ -64,4 +64,14 @@ test_expect_success \
>  	cmp victim/.git/refs/heads/master .git/refs/heads/master
>  '
>  
> +test_expect_success \
> +        'pushing with --force should be denied with denyNonFastforwards' '
> +	cd victim &&
> +	git-repo-config receive.denyNonFastforwards true &&
> +	cd .. &&
> +	git-update-ref refs/heads/master master^ &&
> +	git-send-pack --force ./victim/.git/ master &&
> +	! diff -u .git/refs/heads/master victim/.git/refs/heads/master
> +'
> +
>  test_done

The change shown by "git -SGIT_CONFIG -p t/Makefile" seems to
interfere with this test.  When I run it from shell by hand it
works OK, but when I run it like this:

	cd t && make T=t5400*.sh

it barfs.  s/git-send-pack/strace -f git-send-pack/ seems to
indicate that the receiving end is trying to open .git/config
(rightly, because you told it to do so three months ago ;-)
while its $cwd is victim/.git and fails to read the setting you
are trying to test.  Not good.

I think the change to t/Makefile from 9c3796fc needs to be
rethought.  Most of the tests would be fine with .git/config
(they never step outside t/trash/.git repository), but others
need tweaking, including unsetting it (while unsetting HOME at
the same time perhaps when you do not want to be affected).
Also it may make sense to do the default setting of GIT_CONFIG
in t/test-lib.sh, with a prominent warning why we explicitly
set it to a known value.

In the meantime, I got things working with this patch on top of
your test update.

---

diff --git a/t/t5400-send-pack.sh b/t/t5400-send-pack.sh
index 6be3c80..be47ee2 100755
--- a/t/t5400-send-pack.sh
+++ b/t/t5400-send-pack.sh
@@ -64,6 +64,10 @@ test_expect_success \
 	cmp victim/.git/refs/heads/master .git/refs/heads/master
 '
 
+unset GIT_CONFIG GIT_CONFIG_LOCAL
+HOME=`pwd`/no-such-directory
+export HOME ;# this way we force the victim/.git/config to be used.
+
 test_expect_success \
         'pushing with --force should be denied with denyNonFastforwards' '
 	cd victim &&

^ permalink raw reply related

* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Jeff King @ 2006-09-21  5:52 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.63.0609210211570.19042@wbgn013.biozentrum.uni-wuerzburg.de>

On Thu, Sep 21, 2006 at 02:17:22AM +0200, Johannes Schindelin wrote:

> So we indeed assumed that git-merge-base returns the old commit in the 
> case of a fast-forward (git-merge-base returns just the first item of the 
> result of get_merge_bases()).
> 
> Note that I have no proof that this assumption is true. It might be wrong 
> in this case:
> 
>     X - a - b - c - Y
>   /           /
> o - d - e - f

In your example, git-merge-base X Y returns X. In fact, I could only get
one merge base out of git-merge-base --all. I tried looking in the tests
to find a case that produced multiple merge bases, but I was unable to
find one. Is there an example floating around somewhere?

-Peff

^ permalink raw reply

* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Junio C Hamano @ 2006-09-21  5:35 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0609210206320.19042@wbgn013.biozentrum.uni-wuerzburg.de>

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> On Wed, 20 Sep 2006, Jeff King wrote:
>
>> Memory leak on 'bases'. It shouldn't matter much because the program is
>> short-lived, but I couldn't remember if we have a policy on such things
>> with increasing lib-ification.
>
> True. How about this:
>
> -- snip --
>
> +		backup = get_merge_bases(old_commit, new_commit, 1);
> +		for (bases = backup;
>  				bases; bases = bases->next)
>  			if (!hashcmp(old_sha1, bases->item->object.sha1))
>  				break;
>  		if (!bases)
>  			return error("denying non-fast forward;"
>  					" you should pull first");
> +		free_commit_list(backup);

Still leaking on the error path ;-).

Will fixup and apply; no need to resend.

^ permalink raw reply

* Re: [PATCH 0/6] packed deltas with offset to base instead of sha1
From: Junio C Hamano @ 2006-09-21  5:30 UTC (permalink / raw)
  To: Nicolas Pitre; +Cc: git, Shawn Pearce
In-Reply-To: <Pine.LNX.4.64.0609202350450.2627@xanadu.home>

Nicolas Pitre <nico@cam.org> writes:

> The following patches are the result of my work to allow deltas to have
> their base specified as an offset within a pack instead of a 20 byte 
> sha1.
>
> This turned to be somewhat more involved than I originally expected. 
> Given the relative pack reduction resulting from that, I might have 
> decided against doing this if I had known beforehand how much work was 
> needed.
>
> But since it is done now I think it is worth merging nevertheless.  Some 
> parts are still pure code cleanups anyway.
>
> Overall the larger projects are likely to benefit more as they have a 
> larger proportion of deltas.  On the historic Linux archive the pack 
> reduction is about 5%.

Nice, although I suspect this would make it a bit more involved
to merge a few outstanding stuff.

Will take a look when I'm done looking at Linus's packed-ref
stuff.

^ permalink raw reply

* Re: pseudo initial empty commit and tag for git-log and git-describe?
From: Nguyễn Thái Ngọc Duy @ 2006-09-21  5:23 UTC (permalink / raw)
  To: Matthias Kestenholz; +Cc: git
In-Reply-To: <1158761400.6516.25.camel@localhost.localdomain>

On 9/20/06, Matthias Kestenholz <lists@spinlock.ch> wrote:
> hello
> you can use git log -p --root  to also display the root commit.
Thanks. I didn't know about --root.
-- 
Duy

^ permalink raw reply

* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Junio C Hamano @ 2006-09-21  5:08 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0609210211570.19042@wbgn013.biozentrum.uni-wuerzburg.de>

Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:

> On Wed, 20 Sep 2006, Junio C Hamano wrote:
>
>> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>> 
>> > 	No longer barfs on new refs, and tries all merge bases (even if I
>> > 	cannot come up with any scenario where there is more than one merge
>> > 	base in the case of a fast forward).
>> 
>> Hmm.  If that is the case (and I think it is although I haven't
>> come up with a proof),
>
> From git-fetch.sh:
>
>             # Require fast-forward.
>             mb=$(git-merge-base "$local" "$2") &&
>...
> So we indeed assumed that git-merge-base returns the old commit in the 
> case of a fast-forward (git-merge-base returns just the first item of the 
> result of get_merge_bases()).

I think this was leftover from the days we naïvely assumed that
multiple bases does not matter, and probably needs updating.

> Note that I have no proof that this assumption is true. It might be wrong 
> in this case:
>
>     X - a - b - c - Y
>   /           /
> o - d - e - f
>
> where X is the old commit, and Y is the new commit. But I am too tired to 
> test it right now.

^ permalink raw reply

* [PATCH 1/6] move pack creation to version 3
From: Nicolas Pitre @ 2006-09-21  4:11 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

It's been quite a while now that GIT is able to read version 3 packs.
Let's create them at last.

Signed-off-by: Nicolas Pitre <nico@cam.org>

diff --git a/diff-delta.c b/diff-delta.c
index fa16d06..51df460 100644
--- a/diff-delta.c
+++ b/diff-delta.c
@@ -308,8 +308,8 @@ create_delta(const struct delta_index *i
 				continue;
 			if (ref_size > top - src)
 				ref_size = top - src;
-			if (ref_size > 0x10000)
-				ref_size = 0x10000;
+			if (ref_size > 0xffffff)
+				ref_size = 0xffffff;
 			if (ref_size <= msize)
 				break;
 			while (ref_size-- && *src++ == *ref)
@@ -318,6 +318,8 @@ create_delta(const struct delta_index *i
 				/* this is our best match so far */
 				msize = ref - entry->ptr;
 				moff = entry->ptr - ref_data;
+				if (msize >= 0x10000)
+					break;  /* this is good enough */
 			}
 		}
 
@@ -381,6 +383,8 @@ create_delta(const struct delta_index *i
 			if (msize & 0xff) { out[outpos++] = msize; i |= 0x10; }
 			msize >>= 8;
 			if (msize & 0xff) { out[outpos++] = msize; i |= 0x20; }
+			msize >>= 8;
+			if (msize & 0xff) { out[outpos++] = msize; i |= 0x40; }
 
 			*op = i;
 		}
diff --git a/pack.h b/pack.h
index eb07b03..05557da 100644
--- a/pack.h
+++ b/pack.h
@@ -7,7 +7,7 @@ #include "object.h"
  * Packed object header
  */
 #define PACK_SIGNATURE 0x5041434b	/* "PACK" */
-#define PACK_VERSION 2
+#define PACK_VERSION 3
 #define pack_version_ok(v) ((v) == htonl(2) || (v) == htonl(3))
 struct pack_header {
 	unsigned int hdr_signature;

^ permalink raw reply related

* [PATCH 6/6] make git-pack-objects able to create deltas with offset to base
From: Nicolas Pitre @ 2006-09-21  4:09 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


This is enabled with --delta-base-offset only, and doesn't work with
pack data reuse yet.

The idea is to allow for the fetch protocol to use an extension flag
to notify the remote end that --delta-base-offset can be used with
git-pack-objects. Eventually git-repack will always provide this flag.

With this, all delta base objects are now pushed before deltas that depend
on them.  This is a requirements for OBJ_OFS_DELTA.  This is not a
requirement for OBJ_REF_DELTA but always doing so makes the code simpler.

Signed-off-by: Nicolas Pitre <nico@cam.org>

---

Delta data reuse is possible, of course, but that will come through a
separate patch.  I need to think about it some more in order to implement
it as efficiently as possible.  The issue is to get back to the
corresponding object entry given an object offset in an existing pack.

I guess I could use the pack offset to find the corresponding sha1 in the pack
index, and then use locate_object_entry_hash(), but that would require a pack
index sorted by offset to be efficient... which means yet more memory usage.
Well, I need to look at that revindex more closely I guess...

diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index c62734a..ec57536 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -60,6 +60,8 @@ static int non_empty;
 static int no_reuse_delta;
 static int local;
 static int incremental;
+static int allow_ofs_delta;
+
 static struct object_entry **sorted_by_sha, **sorted_by_type;
 static struct object_entry *objects;
 static int nr_objects, nr_alloc, nr_result;
@@ -334,9 +336,6 @@ static unsigned long write_object(struct
 	enum object_type obj_type;
 	int to_reuse = 0;
 
-	if (entry->preferred_base)
-		return 0;
-
 	obj_type = entry->type;
 	if (! entry->in_pack)
 		to_reuse = 0;	/* can't reuse what we don't have */
@@ -380,18 +379,35 @@ static unsigned long write_object(struct
 		if (entry->delta) {
 			buf = delta_against(buf, size, entry);
 			size = entry->delta_size;
-			obj_type = OBJ_REF_DELTA;
+			obj_type = (allow_ofs_delta && entry->delta->offset) ?
+				OBJ_OFS_DELTA : OBJ_REF_DELTA;
 		}
 		/*
 		 * The object header is a byte of 'type' followed by zero or
-		 * more bytes of length.  For deltas, the 20 bytes of delta
-		 * sha1 follows that.
+		 * more bytes of length.
 		 */
 		hdrlen = encode_header(obj_type, size, header);
 		sha1write(f, header, hdrlen);
 
-		if (entry->delta) {
-			sha1write(f, entry->delta, 20);
+		if (obj_type == OBJ_OFS_DELTA) {
+			/*
+			 * Deltas with relative base contain an additional
+			 * encoding of the relative offset for the delta
+			 * base from this object's position in the pack.
+			 */
+			unsigned long ofs = entry->offset - entry->delta->offset;
+			unsigned pos = sizeof(header) - 1;
+			header[pos] = ofs & 127;
+			while (ofs >>= 7)
+				header[--pos] = 128 | (--ofs & 127);
+			sha1write(f, header + pos, sizeof(header) - pos);
+			hdrlen += sizeof(header) - pos;
+		} else if (obj_type == OBJ_REF_DELTA) {
+			/*
+			 * Deltas with a base reference contain
+			 * an additional 20 bytes for the base sha1.
+			 */
+			sha1write(f, entry->delta->sha1, 20);
 			hdrlen += 20;
 		}
 		datalen = sha1write_compressed(f, buf, size);
@@ -413,7 +429,7 @@ static unsigned long write_object(struct
 			reused_delta++;
 		reused++;
 	}
-	if (obj_type == OBJ_REF_DELTA)
+	if (entry->delta)
 		written_delta++;
 	written++;
 	return hdrlen + datalen;
@@ -423,17 +439,16 @@ static unsigned long write_one(struct sh
 			       struct object_entry *e,
 			       unsigned long offset)
 {
-	if (e->offset)
+	if (e->offset || e->preferred_base)
 		/* offset starts from header size and cannot be zero
 		 * if it is written already.
 		 */
 		return offset;
-	e->offset = offset;
-	offset += write_object(f, e);
-	/* if we are deltified, write out its base object. */
+	/* if we are deltified, write out its base object first. */
 	if (e->delta)
 		offset = write_one(f, e->delta, offset);
-	return offset;
+	e->offset = offset;
+	return offset + write_object(f, e);
 }
 
 static void write_pack_file(void)
@@ -1484,6 +1499,10 @@ int cmd_pack_objects(int argc, const cha
 			no_reuse_delta = 1;
 			continue;
 		}
+		if (!strcmp("--delta-base-offset", arg)) {
+			allow_ofs_delta = no_reuse_delta = 1;
+			continue;
+		}
 		if (!strcmp("--stdout", arg)) {
 			pack_to_stdout = 1;
 			continue;

^ permalink raw reply related

* [PATCH 5/6] teach git-index-pack about deltas with offset to base
From: Nicolas Pitre @ 2006-09-21  4:08 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git


Signed-off-by: Nicolas Pitre <nico@cam.org>

diff --git a/index-pack.c b/index-pack.c
index aef7f0a..fffddd2 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -18,10 +18,15 @@ struct object_entry
 	unsigned char sha1[20];
 };
 
+union delta_base {
+	unsigned char sha1[20];
+	unsigned long offset;
+};
+
 struct delta_entry
 {
 	struct object_entry *obj;
-	unsigned char base_sha1[20];
+	union delta_base base;
 };
 
 static const char *pack_name;
@@ -134,13 +139,13 @@ static void *unpack_entry_data(unsigned 
 static void *unpack_raw_entry(unsigned long offset,
 			      enum object_type *obj_type,
 			      unsigned long *obj_size,
-			      unsigned char *delta_base,
+			      union delta_base *delta_base,
 			      unsigned long *next_obj_offset)
 {
 	unsigned long pack_limit = pack_size - 20;
 	unsigned long pos = offset;
 	unsigned char c;
-	unsigned long size;
+	unsigned long size, base_offset;
 	unsigned shift;
 	enum object_type type;
 	void *data;
@@ -161,26 +166,43 @@ static void *unpack_raw_entry(unsigned l
 	case OBJ_REF_DELTA:
 		if (pos + 20 >= pack_limit)
 			bad_object(offset, "object extends past end of pack");
-		hashcpy(delta_base, pack_base + pos);
+		hashcpy(delta_base->sha1, pack_base + pos);
 		pos += 20;
-		/* fallthru */
+		break;
+	case OBJ_OFS_DELTA:
+		memset(delta_base, 0, sizeof(*delta_base));
+		c = pack_base[pos++];
+		base_offset = c & 127;
+		while (c & 128) {
+			base_offset += 1;
+			if (!base_offset || base_offset & ~(~0UL >> 7))
+				bad_object(offset, "offset value overflow for delta base object");
+			if (pos >= pack_limit)
+				bad_object(offset, "object extends past end of pack");
+			c = pack_base[pos++];
+			base_offset = (base_offset << 7) + (c & 127);
+		}
+		delta_base->offset = offset - base_offset;
+		if (delta_base->offset >= offset)
+			bad_object(offset, "delta base offset is out of bound");
+		break;
 	case OBJ_COMMIT:
 	case OBJ_TREE:
 	case OBJ_BLOB:
 	case OBJ_TAG:
-		data = unpack_entry_data(offset, &pos, size);
 		break;
 	default:
 		bad_object(offset, "bad object type %d", type);
 	}
 
+	data = unpack_entry_data(offset, &pos, size);
 	*obj_type = type;
 	*obj_size = size;
 	*next_obj_offset = pos;
 	return data;
 }
 
-static int find_delta(const unsigned char *base_sha1)
+static int find_delta(const union delta_base *base)
 {
 	int first = 0, last = nr_deltas;
 
@@ -189,7 +211,7 @@ static int find_delta(const unsigned cha
                 struct delta_entry *delta = &deltas[next];
                 int cmp;
 
-                cmp = hashcmp(base_sha1, delta->base_sha1);
+                cmp = memcmp(base, &delta->base, sizeof(*base));
                 if (!cmp)
                         return next;
                 if (cmp < 0) {
@@ -201,18 +223,18 @@ static int find_delta(const unsigned cha
         return -first-1;
 }
 
-static int find_deltas_based_on_sha1(const unsigned char *base_sha1,
-				     int *first_index, int *last_index)
+static int find_delta_childs(const union delta_base *base,
+			     int *first_index, int *last_index)
 {
-	int first = find_delta(base_sha1);
+	int first = find_delta(base);
 	int last = first;
 	int end = nr_deltas - 1;
 
 	if (first < 0)
 		return -1;
-	while (first > 0 && !hashcmp(deltas[first - 1].base_sha1, base_sha1))
+	while (first > 0 && !memcmp(&deltas[first - 1].base, base, sizeof(*base)))
 		--first;
-	while (last < end && !hashcmp(deltas[last + 1].base_sha1, base_sha1))
+	while (last < end && !memcmp(&deltas[last + 1].base, base, sizeof(*base)))
 		++last;
 	*first_index = first;
 	*last_index = last;
@@ -253,13 +275,13 @@ static void resolve_delta(struct delta_e
 	void *result;
 	unsigned long result_size;
 	enum object_type delta_type;
-	unsigned char base_sha1[20];
+	union delta_base delta_base;
 	unsigned long next_obj_offset;
 	int j, first, last;
 
 	obj->real_type = type;
 	delta_data = unpack_raw_entry(obj->offset, &delta_type,
-				      &delta_size, base_sha1,
+				      &delta_size, &delta_base,
 				      &next_obj_offset);
 	result = patch_delta(base_data, base_size, delta_data, delta_size,
 			     &result_size);
@@ -267,10 +289,22 @@ static void resolve_delta(struct delta_e
 	if (!result)
 		bad_object(obj->offset, "failed to apply delta");
 	sha1_object(result, result_size, type, obj->sha1);
-	if (!find_deltas_based_on_sha1(obj->sha1, &first, &last)) {
+
+	hashcpy(delta_base.sha1, obj->sha1);
+	if (!find_delta_childs(&delta_base, &first, &last)) {
 		for (j = first; j <= last; j++)
-			resolve_delta(&deltas[j], result, result_size, type);
+			if (deltas[j].obj->type == OBJ_REF_DELTA)
+				resolve_delta(&deltas[j], result, result_size, type);
 	}
+
+	memset(&delta_base, 0, sizeof(delta_base));
+	delta_base.offset = obj->offset;
+	if (!find_delta_childs(&delta_base, &first, &last)) {
+		for (j = first; j <= last; j++)
+			if (deltas[j].obj->type == OBJ_OFS_DELTA)
+				resolve_delta(&deltas[j], result, result_size, type);
+	}
+
 	free(result);
 }
 
@@ -278,14 +312,14 @@ static int compare_delta_entry(const voi
 {
 	const struct delta_entry *delta_a = a;
 	const struct delta_entry *delta_b = b;
-	return hashcmp(delta_a->base_sha1, delta_b->base_sha1);
+	return memcmp(&delta_a->base, &delta_b->base, sizeof(union delta_base));
 }
 
 static void parse_pack_objects(void)
 {
 	int i;
 	unsigned long offset = sizeof(struct pack_header);
-	unsigned char base_sha1[20];
+	struct delta_entry *delta = deltas;
 	void *data;
 	unsigned long data_size;
 
@@ -299,12 +333,12 @@ static void parse_pack_objects(void)
 		struct object_entry *obj = &objects[i];
 		obj->offset = offset;
 		data = unpack_raw_entry(offset, &obj->type, &data_size,
-					base_sha1, &offset);
+					&delta->base, &offset);
 		obj->real_type = obj->type;
-		if (obj->type == OBJ_REF_DELTA) {
-			struct delta_entry *delta = &deltas[nr_deltas++];
+		if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA) {
+			nr_deltas++;
 			delta->obj = obj;
-			hashcpy(delta->base_sha1, base_sha1);
+			delta++;
 		} else
 			sha1_object(data, data_size, obj->type, obj->sha1);
 		free(data);
@@ -312,7 +346,7 @@ static void parse_pack_objects(void)
 	if (offset != pack_size - 20)
 		die("packfile '%s' has junk at the end", pack_name);
 
-	/* Sort deltas by base SHA1 for fast searching */
+	/* Sort deltas by base SHA1/offset for fast searching */
 	qsort(deltas, nr_deltas, sizeof(struct delta_entry),
 	      compare_delta_entry);
 
@@ -326,22 +360,37 @@ static void parse_pack_objects(void)
 	 */
 	for (i = 0; i < nr_objects; i++) {
 		struct object_entry *obj = &objects[i];
-		int j, first, last;
+		union delta_base base;
+		int j, ref, ref_first, ref_last, ofs, ofs_first, ofs_last;
 
-		if (obj->type == OBJ_REF_DELTA)
+		if (obj->type == OBJ_REF_DELTA || obj->type == OBJ_OFS_DELTA)
 			continue;
-		if (find_deltas_based_on_sha1(obj->sha1, &first, &last))
+		hashcpy(base.sha1, obj->sha1);
+		ref = !find_delta_childs(&base, &ref_first, &ref_last);
+		memset(&base, 0, sizeof(base));
+		base.offset = obj->offset;
+		ofs = !find_delta_childs(&base, &ofs_first, &ofs_last);
+		if (!ref && !ofs)
 			continue;
 		data = unpack_raw_entry(obj->offset, &obj->type, &data_size,
-					base_sha1, &offset);
-		for (j = first; j <= last; j++)
-			resolve_delta(&deltas[j], data, data_size, obj->type);
+					&base, &offset);
+		if (ref)
+			for (j = ref_first; j <= ref_last; j++)
+				if (deltas[j].obj->type == OBJ_REF_DELTA)
+					resolve_delta(&deltas[j], data,
+						      data_size, obj->type);
+		if (ofs)
+			for (j = ofs_first; j <= ofs_last; j++)
+				if (deltas[j].obj->type == OBJ_OFS_DELTA)
+					resolve_delta(&deltas[j], data,
+						      data_size, obj->type);
 		free(data);
 	}
 
 	/* Check for unresolved deltas */
 	for (i = 0; i < nr_deltas; i++) {
-		if (deltas[i].obj->real_type == OBJ_REF_DELTA)
+		if (deltas[i].obj->real_type == OBJ_REF_DELTA ||
+		    deltas[i].obj->real_type == OBJ_OFS_DELTA)
 			die("packfile '%s' has unresolved deltas",  pack_name);
 	}
 }

^ permalink raw reply related

* [PATCH 4/6] teach git-unpack-objects about deltas with offset to base
From: Nicolas Pitre @ 2006-09-21  4:07 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

For delta resolution to be possible, a list of sha1/offset tupple must
be constructed in memory in order to load the appropriate base object.

Signed-off-by: Nicolas Pitre <nico@cam.org>

diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c
index c6c6368..e70a711 100644
--- a/builtin-unpack-objects.c
+++ b/builtin-unpack-objects.c
@@ -15,7 +15,7 @@ static const char unpack_usage[] = "git-
 
 /* We always read in 4kB chunks. */
 static unsigned char buffer[4096];
-static unsigned long offset, len;
+static unsigned long offset, len, consumed_bytes;
 static SHA_CTX ctx;
 
 /*
@@ -51,6 +51,7 @@ static void use(int bytes)
 		die("used more bytes than were available");
 	len -= bytes;
 	offset += bytes;
+	consumed_bytes += bytes;
 }
 
 static void *get_data(unsigned long size)
@@ -89,35 +90,49 @@ static void *get_data(unsigned long size
 
 struct delta_info {
 	unsigned char base_sha1[20];
+	unsigned long base_offset;
 	unsigned long size;
 	void *delta;
+	unsigned nr;
 	struct delta_info *next;
 };
 
 static struct delta_info *delta_list;
 
-static void add_delta_to_list(unsigned char *base_sha1, void *delta, unsigned long size)
+static void add_delta_to_list(unsigned nr, unsigned const char *base_sha1,
+			      unsigned long base_offset,
+			      void *delta, unsigned long size)
 {
 	struct delta_info *info = xmalloc(sizeof(*info));
 
 	hashcpy(info->base_sha1, base_sha1);
+	info->base_offset = base_offset;
 	info->size = size;
 	info->delta = delta;
+	info->nr = nr;
 	info->next = delta_list;
 	delta_list = info;
 }
 
-static void added_object(unsigned char *sha1, const char *type, void *data, unsigned long size);
+struct obj_info {
+	unsigned long offset;
+	unsigned char sha1[20];
+};
+
+static struct obj_info *obj_list;
 
-static void write_object(void *buf, unsigned long size, const char *type)
+static void added_object(unsigned nr, const char *type, void *data,
+			 unsigned long size);
+
+static void write_object(unsigned nr, void *buf, unsigned long size,
+			 const char *type)
 {
-	unsigned char sha1[20];
-	if (write_sha1_file(buf, size, type, sha1) < 0)
+	if (write_sha1_file(buf, size, type, obj_list[nr].sha1) < 0)
 		die("failed to write object");
-	added_object(sha1, type, buf, size);
+	added_object(nr, type, buf, size);
 }
 
-static void resolve_delta(const char *type,
+static void resolve_delta(unsigned nr, const char *type,
 			  void *base, unsigned long base_size,
 			  void *delta, unsigned long delta_size)
 {
@@ -130,20 +145,23 @@ static void resolve_delta(const char *ty
 	if (!result)
 		die("failed to apply delta");
 	free(delta);
-	write_object(result, result_size, type);
+	write_object(nr, result, result_size, type);
 	free(result);
 }
 
-static void added_object(unsigned char *sha1, const char *type, void *data, unsigned long size)
+static void added_object(unsigned nr, const char *type, void *data,
+			 unsigned long size)
 {
 	struct delta_info **p = &delta_list;
 	struct delta_info *info;
 
 	while ((info = *p) != NULL) {
-		if (!hashcmp(info->base_sha1, sha1)) {
+		if (!hashcmp(info->base_sha1, obj_list[nr].sha1) ||
+		    info->base_offset == obj_list[nr].offset) {
 			*p = info->next;
 			p = &delta_list;
-			resolve_delta(type, data, size, info->delta, info->size);
+			resolve_delta(info->nr, type, data, size,
+				      info->delta, info->size);
 			free(info);
 			continue;
 		}
@@ -151,7 +169,8 @@ static void added_object(unsigned char *
 	}
 }
 
-static void unpack_non_delta_entry(enum object_type kind, unsigned long size)
+static void unpack_non_delta_entry(enum object_type kind, unsigned long size,
+				   unsigned nr)
 {
 	void *buf = get_data(size);
 	const char *type;
@@ -164,30 +183,80 @@ static void unpack_non_delta_entry(enum 
 	default: die("bad type %d", kind);
 	}
 	if (!dry_run && buf)
-		write_object(buf, size, type);
+		write_object(nr, buf, size, type);
 	free(buf);
 }
 
-static void unpack_delta_entry(unsigned long delta_size)
+static void unpack_delta_entry(enum object_type kind, unsigned long delta_size,
+			       unsigned nr)
 {
 	void *delta_data, *base;
 	unsigned long base_size;
 	char type[20];
 	unsigned char base_sha1[20];
 
-	hashcpy(base_sha1, fill(20));
-	use(20);
+	if (kind == OBJ_REF_DELTA) {
+		hashcpy(base_sha1, fill(20));
+		use(20);
+		delta_data = get_data(delta_size);
+		if (dry_run || !delta_data) {
+			free(delta_data);
+			return;
+		}
+		if (!has_sha1_file(base_sha1)) {
+			hashcpy(obj_list[nr].sha1, null_sha1);
+			add_delta_to_list(nr, base_sha1, 0, delta_data, delta_size);
+			return;
+		}
+	} else {
+		unsigned base_found = 0;
+		unsigned char *pack, c;
+		unsigned long base_offset;
+		unsigned lo, mid, hi;
 
-	delta_data = get_data(delta_size);
-	if (dry_run || !delta_data) {
-		free(delta_data);
-		return;
-	}
+		pack = fill(1);
+		c = *pack;
+		use(1);
+		base_offset = c & 127;
+		while (c & 128) {
+			base_offset += 1;
+			if (!base_offset || base_offset & ~(~0UL >> 7))
+				die("offset value overflow for delta base object");
+			pack = fill(1);
+			c = *pack;
+			use(1);
+			base_offset = (base_offset << 7) + (c & 127);
+		}
+		base_offset = obj_list[nr].offset - base_offset;
 
-	if (!has_sha1_file(base_sha1)) {
-		add_delta_to_list(base_sha1, delta_data, delta_size);
-		return;
+		delta_data = get_data(delta_size);
+		if (dry_run || !delta_data) {
+			free(delta_data);
+			return;
+		}
+		lo = 0;
+		hi = nr;
+		while (lo < hi) {
+			mid = (lo + hi)/2;
+			if (base_offset < obj_list[mid].offset) {
+				hi = mid;
+			} else if (base_offset > obj_list[mid].offset) {
+				lo = mid + 1;
+			} else {
+				hashcpy(base_sha1, obj_list[mid].sha1);
+				base_found = !is_null_sha1(base_sha1);
+				break;
+			}
+		}
+		if (!base_found) {
+			/* The delta base object is itself a delta that
+			   has not been	resolved yet. */
+			hashcpy(obj_list[nr].sha1, null_sha1);
+			add_delta_to_list(nr, null_sha1, base_offset, delta_data, delta_size);
+			return;
+		}
 	}
+
 	base = read_sha1_file(base_sha1, type, &base_size);
 	if (!base) {
 		error("failed to read delta-pack base object %s",
@@ -197,7 +266,7 @@ static void unpack_delta_entry(unsigned 
 		has_errors = 1;
 		return;
 	}
-	resolve_delta(type, base, base_size, delta_data, delta_size);
+	resolve_delta(nr, type, base, base_size, delta_data, delta_size);
 	free(base);
 }
 
@@ -208,6 +277,8 @@ static void unpack_one(unsigned nr, unsi
 	unsigned long size;
 	enum object_type type;
 
+	obj_list[nr].offset = consumed_bytes;
+
 	pack = fill(1);
 	c = *pack;
 	use(1);
@@ -216,7 +287,7 @@ static void unpack_one(unsigned nr, unsi
 	shift = 4;
 	while (c & 0x80) {
 		pack = fill(1);
-		c = *pack++;
+		c = *pack;
 		use(1);
 		size += (c & 0x7f) << shift;
 		shift += 7;
@@ -225,13 +296,14 @@ static void unpack_one(unsigned nr, unsi
 		static unsigned long last_sec;
 		static unsigned last_percent;
 		struct timeval now;
-		unsigned percentage = (nr * 100) / total;
+		unsigned percentage = ((nr+1) * 100) / total;
 
 		gettimeofday(&now, NULL);
 		if (percentage != last_percent || now.tv_sec != last_sec) {
 			last_sec = now.tv_sec;
 			last_percent = percentage;
-			fprintf(stderr, "%4u%% (%u/%u) done\r", percentage, nr, total);
+			fprintf(stderr, "%4u%% (%u/%u) done\r",
+					percentage, (nr+1), total);
 		}
 	}
 	switch (type) {
@@ -239,10 +311,11 @@ static void unpack_one(unsigned nr, unsi
 	case OBJ_TREE:
 	case OBJ_BLOB:
 	case OBJ_TAG:
-		unpack_non_delta_entry(type, size);
+		unpack_non_delta_entry(type, size, nr);
 		return;
 	case OBJ_REF_DELTA:
-		unpack_delta_entry(size);
+	case OBJ_OFS_DELTA:
+		unpack_delta_entry(type, size, nr);
 		return;
 	default:
 		error("bad object type %d", type);
@@ -265,9 +338,10 @@ static void unpack_all(void)
 		die("unknown pack file version %d", ntohl(hdr->hdr_version));
 	fprintf(stderr, "Unpacking %d objects\n", nr_objects);
 
+	obj_list = xmalloc(nr_objects * sizeof(*obj_list));
 	use(sizeof(struct pack_header));
 	for (i = 0; i < nr_objects; i++)
-		unpack_one(i+1, nr_objects);
+		unpack_one(i, nr_objects);
 	if (delta_list)
 		die("unresolved deltas left after unpacking");
 }

^ 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