45237c337492a4deefe918662967faf4add2e9f8
   1#!/bin/bash
   2. shellopts.sh
   3set -e
   4
   5create()
   6{
   7        echo "$1" >"$1"
   8        git add "$1"
   9}
  10
  11check()
  12{
  13        echo
  14        echo "check:" "$@"
  15        if "$@"; then
  16                echo ok
  17                return 0
  18        else
  19                echo FAILED
  20                exit 1
  21        fi
  22}
  23
  24check_not()
  25{
  26        echo
  27        echo "check: NOT " "$@"
  28        if "$@"; then
  29                echo FAILED
  30                exit 1
  31        else
  32                echo ok
  33                return 0
  34        fi
  35}
  36
  37check_equal()
  38{
  39        echo
  40        echo "check a:" "{$1}"
  41        echo "      b:" "{$2}"
  42        if [ "$1" = "$2" ]; then
  43                return 0
  44        else
  45                echo FAILED
  46                exit 1
  47        fi
  48}
  49
  50fixnl()
  51{       
  52        t=""
  53        while read x; do
  54                t="$t$x "
  55        done
  56        echo $t
  57}
  58
  59multiline()
  60{
  61        while read x; do
  62                set -- $x
  63                for d in "$@"; do
  64                        echo "$d"
  65                done
  66        done
  67}
  68
  69undo()
  70{
  71        git reset --hard HEAD~
  72}
  73
  74last_commit_message()
  75{
  76        git log --pretty=format:%s -1
  77}
  78
  79rm -rf mainline subproj
  80mkdir mainline subproj
  81
  82cd subproj
  83git init
  84
  85create sub1
  86git commit -m 'sub1'
  87git branch sub1
  88git branch -m master subproj
  89check true
  90
  91create sub2
  92git commit -m 'sub2'
  93git branch sub2
  94
  95create sub3
  96git commit -m 'sub3'
  97git branch sub3
  98
  99cd ../mainline
 100git init
 101create main4
 102git commit -m 'main4'
 103git branch -m master mainline
 104git branch subdir
 105
 106git fetch ../subproj sub1
 107git branch sub1 FETCH_HEAD
 108
 109# check if --message works for add
 110check_not git subtree merge --prefix=subdir sub1
 111check_not git subtree pull --prefix=subdir ../subproj sub1
 112git subtree add --prefix=subdir --message="Added subproject" sub1
 113check_equal "$(last_commit_message)" "Added subproject"
 114undo
 115
 116# check if --message works as -m and --prefix as -P
 117git subtree add -P subdir -m "Added subproject using git subtree" sub1
 118check_equal "$(last_commit_message)" "Added subproject using git subtree"
 119undo
 120
 121# check if --message works with squash too
 122git subtree add -P subdir -m "Added subproject with squash" --squash sub1
 123check_equal "$(last_commit_message)" "Added subproject with squash"
 124undo
 125
 126git subtree add --prefix=subdir/ FETCH_HEAD
 127check_equal "$(last_commit_message)" "Add 'subdir/' from commit '$(git rev-parse sub1)'"
 128
 129# this shouldn't actually do anything, since FETCH_HEAD is already a parent
 130git merge -m 'merge -s -ours' -s ours FETCH_HEAD
 131
 132create subdir/main-sub5
 133git commit -m 'main-sub5'
 134
 135create main6
 136git commit -m 'main6 boring'
 137
 138create subdir/main-sub7
 139git commit -m 'main-sub7'
 140
 141git fetch ../subproj sub2
 142git branch sub2 FETCH_HEAD
 143
 144# check if --message works for merge
 145git subtree merge --prefix=subdir -m "Merged changes from subproject" sub2
 146check_equal "$(last_commit_message)" "Merged changes from subproject"
 147undo
 148
 149# check if --message for merge works with squash too
 150git subtree merge --prefix subdir -m "Merged changes from subproject using squash" --squash sub2
 151check_equal "$(last_commit_message)" "Merged changes from subproject using squash"
 152undo
 153
 154git subtree merge --prefix=subdir FETCH_HEAD
 155git branch pre-split
 156check_equal "$(last_commit_message)" "Merge commit '$(git rev-parse sub2)' into mainline"
 157
 158# Check that prefix argument is required for split (exits with warning and exit status = 1)
 159! result=$(git subtree split 2>&1)
 160check_equal "You must provide the --prefix option." "$result"
 161
 162# Check that the <prefix> exists for a split.
 163! result=$(git subtree split --prefix=non-existent-directory 2>&1)
 164check_equal "'non-existent-directory' does not exist; use 'git subtree add'" \
 165  "$result"
 166
 167# check if --message works for split+rejoin
 168spl1=$(git subtree split --annotate='*' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)
 169echo "spl1={$spl1}"
 170git branch spl1 "$spl1"
 171check_equal "$(last_commit_message)" "Split & rejoin"
 172undo
 173
 174# check split with --branch
 175git subtree split --annotate='*' --prefix subdir --onto FETCH_HEAD --branch splitbr1
 176check_equal "$(git rev-parse splitbr1)" "$spl1"
 177
 178# check split with --branch for an existing branch
 179git branch splitbr2 sub1
 180git subtree split --annotate='*' --prefix subdir --onto FETCH_HEAD --branch splitbr2
 181check_equal "$(git rev-parse splitbr2)" "$spl1"
 182
 183# check split with --branch for an incompatible branch
 184result=$(git subtree split --prefix subdir --onto FETCH_HEAD --branch subdir || echo "caught error")
 185check_equal "$result" "caught error"
 186
 187
 188git subtree split --annotate='*' --prefix subdir --onto FETCH_HEAD --rejoin
 189check_equal "$(last_commit_message)" "Split 'subdir/' into commit '$spl1'"
 190
 191create subdir/main-sub8
 192git commit -m 'main-sub8'
 193
 194cd ../subproj
 195git fetch ../mainline spl1
 196git branch spl1 FETCH_HEAD
 197git merge FETCH_HEAD
 198
 199create sub9
 200git commit -m 'sub9'
 201
 202cd ../mainline
 203split2=$(git subtree split --annotate='*' --prefix subdir/ --rejoin)
 204git branch split2 "$split2"
 205
 206create subdir/main-sub10
 207git commit -m 'main-sub10'
 208
 209spl3=$(git subtree split --annotate='*' --prefix subdir --rejoin)
 210git branch spl3 "$spl3"
 211
 212cd ../subproj
 213git fetch ../mainline spl3
 214git branch spl3 FETCH_HEAD
 215git merge FETCH_HEAD
 216git branch subproj-merge-spl3
 217
 218chkm="main4 main6"
 219chkms="main-sub10 main-sub5 main-sub7 main-sub8"
 220chkms_sub=$(echo $chkms | multiline | sed 's,^,subdir/,' | fixnl)
 221chks="sub1 sub2 sub3 sub9"
 222chks_sub=$(echo $chks | multiline | sed 's,^,subdir/,' | fixnl)
 223
 224# make sure exactly the right set of files ends up in the subproj
 225subfiles=$(git ls-files | fixnl)
 226check_equal "$subfiles" "$chkms $chks"
 227
 228# make sure the subproj history *only* contains commits that affect the subdir.
 229allchanges=$(git log --name-only --pretty=format:'' | sort | fixnl)
 230check_equal "$allchanges" "$chkms $chks"
 231
 232cd ../mainline
 233git fetch ../subproj subproj-merge-spl3
 234git branch subproj-merge-spl3 FETCH_HEAD
 235git subtree pull --prefix=subdir ../subproj subproj-merge-spl3
 236
 237# make sure exactly the right set of files ends up in the mainline
 238mainfiles=$(git ls-files | fixnl)
 239check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub"
 240
 241# make sure each filename changed exactly once in the entire history.
 242# 'main-sub??' and '/subdir/main-sub??' both change, because those are the
 243# changes that were split into their own history.  And 'subdir/sub??' never
 244# change, since they were *only* changed in the subtree branch.
 245allchanges=$(git log --name-only --pretty=format:'' | sort | fixnl)
 246check_equal "$allchanges" "$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"
 247
 248# make sure the --rejoin commits never make it into subproj
 249check_equal "$(git log --pretty=format:'%s' HEAD^2 | grep -i split)" ""
 250
 251# make sure no 'git subtree' tagged commits make it into subproj. (They're
 252# meaningless to subproj since one side of the merge refers to the mainline)
 253check_equal "$(git log --pretty=format:'%s%n%b' HEAD^2 | grep 'git-subtree.*:')" ""
 254
 255
 256# check if split can find proper base without --onto
 257# prepare second pair of repositories
 258mkdir test2
 259cd test2
 260
 261mkdir main
 262cd main
 263git init
 264create main1
 265git commit -m "main1"
 266
 267cd ..
 268mkdir sub
 269cd sub
 270git init
 271create sub2
 272git commit -m "sub2"
 273
 274cd ../main
 275git fetch ../sub master
 276git branch sub2 FETCH_HEAD
 277git subtree add --prefix subdir sub2
 278
 279cd ../sub
 280create sub3
 281git commit -m "sub3"
 282
 283cd ../main
 284git fetch ../sub master
 285git branch sub3 FETCH_HEAD
 286git subtree merge --prefix subdir sub3
 287
 288create subdir/main-sub4
 289git commit -m "main-sub4"
 290git subtree split --prefix subdir --branch mainsub4
 291
 292# at this point, the new commit's parent should be sub3
 293# if it's not, something went wrong (the "newparent" of "master~" commit should have been sub3,
 294# but it wasn't, because it's cache was not set to itself)
 295check_equal "$(git log --pretty=format:%P -1 mainsub4)" "$(git rev-parse sub3)"
 296
 297mkdir subdir2
 298create subdir2/main-sub5
 299git commit -m "main-sub5"
 300git subtree split --prefix subdir2 --branch mainsub5
 301
 302# also test that we still can split out an entirely new subtree
 303# if the parent of the first commit in the tree isn't empty,
 304# then the new subtree has accidently been attached to something
 305check_equal "$(git log --pretty=format:%P -1 mainsub5)" ""
 306
 307
 308# make sure no patch changes more than one file.  The original set of commits
 309# changed only one file each.  A multi-file change would imply that we pruned
 310# commits too aggressively.
 311joincommits()
 312{
 313        commit=
 314        all=
 315        while read x y; do
 316                echo "{$x}" >&2
 317                if [ -z "$x" ]; then
 318                        continue
 319                elif [ "$x" = "commit:" ]; then
 320                        if [ -n "$commit" ]; then
 321                                echo "$commit $all"
 322                                all=
 323                        fi
 324                        commit="$y"
 325                else
 326                        all="$all $y"
 327                fi
 328        done
 329        echo "$commit $all"
 330}
 331x=
 332git log --pretty=format:'commit: %H' | joincommits |
 333(       while read commit a b; do
 334                echo "Verifying commit $commit"
 335                check_equal "$b" ""
 336                x=1
 337        done
 338        check_equal "$x" 1
 339) || exit 1
 340
 341echo
 342echo 'ok'