CommunityProductivity & Collaborationgithub.com

git-coda

Automated Git workflow one-click ship assistant. Executes the complete 'ship' flow: create a new branch from the latest main → commit → push → create PR → squash merge → back to main. Invoking 'ship' itself authorizes the full process; it automatically infers branch names, commit messages, and PR content, and proactively resolves Git conflicts, tests, lint, type checks, builds, and CI failures, continuously fixing and retrying until the changes are successfully merged.

What is git-coda?

git-coda automates the entire 'ship' workflow for developers using Claude Code, Cursor, Codex, or similar AI agents. It takes the current workspace changes and completes the full pipeline: branching from the latest main, committing, pushing, creating a PR, squash merging, and returning to main. The tool is designed to handle everything autonomously—it infers branch names using conventional commits format, generates commit messages and PR descriptions from the diff, and automatically resolves merge conflicts, test failures, lint errors, type issues, build problems, and CI failures through a structured fix-and-retry loop. It only pauses for external blockers like missing authentication, permission issues, or repository protection rules that the environment cannot resolve. The core principle is that invoking 'ship' signifies full authorization to proceed without asking for confirmation on intermediate decisions like branch naming, commit messages, or whether to continue after failures. It supports GitHub via `gh` CLI integration and is intended for use with AI coding agents that can execute shell commands and interpret repository context.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/rufus-fan/git-coda/tree/HEAD

Installed? Explore more Productivity & Collaboration skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

git-coda — One-Shot Ship Workflow

git-coda is the project name; coda (finale) is the closing section of a movement, gathering the entire development history into a single note and landing back on main. The verb for the workflow is still ship.

Goal & Success Criteria

Take the current workspace changes and run them through this complete path:

Current changes → Create new branch from latest main → commit → PR → squash merge → back to main

Calling ship signifies authorization to execute the entire workflow. The process should run continuously without asking for confirmation on branch names, commit messages, PR titles, PR descriptions, conflict resolutions, verification fixes, or whether to continue.

This authorization includes:

  • Modifying current functional code to make it compatible with the live functionality of the latest main.
  • Fixing test, lint, type, build, and CI issues caused by the current changes or conflicts.
  • Creating necessary fix commits and pushing them repeatedly.
  • Syncing with the latest main before merging, resolving new conflicts, and re-verifying.

The workflow is only considered complete when all of the following conditions are met:

  1. The PR has been successfully merged into main; "PR created" or "auto-merge enabled" is not sufficient.
  2. Required checks have passed, or the repository has no runnable checks.
  3. The local branch has returned to main and has been fast-forwarded to the merged commit if possible.

Core Execution Principles

  • The default result of ship is "successful release", not "found issues and handed them back to the user".
  • When a command fails, diagnose the cause first and resume the workflow; do not mechanically repeat the same failed command.
  • Use the current live functionality on origin/main and the product goal of the current changes as joint constraints; prioritize retaining both.
  • Fix the root cause; do not fake passing by skipping tests, deleting assertions, disabling rules, or using --no-verify.
  • Do not use destructive methods like force push, reset --hard, discarding commits, or overwriting user changes.
  • Only pause when there is a lack of authentication/permissions, a need for external approval, persistent platform/network unavailability, or when the intent truly cannot be determined from the code and context. When pausing, explain only the single action required from the user.

Step 0: Information Gathering

Before starting, check the current state:

git status --short --branch
git branch --show-current
git diff --stat
git diff --cached --stat
git remote -v
gh auth status

Record the current branch, uncommitted changes, and unpushed commits to avoid losing user work. If there are no uncommitted changes, check if there are commits on the current branch pending release relative to origin/main. If neither exists, indicate there is nothing to publish and stop.

Automatically determine the following information:

1. Branch Name

  • Use directly if already provided by the user.
  • Otherwise, infer from the changes in the format <type>/<short-desc>.
  • Follow existing branch prefixes or naming conventions in the target repository; use a semantic name if there is no convention.
  • If a branch with the same name already exists locally or remotely, automatically append a short suffix to avoid interruption due to naming conflicts.

2. Commit Message

  • Use directly if already provided by the user.
  • Otherwise, generate a Conventional Commits format from the full diff: <type>(<scope>): <description>.

3. PR Title and Body

  • PR title defaults to the commit message.
  • PR body is automatically generated from the diff, containing 2–3 bullet points, an overview of changed files, and verification results.
  • Do not separately ask for the PR name or body.

After determining these, briefly inform the user of the branch and commit to be used, then continue immediately without waiting for a reply.

Step 1: Sync Main Branch

If there are workspace changes, first create a stash with a unique identifier and record the corresponding reference; do not create an empty stash if there are no changes.

git stash push --include-untracked -m "git-coda: <timestamp>"
git fetch --prune origin

After fetching, check for commits pending release based on the original branch and HEAD recorded in Step 0. If the original feature branch already has commits, keep that branch, merge origin/main directly, then restore the current stash; do not switch to main first and then decide whether the original branch has commits. Only create a new release branch from origin/main if the original branch has no commits pending release.

First, verify the target main branch from the remote HEAD or repository configuration; main below is a placeholder; if the repository uses master or another name, replace all occurrences with the actual branch.

Inform the user of the latest main branch commit hash.

If the local main cannot be fast-forwarded:

  1. Check for local unique commits; do not delete or overwrite them.
  2. Create the release branch directly from the latest origin/main and continue the release process.
  3. When finally returning to main, keep these local commits and clearly state that the local main was not overwritten; this does not affect the completed online merge.

Step 2: Create Branch

git checkout -b <branch-name> origin/main

If the current work is already on a feature branch with pending release commits, you may continue using it; first merge the latest origin/main and resolve any conflicts by following the "Conflict Handling Process". Do not re-commit the same changes.

Step 3: Restore Changes and Commit

git stash apply <recorded-stash>
git add -A
git commit -m "<commit-message>"

If stash apply results in conflicts, resolve them following the "Conflict Handling Process". After confirming all changes have been restored and committed, delete the stash created during this process; do not accidentally delete any pre-existing user stashes.

If commit hooks fail, treat them as verification failures: fix the root cause, re-stage, and re-commit without using --no-verify.

Conflict Handling Process

The following process applies to stash apply, merging the latest main, non-fast-forward remote branches, and PR merge conflicts.

  1. Gather facts:

    git status
    git diff --name-only --diff-filter=U
    git log --oneline --left-right origin/main...HEAD
    
  2. Examine the base, current branch, and other branch versions of each conflicting file, and read the relevant callers, tests, types, configurations, and recent commits. Do not just look at the conflict markers, and do not blindly select ours or theirs for the entire file.

  3. Determine the intent on both sides:

    • origin/main represents the current live behavior; it must be preserved unless the current feature explicitly replaces it.
    • The current branch represents the goal of the current feature; do not silently delete its changes to resolve a conflict.
    • If both sides add valid functionality, integrate the interfaces, data flows, and boundary conditions so both work.
    • Update conflicting tests according to the final product behavior; regenerate lock files and generated files using the repository's designated tool.
  4. Edit until there are no conflict markers, execute git add, and confirm git diff --name-only --diff-filter=U is empty.

  5. Run minimal verification related to the conflicting files, then run the full verification required by the repository.

  6. Create a merge or fix commit and continue the original workflow.

If it is impossible to determine the correct resolution solely from the conflict blocks, continue gathering evidence from the implementation, tests, call chains, commit history, and project documentation. Only ask the user if the two behaviors are mutually exclusive and the product intent remains unclear, and present the options, their impact, and a clear recommendation in one go.

Step 3.5: Local Verification

Based on the current changes and repository documentation, look for existing verification commands:

  1. First read AGENTS.md, CONTRIBUTING.md, and README.md.
  2. Then check project files like package.json, pyproject.toml, Makefile, and CI configuration.
  3. If necessary, use the project's existing package manager (based on lock files) to install dependencies; do not upgrade dependencies without reason.
  4. First run checks directly related to the scope of the changes, then run lint, typecheck, test, or build as required by the repository.
  5. If no trusted commands are found, clearly inform the user which verifications were skipped and why; do not invent commands.

Verification Failure Fix Loop

Do not pause when verification fails; handle it with the following loop:

  1. Keep the complete error output, identify the first root cause, not just the last cascading error.
  2. Determine whether the failure is from product code, test expectations, types, formatting, dependencies, configuration, or the environment.
  3. Apply the minimal correct fix that satisfies both the live functionality and the current feature:
    • Prefer the repository's existing formatter or lint autofix, then handle remaining issues.
    • Fix code defects by modifying code.
    • Only update tests if the current feature intentionally changes behavior and the original expectation is now outdated; do not weaken, skip, or delete valid tests.
    • If the environment is missing dependencies, restore it according to the project lock files; do not use this as an opportunity to perform unrelated upgrades.
  4. First re-run the failed minimal check, then re-run all required checks.
  5. If new failures appear, continue diagnosing and fixing until all pass.

Fixes made before the first push can be included in the current commit; fixes made after the first push should be created as new commits and pushed normally; do not force push to clean up history. As long as each round produces new evidence or substantial progress, continue advancing; do not give up due to the number of failures.

