Compare commits

...

76 Commits

Author SHA1 Message Date
Jesse Duffield
41152881db Merge branch 'master' of https://github.com/jesseduffield/lazygit 2018-08-09 10:32:18 +10:00
Jesse Duffield
d33fff54a3 point to homebrew repo 2018-08-09 10:32:12 +10:00
Jesse Duffield
3bf621de65 Update README.md 2018-08-09 10:21:45 +10:00
Jesse Duffield
0c84055abd show error on git add --patching untracked file 2018-08-09 09:33:18 +10:00
Jesse Duffield
5d9df3ca07 Merge pull request #86 from dawidd6/patch-1
Precise supported ubuntu releases by ppa
2018-08-09 09:25:21 +10:00
Dawid Dziurla
6581bec1ce precise supported ubuntu releases by ppa 2018-08-08 23:21:41 +02:00
Jesse Duffield
ce3f81a2d3 remove github token 2018-08-09 00:26:32 +10:00
Jesse Duffield
bc479a9bf5 correct repo name 2018-08-08 23:29:59 +10:00
Jesse Duffield
83a9a6d1f5 Merge branch 'master' of https://github.com/jesseduffield/lazygit 2018-08-08 23:28:59 +10:00
Jesse Duffield
ca0b3debe9 attempt brew formula 2018-08-08 23:28:52 +10:00
Jesse Duffield
84a2b1ceb9 Update README.md 2018-08-08 23:21:35 +10:00
Jesse Duffield
5951811a8b fix releaser 2018-08-08 23:16:52 +10:00
Jesse Duffield
968f3b2c1c revert to stock standard goreleaser yml 2018-08-08 23:13:26 +10:00
Jesse Duffield
aacbb72e6c use env github token 2018-08-08 23:09:39 +10:00
Jesse Duffield
48ab294922 remove newline in github token 2018-08-08 23:06:50 +10:00
Jesse Duffield
555996642d try just pointing at the directory 2018-08-08 23:04:51 +10:00
Jesse Duffield
aad4269128 fix yml 2018-08-08 23:03:10 +10:00
Jesse Duffield
b3fbe8453f fix yml format 2018-08-08 23:00:27 +10:00
Jesse Duffield
ffac0e6420 Merge branch 'feature/gorelease' 2018-08-08 22:54:49 +10:00
Jesse Duffield
7371765d47 bring back white borders for everybody 2018-08-08 22:53:24 +10:00
Jesse Duffield
7f75808499 cleanup for goreleaser 2018-08-08 22:51:18 +10:00
Jesse Duffield
778cb14dc4 update to use goreleaser ldflags 2018-08-08 22:48:37 +10:00
Jesse Duffield
00c679a3f0 swap travis for goreleaser 2018-08-08 22:40:01 +10:00
Jesse Duffield
d9ec6f9890 switch border color back to black for osx 2018-08-08 21:53:28 +10:00
Jesse Duffield
9858bfe4c3 use brighter panels for linux 2018-08-08 21:46:56 +10:00
Jesse Duffield
feada164d0 use file glob 2018-08-08 21:22:08 +10:00
Jesse Duffield
a1706ef2ee remove 1.7 because I'm not using it 2018-08-08 21:09:51 +10:00
Jesse Duffield
1bd3aa9708 remove version number from filename and use regex to pick files to deploy 2018-08-08 21:08:05 +10:00
Jesse Duffield
d0aaf94068 use default platforms 2018-08-08 21:04:04 +10:00
Jesse Duffield
8054d85782 add more archs to travis.yml 2018-08-08 20:59:32 +10:00
Jesse Duffield
31a8be5f32 update keybindings 2018-08-08 20:53:14 +10:00
Jesse Duffield
ca04655a09 merge master/better-file-opening into master 2018-08-08 20:50:45 +10:00
Jesse Duffield
4281cc2884 add git config check and editing ability 2018-08-08 20:45:12 +10:00
Jesse Duffield
8013f18177 add test script that reads user input for subprocess testing 2018-08-08 20:44:06 +10:00
Jesse Duffield
c965333756 "opening and editing" 2018-08-08 19:46:21 +10:00
Jesse Duffield
54408a912c merge moving keybindings to its own file 2018-08-08 19:24:33 +10:00
Jesse Duffield
3839719154 "move keybindings into its own file" 2018-08-08 19:18:41 +10:00
Jesse Duffield
e8c4bf20f6 merge master 2018-08-08 19:13:13 +10:00
Jesse Duffield
fbadbdd771 version with tag 2018-08-08 18:57:27 +10:00
Jesse Duffield
c6aee678c0 bump dep 2018-08-08 18:57:03 +10:00
Jesse Duffield
c4c27262f2 allow go 1.7 to fail 2018-08-08 18:02:18 +10:00
Jesse Duffield
a253b0b897 Merge branch 'master' of https://github.com/jesseduffield/lazygit 2018-08-08 08:59:09 +10:00
Jesse Duffield
5ca47c3f47 merge master 2018-08-08 08:58:24 +10:00
Jesse Duffield
456c593c72 Update README.md 2018-08-08 08:49:37 +10:00
Jesse Duffield
3b264806ef add version number 2018-08-08 08:32:52 +10:00
Jesse Duffield
92e75d4602 "step one towards dealing with gpgsign" 2018-08-08 08:24:24 +10:00
Jesse Duffield
7add598235 give everybody permission 2018-08-08 08:13:40 +10:00
Jesse Duffield
2853aba951 appending version number to binaries 2018-08-08 08:07:43 +10:00
Jesse Duffield
8cc444182f make binaries executable 2018-08-08 08:02:33 +10:00
Jesse Duffield
2a25ce014b use correct filenames 2018-08-08 07:56:55 +10:00
Jesse Duffield
411c02324f use gox default output 2018-08-08 07:54:46 +10:00
Jesse Duffield
2f50cbf2b8 use gox default output 2018-08-08 07:54:11 +10:00
Jesse Duffield
417cb97dc6 add file to command 2018-08-08 07:49:45 +10:00
Jesse Duffield
fb5d25c9e9 Merge branch 'master' into feature/better-file-opening 2018-08-08 07:41:55 +10:00
Jesse Duffield
f580572e70 Merge branch 'master' of https://github.com/jesseduffield/lazygit 2018-08-08 07:40:04 +10:00
Jesse Duffield
ba30e9e450 log some travis ci stuff 2018-08-08 07:39:58 +10:00
Nicolas Borboën
30d79bfa2c Merge remote-tracking branch 'upstream/master' into ponsfrilus/cli-version 2018-08-07 16:17:01 +02:00
Nicolas Borboën
4d9d2b134f Add lazygit --v version
* Recover Rev and Build Date from build args
* Moved `debuggingPointer` and `versionFlag` to `var()`
* Print version and exit in case of `-v` or `--v`
2018-08-07 16:15:23 +02:00
Nicolas Borboën
6cb0a14f33 Add build date to build cmd 2018-08-07 16:11:53 +02:00
Jesse Duffield
51d3e679bf Merge pull request #66 from ponsfrilus/patch-1
[fix] link to code of conduct
2018-08-07 23:21:22 +10:00
Jesse Duffield
bab884f1df nonrelative path to binaries 2018-08-07 23:18:18 +10:00
Jesse Duffield
1730089b09 try master branch for dep 2018-08-07 23:04:55 +10:00
Nicolas Borboën
8c823965ab [fix] link to code of conduct 2018-08-07 14:59:22 +02:00
Jesse Duffield
aa6a0bd43b Merge branch 'master' of https://github.com/jesseduffield/lazygit 2018-08-07 22:53:38 +10:00
Jesse Duffield
d781a8e650 if you had one shot 2018-08-07 22:53:29 +10:00
Jesse Duffield
dd6cdc02f0 Merge pull request #65 from ponsfrilus/ponsfrilus/coc-cg
Code of Conduct + Contributing guide proposal
2018-08-07 22:46:43 +10:00
Nicolas Borboën
2311675d08 It appears that markdown files are better handeled by GitHub with extensions. 2018-08-07 14:38:58 +02:00
Nicolas Borboën
cda365a93f Contributing guide proposal 2018-08-07 14:32:04 +02:00
Nicolas Borboën
a6cb0feff1 Contributing guide added
This is a mix between
  * https://gist.github.com/PurpleBooth/b24679402957c63ec426
  *
