changelog: fix bug in heads computation
This patch refactors the native computation of heads. It fixes a bug where
filtered heads in the pending index could be returned by the native code
despite their filtering.
--- a/mercurial/parsers.c Tue May 26 12:08:50 2015 -0700
+++ b/mercurial/parsers.c Tue May 26 12:09:04 2015 -0700
@@ -1194,7 +1194,7 @@
static PyObject *index_headrevs(indexObject *self, PyObject *args)
{
- Py_ssize_t i, len, addlen;
+ Py_ssize_t i, j, len;
char *nothead = NULL;
PyObject *heads = NULL;
PyObject *filter = NULL;
@@ -1237,9 +1237,9 @@
if (nothead == NULL)
goto bail;
- for (i = 0; i < self->raw_length; i++) {
- const char *data;
- int parent_1, parent_2, isfiltered;
+ for (i = 0; i < len; i++) {
+ int isfiltered;
+ int parents[2];
isfiltered = check_filter(filter, i);
if (isfiltered == -1) {
@@ -1253,49 +1253,11 @@
continue;
}
- data = index_deref(self, i);
- parent_1 = getbe32(data + 24);
- parent_2 = getbe32(data + 28);
-
- if (parent_1 >= 0)
- nothead[parent_1] = 1;
- if (parent_2 >= 0)
- nothead[parent_2] = 1;
- }
-
- addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
-
- for (i = 0; i < addlen; i++) {
- PyObject *rev = PyList_GET_ITEM(self->added, i);
- PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
- PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
- long parent_1, parent_2;
- int isfiltered;
-
- if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
- PyErr_SetString(PyExc_TypeError,
- "revlog parents are invalid");
- goto bail;
+ index_get_parents(self, i, parents);
+ for (j = 0; j < 2; j++) {
+ if (parents[j] >= 0)
+ nothead[parents[j]] = 1;
}
-
- isfiltered = check_filter(filter, i);
- if (isfiltered == -1) {
- PyErr_SetString(PyExc_TypeError,
- "unable to check filter");
- goto bail;
- }
-
- if (isfiltered) {
- nothead[i] = 1;
- continue;
- }
-
- parent_1 = PyInt_AS_LONG(p1);
- parent_2 = PyInt_AS_LONG(p2);
- if (parent_1 >= 0)
- nothead[parent_1] = 1;
- if (parent_2 >= 0)
- nothead[parent_2] = 1;
}
for (i = 0; i < len; i++) {
--- a/tests/test-obsolete.t Tue May 26 12:08:50 2015 -0700
+++ b/tests/test-obsolete.t Tue May 26 12:09:04 2015 -0700
@@ -886,3 +886,33 @@
#endif
+Test heads computation on pending index changes with obsolescence markers
+ $ cd ..
+ $ cat >$TESTTMP/test_extension.py << EOF
+ > from mercurial import cmdutil
+ > from mercurial.i18n import _
+ >
+ > cmdtable = {}
+ > command = cmdutil.command(cmdtable)
+ > @command("amendtransient",[], _('hg amendtransient [rev]'))
+ > def amend(ui, repo, *pats, **opts):
+ > def commitfunc(ui, repo, message, match, opts):
+ > return repo.commit(message, repo['.'].user(), repo['.'].date(), match)
+ > opts['message'] = 'Test'
+ > opts['logfile'] = None
+ > cmdutil.amend(ui, repo, commitfunc, repo['.'], {}, pats, opts)
+ > print repo.changelog.headrevs()
+ > EOF
+ $ cat >> $HGRCPATH << EOF
+ > [extensions]
+ > testextension=$TESTTMP/test_extension.py
+ > EOF
+ $ hg init repo-issue-nativerevs-pending-changes
+ $ cd repo-issue-nativerevs-pending-changes
+ $ mkcommit a
+ $ mkcommit b
+ $ hg up ".^"
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ echo aa > a
+ $ hg amendtransient
+ [1, 3]