it-swarm.com.de

Wie sage ich git, meine lokale Version für konfliktbehaftete Zusammenführungen einer bestimmten Datei immer auszuwählen?

Angenommen, ich arbeite mit einer Person ü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 einzurichten, um mich nicht jedes Mal, wenn ich ziehe, über einen Konflikt zu beklagen? Ich möchte beim Zusammenfügen dieser Datei immer meine lokale Version auswählen.

90
saffsd

In der konkreten Instanz einer Konfigurationsdatei stimme ich der Rons Antwort zu:
Eine Konfiguration sollte für Ihren Arbeitsbereich "privat" sein (daher "ignoriert", wie in "in einer .gitignore-Datei deklariert").
Möglicherweise haben Sie eine Konfigurationsdatei template mit tokenized values ​​ und ein Skript, das diese config.template-Datei in eine private (und ignorierte) Konfigurationsdatei umwandelt.


Diese spezielle Bemerkung beantwortet jedoch keine allgemeinere Frage, d. H. Ihre Frage (!):

Wie sage ich git, meine lokale Version für konfliktbehaftete Zusammenführungen einer bestimmten Datei immer auszuwählen? (für eine beliebige Datei oder Dateigruppe)

Diese Art der Zusammenführung ist eine "Kopierzusammenführung", bei der Sie immer die "unsere" oder "ihre" -Version einer Datei kopieren, wenn ein Konflikt vorliegt.

(wie Brian Vandenberg notes in den Kommentaren , 'ours' und 'theirs') werden hier für eine Zusammenführung verwendet.
Sie sind umgekehrt für eine rebase: siehe " Why is the meaning of “ours” and “theirs” reversed with git-svn ", die eine Rebase verwendet, " git rebase, die 'local' und 'remote' " verfolgt.

Für "eine Datei" (eine Datei im Allgemeinen, die nicht von einer "config" -Datei spricht, da dies ein schlechtes Beispiel ist), würden Sie dies mit einem benutzerdefinierten Skript erreichen, das durch Zusammenführen aufgerufen wird.
Git wird dieses Skript aufrufen, weil Sie einen gitattributes -Wert definieren, der einen benutzerdefinierten Merge-Treiber definiert.

Der "benutzerdefinierte Zusammenführungstreiber" ist in diesem Fall ein sehr einfaches Skript, das die aktuelle Version im Wesentlichen unverändert lässt, sodass Sie immer Ihre lokale Version auswählen können. 


Testen wir das in einem einfachen Szenario mit einem msysgit 1.6.3 unter Windows in einer reinen DOS-Sitzung:

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 aufweisen, die jedoch 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" auf "myBranch" mit folgenden Elementen zu verbinden:

  • manuelle Lösung für widersprüchliche Zusammenführungen
  • außer für dirWithCopyMerge\b.txt, wo ich immer meine-Version von b.txt aufbewahren möchte.

Da die Zusammenführung in 'MyBranch' erfolgt, werden wir wieder zu ihr wechseln und die 'gitattributes' -Anweisungen hinzufügen, 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 eine .gitattributes-Datei im dirWithCopyMerge-Verzeichnis definiert (nur in dem Zweig definiert, in dem die Zusammenführung stattfindet: myBranch), und wir haben eine .git\config-Datei, die jetzt einen Zusammenführungstreiber 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 ist bereit zum Zusammenführen und hat Konflikte
  • b.txt bleibt noch unangetastet, da der Merge-Treiber dafür sorgen soll (aufgrund der Direktive in der .gitattributes-Datei in seinem Verzeichnis).

Definieren Sie einen keepMine.sh an einer beliebigen Stelle in Ihrem %PATH% (oder $PATH für unseren Unix-Freund. Ich mache beides natürlich: Ich habe eine Ubuntu-Sitzung in einer VirtualBox-Sitzung)

Wie kommentiert von lrkwz und im Abschnitt " Merge Strategies " von Git - Git-Attribute anpassen beschrieben, können Sie das Shell-Skript durch den Shell-Befehl true ersetzen.

git config merge.keepMine.driver true

Im allgemeinen Fall können Sie jedoch 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 Zusammenführungstreiber;) (In diesem Fall ist es noch einfacher, verwenden Sie true).
(Wenn Sie die andere Version beibehalten möchten, fügen Sie vor der exit 0-Zeile Folgendes ein:
cp -f $3 $2.
Das ist es. Der Merge-Treiber würde die Version aus dem anderen Zweig immer beibehalten und alle lokalen Änderungen überschreiben.

Jetzt wiederholen wir die Zusammenführung von Anfang an:

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'.

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 beibehalten wurde

type dirWithCopyMerge\b.txt
b
myLineForB

Das letzte Commit repräsentiert die full -Mischung:

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

(Die Zeile, die mit Merge beginnt, beweist das.)


Sie können einen Serientreiber definieren, kombinieren und/oder überschreiben, so wie Git dies tun wird:

  • <dir>/.gitattributes prüfen (das sich im selben Verzeichnis wie der betreffende Pfad befindet): Vorrang vor dem anderen .gitattributes in Verzeichnissen
  • Dann prüft es .gitattributes (das sich im übergeordneten Verzeichnis befindet) und setzt nur dann Anweisungen, wenn es noch nicht festgelegt ist
  • Schließlich untersucht es $GIT_DIR/info/attributes. Diese Datei wird verwendet, um die In-Tree-Einstellungen zu überschreiben. Es werden <dir>/.gitattributes-Anweisungen überschrieben.

Mit "Kombinieren" meine ich "Aggregat" für mehrere Zusammenführungstreiber.
Nick Green versucht, in den Kommentaren , um Merge-Treiber tatsächlich zu kombinieren: siehe " Pom's über Python-Git-Treiber zusammenführen ".
.__ Wie in seiner anderen Frage erwähnt, funktioniert es jedoch nur bei Konflikten (gleichzeitige Änderung in beiden Zweigen).

133
VonC

Wir haben mehrere Konfigurationsdateien, die wir niemals überschreiben wollen. .Gitignore und .gitattributes funktionierten in unserer Situation jedoch nicht. Unsere Lösung bestand darin, die Konfigurationsdateien in einem Konfigurationszweig zu speichern. Lassen Sie dann die Dateien während der git-Zusammenführung ändern, verwenden Sie jedoch unmittelbar nach der Zusammenführung den "git checkout branch -". um unsere Konfigurationsdateien nach jeder Zusammenführung aus dem Zweig configs zu kopieren . Detaillierte Stackoverflow-Antwort hier

0
HamletHub