Recall from technique 13 that rebasing is similar to merging but requires rewriting history. Let’s create a branch that you can rebase:
1 Change to the directory containing your repository: for example, cd /Users/mike/GitInPracticeRedux/.
2 Run git checkout -b inspiration v0.1.
3 Edit 01-IntroducingGitInPractice.asciidoc, and make a change to the file.
4 Run git commit --message="Add Chapter 1 inspiration." 01-Introducing-GitInPractice.asciidoc. The output should resemble the following.
111 TECHNIQUE 43 Rebasing commits on top of another branch: git rebase
# git commit --message="Add Chapter 1 inspiration."
01-IntroducingGitInPractice.asciidoc
[inspiration 88e8b4b] Add Chapter 1 inspiration.
1 file changed, 1 insertion(+)
Figure 6.5 shows the new inspiration branch. It has a single commit, and the parent of that commit is the commit that has the v0.1 tag.
Now let’s rebase this branch.
Problem
You wish to rebase the inspiration branch on top of the v0.1-release branch.
Solution
1 Change to the directory containing your repository: for example, cd /Users/mike/GitInPracticeRedux/.
2 Run git checkout inspiration.
3 Run git rebase v0.1-release. The output should resemble the following.
# git rebase v0.1-release
First, rewinding head to replay your work on top of it...
Applying: Add Chapter 1 inspiration.
B
shows that Git is moving the HEAD pointer to the latest commit on the v0.1-release branch. It’s doing this so it can apply the newly created commit on the inspiration branch with the latest commit on the v0.1-release branch as its parent.C
shows a list of each commit (in this case, only one) re-created on the branch. Effec-tively, each commit on the branch being rebased is cherry-picked (discussed in tech-nique 38) on top of the new base: the latest commit on the v0.1-release branch.Because their parent commits have changed, so do the SHA-1s of all the commits.
Figure 6.6 shows the rebased inspiration branch. It still has a single commit, but that commit’s parent is now the latest commit on the v0.1-release branch rather than the commit tagged v0.1. Note that GitX reflowed and recolored some of the
Listing 6.5 Output: commit to be rebased
Listing 6.6 Rebase output
Figure 6.5 Newly created inspiration branch
HEAD rewound
B
Applying a commit
C
branches; master is now to the right of v0.1-release, and v0.1-release is now green. This doesn’t have any significance beyond GitX trying to make the output more readable.
Note that some editions of this book are printed in grayscale, so these colors may not be visible. Instead, please compare them to GitX on your computer.
You have rebased the inspiration branch on top of the v0.1-release branch.
Discussion
The argument to git rebase can be any ref. You could rebase on an arbitrary commit, but this is generally a bad idea. You should usually rebase on top of either an updated branch or a different branch/tag.
If you made multiple commits to the wrong branch, you can’t use git rebase as is to fix this. But you can do so with git rebase --interactive, which you’ll see in technique 44.
Let’s look at the reflog again to see what effects the rebase had.
# git reflog
5d4ad83 HEAD@{0}: rebase finished: returning to refs/heads/inspiration 5d4ad83 HEAD@{1}: rebase: Add Chapter 1 inspiration.
a8200e1 HEAD@{2}: rebase: checkout v0.1-release 88e8b4b HEAD@{3}: commit: Add Chapter 1 inspiration.
725c33a HEAD@{4}: checkout: moving from master to inspiration 4455fa9 HEAD@{5}: reset: moving to 4455fa9
3e3c417 HEAD@{6}: reset: moving to HEAD^
...
B
shows that the rebase operation has completed successfully, so the inspiration branch was updated to point to the rebased commit.C
shows the new commit that was created with the parent pointing to the latest com-mit on the v0.1-release branch. The inspiration branch was updated after this commit was successfully created. This avoids a situation where a failed rebase oper-ation leaves a branch in an inconsistent state.D
shows the beginning of the rebase operation by checking out the v0.1-release branch that is being used as a new parent.E
shows the new commit that was made before it was rebased.If you wanted to undo this operation, you could run git branch --force inspiration 88e8b4b to reset the inspiration branch pointer to point back to the existing com-mit, essentially undoing the rebase.
Listing 6.7 Reflog output after rebase
Figure 6.6 Rebased
113 TECHNIQUE 43 Rebasing commits on top of another branch: git rebase
Sometimes git rebase operations may fail in a way similar to a git merge or git cherry-pick operation. There may be a merge conflict where changes have been made to the same parts of the same files that have been modified in rebased commits.
The main difference when resolving a git rebase (or git cherry-pick) conflict is that, because there’s no merge commit, it has to be done for each commit at a time.
If the preceding rebase had failed, the output would look something like this.
First, rewinding head to replay your work on top of it...
Applying: Add Chapter 1 inspiration.
Using index info to reconstruct a base tree...
M 01-IntroducingGitInPractice.asciidoc Falling back to patching base and 3-way merge...
Auto-merging 01-IntroducingGitInPractice.asciidoc CONFLICT (content): Merge conflict in
01-IntroducingGitInPractice.asciidoc Failed to merge in the changes.
Patch failed at 0001 Add Chapter 1 inspiration.
The copy of the patch that failed is found in:
/Users/mike/Documents/GitInPracticeRedux/.git/rebase-apply/patch When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
B
shows the same first two lines as a successful rebase; the HEAD was rewound, and Git tried to apply the changes in the commit. The only difference is that, in this case, the changes couldn’t be merged automatically.C
shows the attempt by rebase to merge the multiple changes that were made to the same file. This may be successful, but in this case the merge failed, so rebase tells the user to solve it manually.D
shows the instructions involved in solving the rebase conflict. There are three sug-gested flags: git rebase --continue should be run after the normal merge conflict-resolution process of manually resolving the conflicts and marking them as fixed using git add. This continues the rebase operation by rebasing any fur-ther commits and, if successful, updating the rebased branch.
git rebase --skip means that, rather than solving the merge conflicts in this particular commit, the commit is skipped and the next one is applied instead.
This may make sense in certain situations where the functionality of this com-mit has already been made by another comcom-mit on the branch you’re rebasing on top of, making this commit redundant.
git rebase --abort gives up on the git rebase process altogether and returns the branch to its state before the rebase was attempted.
Listing 6.8 Output: rebase conflict
Rebase