How to disambiguate an ambiguous abbreviated sha1 in git
I was intrigued by Josh Stone’s analysis of sha1 abbreviation collisions.
Let’s say somebody wrote down an abbreviated commit id,
8b82547e33, at a time when it was unambiguous. But since then other objects have been created with that same prefix, so that now git tells you (twice, for some reason):
$ git show 8b82547e33 error: short SHA1 8b82547e33 is ambiguous. error: short SHA1 8b82547e33 is ambiguous. fatal: ambiguous argument '8b82547e33': unknown revision or path not in the working tree. Use '--' to separate paths from revisions, like this: 'git <command> [<revision>...] -- [<file>...]'
Now, as a human, I could probably tell which object I meant if git would just show me the ambiguous objects. How can I achieve something like the following?
$ git objects-starting-with 8b82547e33 8b82547e33e: commit: l2tp: Restore socket refcount when sendmsg succeeds 8b82547e338: tree [2 files, 26 subtrees]
(Note: the above examples are using a relatively current clone of http://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git.)
2 Solutions collect form web for “How to disambiguate an ambiguous abbreviated sha1 in git”
You can use
git rev-parse, assuming you have at least a 4-digit prefix of the full hash.
git rev-parse --disambiguate=8b82547e33
With Git 2.11+ (Q4 2016), you won’t even have to type
git rev-parse --disambiguate=....
Git will list for you the possible candidates!
See commit 5b33cb1 (27 Sep 2016), and commit 1ffa26c, commit fad6b9e, commit 16ddcd4, commit 0c99171, commit 59e4e34, commit 0016043, commit 5d5def2, commit 8a10fea, commit 7243ffd, commit 259942f (26 Sep 2016) by Jeff King (
(Merged by Junio C Hamano —
gitster — in commit 66c22ba, 06 Oct 2016)
get_short_sha1: list ambiguous objects on error
When the user gives us an ambiguous short sha1, we print an error and refuse to resolve it.
In some cases, the next step is for them to feed us more characters (e.g., if they were retyping or cut-and-pasting from a full sha1). But in other cases, that might be all they have.
For example, an old commit message may have used a 7-character hex that was
unique at the time, but is now ambiguous.
Git doesn’t provide any information about the ambiguous objects it found, so it’s hard for the user to find out which one they probably meant.
This patch teaches
get_short_sha1()to list the sha1s of the objects it found, along with a few bits of information that may help the user decide which one they meant.
Here’s what it looks like on git.git:
$ git rev-parse b2e1 error: short SHA1 b2e1 is ambiguous hint: The candidates are: hint: b2e1196 tag v2.8.0-rc1 hint: b2e11d1 tree hint: b2e1632 commit 2007-11-14 - Merge branch 'bs/maint-commit-options' hint: b2e1759 blob hint: b2e18954 blob hint: b2e1895c blob fatal: ambiguous argument 'b2e1': unknown revision or path not in the working tree. Use '--' to separate paths from revisions, like this: 'git <command> [<revision>...] -- [<file>...]'
We show the tagname for tags, and the date and subject for commits.
For trees and blobs, in theory we could dig in the history to find the paths at which they were present. But that’s very expensive (on the order of 30s for the kernel), and it’s not likely to be all that helpful.
Most short references are to commits, so the useful information is typically going to be that the object in question isn’t a commit. So it’s silly to spend a lot of CPU preemptively digging up the path; the user can do it themselves if they really need to.
And of course it’s somewhat ironic that we abbreviate the sha1s in the disambiguation hint.
But full sha1s would cause annoying line wrapping for the commit lines, and presumably the user is going to just re-issue their command immediately with the corrected sha1.
We also restrict the list to those that match any disambiguation hint. E.g.:
$ git rev-parse b2e1:foo error: short SHA1 b2e1 is ambiguous hint: The candidates are: hint: b2e1196 tag v2.8.0-rc1 hint: b2e11d1 tree hint: b2e1632 commit 2007-11-14 - Merge branch 'bs/maint-commit-options' fatal: Invalid object name 'b2e1'.
does not bother reporting the blobs, because they cannot work as a treeish.