I'm aware that git bisect is branch-aware by design, so that if between good commit, G, and bad commit, B, you merged in a branch, it needs to take those changes into consideration as well, as the bug may be contained in the branch.
In my case I have a dependency as a side branch and I merge in changes to my main project from time to time. The dependency can be considered a library that has a different way of running, different build-system etc. from my main project, but I still want recent changes from it via merges to the main branch.
The problem is then that while bisecting in this scenario, you end up on non-compilable commits in the commits from the dependency.
I would really just want to consider each branch merge as a single commit while doing the bisection.
A workaround I've found so far is making a list of valid commits G..B with git log --first-parent, and then while bisecting, do git bisect skip if the current commit isn't in that list. That takes a lot of time though (lots of files to checkout/change for each skip).
So the question is: Is there any way of doing --first-parent with git bisect or providing a list of commits i feel are valid to be able to avoid checking out branches I know already are not compilable? How do we only check the commits marked o in the diagram?
G---o---o---o---o---o---o---B main project branch / / / x---x---x---x---x dependency \ / x' dependency project taskbranch
Edit: added diagram for clarity
If the history looks like:
where L is bad, B is good, and you want to ignore the DEFG branch, then running
where B,C,G,and L are the respective shas seems to do what you want.
So, the assumption that the first parent of a merge commit is always the same branch isn't always correct. For instance, if you are off on a topic branch and merge master to it to get up to date (so for this merge commit, the first parent is the topic branch) and then checkout master and merge topic back to it, you get a fast forward merge, which just moves master to the merge commit that had first parent as your topic branch. This may seem contrived, but its actually a pretty normal workflow - I always merge master into my branch so that my merge back to master will be a trivial merge (i.e., fast forward-able) (Sorry James, always forget to rebase it).
There is one way that I've found to help figure out which parent is your branch - the merge commit comment itself. By default, git composes a merge commit comment that says which branch was merged and you can use this to deduce which parent is the branch you are interested in, so long as the person doing the merge commit didn't overwrite this merge commit comment.
So I tried this out and it seems to work for me. I wrote a Python script to help do this on github. If you run this script, it will try to trace backwards and follow your branch and emit a list of commit ids that are the tips of the branches that are merged into your branch. With this list, you can give these to "git bisect good" and bisect will then omit all of the commits on the merged branches from your bisection, achieving the desired result.
I've been looking for something like this too. As far as I've got is that
git rev-list --bisect --first-parent
seems to do what you want to, and the docs for rev-list implies that the--bisect
option is what bisect uses internally - but gettinggit bisect
to add that flag to its call(s) to rev-list seems less trivial:The bisect command is implemented by a shell script git-bisect, which in turn uses a builtin command
bisect--helper
to actually do the interesting part ("computation, display and checkout" says the comment...), apparently based on a bunch of magic state files in .git/. And it seems to be the rev-list command that is reusing code from bisect--helper rather than the other way around as you might expect.So, you'd have to extend the bisect--helper code's commit filtering to do it, I think.
As a workaround, something like this might work: after bisect checks something out for you, reset to a different one using
git rev-list --bisect --first-parent
, test that and mark it good/bad/skip and continue from there.