web-dev-qa-db-ja.com

特定のファイルで競合するマージに対して常にローカルバージョンを選択するようにgitに指示するにはどうすればよいですか?

Gitリポジトリを介して誰かと共同作業を行っているとします。外部の変更を一切受け入れたくない特定のファイルがあります。

Git pullのたびに競合のマージについて文句を言わないようにローカルリポジトリを設定する方法はありますか?このファイルをマージするときは、常にローカルバージョンを選択したいと思います。

94
saffsd

構成ファイルの特定のインスタンスでは、 Ronの答え に同意します。
configはワークスペースに対して「プライベート」にする必要があります(「_.gitignore_ファイルで宣言」のように「無視」されます)。
構成ファイルtemplateトークン化された値があり、その_config.template_ファイルをプライベートに変換するスクリプトがある場合があります(および無視された)構成ファイル。


ただし、その特定の発言は、より一般的な質問、つまりあなたの質問(!)とは答えません:

特定のファイルで競合するマージに対して常にローカルバージョンを選択するようにgitに指示するにはどうすればよいですか? (ファイルまたはファイルのグループの場合)

この種のマージは「コピーマージ」であり、競合が発生した場合は常に「私たち」または「彼らの」バージョンのファイルをコピーします。

Brian Vandenberg 注意 コメント内の'ours'および 'theirs'はここでマージに使用されます
これらはreversedで、rebase:リベースを使用する「 _Why is the meaning of “ours” and “theirs” reversed with git-svn_ 」を参照してください。 「 _git rebase_、「ローカル」と「リモート」を追跡する 」)

「ファイル」(一般的なファイルであり、「config」ファイルとは言えませんが、これは悪い例ですから)では、マージを通じて呼び出されるカスタムスクリプトを使用してそれを実現します。
Gitはそのスクリプトを呼び出します。これは、カスタムマージドライバーを定義する gitattributesvalue を定義するためです。

「カスタムマージドライバー」は、この場合、基本的に現在のバージョンを変更せずに維持する非常に単純なスクリプトであるため、常にローカルバージョンを選択できます。


単純なシナリオで、Windowsのmsysgit 1.6.3を使用して、単なるDOSセッションでテストしてみましょう。

_cd f:\prog\git\test
mkdir copyMerge\dirWithConflicts
mkdir copyMerge\dirWithCopyMerge
cd copyMerge
git init
Initialized empty Git repository in F:/prog/git/test/copyMerge/.git/
_

次に、2つのファイルを作成してみましょう。どちらのファイルにも競合がありますが、マージの方法は異なります。

_echo a > dirWithConflicts\a.txt
echo b > dirWithCopyMerge\b.txt
git add -A
git commit -m "first commit with 2 directories and 2 files"
[master (root-commit) 0adaf8e] first commit with 2 directories and 2 files
_

2つの異なるgitブランチのこれらのファイルのコンテンツに「競合」を導入します。

_git checkout -b myBranch
Switched to a new branch 'myBranch'
echo myLineForA >> dirWithConflicts\a.txt
echo myLineForB >> dirWithCopyMerge\b.txt
git add -A
git commit -m "add modification in myBranch"
[myBranch 97eac61] add modification in myBranch

git checkout master
Switched to branch 'master'
git checkout -b hisBranch
Switched to a new branch 'hisBranch'
echo hisLineForA >> dirWithConflicts\a.txt
echo hisLineForB >> dirWithCopyMerge\b.txt
git add -A
git commit -m "add modification in hisBranch"
[hisBranch 658c31c] add modification in hisBranch
_

次に、「myBranch」に「hisBranch」をマージしてみましょう。

  • 競合するマージの手動解決
  • except_dirWithCopyMerge\b.txt_の場合、常に保持したいmyバージョンの_b.txt_。

マージは「MyBranch」で発生するため、それに切り替えて、マージ動作をカスタマイズする「gitattributes」ディレクティブを追加します。

_git checkout myBranch
Switched to branch 'myBranch'
echo b.txt merge=keepMine > dirWithCopyMerge\.gitattributes
git config merge.keepMine.name "always keep mine during merge"
git config merge.keepMine.driver "keepMine.sh %O %A %B"
git add -A
git commit -m "prepare myBranch with .gitattributes merge strategy"
[myBranch ec202aa] prepare myBranch with .gitattributes merge strategy
_

_.gitattributes_ファイルがdirWithCopyMergeディレクトリ(マージが発生するブランチでのみ定義:myBranch)に定義されており、_.git\config_ファイルがあります。マージドライバが含まれるようになりました。

_[merge "keepMine"]
        name = always keep mine during merge
        driver = keepMine.sh %O %A %B
_

KeepMine.shをまだ定義しておらず、とにかくマージを開始した場合、以下が得られます。

_git merge hisBranch
sh: keepMine.sh: command not found
fatal: Failed to execute internal merge
git st
# On branch myBranch
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   dirWithConflicts/a.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

type dirWithConflicts\a.txt
a
<<<<<<< HEAD:dirWithConflicts/a.txt
myLineForA
=======
hisLineForA
>>>>>>> hisBranch:dirWithConflicts/a.txt
_

それは結構です:

  • _a.txt_はマージする準備ができており、競合があります
  • _b.txt_は、マージドライバーがそれを処理することになっているため、まだ変更されていません(ディレクトリ内の_.gitattributes_ファイル内のディレクティブのため)。

_keepMine.sh_を_%PATH%_の任意の場所で定義します(またはUnixの友人の場合は_$PATH_。両方とも行います:VirtualBoxセッションでUbuntuセッションがあります)

lrkwz による コメント 、および Gitのカスタマイズ-Git属性 の「 Merge Strategies 」セクションで説明されているように、シェルを置き換えることができますシェルコマンドtrueを使用したスクリプト。

_git config merge.keepMine.driver true
_

ただし、一般的な場合、スクリプトファイルを定義できます。

keepMine.sh

_# I want to keep MY version when there is a conflict
# Nothing to do: %A (the second parameter) already contains my version
# Just indicate the merge has been successfully "resolved" with the exit status
exit 0
_

(これは1つの単純なマージドライバーでした;)(その場合はさらに単純で、trueを使用します)
(他のバージョンを保持する場合は、_exit 0_行の前に追加します。
_cp -f $3 $2_。
それでおしまい。ドライバーをマージすると、他のブランチからのバージョンが保持され、ローカルの変更が上書きされます)

では、最初からマージを再試行しましょう。

_git reset --hard
HEAD is now at ec202aa prepare myBranch with .gitattributes merge strategy

git merge hisBranch
Auto-merging dirWithConflicts/a.txt
CONFLICT (content): Merge conflict in dirWithConflicts/a.txt
Auto-merging dirWithCopyMerge/b.txt
Automatic merge failed; fix conflicts and then commit the result.
_

マージは失敗します...a.txtの場合のみ
a.txtを編集して、「hisBranch」の行をそのままにして、

_git add -A
git commit -m "resolve a.txt by accepting hisBranch version"
[myBranch 77bc81f] resolve a.txt by accepting hisBranch version
_

このマージ中にb.txtが保存されていることを確認しましょう

_type dirWithCopyMerge\b.txt
b
myLineForB
_

最後のコミットはfullマージを表します:

_git show -v 77bc81f5e
commit 77bc81f5ed585f90fc1ca5e2e1ddef24a6913a1d
Merge: ec202aa 658c31c
git merge hisBranch
Already up-to-date.
_

(Mergeで始まる行はそれを証明します)


Gitのように、マージドライバーを定義、結合、および/または上書きできることを考慮してください。

  • _<dir>/.gitattributes_(問題のパスと同じディレクトリにあります)を調べます:ディレクトリ内の他の_.gitattributes_に優先します
  • 次に、_.gitattributes_(親ディレクトリにある)を調べ、まだ設定されていない場合にのみディレクティブを設定します
  • 最後に_$GIT_DIR/info/attributes_を調べます。このファイルは、ツリー内の設定を上書きするために使用されます。 _<dir>/.gitattributes_ディレクティブを上書きします。

「結合」とは、複数のマージドライバーを「集約」することを意味します。
Nick Green は、実際にマージドライバを結合しようとする コメント内の :「 python git driver を介したpomのマージ」を参照してください。 。
ただし、 彼の他の質問 で述べたように、競合の場合にのみ機能します(両方のブランチでの同時変更)。

137
VonC

上書きしたくない設定ファイルが複数あります。ただし、.gitignoreおよび.gitattributesはこの状況では機能しませんでした。私たちの解決策は、構成ファイルを構成ブランチに保存することでした。次に、gitマージ中にファイルを変更できるようにしますが、マージの直後に「git checkout branch-」を使用します。マージのたびにconfigsブランチから設定ファイルをコピーします。 スタックオーバーフローの詳細な回答はこちら

0
HamletHub