fix: forced monorepo splits fail during cleanup - #52

Merged
imorland merged 1 commit into
3.xfrom
im/fix-force-split
Aug 1, 2026
Merged

fix: forced monorepo splits fail during cleanup#52
imorland merged 1 commit into
3.xfrom
im/fix-force-split

Conversation

@imorland

Copy link
Copy Markdown
Member

Two bugs in monorepo:split --force, both found by using it regularly on the Flarum monorepo.

Cleanup deletes a branch that a forced split never creates

splitAndPush() only creates the <remote>-tmp branch on the non-forced path:

if(force){execSync(`git push --force ${pushArgs}`,{ cwd });// pushes the sha directly}else{execSync(`git switch -c ${tmpBranch}${sha1}`,{ cwd });}

but cleanupBranchAndRemote() ran git branch -D <remote>-tmp unconditionally. So every forced split threw once all the pushes had already succeeded — the work was done, the command still ended in an error.

--force ignored --no-interaction

The force confirmation is a confirm param with initial: false. In non-interactive mode PromptsIO::getParam() returns the initial value rather than prompting, so the answer was always "no" and monorepo:split --force --no-interaction reliably printed "Decided not to force push" and did nothing.

That's precisely the flag combination a script or CI job would use, and it silently no-oped. The confirmation is now skipped when the operator has already asked not to be prompted — --no-interaction means "don't ask me", so a forced split proceeds.

Worth being deliberate about: this makes --force --no-interaction genuinely force-push to every split repo without confirmation. That is the intent of the flag pair, and the guard remains for interactive use.

Verification

yarn test — 22 suites, 176 tests, Prettier clean. Both paths exercised by hand against the Flarum monorepo on Apple silicon over an extended period.

splitAndPush only creates the <remote>-tmp branch on the non-forced
path — a forced split pushes the split sha straight to the remote — but
cleanupBranchAndRemote deleted that branch unconditionally, so every
forced split ended in a git error once the pushes had succeeded.
Forced splits also ignored --no-interaction. getParam answers a confirm
with its initial value in non-interactive mode, and this one starts at
false, so 'monorepo:split --force --no-interaction' always took the
'decided not to force push' path and quietly did nothing — which is
exactly the combination a script or CI job would use. The confirmation
is now skipped when the operator has already asked for no prompts.
@imorland
imorland merged commit 24f5046 into 3.xAug 1, 2026
3 checks passed
@imorland
imorland deleted the im/fix-force-split branch August 1, 2026 00:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@imorland
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix: forced monorepo splits fail during cleanup - #52

Merged
imorland merged 1 commit into
3.xfrom
im/fix-force-split
Aug 1, 2026
Merged

fix: forced monorepo splits fail during cleanup#52
imorland merged 1 commit into
3.xfrom
im/fix-force-split

Conversation

@imorland

Copy link
Copy Markdown
Member

Two bugs in monorepo:split --force, both found by using it regularly on the Flarum monorepo.

Cleanup deletes a branch that a forced split never creates

splitAndPush() only creates the <remote>-tmp branch on the non-forced path:

if(force){execSync(`git push --force ${pushArgs}`,{ cwd });// pushes the sha directly}else{execSync(`git switch -c ${tmpBranch}${sha1}`,{ cwd });}

but cleanupBranchAndRemote() ran git branch -D <remote>-tmp unconditionally. So every forced split threw once all the pushes had already succeeded — the work was done, the command still ended in an error.

--force ignored --no-interaction

The force confirmation is a confirm param with initial: false. In non-interactive mode PromptsIO::getParam() returns the initial value rather than prompting, so the answer was always "no" and monorepo:split --force --no-interaction reliably printed "Decided not to force push" and did nothing.

That's precisely the flag combination a script or CI job would use, and it silently no-oped. The confirmation is now skipped when the operator has already asked not to be prompted — --no-interaction means "don't ask me", so a forced split proceeds.

Worth being deliberate about: this makes --force --no-interaction genuinely force-push to every split repo without confirmation. That is the intent of the flag pair, and the guard remains for interactive use.

Verification

yarn test — 22 suites, 176 tests, Prettier clean. Both paths exercised by hand against the Flarum monorepo on Apple silicon over an extended period.

splitAndPush only creates the <remote>-tmp branch on the non-forced
path — a forced split pushes the split sha straight to the remote — but
cleanupBranchAndRemote deleted that branch unconditionally, so every
forced split ended in a git error once the pushes had succeeded.
Forced splits also ignored --no-interaction. getParam answers a confirm
with its initial value in non-interactive mode, and this one starts at
false, so 'monorepo:split --force --no-interaction' always took the
'decided not to force push' path and quietly did nothing — which is
exactly the combination a script or CI job would use. The confirmation
is now skipped when the operator has already asked for no prompts.
@imorland
imorland merged commit 24f5046 into 3.xAug 1, 2026
3 checks passed
@imorland
imorland deleted the im/fix-force-split branch August 1, 2026 00:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@imorland
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: forced monorepo splits fail during cleanup - #52

Merged
imorland merged 1 commit into
3.xfrom
im/fix-force-split
Aug 1, 2026
Merged

fix: forced monorepo splits fail during cleanup#52
imorland merged 1 commit into
3.xfrom
im/fix-force-split

Conversation

@imorland

Copy link
Copy Markdown
Member

Two bugs in monorepo:split --force, both found by using it regularly on the Flarum monorepo.

Cleanup deletes a branch that a forced split never creates

splitAndPush() only creates the <remote>-tmp branch on the non-forced path:

if(force){execSync(`git push --force ${pushArgs}`,{ cwd });// pushes the sha directly}else{execSync(`git switch -c ${tmpBranch}${sha1}`,{ cwd });}

but cleanupBranchAndRemote() ran git branch -D <remote>-tmp unconditionally. So every forced split threw once all the pushes had already succeeded — the work was done, the command still ended in an error.

--force ignored --no-interaction

The force confirmation is a confirm param with initial: false. In non-interactive mode PromptsIO::getParam() returns the initial value rather than prompting, so the answer was always "no" and monorepo:split --force --no-interaction reliably printed "Decided not to force push" and did nothing.

That's precisely the flag combination a script or CI job would use, and it silently no-oped. The confirmation is now skipped when the operator has already asked not to be prompted — --no-interaction means "don't ask me", so a forced split proceeds.

Worth being deliberate about: this makes --force --no-interaction genuinely force-push to every split repo without confirmation. That is the intent of the flag pair, and the guard remains for interactive use.

Verification

yarn test — 22 suites, 176 tests, Prettier clean. Both paths exercised by hand against the Flarum monorepo on Apple silicon over an extended period.

splitAndPush only creates the <remote>-tmp branch on the non-forced
path — a forced split pushes the split sha straight to the remote — but
cleanupBranchAndRemote deleted that branch unconditionally, so every
forced split ended in a git error once the pushes had succeeded.
Forced splits also ignored --no-interaction. getParam answers a confirm
with its initial value in non-interactive mode, and this one starts at
false, so 'monorepo:split --force --no-interaction' always took the
'decided not to force push' path and quietly did nothing — which is
exactly the combination a script or CI job would use. The confirmation
is now skipped when the operator has already asked for no prompts.
@imorland
imorland merged commit 24f5046 into 3.xAug 1, 2026
3 checks passed
@imorland
imorland deleted the im/fix-force-split branch August 1, 2026 00:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@imorland
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: forced monorepo splits fail during cleanup - #52

Merged
imorland merged 1 commit into
3.xfrom
im/fix-force-split
Aug 1, 2026
Merged

fix: forced monorepo splits fail during cleanup#52
imorland merged 1 commit into
3.xfrom
im/fix-force-split

Conversation

@imorland

Copy link
Copy Markdown
Member

Two bugs in monorepo:split --force, both found by using it regularly on the Flarum monorepo.

Cleanup deletes a branch that a forced split never creates

splitAndPush() only creates the <remote>-tmp branch on the non-forced path:

if(force){execSync(`git push --force ${pushArgs}`,{ cwd });// pushes the sha directly}else{execSync(`git switch -c ${tmpBranch}${sha1}`,{ cwd });}

but cleanupBranchAndRemote() ran git branch -D <remote>-tmp unconditionally. So every forced split threw once all the pushes had already succeeded — the work was done, the command still ended in an error.

--force ignored --no-interaction

The force confirmation is a confirm param with initial: false. In non-interactive mode PromptsIO::getParam() returns the initial value rather than prompting, so the answer was always "no" and monorepo:split --force --no-interaction reliably printed "Decided not to force push" and did nothing.

That's precisely the flag combination a script or CI job would use, and it silently no-oped. The confirmation is now skipped when the operator has already asked not to be prompted — --no-interaction means "don't ask me", so a forced split proceeds.

Worth being deliberate about: this makes --force --no-interaction genuinely force-push to every split repo without confirmation. That is the intent of the flag pair, and the guard remains for interactive use.

Verification

yarn test — 22 suites, 176 tests, Prettier clean. Both paths exercised by hand against the Flarum monorepo on Apple silicon over an extended period.

splitAndPush only creates the <remote>-tmp branch on the non-forced
path — a forced split pushes the split sha straight to the remote — but
cleanupBranchAndRemote deleted that branch unconditionally, so every
forced split ended in a git error once the pushes had succeeded.
Forced splits also ignored --no-interaction. getParam answers a confirm
with its initial value in non-interactive mode, and this one starts at
false, so 'monorepo:split --force --no-interaction' always took the
'decided not to force push' path and quietly did nothing — which is
exactly the combination a script or CI job would use. The confirmation
is now skipped when the operator has already asked for no prompts.
@imorland
imorland merged commit 24f5046 into 3.xAug 1, 2026
3 checks passed
@imorland
imorland deleted the im/fix-force-split branch August 1, 2026 00:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@imorland
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix: forced monorepo splits fail during cleanup - #52

Merged
imorland merged 1 commit into
3.xfrom
im/fix-force-split
Aug 1, 2026
Merged

fix: forced monorepo splits fail during cleanup#52
imorland merged 1 commit into
3.xfrom
im/fix-force-split

Conversation

@imorland

Copy link
Copy Markdown
Member

Two bugs in monorepo:split --force, both found by using it regularly on the Flarum monorepo.

Cleanup deletes a branch that a forced split never creates

splitAndPush() only creates the <remote>-tmp branch on the non-forced path:

if(force){execSync(`git push --force ${pushArgs}`,{ cwd });// pushes the sha directly}else{execSync(`git switch -c ${tmpBranch}${sha1}`,{ cwd });}

but cleanupBranchAndRemote() ran git branch -D <remote>-tmp unconditionally. So every forced split threw once all the pushes had already succeeded — the work was done, the command still ended in an error.

--force ignored --no-interaction

The force confirmation is a confirm param with initial: false. In non-interactive mode PromptsIO::getParam() returns the initial value rather than prompting, so the answer was always "no" and monorepo:split --force --no-interaction reliably printed "Decided not to force push" and did nothing.

That's precisely the flag combination a script or CI job would use, and it silently no-oped. The confirmation is now skipped when the operator has already asked not to be prompted — --no-interaction means "don't ask me", so a forced split proceeds.

Worth being deliberate about: this makes --force --no-interaction genuinely force-push to every split repo without confirmation. That is the intent of the flag pair, and the guard remains for interactive use.

Verification

yarn test — 22 suites, 176 tests, Prettier clean. Both paths exercised by hand against the Flarum monorepo on Apple silicon over an extended period.

splitAndPush only creates the <remote>-tmp branch on the non-forced
path — a forced split pushes the split sha straight to the remote — but
cleanupBranchAndRemote deleted that branch unconditionally, so every
forced split ended in a git error once the pushes had succeeded.
Forced splits also ignored --no-interaction. getParam answers a confirm
with its initial value in non-interactive mode, and this one starts at
false, so 'monorepo:split --force --no-interaction' always took the
'decided not to force push' path and quietly did nothing — which is
exactly the combination a script or CI job would use. The confirmation
is now skipped when the operator has already asked for no prompts.
@imorland
imorland merged commit 24f5046 into 3.xAug 1, 2026
3 checks passed
@imorland
imorland deleted the im/fix-force-split branch August 1, 2026 00:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@imorland
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: forced monorepo splits fail during cleanup - #52

Merged
imorland merged 1 commit into
3.xfrom
im/fix-force-split
Aug 1, 2026
Merged

fix: forced monorepo splits fail during cleanup#52
imorland merged 1 commit into
3.xfrom
im/fix-force-split

Conversation

@imorland

Copy link
Copy Markdown
Member

Two bugs in monorepo:split --force, both found by using it regularly on the Flarum monorepo.

Cleanup deletes a branch that a forced split never creates

splitAndPush() only creates the <remote>-tmp branch on the non-forced path:

if(force){execSync(`git push --force ${pushArgs}`,{ cwd });// pushes the sha directly}else{execSync(`git switch -c ${tmpBranch}${sha1}`,{ cwd });}

but cleanupBranchAndRemote() ran git branch -D <remote>-tmp unconditionally. So every forced split threw once all the pushes had already succeeded — the work was done, the command still ended in an error.

--force ignored --no-interaction

The force confirmation is a confirm param with initial: false. In non-interactive mode PromptsIO::getParam() returns the initial value rather than prompting, so the answer was always "no" and monorepo:split --force --no-interaction reliably printed "Decided not to force push" and did nothing.

That's precisely the flag combination a script or CI job would use, and it silently no-oped. The confirmation is now skipped when the operator has already asked not to be prompted — --no-interaction means "don't ask me", so a forced split proceeds.

Worth being deliberate about: this makes --force --no-interaction genuinely force-push to every split repo without confirmation. That is the intent of the flag pair, and the guard remains for interactive use.

Verification

yarn test — 22 suites, 176 tests, Prettier clean. Both paths exercised by hand against the Flarum monorepo on Apple silicon over an extended period.

splitAndPush only creates the <remote>-tmp branch on the non-forced
path — a forced split pushes the split sha straight to the remote — but
cleanupBranchAndRemote deleted that branch unconditionally, so every
forced split ended in a git error once the pushes had succeeded.
Forced splits also ignored --no-interaction. getParam answers a confirm
with its initial value in non-interactive mode, and this one starts at
false, so 'monorepo:split --force --no-interaction' always took the
'decided not to force push' path and quietly did nothing — which is
exactly the combination a script or CI job would use. The confirmation
is now skipped when the operator has already asked for no prompts.
@imorland
imorland merged commit 24f5046 into 3.xAug 1, 2026
3 checks passed
@imorland
imorland deleted the im/fix-force-split branch August 1, 2026 00:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@imorland
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix: forced monorepo splits fail during cleanup - #52

Merged
imorland merged 1 commit into
3.xfrom
im/fix-force-split
Aug 1, 2026
Merged

fix: forced monorepo splits fail during cleanup#52
imorland merged 1 commit into
3.xfrom
im/fix-force-split

Conversation

@imorland

Copy link
Copy Markdown
Member

Two bugs in monorepo:split --force, both found by using it regularly on the Flarum monorepo.

Cleanup deletes a branch that a forced split never creates

splitAndPush() only creates the <remote>-tmp branch on the non-forced path:

if(force){execSync(`git push --force ${pushArgs}`,{ cwd });// pushes the sha directly}else{execSync(`git switch -c ${tmpBranch}${sha1}`,{ cwd });}

but cleanupBranchAndRemote() ran git branch -D <remote>-tmp unconditionally. So every forced split threw once all the pushes had already succeeded — the work was done, the command still ended in an error.

--force ignored --no-interaction

The force confirmation is a confirm param with initial: false. In non-interactive mode PromptsIO::getParam() returns the initial value rather than prompting, so the answer was always "no" and monorepo:split --force --no-interaction reliably printed "Decided not to force push" and did nothing.

That's precisely the flag combination a script or CI job would use, and it silently no-oped. The confirmation is now skipped when the operator has already asked not to be prompted — --no-interaction means "don't ask me", so a forced split proceeds.

Worth being deliberate about: this makes --force --no-interaction genuinely force-push to every split repo without confirmation. That is the intent of the flag pair, and the guard remains for interactive use.

Verification

yarn test — 22 suites, 176 tests, Prettier clean. Both paths exercised by hand against the Flarum monorepo on Apple silicon over an extended period.

splitAndPush only creates the <remote>-tmp branch on the non-forced
path — a forced split pushes the split sha straight to the remote — but
cleanupBranchAndRemote deleted that branch unconditionally, so every
forced split ended in a git error once the pushes had succeeded.
Forced splits also ignored --no-interaction. getParam answers a confirm
with its initial value in non-interactive mode, and this one starts at
false, so 'monorepo:split --force --no-interaction' always took the
'decided not to force push' path and quietly did nothing — which is
exactly the combination a script or CI job would use. The confirmation
is now skipped when the operator has already asked for no prompts.
@imorland
imorland merged commit 24f5046 into 3.xAug 1, 2026
3 checks passed
@imorland
imorland deleted the im/fix-force-split branch August 1, 2026 00:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@imorland
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix: forced monorepo splits fail during cleanup - #52

Merged
imorland merged 1 commit into
3.xfrom
im/fix-force-split
Aug 1, 2026
Merged

fix: forced monorepo splits fail during cleanup#52
imorland merged 1 commit into
3.xfrom
im/fix-force-split

Conversation

@imorland

Copy link
Copy Markdown
Member

Two bugs in monorepo:split --force, both found by using it regularly on the Flarum monorepo.

Cleanup deletes a branch that a forced split never creates

splitAndPush() only creates the <remote>-tmp branch on the non-forced path:

if(force){execSync(`git push --force ${pushArgs}`,{ cwd });// pushes the sha directly}else{execSync(`git switch -c ${tmpBranch}${sha1}`,{ cwd });}

but cleanupBranchAndRemote() ran git branch -D <remote>-tmp unconditionally. So every forced split threw once all the pushes had already succeeded — the work was done, the command still ended in an error.

--force ignored --no-interaction

The force confirmation is a confirm param with initial: false. In non-interactive mode PromptsIO::getParam() returns the initial value rather than prompting, so the answer was always "no" and monorepo:split --force --no-interaction reliably printed "Decided not to force push" and did nothing.

That's precisely the flag combination a script or CI job would use, and it silently no-oped. The confirmation is now skipped when the operator has already asked not to be prompted — --no-interaction means "don't ask me", so a forced split proceeds.

Worth being deliberate about: this makes --force --no-interaction genuinely force-push to every split repo without confirmation. That is the intent of the flag pair, and the guard remains for interactive use.

Verification

yarn test — 22 suites, 176 tests, Prettier clean. Both paths exercised by hand against the Flarum monorepo on Apple silicon over an extended period.

splitAndPush only creates the <remote>-tmp branch on the non-forced
path — a forced split pushes the split sha straight to the remote — but
cleanupBranchAndRemote deleted that branch unconditionally, so every
forced split ended in a git error once the pushes had succeeded.
Forced splits also ignored --no-interaction. getParam answers a confirm
with its initial value in non-interactive mode, and this one starts at
false, so 'monorepo:split --force --no-interaction' always took the
'decided not to force push' path and quietly did nothing — which is
exactly the combination a script or CI job would use. The confirmation
is now skipped when the operator has already asked for no prompts.
@imorland
imorland merged commit 24f5046 into 3.xAug 1, 2026
3 checks passed
@imorland
imorland deleted the im/fix-force-split branch August 1, 2026 00:01
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@imorland