From 9c6239df3dda06b94ba70787871ca074f651745f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= Date: Fri, 17 Jun 2022 21:20:37 +0200 Subject: [PATCH 1/8] Worktrees should not be filtered out But non-git directories should --- pkg/app/app.go | 2 +- pkg/gui/recent_repos_panel.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/app/app.go b/pkg/app/app.go index 9a7b1ffcc..418c1406e 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -148,7 +148,7 @@ func isGitVersionValid(versionStr string) bool { func isDirectoryAGitRepository(dir string) (bool, error) { info, err := os.Stat(filepath.Join(dir, ".git")) - return info != nil && info.IsDir(), err + return info != nil, err } func (app *App) setupRepo() (bool, error) { diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 605ae79d3..71354aac1 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -110,7 +110,7 @@ func newRecentReposList(recentRepos []string, currentRepo string) (bool, []strin newRepos := []string{currentRepo} for _, repo := range recentRepos { if repo != currentRepo { - if _, err := os.Stat(repo); err != nil { + if _, err := os.Stat(filepath.Join(repo, ".git")); err != nil { continue } newRepos = append(newRepos, repo) From e6e4513f45689f907fc8143b0ac5183ae1032bd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= Date: Fri, 17 Jun 2022 21:10:19 +0200 Subject: [PATCH 2/8] Show active branch for recent repo Split recent repo menu into three columns --- pkg/gui/recent_repos_panel.go | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 71354aac1..94161030d 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -1,24 +1,42 @@ package gui import ( + "fmt" "os" "path/filepath" + "strings" "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" "github.com/jesseduffield/lazygit/pkg/env" + "github.com/jesseduffield/lazygit/pkg/gui/presentation/icons" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" ) -func (gui *Gui) handleCreateRecentReposMenu() error { - recentRepoPaths := gui.c.GetAppState().RecentRepos +func (gui *Gui) getCurrentBranch(path string) string { + if branch, err := gui.os.Cmd.New( + fmt.Sprintf("git -C %s rev-parse --abbrev-ref HEAD", gui.os.Quote(path)), + ).DontLog().RunWithOutput(); err == nil { + return strings.Trim(branch, "\n") + } + return "" +} + +func (gui *Gui) handleCreateRecentReposMenu() error { + // we skip the first one because we're currently in it + recentRepoPaths := gui.c.GetAppState().RecentRepos[1:] + + menuItems := slices.Map(recentRepoPaths, func(path string) *types.MenuItem { + branchName, _ := currentBranches.Load(path) + if icons.IsIconEnabled() { + branchName = icons.BRANCH_ICON + " " + branchName + } - // we won't show the current repo hence the -1 - menuItems := slices.Map(recentRepoPaths[1:], func(path string) *types.MenuItem { return &types.MenuItem{ LabelColumns: []string{ filepath.Base(path), + style.FgCyan.Sprint(branchName), style.FgMagenta.Sprint(path), }, OnPress: func() error { From 7c09ce38719ddf44e775783a7dfea0f3e6d4071c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= Date: Fri, 29 Jul 2022 22:53:05 +0200 Subject: [PATCH 3/8] Parallelize fetching current branch --- pkg/gui/recent_repos_panel.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 94161030d..636c01b1e 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" "strings" + "sync" "github.com/jesseduffield/generics/slices" "github.com/jesseduffield/lazygit/pkg/commands" @@ -27,10 +28,24 @@ func (gui *Gui) handleCreateRecentReposMenu() error { // we skip the first one because we're currently in it recentRepoPaths := gui.c.GetAppState().RecentRepos[1:] + currentBranches := sync.Map{} + + wg := sync.WaitGroup{} + wg.Add(len(recentRepoPaths)) + + for _, path := range recentRepoPaths { + go func(path string) { + defer wg.Done() + currentBranches.Store(path, gui.getCurrentBranch(path)) + }(path) + } + + wg.Wait() + menuItems := slices.Map(recentRepoPaths, func(path string) *types.MenuItem { branchName, _ := currentBranches.Load(path) if icons.IsIconEnabled() { - branchName = icons.BRANCH_ICON + " " + branchName + branchName = icons.BRANCH_ICON + " " + fmt.Sprintf("%v", branchName) } return &types.MenuItem{ From 25ddac0d8fc227836f67f9a9402a32456d3ab1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= Date: Sat, 30 Jul 2022 17:28:07 +0200 Subject: [PATCH 4/8] Gotta go fast --- pkg/gui/recent_repos_panel.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 636c01b1e..6d7eacb8b 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -2,6 +2,7 @@ package gui import ( "fmt" + "io/ioutil" "os" "path/filepath" "strings" @@ -16,12 +17,14 @@ import ( ) func (gui *Gui) getCurrentBranch(path string) string { - if branch, err := gui.os.Cmd.New( - fmt.Sprintf("git -C %s rev-parse --abbrev-ref HEAD", gui.os.Quote(path)), - ).DontLog().RunWithOutput(); err == nil { - return strings.Trim(branch, "\n") + if headFile, err := ioutil.ReadFile(fmt.Sprintf("%s/.git/HEAD", path)); err == nil { + content := strings.TrimSpace(string(headFile)) + branch := strings.TrimPrefix(content, "ref: refs/heads/") + return branch } - return "" + // worktrees don't have `.git/HEAD` + // and detached HEAD repos have only a hash in `.git/HEAD` + return "HEAD" } func (gui *Gui) handleCreateRecentReposMenu() error { From 966733240c0a6b2ca2233aa260966d53915254e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= Date: Sat, 30 Jul 2022 19:02:19 +0200 Subject: [PATCH 5/8] Refactor a bit, enable worktrees --- pkg/gui/recent_repos_panel.go | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 6d7eacb8b..bfc363e76 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -17,13 +17,36 @@ import ( ) func (gui *Gui) getCurrentBranch(path string) string { - if headFile, err := ioutil.ReadFile(fmt.Sprintf("%s/.git/HEAD", path)); err == nil { - content := strings.TrimSpace(string(headFile)) - branch := strings.TrimPrefix(content, "ref: refs/heads/") - return branch + readHeadFile := func(path string) (string, error) { + headFile, err := ioutil.ReadFile(fmt.Sprintf("%s%cHEAD", path, os.PathSeparator)) + if err == nil { + content := strings.TrimSpace(string(headFile)) + branch := strings.TrimPrefix(content, "ref: refs/heads/") + return branch, nil + } + return "", err } - // worktrees don't have `.git/HEAD` - // and detached HEAD repos have only a hash in `.git/HEAD` + + gitDirPath := fmt.Sprintf("%s%c.git", path, os.PathSeparator) + + if gitDir, err := os.Stat(gitDirPath); err == nil { + if gitDir.IsDir() { + // ordinary repo + if branch, err := readHeadFile(gitDirPath); err == nil { + return branch + } + } else { + // worktree + if worktreeGitDir, err := ioutil.ReadFile(gitDirPath); err == nil { + content := strings.TrimSpace(string(worktreeGitDir)) + worktreePath := strings.TrimPrefix(content, "gitdir: ") + if branch, err := readHeadFile(worktreePath); err == nil { + return branch + } + } + } + } + return "HEAD" } From 767ef3166106d32bb60bf580f553dfa220d12391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= Date: Sun, 31 Jul 2022 08:43:31 +0200 Subject: [PATCH 6/8] Use filepath.Join instead of manual concat --- pkg/gui/recent_repos_panel.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index bfc363e76..fc2c38262 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -18,7 +18,7 @@ import ( func (gui *Gui) getCurrentBranch(path string) string { readHeadFile := func(path string) (string, error) { - headFile, err := ioutil.ReadFile(fmt.Sprintf("%s%cHEAD", path, os.PathSeparator)) + headFile, err := ioutil.ReadFile(filepath.Join(path, "HEAD")) if err == nil { content := strings.TrimSpace(string(headFile)) branch := strings.TrimPrefix(content, "ref: refs/heads/") @@ -27,7 +27,7 @@ func (gui *Gui) getCurrentBranch(path string) string { return "", err } - gitDirPath := fmt.Sprintf("%s%c.git", path, os.PathSeparator) + gitDirPath := filepath.Join(path, ".git") if gitDir, err := os.Stat(gitDirPath); err == nil { if gitDir.IsDir() { From 37bdbd9a21617be17a07e89f165492734f9dfa7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= Date: Sun, 31 Jul 2022 08:44:42 +0200 Subject: [PATCH 7/8] Display short SHA when in `detached HEAD` state --- pkg/gui/recent_repos_panel.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index fc2c38262..3ccf77bcd 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -14,6 +14,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/gui/presentation/icons" "github.com/jesseduffield/lazygit/pkg/gui/style" "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/jesseduffield/lazygit/pkg/utils" ) func (gui *Gui) getCurrentBranch(path string) string { @@ -21,8 +22,16 @@ func (gui *Gui) getCurrentBranch(path string) string { headFile, err := ioutil.ReadFile(filepath.Join(path, "HEAD")) if err == nil { content := strings.TrimSpace(string(headFile)) - branch := strings.TrimPrefix(content, "ref: refs/heads/") - return branch, nil + refsPrefix := "ref: refs/heads/" + branchDisplay := "" + if strings.HasPrefix(content, refsPrefix) { + // is a branch + branchDisplay = strings.TrimPrefix(content, refsPrefix) + } else { + // detached HEAD state, displaying short SHA + branchDisplay = utils.ShortSha(content) + } + return branchDisplay, nil } return "", err } @@ -47,7 +56,7 @@ func (gui *Gui) getCurrentBranch(path string) string { } } - return "HEAD" + return "unknown branch" } func (gui *Gui) handleCreateRecentReposMenu() error { From 44de380c2b8d7633a3c9c078f032c5822e830598 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luka=20Marku=C5=A1i=C4=87?= Date: Sun, 31 Jul 2022 08:57:57 +0200 Subject: [PATCH 8/8] Add i18n for unknown branch --- pkg/gui/recent_repos_panel.go | 2 +- pkg/i18n/english.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/gui/recent_repos_panel.go b/pkg/gui/recent_repos_panel.go index 3ccf77bcd..3b817fbca 100644 --- a/pkg/gui/recent_repos_panel.go +++ b/pkg/gui/recent_repos_panel.go @@ -56,7 +56,7 @@ func (gui *Gui) getCurrentBranch(path string) string { } } - return "unknown branch" + return gui.c.Tr.LcBranchUnknown } func (gui *Gui) handleCreateRecentReposMenu() error { diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index af5a8a99b..18d64016b 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -409,6 +409,7 @@ type TranslationSet struct { NoFilesStagedPrompt string BranchNotFoundTitle string BranchNotFoundPrompt string + LcBranchUnknown string UnstageLinesTitle string UnstageLinesPrompt string LcCreateNewBranchFromCommit string @@ -1045,6 +1046,7 @@ func EnglishTranslationSet() TranslationSet { NoFilesStagedPrompt: "You have not staged any files. Commit all files?", BranchNotFoundTitle: "Branch not found", BranchNotFoundPrompt: "Branch not found. Create a new branch named", + LcBranchUnknown: "branch unknown", UnstageLinesTitle: "Unstage lines", UnstageLinesPrompt: "Are you sure you want to delete the selected lines (git reset)? It is irreversible.\nTo disable this dialogue set the config key of 'gui.skipUnstageLineWarning' to true", LcCreateNewBranchFromCommit: "create new branch off of commit",