aboutsummaryrefslogtreecommitdiffstats
path: root/t
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2026-09-22 19:53:29 +0200
committerMattias Andrée <m@maandree.se>2026-09-22 19:53:29 +0200
commitd8de1b23e8ec896759424a2f146969783cdd89e3 (patch)
treeed1ea3e97add5116230fd2df34e42b829a70ab39 /t
parentfix doc text (diff)
downloadgit-rediff-d8de1b23e8ec896759424a2f146969783cdd89e3.tar.gz
git-rediff-d8de1b23e8ec896759424a2f146969783cdd89e3.tar.bz2
git-rediff-d8de1b23e8ec896759424a2f146969783cdd89e3.tar.xz
Add conflcit resultions strategies and interactive mode, and a lot of tests1.1
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to '')
-rwxr-xr-xt/all-positive-options-merge23
-rwxr-xr-xt/all-positive-options-select-head23
-rwxr-xr-xt/all-positive-options-select-tail23
-rwxr-xr-xt/combination-2-interactive19
-rwxr-xr-xt/combination-2-merge20
-rwxr-xr-xt/combination-2-remove-base27
-rwxr-xr-xt/combination-2-select-head22
-rwxr-xr-xt/combination-2-select-tail22
-rwxr-xr-xt/combination-interactive-2-no-interactive29
-rwxr-xr-xt/combination-merge-2-no-merge28
-rwxr-xr-xt/combination-merge-reduce36
-rwxr-xr-xt/combination-remove-base-2-no-remove-base28
-rwxr-xr-xt/combination-remove-base-merge-reduce34
-rwxr-xr-xt/combination-remove-base-reduce38
-rwxr-xr-xt/combination-remove-base-select-head-reduce18
-rwxr-xr-xt/combination-remove-base-select-tail-reduce18
-rwxr-xr-xt/combination-select-head-2-no-select-head28
-rwxr-xr-xt/combination-select-head-reduce30
-rwxr-xr-xt/combination-select-tail-2-no-select-tail28
-rwxr-xr-xt/combination-select-tail-reduce30
-rw-r--r--t/common.sh165
-rwxr-xr-xt/interactive-edit64
-rwxr-xr-xt/interactive-help28
-rwxr-xr-xt/interactive-multiple-commands113
-rwxr-xr-xt/interactive-short-option46
-rwxr-xr-xt/interactive-skip30
-rwxr-xr-xt/interactive-two-files44
-rwxr-xr-xt/invalid-option-combinations20
-rwxr-xr-xt/marker-size-1018
-rwxr-xr-xt/marker-size-318
-rwxr-xr-xt/marker-size-longer-ignored16
-rwxr-xr-xt/marker-size-shorter-ignored16
-rwxr-xr-xt/merge-111
-rwxr-xr-xt/merge-2-different15
-rwxr-xr-xt/merge-2-identical15
-rwxr-xr-xt/merge-base17
-rwxr-xr-xt/merge-empty-base16
-rwxr-xr-xt/merge-empty-head16
-rwxr-xr-xt/merge-empty-tail16
-rwxr-xr-xt/merge-head18
-rwxr-xr-xt/merge-head-420
-rwxr-xr-xt/merge-lower-middle-428
-rwxr-xr-xt/merge-multiple-conflicts34
-rwxr-xr-xt/merge-multiple-files30
-rwxr-xr-xt/merge-no-conflicts11
-rwxr-xr-xt/merge-short-option18
-rwxr-xr-xt/merge-tail18
-rwxr-xr-xt/merge-tail-420
-rwxr-xr-xt/merge-upper-middle-428
-rwxr-xr-xt/missing-newline-non-conflict10
-rwxr-xr-xt/mixed-marker-sizes30
-rwxr-xr-xt/no-option-interactive30
-rwxr-xr-xt/no-option-interactive-no-yes20
-rwxr-xr-xt/no-option-interactive-yes-no19
-rwxr-xr-xt/no-option-merge28
-rwxr-xr-xt/no-option-merge-no-yes18
-rwxr-xr-xt/no-option-merge-yes-no17
-rwxr-xr-xt/no-option-reduce20
-rwxr-xr-xt/no-option-reduce-no-yes17
-rwxr-xr-xt/no-option-reduce-yes-no17
-rwxr-xr-xt/no-option-remove-base28
-rwxr-xr-xt/no-option-remove-base-no-yes22
-rwxr-xr-xt/no-option-remove-base-yes-no24
-rwxr-xr-xt/no-option-select-head28
-rwxr-xr-xt/no-option-select-head-no-yes18
-rwxr-xr-xt/no-option-select-head-yes-no17
-rwxr-xr-xt/no-option-select-head-yes-then-select-tail-yes-no18
-rwxr-xr-xt/no-option-select-tail28
-rwxr-xr-xt/no-option-select-tail-no-yes18
-rwxr-xr-xt/no-option-select-tail-yes-no17
-rwxr-xr-xt/no-option-select-tail-yes-then-select-head-yes-no18
-rwxr-xr-xt/no-reduce17
-rwxr-xr-xt/no-reduce-111
-rwxr-xr-xt/no-reduce-2-files24
-rwxr-xr-xt/no-reduce-2-full19
-rwxr-xr-xt/no-reduce-2-head21
-rwxr-xr-xt/no-reduce-2-hunks21
-rwxr-xr-xt/no-reduce-2-middle25
-rwxr-xr-xt/no-reduce-2-multiple-partial33
-rwxr-xr-xt/no-reduce-2-non-aligned27
-rwxr-xr-xt/no-reduce-2-none17
-rwxr-xr-xt/no-reduce-2-tail21
-rwxr-xr-xt/no-reduce-3-full23
-rwxr-xr-xt/no-reduce-3-head26
-rwxr-xr-xt/no-reduce-3-middle32
-rwxr-xr-xt/no-reduce-3-multiple-partial44
-rwxr-xr-xt/no-reduce-3-none20
-rwxr-xr-xt/no-reduce-3-tail26
-rwxr-xr-xt/no-reduce-4-full27
-rwxr-xr-xt/no-reduce-4-head31
-rwxr-xr-xt/no-reduce-4-middle39
-rwxr-xr-xt/no-reduce-4-multiple-partial55
-rwxr-xr-xt/no-reduce-4-none23
-rwxr-xr-xt/no-reduce-4-tail31
-rwxr-xr-xt/no-reduce-5-full31
-rwxr-xr-xt/no-reduce-5-head36
-rwxr-xr-xt/no-reduce-5-middle46
-rwxr-xr-xt/no-reduce-5-multiple-partial66
-rwxr-xr-xt/no-reduce-5-none26
-rwxr-xr-xt/no-reduce-5-tail36
-rwxr-xr-xt/no-reduce-dashdash-dashprefix17
-rwxr-xr-xt/no-reduce-empty-base16
-rwxr-xr-xt/no-reduce-empty-head16
-rwxr-xr-xt/no-reduce-empty-tail16
-rwxr-xr-xt/no-reduce-no-conflicts11
-rwxr-xr-xt/null-bytes15
-rwxr-xr-xt/reduce-19
-rwxr-xr-xt/reduce-2-files26
-rwxr-xr-xt/reduce-2-full22
-rwxr-xr-xt/reduce-2-head30
-rwxr-xr-xt/reduce-2-hunks24
-rwxr-xr-xt/reduce-2-middle41
-rwxr-xr-xt/reduce-2-multiple-partial53
-rwxr-xr-xt/reduce-2-non-aligned43
-rwxr-xr-xt/reduce-2-none24
-rwxr-xr-xt/reduce-2-tail30
-rwxr-xr-xt/reduce-3-full26
-rwxr-xr-xt/reduce-3-head38
-rwxr-xr-xt/reduce-3-middle54
-rwxr-xr-xt/reduce-3-multiple-partial70
-rwxr-xr-xt/reduce-3-none30
-rwxr-xr-xt/reduce-3-tail38
-rwxr-xr-xt/reduce-4-full30
-rwxr-xr-xt/reduce-4-head46
-rwxr-xr-xt/reduce-4-middle67
-rwxr-xr-xt/reduce-4-multiple-partial87
-rwxr-xr-xt/reduce-4-none36
-rwxr-xr-xt/reduce-4-tail46
-rwxr-xr-xt/reduce-5-full34
-rwxr-xr-xt/reduce-5-head54
-rwxr-xr-xt/reduce-5-middle80
-rwxr-xr-xt/reduce-5-multiple-partial104
-rwxr-xr-xt/reduce-5-none42
-rwxr-xr-xt/reduce-5-tail54
-rwxr-xr-xt/reduce-empty-base16
-rwxr-xr-xt/reduce-empty-head16
-rwxr-xr-xt/reduce-empty-tail16
-rwxr-xr-xt/reduce-is-default23
-rwxr-xr-xt/reduce-no-conflicts11
-rwxr-xr-xt/remove-base-112
-rwxr-xr-xt/remove-base-215
-rwxr-xr-xt/remove-base-322
-rwxr-xr-xt/remove-base-3-empty-base21
-rwxr-xr-xt/remove-base-3-empty-head20
-rwxr-xr-xt/remove-base-3-empty-tail20
-rwxr-xr-xt/remove-base-419
-rwxr-xr-xt/remove-base-521
-rwxr-xr-xt/remove-base-multiple-files33
-rwxr-xr-xt/remove-base-multiple-hunks36
-rwxr-xr-xt/remove-base-no-conflicts11
-rwxr-xr-xt/select-head-112
-rwxr-xr-xt/select-head-216
-rwxr-xr-xt/select-head-318
-rwxr-xr-xt/select-head-3-empty-base17
-rwxr-xr-xt/select-head-3-empty-head16
-rwxr-xr-xt/select-head-3-empty-tail17
-rwxr-xr-xt/select-head-422
-rwxr-xr-xt/select-head-multiple-files30
-rwxr-xr-xt/select-head-multiple-hunks28
-rwxr-xr-xt/select-head-no-conflicts11
-rwxr-xr-xt/select-tail-112
-rwxr-xr-xt/select-tail-216
-rwxr-xr-xt/select-tail-318
-rwxr-xr-xt/select-tail-3-empty-base17
-rwxr-xr-xt/select-tail-3-empty-head17
-rwxr-xr-xt/select-tail-3-empty-tail16
-rwxr-xr-xt/select-tail-422
-rwxr-xr-xt/select-tail-multiple-files30
-rwxr-xr-xt/select-tail-multiple-hunks28
-rwxr-xr-xt/select-tail-no-conflicts11
-rwxr-xr-xt/stdin-dash-operand21
-rwxr-xr-xt/stdin-dashdash-dash-operand21
-rwxr-xr-xt/stdin-dashdash-no-operand21
-rwxr-xr-xt/stdin-no-operand21
-rwxr-xr-xt/unclosed-conflict-head12
-rwxr-xr-xt/unclosed-conflict-head-parent14
-rwxr-xr-xt/unclosed-conflict-head-parent-tail16
-rwxr-xr-xt/unclosed-conflict-head-tail14
-rwxr-xr-xt/unexpected-separator-end11
-rwxr-xr-xt/unexpected-separator-parent11
-rwxr-xr-xt/unexpected-separator-tail11
181 files changed, 4937 insertions, 0 deletions
diff --git a/t/all-positive-options-merge b/t/all-positive-options-merge
new file mode 100755
index 0000000..eeb21d0
--- /dev/null
+++ b/t/all-positive-options-merge
@@ -0,0 +1,23 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ ours
+
+printf '%s' h > input
+normal --merge --remove-base --reduce --interactive file 8<input 9>output
+test -s output
diff --git a/t/all-positive-options-select-head b/t/all-positive-options-select-head
new file mode 100755
index 0000000..999dc31
--- /dev/null
+++ b/t/all-positive-options-select-head
@@ -0,0 +1,23 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ ours
+
+printf '%s' h > input
+normal --select-head --remove-base --reduce --interactive file 8<input 9>output
+test -s output
diff --git a/t/all-positive-options-select-tail b/t/all-positive-options-select-tail
new file mode 100755
index 0000000..dbf72a7
--- /dev/null
+++ b/t/all-positive-options-select-tail
@@ -0,0 +1,23 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ ours
+
+printf '%s' h > input
+normal --select-tail --remove-base --reduce --interactive file 8<input 9>output
+test -s output
diff --git a/t/combination-2-interactive b/t/combination-2-interactive
new file mode 100755
index 0000000..d2cb14e
--- /dev/null
+++ b/t/combination-2-interactive
@@ -0,0 +1,19 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ ours
+
+printf '%s' h > input
+normal --interactive --interactive file 8<input 9>output
+test -s output
diff --git a/t/combination-2-merge b/t/combination-2-merge
new file mode 100755
index 0000000..5379244
--- /dev/null
+++ b/t/combination-2-merge
@@ -0,0 +1,20 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ ours \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --merge --merge --no-reduce file
+
+also_interactive m
diff --git a/t/combination-2-remove-base b/t/combination-2-remove-base
new file mode 100755
index 0000000..a7db4cd
--- /dev/null
+++ b/t/combination-2-remove-base
@@ -0,0 +1,27 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+conflict --remove-base --remove-base --no-reduce file
+
+also_interactive bb
diff --git a/t/combination-2-select-head b/t/combination-2-select-head
new file mode 100755
index 0000000..e326f15
--- /dev/null
+++ b/t/combination-2-select-head
@@ -0,0 +1,22 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ ours
+
+normal --select-head --select-head --no-reduce file
+
+also_interactive h
diff --git a/t/combination-2-select-tail b/t/combination-2-select-tail
new file mode 100755
index 0000000..594e315
--- /dev/null
+++ b/t/combination-2-select-tail
@@ -0,0 +1,22 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ theirs
+
+normal --select-tail --select-tail --no-reduce file
+
+also_interactive t
diff --git a/t/combination-interactive-2-no-interactive b/t/combination-interactive-2-no-interactive
new file mode 100755
index 0000000..1126b8c
--- /dev/null
+++ b/t/combination-interactive-2-no-interactive
@@ -0,0 +1,29 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s' q > input
+conflict --interactive --no-interactive --no-interactive file 8<input 9>output
+test ! -s output
diff --git a/t/combination-merge-2-no-merge b/t/combination-merge-2-no-merge
new file mode 100755
index 0000000..e249817
--- /dev/null
+++ b/t/combination-merge-2-no-merge
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ ours \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ ours \
+ "${END} theirs"
+
+conflict --merge --no-merge --no-merge file
+
+also_interactive rr
diff --git a/t/combination-merge-reduce b/t/combination-merge-reduce
new file mode 100755
index 0000000..aec3a30
--- /dev/null
+++ b/t/combination-merge-reduce
@@ -0,0 +1,36 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ first \
+ "${PARENT} base" \
+ not first \
+ "${TAIL}" \
+ not first \
+ "${END} theirs" \
+ "${HEAD} ours" \
+ ours \
+ common \
+ "${PARENT} base" \
+ base \
+ common \
+ "${TAIL}" \
+ theirs \
+ common \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ first \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs" \
+ common
+
+conflict --merge --reduce file
+
+also_interactive mm
diff --git a/t/combination-remove-base-2-no-remove-base b/t/combination-remove-base-2-no-remove-base
new file mode 100755
index 0000000..835e751
--- /dev/null
+++ b/t/combination-remove-base-2-no-remove-base
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --remove-base --no-remove-base --no-remove-base file
+
+also_interactive rr
diff --git a/t/combination-remove-base-merge-reduce b/t/combination-remove-base-merge-reduce
new file mode 100755
index 0000000..48025c4
--- /dev/null
+++ b/t/combination-remove-base-merge-reduce
@@ -0,0 +1,34 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ not first \
+ "${PARENT} base" \
+ not first \
+ "${TAIL}" \
+ first \
+ "${END} theirs" \
+ "${HEAD} ours" \
+ ours \
+ common \
+ "${PARENT} base" \
+ base \
+ common \
+ "${TAIL}" \
+ theirs \
+ common \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ first \
+ "${HEAD} ours" \
+ ours \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs" \
+ common
+
+conflict --remove-base --merge --reduce file
+
+also_interactive mm
diff --git a/t/combination-remove-base-reduce b/t/combination-remove-base-reduce
new file mode 100755
index 0000000..952681e
--- /dev/null
+++ b/t/combination-remove-base-reduce
@@ -0,0 +1,38 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs" \
+ "${HEAD} ours" \
+ ours \
+ common \
+ "${PARENT} base" \
+ base \
+ common \
+ "${TAIL}" \
+ theirs \
+ common \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ "${HEAD} ours" \
+ ours \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs" \
+ "${HEAD} ours" \
+ ours \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs" \
+ common
+
+conflict --remove-base --reduce file
+
+also_interactive bbbb
diff --git a/t/combination-remove-base-select-head-reduce b/t/combination-remove-base-select-head-reduce
new file mode 100755
index 0000000..96e828d
--- /dev/null
+++ b/t/combination-remove-base-select-head-reduce
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ ours
+
+normal --remove-base --select-head --reduce file
+
+also_interactive h
diff --git a/t/combination-remove-base-select-tail-reduce b/t/combination-remove-base-select-tail-reduce
new file mode 100755
index 0000000..8e0f465
--- /dev/null
+++ b/t/combination-remove-base-select-tail-reduce
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ theirs
+
+normal --remove-base --select-tail --reduce file
+
+also_interactive t
diff --git a/t/combination-select-head-2-no-select-head b/t/combination-select-head-2-no-select-head
new file mode 100755
index 0000000..06a1464
--- /dev/null
+++ b/t/combination-select-head-2-no-select-head
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --select-head --no-select-head --no-select-head file
+
+also_interactive rr
diff --git a/t/combination-select-head-reduce b/t/combination-select-head-reduce
new file mode 100755
index 0000000..796f613
--- /dev/null
+++ b/t/combination-select-head-reduce
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ first \
+ "${PARENT} base" \
+ not first \
+ "${TAIL}" \
+ not first \
+ "${END} theirs" \
+ "${HEAD} ours" \
+ ours \
+ common \
+ "${PARENT} base" \
+ base \
+ common \
+ "${TAIL}" \
+ theirs \
+ common \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ first \
+ ours \
+ common
+
+normal --select-head --reduce file
+
+also_interactive hh
diff --git a/t/combination-select-tail-2-no-select-tail b/t/combination-select-tail-2-no-select-tail
new file mode 100755
index 0000000..55eb1d6
--- /dev/null
+++ b/t/combination-select-tail-2-no-select-tail
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --select-tail --no-select-tail --no-select-tail file
+
+also_interactive rr
diff --git a/t/combination-select-tail-reduce b/t/combination-select-tail-reduce
new file mode 100755
index 0000000..c1504ac
--- /dev/null
+++ b/t/combination-select-tail-reduce
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ not first \
+ "${PARENT} base" \
+ not first \
+ "${TAIL}" \
+ first \
+ "${END} theirs" \
+ "${HEAD} ours" \
+ ours \
+ common \
+ "${PARENT} base" \
+ base \
+ common \
+ "${TAIL}" \
+ theirs \
+ common \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ first \
+ theirs \
+ common
+
+normal --select-tail --reduce file
+
+also_interactive tt
diff --git a/t/common.sh b/t/common.sh
new file mode 100644
index 0000000..30e4b6e
--- /dev/null
+++ b/t/common.sh
@@ -0,0 +1,165 @@
+set -eu
+
+tmp=testdir.$$
+command="../git-rediff"
+
+interactive () {
+ test $# = 0
+ command="../git-rediff.t"
+}
+
+cleanup () {
+ cd -- ..
+ rm -rf -- "${tmp}"
+}
+
+trap cleanup 0 HUP INT TERM
+
+mkdir -- "${tmp}"
+cd -- "${tmp}"
+git init -q .
+git config user.email test@example.invalid
+git config user.name test
+
+set_marker_variables () {
+ test $# = 1
+ HEAD="$(printf '%*.s\n' "$1" '' | tr ' ' '<')"
+ PARENT="$(printf '%*.s\n' "$1" '' | tr ' ' '|')"
+ TAIL="$(printf '%*.s\n' "$1" '' | tr ' ' '=')"
+ END="$(printf '%*.s\n' "$1" '' | tr ' ' '>')"
+}
+
+set_marker_variables 7
+
+set_conflict_marker_size () {
+ test $# = 2
+ # $1 = marker size
+ # $2 = affected file
+ set_marker_variables "$1"
+ printf '%s conflict-marker-size=%s\n' "$2" "$1" >> .gitattributes
+}
+
+again_command=''
+
+save_files () {
+ while test ! $# = 0; do
+ if test "$1" = - || test "$1" = --; then
+ shift 1
+ break
+ elif printf '%s\n' "$1" | grep -q '^-'; then
+ shift 1
+ else
+ break
+ fi
+ done
+ for f; do
+ if test ! "$f" = -; then
+ cp -- "$f" "$f".original
+ fi
+ done
+}
+
+no_error () {
+ test -z "${again_command}"
+ again_command="$*"
+ shift 1
+ save_files "$@"
+ set +e
+ "$command" "$@"
+ status=$?
+ set -e
+ while test ! $# = 0; do
+ if test "$1" = - || test "$1" = --; then
+ shift 1
+ break
+ elif printf '%s\n' "$1" | grep -q '^-'; then
+ shift 1
+ else
+ break
+ fi
+ done
+ for f; do
+ if test ! "$f" = -; then
+ diff -u -- "$f" "$f".expected >&2
+ cp -- "$f".original "$f"
+ fi
+ done
+}
+
+normal () {
+ no_error normal "$@"
+ test $status = 0
+}
+
+conflict () {
+ no_error conflict "$@"
+ test $status = 1
+}
+
+error () {
+ set +e
+ "$command" "$@" 2>/dev/null
+ status=$?
+ set -e
+ test $status = 2
+}
+
+also_interactive () {
+ test $# = 1
+ test -n "${again_command}"
+ cmd="${again_command}"
+ again_command=''
+ interactive
+ printf '%s' "$1" > i-input
+ ${cmd} 8<i-input 9>/dev/null
+}
+
+interactive_line () {
+ test $# = 2
+ printf '\e[%sm%s\n\e[0m' "$1" "$2"
+}
+
+interactive_marker () {
+ test $# = 1
+ interactive_line 36 "$1"
+}
+
+interactive_side () {
+ test $# = 1
+ interactive_line 32 "$1"
+}
+
+interactive_base () {
+ test $# = 1
+ interactive_line 31 "$1"
+}
+
+interactive_filename () {
+ test $# = 1
+ printf '\e[1m%s\e[0m\n' "$1"
+}
+
+interactive_prompt () {
+ test $# = 2
+ printf '\e[1;34m(%s/%s) Resolve this conflict [h,t,b,m,r,e,s,d,q,?]? \e[0m\n' "$1" "$2"
+}
+
+interactive_help () {
+ test $# = 1
+ printf '\e[1;31m'
+ printf '%s\n' \
+ 'h - select head' \
+ 't - select tail'
+ if test "$1" = 3; then
+ printf '%s\n' 'b - remove base'
+ fi
+ printf '%s\n' \
+ 'm - merge' \
+ 'r - reduce' \
+ 'e - manually edit this hunk' \
+ 's - skip this hunk' \
+ 'd - skip this hunk and all later hunks in the file' \
+ 'q - quit; skip this hunk and all remaining hunks' \
+ '? - print help'
+ printf '\e[0m'
+}
diff --git a/t/interactive-edit b/t/interactive-edit
new file mode 100755
index 0000000..e0ff7b4
--- /dev/null
+++ b/t/interactive-edit
@@ -0,0 +1,64 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ head \
+ "${TAIL}" \
+ tail \
+ "${END} theirs"
+
+for editor in EDITOR VISUAL CORE_EDITOR REDIFF_EDITOR GIT_EDITOR; do
+ printf '%s\n' > "${editor}" \
+ '#!/bin/sh -e' \
+ 'printf "%s\\n" "$(basename -- "$0")" > "$1"'
+ chmod +x -- "$editor"
+done
+
+printf '%s\n' \
+ '#!/bin/sh -e' \
+ 'printf "%s\\n" vi > "$1"' > ./vi
+chmod +x ./vi
+
+(
+ interactive_marker "${HEAD} ours"
+ interactive_side head
+ interactive_marker "${TAIL}"
+ interactive_side tail
+ interactive_marker "${END} theirs"
+ interactive_prompt 1 1
+) > output.expected
+
+run_editor_test () {
+ printf '%s\n' "$1" > file.expected
+ shift 1
+
+ unset GIT_EDITOR VISUAL EDITOR
+ git config --local --unset-all core.editor || :
+ git config --local --unset-all rediff.editor || :
+
+ while test ! $# = 0; do
+ if test "$1" = VI; then
+ export PATH=".:${PATH}"
+ elif test "$1" = CORE_EDITOR; then
+ git config core.editor ./CORE_EDITOR
+ elif test "$1" = REDIFF_EDITOR; then
+ git config rediff.editor ./REDIFF_EDITOR
+ else
+ eval "export $1=./$1"
+ fi
+ shift 1
+ done
+ printf '%s' e > input
+ normal --interactive file 8<input 9>output
+ diff -u -- output.expected output >&2
+ again_command=''
+}
+
+run_editor_test vi VI
+run_editor_test EDITOR EDITOR
+run_editor_test VISUAL EDITOR VISUAL
+run_editor_test CORE_EDITOR EDITOR VISUAL CORE_EDITOR
+run_editor_test REDIFF_EDITOR EDITOR VISUAL CORE_EDITOR REDIFF_EDITOR
+run_editor_test GIT_EDITOR EDITOR VISUAL CORE_EDITOR REDIFF_EDITOR GIT_EDITOR
diff --git a/t/interactive-help b/t/interactive-help
new file mode 100755
index 0000000..398d9dc
--- /dev/null
+++ b/t/interactive-help
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ head \
+ "${TAIL}" \
+ tail \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ head
+
+(
+ interactive_marker "${HEAD} ours"
+ interactive_side head
+ interactive_marker "${TAIL}"
+ interactive_side tail
+ interactive_marker "${END} theirs"
+ interactive_prompt 1 1
+ interactive_help 2
+ interactive_prompt 1 1
+) > output.expected
+
+printf '%s' '?h' > input
+normal --interactive file 8<input 9>output
+diff -u -- output.expected output >&2
diff --git a/t/interactive-multiple-commands b/t/interactive-multiple-commands
new file mode 100755
index 0000000..a279541
--- /dev/null
+++ b/t/interactive-multiple-commands
@@ -0,0 +1,113 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ head \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ tail \
+ "${END} theirs" \
+ "${HEAD} ours" \
+ head \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ tail \
+ "${END} theirs" \
+ "${HEAD} ours" \
+ head \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ tail \
+ "${END} theirs" \
+ "${HEAD} ours" \
+ first \
+ "${PARENT} base" \
+ not first \
+ "${TAIL}" \
+ not first \
+ "${END} theirs" \
+ "${HEAD} ours" \
+ ours \
+ common \
+ "${PARENT} base" \
+ base \
+ common \
+ "${TAIL}" \
+ theirs \
+ common \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ head \
+ tail \
+ "${HEAD} ours" \
+ head \
+ "${TAIL}" \
+ tail \
+ "${END} theirs" \
+ first \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs" \
+ common
+
+(
+ interactive_marker "${HEAD} ours"
+ interactive_side head
+ interactive_marker "${PARENT} base"
+ interactive_base base
+ interactive_marker "${TAIL}"
+ interactive_side tail
+ interactive_marker "${END} theirs"
+ interactive_prompt 1 5
+ interactive_marker "${HEAD} ours"
+ interactive_side head
+ interactive_marker "${PARENT} base"
+ interactive_base base
+ interactive_marker "${TAIL}"
+ interactive_side tail
+ interactive_marker "${END} theirs"
+ interactive_prompt 2 5
+ interactive_marker "${HEAD} ours"
+ interactive_side head
+ interactive_marker "${PARENT} base"
+ interactive_base base
+ interactive_marker "${TAIL}"
+ interactive_side tail
+ interactive_marker "${END} theirs"
+ interactive_prompt 3 5
+ interactive_marker "${HEAD} ours"
+ interactive_side first
+ interactive_marker "${PARENT} base"
+ interactive_base not
+ interactive_base first
+ interactive_marker "${TAIL}"
+ interactive_side not
+ interactive_side first
+ interactive_marker "${END} theirs"
+ interactive_prompt 4 5
+ interactive_marker "${HEAD} ours"
+ interactive_side ours
+ interactive_side common
+ interactive_marker "${PARENT} base"
+ interactive_base base
+ interactive_base common
+ interactive_marker "${TAIL}"
+ interactive_side theirs
+ interactive_side common
+ interactive_marker "${END} theirs"
+ interactive_prompt 5 5
+) > output.expected
+
+printf '%s' htbmr > input
+conflict --interactive file 8<input 9>output
+diff -u -- output.expected output >&2
diff --git a/t/interactive-short-option b/t/interactive-short-option
new file mode 100755
index 0000000..904f7e2
--- /dev/null
+++ b/t/interactive-short-option
@@ -0,0 +1,46 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours-1 \
+ "${PARENT} base" \
+ base-1 \
+ "${TAIL}" \
+ theirs-1 \
+ "${END} theirs" \
+ "${HEAD} ours" \
+ ours-2 \
+ "${PARENT} base" \
+ base-2 \
+ "${TAIL}" \
+ theirs-2 \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ theirs-1 \
+ ours-2
+
+(
+ interactive_marker "${HEAD} ours"
+ interactive_side ours-1
+ interactive_marker "${PARENT} base"
+ interactive_base base-1
+ interactive_marker "${TAIL}"
+ interactive_side theirs-1
+ interactive_marker "${END} theirs"
+ interactive_prompt 1 2
+ interactive_marker "${HEAD} ours"
+ interactive_side ours-2
+ interactive_marker "${PARENT} base"
+ interactive_base base-2
+ interactive_marker "${TAIL}"
+ interactive_side theirs-2
+ interactive_marker "${END} theirs"
+ interactive_prompt 2 2
+) > output.expected
+
+printf '%s' th > input
+normal -i file 8<input 9>output
+diff -u -- output.expected output >&2
diff --git a/t/interactive-skip b/t/interactive-skip
new file mode 100755
index 0000000..baf9e1b
--- /dev/null
+++ b/t/interactive-skip
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ head \
+ "${TAIL}" \
+ tail \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ "${HEAD} ours" \
+ head \
+ "${TAIL}" \
+ tail \
+ "${END} theirs"
+
+(
+ interactive_marker "${HEAD} ours"
+ interactive_side head
+ interactive_marker "${TAIL}"
+ interactive_side tail
+ interactive_marker "${END} theirs"
+ interactive_prompt 1 1
+) > output.expected
+
+printf '%s' s > input
+conflict --interactive file 8<input 9>output
+diff -u -- output.expected output >&2
diff --git a/t/interactive-two-files b/t/interactive-two-files
new file mode 100755
index 0000000..c2c3f02
--- /dev/null
+++ b/t/interactive-two-files
@@ -0,0 +1,44 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours-1 \
+ "${TAIL}" \
+ theirs-1 \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ theirs-1
+
+printf '%s\n' > file2 \
+ "${HEAD} ours" \
+ ours-2 \
+ "${TAIL}" \
+ theirs-2 \
+ "${END} theirs"
+
+printf '%s\n' > file2.expected \
+ ours-2
+
+(
+ interactive_filename file
+ interactive_marker "${HEAD} ours"
+ interactive_side ours-1
+ interactive_marker "${TAIL}"
+ interactive_side theirs-1
+ interactive_marker "${END} theirs"
+ interactive_prompt 1 1
+ interactive_filename file2
+ interactive_marker "${HEAD} ours"
+ interactive_side ours-2
+ interactive_marker "${TAIL}"
+ interactive_side theirs-2
+ interactive_marker "${END} theirs"
+ interactive_prompt 1 1
+) > output.expected
+
+printf '%s' th > input
+normal --interactive file file2 8<input 9>output
+diff -u -- output.expected output >&2
diff --git a/t/invalid-option-combinations b/t/invalid-option-combinations
new file mode 100755
index 0000000..527ce63
--- /dev/null
+++ b/t/invalid-option-combinations
@@ -0,0 +1,20 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' text > file
+cp -- file file.expected
+
+error --merge --select-head file
+error --select-head --merge file
+error --merge --select-tail file
+error --select-tail --merge file
+error --select-head --select-tail file
+error --select-tail --select-head file
+error --merge --select-head --select-tail file
+error --merge --select-tail --select-head file
+error --select-head --merge --select-tail file
+error --select-head --select-tail --merge file
+error --select-tail --merge --select-head file
+error --select-tail --select-head --merge file
+error --unknown-option file
+error '-$' file
diff --git a/t/marker-size-10 b/t/marker-size-10
new file mode 100755
index 0000000..38fdc8d
--- /dev/null
+++ b/t/marker-size-10
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+set_conflict_marker_size 10 file
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same
+
+normal file
+
+also_interactive r
diff --git a/t/marker-size-3 b/t/marker-size-3
new file mode 100755
index 0000000..1cab4dd
--- /dev/null
+++ b/t/marker-size-3
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+set_conflict_marker_size 3 file
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} theirs'"
+
+printf '%s\n' > file.expected \
+ same
+
+normal file
+
+also_interactive r
diff --git a/t/marker-size-longer-ignored b/t/marker-size-longer-ignored
new file mode 100755
index 0000000..4453d7f
--- /dev/null
+++ b/t/marker-size-longer-ignored
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+set_conflict_marker_size 3 file
+
+printf '%s\n' > file \
+ '<<<< not a marker' \
+ '|||| not a marker' \
+ '==== not a marker' \
+ '>>>> not a marker'
+
+cp -- file file.expected
+
+normal file
+
+also_interactive ''
diff --git a/t/marker-size-shorter-ignored b/t/marker-size-shorter-ignored
new file mode 100755
index 0000000..cf16be7
--- /dev/null
+++ b/t/marker-size-shorter-ignored
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+set_conflict_marker_size 3 file
+
+printf '%s\n' > file \
+ '<< not a marker' \
+ '| not a marker' \
+ '== not a marker' \
+ '> not a marker'
+
+cp -- file file.expected
+
+normal file
+
+also_interactive ''
diff --git a/t/merge-1 b/t/merge-1
new file mode 100755
index 0000000..5967f4e
--- /dev/null
+++ b/t/merge-1
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} only" \
+ only \
+ "${END} only"
+
+cp -- file file.expected
+
+error --merge --no-reduce file
diff --git a/t/merge-2-different b/t/merge-2-different
new file mode 100755
index 0000000..b27a88e
--- /dev/null
+++ b/t/merge-2-different
@@ -0,0 +1,15 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --merge --no-reduce file
+
+also_interactive m
diff --git a/t/merge-2-identical b/t/merge-2-identical
new file mode 100755
index 0000000..eafc4d1
--- /dev/null
+++ b/t/merge-2-identical
@@ -0,0 +1,15 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --merge --no-reduce file
+
+also_interactive m
diff --git a/t/merge-base b/t/merge-base
new file mode 100755
index 0000000..8b7969e
--- /dev/null
+++ b/t/merge-base
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} a" \
+ same \
+ "${PARENT} b" \
+ different \
+ "${TAIL}" \
+ same \
+ "${END} c"
+
+cp -- file file.expected
+
+conflict --merge --no-reduce file
+
+also_interactive m
diff --git a/t/merge-empty-base b/t/merge-empty-base
new file mode 100755
index 0000000..6298768
--- /dev/null
+++ b/t/merge-empty-base
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ "${PARENT} base" \
+ "${TAIL}" \
+ same \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --merge --no-reduce file
+
+also_interactive m
diff --git a/t/merge-empty-head b/t/merge-empty-head
new file mode 100755
index 0000000..257df23
--- /dev/null
+++ b/t/merge-empty-head
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ "${PARENT} base" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} theirs"
+
+: > file.expected
+
+normal --merge --no-reduce file
+
+also_interactive m
diff --git a/t/merge-empty-tail b/t/merge-empty-tail
new file mode 100755
index 0000000..0574dfc
--- /dev/null
+++ b/t/merge-empty-tail
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ "${PARENT} base" \
+ same \
+ "${TAIL}" \
+ "${END} theirs"
+
+: > file.expected
+
+normal --merge --no-reduce file
+
+also_interactive m
diff --git a/t/merge-head b/t/merge-head
new file mode 100755
index 0000000..a87492e
--- /dev/null
+++ b/t/merge-head
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} a" \
+ different \
+ "${PARENT} b" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} c"
+
+printf '%s\n' > file.expected \
+ different
+
+normal --merge --no-reduce file
+
+also_interactive m
diff --git a/t/merge-head-4 b/t/merge-head-4
new file mode 100755
index 0000000..288ac66
--- /dev/null
+++ b/t/merge-head-4
@@ -0,0 +1,20 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ different \
+ "${PARENT} 2" \
+ same \
+ "${PARENT} 3" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} 4"
+
+printf '%s\n' > file.expected \
+ different
+
+normal --merge --no-reduce file
+
+also_interactive m
diff --git a/t/merge-lower-middle-4 b/t/merge-lower-middle-4
new file mode 100755
index 0000000..a378bcc
--- /dev/null
+++ b/t/merge-lower-middle-4
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ same \
+ "${PARENT} 2" \
+ same \
+ "${PARENT} 3" \
+ different \
+ "${TAIL}" \
+ same \
+ "${END} 4"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ same \
+ "${PARENT} 2" \
+ same \
+ "${PARENT} 3" \
+ different \
+ "${TAIL}" \
+ same \
+ "${END} 4"
+
+conflict --merge --no-reduce file
+
+also_interactive m
diff --git a/t/merge-multiple-conflicts b/t/merge-multiple-conflicts
new file mode 100755
index 0000000..7aaccbc
--- /dev/null
+++ b/t/merge-multiple-conflicts
@@ -0,0 +1,34 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ before \
+ "${HEAD} ours" \
+ same \
+ "${PARENT} base" \
+ same \
+ "${TAIL}" \
+ different-three \
+ "${END} theirs" \
+ between \
+ "${HEAD} ours" \
+ different-four \
+ "${PARENT} base" \
+ same \
+ "${PARENT} other" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} theirs" \
+ after
+
+printf '%s\n' > file.expected \
+ before \
+ different-three \
+ between \
+ different-four \
+ after
+
+normal --merge --no-reduce file
+
+also_interactive mm
diff --git a/t/merge-multiple-files b/t/merge-multiple-files
new file mode 100755
index 0000000..23a8bb5
--- /dev/null
+++ b/t/merge-multiple-files
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > first \
+ "${HEAD} ours" \
+ same \
+ "${PARENT} base" \
+ same \
+ "${TAIL}" \
+ first-different \
+ "${END} theirs"
+
+printf '%s\n' > first.expected \
+ first-different
+
+printf '%s\n' > second \
+ "${HEAD} ours" \
+ second-different \
+ "${PARENT} base" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} theirs"
+
+printf '%s\n' > second.expected \
+ second-different
+
+normal --merge --no-reduce first second
+
+also_interactive mm
diff --git a/t/merge-no-conflicts b/t/merge-no-conflicts
new file mode 100755
index 0000000..5dc5804
--- /dev/null
+++ b/t/merge-no-conflicts
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ no conflicts
+
+cp -- file file.expected
+
+normal --merge --no-reduce file
+
+also_interactive ''
diff --git a/t/merge-short-option b/t/merge-short-option
new file mode 100755
index 0000000..3a68ee0
--- /dev/null
+++ b/t/merge-short-option
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ "${PARENT} base" \
+ same \
+ "${TAIL}" \
+ different \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ different
+
+normal -m --no-reduce file
+
+also_interactive s
diff --git a/t/merge-tail b/t/merge-tail
new file mode 100755
index 0000000..c3949c0
--- /dev/null
+++ b/t/merge-tail
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} a" \
+ same \
+ "${PARENT} b" \
+ same \
+ "${TAIL}" \
+ different \
+ "${END} c"
+
+printf '%s\n' > file.expected \
+ different
+
+normal --merge --no-reduce file
+
+also_interactive m
diff --git a/t/merge-tail-4 b/t/merge-tail-4
new file mode 100755
index 0000000..ecfff16
--- /dev/null
+++ b/t/merge-tail-4
@@ -0,0 +1,20 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ same \
+ "${PARENT} 2" \
+ same \
+ "${PARENT} 3" \
+ same \
+ "${TAIL}" \
+ different \
+ "${END} 4"
+
+printf '%s\n' > file.expected \
+ different
+
+normal --merge --no-reduce file
+
+also_interactive m
diff --git a/t/merge-upper-middle-4 b/t/merge-upper-middle-4
new file mode 100755
index 0000000..c113241
--- /dev/null
+++ b/t/merge-upper-middle-4
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ same \
+ "${PARENT} 2" \
+ different \
+ "${PARENT} 3" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} 4"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ same \
+ "${PARENT} 2" \
+ different \
+ "${PARENT} 3" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} 4"
+
+conflict --merge --no-reduce file
+
+also_interactive m
diff --git a/t/missing-newline-non-conflict b/t/missing-newline-non-conflict
new file mode 100755
index 0000000..a89640a
--- /dev/null
+++ b/t/missing-newline-non-conflict
@@ -0,0 +1,10 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s' 'non-conflict without newline' > file
+
+cp -- file file.expected
+
+normal file
+
+also_interactive ''
diff --git a/t/mixed-marker-sizes b/t/mixed-marker-sizes
new file mode 100755
index 0000000..8cd186b
--- /dev/null
+++ b/t/mixed-marker-sizes
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+
+set_conflict_marker_size 3 small
+
+printf '%s\n' > small \
+ "${HEAD} small-head" \
+ shared \
+ "${TAIL}" \
+ shared \
+ "${END} small-tail"
+
+printf '%s\n' > small.expected \
+ shared
+
+set_conflict_marker_size 10 large
+
+printf '%s\n' > large \
+ "${HEAD} large-head" \
+ shared \
+ "${TAIL}" \
+ shared \
+ "${END} large-tail"
+
+printf '%s\n' > large.expected \
+ shared
+
+normal small large
+
+also_interactive rr
diff --git a/t/no-option-interactive b/t/no-option-interactive
new file mode 100755
index 0000000..5609f68
--- /dev/null
+++ b/t/no-option-interactive
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s' q > input
+
+conflict --no-interactive file 8<input 9>output
+test ! -s output
diff --git a/t/no-option-interactive-no-yes b/t/no-option-interactive-no-yes
new file mode 100755
index 0000000..7417667
--- /dev/null
+++ b/t/no-option-interactive-no-yes
@@ -0,0 +1,20 @@
+#!/bin/sh -e
+. t/common.sh
+
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ ours
+
+printf '%s' h > input
+
+normal --no-interactive --interactive --no-reduce file 8<input 9>output
diff --git a/t/no-option-interactive-yes-no b/t/no-option-interactive-yes-no
new file mode 100755
index 0000000..2a3b0c4
--- /dev/null
+++ b/t/no-option-interactive-yes-no
@@ -0,0 +1,19 @@
+#!/bin/sh -e
+. t/common.sh
+
+interactive
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+cp -- file file.expected
+
+printf '%s' q > input
+
+conflict --interactive --no-interactive --no-reduce file 8<input 9>output
diff --git a/t/no-option-merge b/t/no-option-merge
new file mode 100755
index 0000000..5f55d74
--- /dev/null
+++ b/t/no-option-merge
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --no-merge file
+
+also_interactive rr
diff --git a/t/no-option-merge-no-yes b/t/no-option-merge-no-yes
new file mode 100755
index 0000000..8ae2bc4
--- /dev/null
+++ b/t/no-option-merge-no-yes
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ old \
+ "${PARENT} base" \
+ old \
+ "${TAIL}" \
+ new \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ new
+
+normal --no-merge --merge --no-reduce file
+
+also_interactive m
diff --git a/t/no-option-merge-yes-no b/t/no-option-merge-yes-no
new file mode 100755
index 0000000..f351e7c
--- /dev/null
+++ b/t/no-option-merge-yes-no
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --merge --no-merge file
+
+also_interactive r
diff --git a/t/no-option-reduce b/t/no-option-reduce
new file mode 100755
index 0000000..3c345b2
--- /dev/null
+++ b/t/no-option-reduce
@@ -0,0 +1,20 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-option-reduce-no-yes b/t/no-option-reduce-no-yes
new file mode 100755
index 0000000..e6a7d8c
--- /dev/null
+++ b/t/no-option-reduce-no-yes
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --no-reduce --reduce file
+
+also_interactive r
diff --git a/t/no-option-reduce-yes-no b/t/no-option-reduce-yes-no
new file mode 100755
index 0000000..82fa7bd
--- /dev/null
+++ b/t/no-option-reduce-yes-no
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --reduce --no-reduce file
+
+also_interactive s
diff --git a/t/no-option-remove-base b/t/no-option-remove-base
new file mode 100755
index 0000000..fbb8385
--- /dev/null
+++ b/t/no-option-remove-base
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --no-remove-base file
+
+also_interactive rr
diff --git a/t/no-option-remove-base-no-yes b/t/no-option-remove-base-no-yes
new file mode 100755
index 0000000..9f6fed8
--- /dev/null
+++ b/t/no-option-remove-base-no-yes
@@ -0,0 +1,22 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ "${HEAD} ours" \
+ ours \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --no-remove-base --remove-base --no-reduce file
+
+also_interactive bb
diff --git a/t/no-option-remove-base-yes-no b/t/no-option-remove-base-yes-no
new file mode 100755
index 0000000..e93b8ee
--- /dev/null
+++ b/t/no-option-remove-base-yes-no
@@ -0,0 +1,24 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --remove-base --no-remove-base --no-reduce file
+
+also_interactive ss
diff --git a/t/no-option-select-head b/t/no-option-select-head
new file mode 100755
index 0000000..d882b14
--- /dev/null
+++ b/t/no-option-select-head
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --no-select-head file
+
+also_interactive rr
diff --git a/t/no-option-select-head-no-yes b/t/no-option-select-head-no-yes
new file mode 100755
index 0000000..1496892
--- /dev/null
+++ b/t/no-option-select-head-no-yes
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ ours
+
+normal --no-select-head --select-head --no-reduce file
+
+also_interactive h
diff --git a/t/no-option-select-head-yes-no b/t/no-option-select-head-yes-no
new file mode 100755
index 0000000..3093de5
--- /dev/null
+++ b/t/no-option-select-head-yes-no
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --select-head --no-select-head --no-reduce file
+
+also_interactive s
diff --git a/t/no-option-select-head-yes-then-select-tail-yes-no b/t/no-option-select-head-yes-then-select-tail-yes-no
new file mode 100755
index 0000000..7bc5924
--- /dev/null
+++ b/t/no-option-select-head-yes-then-select-tail-yes-no
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ ours
+
+normal --select-head --select-tail --no-select-tail --no-reduce file
+
+also_interactive h
diff --git a/t/no-option-select-tail b/t/no-option-select-tail
new file mode 100755
index 0000000..8c30d7e
--- /dev/null
+++ b/t/no-option-select-tail
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ same \
+ ours \
+ "${PARENT} base" \
+ same \
+ base \
+ "${TAIL}" \
+ same \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ same \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --no-select-tail file
+
+also_interactive rr
diff --git a/t/no-option-select-tail-no-yes b/t/no-option-select-tail-no-yes
new file mode 100755
index 0000000..9984272
--- /dev/null
+++ b/t/no-option-select-tail-no-yes
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ theirs
+
+normal --no-select-tail --select-tail --no-reduce file
+
+also_interactive t
diff --git a/t/no-option-select-tail-yes-no b/t/no-option-select-tail-yes-no
new file mode 100755
index 0000000..b2c3cc9
--- /dev/null
+++ b/t/no-option-select-tail-yes-no
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --select-tail --no-select-tail --no-reduce file
+
+also_interactive s
diff --git a/t/no-option-select-tail-yes-then-select-head-yes-no b/t/no-option-select-tail-yes-then-select-head-yes-no
new file mode 100755
index 0000000..a46efa4
--- /dev/null
+++ b/t/no-option-select-tail-yes-then-select-head-yes-no
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ theirs
+
+normal --select-tail --select-head --no-select-head --no-reduce file
+
+also_interactive t
diff --git a/t/no-reduce b/t/no-reduce
new file mode 100755
index 0000000..878eeea
--- /dev/null
+++ b/t/no-reduce
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} HEAD" \
+ same \
+ head \
+ "${TAIL}" \
+ same \
+ tail \
+ "${END} branch"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-1 b/t/no-reduce-1
new file mode 100755
index 0000000..8f549eb
--- /dev/null
+++ b/t/no-reduce-1
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ same \
+ "${END} 1"
+
+cp -- file file.expected
+
+error --no-reduce file
diff --git a/t/no-reduce-2-files b/t/no-reduce-2-files
new file mode 100755
index 0000000..29d7ea3
--- /dev/null
+++ b/t/no-reduce-2-files
@@ -0,0 +1,24 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ first \
+ "${TAIL}" \
+ first \
+ "${END} theirs"
+
+cp -- file file.expected
+
+printf '%s\n' > file2 \
+ "${HEAD} ours" \
+ second \
+ "${TAIL}" \
+ second \
+ "${END} theirs"
+
+cp -- file2 file2.expected
+
+conflict --no-reduce file file2
+
+also_interactive ss
diff --git a/t/no-reduce-2-full b/t/no-reduce-2-full
new file mode 100755
index 0000000..20b4c19
--- /dev/null
+++ b/t/no-reduce-2-full
@@ -0,0 +1,19 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ common-first \
+ common-second \
+ common-third \
+ "${TAIL} 2" \
+ common-first \
+ common-second \
+ common-third \
+ "${END} 2"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-2-head b/t/no-reduce-2-head
new file mode 100755
index 0000000..34029cd
--- /dev/null
+++ b/t/no-reduce-2-head
@@ -0,0 +1,21 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first \
+ branch-1-second \
+ "${TAIL} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first \
+ branch-2-second \
+ "${END} 2"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-2-hunks b/t/no-reduce-2-hunks
new file mode 100755
index 0000000..bc9c550
--- /dev/null
+++ b/t/no-reduce-2-hunks
@@ -0,0 +1,21 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ first \
+ "${TAIL}" \
+ first \
+ "${END} theirs" \
+ between \
+ "${HEAD} ours" \
+ second \
+ "${TAIL}" \
+ second \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive ss
diff --git a/t/no-reduce-2-middle b/t/no-reduce-2-middle
new file mode 100755
index 0000000..5409cbd
--- /dev/null
+++ b/t/no-reduce-2-middle
@@ -0,0 +1,25 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${TAIL} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${END} 2"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-2-multiple-partial b/t/no-reduce-2-multiple-partial
new file mode 100755
index 0000000..bf25762
--- /dev/null
+++ b/t/no-reduce-2-multiple-partial
@@ -0,0 +1,33 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first-a \
+ branch-1-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-1-second-a \
+ branch-1-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first-a \
+ branch-2-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-2-second-a \
+ branch-2-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${END} 2"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-2-non-aligned b/t/no-reduce-2-non-aligned
new file mode 100755
index 0000000..542435f
--- /dev/null
+++ b/t/no-reduce-2-non-aligned
@@ -0,0 +1,27 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ before-common-first \
+ before-common-second \
+ head-only-first \
+ head-only-second \
+ middle-common-first \
+ middle-common-second \
+ head-last \
+ "${TAIL} 2" \
+ before-common-first \
+ before-common-second \
+ tail-only \
+ middle-common-first \
+ middle-common-second \
+ tail-last-first \
+ tail-last-second \
+ "${END} 2"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-2-none b/t/no-reduce-2-none
new file mode 100755
index 0000000..d09b857
--- /dev/null
+++ b/t/no-reduce-2-none
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${TAIL} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${END} 2"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-2-tail b/t/no-reduce-2-tail
new file mode 100755
index 0000000..4eb8bd8
--- /dev/null
+++ b/t/no-reduce-2-tail
@@ -0,0 +1,21 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 2" \
+ branch-2-first \
+ branch-2-second \
+ tail-common-first \
+ tail-common-second \
+ "${END} 2"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-3-full b/t/no-reduce-3-full
new file mode 100755
index 0000000..8e36d3e
--- /dev/null
+++ b/t/no-reduce-3-full
@@ -0,0 +1,23 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 2" \
+ common-first \
+ common-second \
+ common-third \
+ "${TAIL} 3" \
+ common-first \
+ common-second \
+ common-third \
+ "${END} 3"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-3-head b/t/no-reduce-3-head
new file mode 100755
index 0000000..3d2475c
--- /dev/null
+++ b/t/no-reduce-3-head
@@ -0,0 +1,26 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first \
+ branch-2-second \
+ "${TAIL} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first \
+ branch-3-second \
+ "${END} 3"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-3-middle b/t/no-reduce-3-middle
new file mode 100755
index 0000000..da3eb25
--- /dev/null
+++ b/t/no-reduce-3-middle
@@ -0,0 +1,32 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${PARENT} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${TAIL} 3" \
+ branch-3-before-first \
+ branch-3-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-3-after-first \
+ branch-3-after-second \
+ "${END} 3"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-3-multiple-partial b/t/no-reduce-3-multiple-partial
new file mode 100755
index 0000000..232afd0
--- /dev/null
+++ b/t/no-reduce-3-multiple-partial
@@ -0,0 +1,44 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first-a \
+ branch-1-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-1-second-a \
+ branch-1-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first-a \
+ branch-2-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-2-second-a \
+ branch-2-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first-a \
+ branch-3-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-3-second-a \
+ branch-3-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${END} 3"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-3-none b/t/no-reduce-3-none
new file mode 100755
index 0000000..c5c05bf
--- /dev/null
+++ b/t/no-reduce-3-none
@@ -0,0 +1,20 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${TAIL} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${END} 3"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-3-tail b/t/no-reduce-3-tail
new file mode 100755
index 0000000..776eebd
--- /dev/null
+++ b/t/no-reduce-3-tail
@@ -0,0 +1,26 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 3" \
+ branch-3-first \
+ branch-3-second \
+ tail-common-first \
+ tail-common-second \
+ "${END} 3"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-4-full b/t/no-reduce-4-full
new file mode 100755
index 0000000..49f47c2
--- /dev/null
+++ b/t/no-reduce-4-full
@@ -0,0 +1,27 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 2" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 3" \
+ common-first \
+ common-second \
+ common-third \
+ "${TAIL} 4" \
+ common-first \
+ common-second \
+ common-third \
+ "${END} 4"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-4-head b/t/no-reduce-4-head
new file mode 100755
index 0000000..68425c6
--- /dev/null
+++ b/t/no-reduce-4-head
@@ -0,0 +1,31 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first \
+ branch-3-second \
+ "${TAIL} 4" \
+ head-common-first \
+ head-common-second \
+ branch-4-first \
+ branch-4-second \
+ "${END} 4"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-4-middle b/t/no-reduce-4-middle
new file mode 100755
index 0000000..b91f36e
--- /dev/null
+++ b/t/no-reduce-4-middle
@@ -0,0 +1,39 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${PARENT} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${PARENT} 3" \
+ branch-3-before-first \
+ branch-3-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-3-after-first \
+ branch-3-after-second \
+ "${TAIL} 4" \
+ branch-4-before-first \
+ branch-4-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-4-after-first \
+ branch-4-after-second \
+ "${END} 4"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-4-multiple-partial b/t/no-reduce-4-multiple-partial
new file mode 100755
index 0000000..3ae2034
--- /dev/null
+++ b/t/no-reduce-4-multiple-partial
@@ -0,0 +1,55 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first-a \
+ branch-1-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-1-second-a \
+ branch-1-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first-a \
+ branch-2-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-2-second-a \
+ branch-2-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first-a \
+ branch-3-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-3-second-a \
+ branch-3-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 4" \
+ head-common-first \
+ head-common-second \
+ branch-4-first-a \
+ branch-4-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-4-second-a \
+ branch-4-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${END} 4"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-4-none b/t/no-reduce-4-none
new file mode 100755
index 0000000..cdb5a0f
--- /dev/null
+++ b/t/no-reduce-4-none
@@ -0,0 +1,23 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${TAIL} 4" \
+ branch-4-first \
+ branch-4-second \
+ "${END} 4"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-4-tail b/t/no-reduce-4-tail
new file mode 100755
index 0000000..a9edec7
--- /dev/null
+++ b/t/no-reduce-4-tail
@@ -0,0 +1,31 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 4" \
+ branch-4-first \
+ branch-4-second \
+ tail-common-first \
+ tail-common-second \
+ "${END} 4"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-5-full b/t/no-reduce-5-full
new file mode 100755
index 0000000..d735484
--- /dev/null
+++ b/t/no-reduce-5-full
@@ -0,0 +1,31 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 2" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 3" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 4" \
+ common-first \
+ common-second \
+ common-third \
+ "${TAIL} 5" \
+ common-first \
+ common-second \
+ common-third \
+ "${END} 5"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-5-head b/t/no-reduce-5-head
new file mode 100755
index 0000000..883240c
--- /dev/null
+++ b/t/no-reduce-5-head
@@ -0,0 +1,36 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first \
+ branch-3-second \
+ "${PARENT} 4" \
+ head-common-first \
+ head-common-second \
+ branch-4-first \
+ branch-4-second \
+ "${TAIL} 5" \
+ head-common-first \
+ head-common-second \
+ branch-5-first \
+ branch-5-second \
+ "${END} 5"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-5-middle b/t/no-reduce-5-middle
new file mode 100755
index 0000000..3826bc6
--- /dev/null
+++ b/t/no-reduce-5-middle
@@ -0,0 +1,46 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${PARENT} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${PARENT} 3" \
+ branch-3-before-first \
+ branch-3-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-3-after-first \
+ branch-3-after-second \
+ "${PARENT} 4" \
+ branch-4-before-first \
+ branch-4-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-4-after-first \
+ branch-4-after-second \
+ "${TAIL} 5" \
+ branch-5-before-first \
+ branch-5-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-5-after-first \
+ branch-5-after-second \
+ "${END} 5"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-5-multiple-partial b/t/no-reduce-5-multiple-partial
new file mode 100755
index 0000000..802b414
--- /dev/null
+++ b/t/no-reduce-5-multiple-partial
@@ -0,0 +1,66 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first-a \
+ branch-1-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-1-second-a \
+ branch-1-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first-a \
+ branch-2-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-2-second-a \
+ branch-2-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first-a \
+ branch-3-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-3-second-a \
+ branch-3-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 4" \
+ head-common-first \
+ head-common-second \
+ branch-4-first-a \
+ branch-4-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-4-second-a \
+ branch-4-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 5" \
+ head-common-first \
+ head-common-second \
+ branch-5-first-a \
+ branch-5-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-5-second-a \
+ branch-5-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${END} 5"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-5-none b/t/no-reduce-5-none
new file mode 100755
index 0000000..fbd2808
--- /dev/null
+++ b/t/no-reduce-5-none
@@ -0,0 +1,26 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${PARENT} 4" \
+ branch-4-first \
+ branch-4-second \
+ "${TAIL} 5" \
+ branch-5-first \
+ branch-5-second \
+ "${END} 5"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-5-tail b/t/no-reduce-5-tail
new file mode 100755
index 0000000..8799582
--- /dev/null
+++ b/t/no-reduce-5-tail
@@ -0,0 +1,36 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 4" \
+ branch-4-first \
+ branch-4-second \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 5" \
+ branch-5-first \
+ branch-5-second \
+ tail-common-first \
+ tail-common-second \
+ "${END} 5"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-dashdash-dashprefix b/t/no-reduce-dashdash-dashprefix
new file mode 100755
index 0000000..5ddaaed
--- /dev/null
+++ b/t/no-reduce-dashdash-dashprefix
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > -file \
+ "${HEAD} HEAD" \
+ same \
+ head \
+ "${TAIL}" \
+ same \
+ tail \
+ "${END} branch"
+
+cp -- -file -file.expected
+
+conflict --no-reduce -- -file
+
+also_interactive s
diff --git a/t/no-reduce-empty-base b/t/no-reduce-empty-base
new file mode 100755
index 0000000..2cc942f
--- /dev/null
+++ b/t/no-reduce-empty-base
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ common \
+ "${PARENT} base" \
+ "${TAIL}" \
+ common \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-empty-head b/t/no-reduce-empty-head
new file mode 100755
index 0000000..95c0338
--- /dev/null
+++ b/t/no-reduce-empty-head
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ "${PARENT} base" \
+ common \
+ "${TAIL}" \
+ common \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-empty-tail b/t/no-reduce-empty-tail
new file mode 100755
index 0000000..b8888ae
--- /dev/null
+++ b/t/no-reduce-empty-tail
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ common \
+ "${PARENT} base" \
+ common \
+ "${TAIL}" \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --no-reduce file
+
+also_interactive s
diff --git a/t/no-reduce-no-conflicts b/t/no-reduce-no-conflicts
new file mode 100755
index 0000000..ac818e6
--- /dev/null
+++ b/t/no-reduce-no-conflicts
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ no conflicts
+
+cp -- file file.expected
+
+normal --no-reduce file
+
+also_interactive ''
diff --git a/t/null-bytes b/t/null-bytes
new file mode 100755
index 0000000..9a7ee7f
--- /dev/null
+++ b/t/null-bytes
@@ -0,0 +1,15 @@
+#!/bin/sh -e
+. t/common.sh
+
+(
+ printf '%s\n' "${HEAD} ours"
+ printf 'same\000text\n'
+ printf '%s\n' "${TAIL}"
+ printf 'same\000text\n'
+ printf '%s\n' "${END} theirs"
+) > file
+
+printf 'same\000text\n' > file.expected
+
+"$command" --reduce file
+cmp -s -- file file.expected
diff --git a/t/reduce-1 b/t/reduce-1
new file mode 100755
index 0000000..4f96968
--- /dev/null
+++ b/t/reduce-1
@@ -0,0 +1,9 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ same \
+ "${END} 1"
+
+error --reduce file
diff --git a/t/reduce-2-files b/t/reduce-2-files
new file mode 100755
index 0000000..d28e142
--- /dev/null
+++ b/t/reduce-2-files
@@ -0,0 +1,26 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ first \
+ "${TAIL}" \
+ first \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ first
+
+printf '%s\n' > file2 \
+ "${HEAD} ours" \
+ second \
+ "${TAIL}" \
+ second \
+ "${END} theirs"
+
+printf '%s\n' > file2.expected \
+ second
+
+normal --reduce file file2
+
+also_interactive rr
diff --git a/t/reduce-2-full b/t/reduce-2-full
new file mode 100755
index 0000000..59a1b5e
--- /dev/null
+++ b/t/reduce-2-full
@@ -0,0 +1,22 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ common-first \
+ common-second \
+ common-third \
+ "${TAIL} 2" \
+ common-first \
+ common-second \
+ common-third \
+ "${END} 2"
+
+printf '%s\n' > file.expected \
+ common-first \
+ common-second \
+ common-third
+
+normal --reduce file
+
+also_interactive r
diff --git a/t/reduce-2-head b/t/reduce-2-head
new file mode 100755
index 0000000..d4bcada
--- /dev/null
+++ b/t/reduce-2-head
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first \
+ branch-1-second \
+ "${TAIL} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first \
+ branch-2-second \
+ "${END} 2"
+
+printf '%s\n' > file.expected \
+ head-common-first \
+ head-common-second \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${TAIL} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${END} 2"
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-2-hunks b/t/reduce-2-hunks
new file mode 100755
index 0000000..22146e6
--- /dev/null
+++ b/t/reduce-2-hunks
@@ -0,0 +1,24 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ first \
+ "${TAIL}" \
+ first \
+ "${END} theirs" \
+ between \
+ "${HEAD} ours" \
+ second \
+ "${TAIL}" \
+ second \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ first \
+ between \
+ second
+
+normal --reduce file
+
+also_interactive rr
diff --git a/t/reduce-2-middle b/t/reduce-2-middle
new file mode 100755
index 0000000..f2ab8d3
--- /dev/null
+++ b/t/reduce-2-middle
@@ -0,0 +1,41 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${TAIL} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${END} 2"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ "${TAIL} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ "${END} 2" \
+ middle-common-first \
+ middle-common-second \
+ "${HEAD} 1" \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${TAIL} 2" \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${END} 2"
+
+conflict --reduce file
+
+also_interactive rrr
diff --git a/t/reduce-2-multiple-partial b/t/reduce-2-multiple-partial
new file mode 100755
index 0000000..eaf4ba5
--- /dev/null
+++ b/t/reduce-2-multiple-partial
@@ -0,0 +1,53 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first-a \
+ branch-1-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-1-second-a \
+ branch-1-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first-a \
+ branch-2-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-2-second-a \
+ branch-2-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${END} 2"
+
+printf '%s\n' > file.expected \
+ head-common-first \
+ head-common-second \
+ "${HEAD} 1" \
+ branch-1-first-a \
+ branch-1-first-b \
+ "${TAIL} 2" \
+ branch-2-first-a \
+ branch-2-first-b \
+ "${END} 2" \
+ middle-common-first \
+ middle-common-second \
+ "${HEAD} 1" \
+ branch-1-second-a \
+ branch-1-second-b \
+ "${TAIL} 2" \
+ branch-2-second-a \
+ branch-2-second-b \
+ "${END} 2" \
+ tail-common-first \
+ tail-common-second
+
+conflict --reduce file
+
+also_interactive rrr
diff --git a/t/reduce-2-non-aligned b/t/reduce-2-non-aligned
new file mode 100755
index 0000000..58202d1
--- /dev/null
+++ b/t/reduce-2-non-aligned
@@ -0,0 +1,43 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ before-common-first \
+ before-common-second \
+ head-only-first \
+ head-only-second \
+ middle-common-first \
+ middle-common-second \
+ head-last \
+ "${TAIL} 2" \
+ before-common-first \
+ before-common-second \
+ tail-only \
+ middle-common-first \
+ middle-common-second \
+ tail-last-first \
+ tail-last-second \
+ "${END} 2"
+
+printf '%s\n' > file.expected \
+ before-common-first \
+ before-common-second \
+ "${HEAD} 1" \
+ head-only-first \
+ head-only-second \
+ "${TAIL} 2" \
+ tail-only \
+ "${END} 2" \
+ middle-common-first \
+ middle-common-second \
+ "${HEAD} 1" \
+ head-last \
+ "${TAIL} 2" \
+ tail-last-first \
+ tail-last-second \
+ "${END} 2"
+
+conflict --reduce file
+
+also_interactive rrr
diff --git a/t/reduce-2-none b/t/reduce-2-none
new file mode 100755
index 0000000..63efabc
--- /dev/null
+++ b/t/reduce-2-none
@@ -0,0 +1,24 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${TAIL} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${END} 2"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${TAIL} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${END} 2"
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-2-tail b/t/reduce-2-tail
new file mode 100755
index 0000000..fb125f8
--- /dev/null
+++ b/t/reduce-2-tail
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 2" \
+ branch-2-first \
+ branch-2-second \
+ tail-common-first \
+ tail-common-second \
+ "${END} 2"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${TAIL} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${END} 2" \
+ tail-common-first \
+ tail-common-second
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-3-full b/t/reduce-3-full
new file mode 100755
index 0000000..72cabeb
--- /dev/null
+++ b/t/reduce-3-full
@@ -0,0 +1,26 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 2" \
+ common-first \
+ common-second \
+ common-third \
+ "${TAIL} 3" \
+ common-first \
+ common-second \
+ common-third \
+ "${END} 3"
+
+printf '%s\n' > file.expected \
+ common-first \
+ common-second \
+ common-third
+
+normal --reduce file
+
+also_interactive r
diff --git a/t/reduce-3-head b/t/reduce-3-head
new file mode 100755
index 0000000..abc705c
--- /dev/null
+++ b/t/reduce-3-head
@@ -0,0 +1,38 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first \
+ branch-2-second \
+ "${TAIL} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first \
+ branch-3-second \
+ "${END} 3"
+
+printf '%s\n' > file.expected \
+ head-common-first \
+ head-common-second \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${TAIL} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${END} 3"
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-3-middle b/t/reduce-3-middle
new file mode 100755
index 0000000..25caf2f
--- /dev/null
+++ b/t/reduce-3-middle
@@ -0,0 +1,54 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${PARENT} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${TAIL} 3" \
+ branch-3-before-first \
+ branch-3-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-3-after-first \
+ branch-3-after-second \
+ "${END} 3"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ "${PARENT} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ "${TAIL} 3" \
+ branch-3-before-first \
+ branch-3-before-second \
+ "${END} 3" \
+ middle-common-first \
+ middle-common-second \
+ "${HEAD} 1" \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${PARENT} 2" \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${TAIL} 3" \
+ branch-3-after-first \
+ branch-3-after-second \
+ "${END} 3"
+
+conflict --reduce file
+
+also_interactive rrr
diff --git a/t/reduce-3-multiple-partial b/t/reduce-3-multiple-partial
new file mode 100755
index 0000000..ec8cab7
--- /dev/null
+++ b/t/reduce-3-multiple-partial
@@ -0,0 +1,70 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first-a \
+ branch-1-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-1-second-a \
+ branch-1-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first-a \
+ branch-2-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-2-second-a \
+ branch-2-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first-a \
+ branch-3-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-3-second-a \
+ branch-3-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${END} 3"
+
+printf '%s\n' > file.expected \
+ head-common-first \
+ head-common-second \
+ "${HEAD} 1" \
+ branch-1-first-a \
+ branch-1-first-b \
+ "${PARENT} 2" \
+ branch-2-first-a \
+ branch-2-first-b \
+ "${TAIL} 3" \
+ branch-3-first-a \
+ branch-3-first-b \
+ "${END} 3" \
+ middle-common-first \
+ middle-common-second \
+ "${HEAD} 1" \
+ branch-1-second-a \
+ branch-1-second-b \
+ "${PARENT} 2" \
+ branch-2-second-a \
+ branch-2-second-b \
+ "${TAIL} 3" \
+ branch-3-second-a \
+ branch-3-second-b \
+ "${END} 3" \
+ tail-common-first \
+ tail-common-second
+
+conflict --reduce file
+
+also_interactive rrr
diff --git a/t/reduce-3-none b/t/reduce-3-none
new file mode 100755
index 0000000..9083c88
--- /dev/null
+++ b/t/reduce-3-none
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${TAIL} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${END} 3"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${TAIL} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${END} 3"
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-3-tail b/t/reduce-3-tail
new file mode 100755
index 0000000..5291c57
--- /dev/null
+++ b/t/reduce-3-tail
@@ -0,0 +1,38 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 3" \
+ branch-3-first \
+ branch-3-second \
+ tail-common-first \
+ tail-common-second \
+ "${END} 3"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${TAIL} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${END} 3" \
+ tail-common-first \
+ tail-common-second
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-4-full b/t/reduce-4-full
new file mode 100755
index 0000000..e29c089
--- /dev/null
+++ b/t/reduce-4-full
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 2" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 3" \
+ common-first \
+ common-second \
+ common-third \
+ "${TAIL} 4" \
+ common-first \
+ common-second \
+ common-third \
+ "${END} 4"
+
+printf '%s\n' > file.expected \
+ common-first \
+ common-second \
+ common-third
+
+normal --reduce file
+
+also_interactive r
diff --git a/t/reduce-4-head b/t/reduce-4-head
new file mode 100755
index 0000000..9d36033
--- /dev/null
+++ b/t/reduce-4-head
@@ -0,0 +1,46 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first \
+ branch-3-second \
+ "${TAIL} 4" \
+ head-common-first \
+ head-common-second \
+ branch-4-first \
+ branch-4-second \
+ "${END} 4"
+
+printf '%s\n' > file.expected \
+ head-common-first \
+ head-common-second \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${TAIL} 4" \
+ branch-4-first \
+ branch-4-second \
+ "${END} 4"
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-4-middle b/t/reduce-4-middle
new file mode 100755
index 0000000..c333b0f
--- /dev/null
+++ b/t/reduce-4-middle
@@ -0,0 +1,67 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${PARENT} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${PARENT} 3" \
+ branch-3-before-first \
+ branch-3-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-3-after-first \
+ branch-3-after-second \
+ "${TAIL} 4" \
+ branch-4-before-first \
+ branch-4-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-4-after-first \
+ branch-4-after-second \
+ "${END} 4"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ "${PARENT} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ "${PARENT} 3" \
+ branch-3-before-first \
+ branch-3-before-second \
+ "${TAIL} 4" \
+ branch-4-before-first \
+ branch-4-before-second \
+ "${END} 4" \
+ middle-common-first \
+ middle-common-second \
+ "${HEAD} 1" \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${PARENT} 2" \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${PARENT} 3" \
+ branch-3-after-first \
+ branch-3-after-second \
+ "${TAIL} 4" \
+ branch-4-after-first \
+ branch-4-after-second \
+ "${END} 4"
+
+conflict --reduce file
+
+also_interactive rrr
diff --git a/t/reduce-4-multiple-partial b/t/reduce-4-multiple-partial
new file mode 100755
index 0000000..bf23792
--- /dev/null
+++ b/t/reduce-4-multiple-partial
@@ -0,0 +1,87 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first-a \
+ branch-1-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-1-second-a \
+ branch-1-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first-a \
+ branch-2-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-2-second-a \
+ branch-2-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first-a \
+ branch-3-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-3-second-a \
+ branch-3-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 4" \
+ head-common-first \
+ head-common-second \
+ branch-4-first-a \
+ branch-4-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-4-second-a \
+ branch-4-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${END} 4"
+
+printf '%s\n' > file.expected \
+ head-common-first \
+ head-common-second \
+ "${HEAD} 1" \
+ branch-1-first-a \
+ branch-1-first-b \
+ "${PARENT} 2" \
+ branch-2-first-a \
+ branch-2-first-b \
+ "${PARENT} 3" \
+ branch-3-first-a \
+ branch-3-first-b \
+ "${TAIL} 4" \
+ branch-4-first-a \
+ branch-4-first-b \
+ "${END} 4" \
+ middle-common-first \
+ middle-common-second \
+ "${HEAD} 1" \
+ branch-1-second-a \
+ branch-1-second-b \
+ "${PARENT} 2" \
+ branch-2-second-a \
+ branch-2-second-b \
+ "${PARENT} 3" \
+ branch-3-second-a \
+ branch-3-second-b \
+ "${TAIL} 4" \
+ branch-4-second-a \
+ branch-4-second-b \
+ "${END} 4" \
+ tail-common-first \
+ tail-common-second
+
+conflict --reduce file
+
+also_interactive rrr
diff --git a/t/reduce-4-none b/t/reduce-4-none
new file mode 100755
index 0000000..75c95c3
--- /dev/null
+++ b/t/reduce-4-none
@@ -0,0 +1,36 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${TAIL} 4" \
+ branch-4-first \
+ branch-4-second \
+ "${END} 4"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${TAIL} 4" \
+ branch-4-first \
+ branch-4-second \
+ "${END} 4"
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-4-tail b/t/reduce-4-tail
new file mode 100755
index 0000000..752f680
--- /dev/null
+++ b/t/reduce-4-tail
@@ -0,0 +1,46 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 4" \
+ branch-4-first \
+ branch-4-second \
+ tail-common-first \
+ tail-common-second \
+ "${END} 4"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${TAIL} 4" \
+ branch-4-first \
+ branch-4-second \
+ "${END} 4" \
+ tail-common-first \
+ tail-common-second
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-5-full b/t/reduce-5-full
new file mode 100755
index 0000000..439a510
--- /dev/null
+++ b/t/reduce-5-full
@@ -0,0 +1,34 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 2" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 3" \
+ common-first \
+ common-second \
+ common-third \
+ "${PARENT} 4" \
+ common-first \
+ common-second \
+ common-third \
+ "${TAIL} 5" \
+ common-first \
+ common-second \
+ common-third \
+ "${END} 5"
+
+printf '%s\n' > file.expected \
+ common-first \
+ common-second \
+ common-third
+
+normal --reduce file
+
+also_interactive r
diff --git a/t/reduce-5-head b/t/reduce-5-head
new file mode 100755
index 0000000..a85ca8c
--- /dev/null
+++ b/t/reduce-5-head
@@ -0,0 +1,54 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first \
+ branch-3-second \
+ "${PARENT} 4" \
+ head-common-first \
+ head-common-second \
+ branch-4-first \
+ branch-4-second \
+ "${TAIL} 5" \
+ head-common-first \
+ head-common-second \
+ branch-5-first \
+ branch-5-second \
+ "${END} 5"
+
+printf '%s\n' > file.expected \
+ head-common-first \
+ head-common-second \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${PARENT} 4" \
+ branch-4-first \
+ branch-4-second \
+ "${TAIL} 5" \
+ branch-5-first \
+ branch-5-second \
+ "${END} 5"
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-5-middle b/t/reduce-5-middle
new file mode 100755
index 0000000..1a4cd73
--- /dev/null
+++ b/t/reduce-5-middle
@@ -0,0 +1,80 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${PARENT} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${PARENT} 3" \
+ branch-3-before-first \
+ branch-3-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-3-after-first \
+ branch-3-after-second \
+ "${PARENT} 4" \
+ branch-4-before-first \
+ branch-4-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-4-after-first \
+ branch-4-after-second \
+ "${TAIL} 5" \
+ branch-5-before-first \
+ branch-5-before-second \
+ middle-common-first \
+ middle-common-second \
+ branch-5-after-first \
+ branch-5-after-second \
+ "${END} 5"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-before-first \
+ branch-1-before-second \
+ "${PARENT} 2" \
+ branch-2-before-first \
+ branch-2-before-second \
+ "${PARENT} 3" \
+ branch-3-before-first \
+ branch-3-before-second \
+ "${PARENT} 4" \
+ branch-4-before-first \
+ branch-4-before-second \
+ "${TAIL} 5" \
+ branch-5-before-first \
+ branch-5-before-second \
+ "${END} 5" \
+ middle-common-first \
+ middle-common-second \
+ "${HEAD} 1" \
+ branch-1-after-first \
+ branch-1-after-second \
+ "${PARENT} 2" \
+ branch-2-after-first \
+ branch-2-after-second \
+ "${PARENT} 3" \
+ branch-3-after-first \
+ branch-3-after-second \
+ "${PARENT} 4" \
+ branch-4-after-first \
+ branch-4-after-second \
+ "${TAIL} 5" \
+ branch-5-after-first \
+ branch-5-after-second \
+ "${END} 5"
+
+conflict --reduce file
+
+also_interactive rrr
diff --git a/t/reduce-5-multiple-partial b/t/reduce-5-multiple-partial
new file mode 100755
index 0000000..e95805f
--- /dev/null
+++ b/t/reduce-5-multiple-partial
@@ -0,0 +1,104 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ head-common-first \
+ head-common-second \
+ branch-1-first-a \
+ branch-1-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-1-second-a \
+ branch-1-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ head-common-first \
+ head-common-second \
+ branch-2-first-a \
+ branch-2-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-2-second-a \
+ branch-2-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 3" \
+ head-common-first \
+ head-common-second \
+ branch-3-first-a \
+ branch-3-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-3-second-a \
+ branch-3-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 4" \
+ head-common-first \
+ head-common-second \
+ branch-4-first-a \
+ branch-4-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-4-second-a \
+ branch-4-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 5" \
+ head-common-first \
+ head-common-second \
+ branch-5-first-a \
+ branch-5-first-b \
+ middle-common-first \
+ middle-common-second \
+ branch-5-second-a \
+ branch-5-second-b \
+ tail-common-first \
+ tail-common-second \
+ "${END} 5"
+
+printf '%s\n' > file.expected \
+ head-common-first \
+ head-common-second \
+ "${HEAD} 1" \
+ branch-1-first-a \
+ branch-1-first-b \
+ "${PARENT} 2" \
+ branch-2-first-a \
+ branch-2-first-b \
+ "${PARENT} 3" \
+ branch-3-first-a \
+ branch-3-first-b \
+ "${PARENT} 4" \
+ branch-4-first-a \
+ branch-4-first-b \
+ "${TAIL} 5" \
+ branch-5-first-a \
+ branch-5-first-b \
+ "${END} 5" \
+ middle-common-first \
+ middle-common-second \
+ "${HEAD} 1" \
+ branch-1-second-a \
+ branch-1-second-b \
+ "${PARENT} 2" \
+ branch-2-second-a \
+ branch-2-second-b \
+ "${PARENT} 3" \
+ branch-3-second-a \
+ branch-3-second-b \
+ "${PARENT} 4" \
+ branch-4-second-a \
+ branch-4-second-b \
+ "${TAIL} 5" \
+ branch-5-second-a \
+ branch-5-second-b \
+ "${END} 5" \
+ tail-common-first \
+ tail-common-second
+
+conflict --reduce file
+
+also_interactive rrr
diff --git a/t/reduce-5-none b/t/reduce-5-none
new file mode 100755
index 0000000..d22f1e5
--- /dev/null
+++ b/t/reduce-5-none
@@ -0,0 +1,42 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${PARENT} 4" \
+ branch-4-first \
+ branch-4-second \
+ "${TAIL} 5" \
+ branch-5-first \
+ branch-5-second \
+ "${END} 5"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${PARENT} 4" \
+ branch-4-first \
+ branch-4-second \
+ "${TAIL} 5" \
+ branch-5-first \
+ branch-5-second \
+ "${END} 5"
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-5-tail b/t/reduce-5-tail
new file mode 100755
index 0000000..a003cd3
--- /dev/null
+++ b/t/reduce-5-tail
@@ -0,0 +1,54 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ tail-common-first \
+ tail-common-second \
+ "${PARENT} 4" \
+ branch-4-first \
+ branch-4-second \
+ tail-common-first \
+ tail-common-second \
+ "${TAIL} 5" \
+ branch-5-first \
+ branch-5-second \
+ tail-common-first \
+ tail-common-second \
+ "${END} 5"
+
+printf '%s\n' > file.expected \
+ "${HEAD} 1" \
+ branch-1-first \
+ branch-1-second \
+ "${PARENT} 2" \
+ branch-2-first \
+ branch-2-second \
+ "${PARENT} 3" \
+ branch-3-first \
+ branch-3-second \
+ "${PARENT} 4" \
+ branch-4-first \
+ branch-4-second \
+ "${TAIL} 5" \
+ branch-5-first \
+ branch-5-second \
+ "${END} 5" \
+ tail-common-first \
+ tail-common-second
+
+conflict --reduce file
+
+also_interactive rr
diff --git a/t/reduce-empty-base b/t/reduce-empty-base
new file mode 100755
index 0000000..09e80cc
--- /dev/null
+++ b/t/reduce-empty-base
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ common \
+ "${PARENT} base" \
+ "${TAIL}" \
+ common \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --reduce file
+
+also_interactive r
diff --git a/t/reduce-empty-head b/t/reduce-empty-head
new file mode 100755
index 0000000..6d082aa
--- /dev/null
+++ b/t/reduce-empty-head
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ "${PARENT} base" \
+ common \
+ "${TAIL}" \
+ common \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --reduce file
+
+also_interactive r
diff --git a/t/reduce-empty-tail b/t/reduce-empty-tail
new file mode 100755
index 0000000..a1ce3df
--- /dev/null
+++ b/t/reduce-empty-tail
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ common \
+ "${PARENT} base" \
+ common \
+ "${TAIL}" \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --reduce file
+
+also_interactive r
diff --git a/t/reduce-is-default b/t/reduce-is-default
new file mode 100755
index 0000000..c5f7dd8
--- /dev/null
+++ b/t/reduce-is-default
@@ -0,0 +1,23 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} HEAD" \
+ same \
+ head \
+ "${TAIL}" \
+ same \
+ tail \
+ "${END} branch"
+
+printf '%s\n' > file.expected \
+ same \
+ "${HEAD} HEAD" \
+ head \
+ "${TAIL}" \
+ tail \
+ "${END} branch"
+
+conflict file
+
+also_interactive rr
diff --git a/t/reduce-no-conflicts b/t/reduce-no-conflicts
new file mode 100755
index 0000000..41dbae0
--- /dev/null
+++ b/t/reduce-no-conflicts
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ no conflicts
+
+cp -- file file.expected
+
+normal --reduce file
+
+also_interactive ''
diff --git a/t/remove-base-1 b/t/remove-base-1
new file mode 100755
index 0000000..b497fe6
--- /dev/null
+++ b/t/remove-base-1
@@ -0,0 +1,12 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} Head" \
+ head \
+ "${END} Head"
+
+printf '%s\n' > file.expected \
+ head
+
+error --remove-base --no-reduce file
diff --git a/t/remove-base-2 b/t/remove-base-2
new file mode 100755
index 0000000..c4a4fb6
--- /dev/null
+++ b/t/remove-base-2
@@ -0,0 +1,15 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+cp -- file file.expected
+
+conflict --remove-base --no-reduce file
+
+also_interactive b
diff --git a/t/remove-base-3 b/t/remove-base-3
new file mode 100755
index 0000000..b0be37f
--- /dev/null
+++ b/t/remove-base-3
@@ -0,0 +1,22 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ "${HEAD} ours" \
+ ours \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --remove-base --no-reduce file
+
+also_interactive bb
diff --git a/t/remove-base-3-empty-base b/t/remove-base-3-empty-base
new file mode 100755
index 0000000..b3e009d
--- /dev/null
+++ b/t/remove-base-3-empty-base
@@ -0,0 +1,21 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ "${HEAD} ours" \
+ ours \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --remove-base --no-reduce file
+
+also_interactive bb
diff --git a/t/remove-base-3-empty-head b/t/remove-base-3-empty-head
new file mode 100755
index 0000000..af4f9e9
--- /dev/null
+++ b/t/remove-base-3-empty-head
@@ -0,0 +1,20 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ "${HEAD} ours" \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+conflict --remove-base --no-reduce file
+
+also_interactive bb
diff --git a/t/remove-base-3-empty-tail b/t/remove-base-3-empty-tail
new file mode 100755
index 0000000..bf0302b
--- /dev/null
+++ b/t/remove-base-3-empty-tail
@@ -0,0 +1,20 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ "${HEAD} ours" \
+ ours \
+ "${TAIL}" \
+ "${END} theirs"
+
+conflict --remove-base --no-reduce file
+
+also_interactive bb
diff --git a/t/remove-base-4 b/t/remove-base-4
new file mode 100755
index 0000000..4e77685
--- /dev/null
+++ b/t/remove-base-4
@@ -0,0 +1,19 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} head" \
+ head \
+ "${PARENT} 2" \
+ second \
+ "${PARENT} 3" \
+ third \
+ "${TAIL}" \
+ tail \
+ "${END} tail"
+
+cp -- file file.expected
+
+conflict --remove-base --no-reduce file
+
+also_interactive b
diff --git a/t/remove-base-5 b/t/remove-base-5
new file mode 100755
index 0000000..fd50087
--- /dev/null
+++ b/t/remove-base-5
@@ -0,0 +1,21 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} head" \
+ head \
+ "${PARENT} 2" \
+ second \
+ "${PARENT} 3" \
+ third \
+ "${PARENT} 4" \
+ fourth \
+ "${TAIL}" \
+ tail \
+ "${END} tail"
+
+cp -- file file.expected
+
+conflict --remove-base --no-reduce file
+
+also_interactive b
diff --git a/t/remove-base-multiple-files b/t/remove-base-multiple-files
new file mode 100755
index 0000000..e3ad177
--- /dev/null
+++ b/t/remove-base-multiple-files
@@ -0,0 +1,33 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > first \
+ "${HEAD} first" \
+ first-head \
+ "${TAIL}" \
+ first-tail \
+ "${END}"
+
+cp -- first first.expected
+
+printf '%s\n' > second \
+ before \
+ "${HEAD} second" \
+ second-head \
+ "${PARENT} middle" \
+ second-middle \
+ "${TAIL}" \
+ second-tail \
+ "${END}"
+
+printf '%s\n' > second.expected \
+ before \
+ "${HEAD} second" \
+ second-head \
+ "${TAIL}" \
+ second-tail \
+ "${END}"
+
+conflict --remove-base --no-reduce first second
+
+also_interactive bbb
diff --git a/t/remove-base-multiple-hunks b/t/remove-base-multiple-hunks
new file mode 100755
index 0000000..c3fdc0f
--- /dev/null
+++ b/t/remove-base-multiple-hunks
@@ -0,0 +1,36 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} first" \
+ first-head \
+ "${TAIL}" \
+ first-tail \
+ "${END}" \
+ between \
+ "${HEAD} second" \
+ second-head \
+ "${PARENT} middle" \
+ second-middle \
+ "${TAIL}" \
+ second-tail \
+ "${END}" \
+ after
+
+printf '%s\n' > file.expected \
+ "${HEAD} first" \
+ first-head \
+ "${TAIL}" \
+ first-tail \
+ "${END}" \
+ between \
+ "${HEAD} second" \
+ second-head \
+ "${TAIL}" \
+ second-tail \
+ "${END}" \
+ after
+
+conflict --remove-base --no-reduce file
+
+also_interactive bbbb
diff --git a/t/remove-base-no-conflicts b/t/remove-base-no-conflicts
new file mode 100755
index 0000000..9c36985
--- /dev/null
+++ b/t/remove-base-no-conflicts
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ no conflicts in this file
+
+cp -- file file.expected
+
+normal --remove-base --no-reduce file
+
+also_interactive ''
diff --git a/t/select-head-1 b/t/select-head-1
new file mode 100755
index 0000000..f803cf2
--- /dev/null
+++ b/t/select-head-1
@@ -0,0 +1,12 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} Head" \
+ head \
+ "${END} Head"
+
+printf '%s\n' > file.expected \
+ head
+
+error --select-head --no-reduce file
diff --git a/t/select-head-2 b/t/select-head-2
new file mode 100755
index 0000000..e050f9f
--- /dev/null
+++ b/t/select-head-2
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} head" \
+ head \
+ "${TAIL}" \
+ tail \
+ "${END} tail"
+
+printf '%s\n' > file.expected \
+ head
+
+normal --select-head --no-reduce file
+
+also_interactive h
diff --git a/t/select-head-3 b/t/select-head-3
new file mode 100755
index 0000000..98e5b63
--- /dev/null
+++ b/t/select-head-3
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ ours
+
+normal --select-head --no-reduce file
+
+also_interactive h
diff --git a/t/select-head-3-empty-base b/t/select-head-3-empty-base
new file mode 100755
index 0000000..0bfa110
--- /dev/null
+++ b/t/select-head-3-empty-base
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD}" \
+ ours \
+ "${PARENT}" \
+ "${TAIL}" \
+ theirs \
+ "${END}"
+
+printf '%s\n' > file.expected \
+ ours
+
+normal --select-head --no-reduce file
+
+also_interactive h
diff --git a/t/select-head-3-empty-head b/t/select-head-3-empty-head
new file mode 100755
index 0000000..f1ebd7c
--- /dev/null
+++ b/t/select-head-3-empty-head
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ "${PARENT} base" \
+ base \
+ "${TAIL} theirs" \
+ theirs \
+ "${END} end of conflict"
+
+: > file.expected
+
+normal --select-head --no-reduce file
+
+also_interactive h
diff --git a/t/select-head-3-empty-tail b/t/select-head-3-empty-tail
new file mode 100755
index 0000000..8041a15
--- /dev/null
+++ b/t/select-head-3-empty-tail
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} o" \
+ ours \
+ "${PARENT} b" \
+ base \
+ "${TAIL}" \
+ "${END} t"
+
+printf '%s\n' > file.expected \
+ ours
+
+normal --select-head --no-reduce file
+
+also_interactive h
diff --git a/t/select-head-4 b/t/select-head-4
new file mode 100755
index 0000000..6c9c9dd
--- /dev/null
+++ b/t/select-head-4
@@ -0,0 +1,22 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} head" \
+ head \
+ "${PARENT} 2" \
+ second \
+ "${PARENT} 3" \
+ third \
+ "${PARENT} 4" \
+ fourth \
+ "${TAIL}" \
+ tail \
+ "${END} tail"
+
+printf '%s\n' > file.expected \
+ head
+
+normal --select-head --no-reduce file
+
+also_interactive h
diff --git a/t/select-head-multiple-files b/t/select-head-multiple-files
new file mode 100755
index 0000000..ba103a1
--- /dev/null
+++ b/t/select-head-multiple-files
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > first \
+ "${HEAD} first" \
+ first-head \
+ "${TAIL}" \
+ first-tail \
+ "${END}"
+
+printf '%s\n' > first.expected \
+ first-head
+
+printf '%s\n' > second \
+ before \
+ "${HEAD} second" \
+ second-head \
+ "${PARENT} middle" \
+ second-middle \
+ "${TAIL}" \
+ second-tail \
+ "${END}"
+
+printf '%s\n' > second.expected \
+ before \
+ second-head
+
+normal --select-head --no-reduce first second
+
+also_interactive hh
diff --git a/t/select-head-multiple-hunks b/t/select-head-multiple-hunks
new file mode 100755
index 0000000..f0bad13
--- /dev/null
+++ b/t/select-head-multiple-hunks
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} first" \
+ first-head \
+ "${TAIL}" \
+ first-tail \
+ "${END}" \
+ between \
+ "${HEAD} second" \
+ second-head \
+ "${PARENT} middle" \
+ second-middle \
+ "${TAIL}" \
+ second-tail \
+ "${END}" \
+ after
+
+printf '%s\n' > file.expected \
+ first-head \
+ between \
+ second-head \
+ after
+
+normal --select-head --no-reduce file
+
+also_interactive hh
diff --git a/t/select-head-no-conflicts b/t/select-head-no-conflicts
new file mode 100755
index 0000000..d996675
--- /dev/null
+++ b/t/select-head-no-conflicts
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ no conflicts in this file
+
+cp -- file file.expected
+
+normal --select-head --no-reduce file
+
+also_interactive ''
diff --git a/t/select-tail-1 b/t/select-tail-1
new file mode 100755
index 0000000..b11e471
--- /dev/null
+++ b/t/select-tail-1
@@ -0,0 +1,12 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} Tail" \
+ tail \
+ "${END} Tail"
+
+printf '%s\n' > file.expected \
+ tail
+
+error --select-tail --no-reduce file
diff --git a/t/select-tail-2 b/t/select-tail-2
new file mode 100755
index 0000000..a6d1c0f
--- /dev/null
+++ b/t/select-tail-2
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} head" \
+ head \
+ "${TAIL}" \
+ tail \
+ "${END} tail"
+
+printf '%s\n' > file.expected \
+ tail
+
+normal --select-tail --no-reduce file
+
+also_interactive t
diff --git a/t/select-tail-3 b/t/select-tail-3
new file mode 100755
index 0000000..7a7962a
--- /dev/null
+++ b/t/select-tail-3
@@ -0,0 +1,18 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} theirs"
+
+printf '%s\n' > file.expected \
+ theirs
+
+normal --select-tail --no-reduce file
+
+also_interactive t
diff --git a/t/select-tail-3-empty-base b/t/select-tail-3-empty-base
new file mode 100755
index 0000000..6e88956
--- /dev/null
+++ b/t/select-tail-3-empty-base
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} head" \
+ ours \
+ "${PARENT} parent" \
+ "${TAIL}" \
+ theirs \
+ "${END} tail"
+
+printf '%s\n' > file.expected \
+ theirs
+
+normal --select-tail --no-reduce file
+
+also_interactive t
diff --git a/t/select-tail-3-empty-head b/t/select-tail-3-empty-head
new file mode 100755
index 0000000..424c73b
--- /dev/null
+++ b/t/select-tail-3-empty-head
@@ -0,0 +1,17 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} OURS" \
+ "${PARENT} BASE" \
+ base \
+ "${TAIL}" \
+ theirs \
+ "${END} THEIRS"
+
+printf '%s\n' > file.expected \
+ theirs
+
+normal --select-tail --no-reduce file
+
+also_interactive t
diff --git a/t/select-tail-3-empty-tail b/t/select-tail-3-empty-tail
new file mode 100755
index 0000000..d625068
--- /dev/null
+++ b/t/select-tail-3-empty-tail
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} ours" \
+ ours \
+ "${PARENT} base" \
+ base \
+ "${TAIL}" \
+ "${END} theirs"
+
+: > file.expected
+
+normal --select-tail --no-reduce file
+
+also_interactive t
diff --git a/t/select-tail-4 b/t/select-tail-4
new file mode 100755
index 0000000..45111db
--- /dev/null
+++ b/t/select-tail-4
@@ -0,0 +1,22 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} head" \
+ head \
+ "${PARENT} 2" \
+ second \
+ "${PARENT} 3" \
+ third \
+ "${PARENT} 4" \
+ fourth \
+ "${TAIL}" \
+ tail \
+ "${END} tail"
+
+printf '%s\n' > file.expected \
+ tail
+
+normal --select-tail --no-reduce file
+
+also_interactive t
diff --git a/t/select-tail-multiple-files b/t/select-tail-multiple-files
new file mode 100755
index 0000000..f2c8ae8
--- /dev/null
+++ b/t/select-tail-multiple-files
@@ -0,0 +1,30 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > first \
+ "${HEAD} first" \
+ first-head \
+ "${TAIL}" \
+ first-tail \
+ "${END}"
+
+printf '%s\n' > first.expected \
+ first-tail
+
+printf '%s\n' > second \
+ before \
+ "${HEAD} second" \
+ second-head \
+ "${PARENT} middle" \
+ second-middle \
+ "${TAIL}" \
+ second-tail \
+ "${END}"
+
+printf '%s\n' > second.expected \
+ before \
+ second-tail
+
+normal --select-tail --no-reduce first second
+
+also_interactive tt
diff --git a/t/select-tail-multiple-hunks b/t/select-tail-multiple-hunks
new file mode 100755
index 0000000..eaa80f1
--- /dev/null
+++ b/t/select-tail-multiple-hunks
@@ -0,0 +1,28 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} first" \
+ first-head \
+ "${TAIL}" \
+ first-tail \
+ "${END}" \
+ between \
+ "${HEAD} second" \
+ second-head \
+ "${PARENT} middle" \
+ second-middle \
+ "${TAIL}" \
+ second-tail \
+ "${END}" \
+ after
+
+printf '%s\n' > file.expected \
+ first-tail \
+ between \
+ second-tail \
+ after
+
+normal --select-tail --no-reduce file
+
+also_interactive tt
diff --git a/t/select-tail-no-conflicts b/t/select-tail-no-conflicts
new file mode 100755
index 0000000..ba98700
--- /dev/null
+++ b/t/select-tail-no-conflicts
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ no conflicts in this file
+
+cp -- file file.expected
+
+normal --select-tail --no-reduce file
+
+also_interactive ''
diff --git a/t/stdin-dash-operand b/t/stdin-dash-operand
new file mode 100755
index 0000000..42d960a
--- /dev/null
+++ b/t/stdin-dash-operand
@@ -0,0 +1,21 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} HEAD" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} branch"
+
+printf '%s\n' > file.expected \
+ same
+
+cp -- file input
+normal --reduce - < input > output
+cmp -s -- file input
+diff -u -- output file.expected >&2
+
+also_interactive r < input > output
+cmp -s -- file input
+diff -u -- output file.expected >&2
diff --git a/t/stdin-dashdash-dash-operand b/t/stdin-dashdash-dash-operand
new file mode 100755
index 0000000..f9e41c6
--- /dev/null
+++ b/t/stdin-dashdash-dash-operand
@@ -0,0 +1,21 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} HEAD" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} branch"
+
+printf '%s\n' > file.expected \
+ same
+
+cp -- file input
+normal --reduce -- - < input > output
+cmp -s -- file input
+diff -u -- output file.expected >&2
+
+also_interactive r < input > output
+cmp -s -- file input
+diff -u -- output file.expected >&2
diff --git a/t/stdin-dashdash-no-operand b/t/stdin-dashdash-no-operand
new file mode 100755
index 0000000..1e9c6c6
--- /dev/null
+++ b/t/stdin-dashdash-no-operand
@@ -0,0 +1,21 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} HEAD" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} branch"
+
+printf '%s\n' > file.expected \
+ same
+
+cp -- file input
+normal --reduce -- < input > output
+cmp -s -- file input
+diff -u -- output file.expected >&2
+
+also_interactive r < input > output
+cmp -s -- file input
+diff -u -- output file.expected >&2
diff --git a/t/stdin-no-operand b/t/stdin-no-operand
new file mode 100755
index 0000000..54a3cb4
--- /dev/null
+++ b/t/stdin-no-operand
@@ -0,0 +1,21 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} HEAD" \
+ same \
+ "${TAIL}" \
+ same \
+ "${END} branch"
+
+printf '%s\n' > file.expected \
+ same
+
+cp -- file input
+normal --reduce < input > output
+cmp -s -- file input
+diff -u -- output file.expected >&2
+
+also_interactive r < input > output
+cmp -s -- file input
+diff -u -- output file.expected >&2
diff --git a/t/unclosed-conflict-head b/t/unclosed-conflict-head
new file mode 100755
index 0000000..4a7f4a2
--- /dev/null
+++ b/t/unclosed-conflict-head
@@ -0,0 +1,12 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} a" \
+ broken
+
+cp -- file file.original
+
+error file
+
+diff -u -- file file.original >&2
diff --git a/t/unclosed-conflict-head-parent b/t/unclosed-conflict-head-parent
new file mode 100755
index 0000000..ae4c501
--- /dev/null
+++ b/t/unclosed-conflict-head-parent
@@ -0,0 +1,14 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} a" \
+ first \
+ "${PARENT} b" \
+ broken
+
+cp -- file file.original
+
+error file
+
+diff -u -- file file.original >&2
diff --git a/t/unclosed-conflict-head-parent-tail b/t/unclosed-conflict-head-parent-tail
new file mode 100755
index 0000000..c05ca5d
--- /dev/null
+++ b/t/unclosed-conflict-head-parent-tail
@@ -0,0 +1,16 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} a" \
+ first \
+ "${PARENT} b" \
+ middle \
+ "${TAIL}" \
+ broken
+
+cp -- file file.original
+
+error file
+
+diff -u -- file file.original >&2
diff --git a/t/unclosed-conflict-head-tail b/t/unclosed-conflict-head-tail
new file mode 100755
index 0000000..b84755e
--- /dev/null
+++ b/t/unclosed-conflict-head-tail
@@ -0,0 +1,14 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${HEAD} a" \
+ first \
+ "${TAIL}" \
+ broken
+
+cp -- file file.original
+
+error file
+
+diff -u -- file file.original >&2
diff --git a/t/unexpected-separator-end b/t/unexpected-separator-end
new file mode 100755
index 0000000..1f81488
--- /dev/null
+++ b/t/unexpected-separator-end
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${END}"
+
+cp -- file file.original
+
+error file
+
+diff -u -- file file.original >&2
diff --git a/t/unexpected-separator-parent b/t/unexpected-separator-parent
new file mode 100755
index 0000000..1b86d70
--- /dev/null
+++ b/t/unexpected-separator-parent
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${PARENT} base"
+
+cp -- file file.original
+
+error file
+
+diff -u -- file file.original >&2
diff --git a/t/unexpected-separator-tail b/t/unexpected-separator-tail
new file mode 100755
index 0000000..e8f8ad6
--- /dev/null
+++ b/t/unexpected-separator-tail
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+. t/common.sh
+
+printf '%s\n' > file \
+ "${TAIL}"
+
+cp -- file file.original
+
+error file
+
+diff -u -- file file.original >&2