How lazygit Handles Large Repositories with Many Files and Commits

lazygit handles large repositories by lazy-loading commit history and limiting initial git log output to 300 commits, automatically expanding the view when users scroll past a 200-commit threshold.

The lazygit terminal UI is engineered to remain responsive even when navigating repositories containing thousands of files and tens of thousands of commits. According to the lazygit source code, this performance is achieved through a lazy-loading architecture that defers expensive Git operations until explicitly requested by the user.

The Lazy-Loading Architecture

Limiting Initial Commit History

When lazygit opens a repository, it does not immediately load the entire commit graph. Instead, the CommitLoader in pkg/commands/git_commands/commit_loader.go constructs a git log command that returns only the most recent 300 commits by default.

The command builder uses conditional arguments to inject the limit flag only when the Limit option is enabled:

func (self *CommitLoader) getLogCmd(opts GetCommitsOptions) *oscommands.CmdObj {
    cmdArgs := NewGitCmd("log").
        Arg(opts.RefName).
        ArgIf(opts.All, "--all").
        Arg("--oneline").
        Arg(prettyFormat).
        ArgIf(opts.Limit, "-300") // <-- limits output to 300 commits
    return self.cmd.New(cmdArgs).DontLog()
}

Source: commit_loader.go#L89-L99

The Commit Threshold Mechanism

To balance responsiveness with access to full history, lazygit implements a threshold constant of 200 commits. This heuristic is defined in pkg/gui/controllers/local_commits_controller.go as COMMIT_THRESHOLD.

When a user scrolls through the commit list and the selected index exceeds this threshold, the controller automatically disables the limit flag and refreshes the view to load the complete commit history.

Key Implementation Details

Building the Limited Git Command

The CommitLoader orchestrates the lazy-loading process. In pkg/commands/git_commands/commit_loader.go, the loadCommits function executes the constructed command and parses the output into models.Commit structs. By default, the UI initializes with GetCommitsOptions{Limit: true}, ensuring that massive repositories do not freeze the terminal on startup.

Monitoring User Navigation

The LocalCommitsController in pkg/gui/controllers/local_commits_controller.go monitors focus events to detect when the user approaches the end of the limited commit range:

func (self *LocalCommitsController) GetOnFocus() func(types.OnFocusOpts) {
    return func(types.OnFocusOpts) {
        context := self.context()
        if context.GetSelectedLineIdx() > COMMIT_THRESHOLD && context.GetLimitCommits() {
            context.SetLimitCommits(false)               // remove the limit
            self.c.Refresh(types.RefreshOptions{
                Mode:  types.ASYNC,
                Scope: []types.RefreshableView{types.COMMITS},
            })
        }
    }
}

Source: local_commits_controller.go#L9-L15

Managing UI State

The limit flag is stored in the LocalCommitsContext view model defined in pkg/gui/context/local_commits_context.go. This context provides SetLimitCommits and GetLimitCommits methods that the controller uses to toggle between restricted and full history modes.

func (self *LocalCommitsViewModel) SetLimitCommits(value bool) { self.limitCommits = value }
func (self *LocalCommitsViewModel) GetLimitCommits() bool    { return self.limitCommits }

Source: local_commits_context.go#L30-L36

Automatic Expansion Triggers

Scrolling Past the Threshold

When the selected commit index exceeds the COMMIT_THRESHOLD of 200, lazygit assumes the user intends to browse deeper history. The controller clears the limitCommits flag and triggers an asynchronous refresh, causing the next git log execution to omit the -300 argument and stream the full commit graph.

Show Whole Git Graph Toggle

Users can manually force a full load by toggling the "Show whole git graph" option. This action calls SetShowWholeGitGraph on the context, which internally disables the commit limit:

self.context().SetShowWholeGitGraph(!self.context().GetShowWholeGitGraph())
if self.context().GetShowWholeGitGraph() {
    self.context().SetLimitCommits(false) // load everything
}

Source: local_commits_controller.go

File-Level Optimizations

Beyond commit history, lazygit applies similar lazy-loading principles to file operations. When displaying working tree changes, the UI only executes git diff for the specific file currently under the cursor. This on-demand diff generation, implemented in pkg/commands/git_commands/working_tree.go, prevents the terminal from freezing when repositories contain thousands of modified files.

Summary

  • lazygit limits initial commit history to 300 commits using a conditional -300 flag in git log commands constructed by CommitLoader.
  • The 200-commit threshold (COMMIT_THRESHOLD) triggers automatic expansion when users scroll deep into the history.
  • UI state management via LocalCommitsContext tracks whether the view is limited, allowing controllers to toggle between restricted and full modes.
  • Manual overrides like "Show whole git graph" immediately disable limits for users who need complete visibility.
  • File-level lazy loading ensures diffs are computed only for selected files, keeping the UI responsive in large working trees.

Frequently Asked Questions

How many commits does lazygit load by default?

By default, lazygit loads only the 300 most recent commits when you open a repository. This limit is applied via the -300 argument passed to the git log command in pkg/commands/git_commands/commit_loader.go. The restriction keeps the UI responsive on repositories with tens of thousands of commits.

At what point does lazygit load the full commit history?

lazygit loads the full commit history when you scroll past the 200-commit threshold (defined as COMMIT_THRESHOLD in pkg/gui/controllers/local_commits_controller.go). Once your cursor moves beyond the 200th commit, the controller automatically clears the limit flag and refreshes the view to stream the complete Git history.

Can I force lazygit to show all commits immediately?

Yes. You can toggle the "Show whole git graph" option, which calls SetShowWholeGitGraph on the LocalCommitsContext. This action disables the commit limit immediately, causing the next refresh to execute a full git log without the -300 restriction. Alternatively, simply scrolling past the 200-commit threshold triggers the same behavior automatically.

How does lazygit handle repositories with thousands of modified files?

lazygit uses on-demand diff generation for file operations. Rather than computing diffs for every modified file upfront, the UI only executes git diff for the specific file currently selected in the working tree view. This implementation in pkg/commands/git_commands/working_tree.go ensures that viewing the status of a repository with thousands of pending changes remains fluid and responsive.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →