Git rebase is confusing
(written by lawrence, however indented passages are often quotes)
This is a fantastic explanation of one of the most confusing things about git: the use of rebase, and in particular the use of rebase to resolve conflicts.
SourceI am not writing this because I am a git master (I am not) but to point out a thing that I took an unreasonable amount of time to understand. Basically, I am going to show that “git rebase” serves many completely different roles instead of one:
a) rebasing, that is, making a sequence of commits coming from several branches appear like a perfectly serialized development effort, as if it were done by a single person;
b) changing history and editing older commits;
c) “Merging” into master without adding merge commits.
First, let’s see the canonical usage of rebase. Let’s say someone begins with a very simple program:
int main()
{
printf(“Hello world”);
}
From that point, two guys create separate development branches. The lucky one works on ‘features’ branch, that only adds new functionality. After a series of commits, he ends up with the following code:int main()
{
printf(“Hello world !\n”);
printf(“This is my first program\n”);return 0;
}
The commit log of ‘features’ branch is:Added another message 030943f4052e8f5421baf59a3ce68be1ffb8ba17
Added return value fcc6d6a6f72192ad49bd925319746a96a73ce498
Added exclamation point and newline to msg ad184928f92ca8b347313cbe436970630493b36f
The unlucky programmer was charged with the ‘bugfixes’ branch, the boring stuff, and after some bugfixes he has the following code:#include
int main(int argc, char *argv[])
{
printf(“Hello world\n”);
}
And his commit log is:90d1d91d55a4da36c1f27f625119c4c24db33d8e Fixed main() prototype
c244d58951a8683e8f5958d1307e153daba902e8 Added newline
a50cde08b410ba472c567e6da9bf5b2f29b9bd60 Added include file
Ok, now we would like to merge both branches back into ‘master’ branch. We could use ‘git merge’ from master branch:$ git merge bugfixes
…
$ git merge features/Users/epx/art.merge $ git merge features
Auto-merging main.c
CONFLICT (content): Merge conflict in main.c
Automatic merge failed; fix conflicts and then commit the result.
$ vi main.c
$ git commit -a
The problem that many developers see in this, is that non-trivial merges (that have conflicts) create new commits by themselves, which make the log “dirty”:commit 0bcbbf575f08986d0ea89aabf348c3bc008fb618
Merge: a50cde0 ad18492
Author: Elvis Pfutzenreuter
Date: Tue Jun 8 17:31:36 2010 -0300Merge branch ‘features’
Conflicts:
main.c
The “git pull” command does the same thing. Sometimes this is the only way to go, but if the original developers can still be reached, we can ask one of them to rebase his own patches.Let’s adopt the ‘bugfixes’ patches first, and then ask ‘features’ to rebase against newest master:
$ git checkout bugfixes
$ git rebase master # just to be sure
$ git checkout master
$ git rebase bugfixes # “merging”
First, rewinding head to replay your work on top of it…
Fast-forwarded master to bugfixes.
$ git checkout features
$ git rebase master
First, rewinding head to replay your work on top of it…
Applying: Added another message
Using index info to reconstruct a base tree…
Falling back to patching base and 3-way merge…
Auto-merging main.c
CONFLICT (content): Merge conflict in main.c
Failed to merge in the changes.
Patch failed at 0001 Added another messageWhen you have resolved this problem run “git rebase –continue”.
If you would prefer to skip this patch, instead run “git rebase –skip”.
To restore the original branch and stop rebasing run “git rebase –abort”.
The conflict does not go away by itself, but in this case we fix the conflict and continue, and the original patch “Added another message” will be itself changed:$ vi main.c
$ git add main.c
$ git rebase –continue
Another conflict will happen in patch “Added exclamation point…” and we fix the same way. In the end, the ‘features’ patches will be on top of the master/bugfixing patches, as if the new features developer had waited for the bug fixes to be ready, before he did anything new.Sometimes git can work out these conflicts by itself; human intervention is called only when two or more branches touched the same line of code and did different things on it.
Now the master can ‘merge’ from features too:
$ git rebase features
First, rewinding head to replay your work on top of it…
Fast-forwarded master to features.
The final log in master is:Fixed main() prototype 90d1d91d55a4da36c1f27f625119c4c24db33d8e
Added newline c244d58951a8683e8f5958d1307e153daba902e8
Added include file a50cde08b410ba472c567e6da9bf5b2f29b9bd60
Added another message adf09430af144d3b6c14d5fc39ce26a867d2bd61
Added return value 44e0094853e2cf3c949cfa8a34665342309664e1
Added exclamation point and newline f999aa837539a7301b16534ca59a4c6ecc102deb
The master log is a perfectly serialized development history that anybody can follow.Note that all feature-related commits have different SHA-1 signatures, while the bugfix commits have retained the original signatures. This is because feature commits had to be rewritten upon rebasing (since they are now changing a different main.c than the developer first worked on). The bugfix commits retained original signature because they were already based on latest master.
January 10, 2012 1:09 pm
From lawrence on Fred Dewey is misunderstood
"Thank you, Charlotte. But what is the main advantage of Kachingle for you? You could perhaps find a more direc..."