[gnu.emacs] auto-merge in GNU Emacs

jberk@pretzel.sw.stratus.com (Joe Berkovitz) (02/02/90)

Is there anyone who knows of (or has written) any .el code to
interactively reconcile or merge two different revisions of
a text file into a single copy?

This is for use in situations where a source file has been
modified in parallel by two people, and the two sets of changes
need to be reconciled.  It would be nice to have emacs put up
the two originals and the merged output in 3 different buffers,
and have it walk one through the different merged areas to
inspect and approve or recursively edit each change.  I suspect
that "diff3" or "diff" could be invoked as a child process to
do most of the comparison work; emacs would merely need to
scan the resulting output for line numbers, etc.

If no one knows of such, I may end up doing it myself and posting
the results anyway.  

Thanks much,

Joe Berkovitz @ Stratus Computer, Inc.
(jberk@pretzel.sw.stratus.com)

merlyn@iwarp.intel.com (Randal Schwartz) (02/02/90)

In article <665@lectroid.sw.stratus.com>, jberk@pretzel (Joe Berkovitz) writes:
| Is there anyone who knows of (or has written) any .el code to
| interactively reconcile or merge two different revisions of
| a text file into a single copy?

I wrote some Elisp code to feed the old and new file through diff
-D___NEW___ which marks the old text and new text cleanly, and then
bound a few keys to say "select the next old chunk (discarding the new
chunk)" or "select the next new chunk (discarding the old chunk)".
That worked, more or less, but it was a bit of a kludge.  Let me know
if you want to start with that.

Just another GNU Emacs hacker,
-- 
/=Randal L. Schwartz, Stonehenge Consulting Services (503)777-0095 ==========\
| on contract to Intel's iWarp project, Beaverton, Oregon, USA, Sol III      |
| merlyn@iwarp.intel.com ...!any-MX-mailer-like-uunet!iwarp.intel.com!merlyn |
\=Cute Quote: "Welcome to Portland, Oregon, home of the California Raisins!"=/

moss@takahe.cs.umass.edu (Eliot &) (02/02/90)

I picked up a package called "emerge" that can compare two variants, or two
variants with a specified common ancestor, and let you choose how to merge
each differing part. It looks like a snazzy, complete package, but I have not
yet had the time/opportunity to learn it. Some of the documentation is
enclosed below; enjoy!

From: drw@math.mit.edu (Dale R. Worley)
Newsgroups: comp.emacs,gnu.emacs
Subject: Emerge - merge two files or buffers, documentation (part 1 of 2)
Date: 23 Sep 89 04:44:38 GMT
Followup-To: comp.emacs

This is the documentation for "emerge.el", an Emacs package that
allows you to combine two versions of a file by selecting, for each
place where they differ, which version of the difference you prefer.
It is similar to Sun's "filemerge".

Written by Dale R. Worley, drw@math.mit.edu.

- Starting

To start Emerge, you must run one of four commands:

	emerge-files
	emerge-files-with-ancestor
	emerge-buffers
	emerge-buffers-with-ancestor

The "files" versions prompt you for two file names (the "A" and "B"
files), the "buffers" versions prompt you for two buffer names (the
"A" and "B" buffers).  Emerge then runs a "diff" of the two entities
(emerge-buffers writes the buffers into temporary files for input to
diff) and digests the output to form a list of the differences between
the two files.  Then three buffers are set up: two containing the
entities (emerge-files does a find-file (C-x C-f) on the files to get
them into buffers), and one, the "merge buffer", which contains the
working copy of the merged file that you are constructing.  The three
buffers are put up in a nice three-window display, showing the A and B
buffers in the upper half and the merge buffer in the lower half.

The versions of the command that say "with-ancestor" ask for a third
name, that of an entity which is a common ancestor from which the
versions being merged were derived.  These commands use "diff3" to
compare all three versions.  If one version of a difference agrees
with the ancestor, then it is presumed that the other version is the
"correct" version, and is said to be "preferred".

