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


399

視覚的なマージツールは必要ありません。また、競合するファイルを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つのアクションをより簡単に行う方法を誰かが指摘できますか?ありがとう


4
私はそれを3年以上gitコマンドラインユーザーとしてあなたに提供する必要があります。これはメモリから行うのが途方もなく難しいと思います。それは本当にデフォルトで組み込まれるべきです。
Mauvis Ledford 2013

回答:


602

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

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

自分のバージョンをチェックアウトするには、次のいずれかを使用できます。

git checkout HEAD -- <filename>

または

git checkout --ours -- <filename>

または

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

他のバージョンをチェックアウトするには、次のいずれかを使用できます。

git checkout test-branch -- <filename>

または

git checkout --theirs -- <filename>

または

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

また、「追加」を実行して解決済みとしてマークする必要があります。

git add <filename>

31
私はそれは少し奇妙なことが判明--oursし、--theirs意味を正確に、このコマンドを実行しようとしたとき、私は直感的に考えたものの反対...
ジョシュアMuheim

6
使用するときは注意してくださいgit show。これにより、改行の正規化がスキップされます。
クロニアル

2
これは、いくつかのファイルには適していますが、多くのファイルが競合している場合(コメントの日付が変更されたため)、どのように実行しますか?
JhovaniC 2013

4
@Santhos:--リビジョン(ブランチ名など)をパス名(ファイル名、ディレクトリ)から分離するためにGitによって使用されます。名前がブランチの名前なのかファイルの名前なのかをGitが判断できない場合は重要です。これは、オプションと引数(ファイル名)を区切るために二重ダッシュを使用するというPOSIX(またはGNU)の規則に従います。
JakubNarębski、2014年

3
@Sammaron @Joshua Muheim; リベース操作のコンテキストで競合を解決している場合、theirs/ oursが入れ替わって表示されることがあります。リベースはターゲットブランチをチェックアウトし、「your」ブランチからターゲットにコミットをチェリーピックすることで機能するため、着信変更(「theirs」)は「your」ブランチからのものであり、現在のブランチはターゲットブランチ(「ours」)です。 )。
RJFalconer

93

これを試して:

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

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


5
これにより、競合するすべてのファイルに対する変更が保持されるため、予期しない競合が発生した場合に危険になる可能性があります。
John

3
また、cherry-pickやrebaseなどの他のmerge-yコマンドにこれを使用できます。
idbrii 2016年

50

Jakubの答えに基づいて、便宜のために次のgitエイリアスを設定できます:

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

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

またはrunの[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'

1
私のために働いていません...これらはbashまたは他のシェルですか?
user456584

これらはgitエイリアスです。の[alias]セクションに追加する~.gitconfigか、を使用してくださいgit config --global accept-ours "..."。私の答えを編集しました。
kynan 2012

2
このエイリアスがどれだけの時間を節約してくれたかはわかりません。いいぞ!
アダムパーキン

1
@hakreエイリアスを引用符で囲んでください。そうしないと、シェルがエイリアスを解釈しようとします。または、手動でを編集します~/.gitconfig
kynan 2013

1
デフォルト値のシェル構文:!f() { git checkout --ours -- "${@:-.}" git add -u "${@:-.}; }; f
jthill

17

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"

0

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

  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方向マージを再実行し、指定された方向の競合を解決することを選択します。これにはいくつかの注意点があります。具体的には、マージコマンドに渡されたdiffオプション(アルゴリズムや空白処理など)を無視します。元のファイルからきれいにマージを行います(そのため、ファイルへの手動による変更は破棄されます。また、ファイルにあるはずのdiffマーカーと混同されないという利点があります。

keep(ours|theirs)このツールは、単に正規表現でそれらを検出し、差分マーカーと囲まれたセクションを編集します。これには、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.conflictstyleでない場合は、ルールdiff3/^|||||||/パターンを代わりにsedする必要があり/^=======/ます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.