Skip to content

Instantly share code, notes, and snippets.

@garfvl
Last active October 24, 2023 09:00
Show Gist options
  • Save garfvl/402cdc1c70ec2ba96b039a45c38832f2 to your computer and use it in GitHub Desktop.
Save garfvl/402cdc1c70ec2ba96b039a45c38832f2 to your computer and use it in GitHub Desktop.

Tig: Splitting a single-file commit the easy way

The problem

A common issue during a branch rebase:

  • merging multiple commits is pretty easy with the squash action
  • splitting a commit in smaller ones can be a pain in the *ss, especially if the changes are inside a common file.

An example of "to split" commit:

commit f626cfd75023b0e6ec4825a34617ee367ef0cf02
Author: Simon Latapie <garf@videolan.org>
Date:   Wed Aug 21 22:59:08 2019 +0200

    This commit has to be split

diff --git a/a_file.md b/a_file.md
index 50d91df..7ef7f4e 100644
--- a/a_file.md
+++ b/a_file.md
@@ -1,4 +1,13 @@
+# Let's add some title...
+
+## ...And some section...
 
 This is from a
-prevoius commit
+previous commit
+
+## And another section
+
+But in the future I will change my mind and will want to isolate this section in another commit
+
+## And This conclusion will go with the title

First, let's start the rebase

Find the commit hash and launch an interactive rebase

$ git rebase -i <commit_hash>^

Then change pick to edit or e, and save.

You are now inside the rebase workflow:

$ git rebase -i f626cfd75023b0e6ec4825a34617ee367ef0cf02^
Stopped at f626cfd...  This commit has to be split
You can amend the commit now, with

  git commit --amend 

Once you are satisfied with your changes, run

  git rebase --continue

Note: you can also use some tig shortcut to do that if you follow this guide.

Now, reset the state while keeping the changes:

$ git reset HEAD~
Unstaged changes after reset:
M	a_file.md

Split the changes: the academic way

Using the git add --patch during an interactive rebase edition will give you access to the "interactive" form that will let you split the diff into hunks, and stage only these parts of the commit:

https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging

But this is not very handy: to easy way to follow what's have been staged, per line selection is not easy, etc.

Split the changes: the tig way

Launch tig.

All the changes from the commit will be displayed in the Unstaged changes line.

Explore the Unstaged changes (Navigate with j and k keys), and select the diff lines you want to separate from the original commit with the 1 key.

All the lines you have selected will be displayed in the Staged changes line:

  • If you want to modify the staged changes: select the Staged changes line, browse it and press 1 key for each line you want to unstage.
  • If you want to cancel the staged changes: select the Staged changes line and press u key.
[main] Staged changes                                                                                100%
 a_file.md | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/a_file.md b/a_file.md
index 50d91df..93235c4 100644
--- a/a_file.md
+++ b/a_file.md
@@ -1,4 +1,7 @@

 This is from a
 prevoius commit
+## And another section
+
+But in the future I will change my mind and will want to isolate this section in another commit

When you are statisfied:

  • switch to status view by pressing s key (you can also check the staged changes in this view under the Changes to be commited section),
  • then press C (capital C) to launch git commit, and create your split commit
  • then press m to go back to the main view in tig

Finish the rebase process

Repeat the stage/commit steps until you have no more unstaged changes.

Then launch git rebase --continue to finish the rebase process.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment