Git вернуть несколько конкретных коммитов

Проблема: ветвь имеет хорошие коммиты, чередующиеся с нежелательными.

Попытка решения:

git revert hash5 hash8 hash9 hash23

То, что я думал, что это будет сделано, это то, что оно применило бы все указанные коммиты, а затем разрешило бы мне выявить любые конфликты.

Что я сейчас думаю, что происходит:

  • git применяет commit hash5, в процессе которого возникают большие конфликты.
  • Я присоединяюсь к слиянию, редактирую код, на что хочу, чтобы он выглядел, создавая сцену для большего количества конфликтов (см. следующую точку).
  • git применяет commit hash8, которые конфликтуют с изменениями, выполненными в слиянии
  • Я пытаюсь слить... и т.д.

Вопрос: Как мне получить git, чтобы применить все реверты в строке, прежде чем представлять мне какие-либо возможные конфликты?

Ответы

Ответ 1

Проверка работоспособности

Во-первых, обратите внимание, что git revert возвращает ваши исправления в том порядке, в котором вы перечисляете свои хэши; вам нужно перечислить хеши от самых новых до самых старых, так как вы хотите двигаться назад во времени. Итак, я собираюсь назвать ваши хеши

<hash1> ... <hashN>

где <hash1> старше <hash2>... старше <hashN>. Итак, убедитесь, что вы делали

git revert <hashN> ... <hash1>

в первую очередь!

Простое решение

Во-вторых, если вы вернули их в правильном порядке, попробуйте вариант --no-commit:

git revert --no-commit <hashN> ... <hash1>

Более активное решение

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

  • Создайте большую фиксацию:

    Создайте ветку у родителя самого старого коммита:

    git checkout -b big-commit <hash1>~
    

    Скопируйте коммиты на новую ветку и сверните их:

    git cherry-pick --no-commit <hash1> ... <hashN>
    git commit -m "Big commit"
    

    Теперь у вас должна быть одна большая фиксация на вашей ветке big-commit.

  • Применить большую фиксацию в обратном направлении к ветке, которую вы пытаетесь вернуть:

    git checkout <branch you wanted to revert on>
    git revert big-commit
    

Другое относительно простое решение

Используйте выборочную перезагрузку, чтобы перестроить рассматриваемую ветку, как если бы она не содержала нежелательных коммитов:

  • Создайте новую ветвь rebuild для работы в:

    git checkout -b rebuild <branch you want to revert>
    
  • Интерактивно rebase, отбрасывая коммиты, которые вы не хотите:

    git rebase -i <hash1>~
    

    В редакторе интерактивной перезаписи удалите строки для <hash1>... <hashN>.

Теперь ваш ветвь rebuild будет содержать <branch you want to revert>, как будто <hash1>... <hashN> никогда не существовало. Если вы столкнетесь с конфликтами здесь, казалось бы, они неизбежны.

Если вам нужна ваша работа на <branch you want to revert>, и вы не можете просто git reset указать ее в новую ветвь rebuild:

git checkout <branch you want to revert>
git reset --hard rebuild

(например, потому что вы уже публично публиковали его), вместо этого вы можете применить различия к <branch you want to revert> как патч:

git co <branch you want to revert>    
git diff <branch you want to revert> rebuild | patch