Inizia
Branch Merge Readiness Review: Which Are Safe?

Branch Merge Readiness Review: Which Are Safe?

Read-only pre-merge check of your branches: conflicts, scope drift, leaked secrets and re-run tests, then a verdict per branch and a merge order.
#Ricerca
Valutazione
Servono altre valutazioni
Venduti
0
Come si usa
Scarica

How it works

Branch Merge Readiness Review takes the review-pending branches you give it (names, a one-line brief of each branch's task, the target branch) and inspects each one read-only, in a fixed order, instead of trusting "done, tests pass". It never merges, pushes or changes your repository, and it asks before running any branch code.

Phase 1 - Conflicts. A dry-run merge against the merge-base (git merge-tree), plus a pairwise check so the merge order accounts for branches that collide with each other.

Phase 2 - Scope. Every changed file is compared with the stated task: in scope, adjacent, or out of scope (deploy scripts, unrelated modules, weakened tests, CI changes).

Phase 3 - Leaks and artifacts. A diff scan for secret-looking content, sensitive file names, build output and large binaries. Matches are masked in the report.

Phase 4 - Tests re-run by the agent. Runs the project's tests itself in an exported copy, records the exact command, exit code and pass/fail counts, and compares with a baseline on the target branch. If tests cannot run, it says so and never assumes a pass.

Phase 5-6 - Verdicts and order. MERGE / MERGE_AFTER_FIX / HOLD / NEEDS_INFO per branch with an evidence table, required fixes, a recommended merge order, and the exact commands run so you can repeat every check. The secret scan is a heuristic, not a security audit.

Sample output

Real, unedited output from running this Skill on a sample problem:

> **Read-only review.** Nothing was merged, pushed, checked out over your working tree, or modified. The secret scan is a pattern heuristic, not a security audit: a clean scan does **not** prove a branch has no secrets, and a MERGE verdict is a recommendation, not a guarantee that the code is correct or safe. The human who merges owns the decision.

Repository: /tmp/demo4/repo-branch-merge-readiness-review, target: main @ b015557, reviewed on 2026-10-18.

(Sample request was hand-written, fictional fixture repo. Test execution relied on the explicit authorization in the request: exported copies only, command `python3 -I -m unittest`, no network, no dependency install.)

## Verdicts
| Branch | Tip | Verdict | One-line reason |
|---|---|---|---|
| feature/subtract | 3d222be | **MERGE** | Clean dry-run merge, in scope, nothing found by the scan, 2 tests pass on branch and on the merged tree. |
| feature/multiply | 41c7f1e | **MERGE_AFTER_FIX** | Conflicts with main in calc.py (main added negate() at the same spot); otherwise in scope and tests pass. Rebase and re-test. |
| feature/divide | c7ec94e | **HOLD** | Adds a .env containing an AWS-style key id and secret, a 3 MB minified bundle, and a deploy script, none of which the task asked for. |

## Evidence
| Check | feature/subtract | feature/multiply | feature/divide |
|---|---|---|---|
| Conflicts vs main (merge-base 6f6658b; behind/ahead 1/1 each) | CLEAN (merge-tree exit 0, tree eac2c2f) | CONFLICT in `calc.py` (exit 1) | CLEAN (merge-tree exit 0, tree f673658) |
| Scope vs brief | IN SCOPE: `subtract.py` (new), `test_calc.py` (+3 lines) | IN SCOPE: `calc.py` (+3), `test_calc.py` (+3/-1; the removed line is the import line being extended) | OUT OF SCOPE: `.env`, `deploy/release.sh`, `dist/bundle.min.js`. In scope: `divide.py`, `test_calc.py` |
| Leaks / artifacts | NONE FOUND (checked: sensitive file names, secret patterns on added lines, build paths, blobs over 1 MB; added lines only, not full history) | NONE FOUND (same checks) | FINDINGS: `.env` added; line 1 `AWS_ACCESS_KEY_ID=AKIA****` (AWS access key id pattern; cannot be confirmed as fake from the diff alone); line 2 `AWS_SECRET_ACCESS_KEY=fake****` (generic secret assignment, value looks like a placeholder but cannot be confirmed); `dist/bundle.min.js` build output, 3,000,000 bytes (about 2.9 MB), text; `deploy/release.sh` prints "deploying to prod" only, no network or file deletion seen |
| Tests re-run (python3 -I -m unittest in `git archive` export) | PASS (Ran 2 tests, OK; exit 0). Merged tree also PASS (2 tests, exit 0) | PASS on branch alone (Ran 2 tests, OK; exit 0). Merged result NOT TESTED (it conflicts) | PASS on branch alone (Ran 2 tests, OK; exit 0). Merged tree also PASS (2 tests, exit 0) |
| Author-reported (unverified) | "2 tests pass" | "2 tests pass" | "2 tests pass" |

Baseline: main alone, `Ran 1 test, OK; exit 0`. The author-reported counts matched what I saw on each branch.

## Pairwise conflicts
Only branches that are clean against main are required to be checked pairwise; I also ran the pairs that include multiply for information.

| Pair | Result |
|---|---|
| subtract + divide | CONFLICT in `test_calc.py` (both edit the same import and test lines) |
| subtract + multiply | CONFLICT in `test_calc.py` (informational; multiply already conflicts with main) |
| multiply + divide | CONFLICT in `test_calc.py` (informational) |

All three branches edit the same spot in `test_calc.py`, so whichever merges second will need a rebase.

## Required fixes
- **feature/multiply (owner: author)**: rebase onto current main, resolve the `calc.py` conflict (keep both `negate()` and `multiply()`), re-run `python3 -m unittest` and read the count the runner prints. Also expect a `test_calc.py` conflict if subtract lands first.
- **feature/divide (owner: author, then repository owner)**:
  1. Remove `.env` from the branch **and** treat the key pair as exposed: rotate or revoke it at the provider if it was ever real. Deleting the file in a new commit does not remove it from the branch history, so the branch must be recreated or have its history rewritten by its owner before merging. (This Skill does not do that.)
  2. Remove `dist/bundle.min.js` (build output) and add `dist/` to `.gitignore`.
  3. Drop `deploy/release.sh` or move it to its own reviewed branch; it is not part of "add divide()".
  4. Then rebase after subtract lands (the `test_calc.py` conflict) and re-run this review.

## Recommended merge order
1. **feature/subtract** - clean, smallest, tests pass on the merged tree. (Advice only; after it merges, main has changed.)
2. **feature/multiply** - after its rebase (it will also need to be rebased over subtract's `test_calc.py` change), re-run Phases 1 and 4.
3. **feature/divide** - blocked (HOLD); not ordered until the secret is handled and the branch is cleaned. Expect another `test_calc.py` rebase.

## Commands run
Read-only unless marked. All in /tmp/demo4/repo-branch-merge-readiness-review.
1. `git rev-parse --is-shallow-repository` -> false (exit 0)
2. `git rev-parse --verify --short main` / `feature/subtract` / `feature/multiply` / `feature/divide` -> b015557 / 3d222be / 41c7f1e / c7ec94e (exit 0 each). A first attempt that passed all refs in one call failed with exit 128 ("Needed a single revision"); nothing was changed.
3. `git merge-base main feature/<b>` -> 6f6658bcc94e (all three)
4. `git rev-list --left-right --count main...feature/<b>` -> `1 1` (all three)
5. `git merge-tree --write-tree main feature/subtract` -> exit 0; `... feature/multiply` -> exit 1 (CONFLICT calc.py); `... feature/divide` -> exit 0
6. `git merge-tree --write-tree feature/subtract feature/multiply`, `... feature/subtract feature/divide`, `... feature/multiply feature/divide` -> exit 1 each (test_calc.py)
7. `git diff --name-status main...feature/<b>` and `git diff --stat main...feature/<b>`, `git diff --numstat main...feature/<b>`
8. `git diff main...feature/<b> | grep -E '^\+' | grep -niE '<AKIA/ASIA, gh tokens, xox, sk_live_, private key block, JWT, generic secret-assignment patterns>'` (matches only in feature/divide; output masked)
9. `git cat-file -s feature/divide:dist/bundle.min.js` -> 3000000
10. `git show feature/divide:deploy/release.sh`
11. EXECUTES BRANCH CODE (authorized in the request): for b in main, feature/subtract, feature/multiply, feature/divide: `T=$(mktemp -d); git archive <b> | tar -x -C "$T"; cd "$T" && python3 -I -m unittest` -> exit 0 each (1, 2, 2, 2 tests; all OK); temp dirs removed
12. EXECUTES BRANCH CODE (authorized): same export-and-test for the merged trees `git archive $(git merge-tree --write-tree main feature/subtract)` and for feature/divide -> exit 0 each (2 tests, OK)
13. `git status --short | wc -l` -> 0 (working tree untouched)

## Not checked / NEEDS_INFO
- History before the branch point, and any commit inside a branch that adds then removes a secret (only the net diff against main was scanned).
- Whether the AWS-style values in feature/divide are real; treated as exposed because the diff cannot prove they are fake.
- Code quality, edge cases (e.g. divide by zero is not handled or tested), runtime behavior, dependency vulnerabilities, licenses.
- multiply's merged result (it conflicts), and the combined result of merging all branches together.

This is a pre-merge readiness estimate from read-only checks. Nothing was merged. Re-run after the branches change.

Use cases

  • Which of these AI-agent branches can I merge, and in what order?
  • Check my branches for merge conflicts, leaked secrets and out-of-scope changes before I merge
  • Verify "all tests pass" claims by re-running the tests instead of trusting the author
  • Pre-merge review of contractor or subagent branches against the task each one was assigned

FAQ

Will it merge or push anything? No. It uses read-only git commands and a dry-run merge; nothing is merged, pushed or checked out over your working tree.

Does it run my code? Only the project's tests, in an exported copy, and only after telling you the command and getting your OK (or relying on your explicit authorization). If it has neither, it records the tests as not run.

Is the secret scan a security audit? No. It matches common key patterns and file names in what each branch adds; a clean result is not proof of no secrets, and a hit is treated as exposed until you confirm otherwise.

What if the tests can't run or a branch has no task brief? The affected check is reported as NOT RUN, COULD NOT RUN or NEEDS_INFO. It never turns "could not check" into "passed".