authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-03-01 11:36:41-08:00
committergravatar for jmarminge@gmail.comJulius Marminge <jmarminge@gmail.com> 2026-03-01 20:06:01-08:00
log96efd1cef04489233e00f602bad42d5dd7625ecc
treedc859f17c1eada59352018836b008a64e22e30bf
parentc8974ede6dc26b931c89d7415b9cbdd534aa8de4

fix: avoid no-upstream push skip when base cannot be resolved

Co-authored-by: codex <codex@users.noreply.github.com>

2 files changed, 44 insertions(+), 6 deletions(-)

apps/server/src/git/Layers/GitCore.test.ts+25
......@@ -1177,6 +1177,31 @@ it.layer(TestLayer)("git integration", (it) => {
11771177 }),
11781178 );
11791179
1180 it.effect("pushes with upstream setup when no comparable base branch exists", () =>
1181 Effect.gen(function* () {
1182 const tmp = yield* makeTmpDir();
1183 const remote = yield* makeTmpDir();
1184 yield* git(tmp, ["init", "--initial-branch=trunk"]);
1185 yield* git(tmp, ["config", "user.email", "test@test.com"]);
1186 yield* git(tmp, ["config", "user.name", "Test"]);
1187 yield* writeTextFile(path.join(tmp, "README.md"), "hello\n");
1188 yield* git(tmp, ["add", "README.md"]);
1189 yield* git(tmp, ["commit", "-m", "initial"]);
1190 yield* git(remote, ["init", "--bare"]);
1191 yield* git(tmp, ["remote", "add", "origin", remote]);
1192 yield* git(tmp, ["checkout", "-b", "feature/no-base"]);
1193
1194 const core = yield* GitCore;
1195 const pushed = yield* core.pushCurrentBranch(tmp, null);
1196 expect(pushed.status).toBe("pushed");
1197 expect(pushed.setUpstream).toBe(true);
1198 expect(pushed.upstreamBranch).toBe("origin/feature/no-base");
1199 expect(yield* git(tmp, ["rev-parse", "--abbrev-ref", "@{upstream}"])).toBe(
1200 "origin/feature/no-base",
1201 );
1202 }),
1203 );
1204
11801205 it.effect("includes command context when worktree removal fails", () =>
11811206 Effect.gen(function* () {
11821207 const tmp = yield* makeTmpDir();
apps/server/src/git/Layers/GitCore.ts+19-6
......@@ -630,12 +630,25 @@ const makeGitCore = Effect.gen(function* () {
630630 );
631631 }
632632
633 if (details.aheadCount === 0 && details.behindCount === 0) {
634 return {
635 status: "skipped_up_to_date" as const,
636 branch,
637 ...(details.upstreamRef ? { upstreamBranch: details.upstreamRef } : {}),
638 };
633 const hasNoLocalDelta = details.aheadCount === 0 && details.behindCount === 0;
634 if (hasNoLocalDelta) {
635 if (details.hasUpstream) {
636 return {
637 status: "skipped_up_to_date" as const,
638 branch,
639 ...(details.upstreamRef ? { upstreamBranch: details.upstreamRef } : {}),
640 };
641 }
642
643 const comparableBaseBranch = yield* resolveBaseBranchForNoUpstream(cwd, branch).pipe(
644 Effect.catch(() => Effect.succeed(null)),
645 );
646 if (comparableBaseBranch) {
647 return {
648 status: "skipped_up_to_date" as const,
649 branch,
650 };
651 }
639652 }
640653
641654 if (!details.hasUpstream) {