From 73735b503cba36fb8bde717d57a1f901f574eb8f Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Tue, 3 Feb 2026 21:03:25 +0900 Subject: [PATCH 1/3] Added failing example --- bundler/spec/install/gemfile/sources_spec.rb | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/bundler/spec/install/gemfile/sources_spec.rb b/bundler/spec/install/gemfile/sources_spec.rb index 69b0816a1899..4957ef70be2c 100644 --- a/bundler/spec/install/gemfile/sources_spec.rb +++ b/bundler/spec/install/gemfile/sources_spec.rb @@ -1236,4 +1236,41 @@ expect(the_bundle).to include_gems("fallback_dep 1.0.0", source: "remote2") end end + + context "when a path gem has a transitive dependency that does not exist in the path source" do + before do + build_repo2 do + build_gem "missing_dep", "1.0.0" + build_gem "foo", "1.0.0" + end + + build_lib "parent_gem", "1.0.0", path: lib_path("parent_gem") do |s| + s.add_dependency "missing_dep" + end + + gemfile <<-G + source "https://gem.repo2" + + gem "foo" + + gem "parent_gem", path: "#{lib_path("parent_gem")}" + G + + bundle :install, artifice: "compact_index" + end + + it "falls back to the default rubygems source for that dependency when updating" do + build_repo2 do + build_gem "foo", "2.0.0" + end + + system_gems [] + + bundle "update foo", artifice: "compact_index" + + expect(the_bundle).to include_gems("parent_gem 1.0.0", "missing_dep 1.0.0", "foo 2.0.0") + expect(the_bundle).to include_gems("parent_gem 1.0.0", source: "path@#{lib_path("parent_gem")}") + expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2") + end + end end From 7c89d2588d66bd1998804055614138826ad89b31 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 4 Feb 2026 10:51:06 +0900 Subject: [PATCH 2/3] Require parent path source to contain matching specs before selecting it as replacement --- bundler/lib/bundler/definition.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bundler/lib/bundler/definition.rb b/bundler/lib/bundler/definition.rb index 639740e46b6b..3cf9fbe8bf03 100644 --- a/bundler/lib/bundler/definition.rb +++ b/bundler/lib/bundler/definition.rb @@ -1077,7 +1077,7 @@ def converge_specs(specs) end end - if parent_dep && parent_dep.source.is_a?(Source::Path) + if parent_dep && parent_dep.source.is_a?(Source::Path) && parent_dep.source.specs[s]&.any? replacement_source = parent_dep.source else replacement_source = sources.get(lockfile_source) From 00c8bb7bc5536a2858933c7436a71bc93a76068a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Feb 2026 02:50:52 +0000 Subject: [PATCH 3/3] Add test case for git sources with transitive dependencies Co-authored-by: hsbt <12301+hsbt@users.noreply.github.com> --- bundler/spec/install/gemfile/sources_spec.rb | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/bundler/spec/install/gemfile/sources_spec.rb b/bundler/spec/install/gemfile/sources_spec.rb index 4957ef70be2c..c72a2b982a99 100644 --- a/bundler/spec/install/gemfile/sources_spec.rb +++ b/bundler/spec/install/gemfile/sources_spec.rb @@ -1273,4 +1273,41 @@ expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2") end end + + context "when a git gem has a transitive dependency that does not exist in the git source" do + before do + build_repo2 do + build_gem "missing_dep", "1.0.0" + build_gem "foo", "1.0.0" + end + + build_git "parent_gem", "1.0.0", path: lib_path("parent_gem") do |s| + s.add_dependency "missing_dep" + end + + gemfile <<-G + source "https://gem.repo2" + + gem "foo" + + gem "parent_gem", git: "#{lib_path("parent_gem")}" + G + + bundle :install, artifice: "compact_index" + end + + it "falls back to the default rubygems source for that dependency when updating" do + build_repo2 do + build_gem "foo", "2.0.0" + end + + system_gems [] + + bundle "update foo", artifice: "compact_index" + + expect(the_bundle).to include_gems("parent_gem 1.0.0", "missing_dep 1.0.0", "foo 2.0.0") + expect(the_bundle).to include_gems("parent_gem 1.0.0", source: "git@#{lib_path("parent_gem")}") + expect(the_bundle).to include_gems("missing_dep 1.0.0", source: "remote2") + end + end end