The new solution for a triangular workflow (pull from one branch, push to another) would be:
git config --global merge.autosetupmerge=true # pull from origin/master
git config push.default current # push to origin/feature1
git switch -c feature1 origin/master
With Git 2.37 (Q3 2022), "git -c branch.autosetupmerge=simple branch $A $B
"(man)" will set the $B
as $A
's upstream only when $A
and $B
shares the same name, and "git -c push.default=simple
" on branch $A
would push to update the branch $A at the remote $B
came from.
Also more places use the sole remote, if exists, before defaulting to 'origin
'.
See commit 05d5775, commit 8a649be, commit bdaf1df (29 Apr 2022) by Tao Klerks (TaoK
).
(Merged by Junio C Hamano -- gitster
-- in commit f49c478, 26 May 2022)
branch
: new autosetupmerge
option 'simple
' for matching branches
Signed-off-by: Tao Klerks
With the default push.default
option, "simple
", beginners are protected from accidentally pushing to the "wrong" branch in centralized workflows: if the remote tracking branch they would push to does not have the same name as the local branch, and they try to do a "default push
", they get an error and explanation with options.
There is a particular centralized workflow where this often happens: a user branches to a new local topic branch from an existing remote branch, eg with "checkout -b feature1 origin/master
".
Problem:
With the default branch.autosetupmerge
configuration (value "true
"), git will automatically add origin/master
as the upstream tracking branch.
When the user pushes with a default "git push
"(man), with the intention of pushing their (new) topic branch to the remote, they get an error, and (amongst other things) a suggestion to run "git push origin HEAD
".
If they follow this suggestion the push succeeds, but on subsequent default pushes they continue to get an error - so eventually they figure out to add "-u
" to change the tracking branch, or they spelunk the push.default
config doc as proposed and set it to "current
", or some GUI tooling does one or the other of these things for them.
When one of their coworkers later works on the same topic branch, they don't get any of that "weirdness".
They just "git checkout feature1
"(man) and everything works exactly as they expect, with the shared remote branch set up as remote tracking branch, and push and pull working out of the box.
The "stable state" for this way of working is that local branches have the same-name remote tracking branch (origin/feature1
in this example), and multiple people can work on that remote feature branch at the same time, trusting "git pull
"(man) to merge or rebase as required for them to be able to push their interim changes to that same feature branch on that same remote.
(merging from the upstream "master
" branch, and merging back to it, are separate more involved processes in this flow).
Problem (bis):
There is a problem in this flow/way of working, however, which is that the first user, when they first branched from origin/master
, ended up with the "wrong" remote tracking branch (different from the stable state).
For a while, before they pushed (and maybe longer, if they don't use -u
/--set-upstream
), their "git pull
" was not getting other users' changes to the feature branch - it was getting any changes from the remote "master
" branch instead (a completely different class of changes!)
An experienced Git user might say well yeah, that's what it means to have the remote tracking branch set to origin/master
!" - but the original user above didn't ask to have the remote master
branch added as remote tracking branch - that just happened automatically when they branched their feature branch.
They didn't necessarily even notice or understand the meaning of the "set up to track 'origin/master
'" message when they created the branch - especially if they are using a GUI.
Looking at how to fix this, you might think "OK, so disable auto setup of remote tracking - set branch.autosetupmerge
to false" - but that will inconvenience the second user in this story - the one who just wanted to start working on the topic branch.
The first and second users swap roles at different points in time of course - they should both have a sane configuration that does the right thing in both situations.
Make this "branches have the same name locally as on the remote" workflow less painful / more obvious by introducing a new branch.autosetupmerge
option called "simple
", to match the same-name "push.default
" option that makes similar assumptions.
This new option automatically sets up tracking in a subset of the current default situations: when the original ref is a remote tracking branch and has the same branch name on the remote (as the new local branch name).
Update the error displayed when the 'push.default=simple' configuration rejects a mismatching-upstream-name default push, to offer this new branch.autosetupmerge
option that will prevent this class of error.
With this new configuration, in the example situation above, the first user does not get origin/master
set up as the tracking branch for the new local branch.
If they "git pull
" in their new local-only branch, they get an error explaining there is no upstream branch - which makes sense and is helpful.
If they "git push
", they get an error explaining how to push and suggesting they specify --set-upstream
- which is exactly the right thing to do for them.
This new option is likely not appropriate for users intentionally implementing a "triangular workflow" with a shared upstream tracking branch, that they "git pull
" in and a private feature branch that they push/force-push to just for remote safe-keeping until they are ready to push up to the shared branch explicitly/separately.
Such users are likely to prefer keeping the current default merge.autosetupmerge=true
behavior, and change their push.default
to "current
".
git config
now includes in its man page:
branch.autoSetupMerge
simple
-- automatic setup is done only when the starting point
is a remote-tracking branch and the new branch has the same name as the remote branch.
This option defaults to true.
git branch
now includes in its man page:
-t / --track[=(direct|inherit)]
The branch.autoSetupMerge
configuration variable specifies how git switch
,
git checkout
and git branch
should behave when neither --track
nor
--no-track
are specified:
- The default option,
true
, behaves as though --track=direct
were given whenever the start-point is a remote-tracking branch.
false
behaves as if --no-track
were given. always
behaves as though
--track=direct
were given.
inherit
behaves as though --track=inherit
were given.
simple
behaves as though --track=direct
were given only when
the start-point is a remote-tracking branch and the new branch has the same
name as the remote branch.