github.com/dolthub/dolt/go@v0.40.5-0.20240520175717-68db7794bea6/libraries/doltcore/merge/revert.go (about)

     1  // Copyright 2021 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package merge
    16  
    17  import (
    18  	"fmt"
    19  
    20  	"github.com/dolthub/go-mysql-server/sql"
    21  
    22  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
    23  	"github.com/dolthub/dolt/go/libraries/doltcore/table/editor"
    24  )
    25  
    26  // Revert is a convenience function for a three-way merge. In particular, given some root and a collection of commits
    27  // that are all parents of the root value, this applies a three-way merge with the following characteristics (assuming
    28  // a commit is HEAD~1):
    29  //
    30  // Base:   HEAD~1
    31  // Ours:   root
    32  // Theirs: HEAD~2
    33  //
    34  // The root is updated with the merged result, and this process is repeated for each commit given, in the order given.
    35  // Currently, we error on conflicts or constraint violations generated by the merge.
    36  func Revert(ctx *sql.Context, ddb *doltdb.DoltDB, root doltdb.RootValue, commits []*doltdb.Commit, opts editor.Options) (doltdb.RootValue, string, error) {
    37  	revertMessage := "Revert"
    38  
    39  	for _, cm := range commits {
    40  		if len(cm.DatasParents()) == 0 {
    41  			h, err := cm.HashOf()
    42  			if err != nil {
    43  				return nil, "", err
    44  			}
    45  			return nil, "", fmt.Errorf("cannot revert commit with no parents (%s)", h.String())
    46  		}
    47  	}
    48  
    49  	for i, baseCommit := range commits {
    50  		if i > 0 {
    51  			revertMessage += " and"
    52  		}
    53  		baseRoot, err := baseCommit.GetRootValue(ctx)
    54  		if err != nil {
    55  			return nil, "", err
    56  		}
    57  		baseMeta, err := baseCommit.GetCommitMeta(ctx)
    58  		if err != nil {
    59  			return nil, "", err
    60  		}
    61  		revertMessage = fmt.Sprintf(`%s "%s"`, revertMessage, baseMeta.Description)
    62  
    63  		optCmt, err := ddb.ResolveParent(ctx, baseCommit, 0)
    64  		if err != nil {
    65  			return nil, "", err
    66  		}
    67  		parentCM, ok := optCmt.ToCommit()
    68  		if !ok {
    69  			return nil, "", doltdb.ErrGhostCommitEncountered
    70  		}
    71  
    72  		theirRoot, err := parentCM.GetRootValue(ctx)
    73  		if err != nil {
    74  			return nil, "", err
    75  		}
    76  
    77  		var result *Result
    78  		result, err = MergeRoots(ctx, root, theirRoot, baseRoot, parentCM, baseCommit, opts, MergeOpts{IsCherryPick: false})
    79  		if err != nil {
    80  			return nil, "", err
    81  		}
    82  		root = result.Root
    83  
    84  		if ok, err := doltdb.HasConflicts(ctx, result.Root); err != nil {
    85  			return nil, "", err
    86  		} else if ok {
    87  			return nil, "", fmt.Errorf("revert currently does not handle conflicts")
    88  		}
    89  		if ok, err := doltdb.HasConstraintViolations(ctx, result.Root); err != nil {
    90  			return nil, "", err
    91  		} else if ok {
    92  			return nil, "", fmt.Errorf("revert currently does not handle constraint violations")
    93  		}
    94  	}
    95  
    96  	return root, revertMessage, nil
    97  }