merge-up
Skill1.1k starsChanged 8 days agoMITView on GitHub
Cascade-merge the maintained Symfony UX branches from oldest to newest (2.x -> 3.x), resolve conflicts, run the affected packages' tests and prepare the push. Use when the user wants the maintained branches merged up or synced.
- Commits and pushes
We split this skill into the rules it gives an agent
17 rules. About 0 are common, 10 are distinctive, and 7 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈10
Distinctive · estimate
This author's own choices. Worth a look.
7
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 34
If any output, stop:
- Distinctive: line 104
Read each conflicted file, resolve it, then git add it by name.
- Very specific: line 129
Remove test methods marked @group legacy / #[Group('legacy')]: the deprecations they cover are gone in 3.x.
- Distinctive: line 132
Prefer the TARGET branch's approach for any refactored idiom.
- Very specific: line 141
After resolving, show git diff HEAD~1 (first parent of the merge commit, i.e.
- Very specific: line 159
When src/<NAME>/assets/ changed, also run that package's JS tests: (cd src/<NAME>/assets.
- Distinctive: line 166
If tests fail or report PHPUnit deprecations (2.x runs phpunit-bridge, 3.x PHPUnit 11/12), first check whether the failure is pre-existing.
- Distinctive: line 174
Only fix failures introduced by the merge:
- Very specific: line 177
Commit the fix: [<ComponentName>] Fix merge conflict resolution.
- Very specific: line 188
Before writing a CI failure off as flaky, check that the group meant to exclude it is actually excluded: the jobs pass --exclude-group …
- Distinctive: line 215
Wait until they report it done.
- Distinctive: line 241
Never force-push or rewrite history.
- Very specific: line 242
Never use --no-verify on commits.
- Distinctive: line 243
Never git add -A (or git add .) while resolving: it sweeps the user's untracked working files into the merge commit.
- Very specific: line 244
Never git reset in the middle of a merge: it deletes .git/MERGE_HEAD, and the commit that follows records a single parent, silently turning …
- Distinctive: line 245
Never auto-recover from a failed git pull.
- Distinctive: line 246
Never parallelize the cascade or run branches concurrently (e.g.
≈ “Common” is an estimate: at least 1 in 5 of the 308,232 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Symfony UX Branch Cascade Merge
Merges each maintained branch into the next one, from oldest to newest.
Progress checklist
- Step 0: Pre-flight checks
- Step 1: Fetch maintained branches and pull them
- Step 2: Cascade merge loop
Confirmation rule
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.
Step 0 — Pre-flight checks
git status --porcelain --untracked-files=noIf any output, stop:
"The working tree is not clean. Please commit or stash your changes first."
Step 1 — Fetch maintained branches and pull them
1a. Get the branch list
The maintained branches, oldest first:
- 2.x
- 3.x
Store them as BRANCHES.
1b. Pull every branch
For each branch in BRANCHES:
git checkout <branch>
git pull --ff-only upstream <branch>Using --ff-only ensures local branches haven't diverged from upstream. If the
pull fails, stop and report the error.
Step 2 — Cascade merge loop
For each consecutive pair (SOURCE, TARGET) in BRANCHES:
2a. Merge
git checkout <TARGET>Read the merge-up notes of the incoming pull requests first. The bot copies the whole pull request description into the merge commit, so the authors' own instructions for this merge are already in the local history. A description can end with a "Merge-up to <branch>" paragraph naming the declarations to add, the style the target branch expects, or the resolved code itself:
git log --merges --format=%H <TARGET>..<SOURCE> \
| xargs -I{} git log -1 --format=%B {} \
| grep -inE 'merge(d| )?-?up|adapt|on [0-9]+\.x'Prefer the resolution a note gives over an equivalent one of your own: it is what the author wrote the change for and usually ran on the target branch already, and a merge commit is the wrong place for a refactor. A note also covers files that merge cleanly, which is why this runs before the merge and not only when git reports a conflict.
git merge <SOURCE>Three outcomes are possible:
- Already up-to-date: print "✓
<TARGET>already up-to-date with<SOURCE>" and skip to the next pair. - Clean merge (no conflicts): git creates the merge commit automatically. Proceed directly to step 2c.
- Conflicts: proceed to step 2b.
2b. Resolve conflicts (only when git reports conflicts)
List conflicts:
git diff --name-only --diff-filter=URead each conflicted file, resolve it, then git add it by name. When all are resolved:
git commit --no-editConflict resolution rules
| File pattern | Strategy |
CHANGELOG*.md | Keep entries from both sides; newer branch entries on top |
version in assets/package.json, version constants | Keep the TARGET branch value |
assets/dist/** | Never merge by hand. Resolve the sources first, then rebuild the package on the TARGET (cd src/<NAME>/assets && pnpm run build) and stage the result: CI's "Dist Files Unbuilt" job fails when dist/ does not match a fresh build |
.github/workflows/*.yaml, CI config | Keep the TARGET value for branch-specific pins. A job merged from SOURCE may carry SOURCE's php-version (2.x runs PHP 8.1+); bump it to the TARGET's minimum (3.x runs PHP 8.4+) |
| Idiom the TARGET replaced (logic extracted to a trait, a method or class removed) | Take the TARGET version; the SOURCE change is superseded. git checkout --ours <file>, then re-apply the part of the SOURCE fix the TARGET still needs |
| File the TARGET deleted (modify/delete conflict) | Keep it deleted if the TARGET removed the feature (confirm with git log <TARGET> -- <file>); the SOURCE edit is moot. git rm <file> |
Test using docblock metadata (@dataProvider, @testWith, @group legacy) | Convert to attributes (#[DataProvider(...)], #[TestWith([...])], #[Group(...)]). 3.x runs PHPUnit 11/12, where doc-comment metadata is deprecated and then ignored, so the data sets are never passed and the test errors with "too few arguments" |
Compat guard added by SOURCE (class_exists() / method_exists() fallback for a symbol an older dependency may lack) | Check whether the TARGET dropped it on purpose: git log <TARGET> -S'<guard text>' -- <file>. If it did, take SOURCE's new structure but leave the guard out |
| Both sides added a member at the same spot (no overlapping content, git just collapsed them onto a shared closing) | Keep both. Give each its own terminator: two elseif branches each need their own return/closing brace, and two methods each need their own }. Private methods go last, after all public ones |
| Code files | Merge logically based on context; when unsure, ask the user |
Structural divergence across major versions
3.x removed what 2.x deprecated and raised the minimum PHP from 8.1 to 8.4. When merging 2.x into 3.x:
- Remove test methods marked
@group legacy/#[Group('legacy')]: the deprecations they cover are gone in 3.x. Also remove any test, fixture or import that references a removed symbol, otherwise it fatals on the TARGET. - Code merged from SOURCE that branches on or polyfills a PHP below 8.4 (
\PHP_VERSION_ID < ...guards, orfunction_exists()/class_exists()fallbacks for symbols that are always available) is dead on 3.x and can be collapsed to the modern path. The TARGET usually dropped it already, so prefer its version; clean up only where SOURCE's old-PHP code lands somewhere the TARGET had not simplified. - New
test*methods from 2.x arrive without a return type, while 3.x declares: voidon them (its php-cs-fixer config appliesvoid_returntotests/). Runphp vendor/bin/php-cs-fixer fix <file>on the merged test files. - Prefer the TARGET branch's approach for any refactored idiom.
Divergence a clean merge hides
Most of these produce no conflict at all: the merge succeeds and the tests fail. They show up as a merged test that is fine on SOURCE and wrong on TARGET.
- A config key the TARGET removed or deprecated. A merged test builds a bundle config that the TARGET no longer accepts. The symptom is
Unrecognized option "x"with the valid list attached, or a deprecation the run reports. Drop the key if it is boilerplate rather than what the test is about. Grep the whole merge diff for the key, since several merged tests usually carry it. - A default the TARGET flipped. SOURCE adds a code path behind a flag whose default the TARGET changed, so the new path becomes the TARGET's default and changes observable output. Both sides merge cleanly and the assertions SOURCE wrote for the old path now fail. Confirm with
git log <TARGET> -S'<flag> = <value>', then adapt the expectations, capturing the real output from a run rather than guessing at it.
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.
2c. Run tests for affected packages
Extract package and bridge names from changed files:
git diff --name-only HEAD~1..HEADPaths look like src/<NAME>/..., or src/<NAME>/src/Bridge/<BRIDGE>/... for a bridge, which has its own composer.json and test suite. Deduplicate, then run the tests from each directory. Each package has its own vendor/ and the branches pin different dependencies, so update it first:
(cd <DIR>; composer update; symfony php vendor/bin/phpunit)When src/<NAME>/assets/ changed, also run that package's JS tests: (cd src/<NAME>/assets; pnpm run test:unit).
Ignore files outside these directories (root configs, .github/, etc.): they
don't have package-level test suites.
Read the whole summary line, not just the exit status: a suite can end with Tests: N, Failures: 1 or abort on a Fatal error well before any FAILURES! banner, and ANSI colour codes sit in front of those words, so a check anchored to the start of a line reports a red run as green.
If tests fail or report PHPUnit deprecations (2.x runs phpunit-bridge, 3.x PHPUnit 11/12), first check whether the failure is pre-existing. Cheapest test first: if the merge did not touch the failing area, it did not cause the failure.
git diff --name-only HEAD~1..HEAD -- <path of the failing test or the code it covers>Only when that is inconclusive, run the test on the TARGET before the merge (git checkout HEAD~1, run, git checkout <TARGET>). Beware a CI baseline as evidence: a branch tip that has not been pushed in a while keeps an old green run, and CI installs dependencies fresh on every run, so a release made in between can turn a suite red with no commit to blame.
Only fix failures introduced by the merge:
- Analyze and fix the code, including any PHPUnit deprecation notices.
- Commit the fix:
[<ComponentName>] Fix merge conflict resolution. - Re-run failing tests until green and deprecation-free.
Report any pre-existing failures to the user without attempting to fix them.
Failures a local run cannot show
A local composer update installs the sibling UX packages a package requires (e.g. symfony/ux-twig-component for LiveComponent) from Packagist, at their released version. CI first runs .github/build-packages.php, which rewrites every composer.json to use the sibling packages from the checkout. A merged test that relies on a sibling change from the same merge can therefore fail locally and pass in CI. To reproduce CI, run php .github/build-packages.php before composer update, and restore the rewritten composer.json files with git checkout -- '*composer.json' before committing anything.
CI also runs a lowest-dependencies job and jobs pinned to specific Symfony versions, while a local run gets the newest versions the constraints allow. An assertion pinned to a Symfony component's exception message can break when a newer release appends to it: assert the part that identifies the failure and leave the tail free (drop a trailing ., or use expectExceptionMessageMatches()), and fix it on the oldest branch that has the test so the cascade carries it up.
Before writing a CI failure off as flaky, check that the group meant to exclude it is actually excluded: the jobs pass --exclude-group skip-on-lowest and --exclude-group transient-on-windows, and on 3.x the group has to be an attribute, since PHPUnit 11 deprecates doc-comment metadata and PHPUnit 12 ignores it.
2d. Ask for confirmation before pushing
Show:
Merge: <SOURCE> -> <TARGET>
Affected: <package list>
Tests: all passing
Commits since upstream/<TARGET>:
git log --oneline upstream/<TARGET>..<TARGET>
Ready to push? (yes / no)Wait for confirmation. The user may make changes themselves before confirming.
2e. Hand over the push and continue
The user pushes. Print the command for them to run:
git push upstream <TARGET>Wait until they report it done. If the push fails, stop and let them handle it.
Print "✓ <SOURCE> -> <TARGET> done." and continue to the next pair.
Final summary
All merges complete:
2.x -> 3.x ✓Gotchas
CHANGELOG.mdconflicts are the most common; entries must be kept from both sides, never dropped.- A merge can introduce test failures even without conflicts, because behavior from the older branch may be incompatible with newer code. Always run tests.
- A clean (no-conflict) merge still needs verification, not just a commit: auto-merged test metadata (docblock vs attribute), a rebuilt
dist/, and CI version pins can each be wrong even when git reports no conflict. - Some packages have slow test suites. Only run tests for packages with changed files, not the entire project.
- When the user states a constraint about the merge as a whole, it applies to the entire merge diff, not only to the files git flagged as conflicting. Grep the whole diff for the concept and check every hit, including other packages and their bridges. Auto-merged hunks are where a constraint like that gets lost silently.
- Resolving only the conflicted hunk of a file leaves the rest of it auto-merged. When the two sides restructured the same file, read the resolved file end to end before staging it, otherwise it can end up declaring the same thing twice or dropping a
return.
Error handling
- Never force-push or rewrite history.
- Never use
--no-verifyon commits. - Never
git add -A(orgit add .) while resolving: it sweeps the user's untracked working files into the merge commit. Stage the files you resolved, by name. - Never
git resetin the middle of a merge: it deletes.git/MERGE_HEAD, and the commit that follows records a single parent, silently turning the merge into a squash. - Never auto-recover from a failed
git pull. Stop and hand control back to the user. - Never parallelize the cascade or run branches concurrently (e.g. via subagents): each merge depends on the previous one and shares the git working tree. Run strictly oldest to newest, one at a time.
Trending
Quiet since September.about the whole repository
Who's talking about symfony/ux
- symfony/symfony“[Form] Add `MultiStepType`”GitHub · Jan 18, 2025 · 40 reactions
- twigphp/Twig“Add an `html_attr` function to make outputting HTML attributes easier”GitHub · Dec 6, 2023 · 12 reactions
- twigphp/Twig“Introduce CVA to html-extra”GitHub · Mar 9, 2024 · 6 reactions
- chartjs/Chart.js“Rollup build failing since Chart.js 3.9”GitHub · Aug 15, 2022 · 6 reactions
- contao/contao“Refactored backend controllers and backend module fragments”GitHub · Feb 14, 2021 · 6 reactions
The biggest 5 of 44 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 44
Talked about on GitHub and Stack Overflow (44 times).
On GitHub · 41
- Jan 18, 2025[Form] Add `MultiStepType` — symfony/symfony40 reactions · 24 comments
- Dec 6, 2023Add an `html_attr` function to make outputting HTML attributes easier — twigphp/Twig12 reactions · 35 comments
- Mar 9, 2024Introduce CVA to html-extra — twigphp/Twig6 reactions · 6 comments
- Aug 15, 2022Rollup build failing since Chart.js 3.9 — chartjs/Chart.js6 reactions · 2 comments
- Feb 14, 2021Refactored backend controllers and backend module fragments — contao/contao6 reactions · 2 comments
36 more on GitHub
- Jul 14, 2022Don't update package.json or controllers.json if vendor not updated — symfony/flex5 reactions · 6 comments
- Jun 4, 2025Improve `Config::getMergedConfig()` perf by ~15% — gehrisandro/tailwind-merge-phpsays it tested it3 reactions · 3 comments
- Nov 25, 2021Add `make:twig-component` maker — symfony/maker-bundle3 reactions · 6 comments
- Aug 8, 2026Switching away from `scrivo/highlight.php` in the code element — contao/contao2 reactions · 6 comments
- Jan 9, 2026[UX-Icon] Add ability to lock icon — Sylius/Sylius2 reactions · 3 comments
- Aug 18, 2024[RFC] Add PreLexerInterface — twigphp/Twig2 reactions · 3 comments
- Apr 18, 2024Twig functions becoming internal — twigphp/Twig2 reactions · 26 comments
- Sep 27, 2026Complete Twig function hash keys and values from the PHP parameter array shape — Haehnchen/idea-php-symfony2-plugin1 reaction
- Sep 17, 2026Fresh install using docker is failing with errors unable to access the database file. — SolidInvoice/SolidInvoice1 reaction
- Apr 10, 2026Update Symfony UX packages to 3.x — symfony/ux.symfony.com1 reaction
- Jan 20, 2026Add `html_attr_relaxed` escaping strategy — twigphp/Twig1 reaction · 3 comments
- Jan 16, 2026Import and migrate Toolkit recipes here — symfony/ux.symfony.com1 reaction
- Jan 12, 2026Support for ComponentName/index.html.twig anonymous templates — Haehnchen/idea-php-symfony2-plugin1 reaction · 1 comment
- Nov 22, 2025Fix declaration of twig extension as runtime — symfony/mercure-bundle1 reaction · 1 comment
- Nov 21, 2025feat: allow PHPUnit 9 — spatie/phpunit-snapshot-assertions1 reaction · 1 comment
- Oct 8, 2025[UX][Bug] Avoid considering "false" as a truthy value for "synchronize_package_json" — symfony/flex1 reaction · 6 comments
- Jul 16, 2025[Panther] Configure env `PANTHER_DEVTOOLS=0` — symfony/recipes1 reaction · 2 comments
- Jul 13, 2025[PropertyInfo] `PhpStanExtractor::getDocBlock` fallback to `getX()` PHPDoc even if property `X` exists (but has no PHPDoc) — symfony/symfony1 reaction · 2 comments
- May 7, 2025[FrameworkBundle] Ensure `Email` class exists before using it — symfony/symfony1 reaction · 2 comments
- Sep 19, 2024Auto-Set Locale from HTML-lang-attribute when used with international routing — FriendsOfSymfony/FOSJsRoutingBundle1 reaction · 1 comment
- Sep 18, 2024vite_entry_link_tags nonce attribute — lhapaipai/symfony-vite-dev1 reaction · 8 comments
- Jan 17, 2024[DomCrawler] Allow to add choices to single select — symfony/symfony1 reaction · 3 comments
- Dec 28, 2023🚧 New autocomplete — Sylius/Sylius1 reaction · 1 comment
- Nov 28, 2023Removing yarn — symfony/symfony-docs1 reaction · 3 comments
- Nov 9, 2023[AssetMapper] Only download a CSS file if it is explicitly advertised — symfony/symfony1 reaction · 2 comments
- Jan 17, 2022[WIP] Integrating UX docs more closely into Symfony docs — symfony/symfony-docs1 reaction · 6 comments
- Jan 11, 2022[HttpFoundation] : add support for text/vnd.turbo-stream.html — symfony/symfony1 reaction · 4 comments
- Feb 27, 2025How can we update the `TurboStreamListenerRenderer` configuration? — symfony/mercure-bundle0 reactions · 4 comments
- Jan 25, 2025Add contributing steps — symfony/stimulus-bridge0 reactions
- Jan 5, 2025Universal Module Definition (UMD) vs ES Modules (ESM) — Leaflet/Leaflet.Editable0 reactions · 2 comments
- Oct 11, 2024[AssetMapper] Document how to install in China (JsDelivr is not accessible reliably) — symfony/symfony0 reactions · 6 comments
- Apr 21, 2024Feature request: stimulus-helper package, a package for rendering stimulus attributes easily — ajaishankar/stimulus-reactive0 reactions · 3 comments
- May 4, 2023Upgrade Symfony UX — Demokratis-ch/demokratis-ch0 reactions
- Dec 10, 2021Symfony UX — Coderockr/backstage0 reactions
- Sep 29, 2021Handle state refresh without poll — sandoche/Symfony-ux-live-component-todo-list0 reactions
- Jun 17, 2021Use typing effect for pages' titles — Elao/elao_0 reactions
On Stack Overflow · 3
- Jul 21, 2023How to add DateTime adapter to symfony/ux-chartjs?2 votes
- Feb 22, 2023Symfony 5 - Override Form Type Options1 vote
- Jul 27, 2026Symfony UX Live Components: File Validation Only Triggers After Other Fields Pass Validation0 votes
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 1
- symfony/symfony★ 31k55% same
Wrote their own version · 1
- joris887/exosuit★ 8same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository7 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- pr-authoringSkill
- pr-review-merge-prepSkill
- security-triageSkill
- symfony-security-reviewSkill
- symfony-ux-toolkit-kitSkill
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

