# How to create patches for a merge?

5 messages from 2010-02-18 to 2010-02-20. Participants: Geoffrey Lee, Junio C Hamano, Jeff King, Clemens Buchacher.
Thread: https://gitlist.dev/t/22709

## Geoffrey Lee, 2010-02-18 11:40

Subject: How to create patches for a merge?
Message-ID: <83d7aaa41002180340p2f9b7241h9c220b84ec5dd1d@mail.gmail.com>
URL: https://gitlist.dev/e/83d7aaa41002180340p2f9b7241h9c220b84ec5dd1d%40mail.gmail.com

```
When I use "git format-patch", it doesn't seem to include merges. How
can I perform a merge and then e-mail it to someone as a set of
patches?

For example, let's say that I merge two branches and perform another
commit on top of the merge:

git init

echo "initial file" > test.txt
git add test.txt
git commit -m "Commit A"

git checkout -b foo master
echo "foo" > test.txt
git commit -a -m "Commit B"

git checkout -b bar master
echo "bar" > test.txt
git commit -a -m "Commit C"

git merge foo
echo "foobar" > test.txt
git commit -a -m "Commit M"

echo "2nd line" >> test.txt
git commit -a -m "Commit D"

This creates the following tree:

    B
  /   \
A       M - D
  \   /
    C

Now I try to checkout the initial commit and replay the above changes:

git checkout -b replay master
git format-patch --stdout master..bar | git am -3

This produces a merge conflict. In this scenario, "git format-patch
master..bar" only produces 3 patches, omitting "Commit M". How do I
deal with this?

-Geoffrey Lee

```

## Junio C Hamano, 2010-02-18 18:10

Subject: Re: How to create patches for a merge?
Message-ID: <7veikifm9m.fsf@alter.siamese.dyndns.org>
URL: https://gitlist.dev/e/7veikifm9m.fsf%40alter.siamese.dyndns.org
In-Reply-To: <83d7aaa41002180340p2f9b7241h9c220b84ec5dd1d@mail.gmail.com>

```
Geoffrey Lee <geoffreyj.lee@gmail.com> writes:

> This produces a merge conflict. In this scenario, "git format-patch
> master..bar" only produces 3 patches, omitting "Commit M". How do I
> deal with this?

There is no provision for communicating how a conflict is resolved over
patches.  The answer to your "How do I deal with *this*" question would be
"It is up to you.", if your "*this*" is "I want to communicate this as a
patch".  The steps to deal with "*this*" may go like this:

 - Think what shape of patch you want to see in order to convey what
   "Commit M" did to the recipient of your patch series.  First, try to
   construct it, by hand if necessary, as a design of such a feature.

 - How would a recipient "apply" such a patch?  As commonly used "patch"
   implementations, including "git apply", may not be able to read the
   above format, and they would certainly not create a merge commit, so
   you need to design the recieving side as well.

 - Then implement them ;-)

The best I think of offhand to reproduce

     B---M---D
    /   /
   A---C

might go like this:

 (1) Emit diff between (A,B) as usual;

 (2) Emit diff between (A,C) as usual, but with additional information
     usually not found in regular patches to help recipient that this
     should be applied to the same commit as (1) is applied to;

 (3) Emit diff between (B,M) and (C,M), but make sure that they won't be
     seen as a patch to be applied by ordinary "patch" programs to avoid
     mistakes at the recipient side.  Include some way to tell the
     recipient that these two "patches" need to be applied to the results
     of applying (1) and (2), and that the result needs to be recorded as
     a merge between them.

 (4) Emit D as usual;

Then the recipient would start from something that resembles A (call it X)
and do the following:

 (5) Apply (1); call that result B'

       B'
      /
     X

 (6) Apply (2), following that additional insn to apply the patch to the
     base of (5); call that result C'

       B'
      /
     X---C'

 (7) Apply (B,M) half of (3) to B' and call it M'


       B'..M'
      /
     X---C'

 (8) Apply (C,M) half of (3) to C' and call it M"

       B'--M' M"
      /      .
     X------C'

 (9) If M' and M" do not match (which can happen when A and X are majorly
     different), merge them using X as their common ancestor, and resolve
     conflicts as necessary, and call the result M'".

     If M' and M" do match, be happy and call either of them M'".

         B'..M'..M'"                B'..M'"
        /       .       or         /   . 
       /       M"                 X---C'
      /       .
     X-------C'

 (10) Record M'" as children of B' and C'.

       B'--M'"
      /   /
     X---C'

 (11) Apply (4); call that result D'

        B'--M'"-D'
      /   /
     X---C'

and you are done.

```

## Jeff King, 2010-02-18 20:37

Subject: Re: How to create patches for a merge?
Message-ID: <20100218203738.GB8110@coredump.intra.peff.net>
URL: https://gitlist.dev/e/20100218203738.GB8110%40coredump.intra.peff.net
In-Reply-To: <83d7aaa41002180340p2f9b7241h9c220b84ec5dd1d@mail.gmail.com>

```
On Thu, Feb 18, 2010 at 03:40:07AM -0800, Geoffrey Lee wrote:

> When I use "git format-patch", it doesn't seem to include merges. How
> can I perform a merge and then e-mail it to someone as a set of
> patches?

Is it important that it be patches, or simply that it go over email? In
the latter case, you can use "git bundle" to create a set of commits,
including merges, and send them to the remote.

-Peff

```

