Skip to content
Agentmart
Submit a tool

gh-pr

Open a GitHub pull request (draft or ready for review) from the current branch using the gh CLI.

Skill by Dzhuneyt

IndexedMIT
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/dzhuneyt-gh-pr

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Open a GitHub pull request (draft or ready for review) from the current branch using the gh CLI. Use this whenever the user wants to open, create, raise, submit, or "ship" a PR / pull request, or says things like "open a PR", "PR this branch", "put this up for review", or invokes /gh-pr — even when they don't specify the base branch, title, or description. Handles pushing the branch, writing the title and body from the actual diff, respecting the repo's PR template, linking issues, and dropping to --draft for unfinished work.

Use cases: writing

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/gh-pr

What's inside

Skill name
gh-pr
Description
Open a GitHub pull request (draft or ready for review) from the current branch using the gh CLI. Use this whenever the user wants to open, create, raise, submit, or "ship" a PR / pull request, or says things like "open a PR", "PR this branch", "put this up for review", or invokes /gh-pr — even when they don't specify the base branch, title, or description. Handles pushing the branch, writing the title and body from the actual diff, respecting the repo's PR template, linking issues, and dropping to --draft for unfinished work.
License
MIT
Instructions
264 lines in SKILL.md · view on GitHub

Files (1)

  • SKILL.md

SKILL.md (first lines)

# gh-pr

Open a pull request from the current branch with a title and body that reflect what actually changed, not just the last commit message. The goal is a PR a reviewer can understand without reading the diff first.

Use `gh` for everything. It handles auth, the API, and returns a URL at the end. Do not script raw API calls.

## The shape of the work

Three phases, in order. The hard rule that drives the ordering: **nothing gets pushed until the work is confirmed to be on the right branch.** Phase 2 is entirely local and reversible; the first irreversible-ish action (push) is the top of Phase 3.

```
  Phase 1  Can I run?         local gates + gh auth
                              any gate fails -> stop
     |
     v
  Phase 2  Right place?       base -> assess -> branch-fit -> settle tree
                              all local, nothing pushed yet
     |
     v
  Phase 3  Open the PR        push -> compose -> gh pr create -> url
```

---

# PHASE 1 · Can I run?

## Step 0: cheap local gates

All local — no network, no push — so they fail in milliseconds before any expensive work. Order matters: cheapest and most fundamental first.

**Hard exits** — nothing downstream can recover, so bail immediately with a clear message:

1. **Not a git repo.** `git rev-parse --is-inside-work-tree`. Fastest check; run it first.
2. **`gh` not installed.** `command -v gh`. The cheap, local half of the auth check — keep it separate from `gh auth status` (network, see Preflight). "Not installed" and "not logged in" need different messages.
3. **No `origin` remote.** `git remote get-url origin` (non-zero exit = no `origin`). This skill assumes a single remote named `origin` and pushes the branch there; with no `origin` there's nowhere to push and nothing for `gh` to target, so stop here. **Fork workflows are out of scope** — pushing to a fork while basing the PR against an `upstream` repo (`--head owner:branch`) is deliberately not handled. If the only remote is named something else (e.g. `upstream`), stop and ask rather than guessing.
4. **Remote isn't GitHub.** `git remote get-url origin`, check the host. GitLab/Bitbucket/anything else → `gh` can't help, stop here.
5. **Detached HEAD or unborn branch.** `git symbolic-ref -q HEAD` (empty = detached; also catches a fresh repo with no commits). No branch means nothing to PR.

**Confirm and stop** — possible but almost always a mistake, so pause rather than refuse:

