---
name: step-merge
description: Review checklist and merge PR
next_step: steps/step-finish.md
---

# Step: MERGE - Review and Merge PR

## YOUR TASK:

Run through review checklist and merge the pull request with appropriate strategy.

**ULTRA THINK about merge safety.**

---

## EXECUTION SEQUENCE:

### 1. Load Config and PR Context

```bash
# Load GitFlow config (sets GF_* variables)
read_gitflow_config || { echo "❌ Run /gitflow init first."; exit 1; }

CURRENT=$(git rev-parse --abbrev-ref HEAD)
GIT_PROVIDER="$GF_PROVIDER"

# Try loading persisted PR state first
CONFIG_DIR=$(dirname "$GF_CONFIG_FILE")
PR_STATE_FILE="$CONFIG_DIR/cache/pr-state.json"
if [ -f "$PR_STATE_FILE" ]; then
  PR_NUMBER=$(grep -oP '"pr_number":\s*"\K[^"]+' "$PR_STATE_FILE" | head -1)
  TARGET_BRANCH=$(grep -oP '"target_branch":\s*"\K[^"]+' "$PR_STATE_FILE" | head -1)
  echo "✓ Loaded PR state from cache: PR #$PR_NUMBER → $TARGET_BRANCH"
fi

# Fallback: query provider if no cached state
if [ -z "$PR_NUMBER" ]; then
  if [ "$GIT_PROVIDER" = "github" ]; then
    PR_NUMBER=$(gh pr list --head "$CURRENT" --json number --jq '.[0].number')
    PR_STATUS=$(gh pr view $PR_NUMBER --json state,mergeable,reviews --jq '.')
  elif [ "$GIT_PROVIDER" = "azuredevops" ]; then
    PR_NUMBER=$(az repos pr list --source-branch "$CURRENT" --query "[0].pullRequestId" -o tsv)
    PR_STATUS=$(az repos pr show --id $PR_NUMBER --query "{status:status,mergeStatus:mergeStatus}")
  fi
fi

[ -z "$PR_NUMBER" ] && {
  echo "❌ No PR found for branch $CURRENT"
  echo "→ Run /gitflow pr first"
  STOP
}
```

### 2. Display Review Checklist

```
╔══════════════════════════════════════════════════════════════════╗
║                    PR REVIEW CHECKLIST                            ║
╠══════════════════════════════════════════════════════════════════╣
║  PR #${PR_NUMBER}: ${PR_TITLE}                                    ║
╠══════════════════════════════════════════════════════════════════╣

## Code Quality
- [ ] Code follows project conventions
- [ ] No unnecessary complexity
- [ ] No code duplication
- [ ] Variable/function names are clear

## Security
- [ ] No hardcoded secrets
- [ ] Input validation present
- [ ] Authentication/authorization correct
- [ ] No SQL injection risks

## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests pass
- [ ] Manual testing completed

## EF Core (if applicable)
- [ ] Migration files complete (3 files)
- [ ] No destructive operations (or confirmed)
- [ ] Snapshot synced with base

## Documentation
- [ ] Code comments where needed
- [ ] API docs updated (if applicable)
- [ ] README updated (if applicable)

╚══════════════════════════════════════════════════════════════════╝
```

### 3. Check CI Status

```bash
if [ "$GIT_PROVIDER" = "github" ]; then
  CI_STATUS=$(gh pr checks $PR_NUMBER --json state --jq '.[].state' | sort -u)

  [[ "$CI_STATUS" == *"FAILURE"* ]] && {
    echo "❌ CI checks failing"
    gh pr checks $PR_NUMBER

    if [ "$auto_mode" != true ]; then
      AskUserQuestion:
        header: "CI"
        question: "CI checks are failing. Continue anyway?"
        options:
          - label: "Wait for fix"
          - label: "Merge anyway (not recommended)"
    fi
  }
fi
```

### 4. Check Review Status

