Отменить изменения в git (не переписывать историю)

StackOverflow https://stackoverflow.com/questions/642264

  •  22-07-2019
  •  | 
  •  

Вопрос

Я внес изменения в сценарий и зафиксировал их.Затем я внес еще несколько изменений и перенес их в удаленный репозиторий и тому подобное.

Потом я понял, что первое изменение, о котором я упомянул, было глупым, и хочу отменить его..Могу ли я "отменить" этот коммит, не копируя / вставляя разницу вручную?

В качестве примера:У меня есть два файла, a.py и b.py:

Commit 1:
I delete a function in a.py

Commit 2:
I change a few lines in b.py

Commit 3:
I change the docstring in a.py

Могу ли я отменить удаление этой функции и сделать так, чтобы она отображалась как "фиксация 4" (вместо удаления фиксации 1)

Это было полезно?

Решение

Да, для этого вы можете использовать git revert . См. раздел руководства по git в этом для получения дополнительной информации.

Суть в том, что вы можете сказать:

git revert 4f4k2a

Где 4f4k2a - это идентификатор коммита, который вы хотите отменить, и он попытается отменить его.

Другие советы

Просто комментарий:

git revert aCommit

возвращает ли ВСЕ зафиксировать (как в "все файлы часть коммита" ):
он вычисляет обратный патч, применяет его к HEAD и фиксирует.

Итак, здесь две проблемы (первая легко решаема).:

  • он всегда фиксируется, поэтому вы можете захотеть добавить -no-commit вариант:"git revert --no-commit aCommit":это полезно при возврате эффекта нескольких коммитов к вашему индексу подряд.
  • это не относится к определенному файлу (что, если вы a.py участвовали в фиксации с 1000 другими изменениями, которые вы, возможно, не захотите отменять)?
    Для этого, если вы хотите извлечь определенные файлы в том виде, в каком они были в другом коммите, вы должны увидеть git-checkout, в частности , git checkout <commit> <filename> синтаксис (хотя это не совсем то, что вам нужно в данном случае)

Простой Мерзавец (Элайджа Ньюрен) попытался внести более "полный возврат" в Список рассылки Git;но без особого успеха:

Люди иногда хотят "отменить изменения".

Так вот, это может быть:

  • изменения, внесенные между 32 и 29 редакциями назад,
  • это могут быть все изменения, произошедшие с момента последней фиксации,
  • это могут быть изменения, произошедшие с момента 3 коммитов назад, или
  • это может быть всего лишь один конкретный коммит.
  • Тот Самый пользователь может захотеть преобразовать такие возвраты только в определенные файлы,

(eg revert является задокументировано здесь, но я не уверен, что это часть текущего дистрибутива eg , хотя)

но в конце концов все сводится к "отмене изменений".

eg revert --since HEAD~3  # Undo all changes since HEAD~3
eg revert --in HEAD~8     # much like git revert HEAD~8, but nocommit by default
eg revert --since HEAD foo.py  # Undo changes to foo.py since last commit
eg revert foo.py               # Same as above
eg revert --in trial~7 bar.c baz.  # Undo changes made in trial~7 to bar.[ch]

Действительно ли эти виды "возврата данных" настолько различны, что должны быть разные команды, или что некоторые из этих операций не должны поддерживаться простой командой возврата?
Конечно, большинство пользователей большую часть времени, вероятно, будут использовать "eg revert FILE1 FILE2..." форма, но я не видел вреда в поддержке дополнительных возможностей.

Also...is есть что-нибудь фундаментальное, что удержало бы core git от принятия такого поведения?

Илия

Примечание:коммиты по умолчанию не имеют смысла для обобщенного revert командовать, и "git revert REVISION" выдал бы ошибку с инструкциями (указывающими пользователю добавить флаг --in).


Допустим, у вас есть из 50 зафиксированных 20 файлов, и вы понимаете, что старая фиксация X внесла изменения, которые не должны были иметь места.
Немного сантехники приведено в порядок.
Что вам нужно, так это способ перечислить все конкретные файлы, которые вам нужны для вернуться
(как в "отменить изменения, внесенные в commit X, с сохранением всех последующих изменений"),
и затем, для каждого из них:

git-merge-file -p a.py X X^

Проблема здесь заключается в том, чтобы восстановить потерянную функцию без удаления всех последующих изменений в a.py, которые вы, возможно, захотите сохранить.
Эту технику иногда называют "негативным слиянием".

С тех пор как git merge-file <current-file> <base-file> <other-file> означает:
включает в себя все изменения, которые приводят к <base-file> Для <other-file> в <current-file>, вы можете восстановить удалите функцию, сказав, что вы хотите включить все изменения.)

  • От:X (где функция была удалена)
  • Для:X^ (предыдущая фиксация перед X, где функция все еще была там)

Примечание:тот самый '-p' аргумент, который позволяет вам сначала просмотреть изменения, ничего не делая с текущим файлом.Когда вы будете уверены, удалите этот параметр.

Примечание:тот самый git merge-file является не все так просто:вы не можете ссылаться на предыдущие версии файла просто так.
(вы бы снова и снова получали это разочаровывающее сообщение: error: Could not stat X)
Ты должен:

git cat-file blob a.py > tmp/ori # current file before any modification
git cat-file blob HEAD~2:a.py > tmp/X # file with the function deleted
git cat-file blob HEAD~3:a.py > tmp/F # file with the function which was still there

git merge-file a.py tmp/X tmp/F # basically a RCS-style merge
                                 # note the inversed commit order: X as based, then F
                                 # that is why is is a "negative merge"
diff -u a.py tmp/ori # eyeball the merge result
git add a.py 
git commit -m "function restored" # and any other changes made from X are preserved!

Если это должно быть сделано для большого количества файлов в рамках предыдущей фиксации...некоторые сценарии в порядке вещей ;)

Чтобы отменить изменения только в одном файле в коммите, как VonC указал, я бы checkout выбрал ветку (master или trunk или что-то еще), а затем diff версию файла, которую я хотел восстановить, и обработал его как новый коммит:

$ git checkout trunk
$ git checkout 4f4k2a^ a.py
$ git add a.py
$ git diff              #verify I'm only changing what I want; edit as needed
$ git commit -m 'recover function deleted from a.py in 4f4k2a'

Вероятно, есть сантехническая команда, которая сделает это напрямую, но я бы не стал ее использовать, если бы знал это. Дело не в том, что я не доверяю Git, но я не доверяю себе - я бы не стал доверять тому, что знал, не посмотрев, что изменилось в этом файле в этом коммите и с тех пор. И как только я посмотрю, проще будет создать новый коммит, отредактировав <=>. Возможно, это просто личный стиль работы.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top