## Geoffrey Lee, 2010-02-19 10:25

Subject: Re: How to create patches for a merge?
Message-ID: <83d7aaa41002190225o3255248re1581a86e1346f28@mail.gmail.com>
URL: https://gitlist.dev/e/83d7aaa41002190225o3255248re1581a86e1346f28%40mail.gmail.com
In-Reply-To: <20100218203738.GB8110@coredump.intra.peff.net>

```
On Thu, Feb 18, 2010 at 12:37 PM, Jeff King <peff@peff.net> wrote:
> On Thu, Feb 18, 2010 at 03:40:07AM -0800, Geoffrey Lee wrote:
>
>> When I use "git format-patch", it doesn't seem to include merges. How
>> can I perform a merge and then e-mail it to someone as a set of
>> patches?
>
> Is it important that it be patches, or simply that it go over email? In
> the latter case, you can use "git bundle" to create a set of commits,
> including merges, and send them to the remote.

I was not aware of "git bundle". That does exactly what I need. Thanks!

-Geoffrey Lee

```

## Clemens Buchacher, 2010-02-20 17:39

Subject: Re: How to create patches for a merge?
Message-ID: <20100220173910.GA4095@localhost>
URL: https://gitlist.dev/e/20100220173910.GA4095%40localhost
In-Reply-To: <83d7aaa41002190225o3255248re1581a86e1346f28@mail.gmail.com>

```
On Fri, Feb 19, 2010 at 02:25:14AM -0800, Geoffrey Lee wrote:
> On Thu, Feb 18, 2010 at 12:37 PM, Jeff King <peff@peff.net> wrote:
> > On Thu, Feb 18, 2010 at 03:40:07AM -0800, Geoffrey Lee wrote:
> >
> >> When I use "git format-patch", it doesn't seem to include merges. How
> >> can I perform a merge and then e-mail it to someone as a set of
> >> patches?
> >
> > Is it important that it be patches, or simply that it go over email? In
> > the latter case, you can use "git bundle" to create a set of commits,
> > including merges, and send them to the remote.
> 
> I was not aware of "git bundle". That does exactly what I need. Thanks!

Below is git-send-bdl, a small wrapper I use for git bundle. It creates
bundles only for the commits which are not already known to the origin and
mails them to a configured address. It requires mutt for sending emails (the
-m option is just for show).  It should probably use sendmail. But maybe
this is still useful as a reference.

Have fun,
Clemens
---

#!/bin/bash

usage ()
{
	echo "`basename $0`: [-t <address>] [-m <mailer>] [-r <remote>] [<repo>...]" >&2
	exit 1
}

if ! test -x `which getopt`
then
	echo "fatal: getopt required but not found" >&2
	exit 2
fi

OPT=`getopt -o et:m:r: -- "$@"`
code=$?
if test $code -gt 0
then
	usage
	exit 1
fi
eval set -- "$OPT"

mailer=${GIT_SEND_BDL_MAILER:-mutt}
remote=origin
addr=
edit=
while test "$1" != "--"
do
	case "$1" in
		-r) remote="$2"; shift;;
		-m) mailer="$2"; shift;;
		-t) addr="$addr $2"; shift;;
		-e) edit=YesPlease;;
		-h) usage;;
		*) echo "unkown option: $1" >&2; exit 2;;
	esac
	shift
done
shift

if test -z $addr
then
	addr="$GIT_SEND_BDL_TO"
fi

if test $# -eq 0
then
	cdup=`git rev-parse --show-cdup 2>/dev/null`
	if test $? -gt 0
	then
		echo "fatal: no repositories specified and none found" >&2
		usage
	fi
	set -- "$PWD/${cdup}"
fi

if test -z "$addr"
then
	echo "fatal: no recipients specified" >&2
	usage
fi

if ! test -x `which $mailer`
then
	echo "fatal: mailer not found: $mailer" >&2
	usage
fi

bundle=()
while test $# -gt 0
do
	path=$1
	shift
	cd $path
	name=`basename "$PWD"`
	echo " * $name"
	target=/tmp/${name}.git
	if ! git remote | grep -q "^$remote\$"
	then
		echo error: unknown remote: $remote >&2
		continue
	fi
	refs="--branches"
	remote_refs=`git show-ref | cut -f2 -d' ' | \
			grep ^refs/remotes/$remote/`
	if test -n "$remote_refs"
	then
		refs="$refs --not $remote_refs"
	fi
	refs="$refs --tags"
	git bundle create $target $refs
	cd - >/dev/null
	bundle[${#bundle[@]}]=$target
done

attachments=
for i in ${bundle[@]}
do
	if test -f $i
	then
		attachments="$attachments $i"
	fi
done

exec 3</dev/null
if test -n "$edit"
then
	exec 3<&0
fi
$mailer -s 'git bundles' -a $attachments -- $addr <&3
ret=$?
exec 3<&-
if test $ret -gt 0
then
	echo "fatal: mailer exited with status $ret" >&2
	exit 1
fi

rm -f ${bundle[@]}

```
