summaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2019-03-18 21:19:07 +1100
committerJesse Duffield <jessedduffield@gmail.com>2019-03-23 13:26:17 +1100
commitf502f75e1f56bf8f34d3fdf42e934919cd045d85 (patch)
tree27236dda4b1bd011d43e0bc1efb2e642371c6c6d /pkg
parentff97ef7b94b5ccfda1d8b98b0a7e21a779309fcc (diff)
add more options for resetting files in the working tree
Diffstat (limited to 'pkg')
-rw-r--r--pkg/commands/git.go19
-rw-r--r--pkg/commands/git_test.go103
-rw-r--r--pkg/gui/files_panel.go88
-rw-r--r--pkg/i18n/dutch.go18
-rw-r--r--pkg/i18n/english.go18
-rw-r--r--pkg/i18n/polish.go18
6 files changed, 221 insertions, 43 deletions
diff --git a/pkg/commands/git.go b/pkg/commands/git.go
index e674dc720..dbd9087c2 100644
--- a/pkg/commands/git.go
+++ b/pkg/commands/git.go
@@ -217,11 +217,11 @@ func includesInt(list []int, a int) bool {
// ResetAndClean removes all unstaged changes and removes all untracked files
func (c *GitCommand) ResetAndClean() error {
- if err := c.OSCommand.RunCommand("git reset --hard HEAD"); err != nil {
+ if err := c.ResetHardHead(); err != nil {
return err
}
- return c.OSCommand.RunCommand("git clean -fd")
+ return c.RemoveUntrackedFiles()
}
func (c *GitCommand) GetCurrentBranchUpstreamDifferenceCount() (string, string) {
@@ -890,3 +890,18 @@ func (c *GitCommand) DiscardOldFileChanges(commits []*Commit, commitIndex int, f
// continue
return c.GenericMerge("rebase", "continue")
}
+
+// DiscardAnyUnstagedFileChanges discards any unstages file changes via `git checkout -- .`
+func (c *GitCommand) DiscardAnyUnstagedFileChanges() error {
+ return c.OSCommand.RunCommand("git checkout -- .")
+}
+
+// RemoveUntrackedFiles runs `git clean -fd`
+func (c *GitCommand) RemoveUntrackedFiles() error {
+ return c.OSCommand.RunCommand("git clean -fd")
+}
+
+// ResetHardHead runs `git reset --hard HEAD`
+func (c *GitCommand) ResetHardHead() error {
+ return c.OSCommand.RunCommand("git reset --hard HEAD")
+}
diff --git a/pkg/commands/git_test.go b/pkg/commands/git_test.go
index 614ad527b..aa1785af8 100644
--- a/pkg/commands/git_test.go
+++ b/pkg/commands/git_test.go
@@ -1933,8 +1933,8 @@ func TestGitCommandGetCommitFiles(t *testing.T) {
}
}
-// TestGitCommandDiscardUnstagedChanges is a function.
-func TestGitCommandDiscardUnstagedChanges(t *testing.T) {
+// TestGitCommandDiscardUnstagedFileChanges is a function.
+func TestGitCommandDiscardUnstagedFileChanges(t *testing.T) {
type scenario struct {
testName string
file *File
@@ -1967,3 +1967,102 @@ func TestGitCommandDiscardUnstagedChanges(t *testing.T) {
})
}
}
+
+// TestGitCommandDiscardAnyUnstagedFileChanges is a function.
+func TestGitCommandDiscardAnyUnstagedFileChanges(t *testing.T) {
+ type scenario struct {
+ testName string
+ command func(string, ...string) *exec.Cmd
+ test func(error)
+ }
+
+ scenarios := []scenario{
+ {
+ "valid case",
+ test.CreateMockCommand(t, []*test.CommandSwapper{
+ {
+ Expect: `git checkout -- .`,
+ Replace: "echo",
+ },
+ }),
+ func(err error) {
+ assert.NoError(t, err)
+ },
+ },
+ }
+
+ gitCmd := NewDummyGitCommand()
+
+ for _, s := range scenarios {
+ t.Run(s.testName, func(t *testing.T) {
+ gitCmd.OSCommand.command = s.command
+ s.test(gitCmd.DiscardAnyUnstagedFileChanges())
+ })
+ }
+}
+
+// TestGitCommandRemoveUntrackedFiles is a function.
+func TestGitCommandRemoveUntrackedFiles(t *testing.T) {
+ type scenario struct {
+ testName string
+ command func(string, ...string) *exec.Cmd
+ test func(error)
+ }
+
+ scenarios := []scenario{
+ {
+ "valid case",
+ test.CreateMockCommand(t, []*test.CommandSwapper{
+ {
+ Expect: `git clean -fd`,
+ Replace: "echo",
+ },
+ }),
+ func(err error) {
+ assert.NoError(t, err)
+ },
+ },
+ }
+
+ gitCmd := NewDummyGitCommand()
+
+ for _, s := range scenarios {
+ t.Run(s.testName, func(t *testing.T) {
+ gitCmd.OSCommand.command = s.command
+ s.test(gitCmd.RemoveUntrackedFiles())
+ })
+ }
+}
+
+// TestGitCommandResetHardHead is a function.
+func TestGitCommandResetHardHead(t *testing.T) {
+ type scenario struct {
+ testName string
+ command func(string, ...string) *exec.Cmd
+ test func(error)
+ }
+
+ scenarios := []scenario{
+ {
+ "valid case",
+ test.CreateMockCommand(t, []*test.CommandSwapper{
+ {
+ Expect: `git reset --hard HEAD`,
+ Replace: "echo",
+ },
+ }),
+ func(err error) {
+ assert.NoError(t, err)
+ },
+ },
+ }
+
+ gitCmd := NewDummyGitCommand()
+
+ for _, s := range scenarios {
+ t.Run(s.testName, func(t *testing.T) {
+ gitCmd.OSCommand.command = s.command
+ s.test(gitCmd.ResetHardHead())
+ })
+ }
+}
diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go
index deaffb83b..2f91df519 100644
--- a/pkg/gui/files_panel.go
+++ b/pkg/gui/files_panel.go
@@ -10,6 +10,7 @@ import (
"fmt"
"strings"
+ "github.com/fatih/color"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/utils"
@@ -455,15 +456,6 @@ func (gui *Gui) handleAbortMerge(g *gocui.Gui, v *gocui.View) error {
return gui.refreshFiles()
}
-func (gui *Gui) handleResetAndClean(g *gocui.Gui, v *gocui.View) error {
- return gui.createConfirmationPanel(g, v, gui.Tr.SLocalize("ClearFilePanel"), gui.Tr.SLocalize("SureResetHardHead"), func(g *gocui.Gui, v *gocui.View) error {
- if err := gui.GitCommand.ResetAndClean(); err != nil {
- gui.createErrorPanel(g, err.Error())
- }
- return gui.refreshFiles()
- }, nil)
-}
-
func (gui *Gui) openFile(filename string) error {
if err := gui.OSCommand.OpenFile(filename); err != nil {
return gui.createErrorPanel(gui.g, err.Error())
@@ -498,13 +490,22 @@ type discardOption struct {
description string
}
-type discardOptionValue int
+type discardAllOption struct {
+ handler func() error
+ description string
+ command string
+}
// GetDisplayStrings is a function.
func (r *discardOption) GetDisplayStrings(isFocused bool) []string {
return []string{r.description}
}
+// GetDisplayStrings is a function.
+func (r *discardAllOption) GetDisplayStrings(isFocused bool) []string {
+ return []string{r.description, color.New(color.FgRed).Sprint(r.command)}
+}
+
func (gui *Gui) handleCreateDiscardMenu(g *gocui.Gui, v *gocui.View) error {
file, err := gui.getSelectedFile(g)
if err != nil {
@@ -518,11 +519,7 @@ func (gui *Gui) handleCreateDiscardMenu(g *gocui.Gui, v *gocui.View) error {
{
description: gui.Tr.SLocalize("discardAllChanges"),
handler: func(file *commands.File) error {
- if err := gui.GitCommand.DiscardAllFileChanges(file); err != nil {
- return err
- }
-
- return gui.refreshFiles()
+ return gui.GitCommand.DiscardAllFileChanges(file)
},
},
{
@@ -537,11 +534,7 @@ func (gui *Gui) handleCreateDiscardMenu(g *gocui.Gui, v *gocui.View) error {
discardUnstagedChanges := &discardOption{
description: gui.Tr.SLocalize("discardUnstagedChanges"),
handler: func(file *commands.File) error {
- if err := gui.GitCommand.DiscardUnstagedFileChanges(file); err != nil {
- return err
- }
-
- return gui.refreshFiles()
+ return gui.GitCommand.DiscardUnstagedFileChanges(file)
},
}
@@ -549,8 +542,61 @@ func (gui *Gui) handleCreateDiscardMenu(g *gocui.Gui, v *gocui.View) error {
}
handleMenuPress := func(index int) error {
- return options[index].handler(file)
+ if err := options[index].handler(file); err != nil {
+ return err
+ }
+
+ return gui.refreshFiles()
}
return gui.createMenu(file.Name, options, handleMenuPress)
}
+
+func (gui *Gui) handleResetAndClean(g *gocui.Gui, v *gocui.View) error {
+ options := []*discardAllOption{
+ {
+ description: gui.Tr.SLocalize("discardAllChangesToAllFiles"),
+ command: "reset --hard HEAD && git clean -fd",
+ handler: func() error {
+ return gui.GitCommand.ResetAndClean()
+ },
+ },
+ {
+ description: gui.Tr.SLocalize("discardAnyUnstagedChanges"),
+ command: "git checkout -- .",
+ handler: func() error {
+ return gui.GitCommand.DiscardAnyUnstagedFileChanges()
+ },
+ },
+ {
+ description: gui.Tr.SLocalize("discardUntrackedFiles"),
+ command: "git clean -fd",
+ handler: func() error {
+ return gui.GitCommand.RemoveUntrackedFiles()
+ },
+ },
+ {
+ description: gui.Tr.SLocalize("hardReset"),
+ command: "git reset --hard HEAD",
+ handler: func() error {
+ return gui.GitCommand.ResetHardHead()
+ },
+ },
+ {
+ description: gui.Tr.SLocalize("cancel"),
+ handler: func() error {
+ return nil
+ },
+ },
+ }
+
+ handleMenuPress := func(index int) error {
+ if err := options[index].handler(); err != nil {
+ return err
+ }
+
+ return gui.refreshFiles()
+ }
+
+ return gui.createMenu("", options, handleMenuPress)
+}
diff --git a/pkg/i18n/dutch.go b/pkg/i18n/dutch.go
index add38dd59..662c7cce6 100644
--- a/pkg/i18n/dutch.go
+++ b/pkg/i18n/dutch.go
@@ -158,9 +158,6 @@ func addDutch(i18nObject *i18n.Bundle) error {
ID: "FileNoMergeCons",
Other: "Dit bestand heeft geen merge conflicten",
}, &i18n.Message{
- ID: "SureResetHardHead",
- Other: "Weet je het zeker dat je `reset --hard HEAD` en `clean -fd` wil uitvoeren? Het kan dat je hierdoor bestanden verliest",
- }, &i18n.Message{
ID: "SureTo",
Other: "Weet je het zeker dat je {{.fileName}} wilt {{.deleteVerb}} (je veranderingen zullen worden verwijderd)",
}, &i18n.Message{
@@ -341,9 +338,6 @@ func addDutch(i18nObject *i18n.Bundle) error {
ID: "CantCloseConfirmationPrompt",
Other: "Kon de bevestiging prompt niet sluiten: {{.error}}",
}, &i18n.Message{
- ID: "ClearFilePanel",
- Other: "maak bestandsvenster leeg",
- }, &i18n.Message{
ID: "MergeAborted",
Other: "Merge afgebroken",
}, &i18n.Message{
@@ -694,6 +688,18 @@ func addDutch(i18nObject *i18n.Bundle) error {
}, &i18n.Message{
ID: "discardUnstagedChanges",
Other: "discard unstaged changes",
+ }, &i18n.Message{
+ ID: "discardAllChangesToAllFiles",
+ Other: "nuke working tree",
+ }, &i18n.Message{
+ ID: "discardAnyUnstagedChanges",
+ Other: "discard unstaged changes",
+ }, &i18n.Message{
+ ID: "discardUntrackedFiles",
+ Other: "discard untracked files",
+ }, &i18n.Message{
+ ID: "hardReset",
+ Other: "hard reset",
},
)
}
diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go
index 7f22e82bd..4e2a6a094 100644
--- a/pkg/i18n/english.go
+++ b/pkg/i18n/english.go
@@ -181,9 +181,6 @@ func addEnglish(i18nObject *i18n.Bundle) error {
ID: "FileNoMergeCons",
Other: "This file has no inline merge conflicts",
}, &i18n.Message{
- ID: "SureResetHardHead",
- Other: "Are you sure you want to `reset --hard HEAD` and `clean -fd`? You may lose changes",
- }, &i18n.Message{
ID: "SoftReset",
Other: "Soft reset",
}, &i18n.Message{
@@ -406,9 +403,6 @@ func addEnglish(i18nObject *i18n.Bundle) error {
ID: "NoChangedFiles",
Other: "No changed files",
}, &i18n.Message{
- ID: "ClearFilePanel",
- Other: "Clear file panel",
- }, &i18n.Message{
ID: "MergeAborted",
Other: "Merge aborted",
}, &i18n.Message{
@@ -717,6 +711,18 @@ func addEnglish(i18nObject *i18n.Bundle) error {
}, &i18n.Message{
ID: "discardUnstagedChanges",
Other: "discard unstaged changes",
+ }, &i18n.Message{
+ ID: "discardAllChangesToAllFiles",
+ Other: "nuke working tree",
+ }, &i18n.Message{
+ ID: "discardAnyUnstagedChanges",
+ Other: "discard unstaged changes",
+ }, &i18n.Message{
+ ID: "discardUntrackedFiles",
+ Other: "discard untracked files",
+ }, &i18n.Message{
+ ID: "hardReset",
+ Other: "hard reset",
},
)
}
diff --git a/pkg/i18n/polish.go b/pkg/i18n/polish.go
index b8e43059f..049c7cefa 100644
--- a/pkg/i18n/polish.go
+++ b/pkg/i18n/polish.go
@@ -147,9 +147,6 @@ func addPolish(i18nObject *i18n.Bundle) error {
ID: "FileNoMergeCons",
Other: "Ten plik nie powoduje konfliktów scalania",
}, &i18n.Message{
- ID: "SureResetHardHead",
- Other: "Jesteś pewny, że chcesz wykonać `reset --hard HEAD` i `clean -fd`? Możesz stracić wprowadzone zmiany",
- }, &i18n.Message{
ID: "SureTo",
Other: "Jesteś pewny, że chcesz {{.deleteVerb}} {{.fileName}} (stracisz swoje wprowadzone zmiany)?",
}, &i18n.Message{
@@ -333,9 +330,6 @@ func addPolish(i18nObject *i18n.Bundle) error {
ID: "CantCloseConfirmationPrompt",
Other: "Nie można zamknąć monitu potwierdzenia: {{.error}}",
}, &i18n.Message{
- ID: "ClearFilePanel",
- Other: "Wyczyść panel plików",
- }, &i18n.Message{
ID: "MergeAborted",
Other: "Scalanie anulowane",
}, &i18n.Message{
@@ -677,6 +671,18 @@ func addPolish(i18nObject *i18n.Bundle) error {
}, &i18n.Message{
ID: "discardUnstagedChanges",
Other: "discard unstaged changes",
+ }, &i18n.Message{
+ ID: "discardAllChangesToAllFiles",
+ Other: "nuke working tree",
+ }, &i18n.Message{
+ ID: "discardAnyUnstagedChanges",
+ Other: "discard unstaged changes",
+ }, &i18n.Message{
+ ID: "discardUntrackedFiles",
+ Other: "discard untracked files",
+ }, &i18n.Message{
+ ID: "hardReset",
+ Other: "hard reset",
},
)
}