Skip to content

Commit 6269b6b

Browse files
committed
sha1_name.c: get_describe_name() by definition groks only commits
Teach get_describe_name() to pass the disambiguation hint down the callchain to get_short_sha1(). Also add tests to show various syntactic elements that we could take advantage of the object type information to help disambiguration of abbreviated object names. Many of them are marked as broken, and some of them will be fixed in later patches in this series. Signed-off-by: Junio C Hamano <[email protected]>
1 parent aa1dec9 commit 6269b6b

File tree

2 files changed

+257
-1
lines changed

2 files changed

+257
-1
lines changed

sha1_name.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
603603
static int get_describe_name(const char *name, int len, unsigned char *sha1)
604604
{
605605
const char *cp;
606+
unsigned flags = GET_SHA1_QUIETLY | GET_SHA1_COMMIT;
606607

607608
for (cp = name + len - 1; name + 2 <= cp; cp--) {
608609
char ch = *cp;
@@ -613,7 +614,7 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1)
613614
if (ch == 'g' && cp[-1] == '-') {
614615
cp++;
615616
len -= cp - name;
616-
return get_short_sha1(cp, len, sha1, GET_SHA1_QUIETLY);
617+
return get_short_sha1(cp, len, sha1, flags);
617618
}
618619
}
619620
}

