Add default-branch safeguard with auto feature-branch fallback#131
Add default-branch safeguard with auto feature-branch fallback#131juliusmarminge merged 15 commits intomainfrom
Conversation
- Prompt before commit/push actions on the default branch - Allow one-click create+checkout of an auto-named feature branch and continue - Add logic/tests for date-based unique auto feature branch naming
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
- Treat no-upstream branches as publishable: enable Push/Create PR and update quick actions - Route Create PR menu action through commit+push+PR flow when appropriate - Simplify Git action dialog to commit-only and add "Commit on new branch" option
- test push-only quick action on default branch without upstream - verify push and create PR stay disabled when branch is behind
- Change quick action to `Push` (not `Push & create PR`) when branch has no upstream and is not ahead - Keep `Create PR` menu item disabled until the branch has commits ahead - Add/adjust logic tests for both no-ahead and ahead scenarios
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Autofix Details
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: PR disabled reason inconsistent with updated canCreatePr logic
- Removed the stale
!gitStatus.hasUpstreamcheck fromgetMenuActionDisabledReasonso that when a branch has no upstream and no commits ahead, the correct message "No local commits to include in a PR" is shown instead of the misleading upstream message.
- Removed the stale
- ✅ Fixed: Duplicated branch-checkout-and-continue logic across callbacks
- Extracted the shared checkout-toast-chain pattern into a
checkoutNewBranchAndRunActionhelper callback, reducing bothcheckoutFeatureBranchAndContinuePendingActionandrunDialogActionOnNewBranchto thin wrappers that delegate to it.
- Extracted the shared checkout-toast-chain pattern into a
Or push these changes by commenting:
@cursor push 175f39a882
Preview (175f39a882)
diff --git a/apps/web/src/components/GitActionsControl.tsx b/apps/web/src/components/GitActionsControl.tsx
--- a/apps/web/src/components/GitActionsControl.tsx
+++ b/apps/web/src/components/GitActionsControl.tsx
@@ -105,9 +105,6 @@
if (hasChanges) {
return "Commit local changes before creating a PR.";
}
- if (!gitStatus.hasUpstream) {
- return "Set an upstream branch before creating a PR.";
- }
if (!isAhead) {
return "No local commits to include in a PR.";
}
@@ -314,7 +311,8 @@
stopProgressUpdates();
const resultToast = summarizeGitResult(result);
- const existingOpenPrUrl = actionStatus?.pr?.state === "open" ? actionStatus.pr.url : undefined;
+ const existingOpenPrUrl =
+ actionStatus?.pr?.state === "open" ? actionStatus.pr.url : undefined;
const prUrl = result.pr.url ?? existingOpenPrUrl;
const shouldOfferPushCta = action === "commit" && result.commit.status === "created";
const shouldOfferOpenPrCta =
@@ -406,96 +404,72 @@
});
}, [pendingDefaultBranchAction, runGitActionWithToast]);
+ const checkoutNewBranchAndRunAction = useCallback(
+ (actionParams: {
+ action: GitStackedAction;
+ commitMessage?: string;
+ forcePushOnlyProgress?: boolean;
+ onConfirmed?: () => void;
+ }) => {
+ const branchName = resolveAutoFeatureBranchName(
+ branchList?.branches.map((branch) => branch.name) ?? [],
+ );
+
+ const checkoutPromise = createBranchAndCheckoutMutation.mutateAsync(branchName);
+ toastManager.promise(checkoutPromise, {
+ loading: { title: `Creating ${branchName}...`, data: threadToastData },
+ success: () => ({
+ title: `Checked out ${branchName}`,
+ data: threadToastData,
+ }),
+ error: (error) => ({
+ title: "Failed to checkout feature branch",
+ description: error instanceof Error ? error.message : "An error occurred.",
+ data: threadToastData,
+ }),
+ });
+
+ void checkoutPromise
+ .then(() => {
+ const statusOverride = gitStatusForActions
+ ? { ...gitStatusForActions, branch: branchName, pr: null }
+ : null;
+ return runGitActionWithToast({
+ ...actionParams,
+ skipDefaultBranchPrompt: true,
+ statusOverride,
+ isDefaultBranchOverride: false,
+ });
+ })
+ .catch(() => undefined);
+ },
+ [
+ branchList?.branches,
+ createBranchAndCheckoutMutation,
+ gitStatusForActions,
+ runGitActionWithToast,
+ threadToastData,
+ ],
+ );
+
const checkoutFeatureBranchAndContinuePendingAction = useCallback(() => {
if (!pendingDefaultBranchAction) return;
const pendingAction = pendingDefaultBranchAction;
- const branchName = resolveAutoFeatureBranchName(branchList?.branches.map((branch) => branch.name) ?? []);
setPendingDefaultBranchAction(null);
+ checkoutNewBranchAndRunAction(pendingAction);
+ }, [pendingDefaultBranchAction, checkoutNewBranchAndRunAction]);
- const checkoutPromise = createBranchAndCheckoutMutation.mutateAsync(branchName);
- toastManager.promise(checkoutPromise, {
- loading: { title: `Creating ${branchName}...`, data: threadToastData },
- success: () => ({
- title: `Checked out ${branchName}`,
- data: threadToastData,
- }),
- error: (error) => ({
- title: "Failed to checkout feature branch",
- description: error instanceof Error ? error.message : "An error occurred.",
- data: threadToastData,
- }),
- });
-
- void checkoutPromise
- .then(() => {
- const statusOverride = gitStatusForActions
- ? { ...gitStatusForActions, branch: branchName, pr: null }
- : null;
- return runGitActionWithToast({
- ...pendingAction,
- skipDefaultBranchPrompt: true,
- statusOverride,
- isDefaultBranchOverride: false,
- });
- })
- .catch(() => undefined);
- }, [
- branchList?.branches,
- createBranchAndCheckoutMutation,
- gitStatusForActions,
- pendingDefaultBranchAction,
- runGitActionWithToast,
- threadToastData,
- ]);
-
const runDialogActionOnNewBranch = useCallback(() => {
if (!isCommitDialogOpen) return;
- const action: GitStackedAction = "commit";
const commitMessage = dialogCommitMessage.trim();
- const branchName = resolveAutoFeatureBranchName(branchList?.branches.map((branch) => branch.name) ?? []);
-
setIsCommitDialogOpen(false);
setDialogCommitMessage("");
-
- const checkoutPromise = createBranchAndCheckoutMutation.mutateAsync(branchName);
- toastManager.promise(checkoutPromise, {
- loading: { title: `Creating ${branchName}...`, data: threadToastData },
- success: () => ({
- title: `Checked out ${branchName}`,
- data: threadToastData,
- }),
- error: (error) => ({
- title: "Failed to checkout feature branch",
- description: error instanceof Error ? error.message : "An error occurred.",
- data: threadToastData,
- }),
+ checkoutNewBranchAndRunAction({
+ action: "commit",
+ ...(commitMessage ? { commitMessage } : {}),
});
+ }, [isCommitDialogOpen, dialogCommitMessage, checkoutNewBranchAndRunAction]);
- void checkoutPromise
- .then(() => {
- const statusOverride = gitStatusForActions
- ? { ...gitStatusForActions, branch: branchName, pr: null }
- : null;
- return runGitActionWithToast({
- action,
- ...(commitMessage ? { commitMessage } : {}),
- skipDefaultBranchPrompt: true,
- statusOverride,
- isDefaultBranchOverride: false,
- });
- })
- .catch(() => undefined);
- }, [
- branchList?.branches,
- createBranchAndCheckoutMutation,
- dialogCommitMessage,
- gitStatusForActions,
- isCommitDialogOpen,
- runGitActionWithToast,
- setIsCommitDialogOpen,
- threadToastData,
- ]);
-
const runQuickAction = useCallback(() => {
if (quickAction.kind === "open_pr") {
void openExistingPr();
@@ -738,7 +712,9 @@
<div className="grid grid-cols-[auto_1fr] items-center gap-x-2 gap-y-1">
<span className="text-muted-foreground">Branch</span>
<span className="flex items-center justify-between gap-2">
- <span className="font-medium">{gitStatusForActions?.branch ?? "(detached HEAD)"}</span>
+ <span className="font-medium">
+ {gitStatusForActions?.branch ?? "(detached HEAD)"}
+ </span>
{isDefaultBranch && (
<span className="text-right text-warning text-xs">Warning: default branch</span>
)}- Compute ahead count from base branch when upstream is missing - Skip push/PR actions when no local commits are ahead - Update server and UI tests for no-upstream push/PR behavior
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Stale closure in toast CTA after feature-branch checkout
- Added a useRef that always points to the latest runGitActionWithToast, and updated the toast CTA onClick handlers (Push and Create PR) to call via the ref instead of the stale closure, ensuring they always use current isDefaultBranch and gitStatusForActions values.
Or push these changes by commenting:
@cursor push c2a5cab307
Preview (c2a5cab307)
diff --git a/apps/web/src/components/GitActionsControl.tsx b/apps/web/src/components/GitActionsControl.tsx
--- a/apps/web/src/components/GitActionsControl.tsx
+++ b/apps/web/src/components/GitActionsControl.tsx
@@ -1,6 +1,6 @@
import { type GitStatusResult, type GitStackedAction, type ThreadId } from "@t3tools/contracts";
import { useIsMutating, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
-import { useCallback, useEffect, useMemo, useState } from "react";
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { ChevronDownIcon, CloudUploadIcon, GitCommitIcon, InfoIcon } from "lucide-react";
import { GitHubIcon } from "./Icons";
import {
@@ -308,7 +308,8 @@
stopProgressUpdates();
const resultToast = summarizeGitResult(result);
- const existingOpenPrUrl = actionStatus?.pr?.state === "open" ? actionStatus.pr.url : undefined;
+ const existingOpenPrUrl =
+ actionStatus?.pr?.state === "open" ? actionStatus.pr.url : undefined;
const prUrl = result.pr.url ?? existingOpenPrUrl;
const shouldOfferPushCta = action === "commit" && result.commit.status === "created";
const shouldOfferOpenPrCta =
@@ -338,7 +339,7 @@
actionProps: {
children: "Push",
onClick: () => {
- void runGitActionWithToast({
+ void runGitActionWithToastRef.current({
action: "commit_push",
forcePushOnlyProgress: true,
onConfirmed: closeResultToast,
@@ -364,7 +365,7 @@
children: "Create PR",
onClick: () => {
closeResultToast();
- void runGitActionWithToast({ action: "commit_push_pr" });
+ void runGitActionWithToastRef.current({ action: "commit_push_pr" });
},
},
}
@@ -390,6 +391,9 @@
],
);
+ const runGitActionWithToastRef = useRef(runGitActionWithToast);
+ runGitActionWithToastRef.current = runGitActionWithToast;
+
const continuePendingDefaultBranchAction = useCallback(() => {
if (!pendingDefaultBranchAction) return;
const pendingAction = pendingDefaultBranchAction;
@@ -710,7 +714,9 @@
<div className="grid grid-cols-[auto_1fr] items-center gap-x-2 gap-y-1">
<span className="text-muted-foreground">Branch</span>
<span className="flex items-center justify-between gap-2">
- <span className="font-medium">{gitStatusForActions?.branch ?? "(detached HEAD)"}</span>
+ <span className="font-medium">
+ {gitStatusForActions?.branch ?? "(detached HEAD)"}
+ </span>
{isDefaultBranch && (
<span className="text-right text-warning text-xs">Warning: default branch</span>
)}Co-authored-by: codex <codex@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Base branch lookup ignores remote-tracking refs
- Added a fallback check for refs/remotes/origin/ in resolveBaseBranchForNoUpstream so that when a base branch exists only as a remote-tracking ref, it returns origin/ instead of null.
Or push these changes by commenting:
@cursor push 09e1d6f726
Preview (09e1d6f726)
diff --git a/apps/server/src/git/Layers/GitCore.ts b/apps/server/src/git/Layers/GitCore.ts
--- a/apps/server/src/git/Layers/GitCore.ts
+++ b/apps/server/src/git/Layers/GitCore.ts
@@ -314,6 +314,16 @@
if (yield* branchExists(cwd, candidate)) {
return candidate;
}
+
+ const remoteResult = yield* executeGit(
+ "GitCore.resolveBaseBranchForNoUpstream.remoteRefCheck",
+ cwd,
+ ["show-ref", "--verify", "--quiet", `refs/remotes/origin/${candidate}`],
+ { allowNonZeroExit: true },
+ );
+ if (remoteResult.code === 0) {
+ return `origin/${candidate}`;
+ }
}
return null;Co-authored-by: codex <codex@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Commit message not cleared after dialog submission
- Added the missing
setDialogCommitMessage("")call inrunDialogActionto match the reset behavior of all other dialog close paths.
- Added the missing
Or push these changes by commenting:
@cursor push 671782ab19
Preview (671782ab19)
diff --git a/apps/web/src/components/GitActionsControl.tsx b/apps/web/src/components/GitActionsControl.tsx
--- a/apps/web/src/components/GitActionsControl.tsx
+++ b/apps/web/src/components/GitActionsControl.tsx
@@ -538,6 +538,7 @@
if (!isCommitDialogOpen) return;
const commitMessage = dialogCommitMessage.trim();
setIsCommitDialogOpen(false);
+ setDialogCommitMessage("");
void runGitActionWithToast({
action: "commit",
...(commitMessage ? { commitMessage } : {}),Co-authored-by: codex <codex@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Dialog describes "commit" for push-only actions on default branch
- Replaced the static DEFAULT_BRANCH_ACTION_DESCRIPTION record with a resolveDefaultBranchDialogWording function that adapts the dialog title, description, and confirm button label based on whether there are actual working tree changes, so push-only scenarios show "Push to default branch?" instead of commit-centric language.
Or push these changes by commenting:
@cursor push 9bcf132a10
Preview (9bcf132a10)
diff --git a/apps/web/src/components/GitActionsControl.tsx b/apps/web/src/components/GitActionsControl.tsx
--- a/apps/web/src/components/GitActionsControl.tsx
+++ b/apps/web/src/components/GitActionsControl.tsx
@@ -115,11 +115,28 @@
const COMMIT_DIALOG_DESCRIPTION =
"Review and confirm your commit. Leave the message blank to auto-generate one.";
-const DEFAULT_BRANCH_ACTION_DESCRIPTION: Record<GitStackedAction, string> = {
- commit: "commit changes",
- commit_push: "commit and push changes",
- commit_push_pr: "commit, push, and create a PR",
-};
+function resolveDefaultBranchDialogWording(
+ action: GitStackedAction,
+ hasWorkingTreeChanges: boolean,
+): { title: string; description: string; confirmLabel: string } {
+ if (hasWorkingTreeChanges) {
+ return {
+ title: "Commit to default branch?",
+ description:
+ action === "commit_push_pr"
+ ? "commit, push, and create a PR"
+ : action === "commit_push"
+ ? "commit and push changes"
+ : "commit changes",
+ confirmLabel: "Commit to",
+ };
+ }
+ return {
+ title: "Push to default branch?",
+ description: action === "commit_push_pr" ? "push and create a PR" : "push changes",
+ confirmLabel: "Push to",
+ };
+}
function GitActionItemIcon({ icon }: { icon: GitActionIconName }) {
if (icon === "commit") return <GitCommitIcon />;
@@ -203,6 +220,17 @@
? (quickAction.hint ?? "This action is currently unavailable.")
: null;
+ const defaultBranchDialogWording = useMemo(
+ () =>
+ pendingDefaultBranchAction
+ ? resolveDefaultBranchDialogWording(
+ pendingDefaultBranchAction.action,
+ !!gitStatusForActions?.hasWorkingTreeChanges,
+ )
+ : null,
+ [pendingDefaultBranchAction, gitStatusForActions?.hasWorkingTreeChanges],
+ );
+
const openExistingPr = useCallback(async () => {
const api = readNativeApi();
if (!api) {
@@ -308,7 +336,8 @@
stopProgressUpdates();
const resultToast = summarizeGitResult(result);
- const existingOpenPrUrl = actionStatus?.pr?.state === "open" ? actionStatus.pr.url : undefined;
+ const existingOpenPrUrl =
+ actionStatus?.pr?.state === "open" ? actionStatus.pr.url : undefined;
const prUrl = result.pr.url ?? existingOpenPrUrl;
const shouldOfferPushCta = action === "commit" && result.commit.status === "created";
const shouldOfferOpenPrCta =
@@ -716,7 +745,9 @@
<div className="grid grid-cols-[auto_1fr] items-center gap-x-2 gap-y-1">
<span className="text-muted-foreground">Branch</span>
<span className="flex items-center justify-between gap-2">
- <span className="font-medium">{gitStatusForActions?.branch ?? "(detached HEAD)"}</span>
+ <span className="font-medium">
+ {gitStatusForActions?.branch ?? "(detached HEAD)"}
+ </span>
{isDefaultBranch && (
<span className="text-right text-warning text-xs">Warning: default branch</span>
)}
@@ -801,14 +832,13 @@
>
<DialogPopup>
<DialogHeader>
- <DialogTitle>Commit to default branch?</DialogTitle>
+ <DialogTitle>
+ {defaultBranchDialogWording?.title ?? "Push to default branch?"}
+ </DialogTitle>
<DialogDescription>
- This action will{" "}
- {pendingDefaultBranchAction
- ? DEFAULT_BRANCH_ACTION_DESCRIPTION[pendingDefaultBranchAction.action]
- : "push changes"}{" "}
- on "{gitStatusForActions?.branch ?? "default"}". You can continue on this branch or
- create a feature branch and run the same action there.
+ This action will {defaultBranchDialogWording?.description ?? "push changes"} on "
+ {gitStatusForActions?.branch ?? "default"}". You can continue on this branch or create
+ a feature branch and run the same action there.
</DialogDescription>
</DialogHeader>
<DialogFooter>
@@ -816,7 +846,8 @@
Abort
</Button>
<Button variant="outline" size="sm" onClick={continuePendingDefaultBranchAction}>
- Commit to {gitStatusForActions?.branch ?? "default"}
+ {defaultBranchDialogWording?.confirmLabel ?? "Push to"}{" "}
+ {gitStatusForActions?.branch ?? "default"}
</Button>
<Button size="sm" onClick={checkoutFeatureBranchAndContinuePendingAction}>
Checkout feature branch & continueCo-authored-by: codex <codex@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Status override omits
hasUpstreamreset after branch checkout- Added
hasUpstream: false,aheadCount: 0, andbehindCount: 0to the statusOverride so a newly created branch correctly reflects that it has no upstream tracking.
- Added
Or push these changes by commenting:
@cursor push 96ecc90a4b
Preview (96ecc90a4b)
diff --git a/apps/web/src/components/GitActionsControl.tsx b/apps/web/src/components/GitActionsControl.tsx
--- a/apps/web/src/components/GitActionsControl.tsx
+++ b/apps/web/src/components/GitActionsControl.tsx
@@ -445,7 +445,14 @@
void checkoutPromise
.then(() => {
const statusOverride = gitStatusForActions
- ? { ...gitStatusForActions, branch: branchName, pr: null }
+ ? {
+ ...gitStatusForActions,
+ branch: branchName,
+ pr: null,
+ hasUpstream: false,
+ aheadCount: 0,
+ behindCount: 0,
+ }
: null;
return runGitActionWithToast({
...actionParams,…er branch checkout Co-authored-by: Julius Marminge <juliusmarminge@users.noreply.github.com> Applied via @cursor push command
Co-authored-by: codex <codex@users.noreply.github.com>
Co-authored-by: codex <codex@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Feature-branch fallback silently skips push for no-change scenarios
- Added a
remoteBranchExistscheck so thecomparableBaseBranchguard only returnsskipped_up_to_datewhen the branch already exists on the remote, ensuring newly created feature branches are always pushed.
- Added a
- ✅ Fixed: Unreachable
commitcase in dialog copy function- Removed the dead
input.action === "commit"branch fromresolveDefaultBranchActionDialogCopysincerequiresDefaultBranchConfirmationonly returns true forcommit_pushandcommit_push_pr.
- Removed the dead
Or push these changes by commenting:
@cursor push 9c881ee5f3
Preview (9c881ee5f3)
diff --git a/apps/server/src/git/Layers/GitCore.ts b/apps/server/src/git/Layers/GitCore.ts
--- a/apps/server/src/git/Layers/GitCore.ts
+++ b/apps/server/src/git/Layers/GitCore.ts
@@ -581,7 +581,10 @@
const comparableBaseBranch = yield* resolveBaseBranchForNoUpstream(cwd, branch).pipe(
Effect.catch(() => Effect.succeed(null)),
);
- if (comparableBaseBranch) {
+ const branchExistsOnRemote = yield* remoteBranchExists(cwd, branch).pipe(
+ Effect.catch(() => Effect.succeed(false)),
+ );
+ if (comparableBaseBranch && branchExistsOnRemote) {
return {
status: "skipped_up_to_date" as const,
branch,
diff --git a/apps/web/src/components/GitActionsControl.logic.ts b/apps/web/src/components/GitActionsControl.logic.ts
--- a/apps/web/src/components/GitActionsControl.logic.ts
+++ b/apps/web/src/components/GitActionsControl.logic.ts
@@ -290,14 +290,6 @@
const branchLabel = input.branchName;
const suffix = ` on "${branchLabel}". You can continue on this branch or create a feature branch and run the same action there.`;
- if (input.action === "commit") {
- return {
- title: "Commit to default branch?",
- description: `This action will commit changes${suffix}`,
- continueLabel: `Commit to ${branchLabel}`,
- };
- }
-
if (input.action === "commit_push") {
if (input.includesCommit) {
return {Co-authored-by: codex <codex@users.noreply.github.com>

Summary
feature/stacked-YYYYMMDDwith numeric suffixes on conflicts).resolveAutoFeatureBranchNamelogic for deterministic branch naming and collision handling.Testing
resolveAutoFeatureBranchNameinapps/web/src/components/GitActionsControl.logic.test.ts(base-name and suffix-collision scenarios).Note
Medium Risk
Changes core git status/push logic and UI action flows around upstreamless branches and default-branch operations, which could alter when pushes are skipped or upstreams are auto-set. Risk is moderated by added integration/unit tests but still impacts common git workflows.
Overview
Improves upstream-less branch handling by computing
aheadCountagainst a resolved base branch (configuredbranch.<name>.gh-merge-base,origin/HEAD, ormain/master) when no upstream is set, and using that to drivestatusDetailsandpushCurrentBranchdecisions.Updates push behavior to skip when there’s no local delta and the remote branch already exists, and to auto-push with
-u origin <branch>when no upstream exists but the branch needs publishing; adds server tests covering these edge cases and a manager test for creating a PR from a no-upstream branch.Adjusts the web git actions UI to allow push/PR actions without an upstream, adds a default-branch confirmation dialog with improved copy plus an option to auto-create/checkout a dated feature branch (
feature/stacked-YYYYMMDD[-N]) and continue the action; includes new unit tests for the naming and dialog-copy logic.Written by Cursor Bugbot for commit 839feaf. This will update automatically on new commits. Configure here.
Note
Add a default-branch safeguard and auto feature-branch fallback by updating
GitCore.pushCurrentBranchandGitActionsControlto compute ahead counts without upstream and gate push/PR flows onmain/masterIntroduce base-branch resolution and ahead-count computation for no-upstream branches in
apps/server/src/git/Layers/GitCore.ts, adjust push behavior to skip or set upstream based on remote presence, and add UI flows to confirm actions on the default branch with auto feature-branch naming inapps/web/src/components/GitActionsControl.tsx.📍Where to Start
Start with
GitCore.readStatusDetailsandGitCore.pushCurrentBranchin GitCore.ts, then review the default-branch confirmation flow in GitActionsControl.tsx.Macroscope summarized 839feaf.