Олег Марков
Интерактивное добавление в Git - git add -p
Введение
Интерактивное добавление через git add -p помогает собирать осмысленные коммиты из «разбитых» изменений. Часто во время работы вы правите сразу несколько задач в одном файле – фиксируете баг, немного рефакторите код, правите комментарии. Если все это закоммитить одним набором, история становится нечитаемой и сложнее откатывать изменения.
С помощью git add -p вы можете выбрать, какие конкретно части диффа попадут в следующий коммит. Смотрите, я покажу вам, как по шагам разбивать изменения на логические куски и добавлять в индекс только то, что действительно относится к определенной задаче.
В статье вы увидите:
- что такое интерактивное добавление и когда оно полезно;
- как читать интерфейс git add -p;
- как управлять hunks (кусочками диффа) – разбивать, объединять, частично добавлять;
- как работать с выборочными строками внутри одного куска;
- типичные сценарии – разделение фичи и рефакторинга, частичное исправление файла, откат части правок;
- распространенные ошибки и как их избежать.
Теперь давайте шаг за шагом разберем, как именно работает git add -p и как вы можете встроить его в свой ежедневный рабочий процесс.
Что такое интерактивное добавление в Git
Индекс Git и его роль
Чтобы понять, что делает git add -p, полезно освежить в памяти три состояния файла в Git:
- рабочая директория – ваши текущие файлы на диске;
- индекс (staging area) – набор изменений, подготовленных к коммиту;
- последний коммит – зафиксированная версия проекта.
Обычный git add file добавляет в индекс все изменения файла целиком. Если вы меняли разные части файла для разных задач, то при следующем коммите они все попадут в историю одновременно.
Интерактивное добавление позволяет гораздо тоньше управлять индексом: вы можете положить в индекс только выбранные фрагменты диффа, а остальные оставить в рабочей директории.
Что делает git add -p в двух словах
Команда:
git add -p
запускает диалоговый режим. Git показывает вам изменения по одному «хунку» (hunk) – это небольшой непрерывный блок строк, в котором есть отличия от последнего коммита. Для каждого блока вы решаете, добавить его в индекс или пропустить.
Вы видите дифф и строку с подсказкой, где предлагаются варианты действий: добавить целиком, разбить на меньшие части, показать помощь, выйти и т.д. Давайте посмотрим, как это выглядит на практике.
Базовый сценарий работы с git add -p
Пример простого диффа
Представьте, что вы изменили файл main.py:
# main.py
def add(a, b):
# Старый комментарий
return a + b
def multiply(a, b):
return a * b
Вы решили:
- переписать комментарий к функции add;
- добавить логирование в multiply.
После правок файл выглядит так:
# main.py
def add(a, b):
# Складываем два числа и возвращаем результат
return a + b
def multiply(a, b):
print("Multiplying", a, b) # Добавляем простое логирование
return a * b
Теперь вы вызываете:
git add -p main.py
И видите примерно такой хунк:
diff --git a/main.py b/main.py
index 1234567..89abcde 100644
--- a/main.py
+++ b/main.py
@@ -1,7 +1,9 @@
def add(a, b):
- # Старый комментарий
+ # Складываем два числа и возвращаем результат
return a + b
def multiply(a, b):
- return a * b
+ print("Multiplying", a, b) # Добавляем простое логирование
+ return a * b
Stage this hunk [y,n,q,a,d,s,e,?]?
Здесь я размещаю пример, чтобы вам было проще понять структуру:
- строки, которые были, но удалены, помечены минусом;
- строки, которые добавились, помечены плюсом;
- контекст вокруг изменений без знаков – это просто для понимания места в файле.
Пока что это один общий хунк, но вы, возможно, хотите сделать два разных коммита:
- один – только с исправленным комментарием;
- второй – с логированием в multiply.
Сейчас этот пример нам понадобится, когда мы дойдем до разбиения hunks.
Первые действия – y, n, q, a, d
Под диффом Git пишет:
Stage this hunk [y,n,q,a,d,s,e,?]?
Расшифруем базовые варианты:
- y – добавить этот хунк в индекс;
- n – пропустить этот хунк, не добавлять;
- q – выйти, не показывая остальные hunks;
- a – добавить этот и все оставшиеся hunks этого файла;
- d – пропустить этот и все оставшиеся hunks этого файла.
Смотрите, я покажу вам, как это работает на простом случае.
Если вы нажмете y, весь хунк будет помещен в индекс. Затем Git покажет следующий хунк (если он есть). Если больше изменений нет, интерактивный режим завершится.
Если вы нажмете n, этот хунк останется только в рабочей директории (не будет в индексе), и вы перейдете к следующему.
В реальной работе вы чаще всего будете использовать связку:
- s – split (разбить хунк на более мелкие);
- e – edit (ручное редактирование хунка).
Теперь давайте разберемся с ними подробнее.
Управление hunks – разбиение, редактирование, повторный просмотр
Разбиение хунка – команда s
Вернемся к нашему примеру с main.py. Вы хотите разделить изменения в add и multiply на два разных коммита. Видите один большой хунк и приглашение:
Stage this hunk [y,n,q,a,d,s,e,?]?
Нажимаете:
s
Git попытается автоматически разбить хунк на более мелкие, логически независимые части. Продолжение вывода может выглядеть так (упрощенно):
@@ -1,4 +1,4 @@
def add(a, b):
- # Старый комментарий
+ # Складываем два числа и возвращаем результат
return a + b
Stage this hunk [y,n,q,a,d,s,e,?]?
Сначала он показывает фрагмент с функцией add. Если вы нажмете y:
- комментарий к add попадет в индекс;
- изменения в multiply пока останутся нетронутыми.
После этого Git покажет следующий хунк:
@@ -5,4 +6,6 @@
def multiply(a, b):
- return a * b
+ print("Multiplying", a, b) # Добавляем простое логирование
+ return a * b
Stage this hunk [y,n,q,a,d,s,e,?]?
Теперь вы можете, например, нажать n, чтобы не добавлять логирование в этот коммит.
В результате:
- индекс содержит только изменение комментария в add;
- рабочая директория содержит и комментарий, и логирование;
- после коммита можно снова выполнить git add -p и добавить оставшийся хунк.
Это базовый прием разбиения «случайно смешанных» изменений.
Что делать, если s не помогает
Бывает, что Git не может дальше разбить хунк. Тогда после нажатия s вы увидите сообщение вроде:
Sorry, cannot split this hunk
Обычно это значит, что изменения слишком тесно связаны и Git не может гарантировать корректность кода после разбиения. В таких случаях у вас есть два варианта:
- Использовать e и вручную отредактировать хунк.
- Временно изменить файл так, чтобы Git смог разделить изменения (например, разбить одну большую правку на две правки в разных участках кода).
Сейчас давайте сконцентрируемся на первом варианте – ручном редактировании.
Ручное редактирование хунка – команда e
Когда вы нажимаете:
e
Git открывает текущий хунк в вашем редакторе (тем, который указан в переменной окружения GIT_EDITOR или core.editor в конфиге). Там вы увидите тот же дифф, но с дополнительными подсказками в комментариях.
Например:
@@ -1,7 +1,9 @@
def add(a, b):
- # Старый комментарий
+ # Складываем два числа и возвращаем результат
return a + b
def multiply(a, b):
- return a * b
+ print("Multiplying", a, b) # Добавляем простое логирование
+ return a * b
# Manual hunk edit mode
# To remove lines from the hunk, delete them
# To add lines, do not touch lines starting with @@ or index
Теперь вы увидите, как это выглядит в редакторе. Важно правило: вы можете удалять строки из этого временного диффа, но не должны менять структуру служебных строк (те, что начинаются с @@ или #, и заголовки diff).
Если вы хотите закоммитить только изменение комментария, вы можете удалить строки, относящиеся к multiply:
@@ -1,7 +1,9 @@
def add(a, b):
- # Старый комментарий
+ # Складываем два числа и возвращаем результат
return a + b
def multiply(a, b):
- return a * b
+# (эти строки мы удалили из хунка, чтобы они не попали в индекс)
Обратите внимание, как этот фрагмент кода решает задачу: вы фактически говорите Git «сделай вид, что изменений в multiply не было» для текущего добавления. Когда вы сохраните файл и закроете редактор, Git применит только тот кусок, который остался в диффе.
Если вы случайно отредактируете служебные строки или сделаете дифф некорректным, Git откажется от ручного редактирования и вернет вас к выбору hunks, не меняя ничего в индексе.
Повторный просмотр – команда g и навигация по hunks
Если в файле много hunks, возможно, вам захочется перескочить к определенному или вернуться к уже увиденному. Для этого есть опция:
- g – выбрать hunk по номеру (goto hunk).
Когда вы нажмете g, Git запросит номер:
Go to which hunk [1-5]?
Вы вводите номер нужного хунка, и Git сразу покажет его. Это удобно, если вы сначала быстро просмотрели все изменения, а потом решили более аккуратно обработать конкретный блок.
Также можно двигаться:
- через клавишу Enter – иногда она повторяет предыдущий ответ или подтверждает действие (в разных версиях поведение немного отличается, лучше ориентироваться на подсказки на экране);
- через q – выйти из режима в любой момент.
Расширенный набор команд в git add -p
Полный список команд в приглашении
Когда вы не уверены, что значит та или иная буква, нажмите:
?
Git напечатает пояснение ко всем опциям. Для классического git add -p (интерактивного режима) список обычно примерно такой:
- y – добавить этот хунк;
- n – пропустить этот хунк;
- q – выйти, не обрабатывая остальные hunks;
- a – добавить этот и все оставшиеся hunks в текущем файле;
- d – пропустить этот и все оставшиеся hunks в текущем файле;
- s – разбить хунк на меньшие части (если возможно);
- e – вручную отредактировать текущий хунк;
- g – выбрать хунк по номеру;
- / – поиск по тексту в hunks;
- j – перейти к следующему хунку, оставив этот не решенным;
- J – пометить текущий хунк как добавленный и перейти дальше (поведение может отличаться в зависимости от версии Git);
- k – перейти к предыдущему хунку;
- K – аналогично J, но в обратном порядке (встречается не во всех версиях).
В повседневной практике чаще всего достаточно y, n, s, e, q, но хорошо знать, что у вас есть расширенные возможности навигации и поиска.
Поиск по hunks – команда /
Если у вас большие изменения и множество hunks, бывает удобно найти хунк по фрагменту текста. Например, вам нужен хунк, где встречается имя функции handle_request. Вы нажимаете:
/
Затем вводите строку для поиска:
handle_request
Git будет прокручивать hunks, пока не найдет тот, где есть это слово. Это ускоряет работу в больших коммитах, где вручную искать нужный фрагмент долго.
Пропуск, но с намерением вернуться – j и k
Опции j и k позволяют просто перемещаться по hunks, пока вы не приняли решение по текущему. Это полезно, если вы хотите сначала оценить картину целиком.
Например:
- вы видите первый хунк, не уверены, стоит ли его включать;
- нажимаете j и смотрите второй, третий и так далее;
- потом с помощью k можете вернуться назад, к тому, который вас интересовал.
Пока вы не нажмете y, n, a, d или другую «решающую» команду, состояние хунка не меняется.
Практические сценарии использования git add -p
Разделение фичи и рефакторинга
Один из самых частых сценариев – вы в одном файле:
- добавили новую функциональность;
- параллельно почистили стиль кода, переименовали пару переменных, поправили форматирование.
Коммит «Фича + рефакторинг вперемешку» потом сложно ревьюить и откатывать. Давайте разберемся на примере.
Предположим, файл handler.go (язык не принципиален) до изменений:
// handler.go
func Handle(req Request) Response {
// TODO: добавить логирование
result := process(req) // обработка запроса
return result
}
После работы вы получили:
// handler.go
func Handle(req Request) Response {
logRequest(req) // Добавили логирование
res := process(req) // Переименовали переменную result -> res
return res // Обновили возвращаемое значение
}
Теперь запускаете:
git add -p handler.go
Пусть Git показывает один общий хунк. Ваш план:
- В одном коммите добавить только логирование.
- В следующем – только рефакторинг имен переменных.
Действия:
- Нажать s, чтобы разбить хунк.
- Если Git не может автоматически, нажать e и вручную отредактировать хунк так, чтобы оставить только строки с logRequest.
- Сохранить и выйти из редактора – в индекс уйдут только изменения с логированием.
- Закоммитить: git commit -m "Add request logging".
- Заново вызвать git add -p и теперь добавить рефакторинг.
Так вы получаете два логичных, атомарных коммита вместо одного «сваленного».
Частичное исправление багов
Другой частый сценарий – вы чините баг и по пути добавляете отладочный вывод, временные проверки, комментарии. Не всё из этого должно попасть в итоговый коммит.
Например:
def process_order(order):
# TODO: удалить отладку после фикса бага
print("DEBUG", order) # Временный вывод
if not order.items:
raise ValueError("Empty order")
# Исправление бага - раньше мы не проверяли скидку на None
if order.discount is not None:
apply_discount(order)
return order
Смотрите, я покажу вам, как можно добавить только фикс бага, не трогая временный вывод:
- Вызываете git add -p.
- На хунке, где вместе и print, и проверка скидки, нажимаете s или e.
- Оставляете только строки, которые связаны с проверкой скидки.
- Добавляете их в индекс.
- Делаете коммит с текстом вида Fix discount handling for orders without discount.
После этого:
- временный print останется только в рабочей директории;
- его можно позже убрать и закоммитить отдельно или не коммитить вовсе.
Частичный откат изменений через git restore -p или git checkout -p
Интерактивная работа с hunks не ограничивается git add -p. Есть похожие режимы для отката изменений:
- git restore -p file (современный вариант);
- git checkout -p file (старый, но до сих пор используемый).
Идея такая же: вы видите дифф и по hunks выбираете, какие изменения отменить, а какие оставить.
Например, вы случайно изменили слишком много в файле, но хотите отменить только часть:
git restore -p main.py
Дальше команды и поведение очень похожи на git add -p. Выбирая y, вы разрешаете Git откатить этот хунк к состоянию последнего коммита. Это отличный способ точечно отменять только неудачные фрагменты правок.
Особенности работы с большими файлами и сложными диффами
Когда Git не может разумно разбить hunk
Иногда вы видите очень большой хунк, и команда s не дает нужного результата. Причины:
- изменения связаны по логике – например, вы переносили блок кода, меняли отступы и добавляли новые строки;
- изменения затрагивают почти каждую строку в большом участке.
В такой ситуации возможны варианты:
Временно упростить изменения.
- Вернуть часть кода к прежнему виду.
- Сделать промежуточный коммит.
- Снова внести оставшиеся правки.
Использовать ручное редактирование (e).
- Но внимательно следить, чтобы после частичного добавления код оставался работоспособным.
Помните, что git add -p не анализирует смысл кода, он оперирует только строками. Он не знает, что после вашего «разрезания» хунка файл может перестать компилироваться или запускаться.
Риски при ручном редактировании хунков
Когда вы редактируете хунк вручную, есть два типа ошибок:
Некорректный дифф.
- Git это заметит и не применит изменения.
- Ничего страшного – просто хунк не будет добавлен.
Корректный дифф, но логически неверный код.
- Например, вы добавили вызов функции, но не добавили ее определение.
- Для Git это нормальный дифф, он его применит.
- Но ваш код может не работать.
Поэтому при сложном «распиливании» больших изменений всегда полезно:
- после коммита запускать тесты;
- собирать проект (если это компилируемый язык);
- хотя бы вручную запускать ключевые сценарии.
Ограничения при работе с бинарными файлами
git add -p рассчитан на текстовые файлы. Для бинарных файлов (изображения, PDF, архивы) Git не может показать осмысленный дифф, поэтому:
- либо вы не увидите их в интерактивном режиме вообще;
- либо увидите сообщение, что дифф недоступен.
Если вы часто работаете с форматами, которые по сути текстовые, но Git их считает бинарными, можно настроить .gitattributes, чтобы Git понимал их как текст. Но это уже отдельная, более широкая тема.
Интерактивный режим git add -i и связь с git add -p
Кратко про git add -i
Кроме git add -p в Git есть еще одна интерактивная команда:
git add -i
Она открывает меню с пунктами:
- status – показать статус;
- update – добавить изменения в уже отслеживаемых файлах;
- revert – откатить изменения;
- patch – режим патчей, по сути то же, что git add -p;
- и другие.
Если вы выберете пункт patch, вы попадете в тот же режим выбора hunks, что и при git add -p. Разница только в том, что -i дает вам меню повыше уровнем, где можно, например, сразу увидеть список файлов и выбирать, с какими работать.
Когда удобнее -i, а когда -p
- git add -p – быстрее, если вы сразу знаете, над каким файлом или файлам хотите работать.
- git add -i – полезен, когда изменений много, в разных файлах, и вы хотите сначала увидеть общее меню и выбирать дальше.
Для целей именно «частичного добавления» хватает и git add -p, но хорошо знать, что интерактивный режим можно запустить и через -i.
Настройка редактора и удобства работы
Как выбрать редактор для e
Когда вы используете e для ручного редактирования хунка, Git открывает файл в редакторе, который определяется в таком порядке:
- Переменная окружения GIT_EDITOR.
- Настройка core.editor в конфиге Git.
- Переменные окружения VISUAL и EDITOR.
Если вы хотите всегда использовать, например, Vim:
git config --global core.editor "vim"
Если предпочитаете VS Code:
git config --global core.editor "code --wait"
Комментарий к последней команде:
- флаг --wait говорит VS Code дождаться закрытия файла, прежде чем возвращать управление Git.
Таким образом, вы точно контролируете, где будете редактировать хунк.
Цвета и удобство чтения диффов
Чтобы взаимодействие с git add -p было комфортным, убедитесь, что у вас включена подсветка цветов для диффов. Обычно достаточно настроек по умолчанию, но можно явно указать:
git config --global color.ui auto
Это делает:
- добавленные строки – зелеными;
- удаленные – красными;
- заголовки – с другим цветом.
Читаемость диффов заметно улучшается, особенно в больших правках.
Часто используемые алиасы
Чтобы не набирать каждый раз длинные команды, разработчики часто добавляют алиасы. Например:
git config --global alias.ap "add -p"
git config --global alias.cp "checkout -p"
git config --global alias.rp "restore -p"
Теперь вы можете использовать:
git ap
git rp file.py
Это ускоряет повседневную работу, особенно если вы активно пользуетесь интерактивными режимами.
Типичные ошибки и как их избежать
Ошибка 1 – «Добавил не тот хунк»
Иногда вы по привычке нажимаете y, а потом понимаете, что хотели n. В этом случае вы можете:
Отменить последнее добавление с помощью git restore --staged:
git restore --staged путь/к/файлу// Сбрасываем файл из индекса, изменения остаются в рабочей директории
И снова запустить git add -p для этого файла и аккуратно выбрать нужные hunks.
Если вы уже сделали коммит, но еще не пушили его, можно использовать:
git reset --soft HEAD~1
// Откатываем последний коммит, но сохраняем изменения в индексе и рабочей директории
После этого вы можете пере-собрать коммит с нужными hunks.
Ошибка 2 – «Код после разрезания перестал работать»
Это не ошибка Git, а естественный риск при частичном добавлении. Чтобы снизить риски:
- старайтесь разбивать изменения на логические фрагменты уже во время разработки;
- после каждого коммита, собранного через git add -p, прогоняйте тесты или хотя бы ключевые проверки;
- если сомневаетесь, лучше сделать немного более крупный, но цельный коммит, чем слишком агрессивно «резать» код.
Ошибка 3 – «Путаюсь в hunks, не понимаю, что уже добавил»
Полезные команды:
- git status – покажет, какие файлы в индексе, какие только в рабочей директории;
- git diff – покажет изменения, которые еще не в индексе;
- git diff --cached – покажет то, что уже находится в индексе и попадет в следующий коммит.
Например:
git diff # Что еще НЕ добавлено
git diff --cached # Что уже добавлено в индекс
// Вместе они дают полную картину, что именно будет закоммичено, а что нет
Используйте их после серии интерактивных добавлений, чтобы убедиться, что индекс содержит только ожидаемые изменения.
Заключение
Интерактивное добавление через git add -p – это инструмент для более аккуратной работы с историей проекта. Вместо того чтобы коммитить все изменения файла целиком, вы выбираете конкретные hunks и даже отдельные строки, которые действительно относятся к текущей задаче.
Вы посмотрели:
- как git add -p показывает изменения по hunks и какие есть базовые команды;
- как разбивать hunks командой s и вручную редактировать их через e;
- как использовать интерактивное добавление, чтобы разделять фичи, рефакторинг и временную отладку;
- чем дополняет git add -p интерактивный режим git add -i;
- какие типичные ошибки возникают и как их минимизировать.
Если встроить git add -p в свой ежедневный процесс, коммиты становятся более атомарными и понятными, ревью упрощается, а откат отдельных изменений перестает быть проблемой. Важно лишь помнить о балансе: тонкое управление hunks не должно заменять осмысленное планирование и структурирование работы, но отлично помогает исправить ситуацию, когда изменения уже «смешались» в одном файле.
Частозадаваемые технические вопросы по теме
Как сделать выбор строк внутри одного хунка без ручного редактирования e
В классическом git add -p выбор отдельных строк возможен только через e и ручное редактирование. Но в некоторых оболочках (например, в TortoiseGit или IDE) есть визуальные интерфейсы, позволяющие кликать по строкам. В чистом Git в терминале вы редактируете хунк вручную – удаляете строки с плюсом, которые не хотите добавлять, и сохраняете файл.
Как частично добавить только отдельные файлы, а потом уже hunks
Сначала ограничьте интерактивный режим нужными файлами:
git add -p file1.py file2.py
Git будет показывать hunks только из этих файлов. Это удобно, если у вас много измененных файлов, но интерактивно вы хотите обработать только несколько.
Можно ли использовать git add -p вместе с git commit -p
Команда git commit -p по сути объединяет git add -p и git commit. Она сразу запускает выбор hunks, а затем открывает редактор сообщения коммита. Это удобно, если вы уверены, что будете коммитить сразу после интерактивного добавления. Внутри commit -p интерфейс работы с hunks такой же.
Как откатить только часть уже добавленных в индекс изменений
Используйте git restore -p с флагом --staged:
git restore -p --staged file.py
В интерактивном режиме вы увидите hunks, которые находятся в индексе, и сможете выбрать, какие из них «вытащить» обратно в рабочую директорию. Это зеркальное отражение git add -p, только в обратную сторону.
Почему git add -p не показывает некоторые файлы с изменениями
Проверьте несколько моментов:
- Тип файла – бинарные файлы не показываются как обычный дифф.
- Игнорирование – если файл совпадает с правилами .gitignore и не был добавлен ранее, он может не участвовать в интерактивном добавлении.
- Фильтры – если вы запускаете git add -p с указанием файлов или путей, Git обработает только их. Убедитесь, что вы не сузили список слишком сильно.
Постройте личный план изучения Git до уровня Middle — бесплатно!
Git — часть карты развития Frontend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Бесплатные лекции
Все гайды по Git
Лучшие курсы по теме

Основы Git
Антон Ларичев
TypeScript с нуля
Антон Ларичев