I'm investigating how rebase works, and I'm finding that it doesn't
work well if the rebased branch contains merges.  Am I using rebase
incorrectly?

In particular, if there are merge commits on the old branch that
contain changes that are not contained in either of the commits that
are merged, rebase doesn't carry them properly into the new branch.

(This sort of merge is not unusual; there may be adjustments needed to
combine two sets of changes for reasons other than a purely textual
collision between the changes.)

As far as I can tell, rebase without --preserve-merges entirely
ignores merge commits on the old branch.  Rebase with
--perserve-merges seems to recreate the new merges de novo rather than
by examining the old merge to determine what it changes.  Neither of
these actions is optimal (IMHO).

As a test case, I've written the following shell script.  It's written
for Linux, but the comments should be clear enough to allow manually
executing the git commands on other systems.  The places where I think
Git is behaving poorly are marked with "***".  Following the script is
the output of my execution of the script.

The beginning of the script creates this commit structure:

               A---B---C---D master
                \
                 \   Q  
                  \ / \ 
                   P   S---T dev
                    \ / 
                     R  

The goal is to rebase dev (calling it branch 'rebase') to the head of
master.  But getting the changes that are in S that are not in Q or R
carried into the new branch seems to be impossible.

----------------------------------------------------------------------
set -ve

# Create a temporary directory and go into it.
DIR=temp.$$
mkdir $DIR
cd $DIR

# Create a Git repository.
git init

# Create a file containing the lines 1 to 10.
seq 1 10 >file
git add file
git commit -m 'Commit A'

# Start the dev branch at commit A.
git branch dev HEAD

# Add lines 1.5, 2.5, and 3.5 in a series of commits on master.
# This sed command adds a line 1.5 before the line 2.

sed --in-place -e '/^2$/i1.5' file
git commit -a -m 'Commit B'

sed --in-place -e '/^3$/i2.5' file
git commit -a -m 'Commit C'

sed --in-place -e '/^4$/i3.5' file
git commit -a -m 'Commit D'

# Show the commit structure of master.
git log --graph --oneline master
git log --graph -p master

# Go to the dev branch and create commits with a non-trivial merge.
git checkout dev

sed --in-place -e '/^5$/i4.5' file
git commit -a -m 'Commit P'

git branch dev1 HEAD

sed --in-place -e '/^6$/i5.5' file
git commit -a -m 'Commit Q'

git checkout dev1

sed --in-place -e '/^7$/i6.5' file
git commit -a -m 'Commit R'

git checkout dev

# Merge commits Q and R, but add the additional line 7.5 (to simulate
# fixes that were needed to resolve the merge).

git merge --no-commit dev1
sed --in-place -e '/^8$/i7.5' file
git commit -a -m 'Commit S'

sed --in-place -e '/^9$/i8.5' file
git commit -a -m 'Commit T'

# Show the commit structure of dev.
git log --graph --oneline dev
# *** Note that the diffs do not show the line 7.5 added in commit S.
git log --graph -p dev

# Rebase the dev branch to the tip of master.
git checkout dev
git branch -f rebase dev
git checkout rebase
git rebase master

# Show the commit structure.
git log --graph --oneline
# *** Note that the line 7.5 added in commit S isn't carried into the new 
branch.
git log --graph -p

# Rebase the dev branch to the tip of master using --preserve-merges.
git checkout dev
git branch -f rebase dev
git checkout rebase
git rebase --preserve-merges master

# Show the commit structure.
git log --graph --oneline
# *** Note that the line 7.5 added in commit S isn't carried into the new 
branch.
git log --graph -p
----------------------------------------------------------------------
$ # Create a temporary directory and go into it.
$ DIR=temp.$$
$ mkdir $DIR
$ cd $DIR

$ # Create a Git repository.
$ git init
Initialized empty Git repository in 
/common/not-replicated/worley/T7/temp.21586/.git/

$ # Create a file containing the lines 1 to 10.
$ seq 1 10 >file
$ git add file
$ git commit -m 'Commit A'
[master (root-commit) 4bd9843] Commit A
 1 files changed, 10 insertions(+), 0 deletions(-)
 create mode 100644 file

$ # Start the dev branch at commit A.
$ git branch dev HEAD

$ # Add lines 1.5, 2.5, and 3.5 in a series of commits on master.
$ # This sed command adds a line 1.5 before the line 2.

$ sed --in-place -e '/^2$/i1.5' file
$ git commit -a -m 'Commit B'
[master a611052] Commit B
 1 files changed, 1 insertions(+), 0 deletions(-)

$ sed --in-place -e '/^3$/i2.5' file
$ git commit -a -m 'Commit C'
[master 23aebfa] Commit C
 1 files changed, 1 insertions(+), 0 deletions(-)

$ sed --in-place -e '/^4$/i3.5' file
$ git commit -a -m 'Commit D'
[master b1bdf0e] Commit D
 1 files changed, 1 insertions(+), 0 deletions(-)

$ # Show the commit structure of master.
$ git log --graph --oneline master
* b1bdf0e Commit D
* 23aebfa Commit C
* a611052 Commit B
* 4bd9843 Commit A
$ git log --graph -p master
* commit b1bdf0e3b7a491cc4ea5c6c8802b9c48e1cb7fdb
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit D
| 
| diff --git a/file b/file
| index 478aae5..9806d67 100644
| --- a/file
| +++ b/file
| @@ -3,6 +3,7 @@
|  2
|  2.5
|  3
| +3.5
|  4
|  5
|  6
|  
* commit 23aebfa6af3ed49d8bca4e2c571ba206e468cc1d
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit C
| 
| diff --git a/file b/file
| index 01d4c89..478aae5 100644
| --- a/file
| +++ b/file
| @@ -1,6 +1,7 @@
|  1
|  1.5
|  2
| +2.5
|  3
|  4
|  5
|  
* commit a611052d0959c26c6df01227f8121cb0dcaacfaa
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit B
| 
| diff --git a/file b/file
| index f00c965..01d4c89 100644
| --- a/file
| +++ b/file
| @@ -1,4 +1,5 @@
|  1
| +1.5
|  2
|  3
|  4
|  
* commit 4bd9843bf644d5d9e248d0c1d2864a764d156a1d
  Author: Dale Worley <wor...@ariadne.com>
  Date:   Thu Jan 31 12:23:48 2013 -0500
  
      Commit A
  
  diff --git a/file b/file
  new file mode 100644
  index 0000000..f00c965
  --- /dev/null
  +++ b/file
  @@ -0,0 +1,10 @@
  +1
  +2
  +3
  +4
  +5
  +6
  +7
  +8
  +9
  +10

$ # Go to the dev branch and create commits with a non-trivial merge.
$ git checkout dev
$ Switched to branch 'dev'

$ sed --in-place -e '/^5$/i4.5' file
$ git commit -a -m 'Commit P'
[dev 805868a] Commit P
 1 files changed, 1 insertions(+), 0 deletions(-)

$ git branch dev1 HEAD

$ sed --in-place -e '/^6$/i5.5' file
$ git commit -a -m 'Commit Q'
[dev 5a517a8] Commit Q
 1 files changed, 1 insertions(+), 0 deletions(-)

$ git checkout dev1
Switched to branch 'dev1'

$ sed --in-place -e '/^7$/i6.5' file
$ git commit -a -m 'Commit R'
[dev1 7a02b53] Commit R
 1 files changed, 1 insertions(+), 0 deletions(-)

$ git checkout dev
Switched to branch 'dev'

$ # Merge commits Q and R, but add the additional line 7.5 (to simulate
$ # fixes that were needed to resolve the merge).

$ git merge --no-commit dev1
Auto-merging file
Automatic merge went well; stopped before committing as requested
$ sed --in-place -e '/^8$/i7.5' file
$ git commit -a -m 'Commit S'
[dev fa07bef] Commit S

$ sed --in-place -e '/^9$/i8.5' file
$ git commit -a -m 'Commit T'
[dev 49da12f] Commit T
 1 files changed, 1 insertions(+), 0 deletions(-)

