Fossil Forum

Merge conflict common ancestor marker

Merge conflict common ancestor marker

(1) By anonymous on 2018-10-17 03:59:13 [link] [source]

Fossil merge conflict output is very informative and includes a common ancestor section:

I wonder if it's possible to use " " for the leading marker instead of "="?

This would make it agree with Git (diff3 mode), which in turn helps with visual tools that automatically highlight conflict sections and help in resolving it.

Basically, make the common ancestor header look something like:



(2) By anonymous on 2018-10-17 05:06:53 in reply to 1 [link] [source]

I wonder if it's possible to use "" for the leading marker instead of "="?

Should read "|" for the pipe-char.

Looks like our Markdown parser took the unescaped pipe for a table column separator. Interesting...

(3) By Warren Young (wyoung) on 2018-10-17 11:17:06 in reply to 1 [link] [source]

What tool are you using that doesn't understand Fossil's conflict markers? I'm pretty sure it's an old convention predating Fossil, which implies that it's your merge tool that needs to be changed, not Fossil.

(4) By anonymous on 2018-10-17 18:55:38 in reply to 3 [link] [source]

Perhaps it was not clear from my orginal post. Here's the comparison between conflict sections produced by Fossil vs Git.

Fossil conflict, src/merge3.c:

  <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
    puts 'hola world'
  ======= COMMON ANCESTOR content follows ============================
    puts 'hello world'
  ======= MERGED IN content follows ==================================
    putd 'hello mundo'
  >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Git conflict (diff3-style), Git - Advanced Merging:

  <<<<<<< ours
    puts 'hola world'
  ||||||| base
    puts 'hello world'
    puts 'hello mundo'
  >>>>>>> theirs

You can see that both formats are very much similar. However, the COMMON ANCESTOR section is marked differently. Git uses "|" (pipe-char) leading marker for the ancestor section and "=" for the merged-in section. Fossil uses "=" for both.

I could not find any specs that generally govern the formatting of the common ancestor section.

Git's convention does have two advantages:

  1. each section has its marker; this simplifies parsing by tools
  2. mnemonic meaning, "|" signifies center-line, with ours the the left, theirs on the right

Fossil's convention holds a descriptive advantage -- the verbose labels make section contents more clear.

TLDR; By adopting "|" for Fossil's common ancestor section leading mark, it would equally simplify the parsing.

So, what I ask is to have Fossil output the confict with a format like this (?maybe a config option):

  <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<
    puts 'hola world'
  ||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||
    puts 'hello world'
  ======= MERGED IN content follows ==================================
    putd 'hello mundo'
  >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Git's convention is the most visible online and thus has a better chance for support by visual tools.

(5) By andygoth on 2018-10-17 20:22:10 in reply to 4 [link] [source]

Are you suggesting merging the merge marker conventions? ;^)

I think this is a good change. I definitely prefer our merge marker format over git's format, but that doesn't mean we can't meet in the middle, and your proposal certainly does that.

Please allow me to disagree that this change simplifies parsing tools. I dislike parsing tools that take shortcuts since they are susceptible to false positives. It is best to parse the whole line. Better still is to maintain state so that, for example, the >>>>>>> merge marker means nothing unless it comes after ======= without any intervening merge markers. Don't get me wrong; this is not a complaint. It's just a word of caution.

(6.1) By sebyte on 2019-11-14 09:08:34 edited from 6.0 in reply to 1 [link] [source]

I would like to second this call.

As far as I can tell, use of the pipe character has nothing to do with Git, per se. Rather, it is a Gnu diff3 convention:

Accordingly, Emacs' Simple Merge mode (smerge-mode.el) has matched conflict markers in source files like so:

(defconst smerge-begin-re "^<<<<<<< \\(.*\\)\n")
(defconst smerge-base-re "^||||||| \\(.*\\)\n")
(defconst smerge-lower-re "^=======\n")
(defconst smerge-end-re "^>>>>>>> \\(.*\\)\n")

since approx. 1999.

In my opinion, a diff3-conflict-markers setting defaulting to off would be a sensible addition.


