fix(git-workflows): make refresh tag cleanup safe#238
fix(git-workflows): make refresh tag cleanup safe#238JacobPEvans wants to merge 1 commit intomainfrom
Conversation
There was a problem hiding this comment.
Code Review
This pull request refines the definitions and procedures for managing stale worktrees and repository synchronization, including a new section on tag auditing and cleanup. The reviewer suggested explicitly switching to the main branch before performing a fast-forward merge to ensure the sync process is robust.
| 4. Sync the default branch from its existing worktree with a fast-forward only merge: | ||
| `git merge --ff-only origin/<default>`. | ||
| If the default worktree is dirty or divergent, report it and skip instead of resetting. |
There was a problem hiding this comment.
The instruction to sync the default branch is missing an explicit step to switch to the main branch. To ensure robustness in git workflow scripts, explicitly switch to the main branch (git switch main) before pulling updates, as per repository guidelines.
| 4. Sync the default branch from its existing worktree with a fast-forward only merge: | |
| `git merge --ff-only origin/<default>`. | |
| If the default worktree is dirty or divergent, report it and skip instead of resetting. | |
| 4. Switch to the main branch and sync it with a fast-forward only merge: | |
| git switch main | |
| git merge --ff-only origin/main | |
| If the branch is dirty or divergent, report it and skip instead of resetting. |
References
- To ensure robustness in git workflow scripts, explicitly switch to the main branch (git switch main) before pulling updates.
There was a problem hiding this comment.
Pull request overview
Updates the /refresh-repo and related standards documentation to make repo refresh and cleanup safer—especially around tag handling and stale worktree detection—by separating tag auditing from branch refresh and tightening the definition of “stale”.
Changes:
- Adjust
/refresh-reposync workflow to fetch without tags and prune stale remote branches by default. - Add a dedicated tag audit/cleanup step that only deletes local-only release-style tags and reports tag drift.
- Refine stale worktree criteria to reduce risk around squash-merged branches, and align the standards doc with this definition.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| git-workflows/skills/refresh-repo/SKILL.md | Reworks refresh flow (no-tags fetch), adds tag audit guidance, tightens stale-worktree cleanup rules and reporting. |
| git-standards/skills/git-workflow-standards/SKILL.md | Updates the “stale worktree” definition to match the new safer criteria. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| For each worktree from `git worktree list`: | ||
|
|
||
| 1. Skip the default branch (main/master) and bare repo entries | ||
| 1. Skip the default branch (main/master), the current branch, and bare repo entries |
There was a problem hiding this comment.
In Worktree Cleanup Step 1, “Skip the default branch (main/master)” conflicts with the earlier instruction to derive the default branch from origin/HEAD. If the default branch is something else (e.g., develop), this wording could lead to cleaning up the default worktree. Consider phrasing this as “skip <default>” (and/or explicitly include develop if that’s intended).
| 1. Skip the default branch (main/master), the current branch, and bare repo entries | |
| 1. Skip the default branch (`<default>` as derived from `origin/HEAD`), the current branch, and bare repo entries |
| If the default worktree is dirty or divergent, report it and skip instead of resetting. | ||
| 5. Delete local branches already merged into the default branch with `git branch -d`. |
There was a problem hiding this comment.
Step 4 says to skip syncing the default worktree if it’s dirty/divergent, but the workflow continues into branch deletion and stale checks that depend on the default branch being up to date. To avoid misclassifying branches as merged/stale (especially if local <default> has diverged), consider explicitly skipping the subsequent “delete merged branches” / stale-worktree evaluation when the default branch can’t be fast-forwarded cleanly.
| If the default worktree is dirty or divergent, report it and skip instead of resetting. | |
| 5. Delete local branches already merged into the default branch with `git branch -d`. | |
| If the default worktree is dirty, divergent, or cannot be fast-forwarded cleanly, report it | |
| and skip instead of resetting. In that case, also skip any later cleanup that depends on the | |
| default branch being up to date, including merged-branch deletion and stale-worktree | |
| evaluation, for this run. | |
| 5. Only if Step 4 successfully fast-forwarded the default branch, delete local branches already | |
| merged into the default branch with `git branch -d`. |
| - The branch has a merged PR whose `headRefOid` matches the local branch `HEAD` | ||
| (`gh pr list --state merged --head <branch> --json number,headRefOid,mergedAt`) | ||
| - Its remote tracking branch was deleted (`[gone]` in `git branch -vv`) and it has no commits | ||
| ahead of the default branch (`git log origin/<default>..HEAD --oneline` is empty) |
There was a problem hiding this comment.
The merged-PR criterion relies on matching headRefOid to local HEAD, but gh pr list --state merged --head <branch> can return multiple PRs (e.g., if a branch name was reused). The instructions should specify which PR to compare against (typically the most recently merged by mergedAt, or require an exact PR number) to avoid treating the wrong PR as evidence the worktree is stale.
| Use native Git commands to compare local tags to remote tags: | ||
|
|
||
| ```bash | ||
| git for-each-ref '--format=%(refname:short)' refs/tags | ||
| git show-ref --tags | ||
| git ls-remote --tags --refs origin | ||
| ``` |
There was a problem hiding this comment.
The tag audit section covers local-only tags and “same name, different object” mismatches, but it doesn’t describe what to do about tags that exist on origin but not locally (which is also a form of drift). Consider explicitly calling out that case (at least report it), and if desired, recommend fetching specific missing release tags (e.g., git fetch origin tag <tag>) rather than a broad tags fetch.
| **Stale definition**: No open PR, no uncommitted changes, and either: | ||
|
|
||
| - The branch has a merged PR whose `headRefOid` matches the local branch `HEAD` | ||
| (`gh pr list --state merged --head <branch> --json number,headRefOid,mergedAt`) | ||
| - Its remote tracking branch was deleted (`[gone]` in `git branch -vv`) and it has no commits | ||
| ahead of the default branch (`git log origin/<default>..HEAD --oneline` is empty) |
There was a problem hiding this comment.
This PR updates the stale-worktree definition here, but .claude/rules/worktree-conventions.md still documents the older “merged PR OR [gone]” heuristic without the headRefOid == HEAD safeguard. To keep the repo’s guidance consistent (and avoid users applying the older, less safe definition), consider updating that doc to match the new definition or linking to this updated source of truth.
| Use `git worktree remove` (never `--force`) — Git natively blocks removal of dirty worktrees. | ||
| **Stale worktree**: A branch with no open PR, no uncommitted changes, and either a merged PR | ||
| whose `headRefOid` matches local `HEAD`, or a deleted remote (`[gone]`) with no commits ahead | ||
| of the default branch (`git log origin/<default>..HEAD --oneline` is empty). Branches with open |
There was a problem hiding this comment.
This updated stale-worktree definition uses the placeholder origin/<default>, but other examples in this same document still hard-code origin/main (e.g., the sync workflow below). Consider standardizing on either <default> throughout or main throughout so the standards doc doesn’t give mixed guidance.
| of the default branch (`git log origin/<default>..HEAD --oneline` is empty). Branches with open | |
| of the default branch (`git log origin/main..HEAD --oneline` is empty). Branches with open |
Summary
git fetch origin --no-tags --prune --forceby defaultTest Plan
markdownlint-cli2 git-workflows/skills/refresh-repo/SKILL.md git-standards/skills/git-workflow-standards/SKILL.mdpre-commit run --files git-workflows/skills/refresh-repo/SKILL.md git-standards/skills/git-workflow-standards/SKILL.mdgit diff --checkNotes
./scripts/run-tests.shreported no test files found in this repo layoutbats testscould not run locally becausebatsis not installed