We introduced php-cs-fixer into our codebase and I want to rebase an existing feature branch. We enforce a semi-linear history, so every feature branch is rebased before merging without squashing the whole branch.
To keep the history clean I want to run the tool on every commit in the branch, but keep the commits in place and not have the code style change with a later commit, but already be correct in every commit that will later be merged into the main branch.
Using git rebase --exec "./vendor/bin/php-cs-fixer fix" main results in a lot of conflicts that I don't want to fix manually, as it is very error-prone.
I came up with this semi-automatic approach:
I started with
git rebase -i mainand replaced everypickoperation with aneditoperation. (Vim::%s/pick/edit/)Instead of conflict resolving manually, I use
git checkout REBASE_HEAD ., to replace the working tree with the non-code formatted version and then run the code formatting tool again. (In this example./vendor/bin/php-cs-fixer fix)Because the rebase behavior is slightly different if a conflict occurs, you need to follow up with different commands to complete the current commit based on the state:
This command if you encounter a normal "edit" breakpoint:
Looks like
After checkout and code format, amend current commit and continue rebase:
Complete one-step command:
This command if you encounter a rebase conflict:
Looks like this (hints might be colored):
After checkout and code format, stage changes and let
git rebase --continueamend the commit:Complete one-step command:
If you use the wrong command, the end result will be the same, but you will lose some commits.
Sadly, I couldn't figure out a way to use
git rebase --exec(REBASE_HEADisn't defined during the exec command?) or a way to automatically use the correct resolve command.I'm sure there is a better solution, but I couldn't find it, so I present mine here.