gitgit-mergegit-rebasegit-pullgit-fetch

Why does `git pull origin master:master` from non-master branch cause branch to be rebased?


I'm on branch master and do git log

commit 9937b91089895fac45a39a3bda2935e19eb42554 (HEAD -> master, origin/master, origin/HEAD)
...

git status prints

On branch master
Your branch is up to date with 'origin/master'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        src/orig/

nothing added to commit but untracked files present (use "git add" to track)

and git branch prints

  foo
* master

The I git checkout foo which prints

Switched to branch 'foo'
Your branch is up to date with 'origin/foo'.
...

git status prints

On branch foo
Your branch is up to date with 'origin/foo'.

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        src/orig/

nothing added to commit but untracked files present (use "git add" to track)

and git branch prints

* foo
  master

The I do git pull origin master:master, which prints

Auto-merging .config/Packages.props
CONFLICT (content): Merge conflict in .config/Packages.props
Auto-merging .corext/corext.config
error: could not apply 2fda5e13a117... Initial commit
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config advice.mergeConflict false"
Recorded preimage for '.config/Packages.props'
Could not apply 2fda5e13a117... Initial commit

git status prints

interactive rebase in progress; onto 9937b9108989
Last command done (1 command done):
   pick 2fda5e13a117 Initial commit
No commands remaining.
You are currently rebasing branch 'foo' on '9937b9108989'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
        both modified:   .config/Packages.props

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        src/Services/AZSM/Test/AzSM.SpanningTests/orig/

and git branch prints

* (no branch, rebasing foo)
  master

Then I do git rebase --abort, git checkout master, and git log which prints

commit 9937b91089895fac45a39a3bda2935e19eb42554 (HEAD -> master, origin/master, origin/HEAD)
...

indicating master no changes were pulled into master (maybe there weren't any).


I thought running git pull origin master:master from the foo branch would be equivalent to

git checkout master
git pull origin master
git checkout foo

but it seems like it's not because git pull origin master:master seems to rebase foo.


Solution

  • I thought running git pull origin master:master from the foo branch would be equivalent to ...

    It is not. git pull is basically a git fetch followed by either a git merge or a git rebase.

    More precisely, git pull runs git fetch with the given parameters and then depending on configuration options or command line flags, will call either git rebase or git merge to reconcile diverging branches.

    When you run git pull origin master:master, you're basically asking Git to retrieve the last changes on the remote's master and store them into the corresponding tracking branch origin/master, not merging/rebasing into/onto your master branch. The merge/rebase part happens on the currently checked out branch, in your case foo. In this scenario, since the pull cannot be resolved with a fast-forward, because master and foo have diverged, Git falls back on a rebase.

    The reason why when you perform a git pull Git rebases instead of merging might be because you either have the pull.rebase configuration enabled, or branch.foo.rebase set to true. If by default you prefer merging rather than rebasing, then enter git config --local pull.rebase false or git config --local branch.foo.rebase false (depending on which config was enabled). Also, make sure that branch.autoSetupRebase is set to never, to prevent you from creating branches with the rebase config automatically set to true.

    Lastly, if you want to update your master branch, you need to checkout master and run a git pull from there.