Angenommen, ich arbeite mit jemandem über ein Git-Repository zusammen und es gibt eine bestimmte Datei, an der ich niemals externe Änderungen akzeptieren möchte.
Gibt es eine Möglichkeit, mein lokales Repo so einzurichten, dass es sich nicht bei jedem Git-Pull über eine Konfliktzusammenführung beschwert? Ich möchte beim Zusammenführen dieser Datei immer meine lokale Version auswählen.
In Bezug auf die spezifische Instanz einer Konfigurationsdatei würde ich Rons Antwort zustimmen:
Eine Konfiguration sollte für Ihren Arbeitsbereich “privat” sein (daher “ignoriert”, wie in “deklariert in a .gitignore
Datei”).
Möglicherweise haben Sie eine Konfigurationsdatei Vorlage mit Tokenisierte Werte darin, und ein Skript, das das umwandelt config.template
Datei in eine private (und ignorierte) Konfigurationsdatei.
Diese spezifische Bemerkung beantwortet jedoch nicht eine umfassendere, allgemeinere Frage, dh Ihre Frage (!):
Wie kann ich Git anweisen, immer meine lokale Version für Konflikte bei Zusammenführungen einer bestimmten Datei auszuwählen? (für jede Datei oder Gruppe von Dateien)
Diese Art der Zusammenführung ist eine “Kopie-Zusammenführung”, bei der Sie immer “unsere” oder “ihre” Version einer Datei kopieren, wenn es einen Konflikt gibt.
(wie Brian Vandenberg in den Kommentaren anmerkt, ‘ours
‘ und ‘theirs
‘ werden hier für eine Zusammenführung verwendet.
Sie sind rückgängig gemacht Für ein rebasieren: sehen “Why is the meaning of “ours” and “theirs” reversed with git-svn
“, das eine Rebase verwendet, “git rebase
Verfolgen von ‘lokal’ und ‘remote'”)
Für “eine Datei” (eine Datei im Allgemeinen, nicht die Rede von einer “Konfigurations”-Datei, da dies ein schlechtes Beispiel ist) würden Sie dies mit einem benutzerdefinierten Skript erreichen, das durch Zusammenführungen aufgerufen wird.
Git ruft dieses Skript auf, weil Sie a definieren müssen Gitarristen Wertwas a definiert benutzerdefinierter Merge-Treiber.
Der “benutzerdefinierte Merge-Treiber” ist in diesem Fall ein sehr einfaches Skript, das im Grunde die aktuelle Version unverändert beibehält, sodass Sie immer Ihre lokale Version auswählen können.
IE., wie von Ciro Santilli festgestellt:
echo 'path/to/file merge=ours' >> .gitattributes
git config --global merge.ours.driver true
Lassen Sie uns das in einem einfachen Szenario mit msysgit 1.6.3 unter Windows in einer reinen DOS-Sitzung testen:
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/
Lassen Sie uns nun zwei Dateien erstellen, die beide Konflikte haben, aber unterschiedlich zusammengeführt werden.
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
Wir werden einen “Konflikt” in den Inhalt dieser beiden Dateien in zwei verschiedenen Git-Zweigen einführen:
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
Versuchen wir nun, “hisBranch” mit “myBranch” zusammenzuführen, mit:
- manuelle Lösung für widersprüchliche Zusammenführungen
- außer zum
dirWithCopyMerge\b.txt
wo ich immer bleiben will mein Version von b.txt
.
Da die Zusammenführung erfolgt in ‘MyBranch
‘, wir wechseln zurück und fügen das ‘gitattributes
‘ Direktiven, die das Zusammenführungsverhalten anpassen.
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
Wir haben ein .gitattributes
Datei definiert in der dirWithCopyMerge
Verzeichnis (nur in dem Zweig definiert, in dem die Zusammenführung erfolgt: myBranch
), und wir haben eine .git\config
Datei, die jetzt einen Merge-Treiber enthält.
[merge "keepMine"]
name = always keep mine during merge
driver = keepMine.sh %O %A %B
Wenn Sie keepMine.sh noch nicht definieren und die Zusammenführung trotzdem starten, erhalten Sie Folgendes.
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
Das ist gut:
a.txt
bereit ist, zusammengeführt zu werden, und enthält Konflikte
b.txt
noch unangetastet, da sich der Merge-Treiber darum kümmern soll (aufgrund der Direktive in der .gitattributes
Datei in seinem Verzeichnis).
Definiere a keepMine.sh
irgendwo in deinem %PATH%
(oder $PATH
für unseren Unix-Freund. Ich mache natürlich beides: Ich habe eine Ubuntu-Sitzung in einer VirtualBox-Sitzung)
Wie von lrkwz kommentiert und beschrieben im “Strategien zusammenführen„Abschnitt von Anpassen von Git – Git-Attributekönnen Sie das Shell-Skript durch den Shell-Befehl ersetzen true
.
git config merge.keepMine.driver true
Aber im allgemeinen Fall können Sie eine Skriptdatei definieren:
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
(Das war ein einfacher Merge-Treiber 😉 (Noch einfacher in diesem Fall use true
)
(Wenn Sie die andere Version behalten möchten, fügen Sie einfach vor der exit 0
Linie:
cp -f $3 $2
.
Das ist es. Ihr Merge-Treiber würde immer die Version aus dem anderen Zweig behalten und alle lokalen Änderungen überschreiben)
Lassen Sie uns nun die Zusammenführung von Anfang an wiederholen:
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.
Die Zusammenführung schlägt fehl… nur für a.txt.
Bearbeiten Sie a.txt und verlassen Sie die Zeile von ‘hisBranch’, dann:
git add -A
git commit -m "resolve a.txt by accepting hisBranch version"
[myBranch 77bc81f] resolve a.txt by accepting hisBranch version
Lassen Sie uns überprüfen, ob b.txt während dieser Zusammenführung erhalten geblieben ist
type dirWithCopyMerge\b.txt
b
myLineForB
Das letzte Commit repräsentiert die voll verschmelzen:
git show -v 77bc81f5e
commit 77bc81f5ed585f90fc1ca5e2e1ddef24a6913a1d
Merge: ec202aa 658c31c
git merge hisBranch
Already up-to-date.
(Die Zeile, die mit Merge beginnt, beweist das)
Denken Sie daran, dass Sie Merge-Treiber definieren, kombinieren und/oder überschreiben können, wie es Git tun wird:
- untersuchen
<dir>/.gitattributes
(das sich im selben Verzeichnis wie der betreffende Pfad befindet): wird sich gegenüber dem anderen durchsetzen .gitattributes
in Verzeichnissen
- Dann prüft es
.gitattributes
(das sich im übergeordneten Verzeichnis befindet) wird nur Anweisungen setzen, wenn sie noch nicht gesetzt sind
- Abschließend wird geprüft
$GIT_DIR/info/attributes
. Diese Datei wird verwendet, um die In-Tree-Einstellungen zu überschreiben. Es wird überschrieben <dir>/.gitattributes
Richtlinien.
Mit “Kombinieren” meine ich “Aggregat” mehrerer Merge-Treiber.
Nick Green versucht in den Kommentaren tatsächlich Merge-Treiber zu kombinieren: siehe “Poms über den Python-Git-Treiber zusammenführen“.
Wie in seiner anderen Frage erwähnt, funktioniert es jedoch nur im Konfliktfall (gleichzeitige Änderung in beiden Zweigen).
Wie @ciro-santilli kommentiert hat, ist die einfache Möglichkeit, es zu verwenden .gitattributes
mit Einstellungen es:
path/to/file merge=ours
und aktivieren Sie diese Strategie mit:
git config --global merge.ours.driver true
(Ich füge dies als Antwort hinzu, um es sichtbarer zu machen, mache es aber zu einem Community-Wiki, um nicht zu versuchen, die Credits des Benutzers für mich selbst zu übertreffen. Bitte stimmen Sie seinen Kommentar unter dem Q hier hoch, um ihm ein Lob auszusprechen!)
Ich habe gerade eine einfache Lösung über .gitattributes und einen sehr einfachen “Merge-Treiber” hinzugefügt.
– VonC
30. Mai 2009 um 20:13 Uhr
TD;LR :
echo 'path/to/file merge=ours' >> .gitattributes && git config --global merge.ours.driver true
– Ciro Santilli Путлер Капут 六四事
28. April 2014 um 14:51 Uhr
@CiroSantilli: Funktioniert wie ein Zauber unter Linux. Dieser Treiber ist einfach genug, um in Git eingebaut zu werden …
– krlmlr
15. August 2014 um 18:10 Uhr
Möchten Sie Ihre Änderungen in die Datei übertragen? Oder ist es zum Beispiel eine Konfigurationsdatei, in der die Standardeinstellung in git gespeichert ist.
– Ian Ringrose
22. September 2016 um 11:04 Uhr
Der Kommentar von @CiroSantilli新疆改造中心六四事件法轮功 ist korrekt, aber dieses Verhalten wird für jedes Repo auf Ihrem System mit dem auftreten
--global
Schild. Wenn Sie dieses Verhalten nur für ein einzelnes Repo wünschen, lassen Sie die--global
Flagge:echo 'path/to/file merge=ours' >> .gitattributes && git config merge.ours.driver true
– Majorobot
25. Februar 2019 um 22:09 Uhr