2015-10-14 12 views
7

Ich versuche, etwas zu implementieren, das mir das Ergebnis git pull oder git fetch && git merge geben wird. Ich habe das funktioniert teilweise, aber das Problem, das ich habe, ist, dass nach dem Ausführen des folgenden Codes, der aktuelle Repo ist zu denken, dass es lokale Änderungen zu verpflichten sind.Git2go - pull && Merge

Soweit ich sehen kann, glaube ich, dass ich das kommentierte Commit wahrscheinlich nicht vom richtigen HEAD erstelle oder ich noch ein Commit machen muss? (Ich bin nicht sicher).

Mein Code sieht wie folgt aus, und ich bin fest:

func (repo *Repo) Pull() error { 
    // Get remote 
    remote, err := repo.Remotes.Lookup("origin") 
    if err != nil { 
     remote, err = repo.Remotes.Create("origin", repo.Path()) 
     if err != nil { 
      return err 
     } 
    } 

    // Get the branch 
    branch, err := repo.Branch() 
    if err != nil { 
     return err 
    } 

    // Get the name 
    branchName, err := branch.Name() 
    if err != nil { 
     return err 
    } 

    if err := remote.Fetch([]string{}, &git.FetchOptions{}, ""); err != nil { 
     return err 
    } 

    // Merge 
    remoteRef, err := repo.References.Lookup("refs/remotes/origin/" + branchName) 
    if err != nil { 
     return err 
    } 

    mergeRemoteHead, err := repo.AnnotatedCommitFromRef(remoteRef) 
    if err != nil { 
     return err 
    } 

    mergeHeads := make([]*git.AnnotatedCommit, 1) 
    mergeHeads[0] = mergeRemoteHead 
    if err = repo.Merge(mergeHeads, nil, nil); err != nil { 
     return err 
    } 

    return nil 
} 

Nachdem es läuft, ich die Änderungen bekommen von entfernten verschmolzen und das Arbeitsverzeichnis aktualisiert, aber es sagt mir, ich brauche, um ein Commit zu machen.

Ich denke, ich habe ein ähnliches Problem wie das OP von this question.

Antwort

7

Das ist die git_merge Funktion Weg libgit2 ist dokumentiert:

Änderungen in Szene gesetzt werden für begehen und Konflikte werden in den Index geschrieben. Anrufer sollten den Index des Repositorys nach Abschluss überprüfen, Konflikte lösen und ein Commit vorbereiten.

So müssen Sie Code hinzufügen, um zu überprüfen, ob die index has conflicts. Wenn es keine gibt, können Sie commit was inszeniert ist. Andernfalls würden Sie wahrscheinlich den Benutzer auffordern, die Konflikte zu lösen.

+0

Können Sie ein wenig darüber, warum ich ein Commit erstellen müssen? Dies sind eingehende Änderungen von "Herkunft". Sollten sie inszeniert werden? Sollte es nicht nur diese Änderungen wiederholen und mir ein sauberes Arbeitsverzeichnis hinterlassen (vorausgesetzt, dass wir keine Änderungen vor Ort vorgenommen haben). Diese Funktion setzt Änderungen, die nicht lokal vorgenommen wurden, und zeichnet keine von Remote heruntergezogenen Commits auf. – Sthe

+0

libgit2 (und seine Bindungen) arbeiten auf einer niedrigeren Ebene als die git (Porzellan) -Befehlszeile. Insbesondere macht git2go 'Merge' viel weniger als' git merge'. Während 'git merge' standardmäßig dazu in der Lage ist, Merges zu beschleunigen (was in Wirklichkeit gar keine Merges sind, siehe' --ff'), erzeugt git2go's 'Merge' explizit eine Zusammenführung, selbst wenn es ein Schnellvorlauf war möglich. Eine Zusammenführung erstellt wiederum immer eine Zusammenführungs-Festschreibung, und um etwas festzulegen, muss der Index ausgefüllt werden. Auch hier ist git2gos 'Merge' weitaus low-level und erfordert, dass Sie explizit committen, auch wenn keine Konflikte bestehen. – sschuberth

3

Mit der Eingabe von sschuberth 's Antwort oben, war ich in der Lage, eine funktionierende Version dieser Funktion zusammenzustellen, und ich dachte, ich würde den Durchbruch teilen. Wie bereits erwähnt, funktioniert die Funktion repo.Merge() in libgit2 (in diesem Fall Git2go) nicht annähernd so viel wie git pull. Lassen Sie mich noch einen Schritt zu einer Zeit, erklären (ich stehe korrigiert):

Wie here erklärt, tut git pull eigentlich ein git fetch und dann ein git merge und das ist, was wir tun:

die Fern Suchen abrufen Änderungen von

remote, err := repo.Remotes.Lookup("origin") 
if err != nil { 
    return err 
} 

Änderungen von entfernten Fetch

if err := remote.Fetch([]string{}, nil, ""); err != nil { 
    return err 
} 

Holen Sie sich das entsprechende Remote-Referenz

remoteBranch, err := repo.References.Lookup("refs/remotes/origin/branch_name") 
if err != nil { 
    return err 
} 

Sie haben nun die Änderungen aus der Fernbedienung, aber Sie müssen, damit Sie Git sagen, wie mit ihnen weiter beschäftigen. Also, führe eine Merge-Analyse durch.

Führen Sie eine Zusammenführung Analyse

annotatedCommit, err := repo.AnnotatedCommitFromRef(remoteBranch) 
if err != nil { 
    return err 
} 

// Do the merge analysis 
mergeHeads := make([]*git.AnnotatedCommit, 1) 
mergeHeads[0] = annotatedCommit 
analysis, _, err := repo.MergeAnalysis(mergeHeads) 
if err != nil { 
    return err 
} 

Sie jetzt brauchen, zu sehen den Wert von analysis zu überprüfen, welche status value verweist er auf und die Zusammenführung tun entsprechend.

Testen der Rückgabewert

Achten Sie darauf, den Test auf der binären Ebene zu tun, damit die Bit-Operatoren verwenden. Zum Beispiel:

if analysis & git.MergeAnalysisUpToDate != 0 { 
    return nil 
} 

Hier gibt es nichts zu tun (in meinem Fall). Alles ist auf dem neuesten Stand.

Kurz gesagt, führt der Codeblock oben nur eine Zusammenführung durch und testet auf Konflikte nach. Wenn Konflikte auftreten, gehen Sie mit ihnen um (fragen Sie den Benutzer vielleicht). Dies führt zu nicht festgeschriebenen Änderungen. Stellen Sie daher sicher, dass Sie ein Commit danach erstellen.

else if analysis & git.MergeAnalysisFastForward != 0 { 
    // Fast-forward changes 
    // Get remote tree 
    remoteTree, err := repo.LookupTree(remoteBranchID) 
    if err != nil { 
     return err 
    } 

    // Checkout 
    if err := repo.CheckoutTree(remoteTree, nil); err != nil { 
     return err 
    } 

    branchRef, err := repo.References.Lookup("refs/heads/branch_name") 
    if err != nil { 
     return err 
    } 

    // Point branch to the object 
    branchRef.SetTarget(remoteBranchID, "") 
    if _, err := head.SetTarget(remoteBranchID, ""); err != nil { 
     return err 
    } 

} 

Im obigen Code ist nichts zusammenzuführen. Sie müssen nur die Änderungen von remote auf Ihren lokalen und den aktualisierten HEAD-Code wiederholen.

Das obige war für mich ausreichend. Ich hoffe der Ansatz hilft dir auch. Finden Sie die komplette Funktion auf this gist