There are two ways to sync a feature branch with another branch; merge (
git merge) or rebase (
git rebase). Merging strategy has a few downsides like addition of a merge commit (or not if it can fast-forward), non-linear commit history and others. Where these things are important rebase strategy is viable.
A rebase to sync changes from another branch can be done in the like this:
git checkout <feature_branch> git rebase main
git rebase reapply commits from feature branch on top (ie after) of all changes/commits from main (or specified branch). It basically changes and move base/tip/parent of feature branch.
The following is the visual representation of it:
A---B---C feature / D---E---F---G main
The feature branch after rebase becomes
A'--B'--C' feature / D---E---F---G main
Rebase also has an interactive mode, guiding you through the process and giving additional fine tune controls which can be used for following:
- Cleaning history
- Rewriting commit messages
- Reorder commits
- Squashing multiple commits
- Dropping a commit (off the face of the earth ;))
To do an interactive rebase, just add
git rebase -i main
It will show a visual prompt in a text editor, like the following:
pick f58924e xkcd 1296 pick dd820cc another, xkcd 1597 pick a58124a xkcd 688 # Rebase 0bbe6c4..dd820cc onto 0bbe6c4 (2 commands) # # Commands: # p, pick <commit> = use commit # r, reword <commit> = use commit, but edit the commit message # e, edit <commit> = use commit, but stop for amending # s, squash <commit> = use commit, but meld into previous commit # f, fixup <commit> = like "squash", but discard this commit's log message # x, exec <command> = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop <commit> = remove commit # l, label <label> = label current HEAD with a name # t, reset <label> = reset HEAD to a label # m, merge [-C <commit> | -c <commit>] <label> [# <oneline>] # . create a merge commit using the original merge commit's # . message (or the oneline, if no original merge commit was # . specified). Use -c <commit> to reword the commit message. # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. #
Initial lines show a list of all commits in feature branch, followed by commented commands/actions which can be performed on them.
pick to whichever action (
drop, etc) required. Action which require additional input will open another set of prompts with instructions for the same. The sequence of commits can also be changed here by moving commit up or down the list.
Rebase can also be used for squashing commits (in local branch) by following:
git rebase -i HEAD~3
3 is the number of preceding commits to be squashed into one.
The command, will open an interactive prompt, as shown in the interactive rebase section. Reorder commits, add
pick to a single commit (in which others will be squashed) and move it to the top. Add
squash before other commits. After saving, another prompt will open asking for a unified commit message. Edit, save and you’re done.
Caveats of rebase
- Don’t use rebase on public/shared branch (rebasing from it is fine). Also applies on pushed commits. Things might get messy.
- Rebase will present conflicts one commit at a time when merge will present them all at once, so choose accordingly.
- Reverting commits is a tad more difficult after rebases.