From be31b2852e2b8c62acd1ecce99a16fc5843bdd17 Mon Sep 17 00:00:00 2001 From: Stephanie You Date: Fri, 1 Dec 2023 15:28:56 -0800 Subject: [PATCH 1/4] adds --single-branch for dolt clone --- go/cmd/dolt/cli/arg_parser_helpers.go | 1 + go/cmd/dolt/cli/flags.go | 1 + go/cmd/dolt/commands/clone.go | 3 +- go/libraries/doltcore/env/actions/clone.go | 30 +++++++++---------- .../doltcore/sqle/database_provider.go | 2 +- integration-tests/bats/remotes.bats | 15 ++++++++++ 6 files changed, 35 insertions(+), 17 deletions(-) diff --git a/go/cmd/dolt/cli/arg_parser_helpers.go b/go/cmd/dolt/cli/arg_parser_helpers.go index 9848beb391d..eb8cd1ae069 100644 --- a/go/cmd/dolt/cli/arg_parser_helpers.go +++ b/go/cmd/dolt/cli/arg_parser_helpers.go @@ -125,6 +125,7 @@ func CreateCloneArgParser() *argparser.ArgParser { ap.SupportsString(dbfactory.OSSCredsFileParam, "", "file", "OSS credentials file.") ap.SupportsString(dbfactory.OSSCredsProfile, "", "profile", "OSS profile to use.") ap.SupportsString(UserFlag, "u", "user", "User name to use when authenticating with the remote. Gets password from the environment variable {{.EmphasisLeft}}DOLT_REMOTE_PASSWORD{{.EmphasisRight}}.") + ap.SupportsFlag(SingleBranchFlag, "", "Clone only the history leading to the tip of a single branch, either specified by --branch or the primary branch remote's HEAD points at.") return ap } diff --git a/go/cmd/dolt/cli/flags.go b/go/cmd/dolt/cli/flags.go index 0a411ddc033..1fdaa1b013e 100644 --- a/go/cmd/dolt/cli/flags.go +++ b/go/cmd/dolt/cli/flags.go @@ -59,6 +59,7 @@ const ( ShallowFlag = "shallow" ShowIgnoredFlag = "ignored" SilentFlag = "silent" + SingleBranchFlag = "single-branch" SkipEmptyFlag = "skip-empty" SoftResetParam = "soft" SquashParam = "squash" diff --git a/go/cmd/dolt/commands/clone.go b/go/cmd/dolt/commands/clone.go index 5768563401a..2940f2fa486 100644 --- a/go/cmd/dolt/commands/clone.go +++ b/go/cmd/dolt/commands/clone.go @@ -98,6 +98,7 @@ func (cmd CloneCmd) Exec(ctx context.Context, commandStr string, args []string, func clone(ctx context.Context, apr *argparser.ArgParseResults, dEnv *env.DoltEnv) errhand.VerboseError { remoteName := apr.GetValueOrDefault(cli.RemoteParam, "origin") branch := apr.GetValueOrDefault(cli.BranchParam, "") + singleBranch := apr.Contains(cli.SingleBranchFlag) dir, urlStr, verr := parseArgs(apr) if verr != nil { return verr @@ -143,7 +144,7 @@ func clone(ctx context.Context, apr *argparser.ArgParseResults, dEnv *env.DoltEn // Nil out the old Dolt env so we don't accidentally operate on the wrong database dEnv = nil - err = actions.CloneRemote(ctx, srcDB, remoteName, branch, clonedEnv) + err = actions.CloneRemote(ctx, srcDB, remoteName, branch, singleBranch, clonedEnv) if err != nil { // If we're cloning into a directory that already exists do not erase it. Otherwise // make best effort to delete the directory we created. diff --git a/go/libraries/doltcore/env/actions/clone.go b/go/libraries/doltcore/env/actions/clone.go index f24abd51426..82d5de273ad 100644 --- a/go/libraries/doltcore/env/actions/clone.go +++ b/go/libraries/doltcore/env/actions/clone.go @@ -156,7 +156,7 @@ func sortedKeys(m map[string]iohelp.ReadStats) []string { return keys } -func CloneRemote(ctx context.Context, srcDB *doltdb.DoltDB, remoteName, branch string, dEnv *env.DoltEnv) error { +func CloneRemote(ctx context.Context, srcDB *doltdb.DoltDB, remoteName, branch string, singleBranch bool, dEnv *env.DoltEnv) error { eventCh := make(chan pull.TableFileEvent, 128) wg := &sync.WaitGroup{} @@ -215,25 +215,25 @@ func CloneRemote(ctx context.Context, srcDB *doltdb.DoltDB, remoteName, branch s // create remote refs corresponding to each of them. We delete all of // the local branches except for the one corresponding to |branch|. for _, brnch := range branches { - cs, _ := doltdb.NewCommitSpec(brnch.GetPath()) - cm, err := dEnv.DoltDB.Resolve(ctx, cs, nil) - if err != nil { - return fmt.Errorf("%w: %s; %s", ErrFailedToResolveBranchRef, brnch.String(), err.Error()) - - } - - remoteRef := ref.NewRemoteRef(remoteName, brnch.GetPath()) - err = dEnv.DoltDB.SetHeadToCommit(ctx, remoteRef, cm) - if err != nil { - return fmt.Errorf("%w: %s; %s", ErrFailedToCreateRemoteRef, remoteRef.String(), err.Error()) - - } - if brnch.GetPath() != branch { err := dEnv.DoltDB.DeleteBranch(ctx, brnch, nil) if err != nil { return fmt.Errorf("%w: %s; %s", ErrFailedToDeleteBranch, brnch.String(), err.Error()) } + } else if !singleBranch || brnch.GetPath() == branch { + cs, _ := doltdb.NewCommitSpec(brnch.GetPath()) + cm, err := dEnv.DoltDB.Resolve(ctx, cs, nil) + if err != nil { + return fmt.Errorf("%w: %s; %s", ErrFailedToResolveBranchRef, brnch.String(), err.Error()) + + } + + remoteRef := ref.NewRemoteRef(remoteName, brnch.GetPath()) + err = dEnv.DoltDB.SetHeadToCommit(ctx, remoteRef, cm) + if err != nil { + return fmt.Errorf("%w: %s; %s", ErrFailedToCreateRemoteRef, remoteRef.String(), err.Error()) + + } } } diff --git a/go/libraries/doltcore/sqle/database_provider.go b/go/libraries/doltcore/sqle/database_provider.go index 41135786009..5ff4c1af57b 100644 --- a/go/libraries/doltcore/sqle/database_provider.go +++ b/go/libraries/doltcore/sqle/database_provider.go @@ -527,7 +527,7 @@ func (p *DoltDatabaseProvider) cloneDatabaseFromRemote( return nil, err } - err = actions.CloneRemote(ctx, srcDB, remoteName, branch, dEnv) + err = actions.CloneRemote(ctx, srcDB, remoteName, branch, false, dEnv) if err != nil { return nil, err } diff --git a/integration-tests/bats/remotes.bats b/integration-tests/bats/remotes.bats index 76698efc6d1..0dd65d7d5ea 100644 --- a/integration-tests/bats/remotes.bats +++ b/integration-tests/bats/remotes.bats @@ -1008,6 +1008,21 @@ create_five_remote_branches_main_and_master() { [[ "$output" =~ "remotes/origin/branch-two" ]] || false } +@test "remotes: clone --single-branch does not create remote refs for all remote branches" { + create_three_remote_branches + cd dolt-repo-clones + dolt clone --single-branch http://localhost:50051/test-org/test-repo + cd test-repo + run dolt branch -a + [ "$status" -eq 0 ] + [[ "$output" =~ "* main" ]] || false + [[ ! "$output" =~ " branch-one" ]] || false + [[ ! "$output" =~ " branch-two" ]] || false + [[ "$output" =~ "remotes/origin/main" ]] || false + [[ ! "$output" =~ "remotes/origin/branch-one" ]] || false + [[ ! "$output" =~ "remotes/origin/branch-two" ]] || false +} + @test "remotes: fetch creates new remote refs for new remote branches" { create_main_remote_branch From 90b62c8bd75a5c1cc05e2d9d0c4a44caf0912345 Mon Sep 17 00:00:00 2001 From: Stephanie You Date: Fri, 1 Dec 2023 15:51:44 -0800 Subject: [PATCH 2/4] small fix --- go/libraries/doltcore/dtestutils/testcommands/multienv.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/libraries/doltcore/dtestutils/testcommands/multienv.go b/go/libraries/doltcore/dtestutils/testcommands/multienv.go index ecb6ba4db10..f5ac33a2190 100644 --- a/go/libraries/doltcore/dtestutils/testcommands/multienv.go +++ b/go/libraries/doltcore/dtestutils/testcommands/multienv.go @@ -195,7 +195,7 @@ func (mr *MultiRepoTestSetup) CloneDB(fromRemote, dbName string) { mr.Errhand(err) } - err = actions.CloneRemote(ctx, srcDB, r.Name, "", dEnv) + err = actions.CloneRemote(ctx, srcDB, r.Name, "", false, dEnv) if err != nil { mr.Errhand(err) } From 4ec6d2b9fe8352ecdabdc3697177a04f1fde4df0 Mon Sep 17 00:00:00 2001 From: Stephanie You Date: Mon, 4 Dec 2023 10:00:58 -0800 Subject: [PATCH 3/4] PR comments --- go/cmd/dolt/cli/arg_parser_helpers.go | 2 +- go/libraries/doltcore/env/actions/clone.go | 21 +++++++-------- integration-tests/bats/remotes.bats | 30 ++++++++++++++++++++++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/go/cmd/dolt/cli/arg_parser_helpers.go b/go/cmd/dolt/cli/arg_parser_helpers.go index eb8cd1ae069..0a04e0f20bc 100644 --- a/go/cmd/dolt/cli/arg_parser_helpers.go +++ b/go/cmd/dolt/cli/arg_parser_helpers.go @@ -125,7 +125,7 @@ func CreateCloneArgParser() *argparser.ArgParser { ap.SupportsString(dbfactory.OSSCredsFileParam, "", "file", "OSS credentials file.") ap.SupportsString(dbfactory.OSSCredsProfile, "", "profile", "OSS profile to use.") ap.SupportsString(UserFlag, "u", "user", "User name to use when authenticating with the remote. Gets password from the environment variable {{.EmphasisLeft}}DOLT_REMOTE_PASSWORD{{.EmphasisRight}}.") - ap.SupportsFlag(SingleBranchFlag, "", "Clone only the history leading to the tip of a single branch, either specified by --branch or the primary branch remote's HEAD points at.") + ap.SupportsFlag(SingleBranchFlag, "", "Clone only the history leading to the tip of a single branch, either specified by --branch or the remote's HEAD (default).") return ap } diff --git a/go/libraries/doltcore/env/actions/clone.go b/go/libraries/doltcore/env/actions/clone.go index 82d5de273ad..e0cac4b9029 100644 --- a/go/libraries/doltcore/env/actions/clone.go +++ b/go/libraries/doltcore/env/actions/clone.go @@ -214,27 +214,28 @@ func CloneRemote(ctx context.Context, srcDB *doltdb.DoltDB, remoteName, branch s // 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 _, brnch := range branches { - if brnch.GetPath() != branch { - err := dEnv.DoltDB.DeleteBranch(ctx, brnch, nil) - if err != nil { - return fmt.Errorf("%w: %s; %s", ErrFailedToDeleteBranch, brnch.String(), err.Error()) - } - } else if !singleBranch || brnch.GetPath() == branch { - cs, _ := doltdb.NewCommitSpec(brnch.GetPath()) + for _, br := range branches { + if !singleBranch || (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, brnch.String(), err.Error()) + return fmt.Errorf("%w: %s; %s", ErrFailedToResolveBranchRef, br.String(), err.Error()) } - remoteRef := ref.NewRemoteRef(remoteName, brnch.GetPath()) + 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 { + err := dEnv.DoltDB.DeleteBranch(ctx, br, nil) + if err != nil { + return fmt.Errorf("%w: %s; %s", ErrFailedToDeleteBranch, br.String(), err.Error()) + } + } } // TODO: make this interface take a DoltRef and marshal it automatically diff --git a/integration-tests/bats/remotes.bats b/integration-tests/bats/remotes.bats index 0dd65d7d5ea..26dbfffb9b1 100644 --- a/integration-tests/bats/remotes.bats +++ b/integration-tests/bats/remotes.bats @@ -1023,6 +1023,36 @@ create_five_remote_branches_main_and_master() { [[ ! "$output" =~ "remotes/origin/branch-two" ]] || false } +@test "remotes: clone --branch specifies which branch to clone" { + create_three_remote_branches + cd dolt-repo-clones + dolt clone --branch branch-one http://localhost:50051/test-org/test-repo + cd test-repo + run dolt branch -a + [ "$status" -eq 0 ] + [[ "$output" =~ "* branch-one" ]] || false + [[ ! "$output" =~ " main" ]] || false + [[ ! "$output" =~ " branch-two" ]] || false + [[ "$output" =~ "remotes/origin/main" ]] || false + [[ "$output" =~ "remotes/origin/branch-one" ]] || false + [[ "$output" =~ "remotes/origin/branch-two" ]] || false +} + +@test "remotes: clone --single-branch --branch does not create all remote refs" { + create_three_remote_branches + cd dolt-repo-clones + dolt clone --branch branch-one --single-branch http://localhost:50051/test-org/test-repo + cd test-repo + run dolt branch -a + [ "$status" -eq 0 ] + [[ "$output" =~ "* branch-one" ]] || false + [[ ! "$output" =~ " main" ]] || false + [[ ! "$output" =~ " branch-two" ]] || false + [[ ! "$output" =~ "remotes/origin/main" ]] || false + [[ "$output" =~ "remotes/origin/branch-one" ]] || false + [[ ! "$output" =~ "remotes/origin/branch-two" ]] || false +} + @test "remotes: fetch creates new remote refs for new remote branches" { create_main_remote_branch From 6b54e53586a059d6cea6fca315ae1613d365c61a Mon Sep 17 00:00:00 2001 From: Stephanie You Date: Tue, 5 Dec 2023 09:53:02 -0800 Subject: [PATCH 4/4] simplify single-branch logic --- go/libraries/doltcore/env/actions/clone.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/libraries/doltcore/env/actions/clone.go b/go/libraries/doltcore/env/actions/clone.go index e0cac4b9029..b1c3c6e1838 100644 --- a/go/libraries/doltcore/env/actions/clone.go +++ b/go/libraries/doltcore/env/actions/clone.go @@ -215,7 +215,7 @@ func CloneRemote(ctx context.Context, srcDB *doltdb.DoltDB, remoteName, branch s // 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 || (singleBranch && br.GetPath() == branch) { + if !singleBranch || br.GetPath() == branch { cs, _ := doltdb.NewCommitSpec(br.GetPath()) cm, err := dEnv.DoltDB.Resolve(ctx, cs, nil) if err != nil {