How to pick an exquisite feature among a huge number of unmerged commits?
2025年6月20日My dev branch is 400 commits ahead of master. How do I craft an exquisite pull request from astronomical unmerged commits?
Make a PR
Plan
Conceive a pull request about a feature of which most development is in a single file, which I call it mainFile
here. It’s advised to supply automated tests on the feature in this PR because otherwise I don’t know whether this feature is correct or complete. It’s OK for this feature to depend on changes in other files, which is quite inevitable.
Locate the nearest commit to master where the feature is complete. Mark this commit as EndOfPR. Hence, I form a pull request in the range master...EndOfPR
.
How to find EndOfPR?
#!/bin/bash
# trap 'git reset --hard HEAD' EXIT
# Step 1: Build library
echo "Building the library..."
MSBuild.exe '-t:Build' '-p:Configuration=debug;Platform=x86' 'Substitutions/Substitutions.vcxproj' || exit 125
# Step 2: Apply SimpleCLI commit
echo "Cherry-picking the SimpleCLI commit..."
git reset --hard HEAD
git cherry-pick -X theirs --no-commit SimpleCLI
# Step 3: Build CLI
echo "Building the CLI project..."
MSBuild.exe -t:Build '-p:Configuration=debug;Platform=x86' "cli/cli.vcxproj" || exit 0
exit 1
Exit code 125 means this commit is untestable. git bisect will skip this commit.
(SimpleCLI) $ git bisect start --term-new fixed --term-old broken status: waiting for both good and bad commits (SimpleCLI|BISECTING) $ git bisect fixed SimpleCLI status: waiting for good commit(s), bad commit known (SimpleCLI|BISECTING) $ git bisect broken master Bisecting: 200 revisions left to test after this (roughly 8 steps) ((be7cd98...)|BISECTING) $ git bisect run bash cli.sh
By default git bisect uses terms good and bad. Good refers to an old commit, probably master. Bad refers to a new commit, probably dev. This is in the case of locating a bug. But in my case, the situation is reversed. My master is bad, and my dev is good. To avoid confusion, I choose new terms fixed and broken. Notice the exit code in Listing is also reversed.
Then although I’ve chosen new terms, git bisect is still in its old mindset, reporting “waiting for good commit(s), bad commit known”, which sounds misleading and you can safely ignore.
The number of commits between SimpleCLI to master is roughly 400, so git bisect tells me that “after testing be7cd98, there are 200 revisions to test.”
Next, I run git bisect run
which automatically tests the 200 or less revisions. It will mark commits as fixed, broken, or skip, and eventually find the first fixed commit.
Finally run git bisect reset
to clean up and finish the bisect session.
Execute
Create a PR branch at EndOfPR. Next, rather than git rebase --interactive --force master
or cherrypick and selecting only commits affecting the main file, I should use git-filter-repo. git-filter-repo is a recommended tool by git filter branch and it is at lightning speed. There are many ways to run git-filter-repo. I will use the notation python git-filter-repo
in this article.
git checkout PR python git-filter-repo --pathmainFile
--pathfile1
--pathfile2
master..PR
Use Visual Studio Analysis to exam transitively included files, and add these files (.h and .cpp) as dependency if you know the feature depends on them. Trial and error can take a few times, but thank to the speed of git-filter-repo, it won’t be long before you figure out the scope of files.
Rebase the rest
git rebase –update-refs
TortoiseGit ignores the config rebase.updateRefs
[1].
References
- Slawomir Brzezinski . When rebasing a branch, allow moving all other local branches along with their commits. . 2017-10-28 [2025-06-21].↑