---
name: glab-mr-rebase
description: >
  Rebase a single MR on its target branch, auto-resolving conflicts when possible,
  then push the rewritten branch. Stops after push — does not restart pipelines.
  Use when the user says /glab-mr-rebase, 'rebase cette MR', 'rebase ma MR',
  'rebase la branche sur main', 'résous les conflits', or wants to bring an MR
  up to date with its target branch.
argument-hint: "[optional: MR !IID — defaults to the MR for the current branch] [--rebase-only]"
allowed-tools:
  - Read
  - Edit
  - Glob
  - Grep
  - Bash
---

Rebase a single merge request on its target branch and push, auto-resolving conflicts when possible.

## Required tools

- `glab`
- `jq`

Run `pysae-ai-tools tools require <tools>` before starting; if it exits non-zero, abort and report the install command from stderr to the user.

## Mode detection

```bash
# --rebase-only: never fall back to a merge commit — a too-divergent / unresolvable branch
# fails instead (used by /code-autopilot-batch's merge-gate, which wants a clean linear rebase
# and escalates on failure rather than injecting a merge commit).
REBASE_ONLY=$(echo "$ARGUMENTS" | grep -oE -- '--rebase-only' | head -n1)
REFS=$(echo "$ARGUMENTS" | sed -E 's/--rebase-only//g' | tr -s ' ' | sed 's/^ //; s/ $//')
CTX=$(pysae-ai-tools internal detect-context $REFS)
IS_CI=$(echo "$CTX" | jq -r '.is_ci')
MR_IID=$(echo "$CTX" | jq -r '.mr_iid // empty')
```

If `MR_IID` is empty, inform the user and stop.

## Step 1 : Resolve MR metadata

Fetch the MR to get the source and target branches:
```bash
MR_JSON=$(glab mr view <MR_IID> --output json)
```
Extract `source_branch` and `target_branch`.

**Capture the pre-rebase approval state** so we can restore it after a force-push:
```bash
WAS_APPROVED=$(echo "$MR_JSON" | jq -r '(.approved_by | length) > 0')
```
GitLab projects with « Reset approvals on push » enabled drop every approval when the branch is rewritten (force-push after rebase / merge fallback). We re-add ours in step 3 if needed.

## Step 2 : Rebase

### Work in an isolated worktree (never touch the caller's working dir)

Do **not** `git checkout <source_branch>` in the current directory — that strands the caller's
state and, in `/code-autopilot-batch`'s parallel mode, collides with other tickets' worktrees.
Always operate in a dedicated worktree for the branch:

```bash
git fetch origin

# Reuse the branch's existing worktree if it is already checked out (the batch's per-ticket
# worktree); otherwise create a throwaway one. Never mutate the current checkout.
WT=$(git worktree list --porcelain | awk -v b="refs/heads/<source_branch>" '
  /^worktree /{p=$2} $0=="branch "b{print p}')
if [ -n "$WT" ]; then
  CREATED_WT=false
else
  WT="$(mktemp -d)/mr-rebase-<MR_IID>"   # parent exists, subdir doesn't → git creates it
  git worktree add "$WT" <source_branch> 2>/dev/null \
    || git worktree add --track -b <source_branch> "$WT" origin/<source_branch>
  CREATED_WT=true
fi
cd "$WT"
git pull origin <source_branch>
```

Run every git command below **from `$WT`**. After the push (or on any abort), if `CREATED_WT`
is true, clean up: `cd - && git worktree remove "$WT" --force`.

### Rebase on target branch
```bash
git rebase origin/<target_branch>
```

### Handle conflicts

**If rebase succeeds** → go to the « Push » sub-step.

**If rebase has conflicts**, resolve them automatically (no `AskUserQuestion`) and track how many commits produce conflicts:
1. Read each conflicting file
2. Resolve the conflict (keep the intent of both sides)
3. `git add <file>`
4. `git rebase --continue`
5. If the next commit also has conflicts, increment the conflict commit counter
6. **If 3 or more commits have produced conflicts** → the branch has diverged too much for a clean rebase:
   - **`--rebase-only` (autopilot / merge-gate)**: do **not** fall back to a merge commit (it would break a linear/squash pipeline and hide the divergence). `git rebase --abort`, clean up the worktree, and report failure — the caller escalates.
   - **otherwise (interactive default)**: abort and fall back to merge:
     ```bash
     git rebase --abort
     git merge origin/<target_branch> --no-edit
     ```
     If the merge also has conflicts, resolve them.
