| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description='merge simplification' |
| 4 | |
| 5 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main |
| 6 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME |
| 7 | |
| 8 | . ./test-lib.sh |
| 9 | |
| 10 | note () { |
| 11 | git tag "$1" |
| 12 | } |
| 13 | |
| 14 | unnote () { |
| 15 | test_when_finished "rm -f tmp" && |
| 16 | git name-rev --tags --annotate-stdin >tmp && |
| 17 | sed -e "s|$OID_REGEX (tags/\([^)]*\)) |\1 |g" <tmp |
| 18 | } |
| 19 | |
| 20 | # |
| 21 | # Create a test repo with an interesting commit graph: |
| 22 | # |
| 23 | # A-----B-----G--H--I--K--L |
| 24 | # \ \ / / |
| 25 | # \ \ / / |
| 26 | # C--D--E--F J |
| 27 | # |
| 28 | # The commits are laid out from left-to-right starting with |
| 29 | # the root commit A and terminating at the tip commit L. |
| 30 | # |
| 31 | # There are a few places where we adjust the commit date or |
| 32 | # author date to make the --topo-order, --date-order, and |
| 33 | # --author-date-order flags produce different output. |
| 34 | |
| 35 | test_expect_success setup ' |
| 36 | echo "Hi there" >file && |
| 37 | echo "initial" >lost && |
| 38 | git add file lost && |
| 39 | test_tick && git commit -m "Initial file and lost" && |
| 40 | note A && |
| 41 | |
| 42 | git branch other-branch && |
| 43 | |
| 44 | git symbolic-ref HEAD refs/heads/unrelated && |
| 45 | git rm -f "*" && |
| 46 | echo "Unrelated branch" >side && |
| 47 | git add side && |
| 48 | test_tick && git commit -m "Side root" && |
| 49 | note J && |
| 50 | git checkout main && |
| 51 | |
| 52 | echo "Hello" >file && |
| 53 | echo "second" >lost && |
| 54 | git add file lost && |
| 55 | test_tick && GIT_AUTHOR_DATE=$(($test_tick + 120)) git commit -m "Modified file and lost" && |
| 56 | note B && |
| 57 | |
| 58 | git checkout other-branch && |
| 59 | |
| 60 | echo "Hello" >file && |
| 61 | >lost && |
| 62 | git add file lost && |
| 63 | test_tick && git commit -m "Modified the file identically" && |
| 64 | note C && |
| 65 | |
| 66 | echo "This is a stupid example" >another-file && |
| 67 | git add another-file && |
| 68 | test_tick && git commit -m "Add another file" && |
| 69 | note D && |
| 70 | |
| 71 | test_tick && |
| 72 | test_must_fail git merge -m "merge" main && |
| 73 | >lost && git commit -a -m "merge" && |
| 74 | note E && |
| 75 | |
| 76 | echo "Yet another" >elif && |
| 77 | git add elif && |
| 78 | test_tick && git commit -m "Irrelevant change" && |
| 79 | note F && |
| 80 | |
| 81 | git checkout main && |
| 82 | echo "Yet another" >elif && |
| 83 | git add elif && |
| 84 | test_tick && git commit -m "Another irrelevant change" && |
| 85 | note G && |
| 86 | |
| 87 | test_tick && git merge -m "merge" other-branch && |
| 88 | note H && |
| 89 | |
| 90 | echo "Final change" >file && |
| 91 | test_tick && git commit -a -m "Final change" && |
| 92 | note I && |
| 93 | |
| 94 | git checkout main && |
| 95 | test_tick && git merge --allow-unrelated-histories -m "Coolest" unrelated && |
| 96 | note K && |
| 97 | |
| 98 | echo "Immaterial" >elif && |
| 99 | git add elif && |
| 100 | test_tick && git commit -m "Last" && |
| 101 | note L |
| 102 | ' |
| 103 | |
| 104 | FMT='tformat:%P %H | %s' |
| 105 | |
| 106 | check_outcome () { |
| 107 | outcome=$1 |
| 108 | shift |
| 109 | for c in $1 |
| 110 | do |
| 111 | echo "$c" |
| 112 | done >expect && |
| 113 | shift && |
| 114 | param="$*" && |
| 115 | test_expect_$outcome "log $param" ' |
| 116 | git log --pretty="$FMT" --parents $param >out && |
| 117 | unnote >actual <out && |
| 118 | sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual && |
| 119 | test_cmp expect check |
| 120 | ' |
| 121 | } |
| 122 | |
| 123 | check_result () { |
| 124 | check_outcome success "$@" |
| 125 | } |
| 126 | |
| 127 | check_result 'L K J I H F E D C G B A' --full-history --topo-order |
| 128 | check_result 'L K I H G F E D C B J A' --full-history |
| 129 | check_result 'L K I H G F E D C B J A' --full-history --date-order |
| 130 | check_result 'L K I H G F E D B C J A' --full-history --author-date-order |
| 131 | check_result 'K I H E C B A' --full-history -- file |
| 132 | check_result 'K I H E C B A' --full-history --topo-order -- file |
| 133 | check_result 'K I H E C B A' --full-history --date-order -- file |
| 134 | check_result 'K I H E B C A' --full-history --author-date-order -- file |
| 135 | check_result 'I E C B A' --simplify-merges -- file |
| 136 | check_result 'I E C B A' --simplify-merges --topo-order -- file |
| 137 | check_result 'I E C B A' --simplify-merges --date-order -- file |
| 138 | check_result 'I E B C A' --simplify-merges --author-date-order -- file |
| 139 | check_result 'I B A' -- file |
| 140 | check_result 'I B A' --topo-order -- file |
| 141 | check_result 'I B A' --date-order -- file |
| 142 | check_result 'I B A' --author-date-order -- file |
| 143 | check_result 'H' --first-parent -- another-file |
| 144 | check_result 'H' --first-parent --topo-order -- another-file |
| 145 | |
| 146 | check_result 'L K I H G B A' --first-parent L |
| 147 | check_result 'F E D C' --exclude-first-parent-only F ^L |
| 148 | check_result '' F ^L |
| 149 | check_result 'L K I H G J' L ^F |
| 150 | check_result 'L K I H G B J' --exclude-first-parent-only L ^F |
| 151 | check_result 'L K I H G B' --exclude-first-parent-only --first-parent L ^F |
| 152 | |
| 153 | check_result 'E C B A' --full-history E -- lost |
| 154 | test_expect_success 'full history simplification without parent' ' |
| 155 | printf "%s\n" E C B A >expect && |
| 156 | git log --pretty="$FMT" --full-history E -- lost >out && |
| 157 | unnote >actual <out && |
| 158 | sed -e "s/^.* \([^ ]*\) .*/\1/" >check <actual && |
| 159 | test_cmp expect check |
| 160 | ' |
| 161 | |
| 162 | test_expect_success '--full-diff is not affected by --parents' ' |
| 163 | git log -p --pretty="%H" --full-diff -- file >expected && |
| 164 | git log -p --pretty="%H" --full-diff --parents -- file >actual && |
| 165 | test_cmp expected actual |
| 166 | ' |
| 167 | |
| 168 | # |
| 169 | # Create a new history to demonstrate the value of --show-pulls |
| 170 | # with respect to the subtleties of simplified history, --full-history, |
| 171 | # and --simplify-merges. |
| 172 | # |
| 173 | # .-A---M-----C--N---O---P |
| 174 | # / / \ \ \/ / / |
| 175 | # I B \ R-'`-Z' / |
| 176 | # \ / \/ / |
| 177 | # \ / /\ / |
| 178 | # `---X--' `---Y--' |
| 179 | # |
| 180 | # This example is explained in Documentation/rev-list-options.adoc |
| 181 | |
| 182 | test_expect_success 'setup rebuild repo' ' |
| 183 | rm -rf .git * && |
| 184 | git init && |
| 185 | git switch -c topic && |
| 186 | |
| 187 | echo base >file && |
| 188 | git add file && |
| 189 | test_commit I && |
| 190 | |
| 191 | echo A >file && |
| 192 | git add file && |
| 193 | test_commit A && |
| 194 | |
| 195 | git switch -c branchB I && |
| 196 | echo B >file && |
| 197 | git add file && |
| 198 | test_commit B && |
| 199 | |
| 200 | git switch topic && |
| 201 | test_must_fail git merge -m "M" B && |
| 202 | echo A >file && |
| 203 | echo B >>file && |
| 204 | git add file && |
| 205 | git merge --continue && |
| 206 | note M && |
| 207 | |
| 208 | echo C >other && |
| 209 | git add other && |
| 210 | test_commit C && |
| 211 | |
| 212 | git switch -c branchX I && |
| 213 | echo X >file && |
| 214 | git add file && |
| 215 | test_commit X && |
| 216 | |
| 217 | git switch -c branchR M && |
| 218 | git merge -m R -Xtheirs X && |
| 219 | note R && |
| 220 | |
| 221 | git switch topic && |
| 222 | git merge -m N R && |
| 223 | note N && |
| 224 | |
| 225 | git switch -c branchY M && |
| 226 | echo Y >y && |
| 227 | git add y && |
| 228 | test_commit Y && |
| 229 | |
| 230 | git switch -c branchZ C && |
| 231 | echo Z >z && |
| 232 | git add z && |
| 233 | test_commit Z && |
| 234 | |
| 235 | git switch topic && |
| 236 | git merge -m O Z && |
| 237 | note O && |
| 238 | |
| 239 | git merge -m P Y && |
| 240 | note P |
| 241 | ' |
| 242 | |
| 243 | check_result 'X I' -- file |
| 244 | check_result 'N R X I' --show-pulls -- file |
| 245 | |
| 246 | check_result 'P O N R X M B A I' --full-history --topo-order -- file |
| 247 | check_result 'N R X M B A I' --simplify-merges --topo-order --show-pulls -- file |
| 248 | check_result 'R X M B A I' --simplify-merges --topo-order -- file |
| 249 | check_result 'N M A I' --first-parent -- file |
| 250 | check_result 'N M A I' --first-parent --show-pulls -- file |
| 251 | |
| 252 | # --ancestry-path implies --full-history |
| 253 | check_result 'P O N R M' --topo-order \ |
| 254 | --ancestry-path A..HEAD -- file |
| 255 | check_result 'P O N R M' --topo-order \ |
| 256 | --show-pulls \ |
| 257 | --ancestry-path A..HEAD -- file |
| 258 | check_result 'P O N R M' --topo-order \ |
| 259 | --full-history \ |
| 260 | --ancestry-path A..HEAD -- file |
| 261 | check_result 'R M' --topo-order \ |
| 262 | --simplify-merges \ |
| 263 | --ancestry-path A..HEAD -- file |
| 264 | check_result 'N R M' --topo-order \ |
| 265 | --simplify-merges --show-pulls \ |
| 266 | --ancestry-path A..HEAD -- file |
| 267 | |
| 268 | test_expect_success 'log --graph --simplify-merges --show-pulls' ' |
| 269 | cat >expect <<-\EOF && |
| 270 | * N |
| 271 | * R |
| 272 | |\ |
| 273 | | * X |
| 274 | * | M |
| 275 | |\ \ |
| 276 | | * | B |
| 277 | | |/ |
| 278 | * / A |
| 279 | |/ |
| 280 | * I |
| 281 | EOF |
| 282 | git log --graph --pretty="%s" \ |
| 283 | --simplify-merges --show-pulls \ |
| 284 | -- file >actual && |
| 285 | test_cmp expect actual |
| 286 | ' |
| 287 | |
| 288 | test_expect_success 'exclude-first-parent-only with parent already seen' ' |
| 289 | git checkout --orphan test-seen && |
| 290 | git rm -rf . && |
| 291 | test_commit r1 && |
| 292 | git checkout -b branch-f && |
| 293 | test_commit f && |
| 294 | git checkout test-seen && |
| 295 | git merge --no-ff --no-edit -m r2 branch-f && |
| 296 | git tag r2 && |
| 297 | |
| 298 | git rev-list --exclude-first-parent-only f ^r2 >actual && |
| 299 | git rev-parse f >expect && |
| 300 | test_cmp expect actual && |
| 301 | |
| 302 | git rev-list --exclude-first-parent-only f r1 ^r2 >actual2 && |
| 303 | test_cmp expect actual2 |
| 304 | ' |
| 305 | |
| 306 | test_done |