Skip to content

Commit 12ebc77

Browse files
author
Ross Nicoll
committed
Add support for cherrypick()
1 parent d64dd15 commit 12ebc77

File tree

3 files changed

+116
-0
lines changed

3 files changed

+116
-0
lines changed

src/repository.c

+41
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,46 @@ Repository_merge(Repository *self, PyObject *py_oid)
634634
Py_RETURN_NONE;
635635
}
636636

637+
PyDoc_STRVAR(Repository_cherrypick__doc__,
638+
"cherrypick(id)\n"
639+
"\n"
640+
"Cherry-pick the given oid, producing changes in the index and working directory.\n"
641+
"\n"
642+
"Merges the given commit into HEAD as a cherrypick, writing the results into the\n"
643+
"working directory. Any changes are staged for commit and any conflicts\n"
644+
"are written to the index. Callers should inspect the repository's\n"
645+
"index after this completes, resolve any conflicts and prepare a\n"
646+
"commit.");
647+
648+
PyObject *
649+
Repository_cherrypick(Repository *self, PyObject *py_oid)
650+
{
651+
git_commit *commit;
652+
git_oid oid;
653+
int err;
654+
size_t len;
655+
git_cherrypick_options cherrypick_opts = GIT_CHERRYPICK_OPTIONS_INIT;
656+
657+
len = py_oid_to_git_oid(py_oid, &oid);
658+
if (len == 0)
659+
return NULL;
660+
661+
err = git_commit_lookup(&commit, self->repo, &oid);
662+
if (err < 0)
663+
return Error_set(err);
664+
665+
cherrypick_opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE;
666+
err = git_cherrypick(self->repo,
667+
commit,
668+
(const git_cherrypick_options *)&cherrypick_opts);
669+
670+
git_commit_free(commit);
671+
if (err < 0)
672+
return Error_set(err);
673+
674+
Py_RETURN_NONE;
675+
}
676+
637677
PyDoc_STRVAR(Repository_walk__doc__,
638678
"walk(oid[, sort_mode]) -> iterator\n"
639679
"\n"
@@ -1462,6 +1502,7 @@ PyMethodDef Repository_methods[] = {
14621502
METHOD(Repository, merge_base, METH_VARARGS),
14631503
METHOD(Repository, merge_analysis, METH_O),
14641504
METHOD(Repository, merge, METH_O),
1505+
METHOD(Repository, cherrypick, METH_O),
14651506
METHOD(Repository, read, METH_O),
14661507
METHOD(Repository, write, METH_VARARGS),
14671508
METHOD(Repository, create_reference_direct, METH_VARARGS),

src/repository.h

+1
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,6 @@ PyObject* Repository_TreeBuilder(Repository *self, PyObject *args);
7070
PyObject* Repository_blame(Repository *self, PyObject *args, PyObject *kwds);
7171

7272
PyObject* Repository_merge(Repository *self, PyObject *py_oid);
73+
PyObject* Repository_cherrypick(Repository *self, PyObject *py_oid);
7374

7475
#endif

test/test_cherrypick.py

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# -*- coding: UTF-8 -*-
2+
#
3+
# Copyright 2010-2014 The pygit2 contributors
4+
#
5+
# This file is free software; you can redistribute it and/or modify
6+
# it under the terms of the GNU General Public License, version 2,
7+
# as published by the Free Software Foundation.
8+
#
9+
# In addition to the permissions in the GNU General Public License,
10+
# the authors give you unlimited permission to link the compiled
11+
# version of this file into combinations with other programs,
12+
# and to distribute those combinations without any restriction
13+
# coming from the use of this file. (The General Public License
14+
# restrictions do apply in other respects; for example, they cover
15+
# modification of the file, and distribution when not linked into
16+
# a combined executable.)
17+
#
18+
# This file is distributed in the hope that it will be useful, but
19+
# WITHOUT ANY WARRANTY; without even the implied warranty of
20+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21+
# General Public License for more details.
22+
#
23+
# You should have received a copy of the GNU General Public License
24+
# along with this program; see the file COPYING. If not, write to
25+
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
26+
# Boston, MA 02110-1301, USA.
27+
28+
"""Tests for merging and information about it."""
29+
30+
# Import from the future
31+
from __future__ import absolute_import
32+
from __future__ import unicode_literals
33+
34+
import unittest
35+
import os
36+
37+
from pygit2 import GIT_MERGE_ANALYSIS_NONE, GIT_MERGE_ANALYSIS_NORMAL, GIT_MERGE_ANALYSIS_UP_TO_DATE
38+
from pygit2 import GIT_MERGE_ANALYSIS_FASTFORWARD, GIT_MERGE_ANALYSIS_UNBORN
39+
import pygit2
40+
41+
from . import utils
42+
43+
class CherrypickTestBasic(utils.RepoTestCaseForMerging):
44+
45+
def test_cherrypick_none(self):
46+
self.assertRaises(TypeError, self.repo.cherrypick, None)
47+
48+
def test_cherrypick_invalid_hex(self):
49+
branch_head_hex = '12345678'
50+
self.assertRaises(KeyError, self.repo.cherrypick, branch_head_hex)
51+
52+
def test_cherrypick_already_something_in_index(self):
53+
branch_head_hex = '03490f16b15a09913edb3a067a3dc67fbb8d41f1'
54+
branch_oid = self.repo.get(branch_head_hex).id
55+
with open(os.path.join(self.repo.workdir, 'inindex.txt'), 'w') as f:
56+
f.write('new content')
57+
self.repo.index.add('inindex.txt')
58+
self.assertRaises(pygit2.GitError, self.repo.cherrypick, branch_oid)
59+
60+
class CherrypickTestWithConflicts(utils.RepoTestCaseForMerging):
61+
62+
def test_cherrypick_remove_conflicts(self):
63+
other_branch_tip = '1b2bae55ac95a4be3f8983b86cd579226d0eb247'
64+
self.repo.cherrypick(other_branch_tip)
65+
idx = self.repo.index
66+
conflicts = idx.conflicts
67+
self.assertTrue(conflicts is not None)
68+
try:
69+
conflicts['.gitignore']
70+
except KeyError:
71+
self.fail("conflicts['.gitignore'] raised KeyError unexpectedly")
72+
del idx.conflicts['.gitignore']
73+
self.assertRaises(KeyError, conflicts.__getitem__, '.gitignore')
74+
self.assertTrue(idx.conflicts is None)

0 commit comments

Comments
 (0)