https://github.com/thoughtbot/factory_bot_rails/blob/master/CONTRIBUTING.md
  * https://gist.github.com/briandk/3d2e8b3ec8daf5a27a62
  * https://github.com/nayafia/contributing-template
2018-08-07 14:28:52 +02:00
Nicolas Borboën
ade0dc447e Code of conduct added
* Based on contributor-covenant.org
2018-08-07 14:27:11 +02:00
Jesse Duffield
5a624764a8 support patched adding 2018-08-07 19:50:35 +10:00
Jesse Duffield
b541987007 fixup 2018-08-07 18:37:48 +10:00
Jesse Duffield
2d4801c39d merge updated keybinding structure 2018-08-07 18:14:49 +10:00
Jesse Duffield
7fe54e889d merge master 2018-08-07 18:13:45 +10:00
Jesse Duffield
f6a9c727fa run subprocess cleanly 2018-08-07 18:05:43 +10:00
Jesse Duffield
9067c3be3e handling file edit 2018-08-06 23:29:00 +10:00
15 changed files with 562 additions and 164 deletions

54
.goreleaser.yml Normal file
View File

@@ -0,0 +1,54 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
builds:
- env:
- CGO_ENABLED=0
goos:
- freebsd
- windows
- darwin
- linux
goarch:
- amd64
- arm
- arm64
archive:
replacements:
darwin: Darwin
linux: Linux
windows: Windows
386: i386
amd64: x86_64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
brew:
# Reporitory to push the tap to.
github:
owner: jesseduffield
name: homebrew-lazygit
# Your app's homepage.
# Default is empty.
homepage: "https://github.com/jesseduffield/lazygit/"
# Your app's description.
# Default is empty.
description: "A simple terminal UI for git commands, written in Go"
# # Packages your package depends on.
# dependencies:
# - git
# - zsh
# # Packages that conflict with your package.
# conflicts:
# - svn
# - bash

View File

@@ -1,40 +0,0 @@
language: go
sudo: false
env:
- DEP_VERSION="0.5.0"
matrix:
include:
- go: 1.x
env: LATEST=true
- go: 1.7
- go: tip
allow_failures:
- go: tip
before_install:
# Download the binary to bin folder in $GOPATH
- curl -L -s https://github.com/golang/dep/releases/download/v${DEP_VERSION}/dep-linux-386 -o $GOPATH/bin/dep
# Make the binary executable
- chmod +x $GOPATH/bin/dep
- ls $GOPATH/bin/
- dep ensure
- go get github.com/mitchellh/gox
install:
-
script:
# - go get -v ./...
# - diff -u <(echo -n) <(gofmt -d .) # can't make gofmt ignore vendor directory
# - go vet $(go list ./... | grep -v /vendor/)
- if [ "${LATEST}" = "true" ]; then gox -os="linux darwin windows" -arch="amd64" -output="lazygit.." -ldflags "-X main.Rev=`git rev-parse --short HEAD`" -verbose ./...; fi
deploy:
provider: releases
skip_cleanup: true
api_key:
secure: TnB8I+swjicHuGTXk3ncm1Aaa12eIJqWV/Lhcnbb01i39p6+fyn3vDMdWPcejt3R8gcJqv4wyP8UQVO9G1qkLppt6V/qAuY5x6nX0MgEa3t+8JLJnGYHZYsuIgan/ecAmeu5+6dgUhr9Oq6zQOEv/O88NsALzMlqnEQNXI8XSoScfhkiVDIp3zWov0vBizCdThnNgTx9zRpJVoqxmhWvgt+me2+fOhSx1Y+3ZA2gE7zq8IFAbxp36d0rsR5lKqmTuF+YsF9iQ7Ar+xCjbRunLsZx+VwGqGfpS/qS7EwsEqBI0vEO76eFJkwEsIzOvJiFNhBDUu3upquBFMT4uzxRxH3eV+J4mZtu29UDLdvKI5Q730Lk9AgmH4now+RmP08M0SEXJa+AnHeuBv2u1iU5bu+sI6CORVQzKQwOph9AABDjSZ54wrXIpYEeIW2sz8nx+hiG6QL1mqfM/l+55BR69u3vxKYMryQBxPuzhZCTOqqI4uahlb6GIUNZJ9vGZeIA9HFJq3ymW8cdrpYzhKf3Nx9jK+Yb81h5/AHq9iChXEC63VPCDXXGRllh2UYWNYCaAdtk+ekpLR8299e4CaEregy6g5U2S3/xrBKl87miu1uJ/fquXoxGdSU+JcmsmXZ26sGIU2TCYdNjSfIgpOyfMmB4JNtKHqWRHA9Fe42CRpA=
file:
- lazygit.windows.amd64.exe
- lazygit.darwin.amd64
- lazygit.linux.amd64
on:
repo: jesseduffield/lazygit
tags: true
condition: $LATEST = true

74
CODE-OF-CONDUCT.md Normal file
View File

@@ -0,0 +1,74 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the [project leader](https://github.com/jesseduffield).
All complaints will be reviewed and investigated and will result in a response that
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org

34
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,34 @@
# Contributing
♥ We love pull requests from everyone !
When contributing to this repository, please first discuss the change you wish
to make via issue, email, or any other method with the owners of this repository
before making a change.
## So all code changes happen through Pull Requests
Pull requests are the best way to propose changes to the codebase. We actively
welcome your pull requests:
1. Fork the repo and create your branch from `master`.
2. If you've added code that should be tested, add tests.
3. If you've added code that need documentation, update the documentation.
4. Be sure to test your modifications.
5. Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
6. Issue that pull request!
## Code of conduct
Please note by participating in this project, you agree to abide by the [code of conduct].
[code of conduct]: https://github.com/jesseduffield/lazygit/blob/master/CODE-OF-CONDUCT.md
## Any contributions you make will be under the MIT Software License
In short, when you submit code changes, your submissions are understood to be
under the same [MIT License](http://choosealicense.com/licenses/mit/) that
covers the project. Feel free to contact the maintainers if that's a concern.
## Report bugs using Github's [issues](https://github.com/jesseduffield/lazygit/issues)
We use GitHub issues to track public bugs. Report a bug by [opening a new
issue](https://github.com/jesseduffield/lazygit/issues/new); it's that easy!

39
Gopkg.lock generated
View File

@@ -2,10 +2,10 @@
[[projects]]
digest = "1:865079840386857c809b72ce300be7580cb50d3d3129ce11bf9aa6ca2bc1934a"
digest = "1:ade392a843b2035effb4b4a2efa2c3bab3eb29b992e98bacf9c898b0ecb54e45"
name = "github.com/fatih/color"
packages = ["."]
pruneopts = "UT"
pruneopts = "NUT"
revision = "5b77d2a35fb0ede96d138fc9a99f5c9b6aef11b4"
version = "v1.7.0"
@@ -14,55 +14,63 @@
digest = "1:4a8ed9b8cf22bd03bee5d74179fa06a282e4a73b6de949f7a865ff56cd2537e0"
name = "github.com/golang-collections/collections"
packages = ["stack"]
pruneopts = "UT"
pruneopts = "NUT"
revision = "604e922904d35e97f98a774db7881f049cd8d970"
[[projects]]
branch = "master"
digest = "1:f086cf183e423bf1926f4de05f47bf57132fe5db9c99e464f733ce925280fc81"
digest = "1:82b3bbc50ba7b6065b0229ebf0fc990a76e47410acd510294e435aeb3523293e"
name = "github.com/jesseduffield/gocui"
packages = ["."]
pruneopts = "UT"
pruneopts = "NUT"
revision = "3c923f53ac9952af649af04a067405843558d56f"
[[projects]]
digest = "1:c658e84ad3916da105a761660dcaeb01e63416c8ec7bc62256a9b411a05fcd67"
digest = "1:08c231ec84231a7e23d67e4b58f975e1423695a32467a362ee55a803f9de8061"
name = "github.com/mattn/go-colorable"
packages = ["."]
pruneopts = "UT"
pruneopts = "NUT"
revision = "167de6bfdfba052fa6b2d3664c8f5272e23c9072"
version = "v0.0.9"
[[projects]]
digest = "1:d4d17353dbd05cb52a2a52b7fe1771883b682806f68db442b436294926bbfafb"
digest = "1:bc4f7eec3b7be8c6cb1f0af6c1e3333d5bb71072951aaaae2f05067b0803f287"
name = "github.com/mattn/go-isatty"
packages = ["."]
pruneopts = "UT"
pruneopts = "NUT"
revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39"
version = "v0.0.3"
[[projects]]
digest = "1:e2d1d410fb367567c2b53ed9e2d719d3c1f0891397bb2fa49afd747cfbf1e8e4"
digest = "1:cb591533458f6eb6e2c1065ff3eac6b50263d7847deb23fc9f79b25bc608970e"
name = "github.com/mattn/go-runewidth"
packages = ["."]
pruneopts = "UT"
pruneopts = "NUT"
revision = "9e777a8366cce605130a531d2cd6363d07ad7317"
version = "v0.0.2"
[[projects]]
branch = "master"
digest = "1:c9b6e36dbd23f8403a04493376916ca5dad8c01b2da5ae0a05e6a468eb0b6f24"
digest = "1:34d9354c2c5d916c05864327553047df59fc10e86ff1f408e4136eba0a25a5ec"
name = "github.com/nsf/termbox-go"
packages = ["."]
pruneopts = "UT"
pruneopts = "NUT"
revision = "5c94acc5e6eb520f1bcd183974e01171cc4c23b3"
[[projects]]
digest = "1:cd5ffc5bda4e0296ab3e4de90dbb415259c78e45e7fab13694b14cde8ab74541"
name = "github.com/tcnksm/go-gitconfig"
packages = ["."]
pruneopts = "NUT"
revision = "d154598bacbf4501c095a309753c5d4af66caa81"
version = "v0.1.2"
[[projects]]
branch = "master"
digest = "1:9ec6ad2659635ba0974dd7e55bf84233523eb4e7535c9a2fddaefc4cc62a3eac"
digest = "1:4d8a79fbc6fa348fc94afa4235947c5196b7900ed71b94aa5fcbc7e273d150e1"
name = "golang.org/x/sys"
packages = ["unix"]
pruneopts = "UT"
pruneopts = "NUT"
revision = "0ffbfd41fbef8ffcf9b62b0b0aa3a5873ed7a4fe"
[solve-meta]
@@ -72,6 +80,7 @@
"github.com/fatih/color",
"github.com/golang-collections/collections/stack",
"github.com/jesseduffield/gocui",
"github.com/tcnksm/go-gitconfig",
]
solver-name = "gps-cdcl"
solver-version = 1

View File

@@ -9,19 +9,20 @@ Are YOU tired of typing every git command directly into the terminal, but you're
![Gif](https://image.ibb.co/mmeXho/optimisedgif.gif)
## Installation
### Via binary release
You can download a binary release [here](https://github.com/jesseduffield/lazygit/releases)
### Via Go
In a terminal call this command:
`go get github.com/jesseduffield/lazygit`
(if you don't have Go installed, you can follow the installation guide [here](https://golang.org/doc/install).
Then just call `lazygit` in your terminal inside a git repository.
If you want, you can also add an alias for this with `echo "alias lg='lazygit'" >> ~/.zshrc` (or whichever rc file you're using).
Please note:
If you get an error claiming that lazygit cannot be found or is not defined, you may need to add `~/go/bin` to your $PATH (MacOS/Linux), or `%HOME%\go\bin` (Windows)
If you get an error claiming that lazygit cannot be found or is not defined, you may need to add `~/go/bin` to your $PATH (MacOS/Linux), or `%HOME%\go\bin` (Windows). Not to be mistaked for `C:\Go\bin` (which is for Go's own binaries, not apps like Lazygit)
### Ubuntu
Packages for Ubuntu 16.04 and up are available via Launchpad PPA.
Packages for Ubuntu 16.04, 18.04 and 18.10 are available via Launchpad PPA.
They are built daily, straight from master branch.
@@ -31,6 +32,14 @@ sudo apt-get update
sudo apt-get install lazygit
```
## Usage
Call `lazygit` in your terminal inside a git repository.
If you want, you can also add an alias for this with `echo "alias lg='lazygit'" >> ~/.zshrc` (or whichever rc file you're using).
Basic tutorial [Here](https://www.youtube.com/watch?v=VDXvbHZYeKY)
[Keybindings](https://github.com/jesseduffield/lazygit/blob/master/docs/Keybindings.md)
## Cool features
- Adding files easily
- Resolving merge conflicts
@@ -45,19 +54,17 @@ sudo apt-get install lazygit
### Viewing commit diffs
![Viewing Commit Diffs](https://image.ibb.co/gPD02o/capture.png)
## Docs
[Keybindings](https://github.com/jesseduffield/lazygit/blob/master/docs/Keybindings.md)
## Milestones
- [ ] Easy Installation (homebrew, release binaries)
- [ ] Configurable Keybindings
- [ ] Configurable Color Themes
- [ ] Spawning Subprocesses (help needed - have a look at https://github.com/jesseduffield/lazygit/pull/18)
- [ ] Maintainability
- [ ] Performance
- [ ] i18n
## Contributing
I'll find a good template for contributing and then add it to the repo (or if somebody has a suggestion please put up a PR)
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).

View File

@@ -13,7 +13,9 @@
space: toggle staged
c: commit changes
shift+S: stash files
o: open (osx only)
t: add patched (i.e. pick chunks of a file to add)
o: open
e: edit
s: open in sublime (requires 'subl' command)
v: open in vscode (requires 'code' command)
i: add to .gitignore

View File

@@ -63,6 +63,24 @@ func handleFilePress(g *gocui.Gui, v *gocui.View) error {
return handleFileSelect(g, v)
}
func handleAddPatch(g *gocui.Gui, v *gocui.View) error {
file, err := getSelectedFile(g)
if err != nil {
if err == ErrNoFiles {
return nil
}
return err
}
if !file.HasUnstagedChanges {
return createErrorPanel(g, "File has no unstaged changes to add")
}
if !file.Tracked {
return createErrorPanel(g, "Cannot git add --patch untracked files")
}
gitAddPatch(g, file.Name)
return err
}
func getSelectedFile(g *gocui.Gui) (GitFile, error) {
if len(state.GitFiles) == 0 {
return GitFile{}, ErrNoFiles
@@ -115,12 +133,12 @@ func renderfilesOptions(g *gocui.Gui, gitFile *GitFile) error {
"S": "stash files",
"c": "commit changes",
"o": "open",
"s": "sublime",
"v": "vscode",
"i": "ignore",
"d": "delete",
"space": "toggle staged",
"R": "refresh",
"t": "add patch",
"e": "edit",
}
if state.HasMergeConflicts {
optionsMap["a"] = "abort merge"
@@ -163,7 +181,7 @@ func handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
if message == "" {
return createErrorPanel(g, "You cannot commit without a commit message")
}
if output, err := gitCommit(message); err != nil {
if output, err := gitCommit(g, message); err != nil {
return createErrorPanel(g, output)
}
refreshFiles(g)
@@ -172,7 +190,7 @@ func handleCommitPress(g *gocui.Gui, filesView *gocui.View) error {
return nil
}
func genericFileOpen(g *gocui.Gui, v *gocui.View, open func(string) (string, error)) error {
func genericFileOpen(g *gocui.Gui, v *gocui.View, open func(*gocui.Gui, string) (string, error)) error {
file, err := getSelectedFile(g)
if err != nil {
if err != ErrNoFiles {
@@ -180,18 +198,24 @@ func genericFileOpen(g *gocui.Gui, v *gocui.View, open func(string) (string, err
}
return nil
}
if output, err := open(file.Name); err != nil {
return createErrorPanel(g, output)
if _, err := open(g, file.Name); err != nil {
return createErrorPanel(g, err.Error())
}
return nil
}
func handleFileEdit(g *gocui.Gui, v *gocui.View) error {
return genericFileOpen(g, v, editFile)
}
func handleFileOpen(g *gocui.Gui, v *gocui.View) error {
return genericFileOpen(g, v, openFile)
}
func handleSublimeFileOpen(g *gocui.Gui, v *gocui.View) error {
return genericFileOpen(g, v, sublimeOpenFile)
}
func handleVsCodeFileOpen(g *gocui.Gui, v *gocui.View) error {
return genericFileOpen(g, v, vsCodeOpenFile)
}

View File

@@ -13,11 +13,16 @@ import (
"time"
"github.com/fatih/color"
"github.com/jesseduffield/gocui"
gitconfig "github.com/tcnksm/go-gitconfig"
)
var (
// ErrNoCheckedOutBranch : When we have no checked out branch
ErrNoCheckedOutBranch = errors.New("No currently checked out branch")
// ErrNoOpenCommand : When we don't know which command to use to open a file
ErrNoOpenCommand = errors.New("Unsure what command to use to open this file")
)
// GitFile : A staged/unstaged file
@@ -263,23 +268,73 @@ func runCommand(command string) (string, error) {
commandStartTime := time.Now()
commandLog(command)
splitCmd := strings.Split(command, " ")
devLog(splitCmd)
cmdOut, err := exec.Command(splitCmd[0], splitCmd[1:]...).CombinedOutput()
devLog("run command time: ", time.Now().Sub(commandStartTime))
return sanitisedCommandOutput(cmdOut, err)
}
func openFile(filename string) (string, error) {
return runCommand("open " + filename)
}
func vsCodeOpenFile(filename string) (string, error) {
func vsCodeOpenFile(g *gocui.Gui, filename string) (string, error) {
return runCommand("code -r " + filename)
}
func sublimeOpenFile(filename string) (string, error) {
func sublimeOpenFile(g *gocui.Gui, filename string) (string, error) {
return runCommand("subl " + filename)
}
func openFile(g *gocui.Gui, filename string) (string, error) {
cmdName, cmdTrail, err := getOpenCommand()
if err != nil {
return "", err
}
return runCommand(cmdName + " " + filename + cmdTrail)
}
func getOpenCommand() (string, string, error) {
//NextStep open equivalents: xdg-open (linux), cygstart (cygwin), open (OSX)
trailMap := map[string]string{
"xdg-open": " &>/dev/null &",
"cygstart": "",
"open": "",
}
for name, trail := range trailMap {
if out, _ := runCommand("which " + name); out != "exit status 1" {
return name, trail, nil
}
}
return "", "", ErrNoOpenCommand
}
func gitAddPatch(g *gocui.Gui, filename string) {
runSubProcess(g, "git", "add", "--patch", filename)
}
func editFile(g *gocui.Gui, filename string) (string, error) {
editor, _ := gitconfig.Global("core.editor")
if editor == "" {
editor = os.Getenv("VISUAL")
}
if editor == "" {
editor = os.Getenv("EDITOR")
}
if editor == "" {
return "", createErrorPanel(g, "No editor defined in $VISUAL, $EDITOR, or git config.")
}
runSubProcess(g, editor, filename)
return "", nil
}
func runSubProcess(g *gocui.Gui, cmdName string, commandArgs ...string) {
subprocess = exec.Command(cmdName, commandArgs...)
subprocess.Stdin = os.Stdin
subprocess.Stdout = os.Stdout
subprocess.Stderr = os.Stderr
g.Update(func(g *gocui.Gui) error {
return ErrSubprocess
})
}
func getBranchGraph(branch string, baseBranch string) (string, error) {
return runCommand("git log --graph --color --abbrev-commit --decorate --date=relative --pretty=medium -100 " + branch)
@@ -403,7 +458,12 @@ func removeFile(file GitFile) error {
return err
}
func gitCommit(message string) (string, error) {
func gitCommit(g *gocui.Gui, message string) (string, error) {
gpgsign, _ := gitconfig.Global("commit.gpgsign")
if gpgsign != "" {
runSubProcess(g, "bash", "-c", "git commit -m \""+message+"\"")
return "", nil
}
return runDirectCommand("git commit -m \"" + message + "\"")
}

94
gui.go
View File

@@ -5,8 +5,6 @@ import (
// "io"
// "io/ioutil"
"log"
"runtime"
"strings"
"time"
@@ -71,75 +69,9 @@ func handleRefresh(g *gocui.Gui, v *gocui.View) error {
return refreshSidePanels(g)
}
// Binding - a keybinding mapping a key and modifier to a handler. The keypress
// is only handled if the given view has focus, or handled globally if the view
// is ""
type Binding struct {
ViewName string
Handler func(*gocui.Gui, *gocui.View) error
Key interface{} // FIXME: find out how to get `gocui.Key | rune`
Modifier gocui.Modifier
}
func keybindings(g *gocui.Gui) error {
bindings := []Binding{
Binding{ViewName: "", Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: previousView},
Binding{ViewName: "", Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: nextView},
Binding{ViewName: "", Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: nextView},
Binding{ViewName: "", Key: 'q', Modifier: gocui.ModNone, Handler: quit},
Binding{ViewName: "", Key: gocui.KeyCtrlC, Modifier: gocui.ModNone, Handler: quit},
Binding{ViewName: "", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: cursorDown},
Binding{ViewName: "", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: cursorUp},
Binding{ViewName: "", Key: gocui.KeyPgup, Modifier: gocui.ModNone, Handler: scrollUpMain},
Binding{ViewName: "", Key: gocui.KeyPgdn, Modifier: gocui.ModNone, Handler: scrollDownMain},
Binding{ViewName: "", Key: 'P', Modifier: gocui.ModNone, Handler: pushFiles},
Binding{ViewName: "", Key: 'p', Modifier: gocui.ModNone, Handler: pullFiles},
Binding{ViewName: "", Key: 'R', Modifier: gocui.ModNone, Handler: handleRefresh},
Binding{ViewName: "files", Key: 'c', Modifier: gocui.ModNone, Handler: handleCommitPress},
Binding{ViewName: "files", Key: gocui.KeySpace, Modifier: gocui.ModNone, Handler: handleFilePress},
Binding{ViewName: "files", Key: 'd', Modifier: gocui.ModNone, Handler: handleFileRemove},
Binding{ViewName: "files", Key: 'm', Modifier: gocui.ModNone, Handler: handleSwitchToMerge},
Binding{ViewName: "files", Key: 'o', Modifier: gocui.ModNone, Handler: handleFileOpen},
Binding{ViewName: "files", Key: 's', Modifier: gocui.ModNone, Handler: handleSublimeFileOpen},
Binding{ViewName: "files", Key: 'v', Modifier: gocui.ModNone, Handler: handleVsCodeFileOpen},
Binding{ViewName: "files", Key: 'i', Modifier: gocui.ModNone, Handler: handleIgnoreFile},
Binding{ViewName: "files", Key: 'r', Modifier: gocui.ModNone, Handler: handleRefreshFiles},
Binding{ViewName: "files", Key: 'S', Modifier: gocui.ModNone, Handler: handleStashSave},
Binding{ViewName: "files", Key: 'a', Modifier: gocui.ModNone, Handler: handleAbortMerge},
Binding{ViewName: "main", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: handleSelectTop},
Binding{ViewName: "main", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: handleSelectBottom},
Binding{ViewName: "main", Key: gocui.KeyEsc, Modifier: gocui.ModNone, Handler: handleEscapeMerge},
Binding{ViewName: "main", Key: gocui.KeySpace, Modifier: gocui.ModNone, Handler: handlePickHunk},
Binding{ViewName: "main", Key: 'b', Modifier: gocui.ModNone, Handler: handlePickBothHunks},
Binding{ViewName: "main", Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: handleSelectPrevConflict},
Binding{ViewName: "main", Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: handleSelectNextConflict},
Binding{ViewName: "main", Key: 'z', Modifier: gocui.ModNone, Handler: handlePopFileSnapshot},
Binding{ViewName: "branches", Key: gocui.KeySpace, Modifier: gocui.ModNone, Handler: handleBranchPress},
Binding{ViewName: "branches", Key: 'c', Modifier: gocui.ModNone, Handler: handleCheckoutByName},
Binding{ViewName: "branches", Key: 'F', Modifier: gocui.ModNone, Handler: handleForceCheckout},
Binding{ViewName: "branches", Key: 'n', Modifier: gocui.ModNone, Handler: handleNewBranch},
Binding{ViewName: "branches", Key: 'm', Modifier: gocui.ModNone, Handler: handleMerge},
Binding{ViewName: "commits", Key: 's', Modifier: gocui.ModNone, Handler: handleCommitSquashDown},
Binding{ViewName: "commits", Key: 'r', Modifier: gocui.ModNone, Handler: handleRenameCommit},
Binding{ViewName: "commits", Key: 'g', Modifier: gocui.ModNone, Handler: handleResetToCommit},
Binding{ViewName: "stash", Key: gocui.KeySpace, Modifier: gocui.ModNone, Handler: handleStashApply},
Binding{ViewName: "stash", Key: 'k', Modifier: gocui.ModNone, Handler: handleStashPop},
Binding{ViewName: "stash", Key: 'd', Modifier: gocui.ModNone, Handler: handleStashDrop},
}
for _, binding := range bindings {
if err := g.SetKeybinding(binding.ViewName, binding.Key, binding.Modifier, binding.Handler); err != nil {
return err
}
}
return nil
}
func layout(g *gocui.Gui) error {
g.Highlight = true
g.SelFgColor = gocui.ColorWhite | gocui.AttrBold
if runtime.GOOS != "windows" {
g.FgColor = gocui.ColorBlack
}
width, height := g.Size()
leftSideWidth := width / 3
statusFilesBoundary := 2
@@ -225,14 +157,23 @@ func layout(g *gocui.Gui) error {
v.FgColor = gocui.ColorWhite
}
if v, err := g.SetView("options", -1, optionsTop, width, optionsTop+2, 0); err != nil {
if v, err := g.SetView("options", -1, optionsTop, width-len(version)-2, optionsTop+2, 0); err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.BgColor = gocui.ColorDefault
v.FgColor = gocui.ColorBlue
v.Frame = false
v.Title = "Options"
}
if v, err := g.SetView("version", width-len(version)-1, optionsTop, width, optionsTop+2, 0); err != nil {
if err != gocui.ErrUnknownView {
return err
}
v.BgColor = gocui.ColorDefault
v.FgColor = gocui.ColorGreen
v.Frame = false
renderString(g, "version", version)
// these are only called once
handleFileSelect(g, filesView)
@@ -261,10 +202,10 @@ func updateLoader(g *gocui.Gui) {
}
}
func run() {
func run() (err error) {
g, err := gocui.NewGui(gocui.OutputNormal, OverlappingEdges)
if err != nil {
log.Panicln(err)
return
}
defer g.Close()
@@ -283,13 +224,12 @@ func run() {
g.SetManagerFunc(layout)
if err := keybindings(g); err != nil {
log.Panicln(err)
if err = keybindings(g); err != nil {
return
}
if err := g.MainLoop(); err != nil && err != gocui.ErrQuit {
log.Panicln(err)
}
err = g.MainLoop()
return
}
func quit(g *gocui.Gui, v *gocui.View) error {

68
keybindings.go Normal file
View File

@@ -0,0 +1,68 @@
package main
import "github.com/jesseduffield/gocui"
// Binding - a keybinding mapping a key and modifier to a handler. The keypress
// is only handled if the given view has focus, or handled globally if the view
// is ""
type Binding struct {
ViewName string
Handler func(*gocui.Gui, *gocui.View) error
Key interface{} // FIXME: find out how to get `gocui.Key | rune`
Modifier gocui.Modifier
}
func keybindings(g *gocui.Gui) error {
bindings := []Binding{
Binding{ViewName: "", Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: previousView},
Binding{ViewName: "", Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: nextView},
Binding{ViewName: "", Key: gocui.KeyTab, Modifier: gocui.ModNone, Handler: nextView},
Binding{ViewName: "", Key: 'q', Modifier: gocui.ModNone, Handler: quit},
Binding{ViewName: "", Key: gocui.KeyCtrlC, Modifier: gocui.ModNone, Handler: quit},
Binding{ViewName: "", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: cursorDown},
Binding{ViewName: "", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: cursorUp},
Binding{ViewName: "", Key: gocui.KeyPgup, Modifier: gocui.ModNone, Handler: scrollUpMain},
Binding{ViewName: "", Key: gocui.KeyPgdn, Modifier: gocui.ModNone, Handler: scrollDownMain},
Binding{ViewName: "", Key: 'P', Modifier: gocui.ModNone, Handler: pushFiles},
Binding{ViewName: "", Key: 'p', Modifier: gocui.ModNone, Handler: pullFiles},
Binding{ViewName: "", Key: 'R', Modifier: gocui.ModNone, Handler: handleRefresh},
Binding{ViewName: "files", Key: 'c', Modifier: gocui.ModNone, Handler: handleCommitPress},
Binding{ViewName: "files", Key: gocui.KeySpace, Modifier: gocui.ModNone, Handler: handleFilePress},
Binding{ViewName: "files", Key: 'd', Modifier: gocui.ModNone, Handler: handleFileRemove},
Binding{ViewName: "files", Key: 'm', Modifier: gocui.ModNone, Handler: handleSwitchToMerge},
Binding{ViewName: "files", Key: 'e', Modifier: gocui.ModNone, Handler: handleFileEdit},
Binding{ViewName: "files", Key: 'o', Modifier: gocui.ModNone, Handler: handleFileOpen},
Binding{ViewName: "files", Key: 's', Modifier: gocui.ModNone, Handler: handleSublimeFileOpen},
Binding{ViewName: "files", Key: 'v', Modifier: gocui.ModNone, Handler: handleVsCodeFileOpen},
Binding{ViewName: "files", Key: 'i', Modifier: gocui.ModNone, Handler: handleIgnoreFile},
Binding{ViewName: "files", Key: 'r', Modifier: gocui.ModNone, Handler: handleRefreshFiles},
Binding{ViewName: "files", Key: 'S', Modifier: gocui.ModNone, Handler: handleStashSave},
Binding{ViewName: "files", Key: 'a', Modifier: gocui.ModNone, Handler: handleAbortMerge},
Binding{ViewName: "files", Key: 't', Modifier: gocui.ModNone, Handler: handleAddPatch},
Binding{ViewName: "main", Key: gocui.KeyArrowUp, Modifier: gocui.ModNone, Handler: handleSelectTop},
Binding{ViewName: "main", Key: gocui.KeyArrowDown, Modifier: gocui.ModNone, Handler: handleSelectBottom},
Binding{ViewName: "main", Key: gocui.KeyEsc, Modifier: gocui.ModNone, Handler: handleEscapeMerge},
Binding{ViewName: "main", Key: gocui.KeySpace, Modifier: gocui.ModNone, Handler: handlePickHunk},
Binding{ViewName: "main", Key: 'b', Modifier: gocui.ModNone, Handler: handlePickBothHunks},
Binding{ViewName: "main", Key: gocui.KeyArrowLeft, Modifier: gocui.ModNone, Handler: handleSelectPrevConflict},
Binding{ViewName: "main", Key: gocui.KeyArrowRight, Modifier: gocui.ModNone, Handler: handleSelectNextConflict},
Binding{ViewName: "main", Key: 'z', Modifier: gocui.ModNone, Handler: handlePopFileSnapshot},
Binding{ViewName: "branches", Key: gocui.KeySpace, Modifier: gocui.ModNone, Handler: handleBranchPress},
Binding{ViewName: "branches", Key: 'c', Modifier: gocui.ModNone, Handler: handleCheckoutByName},
Binding{ViewName: "branches", Key: 'F', Modifier: gocui.ModNone, Handler: handleForceCheckout},
Binding{ViewName: "branches", Key: 'n', Modifier: gocui.ModNone, Handler: handleNewBranch},
Binding{ViewName: "branches", Key: 'm', Modifier: gocui.ModNone, Handler: handleMerge},
Binding{ViewName: "commits", Key: 's', Modifier: gocui.ModNone, Handler: handleCommitSquashDown},
Binding{ViewName: "commits", Key: 'r', Modifier: gocui.ModNone, Handler: handleRenameCommit},
Binding{ViewName: "commits", Key: 'g', Modifier: gocui.ModNone, Handler: handleResetToCommit},
Binding{ViewName: "stash", Key: gocui.KeySpace, Modifier: gocui.ModNone, Handler: handleStashApply},
Binding{ViewName: "stash", Key: 'k', Modifier: gocui.ModNone, Handler: handleStashPop},
Binding{ViewName: "stash", Key: 'd', Modifier: gocui.ModNone, Handler: handleStashDrop},
}
for _, binding := range bindings {
if err := g.SetKeybinding(binding.ViewName, binding.Key, binding.Modifier, binding.Handler); err != nil {
return err
}
}
return nil
}

40
main.go
View File

@@ -1,19 +1,31 @@
package main
import (
"errors"
"flag"
"fmt"
"log"
"os"
"os/exec"
"os/user"
"time"
"github.com/fatih/color"
"github.com/jesseduffield/gocui"
)
// ErrSubProcess is raised when we are running a subprocess
var (
startTime time.Time
debugging bool
ErrSubprocess = errors.New("running subprocess")
subprocess *exec.Cmd
startTime time.Time
commit string
version = "unversioned"
date string
debuggingFlag = flag.Bool("debug", false, "a boolean")
versionFlag = flag.Bool("v", false, "Print the current version")
)
func homeDirectory() string {
@@ -37,7 +49,7 @@ func commandLog(objects ...interface{}) {
}
func localLog(colour color.Attribute, path string, objects ...interface{}) {
if !debugging {
if !*debuggingFlag {
return
}
f, _ := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, 0644)
@@ -58,12 +70,24 @@ func navigateToRepoRootDirectory() {
}
func main() {
debuggingPointer := flag.Bool("debug", false, "a boolean")
flag.Parse()
debugging = *debuggingPointer
devLog("\n\n\n\n\n\n\n\n\n\n")
startTime = time.Now()
devLog("\n\n\n\n\n\n\n\n\n\n")
flag.Parse()
if *versionFlag {
fmt.Printf("commit=%s, build date=%s, version=%s", commit, date, version)
os.Exit(0)
}
verifyInGitRepo()
navigateToRepoRootDirectory()
run()
for {
if err := run(); err != nil {
if err == gocui.ErrQuit {
break
} else if err == ErrSubprocess {
subprocess.Run()
} else {
log.Panicln(err)
}
}
}
}

View File

@@ -0,0 +1,7 @@
#!/bin/bash
# For testing subprocesses that require input
# Ask the user for login details
read -p 'Username: ' user
read -sp 'Password: ' pass
echo
echo Hello $user

22
vendor/github.com/tcnksm/go-gitconfig/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,22 @@
Copyright (c) 2014 tcnksm
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

113
vendor/github.com/tcnksm/go-gitconfig/gitconfig.go generated vendored Normal file
View File

@@ -0,0 +1,113 @@
// Package gitconfig enables you to use `~/.gitconfig` values in Golang.
//
// For a full guide visit http://github.com/tcnksm/go-gitconfig
//
// package main
//
// import (
// "github.com/tcnksm/go-gitconfig"
// "fmt"
// )
//
// func main() {
// user, err := gitconfig.Global("user.name")
// if err == nil {
// fmt.Println(user)
// }
// }
//
package gitconfig
import (
"bytes"
"fmt"
"io/ioutil"
"os/exec"
"regexp"
"strings"
"syscall"
)
// Entire extracts configuration value from `$HOME/.gitconfig` file ,
// `$GIT_CONFIG`, /etc/gitconfig or include.path files.
func Entire(key string) (string, error) {
return execGitConfig(key)
}
// Global extracts configuration value from `$HOME/.gitconfig` file or `$GIT_CONFIG`.
func Global(key string) (string, error) {
return execGitConfig("--global", key)
}
// Local extracts configuration value from current project repository.
func Local(key string) (string, error) {
return execGitConfig("--local", key)
}
// GithubUser extracts github.user name from `Entire gitconfig`
// This is same as Entire("github.user")
func GithubUser() (string, error) {
return Entire("github.user")
}
// Username extracts git user name from `Entire gitconfig`.
// This is same as Entire("user.name")
func Username() (string, error) {
return Entire("user.name")
}
// Email extracts git user email from `$HOME/.gitconfig` file or `$GIT_CONFIG`.
// This is same as Global("user.email")
func Email() (string, error) {
return Entire("user.email")
}
// OriginURL extract remote origin url from current project repository.
// This is same as Local("remote.origin.url")
func OriginURL() (string, error) {
return Local("remote.origin.url")
}
// Repository extract repository name of current project repository.
func Repository() (string, error) {
url, err := OriginURL()
if err != nil {
return "", err
}
repo := retrieveRepoName(url)
return repo, nil
}
// Github extracts github token from `Entire gitconfig`.
// This is same as Entire("github.token")
func GithubToken() (string, error) {
return Entire("github.token")
}
func execGitConfig(args ...string) (string, error) {
gitArgs := append([]string{"config", "--get", "--null"}, args...)
var stdout bytes.Buffer
cmd := exec.Command("git", gitArgs...)
cmd.Stdout = &stdout
cmd.Stderr = ioutil.Discard
err := cmd.Run()
if exitError, ok := err.(*exec.ExitError); ok {
if waitStatus, ok := exitError.Sys().(syscall.WaitStatus); ok {
if waitStatus.ExitStatus() == 1 {
return "", fmt.Errorf("the key `%s` is not found", args[len(args)-1])
}
}
return "", err
}
return strings.TrimRight(stdout.String(), "\000"), nil
}
var RepoNameRegexp = regexp.MustCompile(`.+/([^/]+)(\.git)?$`)
func retrieveRepoName(url string) string {
matched := RepoNameRegexp.FindStringSubmatch(url)
return strings.TrimSuffix(matched[1], ".git")
}