t/t1512-rev-parse-disambiguation.sh

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
#!/bin/sh
2+
3+
test_description='object name disambiguation
4+
5+
Create blobs, trees, commits and a tag that all share the same
6+
prefix, and make sure "git rev-parse" can take advantage of
7+
type information to disambiguate short object names that are
8+
not necessarily unique.
9+
10+
The final history used in the test has five commits, with the bottom
11+
one tagged as v1.0.0. They all have one regular file each.
12+
13+
+-------------------------------------------+
14+
| |
15+
| .-------b3wettvi---- ad2uee |
16+
| / / |
17+
| a2onsxbvj---czy8f73t--ioiley5o |
18+
| |
19+
+-------------------------------------------+
20+
21+
'
22+
23+
. ./test-lib.sh
24+
25+
test_expect_success 'blob and tree' '
26+
test_tick &&
27+
(
28+
for i in 0 1 2 3 4 5 6 7 8 9
29+
do
30+
echo $i
31+
done
32+
echo
33+
echo b1rwzyc3
34+
) >a0blgqsjc &&
35+
36+
# create one blob 0000000000b36
37+
git add a0blgqsjc &&
38+
39+
# create one tree 0000000000cdc
40+
git write-tree
41+
'
42+
43+
test_expect_success 'warn ambiguity when no candidate matches type hint' '
44+
test_must_fail git rev-parse --verify 000000000^{commit} 2>actual &&
45+
grep "short SHA1 000000000 is ambiguous" actual
46+
'
47+
48+
test_expect_failure 'disambiguate tree-ish' '
49+
# feed tree-ish in an unambiguous way
50+
git rev-parse --verify 0000000000cdc:a0blgqsjc &&
51+
52+
# ambiguous at the object name level, but there is only one
53+
# such tree-ish (the other is a blob)
54+
git rev-parse --verify 000000000:a0blgqsjc
55+
'
56+
57+
test_expect_failure 'disambiguate blob' '
58+
sed -e "s/|$//" >patch <<-EOF &&
59+
diff --git a/frotz b/frotz
60+
index 000000000..ffffff 100644
61+
--- a/frotz
62+
+++ b/frotz
63+
@@ -10,3 +10,4 @@
64+
9
65+
|
66+
b1rwzyc3
67+
+irwry
68+
EOF
69+
(
70+
GIT_INDEX_FILE=frotz &&
71+
export GIT_INDEX_FILE &&
72+
git apply --build-fake-ancestor frotz patch &&
73+
git cat-file blob :frotz >actual
74+
) &&
75+
test_cmp a0blgqsjc actual
76+
'
77+
78+
test_expect_failure 'disambiguate tree' '
79+
commit=$(echo "d7xm" | git commit-tree 000000000) &&
80+
test $(git rev-parse $commit^{tree}) = $(git rev-parse 0000000000cdc)
81+
'
82+
83+
test_expect_success 'first commit' '
84+
# create one commit 0000000000e4f
85+
git commit -m a2onsxbvj
86+
'
87+
88+
test_expect_failure 'disambiguate commit-ish' '
89+
# feed commit-ish in an unambiguous way
90+
git rev-parse --verify 0000000000e4f^{commit} &&
91+
92+
# ambiguous at the object name level, but there is only one
93+
# such commit (the others are tree and blob)
94+
git rev-parse --verify 000000000^{commit} &&
95+
96+
# likewise
97+
git rev-parse --verify 000000000^0
98+
'
99+
100+
test_expect_failure 'disambiguate commit' '
101+
commit=$(echo "j9xqh" | git commit-tree 0000000000cdc -p 000000000) &&
102+
test $(git rev-parse $commit^) = $(git rev-parse 0000000000e4f)
103+
'
104+
105+
test_expect_failure 'log name1..name2 takes only commit-ishes on both ends' '
106+
git log 000000000..000000000 &&
107+
git log ..000000000 &&
108+
git log 000000000.. &&
109+
git log 000000000...000000000 &&
110+
git log ...000000000 &&
111+
git log 000000000...
112+
'
113+
114+
test_expect_failure 'rev-parse name1..name2 takes only commit-ishes on both ends' '
115+
git rev-parse 000000000..000000000 &&
116+
git rev-parse ..000000000 &&
117+
git rev-parse 000000000..
118+
'
119+
120+
test_expect_failure 'git log takes only commit-ish' '
121+
git log 000000000
122+
'
123+
124+
test_expect_failure 'git reset takes only commit-ish' '
125+
git reset 000000000
126+
'
127+
128+
test_expect_success 'first tag' '
129+
# create one tag 0000000000f8f
130+
git tag -a -m j7cp83um v1.0.0
131+
'
132+
133+
test_expect_failure 'two semi-ambiguous commit-ish' '
134+
# Once the parser becomes ultra-smart, it could notice that
135+
# 110282 before ^{commit} name many different objects, but
136+
# that only two (HEAD and v1.0.0 tag) can be peeled to commit,
137+
# and that peeling them down to commit yield the same commit
138+
# without ambiguity.
139+
git rev-parse --verify 110282^{commit} &&
140+
141+
# likewise
142+
git log 000000000..000000000 &&
143+
git log ..000000000 &&
144+
git log 000000000.. &&
145+
git log 000000000...000000000 &&
146+
git log ...000000000 &&
147+
git log 000000000...
148+
'
149+
150+
test_expect_failure 'three semi-ambiguous tree-ish' '
151+
# Likewise for tree-ish. HEAD, v1.0.0 and HEAD^{tree} share
152+
# the prefix but peeling them to tree yields the same thing
153+
git rev-parse --verify 000000000^{tree}
154+
'
155+
156+
test_expect_success 'parse describe name' '
157+
# feed an unambiguous describe name
158+
git rev-parse --verify v1.0.0-0-g0000000000e4f &&
159+
160+
# ambiguous at the object name level, but there is only one
161+
# such commit (others are blob, tree and tag)
162+
git rev-parse --verify v1.0.0-0-g000000000
163+
'
164+
165+
test_expect_success 'more history' '
166+
# commit 0000000000043
167+
git mv a0blgqsjc d12cr3h8t &&
168+
echo h62xsjeu >>d12cr3h8t &&
169+
git add d12cr3h8t &&
170+
171+
test_tick &&
172+
git commit -m czy8f73t &&
173+
174+
# commit 00000000008ec
175+
git mv d12cr3h8t j000jmpzn &&
176+
echo j08bekfvt >>j000jmpzn &&
177+
git add j000jmpzn &&
178+
179+
test_tick &&
180+
git commit -m ioiley5o &&
181+
182+
# commit 0000000005b0
183+
git checkout v1.0.0^0 &&
184+
git mv a0blgqsjc f5518nwu &&
185+
186+
for i in h62xsjeu j08bekfvt kg7xflhm
187+
do
188+
echo $i
189+
done >>f5518nwu &&
190+
git add f5518nwu &&
191+
192+
test_tick &&
193+
git commit -m b3wettvi &&
194+
side=$(git rev-parse HEAD) &&
195+
196+
# commit 000000000066
197+
git checkout master &&
198+
199+
# If you use recursive, merge will fail and you will need to
200+
# clean up a0blgqsjc as well. If you use resolve, merge will
201+
# succeed.
202+
test_might_fail git merge --no-commit -s recursive $side &&
203+
git rm -f f5518nwu j000jmpzn &&
204+
205+
test_might_fail git rm -f a0blgqsjc &&
206+
(
207+
git cat-file blob $side:f5518nwu
208+
echo j3l0i9s6
209+
) >ab2gs879 &&
210+
git add ab2gs879 &&
211+
212+
test_tick &&
213+
git commit -m ad2uee
214+
215+
'
216+
217+
test_expect_failure 'parse describe name taking advantage of generation' '
218+
# ambiguous at the object name level, but there is only one
219+
# such commit at generation 0
220+
git rev-parse --verify v1.0.0-0-g000000000 &&
221+
222+
# likewise for generation 2 and 4
223+
git rev-parse --verify v1.0.0-2-g000000000 &&
224+
git rev-parse --verify v1.0.0-4-g000000000
225+
'
226+
227+
# Note: because rev-parse does not even try to disambiguate based on
228+
# the generation number, this test currently succeeds for a wrong
229+
# reason. When it learns to use the generation number, the previous
230+
# test should succeed, and also this test should fail because the
231+
# describe name used in the test with generation number can name two
232+
# commits. Make sure that such a future enhancement does not randomly
233+
# pick one.
234+
test_expect_success 'parse describe name not ignoring ambiguity' '
235+
# ambiguous at the object name level, and there are two such
236+
# commits at generation 1
237+
test_must_fail git rev-parse --verify v1.0.0-1-g000000000
238+
'
239+
240+
test_expect_success 'ambiguous commit-ish' '
241+
# Now there are many commits that begin with the
242+
# common prefix, none of these should pick one at
243+
# random. They all should result in ambiguity errors.
244+
test_must_fail git rev-parse --verify 110282^{commit} &&
245+
246+
# likewise
247+
test_must_fail git log 000000000..000000000 &&
248+
test_must_fail git log ..000000000 &&
249+
test_must_fail git log 000000000.. &&
250+
test_must_fail git log 000000000...000000000 &&
251+
test_must_fail git log ...000000000 &&
252+
test_must_fail git log 000000000...
253+
'
254+
255+
test_done

0 commit comments

Comments
 (0)