From c9a26789d88b18f8b4620f37307df2976292d2a0 Mon Sep 17 00:00:00 2001
From: "GPT 5.4" <codex@openai.com>
Date: Tue, 21 Apr 2026 09:30:29 +0800
Subject: [PATCH] Make sure that multi-options are checked after splitting them
 with `shlex`

Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
---
 git/repo/base.py       |  4 ++--
 test/test_clone.py     | 18 ++++++++++++++++++
 test/test_submodule.py | 11 +++++++++++
 3 files changed, 31 insertions(+), 2 deletions(-)

Index: GitPython-3.1.44/git/repo/base.py
===================================================================
--- GitPython-3.1.44.orig/git/repo/base.py
+++ GitPython-3.1.44/git/repo/base.py
@@ -1381,8 +1381,8 @@ class Repo:
             Git.check_unsafe_protocols(str(url))
         if not allow_unsafe_options:
             Git.check_unsafe_options(options=list(kwargs.keys()), unsafe_options=cls.unsafe_git_clone_options)
-        if not allow_unsafe_options and multi_options:
-            Git.check_unsafe_options(options=multi_options, unsafe_options=cls.unsafe_git_clone_options)
+        if not allow_unsafe_options and multi:
+            Git.check_unsafe_options(options=multi, unsafe_options=cls.unsafe_git_clone_options)
 
         proc = git.clone(
             multi,
Index: GitPython-3.1.44/test/test_clone.py
===================================================================
--- GitPython-3.1.44.orig/test/test_clone.py
+++ GitPython-3.1.44/test/test_clone.py
@@ -6,7 +6,7 @@ import re
 
 import git
 
-from test.lib import TestBase, with_rw_directory
+from test.lib import TestBase, with_rw_directory, with_rw_repo
 
 
 class TestClone(TestBase):
@@ -29,3 +29,22 @@ class TestClone(TestBase):
             )
         else:
             self.fail("GitCommandError not raised")
+
+    @with_rw_repo("HEAD")
+    def test_clone_unsafe_options_are_checked_after_splitting_multi_options(self, rw_repo):
+        with tempfile.TemporaryDirectory() as tdir:
+            tmp_dir = pathlib.Path(tdir)
+            payload = "--single-branch --config protocol.ext.allow=always"
+
+            with self.assertRaises(UnsafeOptionError):
+                rw_repo.clone(tmp_dir, multi_options=[payload])
+
+    @with_rw_repo("HEAD")
+    def test_clone_from_unsafe_options_are_checked_after_splitting_multi_options(self, rw_repo):
+        with tempfile.TemporaryDirectory() as tdir:
+            tmp_dir = pathlib.Path(tdir)
+            payload = "--single-branch --config protocol.ext.allow=always"
+
+            with self.assertRaises(UnsafeOptionError):
+                Repo.clone_from(rw_repo.working_dir, tmp_dir, multi_options=[payload])
+
Index: GitPython-3.1.44/test/test_submodule.py
===================================================================
--- GitPython-3.1.44.orig/test/test_submodule.py
+++ GitPython-3.1.44/test/test_submodule.py
@@ -1311,6 +1311,17 @@ class TestSubmodule(TestBase):
                 assert not tmp_file.exists()
 
     @with_rw_repo("HEAD")
+    def test_submodule_update_unsafe_options_are_checked_after_splitting_multi_options(self, rw_repo):
+        with tempfile.TemporaryDirectory() as tdir:
+            tmp_dir = Path(tdir)
+            payload = "--single-branch --config protocol.ext.allow=always"
+            submodule = Submodule(rw_repo, b"\0" * 20, name="new", path="new", url=str(tmp_dir))
+
+            with self.assertRaises(UnsafeOptionError):
+                submodule.update(clone_multi_options=[payload])
+            assert not submodule.module_exists()
+
+    @with_rw_repo("HEAD")
     def test_submodule_update_unsafe_options_allowed(self, rw_repo):
         with tempfile.TemporaryDirectory() as tdir:
             tmp_dir = Path(tdir)