(Note that if you use emerge-files, there is no guarantee that the
disk version of a file agrees with its buffer version -- find-file
doesn't check.  So make sure you save the files first!)

During the merge, the A and B buffers are read-only, so you don't
damage them.  (This is because the A and B versions of the differences
are extracted from these buffers.)  When you quit the merge, the
read-only/read-write status and modified flag on the A and B buffers
are restored.  In addition, auto-saving of the A and B buffers is
suppressed during the merge.  This is because Emerge modifies the A
and B buffers to point out the text of the differences, and it would
be useless to save these changes.  (Just before suppressing
auto-saving, Emerge forces an auto-save.)

You can have any number of merges going at once -- just don't use any
one buffer as input to more than one merge at once, since that will
cause the read-only/modified/auto-save status save-and-restore to
screw up.

- Merging

Once you have started the merge, you manipulate the merge buffer with
special commands issued in the merge buffer.  You may also edit the
buffer with ordinary Emacs commands.  Emerge keeps track of each
difference between the A and B buffers and the corresponding section
of the merge buffer.  Initially, all differences show the A version,
except those for which B is preferred (because A agrees with the
ancestor), which show the B version.  Emerge always has its attention
focused on one particular difference, which is marked off in the three
buffers by "vvvvvvvvvvvvvvvvvvvv" above and "^^^^^^^^^^^^^^^^^^^^"
below.  The number of the difference is shown in the mode line.

A merge buffer can be in two modes: "fast" mode and "edit" mode.  In
fast mode, emerge commands are single characters, and ordinary Emacs
commands are disabled.  This makes Emerge operations fast, but
prevents you from doing more than selecing the A or the B version of
differences.  In edit mode, all emerge commands must be prefixed with
C-c, and all (non-conflicting) Emacs commands are available.  This
allows editing the merge buffer, but slows down Emerge operations.
Edit and fast modes are indicated by "F" and "E" in the minor modes in
the mode line.

The Emerge commands are:

	p	go to the previous difference
	n	go to the next difference
	a	select the A version of this difference
	b	select the B version of this difference
	j	go to a particular difference (prefix argument
		specifies which difference)
	q	quit - finish the merge*
	f	go into fast mode
	e	go into edit mode
	C-a	set/clear auto-advance mode*
	C-s	set/clear skip-prefers mode*
	C-l	recenter (C-l) all three windows*
	- and 0-9
		numeric arguments
	M-a	select the A version as the default from here down in
		the merge buffer*
	M-b	select the B version as the default from here down in
		the merge buffer*

* - more details on these commands are given below

- Differences and their states

A difference can have one of six states:

A:  the difference is showing the A version.

B:  the difference is showing the B version.

default-A and default-B: the difference is showing the A or B state,
but has never been selected by the user.  All differences start in the
default-A state (and thus the merge buffer is a copy of the A buffer),
except those for which one buffer or another is preferred.  When the
user selects the difference, it changes to the A or B state.

prefer-A and prefer-B: the difference is showing the A or B state.  In
addition, the other buffer (that is, for prefer-A, the B buffer; for
prefer-B, the A buffer) agrees with the ancestor buffer.  Thus,
presumably, the displayed version is the correct one.  The "a" and "b"
commands override these states, and turn them into the A and B states.

The state of the currently selected difference is shown in the mode
line of the merge window:

	state		display

	A		A
	B		B
	prefer-A	A*
	prefer-B	B*

- Select default commands (M-a and M-b)

The M-a and M-b commands change all default-A's to default-B's (or
vice-versa) from the selected difference on down to the end of the
file to default-A or default-B, respectively.  Thus, a difference that
has been selected will never be affected by M-a or M-b.  This leads to
the unexpected result that M-a or M-b never affects the difference
selected at the moment, but prevents differences that you have already
looked at from changing unexpectedly.

If you work your way down from the top of the file, using M-a and M-b
at judicious points, you can effectivly make the A version the default
for some sections of the merge buffer and the B version the default
for others.

- Exiting (q)

The quit command finishes the merge session by restoring the state of
the A and B buffers and removing the markers around the currently
selected difference.  It also disables the Emerge commands in the
merge buffer, since executing them later could damage the contents of
the various buffers.

If "q" is given a prefix argument, Emerge attempts to replace the
contents of the file that the A buffer is visiting with the contents
of the merge buffer.  The A buffer is given a temporary name, the
merge buffer is named after the file (and set to visit the file), and
the merge buffer is written to disk.

- Auto-advance mode (C-a)

If auto-advance mode is set, the "a" and "b" commands perform an "n"
(select next difference) afterward.  When auto-advance mode is set,
it is indicated by "A" in the minor modes in the mode line.
"C-a" with a positive argument sets auto-advance, with a non-positive
argument clears it, and with no argument toggles it.

- Skip-prefers mode (C-a)

If skip-prefers mode is set, the "n" and "p" commands skip over
differences with states prefer-A and prefer-B.  Thus you will only see
differences for which one version isn't presumed "correct".  When
skip-prefers mode is set, it is indicated by "S" in the minor modes in
the mode line.  "C-s" with a positive argument sets auto-advance, with
a non-positive argument clears it, and with no argument toggles it.

- Recenter (C-l)

The Emerge "C-l" command causes the "recenter" command (C-l) to be
executed in all three windows.  Any prefix argument is passed to each
recenter.  Particularly useful is "0 C-l", which causes the points
(pointing to the first lines of the difference texts) to be positioned
to the top lines of the windows.
--

		J. Eliot B. Moss, Assistant Professor
		Department of Computer and Information Science
		Lederle Graduate Research Center
		University of Massachusetts
		Amherst, MA  01003
		(413) 545-4206; Moss@cs.umass.edu