Home > other >  How can I check that commits stay in author date order?
How can I check that commits stay in author date order?

Time:02-25

Motivation

Let's say we have these commits (most recently committed on the left):

E-F-G-H-I-J-K-L-M-N

We want to release E on another branch, so we cherry-pick it, but a conflict arises and we discover that we need J as well. We take J but still have conflicts so we take M as well, which E depended on in a different way than J. Then it works. Our history on the new branch is now:

E-M-J

The obvious downside here is that the commits aren't ordered in the same logical way they were before, seeing E-J-M as a feature embedded in the longer history. One solution is to reorder git commit history by date. However, rebasing activity on the original local branch may mean that J actually has an author date that is before M. At worst, an interactive rebase to re-sort by author date may not even work if e.g. we needed K-L (in that order, because K depends on L) but L has an author date after K.

One solution is to manually modify author dates when you run into this issue, but that's not the focus here.

Edit: Why prefer E-J-M?

Many comments seem to focus on the motivation, so perhaps it is worth expanding on.

Let's say you cherry-pick E on top of M-J and it doesn't work (conflicts). Now you need to go find the commit you're missing, and cherry-pick it into the right place. If it's L, then L-M-J may create an unnecessary conflict when J-L-M would not have. In the real example there are more than 50 commits.

It's also significantly easier to read commits in a history that were done in the same order as they were done in reality, especially over months of potentially different projects. If the new E-M-J branch is going to e.g. pass all tests (as well as not create conflicts) you need to make sure you didn't miss any bugfix commits in {F, G, H, I, K, L}. Keeping commits in order helps you keep track of what commits you've reviewed for inclusion.

Question

I'd like to check that before every push all commits are in author date order (at least relative to the last pushed commit). I'd probably put this in a pre-push hook. Is there a simple way to run this check? Perhaps it's hard if the branch doesn't have a remote yet?

It may also help to ensure the new author dates are all after the author date of the "last pushed commit" but perhaps that's a different question.

CodePudding user response:

I think you need to make a decision about what the new branch is. You stated:

Our history on the new branch is now...

What is the relationship of that new branch to the other one? Is it a new separate development line that should never be merged again? If:

  • Yes: then who cares if the commits are in a different order than some unrelated older branch!
  • No: then why cherry-pick at all? Just branch off the other branch and "have it all". You're going to be merging again in the future anyway and might as well keep it as up to date as possible by "rebasing onto", or "merging in" the original branch.

Tips:

  1. IMHO best practice would lean towards the latter option of merging instead of cherry-picking, whenever possible.
  2. If you still end up cherry-picking, and if you will have the new different commit IDs in the repo long term along with the source commits, I'd recommend using the -x option to append the original commit ID to the commit message. This way when someone sees it, it's more obvious that this came from another commit somewhere else in the repo that likely had different context, which they could go look at if they wish.

CodePudding user response:

Just redo the new-branch construction. Once you've found all the commits you need to cherry-pick to get the results you want, go back and cherry-pick them in the order you want.

What you did to discover all your dependencies:

git cherry-pick E
test test # fails
runaround checking # discover M
git cherry-pick M
test test test # fails again
runaround checking some more # discover J
git cherry-pick J
test test test # success

Now you know what you need, but your first-draft history is disorganized. So do a rewrite-and-cleanup pass to make the publishable history you want:

git reset --hard E^
git cherry-pick M J E

and publish that.

To detect out-of-order commits,

git log --first-parent --pretty=%H\ %at\ %as | sort -cnr -k2

That's "check that the second field (%at, the author timestamp in seconds-since-epoch) is in reverse numeric order".


Many projects do the record-keeping you're after with branch-per-feature histories, merging features only when they have presentable, publishable histories. This way Git already keeps, and publishes, and automatically uses the records you're currently managing with your less-accessible sideband notes, and your question shows the cost of concealing the real structure of your history from team members and from Git.

  • Related