Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8288de0c84 | ||
|
|
1da2afd450 | ||
|
|
03de51747e | ||
|
|
3d698cd7c1 | ||
|
|
a48cc245e7 | ||
|
|
9ed3a8ee05 | ||
|
|
64daf1310d | ||
|
|
e5ba0d9d9c | ||
|
|
50e4e9d58d | ||
|
|
03b9db5e0a | ||
|
|
043cb2ea44 | ||
|
|
a62d70fbd5 | ||
|
|
053e80a08e |
@@ -2,7 +2,7 @@
|
||||
|
||||
Default path for the config file:
|
||||
|
||||
* Linux: `~/.config/jesseduffield/lazygit/config.yml`
|
||||
* Linux: `~/.config/lazygit/config.yml`
|
||||
* MacOS: `~/Library/Application Support/jesseduffield/lazygit/config.yml`
|
||||
* Windows: `%APPDATA%\jesseduffield\lazygit\config.yml`
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package commands
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/jesseduffield/lazygit/pkg/commands/models"
|
||||
@@ -25,7 +24,7 @@ func (c *GitCommand) Commit(message string, flags string) (*exec.Cmd, error) {
|
||||
splitMessage := strings.Split(message, "\n")
|
||||
lineArgs := ""
|
||||
for _, line := range splitMessage {
|
||||
lineArgs += fmt.Sprintf(" -m %s", strconv.Quote(line))
|
||||
lineArgs += fmt.Sprintf(" -m %s", c.OSCommand.Quote(line))
|
||||
}
|
||||
|
||||
command := fmt.Sprintf("git commit %s%s", flags, lineArgs)
|
||||
|
||||
@@ -22,7 +22,7 @@ func (c *GitCommand) CatFile(fileName string) (string, error) {
|
||||
func (c *GitCommand) StageFile(fileName string) error {
|
||||
// renamed files look like "file1 -> file2"
|
||||
fileNames := strings.Split(fileName, " -> ")
|
||||
return c.OSCommand.RunCommand("git add %s", c.OSCommand.Quote(fileNames[len(fileNames)-1]))
|
||||
return c.OSCommand.RunCommand("git add -- %s", c.OSCommand.Quote(fileNames[len(fileNames)-1]))
|
||||
}
|
||||
|
||||
// StageAll stages all files
|
||||
@@ -37,9 +37,9 @@ func (c *GitCommand) UnstageAll() error {
|
||||
|
||||
// UnStageFile unstages a file
|
||||
func (c *GitCommand) UnStageFile(fileName string, tracked bool) error {
|
||||
command := "git rm --cached --force %s"
|
||||
command := "git rm --cached --force -- %s"
|
||||
if tracked {
|
||||
command = "git reset HEAD %s"
|
||||
command = "git reset HEAD -- %s"
|
||||
}
|
||||
|
||||
// renamed files look like "file1 -> file2"
|
||||
@@ -149,7 +149,7 @@ func (c *GitCommand) WorktreeFileDiffCmdStr(file *models.File, plain bool, cache
|
||||
cachedArg = "--cached"
|
||||
}
|
||||
if !file.Tracked && !file.HasStagedChanges && !cached {
|
||||
trackedArg = "--no-index /dev/null"
|
||||
trackedArg = "--no-index -- /dev/null"
|
||||
}
|
||||
if plain {
|
||||
colorArg = "never"
|
||||
|
||||
@@ -1037,7 +1037,7 @@ func TestGitCommandStageFile(t *testing.T) {
|
||||
gitCmd := NewDummyGitCommand()
|
||||
gitCmd.OSCommand.Command = func(cmd string, args ...string) *exec.Cmd {
|
||||
assert.EqualValues(t, "git", cmd)
|
||||
assert.EqualValues(t, []string{"add", "test.txt"}, args)
|
||||
assert.EqualValues(t, []string{"add", "--", "test.txt"}, args)
|
||||
|
||||
return secureexec.Command("echo")
|
||||
}
|
||||
@@ -1059,7 +1059,7 @@ func TestGitCommandUnstageFile(t *testing.T) {
|
||||
"Remove an untracked file from staging",
|
||||
func(cmd string, args ...string) *exec.Cmd {
|
||||
assert.EqualValues(t, "git", cmd)
|
||||
assert.EqualValues(t, []string{"rm", "--cached", "--force", "test.txt"}, args)
|
||||
assert.EqualValues(t, []string{"rm", "--cached", "--force", "--", "test.txt"}, args)
|
||||
|
||||
return secureexec.Command("echo")
|
||||
},
|
||||
@@ -1072,7 +1072,7 @@ func TestGitCommandUnstageFile(t *testing.T) {
|
||||
"Remove a tracked file from staging",
|
||||
func(cmd string, args ...string) *exec.Cmd {
|
||||
assert.EqualValues(t, "git", cmd)
|
||||
assert.EqualValues(t, []string{"reset", "HEAD", "test.txt"}, args)
|
||||
assert.EqualValues(t, []string{"reset", "HEAD", "--", "test.txt"}, args)
|
||||
|
||||
return secureexec.Command("echo")
|
||||
},
|
||||
@@ -1455,7 +1455,7 @@ func TestGitCommandDiff(t *testing.T) {
|
||||
"File not tracked and file has no staged changes",
|
||||
func(cmd string, args ...string) *exec.Cmd {
|
||||
assert.EqualValues(t, "git", cmd)
|
||||
assert.EqualValues(t, []string{"diff", "--submodule", "--no-ext-diff", "--color=always", "--no-index", "/dev/null", "test.txt"}, args)
|
||||
assert.EqualValues(t, []string{"diff", "--submodule", "--no-ext-diff", "--color=always", "--no-index", "--", "/dev/null", "test.txt"}, args)
|
||||
|
||||
return secureexec.Command("echo")
|
||||
},
|
||||
|
||||
@@ -14,7 +14,7 @@ func (c *GitCommand) GetFilesInDiff(from string, to string, reverse bool, patchM
|
||||
reverseFlag = " -R "
|
||||
}
|
||||
|
||||
filenames, err := c.OSCommand.RunCommandWithOutput("git diff --submodule --no-ext-diff --name-status %s %s %s", reverseFlag, from, to)
|
||||
filenames, err := c.OSCommand.RunCommandWithOutput("git diff --submodule --no-ext-diff --name-status -z %s %s %s", reverseFlag, from, to)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -26,13 +26,12 @@ func (c *GitCommand) GetFilesInDiff(from string, to string, reverse bool, patchM
|
||||
func (c *GitCommand) getCommitFilesFromFilenames(filenames string, parent string, patchManager *patch.PatchManager) []*models.CommitFile {
|
||||
commitFiles := make([]*models.CommitFile, 0)
|
||||
|
||||
for _, line := range strings.Split(strings.TrimRight(filenames, "\n"), "\n") {
|
||||
lines := strings.Split(strings.TrimRight(filenames, "\x00"), "\x00")
|
||||
n := len(lines)
|
||||
for i := 0; i < n-1; i += 2 {
|
||||
// typical result looks like 'A my_file' meaning my_file was added
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
changeStatus := line[0:1]
|
||||
name := line[2:]
|
||||
changeStatus := lines[i]
|
||||
name := lines[i+1]
|
||||
status := patch.UNSELECTED
|
||||
if patchManager != nil && patchManager.To == parent {
|
||||
status = patchManager.GetFileStatus(name)
|
||||
|
||||
@@ -37,7 +37,7 @@ func (c *GitCommand) GetStatusFiles(opts GetStatusFileOptions) []*models.File {
|
||||
change := statusString[0:2]
|
||||
stagedChange := change[0:1]
|
||||
unstagedChange := statusString[1:2]
|
||||
filename := c.OSCommand.Unquote(statusString[3:])
|
||||
filename := statusString[3:]
|
||||
untracked := utils.IncludesString([]string{"??", "A ", "AM"}, change)
|
||||
hasNoStagedChanges := utils.IncludesString([]string{" ", "U", "?"}, stagedChange)
|
||||
hasMergeConflicts := utils.IncludesString([]string{"DD", "AA", "UU", "AU", "UA", "UD", "DU"}, change)
|
||||
@@ -72,7 +72,13 @@ func (c *GitCommand) GitStatus(opts GitStatusOptions) (string, error) {
|
||||
noRenamesFlag = "--no-renames"
|
||||
}
|
||||
|
||||
return c.OSCommand.RunCommandWithOutput("git status %s --porcelain %s", opts.UntrackedFilesArg, noRenamesFlag)
|
||||
statusLines, err := c.OSCommand.RunCommandWithOutput("git status %s --porcelain -z %s", opts.UntrackedFilesArg, noRenamesFlag)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
statusLines = strings.Replace(statusLines, "\x00", "\n", -1)
|
||||
return statusLines, nil
|
||||
}
|
||||
|
||||
// MergeStatusFiles merge status files
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@@ -24,14 +23,13 @@ import (
|
||||
|
||||
// Platform stores the os state
|
||||
type Platform struct {
|
||||
OS string
|
||||
CatCmd string
|
||||
Shell string
|
||||
ShellArg string
|
||||
EscapedQuote string
|
||||
OpenCommand string
|
||||
OpenLinkCommand string
|
||||
FallbackEscapedQuote string
|
||||
OS string
|
||||
CatCmd string
|
||||
Shell string
|
||||
ShellArg string
|
||||
EscapedQuote string
|
||||
OpenCommand string
|
||||
OpenLinkCommand string
|
||||
}
|
||||
|
||||
// OSCommand holds all the os commands
|
||||
@@ -129,7 +127,7 @@ func (c *OSCommand) ShellCommandFromString(commandStr string) *exec.Cmd {
|
||||
if c.Platform.OS == "windows" {
|
||||
quotedCommand = commandStr
|
||||
} else {
|
||||
quotedCommand = strconv.Quote(commandStr)
|
||||
quotedCommand = c.Quote(commandStr)
|
||||
}
|
||||
|
||||
shellCommand := fmt.Sprintf("%s %s %s", c.Platform.Shell, c.Platform.ShellArg, quotedCommand)
|
||||
@@ -245,20 +243,19 @@ func (c *OSCommand) PrepareSubProcess(cmdName string, commandArgs ...string) *ex
|
||||
|
||||
// Quote wraps a message in platform-specific quotation marks
|
||||
func (c *OSCommand) Quote(message string) string {
|
||||
message = strings.Replace(message, "`", "\\`", -1)
|
||||
escapedQuote := c.Platform.EscapedQuote
|
||||
if strings.Contains(message, c.Platform.EscapedQuote) {
|
||||
escapedQuote = c.Platform.FallbackEscapedQuote
|
||||
if c.Platform.OS == "windows" {
|
||||
message = strings.Replace(message, `"`, `"'"'"`, -1)
|
||||
message = strings.Replace(message, `\"`, `\\"`, -1)
|
||||
} else {
|
||||
message = strings.Replace(message, `\`, `\\`, -1)
|
||||
message = strings.Replace(message, `"`, `\"`, -1)
|
||||
message = strings.Replace(message, "`", "\\`", -1)
|
||||
message = strings.Replace(message, "$", "\\$", -1)
|
||||
}
|
||||
escapedQuote := c.Platform.EscapedQuote
|
||||
return escapedQuote + message + escapedQuote
|
||||
}
|
||||
|
||||
// Unquote removes wrapping quotations marks if they are present
|
||||
// this is needed for removing quotes from staged filenames with spaces
|
||||
func (c *OSCommand) Unquote(message string) string {
|
||||
return strings.Replace(message, `"`, "", -1)
|
||||
}
|
||||
|
||||
// AppendLineToFile adds a new line in file
|
||||
func (c *OSCommand) AppendLineToFile(filename, line string) error {
|
||||
f, err := os.OpenFile(filename, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||
|
||||
@@ -8,13 +8,12 @@ import (
|
||||
|
||||
func getPlatform() *Platform {
|
||||
return &Platform{
|
||||
OS: runtime.GOOS,
|
||||
CatCmd: "cat",
|
||||
Shell: "bash",
|
||||
ShellArg: "-c",
|
||||
EscapedQuote: "'",
|
||||
OpenCommand: "open {{filename}}",
|
||||
OpenLinkCommand: "open {{link}}",
|
||||
FallbackEscapedQuote: "\"",
|
||||
OS: runtime.GOOS,
|
||||
CatCmd: "cat",
|
||||
Shell: "bash",
|
||||
ShellArg: "-c",
|
||||
EscapedQuote: `"`,
|
||||
OpenCommand: "open {{filename}}",
|
||||
OpenLinkCommand: "open {{link}}",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,6 +114,8 @@ func TestOSCommandOpenFile(t *testing.T) {
|
||||
func TestOSCommandQuote(t *testing.T) {
|
||||
osCommand := NewDummyOSCommand()
|
||||
|
||||
osCommand.Platform.OS = "linux"
|
||||
|
||||
actual := osCommand.Quote("hello `test`")
|
||||
|
||||
expected := osCommand.Platform.EscapedQuote + "hello \\`test\\`" + osCommand.Platform.EscapedQuote
|
||||
@@ -129,7 +131,7 @@ func TestOSCommandQuoteSingleQuote(t *testing.T) {
|
||||
|
||||
actual := osCommand.Quote("hello 'test'")
|
||||
|
||||
expected := osCommand.Platform.FallbackEscapedQuote + "hello 'test'" + osCommand.Platform.FallbackEscapedQuote
|
||||
expected := osCommand.Platform.EscapedQuote + "hello 'test'" + osCommand.Platform.EscapedQuote
|
||||
|
||||
assert.EqualValues(t, expected, actual)
|
||||
}
|
||||
@@ -142,18 +144,20 @@ func TestOSCommandQuoteDoubleQuote(t *testing.T) {
|
||||
|
||||
actual := osCommand.Quote(`hello "test"`)
|
||||
|
||||
expected := osCommand.Platform.EscapedQuote + "hello \"test\"" + osCommand.Platform.EscapedQuote
|
||||
expected := osCommand.Platform.EscapedQuote + `hello \"test\"` + osCommand.Platform.EscapedQuote
|
||||
|
||||
assert.EqualValues(t, expected, actual)
|
||||
}
|
||||
|
||||
// TestOSCommandUnquote is a function.
|
||||
func TestOSCommandUnquote(t *testing.T) {
|
||||
// TestOSCommandQuoteWindows tests the quote function for Windows
|
||||
func TestOSCommandQuoteWindows(t *testing.T) {
|
||||
osCommand := NewDummyOSCommand()
|
||||
|
||||
actual := osCommand.Unquote(`hello "test"`)
|
||||
osCommand.Platform.OS = "windows"
|
||||
|
||||
expected := "hello test"
|
||||
actual := osCommand.Quote(`hello "test"`)
|
||||
|
||||
expected := osCommand.Platform.EscapedQuote + `hello "'"'"test"'"'"` + osCommand.Platform.EscapedQuote
|
||||
|
||||
assert.EqualValues(t, expected, actual)
|
||||
}
|
||||
|
||||
@@ -2,11 +2,10 @@ package oscommands
|
||||
|
||||
func getPlatform() *Platform {
|
||||
return &Platform{
|
||||
OS: "windows",
|
||||
CatCmd: "cmd /c type",
|
||||
Shell: "cmd",
|
||||
ShellArg: "/c",
|
||||
EscapedQuote: `\"`,
|
||||
FallbackEscapedQuote: "\\'",
|
||||
OS: "windows",
|
||||
CatCmd: "cmd /c type",
|
||||
Shell: "cmd",
|
||||
ShellArg: "/c",
|
||||
EscapedQuote: `\"`,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ type AppConfigurer interface {
|
||||
SaveAppState() error
|
||||
SetIsNewRepo(bool)
|
||||
GetIsNewRepo() bool
|
||||
ReloadUserConfig() error
|
||||
}
|
||||
|
||||
// NewAppConfig makes a new app config
|
||||
@@ -203,6 +204,16 @@ func (c *AppConfig) GetUserConfigDir() string {
|
||||
return c.UserConfigDir
|
||||
}
|
||||
|
||||
func (c *AppConfig) ReloadUserConfig() error {
|
||||
userConfig, err := loadUserConfigWithDefaults(c.UserConfigDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.UserConfig = userConfig
|
||||
return nil
|
||||
}
|
||||
|
||||
func configFilePath(filename string) (string, error) {
|
||||
folder, err := findOrCreateConfigDir()
|
||||
if err != nil {
|
||||
|
||||
@@ -550,5 +550,5 @@ func (gui *Gui) findBranchNameSuggestions(input string) []*types.Suggestion {
|
||||
// sanitizedBranchName will remove all spaces in favor of a dash "-" to meet
|
||||
// git's branch naming requirement.
|
||||
func sanitizedBranchName(input string) string {
|
||||
return strings.ReplaceAll(input, " ", "-")
|
||||
return strings.Replace(input, " ", "-", -1)
|
||||
}
|
||||
|
||||
@@ -464,6 +464,9 @@ func (gui *Gui) Run() error {
|
||||
}
|
||||
|
||||
g.OnSearchEscape = gui.onSearchEscape
|
||||
if err := gui.Config.ReloadUserConfig(); err != nil {
|
||||
return nil
|
||||
}
|
||||
userConfig := gui.Config.GetUserConfig()
|
||||
g.SearchEscapeKey = gui.getKey(userConfig.Keybinding.Universal.Return)
|
||||
g.NextSearchMatchKey = gui.getKey(userConfig.Keybinding.Universal.NextMatch)
|
||||
|
||||
@@ -303,8 +303,8 @@ func dutchTranslationSet() TranslationSet {
|
||||
LcAddNewRemote: `voeg een nieuwe remote toe`,
|
||||
LcNewRemoteName: `Nieuwe remote name:`,
|
||||
LcNewRemoteUrl: `Nieuwe remote url:`,
|
||||
LcEditRemoteName: `Enter updated remote naam voor {{ .remoteName }}:`,
|
||||
LcEditRemoteUrl: `Enter updated remote url voor {{ .remoteName }}:`,
|
||||
LcEditRemoteName: `Enter updated remote naam voor {{.remoteName}}:`,
|
||||
LcEditRemoteUrl: `Enter updated remote url voor {{.remoteName}}:`,
|
||||
LcRemoveRemote: `verwijder remote`,
|
||||
LcRemoveRemotePrompt: "Weet je zeker dat je deze remote wilt verwijderen",
|
||||
DeleteRemoteBranch: "Verwijder Remote Branch",
|
||||
|
||||
@@ -437,7 +437,34 @@ type TranslationSet struct {
|
||||
LcCopiedToClipboard string
|
||||
}
|
||||
|
||||
const englishReleaseNotes = `## lazygit 0.24 Release Notes
|
||||
const englishReleaseNotes = `## lazygit 0.26 Release Notes
|
||||
|
||||
- Config changes applied after editing from within lazygit, no reload required.
|
||||
|
||||
- LOTS of fixes for rendering filenames with strange characters, escaped
|
||||
characters, and UI fixes, by the amazing @Ryooooooga!
|
||||
|
||||
- Also thanks to @Isti115
|
||||
|
||||
## lazygit 0.25 Release Notes
|
||||
|
||||
- Fixes for windows, thanks @murphy66!
|
||||
|
||||
- Allow mapping spaces to dashes when creating a branch, thanks @caquillo07!
|
||||
|
||||
- Allow configuring file refresh and fetch frequency, thanks @Liberatys!
|
||||
|
||||
- Minor security improvement
|
||||
|
||||
- Wide characters supported when entering commit messages, thanks @Ryooooooga!
|
||||
|
||||
- Original branch name appears when renaming, thanks piresrui!
|
||||
|
||||
- Better menus, thanks @1jz!
|
||||
|
||||
- Also thanks to @snipem, @dbast, and @dawidd6
|
||||
|
||||
## lazygit 0.24 Release Notes
|
||||
|
||||
- Suggestions now shown when checking out branch by name
|
||||
|
||||
@@ -844,8 +871,8 @@ func englishTranslationSet() TranslationSet {
|
||||
LcAddNewRemote: `add new remote`,
|
||||
LcNewRemoteName: `New remote name:`,
|
||||
LcNewRemoteUrl: `New remote url:`,
|
||||
LcEditRemoteName: `Enter updated remote name for {{ .remoteName }}:`,
|
||||
LcEditRemoteUrl: `Enter updated remote url for {{ .remoteName }}:`,
|
||||
LcEditRemoteName: `Enter updated remote name for {{.remoteName}}:`,
|
||||
LcEditRemoteUrl: `Enter updated remote url for {{.remoteName}}:`,
|
||||
LcRemoveRemote: `remove remote`,
|
||||
LcRemoveRemotePrompt: "Are you sure you want to remove remote",
|
||||
DeleteRemoteBranch: "Delete Remote Branch",
|
||||
|
||||
Reference in New Issue
Block a user