Skip to content

CI: add check to prevent merge commits in PRs - #21741

Open
Ratnesh5 wants to merge 2 commits into
ankidroid:mainfrom
Ratnesh5:fix/21607-no-merge-commits
Open

CI: add check to prevent merge commits in PRs#21741
Ratnesh5 wants to merge 2 commits into
ankidroid:mainfrom
Ratnesh5:fix/21607-no-merge-commits

Conversation

@Ratnesh5

@Ratnesh5 Ratnesh5 commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Purpose / Description

Adds a new GitHub Actions workflow that automatically prevents Pull Requests from being merged if they contain merge commits. This enforces a linear, rebased commit history and reduces manual checks by maintainers.

Fixes

Approach

Created a new workflow (check_merge_commits.yml) that runs on the pull_request event. It uses the pre-installed GitHub CLI (gh api) to query the GitHub REST API for all commits in the current PR and counts them. If any commit has more than 1 parent (parents | length > 1), it fails the workflow and prompts the contributor to rebase. Using the GitHub API avoids the need to do a slow, deep Git checkout of the repository.

How Has This Been Tested?

This was tested by verifying that the GitHub Action triggers correctly when this Pull Request is opened. The logic was verified using gh api against existing PRs to ensure it correctly identifies commits with multiple parents.

Checklist

Please, go through these checks before submitting the PR.

  • You have a descriptive commit message with a short title (first line, max 50 chars).
  • You have commented your code, particularly in hard-to-understand areas
  • You have performed a self-review of your own code
  • UI changes: include screenshots of all affected screens (in particular showing any new or changed strings)
  • UI Changes: You have tested your change using the Google Accessibility Scanner

Comment thread .github/workflows/check_merge_commits.yml Fixed
@Ratnesh5

Ratnesh5 commented Sep 5, 2026

Copy link
Copy Markdown
Contributor Author

Hi @david-allison can you have a look in this PR?

@david-allison

Copy link
Copy Markdown
Member

Hi, no need to ping until it's been a few days 😅, it's almost midnight here

@Ratnesh5

Ratnesh5 commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Hi, no need to ping until it's been a few days 😅, it's almost midnight here

Sorry!!, Will take care about that from now onwards.

@david-allison

Copy link
Copy Markdown
Member

The logic was verified using gh api against existing PRs to ensure it correctly identifies commits with multiple parents.

Could you elaborate? What did you run this against [and what did you run]?


Can you confirm that nothing here was AI-generated? It feels a bit too 'clean'

@Ratnesh5

Ratnesh5 commented Sep 7, 2026

Copy link
Copy Markdown
Contributor Author

Could you elaborate? What did you run this against [and what did you run]?

I tested this against my existing PR for issue #21671 and ran the script against it locally in my terminal.
I ran this command to simulate what github action does

gh api --paginate /repos/ankidroid/Anki-Android/pulls/21671/commits --jq '[.[] | select(.parents | length > 1)] | length'

This command asks the github API for all the commits in PR #21671, and then counts how many of those commits have more than 1 parent.
It correctly output 0. For the PRs having merge commits it would output >0 depending on how many merge commits are found in PR.

Can you confirm that nothing here was AI-generated? It feels a bit too 'clean'

Yeah I can confirm that nothing here was AI generated.
I just prefer to keep it well formatted and documented.

@david-allison

Copy link
Copy Markdown
Member

It correctly output 0. For the PRs having merge commits it would output >0 depending on how many merge commits are found in PR.

Did you test this on a PR with conflicts, and on one which goes past the paginate boundary?

@Ratnesh5

Ratnesh5 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Did you test this on a PR with conflicts, and on one which goes past the paginate boundary?

I haven't manually run the test against a PR with conflicts or one that goes past the pagination boundary but the script handles those cases. The github API endpoint that I am using simply lists the commits on the head branch and I have included the gh api --paginate flag, which automatically follows all link headers to fetch paginated results.

@david-allison

david-allison commented Sep 8, 2026

Copy link
Copy Markdown
Member
gh api --paginate /repos/ankitects/anki/pulls/4289/commits --jq '[.[] | select(.parents | length > 1)] | length' | cat
4
1
4

which I believe would break the check

edge case: the check also seems broken over 250 commits

gh api --paginate /repos/ankitects/anki/pulls/4289/commits --jq 'length' | cat
100
100
50

@Ratnesh5

Ratnesh5 commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Hm yes the gh tools when combines with --paginate and --jq it does not combine all the pages together first. It applies filter to each page individually as it arrives and yes also there is limitation of 250 commits.

To make this completely robust against edge cases, would you prefer I just switch the workflow to use a deep git checkout and pure git instead of the API? Something like this

      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 
      - name: Check for merge commits
        run: |
          MERGE_COMMITS=$(git log --merges --oneline origin/${{ github.base_ref }}..HEAD)
          
          if [ -n "$MERGE_COMMITS" ]; then
            # fail check
          fi

This approach handles infinite commits and ignores API pagination entirely, let me know what do you think about this approach..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a CI check which fails if merge commits exist in a PR's commits

3 participants