When pushing new commits to a pull request, it's essential to manage ongoing jobs effectively to prevent resource wastage and streamline the development process. In this blog post, we'll explore how you can utilize GitHub Actions' concurrency options to automatically cancel in-progress jobs when pushing new commits, enhancing productivity and resource management.

GitHub Actions provides concurrency options that allow you to control how workflows run in parallel. One such option is cancel-in-progress, which automatically cancels in-progress jobs associated with previous workflow runs when new workflow runs are triggered. By enabling this option, you can ensure that only the most recent workflow runs are executed, eliminating redundancy and preventing conflicts.

Using concurrency to cancel any in-progress job or run

To use concurrency to cancel any in-progress job or run in GitHub Actions, you can use the concurrency key with the cancel-in-progress option set to true:

concurrency:
  group: ${{ github.ref }}
  cancel-in-progress: true

Using a fallback value

If you build the group name with a property that is only defined for specific events, you can use a fallback value. For example, github.head_ref is only defined on pull_request events. If your workflow responds to other events in addition to pull_request events, you will need to provide a fallback to avoid a syntax error. The following concurrency group cancels in-progress jobs or runs on pull_request events only; if github.head_ref is undefined, the concurrency group will fallback to the run ID, which is guaranteed to be both unique and defined for the run.

concurrency:
  group: ${{ github.head_ref || github.run_id }}
  cancel-in-progress: true

Only cancel in-progress jobs or runs for the current workflow

If you have multiple workflows in the same repository, concurrency group names must be unique across workflows to avoid canceling in-progress jobs or runs from other workflows. Otherwise, any previously in-progress or pending job will be canceled, regardless of the workflow.

To only cancel in-progress runs of the same workflow, you can use the github.workflow property to build the concurrency group:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

Only cancel in-progress jobs on specific branches

If you would like to cancel in-progress jobs on certain branches but not on others, you can use conditional expressions with cancel-in-progress. For example, you can do this if you would like to cancel in-progress jobs on development branches but not on release branches.

To only cancel in-progress runs of the same workflow when not running on a release branch, you can set cancel-in-progress to an expression similar to the following:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ !contains(github.ref, 'release/')}}

In this example, multiple pushes to a release/1.2.3 branch would not cancel in-progress runs. Pushes to another branch, such as main, would cancel in-progress runs.

More information