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

[PATCH 6/7] builtin/describe.c: describe a blob

From
Stefan Beller <sbeller@google.com>
Date
Oct 31, 2017, 00:33 UTC
Message-ID
<20171031003351.22341-7-sbeller@google.com>
In-Reply-To
<20171031003351.22341-1-sbeller@google.com>

Sometimes users are given a hash of an object and they want to identify it further (ex.: Use verify-pack to find the largest blobs, but what are these? or [1])

"This is an interesting endeavor, because describing things is hard."
  -- me, upon writing this patch.

When describing commits, we try to anchor them to tags or refs, as these are conceptually on a higher level than the commit. And if there is no ref or tag that matches exactly, we're out of luck. So we employ a heuristic to make up a name for the commit. These names are ambivalent, there might be different tags or refs to anchor to, and there might be different path in the DAG to travel to arrive at the commit precisely.

When describing a blob, we want to describe the blob from a higher layer as well, which is a tuple of (commit, deep/path) as the tree objects involved are rather uninteresting. The same blob can be referenced by multiple commits, so how we decide which commit to use? This patch implements a rather naive approach on this: As there are no back pointers from blobs to commits in which the blob occurs, we'll start walking from any tips available, listing the blobs in-order of the commit and once we found the blob, we'll take the first commit that listed the blob. For source code this is likely not the first commit that introduced the blob, but rather the latest commit that contained the blob. For example:

  git describe v0.99:Makefile
  v0.99-5-gab6625e06a:Makefile

tells us the latest commit that contained the Makefile as it was in tag v0.99 is commit v0.99-5-gab6625e06a (and at the same path), as the next commit on top v0.99-6-gb1de9de2b9 ([PATCH] Bootstrap "make dist", 2005-07-11) touches the Makefile.

Let's see how this description turns out, if it is useful in day-to-day use as I have the intuition that we'd rather want to see the *first* commit that this blob was introduced to the repository (which can be achieved easily by giving the `--reverse` flag in the describe_blob rev walk).

[1] https://stackoverflow.com/questions/223678/which-commit-has-this-blob
Signed-off-by: Stefan Beller <sbeller@google.com>
---
 Documentation/git-describe.txt | 12 +++++++-
 builtin/describe.c             | 65 ++++++++++++++++++++++++++++++++++++++----
 t/t6120-describe.sh            | 15 ++++++++++
 3 files changed, 86 insertions(+), 6 deletions(-)
diff --git a/Documentation/git-describe.txt b/Documentation/git-describe.txt
index c924c945ba..3d618b2445 100644
--- a/Documentation/git-describe.txt
+++ b/Documentation/git-describe.txt
@@ -3,7 +3,7 @@ git-describe(1)
 
 NAME
 ----
-git-describe - Describe a commit using the most recent tag reachable from it
+git-describe - Describe a commit or blob using the most recent tag reachable from it
 
 
 SYNOPSIS
@@ -24,6 +24,16 @@ By default (without --all or --tags) `git describe` only shows
 annotated tags.  For more information about creating annotated tags
 see the -a and -s options to linkgit:git-tag[1].
 
+If the given `<commit-ish>` refers to a blob, it will be described
+as `<commit-description>:<path>`, such that the blob can be found
+at `<path>` in the `<commit-ish`. Note, that the commit is likely
+not the commit that introduced the blob, but the one that was found
+first; to find the commit that introduced the blob, you need to find
+the commit that last touched the path, e.g.
+`git log <commit-description> -- <path>`.
+As blobs do not point at the commits they are contained in,
+describing blobs is slow as we have to walk the whole graph.
+
 OPTIONS
 -------
 <commit-ish>...::
diff --git a/builtin/describe.c b/builtin/describe.c
index 9e9a5ed5d4..382cbae908 100644
--- a/builtin/describe.c
+++ b/builtin/describe.c
@@ -3,6 +3,7 @@
 #include "lockfile.h"
 #include "commit.h"
 #include "tag.h"
+#include "blob.h"
 #include "refs.h"
 #include "builtin.h"
 #include "exec_cmd.h"
@@ -11,8 +12,9 @@
 #include "hashmap.h"
 #include "argv-array.h"
 #include "run-command.h"
+#include "revision.h"
+#include "list-objects.h"
 
-#define SEEN		(1u << 0)
 #define MAX_TAGS	(FLAG_BITS - 1)
 
 static const char * const describe_usage[] = {
@@ -434,6 +436,54 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
 		strbuf_addstr(dst, suffix);
 }
 
