Skip to content

Commit e973e6f

Browse files
committed
Added Repo.merge_base(...) implementation, including test-case.
Fixes #169
1 parent a2d3952 commit e973e6f

File tree

3 files changed

+63
-2
lines changed

3 files changed

+63
-2
lines changed

Diff for: doc/source/changes.rst

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
Changelog
33
=========
44

5+
0.3.6 - Features
6+
================
7+
* Added `Repo.merge_base()` implementation. See the `respective issue on github <https://github.com/gitpython-developers/GitPython/issues/169>`_
8+
* A list of all issues can be found here: https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v0.3.6+-+Features%22+
9+
510
0.3.5 - Bugfixes
611
================
712
* push/pull/fetch operations will not block anymore

Diff for: git/repo/base.py

+35-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
# This module is part of GitPython and is released under
55
# the BSD License: http://www.opensource.org/licenses/bsd-license.php
66

7-
from git.exc import InvalidGitRepositoryError, NoSuchPathError
7+
from git.exc import (
8+
InvalidGitRepositoryError,
9+
NoSuchPathError,
10+
GitCommandError
11+
)
812
from git.cmd import (
913
Git,
1014
handle_process_output
@@ -456,6 +460,36 @@ def iter_commits(self, rev=None, paths='', **kwargs):
456460

457461
return Commit.iter_items(self, rev, paths, **kwargs)
458462

463+
def merge_base(self, *rev, **kwargs):
464+
"""Find the closest common ancestor for the given revision (e.g. Commits, Tags, References, etc).
465+
:param rev: At least two revs to find the common ancestor for.
466+
:param kwargs: Additional arguments to be passed to the repo.git.merge_base() command which does all the work.
467+
:return: A list of Commit objects. If --all was not specified as kwarg, the list will have at max one Commit,
468+
or is empty if no common merge base exists.
469+
:raises ValueError: If not at least two revs are provided
470+
"""
471+
if len(rev) < 2:
472+
raise ValueError("Please specify at least two revs, got only %i" % len(rev))
473+
# end handle input
474+
475+
res = list()
476+
try:
477+
lines = self.git.merge_base(*rev, **kwargs).splitlines()
478+
except GitCommandError as err:
479+
if err.status == 128:
480+
raise
481+
# end handle invalid rev
482+
# Status code 1 is returned if there is no merge-base
483+
# (see https://github.com/git/git/blob/master/builtin/merge-base.c#L16)
484+
return res
485+
# end exception handling
486+
487+
for line in lines:
488+
res.append(self.commit(line))
489+
# end for each merge-base
490+
491+
return res
492+
459493
def _get_daemon_export(self):
460494
filename = join(self.git_dir, self.DAEMON_EXPORT_FILE)
461495
return os.path.exists(filename)

Diff for: git/test/test_repo.py

+23-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@
2727
Submodule,
2828
GitCmdObjectDB,
2929
Remote,
30-
BadName
30+
BadName,
31+
GitCommandError
3132
)
3233
from git.repo.fun import touch
3334
from git.util import join_path_native
@@ -737,3 +738,24 @@ def test_empty_repo(self, rw_dir):
737738
# Now a branch should be creatable
738739
nb = r.create_head('foo')
739740
assert nb.is_valid()
741+
742+
def test_merge_base(self):
743+
repo = self.rorepo
744+
c1 = 'f6aa8d1'
745+
c2 = repo.commit('d46e3fe')
746+
c3 = '763ef75'
747+
self.failUnlessRaises(ValueError, repo.merge_base)
748+
self.failUnlessRaises(ValueError, repo.merge_base, 'foo')
749+
750+
# two commit merge-base
751+
res = repo.merge_base(c1, c2)
752+
assert isinstance(res, list) and len(res) == 1 and isinstance(res[0], Commit)
753+
assert res[0].hexsha.startswith('3936084')
754+
755+
for kw in ('a', 'all'):
756+
res = repo.merge_base(c1, c2, c3, **{kw: True})
757+
assert isinstance(res, list) and len(res) == 1
758+
# end for eaech keyword signalling all merge-bases to be returned
759+
760+
# Test for no merge base - can't do as we have
761+
self.failUnlessRaises(GitCommandError, repo.merge_base, c1, 'ffffff')

0 commit comments

Comments
 (0)