Skip to content

Commit 76ac61a

Browse files
committed
Merge with latest branch 'exp_git_dir'
Conflicts: git/repo/base.py git/repo/fun.py git/test/test_submodule.py
2 parents cc77e6b + 9d5d143 commit 76ac61a

File tree

5 files changed

+74
-46
lines changed

5 files changed

+74
-46
lines changed

git/cmd.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class Git(LazyMixin):
162162
Set its value to 'full' to see details about the returned values.
163163
"""
164164
__slots__ = ("_working_dir", "cat_file_all", "cat_file_header", "_version_info",
165-
"_git_options", "_environment")
165+
"_git_options", "_persistent_git_options", "_environment")
166166

167167
_excluded_ = ('cat_file_all', 'cat_file_header', '_version_info')
168168

@@ -405,6 +405,7 @@ def __init__(self, working_dir=None):
405405
super(Git, self).__init__()
406406
self._working_dir = working_dir
407407
self._git_options = ()
408+
self._persistent_git_options = []
408409

409410
# Extra environment variables to pass to git commands
410411
self._environment = {}
@@ -421,6 +422,20 @@ def __getattr__(self, name):
421422
return LazyMixin.__getattr__(self, name)
422423
return lambda *args, **kwargs: self._call_process(name, *args, **kwargs)
423424

425+
def set_persistent_git_options(self, **kwargs):
426+
"""Specify command line options to the git executable
427+
for subsequent subcommand calls
428+
429+
:param kwargs:
430+
is a dict of keyword arguments.
431+
these arguments are passed as in _call_process
432+
but will be passed to the git command rather than
433+
the subcommand.
434+
"""
435+
436+
self._persistent_git_options = self.transform_kwargs(
437+
split_single_char_options=True, **kwargs)
438+
424439
def _set_cache_(self, attr):
425440
if attr == '_version_info':
426441
# We only use the first 4 numbers, as everthing else could be strings in fact (on windows)
@@ -839,7 +854,10 @@ def _call_process(self, method, *args, **kwargs):
839854

840855
call = [self.GIT_PYTHON_GIT_EXECUTABLE]
841856

842-
# add the git options, the reset to empty
857+
# add persistent git options
858+
call.extend(self._persistent_git_options)
859+
860+
# add the git options, then reset to empty
843861
# to avoid side_effects
844862
call.extend(self._git_options)
845863
self._git_options = ()

git/repo/base.py

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,9 @@
3030
from git.refs import HEAD, Head, Reference, TagReference
3131
from git.remote import Remote, add_progress, to_progress_instance
3232
from git.util import Actor, finalize_process, decygpath, hex_to_bin
33-
3433
import os.path as osp
3534

36-
from .fun import rev_parse, is_git_dir, find_git_dir, touch
35+
from .fun import rev_parse, is_git_dir, find_submodule_git_dir, touch
3736

3837

3938
log = logging.getLogger(__name__)
@@ -50,7 +49,7 @@
5049

5150

5251
def _expand_path(p):
53-
return osp.abspath(osp.expandvars(osp.expanduser(p)))
52+
return osp.normpath(osp.abspath(osp.expandvars(osp.expanduser(p))))
5453

5554

5655
class Repo(object):
@@ -69,6 +68,11 @@ class Repo(object):
6968
'git_dir' is the .git repository directory, which is always set."""
7069
DAEMON_EXPORT_FILE = 'git-daemon-export-ok'
7170