$ # Show the commit structure of dev.
$ git log --graph --oneline dev
* 49da12f Commit T
*   fa07bef Commit S
|\  
| * 7a02b53 Commit R
* | 5a517a8 Commit Q
|/  
* 805868a Commit P
* 4bd9843 Commit A
$ git log --graph -p dev
* commit 49da12fad3ed7073a13b5b7431ddd1192e1f8f0a
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit T
| 
| diff --git a/file b/file
| index 26d02ff..335fde5 100644
| --- a/file
| +++ b/file
| @@ -10,5 +10,6 @@
|  7
|  7.5
|  8
| +8.5
|  9
|  10
|    
*   commit fa07bef298eeff67ff17334b187dd5221e614649
|\  Merge: 5a517a8 7a02b53
| | Author: Dale Worley <wor...@ariadne.com>
| | Date:   Thu Jan 31 12:23:48 2013 -0500
| | 
| |     Commit S
| |   
| * commit 7a02b53dc7eb464b8fedb6f20edef0e10f241f19
| | Author: Dale Worley <wor...@ariadne.com>
| | Date:   Thu Jan 31 12:23:48 2013 -0500
| | 
| |     Commit R
| | 
| | diff --git a/file b/file
| | index 3af8587..546efa5 100644
| | --- a/file
| | +++ b/file
| | @@ -5,6 +5,7 @@
| |  4.5
| |  5
| |  6
| | +6.5
| |  7
| |  8
| |  9
| |   
* | commit 5a517a8508678b73b4348dff7b3f68e6c4cc1745
|/  Author: Dale Worley <wor...@ariadne.com>
|   Date:   Thu Jan 31 12:23:48 2013 -0500
|   
|       Commit Q
|   
|   diff --git a/file b/file
|   index 3af8587..e8d2a6e 100644
|   --- a/file
|   +++ b/file
|   @@ -4,6 +4,7 @@
|    4
|    4.5
|    5
|   +5.5
|    6
|    7
|    8
|  
* commit 805868afd8edd628e3b17f25c9f43f4138b17769
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit P
| 
| diff --git a/file b/file
| index f00c965..3af8587 100644
| --- a/file
| +++ b/file
| @@ -2,6 +2,7 @@
|  2
|  3
|  4
| +4.5
|  5
|  6
|  7
|  
* commit 4bd9843bf644d5d9e248d0c1d2864a764d156a1d
  Author: Dale Worley <wor...@ariadne.com>
  Date:   Thu Jan 31 12:23:48 2013 -0500
  
      Commit A
  
  diff --git a/file b/file
  new file mode 100644
  index 0000000..f00c965
  --- /dev/null
  +++ b/file
  @@ -0,0 +1,10 @@
  +1
  +2
  +3
  +4
  +5
  +6
  +7
  +8
  +9
  +10

$ # Rebase the dev branch to the tip of master.
$ git checkout dev
Already on 'dev'
$ git branch -f rebase dev
$ git checkout rebase
Switched to branch 'rebase'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Commit P
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging file
Applying: Commit R
Applying: Commit Q
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging file
Applying: Commit T
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging file

$ # Show the commit structure.
$ git log --graph --oneline
* e69cd59 Commit T
* b75ee63 Commit Q
* 72026e5 Commit R
* f9c8dd9 Commit P
* b1bdf0e Commit D
* 23aebfa Commit C
* a611052 Commit B
* 4bd9843 Commit A
$ git log --graph -p
* commit e69cd59027d213a105c974908502279bbbfdec84
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit T
| 
| diff --git a/file b/file
| index 5394052..d5647ae 100644
| --- a/file
| +++ b/file
| @@ -12,5 +12,6 @@
|  6.5
|  7
|  8
| +8.5
|  9
|  10
|  
* commit b75ee633387bc180e4bd3c123ca8fe7db73c0518
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit Q
| 
| diff --git a/file b/file
| index f81b941..5394052 100644
| --- a/file
| +++ b/file
| @@ -7,6 +7,7 @@
|  4
|  4.5
|  5
| +5.5
|  6
|  6.5
|  7
|  
* commit 72026e5a9b80537dffea4cabab86323034b714ce
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit R
| 
| diff --git a/file b/file
| index ce9e0c7..f81b941 100644
| --- a/file
| +++ b/file
| @@ -8,6 +8,7 @@
|  4.5
|  5
|  6
| +6.5
|  7
|  8
|  9
|  
* commit f9c8dd90d6a1635b42b7876faebd337b2e5d82a1
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit P
| 
| diff --git a/file b/file
| index 9806d67..ce9e0c7 100644
| --- a/file
| +++ b/file
| @@ -5,6 +5,7 @@
|  3
|  3.5
|  4
| +4.5
|  5
|  6
|  7
|  
* commit b1bdf0e3b7a491cc4ea5c6c8802b9c48e1cb7fdb
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit D
| 
| diff --git a/file b/file
| index 478aae5..9806d67 100644
| --- a/file
| +++ b/file
| @@ -3,6 +3,7 @@
|  2
|  2.5
|  3
| +3.5
|  4
|  5
|  6
|  
* commit 23aebfa6af3ed49d8bca4e2c571ba206e468cc1d
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit C
| 
| diff --git a/file b/file
| index 01d4c89..478aae5 100644
| --- a/file
| +++ b/file
| @@ -1,6 +1,7 @@
|  1
|  1.5
|  2
| +2.5
|  3
|  4
|  5
|  
* commit a611052d0959c26c6df01227f8121cb0dcaacfaa
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit B
| 
| diff --git a/file b/file
| index f00c965..01d4c89 100644
| --- a/file
| +++ b/file
| @@ -1,4 +1,5 @@
|  1
| +1.5
|  2
|  3
|  4
|  
* commit 4bd9843bf644d5d9e248d0c1d2864a764d156a1d
  Author: Dale Worley <wor...@ariadne.com>
  Date:   Thu Jan 31 12:23:48 2013 -0500
  
      Commit A
  
  diff --git a/file b/file
  new file mode 100644
  index 0000000..f00c965
  --- /dev/null
  +++ b/file
  @@ -0,0 +1,10 @@
  +1
  +2
  +3
  +4
  +5
  +6
  +7
  +8
  +9
  +10

