libgit2: fix checkout logic for CheckoutBranch
Use the target commit, to checkout tree and set the head to the desired branch instead of doing a hard reset to the target commit. Signed-off-by: Sanskar Jaiswal <jaiswalsanskar078@gmail.com>
This commit is contained in:
parent
c68c62ca12
commit
ae27f9ec69
|
@ -161,25 +161,50 @@ func (c *CheckoutBranch) Checkout(ctx context.Context, path, url string, opts *g
|
||||||
}
|
}
|
||||||
defer upstreamCommit.Free()
|
defer upstreamCommit.Free()
|
||||||
|
|
||||||
// Once the index has been updated with Fetch, and we know the tip commit,
|
// We try to lookup the branch (and create it if it doesn't exist), so that we can
|
||||||
// a hard reset can be used to align the local worktree with the remote branch's.
|
// switch the repo to the specified branch. This is done so that users of this api
|
||||||
err = repo.ResetToCommit(upstreamCommit, git2go.ResetHard, &git2go.CheckoutOptions{
|
// can expect the repo to be at the desired branch, when cloned.
|
||||||
|
localBranch, err := repo.LookupBranch(c.Branch, git2go.BranchLocal)
|
||||||
|
if git2go.IsErrorCode(err, git2go.ErrorCodeNotFound) {
|
||||||
|
localBranch, err = repo.CreateBranch(c.Branch, upstreamCommit, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to create local branch '%s': %w", c.Branch, err)
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to lookup branch '%s': %w", c.Branch, err)
|
||||||
|
}
|
||||||
|
defer localBranch.Free()
|
||||||
|
|
||||||
|
tree, err := repo.LookupTree(upstreamCommit.TreeId())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to lookup tree for branch '%s': %w", c.Branch, err)
|
||||||
|
}
|
||||||
|
defer tree.Free()
|
||||||
|
|
||||||
|
err = repo.CheckoutTree(tree, &git2go.CheckoutOpts{
|
||||||
|
// the remote branch should take precedence if it exists at this point in time.
|
||||||
Strategy: git2go.CheckoutForce,
|
Strategy: git2go.CheckoutForce,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to hard reset to commit for '%s': %w", managed.EffectiveURL(url), gitutil.LibGit2Error(err))
|
return nil, fmt.Errorf("unable to checkout tree for branch '%s': %w", c.Branch, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the current head to point to the requested branch.
|
||||||
|
err = repo.SetHead("refs/heads/" + c.Branch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to set HEAD to branch '%s':%w", c.Branch, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the current worktree's head as reference for the commit to be returned.
|
// Use the current worktree's head as reference for the commit to be returned.
|
||||||
head, err := repo.Head()
|
head, err := repo.Head()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("git resolve HEAD error: %w", err)
|
return nil, fmt.Errorf("unable to resolve HEAD: %w", err)
|
||||||
}
|
}
|
||||||
defer head.Free()
|
defer head.Free()
|
||||||
|
|
||||||
cc, err := repo.LookupCommit(head.Target())
|
cc, err := repo.LookupCommit(head.Target())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to lookup HEAD commit '%s' for branch '%s': %w", head.Target(), c.Branch, err)
|
return nil, fmt.Errorf("unable to lookup HEAD commit '%s' for branch '%s': %w", head.Target(), c.Branch, err)
|
||||||
}
|
}
|
||||||
defer cc.Free()
|
defer cc.Free()
|
||||||
|
|
||||||
|
|
|
@ -517,6 +517,7 @@ func TestManagedCheckoutBranch_Checkout(t *testing.T) {
|
||||||
|
|
||||||
repo, err := git2go.OpenRepository(filepath.Join(server.Root(), repoPath))
|
repo, err := git2go.OpenRepository(filepath.Join(server.Root(), repoPath))
|
||||||
g.Expect(err).ToNot(HaveOccurred())
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer repo.Free()
|
||||||
|
|
||||||
branchRef, err := repo.References.Lookup(fmt.Sprintf("refs/heads/%s", git.DefaultBranch))
|
branchRef, err := repo.References.Lookup(fmt.Sprintf("refs/heads/%s", git.DefaultBranch))
|
||||||
g.Expect(err).ToNot(HaveOccurred())
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
@ -524,6 +525,7 @@ func TestManagedCheckoutBranch_Checkout(t *testing.T) {
|
||||||
|
|
||||||
commit, err := repo.LookupCommit(branchRef.Target())
|
commit, err := repo.LookupCommit(branchRef.Target())
|
||||||
g.Expect(err).ToNot(HaveOccurred())
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer commit.Free()
|
||||||
|
|
||||||
authOpts := &git.AuthOptions{
|
authOpts := &git.AuthOptions{
|
||||||
TransportOptionsURL: getTransportOptionsURL(git.HTTP),
|
TransportOptionsURL: getTransportOptionsURL(git.HTTP),
|
||||||
|
@ -552,6 +554,33 @@ func TestManagedCheckoutBranch_Checkout(t *testing.T) {
|
||||||
g.Expect(err).ToNot(HaveOccurred())
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
g.Expect(cc.String()).To(Equal(git.DefaultBranch + "/" + commit.Id().String()))
|
g.Expect(cc.String()).To(Equal(git.DefaultBranch + "/" + commit.Id().String()))
|
||||||
g.Expect(git.IsConcreteCommit(*cc)).To(Equal(true))
|
g.Expect(git.IsConcreteCommit(*cc)).To(Equal(true))
|
||||||
|
|
||||||
|
// Create a new branch and push it.
|
||||||
|
err = createBranch(repo, "test", nil)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
transportOptsURL := getTransportOptionsURL(git.HTTP)
|
||||||
|
managed.AddTransportOptions(transportOptsURL, managed.TransportOptions{
|
||||||
|
TargetURL: repoURL,
|
||||||
|
})
|
||||||
|
defer managed.RemoveTransportOptions(transportOptsURL)
|
||||||
|
origin, err := repo.Remotes.Create("origin", transportOptsURL)
|
||||||
|
defer origin.Free()
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = origin.Push([]string{"refs/heads/test:refs/heads/test"}, &git2go.PushOptions{})
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
branch.Branch = "test"
|
||||||
|
tmpDir2 := t.TempDir()
|
||||||
|
cc, err = branch.Checkout(ctx, tmpDir2, repoURL, authOpts)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
// Check if the repo HEAD points to the branch.
|
||||||
|
repo, err = git2go.OpenRepository(tmpDir2)
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
head, err := repo.Head()
|
||||||
|
defer head.Free()
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
g.Expect(head.Branch().Name()).To(Equal("test"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestManagedCheckoutTag_Checkout(t *testing.T) {
|
func TestManagedCheckoutTag_Checkout(t *testing.T) {
|
||||||
|
@ -573,6 +602,7 @@ func TestManagedCheckoutTag_Checkout(t *testing.T) {
|
||||||
|
|
||||||
repo, err := git2go.OpenRepository(filepath.Join(server.Root(), repoPath))
|
repo, err := git2go.OpenRepository(filepath.Join(server.Root(), repoPath))
|
||||||
g.Expect(err).ToNot(HaveOccurred())
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer repo.Free()
|
||||||
|
|
||||||
branchRef, err := repo.References.Lookup(fmt.Sprintf("refs/heads/%s", git.DefaultBranch))
|
branchRef, err := repo.References.Lookup(fmt.Sprintf("refs/heads/%s", git.DefaultBranch))
|
||||||
g.Expect(err).ToNot(HaveOccurred())
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
@ -580,6 +610,7 @@ func TestManagedCheckoutTag_Checkout(t *testing.T) {
|
||||||
|
|
||||||
commit, err := repo.LookupCommit(branchRef.Target())
|
commit, err := repo.LookupCommit(branchRef.Target())
|
||||||
g.Expect(err).ToNot(HaveOccurred())
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
defer commit.Free()
|
||||||
_, err = tag(repo, commit.Id(), false, "tag-1", time.Now())
|
_, err = tag(repo, commit.Id(), false, "tag-1", time.Now())
|
||||||
|
|
||||||
checkoutTag := CheckoutTag{
|
checkoutTag := CheckoutTag{
|
||||||
|
|
Loading…
Reference in New Issue