2016-04-12 16 views
0

Wir verzweigen Master (wir verwenden nicht einen dev-Zweig, fragen Sie nicht warum) und wenn QA eine Zusammenführungs-Anfrage für den Zweig, verbinden wir es mit der QC-Zweig, dann, wenn sie fertig sind Tests, verbinden wir es mit dem Master-Zweig. Wir verschmelzen niemals qc, um Zweige von Master zu qc zu masteren oder zu rebasen, obwohl wir den Zweig schnell zum Master weiterleiten können (durch git merge --ff-only master oder git rebase -i), obwohl es im Allgemeinen einfach ist, einfach überzugehen.Verschmelzung Konflikte zwischen Zweigen beim Zusammenführen zu qc und Master separat

Verzweigungen (basierend auf Aufgaben, die vom Manager festgelegt wurden) können jedoch an verschiedenen Basen gestartet, in einer anderen Reihenfolge in qc zusammengeführt und in einer anderen Reihenfolge wieder in den Master zusammengeführt werden.

Das Problem ist, weil wir oft die gleiche Codezeile für verschiedene Features ändern müssen (wir können dies aufgrund der Art und Weise, wie der Code ursprünglich strukturiert war und welche Änderungen angefordert werden, nicht vollständig vermeiden), so dass wir Merge-Konflikte bekommen fast jede Woche, und wenn Dinge in verschiedenen Ordnungen zu verschiedenen Zweigen zusammengefügt werden, können wir am Ende dieselben Konflikte immer wieder reparieren oder verschiedene Änderungen in derselben Zeile zusammenführen (oder neue Zeilen in verschiedenen Zeilen verteilen) verzweigt sich in verschiedene Zeilen). Whew

Um identische Zusammenführungskonfliktberichtigungen zu beseitigen, versuchten wir den Zweig, der in QC verschmolzen wurde, neu zu gründen (der auf einem Vorlagencommit zurückgehen kann), aber irgendwie die commits auf qc und Meister dupliziert; Es ist in Ordnung, die Commits erneut anzuwenden, um sie zu beherrschen und die auf qc zu verlieren, da wir sie einfach wieder in qc zusammenführen können (wir verschmelzen Master zu qc, wenn er aktualisiert wird).

Wie vermeiden wir diese doppelten Commits und Konflikte, und gibt es einen besseren Weg, dies zu verwalten?

Jemand schlug eine Sache vor: git rebase --onto master qc branch Wäre dies machbar für Zweige, die Konflikte, die müssen, um von qc zu Master gehen zu gehen, um redundante Konfliktlösung zu verhindern?

Antwort

0

Umbasierung Duplikate verpflichtet, weil das ist, was Rebasing ist: es ist eine automatisierte Reihe von git cherry-pick Operationen und git cherry-pick ist ein Commit-Kopierer.

Die Identität jedes Objekts ist sein Hash: 251654c5f6f256fe6e23c2c85f1a70594aae00d4 zum Beispiel. Der Hash-Wert ist eine Prüfsumme des Inhalts des gehashten Objekts. Im Falle eines begehen Objekt sind die Inhalte:

  • den Namen und die E-Mail für den Commit des Autors;
  • Name und E-Mail-Adresse des Committer;
  • die Identität des Top-Level-Quellbaums für das Commit (d. H. Ein Snapshot jeder Datei, die diesem Commit zugeordnet ist, dargestellt durch die ID eines Baumobjekts);
  • die Liste der Eltern-Commit-IDs (mehr Commit-Objekt-Hashes); und
  • die Protokollnachricht für das Festschreiben.

Typischerweise ist der Grund, warum Sie eine Festschreibung herauspicken ist eine leicht verändert, um versions in der Tat, wenn Sie machen ein Bit für Bit genau um die gleiche kopieren Sie bekommen nur die Original-commit ID zurück, da der Hash der gleichen Menge von Eingabebits den gleichen Wert hat. Bei einem Cherry-Picked Commit haben Sie jedoch normalerweise einen etwas anderen Quellbaum und haben fast immer eine andere Eltern-ID.

Betrachten Sie dieses Beispiel begehen (immer so leicht modifiziert, Spam-E-Mail-Scanner zu besiegen):

tree 3b2ac3530e713fc93aa93525bed9623679f99173 
parent d2628061aa3b38b9f5dbdcd9136711a5a4ac3a1a 
author Chris Torek <[email protected]> 1459821791 -0700 
committer Chris Torek <[email protected]> 1459821791 -0700 

distributed: clarify GUID uniqueness 

