dolt merge --no-ff (#965)

This commit is contained in:
Brian Hendriks
2020-11-05 14:04:48 -08:00
committed by GitHub
parent 8482e62ca7
commit 348af61251
3 changed files with 111 additions and 8 deletions

View File

@@ -187,6 +187,49 @@ teardown() {
[[ ! "$output" =~ "test1" ]] || false
}
@test "no-ff merge" {
dolt checkout -b merge_branch
dolt SQL -q "INSERT INTO test1 values (0,1,2)"
dolt add test1
dolt commit -m "modify test1"
dolt checkout master
run dolt merge merge_branch --no-ff -m "no-ff merge"
[ "$status" -eq 0 ]
[[ ! "$output" =~ "Fast-forward" ]] || false
run dolt log
[ "$status" -eq 0 ]
[[ "$output" =~ "no-ff merge" ]] || false
}
@test "no-ff merge doesn't stomp working changes and doesn't fast forward" {
dolt checkout -b merge_branch
dolt SQL -q "INSERT INTO test1 values (0,1,2)"
dolt add test1
dolt commit -m "modify test1"
dolt checkout master
dolt SQL -q "INSERT INTO test2 values (0,1,2)"
run dolt status
[ "$status" -eq 0 ]
[[ "$output" =~ "test2" ]] || false
[[ ! "$output" =~ "test1" ]] || false
run dolt merge merge_branch --no-ff -m "no-ff merge"
[ "$status" -eq 0 ]
[[ ! "$output" =~ "Fast-forward" ]] || false
run dolt status
[ "$status" -eq 0 ]
[[ "$output" =~ "test2" ]] || false
[[ ! "$output" =~ "test1" ]] || false
run dolt log
[ "$status" -eq 0 ]
[[ "$output" =~ "no-ff merge" ]] || false
}
@test "3way merge rejected when working changes touch same tables" {
dolt checkout -b merge_branch
dolt SQL -q "INSERT INTO test1 values (0,1,2)"

View File

@@ -37,6 +37,7 @@ import (
const (
abortParam = "abort"
squashParam = "squash"
noFFParam = "no-ff"
)
var mergeDocs = cli.CommandDocumentationContent{
@@ -50,6 +51,7 @@ The second syntax ({{.LessThan}}dolt merge --abort{{.GreaterThan}}) can only be
Synopsis: []string{
"[--squash] {{.LessThan}}branch{{.GreaterThan}}",
"--no-ff [-m message] {{.LessThan}}branch{{.GreaterThan}}",
"--abort",
},
}
@@ -81,6 +83,8 @@ func (cmd MergeCmd) createArgParser() *argparser.ArgParser {
ap := argparser.NewArgParser()
ap.SupportsFlag(abortParam, "", abortDetails)
ap.SupportsFlag(squashParam, "", "Merges changes to the working set without updating the commit history")
ap.SupportsFlag(noFFParam, "", "Create a merge commit even when the merge resolves as a fast-forward.")
ap.SupportsString(commitMessageArg, "m", "msg", "Use the given {{.LessThan}}msg{{.GreaterThan}} as the commit message.")
return ap
}
@@ -95,6 +99,11 @@ func (cmd MergeCmd) Exec(ctx context.Context, commandStr string, args []string,
help, usage := cli.HelpAndUsagePrinters(cli.GetCommandDocumentation(commandStr, mergeDocs, ap))
apr := cli.ParseArgs(ap, args, help)
if apr.ContainsAll(squashParam, noFFParam) {
cli.PrintErrf("error: Flags '--%s' and '--%s' cannot be used together.\n", squashParam, noFFParam)
return 1
}
var verr errhand.VerboseError
if apr.Contains(abortParam) {
if !dEnv.IsMergeActive() {
@@ -131,8 +140,7 @@ func (cmd MergeCmd) Exec(ctx context.Context, commandStr string, args []string,
}
if verr == nil {
squash := apr.Contains(squashParam)
verr = mergeCommitSpec(ctx, squash, dEnv, commitSpecStr)
verr = mergeCommitSpec(ctx, apr, dEnv, commitSpecStr)
}
}
}
@@ -154,7 +162,7 @@ func abortMerge(ctx context.Context, doltEnv *env.DoltEnv) errhand.VerboseError
return errhand.BuildDError("fatal: failed to revert changes").AddCause(err).Build()
}
func mergeCommitSpec(ctx context.Context, squash bool, dEnv *env.DoltEnv, commitSpecStr string) errhand.VerboseError {
func mergeCommitSpec(ctx context.Context, apr *argparser.ArgParseResults, dEnv *env.DoltEnv, commitSpecStr string) errhand.VerboseError {
cm1, verr := ResolveCommitWithVErr(dEnv, "HEAD")
if verr != nil {
@@ -186,6 +194,7 @@ func mergeCommitSpec(ctx context.Context, squash bool, dEnv *env.DoltEnv, commit
cli.Println("Updating", h1.String()+".."+h2.String())
squash := apr.Contains(squashParam)
if squash {
cli.Println("Squash commit -- not updating HEAD")
}
@@ -206,7 +215,11 @@ func mergeCommitSpec(ctx context.Context, squash bool, dEnv *env.DoltEnv, commit
}
if ok, err := cm1.CanFastForwardTo(ctx, cm2); ok {
return executeFFMerge(ctx, squash, dEnv, cm2, workingDiffs)
if apr.Contains(noFFParam) {
return execNoFFMerge(ctx, apr, dEnv, cm2, verr, workingDiffs)
} else {
return executeFFMerge(ctx, squash, dEnv, cm2, workingDiffs)
}
} else if err == doltdb.ErrUpToDate || err == doltdb.ErrIsAhead {
cli.Println("Already up to date.")
return nil
@@ -215,6 +228,48 @@ func mergeCommitSpec(ctx context.Context, squash bool, dEnv *env.DoltEnv, commit
}
}
func execNoFFMerge(ctx context.Context, apr *argparser.ArgParseResults, dEnv *env.DoltEnv, cm2 *doltdb.Commit, verr errhand.VerboseError, workingDiffs map[string]hash.Hash) errhand.VerboseError {
mergedRoot, err := cm2.GetRootValue()
if err != nil {
return errhand.BuildDError("error: reading from database").AddCause(err).Build()
}
verr = mergedRootToWorking(ctx, false, dEnv, mergedRoot, workingDiffs, cm2, map[string]*merge.MergeStats{})
if verr != nil {
return verr
}
msg, msgOk := apr.GetValue(commitMessageArg)
if !msgOk {
msg = getCommitMessageFromEditor(ctx, dEnv)
}
t := doltdb.CommitNowFunc()
if commitTimeStr, ok := apr.GetValue(dateParam); ok {
var err error
t, err = parseDate(commitTimeStr)
if err != nil {
return errhand.BuildDError("error: invalid date").AddCause(err).Build()
}
}
err = actions.CommitStaged(ctx, dEnv, actions.CommitStagedProps{
Message: msg,
Date: t,
AllowEmpty: apr.Contains(allowEmptyFlag),
CheckForeignKeys: !apr.Contains(forceFlag),
})
if err != nil {
return errhand.BuildDError("error: committing").AddCause(err).Build()
}
return nil
}
func applyChanges(ctx context.Context, root *doltdb.RootValue, workingDiffs map[string]hash.Hash) (*doltdb.RootValue, errhand.VerboseError) {
var err error
for tblName, h := range workingDiffs {
@@ -307,6 +362,12 @@ func executeMerge(ctx context.Context, squash bool, dEnv *env.DoltEnv, cm1, cm2
}
}
return mergedRootToWorking(ctx, squash, dEnv, mergedRoot, workingDiffs, cm2, tblToStats)
}
func mergedRootToWorking(ctx context.Context, squash bool, dEnv *env.DoltEnv, mergedRoot *doltdb.RootValue, workingDiffs map[string]hash.Hash, cm2 *doltdb.Commit, tblToStats map[string]*merge.MergeStats) errhand.VerboseError {
var err error
workingRoot := mergedRoot
if len(workingDiffs) > 0 {
workingRoot, err = applyChanges(ctx, mergedRoot, workingDiffs)

View File

@@ -104,8 +104,7 @@ func pullFromRemote(ctx context.Context, dEnv *env.DoltEnv, apr *argparser.ArgPa
remoteTrackRef := refSpec.DestRef(branch)
if remoteTrackRef != nil {
squash := apr.Contains(squashParam)
verr = pullRemoteBranch(ctx, squash, dEnv, remote, branch, remoteTrackRef)
verr = pullRemoteBranch(ctx, apr, dEnv, remote, branch, remoteTrackRef)
if verr != nil {
return verr
@@ -128,7 +127,7 @@ func pullFromRemote(ctx context.Context, dEnv *env.DoltEnv, apr *argparser.ArgPa
return nil
}
func pullRemoteBranch(ctx context.Context, squash bool, dEnv *env.DoltEnv, r env.Remote, srcRef, destRef ref.DoltRef) errhand.VerboseError {
func pullRemoteBranch(ctx context.Context, apr *argparser.ArgParseResults, dEnv *env.DoltEnv, r env.Remote, srcRef, destRef ref.DoltRef) errhand.VerboseError {
srcDB, err := r.GetRemoteDB(ctx, dEnv.DoltDB.ValueReadWriter().Format())
if err != nil {
@@ -147,5 +146,5 @@ func pullRemoteBranch(ctx context.Context, squash bool, dEnv *env.DoltEnv, r env
return errhand.BuildDError("error: fetch failed").AddCause(err).Build()
}
return mergeCommitSpec(ctx, squash, dEnv, destRef.String())
return mergeCommitSpec(ctx, apr, dEnv, destRef.String())
}