Rewrite History Without Losing the Plot
History editing in lazygit is the problem of placing a selected change where it belongs without making the process unreadable. This chapter follows how lazygit turns a visible commit selection into Git rebase instructions, then compares new commits, fixups, amends, squashes, and custom patches as different ways of preserving or changing that intent. The practical judgment is not simply how to obtain a cleaner graph; it is how to choose a history operation that remains understandable to the person reviewing it and safe for the people who may already depend on it.
A commit graph records more than a final file state. It records the sequence in which decisions were made, and that sequence can be useful while a change is under review. If a reviewer asks for a correction to an older commit, immediately folding the correction into that commit may produce a neat final graph but remove the evidence of what changed in response to the review. Leaving the correction as an ordinary last commit preserves evidence but can make the branch harder to merge. The right operation depends on whether the current goal is review, local repair, or final integration.
Interactive rebase as a visible state transition
An interactive rebase takes a range of commits and asks Git to replay or alter them according to a sequence of instructions. In a traditional workflow, the user may edit a rebase TODO file, change actions such as pick, edit, squash, or fixup, save it, and then respond as Git stops at each required point. The mechanics are powerful, but the TODO file is a poor place to express intent if the user has to translate between lines of text and the commits those lines name.
Lazygit makes the commit list the primary selection surface. The user can choose a commit or range and request an action such as squash, fixup, drop, reword, or movement. The application then constructs the corresponding TODO changes and asks Git to run lazygit as its sequence editor. A short-lived daemon component receives instructions about how the TODO should be changed; the user interacts with the commit representation, while Git remains responsible for executing the rebase. This arrangement preserves the underlying Git operation but moves the high-risk interpretation step into a view where the affected commits, their order, and their relationships are visible.
The distinction between a real commit and a TODO entry matters during this process. An ordinary commit has a hash, parents, author, message, and place in the graph. A TODO entry represents an instruction for the current rebase. It may name a commit while carrying an action that has not yet happened. Lazygit's commit model keeps that action separate from the commit's identity, which lets the UI show both what exists and what Git is about to do. Without that distinction, a user could mistake a planned squash for a completed one or read a temporary rebase state as the final history.
The lifecycle begins with a stable graph and a selected target. Lazygit chooses the appropriate base commit, or the repository root when the operation reaches the first commit, and generates the requested sequence-editor instructions. Git then enters a rebase-in-progress state. Each TODO action can change the commit currently being replayed or the relationship between commits.