6. **On the default branch.** A PR from `main` into `main` is almost always wrong. Cheap path: if `git symbolic-ref refs/remotes/origin/HEAD` resolves locally (it only exists when the clone set `origin/HEAD`, e.g. via `git remote set-head origin -a`), compare against it here. If it's missing, skip the check here — Preflight resolves the default branch authoritatively and re-checks.
7. **Mid-operation.** Check for `MERGE_HEAD`, `.git/rebase-merge`, `.git/rebase-apply`, `.git/CHERRY_PICK_HEAD`, `.git/REVERT_HEAD`. A rebase/merge/cherry-pick/revert in flight means the tree is half-applied — a PR now is garbage.
8. **Zero commits ahead of base.** A smoke test only — base isn't resolved yet (that's Phase 2). Compare against the locally-resolved default branch (the `origin/HEAD` target from Step 0's default-branch check; skip if that ref is missing) using `git rev-list --count origin/<default>..HEAD`. **Before treating zero as a bail, check `git status --porcelain`:** a dirty tree means the work exists but is uncommitted — don't exit; carry on to Phase 2 and let "Settle uncommitted changes" commit it. Only zero commits + clean tree is a true hard exit. Phase 2 authoritatively determines the base (including any user-specified base) and supersedes this check; a non-zero count here is not a guarantee against the real base, and `origin/<default>` may be locally stale.

Once Step 0 passes, `git branch --show-current` gives the head branch for everything below.

## Preflight (network)

Costs a round trip, so it runs only after Step 0 clears.

- `gh auth status` — confirm the CLI is authenticated. If not, point the user at `gh auth login`; do not log in for them.
- **Resolve the default branch once, here.** Everything downstream (the Step 0 default-branch check, the base in Phase 2) refers back to this single value. Fallback chain — first hit wins:
  1. `git symbolic-ref --short refs/remotes/origin/HEAD` → strip the `origin/` prefix (local, no round trip).
  2. `gh repo view --json defaultBranchRef --jq .defaultBranchRef.name` (authoritative, one round trip).

  If Step 0's local check was skipped because `origin/HEAD` was missing, re-check now that the head branch isn't this default.

---

# PHASE 2 · Is the work in the right place?

Everything in this phase is local. Resolve all of it before pushing.

## Determine the base branch

Reuse the default branch already resolved in Preflight — don't resolve it again. Use that default unless the user named a different base. Stacked PRs (a feature branch targeting another feature branch) are real but rare — the user usually says so. When in doubt, ask rather than assume `main`.

## Assess local state

Gather the facts once; they feed both the branch-fit decision and the PR body.

First resolve the upstream once, because the default first-PR path has none — the branch has never been pushed, so `origin/<branch>` doesn't exist and any `origin/<branch>..HEAD` comparison errors out:

```bash
git rev-parse --abbrev-ref @{u} 2>/dev/null               # upstream, or empty
```

- **Upstream exists** → unpushed commits are `git log --oneline @{u}..HEAD`.
- **No upstream** (first PR) → there's nothing to compare against; treat *every* commit since base as unpushed and skip the `origin/<branch>` comparisons entirely.

```bash
git status --porcelain                                    # dirty tree?
git log --reverse --format='%s%n%b' origin/<base>..HEAD   # commits since base
git diff --stat origin/<base>...HEAD                      # files + scope
gh pr list --head <branch> --state open --json number,url,title  # open PR?
```

The **local-only delta** = unpushed commits + uncommitted changes. That's the work that isn't yet captured anywhere — and it's the thing the branch-fit check reasons about. On the first-PR path every commit since base is part of that delta.

## Branch-fit decision

The failure mode: the user finished feature A (maybe already PR'd), started feature B without switching branches, and is now about to push B's work onto A.

Do **not** anchor on "does the branch name match the diff." Generic/personal names (`dev`, `wip`, `dzh/misc`) match nothing and false-positive constantly, and branches legitimately grow scope. Anchor on whether the branch already has a PR and whether there's local-only work on top of it:

```
  open PR on branch?   local-only delta?   -> action
  -----------------------------------------------------------------
  no                   either                 open a fresh PR
  yes                  none                   nothing new -> stop
  yes                  some                   STOP and ask (below)
```

Only the last row stops a routine flow. In that case summarize the **delta only** (not the whole branch), e.g. "Branch `<branch>` already has open PR #123. You have 2 unpushed commits and 4 changed files since then — do these belong on this branch, or should they move to their own branch?"

Keep this gate high-precision. If it interrupts routine PRs with "are you sure you're on the right branch?", the user learns to mash through it and it stops being useful. Only the bottom-right cell stops the flow.

## If the work needs to move

The remedy forks on committed vs uncommitted, because the mechanics and risk differ sharply:

```
  move the work off this branch:

  uncommitted  ->  git switch -c <new> origin/<base>      safe, just do it
                   (then continue — PR opens from <new>)
  committed    ->  git switch -c <new> origin/<base>      you do this
                   cherry-pick the stray commits onto <new>
                   ...then reset old branch + force-push   user's call — STOP

From Dzhuneyt/skills, MIT.

More from Dzhuneyt/skills

Signals

Stars
0
Forks
0
Open issues
1
Last commit (this folder)
Aug 5, 2026 (2 months ago)

From GitHub (fetched Oct 24, 2026).

Details

License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from Dzhuneyt

Cite this page

gh-pr skill. Agent Mart. https://agentmart.dev/skills/dzhuneyt-gh-pr (last updated 2026-10-24)