Отменить диапазон коммитов в 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"
VonC
источник
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

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

Ramast
источник
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