Please open notebook rsepython-s1r11.ipynb
A git merge is only one of two ways to get someone else’s work into yours. The other is called a rebase.
In a merge, a revision is added, which brings the branches together. Both histories are retained. In a rebase, git tries to work out
What would you need to have done, to make your changes, if your colleague had already made theirs?
Git will invent some new revisions, and the result will be a repository with an apparently linear history.
We’ve built a repository to help visualise the difference between a merge and a rebase, at https://github.com/UCL-RITS/wocky_rebase/blob/master/wocky.md.
The initial state of both collaborators is a text file, wocky.md:
It was clear and cold,
and the slimy monsters
On the master branch, a second commit (‘Dancing’) has been added:
It was clear and cold,
and the slimy monsters
danced and spun in the waves
On the “Carollian” branch, a commit has been added translating the initial state into Lewis Caroll’s language:
'Twas brillig,
and the slithy toves
So the logs look like this:
git log --oneline --graph master
* 2a74d89 Dancing
* 6a4834d Initial state
git log --oneline --graph carollian
* 2232bf3 Translate into Caroll’s language * 6a4834d Initial state
If we now merge carollian into master, the final state will include both changes:
'Twas brillig,
and the slithy toves
danced and spun in the waves
But the graph shows a divergence and then a convergence:
git log --oneline --graph
* b41f869 Merge branch ‘carollian’ into master_merge_carollian
|\
| * 2232bf3 Translate into Caroll’s language
* | 2a74d89 Dancing
|/
* 6a4834d Initial state
But if we rebase, the final content of the file is still the same, but the graph is different:
git log --oneline --graph master_rebase_carollian
* df618e0 Dancing
* 2232bf3 Translate into Caroll’s language
* 6a4834d Initial state
To trigger the rebase, we did:
git checkout master
git rebase carollian
If this had been a remote, we would merge it with:
git pull --rebase
If we want to continue with the translation, and now want to merge the rebased branch into the carollian branch, we get:
Updating 2232bf3..df618e0
Fast-forward
wocky.md | 1 +
1 file changed, 1 insertion(+)
The rebased branch was rebased on the carollian branch, so this merge was just a question of updating metadata to redefine the branch label: a “fast forward”.
Some people like the clean, apparently linear history that rebase provides.
But rebase rewrites history.
If you’ve already pushed, or anyone else has got your changes, things will get screwed up.
If you know your changes are still secret, it might be better to rebase to keep the history clean. If in doubt, just merge.
A second use of the git rebase
command, is to rebase your work on top of one of your own earlier commits,
in interactive mode, to “squash” several commits that should really be one:
git log
ea15 Some good work
ll54 Fix another typo
de73 Fix a typo
ab11 A great piece of work
cd27 Initial commit
If we type
git rebase -i ab11 #OR HEAD^^
an edit window pops up with:
pick cd27 Initial commit
pick ab11 A great piece of work
pick de73 Fix a typo
pick ll54 Fix another typo
pick ea15 Some good work
# Rebase 60709da..30e0ccb onto 60709da
#
# Commands:
# p, pick = use commit
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
We can rewrite select commits to be merged, so that the history is neater before we push. This is a great idea if you have lots of trivial typo commits.
pick cd27 Initial commit
pick ab11 A great piece of work
squash de73 Fix a typo
squash ll54 Fix another typo
pick ea15 Some good work
save the interactive rebase config file, and rebase will build a new history:
git log
de82 Some good work
fc52 A great piece of work
cd27 Initial commit
Note the commit hash codes for ‘Some good work’ and ‘A great piece of work’ have changed, as the change they represent has changed.