mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-07-28 16:02:01 +03:00
WIP refactor
This commit is contained in:
@ -3,17 +3,23 @@ package commands
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
git "gopkg.in/src-d/go-git.v4"
|
"github.com/jesseduffield/gocui"
|
||||||
|
"github.com/jesseduffield/lazygit/pkg/git"
|
||||||
|
gitconfig "github.com/tcnksm/go-gitconfig"
|
||||||
|
gogit "gopkg.in/src-d/go-git.v4"
|
||||||
|
"gopkg.in/src-d/go-git.v4/plumbing/object"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GitCommand is our main git interface
|
// GitCommand is our main git interface
|
||||||
type GitCommand struct {
|
type GitCommand struct {
|
||||||
Log *logrus.Logger
|
Log *logrus.Logger
|
||||||
OSCommand *OSCommand
|
OSCommand *OSCommand
|
||||||
Worktree *git.Worktree
|
Worktree *gogit.Worktree
|
||||||
Repo *git.Repository
|
Repo *gogit.Repository
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGitCommand it runs git commands
|
// NewGitCommand it runs git commands
|
||||||
@ -32,6 +38,7 @@ func (c *GitCommand) SetupGit() {
|
|||||||
c.setupWorktree()
|
c.setupWorktree()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GitIgnore adds a file to the .gitignore of the repo
|
||||||
func (c *GitCommand) GitIgnore(filename string) {
|
func (c *GitCommand) GitIgnore(filename string) {
|
||||||
if _, err := c.OSCommand.RunDirectCommand("echo '" + filename + "' >> .gitignore"); err != nil {
|
if _, err := c.OSCommand.RunDirectCommand("echo '" + filename + "' >> .gitignore"); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -55,7 +62,6 @@ func (c *GitCommand) navigateToRepoRootDirectory() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *GitCommand) setupWorktree() {
|
func (c *GitCommand) setupWorktree() {
|
||||||
var err error
|
|
||||||
r, err := git.PlainOpen(".")
|
r, err := git.PlainOpen(".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@ -63,9 +69,151 @@ func (c *GitCommand) setupWorktree() {
|
|||||||
c.Repo = r
|
c.Repo = r
|
||||||
|
|
||||||
w, err := r.Worktree()
|
w, err := r.Worktree()
|
||||||
c.Worktree = w
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
c.Worktree = w
|
c.Worktree = w
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ResetHard does the equivalent of `git reset --hard HEAD`
|
||||||
|
func (c *GitCommand) ResetHard() error {
|
||||||
|
return c.Worktree.Reset(&gogit.ResetOptions{Mode: git.HardReset})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpstreamDifferenceCount checks how many pushables/pullables there are for the
|
||||||
|
// current branch
|
||||||
|
func (c *GitCommand) UpstreamDifferenceCount() (string, string) {
|
||||||
|
pushableCount, err := c.OSCommand.runDirectCommand("git rev-list @{u}..head --count")
|
||||||
|
if err != nil {
|
||||||
|
return "?", "?"
|
||||||
|
}
|
||||||
|
pullableCount, err := c.OSCommand.runDirectCommand("git rev-list head..@{u} --count")
|
||||||
|
if err != nil {
|
||||||
|
return "?", "?"
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(pushableCount), strings.TrimSpace(pullableCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCommitsToPush Returns the sha's of the commits that have not yet been pushed
|
||||||
|
// to the remote branch of the current branch
|
||||||
|
func (c *GitCommand) GetCommitsToPush() []string {
|
||||||
|
pushables, err := c.OSCommand.runDirectCommand("git rev-list @{u}..head --abbrev-commit")
|
||||||
|
if err != nil {
|
||||||
|
return make([]string, 0)
|
||||||
|
}
|
||||||
|
return splitLines(pushables)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetGitBranches returns a list of branches for the current repo, with recency
|
||||||
|
// values stored against those that are in the reflog
|
||||||
|
func (c *GitCommand) GetGitBranches() []Branch {
|
||||||
|
builder := git.newBranchListBuilder()
|
||||||
|
return builder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
// BranchIncluded states whether a branch is included in a list of branches,
|
||||||
|
// with a case insensitive comparison on name
|
||||||
|
func (c *GitCommand) BranchIncluded(branchName string, branches []Branch) bool {
|
||||||
|
for _, existingBranch := range branches {
|
||||||
|
if strings.ToLower(existingBranch.Name) == strings.ToLower(branchName) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenameCommit renames the topmost commit with the given name
|
||||||
|
func (c *GitCommand) RenameCommit(name string) (string, error) {
|
||||||
|
return c.OSCommand.runDirectCommand("git commit --allow-empty --amend -m \"" + name + "\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) Fetch() (string, error) {
|
||||||
|
return c.OSCommand.runDirectCommand("git fetch")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) ResetToCommit(sha string) (string, error) {
|
||||||
|
return c.OSCommand.runDirectCommand("git reset " + sha)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) NewBranch(name string) (string, error) {
|
||||||
|
return c.OSCommand.runDirectCommand("git checkout -b " + name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) DeleteBranch(branch string) (string, error) {
|
||||||
|
return runCommand("git branch -d " + branch)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) ListStash() (string, error) {
|
||||||
|
return c.OSCommand.runDirectCommand("git stash list")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) Merge(branchName string) (string, error) {
|
||||||
|
return c.OSCommand.runDirectCommand("git merge --no-edit " + branchName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *GitCommand) AbortMerge() (string, error) {
|
||||||
|
return c.OSCommand.runDirectCommand("git merge --abort")
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitCommit(g *gocui.Gui, message string) (string, error) {
|
||||||
|
gpgsign, _ := gitconfig.Global("commit.gpgsign")
|
||||||
|
if gpgsign != "" {
|
||||||
|
runSubProcess(g, "git", "commit")
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
userName, err := gitconfig.Username()
|
||||||
|
if userName == "" {
|
||||||
|
return "", errNoUsername
|
||||||
|
}
|
||||||
|
userEmail, err := gitconfig.Email()
|
||||||
|
_, err = w.Commit(message, &git.CommitOptions{
|
||||||
|
Author: &object.Signature{
|
||||||
|
Name: userName,
|
||||||
|
Email: userEmail,
|
||||||
|
When: time.Now(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err.Error(), err
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitPull() (string, error) {
|
||||||
|
return runDirectCommand("git pull --no-edit")
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitPush() (string, error) {
|
||||||
|
return runDirectCommand("git push -u origin " + state.Branches[0].Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitSquashPreviousTwoCommits(message string) (string, error) {
|
||||||
|
return runDirectCommand("git reset --soft HEAD^ && git commit --amend -m \"" + message + "\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
func gitSquashFixupCommit(branchName string, shaValue string) (string, error) {
|
||||||
|
var err error
|
||||||
|
commands := []string{
|
||||||
|
"git checkout -q " + shaValue,
|
||||||
|
"git reset --soft " + shaValue + "^",
|
||||||
|
"git commit --amend -C " + shaValue + "^",
|
||||||
|
"git rebase --onto HEAD " + shaValue + " " + branchName,
|
||||||
|
}
|
||||||
|
ret := ""
|
||||||
|
for _, command := range commands {
|
||||||
|
devLog(command)
|
||||||
|
output, err := runDirectCommand(command)
|
||||||
|
ret += output
|
||||||
|
if err != nil {
|
||||||
|
devLog(ret)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// We are already in an error state here so we're just going to append
|
||||||
|
// the output of these commands
|
||||||
|
ret += runDirectCommandIgnoringError("git branch -d " + shaValue)
|
||||||
|
ret += runDirectCommandIgnoringError("git checkout " + branchName)
|
||||||
|
}
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package main
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
||||||
@ -279,7 +279,7 @@ func verifyInGitRepo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func getCommits() []Commit {
|
func getCommits() []Commit {
|
||||||
pushables := gitCommitsToPush()
|
pushables := git.GetCommitsToPush()
|
||||||
log := getLog()
|
log := getLog()
|
||||||
commits := make([]Commit, 0)
|
commits := make([]Commit, 0)
|
||||||
// now we can split it up and turn it into commits
|
// now we can split it up and turn it into commits
|
||||||
@ -447,73 +447,3 @@ func gitSquashFixupCommit(branchName string, shaValue string) (string, error) {
|
|||||||
}
|
}
|
||||||
return ret, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func gitRenameCommit(message string) (string, error) {
|
|
||||||
return runDirectCommand("git commit --allow-empty --amend -m \"" + message + "\"")
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitFetch() (string, error) {
|
|
||||||
return runDirectCommand("git fetch")
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitResetToCommit(sha string) (string, error) {
|
|
||||||
return runDirectCommand("git reset " + sha)
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitNewBranch(name string) (string, error) {
|
|
||||||
return runDirectCommand("git checkout -b " + name)
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitDeleteBranch(branch string) (string, error) {
|
|
||||||
return runCommand("git branch -d " + branch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitListStash() (string, error) {
|
|
||||||
return runDirectCommand("git stash list")
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitMerge(branchName string) (string, error) {
|
|
||||||
return runDirectCommand("git merge --no-edit " + branchName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitAbortMerge() (string, error) {
|
|
||||||
return runDirectCommand("git merge --abort")
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitUpstreamDifferenceCount() (string, string) {
|
|
||||||
pushableCount, err := runDirectCommand("git rev-list @{u}..head --count")
|
|
||||||
if err != nil {
|
|
||||||
return "?", "?"
|
|
||||||
}
|
|
||||||
pullableCount, err := runDirectCommand("git rev-list head..@{u} --count")
|
|
||||||
if err != nil {
|
|
||||||
return "?", "?"
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(pushableCount), strings.TrimSpace(pullableCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitCommitsToPush() []string {
|
|
||||||
pushables, err := runDirectCommand("git rev-list @{u}..head --abbrev-commit")
|
|
||||||
if err != nil {
|
|
||||||
return make([]string, 0)
|
|
||||||
}
|
|
||||||
return splitLines(pushables)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getGitBranches() []Branch {
|
|
||||||
builder := newBranchListBuilder()
|
|
||||||
return builder.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
func branchIncluded(branchName string, branches []Branch) bool {
|
|
||||||
for _, existingBranch := range branches {
|
|
||||||
if strings.ToLower(existingBranch.Name) == strings.ToLower(branchName) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func gitResetHard() error {
|
|
||||||
return w.Reset(&git.ResetOptions{Mode: git.HardReset})
|
|
||||||
}
|
|
||||||
|
@ -123,7 +123,7 @@ func refreshBranches(g *gocui.Gui) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
state.Branches = getGitBranches()
|
state.Branches = git.GetGitBranches()
|
||||||
v.Clear()
|
v.Clear()
|
||||||
for _, branch := range state.Branches {
|
for _, branch := range state.Branches {
|
||||||
fmt.Fprintln(v, branch.getDisplayString())
|
fmt.Fprintln(v, branch.getDisplayString())
|
||||||
|
@ -148,7 +148,7 @@ func handleRenameCommit(g *gocui.Gui, v *gocui.View) error {
|
|||||||
return createErrorPanel(g, "Can only rename topmost commit")
|
return createErrorPanel(g, "Can only rename topmost commit")
|
||||||
}
|
}
|
||||||
createPromptPanel(g, v, "Rename Commit", func(g *gocui.Gui, v *gocui.View) error {
|
createPromptPanel(g, v, "Rename Commit", func(g *gocui.Gui, v *gocui.View) error {
|
||||||
if output, err := gitRenameCommit(v.Buffer()); err != nil {
|
if output, err := git.RenameCommit(v.Buffer()); err != nil {
|
||||||
return createErrorPanel(g, output)
|
return createErrorPanel(g, output)
|
||||||
}
|
}
|
||||||
if err := refreshCommits(g); err != nil {
|
if err := refreshCommits(g); err != nil {
|
||||||
|
@ -354,7 +354,7 @@ func handleAbortMerge(g *gocui.Gui, v *gocui.View) error {
|
|||||||
|
|
||||||
func handleResetHard(g *gocui.Gui, v *gocui.View) error {
|
func handleResetHard(g *gocui.Gui, v *gocui.View) error {
|
||||||
return createConfirmationPanel(g, v, "Clear file panel", "Are you sure you want `reset --hard HEAD`? You may lose changes", func(g *gocui.Gui, v *gocui.View) error {
|
return createConfirmationPanel(g, v, "Clear file panel", "Are you sure you want `reset --hard HEAD`? You may lose changes", func(g *gocui.Gui, v *gocui.View) error {
|
||||||
if err := gitResetHard(); err != nil {
|
if err := git.ResetHard(); err != nil {
|
||||||
createErrorPanel(g, err.Error())
|
createErrorPanel(g, err.Error())
|
||||||
}
|
}
|
||||||
return refreshFiles(g)
|
return refreshFiles(g)
|
||||||
|
@ -17,7 +17,7 @@ func refreshStatus(g *gocui.Gui) error {
|
|||||||
// contents end up cleared
|
// contents end up cleared
|
||||||
g.Update(func(*gocui.Gui) error {
|
g.Update(func(*gocui.Gui) error {
|
||||||
v.Clear()
|
v.Clear()
|
||||||
pushables, pullables := gitUpstreamDifferenceCount()
|
pushables, pullables := git.UpstreamDifferenceCount()
|
||||||
fmt.Fprint(v, "↑"+pushables+"↓"+pullables)
|
fmt.Fprint(v, "↑"+pushables+"↓"+pullables)
|
||||||
branches := state.Branches
|
branches := state.Branches
|
||||||
if err := updateHasMergeConflictStatus(); err != nil {
|
if err := updateHasMergeConflictStatus(); err != nil {
|
||||||
|
Reference in New Issue
Block a user