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
One way to do this is use of an Interactive rebase to
$ git checkout feature $ git rebase -i main
pick aaaaaa Add functionality -pick bbbbbb Bind configuration +edit bbbbbb Bind configuration pick cccccc Create handlers
Edit the commit
An improvement upon this is use of the
--autosquash flag for
git commit --fixup,
it enables queuing up fixes to older commits.
# On cccccc (HEAD, feature) $ vim config.py $ git add config.py $ git commit --fixup ":/Bind config"
This creates a new commit with the message
fixup! Bind configuration.
Queue up any number of such
fixup commits and run an interactive
rebase with the
The instruction list will place these commits in their right places, ready to
combine with their targets.
Save and quit, and the old commit is all fixed up.
This improves the process but it necessitates recalling the log message of the target commit. This can be more streamlined.
2. Using Tig
Tig is a command-line UI for Git.
It augments the regular usage of
git, and has become my primary method of
2.1. 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 j/k, and open it with
Inspect the commit. Move around with j/k, or Ctrl-D/Ctrl-U for page down and up. Close the commit with q and similarly inspect the other commits.
Open the status view by pressing s. Look around using the same keys as before. Quit with Q.
2.2. 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 running
tig status or by running
tig and pressing s.
In the status view, navigate to a file (j/k) in the
Changes not staged for commit section and open it (Enter).
Inside the file, navigate to a chunk (j/k) and perform one of the following:
Stage this entire chunk (u)
Stage a single line in the chunk (1)
Increase (]) or decrease ([) diff context
Split the chunk (\) and go to step 3
Close the file (q)
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 quit (Q) and run
3. Auto-squashing with Tig
Tig is configurable via a
Among other things, it supports introducing new key bindings that execute
~/.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-R will 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
Stage changes in the status view (partially if necessary)
and switch back to the main view (q).
In the main view, navigate to the commit to be fixed (j/k) and
create a new
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
Adjust the rebase instruction list if necessary, save, and quit.
By providing convenient methods of partial staging with auto squashing, Tig streamlines the process of fixing up older commits. It’s a valuable addition to the toolbox for anyone who uses Git.
Edit(2020-04-30): Add instructions for configuring via