summaryrefslogtreecommitdiffstats
path: root/pkg/commands/git.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/commands/git.go')
-rw-r--r--pkg/commands/git.go123
1 files changed, 80 insertions, 43 deletions
diff --git a/pkg/commands/git.go b/pkg/commands/git.go
index 6e86fe0b5..815c84423 100644
--- a/pkg/commands/git.go
+++ b/pkg/commands/git.go
@@ -63,16 +63,17 @@ func setupRepositoryAndWorktree(openGitRepository func(string) (*gogit.Repositor
// GitCommand is our main git interface
type GitCommand struct {
- Log *logrus.Entry
- OSCommand *OSCommand
- Worktree *gogit.Worktree
- Repo *gogit.Repository
- Tr *i18n.Localizer
- Config config.AppConfigurer
- getGlobalGitConfig func(string) (string, error)
- getLocalGitConfig func(string) (string, error)
- removeFile func(string) error
- DotGitDir string
+ Log *logrus.Entry
+ OSCommand *OSCommand
+ Worktree *gogit.Worktree
+ Repo *gogit.Repository
+ Tr *i18n.Localizer
+ Config config.AppConfigurer
+ getGlobalGitConfig func(string) (string, error)
+ getLocalGitConfig func(string) (string, error)
+ removeFile func(string) error
+ DotGitDir string
+ onSuccessfulContinue func() error
}
// NewGitCommand it runs git commands
@@ -376,7 +377,7 @@ func (c *GitCommand) Commit(message string, flags string) (*exec.Cmd, error) {
// AmendHead amends HEAD with whatever is staged in your working tree
func (c *GitCommand) AmendHead() (*exec.Cmd, error) {
- command := "git commit --amend --no-edit"
+ command := "git commit --amend --no-edit --allow-empty"
if c.usingGpg() {
return c.OSCommand.PrepareSubProcess(c.OSCommand.Platform.shell, c.OSCommand.Platform.shellArg, command), nil
}
@@ -530,7 +531,7 @@ func (c *GitCommand) Ignore(filename string) error {
// Show shows the diff of a commit
func (c *GitCommand) Show(sha string) (string, error) {
- show, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git show --color %s", sha))
+ show, err := c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git show --color --no-renames %s", sha))
if err != nil {
return "", err
}
@@ -605,11 +606,11 @@ func (c *GitCommand) Diff(file *File, plain bool, cached bool) string {
return s
}
-func (c *GitCommand) ApplyPatch(patch string, reverse bool, cached bool) (string, error) {
+func (c *GitCommand) ApplyPatch(patch string, reverse bool, cached bool, extraFlags string) error {
filename, err := c.OSCommand.CreateTempFile("patch", patch)
if err != nil {
c.Log.Error(err)
- return "", err
+ return err
}
defer func() { _ = c.OSCommand.Remove(filename) }()
@@ -624,7 +625,7 @@ func (c *GitCommand) ApplyPatch(patch string, reverse bool, cached bool) (string
cachedFlag = "--cached"
}
- return c.OSCommand.RunCommandWithOutput(fmt.Sprintf("git apply %s %s %s", cachedFlag, reverseFlag, c.OSCommand.Quote(filename)))
+ return c.OSCommand.RunCommand(fmt.Sprintf("git apply %s %s %s %s", cachedFlag, reverseFlag, extraFlags, c.OSCommand.Quote(filename)))
}
func (c *GitCommand) FastForward(branchName string) error {
@@ -645,13 +646,29 @@ func (c *GitCommand) RunSkipEditorCommand(command string) error {
// GenericMerge takes a commandType of "merge" or "rebase" and a command of "abort", "skip" or "continue"
// By default we skip the editor in the case where a commit will be made
func (c *GitCommand) GenericMerge(commandType string, command string) error {
- return c.RunSkipEditorCommand(
+ err := c.RunSkipEditorCommand(
fmt.Sprintf(
"git %s --%s",
commandType,
command,
),
)
+ if err != nil {
+ return err
+ }
+
+ // sometimes we need to do a sequence of things in a rebase but the user needs to
+ // fix merge conflicts along the way. When this happens we queue up the next step
+ // so that after the next successful rebase continue we can continue from where we left off
+ if commandType == "rebase" && command == "continue" && c.onSuccessfulContinue != nil {
+ f := c.onSuccessfulContinue
+ c.onSuccessfulContinue = nil
+ return f()
+ }
+ if command == "abort" {
+ c.onSuccessfulContinue = nil
+ }
+ return nil
}
func (c *GitCommand) RewordCommit(commits []*Commit, index int) (*exec.Cmd, error) {
@@ -852,8 +869,8 @@ func (c *GitCommand) CherryPickCommits(commits []*Commit) error {
}
// GetCommitFiles get the specified commit files
-func (c *GitCommand) GetCommitFiles(commitSha string) ([]*CommitFile, error) {
- cmd := fmt.Sprintf("git show --pretty= --name-only %s", commitSha)
+func (c *GitCommand) GetCommitFiles(commitSha string, patchManager *PatchManager) ([]*CommitFile, error) {
+ cmd := fmt.Sprintf("git show --pretty= --name-only --no-renames %s", commitSha)
files, err := c.OSCommand.RunCommandWithOutput(cmd)
if err != nil {
return nil, err
@@ -862,10 +879,16 @@ func (c *GitCommand) GetCommitFiles(commitSha string) ([]*CommitFile, error) {
commitFiles := make([]*CommitFile, 0)
for _, file := range strings.Split(strings.TrimRight(files, "\n"), "\n") {
+ status := UNSELECTED
+ if patchManager != nil && patchManager.CommitSha == commitSha {
+ status = patchManager.GetFileStatus(file)
+ }
+
commitFiles = append(commitFiles, &CommitFile{
Sha: commitSha,
Name: file,
DisplayString: file,
+ Status: status,
})
}
@@ -873,8 +896,12 @@ func (c *GitCommand) GetCommitFiles(commitSha string) ([]*CommitFile, error) {
}
// ShowCommitFile get the diff of specified commit file
-func (c *GitCommand) ShowCommitFile(commitSha, fileName string) (string, error) {
- cmd := fmt.Sprintf("git show --color %s -- %s", commitSha, fileName)
+func (c *GitCommand) ShowCommitFile(commitSha, fileName string, plain bool) (string, error) {
+ colorArg := "--color"
+ if plain {
+ colorArg = ""
+ }
+ cmd := fmt.Sprintf("git show --no-renames %s %s -- %s", colorArg, commitSha, fileName)
return c.OSCommand.RunCommandWithOutput(cmd)
}
@@ -886,28 +913,7 @@ func (c *GitCommand) CheckoutFile(commitSha, fileName string) error {
// DiscardOldFileChanges discards changes to a file from an old commit
func (c *GitCommand) DiscardOldFileChanges(commits []*Commit, commitIndex int, fileName string) error {
- if len(commits)-1 < commitIndex {
- return errors.New("index outside of range of commits")
- }
-
- // 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() {
- return errors.New(c.Tr.SLocalize("DisabledForGPG"))
- }
-
- todo, sha, err := c.GenerateGenericRebaseTodo(commits, commitIndex, "edit")
- if err != nil {
- return err
- }
-
- cmd, err := c.PrepareInteractiveRebaseCommand(sha, todo, true)
- if err != nil {
- return err
- }
-
- if err := c.OSCommand.RunPreparedCommand(cmd); err != nil {
+ if err := c.BeginInteractiveRebaseForCommit(commits, commitIndex); err != nil {
return err
}
@@ -924,7 +930,7 @@ func (c *GitCommand) DiscardOldFileChanges(commits []*Commit, commitIndex int, f
}
// amend the commit
- cmd, err = c.AmendHead()
+ cmd, err := c.AmendHead()
if cmd != nil {
return errors.New("received unexpected pointer to cmd")
}
@@ -1016,3 +1022,34 @@ func (c *GitCommand) StashSaveStagedChanges(message string) error {
return nil
}
+
+// BeginInteractiveRebaseForCommit starts an interactive rebase to edit the current
+// commit and pick all others. After this you'll want to call `c.GenericMerge("rebase", "continue")`
+func (c *GitCommand) BeginInteractiveRebaseForCommit(commits []*Commit, commitIndex int) error {
+ if len(commits)-1 < commitIndex {
+ return errors.New("index outside of range of commits")
+ }
+
+ // 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() {
+ return errors.New(c.Tr.SLocalize("DisabledForGPG"))
+ }
+
+ todo, sha, err := c.GenerateGenericRebaseTodo(commits, commitIndex, "edit")
+ if err != nil {
+ return err
+ }
+
+ cmd, err := c.PrepareInteractiveRebaseCommand(sha, todo, true)
+ if err != nil {
+ return err
+ }
+
+ if err := c.OSCommand.RunPreparedCommand(cmd); err != nil {
+ return err
+ }
+
+ return nil
+}