Мне нужно выскочить и выбросить «средний» коммит в моей основной ветке. Как я могу это сделать?

96

Например, в следующей основной ветке мне нужно удалить только фиксацию af5c7bf16e6f04321f966b4231371b21475bc4da, которая является второй из-за предыдущей перебазировки:

commit 60b413512e616997c8b929012cf9ca56bf5c9113
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Tue Apr 12 23:50:15 2011 +0200

    add generic config/initializers/omniauth.example.rb

commit af5c7bf16e6f04321f966b4231371b21475bc4da
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Fri Apr 22 00:15:50 2011 +0200

    show github user info if logged

commit e6523efada4d75084e81971c4dc2aec621d45530
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Fri Apr 22 17:20:48 2011 +0200

    add multiple .container at blueprint layout

commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22
Author: Luca G. Soave <luca.soave@gmail.com>
Date:   Thu Apr 21 19:55:57 2011 +0200

    add %h1 Fantastic Logo + .right for 'Sign in with Github'

Мне нужно поддерживать

  • Первый коммит 60b413512e616997c8b929012cf9ca56bf5c9113,
  • Третий коммит e6523efada4d75084e81971c4dc2aec621d45530 и
  • Последний коммит 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22

"выбросить" только Второй коммит af5c7bf16e6f04321f966b4231371b21475bc4da

Как я могу это сделать? Заранее спасибо Лука

Лука Г. Соаве
источник

Ответы:

103

Возможны варианты восстановления базы или возврата . Rebase фактически удалит фиксацию из истории, так что будет выглядеть так, как будто второй фиксации никогда не существовало. Это будет проблемой, если вы переместили основную ветку в любые другие репозитории. Если в этом случае вы попытаетесь нажать после перезагрузки, git выдаст вам ошибку отклонения без перемотки вперед .

Возврат - правильное решение, если ветка была поделена с другими репозиториями. git revert af5c7bf16сделает новый коммит, который просто отменяет изменения, внесенные af5c7bf16. Таким образом, история не переписывается, вы ведете четкую запись ошибки, а другие репозитории примут толчок.

Вот хороший способ стирания: git rebase -i <commit>^ это приведет вас к фиксации непосредственно перед той, которую вы хотите удалить. Интерактивный редактор покажет вам список всех коммитов до этого момента. Вы можете выбрать, сжать и т. Д. В этом случае удалите строку фиксации, которую вы хотите стереть, и сохраните файл. Rebase завершит свою работу.

JCotton
источник
2
Если я выберу Rebase, какой коммит нужно перебазировать? Мне нужно сбросить только второй ...
Лука Г. Соаве
@ BBJ3 См. Ответ mipadi.
Prajwal Dhatwalia
34

Если перебазировать вариант, вы можете перебазировать и просто отбросить его:

$ git rebase -i 414ceffc^

Если перебазирование невозможно, вы можете просто отменить его:

$ git revert af5c7bf16
мипади
источник
если я получил "git rebase 414ceffc", который является более старым четвертым коммитом, не потеряю ли я также третий e6523 и первый 60b41?
Лука Г. Соаве
3
@Luca G. Soave: Вы "потеряете" фиксацию только в том случае, если вы специально укажете git rebaseее сбросить (запустив rebaseв интерактивном режиме и удалив запись).
mipadi
Спасибо, mipadi, я отдаю свой голос JCotton по существу за подробное объяснение, даже если вы двое сказали одно и то же ... еще раз спасибо.
Лука Г. Соаве
30

Несмотря на всю заслугу первоначальных ответов, полученных здесь, я не нашел их, чтобы дать удовлетворительный ответ на вопрос. Если вы оказались в ситуации, когда вам нужно удалить коммит или набор коммитов из середины истории, я предлагаю следующее:

  • Создайте новую ветку в начале той, которая содержит все коммиты, и переключитесь на нее.
  • Верните новую ветку обратно в точку, с которой вы хотите начать новую базу.
  • Затем (вот ключевой момент) вишня выберите последующие коммиты, которые вы действительно хотите применить после этого из исходной ветки к новой, и пропустите коммиты, которые вам больше не нужны (то есть те, которые вы удаляете).
  • При желании переименуйте исходную ветку во что-нибудь, указывающее на ее старый код, а затем переименуйте новую ветку так, как называлась исходная.
  • Наконец, отправьте свои изменения в удаленное репо (если оно используется). Вам, вероятно, потребуется использовать «принудительный толчок». Если у ваших соавторов есть проблемы с получением изменений, им может быть проще просто клонировать репозиторий снова из удаленного источника. Так или иначе, вы, вероятно, захотите поговорить с ними, если вы все равно вырываете коммиты из середины своей истории!

Вот информация о Cherry Picking: что означает выбор вишневого коммита с помощью git?

Вот несколько примеров того, как это сделать с Tortoise Git (как я только что сделал). Определенно проще использовать утилиту gui для такого рода операций! Сбор вишни с помощью TortoiseGit

BuvinJ
источник
6
Это должен был быть главный ответ!
MadOgre
Хороший способ использовать вишневый выбор, это решение даже лучше, если вы хотите «пропустить» более одной фиксации.
Джонни Виллер
Не совсем ответ на исходный вопрос. Хотя предлагаемое решение работает, оно занимает гораздо больше времени / неудобно, и IMO не приносит никакой пользы. Если ветка уже была отправлена ​​(и использовалась в дикой природе), вероятно, ответом будет стратегия возврата. Если нет, я бы использовал интерактивное перебазирование и удаление ошибочной фиксации. Если он был отправлен, но мы знаем, что он никем не используется, вы все равно можете уйти с помощью перебазирования с последующим принудительным толчком.
raduw