Perform git operations, manage branches, handle multi-remote setups, create PRs/MRs, cut releases, and maintain audit-grade change history across GitHub, GitLab, and Forgejo. The goal is clean, signed, traceable history that satisfies both engineering standards and compliance requirements (PCI-DSS 4.0).
Target versions (October 2026):
- git: 2.56.0 (current stable, 2026-09-28). Additions include
git refscreate/delete/update/rename,fetch.followRemoteHEAD, andgit history drop; 2.55 added Linux fsmonitor, remote-group push, and parallel compatible hooks. - GitHub CLI (
gh): 2.102.0 - GitLab CLI (
glab): 1.120.0 - Forgejo CLI (
fj): 0.6.0 (latest Codeberg release, rechecked 2026-10-02;fj pr merge --helpconfirmed September 25; sourcecodeberg.org/forgejo-contrib/forgejo-cli). Rust-written, official community CLI. Covers PRs (incl. AGit), issues, repos, releases, tags, actions. - Forgejo: v16.0.5 current; v15.0.9 is the current LTS (both 2026-09-17). Critical RCE (CVE-2025-68937) patched in v13.0.2+.
- prek: 0.5.4 (Rust, recommended) or pre-commit: 4.6.2 (Python, largest ecosystem)
- git-filter-repo: 2.47.0
- gitleaks: 8.30.1 (secret scanning)
- cosign: 3.1.3 (Sigstore, for tag/release signing context)
This skill covers five domains depending on context:
- Operations - commits, branches, merges, rebases, stashing, bisect, reflog, recovery
- Remotes & forges - multi-remote setups, GitHub/GitLab/Forgejo differences, mirroring
- PR/MR workflow - feature branches, review flow, merge strategies, release cutting
- Security - commit signing, credential management, hooks, secret scanning, history scrubbing
- Compliance - PCI-DSS 4.0 change management, audit trails, branch protection as controls
When to use
- Creating commits (message style, signing, authorship)
- Managing branches (creation, cleanup, protection, naming)
- Working with remotes (push, pull, fetch, multi-remote sync)
- Creating PRs/MRs (title, description, review process, merge strategy)
- Cutting releases (tagging, changelog, GitHub/Forgejo releases)
- Resolving merge conflicts or rebasing
- Recovering from mistakes (reflog, reset, revert, cherry-pick, bisect)
- Configuring git (aliases, hooks, attributes, credentials, signing)
- Scrubbing sensitive data from history (filter-repo)
- Setting up branch protection rules or rulesets
- Multi-forge workflows (mirroring, token management, SSH keys)
- PCI-DSS change management evidence
When NOT to use
- CI/CD pipeline design - use ci-cd; this skill handles git operations within pipelines, not pipeline architecture
- PR/MR code review - use code-review; this skill creates PRs, doesn't review code in them
- Full application security audit - use security-audit; this skill covers secrets in git history and git-specific security, not application-level vulnerability assessment
- Docker image tagging strategy - use docker; this skill handles git tags, not container tags
- Post-session or post-merge documentation sweeps (README, changelog, runbooks) - use update-docs
AI Self-Check
AI tools consistently produce the same git mistakes. Before performing any git operation, verify against this list:
- Read before rewrite. Never
Edit/Writefiles withoutReading them first. Nevergit commitwithout checkinggit status+git diff. - No destructive ops without confirmation.
reset --hard,push --force,branch -D,clean -fd,checkout ., andrebaseon shared branches all require explicit user approval. Propose safer alternatives first (--force-with-lease,revert, new branch,stash). - Authorship correct. Check the project's instruction file for author overrides. Many setups have a local git config that's wrong for the remote (e.g., Forgejo identity vs GitHub identity).
- Commit message format. Follow the project's convention (check recent
git log). Default: conventional commits (type(scope): description). - No secrets in commits. Check
git diff --cachedfor API keys, tokens, passwords,.envfiles, private keys before committing. If found, unstage immediately. - No AI attribution in commits. Never add
Co-Authored-Bylines or any mention of AI tools in commits. No exceptions unless the project explicitly requires it. - Instruction-file policy respected. Follow the repo's policy for
AGENTS.mdor other instruction files. Never commit local agent state directories like.claude/, and never mention local-only tooling files in commit messages. - No tool-specific paths in commits.
.claude/,.cursor/,.superpowers/,.worktrees/,docs/local/,PLAN.md,SECURITY-AUDIT.mdare local artifacts. Verify.gitignorecovers AI tooling artifacts BEFORE staging (.claude/, .cursor/, .codex/, PLAN.md) - Branch target correct. Verify you're on the right branch before committing. Verify the PR/MR targets the right base branch.
- Requester authorized for admin changes. In shared chats, do not commit or push infrastructure, Kubernetes, secrets, firewall, or other admin changes from a participant who is not authorized to approve them. Stop and ask the authorized owner first.
- Remote target correct. Multi-remote setups exist. Check which remote(s) to push to. Some projects push to multiple remotes (e.g., Forgejo + GitHub).
- Signing configured. If the project requires signed commits, verify signing works before committing (
git log --show-signature -1). - No
--no-verify. Never skip pre-commit hooks unless the user explicitly asks. Hooks exist for a reason - fix the underlying issue instead. - No interactive flags. Never use
-i(interactive) flags (git rebase -i,git add -i) in automated contexts - they require TTY input. - Tags pushed separately.
git pushdoesn't push tags by default. Alwaysgit push --tagsorgit push origin <tag>explicitly. - Feature branch up to date. Before creating a PR/MR, rebase onto the latest base branch to avoid merge conflicts.
- Lock files regenerated after conflict resolution. After resolving conflicts in dependency files (
package.json,Cargo.toml,go.mod,pyproject.toml), re-run the package manager to regenerate the lock file. Never manually merge lock files. Then regenerate:npm install,yarn install,go mod tidy, orcargo generate-lockfile. - Force-push safety. If force-push is needed, always use
--force-with-lease(refuses if remote has unfetched commits). Plain--forcerequires explicit user approval and team coordination. - Version info dated. When citing tool versions, include a date so readers know when to re-check. Stale version numbers cause silent breakage.
- Forge-CLI subcommands verified. Before scripting
fj/gh/glab/teacommands in a runbook, hooks, or CI, confirm the subcommand and flags exist on the target version (<cli> <cmd> --help). These CLIs add, rename, and remove subcommands across minor versions; docs lag behind the binary. - Ref safety checked: branch, remote, upstream, and worktree path are verified before history edits
- Recovery path known: reflog, backup branch, or bundle exists before destructive history operations
- Cross-cutting agent hygiene applied - see
references/agent-hygiene.md
Performance
- Use path-limited
git log,git diff, andgit grepbefore whole-history scans. - Fetch only needed remotes/branches in large repos when full prune is unnecessary.
- Keep commits small enough for review and bisect, but not so small that they split one behavior across many commits.
Workflow
Step 1: Identify the forge and project context
| Signal | Forge |
|---|---|
.github/ directory, gh CLI |
GitHub |
.gitlab-ci.yml, glab CLI, user says "work" |
GitLab |
.forgejo/ directory, user says "home" |
Forgejo |
Multiple remotes in git remote -v |
Multi-forge |
Read the project's instruction file (AGENTS.md or equivalent) for:
- Commit conventions (message format, scope list, authorship overrides)
- Branch strategy (trunk-based, feature branches, release branches)
- Remote setup (which remotes exist, which to push to, SSH keys)
- Release process (version bump files, tag format, changelog)
- Signing requirements (GPG, SSH, or unsigned)
- Content restrictions (domains, tool names, paths that must not appear in git history)
Step 2: Determine the operation
- "Commit this" / "save my work" -> Commit workflow (Step 3a)
- "Create a PR/MR" -> PR/MR workflow (Step 3b)
- "Cut a release" -> Release workflow (Step 3c)
- "Fix this mess" / "undo" / "recover" -> Recovery operations (Step 3d)
- "Pull failed" / "branches diverged" -> Diverged branch resolution (Step 3e)
- "Pull/update all repos under a directory" -> Bulk repo update workflow (Step 3f)
- "Set up signing" / "configure git" -> Configuration (references)
- "Clean up history" / "scrub secrets" -> History rewriting (references)
- "Set up branch protection" -> Protection rules (references)
Step 3a: Commit workflow
Copy this checklist and track progress:
- Inspect state and diff
- Stage selected files only
- Review the staged diff (secrets, debug code, unrelated changes)
- Write the message in the project's convention
- Commit with required authorship and signing
- Verify authorship and signature before pushing
- Check state:
git status(never-uallon large repos) +git diff(staged and unstaged) - Stage selectively:
git add <specific files>- nevergit add -Aorgit add .without reviewing what's included. Check for secrets, binaries, generated files, AI tooling artifacts. - Check the diff:
git diff --cached- read what you're about to commit. Look for debug code, TODO comments, accidental changes to unrelated files. If anything does not belong, unstage it (git restore --staged <file>) and return to step 2. - Write the message: follow the project's convention. Default format:
type(scope): concise description
Optional body explaining *why*, not *what*.
Select type from: feat, fix, docs, refactor, chore, ci, build, revert.
Extended types (use if the project convention allows): test, perf, security.
Always check the project's instruction file and recent git log first - the project may have a
different type list or naming convention. Project instructions override these defaults.
Scopes are strongly recommended but not blindly enforced. A scope adds context that makes
git log --oneline scannable: fix(auth): token expiry vs fix: token expiry. Use the
component, module, or area name. Skip the scope only when the change is truly cross-cutting
or the project doesn't use scopes.
Breaking changes: append ! after the type/scope: feat(api)!: drop v1 endpoints.
For detailed breakage notes, add BREAKING CHANGE: in the commit body footer.
Message guidelines:
- Imperative mood ("add feature", not "added feature" or "adds feature")
- First line under 72 characters
- Body wrapped at 72 characters
- Explain why the change was made, not what changed (the diff shows what)
- Reference issue/ticket numbers where applicable
- Casual, human-sounding tone. Like a competent human wrote it, not an AI.
Good:
fix(caddy): self-healing volume permissions,feat(auth): add OIDC loginBad: "fix stuff", "wip", "update files", "enhance the robustness of the authentication module" - Plain ASCII only. No em-dashes, curly quotes, ligatures, or fancy punctuation in commit messages.
- Never mention local instruction files or AI tooling in commit messages or bodies. If you're updating local-only instruction files alongside code changes, don't include them in the commit.
- Never add
Co-Authored-Byor AI attribution lines. NoSigned-off-by: AI. No mentions of specific AI tools in the commit metadata.
- Commit: with any required authorship overrides and signing flags from project config.
- Verify:
git log -1 --format="%h %s%n Author: %an <%ae>%n Committer: %cn <%ce>"- check authorship is correct before pushing. If it is wrong and the commit is unpushed, fix the identity config, rungit commit --amend --reset-author --no-edit, and repeat this step.
Step 3b: PR/MR workflow
First check: does the project use feature branches? Read the project instruction file. Some projects
(especially solo projects) work directly on main by preference. The default here assumes
collaborative development with review. Adapt to the project's actual workflow.
Read references/forge-workflows.md for forge-specific PR/MR creation
patterns (GitHub gh pr create, GitLab glab mr create, Forgejo fj pr create or web UI/API).
Detect the forge CLI first (command -v gh, glab, or fj); if it is missing, use the install
table or the REST API fallback in that reference.
Select verification from the diff and repository policy. Opening a PR does not by itself justify a full build, integration suite, or release pipeline. Run affected checks and honor required merge gates; reuse passing results for the same revision and relevant inputs. If CI does unnecessary work, use ci-cd to scope its triggers and jobs rather than bypassing checks or repeatedly dispatching the full pipeline.
General flow:
-
Create feature branch:
git checkout -b type/short-description(e.g.,feat/user-search,fix/auth-bypass). Keep branch names lowercase, hyphenated, prefixed with type. -
Make changes: commit early, commit often. Each commit should be a logical unit.
-
Rebase onto base:
git fetch origin && git rebase origin/main(or whatever the base branch is). Resolve conflicts: look for<<<<<<<,=======,>>>>>>>markers, keep the correct content from both sides (often both additions belong), thengit addandgit rebase --continue. After resolving conflicts in dependency files (package.json,Cargo.toml,go.mod, etc.), re-run the package manager to regenerate the lock file. Never merge the base into the feature branch. For merge strategy guidance, seereferences/forge-workflows.md.Dependency file conflicts (
package.json,go.mod,pyproject.toml): keep additions from both branches; when the same dependency has conflicting version pins, reconcile both branches' constraints and intent, then let the package manager resolve a compatible version and validate the affected behavior. Never hand-edit the lock file - always regenerate it by running the package manager (npm install,go mod tidy,uv sync, etc.) after resolving the manifest conflict. Do not use--oursor--theirsfor dependency manifest conflicts - these silently drop one branch's additions. -
Push:
git push -u origin feat/short-description. Then verify the remote actually advanced: comparegit rev-parse HEADwith the forge PR/MR head SHA (gh pr view ...,glab mr view ..., or forge API). Do not rely on a terse or aliased push wrapper alone. If upstream tracking is missing or odd, push the exact refspec explicitly and re-check the PR/MR head before claiming the update landed. -
Create PR/MR: with a clear title (under 70 chars), body with summary + test plan.
-
Review cycle: address feedback with follow-up commits by default. Rebase and push with
--force-with-leaseonly on a private feature branch after explicit user confirmation and a fresh fetch. Never rewrite a shared branch. -
Merge: squash-merge for clean history (default), or rebase-merge if commit history is meaningful.
-
Cleanup: delete the remote branch after merge.
git branch -d feat/short-descriptionlocally.
Branch naming convention:
feat/description- new featuresfix/description- bug fixesrefactor/description- code restructuringchore/description- maintenance, deps, configdocs/description- documentation onlyci/description- CI/CD changessecurity/description- security fixes (consider if this should be a private advisory instead)
Step 3c: Release workflow
Read references/forge-workflows.md for forge-specific release creation.
Versioning scheme: semver vMAJOR.MINOR.PATCH with optional pre-release suffixes.
| Version | When | CI behavior |
|---|---|---|
v0.12.0-alpha.1 |
Start of new minor version, iterating on new features | Tag + release (marked pre-release). Image build optional per project. |
v0.12.0-alpha.2 |
Continued iteration, not stable yet | Same as above. |
v0.12.0 |
Features stable, ready for production | Full release: tag + release + image build + deploy. |
v0.12.1 |
Patch fix on stable release | Full release. |
Alpha workflow:
- When starting work on a new minor version, tag
vX.Y.0-alpha.1 - Increment the alpha number (
-alpha.2,-alpha.3) as you iterate - When stable, drop the
-alphasuffix and releasevX.Y.0 - Alpha tags still get GitHub/Forgejo releases (marked
--prerelease) so CI can optionally build images - The project instruction file defines whether alpha tags trigger image builds or not
Copy this checklist and track progress:
- Version files bumped
- Bump commit created
- Annotated tag created
- Commit and tag pushed to every release remote
- Forge release created
- Release pipeline confirmed running on the tag
General flow:
- Version bump: update all version files (check the project instruction file for the list - every project is different).
- Commit:
chore: bump version to X.Y.Z(orchore: bump version to X.Y.Z-alpha.N) - Tag:
git tag -a vX.Y.Z -m "vX.Y.Z"(annotated tags, not lightweight). - Push: push commits AND tags.
git push origin main && git push origin vX.Y.Z. If multi-remote, push to all. - Create release: GitHub (
gh release create), GitLab (glab release create), or Forgejo (API/web). For alpha/pre-release:gh release create vX.Y.Z-alpha.N --prerelease --title "vX.Y.Z-alpha.N" - Verify: check that CI/CD picked up the tag and started the release pipeline. If it did
not, confirm the tag reached the remote (
git ls-remote --tags origin vX.Y.Z) and matches the workflow's tag trigger, then return to step 4.
Changelog generation: default to the project's existing tool. With none, use
gh release create --generate-notes (PR titles since the last tag) on GitHub, or git-cliff
when the project keeps a committed CHANGELOG.md. The ! marker and consistent scopes make
either output more useful.
Step 3d: Recovery operations
Read references/recovery-and-maintenance.md for detailed recovery
procedures (reflog, bisect, rerere, filter-repo, etc.).
Git almost never loses data. Reflog retention is configurable: defaults are 90 days for reachable entries and 30 for unreachable entries; expiration and GC can remove recovery data.
Quick reference:
- Undo last commit (keep changes):
git reset --soft HEAD~1 - Undo last commit (discard changes):
git reset --hard HEAD~1- DESTRUCTIVE, confirm first - Revert a pushed commit:
git revert <sha>(creates a new commit, safe for shared branches) - Find lost commits:
git reflog- shows retained HEAD movements; do not assume a fixed recovery window - Find which commit broke something:
git bisect start && git bisect bad && git bisect good <sha> - Automated bisect with test script:
git bisect start HEAD v1.0.0 && git bisect run bun test src/auth.test.ts- runs the test at each bisect step automatically. Exit codes: 0 = good, 1-127 except 125 = bad, 125 = skip this commit, 128-255 = abort the bisect immediately. Ideal for CI integration:git bisect run ./scripts/ci-check.sh - Squash last N commits (no interactive rebase):
git reset --soft HEAD~N && git commit -m "feat: combined change"- resets N commits but keeps all changes staged, then commits them as one. Safer thangit rebase -iin automated contexts. - Recover deleted branch:
git reflog, find the SHA,git checkout -b branch-name <sha> - Scrub secrets from history: check
command -v git-filter-repo >/dev/null || { echo "install git-filter-repo (pipx install git-filter-repo, or the distro package)" >&2; exit 1; }and stop if it is missing, then setGIT_FILTER_REPO_REPLACEMENTSto a mode-0600 temporary replacement file populated from a secret manager or no-echo stdin, then run: "${GIT_FILTER_REPO_REPLACEMENTS:?set a mode-0600 replacement file}"followed bygit filter-repo --replace-text "$GIT_FILTER_REPO_REPLACEMENTS". Remove the temporary file normally after use. Never put the leaked value in argv, command text, or shell history. Then force-push ALL branches and tags, coordinated with the team. See references.
Step 3e: Diverged branch resolution
When git pull fails with "divergent branches" or git status shows "have diverged":
- Understand the divergence:
git log --oneline HEAD..origin/branch(what remote has) andgit log --oneline origin/branch..HEAD(what you have locally). - Choose strategy based on context:
- Your commits are the ones that matter (common for solo work):
git pull --rebase origin branch- replays your local commits on top of remote. - Remote commits are the ones that matter (someone force-pushed, or you want to discard local):
git reset --hard origin/branch- DESTRUCTIVE, confirm first. - Both sides have real work (collaboration divergence):
git pull --rebase origin branch, resolve conflicts at each step,git rebase --continue. - You don't know yet: inspect both histories and repository policy before selecting a strategy; do not run a configuration-dependent pull as a probe.
- Your commits are the ones that matter (common for solo work):
- After resolving: verify with
git log --oneline -10that history looks correct. - Prevent recurrence: if this was caused by force-push on a shared branch, set up branch protection. If caused by forgetting to pull before committing, consider
git config pull.rebase truefor rebase-on-pull default.
Step 3f: Bulk repo update workflow
When asked to pull or update many repositories under a directory, keep the run sequential, auditable, and conservative. Per repository, track:
- Branch, upstream, and dirty state recorded
- Fetched and fast-forwarded (or skipped with a reason)
- Stash, if any, re-applied and verified
- Ahead/behind and porcelain status checked
- Discover only real repo roots first, usually direct children of the requested directory unless the user explicitly asks for a recursive scan. Avoid vendored repos, worktrees, dependency caches, and generated checkouts.
- Process repos sequentially, not in parallel. This avoids hammering SSH remotes, rate limits, or firewall protections.
- For each repo, record the branch, upstream, and dirty state before changing anything.
- Run
git fetch --all --prune, thengit pull --ff-only --recurse-submodulesonly when an upstream exists. Do not create merge commits during bulk maintenance. When submodules are present, also rungit submodule update --init --recursiveafter the pull ---recurse-submodulesupdates existing submodule checkouts but does not initialize new submodules added since the last pull. - If authorized to stash local changes, record the original index and worktree diffs,
create a named stash, fast-forward, then use
git stash apply --indexwith that stash's exact object id. Keep it until both content and the staged/unstaged split are verified. - If applying the index conflicts, preserve the stash and stop updating that repository. Resolve against the saved staged and unstaged patches deliberately; never blanket-unstage user work. Report the unresolved repository and continue independent repositories.
- Verify every repo with
git rev-list --left-right --count HEAD...@{u}andgit status --porcelain. Report repos that remain dirty or have no upstream.
Multi-Forge Patterns
Many projects use multiple git remotes (e.g., Forgejo for self-hosted CI + GitHub for public releases, or GitLab at work + GitHub for open source mirrors).
- Keep
originas the primary development remote and name mirrors explicitly. - Push to multiple remotes explicitly; do not make "push everywhere" the default.
- Use separate SSH keys per forge.
- Remember that CLI auth can be overridden by environment variables, especially
GITHUB_TOKEN.
Detailed multi-forge workflows stay in references/forge-workflows.md.
Commit Signing
- Sign commits because unsigned authorship is trivial to spoof.
- SSH signing is the default recommendation for most teams.
- GPG still matters where long-lived key lifecycles or policy require it.
- gitsign is attractive for low-management open-source flows, but it changes the trust model.
Detailed signing setup stays in references/security-and-signing.md.
Security
- Keep credentials out of the repo, including
.envfiles, keys, and embedded connection strings. - Use secure credential helpers, not plaintext storage.
- Use hooks for secrets, lint, and branch protection, but treat untrusted hook configs as code execution surfaces.
- If a secret hit history, scrub it and rotate it. History rewriting does not undo the exposure.
- Keep
.gitignoreand.gitattributesintentional; AI tooling artifacts belong out of the repo by default.
Detailed security and signing guidance stays in references/security-and-signing.md.
PCI-DSS 4.0 Change Evidence
For repositories in PCI scope, use protected branches, required review, linked test and security checks, and retained or exported forge audit evidence for the organization's applicable software change controls. Map each control to the current PCI DSS text with the assessor; Git configuration alone does not prove training, environment separation, or the full change-management process. Signed commits authenticate a signing key under the chosen trust model. They do not prove that the signer completed security training or that the change was reviewed, tested, or authorized.
Reference Files
references/forge-workflows.md- GitHub, GitLab, and Forgejo-specific patterns for PRs/MRs, releases, branch protection, rulesets, CLI usage, and API callsreferences/security-and-signing.md- commit signing setup (SSH/GPG/gitsign), credential management, secret scanning, CVE reference, git security hardeningreferences/recovery-and-maintenance.md- reflog, bisect, rerere, filter-repo, stash, worktree, submodule/subtree, large repo optimization, housekeeping
Output Contract
See references/output-contract.md for the full contract.
- Skill name: GIT
- Deliverable bucket:
audits - Mode: conditional. When invoked to analyze, review, audit, or improve existing repo content, apply the reporting size and evidence rules in
references/output-contract.mdand write the deliverable todocs/local/audits/git/<YYYY-MM-DD>-<slug>.md. When invoked to answer a question, teach a concept, build a new artifact, or generate content, respond freely without the contract. - Severity scale:
P0 | P1 | P2 | P3 | info(see shared contract; only used in audit/review mode).
Related Skills
- ci-cd - pipeline design that triggers on git events (push, PR, tag). This skill handles the git operations; ci-cd handles the pipeline that reacts to them.
- security-audit - application-level secret scanning and vulnerability assessment. This skill covers secrets in git history and git-specific security (signing, hooks, credentials).
- code-review - reviews code quality. This skill creates the PR/MR; code-review evaluates the code in it.
- update-docs - post-session documentation sweep. May update shared instruction files with new git gotchas discovered during a session.
Rules
The AI Self-Check above holds the per-operation guards (confirmation for destructive ops, authorship, selective staging, hooks, tags, force-push, admin authorization). These add:
- Show the target set before cleanup. Never run commands that delete branches, tags, or ignored files without listing what they will remove first.
- Prefer revert over history rewrite on shared branches. Rewrites need a force-push and break every other clone.
- Feature branches for collaboration. When others will review the work, use feature branches with PRs/MRs. Direct-to-main is acceptable for solo projects when the user explicitly prefers it.
- Rebase workflow. Rebase feature branches onto base, don't merge base into feature. Squash on merge for clean history unless the commit history is meaningful.
- Annotated tags for releases.
git tag -a vX.Y.Z -m "vX.Y.Z", not lightweight tags. Annotated tags carry metadata (tagger, date, message) and are what forges use for releases. - PCI-DSS evidence. In regulated environments, git history IS the audit trail. Protect it: signed commits, branch protection, required reviews, no history rewriting on release branches.