@@ -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 ,
0 commit comments