Git fork
1#!/bin/sh
2
3test_description='test log -L'
4GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
5export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
6
7. ./test-lib.sh
8
9test_expect_success 'setup (import history)' '
10 git fast-import < "$TEST_DIRECTORY"/t4211/history.export &&
11 git reset --hard
12'
13
14test_expect_success 'basic command line parsing' '
15 # This may fail due to "no such path a.c in commit", or
16 # "-L is incompatible with pathspec", depending on the
17 # order the error is checked. Either is acceptable.
18 test_must_fail git log -L1,1:a.c -- a.c &&
19
20 # -L requires there is no pathspec
21 test_must_fail git log -L1,1:b.c -- b.c 2>error &&
22 test_grep "cannot be used with pathspec" error &&
23
24 # This would fail because --follow wants a single path, but
25 # we may fail due to incompatibility between -L/--follow in
26 # the future. Either is acceptable.
27 test_must_fail git log -L1,1:b.c --follow &&
28 test_must_fail git log --follow -L1,1:b.c &&
29
30 # This would fail because -L wants no pathspec, but
31 # we may fail due to incompatibility between -L/--follow in
32 # the future. Either is acceptable.
33 test_must_fail git log --follow -L1,1:b.c -- b.c
34'
35
36canned_test_1 () {
37 test_expect_$1 "$2" "
38 git log $2 >actual &&
39 test_cmp \"\$TEST_DIRECTORY\"/t4211/$(test_oid algo)/expect.$3 actual
40 "
41}
42
43canned_test () {
44 canned_test_1 success "$@"
45}
46canned_test_failure () {
47 canned_test_1 failure "$@"
48}
49
50test_bad_opts () {
51 test_expect_success "invalid args: $1" "
52 test_must_fail git log $1 2>errors &&
53 test_grep '$2' errors
54 "
55}
56
57canned_test "-L 4,12:a.c simple" simple-f
58canned_test "-L 4,+9:a.c simple" simple-f
59canned_test "-L '/long f/,/^}/:a.c' simple" simple-f
60canned_test "-L :f:a.c simple" simple-f-to-main
61
62canned_test "-L '/main/,/^}/:a.c' simple" simple-main
63canned_test "-L :main:a.c simple" simple-main-to-end
64
65canned_test "-L 1,+4:a.c simple" beginning-of-file
66
67canned_test "-L 20:a.c simple" end-of-file
68
69canned_test "-L '/long f/',/^}/:a.c -L /main/,/^}/:a.c simple" two-ranges
70canned_test "-L 24,+1:a.c simple" vanishes-early
71
72canned_test "-M -L '/long f/,/^}/:b.c' move-support" move-support-f
73canned_test "-M -L ':f:b.c' parallel-change" parallel-change-f-to-main
74
75canned_test "-L 4,12:a.c -L :main:a.c simple" multiple
76canned_test "-L 4,18:a.c -L ^:main:a.c simple" multiple-overlapping
77canned_test "-L :main:a.c -L 4,18:a.c simple" multiple-overlapping
78canned_test "-L 4:a.c -L 8,12:a.c simple" multiple-superset
79canned_test "-L 8,12:a.c -L 4:a.c simple" multiple-superset
80
81canned_test "-L 10,16:b.c -L 18,26:b.c main" no-assertion-error
82
83test_bad_opts "-L" "switch.*requires a value"
84test_bad_opts "-L b.c" "argument not .start,end:file"
85test_bad_opts "-L 1:" "argument not .start,end:file"
86test_bad_opts "-L 1:nonexistent" "There is no path"
87test_bad_opts "-L 1:simple" "There is no path"
88test_bad_opts "-L '/foo:b.c'" "argument not .start,end:file"
89test_bad_opts "-L 1000:b.c" "has only.*lines"
90test_bad_opts "-L :b.c" "argument not .start,end:file"
91test_bad_opts "-L :foo:b.c" "no match"
92
93test_expect_success '-L X (X == nlines)' '
94 n=$(wc -l <b.c) &&
95 git log -L $n:b.c
96'
97
98test_expect_success '-L X (X == nlines + 1)' '
99 n=$(expr $(wc -l <b.c) + 1) &&
100 test_must_fail git log -L $n:b.c
101'
102
103test_expect_success '-L X (X == nlines + 2)' '
104 n=$(expr $(wc -l <b.c) + 2) &&
105 test_must_fail git log -L $n:b.c
106'
107
108test_expect_success '-L ,Y (Y == nlines)' '
109 n=$(printf "%d" $(wc -l <b.c)) &&
110 git log -L ,$n:b.c
111'
112
113test_expect_success '-L ,Y (Y == nlines + 1)' '
114 n=$(expr $(wc -l <b.c) + 1) &&
115 git log -L ,$n:b.c
116'
117
118test_expect_success '-L ,Y (Y == nlines + 2)' '
119 n=$(expr $(wc -l <b.c) + 2) &&
120 git log -L ,$n:b.c
121'
122
123test_expect_success '-L with --first-parent and a merge' '
124 git checkout parallel-change &&
125 git log --first-parent -L 1,1:b.c
126'
127
128test_expect_success '-L with --output' '
129 git checkout parallel-change &&
130 git log --output=log -L :main:b.c >output &&
131 test_must_be_empty output &&
132 test_line_count = 70 log
133'
134
135test_expect_success 'range_set_union' '
136 test_seq 500 > c.c &&
137 git add c.c &&
138 git commit -m "many lines" &&
139 test_seq 1000 > c.c &&
140 git add c.c &&
141 git commit -m "modify many lines" &&
142 git log $(for x in $(test_seq 200); do echo -L $((2*x)),+1:c.c || return 1; done)
143'
144
145test_expect_success '-s shows only line-log commits' '
146 git log --format="commit %s" -L1,24:b.c >expect.raw &&
147 grep ^commit expect.raw >expect &&
148 git log --format="commit %s" -L1,24:b.c -s >actual &&
149 test_cmp expect actual
150'
151
152test_expect_success '-p shows the default patch output' '
153 git log -L1,24:b.c >expect &&
154 git log -L1,24:b.c -p >actual &&
155 test_cmp expect actual
156'
157
158test_expect_success '--raw is forbidden' '
159 test_must_fail git log -L1,24:b.c --raw
160'
161
162test_expect_success 'setup for checking fancy rename following' '
163 git checkout --orphan moves-start &&
164 git reset --hard &&
165
166 printf "%s\n" 12 13 14 15 b c d e >file-1 &&
167 printf "%s\n" 22 23 24 25 B C D E >file-2 &&
168 git add file-1 file-2 &&
169 test_tick &&
170 git commit -m "Add file-1 and file-2" &&
171 oid_add_f1_f2=$(git rev-parse --short HEAD) &&
172
173 git checkout -b moves-main &&
174 printf "%s\n" 11 12 13 14 15 b c d e >file-1 &&
175 git commit -a -m "Modify file-1 on main" &&
176 oid_mod_f1_main=$(git rev-parse --short HEAD) &&
177
178 printf "%s\n" 21 22 23 24 25 B C D E >file-2 &&
179 git commit -a -m "Modify file-2 on main #1" &&
180 oid_mod_f2_main_1=$(git rev-parse --short HEAD) &&
181
182 git mv file-1 renamed-1 &&
183 git commit -m "Rename file-1 to renamed-1 on main" &&
184
185 printf "%s\n" 11 12 13 14 15 b c d e f >renamed-1 &&
186 git commit -a -m "Modify renamed-1 on main" &&
187 oid_mod_r1_main=$(git rev-parse --short HEAD) &&
188
189 printf "%s\n" 21 22 23 24 25 B C D E F >file-2 &&
190 git commit -a -m "Modify file-2 on main #2" &&
191 oid_mod_f2_main_2=$(git rev-parse --short HEAD) &&
192
193 git checkout -b moves-side moves-start &&
194 printf "%s\n" 12 13 14 15 16 b c d e >file-1 &&
195 git commit -a -m "Modify file-1 on side #1" &&
196 oid_mod_f1_side_1=$(git rev-parse --short HEAD) &&
197
198 printf "%s\n" 22 23 24 25 26 B C D E >file-2 &&
199 git commit -a -m "Modify file-2 on side" &&
200 oid_mod_f2_side=$(git rev-parse --short HEAD) &&
201
202 git mv file-2 renamed-2 &&
203 git commit -m "Rename file-2 to renamed-2 on side" &&
204
205 printf "%s\n" 12 13 14 15 16 a b c d e >file-1 &&
206 git commit -a -m "Modify file-1 on side #2" &&
207 oid_mod_f1_side_2=$(git rev-parse --short HEAD) &&
208
209 printf "%s\n" 22 23 24 25 26 A B C D E >renamed-2 &&
210 git commit -a -m "Modify renamed-2 on side" &&
211 oid_mod_r2_side=$(git rev-parse --short HEAD) &&
212
213 git checkout moves-main &&
214 git merge moves-side &&
215 oid_merge=$(git rev-parse --short HEAD)
216'
217
218test_expect_success 'fancy rename following #1' '
219 cat >expect <<-EOF &&
220 $oid_merge Merge branch '\''moves-side'\'' into moves-main
221 $oid_mod_f1_side_2 Modify file-1 on side #2
222 $oid_mod_f1_side_1 Modify file-1 on side #1
223 $oid_mod_r1_main Modify renamed-1 on main
224 $oid_mod_f1_main Modify file-1 on main
225 $oid_add_f1_f2 Add file-1 and file-2
226 EOF
227 git log -L1:renamed-1 --oneline --no-patch >actual &&
228 test_cmp expect actual
229'
230
231test_expect_success 'fancy rename following #2' '
232 cat >expect <<-EOF &&
233 $oid_merge Merge branch '\''moves-side'\'' into moves-main
234 $oid_mod_r2_side Modify renamed-2 on side
235 $oid_mod_f2_side Modify file-2 on side
236 $oid_mod_f2_main_2 Modify file-2 on main #2
237 $oid_mod_f2_main_1 Modify file-2 on main #1
238 $oid_add_f1_f2 Add file-1 and file-2
239 EOF
240 git log -L1:renamed-2 --oneline --no-patch >actual &&
241 test_cmp expect actual
242'
243
244# Create the following linear history, where each commit does what its
245# subject line promises:
246#
247# * 66c6410 Modify func2() in file.c
248# * 50834e5 Modify other-file
249# * fe5851c Modify func1() in file.c
250# * 8c7c7dd Add other-file
251# * d5f4417 Add func1() and func2() in file.c
252test_expect_success 'setup for checking line-log and parent oids' '
253 git checkout --orphan parent-oids &&
254 git reset --hard &&
255
256 cat >file.c <<-\EOF &&
257 int func1()
258 {
259 return F1;
260 }
261
262 int func2()
263 {
264 return F2;
265 }
266 EOF
267 git add file.c &&
268 test_tick &&
269 first_tick=$test_tick &&
270 git commit -m "Add func1() and func2() in file.c" &&
271
272 echo 1 >other-file &&
273 git add other-file &&
274 test_tick &&
275 git commit -m "Add other-file" &&
276
277 sed -e "s/F1/F1 + 1/" file.c >tmp &&
278 mv tmp file.c &&
279 git commit -a -m "Modify func1() in file.c" &&
280
281 echo 2 >other-file &&
282 git commit -a -m "Modify other-file" &&
283
284 sed -e "s/F2/F2 + 2/" file.c >tmp &&
285 mv tmp file.c &&
286 git commit -a -m "Modify func2() in file.c" &&
287
288 head_oid=$(git rev-parse --short HEAD) &&
289 prev_oid=$(git rev-parse --short HEAD^) &&
290 root_oid=$(git rev-parse --short HEAD~4)
291'
292
293# Parent oid should be from immediate parent.
294test_expect_success 'parent oids without parent rewriting' '
295 cat >expect <<-EOF &&
296 $head_oid $prev_oid Modify func2() in file.c
297 $root_oid Add func1() and func2() in file.c
298 EOF
299 git log --format="%h %p %s" --no-patch -L:func2:file.c >actual &&
300 test_cmp expect actual
301'
302
303# Parent oid should be from the most recent ancestor touching func2(),
304# i.e. in this case from the root commit.
305test_expect_success 'parent oids with parent rewriting' '
306 cat >expect <<-EOF &&
307 $head_oid $root_oid Modify func2() in file.c
308 $root_oid Add func1() and func2() in file.c
309 EOF
310 git log --format="%h %p %s" --no-patch -L:func2:file.c --parents >actual &&
311 test_cmp expect actual
312'
313
314test_expect_success 'line-log with --before' '
315 echo $root_oid >expect &&
316 git log --format=%h --no-patch -L:func2:file.c --before=$first_tick >actual &&
317 test_cmp expect actual
318'
319
320test_expect_success 'setup tests for zero-width regular expressions' '
321 cat >expect <<-EOF
322 Modify func1() in file.c
323 Add func1() and func2() in file.c
324 EOF
325'
326
327test_expect_success 'zero-width regex $ matches any function name' '
328 git log --format="%s" --no-patch "-L:$:file.c" >actual &&
329 test_cmp expect actual
330'
331
332test_expect_success 'zero-width regex ^ matches any function name' '
333 git log --format="%s" --no-patch "-L:^:file.c" >actual &&
334 test_cmp expect actual
335'
336
337test_expect_success 'zero-width regex .* matches any function name' '
338 git log --format="%s" --no-patch "-L:.*:file.c" >actual &&
339 test_cmp expect actual
340'
341
342test_expect_success 'show line-log with graph' '
343 qz_to_tab_space >expect <<-EOF &&
344 * $head_oid Modify func2() in file.c
345 |Z
346 | diff --git a/file.c b/file.c
347 | --- a/file.c
348 | +++ b/file.c
349 | @@ -6,4 +6,4 @@
350 | int func2()
351 | {
352 | - return F2;
353 | + return F2 + 2;
354 | }
355 * $root_oid Add func1() and func2() in file.c
356 ZZ
357 diff --git a/file.c b/file.c
358 --- /dev/null
359 +++ b/file.c
360 @@ -0,0 +6,4 @@
361 +int func2()
362 +{
363 + return F2;
364 +}
365 EOF
366 git log --graph --oneline -L:func2:file.c >actual &&
367 test_cmp expect actual
368'
369
370test_done