DEV Community

Cover image for Rewriting the history with Git rebase
Axel Navarro for Cloud(x);

Posted on • Edited on

Rewriting the history with Git rebase

As when we work in a new topic (feature or bugfix) it is recommended to keep our branch up-to-date with the target branch (main, development, etc.), we can use the git rebase command instead of git merge in order to keep our Git history clean.

💡 The Git documentation uses topic branch as a generic term for feature branch and bugfix branch, giving to branches like main, development, etc. the name of shared branch because are being used for multiple developers.

The git rebase command reapplies our commits on top of the target branch, rewriting the Git history. This is not recommended on shared branches because it causes divergence (and therefore the need of conflict solving) and panic on your teammates 😬 since it is sometimes hard to resolve.

The basics

To be clear about how git rebase works we're going to use the simplest example: you have 3 commits in your topic branch and you want to get the latest changes from main. To do so you can simply run the following command:

git rebase main
Enter fullscreen mode Exit fullscreen mode

If you're lucky to get no conflicts then you'll have a new Git history with your 3 commits on the top of the main branch and you just need to override (--force) the remote branch with your new history.

git push --force origin mytopic-branch
Enter fullscreen mode Exit fullscreen mode

But what if we have conflicts? Well, you're reapplying 3 commits so any of these could bring conflicts. Just resolve conflicts as always and then continue rebasing:

git add .
git rebase --continue
Enter fullscreen mode Exit fullscreen mode

Let's check a more dynamic scenario.

Squashing commits interactively

If you made several commits while you were preparing your work but now you want to combine your commits into one before creating the pull request then you can rebase against your target branch using the --interactive argument git rebase --interactive main. A git-rebase-todo file will be open in the default editor (nano, vim, etc.) where you can edit the commands that Git will execute to reapply your commits. Let's check this example:

pick 0680aa7 fix grid responsiveness
fixup 68ab202 fix unit tests
exec npm test
reword 76d14ac fix grid layout for iOS
exec npm test
Enter fullscreen mode Exit fullscreen mode

🧠 Thegit-rebase-todo file is a sequence of commands to be executed by Git, and you can run any shell command using the exec command.

The pick is used to take a commit as-is. The commit message is displayed by Git only to help you to identify what changes are there (Git will ignore if you edit it).

Then we have the fixup command, which combines a specific commit into the previous one without changing the commit message.

If the npm test fails you will see the following message:

warning: execution failed: npm test
You can fix the problem, and then run

  git rebase --continue
Enter fullscreen mode Exit fullscreen mode

Sad time when you need to fix the tests 😢. Before continuing the rebase you will need to commit these changes creating a new commit; or integrating there in the latest one using the classic git commit --amend.

git add .
git commit --amend
git rebase --continue
Enter fullscreen mode Exit fullscreen mode

The reword command that we put into the git-rebase-todo file will open your default editor (e.g. nano) with the current commit message for 76d14ac. Edit it and save to continue.

💡 The git rebase reapplies commits, you can do this without needing a target branch (main): just indicate how many commits you want to reapply for the current branch (HEAD). For our example of 3 latest commits:

git rebase --interactive HEAD~3
Enter fullscreen mode Exit fullscreen mode

🧠 Remember that HEAD is a pointer to either your current branch or your current commit when you're in a detached HEAD (meaning you are located in a commit not associated with any branch).

And, this is the usage of git rebase --interactive 🎉. Let's continue with the git rebase --exec.

Do you either prefer rebase or merge to keep your branch up to date? 👇 Let me know in the comments.

Conclusion

You can manipulate the commits in a useful way using git rebase, maybe just using it to keep your work up to date using a linear history, optionally combining your editions into one commit using fixup.

I hope this guide helps you understand more about Git and how to manipulate your commits safely because you can always git rebase --abort if the things aren't going how is planned.

In the following post of this series of git rebase we're going to see how to run tests for the rebased commits automatically. 😬

Top comments (0)