Differences between revisions 7 and 31 (spanning 24 versions)
Revision 7 as of 2006-12-19 20:00:17
Size: 2796
Editor: BrendanCully
Comment: Flesh out transplant merge
Revision 31 as of 2011-11-11 14:18:50
Size: 6153
Editor: PaulBoddie
Comment: Fixed formatting.
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
This extension allows you to transplant patches from another branch.
It records the original changeset ID in the transplanted changeset,
and avoids transplanting previously-transplanted patches. It can
also be used to rebase a branch against upstream changes (including
dropping changesets that have been adopted upstream).
== Transplant extension ==
'''This extension is distributed along with Mercurial.'''
Line 7: Line 4:
=== Using transplant to rewrite changesets === ''Author: Brendan Cully''
Line 9: Line 6:
The transplant extension accepts a {{{--filter}}} option, which lets you edit
the changelog message and patch before applying it to its destination (they
are supplied to the script as {{{$1}}} and {{{$2}}}, respectively). For
example, you could add a "Signed-off-by: " header to each changeset with
a script like this:
{i} The Cmd:graft command provides similar functionality in Mercurial 2.0 or newer.

=== Overview ===
This extension allows you to transplant patches from another branch or repository.

It records the original changeset ID in the transplanted changeset, and avoids transplanting previously-transplanted patches.

It can also be used to rebase a branch against upstream changes (including dropping changesets that have been adopted upstream), to rewrite changesets and to cherrypick some changesets.

Transplanted patches are recorded in a .hg/transplant/transplants file, as a map from a changeset hash to its hash in the source repository.

Selected changesets will be applied on top of the current working directory with the log of the original changeset. Optionally, the transplanted changeset changelog can show an additional comment to show which changeset it has been transplanted from.

=== Configuration ===
Enable the extension by adding following lines to a hgrc (~/.hgrc, .hg/hgrc, or /etc/mercurial/hgrc):
Line 16: Line 23:
[extensions]
transplant=
}}}
=== Usage ===
The extension can be used either as a normal command or interactively, using a text interface:

{{{hg transplant [-s REPOSITORY] [-b BRANCH [-a]] [-p REV] [-m REV] [REV]...}}}

where the options are:
||{{{-s}}} or {{{--source}}} ||pull patches from repository REPOSITORY ||
||{{{-b}}} or {{{--branch}}} ||pull patches from branch BRANCH ||
||{{{-a}}} or {{{--all}}} ||pull all changesets up to BRANCH ||
||{{{-p}}} or {{{--prune}}} ||skip over or prune REV ||
||{{{-m}}} or {{{--merge}}} ||merge at REV ||
||{{{--log}}} ||append transplant info to log message ||
||{{{-c}}} or {{{--continue}}} ||continue last transplant session after repair ||
||{{{--filter}}} ||filter changesets through FILTER ||




==== Using transplant in interactive mode ====
If no merges or revisions are provided to transplant, then it starts in interactive mode, showing a changeset browser to select the desired revisions to transplant.

==== Using transplant to cherrypick a set of changesets ====
Transplant can manage multiple changesets or changeset ranges like this:

{{{hg transplant REV1:REV2 REV3}}}

This example would cherrypick the range of changesets specified by REV1:REV2 and the additional changeset REV3 upon the working directory revision.

==== Using transplant to rebase some changesets ====
{{{hg transplant --branch REV4}}}

This example would rebase the changesets from REV4 till its (branch) head upon the working directory revision.

==== Using transplant to rewrite changesets using a filter ====
The transplant extension accepts a {{{--filter <filterprogram>}}} option, which lets you edit the changelog message and patch before applying it to its destination. The filenames of temporary files containing the changelog message and patch are supplied to the filter as the first two arguments, respectively ({{{$1}}} and {{{$2}}}, if the filter is a shell script).

If the filter exits with a non-zero exit status, the transplant operation will be aborted. If those files no longer exist, or are invalid after the filter exits the transplant operation will also be aborted. Otherwise, the contents of those files will be used when creating the new, transplanted changeset.

The changelog message file actually starts with three lines of information about the commit, followed by the exact changelog message. For example:

{{{
# HG changeset patch
# User erh
# Date 1276534440 18000
Change foo to bar.
}}}
The filter script is also passed the user and the original revision ID in environment variables HGUSER and HGREVISION respectively, which can then be used in the script. For example, you could add a "Signed-off-by: " header to each changeset with a script like this:

