Skip to content

Commit 07fd8ec

Browse files
committed
Keep main worktree path cached
1 parent 15b4984 commit 07fd8ec

File tree

2 files changed

+31
-29
lines changed

2 files changed

+31
-29
lines changed

git_machete/client/traverse.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,7 @@ def _update_worktrees_cache_after_checkout(self, checked_out_branch: LocalBranch
6969

7070
def _switch_to_branch_worktree(
7171
self,
72-
branch: LocalBranchShortName,
73-
*,
74-
main_worktree_path: str) -> None:
72+
branch: LocalBranchShortName) -> None:
7573
"""
7674
Switch to the worktree where the branch is checked out, or to main worktree if branch is not checked out.
7775
This may involve changing the current working directory.
@@ -83,6 +81,7 @@ def _switch_to_branch_worktree(
8381
if worktree_path is None:
8482
# Branch is not checked out anywhere, need to checkout in main worktree
8583
# Only cd if we're currently in a different worktree (linked worktree)
84+
main_worktree_path = self._git.get_main_worktree_path()
8685
if current_worktree_root != main_worktree_path:
8786
print(f"Changing directory to main worktree at {bold(main_worktree_path)}")
8887
os.chdir(main_worktree_path)
@@ -139,8 +138,7 @@ def traverse(
139138
self._init_code_hosting_client()
140139
current_user = self.code_hosting_client.get_current_user_login()
141140

142-
# Store the main worktree path and initial directory for later restoration
143-
main_worktree_path = self._git.get_main_worktree_path()
141+
# Store the initial directory for later restoration
144142
initial_branch = nearest_remaining_branch = self._git.get_current_branch()
145143
initial_worktree_root = self._git.get_root_dir()
146144

@@ -151,14 +149,14 @@ def traverse(
151149
dest = self.root_branch_for(self._git.get_current_branch(), if_unmanaged=PickRoot.FIRST)
152150
self._print_new_line(False)
153151
print(f"Checking out the root branch ({bold(dest)})")
154-
self._switch_to_branch_worktree(dest, main_worktree_path=main_worktree_path)
152+
self._switch_to_branch_worktree(dest)
155153
current_branch = dest
156154
elif opt_start_from == TraverseStartFrom.FIRST_ROOT:
157155
# Note that we already ensured that there is at least one managed branch.
158156
dest = self.managed_branches[0]
159157
self._print_new_line(False)
160158
print(f"Checking out the first root branch ({bold(dest)})")
161-
self._switch_to_branch_worktree(dest, main_worktree_path=main_worktree_path)
159+
self._switch_to_branch_worktree(dest)
162160
current_branch = dest
163161
elif opt_start_from == TraverseStartFrom.HERE:
164162
current_branch = self._git.get_current_branch()
@@ -168,7 +166,7 @@ def traverse(
168166
self.expect_in_managed_branches(dest)
169167
self._print_new_line(False)
170168
print(f"Checking out branch {bold(dest)}")
171-
self._switch_to_branch_worktree(dest, main_worktree_path=main_worktree_path)
169+
self._switch_to_branch_worktree(dest)
172170
current_branch = dest
173171
else:
174172
raise UnexpectedMacheteException(f"Unexpected value for opt_start_from: {opt_start_from}")
@@ -245,7 +243,7 @@ def traverse(
245243
if branch != current_branch and needs_any_action:
246244
self._print_new_line(False)
247245
print(f"Checking out {bold(branch)}")
248-
self._switch_to_branch_worktree(branch, main_worktree_path=main_worktree_path)
246+
self._switch_to_branch_worktree(branch)
249247
current_branch = branch
250248
self._print_new_line(False)
251249
self.status(
@@ -471,9 +469,9 @@ def traverse(
471469
if opt_return_to == TraverseReturnTo.HERE:
472470
# Return to initial branch
473471
# No point switching back to initial directory as cwd won't propagate back to the calling shell anyway
474-
self._switch_to_branch_worktree(initial_branch, main_worktree_path=main_worktree_path)
472+
self._switch_to_branch_worktree(initial_branch)
475473
elif opt_return_to == TraverseReturnTo.NEAREST_REMAINING:
476-
self._switch_to_branch_worktree(nearest_remaining_branch, main_worktree_path=main_worktree_path)
474+
self._switch_to_branch_worktree(nearest_remaining_branch)
477475
# For NEAREST_REMAINING, we stay in the worktree where the branch is checked out
478476
# otherwise opt_return_to == TraverseReturnTo.STAY, so no action is needed
479477

git_machete/git_operations.py

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ def __init__(self) -> None:
220220

221221
self.__git_version: Optional[Tuple[int, int, int]] = None
222222
self.__root_dir: Optional[str] = None
223+
self.__main_worktree: Optional[str] = None
223224
self.__main_git_dir: Optional[str] = None
224225
self.__worktree_git_dir: Optional[str] = None
225226

@@ -254,6 +255,7 @@ def flush_caches(self) -> None:
254255
self.__remotes_cached = None
255256
self.__removed_from_remote = None
256257
self.__root_dir = None
258+
self.__main_worktree = None
257259
self.__short_commit_hash_by_revision_cached = {}
258260

259261
def flush_root_dir_cache(self) -> None:
@@ -630,24 +632,26 @@ def get_main_worktree_path(self) -> str:
630632
"""
631633
Returns the path to the main worktree (not a linked worktree).
632634
"""
633-
if self.get_git_version() < (2, 5):
634-
# git worktree command was introduced in git 2.5
635-
# If worktrees aren't supported, just return the current root dir
636-
return self.get_root_dir()
637-
638-
# We can't rely on `git rev-parse --git-common-dir`
639-
# since in some earlier supported versions of git
640-
# this path is apparently printed in a faulty way when dealing with worktrees.
641-
# Let's parse the output of of `git worktree list` instead.
642-
result = self._popen_git("worktree", "list", "--porcelain")
643-
644-
# The first worktree in the list is always the main worktree
645-
first_entry = result.stdout.splitlines()[0]
646-
if first_entry.startswith('worktree '):
647-
return first_entry[len('worktree '):]
648-
else:
649-
raise UnexpectedMacheteException("Could not obtain the main worktree path from "
650-
f"`git worktree list --porcelain` output (first line: `{first_entry}`)")
635+
if not self.__main_worktree:
636+
if self.get_git_version() < (2, 5):
637+
# git worktree command was introduced in git 2.5
638+
# If worktrees aren't supported, just return the current root dir
639+
self.__main_worktree = self.get_root_dir()
640+
else:
641+
# We can't rely on `git rev-parse --git-common-dir`
642+
# since in some earlier supported versions of git
643+
# this path is apparently printed in a faulty way when dealing with worktrees.
644+
# Let's parse the output of of `git worktree list` instead.
645+
result = self._popen_git("worktree", "list", "--porcelain")
646+
647+
# The first worktree in the list is always the main worktree
648+
first_entry = result.stdout.splitlines()[0]
649+
if first_entry.startswith('worktree '):
650+
self.__main_worktree = first_entry[len('worktree '):]
651+
else:
652+
raise UnexpectedMacheteException("Could not obtain the main worktree path from "
653+
f"`git worktree list --porcelain` output (first line: `{first_entry}`)")
654+
return self.__main_worktree
651655

652656
def checkout(self, branch: LocalBranchShortName) -> None:
653657
self._run_git("checkout", "--quiet", branch, "--", flush_caches=True)

0 commit comments

Comments
 (0)