In the meantime, adding the following to your dotemacs is a possible workaround:

(defun smerge-try-smerge-mode ()
    (goto-char (point-min))
    (when (re-search-forward "^<<<<<<< " nil t)
      (require 'smerge-mode)
      (when (eq (vc-deduce-backend) 'Fossil)
        (mapc #'make-variable-buffer-local
              '(smerge-base-re smerge-lower-re))
        (setq smerge-base-re ; "^||||||| \\(.*\\)\n"
          "^======= COMMON ANCESTOR \\(.*\\)\n"
          smerge-lower-re ; "^=======\n"
          "^======= MERGED IN .*\n"))
      (smerge-mode 1))))
(add-hook 'find-file-hook 'smerge-try-smerge-mode t)

This assumes you have vc-fossil.el:


(7.1) By sebyte on 2021-03-09 18:57:20 edited from 7.0 in reply to 1 [link] [source]

This change was made 9th May 2020. (Thanks to ashepilko for making the change). However, Fossil's conflict markers still differ slightly from those made by diff3.

Firstly, as described in Marking conflicts, diff3 writes beginning-of-conflict markers on new lines, i.e, the beginning-of-conflict marker always starts at column zero.

Fossil usually inserts beginning-of-conflict markers starting at column zero but may occasionally insert them at the end of the line.

Secondly, the diff3 end-of-lines-from-B marker (=======) is never followed by anything on the same line.

Fossil's end-of-lines-from-B marker is: ======= MERGED IN content follows ===[...].

These are the only two reamining differences, and they are easy to work around.

If you add the following to your init file, Emacs' Simple Merge mode should work well with Fossil's conflict markers:

(defun smerge-try-smerge-mode ()
  (require 'smerge-mode)
  (let* ((fossil-begin-re (substring smerge-begin-re 1)) ; strip the `^'
            (goto-char (point-min))
            (re-search-forward fossil-begin-re nil t))))
    (when applicable-p
      (require 'vc)
      (when (eq (vc-deduce-backend) 'Fossil)
         smerge-begin-re fossil-begin-re ; was "^<<<<<<< \\(.*\\)\n"
         smerge-lower-re "^=======.*\n"  ; was "^=======\n"
         (concat smerge-begin-re "\\|" smerge-end-re "\\|"
                 smerge-base-re "\\|" smerge-lower-re "\\|")))
      (goto-char (point-min))

(add-hook 'find-file-hook 'smerge-try-smerge-mode t)

[Edited to reflect feedback in subsequent post].

(8) By Stephan Beal (stephan) on 2021-03-09 17:38:39 in reply to 7.0 [link] [source]

As far as I can tell, Fossil may insert beginning-of-conflict markers anywhere in the line, often at the end.

In 13 years of using it i've never seen it put them anywhere but on their own lines.

(9) By sebyte on 2021-03-09 18:53:10 in reply to 8 [source]

That's interesting.

As a mostly solitary programmer and a relatively new Fossil user, I've only encountered conflicts using Fossil twice. On the second occasion, today, the beginning-of-conflict marker was in Fossil file .fossil-settings/ignore-glob and it appeared at the end of the line:

*sqlite3-see.*<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<                                                                                        
||||||| COMMON ANCESTOR content follows ||||||||||||||||||||||||||||                                                                                                      
======= MERGED IN content follows ==================================                                                                                                      
>>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>                                                                                                      

I shall edit my previous post to reflect your much greater experience.

(10) By Warren Young (wyoung) on 2021-03-09 19:03:01 in reply to 9 [link] [source]

Is this by chance a CRLF-terminated (DOS) text file?

(11) By sebyte on 2021-03-09 19:22:31 in reply to 10 [link] [source]

Nope. No chance at all. I run Debian GNU/Linux everywhere.

(12) By John Rouillard (rouilj) on 2021-03-09 19:35:13 in reply to 10 [link] [source]

$2 says that the original file didn't have a newline at the end of the file. So the marker appears appended at the end of the line.

(13) By Larry Brasfield (larrybr) on 2021-03-09 19:57:24 in reply to 12 [link] [source]

Does such a well isolated whitespace difference trip up the auto-merge? That would be surprising to me.

(14) By sebyte on 2021-03-09 20:06:18 in reply to 12 [link] [source]

That's what I thought initially, but this hex dump proves otherwise.

(15) By Stephan Beal (stephan) on 2021-03-10 03:48:13 in reply to 9 [link] [source]

the beginning-of-conflict marker was in Fossil file .fossil-settings/ignore-glob and it appeared at the end of the line:

Looking at the code which injects the markers:


i can see no indication that it makes an effort to start the markers on their own lines, but i've never seen it not do that.

You've shown us that the file uses Unix-style newlines, but did both of the copies being merged have them? It's vaguely conceivable that a mixed-mode merge might hiccup like that (if it can be called a hiccup - it's not "wrong" per se, just weird).

(16) By sebyte on 2021-03-10 10:09:04 in reply to 15 [link] [source]

Your vague conception is spot on.

The merge is between .fossil-settings/ignore-glob on my personal branch and the same file on trunk. Sure enough, the trunk version does not end with a new line, as demonstrated by this hexdump.

I suppose the question now is whether or not src/merge3.c should prevent this from happening.

I will feel more confident submitting a patch for Emacs' Simple Merge mode if the only change is to the pattern matching the end-of-lines-from-B marker (currently "^=======\n").

(17) By Stephan Beal (stephan) on 2021-03-10 10:33:53 in reply to 16 [link] [source]

I suppose the question now is whether or not src/merge3.c should prevent this from happening.

It's not broken if it can still detect them later when it wants to report a conflict (but see below). Those markers are for fossil, not for arbitrary software. e.g. the commit process checks all files for those markers and rejects the commit unless a flag is used to force it. However, insofar as i can determine it only looks for them at the start of a line (otherwise the merge markers themselves in merge.c would trigger that warning).

An admittedly cursory examination of this line:


suggests that it might skip over such a "misplaced" marker. The has-conflict-marker check checks for any one of the 4 marker lines, though, so for that to break (if it would - i haven't tested it) all four of the markers would have to be somewhere other than at the start of a line.

Worst case, at this point:


we can look back one byte for \n, and output one if there isn't one and we're not at the start of the output.

If you'd like to patch that i'd be happy to test it for you.

(18) By sebyte on 2021-03-10 11:01:06 in reply to 17 [link] [source]

That's a kind offer, thank you, but I'm not a C programmer so I wouldn't know where to begin.

(19) By Stephan Beal (stephan) on 2021-03-10 12:44:32 in reply to 18 [link] [source]

I'm not a C programmer so I wouldn't know where to begin.

It's moot - Richard already patched it :).

(20) By sebyte on 2021-03-10 15:18:13 in reply to 19 [link] [source]

Great! Thank you everyone, especially Richard & Stephan.

The previously suggested init file code needed to make Emacs' Simple Merge minor mode play nicely with Fossil now looks like this:

(defun smerge-try-smerge-mode ()
  (require 'smerge-mode)
  (when (save-excursion
          (goto-char (point-min))
          (re-search-forward smerge-begin-re nil t))
    (require 'vc)
    (when (eq (vc-deduce-backend) 'Fossil)
       smerge-lower-re "^=======.*\n" ; was "^=======\n"
       (concat smerge-begin-re "\\|" smerge-end-re "\\|"
               smerge-base-re "\\|" smerge-lower-re "\\|")))
    (goto-char (point-min))

(add-hook 'find-file-hook 'smerge-try-smerge-mode t)

To be clear, this does more than simply adapt the mode to Fossil's conflict markers. It automatically activates the mode in file buffers which contain conflict markers of any kind(†). The adaptations are only made when necessary, i.e. when Fossil is being used.

† Provided the beginning-of-conflict marker matches pattern "^<<<<<<< \\(.*\\)\n").

(21) By anonymous on 2021-03-11 18:18:33 in reply to 20 [link] [source]

(Not emacs user). It appears that Fossil's merge conflict indicators seem to be very similar to Git's. Maybe there's a way to make use of what's already there in emacs to support Git?

For example,