Find a file
Mirek Kratochvil 9dfe7b924d support colors
2025-07-15 10:22:57 +02:00
CHANGELOG.md initial somewhat works 2025-07-12 23:14:40 +02:00
LICENSE initial somewhat works 2025-07-12 23:14:40 +02:00
Main.hs clean up, support external tokenizers 2025-07-14 10:33:22 +02:00
Opts.hs support colors 2025-07-15 10:22:57 +02:00
README.md rm this 2025-07-14 10:56:09 +02:00
Toks.hs clean up, support external tokenizers 2025-07-14 10:33:22 +02:00
werge.cabal initial somewhat works 2025-07-12 23:14:40 +02:00

werge (merge weird stuff)

This is a partial work-alike of diff3 and git merge and other merge-y tools that is capable of

  • merging token-size changes instead of line-size ones
  • largely ignoring changes in blank characters

These properties are great for several use-cases:

  • merging free-flowing text changes (such as in TeX) irrespective of linebreaks etc,
  • merging of changesets that use different code formatters
  • minimizing the conflict size of tiny changes to a few characters, making them easier to resolve

How does it work?

  • Instead of lines, the files are torn to small tokens (words, spaces, symbols, ...) and these are diffed and merged individually.
  • Some tokens are marked as spaces by the tokenizer, which allows the merge algorithm to be (selectively) more zealous when resolving conflicts on these.

Tokenizers are simple, implementable as linear scanners that print separate tokens on individual lines that are prefixed with a space mark (. for space and | for non-space), and also escape newlines and backslashes. A default tokenization of string "hello \ world" with a new line at the end is listed below (note the invisible space on the lines with dots):

|hello
. 
|\\
. 
|world
.\n

Users may supply any tokenizer via option -F, e.g. this script makes line-size tokens (reproducing the usual line merges):

#!/usr/bin/env python3
import sys
for l in sys.stdin.readlines():
    if len(l)==0: continue
    if l[-1]=='\n':
        print('|'+l[:-1].replace('\\','\\\\')+'\\n')
    else:
        print('|'+l.replace('\\','\\\\'))

Installation

cabal install

Running of werge requires a working installation of diff compatible with the one from GNU diffutils. You may set up a path to such diff (or a wrapper script) via environment variable WERGE_DIFF.

Help & features

werge -- blanks-friendly mergetool for tiny interdwindled changes

Usage: werge [(-F|--tok-filter FILTER) | (-i|--simple-tokens) | 
               (-I|--full-tokens)] [-s|--spaces (normal|conflict|my|old|your)] 
             [-C|--expand-context N] [--no-zeal | (-z|--zeal)] 
             [--label-start STRING] [--label-mo STRING] [--label-oy STRING] 
             [--label-end STRING] [--conflict-overlaps] [--conflict-separate]
             COMMAND

Available options:
  -F,--tok-filter FILTER   external program to separate the text to tokens
  -i,--simple-tokens       use wider character class to separate the tokens
                           (results in larger tokens and ignores case)
  -I,--full-tokens         separate characters by all known character classes
                           (default)
  -s,--spaces (normal|conflict|my|old|your)
                           mode of merging the space-only changes; instead of
                           usual resolution one may choose to always conflict or
                           to default the space from the source files (default:
                           normal)
  -C,--expand-context N    Consider changes that are at most N tokens apart to
                           be a single change. Zero may cause bad resolutions of
                           near conflicting edits. (default: 1)
  --no-zeal                avoid zealous mode (default)
  -z,--zeal                try to zealously minify conflicts, potentially
                           resolving them
  --label-start STRING     label for beginning of the conflict
                           (default: "<<<<<")
  --label-mo STRING        separator of local edits and original
                           (default: "|||||")
  --label-oy STRING        separator of original and other people's edits
                           (default: "=====")
  --label-end STRING       label for end of the conflict (default: ">>>>>")
  --conflict-overlaps      do not resolve overlapping changes
  --conflict-separate      do not resolve separate (non-overlapping) changes
  -h,--help                Show this help text
  --version                Show version information

Available commands:
  merge                    diff3-style merge of two changesets
  git                      automerge unmerged files in git conflict

werge is a free software, use it accordingly.