Background
As software engineers, we have always been looking for better ways to manage our codebases. We have used different source control systems like Git, and we may need advanced techniques from time to time to resolve some new issues we face, specially when working on bigger software solutions with huge codebases.
One such situation is when we need to re-write Git history of a repository for any reason including:
- update (amend) a commit message
- remove (drop) a specific commit
- combine (squash) some commits with a specific commit
- re-order commits
Let's do it!
Hands on terminal
We can create a new Git repository and add some files and make some changes in those files and then make some commits. Suppose we need to update the last 7 commits (crazy I know!). Let's run this command:
git rebase -i HEAD~7
This will open an interactive window where we can choose the proper action to apply to the repository history. Note that Git adds the commit messages in reverse order, so commit 11454df test something!
is actually our last commit:
pick 58bc9d0 file.txt created
pick 121c507 file2.txt created
pick 64a2c99 file2.txt updated
pick 2ef342a file2.txt updated step 1!
pick e84f687 file2.txt updated step 2!
pick 16c8448 file2.txt updated step 3!
pick 11454df test something!
# Rebase e84f687..11454df onto e84f687 (7 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
# d, drop <commit> = remove commit
#
# REMOVED FOR BREVITY
You will see we have a couple of options to choose including:
- select (pick) the same commit
- update (reword) a commit message in-place
- update (edit) a commit message (This will open another window to edit the commit message)
- combine (squash) commit messages
- remove (drop) a commit
All we need to do is select the required action (e.g. pick
or squash
) and replace the current pick
actions with the new action:
reword 58bc9d0 file.txt created and updated
pick 121c507 file2.txt created
pick 64a2c99 file2.txt updated
squash 2ef342a file2.txt updated step 1!
squash e84f687 file2.txt updated step 2!
squash 16c8448 file2.txt updated step 3!
drop 11454df test something!
#
# REMOVED FOR BREVITY
After saving the above (e.g. using :wq
in vi
), as we asked Git to squash some of our commits, it will open another window so we can finalize the commit message:
# This is a combination of 4 commits.
# This is the 1st commit message:
file2.txt updated
# This is the commit message #2:
file2.txt updated step 1!
# This is the commit message #3:
file2.txt updated step 2!
# This is the commit message #4:
file2.txt updated step 3!
# Please enter the commit message for your changes.
#
# REMOVED FOR BREVITY
We can update this to have our desired message (e.g. remove all except file2.txt updated
) or we can save it just as it is. Note that lines starting with a hash #
will not be added to the final commit message.
Now if you run git log
, you will see the applied changes which are:
- update the message of the 1st commit
- retain the 2nd and the 3rd commits
- squash the 4th, 5th and the 6th commits into the 3rd commit (This opens another window so we can make the final change)
- remove the 7th commit
Note that instead of squash
we could choose fixup
for commits we want to combine and Git would choose the message of the pick
commit before those commits (i.e. 64a2c99
) as the final commit message for the combined commits.
Also, for re-ordering commits, we can simply change the line arrangement of the commits and put a specific commit before or after another commit:
pick 121c507 file2.txt created
pick 58bc9d0 file.txt created
Happy coding!
Top comments (0)