2013-12-12 4 views
9

Beim Refactoring von Quellcode müssen Sie manchmal große Textblöcke in eine Datei oder sogar in eine neue Datei verschieben. Sie erstellen einen Zweig refactored und verpflichten sich:Verweisen von Git auf verschobene Inhalte (nicht einfach verschobene Dateien)

$git checkout master 
$git branch refactored 
$git checkout refactored 
<move code around> 
$git commit -m "refactored code" 

jedoch Menschen auf dem alten pre-refactor Zweig begehen kann, den Code zu ändern, die verschoben wurde:

$git checkout master 
<change code that was moved elsewhere on branch refactored> 
$git commit -m "bugfix" 

Auf Zweig refactored, Sie dann wollen Änderungen in master gemacht zu übernehmen:

$git checkout refactored 
$git merge master 
<giant merge conflict> 

Dies führt zu einem großen merge Konflikt. Wenn es eine Möglichkeit git mitzuteilen, dass der Inhalt einfach verschoben wurde, sollte es möglich sein, automatisch zusammenzuführen.

Der schlimmste Teil ist, dass auch nach dem Konflikt und commiting es zu lösen, git noch nicht die Auflösung weiter verschmilzt, um herauszufinden, verwenden kann:

<fix conflicts> 
$git commit -m "merge master into refactored" 
$git checkout master 
<change more code> 
$git commit -m "bugfix2" 
$git checkout refactored 
$git merge master 
<another giant merge conflict> 

Ist das überhaupt vermeidbar? Ich habe versucht git rerere und es kann die Konflikte hier nicht lösen. Gibt es irgendeinen Weg, wie Git einen Textblock als tatsächlichen Zug verschieben kann, anstatt ihn zu löschen und einzufügen? Wenn dies nicht möglich ist, was ist der beste Ansatz zum Minimieren von Zusammenführungskonflikten, wenn Sie die beiden parallelen Zweige für eine Weile behalten müssen?

Während dies ist einfach genug für moving the contents of a complete file, konnte ich nicht finden Informationen zum Verschieben nur Teil davon, oder innerhalb der gleichen Datei verschieben.

Auch, wenn es eine Lösung dafür gibt, was wäre das Verhalten von git blame auf dem refaktorierten Code? Würde es auf das Refactoring-Commit zeigen oder es ignorieren? Gibt es einen Weg, das Spätere zu erreichen?

Falls jemand interessiert, ich habe eine Base64-codierte tar.gz des (sehr minimal) Repository habe ich mich für Tests mit on pastebin

Möglichen Lösungen

Eine mögliche Lösung durchführen könnte die Zusammenführen durch Anwenden eines (automatisch) bearbeiteten Patches mit den Änderungen im vorrefaktorierten Zweig. Ist dafür Software entwickelt worden? Mit diesem Ansatz denke ich, dass git blame auf das Refactoring-Commit verweisen würde, da dies für git transparent ist.

Ich habe the same question, applied to diff gefunden. Es gibt keine Erwähnung zu einer bestehenden nicht-proprietären Implementierung, aber dort zu einem Algorithmus, der Blockbewegung verfolgt

+0

Ich schlage vor, Sie mehr begehen zu machen. Wenn Sie eine Menge Daten ändern, haben Sie mehr Commit, die Sie haben, weniger Problem beim Zusammenführen des Codes. – sensorario

+0

@sensorario das ist ein guter Vorschlag im Allgemeinen. Ich bin nicht sicher, wie Sie es für das Refactoring anwenden würden, obwohl - das Verschieben einer Funktion/kleine Blöcke auf einmal nicht helfen wird – goncalopp

+0

Wenn Sie Dateien ändern, haben Sie zwei verschiedene Inhalte. Ja, auch wenn Sie eine Funktion von einer Datei in eine andere verschieben. Wenn Sie Konflikte minimieren möchten, machen Sie mehr und mehr Commits. Bitte versuche. – sensorario

Antwort

1

Leider kann man die eingebauten Git-Merge-Strategien nicht ersetzen, soweit ich das beurteilen kann. Dies bedeutet, dass Sie die Konflikte nicht stoppen können, jedoch können Sie ein intelligentes Werkzeug verwenden, um sie zu lösen.

Dieses Semantic Merge interessant aussieht, kann es auch used by git

+0

Ich habe SemanticMerge im Beispielrepository ausprobiert. Erstens, auf Linux, stellt es 80 MB Abhängigkeiten vor - viele Pakete von plasticscm und was scheint, mono zu sein. Das Zusammenführen muss manuell mit 'git mergetool' durchgeführt werden, und das Tool benötigt eine Interaktion (" Hit return to start ") und verwendet eine GUI (kann nicht von CLI, AFAICT ausgeführt werden). Schließlich konnte ich die Konflikte in meinem Beispiel nicht zusammenführen, da "Parsingfehler gefunden wurden, die Bäume könnten inkonsistent sein". Ich bin mir nicht sicher, ob das Tool tatsächlich irgendwas macht, da ich dann einen Fehler bekomme "Objektverweis nicht auf eine Instanz eines Objekts gesetzt". – goncalopp

+0

Um fair zu sein, habe ich es auf ubuntu 12.04 LTS (Precise Pangolin) ausprobiert, was nicht unbedingt unterstützt wird ('wir garantieren nur die Unterstützung von Debian 6.0, aber dieses Repository kann auch auf neuere Debian - Versionen (wie 7.0, Instanz) und Ubuntu-Distributionen (insbesondere LTS-Versionen) ') – goncalopp

0

sei es nicht möglich ist, diesen zusätzlichen Aufwand zu vermeiden, aber dann wieder das ist, wie Git funktionieren soll:

Die andere grundlegend Smart Design Entscheidung ist, wie Git zusammenführt. Die Merging-Algorithmen sind intelligent, aber sie versuchen nicht, zu schlau zu sein. Eindeutige Entscheidungen werden automatisch getroffen, aber bei Zweifeln liegt es am Benutzer zu entscheiden. So sollte es sein. Sie möchten nicht, dass eine Maschine diese Entscheidungen für Sie trifft. Du wirst es nie wollen. Das ist die grundlegende Erkenntnis in der Git-Ansatz zu verschmelzen: während jedes andere Versionskontrollsystem versucht, intelligenter zu werden, ist Git glücklich selbst als "dummer Content-Manager" beschrieben, und es ist besser dafür.

(Von Wincent Colaiuta's blog)

Verwandte Themen