From 89a7356933e8baba0fe2e470d04790aaf13e63a8 Mon Sep 17 00:00:00 2001 From: Melvin Carvalho Date: Sat, 16 May 2026 20:45:17 +0200 Subject: [PATCH] fix(git): pin auto-init default branch to `main` for predictable updateInstead `git init` (no `-b`) honours the server's `init.defaultBranch`, which on a server configured for e.g. `gh-pages` makes pushes to `main` silently fail to extract the working tree (the ref updates but `receive.denyCurrentBranch updateInstead` only fires when the push matches the branch HEAD points at). Pass `-b main` explicitly so the auto-init'd HEAD is deterministic regardless of server config. `git push pod HEAD:main` then works on every deployment. Adds a test reading `.git/HEAD` and asserting `ref: refs/heads/main`. Fixes #471 --- src/handlers/git.js | 8 +++++++- test/git-auto-init.test.js | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/handlers/git.js b/src/handlers/git.js index 2eced00c..3573bcae 100644 --- a/src/handlers/git.js +++ b/src/handlers/git.js @@ -140,7 +140,13 @@ function tryAutoInitRepo(repoAbs, log) { } else { mkdirSync(repoAbs, { recursive: true }); } - const result = spawnSync('git', ['init', repoAbs], { + // Pin the initial branch to `main` regardless of the server's + // `init.defaultBranch` config. `receive.denyCurrentBranch + // updateInstead` only extracts the working tree when the push + // targets the branch HEAD points at, so a deterministic default + // keeps `git push pod HEAD:main` working on every deployment. See + // #471. + const result = spawnSync('git', ['init', '-b', 'main', repoAbs], { stdio: ['ignore', 'pipe', 'pipe'] }); if (result.status !== 0) { diff --git a/test/git-auto-init.test.js b/test/git-auto-init.test.js index f55bdfb8..db651d91 100644 --- a/test/git-auto-init.test.js +++ b/test/git-auto-init.test.js @@ -15,7 +15,7 @@ import { createServer } from '../src/server.js'; import { createServer as createNetServer } from 'net'; import fs from 'fs-extra'; import path from 'path'; -import { existsSync, statSync, writeFileSync } from 'fs'; +import { existsSync, statSync, writeFileSync, readFileSync } from 'fs'; const TEST_HOST = 'localhost'; const DATA_DIR = './test-data-git-auto-init'; @@ -77,6 +77,21 @@ describe('Git auto-init on first push', () => { assert.ok(existsSync(path.join(dotGit, 'refs')), '.git/refs must exist'); }); + it('pins the initial branch to `main` regardless of server config', async () => { + // `updateInstead` only extracts the working tree when the push + // targets the branch HEAD points at. If `git init` honoured the + // server's `init.defaultBranch`, a server configured for e.g. + // `gh-pages` would silently fail to extract files pushed to `main`. + // Pin the auto-init'd HEAD so `git push pod HEAD:main` works + // everywhere. See #471. + const repoPath = 'public/apps/penny'; + const headPath = path.resolve(DATA_DIR, repoPath, '.git', 'HEAD'); + assert.ok(existsSync(headPath), 'prereq: repo from earlier test still exists'); + const head = readFileSync(headPath, 'utf8').trim(); + assert.strictEqual(head, 'ref: refs/heads/main', + `HEAD must point at refs/heads/main, got: ${head}`); + }); + it('auto-inits a regular repo when the target directory exists but is empty', async () => { const repoPath = 'public/empty-dir'; await fs.ensureDir(path.resolve(DATA_DIR, repoPath));