From dff3200e5ca078977a40d92ad4236b9c8d60499e Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 7 May 2026 20:08:37 +0900 Subject: [ruby/rubygems] Stop blanket-unlocking the lockfile on :all overrides Previously, any :all override called unlock_all_locked_specs_for_override which pushed every locked spec into @gems_to_unlock. A user adding a narrow `override :all, required_ruby_version: :ignore_upper` thus paid for a full re-resolve that could pull unrelated dependency upgrades/downgrades. Make :all overrides leave the lockfile alone at converge time. They take effect on a fresh resolution (no lockfile) or when the user opts in via `bundle update`. Per-gem overrides retain their unlock for the named gem since the user explicitly named the target. https://github.com/ruby/rubygems/commit/3c95ab99e3 Co-Authored-By: Claude Opus 4.7 (1M context) --- lib/bundler/definition.rb | 18 ++++-------------- spec/bundler/install/gemfile/override_spec.rb | 8 +++++++- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 2fe28f7656..2aa74804ba 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -1061,11 +1061,10 @@ module Bundler def converge_overrides_outside_dependencies @overrides.each do |override| - if override.target == :all - unlock_all_locked_specs_for_override - next - end - + # :all overrides are intentionally not pre-unlocked. They take effect on + # fresh resolution (no lockfile) or when the user runs `bundle update`. + # Forcing a full re-resolve from a single :all directive would surprise + # users with unrelated dependency churn. next unless override.target.is_a?(String) name = override.target @@ -1081,15 +1080,6 @@ module Bundler end end - def unlock_all_locked_specs_for_override - @originally_locked_specs.each do |locked_spec| - name = locked_spec.name - next if @changed_dependencies.include?(name) - @gems_to_unlock << name - @changed_dependencies << name - end - end - # Remove elements from the locked specs that are expired. This will most # commonly happen if the Gemfile has changed since the lockfile was last # generated diff --git a/spec/bundler/install/gemfile/override_spec.rb b/spec/bundler/install/gemfile/override_spec.rb index 19fa2ee915..02b0e7d772 100644 --- a/spec/bundler/install/gemfile/override_spec.rb +++ b/spec/bundler/install/gemfile/override_spec.rb @@ -291,7 +291,7 @@ RSpec.describe "override DSL" do expect(err).to include("still_blocked") end - it "re-resolves a previously locked spec when an :all metadata override is added" do + it "preserves locked versions when an :all metadata override is added without bundle update" do build_repo2 do build_gem "selectable", "1.0" build_gem "selectable", "2.0" do |s| @@ -313,7 +313,13 @@ RSpec.describe "override DSL" do gem "selectable" G + # :all override alone does not pre-unlock locked specs; narrow change + # should not trigger unrelated lockfile churn. bundle :lock + expect(lockfile).to include("selectable (1.0)") + + # bundle update opts the user into re-resolution under the override. + bundle "update selectable" expect(lockfile).to include("selectable (2.0)") end end -- cgit v1.2.3