Skip to content
/ fixdown Public

Let `git commit --amend` reach into the mists of time

License

Notifications You must be signed in to change notification settings

brasic/fixdown

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 

Repository files navigation

fixdown

Let git commit --amend reach into the mists of time


Installation

Copy into your $PATH.

What's this?

One git workflow I use involves frequently rebasing. After a messy initial phase I have my PR shaped into roughly the commits that tell the story of the change I'm making, and hopefully made it as reviewable as possible, for example by cabining less interesting commits that mostly consist of vendored or autogenerated files into their own commits that can be ignor^H^H^H^H^Hcarefully given specific attention.

$ git log --oneline
5e6ccba Paperwork
06fb676 Deal with butterfly-effect test failures
51d0d53 Add metrics and deploy safety valves
6d08e46 Use the new useful thing in various places
f6c893f Introduce something useful
e16fcb4 Scaffolding and vendored files

Often this phase ends up lasting longer than expected, and I need to make many changes to basically all of these commits. Since I care about my carefully crafted commit log, of course that means I'm going to use git-rebase to apply those changes to the original commits so I don't end up asking reviewers and archaeologists to wade through something like

$ git log --oneline
3032029 total refactor
ed8d317 autocorrect everything
dda23ca wip
5c20c2f I love linters
9bdd483 Does it work now?
c75cde8 Once more
1a37271 Try to fix a test
e16fcb4 Nicely crafted commit

Commits like those are often a necessary part of the development process, but IMHO they don't belong in the final PR. So I rebase them away once they've settled.

Unfortunately if you're not careful doing this a lot can distort the original commits and cause many git conflicts, especially if you're changing files that have a lot of upstream activity that you're also integrating with rebase. You make things a lot easier on yourself if you use the --fixup option when committing and then --autosquash when rebasing to apply each fixup on top of the most recent change to that file.

$ git commit --fixup 06fb676 test/   -m 'few more test fixes'
$ git commit --fixup e16fcb4 vendor/ -m 'upgrade dep to latest version'
$ git commit --fixup f6c893f src/    -m 'comment typo in main change'
$ git commit --fixup 06fb676 test/   -m 'o no more tests'
$ git rebase origin/main -i --autosquash
  1 pick e16fcb4 Scaffolding and vendored files
  2 fixup 0000389 fixup! Scaffolding and vendored files            # upgrade dep to latest version
  3 pick f6c893f Introduce something useful
  4 fixup 0000389 fixup! Scaffolding and vendored files            # comment typo in main change
  5 pick 6d08e46 Use the new useful thing in various places
  6 pick 51d0d53 Add metrics and deploy safety valves
  7 pick 06fb676 Deal with butterfly-effect test failures
  8 fixup 05c38c8 fixup! Deal with butterfly-effect test failures  # few more test fixes
  9 fixup 05c38c8 fixup! Deal with butterfly-effect test failures  # o no more tests
 10 pick 5e6ccba Paperwork
 11
 12 # (10 commands)
.git/rebase-merge/git-rebase-todo [unix GITREBASE] [0001,0001,1][10%]
:wq
Successfully rebased and updated refs/heads/topic.

After that rebase, all the fixups are still there but my original commit structure is still intact.

This is a fun workflow! It feels like a generalization of repeatedly fixing things with git commit --amend --no-edit ., which I'm also a big fan of.

So that works great, but it's kind of annoying to keep tracking down what the most recent commit to have modified a file so you can pass it to --fixup. This script automates that process: for each modified file in your working tree it creates a single commit marked as a fixup of the last commit which modified that file. Doing this lets you flush all the pending changes in your tree as amendments to the relevant commits in just two commands with a guarantee of no conflicts (unless they came from upstream):

$ fixdown
# [info about commits being made]
$ git rebase --autosquash origin/main
# all done 🎉

About

Let `git commit --amend` reach into the mists of time

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Languages