35

I'm trying to find the source of a bug that's come up since a commit in the past day on a long lived branch (which will be released much much later) called feature-x.

There's a bug though. I find behavior that I don't expect from my script which might have been introduced in any of the commit's up till now, specifically because features of master are used heavily in feature-x, but less so on Master itself.

To test this behavior, I have to run my script, dependent.pl. But when bisect jumps half way down the code, my script doesn't exist on Master and so it's impossible to test.

I believe this is because bisect pulls you out into a headless state, but in this case I really want to be in the context of this other history/changeset, and not floating in the ether.

Before anyone jumps to hit the you're doing it wrong buzzer, our team likes merging branches in these situations as the metaphor works well for this situation, not rebase-ing.

I'll demo this by creating a sample repo:

git init

echo 'sub f { print $_; }' > main.pl
git add .
git commit -a -m "inital commit"

git branch feature-x
git checkout feature-x
echo 'main::f(1)' > dependent.pl
git add .
git commit -a -m "Starting work on feature X"
git tag dev-1.0

git checkout master
echo "sub f { return 1; }" > main.pl
git commit -a -m "sub f { return 1; }"
echo "sub f { return 2; }" > main.pl
git commit -a -m "sub f { return 2; }"
echo "sub f { return 3; }" > main.pl
git commit -a -m "sub f { return 3; }"

git tag release-1.0

git checkout feature-x
git merge master

echo 'print main::f();' > dependent.pl
git commit -a -m "Updating call to f"

So now you get a repo that looks like this:

o Updating call to f ( Head of branch 'feature-x' )
o Merge branch master onto feature-x
|\
| o sub f { return 3; } (TAG release-1.0) ( Head of branch 'master' )
| o sub f { return 2; }
| o sub f { return 1; }
o | Starting work on feature X ( TAG 'dev-1.0' )
 \|
  o initial commit

So I run the command git bisect start feature-x dev-1.0 expecting I'll be able to find what broke my code in dependent.pl, I end up on commit 'sub f { return 2 }' without my history of changes from feature-x (i.e. If I run ls, all I see is main.pl and dependent.pl is missing).

This puts me in an untestable state. I cannot know if the current commit broke my work or not, nor can I say that commits on master broke it, so I can't say this commit is good or bad.

How can I test what broke my current branch?

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
heymatthew
  • 6,716
  • 5
  • 26
  • 22
  • I'm not sure to fully understand your problem. 1) I did "git bisect start test dependent". 2) File dependent.txt is not there, so no problem yet -> I do "git bisect good" 3) File dependent.txt is present, contains "dependent", this is good: "git bisect good". 4) git bisect have found the guilty commit (no other commit left). You may know that the bug is on the test branch but git bisect cannot guess that, so it "bisects" through all ancestors. – gawi Sep 09 '10 at 02:46
  • gawi: dependent.txt contains references to a.txt, and the only way to test for the bug is by running dependent.txt. You can't test dependent.txt if it's not there, so you can't say "git bisect good" at that stage. – heymatthew Sep 09 '10 at 03:08
  • @The Daemons Advocate Hmm... maybe the example using text files is too limited to illustrate the root of your problem. I'm still under the impression that "git bisect good" is appropriate as it tells bisect to move to go forward as the item to test is not yet present. – gawi Sep 09 '10 at 15:18
  • By the way, if this is actual test code, it should be in your master branch. It may not be part of what you *distribute* (when you package up you can ignore it) but test code is part of a code base, and should be available there to run at any time, so that for example, prior to making commit b you could run your tests, rather than having to commit, merge, test, and then reset/amend if it doesn't work. – Cascabel Sep 09 '10 at 18:00
  • @gawi Yes, there are two things I should change about my example. I'm working with perl files, not text files, and the branch test should be named extended features. – heymatthew Sep 09 '10 at 23:19
  • @Jefromi Test doesn't contain test code, soz. This branch contains a subset of features being worked on that are not yet ready to be released. They are however, integrated rather closely with the existing project and do have a strong dependency on it. I'm going to refine my example to try clarify what I'm trying to do. – heymatthew Sep 09 '10 at 23:22
  • Okay. That doesn't change what I said about the way bisect works in my answer, just means that your workflow isn't broken like I thought it might be. (It's still kind of a bad idea to merge frequently from master to a topic branch, but it won't kill you, I suppose.) – Cascabel Sep 09 '10 at 23:38
  • @Jefromi kk, I see what you're getting at but I still think that bisect should keep where I am on a branch if I specify initial good/bad commits on it. – heymatthew Sep 10 '10 at 02:50
  • @Jefromi If I do a git status I'm told that I'm not on any branch. The only way I really understand where I am is if I bring up gitk and look at the commit. In order to test these particular commits, I'd have to merge whenever I found myself outside of the change-set introduced on my branch. – heymatthew Sep 10 '10 at 02:54
  • Yes, by its very definition, git bisect checks out commits which are not at the tip of the branch. "On a branch" means "at the tip", not "an ancestor of the tip." bisect does provide a convenient way to launch gitk (`git bisect visualize`) should you have trouble keeping track of what it's doing, but it really is doing a binary search through the history between the two points you specify, and if part of `good..bad` is commits which were merged, they're included too, as with any rev-list. And yes, in your particular case, you'd have to do test merges like I described. – Cascabel Sep 10 '10 at 12:54
  • 1
    If this helps clarify any, if you check out commit "Merge branch master onto feature-x", you are *not* on a branch, and that is clearly part of the bisect you want to do. – Cascabel Sep 10 '10 at 12:56
  • @Jefromi why is it a bad idea to frequently merge from master to a topic branch? We do that all the time where I work... – wrongusername Jul 10 '12 at 16:52
  • @wrongusername: http://gitster.livejournal.com/42247.html The main point with respect to your question: master branches tend to include many changes, and topic branches are about encapsulating single changes. Merging from topic to master makes sense; you're saying that you want the canonical version to include that single change. Merging from master to topic generally doesn't; you're saying that you want that single change to include everything that's been bundled up in master. – Cascabel Jul 10 '12 at 17:35
  • @Jefromi Ahh, I see. But if you're working on a big team with daily changes, wouldn't you want to always be up to date with what other changes in the code are being made? – wrongusername Jul 10 '12 at 17:46
  • @Jefromi I finished reading the article, and I wonder if the goal of a topic branch can't always be "add feature Foo to the latest version of the software"? We merge from master daily at the place where I work at, and I never knew better – wrongusername Jul 10 '12 at 17:50
  • @wrongusername: It may not cause you trouble most of the time, but sometimes the extra clutter is harmful. You can pick up bugs or behavior changes irrelevant to what you're working on. And if your topic really is coherent, then there's not any difference between "add feature X" and "add feature X to the latest version". If adding the feature requires interaction with one other thing, it's cleaner to merge that topic branch than everything. And if it interacts with *everything*, either you're not doing a good job dividing up work, or it's a project-wide change that's not a normal topic branch. – Cascabel Jul 10 '12 at 18:37
  • @Jefromi ahh, good point. Indeed, I regularly pick up bugs created by others in this manner. But these bugs were discovered by me while developing my independent feature that interacted with the buggy code indirectly. Wouldn't I be discovering all these bugs at once had my branch been merged into production? – wrongusername Jul 10 '12 at 20:05
  • @wrongusername This is really not the place for extended discussion - ask a separate question if you have a lot more you want to know. But as long as I'm here: one, those bugs really should be found in a way other than by developing an independent feature (say, testing), so ideally they'd appear then be fixed, and when you merge later, you'd never know; and two, you can always do periodic test merges (which you then throw away) to see if you're still on track if you're worried. – Cascabel Jul 10 '12 at 20:12

