tl;dr: If you interactively rebase to clean up a PR, GitHub displays all your commits in the wrong order and wastes everybody's goddamn time. Fix it like this:
git rebase -i <PARENT SHA> -x 'sleep 1 && git commit --amend --no-edit --date=now'
Explanation:
Git commits have a natural order defined by parent/child relationships. (Gets ambiguous with merge commits, but never mind that for now.)
GitHub's pull request interface does not use that natural commit order. It orders commits by their author date, which is arbitrary metadata attached to each commit. (Commits also have a committer date, which usually tracks the commit order more closely.)
Well, using a wrong-ass order is fine as long as you're not actually doing any work. But if you're trying to divide a big change into legible units for your reviewers, you're probably using interactive rebasing to rewrite your commit history. And git rebase -i preserves the original author date for any commit that you move (or reword) but don't completely disintegrate. So something like this happens:
WIP:
- Commit 1: Do Easy Thing.
- Commits 2-26: Flail around, eventually accomplish Hard Thing.
- Commit 27: Remove bad old code that's unnecessary thanks to Hard Thing.
Cleaned up for review:
- Commit 1: Easy.
- Commit 2: Backend part of Hard.
- Commit 3: Frontend part of Hard.
- Commit 4: Cleanup.
On GitHub: 🌋
- Commit 1: Easy.
- Commit 4: Cleanup.
- Commit 3: Frontend part of Hard.
- Commit 2: Backend part of Hard.
GitHub has a help page about this that is singularly useless and wrongheaded, basically explaining that you are incorrect for caring about cause and effect. Okay!!
Most of the fixes I found seemed clunky; for example, this guy just manually edits every commit. But as he points out, a proper fix HAS to be clunky, because if it goes too fast you get multiple commits per second and then the order is random. (Which is why my attempt of git rebase <PARENT> --onto <PARENT> --ignore-date didn't do shit!)
But rebase -i has an --exec flag for automating edits, which means you can get at least one second between commits with just a one-liner! Which, again, is:
git rebase -i <PARENT SHA> -x 'sleep 1 && git commit --amend --no-edit --date=now'
That's basically a shortcut for adding an exec ... line after every step in the plan produced by a normal git rebase -i; it'll still open the plan in your editor, and you can close the file to confirm. Also, note that there's an implicit git rebase --continue that happens after an exec step, so you don't need to handle that part yourself.
no subject
Date: 2020-05-23 02:23 am (UTC)no subject
Date: 2020-05-24 12:14 am (UTC)