1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
|
#!/bin/sh
test_description='check various push.default settings'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
test_expect_success 'setup bare remotes' '
git init --bare repo1 &&
git remote add parent1 repo1 &&
git init --bare repo2 &&
git remote add parent2 repo2 &&
test_commit one &&
git push parent1 HEAD &&
git push parent2 HEAD
'
# $1 = local revision
# $2 = remote revision (tested to be equal to the local one)
# $3 = [optional] repo to check for actual output (repo1 by default)
check_pushed_commit () {
git log -1 --format='%h %s' "$1" >expect &&
git --git-dir="${3:-repo1}" log -1 --format='%h %s' "$2" >actual &&
test_cmp expect actual
}
# $1 = push.default value
# $2 = expected target branch for the push
# $3 = [optional] repo to check for actual output (repo1 by default)
test_push_success () {
git ${1:+-c} ${1:+push.default="$1"} push &&
check_pushed_commit HEAD "$2" "$3"
}
# $1 = push.default value
# check that push fails and does not modify any remote branch
test_push_failure () {
git --git-dir=repo1 log --no-walk --format='%h %s' --all >expect &&
test_must_fail git ${1:+-c} ${1:+push.default="$1"} push &&
git --git-dir=repo1 log --no-walk --format='%h %s' --all >actual &&
test_cmp expect actual
}
# $1 = success or failure
# $2 = push.default value
# $3 = branch to check for actual output (main or foo)
# $4 = [optional] switch to triangular workflow
test_pushdefault_workflow () {
workflow=central
pushdefault=parent1
if test -n "${4-}"; then
workflow=triangular
pushdefault=parent2
fi
test_expect_success "push.default = $2 $1 in $workflow workflows" "
test_config branch.main.remote parent1 &&
test_config branch.main.merge refs/heads/foo &&
test_config remote.pushdefault $pushdefault &&
test_commit commit-for-$2${4+-triangular} &&
test_push_$1 $2 $3 ${4+repo2}
"
}
test_expect_success '"upstream" pushes to configured upstream' '
git checkout main &&
test_config branch.main.remote parent1 &&
test_config branch.main.merge refs/heads/foo &&
test_commit two &&
test_push_success upstream foo
'
test_expect_success '"upstream" does not push on unconfigured remote' '
git checkout main &&
test_unconfig branch.main.remote &&
test_commit three &&
test_push_failure upstream
'
test_expect_success '"upstream" does not push on unconfigured branch' '
git checkout main &&
test_config branch.main.remote parent1 &&
test_unconfig branch.main.merge &&
test_commit four &&
test_push_failure upstream
'
test_expect_success '"upstream" does not push when remotes do not match' '
git checkout main &&
test_config branch.main.remote parent1 &&
test_config branch.main.merge refs/heads/foo &&
test_config push.default upstream &&
test_commit five &&
test_must_fail git push parent2
'
test_expect_success '"current" does not push when multiple remotes and none origin' '
git checkout main &&
test_config push.default current &&
test_commit current-multi &&
test_must_fail git push
'
test_expect_success '"current" pushes when remote explicitly specified' '
git checkout main &&
test_config push.default current &&
test_commit current-specified &&
git push parent1
'
test_expect_success '"current" pushes to origin when no remote specified among multiple' '
git checkout main &&
test_config remote.origin.url repo1 &&
test_config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" &&
test_commit current-origin &&
test_push_success current main
'
test_expect_success '"current" pushes to single remote even when not specified' '
git checkout main &&
test_when_finished git remote add parent1 repo1 &&
git remote remove parent1 &&
test_commit current-implied &&
test_push_success current main repo2
'
test_expect_success 'push from/to new branch with non-defaulted remote fails with upstream, matching, current and simple ' '
git checkout -b new-branch &&
test_push_failure simple &&
test_push_failure matching &&
test_push_failure upstream &&
test_push_failure current
'
test_expect_success 'push from/to new branch fails with upstream and simple ' '
git checkout -b new-branch-1 &&
test_config branch.new-branch-1.remote parent1 &&
test_push_failure simple &&
test_push_failure upstream
'
# The behavior here is surprising but not entirely wrong:
# - the current branch is used to determine the target remote
# - the "matching" push default pushes matching branches, *ignoring* the
# current new branch as it does not have upstream tracking
# - the default push succeeds
#
# A previous test expected this to fail, but for the wrong reasons:
# it expected to fail because the branch is new and cannot be pushed, but
# in fact it was failing because of an ambiguous remote
#
test_expect_failure 'push from/to new branch fails with matching ' '
git checkout -b new-branch-2 &&
test_config branch.new-branch-2.remote parent1 &&
test_push_failure matching
'
test_expect_success 'push from/to branch with tracking fails with nothing ' '
git checkout -b tracked-branch &&
test_config branch.tracked-branch.remote parent1 &&
test_config branch.tracked-branch.merge refs/heads/tracked-branch &&
test_push_failure nothing
'
test_expect_success 'push from/to new branch succeeds with upstream if push.autoSetupRemote' '
git checkout -b new-branch-a &&
test_config push.autoSetupRemote true &&
test_config branch.new-branch-a.remote parent1 &&
test_push_success upstream new-branch-a
'
test_expect_success 'push from/to new branch succeeds with simple if push.autoSetupRemote' '
git checkout -b new-branch-c &&
test_config push.autoSetupRemote true &&
test_config branch.new-branch-c.remote parent1 &&
test_push_success simple new-branch-c
'
test_expect_success '"matching" fails if none match' '
git init --bare empty &&
test_must_fail git push empty : 2>actual &&
test_grep "Perhaps you should specify a branch" actual
'
test_expect_success 'push ambiguously named branch with upstream, matching and simple' '
git checkout -b ambiguous &&
test_config branch.ambiguous.remote parent1 &&
test_config branch.ambiguous.merge refs/heads/ambiguous &&
git tag ambiguous &&
test_push_success simple ambiguous &&
test_push_success matching ambiguous &&
test_push_success upstream ambiguous
'
test_expect_success 'push from/to new branch with current creates remote branch' '
test_config branch.new-branch.remote repo1 &&
git checkout new-branch &&
test_push_success current new-branch
'
test_expect_success 'push to existing branch, with no upstream configured' '
test_config branch.main.remote repo1 &&
git checkout main &&
test_push_failure simple &&
test_push_failure upstream
'
test_expect_success 'push to existing branch, upstream configured with same name' '
test_config branch.main.remote repo1 &&
test_config branch.main.merge refs/heads/main &&
git checkout main &&
test_commit six &&
test_push_success upstream main &&
test_commit seven &&
test_push_success simple main
'
test_expect_success 'push to existing branch, upstream configured with different name' '
test_config branch.main.remote repo1 &&
test_config branch.main.merge refs/heads/other-name &&
git checkout main &&
test_commit eight &&
test_push_success upstream other-name &&
test_commit nine &&
test_push_failure simple &&
git --git-dir=repo1 log -1 --format="%h %s" "other-name" >expect-other-name &&
test_push_success current main &&
git --git-dir=repo1 log -1 --format="%h %s" "other-name" >actual-other-name &&
test_cmp expect-other-name actual-other-name
'
# We are on 'main', which integrates with 'foo' from parent1
# remote (set in test_pushdefault_workflow helper). Push to
# parent1 in centralized, and push to parent2 in triangular workflow.
# The parent1 repository has 'main' and 'foo' branches, while
# the parent2 repository has only 'main' branch.
#
# test_pushdefault_workflow() arguments:
# $1 = success or failure
# $2 = push.default value
# $3 = branch to check for actual output (main or foo)
# $4 = [optional] switch to triangular workflow
# update parent1's main (which is not our upstream)
test_pushdefault_workflow success current main
# update parent1's foo (which is our upstream)
test_pushdefault_workflow success upstream foo
# upstream is foo which is not the name of the current branch
test_pushdefault_workflow failure simple main
# main and foo are updated
test_pushdefault_workflow success matching main
# main is updated
test_pushdefault_workflow success current main triangular
# upstream mode cannot be used in triangular
test_pushdefault_workflow failure upstream foo triangular
# in triangular, 'simple' works as 'current' and update the branch
# with the same name.
test_pushdefault_workflow success simple main triangular
# main is updated (parent2 does not have foo)
test_pushdefault_workflow success matching main triangular
# default tests, when no push-default is specified. This
# should behave the same as "simple" in non-triangular
# settings, and as "current" otherwise.
test_expect_success 'default behavior allows "simple" push' '
test_config branch.main.remote parent1 &&
test_config branch.main.merge refs/heads/main &&
test_config remote.pushdefault parent1 &&
test_commit default-main-main &&
test_push_success "" main
'
test_expect_success 'default behavior rejects non-simple push' '
test_config branch.main.remote parent1 &&
test_config branch.main.merge refs/heads/foo &&
test_config remote.pushdefault parent1 &&
test_commit default-main-foo &&
test_push_failure ""
'
test_expect_success 'default triangular behavior acts like "current"' '
test_config branch.main.remote parent1 &&
test_config branch.main.merge refs/heads/foo &&
test_config remote.pushdefault parent2 &&
test_commit default-triangular &&
test_push_success "" main repo2
'
test_done
|