From 37a58e2dbeee2e3db9765f8f78ce82ee549fa3b5 Mon Sep 17 00:00:00 2001 From: Ammar Date: Fri, 7 Nov 2025 16:08:07 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=A4=96=20fix:=20use=20git=20show-bran?= =?UTF-8?q?ch=20for=20clearer=20SSH=20workspace=20force=20delete=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace 'git log --branches --not --remotes' with 'git show-branch' to provide clearer context when attempting to delete SSH workspaces with unpushed commits. The new output shows the relationship between the feature branch and the default branch (main/master), making it immediately clear when commits have been squash-merged. This addresses confusion in squash-merge workflows where commits appear 'unpushed' even after the PR is merged. **Before:** 5d307e9 feat: add feature work 2 5e195dd feat: add feature work 1 **After:** Branch status compared to origin/main: * [feature-branch] feat: add feature work 2 ! [origin/main] feat: add all feature work (squashed) -- * [origin/main] feat: add all feature work (squashed) + [feature-branch] feat: add feature work 2 + [feature-branch^] feat: add feature work 1 +* [origin/main^] Initial commit Note: If your PR was squash-merged, these commits are already in origin/main and safe to delete. The implementation falls back to the original git log command when: - No remote branches exist - Default branch cannot be determined - show-branch fails for any reason This ensures backward compatibility while providing better UX in the common case. _Generated with `cmux`_ --- src/runtime/SSHRuntime.ts | 44 +++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/runtime/SSHRuntime.ts b/src/runtime/SSHRuntime.ts index 37cb22cf2..27458696e 100644 --- a/src/runtime/SSHRuntime.ts +++ b/src/runtime/SSHRuntime.ts @@ -985,10 +985,46 @@ export class SSHRuntime implements Runtime { cd ${shescape.quote(deletedPath)} || exit 1 git diff --quiet --exit-code && git diff --quiet --cached --exit-code || exit 1 if git remote | grep -q .; then - unpushed=$(git log --branches --not --remotes --oneline) - if [ -n "$unpushed" ]; then - echo "$unpushed" | head -10 >&2 - exit 2 + # Get current branch + BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) + + # Get default branch (try origin/HEAD, fallback to main, then master) + DEFAULT=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@') + if [ -z "$DEFAULT" ]; then + if git rev-parse --verify origin/main >/dev/null 2>&1; then + DEFAULT="main" + elif git rev-parse --verify origin/master >/dev/null 2>&1; then + DEFAULT="master" + fi + fi + + # If we have both branch and default, use show-branch for better output + if [ -n "$BRANCH" ] && [ -n "$DEFAULT" ]; then + if git show-branch "$BRANCH" "origin/$DEFAULT" >/dev/null 2>&1; then + # Check if there are commits not in the default branch + if ! git merge-base --is-ancestor "$BRANCH" "origin/$DEFAULT" 2>/dev/null; then + echo "Branch status compared to origin/$DEFAULT:" >&2 + echo "" >&2 + git show-branch "$BRANCH" "origin/$DEFAULT" 2>&1 | head -20 >&2 + echo "" >&2 + echo "Note: If your PR was squash-merged, these commits are already in origin/$DEFAULT and safe to delete." >&2 + exit 2 + fi + else + # Fallback to git log if show-branch fails + unpushed=$(git log --branches --not --remotes --oneline) + if [ -n "$unpushed" ]; then + echo "$unpushed" | head -10 >&2 + exit 2 + fi + fi + else + # Fallback to git log if we can't determine branches + unpushed=$(git log --branches --not --remotes --oneline) + if [ -n "$unpushed" ]; then + echo "$unpushed" | head -10 >&2 + exit 2 + fi fi fi exit 0 From 57b340139dd5c8cfe09d2ed06ca250af89ea785c Mon Sep 17 00:00:00 2001 From: Ammar Date: Fri, 7 Nov 2025 16:12:11 +0000 Subject: [PATCH 2/2] fix: only show show-branch when commits are truly unpushed The previous implementation blocked deletion whenever the branch wasn't an ancestor of the default branch, even if all commits were pushed to origin/feature-branch. This forced users to use --force unnecessarily. Now we: 1. First check git log --branches --not --remotes (original behavior) 2. Only if that finds unpushed commits, show the enhanced error This maintains the original safety check (only block truly unpushed commits) while providing better error messaging when it matters. --- src/runtime/SSHRuntime.ts | 60 ++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 36 deletions(-) diff --git a/src/runtime/SSHRuntime.ts b/src/runtime/SSHRuntime.ts index 27458696e..af94e0ace 100644 --- a/src/runtime/SSHRuntime.ts +++ b/src/runtime/SSHRuntime.ts @@ -985,46 +985,34 @@ export class SSHRuntime implements Runtime { cd ${shescape.quote(deletedPath)} || exit 1 git diff --quiet --exit-code && git diff --quiet --cached --exit-code || exit 1 if git remote | grep -q .; then - # Get current branch - BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) - - # Get default branch (try origin/HEAD, fallback to main, then master) - DEFAULT=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@') - if [ -z "$DEFAULT" ]; then - if git rev-parse --verify origin/main >/dev/null 2>&1; then - DEFAULT="main" - elif git rev-parse --verify origin/master >/dev/null 2>&1; then - DEFAULT="master" - fi - fi - - # If we have both branch and default, use show-branch for better output - if [ -n "$BRANCH" ] && [ -n "$DEFAULT" ]; then - if git show-branch "$BRANCH" "origin/$DEFAULT" >/dev/null 2>&1; then - # Check if there are commits not in the default branch - if ! git merge-base --is-ancestor "$BRANCH" "origin/$DEFAULT" 2>/dev/null; then - echo "Branch status compared to origin/$DEFAULT:" >&2 - echo "" >&2 - git show-branch "$BRANCH" "origin/$DEFAULT" 2>&1 | head -20 >&2 - echo "" >&2 - echo "Note: If your PR was squash-merged, these commits are already in origin/$DEFAULT and safe to delete." >&2 - exit 2 - fi - else - # Fallback to git log if show-branch fails - unpushed=$(git log --branches --not --remotes --oneline) - if [ -n "$unpushed" ]; then - echo "$unpushed" | head -10 >&2 - exit 2 + # First, check the original condition: any commits not in any remote + unpushed=$(git log --branches --not --remotes --oneline) + if [ -n "$unpushed" ]; then + # Get current branch for better error messaging + BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null) + + # Get default branch (try origin/HEAD, fallback to main, then master) + DEFAULT=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@') + if [ -z "$DEFAULT" ]; then + if git rev-parse --verify origin/main >/dev/null 2>&1; then + DEFAULT="main" + elif git rev-parse --verify origin/master >/dev/null 2>&1; then + DEFAULT="master" fi fi - else - # Fallback to git log if we can't determine branches - unpushed=$(git log --branches --not --remotes --oneline) - if [ -n "$unpushed" ]; then + + # If we have both branch and default, use show-branch for better output + if [ -n "$BRANCH" ] && [ -n "$DEFAULT" ] && git show-branch "$BRANCH" "origin/$DEFAULT" >/dev/null 2>&1; then + echo "Branch status compared to origin/$DEFAULT:" >&2 + echo "" >&2 + git show-branch "$BRANCH" "origin/$DEFAULT" 2>&1 | head -20 >&2 + echo "" >&2 + echo "Note: If your PR was squash-merged, these commits are already in origin/$DEFAULT and safe to delete." >&2 + else + # Fallback to just showing the commit list echo "$unpushed" | head -10 >&2 - exit 2 fi + exit 2 fi fi exit 0