Rewriting your (git) history
Tags: git, productivity
Published: 2019-08-02 04:01:25

So you probably know a lot of basics of git, but if you have been using it for a while you have probably encountered a situation where you want to change a commit that's already been pushed. Some argue this is bad practice, and others say it's bad to have an unclean commit history. Although I probably lean more towards the latter, this post is simply about the tools you can use if you want to change some of your already pushed commits

## 1. Change most recent commit message
```
git commit --amend
```
If you have been using git for a while you probably already know about this one. It's generally used to change your most recent commits message if you found a type or wanted to change your commit message layout. It can also be used to changed the author by appending `--reset-author` to the amend

# The interactive rebase
For these examples, I am going to be using 3 commits I have created (see below) and all of these examples first involve the interactive rebase command:
```
git rebase -i HEAD~3
```
This will lead you to a terminal output that looks something like this:
```
pick 74c349f [1] Dummy commit 1
pick f490852 [2] Dummy commit 2
pick 717eaa6 [3] Dummy commit 3

# Rebase b8d17a8..717eaa6 onto b8d17a8 (3 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.
```

I will use this as the basis for the rest of the examples

## 2. Squashing commits
Squashing commits is useful if you have some related commits that could be merged into one larger commit, or in some cases, used to make code reviews easier

To squash the commits simply replace the word `pick` with `s` for commits 2 and 3 to merge them both into commit 1.
e.g.:
```
pick 74c349f [1] Dummy commit 1
s f490852 [2] Dummy commit 2
s 717eaa6 [3] Dummy commit 3
```

This will lead you to a new commit where you can edit/merge the commit message after you save and exit the commit message. After saving your commit message you should be able to `git log` and see your changes all in one commit

## 3. Changing an old commit message (reword)
If I wanted to change the message of commit 3, i would do:
```
pick 74c349f [1] Dummy commit 1
r f490852 [2] Dummy commit 2
pick 717eaa6 [3] Dummy commit 3
```
Then continue on like a normal `git commit --amend`

## 4. Dropping a commit
If you are dropping a commit, be extra careful about the contents and consider squashing instead. However if you really want to delete a commit, just use the drop command. e.g.
```
pick 74c349f [1] Dummy commit 1
d f490852 [2] Dummy commit 2
pick 717eaa6 [3] Dummy commit 3
```

This will delete `[2] Dummy commit 2` from your commit history and the changes along with it

## 5. Editing a commit
If you want to add or remove a file/change from a previous commit, you can use the edit functionality. For example, if you added a file but it should actually belong in the previous commit, you would do:
```
pick 74c349f [1] Dummy commit 1
e f490852 [2] Dummy commit 2
pick 717eaa6 [3] Dummy commit 3
```
Then you can add/remove files as you wish. Once you are done, then use the `git commit --amend` command, followed by a `git rebase --continue`

This can also be used to split a commit in two. As an example, if you follow the above edit step, and want to add a new commit before it you would do the above and then:
```
git reset HEAD^
```
From here to you add the files you would like, and create new commits. Then when you are done, execute the `git rebase --continue` command

------

Thank you for reading, and I hope this clears up some of the interactive rebase functionality