Skip to content

Commit 58f7e5f

Browse files
committed
Add composite action to forbid merge commits in Pull Requests.
0 parents  commit 58f7e5f

3 files changed

Lines changed: 122 additions & 0 deletions

File tree

.github/workflows/pull-request.yml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
on: pull_request
2+
3+
jobs:
4+
check-merge-commits:
5+
runs-on: ubuntu-latest
6+
steps:
7+
- name: Checkout code
8+
uses: actions/checkout@v4
9+
with:
10+
fetch-depth: 0
11+
12+
- name: Run Forbid Merge Commits Action
13+
uses: ./

README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# "Forbid merge commits" GitHub Action
2+
3+
This action enforces clean git history that looks like this:
4+
5+
<img width="141" src="https://github.com/motlin/forbid-merge-commits-action/assets/244258/6b1bbe24-e6bd-43c4-8f1a-3d8e3691435f">
6+
7+
It fails on Pull Requests that include merge commits.
8+
9+
This rule is designed to prevent developers from merging the default branch _into_ their branch as a way of making it up-to-date. This creates [foxtrot commits](https://blog.developer.atlassian.com/stop-foxtrots-now/) and confusing git log graphs.
10+
11+
This rule is also designed to prevent using GitHub's "Update Branch" button, which merges the base branch _into_ the source branch. Instead, use the pull-down "Rebase Branch" button which rebases the source branch _onto_ the base branch. This is a common problem if "Always suggest updating pull request branches" is enabled, because "Update Branch" is the default choice in the pull-down and [it cannot be disabled or changed](https://github.com/orgs/community/discussions/12032).
12+
13+
## Handling failure messages
14+
15+
If this action fails due to the presence of merge commits, it will print out the offending commits and fail the workflow. To resolve this, you will need to rebase your branch onto the base branch.
16+
17+
If the "Rebase Branch" button is available, you can use that.
18+
19+
<img width="335" src="https://github.com/motlin/forbid-merge-commits-action/assets/244258/dbb60788-3908-41f9-81db-4ba568d97fd5">
20+
21+
Otherwise, you can rebase your branch locally using the following commands:
22+
23+
```bash
24+
git pull <upstream-remote> <base-branch> --rebase
25+
git push --force-with-lease origin <branch_name>
26+
```
27+
28+
The `<upstream-remote>` is usually named `upstream` or `origin`. The `<base-branch>` is usually named `main` or `master`.
29+
30+
## When this Action is not applicable
31+
32+
Sometimes including merge commits in Pull Requests is acceptable. For example, when maintaining a library it is common to fix problems on stable branches and merge the fixes into the default branch. In such cases, you may want to configure this action to run only on some branches, or remove it entirely.
33+
34+
## How to add this action to your repository
35+
36+
This action is designed trigger only `on: pull_request` events. To add this action to your repository, you can add it to an existing workflow file that triggers only on Pull Requests, or create a new workflow file.
37+
38+
To add this action to your repository, you need to create a new workflow file in the `.github/workflows/` directory of your repository.
39+
40+
Here is an example `.github/workflows/pull-request.yml` workflow.
41+
42+
```yaml
43+
on: pull_request
44+
45+
jobs:
46+
forbid-merge-commits:
47+
runs-on: ubuntu-latest
48+
steps:
49+
- name: Run Forbid Merge Commits Action
50+
uses: motlin/forbid-merge-commits-action@main
51+
```
52+
53+
## Recommended settings
54+
55+
This action is designed to be used with the settings "Allow merge commits" and "Always suggest updating pull request branches."
56+
57+
<img width="808" src="https://github.com/motlin/forbid-merge-commits-action/assets/244258/138ab7c1-6c14-4b1b-8bc4-a61fc3f6cfb6">
58+
59+
## How is this different from the "Require Linear History" status check?
60+
61+
"Require linear history" does not allow merges at all. It is used with "Squash and Merge" or "Rebase and Merge" and creates a completely linear history.
62+
63+
This workflow is meant to be used with the "Merge" button on Pull Requests. These merge commits let us see who clicked the merge button, and which commits were grouped together into a single Pull Request with multiple commits.
64+
65+
## Prior art
66+
67+
This action is similar to [cyberark/enforce-rebase](https://github.com/cyberark/enforce-rebase), which runs using a deprecated version of Node. This action is implemented as a Composite Action using yaml, which is easier to keep up-to-date.

action.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: 'Forbid Merge Commits'
2+
description: 'A composite action to forbid merge commits in pull requests.'
3+
branding:
4+
icon: 'git-merge'
5+
color: 'purple'
6+
7+
runs:
8+
using: "composite"
9+
steps:
10+
- name: Checkout code
11+
uses: actions/checkout@v4
12+
with:
13+
fetch-depth: 0
14+
15+
- name: Check for merge commits
16+
run: |
17+
set -Eeuo pipefail
18+
19+
MERGE_COMMITS=$(git log --merges --format=%H origin/${{github.base_ref}}..refs/remotes/pull/${{github.event.pull_request.number}}/merge^2 --)
20+
if [ -n "$MERGE_COMMITS" ]; then
21+
22+
echo '::error title=Found merge commits::Found merge commits. Refer to https://github.com/motlin/forbid-merge-commits-action#handling-failure-messages for guidance.'
23+
24+
echo -e '## Found merge commits.\n\nRefer to [handling failure messages](https://github.com/motlin/forbid-merge-commits-action#handling-failure-messages) for guidance.\n' >> $GITHUB_STEP_SUMMARY
25+
26+
for COMMIT_HASH in $MERGE_COMMITS; do
27+
echo "::warning::Merge commit: $COMMIT_HASH"
28+
echo "::group::git show $COMMIT_HASH"
29+
git show $COMMIT_HASH
30+
echo '::endgroup::'
31+
32+
echo '' >> $GITHUB_STEP_SUMMARY
33+
echo '```console' >> $GITHUB_STEP_SUMMARY
34+
git show $COMMIT_HASH >> $GITHUB_STEP_SUMMARY
35+
echo '```' >> $GITHUB_STEP_SUMMARY
36+
done
37+
38+
exit 1
39+
else
40+
echo 'Success: No merge commits found'
41+
fi
42+
shell: bash

0 commit comments

Comments
 (0)