Subject: [PATCH v3 0/2] adding new branch.autosetupmerge option "simple"

From: "Tao Klerks via GitGitGadget" <[email-masked]>
Date: Mon, 28 Feb 2022 07:14:24 +0000

Re-sending with proposed fixes to concerns raised by Junio.

This patchset introduces a new option to the branch.autosetupmerge setting,
"simple", which is intended to be consistent with and complementary to the
push.default "simple" option.

The push.defaut option "simple" helps produce predictable/understandable
behavior for beginners, where they don't accidentally push to the "wrong"
branch in centralized workflows. If they create a local branch with a
different name and then try to do a plain push, it will helpfully fail and
explain why.

However, such users can often find themselves confused by the behavior of
git after they first branch, and before they push. At that stage, their
upstream tracking branch is the original remote branch, and pull will be
bringing in "upstream changes" - eg all changes to "main", in a typical
project where that's where they branched from. On the other hand, once they
push their new branch (dealing with the initial error, following
instructions to push to the right name), subsequent "pull" calls will behave
as expected, only bring in any changes to that new branch they pushed.

The new option introduced here, with push.default set to simple, ensures
that push/pull behavior is generally consistent - tracking will be
automatically set up for branches that push will work for (and pull will be
consistent for) only.

Tao Klerks (2):
  merge: new autosetupmerge option 'simple' for matching branches
  t3200: tests for new branch.autosetupmerge option "simple"

 Documentation/config/branch.txt |  4 +++-
 Documentation/git-branch.txt    | 18 ++++++++++-------
 branch.c                        | 19 ++++++++++++++++++
 branch.h                        |  1 +
 config.c                        |  3 +++
 t/t3200-branch.sh               | 35 +++++++++++++++++++++++++++++++++
 6 files changed, 72 insertions(+), 8 deletions(-)

base-commit: dab1b7905d0b295f1acef9785bb2b9cbb0fdec84
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1161%2FTaoK%2Ffeature-branch-autosetupmerge-simple-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1161/TaoK/feature-branch-autosetupmerge-simple-v3
Pull-Request: https://github.com/gitgitgadget/git/pull/1161

Range-diff vs v2:

 1:  890e016bfc0 ! 1:  0b5d4789512 merge: new autosetupmerge option 'simple' for matching branches
     @@ Metadata
       ## Commit message ##
          merge: new autosetupmerge option 'simple' for matching branches
      
     -    This commit introduces a new option to the branch.autosetupmerge
     -    setting, "simple", which is intended to be consistent with and
     -    complementary to the push.default "simple" option.
     -
     -    The push.defaut option "simple" helps produce
     -    predictable/understandable behavior for beginners, where they don't
     -    accidentally push to the "wrong" branch in centralized workflows. If
     -    they create a local branch with a different name and then try to do a
     -    plain push, it will helpfully fail and explain why.
     -
     -    However, such users can often find themselves confused by the behavior
     -    of git after they first branch, and before they push. At that stage,
     -    their upstream tracking branch is the original remote branch, and pull
     -    will be bringing in "upstream changes" - eg all changes to "main", in
     -    a typical project where that's where they branched from.
     -    On the other hand, once they push their new branch (dealing with the
     -    initial error, following instructions to push to the right name),
     -    subsequent "pull" calls will behave as expected, only bring in any
     -    changes to that new branch they pushed.
     -
     -    The new option introduced here, with push.default set to simple,
     -    ensures that push/pull behavior is generally consistent - tracking
     -    will be automatically set up for branches that push will work for
     -    (and pull will be consistent for) only.
     +    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 feature branch from an existing
     +    upstream branch, eg with "checkout -b feature1 origin/master". With
     +    the default branch.autosetupmerge configuration (value "true"), git
     +    will automatically add origin/master as the remote tracking branch.
     +
     +    When the user pushes with "git push", they get an error, and (amongst
     +    other things) a suggestion to run "git push origin HEAD". Eventually
     +    they figure out to add "-u" to change the tracking branch, or they set
     +    push.default to "current", or some tooling does one or the other of
     +    these things for them.
     +
     +    When one of their coworkers works on the same branch, they don't get
     +    any of that weirdness. They just "git checkout feature1" 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" 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).
     +
     +    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" wasn't 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!)
     +
     +    Any experienced git user will presumably say "well yeah, that's what
     +    it means to have the remote tracking branch set to origin/master!" -
     +    but that user 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 feature 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 these flows painless 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).
     +
     +    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".
      
          Signed-off-by: Tao Klerks <[email-masked]>
      
 2:  c16a8fe01e7 ! 2:  d5b18c7949f t3200: tests for new branch.autosetupmerge option "simple"
     @@ Metadata
       ## Commit message ##
          t3200: tests for new branch.autosetupmerge option "simple"
      
     -    In the previous commit a new autosetupmerge option was
     -    introduced. Here the existing branch tests are extended
     -    with three new cases testing this option - the obvious
     -    matching-name and non-matching-name cases, and also a
     -    non-matching-ref-type case.
     +    In the previous commit a new autosetupmerge option was introduced.
      
     -    The matching-name case needs to temporarily create
     -    an independent repo to fetch from, as the general
     -    strategy of using the local repo as the remote in these
     -    tests precludes locally branching with the same
     +    Extend the existing branch tests with three new cases testing this
     +    option - the obvious matching-name and non-matching-name cases, and
     +    also a non-matching-ref-type case.
     +
     +    The matching-name case needs to temporarily create an independent
     +    repo to fetch from, as the general strategy of using the local repo as
     +    the remote in these tests precludes locally branching with the same
          name as in the "remote".
      
          Signed-off-by: Tao Klerks <[email-masked]>

-- 
gitgitgadget