Be more selective in our remote references when cloning another repo

This commit is contained in:
Neil Macneale IV
2024-01-19 16:24:08 -08:00
parent 6b41096d81
commit e2721cfb94
2 changed files with 59 additions and 25 deletions
+21
View File
@@ -1254,6 +1254,27 @@ func (ddb *DoltDB) deleteRef(ctx context.Context, dref ref.DoltRef, replicationS
return err
}
// DeleteAllRefs Very destructive, use with caution. Not only does this drop all data, Dolt assume there is always
// a reference in the DB, so do not call this and walk away. The only use case for this method is the
// `dolt clone` command which strip everything from the remote's root object - dolt_clone stored procedure doesn't currently
// use this code path (TODO).
func (ddb *DoltDB) DeleteAllRefs(ctx context.Context) error {
dss, err := ddb.db.Datasets(ctx)
if err != nil {
return err
}
err = dss.IterAll(ctx, func(key string, addr hash.Hash) error {
ds, e := ddb.db.GetDataset(ctx, key)
if e != nil {
return e
}
_, e = ddb.db.Delete(ctx, ds, "")
return e
})
return err
}
// NewTagAtCommit create a new tag at the commit given.
func (ddb *DoltDB) NewTagAtCommit(ctx context.Context, tagRef ref.DoltRef, c *Commit, meta *datas.TagMeta) error {
if !IsValidTagRef(tagRef) {
+38 -25
View File
@@ -47,10 +47,10 @@ var ErrNoDataAtRemote = errors.New("remote at that url contains no Dolt data")
var ErrFailedToListBranches = errors.New("failed to list branches")
var ErrFailedToGetBranch = errors.New("could not get branch")
var ErrFailedToGetRootValue = errors.New("could not find root value")
var ErrFailedToResolveBranchRef = errors.New("could not resole branch ref")
var ErrFailedToCreateRemoteRef = errors.New("could not create remote ref")
var ErrFailedToCreateTagRef = errors.New("could not create tag ref")
var ErrFailedToCreateLocalBranch = errors.New("could not create local branch")
var ErrFailedToDeleteBranch = errors.New("could not delete local branch after clone")
var ErrFailedToUpdateDocs = errors.New("failed to update docs on the filesystem")
var ErrUserNotFound = errors.New("could not determine user name. run dolt config --global --add user.name")
var ErrEmailNotFound = errors.New("could not determine email. run dolt config --global --add user.email")
var ErrCloneFailed = errors.New("clone failed")
@@ -179,11 +179,20 @@ func CloneRemote(ctx context.Context, srcDB *doltdb.DoltDB, remoteName, branch s
return fmt.Errorf("%w; %s", ErrCloneFailed, err.Error())
}
branches, err := dEnv.DoltDB.GetBranches(ctx)
// Get all the refs from the remote. These branch remotes will be translated to remote branches, tags will
// be preserved, and all other refs will be ignored.
remoteRefHashes, err := dEnv.DoltDB.GetRefsWithHashes(ctx)
if err != nil {
return fmt.Errorf("%w; %s", ErrFailedToListBranches, err.Error())
return fmt.Errorf("%w; %s", ErrCloneFailed, err.Error())
}
branches := make([]ref.DoltRef, 0, len(remoteRefHashes))
for _, refHash := range remoteRefHashes {
if refHash.Ref.GetType() == ref.BranchRefType {
br := refHash.Ref.(ref.BranchRef)
branches = append(branches, br)
}
}
if branch == "" {
branch = env.GetDefaultBranch(dEnv, branches)
}
@@ -210,31 +219,35 @@ func CloneRemote(ctx context.Context, srcDB *doltdb.DoltDB, remoteName, branch s
return fmt.Errorf("%w: %s; %s", ErrFailedToGetRootValue, branch, err.Error())
}
// After actions.Clone, we have repository with a local branch for
// every branch in the remote. What we want is a remote branch ref for
// every branch in the remote. We iterate through local branches and
// create remote refs corresponding to each of them. We delete all of
// the local branches except for the one corresponding to |branch|.
for _, br := range branches {
if !singleBranch || br.GetPath() == branch {
cs, _ := doltdb.NewCommitSpec(br.GetPath())
cm, err := dEnv.DoltDB.Resolve(ctx, cs, nil)
if err != nil {
return fmt.Errorf("%w: %s; %s", ErrFailedToResolveBranchRef, br.String(), err.Error())
err = dEnv.DoltDB.DeleteAllRefs(ctx)
if err != nil {
return err
}
// Preserve only branch and tag references from the remote. Branches are translated into remote branches, tags are preserved.
for _, refHash := range remoteRefHashes {
if refHash.Ref.GetType() == ref.BranchRefType {
br := refHash.Ref.(ref.BranchRef)
if !singleBranch || br.GetPath() == branch {
remoteRef := ref.NewRemoteRef(remoteName, br.GetPath())
err = dEnv.DoltDB.SetHead(ctx, remoteRef, refHash.Hash)
if err != nil {
return fmt.Errorf("%w: %s; %s", ErrFailedToCreateRemoteRef, remoteRef.String(), err.Error())
}
}
remoteRef := ref.NewRemoteRef(remoteName, br.GetPath())
err = dEnv.DoltDB.SetHeadToCommit(ctx, remoteRef, cm)
if err != nil {
return fmt.Errorf("%w: %s; %s", ErrFailedToCreateRemoteRef, remoteRef.String(), err.Error())
if br.GetPath() == branch {
// This is the only local branch after the clone is complete.
err = dEnv.DoltDB.SetHead(ctx, br, refHash.Hash)
if err != nil {
return fmt.Errorf("%w: %s; %s", ErrFailedToCreateLocalBranch, br.String(), err.Error())
}
}
}
if br.GetPath() != branch {
err := dEnv.DoltDB.DeleteBranch(ctx, br, nil)
} else if refHash.Ref.GetType() == ref.TagRefType {
tr := refHash.Ref.(ref.TagRef)
err = dEnv.DoltDB.SetHead(ctx, tr, refHash.Hash)
if err != nil {
return fmt.Errorf("%w: %s; %s", ErrFailedToDeleteBranch, br.String(), err.Error())
return fmt.Errorf("%w: %s; %s", ErrFailedToCreateTagRef, tr.String(), err.Error())
}
}
}