revert: Add support for git_revert_commit via Repository.revert_commit()

This change adds `Repository.revert_commit()` which wraps around
`git_revert_commit` which will return an `Index` with the appropriate
changes to revert the specified commit.

Fixes #710
This commit is contained in:
Mark Adams
2017-06-05 16:06:05 -05:00
parent 87beb76dcc
commit c6305a062b
4 changed files with 60 additions and 3 deletions

View File

@@ -68,7 +68,7 @@ Authors
Peter Dave Hello Philippe Ombredanne Ridge Kennedy Peter Dave Hello Philippe Ombredanne Ridge Kennedy
Ross Nicoll Rui Abreu Ferreira Sheeo Ross Nicoll Rui Abreu Ferreira Sheeo
Soasme Vladimir Rutsky Yu Jianjian Soasme Vladimir Rutsky Yu Jianjian
chengyuhang earl chengyuhang earl Mark Adams
License License
============== ==============

View File

@@ -922,3 +922,5 @@ typedef enum {
int git_attr_get(const char **value_out, git_repository *repo, uint32_t flags, const char *path, const char *name); int git_attr_get(const char **value_out, git_repository *repo, uint32_t flags, const char *path, const char *name);
git_attr_t git_attr_value(const char *attr); git_attr_t git_attr_value(const char *attr);
int git_revert_commit(git_index **out, git_repository *repo, git_commit *revert_commit, git_commit *our_commit, unsigned int mainline, const git_merge_options *merge_options);

View File

@@ -1001,6 +1001,39 @@ class BaseRepository(_Repository):
err = C.git_repository_set_ident(self._repo, to_bytes(name), to_bytes(email)) err = C.git_repository_set_ident(self._repo, to_bytes(name), to_bytes(email))
check_error(err) check_error(err)
def revert_commit(self, revert_commit, our_commit, mainline=0):
"""Reverts the given Commit against the given "our" Commit,
producing an Index that reflects the result of the revert.
Arguments
revert_commit
The Commit to revert
our_commit
The Commit to revert against (eg, HEAD)
mainline
The parent of the revert Commit, if it is a merge (i.e. 1, 2)
Returns an Index with the result of the revert.
"""
cindex = ffi.new('git_index **')
revert_commit_ptr = ffi.new('git_commit **')
our_commit_ptr = ffi.new('git_commit **')
ffi.buffer(revert_commit_ptr)[:] = revert_commit._pointer[:]
ffi.buffer(our_commit_ptr)[:] = our_commit._pointer[:]
opts = ffi.new('git_merge_options *')
err = C.git_merge_init_options(opts, C.GIT_MERGE_OPTIONS_VERSION)
check_error(err)
err = C.git_revert_commit(
cindex, self._repo, revert_commit_ptr[0], our_commit_ptr[0], mainline, opts
)
check_error(err)
return Index.from_c(self, cindex)
class Branches(object): class Branches(object):
def __init__(self, repository, flag=GIT_BRANCH_ALL): def __init__(self, repository, flag=GIT_BRANCH_ALL):

View File

@@ -43,7 +43,7 @@ import six
if six.PY2: if six.PY2:
from urllib import pathname2url from urllib import pathname2url
if six.PY3: if six.PY3:
from urllib.request import pathname2url from urllib.request import pathname2url
@@ -435,6 +435,28 @@ class RepositoryTest_II(utils.RepoTestCase):
self.repo.stash_drop() self.repo.stash_drop()
self.assertRaises(KeyError, self.repo.stash_pop) self.assertRaises(KeyError, self.repo.stash_pop)
def test_revert(self):
master = self.repo.head.peel()
commit_to_revert = self.repo['4ec4389a8068641da2d6578db0419484972284c8']
parent = commit_to_revert.parents[0]
commit_diff_stats = (
parent.tree.diff_to_tree(commit_to_revert.tree).stats
)
revert_index = self.repo.revert_commit(commit_to_revert, master)
revert_diff_stats = revert_index.diff_to_tree(master.tree).stats
self.assertEquals(
revert_diff_stats.insertions, commit_diff_stats.deletions
)
self.assertEquals(
revert_diff_stats.deletions, commit_diff_stats.insertions
)
self.assertEquals(
revert_diff_stats.files_changed, commit_diff_stats.files_changed
)
class RepositorySignatureTest(utils.RepoTestCase): class RepositorySignatureTest(utils.RepoTestCase):
def test_default_signature(self): def test_default_signature(self):
@@ -533,7 +555,7 @@ class CloneRepositoryTest(utils.NoRepoTestCase):
src_repo_relpath = "./test/data/testrepo.git/" src_repo_relpath = "./test/data/testrepo.git/"
repo_path = os.path.join(self._temp_dir, "clone-into") repo_path = os.path.join(self._temp_dir, "clone-into")
url = pathname2url(os.path.realpath(src_repo_relpath)) url = pathname2url(os.path.realpath(src_repo_relpath))
if url.startswith('///'): if url.startswith('///'):
url = 'file:' + url url = 'file:' + url
else: else: