Note:

This page appears to contain material that is no longer relevant. Please help improve this page by updating its content.

Merging Modified Patches

The problem

Using MqExtension one can edit patches in any order.

If some patch is modified (edit files, hg qrefresh), the change may conflict with patches that apply on top of this patch. When this happens, hg qpush complains, and creates .rej reject files. The conflict then has to be resolved manually, using editor, and the patch that conflicted can be refreshed using hg qrefresh. This process may have to be repeated if more patches apply on top and cause conflicts.

Manual resolution of conflicts using .rej files is much less convenient than the usual Mercurial merge process.

A different, though related, problem is when the changes in a patch conflict with previously applied patches, or with the base files. The solution provided here does not apply to that problem.

Solution

One can modify MqMerge procedure to apply it to conflicting patches and use the power of Mercurial merge process for resolving patch conflicts, and avoid .rej files.

Knowing in advance

If one knows in advance that edit of some patch would cause conflicts with patches applied on top of it, do the following:

# Push all patches.
hg qpush -a

# Find out what is the qparent revision.
hg log --template '{rev}:{node|short}\n' -r qparent
# Take note of printed <qparent> revision; note the treatment
#    of qparent = 000000000000 below.

# Save the patch queue state.
hg qsave -e -c
# Take note of patches.<N>

# Go to revision before any patches are applied.
# [TODO: can this step be skipped? If yes, hg log can be skipped too]
hg update <qparent>

# Go to the patch you want to edit.
hg qpush -m
# Repeat until you reach the patch you want to edit,
# or you could use hg qgoto <mypatch>.

# Edit the files.

# Reflect the changes in the patch.
hg qrefresh

# Push all patches, using hg to perform merges.
hg qpush -m -a

# Cleanup
hg qpop -a
hg qpop -a -n patches.<N>
rm -rf .hg/patches.<N>

A somewhat special case occurs when the patch queue is applied atop a fresh repository (i.e., no commits to the working directory were made before applying the patch queue), meaning the hg log command will list the qparent as -1:000000000000. When performing the hg update, either use hg update -r 000000000000 or hg update -r null; hg update -r -1 will be interpreted as an alias for the tip and will actually not change the working directory.

Not knowing in advance

If you don't know in advance that patch edit will cause a conflict with subsequent patches (a common case) you can still use the above procedure, if you have somewhere a version of the patch before hg qrefresh. For example, if you use versioned patch queues (initialized with hg qinit -c) you could retrieve the old version from the patch repository.

# Save the refreshed patch
cp -i .hg/patches/mypatch ~/

# Restore the previous version of the patch.
# For example:
mq revert .hg/patches/mypatch

# Pop all patches
hg qpop -a

The above "restore" command assumes that versioned patches are used (see above), and that the changes to the patches haven't been committed yet, but the changes before the patch update have been committed. If all changes have been committed you can use mq revert -r <revision> .hg/patches/mypatch. Also, this assumes that a convenience alias was defined: alias mq='hg -R $(hg root)/.hg/patches'. In any case, the key is that you have to have the previous version of this patch somewhere, and you need to restore the patch in mq to that version (after saving the new version).

Now, follow the above merge procedure until "Edit the files". Then:

# Put back the modified patch into the patch queue
cp ~/mypatch .hg/patches/

# Pop and push the make mq use this patch
hg qpop
hg qpush

Now, continue with the merge procedure starting with hg qpush -m -a.

MqMergePatches (last edited 2012-05-08 14:14:42 by 46-116-136-37)