2016-11-15 3 views
3

In diesem Beispiel denkt git nicht, dass es umbasen muss, aber es tut es eindeutig.Warum denkt dieser Gitarrist, dass es nichts zu tun gibt?

Hier ist eine schnelle Skript ist ein Mini-Test Git Repository

#!/bin/bash 
rm -rf testgit 
mkdir testgit 
cd testgit 
git init 
echo -e "a\nb\nc" > file 
git add file 
git commit -am 'first' 

git checkout -b lineA 
echo -e "A\nb\nc" > file 
git commit -am 'A' 

git checkout -b lineB 
echo -e "a\nB\nc" > file 
git commit -am 'B' 

git checkout -b lineC 
echo -e "a\nb\nC" > file 
git commit -am 'C' 

Danach läuft, ist hier zu schaffen, was file wie in jedem Zweig

master | lineA | lineB | lineC 
------------------------------ 

a  A  a  a 
b  b  B  b 
c  c  c  C 

Jetzt ist sieht alle Zweige in Master lassen fusionieren, danach sollte jeder Buchstabe in file groß geschrieben werden

$ git checkout master 
$ git merge lineA 

Okay.

$ git checkout lineB 
$ git rebase master 
Current branch lineB is up to date. 

Was? Nein, der Meister hat sich geändert.

$ git checkout master 
$ cat file 
A 
b 
c 

$ git checkout lineB 
$ cat file 
a 
B 
c 

Es scheint mir, dass Branch lineB muss Rebase die Änderung zu Master durch Fusion LineA übernommen enthalten.

Warum denkt Git nicht, dass dies getan werden muss?

Außerdem, wenn Sie das tun

$ git checkout master 
$ git merge lineA 
Already up-to-date. 
$ git merge lineB 
... 
1 file changed, 2 insertions(+), 2 deletions(-) 
$ cat file 
a 
B 
c 
$ git merge lineC 
... 
1 file changed, 2 insertions(+), 2 deletions(-) 
$ cat file 
a 
b 
C 

Hier werden die Verschmelzungen sollte in Konflikt geraten, aber git ist clobbering sie leise. Ich weiß nicht, ob das relevant ist, aber es scheint komisch.

Antwort

2

Ergebnis der ersten Befehle

Nach dem Skript haben wir (die Leitungszweig Namen abzukürzen ...):

master lA lB lC 
    ↓  ↓ ↓ ↓ 
first----A----B----C 

Diese Befehle:

$ git checkout master 
$ git merge lineA 

Ergebnisse in eine Schnellvorlauf-Zusammenführung, die master verschiebt, um auf denselben Commit wie lineA zu zeigen.

Giving:

 master 
     lA lB lC 
     ↓ ↓ ↓ 
first----A----B----C 

keine Arbeit für die Rebase

Also diese Folge von Befehlen:

$ git checkout lineB 
$ git rebase master 

sagen, ist die lineB Zweig oben auf master bewegen.

... aber es ist bereits oben auf master.

master müsste einige Commits in seiner Geschichte haben, die lineB nicht für den Rebase-Befehl hat, um irgendeine Arbeit zu haben.

Kein Merge Konflikt

Wenn Git ein merge commit schafft es die Geschichte der Eltern berücksichtigt, die in der Zusammenführung gehen werden. In diesem Fall zeigen beide Zweige auf Commits in einer gemeinsamen Commit-Kette. Git kann sehen, dass der A Commit vor dem B Commit kam, der vor dem C Commit kam. Als solches betrachtet Git die späteren Commits als Ergänzungen zu den früheren Commits und als solche stehen sie nicht in Konflikt.

Wenn stattdessen Sie hatten eine Geschichte wie:

 master 
     ↓ 
     ---A 
    /
    | lB 
    | ↓ 
first----B 

