Cascade-merge maintained Symfony branches from oldest to newest (e.g. 6.4 → 7.4 → 8.0 → 8.1). Use when the user says "merge branches", "merge up", "cascade merge", "sync branches", or "update branches".
Merges each maintained branch into the next one, from oldest to newest.
Whenever the skill says "Wait for confirmation", treat anything other than an explicit affirmative as no: stop and ask the user how they want to proceed.
git status --porcelain --untracked-files=no
If any output, stop:
"The working tree is not clean. Please commit or stash your changes first."
curl -s https://symfony.com/releases.json
Read maintained_versions. It is already sorted oldest → newest (e.g.
["6.4", "7.4", "8.0", "8.1"]). Store as BRANCHES.
For each branch in BRANCHES:
git checkout <branch>
git pull --ff-only origin <branch>
Using --ff-only ensures local branches haven't diverged from origin. If the
pull fails, stop and report the error.
For each consecutive pair (SOURCE, TARGET) in BRANCHES:
git checkout <TARGET>
composer up
git merge <SOURCE>
Three outcomes are possible:
<TARGET> already up-to-date with <SOURCE>"
and skip to the next pair.List conflicts:
git diff --name-only --diff-filter=U
Read each conflicted file, resolve it, then git add it. When all are resolved:
git commit --no-edit
| File pattern | Strategy |
|---|---|
CHANGELOG*.md | Keep entries from both sides; newer branch entries on top |
Version constants, composer.json branch aliases | Keep the TARGET branch value |
| Code files | Merge logically based on context; when unsure, ask the user |
When merging from one major version to the next (e.g. 6.4 → 7.0), remove test
methods marked with @group legacy or #[Group('legacy')]. The deprecations
they cover have been removed in the new major version, so the tests are no
longer relevant.
After resolving, show git diff HEAD~1 (first parent of the merge commit, i.e.
the previous TARGET state) and wait for the user to confirm the resolution looks
correct before proceeding.
Extract component, bridge, and bundle names from changed files:
git diff --name-only HEAD~1..HEAD
Paths look like src/Symfony/{Component,Bridge,Bundle}/<NAME>/.... Deduplicate,
then run tests for each:
./phpunit src/Symfony/Component/<NAME>
./phpunit src/Symfony/Bridge/<NAME>
./phpunit src/Symfony/Bundle/<NAME>
For files under src/Symfony/Contracts/, run the single shared test suite:
./phpunit src/Symfony/Contracts
Ignore files outside these directories (root configs, .github/, etc.): they
don't have component-level test suites.
If tests fail or report PHPUnit deprecations (the PHPUnit version may differ
between branches), first check whether the failure is pre-existing: run the same
test on the TARGET branch before the merge (git stash && git checkout HEAD~1
or check CI). Only fix failures introduced by the merge:
[<ComponentName>] Fix merge conflict resolution.Report any pre-existing failures to the user without attempting to fix them.
Show:
Merge: <SOURCE> → <TARGET>
Affected: <component list>
Tests: all passing
Commits since origin/<TARGET>:
git log --oneline origin/<TARGET>..<TARGET>
Ready to push? (yes / no)
Wait for confirmation. The user may make changes themselves before confirming.
git push origin <TARGET>
If the push fails, stop and report the error.
Print "✓ <SOURCE> → <TARGET> done." and continue to the next pair.
All merges complete:
6.4 → 7.4 ✓
7.4 → 8.0 ✓
8.0 → 8.1 ✓
CHANGELOG.md conflicts are the most common; entries must be kept from both
sides, never dropped.--no-verify on commits.git push or git pull. Stop and hand
control back to the user.