ronantakizawa/codereview-bench huggingface dataset:
Repository: jesseduffield/lazygit
File: pkg/commands/oscommands/os.go (Go)

Code before:
// AppendLineToFile adds a new line in file
func (c *OSCommand) AppendLineToFile(filename, line string) error {
	c.LogCommand(fmt.Sprintf("Appending '%s' to file '%s'", line, filename), false)
	f, err := os.OpenFile(filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0o600)
	if err != nil {
		return utils.WrapError(err)
	}
	defer f.Close()

	info, err := os.Stat(filename)
	if err != nil {
		return utils.WrapError(err)
	}

	buf := make([]byte, 1)
	if info.Size() > 0 {
		// read last char
		if _, err := f.ReadAt(buf, info.Size()-1); err != nil {
			return utils.WrapError(err)
		}
	}

	// if the last byte of the file is not a newline, add it
	if []byte("\n")[0] != buf[0] {
		_, err = f.WriteString("\n")
	}

	if err == nil {
		_, err = f.WriteString(line + "\n")
	}

	if err != nil {
		return utils.WrapError(err)
	}
	return nil
}

// CreateFileWithContent creates a file with the given content
func (c *OSCommand) CreateFileWithContent(path string, content string) error {
	c.LogCommand(fmt.Sprintf("Creating file '%s'", path), false)
	if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
		c.Log.Error(err)
		return err
	}

	if err := ioutil.WriteFile(path, []byte(content), 0o644); err != nil {
		c.Log.Error(err)
		return utils.WrapError(err)
	}

	return nil

Review comment (suggestion):
```suggestion
	if info.Size() > 0 {
		// read last char
		buf := make([]byte, 1)
		if _, err := f.ReadAt(buf, info.Size()-1); err != nil {
			return utils.WrapError(err)
		}

		// if the last byte of the file is not a newline, add it
		if []byte("\n")[0] != buf[0] {
			_, err = f.WriteString("\n")
		}
	}
```

Code after:
// AppendLineToFile adds a new line in file
func (c *OSCommand) AppendLineToFile(filename, line string) error {
	c.LogCommand(fmt.Sprintf("Appending '%s' to file '%s'", line, filename), false)
	f, err := os.OpenFile(filename, os.O_APPEND|os.O_RDWR|os.O_CREATE, 0o600)
	if err != nil {
		return utils.WrapError(err)
	}
	defer f.Close()

	info, err := os.Stat(filename)
	if err != nil {
		return utils.WrapError(err)
	}

	if info.Size() > 0 {
		// read last char
		buf := make([]byte, 1)
		if _, err := f.ReadAt(buf, info.Size()-1); err != nil {
			return utils.WrapError(err)
		}

		// if the last byte of the file is not a newline, add it
		if []byte("\n")[0] != buf[0] {
			_, err = f.WriteString("\n")
		}
	}

	if err == nil {
		_, err = f.WriteString(line + "\n")
	}

	if err != nil {
		return utils.WrapError(err)
	}
	return nil
}

// CreateFileWithContent creates a file with the given content
func (c *OSCommand) CreateFileWithContent(path string, content string) error {
	c.LogCommand(fmt.Sprintf("Creating file '%s'", path), false)
	if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
		c.Log.Error(err)
		return err
	}

	if err := ioutil.WriteFile(path, []byte(content), 0o644); err != nil {
		c.Log.Error(err)
		return utils.WrapError(err)
	}

	return nil
Repository: jesseduffield/lazygit
File: pkg/utils/formatting.go (Go)

Code before:
			builder.WriteString(WithPadding(stringArray[j], padWidth))
			builder.WriteString(" ")
		}
		if len(stringArray)-1 < len(padWidths) {
			continue
		}
		builder.WriteString(stringArray[len(padWidths)])

		if i < len(stringArrays)-1 {
			builder.WriteString("\n")
		}
	}
	return builder.String()
}

func getPadWidths(stringArrays [][]string) []int {
	maxWidth := slices.MaxBy(stringArrays, func(stringArray []string) int {
		return len(stringArray)
	})

	if maxWidth-1 < 0 {
		return []int{}
	}
	return slices.Map(lo.Range(maxWidth-1), func(i int) int {
		return slices.MaxBy(stringArrays, func(stringArray []string) int {
			// the `cancel` button has only one column so this avoids a crash if maxWidth > 2
			if i >= len(stringArray) {
				i = len(stringArray) - 1
			}
			uncoloredStr := Decolorise(stringArray[i])

			return runewidth.StringWidth(uncoloredStr)
		})
	})
}

