Отменить часть неустановленных изменений в git

158

Как мне отменить часть моих неустановленных изменений в git, но сохранить остальные как неизменные? Я понял это так:

git commit --interactive
# Choose the parts I want to delete
# Commit the changes
git stash
git rebase -i master # (I am an ancestor of master)
# Delete the line of the most recent commit
git stash apply

Это работает, но было бы хорошо, если бы было что-то вроде git commit --interactiveтолько для отмены изменений. Есть лучшие методы?

asmeurer
источник

Ответы:

265

Вы можете использовать git checkout -p, что позволяет вам выбирать отдельные фрагменты из разницы между вашей рабочей копией и индексом для возврата. Аналогично, git add -pпозволяет вам выбирать блоки для добавления в индекс и git reset -pпозволяет выбирать отдельные блоки из разницы между индексом и HEAD для возврата из индекса.

$ git checkout -p file/to/partially/revert
# or ...
$ git checkout -p .

Если вы хотите сделать снимок вашего репозитория git заранее, чтобы сохранить эти изменения перед их отменой, я хотел бы сделать:

$ git stash; git stash apply

Если вы используете это часто, вы можете использовать псевдоним:

[alias]
    checkpoint = !git stash; git stash apply

Отмена отдельных фрагментов или строк может быть еще проще, если вы используете хороший режим редактора или плагин, который может обеспечить поддержку выбора строк для прямого возврата, что -pиногда может быть немного неуклюжим для использования. Я использую Magit , режим Emacs, который очень полезен для работы с Git. В Magit вы можете запустить magit-status, найти различия для изменений, которые вы хотите отменить, выбрать строки, которые вы хотите отменить (или просто навести курсор на блоки, которые вы хотите отменить, если вы хотите отменить блок за раз вместо линия за раз), и нажмите, kчтобы отменить эти конкретные линии. Я настоятельно рекомендую Magit, если вы используете Emacs.

Брайан Кэмпбелл
источник
Я думаю, что это примерно так же сложно, как и решение, которое я изначально придумал, но я думаю, что мое оригинальное решение имеет преимущество, заключающееся в сохранении удаленных строк в течение 30 дней, потому что они зафиксированы. Я думаю, может быть, было бы неплохо написать сценарий оболочки вокруг него.
asmeurer
1
Извините, я только что понял, что git checkoutтакже имеет -pфлаг, который делает именно то, что вы просили в одной команде. Извинения за предыдущий сложный набор шагов; Вы можете просто использовать git checkout -p. Что касается сохранения, перед тем как сделать что-то потенциально разрушительное, я часто делаю git stash; git stash apply(или создаю псевдоним, который делает это как git checkpointили что-то), чтобы записать текущее дерево в тайник, чтобы я мог вернуться к нему, если что-то пойдет не так.
Брайан Кэмпбелл
Вот и все, вот решение! Что касается псевдонима, я думаю, что что-то вроде этого git commit -a -m "Backup Commit" --edit; git reset HEAD^ было бы лучше, потому что тогда это не испортило бы мое состояние тайника, которое я могу использовать для чего-то другого. Затем, если у вас есть SHA1, вы можете выбрать его в течение следующих 30 дней. --Edit позволяет вам добавить информацию к сообщению фиксации, чтобы помочь вам найти SHA1 позже, если вы этого хотите. С другой стороны, это испортило бы git reflog, поэтому я думаю, что это компромисс, основанный на том, что вы делаете.
asmeurer
Псевдоним контрольной точки у меня не работает: выполняется только первая команда, а не вторая. Это печально, потому что мне бы это понравилось. Я использую GIT версии 1.7.10.4.
Фабьен,
Есть ли способ заставить git checkout -pне применять патчи к индексу, а только ставить их?
Геремия
28
git diff > patchfile

Затем отредактируйте файл заплатки и удалите части, которые вы не хотите отменять, затем:

patch -R < patchfile
octoberblu3
источник
6
Тем не менее, этот ответ особенно примечателен своей простотой и простотой использования. +1
tholy
Сгенерированный patchfileвыглядит отлично в Vim, и это действительно помогает!
Били
Отлично. Можно подтвердить, что он также работает под Windows с Cygwin и Ubuntu Bash для Windows.
Checo R
1
Заметьте, что вы также можете использовать git apply -Rвместо patch(просто чтобы остаться в рамках git или в отличие от patchнедоступного события )
user1556435
patch: **** malformed patch at line 41: @@ -428,9 +443,9 @@ you should place your code here."
HappyFace
5

Вы могли бы сделать

git checkout master -- path/to/file

Для каждого файла вы хотите сбросить.

Дрю Хоскинс
источник
Или используйте HEAD вместо мастера, если работаете над веткой. Как говорится в отчете «git status» (по крайней мере, в последних версиях).
Джонатан Леффлер
1

Как насчет

  1. Возврат затронутых файлов с изменениями из индекса
  2. используйте git add -pдля добавления только тех изменений, которые вы хотите внести в индекс.
Abizern
источник
1

Когда я запускаю «git status», он говорит:

$ git status
# On branch fr/fr.002
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   makefile
#
no changes added to commit (use "git add" and/or "git commit -a")
$

Итак, чтобы отменить неустановленные правки, он говорит мне:

git checkout -- makefile
Джонатан Леффлер
источник
3
Я думаю, что он задавался вопросом о том, как вернуть отдельные фрагменты, а не целый файл за один раз. Это, конечно, решение, если вам просто нужно отменить все изменения в файле.
Брайан Кэмпбелл
Да, я подозреваю, что ты прав. Как вы сказали, параметры 'git checkout -p' и 'git add -p', скорее всего, будут именно тем, что вам нужно.
Джонатан Леффлер
1

Ответ Брайан Кэмпбелл выходит из строя мой мерзавца, версия 1.9.2.msysgit.0, по неизвестным причинам, так что мой подход к стадии Hunks я хочу сохранить, Сбросьте изменения в рабочей копии, а затем убрать из буфера.

$ git add -p
   ... select the hunks to keep
$ git checkout -- .
$ git reset HEAD .
G-Wiz
источник
1
Есть также git stash -p. Вы могли бы сделать git stash -p; git reset --hard; git stash pop. Это практически то же самое, что вы делаете, за исключением того, что вам не нужно писать сообщение коммита.
asmeurer
@asmeurer ура. Моему не требуется сообщение коммита, но, скорее всего, имеет смысл использовать тайник, а не индекс для этого.
G-Wiz
0

Вы можете сделать git checkoutи дать ему названия частей, которые вы хотите отменить.

Андрей
источник