POV: you join a project that already has their CI/CD setup. They have a killer test suite and several github actions when branches are pushed and when PRs are opened. You are prevented from merging until all the checks are green.
These people really know what they’re doing. :) And you must be a fantastic judge of character for choosing to join them.
You complete a piece of work and open a PR and you notice that there are two Github actions that seem to run tests. The output on the PR looks something like this:
That really looks like they are running the same CI process twice… That seems like an unnecessary use of resources and time.
Even worse, you just opened a PR and somehow the (push) action succeed, and yet the (pull_request) action fails. How can that be possible? Aren’t they testing the same thing? And now this faulty, redundant Github action is preventing you from merging!
You decide to assume the best of the people who seemed to be doing so much good and you come to find out that pushand pull_requestGithub triggers do, in fact, run your tests and/or attempt to build your application using two different sets of code.
What’s the Difference
If you look at the Github documentation on their various triggers you’ll find this description under the Github SHA column of the pull_request trigger:
“Last merge commit on the GITHUB_REF branch”
Ok, cool so what is that? The “Last merge commit” is the result of the merging your changes from the branch that you are working on into the target branch.
So if you created a branch named my-feature and you are trying to merge that into main the pull_request trigger is running on the result of my-feature being merged into main.
The push trigger, on the other hand, is running on the code from your branch only.
Here are a couple pictures to help represent the code that the two triggers run on. Say at commit A you branch off and create commits E, F, and G. While you’re working your teammates push commits B, C, and D to main. You open a pull request, requesting that your code is merged from your branch into main.
Below is a representation of what thepull_request trigger runs on. It would run on H which is the result of your commits merged with the commits on main.
Now, here is a representation of what the push trigger runs on. It would run on G — which is all the commits up to A plus the three commits (E, F, and G) that you made to your branch.
Now, here is a representation of what the push trigger runs on. It would run on G — which is all the commits up to A plus the three commits (E, F, and G) that you made to your branch.
As you can see, the two workflow triggers run on different versions of the code.
Why It’s Important To Have Both
Both of these workflows are valuable and I would advocate for having both of them configured for your applications.
Why Pull Request?
I’m sure you can image why the pull request trigger would be valuable especially if a merge to main causes an automatic deploy to production (or any environment that devs or other users are in regularly).
Pull request triggered workflows are valuable because knowing that the merge commit doesn’t break the test gives you greater confidence that your branch is safe to merge.
The amount of confidence it gives you depends on a couple other things. First, I want to note that if you workflow runs tests you can only trust the result as much as you trust your test suite. Let’s assume here that you have a very robust test suite that gives you great confidence when it succeeds.
There are two scenarios that are worth walking through here.
Scenario 1: Nothing new in main branch since your PR was opened
When the pull request workflow runs it will validate that all your tests pass on the merge of main at the time the workflow runs and your branch. Let’s say that the Git log looks something like this when your workflow runs and it still looks like this right before you hit the merge button.
If the tests pass when run on commit H and you were to deploy from merges to main you can be certain that the tests passed on the code that will be deployed when you merge your PR.
Scenario 2: New commits in main branch since your PR was opened
If several things got commited between the time of the workflow running and you actually hitting the “Merge pull request” button then the state of the world before you hit merge pull request now looks something like this:
If you are deploying to production on merges to main then even though your workflow ran on H and succeeded when you hit the merge pull request button what will actually get deployed is merge commit K which your workflow never ran on.
In order to ensure that the tests run on the merge commit created by your branch merged into the latest version of main you can choose to require up to date branches in Github before merging (instructions here). This will prevent your PRs from merging unless all checks pass on the latest version of main merged with your branch.
Having the pull_request workflow is incredibly important if you want to have confidence in the state of your code before PRs merge to main and potentially deploy to production. Next, I will explain the value that the push workflow has when used with a pull_request workflow.
Why Push?
Imagine if you created a branch, tested it locally, and all the tests pass. Now you open a PR and the pull_request test run is failing. Many developers who don’t know what that is really testing against would become very confused. Having the push trigger allows additional insights into why the pull_request workflow might be failing. The key is that the branch being merged into introduces code that doesn’t play nicely with yours. While your branch may be fine in and of itself the failure of one while the other is passing indicates you should update your branch with the latest main and rerun tests locally in order to allow the two pieces of code to work together. The two workflows together provider faster feedback and more insights of what might be happening.
This configuration ensures that branches aren’t merged into main unless the merge commit passes the tests, and it allows developers quick feedback on whether or not it was changes on their own branch failing or some sort of issue in the future merge to main that caused failures.