# Dw Git

> >-

- **Type:** Skill
- **Install:** `agentstack add skill-dominikwozniak-dw-solo-skills-dw-git`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [dominikwozniak](https://agentstack.voostack.com/s/dominikwozniak)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [dominikwozniak](https://github.com/dominikwozniak)
- **Source:** https://github.com/dominikwozniak/dw-solo-skills/tree/main/skills/dw-git

## Install

```sh
agentstack add skill-dominikwozniak-dw-solo-skills-dw-git
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# dw-git — all git ops, by the project's own conventions

Every git operation in one place, so the conventions live in exactly one place: the rest of the loop
delegates here by prose — the build step commits the way this skill does, the ship step pushes and
opens PRs the way this skill does.

## What it reads

Before any operation, look for a `## Git conventions` block in `AGENTS.md` (repo root) first, then in
a legacy `CLAUDE.local.md`. **First one found wins**, and its values **override** the defaults below —
commit format, default branch, branch naming, trailer policy, PR title format, rebase-vs-merge,
signing. With neither file, or neither carrying such a block, use the documented defaults.

`CLAUDE.md` is deliberately not in that list: where it exists it is a symlink to `AGENTS.md`, so
reading it is reading the first entry twice. And `AGENTS.md` comes first because it is **tracked** —
it reaches a fresh clone and a `git worktree` checkout, which is exactly where the old gitignored
copy left this skill falling back to defaults the repo had already overridden.

**Resolving the default branch** is the one lookup every other skill borrows from here: take it from
`## Git conventions`, else `git symbolic-ref --short refs/remotes/origin/HEAD`, else `main`. Never
assume `main` outright.

**Which ref of it to diff against** is the second half of that lookup, and every skill that reviews a
diff borrows it too. Fetch, then take whichever of the two already contains the other:

```bash
git fetch origin --quiet 2>/dev/null || true
base=                                        # the default — see below
git rev-parse --verify --quiet origin/ >/dev/null \
  && git merge-base --is-ancestor  origin/ \
  && base=origin/                            # origin contains local, so it is ahead
```

**Never prefer `origin/` by reflex.** It is wrong exactly when the local branch is _ahead_ — the
normal state while an unpushed `chore: shape …` commit sits on it: the merge-base reaches back past
that commit, so the diff under review swallows work the branch didn't write. Only a local branch that
has _fallen behind_ earns the remote ref, and that is the one thing the check settles. Local is the
**default** because the two cases it can't settle have no better answer: **diverged**, where neither
contains the other — say so, and use local, since the branch was cut from it — and **no `origin` at
all**. Keep the `rev-parse` guard: `--is-ancestor` exits 128 on a ref that doesn't exist, not 1, so a
chain that falls through to `origin/` on failure hands back a ref that won't resolve.

dw-git writes **no `.ai/` artifact** — its durable output is the git history itself.

## Operations

### commit

**Defaults** (overridden by `## Git conventions`):

- Subject shape and trailer are **declared, not inferred**: read the `- **Commit pattern**:` and
  `- **Commit trailer**:` bullets under `## Solo lane`. Those are what
  `enforce-commit-hygiene.sh` enforces, so a message ignoring them is refused before it reaches git —
  don't restate them here or guess at them from the log. With neither bullet the hook's own defaults
  apply: [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) and no trailer.
- What the pattern can't express, and you still owe: imperative mood, lowercase, no trailing period,
  ≤72 chars — plus a `[TICKET-XXX] ` prefix when the branch matches `^[A-Z]+-\d+`.
- Body: what + why for non-trivial changes; omit for trivial ones.
- **NO** "Generated with Claude Code" footer.
- One logical change per commit — split when session work spans concerns.

**Workflow:**

1. `git status --short` — see everything.
2. Classify: session work (created/edited this conversation) vs pre-existing /
   unrelated. **Stage session work by name** (`git add path1 path2`); never
   `git add .` / `git add -A` — `enforce-commit-hygiene.sh` refuses both where installed, and where
   it isn't the rule stands anyway. Only the user can run one.
3. Exclude sensitive files (`.env`, credentials, keys) — warn, don't stage.
4. `git diff --staged` — review what's actually staged.
5. Ticket key from branch: `git rev-parse --abbrev-ref HEAD | grep -oE '^[A-Z]+-[0-9]+'`.
   If found, prefix `[KEY] ` — but only if the declared `- **Commit pattern**:` admits it. A pattern
   anchored at `^(feat|fix|…)` does not, and the hook will refuse every commit; that is a
   contradiction in the repo's own declarations, so say so rather than fighting it.
6. Commit — `-m` for the subject, repeat `-m` for the body (no heredoc needed for a
   short body). Use plain `git commit` and follow the project's signing convention
   from `## Git conventions`; don't add `-S` or run `git config` to change signing.
   Surface an error only if the commit genuinely fails.
   - **A backtick inside a double-quoted `-m` is command substitution, and it fails silently** —
     the phrase commits **gone** and the commit still succeeds.
     `enforce-commit-hygiene.sh` refuses it where installed; where it isn't, single-quote the
     message, escape the backticks, or put the message in a file and use `-F`.
   - Read the message back with `git cat-file -p HEAD` — **not `git log`**, whose output a
     token-filtering proxy or a pager may shorten, which makes a real truncation and a trimmed
     display indistinguishable in both directions.
7. `git log --oneline -1` — confirm.

### push

**Defaults:**

- Plain `git push` for feature branches.
- Force-push is blocked by `block-dangerous-commands.sh` when installed; otherwise
  refuse it manually.
- Pushing to `main` / `master` / `develop` needs explicit confirmation first.

**Workflow:**

1. `git rev-parse --abbrev-ref HEAD`. If it's a protected branch, confirm before pushing.
2. Upstream check: `git rev-parse --abbrev-ref @{u} 2>/dev/null`.
3. No upstream → `git push -u origin "$(git rev-parse --abbrev-ref HEAD)"`; else `git push`.
4. Report the result.

### PR — "open PR", "create pull request"

**Defaults:**

- Title: same format as the commit subject.
- Body: summary + test plan derived from the commits since the base branch; **no**
  attribution footer.
- Use `.github/PULL_REQUEST_TEMPLATE.md` as the body skeleton if it exists.
- Create via `gh pr create` — never the web UI, and `gh` over a GitHub MCP server:
  less context, same result.

**Workflow:**

1. Push the branch first if it isn't pushed (see **push**).
2. Base branch: the default branch, resolved as above.
3. Build the body (PR template if present, else `## Summary` bullets +
   `## Test plan` checklist).
4. `gh pr create --title "..." --body "..."`; print the PR URL.

### sync — "sync with main", "rebase"

**Defaults:** rebase, not merge. Refuse on a dirty tree — ask the user to commit
or stash first.

```bash
git fetch origin
git rebase origin/
```

On conflicts: report them and **stop** — do not auto-resolve.

### branch — "new branch", "switch branch"

Use `git switch -c` (not `git checkout -b`). Default name: the kebab slug of what the branch is
for — the same spelling the change docs under `.ai/work/` use. Prefix a ticket key only when the
project's conventions carry one.

### stash — "stash my work"

Always with a message: `git stash push -m ""`. Never bare
`git stash`.

## Notes

- Every branch read is `git rev-parse --abbrev-ref HEAD`, never `git branch --show-current` —
  the latter prints an empty string on a detached HEAD, which silently turns a branch check
  into a no-match.
- Defaults assume `block-dangerous-commands.sh` is installed (via the scaffolder).
  If it isn't, manually refuse the same patterns (force-push, hard-reset,
  `clean -d`/`-f`).
- Modern verbs throughout: `git switch` / `git restore` over `git checkout`.

**Next:** `dw-next` to get back to building.

$ARGUMENTS

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [dominikwozniak](https://github.com/dominikwozniak)
- **Source:** [dominikwozniak/dw-solo-skills](https://github.com/dominikwozniak/dw-solo-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-dominikwozniak-dw-solo-skills-dw-git
- Seller: https://agentstack.voostack.com/s/dominikwozniak
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
