test.shon commit Oops, forgot a COPYING file. It's GPLv2. (d8b2c0d)
   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_equal()
  25{
  26        echo
  27        echo "check a:" "{$1}"
  28        echo "      b:" "{$2}"
  29        if [ "$1" = "$2" ]; then
  30                return 0
  31        else
  32                echo FAILED
  33                exit 1
  34        fi
  35}
  36
  37fixnl()
  38{       
  39        t=""
  40        while read x; do
  41                t="$t$x "
  42        done
  43        echo $t
  44}
  45
  46multiline()
  47{
  48        while read x; do
  49                set -- $x
  50                for d in "$@"; do
  51                        echo "$d"
  52                done
  53        done
  54}
  55
  56rm -rf mainline subproj
  57mkdir mainline subproj
  58
  59cd subproj
  60git init
  61
  62create sub1
  63git commit -m 'sub1'
  64git branch sub1
  65git branch -m master subproj
  66check true
  67
  68create sub2
  69git commit -m 'sub2'
  70git branch sub2
  71
  72create sub3
  73git commit -m 'sub3'
  74git branch sub3
  75
  76cd ../mainline
  77git init
  78create main4
  79git commit -m 'main4'
  80git branch -m master mainline
  81git branch subdir
  82
  83git fetch ../subproj sub1
  84git branch sub1 FETCH_HEAD
  85git subtree add --prefix=subdir/ FETCH_HEAD
  86
  87# this shouldn't actually do anything, since FETCH_HEAD is already a parent
  88git merge -m 'merge -s -ours' -s ours FETCH_HEAD
  89
  90create subdir/main-sub5
  91git commit -m 'main-sub5'
  92
  93create main6
  94git commit -m 'main6 boring'
  95
  96create subdir/main-sub7
  97git commit -m 'main-sub7'
  98
  99git fetch ../subproj sub2
 100git branch sub2 FETCH_HEAD
 101git subtree merge --prefix=subdir FETCH_HEAD
 102git branch pre-split
 103
 104spl1=$(git subtree split --annotate='*' \
 105                --prefix subdir --onto FETCH_HEAD --rejoin)
 106echo "spl1={$spl1}"
 107git branch spl1 "$spl1"
 108
 109create subdir/main-sub8
 110git commit -m 'main-sub8'
 111
 112cd ../subproj
 113git fetch ../mainline spl1
 114git branch spl1 FETCH_HEAD
 115git merge FETCH_HEAD
 116
 117create sub9
 118git commit -m 'sub9'
 119
 120cd ../mainline
 121split2=$(git subtree split --annotate='*' --prefix subdir/ --rejoin)
 122git branch split2 "$split2"
 123
 124create subdir/main-sub10
 125git commit -m 'main-sub10'
 126
 127spl3=$(git subtree split --annotate='*' --prefix subdir --rejoin)
 128git branch spl3 "$spl3"
 129
 130cd ../subproj
 131git fetch ../mainline spl3
 132git branch spl3 FETCH_HEAD
 133git merge FETCH_HEAD
 134git branch subproj-merge-spl3
 135
 136chkm="main4 main6"
 137chkms="main-sub10 main-sub5 main-sub7 main-sub8"
 138chkms_sub=$(echo $chkms | multiline | sed 's,^,subdir/,' | fixnl)
 139chks="sub1 sub2 sub3 sub9"
 140chks_sub=$(echo $chks | multiline | sed 's,^,subdir/,' | fixnl)
 141
 142# make sure exactly the right set of files ends up in the subproj
 143subfiles=$(git ls-files | fixnl)
 144check_equal "$subfiles" "$chkms $chks"
 145
 146# make sure the subproj history *only* contains commits that affect the subdir.
 147allchanges=$(git log --name-only --pretty=format:'' | sort | fixnl)
 148check_equal "$allchanges" "$chkms $chks"
 149
 150cd ../mainline
 151git fetch ../subproj subproj-merge-spl3
 152git branch subproj-merge-spl3 FETCH_HEAD
 153git subtree pull --prefix=subdir ../subproj subproj-merge-spl3
 154
 155# make sure exactly the right set of files ends up in the mainline
 156mainfiles=$(git ls-files | fixnl)
 157check_equal "$mainfiles" "$chkm $chkms_sub $chks_sub"
 158
 159# make sure each filename changed exactly once in the entire history.
 160# 'main-sub??' and '/subdir/main-sub??' both change, because those are the
 161# changes that were split into their own history.  And 'subdir/sub??' never
 162# change, since they were *only* changed in the subtree branch.
 163allchanges=$(git log --name-only --pretty=format:'' | sort | fixnl)
 164check_equal "$allchanges" "$(echo $chkms $chkm $chks $chkms_sub | multiline | sort | fixnl)"
 165
 166# make sure the --rejoin commits never make it into subproj
 167check_equal "$(git log --pretty=format:'%s' HEAD^2 | grep -i split)" ""
 168
 169# make sure no 'git subtree' tagged commits make it into subproj. (They're
 170# meaningless to subproj since one side of the merge refers to the mainline)
 171check_equal "$(git log --pretty=format:'%s%n%b' HEAD^2 | grep 'git-subtree.*:')" ""
 172
 173# make sure no patch changes more than one file.  The original set of commits
 174# changed only one file each.  A multi-file change would imply that we pruned
 175# commits too aggressively.
 176joincommits()
 177{
 178        commit=
 179        all=
 180        while read x y; do
 181                echo "{$x}" >&2
 182                if [ -z "$x" ]; then
 183                        continue
 184                elif [ "$x" = "commit:" ]; then
 185                        if [ -n "$commit" ]; then
 186                                echo "$commit $all"
 187                                all=
 188                        fi
 189                        commit="$y"
 190                else
 191                        all="$all $y"
 192                fi
 193        done
 194        echo "$commit $all"
 195}
 196x=
 197git log --pretty=format:'commit: %H' | joincommits |
 198(       while read commit a b; do
 199                echo "Verifying commit $commit"
 200                check_equal "$b" ""
 201                x=1
 202        done
 203        check_equal "$x" 1
 204) || exit 1
 205
 206echo
 207echo 'ok'