Adjust to the merge changes

There is no more MergeResult type. Instead, the user can use
Repository.merge_analysis() to get an overview of their options and call
git_merge() when they mean to merge.

The git_merge() function now also performs a checkout.
This commit is contained in:
Carlos Martín Nieto
2014-03-25 03:14:02 +01:00
parent a870a59f2a
commit 55037c23a3
6 changed files with 84 additions and 242 deletions

View File

@@ -1,145 +0,0 @@
/*
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
* as published by the Free Software Foundation.
*
* In addition to the permissions in the GNU General Public License,
* the authors give you unlimited permission to link the compiled
* version of this file into combinations with other programs,
* and to distribute those combinations without any restriction
* coming from the use of this file. (The General Public License
* restrictions do apply in other respects; for example, they cover
* modification of the file, and distribution when not linked into
* a combined executable.)
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "utils.h"
#include "types.h"
#include "oid.h"
#include "repository.h"
#include "mergeresult.h"
extern PyTypeObject MergeResultType;
extern PyTypeObject IndexType;
PyObject *
git_merge_result_to_python(git_merge_result *merge_result)
{
MergeResult *py_merge_result;
py_merge_result = PyObject_New(MergeResult, &MergeResultType);
if (!py_merge_result)
return NULL;
py_merge_result->result = merge_result;
return (PyObject*) py_merge_result;
}
void
MergeResult_dealloc(MergeResult *self)
{
git_merge_result_free(self->result);
PyObject_Del(self);
}
PyDoc_STRVAR(MergeResult_is_uptodate__doc__, "Is up to date");
PyObject *
MergeResult_is_uptodate__get__(MergeResult *self)
{
if (git_merge_result_is_uptodate(self->result))
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}
PyDoc_STRVAR(MergeResult_is_fastforward__doc__, "Is fastforward");
PyObject *
MergeResult_is_fastforward__get__(MergeResult *self)
{
if (git_merge_result_is_fastforward(self->result))
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}
PyDoc_STRVAR(MergeResult_fastforward_id__doc__, "Fastforward Oid");
PyObject *
MergeResult_fastforward_id__get__(MergeResult *self)
{
if (git_merge_result_is_fastforward(self->result)) {
git_oid fastforward_id;
git_merge_result_fastforward_id(&fastforward_id, self->result);
return git_oid_to_python((const git_oid *)&fastforward_id);
}
else Py_RETURN_NONE;
}
PyGetSetDef MergeResult_getseters[] = {
GETTER(MergeResult, is_uptodate),
GETTER(MergeResult, is_fastforward),
GETTER(MergeResult, fastforward_id),
{NULL},
};
PyDoc_STRVAR(MergeResult__doc__, "MergeResult object.");
PyTypeObject MergeResultType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_pygit2.MergeResult", /* tp_name */
sizeof(MergeResult), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)MergeResult_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
MergeResult__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
MergeResult_getseters, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};

View File

@@ -1,37 +0,0 @@
/*
* Copyright 2010-2014 The pygit2 contributors
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2,
* as published by the Free Software Foundation.
*
* In addition to the permissions in the GNU General Public License,
* the authors give you unlimited permission to link the compiled
* version of this file into combinations with other programs,
* and to distribute those combinations without any restriction
* coming from the use of this file. (The General Public License
* restrictions do apply in other respects; for example, they cover
* modification of the file, and distribution when not linked into
* a combined executable.)
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef INCLUDE_pygit2_merge_result_h
#define INCLUDE_pygit2_merge_result_h
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <git2.h>
PyObject* git_merge_result_to_python(git_merge_result *merge_result);
#endif

View File

@@ -71,7 +71,6 @@ extern PyTypeObject NoteIterType;
extern PyTypeObject BlameType;
extern PyTypeObject BlameIterType;
extern PyTypeObject BlameHunkType;
extern PyTypeObject MergeResultType;
@@ -477,8 +476,11 @@ moduleinit(PyObject* m)
ADD_CONSTANT_INT(m, GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES)
/* Merge */
INIT_TYPE(MergeResultType, NULL, NULL)
ADD_TYPE(m, MergeResult)
ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_NONE)
ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_NORMAL)
ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_UP_TO_DATE)
ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_FASTFORWARD)
ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_UNBORN)
/* Global initialization of libgit2 */
git_threads_init();

View File

@@ -38,7 +38,6 @@
#include "remote.h"
#include "branch.h"
#include "blame.h"
#include "mergeresult.h"
#include "signature.h"
#include <git2/odb_backend.h>
@@ -587,28 +586,61 @@ Repository_merge_base(Repository *self, PyObject *args)
return git_oid_to_python(&oid);
}
PyDoc_STRVAR(Repository_merge_analysis__doc__,
"merge_analysis(id) -> Integer\n"
"\n"
"Analyzes the given branch and determines the opportunities for merging\n"
"them into the HEAD of the repository\n"
"\n"
"The returned value is a mixture of the GIT_MERGE_ANALYSIS_NONE, _NORMAL,\n"
" _UP_TO_DATE, _FASTFORWARD and _UNBORN flags");
PyObject *
Repository_merge_analysis(Repository *self, PyObject *py_id)
{
int err;
size_t len;
git_oid id;
git_merge_head *merge_head;
git_merge_analysis_t analysis;
len = py_oid_to_git_oid(py_id, &id);
if (len == 0)
return NULL;
err = git_merge_head_from_id(&merge_head, self->repo, &id);
if (err < 0)
return Error_set(err);
err = git_merge_analysis(&analysis, self->repo, (const git_merge_head **) &merge_head, 1);
git_merge_head_free(merge_head);
if (err < 0)
return Error_set(err);
return PyLong_FromLong(analysis);
}
PyDoc_STRVAR(Repository_merge__doc__,
"merge(id) -> MergeResult\n"
"merge(id)\n"
"\n"
"Merges the given id and returns the MergeResult.\n"
"Merges the given id into HEAD.\n"
"\n"
"If the merge is fastforward the MergeResult will contain the new\n"
"fastforward oid.\n"
"If the branch is uptodate, nothing to merge, the MergeResult will\n"
"have the fastforward oid as None.\n"
"If the merge is not fastforward the MergeResult will have the status\n"
"produced by the merge, even if there are conflicts.");
"Merges the given commit(s) into HEAD, writing the results into the\n"
"working directory. Any changes are staged for commit and any conflicts\n"
"are written to the index. Callers should inspect the repository's\n"
"index after this completes, resolve any conflicts and prepare a\n"
"commit.");
PyObject *
Repository_merge(Repository *self, PyObject *py_oid)
{
git_merge_result *merge_result;
git_merge_head *oid_merge_head;
git_oid oid;
const git_merge_opts default_opts = GIT_MERGE_OPTS_INIT;
int err;
size_t len;
PyObject *py_merge_result;
git_merge_options merge_opts = GIT_MERGE_OPTIONS_INIT;
git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
len = py_oid_to_git_oid(py_oid, &oid);
if (len == 0)
@@ -618,15 +650,15 @@ Repository_merge(Repository *self, PyObject *py_oid)
if (err < 0)
return Error_set(err);
err = git_merge(&merge_result, self->repo,
err = git_merge(self->repo,
(const git_merge_head **)&oid_merge_head, 1,
&default_opts);
&merge_opts, &checkout_opts);
git_merge_head_free(oid_merge_head);
if (err < 0)
return Error_set(err);
py_merge_result = git_merge_result_to_python(merge_result);
return py_merge_result;
Py_RETURN_NONE;
}
PyDoc_STRVAR(Repository_walk__doc__,
@@ -1623,6 +1655,7 @@ PyMethodDef Repository_methods[] = {
METHOD(Repository, TreeBuilder, METH_VARARGS),
METHOD(Repository, walk, METH_VARARGS),
METHOD(Repository, merge_base, METH_VARARGS),
METHOD(Repository, merge_analysis, METH_O),
METHOD(Repository, merge, METH_O),
METHOD(Repository, read, METH_O),
METHOD(Repository, write, METH_VARARGS),

View File

@@ -249,10 +249,4 @@ typedef struct {
char boundary;
} BlameHunk;
/* git_merge */
typedef struct {
PyObject_HEAD
git_merge_result *result;
} MergeResult;
#endif

View File

@@ -40,6 +40,8 @@ from os.path import join, realpath
# Import from pygit2
from pygit2 import GIT_OBJ_ANY, GIT_OBJ_BLOB, GIT_OBJ_COMMIT
from pygit2 import GIT_MERGE_ANALYSIS_NONE, GIT_MERGE_ANALYSIS_NORMAL, GIT_MERGE_ANALYSIS_UP_TO_DATE
from pygit2 import GIT_MERGE_ANALYSIS_FASTFORWARD, GIT_MERGE_ANALYSIS_UNBORN
from pygit2 import init_repository, clone_repository, discover_repository
from pygit2 import Oid, Reference, hashfile
import pygit2
@@ -308,57 +310,50 @@ class RepositoryTest_III(utils.RepoTestCaseForMerging):
def test_merge_none(self):
self.assertRaises(TypeError, self.repo.merge, None)
def test_merge_uptodate(self):
def test_merge_analysis_uptodate(self):
branch_head_hex = '5ebeeebb320790caf276b9fc8b24546d63316533'
branch_oid = self.repo.get(branch_head_hex).id
merge_result = self.repo.merge(branch_oid)
self.assertTrue(merge_result.is_uptodate)
self.assertFalse(merge_result.is_fastforward)
self.assertEqual(None, merge_result.fastforward_id)
branch_id = self.repo.get(branch_head_hex).id
analysis = self.repo.merge_analysis(branch_id)
self.assertTrue(analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE)
self.assertFalse(analysis & GIT_MERGE_ANALYSIS_FASTFORWARD)
self.assertEqual({}, self.repo.status())
def test_merge_fastforward(self):
def test_merge_analysis_fastforward(self):
branch_head_hex = 'e97b4cfd5db0fb4ebabf4f203979ca4e5d1c7c87'
branch_oid = self.repo.get(branch_head_hex).id
merge_result = self.repo.merge(branch_oid)
self.assertFalse(merge_result.is_uptodate)
self.assertTrue(merge_result.is_fastforward)
# Asking twice to assure the reference counting is correct
self.assertEqual(branch_head_hex, merge_result.fastforward_id.hex)
self.assertEqual(branch_head_hex, merge_result.fastforward_id.hex)
branch_id = self.repo.get(branch_head_hex).id
analysis = self.repo.merge_analysis(branch_id)
self.assertFalse(analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE)
self.assertTrue(analysis & GIT_MERGE_ANALYSIS_FASTFORWARD)
self.assertEqual({}, self.repo.status())
def test_merge_no_fastforward_no_conflicts(self):
branch_head_hex = '03490f16b15a09913edb3a067a3dc67fbb8d41f1'
branch_oid = self.repo.get(branch_head_hex).id
merge_result = self.repo.merge(branch_oid)
self.assertFalse(merge_result.is_uptodate)
self.assertFalse(merge_result.is_fastforward)
branch_id = self.repo.get(branch_head_hex).id
analysis= self.repo.merge_analysis(branch_id)
self.assertFalse(analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE)
self.assertFalse(analysis & GIT_MERGE_ANALYSIS_FASTFORWARD)
# Asking twice to assure the reference counting is correct
self.assertEqual(None, merge_result.fastforward_id)
self.assertEqual(None, merge_result.fastforward_id)
self.assertEqual({'bye.txt': 1}, self.repo.status())
self.assertEqual({'bye.txt': 1}, self.repo.status())
# Checking the index works as expected
self.repo.index.remove('bye.txt')
self.repo.index.write()
self.assertEqual({'bye.txt': 128}, self.repo.status())
self.assertEqual({}, self.repo.status())
self.assertEqual({}, self.repo.status())
def test_merge_no_fastforward_conflicts(self):
branch_head_hex = '1b2bae55ac95a4be3f8983b86cd579226d0eb247'
branch_oid = self.repo.get(branch_head_hex).id
merge_result = self.repo.merge(branch_oid)
self.assertFalse(merge_result.is_uptodate)
self.assertFalse(merge_result.is_fastforward)
branch_id = self.repo.get(branch_head_hex).id
analysis = self.repo.merge_analysis(branch_id)
self.assertFalse(analysis & GIT_MERGE_ANALYSIS_UP_TO_DATE)
self.assertFalse(analysis & GIT_MERGE_ANALYSIS_FASTFORWARD)
self.repo.merge(branch_id)
status = pygit2.GIT_STATUS_WT_NEW | pygit2.GIT_STATUS_INDEX_DELETED
# Asking twice to assure the reference counting is correct
self.assertEqual(None, merge_result.fastforward_id)
self.assertEqual(None, merge_result.fastforward_id)
self.assertEqual({'.gitignore': 132}, self.repo.status())
self.assertEqual({'.gitignore': 132}, self.repo.status())
self.assertEqual({'.gitignore': status}, self.repo.status())
self.assertEqual({'.gitignore': status}, self.repo.status())
# Checking the index works as expected
self.repo.index.add('.gitignore')
self.repo.index.write()
self.assertEqual({'.gitignore': 2}, self.repo.status())
self.assertEqual({'.gitignore': pygit2.GIT_STATUS_INDEX_MODIFIED}, self.repo.status())
def test_merge_invalid_hex(self):
branch_head_hex = '12345678'