From 919164df96d9f956c8be712f33a9a037b097745b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 16 Oct 2009 13:05:01 +0200 Subject: repo.untracked_files added including test --- lib/git/repo.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 554c10cb..6edb7f62 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -285,6 +285,37 @@ class Repo(object): return False return len(self.git.diff('HEAD', '--').strip()) > 0 + + @property + def untracked_files(self): + """ + Returns + list(str,...) + + Files currently untracked as they have not been staged yet. Paths + are relative to the current working directory of the git command. + + Note + ignored files will not appear here, i.e. files mentioned in .gitignore + """ + # make sure we get all files, no only untracked directores + proc = self.git.commit(untracked_files=True, as_process=True) + stream = iter(proc.stdout) + untracked_files = list() + for line in stream: + if not line.startswith("# Untracked files:"): + continue + # skip two lines + stream.next() + stream.next() + + for untracked_info in stream: + if not untracked_info.startswith("#\t"): + break + untracked_files.append(untracked_info.replace("#\t", "").rstrip()) + # END for each utracked info line + # END for each line + return untracked_files @property def active_branch(self): -- cgit v1.2.1 From bb24f67e64b4ebe11c4d3ce7df021a6ad7ca98f2 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 16 Oct 2009 16:09:07 +0200 Subject: Fixed object bug that would cause object ids not to be resolved to sha's as this was assumed - now there is a test for it as well repo: removed diff and commit_diff methods, added 'head' property returning the current head as Reference object --- lib/git/repo.py | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 6edb7f62..a77ced3c 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -106,6 +106,15 @@ class Repo(object): # alias heads branches = heads + @property + def head(self): + """ + Return + Head Object, reference pointing to the current head of the repository + """ + return Head(self,'HEAD') + + @property def tags(self): """ @@ -129,7 +138,7 @@ class Repo(object): if rev is None: rev = self.active_branch - c = Object(self, rev) + c = Object.new(self, rev) assert c.type == "commit", "Revision %s did not point to a commit, but to %s" % (rev, c) return c @@ -327,34 +336,7 @@ class Repo(object): """ return Head( self, self.git.symbolic_ref('HEAD').strip() ) - - def diff(self, a, b, *paths): - """ - The diff from commit ``a`` to commit ``b``, optionally restricted to the given file(s) - - ``a`` - is the base commit - ``b`` - is the other commit - - ``paths`` - is an optional list of file paths on which to restrict the diff - Returns - ``str`` - """ - return self.git.diff(a, b, '--', *paths) - - def commit_diff(self, commit): - """ - The commit diff for the given commit - ``commit`` is the commit name/id - - Returns - ``git.Diff[]`` - """ - return Commit.diff(self, commit) - def blame(self, rev, file): """ The blame information for the given file at the given revision. -- cgit v1.2.1 From 17852bde65c12c80170d4c67b3136d8e958a92a9 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 18 Oct 2009 12:50:11 +0200 Subject: repo: fixed untracked files function which used git-commit before, it can open vim to get a message though which makes the program appear to freeze - using git-status now --- lib/git/repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index a77ced3c..cc4a6c6b 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -308,7 +308,7 @@ class Repo(object): ignored files will not appear here, i.e. files mentioned in .gitignore """ # make sure we get all files, no only untracked directores - proc = self.git.commit(untracked_files=True, as_process=True) + proc = self.git.status(untracked_files=True, as_process=True) stream = iter(proc.stdout) untracked_files = list() for line in stream: -- cgit v1.2.1 From 9513aa01fab73f53e4fe18644c7d5b530a66c6a1 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Sun, 18 Oct 2009 23:15:55 +0200 Subject: Added frame for configuration reader involving a meta class, decorators and tests - most of which still has to be filled out --- lib/git/repo.py | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index cc4a6c6b..c53a4d9b 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -5,6 +5,7 @@ # the BSD License: http://www.opensource.org/licenses/bsd-license.php import os +import sys import re import gzip import StringIO @@ -15,7 +16,7 @@ from cmd import Git from actor import Actor from refs import * from objects import * - +from config import GitConfigParser class Repo(object): """ @@ -30,6 +31,10 @@ class Repo(object): re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$') re_author_committer_start = re.compile(r'^(author|committer)') re_tab_full_line = re.compile(r'^\t(.*)$') + + # invariants + # represents the configuration level of a configuration file + config_level = ("system", "global", "repository") def __init__(self, path=None): """ @@ -125,6 +130,52 @@ class Repo(object): """ return Tag.list_items(self) + def _get_config_path(self, config_level ): + # we do not support an absolute path of the gitconfig on windows , + # use the global config instead + if sys.platform == "win32" and config_level == "system": + config_level = "global" + + if config_level == "system": + return "/etc/gitconfig" + elif config_level == "global": + return os.path.expanduser("~/.gitconfig") + elif config_level == "repository": + return "%s/config" % self.git.git_dir + + raise ValueError( "Invalid configuration level: %r" % config_level ) + + @property + def config_reader(self): + """ + Returns + GitConfigParser allowing to read the full git configuration, but not to write it + + The configuration will include values from the system, user and repository + configuration files. + + NOTE: On windows, system configuration cannot currently be read as the path is + unknown, instead the global path will be used. + """ + files = [ self._get_config_path(f) for f in self.config_level ] + return GitConfigParser(files, read_only=True) + + def config_writer(self, config_level="repository"): + """ + Returns + GitConfigParser allowing to write values of the specified configuration file level. + Config writers should be retrieved, used to change the configuration ,and written + right away as they will lock the configuration file in question and prevent other's + to write it. + + ``config_level`` + One of the following values + system = sytem wide configuration file + global = user level configuration file + repository = configuration file for this repostory only + """ + return GitConfigParser(self._get_config_path(config_level), read_only = False) + def commit(self, rev=None): """ The Commit object for the specified revision -- cgit v1.2.1 From a07cdbae1d485fd715a5b6eca767f211770fea4d Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 18:06:19 +0200 Subject: Added remote module and test cases - about to implement remote option handling --- lib/git/repo.py | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index c53a4d9b..ddbedd0c 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -17,6 +17,7 @@ from actor import Actor from refs import * from objects import * from config import GitConfigParser +from remote import Remote class Repo(object): """ @@ -107,6 +108,13 @@ class Repo(object): ``git.Head[]`` """ return Head.list_items(self) + + @property + def remotes(self): + """ + A list of Remote objects allowing to access and manipulate remotes + """ + return Remote.list_items(self) # alias heads branches = heads -- cgit v1.2.1 From 048acc4596dc1c6d7ed3220807b827056cb01032 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 18:53:55 +0200 Subject: Added configuration access including tests to remote config: fixed issue that would cause it to abort reading if the file did not exist - this is valid now Test does not work as the configuration parsing does not work as expected - this must be fixed first --- lib/git/repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index ddbedd0c..d5cc9782 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -149,7 +149,7 @@ class Repo(object): elif config_level == "global": return os.path.expanduser("~/.gitconfig") elif config_level == "repository": - return "%s/config" % self.git.git_dir + return "%s/config" % self.path raise ValueError( "Invalid configuration level: %r" % config_level ) -- cgit v1.2.1 From 11b1f6edc164e2084e3ff034d3b65306c461a0be Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 22:08:23 +0200 Subject: repo.remote method added CHANGES updated to carry information about remotes and config --- lib/git/repo.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index d5cc9782..0a8592ab 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -115,6 +115,20 @@ class Repo(object): A list of Remote objects allowing to access and manipulate remotes """ return Remote.list_items(self) + + def remote(self, name='origin'): + """ + Return + Remote with the specified name + + Raise + ValueError if no remote with such a name exists + """ + for remote in Remote.iter_items(self): + if remote.name == name: + return remote + # END for each existing remote + raise ValueError( "Remote named %s does not exist" % name ) # alias heads branches = heads -- cgit v1.2.1 From 0b3ecf2dcace76b65765ddf1901504b0b4861b08 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 22:49:52 +0200 Subject: commit.count: is an instance method now repo: added head , tag and iter_trees methods for completeness changes: headlines now sorted chronologically --- lib/git/repo.py | 47 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 13 deletions(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 0a8592ab..c5b3d79b 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -108,6 +108,20 @@ class Repo(object): ``git.Head[]`` """ return Head.list_items(self) + + # alias heads + branches = heads + + @property + def head(self,path="HEAD"): + """ + Return + Head Object, reference pointing to commit + + ``path`` + path to the head or its name, i.e. master or heads/master + """ + return Head(self,path) @property def remotes(self): @@ -130,18 +144,6 @@ class Repo(object): # END for each existing remote raise ValueError( "Remote named %s does not exist" % name ) - # alias heads - branches = heads - - @property - def head(self): - """ - Return - Head Object, reference pointing to the current head of the repository - """ - return Head(self,'HEAD') - - @property def tags(self): """ @@ -150,7 +152,17 @@ class Repo(object): Returns ``git.Tag[]`` """ - return Tag.list_items(self) + return TagReference.list_items(self) + + def tag(self,path): + """ + Return + TagReference Object, reference pointing to a Commit or Tag + + ``path`` + path to the tag reference, i.e. 0.1.5 or tags/0.1.5 + """ + return TagReference(self, path) def _get_config_path(self, config_level ): # we do not support an absolute path of the gitconfig on windows , @@ -214,6 +226,15 @@ class Repo(object): c = Object.new(self, rev) assert c.type == "commit", "Revision %s did not point to a commit, but to %s" % (rev, c) return c + + def iter_trees(self, *args, **kwargs): + """ + Returns + Iterator yielding Tree objects + + Note: Takes all arguments known to iter_commits method + """ + return ( c.tree for c in self.iter_commits(*args, **kwargs) ) def tree(self, ref=None): """ -- cgit v1.2.1 From 989671780551b7587d57e1d7cb5eb1002ade75b4 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Mon, 19 Oct 2009 23:44:18 +0200 Subject: Implemneted IterableLists for refs, commits and remote objects including simple tests --- lib/git/repo.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index c5b3d79b..0f4be1b1 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -105,7 +105,7 @@ class Repo(object): this repo Returns - ``git.Head[]`` + ``git.IterableList(Head, ...)`` """ return Head.list_items(self) @@ -127,6 +127,9 @@ class Repo(object): def remotes(self): """ A list of Remote objects allowing to access and manipulate remotes + + Returns + ``git.IterableList(Remote, ...)`` """ return Remote.list_items(self) @@ -138,11 +141,7 @@ class Repo(object): Raise ValueError if no remote with such a name exists """ - for remote in Remote.iter_items(self): - if remote.name == name: - return remote - # END for each existing remote - raise ValueError( "Remote named %s does not exist" % name ) + return Remote(self, name) @property def tags(self): @@ -150,7 +149,7 @@ class Repo(object): A list of ``Tag`` objects that are available in this repo Returns - ``git.Tag[]`` + ``git.IterableList(TagReference, ...)`` """ return TagReference.list_items(self) -- cgit v1.2.1 From e64957d8e52d7542310535bad1e77a9bbd7b4857 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 00:04:10 +0200 Subject: Improved is_dirty including test --- lib/git/repo.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 0f4be1b1..8126bff4 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -370,23 +370,33 @@ class Repo(object): alternates = property(_get_alternates, _set_alternates, doc="Retrieve a list of alternates paths or set a list paths to be used as alternates") @property - def is_dirty(self): + def is_dirty(self, index=True, working_tree=True, untracked_files=False): """ - Return the status of the index. - Returns - ``True``, if the index has any uncommitted changes, - otherwise ``False`` - - NOTE - Working tree changes that have not been staged will not be detected ! + ``True``, the repository is considered dirty. By default it will react + like a git-status without untracked files, hence it is dirty if the + index or the working copy have changes. """ if self.bare: # Bare repositories with no associated working directory are # always consired to be clean. return False - - return len(self.git.diff('HEAD', '--').strip()) > 0 + + # start from the one which is fastest to evaluate + default_args = ('--abbrev=40', '--full-index', '--raw') + if index: + if len(self.git.diff('HEAD', '--cached', *default_args)): + return True + # END index handling + if working_tree: + if len(self.git.diff('HEAD', *default_args)): + return True + # END working tree handling + if untracked_files: + if len(self.untracked_files): + return True + # END untracked files + return False @property def untracked_files(self): -- cgit v1.2.1 From aa5e366889103172a9829730de1ba26d3dcbc01b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 10:11:16 +0200 Subject: Moved specialized methods like dashify, touch and is_git_dir to module to the respective modules that use them fixed repo.daemon_export which did not work anymore due to incorrect touch implementation and wrong property names --- lib/git/repo.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 8126bff4..966edf9d 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -11,7 +11,6 @@ import gzip import StringIO from errors import InvalidGitRepositoryError, NoSuchPathError -from utils import touch, is_git_dir from cmd import Git from actor import Actor from refs import * @@ -19,6 +18,23 @@ from objects import * from config import GitConfigParser from remote import Remote +def touch(filename): + fp = open(filename, "w") + fp.close() + +def is_git_dir(d): + """ This is taken from the git setup.c:is_git_directory + function.""" + + if os.path.isdir(d) and \ + os.path.isdir(os.path.join(d, 'objects')) and \ + os.path.isdir(os.path.join(d, 'refs')): + headref = os.path.join(d, 'HEAD') + return os.path.isfile(headref) or \ + (os.path.islink(headref) and + os.readlink(headref).startswith('refs')) + return False + class Repo(object): """ Represents a git repository and allows you to query references, -- cgit v1.2.1 From dd76b9e72b21d2502a51e3605e5e6ab640e5f0bd Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 10:45:40 +0200 Subject: Fixed bare repository handling - bare is now a property to prevent writing it --- lib/git/repo.py | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 966edf9d..3efefd9c 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -79,22 +79,30 @@ class Repo(object): self.path = None curpath = epath + + # walk up the path to find the .git dir while curpath: if is_git_dir(curpath): - self.bare = True self.path = curpath self.wd = curpath break gitpath = os.path.join(curpath, '.git') if is_git_dir(gitpath): - self.bare = False self.path = gitpath self.wd = curpath break curpath, dummy = os.path.split(curpath) if not dummy: break - + # END while curpath + + self._bare = False + try: + self._bare = self.config_reader("repository").getboolean('core','bare') + except Exception: + # lets not assume the option exists, although it should + pass + if self.path is None: raise InvalidGitRepositoryError(epath) @@ -113,6 +121,15 @@ class Repo(object): doc="the project's description") del _get_description del _set_description + + + @property + def bare(self): + """ + Returns + True if the repository is bare + """ + return self._bare @property def heads(self): @@ -194,8 +211,7 @@ class Repo(object): raise ValueError( "Invalid configuration level: %r" % config_level ) - @property - def config_reader(self): + def config_reader(self, config_level=None): """ Returns GitConfigParser allowing to read the full git configuration, but not to write it @@ -205,8 +221,18 @@ class Repo(object): NOTE: On windows, system configuration cannot currently be read as the path is unknown, instead the global path will be used. - """ - files = [ self._get_config_path(f) for f in self.config_level ] + + ``config_level`` + For possible values, see config_writer method + If None, all applicable levels will be used. Specify a level in case + you know which exact file you whish to read to prevent reading multiple files for + instance + """ + files = None + if config_level is None: + files = [ self._get_config_path(f) for f in self.config_level ] + else: + files = [ self._get_config_path(config_level) ] return GitConfigParser(files, read_only=True) def config_writer(self, config_level="repository"): @@ -393,7 +419,7 @@ class Repo(object): like a git-status without untracked files, hence it is dirty if the index or the working copy have changes. """ - if self.bare: + if self._bare: # Bare repositories with no associated working directory are # always consired to be clean. return False -- cgit v1.2.1 From 972a8b84bb4a3adec6322219c11370e48824404e Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 10:48:31 +0200 Subject: Added slots to Repo type to be sure we do not accidentally set values on it, and to be more efficient of course ;) TODO: Added info about possible config improvement --- lib/git/repo.py | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 3efefd9c..898b0f30 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -42,6 +42,7 @@ class Repo(object): the log. """ DAEMON_EXPORT_FILE = 'git-daemon-export-ok' + __slots__ = ( "wd", "path", "_bare", "git" ) # precompiled regex re_whitespace = re.compile(r'\s+') -- cgit v1.2.1 From 35a09c0534e89b2d43ec4101a5fb54576b577905 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 20 Oct 2009 11:17:39 +0200 Subject: repo.alternates test cheked for correctness and bugfixed - totally mocked tests bare the risk that things do not work properly outside of the sandbox. --- lib/git/repo.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 898b0f30..37847c98 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -394,21 +394,25 @@ class Repo(object): Raises NoSuchPathError + Note + The method does not check for the existance of the paths in alts + as the caller is responsible. + Returns None """ - for alt in alts: - if not os.path.exists(alt): - raise NoSuchPathError("Could not set alternates. Alternate path %s must exist" % alt) - + alternates_path = os.path.join(self.path, 'objects', 'info', 'alternates') if not alts: - os.remove(os.path.join(self.path, 'objects', 'info', 'alternates')) + if os.path.isfile(alternates_path): + os.remove(alternates_path) else: try: - f = open(os.path.join(self.path, 'objects', 'info', 'alternates'), 'w') + f = open(alternates_path, 'w') f.write("\n".join(alts)) finally: f.close() + # END file handling + # END alts handling alternates = property(_get_alternates, _set_alternates, doc="Retrieve a list of alternates paths or set a list paths to be used as alternates") -- cgit v1.2.1 From 6fcbda4e363262a339d1cacbf7d2945ec3bd83f0 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 21 Oct 2009 14:59:30 +0200 Subject: touch method improved to open for appending which would not clear the file and be like an actual touch --- lib/git/repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 37847c98..47b99ea4 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -19,7 +19,7 @@ from config import GitConfigParser from remote import Remote def touch(filename): - fp = open(filename, "w") + fp = open(filename, "a") fp.close() def is_git_dir(d): -- cgit v1.2.1 From 5e52a00c81d032b47f1bc352369be3ff8eb87b27 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 21 Oct 2009 17:00:40 +0200 Subject: repo.is_dirty: fixed incorrect check of a dirty working tree, previously it would compare HEAD against the working tree, not the index which was intended --- lib/git/repo.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 47b99ea4..956a3341 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -432,11 +432,13 @@ class Repo(object): # start from the one which is fastest to evaluate default_args = ('--abbrev=40', '--full-index', '--raw') if index: + # diff index against HEAD if len(self.git.diff('HEAD', '--cached', *default_args)): return True # END index handling if working_tree: - if len(self.git.diff('HEAD', *default_args)): + # diff index against working tree + if len(self.git.diff(*default_args)): return True # END working tree handling if untracked_files: -- cgit v1.2.1 From f62c9b9c0c9bda792c3fa531b18190e97eb53509 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 12:24:36 +0200 Subject: Git.cmd: removed with_raw_output option repo.archive: made it work with new way of custom output streams added test for repo.archive which was missing for some reason --- lib/git/repo.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 956a3341..b6624d8b 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -641,32 +641,23 @@ class Repo(object): Examples:: - >>> repo.archive(open("archive" + >>> repo.archive(open("archive")) - >>> repo.archive_tar_gz('a87ff14') - - - >>> repo.archive_tar_gz('master', 'myproject/') - - Raise GitCommandError in case something went wrong + Returns + self """ if treeish is None: treeish = self.active_branch if prefix and 'prefix' not in kwargs: kwargs['prefix'] = prefix - kwargs['as_process'] = True kwargs['output_stream'] = ostream - proc = self.git.archive(treeish, **kwargs) - status = proc.wait() - if status != 0: - raise GitCommandError( "git-archive", status, proc.stderr.read() ) - - + self.git.archive(treeish, **kwargs) + return self def __repr__(self): return '' % self.path -- cgit v1.2.1 From 58e2157ad3aa9d75ef4abb90eb2d1f01fba0ba2b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Thu, 22 Oct 2009 23:20:16 +0200 Subject: Added SymbolicReference and HEAD type to better represent these special types of references and allow special handling Head.reset now is an instance method of HEAD type Concatenated all reference specific tests into test_refs started to fix tests breaking now because of changed interface --- lib/git/repo.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index b6624d8b..94555a31 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -147,15 +147,12 @@ class Repo(object): branches = heads @property - def head(self,path="HEAD"): + def head(self): """ Return - Head Object, reference pointing to commit - - ``path`` - path to the head or its name, i.e. master or heads/master + HEAD Object pointing to the current head reference """ - return Head(self,path) + return HEAD(self,'HEAD') @property def remotes(self): @@ -486,8 +483,7 @@ class Repo(object): Returns Head to the active branch """ - return Head( self, self.git.symbolic_ref('HEAD').strip() ) - + return self.head.reference def blame(self, rev, file): """ -- cgit v1.2.1 From 3d3a24b22d340c62fafc0e75a349c0ffe34d99d7 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Fri, 23 Oct 2009 11:07:04 +0200 Subject: Added repo.index property including simple test, and additional ideas in the TODO list --- lib/git/repo.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 94555a31..569d6f1b 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -14,6 +14,7 @@ from errors import InvalidGitRepositoryError, NoSuchPathError from cmd import Git from actor import Actor from refs import * +from index import IndexFile from objects import * from config import GitConfigParser from remote import Remote @@ -145,6 +146,14 @@ class Repo(object): # alias heads branches = heads + + @property + def index(self): + """ + Returns + IndexFile representing this repository's index. + """ + return IndexFile(self) @property def head(self): -- cgit v1.2.1 From 685d6e651197d54e9a3e36f5adbadd4d21f4c7e5 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 18:41:35 +0100 Subject: Added repo.refs for completeness (as remote.refs is there as well and quite nice to use) --- lib/git/repo.py | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 569d6f1b..2383eb2a 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -143,6 +143,16 @@ class Repo(object): ``git.IterableList(Head, ...)`` """ return Head.list_items(self) + + @property + def refs(self): + """ + A list of Reference objects representing tags, heads and remote references. + + Returns + IterableList(Reference, ...) + """ + return Reference.list_items(self) # alias heads branches = heads -- cgit v1.2.1 From 8b5121414aaf2648b0e809e926d1016249c0222c Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 28 Oct 2009 22:17:39 +0100 Subject: Another attempt to make fetch emit progress information, but in fact its proven now that this is not happening if stderr is being redirected. A test is in place that will most likely fail in case this ever changes --- lib/git/repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 2383eb2a..d81106c0 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -625,7 +625,7 @@ class Repo(object): Create a clone from this repository. ``path`` - is the full path of the new repo (traditionally ends with /.git) + is the full path of the new repo (traditionally ends with ./.git). ``kwargs`` keyword arguments to be given to the git-clone command -- cgit v1.2.1 From 6bca9899b5edeed7f964e3124e382c3573183c68 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 15:20:28 +0100 Subject: repo.is_dirty: is a method now - the property based interface didn't allow all parameters to be used. The test would not test everything either, and I would consider this a bug that slipped through --- lib/git/repo.py | 1 - 1 file changed, 1 deletion(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index d81106c0..52469e04 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -432,7 +432,6 @@ class Repo(object): alternates = property(_get_alternates, _set_alternates, doc="Retrieve a list of alternates paths or set a list paths to be used as alternates") - @property def is_dirty(self, index=True, working_tree=True, untracked_files=False): """ Returns -- cgit v1.2.1 From dbc18b92362f60afc05d4ddadd6e73902ae27ec7 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 15:52:45 +0100 Subject: repo: added create_* and delete_* methods for refs ( head, tag, remote ) as a convenient shortcut to using the classes manually --- lib/git/repo.py | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 52469e04..9c3db055 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -213,6 +213,61 @@ class Repo(object): """ return TagReference(self, path) + def create_head(self, path, commit='HEAD', force=False, **kwargs ): + """ + Create a new head within the repository. + + For more documentation, please see the Head.create method. + + Returns + newly created Head Reference + """ + return Head.create(self, path, commit, force, **kwargs) + + def delete_head(self, *heads, **kwargs): + """ + Delete the given heads + + ``kwargs`` + Additional keyword arguments to be passed to git-branch + """ + return Head.delete(self, *heads, **kwargs) + + def create_tag(self, path, ref='HEAD', message=None, force=False, **kwargs): + """ + Create a new tag reference. + + For more documentation, please see the TagReference.create method. + + Returns + TagReference object + """ + return TagReference.create(self, path, ref, message, force, **kwargs) + + def delete_tag(self, *tags): + """ + Delete the given tag references + """ + return TagReference.delete(self, *tags) + + def create_remote(self, name, url, **kwargs): + """ + Create a new remote. + + For more information, please see the documentation of the Remote.create + methods + + Returns + Remote reference + """ + return Remote.create(self, name, url, **kwargs) + + def delete_remote(self, remote): + """ + Delete the given remote. + """ + return Remote.remove(self, remote) + def _get_config_path(self, config_level ): # we do not support an absolute path of the gitconfig on windows , # use the global config instead -- cgit v1.2.1 From 3cb5ba18ab1a875ef6b62c65342de476be47871b Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Tue, 3 Nov 2009 16:35:33 +0100 Subject: object: renamed id attribute to sha as it in fact is always being rewritten as sha, even if the passed in id was a ref. This is done to assure objects are uniquely identified and will compare correctly --- lib/git/repo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 9c3db055..41484aa0 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -622,7 +622,7 @@ class Repo(object): sha = info['id'] c = commits.get(sha) if c is None: - c = Commit( self, id=sha, + c = Commit( self, sha, author=Actor._from_string(info['author'] + ' ' + info['author_email']), authored_date=info['author_date'], committer=Actor._from_string(info['committer'] + ' ' + info['committer_email']), -- cgit v1.2.1 From f41d42ee7e264ce2fc32cea555e5f666fa1b1fe9 Mon Sep 17 00:00:00 2001 From: Sebastian Thiel Date: Wed, 4 Nov 2009 13:17:37 +0100 Subject: Improved cmd error handling in case an invalid revision is specified for an object repo.tree: improved to be less restricting --- lib/git/repo.py | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) (limited to 'lib/git/repo.py') diff --git a/lib/git/repo.py b/lib/git/repo.py index 41484aa0..6d388633 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -349,12 +349,12 @@ class Repo(object): """ return ( c.tree for c in self.iter_commits(*args, **kwargs) ) - def tree(self, ref=None): + def tree(self, rev=None): """ - The Tree object for the given treeish reference + The Tree object for the given treeish revision - ``ref`` - is a Ref instance defaulting to the active_branch if None. + ``rev`` + is a revision pointing to a Treeish ( being a commit or tree ) Examples:: @@ -364,32 +364,19 @@ class Repo(object): ``git.Tree`` NOTE - A ref is requried here to assure you point to a commit or tag. Otherwise - it is not garantueed that you point to the root-level tree. - If you need a non-root level tree, find it by iterating the root tree. Otherwise it cannot know about its path relative to the repository root and subsequent operations might have unexpected results. """ - if ref is None: - ref = self.active_branch - if not isinstance(ref, Reference): - raise ValueError( "Reference required, got %r" % ref ) - - - # As we are directly reading object information, we must make sure - # we truly point to a tree object. We resolve the ref to a sha in all cases - # to assure the returned tree can be compared properly. Except for - # heads, ids should always be hexshas - hexsha, typename, size = self.git.get_object_header( ref ) - if typename != "tree": - # will raise if this is not a valid tree - hexsha, typename, size = self.git.get_object_header( str(ref)+'^{tree}' ) - # END tree handling - ref = hexsha - - # the root has an empty relative path and the default mode - return Tree(self, ref, 0, '') + if rev is None: + rev = self.active_branch + + c = Object.new(self, rev) + if c.type == "commit": + return c.tree + elif c.type == "tree": + return c + raise ValueError( "Revision %s did not point to a treeish, but to %s" % (rev, c)) def iter_commits(self, rev=None, paths='', **kwargs): """ -- cgit v1.2.1