Add the phrase {Doppelg\"anger commit} in a side-note. 
Git and Mercurial allow them as long as they never meet. 

Ich kann dies, indem zunächst verpflichten kopieren ein git diff gegen seine Eltern tun begehen (zu zeigen, was ich geändert) :

diff --git a/distributed.tex b/distributed.tex 
index 40fb7fd..6d8854b 100644 
--- a/distributed.tex 
+++ b/distributed.tex 
@@ -41,8 +41,18 @@ to discover and exchange commits 
whenever you direct the system to synchronize your clone 
with a peer. 
In order to make this work correctly, 
-these GUIDs really must be globally unique 
-(across all repositories). 
+these GUIDs really must be globally unique.\sidenote 
+{More specifically, they must be unique 
+among all clones of a given repository, 
+\emph{including forks that may rejoin in the future}. 
+This is a somewhat weaker requirement than true global uniqueness. 
+For instance, if Alice makes a commit, 
+but then destroys it without ever sharing it with anyone else, 
+the destroyed commit is allowed to have the same GUID 
+as some future commit, 
+or a commit in an unrelated repository. 
+You can think of this as allowing Doppelg\"anger commits: 
+they may share a GUID only as long as they never meet.} 
It would not do 
for Bob to create a \emph{different} commit (in \git) 
or changeset (in \mercurial) 

Jetzt, wo ich das diff habe ich das diff als Patch einige andere begehen überprüfen können, anwenden und ein neues aus dem Ergebnis, erneut mit der Log-Nachricht begehen machen. Ich werde ein neues Commit, mit der gleichen Protokollmeldung und dem gleichen Effekt auf Datei distributed.tex, aber (wahrscheinlich) anders tree und (definitiv) anders parent, und einen neuen Committer-Zeitstempel und damit einen anderen Hash.

Das ist eine einzige Auswahl: Vergleichen Sie ein Commit mit seinem Parent (um es in ein Changeset zu konvertieren), wenden Sie diese Änderung woanders an und machen Sie ein neues Commit vom Ergebnis. Angenommen, wir diese Operation für eine Kette von Commits wiederholen :

... <- B3 <- B4 <- B5 <-- branch-X 
    \ 
    F6 <- F7 <- F8  <-- feature-Y 

Lassen Sie uns sagen, dass wir F6 durch F8 kopieren. Rufen Sie die Kopie von F6, F6' an, um sie vom Original zu unterscheiden. Machen Sie den Eltern von F6'B5 sein, und die Eltern von F7' sein F6', und die Eltern von F8'F7' sein, so dass wir erhalten:

     F6' <- F7' <- F8' 
        /
... <- B3 <- B4 <- B5 <-- branch-X 
    \ 
    F6 <- F7 <- F8  <-- feature-Y 

ist eine letzte, was wir nun tun. Lassen Sie uns das Etikett feature-Y, entfernen Sie die aktuell begehen F8 stecken, und fügen Sie ihn auf F8' statt.

     F6' <- F7' <- F8' <-- feature-Y 
        /
... <- B3 <- B4 <- B5 <-- branch-X 
    \ 
    F6 <- F7 <- F8  [abandoned] 

Et voila, haben wir gerade umbasiert-d.h, -einige Commits kopiert, die auf feature-Y waren. Die neuen Kopien befinden sich jetzt auf dem Zweig feature-Y (während des Kopiervorgangs waren sie auf keine Zweig, oder besser, auf die spezielle anonyme Zweig, den Sie haben, wenn Sie im "abgetrennten HEAD" -Modus sind) und die Originalkopien sind ... gut , noch da.

Ich markierte sie hier [verlassen], aber wenn es andere Astes an Etiketten, die Sie F8 verpflichten lassen finden, werden Sie noch in der Lage sein, alle Original-Commits zu sehen. Der Befehl git rebase verschiebt das feature-Y-Label, aber nicht, um zu sehen, ob ein anderes Label die Commits sichtbar hält.


bearbeiten: Das gleiche gilt, wenn einige der kopierten-und-dann-aufgegeben Commits über eine Zusammenführung sichtbar sind begehen, zum Beispiel:

     F6' <- F7' <- F8' <-- feature-Y 
        /
.... <- B3 <- B4 <- B5 <-- branch-X 
\ \ 
\ F6 <- F7 <- F8  [abandoned] 
    \    \ 
    C2 <--- C3 <-- C4  <-- branch-C 

Hier branch-C macht begeht C2 durch C4 sichtbar, aber C4 ist ein Merge-Commit, das F8 sichtbar macht. So jetzt beide F8 (über C4 von branch-C) und F8' (über feature-Y) wird angezeigt, wenn Sie das Repository durchsuchen.

Diese Art der Sache steuert, wann und warum Sie sollten oder nicht umbasen sollten. Seit Rebase Kopien verpflichtet, müssen Sie eines von zwei Dingen sicher sein: dass die Originale wirklich aufgegeben werden, oder dass es in Ordnung ist, die Originale an anderer Stelle zu erhalten. [Bearbeiten beenden.]


Die andere Sache, dass git rebase automatisiert für Sie ist die Wahl, die zu kopieren verpflichtet. Warum haben wir uns entschieden, F6 durch F8 zu kopieren? Warum diese drei einschließen und alle anderen ausschließen? Dies ist, wo die Argumente zu git rebase in kommen die jetzt auf diesen Vorschlag Lassen zurückkehren.

git rebase --onto master qc branch 

Dies ist die vollständig angegebene Form git rebase. Das allerletzte Argument, , macht git rebase in diesem Fall git checkout branch. Das heißt, das zusätzliche Argument wird einfach an git checkout übergeben. Danach kann das zusätzliche Argument nicht mehr verwendet werden, also könnten wir folgendes tun:

stattdessen.

Der --onto commit Teil des Befehls gibt an, wo die Kopien gehen. Genauer gesagt, kopierten wir F6 zu F6' mit seinem neuen Elternteil B5. Wenn Sie --onto verwenden, geben Sie dieses Ziel-Commit an. (Einen Zweignamen verwenden, in diesem Fall master, bedeutet nur, um die Spitze zu verwenden begeht an diesem Zweig.)

Die ein Argument bleibt, gc in unserem Fall ist das, was git rebase Anrufe <upstream>.

Wenn wir das täten nicht--onto angeben, das <upstream> Argument würde zwei Rollen hat: es das Ziel verpflichten nennen würde, und es würde git rebase die Identität eines verpflichten, dass es sollte speziell nicht Kopie (und dann nicht kopieren noch mehr Commits, basierend auf dieser ID). Wenn wir jedoch --onto verwenden, haben wir bereits das Ziel-Commit angegeben, sodass das verbleibende Argument nur noch eine Rolle hat: Commits angeben, um das Kopieren zu vermeiden.

Die Art und Weise, wie dieses "Commits to Copy vermeiden" -Ding funktioniert, kann ein bisschen schwierig sein, sich den Kopf zu wickeln. Wir spezifizieren eine insbesondere commit, aber Rebase verwendet hier einen Trick, den git selbst ständig benutzt.Wenn wir git verweisen auf einige begehen, können wir sie fragen bei nur suchen, die zu begehen:

$ git rev-parse c96a 
c96af44caf036cf9f04d77c6146086a4ee422ceb 

oder wir können sie bitten, schaut euch das an begehen und alle seine Eltern verpflichtet (auch bekannt als seine Abstammung):

$ git rev-list c96a 
c96af44caf036cf9f04d77c6146086a4ee422ceb 
bca8213e6fda6fdf92b3a5fbc4ee59f755e04a9c 
86ac01b3e1d771033e93af93366ace1b586d7c74 
bc3fa7a3571231e334f6f06e5610e04227ef1f0b 

(rev-parse tut das ein Commit Sache während rev-list die Abstammung Variante standardmäßig der Fall ist, obwohl rev-list enorm flexibel und ist im Herzen oder zumindest die Leber oder Milz-von vielen Git-Befehlen).

Git rebase wählt sein <upstream> Argument mit Abstammung Commits zu bekommen, um ausschließen, während der aktuelle Zweig Auswahl (nach der Überprüfung heraus, wenn Sie ihnen geben, dass ein zusätzliches Argument) mit Abstammung Commits zu bekommen, um umfassen. Was immer bleibt, nachdem die Ausschlussgruppe ausgeschlossen wurde, sind die zu kopierenden Commits.

Mit der --onto Formularfreigaben <upstream> von seiner Doppeltätigkeitsrolle, so dass Sie selektiver sein können, wenn Sie entscheiden, welche Zusagen zu vermeiden, zu kopieren. Sie werden immer noch Commits kopieren, mit allem was dazu gehört. Insbesondere, wenn Sie Rebase zu kopieren (und dann vergessen Sie die Originale von) Commits, die andere Leute verwenden, müssen sie auch jede Arbeit, die sie getan haben, dass Rebben auf die Originale.

+0

Ich bemerkte, dass die Kopien nur passieren, wenn die Commits in einem anderen Zweig zusammengeführt wurden; nicht zusammengefügte Zweige würden ohne Kopieren reBasen. –

+0

Sie werden immer noch kopiert. Was mit dem Merge-Fall passiert ist, dass * die Originale noch erreichbar sind *, diesmal nicht von einem Branch-Namen, sondern von dem Merge-Commit. Ich füge ein Beispiel mit einer Zusammenführung hinzu. – torek