summaryrefslogtreecommitdiffstats
path: root/pkg/commands
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2019-03-11 13:04:08 +1100
committerJesse Duffield <jessedduffield@gmail.com>2019-03-16 10:20:27 +1100
commit4f7f6a073ced1b31be6bbac119d1f0f4de229578 (patch)
tree492d67c4e51b4593c74d26e9a46c434f11c267f7 /pkg/commands
parent0e008cc15f8e7cbb6869151d48ae30403bf4dc70 (diff)
allow user to discard old file changes for a given commit
Diffstat (limited to 'pkg/commands')
-rw-r--r--pkg/commands/errors.go14
-rw-r--r--pkg/commands/git.go77
-rw-r--r--pkg/commands/os.go14
3 files changed, 93 insertions, 12 deletions
diff --git a/pkg/commands/errors.go b/pkg/commands/errors.go
new file mode 100644
index 000000000..4723eb95d
--- /dev/null
+++ b/pkg/commands/errors.go
@@ -0,0 +1,14 @@
+package commands
+
+import "github.com/go-errors/errors"
+
+// WrapError wraps an error for the sake of showing a stack trace at the top level
+// the go-errors package, for some reason, does not return nil when you try to wrap
+// a non-error, so we're just doing it here
+func WrapError(err error) error {
+ if err == nil {
+ return err
+ }
+
+ return errors.Wrap(err, 0)
+}
diff --git a/pkg/commands/git.go b/pkg/commands/git.go
index 96b25316c..c4de147cd 100644
--- a/pkg/commands/git.go
+++ b/pkg/commands/git.go
@@ -32,11 +32,11 @@ func navigateToRepoRootDirectory(stat func(string) (os.FileInfo, error), chdir f
}
if !os.IsNotExist(err) {
- return errors.Wrap(err, 0)
+ return WrapError(err)
}
if err = chdir(".."); err != nil {
- return errors.Wrap(err, 0)
+ return WrapError(err)
}
}
}
@@ -797,10 +797,25 @@ func (c *GitCommand) CherryPickCommits(commits []*Commit) error {
return c.OSCommand.RunPreparedCommand(cmd)
}
-// CommitFiles get the specified commit files
-func (c *GitCommand) CommitFiles(commitID string) (string, error) {
+// GetCommitFiles get the specified commit files
+func (c *GitCommand) GetCommitFiles(commitID string) ([]*CommitFile, error) {
cmd := fmt.Sprintf("git show --pretty= --name-only %s", commitID)
- return c.OSCommand.RunCommandWithOutput(cmd)
+ files, err := c.OSCommand.RunCommandWithOutput(cmd)
+ if err != nil {
+ return nil, err
+ }
+
+ commitFiles := make([]*CommitFile, 0)
+
+ for _, file := range strings.Split(strings.TrimRight(files, "\n"), "\n") {
+ commitFiles = append(commitFiles, &CommitFile{
+ Sha: commitID,
+ Name: file,
+ DisplayString: file,
+ })
+ }
+
+ return commitFiles, nil
}
// ShowCommitFile get the diff of specified commit file
@@ -814,3 +829,55 @@ func (c *GitCommand) CheckoutFile(commitSha, fileName string) error {
cmd := fmt.Sprintf("git checkout %s %s", commitSha, fileName)
return c.OSCommand.RunCommand(cmd)
}
+
+// DiscardOldFileChanges discards changes to a file from an old commit
+func (c *GitCommand) DiscardOldFileChanges(commits []*Commit, commitIndex int, fileName string) error {
+ // we can make this GPG thing possible it just means we need to do this in two parts:
+ // one where we handle the possibility of a credential request, and the other
+ // where we continue the rebase
+ if c.usingGpg() {
+ errors.New("feature not available for users using GPG")
+ }
+
+ commitSha := commits[commitIndex].Sha
+
+ todo, err := c.GenerateGenericRebaseTodo(commits, commitIndex, "edit")
+ if err != nil {
+ return err
+ }
+
+ cmd, err := c.PrepareInteractiveRebaseCommand(commitSha+"^", todo, true)
+ if err != nil {
+ return err
+ }
+
+ if err := c.OSCommand.RunPreparedCommand(cmd); err != nil {
+ return err
+ }
+
+ // check if file exists in previous commit (this command returns an error if the file doesn't exist)
+ if err := c.OSCommand.RunCommand(fmt.Sprintf("git cat-file -e HEAD^:%s", fileName)); err != nil {
+ if err := c.OSCommand.RemoveFile(fileName); err != nil {
+ return err
+ }
+ if err := c.StageFile(fileName); err != nil {
+ return err
+ }
+ } else {
+ if err := c.CheckoutFile("HEAD^", fileName); err != nil {
+ return err
+ }
+ }
+
+ // amend the commit
+ cmd, err = c.AmendHead()
+ if cmd != nil {
+ errors.New("received unexpected pointer to cmd")
+ }
+ if err != nil {
+ return err
+ }
+
+ // continue
+ return c.GenericMerge("rebase", "continue")
+}
diff --git a/pkg/commands/os.go b/pkg/commands/os.go
index a7a1fdaa4..9e0967cba 100644
--- a/pkg/commands/os.go
+++ b/pkg/commands/os.go
@@ -145,7 +145,7 @@ func sanitisedCommandOutput(output []byte, err error) (string, error) {
// errors like 'exit status 1' are not very useful so we'll create an error
// from the combined output
if outputString == "" {
- return "", errors.Wrap(err, 0)
+ return "", WrapError(err)
}
return outputString, errors.New(outputString)
}
@@ -224,13 +224,13 @@ func (c *OSCommand) Unquote(message string) string {
func (c *OSCommand) AppendLineToFile(filename, line string) error {
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
- return errors.Wrap(err, 0)
+ return WrapError(err)
}
defer f.Close()
_, err = f.WriteString("\n" + line)
if err != nil {
- return errors.Wrap(err, 0)
+ return WrapError(err)
}
return nil
}
@@ -240,16 +240,16 @@ func (c *OSCommand) CreateTempFile(filename, content string) (string, error) {
tmpfile, err := ioutil.TempFile("", filename)
if err != nil {
c.Log.Error(err)
- return "", errors.Wrap(err, 0)
+ return "", WrapError(err)
}
if _, err := tmpfile.WriteString(content); err != nil {
c.Log.Error(err)
- return "", errors.Wrap(err, 0)
+ return "", WrapError(err)
}
if err := tmpfile.Close(); err != nil {
c.Log.Error(err)
- return "", errors.Wrap(err, 0)
+ return "", WrapError(err)
}
return tmpfile.Name(), nil
@@ -258,7 +258,7 @@ func (c *OSCommand) CreateTempFile(filename, content string) (string, error) {
// RemoveFile removes a file at the specified path
func (c *OSCommand) RemoveFile(filename string) error {
err := os.Remove(filename)
- return errors.Wrap(err, 0)
+ return WrapError(err)
}
// FileExists checks whether a file exists at the specified path