+struct process_commit_data {
+	struct object_id current_commit;
+	struct object_id looking_for;
+	struct strbuf *dst;
+};
+
+static void process_commit(struct commit *commit, void *data)
+{
+	struct process_commit_data *pcd = data;
+	pcd->current_commit = commit->object.oid;
+}
+
+static void process_object(struct object *obj, const char *path, void *data)
+{
+	struct process_commit_data *pcd = data;
+
+	if (!oidcmp(&pcd->looking_for, &obj->oid) && !pcd->dst->len) {
+		reset_revision_walk();
+		describe_commit(&pcd->current_commit, pcd->dst);
+		strbuf_addf(pcd->dst, ":%s", path);
+	}
+}
+
+static void describe_blob(struct object_id oid, struct strbuf *dst)
+{
+	struct rev_info revs;
+	struct argv_array args = ARGV_ARRAY_INIT;
+	struct process_commit_data pcd = { null_oid, oid, dst};
+
+	argv_array_pushl(&args, "internal: The first arg is not parsed",
+		"--all", "--reflog", /* as many starting points as possible */
+		/* NEEDSWORK: --all is incompatible with worktrees for now: */
+		"--single-worktree",
+		"--objects",
+		"--in-commit-order",
+		NULL);
+
+	init_revisions(&revs, NULL);
+	if (setup_revisions(args.argc, args.argv, &revs, NULL) > 1)
+		BUG("setup_revisions could not handle all args?");
+
+	if (prepare_revision_walk(&revs))
+		die("revision walk setup failed");
+
+	traverse_commit_list(&revs, process_commit, process_object, &pcd);
+	reset_revision_walk();
+}
+
 static void describe(const char *arg, int last_one)
 {
 	struct object_id oid;
@@ -445,11 +495,16 @@ static void describe(const char *arg, int last_one)
 
 	if (get_oid(arg, &oid))
 		die(_("Not a valid object name %s"), arg);
-	cmit = lookup_commit_reference(&oid);
-	if (!cmit)
-		die(_("%s is not a valid '%s' object"), arg, commit_type);
+	cmit = lookup_commit_reference_gently(&oid, 1);
 
-	describe_commit(&oid, &sb);
+	if (cmit) {
+		describe_commit(&oid, &sb);
+	} else {
+		if (lookup_blob(&oid))
+			describe_blob(oid, &sb);
+		else
+			die(_("%s is neither a commit nor blob"), arg);
+	}
 
 	puts(sb.buf);
 
diff --git a/t/t6120-describe.sh b/t/t6120-describe.sh
index 1c0e8659d9..3be01316e8 100755
--- a/t/t6120-describe.sh
+++ b/t/t6120-describe.sh
@@ -310,6 +310,21 @@ test_expect_success 'describe ignoring a borken submodule' '
 	grep broken out
 '
 
+test_expect_success 'describe a blob at a tag' '
+	echo "make it a unique blob" >file &&
+	git add file && git commit -m "content in file" &&
+	git tag -a -m "latest annotated tag" unique-file &&
+	git describe HEAD:file >actual &&
+	echo "unique-file:file" >expect &&
+	test_cmp expect actual
+'
+
+test_expect_success 'describe a surviving blob' '
+	git commit --allow-empty -m "empty commit" &&
+	git describe HEAD:file >actual &&
+	grep unique-file-1-g actual
+'
+
 test_expect_failure ULIMIT_STACK_SIZE 'name-rev works in a deep repo' '
 	i=1 &&
 	while test $i -lt 8000
-- 
2.15.0.rc2.443.gfcc3b81c0a
Previous: Stefan BellerNext: Junio C Hamano
Message 24 of 110 in “git-describe <blob> ?”
  1. 0/3 git-describe <blob> ?Stefan Beller, Oct 28, 2017
  2. 1/3 list-objects.c: factor out traverse_trees_and_blobsStefan Beller, Oct 28, 2017
  3. 2/3 revision.h: introduce blob/tree walking in order of the commitsStefan Beller, Oct 28, 2017
  4. Johannes SchindelinOct 28, 2017
  5. Stefan BellerOct 29, 2017
  6. Stefan BellerOct 29, 2017
  7. Junio C HamanoOct 29, 2017
  8. 3/3 builtin/describe: describe blobsStefan Beller, Oct 28, 2017
  9. Johannes SchindelinOct 28, 2017
  10. Jacob KellerOct 28, 2017
  11. Stefan BellerOct 29, 2017
  12. Kevin DaudtOct 29, 2017
  13. Johannes SchindelinOct 29, 2017
  14. Johannes SchindelinOct 28, 2017
  15. Stefan BellerOct 29, 2017
  16. Johannes SchindelinOct 28, 2017
  17. 0/7 git-describe <blob>Stefan Beller, Oct 31, 2017
  18. 1/7 list-objects.c: factor out traverse_trees_and_blobsStefan Beller, Oct 31, 2017
  19. Junio C HamanoOct 31, 2017
  20. 5/7 builtin/describe.c: factor out describe_commitStefan Beller, Oct 31, 2017
  21. 4/7 builtin/describe.c: print debug statements earlierStefan Beller, Oct 31, 2017
  22. Junio C HamanoOct 31, 2017
  23. Stefan BellerOct 31, 2017
  24. 6/7 builtin/describe.c: describe a blobStefan Beller, Oct 31, 2017
  25. Junio C HamanoOct 31, 2017
  26. Stefan BellerOct 31, 2017
  27. Junio C HamanoNov 1, 2017
  28. Stefan BellerNov 1, 2017
  29. Junio C HamanoNov 2, 2017
  30. Junio C HamanoNov 2, 2017
  31. Philip OakleyNov 4, 2017
  32. Junio C HamanoNov 5, 2017
  33. Philip OakleyNov 6, 2017
  34. Stefan BellerNov 9, 2017
  35. Philip OakleyNov 10, 2017
  36. Junio C HamanoNov 10, 2017
  37. 0/1 describe a blob: with better docsStefan Beller, Nov 10, 2017
  38. builtin/describe.c: describe a blobStefan Beller, Nov 10, 2017
  39. Junio C HamanoNov 13, 2017
  40. Stefan BellerNov 14, 2017
  41. Philip OakleyNov 20, 2017
  42. Philip OakleyNov 20, 2017
  43. Junio C HamanoNov 1, 2017
  44. 7/7 t6120: fix typo in test nameStefan Beller, Oct 31, 2017
  45. Junio C HamanoNov 1, 2017
  46. Stefan BellerNov 1, 2017
  47. Junio C HamanoNov 2, 2017
  48. 3/7 builtin/describe.c: rename `oid` to avoid variable shadowingStefan Beller, Oct 31, 2017
  49. Jacob KellerOct 31, 2017
  50. 2/7 revision.h: introduce blob/tree walking in order of the commitsStefan Beller, Oct 31, 2017
  51. Junio C HamanoOct 31, 2017
  52. Stefan BellerOct 31, 2017
  53. 0/7 git describe blobStefan Beller, Oct 31, 2017
  54. 1/7 list-objects.c: factor out traverse_trees_and_blobsStefan Beller, Oct 31, 2017
  55. Junio C HamanoNov 1, 2017
  56. 4/7 builtin/describe.c: print debug statements earlierStefan Beller, Oct 31, 2017
  57. Eric SunshineOct 31, 2017
  58. 7/7 t6120: fix typo in test nameStefan Beller, Oct 31, 2017
  59. 2/7 revision.h: introduce blob/tree walking in order of the commitsStefan Beller, Oct 31, 2017
  60. Junio C HamanoNov 1, 2017
  61. Johannes SchindelinNov 1, 2017
  62. Junio C HamanoNov 1, 2017
  63. Stefan BellerNov 1, 2017
  64. Johannes SchindelinNov 1, 2017
  65. Stefan BellerNov 1, 2017
  66. Johannes SchindelinNov 1, 2017
  67. Stefan BellerNov 1, 2017
  68. Johannes SchindelinNov 1, 2017
  69. Jeff KingNov 1, 2017
  70. Johannes SchindelinNov 1, 2017
  71. Junio C HamanoNov 2, 2017
  72. 6/7 builtin/describe.c: describe a blobStefan Beller, Oct 31, 2017
  73. Eric SunshineOct 31, 2017
  74. Stefan BellerNov 1, 2017
  75. Junio C HamanoNov 1, 2017
  76. Johannes SchindelinNov 1, 2017
  77. Stefan BellerNov 1, 2017
  78. Jacob KellerNov 1, 2017
  79. Johannes SchindelinNov 1, 2017
  80. Stefan BellerNov 1, 2017
  81. Johannes SchindelinNov 1, 2017
  82. Stefan BellerNov 1, 2017
  83. Jacob KellerNov 2, 2017
  84. Junio C HamanoNov 3, 2017
  85. Jacob KellerNov 3, 2017
  86. Junio C HamanoNov 3, 2017
  87. Andreas SchwabNov 2, 2017
  88. Stefan BellerNov 2, 2017
  89. Johannes SchindelinNov 3, 2017
  90. Stefan BellerNov 1, 2017
  91. 3/7 builtin/describe.c: rename `oid` to avoid variable shadowingStefan Beller, Oct 31, 2017
  92. 5/7 builtin/describe.c: factor out describe_commitStefan Beller, Oct 31, 2017
  93. Junio C HamanoNov 1, 2017
  94. 0/7 git describe blobStefan Beller, Nov 2, 2017
  95. 1/7 t6120: fix typo in test nameStefan Beller, Nov 2, 2017
  96. 2/7 list-objects.c: factor out traverse_trees_and_blobsStefan Beller, Nov 2, 2017
  97. 3/7 revision.h: introduce blob/tree walking in order of the commitsStefan Beller, Nov 2, 2017
  98. Jonathan TanNov 14, 2017
  99. 6/7 builtin/describe.c: factor out describe_commitStefan Beller, Nov 2, 2017
  100. 5/7 builtin/describe.c: print debug statements earlierStefan Beller, Nov 2, 2017
  101. Jonathan TanNov 14, 2017
  102. Stefan BellerNov 14, 2017
  103. 7/7 builtin/describe.c: describe a blobStefan Beller, Nov 2, 2017
  104. Jonathan TanNov 14, 2017
  105. Stefan BellerNov 14, 2017
  106. Jonathan TanNov 14, 2017
  107. 4/7 builtin/describe.c: rename `oid` to avoid variable shadowingStefan Beller, Nov 2, 2017
  108. Jacob KellerNov 3, 2017
  109. Junio C HamanoNov 3, 2017
  110. Stefan BellerNov 3, 2017

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.