18

git pull --rebase removes unpushed merge commits. Is there a way to make it preserve them?

Say my history looks like—

A
| \ 
B  H
|  |
C  G
|  |
D  F
| /
E

(A being the merge commit.)

After a git pull --rebase it becomes—

H
|
G
|
F
|
X
|
B
|
C
|
D
|
E

(X being the new commits git pull --rebase inserted into my history.)—A is removed.

I know you can use git rebase --preserve-merges to preserve them with git rebase, but I don't see a way to preserve them with git pull --rebase.

Mario F
  • 45,569
  • 6
  • 37
  • 38
user1569050
  • 6,099
  • 2
  • 18
  • 14
  • You mean you want to keep the structure of the revision graph? (Otherwise, I'm not sure what that `A` is supposed to be.) – Christopher Creutzig Aug 08 '12 at 11:47
  • Yes—`A` is just the merge commit, "Merge branch *foo* into *bar*" – user1569050 Aug 08 '12 at 11:51
  • git 1.8.5 will introduce a neat way to preserve merge on `pull --rebase`: see [my answer below](http://stackoverflow.com/a/18756102/6309) – VonC Sep 12 '13 at 05:36
  • I do not get, why this rebases the local history even with no remote changes at all aka I already had everything but wanted to be sure. Ideas? – ReneS Nov 18 '13 at 16:50

4 Answers4

35

Update: As I presented in "What exactly does Git's "rebase --preserve-merges" do (and why?)", since Git 2.18 (Q2 2018), you would prefer the new option --rebase-merges to the legacy one --preserve-merge

Since then:

So:

git rebase --interactive --rebase-merges origin/master 
# or
git config pull.rebase merges
git rebase --interactive origin/master (would use rebase-merges)

Original answer 2013:

Or (for the upcoming git 1.8.5 Q4 2013, now delivered in git 1.8.5, 2013-11-27):

"git pull --rebase" always chose to do the bog-standard flattening rebase.
You can tell it to run "rebase --preserve-merges" by setting "pull.rebase" configuration to "preserve".

So a simple config will be enough to make sure your pull --rebase does preserve merge:

git config pull.rebase preserve

See commit 66713ef3 for more (thanks to Stephen Haberman):

pull: allow pull to preserve merges when rebasing

If a user is working on master, and has merged in their feature branch, but now has to "git pull" because master moved, with pull.rebase their feature branch will be flattened into master.

This is because "git pull" currently does not know about rebase's preserve merges flag, which would avoid this behavior, as it would instead replay just the merge commit of the feature branch onto the new master, and not replay each individual commit in the feature branch.

Add a --rebase=preserve option, which will pass along --preserve-merges to rebase.

Also add 'preserve' to the allowed values for the pull.rebase config setting.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • 5
    For those that work with lots of repositories make it work everywhere with: `git config --global pull.rebase preserve` – Mark Edington May 21 '14 at 22:16
18

you can split your pull in a fetch and a rebase

git fetch origin master
git rebase origin master --preserve-merges
Mario F
  • 45,569
  • 6
  • 37
  • 38
9

Simply:

git pull --rebase=preserve

From the docs:

When set to preserve, rebase with the --preserve-merges option passed to git rebase so that locally created merge commits will not be flattened.

Nick F
  • 9,781
  • 7
  • 75
  • 90
Weidenrinde
  • 2,152
  • 1
  • 20
  • 21
0

Since git v2.22.0, --preserve-merges option has been deprecated in favor of --rebase-merges (to be used in combination with --interactive option) to reapply commits on top of another base tip with git-rebase:

git fetch origin master
git rebase --interactive --rebase-merges origin/master 
Th. Ma.
  • 9,432
  • 5
  • 31
  • 46