2

Assume the following git branch: A -> B -> C -> D -> E -> F -> G

I've determined via git bisect that commit C introduced a bug, but reverting the changes introduced by C at the top of the branch does not solve the issue. This indicated to me that there are other bugs in later commits on that branch.

Is there a way to synthesize the following branch: A -> B -> D1 -> E1 -> F1 -> G1 , where the 1 indicates that the changes introduced in commit C do not exist ? I would then run git bisect on that branch as well to determine find the other bug. [ hopefully this would not need to be repeated multiple times ]

Chaim Geretz
  • 826
  • 5
  • 23

2 Answers2

4

Yes:

git checkout -b newbranch <specifier-for-B>
git cherry-pick <specifier-for-C>..<specifier-for-G>

These <specifier>s can be raw hash IDs, or branch names, or branch names with ~number to count back number first-commits, and so on. The trick is to make a new branch that ends at the last good commit, then cherry-pick in the rest of the maybe-good commits excluding the known-bad commit.

Once you have this new branch, you can use git rebase -i or git rebase --onto <target> <exclude> to drop even more commits, if you like.

torek
  • 448,244
  • 59
  • 642
  • 775
  • 1
    Note, by the way, that [Jonathan.Brink's method](https://stackoverflow.com/a/45600474/1256452) is basically the same except that he starts with the new branch at the same tip as the old branch, then has you remove commits. If you have to do repeated removes this may feel more convenient. It does need the one interactive rebase step (or fancy `rebase --onto` footwork) though. – torek Aug 09 '17 at 20:55
2

You could interactively rebase and remove that commit.

First create the test branch:

git checkout -b test

Next, start the rebase:

git rebase -i C^ # the parent of C

When you are in the interactive rebase screen, delete the line that contains commit C.

This will make the save branch effectively match A -> B -> D1 -> E1 -> F1 -> G1 and you can continue your testing.

If you find that C was the only commit you need to remove, another option would be to revert it so you don't need to push any history that modifies already-pushed commits:

git checkout master # get back to where you started
git revert C        # will create a revertion commit
git push            # will only push 1 new commit, the inverse of C
Jonathan.Brink
  • 23,757
  • 20
  • 73
  • 115