|
| 1 | +--- |
| 2 | +name: merge-up |
| 3 | +description: > |
| 4 | + Cascade-merge maintained branches from oldest to newest (e.g. |
| 5 | + 3.1.x → 3.2.x → 3.3.x → 4.0.x). Use when the user says "merge branches", |
| 6 | + "merge up", "cascade merge", "sync branches", or "update branches". |
| 7 | +--- |
| 8 | + |
| 9 | +# Branch Cascade Merge |
| 10 | + |
| 11 | +Merges each maintained branch into the next one, from oldest to newest. |
| 12 | + |
| 13 | +## Progress checklist |
| 14 | + |
| 15 | +- [ ] Step 0: Pre-flight checks |
| 16 | +- [ ] Step 1: Determine maintained branches and pull them |
| 17 | +- [ ] Step 2: Cascade merge loop |
| 18 | + |
| 19 | +--- |
| 20 | + |
| 21 | +## Confirmation rule |
| 22 | + |
| 23 | +Whenever the skill says **"Wait for confirmation"**, treat anything other than an |
| 24 | +explicit affirmative as **no**: stop and ask the user how they want to proceed. |
| 25 | + |
| 26 | +--- |
| 27 | + |
| 28 | +## Step 0 — Pre-flight checks |
| 29 | + |
| 30 | +```bash |
| 31 | +git status --porcelain --untracked-files=no |
| 32 | +``` |
| 33 | + |
| 34 | +If any output, **stop**: |
| 35 | +> "The working tree is not clean. Please commit or stash your changes first." |
| 36 | +
|
| 37 | +--- |
| 38 | + |
| 39 | +## Step 1 — Determine maintained branches and pull them |
| 40 | + |
| 41 | +### 1a. Get the branch list |
| 42 | + |
| 43 | +Ask the user which branches to cascade-merge. The user should provide an |
| 44 | +ordered list from oldest to newest (e.g. `3.1.x 3.2.x 3.3.x 4.0.x`). |
| 45 | + |
| 46 | +If the user doesn't provide a list, determine it from remote branches: |
| 47 | + |
| 48 | +```bash |
| 49 | +git branch -r --list 'origin/*.*.x' | sed 's|origin/||' | sort -V |
| 50 | +``` |
| 51 | + |
| 52 | +Present the list and **wait for confirmation** before proceeding. The user may |
| 53 | +want to exclude some branches (e.g. EOL branches). Store the confirmed list as |
| 54 | +`BRANCHES`. |
| 55 | + |
| 56 | +### 1b. Pull every branch |
| 57 | + |
| 58 | +For each branch in `BRANCHES`: |
| 59 | + |
| 60 | +```bash |
| 61 | +git checkout <branch> |
| 62 | +git pull --ff-only origin <branch> |
| 63 | +``` |
| 64 | + |
| 65 | +Using `--ff-only` ensures local branches haven't diverged from origin. If the |
| 66 | +pull fails, **stop** and report the error. |
| 67 | + |
| 68 | +--- |
| 69 | + |
| 70 | +## Step 2 — Cascade merge loop |
| 71 | + |
| 72 | +For each consecutive pair `(SOURCE, TARGET)` in `BRANCHES`: |
| 73 | + |
| 74 | +### 2a. Merge |
| 75 | + |
| 76 | +```bash |
| 77 | +git checkout <TARGET> |
| 78 | +git merge <SOURCE> |
| 79 | +``` |
| 80 | + |
| 81 | +Three outcomes are possible: |
| 82 | + |
| 83 | +- **Already up-to-date:** print "✓ `<TARGET>` already up-to-date with `<SOURCE>`" |
| 84 | + and skip to the next pair. |
| 85 | +- **Clean merge (no conflicts):** git creates the merge commit automatically. |
| 86 | + Proceed directly to step 2c. |
| 87 | +- **Conflicts:** proceed to step 2b. |
| 88 | + |
| 89 | +### 2b. Resolve conflicts (only when git reports conflicts) |
| 90 | + |
| 91 | +List conflicts: |
| 92 | + |
| 93 | +```bash |
| 94 | +git diff --name-only --diff-filter=U |
| 95 | +``` |
| 96 | + |
| 97 | +Read each conflicted file, resolve it, then `git add` it. When all are resolved: |
| 98 | + |
| 99 | +```bash |
| 100 | +git commit --no-edit |
| 101 | +``` |
| 102 | + |
| 103 | +#### Conflict resolution rules |
| 104 | + |
| 105 | +| File pattern | Strategy | |
| 106 | +|---|---| |
| 107 | +| `CHANGELOG*.md` | Keep entries from both sides; newer branch entries on top | |
| 108 | +| Version constants, `composer.json` branch aliases | Keep the TARGET branch value | |
| 109 | +| `composer.json` dependency versions | Keep the TARGET branch value (newer branch may require higher versions) | |
| 110 | +| Code files | Merge logically based on context; when unsure, ask the user | |
| 111 | + |
| 112 | +After resolving, show `git diff HEAD~1` (first parent of the merge commit, i.e. |
| 113 | +the previous TARGET state) and wait for the user to confirm the resolution looks |
| 114 | +correct before proceeding. |
| 115 | + |
| 116 | +### 2c. Run tests |
| 117 | + |
| 118 | +Run the test suite to verify the merge didn't break anything: |
| 119 | + |
| 120 | +```bash |
| 121 | +composer install |
| 122 | +vendor/bin/phpunit |
| 123 | +``` |
| 124 | + |
| 125 | +If the project uses `castor`, prefer: |
| 126 | + |
| 127 | +```bash |
| 128 | +composer install |
| 129 | +castor phpunit |
| 130 | +``` |
| 131 | + |
| 132 | +If tests fail, first check whether the failure is pre-existing: run the same |
| 133 | +test on the TARGET branch before the merge. Only fix failures introduced by the |
| 134 | +merge: |
| 135 | +1. Analyze and fix the code. |
| 136 | +2. Commit the fix with a descriptive message. |
| 137 | +3. Re-run failing tests until green. |
| 138 | + |
| 139 | +Report any pre-existing failures to the user without attempting to fix them. |
| 140 | + |
| 141 | +### 2d. Ask for confirmation before pushing |
| 142 | + |
| 143 | +Show: |
| 144 | + |
| 145 | +``` |
| 146 | +Merge: <SOURCE> → <TARGET> |
| 147 | +Tests: all passing |
| 148 | +
|
| 149 | +Commits since origin/<TARGET>: |
| 150 | +git log --oneline origin/<TARGET>..<TARGET> |
| 151 | +
|
| 152 | +Ready to push? (yes / no) |
| 153 | +``` |
| 154 | + |
| 155 | +**Wait for confirmation.** The user may make changes themselves before confirming. |
| 156 | + |
| 157 | +### 2e. Push and continue |
| 158 | + |
| 159 | +```bash |
| 160 | +git push origin <TARGET> |
| 161 | +``` |
| 162 | + |
| 163 | +If the push fails, **stop** and report the error. |
| 164 | + |
| 165 | +Print "✓ `<SOURCE>` → `<TARGET>` done." and continue to the next pair. |
| 166 | + |
| 167 | +--- |
| 168 | + |
| 169 | +## Final summary |
| 170 | + |
| 171 | +``` |
| 172 | +All merges complete: |
| 173 | + 3.1.x → 3.2.x ✓ |
| 174 | + 3.2.x → 3.3.x ✓ |
| 175 | + 3.3.x → 4.0.x ✓ |
| 176 | +``` |
| 177 | + |
| 178 | +--- |
| 179 | + |
| 180 | +## Gotchas |
| 181 | + |
| 182 | +- `CHANGELOG.md` conflicts are the most common; entries must be kept from both |
| 183 | + sides, never dropped. |
| 184 | +- A merge can introduce test failures even without conflicts, because behavior |
| 185 | + from the older branch may be incompatible with newer code. Always run tests. |
| 186 | +- When merging across major versions (e.g. 3.x → 4.x), pay extra attention to |
| 187 | + breaking changes, removed deprecations, and updated PHP version requirements. |
| 188 | + |
| 189 | +## Error handling |
| 190 | + |
| 191 | +- **Never** force-push or rewrite history. |
| 192 | +- **Never** use `--no-verify` on commits. |
| 193 | +- **Never** auto-recover from a failed `git push` or `git pull`. Stop and hand |
| 194 | + control back to the user. |
0 commit comments