From: Peter Kjellerstedt Date: Fri, 07 May 2010 16:35:41 GMT Subject: RE: Any way to get complete diff up to a tag? Message-ID: In-Reply-To: > -----Original Message----- > From: git-owner@vger.kernel.org [mailto:git-owner@vger.kernel.org] On > Behalf Of Linus Torvalds > Sent: den 6 maj 2010 19:09 > To: Peter Kjellerstedt > Cc: Johannes Sixt; git@vger.kernel.org; Björn Steinbrink > Subject: RE: Any way to get complete diff up to a tag? > > On Thu, 6 May 2010, Peter Kjellerstedt wrote: > > > > Since the 4b825dc642cb6eb9a060e54bf8d69288fbee4904 SHA1 is somewhat > > cumbersome to remember, wouldn't it be an idea to give it some kind > > of alias or mnemonic? E.g., something like @~ (or some other mix of > > odd characters which do not clash with all the other similar > > constructs already used for references). > > Well, you don't strictly speaking have to "remember" it, you can always > just re-generate it. The most straightforward way to do that is > probably > > git hash-object -t tree --stdin < /dev/null Thank you, that is good to know. > although I admit that maybe we could have some syntax for "git diff" > that would do the "diff against empty tree" automatically. It does > seem to be conceptually a reasonable thing to do. > > For example, right now if you give "git diff" a single SHA1, it will > work against the working tree. Except if you add "--cached", to say > that you want the diff against the index. I don't think it would be in > any way _wrong_ to make "--root" mean that you want it against an > empty tree. > > [ We already accept "--root", but it has no meaning for "git diff" > with a single SHA1. It matters for showing the root commit for > 'git-diff-tree'. > > And means something totally different for git-format-patch ] > > So we certainly _could_ do something like > > git diff --root I went ahead and implemented support for --root as an option to git diff (patch attached for reference). However, I then realized that there are probably more commands that would benefit from the same support, e.g., git diff-index. Then I thought about git diff-tree and realized that it could also benefit from my version of --root, but as you mentioned above, it already has a --root option with a different semantic... I also figured it would be a hassle for me to find all commands who can use a --root option, not knowing the internals of git well enough yet. So I then went back to my original idea of making an alias for the empty tree, and came up with a two line patch which I will send as a separate patch, and see what you guys think of the idea. > and make it do what you want. That said, the "empty tree" thing works > for all versions of git (well, some older versions of git need the > actual object, but you could always use "-w" on that git-hash-object > command line, and then it really should work for every git version). > > Linus //Peter From d9d482db98aa3ff3545cf66a8f851cc459b0eacd Mon Sep 17 00:00:00 2001 From: Peter Kjellerstedt Date: Fri, 7 May 2010 17:11:19 +0200 Subject: [PATCH] diff: Make git diff support the --root option Using 'git diff --root ' will give all the changes between the empty tree and . It is also possible to use 'git diff --root --cached' to get all changes between the empty tree and the current index. Signed-off-by: Peter Kjellerstedt --- builtin/diff.c | 28 ++++++++++++++++++++++------ revision.c | 12 ++++++++++++ revision.h | 1 + 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/builtin/diff.c b/builtin/diff.c index ffcdd05..8da59dd 100644 --- a/builtin/diff.c +++ b/builtin/diff.c @@ -253,6 +253,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix) const char *path = NULL; struct blobinfo blob[2]; int nongit; + int cached = 0; int result = 0; /* @@ -316,10 +317,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix) setup_pager(); /* - * Do we have --cached and not have a pending object, then - * default to HEAD by hand. Eek. + * If we have --cached and/or --root we may need to add the empty tree + * or HEAD by hand. Eek. */ - if (!rev.pending.nr) { + if (rev.pending.nr <= 1) { int i; for (i = 1; i < argc; i++) { const char *arg = argv[i]; @@ -327,14 +328,29 @@ int cmd_diff(int argc, const char **argv, const char *prefix) break; else if (!strcmp(arg, "--cached") || !strcmp(arg, "--staged")) { - add_head_to_pending(&rev); - if (!rev.pending.nr) - die("No HEAD commit to compare with (yet)"); + cached = 1; break; } } } + if (!rev.pending.nr) { + if (rev.show_root_diff) { + add_empty_tree_to_pending(&rev); + if (!rev.pending.nr) + die("No empty tree to compare with"); + } else if (cached) { + add_head_to_pending(&rev); + if (!rev.pending.nr) + die("No HEAD commit to compare with (yet)"); + } + } else if (rev.pending.nr == 1 && rev.show_root_diff && !cached) { + add_empty_tree_to_pending(&rev); + if (rev.pending.nr != 2) + die("No empty tree to compare with"); + rev.diffopt.flags ^= DIFF_OPT_REVERSE_DIFF; + } + for (i = 0; i < rev.pending.nr; i++) { struct object_array_entry *list = rev.pending.objects+i; struct object *obj = list->item; diff --git a/revision.c b/revision.c index f4b8b38..c3a78dc 100644 --- a/revision.c +++ b/revision.c @@ -169,6 +169,18 @@ void add_head_to_pending(struct rev_info *revs) add_pending_object(revs, obj, "HEAD"); } +void add_empty_tree_to_pending(struct rev_info *revs) +{ + unsigned char sha1[20]; + struct object *obj; + if (get_sha1(EMPTY_TREE_SHA1_HEX, sha1)) + return; + obj = parse_object(sha1); + if (!obj) + return; + add_pending_object(revs, obj, EMPTY_TREE_SHA1_HEX); +} + static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags) { struct object *object; diff --git a/revision.h b/revision.h index 568f1c9..e1a7d9d 100644 --- a/revision.h +++ b/revision.h @@ -176,6 +176,7 @@ extern void add_object(struct object *obj, extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name); extern void add_head_to_pending(struct rev_info *); +extern void add_empty_tree_to_pending(struct rev_info *revs); enum commit_action { commit_ignore, -- 1.7.0.1