When I first wrote this I was unaware of git commit --squash
. This
feature provides similiar functionality to that provided by the
scripts in this repository.
git-squash
is useful when you want to squash an already existing
commit into another commit. git-squash-files
has no analogue in the
current git
distribution.
When iterating a patch-set, I often find myself squashing with
git-rebase -i
. For instance, say you have a repository that looks
like this,
A <-- B <-- C
^
HEAD
You find a silly mistake in B
, which you correct in a new commit D
yielding,
A <-- B <-- C <-- D
^
To produce a clean revision history (or to hide your silly mistake),
you'd want to absorb D
into B
to produce,
A <-- B+D <-- C
^
To do this with git rebase
, you'd need to run git rebase -i A
,
look through a list of commits, find D
, move it after B
, changes
its flag to squash
, save, and exit. This kills time.
Enter git squash
,
$ git squash D --into B
Squashing multiple commits is trivial,
$ git squash F Z D --into B
git-squash
will automatically put F
, Z
, and D
into topological
order before squashing to minimize the chance for conflicts.
Say you are working on you pet project one afternoon and add a lovely
new feature to turtle-feeder.c
. Confident in your work, you move on
to add more lovely features elsewhere in the repository without
testing (since bugs never happen, right?).
Several hours of hacking and numerous finished features later, you go
to test your day's work. It doesn't take long to realize that you
introduced a trivial bug into turtle-feeder.c
, which you handily fix
and commit. Being a strong believer in clean revision history, you
want to absorb this fix into your original commit.
Previously this would have involved using git rebase -i
and
squashing the fix into the original commit. git-squash
described
above makes this process slightly easier,
$ git squash FIX --into=ORIGINAL
But this of course assumes that you know the commit id of ORIGINAL
.
This seems silly; in all likelihood ORIGINAL
is one of the last
commits to touch turtle-feeder.c
. Why can't git
just do what you
want?
git-squash-files
does just that,
$ git squash-files HEAD^..HEAD
Choose a commit to squash
d210978 silly turtle-feeder fix
into,
1. 7797f05 turtle-feeder: introduce new feature
2. 2c6ba60 turtle-feeder: don't feed twice on saturday
3. a849213 Various fixes
4. 4ff91b1 turtle-feeder: initial commmit
0. Skip this commit
[1]? <Enter>
Squashed d210978d7c077cb99954898c8890958a7bdfba15 into 7797f05af13897a9a588cc076dc2b163ff7d94d7
$
In particular, git-squash-files
iterates through each of the commits
in the given range and for each one,
- Ensures that the commit touches only one file
- Finds the recent commits which touch this file
- Prompts the user to select one of these to squash into
- Uses
git squash
to squash the commit
To install, just use the included makefile,
$ sudo make install
Optionally, define the DESTDIR
variable to specify a different installation
root (default is /usr/local
).