Remove agent git worktree feature flag (#50778)

Richard Feldman created

Remove the separate `AgentGitWorktreesFeatureFlag` and replace all its
checks with the existing `AgentV2FeatureFlag`. The git worktree
functionality is now gated behind the same flag as agent v2.

Changes:
- Removed `AgentGitWorktreesFeatureFlag` from `feature_flags`
- Replaced all `has_flag::<AgentGitWorktreesFeatureFlag>()` checks with
`has_flag::<AgentV2FeatureFlag>()`
- Simplified toolbar condition that was redundantly checking both flags
- Updated tests accordingly

Closes AI-73

Release Notes:

- N/A

Change summary

crates/agent_ui/src/agent_panel.rs   | 111 +----------------------------
crates/feature_flags/src/flags.rs    |  10 --
crates/zed/src/visual_test_runner.rs |   5 -
3 files changed, 6 insertions(+), 120 deletions(-)

Detailed changes

crates/agent_ui/src/agent_panel.rs 🔗

@@ -22,7 +22,7 @@ use project::{
 use serde::{Deserialize, Serialize};
 use settings::{LanguageModelProviderSetting, LanguageModelSelection};
 
-use feature_flags::{AgentGitWorktreesFeatureFlag, AgentV2FeatureFlag, FeatureFlagAppExt as _};
+use feature_flags::{AgentV2FeatureFlag, FeatureFlagAppExt as _};
 use zed_actions::agent::{OpenClaudeAgentOnboardingModal, ReauthenticateAgent, ReviewBranchDiff};
 
 use crate::ManageProfiles;
@@ -695,7 +695,7 @@ impl AgentPanel {
                         }
                         if let Some(start_thread_in) = serialized_panel.start_thread_in {
                             let is_worktree_flag_enabled =
-                                cx.has_flag::<AgentGitWorktreesFeatureFlag>();
+                                cx.has_flag::<AgentV2FeatureFlag>();
                             let is_valid = match &start_thread_in {
                                 StartThreadIn::LocalProject => true,
                                 StartThreadIn::NewWorktree => {
@@ -1860,9 +1860,7 @@ impl AgentPanel {
     }
 
     fn set_start_thread_in(&mut self, action: &StartThreadIn, cx: &mut Context<Self>) {
-        if matches!(action, StartThreadIn::NewWorktree)
-            && !cx.has_flag::<AgentGitWorktreesFeatureFlag>()
-        {
+        if matches!(action, StartThreadIn::NewWorktree) && !cx.has_flag::<AgentV2FeatureFlag>() {
             return;
         }
 
@@ -3496,9 +3494,7 @@ impl AgentPanel {
                     .pl(DynamicSpacing::Base04.rems(cx))
                     .pr(DynamicSpacing::Base06.rems(cx))
                     .when(
-                        has_v2_flag
-                            && cx.has_flag::<AgentGitWorktreesFeatureFlag>()
-                            && !self.active_thread_has_messages(cx),
+                        has_v2_flag && !self.active_thread_has_messages(cx),
                         |this| this.child(self.render_start_thread_in_selector(cx)),
                     )
                     .child(new_thread_menu)
@@ -4635,10 +4631,7 @@ mod tests {
     async fn test_thread_target_serialization_round_trip(cx: &mut TestAppContext) {
         init_test(cx);
         cx.update(|cx| {
-            cx.update_flags(
-                true,
-                vec!["agent-v2".to_string(), "agent-git-worktrees".to_string()],
-            );
+            cx.update_flags(true, vec!["agent-v2".to_string()]);
             agent::ThreadStore::init_global(cx);
             language_model::LanguageModelRegistry::test(cx);
         });
@@ -4725,100 +4718,6 @@ mod tests {
         });
     }
 
-    #[gpui::test]
-    async fn test_thread_target_deserialization_falls_back_when_worktree_flag_disabled(
-        cx: &mut TestAppContext,
-    ) {
-        init_test(cx);
-        cx.update(|cx| {
-            cx.update_flags(
-                true,
-                vec!["agent-v2".to_string(), "agent-git-worktrees".to_string()],
-            );
-            agent::ThreadStore::init_global(cx);
-            language_model::LanguageModelRegistry::test(cx);
-        });
-
-        let fs = FakeFs::new(cx.executor());
-        fs.insert_tree(
-            "/project",
-            json!({
-                ".git": {},
-                "src": {
-                    "main.rs": "fn main() {}"
-                }
-            }),
-        )
-        .await;
-        fs.set_branch_name(Path::new("/project/.git"), Some("main"));
-
-        let project = Project::test(fs.clone(), [Path::new("/project")], cx).await;
-
-        let multi_workspace =
-            cx.add_window(|window, cx| MultiWorkspace::test_new(project.clone(), window, cx));
-
-        let workspace = multi_workspace
-            .read_with(cx, |multi_workspace, _cx| {
-                multi_workspace.workspace().clone()
-            })
-            .unwrap();
-
-        workspace.update(cx, |workspace, _cx| {
-            workspace.set_random_database_id();
-        });
-
-        let cx = &mut VisualTestContext::from_window(multi_workspace.into(), cx);
-
-        // Wait for the project to discover the git repository.
-        cx.run_until_parked();
-
-        let panel = workspace.update_in(cx, |workspace, window, cx| {
-            let text_thread_store = cx.new(|cx| TextThreadStore::fake(project.clone(), cx));
-            let panel =
-                cx.new(|cx| AgentPanel::new(workspace, text_thread_store, None, window, cx));
-            workspace.add_panel(panel.clone(), window, cx);
-            panel
-        });
-
-        cx.run_until_parked();
-
-        panel.update(cx, |panel, cx| {
-            panel.set_start_thread_in(&StartThreadIn::NewWorktree, cx);
-        });
-
-        panel.read_with(cx, |panel, _cx| {
-            assert_eq!(
-                *panel.start_thread_in(),
-                StartThreadIn::NewWorktree,
-                "thread target should be NewWorktree before reload"
-            );
-        });
-
-        // Let serialization complete.
-        cx.run_until_parked();
-
-        // Disable worktree flag and reload panel from serialized data.
-        cx.update(|_, cx| {
-            cx.update_flags(true, vec!["agent-v2".to_string()]);
-        });
-
-        let prompt_builder = Arc::new(prompt_store::PromptBuilder::new(None).unwrap());
-        let async_cx = cx.update(|window, cx| window.to_async(cx));
-        let loaded_panel =
-            AgentPanel::load(workspace.downgrade(), prompt_builder.clone(), async_cx)
-                .await
-                .expect("panel load should succeed");
-        cx.run_until_parked();
-
-        loaded_panel.read_with(cx, |panel, _cx| {
-            assert_eq!(
-                *panel.start_thread_in(),
-                StartThreadIn::LocalProject,
-                "thread target should fall back to LocalProject when worktree flag is disabled"
-            );
-        });
-    }
-
     #[gpui::test]
     async fn test_set_active_blocked_during_worktree_creation(cx: &mut TestAppContext) {
         init_test(cx);

crates/feature_flags/src/flags.rs 🔗

@@ -37,16 +37,6 @@ impl FeatureFlag for AgentSharingFeatureFlag {
     const NAME: &'static str = "agent-sharing";
 }
 
-pub struct AgentGitWorktreesFeatureFlag;
-
-impl FeatureFlag for AgentGitWorktreesFeatureFlag {
-    const NAME: &'static str = "agent-git-worktrees";
-
-    fn enabled_for_staff() -> bool {
-        false
-    }
-}
-
 pub struct DiffReviewFeatureFlag;
 
 impl FeatureFlag for DiffReviewFeatureFlag {

crates/zed/src/visual_test_runner.rs 🔗

@@ -3099,10 +3099,7 @@ fn run_start_thread_in_selector_visual_tests(
 
     // Enable feature flags so the thread target selector renders
     cx.update(|cx| {
-        cx.update_flags(
-            true,
-            vec!["agent-v2".to_string(), "agent-git-worktrees".to_string()],
-        );
+        cx.update_flags(true, vec!["agent-v2".to_string()]);
     });
 
     // Create a temp directory with a real git repo so "New Worktree" is enabled