Merge pull request #5165 from dolthub/zachmu/delete-branch

Fixed branch -d behavior on unmerged branches to match git
This commit is contained in:
Zach Musgrave
2023-01-23 18:55:31 -08:00
committed by GitHub
15 changed files with 256 additions and 194 deletions
+11 -14
View File
@@ -72,6 +72,8 @@ const (
showCurrentFlag = "show-current"
)
var ErrUnmergedBranchDelete = errors.New("The branch '%s' is not fully merged.\nIf you are sure you want to delete it, run 'dolt branch -D %s'.")
type BranchCmd struct{}
// Name is returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
@@ -124,9 +126,9 @@ func (cmd BranchCmd) Exec(ctx context.Context, commandStr string, args []string,
case apr.Contains(copyFlag):
return copyBranch(ctx, dEnv, apr, usage)
case apr.Contains(deleteFlag):
return deleteBranches(ctx, dEnv, apr, usage)
return deleteBranches(ctx, dEnv, apr, usage, apr.Contains(forceFlag))
case apr.Contains(deleteForceFlag):
return deleteForceBranches(ctx, dEnv, apr, usage)
return deleteBranches(ctx, dEnv, apr, usage, true)
case apr.Contains(listFlag):
return printBranches(ctx, dEnv, apr, usage)
case apr.Contains(showCurrentFlag):
@@ -261,7 +263,7 @@ func moveBranch(ctx context.Context, dEnv *env.DoltEnv, apr *argparser.ArgParseR
force := apr.Contains(forceFlag)
src := apr.Arg(0)
dest := apr.Arg(1)
err := actions.RenameBranch(ctx, dEnv.DbData(), dEnv.Config, src, apr.Arg(1), force)
err := actions.RenameBranch(ctx, dEnv.DbData(), src, apr.Arg(1), dEnv, force)
var verr errhand.VerboseError
if err != nil {
@@ -310,31 +312,26 @@ func copyBranch(ctx context.Context, dEnv *env.DoltEnv, apr *argparser.ArgParseR
return HandleVErrAndExitCode(verr, usage)
}
func deleteBranches(ctx context.Context, dEnv *env.DoltEnv, apr *argparser.ArgParseResults, usage cli.UsagePrinter) int {
return handleDeleteBranches(ctx, dEnv, apr, usage, apr.Contains(forceFlag))
}
func deleteForceBranches(ctx context.Context, dEnv *env.DoltEnv, apr *argparser.ArgParseResults, usage cli.UsagePrinter) int {
return handleDeleteBranches(ctx, dEnv, apr, usage, true)
}
func handleDeleteBranches(ctx context.Context, dEnv *env.DoltEnv, apr *argparser.ArgParseResults, usage cli.UsagePrinter, force bool) int {
func deleteBranches(ctx context.Context, dEnv *env.DoltEnv, apr *argparser.ArgParseResults, usage cli.UsagePrinter, force bool) int {
if apr.NArg() == 0 {
usage()
return 1
}
for i := 0; i < apr.NArg(); i++ {
brName := apr.Arg(i)
err := actions.DeleteBranch(ctx, dEnv.DbData(), dEnv.Config, brName, actions.DeleteOptions{
err := actions.DeleteBranch(ctx, dEnv.DbData(), brName, actions.DeleteOptions{
Force: force,
Remote: apr.Contains(remoteFlag),
})
}, dEnv)
if err != nil {
var verr errhand.VerboseError
if err == doltdb.ErrBranchNotFound {
verr = errhand.BuildDError("fatal: branch '%s' not found", brName).Build()
} else if err == actions.ErrUnmergedBranch {
verr = errhand.BuildDError(ErrUnmergedBranchDelete.Error(), brName, brName).Build()
} else if err == actions.ErrCOBranchDelete {
verr = errhand.BuildDError("error: Cannot delete checked out branch '%s'", brName).Build()
} else {
+1 -1
View File
@@ -147,7 +147,7 @@ func pullHelper(ctx context.Context, dEnv *env.DoltEnv, pullSpec *env.PullSpec)
return fmt.Errorf("fetch failed; %w", err)
}
// Only merge iff branch is current branch and there is an upstream set (pullSpec.Branch is set to nil if there is no upstream)
// Merge iff branch is current branch and there is an upstream set (pullSpec.Branch is set to nil if there is no upstream)
if branchRef != pullSpec.Branch {
continue
}
+118 -36
View File
@@ -29,10 +29,10 @@ import (
var ErrAlreadyExists = errors.New("already exists")
var ErrCOBranchDelete = errors.New("attempted to delete checked out branch")
var ErrUnmergedBranchDelete = errors.New("attempted to delete a branch that is not fully merged into its parent; use `-f` to force")
var ErrUnmergedBranch = errors.New("branch is not fully merged")
var ErrWorkingSetsOnBothBranches = errors.New("checkout would overwrite uncommitted changes on target branch")
func RenameBranch(ctx context.Context, dbData env.DbData, config *env.DoltCliConfig, oldBranch, newBranch string, force bool) error {
func RenameBranch(ctx context.Context, dbData env.DbData, oldBranch, newBranch string, remoteDbPro env.RemoteDbProvider, force bool) error {
oldRef := ref.NewBranchRef(oldBranch)
newRef := ref.NewBranchRef(newBranch)
@@ -67,7 +67,7 @@ func RenameBranch(ctx context.Context, dbData env.DbData, config *env.DoltCliCon
}
}
return DeleteBranch(ctx, dbData, config, oldBranch, DeleteOptions{Force: true})
return DeleteBranch(ctx, dbData, oldBranch, DeleteOptions{Force: true}, remoteDbPro)
}
func CopyBranch(ctx context.Context, dEnv *env.DoltEnv, oldBranch, newBranch string, force bool) error {
@@ -113,27 +113,27 @@ type DeleteOptions struct {
Remote bool
}
func DeleteBranch(ctx context.Context, dbData env.DbData, config *env.DoltCliConfig, brName string, opts DeleteOptions) error {
var dref ref.DoltRef
func DeleteBranch(ctx context.Context, dbData env.DbData, brName string, opts DeleteOptions, remoteDbPro env.RemoteDbProvider) error {
var branchRef ref.DoltRef
if opts.Remote {
var err error
dref, err = ref.NewRemoteRefFromPathStr(brName)
branchRef, err = ref.NewRemoteRefFromPathStr(brName)
if err != nil {
return err
}
} else {
dref = ref.NewBranchRef(brName)
if ref.Equals(dbData.Rsr.CWBHeadRef(), dref) {
branchRef = ref.NewBranchRef(brName)
if ref.Equals(dbData.Rsr.CWBHeadRef(), branchRef) {
return ErrCOBranchDelete
}
}
return DeleteBranchOnDB(ctx, dbData, config, dref, opts)
return DeleteBranchOnDB(ctx, dbData, branchRef, opts, remoteDbPro)
}
func DeleteBranchOnDB(ctx context.Context, dbData env.DbData, config *env.DoltCliConfig, dref ref.DoltRef, opts DeleteOptions) error {
ddb := dbData.Ddb
hasRef, err := ddb.HasRef(ctx, dref)
func DeleteBranchOnDB(ctx context.Context, dbdata env.DbData, branchRef ref.DoltRef, opts DeleteOptions, pro env.RemoteDbProvider) error {
ddb := dbdata.Ddb
hasRef, err := ddb.HasRef(ctx, branchRef)
if err != nil {
return err
@@ -142,36 +142,27 @@ func DeleteBranchOnDB(ctx context.Context, dbData env.DbData, config *env.DoltCl
}
if !opts.Force && !opts.Remote {
ms, err := doltdb.NewCommitSpec(env.GetDefaultInitBranch(config))
// check to see if the branch is fully merged into its parent
trackedBranches, err := dbdata.Rsr.GetBranches()
if err != nil {
return err
}
init, err := ddb.Resolve(ctx, ms, nil)
if err != nil {
return err
}
cs, err := doltdb.NewCommitSpec(dref.String())
if err != nil {
return err
}
cm, err := ddb.Resolve(ctx, cs, nil)
if err != nil {
return err
}
isMerged, _ := init.CanFastReverseTo(ctx, cm)
if err != nil && !errors.Is(err, doltdb.ErrUpToDate) {
return err
}
if !isMerged {
return ErrUnmergedBranchDelete
trackedBranch, hasUpstream := trackedBranches[branchRef.GetPath()]
if hasUpstream {
err = validateBranchMergedIntoUpstream(ctx, dbdata, branchRef, trackedBranch.Remote, pro)
if err != nil {
return err
}
} else {
err = validateBranchMergedIntoCurrentWorkingBranch(ctx, dbdata, branchRef)
if err != nil {
return err
}
}
}
wsRef, err := ref.WorkingSetRefForHead(dref)
wsRef, err := ref.WorkingSetRefForHead(branchRef)
if err != nil {
if !errors.Is(err, ref.ErrWorkingSetUnsupported) {
return err
@@ -183,7 +174,98 @@ func DeleteBranchOnDB(ctx context.Context, dbData env.DbData, config *env.DoltCl
}
}
return ddb.DeleteBranch(ctx, dref)
return ddb.DeleteBranch(ctx, branchRef)
}
// validateBranchMergedIntoCurrentWorkingBranch returns an error if the given branch is not fully merged into the HEAD of the current branch.
func validateBranchMergedIntoCurrentWorkingBranch(ctx context.Context, dbdata env.DbData, branch ref.DoltRef) error {
branchSpec, err := doltdb.NewCommitSpec(branch.GetPath())
if err != nil {
return err
}
branchHead, err := dbdata.Ddb.Resolve(ctx, branchSpec, nil)
if err != nil {
return err
}
cwbCs, err := doltdb.NewCommitSpec("HEAD")
if err != nil {
return err
}
cwbHead, err := dbdata.Ddb.Resolve(ctx, cwbCs, dbdata.Rsr.CWBHeadRef())
if err != nil {
return err
}
isMerged, err := branchHead.CanFastForwardTo(ctx, cwbHead)
if err != nil {
if errors.Is(err, doltdb.ErrUpToDate) {
return nil
}
if errors.Is(err, doltdb.ErrIsAhead) {
return ErrUnmergedBranch
}
return err
}
if !isMerged {
return ErrUnmergedBranch
}
return nil
}
// validateBranchMergedIntoUpstream returns an error if the branch provided is not fully merged into its upstream
func validateBranchMergedIntoUpstream(ctx context.Context, dbdata env.DbData, branch ref.DoltRef, remoteName string, pro env.RemoteDbProvider) error {
remotes, err := dbdata.Rsr.GetRemotes()
if err != nil {
return err
}
remote, ok := remotes[remoteName]
if !ok {
// TODO: skip error?
return fmt.Errorf("remote %s not found", remoteName)
}
remoteDb, err := pro.GetRemoteDB(ctx, dbdata.Ddb.ValueReadWriter().Format(), remote, false)
if err != nil {
return err
}
cs, err := doltdb.NewCommitSpec(branch.GetPath())
if err != nil {
return err
}
remoteBranchHead, err := remoteDb.Resolve(ctx, cs, nil)
if err != nil {
return err
}
localBranchHead, err := dbdata.Ddb.Resolve(ctx, cs, nil)
if err != nil {
return err
}
canFF, err := localBranchHead.CanFastForwardTo(ctx, remoteBranchHead)
if err != nil {
if errors.Is(err, doltdb.ErrUpToDate) {
return nil
}
if errors.Is(err, doltdb.ErrIsAhead) {
return ErrUnmergedBranch
}
return err
}
if !canFF {
return ErrUnmergedBranch
}
return nil
}
func CreateBranchWithStartPt(ctx context.Context, dbData env.DbData, newBranch, startPt string, force bool) error {
+8
View File
@@ -98,6 +98,14 @@ type DoltEnv struct {
IgnoreLockFile bool
}
func (dEnv *DoltEnv) GetRemoteDB(ctx context.Context, format *types.NomsBinFormat, r Remote, withCaching bool) (*doltdb.DoltDB, error) {
if withCaching {
return r.GetRemoteDB(ctx, format, dEnv)
} else {
return r.GetRemoteDBWithoutCaching(ctx, format, dEnv)
}
}
// Load loads the DoltEnv for the .dolt directory determined by resolving the specified urlStr with the specified Filesys.
func Load(ctx context.Context, hdp HomeDirProvider, fs filesys.Filesys, urlStr string, version string) *DoltEnv {
cfg, cfgErr := LoadDoltCliConfig(hdp, fs)
+6
View File
@@ -22,6 +22,7 @@ import (
"github.com/dolthub/dolt/go/libraries/doltcore/ref"
"github.com/dolthub/dolt/go/libraries/utils/filesys"
"github.com/dolthub/dolt/go/store/hash"
"github.com/dolthub/dolt/go/store/types"
)
type RepoStateReader interface {
@@ -46,6 +47,11 @@ type RepoStateWriter interface {
UpdateBranch(name string, new BranchConfig) error
}
// RemoteDbProvider is an interface for getting a database from a remote
type RemoteDbProvider interface {
GetRemoteDB(ctx context.Context, format *types.NomsBinFormat, r Remote, withCaching bool) (*doltdb.DoltDB, error)
}
type DbData struct {
Ddb *doltdb.DoltDB
Rsw RepoStateWriter
@@ -303,11 +303,11 @@ func (p DoltDatabaseProvider) AllDatabases(ctx *sql.Context) (all []sql.Database
return all
}
func (p DoltDatabaseProvider) GetRemoteDB(ctx *sql.Context, srcDB *doltdb.DoltDB, r env.Remote, withCaching bool) (*doltdb.DoltDB, error) {
func (p DoltDatabaseProvider) GetRemoteDB(ctx context.Context, format *types.NomsBinFormat, r env.Remote, withCaching bool) (*doltdb.DoltDB, error) {
if withCaching {
return r.GetRemoteDB(ctx, srcDB.ValueReadWriter().Format(), p.remoteDialer)
return r.GetRemoteDB(ctx, format, p.remoteDialer)
}
return r.GetRemoteDBWithoutCaching(ctx, srcDB.ValueReadWriter().Format(), p.remoteDialer)
return r.GetRemoteDBWithoutCaching(ctx, format, p.remoteDialer)
}
func (p DoltDatabaseProvider) CreateDatabase(ctx *sql.Context, name string) error {
@@ -146,7 +146,7 @@ func doDoltBackup(ctx *sql.Context, args []string) (int, error) {
return statusErr, fmt.Errorf("unrecognized dolt_backup parameter: %s", apr.Arg(0))
}
destDb, err := sess.Provider().GetRemoteDB(ctx, dbData.Ddb, b, true)
destDb, err := sess.Provider().GetRemoteDB(ctx, dbData.Ddb.ValueReadWriter().Format(), b, true)
if err != nil {
return statusErr, fmt.Errorf("error loading backup destination: %w", err)
}
@@ -111,7 +111,7 @@ func renameBranch(ctx *sql.Context, dbData env.DbData, apr *argparser.ArgParseRe
return err
}
err := actions.RenameBranch(ctx, dbData, loadConfig(ctx), oldBranchName, newBranchName, force)
err := actions.RenameBranch(ctx, dbData, oldBranchName, newBranchName, sess.Provider(), force)
if err != nil {
return err
}
@@ -162,6 +162,7 @@ func deleteBranches(ctx *sql.Context, dbData env.DbData, apr *argparser.ArgParse
}
var updateFS = false
dSess := dsess.DSessFromSess(ctx.Session)
for _, branchName := range apr.Args {
if len(branchName) == 0 {
return EmptyBranchNameErr
@@ -174,9 +175,9 @@ func deleteBranches(ctx *sql.Context, dbData env.DbData, apr *argparser.ArgParse
return err
}
}
err = actions.DeleteBranch(ctx, dbData, loadConfig(ctx), branchName, actions.DeleteOptions{
err = actions.DeleteBranch(ctx, dbData, branchName, actions.DeleteOptions{
Force: force,
})
}, dSess.Provider())
if err != nil {
return err
}
@@ -64,7 +64,7 @@ func doDoltFetch(ctx *sql.Context, args []string) (int, error) {
updateMode := ref.UpdateMode{Force: apr.Contains(cli.ForceFlag)}
srcDB, err := sess.Provider().GetRemoteDB(ctx, dbData.Ddb, remote, false)
srcDB, err := sess.Provider().GetRemoteDB(ctx, dbData.Ddb.ValueReadWriter().Format(), remote, false)
if err != nil {
return 1, err
}
@@ -80,7 +80,7 @@ func doDoltPull(ctx *sql.Context, args []string) (int, int, error) {
return noConflictsOrViolations, threeWayMerge, err
}
srcDB, err := sess.Provider().GetRemoteDB(ctx, dbData.Ddb, pullSpec.Remote, false)
srcDB, err := sess.Provider().GetRemoteDB(ctx, dbData.Ddb.ValueReadWriter().Format(), pullSpec.Remote, false)
if err != nil {
return noConflictsOrViolations, threeWayMerge, fmt.Errorf("failed to get remote db; %w", err)
}
@@ -70,7 +70,7 @@ func doDoltPush(ctx *sql.Context, args []string) (int, error) {
if err != nil {
return cmdFailure, err
}
remoteDB, err := sess.Provider().GetRemoteDB(ctx, dbData.Ddb, opts.Remote, true)
remoteDB, err := sess.Provider().GetRemoteDB(ctx, dbData.Ddb.ValueReadWriter().Format(), opts.Remote, true)
if err != nil {
return 1, actions.HandleInitRemoteStorageClientErr(opts.Remote.Name, opts.Remote.Url, err)
}
@@ -15,12 +15,15 @@
package dsess
import (
"context"
"github.com/dolthub/go-mysql-server/sql"
"gopkg.in/src-d/go-errors.v1"
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
"github.com/dolthub/dolt/go/libraries/doltcore/env"
"github.com/dolthub/dolt/go/libraries/utils/filesys"
"github.com/dolthub/dolt/go/store/types"
)
// ErrRevisionDbNotFound is thrown when a RevisionDatabaseProvider cannot find a specified revision database.
@@ -66,6 +69,7 @@ type RemoteReadReplicaDatabase interface {
type DoltDatabaseProvider interface {
sql.MutableDatabaseProvider
RevisionDatabaseProvider
// env.RemoteDbProvider
// FileSystem returns the filesystem used by this provider, rooted at the data directory for all databases.
FileSystem() filesys.Filesys
@@ -77,7 +81,7 @@ type DoltDatabaseProvider interface {
// withCaching defines whether the remoteDB gets cached or not.
// This function replaces env.Remote's GetRemoteDB method during SQL session to access dialer in order
// to get remote database associated to the env.Remote object.
GetRemoteDB(ctx *sql.Context, srcDB *doltdb.DoltDB, r env.Remote, withCaching bool) (*doltdb.DoltDB, error)
GetRemoteDB(ctx context.Context, format *types.NomsBinFormat, r env.Remote, withCaching bool) (*doltdb.DoltDB, error)
// CloneDatabaseFromRemote clones the database from the specified remoteURL as a new database in this provider.
// dbName is the name for the new database, branch is an optional parameter indicating which branch to clone
// (otherwise all branches are cloned), remoteName is the name for the remote created in the new database, and
@@ -113,7 +117,7 @@ func (e emptyRevisionDatabaseProvider) IsRevisionDatabase(_ *sql.Context, _ stri
return false, nil
}
func (e emptyRevisionDatabaseProvider) GetRemoteDB(ctx *sql.Context, srcDB *doltdb.DoltDB, r env.Remote, withCaching bool) (*doltdb.DoltDB, error) {
func (e emptyRevisionDatabaseProvider) GetRemoteDB(ctx context.Context, format *types.NomsBinFormat, r env.Remote, withCaching bool) (*doltdb.DoltDB, error) {
return nil, nil
}
@@ -1713,7 +1713,7 @@ var DoltBranchScripts = []queries.ScriptTest{
{
// Trying to delete a branch with unpushed changes fails without force option
Query: "CALL DOLT_BRANCH('-d', 'myNewBranchWithCommit')",
ExpectedErrStr: "attempted to delete a branch that is not fully merged into its parent; use `-f` to force",
ExpectedErrStr: "branch is not fully merged",
},
{
Query: "CALL DOLT_BRANCH('-df', 'myNewBranchWithCommit')",
+92
View File
@@ -47,3 +47,95 @@ teardown() {
run dolt sql -q 'show tables'
[[ "$output" =~ "test" ]] || false
}
@test "branch: deleting an unmerged branch with a remote" {
mkdir -p remotes/origin
dolt remote add origin file://./remotes/origin
dolt sql -q "create table t1 (id int primary key);"
dolt commit -Am "initial commit"
dolt branch b1
dolt branch b2
dolt branch b3
dolt push --set-upstream origin b1
dolt push --set-upstream origin b2
dolt push --set-upstream origin b3
# b1 is one commit ahead of the remote
dolt checkout b1
dolt sql -q "create table t2 (id int primary key);"
dolt commit -Am "new table"
# b2 is even with the remote
# b3 is one commit behind the remote
dolt checkout b3
dolt sql -q "create table t2 (id int primary key);"
dolt commit -Am "new table"
dolt push origin b3
dolt reset --hard HEAD~
dolt checkout main
run dolt branch -d b1
[ "$status" -ne 0 ]
[[ "$output" =~ "branch 'b1' is not fully merged" ]] || false
[[ "$output" =~ "run 'dolt branch -D b1'" ]] || false
dolt branch -D b1
dolt branch -d b2
dolt branch -d b3
run dolt branch
[ "$status" -eq 0 ]
[[ ! "$output" =~ "b1" ]] || false
[[ ! "$output" =~ "b2" ]] || false
[[ ! "$output" =~ "b3" ]] || false
}
@test "branch: deleting an unmerged branch with no remote" {
dolt sql -q "create table t1 (id int primary key);"
dolt commit -Am "commit 1"
dolt sql -q "create table t2 (id int primary key);"
dolt commit -Am "commit 2"
dolt branch b1
dolt branch b2
dolt branch b3
# b1 is one commit ahead of main
dolt checkout b1
dolt sql -q "create table t3 (id int primary key);"
dolt commit -Am "new table"
# two additional copies
dolt branch b1-1
dolt branch b1-2
# b2 is even with main
# b3 is one commit behind main
dolt checkout b3
dolt reset --hard HEAD~
dolt checkout main
run dolt branch -d b1
[ "$status" -ne 0 ]
[[ "$output" =~ "branch 'b1' is not fully merged" ]] || false
[[ "$output" =~ "run 'dolt branch -D b1'" ]] || false
dolt branch -D b1
dolt checkout b1-1
# this works because it's even with the checked out branch (but not with main)
dolt branch -d b1-2
dolt checkout main
dolt branch -D b1-1
dolt branch -d b2
dolt branch -d b3
run dolt branch
[ "$status" -eq 0 ]
[[ ! "$output" =~ "b1" ]] || false
[[ ! "$output" =~ "b2" ]] || false
[[ ! "$output" =~ "b3" ]] || false
}
+2 -130
View File
@@ -18,23 +18,6 @@ teardown() {
teardown_common
}
@test "sql-branch: DOLT_BRANCH works" {
run dolt branch
[[ ! "$output" =~ "new_branch" ]] || false
run dolt sql -q "call dolt_branch('new-branch')"
[ $status -eq 0 ]
# should create new branch and should not checkout the new branch
run dolt status
[ $status -eq 0 ]
[[ "$output" =~ "main" ]] || false
run dolt branch
[ $status -eq 0 ]
[[ "$output" =~ "new-branch" ]] || false
}
@test "sql-branch: CALL DOLT_BRANCH works" {
run dolt branch
[[ ! "$output" =~ "new_branch" ]] || false
@@ -69,20 +52,7 @@ teardown() {
[[ "$output" =~ "new-branch" ]] || false
}
@test "sql-branch: DOLT_BRANCH throws error" {
# branches that already exist
dolt branch existing_branch
run dolt sql -q "call dolt_branch('existing_branch')"
[ $status -eq 1 ]
[[ "$output" =~ "fatal: A branch named 'existing_branch' already exists." ]] || false
# empty branch
run dolt sql -q "call dolt_branch('')"
[ $status -eq 1 ]
[[ "$output" =~ "error: cannot branch empty string" ]] || false
}
@test "sql-branch: CALL DOLT_BRANCH throws error" {
@test "sql-branch: CALL DOLT_BRANCH error cases" {
# branches that already exist
dolt branch existing_branch
run dolt sql -q "CALL DOLT_BRANCH('existing_branch')"
@@ -95,37 +65,6 @@ teardown() {
[[ "$output" =~ "error: cannot branch empty string" ]]
}
@test "sql-branch: DOLT_BRANCH -c copies not current branch and stays on current branch" {
dolt add . && dolt commit -m "0, 1, and 2 in test table"
run dolt status
[[ "$output" =~ "main" ]] || false
dolt checkout -b original
dolt sql -q "insert into test values (4);"
dolt add .
dolt commit -m "add 4 in original"
dolt checkout main
# Current branch should be still main with test table without entry 4
run dolt sql << SQL
call dolt_branch('-c', 'original', 'copy');
SELECT * FROM test WHERE pk > 3;
SQL
[ $status -eq 0 ]
[[ ! "$output" =~ "4" ]] || false
run dolt status
[ $status -eq 0 ]
[[ "$output" =~ "main" ]] || false
run dolt checkout copy
[ $status -eq 0 ]
run dolt sql -q "SELECT * FROM test WHERE pk > 3;"
[[ "$output" =~ "4" ]] || false
}
@test "sql-branch: CALL DOLT_BRANCH -c copies not current branch and stays on current branch" {
dolt add . && dolt commit -m "0, 1, and 2 in test table"
run dolt status
@@ -157,37 +96,6 @@ SQL
[[ "$output" =~ "4" ]] || false
}
@test "sql-branch: DOLT_BRANCH -c throws error on error cases" {
run dolt status
[[ "$output" =~ "main" ]] || false
# branch copying from is empty
run dolt sql -q "call dolt_branch('-c','','copy')"
[ $status -eq 1 ]
[[ "$output" =~ "error: cannot branch empty string" ]] || false
# branch copying to is empty
run dolt sql -q "call dolt_branch('-c','main','')"
[ $status -eq 1 ]
[[ "$output" =~ "error: cannot branch empty string" ]] || false
dolt branch 'existing_branch'
run dolt branch
[[ "$output" =~ "main" ]] || false
[[ "$output" =~ "existing_branch" ]] || false
[[ ! "$output" =~ "original" ]] || false
# branch copying from that don't exist
run dolt sql -q "call dolt_branch('-c', 'original', 'copy');"
[ $status -eq 1 ]
[[ "$output" =~ "fatal: A branch named 'original' not found" ]] || false
# branch copying to that exists
run dolt sql -q "call dolt_branch('-c', 'main', 'existing_branch');"
[ $status -eq 1 ]
[[ "$output" =~ "fatal: A branch named 'existing_branch' already exists." ]] || false
}
@test "sql-branch: CALL DOLT_BRANCH -c throws error on error cases" {
run dolt status
[[ "$output" =~ "main" ]] || false
@@ -219,19 +127,6 @@ SQL
[[ "$output" =~ "fatal: A branch named 'existing_branch' already exists." ]]
}
@test "sql-branch: DOLT_BRANCH works as insert into dolt_branches table" {
dolt add . && dolt commit -m "1, 2, and 3 in test table"
run dolt sql -q "SELECT hash FROM dolt_branches WHERE name='main';"
[ $status -eq 0 ]
mainhash=$output
dolt sql -q "call dolt_branch('feature-branch');"
run dolt sql -q "SELECT hash FROM dolt_branches WHERE name='feature-branch';"
[ $status -eq 0 ]
[ "$output" = "$mainhash" ]
}
@test "sql-branch: CALL DOLT_BRANCH works as insert into dolt_branches table" {
dolt add . && dolt commit -m "1, 2, and 3 in test table"
@@ -245,29 +140,6 @@ SQL
[ "$output" = "$mainhash" ]
}
@test "sql-branch: call dolt_branch to rename and delete" {
dolt add . && dolt commit -m "1, 2, and 3 in test table"
dolt branch new_branch
run dolt sql -q "call dolt_branch('-m', 'new_branch', 'changed');"
[ $status -eq 0 ]
run dolt sql -q "call dolt_branch('-d', 'changed');"
[ $status -eq 0 ]
dolt branch branch_with_unpushed_commit
dolt checkout branch_with_unpushed_commit
dolt commit --allow-empty -am 'empty commit'
dolt checkout main
run dolt sql -q "call dolt_branch('-d', 'branch_with_unpushed_commit');"
[ $status -eq 1 ]
[[ "$output" =~ "attempted to delete a branch that is not fully merged" ]] || false
run dolt sql -q "call dolt_branch('-D', 'branch_with_unpushed_commit');"
[ $status -eq 0 ]
}
@test "sql-branch: CALL DOLT_BRANCH to rename and delete" {
dolt add . && dolt commit -m "1, 2, and 3 in test table"
dolt branch new_branch
@@ -285,7 +157,7 @@ SQL
run dolt sql -q "CALL DOLT_BRANCH('-d', 'branch_with_unpushed_commit');"
[ $status -eq 1 ]
[[ "$output" =~ "attempted to delete a branch that is not fully merged" ]] || false
[[ "$output" =~ "not fully merged" ]] || false
run dolt sql -q "CALL DOLT_BRANCH('-D', 'branch_with_unpushed_commit');"
[ $status -eq 0 ]