// TruncateWithEllipsis returns a string, truncated to a certain length, with an ellipsis
func TruncateWithEllipsis(str string, limit int) string {
	if runewidth.StringWidth(str) > limit && limit <= 3 {
		return strings.Repeat(".", limit)
	}
	return runewidth.Truncate(str, limit, "...")
}

func SafeTruncate(str string, limit int) string {
	if len(str) > limit {
		return str[0:limit]
	} else {
		return str
	}
}

Review comment (bug):
I reckon that this function should be able to safely assume all the rows have the same number of columns. I would instead update the code that adds the cancel option to the menu to ensure it has the same number of columns as other rows.

Reason being that we want this function to catch bugs from elsewhere in the code that cause mismatched columns sizes

Code after:
			builder.WriteString(WithPadding(stringArray[j], padWidth))
			builder.WriteString(" ")
		}
		if len(stringArray)-1 < len(padWidths) {
			continue
		}
		builder.WriteString(stringArray[len(padWidths)])

		if i < len(stringArrays)-1 {
			builder.WriteString("\n")
		}
	}
	return builder.String()
}

func getPadWidths(stringArrays [][]string) []int {
	maxWidth := slices.MaxBy(stringArrays, func(stringArray []string) int {
		return len(stringArray)
	})

	if maxWidth-1 < 0 {
		return []int{}
	}
	return slices.Map(lo.Range(maxWidth-1), func(i int) int {
		return slices.MaxBy(stringArrays, func(stringArray []string) int {
			uncoloredStr := Decolorise(stringArray[i])

			return runewidth.StringWidth(uncoloredStr)
		})
	})
}

// TruncateWithEllipsis returns a string, truncated to a certain length, with an ellipsis
func TruncateWithEllipsis(str string, limit int) string {
	if runewidth.StringWidth(str) > limit && limit <= 3 {
		return strings.Repeat(".", limit)
	}
	return runewidth.Truncate(str, limit, "...")
}

func SafeTruncate(str string, limit int) string {
	if len(str) > limit {
		return str[0:limit]
	} else {
		return str
	}
}

func ShortSha(sha string) string {
	if len(sha) < 8 {
		return sha
Repository: jesseduffield/lazygit
File: pkg/gui/services/custom_commands/handler_creator.go (Go)

Code before:
		return self.c.Error(err)
	}

	cmdObj := self.os.Cmd.NewShell(cmdStr)

	if customCommand.Subprocess {
		return self.c.RunSubprocessAndRefresh(cmdObj)
	}

	loadingText := customCommand.LoadingText
	if loadingText == "" {
		loadingText = self.c.Tr.LcRunningCustomCommandStatus
	}

	return self.c.WithWaitingStatus(loadingText, func() error {
		self.c.LogAction(self.c.Tr.Actions.CustomCommand)

		if customCommand.Stream {
			cmdObj.StreamOutput()
		}
		output, err := cmdObj.RunWithOutput()
		if err != nil {
			return self.c.Error(err)
		}
		if customCommand.ShowOutput {
			return self.c.Alert(cmdStr, output)
		}
		return self.c.Refresh(types.RefreshOptions{})
	})
}


Review comment (suggestion):
Does this call `self.c.Refresh` somewhere in the background, because other control paths do invoke it (e.g. `return self.c.RunSubprocessAndRefresh(cmdObj)`)

Code after:
	cmdStr, err := resolveTemplate(customCommand.Command)
	if err != nil {
		return self.c.Error(err)
	}

	cmdObj := self.os.Cmd.NewShell(cmdStr)

	if customCommand.Subprocess {
		return self.c.RunSubprocessAndRefresh(cmdObj)
	}

	loadingText := customCommand.LoadingText
	if loadingText == "" {
		loadingText = self.c.Tr.LcRunningCustomCommandStatus
	}

	return self.c.WithWaitingStatus(loadingText, func() error {
		self.c.LogAction(self.c.Tr.Actions.CustomCommand)

		if customCommand.Stream {
			cmdObj.StreamOutput()
		}
		output, err := cmdObj.RunWithOutput()
		if err != nil {
			return self.c.Error(err)
		}

		if customCommand.ShowOutput {
			if strings.TrimSpace(output) == "" {
				output = self.c.Tr.EmptyOutput
			}
			if err = self.c.Alert(cmdStr, output); err != nil {
				return self.c.Error(err)
			}
			return self.c.Refresh(types.RefreshOptions{})
		}
		return self.c.Refresh(types.RefreshOptions{})
	})
}
Repository: jesseduffield/lazygit
File: pkg/app/app.go (Go)

