Przejdź do treści
Biblioteka skilli
Programowanie · Automatyzacja

upmerge

/upmerge

Przenosi poprawkę php-src z najniższej gałęzi do wszystkich wyższych utrzymywanych gałęzi, z osobnym commitem scalającym na każdy krok.

Licencja
MIT
Ostatnia zmiana repozytorium
26.05.2026

Ocena i bezpieczeństwo

100/ 100Klasa: dobry
Format25 / 25
Frontmatter z nazwą i opisem, poprawna nazwa, opis do 1024 znaków, nazwa zgodna z folderem.
Odkrywalność25 / 25
Opis mówi, kiedy użyć skilla, ma sensowną długość i jest w 3. osobie.
Treść35 / 35
Co najmniej 150 słów i do 500 linii, nagłówki, listy kroków, przykłady albo kod.
Higiena15 / 15
Bez zaślepek typu TODO, bez ścieżek Windows, z licencją.
Ryzykobrak sygnałów w skanie
Pliki w paczce
1
Skrypty
0
Komentarze HTML
0
Adresy URL w SKILL.md
0
Przestarzałość

Brak sygnałów. Repozytorium zmienione 26.05.2026, bez odwołań do wycofanych modeli i API.

Licencja

MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.

Co robi i kiedy

Przenosi poprawkę php-src z najniższej gałęzi do wszystkich wyższych utrzymywanych gałęzi, z osobnym commitem scalającym na każdy krok.

Wyzwalacze z opisu

upmergemerge uppropagate fix to higher branchesforward-port the fix
Oryginalny opis (EN)

Propagate a php-src bug fix from its lowest fix branch up through every higher maintained branch, applying the per-branch NEWS edit and producing one merge commit per hop. Use when the user says "upmerge", "merge up", "propagate fix to higher branches", "forward-port the fix", "/upmerge", or otherwise wants to mirror a fix that landed on a lower branch onto all newer maintained branches per CONTRIBUTING.md. Defaults to dry-run; `--execute` performs the merges locally. Never pushes, never fetches, never touches the remote.

Jak działa

  1. Inputs
  2. What it produces
  3. Workflow
  4. UPMERGE.md schema
  5. Boundaries
  6. Edge cases
  7. Quality checklist
  8. Out of scope
Sekcje z nagłówków SKILL.md, w oryginale · 273 linii, 1 920 słów
Podgląd SKILL.md
---
name: upmerge
description: >-
  Propagate a php-src bug fix from its lowest fix branch up through every
  higher maintained branch, applying the per-branch NEWS edit and producing
  one merge commit per hop. Use when the user says "upmerge", "merge up",
  "propagate fix to higher branches", "forward-port the fix",
  "/upmerge", or otherwise wants to mirror a fix that landed on a lower
  branch onto all newer maintained branches per CONTRIBUTING.md. Defaults to
  dry-run; `--execute` performs the merges locally. Never pushes, never
  fetches, never touches the remote.
---

# upmerge

Final, optional step of the bug-fix flow. Owns no SPEC.md phase; produces its own one-shot living doc `UPMERGE.md`. Reads the fix commit and `target_branch` from SPEC.md (or accepts explicit args), computes the merge chain dynamically, plans NEWS edits per branch, and — only on `--execute` — applies the merges locally.

## Inputs

1. **SPEC.md** in the task directory resolved per `_shared/task-dir.md`. From it:
   - `type: bug`, `status: done` (Verification phase done — guardrail).
   - `target_branch: PHP-x.y` (the source branch — the "from" of the chain).
   - `linked:` → GH issue number for the NEWS entry.
   - Fix commit SHA recovered from the Progress Log's `bug-fix` entry, or via `git -C $PHP_SRC_DIR log --grep "Closes GH-<N>" -1 --pretty=%H` on `target_branch`.
2. **Or** explicit flags when SPEC.md is absent: `--from PHP-x.y --commit <sha> --issue <N>`.
3. **`$PHP_SRC_DIR`** resolved per `_shared/php-src-detection.md`.
4. **Mode flag**: default dry-run; `--execute` to perform merges.

## What it produces

- `UPMERGE.md` in the same task dir as SPEC.md. Schema below.
- On `--execute`: one merge commit per branch hop in `$PHP_SRC_DIR`, with NEWS spliced on each upper branch. Tree left checked out on the topmost branch in the chain.

No `git push`. Ever.

## Workflow

### 1. Pre-guardrails

Refuse on any of:

- Working tree + index not clean:
  ```bash
  git -C "$PHP_SRC_DIR" diff --quiet && git -C "$PHP_SRC_DIR" diff --cached --quiet
  ```
- `--from` branch missing locally: `git -C "$PHP_SRC_DIR" rev-parse --verify <from>`.
- `--from == master`: nothing above master. Refuse with: `master is the top of the chain; nothing to upmerge.`
- Fix commit not reachable from `--from`: `git merge-base --is-ancestor <sha> <from>` must succeed.
- Fix commit ALREADY in the next-higher branch (already upmerged): the negative form `! git merge-base --is-ancestor <sha> <next>` must succeed. Otherwise refuse with: `Fix already present in <next>; nothing to do.`
- Fix commit didn't touch NEWS on `--from`:
  ```bash
  git -C "$PHP_SRC_DIR" show --stat <sha> | grep -q '^ NEWS '
  ```
  If empty: refuse with: `Fix commit <sha> did not touch NEWS on <from>. Add the NEWS entry on <from> first, then re-run.`
- SPEC.md (if present) Verification phase not `done`. Refuse with: `Run /bug-verify before /upmerge.`

### 2. Resolve inputs

- Resolve `$PHP_SRC_DIR` per `_shared/php-src-detection.md`.
- Resolve task dir per `_shared/task-dir.md`. If SPEC.md exists, read frontmatter → `target_branch`, `linked`, `status`.
- Recover fix commit SHA (Progress Log scan, fallback to `git log --grep`).
- Without SPEC.md, require `--from`, `--commit`, `--issue` all three. Refuse if any missing.

### 3. Compute the merge chain dynamically

Read the maintained-branch list per `_shared/branch-detection.md` algorithm § 1. Intersect with locally-present branches:

```bash
git -C "$PHP_SRC_DIR" for-each-ref --format='%(refname:short)' refs/heads/
```

Take every entry strictly above `<from>` ordered low → high. Example with `<from>=PHP-8.3`:

```
PHP-8.3 (source) → PHP-8.4 → PHP-8.5 → master
```

If any branch in the list is missing locally: stop with `Branch <X> from matrix.php is not checked out locally. Either: git checkout -b <X> origin/<X>, or pass --skip-missing.` Don't auto-fetch (forbidden by the agent's git etiquette).

### 4. Extract the NEWS entry to propagate

From the fix commit on `<from>`, isolate the lines it added to NEWS:

```bash
git -C "$PHP_SRC_DIR" show "<sha>" -- NEWS \
  | awk '/^@@/{in_hunk=1; next} in_hunk && /^\+[^+]/ { sub(/^\+/, ""); print }'
```

Identify the section header those `+` lines live under by scanning the same patch hunk upward for the nearest `- <Component>:` heading. Capture both the section header and the entry body (typically two-three lines starting with `  . Fixed bug GH-NNNNN ...`).

### 5. Plan — write UPMERGE.md (always)

Write `UPMERGE.md` to the task dir (schema below). Records:

- Frontmatter: `type: upmerge`, `status: planned`, `source_branch`, `source_commit`, `issue`, `created`.
- Chain (low → high).
- NEWS entry section + body extracted in step 4.
- One hop block per `(from, to)` pair, all `status: todo`, with the proposed merge subject `Merge branch '<from>'`.
- Build sanity check entry for the chain head (`master-build`), `status: todo`.

If `UPMERGE.md` already exists for this same `source_commit`: re-read it and resume at the first non-`done` hop (same resume algorithm as SPEC.md). If `source_commit` differs (re-planning a different fix): back up to `UPMERGE.md.bak` and rewrite.

**Stop here in dry-run mode.** Report the planned chain and the NEWS entry. Tell the user to re-run with `--execute` to apply.

### 6. Execute (only when `--execute`)

For each `(from, to)` pair in the chain, low → high:

```bash
git -C "$PHP_SRC_DIR" checkout "<to>"
git -C "$PHP_SRC_DIR" merge --no-ff --no-commit -m "Merge branch '<from>'" "<from>"
```

`--no-ff` matches the php-src convention visible in `git log --merges --first-parent` on master. `--no-commit` lets us land the NEWS resolution before the merge commit closes.

#### NEWS conflict resolution (expected)

```bash
# Take the upper branch's NEWS as authoritative
git -C "$PHP_SRC_DIR" checkout --ours -- NEWS
```

Then splice the propagated entry under the matching `- <Component>:` section inside the upper branch's unreleased header (the first line shaped like `?? ??? ????, PHP X.Y.Z`). Use `awk` (not `sed` — multi-line range matching is fragile):

```bash
awk -v section='- Core:' -v entry="$ENTRY_TEXT" '
  BEGIN { spliced = 0 }
  $0 == section && !spliced { print; in_sec=1; next }
  in_sec && /^- / { print entry; print ""; print; in_sec=0; spliced=1; next }
  in_sec && /^$/ && !spliced { print entry; print; in_sec=0; spliced=1; next }
  { print }
  END {
    if (!spliced) {
      # section header not present in upper branch — append a new one
      print ""; print section; print entry
    }
  }
' "$PHP_SRC_DIR/NEWS" > /tmp/news.new && mv /tmp/news.new "$PHP_SRC_DIR/NEWS"
git -C "$PHP_SRC_DIR" add NEWS
```

#### Non-NEWS conflicts

Stop. Mark the current hop `blocked` in UPMERGE.md with `git status` output and exact recovery commands:

```
Conflict outside NEWS — not auto-resolvable. To abort:
  git -C "$PHP_SRC_DIR" merge --abort

Resolve manually, then re-run /upmerge --execute to continue.
```

Do not attempt content-aware resolution outside NEWS.

#### Finalise the hop

```bash
git -C "$PHP_SRC_DIR" commit --no-edit
git -C "$PHP_SRC_DIR" rev-parse HEAD
```

Record the new merge-commit SHA under the hop in UPMERGE.md. Mark the hop `done`. Append one Progress Log line:

```
YYYY-MM-DD HH:MM — upmerge — hop <from> → <to> done (SHA <short>)
```

Loop to the next hop with `(to)` becoming the new `(from)`.

### 7. Post-guardrail — build at chain head

After every hop is `done`, run one build at the topmost branch (the tree is already checked out there):

```bash
cd "$PHP_SRC_DIR" && make -j$(nproc)
```

Per-hop `make test` is **not** run — too slow (≥15 min × N hops) and `/bug-verify` already established correctness on the source branch. A build pass at the top catches header / macro drift between branches that would break compile.

If build fails: mark `master-build` step `blocked`, leave the tree where it is, do not auto-revert. Print the build error tail.

### 8. Report

```
Upmerge complete (dry-run | --execute).

Chain:  <from> → <hop1> → <hop2> → ... → master
Hops:   <N done>/<N total>
Build:  <skipped | passed | failed>
NEWS:   spliced on <list of branches>

UPMERGE.md: <task-dir>/UPMERGE.md

To publish (you decide when):
  git -C "$PHP_SRC_DIR" push origin <from> <hop1> ... master
```

Never run the push. Never print the push without the explicit "you decide when" wrapper.

## UPMERGE.md schema

```markdown
---
type: upmerge
status: planned | in-progress | done | blocked
source_branch: PHP-8.3
source_commit: a1b2c3d
issue: GH-12345
created: YYYY-MM-DD
---

# Upmerge: GH-12345

## Chain
PHP-8.3 (source) → PHP-8.4 → PHP-8.5 → master

## NEWS entry to propagate
Section: `- Core:`
Body:
```
  . Fixed bug GH-12345 (one-line description).
    (contributor-handle)
```

## Hops
- [ ] **PHP-8.3 → PHP-8.4** — status: todo
      merge subject: `Merge branch 'PHP-8.3'`
      merge-commit SHA: (pending)
- [ ] **PHP-8.4 → PHP-8.5** — status: todo
- [ ] **PHP-8.5 → master** — status: todo

## Build check
- [ ] **master-build** — `make -j$(nproc)` at chain head

## Progress Log
- YYYY-MM-DD HH:MM — upmerge — planned chain from .github/matrix.php
```

Status values mirror SPEC.md (`todo` / `in-progress` / `done` / `skipped` / `blocked`). Resume algorithm is identical: re-running `/upmerge --execute` reads UPMERGE.md, finds the first non-`done` hop, picks up there.

## Boundaries

- **No `git push`, `git pull`, `git fetch`, `git remote *`.** The chain is computed from local refs only. If any branch in the chain is stale, that is the user's call to fix.
- **No branch creation or deletion.**
- **No modification of SPEC.md.** Bug-flow state is owned by other skills.
- **No `make test` per hop.** Single build at the chain head only.
- **No GitHub interaction.** No `gh pr`, no `gh issue comment`, no posting of upmerge status to the issue.
- **No conflict resolution outside NEWS.** Code conflicts always block.
- **No backporting.** This skill only goes up the chain. To put a fix on a branch *below* the one it landed on, the user must redo the fix on that branch — the policy is forward-port, not back-port.
- **No proceeding without an explicit `--from` when SPEC.md is absent.** Don't guess.
- **No reversal.** If the user wants to undo: `git reset --hard <pre-upmerge-sha>` per branch is on them. Document this in the final report when relevant.

