merge(1) uses an ed script internally to apply changes to merged files,
It fails to properly merge files which contain lines starting with a dot,
as in the following example:

Save these lines as file1:

./etc/signify/openbsd-66-base.pub
./etc/signify/openbsd-66-fw.pub
./etc/signify/openbsd-66-pkg.pub
./etc/signify/openbsd-66-syspatch.pub
./etc/signify/openbsd-67-base.pub
./etc/skel
./etc/skel/.ssh

Save these lines as file2:

./etc/signify/openbsd-66-base.pub
./etc/signify/openbsd-66-fw.pub
./etc/signify/openbsd-66-pkg.pub
./etc/signify/openbsd-66-syspatch.pub
./etc/skel
./etc/skel/.ssh

Save these lines as file3:

./etc/signify/openbsd-66-base.pub
./etc/signify/openbsd-66-fw.pub
./etc/signify/openbsd-66-pkg.pub
./etc/signify/openbsd-66-syspatch.pub
./etc/signify/openbsd-67-base.pub
./etc/signify/openbsd-67-pkg.pub
./etc/skel
./etc/skel/.ssh

Now run: merge -p file1 file2 file3

The output will be:

./etc/signify/openbsd-66-base.pub
./etc/signify/openbsd-66-fw.pub
./etc/signify/openbsd-66-pkg.pub
./etc/signify/openbsd-66-syspatch.pub
<<<<<<< 1
./etc/signify/openbsd-67-base.pub
=======
./etc/skel
./etc/skel/.ssh

No line with a 67 package key, and no trailing conflict marker!
They are missing because the built-in ed script interpreter considers
the leading dot on this line as a "dot on a line by itself" command:

./etc/signify/openbsd-67-pkg.pub

The code only checks for the existence of a leading dot on the line,
not whether the dot appears on a line by itself.

With the patch below, the merged result looks as expected:

./etc/signify/openbsd-66-base.pub
./etc/signify/openbsd-66-fw.pub
./etc/signify/openbsd-66-pkg.pub
./etc/signify/openbsd-66-syspatch.pub
<<<<<<< 1
./etc/signify/openbsd-67-base.pub
=======
./etc/signify/openbsd-67-base.pub
./etc/signify/openbsd-67-pkg.pub
>>>>>>> 3
./etc/skel
./etc/skel/.ssh

Problem found in Game of Trees, which uses diff3 code derived from merge(1).

ok?

diff e875c3a0682a8180b4f2b861af260412eca02c28 /usr/src
blob - 16cc1b29ff5f7ecd37951b7e464496f0f0b9d6fa
file + usr.bin/rcs/diff3.c
--- usr.bin/rcs/diff3.c
+++ usr.bin/rcs/diff3.c
@@ -496,7 +496,8 @@ ed_patch_lines(struct rcs_lines *dlines, struct rcs_li
                                if (lp == NULL)
                                        errx(1, "ed_patch_lines");
 
-                               if (!memcmp(lp->l_line, ".", 1))
+                               if (lp->l_len >= 2 &&
+                                   !memcmp(lp->l_line, ".", lp->l_len - 2))
                                        break;
 
                                TAILQ_REMOVE(&(plines->l_lines), lp, l_list);

Reply via email to