From 0a6ce282ff98d41a0000bb71d433e8f2268ed625 Mon Sep 17 00:00:00 2001 From: Elian Date: Mon, 23 Jun 2025 13:54:44 -0700 Subject: [PATCH] add test for multiple matching branch names --- .../sqle/dprocedures/dolt_checkout.go | 25 ++++++++---- integration-tests/bats/checkout.bats | 39 +++++++++++++++++++ 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/go/libraries/doltcore/sqle/dprocedures/dolt_checkout.go b/go/libraries/doltcore/sqle/dprocedures/dolt_checkout.go index 6048978862..9f47bcdb44 100644 --- a/go/libraries/doltcore/sqle/dprocedures/dolt_checkout.go +++ b/go/libraries/doltcore/sqle/dprocedures/dolt_checkout.go @@ -29,6 +29,7 @@ import ( "github.com/dolthub/dolt/go/store/hash" "github.com/dolthub/go-mysql-server/sql" "github.com/dolthub/go-mysql-server/sql/types" + "github.com/fatih/color" ) var ErrEmptyBranchName = errors.New("error: cannot checkout empty string") @@ -144,7 +145,7 @@ func doDoltCheckout(ctx *sql.Context, args []string) (statusCode int, successMes // No ref explicitly specified but table(s) are dashDashPos := apr.PositionalArgsSeparatorIndex if dashDashPos == 0 { - err = checkoutTablesFromHead(ctx, roots, currentDbName, apr.Args, rsc) + err = checkoutTablesFromHead(ctx, roots, currentDbName, apr.Args, &rsc) if err != nil { return 1, "", err } @@ -182,7 +183,7 @@ func doDoltCheckout(ctx *sql.Context, args []string) (statusCode int, successMes } // git requires a local ref to already exist to check out tables - err = checkoutTablesFromCommit(ctx, currentDbName, firstArg, apr.Args[1:], rsc) + err = checkoutTablesFromCommit(ctx, currentDbName, firstArg, apr.Args[1:], &rsc) if err != nil { return 1, "", err } @@ -201,7 +202,7 @@ func doDoltCheckout(ctx *sql.Context, args []string) (statusCode int, successMes } if apr.NArg() > 1 && !isTable { - err = checkoutTablesFromCommit(ctx, currentDbName, firstArg, apr.Args[1:], rsc) + err = checkoutTablesFromCommit(ctx, currentDbName, firstArg, apr.Args[1:], &rsc) if err != nil { return 1, "", err } @@ -225,7 +226,7 @@ func doDoltCheckout(ctx *sql.Context, args []string) (statusCode int, successMes return 0, generateSuccessMessage(firstArg, upstream), nil } - err = checkoutTablesFromHead(ctx, roots, currentDbName, apr.Args, rsc) + err = checkoutTablesFromHead(ctx, roots, currentDbName, apr.Args, &rsc) if err != nil { return 1, "", err } @@ -370,7 +371,12 @@ func checkoutRemoteBranch(ctx *sql.Context, dSess *dsess.DoltSession, dbName str return remoteRef.GetPath(), nil } else { - return "", fmt.Errorf("'%s' matched multiple (%v) remote tracking branches", branchName, len(remoteRefs)) + hint := `hint: If you meant to check out a remote tracking branch, on, e.g., 'origin', +hint: you can do so by fully qualifying the name with the --track option: +hint: +hint: dolt checkout --track origin/ +` + return "", fmt.Errorf(color.YellowString(hint)+"'%s' matched multiple (%v) remote tracking branches", branchName, len(remoteRefs)) } } @@ -490,6 +496,9 @@ func checkoutExistingBranch(ctx *sql.Context, dbName string, branchName string, return nil } +// checkoutExistingBranchWithWorkingSetFallback checks out an existing branch, and if the working set does not exist, +// it creates a new working set for the branch pointing to the existing branch HEAD. This resolves the issue where +// a local branch ref was created without a working set, such as when running as a read replica with an old version of dolt. func checkoutExistingBranchWithWorkingSetFallback(ctx *sql.Context, dbName string, branchName string, apr *argparser.ArgParseResults, rsc *doltdb.ReplicationStatusController) error { dbData, ok := dsess.DSessFromSess(ctx.Session).GetDbData(ctx, dbName) if !ok { @@ -541,7 +550,7 @@ func checkoutTablesFromCommit( databaseName string, commitRef string, tables []string, - rsc doltdb.ReplicationStatusController, + rsc *doltdb.ReplicationStatusController, ) error { dSess := dsess.DSessFromSess(ctx.Session) dbData, ok := dSess.GetDbData(ctx, databaseName) @@ -608,7 +617,7 @@ func checkoutTablesFromCommit( return err } - dsess.WaitForReplicationController(ctx, rsc) + dsess.WaitForReplicationController(ctx, *rsc) return dSess.SetWorkingSet(ctx, databaseName, ws.WithStagedRoot(newRoot).WithWorkingRoot(newRoot)) } @@ -625,7 +634,7 @@ func doGlobalCheckout(ctx *sql.Context, branchName string, isForce bool, isNewBr // checkoutTablesFromHead checks out the tables named from the current head and overwrites those tables in the // working root. The working root is then set as the new staged root. -func checkoutTablesFromHead(ctx *sql.Context, roots doltdb.Roots, name string, tables []string, rsc doltdb.ReplicationStatusController) error { +func checkoutTablesFromHead(ctx *sql.Context, roots doltdb.Roots, name string, tables []string, rsc *doltdb.ReplicationStatusController) error { return checkoutTablesFromCommit(ctx, name, "HEAD", tables, rsc) } diff --git a/integration-tests/bats/checkout.bats b/integration-tests/bats/checkout.bats index 63898d9b38..7a48d6b91e 100755 --- a/integration-tests/bats/checkout.bats +++ b/integration-tests/bats/checkout.bats @@ -1115,3 +1115,42 @@ SQL [[ "$output" =~ "* main" ]] || false } +@test "checkout: more than one remote share same branch name" { + # setup two remotes with the same branch name + mkdir -p remote1 + mkdir -p remote2 + mkdir -p local-repo + cd local-repo + dolt init + dolt remote add origin file://../remote1 + dolt remote add origin2 file://../remote2 + + # create a branch on both remotes + dolt checkout -b feature + dolt sql -q "create table test (id int primary key, value int);" + dolt sql -q "insert into test values (1, 100);" + dolt add . + dolt commit -m "Add feature table" + dolt push origin feature + dolt push origin2 feature + + # verify both remotes have the feature branch + run dolt branch -a + [ "$status" -eq 0 ] + [[ "$output" =~ "remotes/origin/feature" ]] || false + [[ "$output" =~ "remotes/origin2/feature" ]] || false + + dolt checkout main + dolt branch -D feature # delete local feature branch to cause ambiguity + + # try to checkout feature without disambiguation, should fail + run dolt checkout feature + [ "$status" -ne 0 ] + [[ "$output" =~ "'feature' matched multiple (2) remote tracking braches" ]] || false + + # verify we're still on main branch + run dolt branch + [ "$status" -eq 0 ] + [[ "$output" =~ "* main" ]] || false +} +