1#!/bin/sh 2# 3# Copyright (c) 2009 Johan Herland 4# 5 6test_description='Test "git submodule foreach" 7 8This test verifies that "git submodule foreach" correctly visits all submodules 9that are currently checked out. 10' 11 12GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 13export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 14 15. ./test-lib.sh 16 17 18test_expect_success 'setup a submodule tree' ' 19 echo file > file && 20 git add file && 21 test_tick && 22 git commit -m upstream && 23 git clone . super && 24 git clone super submodule && 25 ( 26 cd super && 27 git submodule add ../submodule sub1 && 28 git submodule add ../submodule sub2 && 29 git submodule add ../submodule sub3 && 30 git config -f .gitmodules --rename-section \ 31 submodule.sub1 submodule.foo1 && 32 git config -f .gitmodules --rename-section \ 33 submodule.sub2 submodule.foo2 && 34 git config -f .gitmodules --rename-section \ 35 submodule.sub3 submodule.foo3 && 36 git add .gitmodules && 37 test_tick && 38 git commit -m "submodules" && 39 git submodule init sub1 && 40 git submodule init sub2 && 41 git submodule init sub3 42 ) && 43 ( 44 cd submodule && 45 echo different > file && 46 git add file && 47 test_tick && 48 git commit -m "different" 49 ) && 50 ( 51 cd super && 52 ( 53 cd sub3 && 54 git pull 55 ) && 56 git add sub3 && 57 test_tick && 58 git commit -m "update sub3" 59 ) 60' 61 62sub1sha1=$(cd super/sub1 && git rev-parse HEAD) 63sub3sha1=$(cd super/sub3 && git rev-parse HEAD) 64 65pwd=$(pwd) 66 67cat > expect <<EOF 68Entering 'sub1' 69$pwd/clone-foo1-sub1-$sub1sha1 70Entering 'sub3' 71$pwd/clone-foo3-sub3-$sub3sha1 72EOF 73 74test_expect_success 'test basic "submodule foreach" usage' ' 75 git clone super clone && 76 ( 77 cd clone && 78 git submodule update --init -- sub1 sub3 && 79 git submodule foreach "echo \$toplevel-\$name-\$path-\$sha1" > ../actual && 80 git config foo.bar zar && 81 git submodule foreach "git config --file \"\$toplevel/.git/config\" foo.bar" 82 ) && 83 test_cmp expect actual 84' 85 86cat >expect <<EOF 87Entering '../sub1' 88$pwd/clone-foo1-sub1-../sub1-$sub1sha1 89Entering '../sub3' 90$pwd/clone-foo3-sub3-../sub3-$sub3sha1 91EOF 92 93test_expect_success 'test "submodule foreach" from subdirectory' ' 94 mkdir clone/sub && 95 ( 96 cd clone/sub && 97 git submodule foreach "echo \$toplevel-\$name-\$sm_path-\$displaypath-\$sha1" >../../actual 98 ) && 99 test_cmp expect actual 100' 101 102test_expect_success 'setup nested submodules' ' 103 git clone submodule nested1 && 104 git clone submodule nested2 && 105 git clone submodule nested3 && 106 ( 107 cd nested3 && 108 git submodule add ../submodule submodule && 109 test_tick && 110 git commit -m "submodule" && 111 git submodule init submodule 112 ) && 113 ( 114 cd nested2 && 115 git submodule add ../nested3 nested3 && 116 test_tick && 117 git commit -m "nested3" && 118 git submodule init nested3 119 ) && 120 ( 121 cd nested1 && 122 git submodule add ../nested2 nested2 && 123 test_tick && 124 git commit -m "nested2" && 125 git submodule init nested2 126 ) && 127 ( 128 cd super && 129 git submodule add ../nested1 nested1 && 130 test_tick && 131 git commit -m "nested1" && 132 git submodule init nested1 133 ) 134' 135 136test_expect_success 'use "submodule foreach" to checkout 2nd level submodule' ' 137 git clone super clone2 && 138 ( 139 cd clone2 && 140 test_must_fail git rev-parse --resolve-git-dir sub1/.git && 141 test_must_fail git rev-parse --resolve-git-dir sub2/.git && 142 test_must_fail git rev-parse --resolve-git-dir sub3/.git && 143 test_must_fail git rev-parse --resolve-git-dir nested1/.git && 144 git submodule update --init && 145 git rev-parse --resolve-git-dir sub1/.git && 146 git rev-parse --resolve-git-dir sub2/.git && 147 git rev-parse --resolve-git-dir sub3/.git && 148 git rev-parse --resolve-git-dir nested1/.git && 149 test_must_fail git rev-parse --resolve-git-dir nested1/nested2/.git && 150 git submodule foreach "git submodule update --init" && 151 git rev-parse --resolve-git-dir nested1/nested2/.git && 152 test_must_fail git rev-parse --resolve-git-dir nested1/nested2/nested3/.git 153 ) 154' 155 156test_expect_success 'use "foreach --recursive" to checkout all submodules' ' 157 ( 158 cd clone2 && 159 git submodule foreach --recursive "git submodule update --init" && 160 git rev-parse --resolve-git-dir nested1/nested2/nested3/.git && 161 git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git 162 ) 163' 164 165cat > expect <<EOF 166Entering 'nested1' 167Entering 'nested1/nested2' 168Entering 'nested1/nested2/nested3' 169Entering 'nested1/nested2/nested3/submodule' 170Entering 'sub1' 171Entering 'sub2' 172Entering 'sub3' 173EOF 174 175test_expect_success 'test messages from "foreach --recursive"' ' 176 ( 177 cd clone2 && 178 git submodule foreach --recursive "true" > ../actual 179 ) && 180 test_cmp expect actual 181' 182 183cat > expect <<EOF 184Entering '../nested1' 185Entering '../nested1/nested2' 186Entering '../nested1/nested2/nested3' 187Entering '../nested1/nested2/nested3/submodule' 188Entering '../sub1' 189Entering '../sub2' 190Entering '../sub3' 191EOF 192 193test_expect_success 'test messages from "foreach --recursive" from subdirectory' ' 194 ( 195 cd clone2 && 196 mkdir untracked && 197 cd untracked && 198 git submodule foreach --recursive >../../actual 199 ) && 200 test_cmp expect actual 201' 202sub1sha1=$(cd clone2/sub1 && git rev-parse HEAD) 203sub2sha1=$(cd clone2/sub2 && git rev-parse HEAD) 204sub3sha1=$(cd clone2/sub3 && git rev-parse HEAD) 205nested1sha1=$(cd clone2/nested1 && git rev-parse HEAD) 206nested2sha1=$(cd clone2/nested1/nested2 && git rev-parse HEAD) 207nested3sha1=$(cd clone2/nested1/nested2/nested3 && git rev-parse HEAD) 208submodulesha1=$(cd clone2/nested1/nested2/nested3/submodule && git rev-parse HEAD) 209 210cat >expect <<EOF 211Entering '../nested1' 212toplevel: $pwd/clone2 name: nested1 path: nested1 displaypath: ../nested1 hash: $nested1sha1 213Entering '../nested1/nested2' 214toplevel: $pwd/clone2/nested1 name: nested2 path: nested2 displaypath: ../nested1/nested2 hash: $nested2sha1 215Entering '../nested1/nested2/nested3' 216toplevel: $pwd/clone2/nested1/nested2 name: nested3 path: nested3 displaypath: ../nested1/nested2/nested3 hash: $nested3sha1 217Entering '../nested1/nested2/nested3/submodule' 218toplevel: $pwd/clone2/nested1/nested2/nested3 name: submodule path: submodule displaypath: ../nested1/nested2/nested3/submodule hash: $submodulesha1 219Entering '../sub1' 220toplevel: $pwd/clone2 name: foo1 path: sub1 displaypath: ../sub1 hash: $sub1sha1 221Entering '../sub2' 222toplevel: $pwd/clone2 name: foo2 path: sub2 displaypath: ../sub2 hash: $sub2sha1 223Entering '../sub3' 224toplevel: $pwd/clone2 name: foo3 path: sub3 displaypath: ../sub3 hash: $sub3sha1 225EOF 226 227test_expect_success 'test "submodule foreach --recursive" from subdirectory' ' 228 ( 229 cd clone2/untracked && 230 git submodule foreach --recursive "echo toplevel: \$toplevel name: \$name path: \$sm_path displaypath: \$displaypath hash: \$sha1" >../../actual 231 ) && 232 test_cmp expect actual 233' 234 235cat > expect <<EOF 236nested1-nested1 237nested2-nested2 238nested3-nested3 239submodule-submodule 240foo1-sub1 241foo2-sub2 242foo3-sub3 243EOF 244 245test_expect_success 'test "foreach --quiet --recursive"' ' 246 ( 247 cd clone2 && 248 git submodule foreach -q --recursive "echo \$name-\$path" > ../actual 249 ) && 250 test_cmp expect actual 251' 252 253test_expect_success 'use "update --recursive" to checkout all submodules' ' 254 git clone super clone3 && 255 ( 256 cd clone3 && 257 test_must_fail git rev-parse --resolve-git-dir sub1/.git && 258 test_must_fail git rev-parse --resolve-git-dir sub2/.git && 259 test_must_fail git rev-parse --resolve-git-dir sub3/.git && 260 test_must_fail git rev-parse --resolve-git-dir nested1/.git && 261 git submodule update --init --recursive && 262 git rev-parse --resolve-git-dir sub1/.git && 263 git rev-parse --resolve-git-dir sub2/.git && 264 git rev-parse --resolve-git-dir sub3/.git && 265 git rev-parse --resolve-git-dir nested1/.git && 266 git rev-parse --resolve-git-dir nested1/nested2/.git && 267 git rev-parse --resolve-git-dir nested1/nested2/nested3/.git && 268 git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git 269 ) 270' 271 272nested1sha1=$(cd clone3/nested1 && git rev-parse HEAD) 273nested2sha1=$(cd clone3/nested1/nested2 && git rev-parse HEAD) 274nested3sha1=$(cd clone3/nested1/nested2/nested3 && git rev-parse HEAD) 275submodulesha1=$(cd clone3/nested1/nested2/nested3/submodule && git rev-parse HEAD) 276sub1sha1=$(cd clone3/sub1 && git rev-parse HEAD) 277sub2sha1=$(cd clone3/sub2 && git rev-parse HEAD) 278sub3sha1=$(cd clone3/sub3 && git rev-parse HEAD) 279sub1sha1_short=$(cd clone3/sub1 && git rev-parse --short HEAD) 280sub2sha1_short=$(cd clone3/sub2 && git rev-parse --short HEAD) 281 282cat > expect <<EOF 283 $nested1sha1 nested1 (heads/main) 284 $nested2sha1 nested1/nested2 (heads/main) 285 $nested3sha1 nested1/nested2/nested3 (heads/main) 286 $submodulesha1 nested1/nested2/nested3/submodule (heads/main) 287 $sub1sha1 sub1 ($sub1sha1_short) 288 $sub2sha1 sub2 ($sub2sha1_short) 289 $sub3sha1 sub3 (heads/main) 290EOF 291 292test_expect_success 'test "status --recursive"' ' 293 ( 294 cd clone3 && 295 git submodule status --recursive > ../actual 296 ) && 297 test_cmp expect actual 298' 299 300cat > expect <<EOF 301 $nested1sha1 nested1 (heads/main) 302+$nested2sha1 nested1/nested2 (file2~1) 303 $nested3sha1 nested1/nested2/nested3 (heads/main) 304 $submodulesha1 nested1/nested2/nested3/submodule (heads/main) 305EOF 306 307test_expect_success 'ensure "status --cached --recursive" preserves the --cached flag' ' 308 ( 309 cd clone3 && 310 ( 311 cd nested1/nested2 && 312 test_commit file2 313 ) && 314 git submodule status --cached --recursive -- nested1 > ../actual 315 ) && 316 test_cmp expect actual 317' 318 319nested2sha1=$(git -C clone3/nested1/nested2 rev-parse HEAD) 320 321cat > expect <<EOF 322 $nested1sha1 ../nested1 (heads/main) 323+$nested2sha1 ../nested1/nested2 (file2) 324 $nested3sha1 ../nested1/nested2/nested3 (heads/main) 325 $submodulesha1 ../nested1/nested2/nested3/submodule (heads/main) 326 $sub1sha1 ../sub1 ($sub1sha1_short) 327 $sub2sha1 ../sub2 ($sub2sha1_short) 328 $sub3sha1 ../sub3 (heads/main) 329EOF 330 331test_expect_success 'test "status --recursive" from sub directory' ' 332 ( 333 cd clone3 && 334 mkdir tmp && cd tmp && 335 git submodule status --recursive > ../../actual 336 ) && 337 test_cmp expect actual 338' 339 340test_expect_success 'use "git clone --recursive" to checkout all submodules' ' 341 git clone --recursive super clone4 && 342 ( 343 cd clone4 && 344 git rev-parse --resolve-git-dir .git && 345 git rev-parse --resolve-git-dir sub1/.git && 346 git rev-parse --resolve-git-dir sub2/.git && 347 git rev-parse --resolve-git-dir sub3/.git && 348 git rev-parse --resolve-git-dir nested1/.git && 349 git rev-parse --resolve-git-dir nested1/nested2/.git && 350 git rev-parse --resolve-git-dir nested1/nested2/nested3/.git && 351 git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git 352 ) 353' 354 355test_expect_success 'test "update --recursive" with a flag with spaces' ' 356 git clone super "common objects" && 357 git clone super clone5 && 358 ( 359 cd clone5 && 360 test_must_fail git rev-parse --resolve-git-dir d nested1/.git && 361 git submodule update --init --recursive --reference="$(dirname "$PWD")/common objects" && 362 git rev-parse --resolve-git-dir nested1/.git && 363 git rev-parse --resolve-git-dir nested1/nested2/.git && 364 git rev-parse --resolve-git-dir nested1/nested2/nested3/.git && 365 test -f .git/modules/nested1/objects/info/alternates && 366 test -f .git/modules/nested1/modules/nested2/objects/info/alternates && 367 test -f .git/modules/nested1/modules/nested2/modules/nested3/objects/info/alternates 368 ) 369' 370 371test_expect_success 'use "update --recursive nested1" to checkout all submodules rooted in nested1' ' 372 git clone super clone6 && 373 ( 374 cd clone6 && 375 test_must_fail git rev-parse --resolve-git-dir sub1/.git && 376 test_must_fail git rev-parse --resolve-git-dir sub2/.git && 377 test_must_fail git rev-parse --resolve-git-dir sub3/.git && 378 test_must_fail git rev-parse --resolve-git-dir nested1/.git && 379 git submodule update --init --recursive -- nested1 && 380 test_must_fail git rev-parse --resolve-git-dir sub1/.git && 381 test_must_fail git rev-parse --resolve-git-dir sub2/.git && 382 test_must_fail git rev-parse --resolve-git-dir sub3/.git && 383 git rev-parse --resolve-git-dir nested1/.git && 384 git rev-parse --resolve-git-dir nested1/nested2/.git && 385 git rev-parse --resolve-git-dir nested1/nested2/nested3/.git && 386 git rev-parse --resolve-git-dir nested1/nested2/nested3/submodule/.git 387 ) 388' 389 390test_expect_success 'command passed to foreach retains notion of stdin' ' 391 ( 392 cd super && 393 git submodule foreach echo success >../expected && 394 yes | git submodule foreach "read y && test \"x\$y\" = xy && echo success" >../actual 395 ) && 396 test_cmp expected actual 397' 398 399test_expect_success 'command passed to foreach --recursive retains notion of stdin' ' 400 ( 401 cd clone2 && 402 git submodule foreach --recursive echo success >../expected && 403 yes | git submodule foreach --recursive "read y && test \"x\$y\" = xy && echo success" >../actual 404 ) && 405 test_cmp expected actual 406' 407 408test_expect_success 'multi-argument command passed to foreach is not shell-evaluated twice' ' 409 ( 410 cd super && 411 git submodule foreach "echo \\\"quoted\\\"" > ../expected && 412 git submodule foreach echo \"quoted\" > ../actual 413 ) && 414 test_cmp expected actual 415' 416 417test_expect_success 'option-like arguments passed to foreach commands are not lost' ' 418 ( 419 cd super && 420 git submodule foreach "echo be --quiet" > ../expected && 421 git submodule foreach echo be --quiet > ../actual 422 ) && 423 grep -sq -e "--quiet" expected && 424 test_cmp expected actual 425' 426 427test_expect_success 'option-like arguments passed to foreach recurse correctly' ' 428 git -C clone2 submodule foreach --recursive "echo be --an-option" >expect && 429 git -C clone2 submodule foreach --recursive echo be --an-option >actual && 430 grep -e "--an-option" expect && 431 test_cmp expect actual 432' 433 434test_done 435