Most things just work with GitHub Actions. You specify the triggering event and the steps just execute. Once branching and branching strategies get involved, things can get more complicated quickly. A common question I’ve heard is “how do you know when a push
trigger will run once the Actions workflow is on multiple branches?” Hopefully, today’s post will give you some insights. Sometimes having examples helps!
TL;DR – you need a workflow to exist in the the target branch and the workflow in that branch must contain a branch filter that matches the target.
The default branch
First thing to understand – the workflows expect to exist on the default branch. In fact, it’s usually the starting point for a trigger. If your default branch is main
, then you generally need to have the workflows in the .github/workflows
directory in your repository on that branch. Some events only trigger from the default branch ( such as workflow_dispatch
, repository_dispatch
, and schedule
). Others, like push
, use the workflow defined on their branch.
The next few examples should help clarify that process.
The simple case
Let’s consider the case where we have this workflow defined on the main
branch:
1name: Explorations
2on:
3 push:
4 branches: [ "main", "feature" ]
5jobs:
6 build:
7 runs-on: ubuntu-latest
8 steps:
9 - run: echo Hello from ${{ github.ref_name }}!
Next, create a branch from main
called feature
:
In this case, a push
to main or to feature
will trigger the workflow. This is because the branch operation copied the workflow file and made it available to the feature
branch.
If this YAML is modified in the feature
branch, the workflow process will run that version of the YAML for pushes to feature
.
More complicated
What happens if the main
branch does not include a trigger for feature
?
1name: Explorations
2on:
3 push:
4 branches: [ "main" ]
5jobs:
6 build:
7 runs-on: ubuntu-latest
8 steps:
9 - run: echo Hello from ${{ github.ref_name }}!
As expected, push
to the feature branch won’t trigger the workflow. However, if we update this workflow file on feature
, that changes:
1name: Explorations
2on:
3 push:
4 branches: [ "main", "feature" ]
5jobs:
6 build:
7 runs-on: ubuntu-latest
8 steps:
9 - run: echo Hello from ${{ github.ref_name }}!
The feature
branch is related to the default branch, so triggers can occur. Similarly, if we alter the workflow file on feature
to only trigger on the feature
branch, it continues to work.
Children of the branch
What about a situation where a branch such as gamma
has been created and we later add the workflow reference on main
:
1name: Explorations
2on:
3 push:
4 branches: [ "main", "gamma", "feature" ]
5jobs:
6 build:
7 runs-on: ubuntu-latest
8 steps:
9 - run: echo Hello from ${{ github.ref_name }}!
If the workflow didn’t exist at the time gamma
was created, then the trigger doesn’t exist. The workflow needs to be present on the branch to execute the trigger. Like before, we can create a workflow file on gamma
which triggers on that branch. This enables gamma
to handle the push
events. The Git graph would look like this:
What if the workflow is created before the branch operation, as show in the next diagram?
In this case, creating the branches after the workflow file gives us the desired result. The workflow file now exists on beta
and gamma
, so the version on gamma
will run as expected.
The orphan experience
What if we try to create a new branch that is separate and distinct from our default branch (main
), but the name of that branch exists in the workflow on main
? As an example, assume that on the main
branch, we have this file:
1name: Explorations
2on:
3 push:
4 branches: [ "orphan" ]
5jobs:
6 build:
7 runs-on: ubuntu-latest
8 steps:
9 - run: echo Hello from ${{ github.ref_name }}!
An orphan branch can be created in the repository from the command line. For example:
1git checkout --orphan orphan
2ls >> Test.txt
3git add Test.txt
4git commit -a -m "Orphan branch commit"
5git push origin orphan
We now have a two unrelated branches – the default branch and an orphan branch called orphan
.
What do you think will happen? At this point, hopefully you’ve realized the answer is nothing. Because the orphan branch isn’t associated with the default branch, it doesn’t contain a copy of the workflow. As a result, the push
event is not triggered. If we create a workflow in the orphan branch, then everything works as expected.
What that means
In short, workflows will trigger on the push
event when the workflow is present on the matching branch. The logic is simple and makes the process intuitive.
For this reason, you may want to consider using a
CODEOWNERS
file to protect changes to the workflows. While this won’t prevent a new workflow from running, it will ensure that it gets reviewed before it can merge to a protected branch.
In addition, consider environment secrets if you need to avoid exposing certain secrets to the workflow without approval (or gating). Repository and org secrets are available to workflows automatically. Environment secrets, however, require specific criteria to be met in order to expose those secrets. While this might not matter as much for accessing a package management server, it’s a very important consideration for secrets related to your deployment environments (or which expose credentials with elevated privileges).
Happy DevOp’ing!