TLDR; How to commit parts of file or individual lines with Emacs, magit and git cli
Introduction:
Imagine you're working on a feature branch and have made several changes to a file to implement different aspects of the feature. However, some of these changes are related to the feature being developed, while others are unrelated or incomplete. For example, you may have added new functionality, refactored existing code, and made some debugging changes within the same file.
In such a scenario, you may want to commit the completed and relevant changes first to keep your commits focused and meaningful. This allows you to push incremental updates to the remote repository without including unfinished or unrelated changes.
By committing only part of the file, you can ensure that each commit represents a logical unit of work, making it easier to review, revert, or cherry-pick changes in the future. This practice also facilitates collaboration with other team members, as they can understand the purpose and scope of each commit more effectively.
Committing with Magit:
In Magit, the Git interface for Emacs, you can commit part of a file using the following commands:
Stage Specific Hunks:
-
Navigate to the hunks you want to stage using the arrow keys or mouse.
- Press s to stage the changes in the current hunk (shown as "Hunk 1" in image above).
-
Repeat it for each hunk you want to stage.
Explanation: This command stages specific hunks (chunks of changes) within the file, allowing you to selectively include changes in the next commit.
You are not limited to a single file either, if you have multiple changes in multiple files you can select combination of hunks using the same procedure.
Stage Specific Lines:
-
Move the cursor to highlight the desired lines.
- Select the line(s) you want to stage by placing the cursor on the first line and pressing Ctrl-SPC (Space) to start the selection.
-
Press s to stage the changes on the selected line(s).
Explanation: You can choose to stage specific lines of code by first selecting them. Start the selection by placing the cursor on the initial line and pressing Ctrl-SPC. Then, move the cursor to encompass the lines you wish to stage. After selecting the desired lines, use the staging command (s) to include their changes in the commit.
You are not limited to a single line, if you have multiple lines in multiple files you can select combination of lines using the same procedure. If the change encompasses multiple lines you can select region as well and use same staging procedure to stage regions.
Committing with Git Command Line:
You can achieve similar functionality on the command line using Git's built-in commands. Here's how you can commit specific hunks and lines:
Commit Specific Hunks:
- Use the git add -p command to interactively stage changes.
- Git will present each hunk one by one and prompt you with options like y (stage this hunk), n (do not stage this hunk), s (split this hunk into smaller hunks), and more.
- Press y to stage the hunks you want to include in the commit.
Explanation: The git add -p command initiates an interactive staging process where you can select specific hunks to include in the next commit. This allows you to commit only the desired changes within the file.
Commit Specific Lines:
- Use the git add -p command as before to interactively stage changes.
- When prompted for each hunk, select s to split the hunk into smaller parts.
- Git will then prompt you with each line within the hunk.
- Press y to stage the lines you want to include in the commit.
Explanation: By splitting hunks into smaller parts, you can stage individual lines of code. This enables you to commit specific lines within a file while keeping others unchanged or unstaged.
Other Tools
Apart from magit and git cli, there are couple of more tools that you can use to accomplish same things based on your platform. Here is a small list
- VSCode: VScode has built-in Git support via its Source Control tab
- Git-crecord: Git-crecord is a Git subcommand which allows users to interactively select changes to commit or stage using a ncurses-based text user interface. Works on Linux, Mac, and Windows.
- Lazygit: Lazygit is simple terminal UI for git commands. Works on Linux, Mac, and Windows.
- Sublime Merge: Sublime Merge is a git client from the makers of Sublime Text.
- Git Cola: Git cola is GUI for git, it is powered by python and would require python runtime to be installed on the machine where it needs to be run.
- GitHub Desktop: Official Git client from GitHub. Focused on GitHub Workflows. Windows and Mac only.
- SourceTree: Full featured Git GUI with merge tool and repo management from Atlassian, its free.
- Jetbrains Changelist: Built into Jetbrains IDEs like IntelliJ. Allows commit and diff viewing within editor.
- Git-gui: Lightweight portable Git GUI bundled with Git itself on windows and some Mac versions, you will need to install it for linux separately based on your distribution.
Conclusion:
By following these techniques, developers can leverage Git's powerful features to commit part of a file. Whether using Magit in Emacs or Git on the command line, the ability to commit specific hunks and lines maintains a clean version history, contributing to smoother collaboration.