git/list[1] front-page[2] threads[3] people[4] search[5] about
 

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

From
Jeff King <peff@peff.net>
Date
Sep 18, 2008, 09:21 UTC
Message-ID
<20080918092152.GA18732@coredump.intra.peff.net>
In-Reply-To
<20080916062105.GA12708@coredump.intra.peff.net>

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@peff.net>
---
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
Previous: Jeff KingNext: Anatol Pomozov
Message 10 of 22 in “Diff-tree does not work for initial commit”
  1. Anatol PomozovSep 15, 2008
  2. Michael J GruberSep 15, 2008
  3. Junio C HamanoSep 15, 2008
  4. Anatol PomozovSep 15, 2008
  5. Michael J GruberSep 15, 2008
  6. Sverre RabbelierSep 15, 2008
  7. Jeff KingSep 15, 2008
  8. Sverre RabbelierSep 16, 2008
  9. Jeff KingSep 16, 2008
  10. extend meaning of "--root" option to index comparisonsJeff King, Sep 18, 2008
  11. Anatol PomozovSep 18, 2008
  12. Sverre RabbelierSep 18, 2008
  13. Jeff KingSep 19, 2008
  14. Anatol PomozovSep 19, 2008
  15. Jeff KingSep 19, 2008
  16. Re* [RFC/PATCH] extend meaning of "--root" option to index comparisonsJunio C Hamano, Sep 19, 2008
  17. Jeff KingSep 21, 2008
  18. Anatol PomozovSep 21, 2008
  19. Jakub NarebskiSep 21, 2008
  20. Jeff KingSep 22, 2008
  21. Re* [RFC/PATCH] extend meaning of "--root" option to index comparisonsJunio C Hamano, Sep 21, 2008
  22. Jeff KingSep 22, 2008

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.