Contents

Pull requests and CI

Cloud agents such as Codex cloud, Copilot, Jules and Devin work on their own servers and open pull requests. The gitta check compares each open pull request with the others, before anyone merges.

What the check reports

The check posts one comment on each pull request and keeps it up to date.

gitta checkcomment on pull request #124
Breaks together with #123

With a gate set, gitta merged both pull requests on top of the base branch, and your tests failed on the combination.

Does not merge with #123

The two pull requests change the same code in ways that cannot be combined.

Potentially affected

One pull request changed a symbol that the other pull request's new code uses.

Each pull request passes its own tests alone. These problems only appear when they are combined, so a normal CI run does not find them.

GitHub

Add this workflow to your repository.

# .github/workflows/gitta.yml
name: Gitta
on:
  pull_request: { types: [opened, synchronize, reopened] }
  push: { branches: [main] }          # check all open pull requests again when main moves
permissions: { contents: read, pull-requests: write }
concurrency: { group: gitta-pr-check, cancel-in-progress: false }
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - uses: gitta-io/gitta/gitta-action@v1
        with:
          version: 0.1.0
          gate: "npm ci && npm test"
          mode: ${{ github.event_name == 'push' && 'all' || 'current' }}
InputUse
versionThe gitta release to download. The checksum is verified. Leave it empty to build from source, which takes a few minutes the first time.
gateYour test command for each combination. Leave it empty for warnings and merge checks only.
modecurrent checks the pull request that started the run. all checks every open pull request.
fail-onbreaks (default) fails the check when a combination breaks or does not merge. never only comments.

To block merges that break, make the check required in branch protection. See What gitta watches and what it blocks.

Which pull request goes first

When two open pull requests break together, only the newer one (the higher number) fails the check. The older one passes, and its comment names the clash. After the older one merges, the newer one is checked again against the new base, and its own agent adapts it. So two incompatible pull requests never block each other.

ToDo
Let a newer pull request go firstMark the older one as draft, or label it gitta-skip. It is still compared and commented on, but it never makes another pull request fail.
Take an abandoned pull request out of the wayClose it, mark it as draft, or label it gitta-skip.
Merge despite a clashUse your Git host's normal override for required checks. gitta records the merge as reached_main in the audit trail.

GitLab and Azure Repos, coming next, use the same rule. The older merge request goes first.

Merge conflicts in agent pull requests

Agents that work in parallel open many pull requests against the same base. Each one passes its own CI. Trouble starts when two of them meet. Git reports a conflict only when both change the same lines, and that shows up after the first one merges. A change in meaning across files gives no conflict at all. One pull request changes a function, the other adds a call to its old form, and both merge cleanly into code that fails.

The gitta check finds both cases while the pull requests are still open.

When main moves, run the check in all mode, as in the workflow above. Every open pull request is then compared with the new base again, so a pull request that fit yesterday is checked against what merged today.

Background and cloud agents

Background agents and cloud agents work away from your machine and come back with a pull request. Claude Code background sessions, Codex cloud, GitHub Copilot coding agent, Jules and Devin all work this way. Their pull requests often arrive together, all made from the same commit.

The check treats each of them like any other pull request. It compares it with the other open pull requests and with the base, and it posts one comment that it keeps up to date. You don't have to set anything up for each agent. The check runs on the pull request events of your Git host.

To warn cloud agents while they still work, before they open a pull request, give the runners they use a team server token. See Agents in CI.

GitLab Coming next

# .gitlab-ci.yml
include:
  - remote: "https://github.com/gitta-io/gitta/releases/latest/download/gitta.gitlab-ci.yml"
variables:
  GATE: "npm ci && npm test"          # optional

Add a masked CI/CD variable GITTA_TOKEN. It is a project or group access token with the api scope, so the check can comment. The check runs on merge request pipelines and on the default branch.

On GitLab the check runs as a merge request pipeline. It compares the merge request with the other open merge requests into the same target branch, and it posts and updates one note on the merge request. To block merges that break, turn on Pipelines must succeed in the project's merge request settings.

Azure Repos Coming next

# azure-pipelines.yml, run as a build validation policy on the target branch
steps:
  - template: gitta-pr-check.yml      # copied from the release into your repository
    parameters:
      gate: "npm ci && npm test"      # optional

Give the project's build service the permission "Contribute to pull requests" on the repository, so it can comment.

On Azure Repos the template runs as a build validation policy. It compares the pull request with the other active pull requests into the same target branch and comments on it. Make the policy required to block merges that break.

Run the check by hand

 Terminal
$ gitta pr-check --pr origin/feature-a --other origin/feature-b --other origin/feature-c

Warnings and info

When both pull requests edit the same function, object or file, the check says so. It is a warning when the two edits can clash in code, for example when both add a key to the same object. Some overlaps merge cleanly and cannot change what other code does. The check lists these as info, and info never fails the check.

With --json, each result has an info field next to warnings.

The check runs in a blob-less clone (git clone --filter=blob:none) too. It fetches the files it needs in one request, so its time follows the size of the change, not the size of the repository.

Security line

When the other branch removes or switches off a security control that the new code of this pull request calls, the comment has a Security line. With --json, each result has a security field with the same text.

 Terminal
$ gitta pr-check --pr short-links --other public-profiles --base main
### Gitta: short-links against 1 other open pull request(s)

- **Security** with public-profiles: public-profiles removed the login check (`@login_required`) from `app.main.routes.user`, which short-links' new code in app/main/routes.py calls. That code may now run without a logged-in user.

The check reads the committed .gitta-security file, so your own security checks count in CI too.

Review agent pull requests

A person still reviews each pull request. The gitta comment tells the reviewer what changed around the pull request, so the review can focus on the code itself.

  1. Read the gitta comment first. It names the other open pull requests that touch the same code, and whether the combination merges and passes your gate.
  2. Look at every Security line. It names a security control that another pull request removed while this one calls the code it protected.
  3. Check changes to tests and CI. When the work is merged, gitta reports weakened checks in the merge output and the CI log, and records them in the audit trail.
  4. Check changes to AGENTS.md, CLAUDE.md and similar files. They change how every agent works.

For a full review checklist, see the guide How to review AI-generated pull requests.