Muss Git bei Konflikten beim Zusammenführen einer bestimmten Datei die lokale Version auswählen?

Lesezeit: 10 Minuten

Muss Git bei Konflikten beim Zusammenfuhren einer bestimmten Datei die
saffsd

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.

  • 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


Muss Git bei Konflikten beim Zusammenfuhren einer bestimmten Datei die
VonC

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

  • Vielen Dank für die ausführliche Antwort! Ich verstehe, dass es keinen Sinn macht, Konfigurationsdateien zu versionieren, aber ich war hinter einem einfachen, motivierenden Beispiel her. In der Tat ist es die umfassendere Frage, die mich interessiert. Ich hatte noch nie zuvor von Git-Merge-Treibern gehört, also danke, dass Sie mich aufgeklärt haben.

    – saffsd

    31. Mai 2009 um 1:32 Uhr

  • Die cp -f $3 $2 sollte wohl zitiert werden, dh cp -f "$3" "$2".

    – Bogen

    27. September 2010 um 10:40 Uhr


  • @VonC danke für die ausführliche Antwort! Das Problem, das ich damit habe, ist, dass es davon abhängt, ob die Leute den Treiber in ihrer .git/config-Datei einstellen. Ich möchte die Treiberinformationen zum Projekt selbst hinzufügen, damit dies automatisch erfolgt und weniger Einrichtungsarbeit erforderlich ist. Irgendwelche Hinweise?

    – Juan Delgado

    19. Dezember 2011 um 16:34 Uhr

  • @ulmangt: Sie können dieses Skript auch sehr gut im Git-Repo speichern, … solange Sie einen Weg finden, das übergeordnete Verzeichnis zum hinzuzufügen PATH (Unix oder Windows PATH). Da dieses Skript über die Unix-Bash-Shell oder über die MingWin-Bash-MsysGit-Windows-Shell interpretiert wird, ist es portabel.

    – VonC

    4. April 2012 um 14:32 Uhr

  • @VonC Danke. Noch ein Thema. Unter bestimmten Umständen (wenn keine Änderungen an dem lokalen Zweig vorgenommen wurden, in den gemergt wird) scheint es, dass der Merge-Treiber überhaupt nicht aufgerufen wird, was dazu führt, dass die lokalen Dateien geändert werden (die den benutzerdefinierten Merge-Treiber verwenden sollen). um zu verhindern, dass sie sich während einer Zusammenführung ändern). Gibt es eine Möglichkeit Gewalt git immer den Merge-Treiber verwenden?

    – ulmangt

    4. April 2012 um 15:15 Uhr


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!)

  • (Nebenbei: Wenn jemand die Antwort als Kommentar gibt und keine Antwort hinzufügt, ist es vollkommen in Ordnung, eine Nicht-CW-Antwort zu schreiben und die Credits zu erhalten. Wenn sie immer noch ein aktives Mitglied sind, können Sie sie anpingen, um eine Antwort hinzuzufügen, wenn Sie wünschen, aber sie hatten technisch bereits ihre Chance :-)).

    – Halber

    2. Januar 2020 um 21:29 Uhr

1646878690 14 Muss Git bei Konflikten beim Zusammenfuhren einer bestimmten Datei die
HamletHub

Wir haben mehrere Konfigurationsdateien, die wir niemals überschreiben möchten. Allerdings funktionierten .gitignore und .gitattributes in unserer Situation nicht. Unsere Lösung bestand darin, die Konfigurationsdateien in einem Konfigurationszweig zu speichern. Erlauben Sie dann, dass die Dateien während der Git-Zusammenführung geändert werden, aber verwenden Sie unmittelbar nach der Zusammenführung den „git checkout branch –“. um unsere Konfigurationsdateien nach jedem Zusammenführen aus dem Konfigurationszweig zu kopieren. Ausführliche Stackoverflow-Antwort hier

985650cookie-checkMuss Git bei Konflikten beim Zusammenführen einer bestimmten Datei die lokale Version auswählen?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy