From c4bebaf242359bd19574cf1de546a4375f66a4bc Mon Sep 17 00:00:00 2001 From: Kaan Ozkan Date: Fri, 6 Mar 2026 15:22:30 -0500 Subject: [PATCH] Skip DSL generation on branch switch by detecting git HEAD changes When switching branches, VS Code sends hundreds of file change notifications that trigger parallel reload + DSL generation requests. This causes incorrect RBIs and deleted valid files due to stale server state. Detect branch switches by reading .git/HEAD on each file change event. If HEAD changed since last check, skip DSL generation (only reload). Normal user edits don't change HEAD, so they continue to trigger DSL generation as before. Fixes https://github.com/Shopify/team-ruby-dx/issues/1429 --- lib/ruby_lsp/tapioca/addon.rb | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/lib/ruby_lsp/tapioca/addon.rb b/lib/ruby_lsp/tapioca/addon.rb index e227ce75d..1ee563d62 100644 --- a/lib/ruby_lsp/tapioca/addon.rb +++ b/lib/ruby_lsp/tapioca/addon.rb @@ -28,6 +28,7 @@ def initialize @file_checksums = {} #: Hash[String, String] @lockfile_diff = nil #: String? @outgoing_queue = nil #: Thread::Queue? + @last_known_git_head = read_git_head #: String? end # @override @@ -126,6 +127,19 @@ def workspace_did_change_watched_files(changes) @rails_runner_client.trigger_reload + # If git HEAD changed, this is a branch switch (or rebase/pull). Skip DSL generation + # since the server state may be stale. Only reload was needed. + if git_head_changed? + queue = @outgoing_queue + if queue + queue << Notification.window_log_message( + "Tapioca add-on: detected branch switch, skipping DSL generation", + type: Constant::MessageType::INFO, + ) + end + return + end + if needs_compiler_reload @rails_runner_client.delegate_notification( server_addon_name: "Tapioca", @@ -175,6 +189,24 @@ def send_usage_telemetry(feature_name) }) end + #: -> bool + def git_head_changed? + current_head = read_git_head + changed = @last_known_git_head && current_head && @last_known_git_head != current_head + @last_known_git_head = current_head + !!changed + end + + #: -> String? + def read_git_head + git_head_path = File.join(Dir.pwd, ".git", "HEAD") + return unless File.exist?(git_head_path) + + File.read(git_head_path).strip + rescue SystemCallError + nil + end + #: (Hash[Symbol, untyped] change, String path) -> bool def file_updated?(change, path) queue = @outgoing_queue #: as !nil