summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2018-08-11 15:50:42 +1000
committerGitHub <noreply@github.com>2018-08-11 15:50:42 +1000
commitaec125df7042dd88ad402a819ab1285031250474 (patch)
treea0590e78eb5d0c12ebde0a7fc012e2c6e2d985f9
parentbf9a53fada5b4d72f3e3b0a8877ab845867137df (diff)
parent9626ebdf3577090cff24fab82880fe9d330adb59 (diff)
Merge branch 'master' into add-void-readme
-rw-r--r--.gitignore1
-rw-r--r--Gopkg.lock19
-rw-r--r--Gopkg.toml4
-rw-r--r--README.md19
-rw-r--r--branch.go35
-rw-r--r--branch_list_builder.go123
-rw-r--r--branches_panel.go19
-rw-r--r--commit_message_panel.go45
-rw-r--r--commits_panel.go40
-rw-r--r--confirmation_panel.go18
-rw-r--r--docs/Keybindings.md1
-rw-r--r--files_panel.go22
-rw-r--r--gitcommands.go205
-rw-r--r--gui.go21
-rw-r--r--keybindings.go111
-rw-r--r--main.go14
-rw-r--r--merge_panel.go2
-rwxr-xr-xscripts/push_new_patch.go (renamed from bin/push_new_patch.go)0
-rw-r--r--status_panel.go10
-rwxr-xr-xtest/lots_of_commits.sh30
-rwxr-xr-xtest/merge_conflict.sh (renamed from test/generate_basic_repo.sh)2
-rwxr-xr-xtest/unicode_characters.sh35
-rw-r--r--utils.go54
-rw-r--r--vendor/github.com/davecgh/go-spew/LICENSE15
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/bypass.go152
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/bypasssafe.go38
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/common.go341
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/config.go306
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/doc.go211
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/dump.go509
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/format.go419
-rw-r--r--vendor/github.com/davecgh/go-spew/spew/spew.go148
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_darwin.go32
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_freebsd.go8
-rw-r--r--vendor/golang.org/x/sys/unix/syscall_linux.go9
-rw-r--r--vendor/golang.org/x/sys/unix/types_freebsd.go2
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux_386.go3
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go3
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux_arm.go3
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go3
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux_mips.go3
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go3
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go3
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go3
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go3
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go3
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go3
-rw-r--r--vendor/golang.org/x/sys/unix/zerrors_openbsd_amd64.go1
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_darwin_386.go57
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go57
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_darwin_arm.go57
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go57
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_linux_386.go95
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go95
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go95
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go95
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go95
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go95
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go95
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go95
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go95
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go95
-rw-r--r--vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go95
-rw-r--r--vendor/golang.org/x/sys/unix/zsysnum_openbsd_amd64.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_freebsd_386.go2
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_freebsd_amd64.go2
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_freebsd_arm.go2
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux_386.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux_arm.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux_mips.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go1
-rw-r--r--vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go1
-rw-r--r--vendor/gopkg.in/src-d/go-git.v4/plumbing/object/commit.go31
-rw-r--r--vendor/gopkg.in/src-d/go-git.v4/plumbing/object/tree.go5
-rw-r--r--vendor/gopkg.in/src-d/go-git.v4/plumbing/transport/internal/common/common.go5
-rw-r--r--vendor/gopkg.in/src-d/go-git.v4/repository.go8
-rw-r--r--view_helpers.go36
83 files changed, 4115 insertions, 315 deletions
diff --git a/.gitignore b/.gitignore
index 5210291e4..4a37f6ec0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,4 @@ extra/lgit.rb
notes/go.notes
TODO.notes
TODO.md
+test/testrepo/
diff --git a/Gopkg.lock b/Gopkg.lock
index c2689a1ff..4323983be 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -2,6 +2,14 @@
[[projects]]
+ digest = "1:a2c1d0e43bd3baaa071d1b9ed72c27d78169b2b269f71c105ac4ba34b1be4a39"
+ name = "github.com/davecgh/go-spew"
+ packages = ["spew"]
+ pruneopts = "NUT"
+ revision = "346938d642f2ec3594ed81d874461961cd0faa76"
+ version = "v1.1.0"
+
+[[projects]]
digest = "1:de4a74b504df31145ffa8ca0c4edbffa2f3eb7f466753962184611b618fa5981"
name = "github.com/emirpasic/gods"
packages = [
@@ -176,14 +184,14 @@
[[projects]]
branch = "master"
- digest = "1:de22999d08e1604a7c3186ef64b5a18a90e399b99c4e8ff2a8d6c6abf42b7934"
+ digest = "1:87aef4c266c820591e859450c3ee5ab98f9b8755d7cfd9e4db606959eb5b483d"
name = "golang.org/x/sys"
packages = [
"unix",
"windows",
]
pruneopts = "NUT"
- revision = "0ffbfd41fbef8ffcf9b62b0b0aa3a5873ed7a4fe"
+ revision = "904bdc257025c7b3f43c19360ad3ab85783fad78"
[[projects]]
digest = "1:8029e9743749d4be5bc9f7d42ea1659471767860f0cdc34d37c3111bd308a295"
@@ -215,7 +223,7 @@
version = "v4.2.0"
[[projects]]
- digest = "1:fa265385a5175b4aaed0cccec60059a3f363c3f209bba1b658e9a12baddbc5e0"
+ digest = "1:e66078da2bd6e53c72518d7f6ae0c3c8c7f34c0df12c39435ce34a6bce165525"
name = "gopkg.in/src-d/go-git.v4"
packages = [
".",
@@ -260,8 +268,7 @@
"utils/merkletrie/noder",
]
pruneopts = "NUT"
- revision = "3bd5e82b2512d85becae9677fa06b5a973fd4cfb"
- version = "v4.5.0"
+ revision = "43d17e14b714665ab5bc2ecc220b6740779d733f"
[[projects]]
digest = "1:b233ad4ec87ac916e7bf5e678e98a2cb9e8b52f6de6ad3e11834fc7a71b8e3bf"
@@ -275,11 +282,13 @@
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
+ "github.com/davecgh/go-spew/spew",
"github.com/fatih/color",
"github.com/golang-collections/collections/stack",
"github.com/jesseduffield/gocui",
"github.com/tcnksm/go-gitconfig",
"gopkg.in/src-d/go-git.v4",
+ "gopkg.in/src-d/go-git.v4/plumbing",
"gopkg.in/src-d/go-git.v4/plumbing/object",
]
solver-name = "gps-cdcl"
diff --git a/Gopkg.toml b/Gopkg.toml
index 308fea11f..a47fe5e93 100644
--- a/Gopkg.toml
+++ b/Gopkg.toml
@@ -36,3 +36,7 @@
[[constraint]]
branch = "master"
name = "github.com/jesseduffield/gocui"
+
+[[constraint]]
+ name = "gopkg.in/src-d/go-git.v4"
+ revision = "43d17e14b714665ab5bc2ecc220b6740779d733f"
diff --git a/README.md b/README.md
index c95a79dda..91e264296 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,8 @@ Are YOU tired of typing every git command directly into the terminal, but you're
![Gif](https://image.ibb.co/mmeXho/optimisedgif.gif)
+[Twitch Stream](https://www.twitch.tv/jesseduffield)
+
## Installation
### Homebrew
@@ -36,6 +38,20 @@ They follow upstream latest releases
sudo xbps-install -S lazygit
```
+### Arch Linux
+Packages for Arch Linux are available via AUR (Arch User Repository).
+
+There are two packages. The stable one which is built with the latest release and the git version which builds from the most recent commit.
+
+Stable:
+https://aur.archlinux.org/packages/lazygit/
+
+Development:
+https://aur.archlinux.org/packages/lazygit-git/
+
+Instruction of how to install AUR content can be found here:
+https://wiki.archlinux.org/index.php/Arch_User_Repository
+
### Binary Release (Windows/Linux/OSX)
You can download a binary release [here](https://github.com/jesseduffield/lazygit/releases)
@@ -83,3 +99,6 @@ We love your input! Please check out the [contributing guide](CONTRIBUTING.md).
## Work in progress
This is still a work in progress so there's still bugs to iron out and as this is my first project in Go the code could no doubt use an increase in quality, but I'll be improving on it whenever I find the time. If you have any feedback feel free to [raise an issue](https://github.com/jesseduffield/lazygit/issues)/[submit a PR](https://github.com/jesseduffield/lazygit/pulls).
+
+## Social
+If you want to see what I (Jesse) am up to in terms of development, follow me on [twitter](https://twitter.com/DuffieldJesse) or watch me program on [twitch](https://www.twitch.tv/jesseduffield)
diff --git a/branch.go b/branch.go
new file mode 100644
index 000000000..78c2e55aa
--- /dev/null
+++ b/branch.go
@@ -0,0 +1,35 @@
+package main
+
+import (
+ "strings"
+
+ "github.com/fatih/color"
+)
+
+// Branch : A git branch
+type Branch struct {
+ Name string
+ Recency string
+}
+
+func (b *Branch) getDisplayString() string {
+ return withPadding(b.Recency, 4) + coloredString(b.Name, b.getColor())
+}
+
+func (b *Branch) getColor() color.Attribute {
+ switch b.getType() {
+ case "feature":
+ return color.FgGreen
+ case "bugfix":
+ return color.FgYellow
+ case "hotfix":
+ return color.FgRed
+ default:
+ return color.FgWhite
+ }
+}
+
+// expected to return feature/bugfix/hotfix or blank string
+func (b *Branch) getType() string {
+ return strings.Split(b.Name, "/")[0]
+}
diff --git a/branch_list_builder.go b/branch_list_builder.go
new file mode 100644
index 000000000..113a5a44a
--- /dev/null
+++ b/branch_list_builder.go
@@ -0,0 +1,123 @@
+package main
+
+import (
+ "regexp"
+ "strings"
+
+ "gopkg.in/src-d/go-git.v4/plumbing"
+)
+
+// context:
+// we want to only show 'safe' branches (ones that haven't e.g. been deleted)
+// which `git branch -a` gives us, but we also want the recency data that
+// git reflog gives us.
+// So we get the HEAD, then append get the reflog branches that intersect with
+// our safe branches, then add the remaining safe branches, ensuring uniqueness
+// along the way
+
+type branchListBuilder struct{}
+
+func newBranchListBuilder() *branchListBuilder {
+ return &branchListBuilder{}
+}
+
+func (b *branchListBuilder) obtainCurrentBranch() Branch {
+ // I used go-git for this, but that breaks if you've just done a git init,
+ // even though you're on 'master'
+ branchName, _ := runDirectCommand("git symbolic-ref --short HEAD")
+ return Branch{Name: strings.TrimSpace(branchName), Recency: " *"}
+}
+
+func (*branchListBuilder) obtainReflogBranches() []Branch {
+ branches := make([]Branch, 0)
+ rawString, err := runDirectCommand("git reflog -n100 --pretty='%cr|%gs' --grep-reflog='checkout: moving' HEAD")
+ if err != nil {
+ return branches
+ }
+
+ branchLines := splitLines(rawString)
+ for _, line := range branchLines {
+ timeNumber, timeUnit, branchName := branchInfoFromLine(line)
+ timeUnit = abbreviatedTimeUnit(timeUnit)
+ branch := Branch{Name: branchName, Recency: timeNumber + timeUnit}
+ branches = append(branches, branch)
+ }
+ return branches
+}
+
+func (b *branchListBuilder) obtainSafeBranches() []Branch {
+ branches := make([]Branch, 0)
+
+ bIter, err := r.Branches()
+ if err != nil {
+ panic(err)
+ }
+ err = bIter.ForEach(func(b *plumbing.Reference) error {
+ name := b.Name().Short()
+ branches = append(branches, Branch{Name: name})
+ return nil
+ })
+
+ return branches
+}
+
+func (b *branchListBuilder) appendNewBranches(finalBranches, newBranches, existingBranches []Branch, included bool) []Branch {
+ for _, newBranch := range newBranches {
+ if included == branchIncluded(newBranch.Name, existingBranches) {
+ finalBranches = append(finalBranches, newBranch)
+ }
+
+ }
+ return finalBranches
+}
+
+func (b *branchListBuilder) build() []Branch {
+ branches := make([]Branch, 0)
+ head := b.obtainCurrentBranch()
+ safeBranches := b.obtainSafeBranches()
+ if len(safeBranches) == 0 {
+ return append(branches, head)
+ }
+ reflogBranches := b.obtainReflogBranches()
+ reflogBranches = uniqueByName(append([]Branch{head}, reflogBranches...))
+
+ branches = b.appendNewBranches(branches, reflogBranches, safeBranches, true)
+ branches = b.appendNewBranches(branches, safeBranches, branches, false)
+
+ return branches
+}
+
+func uniqueByName(branches []Branch) []Branch {
+ finalBranches := make([]Branch, 0)
+ for _, branch := range branches {
+ if branchIncluded(branch.Name, finalBranches) {
+ continue
+ }
+ finalBranches = append(finalBranches, branch)
+ }
+ return finalBranches
+}
+
+// A line will have the form '10 days ago master' so we need to strip out the
+// useful information from that into timeNumber, timeUnit, and branchName
+func branchInfoFromLine(line string) (string, string, string) {
+ r := regexp.MustCompile("\\|.*\\s")
+ line = r.ReplaceAllString(line, " ")
+ words := strings.Split(line, " ")
+ return words[0], words[1], words[3]
+}
+
+func abbreviatedTimeUnit(timeUnit string) string {
+ r := regexp.MustCompile("s$")
+ timeUnit = r.ReplaceAllString(timeUnit, "")
+ timeUnitMap := map[string]string{
+ "hour": "h",
+ "minute": "m",
+ "second": "s",
+ "week": "w",
+ "year": "y",
+ "day": "d",
+ "month": "m",
+ }
+ return timeUnitMap[timeUnit]
+}
diff --git a/branches_panel.go b/branches_panel.go
index 0b8508a3d..a73d28bb3 100644
--- a/branches_panel.go
+++ b/branches_panel.go
@@ -51,6 +51,20 @@ func handleNewBranch(g *gocui.Gui, v *gocui.View) error {
return nil
}
+func handleDeleteBranch(g *gocui.Gui, v *gocui.View) error {
+ checkedOutBranch := state.Branches[0]
+ selectedBranch := getSelectedBranch(v)
+ if checkedOutBranch.Name == selectedBranch.Name {
+ return createErrorPanel(g, "You cannot delete the checked out branch!")
+ }
+ return createConfirmationPanel(g, v, "Delete Branch", "Are you sure you want delete the branch "+selectedBranch.Name+" ?", func(g *gocui.Gui, v *gocui.View) error {
+ if output, err := gitDeleteBranch(selectedBranch.Name); err != nil {
+ return createErrorPanel(g, output)
+ }
+ return refreshSidePanels(g)
+ }, nil)
+}
+
func handleMerge(g *gocui.Gui, v *gocui.View) error {
checkedOutBranch := state.Branches[0]
selectedBranch := getSelectedBranch(v)
@@ -76,6 +90,7 @@ func renderBranchesOptions(g *gocui.Gui) error {
"m": "merge",
"c": "checkout by name",
"n": "new branch",
+ "d": "delete branch",
"← → ↑ ↓": "navigate",
})
}
@@ -91,7 +106,7 @@ func handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
}
go func() {
branch := getSelectedBranch(v)
- diff, err := getBranchGraph(branch.Name, branch.BaseBranch)
+ diff, err := getBranchGraph(branch.Name)