93 lines
3.2 KiB
Python
93 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Remove a git worktree and optionally delete the associated branch.
|
|
|
|
Usage:
|
|
python tools/remove_worktree.py feature-branch
|
|
python tools/remove_worktree.py feature-branch --force
|
|
"""
|
|
|
|
import argparse
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def run_git_command(cmd: list[str]) -> tuple[int, str, str]:
|
|
"""Run a git command and return exit code, stdout, stderr."""
|
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
return result.returncode, result.stdout.strip(), result.stderr.strip()
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Remove a git worktree and optionally delete its branch")
|
|
parser.add_argument("branch", help="Name of the branch/worktree to remove")
|
|
parser.add_argument("--force", action="store_true", help="Force removal even with uncommitted changes")
|
|
args = parser.parse_args()
|
|
|
|
# Get the base repository name
|
|
current_dir = Path.cwd()
|
|
repo_name = current_dir.name
|
|
|
|
# Construct worktree path (same pattern as create_worktree.py)
|
|
worktree_path = current_dir.parent / f"{repo_name}-{args.branch}"
|
|
|
|
print(f"Looking for worktree at: {worktree_path}")
|
|
|
|
# Check if worktree exists
|
|
returncode, stdout, _ = run_git_command(["git", "worktree", "list"])
|
|
if returncode != 0:
|
|
print("Error: Failed to list worktrees")
|
|
sys.exit(1)
|
|
|
|
worktree_exists = str(worktree_path) in stdout
|
|
if not worktree_exists:
|
|
print(f"Error: Worktree for branch '{args.branch}' not found at {worktree_path}")
|
|
sys.exit(1)
|
|
|
|
# Remove the worktree
|
|
remove_cmd = ["git", "worktree", "remove", str(worktree_path)]
|
|
if args.force:
|
|
remove_cmd.append("--force")
|
|
|
|
print(f"Removing worktree at {worktree_path}...")
|
|
returncode, stdout, stderr = run_git_command(remove_cmd)
|
|
|
|
if returncode != 0:
|
|
if "contains modified or untracked files" in stderr:
|
|
print("Error: Worktree contains uncommitted changes. Use --force to override.")
|
|
else:
|
|
print(f"Error removing worktree: {stderr}")
|
|
sys.exit(1)
|
|
|
|
print(f"Successfully removed worktree at {worktree_path}")
|
|
|
|
# Try to delete the branch
|
|
print(f"Attempting to delete branch '{args.branch}'...")
|
|
|
|
# Check current branch
|
|
returncode, current_branch, _ = run_git_command(["git", "branch", "--show-current"])
|
|
if returncode == 0 and current_branch == args.branch:
|
|
print(f"Cannot delete branch '{args.branch}' - it is currently checked out")
|
|
return
|
|
|
|
# Try to delete the branch
|
|
returncode, stdout, stderr = run_git_command(["git", "branch", "-d", args.branch])
|
|
|
|
if returncode == 0:
|
|
print(f"Successfully deleted branch '{args.branch}'")
|
|
elif "not fully merged" in stderr:
|
|
# Try force delete if regular delete fails due to unmerged changes
|
|
print("Branch has unmerged changes, force deleting...")
|
|
returncode, stdout, stderr = run_git_command(["git", "branch", "-D", args.branch])
|
|
if returncode == 0:
|
|
print(f"Successfully force-deleted branch '{args.branch}'")
|
|
else:
|
|
print(f"Warning: Could not delete branch: {stderr}")
|
|
else:
|
|
print(f"Warning: Could not delete branch: {stderr}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|