diff --git a/go/cmd/dolt/commands/filter-branch.go b/go/cmd/dolt/commands/filter-branch.go index 269f799f313..782893b3b60 100644 --- a/go/cmd/dolt/commands/filter-branch.go +++ b/go/cmd/dolt/commands/filter-branch.go @@ -118,6 +118,12 @@ func (cmd FilterBranchCmd) Exec(ctx context.Context, commandStr string, args []s queryString = string(queryStringBytes) } + if hasChanges, err := HasLocalChanges(ctx, dEnv); err != nil { + return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage) + } else if hasChanges { + verr := errhand.BuildDError("local changes detected, use dolt stash or commit changes before using filter-branch").Build() + return HandleVErrAndExitCode(verr, usage) + } replay := func(ctx context.Context, commit, _, _ *doltdb.Commit) (doltdb.RootValue, error) { var cmHash, before hash.Hash var root doltdb.RootValue diff --git a/go/cmd/dolt/commands/utils.go b/go/cmd/dolt/commands/utils.go index 84f667b9ecf..3799bfa7b85 100644 --- a/go/cmd/dolt/commands/utils.go +++ b/go/cmd/dolt/commands/utils.go @@ -789,3 +789,32 @@ func HandleVErrAndExitCode(verr errhand.VerboseError, usage cli.UsagePrinter) in return 0 } + +// HasLocalChanges compares the working and staged hash against the head hash to determine if there are uncommitted changes. +func HasLocalChanges(ctx context.Context, dEnv *env.DoltEnv) (bool, error) { + hRoot, err := dEnv.HeadRoot(ctx) + if err != nil { + return false, err + } + wRoot, err := dEnv.WorkingRoot(ctx) + if err != nil { + return false, err + } + sRoot, err := dEnv.StagedRoot(ctx) + if err != nil { + return false, err + } + hHash, err := hRoot.HashOf() + if err != nil { + return false, err + } + wHash, err := wRoot.HashOf() + if err != nil { + return false, err + } + sHash, err := sRoot.HashOf() + if err != nil { + return false, err + } + return !hHash.Equal(wHash) || !hHash.Equal(sHash), nil +} diff --git a/integration-tests/bats/filter-branch.bats b/integration-tests/bats/filter-branch.bats index 2d3a3562717..e0851fd531e 100644 --- a/integration-tests/bats/filter-branch.bats +++ b/integration-tests/bats/filter-branch.bats @@ -400,5 +400,30 @@ SQL [[ "$output" =~ "does not exist" ]] || false } +@test "filter-branch: fails with working and staged changes" { + dolt sql -q "insert into test values (3, 3)" + run dolt filter-branch -q "alter table test add column filter int" + [ "$status" -eq 1 ] + [[ "$output" =~ "local changes detected, use dolt stash or commit changes before using filter-branch" ]] || false + dolt add . + run dolt filter-branch -q "alter table test add column filter int" + [ "$status" -eq 1 ] + [[ "$output" =~ "local changes detected, use dolt stash or commit changes before using filter-branch" ]] || false + + dolt commit -m "added row" + run dolt filter-branch -q "alter table test add column filter int" + [ "$status" -eq 0 ] + + run dolt sql -q "select * from test as of 'HEAD'" + [ "$status" -eq 0 ] + [[ "$output" =~ "+----+----+--------+" ]] || false + [[ "$output" =~ "| pk | c0 | filter |" ]] || false + [[ "$output" =~ "+----+----+--------+" ]] || false + [[ "$output" =~ "| 0 | 0 | NULL |" ]] || false + [[ "$output" =~ "| 1 | 1 | NULL |" ]] || false + [[ "$output" =~ "| 2 | 2 | NULL |" ]] || false + [[ "$output" =~ "| 3 | 3 | NULL |" ]] || false + [[ "$output" =~ "+----+----+--------+" ]] || false +}