* Re: [PATCH] describe: fall back to 'HEAD' if no appropriate tag exists
From: Junio C Hamano @ 2006-09-20 22:46 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git, junkio
In-Reply-To: <Pine.LNX.4.63.0609202324210.19042@wbgn013.biozentrum.uni-wuerzburg.de>
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.
^ permalink raw reply
* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Shawn Pearce @ 2006-09-20 22:46 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Johannes Schindelin, git
In-Reply-To: <7vfyemf9ah.fsf@assigned-by-dhcp.cox.net>
Junio C Hamano <junkio@cox.net> wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> > If receive.denyNonFastforwards is set to true, git-receive-pack will deny
> > non fast-forwards, i.e. forced updates. Most notably, a push to a repository
> > which has that flag set to true will fail.
> >
> > As a first user, 'git-init-db --shared' sets this flag, since in a shared
> > setup, you are most unlikely to want forced pushes to succeed.
>
> I am Ok with the general idea, but ...
>
> > @@ -127,6 +129,16 @@ static int update(struct command *cmd)
> > return error("unpack should have generated %s, "
> > "but I can't find it!", new_hex);
> > }
> > + if (deny_non_fast_forwards) {
> > + struct commit *old_commit, *new_commit;
> > + old_commit = (struct commit *)parse_object(old_sha1);
> > + new_commit = (struct commit *)parse_object(new_sha1);
> > + struct commit_list *bases = get_merge_bases(old_commit,
> > + new_commit, 1);
> > + if (!bases || hashcmp(old_sha1, bases->item->object.sha1))
> > + return error("denying non-fast forward;"
> > + " you should pull first");
> > + }
> > safe_create_leading_directories(lock_name);
> >
> > newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
>
> I am wondering if there can be more than one base and the old_sha1
> is not returned as the first one.
Not to mention how does this work when the ref didn't exist?
Is this entire block of code being bypassed by something not show
in the context?
--
Shawn.
^ permalink raw reply
* Re: [PATCH] describe: fall back to 'HEAD' if no appropriate tag exists
From: Johannes Schindelin @ 2006-09-20 22:53 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7v8xkef97b.fsf@assigned-by-dhcp.cox.net>
Hi,
On Wed, 20 Sep 2006, 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.
>
> Another possibility is just to do
>
> puts(sha1_to_hex(cmit->object.sha1))
>
> in this case.
Okay. Could we have the abbreviated sha1, at least?
Ciao,
Dscho
^ permalink raw reply
* [PATCH] add receive.denyNonFastforwards config variable
From: Johannes Schindelin @ 2006-09-20 23:07 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Shawn Pearce
In-Reply-To: <7vfyemf9ah.fsf@assigned-by-dhcp.cox.net>
If receive.denyNonFastforwards is set to true, git-receive-pack will deny
non fast-forwards, i.e. forced updates. Most notably, a push to a repository
which has that flag set will fail.
As a first user, 'git-init-db --shared' sets this flag, since in a shared
setup, you are most unlikely to want forced pushes to succeed.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
2nd try.
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).
Also is C99.
builtin-init-db.c | 1 +
cache.h | 1 +
environment.c | 1 +
receive-pack.c | 16 ++++++++++++++++
setup.c | 2 ++
5 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/builtin-init-db.c b/builtin-init-db.c
index 36c3088..e6a2d7d 100644
--- a/builtin-init-db.c
+++ b/builtin-init-db.c
@@ -310,6 +310,7 @@ int cmd_init_db(int argc, const char **a
*/
sprintf(buf, "%d", shared_repository);
git_config_set("core.sharedrepository", buf);
+ git_config_set("receive.denyNonFastforwards", "true");
}
return 0;
diff --git a/cache.h b/cache.h
index f2fdc00..2224c83 100644
--- a/cache.h
+++ b/cache.h
@@ -188,6 +188,7 @@ extern int prefer_symlink_refs;
extern int log_all_ref_updates;
extern int warn_ambiguous_refs;
extern int shared_repository;
+extern int deny_non_fast_forwards;
extern const char *apply_default_whitespace;
extern int zlib_compression_level;
diff --git a/environment.c b/environment.c
index 84d870c..63b1d15 100644
--- a/environment.c
+++ b/environment.c
@@ -20,6 +20,7 @@ int warn_ambiguous_refs = 1;
int repository_format_version;
char git_commit_encoding[MAX_ENCODING_LENGTH] = "utf-8";
int shared_repository = PERM_UMASK;
+int deny_non_fast_forwards = 0;
const char *apply_default_whitespace;
int zlib_compression_level = Z_DEFAULT_COMPRESSION;
int pager_in_use;
diff --git a/receive-pack.c b/receive-pack.c
index 78f75da..a6ec9f9 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -2,6 +2,8 @@ #include "cache.h"
#include "refs.h"
#include "pkt-line.h"
#include "run-command.h"
+#include "commit.h"
+#include "object.h"
static const char receive_pack_usage[] = "git-receive-pack <git-dir>";
@@ -127,6 +129,20 @@ static int update(struct command *cmd)
return error("unpack should have generated %s, "
"but I can't find it!", new_hex);
}
+ if (deny_non_fast_forwards && !is_null_sha1(old_sha1)) {
+ struct commit *old_commit, *new_commit;
+ struct commit_list *bases;
+
+ old_commit = (struct commit *)parse_object(old_sha1);
+ new_commit = (struct commit *)parse_object(new_sha1);
+ for (bases = get_merge_bases(old_commit, new_commit, 1);
+ 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");
+ }
safe_create_leading_directories(lock_name);
newfd = open(lock_name, O_CREAT | O_EXCL | O_WRONLY, 0666);
diff --git a/setup.c b/setup.c
index 2afdba4..9a46a58 100644
--- a/setup.c
+++ b/setup.c
@@ -244,6 +244,8 @@ int check_repository_format_version(cons
repository_format_version = git_config_int(var, value);
else if (strcmp(var, "core.sharedrepository") == 0)
shared_repository = git_config_perm(var, value);
+ else if (strcmp(var, "receive.denynonfastforwards") == 0)
+ deny_non_fast_forwards = git_config_bool(var, value);
return 0;
}
--
1.4.2.1.g25e3-dirty
^ permalink raw reply related
* [PATCH] gitweb: Fix showing of path in tree view
From: Petr Baudis @ 2006-09-20 23:12 UTC (permalink / raw)
To: git
This patch fixes two things - links to all path elements except the last
one were broken since gitweb does not like the trailing slash in them, and
the root tree was not reachable from the subdirectory view.
To compensate for the one more slash in the front, the trailing slash is
not there anymore. ;-) I don't care if it stays there though.
Signed-off-by: Petr Baudis <pasky@suse.cz>
---
gitweb/gitweb.perl | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/gitweb/gitweb.perl b/gitweb/gitweb.perl
index 834a773..70f409e 100755
--- a/gitweb/gitweb.perl
+++ b/gitweb/gitweb.perl
@@ -1503,12 +1503,13 @@ sub git_print_page_path {
my $fullname = '';
print "<div class=\"page_path\">";
+ print $cgi->a({-href => href(action=>"tree", hash_base=>$hb),
+ -title => '/'}, '/');
foreach my $dir (@dirname) {
- $fullname .= $dir . '/';
+ $fullname .= ($fullname ? '/' : '') . $dir;
print $cgi->a({-href => href(action=>"tree", file_name=>$fullname,
hash_base=>$hb),
- -title => $fullname}, esc_html($dir));
- print "/";
+ -title => $fullname}, esc_html($dir . '/'));
}
if (defined $type && $type eq 'blob') {
print $cgi->a({-href => href(action=>"blob_plain", file_name=>$file_name,
@@ -1518,7 +1519,6 @@ sub git_print_page_path {
print $cgi->a({-href => href(action=>"tree", file_name=>$file_name,
hash_base=>$hb),
-title => $name}, esc_html($basename));
- print "/";
} else {
print esc_html($basename);
}
^ permalink raw reply related
* Re: git pull for update of netdev fails.
From: Krzysztof Halasa @ 2006-09-20 23:12 UTC (permalink / raw)
To: Shawn Pearce
Cc: Linus Torvalds, Petr Baudis, Stephen Hemminger, Jeff Garzik, git
In-Reply-To: <20060920165931.GE23260@spearce.org>
Shawn Pearce <spearce@spearce.org> writes:
> If only the shared repository had a way of advising clients that
> commits stored in ref 'BAAAD' may not survive and thus shouldn't
> be merged.
They could be merged for some temporary purposes, though (such
as compile/run tests). Merging isn't a problem, doing real
development on such material wouldn't be the best idea.
--
Krzysztof Halasa
^ permalink raw reply
* Re: [PATCH 2/2] gitweb: Make git_get_refs_list do work of git_get_references
From: Junio C Hamano @ 2006-09-20 23:14 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <200609210040.52886.jnareb@gmail.com>
Jakub Narebski <jnareb@gmail.com> writes:
> The %refs hash contain also map from peeled (dereferenced) object
> to ref name. The information about derefs is not present in @reflist.
> So the answer is that you can't derive %refs from @reflist.
There we found one candidate for further interface clean-up ;-).
^ permalink raw reply
* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Junio C Hamano @ 2006-09-20 23:19 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0609210107140.19042@wbgn013.biozentrum.uni-wuerzburg.de>
Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
> If receive.denyNonFastforwards is set to true, git-receive-pack will deny
> non fast-forwards, i.e. forced updates. Most notably, a push to a repository
> which has that flag set will fail.
>
> As a first user, 'git-init-db --shared' sets this flag, since in a shared
> setup, you are most unlikely to want forced pushes to succeed.
>
> Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Looks good. Care to do a handful more tasks before we forget?
Documentation/git-init-db.txt
Documentation/config.txt
Documentation/git-receive-pack.txt
t/t5400-send-pack.sh or a new test t/t5401-push-into-shared-repo.sh
^ permalink raw reply
* Re: [PATCH] gitweb: Fix showing of path in tree view
From: Junio C Hamano @ 2006-09-20 23:32 UTC (permalink / raw)
To: Petr Baudis; +Cc: git, Jakub Narebski
In-Reply-To: <20060920231224.GN13132@pasky.or.cz>
Petr Baudis <pasky@suse.cz> writes:
> This patch fixes two things - links to all path elements except the last
> one were broken since gitweb does not like the trailing slash in them, and
> the root tree was not reachable from the subdirectory view.
>
> To compensate for the one more slash in the front, the trailing slash is
> not there anymore. ;-) I don't care if it stays there though.
Hmph. I see the breakage and behaviour-wise your patch is fine.
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 ;-).
^ permalink raw reply
* Re: [PATCH] gitweb: Fix showing of path in tree view
From: Jakub Narebski @ 2006-09-20 23:35 UTC (permalink / raw)
To: git
In-Reply-To: <20060920231224.GN13132@pasky.or.cz>
Petr Baudis wrote:
> This patch fixes two things - links to all path elements except the last
> one were broken since gitweb does not like the trailing slash in them, and
> the root tree was not reachable from the subdirectory view.
>
> To compensate for the one more slash in the front, the trailing slash is
> not there anymore. ;-) I don't care if it stays there though.
Originally '/' was used as separator between directories making the path.
I'd rather use ' / ' to separate parts of pathname more, and not incorporate
it in the link.
Trailing (final) slash is present (and I think should be present) only
for path in "tree" view. From the path alone you can see if it is "tree"
or "blob" view.
--
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
^ permalink raw reply
* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Junio C Hamano @ 2006-09-20 23:38 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: git
In-Reply-To: <Pine.LNX.4.63.0609210107140.19042@wbgn013.biozentrum.uni-wuerzburg.de>
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), the test can be written like this:
if (bases && !bases->next &&
hashcmp(old_sha1, bases->item->object.sha1))
; /* happy */
else
return error("not a fast forward");
perhaps?
^ permalink raw reply
* Re: [PATCH] gitweb: Fix showing of path in tree view
From: Jakub Narebski @ 2006-09-20 23:38 UTC (permalink / raw)
To: git
In-Reply-To: <eesj84$qku$1@sea.gmane.org>
Jakub Narebski wrote:
> Petr Baudis wrote:
>
>> This patch fixes two things - links to all path elements except the last
>> one were broken since gitweb does not like the trailing slash in them, and
>> the root tree was not reachable from the subdirectory view.
>>
>> To compensate for the one more slash in the front, the trailing slash is
>> not there anymore. ;-) I don't care if it stays there though.
>
> Originally '/' was used as separator between directories making the path.
> I'd rather use ' / ' to separate parts of pathname more, and not incorporate
> it in the link.
>
> Trailing (final) slash is present (and I think should be present) only
> for path in "tree" view. From the path alone you can see if it is "tree"
> or "blob" view.
About link to root tree: we could change the commit title to link to root
tree instead of linking to commit view.
--
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
^ permalink raw reply
* Re: [PATCH] gitweb: Fix showing of path in tree view
From: Petr Baudis @ 2006-09-20 23:40 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Jakub Narebski
In-Reply-To: <7vpsdqdsh1.fsf@assigned-by-dhcp.cox.net>
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...
> Petr Baudis <pasky@suse.cz> writes:
>
> > This patch fixes two things - links to all path elements except the last
> > one were broken since gitweb does not like the trailing slash in them, and
> > the root tree was not reachable from the subdirectory view.
> >
> > To compensate for the one more slash in the front, the trailing slash is
> > not there anymore. ;-) I don't care if it stays there though.
>
> Hmph. I see the breakage and behaviour-wise your patch is fine.
>
> 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. :-)
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
$/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1
lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/)
^ permalink raw reply
* Re: [PATCH] gitweb: Fix showing of path in tree view
From: Petr Baudis @ 2006-09-20 23:43 UTC (permalink / raw)
To: Jakub Narebski; +Cc: git
In-Reply-To: <eesje4$qku$2@sea.gmane.org>
Dear diary, on Thu, Sep 21, 2006 at 01:38:49AM CEST, I got a letter
where Jakub Narebski <jnareb@gmail.com> said that...
> Jakub Narebski wrote:
> > Trailing (final) slash is present (and I think should be present) only
> > for path in "tree" view. From the path alone you can see if it is "tree"
> > or "blob" view.
Which sounds like a nice property but the rest of the page looks totally
different anyway, so I don't know how practical that is.
> About link to root tree: we could change the commit title to link to root
> tree instead of linking to commit view.
I don't think that makes any sense. It's a _commit_ title! :-) And if I
want to get to root tree it wouldn't occur to me to click _there_
anyway.
--
Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
#!/bin/perl -sp0777i<X+d*lMLa^*lN%0]dsXx++lMlN/dsM0<j]dsj
$/=unpack('H*',$_);$_=`echo 16dio\U$k"SK$/SM$n\EsN0p[lN*1
lK[d2%Sa2/d0$^Ixp"|dc`;s/\W//g;$_=pack('H*',/((..)*)$/)
^ permalink raw reply
* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Jeff King @ 2006-09-20 23:45 UTC (permalink / raw)
To: Johannes Schindelin; +Cc: Junio C Hamano, git, Shawn Pearce
In-Reply-To: <Pine.LNX.4.63.0609210107140.19042@wbgn013.biozentrum.uni-wuerzburg.de>
On Thu, Sep 21, 2006 at 01:07:54AM +0200, Johannes Schindelin wrote:
> + if (deny_non_fast_forwards && !is_null_sha1(old_sha1)) {
> + struct commit *old_commit, *new_commit;
> + struct commit_list *bases;
> +
> + old_commit = (struct commit *)parse_object(old_sha1);
> + new_commit = (struct commit *)parse_object(new_sha1);
> + for (bases = get_merge_bases(old_commit, new_commit, 1);
> + 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");
> + }
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.
-Peff
^ permalink raw reply
* Re: [PATCH] gitweb: Fix showing of path in tree view
From: Junio C Hamano @ 2006-09-20 23:51 UTC (permalink / raw)
To: Petr Baudis; +Cc: git, Jakub Narebski
In-Reply-To: <20060920234052.GO13132@pasky.or.cz>
Petr Baudis <pasky@suse.cz> writes:
>> Hmph. I see the breakage and behaviour-wise your patch is fine.
>>
>> 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. :-)
Ok, when I commented on it I did not realize that the leading
slash was clickable.
How about rendering it like this?
/ stgit/ commands/ mail.py
^ permalink raw reply
* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Johannes Schindelin @ 2006-09-21 0:07 UTC (permalink / raw)
To: Jeff King; +Cc: Junio C Hamano, git, Shawn Pearce
In-Reply-To: <20060920234548.GA20461@coredump.intra.peff.net>
On Wed, 20 Sep 2006, Jeff King wrote:
> On Thu, Sep 21, 2006 at 01:07:54AM +0200, Johannes Schindelin wrote:
>
> > + if (deny_non_fast_forwards && !is_null_sha1(old_sha1)) {
> > + struct commit *old_commit, *new_commit;
> > + struct commit_list *bases;
> > +
> > + old_commit = (struct commit *)parse_object(old_sha1);
> > + new_commit = (struct commit *)parse_object(new_sha1);
> > + for (bases = get_merge_bases(old_commit, new_commit, 1);
> > + 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");
> > + }
>
> 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 --
---
receive-pack.c | 6 ++++--
1 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/receive-pack.c b/receive-pack.c
index a6ec9f9..d84fc2c 100644
--- a/receive-pack.c
+++ b/receive-pack.c
@@ -131,17 +131,19 @@ static int update(struct command *cmd)
}
if (deny_non_fast_forwards && !is_null_sha1(old_sha1)) {
struct commit *old_commit, *new_commit;
- struct commit_list *bases;
+ struct commit_list *bases, *backup;
old_commit = (struct commit *)parse_object(old_sha1);
new_commit = (struct commit *)parse_object(new_sha1);
- for (bases = get_merge_bases(old_commit, new_commit, 1);
+ 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);
}
safe_create_leading_directories(lock_name);
--
1.4.2.1.g6ad2-dirty
^ permalink raw reply related
* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Johannes Schindelin @ 2006-09-21 0:10 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vzmcudt3t.fsf@assigned-by-dhcp.cox.net>
Hi,
On Wed, 20 Sep 2006, Junio C Hamano wrote:
> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:
>
> > If receive.denyNonFastforwards is set to true, git-receive-pack will deny
> > non fast-forwards, i.e. forced updates. Most notably, a push to a repository
> > which has that flag set will fail.
> >
> > As a first user, 'git-init-db --shared' sets this flag, since in a shared
> > setup, you are most unlikely to want forced pushes to succeed.
> >
> > Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
>
> Looks good. Care to do a handful more tasks before we forget?
>
> Documentation/git-init-db.txt
> Documentation/config.txt
> Documentation/git-receive-pack.txt
> t/t5400-send-pack.sh or a new test t/t5401-push-into-shared-repo.sh
I expected Jakub to ask for it ;-)
-- snip --
[PATCH] Document receive.denyNonFastforwards
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
Documentation/config.txt | 7 +++++++
Documentation/git-init-db.txt | 4 ++++
Documentation/git-receive-pack.txt | 2 ++
t/t5400-send-pack.sh | 10 ++++++++++
4 files changed, 23 insertions(+), 0 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 844cae4..6802d30 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -267,3 +267,10 @@ whatchanged.difftree::
imap::
The configuration variables in the 'imap' section are described
in gitlink:git-imap-send[1].
+
+receive.denyNonFastforwads::
+ If set to true, git-receive-pack will deny a ref update which is
+ not a fast forward. Use this to prevent such an update via a push,
+ even if that push is forced. This configuration variable is
+ set when initializing a shared repository.
+
diff --git a/Documentation/git-init-db.txt b/Documentation/git-init-db.txt
index 63cd5da..ca7d09d 100644
--- a/Documentation/git-init-db.txt
+++ b/Documentation/git-init-db.txt
@@ -48,6 +48,10 @@ is given:
- 'all' (or 'world' or 'everybody'): Same as 'group', but make the repository
readable by all users.
+By default, the configuration flag receive.denyNonFastforward is enabled
+in shared repositories, so that you cannot force a non fast-forwarding push
+into it.
+
--
diff --git a/Documentation/git-receive-pack.txt b/Documentation/git-receive-pack.txt
index f9457d4..0dfadc2 100644
--- a/Documentation/git-receive-pack.txt
+++ b/Documentation/git-receive-pack.txt
@@ -73,6 +73,8 @@ packed and is served via a dumb transpor
There are other real-world examples of using update and
post-update hooks found in the Documentation/howto directory.
+git-receive-pack honours the receive.denyNonFastforwards flag, which
+tells it if updates to a ref should be denied if they are not fast-forwards.
OPTIONS
-------
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
--
1.4.2.1.g6ad2-dirty
^ permalink raw reply related
* Re: [PATCH] add receive.denyNonFastforwards config variable
From: Johannes Schindelin @ 2006-09-21 0:17 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vlkoeds82.fsf@assigned-by-dhcp.cox.net>
Hi,
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") &&
case "$2,$mb" in
$local,*)
if test -n "$verbose"
then
echo >&2 "* $1: same as $3"
fi
;;
*,$local)
echo >&2 "* $1: fast forward to $3"
echo >&2 " from $local to $2"
git-update-ref -m "$rloga: fast-forward" "$1" "$2" "$local"
;;
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
where X is the old commit, and Y is the new commit. But I am too tired to
test it right now.
>... the test can be written like this:
>
> if (bases && !bases->next &&
> hashcmp(old_sha1, bases->item->object.sha1))
> ; /* happy */
> else
> return error("not a fast forward");
Plus
free_commit_list(bases);
as Jeff pointed out.
Ciao,
Dscho
^ permalink raw reply
* Re: [ANNOUNCE] Public Gitweb Hosting Service
From: Linus Torvalds @ 2006-09-21 0:45 UTC (permalink / raw)
To: Petr Baudis; +Cc: git
In-Reply-To: <Pine.LNX.4.64.0609200753370.4388@g5.osdl.org>
On Wed, 20 Sep 2006, Linus Torvalds wrote:
>
> It's _definitely_ broken for me. But it looks like that may be a firefox
> on ppc issue (even if other sites work fine), because I don't have the
> same problem on my Mac Mini. Strange.
>
> Maybe it's a "yum install" that upgraded firefox while it was running or
> something.
Indeed, that seems to have been it. It all works for me now. Very strange
firefox bug that only affected one site ;)
(kernel.org runs a much older gitweb, so it was possibly triggered by
something that gitweb does in newer versions).
Linus
^ permalink raw reply
* [PATCH 0/6] packed deltas with offset to base instead of sha1
From: Nicolas Pitre @ 2006-09-21 4:04 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
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%.
Nicolas
^ permalink raw reply
* (unknown)
From: Nicolas Pitre @ 2006-09-21 4:04 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
[PATCH 1/6] move pack creation to version 3
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 2/6] many cleanups to sha1_file.c
From: Nicolas Pitre @ 2006-09-21 4:05 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
Those cleanups are mainly to set the table for the support of deltas
with base objects referenced by offsets instead of sha1. This means
that many pack lookup functions are converted to take a pack/offset
tuple instead of a sha1.
This eliminates many struct pack_entry usages since this structure
carried redundent information in many cases, and it increased stack
footprint needlessly for a couple recursively called functions that used
to declare a local copy of it for every recursion loop.
In the process, packed_object_info_detail() has been reorganized as well
so to look much saner and more amenable to deltas with offset support.
Finally the appropriate adjustments have been made to functions that
depend on the above changes. But there is no functionality changes yet
simply some code refactoring at this point.
Signed-off-by: Nicolas Pitre <nico@cam.org>
---
This patch might look a bit frightening since it touches core code quite
extensively but all those changes must occur at the same time to keep the
code fully functional. All tests are still passing fine of course. And
again there should not be any change in behavior with this patch.
This will allow for the new functionalities to be added with a minimum of
changes later on and therefore easier to evaluate.
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 8d7a120..96c069a 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -597,15 +597,15 @@ static int add_object_entry(const unsign
if (!exclude) {
for (p = packed_git; p; p = p->next) {
- struct pack_entry e;
- if (find_pack_entry_one(sha1, &e, p)) {
+ unsigned long offset = find_pack_entry_one(sha1, p);
+ if (offset) {
if (incremental)
return 0;
if (local && !p->pack_local)
return 0;
if (!found_pack) {
- found_offset = e.offset;
- found_pack = e.p;
+ found_offset = offset;
+ found_pack = p;
}
}
}
diff --git a/cache.h b/cache.h
index 282eed6..42f13e2 100644
--- a/cache.h
+++ b/cache.h
@@ -383,10 +383,10 @@ extern void unuse_packed_git(struct pack
extern struct packed_git *add_packed_git(char *, int, int);
extern int num_packed_objects(const struct packed_git *p);
extern int nth_packed_object_sha1(const struct packed_git *, int, unsigned char*);
-extern int find_pack_entry_one(const unsigned char *, struct pack_entry *, struct packed_git *);
-extern void *unpack_entry_gently(struct pack_entry *, char *, unsigned long *);
+extern unsigned long find_pack_entry_one(const unsigned char *, struct packed_git *);
+extern void *unpack_entry_gently(struct packed_git *, unsigned long, char *, unsigned long *);
extern unsigned long unpack_object_header_gently(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
-extern void packed_object_info_detail(struct pack_entry *, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
+extern void packed_object_info_detail(struct packed_git *, unsigned long, char *, unsigned long *, unsigned long *, unsigned int *, unsigned char *);
/* Dumb servers support */
extern int update_server_info(int);
diff --git a/pack-check.c b/pack-check.c
index 04c6c00..c0caaee 100644
--- a/pack-check.c
+++ b/pack-check.c
@@ -42,16 +42,16 @@ static int verify_packfile(struct packed
*/
for (i = err = 0; i < nr_objects; i++) {
unsigned char sha1[20];
- struct pack_entry e;
void *data;
char type[20];
- unsigned long size;
+ unsigned long size, offset;
if (nth_packed_object_sha1(p, i, sha1))
die("internal error pack-check nth-packed-object");
- if (!find_pack_entry_one(sha1, &e, p))
+ offset = find_pack_entry_one(sha1, p);
+ if (!offset)
die("internal error pack-check find-pack-entry-one");
- data = unpack_entry_gently(&e, type, &size);
+ data = unpack_entry_gently(p, offset, type, &size);
if (!data) {
err = error("cannot unpack %s from %s",
sha1_to_hex(sha1), p->pack_name);
@@ -84,25 +84,26 @@ static void show_pack_info(struct packed
for (i = 0; i < nr_objects; i++) {
unsigned char sha1[20], base_sha1[20];
- struct pack_entry e;
char type[20];
unsigned long size;
unsigned long store_size;
+ unsigned long offset;
unsigned int delta_chain_length;
if (nth_packed_object_sha1(p, i, sha1))
die("internal error pack-check nth-packed-object");
- if (!find_pack_entry_one(sha1, &e, p))
+ offset = find_pack_entry_one(sha1, p);
+ if (!offset)
die("internal error pack-check find-pack-entry-one");
- packed_object_info_detail(&e, type, &size, &store_size,
+ packed_object_info_detail(p, offset, type, &size, &store_size,
&delta_chain_length,
base_sha1);
printf("%s ", sha1_to_hex(sha1));
if (!delta_chain_length)
- printf("%-6s %lu %u\n", type, size, e.offset);
+ printf("%-6s %lu %lu\n", type, size, offset);
else {
- printf("%-6s %lu %u %u %s\n", type, size, e.offset,
+ printf("%-6s %lu %lu %u %s\n", type, size, offset,
delta_chain_length, sha1_to_hex(base_sha1));
if (delta_chain_length < MAX_CHAIN)
chain_histogram[delta_chain_length]++;
diff --git a/sha1_file.c b/sha1_file.c
index b89edb9..6fae766 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -888,33 +888,32 @@ void * unpack_sha1_file(void *map, unsig
}
/* forward declaration for a mutually recursive function */
-static int packed_object_info(struct pack_entry *entry,
+static int packed_object_info(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep);
-static int packed_delta_info(unsigned char *base_sha1,
- unsigned long delta_size,
- unsigned long left,
+static int packed_delta_info(struct packed_git *p,
+ unsigned long offset,
char *type,
- unsigned long *sizep,
- struct packed_git *p)
+ unsigned long *sizep)
{
- struct pack_entry base_ent;
+ unsigned long base_offset;
+ unsigned char *base_sha1 = (unsigned char *) p->pack_base + offset;
- if (left < 20)
+ if (p->pack_size < offset + 20)
die("truncated pack file");
-
/* The base entry _must_ be in the same pack */
- if (!find_pack_entry_one(base_sha1, &base_ent, p))
+ base_offset = find_pack_entry_one(base_sha1, p);
+ if (!base_offset)
die("failed to find delta-pack base object %s",
sha1_to_hex(base_sha1));
+ offset += 20;
/* We choose to only get the type of the base object and
* ignore potentially corrupt pack file that expects the delta
* based on a base with a wrong size. This saves tons of
* inflate() calls.
*/
-
- if (packed_object_info(&base_ent, type, NULL))
+ if (packed_object_info(p, base_offset, type, NULL))
die("cannot get info for delta-pack base");
if (sizep) {
@@ -926,8 +925,8 @@ static int packed_delta_info(unsigned ch
memset(&stream, 0, sizeof(stream));
- data = stream.next_in = base_sha1 + 20;
- stream.avail_in = left - 20;
+ data = stream.next_in = (unsigned char *) p->pack_base + offset;;
+ stream.avail_in = p->pack_size - offset;
stream.next_out = delta_head;
stream.avail_out = sizeof(delta_head);
@@ -989,75 +988,60 @@ int check_reuse_pack_delta(struct packed
return status;
}
-void packed_object_info_detail(struct pack_entry *e,
+void packed_object_info_detail(struct packed_git *p,
+ unsigned long offset,
char *type,
unsigned long *size,
unsigned long *store_size,
unsigned int *delta_chain_length,
unsigned char *base_sha1)
{
- struct packed_git *p = e->p;
- unsigned long offset;
- unsigned char *pack;
+ unsigned long val;
+ unsigned char *next_sha1;
enum object_type kind;
- offset = unpack_object_header(p, e->offset, &kind, size);
- pack = (unsigned char *) p->pack_base + offset;
- if (kind != OBJ_DELTA)
- *delta_chain_length = 0;
- else {
- unsigned int chain_length = 0;
- if (p->pack_size <= offset + 20)
- die("pack file %s records an incomplete delta base",
- p->pack_name);
- hashcpy(base_sha1, pack);
- do {
- struct pack_entry base_ent;
- unsigned long junk;
-
- find_pack_entry_one(pack, &base_ent, p);
- offset = unpack_object_header(p, base_ent.offset,
- &kind, &junk);
- pack = (unsigned char *) p->pack_base + offset;
- chain_length++;
- } while (kind == OBJ_DELTA);
- *delta_chain_length = chain_length;
- }
- switch (kind) {
- case OBJ_COMMIT:
- case OBJ_TREE:
- case OBJ_BLOB:
- case OBJ_TAG:
- strcpy(type, type_names[kind]);
- break;
- default:
- die("corrupted pack file %s containing object of kind %d",
- p->pack_name, kind);
+ *delta_chain_length = 0;
+ offset = unpack_object_header(p, offset, &kind, size);
+
+ for (;;) {
+ switch (kind) {
+ default:
+ die("corrupted pack file %s containing object of kind %d",
+ p->pack_name, kind);
+ case OBJ_COMMIT:
+ case OBJ_TREE:
+ case OBJ_BLOB:
+ case OBJ_TAG:
+ strcpy(type, type_names[kind]);
+ *store_size = 0; /* notyet */
+ return;
+ case OBJ_DELTA:
+ if (p->pack_size <= offset + 20)
+ die("pack file %s records an incomplete delta base",
+ p->pack_name);
+ next_sha1 = (unsigned char *) p->pack_base + offset;
+ if (*delta_chain_length == 0)
+ hashcpy(base_sha1, next_sha1);
+ offset = find_pack_entry_one(next_sha1, p);
+ break;
+ }
+ offset = unpack_object_header(p, offset, &kind, &val);
+ (*delta_chain_length)++;
}
- *store_size = 0; /* notyet */
}
-static int packed_object_info(struct pack_entry *entry,
+static int packed_object_info(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep)
{
- struct packed_git *p = entry->p;
- unsigned long offset, size, left;
- unsigned char *pack;
+ unsigned long size;
enum object_type kind;
- int retval;
- if (use_packed_git(p))
- die("cannot map packed file");
+ offset = unpack_object_header(p, offset, &kind, &size);
- offset = unpack_object_header(p, entry->offset, &kind, &size);
- pack = (unsigned char *) p->pack_base + offset;
- left = p->pack_size - offset;
+ if (kind == OBJ_DELTA)
+ return packed_delta_info(p, offset, type, sizep);
switch (kind) {
- case OBJ_DELTA:
- retval = packed_delta_info(pack, size, left, type, sizep, p);
- unuse_packed_git(p);
- return retval;
case OBJ_COMMIT:
case OBJ_TREE:
case OBJ_BLOB:
@@ -1070,7 +1054,6 @@ static int packed_object_info(struct pac
}
if (sizep)
*sizep = size;
- unuse_packed_git(p);
return 0;
}
@@ -1107,25 +1090,26 @@ static void *unpack_delta_entry(struct p
char *type,
unsigned long *sizep)
{
- struct pack_entry base_ent;
void *delta_data, *result, *base;
- unsigned long result_size, base_size;
- unsigned char* base_sha1;
+ unsigned long result_size, base_size, base_offset;
+ unsigned char *base_sha1;
- if ((offset + 20) >= p->pack_size)
+ if (p->pack_size < offset + 20)
die("truncated pack file");
-
/* The base entry _must_ be in the same pack */
base_sha1 = (unsigned char*)p->pack_base + offset;
- if (!find_pack_entry_one(base_sha1, &base_ent, p))
+ base_offset = find_pack_entry_one(base_sha1, p);
+ if (!base_offset)
die("failed to find delta-pack base object %s",
sha1_to_hex(base_sha1));
- base = unpack_entry_gently(&base_ent, type, &base_size);
+ offset += 20;
+
+ base = unpack_entry_gently(p, base_offset, type, &base_size);
if (!base)
- die("failed to read delta-pack base object %s",
- sha1_to_hex(base_sha1));
+ die("failed to read delta base object at %lu from %s",
+ base_offset, p->pack_name);
- delta_data = unpack_compressed_entry(p, offset + 20, delta_size);
+ delta_data = unpack_compressed_entry(p, offset, delta_size);
result = patch_delta(base, base_size,
delta_data, delta_size,
&result_size);
@@ -1145,7 +1129,7 @@ static void *unpack_entry(struct pack_en
if (use_packed_git(p))
die("cannot map packed file");
- retval = unpack_entry_gently(entry, type, sizep);
+ retval = unpack_entry_gently(p, entry->offset, type, sizep);
unuse_packed_git(p);
if (!retval)
die("corrupted pack file %s", p->pack_name);
@@ -1153,14 +1137,13 @@ static void *unpack_entry(struct pack_en
}
/* The caller is responsible for use_packed_git()/unuse_packed_git() pair */
-void *unpack_entry_gently(struct pack_entry *entry,
+void *unpack_entry_gently(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep)
{
- struct packed_git *p = entry->p;
- unsigned long offset, size;
+ unsigned long size;
enum object_type kind;
- offset = unpack_object_header(p, entry->offset, &kind, &size);
+ offset = unpack_object_header(p, offset, &kind, &size);
switch (kind) {
case OBJ_DELTA:
return unpack_delta_entry(p, offset, size, type, sizep);
@@ -1192,8 +1175,8 @@ int nth_packed_object_sha1(const struct
return 0;
}
-int find_pack_entry_one(const unsigned char *sha1,
- struct pack_entry *e, struct packed_git *p)
+unsigned long find_pack_entry_one(const unsigned char *sha1,
+ struct packed_git *p)
{
unsigned int *level1_ofs = p->index_base;
int hi = ntohl(level1_ofs[*sha1]);
@@ -1203,12 +1186,8 @@ int find_pack_entry_one(const unsigned c
do {
int mi = (lo + hi) / 2;
int cmp = hashcmp((unsigned char *)index + (24 * mi) + 4, sha1);
- if (!cmp) {
- e->offset = ntohl(*((unsigned int *) ((char *) index + (24 * mi))));
- hashcpy(e->sha1, sha1);
- e->p = p;
- return 1;
- }
+ if (!cmp)
+ return ntohl(*((unsigned int *) ((char *) index + (24 * mi))));
if (cmp > 0)
hi = mi;
else
@@ -1220,6 +1199,8 @@ int find_pack_entry_one(const unsigned c
static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e, const char **ignore_packed)
{
struct packed_git *p;
+ unsigned long offset;
+
prepare_packed_git();
for (p = packed_git; p; p = p->next) {
@@ -1231,8 +1212,13 @@ static int find_pack_entry(const unsigne
if (*ig)
continue;
}
- if (find_pack_entry_one(sha1, e, p))
+ offset = find_pack_entry_one(sha1, p);
+ if (offset) {
+ e->offset = offset;
+ e->p = p;
+ hashcpy(e->sha1, sha1);
return 1;
+ }
}
return 0;
}
@@ -1241,10 +1227,9 @@ struct packed_git *find_sha1_pack(const
struct packed_git *packs)
{
struct packed_git *p;
- struct pack_entry e;
for (p = packs; p; p = p->next) {
- if (find_pack_entry_one(sha1, &e, p))
+ if (find_pack_entry_one(sha1, p))
return p;
}
return NULL;
@@ -1263,12 +1248,16 @@ int sha1_object_info(const unsigned char
if (!map) {
struct pack_entry e;
- if (find_pack_entry(sha1, &e, NULL))
- return packed_object_info(&e, type, sizep);
- reprepare_packed_git();
- if (find_pack_entry(sha1, &e, NULL))
- return packed_object_info(&e, type, sizep);
- return error("unable to find %s", sha1_to_hex(sha1));
+ if (!find_pack_entry(sha1, &e, NULL)) {
+ reprepare_packed_git();
+ if (!find_pack_entry(sha1, &e, NULL))
+ return error("unable to find %s", sha1_to_hex(sha1));
+ }
+ if (use_packed_git(e.p))
+ die("cannot map packed file");
+ status = packed_object_info(e.p, e.offset, type, sizep);
+ unuse_packed_git(e.p);
+ return status;
}
if (unpack_sha1_header(&stream, map, mapsize, hdr, sizeof(hdr)) < 0)
status = error("unable to unpack %s header",
^ permalink raw reply related
* [PATCH 3/6] introduce delta objects with offset to base
From: Nicolas Pitre @ 2006-09-21 4:06 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
This adds a new object, namely OBJ_OFS_DELTA, renames OBJ_DELTA to
OBJ_REF_DELTA to better make the distinction between those two delta
objects, and adds support for the handling of those new delta objects
in sha1_file.c only.
The OBJ_OFS_DELTA contains a relative offset from the delta object's
position in a pack instead of the 20-byte SHA1 reference to identify
the base object. Since the base is likely to be not so far away, the
relative offset is more likely to have a smaller encoding on average
than an absolute offset. And for those delta objects the base must
always be stored first because there is no way to know the distance of
later objects when streaming a pack. Hence this relative offset is
always meant to be negative.
The offset encoding is slightly denser than the one used for object
size -- credits to <linux@horizon.com> (whoever this is) for bringing
it to my attention.
This allows for pack size reduction between 3.2% (Linux-2.6) to over 5%
(linux-historic). Runtime pack access should be faster too since delta
replay does skip a search in the pack index for each delta in a chain.
Signed-off-by: Nicolas Pitre <nico@cam.org>
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 96c069a..c62734a 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -232,7 +232,7 @@ static int encode_header(enum object_typ
int n = 1;
unsigned char c;
- if (type < OBJ_COMMIT || type > OBJ_DELTA)
+ if (type < OBJ_COMMIT || type > OBJ_REF_DELTA)
die("bad type %d", type);
c = (type << 4) | (size & 15);
@@ -297,7 +297,7 @@ static int revalidate_pack_entry(struct
used = unpack_object_header_gently(data, len, &type, &size);
if (!used)
return -1;
- if (type == OBJ_DELTA)
+ if (type == OBJ_REF_DELTA)
used += 20; /* skip base object name */
data += used;
len -= used;
@@ -340,7 +340,7 @@ static unsigned long write_object(struct
obj_type = entry->type;
if (! entry->in_pack)
to_reuse = 0; /* can't reuse what we don't have */
- else if (obj_type == OBJ_DELTA)
+ else if (obj_type == OBJ_REF_DELTA)
to_reuse = 1; /* check_object() decided it for us */
else if (obj_type != entry->in_pack_type)
to_reuse = 0; /* pack has delta which is unusable */
@@ -380,7 +380,7 @@ static unsigned long write_object(struct
if (entry->delta) {
buf = delta_against(buf, size, entry);
size = entry->delta_size;
- obj_type = OBJ_DELTA;
+ obj_type = OBJ_REF_DELTA;
}
/*
* The object header is a byte of 'type' followed by zero or
@@ -409,11 +409,11 @@ static unsigned long write_object(struct
sha1write(f, buf, datalen);
unuse_packed_git(p);
hdrlen = 0; /* not really */
- if (obj_type == OBJ_DELTA)
+ if (obj_type == OBJ_REF_DELTA)
reused_delta++;
reused++;
}
- if (obj_type == OBJ_DELTA)
+ if (obj_type == OBJ_REF_DELTA)
written_delta++;
written++;
return hdrlen + datalen;
@@ -916,7 +916,7 @@ static void check_object(struct object_e
* delta.
*/
if (!no_reuse_delta &&
- entry->in_pack_type == OBJ_DELTA &&
+ entry->in_pack_type == OBJ_REF_DELTA &&
(base_entry = locate_object_entry(base)) &&
(!base_entry->preferred_base)) {
@@ -929,7 +929,7 @@ static void check_object(struct object_e
/* uncompressed size of the delta data */
entry->size = entry->delta_size = size;
entry->delta = base_entry;
- entry->type = OBJ_DELTA;
+ entry->type = OBJ_REF_DELTA;
entry->delta_sibling = base_entry->delta_child;
base_entry->delta_child = entry;
diff --git a/builtin-unpack-objects.c b/builtin-unpack-objects.c
index 4f96bca..c6c6368 100644
--- a/builtin-unpack-objects.c
+++ b/builtin-unpack-objects.c
@@ -241,7 +241,7 @@ static void unpack_one(unsigned nr, unsi
case OBJ_TAG:
unpack_non_delta_entry(type, size);
return;
- case OBJ_DELTA:
+ case OBJ_REF_DELTA:
unpack_delta_entry(size);
return;
default:
diff --git a/cache.h b/cache.h
index 42f13e2..7ecab65 100644
--- a/cache.h
+++ b/cache.h
@@ -273,8 +273,9 @@ enum object_type {
OBJ_TREE = 2,
OBJ_BLOB = 3,
OBJ_TAG = 4,
- /* 5/6 for future expansion */
- OBJ_DELTA = 7,
+ /* 5 for future expansion */
+ OBJ_OFS_DELTA = 6,
+ OBJ_REF_DELTA = 7,
OBJ_BAD,
};
diff --git a/index-pack.c b/index-pack.c
index 80bc6cb..aef7f0a 100644
--- a/index-pack.c
+++ b/index-pack.c
@@ -158,7 +158,7 @@ static void *unpack_raw_entry(unsigned l
}
switch (type) {
- case OBJ_DELTA:
+ case OBJ_REF_DELTA:
if (pos + 20 >= pack_limit)
bad_object(offset, "object extends past end of pack");
hashcpy(delta_base, pack_base + pos);
@@ -301,7 +301,7 @@ static void parse_pack_objects(void)
data = unpack_raw_entry(offset, &obj->type, &data_size,
base_sha1, &offset);
obj->real_type = obj->type;
- if (obj->type == OBJ_DELTA) {
+ if (obj->type == OBJ_REF_DELTA) {
struct delta_entry *delta = &deltas[nr_deltas++];
delta->obj = obj;
hashcpy(delta->base_sha1, base_sha1);
@@ -328,7 +328,7 @@ static void parse_pack_objects(void)
struct object_entry *obj = &objects[i];
int j, first, last;
- if (obj->type == OBJ_DELTA)
+ if (obj->type == OBJ_REF_DELTA)
continue;
if (find_deltas_based_on_sha1(obj->sha1, &first, &last))
continue;
@@ -341,7 +341,7 @@ static void parse_pack_objects(void)
/* Check for unresolved deltas */
for (i = 0; i < nr_deltas; i++) {
- if (deltas[i].obj->real_type == OBJ_DELTA)
+ if (deltas[i].obj->real_type == OBJ_REF_DELTA)
die("packfile '%s' has unresolved deltas", pack_name);
}
}
diff --git a/sha1_file.c b/sha1_file.c
index 6fae766..66ebdde 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -887,26 +887,61 @@ void * unpack_sha1_file(void *map, unsig
return unpack_sha1_rest(&stream, hdr, *size);
}
+static unsigned long get_delta_base(struct packed_git *p,
+ unsigned long offset,
+ enum object_type kind,
+ unsigned long delta_obj_offset,
+ unsigned long *base_obj_offset)
+{
+ unsigned char *base_info = (unsigned char *) p->pack_base + offset;
+ unsigned long base_offset;
+
+ /* there must be at least 20 bytes left regardless of delta type */
+ if (p->pack_size <= offset + 20)
+ die("truncated pack file");
+
+ if (kind == OBJ_OFS_DELTA) {
+ unsigned used = 0;
+ unsigned char c = base_info[used++];
+ 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");
+ c = base_info[used++];
+ base_offset = (base_offset << 7) + (c & 127);
+ }
+ base_offset = delta_obj_offset - base_offset;
+ if (base_offset >= delta_obj_offset)
+ die("delta base offset out of bound");
+ offset += used;
+ } else if (kind == OBJ_REF_DELTA) {
+ /* The base entry _must_ be in the same pack */
+ base_offset = find_pack_entry_one(base_info, p);
+ if (!base_offset)
+ die("failed to find delta-pack base object %s",
+ sha1_to_hex(base_info));
+ offset += 20;
+ } else
+ die("I am totally screwed");
+ *base_obj_offset = base_offset;
+ return offset;
+}
+
/* forward declaration for a mutually recursive function */
static int packed_object_info(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep);
static int packed_delta_info(struct packed_git *p,
unsigned long offset,
+ enum object_type kind,
+ unsigned long obj_offset,
char *type,
unsigned long *sizep)
{
unsigned long base_offset;
- unsigned char *base_sha1 = (unsigned char *) p->pack_base + offset;
- if (p->pack_size < offset + 20)
- die("truncated pack file");
- /* The base entry _must_ be in the same pack */
- base_offset = find_pack_entry_one(base_sha1, p);
- if (!base_offset)
- die("failed to find delta-pack base object %s",
- sha1_to_hex(base_sha1));
- offset += 20;
+ offset = get_delta_base(p, offset, kind, obj_offset, &base_offset);
/* We choose to only get the type of the base object and
* ignore potentially corrupt pack file that expects the delta
@@ -979,7 +1014,7 @@ int check_reuse_pack_delta(struct packed
use_packed_git(p);
ptr = offset;
ptr = unpack_object_header(p, ptr, kindp, sizep);
- if (*kindp != OBJ_DELTA)
+ if (*kindp != OBJ_REF_DELTA)
goto done;
hashcpy(base, (unsigned char *) p->pack_base + ptr);
status = 0;
@@ -996,11 +1031,12 @@ void packed_object_info_detail(struct pa
unsigned int *delta_chain_length,
unsigned char *base_sha1)
{
- unsigned long val;
+ unsigned long obj_offset, val;
unsigned char *next_sha1;
enum object_type kind;
*delta_chain_length = 0;
+ obj_offset = offset;
offset = unpack_object_header(p, offset, &kind, size);
for (;;) {
@@ -1015,7 +1051,13 @@ void packed_object_info_detail(struct pa
strcpy(type, type_names[kind]);
*store_size = 0; /* notyet */
return;
- case OBJ_DELTA:
+ case OBJ_OFS_DELTA:
+ get_delta_base(p, offset, kind, obj_offset, &offset);
+ if (*delta_chain_length == 0) {
+ /* TODO: find base_sha1 as pointed by offset */
+ }
+ break;
+ case OBJ_REF_DELTA:
if (p->pack_size <= offset + 20)
die("pack file %s records an incomplete delta base",
p->pack_name);
@@ -1025,6 +1067,7 @@ void packed_object_info_detail(struct pa
offset = find_pack_entry_one(next_sha1, p);
break;
}
+ obj_offset = offset;
offset = unpack_object_header(p, offset, &kind, &val);
(*delta_chain_length)++;
}
@@ -1033,15 +1076,15 @@ void packed_object_info_detail(struct pa
static int packed_object_info(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep)
{
- unsigned long size;
+ unsigned long size, obj_offset = offset;
enum object_type kind;
offset = unpack_object_header(p, offset, &kind, &size);
- if (kind == OBJ_DELTA)
- return packed_delta_info(p, offset, type, sizep);
-
switch (kind) {
+ case OBJ_OFS_DELTA:
+ case OBJ_REF_DELTA:
+ return packed_delta_info(p, offset, kind, obj_offset, type, sizep);
case OBJ_COMMIT:
case OBJ_TREE:
case OBJ_BLOB:
@@ -1087,23 +1130,15 @@ static void *unpack_compressed_entry(str
static void *unpack_delta_entry(struct packed_git *p,
unsigned long offset,
unsigned long delta_size,
+ enum object_type kind,
+ unsigned long obj_offset,
char *type,
unsigned long *sizep)
{
void *delta_data, *result, *base;
unsigned long result_size, base_size, base_offset;
- unsigned char *base_sha1;
-
- if (p->pack_size < offset + 20)
- die("truncated pack file");
- /* The base entry _must_ be in the same pack */
- base_sha1 = (unsigned char*)p->pack_base + offset;
- base_offset = find_pack_entry_one(base_sha1, p);
- if (!base_offset)
- die("failed to find delta-pack base object %s",
- sha1_to_hex(base_sha1));
- offset += 20;
+ offset = get_delta_base(p, offset, kind, obj_offset, &base_offset);
base = unpack_entry_gently(p, base_offset, type, &base_size);
if (!base)
die("failed to read delta base object at %lu from %s",
@@ -1140,13 +1175,14 @@ static void *unpack_entry(struct pack_en
void *unpack_entry_gently(struct packed_git *p, unsigned long offset,
char *type, unsigned long *sizep)
{
- unsigned long size;
+ unsigned long size, obj_offset = offset;
enum object_type kind;
offset = unpack_object_header(p, offset, &kind, &size);
switch (kind) {
- case OBJ_DELTA:
- return unpack_delta_entry(p, offset, size, type, sizep);
+ case OBJ_OFS_DELTA:
+ case OBJ_REF_DELTA:
+ return unpack_delta_entry(p, offset, size, kind, obj_offset, type, sizep);
case OBJ_COMMIT:
case OBJ_TREE:
case OBJ_BLOB:
^ 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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox