Repository: gitpython-developers/GitPython
Pull request #536 (2016-10-18 13:20:29)

Allow for setting git options, that are persistent across subcommand calls
Currently `_git_options` in class `Git` are reset after each subcommand call. While this is appropriate in most cases, I'm in need to have options for the git executable, that are used with all calls to git on a certain repository and I can't provide this option for each and every call. Therefore I'd like to introduce the possibility to persistently set such options for a given instance of `Git`.

This is my first PR here, so I'm not exactly sure, what you want me to provide. `CONTRIBUTING.md` reads: "Write a test that fails unless your patch is present." 
Where am I supposed to put such a test?
Just add it to `git/test/test_git.py`?



Patch:
diff --git a/git/cmd.py b/git/cmd.py
index f0757301..1481ac81 100644
--- a/git/cmd.py
+++ b/git/cmd.py
@@ -161,7 +161,7 @@ class Git(LazyMixin):
         Set its value to 'full' to see details about the returned values.
     """
     __slots__ = ("_working_dir", "cat_file_all", "cat_file_header", "_version_info",
-                 "_git_options", "_environment")
+                 "_git_options", "_persistent_git_options", "_environment")
 
     _excluded_ = ('cat_file_all', 'cat_file_header', '_version_info')
 
@@ -386,6 +386,7 @@ class Git(LazyMixin):
         super(Git, self).__init__()
         self._working_dir = working_dir
         self._git_options = ()
+        self._persistent_git_options = []
 
         # Extra environment variables to pass to git commands
         self._environment = {}
@@ -402,6 +403,20 @@ class Git(LazyMixin):
             return LazyMixin.__getattr__(self, name)
         return lambda *args, **kwargs: self._call_process(name, *args, **kwargs)
 
+    def set_persistent_git_options(self, **kwargs):
+        """Specify command line options to the git executable
+        for subsequent subcommand calls
+
+        :param kwargs:
+            is a dict of keyword arguments.
+            these arguments are passed as in _call_process
+            but will be passed to the git command rather than
+            the subcommand.
+        """
+
+        self._persistent_git_options = self.transform_kwargs(
+            split_single_char_options=True, **kwargs)
+
     def _set_cache_(self, attr):
         if attr == '_version_info':
             # We only use the first 4 numbers, as everthing else could be strings in fact (on windows)
@@ -820,7 +835,10 @@ class Git(LazyMixin):
 
         call = [self.GIT_PYTHON_GIT_EXECUTABLE]
 
-        # add the git options, the reset to empty
+        # add persistent git options
+        call.extend(self._persistent_git_options)
+
+        # add the git options, then reset to empty
         # to avoid side_effects
         call.extend(self._git_options)
         self._git_options = ()


Test patch:
diff --git a/git/test/test_git.py b/git/test/test_git.py
index bd8ebee2..14c70e18 100644
--- a/git/test/test_git.py
+++ b/git/test/test_git.py
@@ -160,6 +160,20 @@ class TestGit(TestBase):
         git_command_version = self.git.version()
         self.assertEquals(git_version, git_command_version)
 
+    def test_persistent_options(self):
+        git_command_version = self.git.version()
+        # analog to test_options_are_passed_to_git
+        self.git.set_persistent_git_options(version=True)
+        git_version = self.git.NoOp()
+        self.assertEquals(git_version, git_command_version)
+        # subsequent calls keep this option:
+        git_version_2 = self.git.NoOp()
+        self.assertEquals(git_version_2, git_command_version)
+
+        # reset to empty:
+        self.git.set_persistent_git_options()
+        self.assertRaises(GitCommandError, self.git.NoOp)
+
     def test_single_char_git_options_are_passed_to_git(self):
         input_value = 'TestValue'
         output_value = self.git(c='user.name=%s' % input_value).config('--get', 'user.name')