Git rebase has an interactive mode which helps you in rough times while working with git. You might come across situations where you have to alter what you’ve already committed. Interactive rebase provides us with tools and functions which helps us to do such things. Let’s do a quick recap of what rebasing is. By now we know that rebasing re-base our local commits on the top of commits done in the base branch. And due to this the commit hash value changes and it act as a totally new commit with same changes as in earlier one. Hence, we shouldn’t rebase any public branch. That’s just to get a rough idea about rebasing. For more detailed insight you can refer here.
Rewriting the commit history
Interactive rebasing helps you to rewrite your commit history in case you find that you committed something wrong or some previous commit required more work to be done before committing. To tackle and get out of these problems, we have this magic wand in our hand. So, let’s know how can we use it.
Let’s create few files in our git repo(You know how to do it, right?). First create a file with name first.txt with the following content in it
This is the first file in this repository.
and then we add the changes to staging area. And finally commit it as
git commit -m "Add first.txt"
After this create another file with name second.txt with the following content in it
This is the second file in this repo. This content needs to be deleted. We'll do it later
And commit it as
git commit -m "Add third.txt"
Yeah, I know the file name is second.txt but I have done it intentionally. We’ll correct it later. Just keep reading. 🙂
Finally create the actual third.txt with the following content in it:
Yeah! this one is the last file.
and commit it as
git commit -m "Add actual third.txt"
At last, enough preparing. Now is the time to use our magic wand. As of now, our commit history looks like this
d6f128b Add actual third.txt b2d48ff Add third.txt e57559a Add first.txt
What? You also want to see your commit history like this instead of that long output of git log! Ok let me tell you then, I just used few options which git log supports
git log --pretty=format:"%h %s"
To get to know more about such options, do give a read to this.
Now we want to correct the content of our second file and then commit it with correct commit message. For that we can use git rebase as
git rebase -i HEAD~2
Ok. Let’s first understand what does this command mean? For interactive mode we used -i option, short for –interactive. And then we give the number of commits we want to consider. As we know, HEAD always refers to the latest commit of current branch by default. So, to take 2 commits from HEAD(since the second commit from HEAD needs to be corrected), we used ~ symbol. When you’ll hit enter, a text editor would open with following content
pick b2d48ff Add third.txt pick d6f128b Add actual third.txt # Rebase e57559a..d6f128b onto e57559a (2 commands) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # d, drop = remove commit # # 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. # # Note that empty commits are commented out
The last two commits would be shown in older to newer fashion. Git is smart enough to explain you the various options which can be applied to each commit. By default each commit is marked with pick command. If you leave a commit with pick command, it just applies that commit as it is.
In our case we want to edit our first commit in the list, if you see the list of options available, can you guess which option should we use? Yup, you are correct, we would need to use the edit option. We can also use it’s short form ie ‘e‘ as
e b2d48ff Add third.txt pick d6f128b Add actual third.txt ...
Now, as you’ll save the file, you would see a message as
Stopped at b2d48ff... Add third.txt You can amend the commit now, with git commit --amend Once you are satisfied with your changes, run git rebase --continue
So what exactly happened? Let’s understand it, rebase starts to take each commit one by one in the list and performs the command defined against them. In our case, the very first commit in the list comes up with the ‘e‘ option, which says rebase to stop at this commit until user tells it to continue. And as expected it stopped at the commit. Now if you do git log as
git log --pretty=oneline
and it would give you the output as
b2d48ff1ba706f9751bd950e17355a9fb9a3fd99 (HEAD) Add third.txt e57559a96cd0c5b9f2ef4e2dccbcf6f20b3b11d4 Add first.txt
You can see that now our HEAD is at the commit at which rebase stopped. Now we can edit this file. So open second.txt and delete the last two lines. It would be now
This is the second file in this repo.
and then add the changes. Since its commit message was also incorrect, we can correct it now using the –amend option. With this option we can amend the commit refer by HEAD. Since our HEAD is at the second commit, we can now amend it. For that write the following command
git commit --amend
And hit enter, it would open a text editor with the previous incorrect commit message. So we can correct it now and save that file. Now our commit message has been amended. You can check that using git log command. Now do git status
interactive rebase in progress; onto e57559a Last command done (1 command done): edit b2d48ff Add third.txt Next command to do (1 remaining command): pick d6f128b Add actual third.txt (use "git rebase --edit-todo" to view and edit) You are currently editing a commit while rebasing branch 'master' on 'e57559a'. (use "git commit --amend" to amend the current commit) (use "git rebase --continue" once you are satisfied with your changes) nothing to commit, working tree clean
git tells us that interactive rebase is in progress. It means that there are other commits yet to be processed and it also tells you the next command which is going to get execute. So simply do git rebase –continue to continue the interactive rebasing and then it would show you the message like
Successfully rebased and updated refs/heads/master.
Now again look at the git log, in my case it is
9259ca9 Add actual third.txt 7092e07 Add second.txt e57559a Add first.txt
You might have noticed that the hash value of first two commits now has been changed. You know it, right? Yes, it’s because rebasing replays each commit and gives it a new hash value.
Now you know the procedure it follows. Let’s look at other available options rebase provides.
Indeed, squashing is one of the most used technique used by many contributors and anyone who works with git. In simple words, squashing squashes more than one commit into a single commit. Let’s try it. Suppose we want to squash the first two commits in one in our above example. We’ll again give the same command for interactive mode. Can you write it without scrolling above? Nice. Now the text editor would open with following content
pick 7092e07 Add second.txt pick 9259ca9 Add actual third.txt ...
You just need to write ‘s‘ option. write it as
pick 7092e07 Add second.txt s 9259ca9 Add actual third.txt
And then save the file. As soon as you’ll save the file, another text editor would open. It would contain the commit messages of both the commits as git doesn’t know which commit message to take. Either you can keep any one of them or you can rewrite a new commit message. After writing the commit message, just save the file and it’s done. You just squashed your commits in one. Now my commit history looks like this.
b805b0a Add second.txt and third.txt e57559a Add first.txt
If you see the options in rebase text editor, you’ll find this also. fixup is also used to squash the commits together. Then what’s the difference between the two? Well, it’s simple. fixup discards the commit message of the commit on which it is applied. Just this. You just have to use ‘f‘ option instead of ‘s‘ for it.
Well, if you want to correct the commit message of the latest commit, you can use –amend option. But if you need to correct the commit message of previous commits, just use ‘r‘ option for whichever commit’s message you want to correct. As one by one it would take commit and as soon as it reaches at the commit with option ‘r’, you would land into another text editor where you can correct it and save the file. And rebase would continue by itself.
If you want to remove a commit from your commit history, then use ‘d‘ option short for drop and it would be removed. Do notice that the changes will remain there, just the commit would be removed from your history.
If you want to re-order your commits, then just change their position in the rebase text editor. And it’ll be done. So easy, isn’t it?
We just used edit option in the initial example. It is used in case you want to stop at some particular commit and perform any action on that commit specifically.
These are the some of the most helpful functions while using git. You’ll most often come across using these. However, there are some facts which I’ve experienced and can confuse you if you go with default options.
- git rebase -i ignores merge commits until and unless you use the flag ‘-p‘ abbreviated for –preserve-merges. For more details, you can refer to this answer on stackoverflow.
- You can’t rebase the initial commit of your repository. So, in above example if you would try replacing HEAD~2 with HEAD~3 in order to get all the three commits in rebase it would give you the error as
fatal: Needed a single revision invalid upstream 'HEAD~3'
Since the 3rd commit is the root commit of our repository. If you want to change the root commit of your repository and want to know about it then you can refer to this answer on stackoverflow.
And yes, I again want to focus on the part that rebasing changes your commit history. So, you should never rebase a public branch. That’s all from my side.
I hope this would be helpful. I am still a newbie with it. So, if you find any correction or doubt then don’t hesitate to write in the comment sections below. Meet you soon.
Till then, be curious and keep learning!