[HN Gopher] At the end you use Git bisect
___________________________________________________________________
At the end you use Git bisect
Author : _spaceatom
Score : 133 points
Date : 2025-11-02 17:24 UTC (5 hours ago)
(HTM) web link (kevin3010.github.io)
(TXT) w3m dump (kevin3010.github.io)
| huflungdung wrote:
| I hardly think binary search is an unknown algorithm even by
| beginner standards for someone from a completely different field
| trenchpilgrim wrote:
| https://xkcd.com/2501
|
| I know a lot of professional, highly paid SWEs and DevOps
| people who never went to college or had any formal CS or math
| education beyond high school math. I have a friend who figured
| out complexity analysis by himself on the job trying to fix up
| some shitty legacy code. Guy never got past Algebra in school.
|
| (If you're about to ask how they can get jobs while new grads
| can't - by being able to work on really fucking terrible legacy
| code and live in flyover states away from big cities.)
| kfarr wrote:
| Wow and here I was doing this manually all these years.
| lloydatkinson wrote:
| I've used bisect a couple of times but really it's a workaround
| for having a poor process. Automatic unit tests, CI/CD, should
| have caught it first.
|
| It's still very satisfying to watch run though, especially if you
| write a script that it can run automatically (based on the
| existing code) to determine if it's a good or bad commit.
| trenchpilgrim wrote:
| "We write unit tests so our code doesn't have bugs."
|
| "What if the unit tests have bugs?"
| nixpulvis wrote:
| It's not a workaround. In this case it seems like it, but in
| general you cannot always rely on your existing tests covering
| everything. The test you run in the bisect is often updated to
| catch something new which is reported. The process is often:
|
| 1. Start with working code
|
| 2. Introduce bug
|
| 3. Identify bug
|
| 4. Write a regression test
|
| 5. Bisect with new test
|
| In many cases you can skip the bisect because the description
| of the bug makes it clear where the issue is, but not always.
| Izkata wrote:
| Important addendum to 4 that can throw someone their first
| time - Put the new test in a new file and don't commit it to
| the repo yet. You don't want it to disappear or conflict with
| old versions of the test file when bisect checks old commits.
| nixpulvis wrote:
| I've always liked having regression tests somewhat isolated
| anyway, so this works well with that.
| lloydatkinson wrote:
| This is one annoying footgun. It would be great if git
| could ignore some special .bisect directory during the
| entire process. This way the script doesn't need a load of
| ../..
| trenchpilgrim wrote:
| Create a .bisect directory and stick a gitignore inside
| it that ignores the folder. Or, add .bisect/ to a global
| gitignore file.
| slang800 wrote:
| Sometimes you notice a problem that your unit tests didn't
| cover and want to figure out where it was introduced. That's
| where git bisect shines.
|
| You can go back and efficiently run a new test across old
| commits.
| tmoertel wrote:
| I don't think it's that simple. For example: Show me the unit
| tests and CI/CD scripts you would write to prove your code is
| free from security holes.
|
| Yet, _once you 've identified a hole_, you can write a script
| to test for it, run `git biset` to identify what commit
| introduced the hole, and then triage the possible fallout.
| masklinn wrote:
| > Automatic unit tests, CI/CD, should have caught it first.
|
| Tests can't prove the absence of bugs, only their presence.
| Bugs or regressions will slip through.
|
| Bisect is for when that happens _and_ the cause is not obvious.
| lucasoshiro wrote:
| Ideally, we should write bug-free code, but we can't. There are
| some tools to avoid bugs, tests are one of them. Those tools
| avoid them, but not mitigate. Bisect doesn't replace tests, it
| only helps find where the bugs are happening. After finding and
| fixing the bugs, it's a good idea to write a test covering that
| bug.
|
| To sum up: bisect and tests are not in opposite sides, they
| complement each other
| bulatb wrote:
| If you can write CI that catches every bug and has no bugs,
| just use that skill to write your code. No more bugs!
| dpflan wrote:
| `git-bisect` is legit if you have to do the history
| archaeological digging. Though, there is the open question of how
| git commit history is maintained, the squash-and-merge vs. just
| retain all history. With squash-and-merge you're looking at the
| merged pull-request versus with full history you can find the
| true code-level inflection point.
| formerly_proven wrote:
| > with full history you can find the true code-level inflection
| point.
|
| "typo fix"
| inopinatus wrote:
| "tues lunch wip"
| echelon wrote:
| Can someone explain why anyone would want non-squashed PRs?
|
| For the 5% of engineers that diligently split each PR into nice
| semantic changes, I suppose that's nice. But the vast majority
| of engineers don't do this. Individual commits in a PR are
| testing and iteration. You don't want to read though that.
|
| Unless, of course, you're asking the engineer to squash on
| their end before making the PR. But what's the value in that
| ceremony?
|
| Each PR being squashed to 1 commit is nice and easy to reason
| about. If you truly care about making more semantic history,
| split the work into multiple PRs.
|
| For that matter, why merge? Rebase it on top. It's so much
| cleaner. It's atomic and hermetic.
| embedding-shape wrote:
| > For that matter, why merge? Rebase it on top. It's so much
| cleaner. It's atomic and hermetic.
|
| With an explicit merge, you keep two histories, yet mostly
| care about the "main" one. With rebase, you're effectively
| forgetting there ever was a separate history, and chose to
| rewrite the history when "effectively merging" (rebasing).
|
| There's value in both, mostly seems to come down to human
| preference. As long as the people that will be working with
| it agrees, I personally don't care either way which one,
| granted it's consistently applied.
| eastbound wrote:
| Squashed PR allow you to see a single commit, while rebased
| PRs show up as multiple. The squash has the defect that you
| can't rebase PRs that were on top.
|
| But a MERGE... is a single commit on Master, while keeping
| the detailed history!
|
| - We just don't use the merge because they are ugly,
|
| - And they're only ugly because the visualizers make them
| ugly.
|
| It's a tooling problem. The merge is the correct
| implementation. (and yet I use the rebase-fast-forward).
| hinkley wrote:
| Rebasing is slower in practice to trunk based development
| and CI, while merging and squashing are moving farther
| away.
| nixpulvis wrote:
| I'd take fully squashed PRs over endless "fix thing" and
| "updated wip"... but if you work in a way that leaves a
| couple meaningful commits, that's even better. Sometimes I
| end up in this state naturally by having a feature branch,
| which I work on in sub branches, each being squashed into a
| single final commit. Or when the bulk of the logic is on one
| commit, but then a test case or two are added later, or a
| configuration needs changing.
|
| I like merge commits because they preserve the process of the
| review.
| echelon wrote:
| > I like merge commits because they preserve the process of
| the review.
|
| I appreciate that, but I still can't square it with my
| world view.
|
| GitHub or whatever tool you use preserves all the comments
| and feedback and change history if you ever need to go back
| and reference it. Such instances are limited, and in my
| experience it's mainly politics and not technical when this
| happens. The team's PR discussion itself isn't captured in
| git, so it's lossy to expect this type of artifact to live
| in git anyway. It's also much less searchable and less
| first class than just going back to GitHub to access this.
|
| Ultimately, these software development artifacts aren't
| relevant to the _production state_ of the software you 're
| deploying. It feels muddled to put an incomplete version of
| it into your tree when the better source of truth lives
| outside.
| nixpulvis wrote:
| Usually the merge commit is what has the link to the
| PR/MR. So it's the best way to actually find it.
|
| > Ultimately, these software development artifacts aren't
| relevant to the production state of the software you're
| deploying. It feels muddled to put an incomplete version
| of it into your tree when the better source of truth
| lives outside.
|
| You could make the same claim about the entire history.
| Git is a development tool, production just needs a
| working cut of the source.
| hinkley wrote:
| What you have there is people hiding their neuroses and
| lack of commit hygiene and that's avoiding the problem not
| fixing it.
| stefan_ wrote:
| There is no free lunch, the same people that can't be
| bothered to make atomic semantic commits are the same people
| that will ruin your bisect with a commit that doesn't build
| or has some other unrelated run failure. People that don't
| care can't be fixed by tools.
|
| The advice around PRs rings hollow, after all they were
| invented by the very people that don't care - which is why
| they show all changes by default and hide the commits away,
| commit messages buried after 5 clicks. And because this
| profession is now filled with people that don't care, add the
| whole JIRA ticket and fix version rigmarole on top - all
| kinds of things that show up in some PMs report but not in my
| console fixing an issue that requires history.
| rectang wrote:
| Crafting a PR as an easily-consumed, logical sequence of
| commits is particularly useful in open source.
|
| 1. It makes review much easier, which is both important
| because core maintainer effort is the most precious resource
| in open source, and because it increases the likelihood that
| your PR will be accepted.
|
| 2. It makes it easier for people to use the history for
| analysis, which is especially important when you may not be
| able to speak directly to the original author.
|
| These reasons also apply in commercial environments of
| course, but to a lesser extent.
|
| For me, organizing my PRs this way is second nature and only
| nominal effort, because I'm extremely comfortable with Git,
| including the following idiom which serves as a more powerful
| form of `git commit --amend`: git add -p
| git commit --fixup COMMIT_ID git stash git
| rebase -i --autosquash COMMIT_ID~
|
| An additional benefit is that this methodology doesn't work
| well for huge changesets, so it discourages the anti-pattern
| of long-lived topic branches. :)
|
| > _For that matter, why merge? Rebase it on top._
|
| Yes, that works for me although it might not work for people
| who aren't going to the same lengths to craft a logical
| history. I have no interest in preserving my original WIP
| commits -- my goal is to create something that is easy to
| review.
|
| BUT... the PR should ultimately be merged with a merge
| commit. Then when you have a bug you can run `git bisect` on
| merges only, which is good enough.
| vjerancrnjak wrote:
| I have an exactly opposite preference. Give me a big change
| to review. Going commit by commit or any imposed steps is
| not how I write code or how I understand code.
|
| If you did not approach it through literate programming, I
| just prefer all of the thousands of lines at once.
| QuercusMax wrote:
| Reviewing individual changes that may not even build
| properly is a waste of time; reviewing thousands lines of
| lines at once is also a bad idea.
|
| Each unit of code (PR, commit, CL, whatever you want to
| call it) you send for review should be able to stand on
| its own, or at the very least least not break anything
| because it's not hooked into anything important yet.
| rectang wrote:
| You're in luck! For you, there is `git diff`.
|
| (And for me as well -- both the individual commits and
| the PR-level summary are useful.)
|
| So, those of us who prefer commit-sized chunking don't
| have to do anything special to accommodate your
| preference.
|
| It doesn't go the other way, of course, if you present
| one big commit to me. But so long as your code is well-
| commented (heh) and the PR isn't too huge (heh heh) and
| you don't intersperse file renamings (heh heh heh) or
| code formatting changes (heh heh heh heh) which make it
| extremely difficult to see what you changed... no
| problem!
| Izkata wrote:
| > or code formatting changes (heh heh heh heh) which make
| it extremely difficult to see what you changed...
|
| One of the "individual commits saved me" cases was when
| one of these introduced a bug. They tried to cut the
| number of lines in half by moving conditions around, not
| intending to make any functional changes, but didn't
| account for a rare edge case. It was in a company-shared
| library and we didn't find it until upgrading it on one
| of our products a year or two after the change.
| rectang wrote:
| One of the reasons I don't like a policy of "every commit
| must pass CI" is that I prefer to perform verbatim file
| moves in a dedicated commit (which inevitably breaks CI)
| with no logical changes at all, then modify code as
| necessary to accommodate the move in a separate commit.
| It makes review and debugging much easier.
| dpflan wrote:
| You are model citizen with those file moves. Totally
| agree with how that can be very disruptive for legibility
| and comprehension of changes.
| Izkata wrote:
| > 2. It makes it easier for people to use the history for
| analysis, which is especially important when you may not be
| able to speak directly to the original author.
|
| I've been on a maintenance team for ~5 years and this has
| saved me so many times in svn, where you can't squash, for
| weird edge cases caused by a change a decade or more ago.
| It's _the_ reason I 'm against blind squashes in git.
|
| My favorite was, around 2022, discovering something that
| everyone believed was released in 2015, but was temporarily
| reverted in 2016 while dealing with another bug, that the
| original team forgot to re-release. If the 2016 reversion
| had been squashed along with the other bug, I might never
| have learned it was intended to be temporary.
|
| I'm fine with manually squashing "typo" commits, but these
| individual ones are the kind where you can't know ahead of
| time if they'll be useful. It's better to keep them, and
| use "git log --first-parent" if you only want the overview
| of merges.
| hinkley wrote:
| Someone did this to code meant to cut our web crawler
| bandwidth and someone didn't notice it for like two years
| after it got toggled back off. So stupid. We were able to
| shrink the cluster after enabling it again.
| hinkley wrote:
| Also for a year from now when I'm wondering wtf I was
| thinking when I put that bug into the code. Was a thinking
| of a different corner case? Or not at all?
| mikeocool wrote:
| If you ever worked with stacked PRs, and the top one gets
| squashed and merged it often becomes a nightmare to rebase
| the rest of the PRs to bring them up to date.
| rectang wrote:
| I wish this was easier. I have a workflow that I use to
| create stacked PRs which involves changing the target
| branch of the next PR to `main` after merging its
| predecessor, but it is too fragile to institute as a
| policy.
|
| However, this is also just a more specific version of the
| general problem that long-lived, elaborate topic branches
| are difficult to work with.
| baq wrote:
| jj makes this mostly trivial - well worth checking out if
| you'd like to work this way, but GitHub gets in the way.
| nothrabannosir wrote:
| Because github doesn't support stacked diffs, basically.
|
| T_T
| leptons wrote:
| I manage a team of developers, and I don't think any of us
| squash commits, and I really don't care. It's been working
| fine for 8 years at this job.
|
| We keep our git use extremely simple, we don't spend much
| time even thinking about git. The most we do with git is
| commit, push, and merge (and stash is useful too). Never need
| to rebase or get any deeper into git. Doing anything
| complicated with git is wasting development time. Squashing
| commits isn't useful to us at all. We have too much forward
| velocity to worry that some commit isn't squashed. If a bug
| does come up, we move forward and fix it, the git history
| doesn't really figure into our process much, if at all.
| ziml77 wrote:
| Squash is just something you do at the point of merging.
| It's a single option during the merge and doesn't have you
| doing any more work than a merge that you don't squash. I
| don't know about github, but I know in gitlab it's a simple
| checkbox in the merge request (and it can be set to be
| checked by default by the admin if they want).
| leptons wrote:
| That's great for you, but squashing commits doesn't do
| anything for our team. It hides somewhat useful
| information, which never seemed like a good thing to me.
|
| Other teams at my company are obsessive about squashing,
| and I am glad I don't work on those teams. They are
| frustrating to work with, they are notoriously slow to
| ship anything, and their product still breaks even with
| all their processes and hurdles to getting anything
| shipped. Teams that demand squashing simply don't impress
| me at all.
| SatvikBeri wrote:
| Making human-readable commit history is not that hard with a
| little practice. It's one of the big benefits of tools like
| magit or jj. My team started doing it a few weeks ago, and
| it's made reviewing PRs substantially easier.
| criemen wrote:
| +1: EdaMagit has been a game changer for me wrt reordering
| commits, fusing them together, and writing at least 1-2
| sentences of proper commit messages after the fact.
| CogitoCogito wrote:
| I have always been very careful with git histories and often
| rewrite/squash them before final review/merge. Often my
| rewritten histories have nothing to do with the original
| history and commits are logically/intuitively separated and
| individually testable.
|
| That said, very few people seem to be like me. Most people
| have no concept of what a clear commit history is. I think
| it's kind of similar to how most people are terrible written
| communicators. Few people have any clue how to express
| themselves clearly. The easiest way to deal with people like
| this is to just have them squash their PRs. This way you can
| at least enforce some sanity at review and then the final
| commit should enforce some standards.
|
| I agree on rebasing instead of straight merging, but even
| that's too complicated for most people.
| bentcorner wrote:
| > _If you truly care about making more semantic history,
| split the work into multiple PRs._
|
| This exactly - if your commit history for a PR is interesting
| enough to split apart, then the original PR was too large and
| should have been split up to begin with.
|
| This is also a team culture thing - people won't make "clean"
| commits into a PR if they know people aren't going to be
| bisecting into them and trying to build. OTOH, having people
| spend time prepping good commits is potentially time wasted
| if nobody ever looks at the PR commit history aside from the
| PR reviewers.
| hamburglar wrote:
| If I have a feature branch, and as part of that feature
| change, I did a simple refactor of something, I definitely
| want that committed as two separate commits in the PR,
| because you can look at the changes in isolation and it
| makes them a LOT easier to follow. And if you prefer, you
| can look at the diff of the entire PR in one single view. I
| don't see the downside.
|
| And please do not come back with "you shouldn't do a
| refactor as part of a feature change." We don't need to add
| bureaucracy to avoid a problem caused by failure to
| understand the power of good version control.
| normie3000 wrote:
| This bureaucracy has very low overhead. Squash-merge the
| feature and then the refactor, or the refactor then the
| feature. Also makes reviewing each quicker.
| PaulDavisThe1st wrote:
| the feature isn't _ready_ for merge when the refactor
| happens ....
| koolba wrote:
| > Can someone explain why anyone would want non-squashed PRs?
|
| So you can differentiate the plumbing from the porcelain.
|
| If all the helpers, function expansions, typo corrections,
| and general renamings are isolated, what remains is the pure
| additional functional changes on its own. It makes reviewing
| changes much easier.
| vjerancrnjak wrote:
| You can just inspect merge commits, you can also just bisect
| over merge commits.
|
| Splitting work into multiple PRs is unnecessary ritual.
|
| I have never reasoned about git history or paid attention to
| most commit messages or found any of it useful compared to
| the contents of the change.
|
| When I used git bisect with success it was on unknown
| projects. Known projects are easy to debug.
| pizza234 wrote:
| > Each PR being squashed to 1 commit is nice and easy to
| reason about. If you truly care about making more semantic
| history, split the work into multiple PRs.
|
| I don't argue with your point (even if I am obsessive about
| commits separation), but one needs to keep in mind that the
| reverse also applies, that is, on other end of the spectrum,
| there are devs who create kitchen-sink PRs which include, for
| example, refactorings, which make squashed PRs harder to
| reasons about.
| borntyping wrote:
| > Can someone explain why anyone would want non-squashed PRs?
| > > For the 5% of engineers that diligently split each PR
| into nice semantic changes, I suppose that's nice. But the
| vast majority of engineers don't do this.
|
| I think cause and effect are the other way around here. You
| write and keep work-in-progress commits without caring about
| changes _because_ the history will be discarded and the team
| will only look at pull requests as a single unit, and write
| tidy distinct commits _because_ the history will be kept and
| individual commits will be reviewed.
|
| I've done both, and getting everyone to do commits properly
| is much nicer, though GitHub and similar tools don't really
| support or encourage it. If you work with repository history
| a lot (for example, you have important repositories that
| aren't frequently committed to, or maintain many different
| versions of the project) it's invaluable. Most projects don't
| really care about the history--only the latest changes--and
| work with pull-requests, which is why they tend to use the
| squashed pull request approach.
| baq wrote:
| It's mostly because pull requests are what is being tested
| in CI, not individual commits. Might as well squash as
| nobody wants to deal with untested in-between crap.
|
| If you mean stacked PRs, yeah GitHub absolutely sucks.
| Gerrit a decade ago was a better experience.
| adastra22 wrote:
| That's a problem with your CI. You can configure it to
| test all commits which make up the PR.
| baq wrote:
| My CI takes 20+ mins and costs meaningful $ per run. Not
| happening.
| adastra22 wrote:
| > That's a problem with your CI.
| baq wrote:
| Yes, but not in the way you think.
| adastra22 wrote:
| > For the 5% of engineers that diligently split each PR into
| nice semantic changes, I suppose that's nice. But the vast
| majority of engineers don't do this.
|
| Here's a simple reason: at my company, if you don't do this,
| you get fired.
|
| This is basic engineering hygiene.
| mkleczek wrote:
| git merge --no-ff
|
| git log --first-parent
|
| git bisect --first-parent
|
| The above gives you clean PR history in the main branch while
| retaining detailed work history in (merged) feature branches.
|
| I really don't understand why would I squash having git merge
| --no-ff at my disposal...
| rectang wrote:
| +1, I have `git merge --no-ff` and `git pull --ff-only` set
| in my global gitconfig[1].
|
| [1] https://github.com/rectang/dotfiles/blob/master/gitextr
| a#L11...
| anonymars wrote:
| Hoo boy is it fun to figure out where things went wrong when
| the real commit history was thrown away to make it look
| prettier. _Especially_ a mistake from a merge conflict.
| hinkley wrote:
| I had to stop two devs from fisticuffs. One of them used
| merge and manufactured a bug in the other's code and was
| making a stink about it in the middle of the cubicles.
|
| Merges lie I worse ways than rebase does. Hands down. With
| rebase I break my own shit. With merge I can break yours.
| Since your code is already merges into trunk, it has fewer
| eyes on it now and it's on _me_ to make sure my code works
| with yours and not vice versa.
| lucasoshiro wrote:
| I wrote a text about that:
|
| https://lucasoshiro.github.io/posts-
| en/2024-04-08-please_don...
| rf15 wrote:
| Honestly, after 20 years in the field: optimising the workflow
| for when you can already reliably reproduce the bug seems
| misapplied because that's the part that already takes the least
| amount of time and effort for most projects.
| nixpulvis wrote:
| Just because you can reproduce it doesn't mean you know what is
| causing it. Running a bisect to fix which commit introduces it
| will reduce the area you need to search for the cause.
| SoftTalker wrote:
| I can think of only a couple of cases over 20+ years where I
| had to bisect the commit history to find a bug. By far the
| normal case is that I can isolate it to a function or a query
| or a class pretty quickly. But most of my experience is with
| projects where I know the code quite well.
| cloud8421 wrote:
| I think your last sentence is the key point - the times
| I've used bisect have been related to code I didn't really
| know, and where the knowledgeable person was not with the
| company more or on holiday.
| nixpulvis wrote:
| Exactly. And even if I do know the source pretty well,
| that doesn't mean I'm caught up on all the new changes
| coming in. It's often a lot faster to bisect than to read
| the log over the month or two since I touched something.
| hinkley wrote:
| Or they were barking up a wrong tree and didn't know it
| yet, and the rest of us were doing parallel discovery.
|
| Tick tock. You need competence in depth when you have
| SLIs.
| hinkley wrote:
| I've needed CPR zero times and bisect around a dozen. You
| should know both particularly for emergencies.
| hinkley wrote:
| I would add to nixpulvis's comments that git history may also
| help you find a repro case, especially if you've only found a
| half-assed repro case that is overly broad.
|
| Before you find even that, your fire drill strategy is very
| very important. Is there enough detail in the incident channel
| and our CD system for coworkers to put their dev sandbox in the
| same state as production? Is there enough if a clue of what is
| happening for them to run speculative tests in parallel? Is the
| data architecture clean enough that your experiments don't
| change the outcome of mine? Onboarding docs and deployment
| process docs, if they are tight, reduce the Amdahl's Law effect
| as it applies to figuring out what the bug is and where it is.
| Which is I. This context also Brooks 's Law.
| f311a wrote:
| I've used bisect a few times in my life. Most of the time, I
| already know which files or functions might have introduced a
| bug.
|
| Looking at the history of specific files or functions usually
| gives a quick idea. In modern Git, you can search the history of
| a specific function. >> git log -L
| :func_name:path/to/a/file.c
|
| You need to have a proper .gitattributes file, though.
| _1tan wrote:
| Can you elaborate on the dependent .gitattributes file? Where
| can I find more information on the necessary content? Sounds
| super useful!
| f311a wrote:
| You need to specify diff format, so that Git can correctly
| identify and parse function body.
|
| *.py diff=python
| _1tan wrote:
| Thanks!
| adastra22 wrote:
| I use git bisect literally every day. We are clearly different
| people :)
| hinkley wrote:
| I don't use it for myself often, but I use it fairly often
| when someone has to escalate a problem to me. And how you
| work when the shit hits the fan says a lot about you overall,
| IMO.
| adastra22 wrote:
| Basically any time I'm like "huh, that's weird," even if it
| is not a bug, I bisect and see when that behavior was
| introduced. Because (1) this is trivial and no work to do
| (`git bisect run` is completely autonomous), and (2) it
| gets me to the commit that introduces the change, which has
| all the context that might tell me why it is acting that
| way.
|
| Nothing annoys me more than a codebase with broken commits
| that break git bisect.
| hinkley wrote:
| Ah, in that case the JetBrains diff tool lets you
| annotate inside the diff window and I can usually walk
| back to where this possible off by one error was first
| authored that way.
|
| It probably would be slightly faster to jump to bisect.
| But it's not in my muscle memory.
| nielsole wrote:
| Alternatively if you do not have that set up, `git log -S`
| helps you find commits whose diff contain a specific string.
| PaulDavisThe1st wrote:
| I use this often, but it is sadly weak when used on C++ code
| that includes polymorphic methods/functions: /*
| snip */ void Object::do_the_thing (int)
| { } void Object::do_the_thing (float)
| { } /* snip*/
|
| AFAICT, git log will never be able to be told to review the
| history of the _second_ version.
| bikelang wrote:
| Git bisect was an extremely powerful tool when I worked in a big-
| ball-of-mud codebase that had no test coverage and terrible
| abstractions which made it impossible to write meaningful tests
| in the first place. In that codebase it was far easier to find a
| bug by finding the commit it was introduced in - simply because
| it was impossible to reason through the codebase otherwise.
|
| In any high quality codebase I've worked in, git bisect has been
| totally unnecessary. It doesn't matter which commit the bug was
| introduced in when it's simple to test the components of your
| code in isolation and you have useful observability to instruct
| you on where to look and what use inputs to test with.
|
| This has been my experience working on backend web services -
| YMMV wildly in different domains.
| sfvisser wrote:
| Even if you can reason through a code base a bisect can still
| be much quicker.
|
| Instead of understanding the code you only need to understand
| the bug. Much easier!
| foresto wrote:
| I find git bisect indispensable when tracking down weird kernel
| bugs.
| Volundr wrote:
| If all you care about it fixing the bug, this is probably often
| true. Certainly bisect is not part of my daily workflow.
| Sometimes though you also need to know how long a bug has been
| in place e.x. to track down which records may have been
| incorrectly processed.
|
| Edit: tracking down where something was introduced can also be
| extremely helpful for "is this a bug or a feature" type
| investigations, of which I have done many. Blame is generally
| the first tool for this, but over the course of years the blame
| and get obscured.
| jayknight wrote:
| Yes to both of these. In a healthcare setting, some bugs
| leave data that needs to be reviewed and/or corrected after
| it is identified and fixed.
|
| And also a fair number of bugs filed can be traced back to
| someone asking for it to work that way.
| hinkley wrote:
| See also Two Devs Breaking Each Other's Features.
|
| I got to hear about a particularly irate customer during a
| formative time of my life and decided that understanding why
| weird bugs got in the code was necessary to prevent
| regressions that harm customer trust in the company. We took
| too long to fix a bug and we reintroduced it within a month.
| Because the fix broke another feature and someone tried to
| put it back
| kccqzy wrote:
| Git bisect is never unnecessary. Even when you can easily test
| the components and find the bug that way, a bisect allows you
| to understand why the bug was introduced. This is wonderful in
| all places where there is a culture of writing long and
| comprehensive commit messages. You get to understand why the
| bug occurred from a previous commit message and you will write
| about that context in your bug fix commit message. And this
| becomes positive reinforcement. The better the commit messages
| are, the more useful it is to use git bisect or git blame to
| find the relevant commit messages.
| kemayo wrote:
| Yeah, bisect is really handy because often a bug will have
| been introduced as a side-effect of a change made to support
| something else, and if you don't know what new usage was
| introduced you're relatively likely to break _that_ in the
| course of fixing the bug.
|
| You can avoid it via the "just look at every usage of this
| function and hold the entire codebase in your head" method,
| of course, but looking at the commit seems a bit simpler.
| _alternator_ wrote:
| 'git blame' is often more handy for finding the reason that
| the change was made, assuming you know the location of the
| bug. It tells you the commit and the commit message.
| diegocg wrote:
| There are certainly other use cases. git bisect was enormously
| useful when it was introduced in order to find Linux kernel
| regressions. In these cases you might not even be able to have
| tests (eg. a driver needs to be tested against real hardware -
| hardware that the developer that introduced the bug could not
| have), and as an user you don't have a clue about the code.
| Before git bisect, you had to report the bug and hope that some
| dev would help you via email, perhaps by providing some patch
| with print debug statements to gather information. With git
| bisect, all of sudden a normal user was able to bisect the
| kernel by himself and point to the concrete commit (and dev)
| that broke things. That, plus a fine-grained commit history,
| entirely changed how to find and fix bugs.
| rr808 wrote:
| Surely everyone has a CI pipeline that wont allow merges with
| failing tests?
| ervine wrote:
| More than one assumption in that sentence, ha!
| trenchpilgrim wrote:
| Including "code is delivered in a way that involves merges"
| ervine wrote:
| This feels like a "is a hotdog a sandwich?" situation.
|
| "Is sftp-ing to prod a merge?"
| trenchpilgrim wrote:
| My team follows good practice but I deal with a vendor
| who emails us a ZIP file :scream:
| ervine wrote:
| Honestly it's kind of refreshing to just push files to a
| server.
| trenchpilgrim wrote:
| I've been telling people for years, if the process to
| deploy to an environment is more complicated than one
| click, it's too complicated!
| jmount wrote:
| This if the case where you introduce the test after the
| failure.
| thealistra wrote:
| But most CIs allow flaky tests :)
| anthomtb wrote:
| Binary searching your commit history and using version control
| software to automate the process just seems so...obvious?
|
| I get that author learned a new-to-him technique and is excited
| to share with the world. But to this dev, with a rapidly greying
| beard, the article has the vibe of "Hey bro! You're not gonna
| believe this. But I just learned the Pope is _catholic_. "
| Espressosaurus wrote:
| Seriously.
|
| Binary search is one of the first things you learn in
| algorithms, and in a well-managed branch the commit tree is
| already a sorted straight line, so it's just obvious as hell,
| whether or not you use your VCS to run the bisect or you do it
| by hand yourself.
|
| "Hey guys, check it out! Water is _wet_! "
| PaulDavisThe1st wrote:
| ObXKCD: https://xkcd.com/1053/
|
| I mean, do you _really_ not know this XKCD?
| monitron wrote:
| > the OG tool `git`
|
| This phrase immediately turned the rest of my hair gray. I'm old
| enough to still think of Git as the "new" version control system,
| having survived CVS and Subversion before it.
| c0brac0bra wrote:
| But did you survive rcs?
| 0x20cowboy wrote:
| Or visual source safe
| PaulKeeble wrote:
| _shudder_ I had almost forgot.
| smcameron wrote:
| and sccs
| shermantanktop wrote:
| :raises hand
|
| At my mid 90s Unix shop, everyone had to use someone's
| script which in turn called sccs. I don't recall what it
| did, but I remember being annoyed that someone's attempt to
| save keystrokes meant I had to debug alpha-quality script
| code before the sccs man page was relevant.
|
| Adding -x to the shebang line was the only way to figure
| out what was really going on.
| rco8786 wrote:
| I still remember dragging my team kicking and screaming away
| from Subversion. Which, to be fair, was _fine_. I think
| GitHub's rise was really what won it for git vs subversion. The
| others though, good riddance.
| inamberclad wrote:
| 'git bisect run' is probably one of the most important software
| tools ever.
| utopiah wrote:
| I agree with the post.
|
| I also think that typically if you have to resort to bisect you
| are probably in a wrong place. You should have found the bug
| earlier so if do not even know when the bug came from
|
| - your test coverage isn't good sufficient
|
| - your tests are probably not actually testing what you believe
| they do
|
| - your architecture is complex, too complex for you
|
| To be clear though I do include myself in this abstract "you".
| imiric wrote:
| I mean, sure--in a perfect world bugs would be caught by tests
| before they're even deployed to production.
|
| But few of us have the privilege of working on such codebases,
| and with people who have that kind of discipline and quality
| standards.
|
| In reality, most codebases have statement coverage that rarely
| exceeds 50%, if coverage is tracked at all; tests are brittle,
| flaky, difficult to maintain, and likely have bugs themselves;
| and architecture is an afterthought for a system that grew
| organically under deadline pressure, where refactors are seen
| as a waste of time.
|
| So given that, bisect can be very useful. Yet in practice it
| likely won't, since usually the same teams that would benefit
| from it, don't have the discipline to maintain a clean history
| with atomic commits, which is crucial for bisect to work. If
| the result is a 2000-line commit, you still have to dig through
| the code to find the root cause.
| lucasoshiro wrote:
| Git has some really good tools for searching code and debugging.
| A few years ago I wrote a blog post abot them, including bisect,
| log -L, log -S and blame. You can see it and the discussion here:
| https://news.ycombinator.com/item?id=39877637
| paulbjensen wrote:
| I recently used git bisect to help find the root cause of a bug
| in a fun little jam of mine (a music player/recorder written in
| Svelte - https://lets-make-sweet-music.com).
|
| My scenario with the project was:
|
| - no unit/E2E tests - no error occurring, either from Sentry
| tracking or in the developer tools console. - Many git commits to
| check through as GitHub's dependabot alerts had been busy in the
| meantime.
|
| I would say git bisect was a lifesaver - I managed to trace the
| error to my attempt to replace a file I had with the library I
| extracted for what it did (http://github.com/anephenix/event-
| emitter).
|
| It turns out that the file had implemented a feature that I
| hadn't ported to the library (to be able to attach multiple event
| names to call the same function).
|
| I think the other thing that helps is to keep git commits small,
| so that when you do discover the commit that breaks the app, you
| can easily find the root cause among the small number of
| files/code that changed.
|
| Where it becomes more complex is when the root cause of the error
| requires evaluating not just one component that can change (in my
| case a frontend SPA), but also other components like the backend
| API, as well as the data in the database.
___________________________________________________________________
(page generated 2025-11-02 23:01 UTC)