Merge pull request #7373 from dolthub/steph/rebase

add `dolt rebase` command
This commit is contained in:
stephanie
2024-01-23 10:27:58 -08:00
committed by GitHub
20 changed files with 843 additions and 59 deletions

View File

@@ -359,7 +359,7 @@ func getCommitMessageFromEditor(sqlCtx *sql.Context, queryist cli.Queryist, sugg
editorStr := cliCtx.Config().GetStringOrDefault(config.DoltEditor, backupEd)
cli.ExecuteWithStdioRestored(func() {
commitMsg, cErr := editor.OpenCommitEditor(editorStr, initialMsg)
commitMsg, cErr := editor.OpenTempEditor(editorStr, initialMsg)
if cErr != nil {
err = cErr
}

View File

@@ -0,0 +1,341 @@
// Copyright 2024 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 (
"bytes"
"context"
"errors"
"fmt"
"os"
"strings"
"github.com/dolthub/go-mysql-server/sql"
"github.com/gocraft/dbr/v2"
"github.com/gocraft/dbr/v2/dialect"
"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/dconfig"
"github.com/dolthub/dolt/go/libraries/doltcore/env"
"github.com/dolthub/dolt/go/libraries/doltcore/rebase"
"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dprocedures"
"github.com/dolthub/dolt/go/libraries/utils/argparser"
"github.com/dolthub/dolt/go/libraries/utils/config"
"github.com/dolthub/dolt/go/libraries/utils/editor"
)
var rebaseDocs = cli.CommandDocumentationContent{
ShortDesc: "Reapplies commits on top of another base tip",
LongDesc: `Rewrites commit history for the current branch by replaying commits, allowing the commits to be reordered,
squashed, or dropped. The commits included in the rebase plan are the commits reachable by the current branch, but NOT
reachable from the branch specified as the argument when starting a rebase (also known as the upstream branch). This is
the same as Git and Dolt's "two dot log" syntax, or |upstreamBranch|..|currentBranch|.
Rebasing is useful to clean and organize your commit history, especially before merging a feature branch back to a shared
branch. For example, you can drop commits that contain debugging or test changes, or squash or fixup small commits into a
single commit, or reorder commits so that related changes are adjacent in the new commit history.
`,
Synopsis: []string{
`(-i | --interactive) {{.LessThan}}upstream{{.GreaterThan}}`,
`(--continue | --abort)`,
},
}
type RebaseCmd struct{}
var _ cli.Command = RebaseCmd{}
// Name returns the name of the Dolt cli command. This is what is used on the command line to invoke the command
func (cmd RebaseCmd) Name() string {
return "rebase"
}
// Description returns a description of the command
func (cmd RebaseCmd) Description() string {
return rebaseDocs.ShortDesc
}
// EventType returns the type of the event to log
func (cmd RebaseCmd) EventType() eventsapi.ClientEventType {
return eventsapi.ClientEventType_REBASE
}
func (cmd RebaseCmd) Docs() *cli.CommandDocumentation {
ap := cmd.ArgParser()
return cli.NewCommandDocumentation(rebaseDocs, ap)
}
func (cmd RebaseCmd) ArgParser() *argparser.ArgParser {
return cli.CreateRebaseArgParser()
}
// Exec executes the command
func (cmd RebaseCmd) Exec(ctx context.Context, commandStr string, args []string, dEnv *env.DoltEnv, cliCtx cli.CliContext) int {
ap := cmd.ArgParser()
help, usage := cli.HelpAndUsagePrinters(cli.CommandDocsForCommandString(commandStr, rebaseDocs, ap))
apr := cli.ParseArgsOrDie(ap, args, help)
queryist, sqlCtx, closeFunc, err := cliCtx.QueryEngine(ctx)
if err != nil {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
if closeFunc != nil {
defer closeFunc()
}
branchName, err := getActiveBranchName(sqlCtx, queryist)
if err != nil {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
query, err := constructInterpolatedDoltRebaseQuery(apr)
if err != nil {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
rows, err := GetRowsForSql(queryist, sqlCtx, query)
if err != nil {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
status, err := getInt64ColAsInt64(rows[0][0])
if err != nil {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
if status == 1 {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(errors.New("error: "+rows[0][1].(string))), usage)
}
message := rows[0][1].(string)
if strings.Contains(message, dprocedures.SuccessfulRebaseMessage) {
cli.Println(dprocedures.SuccessfulRebaseMessage + branchName)
} else if strings.Contains(message, dprocedures.RebaseAbortedMessage) {
cli.Println(dprocedures.RebaseAbortedMessage)
} else {
rebasePlan, err := getRebasePlan(cliCtx, sqlCtx, queryist, apr.Arg(0), branchName)
if err != nil {
// attempt to abort the rebase
_, _, _ = queryist.Query(sqlCtx, "CALL DOLT_REBASE('--abort');")
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
// if all uncommented lines are deleted in the editor, abort the rebase
if rebasePlan == nil || rebasePlan.Steps == nil || len(rebasePlan.Steps) == 0 {
rows, err := GetRowsForSql(queryist, sqlCtx, "CALL DOLT_REBASE('--abort');")
if err != nil {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
status, err := getInt64ColAsInt64(rows[0][0])
if err != nil {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
if status == 1 {
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(errors.New("error: "+rows[0][1].(string))), usage)
}
cli.Println(dprocedures.RebaseAbortedMessage)
} else {
err = insertRebasePlanIntoDoltRebaseTable(rebasePlan, sqlCtx, queryist)
if err != nil {
// attempt to abort the rebase
_, _, _ = queryist.Query(sqlCtx, "CALL DOLT_REBASE('--abort');")
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
rows, err := GetRowsForSql(queryist, sqlCtx, "CALL DOLT_REBASE('--continue');")
if err != nil {
// attempt to abort the rebase
_, _, _ = queryist.Query(sqlCtx, "CALL DOLT_REBASE('--abort');")
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
status, err := getInt64ColAsInt64(rows[0][0])
if err != nil {
// attempt to abort the rebase
_, _, _ = queryist.Query(sqlCtx, "CALL DOLT_REBASE('--abort');")
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(err), usage)
}
if status == 1 {
// attempt to abort the rebase
_, _, _ = queryist.Query(sqlCtx, "CALL DOLT_REBASE('--abort');")
return HandleVErrAndExitCode(errhand.VerboseErrorFromError(errors.New("error: "+rows[0][1].(string))), usage)
}
cli.Println(dprocedures.SuccessfulRebaseMessage + branchName)
}
}
return HandleVErrAndExitCode(nil, usage)
}
// constructInterpolatedDoltRebaseQuery generates the sql query necessary to call the DOLT_REBASE() function.
// Also interpolates this query to prevent sql injection.
func constructInterpolatedDoltRebaseQuery(apr *argparser.ArgParseResults) (string, error) {
var params []interface{}
var args []string
if apr.NArg() == 1 {
params = append(params, apr.Arg(0))
args = append(args, "?")
}
if apr.Contains(cli.InteractiveFlag) {
args = append(args, "'--interactive'")
}
if apr.Contains(cli.ContinueFlag) {
args = append(args, "'--continue'")
}
if apr.Contains(cli.AbortParam) {
args = append(args, "'--abort'")
}
query := fmt.Sprintf("CALL DOLT_REBASE(%s);", strings.Join(args, ", "))
return dbr.InterpolateForDialect(query, params, dialect.MySQL)
}
// getRebasePlan opens an editor for users to edit the rebase plan and returns the parsed rebase plan from the editor.
func getRebasePlan(cliCtx cli.CliContext, sqlCtx *sql.Context, queryist cli.Queryist, rebaseBranch, currentBranch string) (*rebase.RebasePlan, error) {
if cli.ExecuteWithStdioRestored == nil {
return nil, nil
}
if !checkIsTerminal() {
return nil, nil
}
initialRebaseMsg, err := buildInitialRebaseMsg(sqlCtx, queryist, rebaseBranch, currentBranch)
if err != nil {
return nil, err
}
backupEd := "vim"
// try getting default editor on the user system
if ed, edSet := os.LookupEnv(dconfig.EnvEditor); edSet {
backupEd = ed
}
// try getting Dolt config core.editor
editorStr := cliCtx.Config().GetStringOrDefault(config.DoltEditor, backupEd)
var rebaseMsg string
cli.ExecuteWithStdioRestored(func() {
rebaseMsg, err = editor.OpenTempEditor(editorStr, initialRebaseMsg)
})
if err != nil {
return nil, err
}
return parseRebaseMessage(rebaseMsg)
}
// buildInitialRebaseMsg builds the initial message to display to the user when they open the rebase plan editor,
// including the formatted rebase plan.
func buildInitialRebaseMsg(sqlCtx *sql.Context, queryist cli.Queryist, rebaseBranch, currentBranch string) (string, error) {
var buffer bytes.Buffer
rows, err := GetRowsForSql(queryist, sqlCtx, "SELECT action, commit_hash, commit_message FROM dolt_rebase ORDER BY rebase_order")
if err != nil {
return "", err
}
// rebase plan
for _, row := range rows {
action, found := getRebaseAction(row[0])
if !found {
return "", errors.New("invalid rebase action")
}
commitHash := row[1].(string)
commitMessage := row[2].(string)
buffer.WriteString(fmt.Sprintf("%s %s %s\n", action, commitHash, commitMessage))
}
buffer.WriteString("\n")
// help text
rebaseBranchHash, err := getHashOf(queryist, sqlCtx, rebaseBranch)
if err != nil {
return "", err
}
currentBranchHash, err := getHashOf(queryist, sqlCtx, currentBranch)
if err != nil {
return "", err
}
numSteps := len(rows)
buffer.WriteString(fmt.Sprintf("# Rebase %s..%s onto %s (%d commands)\n#\n", rebaseBranchHash, currentBranchHash, rebaseBranchHash, numSteps))
buffer.WriteString("# Commands:\n")
buffer.WriteString("# p, pick <commit> = use commit\n")
buffer.WriteString("# d, drop <commit> = remove commit\n")
buffer.WriteString("# r, reword <commit> = use commit, but edit the commit message\n")
buffer.WriteString("# s, squash <commit> = use commit, but meld into previous commit\n")
buffer.WriteString("# f, fixup <commit> = like \"squash\", but discard this commit's message\n")
buffer.WriteString("# These lines can be re-ordered; they are executed from top to bottom.\n")
buffer.WriteString("#\n")
buffer.WriteString("# If you remove a line here THAT COMMIT WILL BE LOST.\n")
buffer.WriteString("#\n")
buffer.WriteString("# However, if you remove everything, the rebase will be aborted.\n")
buffer.WriteString("#\n")
return buffer.String(), nil
}
// getRebaseAction returns the rebase action for the given row. This conversion is necessary because a local client
// returns an int representing the enum whereas a remote client properly returns the label.
// TODO: Remove this once the local client returns the label.
func getRebaseAction(col interface{}) (string, bool) {
action, ok := col.(string)
if ok {
return action, true
} else {
return dprocedures.RebaseActionEnumType.At(int(col.(uint16)))
}
}
// parseRebaseMessage parses the rebase message from the editor and adds all uncommented out lines as steps in the rebase plan.
func parseRebaseMessage(rebaseMsg string) (*rebase.RebasePlan, error) {
plan := &rebase.RebasePlan{}
splitMsg := strings.Split(rebaseMsg, "\n")
for i, line := range splitMsg {
if !strings.HasPrefix(line, "#") && strings.TrimSpace(line) != "" {
rebaseStepParts := strings.SplitN(line, " ", 3)
if len(rebaseStepParts) != 3 {
return nil, fmt.Errorf("invalid line %d: %s", i, line)
}
plan.Steps = append(plan.Steps, rebase.RebasePlanStep{
Action: rebaseStepParts[0],
CommitHash: rebaseStepParts[1],
CommitMsg: rebaseStepParts[2],
})
}
}
return plan, nil
}
// insertRebasePlanIntoDoltRebaseTable inserts the rebase plan into the dolt_rebase table by re-building the dolt_rebase
// table from scratch.
func insertRebasePlanIntoDoltRebaseTable(plan *rebase.RebasePlan, sqlCtx *sql.Context, queryist cli.Queryist) error {
_, err := GetRowsForSql(queryist, sqlCtx, "TRUNCATE TABLE dolt_rebase")
if err != nil {
return err
}
for i, step := range plan.Steps {
_, err := GetRowsForSql(queryist, sqlCtx, fmt.Sprintf("INSERT INTO dolt_rebase VALUES (%d, '%s', '%s', '%s')", i+1, step.Action, step.CommitHash, step.CommitMsg))
if err != nil {
return err
}
}
return nil
}

View File

@@ -125,6 +125,7 @@ var doltSubCommands = []cli.Command{
commands.ProfileCmd{},
commands.QueryDiff{},
commands.ReflogCmd{},
commands.RebaseCmd{},
}
var commandsWithoutCliCtx = []cli.Command{

View File

@@ -17,7 +17,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.22.0
// protoc v4.26.0
// source: dolt/services/eventsapi/v1alpha1/client_event.proto
package eventsapi

View File

@@ -17,7 +17,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.22.0
// - protoc v4.26.0
// source: dolt/services/eventsapi/v1alpha1/client_event.proto
package eventsapi

View File

@@ -17,7 +17,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.22.0
// protoc v4.26.0
// source: dolt/services/eventsapi/v1alpha1/event_constants.proto
package eventsapi
@@ -157,6 +157,7 @@ const (
ClientEventType_PROFILE ClientEventType = 62
ClientEventType_REFLOG ClientEventType = 63
ClientEventType_SQL_SERVER_HEARTBEAT ClientEventType = 64
ClientEventType_REBASE ClientEventType = 65
)
// Enum value maps for ClientEventType.
@@ -227,6 +228,7 @@ var (
62: "PROFILE",
63: "REFLOG",
64: "SQL_SERVER_HEARTBEAT",
65: "REBASE",
}
ClientEventType_value = map[string]int32{
"TYPE_UNSPECIFIED": 0,
@@ -294,6 +296,7 @@ var (
"PROFILE": 62,
"REFLOG": 63,
"SQL_SERVER_HEARTBEAT": 64,
"REBASE": 65,
}
)
@@ -484,7 +487,7 @@ var file_dolt_services_eventsapi_v1alpha1_event_constants_proto_rawDesc = []byte
0x52, 0x4d, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00,
0x12, 0x09, 0x0a, 0x05, 0x4c, 0x49, 0x4e, 0x55, 0x58, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x57,
0x49, 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x41, 0x52, 0x57,
0x49, 0x4e, 0x10, 0x03, 0x2a, 0xa3, 0x08, 0x0a, 0x0f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45,
0x49, 0x4e, 0x10, 0x03, 0x2a, 0xaf, 0x08, 0x0a, 0x0f, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x45,
0x76, 0x65, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x54, 0x59, 0x50, 0x45,
0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08,
0x0a, 0x04, 0x49, 0x4e, 0x49, 0x54, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x54, 0x41, 0x54,
@@ -550,28 +553,29 @@ var file_dolt_services_eventsapi_v1alpha1_event_constants_proto_rawDesc = []byte
0x04, 0x53, 0x48, 0x4f, 0x57, 0x10, 0x3d, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x52, 0x4f, 0x46, 0x49,
0x4c, 0x45, 0x10, 0x3e, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45, 0x46, 0x4c, 0x4f, 0x47, 0x10, 0x3f,
0x12, 0x18, 0x0a, 0x14, 0x53, 0x51, 0x4c, 0x5f, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52, 0x5f, 0x48,
0x45, 0x41, 0x52, 0x54, 0x42, 0x45, 0x41, 0x54, 0x10, 0x40, 0x2a, 0x6a, 0x0a, 0x08, 0x4d, 0x65,
0x74, 0x72, 0x69, 0x63, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x12, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43,
0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14,
0x0a, 0x10, 0x42, 0x59, 0x54, 0x45, 0x53, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44,
0x45, 0x44, 0x10, 0x01, 0x12, 0x17, 0x0a, 0x13, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44,
0x5f, 0x4d, 0x53, 0x5f, 0x45, 0x4c, 0x41, 0x50, 0x53, 0x45, 0x44, 0x10, 0x02, 0x12, 0x17, 0x0a,
0x13, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x41, 0x50, 0x49, 0x5f, 0x52, 0x50, 0x43, 0x5f, 0x45,
0x52, 0x52, 0x4f, 0x52, 0x10, 0x03, 0x2a, 0x45, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62,
0x75, 0x74, 0x65, 0x49, 0x44, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, 0x55,
0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00,
0x12, 0x15, 0x0a, 0x11, 0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x55, 0x52, 0x4c, 0x5f, 0x53,
0x43, 0x48, 0x45, 0x4d, 0x45, 0x10, 0x02, 0x22, 0x04, 0x08, 0x01, 0x10, 0x01, 0x2a, 0x3f, 0x0a,
0x05, 0x41, 0x70, 0x70, 0x49, 0x44, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x50, 0x50, 0x5f, 0x49, 0x44,
0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c,
0x0a, 0x08, 0x41, 0x50, 0x50, 0x5f, 0x44, 0x4f, 0x4c, 0x54, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c,
0x41, 0x50, 0x50, 0x5f, 0x44, 0x4f, 0x4c, 0x54, 0x47, 0x52, 0x45, 0x53, 0x10, 0x02, 0x42, 0x51,
0x5a, 0x4f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x6f, 0x6c,
0x74, 0x68, 0x75, 0x62, 0x2f, 0x64, 0x6f, 0x6c, 0x74, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x65, 0x6e,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x64, 0x6f, 0x6c, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x73, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x61, 0x70, 0x69, 0x2f, 0x76,
0x31, 0x61, 0x6c, 0x70, 0x68, 0x61, 0x31, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x61, 0x70,
0x69, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x45, 0x41, 0x52, 0x54, 0x42, 0x45, 0x41, 0x54, 0x10, 0x40, 0x12, 0x0a, 0x0a, 0x06, 0x52, 0x45,
0x42, 0x41, 0x53, 0x45, 0x10, 0x41, 0x2a, 0x6a, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63,
0x49, 0x44, 0x12, 0x16, 0x0a, 0x12, 0x4d, 0x45, 0x54, 0x52, 0x49, 0x43, 0x5f, 0x55, 0x4e, 0x53,
0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x42, 0x59,
0x54, 0x45, 0x53, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x45, 0x44, 0x10, 0x01,
0x12, 0x17, 0x0a, 0x13, 0x44, 0x4f, 0x57, 0x4e, 0x4c, 0x4f, 0x41, 0x44, 0x5f, 0x4d, 0x53, 0x5f,
0x45, 0x4c, 0x41, 0x50, 0x53, 0x45, 0x44, 0x10, 0x02, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x4d,
0x4f, 0x54, 0x45, 0x41, 0x50, 0x49, 0x5f, 0x52, 0x50, 0x43, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52,
0x10, 0x03, 0x2a, 0x45, 0x0a, 0x0b, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x49,
0x44, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x54, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x5f, 0x55,
0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x15, 0x0a, 0x11,
0x52, 0x45, 0x4d, 0x4f, 0x54, 0x45, 0x5f, 0x55, 0x52, 0x4c, 0x5f, 0x53, 0x43, 0x48, 0x45, 0x4d,
0x45, 0x10, 0x02, 0x22, 0x04, 0x08, 0x01, 0x10, 0x01, 0x2a, 0x3f, 0x0a, 0x05, 0x41, 0x70, 0x70,
0x49, 0x44, 0x12, 0x16, 0x0a, 0x12, 0x41, 0x50, 0x50, 0x5f, 0x49, 0x44, 0x5f, 0x55, 0x4e, 0x53,
0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x41, 0x50,
0x50, 0x5f, 0x44, 0x4f, 0x4c, 0x54, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x41, 0x50, 0x50, 0x5f,
0x44, 0x4f, 0x4c, 0x54, 0x47, 0x52, 0x45, 0x53, 0x10, 0x02, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x64, 0x6f, 0x6c, 0x74, 0x68, 0x75, 0x62,
0x2f, 0x64, 0x6f, 0x6c, 0x74, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2f, 0x64, 0x6f, 0x6c, 0x74, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73,
0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x61, 0x6c, 0x70,
0x68, 0x61, 0x31, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x61, 0x70, 0x69, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@@ -15,7 +15,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.22.0
// protoc v4.26.0
// source: dolt/services/remotesapi/v1alpha1/chunkstore.proto
package remotesapi

View File

@@ -15,7 +15,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.22.0
// - protoc v4.26.0
// source: dolt/services/remotesapi/v1alpha1/chunkstore.proto
package remotesapi

View File

@@ -15,7 +15,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.22.0
// protoc v4.26.0
// source: dolt/services/remotesapi/v1alpha1/credentials.proto
package remotesapi

View File

@@ -15,7 +15,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.22.0
// - protoc v4.26.0
// source: dolt/services/remotesapi/v1alpha1/credentials.proto
package remotesapi

View File

@@ -15,7 +15,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc v4.22.0
// protoc v4.26.0
// source: dolt/services/replicationapi/v1alpha1/replication.proto
package replicationapi

View File

@@ -15,7 +15,7 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
// versions:
// - protoc-gen-go-grpc v1.2.0
// - protoc v4.22.0
// - protoc v4.26.0
// source: dolt/services/replicationapi/v1alpha1/replication.proto
package replicationapi

View File

@@ -92,6 +92,12 @@ var ErrRebaseConflictWithAbortError = goerrors.NewKind(
"merge conflict detected while rebasing commit %s. " +
"attempted to abort rebase operation, but encountered error: %w")
// SuccessfulRebaseMessage is used when a rebase finishes successfully. The branch that was rebased should be appended
// to the end of the message.
var SuccessfulRebaseMessage = "Successfully rebased and updated refs/heads/"
var RebaseAbortedMessage = "Interactive rebase aborted"
func doltRebase(ctx *sql.Context, args ...string) (sql.RowIter, error) {
res, message, err := doDoltRebase(ctx, args)
if err != nil {
@@ -116,15 +122,15 @@ func doDoltRebase(ctx *sql.Context, args []string) (int, string, error) {
if err != nil {
return 1, "", err
} else {
return 0, "interactive rebase aborted", nil
return 0, RebaseAbortedMessage, nil
}
case apr.Contains(cli.ContinueFlag):
err := continueRebase(ctx)
rebaseBranch, err := continueRebase(ctx)
if err != nil {
return 1, "", err
} else {
return 0, "interactive rebase completed", nil
return 0, SuccessfulRebaseMessage + rebaseBranch, nil
}
default:
@@ -371,7 +377,7 @@ func abortRebase(ctx *sql.Context) error {
return doltSession.SwitchWorkingSet(ctx, ctx.GetCurrentDatabase(), wsRef)
}
func continueRebase(ctx *sql.Context) error {
func continueRebase(ctx *sql.Context) (string, error) {
// TODO: Eventually, when we allow interactive-rebases to be stopped and started (e.g. with the break action,
// or for conflict resolution), we'll need to track what step we're at in the rebase plan.
@@ -379,46 +385,46 @@ func continueRebase(ctx *sql.Context) error {
doltSession := dsess.DSessFromSess(ctx.Session)
workingSet, err := doltSession.WorkingSet(ctx, ctx.GetCurrentDatabase())
if err != nil {
return err
return "", err
}
if !workingSet.RebaseActive() {
return fmt.Errorf("no rebase in progress")
return "", fmt.Errorf("no rebase in progress")
}
db, err := doltSession.Provider().Database(ctx, ctx.GetCurrentDatabase())
if err != nil {
return err
return "", err
}
rdb, ok := db.(rebase.RebasePlanDatabase)
if !ok {
return fmt.Errorf("expected a dsess.RebasePlanDatabase implementation, but received a %T", db)
return "", fmt.Errorf("expected a dsess.RebasePlanDatabase implementation, but received a %T", db)
}
rebasePlan, err := rdb.LoadRebasePlan(ctx)
if err != nil {
return err
return "", err
}
err = rebase.ValidateRebasePlan(ctx, rebasePlan)
if err != nil {
return err
return "", err
}
for _, step := range rebasePlan.Steps {
err = processRebasePlanStep(ctx, &step)
if err != nil {
return err
return "", err
}
}
// Update the branch being rebased to point to the same commit as our temporary working branch
rebaseBranchWorkingSet, err := doltSession.WorkingSet(ctx, ctx.GetCurrentDatabase())
if err != nil {
return err
return "", err
}
dbData, ok := doltSession.GetDbData(ctx, ctx.GetCurrentDatabase())
if !ok {
return fmt.Errorf("unable to get db data for database %s", ctx.GetCurrentDatabase())
return "", fmt.Errorf("unable to get db data for database %s", ctx.GetCurrentDatabase())
}
rebaseBranch := rebaseBranchWorkingSet.RebaseState().Branch()
@@ -427,7 +433,7 @@ func continueRebase(ctx *sql.Context) error {
// Check that the branch being rebased hasn't been updated since the rebase started
err = validateRebaseBranchHasntChanged(ctx, rebaseBranch, rebaseBranchWorkingSet.RebaseState())
if err != nil {
return err
return "", err
}
// TODO: copyABranch (and the underlying call to doltdb.NewBranchAtCommit) has a race condition
@@ -438,25 +444,25 @@ func continueRebase(ctx *sql.Context) error {
// database.CommitWithWorkingSet, since it updates a branch head and working set atomically.
err = copyABranch(ctx, dbData, rebaseWorkingBranch, rebaseBranch, true, nil)
if err != nil {
return err
return "", err
}
// Checkout the branch being rebased
previousBranchWorkingSetRef, err := ref.WorkingSetRefForHead(ref.NewBranchRef(rebaseBranchWorkingSet.RebaseState().Branch()))
if err != nil {
return err
return "", err
}
err = doltSession.SwitchWorkingSet(ctx, ctx.GetCurrentDatabase(), previousBranchWorkingSetRef)
if err != nil {
return err
return "", err
}
// delete the temporary working branch
dbData, ok = doltSession.GetDbData(ctx, ctx.GetCurrentDatabase())
if !ok {
return fmt.Errorf("unable to lookup dbdata")
return "", fmt.Errorf("unable to lookup dbdata")
}
return actions.DeleteBranch(ctx, dbData, rebaseWorkingBranch, actions.DeleteOptions{
return rebaseBranch, actions.DeleteBranch(ctx, dbData, rebaseWorkingBranch, actions.DeleteOptions{
Force: true,
}, doltSession.Provider(), nil)
}

View File

@@ -321,7 +321,7 @@ var DoltRebaseScriptTests = []queries.ScriptTest{
},
{
Query: "call dolt_rebase('--abort');",
Expected: []sql.Row{{0, "interactive rebase aborted"}},
Expected: []sql.Row{{0, "Interactive rebase aborted"}},
},
{
Query: "select active_branch();",
@@ -412,7 +412,7 @@ var DoltRebaseScriptTests = []queries.ScriptTest{
},
{
Query: "call dolt_rebase('--continue');",
Expected: []sql.Row{{0, "interactive rebase completed"}},
Expected: []sql.Row{{0, "Successfully rebased and updated refs/heads/branch1"}},
},
{
// When rebase completes, rebase status should be cleared
@@ -627,7 +627,7 @@ var DoltRebaseScriptTests = []queries.ScriptTest{
},
{
Query: "call dolt_rebase('--continue');",
Expected: []sql.Row{{0, "interactive rebase completed"}},
Expected: []sql.Row{{0, "Successfully rebased and updated refs/heads/branch1"}},
},
{
Query: "select message from dolt_log;",
@@ -694,7 +694,7 @@ var DoltRebaseScriptTests = []queries.ScriptTest{
},
{
Query: "call dolt_rebase('--continue');",
Expected: []sql.Row{{0, "interactive rebase completed"}},
Expected: []sql.Row{{0, "Successfully rebased and updated refs/heads/branch1"}},
},
{
Query: "select message from dolt_log;",

View File

@@ -24,8 +24,8 @@ import (
"github.com/google/uuid"
)
// OpenCommitEditor allows user to write/edit commit message in temporary file
func OpenCommitEditor(ed string, initialContents string) (string, error) {
// OpenTempEditor allows user to write/edit message in temporary file
func OpenTempEditor(ed string, initialContents string) (string, error) {
filename := filepath.Join(os.TempDir(), uuid.New().String())
err := os.WriteFile(filename, []byte(initialContents), os.ModePerm)

View File

@@ -59,7 +59,7 @@ func TestOpenCommitEditor(t *testing.T) {
}
for _, test := range tests {
val, err := OpenCommitEditor(test.editorStr, test.initialContents)
val, err := OpenTempEditor(test.editorStr, test.initialContents)
if err != nil {
t.Error(err)

View File

@@ -136,6 +136,7 @@ SKIP_SERVER_TESTS=$(cat <<-EOM
~cli-hosted.bats~
~profile.bats~
~ls.bats~
~rebase.bats~
EOM
)

View File

@@ -0,0 +1,382 @@
#!/usr/bin/env bats
load $BATS_TEST_DIRNAME/helper/common.bash
setup() {
setup_common
dolt sql -q "CREATE table t1 (pk int primary key, c int);"
dolt add t1
dolt commit -m "main commit 1"
dolt branch b1
dolt sql -q "INSERT INTO t1 VALUES (1,1);"
dolt add t1
dolt commit -m "main commit 2"
dolt checkout b1
dolt sql -q "CREATE table t2 (pk int primary key);"
dolt add t2
dolt commit -m "b1 commit 1"
dolt checkout main
}
teardown() {
assert_feature_version
teardown_common
}
setupCustomEditorScript() {
touch rebaseScript.sh
echo "#!/bin/bash" >> rebaseScript.sh
if [ $# -eq 1 ]; then
echo "mv $1 \$1" >> rebaseScript.sh
fi
chmod +x rebaseScript.sh
export EDITOR=$PWD/rebaseScript.sh
export DOLT_TEST_FORCE_OPEN_EDITOR="1"
}
@test "rebase: no rebase in progress errors" {
run dolt rebase --abort
[ "$status" -eq 1 ]
[[ "$output" =~ "no rebase in progress" ]] || false
run dolt rebase --continue
[ "$status" -eq 1 ]
[[ "$output" =~ "no rebase in progress" ]] || false
}
@test "rebase: -i flag required" {
run dolt rebase b1
[ "$status" -eq 1 ]
[[ "$output" =~ "non-interactive rebases not currently supported" ]] || false
}
@test "rebase: bad args" {
run dolt rebase -i
[ "$status" -eq 1 ]
[[ "$output" =~ "not enough args" ]] || false
run dolt rebase -i main b1
[ "$status" -eq 1 ]
[[ "$output" =~ "rebase takes at most one positional argument" ]] || false
run dolt rebase --abrot
[ "$status" -eq 1 ]
[[ "$output" =~ "error: unknown option \`abrot'" ]] || false
run dolt rebase -i foo
[ "$status" -eq 1 ]
[[ "$output" =~ "branch not found: foo" ]] || false
}
@test "rebase: cannot rebase with dirty working set" {
dolt sql -q "INSERT INTO t1 VALUES (2,2);"
run dolt rebase -i b1
[ "$status" -eq 1 ]
[[ "$output" =~ "cannot start a rebase with uncommitted changes" ]] || false
}
@test "rebase: cannot rebase during active merge" {
dolt checkout b1
dolt sql -q "INSERT INTO t1 VALUES (1,2);"
dolt add t1
dolt commit -m "b1 commit 2"
run dolt merge main
[ "$status" -eq 1 ]
[[ "$output" =~ "Automatic merge failed" ]] || false
run dolt rebase -i main
[ "$status" -eq 1 ]
[[ "$output" =~ "unable to start rebase while a merge is in progress abort the current merge before proceeding" ]] || false
}
@test "rebase: rebase working branch already exists" {
dolt checkout b1
dolt branch dolt_rebase_b1
run dolt rebase -i main
[ "$status" -eq 1 ]
[[ "$output" =~ "fatal: A branch named 'dolt_rebase_b1' already exists." ]] || false
}
@test "rebase: verify custom script" {
setupCustomEditorScript "rebasePlan.txt"
dolt checkout b1
run dolt show head
[ "$status" -eq 0 ]
COMMIT1=${lines[0]:12:32}
touch rebasePlan.txt
echo "pick $COMMIT1 b1 commit 1" >> rebasePlan.txt
run dolt rebase -i main
[ "$status" -eq 0 ]
[[ "$output" =~ "Successfully rebased and updated refs/heads/b1" ]] || false
run dolt log
[ "$status" -eq 0 ]
[[ "$output" =~ "b1 commit 1" ]] || false
[[ "$output" =~ "main commit 2" ]] || false
}
@test "rebase: basic rebase" {
setupCustomEditorScript
dolt checkout b1
run dolt rebase -i main
[ "$status" -eq 0 ]
[[ "$output" =~ "Successfully rebased and updated refs/heads/b1" ]] || false
run dolt log
[ "$status" -eq 0 ]
[[ "$output" =~ "main commit 2" ]] || false
}
@test "rebase: failed rebase will abort and clean up" {
setupCustomEditorScript "invalidRebasePlan.txt"
dolt checkout b1
touch invalidRebasePlan.txt
echo "foo" >> invalidRebasePlan.txt
run dolt rebase -i main
[ "$status" -eq 1 ]
[[ "$output" =~ "invalid line 0: foo" ]] || false
run dolt branch
[ "$status" -eq 0 ]
! [[ "$output" =~ "dolt_rebase_b1" ]] || false
run dolt rebase --continue
[ "$status" -eq 1 ]
[[ "$output" =~ "no rebase in progress" ]] || false
}
@test "rebase: invalid rebase plan" {
setupCustomEditorScript "invalidRebasePlan.txt"
dolt checkout b1
touch invalidRebasePlan.txt
echo "foo" >> invalidRebasePlan.txt
run dolt rebase -i main
[ "$status" -eq 1 ]
[[ "$output" =~ "invalid line 0: foo" ]] || false
touch invalidRebasePlan.txt
echo "pick foo main commit 1" >> invalidRebasePlan.txt
run dolt rebase -i main
[ "$status" -eq 1 ]
[[ "$output" =~ "invalid commit hash: foo" ]] || false
}
@test "rebase: empty rebase plan aborts the rebase" {
setupCustomEditorScript "emptyRebasePlan.txt"
touch emptyRebasePlan.txt
echo "# " >> emptyRebasePlan.txt
echo "# commented out lines don't count" >> emptyRebasePlan.txt
dolt checkout b1
run dolt rebase -i main
[ "$status" -eq 0 ]
[[ "$output" =~ "rebase aborted" ]] || false
run dolt log
[ "$status" -eq 0 ]
! [[ "$output" =~ "main commit 2" ]] || false
run dolt rebase --continue
[ "$status" -eq 1 ]
[[ "$output" =~ "no rebase in progress" ]] || false
run dolt branch
[ "$status" -eq 0 ]
! [[ "$output" =~ "dolt_rebase_b1" ]] || false
}
@test "rebase: multi step rebase" {
setupCustomEditorScript "multiStepPlan.txt"
dolt checkout b1
run dolt show head
[ "$status" -eq 0 ]
COMMIT1=${lines[0]:12:32}
dolt sql -q "insert into t2 values (1);"
dolt commit -am "b1 commit 2"
run dolt show head
[ "$status" -eq 0 ]
COMMIT2=${lines[0]:12:32}
dolt sql -q "insert into t2 values (2);"
dolt commit -am "b1 commit 3"
run dolt show head
[ "$status" -eq 0 ]
COMMIT3=${lines[0]:12:32}
dolt sql -q "insert into t2 values (3);"
dolt commit -am "b1 commit 4"
run dolt show head
[ "$status" -eq 0 ]
COMMIT4=${lines[0]:12:32}
dolt sql -q "insert into t2 values (4);"
dolt commit -am "b1 commit 5"
run dolt show head
[ "$status" -eq 0 ]
COMMIT5=${lines[0]:12:32}
dolt sql -q "insert into t2 values (5);"
dolt commit -am "b1 commit 6"
run dolt show head
[ "$status" -eq 0 ]
COMMIT6=${lines[0]:12:32}
dolt sql -q "insert into t2 values (6);"
dolt commit -am "b1 commit 7"
run dolt show head
[ "$status" -eq 0 ]
COMMIT7=${lines[0]:12:32}
touch multiStepPlan.txt
echo "pick $COMMIT1 b1 commit 1" >> multiStepPlan.txt
echo "squash $COMMIT2 b1 commit 2" >> multiStepPlan.txt
echo "squash $COMMIT3 b1 commit 3" >> multiStepPlan.txt
echo "drop $COMMIT4 b1 commit 4" >> multiStepPlan.txt
echo "reword $COMMIT5 reworded!" >> multiStepPlan.txt
echo "fixup $COMMIT6 b1 commit 6" >> multiStepPlan.txt
echo "pick $COMMIT7 b1 commit 7" >> multiStepPlan.txt
run dolt rebase -i main
[ "$status" -eq 0 ]
[[ "$output" =~ "Successfully rebased and updated refs/heads/b1" ]] || false
run dolt show head
[ "$status" -eq 0 ]
[[ "$output" =~ "b1 commit 7" ]] || false
run dolt show head~1
[ "$status" -eq 0 ]
[[ "$output" =~ "reworded!" ]] || false
run dolt show head~2
[ "$status" -eq 0 ]
[[ "$output" =~ "b1 commit 1" ]] || false
[[ "$output" =~ "b1 commit 2" ]] || false
[[ "$output" =~ "b1 commit 3" ]] || false
run dolt show head~3
[ "$status" -eq 0 ]
[[ "$output" =~ "main commit 2" ]] || false
}
@test "rebase: non-standard plan changes" {
setupCustomEditorScript "nonStandardPlan.txt"
dolt checkout -b b2
dolt sql -q "CREATE table t3 (pk int primary key);"
dolt add t3
dolt commit -m "b2 commit 1"
run dolt show head
[ "$status" -eq 0 ]
COMMIT1=${lines[0]:12:32}
dolt sql -q "insert into t3 values (1);"
dolt commit -am "b2 commit 2"
dolt sql -q "insert into t3 values (2);"
dolt commit -am "b2 commit 3"
dolt checkout b1
run dolt show head
[ "$status" -eq 0 ]
COMMIT2=${lines[0]:12:32}
touch nonStandardPlan.txt
echo "pick $COMMIT1 b2 commit 1" >> nonStandardPlan.txt
echo "pick $COMMIT2 b1 commit 1" >> nonStandardPlan.txt
dolt checkout b2
run dolt rebase -i main
[ "$status" -eq 0 ]
[[ "$output" =~ "Successfully rebased and updated refs/heads/b2" ]] || false
run dolt show head
[ "$status" -eq 0 ]
[[ "$output" =~ "b1 commit 1" ]] || false
run dolt show head~1
[ "$status" -eq 0 ]
[[ "$output" =~ "b2 commit 1" ]] || false
run dolt show head~2
[ "$status" -eq 0 ]
[[ "$output" =~ "main commit 2" ]] || false
}
@test "rebase: rebase skips merge commits" {
setupCustomEditorScript
dolt checkout b1
dolt merge main -m "b1 merge commit"
dolt sql -q "insert into t2 values (1);"
dolt commit -am "b1 commit 2"
dolt checkout main
dolt sql -q "insert into t1 values (2,2);"
dolt commit -am "main commit 3"
dolt checkout b1
run dolt rebase -i main
[ "$status" -eq 0 ]
[[ "$output" =~ "Successfully rebased and updated refs/heads/b1" ]] || false
run dolt log
[ "$status" -eq 0 ]
[[ "$output" =~ "b1 commit 2" ]] || false
[[ "$output" =~ "b1 commit 1" ]] || false
[[ "$output" =~ "main commit 3" ]] || false
! [[ "$output" =~ "b1 merge commit" ]] || false
}
@test "rebase: rebase with data conflicts aborts" {
setupCustomEditorScript
dolt checkout b1
dolt sql -q "INSERT INTO t1 VALUES (1,2);"
dolt commit -am "b1 commit 2"
run dolt rebase -i main
[ "$status" -eq 1 ]
[[ "$output" =~ "merge conflict detected while rebasing commit" ]] || false
[[ "$output" =~ "the rebase has been automatically aborted" ]] || false
run dolt rebase --continue
[ "$status" -eq 1 ]
[[ "$output" =~ "no rebase in progress" ]] || false
run dolt branch
[ "$status" -eq 0 ]
! [[ "$output" =~ "dolt_rebase_b1" ]] || false
}
@test "rebase: rebase with schema conflicts aborts" {
setupCustomEditorScript
dolt checkout b1
dolt sql -q "ALTER TABLE t1 MODIFY COLUMN c varchar(100);"
dolt commit -am "b1 commit 2"
run dolt rebase -i main
[ "$status" -eq 1 ]
[[ "$output" =~ "merge conflict detected while rebasing commit" ]] || false
[[ "$output" =~ "the rebase has been automatically aborted" ]] || false
run dolt rebase --continue
[ "$status" -eq 1 ]
[[ "$output" =~ "no rebase in progress" ]] || false
run dolt branch
[ "$status" -eq 0 ]
! [[ "$output" =~ "dolt_rebase_b1" ]] || false
}

View File

@@ -1338,3 +1338,51 @@ SQL
[ "$status" -eq "0" ]
[[ "$output" =~ "5" ]] || false
}
@test "sql-local-remote: verify dolt rebase behavior" {
cd altDB
dolt sql -q "drop table dolt_ignore;"
dolt add .
dolt branch b1
dolt commit -m "main commit 2"
dolt checkout b1
dolt sql -q "create table t2 (pk int primary key)"
dolt add .
dolt commit -m "b1 commit 1"
touch rebaseScript.sh
echo "#!/bin/bash" >> rebaseScript.sh
chmod +x rebaseScript.sh
export EDITOR=$PWD/rebaseScript.sh
export DOLT_TEST_FORCE_OPEN_EDITOR="1"
run dolt --verbose-engine-setup rebase -i main
[ "$status" -eq 0 ]
[[ "$output" =~ "starting local mode" ]] || false
[[ "$output" =~ "Successfully rebased and updated refs/heads/b1" ]] || false
run dolt log
[ "$status" -eq 0 ]
[[ "$output" =~ "main commit 2" ]] || false
[[ "$output" =~ "b1 commit 1" ]] || false
dolt checkout main
dolt sql -q "create table t3 (pk int primary key)"
dolt add .
dolt commit -m "main commit 3"
dolt checkout b1
start_sql_server altDB
run dolt --verbose-engine-setup rebase -i main
[ "$status" -eq 0 ]
[[ "$output" =~ "starting remote mode" ]] || false
[[ "$output" =~ "Successfully rebased and updated refs/heads/b1" ]] || false
run dolt log
[ "$status" -eq 0 ]
[[ "$output" =~ "main commit 3" ]] || false
[[ "$output" =~ "main commit 2" ]] || false
[[ "$output" =~ "b1 commit 1" ]] || false
}

View File

@@ -94,6 +94,7 @@ enum ClientEventType {
PROFILE = 62;
REFLOG = 63;
SQL_SERVER_HEARTBEAT = 64;
REBASE = 65;
}
enum MetricID {