diff --git a/pkg/commands/patch/hunk.go b/pkg/commands/patch/hunk.go index 98d932126..605c473c1 100644 --- a/pkg/commands/patch/hunk.go +++ b/pkg/commands/patch/hunk.go @@ -75,19 +75,11 @@ func (hunk *PatchHunk) updatedLines(lineIndices []int, reverse bool) []string { } func transformedFirstChar(firstChar string, reverse bool, isLineSelected bool) string { + linesToKeepInPatchContext := "-" if reverse { - if !isLineSelected && firstChar == "+" { - return " " - } else if firstChar == "-" { - return "+" - } else if firstChar == "+" { - return "-" - } else { - return firstChar - } + linesToKeepInPatchContext = "+" } - - if !isLineSelected && firstChar == "-" { + if !isLineSelected && firstChar == linesToKeepInPatchContext { return " " } @@ -100,14 +92,14 @@ func (hunk *PatchHunk) formatHeader(oldStart int, oldLength int, newStart int, n func (hunk *PatchHunk) formatWithChanges(lineIndices []int, reverse bool, startOffset int) (int, string) { bodyLines := hunk.updatedLines(lineIndices, reverse) - startOffset, header, ok := hunk.updatedHeader(bodyLines, startOffset, reverse) + startOffset, header, ok := hunk.updatedHeader(bodyLines, startOffset) if !ok { return startOffset, "" } return startOffset, header + strings.Join(bodyLines, "") } -func (hunk *PatchHunk) updatedHeader(newBodyLines []string, startOffset int, reverse bool) (int, string, bool) { +func (hunk *PatchHunk) updatedHeader(newBodyLines []string, startOffset int) (int, string, bool) { changeCount := nLinesWithPrefix(newBodyLines, []string{"+", "-"}) oldLength := nLinesWithPrefix(newBodyLines, []string{" ", "-"}) newLength := nLinesWithPrefix(newBodyLines, []string{"+", " "}) @@ -117,12 +109,7 @@ func (hunk *PatchHunk) updatedHeader(newBodyLines []string, startOffset int, rev return startOffset, "", false } - var oldStart int - if reverse { - oldStart = hunk.newStart - } else { - oldStart = hunk.oldStart - } + oldStart := hunk.oldStart var newStartOffset int // if the hunk went from zero to positive length, we need to increment the starting point by one diff --git a/pkg/commands/patch/patch_manager.go b/pkg/commands/patch/patch_manager.go index 91adfecb4..3a379b97e 100644 --- a/pkg/commands/patch/patch_manager.go +++ b/pkg/commands/patch/patch_manager.go @@ -162,7 +162,7 @@ func (p *PatchManager) RemoveFileLineRange(filename string, firstLineIdx, lastLi return nil } -func (p *PatchManager) renderPlainPatchForFile(filename string, reverse bool, keepOriginalHeader bool) string { +func (p *PatchManager) renderPlainPatchForFile(filename string, reverse bool) string { info, err := p.getFileInfo(filename) if err != nil { p.Log.Error(err) @@ -176,14 +176,18 @@ func (p *PatchManager) renderPlainPatchForFile(filename string, reverse bool, ke return info.diff case PART: // generate a new diff with just the selected lines - return ModifiedPatchForLines(p.Log, filename, info.diff, info.includedLineIndices, reverse, keepOriginalHeader) + return ModifiedPatchForLines(p.Log, filename, info.diff, info.includedLineIndices, + PatchOptions{ + Reverse: reverse, + KeepOriginalHeader: true, + }) default: return "" } } -func (p *PatchManager) RenderPatchForFile(filename string, plain bool, reverse bool, keepOriginalHeader bool) string { - patch := p.renderPlainPatchForFile(filename, reverse, keepOriginalHeader) +func (p *PatchManager) RenderPatchForFile(filename string, plain bool, reverse bool) string { + patch := p.renderPlainPatchForFile(filename, reverse) if plain { return patch } @@ -199,7 +203,7 @@ func (p *PatchManager) renderEachFilePatch(plain bool) []string { sort.Strings(filenames) patches := slices.Map(filenames, func(filename string) string { - return p.RenderPatchForFile(filename, plain, false, true) + return p.RenderPatchForFile(filename, plain, false) }) output := slices.Filter(patches, func(patch string) bool { return patch != "" @@ -240,42 +244,22 @@ func (p *PatchManager) GetFileIncLineIndices(filename string) ([]int, error) { } func (p *PatchManager) ApplyPatches(reverse bool) error { - // for whole patches we'll apply the patch in reverse - // but for part patches we'll apply a reverse patch forwards + patch := "" + + applyFlags := []string{"index", "3way"} + if reverse { + applyFlags = append(applyFlags, "reverse") + } + for filename, info := range p.fileInfoMap { if info.mode == UNSELECTED { continue } - applyFlags := []string{"index", "3way"} - reverseOnGenerate := false - if reverse { - if info.mode == WHOLE { - applyFlags = append(applyFlags, "reverse") - } else { - reverseOnGenerate = true - } - } - - var err error - // first run we try with the original header, then without - for _, keepOriginalHeader := range []bool{true, false} { - patch := p.RenderPatchForFile(filename, true, reverseOnGenerate, keepOriginalHeader) - if patch == "" { - continue - } - if err = p.applyPatch(patch, applyFlags...); err != nil { - continue - } - break - } - - if err != nil { - return err - } + patch += p.RenderPatchForFile(filename, true, reverse) } - return nil + return p.applyPatch(patch, applyFlags...) } // clears the patch diff --git a/pkg/commands/patch/patch_modifier.go b/pkg/commands/patch/patch_modifier.go index fe0a896b1..79f7b7d31 100644 --- a/pkg/commands/patch/patch_modifier.go +++ b/pkg/commands/patch/patch_modifier.go @@ -13,6 +13,19 @@ var ( patchHeaderRegexp = regexp.MustCompile(`(?ms)(^diff.*?)^@@`) ) +type PatchOptions struct { + // Create a patch that will applied in reverse with `git apply --reverse`. + // This affects how unselected lines are treated when only parts of a hunk + // are selected: usually, for unselected lines we change '-' lines to + // context lines and remove '+' lines, but when Reverse is true we need to + // turn '+' lines into context lines and remove '-' lines. + Reverse bool + + // Whether to keep or discard the original diff header including the + // "index deadbeef..fa1afe1 100644" line. + KeepOriginalHeader bool +} + func GetHeaderFromDiff(diff string) string { match := patchHeaderRegexp.FindStringSubmatch(diff) if len(match) <= 1 { @@ -76,7 +89,7 @@ func NewPatchModifier(log *logrus.Entry, filename string, diffText string) *Patc } } -func (d *PatchModifier) ModifiedPatchForLines(lineIndices []int, reverse bool, keepOriginalHeader bool) string { +func (d *PatchModifier) ModifiedPatchForLines(lineIndices []int, opts PatchOptions) string { // step one is getting only those hunks which we care about hunksInRange := []*PatchHunk{} outer: @@ -95,7 +108,8 @@ outer: formattedHunks := "" var formattedHunk string for _, hunk := range hunksInRange { - startOffset, formattedHunk = hunk.formatWithChanges(lineIndices, reverse, startOffset) + startOffset, formattedHunk = hunk.formatWithChanges( + lineIndices, opts.Reverse, startOffset) formattedHunks += formattedHunk } @@ -108,7 +122,7 @@ outer: // it makes git confused e.g. when dealing with deleted/added files // but with building and applying patches the original header gives git // information it needs to cleanly apply patches - if keepOriginalHeader { + if opts.KeepOriginalHeader { fileHeader = d.header } else { fileHeader = fmt.Sprintf("--- a/%s\n+++ b/%s\n", d.filename, d.filename) @@ -117,13 +131,13 @@ outer: return fileHeader + formattedHunks } -func (d *PatchModifier) ModifiedPatchForRange(firstLineIdx int, lastLineIdx int, reverse bool, keepOriginalHeader bool) string { +func (d *PatchModifier) ModifiedPatchForRange(firstLineIdx int, lastLineIdx int, opts PatchOptions) string { // generate array of consecutive line indices from our range selectedLines := []int{} for i := firstLineIdx; i <= lastLineIdx; i++ { selectedLines = append(selectedLines, i) } - return d.ModifiedPatchForLines(selectedLines, reverse, keepOriginalHeader) + return d.ModifiedPatchForLines(selectedLines, opts) } func (d *PatchModifier) OriginalPatchLength() int { @@ -134,14 +148,14 @@ func (d *PatchModifier) OriginalPatchLength() int { return d.hunks[len(d.hunks)-1].LastLineIdx() } -func ModifiedPatchForRange(log *logrus.Entry, filename string, diffText string, firstLineIdx int, lastLineIdx int, reverse bool, keepOriginalHeader bool) string { +func ModifiedPatchForRange(log *logrus.Entry, filename string, diffText string, firstLineIdx int, lastLineIdx int, opts PatchOptions) string { p := NewPatchModifier(log, filename, diffText) - return p.ModifiedPatchForRange(firstLineIdx, lastLineIdx, reverse, keepOriginalHeader) + return p.ModifiedPatchForRange(firstLineIdx, lastLineIdx, opts) } -func ModifiedPatchForLines(log *logrus.Entry, filename string, diffText string, includedLineIndices []int, reverse bool, keepOriginalHeader bool) string { +func ModifiedPatchForLines(log *logrus.Entry, filename string, diffText string, includedLineIndices []int, opts PatchOptions) string { p := NewPatchModifier(log, filename, diffText) - return p.ModifiedPatchForLines(includedLineIndices, reverse, keepOriginalHeader) + return p.ModifiedPatchForLines(includedLineIndices, opts) } // I want to know, given a hunk, what line a given index is on diff --git a/pkg/commands/patch/patch_modifier_test.go b/pkg/commands/patch/patch_modifier_test.go index ec79cbe32..131490ece 100644 --- a/pkg/commands/patch/patch_modifier_test.go +++ b/pkg/commands/patch/patch_modifier_test.go @@ -69,6 +69,20 @@ index e48a11c..b2ab81b 100644 ... ` +const twoChangesInOneHunk = `diff --git a/filename b/filename +index 9320895..6d79956 100644 +--- a/filename ++++ b/filename +@@ -1,5 +1,5 @@ + apple +-grape ++kiwi + orange +-pear ++banana + lemon +` + const newFile = `diff --git a/newfile b/newfile new file mode 100644 index 0000000..4e680cc @@ -116,7 +130,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: -1, lastLineIndex: -1, - reverse: false, diffText: simpleDiff, expected: "", }, @@ -125,7 +138,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: 5, lastLineIndex: 5, - reverse: false, diffText: simpleDiff, expected: "", }, @@ -134,7 +146,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: 0, lastLineIndex: 11, - reverse: false, diffText: simpleDiff, expected: `--- a/filename +++ b/filename @@ -152,7 +163,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: 6, lastLineIndex: 6, - reverse: false, diffText: simpleDiff, expected: `--- a/filename +++ b/filename @@ -169,7 +179,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: 7, lastLineIndex: 7, - reverse: false, diffText: simpleDiff, expected: `--- a/filename +++ b/filename @@ -187,7 +196,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: -100, lastLineIndex: 100, - reverse: false, diffText: simpleDiff, expected: `--- a/filename +++ b/filename @@ -198,59 +206,6 @@ func TestModifyPatchForRange(t *testing.T) { ... ... ... -`, - }, - { - testName: "whole range reversed", - filename: "filename", - firstLineIndex: 0, - lastLineIndex: 11, - reverse: true, - diffText: simpleDiff, - expected: `--- a/filename -+++ b/filename -@@ -1,5 +1,5 @@ - apple -+orange --grape - ... - ... - ... -`, - }, - { - testName: "removal reversed", - filename: "filename", - firstLineIndex: 6, - lastLineIndex: 6, - reverse: true, - diffText: simpleDiff, - expected: `--- a/filename -+++ b/filename -@@ -1,5 +1,6 @@ - apple -+orange - grape - ... - ... - ... -`, - }, - { - testName: "removal reversed", - filename: "filename", - firstLineIndex: 7, - lastLineIndex: 7, - reverse: true, - diffText: simpleDiff, - expected: `--- a/filename -+++ b/filename -@@ -1,5 +1,4 @@ - apple --grape - ... - ... - ... `, }, { @@ -258,7 +213,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: -100, lastLineIndex: 100, - reverse: false, diffText: addNewlineToEndOfFile, expected: `--- a/filename +++ b/filename @@ -272,37 +226,21 @@ func TestModifyPatchForRange(t *testing.T) { `, }, { - testName: "add newline to end of file, addition only", + testName: "add newline to end of file, reversed", filename: "filename", - firstLineIndex: 8, - lastLineIndex: 8, + firstLineIndex: -100, + lastLineIndex: 100, reverse: true, diffText: addNewlineToEndOfFile, expected: `--- a/filename +++ b/filename -@@ -60,4 +60,5 @@ grape - ... - ... - ... -+last line -\ No newline at end of file - last line -`, - }, - { - testName: "add newline to end of file, removal only", - filename: "filename", - firstLineIndex: 10, - lastLineIndex: 10, - reverse: true, - diffText: addNewlineToEndOfFile, - expected: `--- a/filename -+++ b/filename -@@ -60,4 +60,3 @@ grape +@@ -60,4 +60,4 @@ grape ... ... ... -last line +\ No newline at end of file ++last line `, }, { @@ -310,7 +248,24 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: -100, lastLineIndex: 100, - reverse: false, + diffText: removeNewlinefromEndOfFile, + expected: `--- a/filename ++++ b/filename +@@ -60,4 +60,4 @@ grape + ... + ... + ... +-last line ++last line +\ No newline at end of file +`, + }, + { + testName: "remove newline from end of file, reversed", + filename: "filename", + firstLineIndex: -100, + lastLineIndex: 100, + reverse: true, diffText: removeNewlinefromEndOfFile, expected: `--- a/filename +++ b/filename @@ -328,7 +283,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: 8, lastLineIndex: 8, - reverse: false, diffText: removeNewlinefromEndOfFile, expected: `--- a/filename +++ b/filename @@ -337,6 +291,24 @@ func TestModifyPatchForRange(t *testing.T) { ... ... -last line +`, + }, + { + testName: "remove newline from end of file, removal only, reversed", + filename: "filename", + firstLineIndex: 8, + lastLineIndex: 8, + reverse: true, + diffText: removeNewlinefromEndOfFile, + expected: `--- a/filename ++++ b/filename +@@ -60,5 +60,4 @@ grape + ... + ... + ... +-last line + last line +\ No newline at end of file `, }, { @@ -344,7 +316,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: 9, lastLineIndex: 9, - reverse: false, diffText: removeNewlinefromEndOfFile, expected: `--- a/filename +++ b/filename @@ -355,6 +326,23 @@ func TestModifyPatchForRange(t *testing.T) { last line +last line \ No newline at end of file +`, + }, + { + testName: "remove newline from end of file, addition only, reversed", + filename: "filename", + firstLineIndex: 9, + lastLineIndex: 9, + reverse: true, + diffText: removeNewlinefromEndOfFile, + expected: `--- a/filename ++++ b/filename +@@ -60,3 +60,4 @@ grape + ... + ... + ... ++last line +\ No newline at end of file `, }, { @@ -362,7 +350,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: -100, lastLineIndex: 100, - reverse: false, diffText: twoHunks, expected: `--- a/filename +++ b/filename @@ -389,7 +376,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "filename", firstLineIndex: 7, lastLineIndex: 15, - reverse: false, diffText: twoHunks, expected: `--- a/filename +++ b/filename @@ -408,32 +394,6 @@ func TestModifyPatchForRange(t *testing.T) { ... ... ... -`, - }, - { - testName: "staging part of both hunks, reversed", - filename: "filename", - firstLineIndex: 7, - lastLineIndex: 15, - reverse: true, - diffText: twoHunks, - expected: `--- a/filename -+++ b/filename -@@ -1,5 +1,4 @@ - apple --orange - ... - ... - ... -@@ -8,8 +7,7 @@ grape - ... - ... - ... --pear - lemon - ... - ... - ... `, }, { @@ -441,7 +401,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "newfile", firstLineIndex: -100, lastLineIndex: 100, - reverse: false, diffText: newFile, expected: `--- a/newfile +++ b/newfile @@ -456,28 +415,12 @@ func TestModifyPatchForRange(t *testing.T) { filename: "newfile", firstLineIndex: 6, lastLineIndex: 7, - reverse: false, diffText: newFile, expected: `--- a/newfile +++ b/newfile @@ -0,0 +1,2 @@ +apple +orange -`, - }, - { - testName: "adding a new file, reversed", - filename: "newfile", - firstLineIndex: -100, - lastLineIndex: 100, - reverse: true, - diffText: newFile, - expected: `--- a/newfile -+++ b/newfile -@@ -1,3 +0,0 @@ --apple --orange --grape `, }, { @@ -485,7 +428,6 @@ func TestModifyPatchForRange(t *testing.T) { filename: "newfile", firstLineIndex: -100, lastLineIndex: 100, - reverse: false, diffText: addNewlineToPreviouslyEmptyFile, expected: `--- a/newfile +++ b/newfile @@ -499,13 +441,49 @@ func TestModifyPatchForRange(t *testing.T) { filename: "newfile", firstLineIndex: -100, lastLineIndex: 100, - reverse: true, diffText: addNewlineToPreviouslyEmptyFile, + reverse: true, expected: `--- a/newfile +++ b/newfile -@@ -1,1 +0,0 @@ --new line +@@ -0,0 +1,1 @@ ++new line \ No newline at end of file +`, + }, + { + testName: "adding part of a hunk", + filename: "filename", + firstLineIndex: 6, + lastLineIndex: 7, + reverse: false, + diffText: twoChangesInOneHunk, + expected: `--- a/filename ++++ b/filename +@@ -1,5 +1,5 @@ + apple +-grape ++kiwi + orange + pear + lemon +`, + }, + { + testName: "adding part of a hunk, reverse", + filename: "filename", + firstLineIndex: 6, + lastLineIndex: 7, + reverse: true, + diffText: twoChangesInOneHunk, + expected: `--- a/filename ++++ b/filename +@@ -1,5 +1,5 @@ + apple +-grape ++kiwi + orange + banana + lemon `, }, } @@ -513,7 +491,11 @@ func TestModifyPatchForRange(t *testing.T) { for _, s := range scenarios { s := s t.Run(s.testName, func(t *testing.T) { - result := ModifiedPatchForRange(nil, s.filename, s.diffText, s.firstLineIndex, s.lastLineIndex, s.reverse, false) + result := ModifiedPatchForRange(nil, s.filename, s.diffText, s.firstLineIndex, s.lastLineIndex, + PatchOptions{ + Reverse: s.reverse, + KeepOriginalHeader: false, + }) if !assert.Equal(t, s.expected, result) { fmt.Println(result) } diff --git a/pkg/gui/controllers/staging_controller.go b/pkg/gui/controllers/staging_controller.go index 0cddfb841..78c271640 100644 --- a/pkg/gui/controllers/staging_controller.go +++ b/pkg/gui/controllers/staging_controller.go @@ -181,7 +181,8 @@ func (self *StagingController) applySelection(reverse bool) error { } firstLineIdx, lastLineIdx := state.SelectedRange() - patch := patch.ModifiedPatchForRange(self.c.Log, path, state.GetDiff(), firstLineIdx, lastLineIdx, reverse, false) + patch := patch.ModifiedPatchForRange(self.c.Log, path, state.GetDiff(), firstLineIdx, lastLineIdx, + patch.PatchOptions{Reverse: reverse, KeepOriginalHeader: false}) if patch == "" { return nil @@ -190,6 +191,9 @@ func (self *StagingController) applySelection(reverse bool) error { // apply the patch then refresh this panel // create a new temp file with the patch, then call git apply with that patch applyFlags := []string{} + if reverse { + applyFlags = append(applyFlags, "reverse") + } if !reverse || self.staged { applyFlags = append(applyFlags, "cached") } @@ -227,7 +231,8 @@ func (self *StagingController) editHunk() error { hunk := state.CurrentHunk() patchText := patch.ModifiedPatchForRange( - self.c.Log, path, state.GetDiff(), hunk.FirstLineIdx, hunk.LastLineIdx(), self.staged, false, + self.c.Log, path, state.GetDiff(), hunk.FirstLineIdx, hunk.LastLineIdx(), + patch.PatchOptions{Reverse: self.staged, KeepOriginalHeader: false}, ) patchFilepath, err := self.git.WorkingTree.SaveTemporaryPatch(patchText) if err != nil { @@ -249,9 +254,15 @@ func (self *StagingController) editHunk() error { lineCount := strings.Count(editedPatchText, "\n") + 1 newPatchText := patch.ModifiedPatchForRange( - self.c.Log, path, editedPatchText, 0, lineCount, false, false, + self.c.Log, path, editedPatchText, 0, lineCount, + patch.PatchOptions{KeepOriginalHeader: false}, ) - if err := self.git.WorkingTree.ApplyPatch(newPatchText, "cached"); err != nil { + + applyFlags := []string{"cached"} + if self.staged { + applyFlags = append(applyFlags, "reverse") + } + if err := self.git.WorkingTree.ApplyPatch(newPatchText, applyFlags...); err != nil { return self.c.Error(err) } diff --git a/pkg/gui/refresh.go b/pkg/gui/refresh.go index 9ee5ea0bd..0c6315767 100644 --- a/pkg/gui/refresh.go +++ b/pkg/gui/refresh.go @@ -672,7 +672,7 @@ func (gui *Gui) refreshPatchBuildingPanel(opts types.OnFocusOpts) error { return err } - secondaryDiff := gui.git.Patch.PatchManager.RenderPatchForFile(path, false, false, true) + secondaryDiff := gui.git.Patch.PatchManager.RenderPatchForFile(path, false, false) if err != nil { return err } diff --git a/pkg/integration/clients/tui.go b/pkg/integration/clients/tui.go index f93f4589a..6778bc012 100644 --- a/pkg/integration/clients/tui.go +++ b/pkg/integration/clients/tui.go @@ -121,7 +121,7 @@ func RunTUI() { return nil } - cmd := secureexec.Command("sh", "-c", fmt.Sprintf("code -r pkg/integration/tests/%s", currentTest.Name())) + cmd := secureexec.Command("sh", "-c", fmt.Sprintf("code -r pkg/integration/tests/%s.go", currentTest.Name())) if err := cmd.Run(); err != nil { return err } diff --git a/pkg/integration/tests/patch_building/apply_in_reverse_with_conflict.go b/pkg/integration/tests/patch_building/apply_in_reverse_with_conflict.go new file mode 100644 index 000000000..04d160a01 --- /dev/null +++ b/pkg/integration/tests/patch_building/apply_in_reverse_with_conflict.go @@ -0,0 +1,92 @@ +package patch_building + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var ApplyInReverseWithConflict = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Apply a custom patch in reverse, resulting in a conflict", + ExtraCmdArgs: "", + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.CreateFileAndAdd("file1", "file1 content\n") + shell.CreateFileAndAdd("file2", "file2 content\n") + shell.Commit("first commit") + shell.UpdateFileAndAdd("file1", "file1 content\nmore file1 content\n") + shell.UpdateFileAndAdd("file2", "file2 content\nmore file2 content\n") + shell.Commit("second commit") + shell.UpdateFileAndAdd("file1", "file1 content\nmore file1 content\neven more file1\n") + shell.Commit("third commit") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + Focus(). + Lines( + Contains("third commit").IsSelected(), + Contains("second commit"), + Contains("first commit"), + ). + NavigateToLine(Contains("second commit")). + PressEnter() + + t.Views().CommitFiles(). + IsFocused(). + Lines( + Contains("M").Contains("file1").IsSelected(), + Contains("M").Contains("file2"), + ). + // Add both files to the patch; the first will conflict, the second won't + PressPrimaryAction(). + SelectNextItem(). + PressPrimaryAction() + + t.Views().Information().Content(Contains("building patch")) + + t.Views().PatchBuildingSecondary().Content( + Contains("+more file1 content").Contains("+more file2 content")) + + t.Common().SelectPatchOption(Contains("apply patch in reverse")) + + t.ExpectPopup().Alert(). + Title(Equals("Error")). + Content(Contains("Applied patch to 'file1' with conflicts."). + Contains("Applied patch to 'file2' cleanly.")). + Confirm() + + t.Views().Files(). + Focus(). + Lines( + Contains("UU").Contains("file1").IsSelected(), + ). + PressPrimaryAction() + + t.Views().MergeConflicts(). + IsFocused(). + ContainsLines( + Contains("file1 content"), + Contains("<<<<<<< ours").IsSelected(), + Contains("more file1 content").IsSelected(), + Contains("even more file1").IsSelected(), + Contains("=======").IsSelected(), + Contains(">>>>>>> theirs"), + ). + SelectNextItem(). + PressPrimaryAction() + + t.Views().Files(). + Focus(). + Lines( + Contains("M").Contains("file1").IsSelected(), + Contains("M").Contains("file2"), + ) + + t.Views().Main(). + ContainsLines( + Contains(" file1 content"), + Contains("-more file1 content"), + Contains("-even more file1"), + ) + }, +}) diff --git a/pkg/integration/tests/patch_building/move_to_index_with_conflict.go b/pkg/integration/tests/patch_building/move_to_index_with_conflict.go index bdeb321c4..75ecff9a4 100644 --- a/pkg/integration/tests/patch_building/move_to_index_with_conflict.go +++ b/pkg/integration/tests/patch_building/move_to_index_with_conflict.go @@ -8,7 +8,7 @@ import ( var MoveToIndexWithConflict = NewIntegrationTest(NewIntegrationTestArgs{ Description: "Move a patch from a commit to the index, causing a conflict", ExtraCmdArgs: "", - Skip: true, // Skipping until https://github.com/jesseduffield/lazygit/pull/2471 is merged + Skip: false, SetupConfig: func(config *config.AppConfig) {}, SetupRepo: func(shell *Shell) { shell.CreateFileAndAdd("file1", "file1 content") diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index dd1dfd70f..3a0fa8269 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -99,6 +99,7 @@ var tests = []*components.IntegrationTest{ misc.InitialOpen, patch_building.Apply, patch_building.ApplyInReverse, + patch_building.ApplyInReverseWithConflict, patch_building.CopyPatchToClipboard, patch_building.MoveToIndex, patch_building.MoveToIndexPartial,