Отменить диапазон коммитов в git


128

Как я могу отменить ряд коммитов в git? Глядя на документацию gitrevisions , я не вижу, как указать нужный мне диапазон. Например:

A -> B -> C -> D -> E -> HEAD

Я хочу сделать эквивалент:

git revert B-D

где результат будет:

A -> B -> C -> D -> E -> F -> HEAD

где F содержит знак, обратный BD включительно.


Ближе к концу страницы gitrevisions (7) есть раздел «УКАЗАНИЕ ДИАПАЗОНОВ». Чем то, что вы хотите, отличается от того, что там описано?
Гарет МакКоган,

2
Страница gitrevisions предполагает, что git revert A..D будет делать то, что я хочу. Однако, когда я пытаюсь это сделать, я получаю сообщение об ошибке «fatal: Cannot find 'A..D'»
Alex Spurling

Ответы:


173

Какую версию Git вы используете?

Отмена нескольких коммитов поддерживается только в Git1.7.2 +: см. « Откат к старой фиксации с использованием многократного отката » для более подробной информации.
Текущая git revertстраница руководства предназначена только для текущей версии Git (1.7.4+).


Как сообщает в комментариях ОП Алекс Сперлинг :

Обновление до 1.7.4 работает нормально.
Чтобы ответить на мой собственный вопрос, это синтаксис, который я искал:

git revert B^..D 

B^означает «первый родительский коммит B»: что позволяет включить Bв откат.
См. Раздел « git rev-parseУКАЗАНИЕ ИЗМЕНЕНИЙ », который включает <rev>^, например,HEAD^ синтаксис: подробнее см. « Что означает ^символ каретки ( )? »)

Обратите внимание, что каждая отмененная фиксация совершается отдельно.

Хенрик Н поясняет в комментариях :

git revert OLDER_COMMIT^..NEWER_COMMIT

Как показано ниже, вы можете вернуться, не выполняя сразу:

git revert -n OLDER_COMMIT^..NEWER_COMMIT
git commit -m "revert OLDER_COMMIT to NEWER_COMMIT"

1
Спасибо, это был ответ. Обновление до 1.7.4 работает нормально. Чтобы ответить на мой собственный вопрос, это синтаксис, который я искал: git revert B ^ .. D
Alex Spurling

гений. Спасибо. Мне не приходило в голову, что мне нужно отменить коммиты в обратном порядке, чтобы патчи применились, да. Эта команда указывает путь.
Тим Абелл

5
Я часто возвращаюсь к этому ответу, и мне всегда требуется время, чтобы выяснить порядок. Чтобы помочь себе в будущем:git revert OLDER_COMMIT^..NEWER_COMMIT
Henrik N

2
что означает ^?
Дастин Гетц

1
Первый родитель @DustinGetz: см. Git-scm.com/docs/gitrevisions : «Суффикс ^параметра ревизии означает первого родителя этого объекта фиксации».
VonC

15

Если вы хотите вернуть диапазон фиксации B в D (по крайней мере, в git версии 2) за одну фиксацию, вы можете сделать

 git revert -n B^..D

Это отменяет изменения, сделанные коммитами из родительского коммита B (исключено), в коммит D (включено), но не создает никаких коммитов с отмененными изменениями. Откат изменяет только рабочее дерево и индекс.

Не забудьте зафиксировать изменения после

 git commit -m "revert commit range B to D"

Вы также можете отменить несколько несвязанных коммитов за один коммит, используя тот же метод. например, чтобы вернуть B и D, но не C

 git revert -n B D
 git commit -m "Revert commits B and D"

Ссылка: https://www.kernel.org/pub/software/scm/git/docs/git-revert.html

Спасибо Хонзе Херинг за исправление


3
git revert -n B..Dне отменяет фиксацию B, только C и D. также git revert -n B^..Dвозвращают B.
Хонза Херинг

согласно документации git. ссылка в посте
Ramast 03

1
Если вы ссылаетесь на этот пример (который, я думаю, немного сбивает с толку) в ссылке:, git revert -n master~5..master~2он говорит, что включен пятый последний коммит. Но master~5на самом деле это 6-й последний коммит. См. Выбор ревизии в документации git для получения подробной информации об ..обозначениях :-)
Хонза Херинг,

6

Это git revert OLDER_COMMIT^..NEWER_COMMITне помогло мне.

Я привык git revert -n OLDER_COMMIT^..NEWER_COMMITи все хорошо. Я использую версию git 1.7.9.6.


У меня была такая же проблема, и я исправил ее с помощью -n, но вы должны оставить ^ с OLDER_COMMIT (git revert -n OLDER_COMMIT ^ .. NEWER_COMMIT).
FeelGood

@FeelGood, почему ты должен оставить ^?
Орландо,

У меня была история A -> B -> C, и цель состояла в том, чтобы вернуть B и C. Когда я запускаю 'git revert -n B..C', только C. Когда я использовал «git revert -n B ^ .. C», git вернул обе фиксации. Может я что то не так сделал.
FeelGood

круто, что ж, нужно проверить это, но я думаю, что в моем случае все сработало хорошо (если я не возвращал 1 диапазон фиксации lol), я изменю ответ, включив ^. спасибо
Орландо

2
Параметр -nили --no-commitотменит все изменения в диапазоне за одну фиксацию, вместо того, чтобы создавать откатную фиксацию для каждой фиксации в диапазоне. Конечный результат такой же, как и в, те же изменения будут отменены. Просто зависит от того, как вы хотите, чтобы ваша история git выглядела.
Деннис

0

Используйте, git rebase -iчтобы объединить соответствующие коммиты в один. Тогда вам нужно будет отменить только одну фиксацию.


7
Если вы используете git rebase, вы можете просто удалить коммиты. Я думаю, что есть причина не перебазировать, например, чтобы сохранить SHA1 фиксации F таким же.
Palo Ebermann 02

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