Skip to content

Automate Git Bisect with Event Simulation

This page demonstrates how to find when bugs were introduced that can only be reproduced with interactive user actions.

Git Bisect Run

Git includes the ability to automate bisecting using a script, the typical workflow is as follows:

git bisect start
git bisect good a09c728
git bisect bad b6a0692
git bisect run bash

(replace: a09c728, b6a0692 and with the values that apply to the issue you're investigating).

Once git bisect run is finished it will report the exact revision that introduced an error.

For more details on this see Fully automated bisecting with "git bisect run".

Simulating Events in Blender

Using a script often limits the kinds actions that can be automatically tested to things that can be performed in background mode (without a graphical window).

As Blender is a graphical application, there are times it can be useful to automate interface interactions such as activating menu items, pressing keys, interactive tools that require mouse motion... etc

Since Blender 2.81 it's possible to simulate events, and more recently a utility has been added to simplify the process of creating reproducible actions that can be automated without any user input.

Working Example

This is a practical example of how git bisect run was used with event simulation to find the cause of an error.

This can be used as a template, the actions argument will need to be changed for your specific use case.

The contents of



# An exit code of 125 asks "git bisect" to "skip" the current commit.
# (useful if the build is broken for a short period of time).
cmake --build "$BUILD_DIR" --target install || exit 125

# Prevent non-critical ASAN issues from causing a non-zero exit code.
export ASAN_OPTIONS="detect_leaks=0:check_initialization_order=0"

    --factory-startup \
    --no-window-focus \
    --enable-event-simulate \
    --python tests/python/ \
    -- \
    --actions \
    'event(type="Z", value="TAP", shift=True)' \
    'operator("object.modifier_add", type="TRIANGULATE")' \
    'event(type="TAB", value="TAP")' \
    'event(type="Z", value="TAP", shift=True)' \
    'event(type="MOUSEMOVE", value="NOTHING")'

# Always use exit code 1 when non-zero,
# since exit codes over 127 from ASAN cause bisect to abort with an error.
echo "exit code: $STATUS"
if [ $STATUS -ne 0 ]; then
  exit 1

These commands track down the commit that caused the error:

git bisect start
git bisect good 3ec57ce6c7fcd3aa59c9b60139321c11f73fb7f7
git bisect bad 1a912462f4e51d069bda5084f3d702006e0a5b7e
git bisect run bash


  • For a full list of options and other examples run:

    blender -b --python tests/python/ -- --help
  • The example on this page relies on crashing for bisect to fail. If the issue you're investigating doesn't result in a crash, you will need another way to exit with a non-zero exit-code.
    This can be done using the script.python_file_run operator which will execute any Python script. This script needs to check for the error case and run sys.exit(1) for the failure state.
    The last action given should look like this:

    operator("script.python_file_run", filepath="/path/to/")
  • You may need to add event(type="MOUSEMOVE", value="NOTHING") as the last action, so the final state of the file is refreshed before exiting.
  • You may need to copy tests/python/ to a temporary location as bisecting to past revisions may remove functionality or the script it's self.
  • Menu search can be a quick way to to run an action: menu("Add Curve Bezier")
    Is the equivalent of pressing F3, typing in "Add Curve Bezier", then pressing Enter.
  • The --keep-open argument can be used to inspect the state of the file once event-simulation has finished, this is helpful when constructing actions and the state of the file is not what you expect.
    If you only want to keep blender open for a short period of time to see the result, adding dummy events is an alternative, e.g. event(type="MOUSEMOVE", value="NOTHING", repeat=10_000)
  • The script can be executed directly from the command-line, comment out the line that builds to quickly test the script.
  • To automatically run the script on file-save inotifywait (from inotify-tools) can be used.

    This allows for fast iterations when setting up command line arguments.

    bash -c 'while true; do inotifywait -e close_write; clear && bash; done'