wake-up-neo.com

Einfaches Tool zum 'Annehmen' oder 'Annehmen' einer ganzen Datei mit git

Ich möchte kein visuelles Zusammenführungswerkzeug, und ich möchte auch nicht die in Konflikt stehende Datei anzeigen und manuell zwischen HEAD (mir) und der importierten Änderung (deren) wählen müssen. Die meiste Zeit möchte ich entweder alle oder alle meine Änderungen haben. Dies ist im Allgemeinen darauf zurückzuführen, dass meine Änderung die Anforderungen erfüllt hat und durch Ziehen zu mir zurückkehrt, aber möglicherweise an verschiedenen Stellen geringfügig geändert wird.

Gibt es ein Kommandozeilen-Tool, das die Konfliktmarkierungen entfernt und auf die eine oder andere Art und Weise auswählt, wie ich es gewählt habe? Oder eine Reihe von Git-Befehlen, die ich mir jeweils selbst geben kann.

# accept mine
alias am="some_sequence;of;commands"
alias at="some_other_sequence;of;commands"

Das zu tun ist ziemlich nervig. Für 'akzeptiere meine' habe ich versucht:

[email protected] ~/linus $ git merge test-branch
Auto-merging Makefile
CONFLICT (content): Merge conflict in Makefile
Automatic merge failed; fix conflicts and then commit the result.

[email protected] ~/linus $ git checkout Makefile 
error: path 'Makefile' is unmerged

[email protected] ~/linus $ git reset --hard HEAD Makefile 
fatal: Cannot do hard reset with paths.

Wie soll ich diese Änderungsmarker loswerden?

Ich kann:

git reset HEAD Makefile; rm Makefile; git checkout Makefile

Aber das scheint ziemlich rund, es muss einen besseren Weg geben. Und zum jetzigen Zeitpunkt bin ich mir nicht sicher, ob git überhaupt glaubt, dass die Fusion stattgefunden hat, also denke ich nicht, dass dies notwendigerweise überhaupt funktioniert.

In die andere Richtung zu gehen, „ihre anzunehmen“, ist ebenso chaotisch. Der einzige Weg, wie ich es herausfinden kann, ist:

git show test-branch:Makefile > Makefile; git add Makefile;

Dies gibt mir auch eine durcheinandergebrachte Commit-Nachricht, die zweimal Conflicts: Makefile enthält.

Kann jemand bitte darauf hinweisen, wie die beiden oben genannten Aktionen auf einfachere Weise durchgeführt werden können? Vielen Dank

365
nosatalian

Die Lösung ist sehr einfach. git checkout <filename> versucht, die Datei aus dem Index auszuchecken, und schlägt daher beim Zusammenführen fehl.

Was Sie tun müssen, ist (d. H. Auschecken eines Festschreiben):

Zum Auschecken Ihrer eigenen Version Sie können eine von:

git checkout HEAD -- <filename>

oder

git checkout --ours -- <filename>

oder

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

Zum Auschecken der anderen Version Sie können eines von:

git checkout test-branch -- <filename>

oder

git checkout --theirs -- <filename>

oder

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

Sie müssten auch 'add' ausführen, um es als gelöst zu markieren:

git add <filename>
561
Jakub Narębski

Versuche dies:

Um ihre Änderungen zu akzeptieren: git merge --strategy-option theirs

Um deine zu akzeptieren: git merge --strategy-option ours

73
Siva Mandadi

Basierend auf der Antwort von Jakub können Sie die folgenden Git-Aliase zur Vereinfachung konfigurieren:

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

Sie können optional einen oder mehrere Dateipfade zum Auflösen verwenden und standardmäßig alles im aktuellen Verzeichnis auflösen, wenn keine angegeben sind.

Fügen Sie sie dem Abschnitt [alias] Ihres ~/.gitconfig Hinzu oder führen Sie sie aus

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'
50
kynan