7. Otherwise, continue resolving until the rebase completes

### Push
```bash
git push --force-with-lease origin <source_branch>
```

`--force-with-lease` is required after rebase (history was rewritten). It is safe because it refuses to push if the remote has commits we don't know about. Then clean up the worktree if `CREATED_WT` is true.

## Step 3 : Restore approval if lost

If `WAS_APPROVED` was `true` (captured in step 1), re-check the MR after the push and restore the approval if it was reset:
```bash
POST_APPROVED=$(glab mr view <MR_IID> --output json | jq -r '(.approved_by | length) > 0')
```

If `WAS_APPROVED` is `true` and `POST_APPROVED` is `false` (« Reset approvals on push » fired), **invoke `/glab-mr-approve !<MR_IID> --ask=false` immediately, without asking the user** — the `--ask=false` flag tells the approve skill to skip the manual-testing confirmation since the MR was already validated before the rebase.

If both are `true` (approval survived) or both are `false` (was never approved), skip this step.

Mention the re-approval in the step 4 report when it happened.

## Step 4 : Report

Use a single line with three slots: status, MR ref + branch, strategy. Pick the strategy label that matches what actually happened:

- `rebase sans conflit` — rebase succeeded without any conflict
- `rebase, conflits résolus` — rebase succeeded after auto-resolving conflicts
- `merge fallback, conflits résolus` — rebase aborted (too divergent), merge used instead (interactive only)
- `échec, intervention manuelle requise` — rebase + merge fallback both failed, OR `--rebase-only` and the branch was too divergent / unresolvable (push skipped, caller escalates)

Format (append `, approval restaurée` when /glab-mr-approve was re-invoked in step 3):
```
✓ !<IID> <source_branch> — <strategy label>, push fait[, approval restaurée]
✗ !<IID> <source_branch> — échec, intervention manuelle requise
```

Examples:
```
✓ !42 feat/add-export — rebase sans conflit, push fait
✓ !38 fix/login-bug — rebase, conflits résolus, push fait, approval restaurée
✓ !27 refactor/auth — merge fallback, conflits résolus, push fait, approval restaurée
✗ !35 chore/big-bang — échec, intervention manuelle requise
```

## Gotchas

- **`--force-with-lease`** — toujours `--force-with-lease`, jamais `--force`. Protège contre l'écrasement de commits poussés entre-temps.
- **Branches protégées** — si le push est refusé, reporter l'erreur sans retry.
- **Pipelines** — ce skill **ne relance ni ne valide** aucun pipeline. La résolution de conflit **n'est donc pas validée** : elle peut compiler et rester sémantiquement fausse. C'est **à l'appelant de re-lancer la CI et d'exiger un pipeline vert avant tout merge** (la merge-gate d'autopilot le fait). Ne jamais merger une branche fraîchement rebasée/résolue sans re-CI.
- **Worktree** — le skill travaille dans un worktree isolé et ne modifie jamais le checkout courant de l'appelant.

## Rules

- **Language**: messages en français, commandes git/glab en anglais
- **Never force push without `--force-with-lease`**
- **Never mutate the caller's working directory** — always operate in a dedicated/reused worktree, cleaned up if created here
- **Auto-resolve conflicts** — pas de `AskUserQuestion`, ni en local ni en CI
- **`--rebase-only`** — pas de fallback merge-commit ; branche trop divergente / non résoluble → échec (l'appelant escalade)
- **Auto-restore approval** — si l'approval saute après force-push, ré-invoquer `/glab-mr-approve --ask=false` sans confirmation. **La re-validation CI reste requise côté appelant** (la ré-approbation ne vaut pas relecture de la résolution)

$ARGUMENTS
