fix: Handle push to checked-out branch in local non-bare repos
git refuses to push to a branch that is currently checked out in a non-bare repository. When the clone's origin is the user's local repo, this blocks merge_and_push entirely. On "branch is currently checked out" error, temporarily set receive.denyCurrentBranch=updateInstead on the remote and retry. This uses git's built-in mechanism to update the working tree safely (rejects if dirty).
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
* on project clones without requiring a worktree.
|
* on project clones without requiring a worktree.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { join } from 'node:path';
|
import { join, resolve } from 'node:path';
|
||||||
import { mkdtempSync, rmSync } from 'node:fs';
|
import { mkdtempSync, rmSync } from 'node:fs';
|
||||||
import { tmpdir } from 'node:os';
|
import { tmpdir } from 'node:os';
|
||||||
import { simpleGit } from 'simple-git';
|
import { simpleGit } from 'simple-git';
|
||||||
@@ -164,7 +164,26 @@ export class SimpleGitBranchManager implements BranchManager {
|
|||||||
|
|
||||||
async pushBranch(repoPath: string, branch: string, remote = 'origin'): Promise<void> {
|
async pushBranch(repoPath: string, branch: string, remote = 'origin'): Promise<void> {
|
||||||
const git = simpleGit(repoPath);
|
const git = simpleGit(repoPath);
|
||||||
|
try {
|
||||||
await git.push(remote, branch);
|
await git.push(remote, branch);
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : String(err);
|
||||||
|
if (!msg.includes('branch is currently checked out')) throw err;
|
||||||
|
|
||||||
|
// Local non-bare repo with the branch checked out — temporarily allow it.
|
||||||
|
// receive.denyCurrentBranch=updateInstead updates the remote's working tree
|
||||||
|
// and index to match, or rejects if the working tree is dirty.
|
||||||
|
const remoteUrl = (await git.remote(['get-url', remote]))?.trim();
|
||||||
|
if (!remoteUrl) throw err;
|
||||||
|
const remotePath = resolve(repoPath, remoteUrl);
|
||||||
|
const remoteGit = simpleGit(remotePath);
|
||||||
|
await remoteGit.addConfig('receive.denyCurrentBranch', 'updateInstead');
|
||||||
|
try {
|
||||||
|
await git.push(remote, branch);
|
||||||
|
} finally {
|
||||||
|
await remoteGit.raw(['config', '--unset', 'receive.denyCurrentBranch']);
|
||||||
|
}
|
||||||
|
}
|
||||||
log.info({ repoPath, branch, remote }, 'branch pushed to remote');
|
log.info({ repoPath, branch, remote }, 'branch pushed to remote');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user