Skip to content

Commit 66beac6

Browse files
committed
Merge branch 'master' of git://gitorious.org/git-python/david into bisect
2 parents 93e1979 + 3980f11 commit 66beac6

File tree

3 files changed

+94
-40
lines changed

3 files changed

+94
-40
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
*~
44
/lib/GitPython.egg-info
55
/build
6+
/dist

lib/git/cmd.py

+81-33
Original file line numberDiff line numberDiff line change
@@ -12,46 +12,72 @@ class Git(MethodMissingMixin):
1212
"""
1313
The Git class manages communication with the Git binary
1414
"""
15-
def __init__(self, git_dir=None):
15+
def __init__(self, git_dir=None, bare_repo=False):
1616
super(Git, self).__init__()
1717
if git_dir:
18-
self.find_git_dir(git_dir)
18+
self._location = os.path.abspath(git_dir)
1919
else:
20-
self.find_git_dir(os.getcwd())
21-
22-
def find_git_dir(self, path):
23-
"""Find the best value for self.git_dir.
24-
For bare repositories, this is the path to the bare repository.
25-
For repositories with work trees, this is the work tree path.
26-
27-
When barerepo.git is passed in, self.git_dir = barerepo.git
28-
When worktree/.git is passed in, self.git_dir = worktree
29-
When worktree is passed in, self.git_dir = worktree
30-
"""
31-
32-
path = os.path.abspath(path)
33-
self.git_dir = path
34-
35-
cdup = self.execute(["git", "rev-parse", "--show-cdup"])
36-
if cdup:
37-
path = os.path.abspath(os.path.join(self.git_dir, cdup))
38-
else:
39-
is_bare_repository =\
40-
self.rev_parse(is_bare_repository=True) == "true"
41-
is_inside_git_dir =\
42-
self.rev_parse(is_inside_git_dir=True) == "true"
43-
44-
if not is_bare_repository and is_inside_git_dir:
45-
path = os.path.dirname(self.git_dir)
46-
47-
self.git_dir = path
20+
self._location = os.getcwd()
21+
self._is_bare_repo = bare_repo
22+
self.refresh()
23+
24+
def refresh(self):
25+
self._git_dir = None
26+
self._is_in_repo = not not self.get_git_dir()
27+
self._work_tree = None
28+
self._cwd = self._git_dir
29+
if self._git_dir and not self._is_bare_repo:
30+
self._cwd = self.get_work_tree()
31+
32+
def _is_git_dir(self, d):
33+
""" This is taken from the git setup.c:is_git_directory
34+
function."""
35+
36+
if os.path.isdir(d) and \
37+
os.path.isdir(os.path.join(d, 'objects')) and \
38+
os.path.isdir(os.path.join(d, 'refs')):
39+
headref = os.path.join(d, 'HEAD')
40+
return os.path.isfile(headref) or \
41+
(os.path.islink(headref) and
42+
os.readlink(headref).startswith('refs'))
43+
return False
44+
45+
def get_git_dir(self):
46+
if not self._git_dir:
47+
self._git_dir = os.getenv('GIT_DIR')
48+
if self._git_dir and self._is_git_dir(self._git_dir):
49+
return self._git_dir
50+
curpath = self._location
51+
while curpath:
52+
if self._is_git_dir(curpath):
53+
self._git_dir = curpath
54+
break
55+
gitpath = os.path.join(curpath, '.git')
56+
if self._is_git_dir(gitpath):
57+
self._git_dir = gitpath
58+
break
59+
curpath, dummy = os.path.split(curpath)
60+
if not dummy:
61+
break
62+
return self._git_dir
63+
64+
def get_work_tree(self):
65+
if self._is_bare_repo:
66+
return None
67+
if not self._work_tree:
68+
self._work_tree = os.getenv('GIT_WORK_TREE')
69+
if not self._work_tree or not os.path.isdir(self._work_tree):
70+
self._work_tree = os.path.abspath(
71+
os.path.join(self._git_dir, '..'))
72+
return self._work_tree
4873

4974
@property
5075
def get_dir(self):
51-
return self.git_dir
76+
return self._git_dir
5277

5378
def execute(self, command,
5479
istream=None,
80+
keep_cwd=False,
5581
with_status=False,
5682
with_stderr=False,
5783
with_exceptions=False,
@@ -67,6 +93,11 @@ def execute(self, command,
6793
``istream``
6894
Standard input filehandle passed to subprocess.Popen.
6995
96+
``keep_cwd``
97+
Whether to use the current working directory from os.getcwd().
98+
GitPython uses get_work_tree() as its working directory by
99+
default and get_git_dir() for bare repositories.
100+
70101
``with_status``
71102
Whether to return a (status, str) tuple.
72103
@@ -94,9 +125,15 @@ def execute(self, command,
94125
else:
95126
stderr = subprocess.PIPE
96127

128+
# Allow the user to have the command executed in their working dir.
129+
if keep_cwd:
130+
cwd = os.getcwd()
131+
else:
132+
cwd=self._cwd
133+
97134
# Start the process
98135
proc = subprocess.Popen(command,
99-
cwd=self.git_dir,
136+
cwd=cwd,
100137
stdin=istream,
101138
stderr=stderr,
102139
stdout=subprocess.PIPE
@@ -107,6 +144,10 @@ def execute(self, command,
107144
status = proc.wait()
108145
proc.stdout.close()
109146

147+
if proc.stderr:
148+
stderr_value = proc.stderr.read()
149+
proc.stderr.close()
150+
110151
# Strip off trailing whitespace by default
111152
if not with_raw_output:
112153
stdout_value = stdout_value.rstrip()
@@ -118,7 +159,12 @@ def execute(self, command,
118159
% (str(command), status))
119160

120161
if GIT_PYTHON_TRACE == 'full':
121-
print "%s %d: '%s'" % (command, status, stdout_value)
162+
if stderr_value:
163+
print "%s -> %d: '%s' !! '%s'" % (command, status, stdout_value, stderr_value)
164+
elif stdout_value:
165+
print "%s -> %d: '%s'" % (command, status, stdout_value)
166+
else:
167+
print "%s -> %d" % (command, status)
122168

123169
# Allow access to the command's status code
124170
if with_status:
@@ -170,6 +216,7 @@ def method_missing(self, method, *args, **kwargs):
170216
# Handle optional arguments prior to calling transform_kwargs
171217
# otherwise these'll end up in args, which is bad.
172218
istream = kwargs.pop("istream", None)
219+
keep_cwd = kwargs.pop("keep_cwd", None)
173220
with_status = kwargs.pop("with_status", None)
174221
with_stderr = kwargs.pop("with_stderr", None)
175222
with_exceptions = kwargs.pop("with_exceptions", None)
@@ -185,6 +232,7 @@ def method_missing(self, method, *args, **kwargs):
185232

186233
return self.execute(call,
187234
istream = istream,
235+
keep_cwd = keep_cwd,
188236
with_status = with_status,
189237
with_stderr = with_stderr,
190238
with_exceptions = with_exceptions,

lib/git/repo.py

+12-7
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
class Repo(object):
1313
DAEMON_EXPORT_FILE = 'git-daemon-export-ok'
1414

15-
def __init__(self, path):
15+
def __init__(self, path=None):
1616
"""
1717
Create a new Repo instance
1818
@@ -27,19 +27,24 @@ def __init__(self, path):
2727
Returns
2828
``GitPython.Repo``
2929
"""
30-
epath = os.path.abspath(path)
30+
if not os.path.exists(path):
31+
raise NoSuchPathError(path)
32+
33+
self.git = Git(path)
34+
self.path = self.git.get_git_dir()
35+
if not self.path:
36+
raise InvalidGitRepositoryError(path)
37+
epath = self.git.get_work_tree()
3138

3239
if os.path.exists(os.path.join(epath, '.git')):
33-
self.path = os.path.join(epath, '.git')
3440
self.bare = False
35-
elif os.path.exists(epath) and re.search('\.git$', epath):
36-
self.path = epath
41+
elif os.path.exists(epath) and epath.endswith('.git'):
3742
self.bare = True
3843
elif os.path.exists(epath):
3944
raise InvalidGitRepositoryError(epath)
4045
else:
4146
raise NoSuchPathError(epath)
42-
self.git = Git(self.path)
47+
4348

4449
@property
4550
def description(self):
@@ -275,7 +280,7 @@ def init_bare(self, path, mkdir=True, **kwargs):
275280
if mkdir and not os.path.exists(path):
276281
os.makedirs(path, 0755)
277282

278-
git = Git(path)
283+
git = Git(path, bare_repo=True)
279284
output = git.init(**kwargs)
280285
return Repo(path)
281286
create = init_bare

0 commit comments

Comments
 (0)