mirror of
https://github.com/dolthub/dolt.git
synced 2026-02-09 18:59:12 -06:00
@@ -58,7 +58,7 @@ var fkWarningMessage = "Warning: This merge is being applied to tables that have
|
||||
|
||||
type MergeCmd struct{}
|
||||
|
||||
// Name is returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
|
||||
// Name returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
|
||||
func (cmd MergeCmd) Name() string {
|
||||
return "merge"
|
||||
}
|
||||
|
||||
96
go/cmd/dolt/commands/merge_base.go
Normal file
96
go/cmd/dolt/commands/merge_base.go
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright 2021 Dolthub, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package commands
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/dolthub/dolt/go/cmd/dolt/cli"
|
||||
"github.com/dolthub/dolt/go/cmd/dolt/errhand"
|
||||
eventsapi "github.com/dolthub/dolt/go/gen/proto/dolt/services/eventsapi/v1alpha1"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/env"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/merge"
|
||||
"github.com/dolthub/dolt/go/libraries/utils/argparser"
|
||||
"github.com/dolthub/dolt/go/libraries/utils/filesys"
|
||||
)
|
||||
|
||||
var mergeBaseDocs = cli.CommandDocumentationContent{
|
||||
ShortDesc: `Find the common ancestor of two commits.`,
|
||||
LongDesc: `Find the common ancestor of two commits, and return the ancestor's commit hash.'`,
|
||||
Synopsis: []string{
|
||||
`{{.LessThan}}commit spec{{.GreaterThan}} {{.LessThan}}commit spec{{.GreaterThan}}`,
|
||||
},
|
||||
}
|
||||
|
||||
type MergeBaseCmd struct{}
|
||||
|
||||
// Name returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
|
||||
func (cmd MergeBaseCmd) Name() string {
|
||||
return "merge-base"
|
||||
}
|
||||
|
||||
// Description returns a description of the command
|
||||
func (cmd MergeBaseCmd) Description() string {
|
||||
return mergeBaseDocs.ShortDesc
|
||||
}
|
||||
|
||||
// CreateMarkdown creates a markdown file containing the helptext for the command at the given path
|
||||
func (cmd MergeBaseCmd) CreateMarkdown(fs filesys.Filesys, path, commandStr string) error {
|
||||
ap := cmd.createArgParser()
|
||||
return CreateMarkdown(fs, path, cli.GetCommandDocumentation(commandStr, mergeBaseDocs, ap))
|
||||
}
|
||||
|
||||
func (cmd MergeBaseCmd) createArgParser() *argparser.ArgParser {
|
||||
ap := argparser.NewArgParser()
|
||||
//ap.ArgListHelp = append(ap.ArgListHelp, [2]string{"start-point", "A commit that a new branch should point at."})
|
||||
return ap
|
||||
}
|
||||
|
||||
// EventType returns the type of the event to log
|
||||
func (cmd MergeBaseCmd) EventType() eventsapi.ClientEventType {
|
||||
return eventsapi.ClientEventType_TYPE_UNSPECIFIED
|
||||
}
|
||||
|
||||
// Exec executes the command
|
||||
func (cmd MergeBaseCmd) Exec(ctx context.Context, commandStr string, args []string, dEnv *env.DoltEnv) int {
|
||||
ap := cmd.createArgParser()
|
||||
help, usage := cli.HelpAndUsagePrinters(cli.GetCommandDocumentation(commandStr, mergeBaseDocs, ap))
|
||||
apr := cli.ParseArgsOrDie(ap, args, help)
|
||||
|
||||
var verr errhand.VerboseError
|
||||
if apr.NArg() != 2 {
|
||||
verr = errhand.BuildDError("%s takes exactly 2 args", cmd.Name()).Build()
|
||||
return HandleVErrAndExitCode(verr, usage)
|
||||
}
|
||||
|
||||
left, verr := ResolveCommitWithVErr(dEnv, apr.Arg(0))
|
||||
if verr != nil {
|
||||
return HandleVErrAndExitCode(verr, usage)
|
||||
}
|
||||
|
||||
right, verr := ResolveCommitWithVErr(dEnv, apr.Arg(1))
|
||||
if verr != nil {
|
||||
return HandleVErrAndExitCode(verr, usage)
|
||||
}
|
||||
|
||||
mergeBase, err := merge.MergeBase(ctx, left, right)
|
||||
if err != nil {
|
||||
verr = errhand.BuildDError("could not find merge-base for args %s", apr.Args()).AddCause(err).Build()
|
||||
return HandleVErrAndExitCode(verr, usage)
|
||||
}
|
||||
|
||||
cli.Println(mergeBase.String())
|
||||
return 0
|
||||
}
|
||||
@@ -84,7 +84,7 @@ func ResolveCommitWithVErr(dEnv *env.DoltEnv, cSpecStr string) (*doltdb.Commit,
|
||||
if err == doltdb.ErrInvalidAncestorSpec {
|
||||
return nil, errhand.BuildDError("'%s' could not resolve ancestor spec", cSpecStr).Build()
|
||||
} else if err == doltdb.ErrBranchNotFound {
|
||||
return nil, errhand.BuildDError("unknown branch in commit spec: '%s'", cSpecStr).Build()
|
||||
return nil, errhand.BuildDError("unknown ref in commit spec: '%s'", cSpecStr).Build()
|
||||
} else if doltdb.IsNotFoundErr(err) {
|
||||
return nil, errhand.BuildDError("'%s' not found", cSpecStr).Build()
|
||||
} else if err == doltdb.ErrFoundHashNotACommit {
|
||||
|
||||
@@ -90,6 +90,7 @@ var doltCommand = cli.NewSubCommandHandler("dolt", "it's git for data", []cli.Co
|
||||
commands.GarbageCollectionCmd{},
|
||||
commands.FilterBranchCmd{},
|
||||
commands.VerifyConstraintsCmd{},
|
||||
commands.MergeBaseCmd{},
|
||||
})
|
||||
|
||||
func init() {
|
||||
|
||||
32
go/libraries/doltcore/merge/merge_base.go
Normal file
32
go/libraries/doltcore/merge/merge_base.go
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2021 Dolthub, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package merge
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
|
||||
|
||||
"github.com/dolthub/dolt/go/store/hash"
|
||||
)
|
||||
|
||||
func MergeBase(ctx context.Context, left, right *doltdb.Commit) (base hash.Hash, err error) {
|
||||
ancestor, err := doltdb.GetCommitAncestor(ctx, left, right)
|
||||
if err != nil {
|
||||
return base, err
|
||||
}
|
||||
|
||||
return ancestor.HashOf()
|
||||
}
|
||||
124
go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go
Normal file
124
go/libraries/doltcore/sqle/dfunctions/dolt_merge_base.go
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright 2021 Dolthub, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package dfunctions
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/dolthub/go-mysql-server/sql"
|
||||
"github.com/dolthub/go-mysql-server/sql/expression"
|
||||
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/merge"
|
||||
"github.com/dolthub/dolt/go/libraries/doltcore/sqle"
|
||||
)
|
||||
|
||||
const DoltMergeBaseFuncName = "dolt_merge_base"
|
||||
|
||||
type MergeBase struct {
|
||||
expression.BinaryExpression
|
||||
}
|
||||
|
||||
// NewMergeBase returns a MergeBase sql function.
|
||||
func NewMergeBase(left, right sql.Expression) sql.Expression {
|
||||
return &MergeBase{expression.BinaryExpression{Left: left, Right: right}}
|
||||
}
|
||||
|
||||
// Eval implements the sql.Expression interface.
|
||||
func (d MergeBase) Eval(ctx *sql.Context, row sql.Row) (interface{}, error) {
|
||||
if _, ok := d.Left.Type().(sql.StringType); !ok {
|
||||
return nil, sql.ErrInvalidType.New(d.Left.Type())
|
||||
}
|
||||
if _, ok := d.Right.Type().(sql.StringType); !ok {
|
||||
return nil, sql.ErrInvalidType.New(d.Right.Type())
|
||||
}
|
||||
|
||||
leftSpec, err := d.Left.Eval(ctx, row)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rightSpec, err := d.Right.Eval(ctx, row)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if leftSpec == nil || rightSpec == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
left, right, err := resolveRefSpecs(ctx, leftSpec.(string), rightSpec.(string))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
mergeBase, err := merge.MergeBase(ctx, left, right)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mergeBase.String(), nil
|
||||
}
|
||||
|
||||
func resolveRefSpecs(ctx *sql.Context, leftSpec, rightSpec string) (left, right *doltdb.Commit, err error) {
|
||||
lcs, err := doltdb.NewCommitSpec(leftSpec)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
rcs, err := doltdb.NewCommitSpec(rightSpec)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
sess := sqle.DSessFromSess(ctx.Session)
|
||||
dbName := ctx.GetCurrentDatabase()
|
||||
|
||||
dbData, ok := sess.GetDbData(dbName)
|
||||
if !ok {
|
||||
return nil, nil, sql.ErrDatabaseNotFound.New(dbName)
|
||||
}
|
||||
doltDB, ok := sess.GetDoltDB(dbName)
|
||||
if !ok {
|
||||
return nil, nil, sql.ErrDatabaseNotFound.New(dbName)
|
||||
}
|
||||
|
||||
left, err = doltDB.Resolve(ctx, lcs, dbData.Rsr.CWBHeadRef())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
right, err = doltDB.Resolve(ctx, rcs, dbData.Rsr.CWBHeadRef())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// String implements the sql.Expression interface.
|
||||
func (d MergeBase) String() string {
|
||||
return fmt.Sprintf("DOLT_MERGE_BASE(%s,%s)", d.Left.String(), d.Right.String())
|
||||
}
|
||||
|
||||
// Type implements the sql.Expression interface.
|
||||
func (d MergeBase) Type() sql.Type {
|
||||
return sql.Text
|
||||
}
|
||||
|
||||
// WithChildren implements the sql.Expression interface.
|
||||
func (d MergeBase) WithChildren(children ...sql.Expression) (sql.Expression, error) {
|
||||
if len(children) != 2 {
|
||||
return nil, sql.ErrInvalidChildrenNumber.New(d, len(children), 2)
|
||||
}
|
||||
return NewMergeBase(children[0], children[1]), nil
|
||||
}
|
||||
@@ -29,6 +29,7 @@ var DoltFunctions = []sql.Function{
|
||||
sql.FunctionN{Name: DoltCheckoutFuncName, Fn: NewDoltCheckoutFunc},
|
||||
sql.FunctionN{Name: DoltMergeFuncName, Fn: NewDoltMergeFunc},
|
||||
sql.Function0{Name: ActiveBranchFuncName, Fn: NewActiveBranchFunc},
|
||||
sql.Function2{Name: DoltMergeBaseFuncName, Fn: NewMergeBase},
|
||||
}
|
||||
|
||||
// These are the DoltFunctions that get exposed to Dolthub Api.
|
||||
|
||||
@@ -12,7 +12,7 @@ teardown() {
|
||||
@test "conflict-detection: merge non-existant branch errors" {
|
||||
run dolt merge batmans-parents
|
||||
[ $status -eq 1 ]
|
||||
[[ "$output" =~ "unknown branch" ]] || false
|
||||
[[ "$output" =~ "unknown ref" ]] || false
|
||||
[[ ! "$output" =~ "panic" ]] || false
|
||||
}
|
||||
|
||||
|
||||
91
integration-tests/bats/merge-base.bats
Normal file
91
integration-tests/bats/merge-base.bats
Normal file
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env bats
|
||||
load $BATS_TEST_DIRNAME/helper/common.bash
|
||||
|
||||
setup() {
|
||||
setup_common
|
||||
|
||||
dolt sql -q "CREATE TABLE test (pk int primary key);"
|
||||
dolt add -A && dolt commit -m "commit A"
|
||||
dolt branch zero
|
||||
|
||||
dolt sql -q "INSERT INTO test VALUES (0);"
|
||||
dolt commit -am "commit B"
|
||||
dolt branch one
|
||||
dolt branch two
|
||||
|
||||
dolt sql -q "INSERT INTO test VALUES (1);"
|
||||
dolt commit -am "commit C"
|
||||
|
||||
dolt checkout two
|
||||
dolt sql -q "INSERT INTO test VALUES (2);"
|
||||
dolt commit -am "commit D"
|
||||
dolt checkout master
|
||||
|
||||
# # # # # # # # # # # # # # # # # # # # # # #
|
||||
# #
|
||||
# <-- (zero) #
|
||||
# / #
|
||||
# / <-- (one) #
|
||||
# / / #
|
||||
# (init) -- (A) -- (B) -- (C) <-- (master) #
|
||||
# \ #
|
||||
# -- (D) <-- (two) #
|
||||
# #
|
||||
# # # # # # # # # # # # # # # # # # # # # # #
|
||||
}
|
||||
|
||||
teardown() {
|
||||
teardown_common
|
||||
}
|
||||
|
||||
@test "merge-base: cli" {
|
||||
run dolt merge-base master two
|
||||
[ "$status" -eq 0 ]
|
||||
MERGE_BASE="$output"
|
||||
|
||||
run dolt merge-base master one
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "$MERGE_BASE" ]
|
||||
|
||||
run dolt merge-base one two
|
||||
[ "$status" -eq 0 ]
|
||||
[ "$output" = "$MERGE_BASE" ]
|
||||
|
||||
dolt checkout master
|
||||
run dolt log
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "$MERGE_BASE" ]] || false
|
||||
|
||||
dolt checkout two
|
||||
run dolt log
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" =~ "$MERGE_BASE" ]] || false
|
||||
|
||||
dolt checkout zero
|
||||
run dolt log
|
||||
[ "$status" -eq 0 ]
|
||||
[[ ! "$output" =~ "$MERGE_BASE" ]] || false
|
||||
}
|
||||
|
||||
@test "merge-base: sql" {
|
||||
run dolt sql -q "SELECT message FROM dolt_log WHERE commit_hash = dolt_merge_base('master', 'zero');" -r csv
|
||||
[ "$status" -eq 0 ]
|
||||
[ "${lines[1]}" = "commit A" ]
|
||||
|
||||
run dolt sql -q "SELECT message FROM dolt_log WHERE commit_hash = dolt_merge_base('master', 'one');" -r csv
|
||||
[ "$status" -eq 0 ]
|
||||
[ "${lines[1]}" = "commit B" ]
|
||||
|
||||
run dolt sql -q "SELECT message FROM dolt_log WHERE commit_hash = dolt_merge_base('master', 'two');" -r csv
|
||||
[ "$status" -eq 0 ]
|
||||
[ "${lines[1]}" = "commit B" ]
|
||||
|
||||
run dolt sql -q "SELECT message FROM dolt_log WHERE commit_hash = dolt_merge_base('master', 'master');" -r csv
|
||||
[ "$status" -eq 0 ]
|
||||
[ "${lines[1]}" = "commit C" ]
|
||||
|
||||
# dolt_merge_base() resolves commit hashes
|
||||
run dolt sql -q "SELECT dolt_merge_base('master', hashof('one')) = dolt_merge_base(hashof('master'),'one') FROM dual;" -r csv
|
||||
[ "$status" -eq 0 ]
|
||||
[ "${lines[1]}" = "true" ]
|
||||
}
|
||||
@@ -53,6 +53,7 @@ teardown() {
|
||||
[[ "$output" =~ "migrate - Executes a repository migration to update to the latest format." ]] || false
|
||||
[[ "$output" =~ "gc - Cleans up unreferenced data from the repository." ]] || false
|
||||
[[ "$output" =~ "filter-branch - Edits the commit history using the provided query." ]] || false
|
||||
[[ "$output" =~ "merge-base - Find the common ancestor of two commits." ]] || false
|
||||
}
|
||||
|
||||
@test "no-repo: check all commands for valid help text" {
|
||||
|
||||
Reference in New Issue
Block a user