Korzystając z powyższej odpowiedzi z
sschuberth
, udało mi się stworzyć działającą wersję tej funkcji i pomyślałem, że podzielę się tym przełomem. Jak wskazano, funkcja
repo.Merge()
w libgit2 (jak w tym przypadku Git2go) nie robi tak wiele, jak robi to
git pull
. Pozwól mi wyjaśnić to jeden krok na raz (stoję poprawione):
Jak wyjaśniono here, git pull
faktycznie robi git fetch
a następnie git merge
i to, co zrobimy:
Zlokalizuj pilota do pobrania zmiany od
remote, err := repo.Remotes.Lookup("origin")
if err != nil {
return err
}
Fetch zmian z zdalnego
if err := remote.Fetch([]string{}, nil, ""); err != nil {
return err
}
Uzyskaj odpowiedni zdalnego adresowania
remoteBranch, err := repo.References.Lookup("refs/remotes/origin/branch_name")
if err != nil {
return err
}
Masz teraz zmiany z pilota, ale trzeba pozwolić Git powiedzieć, jak radzić sobie z nimi dalej. Tak więc, wykonaj analizę scalania.
Przeprowadzić analizę Merge
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
}
Teraz trzeba sprawdzić wartość analysis
aby zobaczyć, które status value to wskazuje i zrobić scalania odpowiednio.
test zwrócona wartość
Pamiętaj, aby zrobić test na poziomie binarnym, więc używać bitowe operatorów. Na przykład:
if analysis & git.MergeAnalysisUpToDate != 0 {
return nil
}
Nie ma tu nic do roboty (w moim przypadku). Wszystko jest aktualne.
else if analysis & git.MergeAnalysisNormal != 0 {
// Just merge changes
if err := repo.Merge([]*git.AnnotatedCommit{annotatedCommit}, nil, nil); err != nil {
return err
}
// Check for conflicts
index, err := repo.Index()
if err != nil {
return err
}
if index.HasConflicts() {
return errors.New("Conflicts encountered. Please resolve them.")
}
// Make the merge commit
sig, err := repo.DefaultSignature()
if err != nil {
return err
}
// Get Write Tree
treeId, err := index.WriteTree()
if err != nil {
return err
}
tree, err := repo.LookupTree(treeId)
if err != nil {
return err
}
localCommit, err := repo.LookupCommit(head.Target())
if err != nil {
return err
}
remoteCommit, err := repo.LookupCommit(remoteBranchID)
if err != nil {
return err
}
repo.CreateCommit("HEAD", sig, sig, "", tree, localCommit, remoteCommit)
// Clean up
repo.StateCleanup()
}
W skrócie, powyższy blok kodu wykonuje scalanie i testuje konflikty po. Jeśli napotkasz jakiekolwiek konflikty, radzę sobie z nimi (prawdopodobnie zachęcam użytkownika). Spowoduje to niezatwierdzone zmiany, więc pamiętaj o utworzeniu zatwierdzenia po.
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
}
}
W powyższym kodzie nie ma nic do scalenia. Trzeba tylko powtórzyć zmiany ze zdalnego na lokalny i zaktualizować tam, gdzie wskazuje HEAD.
Powyższe było dla mnie wystarczające. Mam nadzieję, że to podejście również ci pomoże. Znajdź pełną funkcję na this gist
Czy mógłbyś nieco wyjaśnić, dlaczego muszę utworzyć zatwierdzenie? Są to nadchodzące zmiany z "pochodzenia". Czy powinny być wystawiane? Nie powinien tylko odtwarzać tych zmian i zostawić mi czysty katalog roboczy (biorąc pod uwagę, że nie wprowadziliśmy żadnych zmian, które wprowadziliśmy lokalnie). Ta funkcja wprowadza zmiany, które nie zostały wprowadzone lokalnie, i nie zapisuje zatwierdzeń wycofanych ze zdalnego. – Sthe
libgit2 (i jego powiązania) działają na niższym poziomie niż linia poleceń git (porcelana). W szczególności, 'Merge' git2go robi o wiele mniej niż' git merge'. Podczas gdy 'git merge' domyślnie jest w stanie uprościć szybkie przewijanie do przodu (które w rzeczywistości wcale nie są scalone, patrz' --ff'), 'Merge' git2go jawnie tworzy scalenie, nawet jeśli fast-forward był możliwy. Merge z kolei zawsze tworzy zatwierdzenie scalenia, a aby coś zatwierdzić, indeks musi zostać wypełniony. Znowu "Scalenie" git2go jest znacznie bardziej niskopoziomowe i wymaga jawnego zatwierdzenia, nawet jeśli nie ma konfliktów. – sschuberth