Due to the limitations of the solutions I originally posted in my first "Answer" here which involve diff -D ...
and diff -U ...
, I decided to write a solution in python, using python's difflib
module.
I wrote it to produce output which looks relatively similar to the "merge conflict" output from git
. It utilizes delimiters containing the strings <<<<<<<<
, ========
, and >>>>>>>>
, and as we know, this might lead to ambiguities if the original text contains strings like this. However, this same problem with ambiguities could exist within "merge conflict" output from git
, but since I'm comfortable with git
and willing to accept it there, I'm also comfortable with these ambiguities in my own solution.
The output isn't precisely the same as that from git
"merge conflict" output, but it's similar enough to satisfy my wishes.
First, here is the python program (I cleaned up the original python code that I posted here, and this is the cleaned-up version). I call this program filemerge
...
#!/usr/bin/python3
### Take the diff's between two files and output
### the common and different lines in a manner
### which is very similar to the way that `git`
### depicts merge conflicts.
import sys
sys.dont_write_bytecode = True
import os
from difflib import unified_diff
prog = None
diff_start = '<<<<<<<<'
diff_sep = '========'
diff_end = '>>>>>>>>'
def main():
if len(sys.argv) < 3:
print(f'\nusage: {prog} file1 file2\n')
return 1
file1, file2 = sys.argv[1:3]
data1 = None
data2 = None
missing = []
try:
with open(file1, 'r') as f:
data1 = f.readlines()
except Exception:
missing.append(file1)
try:
with open(file2, 'r') as f:
data2 = f.readlines()
except Exception:
missing.append(file2)
if missing:
print(f'\nnot found: {", ".join(missing)}\n')
return 1
n1 = len(data1)
n2 = len(data2)
max_lines = (n1 + 1) if n1 > n2 else (n2 + 1)
count = 0
state = ''
sep_printed = False
next_file = ''
for line in unified_diff(data1, data2, n=max_lines):
count += 1
if count < 4:
continue
# Every line which is returned by unified_diff()
# is at least 2 characters long. Each of these
# lines starts with either ' ', '+', or '-', and
# each of these lines ends with a newline.
line = line[:-1]
ch0 = line[0]
if ch0 == ' ':
if state:
state = ''
if not sep_printed:
print(f'{diff_sep}{next_file}')
print(diff_end)
sep_printed = False
next_file = ''
elif ch0 == '-':
if state == ch0:
pass
elif state == '+':
print(f'{diff_sep} file={file1}')
sep_printed = True
next_file = ''
else:
print(f'{diff_start} file={file1}')
sep_printed = False
next_file = f' file={file2}'
state = ch0
elif ch0 == '+':
if state == ch0:
pass
elif state == '-':
print(f'{diff_sep} file={file2}')
sep_printed = True
next_file = ''
else:
print(f'{diff_start} file={file2}')
sep_printed = False
next_file = f' file={file1}'
state = ch0
print(line[1:])
if state:
if not sep_printed:
print(f'{diff_sep}{next_file}')
next_file = ''
print(diff_end)
return 0
if __name__ == '__main__':
prog = os.path.basename(sys.argv[0])
sys.exit(main())
Here are the input files that I tested it with. They're similar but not exactly the same as the input files I originally posted in my question here ...
==== file.1
====
common line 1 ...
common line 2 ...
common line 3 ...
something unique from file.1
a second line of something unique from file.1
common line 4 ...
common line 5 ...
something unique from file.1
common line 6 ...
common line 7 ...
penultimate file.1 line
common line 8 ...
==== file.2
====
common line 1 ...
second line from file.2
common line 2 ...
common line 3 ...
something unique from file.2
common line 4 ...
common line 5 ...
something unique from file.2
a second line of something unique from file.2
common line 6 ...
common line 7 ...
common line 8 ...
I run the command like this ...
filemerge file.1 file.2 >file.merged
And these are the resulting contents of file.merged
...
common line 1 ...
<<<<<<<< file=file.2
second line from file.2
======== file=file.1
>>>>>>>>
common line 2 ...
common line 3 ...
<<<<<<<< file=file.1
something unique from file.1
a second line of something unique from file.1
======== file=file.2
something unique from file.2
>>>>>>>>
common line 4 ...
common line 5 ...
<<<<<<<< file=file.1
something unique from file.1
======== file=file.2
something unique from file.2
a second line of something unique from file.2
>>>>>>>>
common line 6 ...
common line 7 ...
<<<<<<<< file=file.1
penultimate file.1 line
======== file=file.2
>>>>>>>>
common line 8 ...
As I mentioned, this isn't precisely the same format as that of the "merge conflict" output from git
, but it's very similar, and that's close enough for me.
file.1
andfile.2
, are shown.