1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-04-21 12:16:54 +02:00

Make "Find base commit for fixup" work with hunks with only added lines

To understand what this does and why, read the design document that I'm about to
add in the next commit.
This commit is contained in:
Stefan Haller 2024-05-19 20:11:50 +02:00
parent c1a65546ad
commit dbdabb34f3
5 changed files with 179 additions and 11 deletions

View File

@ -47,16 +47,21 @@ func (self *FixupHelper) HandleFindBaseCommitForFixupPress() error {
if err != nil { if err != nil {
return err return err
} }
if diff == "" {
deletedLineHunks, addedLineHunks := parseDiff(diff)
var hashes []string
warnAboutAddedLines := false
if len(deletedLineHunks) > 0 {
hashes, err = self.blameDeletedLines(deletedLineHunks)
warnAboutAddedLines = len(addedLineHunks) > 0
} else if len(addedLineHunks) > 0 {
hashes, err = self.blameAddedLines(addedLineHunks)
} else {
return errors.New(self.c.Tr.NoChangedFiles) return errors.New(self.c.Tr.NoChangedFiles)
} }
deletedLineHunks, addedLineHunks := parseDiff(diff)
if len(deletedLineHunks) == 0 {
return errors.New(self.c.Tr.NoDeletedLinesInDiff)
}
hashes, err := self.blameDeletedLines(deletedLineHunks)
if err != nil { if err != nil {
return err return err
} }
@ -104,7 +109,7 @@ func (self *FixupHelper) HandleFindBaseCommitForFixupPress() error {
return self.c.PushContext(self.c.Contexts().LocalCommits) return self.c.PushContext(self.c.Contexts().LocalCommits)
} }
if len(addedLineHunks) > 0 { if warnAboutAddedLines {
return self.c.Confirm(types.ConfirmOpts{ return self.c.Confirm(types.ConfirmOpts{
Title: self.c.Tr.FindBaseCommitForFixup, Title: self.c.Tr.FindBaseCommitForFixup,
Prompt: self.c.Tr.HunksWithOnlyAddedLinesWarning, Prompt: self.c.Tr.HunksWithOnlyAddedLinesWarning,
@ -220,6 +225,87 @@ func (self *FixupHelper) blameDeletedLines(deletedLineHunks []*hunk) ([]string,
return result.ToSlice(), errg.Wait() return result.ToSlice(), errg.Wait()
} }
func (self *FixupHelper) blameAddedLines(addedLineHunks []*hunk) ([]string, error) {
errg := errgroup.Group{}
hashesChan := make(chan []string)
for _, h := range addedLineHunks {
errg.Go(func() error {
result := make([]string, 0, 2)
appendBlamedLine := func(blameOutput string) {
blameLines := strings.Split(strings.TrimSuffix(blameOutput, "\n"), "\n")
if len(blameLines) == 1 {
result = append(result, strings.Split(blameLines[0], " ")[0])
}
}
// Blame the line before this hunk, if there is one
if h.startLineIdx > 0 {
blameOutput, err := self.c.Git().Blame.BlameLineRange(h.filename, "HEAD", h.startLineIdx, 1)
if err != nil {
return err
}
appendBlamedLine(blameOutput)
}
// Blame the line after this hunk. We don't know how many lines the
// file has, so we can't check if there is a line after the hunk;
// let the error tell us.
blameOutput, err := self.c.Git().Blame.BlameLineRange(h.filename, "HEAD", h.startLineIdx+1, 1)
if err != nil {
// If this fails, we're probably at the end of the file (we
// could have checked this beforehand, but it's expensive). If
// there was a line before this hunk, this is fine, we'll just
// return that one; if not, the hunk encompasses the entire
// file, and we can't blame the lines before and after the hunk.
// This is an error.
if h.startLineIdx == 0 {
return errors.New("Entire file") // TODO i18n
}
} else {
appendBlamedLine(blameOutput)
}
hashesChan <- result
return nil
})
}
go func() {
// We don't care about the error here, we'll check it later (in the
// return statement below). Here we only wait for all the goroutines to
// finish so that we can close the channel.
_ = errg.Wait()
close(hashesChan)
}()
result := set.New[string]()
for hashes := range hashesChan {
if len(hashes) == 1 {
result.Add(hashes[0])
} else if len(hashes) > 1 {
if hashes[0] == hashes[1] {
result.Add(hashes[0])
} else {
_, index1, ok1 := self.findCommit(hashes[0])
_, index2, ok2 := self.findCommit(hashes[1])
if ok1 && ok2 {
result.Add(lo.Ternary(index1 < index2, hashes[0], hashes[1]))
} else if ok1 {
result.Add(hashes[0])
} else if ok2 {
result.Add(hashes[1])
} else {
return nil, errors.New(self.c.Tr.NoBaseCommitsFound)
}
}
}
}
return result.ToSlice(), errg.Wait()
}
func (self *FixupHelper) findCommit(hash string) (*models.Commit, int, bool) { func (self *FixupHelper) findCommit(hash string) (*models.Commit, int, bool) {
return lo.FindIndexOf(self.c.Model().Commits, func(commit *models.Commit) bool { return lo.FindIndexOf(self.c.Model().Commits, func(commit *models.Commit) bool {
return commit.Hash == hash return commit.Hash == hash

View File

@ -42,7 +42,6 @@ type TranslationSet struct {
CommitChangesWithEditor string CommitChangesWithEditor string
FindBaseCommitForFixup string FindBaseCommitForFixup string
FindBaseCommitForFixupTooltip string FindBaseCommitForFixupTooltip string
NoDeletedLinesInDiff string
NoBaseCommitsFound string NoBaseCommitsFound string
MultipleBaseCommitsFoundStaged string MultipleBaseCommitsFoundStaged string
MultipleBaseCommitsFoundUnstaged string MultipleBaseCommitsFoundUnstaged string
@ -1005,7 +1004,6 @@ func EnglishTranslationSet() TranslationSet {
CommitChangesWithEditor: "Commit changes using git editor", CommitChangesWithEditor: "Commit changes using git editor",
FindBaseCommitForFixup: "Find base commit for fixup", FindBaseCommitForFixup: "Find base commit for fixup",
FindBaseCommitForFixupTooltip: "Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md>", FindBaseCommitForFixupTooltip: "Find the commit that your current changes are building upon, for the sake of amending/fixing up the commit. This spares you from having to look through your branch's commits one-by-one to see which commit should be amended/fixed up. See docs: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md>",
NoDeletedLinesInDiff: "No deleted lines in diff",
NoBaseCommitsFound: "No base commits found", NoBaseCommitsFound: "No base commits found",
MultipleBaseCommitsFoundStaged: "Multiple base commits found. (Try staging fewer changes at once)", MultipleBaseCommitsFoundStaged: "Multiple base commits found. (Try staging fewer changes at once)",
MultipleBaseCommitsFoundUnstaged: "Multiple base commits found. (Try staging some of the changes)", MultipleBaseCommitsFoundUnstaged: "Multiple base commits found. (Try staging some of the changes)",

View File

@ -33,7 +33,6 @@ func polishTranslationSet() TranslationSet {
CommitChangesWithEditor: "Zatwierdź zmiany używając edytora git", CommitChangesWithEditor: "Zatwierdź zmiany używając edytora git",
FindBaseCommitForFixup: "Znajdź bazowy commit do poprawki", FindBaseCommitForFixup: "Znajdź bazowy commit do poprawki",
FindBaseCommitForFixupTooltip: "Znajdź commit, na którym opierają się Twoje obecne zmiany, w celu poprawienia/zmiany commita. To pozwala Ci uniknąć przeglądania commitów w Twojej gałęzi jeden po drugim, aby zobaczyć, który commit powinien być poprawiony/zmieniony. Zobacz dokumentację: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md>", FindBaseCommitForFixupTooltip: "Znajdź commit, na którym opierają się Twoje obecne zmiany, w celu poprawienia/zmiany commita. To pozwala Ci uniknąć przeglądania commitów w Twojej gałęzi jeden po drugim, aby zobaczyć, który commit powinien być poprawiony/zmieniony. Zobacz dokumentację: <https://github.com/jesseduffield/lazygit/tree/master/docs/Fixup_Commits.md>",
NoDeletedLinesInDiff: "Brak usuniętych linii w różnicach",
NoBaseCommitsFound: "Nie znaleziono bazowych commitów", NoBaseCommitsFound: "Nie znaleziono bazowych commitów",
MultipleBaseCommitsFoundStaged: "Znaleziono wiele bazowych commitów. (Spróbuj zatwierdzić mniej zmian naraz)", MultipleBaseCommitsFoundStaged: "Znaleziono wiele bazowych commitów. (Spróbuj zatwierdzić mniej zmian naraz)",
MultipleBaseCommitsFoundUnstaged: "Znaleziono wiele bazowych commitów. (Spróbuj zatwierdzić część zmian)", MultipleBaseCommitsFoundUnstaged: "Znaleziono wiele bazowych commitów. (Spróbuj zatwierdzić część zmian)",

View File

@ -0,0 +1,84 @@
package commit
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var FindBaseCommitForFixupOnlyAddedLines = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Finds the base commit to create a fixup for, when all staged hunks have only added lines",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.NewBranch("mybranch").
EmptyCommit("1st commit").
CreateFileAndAdd("file1", "line A\nline B\nline C\n").
Commit("2nd commit").
UpdateFileAndAdd("file1", "line A\nline B changed\nline C\n").
Commit("3rd commit").
CreateFileAndAdd("file2", "line X\nline Y\nline Z\n").
Commit("4th commit").
UpdateFile("file1", "line A\nline B changed\nline B'\nline C\n").
UpdateFile("file2", "line W\nline X\nline Y\nline Z\n")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Lines(
Contains("4th commit"),
Contains("3rd commit"),
Contains("2nd commit"),
Contains("1st commit"),
)
// Two changes from different commits: this fails
t.Views().Files().
Focus().
Press(keys.Files.FindBaseCommitForFixup)
t.ExpectPopup().Alert().
Title(Equals("Error")).
Content(
Contains("Multiple base commits found").
Contains("3rd commit").
Contains("4th commit"),
).
Confirm()
// Stage only one of the files: this succeeds
t.Views().Files().
IsFocused().
NavigateToLine(Contains("file1")).
PressPrimaryAction().
Press(keys.Files.FindBaseCommitForFixup)
t.Views().Commits().
IsFocused().
Lines(
Contains("4th commit"),
Contains("3rd commit").IsSelected(),
Contains("2nd commit"),
Contains("1st commit"),
).
Press(keys.Commits.AmendToCommit)
t.ExpectPopup().Confirmation().
Title(Equals("Amend commit")).
Content(Contains("Are you sure you want to amend this commit with your staged files?")).
Confirm()
// Now only the other file is modified (and unstaged); this works now
t.Views().Files().
Focus().
Press(keys.Files.FindBaseCommitForFixup)
t.Views().Commits().
IsFocused().
Lines(
Contains("4th commit").IsSelected(),
Contains("3rd commit"),
Contains("2nd commit"),
Contains("1st commit"),
)
},
})

View File

@ -79,6 +79,7 @@ var tests = []*components.IntegrationTest{
commit.CreateTag, commit.CreateTag,
commit.DiscardOldFileChanges, commit.DiscardOldFileChanges,
commit.FindBaseCommitForFixup, commit.FindBaseCommitForFixup,
commit.FindBaseCommitForFixupOnlyAddedLines,
commit.FindBaseCommitForFixupWarningForAddedLines, commit.FindBaseCommitForFixupWarningForAddedLines,
commit.Highlight, commit.Highlight,
commit.History, commit.History,