71+
git = None # Must exist, or __del__ will fail in case we raise on `__init__()`
72+
working_dir = None
73+
_working_tree_dir = None
74+
git_dir = None
75+
7276
# precompiled regex
7377
re_whitespace = re.compile(r'\s+')
7478
re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$')
@@ -95,8 +99,9 @@ def __init__(self, path=None, odbt=DefaultDBType, search_parent_directories=Fals
9599
repo = Repo("~/Development/git-python.git")
96100
repo = Repo("$REPOSITORIES/Development/git-python.git")
97101
98-
In *Cygwin*, path may be a `'cygdrive/...'` prefixed path.
99-
102+
- In *Cygwin*, path may be a `'cygdrive/...'` prefixed path.
103+
- If `None, current-directory is used.
104+
- The :envvar:`GIT_DIR` if set and not empty takes precendance over this parameter.
100105
:param odbt:
101106
Object DataBase type - a type which is constructed by providing
102107
the directory containing the database objects, i.e. .git/objects. It will
@@ -109,40 +114,39 @@ def __init__(self, path=None, odbt=DefaultDBType, search_parent_directories=Fals
109114
:raise InvalidGitRepositoryError:
110115
:raise NoSuchPathError:
111116
:return: git.Repo """
117+
epath = os.getenv('GIT_DIR') or path or os.getcwd()
112118
if Git.is_cygwin():
113-
path = decygpath(path)
114-
115-
epath = _expand_path(path or os.getcwd())
116-
self.git = None # should be set for __del__ not to fail in case we raise
117-
if not osp.exists(epath):
119+
epath = decygpath(epath)
120+
epath = _expand_path(epath or path or os.getcwd())
121+
if not os.path.exists(epath):
118122
raise NoSuchPathError(epath)
119123

120-
self.working_dir = None
121-
self._working_tree_dir = None
122-
self.git_dir = None
123-
curpath = os.getenv('GIT_DIR', epath)
124-
125-
# walk up the path to find the .git dir
124+
## Walk up the path to find the `.git` dir.
125+
#
126+
curpath = epath
126127
while curpath:
127128
# ABOUT osp.NORMPATH
128129
# It's important to normalize the paths, as submodules will otherwise initialize their
129130
# repo instances with paths that depend on path-portions that will not exist after being
130131
# removed. It's just cleaner.
131132
if is_git_dir(curpath):
132-
self.git_dir = osp.normpath(curpath)
133-
self._working_tree_dir = osp.dirname(self.git_dir)
133+
self.git_dir = curpath
134+
self._working_tree_dir = os.path.dirname(self.git_dir)
134135
break
135136

136-
gitpath = find_git_dir(osp.join(curpath, '.git'))
137-
if gitpath is not None:
138-
self.git_dir = osp.normpath(gitpath)
137+
sm_gitpath = find_submodule_git_dir(osp.join(curpath, '.git'))
138+
if sm_gitpath is not None:
139+
self.git_dir = osp.normpath(sm_gitpath)
140+
sm_gitpath = find_submodule_git_dir(osp.join(curpath, '.git'))
141+
if sm_gitpath is not None:
142+
self.git_dir = _expand_path(sm_gitpath)
139143
self._working_tree_dir = curpath
140144
break
141145

142146
if not search_parent_directories:
143147
break
144-
curpath, dummy = osp.split(curpath)
145-
if not dummy:
148+
curpath, tail = osp.split(curpath)
149+
if not tail:
146150
break
147151
# END while curpath
148152

git/repo/fun.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
from git.cmd import Git
1717

1818

19-
__all__ = ('rev_parse', 'is_git_dir', 'touch', 'find_git_dir', 'name_to_object', 'short_to_long', 'deref_tag',
19+
__all__ = ('rev_parse', 'is_git_dir', 'touch', 'find_submodule_git_dir', 'name_to_object', 'short_to_long', 'deref_tag',
2020
'to_commit')
2121

2222

@@ -47,7 +47,8 @@ def is_git_dir(d):
4747
return False
4848

4949

50-
def find_git_dir(d):
50+
def find_submodule_git_dir(d):
51+
"""Search for a submodule repo."""
5152
if is_git_dir(d):
5253
return d
5354

@@ -60,12 +61,13 @@ def find_git_dir(d):
6061
else:
6162
if content.startswith('gitdir: '):
6263
path = content[8:]
64+
6365
if Git.is_cygwin():
6466
## Cygwin creates submodules prefixed with `/cygdrive/...` suffixes.
6567
path = decygpath(path)
6668
if not osp.isabs(path):
6769
path = osp.join(osp.dirname(d), path)
68-
return find_git_dir(path)
70+
return find_submodule_git_dir(path)
6971
# end handle exception
7072
return None
7173

git/test/test_git.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,20 @@ def test_options_are_passed_to_git(self):
162162
git_command_version = self.git.version()
163163
self.assertEquals(git_version, git_command_version)
164164

165+
def test_persistent_options(self):
166+
git_command_version = self.git.version()
167+
# analog to test_options_are_passed_to_git
168+
self.git.set_persistent_git_options(version=True)
169+
git_version = self.git.NoOp()
170+
self.assertEquals(git_version, git_command_version)
171+
# subsequent calls keep this option:
172+
git_version_2 = self.git.NoOp()
173+
self.assertEquals(git_version_2, git_command_version)
174+
175+
# reset to empty:
176+
self.git.set_persistent_git_options()
177+
self.assertRaises(GitCommandError, self.git.NoOp)
178+
165179
def test_single_char_git_options_are_passed_to_git(self):
166180
input_value = 'TestValue'
167181
output_value = self.git(c='user.name=%s' % input_value).config('--get', 'user.name')

git/test/test_submodule.py

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,34 +7,24 @@
77

88
import git
99
from git.cmd import Git
10-
from git.compat import (
11-
string_types,
12-
is_win,
13-
)
10+
from git.compat import string_types, is_win
1411
from git.exc import (
1512
InvalidGitRepositoryError,
1613
RepositoryDirtyError
1714
)
1815
from git.objects.submodule.base import Submodule
19-
from git.objects.submodule.root import (
20-
RootModule,
21-
RootUpdateProgress,
22-
)
16+
from git.objects.submodule.root import RootModule, RootUpdateProgress
2317
from git.repo.fun import (
24-
find_git_dir,
25-
touch,
18+
find_submodule_git_dir,
19+
touch
2620
)
2721
from git.test.lib import (
2822
TestBase,
29-
with_rw_repo,
23+
with_rw_repo
3024
)
3125
from git.test.lib import with_rw_directory
32-
from git.util import (
33-
to_native_path_linux,
34-
join_path_native,
35-
HIDE_WINDOWS_KNOWN_ERRORS,
36-
)
37-
26+
from git.util import HIDE_WINDOWS_KNOWN_ERRORS
27+
from git.util import to_native_path_linux, join_path_native
3828
import os.path as osp
3929

4030

@@ -775,7 +765,7 @@ def assert_exists(sm, value=True):
775765
else:
776766
assert osp.isfile(module_repo_path)
777767
assert sm.module().has_separate_working_tree()
778-
assert find_git_dir(module_repo_path) is not None, "module pointed to by .git file must be valid"
768+
assert find_submodule_git_dir(module_repo_path) is not None, "module pointed to by .git file must be valid"
779769
# end verify submodule 'style'
780770

781771
# test move

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy