Git and Visual Studio 2017 part 15 : Revise local commits
In previous article, I explained how to undo the commit you shared with others by using “revise”. In this article, I show you how to revise local commits before sharing with others. I couldn’t find a way to make this happen in Visual Studio 2017 though.
Revise commits in Git
If I simply want to change commit comment or add additional items into previously created commit, run commit command with --amend option. However, when I want to split the commit into multiple commits or combine multiple commits into one, or if I want to change commit comment of old commit, what can I do? I can use “rebase” to do it.
Rebase is explained in part 6 and that is to take changes from another branch to current branch as new base. But it has another usage, too. Let’s do it!
Combines multiple commits into one commit (squash)
1. Run ‘git log --oneline --graph --all’ to see current commit history.
2. To simplify the log, let’s reset back to old commit. Run ‘git reset --hard 3127d2f’ and ‘git branch -D dev’. Now I am at the commit right after added README.md.
3. Run ‘echo “Change 1” >>README.md’ and ‘git commit -am “Change 1”’.
4. Do the same for Change 2 and Change 3. Run ‘git log --oneline --graph --all’ to see history.
5. Let’s combine last three commits into one before I share them to others. Run ‘git rebase -i 3127d2f’. It may sound wired as you rebase to same branch. But the -i option give you an opportunity to revise your commits. In this case, I replay three commits from 3127d2f by revising them.
6. Change them like below. This means I take the first one as it is, then combine (squash) last two commits into the first commit.
7. Once I saved the change, git opens another editor window to let me write commit message. Change the comment as you want and save it.
8. Run ‘git log --oneline --graph --all’ to see the history.
Remove or change commits order
1. Run ‘git reset --hard b8c51a9’ to reset it, and ‘git rebase -i 3127d2f’ to restart rebasing.
2. Edit it like below. This will remove “Change 2” and reverse first and third commits.
3. Then you see conflict error. Run ‘git mergetool’ to resolve the conflict. I took both this time so that all lines remain.
4. Run ‘git rebase --continue’ to continue the rebase. Git opens editor to let me write commit comment. As I don’t have any intention to change it, I simply close the editor. Now it starts applying another commit and encounter conflict again. Resolve it by ‘git mergetool’. This time, I took both to keep all comment lines.
5. Run ‘git rebase --continue’. Again, it opens the editor to let me specify commit comments. This time I changed it. Save and close.
6. Run ‘git log --oneline --graph --all’. You see commits are revised. As these are new commits from Git point of view, they have different SHA1 hash.
Split the commit into multiple
Finally, lets split a single commit into multiple.
1. Run ‘git rebase -i 3127d2f’ to start rebasing again. This time, change it like below. To keep it simple, I split Change 3 commit and drop the last one. Save and close.
2. Git stops rebasing as I specify “edit”. Now it is time to split commits. As I only modify README.md, I use ‘git commit -p’ to decide which line to commit.
3. Now you are at right after commit 41a2065 is done. Let’s move back one HEAD back so that I can re-do the commit content. Run ‘git reset HEAD~1’, then run ‘git log --oneline’ and ‘git status’ to see current situation. I see many comments but simply put, I am on commit 3127d2f and README.md is not staged yet.
4. If I stage README.md as it is, nothing changed. Run ‘git add -p README.md’. This called patch mode and you can have granular control. Right now, Git considers three comment lines into single hunk.
5. Type “e” and enter which lets you manually change it.
6. Change it like this, so that it only contains “Change 1”.
7. Run ‘git status’ to see you have same file in staged and not staged area.
8. Run ‘git commit -m “Change 1”’. Repeat it two more time to create three commits like before.
9. Once you complete splitting the commit, run ‘git rebase --continue’, as we are in the middle of rebasing.
10. Run ‘git log --oneline --graph --all’. Now the first commit splits into three commits and removed the last commit “Change 1 after Change 3”.
Revise interactive options
As the comment above says, there are several options. See here for more detail.
Revise commits in VS
Visual Studio 2017 doesn’t seem to have interactive rebase capability at the moment..
Summary
At first, this was a bit confusing, but knowing the capability, you can commit locally more relaxing as we can tweak it later. DO NOT PUSH until you are ready !
By the way, Visual Studio Code has several capabilities which Visual Studio 2017 doesn’t have. One of such capability is to patch commit, so that you can simply select lines from a file and add to staging area. If you are interested in Git and Visual Studio Code, then I will consider writing it in the future. Go to next article.
Ken