$ # Rebase the dev branch to the tip of master using --preserve-merges.
$ git checkout dev
Switched to branch 'dev'
$ git branch -f rebase dev
$ git checkout rebase
Switched to branch 'rebase'
$ git rebase --preserve-merges master
Successfully rebased and updated refs/heads/rebase.

$ # Show the commit structure.
$ git log --graph --oneline
* 150264a Commit T
*   7868322 Commit S
|\  
| * 72026e5 Commit R
* | 0572677 Commit Q
|/  
* f9c8dd9 Commit P
* b1bdf0e Commit D
* 23aebfa Commit C
* a611052 Commit B
* 4bd9843 Commit A
$ git log --graph -p
* commit 150264abd15d2a8d13e37cc7d4c614d3514f9efb
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit T
| 
| diff --git a/file b/file
| index 5394052..d5647ae 100644
| --- a/file
| +++ b/file
| @@ -12,5 +12,6 @@
|  6.5
|  7
|  8
| +8.5
|  9
|  10
|    
*   commit 7868322b19d3c3dd2c829223042b6c6f28378ec1
|\  Merge: 0572677 72026e5
| | Author: Dale Worley <wor...@ariadne.com>
| | Date:   Thu Jan 31 12:23:48 2013 -0500
| | 
| |     Commit S
| |   
| * commit 72026e5a9b80537dffea4cabab86323034b714ce
| | Author: Dale Worley <wor...@ariadne.com>
| | Date:   Thu Jan 31 12:23:48 2013 -0500
| | 
| |     Commit R
| | 
| | diff --git a/file b/file
| | index ce9e0c7..f81b941 100644
| | --- a/file
| | +++ b/file
| | @@ -8,6 +8,7 @@
| |  4.5
| |  5
| |  6
| | +6.5
| |  7
| |  8
| |  9
| |   
* | commit 057267740ed9e21f1e21e615cfb0f99d05634074
|/  Author: Dale Worley <wor...@ariadne.com>
|   Date:   Thu Jan 31 12:23:48 2013 -0500
|   
|       Commit Q
|   
|   diff --git a/file b/file
|   index ce9e0c7..fc8a02f 100644
|   --- a/file
|   +++ b/file
|   @@ -7,6 +7,7 @@
|    4
|    4.5
|    5
|   +5.5
|    6
|    7
|    8
|  
* commit f9c8dd90d6a1635b42b7876faebd337b2e5d82a1
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit P
| 
| diff --git a/file b/file
| index 9806d67..ce9e0c7 100644
| --- a/file
| +++ b/file
| @@ -5,6 +5,7 @@
|  3
|  3.5
|  4
| +4.5
|  5
|  6
|  7
|  
* commit b1bdf0e3b7a491cc4ea5c6c8802b9c48e1cb7fdb
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit D
| 
| diff --git a/file b/file
| index 478aae5..9806d67 100644
| --- a/file
| +++ b/file
| @@ -3,6 +3,7 @@
|  2
|  2.5
|  3
| +3.5
|  4
|  5
|  6
|  
* commit 23aebfa6af3ed49d8bca4e2c571ba206e468cc1d
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit C
| 
| diff --git a/file b/file
| index 01d4c89..478aae5 100644
| --- a/file
| +++ b/file
| @@ -1,6 +1,7 @@
|  1
|  1.5
|  2
| +2.5
|  3
|  4
|  5
|  
* commit a611052d0959c26c6df01227f8121cb0dcaacfaa
| Author: Dale Worley <wor...@ariadne.com>
| Date:   Thu Jan 31 12:23:48 2013 -0500
| 
|     Commit B
| 
| diff --git a/file b/file
| index f00c965..01d4c89 100644
| --- a/file
| +++ b/file
| @@ -1,4 +1,5 @@
|  1
| +1.5
|  2
|  3
|  4
|  
* commit 4bd9843bf644d5d9e248d0c1d2864a764d156a1d
  Author: Dale Worley <wor...@ariadne.com>
  Date:   Thu Jan 31 12:23:48 2013 -0500
  
      Commit A
  
  diff --git a/file b/file
  new file mode 100644
  index 0000000..f00c965
  --- /dev/null
  +++ b/file
  @@ -0,0 +1,10 @@
  +1
  +2
  +3
  +4
  +5
  +6
  +7
  +8
  +9
  +10
----------------------------------------------------------------------

Dale

-- 
You received this message because you are subscribed to the Google Groups "Git 
for human beings" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to git-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to