{{{#!sh
Line 20: Line 79:
Signed-off-by: Me Signed-off-by: $HGUSER
Line 24: Line 83:
As a slightly more complicated example, I used the following script to import
my transplant extension from a standalone repository into mercurial's {{{hgext}}}
folder (transplant uses git-style patches, so a little extra work was required):
As a slightly more complicated example, I used the following script to import my transplant extension from a standalone repository into mercurial's {{{hgext}}} folder (transplant uses git-style patches, so a little extra work was required):
Line 29: Line 86:
{{{
{{{#!sh
Line 35: Line 93:
# This performs an in-place (-i) modification of the $PATCH file
Line 45: Line 104:
=== Merging with transplants ===
==== Merging with transplants ====
Line 50: Line 108:
 2. Find the source node on the other tree.
 3. Perform a merge where the local node is the node found above (whichever is on the local branch) and the remote node is the "parent" of the corresponding node.
 4. Use the result as the merge base, skipping over the remote node found above, and repeat until the target heads are merged.
 1. Find the source node on the other tree.
 1. Perform a merge where the local node is the node found above (whichever is on the local branch) and the remote node is the "parent" of the corresponding node.
 1. Use the result as the merge base, skipping over the remote node found above, and repeat until the target heads are merged.
Line 62: Line 120:
      C -> c1 [constraint=false]       C -> c1 [constraint=false, color=lightgray]
Line 64: Line 122:
      c1 [shape="circle"]       c1 [style=fill, color=lightgray]
Line 67: Line 125:
Line 69: Line 126:
Line 75: Line 131:
     a -> b -> CM -> e -> F
     a -> C -> CM -> E -> F
     a -> b -> CM -> d -> e -> F
     a -> C -> CM -> D -> E -> F
Line 80: Line 136:
=== See also ===
 * [[RebasePlan|Rebase Command]]
Line 82: Line 140:
CategoryExtension CategoryBundledExtension

Transplant extension

This extension is distributed along with Mercurial.

Author: Brendan Cully

{i} The graft command provides similar functionality in Mercurial 2.0 or newer.

Overview

This extension allows you to transplant patches from another branch or repository.

It records the original changeset ID in the transplanted changeset, and avoids transplanting previously-transplanted patches.

It can also be used to rebase a branch against upstream changes (including dropping changesets that have been adopted upstream), to rewrite changesets and to cherrypick some changesets.

Transplanted patches are recorded in a .hg/transplant/transplants file, as a map from a changeset hash to its hash in the source repository.

Selected changesets will be applied on top of the current working directory with the log of the original changeset. Optionally, the transplanted changeset changelog can show an additional comment to show which changeset it has been transplanted from.

Configuration

Enable the extension by adding following lines to a hgrc (~/.hgrc, .hg/hgrc, or /etc/mercurial/hgrc):

[extensions]
transplant=

Usage

The extension can be used either as a normal command or interactively, using a text interface:

hg transplant [-s REPOSITORY] [-b BRANCH [-a]] [-p REV] [-m REV] [REV]...

where the options are:

-s or --source

pull patches from repository REPOSITORY

-b or --branch

pull patches from branch BRANCH

-a or --all

pull all changesets up to BRANCH

-p or --prune

skip over or prune REV

-m or --merge

merge at REV

--log

append transplant info to log message

-c or --continue

continue last transplant session after repair

--filter

filter changesets through FILTER

Using transplant in interactive mode

If no merges or revisions are provided to transplant, then it starts in interactive mode, showing a changeset browser to select the desired revisions to transplant.

Using transplant to cherrypick a set of changesets

Transplant can manage multiple changesets or changeset ranges like this:

hg transplant REV1:REV2 REV3

This example would cherrypick the range of changesets specified by REV1:REV2 and the additional changeset REV3 upon the working directory revision.

Using transplant to rebase some changesets

hg transplant --branch REV4

This example would rebase the changesets from REV4 till its (branch) head upon the working directory revision.

Using transplant to rewrite changesets using a filter

The transplant extension accepts a --filter <filterprogram> option, which lets you edit the changelog message and patch before applying it to its destination. The filenames of temporary files containing the changelog message and patch are supplied to the filter as the first two arguments, respectively ($1 and $2, if the filter is a shell script).

If the filter exits with a non-zero exit status, the transplant operation will be aborted. If those files no longer exist, or are invalid after the filter exits the transplant operation will also be aborted. Otherwise, the contents of those files will be used when creating the new, transplanted changeset.

The changelog message file actually starts with three lines of information about the commit, followed by the exact changelog message. For example:

# HG changeset patch
# User erh
# Date 1276534440 18000
Change foo to bar.

The filter script is also passed the user and the original revision ID in environment variables HGUSER and HGREVISION respectively, which can then be used in the script. For example, you could add a "Signed-off-by: " header to each changeset with a script like this:

#!/bin/sh

cat <<EOF >> "$1"

Signed-off-by: $HGUSER
EOF

As a slightly more complicated example, I used the following script to import my transplant extension from a standalone repository into mercurial's hgext folder (transplant uses git-style patches, so a little extra work was required):

import.sh:

#!/bin/sh

MESSAGE="$1"
PATCH="$2"

# This performs an in-place (-i) modification of the $PATCH file
sed -e's,^\(--- a/\)\|\(+++ b/\),&hgext/,' \
    -e'/^diff --git/s,a/\(.*\) b/\(.*\),a/hgext/\1 b/hgext/\2,' \
    -e's,^\(rename\|copy\) \(from\|to\) ,&hgext/', \
    -i "$PATCH"

I then did the import like so:

hg transplant -s ../transplant --filter import.sh 0:tip

Merging with transplants

Three-way merge doesn't cope particularly well with transplanted patches - it will tend to generate false conflicts. Here's a possible strategy for handling transplant merges that I mean to integrate into the transplant extension soon:

  1. Walk forward from the merge base to the first node that is transplanted from one tree to the other.
  2. Find the source node on the other tree.
  3. Perform a merge where the local node is the node found above (whichever is on the local branch) and the remote node is the "parent" of the corresponding node.
  4. Use the result as the merge base, skipping over the remote node found above, and repeat until the target heads are merged.

In the following example, c1 is transplanted from C.

To produce the merge node F, we'd start with a merge base of a, and merge local node C with remote node b to produce CM. We'd then use CM as a merge base for e and E to produce F:

See also


CategoryBundledExtension

TransplantExtension (last edited 2015-05-29 19:43:43 by mpm)