[RFC/PATCH] extend meaning of "--root" option to index comparisons

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The "--root" option generally means "treat any commits
without parents as a big creation event". This extends the
meaning to make an index comparison against a non-existant
HEAD into a big creation event. In other words, "if this
index _were_ to become a commit, this is how we would show
it with --root."

Specifically, we cover the case of

  git diff --cached --root

to show either the diff between the index and HEAD, or if
there is no HEAD, show the diff against the empty tree.
This can simplify calling scripts which must otherwise
special-case the initial commit when showing the index
status.

We intentionally don't cover:

  - git diff --cached --root HEAD

    The user has specifically asked for HEAD, which doesn't
    exist.

  - git diff-index

    The user is required to specify a tree-ish to
    diff-index; if that tree-ish doesn't exist, we should
    report an error.

Signed-off-by: Jeff King <peff@xxxxxxxx>
---
On Tue, Sep 16, 2008 at 02:21:05AM -0400, Jeff King wrote:

> Right, that was what I meant by "incomplete". I think there are several
> other cases where giving "--root" would have expected behavior but is
> currently ignored. I'll take a closer look, but I probably won't have
> time for a few days.

Actually, I wasn't able to find any more cases. I don't think it makes
sense to override the behavior when an explicit tree-ish is given, so
that cuts out the two places mentioned above. Though I think
that scripts using this might prefer the plumbing
diff-index, so maybe there is a better way to support this
(e.g., if --root is specified without a tree-ish, assume
HEAD or empty tree).

diff-tree already handles --root itself. And there is no way to my
knowledge to provoke the same kind of "show the diff against its parent"
behavior via git-diff, since a single tree-ish there means "diff against
the working tree".

And of course for diff-files, such an option makes no sense.

Can you think of any other cases?

 builtin-diff.c       |    7 +++++--
 revision.c           |   17 ++++++++++++++---
 revision.h           |    1 +
 t/t4030-diff-root.sh |   21 +++++++++++++++++++++
 4 files changed, 41 insertions(+), 5 deletions(-)
 create mode 100755 t/t4030-diff-root.sh

diff --git a/builtin-diff.c b/builtin-diff.c
index 037c303..0a1efb5 100644
--- a/builtin-diff.c
+++ b/builtin-diff.c
@@ -315,8 +315,11 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
 				break;
 			else if (!strcmp(arg, "--cached")) {
 				add_head_to_pending(&rev);
-				if (!rev.pending.nr)
-					die("No HEAD commit to compare with (yet)");
+				if (!rev.pending.nr) {
+					if (!rev.show_root_diff)
+						die("No HEAD commit to compare with (yet)");
+					add_empty_to_pending(&rev);
+				}
 				break;
 			}
 		}
diff --git a/revision.c b/revision.c
index 499f0e0..de0fd89 100644
--- a/revision.c
+++ b/revision.c
@@ -145,16 +145,27 @@ void add_pending_object(struct rev_info *revs, struct object *obj, const char *n
 	add_pending_object_with_mode(revs, obj, name, S_IFINVALID);
 }
 
-void add_head_to_pending(struct rev_info *revs)
+static void add_to_pending_by_name(struct rev_info *revs, const char *name)
 {
 	unsigned char sha1[20];
 	struct object *obj;
-	if (get_sha1("HEAD", sha1))
+	if (get_sha1(name, sha1))
 		return;
 	obj = parse_object(sha1);
 	if (!obj)
 		return;
-	add_pending_object(revs, obj, "HEAD");
+	add_pending_object(revs, obj, name);
+}
+
+void add_head_to_pending(struct rev_info *revs)
+{
+	add_to_pending_by_name(revs, "HEAD");
+}
+
+void add_empty_to_pending(struct rev_info *revs)
+{
+	add_to_pending_by_name(revs,
+			"4b825dc642cb6eb9a060e54bf8d69288fbee4904");
 }
 
 static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)
diff --git a/revision.h b/revision.h
index fc23522..108f43d 100644
--- a/revision.h
+++ b/revision.h
@@ -151,6 +151,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_to_pending(struct rev_info *);
 
 enum commit_action {
 	commit_ignore,
diff --git a/t/t4030-diff-root.sh b/t/t4030-diff-root.sh
new file mode 100755
index 0000000..e5174b7
--- /dev/null
+++ b/t/t4030-diff-root.sh
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+test_description='diff --root allows comparison between index and root'
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	echo content >file &&
+	git add file
+'
+
+test_expect_success 'diff --cached (without --root)' '
+	test_must_fail git diff --cached --name-only
+'
+
+test_expect_success 'diff --cached (with --root)' '
+	echo file >expect &&
+	git diff --cached --name-only --root >actual &&
+	test_cmp expect actual
+'
+
+test_done
-- 
1.6.0.2.249.g97d7f.dirty

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux