Зафиксировать только часть файла в Git


2766

Когда я делаю изменения в файле в Git, как я могу зафиксировать только некоторые изменения?

Например, как я могу зафиксировать только 15 строк из 30 строк, которые были изменены в файле?


3
related stackoverflow.com/q/34609924/52074 : если вам нужно разбить кусок на более мелкие фрагменты.
Тревор Бойд Смит

Резюме: с точки зрения возможностей: git gui= git add -e> git add -i -p; с точки зрения удобства: git gui> git add -i -p> git add -e. Итак: выбирайте, git guiкогда у вас есть доступ к X. Выберите git add -i -pдля простых вещей, а когда у вас нет или вы не хотите использовать X. git add -eдля сложной постановки без X.
Пенге Ген

Ответы:


3689

Вы можете использовать git add --patch <filename>(или -pдля краткости), и git начнет разбивать ваш файл на то, что он считает разумными "кусочками" (частями файла). Затем он подскажет вам этот вопрос:

Stage this hunk [y,n,q,a,d,/,j,J,g,s,e,?]?

Вот описание каждой опции:

  • y поставить этот кусок для следующего коммита
  • n не ставьте этот кусок для следующего коммита
  • qуволиться; не ставьте этот кусок или любой другой оставшийся кусок
  • a поставить этот кусок и все последующие фрагменты в файле
  • d не ставьте этот кусок или любой из более поздних фрагментов в файле
  • g выберите кусок, чтобы перейти к
  • / искать кусок, соответствующий заданному регулярному выражению
  • j оставьте этот кусок нерешенным, смотрите следующий нерешенный кусок
  • J оставьте этот кусок нерешенным, смотрите следующий кусок
  • k оставить этот кусок нерешенным, см. предыдущий нерешенный кусок
  • K оставьте этот кусок нерешенным, см. предыдущий кусок
  • s разделить текущий кусок на более мелкие фрагменты
  • e вручную редактировать текущий блок
  • ? распечатать справку

Если файл еще не в хранилище, вы можете сначала сделать git add -N <filename>. После этого вы можете продолжить git add -p <filename>.

После этого вы можете использовать:

  • git diff --staged чтобы убедиться, что вы поставили правильные изменения
  • git reset -p расшатать ошибочно добавленные куски
  • git commit -v чтобы просмотреть ваш коммит во время редактирования сообщения о коммите.

Обратите внимание, что это сильно отличается от git format-patchкоманды, целью которой является анализ данных фиксации в .patchфайлы.

Ссылка на будущее: Git Tools - Интерактивная постановка


83
Может быть полезно отметить, что -p/--patchэто ярлык к действию исправления внутри -i/--interactiveкоманды, запускающий полезный интерактивный режим .
tutuDajuju

5
> Что произойдет, если этот файл уже поставлен? Это покажет только неустановленные изменения. Так же, как git diffи
Евгений Коньков

3
Как я могу редактировать текущий блок вручную? Я не знаю, что делать после ввода е.
Хунсу

23
После нажатия кнопки e, Вы можете редактировать ломоть вручную путем замены +или -по#
veksen

1
это здорово, но теперь, как мне на самом деле это подтолкнуть? если я делаю git pushэто говорит уже в курсе. и если я это сделаю, git diffя увижу куски, которые я сказал n. если я git diff --stagedвижу, я вижу коммит, который я хочу нажать. Если я могу нажать коммит, как я могу удалить фрагменты, которые я сказал no?
Чови

250

Вы можете использовать git add --interactiveили , а затем ( не ); см. Интерактивный режим на странице руководства git-add или просто следуйте инструкциям.git add -p <file>git commit git commit -a

Modern Git также имеет git commit --interactivegit commit --patch, который является ярлыком для опции исправления в интерактивном коммите).

Если вы предпочитаете делать это из GUI, вы можете использовать git-gui . Вы можете просто пометить чанки, которые хотите включить в коммит. Мне лично это проще, чем пользоваться git add -i. Другие графические интерфейсы git, такие как QGit или GitX, также могут иметь эту функцию.


1
Интересно, что на windows.github.com была поддержка частичной фиксации файлов, но, похоже, она недавно была удалена ..
Юри

1
@Juri Я думаю, что поддержка частичных коммитов файлов вернулась.
Ela782

@Juri Не за что. Я действительно никогда не замечал, что это было там раньше - я видел это на прошлой неделе и думал: «О, какая удивительная новая особенность»! :-)
Ela782

1
В настоящее время windows.github.com перенаправляет на переименованный GitHub Desktop, который лучше Git GUI и поддерживает частичные коммиты ... но не поддерживает подпись коммитов. Вздох.

147

Git GUI предоставляет эту функциональность в представлении diff. Просто щелкните правой кнопкой мыши на строке (строках), которая вас интересует, и вы должны увидеть пункт меню «подготовить эту строку для фиксации».


13
для сложных патчей это обычно самый быстрый подход для меня.
hochl

7
Это очень эффективный и интуитивно понятный способ добавления изменений в область подготовки с мелкой детализацией. Также можно выделить несколько строк и все изменения в этом выборе будут добавлены.
Jox

Обратите внимание, что это не так gitk, но он включен в Git Bash для Windows; Вы должны иметь пункт меню Пуск для него или можете запустить его с помощью команды git gui. Там также, stage this hunkчто, вероятно, более полезно, чем stage this line. Может быть новым, так как этот ответ был создан 10 лет назад.
Крис

82

Я считаю, что git add -e myfileэто самый простой способ (по крайней мере, мои предпочтения), поскольку он просто открывает текстовый редактор и позволяет вам выбрать, какую строку вы хотите поставить, а какую - нет. По поводу команд редактирования:

добавленный контент:

Добавленный контент представлен строками, начинающимися с «+». Вы можете предотвратить размещение любых добавочных строк, удалив их.

удаленный контент:

Удаленный контент представлен строками, начинающимися с «-». Вы можете предотвратить постановку их удаления, преобразовав "-" в "" (пробел).

измененный контент:

Модифицированный контент представлен линиями «-» (удаление старого контента), за которыми следуют строки «+» (добавление контента замены). Вы можете предотвратить внесение изменений, преобразовав строки "-" в "" и удалив строки "+". Помните, что изменение только половины пары может привести к непонятным изменениям в индексе.

Все детали о git addдоступны наgit --help add


7
Это было бы более полезно, если бы где-то было четкое объяснение того, как на самом деле выбрать эти строки (то есть фактические команды для ввода). Я не мог найти один в документации. Не могли бы вы добавить ссылку?
Алекс

4
Для тех, кто не любит сокращенные варианты, -eесть --edit.
Колюня

2
@Alex Ссылочные цитаты, добавленные TheFreedomBanana, взяты из раздела РЕДАКТИРОВАНИЕ ПАТЧЕЙ вgit --help add
Рэндалл

8
Это единственный ответ (требующий только git), который решает проблему добавления / удаления по линии, когда вы не можете уменьшить размеры sв интерактивном режиме патчей.
cdosborn

3
Может быть полезно понять, что эта команда ( git add -e) * не * изменяет содержимое файла на диске. Он просто перемещает часть изменений из неустановленных в поэтапные (индекс).
Penghe Geng

44

Если вы используете vim, вы можете попробовать отличный плагин под названием fugitive .

Вы можете увидеть различие файла между рабочей копией и индексом с помощью :Gdiff, а затем добавить строки или фрагменты в индекс, используя классические команды vim diff, например dp. Сохраните изменения в индексе и подтвердите их :Gcommit, и все готово.

Очень хорошие вводные скринкасты здесь (см. Часть 2 ).


Большое вам спасибо за эти ссылки. Точно так же, как мне нужно. Особенно :diffget/:diffputв визуальном режиме, где я могу выбрать определенные строки, которые я хочу сбросить / зафиксировать. Итак, убедитесь еще раз: vim потрясающий.
goodniceweb

30

Я настоятельно рекомендую использовать SourceTree от Atlassian. (Это бесплатно.) Это делает это тривиальным. Вы можете быстро и легко создавать отдельные фрагменты кода или отдельные строки кода.

введите описание изображения здесь


1
Я согласен, что SourceTree - хороший инструмент для этой цели, потому что он дает вам более детальный контроль, чем это возможно через командную строку.

19
@cupcake Я бы сказал, что наоборот, поскольку SourceTree, вероятно, использует эти исполняемые файлы git для командной строки, по своей сути всегда можно будет выполнять те же (или более) детальные действия через «командную строку».
tutuDajuju

2
Вне зависимости от тонкой аргументации, я очень рекомендую SourceTree, так как постановка фрагментов и отдельных строк очень проста: i.imgur.com/85bNu4C.png
Марс Робертсон,

1
@tutuDajuju В этом случае я не уверен, что это правда. SourceTree имеет возможность выбирать, какие части ставить построчно . Вам не нужно ставить целый кусок; Вы можете поставить 2 линии в середине ломоть. Я понятия не имею, как это достигает этого, все же. (В настоящее время я пытаюсь обойти невозможность SourceTree ставить отдельные строки для неотслеживаемого файла. Я попал сюда в поисках обходного пути, но обнаружил, что git, по-видимому, не предлагает возможность построчно Во всяком случае. По крайней мере, не в прямой форме.)
jpmc26

1
@ Солнце, вы можете нажать на строку 50 и Shift + клик на строке 100, а затем этап. Вы можете легко поставить строку 50-100 в Sourcetree :)
ryan123

26

Стоит отметить , что использование git add --patchдля нового файла необходимо сначала добавить файл индекса с git add --intent-to-add:

git add -N file
git add -p file

23

Когда у меня будет много изменений, и в итоге я создам несколько коммитов из этих изменений, я хочу временно сохранить свою начальную точку, прежде чем ставить вещи.

Нравится:

$ git stash -u
Saved working directory and index state WIP on master: 47a1413 ...
$ git checkout -p stash
... step through patch hunks
$ git commit -m "message for 1st commit"
$ git checkout -p stash
... step through patch hunks
$ git commit -m "message for 2nd commit"
$ git stash pop

Ответ Whymarrh - то, что я обычно делаю, за исключением того, что иногда происходит много изменений, и я могу сказать, что могу ошибиться при постановке вещей, и я хочу зафиксированное состояние, к которому я могу прибегнуть для второго прохода.


12

Если вы используете emacs, взгляните на Magit , который предоставляет интерфейс git для emacs. Он поддерживает постановку фрагментов (частей файлов) довольно хорошо.


Я часто путаюсь с командой git, желающей открыть редактор, когда запускаю его из окна оболочки Mx. Перехватывает ли magit это безумие и открывает для этого только новый буфер? (пожалуйста, никаких подсказок background-emacs-daemon; все равно спасибо, но жизнь слишком коротка).
user2066657

Нет, насколько я могу судить, это не перехватывает это. Но не просто поверьте мне на слово, потому что (1) я почти никогда не использую окно оболочки в Emacs и (2) я обычно использую emacsclient. Сказав это, если emacsclient является опцией для вас, это по крайней мере предотвратило открытие дополнительного окна с emacs и открытием буфера "COMMIT_EDITMSG" в моем существующем окне Emacs.
Марк ван Лент


9

Для тех, кто использует Git Extensions :

В окне «Фиксация» выберите файл, который вы хотите частично зафиксировать, затем выделите текст, который вы хотите зафиксировать, на правой панели, затем щелкните правой кнопкой мыши выделенную область и выберите «Поместить выделенные строки» в контекстном меню.


2
Сочетание клавиш в Git Extensions для 'Stage selected lines' s- очень полезно для быстрого размещения частей файлов для фиксации.
Alchemistmatt

8

Как и в ответе jdsumsion, вы также можете спрятать свою текущую работу, но затем использовать difftool, такой как meld, чтобы извлечь выбранные изменения из тайника. Таким образом, вы даже можете легко редактировать фрагменты вручную, что немного неприятно, когда git add -p:

$ git stash -u
$ git difftool -d -t meld stash
$ git commit -a -m "some message"
$ git stash pop

Использование метода stash дает вам возможность проверить, работает ли ваш код, до того, как вы его подтвердите.


это работает хорошо, но если вы используете git commit --amend, кажется, что вы не можете открыть тайник впоследствии, или есть способ сделать это?
Mark

7

Добавление предыдущего ответа, если вы предпочитаете использовать командную строку, ввод git add -e myfileдает вам возможность выбирать построчно то, что вы хотите зафиксировать, потому что эта команда откроет редактор с различиями, например так:

введите описание изображения здесь

Как вы, возможно, знаете, строки, начинающиеся с +добавления, строки, начинающиеся с -удаления. Так:

  • Чтобы не ставить дополнение, просто удалите эту строку.
  • Чтобы не удалять, просто замените -пробелом .

Вот что git add -hговорит о добавлении файлов таким образом (исправление файлов):

добавленный контент Добавленный контент представлен строками, начинающимися с "+". Вы можете предотвратить размещение любых добавочных строк, удалив их.

удаленный контент: удаленный контент представлен строками, начинающимися с «-». Вы можете предотвратить постановку их удаления, преобразовав "-" в "" (пробел).

Модифицированный контент: Модифицированный контент представлен линиями «-» (удаление старого контента), за которыми следуют строки «+» (добавление контента замены). Вы можете предотвратить внесение изменений, преобразовав строки "-" в "" и удалив строки "+". Помните, что изменение только половины пары может привести к непонятным изменениям в индексе.

Внимание: не изменяйте содержимое файла, это не очень хорошее место для этого. Просто поменяйте операторы удаленных или добавленных строк.


Какой предыдущий ответ? Ответы хранятся в зависимости от количества набранных ими баллов. Таким образом, ваш ответ сейчас находится в другом месте, чем когда вы его писали, по сравнению с другими ответами.
KulaGGin

Я полагаю, что указанный ответ получен от @theFreedomBanana
K. Symbol

6

Плагин vim-gitgutter может ставить фрагменты, не выходя из редактора vim с помощью

:GitGutterStageHunk

Помимо этого, он предоставляет другие интересные функции, такие как столбец различий, как в некоторых современных средах разработки.

Если только часть ломоть должна быть организована vim-беглец

:Gdiff

позволяет визуальный выбор диапазона затем :'<,'>diffputили :'<,'>diffgetдля постановки / возврата отдельных изменений линий.



4

С TortoiseGit:

щелкните правой кнопкой мыши на файле и используйте Context Menu → Restore after commit. Это создаст копию файла как есть. Затем вы можете отредактировать файл, например, в TortoiseGitMerge и отменить все изменения, которые вы не хотите фиксировать. После сохранения этих изменений вы можете зафиксировать файл.


4

Прошло 10 лет с тех пор, как этот вопрос был задан. И я надеюсь, что этот ответ будет кому-то полезен. Как уже упоминалось в ответе здесь , где GUI не вариант, расширение Crecord Эндрю Шадуры помогает окно ncurses, в котором мы можем выбрать строки для фиксации.

Настройте расширение следующим образом:

git clone https://github.com/andrewshadura/git-crecord
cd git-crecord
./setup.py install
ln -s $PWD/git-crecord ~/.local/bin/git-crecord

Перейдите к вашему git-репо и вызовите его следующим образом:

git crecord

Это вызовет интерфейс ncurses, который можно использовать, как показано ниже. Нажатие следующих клавиш в окне ncurses выполнит определенные действия:

f       hunk toggle fold (arrow keys can also be used)
space   toggle hunk selection
a       toggle commit or amend
c       confirm and open commit window

Скриншот, показывающий пример использованияпример




2

git-meld-index - цитирование с сайта:

git-meld-index запускает meld - или любой другой git difftool (kdiff3, diffuse и т. д.) - чтобы вы могли интерактивно вносить изменения в индекс git (также известный как область подготовки git).

Это похоже на функциональность git add -p и git add --interactive. В некоторых случаях meld легче / быстрее использовать, чем git add -p. Это потому, что соединение позволяет вам, например,:

  • увидеть больше контекста
  • см. внутристрочные различия
  • отредактируйте вручную и увидите «живые» обновления diff (обновляются после каждого нажатия клавиши)
  • перейти к изменению, не произнося 'n', к каждому изменению, которое вы хотите пропустить

Применение

В репозитории git запустите:

git meld-index

Вы увидите, что meld (или ваш сконфигурированный git difftool) всплывает с:

LEFT : временные файлы, содержащие каталоги, скопированные из вашего рабочего дерева

ВПРАВО : временный каталог с содержимым индекса. Сюда также входят файлы, которых еще нет в индексе, но которые изменены или не отслежены в рабочей копии - в этом случае вы увидите содержимое файла из HEAD.

Отредактируйте указатель (с правой стороны), пока не будете довольны. Не забудьте сохранить при необходимости.

Когда вы закончите, закройте meld, и git-meld-index обновит индекс, чтобы он соответствовал содержимому временного каталога с правой стороны от только что отредактированного meld.


2

Если это на Windowsплатформе, по моему мнению, git guiэто очень хороший инструмент для stage/ commitнесколько строк изunstaged файла

1. Гуд мудрый:

  • Выберите файл из unstagged Changesраздела
  • Правый клик по коду кода, который нужно поставить
  • Выбрать Stage Hunk for commit

2. Линия мудрая:

  • Выберите файл из unstagged Changesраздела
  • Выберите линию / линии для постановки
  • Щелкните правой кнопкой мыши и выберите Stage Lines for commit

3. Если вы хотите подготовить файл целиком, за исключением нескольких строк:

  • Выберите файл из unstagged Changesраздела
  • Нажмите Ctrl+T (Stage file to commit)
  • Выбранный файл теперь перемещается в Staged Changesраздел
  • Выберите линию / линии для постановки
  • Щелкните правой кнопкой мыши и выберите UnStage Lines for commit

1

Как показывает один ответ выше, вы можете использовать git add --patch filename.txt

или краткая форма git add -p filename.txt

... но для файлов, уже находящихся в вашем репозитории, в s гораздо лучше использовать флаг --patch для команды commit напрямую (если вы используете достаточно свежую версию git): git commit --patch filename.txt

... или, опять же, краткая форма git commit -p filename.txt

... а затем используя упомянутые ключи (y / n и т. д.), для выбора строк, которые будут включены в коммит.


Что это дает вам " git add -p filename.txt" помимо того, что меньше места для ошибок? Если вы испортили частичное изменение файла, отмена добавления лучше, чем отмена фиксации.
CTMacUser

Я не знаю почему, но когда я говорю «n», строка включается… и когда я говорю «y» на втором блоке, она также включается.
Чови

1

Git-Cola - это отличный графический интерфейс, который также имеет встроенную функцию. Просто выберите линии для сцены и нажмите S. Если выбор не сделан, весь блок ставится.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.