summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2015-01-13 20:00:21 +0100
committerSebastian Thiel <byronimo@gmail.com>2015-01-13 20:00:21 +0100
commite973e6f829de5dd1c09d0db39d232230e7eb01d8 (patch)
tree0a1af5290ee8fc7b53a49ee7014f00bf5c05cadc
parenta2d39529eea4d0ecfcd65a2d245284174cd2e0aa (diff)
downloadgitpython-e973e6f829de5dd1c09d0db39d232230e7eb01d8.tar.gz
Added `Repo.merge_base(...)` implementation, including test-case.
Fixes #169
-rw-r--r--doc/source/changes.rst5
-rw-r--r--git/repo/base.py36
-rw-r--r--git/test/test_repo.py24
3 files changed, 63 insertions, 2 deletions
diff --git a/doc/source/changes.rst b/doc/source/changes.rst
index a64143c5..e18b07ce 100644
--- a/doc/source/changes.rst
+++ b/doc/source/changes.rst
@@ -2,6 +2,11 @@
Changelog
=========
+0.3.6 - Features
+================
+* Added `Repo.merge_base()` implementation. See the `respective issue on github <https://github.com/gitpython-developers/GitPython/issues/169>`_
+* A list of all issues can be found here: https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v0.3.6+-+Features%22+
+
0.3.5 - Bugfixes
================
* push/pull/fetch operations will not block anymore
diff --git a/git/repo/base.py b/git/repo/base.py
index d6efbd58..f5ed2479 100644
--- a/git/repo/base.py
+++ b/git/repo/base.py
@@ -4,7 +4,11 @@
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
-from git.exc import InvalidGitRepositoryError, NoSuchPathError
+from git.exc import (
+ InvalidGitRepositoryError,
+ NoSuchPathError,
+ GitCommandError
+)
from git.cmd import (
Git,
handle_process_output
@@ -456,6 +460,36 @@ class Repo(object):
return Commit.iter_items(self, rev, paths, **kwargs)
+ def merge_base(self, *rev, **kwargs):
+ """Find the closest common ancestor for the given revision (e.g. Commits, Tags, References, etc).
+ :param rev: At least two revs to find the common ancestor for.
+ :param kwargs: Additional arguments to be passed to the repo.git.merge_base() command which does all the work.
+ :return: A list of Commit objects. If --all was not specified as kwarg, the list will have at max one Commit,
+ or is empty if no common merge base exists.
+ :raises ValueError: If not at least two revs are provided
+ """
+ if len(rev) < 2:
+ raise ValueError("Please specify at least two revs, got only %i" % len(rev))
+ # end handle input
+
+ res = list()
+ try:
+ lines = self.git.merge_base(*rev, **kwargs).splitlines()
+ except GitCommandError as err:
+ if err.status == 128:
+ raise
+ # end handle invalid rev
+ # Status code 1 is returned if there is no merge-base
+ # (see https://github.com/git/git/blob/master/builtin/merge-base.c#L16)
+ return res
+ # end exception handling
+
+ for line in lines:
+ res.append(self.commit(line))
+ # end for each merge-base
+
+ return res
+
def _get_daemon_export(self):
filename = join(self.git_dir, self.DAEMON_EXPORT_FILE)
return os.path.exists(filename)
diff --git a/git/test/test_repo.py b/git/test/test_repo.py
index 046b20a7..a782cefa 100644
--- a/git/test/test_repo.py
+++ b/git/test/test_repo.py
@@ -27,7 +27,8 @@ from git import (
Submodule,
GitCmdObjectDB,
Remote,
- BadName
+ BadName,
+ GitCommandError
)
from git.repo.fun import touch
from git.util import join_path_native
@@ -737,3 +738,24 @@ class TestRepo(TestBase):
# Now a branch should be creatable
nb = r.create_head('foo')
assert nb.is_valid()
+
+ def test_merge_base(self):
+ repo = self.rorepo
+ c1 = 'f6aa8d1'
+ c2 = repo.commit('d46e3fe')
+ c3 = '763ef75'
+ self.failUnlessRaises(ValueError, repo.merge_base)
+ self.failUnlessRaises(ValueError, repo.merge_base, 'foo')
+
+ # two commit merge-base
+ res = repo.merge_base(c1, c2)
+ assert isinstance(res, list) and len(res) == 1 and isinstance(res[0], Commit)
+ assert res[0].hexsha.startswith('3936084')
+
+ for kw in ('a', 'all'):
+ res = repo.merge_base(c1, c2, c3, **{kw: True})
+ assert isinstance(res, list) and len(res) == 1
+ # end for eaech keyword signalling all merge-bases to be returned
+
+ # Test for no merge base - can't do as we have
+ self.failUnlessRaises(GitCommandError, repo.merge_base, c1, 'ffffff')