From f741b6104946c36e34527a2f195100bf271c156d Mon Sep 17 00:00:00 2001 From: schickling-assistant <261620128+schickling-assistant@users.noreply.github.com> Date: Tue, 10 Nov 2026 01:53:38 +0100 Subject: [PATCH 1/3] fix(megarepo): enable reflogs on store bare repositories agent-identity: agent/effect-utils/effect-utils-manager agent-persona: generalist agent-supervisor: unavailable agent-tool: unknown agent-runtime: unknown agent-model: unknown --- packages/@overeng/megarepo/docs/spec.md | 4 + .../src/core/git-reflog.integration.test.ts | 88 +++++++++++++++++++ packages/@overeng/megarepo/src/core/git.ts | 26 ++++++ 3 files changed, 118 insertions(+) create mode 100644 packages/@overeng/megarepo/src/core/git-reflog.integration.test.ts diff --git a/packages/@overeng/megarepo/docs/spec.md b/packages/@overeng/megarepo/docs/spec.md index 8a7b61d59d..7c7a72979e 100644 --- a/packages/@overeng/megarepo/docs/spec.md +++ b/packages/@overeng/megarepo/docs/spec.md @@ -37,6 +37,10 @@ Global repository cache at `~/.megarepo/` (configurable via `MEGAREPO_STORE`). The store uses **bare repos with worktrees per ref**: +New bare stores set local `core.logAllRefUpdates=true` so branch updates leave +reflogs for last-touch and recovery evidence. Fetching an existing store enables +this setting before updating refs, preserving an existing `always` value. + ``` ~/.megarepo/ github.com/ diff --git a/packages/@overeng/megarepo/src/core/git-reflog.integration.test.ts b/packages/@overeng/megarepo/src/core/git-reflog.integration.test.ts new file mode 100644 index 0000000000..2e10a8c8e1 --- /dev/null +++ b/packages/@overeng/megarepo/src/core/git-reflog.integration.test.ts @@ -0,0 +1,88 @@ +import { NodeServices } from '@effect/platform-node' +import { describe, it } from '@effect/vitest' +import { Effect } from 'effect' +import * as FileSystem from 'effect/FileSystem' +import { expect } from 'vitest' + +import * as Git from './git.ts' + +const makeFixture = Effect.gen(function* () { + const fs = yield* FileSystem.FileSystem + const root = yield* fs.makeTempDirectoryScoped() + const source = `${root}/source` + const bare = `${root}/store.git` + yield* fs.makeDirectory(source) + yield* Git.runCommand({ cwd: source, args: ['init', '-b', 'main'] }) + yield* Git.runCommand({ + cwd: source, + args: [ + '-c', + 'user.name=Test User', + '-c', + 'user.email=test@example.com', + '-c', + 'commit.gpgsign=false', + 'commit', + '--allow-empty', + '-m', + 'initial', + ], + }) + yield* Git.cloneBare({ url: source, targetPath: bare }) + return { source, bare } +}) + +const readLogging = (repoPath: string) => + Git.runCommand({ + cwd: repoPath, + args: ['config', '--local', '--get', 'core.logAllRefUpdates'], + }) + +const expectFetchedReflog = (repoPath: string) => + Effect.gen(function* () { + const commit = yield* Git.runCommand({ cwd: repoPath, args: ['rev-parse', 'main'] }) + const reflog = yield* Git.runCommand({ + cwd: repoPath, + args: ['reflog', 'show', '--format=%H', 'refs/remotes/origin/main'], + }) + expect(reflog.split('\n')).toContain(commit) + }) + +describe('bare store reflogs', () => { + it.effect('enables reflogs on clone and records a later branch update', () => + Effect.gen(function* () { + const { bare } = yield* makeFixture + expect(yield* readLogging(bare)).toBe('true') + yield* Git.fetchBare({ repoPath: bare }) + yield* expectFetchedReflog(bare) + }).pipe(Effect.provide(NodeServices.layer), Effect.scoped), + ) + + it.effect('enables missing local reflog configuration before fetching existing stores', () => + Effect.gen(function* () { + const { bare } = yield* makeFixture + yield* Git.runCommand({ + cwd: bare, + args: ['config', '--local', '--unset-all', 'core.logAllRefUpdates'], + }) + yield* Git.fetchBare({ repoPath: bare }) + expect(yield* readLogging(bare)).toBe('true') + yield* expectFetchedReflog(bare) + }).pipe(Effect.provide(NodeServices.layer), Effect.scoped), + ) + + for (const value of ['false', 'always']) { + it.effect(`fetch ${value === 'always' ? 'preserves always' : 'enables disabled reflogs'}`, () => + Effect.gen(function* () { + const { bare } = yield* makeFixture + yield* Git.runCommand({ + cwd: bare, + args: ['config', '--local', 'core.logAllRefUpdates', value], + }) + yield* Git.fetchBare({ repoPath: bare }) + expect(yield* readLogging(bare)).toBe(value === 'always' ? 'always' : 'true') + yield* expectFetchedReflog(bare) + }).pipe(Effect.provide(NodeServices.layer), Effect.scoped), + ) + } +}) diff --git a/packages/@overeng/megarepo/src/core/git.ts b/packages/@overeng/megarepo/src/core/git.ts index 8bb6195661..7a2fc79a58 100644 --- a/packages/@overeng/megarepo/src/core/git.ts +++ b/packages/@overeng/megarepo/src/core/git.ts @@ -891,6 +891,27 @@ export const repairBareOriginFetchRefspec = ({ repoPath }: { repoPath: string }) }), ) +/** Enable store reflogs without weakening an existing `always` policy. Caller holds the writer lock. */ +export const ensureBareRefLogging = Effect.fn('git/ensure-bare-ref-logging')(function* ({ + repoPath, +}: { + repoPath: string +}) { + const value = yield* runGitCommand({ + args: ['config', '--local', '--get', 'core.logAllRefUpdates'], + cwd: repoPath, + }).pipe( + Effect.catchTag('GitCommandError', (error) => + error.exitCode === 1 && error.stderr === '' ? Effect.succeed('') : Effect.fail(error), + ), + ) + if (value === 'true' || value === 'always') return + yield* runGitCommand({ + args: ['config', '--local', 'core.logAllRefUpdates', 'true'], + cwd: repoPath, + }) +}) + /** * Clone a repository as a bare repo. * Configures fetch refspec so remote tracking refs are created on fetch. @@ -929,6 +950,10 @@ export const cloneBare = (args: { url: string; targetPath: string }) => { args: ['config', 'remote.origin.fetch', bareOriginFetchRefspec], cwd: args.targetPath, }) + yield* runGitCommand({ + args: ['config', '--local', 'core.logAllRefUpdates', 'true'], + cwd: args.targetPath, + }) return exists === false }).pipe( withGitWriterLock({ path: args.targetPath, create: true }), @@ -959,6 +984,7 @@ export const fetchBare = (args: { refs?: ReadonlyArray }) => Effect.gen(function* () { + yield* ensureBareRefLogging({ repoPath: args.repoPath }) const remote = args.remote ?? 'origin' yield* runGitCommandWithRetry({ args: ['fetch', '--no-tags', '--prune', remote, bareOriginFetchRefspec], From d843b17ab0b17da8f96f935ad66a684b7b3150be Mon Sep 17 00:00:00 2001 From: schickling-assistant <261620128+schickling-assistant@users.noreply.github.com> Date: Tue, 10 Nov 2026 14:54:19 +0100 Subject: [PATCH 2/3] fix(megarepo): register reflog regression coverage agent-identity: agent/effect-utils/effect-utils-manager agent-persona: generalist agent-supervisor: unavailable agent-tool: OMP agent-tool-version: 18.12.5 agent-runtime: OMP 18.12.5 agent-model: openai-codex/gpt-6.1-sol --- buck2-test-authority.json | 2 ++ packages/@overeng/megarepo/BUCK | 6 +++- .../src/core/git-reflog.integration.test.ts | 29 +++++++++++-------- packages/@overeng/megarepo/src/core/git.ts | 3 +- packages/@overeng/tui-stories/BUCK | 5 +++- 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/buck2-test-authority.json b/buck2-test-authority.json index cc10ad8cf4..65010845d7 100644 --- a/buck2-test-authority.json +++ b/buck2-test-authority.json @@ -887,6 +887,7 @@ "src/cli/worktree-lease.integration.test.ts", "src/core/config.unit.test.ts", "src/core/git-memory.integration.test.ts", + "src/core/git-reflog.integration.test.ts", "src/core/git-streaming-parsers.integration.test.ts", "src/core/git-timeout.integration.test.ts", "src/core/git.unit.test.ts", @@ -963,6 +964,7 @@ "src/cli/worktree-lease.integration.test.ts", "src/core/config.unit.test.ts", "src/core/git-memory.integration.test.ts", + "src/core/git-reflog.integration.test.ts", "src/core/git-streaming-parsers.integration.test.ts", "src/core/git-timeout.integration.test.ts", "src/core/git.unit.test.ts", diff --git a/packages/@overeng/megarepo/BUCK b/packages/@overeng/megarepo/BUCK index 9e8d651ef0..b883868299 100644 --- a/packages/@overeng/megarepo/BUCK +++ b/packages/@overeng/megarepo/BUCK @@ -7,7 +7,7 @@ load("//buck2/products:defs.bzl", "javascript_product") # Projection source: packages/@overeng/megarepo/BUCK.genie.ts # Projection schema version: 13 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:467bfb4a75d4f8ac21b6c3a623362f1ec8c7f974b9f11a87f86cfc838408ae10 +# Semantic fingerprint: sha256:2fb65b1597af84bcf5758af087b0b7f7bdc22f0989894249082a76dfc500e193 # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") @@ -193,6 +193,7 @@ export_materialization_inputs([ "src/core/config.ts", "src/core/config.unit.test.ts", "src/core/git-memory.integration.test.ts", + "src/core/git-reflog.integration.test.ts", "src/core/git-streaming-parsers.integration.test.ts", "src/core/git-timeout.integration.test.ts", "src/core/git.ts", @@ -519,6 +520,7 @@ package_view( "src/core/config.ts": "src/core/config.ts", "src/core/config.unit.test.ts": "src/core/config.unit.test.ts", "src/core/git-memory.integration.test.ts": "src/core/git-memory.integration.test.ts", + "src/core/git-reflog.integration.test.ts": "src/core/git-reflog.integration.test.ts", "src/core/git-streaming-parsers.integration.test.ts": "src/core/git-streaming-parsers.integration.test.ts", "src/core/git-timeout.integration.test.ts": "src/core/git-timeout.integration.test.ts", "src/core/git.ts": "src/core/git.ts", @@ -847,6 +849,7 @@ package_view( "src/core/config.ts": "src/core/config.ts", "src/core/config.unit.test.ts": "src/core/config.unit.test.ts", "src/core/git-memory.integration.test.ts": "src/core/git-memory.integration.test.ts", + "src/core/git-reflog.integration.test.ts": "src/core/git-reflog.integration.test.ts", "src/core/git-streaming-parsers.integration.test.ts": "src/core/git-streaming-parsers.integration.test.ts", "src/core/git-timeout.integration.test.ts": "src/core/git-timeout.integration.test.ts", "src/core/git.ts": "src/core/git.ts", @@ -1170,6 +1173,7 @@ package_view( "src/core/config.ts": "src/core/config.ts", "src/core/config.unit.test.ts": "src/core/config.unit.test.ts", "src/core/git-memory.integration.test.ts": "src/core/git-memory.integration.test.ts", + "src/core/git-reflog.integration.test.ts": "src/core/git-reflog.integration.test.ts", "src/core/git-streaming-parsers.integration.test.ts": "src/core/git-streaming-parsers.integration.test.ts", "src/core/git-timeout.integration.test.ts": "src/core/git-timeout.integration.test.ts", "src/core/git.ts": "src/core/git.ts", diff --git a/packages/@overeng/megarepo/src/core/git-reflog.integration.test.ts b/packages/@overeng/megarepo/src/core/git-reflog.integration.test.ts index 2e10a8c8e1..d4d68822aa 100644 --- a/packages/@overeng/megarepo/src/core/git-reflog.integration.test.ts +++ b/packages/@overeng/megarepo/src/core/git-reflog.integration.test.ts @@ -6,6 +6,9 @@ import { expect } from 'vitest' import * as Git from './git.ts' +process.env.GIT_CONFIG_GLOBAL = '/dev/null' +process.env.GIT_CONFIG_SYSTEM = '/dev/null' + const makeFixture = Effect.gen(function* () { const fs = yield* FileSystem.FileSystem const root = yield* fs.makeTempDirectoryScoped() @@ -71,18 +74,20 @@ describe('bare store reflogs', () => { }).pipe(Effect.provide(NodeServices.layer), Effect.scoped), ) - for (const value of ['false', 'always']) { - it.effect(`fetch ${value === 'always' ? 'preserves always' : 'enables disabled reflogs'}`, () => - Effect.gen(function* () { - const { bare } = yield* makeFixture - yield* Git.runCommand({ - cwd: bare, - args: ['config', '--local', 'core.logAllRefUpdates', value], - }) - yield* Git.fetchBare({ repoPath: bare }) - expect(yield* readLogging(bare)).toBe(value === 'always' ? 'always' : 'true') - yield* expectFetchedReflog(bare) - }).pipe(Effect.provide(NodeServices.layer), Effect.scoped), + for (const value of ['false', 'always', 'ALWAYS']) { + it.effect( + `fetch ${value === 'false' ? 'enables disabled reflogs' : `preserves ${value}`}`, + () => + Effect.gen(function* () { + const { bare } = yield* makeFixture + yield* Git.runCommand({ + cwd: bare, + args: ['config', '--local', 'core.logAllRefUpdates', value], + }) + yield* Git.fetchBare({ repoPath: bare }) + expect(yield* readLogging(bare)).toBe(value === 'false' ? 'true' : value) + yield* expectFetchedReflog(bare) + }).pipe(Effect.provide(NodeServices.layer), Effect.scoped), ) } }) diff --git a/packages/@overeng/megarepo/src/core/git.ts b/packages/@overeng/megarepo/src/core/git.ts index 7a2fc79a58..56792a425e 100644 --- a/packages/@overeng/megarepo/src/core/git.ts +++ b/packages/@overeng/megarepo/src/core/git.ts @@ -905,7 +905,8 @@ export const ensureBareRefLogging = Effect.fn('git/ensure-bare-ref-logging')(fun error.exitCode === 1 && error.stderr === '' ? Effect.succeed('') : Effect.fail(error), ), ) - if (value === 'true' || value === 'always') return + const normalized = value.toLowerCase() + if (normalized === 'true' || normalized === 'always') return yield* runGitCommand({ args: ['config', '--local', 'core.logAllRefUpdates', 'true'], cwd: repoPath, diff --git a/packages/@overeng/tui-stories/BUCK b/packages/@overeng/tui-stories/BUCK index f15e028d26..21229aa146 100644 --- a/packages/@overeng/tui-stories/BUCK +++ b/packages/@overeng/tui-stories/BUCK @@ -7,7 +7,7 @@ load("//buck2/products:defs.bzl", "javascript_product") # Projection source: packages/@overeng/tui-stories/BUCK.genie.ts # Projection schema version: 13 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:b93d0006b8d5a54a23a32e8c4de47701ff523f71c088bc9b0e0552f48e8f04c7 +# Semantic fingerprint: sha256:ce22cb54526b18bc11014f2c33324601fcee76b158c2d84c92e5d79f8fbe9bbb # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") @@ -315,6 +315,7 @@ package_view( "node_modules/@overeng/megarepo/src/core/config.ts": "//packages/@overeng/megarepo:src/core/config.ts", "node_modules/@overeng/megarepo/src/core/config.unit.test.ts": "//packages/@overeng/megarepo:src/core/config.unit.test.ts", "node_modules/@overeng/megarepo/src/core/git-memory.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-memory.integration.test.ts", + "node_modules/@overeng/megarepo/src/core/git-reflog.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-reflog.integration.test.ts", "node_modules/@overeng/megarepo/src/core/git-streaming-parsers.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-streaming-parsers.integration.test.ts", "node_modules/@overeng/megarepo/src/core/git-timeout.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-timeout.integration.test.ts", "node_modules/@overeng/megarepo/src/core/git.ts": "//packages/@overeng/megarepo:src/core/git.ts", @@ -716,6 +717,7 @@ package_view( "node_modules/@overeng/megarepo/src/core/config.ts": "//packages/@overeng/megarepo:src/core/config.ts", "node_modules/@overeng/megarepo/src/core/config.unit.test.ts": "//packages/@overeng/megarepo:src/core/config.unit.test.ts", "node_modules/@overeng/megarepo/src/core/git-memory.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-memory.integration.test.ts", + "node_modules/@overeng/megarepo/src/core/git-reflog.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-reflog.integration.test.ts", "node_modules/@overeng/megarepo/src/core/git-streaming-parsers.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-streaming-parsers.integration.test.ts", "node_modules/@overeng/megarepo/src/core/git-timeout.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-timeout.integration.test.ts", "node_modules/@overeng/megarepo/src/core/git.ts": "//packages/@overeng/megarepo:src/core/git.ts", @@ -1117,6 +1119,7 @@ package_view( "node_modules/@overeng/megarepo/src/core/config.ts": "//packages/@overeng/megarepo:src/core/config.ts", "node_modules/@overeng/megarepo/src/core/config.unit.test.ts": "//packages/@overeng/megarepo:src/core/config.unit.test.ts", "node_modules/@overeng/megarepo/src/core/git-memory.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-memory.integration.test.ts", + "node_modules/@overeng/megarepo/src/core/git-reflog.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-reflog.integration.test.ts", "node_modules/@overeng/megarepo/src/core/git-streaming-parsers.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-streaming-parsers.integration.test.ts", "node_modules/@overeng/megarepo/src/core/git-timeout.integration.test.ts": "//packages/@overeng/megarepo:src/core/git-timeout.integration.test.ts", "node_modules/@overeng/megarepo/src/core/git.ts": "//packages/@overeng/megarepo:src/core/git.ts", From 4dafa209daec50e7a2034aad722df2f20e5c5992 Mon Sep 17 00:00:00 2001 From: schickling-assistant <261620128+schickling-assistant@users.noreply.github.com> Date: Tue, 10 Nov 2026 16:40:21 +0100 Subject: [PATCH 3/3] fix(megarepo): run reflog coverage in Git-enabled test lane agent-identity: agent/effect-utils/effect-utils-manager agent-persona: generalist agent-supervisor: unavailable agent-tool: OMP agent-tool-version: 18.12.5 agent-runtime: OMP 18.12.5 agent-model: openai-codex/gpt-6.1-sol --- buck2-test-authority.json | 2 ++ packages/@overeng/megarepo/BUCK | 4 +++- packages/@overeng/megarepo/BUCK.genie.ts | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/buck2-test-authority.json b/buck2-test-authority.json index 65010845d7..8bae2f506a 100644 --- a/buck2-test-authority.json +++ b/buck2-test-authority.json @@ -840,6 +840,7 @@ "src/cli/store.integration.test.ts", "src/cli/sync.integration.test.ts", "src/core/git-memory.integration.test.ts", + "src/core/git-reflog.integration.test.ts", "src/core/git-streaming-parsers.integration.test.ts", "src/core/git-timeout.integration.test.ts", "src/core/nix-lock/mod.integration.test.ts", @@ -1031,6 +1032,7 @@ "src/cli/store.integration.test.ts", "src/cli/sync.integration.test.ts", "src/core/git-memory.integration.test.ts", + "src/core/git-reflog.integration.test.ts", "src/core/git-streaming-parsers.integration.test.ts", "src/core/git-timeout.integration.test.ts", "src/core/nix-lock/mod.integration.test.ts", diff --git a/packages/@overeng/megarepo/BUCK b/packages/@overeng/megarepo/BUCK index b883868299..bdfd6a6638 100644 --- a/packages/@overeng/megarepo/BUCK +++ b/packages/@overeng/megarepo/BUCK @@ -7,7 +7,7 @@ load("//buck2/products:defs.bzl", "javascript_product") # Projection source: packages/@overeng/megarepo/BUCK.genie.ts # Projection schema version: 13 # Projection generator: effect-utils/genie/buck2-typescript-package-projection -# Semantic fingerprint: sha256:2fb65b1597af84bcf5758af087b0b7f7bdc22f0989894249082a76dfc500e193 +# Semantic fingerprint: sha256:95381df02a78d0cec2e092ec731bc6e403601754d9e15c051d16431cb568d5ab # Regenerate: devenv tasks run genie:run load("//buck2:materialization.bzl", "export_materialization_inputs", "package_view") @@ -1389,6 +1389,7 @@ vitest_test( "src/cli/store.integration.test.ts", "src/cli/sync.integration.test.ts", "src/core/git-memory.integration.test.ts", + "src/core/git-reflog.integration.test.ts", "src/core/git-streaming-parsers.integration.test.ts", "src/core/git-timeout.integration.test.ts", "src/core/nix-lock/mod.integration.test.ts", @@ -1437,6 +1438,7 @@ vitest_collect( "src/cli/store.integration.test.ts", "src/cli/sync.integration.test.ts", "src/core/git-memory.integration.test.ts", + "src/core/git-reflog.integration.test.ts", "src/core/git-streaming-parsers.integration.test.ts", "src/core/git-timeout.integration.test.ts", "src/core/nix-lock/mod.integration.test.ts", diff --git a/packages/@overeng/megarepo/BUCK.genie.ts b/packages/@overeng/megarepo/BUCK.genie.ts index 6ebab8acff..a1c711b777 100644 --- a/packages/@overeng/megarepo/BUCK.genie.ts +++ b/packages/@overeng/megarepo/BUCK.genie.ts @@ -76,6 +76,7 @@ export const buck2TypeScriptAdmission = { 'src/cli/store.integration.test.ts', 'src/cli/sync.integration.test.ts', 'src/core/git-memory.integration.test.ts', + 'src/core/git-reflog.integration.test.ts', 'src/core/git-streaming-parsers.integration.test.ts', 'src/core/git-timeout.integration.test.ts', 'src/core/nix-lock/mod.integration.test.ts',