automatically created too.
The future of bisecting
-----------------------
"git replace"
~~~~~~~~~~~~~
We saw earlier that "git bisect skip" is now using a PRNG to try to
avoid areas in the commit graph where commits are untestable. The
problem is that sometimes the first bad commit will be in an
untestable area.
To simplify the discussion we will suppose that the untestable area is
a simple string of commits and that it was created by a breakage
introduced by one commit (let's call it BBC for bisect breaking
commit) and later fixed by another one (let's call it BFC for bisect
fixing commit).
For example:
-------------
...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z-...
-------------
where we know that Y is good and BFC is bad, and where BBC and X1 to
X6 are untestable.
In this case if you are bisecting manually, what you can do is create
a special branch that starts just before the BBC. The first commit in
this branch should be the BBC with the BFC squashed into it. And the
other commits in the branch should be the commits between BBC and BFC
rebased on the first commit of the branch and then the commit after
BFC also rebased on.
For example:
-------------
(BBC+BFC)-X1'-X2'-X3'-X4'-X5'-X6'-Z'
/
...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z-...
-------------
where commits quoted with ' have been rebased.
You can easily create such a branch with Git using interactive rebase.
For example using:
-------------
$ git rebase -i Y Z
-------------
and then moving BFC after BBC and squashing it.
After that you can start bisecting as usual in the new branch and you
should eventually find the first bad commit.
For example:
-------------
$ git bisect start Z' Y
-------------
If you are using "git bisect run", you can use the same manual fix up
as above, and then start another "git bisect run" in the special
branch. Or as the "git bisect" man page says, the script passed to
"git bisect run" can apply a patch before it compiles and test the
software <<8>>. The patch should turn a current untestable commits
into a testable one. So the testing will result in "good" or "bad" and
"git bisect" will be able to find the first bad commit. And the script
should not forget to remove the patch once the testing is done before
exiting from the script.
(Note that instead of a patch you can use "git cherry-pick BFC" to
apply the fix, and in this case you should use "git reset --hard
HEAD^" to revert the cherry-pick after testing and before returning
from the script.)
But the above ways to work around untestable areas are a little bit
clunky. Using special branches is nice because these branches can be
shared by developers like usual branches, but the risk is that people
will get many such branches. And it disrupts the normal "git bisect"
work-flow. So, if you want to use "git bisect run" completely
automatically, you have to add special code in your script to restart
bisection in the special branches.
Anyway one can notice in the above special branch example that the Z'
and Z commits should point to the same source code state (the same
"tree" in git parlance). That's because Z' result from applying the
same changes as Z just in a slightly different order.
So if we could just "replace" Z by Z' when we bisect, then we would
not need to add anything to a script. It would just work for anyone in
the project sharing the special branches and the replacements.
With the example above that would give:
-------------
(BBC+BFC)-X1'-X2'-X3'-X4'-X5'-X6'-Z'-...
/
...-Y-BBC-X1-X2-X3-X4-X5-X6-BFC-Z
-------------
That's why the "git replace" command was created. Technically it
stores replacements "refs" in the "refs/replace/" hierarchy. These
"refs" are like branches (that are stored in "refs/heads/") or tags
(that are stored in "refs/tags"), and that means that they can
automatically be shared like branches or tags among developers.
"git replace" is a very powerful mechanism. It can be used to fix
commits in already released history, for example to