So far, you have staged entire files with git add. But what happens when a single file contains changes that belong in different commits? Maybe you added a feature and removed a console.log in the same file, or you fixed a bug while also refactoring nearby code.
Staging the entire file would bundle unrelated changes into one commit, making your history harder to read, harder to review, and harder to revert. Partial staging lets you pick exactly which lines go into each commit.
Here is a file with two unrelated changes mixed together — a new import and debounce hook (feature work) alongside the removal of a TODO comment and console.log (cleanup):
Komitly - Mixed changes in one file
src/components/SearchBar.tsx
@@ -1,9 +1,12 @@
11import { useState } from 'react';
2+import { useDebounce } from '../hooks/useDebounce';
9+ const res = await fetch(`/api/search?q=${debouncedQuery}`);
10+ return res.json();
11+ };
812
913 return (
With partial staging, you can split this into two clean commits instead of one messy one:
Komitly - Clean, focused history
d4e5f6afeat: add search API integrationmain
c3d4e5ffeat: add useDebounce hook and search imports
b2c3d4erefactor: remove TODO and console.log from SearchBar
a1b2c3dInitial commit
Compare that to the alternative — everything lumped together:
Komitly - Messy history
b2c3d4eAdd search stuff and cleanup and APImain
a1b2c3dInitial commit
Partial staging is what separates a history that tells a story from a history that is just a timeline of saves. Each commit should represent one logical change — and partial staging is how you achieve that when reality does not cooperate.
git add -p: Interactive hunk staging
The -p (patch) flag turns git add into an interactive tool. Instead of staging the whole file, Git shows you each hunk (a block of consecutive changes) and asks whether to stage it.
Terminal
$ git add -p src/components/SearchBar.tsx
Hover over each part to see what it does
The prompt options
At each hunk, Git shows a prompt with single-letter options. Here is what each one does:
git add -p options
y — Stage this hunk (yes)
n — Skip this hunk (no)
q — Quit — do not stage this hunk or any remaining hunks
a — Stage this hunk and ALL remaining hunks in this file
d — Do not stage this hunk or any remaining hunks in this file
s — Split this hunk into smaller hunks (only works if there are
unchanged lines between changes)
e — Manually edit this hunk (advanced — opens your editor)
? — Show help
The most common workflow is simple: press y to stage a hunk, n to skip it. For most partial staging tasks, that is all you need.
What a hunk looks like
Git splits the diff into hunks automatically. Each hunk is a contiguous block of changes surrounded by unchanged context lines. Here is how our file splits into two hunks:
Hunk 1 — New import and debounce hook
src/components/SearchBar.tsx
@@ -1,4 +1,5 @@ Hunk 1: Add import
11import { useState } from 'react';
2+import { useDebounce } from '../hooks/useDebounce';
@@ -7,8 +8,11 @@ Hunk 2: Replace TODO with implementation
11
2- // TODO: implement search
3- console.log('search query:', query);
2+ const handleSearch = async () => {
3+ const res = await fetch(`/api/search?q=${debouncedQuery}`);
4+ return res.json();
5+ };
46
57 return (
You can stage hunk 1 and skip hunk 2, then commit. After that, stage hunk 2 and commit separately. The file ends up with the same final state, but the history tells a clearer story.
Beyond hunks: Editing and splitting
Splitting hunks with s
Sometimes Git groups changes into a single hunk that you want to split. If there are unchanged lines between the modifications, pressing s splits the hunk into smaller pieces:
Terminal
@@ -1,12 +1,15 @@
import { useState } from 'react';
+import { useDebounce } from '../hooks/useDebounce';
...
- // TODO: implement search
- console.log('search query:', query);
+ const handleSearch = async () => {
+ ...
(1/1) Stage this hunk [y,n,q,a,d,s,e,?]? s
Split into 2 hunks.
@@ -1,4 +1,5 @@
import { useState } from 'react';
+import { useDebounce } from '../hooks/useDebounce';
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]? y
The s option only works when there are context lines between changes. If the changes are on adjacent lines, you need the e (edit) option instead.
Manual editing with e
The e option is the most powerful but also the most error-prone. It opens the hunk in your editor and lets you choose individual lines to stage:
Manual hunk editing rules
# When you press 'e', Git opens the hunk in your editor.
# Rules for editing:
#
# - Lines starting with '-' (deletions):
# Remove the line to KEEP the deletion
# Change '-' to ' ' (space) to IGNORE the deletion
#
# - Lines starting with '+' (additions):
# Keep the line to STAGE the addition
# Delete the line to NOT STAGE the addition
#
# - Lines starting with ' ' (context):
# Do not edit these — they are reference lines
#
# Save and close the editor to apply your edits.
The e option requires careful attention to the rules. One wrong edit and the patch fails silently. For most people, a visual tool is far safer and faster for line-level staging — which is where Komitly shines.
Line-level staging in Komitly
The terminal interface for git add -p works, but it is awkward — you cannot see the full file, you cannot easily go back, and the e option is fragile. Komitly replaces this entire workflow with a visual diff viewer where staging is as simple as clicking.
Hunk staging
In the diff viewer, each hunk has a Stage button in the gutter. Click it to stage that hunk — the file immediately appears in both the staged and unstaged sections of the staging panel, because part of it is staged and part is not:
Komitly - Partially staged file
Staged (2)
Msrc/components/SearchBar.tsx
Asrc/hooks/useDebounce.ts
Changes (2)
Msrc/components/SearchBar.tsx
Msrc/utils/api.ts
Line-level selection
For even more precision, toggle to line staging mode in the diff viewer header. Now you can:
Click individual added or removed lines to select them.
Shift+click to select a range of lines.
Click Stage Selected to stage only the selected lines.
This is the visual equivalent of git add -p with the e option — but without the error-prone manual editing. You see the entire diff, click the lines you want, and stage them. Done.
Unstage and discard by line
The same line-level control works in reverse. After staging, you can select individual lines and Unstage Selected to move them back. You can also Discard Selected to permanently remove specific lines from the working tree — with a confirmation dialog to prevent accidents.
Toggle between modes
The diff viewer header has a toggle to switch between hunk mode and line mode. Use hunk mode for quick staging when hunks align with your intent. Switch to line mode when you need finer control.
Line-level staging in Komitly replaces the most intimidating part of git add -p — the e option — with a click-to-select interface. You see the full diff, pick lines visually, and stage them without risk of a broken patch.
Practical examples
Here are three real-world scenarios where partial staging makes your history significantly better:
Terminal
$ git add -p src/components/SearchBar.tsx
# Stage only the hunk that removes console.log → y
# Skip the hunk that adds the import → n
$ git commit -m "refactor: remove TODO and console.log from SearchBar"
[main b2c3d4e] refactor: remove TODO and console.log from SearchBar
[main c3d4e5f] feat: add useDebounce hook and search imports
Terminal
$ git add -p
# For each hunk: 'y' to stage clean code, 'n' to skip debug code
# For mixed hunks: 's' to split or 'e' to manually edit
$ git commit -m "feat: add search API integration"
[main d4e5f6a] feat: add search API integration
# Now discard the debug lines
$ git restore src/components/SearchBar.tsx
Organizing a messy session
# Review what changed
git diff --stat
# Stage and commit each concern separately
git add -p # Pick hunks for the first logical commit
git commit -m "refactor: extract validation logic"
git add -p # Pick hunks for the second commit
git commit -m "feat: add input length validation"
git add -p # Pick hunks for the third commit
git commit -m "test: add validation edge case tests"
Best practices
Stage by intent, not by file. The question is not "which files changed?" but "which changes belong together?" A single file can contribute to multiple commits.
Review the staged diff before committing. After partial staging, always run git diff --staged (or click through staged files in Komitly) to verify the commit is coherent and nothing is missing.
Commit more often. If you find yourself doing a lot of partial staging, it is a sign you should be committing more frequently. Stage and commit after each logical change instead of batching them.
Use hunk mode for speed, line mode for precision. Most of the time, hunk-level staging is enough. Reserve line-level selection for cases where a hunk contains mixed concerns.
Test after partial staging. After staging a subset of changes, make sure the committed state actually works. You can temporarily stash the unstaged changes with git stash --keep-index to test only the staged code.
Summary
Partial staging is the key to a clean, readable Git history. Instead of committing everything at once, you pick exactly which changes go into each commit. Here is a quick recap:
git add -p — Stage individual hunks interactively. Use y/n to accept or skip hunks, s to split, and e to edit manually.
Hunks are contiguous blocks of changes. If a hunk is too large, split it with s or edit with e.
A file can appear in both the staged and unstaged sections when only part of it is staged.
In Komitly, hunk staging is one click in the diff viewer gutter. Line-level staging uses click and Shift+click to select individual lines — no manual patch editing required.
Use git diff --staged to verify the staged subset before committing.
Partial staging turns a messy coding session into a series of clean, focused commits that are easy to review, easy to revert, and easy to understand.
With line-level staging in your toolkit, you have full control over every commit. You now have all the fundamentals to use Git confidently — from git init to partial staging, from pull requests to conflict resolution.