summaryrefslogtreecommitdiff
path: root/lib/git
diff options
context:
space:
mode:
Diffstat (limited to 'lib/git')
-rw-r--r--lib/git/commit.py30
-rw-r--r--lib/git/diff.py72
-rw-r--r--lib/git/repo.py48
3 files changed, 80 insertions, 70 deletions
diff --git a/lib/git/commit.py b/lib/git/commit.py
index 057530a6..091cf78c 100644
--- a/lib/git/commit.py
+++ b/lib/git/commit.py
@@ -41,7 +41,7 @@ class Commit(LazyMixin):
is the committed DateTime
``message``
- is the first line of the commit message
+ is the commit message
``parents``
is the list of the parents of the commit
@@ -81,8 +81,12 @@ class Commit(LazyMixin):
def id_abbrev(self):
return self.id[0:7]
+ @property
+ def summary(self):
+ return self.message.split('\n', 1)[0]
+
@classmethod
- def count(cls, repo, ref):
+ def count(cls, repo, ref, path=''):
"""
Count the number of commits reachable from this ref
@@ -92,13 +96,16 @@ class Commit(LazyMixin):
``ref``
is the ref from which to begin (SHA1 or name)
+ ``path``
+ is an optinal path
+
Returns
int
"""
- return len(repo.git.rev_list(ref).strip().splitlines())
+ return len(repo.git.rev_list(ref, '--', path).strip().splitlines())
@classmethod
- def find_all(cls, repo, ref, **kwargs):
+ def find_all(cls, repo, ref, path='', **kwargs):
"""
Find all commits matching the given criteria.
``repo``
@@ -107,6 +114,9 @@ class Commit(LazyMixin):
``ref``
is the ref from which to begin (SHA1 or name)
+ ``path``
+ is an optinal path
+
``options``
is a Hash of optional arguments to git where
``max_count`` is the maximum number of commits to fetch
@@ -118,7 +128,7 @@ class Commit(LazyMixin):
options = {'pretty': 'raw'}
options.update(kwargs)
- output = repo.git.rev_list(ref, **options)
+ output = repo.git.rev_list(ref, '--', path, **options)
return cls.list_from_string(repo, output)
@classmethod
@@ -153,7 +163,7 @@ class Commit(LazyMixin):
while lines and lines[0].startswith(' '):
messages.append(lines.pop(0).strip())
- message = messages and messages[0] or ''
+ message = '\n'.join(messages)
commits.append(Commit(repo, id=id, parents=parents, tree=tree, author=author, authored_date=authored_date,
committer=committer, committed_date=committed_date, message=message))
@@ -194,13 +204,13 @@ class Commit(LazyMixin):
if b:
paths.insert(0, b)
paths.insert(0, a)
- text = repo.git.diff(full_index=True, *paths)
+ text = repo.git.diff('-M', full_index=True, *paths)
return diff.Diff.list_from_string(repo, text)
@property
def diffs(self):
if not self.parents:
- d = self.repo.git.show(self.id, full_index=True, pretty='raw')
+ d = self.repo.git.show(self.id, '-M', full_index=True, pretty='raw')
if re.search(r'diff --git a', d):
if not re.search(r'^diff --git a', d):
p = re.compile(r'.+?(diff --git a)', re.MULTILINE | re.DOTALL)
@@ -214,14 +224,14 @@ class Commit(LazyMixin):
@property
def stats(self):
if not self.parents:
- text = self.repo.git.diff(self.id, numstat=True)
+ text = self.repo.git.diff(self.id, '--', numstat=True)
text2 = ""
for line in text.splitlines():
(insertions, deletions, filename) = line.split("\t")
text2 += "%s\t%s\t%s\n" % (deletions, insertions, filename)
text = text2
else:
- text = self.repo.git.diff(self.parents[0].id, self.id, numstat=True)
+ text = self.repo.git.diff(self.parents[0].id, self.id, '--', numstat=True)
return stats.Stats.list_from_string(self.repo, text)
def __str__(self):
diff --git a/lib/git/diff.py b/lib/git/diff.py
index 51315fe3..7a6770c4 100644
--- a/lib/git/diff.py
+++ b/lib/git/diff.py
@@ -12,7 +12,9 @@ class Diff(object):
A Diff contains diff information between two commits.
"""
- def __init__(self, repo, a_path, b_path, a_commit, b_commit, a_mode, b_mode, new_file, deleted_file, diff):
+ def __init__(self, repo, a_path, b_path, a_commit, b_commit, a_mode,
+ b_mode, new_file, deleted_file, rename_from,
+ rename_to, diff):
self.repo = repo
self.a_path = a_path
self.b_path = b_path
@@ -30,56 +32,40 @@ class Diff(object):
self.b_mode = b_mode
self.new_file = new_file
self.deleted_file = deleted_file
+ self.rename_from = rename_from
+ self.rename_to = rename_to
+ self.renamed = rename_from != rename_to
self.diff = diff
@classmethod
def list_from_string(cls, repo, text):
- lines = text.splitlines()
- a_mode = None
- b_mode = None
diffs = []
- while lines:
- m = re.search(r'^diff --git a/(\S+) b/(\S+)$', lines.pop(0))
- if m:
- a_path, b_path = m.groups()
- if re.search(r'^old mode', lines[0]):
- m = re.search(r'^old mode (\d+)', lines.pop(0))
- if m:
- a_mode, = m.groups()
- m = re.search(r'^new mode (\d+)', lines.pop(0))
- if m:
- b_mode, = m.groups()
- if re.search(r'^diff --git', lines[0]):
- diffs.append(Diff(repo, a_path, b_path, None, None, a_mode, b_mode, False, False, None))
- continue
- new_file = False
- deleted_file = False
+ diff_header = re.compile(r"""
+ #^diff[ ]--git
+ [ ]a/(?P<a_path>\S+)[ ]b/(?P<b_path>\S+)\n
+ (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
+ ^rename[ ]from[ ](?P<rename_from>\S+)\n
+ ^rename[ ]to[ ](?P<rename_to>\S+)(?:\n|$))?
+ (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
+ ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
+ (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
+ (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
+ (?:^index[ ](?P<a_commit>[0-9A-Fa-f]+)
+ \.\.(?P<b_commit>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
+ """, re.VERBOSE | re.MULTILINE).match
- if re.search(r'^new file', lines[0]):
- m = re.search(r'^new file mode (.+)', lines.pop(0))
- if m:
- b_mode, = m.groups()
- a_mode = None
- new_file = True
- elif re.search(r'^deleted file', lines[0]):
- m = re.search(r'^deleted file mode (.+)$', lines.pop(0))
- if m:
- a_mode, = m.groups()
- b_mode = None
- deleted_file = True
+ for diff in ('\n' + text).split('\ndiff --git')[1:]:
+ header = diff_header(diff)
- m = re.search(r'^index ([0-9A-Fa-f]+)\.\.([0-9A-Fa-f]+) ?(.+)?$', lines.pop(0))
- if m:
- a_commit, b_commit, b_mode = m.groups()
- if b_mode:
- b_mode = b_mode.strip()
+ a_path, b_path, similarity_index, rename_from, rename_to, \
+ old_mode, new_mode, new_file_mode, deleted_file_mode, \
+ a_commit, b_commit, b_mode = header.groups()
+ new_file, deleted_file = bool(new_file_mode), bool(deleted_file_mode)
- diff_lines = []
- while lines and not re.search(r'^diff', lines[0]):
- diff_lines.append(lines.pop(0))
-
- diff = "\n".join(diff_lines)
- diffs.append(Diff(repo, a_path, b_path, a_commit, b_commit, a_mode, b_mode, new_file, deleted_file, diff))
+ diffs.append(Diff(repo, a_path, b_path, a_commit, b_commit,
+ old_mode or deleted_file_mode, new_mode or new_file_mode or b_mode,
+ new_file, deleted_file, rename_from, rename_to, diff[header.end():]))
return diffs
+
diff --git a/lib/git/repo.py b/lib/git/repo.py
index 093fdf0e..2d0fb973 100644
--- a/lib/git/repo.py
+++ b/lib/git/repo.py
@@ -100,13 +100,16 @@ class Repo(object):
"""
return Tag.find_all(self)
- def commits(self, start='master', max_count=10, skip=0):
+ def commits(self, start='master', path='', max_count=10, skip=0):
"""
A list of Commit objects representing the history of a given ref/commit
``start``
is the branch/commit name (default 'master')
+ ``path``
+ is an optional path
+
``max_count``
is the maximum number of commits to return (default 10)
@@ -119,9 +122,9 @@ class Repo(object):
options = {'max_count': max_count,
'skip': skip}
- return Commit.find_all(self, start, **options)
+ return Commit.find_all(self, start, path, **options)
- def commits_between(self, frm, to):
+ def commits_between(self, frm, to, path = ''):
"""
The Commits objects that are reachable via ``to`` but not via ``frm``
Commits are returned in chronological order.
@@ -132,12 +135,15 @@ class Repo(object):
``to``
is the branch/commit name of the older item
+ ``path``
+ is an optinal path
+
Returns
``git.Commit[]``
"""
- return Commit.find_all(self, "%s..%s" % (frm, to)).reverse()
+ return Commit.find_all(self, "%s..%s" % (frm, to), path).reverse()
- def commits_since(self, start='master', since='1970-01-01'):
+ def commits_since(self, start='master', path='', since='1970-01-01'):
"""
The Commits objects that are newer than the specified date.
Commits are returned in chronological order.
@@ -145,6 +151,9 @@ class Repo(object):
``start``
is the branch/commit name (default 'master')
+ ``path``
+ is an optinal path
+
``since``
is a string represeting a date/time
@@ -153,33 +162,39 @@ class Repo(object):
"""
options = {'since': since}
- return Commit.find_all(self, start, **options)
+ return Commit.find_all(self, start, path, **options)
- def commit_count(self, start='master'):
+ def commit_count(self, start='master', path=''):
"""
The number of commits reachable by the given branch/commit
``start``
is the branch/commit name (default 'master')
+ ``path``
+ is an optinal path
+
Returns
int
"""
- return Commit.count(self, start)
+ return Commit.count(self, start, path)
- def commit(self, id):
+ def commit(self, id, path = ''):
"""
The Commit object for the specified id
``id``
is the SHA1 identifier of the commit
+ ``path``
+ is an optinal path
+
Returns
git.Commit
"""
options = {'max_count': 1}
- commits = Commit.find_all(self, id, **options)
+ commits = Commit.find_all(self, id, path, **options)
if not commits:
raise ValueError, 'Invalid identifier %s' % id
@@ -192,8 +207,8 @@ class Repo(object):
Returns
``git.Commit[]``
"""
- repo_refs = self.git.rev_list(ref).strip().splitlines()
- other_repo_refs = other_repo.git.rev_list(other_ref).strip().splitlines()
+ repo_refs = self.git.rev_list(ref, '--').strip().splitlines()
+ other_repo_refs = other_repo.git.rev_list(other_ref, '--').strip().splitlines()
diff_refs = list(set(other_repo_refs) - set(repo_refs))
return map(lambda ref: Commit.find_all(other_repo, ref, max_count=1)[0], diff_refs)
@@ -236,10 +251,9 @@ class Repo(object):
"""
options = {'pretty': 'raw'}
options.update(kwargs)
+ arg = [commit, '--']
if path:
- arg = [commit, '--', path]
- else:
- arg = [commit]
+ arg.append(path)
commits = self.git.log(*arg, **options)
return Commit.list_from_string(self, commits)
@@ -450,13 +464,13 @@ class Repo(object):
# always consired to be clean.
return False
- return len(self.git.diff('HEAD').strip()) > 0
+ return len(self.git.diff('HEAD', '--').strip()) > 0
@property
def active_branch(self):
"""
The name of the currently active branch.
-
+
Returns
str (the branch name)
"""