While working on a branch locally, it can become necessary to make minor
changes to older commits. For example, consider the need to fix a typo in
commit B in the following
$ git checkout -b feature # ... $ git commit -m "Add functionality" # A # ... $ git commit -m "Bind configuration" # B # ... $ git commit -m "Create handlers" # C o (master) \ A---B---C (HEAD, feature)
One way to do this is use of an Interactive rebase to
edit commit B.
$ git checkout feature $ git rebase -i master
pick aaaaaa Add functionality -pick bbbbbb Bind configuration +edit bbbbbb Bind configuration pick cccccc Create handlers
# On commit bbbbbb $ vim config.py $ git add config.py $ git commit --amend $ git rebase --continue o (master) \ A---B'---C' (HEAD, feature)
# On cccccc (HEAD, feature) $ vim config.py $ git add config.py $ git commit --fixup ":/Bind config"
":/Bind config"is short for “most recent commit with a commit message matching
Bind config.” See
man gitrevisionsfor more.
This creates a new commit with the message
fixup! Bind configuration.
$ git log ffffff fixup! Bind configuration cccccc Create handlers bbbbbb Bind configuration aaaaaa Add functionality o (master) \ A---B---C---F (HEAD, feature)
Queue up any number of such
fixup commits and run an interactive rebase with
--autosquash flag. The instruction list will place these commits in
their right places, ready to combine with their targets.
$ git rebase -i --autosquash pick aaaaaa Add functionality pick bbbbbb Bind configuration fixup ffffff fixup! Bind configuration pick cccccc Create handlers
Save and quit, and the old commit is all fixed up.
o (master) \ A---B'---C' (HEAD, feature)
This improves the process but it necessitates recalling the log message of the target commit. This can be more streamlined.
Tig is a command-line UI for Git. It augments the regular usage of
and has become my primary method of committing code.
Navigating Tig’s main view
Tig’s main view displays a list of commits for the current branch. Try it out:
tig, navigate to a commit with
k, and open it with
Inspect the commit. Move around with
Ctrl-U for page
down and up. Close the commit with
q and similarly inspect the other
Open the status view by pressing
s. Look around using the same keys as
before. Quit with
Partially staging changes with Tig
A productivity win of Tig right out the box is an easier to use method of
partially staging changes (versus
git add --patch).
To try it out, make changes in a repository and open the Tig status view by
tig status or by running
tig and pressing
s. In the status
view, navigate to a file (
k) in the Changes not staged for commit
section and open it (
Inside the file, navigate to a chunk (
k) and perform one of the
- Stage this entire chunk (
- Stage a single line in the chunk (
- Increase (
]) or decrease (
[) diff context
- Split the chunk (
\) and go to step 3
- Close the file (
Repeat for other files with uncommitted changes. Similarly unstage changes from files in the Changes to be committed section if necessary.
When ready, commit the staged changes from within Tig (
C in status view) or
Q) and run
Auto-squashing with Tig
Tig is configurable via a
~/.config/tig/config file. Among other things, it
supports introducing new key bindings that execute arbitrary
~/.config/tig/config file if it doesn’t already exist and add the
following to it.
bind main = !git commit --fixup=%(commit) bind main <Ctrl-R> !git rebase --autosquash -i %(commit)
Alternatively, add the following to
~/.gitconfig instead. This will have the
same effect as the changes suggested above.
[tig "bind"] main = = !git commit --fixup=%(commit) main = <ctrl-r> !git rebase --autosquash -i %(commit)
This introduces the following key bindings to the
=will create a new
fixupcommit for the focused commit
Ctrl-Rwill being an interactive rebase with auto-squashing enabled on top of the focused commit
To try it out, make changes in a repository and open
tig. Stage changes in
the status view (partially if necessary) and switch back to the main
In the main view, navigate to the commit to be fixed (
k) and create a
fixup commit by pressing
Queue up as many such fixes as needed.
When it’s time to apply the
fixup commits, navigate to a commit before the
oldest commit being fixed, and press
Ctrl-R to start the interactive rebase.
Adjust the rebase instruction list if necessary, save, and quit.
Edit: 2020-04-30: Add instructions for configuring via