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:
parent
c1a65546ad
commit
dbdabb34f3
@ -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
|
||||||
|
@ -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)",
|
||||||
|
@ -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)",
|
||||||
|
@ -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"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
})
|
@ -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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user