gitマージの競合を説明するために、同じ意味を持つ2つのgitベースではないテキストファイルをマージします。

gitマージの競合を説明するために、同じ意味を持つ2つのgitベースではないテキストファイルをマージします。

git「マージの競合」が説明されている方法と同様の意味を使用して、gitベースではなく2つのテキストファイルをマージしたいと思います。

file.1たとえば、名前が似ているが内容が同じではない2つのテキストファイルがあるとしますfile.2。これら2つのファイルを次のように3番目のファイルにマージしたいと思います。

hypothetical-merge-utility file.1 file.2 file.merged

file.merged次のような方法でファイルの内容と各相違点を一覧表示する作成が必要です。

common line 1 ...
common line 2 ...
common line 3 ...
<<<<<<< file.1
something unique from file.1
a second line of something unique from file.1
======= file.2
something unique from file.2
>>>>>>> end of diff
common line 4 ...
common line 5 ...
<<<<<<< file.1
something unique from file.1
======= file.2
something unique from file.2
a second line of something unique from file.2
>>>>>>> end of diff
common line 6 ...
common line 7 ...
... etc. ...

つまり、file.1との間のすべての違いがfile.2「マージの競合」の表現に似ていることを望みますgit

<<<<<<<<、、、および========その他の区切り記号を使用しても構いません。>>>>>>>>

Linuxには、テキストファイルをマージするために使用できるユーティリティがたくさんあることがわかっています。しかし、私はただgit「マージの競合」が説明されているのと同様の方法で、マージされたデータを具体的に表すコンテンツを見つけます。

そのようなユーティリティについて知っている人はいますか?

よろしくお願いします。

修正する:Ed Mortonの次の質問に基づいて、両方のテストファイルの内容は次のとおりです。

====ファイル。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 ...

====ファイル。2 ====

common line 1 ...
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 ...

答え1

ノート:これはやや合理的な「回答」だと思いますが、今はもう一つの「答え」を思いつきました。以下の他の「回答」を参照してください。

この「答え」の元のバージョンは...

ああ!ここに文を載せるには早すぎますね。-Dコマンドラインオプションを知らなかったdiffが、これができることに気づきました...

diff -D file.1 file.2 >file.merged

それは次のものを生成しますfile.merged...

common line 1 ...
common line 2 ...
common line 3 ...
#ifdef file.1
something unique from file.1
a second line of something unique from file.1
#else /* file.1 */
something unique from file.2
#endif /* file.1 */
common line 4 ...
common line 5 ...
#ifdef file.1
something unique from file.1
#else /* file.1 */
something unique from file.2
a second line of something unique from file.2
#endif /* file.1 */
common line 6 ...
common line 7 ...
... etc. ...

私が余裕があり#ifdef#elseOK、私が余裕がある#endifようにgit<<<<<<<<OK。========>>>>>>>>

修正する:...私はこれを見つけました: https://stackoverflow.com/questions/16902001/manually-merge-two-files-using-diff

統合diff形式を使用して同様の操作を実行する方法も示します。合計の最大行数よりも大きい引数を持つオプションをdiff提供します。たとえば...-Ufile.1file.2

diff -U 99999999 file.1 file.2 | tail -n +4 >file.merged

これにより、次のような結果が生成されます。

 common line 1 ...
 common line 2 ...
 common line 3 ...
+something unique from file.2
-something unique from file.1
-a second line of something unique from file.1
 common line 4 ...
 common line 5 ...
+something unique from file.2
+a second line of something unique from file.2
-something unique from file.1
 common line 6 ...
 common line 7 ...
 ... etc. ...

線は+の固有データを表しfile.2-線はの固有データを表しますfile.1

私はそれ+-行を扱うことができます。

答え2

出力形式にあまり興味がないように聞こえますが、各ファイルからどの行が出るのか、どの行が共通しているのかを識別する方法を知りたいだけです。これはどうですか:

$ diff --old-line-format=$'-%l\n' --new-line-format=$'+%l\n' --unchanged-line-format=$'=%l\n' file.1 file.2
=common line 1 ...
=common line 2 ...
=common line 3 ...
-something unique from file.1
-a second line of something unique from file.1
+something unique from file.2
=common line 4 ...
=common line 5 ...
-something unique from file.1
+something unique from file.2
+a second line of something unique from file.2
=common line 6 ...
=common line 7 ...

その行のソースインジケータを取得するために行の内容をテストする必要があるソリューションに注意してください(たとえば、<<<<<<< file.1何が一意であるかを知りたい場合はfile1fileその文字列とまったく同じ行が含まれている場合はどうなりますか?)。常に発生します。その文字列が入力に表示される可能性がある場合、すべての文字列のテストは失敗するため、各行の一意の位置を示すマークです。上記のように、最初の文字は常に行のソースを表しているため、可能なファイルの内容と競合しません。 git merge衝突の正確な出力形式を取得するには(推奨されません)、上記の内容を印刷する単純なawkスクリプトにパイプするか、行の<<< file最初の文字が必要に応じて変更されたときに常にパイプすることができます。その文字を削除してください。

答え3

diff -D ...と関連する最初の「回答」に最初に投稿したソリューションの制限のため、Pythonモジュールを使用してPythonでソリューションを作成することdiff -U ...にしました。difflib

、、、などの文字列を含む区切り文字をgit使用しますが、わかるように、元のテキストにこのような文字列が含まれていると、あいまいさが発生する可能性があります。しかし、「マージクラッシュ」出力にも同じ曖昧さが存在する可能性がありますが、私はそれに満足して喜んで一緒に住んでいるので、私のソリューションのこのあいまいさにも満足しています。<<<<<<<<========>>>>>>>>gitgit

出力は「マージ衝突」出力とまったく同じではありませんが、git私が望むだけで十分です。

まず、ここにPythonプログラムがあります(ここで公開した元のPythonコードをクリーンアップしましたが、これがクリーンアップされたバージョンです)。私はこのプログラムを呼び出します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())

これはテストに使用した入力ファイルです。元の質問に投稿した入力ファイルと似ていますが、まったく同じではありません...

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 ...

このように命令を実行します...

filemerge file.1 file.2 >file.merged

結果は次のとおりです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 ...

前述のように、これはMerge Contributesの出力とまったく同じ形式ではありませんが、非常にgit似ており、私には十分似ています。

関連情報