1 Answers1

38

The problem here is that git bisect is branch aware. When you tell it that "dependent" is good and "test" is bad, and one of the changes between there is a merge commit, it knows that in order to figure out where the problem was introduced, it's going to have to look at commits a, b, and c - otherwise, all it would be able to tell you is whether or not it's broken as of that merge commit.

It sounds like what you're expecting is to test the combination of commit b with the changes from the other branch, which is content which doesn't exist in any commit, and git bisect only lets you test commits! In order to test that content, you'd have to do a series of test merges - check out b, merge dependent, let you test, then check out a or c, merge dependent, let you test again. You can very easily do git merge --no-commit dependent once it's left you at commit b, then do git reset --hard when done with testing before running git bisect good/bad.

Otherwise, if I've misunderstood you expect it not to test any commits on the merged branch, and only test the merge commit itself (you don't care which of a, b, or c broke it), simply tell it that everything on the merged branch is good. Even better if you know that a, b, and c have nothing to do with it. Then you know without even testing that they're good!

But the one thing that you can't expect is for git to completely ignore commits a, b, and c. It has absolutely no way of knowing whether or not their changes are relevant to your "bug", and their changes are part of the difference between your good and bad commits.

Cascabel
  • 479,068
  • 72
  • 370
  • 318
  • Lets say a.txt has a function f that's called from dependent.txt, and had changes applied to it in commits a, b and c. How would you know that changes introduced in f didn't break dependent.txt? – heymatthew Sep 09 '10 at 04:18
  • 7
    Again, you're asking to test a set of content which does not exist in any commit - for example, the combination of the changes from b with the changes from dependent. To get that content in your working tree, the most general method would be to do a test merge as I described, then reset it away before proceeding. – Cascabel Sep 09 '10 at 13:10
  • @The Daemons Advocate I agree with Jefromi. It looks like you are using the test branch to add testing material to the tree, that's a bit unusual. If dependent.txt is used for testing, maybe it should be in the master branch. Another answer could be: merge more often to have better granularity. – gawi Sep 09 '10 at 15:27
  • > * all it would be able to tell you is whether or not it's broken as of that merge commit* In many cases we don't care which *commit* broke, we care about which *Pull Request*. We want the merge commit! – pkamb Jun 29 '18 at 21:30