Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/skills/resolve-merge-conflicts/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
name: resolve-merge-conflicts
description: Merge a base ref and safely regenerate compiled workflow lock-file conflicts.
tools:
bash:
- "./.github/skills/resolve-merge-conflicts/resolve.sh *"
- "git diff *"
- "git status *"
---

# Resolve Merge Conflicts

Use this skill when merging `origin/main` into a branch, especially when the
only conflicts are generated `.github/workflows/*.lock.yml` files.

## One-step path

From the repository root, run:

```bash
./.github/skills/resolve-merge-conflicts/resolve.sh origin/main
```

The command works both before a merge and after another command has stopped on
conflicts. It:

1. Starts the merge with `--no-commit`, or resumes the current merge.
2. Refuses to auto-resolve if any conflict is not a workflow `.lock.yml`.
3. Runs `make recompile` once so generated files come from the merged Markdown.
4. Stages the regenerated conflicting lock files.
5. Verifies that no unresolved paths or whitespace errors remain.

The script does not fetch, commit, push, abort, or edit workflow Markdown.
Refresh `origin/main` first only when credentials are available. After success,
review the staged merge, run the repository's final validation gate, then
commit and push.

## Safety rules

- Never choose `ours` or `theirs` for compiled lock files; regenerate them.
- Never manually remove conflict markers from `.lock.yml` files.
- Never auto-resolve a source `.md`, Go, JavaScript, or other mixed conflict.
- If the script refuses a mixed conflict, resolve source conflicts on their
merits, stage them, and rerun the same command. It will regenerate the
remaining lock conflicts.
- Do not abort an existing merge unless the user explicitly requests it.

102 changes: 102 additions & 0 deletions .github/skills/resolve-merge-conflicts/resolve.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#!/usr/bin/env bash
set -euo pipefail

usage() {
cat <<'EOF'
Usage: resolve.sh [BASE_REF]

Merge BASE_REF (default: origin/main) without committing, then resolve
workflow lock-file-only conflicts by running make recompile.

If a merge is already in progress, BASE_REF is ignored and the current
conflicts are processed.
EOF
}

die() {
echo "error: $*" >&2
exit 1
}

if [[ ${1:-} == "--help" || ${1:-} == "-h" ]]; then
usage
exit 0
fi
if (( $# > 1 )); then
usage >&2
exit 2
fi

base_ref=${1:-origin/main}
repo_root=$(git rev-parse --show-toplevel 2>/dev/null) ||
die "run this command inside a Git repository"
cd "$repo_root"

merge_in_progress=false
if git rev-parse -q --verify MERGE_HEAD >/dev/null; then
merge_in_progress=true
else
Comment on lines +35 to +38
git rev-parse --verify "${base_ref}^{commit}" >/dev/null 2>&1 ||
die "base ref '$base_ref' is unavailable; fetch it first if credentials are available"

if [[ -n $(git status --porcelain) ]]; then
die "working tree must be clean before starting the merge"
fi

echo "Merging $base_ref without committing..."
if ! git merge --no-edit --no-commit "$base_ref"; then
if ! git rev-parse -q --verify MERGE_HEAD >/dev/null; then
die "merge failed before creating a resolvable merge state"
fi
merge_in_progress=true
fi
fi

mapfile -d '' conflicts < <(git diff --name-only --diff-filter=U -z)
non_lock_conflicts=()
for path in "${conflicts[@]}"; do
if [[ ! $path =~ ^\.github/workflows/[^/]+\.lock\.yml$ ]]; then
non_lock_conflicts+=("$path")
fi
done

if (( ${#non_lock_conflicts[@]} > 0 )); then
echo "Refusing automatic resolution; resolve these source conflicts first:" >&2
printf ' %s\n' "${non_lock_conflicts[@]}" >&2
exit 1
fi

if (( ${#conflicts[@]} > 0 )); then
echo "Regenerating ${#conflicts[@]} conflicted workflow lock file(s)..."
else
echo "No unresolved source conflicts; recompiling workflows..."
fi
make recompile

if (( ${#conflicts[@]} > 0 )); then
git add -- "${conflicts[@]}"
fi

mapfile -d '' regenerated_locks < <(
git diff --name-only -z -- '.github/workflows/*.lock.yml'
)
if (( ${#regenerated_locks[@]} > 0 )); then
git add -- "${regenerated_locks[@]}"
fi

mapfile -d '' remaining < <(git diff --name-only --diff-filter=U -z)
if (( ${#remaining[@]} > 0 )); then
printf 'error: unresolved conflicts remain:\n' >&2
printf ' %s\n' "${remaining[@]}" >&2
exit 1
fi

git diff --check
git diff --cached --check

if [[ $merge_in_progress == true ]] ||
git rev-parse -q --verify MERGE_HEAD >/dev/null; then
echo "Resolved and staged generated lock conflicts. Review and commit the merge."
else
echo "Merge and workflow recompilation complete. Review the working tree."
fi