git-town
git-town copied to clipboard
"git town compress --all" command
- [ ] runs #1529 for all local branches
- [ ] option
--currentalways accepts the current version in case of merge conflicts
Would this command also be useful for cleaning up the merge history on a chain of dependent PRs that are continually in development?
In particular, if I've always got a child PR open, then that child PR will continually carry the messy merge history of all PRs before it. At some point, I'd like to just reset this history and force push (in the case of GitHub) so that when I run git log, I've got a clean history on the PR chain.
I'm assuming that this feature would essentially git rebase -i each PR in a chain. If it was just one PR without any children, I could just do the git rebase -i myself, but if there are children, then the subsequent rebase gets messy because I need to refer to a now-deleted reference for the parent. If I was tracking all the Git hashes during this process, it would be straightforward to perform each git rebase -i, so overall, this seems like it wouldn't be too hard to implement within git town.
Actually, the flow might not be as hard as I was thinking. If the goal is to just squash each GitHub PR into 1 commit within a chain, then it could look like this:
Assuming this hierarchy:
- main
- feature-1
- feature-2
git checkout feature-1
git reset --soft main
git commit -a -m"New Feature-1 comment"
git push --force
git checkout feature-2
git reset --soft feature-1
git commit -a -m"New Feature-2 comment"
git push --force
A huge caveat here is that these commands are highly destructive, so it would be good to track all the previous Git Hashes to enable a robust "Undo".
A quick note about using git rebase -i: I've found that when dealing with lots of squash-merged parents, git rebase -i tends to force me to deal with lots of merge conflicts that aren't actually real conflicts, but are rather a side-effect of Git not understanding the squash-merged commits to main. For this reason, I sometimes just declare commit bankruptcy and use the git reset --soft parent && git commit -a -m "..." flow. If the PRs are already small in scope, then the value of these intermediate commits is somewhat diminished.
Thanks for sharing the -a switch for git commit, I wasn't aware of it!
The plan is to use git push --force-with-lease. With it, the commit compress will still be highly destructive, but should never destroy anything.
You are right that rebasing too much leads to problems. That's why the sync-feature-strategy defaults to merge. This saves a lot of headaches and all the ugly temporary commits get squashed away when shipping or squash-merging the branch.
That --force-with-lease option looks interesting, and does appear to provide a lot more protection than a naked --force!
I'm definitely a big fan of using merge as the default sync strategy because of it's relative safety, but also the volume of merge commits on the PR chain increases with something like O(N*M) with N as the length of the chain and M as the number of other commits to main during development.
In some sense, though, this really just boils down to weaknesses in the git log command. If I had an equivalent --graph view that ignored the noise from the merge commits on feature branches, then I would almost never bother using something like compress!
I agree the merge strategy leads to lots of commits in PRs. I often end up with several hundred commits in my PRs. It's not a problem for me since I never look at individual commits. I mostly look at the changes a PR makes.
I think you could create a tool that displays the same information as the Git log or graph command but filters out the merge commits as well as the commits that these merge commits bring in from the parent branch. If it's useful, such a command could be integrated into Git Town since Git Town knows the parent branch of each branch.
I actually find the merge commits helpful. They help distinguish when a feature branch was last changed vs last synced. Let's say I have an old branch that I committed to three months ago. If I merge-sync it, the commits in the branch are still three months old and there is a new merge commit. This tells me its an old branch that was synced recently. If I rebase-sync the same branch, the commits on the branch are now all rewritten to be recent, and the information that this is an old branch is lost.
Also, when I see a feature branch with tons of merge commits in it, I know it's been around for a long time and has been synced a lot. This tells me that the chance for merge conflicts that were poorly resolved is higher, so I look more for them. Also, that it's time to merge or delete this branch since it's getting old!
Git Town's undo is pretty robust. It takes a snapshot of all branches and their SHA before and after Git Town runs and then calculates the diff between the before and after state. Undoing a command means simply re-creating all the branches that existed before the command ran and pointing them at the right SHA. I'm pretty confident that this would cover the compress use case.
Would it be possible to have an option to auto-compress commits when syncing stacks? That would help nicely with #3236 and the new rebase sync strategy behaviours introduced in v13!
That's a really cool idea! I have created https://github.com/git-town/git-town/issues/3320 to track it's implementation.