```skill
---
name: merge-branch
description: Git branch merging workflow — merges current feature branch into the default branch (main/master) with conflict detection, working tree validation, and safety checks.
---

# Merge Branch

## Overview

This skill merges the current feature branch into the detected default branch (main or master).

**Prerequisites:**
- Working in a git repository
- On a feature branch (not already on default branch)
- Have commits ready to merge

**Outcome:**
- Feature branch merged into default branch
- Default branch updated with latest changes
- Ready to push merged changes to remote

## Default Branch Detection

Detect the default branch name:
```sh
git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@'
```
Fallback: check if `master` exists, else `main`. Store as `{default_branch}`.

## Pre-Merge Validation

Run these checks BEFORE merging:

### 1. Get Current Branch

```sh
CURRENT_BRANCH=$(git branch --show-current)
```

### 2. Verify Not on Default Branch

```sh
if [ "$CURRENT_BRANCH" = "{default_branch}" ]; then
  echo "ERROR: Already on default branch. Cannot merge into self."
  exit 1
fi
```

### 3. Check Working Tree State

```sh
IS_DIRTY=$(git status --porcelain)
```

If `IS_DIRTY` is not empty, working tree is dirty. Handle before merging.

## Dirty Working Tree Options

When dirty, present these options to the user (use `ask_questions` tool):

- **Commit changes first**: `git add -A && git commit -m "message"` — commits all changes before merging
- **Stash changes**: `git stash push -m "WIP: auto-stash before merge"` — saves changes for later
- **Discard changes**: `git checkout -- . && git clean -fd` — permanently removes uncommitted changes
- **Abort**: Stop the workflow — user handles git state manually

After committing, stashing, or discarding, working tree is clean. Proceed with merge.

## Merge Execution

After working tree is clean:

### 1. Switch to Default Branch

```sh
git checkout {default_branch}
```

### 2. Pull Latest Changes

```sh
git pull
```

### 3. Execute Merge

```sh
git merge $CURRENT_BRANCH
```

### 4. Handle Merge Result

Check exit code:

- **Exit 0** (success): Merge completed successfully
  ```
  ✓ Merged $CURRENT_BRANCH into {default_branch}
  Next steps:
  - Review merged changes: git log
  - Push to remote: git push
  - Delete feature branch if done: git branch -d $CURRENT_BRANCH
  ```

- **Non-zero exit** (conflict): Merge conflict detected
  ```sh
  git merge --abort
  echo "ERROR: Merge conflict detected. Merge aborted."
  echo "Resolve conflicts manually and retry merge."
  exit 1
  ```

## Error Handling

| Scenario | Error Message | Exit Code |
|----------|---------------|-----------|
| Already on default branch | `ERROR: Already on default branch. Cannot merge into self.` | 1 |
| Dirty working tree (user aborts) | `ERROR: Working tree is dirty. Merge aborted.` | 1 |
| Merge conflict | `ERROR: Merge conflict detected. Merge aborted.` | 1 |
| Default branch detection fails | `ERROR: Could not detect default branch.` | 1 |

All errors exit with non-zero status to prevent downstream issues.

## Usage Example

Complete workflow demonstrating all steps:

```sh
#!/bin/bash
set -e

# Step 1: Detect default branch
DEFAULT_BRANCH=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@')
if [ -z "$DEFAULT_BRANCH" ]; then
  if git show-ref --verify --quiet refs/heads/master; then
    DEFAULT_BRANCH="master"
  else
    DEFAULT_BRANCH="main"
  fi
fi

# Step 2: Get current branch
CURRENT_BRANCH=$(git branch --show-current)

# Step 3: Verify not on default branch
if [ "$CURRENT_BRANCH" = "$DEFAULT_BRANCH" ]; then
  echo "ERROR: Already on default branch. Cannot merge into self."
  exit 1
fi

# Step 4: Check working tree state
IS_DIRTY=$(git status --porcelain)
if [ -n "$IS_DIRTY" ]; then
  echo "WARNING: Working tree is dirty."
  echo "Options: (c)ommit, (s)tash, (d)iscard, (a)bort"
  read -p "Choose: " choice
  case $choice in
    c) git add -A && git commit -m "Changes before merge" ;;
    s) git stash push -m "WIP: auto-stash before merge" ;;
    d) git checkout -- . && git clean -fd ;;
    a) echo "Merge aborted."; exit 1 ;;
    *) echo "Invalid choice. Aborting."; exit 1 ;;
  esac
fi

# Step 5: Switch to default branch
git checkout $DEFAULT_BRANCH

# Step 6: Pull latest changes
git pull

# Step 7: Execute merge
if git merge $CURRENT_BRANCH; then
  echo "✓ Merged $CURRENT_BRANCH into $DEFAULT_BRANCH"
  echo "Next steps:"
  echo "- Review merged changes: git log"
  echo "- Push to remote: git push"
  echo "- Delete feature branch if done: git branch -d $CURRENT_BRANCH"
else
  echo "ERROR: Merge conflict detected. Aborting merge."
  git merge --abort
  exit 1
fi
```
