mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-12 12:55:47 +02:00
better handling of merge conflicts
This commit is contained in:
parent
a47c889cbb
commit
fab194e923
4 changed files with 248 additions and 187 deletions
|
@ -29,12 +29,24 @@ func stagedFiles(files []GitFile) []GitFile {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stageSelectedFile(g *gocui.Gui) error {
|
||||||
|
file, err := getSelectedFile(g)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return stageFile(file.Name)
|
||||||
|
}
|
||||||
|
|
||||||
func handleFilePress(g *gocui.Gui, v *gocui.View) error {
|
func handleFilePress(g *gocui.Gui, v *gocui.View) error {
|
||||||
file, err := getSelectedFile(g)
|
file, err := getSelectedFile(g)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if file.HasMergeConflicts {
|
||||||
|
return handleSwitchToMerge(g, v)
|
||||||
|
}
|
||||||
|
|
||||||
if file.HasUnstagedChanges {
|
if file.HasUnstagedChanges {
|
||||||
stageFile(file.Name)
|
stageFile(file.Name)
|
||||||
} else {
|
} else {
|
||||||
|
@ -291,7 +303,7 @@ func handleSwitchToMerge(g *gocui.Gui, v *gocui.View) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if !file.HasMergeConflicts {
|
if !file.HasMergeConflicts {
|
||||||
return nil
|
return createErrorPanel(g, "This file has no merge conflicts")
|
||||||
}
|
}
|
||||||
switchFocus(g, v, mergeView)
|
switchFocus(g, v, mergeView)
|
||||||
return refreshMergePanel(g)
|
return refreshMergePanel(g)
|
||||||
|
|
5
gui.go
5
gui.go
|
@ -135,7 +135,10 @@ func keybindings(g *gocui.Gui) error {
|
||||||
if err := g.SetKeybinding("main", gocui.KeyArrowDown, gocui.ModNone, handleSelectBottom); err != nil {
|
if err := g.SetKeybinding("main", gocui.KeyArrowDown, gocui.ModNone, handleSelectBottom); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := g.SetKeybinding("main", gocui.KeySpace, gocui.ModNone, handlePickConflict); err != nil {
|
if err := g.SetKeybinding("main", gocui.KeySpace, gocui.ModNone, handlePickHunk); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := g.SetKeybinding("main", 'b', gocui.ModNone, handlePickBothHunks); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := g.SetKeybinding("main", gocui.KeyArrowLeft, gocui.ModNone, handleSelectPrevConflict); err != nil {
|
if err := g.SetKeybinding("main", gocui.KeyArrowLeft, gocui.ModNone, handleSelectPrevConflict); err != nil {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -86,16 +87,21 @@ func handleSelectPrevConflict(g *gocui.Gui, v *gocui.View) error {
|
||||||
return refreshMergePanel(g)
|
return refreshMergePanel(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isIndexToDelete(i int, conflict conflict, top bool) bool {
|
func isIndexToDelete(i int, conflict conflict, pick string) bool {
|
||||||
return i == conflict.middle ||
|
return i == conflict.middle ||
|
||||||
i == conflict.start ||
|
i == conflict.start ||
|
||||||
i == conflict.end ||
|
i == conflict.end ||
|
||||||
(!top && i > conflict.start && i < conflict.middle) ||
|
pick != "both" &&
|
||||||
(top && i > conflict.middle && i < conflict.end)
|
(pick == "bottom" && i > conflict.start && i < conflict.middle) ||
|
||||||
|
(pick == "top" && i > conflict.middle && i < conflict.end)
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveConflict(filename string, conflict conflict, top bool) error {
|
func resolveConflict(g *gocui.Gui, conflict conflict, pick string) error {
|
||||||
file, err := os.Open(filename)
|
gitFile, err := getSelectedFile(g)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
file, err := os.Open(gitFile.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -108,16 +114,20 @@ func resolveConflict(filename string, conflict conflict, top bool) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if !isIndexToDelete(i, conflict, top) {
|
if !isIndexToDelete(i, conflict, pick) {
|
||||||
output += line
|
output += line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
devLog(output)
|
devLog(output)
|
||||||
return ioutil.WriteFile(filename, []byte(output), 0644)
|
return ioutil.WriteFile(gitFile.Name, []byte(output), 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func pushFileSnapshot(filename string) error {
|
func pushFileSnapshot(g *gocui.Gui) error {
|
||||||
content, err := catFile(filename)
|
gitFile, err := getSelectedFile(g)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
content, err := catFile(gitFile.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -139,14 +149,25 @@ func handlePopFileSnapshot(g *gocui.Gui, v *gocui.View) error {
|
||||||
return refreshMergePanel(g)
|
return refreshMergePanel(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePickConflict(g *gocui.Gui, v *gocui.View) error {
|
func handlePickHunk(g *gocui.Gui, v *gocui.View) error {
|
||||||
conflict := state.Conflicts[state.ConflictIndex]
|
conflict := state.Conflicts[state.ConflictIndex]
|
||||||
gitFile, err := getSelectedFile(g)
|
pushFileSnapshot(g)
|
||||||
if err != nil {
|
pick := "bottom"
|
||||||
return err
|
if state.ConflictTop {
|
||||||
|
pick = "top"
|
||||||
}
|
}
|
||||||
pushFileSnapshot(gitFile.Name)
|
err := resolveConflict(g, conflict, pick)
|
||||||
err = resolveConflict(gitFile.Name, conflict, state.ConflictTop)
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
refreshMergePanel(g)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePickBothHunks(g *gocui.Gui, v *gocui.View) error {
|
||||||
|
conflict := state.Conflicts[state.ConflictIndex]
|
||||||
|
pushFileSnapshot(g)
|
||||||
|
err := resolveConflict(g, conflict, "both")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -169,7 +190,7 @@ func refreshMergePanel(g *gocui.Gui) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(state.Conflicts) == 0 {
|
if len(state.Conflicts) == 0 {
|
||||||
state.ConflictIndex = 0
|
return handleCompleteMerge(g)
|
||||||
} else if state.ConflictIndex > len(state.Conflicts)-1 {
|
} else if state.ConflictIndex > len(state.Conflicts)-1 {
|
||||||
state.ConflictIndex = len(state.Conflicts) - 1
|
state.ConflictIndex = len(state.Conflicts) - 1
|
||||||
}
|
}
|
||||||
|
@ -196,9 +217,11 @@ func scrollToConflict(g *gocui.Gui) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
conflict := state.Conflicts[state.ConflictIndex]
|
conflict := state.Conflicts[state.ConflictIndex]
|
||||||
ox, oy := mainView.Origin()
|
ox, _ := mainView.Origin()
|
||||||
devLog(oy, conflict.start)
|
_, height := mainView.Size()
|
||||||
return mainView.SetOrigin(ox, conflict.start)
|
conflictMiddle := (conflict.end + conflict.start) / 2
|
||||||
|
newOriginY := int(math.Max(0, float64(conflictMiddle-(height/2))))
|
||||||
|
return mainView.SetOrigin(ox, newOriginY)
|
||||||
}
|
}
|
||||||
|
|
||||||
func switchToMerging(g *gocui.Gui) error {
|
func switchToMerging(g *gocui.Gui) error {
|
||||||
|
@ -216,6 +239,7 @@ func renderMergeOptions(g *gocui.Gui) error {
|
||||||
"up/down": "pick hunk",
|
"up/down": "pick hunk",
|
||||||
"left/right": "previous/next commit",
|
"left/right": "previous/next commit",
|
||||||
"space": "pick hunk",
|
"space": "pick hunk",
|
||||||
|
"b": "pick both hunks",
|
||||||
"z": "undo",
|
"z": "undo",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -228,3 +252,13 @@ func handleEscapeMerge(g *gocui.Gui, v *gocui.View) error {
|
||||||
refreshFiles(g)
|
refreshFiles(g)
|
||||||
return switchFocus(g, v, filesView)
|
return switchFocus(g, v, filesView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleCompleteMerge(g *gocui.Gui) error {
|
||||||
|
filesView, err := g.View("files")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
stageSelectedFile(g)
|
||||||
|
refreshFiles(g)
|
||||||
|
return switchFocus(g, nil, filesView)
|
||||||
|
}
|
||||||
|
|
|
@ -18,19 +18,31 @@ cd ${reponame}
|
||||||
|
|
||||||
git init
|
git init
|
||||||
|
|
||||||
|
function add_spacing {
|
||||||
|
for i in {1..60}
|
||||||
|
do
|
||||||
|
echo "..." >> $1
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
echo "Here is a story that has been told throuhg the ages" >> file1
|
echo "Here is a story that has been told throuhg the ages" >> file1
|
||||||
|
|
||||||
git add file1
|
git add file1
|
||||||
git commit -m "first commit"
|
git commit -m "first commit"
|
||||||
|
|
||||||
git checkout -b develop
|
git checkout -b develop
|
||||||
|
|
||||||
echo "once upon a time there was a dog" >> file1
|
echo "once upon a time there was a dog" >> file1
|
||||||
|
add_spacing file1
|
||||||
|
echo "once upon a time there was another dog" >> file1
|
||||||
git add file1
|
git add file1
|
||||||
git commit -m "first commit on develop"
|
git commit -m "first commit on develop"
|
||||||
|
|
||||||
git checkout master
|
git checkout master
|
||||||
|
|
||||||
echo "once upon a time there was a cat" >> file1
|
echo "once upon a time there was a cat" >> file1
|
||||||
|
add_spacing file1
|
||||||
|
echo "once upon a time there was another cat" >> file1
|
||||||
git add file1
|
git add file1
|
||||||
git commit -m "first commit on develop"
|
git commit -m "first commit on develop"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue