Compare commits

...
19 Commits
Author SHA1 Message Date
Jesse Duffield 0227b93409 fix branch parser 2020-03-18 23:26:02 +11:00
Jesse Duffield b0ec0821d5 fix docs 2020-03-18 22:50:35 +11:00
hitsuji_no_shippo 13a7806cac add opne menu keybindings in docs 2020-03-18 22:50:35 +11:00
hitsuji_no_shippo 41c76fb748 add close menu keybindings in docs 2020-03-18 22:50:35 +11:00
hitsuji_no_shippo ac0c3b9f92 fix search keybindings in docs 2020-03-18 22:50:35 +11:00
Jesse Duffield 1be0ff8da7 better upstream tracking and allow renaming a branch 2020-03-18 21:29:06 +11:00
hitsuji_no_shippo 2169b5109f add search keybings in docs 2020-03-11 19:43:22 +11:00
hitsuji_no_shippo 4a2292a53c fix keybindings of main panel in docs 2020-03-11 19:43:22 +11:00
Jesse Duffield 7df4b736cf be a bit more lenient 2020-03-09 12:41:41 +11:00
Jesse Duffield e47ad846c4 big golangci-lint cleanup 2020-03-09 12:23:13 +11:00
Jesse Duffield 8f68ac2129 case insensitive search
By default, search is now case insensitive.
If you include uppercase characters in your search string, the search
will become case sensitive. This means there is no way to do a case-
insensitive search of all-lowercase strings. We could add more support
for this but we'll wait until we come across the use case
2020-03-09 11:17:50 +11:00
Dawid Dziurla 1ea2825a54 add homebrew bump formula workflow 2020-03-08 20:13:16 +11:00
Jesse Duffield 19146d61b1 use selected branch as base when creating a new branch 2020-03-08 18:44:15 +11:00
skwerlman e541b809ce update tests to match changed command 2020-03-06 09:25:31 +11:00
skwerlman 6ca08c6519 make branches and files non-ambiguous for git-log
fixes #694
2020-03-06 09:25:31 +11:00
Dawid Dziurla b43540820b Merge pull request #695 from chenrui333/go-1.14
Bump golang to v1.14
2020-03-04 16:38:56 +01:00
Rui Chen 3d57da71eb Add gox to vendor list 2020-03-04 10:32:07 -05:00
Rui Chen 0130fd3666 go mod vendor 2020-03-03 18:16:09 -05:00
Rui Chen 395afc4a8d Bump golang to v1.14 2020-03-03 18:14:49 -05:00
50 changed files with 584 additions and 435 deletions
+2 -2
View File
@@ -2,7 +2,7 @@ version: 2
jobs:
build:
docker:
- image: circleci/golang:1.13
- image: circleci/golang:1.14
environment:
GO111MODULE: "on"
working_directory: /go/src/github.com/jesseduffield/lazygit
@@ -38,7 +38,7 @@ jobs:
release:
docker:
- image: circleci/golang:1.13
- image: circleci/golang:1.14
working_directory: /go/src/github.com/jesseduffield/lazygit
steps:
- checkout
+20
View File
@@ -0,0 +1,20 @@
name: Bump Homebrew formula
on:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
steps:
- name: Get tag
id: tag
run: echo "::set-output name=tag::${GITHUB_REF##*/}"
- name: Bump Homebrew formula
uses: dawidd6/action-homebrew-bump-formula@v1.1.0
with:
token: ${{secrets.GITHUB_API_TOKEN}}
formula: lazygit
url: "https://github.com/${{github.repository}}/archive/${{steps.tag.outputs.tag}}.tar.gz"
+2 -2
View File
@@ -2,12 +2,12 @@
# docker build -t lazygit .
# docker run -it lazygit:latest /bin/sh -l
FROM golang:1.13-alpine3.10
FROM golang:1.14-alpine3.11
WORKDIR /go/src/github.com/jesseduffield/lazygit/
COPY ./ .
RUN CGO_ENABLED=0 GOOS=linux go build
FROM alpine:3.10
FROM alpine:3.11
RUN apk add -U git xdg-utils
WORKDIR /go/src/github.com/jesseduffield/lazygit/
COPY --from=0 /go/src/github.com/jesseduffield/lazygit /go/src/github.com/jesseduffield/lazygit
+26 -4
View File
@@ -10,6 +10,7 @@
<kbd>P</kbd>: push
<kbd>p</kbd>: pull
<kbd>R</kbd>: refresh
<kbd>x</kbd>: open menu
<kbd>+</kbd>: next screen mode (normal/half/fullscreen)
<kbd>_</kbd>: prev screen mode
<kbd>:</kbd>: execute custom command
@@ -29,6 +30,8 @@
<kbd>i</kbd>: show git-flow options
<kbd>f</kbd>: fast-forward this branch from its upstream
<kbd>g</kbd>: view reset options
<kbd>R</kbd>: rename branch
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Remote Branches (in Remotes tab))
@@ -41,6 +44,7 @@
<kbd>d</kbd>: delete branch
<kbd>r</kbd>: rebase checked-out branch onto this branch
<kbd>u</kbd>: set as upstream of checked-out branch
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Remotes Tab)
@@ -50,6 +54,7 @@
<kbd>n</kbd>: add new remote
<kbd>d</kbd>: remove remote
<kbd>e</kbd>: edit remote
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Tags Tab)
@@ -60,6 +65,7 @@
<kbd>P</kbd>: push tag
<kbd>n</kbd>: create tag
<kbd>g</kbd>: view reset options
<kbd>/</kbd>: start search
</pre>
## Commit Files Panel
@@ -71,6 +77,13 @@
<kbd>o</kbd>: open file
<kbd>space</kbd>: toggle file included in patch
<kbd>enter</kbd>: enter file to add selected lines to the patch
<kbd>/</kbd>: start search
</pre>
## Commits Panel
<pre>
<kbd>/</kbd>: start search
</pre>
## Commits Panel (Commits Tab)
@@ -126,6 +139,7 @@
<kbd>enter</kbd>: stage individual hunks/lines
<kbd>f</kbd>: fetch
<kbd>g</kbd>: view upstream reset options
<kbd>/</kbd>: start search
</pre>
## Main Panel (Merging)
@@ -156,8 +170,7 @@
<kbd>▼</kbd>: select next line
<kbd>◄</kbd>: select previous hunk
<kbd>►</kbd>: select next hunk
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>space</kbd>: add/remove line(s) to patch
<kbd>v</kbd>: toggle drag select
<kbd>V</kbd>: toggle drag select
<kbd>a</kbd>: toggle select hunk
@@ -167,8 +180,8 @@
<pre>
<kbd>esc</kbd>: return to files panel
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>space</kbd>: toggle line staged / unstaged
<kbd>d</kbd>: delete change (git reset)
<kbd>tab</kbd>: switch to other panel
<kbd>▲</kbd>: select previous line
<kbd>▼</kbd>: select next line
@@ -184,12 +197,21 @@
<kbd>C</kbd>: commit changes using git editor
</pre>
## Menu Panel
<pre>
<kbd>esc</kbd>: close menu
<kbd>q</kbd>: close menu
<kbd>/</kbd>: start search
</pre>
## Stash Panel
<pre>
<kbd>space</kbd>: apply
<kbd>g</kbd>: pop
<kbd>d</kbd>: drop
<kbd>/</kbd>: start search
</pre>
## Status Panel
+26 -4
View File
@@ -10,6 +10,7 @@
<kbd>P</kbd>: push
<kbd>p</kbd>: pull
<kbd>R</kbd>: verversen
<kbd>x</kbd>: open menu
<kbd>+</kbd>: next screen mode (normal/half/fullscreen)
<kbd>_</kbd>: prev screen mode
<kbd>:</kbd>: voor aangepast commando uit
@@ -29,6 +30,8 @@
<kbd>i</kbd>: show git-flow options
<kbd>f</kbd>: fast-forward this branch from its upstream
<kbd>g</kbd>: bekijk reset opties
<kbd>R</kbd>: rename branch
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Remote Branches (in Remotes tab))
@@ -41,6 +44,7 @@
<kbd>d</kbd>: verwijder branch
<kbd>r</kbd>: rebase branch
<kbd>u</kbd>: set as upstream of checked-out branch
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Remotes Tab)
@@ -50,6 +54,7 @@
<kbd>n</kbd>: add new remote
<kbd>d</kbd>: remove remote
<kbd>e</kbd>: edit remote
<kbd>/</kbd>: start search
</pre>
## Branches Panel (Tags Tab)
@@ -60,6 +65,7 @@
<kbd>P</kbd>: push tag
<kbd>n</kbd>: create tag
<kbd>g</kbd>: bekijk reset opties
<kbd>/</kbd>: start search
</pre>
## Commit bestanden Panel
@@ -71,6 +77,13 @@
<kbd>o</kbd>: open bestand
<kbd>space</kbd>: toggle file included in patch
<kbd>enter</kbd>: enter file to add selected lines to the patch
<kbd>/</kbd>: start search
</pre>
## Commits Panel
<pre>
<kbd>/</kbd>: start search
</pre>
## Commits Panel (Commits Tab)
@@ -126,6 +139,7 @@
<kbd>enter</kbd>: stage individuele hunks/lijnen
<kbd>f</kbd>: fetch
<kbd>g</kbd>: view upstream reset options
<kbd>/</kbd>: start search
</pre>
## Hoofd Panel (Merging)
@@ -156,8 +170,7 @@
<kbd>▼</kbd>: selecteer de volgende lijn
<kbd>◄</kbd>: selecteer de vorige hunk
<kbd>►</kbd>: selecteer de volgende hunk
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>space</kbd>: add/remove line(s) to patch
<kbd>v</kbd>: toggle drag select
<kbd>V</kbd>: toggle drag select
<kbd>a</kbd>: toggle select hunk
@@ -167,8 +180,8 @@
<pre>
<kbd>esc</kbd>: ga terug naar het bestanden paneel
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>space</kbd>: toggle line staged / unstaged
<kbd>d</kbd>: delete change (git reset)
<kbd>tab</kbd>: switch to other panel
<kbd>▲</kbd>: selecteer de vorige lijn
<kbd>▼</kbd>: selecteer de volgende lijn
@@ -184,12 +197,21 @@
<kbd>C</kbd>: commit veranderingen met de git editor
</pre>
## Menu Panel
<pre>
<kbd>esc</kbd>: close menu
<kbd>q</kbd>: close menu
<kbd>/</kbd>: start search
</pre>
## Stash Panel
<pre>
<kbd>space</kbd>: toepassen
<kbd>g</kbd>: pop
<kbd>d</kbd>: drop
<kbd>/</kbd>: start search
</pre>
## Status Panel
+26 -4
View File
@@ -10,6 +10,7 @@
<kbd>P</kbd>: push
<kbd>p</kbd>: pull
<kbd>R</kbd>: odśwież
<kbd>x</kbd>: open menu
<kbd>+</kbd>: next screen mode (normal/half/fullscreen)
<kbd>_</kbd>: prev screen mode
<kbd>:</kbd>: execute custom command
@@ -29,6 +30,8 @@
<kbd>i</kbd>: show git-flow options
<kbd>f</kbd>: fast-forward this branch from its upstream
<kbd>g</kbd>: view reset options
<kbd>R</kbd>: rename branch
<kbd>/</kbd>: start search
</pre>
## Gałęzie Panel (Remote Branches (in Remotes tab))
@@ -41,6 +44,7 @@
<kbd>d</kbd>: usuń gałąź
<kbd>r</kbd>: rebase branch
<kbd>u</kbd>: set as upstream of checked-out branch
<kbd>/</kbd>: start search
</pre>
## Gałęzie Panel (Remotes Tab)
@@ -50,6 +54,7 @@
<kbd>n</kbd>: add new remote
<kbd>d</kbd>: remove remote
<kbd>e</kbd>: edit remote
<kbd>/</kbd>: start search
</pre>
## Gałęzie Panel (Tags Tab)
@@ -60,6 +65,7 @@
<kbd>P</kbd>: push tag
<kbd>n</kbd>: create tag
<kbd>g</kbd>: view reset options
<kbd>/</kbd>: start search
</pre>
## Commit files Panel
@@ -71,6 +77,13 @@
<kbd>o</kbd>: otwórz plik
<kbd>space</kbd>: toggle file included in patch
<kbd>enter</kbd>: enter file to add selected lines to the patch
<kbd>/</kbd>: start search
</pre>
## Commity Panel
<pre>
<kbd>/</kbd>: start search
</pre>
## Commity Panel (Commits Tab)
@@ -126,6 +139,7 @@
<kbd>enter</kbd>: zatwierdź pojedyncze linie
<kbd>f</kbd>: fetch
<kbd>g</kbd>: view upstream reset options
<kbd>/</kbd>: start search
</pre>
## Main Panel (Merging)
@@ -156,8 +170,7 @@
<kbd>▼</kbd>: select next line
<kbd>◄</kbd>: select previous hunk
<kbd>►</kbd>: select next hunk
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>space</kbd>: add/remove line(s) to patch
<kbd>v</kbd>: toggle drag select
<kbd>V</kbd>: toggle drag select
<kbd>a</kbd>: toggle select hunk
@@ -167,8 +180,8 @@
<pre>
<kbd>esc</kbd>: wróć do panelu plików
<kbd>space</kbd>: stage selection
<kbd>d</kbd>: reset selection
<kbd>space</kbd>: toggle line staged / unstaged
<kbd>d</kbd>: delete change (git reset)
<kbd>tab</kbd>: switch to other panel
<kbd>▲</kbd>: select previous line
<kbd>▼</kbd>: select next line
@@ -184,12 +197,21 @@
<kbd>C</kbd>: commituj zmiany używając edytora z gita
</pre>
## Menu Panel
<pre>
<kbd>esc</kbd>: close menu
<kbd>q</kbd>: close menu
<kbd>/</kbd>: start search
</pre>
## Schowek Panel
<pre>
<kbd>space</kbd>: zastosuj
<kbd>g</kbd>: wyciągnij
<kbd>d</kbd>: porzuć
<kbd>/</kbd>: start search
</pre>
## Status Panel
+3 -2
View File
@@ -1,6 +1,6 @@
module github.com/jesseduffield/lazygit
go 1.13
go 1.14
require (
github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
@@ -11,7 +11,7 @@ require (
github.com/golang/protobuf v1.3.2 // indirect
github.com/google/go-cmp v0.3.1 // indirect
github.com/integrii/flaggy v1.4.0
github.com/jesseduffield/gocui v0.3.1-0.20200301081700-d6e485450113
github.com/jesseduffield/gocui v0.3.1-0.20200309001002-7765949e1c8a
github.com/jesseduffield/pty v1.2.1
github.com/jesseduffield/termbox-go v0.0.0-20200130214842-1d31d1faa3c9 // indirect
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
@@ -20,6 +20,7 @@ require (
github.com/mattn/go-isatty v0.0.11 // indirect
github.com/mattn/go-runewidth v0.0.8
github.com/mgutz/str v1.2.0
github.com/mitchellh/gox v1.0.1 // indirect
github.com/nicksnyder/go-i18n/v2 v2.0.3
github.com/onsi/ginkgo v1.10.3 // indirect
github.com/onsi/gomega v1.7.1 // indirect
+8 -2
View File
@@ -68,6 +68,8 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/go-version v1.0.0 h1:21MVWPKDphxa7ineQQTrCU5brh7OuVVAzGOCnnCPtE8=
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
@@ -76,10 +78,10 @@ github.com/integrii/flaggy v1.4.0 h1:A1x7SYx4jqu5NSrY14z8Z+0UyX2S5ygfJJrfolWR3zM
github.com/integrii/flaggy v1.4.0/go.mod h1:tnTxHeTJbah0gQ6/K0RW0J7fMUBk9MCF5blhm43LNpI=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jesseduffield/gocui v0.3.1-0.20200224201655-5024a02682ed h1:glGs+mzPZOl1iHiUsBW3918WeFwqsbQQ/jtLkkQXDi4=
github.com/jesseduffield/gocui v0.3.1-0.20200224201655-5024a02682ed/go.mod h1:2RtZznzYKt8RLRwvFiSkXjU0Ei8WwHdubgnlaYH47dw=
github.com/jesseduffield/gocui v0.3.1-0.20200301081700-d6e485450113 h1:jHZRVJUWsU8HaQ0crocz0i0BkpOqFLDJEO/AtBp+Ecs=
github.com/jesseduffield/gocui v0.3.1-0.20200301081700-d6e485450113/go.mod h1:2RtZznzYKt8RLRwvFiSkXjU0Ei8WwHdubgnlaYH47dw=
github.com/jesseduffield/gocui v0.3.1-0.20200309001002-7765949e1c8a h1:JSORQue6V4bMppr22dtUuYX+w79cgupo66PcGZ9ijlU=
github.com/jesseduffield/gocui v0.3.1-0.20200309001002-7765949e1c8a/go.mod h1:2RtZznzYKt8RLRwvFiSkXjU0Ei8WwHdubgnlaYH47dw=
github.com/jesseduffield/pty v1.2.1 h1:7xYBiwNH0PpWqC8JmvrPq1a/ksNqyCavzWu9pbBGYWI=
github.com/jesseduffield/pty v1.2.1/go.mod h1:7jlS40+UhOqkZJDIG1B/H21xnuET/+fvbbnHCa8wSIo=
github.com/jesseduffield/termbox-go v0.0.0-20200130214842-1d31d1faa3c9 h1:iBBk1lhFwjwJw//J2m1yyz9S368GeXQTpMVACTyQMh0=
@@ -119,6 +121,10 @@ github.com/mgutz/str v1.2.0 h1:4IzWSdIz9qPQWLfKZ0rJcV0jcUDpxvP4JVZ4GXQyvSw=
github.com/mgutz/str v1.2.0/go.mod h1:w1v0ofgLaJdoD0HpQ3fycxKD1WtxpjSo151pK/31q6w=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=
github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
github.com/mitchellh/iochan v1.0.0 h1:C+X3KsSTLFVBr/tK1eYN/vs4rJcvsiLU338UhYPJWeY=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-6
View File
@@ -4,7 +4,6 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
"github.com/go-errors/errors"
@@ -20,11 +19,6 @@ var (
buildSource = "unknown"
)
func projectPath(path string) string {
gopath := os.Getenv("GOPATH")
return filepath.FromSlash(gopath + "/src/github.com/jesseduffield/lazygit/" + path)
}
func main() {
flaggy.DefaultParser.ShowVersionWithVersionFlag = false
+5 -4
View File
@@ -3,8 +3,9 @@ package commands
// Branch : A git branch
// duplicating this for now
type Branch struct {
Name string
Recency string
Pushables string
Pullables string
Name string
Recency string
Pushables string
Pullables string
UpstreamName string
}
+99 -83
View File
@@ -7,8 +7,6 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils"
"github.com/sirupsen/logrus"
"gopkg.in/src-d/go-git.v4/plumbing"
)
// context:
@@ -36,86 +34,97 @@ func NewBranchListBuilder(log *logrus.Entry, gitCommand *GitCommand) (*BranchLis
}, nil
}
func (b *BranchListBuilder) obtainCurrentBranch() *Branch {
func (b *BranchListBuilder) obtainCurrentBranchName() string {
branchName, err := b.GitCommand.CurrentBranchName()
if err != nil {
panic(err.Error())
}
return &Branch{Name: strings.TrimSpace(branchName)}
return branchName
}
func (b *BranchListBuilder) obtainReflogBranches() []*Branch {
branches := make([]*Branch, 0)
// if we directly put this string in RunCommandWithOutput the compiler complains because it thinks it's a format string
unescaped := "git reflog --date=relative --pretty='%gd|%gs' --grep-reflog='checkout: moving' HEAD"
rawString, err := b.GitCommand.OSCommand.RunCommandWithOutput(unescaped)
if err != nil {
return branches
}
branchLines := utils.SplitLines(rawString)
for _, line := range branchLines {
recency, branchName := branchInfoFromLine(line)
if branchName == "" {
continue
}
branch := &Branch{Name: branchName, Recency: recency}
branches = append(branches, branch)
}
return uniqueByName(branches)
}
func (b *BranchListBuilder) obtainSafeBranches() []*Branch {
branches := make([]*Branch, 0)
bIter, err := b.GitCommand.Repo.Branches()
func (b *BranchListBuilder) obtainBranches() []*Branch {
cmdStr := `git branch --format="%(refname:short)|%(upstream:short)|%(upstream:track)"`
output, err := b.GitCommand.OSCommand.RunCommandWithOutput(cmdStr)
if err != nil {
panic(err)
}
bIter.ForEach(func(b *plumbing.Reference) error {
name := b.Name().Short()
branches = append(branches, &Branch{Name: name})
return nil
})
trimmedOutput := strings.TrimSpace(output)
outputLines := strings.Split(trimmedOutput, "\n")
if len(outputLines) <= 1 {
return []*Branch{}
}
branches := make([]*Branch, len(outputLines)-1)
for i, line := range outputLines[1:] {
split := strings.Split(line, SEPARATION_CHAR)
name := split[0]
branches[i] = &Branch{
Name: name,
Pullables: "?",
Pushables: "?",
}
upstreamName := split[1]
if upstreamName == "" {
continue
}
branches[i].UpstreamName = upstreamName
track := split[2]
re := regexp.MustCompile(`ahead (\d+)`)
match := re.FindStringSubmatch(track)
if len(match) > 1 {
branches[i].Pushables = match[1]
} else {
branches[i].Pushables = "0"
}
re = regexp.MustCompile(`behind (\d+)`)
match = re.FindStringSubmatch(track)
if len(match) > 1 {
branches[i].Pullables = match[1]
} else {
branches[i].Pullables = "0"
}
}
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 sanitisedReflogName(reflogBranch *Branch, safeBranches []*Branch) string {
for _, safeBranch := range safeBranches {
if strings.ToLower(safeBranch.Name) == strings.ToLower(reflogBranch.Name) {
return safeBranch.Name
}
}
return reflogBranch.Name
}
// Build the list of branches for the current repo
func (b *BranchListBuilder) Build() []*Branch {
branches := make([]*Branch, 0)
head := b.obtainCurrentBranch()
safeBranches := b.obtainSafeBranches()
currentBranchName := b.obtainCurrentBranchName()
branches := b.obtainBranches()
reflogBranches := b.obtainReflogBranches()
for i, reflogBranch := range reflogBranches {
reflogBranches[i].Name = sanitisedReflogName(reflogBranch, safeBranches)
// loop through reflog branches. If there is a match, merge them, then remove it from the branches and keep it in the reflog branches
branchesWithRecency := make([]*Branch, 0)
outer:
for _, reflogBranch := range reflogBranches {
for j, branch := range branches {
if strings.EqualFold(reflogBranch.Name, branch.Name) {
branch.Recency = reflogBranch.Recency
branchesWithRecency = append(branchesWithRecency, branch)
branches = append(branches[0:j], branches[j+1:]...)
continue outer
}
}
}
branches = b.appendNewBranches(branches, reflogBranches, safeBranches, true)
branches = b.appendNewBranches(branches, safeBranches, branches, false)
branches = append(branchesWithRecency, branches...)
if len(branches) == 0 || branches[0].Name != head.Name {
branches = append([]*Branch{head}, branches...)
// if it's the current branch we need to pull it up to the top
for i, branch := range branches {
if branch.Name == currentBranchName {
branches = append(branches[0:i], branches[i+1:]...)
branches = append([]*Branch{branch}, branches...)
break
}
}
if len(branches) == 0 || branches[0].Name != currentBranchName {
branches = append([]*Branch{{Name: currentBranchName}}, branches...)
}
branches[0].Recency = " *"
@@ -123,26 +132,6 @@ func (b *BranchListBuilder) Build() []*Branch {
return branches
}
func branchIncluded(branchName string, branches []*Branch) bool {
for _, existingBranch := range branches {
if strings.ToLower(existingBranch.Name) == strings.ToLower(branchName) {
return true
}
}
return false
}
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) {
@@ -172,3 +161,30 @@ func abbreviatedTimeUnit(timeUnit string) string {
}
return timeUnitMap[timeUnit]
}
func (b *BranchListBuilder) obtainReflogBranches() []*Branch {
branches := make([]*Branch, 0)
// if we directly put this string in RunCommandWithOutput the compiler complains because it thinks it's a format string
unescaped := "git reflog --date=relative --pretty='%gd|%gs' --grep-reflog='checkout: moving' HEAD"
rawString, err := b.GitCommand.OSCommand.RunCommandWithOutput(unescaped)
if err != nil {
return branches
}
branchNameMap := map[string]bool{}
branchLines := utils.SplitLines(rawString)
for _, line := range branchLines {
recency, branchName := branchInfoFromLine(line)
if branchName == "" {
continue
}
if _, ok := branchNameMap[branchName]; ok {
continue
}
branchNameMap[branchName] = true
branch := &Branch{Name: branchName, Recency: recency}
branches = append(branches, branch)
}
return branches
}
+8 -4
View File
@@ -327,8 +327,8 @@ func (c *GitCommand) ResetToCommit(sha string, strength string) error {
}
// NewBranch create new branch
func (c *GitCommand) NewBranch(name string) error {
return c.OSCommand.RunCommand("git checkout -b %s", name)
func (c *GitCommand) NewBranch(name string, baseBranch string) error {
return c.OSCommand.RunCommand("git checkout -b %s %s", name, baseBranch)
}
// CurrentBranchName is a function.
@@ -343,7 +343,7 @@ func (c *GitCommand) CurrentBranchName() (string, error) {
match := re.FindStringSubmatch(output)
branchName = match[1]
}
return utils.TrimTrailingNewline(branchName), nil
return strings.TrimSpace(branchName), nil
}
// DeleteBranch delete branch
@@ -563,7 +563,7 @@ func (c *GitCommand) ShowCmdStr(sha string) string {
}
func (c *GitCommand) GetBranchGraphCmdStr(branchName string) string {
return fmt.Sprintf("git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium %s", branchName)
return fmt.Sprintf("git log --graph --color=always --abbrev-commit --decorate --date=relative --pretty=medium %s --", branchName)
}
// GetRemoteURL returns current repo remote url
@@ -1163,3 +1163,7 @@ func (c *GitCommand) GetPager(width int) string {
func (c *GitCommand) colorArg() string {
return c.Config.GetUserConfig().GetString("git.paging.colorArg")
}
func (c *GitCommand) RenameBranch(oldName string, newName string) error {
return c.OSCommand.RunCommand("git branch --move %s %s", oldName, newName)
}
+4 -4
View File
@@ -636,12 +636,12 @@ func TestGitCommandNewBranch(t *testing.T) {
gitCmd := NewDummyGitCommand()
gitCmd.OSCommand.command = func(cmd string, args ...string) *exec.Cmd {
assert.EqualValues(t, "git", cmd)
assert.EqualValues(t, []string{"checkout", "-b", "test"}, args)
assert.EqualValues(t, []string{"checkout", "-b", "test", "master"}, args)
return exec.Command("echo")
}
assert.NoError(t, gitCmd.NewBranch("test"))
assert.NoError(t, gitCmd.NewBranch("test", "master"))
}
// TestGitCommandDeleteBranch is a function.
@@ -1449,7 +1449,7 @@ func TestGitCommandGetBranchGraph(t *testing.T) {
gitCmd := NewDummyGitCommand()
gitCmd.OSCommand.command = func(cmd string, args ...string) *exec.Cmd {
assert.EqualValues(t, "git", cmd)
assert.EqualValues(t, []string{"log", "--graph", "--color=always", "--abbrev-commit", "--decorate", "--date=relative", "--pretty=medium", "test"}, args)
assert.EqualValues(t, []string{"log", "--graph", "--color=always", "--abbrev-commit", "--decorate", "--date=relative", "--pretty=medium", "test", "--"}, args)
return exec.Command("echo")
}
@@ -2130,7 +2130,7 @@ func TestGitCommandSkipEditorCommand(t *testing.T) {
)
})
cmd.RunSkipEditorCommand("true")
_ = cmd.RunSkipEditorCommand("true")
}
func TestFindDotGitDir(t *testing.T) {
+1
View File
@@ -334,6 +334,7 @@ keybinding:
checkoutBranchByName: 'c'
forceCheckoutBranch: 'F'
rebaseBranch: 'r'
renameBranch: 'R'
mergeIntoCurrentBranch: 'M'
viewGitFlowOptions: 'i'
fastForward: 'f'
+1 -3
View File
@@ -66,9 +66,7 @@ func (gui *Gui) WithWaitingStatus(name string, f func() error) error {
if appStatus == "" {
return
}
if err := gui.renderString(gui.g, "appStatus", appStatus); err != nil {
gui.Log.Warn(err)
}
gui.renderString(gui.g, "appStatus", appStatus)
}
}()
+63 -42
View File
@@ -40,12 +40,7 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
return gui.newStringTask("main", gui.Tr.SLocalize("NoBranchesThisRepo"))
}
branch := gui.getSelectedBranch()
if err := gui.focusPoint(0, gui.State.Panels.Branches.SelectedLine, len(gui.State.Branches), v); err != nil {
return err
}
if err := gui.RenderSelectedBranchUpstreamDifferences(); err != nil {
return err
}
v.FocusPoint(0, gui.State.Panels.Branches.SelectedLine)
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(branch.Name),
@@ -56,24 +51,6 @@ func (gui *Gui) handleBranchSelect(g *gocui.Gui, v *gocui.View) error {
return nil
}
func (gui *Gui) RenderSelectedBranchUpstreamDifferences() error {
return gui.newTask("branches", func(stop chan struct{}) error {
branch := gui.getSelectedBranch()
branch.Pushables, branch.Pullables = gui.GitCommand.GetBranchUpstreamDifferenceCount(branch.Name)
select {
case <-stop:
return nil
default:
}
branchesView := gui.getBranchesView()
displayStrings := presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.currentViewName() == "branches", gui.State.Panels.Branches.SelectedLine)
gui.renderDisplayStrings(branchesView, displayStrings)
return nil
})
}
// gui.refreshStatus is called at the end of this because that's when we can
// be sure there is a state.Branches array to pick the current branch from
func (gui *Gui) refreshBranches(g *gocui.Gui) error {
@@ -108,9 +85,8 @@ func (gui *Gui) renderLocalBranchesWithSelection() error {
branchesView := gui.getBranchesView()
gui.refreshSelectedLine(&gui.State.Panels.Branches.SelectedLine, len(gui.State.Branches))
if err := gui.RenderSelectedBranchUpstreamDifferences(); err != nil {
return err
}
displayStrings := presentation.GetBranchListDisplayStrings(gui.State.Branches, gui.State.ScreenMode != SCREEN_NORMAL)
gui.renderDisplayStrings(branchesView, displayStrings)
if gui.g.CurrentView() == branchesView {
if err := gui.handleBranchSelect(gui.g, branchesView); err != nil {
return err
@@ -161,7 +137,7 @@ func (gui *Gui) handleForceCheckout(g *gocui.Gui, v *gocui.View) error {
title := gui.Tr.SLocalize("ForceCheckoutBranch")
return gui.createConfirmationPanel(g, v, true, title, message, func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.Checkout(branch.Name, true); err != nil {
gui.createErrorPanel(g, err.Error())
_ = gui.createErrorPanel(g, err.Error())
}
return gui.refreshSidePanels(g)
}, nil)
@@ -205,10 +181,9 @@ func (gui *Gui) handleCheckoutRef(ref string) error {
}
func (gui *Gui) handleCheckoutByName(g *gocui.Gui, v *gocui.View) error {
gui.createPromptPanel(g, v, gui.Tr.SLocalize("BranchName")+":", "", func(g *gocui.Gui, v *gocui.View) error {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("BranchName")+":", "", func(g *gocui.Gui, v *gocui.View) error {
return gui.handleCheckoutRef(gui.trimmedContent(v))
})
return nil
}
func (gui *Gui) getCheckedOutBranch() *commands.Branch {
@@ -220,31 +195,31 @@ func (gui *Gui) getCheckedOutBranch() *commands.Branch {
}
func (gui *Gui) handleNewBranch(g *gocui.Gui, v *gocui.View) error {
branch := gui.getCheckedOutBranch()
branch := gui.getSelectedBranch()
if branch == nil {
return nil
}
message := gui.Tr.TemplateLocalize(
"NewBranchNameBranchOff",
Teml{
"branchName": branch.Name,
},
)
gui.createPromptPanel(g, v, message, "", func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.NewBranch(gui.trimmedContent(v)); err != nil {
return gui.createPromptPanel(g, v, message, "", func(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.NewBranch(gui.trimmedContent(v), branch.Name); err != nil {
return gui.createErrorPanel(g, err.Error())
}
if err := gui.refreshSidePanels(g); err != nil {
return gui.createErrorPanel(g, err.Error())
}
gui.refreshSidePanels(g)
return gui.handleBranchSelect(g, v)
})
return nil
}
func (gui *Gui) handleDeleteBranch(g *gocui.Gui, v *gocui.View) error {
return gui.deleteBranch(g, v, false)
}
func (gui *Gui) handleForceDeleteBranch(g *gocui.Gui, v *gocui.View) error {
return gui.deleteBranch(g, v, true)
}
func (gui *Gui) deleteBranch(g *gocui.Gui, v *gocui.View, force bool) error {
selectedBranch := gui.getSelectedBranch()
if selectedBranch == nil {
@@ -378,7 +353,7 @@ func (gui *Gui) handleFastForward(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.FastForward(branch.Name, remoteName, remoteBranchName); err != nil {
_ = gui.createErrorPanel(gui.g, err.Error())
}
_ = gui.RenderSelectedBranchUpstreamDifferences()
_ = gui.refreshBranches(gui.g)
}
_ = gui.closeConfirmationPrompt(gui.g, true)
@@ -397,7 +372,9 @@ func (gui *Gui) onBranchesTabClick(tabIndex int) error {
func (gui *Gui) switchBranchesPanelContext(context string) error {
branchesView := gui.getBranchesView()
branchesView.Context = context
gui.onSearchEscape()
if err := gui.onSearchEscape(); err != nil {
return err
}
contextTabIndexMap := map[string]int{
"local-branches": 0,
@@ -408,7 +385,13 @@ func (gui *Gui) switchBranchesPanelContext(context string) error {
branchesView.TabIndex = contextTabIndexMap[context]
switch context {
return gui.refreshBranchesViewWithSelection()
}
func (gui *Gui) refreshBranchesViewWithSelection() error {
branchesView := gui.getBranchesView()
switch branchesView.Context {
case "local-branches":
return gui.renderLocalBranchesWithSelection()
case "remotes":
@@ -458,3 +441,41 @@ func (gui *Gui) onBranchesPanelSearchSelect(selectedLine int) error {
}
return nil
}
func (gui *Gui) handleRenameBranch(g *gocui.Gui, v *gocui.View) error {
branch := gui.getSelectedBranch()
if branch == nil {
return nil
}
promptForNewName := func() error {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("NewBranchNamePrompt")+" "+branch.Name+":", "", func(g *gocui.Gui, v *gocui.View) error {
newName := gui.trimmedContent(v)
if err := gui.GitCommand.RenameBranch(branch.Name, newName); err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
// need to checkout so that the branch shows up in our reflog and therefore
// doesn't get lost among all the other branches when we switch to something else
if err := gui.GitCommand.Checkout(newName, false); err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
return gui.refreshBranches(gui.g)
})
}
// I could do an explicit check here for whether the branch is tracking a remote branch
// but if we've selected it we'll already know that via Pullables and Pullables.
// Bit of a hack but I'm lazy.
notTrackingRemote := branch.Pullables == "?"
if notTrackingRemote {
return promptForNewName()
}
return gui.createConfirmationPanel(gui.g, v, true, gui.Tr.SLocalize("renameBranch"), gui.Tr.SLocalize("RenameBranchWarning"), func(_g *gocui.Gui, _v *gocui.View) error {
return promptForNewName()
}, nil)
}
func (gui *Gui) currentBranch() *commands.Branch {
return gui.State.Branches[0]
}
+7 -6
View File
@@ -36,16 +36,15 @@ func (gui *Gui) handleCommitFileSelect(g *gocui.Gui, v *gocui.View) error {
commitFile := gui.getSelectedCommitFile(g)
if commitFile == nil {
return gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil
}
if err := gui.refreshSecondaryPatchPanel(); err != nil {
return err
}
if err := gui.focusPoint(0, gui.State.Panels.CommitFiles.SelectedLine, len(gui.State.CommitFiles), v); err != nil {
return err
}
v.FocusPoint(0, gui.State.Panels.CommitFiles.SelectedLine)
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCommitFileCmdStr(commitFile.Sha, commitFile.Name, false),
@@ -132,7 +131,8 @@ func (gui *Gui) handleToggleFileForPatch(g *gocui.Gui, v *gocui.View) error {
commitFile := gui.getSelectedCommitFile(g)
if commitFile == nil {
return gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
gui.renderString(g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil
}
toggleTheFile := func() error {
@@ -187,7 +187,8 @@ func (gui *Gui) enterCommitFile(selectedLineIdx int) error {
commitFile := gui.getSelectedCommitFile(gui.g)
if commitFile == nil {
return gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil
}
enterTheFile := func(selectedLineIdx int) error {
+3 -2
View File
@@ -52,7 +52,7 @@ func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error {
}
func (gui *Gui) handleCommitClose(g *gocui.Gui, v *gocui.View) error {
g.SetViewOnBottom("commitMessage")
_, _ = g.SetViewOnBottom("commitMessage")
return gui.switchFocus(g, v, gui.getFilesView())
}
@@ -68,7 +68,8 @@ func (gui *Gui) handleCommitFocused(g *gocui.Gui, v *gocui.View) error {
"keyBindConfirm": "enter",
},
)
return gui.renderString(g, "options", message)
gui.renderString(g, "options", message)
return nil
}
func (gui *Gui) getBufferLength(view *gocui.View) string {
+8 -59
View File
@@ -3,8 +3,6 @@ package gui
import (
"strconv"
"github.com/go-errors/errors"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
@@ -55,9 +53,7 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
return gui.newStringTask("main", gui.Tr.SLocalize("NoCommitsThisBranch"))
}
if err := gui.focusPoint(0, gui.State.Panels.Commits.SelectedLine, len(gui.State.Commits), v); err != nil {
return err
}
v.FocusPoint(0, gui.State.Panels.Commits.SelectedLine)
// if specific diff mode is on, don't show diff
if gui.State.Panels.Commits.SpecificDiffMode {
@@ -77,7 +73,7 @@ func (gui *Gui) handleCommitSelect(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) refreshCommits(g *gocui.Gui) error {
g.Update(func(*gocui.Gui) error {
// I think this is here for the sake of some kind of rebasing thing
gui.refreshStatus(g)
_ = gui.refreshStatus(g)
if err := gui.refreshCommitsWithLimit(); err != nil {
return err
@@ -121,28 +117,6 @@ func (gui *Gui) refreshCommitsWithLimit() error {
// specific functions
func (gui *Gui) handleResetToCommit(g *gocui.Gui, commitView *gocui.View) error {
return gui.createConfirmationPanel(g, commitView, true, gui.Tr.SLocalize("ResetToCommit"), gui.Tr.SLocalize("SureResetThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
commit := gui.getSelectedCommit(g)
if commit == nil {
panic(errors.New(gui.Tr.SLocalize("NoCommitsThisBranch")))
}
if err := gui.GitCommand.ResetToCommit(commit.Sha, "mixed"); err != nil {
return gui.createErrorPanel(g, err.Error())
}
if err := gui.refreshCommits(g); err != nil {
panic(err)
}
if err := gui.refreshFiles(); err != nil {
panic(err)
}
gui.resetOrigin(commitView)
gui.State.Panels.Commits.SelectedLine = 0
return gui.handleCommitSelect(g, commitView)
}, nil)
}
func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error {
if len(gui.State.Commits) <= 1 {
return gui.createErrorPanel(g, gui.Tr.SLocalize("YouNoCommitsToSquash"))
@@ -156,23 +130,12 @@ func (gui *Gui) handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error {
return nil
}
gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Squash"), gui.Tr.SLocalize("SureSquashThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Squash"), gui.Tr.SLocalize("SureSquashThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("SquashingStatus"), func() error {
err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "squash")
return gui.handleGenericMergeCommandResult(err)
})
}, nil)
return nil
}
// TODO: move to files panel
func (gui *Gui) anyUnStagedChanges(files []*commands.File) bool {
for _, file := range files {
if file.Tracked && file.HasUnstagedChanges {
return true
}
}
return false
}
func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error {
@@ -188,13 +151,12 @@ func (gui *Gui) handleCommitFixup(g *gocui.Gui, v *gocui.View) error {
return nil
}
gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Fixup"), gui.Tr.SLocalize("SureFixupThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Fixup"), gui.Tr.SLocalize("SureFixupThisCommit"), func(g *gocui.Gui, v *gocui.View) error {
return gui.WithWaitingStatus(gui.Tr.SLocalize("FixingStatus"), func() error {
err := gui.GitCommand.InteractiveRebase(gui.State.Commits, gui.State.Panels.Commits.SelectedLine, "fixup")
return gui.handleGenericMergeCommandResult(err)
})
}, nil)
return nil
}
func (gui *Gui) handleRenameCommit(g *gocui.Gui, v *gocui.View) error {
@@ -264,21 +226,6 @@ func (gui *Gui) handleMidRebaseCommand(action string) (bool, error) {
return true, gui.refreshCommits(gui.g)
}
// handleMoveTodoDown like handleMidRebaseCommand but for moving an item up in the todo list
func (gui *Gui) handleMoveTodoDown(index int) (bool, error) {
selectedCommit := gui.State.Commits[index]
if selectedCommit.Status != "rebasing" {
return false, nil
}
if gui.State.Commits[index+1].Status != "rebasing" {
return true, nil
}
if err := gui.GitCommand.MoveTodoDown(index); err != nil {
return true, gui.createErrorPanel(gui.g, err.Error())
}
return true, gui.refreshCommits(gui.g)
}
func (gui *Gui) handleCommitDelete(g *gocui.Gui, v *gocui.View) error {
applied, err := gui.handleMidRebaseCommand("drop")
if err != nil {
@@ -504,7 +451,7 @@ func (gui *Gui) setDiffMode() {
v.Title = gui.Tr.SLocalize("CommitsTitle")
}
gui.refreshCommits(gui.g)
_ = gui.refreshCommits(gui.g)
}
func (gui *Gui) hasCommit(commits []*commands.Commit, target string) (int, bool) {
@@ -623,7 +570,9 @@ func (gui *Gui) onCommitsTabClick(tabIndex int) error {
func (gui *Gui) switchCommitsPanelContext(context string) error {
commitsView := gui.getCommitsView()
commitsView.Context = context
gui.onSearchEscape()
if err := gui.onSearchEscape(); err != nil {
return err
}
contextTabIndexMap := map[string]int{
"branch-commits": 0,
+2 -10
View File
@@ -122,9 +122,7 @@ func (gui *Gui) createPopupPanel(g *gocui.Gui, currentView *gocui.View, title, p
}()
}
if err := gui.renderString(g, "confirmation", prompt); err != nil {
return err
}
gui.renderString(g, "confirmation", prompt)
return gui.setKeyBindings(g, handleConfirm, handleClose, returnFocusOnClose)
})
return nil
@@ -151,19 +149,13 @@ func (gui *Gui) setKeyBindings(g *gocui.Gui, handleConfirm, handleClose func(*go
"keyBindConfirm": "enter",
},
)
if err := gui.renderString(g, "options", actions); err != nil {
return err
}
gui.renderString(g, "options", actions)
if err := g.SetKeybinding("confirmation", nil, gocui.KeyEnter, gocui.ModNone, gui.wrappedConfirmationFunction(handleConfirm, returnFocusOnClose)); err != nil {
return err
}
return g.SetKeybinding("confirmation", nil, gocui.KeyEsc, gocui.ModNone, gui.wrappedConfirmationFunction(handleClose, returnFocusOnClose))
}
func (gui *Gui) createMessagePanel(g *gocui.Gui, currentView *gocui.View, title, prompt string) error {
return gui.createPopupPanel(g, currentView, title, prompt, false, true, false, nil, nil)
}
// createSpecificErrorPanel allows you to create an error popup, specifying the
// view to be focused when the user closes the popup, and a boolean specifying
// whether we will log the error. If the message may include a user password,
-1
View File
@@ -16,5 +16,4 @@ func (gui *Gui) changeMainViewsContext(context string) {
}
gui.State.MainContext = context
return
}
+2 -1
View File
@@ -82,7 +82,8 @@ func (gui *Gui) handleCredentialsViewFocused(g *gocui.Gui, v *gocui.View) error
"keyBindConfirm": "enter",
},
)
return gui.renderString(g, "options", message)
gui.renderString(g, "options", message)
return nil
}
// HandleCredentialsPopup handles the views after executing a command that might ask for credentials
+4 -2
View File
@@ -23,11 +23,13 @@ type fileWatcher struct {
}
func NewFileWatcher(log *logrus.Entry) *fileWatcher {
watcher, err := fsnotify.NewWatcher()
log.Error(err)
// TODO: get this going again, and ensure we don't see any crashes from it
return &fileWatcher{
Disabled: true,
}
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Error(err)
return &fileWatcher{
+24 -36
View File
@@ -37,9 +37,7 @@ func (gui *Gui) selectFile(alreadySelected bool) error {
return gui.newStringTask("main", gui.Tr.SLocalize("NoChangedFiles"))
}
if err := gui.focusPoint(0, gui.State.Panels.Files.SelectedLine, len(gui.State.Files), gui.getFilesView()); err != nil {
return err
}
gui.getFilesView().FocusPoint(0, gui.State.Panels.Files.SelectedLine)
if file.HasInlineMergeConflicts {
gui.getMainView().Title = gui.Tr.SLocalize("MergeConflictsTitle")
@@ -188,9 +186,12 @@ func (gui *Gui) handleFilePress(g *gocui.Gui, v *gocui.View) error {
}
if file.HasUnstagedChanges {
gui.GitCommand.StageFile(file.Name)
err = gui.GitCommand.StageFile(file.Name)
} else {
gui.GitCommand.UnStageFile(file.Name, file.Tracked)
err = gui.GitCommand.UnStageFile(file.Name, file.Tracked)
}
if err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
if err := gui.refreshFiles(); err != nil {
@@ -268,9 +269,7 @@ func (gui *Gui) handleWIPCommitPress(g *gocui.Gui, filesView *gocui.View) error
return gui.createErrorPanel(gui.g, gui.Tr.SLocalize("SkipHookPrefixNotConfigured"))
}
if err := gui.renderString(g, "commitMessage", skipHookPreifx); err != nil {
return err
}
gui.renderString(g, "commitMessage", skipHookPreifx)
if err := gui.getCommitMessageView().SetCursor(len(skipHookPreifx), 0); err != nil {
return err
}
@@ -284,8 +283,14 @@ func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
}
commitMessageView := gui.getCommitMessageView()
g.Update(func(g *gocui.Gui) error {
g.SetViewOnTop("commitMessage")
gui.switchFocus(g, filesView, commitMessageView)
if _, err := g.SetViewOnTop("commitMessage"); err != nil {
return err
}
if err := gui.switchFocus(g, filesView, commitMessageView); err != nil {
return err
}
gui.RenderCommitLength()
return nil
})
@@ -394,24 +399,20 @@ func (gui *Gui) catSelectedFile(g *gocui.Gui) (string, error) {
func (gui *Gui) handlePullFiles(g *gocui.Gui, v *gocui.View) error {
// if we have no upstream branch we need to set that first
_, pullables := gui.GitCommand.GetCurrentBranchUpstreamDifferenceCount()
currentBranchName, err := gui.GitCommand.CurrentBranchName()
if err != nil {
return err
}
if pullables == "?" {
currentBranch := gui.currentBranch()
if currentBranch.Pullables == "?" {
// see if we have this branch in our config with an upstream
conf, err := gui.GitCommand.Repo.Config()
if err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
for branchName, branch := range conf.Branches {
if branchName == currentBranchName {
if branchName == currentBranch.Name {
return gui.pullFiles(v, fmt.Sprintf("%s %s", branch.Remote, branchName))
}
}
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("EnterUpstream"), "origin/"+currentBranchName, func(g *gocui.Gui, v *gocui.View) error {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("EnterUpstream"), "origin/"+currentBranch.Name, func(g *gocui.Gui, v *gocui.View) error {
upstream := gui.trimmedContent(v)
if err := gui.GitCommand.SetUpstreamBranch(upstream); err != nil {
errorMessage := err.Error()
@@ -462,28 +463,24 @@ func (gui *Gui) pushWithForceFlag(g *gocui.Gui, v *gocui.View, force bool, upstr
func (gui *Gui) pushFiles(g *gocui.Gui, v *gocui.View) error {
// if we have pullables we'll ask if the user wants to force push
_, pullables := gui.GitCommand.GetCurrentBranchUpstreamDifferenceCount()
currentBranchName, err := gui.GitCommand.CurrentBranchName()
if err != nil {
return err
}
currentBranch := gui.currentBranch()
if pullables == "?" {
if currentBranch.Pullables == "?" {
// see if we have this branch in our config with an upstream
conf, err := gui.GitCommand.Repo.Config()
if err != nil {
return gui.createErrorPanel(gui.g, err.Error())
}
for branchName, branch := range conf.Branches {
if branchName == currentBranchName {
if branchName == currentBranch.Name {
return gui.pushWithForceFlag(g, v, false, "", fmt.Sprintf("%s %s", branch.Remote, branchName))
}
}
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("EnterUpstream"), "origin "+currentBranchName, func(g *gocui.Gui, v *gocui.View) error {
return gui.createPromptPanel(g, v, gui.Tr.SLocalize("EnterUpstream"), "origin "+currentBranch.Name, func(g *gocui.Gui, v *gocui.View) error {
return gui.pushWithForceFlag(g, v, false, gui.trimmedContent(v), "")
})
} else if pullables == "0" {
} else if currentBranch.Pullables == "0" {
return gui.pushWithForceFlag(g, v, false, "", "")
}
return gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("ForcePush"), gui.Tr.SLocalize("ForcePushPrompt"), func(g *gocui.Gui, v *gocui.View) error {
@@ -509,15 +506,6 @@ func (gui *Gui) handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error {
return gui.refreshMergePanel()
}
func (gui *Gui) handleAbortMerge(g *gocui.Gui, v *gocui.View) error {
if err := gui.GitCommand.AbortMerge(); err != nil {
return gui.createErrorPanel(g, err.Error())
}
gui.createMessagePanel(g, v, "", gui.Tr.SLocalize("MergeAborted"))
gui.refreshStatus(g)
return gui.refreshFiles()
}
func (gui *Gui) openFile(filename string) error {
if err := gui.OSCommand.OpenFile(filename); err != nil {
return gui.createErrorPanel(gui.g, err.Error())
+22 -23
View File
@@ -24,7 +24,6 @@ import (
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands"
"github.com/jesseduffield/lazygit/pkg/config"
"github.com/jesseduffield/lazygit/pkg/gui/presentation"
"github.com/jesseduffield/lazygit/pkg/i18n"
"github.com/jesseduffield/lazygit/pkg/tasks"
"github.com/jesseduffield/lazygit/pkg/theme"
@@ -81,7 +80,7 @@ type Gui struct {
GitCommand *commands.GitCommand
OSCommand *commands.OSCommand
SubProcess *exec.Cmd
State guiState
State *guiState
Config config.AppConfigurer
Tr *i18n.Localizer
Errors SentinelErrors
@@ -221,7 +220,7 @@ type guiState struct {
// NewGui builds a new gui handler
func NewGui(log *logrus.Entry, gitCommand *commands.GitCommand, oSCommand *commands.OSCommand, tr *i18n.Localizer, config config.AppConfigurer, updater *updates.Updater) (*Gui, error) {
initialState := guiState{
initialState := &guiState{
Files: make([]*commands.File, 0),
PreviousView: "files",
Commits: make([]*commands.Commit, 0),
@@ -278,6 +277,10 @@ func (gui *Gui) nextScreenMode(g *gocui.Gui, v *gocui.View) error {
if err := gui.refreshCommitsViewWithSelection(); err != nil {
return err
}
// same with branches
if err := gui.refreshBranchesViewWithSelection(); err != nil {
return err
}
return nil
}
@@ -288,6 +291,10 @@ func (gui *Gui) prevScreenMode(g *gocui.Gui, v *gocui.View) error {
if err := gui.refreshCommitsViewWithSelection(); err != nil {
return err
}
// same with branches
if err := gui.refreshBranchesViewWithSelection(); err != nil {
return err
}
return nil
}
@@ -381,15 +388,11 @@ func (gui *Gui) onFocusLost(v *gocui.View, newView *gocui.View) error {
return nil
}
if v.IsSearching() && newView.Name() != "search" {
gui.onSearchEscape()
if err := gui.onSearchEscape(); err != nil {
return err
}
}
switch v.Name() {
case "branches":
if v.Context == "local-branches" {
// This stops the branches panel from showing the upstream/downstream changes to the selected branch, when it loses focus
displayStrings := presentation.GetBranchListDisplayStrings(gui.State.Branches, false, -1)
gui.renderDisplayStrings(gui.getBranchesView(), displayStrings)
}
case "main":
// if we have lost focus to a first-class panel, we need to do some cleanup
gui.changeMainViewsContext("normal")
@@ -518,7 +521,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
_, _ = g.SetViewOnBottom("limit")
g.DeleteView("limit")
_ = g.DeleteView("limit")
sidePanelWidthRatio := gui.Config.GetUserConfig().GetFloat64("gui.sidePanelWidth")
@@ -538,7 +541,6 @@ func (gui *Gui) layout(g *gocui.Gui) error {
}
}
panelSplitX := width - 1
mainPanelLeft := leftSideWidth + 1
mainPanelRight := width - 1
secondaryPanelLeft := width - 1
@@ -547,7 +549,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
if gui.State.SplitMainPanel {
if gui.State.ScreenMode == SCREEN_FULL {
mainPanelLeft = 0
panelSplitX = width/2 - 4
panelSplitX := width/2 - 4
mainPanelRight = panelSplitX
secondaryPanelLeft = panelSplitX + 1
} else if width < 220 {
@@ -558,7 +560,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
units := 5
leftSideWidth = width / units
mainPanelLeft = leftSideWidth + 1
panelSplitX = (1 + ((units - 1) / 2)) * width / units
panelSplitX := (1 + ((units - 1) / 2)) * width / units
mainPanelRight = panelSplitX
secondaryPanelLeft = panelSplitX + 1
}
@@ -693,7 +695,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
if err.Error() != "unknown view" {
return err
}
g.SetViewOnBottom("commitMessage")
_, _ = g.SetViewOnBottom("commitMessage")
commitMessageView.Title = gui.Tr.SLocalize("CommitMessage")
commitMessageView.FgColor = textColor
commitMessageView.Editable = true
@@ -765,9 +767,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
v.BgColor = gocui.ColorDefault
v.FgColor = gocui.ColorGreen
v.Frame = false
if err := gui.renderString(g, "information", information); err != nil {
return err
}
gui.renderString(g, "information", information)
// doing this here because it'll only happen once
if err := gui.onInitialViewsCreation(); err != nil {
@@ -812,9 +812,7 @@ func (gui *Gui) layout(g *gocui.Gui) error {
continue
}
// check if the selected line is now out of view and if so refocus it
if err := gui.focusPoint(0, listView.selectedLine, listView.lineCount, listView.view); err != nil {
return err
}
listView.view.FocusPoint(0, listView.selectedLine)
}
mainViewWidth, mainViewHeight := gui.getMainView().Size()
@@ -909,7 +907,8 @@ func (gui *Gui) fetch(g *gocui.Gui, v *gocui.View, canAskForCredentials bool) (u
_ = gui.createConfirmationPanel(g, v, true, gui.Tr.SLocalize("Error"), coloredMessage, close, close)
}
gui.refreshStatus(g)
_ = gui.refreshStatus(g)
return unamePassOpend, err
}
@@ -918,7 +917,7 @@ func (gui *Gui) renderGlobalOptions() error {
fmt.Sprintf("%s/%s", gui.getKeyDisplay("universal.scrollUpMain"), gui.getKeyDisplay("universal.scrollDownMain")): gui.Tr.SLocalize("scroll"),
fmt.Sprintf("%s %s %s %s", gui.getKeyDisplay("universal.prevBlock"), gui.getKeyDisplay("universal.nextBlock"), gui.getKeyDisplay("universal.prevItem"), gui.getKeyDisplay("universal.nextItem")): gui.Tr.SLocalize("navigate"),
fmt.Sprintf("%s/%s", gui.getKeyDisplay("universal.return"), gui.getKeyDisplay("universal.quit")): gui.Tr.SLocalize("close"),
fmt.Sprintf("%s", gui.getKeyDisplay("universal.optionMenu")): gui.Tr.SLocalize("menu"),
gui.getKeyDisplay("universal.optionMenu"): gui.Tr.SLocalize("menu"),
"1-5": gui.Tr.SLocalize("jump"),
})
}
+33 -21
View File
@@ -162,15 +162,15 @@ func (gui *Gui) getKeyDisplay(name string) string {
func GetKeyDisplay(key interface{}) string {
keyInt := 0
switch key.(type) {
switch key := key.(type) {
case rune:
keyInt = int(key.(rune))
keyInt = int(key)
case gocui.Key:
value, ok := keyMapReversed[key.(gocui.Key)]
value, ok := keyMapReversed[key]
if ok {
return value
}
keyInt = int(key.(gocui.Key))
keyInt = int(key)
}
return string(keyInt)
@@ -295,10 +295,11 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Description: gui.Tr.SLocalize("refresh"),
},
{
ViewName: "",
Key: gui.getKey("universal.optionMenu"),
Modifier: gocui.ModNone,
Handler: gui.handleCreateOptionsMenu,
ViewName: "",
Key: gui.getKey("universal.optionMenu"),
Modifier: gocui.ModNone,
Handler: gui.handleCreateOptionsMenu,
Description: gui.Tr.SLocalize("openMenu"),
},
{
ViewName: "",
@@ -568,6 +569,14 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleCreateResetToBranchMenu,
Description: gui.Tr.SLocalize("viewResetOptions"),
},
{
ViewName: "branches",
Contexts: []string{"local-branches"},
Key: gui.getKey("branches.renameBranch"),
Modifier: gocui.ModNone,
Handler: gui.handleRenameBranch,
Description: gui.Tr.SLocalize("renameBranch"),
},
{
ViewName: "branches",
Contexts: []string{"tags"},
@@ -657,10 +666,11 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handlePrevCommitsTab,
},
{
ViewName: "commits",
Key: gui.getKey("universal.startSearch"),
Modifier: gocui.ModNone,
Handler: gui.handleOpenSearchForCommitsPanel,
ViewName: "commits",
Key: gui.getKey("universal.startSearch"),
Modifier: gocui.ModNone,
Handler: gui.handleOpenSearchForCommitsPanel,
Description: gui.Tr.SLocalize("startSearch"),
},
{
ViewName: "commits",
@@ -892,16 +902,18 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
Handler: gui.handleCloseCredentialsView,
},
{
ViewName: "menu",
Key: gui.getKey("universal.return"),
Modifier: gocui.ModNone,
Handler: gui.handleMenuClose,
ViewName: "menu",
Key: gui.getKey("universal.return"),
Modifier: gocui.ModNone,
Handler: gui.handleMenuClose,
Description: gui.Tr.SLocalize("closeMenu"),
},
{
ViewName: "menu",
Key: gui.getKey("universal.quit"),
Modifier: gocui.ModNone,
Handler: gui.handleMenuClose,
ViewName: "menu",
Key: gui.getKey("universal.quit"),
Modifier: gocui.ModNone,
Handler: gui.handleMenuClose,
Description: gui.Tr.SLocalize("closeMenu"),
},
{
ViewName: "information",
@@ -1454,7 +1466,7 @@ func (gui *Gui) GetInitialKeybindings() []*Binding {
// we need a specific keybinding for the commits panel beacuse it usually lazyloads commits
if listView.viewName != "commits" {
bindings = append(bindings, &Binding{ViewName: listView.viewName, Contexts: []string{listView.context}, Key: gui.getKey("universal.startSearch"), Modifier: gocui.ModNone, Handler: gui.handleOpenSearch})
bindings = append(bindings, &Binding{ViewName: listView.viewName, Contexts: []string{listView.context}, Key: gui.getKey("universal.startSearch"), Modifier: gocui.ModNone, Handler: gui.handleOpenSearch, Description: gui.Tr.SLocalize("startSearch")})
}
}
+4 -2
View File
@@ -88,7 +88,8 @@ func (gui *Gui) refreshLineByLinePanel(diff string, secondaryDiff string, second
}
gui.g.Update(func(*gocui.Gui) error {
return gui.setViewContent(gui.g, gui.getSecondaryView(), secondaryPatchParser.Render(-1, -1, nil))
gui.setViewContent(gui.g, gui.getSecondaryView(), secondaryPatchParser.Render(-1, -1, nil))
return nil
})
return false, nil
@@ -241,7 +242,8 @@ func (gui *Gui) refreshMainView() error {
mainView.Wrap = false
gui.g.Update(func(*gocui.Gui) error {
return gui.setViewContent(gui.g, gui.getMainView(), colorDiff)
gui.setViewContent(gui.g, gui.getMainView(), colorDiff)
return nil
})
return nil
+2 -1
View File
@@ -17,7 +17,8 @@ type menuItem struct {
// list panel functions
func (gui *Gui) handleMenuSelect(g *gocui.Gui, v *gocui.View) error {
return gui.focusPoint(0, gui.State.Panels.Menu.SelectedLine, gui.State.MenuItemCount, v)
v.FocusPoint(0, gui.State.Panels.Menu.SelectedLine)
return nil
}
// specific functions
+12 -6
View File
@@ -151,13 +151,19 @@ func (gui *Gui) handlePopFileSnapshot(g *gocui.Gui, v *gocui.View) error {
if err != nil {
return err
}
ioutil.WriteFile(gitFile.Name, []byte(prevContent), 0644)
if err := ioutil.WriteFile(gitFile.Name, []byte(prevContent), 0644); err != nil {
return err
}
return gui.refreshMergePanel()
}
func (gui *Gui) handlePickHunk(g *gocui.Gui, v *gocui.View) error {
conflict := gui.State.Panels.Merging.Conflicts[gui.State.Panels.Merging.ConflictIndex]
gui.pushFileSnapshot(g)
if err := gui.pushFileSnapshot(g); err != nil {
return err
}
pick := "bottom"
if gui.State.Panels.Merging.ConflictTop {
pick = "top"
@@ -178,7 +184,9 @@ func (gui *Gui) handlePickHunk(g *gocui.Gui, v *gocui.View) error {
func (gui *Gui) handlePickBothHunks(g *gocui.Gui, v *gocui.View) error {
conflict := gui.State.Panels.Merging.Conflicts[gui.State.Panels.Merging.ConflictIndex]
gui.pushFileSnapshot(g)
if err := gui.pushFileSnapshot(g); err != nil {
return err
}
err := gui.resolveConflict(g, conflict, "both")
if err != nil {
panic(err)
@@ -215,9 +223,7 @@ func (gui *Gui) refreshMergePanel() error {
mainView := gui.getMainView()
mainView.Wrap = false
if err := gui.setViewContent(gui.g, mainView, content); err != nil {
return err
}
gui.setViewContent(gui.g, mainView, content)
gui.Log.Warn("scrolling to conflict")
if err := gui.scrollToConflict(gui.g); err != nil {
return err
+6 -3
View File
@@ -18,7 +18,8 @@ func (gui *Gui) refreshPatchBuildingPanel(selectedLineIdx int) error {
// get diff from commit file that's currently selected
commitFile := gui.getSelectedCommitFile(gui.g)
if commitFile == nil {
return gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil
}
diff, err := gui.GitCommand.ShowCommitFile(commitFile.Sha, commitFile.Name, true)
@@ -57,7 +58,8 @@ func (gui *Gui) handleToggleSelectionForPatch(g *gocui.Gui, v *gocui.View) error
// add range of lines to those set for the file
commitFile := gui.getSelectedCommitFile(gui.g)
if commitFile == nil {
return gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
gui.renderString(gui.g, "commitFiles", gui.Tr.SLocalize("NoCommiteFiles"))
return nil
}
toggleFunc(commitFile.Name, state.FirstLineIdx, state.LastLineIdx)
@@ -92,7 +94,8 @@ func (gui *Gui) refreshSecondaryPatchPanel() error {
secondaryView.Wrap = false
gui.g.Update(func(*gocui.Gui) error {
return gui.setViewContent(gui.g, gui.getSecondaryView(), gui.GitCommand.PatchManager.RenderAggregatedPatchColored(false))
gui.setViewContent(gui.g, gui.getSecondaryView(), gui.GitCommand.PatchManager.RenderAggregatedPatchColored(false))
return nil
})
} else {
gui.State.SplitMainPanel = false
+20 -7
View File
@@ -10,25 +10,38 @@ import (
"github.com/jesseduffield/lazygit/pkg/utils"
)
func GetBranchListDisplayStrings(branches []*commands.Branch, isFocused bool, selectedLine int) [][]string {
func GetBranchListDisplayStrings(branches []*commands.Branch, fullDescription bool) [][]string {
lines := make([][]string, len(branches))
for i := range branches {
showUpstreamDifferences := isFocused && i == selectedLine
lines[i] = getBranchDisplayStrings(branches[i], showUpstreamDifferences)
lines[i] = getBranchDisplayStrings(branches[i], fullDescription)
}
return lines
}
// getBranchDisplayStrings returns the display string of branch
func getBranchDisplayStrings(b *commands.Branch, showUpstreamDifferences bool) []string {
func getBranchDisplayStrings(b *commands.Branch, fullDescription bool) []string {
displayName := utils.ColoredString(b.Name, GetBranchColor(b.Name))
if showUpstreamDifferences && b.Pushables != "" && b.Pullables != "" {
displayName = fmt.Sprintf("%s ↑%s↓%s", displayName, b.Pushables, b.Pullables)
if b.Pushables != "" && b.Pullables != "" && b.Pushables != "?" && b.Pullables != "?" {
trackColor := color.FgYellow
if b.Pushables == "0" && b.Pullables == "0" {
trackColor = color.FgGreen
}
track := utils.ColoredString(fmt.Sprintf("↑%s↓%s", b.Pushables, b.Pullables), trackColor)
displayName = fmt.Sprintf("%s %s", displayName, track)
}
return []string{b.Recency, displayName}
recencyColor := color.FgCyan
if b.Recency == " *" {
recencyColor = color.FgGreen
}
if fullDescription {
return []string{utils.ColoredString(b.Recency, recencyColor), displayName, utils.ColoredString(b.UpstreamName, color.FgYellow)}
}
return []string{utils.ColoredString(b.Recency, recencyColor), displayName}
}
// GetBranchColor branch color
+3 -3
View File
@@ -17,11 +17,11 @@ func (gui *Gui) handleCreateRebaseOptionsMenu(g *gocui.Gui, v *gocui.View) error
menuItems := make([]*menuItem, len(options))
for i, option := range options {
// note to self. Never, EVER, close over loop variables in a function
innerOption := option
option := option
menuItems[i] = &menuItem{
displayString: innerOption,
displayString: option,
onPress: func() error {
return gui.genericMergeCommand(innerOption)
return gui.genericMergeCommand(option)
},
}
}
+1 -3
View File
@@ -34,9 +34,7 @@ func (gui *Gui) handleReflogCommitSelect(g *gocui.Gui, v *gocui.View) error {
if commit == nil {
return gui.newStringTask("main", "No reflog history")
}
if err := gui.focusPoint(0, gui.State.Panels.ReflogCommits.SelectedLine, len(gui.State.ReflogCommits), v); err != nil {
return err
}
v.FocusPoint(0, gui.State.Panels.ReflogCommits.SelectedLine)
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowCmdStr(commit.Sha),
+1 -4
View File
@@ -38,10 +38,7 @@ func (gui *Gui) handleRemoteBranchSelect(g *gocui.Gui, v *gocui.View) error {
return gui.newStringTask("main", "No branches for this remote")
}
gui.focusPoint(0, gui.State.Panels.Menu.SelectedLine, gui.State.MenuItemCount, v)
if err := gui.focusPoint(0, gui.State.Panels.RemoteBranches.SelectedLine, len(gui.State.RemoteBranches), v); err != nil {
return err
}
v.FocusPoint(0, gui.State.Panels.RemoteBranches.SelectedLine)
branchName := fmt.Sprintf("%s/%s", remote.Name, remoteBranch.Name)
+1 -3
View File
@@ -39,9 +39,7 @@ func (gui *Gui) handleRemoteSelect(g *gocui.Gui, v *gocui.View) error {
if remote == nil {
return gui.newStringTask("main", "No remotes")
}
if err := gui.focusPoint(0, gui.State.Panels.Remotes.SelectedLine, len(gui.State.Remotes), v); err != nil {
return err
}
v.FocusPoint(0, gui.State.Panels.Remotes.SelectedLine)
return gui.newStringTask("main", fmt.Sprintf("%s\nUrls:\n%s", utils.ColoredString(remote.Name, color.FgGreen), strings.Join(remote.Urls, "\n")))
}
+7 -1
View File
@@ -23,7 +23,10 @@ func (gui *Gui) createResetMenu(ref string) error {
return gui.createErrorPanel(gui.g, err.Error())
}
gui.switchCommitsPanelContext("branch-commits")
if err := gui.switchCommitsPanelContext("branch-commits"); err != nil {
return err
}
gui.State.Panels.Commits.SelectedLine = 0
gui.State.Panels.ReflogCommits.SelectedLine = 0
@@ -33,6 +36,9 @@ func (gui *Gui) createResetMenu(ref string) error {
if err := gui.refreshFiles(); err != nil {
return err
}
if err := gui.refreshBranches(gui.g); err != nil {
return err
}
if err := gui.resetOrigin(gui.getCommitsView()); err != nil {
return err
}
+8 -5
View File
@@ -12,14 +12,19 @@ func (gui *Gui) handleOpenSearch(g *gocui.Gui, v *gocui.View) error {
gui.State.Searching.isSearching = true
gui.State.Searching.view = v
gui.renderString(gui.g, "search", "")
gui.switchFocus(gui.g, v, gui.getSearchView())
if err := gui.switchFocus(gui.g, v, gui.getSearchView()); err != nil {
return err
}
return nil
}
func (gui *Gui) handleSearch(g *gocui.Gui, v *gocui.View) error {
gui.State.Searching.searchString = gui.getSearchView().Buffer()
gui.switchFocus(gui.g, nil, gui.State.Searching.view)
if err := gui.switchFocus(gui.g, nil, gui.State.Searching.view); err != nil {
return err
}
if err := gui.State.Searching.view.Search(gui.State.Searching.searchString); err != nil {
return err
}
@@ -85,7 +90,5 @@ func (gui *Gui) handleSearchEscape(g *gocui.Gui, v *gocui.View) error {
return err
}
gui.onSearchEscape()
return nil
return gui.onSearchEscape()
}
-8
View File
@@ -159,11 +159,3 @@ func (gui *Gui) applySelection(reverse bool) error {
}
return nil
}
func (gui *Gui) handleMouseDownSecondaryWhileStaging(g *gocui.Gui, v *gocui.View) error {
state := gui.State.Panels.LineByLine
state.SecondaryFocused = !state.SecondaryFocused
return gui.refreshStagingPanel(false, -1)
}
+9 -7
View File
@@ -34,9 +34,7 @@ func (gui *Gui) handleStashEntrySelect(g *gocui.Gui, v *gocui.View) error {
if stashEntry == nil {
return gui.newStringTask("main", gui.Tr.SLocalize("NoStashEntries"))
}
if err := gui.focusPoint(0, gui.State.Panels.Stash.SelectedLine, len(gui.State.StashEntries), v); err != nil {
return err
}
v.FocusPoint(0, gui.State.Panels.Stash.SelectedLine)
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.ShowStashEntryCmdStr(stashEntry.Index),
@@ -97,9 +95,11 @@ func (gui *Gui) stashDo(g *gocui.Gui, v *gocui.View, method string) error {
return gui.createErrorPanel(g, errorMessage)
}
if err := gui.GitCommand.StashDo(stashEntry.Index, method); err != nil {
gui.createErrorPanel(g, err.Error())
return gui.createErrorPanel(g, err.Error())
}
if err := gui.refreshStashEntries(g); err != nil {
return gui.createErrorPanel(g, err.Error())
}
gui.refreshStashEntries(g)
return gui.refreshFiles()
}
@@ -109,9 +109,11 @@ func (gui *Gui) handleStashSave(stashFunc func(message string) error) error {
}
return gui.createPromptPanel(gui.g, gui.getFilesView(), gui.Tr.SLocalize("StashChanges"), "", func(g *gocui.Gui, v *gocui.View) error {
if err := stashFunc(gui.trimmedContent(v)); err != nil {
gui.createErrorPanel(g, err.Error())
return gui.createErrorPanel(g, err.Error())
}
if err := gui.refreshStashEntries(g); err != nil {
return gui.createErrorPanel(g, err.Error())
}
gui.refreshStashEntries(g)
return gui.refreshFiles()
})
}
+10 -1
View File
@@ -22,11 +22,20 @@ func (gui *Gui) refreshStatus(g *gocui.Gui) error {
// contents end up cleared
g.Update(func(*gocui.Gui) error {
v.Clear()
// TODO: base this off of the current branch
state.pushables, state.pullables = gui.GitCommand.GetCurrentBranchUpstreamDifferenceCount()
if err := gui.updateWorkTreeState(); err != nil {
return err
}
status := fmt.Sprintf("↑%s↓%s", state.pushables, state.pullables)
trackColor := color.FgYellow
if state.pushables == "0" && state.pullables == "0" {
trackColor = color.FgGreen
} else if state.pushables == "?" && state.pullables == "?" {
trackColor = color.FgRed
}
status := utils.ColoredString(fmt.Sprintf("↑%s↓%s", state.pushables, state.pullables), trackColor)
branches := gui.State.Branches
if gui.State.WorkingTreeState != "normal" {
+2 -4
View File
@@ -34,9 +34,7 @@ func (gui *Gui) handleTagSelect(g *gocui.Gui, v *gocui.View) error {
if tag == nil {
return gui.newStringTask("main", "No tags")
}
if err := gui.focusPoint(0, gui.State.Panels.Tags.SelectedLine, len(gui.State.Tags), v); err != nil {
return err
}
v.FocusPoint(0, gui.State.Panels.Tags.SelectedLine)
cmd := gui.OSCommand.ExecutableFromString(
gui.GitCommand.GetBranchGraphCmdStr(tag.Name),
@@ -57,7 +55,7 @@ func (gui *Gui) refreshTags() error {
gui.State.Tags = tags
if gui.getBranchesView().Context == "tags" {
gui.renderTagsWithSelection()
return gui.renderTagsWithSelection()
}
return nil
+2 -1
View File
@@ -59,7 +59,8 @@ func (gui *Gui) newStringTask(viewName string, str string) error {
manager := gui.getManager(view)
f := func(stop chan struct{}) error {
return gui.renderString(gui.g, viewName, str)
gui.renderString(gui.g, viewName, str)
return nil
}
if err := manager.NewTask(f); err != nil {
+1 -3
View File
@@ -47,9 +47,7 @@ func (gui *Gui) startUpdating(newVersion string) {
func (gui *Gui) onUpdateFinish(err error) error {
gui.State.Updating = false
gui.statusManager.removeStatus("updating")
if err := gui.renderString(gui.g, "appStatus", ""); err != nil {
return err
}
gui.renderString(gui.g, "appStatus", "")
if err != nil {
return gui.createErrorPanel(gui.g, "Update failed: "+err.Error())
}
+6 -33
View File
@@ -218,25 +218,18 @@ func (gui *Gui) resetOrigin(v *gocui.View) error {
return v.SetOrigin(0, 0)
}
// if the cursor down past the last item, move it to the last line
func (gui *Gui) focusPoint(cx int, cy int, lineCount int, v *gocui.View) error {
v.FocusPoint(cx, cy)
return nil
}
func (gui *Gui) cleanString(s string) string {
output := string(bom.Clean([]byte(s)))
return utils.NormalizeLinefeeds(output)
}
func (gui *Gui) setViewContent(g *gocui.Gui, v *gocui.View, s string) error {
func (gui *Gui) setViewContent(g *gocui.Gui, v *gocui.View, s string) {
v.Clear()
fmt.Fprint(v, gui.cleanString(s))
return nil
}
// renderString resets the origin of a view and sets its content
func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) error {
func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) {
g.Update(func(*gocui.Gui) error {
v, err := g.View(viewName)
if err != nil {
@@ -248,9 +241,9 @@ func (gui *Gui) renderString(g *gocui.Gui, viewName, s string) error {
if err := v.SetCursor(0, 0); err != nil {
return err
}
return gui.setViewContent(gui.g, v, s)
gui.setViewContent(gui.g, v, s)
return nil
})
return nil
}
func (gui *Gui) optionsMapToString(optionsMap map[string]string) string {
@@ -263,7 +256,8 @@ func (gui *Gui) optionsMapToString(optionsMap map[string]string) string {
}
func (gui *Gui) renderOptionsMap(optionsMap map[string]string) error {
return gui.renderString(gui.g, "options", gui.optionsMapToString(optionsMap))
gui.renderString(gui.g, "options", gui.optionsMapToString(optionsMap))
return nil
}
// TODO: refactor properly
@@ -349,22 +343,6 @@ func (gui *Gui) resizePopupPanel(g *gocui.Gui, v *gocui.View) error {
return err
}
// generalFocusLine takes a lineNumber to focus, and a bottomLine to ensure we can see
func (gui *Gui) generalFocusLine(lineNumber int, bottomLine int, v *gocui.View) error {
_, height := v.Size()
overScroll := bottomLine - height + 1
if overScroll < 0 {
overScroll = 0
}
if err := v.SetOrigin(0, overScroll); err != nil {
return err
}
if err := v.SetCursor(0, lineNumber-overScroll); err != nil {
return err
}
return nil
}
func (gui *Gui) changeSelectedLine(line *int, total int, change int) {
// TODO: find out why we're doing this
if *line == -1 {
@@ -409,11 +387,6 @@ func (gui *Gui) renderPanelOptions() error {
return gui.renderGlobalOptions()
}
func (gui *Gui) handleFocusView(g *gocui.Gui, v *gocui.View) error {
_, err := gui.g.SetCurrentView(v.Name())
return err
}
func (gui *Gui) isPopupPanel(viewName string) bool {
return viewName == "commitMessage" || viewName == "credentials" || viewName == "confirmation" || viewName == "menu"
}
+18
View File
@@ -1008,12 +1008,30 @@ func addEnglish(i18nObject *i18n.Bundle) error {
}, &i18n.Message{
ID: "prevScreenMode",
Other: "prev screen mode",
}, &i18n.Message{
ID: "startSearch",
Other: "start search",
}, &i18n.Message{
ID: "Panel",
Other: "Panel",
}, &i18n.Message{
ID: "Keybindings",
Other: "Keybindings",
}, &i18n.Message{
ID: "renameBranch",
Other: "rename branch",
}, &i18n.Message{
ID: "NewBranchNamePrompt",
Other: "Enter new branch name for branch",
}, &i18n.Message{
ID: "RenameBranchWarning",
Other: "This branch is tracking a remote. This action will only rename the local branch name, not the name of the remote branch. Continue?",
}, &i18n.Message{
ID: "openMenu",
Other: "open menu",
}, &i18n.Message{
ID: "closeMenu",
Other: "close menu",
},
)
}
+2 -4
View File
@@ -23,7 +23,6 @@ type Task struct {
type ViewBufferManager struct {
writer io.Writer
waitingTask *Task
currentTask *Task
waitingMutex sync.Mutex
taskIDMutex sync.Mutex
@@ -79,7 +78,7 @@ func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, linesToRead i
loadingMutex.Lock()
if !loaded {
m.beforeStart()
m.writer.Write([]byte("loading..."))
_, _ = m.writer.Write([]byte("loading..."))
m.refreshView()
}
loadingMutex.Unlock()
@@ -111,7 +110,7 @@ func (m *ViewBufferManager) NewCmdTask(r io.Reader, cmd *exec.Cmd, linesToRead i
m.refreshView()
break outer
}
m.writer.Write(append(scanner.Bytes(), []byte("\n")...))
_, _ = m.writer.Write(append(scanner.Bytes(), []byte("\n")...))
}
m.refreshView()
case <-stop:
@@ -223,5 +222,4 @@ func (t *Task) Stop() {
<-t.notifyStopped
t.Log.Info("received notifystopped message")
t.stopped = true
return
}
-2
View File
@@ -196,8 +196,6 @@ func TestDisplayArraysAligned(t *testing.T) {
}
}
type myStruct struct{}
// TestGetPaddedDisplayStrings is a function.
func TestGetPaddedDisplayStrings(t *testing.T) {
type scenario struct {
+1 -3
View File
@@ -83,9 +83,7 @@ func getBindingSections(mApp *app.App) []*bindingSection {
if len(binding.Contexts) == 0 {
contexts = append(contexts, "")
} else {
for _, context := range binding.Contexts {
contexts = append(contexts, context)
}
contexts = append(contexts, binding.Contexts...)
}
for _, context := range contexts {
+24 -3
View File
@@ -10,6 +10,7 @@ import (
"strings"
"sync"
"time"
"unicode"
"github.com/go-errors/errors"
@@ -466,18 +467,38 @@ func (v *View) Rewind() {
v.readOffset = 0
}
func containsUpcaseChar(str string) bool {
for _, ch := range str {
if unicode.IsUpper(ch) {
return true
}
}
return false
}
func (v *View) updateSearchPositions() {
if v.searcher.searchString != "" {
var normalizeRune func(r rune) rune
var normalizedSearchStr string
// if we have any uppercase characters we'll do a case-sensitive search
if containsUpcaseChar(v.searcher.searchString) {
normalizedSearchStr = v.searcher.searchString
normalizeRune = func(r rune) rune { return r }
} else {
normalizedSearchStr = strings.ToLower(v.searcher.searchString)
normalizeRune = unicode.ToLower
}
v.searcher.searchPositions = []cellPos{}
for y, line := range v.lines {
lineLoop:
for x, _ := range line {
if line[x].chr == rune(v.searcher.searchString[0]) {
for offset := 1; offset < len(v.searcher.searchString); offset++ {
if normalizeRune(line[x].chr) == rune(normalizedSearchStr[0]) {
for offset := 1; offset < len(normalizedSearchStr); offset++ {
if len(line)-1 < x+offset {
continue lineLoop
}
if line[x+offset].chr != rune(v.searcher.searchString[offset]) {
if normalizeRune(line[x+offset].chr) != rune(normalizedSearchStr[offset]) {
continue lineLoop
}
}
+45 -1
View File
@@ -1,4 +1,5 @@
# github.com/cloudfoundry/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21
## explicit
github.com/cloudfoundry/jibber_jabber
# github.com/davecgh/go-spew v1.1.1
github.com/davecgh/go-spew/spew
@@ -10,13 +11,21 @@ github.com/emirpasic/gods/trees
github.com/emirpasic/gods/trees/binaryheap
github.com/emirpasic/gods/utils
# github.com/fatih/color v1.7.0
## explicit
github.com/fatih/color
# github.com/fsnotify/fsnotify v1.4.7
## explicit
github.com/fsnotify/fsnotify
# github.com/go-errors/errors v1.0.1
## explicit
github.com/go-errors/errors
# github.com/golang-collections/collections v0.0.0-20130729185459-604e922904d3
## explicit
github.com/golang-collections/collections/stack
# github.com/golang/protobuf v1.3.2
## explicit
# github.com/google/go-cmp v0.3.1
## explicit
# github.com/hashicorp/hcl v1.0.0
github.com/hashicorp/hcl
github.com/hashicorp/hcl/hcl/ast
@@ -29,61 +38,86 @@ github.com/hashicorp/hcl/json/parser
github.com/hashicorp/hcl/json/scanner
github.com/hashicorp/hcl/json/token
# github.com/integrii/flaggy v1.4.0
## explicit
github.com/integrii/flaggy
# github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
github.com/jbenet/go-context/io
# github.com/jesseduffield/gocui v0.3.1-0.20200301081700-d6e485450113
# github.com/jesseduffield/gocui v0.3.1-0.20200309001002-7765949e1c8a
## explicit
github.com/jesseduffield/gocui
# github.com/jesseduffield/pty v1.2.1
## explicit
github.com/jesseduffield/pty
# github.com/jesseduffield/termbox-go v0.0.0-20200130214842-1d31d1faa3c9
## explicit
github.com/jesseduffield/termbox-go
# github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
## explicit
github.com/kardianos/osext
# github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd
github.com/kevinburke/ssh_config
# github.com/konsorten/go-windows-terminal-sequences v1.0.2
## explicit
github.com/konsorten/go-windows-terminal-sequences
# github.com/magiconair/properties v1.8.1
github.com/magiconair/properties
# github.com/mattn/go-colorable v0.1.4
## explicit
github.com/mattn/go-colorable
# github.com/mattn/go-isatty v0.0.11
## explicit
github.com/mattn/go-isatty
# github.com/mattn/go-runewidth v0.0.8
## explicit
github.com/mattn/go-runewidth
# github.com/mgutz/str v1.2.0
## explicit
github.com/mgutz/str
# github.com/mitchellh/go-homedir v1.1.0
github.com/mitchellh/go-homedir
# github.com/mitchellh/gox v1.0.1
## explicit
# github.com/mitchellh/mapstructure v1.1.2
github.com/mitchellh/mapstructure
# github.com/nicksnyder/go-i18n/v2 v2.0.3
## explicit
github.com/nicksnyder/go-i18n/v2/i18n
github.com/nicksnyder/go-i18n/v2/internal
github.com/nicksnyder/go-i18n/v2/internal/plural
# github.com/onsi/ginkgo v1.10.3
## explicit
# github.com/onsi/gomega v1.7.1
## explicit
# github.com/pelletier/go-toml v1.6.0
## explicit
github.com/pelletier/go-toml
# github.com/pmezard/go-difflib v1.0.0
github.com/pmezard/go-difflib/difflib
# github.com/sergi/go-diff v1.0.0
github.com/sergi/go-diff/diffmatchpatch
# github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0
## explicit
github.com/shibukawa/configdir
# github.com/sirupsen/logrus v1.4.2
## explicit
github.com/sirupsen/logrus
# github.com/spf13/afero v1.2.2
## explicit
github.com/spf13/afero
github.com/spf13/afero/mem
# github.com/spf13/cast v1.3.0
github.com/spf13/cast
# github.com/spf13/jwalterweatherman v1.1.0
## explicit
github.com/spf13/jwalterweatherman
# github.com/spf13/pflag v1.0.5
## explicit
github.com/spf13/pflag
# github.com/spf13/viper v1.6.1
## explicit
github.com/spf13/viper
# github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad
## explicit
github.com/spkg/bom
# github.com/src-d/gcfg v1.4.0
github.com/src-d/gcfg
@@ -91,14 +125,17 @@ github.com/src-d/gcfg/scanner
github.com/src-d/gcfg/token
github.com/src-d/gcfg/types
# github.com/stretchr/testify v1.4.0
## explicit
github.com/stretchr/testify/assert
# github.com/subosito/gotenv v1.2.0
github.com/subosito/gotenv
# github.com/tcnksm/go-gitconfig v0.1.2
## explicit
github.com/tcnksm/go-gitconfig
# github.com/xanzy/ssh-agent v0.2.1
github.com/xanzy/ssh-agent
# golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413
## explicit
golang.org/x/crypto/cast5
golang.org/x/crypto/chacha20
golang.org/x/crypto/curve25519
@@ -116,20 +153,25 @@ golang.org/x/crypto/ssh
golang.org/x/crypto/ssh/agent
golang.org/x/crypto/ssh/knownhosts
# golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
## explicit
golang.org/x/net/context
golang.org/x/net/internal/socks
golang.org/x/net/proxy
# golang.org/x/sys v0.0.0-20191210023423-ac6580df4449
## explicit
golang.org/x/sys/cpu
golang.org/x/sys/unix
golang.org/x/sys/windows
# golang.org/x/text v0.3.2
## explicit
golang.org/x/text/internal/language
golang.org/x/text/internal/language/compact
golang.org/x/text/internal/tag
golang.org/x/text/language
golang.org/x/text/transform
golang.org/x/text/unicode/norm
# gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15
## explicit
# gopkg.in/ini.v1 v1.51.0
gopkg.in/ini.v1
# gopkg.in/src-d/go-billy.v4 v4.3.2
@@ -139,6 +181,7 @@ gopkg.in/src-d/go-billy.v4/helper/polyfill
gopkg.in/src-d/go-billy.v4/osfs
gopkg.in/src-d/go-billy.v4/util
# gopkg.in/src-d/go-git.v4 v4.13.1
## explicit
gopkg.in/src-d/go-git.v4
gopkg.in/src-d/go-git.v4/config
gopkg.in/src-d/go-git.v4/internal/revision
@@ -183,4 +226,5 @@ gopkg.in/src-d/go-git.v4/utils/merkletrie/noder
# gopkg.in/warnings.v0 v0.1.2
gopkg.in/warnings.v0
# gopkg.in/yaml.v2 v2.2.7
## explicit
gopkg.in/yaml.v2