web-dev-qa-db-ja.com

gitを使ってファイル全体に対して「自分のものを受け入れる」または「自分のものを受け入れる」ためのシンプルなツール

私は視覚的なマージツールが欲しくないし、衝突したファイルをviして手動でHEAD(私のもの)とインポートされた変更(彼らのもの)のどちらかを選ぶ必要もない。ほとんどの場合、私は彼らのすべての変更または私のすべての変更が必要です。一般的に、これは私の変更がそれを上向きにしてプルによって私に戻ってきているためですが、さまざまな場所でわずかに修正されるかもしれません。

競合マーカーを取り除き、私の選択に基づいて何らかの方法で選択するコマンドラインツールはありますか。あるいは、それぞれを行うために自分自身を別名設定できるgitコマンドのセット。

# accept mine
alias am="some_sequence;of;commands"
alias at="some_other_sequence;of;commands"

これを行うのはかなり面倒です。 「私の同意」のために私は試してみました:

randy@Sabotage ~/linus $ git merge test-branch
Auto-merging Makefile
CONFLICT (content): Merge conflict in Makefile
Automatic merge failed; fix conflicts and then commit the result.

randy@Sabotage ~/linus $ git checkout Makefile 
error: path 'Makefile' is unmerged

andy@Sabotage ~/linus $ git reset --hard HEAD Makefile 
fatal: Cannot do hard reset with paths.

これらの変更マーカーをどうやって取り除くのでしょうか。

できます:

git reset HEAD Makefile; rm Makefile; git checkout Makefile

しかし、これはやや丸みを帯びているように見えますが、もっと良い方法があるはずです。そして現時点で、gitがマージが起こったとさえ考えているのかどうか私にはわからないので、私はこれが必ずしもうまくいくとは思わない。

逆に言えば、「自分のものを受け入れる」ことも同様に面倒です。私がそれを理解することができる唯一の方法はすることです:

git show test-branch:Makefile > Makefile; git add Makefile;

これは私に混乱したコミットメッセージをも与えます。

より簡単な方法で上記の2つのアクションを実行する方法を誰かが指摘できますか?ありがとう

353
nosatalian

解決策はとても簡単です。 git checkout <filename>インデックスからファイルをチェックアウトしようとするため、マージに失敗します。

あなたがする必要があるのは(すなわち、チェックアウトコミット):

自分のバージョンをチェックアウトするにはあなたはoneのうちの1つを使うことができます:

git checkout HEAD -- <filename>

または

git checkout --ours -- <filename>

または

git show :2:<filename> > <filename> # (stage 2 is ours)

他のバージョンをチェックアウトするあなたはoneを使うことができます:

git checkout test-branch -- <filename>

または

git checkout --theirs -- <filename>

または

git show :3:<filename> > <filename> # (stage 3 is theirs)

解決済みとしてマークするには 'add'を実行する必要があります。

git add <filename>
550
Jakub Narębski

これを試して:

自分の変更を受け入れるには:git merge --strategy-option theirs

あなたを受け入れるには:git merge --strategy-option ours

65
Siva Mandadi

Jakubの回答に基づいて、便利なように次のgitエイリアスを設定することができます。

accept-ours = "!f() { git checkout --ours -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"
accept-theirs = "!f() { git checkout --theirs -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"

それらはオプションで解決するためにファイルの1つまたは複数のパスを取り、何も与えられていない場合は現在のディレクトリの下にあるすべてのものをデフォルトで解決します。

それらを[alias]~/.gitconfigセクションに追加するか、または実行してください。

git config --global alias.accept-ours '!f() { git checkout --ours -- "${@:-.}"; git add -u "${@:-.}"; }; f'
git config --global alias.accept-theirs '!f() { git checkout --theirs -- "${@:-.}"; git add -u "${@:-.}"; }; f'
48
kynan

Kynanの答えに基づいて、これは同じエイリアスで、ファイル名のスペースと最初のダッシュを処理できるように修正されています。

accept-ours = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --ours -- \"$@\"; git add -u -- \"$@\"; }; f"
accept-theirs = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --theirs -- \"$@\"; git add -u -- \"$@\"; }; f"
16
Dar

競合を解決するための理想的な状況は、競合を解決する方法を事前に知っており、-Xoursまたは-Xtheirsの再帰的マージ戦略オプションを渡すことができる場合です。これ以外に、私は3つの美しい景色を見ることができます。

  1. ファイルのバージョンを1つだけにしておきます(競合していないファイルと競合していないファイルが互いに同期しなくなる可能性があるため、これはおそらくマージできないバイナリファイルでのみ使用します)。
  2. あなたは単に特定の方向へのすべての衝突を決定したいのです。
  3. 手動でいくつかの競合を解決してから、特定の方向で残りのすべてを解決する必要があります。

これら3つのシナリオに対処するには、.gitconfigファイル(または同等のもの)に次の行を追加します。

[merge]
  conflictstyle = diff3
[mergetool.getours]
  cmd = git-checkout --ours ${MERGED}
  trustExitCode = true
[mergetool.mergeours]
  cmd = git-merge-file --ours ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keepours]
  cmd = sed -I '' -e '/^<<<<<<</d' -e '/^|||||||/,/^>>>>>>>/d' ${MERGED}
  trustExitCode = true
[mergetool.gettheirs]
  cmd = git-checkout --theirs ${MERGED}
  trustExitCode = true
[mergetool.mergetheirs]
  cmd = git-merge-file --theirs ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keeptheirs]
  cmd = sed -I '' -e '/^<<<<<<</,/^=======/d' -e '/^>>>>>>>/d' ${MERGED}
  trustExitCode = true

get(ours|theirs)ツールはファイルのそれぞれのバージョンを保持し、他のバージョンからのすべての変更を破棄します(したがってマージは行われません)。

merge(ours|theirs)ツールは、ファイルのローカル、ベース、およびリモートの各バージョンから3方向のマージをやり直し、指定された方向の競合を解決します。これにはいくつかの注意点があります。特に、mergeコマンドに渡されたdiffオプション(アルゴリズムや空白の処理など)は無視されます。元のファイルからマージをきれいに実行します(したがって、手動で行ったファイルの変更は破棄されます。また、ファイル内にあるはずの差分マーカーと混同しないという利点があります。

keep(ours|theirs)ツールは単にdiffマーカーと囲まれたセクションを編集し、それらを正規表現で検出します。これにはmergeコマンドからのdiffオプションを保持し、あなたが手作業でいくつかの衝突を解決し、それから残りを自動的に解決できるという利点があります。ファイルに他の競合マーカーがあると混乱する可能性があるという欠点があります。

これらはすべてgit mergetool -t (get|merge|keep)(ours|theirs) [<filename>]を実行することによって使用されます。ここで<filename>が指定されていない場合、競合するすべてのファイルが処理されます。

一般的に言って、正規表現を混同するdiffマーカーがないことを知っていると仮定すると、コマンドのkeep*の変種が最も強力です。 mergetool.keepBackupオプションを未設定またはtrueのままにしておくと、マージ後に*.origファイルをマージの結果と比較して意味があることを確認できます。例として、コミットする前に変更を調べるためにmergetoolの後に以下を実行します。

for f in `find . -name '*.orig'`; do vimdiff $f ${f%.orig}; done

merge.conflictstylediff3ではない場合、代わりにsedルールの/^|||||||/パターンを代わりに/^=======/にする必要があります。

0
Parakleta