* Re: [PATCH] add a diff-files command (revised and cleaned up)
From: Junio C Hamano @ 2005-04-28 21:04 UTC (permalink / raw)
To: Nicolas Pitre; +Cc: Linus Torvalds, git
In-Reply-To: <Pine.LNX.4.62.0504281327520.14033@localhost.localdomain>
>>>>> "NP" == Nicolas Pitre <nico@cam.org> writes:
NP> What about this patch then?
NP> =====
NP> Give show-files the ability to process exclusion pattern.
I just tried this, and I like it. Thanks!
^ permalink raw reply
* Re: diff against a tag ?
From: Linus Torvalds @ 2005-04-28 21:01 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Dave Jones, git
In-Reply-To: <7vpswe7hvj.fsf@assigned-by-dhcp.cox.net>
On Thu, 28 Apr 2005, Junio C Hamano wrote:
>
> Depends on your definition of today, but with the patch below I
> sent today, you can say "diff-tree -p $tag $(cat .git/HEAD)".
I think Dave was wondering how to _find_ the tag in the first place, which
is a different issue.
Right now fsck is the only thing that reports tags that aren't referenced
some other way. Once you know the tag, things are easy - even without
Junio's patch you can just do
object=$(cat-file tag $tag | sed 's/object //;q')
and then you can just do
diff-tree $object $(cat .git/HEAD)
or whatever you want to do.
Dave: do a "fsck --tags" in your tree, and it will talk about the tags it
finds. Then you can create files like .git/refs/tags/v2.6.12-rc2 that
contain pointers to those tags..
Linus
^ permalink raw reply
* Re: Finding file revisions
From: Chris Mason @ 2005-04-28 20:58 UTC (permalink / raw)
To: Kay Sievers; +Cc: Linus Torvalds, git
In-Reply-To: <1114715496.4212.36.camel@localhost.localdomain>
On Thursday 28 April 2005 15:11, Kay Sievers wrote:
>
> Can you confirm this with the kernel tree?
> file-changes -c 9acf6597c533f3d5c991f730c6a1be296679018e
> drivers/usb/core/usb.c
>
> lists the commit:
> diff-tree -r 1d66c64c3cee10a465cd3f8bd9191bbeb718f650
> c79bea07ec4d3ef087962699fe8b2f6dc5ca7754
> f0534ee064901d0108eb7b2b1fcb59a98bb53c2b->c231b4bef314284a168fedb6c5f6c47ae
>c5084fc drivers/usb/core/usb.c cat-file commit
> c79bea07ec4d3ef087962699fe8b2f6dc5ca7754
>
> which seems not to have changed the file asked for.
Hmmm, that does work here:
coffee:/src/git # diff-tree -r 1d66c64c3cee10a465cd3f8bd9191bbeb718f650 c79bea07ec4d3ef087962699fe8b2f6dc5ca7754 | grep usb.core.usb.c
*100644->100644 blob f0534ee064901d0108eb7b2b1fcb59a98bb53c2b->c231b4bef314284a168fedb6c5f6c47aec5084fc drivers/usb/core/usb.c
-chris
^ permalink raw reply
* Re: How to get bash to shut up about SIGPIPE?
From: Linus Torvalds @ 2005-04-28 20:47 UTC (permalink / raw)
To: Ryan Anderson; +Cc: Rene Scharfe, Git Mailing List, Petr Baudis
In-Reply-To: <20050428202739.GE30308@mythryan2.michonline.com>
On Thu, 28 Apr 2005, Ryan Anderson wrote:
>
> Try adding "set -e" to the beginning of cg-log.
Nope. I actually downloaded bash-3.0, and it literally seem sto be
impossible to get bash to not do it.
It has some noise there about signal trapping, but that doesn't actually
seem to work.
Linus
^ permalink raw reply
* Re: diff against a tag ?
From: Junio C Hamano @ 2005-04-28 20:42 UTC (permalink / raw)
To: Dave Jones; +Cc: git
In-Reply-To: <20050428200953.GD8514@redhat.com>
>>>>> "DJ" == Dave Jones <davej@redhat.com> writes:
DJ> Maybe I missed this in the discussion on tags recently
DJ> (I kinda tuned out after a while on that thread).
DJ> Is there an easy way to express 'show me the diff
DJ> between HEAD and 2.6.12rc3' today ?
Depends on your definition of today, but with the patch below I
sent today, you can say "diff-tree -p $tag $(cat .git/HEAD)".
Subject: [PATCH] Rename and extend read_tree_with_tree_or_commit_sha1
Date: Thu, 28 Apr 2005 12:15:43 -0700
Message-ID: <7vu0lq7lwg.fsf@assigned-by-dhcp.cox.net>
This patch renames read_tree_with_tree_or_commit_sha1() to
read_object_with_reference() and extends it to automatically
dereference not just "commit" objects but "tag" objects. With
this patch, you can say e.g.:
ls-tree $tag
read-tree -m $(merge-base $tag $HEAD) $tag $HEAD
diff-cache $tag
diff-tree $tag $HEAD
^ permalink raw reply
* Re: How to get bash to shut up about SIGPIPE?
From: Ryan Anderson @ 2005-04-28 20:27 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Rene Scharfe, Git Mailing List, Petr Baudis
In-Reply-To: <Pine.LNX.4.58.0504281217100.18901@ppc970.osdl.org>
On Thu, Apr 28, 2005 at 12:21:26PM -0700, Linus Torvalds wrote:
> On Thu, 28 Apr 2005, Rene Scharfe wrote:
> >
> > I think you misspelled "cg-log". :-D
>
> My fingers have a hard time learning new patterns, so I've got:
>
> torvalds@ppc970:~/git> cat ~/bin/git
> #!/bin/sh
> cmd="cg-$1"
> shift
> $cmd "$@"
>
> until my fingers learn the new thing.
>
> > Doing "cg-log | head" gives me 10 lines of log and nothing else. Maybe
> > the problem has been fixed between 0.7 and the current version I'm using
> > (commit ID 49612c471eebd26efe926a71752e254c1cdc382d)?
>
> no, this is current as of an hour ago, same head you have.
>
> It's a bash-specific thing, and depends on how you compiled bash.
>
> Defining "DONT_REPORT_SIGPIPE" in config-top.h when building bash gets rid
> of it, but I really don't want to rebuild bash just because of this ;)
Debian's bash seems to have that set, so it's a bit hard for me to test
(I don't really have any non-Debian machines around these days for some
reason.)
Try adding "set -e" to the beginning of cg-log.
That may cause some *other* problems, but I think it will fix this
problem.
--
Ryan Anderson
sometimes Pug Majere
^ permalink raw reply
* Re: How to get bash to shut up about SIGPIPE?
From: Rene Scharfe @ 2005-04-28 20:13 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List, Petr Baudis
In-Reply-To: <Pine.LNX.4.58.0504281217100.18901@ppc970.osdl.org>
Linus Torvalds schrieb:
>
> On Thu, 28 Apr 2005, Rene Scharfe wrote:
>
>>I think you misspelled "cg-log". :-D
>
>
> My fingers have a hard time learning new patterns, so I've got:
>
> torvalds@ppc970:~/git> cat ~/bin/git
> #!/bin/sh
> cmd="cg-$1"
> shift
> $cmd "$@"
As a workaround, add this line after the shift to suppress the ugly
messages:
[ "$cmd" = cg-log ] && exec 2>/dev/null
> Defining "DONT_REPORT_SIGPIPE" in config-top.h when building bash gets rid
> of it, but I really don't want to rebuild bash just because of this ;)
Yes, I just compiled it and in the version from gnu.org this defaults to
not being defined. Man, am I glad my distro uncommented that line. :-)
Looking briefly at the source there doesn't seem to be a way to turn it
off besides this compile time setting. I really wonder why..
Rene
^ permalink raw reply
* diff against a tag ?
From: Dave Jones @ 2005-04-28 20:09 UTC (permalink / raw)
To: git
Maybe I missed this in the discussion on tags recently
(I kinda tuned out after a while on that thread).
Is there an easy way to express 'show me the diff
between HEAD and 2.6.12rc3' today ?
Looking at the commit for rc3, theres nothing obvious
to me distinguishing it from any other commit
other than the "Linux v2.6.12-rc3" in the description,
which makes it somewhat difficult to automate.
Dave
^ permalink raw reply
* Re: [PATCH] Built-in diff driver shows Index: line.
From: Linus Torvalds @ 2005-04-28 20:05 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7vy8b27lyf.fsf@assigned-by-dhcp.cox.net>
On Thu, 28 Apr 2005, Junio C Hamano wrote:
>
> As suggested by Linus as a workaround to unconfuse diffstat,
> this patch adds Index: line before the diff output the built-in
> driver produces.
Actually, I do dislike the Index: line, and think this is a pretty
intrusive work-around for a problem with diffstat.
There are other work-arounds for diffstat. In particular, diffstat has
various heuristics for finding the filename from the +++/--- files, and
the main one is
"*** %[^\t]\t%[^ ] %[^ ] %d %d:%d:%d %d"
(where "***" can be either +++ or ---). If if you match that one, diffstat
will pick up the name (first match) on its own.
Oh, actually maybe the better pattern to use is the one that GNU diff
itself ends up matching:
"*** %[^\t ]%[\t ]%d%c%d%c%d %d:%d:%d"
where the "%c" has to be either '-' or '/' (ie it ends up matching as
"numeric date" + "numeric time").
You can put the "mode" thing at the end, and diffstat won't care about it.
Linus
^ permalink raw reply
* Re: How to get bash to shut up about SIGPIPE?
From: Linus Torvalds @ 2005-04-28 19:21 UTC (permalink / raw)
To: Rene Scharfe; +Cc: Git Mailing List, Petr Baudis
In-Reply-To: <42713379.7080107@lsrfire.ath.cx>
On Thu, 28 Apr 2005, Rene Scharfe wrote:
>
> I think you misspelled "cg-log". :-D
My fingers have a hard time learning new patterns, so I've got:
torvalds@ppc970:~/git> cat ~/bin/git
#!/bin/sh
cmd="cg-$1"
shift
$cmd "$@"
until my fingers learn the new thing.
> Doing "cg-log | head" gives me 10 lines of log and nothing else. Maybe
> the problem has been fixed between 0.7 and the current version I'm using
> (commit ID 49612c471eebd26efe926a71752e254c1cdc382d)?
no, this is current as of an hour ago, same head you have.
It's a bash-specific thing, and depends on how you compiled bash.
Defining "DONT_REPORT_SIGPIPE" in config-top.h when building bash gets rid
of it, but I really don't want to rebuild bash just because of this ;)
Linus
^ permalink raw reply
* [PATCH] Rename and extend read_tree_with_tree_or_commit_sha1
From: Junio C Hamano @ 2005-04-28 19:15 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
This patch renames read_tree_with_tree_or_commit_sha1() to
read_object_with_reference() and extends it to automatically
dereference not just "commit" objects but "tag" objects. With
this patch, you can say e.g.:
ls-tree $tag
read-tree -m $(merge-base $tag $HEAD) $tag $HEAD
diff-cache $tag
diff-tree $tag $HEAD
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
cache.h | 7 +++---
diff-cache.c | 2 -
diff-tree.c | 4 +--
git-mktag.c | 2 -
ls-tree.c | 2 -
read-tree.c | 2 -
sha1_file.c | 67 +++++++++++++++++++++++++++++++----------------------------
7 files changed, 46 insertions(+), 40 deletions(-)
# - 04/28 11:25 Show Index: line from built-in diff driver.
# + 04/28 11:59 Rename and extend read_tree_with_tree_or_commit_sha1
Index: cache.h
--- k/cache.h (mode:100644)
+++ l/cache.h (mode:100644)
@@ -143,9 +143,10 @@ extern int error(const char *err, ...);
extern int cache_name_compare(const char *name1, int len1, const char *name2, int len2);
-extern void *read_tree_with_tree_or_commit_sha1(const unsigned char *sha1,
- unsigned long *size,
- unsigned char *tree_sha1_ret);
+extern void *read_object_with_reference(const unsigned char *sha1,
+ const unsigned char *required_type,
+ unsigned long *size,
+ unsigned char *sha1_ret);
static inline void *xmalloc(int size)
{
Index: diff-cache.c
--- k/diff-cache.c (mode:100644)
+++ l/diff-cache.c (mode:100644)
@@ -180,7 +180,7 @@ int main(int argc, char **argv)
mark_merge_entries();
- tree = read_tree_with_tree_or_commit_sha1(tree_sha1, &size, 0);
+ tree = read_object_with_reference(tree_sha1, "tree", &size, 0);
if (!tree)
die("bad tree object %s", argv[1]);
if (read_tree(tree, size, 1))
Index: diff-tree.c
--- k/diff-tree.c (mode:100644)
+++ l/diff-tree.c (mode:100644)
@@ -238,10 +238,10 @@ static int diff_tree_sha1(const unsigned
unsigned long size1, size2;
int retval;
- tree1 = read_tree_with_tree_or_commit_sha1(old, &size1, 0);
+ tree1 = read_object_with_reference(old, "tree", &size1, 0);
if (!tree1)
die("unable to read source tree (%s)", sha1_to_hex(old));
- tree2 = read_tree_with_tree_or_commit_sha1(new, &size2, 0);
+ tree2 = read_object_with_reference(new, "tree", &size2, 0);
if (!tree2)
die("unable to read destination tree (%s)", sha1_to_hex(new));
retval = diff_tree(tree1, size1, tree2, size2, base);
Index: git-mktag.c
--- k/git-mktag.c (mode:100644)
+++ l/git-mktag.c (mode:100644)
@@ -114,7 +114,7 @@ int main(int argc, char **argv)
// Read the signature
size = read(0, buffer, MAXSIZE);
- // Verify it for some basic sanity: it needs to start with "object <sha1>\ntag "
+ // Verify it for some basic sanity: it needs to start with "object <sha1>\ntype "
if (verify_tag(buffer, size) < 0)
die("invalid tag signature file");
Index: ls-tree.c
--- k/ls-tree.c (mode:100644)
+++ l/ls-tree.c (mode:100644)
@@ -73,7 +73,7 @@ static int list(unsigned char *sha1)
void *buffer;
unsigned long size;
- buffer = read_tree_with_tree_or_commit_sha1(sha1, &size, 0);
+ buffer = read_object_with_reference(sha1, "tree", &size, 0);
if (!buffer)
die("unable to read sha1 file");
list_recursive(buffer, "tree", size, NULL);
Index: read-tree.c
--- k/read-tree.c (mode:100644)
+++ l/read-tree.c (mode:100644)
@@ -12,7 +12,7 @@ static int unpack_tree(unsigned char *sh
void *buffer;
unsigned long size;
- buffer = read_tree_with_tree_or_commit_sha1(sha1, &size, 0);
+ buffer = read_object_with_reference(sha1, "tree", &size, 0);
if (!buffer)
return -1;
return read_tree(buffer, size, stage);
Index: sha1_file.c
--- k/sha1_file.c (mode:100644)
+++ l/sha1_file.c (mode:100644)
@@ -189,44 +189,49 @@ void * read_sha1_file(const unsigned cha
return NULL;
}
-void *read_tree_with_tree_or_commit_sha1(const unsigned char *sha1,
- unsigned long *size,
- unsigned char *tree_sha1_return)
+void *read_object_with_reference(const unsigned char *sha1,
+ const unsigned char *required_type,
+ unsigned long *size,
+ unsigned char *actual_sha1_return)
{
char type[20];
void *buffer;
unsigned long isize;
- int was_commit = 0;
- unsigned char tree_sha1[20];
+ unsigned char actual_sha1[20];
- buffer = read_sha1_file(sha1, type, &isize);
-
- /*
- * We might have read a commit instead of a tree, in which case
- * we parse out the tree_sha1 and attempt to read from there.
- * (buffer + 5) is because the tree sha1 is always at offset 5
- * in a commit record ("tree ").
- */
- if (buffer &&
- !strcmp(type, "commit") &&
- !get_sha1_hex(buffer + 5, tree_sha1)) {
- free(buffer);
- buffer = read_sha1_file(tree_sha1, type, &isize);
- was_commit = 1;
- }
+ memcpy(actual_sha1, sha1, 20);
+ while (1) {
+ int ref_length = -1;
+ const char *ref_type = NULL;
+
+ buffer = read_sha1_file(actual_sha1, type, &isize);
+ if (!buffer)
+ return NULL;
+ if (!strcmp(type, required_type)) {
+ *size = isize;
+ if (actual_sha1_return)
+ memcpy(actual_sha1_return, actual_sha1, 20);
+ return buffer;
+ }
+ /* Handle references */
+ else if (!strcmp(type, "commit"))
+ ref_type = "tree ";
+ else if (!strcmp(type, "tag"))
+ ref_type = "object ";
+ else {
+ free(buffer);
+ return NULL;
+ }
+ ref_length = strlen(ref_type);
- /*
- * Now do we have something and if so is it a tree?
- */
- if (!buffer || strcmp(type, "tree")) {
- free(buffer);
- return NULL;
+ if (memcmp(buffer, ref_type, ref_length) ||
+ get_sha1_hex(buffer + ref_length, actual_sha1)) {
+ free(buffer);
+ return NULL;
+ }
+ /* Now we have the ID of the referred-to object in
+ * actual_sha1. Check again. */
}
-
- *size = isize;
- if (tree_sha1_return)
- memcpy(tree_sha1_return, was_commit ? tree_sha1 : sha1, 20);
- return buffer;
}
int write_sha1_file(char *buf, unsigned long len, const char *type, unsigned char *returnsha1)
^ permalink raw reply
* [PATCH] Built-in diff driver shows Index: line.
From: Junio C Hamano @ 2005-04-28 19:14 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
As suggested by Linus as a workaround to unconfuse diffstat,
this patch adds Index: line before the diff output the built-in
driver produces.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
diff.c | 2 ++
1 files changed, 2 insertions(+)
# - 04/28 11:20 No need to say diff-tree -p -r in git-export
# + 04/28 11:25 Show Index: line from built-in diff driver.
Index: diff.c
--- k/diff.c (mode:100644)
+++ l/diff.c (mode:100644)
@@ -125,6 +125,8 @@ static void builtin_diff(const char *nam
next_at += snprintf(cmd+next_at, cmd_size-next_at,
diff_arg, input_name_sq[0], input_name_sq[1]);
+ printf("Index: %s\n", name);
+ fflush(NULL);
execlp("/bin/sh","sh", "-c", cmd, NULL);
}
^ permalink raw reply
* [PATCH] diff-tree does not need -r in git-export.c
From: Junio C Hamano @ 2005-04-28 19:13 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
No need to pass -r anymore, since diff-tree -p implies recursive
behaviour these days.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
git-export.c | 2 +-
1 files changed, 1 insertion(+), 1 deletion(-)
# - [PATCH] diff-cache.c compilation warning fix.
# + 04/28 11:20 No need to say diff-tree -p -r in git-export
Index: git-export.c
--- k/git-export.c (mode:100644)
+++ l/git-export.c (mode:100644)
@@ -18,7 +18,7 @@ void show_commit(struct commit *commit)
char *against = sha1_to_hex(commit->parents->item->object.sha1);
printf("\n\n======== diff against %s ========\n", against);
fflush(NULL);
- sprintf(cmdline, "diff-tree -p -r %s %s", against, hex);
+ sprintf(cmdline, "diff-tree -p %s %s", against, hex);
system(cmdline);
}
printf("======== end ========\n\n");
^ permalink raw reply
* Re: Finding file revisions
From: Kay Sievers @ 2005-04-28 19:11 UTC (permalink / raw)
To: Chris Mason; +Cc: Linus Torvalds, git
In-Reply-To: <200504280745.05505.mason@suse.com>
On Thu, 2005-04-28 at 07:45 -0400, Chris Mason wrote:
> On Wednesday 27 April 2005 18:19, Linus Torvalds wrote:
> > On Wed, 27 Apr 2005, Chris Mason wrote:
> > > So, new prog attached. New usage:
> > >
> > > file-changes [-c commit_id] [-s commit_id] file ...
> > >
> > > -c is the commit where you want to start searching
> > > -s is the commit where you want to stop searching
> >
> > Your script will do some funky stuff, because you incorrectly think that
> > the rev-list is sorted linearly. It's not. It's sorted in a rough
> > chronological order, but you really can't do the "last" vs "cur" thing
> > that you do, because two commits after each other in the rev-list listing
> > may well be from two totally different branches, so when you compare one
> > tree against the other, you're really doing something pretty nonsensical.
>
> One more rev that should work as you suggested Here's the example output
> from a cogito changeset with merges. I print the diff-tree lines once for each
> matching parent and then print the commit once. It's very primitive, but
> hopefully some day someone will make a gui with happy clicky buttons
> for changesets and filerevs.
>
> diff-tree -r 2544d7558f0ce94ab9c163f5b67244f71d8c85b8 69eeae031bf5447e99b9274761e2361e8c5a944e
> 618fdb616cebbd2fc9f1cddc0b6b75fd575250a1->3579b5fd1182679a39b83eaaa9dd0e7c970f4545 diff-tree.c
> diff-tree -r 9831d8f86095edde393e495d7a55cab9d35d5d05 69eeae031bf5447e99b9274761e2361e8c5a944e
> 2d2913b6b98ac836b43755b1304d2a838dad87dd->4f01bbbbb3fd0e53e9ce968f167b6dae68fcfa92 Makefile
> cat-file commit 69eeae031bf5447e99b9274761e2361e8c5a944e
> tree 7510dc1b63e9e690ec73952e40a31e43af4b55bc
> parent 2544d7558f0ce94ab9c163f5b67244f71d8c85b8
> parent 9831d8f86095edde393e495d7a55cab9d35d5d05
> author Petr Baudis <pasky@ucw.cz> 1114544917 +0200
> committer Petr Baudis <xpasky@machine.sinus.cz> 1114544917 +0200
Can you confirm this with the kernel tree?
file-changes -c 9acf6597c533f3d5c991f730c6a1be296679018e drivers/usb/core/usb.c
lists the commit:
diff-tree -r 1d66c64c3cee10a465cd3f8bd9191bbeb718f650 c79bea07ec4d3ef087962699fe8b2f6dc5ca7754
f0534ee064901d0108eb7b2b1fcb59a98bb53c2b->c231b4bef314284a168fedb6c5f6c47aec5084fc drivers/usb/core/usb.c
cat-file commit c79bea07ec4d3ef087962699fe8b2f6dc5ca7754
which seems not to have changed the file asked for.
Thanks,
Kay
^ permalink raw reply
* Re: How to get bash to shut up about SIGPIPE?
From: Rene Scharfe @ 2005-04-28 19:03 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Git Mailing List, Petr Baudis
In-Reply-To: <Pine.LNX.4.58.0504281121430.18901@ppc970.osdl.org>
Linus Torvalds schrieb:
> Right now my major gripe with cogito is "cg-log" (which is actually
> the only command I use right now, everything else I just do by hand
> with the raw git archive) is that bash is being an ass about SIGPIPE,
> and when I only look at the top part of the log, ie I do something
> like:
>
> torvalds@ppc970:~/src/cogito> git log | head
I think you misspelled "cg-log". :-D
Doing "cg-log | head" gives me 10 lines of log and nothing else. Maybe
the problem has been fixed between 0.7 and the current version I'm using
(commit ID 49612c471eebd26efe926a71752e254c1cdc382d)?
Rene
^ permalink raw reply
* Re: kernel.org now has gitweb installed
From: Linus Torvalds @ 2005-04-28 18:55 UTC (permalink / raw)
To: David Woodhouse; +Cc: Petr Baudis, H. Peter Anvin, Git Mailing List
In-Reply-To: <1114680199.12012.363.camel@baythorne.infradead.org>
On Thu, 28 Apr 2005, David Woodhouse wrote:
>
> Walk the tree once. For each commit, count the number of _children_.
> That's not hard -- each new commit you find below HEAD has one child to
> start with, then you increment that figure by one each time you find
> another path to the same commit.
>
> When printing, you walk the tree depth-first, remote-parent-first.
No, that really sucks.
Realize that "remote" and "local" parents don't really exist. They have no
meaning. I've considered sorting the parents by the sha1 name, but I've
left that for now.
Anyway, the reason remote and local don't matter is that if somebody else
merges with me, and I just pull the result without having any changes in
my tree, we just "fast-forward" to that other side, because otherwise you
can never "converge" on anything (people merging each others trees would
always create a new commit, for no good reason).
What does that mean? It means that my local tree now became the _remote_
parent, even though it was always local to my tree.
So if you look at remote vs local, you're _guaranteed_ to mess up. It has
no meaning.
So what you can do is:
- if there is one parent, just always walk straight down
- if it's a merge, add the parents _in_date_order_ to the list of things
to do, and then pop the most recent one.
Really. You say that dates don't matter, but they _do_ actually matter a
lot more than "remote/local" does. At least they have meaning.
Linus
^ permalink raw reply
* Re: [PATCH] GIT: Create tar archives of tree on the fly, take two
From: Rene Scharfe @ 2005-04-28 18:51 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git, Joshua T. Corbin, Petr Baudis
In-Reply-To: <Pine.LNX.4.58.0504281121070.18901@ppc970.osdl.org>
On Thu, Apr 28, 2005 at 11:21:29AM -0700, Linus Torvalds wrote:
>
> Yes. Mind sending in a sign-off too, and I'll apply it.
Sure thing. Hope it's the only thing I stupidly forgot. :)
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
Index: Makefile
===================================================================
--- a5d7e40207ee2bd713a15d5bc839168139055f5e/Makefile (mode:100644 sha1:378d5ee9a24a9fb7690bfdf79fd3fde2b9563fad)
+++ 0fa216c80d3ecf45d3de1552c03d95a21f8c2a11/Makefile (mode:100644 sha1:0b330dc3fd05253b8fd20ca4f9e98e411074868f)
@@ -18,7 +18,7 @@
cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \
check-files ls-tree merge-base merge-cache unpack-file git-export \
diff-cache convert-cache http-pull rpush rpull rev-list git-mktag \
- diff-tree-helper
+ diff-tree-helper tar-tree
all: $(PROG)
Index: tar-tree.c
===================================================================
--- /dev/null (tree:a5d7e40207ee2bd713a15d5bc839168139055f5e)
+++ 0fa216c80d3ecf45d3de1552c03d95a21f8c2a11/tar-tree.c (mode:100644 sha1:d078cb5a8d4ab5bc2c774b889b602d179bde39b1)
@@ -0,0 +1,363 @@
+#include <time.h>
+#include "cache.h"
+
+#define RECORDSIZE (512)
+#define BLOCKSIZE (RECORDSIZE * 20)
+
+static const char *tar_tree_usage = "tar-tree <key> [basedir]";
+
+static char block[BLOCKSIZE];
+static unsigned long offset;
+
+static const char *basedir;
+static time_t archive_time;
+
+struct path_prefix {
+ struct path_prefix *prev;
+ const char *name;
+};
+
+/* tries hard to write, either succeeds or dies in the attempt */
+static void reliable_write(void *buf, unsigned long size)
+{
+ while (size > 0) {
+ long ret = write(1, buf, size);
+ if (ret < 0) {
+ if (errno == EAGAIN)
+ continue;
+ if (errno == EPIPE)
+ exit(0);
+ die("tar-tree: %s", strerror(errno));
+ } else if (!ret) {
+ die("tar-tree: disk full?");
+ }
+ size -= ret;
+ buf += ret;
+ }
+}
+
+/* writes out the whole block, but only if it is full */
+static void write_if_needed(void)
+{
+ if (offset == BLOCKSIZE) {
+ reliable_write(block, BLOCKSIZE);
+ offset = 0;
+ }
+}
+
+/*
+ * The end of tar archives is marked by 1024 nul bytes and after that
+ * follows the rest of the block (if any).
+ */
+static void write_trailer(void)
+{
+ memset(block + offset, 0, RECORDSIZE);
+ offset += RECORDSIZE;
+ write_if_needed();
+ memset(block + offset, 0, RECORDSIZE);
+ offset += RECORDSIZE;
+ write_if_needed();
+ if (offset) {
+ memset(block + offset, 0, BLOCKSIZE - offset);
+ reliable_write(block, BLOCKSIZE);
+ offset = 0;
+ }
+}
+
+/*
+ * queues up writes, so that all our write(2) calls write exactly one
+ * full block; pads writes to RECORDSIZE
+ */
+static void write_blocked(void *buf, unsigned long size)
+{
+ unsigned long tail;
+
+ if (offset) {
+ unsigned long chunk = BLOCKSIZE - offset;
+ if (size < chunk)
+ chunk = size;
+ memcpy(block + offset, buf, chunk);
+ size -= chunk;
+ offset += chunk;
+ buf += chunk;
+ write_if_needed();
+ }
+ while (size >= BLOCKSIZE) {
+ reliable_write(buf, BLOCKSIZE);
+ size -= BLOCKSIZE;
+ buf += BLOCKSIZE;
+ }
+ if (size) {
+ memcpy(block + offset, buf, size);
+ buf += size;
+ offset += size;
+ }
+ tail = offset % RECORDSIZE;
+ if (tail) {
+ memset(block + offset, 0, RECORDSIZE - tail);
+ offset += RECORDSIZE - tail;
+ }
+ write_if_needed();
+}
+
+static void append_string(char **p, const char *s)
+{
+ unsigned int len = strlen(s);
+ memcpy(*p, s, len);
+ *p += len;
+}
+
+static void append_char(char **p, char c)
+{
+ **p = c;
+ *p += 1;
+}
+
+static void append_long(char **p, long n)
+{
+ int len = sprintf(*p, "%ld", n);
+ *p += len;
+}
+
+static void append_path_prefix(char **buffer, struct path_prefix *prefix)
+{
+ if (!prefix)
+ return;
+ append_path_prefix(buffer, prefix->prev);
+ append_string(buffer, prefix->name);
+ append_char(buffer, '/');
+}
+
+static unsigned int path_prefix_len(struct path_prefix *prefix)
+{
+ if (!prefix)
+ return 0;
+ return path_prefix_len(prefix->prev) + strlen(prefix->name) + 1;
+}
+
+static void append_path(char **p, int is_dir, const char *basepath,
+ struct path_prefix *prefix, const char *path)
+{
+ if (basepath) {
+ append_string(p, basepath);
+ append_char(p, '/');
+ }
+ append_path_prefix(p, prefix);
+ append_string(p, path);
+ if (is_dir)
+ append_char(p, '/');
+}
+
+static unsigned int path_len(int is_dir, const char *basepath,
+ struct path_prefix *prefix, const char *path)
+{
+ unsigned int len = 0;
+ if (basepath)
+ len += strlen(basepath) + 1;
+ len += path_prefix_len(prefix) + strlen(path);
+ if (is_dir)
+ len++;
+ return len;
+}
+
+static void write_header(const char *, const char *, struct path_prefix *,
+ const char *, unsigned int, unsigned long);
+
+/* stores a pax extended header directly in the block buffer */
+static void write_extended_header(const char *headerfilename, int is_dir,
+ const char *basepath,
+ struct path_prefix *prefix,
+ const char *path, unsigned int namelen)
+{
+ char *records, *p;
+ unsigned int size = 1 + 6 + namelen + 1;
+ if (size > 9)
+ size++;
+ if (size > 99)
+ size++;
+ if (size > RECORDSIZE)
+ die("tar-tree: extended header too big, wtf?");
+ write_header(NULL, NULL, NULL, headerfilename, 0100600, size);
+
+ records = block + offset;
+ memset(records, 0, RECORDSIZE);
+ offset += RECORDSIZE;
+ p = records;
+ append_long(&p, size);
+ append_string(&p, " path=");
+ append_path(&p, is_dir, basepath, prefix, path);
+ append_char(&p, '\n');
+ write_if_needed();
+}
+
+/* stores a ustar header directly in the block buffer */
+static void write_header(const char *sha1, const char *basepath,
+ struct path_prefix *prefix, const char *path,
+ unsigned int mode, unsigned long size)
+{
+ unsigned int namelen;
+ char *p, *header = NULL;
+ unsigned int checksum = 0;
+ int i;
+
+ namelen = path_len(S_ISDIR(mode), basepath, prefix, path);
+ if (namelen > 500) {
+ die("tar-tree: name too log of object %s\n", sha1_to_hex(sha1));
+ } else if (namelen > 100) {
+ char *sha1_hex = sha1_to_hex(sha1);
+ char headerfilename[51];
+ sprintf(headerfilename, "%s.paxheader", sha1_hex);
+ /* the extended header must be written before the normal one */
+ write_extended_header(headerfilename, S_ISDIR(mode), basepath,
+ prefix, path, namelen);
+
+ header = block + offset;
+ memset(header, 0, RECORDSIZE);
+ offset += RECORDSIZE;
+ sprintf(header, "%s.data", sha1_hex);
+ } else {
+ header = block + offset;
+ memset(header, 0, RECORDSIZE);
+ offset += RECORDSIZE;
+ p = header;
+ append_path(&p, S_ISDIR(mode), basepath, prefix, path);
+ }
+
+ if (S_ISDIR(mode))
+ mode |= 0755; /* GIT doesn't store permissions of dirs */
+ sprintf(&header[100], "%07o", mode & 07777);
+
+ /* XXX: should we provide more meaningful info here? */
+ sprintf(&header[108], "%07o", 0); /* uid */
+ sprintf(&header[116], "%07o", 0); /* gid */
+ strncpy(&header[265], "git", 31); /* uname */
+ strncpy(&header[297], "git", 31); /* gname */
+
+ sprintf(&header[124], "%011lo", S_ISDIR(mode) ? 0 : size);
+ sprintf(&header[136], "%011lo", archive_time);
+
+ /* typeflag */
+ if (!sha1)
+ header[156] = 'x'; /* extended header */
+ else
+ header[156] = S_ISDIR(mode) ? '5' : '0';
+
+ memcpy(&header[257], "ustar", 6);
+ memcpy(&header[263], "00", 2);
+
+ printf(&header[329], "%07o", 0); /* devmajor */
+ printf(&header[337], "%07o", 0); /* devminor */
+
+ memset(&header[148], ' ', 8);
+ for (i = 0; i < RECORDSIZE; i++)
+ checksum += header[i];
+ sprintf(&header[148], "%07o", checksum & 0x1fffff);
+
+ write_if_needed();
+}
+
+static void traverse_tree(void *buffer, unsigned long size,
+ struct path_prefix *prefix)
+{
+ struct path_prefix this_prefix;
+ this_prefix.prev = prefix;
+
+ while (size) {
+ int namelen = strlen(buffer)+1;
+ void *eltbuf;
+ char elttype[20];
+ unsigned long eltsize;
+ unsigned char *sha1 = buffer + namelen;
+ char *path = strchr(buffer, ' ') + 1;
+ unsigned int mode;
+
+ if (size < namelen + 20 || sscanf(buffer, "%o", &mode) != 1)
+ die("corrupt 'tree' file");
+ buffer = sha1 + 20;
+ size -= namelen + 20;
+
+ eltbuf = read_sha1_file(sha1, elttype, &eltsize);
+ if (!eltbuf)
+ die("cannot read %s", sha1_to_hex(sha1));
+ write_header(sha1, basedir, prefix, path, mode, eltsize);
+ if (!strcmp(elttype, "tree")) {
+ this_prefix.name = path;
+ traverse_tree(eltbuf, eltsize, &this_prefix);
+ } else if (!strcmp(elttype, "blob")) {
+ write_blocked(eltbuf, eltsize);
+ }
+ free(eltbuf);
+ }
+}
+
+/* get commit time from committer line of commit object */
+time_t commit_time(const unsigned char *sha1)
+{
+ char type[20];
+ void *buffer;
+ unsigned long size;
+ time_t result = 0;
+
+ buffer = read_sha1_file(sha1, type, &size);
+ if (buffer) {
+ char *p = buffer;
+ while (size > 0) {
+ char *endp = memchr(p, '\n', size);
+ if (!endp || endp == p)
+ break;
+ *endp = '\0';
+ if (endp - p > 10 && !memcmp(p, "committer ", 10)) {
+ char *nump = strrchr(p, '>');
+ if (!nump)
+ break;
+ nump++;
+ result = strtoul(nump, &endp, 10);
+ if (*endp != ' ')
+ result = 0;
+ break;
+ }
+ size -= endp - p - 1;
+ p = endp + 1;
+ }
+ free(buffer);
+ }
+ return result;
+}
+
+int main(int argc, char **argv)
+{
+ unsigned char sha1[20];
+ void *buffer;
+ unsigned long size;
+ unsigned char tree_sha1[20];
+
+ switch (argc) {
+ case 3:
+ basedir = argv[2];
+ /* FALLTHROUGH */
+ case 2:
+ if (get_sha1_hex(argv[1], sha1) < 0)
+ usage(tar_tree_usage);
+ break;
+ default:
+ usage(tar_tree_usage);
+ }
+
+ sha1_file_directory = getenv(DB_ENVIRONMENT);
+ if (!sha1_file_directory)
+ sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
+
+ buffer = read_tree_with_tree_or_commit_sha1(sha1, &size, tree_sha1);
+ if (!buffer)
+ die("unable to read sha1 file");
+ if (memcmp(sha1, tree_sha1, 20)) /* is sha1 a commit object? */
+ archive_time = commit_time(sha1);
+ if (!archive_time)
+ archive_time = time(NULL);
+ if (basedir)
+ write_header("0", NULL, NULL, basedir, 040755, 0);
+ traverse_tree(buffer, size, NULL);
+ free(buffer);
+ write_trailer();
+ return 0;
+}
^ permalink raw reply
* How to get bash to shut up about SIGPIPE?
From: Linus Torvalds @ 2005-04-28 18:28 UTC (permalink / raw)
To: Git Mailing List, Petr Baudis
Right now my major gripe with cogito is "cg-log" (which is actually the
only command I use right now, everything else I just do by hand with the
raw git archive) is that bash is being an ass about SIGPIPE, and when I
only look at the top part of the log, ie I do something like:
torvalds@ppc970:~/src/cogito> git log | head
it spews out the ten first lines of the log, and then it spews about a
million lines (well, 20, but anyway) of crap:
/home/torvalds/bin/cg-log: line 87: 6338 Done echo -n $color$key $rest
6339 Broken pipe | sed "s/>.*/> ${pdate/+0000/$tz}/"
/home/torvalds/bin/cg-log: line 87: 6328 Done cat-file commit $commit
6329 Broken pipe | while read key rest; do
case "$key" in
"author" | "committer")
if [ "$key" = "author" ]; then
color="$colauthor";
else
color="$colcommitter";
fi; date=(${rest#*> }); sec=${date[0]}; tz=${date[1]}; dtz=${tz/+/}; lsec=$(expr $dtz / 100 \* 3600 + $dtz % 100 \* 60 + $sec); pdate="$(date -Rud "1970-01-01 UTC + $lsec sec" 2>/dev/null)"; if [ "$pdate" ]; then
echo -n $color$key $rest | sed "s/>.*/> ${pdate/+0000/$tz}/"; echo $coldefault;
else
echo $color$key $rest $coldefault;
fi
;;
"")
echo; sed -re '
/
*Signed-off-by:.*/Is//'$colsignoff'&'$coldefault'/
s/./ &/
'
;;
*)
echo $colheader$key $rest $coldefault
;;
esac;
done
which is just incredibly annoying, since it makes the ten lines I actually
_wanted_ to get scroll off the screen..
Damn bash. What's the magic incantation that says SHUT UP!?
Linus
^ permalink raw reply
* Re: [PATCH] GIT: Create tar archives of tree on the fly, take two
From: Linus Torvalds @ 2005-04-28 18:21 UTC (permalink / raw)
To: Rene Scharfe; +Cc: git, Joshua T. Corbin, Petr Baudis
In-Reply-To: <20050428174038.GA24352@lsrfire.ath.cx>
On Thu, 28 Apr 2005, Rene Scharfe wrote:
>
> I think it fits nicely into the core toolset of git. What do you think?
Yes. Mind sending in a sign-off too, and I'll apply it.
Linus
^ permalink raw reply
* [PATCH] GIT: Create tar archives of tree on the fly, take two
From: Rene Scharfe @ 2005-04-28 17:40 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git, Joshua T. Corbin, Petr Baudis
Hi Linus,
here's an improved version of tar-tree, a streaming archive creator for
GIT. The major added feature is blocking; all write(2) calls now have a
size of 10240, just as GNU tar (and tape drives) likes them. The
buffering overhead does not seem to degrade performance because most
files in the repositories I tested this with are smaller than 10KB, so
we need fewer system calls.
File names are still restricted to 500 bytes and the archive format
currently only allows for files up to 8GB. Both restrictions can be
lifted if need be with more pax extended headers.
The archive format used is the pax interchange format, i.e. POSIX tar
format. It can be read by (and created with) GNU tar. If I read the
specs correctly tar-tree should now be standards compliant (modulo
bugs).
Because it streams the archive (think ls-tree merged with cat-file),
tar-tree doesn't need to create any temporary files. That makes it
quite fast.
It accepts tree IDs and commit IDs as first parameter. In the latter
case tar-tree tries to get the commit date out of the committer line.
Else all files in the archive are time-stamped with the current time.
An optional second parameter is used as a path prefix for all files in
the archive. Example:
$ tar-tree a2755a80f40e5794ddc20e00f781af9d6320fafb \
linux-2.6.12-rc3 | bzip9 -9 > linux-2.6.12-rc3.tar.bz2
I think it fits nicely into the core toolset of git. What do you think?
Thanks,
Rene
Index: Makefile
===================================================================
--- a5d7e40207ee2bd713a15d5bc839168139055f5e/Makefile (mode:100644 sha1:378d5ee9a24a9fb7690bfdf79fd3fde2b9563fad)
+++ 0fa216c80d3ecf45d3de1552c03d95a21f8c2a11/Makefile (mode:100644 sha1:0b330dc3fd05253b8fd20ca4f9e98e411074868f)
@@ -18,7 +18,7 @@
cat-file fsck-cache checkout-cache diff-tree rev-tree show-files \
check-files ls-tree merge-base merge-cache unpack-file git-export \
diff-cache convert-cache http-pull rpush rpull rev-list git-mktag \
- diff-tree-helper
+ diff-tree-helper tar-tree
all: $(PROG)
Index: tar-tree.c
===================================================================
--- /dev/null (tree:a5d7e40207ee2bd713a15d5bc839168139055f5e)
+++ 0fa216c80d3ecf45d3de1552c03d95a21f8c2a11/tar-tree.c (mode:100644 sha1:d078cb5a8d4ab5bc2c774b889b602d179bde39b1)
@@ -0,0 +1,363 @@
+#include <time.h>
+#include "cache.h"
+
+#define RECORDSIZE (512)
+#define BLOCKSIZE (RECORDSIZE * 20)
+
+static const char *tar_tree_usage = "tar-tree <key> [basedir]";
+
+static char block[BLOCKSIZE];
+static unsigned long offset;
+
+static const char *basedir;
+static time_t archive_time;
+
+struct path_prefix {
+ struct path_prefix *prev;
+ const char *name;
+};
+
+/* tries hard to write, either succeeds or dies in the attempt */
+static void reliable_write(void *buf, unsigned long size)
+{
+ while (size > 0) {
+ long ret = write(1, buf, size);
+ if (ret < 0) {
+ if (errno == EAGAIN)
+ continue;
+ if (errno == EPIPE)
+ exit(0);
+ die("tar-tree: %s", strerror(errno));
+ } else if (!ret) {
+ die("tar-tree: disk full?");
+ }
+ size -= ret;
+ buf += ret;
+ }
+}
+
+/* writes out the whole block, but only if it is full */
+static void write_if_needed(void)
+{
+ if (offset == BLOCKSIZE) {
+ reliable_write(block, BLOCKSIZE);
+ offset = 0;
+ }
+}
+
+/*
+ * The end of tar archives is marked by 1024 nul bytes and after that
+ * follows the rest of the block (if any).
+ */
+static void write_trailer(void)
+{
+ memset(block + offset, 0, RECORDSIZE);
+ offset += RECORDSIZE;
+ write_if_needed();
+ memset(block + offset, 0, RECORDSIZE);
+ offset += RECORDSIZE;
+ write_if_needed();
+ if (offset) {
+ memset(block + offset, 0, BLOCKSIZE - offset);
+ reliable_write(block, BLOCKSIZE);
+ offset = 0;
+ }
+}
+
+/*
+ * queues up writes, so that all our write(2) calls write exactly one
+ * full block; pads writes to RECORDSIZE
+ */
+static void write_blocked(void *buf, unsigned long size)
+{
+ unsigned long tail;
+
+ if (offset) {
+ unsigned long chunk = BLOCKSIZE - offset;
+ if (size < chunk)
+ chunk = size;
+ memcpy(block + offset, buf, chunk);
+ size -= chunk;
+ offset += chunk;
+ buf += chunk;
+ write_if_needed();
+ }
+ while (size >= BLOCKSIZE) {
+ reliable_write(buf, BLOCKSIZE);
+ size -= BLOCKSIZE;
+ buf += BLOCKSIZE;
+ }
+ if (size) {
+ memcpy(block + offset, buf, size);
+ buf += size;
+ offset += size;
+ }
+ tail = offset % RECORDSIZE;
+ if (tail) {
+ memset(block + offset, 0, RECORDSIZE - tail);
+ offset += RECORDSIZE - tail;
+ }
+ write_if_needed();
+}
+
+static void append_string(char **p, const char *s)
+{
+ unsigned int len = strlen(s);
+ memcpy(*p, s, len);
+ *p += len;
+}
+
+static void append_char(char **p, char c)
+{
+ **p = c;
+ *p += 1;
+}
+
+static void append_long(char **p, long n)
+{
+ int len = sprintf(*p, "%ld", n);
+ *p += len;
+}
+
+static void append_path_prefix(char **buffer, struct path_prefix *prefix)
+{
+ if (!prefix)
+ return;
+ append_path_prefix(buffer, prefix->prev);
+ append_string(buffer, prefix->name);
+ append_char(buffer, '/');
+}
+
+static unsigned int path_prefix_len(struct path_prefix *prefix)
+{
+ if (!prefix)
+ return 0;
+ return path_prefix_len(prefix->prev) + strlen(prefix->name) + 1;
+}
+
+static void append_path(char **p, int is_dir, const char *basepath,
+ struct path_prefix *prefix, const char *path)
+{
+ if (basepath) {
+ append_string(p, basepath);
+ append_char(p, '/');
+ }
+ append_path_prefix(p, prefix);
+ append_string(p, path);
+ if (is_dir)
+ append_char(p, '/');
+}
+
+static unsigned int path_len(int is_dir, const char *basepath,
+ struct path_prefix *prefix, const char *path)
+{
+ unsigned int len = 0;
+ if (basepath)
+ len += strlen(basepath) + 1;
+ len += path_prefix_len(prefix) + strlen(path);
+ if (is_dir)
+ len++;
+ return len;
+}
+
+static void write_header(const char *, const char *, struct path_prefix *,
+ const char *, unsigned int, unsigned long);
+
+/* stores a pax extended header directly in the block buffer */
+static void write_extended_header(const char *headerfilename, int is_dir,
+ const char *basepath,
+ struct path_prefix *prefix,
+ const char *path, unsigned int namelen)
+{
+ char *records, *p;
+ unsigned int size = 1 + 6 + namelen + 1;
+ if (size > 9)
+ size++;
+ if (size > 99)
+ size++;
+ if (size > RECORDSIZE)
+ die("tar-tree: extended header too big, wtf?");
+ write_header(NULL, NULL, NULL, headerfilename, 0100600, size);
+
+ records = block + offset;
+ memset(records, 0, RECORDSIZE);
+ offset += RECORDSIZE;
+ p = records;
+ append_long(&p, size);
+ append_string(&p, " path=");
+ append_path(&p, is_dir, basepath, prefix, path);
+ append_char(&p, '\n');
+ write_if_needed();
+}
+
+/* stores a ustar header directly in the block buffer */
+static void write_header(const char *sha1, const char *basepath,
+ struct path_prefix *prefix, const char *path,
+ unsigned int mode, unsigned long size)
+{
+ unsigned int namelen;
+ char *p, *header = NULL;
+ unsigned int checksum = 0;
+ int i;
+
+ namelen = path_len(S_ISDIR(mode), basepath, prefix, path);
+ if (namelen > 500) {
+ die("tar-tree: name too log of object %s\n", sha1_to_hex(sha1));
+ } else if (namelen > 100) {
+ char *sha1_hex = sha1_to_hex(sha1);
+ char headerfilename[51];
+ sprintf(headerfilename, "%s.paxheader", sha1_hex);
+ /* the extended header must be written before the normal one */
+ write_extended_header(headerfilename, S_ISDIR(mode), basepath,
+ prefix, path, namelen);
+
+ header = block + offset;
+ memset(header, 0, RECORDSIZE);
+ offset += RECORDSIZE;
+ sprintf(header, "%s.data", sha1_hex);
+ } else {
+ header = block + offset;
+ memset(header, 0, RECORDSIZE);
+ offset += RECORDSIZE;
+ p = header;
+ append_path(&p, S_ISDIR(mode), basepath, prefix, path);
+ }
+
+ if (S_ISDIR(mode))
+ mode |= 0755; /* GIT doesn't store permissions of dirs */
+ sprintf(&header[100], "%07o", mode & 07777);
+
+ /* XXX: should we provide more meaningful info here? */
+ sprintf(&header[108], "%07o", 0); /* uid */
+ sprintf(&header[116], "%07o", 0); /* gid */
+ strncpy(&header[265], "git", 31); /* uname */
+ strncpy(&header[297], "git", 31); /* gname */
+
+ sprintf(&header[124], "%011lo", S_ISDIR(mode) ? 0 : size);
+ sprintf(&header[136], "%011lo", archive_time);
+
+ /* typeflag */
+ if (!sha1)
+ header[156] = 'x'; /* extended header */
+ else
+ header[156] = S_ISDIR(mode) ? '5' : '0';
+
+ memcpy(&header[257], "ustar", 6);
+ memcpy(&header[263], "00", 2);
+
+ printf(&header[329], "%07o", 0); /* devmajor */
+ printf(&header[337], "%07o", 0); /* devminor */
+
+ memset(&header[148], ' ', 8);
+ for (i = 0; i < RECORDSIZE; i++)
+ checksum += header[i];
+ sprintf(&header[148], "%07o", checksum & 0x1fffff);
+
+ write_if_needed();
+}
+
+static void traverse_tree(void *buffer, unsigned long size,
+ struct path_prefix *prefix)
+{
+ struct path_prefix this_prefix;
+ this_prefix.prev = prefix;
+
+ while (size) {
+ int namelen = strlen(buffer)+1;
+ void *eltbuf;
+ char elttype[20];
+ unsigned long eltsize;
+ unsigned char *sha1 = buffer + namelen;
+ char *path = strchr(buffer, ' ') + 1;
+ unsigned int mode;
+
+ if (size < namelen + 20 || sscanf(buffer, "%o", &mode) != 1)
+ die("corrupt 'tree' file");
+ buffer = sha1 + 20;
+ size -= namelen + 20;
+
+ eltbuf = read_sha1_file(sha1, elttype, &eltsize);
+ if (!eltbuf)
+ die("cannot read %s", sha1_to_hex(sha1));
+ write_header(sha1, basedir, prefix, path, mode, eltsize);
+ if (!strcmp(elttype, "tree")) {
+ this_prefix.name = path;
+ traverse_tree(eltbuf, eltsize, &this_prefix);
+ } else if (!strcmp(elttype, "blob")) {
+ write_blocked(eltbuf, eltsize);
+ }
+ free(eltbuf);
+ }
+}
+
+/* get commit time from committer line of commit object */
+time_t commit_time(const unsigned char *sha1)
+{
+ char type[20];
+ void *buffer;
+ unsigned long size;
+ time_t result = 0;
+
+ buffer = read_sha1_file(sha1, type, &size);
+ if (buffer) {
+ char *p = buffer;
+ while (size > 0) {
+ char *endp = memchr(p, '\n', size);
+ if (!endp || endp == p)
+ break;
+ *endp = '\0';
+ if (endp - p > 10 && !memcmp(p, "committer ", 10)) {
+ char *nump = strrchr(p, '>');
+ if (!nump)
+ break;
+ nump++;
+ result = strtoul(nump, &endp, 10);
+ if (*endp != ' ')
+ result = 0;
+ break;
+ }
+ size -= endp - p - 1;
+ p = endp + 1;
+ }
+ free(buffer);
+ }
+ return result;
+}
+
+int main(int argc, char **argv)
+{
+ unsigned char sha1[20];
+ void *buffer;
+ unsigned long size;
+ unsigned char tree_sha1[20];
+
+ switch (argc) {
+ case 3:
+ basedir = argv[2];
+ /* FALLTHROUGH */
+ case 2:
+ if (get_sha1_hex(argv[1], sha1) < 0)
+ usage(tar_tree_usage);
+ break;
+ default:
+ usage(tar_tree_usage);
+ }
+
+ sha1_file_directory = getenv(DB_ENVIRONMENT);
+ if (!sha1_file_directory)
+ sha1_file_directory = DEFAULT_DB_ENVIRONMENT;
+
+ buffer = read_tree_with_tree_or_commit_sha1(sha1, &size, tree_sha1);
+ if (!buffer)
+ die("unable to read sha1 file");
+ if (memcmp(sha1, tree_sha1, 20)) /* is sha1 a commit object? */
+ archive_time = commit_time(sha1);
+ if (!archive_time)
+ archive_time = time(NULL);
+ if (basedir)
+ write_header("0", NULL, NULL, basedir, 040755, 0);
+ traverse_tree(buffer, size, NULL);
+ free(buffer);
+ write_trailer();
+ return 0;
+}
^ permalink raw reply
* Re: [PATCH] add a diff-files command (revised and cleaned up)
From: Nicolas Pitre @ 2005-04-28 17:35 UTC (permalink / raw)
To: Linus Torvalds; +Cc: Junio C Hamano, git
In-Reply-To: <Pine.LNX.4.58.0504280950340.18901@ppc970.osdl.org>
On Thu, 28 Apr 2005, Linus Torvalds wrote:
> HOWEVER, there clearly is a separate problem, which is what "show-files"
> currently does very badly (and not at all in some cases), which is the
> "ok, what about the _other_ files?"
Right. And that's the problem I'm trying to solve.
What about this patch then?
=====
Give show-files the ability to process exclusion pattern.
This can be used with the famous dontdiff file as follows to find out
about uncommitted files just like dontdiff is used with the diff
command:
show-files --others --exclude-from=dontdiff
and the exclude list can be reversed with the --ignore switch.
Signed-off-by: Nicolas Pitre <nico@cam.org>
--- a/show-files.c
+++ b/show-files.c
@@ -6,6 +6,7 @@
* Copyright (C) Linus Torvalds, 2005
*/
#include <dirent.h>
+#include <fnmatch.h>
#include "cache.h"
@@ -17,6 +18,70 @@ static int show_stage = 0;
static int show_unmerged = 0;
static int line_terminator = '\n';
+static int nr_excludes;
+static const char **excludes;
+static int excludes_alloc;
+
+static void add_exclude(const char *string)
+{
+ if (nr_excludes == excludes_alloc) {
+ excludes_alloc = alloc_nr(excludes_alloc);
+ excludes = realloc(excludes, excludes_alloc*sizeof(char *));
+ }
+ excludes[nr_excludes++] = string;
+}
+
+static void add_excludes_from_file(const char *fname)
+{
+ int fd, i;
+ long size;
+ char *buf, *entry;
+
+ fd = open(fname, O_RDONLY);
+ if (fd < 0)
+ goto err;
+ size = lseek(fd, 0, SEEK_END);
+ if (size < 0)
+ goto err;
+ lseek(fd, 0, SEEK_SET);
+ if (size == 0) {
+ close(fd);
+ return;
+ }
+ buf = xmalloc(size);
+ if (read(fd, buf, size) != size)
+ goto err;
+ close(fd);
+
+ entry = buf;
+ for (i = 0; i < size; i++) {
+ if (buf[i] == '\n') {
+ if (entry != buf + i) {
+ buf[i] = 0;
+ add_exclude(entry);
+ }
+ entry = buf + i + 1;
+ }
+ }
+ return;
+
+err: perror(fname);
+ exit(1);
+}
+
+static int excluded(const char *pathname)
+{
+ int i;
+ if (nr_excludes) {
+ const char *basename = strrchr(pathname, '/');
+ basename = (basename) ? basename+1 : pathname;
+ for (i = 0; i < nr_excludes; i++)
+ if (fnmatch(excludes[i], basename, 0) == 0)
+ return 1;
+ }
+ return 0;
+}
+
static const char **dir;
static int nr_dir;
static int dir_alloc;
@@ -59,6 +124,8 @@ static void read_directory(const char *p
if (de->d_name[0] == '.')
continue;
+ if (excluded(de->d_name) != show_ignored)
+ continue;
len = strlen(de->d_name);
memcpy(fullname + baselen, de->d_name, len+1);
@@ -101,17 +168,17 @@ static void show_files(void)
int i;
/* For cached/deleted files we don't need to even do the readdir */
- if (show_others | show_ignored) {
+ if (show_others) {
read_directory(".", "", 0);
qsort(dir, nr_dir, sizeof(char *), cmp_name);
- }
- if (show_others) {
for (i = 0; i < nr_dir; i++)
printf("%s%c", dir[i], line_terminator);
}
if (show_cached | show_stage) {
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
+ if (excluded(ce->name) != show_ignored)
+ continue;
if (show_unmerged && !ce_stage(ce))
continue;
if (!show_stage)
@@ -130,14 +197,13 @@ static void show_files(void)
for (i = 0; i < active_nr; i++) {
struct cache_entry *ce = active_cache[i];
struct stat st;
+ if (excluded(ce->name) != show_ignored)
+ continue;
if (!stat(ce->name, &st))
continue;
printf("%s%c", ce->name, line_terminator);
}
}
- if (show_ignored) {
- /* We don't have any "ignore" list yet */
- }
}
int main(int argc, char **argv)
@@ -179,11 +245,34 @@ int main(int argc, char **argv)
continue;
}
- usage("show-files [-z] (--[cached|deleted|others|ignored|stage])*");
+ if (!strcmp(arg, "-x") && i+1 < argc) {
+ add_exclude(argv[++i]);
+ continue;
+ }
+ if (!strncmp(arg, "--exclude=", 10)) {
+ add_exclude(arg+10);
+ continue;
+ }
+ if (!strcmp(arg, "-X") && i+1 < argc) {
+ add_excludes_from_file(argv[++i]);
+ continue;
+ }
+ if (!strncmp(arg, "--exclude-from=", 15)) {
+ add_excludes_from_file(arg+15);
+ continue;
+ }
+
+ usage("show-files [-z] (--[cached|deleted|others|stage])* "
+ "[ --ignored [--exclude=<pattern>] [--exclude-from=<file>) ]");
+ }
+
+ if (show_ignored && !nr_excludes) {
+ fprintf(stderr, "%s: --ignored needs some exclude pattern\n", argv[0]);
+ exit(1);
}
/* With no flags, we default to showing the cached files */
- if (!(show_stage | show_deleted | show_others | show_ignored | show_unmerged))
+ if (!(show_stage | show_deleted | show_others | show_unmerged))
show_cached = 1;
read_cache();
^ permalink raw reply
* Re: Finding file revisions
From: Thomas Glanzmann @ 2005-04-28 17:22 UTC (permalink / raw)
To: git
In-Reply-To: <12c511ca050428101070e12e74@mail.gmail.com>
Hello,
> Looks very useful. Would it be possible to display the date (from the
> commit) instead of the 40-hex-char blobname (but have the link still
> point to the blob). Like this:
First of all there is a date on the site and second I think the sha1
hash much more useful than the date.
Thomas
^ permalink raw reply
* Re: [PATCH 0/3] Merge leftover bits
From: Junio C Hamano @ 2005-04-28 17:20 UTC (permalink / raw)
To: Linus Torvalds; +Cc: git
In-Reply-To: <Pine.LNX.4.58.0504281016390.18901@ppc970.osdl.org>
>>>>> "LT" == Linus Torvalds <torvalds@osdl.org> writes:
LT> On Thu, 28 Apr 2005, Junio C Hamano wrote:
>>
>> This series is a resend of various fixes rediffed against your
>> HEAD this morning.
LT> I actually just applied (and pushed out) your older versions.
What I prepared and were going to send are just a rediff against
2f97813870c73a89b673ea7882f2a078d25c2dcd which did not have
these three bits, so if you have not forgotten about them then
it's fine. I'll not re-send them.
LT> Can you check my current tree, especially if you made some
LT> improvements in the meantime?
No improvements in the meantime but I'll let you know if I see
any problems.
^ permalink raw reply
* Re: [PATCH] add a diff-files command
From: Junio C Hamano @ 2005-04-28 17:16 UTC (permalink / raw)
To: Nicolas Pitre; +Cc: Linus Torvalds, git
In-Reply-To: <Pine.LNX.4.62.0504281238130.14033@localhost.localdomain>
>>>>> "NP" == Nicolas Pitre <nico@cam.org> writes:
NP> ... And yesterday I realized that the (currently unimplemented)
NP> --ignore switch to show-files, combined with the exclusion pattern list,
NP> whould be more logical than teaching show-diff (which I still think is a
NP> misnamer in the context of the other diff tools) about files unknown to
NP> the cache. The patch to show-files is also much smaller and logical.
I agree wholeheartedly with both counts. (1) Linus and I
discussed briefly about renaming show-diff to diff-files but it
is on hold, waiting for a big wholesale rename. (2) the logical
place for the -X and -x is "show-files --ignore".
^ permalink raw reply
* Re: [PATCH 0/3] Merge leftover bits
From: Linus Torvalds @ 2005-04-28 17:17 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git
In-Reply-To: <7voeby968l.fsf@assigned-by-dhcp.cox.net>
On Thu, 28 Apr 2005, Junio C Hamano wrote:
>
> This series is a resend of various fixes rediffed against your
> HEAD this morning.
I actually just applied (and pushed out) your older versions.
Can you check my current tree, especially if you made some improvements in
the meantime?
Linus
^ permalink raw reply
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