git Second Order History

38 views Asked by At

When working on a patchest, I'm expected to provide a set of clean commits. Therefore I often find myself rewriting history repeatedly before my commit-set is clean and ready to be merged.
In this process, after receiving comments from reviewers, I go back with rebase -i to fix my code, fix the commit messages etc. Each time a new revised commit is created to replace the previous one. The previous commit is still out there but is no longer part of the revised history.

After a few history-rewrite iterations I finally get a clean revised commit-set that I can push or convert to a patchset. But now I sometimes like to go back and review the history of changes I did to a commit or set of commits and see what I have done in this history-rewrite process.
I could track it manually - write down somewhere the commit hash of every commit I'm editing before it's rewritten. That way I could review the history of history-rewrites, but this is tedious and error-prone.

Is there a way to automate this and let git itself track the "second order" history - the history of history-rewrites? Get a git log' for a commit that would show all the "amend" operations performed historically to generate that commit?

1

There are 1 answers

0
torek On

There's no such thing as:

the history of modifications of a commit

as commits themselves are literally unchangeable. History rewriting doesn't change the old commits: instead, it makes new-and-improved commits, which you are now using instead of the old commits.

What you can do, to some extent, is to use the reflogs to find the hash IDs that various names (branch names for instance) used to claim as the most recent commit, and use git rev-parse to find the hash IDs they now claim. Then use git rev-list or git log to find commits reachable from the current branch tips.

This has some rather strong limitations. If you've always replaced old-and-lousy commits one-for-one with new-and-improved commits, it's easy to say that branch~5 is the replacement for branch@{1}~5 for instance. But if your history rewrite ever adds or deletes a commit during the rewrite, there's no easy correspondence here.

The other thing you can do, depending on your history rewriting tools, is to keep a mapping file or database. If you have a mapping that says "old commit hash H = new and improved hash H'", for every replaced commit, along with mappings such as "old hash H was deleted" or "new hash H is inserted between old hashes G and I" where appropriate, that will let you do what you want.

In general, however, this is an unsolvable problem. Git does contain something called git range-diff that works on a different variant of the problem: it compares diffs of some known sets of commits—you'll need to save the start and end point hash IDs—and describes the difference between those diffs as "old patch 1 was modified to become new patch 3", "old patch 2 was deleted", "old patch 3 became old patch 1", "new patch 2 inserted", and so on.