The eighteenth batch
[git.git] / t / t8013-blame-ignore-revs.sh
blobd33788d86772936a4e1ad0a1acbca9b2d9b57662
1 #!/bin/sh
3 test_description='ignore revisions when blaming'
5 TEST_PASSES_SANITIZE_LEAK=true
6 . ./test-lib.sh
8 # Creates:
9 # A--B--X
10 # A added line 1 and B added line 2. X makes changes to those lines. Sanity
11 # check that X is blamed for both lines.
12 test_expect_success setup '
13 test_commit A file line1 &&
15 echo line2 >>file &&
16 git add file &&
17 test_tick &&
18 git commit -m B &&
19 git tag B &&
21 test_write_lines line-one line-two >file &&
22 git add file &&
23 test_tick &&
24 git commit -m X &&
25 git tag X &&
26 git tag -a -m "X (annotated)" XT &&
28 git blame --line-porcelain file >blame_raw &&
30 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
31 git rev-parse X >expect &&
32 test_cmp expect actual &&
34 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
35 git rev-parse X >expect &&
36 test_cmp expect actual
39 # Ensure bogus --ignore-rev requests are caught
40 test_expect_success 'validate --ignore-rev' '
41 test_must_fail git blame --ignore-rev X^{tree} file
44 # Ensure bogus --ignore-revs-file requests are silently accepted
45 test_expect_success 'validate --ignore-revs-file' '
46 git rev-parse X^{tree} >ignore_x &&
47 git blame --ignore-revs-file ignore_x file
50 for I in X XT
52 # Ignore X (or XT), make sure A is blamed for line 1 and B for line 2.
53 # Giving X (i.e. commit) and XT (i.e. annotated tag to commit) should
54 # produce the same result.
55 test_expect_success "ignore_rev_changing_lines ($I)" '
56 git blame --line-porcelain --ignore-rev $I file >blame_raw &&
58 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
59 git rev-parse A >expect &&
60 test_cmp expect actual &&
62 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
63 git rev-parse B >expect &&
64 test_cmp expect actual
66 done
68 # For ignored revs that have added 'unblamable' lines, attribute those to the
69 # ignored commit.
70 # A--B--X--Y
71 # Where Y changes lines 1 and 2, and adds lines 3 and 4. The added lines ought
72 # to have nothing in common with "line-one" or "line-two", to keep any
73 # heuristics from matching them with any lines in the parent.
74 test_expect_success ignore_rev_adding_unblamable_lines '
75 test_write_lines line-one-change line-two-changed y3 y4 >file &&
76 git add file &&
77 test_tick &&
78 git commit -m Y &&
79 git tag Y &&
81 git rev-parse Y >expect &&
82 git blame --line-porcelain file --ignore-rev Y >blame_raw &&
84 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 3/s/ .*//p" blame_raw >actual &&
85 test_cmp expect actual &&
87 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 4/s/ .*//p" blame_raw >actual &&
88 test_cmp expect actual
91 # Ignore X and Y, both in separate files. Lines 1 == A, 2 == B.
92 test_expect_success ignore_revs_from_files '
93 git rev-parse X >ignore_x &&
94 git rev-parse Y >ignore_y &&
95 git blame --line-porcelain file --ignore-revs-file ignore_x --ignore-revs-file ignore_y >blame_raw &&
97 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
98 git rev-parse A >expect &&
99 test_cmp expect actual &&
101 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
102 git rev-parse B >expect &&
103 test_cmp expect actual
106 # Ignore X from the config option, Y from a file.
107 test_expect_success ignore_revs_from_configs_and_files '
108 git config --add blame.ignoreRevsFile ignore_x &&
109 git blame --line-porcelain file --ignore-revs-file ignore_y >blame_raw &&
111 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
112 git rev-parse A >expect &&
113 test_cmp expect actual &&
115 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
116 git rev-parse B >expect &&
117 test_cmp expect actual
120 # Override blame.ignoreRevsFile (ignore_x) with an empty string. X should be
121 # blamed now for lines 1 and 2, since we are no longer ignoring X.
122 test_expect_success override_ignore_revs_file '
123 git blame --line-porcelain file --ignore-revs-file "" --ignore-revs-file ignore_y >blame_raw &&
124 git rev-parse X >expect &&
126 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
127 test_cmp expect actual &&
129 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 2/s/ .*//p" blame_raw >actual &&
130 test_cmp expect actual
132 test_expect_success bad_files_and_revs '
133 test_must_fail git blame file --ignore-rev NOREV 2>err &&
134 test_grep "cannot find revision NOREV to ignore" err &&
136 test_must_fail git blame file --ignore-revs-file NOFILE 2>err &&
137 test_grep "could not open.*: NOFILE" err &&
139 echo NOREV >ignore_norev &&
140 test_must_fail git blame file --ignore-revs-file ignore_norev 2>err &&
141 test_grep "invalid object name: NOREV" err
144 # For ignored revs that have added 'unblamable' lines, mark those lines with a
145 # '*'
146 # A--B--X--Y
147 # Lines 3 and 4 are from Y and unblamable. This was set up in
148 # ignore_rev_adding_unblamable_lines.
149 test_expect_success mark_unblamable_lines '
150 git config --add blame.markUnblamableLines true &&
152 git blame --ignore-rev Y file >blame_raw &&
153 echo "*" >expect &&
155 sed -n "3p" blame_raw | cut -c1 >actual &&
156 test_cmp expect actual &&
158 sed -n "4p" blame_raw | cut -c1 >actual &&
159 test_cmp expect actual
162 # Commit Z will touch the first two lines. Y touched all four.
163 # A--B--X--Y--Z
164 # The blame output when ignoring Z should be:
165 # ?Y ... 1)
166 # ?Y ... 2)
167 # Y ... 3)
168 # Y ... 4)
169 # We're checking only the first character
170 test_expect_success mark_ignored_lines '
171 git config --add blame.markIgnoredLines true &&
173 test_write_lines line-one-Z line-two-Z y3 y4 >file &&
174 git add file &&
175 test_tick &&
176 git commit -m Z &&
177 git tag Z &&
179 git blame --ignore-rev Z file >blame_raw &&
180 echo "?" >expect &&
182 sed -n "1p" blame_raw | cut -c1 >actual &&
183 test_cmp expect actual &&
185 sed -n "2p" blame_raw | cut -c1 >actual &&
186 test_cmp expect actual &&
188 sed -n "3p" blame_raw | cut -c1 >actual &&
189 ! test_cmp expect actual &&
191 sed -n "4p" blame_raw | cut -c1 >actual &&
192 ! test_cmp expect actual
195 # For ignored revs that added 'unblamable' lines and more recent commits changed
196 # the blamable lines, mark the unblamable lines with a
197 # '*'
198 # A--B--X--Y--Z
199 # Lines 3 and 4 are from Y and unblamable, as set up in
200 # ignore_rev_adding_unblamable_lines. Z changed lines 1 and 2.
201 test_expect_success mark_unblamable_lines_intermediate '
202 git config --add blame.markUnblamableLines true &&
204 git blame --ignore-rev Y file >blame_raw 2>stderr &&
205 echo "*" >expect &&
207 sed -n "3p" blame_raw | cut -c1 >actual &&
208 test_cmp expect actual &&
210 sed -n "4p" blame_raw | cut -c1 >actual &&
211 test_cmp expect actual
214 # The heuristic called by guess_line_blames() tries to find the size of a
215 # blame_entry 'e' in the parent's address space. Those calculations need to
216 # check for negative or zero values for when a blame entry is completely outside
217 # the window of the parent's version of a file.
219 # This happens when one commit adds several lines (commit B below). A later
220 # commit (C) changes one line in the middle of B's change. Commit C gets blamed
221 # for its change, and that breaks up B's change into multiple blame entries.
222 # When processing B, one of the blame_entries is outside A's window (which was
223 # zero - it had no lines added on its side of the diff).
225 # A--B--C, ignore B to test the ignore heuristic's boundary checks.
226 test_expect_success ignored_chunk_negative_parent_size '
227 rm -rf .git/ &&
228 git init &&
230 test_write_lines L1 L2 L7 L8 L9 >file &&
231 git add file &&
232 test_tick &&
233 git commit -m A &&
234 git tag A &&
236 test_write_lines L1 L2 L3 L4 L5 L6 L7 L8 L9 >file &&
237 git add file &&
238 test_tick &&
239 git commit -m B &&
240 git tag B &&
242 test_write_lines L1 L2 L3 L4 xxx L6 L7 L8 L9 >file &&
243 git add file &&
244 test_tick &&
245 git commit -m C &&
246 git tag C &&
248 git blame file --ignore-rev B >blame_raw
251 # Resetting the repo and creating:
253 # A--B--M
254 # \ /
255 # C-+
257 # 'A' creates a file. B changes line 1, and C changes line 9. M merges.
258 test_expect_success ignore_merge '
259 rm -rf .git/ &&
260 git init &&
262 test_write_lines L1 L2 L3 L4 L5 L6 L7 L8 L9 >file &&
263 git add file &&
264 test_tick &&
265 git commit -m A &&
266 git tag A &&
268 test_write_lines BB L2 L3 L4 L5 L6 L7 L8 L9 >file &&
269 git add file &&
270 test_tick &&
271 git commit -m B &&
272 git tag B &&
274 git reset --hard A &&
275 test_write_lines L1 L2 L3 L4 L5 L6 L7 L8 CC >file &&
276 git add file &&
277 test_tick &&
278 git commit -m C &&
279 git tag C &&
281 test_merge M B &&
282 git blame --line-porcelain file --ignore-rev M >blame_raw &&
284 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 1/s/ .*//p" blame_raw >actual &&
285 git rev-parse B >expect &&
286 test_cmp expect actual &&
288 sed -ne "/^[0-9a-f][0-9a-f]* [0-9][0-9]* 9/s/ .*//p" blame_raw >actual &&
289 git rev-parse C >expect &&
290 test_cmp expect actual
293 test_done