Raw
1 #!/bin/sh
2
3 test_description='ignore revisions when blaming'
4
5 . ./test-lib.sh
6
7 # Creates:
8 # A--B--X
9 # A added line 1 and B added line 2. X makes changes to those lines. Sanity
10 # check that X is blamed for both lines.
11 test_expect_success setup '
12 test_commit A file line1 &&
13
14 echo line2 >>file &&
15 git add file &&
16 test_tick &&
17 git commit -m B &&
18 git tag B &&
19
20 test_write_lines line-one line-two >file &&
21 git add file &&
22 test_tick &&
23 git commit -m X &&
24 git tag X &&
25 git tag -a -m "X (annotated)" XT &&
26
27 git blame --line-porcelain file >blame_raw &&
28
29 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
30 git rev-parse X >expect &&
31 test_cmp expect actual &&
32
33 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
34 git rev-parse X >expect &&
35 test_cmp expect actual
36 '
37
38 # Ensure bogus --ignore-rev requests are caught
39 test_expect_success 'validate --ignore-rev' '
40 test_must_fail git blame --ignore-rev X^{tree} file
41 '
42
43 # Ensure bogus --ignore-revs-file requests are silently accepted
44 test_expect_success 'validate --ignore-revs-file' '
45 git rev-parse X^{tree} >ignore_x &&
46 git blame --ignore-revs-file ignore_x file
47 '
48
49 for I in X XT
50 do
51 # Ignore X (or XT), make sure A is blamed for line 1 and B for line 2.
52 # Giving X (i.e. commit) and XT (i.e. annotated tag to commit) should
53 # produce the same result.
54 test_expect_success "ignore_rev_changing_lines ($I)" '
55 git blame --line-porcelain --ignore-rev $I file >blame_raw &&
56
57 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
58 git rev-parse A >expect &&
59 test_cmp expect actual &&
60
61 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
62 git rev-parse B >expect &&
63 test_cmp expect actual
64 '
65 done
66
67 # For ignored revs that have added 'unblamable' lines, attribute those to the
68 # ignored commit.
69 # A--B--X--Y
70 # Where Y changes lines 1 and 2, and adds lines 3 and 4. The added lines ought
71 # to have nothing in common with "line-one" or "line-two", to keep any
72 # heuristics from matching them with any lines in the parent.
73 test_expect_success ignore_rev_adding_unblamable_lines '
74 test_write_lines line-one-change line-two-changed y3 y4 >file &&
75 git add file &&
76 test_tick &&
77 git commit -m Y &&
78 git tag Y &&
79
80 git rev-parse Y >expect &&
81 git blame --line-porcelain file --ignore-rev Y >blame_raw &&
82
83 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 3/s/ .*//p" blame_raw >actual &&
84 test_cmp expect actual &&
85
86 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 4/s/ .*//p" blame_raw >actual &&
87 test_cmp expect actual
88 '
89
90 # Ignore X and Y, both in separate files. Lines 1 == A, 2 == B.
91 test_expect_success ignore_revs_from_files '
92 git rev-parse X >ignore_x &&
93 git rev-parse Y >ignore_y &&
94 git blame --line-porcelain file --ignore-revs-file ignore_x --ignore-revs-file ignore_y >blame_raw &&
95
96 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
97 git rev-parse A >expect &&
98 test_cmp expect actual &&
99
100 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
101 git rev-parse B >expect &&
102 test_cmp expect actual
103 '
104
105 # Ignore X from the config option, Y from a file.
106 test_expect_success ignore_revs_from_configs_and_files '
107 git config --add blame.ignoreRevsFile ignore_x &&
108 git blame --line-porcelain file --ignore-revs-file ignore_y >blame_raw &&
109
110 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
111 git rev-parse A >expect &&
112 test_cmp expect actual &&
113
114 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
115 git rev-parse B >expect &&
116 test_cmp expect actual
117 '
118
119 # Override blame.ignoreRevsFile (ignore_x) with an empty string. X should be
120 # blamed now for lines 1 and 2, since we are no longer ignoring X.
121 test_expect_success override_ignore_revs_file '
122 git blame --line-porcelain file --ignore-revs-file "" --ignore-revs-file ignore_y >blame_raw &&
123 git rev-parse X >expect &&
124
125 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
126 test_cmp expect actual &&
127
128 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
129 test_cmp expect actual
130 '
131 test_expect_success bad_files_and_revs '
132 test_must_fail git blame file --ignore-rev NOREV 2>err &&
133 test_grep "cannot find revision NOREV to ignore" err &&
134
135 test_must_fail git blame file --ignore-revs-file NOFILE 2>err &&
136 test_grep "could not open.*: NOFILE" err &&
137
138 echo NOREV >ignore_norev &&
139 test_must_fail git blame file --ignore-revs-file ignore_norev 2>err &&
140 test_grep "invalid object name: NOREV" err
141 '
142
143 # For ignored revs that have added 'unblamable' lines, mark those lines with a
144 # '*'
145 # A--B--X--Y
146 # Lines 3 and 4 are from Y and unblamable. This was set up in
147 # ignore_rev_adding_unblamable_lines.
148 test_expect_success mark_unblamable_lines '
149 git config --add blame.markUnblamableLines true &&
150
151 git blame --ignore-rev Y file >blame_raw &&
152 echo "*" >expect &&
153
154 sed -n "3p" blame_raw | cut -c1 >actual &&
155 test_cmp expect actual &&
156
157 sed -n "4p" blame_raw | cut -c1 >actual &&
158 test_cmp expect actual
159 '
160
161 for opt in --porcelain --line-porcelain
162 do
163 test_expect_success "mark_unblamable_lines with $opt" "
164 sha=$(git rev-parse Y) &&
165
166 git -c blame.markUnblamableLines=false blame $opt --ignore-rev Y file >raw &&
167 cat > sedscript <<- 'EOF' &&
168 /^ y3/i\\
169 unblamable
170 /^ y4/i\\
171 unblamable
172 EOF
173 sed -f sedscript raw >expect &&
174
175 git -c blame.markUnblamableLines=true blame $opt --ignore-rev Y file >actual &&
176 test_cmp expect actual
177 "
178 done
179
180 # Commit Z will touch the first two lines. Y touched all four.
181 # A--B--X--Y--Z
182 # The blame output when ignoring Z should be:
183 # ?Y ... 1)
184 # ?Y ... 2)
185 # Y ... 3)
186 # Y ... 4)
187 # We're checking only the first character
188 test_expect_success mark_ignored_lines '
189 git config --add blame.markIgnoredLines true &&
190
191 test_write_lines line-one-Z line-two-Z y3 y4 >file &&
192 git add file &&
193 test_tick &&
194 git commit -m Z &&
195 git tag Z &&
196
197 git blame --ignore-rev Z file >blame_raw &&
198 echo "?" >expect &&
199
200 sed -n "1p" blame_raw | cut -c1 >actual &&
201 test_cmp expect actual &&
202
203 sed -n "2p" blame_raw | cut -c1 >actual &&
204 test_cmp expect actual &&
205
206 sed -n "3p" blame_raw | cut -c1 >actual &&
207 ! test_cmp expect actual &&
208
209 sed -n "4p" blame_raw | cut -c1 >actual &&
210 ! test_cmp expect actual
211 '
212
213 for opt in --porcelain --line-porcelain
214 do
215 test_expect_success "mark_ignored_lines with $opt" "
216 sha=$(git rev-parse Y) &&
217
218 git -c blame.markIgnoredLines=false blame $opt --ignore-rev Z file >raw &&
219 cat > sedscript <<- 'EOF' &&
220 /^ line-one-Z/i\\
221 ignored
222 /^ line-two-Z/i\\
223 ignored
224 EOF
225 sed -f sedscript raw >expect &&
226
227 git -c blame.markIgnoredLines=true blame $opt --ignore-rev Z file >actual &&
228 test_cmp expect actual
229 "
230 done
231
232 # For ignored revs that added 'unblamable' lines and more recent commits changed
233 # the blamable lines, mark the unblamable lines with a
234 # '*'
235 # A--B--X--Y--Z
236 # Lines 3 and 4 are from Y and unblamable, as set up in
237 # ignore_rev_adding_unblamable_lines. Z changed lines 1 and 2.
238 test_expect_success mark_unblamable_lines_intermediate '
239 git config --add blame.markUnblamableLines true &&
240
241 git blame --ignore-rev Y file >blame_raw 2>stderr &&
242 echo "*" >expect &&
243
244 sed -n "3p" blame_raw | cut -c1 >actual &&
245 test_cmp expect actual &&
246
247 sed -n "4p" blame_raw | cut -c1 >actual &&
248 test_cmp expect actual
249 '
250
251 # The heuristic called by guess_line_blames() tries to find the size of a
252 # blame_entry 'e' in the parent's address space. Those calculations need to
253 # check for negative or zero values for when a blame entry is completely outside
254 # the window of the parent's version of a file.
255 #
256 # This happens when one commit adds several lines (commit B below). A later
257 # commit (C) changes one line in the middle of B's change. Commit C gets blamed
258 # for its change, and that breaks up B's change into multiple blame entries.
259 # When processing B, one of the blame_entries is outside A's window (which was
260 # zero - it had no lines added on its side of the diff).
261 #
262 # A--B--C, ignore B to test the ignore heuristic's boundary checks.
263 test_expect_success ignored_chunk_negative_parent_size '
264 rm -rf .git/ &&
265 git init &&
266
267 test_write_lines L1 L2 L7 L8 L9 >file &&
268 git add file &&
269 test_tick &&
270 git commit -m A &&
271 git tag A &&
272
273 test_write_lines L1 L2 L3 L4 L5 L6 L7 L8 L9 >file &&
274 git add file &&
275 test_tick &&
276 git commit -m B &&
277 git tag B &&
278
279 test_write_lines L1 L2 L3 L4 xxx L6 L7 L8 L9 >file &&
280 git add file &&
281 test_tick &&
282 git commit -m C &&
283 git tag C &&
284
285 git blame file --ignore-rev B >blame_raw
286 '
287
288 # Resetting the repo and creating:
289 #
290 # A--B--M
291 # \ /
292 # C-+
293 #
294 # 'A' creates a file. B changes line 1, and C changes line 9. M merges.
295 test_expect_success ignore_merge '
296 rm -rf .git/ &&
297 git init &&
298
299 test_write_lines L1 L2 L3 L4 L5 L6 L7 L8 L9 >file &&
300 git add file &&
301 test_tick &&
302 git commit -m A &&
303 git tag A &&
304
305 test_write_lines BB L2 L3 L4 L5 L6 L7 L8 L9 >file &&
306 git add file &&
307 test_tick &&
308 git commit -m B &&
309 git tag B &&
310
311 git reset --hard A &&
312 test_write_lines L1 L2 L3 L4 L5 L6 L7 L8 CC >file &&
313 git add file &&
314 test_tick &&
315 git commit -m C &&
316 git tag C &&
317
318 test_merge M B &&
319 git blame --line-porcelain file --ignore-rev M >blame_raw &&
320
321 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
322 git rev-parse B >expect &&
323 test_cmp expect actual &&
324
325 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 9/s/ .*//p" blame_raw >actual &&
326 git rev-parse C >expect &&
327 test_cmp expect actual
328 '
329
330 test_done