Skip to content

Commit 56459a3

Browse files
committed
Add setup-sandbox-with-worktrees script for manual testing + warn on different final WD
1 parent cbbf193 commit 56459a3

File tree

4 files changed

+133
-8
lines changed

4 files changed

+133
-8
lines changed

docs/man/git-machete.1

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
2727
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
2828
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
2929
..
30-
.TH "GIT-MACHETE" "1" "Oct 09, 2025" "" "git-machete"
30+
.TH "GIT-MACHETE" "1" "Nov 11, 2025" "" "git-machete"
3131
.SH NAME
32-
git-machete \- git-machete 3.37.0
32+
git-machete \- git-machete 3.37.1
3333
.sp
3434
git machete is a robust tool that \fBsimplifies your git workflows\fP\&.
3535
.sp

git_machete/client/traverse.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from git_machete.git_operations import (GitContext, LocalBranchShortName,
1313
SyncToRemoteStatus)
1414
from git_machete.utils import (bold, flat_map, fmt, get_pretty_choices,
15-
get_right_arrow)
15+
get_right_arrow, warn)
1616

1717

1818
class TraverseReturnTo(ParsableEnum):
@@ -94,8 +94,7 @@ def _switch_to_branch_worktree(
9494
# Branch is checked out in a worktree
9595
# Only cd if we're in a different worktree
9696
if current_worktree_root != worktree_path:
97-
print(f"Branch {bold(branch)} is checked out in worktree at {bold(worktree_path)}")
98-
print("Changing directory to that worktree")
97+
print(f"Changing directory to {bold(worktree_path)} worktree where {bold(branch)} is checked out")
9998
os.chdir(worktree_path)
10099
# Flush root dir cache after directory change so get_root_dir() returns the correct path
101100
self._git.flush_root_dir_cache()
@@ -143,6 +142,7 @@ def traverse(
143142
# Store the main worktree path and initial directory for later restoration
144143
main_worktree_path = self._git.get_main_worktree_path()
145144
initial_branch = nearest_remaining_branch = self._git.get_current_branch()
145+
initial_worktree_root = self._git.get_root_dir()
146146

147147
# Fetch worktrees once at the start to avoid repeated git worktree list calls
148148
self.__worktrees_cache: Dict[LocalBranchShortName, str] = self._git.get_worktrees()
@@ -500,3 +500,13 @@ def traverse(
500500
print(
501501
f"The initial branch {bold(initial_branch)} has been slid out. "
502502
f"Returned to nearest remaining managed branch {bold(nearest_remaining_branch)}")
503+
504+
# Warn if the initial directory doesn't correspond to the final checked out branch's worktree
505+
final_branch = self._git.get_current_branch()
506+
final_worktree_path = self.__worktrees_cache.get(final_branch)
507+
if final_worktree_path and initial_worktree_root != final_worktree_path:
508+
# Final branch is checked out in a worktree different from where we started
509+
warn(
510+
f"Note: branch {bold(final_branch)} is checked out in worktree at {bold(final_worktree_path)}.\n"
511+
f"You may want to change directory with:\n"
512+
f" `cd {final_worktree_path}`")
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/usr/bin/env bash
2+
3+
set -e -o pipefail -u
4+
5+
root_dir=$(realpath "${1-$HOME}")
6+
7+
# First, set up the regular sandbox
8+
script_dir=$(cd "$(dirname "$0")" && pwd)
9+
"$script_dir/setup-sandbox" "$root_dir"
10+
11+
# Now create worktrees
12+
cd "$root_dir/machete-sandbox"
13+
14+
echo
15+
echo "Creating worktrees..."
16+
echo
17+
18+
# Create worktrees for some branches
19+
git worktree add "$root_dir/machete-sandbox-worktrees/allow-ownership-link" allow-ownership-link
20+
echo "Created worktree for allow-ownership-link at $root_dir/machete-sandbox-worktrees/allow-ownership-link"
21+
22+
git worktree add "$root_dir/machete-sandbox-worktrees/build-chain" build-chain
23+
echo "Created worktree for build-chain at $root_dir/machete-sandbox-worktrees/build-chain"
24+
25+
git worktree add "$root_dir/machete-sandbox-worktrees/master" master
26+
echo "Created worktree for master at $root_dir/machete-sandbox-worktrees/master"
27+
28+
# Create a worktree with detached HEAD at the tip of call-ws
29+
call_ws_sha=$(git rev-parse call-ws)
30+
git worktree add --detach "$root_dir/machete-sandbox-worktrees/detached-call-ws" "$call_ws_sha"
31+
echo "Created worktree with detached HEAD at $root_dir/machete-sandbox-worktrees/detached-call-ws (commit $call_ws_sha from call-ws)"
32+
33+
# Create another worktree with detached HEAD at the tip of hotfix/add-trigger
34+
hotfix_sha=$(git rev-parse hotfix/add-trigger)
35+
git worktree add --detach "$root_dir/machete-sandbox-worktrees/detached-hotfix" "$hotfix_sha"
36+
echo "Created worktree with detached HEAD at $root_dir/machete-sandbox-worktrees/detached-hotfix (commit $hotfix_sha from hotfix/add-trigger)"
37+
38+
echo
39+
echo "Worktree list:"
40+
git worktree list
41+
echo
42+
echo
43+
git machete status
44+
echo
45+
echo

tests/test_traverse.py

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1974,10 +1974,9 @@ def test_traverse_with_worktrees(self) -> None:
19741974

19751975
# Verify key behaviors happened:
19761976
# 1. It switched to feature-1 worktree
1977-
assert "Branch feature-1 is checked out in worktree at" in output
1978-
assert "Changing directory to that worktree" in output
1977+
assert "worktree where feature-1 is checked out" in output
19791978
# 2. It switched to feature-2 worktree
1980-
assert "Branch feature-2 is checked out in worktree at" in output
1979+
assert "worktree where feature-2 is checked out" in output
19811980
# 3. Operations were performed
19821981
assert "Rebasing feature-1 onto develop" in output
19831982
assert "Rebasing feature-2 onto feature-1" in output
@@ -2094,3 +2093,74 @@ def test_traverse_updates_worktree_cache_on_checkout(self) -> None:
20942093
# Verify branch-2 was checked out and pushed
20952094
assert "Checking out branch-2" in output
20962095
assert "Pushing untracked branch branch-2" in output
2096+
2097+
def test_traverse_warns_when_final_branch_in_different_worktree(self) -> None:
2098+
if get_git_version() < (2, 5):
2099+
return
2100+
2101+
create_repo_with_remote()
2102+
new_branch("root")
2103+
commit("root")
2104+
push()
2105+
new_branch("branch-1")
2106+
commit("branch-1")
2107+
push()
2108+
new_branch("branch-2")
2109+
commit("branch-2")
2110+
push()
2111+
2112+
body: str = \
2113+
"""
2114+
root
2115+
branch-1
2116+
branch-2
2117+
"""
2118+
rewrite_branch_layout_file(body)
2119+
2120+
# Create a worktree for branch-2
2121+
check_out("root")
2122+
branch_2_worktree = add_worktree("branch-2")
2123+
2124+
# Make root have an additional commit so branch-1 needs rebase
2125+
check_out("root")
2126+
commit("root additional commit")
2127+
push()
2128+
2129+
# Start from root (main worktree), traverse should process through branch-2
2130+
check_out("root")
2131+
output = launch_command("traverse", "-y")
2132+
2133+
# Verify the warning is emitted
2134+
assert "Note: branch branch-2 is checked out in worktree at" in output
2135+
assert f"You may want to change directory with:\n cd {os.path.realpath(branch_2_worktree)}" in output
2136+
2137+
def test_traverse_no_warn_when_final_branch_in_same_worktree(self) -> None:
2138+
if get_git_version() < (2, 5):
2139+
return
2140+
2141+
create_repo_with_remote()
2142+
new_branch("root")
2143+
commit("root")
2144+
push()
2145+
new_branch("branch-1")
2146+
commit("branch-1")
2147+
push()
2148+
2149+
body: str = \
2150+
"""
2151+
root
2152+
branch-1
2153+
"""
2154+
rewrite_branch_layout_file(body)
2155+
2156+
# Create a worktree for branch-1
2157+
check_out("root")
2158+
add_worktree("branch-1")
2159+
2160+
# Start from root (main worktree), traverse ends on root (same worktree)
2161+
check_out("root")
2162+
output = launch_command("traverse", "-y", "--return-to=here")
2163+
2164+
# Verify the warning is NOT emitted
2165+
assert "Note: branch" not in output
2166+
assert "You may want to change directory with:" not in output

0 commit comments

Comments
 (0)