dann Git sie als parallele Entwicklungslinien sehen würde. In diesem Fall würde das Zusammenführen von lB in master oder umgekehrt zu Konflikten führen. Dies liegt daran, B ist kein Zusatz auf A in der Geschichte und als solche braucht Git Benutzereingaben, um zu verstehen, welche der Änderungen zu halten.

+0

ich denke das Gleiche. Verwenden Sie die Erweiterung git, um die Form Ihrer Zweige zu sehen. Für mich haben alle deine erstellten Zweige ihren Ursprung auf Master, also sagt dir Git auf seine Art, dass keine Rebase benötigt wird. An dieser Stelle müssen Sie nur zusammenführen –

1

Ich denke, dein Punkt der Verwirrung ist weiter zurück. Wenn Sie

ausgeführt
git commit -am 'first' 
git checkout -b lineA 

haben Sie einen neuen Zweig lineA aber die Verzweigungsstelle genannt schaffen wurde das Commit Sie habe gerade („first“). Wie Git es ausdrückt, ist first Teil der Geschichte beider Zweige, und an diesem Punkt in Ihrem Skript ist es auch der letzte Commit in beiden Zweigen. Git Protokoll mit einigen Optionen zeigt, dass beiden Zweignamen auf den ersten Punkt begehen, die in diesem Beispiel ist id 58b7dcf begehen:

git log --graph --oneline --decorate 
* 58b7dcf (HEAD, master, lineA) first 

Continuing:

echo -e "A\nb\nc" > file 
git commit -am 'A' 
git log --graph --oneline --decorate 
* ed40ed2 (HEAD, lineA) A 
* 58b7dcf (master) first 

Die Log-Befehl zeigt, dass A (ed40ed2 begehen) ist jetzt das letzte Commit unter lineA, und sein übergeordnetes Commit ist first, das immer noch das letzte Commit unter master ist. Wenn Sie zu diesem Zeitpunkt lineA zurück zu master zusammenführen würden, wäre es eine schnelle (triviale) Zusammenführung, weil keine Commit an master seit lineA davon abgezweigt gemacht wurden. Ebenso würde lineA auf master Rebasing nichts tun, außer

Current branch lineA is up to date. 

berichten, weil die jüngste am Zweig begehen master (die Spitze des Master-Zweig) ist immer noch ein Teil der Geschichte des Zweiges lineA. Fortsetzung:

Jeder neue Zweig wird auf dem letzten Commit des vorherigen erstellt, ohne parallele Entwicklung.Fortsetzung:

git checkout master 
git merge lineA 
Updating 58b7dcf..ed40ed2 
Fast-forward 

Hinweis dies ein Vorspulen merge ist, so dass alle es tat, war master bewegen ed40ed2:

git log --graph --oneline --decorate 
* ed40ed2 (HEAD, master, lineA) A 
* 58b7dcf first 

Endlich:

git checkout lineB 
git rebase master 
Current branch lineB is up to date. 
git log --graph --oneline --decorate 
* f742aed (HEAD, lineB) B 
* ed40ed2 (master, lineA) A 
* 58b7dcf first 

Sie schrieb:

Was? Nein, der Meister hat sich geändert.

Ja, master verändert, aber nicht in einer Weise, die die Geschichte der lineB oder lineC betroffen. master war Fast-Forward zu commit ed40ed2, die bereits die Eltern von lineB war. Um genau zu sein, ist es das Elternteil von f742aed, welches die Commit-ID ist, die ich für das Commit B bekommen habe.

Die Verwirrung für Leute, die zu anderen Versionskontrollsystemen verwendet werden, besteht darin, dass Git eine baumähnliche Datenstruktur (technisch eine DAG) für die Festschreibungsdatensätze aufzeichnet, nicht die Branchennamen. Die Zweige sind vergänglich; Sie sind nur Etiketten, wie bewegliche Versionstags. Die Eltern-Kind-Beziehungen zwischen den Commits sehen Sie in git log --graph und anderen Visualisierungstools.