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


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 завершит свою работу.


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


6
Это должен был быть главный ответ!
— MadOgre

Хороший способ использовать вишневый выбор, это решение даже лучше, если вы хотите «пропустить» более одной фиксации.
— Джонни Виллер

Не совсем ответ на исходный вопрос. Хотя предлагаемое решение работает, оно занимает гораздо больше времени / неудобно, и IMO не приносит никакой пользы. Если ветка уже была отправлена ​​(и использовалась в дикой природе), вероятно, ответом будет стратегия возврата. Если нет, я бы использовал интерактивное перебазирование и удаление ошибочной фиксации. Если он был отправлен, но мы знаем, что он никем не используется, вы все равно можете уйти с помощью перебазирования с последующим принудительным толчком.
— raduw
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.