1446cfeed89071c9935d5fb9a8ea24ec0988d436
   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 --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." "$result"
 165
 166# check if --message works for split+rejoin
 167spl1=$(git subtree split --annotate='*' --prefix subdir --onto FETCH_HEAD --message "Split & rejoin" --rejoin)
 168echo "spl1={$spl1}"
 169git branch spl1 "$spl1"
 170check_equal "$(last_commit_message)" "Split & rejoin"
 171undo
 172
 173# check split with --branch
 174git subtree split --annotate='*' --prefix subdir --onto FETCH_HEAD --branch splitbr1
 175check_equal "$(git rev-parse splitbr1)" "$spl1"
 176
 177# check split with --branch for an existing branch
 178git branch splitbr2 sub1
 179git subtree split --annotate='*' --prefix subdir --onto FETCH_HEAD --branch splitbr2
 180check_equal "$(git rev-parse splitbr2)" "$spl1"
 181
 182# check split with --branch for an incompatible branch
 183result=$(git subtree split --prefix subdir --onto FETCH_HEAD --branch subdir || echo "caught error")
 184check_equal "$result" "caught error"
 185
 186
 187git subtree split --annotate='*' --prefix subdir --onto FETCH_HEAD --rejoin
 188check_equal "$(last_commit_message)" "Split 'subdir/' into commit '$spl1'"
 189
 190create subdir/main-sub8
 191git commit -m 'main-sub8'
 192
 193cd ../subproj
 194git fetch ../mainline spl1
 195git branch spl1 FETCH_HEAD
 196git merge FETCH_HEAD
 197
 198create sub9
 199git commit -m 'sub9'
 200
 201cd ../mainline
 202split2=$(git subtree split --annotate='*' --prefix subdir/ --rejoin)
 203git branch split2 "$split2"
 204
 205create subdir/main-sub10
 206git commit -m 'main-sub10'
 207
 208spl3=$(git subtree split --annotate='*' --prefix subdir --rejoin)
 209git branch spl3 "$spl3"
 210
 211cd ../subproj
 212git fetch ../mainline spl3
 213git branch spl3 FETCH_HEAD
 214git merge FETCH_HEAD
 215git branch subproj-merge-spl3
 216
 217chkm="main4 main6"
 218chkms="main-sub10 main-sub5 main-sub7 main-sub8"
 219chkms_sub=$(echo $chkms | multiline | sed 's,^,subdir/,' | fixnl)
 220chks="sub1 sub2 sub3 sub9"
 221chks_sub=$(echo $chks | multiline | sed 's,^,subdir/,' | fixnl)
 222
 223# make sure exactly the right set of files ends up in the subproj
 224subfiles=$(git ls-files | fixnl)
 225check_equal "$subfiles" "$chkms $chks"
 226
 227# make sure the subproj history *only* contains commits that affect the subdir.
 228allchanges=$(git log --name-only --pretty=format:'' | sort | fixnl)
 229check_equal "$allchanges" "$chkms $chks"
 230
 231cd ../mainline
 232git fetch ../subproj subproj-merge-spl3
 233git branch subproj-merge-spl3 FETCH_HEAD
 234git subtree pull --prefix=subdir ../subproj subproj-merge-spl3
 235
 236# make sure exactly the right set of files ends up in the mainline
 237mainfiles=$(git ls-files | fixnl)
 238check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub"
 239
 240# make sure each filename changed exactly once in the entire history.
 241# 'main-sub??' and '/subdir/main-sub??' both change, because those are the
 242# changes that were split into their own history.  And 'subdir/sub??' never
 243# change, since they were *only* changed in the subtree branch.
 244allchanges=$(git log --name-only --pretty=format:'' | sort | fixnl)
 245check_equal "$allchanges" "$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"
 246
 247# make sure the --rejoin commits never make it into subproj
 248check_equal "$(git log --pretty=format:'%s' HEAD^2 | grep -i split)" ""
 249
 250# make sure no 'git subtree' tagged commits make it into subproj. (They're
 251# meaningless to subproj since one side of the merge refers to the mainline)
 252check_equal "$(git log --pretty=format:'%s%n%b' HEAD^2 | grep 'git-subtree.*:')" ""
 253
 254
 255# check if split can find proper base without --onto
 256# prepare second pair of repositories
 257mkdir test2
 258cd test2
 259
 260mkdir main
 261cd main
 262git init
 263create main1
 264git commit -m "main1"
 265
 266cd ..
 267mkdir sub
 268cd sub
 269git init
 270create sub2
 271git commit -m "sub2"
 272
 273cd ../main
 274git fetch ../sub master
 275git branch sub2 FETCH_HEAD
 276git subtree add --prefix subdir sub2
 277
 278cd ../sub
 279create sub3
 280git commit -m "sub3"
 281
 282cd ../main
 283git fetch ../sub master
 284git branch sub3 FETCH_HEAD
 285git subtree merge --prefix subdir sub3
 286
 287create subdir/main-sub4
 288git commit -m "main-sub4"
 289git subtree split --prefix subdir --branch mainsub4
 290
 291# at this point, the new commit's parent should be sub3
 292# if it's not, something went wrong (the "newparent" of "master~" commit should have been sub3,
 293# but it wasn't, because it's cache was not set to itself)
 294check_equal "$(git log --format=%P -1 mainsub4)" "$(git rev-parse sub3)"
 295
 296
 297
 298# make sure no patch changes more than one file.  The original set of commits
 299# changed only one file each.  A multi-file change would imply that we pruned
 300# commits too aggressively.
 301joincommits()
 302{
 303        commit=
 304        all=
 305        while read x y; do
 306                echo "{$x}" >&2
 307                if [ -z "$x" ]; then
 308                        continue
 309                elif [ "$x" = "commit:" ]; then
 310                        if [ -n "$commit" ]; then
 311                                echo "$commit $all"
 312                                all=
 313                        fi
 314                        commit="$y"
 315                else
 316                        all="$all $y"
 317                fi
 318        done
 319        echo "$commit $all"
 320}
 321x=
 322git log --pretty=format:'commit: %H' | joincommits |
 323(       while read commit a b; do
 324                echo "Verifying commit $commit"
 325                check_equal "$b" ""
 326                x=1
 327        done
 328        check_equal "$x" 1
 329) || exit 1
 330
 331echo
 332echo 'ok'