Этот вопрос плохо определен. В нем прямо не говорится, что автор хочет 1-2- (3 + 4) -5 или 1-2-4-5
RandyTek
14
Ну, через 8 лет я не могу точно сказать, какую проблему я пытался решить. Но в git всегда есть много способов что-то сделать, и есть много ответов, которые понравились разным людям, поэтому я думаю, что двусмысленность не доставляет слишком многим людям много затруднений
1800 ИНФОРМАЦИЯ
1
git rebase --onto 2 3 HEADв значительной степени означает изменение на 2, с коммитами между 3 и HEAD (HEAD является необязательным, или 5 в данном случае)
neaumusic
Ответы:
76
Чтобы объединить ревизию 3 и 4 в одну ревизию, вы можете использовать git rebase. Если вы хотите удалить изменения в редакции 3, вам нужно использовать команду редактирования в интерактивном режиме перебазирования. Если вы хотите объединить изменения в одну ревизию, используйте сквош.
Я успешно использовал эту технику сквоша, но мне никогда не нужно было удалять ревизию раньше. Надеемся, что документация git-rebase в разделе «Разделение коммитов» даст вам достаточно идей, чтобы понять это. (Или кто-то еще может знать).
Начните с самого старого коммита, который вы хотите сохранить как есть:
git rebase -i <after-this-commit>
Редактор будет запущен со всеми коммитами в вашей текущей ветке (игнорируя коммиты слияния), которые идут после данного коммита. Вы можете переупорядочить коммиты в этом списке на свое усмотрение, и вы можете удалить их. Список выглядит примерно так:
забрать мёртвую пчелиную линию этого коммита
pick fa1afe1 Он-лайн следующего коммита
...
Онлайновые описания предназначены исключительно для вашего удовольствия; git-rebase будет смотреть не на них, а на имена коммитов ("deadbee" и "fa1afe1" в этом примере), поэтому не удаляйте и не редактируйте имена.
Заменив команду «pick» на команду «edit», вы можете указать git-rebase прекратить работу после применения этого коммита, чтобы вы могли редактировать файлы и / или сообщение о коммите, вносить изменения и продолжать перебазирование.
Если вы хотите сложить два или более коммитов в один, замените команду «pick» на «squash» для второго и последующих коммитов. Если у коммитов были разные авторы, он будет приписывать сжатый коммит автору первого коммита.
-1 Вопрос хорошо определен, но этот ответ не так ясен. Автор не говорит, каково точное решение.
Александр Левчук
1
Это неверное руководство. Раздел SPLITTING COMMITS не является правильным. Вы хотите прочитать намного выше в руководстве - см. Ответ @Rares Vernica.
Александр Левчук
1
@AleksandrLevchuk Вопрос не является четко определенным: из того, как сформулирован вопрос, неясно, следует ли сохранять или отменять набор изменений в 3. Я согласен, что если изменения будут отменены, другие ответы предлагают более легкий подход. Однако, если изменения будут сохранены, это будет чисто косметическая операция. Оба подхода переписывают историю способами, которые опасны, если другие могут основывать работу на вершине ошибочной истории; в этом случае косметическая очистка не должна выполняться, а удаление изменений лучше выполнить с помощью git revert.
Теодор Мердок
125
Согласно этому комментарию (и я проверил, что это правда), ответ Радо очень близок, но оставляет мерзавца в оторванном состоянии. Вместо этого удалите HEADи используйте это для удаления <commit-id>из ветки, в которой вы находитесь:
Если бы вы могли сказать мне, как также удалить этот идентификатор фиксации из истории, основанный только на идентификаторе фиксации, вы были бы моим героем.
kayleeFrye_onDeck
Можете ли вы включить объяснение, что волшебная команда делает в ответ? Т.е. что обозначает каждый параметр?
alexandroid
это круто, но что если я захочу удалить самый первый коммит в истории? (вот почему я пришел сюда: P)
Стерлинг Камден
2
По какой-то причине ничего не происходит, когда я запускаю это. Тем не менее, изменился, ^чтобы ~1заставить его работать.
Сурьма
Уже поздно, но я собираюсь добавить, что если вы столкнетесь с конфликтами слияния, прервите ребазирование, а затем повторно запустите его --strategy-option theirsв конце.
LastStar007
122
Вот способ удалить неинтерактивную информацию <commit-id>, зная только то, что <commit-id>вы хотели бы удалить:
У меня тоже сработало. Кстати, что делает оператор ^? Означает ли это следующий коммит после указанного?
Хопия
3
@hopia это означает (первый) родитель указанного коммита. Смотрите "git help revisions"
Эмиль Стайрк,
12
См. Рекомендацию @ kareem в его ответе опустить, HEADчтобы избежать отстраненной головы.
mklement0
1
Гораздо проще, чем выяснить, сколько коммитов возвращается на поиск.
Дана Вудман
1
это круто, но что если я захочу удалить самый первый коммит в истории? (вот почему я пришел сюда: P)
Стерлинг Камден
76
Как отмечалось ранее, 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):
Диапазон коммитов также может быть удален с помощью rebase. Если у нас следующая ситуация:
E---F---G---H---I---J topicA
тогда команда
git rebase --onto topicA~5 topicA~3 topicA
приведет к удалению коммитов F и G:
E---H'---I'---J' topicA
Это полезно, если F и G были ошибочными или не должны быть частью темы A. Обратите внимание, что аргумент --onto и параметр могут быть любым допустимым коммитом.
Если все, что вы хотите сделать, это удалить изменения, сделанные в редакции 3, вы можете использовать git revert.
Git revert просто создает новую ревизию с изменениями, которые отменяют все изменения в ревизии, которую вы возвращаете.
Это означает, что вы сохраняете информацию как о нежелательном коммите, так и о коммите, который удаляет эти изменения.
Вероятно, это будет гораздо более дружелюбно, если вообще возможно, что кто-то извлечет из вашего хранилища за это время, так как возврат - это просто стандартный коммит.
К сожалению, это не очень хорошее решение для меня, потому что кто-то случайно вложил в репо 100 МБ дерьма, взорвав его размер и сделав веб-интерфейс вялым.
Стивен Смит
18
Все ответы до сих пор не относятся к последним проблемам:
Есть ли эффективный метод, когда после удаления нужно сотни ревизий?
Далее следуют шаги, но для справки, давайте предположим следующую историю:
С : коммит только после коммита, который будет удален (чистый)
R : коммит, который будет удален
B : коммит, предшествующий коммиту, который нужно удалить (базовый)
Из-за ограничения «сотни ревизий» я предполагаю следующие предварительные условия:
есть какой-то смущающий коммит, который вы хотели бы никогда не существовать
есть ZERO последующих коммитов, которые на самом деле зависят от этого смущающего коммита (ноль конфликтов при возврате)
вам все равно, что вы будете внесены в список «коммиттеров» из сотен промежуточных коммитов («автор» будет сохранен)
вы никогда не разделяли хранилище
или вы на самом деле имеете достаточно влияния на всех людей, которые когда-либо клонировали историю с этим обязательством, чтобы убедить их использовать вашу новую историю
Это довольно ограничительный набор ограничений, но есть интересный ответ, который действительно работает в этом угловом случае.
Вот шаги:
git branch base B
git branch remove-me R
git branch save
git rebase --preserve-merges --onto base remove-me
Если действительно нет конфликтов, то это должно продолжаться без дальнейших перерывов. Если есть конфликты, вы можете разрешить их и rebase --continueили решить просто жить с смущением и rebase --abort.
Теперь вы должны быть на masterтом, что больше не имеет R в нем. В saveточках ветвления, где вы были раньше, в случае , если вы хотите совместить.
Как вы хотите организовать переход всех остальных на вашу новую историю, зависит от вас. Вам нужно будет ознакомиться с stash, reset --hardи cherry-pick. И вы можете удалить base, remove-meи saveветви
Ответы rado и kareem ничего не делают для меня (появляется только сообщение «Текущая ветка актуальна».) Возможно, это происходит потому, что символ «^» не работает в консоли Windows. Однако, согласно этому комментарию, замена «^» на «~ 1» решает проблему.
git rebase --onto 2 3 HEAD
в значительной степени означает изменение на 2, с коммитами между 3 и HEAD (HEAD является необязательным, или 5 в данном случае)Ответы:
Чтобы объединить ревизию 3 и 4 в одну ревизию, вы можете использовать git rebase. Если вы хотите удалить изменения в редакции 3, вам нужно использовать команду редактирования в интерактивном режиме перебазирования. Если вы хотите объединить изменения в одну ревизию, используйте сквош.
Я успешно использовал эту технику сквоша, но мне никогда не нужно было удалять ревизию раньше. Надеемся, что документация git-rebase в разделе «Разделение коммитов» даст вам достаточно идей, чтобы понять это. (Или кто-то еще может знать).
Из документации git :
источник
Согласно этому комментарию (и я проверил, что это правда), ответ Радо очень близок, но оставляет мерзавца в оторванном состоянии. Вместо этого удалите
HEAD
и используйте это для удаления<commit-id>
из ветки, в которой вы находитесь:источник
^
чтобы~1
заставить его работать.--strategy-option theirs
в конце.Вот способ удалить неинтерактивную информацию
<commit-id>
, зная только то, что<commit-id>
вы хотели бы удалить:источник
HEAD
чтобы избежать отстраненной головы.Как отмечалось ранее, git-rebase (1) - ваш друг. Предполагая, что коммиты находятся в вашей
master
ветке, вы должны сделать:Перед:
После:
Из git-rebase (1):
источник
--onto master~3 master~1
?MERGE CONFLICT
ошибку. Я использовал сценарий, упомянутый в stackoverflow.com/questions/2938301/remove-specific-commit, и не могу удалить 2-й коммит в этом примере.Если все, что вы хотите сделать, это удалить изменения, сделанные в редакции 3, вы можете использовать git revert.
Git revert просто создает новую ревизию с изменениями, которые отменяют все изменения в ревизии, которую вы возвращаете.
Это означает, что вы сохраняете информацию как о нежелательном коммите, так и о коммите, который удаляет эти изменения.
Вероятно, это будет гораздо более дружелюбно, если вообще возможно, что кто-то извлечет из вашего хранилища за это время, так как возврат - это просто стандартный коммит.
источник
Все ответы до сих пор не относятся к последним проблемам:
Далее следуют шаги, но для справки, давайте предположим следующую историю:
С : коммит только после коммита, который будет удален (чистый)
R : коммит, который будет удален
B : коммит, предшествующий коммиту, который нужно удалить (базовый)
Из-за ограничения «сотни ревизий» я предполагаю следующие предварительные условия:
Это довольно ограничительный набор ограничений, но есть интересный ответ, который действительно работает в этом угловом случае.
Вот шаги:
git branch base B
git branch remove-me R
git branch save
git rebase --preserve-merges --onto base remove-me
Если действительно нет конфликтов, то это должно продолжаться без дальнейших перерывов. Если есть конфликты, вы можете разрешить их и
rebase --continue
или решить просто жить с смущением иrebase --abort
.Теперь вы должны быть на
master
том, что больше не имеет R в нем. Вsave
точках ветвления, где вы были раньше, в случае , если вы хотите совместить.Как вы хотите организовать переход всех остальных на вашу новую историю, зависит от вас. Вам нужно будет ознакомиться с
stash
,reset --hard
иcherry-pick
. И вы можете удалитьbase
,remove-me
иsave
ветвиисточник
Я также приземлился в аналогичной ситуации. Используйте интерактивную перебазировку, используя команду ниже, и при выборе отбросьте 3-й коммит.
источник
Итак, вот сценарий, с которым я столкнулся, и как я его решил.
вот
R
коммит, который мне нужно было удалить, иI
это единственный коммит, который приходит послеR
Я сделал обратный коммит и раздавил их вместе
Во время интерактивного сквоша за последние 2 коммита.
источник
Ответы rado и kareem ничего не делают для меня (появляется только сообщение «Текущая ветка актуальна».) Возможно, это происходит потому, что символ «^» не работает в консоли Windows. Однако, согласно этому комментарию, замена «^» на «~ 1» решает проблему.
источник