I'm not Git expert and I regularly learn things in Git that changes my view of the tool. When I was showed
git rebase -i, I stopped over-thinking about my commits. When I discovered
git reflog, I became more confident in rebasing. But I think one of the most important command I was taught was
git rebase --onto.
IMHO, the documentation has room for improvement regarding the result of the option. If taking the image of the tree, it basically uproots a part of the tree to replant it somewhere else.
Let's have an example with the following tree:
o---o---o---o master \ \---o---o branch1 \ \---o branch2
Suppose we want to transplant
branch1 to master:
o---o---o---o master \ \ \ \---o' branch2 \ \---o---o branch1
This is a great use-case! On branch
branch2, the command would be
git rebase --onto master branch1. That approximately translates to move everything from
branch2 starting from
branch1 to the tip of
master. I try to remember the syntax by thinking the first argument is the new commit, the second is the old one.
So, but what use-cases are there to move parts of the tree?
While my first reflex when I want to delete commits is to
git rebase -i, it's not always the most convenient. It requires the following steps:
- Locating the first commit to be removed
- Effectively run the
git rebase -icommand
- In the editor, for every commits that needs to be removed, delete the line
- Quit the editor
If the commits to be removed are adjacent, it's easier to
rebase --onto, because you only need the new and the old commit and can do the "deletion" in one line.
Here's an example:
To remove the last 3 commits
Z, you just need:
git rebase --onto A Z
Long-Lived Remote Branches
While it's generally a bad idea to have long-lived branches, it's sometimes required.
Suppose you need to migrate part of your application to a new framework, library, whatever. With small applications, a small task-force can be dedicated to that. The main development team goes on week-end with instructions to commit everything before leaving on Friday. When they come back on Monday, everything has been migrated.
Sadly, life is not always so easy and applications can be too big for such an ideal scenario. In that case, the task force works on a dedicated
migration branch for more than a week-end, in parallel with the main team. But they need to keep up-to-date with the
main branch, and still keep their work.
Hence, every now and then, they rebase the
migration branch at the top of
git rebase --onto master old-root-of-migration
This is different from merging because you keep the history linear.
Sometimes, I want to keep my changes locally, for a number of reasons. For example, I might tinker with additional (or harsher) rules for the code quality tool. In that case, I want to take time to evaluate whether this is relevant for the whole team or not.
As above, this is achieved by regularly rebasing my local
tinker branch onto
As above, it lets me keep my history linear and change the commits relevant to
tinker if the need be. Merging would prevent me from doing this.
git rebase --onto can have different use-cases. The most important ones are related to the handling of long-lived branches, whether local or remote.
As always, it's just one more tool in your toolbelt, so that not everything looks like a nail.
As every command that changes the Git history,
git rebase --onto should only change local commits. You've been warned!