title_bar: Prefer most specific repository for nested git repos#51898
Merged
smitbarmase merged 3 commits intozed-industries:mainfrom Mar 19, 2026
Merged
title_bar: Prefer most specific repository for nested git repos#51898smitbarmase merged 3 commits intozed-industries:mainfrom
smitbarmase merged 3 commits intozed-industries:mainfrom
Conversation
When a project contains nested git repositories, the title bar branch picker can show the parent repo's branch instead of the nested repo's. Repository lookup iterates an FxHashMap and returns the first `starts_with` match. For nested repos, both parent and child match. The function returns whichever one FxHashMap iterates first, which has no guaranteed relationship to path specificity. Apply the same `max_by_key` pattern already used by `GitStore::repository_and_path_for_project_path()` to select the repository with the longest (most specific) work directory path. Apply the same change to `git_ui::resolve_active_repository()` and `recent_projects::get_branch_for_worktree()`, which use the same first-match pattern. Closes zed-industries#7566
osiewicz
approved these changes
Mar 19, 2026
Caio-Ze
added a commit
to Caio-Ze/postprod-ide
that referenced
this pull request
Mar 19, 2026
…industries#51898) ## Context I have a project with a nested git repo inside a parent repo (separate `.git` directory, not a submodule). The title bar shows the parent's branch instead of the nested repo's own branch. The issue is in `get_repository_for_worktree()` — it iterates `git_store.repositories()` (an `FxHashMap`) and returns the first `starts_with` match. Both the parent and nested repo match, and whichever one FxHashMap iterates first wins. There's no reason it should be one or the other. The fix already exists elsewhere in the codebase — `GitStore::repository_and_path_for_project_path()` at `git_store.rs:1826` uses `.max_by_key()` to pick the most specific (longest path) match. This PR applies the same approach to three functions that have the same problem: - `TitleBar::get_repository_for_worktree()` — branch display in title bar - `resolve_active_repository()` in `git_ui` — repository selection for the git panel - `get_branch_for_worktree()` in `recent_projects` — branch display in the project switcher Two other locations use a similar `starts_with` pattern (`effective_active_worktree()` in `title_bar.rs` and worktree selection in `recent_projects.rs`) but those iterate worktrees against a single known repo, not repos against a worktree — so first-match and longest-match give the same result. Left those unchanged. Closes zed-industries#7566 ## How to Review All three changes are the same transformation: first-match loop (or `.find()`) → `.filter().max_by_key()` on path length. The reference is at `crates/project/src/git_store.rs:1826`. The primary fix is `get_repository_for_worktree()` in `title_bar.rs`. The other two are the same pattern. One difference from the reference: I used `.as_os_str().len()` instead of `.clone()` for the `max_by_key` key — avoids cloning an `Arc<Path>` per comparison. Among prefix-related paths (which is all that passes the filter), the longer path is always the more specific match, so length comparison is equivalent. `title_bar` has no existing test infrastructure. Happy to add a test if you'd like — the setup would follow the pattern in `test_git_traversal_with_nested_repos` (`crates/project/tests/integration/git_store.rs`). ``` cargo test -p title_bar -p git_ui -p recent_projects ./script/clippy ``` ## Self-Review Checklist - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Fixed branch picker showing parent repository's branch instead of the nested repository's branch when working in submodules or nested git repos. --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
AmaanBilwar
pushed a commit
to AmaanBilwar/zed
that referenced
this pull request
Mar 20, 2026
…industries#51898) ## Context I have a project with a nested git repo inside a parent repo (separate `.git` directory, not a submodule). The title bar shows the parent's branch instead of the nested repo's own branch. The issue is in `get_repository_for_worktree()` — it iterates `git_store.repositories()` (an `FxHashMap`) and returns the first `starts_with` match. Both the parent and nested repo match, and whichever one FxHashMap iterates first wins. There's no reason it should be one or the other. The fix already exists elsewhere in the codebase — `GitStore::repository_and_path_for_project_path()` at `git_store.rs:1826` uses `.max_by_key()` to pick the most specific (longest path) match. This PR applies the same approach to three functions that have the same problem: - `TitleBar::get_repository_for_worktree()` — branch display in title bar - `resolve_active_repository()` in `git_ui` — repository selection for the git panel - `get_branch_for_worktree()` in `recent_projects` — branch display in the project switcher Two other locations use a similar `starts_with` pattern (`effective_active_worktree()` in `title_bar.rs` and worktree selection in `recent_projects.rs`) but those iterate worktrees against a single known repo, not repos against a worktree — so first-match and longest-match give the same result. Left those unchanged. Closes zed-industries#7566 ## How to Review All three changes are the same transformation: first-match loop (or `.find()`) → `.filter().max_by_key()` on path length. The reference is at `crates/project/src/git_store.rs:1826`. The primary fix is `get_repository_for_worktree()` in `title_bar.rs`. The other two are the same pattern. One difference from the reference: I used `.as_os_str().len()` instead of `.clone()` for the `max_by_key` key — avoids cloning an `Arc<Path>` per comparison. Among prefix-related paths (which is all that passes the filter), the longer path is always the more specific match, so length comparison is equivalent. `title_bar` has no existing test infrastructure. Happy to add a test if you'd like — the setup would follow the pattern in `test_git_traversal_with_nested_repos` (`crates/project/tests/integration/git_store.rs`). ``` cargo test -p title_bar -p git_ui -p recent_projects ./script/clippy ``` ## Self-Review Checklist - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Fixed branch picker showing parent repository's branch instead of the nested repository's branch when working in submodules or nested git repos. --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
toshmukhamedov
pushed a commit
to toshmukhamedov/zed
that referenced
this pull request
Mar 20, 2026
…industries#51898) ## Context I have a project with a nested git repo inside a parent repo (separate `.git` directory, not a submodule). The title bar shows the parent's branch instead of the nested repo's own branch. The issue is in `get_repository_for_worktree()` — it iterates `git_store.repositories()` (an `FxHashMap`) and returns the first `starts_with` match. Both the parent and nested repo match, and whichever one FxHashMap iterates first wins. There's no reason it should be one or the other. The fix already exists elsewhere in the codebase — `GitStore::repository_and_path_for_project_path()` at `git_store.rs:1826` uses `.max_by_key()` to pick the most specific (longest path) match. This PR applies the same approach to three functions that have the same problem: - `TitleBar::get_repository_for_worktree()` — branch display in title bar - `resolve_active_repository()` in `git_ui` — repository selection for the git panel - `get_branch_for_worktree()` in `recent_projects` — branch display in the project switcher Two other locations use a similar `starts_with` pattern (`effective_active_worktree()` in `title_bar.rs` and worktree selection in `recent_projects.rs`) but those iterate worktrees against a single known repo, not repos against a worktree — so first-match and longest-match give the same result. Left those unchanged. Closes zed-industries#7566 ## How to Review All three changes are the same transformation: first-match loop (or `.find()`) → `.filter().max_by_key()` on path length. The reference is at `crates/project/src/git_store.rs:1826`. The primary fix is `get_repository_for_worktree()` in `title_bar.rs`. The other two are the same pattern. One difference from the reference: I used `.as_os_str().len()` instead of `.clone()` for the `max_by_key` key — avoids cloning an `Arc<Path>` per comparison. Among prefix-related paths (which is all that passes the filter), the longer path is always the more specific match, so length comparison is equivalent. `title_bar` has no existing test infrastructure. Happy to add a test if you'd like — the setup would follow the pattern in `test_git_traversal_with_nested_repos` (`crates/project/tests/integration/git_store.rs`). ``` cargo test -p title_bar -p git_ui -p recent_projects ./script/clippy ``` ## Self-Review Checklist - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Fixed branch picker showing parent repository's branch instead of the nested repository's branch when working in submodules or nested git repos. --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
AmaanBilwar
pushed a commit
to AmaanBilwar/zed
that referenced
this pull request
Mar 23, 2026
…industries#51898) ## Context I have a project with a nested git repo inside a parent repo (separate `.git` directory, not a submodule). The title bar shows the parent's branch instead of the nested repo's own branch. The issue is in `get_repository_for_worktree()` — it iterates `git_store.repositories()` (an `FxHashMap`) and returns the first `starts_with` match. Both the parent and nested repo match, and whichever one FxHashMap iterates first wins. There's no reason it should be one or the other. The fix already exists elsewhere in the codebase — `GitStore::repository_and_path_for_project_path()` at `git_store.rs:1826` uses `.max_by_key()` to pick the most specific (longest path) match. This PR applies the same approach to three functions that have the same problem: - `TitleBar::get_repository_for_worktree()` — branch display in title bar - `resolve_active_repository()` in `git_ui` — repository selection for the git panel - `get_branch_for_worktree()` in `recent_projects` — branch display in the project switcher Two other locations use a similar `starts_with` pattern (`effective_active_worktree()` in `title_bar.rs` and worktree selection in `recent_projects.rs`) but those iterate worktrees against a single known repo, not repos against a worktree — so first-match and longest-match give the same result. Left those unchanged. Closes zed-industries#7566 ## How to Review All three changes are the same transformation: first-match loop (or `.find()`) → `.filter().max_by_key()` on path length. The reference is at `crates/project/src/git_store.rs:1826`. The primary fix is `get_repository_for_worktree()` in `title_bar.rs`. The other two are the same pattern. One difference from the reference: I used `.as_os_str().len()` instead of `.clone()` for the `max_by_key` key — avoids cloning an `Arc<Path>` per comparison. Among prefix-related paths (which is all that passes the filter), the longer path is always the more specific match, so length comparison is equivalent. `title_bar` has no existing test infrastructure. Happy to add a test if you'd like — the setup would follow the pattern in `test_git_traversal_with_nested_repos` (`crates/project/tests/integration/git_store.rs`). ``` cargo test -p title_bar -p git_ui -p recent_projects ./script/clippy ``` ## Self-Review Checklist - [x] I've reviewed my own diff for quality, security, and reliability - [x] Unsafe blocks (if any) have justifying comments - [x] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [ ] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Release Notes: - Fixed branch picker showing parent repository's branch instead of the nested repository's branch when working in submodules or nested git repos. --------- Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com> Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
Caio-Ze
added a commit
to Caio-Ze/postprod-ide
that referenced
this pull request
Apr 10, 2026
Fixup for dd0d5be. The original commit hooked `active_item_path_changed`, which fires on every file click and tab switch — making the profile react to individual file focus rather than to project activation. That was wrong: the profile should track which worktree is effectively active in the workspace (the one whose name shows next to the branch in the title bar), not the worktree of whichever file the user happened to click last. This commit rewrites the identification logic to mirror `TitleBar::effective_active_worktree` (crates/title_bar/src/title_bar.rs:463): 1. `active_worktree_override` if set — the user's explicit pick via the project dropdown (introduced by Danilo Leal in c9003e1 for git operations). 2. The worktree containing `Project::active_repository` — the repo of the active file, which thanks to zed-industries#51898 resolves to the most specific repository for nested git setups. 3. First visible worktree as a final fallback. With this logic, `apply_local_active_profile` and `TitleBar::effective_active_worktree` always agree on "which worktree is the current one." The profile name and the title bar project name stay synchronized by definition — they read the same state through the same ordered resolution. Changes: - Rewrote `apply_local_active_profile` to call a new private helper `effective_active_worktree_id`, which implements the three-tier logic. The helper is deliberately inlined (duplicated from `TitleBar::effective_active_worktree`) rather than extracted onto `Workspace` as a shared method — that extraction is a natural follow-up but kept out of scope here. - Removed the `self.apply_local_active_profile(cx)` call at the end of `active_item_path_changed`. File clicks no longer trigger profile re-evaluation. - Added `self.apply_local_active_profile(cx)` calls to `set_active_worktree_override` and `clear_active_worktree_override`, so picking a worktree from the project dropdown drives profile activation. `Workspace::new`'s deferred setup hook and the `MultiWorkspace::activate` hook are unchanged from dd0d5be. Spec: private/specs/persistent-active-profile.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Caio-Ze
added a commit
to Caio-Ze/postprod-ide
that referenced
this pull request
Apr 11, 2026
Fixup for dd0d5be. The original commit hooked `active_item_path_changed`, which fires on every file click and tab switch — making the profile react to individual file focus rather than to project activation. That was wrong: the profile should track which worktree is effectively active in the workspace (the one whose name shows next to the branch in the title bar), not the worktree of whichever file the user happened to click last. This commit rewrites the identification logic to mirror `TitleBar::effective_active_worktree` (crates/title_bar/src/title_bar.rs:463): 1. `active_worktree_override` if set — the user's explicit pick via the project dropdown (introduced by Danilo Leal in c9003e1 for git operations). 2. The worktree containing `Project::active_repository` — the repo of the active file, which thanks to zed-industries#51898 resolves to the most specific repository for nested git setups. 3. First visible worktree as a final fallback. With this logic, `apply_local_active_profile` and `TitleBar::effective_active_worktree` always agree on "which worktree is the current one." The profile name and the title bar project name stay synchronized by definition — they read the same state through the same ordered resolution. Changes: - Rewrote `apply_local_active_profile` to call a new private helper `effective_active_worktree_id`, which implements the three-tier logic. The helper is deliberately inlined (duplicated from `TitleBar::effective_active_worktree`) rather than extracted onto `Workspace` as a shared method — that extraction is a natural follow-up but kept out of scope here. - Removed the `self.apply_local_active_profile(cx)` call at the end of `active_item_path_changed`. File clicks no longer trigger profile re-evaluation. - Added `self.apply_local_active_profile(cx)` calls to `set_active_worktree_override` and `clear_active_worktree_override`, so picking a worktree from the project dropdown drives profile activation. `Workspace::new`'s deferred setup hook and the `MultiWorkspace::activate` hook are unchanged from dd0d5be. Spec: private/specs/persistent-active-profile.md Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Context
I have a project with a nested git repo inside a parent repo (separate
.gitdirectory, not a submodule). The title bar shows the parent's branch instead of the nested repo's own branch.The issue is in
get_repository_for_worktree()— it iteratesgit_store.repositories()(anFxHashMap) and returns the firststarts_withmatch. Both the parent and nested repo match, and whichever one FxHashMap iterates first wins. There's no reason it should be one or the other.The fix already exists elsewhere in the codebase —
GitStore::repository_and_path_for_project_path()atgit_store.rs:1826uses.max_by_key()to pick the most specific (longest path) match. This PR applies the same approach to three functions that have the same problem:TitleBar::get_repository_for_worktree()— branch display in title barresolve_active_repository()ingit_ui— repository selection for the git panelget_branch_for_worktree()inrecent_projects— branch display in the project switcherTwo other locations use a similar
starts_withpattern (effective_active_worktree()intitle_bar.rsand worktree selection inrecent_projects.rs) but those iterate worktrees against a single known repo, not repos against a worktree — so first-match and longest-match give the same result. Left those unchanged.Closes #7566
How to Review
All three changes are the same transformation: first-match loop (or
.find()) →.filter().max_by_key()on path length. The reference is atcrates/project/src/git_store.rs:1826.The primary fix is
get_repository_for_worktree()intitle_bar.rs. The other two are the same pattern.One difference from the reference: I used
.as_os_str().len()instead of.clone()for themax_by_keykey — avoids cloning anArc<Path>per comparison. Among prefix-related paths (which is all that passes the filter), the longer path is always the more specific match, so length comparison is equivalent.title_barhas no existing test infrastructure. Happy to add a test if you'd like — the setup would follow the pattern intest_git_traversal_with_nested_repos(crates/project/tests/integration/git_store.rs).Self-Review Checklist
Release Notes: