Search code examples
gitshell

How to negate exit code for `git bisect run`?


I want to use bisect for the first commit that introduced some line. Using git log -S wasn't successful, so I suspect the issue be introduced in a merge commit.

I could do git bisect run ag my-search-phrase if I were looking for the first commit to remove that line. I tried to use ! ag, but git does not find executable !. I could do bash -c "..." but this is clumsy and harder to read.

Is there a more elegant way to negate the exit code so git bisect run can make use of that?


Solution

  • ! is defined by POSIX and should be available in all compliant shells, cf. 2.9.2 Pipelines, Exit Status

    If the pipeline does not begin with the ! reserved word, the exit status shall be the exit status of the last command specified in the pipeline. Otherwise, the exit status shall be the logical NOT of the exit status of the last command. That is, if the last command returns zero, the exit status shall be 1; if the last command returns greater than zero, the exit status shall be zero.

    That means it should be easy enough to write a trivial wrapper script:

    $ cat "$HOME/bin/not"
    #!/bin/sh
    ! "$@"
    $
    

    (maybe it's possible to combine it with exec?)

    Then use:

    git bisect run not ag my-search-phrase
    

    The only problem with this approach is that it turns the special exit code 125 (used by git bisect to "skip" the current commit) into 0 as well. If you need special handling of this exit code, your script becomes minimally longer to ignore exit code 125:

    #!/bin/sh
    "$@"
    case "$?" in
      125) exit 125 ;;
      0) exit 1 ;;
      *) exit 0 ;;
    esac