Code before:
		if !shouldInitRepo {
			// check if we have a recent repo we can open
			for _, repoDir := range app.Config.GetAppState().RecentRepos {
				if isRepo, _ := isDirectoryAGitRepository(repoDir); isRepo {
					if err := os.Chdir(repoDir); err == nil {
						return true, nil
					}
				}
			}

			fmt.Println(app.Tr.NoRecentRepositories)
			os.Exit(1)
		}
		if err := app.OSCommand.Cmd.New("git init " + initialBranch).Run(); err != nil {
			return false, err
		}
	}

	// Run this afterward so that the previous repo creation steps can run without this interfering
	if isBare, err := isBareRepo(app.OSCommand); isBare {
		if err != nil {
			return false, err
		}

		if isBare {
			log.Fatalln("bare repositories are not supported by lazygit, please make this a working repository.")
		}
	}

	return false, nil
}

func (app *App) Run(startArgs types.StartArgs) error {
	err := app.Gui.RunAndHandleError(startArgs)
	return err
}

// Close closes any resources
func (app *App) Close() error {
	return slices.TryForEach(app.closers, func(closer io.Closer) error {
		return closer.Close()
	})
}


Review comment (suggestion):
I'd add the word `yet` here somewhere to indicate that it _is_ on the roadmap, but hasn't been implemented as of this moment.

Code after:
			}
		case "create":
			shouldInitRepo = true
		case "skip":
			shouldInitRepo = false
		case "quit":
			fmt.Fprintln(os.Stderr, app.Tr.NotARepository)
			os.Exit(1)
		default:
			fmt.Fprintln(os.Stderr, app.Tr.IncorrectNotARepository)
			os.Exit(1)
		}

		if shouldInitRepo {
			if err := app.OSCommand.Cmd.New("git init " + initialBranchArg).Run(); err != nil {
				return false, err
			}
			return false, nil
		}

		// check if we have a recent repo we can open
		for _, repoDir := range app.Config.GetAppState().RecentRepos {
			if isRepo, _ := isDirectoryAGitRepository(repoDir); isRepo {
				if err := os.Chdir(repoDir); err == nil {
					return true, nil
				}
			}
		}

		fmt.Fprintln(os.Stderr, app.Tr.NoRecentRepositories)
		os.Exit(1)
	}

	// Run this afterward so that the previous repo creation steps can run without this interfering
	if isBare, err := git_commands.IsBareRepo(app.OSCommand); isBare {
		if err != nil {
			return false, err
		}

		fmt.Print(app.Tr.BareRepo)

		response, _ := bufio.NewReader(os.Stdin).ReadString('\n')

		if shouldOpenRecent := strings.Trim(response, " \r\n") == "y"; !shouldOpenRecent {
			os.Exit(0)
		}

		if didOpenRepo := openRecentRepo(app); didOpenRepo {
			return true, nil
		}
Repository: jesseduffield/lazygit
File: pkg/app/app.go (Go)

Code before:
	re := regexp.MustCompile(`[^\d]+([\d\.]+)`)
	matches := re.FindStringSubmatch(versionStr)

	if len(matches) == 0 {
		return false
	}

	gitVersion := matches[1]
	majorVersion, err := strconv.Atoi(gitVersion[0:1])
	if err != nil {
		return false
	}
	if majorVersion < 2 {
		return false
	}

	return true
}

func isDirectoryAGitRepository(dir string) (bool, error) {
	info, err := os.Stat(filepath.Join(dir, ".git"))
	return info != nil, err
}

func isBareRepo(osCommand *oscommands.OSCommand) (bool, error) {
	res, err := osCommand.Cmd.New("git rev-parse --is-bare-repository").DontLog().RunWithOutput()

	if err != nil {
		return false, err
	}

	// The command returns output with a newline, so we need to strip
	return strconv.ParseBool(strings.TrimSpace(res))
}

func openRecentRepo(app *App) bool {
	for _, repoDir := range app.Config.GetAppState().RecentRepos {
		if isRepo, _ := isDirectoryAGitRepository(repoDir); isRepo {
			if err := os.Chdir(repoDir); err == nil {
				return true
			}
		}
	}

	return false
}

func (app *App) setupRepo() (bool, error) {
	if err := app.validateGitVersion(); err != nil {
		return false, err
	}

Review comment (refactor):
@jesseduffield should we somehow conflate this `isBareRepo` and [this](https://github.com/nullishamy/lazygit/blob/bdb0b9ae6e84ce7261190f156f8f16fc7d62cffd/pkg/commands/git_commands/status.go#L57) one?

Currently I think the one from `recent_repos_panel` isn't reachable from `app.go`, but maybe it's better to make it public rather than have a duplicate?

Code after:
	return minVersionError
}

func isGitVersionValid(versionStr string) bool {
	// output should be something like: 'git version 2.23.0 (blah)'
	re := regexp.MustCompile(`[^\d]+([\d\.]+)`)
	matches := re.FindStringSubmatch(versionStr)

	if len(matches) == 0 {
		return false
	}

	gitVersion := matches[1]
	majorVersion, err := strconv.Atoi(gitVersion[0:1])
	if err != nil {
		return false
	}
	if majorVersion < 2 {
		return false
	}

	return true
}

func isDirectoryAGitRepository(dir string) (bool, error) {
	info, err := os.Stat(filepath.Join(dir, ".git"))
	return info != nil, err
}

func openRecentRepo(app *App) bool {
	for _, repoDir := range app.Config.GetAppState().RecentRepos {
		if isRepo, _ := isDirectoryAGitRepository(repoDir); isRepo {
			if err := os.Chdir(repoDir); err == nil {
				return true
			}
		}
	}

	return false
}

func (app *App) setupRepo() (bool, error) {
	if err := app.validateGitVersion(); err != nil {
		return false, err
	}

	if env.GetGitDirEnv() != "" {
		// we've been given the git dir directly. We'll verify this dir when initializing our Git object
		return false, nil
	}
Repository: jesseduffield/lazygit
File: pkg/gui/menu_panel.go (Go)

Code before:
			LabelColumns: []string{gui.c.Tr.LcCancel},
			OnPress: func() error {
				return nil
			},
		})
	}

	for _, item := range opts.Items {
		if item.OpensMenu && item.LabelColumns != nil {
			return errors.New("Message for the developer of this app: you've set opensMenu with displaystrings on the menu panel. Bad developer!. Apologies, user")
		}
	}

	gui.State.Contexts.Menu.SetMenuItems(opts.Items)
	gui.State.Contexts.Menu.SetSelectedLineIdx(0)

	gui.Views.Menu.Title = opts.Title
	gui.Views.Menu.FgColor = theme.GocuiDefaultTextColor
	gui.Views.Menu.SetOnSelectItem(gui.onSelectItemWrapper(func(selectedLine int) error {
		return nil
	}))

	gui.Views.Tooltip.Wrap = true
	gui.Views.Tooltip.FgColor = theme.GocuiDefaultTextColor
	gui.Views.Tooltip.Visible = true

	// resetting keybindings so that the menu-specific keybindings are registered
	if err := gui.resetKeybindings(); err != nil {
		return err
	}

	_ = gui.c.PostRefreshUpdate(gui.State.Contexts.Menu)

	// TODO: ensure that if we're opened a menu from within a menu that it renders correctly
	return gui.c.PushContext(gui.State.Contexts.Menu)
}


Review comment (suggestion):
I considered making the downstream code more lenient i.e. just dealing better with being passed rows of different column numbers, but I think it's better to be explicit at the call site, given how easily we could accidentally forget to add a column to a given row when rendering, say, the commits panel.

Code after:
		opts.Items = append(opts.Items, &types.MenuItem{
			LabelColumns: []string{gui.c.Tr.LcCancel},
			OnPress: func() error {
				return nil
			},
		})
	}

	maxColumnSize := 1

	for _, item := range opts.Items {
		if item.LabelColumns == nil {
			item.LabelColumns = []string{item.Label}
		}

		if item.OpensMenu {
			item.LabelColumns[0] = presentation.OpensMenuStyle(item.LabelColumns[0])
		}

		maxColumnSize = utils.Max(maxColumnSize, len(item.LabelColumns))
	}

	for _, item := range opts.Items {
		if len(item.LabelColumns) < maxColumnSize {
			// we require that each item has the same number of columns so we're padding out with blank strings
			// if this item has too few
			item.LabelColumns = append(item.LabelColumns, make([]string, maxColumnSize-len(item.LabelColumns))...)
		}
	}

	gui.State.Contexts.Menu.SetMenuItems(opts.Items)
	gui.State.Contexts.Menu.SetSelectedLineIdx(0)

	gui.Views.Menu.Title = opts.Title
	gui.Views.Menu.FgColor = theme.GocuiDefaultTextColor
	gui.Views.Menu.SetOnSelectItem(gui.onSelectItemWrapper(func(selectedLine int) error {
		return nil
	}))

	gui.Views.Tooltip.Wrap = true
	gui.Views.Tooltip.FgColor = theme.GocuiDefaultTextColor
	gui.Views.Tooltip.Visible = true

	// resetting keybindings so that the menu-specific keybindings are registered
	if err := gui.resetKeybindings(); err != nil {
		return err
	}

	_ = gui.c.PostRefreshUpdate(gui.State.Contexts.Menu)

	// TODO: ensure that if we're opened a menu from within a menu that it renders correctly
Repository: jesseduffield/lazygit
File: pkg/gui/controllers/stash_controller.go (Go)

Code before:
		},
	})
}

func (self *StashController) postStashRefresh() error {
	return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}})
}

func (self *StashController) handleNewBranchOffStashEntry(stashEntry *models.StashEntry) error {
	return self.helpers.Refs.NewBranch(stashEntry.RefName(), stashEntry.Description(), "")
}

func (self *StashController) handleRenameStashEntry(stashEntry *models.StashEntry) error {
	message := utils.ResolvePlaceholderString(
		self.c.Tr.RenameStashPrompt,
		map[string]string{
			"stashName": stashEntry.RefName(),
		},
	)

	return self.c.Prompt(types.PromptOpts{
		Title:          message,
		InitialContent: stashEntry.Name,
		HandleConfirm: func(response string) error {
			self.c.LogAction(self.c.Tr.Actions.RenameStash)
			output, err := self.git.Stash.Drop(stashEntry.Index)
			if err != nil {
				return err
			}

			stashShaPattern := regexp.MustCompile(`\(([0-9a-f]+)\)`)
			matches := stashShaPattern.FindStringSubmatch(output)
			stashSha := ""
			if len(matches) > 1 {
				stashSha = matches[1]
			}

			err = self.git.Stash.Store(stashSha, response)
			_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
			if err != nil {
				return err
			}
			return nil
		},
	})
}


Review comment (refactor):
I would move this logic of this `HandleConfirm` callback into `pkg/commands/git_commands/stash.go` because it's quite specific to git. The `LogAction` and `Refresh` calls can stay here

Code after:
}

func (self *StashController) postStashRefresh() error {
	return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH, types.FILES}})
}

func (self *StashController) handleNewBranchOffStashEntry(stashEntry *models.StashEntry) error {
	return self.helpers.Refs.NewBranch(stashEntry.RefName(), stashEntry.Description(), "")
}

func (self *StashController) handleRenameStashEntry(stashEntry *models.StashEntry) error {
	message := utils.ResolvePlaceholderString(
		self.c.Tr.RenameStashPrompt,
		map[string]string{
			"stashName": stashEntry.RefName(),
		},
	)

	return self.c.Prompt(types.PromptOpts{
		Title:          message,
		InitialContent: stashEntry.Name,
		HandleConfirm: func(response string) error {
			self.c.LogAction(self.c.Tr.Actions.RenameStash)
			err := self.git.Stash.Rename(stashEntry.Index, response)
			_ = self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.STASH}})
			if err != nil {
				return err
			}
			self.context().SetSelectedLineIdx(0) // Select the renamed stash
			return nil
		},
	})
}
Repository: jesseduffield/lazygit
File: pkg/commands/git_commands/stash.go (Go)

Code before:
	// if you had staged an untracked file, that will now appear as 'AD' in git status
	// meaning it's deleted in your working tree but added in your index. Given that it's
	// now safely stashed, we need to remove it.
	files := self.fileLoader.
		GetStatusFiles(loaders.GetStatusFileOptions{})

	for _, file := range files {
		if file.ShortStatus == "AD" {
			if err := self.workingTree.UnStageFile(file.Names(), false); err != nil {
				return err
			}
		}
	}

	return nil
}

func (self *StashCommands) Rename(index int, message string) error {
	output, err := self.Drop(index)
	if err != nil {
		return err
	}

	// `output` is in the following format:
	// Dropped refs/stash@{0} (f0d0f20f2f61ffd6d6bfe0752deffa38845a3edd)
	stashShaPattern := regexp.MustCompile(`\(([0-9a-f]+)\)`)
	matches := stashShaPattern.FindStringSubmatch(output)
	if len(matches) <= 1 {
		return errors.New("Output of `git stash drop` is invalid") // Usually this error does not occur
	}
	stashSha := matches[1]

	err = self.Store(stashSha, message)
	if err != nil {
		return err
	}

	return nil
}


Review comment (performance):
Just tested this out locally, and it works, but I think we should change the approach a bit. You can use `git rev-parse stash@{<index>}` to obtain the hash, and I think we ought to do that for a couple of reasons:
1) `git rev-parse`'s output is never going to change, but I can imagine the output of `git stash drop` changing. If `git stash drop` does change its output, we'll have just lost the user's stash which is going to make them very mad.
2) it spares us the complexity of regexes

So I propose we run three commands:
1) `git rev-parse stash@{<index>}` to get the hash
2) `git stash drop stash@{<index>}` to drop it
3) `git stash store <hash>` to store the renamed stash entry

Code after:
	}

	// if you had staged an untracked file, that will now appear as 'AD' in git status
	// meaning it's deleted in your working tree but added in your index. Given that it's
	// now safely stashed, we need to remove it.
	files := self.fileLoader.
		GetStatusFiles(loaders.GetStatusFileOptions{})

	for _, file := range files {
		if file.ShortStatus == "AD" {
			if err := self.workingTree.UnStageFile(file.Names(), false); err != nil {
				return err
			}
		}
	}

	return nil
}

func (self *StashCommands) Rename(index int, message string) error {
	sha, err := self.Sha(index)
	if err != nil {
		return err
	}

	if err := self.Drop(index); err != nil {
		return err
	}

	err = self.Store(sha, message)
	if err != nil {
		return err
	}

	return nil
}
Repository: jesseduffield/lazygit
File: pkg/integration/tests/branch/checkout_by_name.go (Go)

Code before:
package branch

import (
	"github.com/jesseduffield/lazygit/pkg/config"
	. "github.com/jesseduffield/lazygit/pkg/integration/components"
)

var CheckoutByName = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Try to checkout branch by name.",
	ExtraCmdArgs: "",
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.
			CreateNCommits(3).
			NewBranch("@").
			Checkout("master").
			EmptyCommit("blah")
	},
	Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
		input.SwitchToBranchesWindow()
		assert.CurrentViewName("localBranches")

		assert.MatchSelectedLine(Contains("master"))
		input.NextItem()
		assert.MatchSelectedLine(Contains("@"))
		input.PressKeys(keys.Branches.CheckoutBranchByName)
		assert.InPrompt()
		assert.MatchCurrentViewTitle(Equals("Branch name:"))
		input.Type("new-branch")
		input.Confirm()
		assert.InAlert()
		input.Confirm()


Review comment (bug):
Could we add some more to this description about the specific bug we're trying to defend against? That will help people understand why the test is slightly more complicated than just directly checking out a branch by name

Code after:
package branch

import (
	"github.com/jesseduffield/lazygit/pkg/config"
	. "github.com/jesseduffield/lazygit/pkg/integration/components"
)

var CheckoutByName = NewIntegrationTest(NewIntegrationTestArgs{
	Description:  "Try to checkout branch by name. Verify that it also works on the branch with the special name @.",
	ExtraCmdArgs: "",
	Skip:         false,
	SetupConfig:  func(config *config.AppConfig) {},
	SetupRepo: func(shell *Shell) {
		shell.
			CreateNCommits(3).
			NewBranch("@").
			Checkout("master").
			EmptyCommit("blah")
	},
	Run: func(shell *Shell, input *Input, assert *Assert, keys config.KeybindingConfig) {
		input.SwitchToBranchesWindow()
		assert.CurrentViewName("localBranches")

		assert.MatchSelectedLine(Contains("master"))
		input.NextItem()
		assert.MatchSelectedLine(Contains("@"))
		input.PressKeys(keys.Branches.CheckoutBranchByName)
		assert.InPrompt()
		assert.MatchCurrentViewTitle(Equals("Branch name:"))
		input.Type("new-branch")
		input.Confirm()
		assert.InAlert()
		assert.MatchCurrentViewContent(Equals("Branch not found. Create a new branch named new-branch?"))
		input.Confirm()