Repository: jesseduffield/lazygit
File: pkg/gui/controllers/helpers/fixup_helper.go (Go)

Code before:
	deletedLineInfos := self.parseDiff(diff)
	if len(deletedLineInfos) == 0 {
		return self.c.ErrorMsg("No deleted lines in diff")
	}

	shas := self.blameDeletedLines(deletedLineInfos)

	if len(shas) == 0 {
		// This should never happen
		return self.c.ErrorMsg("No base commits found")
	}
	if len(shas) > 1 {
		subjects, err := self.c.Git().Commit.GetShasAndCommitMessagesFirstLine(shas)
		if err != nil {
			return err
		}
		return self.c.ErrorMsg("Multiple base commits found. (" +
			lo.Ternary(useIndex, "Try staging fewer changes", "Try staging some of the changes") +
			")\n\n" + subjects)
	}

	commit, index, ok := lo.FindIndexOf(self.c.Model().Commits, func(commit *models.Commit) bool {
		return commit.Sha == shas[0]
	})
	if !ok {
		if self.c.Model().Commits[len(self.c.Model().Commits)-1].Status == models.StatusMerged {
			// If the commit is not found, it's most likely because it's already
			// merged, and more than 300 commits away. Check if the last known
			// commit is already merged; if so, show the "already merged" error.
			return self.c.ErrorMsg("The base commit for this change is already on master")
		}
		// If we get here, the current branch must have more then 300 commits. Unlikely...
		return self.c.ErrorMsg("Base commit is not in current view")
	}
	if commit.Status == models.StatusMerged {
		return self.c.ErrorMsg("The base commit for this change is already on master")
	}

	if !useIndex {
		if err := self.c.Git().WorkingTree.StageAll(); err != nil {
			return err
		}
		_ = self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}})
	}

	self.c.Contexts().LocalCommits.SetSelectedLineIdx(index)
	return self.c.PushContext(self.c.Contexts().LocalCommits)
}

func (self *FixupHelper) getDiff() (string, bool, error) {
	args := []string{"-U0", "--ignore-submodules=all", "HEAD", "--"}

Review comment (suggestion):
I would assign `self.c.Model().Commits` to a variable before this line so that if the slice gets swapped out concurrently we don't run the risk of an out-of-bounds exception

Code after:
	deletedLineInfos, hasHunksWithOnlyAddedLines := self.parseDiff(diff)
	if len(deletedLineInfos) == 0 {
		return self.c.ErrorMsg(self.c.Tr.NoDeletedLinesInDiff)
	}

	shas := self.blameDeletedLines(deletedLineInfos)

	if len(shas) == 0 {
		// This should never happen
		return self.c.ErrorMsg(self.c.Tr.NoBaseCommitsFound)
	}
	if len(shas) > 1 {
		subjects, err := self.c.Git().Commit.GetShasAndCommitMessagesFirstLine(shas)
		if err != nil {
			return err
		}
		message := lo.Ternary(hasStagedChanges,
			self.c.Tr.MultipleBaseCommitsFoundStaged,
			self.c.Tr.MultipleBaseCommitsFoundUnstaged)
		return self.c.ErrorMsg(message + "\n\n" + subjects)
	}

	commit, index, ok := lo.FindIndexOf(self.c.Model().Commits, func(commit *models.Commit) bool {
		return commit.Sha == shas[0]
	})
	if !ok {
		commits := self.c.Model().Commits
		if commits[len(commits)-1].Status == models.StatusMerged {
			// If the commit is not found, it's most likely because it's already
			// merged, and more than 300 commits away. Check if the last known
			// commit is already merged; if so, show the "already merged" error.
			return self.c.ErrorMsg(self.c.Tr.BaseCommitIsAlreadyOnMainBranch)
		}
		// If we get here, the current branch must have more then 300 commits. Unlikely...
		return self.c.ErrorMsg(self.c.Tr.BaseCommitIsNotInCurrentView)
	}
	if commit.Status == models.StatusMerged {
		return self.c.ErrorMsg(self.c.Tr.BaseCommitIsAlreadyOnMainBranch)
	}

	doIt := func() error {
		if !hasStagedChanges {
			if err := self.c.Git().WorkingTree.StageAll(); err != nil {
				return err
			}
			_ = self.c.Refresh(types.RefreshOptions{Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}})
		}

		self.c.Contexts().LocalCommits.SetSelectedLineIdx(index)
		return self.c.PushContext(self.c.Contexts().LocalCommits)
	}