Basierend auf der Antwort von kynan sind hier die gleichen Aliase, die so geändert wurden, dass sie Leerzeichen und anfängliche Gedankenstriche in Dateinamen verarbeiten können:

accept-ours = "!f() { [ -z \"[email protected]\" ] && set - '.'; git checkout --ours -- \"[email protected]\"; git add -u -- \"[email protected]\"; }; f"
accept-theirs = "!f() { [ -z \"[email protected]\" ] && set - '.'; git checkout --theirs -- \"[email protected]\"; git add -u -- \"[email protected]\"; }; f"
17
Dar

Die ideale Situation zum Lösen von Konflikten ist, wenn Sie im Voraus wissen, auf welche Weise Sie sie lösen möchten, und die Optionen -Xours Oder -Xtheirs Für rekursive Zusammenführungsstrategien übergeben können. Draußen sehe ich drei Szenarien:

  1. Sie möchten nur eine einzelne Version der Datei behalten (dies sollte wahrscheinlich nur für nicht zusammenführbare Binärdateien verwendet werden, da ansonsten konfliktbehaftete und nicht konfliktbehaftete Dateien nicht miteinander synchronisiert werden können).
  2. Sie möchten einfach alle Konflikte in eine bestimmte Richtung entscheiden.
  3. Sie müssen einige Konflikte manuell lösen und dann den gesamten Rest in eine bestimmte Richtung auflösen.

Um diese drei Szenarien zu lösen, können Sie Ihrer .gitconfig - Datei (oder einer entsprechenden Datei) die folgenden Zeilen hinzufügen:

[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

Das Tool get(ours|theirs) behält nur die jeweilige Version der Datei bei und verwirft alle Änderungen von der anderen Version (es findet also keine Zusammenführung statt).

Das Tool merge(ours|theirs) führt die Drei-Wege-Zusammenführung aus der lokalen, der Basis- und der Remoteversion der Datei erneut durch und löst Konflikte in der angegebenen Richtung. Dies hat einige Einschränkungen, insbesondere: Es werden die Diff-Optionen ignoriert, die an den Merge-Befehl übergeben wurden (z. B. Algorithmus- und Whitespace-Behandlung). Führt die Zusammenführung sauber von den Originaldateien aus (so dass alle manuellen Änderungen an der Datei verworfen werden, die gut oder schlecht sein können); und hat den Vorteil, dass es nicht durch Diff-Marker verwechselt werden kann, die in der Datei enthalten sein sollen.

Das Werkzeug keep(ours|theirs) bearbeitet einfach die Diff-Marken und eingeschlossenen Abschnitte und erkennt sie durch regulären Ausdruck. Dies hat den Vorteil, dass die Diff-Optionen aus dem Merge-Befehl erhalten bleiben und Sie einige Konflikte manuell lösen und den Rest automatisch lösen können. Dies hat den Nachteil, dass andere Konfliktmarkierungen in der Datei verwirrt werden können.

Diese werden alle durch Ausführen von git mergetool -t (get|merge|keep)(ours|theirs) [<filename>] verwendet, wobei, wenn <filename> Nicht angegeben wird, alle in Konflikt stehenden Dateien verarbeitet werden.

Wenn Sie wissen, dass es keine Diff-Marker gibt, die den regulären Ausdruck verwirren, sind die keep* - Varianten des Befehls im Allgemeinen die mächtigsten. Wenn Sie die Option mergetool.keepBackup Nicht setzen oder auf true setzen, können Sie nach dem Zusammenführen die Datei *.orig Mit dem Ergebnis des Zusammenführens vergleichen, um zu überprüfen, ob dies sinnvoll ist. Als Beispiel führe ich nach dem mergetool Folgendes aus, um die Änderungen vor dem Festschreiben zu überprüfen:

for f in `find . -name '*.orig'`; do vimdiff $f ${f%.orig}; done

Hinweis: Wenn merge.conflictstyle Nicht diff3 Ist, muss das /^|||||||/ - Muster in der sed -Regel /^=======/ stattdessen.

1
Parakleta