@@ -41,9 +41,19 @@ class Repo(object):
4141Represents a git repository and allows you to query references,
4242gather commit information, generate diffs, create and clone repositories query
4343the log.
44+
45+ The following attributes are worth using:
46+
47+ 'working_dir' is the working directory of the git command, wich is the working tree
48+ directory if available or the .git directory in case of bare repositories
49+
50+ 'working_tree_dir' is the working tree directory, but will raise AssertionError
51+ if we are a bare repository.
52+
53+ 'git_dir' is the .git repository directoy, which is always set.
4454"""
4555DAEMON_EXPORT_FILE = 'git-daemon-export-ok'
46- __slots__ = ("wd " ,"path " ,"_bare" ,"git" )
56+ __slots__ = ("working_dir " ,"_working_tree_dir" , "git_dir " ,"_bare" ,"git" )
4757
4858# precompiled regex
4959re_whitespace = re .compile (r'\s+' )
@@ -81,26 +91,28 @@ def __init__(self, path=None):
8191if not os .path .exists (epath ):
8292raise NoSuchPathError (epath )
8393
84- self .path = None
94+ self .working_dir = None
95+ self ._working_tree_dir = None
96+ self .git_dir = None
8597curpath = epath
8698
8799# walk up the path to find the .git dir
88100while curpath :
89101if is_git_dir (curpath ):
90- self .path = curpath
91- self .wd = os .path .dirname (curpath )
102+ self .git_dir = curpath
103+ self ._working_tree_dir = os .path .dirname (curpath )
92104break
93105gitpath = os .path .join (curpath ,'.git' )
94106if is_git_dir (gitpath ):
95- self .path = gitpath
96- self .wd = curpath
107+ self .git_dir = gitpath
108+ self ._working_tree_dir = curpath
97109break
98110curpath ,dummy = os .path .split (curpath )
99111if not dummy :
100112break
101113# END while curpath
102114
103- if self .path is None :
115+ if self .git_dir is None :
104116raise InvalidGitRepositoryError (epath )
105117
106118self ._bare = False
@@ -113,24 +125,38 @@ def __init__(self, path=None):
113125# adjust the wd in case we are actually bare - we didn't know that
114126# in the first place
115127if self ._bare :
116- self .wd = self .path
117-
118- self .git = Git (self .wd )
128+ self ._working_tree_dir = None
129+ # END working dir handling
130+
131+ self .working_dir = self ._working_tree_dir or self .git_dir
132+ self .git = Git (self .working_dir )
119133
120134# Description property
121135def _get_description (self ):
122- filename = os .path .join (self .path ,'description' )
136+ filename = os .path .join (self .git_dir ,'description' )
123137return file (filename ).read ().rstrip ()
124138
125139def _set_description (self ,descr ):
126- filename = os .path .join (self .path ,'description' )
140+ filename = os .path .join (self .git_dir ,'description' )
127141file (filename ,'w' ).write (descr + '\n ' )
128142
129143description = property (_get_description ,_set_description ,
130144doc = "the project's description" )
131145del _get_description
132146del _set_description
133147
148+ @property
149+ def working_tree_dir (self ):
150+ """
151+ Returns
152+ The working tree directory of our git repository
153+
154+ Raises AssertionError
155+ If we are a bare repository
156+ """
157+ if self ._working_tree_dir is None :
158+ raise AssertionError ("Repository at %r is bare and does not have a working tree directory" % self .git_dir )
159+ return self ._working_tree_dir
134160
135161@property
136162def bare (self ):
@@ -286,7 +312,7 @@ def _get_config_path(self, config_level ):
286312elif config_level == "global" :
287313return os .path .expanduser ("~/.gitconfig" )
288314elif config_level == "repository" :
289- return "%s/config" % self .path
315+ return "%s/config" % self .git_dir
290316
291317raise ValueError ("Invalid configuration level: %r" % config_level )
292318
@@ -413,11 +439,11 @@ def iter_commits(self, rev=None, paths='', **kwargs):
413439return Commit .iter_items (self ,rev ,paths ,** kwargs )
414440
415441def _get_daemon_export (self ):
416- filename = os .path .join (self .path ,self .DAEMON_EXPORT_FILE )
442+ filename = os .path .join (self .git_dir ,self .DAEMON_EXPORT_FILE )
417443return os .path .exists (filename )
418444
419445def _set_daemon_export (self ,value ):
420- filename = os .path .join (self .path ,self .DAEMON_EXPORT_FILE )
446+ filename = os .path .join (self .git_dir ,self .DAEMON_EXPORT_FILE )
421447fileexists = os .path .exists (filename )
422448if value and not fileexists :
423449touch (filename )
@@ -436,7 +462,7 @@ def _get_alternates(self):
436462Returns
437463list of strings being pathnames of alternates
438464"""
439- alternates_path = os .path .join (self .path ,'objects' ,'info' ,'alternates' )
465+ alternates_path = os .path .join (self .git_dir ,'objects' ,'info' ,'alternates' )
440466
441467if os .path .exists (alternates_path ):
442468try :
@@ -466,7 +492,7 @@ def _set_alternates(self, alts):
466492Returns
467493None
468494"""
469- alternates_path = os .path .join (self .path ,'objects' ,'info' ,'alternates' )
495+ alternates_path = os .path .join (self .git_dir ,'objects' ,'info' ,'alternates' )
470496if not alts :
471497if os .path .isfile (alternates_path ):
472498os .remove (alternates_path )
@@ -706,7 +732,7 @@ def clone(self, path, **kwargs):
706732# END windows handling
707733
708734try :
709- self .git .clone (self .path ,path ,** kwargs )
735+ self .git .clone (self .git_dir ,path ,** kwargs )
710736finally :
711737if prev_cwd is not None :
712738os .chdir (prev_cwd )
@@ -754,4 +780,4 @@ def archive(self, ostream, treeish=None, prefix=None, **kwargs):
754780return self
755781
756782def __repr__ (self ):
757- return '<git.Repo "%s">' % self .path
783+ return '<git.Repo "%s">' % self .git_dir