t / t7003-filter-branch.shon commit Merge branch 'ss/fix-config-fd-leak' into maint (8136099)
   1#!/bin/sh
   2
   3test_description='git filter-branch'
   4. ./test-lib.sh
   5
   6test_expect_success 'setup' '
   7        test_commit A &&
   8        GIT_COMMITTER_DATE="@0 +0000" GIT_AUTHOR_DATE="@0 +0000" &&
   9        test_commit --notick B &&
  10        git checkout -b branch B &&
  11        test_commit D &&
  12        mkdir dir &&
  13        test_commit dir/D &&
  14        test_commit E &&
  15        git checkout master &&
  16        test_commit C &&
  17        git checkout branch &&
  18        git merge C &&
  19        git tag F &&
  20        test_commit G &&
  21        test_commit H
  22'
  23# * (HEAD, branch) H
  24# * G
  25# *   Merge commit 'C' into branch
  26# |\
  27# | * (master) C
  28# * | E
  29# * | dir/D
  30# * | D
  31# |/
  32# * B
  33# * A
  34
  35
  36H=$(git rev-parse H)
  37
  38test_expect_success 'rewrite identically' '
  39        git filter-branch branch
  40'
  41test_expect_success 'result is really identical' '
  42        test $H = $(git rev-parse HEAD)
  43'
  44
  45test_expect_success 'rewrite bare repository identically' '
  46        (git config core.bare true && cd .git &&
  47         git filter-branch branch > filter-output 2>&1 &&
  48        ! fgrep fatal filter-output)
  49'
  50git config core.bare false
  51test_expect_success 'result is really identical' '
  52        test $H = $(git rev-parse HEAD)
  53'
  54
  55TRASHDIR=$(pwd)
  56test_expect_success 'correct GIT_DIR while using -d' '
  57        mkdir drepo &&
  58        ( cd drepo &&
  59        git init &&
  60        test_commit drepo &&
  61        git filter-branch -d "$TRASHDIR/dfoo" \
  62                --index-filter "cp \"$TRASHDIR\"/dfoo/backup-refs \"$TRASHDIR\"" \
  63        ) &&
  64        grep drepo "$TRASHDIR/backup-refs"
  65'
  66
  67test_expect_success 'tree-filter works with -d' '
  68        git init drepo-tree &&
  69        (
  70                cd drepo-tree &&
  71                test_commit one &&
  72                git filter-branch -d "$TRASHDIR/dfoo" \
  73                        --tree-filter "echo changed >one.t" &&
  74                echo changed >expect &&
  75                git cat-file blob HEAD:one.t >actual &&
  76                test_cmp expect actual &&
  77                test_cmp one.t actual
  78        )
  79'
  80
  81test_expect_success 'Fail if commit filter fails' '
  82        test_must_fail git filter-branch -f --commit-filter "exit 1" HEAD
  83'
  84
  85test_expect_success 'rewrite, renaming a specific file' '
  86        git filter-branch -f --tree-filter "mv D.t doh || :" HEAD
  87'
  88
  89test_expect_success 'test that the file was renamed' '
  90        test D = "$(git show HEAD:doh --)" &&
  91        ! test -f D.t &&
  92        test -f doh &&
  93        test D = "$(cat doh)"
  94'
  95
  96test_expect_success 'rewrite, renaming a specific directory' '
  97        git filter-branch -f --tree-filter "mv dir diroh || :" HEAD
  98'
  99
 100test_expect_success 'test that the directory was renamed' '
 101        test dir/D = "$(git show HEAD:diroh/D.t --)" &&
 102        ! test -d dir &&
 103        test -d diroh &&
 104        ! test -d diroh/dir &&
 105        test -f diroh/D.t &&
 106        test dir/D = "$(cat diroh/D.t)"
 107'
 108
 109git tag oldD HEAD~4
 110test_expect_success 'rewrite one branch, keeping a side branch' '
 111        git branch modD oldD &&
 112        git filter-branch -f --tree-filter "mv B.t boh || :" D..modD
 113'
 114
 115test_expect_success 'common ancestor is still common (unchanged)' '
 116        test "$(git merge-base modD D)" = "$(git rev-parse B)"
 117'
 118
 119test_expect_success 'filter subdirectory only' '
 120        mkdir subdir &&
 121        touch subdir/new &&
 122        git add subdir/new &&
 123        test_tick &&
 124        git commit -m "subdir" &&
 125        echo H > A.t &&
 126        test_tick &&
 127        git commit -m "not subdir" A.t &&
 128        echo A > subdir/new &&
 129        test_tick &&
 130        git commit -m "again subdir" subdir/new &&
 131        git rm A.t &&
 132        test_tick &&
 133        git commit -m "again not subdir" &&
 134        git branch sub &&
 135        git branch sub-earlier HEAD~2 &&
 136        git filter-branch -f --subdirectory-filter subdir \
 137                refs/heads/sub refs/heads/sub-earlier
 138'
 139
 140test_expect_success 'subdirectory filter result looks okay' '
 141        test 2 = $(git rev-list sub | wc -l) &&
 142        git show sub:new &&
 143        test_must_fail git show sub:subdir &&
 144        git show sub-earlier:new &&
 145        test_must_fail git show sub-earlier:subdir
 146'
 147
 148test_expect_success 'more setup' '
 149        git checkout master &&
 150        mkdir subdir &&
 151        echo A > subdir/new &&
 152        git add subdir/new &&
 153        test_tick &&
 154        git commit -m "subdir on master" subdir/new &&
 155        git rm A.t &&
 156        test_tick &&
 157        git commit -m "again subdir on master" &&
 158        git merge branch
 159'
 160
 161test_expect_success 'use index-filter to move into a subdirectory' '
 162        git branch directorymoved &&
 163        git filter-branch -f --index-filter \
 164                 "git ls-files -s | sed \"s-    -&newsubdir/-\" |
 165                  GIT_INDEX_FILE=\$GIT_INDEX_FILE.new \
 166                        git update-index --index-info &&
 167                  mv \"\$GIT_INDEX_FILE.new\" \"\$GIT_INDEX_FILE\"" directorymoved &&
 168        git diff --exit-code HEAD directorymoved:newsubdir
 169'
 170
 171test_expect_success 'stops when msg filter fails' '
 172        old=$(git rev-parse HEAD) &&
 173        test_must_fail git filter-branch -f --msg-filter false HEAD &&
 174        test $old = $(git rev-parse HEAD) &&
 175        rm -rf .git-rewrite
 176'
 177
 178test_expect_success 'author information is preserved' '
 179        : > i &&
 180        git add i &&
 181        test_tick &&
 182        GIT_AUTHOR_NAME="B V Uips" git commit -m bvuips &&
 183        git branch preserved-author &&
 184        (sane_unset GIT_AUTHOR_NAME &&
 185         git filter-branch -f --msg-filter "cat; \
 186                        test \$GIT_COMMIT != $(git rev-parse master) || \
 187                        echo Hallo" \
 188                preserved-author) &&
 189        test 1 = $(git rev-list --author="B V Uips" preserved-author | wc -l)
 190'
 191
 192test_expect_success "remove a certain author's commits" '
 193        echo i > i &&
 194        test_tick &&
 195        git commit -m i i &&
 196        git branch removed-author &&
 197        git filter-branch -f --commit-filter "\
 198                if [ \"\$GIT_AUTHOR_NAME\" = \"B V Uips\" ];\
 199                then\
 200                        skip_commit \"\$@\";
 201                else\
 202                        git commit-tree \"\$@\";\
 203                fi" removed-author &&
 204        cnt1=$(git rev-list master | wc -l) &&
 205        cnt2=$(git rev-list removed-author | wc -l) &&
 206        test $cnt1 -eq $(($cnt2 + 1)) &&
 207        test 0 = $(git rev-list --author="B V Uips" removed-author | wc -l)
 208'
 209
 210test_expect_success 'barf on invalid name' '
 211        test_must_fail git filter-branch -f master xy-problem &&
 212        test_must_fail git filter-branch -f HEAD^
 213'
 214
 215test_expect_success '"map" works in commit filter' '
 216        git filter-branch -f --commit-filter "\
 217                parent=\$(git rev-parse \$GIT_COMMIT^) &&
 218                mapped=\$(map \$parent) &&
 219                actual=\$(echo \"\$@\" | sed \"s/^.*-p //\") &&
 220                test \$mapped = \$actual &&
 221                git commit-tree \"\$@\";" master~2..master &&
 222        git rev-parse --verify master
 223'
 224
 225test_expect_success 'Name needing quotes' '
 226
 227        git checkout -b rerere A &&
 228        mkdir foo &&
 229        name="れれれ" &&
 230        >foo/$name &&
 231        git add foo &&
 232        git commit -m "Adding a file" &&
 233        git filter-branch --tree-filter "rm -fr foo" &&
 234        test_must_fail git ls-files --error-unmatch "foo/$name" &&
 235        test $(git rev-parse --verify rerere) != $(git rev-parse --verify A)
 236
 237'
 238
 239test_expect_success 'Subdirectory filter with disappearing trees' '
 240        git reset --hard &&
 241        git checkout master &&
 242
 243        mkdir foo &&
 244        touch foo/bar &&
 245        git add foo &&
 246        test_tick &&
 247        git commit -m "Adding foo" &&
 248
 249        git rm -r foo &&
 250        test_tick &&
 251        git commit -m "Removing foo" &&
 252
 253        mkdir foo &&
 254        touch foo/bar &&
 255        git add foo &&
 256        test_tick &&
 257        git commit -m "Re-adding foo" &&
 258
 259        git filter-branch -f --subdirectory-filter foo &&
 260        test $(git rev-list master | wc -l) = 3
 261'
 262
 263test_expect_success 'Tag name filtering retains tag message' '
 264        git tag -m atag T &&
 265        git cat-file tag T > expect &&
 266        git filter-branch -f --tag-name-filter cat &&
 267        git cat-file tag T > actual &&
 268        test_cmp expect actual
 269'
 270
 271faux_gpg_tag='object XXXXXX
 272type commit
 273tag S
 274tagger T A Gger <tagger@example.com> 1206026339 -0500
 275
 276This is a faux gpg signed tag.
 277-----BEGIN PGP SIGNATURE-----
 278Version: FauxGPG v0.0.0 (FAUX/Linux)
 279
 280gdsfoewhxu/6l06f1kxyxhKdZkrcbaiOMtkJUA9ITAc1mlamh0ooasxkH1XwMbYQ
 281acmwXaWET20H0GeAGP+7vow=
 282=agpO
 283-----END PGP SIGNATURE-----
 284'
 285test_expect_success 'Tag name filtering strips gpg signature' '
 286        sha1=$(git rev-parse HEAD) &&
 287        sha1t=$(echo "$faux_gpg_tag" | sed -e s/XXXXXX/$sha1/ | git mktag) &&
 288        git update-ref "refs/tags/S" "$sha1t" &&
 289        echo "$faux_gpg_tag" | sed -e s/XXXXXX/$sha1/ | head -n 6 > expect &&
 290        git filter-branch -f --tag-name-filter cat &&
 291        git cat-file tag S > actual &&
 292        test_cmp expect actual
 293'
 294
 295test_expect_success 'Tag name filtering allows slashes in tag names' '
 296        git tag -m tag-with-slash X/1 &&
 297        git cat-file tag X/1 | sed -e s,X/1,X/2, > expect &&
 298        git filter-branch -f --tag-name-filter "echo X/2" &&
 299        git cat-file tag X/2 > actual &&
 300        test_cmp expect actual
 301'
 302
 303test_expect_success 'Prune empty commits' '
 304        git rev-list HEAD > expect &&
 305        test_commit to_remove &&
 306        git filter-branch -f --index-filter "git update-index --remove to_remove.t" --prune-empty HEAD &&
 307        git rev-list HEAD > actual &&
 308        test_cmp expect actual
 309'
 310
 311test_expect_success 'prune empty collapsed merges' '
 312        test_config merge.ff false &&
 313        git rev-list HEAD >expect &&
 314        test_commit to_remove_2 &&
 315        git reset --hard HEAD^ &&
 316        test_merge non-ff to_remove_2 &&
 317        git filter-branch -f --index-filter "git update-index --remove to_remove_2.t" --prune-empty HEAD &&
 318        git rev-list HEAD >actual &&
 319        test_cmp expect actual
 320'
 321
 322test_expect_success '--remap-to-ancestor with filename filters' '
 323        git checkout master &&
 324        git reset --hard A &&
 325        test_commit add-foo foo 1 &&
 326        git branch moved-foo &&
 327        test_commit add-bar bar a &&
 328        git branch invariant &&
 329        orig_invariant=$(git rev-parse invariant) &&
 330        git branch moved-bar &&
 331        test_commit change-foo foo 2 &&
 332        git filter-branch -f --remap-to-ancestor \
 333                moved-foo moved-bar A..master \
 334                -- -- foo &&
 335        test $(git rev-parse moved-foo) = $(git rev-parse moved-bar) &&
 336        test $(git rev-parse moved-foo) = $(git rev-parse master^) &&
 337        test $orig_invariant = $(git rev-parse invariant)
 338'
 339
 340test_expect_success 'automatic remapping to ancestor with filename filters' '
 341        git checkout master &&
 342        git reset --hard A &&
 343        test_commit add-foo2 foo 1 &&
 344        git branch moved-foo2 &&
 345        test_commit add-bar2 bar a &&
 346        git branch invariant2 &&
 347        orig_invariant=$(git rev-parse invariant2) &&
 348        git branch moved-bar2 &&
 349        test_commit change-foo2 foo 2 &&
 350        git filter-branch -f \
 351                moved-foo2 moved-bar2 A..master \
 352                -- -- foo &&
 353        test $(git rev-parse moved-foo2) = $(git rev-parse moved-bar2) &&
 354        test $(git rev-parse moved-foo2) = $(git rev-parse master^) &&
 355        test $orig_invariant = $(git rev-parse invariant2)
 356'
 357
 358test_expect_success 'setup submodule' '
 359        rm -fr ?* .git &&
 360        git init &&
 361        test_commit file &&
 362        mkdir submod &&
 363        submodurl="$PWD/submod" &&
 364        ( cd submod &&
 365          git init &&
 366          test_commit file-in-submod ) &&
 367        git submodule add "$submodurl" &&
 368        git commit -m "added submodule" &&
 369        test_commit add-file &&
 370        ( cd submod && test_commit add-in-submodule ) &&
 371        git add submod &&
 372        git commit -m "changed submodule" &&
 373        git branch original HEAD
 374'
 375
 376orig_head=`git show-ref --hash --head HEAD`
 377
 378test_expect_success 'rewrite submodule with another content' '
 379        git filter-branch --tree-filter "test -d submod && {
 380                                         rm -rf submod &&
 381                                         git rm -rf --quiet submod &&
 382                                         mkdir submod &&
 383                                         : > submod/file
 384                                         } || :" HEAD &&
 385        test $orig_head != `git show-ref --hash --head HEAD`
 386'
 387
 388test_expect_success 'replace submodule revision' '
 389        git reset --hard original &&
 390        git filter-branch -f --tree-filter \
 391            "if git ls-files --error-unmatch -- submod > /dev/null 2>&1
 392             then git update-index --cacheinfo 160000 0123456789012345678901234567890123456789 submod
 393             fi" HEAD &&
 394        test $orig_head != `git show-ref --hash --head HEAD`
 395'
 396
 397test_expect_success 'filter commit message without trailing newline' '
 398        git reset --hard original &&
 399        commit=$(printf "no newline" | git commit-tree HEAD^{tree}) &&
 400        git update-ref refs/heads/no-newline $commit &&
 401        git filter-branch -f refs/heads/no-newline &&
 402        echo $commit >expect &&
 403        git rev-parse refs/heads/no-newline >actual &&
 404        test_cmp expect actual
 405'
 406
 407test_done