## Edge cases

| Situation | Handling |
|---|---|
| `--from master` | Refuse (see § 1). |
| Fix commit landed on master only | Refuse: `/upmerge` is for forward-port from a lower branch. |
| Upper branch already contains the GH-NNNNN line in its NEWS | The `awk` splice is effectively idempotent — detect by grepping the upper NEWS for the exact entry first; if present, skip the splice, still produce the merge commit. Note in UPMERGE.md hop body. |
| `.github/matrix.php` missing | Fall back per `_shared/branch-detection.md` § 1 fallback. Note the fallback in the planning step. |
| User aborts mid-chain (Ctrl-C / `git merge --abort`) | Re-running `/upmerge --execute` reads UPMERGE.md, resumes at first non-`done` hop. |
| Upper-branch NEWS has no matching `- <Component>:` section | The awk's END branch appends a new section. Note in the hop body. |
| Fix commit is itself a merge commit (multi-parent) | Refuse: upmerge expects a single linear fix commit. The user must squash/cherry-pick first. |
| The chain has only one hop (`<from>` is just one below master) | Run normally — one hop, one build at the top. |
| User asks for partial upmerge (`--up-to PHP-8.5`) | Honour the flag; truncate the chain at `--up-to`. UPMERGE.md records the truncation. |

## Quality checklist

- [ ] Pre-guardrails all green before any merge happens
- [ ] Merge chain computed from `.github/matrix.php` (or documented fallback), never hardcoded
- [ ] NEWS entry section + body extracted from the source commit, not regenerated
- [ ] Each hop uses `--no-ff --no-commit`, spliced NEWS via `awk`, then `commit --no-edit`
- [ ] Non-NEWS conflicts cause the skill to stop, not silently resolve
- [ ] One build at the chain head; no per-hop test runs
- [ ] UPMERGE.md tracks every hop's SHA; Progress Log appended once per hop
- [ ] No `git push`, `git fetch`, `git pull`, `git remote *` executed
- [ ] Final report prints the push command but does not run it

## Out of scope

- Posting upmerge status to GitHub — never auto. The user pushes and announces themselves.
- Squashing or rewriting the fix commit on the source branch.
- Resolving non-NEWS conflicts.
- Detecting that a fix is security-only and shouldn't be upmerged — that judgement is the user's. If they ran `/upmerge`, the fix is upmergeable.

Wersje

W bazie nie ma innych skilli o nazwie upmerge.

Migawka bazy z 28.10.2026 · wersja paczki 363014ddbf7d (skrót SHA-256 całej paczki)

Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.

Podobne skille

  • 100bug-fix
    Znajduje przyczynę błędu w kodzie C php-src i wdraża poprawkę tak, by padający test .phpt przechodził, a test i poprawkę zapisuje jednym commitem na bieżącej gałęzi.
  • 100bug-context
    Rozpoczyna naprawę błędu w php-src: pobiera zgłoszenie z GitHuba z powiązanymi PR przez gh CLI, zapisuje fazę Context w SPEC.md i przygotowuje szkielet pozostałych faz.
  • 100split-branch
    Dzieli gałąź z N commitami na N gałęzi z jednym commitem każda, gdy użytkownik o to poprosi.
  • 100feature-branch
    Wymusza przepływ pracy feature-branch z Atlassian dla GitHub i GitLab: gałąź od domyślnej, praca, PR lub MR i usunięcie gałęzi lokalnej oraz zdalnej po scaleniu.
  • 100cleanup-branches
    Czyści lokalne gałęzie git, których praca została już scalona do gałęzi bazowej.
  • 100worktree-stale-base-merge
    Pomaga ocenić, czy zielone CI nadal coś znaczy przy merge pull requesta z równoległej gałęzi agenta lub gałęzi odciętej od starszego main, po wylądowaniu gałęzi siostrzanych.

Uwagi i zgłoszenia

Wiadomość trafi do Bartosza Sokolińskiego. Adres e-mail jest potrzebny tylko do odpowiedzi. Szczegóły w polityce prywatności.