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