Step 4: Push and Create PR

git push -u origin <branch-name>

When push is rejected, handle based on the type:

  • Remote branch with the same name contains unrelated content: automatically use a unique branch name and push.
  • Remote branch with the same name belongs to the same feature and has new commits: fetch and merge the remote branch, resolve conflicts, verify, and push again.
  • Temporary network or GitHub failure: retry briefly and check service recovery.
  • Missing authentication or write permission: preserve the full working state and ask the user to complete authorization.

Create a PR using gh pr create:

  • Base: main
  • Head: new branch
  • Title: the commit message
  • Body: contains 2–3 bullet points, an overview of changed files, verification results, and 🤖 Finale via git-coda

If a PR already exists, reuse it; do not create a duplicate. After successful creation, show the PR URL to the user, then continue without waiting for a reply.

Step 5: Wait for CI and Fix

Use available repository commands like gh pr checks <pr-number> --watch to wait for required checks.

When checks fail:

  1. Use commands like gh pr checks or gh run view --log-failed to read the failing tasks and logs.
  2. If reproducible locally, first reproduce the issue, then fix the root cause following the "Verification Failure Fix Loop".
  3. Commit the fix, push normally, and wait for CI again.
  4. Repeat until all required checks pass.

If a check is pending for a long time, inspect the workflow, concurrency queues, and GitHub status; if it's possible to re-run the failed tasks, do so. Only ask the user if a task requires approval from someone with permissions or if an external service is persistently unavailable.

Step 6: Sync with Latest main and Squash Merge

Before merging, sync with the main branch again:

git fetch origin main
git merge --no-edit origin/main

If there are conflicts, resolve them using the "Conflict Handling Process", re-run local verification, push, and wait for CI. Then merge directly:

gh pr merge <pr-number> --squash --delete-branch

If the merge fails due to base update or conflicts, repeat the sync → resolve → verify → push → wait for CI loop, then attempt to merge again. If the repository supports a merge queue, enter the queue and wait until the PR is confirmed to be merged.

Do not bypass branch protection rules. If required approvals, signatures, or permissions are missing, this is an external blocker: display the exact return message from GitHub, explain the steps already completed, and state the single action the user needs to perform.

Step 7: Return to main and Confirm Results

git checkout main
git pull --ff-only origin main
git status --short --branch
gh pr view <pr-number> --json state,mergedAt,mergeCommit,url

Confirm the PR state is "merged", and print the final main commit hash. If the local main has pre-existing unique commits that prevent fast-forwarding, keep them without performing destructive operations; still confirm that the remote PR has been merged and clearly explain the local state.

Print the final status:

🚀 Ship Complete!
  ✓ Branch <branch-name> merged into main
  ✓ Local verification and required CI passed
  ✓ Currently on main, synced with latest code (<commit-hash>)
  ✓ PR: <pr-url>

Error Handling Principles

  • Briefly state what is being done before each step.
  • After any command fails, diagnose, fix, and retry, always aiming for a successful merge.
  • Do not use force push, reset --hard, or any other destructive recovery methods.
  • Proactively resolve conflicts while protecting both the latest live functionality and the current feature's goals.
  • Proactively fix test, lint, type check, build, commit hook, and CI failures.
  • Do not ask for confirmation on automatically inferred branch names, commit messages, PR titles, PR descriptions, or whether to continue.
  • Do not treat repairable failures, multiple debug rounds, or process duration as blockers.
  • Only pause for external conditions that the current environment truly cannot resolve; preserve the branch, commits, and logs needed to resume work.
  • When pausing, provide only the specific, minimal, actionable user action; the process can be resumed from the same point after completion.

Common Edge Cases

CaseHandling Method
Currently on a non-main branch with only workspace changesstash → create a new branch from origin/main → apply → resolve conflicts
Current branch already has pending release commitsKeep the commits, merge latest origin/main, and continue
No uncommitted changesCheck for pending release commits relative to origin/main; only stop if neither exists
Branch name already existsAutomatically generate a unique suffix; if a remote branch with the same name is for the same feature, reuse and integrate
stash apply or merge conflictAnalyze intent on both sides, integrate implementations, verify, and continue
lint/test/typecheck/build failuresFix root cause and loop verification; do not hand failures to the user
CI failuresRead logs, reproduce locally, fix, push, wait for next CI round
main updated before mergeMerge latest origin/main, resolve conflicts, and re-run the verification loop
gh not logged inPrompt to run gh auth login
Required manual approval or no write permissionPreserve the state, explain the single external action needed from the user
User specifies --no-squashUse --merge

Related Skills