github.com/driusan/dgit@v0.0.0-20221118233547-f39f0c15edbb/git/revert.go (about)

     1  package git
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  )
     7  
     8  type RevertOptions struct {
     9  	Edit bool
    10  
    11  	MergeParent int
    12  
    13  	NoCommit bool
    14  	SignOff  bool
    15  
    16  	MergeStrategy       string
    17  	MergeStrategyOption string
    18  
    19  	Continue, Quit, Abort bool
    20  }
    21  
    22  // Reverts the given commits from the HEAD.  Revert doesn't actually create the
    23  // new commit, it returns the new tree and leaves it up to the caller (who has
    24  // a better chance of knowing the appropriate commit message..)
    25  func Revert(c *Client, opts RevertOptions, commits []Commitish) error {
    26  	switch {
    27  	case len(commits) == 0:
    28  		return fmt.Errorf("Must provide commit to revert")
    29  	case len(commits) > 1:
    30  		return fmt.Errorf("Only 1 revert at a time currently supported. Sequencer not implemented")
    31  	}
    32  
    33  	// Ensure that the tree is clean before doing anything.
    34  	worktree, err := DiffFiles(c, DiffFilesOptions{}, nil)
    35  	if err != nil {
    36  		return err
    37  	}
    38  	if len(worktree) > 0 {
    39  		return fmt.Errorf("Untracked changes to files would be modified. Aborting")
    40  	}
    41  	head, err := c.GetHeadCommit()
    42  	if err != nil {
    43  		return err
    44  	}
    45  
    46  	if err := UpdateRef(c, UpdateRefOptions{NoDeref: true}, "REVERT_HEAD", head, ""); err != nil {
    47  		return err
    48  	}
    49  
    50  	cmt, err := commits[0].CommitID(c)
    51  	if err != nil {
    52  		return err
    53  	}
    54  	parents, err := cmt.Parents(c)
    55  	if err != nil {
    56  		return err
    57  	}
    58  	var diff []HashDiff
    59  	if len(parents) == 0 {
    60  		// FIXME: This shouldn't be the case, but needs to be handled
    61  		// as a special case.
    62  		return fmt.Errorf("Can not revert initial commit.")
    63  	} else if len(parents) == 1 {
    64  		diffs, err := DiffTree(c, &DiffTreeOptions{}, parents[0], cmt, nil)
    65  		if err != nil {
    66  			return err
    67  		}
    68  		diff = diffs
    69  	} else if opts.MergeParent <= 0 {
    70  		return fmt.Errorf("Must specify merge parent to revert a merge commit.")
    71  	} else {
    72  		// the merge parent is 1 indexed.
    73  		diffs, err := DiffTree(c, &DiffTreeOptions{}, parents[opts.MergeParent-1], cmt, nil)
    74  		if err != nil {
    75  			return err
    76  		}
    77  		diff = diffs
    78  	}
    79  
    80  	patch, err := ioutil.TempFile("", "gitrevertpatch")
    81  	if err != nil {
    82  		return err
    83  	}
    84  	if err := GeneratePatch(c, DiffCommonOptions{Patch: true}, diff, patch); err != nil {
    85  		return err
    86  	}
    87  	if err := Apply(c, ApplyOptions{ThreeWay: true, Reverse: true, Index: true}, []File{File(patch.Name())}); err != nil {
    88  		return err
    89  	}
    90  	return nil
    91  }