```bash
if [ "$GIT_PROVIDER" = "github" ]; then
  REVIEWS=$(gh pr view $PR_NUMBER --json reviews --jq '.reviews | map(select(.state == "APPROVED")) | length')
  REQUIRED_REVIEWS=$(gh api repos/:owner/:repo --jq '.default_branch_protection.required_pull_request_reviews.required_approving_review_count // 0')

  [ "$REVIEWS" -lt "$REQUIRED_REVIEWS" ] && {
    echo "⚠️ Needs $REQUIRED_REVIEWS approvals, has $REVIEWS"
  }
fi
```

### 5. Determine Merge Strategy

```bash
BRANCH_TYPE=$(echo $CURRENT | cut -d'/' -f1)

case "$BRANCH_TYPE" in
  feature)
    MERGE_STRATEGY="squash"
    DELETE_BRANCH=true
    ;;
  release|hotfix)
    MERGE_STRATEGY="merge"
    DELETE_BRANCH=true
    MERGE_BACK="$GF_DEVELOP_BRANCH"
    ;;
esac
```

### 6. Final Confirmation

```yaml
AskUserQuestion:
  header: "Merge"
  question: "Ready to merge PR #$PR_NUMBER?"
  options:
    - label: "Yes, merge now"
      description: "Strategy: $MERGE_STRATEGY, Delete branch: $DELETE_BRANCH"
    - label: "No, wait"
      description: "Cancel merge"
```

### 7. Execute Merge

**GitHub:**
```bash
case "$MERGE_STRATEGY" in
  squash)
    gh pr merge $PR_NUMBER --squash --delete-branch
    ;;
  merge)
    gh pr merge $PR_NUMBER --merge --delete-branch
    ;;
esac
```

**Azure DevOps:**
```bash
case "$MERGE_STRATEGY" in
  squash)
    az repos pr update --id $PR_NUMBER --status completed --squash true --delete-source-branch true
    ;;
  merge)
    az repos pr update --id $PR_NUMBER --status completed --squash false --delete-source-branch true
    ;;
esac
```

### 8. Verify Merge

```bash
# CRITICAL: Force update tracking refs to get accurate state
git fetch origin $TARGET_BRANCH:refs/remotes/origin/$TARGET_BRANCH --force --quiet
git fetch origin --prune --quiet

MERGED=$(git branch -r --merged origin/$TARGET_BRANCH | grep "$CURRENT" | wc -l)

[ "$MERGED" -eq 0 ] && {
  echo "⚠️ Merge verification failed - branch may not be merged"
  echo "  → Check PR status on remote"
} || {
  echo "✅ Merge verified - branch merged to $TARGET_BRANCH"
}
```

### 9. Summary

```
╔══════════════════════════════════════════════════════════════════╗
║                    PR MERGED                                      ║
╠══════════════════════════════════════════════════════════════════╣
║  PR:       #{PR_NUMBER}                                           ║
║  Strategy: {MERGE_STRATEGY}                                       ║
║  Target:   {TARGET_BRANCH}                                        ║
╠══════════════════════════════════════════════════════════════════╣
║  Branch:   {deleted | kept}                                       ║
{if MERGE_BACK}
║  Merge back: {MERGE_BACK} pending                                 ║
{endif}
╠══════════════════════════════════════════════════════════════════╣
║  NEXT: /gitflow finish                                            ║
╚══════════════════════════════════════════════════════════════════╝
```

---

## ERROR HANDLING:

| Error | Solution |
|-------|----------|
| CI failing | Wait for fix or force merge |
| No reviews | Request review or bypass |
| Merge conflicts | Rebase and retry |
| Branch protection | Request admin merge |

---

## SUCCESS CRITERIA:

- Review checklist completed
- CI checks passing (or bypassed)
- PR merged with correct strategy
- Source branch deleted

## NEXT STEP:

Proceed to `/gitflow finish` (automatically or manually).
