+190 XP

End to end: from issue to merged pull request

# End to end: from issue to merged pull request

Pick up a GitHub issue, let Gemini CLI create a branch, implement and test the change, open a pull request, review the diff yourself, and merge: that is the full professional loop, and Gemini fits inside it without you giving up control of any of the gates.

You already know Gemini CLI as an agentic coding tool that runs in your terminal. This lesson wires it into a real GitHub process. The point is not "let the AI write code." The point is treating Gemini CLI as a fast, tireless contributor whose work still passes through the same review discipline you would apply to any junior engineer.

The loop we are automating

A mature GitHub workflow looks like this:

1. An issue describes a problem or feature.

2. Someone branches off main.

3. They implement a small, focused change with tests.

4. They open a pull request (PR).

5. A human reviews the diff.

6. CI passes, then someone merges.

Gemini CLI can drive steps 2 through 4 for you. Steps 5 and 6 stay human. That separation is the whole design: the model produces a proposal, and the PR is the artifact you inspect before anything touches main.

Setup: GitHub context for the CLI

Gemini CLI can shell out to git and the GitHub CLI (gh) directly, which is how it reads issues and opens PRs. Make sure both are installed and authenticated:

bash
gh auth status          # confirm you are logged in to GitHub
gh auth setup-git       # let gh act as git's credential helper
gemini --version        # confirm Gemini CLI is on your PATH

The key move is giving the CLI a project brief so it does not guess your conventions. Gemini CLI reads a GEMINI.md file at the repo root as persistent context for every session. Treat it like a contract:

markdown
# Project: billing-service

## Workflow rules
- Branch from `main` using `fix/<issue-number>-<slug>` or `feat/<issue-number>-<slug>`.
- One logical change per branch. Keep diffs small.
- Every code change needs a matching test.
- Run `pytest -q` before proposing a PR. Do not open a PR if tests fail.

## Conventions
- Python 3.12, formatted with `ruff format`.
- Conventional Commits for commit messages (`fix:`, `feat:`, `chore:`).
- Never touch `migrations/` without an explicit instruction.

That last line matters. GEMINI.md is where you encode guardrails, not just style. Anything you would tell a new hire in their first week belongs here.

Step 1: Pick up the issue

Say issue #212 reads: *"Refund endpoint returns 200 even when the payment ID is unknown; it should return 404."*

Start a session and hand the issue to the model by number. Gemini CLI can call gh issue view itself, so you do not need to paste the text:

bash
gemini
> Read issue #212 with `gh issue view 212`, then summarize the bug and
  the acceptance criteria before writing any code.

Forcing a summary first is a deliberate technique. You want the model to restate the problem in its own words so you can catch a misread before it writes a line. If the summary is wrong, correct it now. This costs you ten seconds and saves you a bad diff.

Step 2: Branch with hygiene

Once the summary is right, let the CLI branch. Because GEMINI.md defined the naming rule, you can be terse:

bash
> Create the working branch for this issue following the rules in GEMINI.md.

Gemini CLI will run something like git checkout -b fix/212-refund-unknown-payment-404. Branch hygiene means one branch maps to one issue and one logical change. This is not bureaucracy. It is what keeps the eventual diff small enough for a human to actually read, and it lets you abandon a bad attempt with a single git branch -D instead of untangling mixed changes.

If the CLI ever tries to work directly on main, stop it. Working on main is the single most common way an agent quietly corrupts a repo.

Step 3: Implement and test

Now the real work. Gemini CLI is agentic: it will read files, propose edits, and ask to run commands. Approve those actions deliberately.

bash
> Fix issue #212. Locate the refund handler, return 404 when the payment
  ID is not found, and add a test that fails on the old behavior.
  Run `pytest -q` when done and show me the result.

Two things to insist on here:

Tests are part of the change, not a follow-up. A change without a test is a change nobody can trust to stay fixed. The instruction above asks for a test that *fails on the old behavior*, which is how you prove the test is real and not a rubber stamp.

The model runs the tests, and you read the output. Do not accept "I added the fix" on faith. If pytest is red, the loop is not done. Send the failure back:

bash
> pytest failed with `KeyError: 'payment_id'` in test_refund.py:41.
  Fix the test setup, do not change the assertion.

That last clause protects you from a classic failure mode: the model "fixing" a red test by weakening the assertion until it passes. You are the one who decides what the test should prove.

Step 4: Review the diff locally, then open the PR

Before any PR exists, look at the raw diff yourself:

bash
> Show me `git diff --stat`, then the full diff.

--stat first gives you the shape of the change: which files, how many lines. If the model touched twelve files to fix a 404, something is wrong. A tight, on-topic diff is a signal the model understood the task. A sprawling one is a signal to reset.

When the diff is clean, let the CLI commit and open the PR:

bash
> Commit with a Conventional Commit message, push the branch, and open a
  PR against `main` with `gh pr create`. In the PR body, link issue #212
  with "Closes #212" and summarize what changed and how you tested it.

The Closes #212 keyword is not cosmetic. GitHub auto-closes the linked issue when the PR merges, keeping your issue tracker honest. A good PR body written by the model gives your human reviewer (or your future self) the context to review fast.

Gemini CLI: Agentic coding in your terminal

Watch on YouTube

Step 5: Human review is the gate

Here is the part that does not get automated, on purpose. The PR is now on GitHub. Open it in the browser and review the diff as if a stranger wrote it, because functionally one did.

Ask the concrete questions:

  • Does the fix match the acceptance criteria from issue #212?
  • Does the new test actually exercise the unknown-payment path?
  • Did anything sneak in that the issue did not ask for?
  • Is there a security or data implication (auth, logging a payment ID, a migration)?

This is also where a second AI reviewer earns its place. Gemini Code Assist can review pull requests on GitHub, leaving inline comments on the diff. Installed on the repo, it comments automatically when a PR opens. Treat that as a first pass that surfaces obvious issues (missing edge cases, style drift), not as the approval itself. The human still clicks Approve.

The reason to keep the gate human is accountability. When this refund code ships and something breaks at 2 a.m., "the model approved it" is not an answer anyone accepts. The person who merged owns the change. Gemini CLI drafted it; you shipped it.

Knowledge check

1. In the described workflow, why do steps 5 and 6 (reviewing the diff and merging) deliberately stay human while Gemini CLI drives steps 2 through 4?

2. What is the primary purpose of the GEMINI.md file at the repository root?

3. The lesson says the point is 'not let the AI write code' but rather to treat Gemini CLI as a fast, tireless contributor. What core principle does this framing express?

MULTIPLE CHOICE

4. Select ALL statements that correctly describe how Gemini CLI is set up to work within the GitHub process.

Select all the correct answers.

MULTIPLE CHOICE

5. Select ALL guardrails or rules that the example GEMINI.md establishes as part of the workflow contract.

Select all the correct answers.

Step 6: CI, then merge

Your branch-protection rules on main should require green CI before merge. That is standard GitHub configuration and it applies to AI-authored PRs exactly as it does to human ones. Nothing merges red.

If CI fails on something local tests missed (a linter, an integration test, a type check), feed the failure back into the same CLI session:

bash
> The `ruff check` step failed in CI on unused import in refund.py.
  Fix it and push to the same branch.

The PR updates in place, CI re-runs. Once it is green and you have approved, merge:

bash
> Merge the PR with `gh pr merge --squash --delete-branch`.

--squash collapses the model's intermediate commits into one clean commit on main, so your history reads as one change per issue rather than a trail of "fix test" commits. --delete-branch closes the loop on branch hygiene: the throwaway branch is gone, and Closes #212 retires the issue.

Why small diffs make this whole thing work

Every discipline in this lesson (one issue per branch, a test with every change, reviewing --stat before the full diff, squash-merging) points at the same target: keeping the unit of change small enough that a human can fully understand it in a few minutes.

This matters more with an AI contributor, not less. Gemini CLI can generate a 600-line change as easily as a 20-line one, and a long context window means it will happily attempt sprawling refactors. The bottleneck is not the model's ability to write code. It is your ability to verify it. Small diffs keep verification cheap, which keeps the loop fast and safe.

When you feel the urge to say "also refactor the whole payments module while you're in there," resist it. That is a second issue and a second branch.

Scaling the pattern

Once this loop is muscle memory, the same shape scales up:

  • Batch triage. Point the CLI at a set of labeled issues and have it draft PRs one at a time, each on its own branch, each still gated by your review.
  • Custom automation. For repeatable multi-step workflows beyond a single repo, the Agent Development Kit (ADK) lets you build a purpose-built agent, while Gemini CLI stays your interactive, human-in-the-loop tool.

The interactive loop is the foundation. Automate outward from it only once you trust the gate.

Key Takeaways

  • Encode your rules in `GEMINI.md`. Branch naming, "one change per branch," "every change needs a test," and hands-off directories belong in the repo so every session inherits them.
  • Make the model summarize the issue and run the tests before you trust anything. Catch misreads early, and never accept a green PR you have not seen the diff for.
  • Keep the human as the merge gate. Use Gemini Code Assist for a first-pass review, but the person who clicks Merge owns the change on main.
  • Guard `main` with branch protection and require green CI. AI-authored PRs pass the same automated gates as human ones, no exceptions.
  • Keep diffs small. Review git diff --stat first, squash-merge, delete the branch. Small units of change are the thing that makes an AI contributor safe to work with.