Skip to content

fix(git-workflows): make refresh tag cleanup safe#238

Open
JacobPEvans wants to merge 1 commit intomainfrom
fix/refresh-repo-tag-cleanup
Open

fix(git-workflows): make refresh tag cleanup safe#238
JacobPEvans wants to merge 1 commit intomainfrom
fix/refresh-repo-tag-cleanup

Conversation

@JacobPEvans
Copy link
Copy Markdown
Owner

Summary

  • Update /refresh-repo to fetch with git fetch origin --no-tags --prune --force by default
  • Add a separate tag audit that deletes only local-only release-style tags and reports other tag drift
  • Refine stale worktree cleanup to handle squash-merged PR branches only when the merged PR head matches local HEAD
  • Align git workflow standards with the updated stale worktree definition

Test Plan

  • markdownlint-cli2 git-workflows/skills/refresh-repo/SKILL.md git-standards/skills/git-workflow-standards/SKILL.md
  • pre-commit run --files git-workflows/skills/refresh-repo/SKILL.md git-standards/skills/git-workflow-standards/SKILL.md
  • git diff --check

Notes

  • ./scripts/run-tests.sh reported no test files found in this repo layout
  • Direct bats tests could not run locally because bats is not installed

Copilot AI review requested due to automatic review settings April 19, 2026 20:16
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +44 to +46
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.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

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.

Suggested change
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
  1. To ensure robustness in git workflow scripts, explicitly switch to the main branch (git switch main) before pulling updates.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-repo sync 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
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
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

Copilot uses AI. Check for mistakes.
Comment on lines +46 to +47
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`.
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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`.

Copilot uses AI. Check for mistakes.
Comment on lines +83 to +86
- 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)
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +66
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
```
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +81 to +86
**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)
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
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
Copy link

Copilot AI Apr 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants