Как вы удаляете конкретную ревизию в истории git? - PullRequest
201 голосов
/ 01 сентября 2008

Предположим, что ваша история git выглядит так:

1 2 3 4 5

1–5 - это отдельные редакции. Вам нужно удалить 3, сохраняя при этом 1, 2, 4 и 5. Как это можно сделать?

Существует ли эффективный метод, когда после удаляемой сотни обновлений существуют?

Ответы [ 10 ]

118 голосов
/ 14 сентября 2010

Вот способ неинтерактивно удалить конкретную <commit-id>, зная только <commit-id>, которую вы хотите удалить:

git rebase --onto <commit-id>^ <commit-id> HEAD
114 голосов
/ 15 ноября 2012

За этот комментарий (и я проверил, что это правда), ответ Радо очень близок, но оставляет мерзавца в оторванном состоянии. Вместо этого удалите HEAD и используйте это для удаления <commit-id> из вашей ветки:

git rebase --onto <commit-id>^ <commit-id>
74 голосов
/ 06 ноября 2010

Как отмечалось ранее git-rebase (1) - ваш друг. Предполагая, что коммиты находятся в вашей ветке master, вы должны сделать:

git rebase --onto master~3 master~2 master

До:

1---2---3---4---5  master

После того, как:

1---2---4'---5' master

Из git-rebase (1):

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

E---F---G---H---I---J  topicA

затем команда

git rebase --onto topicA~5 topicA~3 topicA

приведет к удалению совершает F и G:

E---H'---I'---J'  topicA

Это полезно, если F и G были ошибочными в некоторых Кстати, или не должно быть частью темы А. Обратите внимание, что аргумент --onto и параметр может быть любым действительный коммит.

72 голосов
/ 01 сентября 2008

Чтобы объединить редакцию 3 и 4 в одну редакцию, вы можете использовать git rebase. Если вы хотите удалить изменения в редакции 3, вам нужно использовать команду редактирования в интерактивном режиме перебазирования. Если вы хотите объединить изменения в одну ревизию, используйте сквош.

Я успешно использовал эту технику сквоша, но мне никогда не нужно было удалять ревизию раньше. Надеемся, что документация git-rebase в разделе «Разделение коммитов» даст вам достаточно идей, чтобы понять это. (Или кто-то еще может знать).

Из документации git :

Начните с самого старого коммита, который вы хотите сохранить как есть:

git rebase -i <after-this-commit>

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

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

Онлайновые описания предназначены исключительно для вашего удовольствия; git-rebase будет смотреть не на них, а на имена коммитов (в этом примере «deadbee» и «fa1afe1»), поэтому не удаляйте и не редактируйте имена.

Заменив команду «pick» на команду «edit», вы можете указать git-rebase прекратить после применения этого коммита, чтобы вы могли редактировать файлы и / или сообщение о коммите, вносить изменения и продолжать перебазирования.

Если вы хотите сложить два или более коммитов в один, замените команду «pick» на «squash» для второго и последующих коммитов. Если у коммитов были разные авторы, то сдавленный коммит будет приписываться автору первого коммита.

22 голосов
/ 05 сентября 2008

Если все, что вы хотите сделать, это удалить изменения, внесенные в редакцию 3, вы можете использовать git revert.

Git revert просто создает новую ревизию с изменениями, которые отменяют все изменения в ревизии, которую вы возвращаете.

Это означает, что вы сохраняете информацию как о нежелательном коммите, так и о коммите, который удаляет эти изменения.

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

15 голосов
/ 24 сентября 2012

Все ответы на данный момент не относятся к конечной проблеме:

Есть ли эффективный метод при сотнях ревизий? после удаляемого?

Далее следуют шаги, но для справки, давайте предположим следующую историю:

[master] -> [hundreds-of-commits-including-merges] -> [C] -> [R] -> [B]

C : коммит, следующий за коммитом, который будет удален (чистый)

R : Коммит, который будет удален

B : коммит, предшествующий коммиту, который будет удален (базовый)

Из-за ограничения «сотни ревизий» я предполагаю следующие предварительные условия:

  1. есть какой-то смущающий коммит, которого вы бы никогда не хотели
  2. есть ZERO последующих коммитов, которые на самом деле зависят от этого смущающего коммита (ноль конфликтов при возврате)
  3. вас не волнует, что вы будете внесены в список «коммиттеров» из сотен промежуточных коммитов («Автор» будет сохранен)
  4. вы никогда не делили хранилище
    • или вы действительно имеете достаточно влияния на всех людей, которые когда-либо клонировали историю с этим обязательством, чтобы убедить их использовать вашу новую историю
    • а вам не волнует о переписывает историю

Это довольно ограниченный набор ограничений, но есть интересный ответ, который действительно работает в этом угловом случае.

Вот шаги:

  1. git branch base B
  2. git branch remove-me R
  3. git branch save
  4. git rebase --preserve-merges --onto base remove-me

Если действительно нет конфликтов, то это должно продолжаться без дальнейших перерывов. Если есть конфликты, вы можете разрешить их и rebase --continue или решить просто жить с смущением и rebase --abort.

Теперь вы должны быть на master, в котором больше нет коммита R . Ветвь save указывает на то место, где вы были раньше, если вы хотите примирить.

Как вы хотите организовать передачу всех остальных в вашу новую историю, зависит от вас. Вам нужно будет ознакомиться с stash, reset --hard и cherry-pick. И вы можете удалить ветви base, remove-me и save

2 голосов
/ 07 сентября 2016

Я тоже приземлился в аналогичной ситуации. Используйте интерактивную перебазировку, используя приведенную ниже команду, и при выборе удалите 3-й коммит

git rebase -i remote/branch
2 голосов
/ 05 ноября 2014

Итак, вот сценарий, с которым я столкнулся, и как я его решил.

[branch-a]

[Hundreds of commits] -> [R] -> [I]

здесь R - это коммит, который мне нужно было удалить, а I - это один коммит, который следует после R

Я сделал обратный коммит и раздавил их вместе

git revert [commit id of R]
git rebase -i HEAD~3

Во время интерактивного сквоша с ребазе последние 2 коммита.

0 голосов
/ 08 июля 2018

Чтобы удалить старую историю коммитов из git repo:

Первый запуск ниже cmd

rm -rf .git

- воссоздать репо из текущего

git init                                                                           
git add .                                                  
git commit -m "first commit"

- отправка в репозиторий github

git remote add origin git@github.com<your git mail>   
git push -u --force origin master
0 голосов
/ 14 сентября 2017

Ответы rado и kareem ничего не делают для меня (появляется только сообщение «Текущая ветка актуальна».) Возможно, это происходит потому, что символ «^» не работает в консоли Windows. Однако, согласно этому комментарию, замена '^' на '~ 1' решает проблему.

git rebase --onto <commit-id>^ <commit-id>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...