520 Stimmen

Einfaches Werkzeug zum "Akzeptieren von deren" oder "Akzeptieren von meinen" für eine ganze Datei mit Git

Ich möchte kein visuelles Zusammenführungswerkzeug, und ich möchte auch nicht die konfliktbehaftete Datei durchsuchen und manuell zwischen HEAD (meiner) und der importierten Änderung (ihrer) wählen müssen. Meistens möchte ich entweder alle ihre Änderungen oder alle meine. Meistens liegt das daran, dass meine Änderung es nach oben geschafft hat und durch einen Pull zu mir zurückkommt, aber an verschiedenen Stellen leicht verändert sein kann.

Gibt es ein Befehlszeilentool, das die Konfliktmarkierungen beseitigt und alles auf die eine oder andere Weise auswählt, je nach meiner Wahl? Oder gibt es eine Reihe von Git-Befehlen, die ich mit Aliasen versehen kann, um jeden einzelnen Befehl auszuführen.

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

Das ist ziemlich lästig. Für "Meinen akzeptieren" habe ich es versucht:

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

randy@sabotage ~/linus $ git checkout Makefile 
error: path 'Makefile' is unmerged

andy@sabotage ~/linus $ git reset --hard HEAD Makefile 
fatal: Cannot do hard reset with paths.

Wie soll ich diese Änderungsmarkierungen wieder loswerden?

Ich kann das:

git reset HEAD Makefile; rm Makefile; git checkout Makefile

Aber das scheint ziemlich umständlich zu sein, es muss einen besseren Weg geben. Und zu diesem Zeitpunkt bin ich mir nicht sicher, ob Git überhaupt denkt, dass die Zusammenführung stattgefunden hat, also glaube ich nicht, dass dies notwendigerweise überhaupt funktioniert.

Umgekehrt ist es genauso chaotisch, wenn man "die ihren" akzeptiert. Der einzige Weg, wie ich es herausfinden kann, ist tun:

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

Dadurch erhalte ich auch eine verkorkste Commit-Meldung, die Konflikte enthält: Makefile zweimal vorkommt.

Kann mir jemand zeigen, wie man die beiden oben genannten Aktionen auf einfachere Weise durchführen kann? Danke

731voto

Jakub Narębski Punkte 286531

Die Lösung ist sehr einfach. git checkout <filename> versucht, die Datei von der Index und scheitert daher bei der Zusammenführung.

Was Sie tun müssen, ist (z. B. ein Checkout übergeben. ):

Um Ihre eigene Version zu überprüfen können Sie un von:

git checkout HEAD -- <filename>

o

git checkout --ours -- <filename>

(Warnung!: Wenn Sie eine Umbasierung vornehmen --ours y --theirs getauscht werden.)

o

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

Um die andere Version zu überprüfen können Sie un von:

git checkout test-branch -- <filename>

o

git checkout --theirs -- <filename>

o

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

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

git add <filename>

157voto

Siva Mandadi Punkte 3433

Versuchen Sie dies:

Ihre Änderungen zu akzeptieren: git merge --strategy-option theirs

Ihre zu akzeptieren: git merge --strategy-option ours

56voto

kynan Punkte 12437

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

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

Sie nehmen optional einen oder mehrere Pfade von aufzulösenden Dateien an und lösen standardmäßig alles unter dem aktuellen Verzeichnis auf, wenn keine angegeben werden.

Fügen Sie sie zu den [alias] Abschnitt Ihres ~/.gitconfig oder laufen

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'

19voto

Dar Punkte 171

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

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

3voto

Parakleta Punkte 1051

Die ideale Situation für die Lösung von Konflikten ist, wenn Sie im Voraus wissen, wie Sie den Konflikt lösen wollen, und die -Xours o -Xtheirs Optionen für eine rekursive Zusammenführungsstrategie. Darüber hinaus sehe ich drei Möglichkeiten:

  1. Sie möchten nur eine einzige Version der Datei behalten (dies sollte wahrscheinlich nur bei nicht zusammenführbaren Binärdateien verwendet werden, da sonst konfliktbehaftete und nicht konfliktbehaftete Dateien nicht mehr synchronisiert werden können).
  2. Sie wollen einfach alle Konflikte in eine bestimmte Richtung entscheiden.
  3. Sie müssen einige Konflikte manuell lösen und dann alle anderen in einer bestimmten Richtung auflösen.

Um diese drei Szenarien zu berücksichtigen, können Sie die folgenden Zeilen in Ihre .gitconfig Datei (oder gleichwertig):

[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

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

El merge(ours|theirs) führt die dreifache Zusammenführung der lokalen, der Basis- und der entfernten Version der Datei erneut durch, wobei die Konflikte in der angegebenen Richtung aufgelöst werden. Dies hat einige Nachteile, insbesondere: es ignoriert die Diff-Optionen, die an den Merge-Befehl übergeben wurden (z. B. Algorithmus und Leerzeichenbehandlung); führt den Merge sauber von den Originaldateien aus durch (so dass alle manuellen Änderungen an der Datei verworfen werden, was gut oder schlecht sein kann); und hat den Vorteil, dass es nicht durch Diff-Markierungen verwirrt werden kann, die eigentlich in der Datei sein sollten.

El keep(ours|theirs) werden einfach die Diff-Markierungen und die eingeschlossenen Abschnitte herausgefiltert, indem sie durch reguläre Ausdrücke erkannt werden. Dies hat den Vorteil, dass die Diff-Optionen des Merge-Befehls erhalten bleiben und Sie einige Konflikte von Hand und den Rest automatisch lösen können. Der Nachteil ist, dass es zu Verwechslungen kommen kann, wenn die Datei weitere Konfliktmarkierungen enthält.

Diese werden alle verwendet, indem sie git mergetool -t (get|merge|keep)(ours|theirs) [<filename>] wenn <filename> nicht angegeben wird, werden alle konfliktbehafteten Dateien verarbeitet.

Im Allgemeinen, vorausgesetzt, Sie wissen, dass es keine Diff-Marker gibt, die den regulären Ausdruck verwirren, ist die keep* Varianten des Befehls sind die leistungsfähigsten. Wenn Sie die mergetool.keepBackup Option nicht gesetzt oder wahr ist, können Sie nach der Zusammenführung die *.orig Datei mit dem Ergebnis der Zusammenführung vergleichen, um zu prüfen, ob es sinnvoll ist. Als Beispiel führe ich Folgendes nach der mergetool um die Änderungen vor dem Übertragen zu überprüfen:

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

Hinweis : Wenn die merge.conflictstyle ist nicht diff3 dann die /^|||||||/ Muster im sed Regel muss sein /^=======/ stattdessen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X