@@ -12,46 +12,72 @@ class Git(MethodMissingMixin):
12
12
"""
13
13
The Git class manages communication with the Git binary
14
14
"""
15
- def __init__ (self , git_dir = None ):
15
+ def __init__ (self , git_dir = None , bare_repo = False ):
16
16
super (Git , self ).__init__ ()
17
17
if git_dir :
18
- self .find_git_dir (git_dir )
18
+ self ._location = os . path . abspath (git_dir )
19
19
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
48
73
49
74
@property
50
75
def get_dir (self ):
51
- return self .git_dir
76
+ return self ._git_dir
52
77
53
78
def execute (self , command ,
54
79
istream = None ,
80
+ keep_cwd = False ,
55
81
with_status = False ,
56
82
with_stderr = False ,
57
83
with_exceptions = False ,
@@ -67,6 +93,11 @@ def execute(self, command,
67
93
``istream``
68
94
Standard input filehandle passed to subprocess.Popen.
69
95
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
+
70
101
``with_status``
71
102
Whether to return a (status, str) tuple.
72
103
@@ -94,9 +125,15 @@ def execute(self, command,
94
125
else :
95
126
stderr = subprocess .PIPE
96
127
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
+
97
134
# Start the process
98
135
proc = subprocess .Popen (command ,
99
- cwd = self . git_dir ,
136
+ cwd = cwd ,
100
137
stdin = istream ,
101
138
stderr = stderr ,
102
139
stdout = subprocess .PIPE
@@ -107,6 +144,10 @@ def execute(self, command,
107
144
status = proc .wait ()
108
145
proc .stdout .close ()
109
146
147
+ if proc .stderr :
148
+ stderr_value = proc .stderr .read ()
149
+ proc .stderr .close ()
150
+
110
151
# Strip off trailing whitespace by default
111
152
if not with_raw_output :
112
153
stdout_value = stdout_value .rstrip ()
@@ -118,7 +159,12 @@ def execute(self, command,
118
159
% (str (command ), status ))
119
160
120
161
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 )
122
168
123
169
# Allow access to the command's status code
124
170
if with_status :
@@ -170,6 +216,7 @@ def method_missing(self, method, *args, **kwargs):
170
216
# Handle optional arguments prior to calling transform_kwargs
171
217
# otherwise these'll end up in args, which is bad.
172
218
istream = kwargs .pop ("istream" , None )
219
+ keep_cwd = kwargs .pop ("keep_cwd" , None )
173
220
with_status = kwargs .pop ("with_status" , None )
174
221
with_stderr = kwargs .pop ("with_stderr" , None )
175
222
with_exceptions = kwargs .pop ("with_exceptions" , None )
@@ -185,6 +232,7 @@ def method_missing(self, method, *args, **kwargs):
185
232
186
233
return self .execute (call ,
187
234
istream = istream ,
235
+ keep_cwd = keep_cwd ,
188
236
with_status = with_status ,
189
237
with_stderr = with_stderr ,
190
238
with_exceptions = with_exceptions ,
0 commit comments