Я уже спрашивал о том, как раздавить первые два коммита в репозитории git.
Хотя решения довольно интересны и не настолько изнурительны, как некоторые другие вещи в git, они все еще немного мешают всем, если вам нужно повторять эту процедуру много раз по мере развития вашего проекта.
Итак, я бы предпочел пройти через боль только один раз, а затем смог бы навсегда использовать стандартный интерактивный ребаз.
Поэтому я хочу иметь пустой начальный коммит, который существует исключительно с целью быть первым. Нет кода, нет ничего. Просто занимая место, чтобы он мог стать базой для перебазирования.
Мой вопрос тогда, имея существующее хранилище, как мне вставить новый пустой коммит перед первым и переместить всех остальных вперед?
Ответы:
Для этого есть 2 шага:
newroot
Для удобства мы поместим новый пустой коммит во временную ветку .1. Создайте новый пустой коммит
Есть несколько способов сделать это.
Используя только сантехнику
Самый чистый подход - использовать сантехнику Git, чтобы просто создать коммит напрямую, что позволяет избежать прикосновения к рабочей копии, индексу или какой ветке извлечено и т. Д.
Создайте объект дерева для пустой директории:
Оберните коммит вокруг него:
Создайте ссылку на него:
Конечно, вы можете перестроить всю процедуру в одну строку, если вы хорошо знаете свою оболочку.
Без сантехники
С помощью обычных фарфоровых команд вы не можете создать пустой коммит без проверки
newroot
ветки и повторного обновления индекса и рабочей копии без уважительной причины. Но некоторые могут найти это легче понять:Обратите внимание, что на очень старых версиях Git, в которых нет
--orphan
переключателяcheckout
, вы должны заменить первую строку следующим образом:2. Переписать историю, чтобы начать с этого пустого коммита
У вас есть два варианта: перебазирование или переписывание чистой истории.
перебазировка
Это имеет преимущество простоты. Однако он также будет обновлять имя и дату коммиттера при каждом последнем коммите в ветви.
Кроме того, с некоторыми крайними историями событий он может даже потерпеть неудачу из-за конфликтов слияния - несмотря на тот факт, что вы переходите на коммит, который ничего не содержит.
Переписать историю
Более чистый подход - переписать ветку. В отличие от с
git rebase
, вам нужно посмотреть, с какого коммита начинается ваша ветка:Переписывание происходит на втором этапе, очевидно; это первый шаг, который требует объяснения. Это
git replace
говорит Git, что всякий раз, когда он видит ссылку на объект, который вы хотите заменить, Git должен вместо этого посмотреть на замену этого объекта.С
--graft
выключателем вы говорите что-то немного другое, чем обычно. Вы говорите, что у вас еще нет объекта замены, но вы хотите заменить<currentroot>
объект фиксации точной копией самого себя, за исключением того, что родительский коммит (ы) замены должен быть тем, который вы перечислили (т.е.newroot
коммит) ). Затемgit replace
идет вперед и создает этот коммит для вас, а затем объявляет этот коммит в качестве замены вашего исходного коммита.Теперь, если вы сделаете a
git log
, вы увидите, что все уже выглядит так, как вы хотите: ветвь начинается сnewroot
.Тем не менее, обратите внимание, что
git replace
это на самом деле не изменяет историю - и при этом не распространяется из вашего хранилища. Он просто добавляет локальное перенаправление в ваш репозиторий с одного объекта на другой. Это означает, что никто не видит эффекта этой замены - только вы.Вот почему
filter-branch
шаг необходим. При этомgit replace
вы создаете точную копию с откорректированными родительскими коммитами для корневого коммита;git filter-branch
затем повторяет этот процесс для всех следующих коммитов. Вот где история на самом деле переписывается, чтобы вы могли поделиться ею.источник
--onto newroot
опция избыточна; Вы можете обойтись без него, потому что аргумент, который вы передаетеnewroot
, совпадает с аргументом вышеnewroot
.git-checkout
него был этот переключатель. Я обновил его, чтобы упомянуть этот подход в первую очередь, спасибо за указатель.git rebase --merge -s recursive -X theirs --onto newroot --root master
для автоматического разрешения всех конфликтов (см. Этот ответ). @AlexanderKuzinСлияние ответов Аристотеля Пагальциса и Уве Кляйн-Кенига и комментария Ричарда Броноски.
(просто положить все в одно место)
источник
git rebase newroot master
, из-за ошибки.Мне нравится ответ Аристотеля. Но обнаружил, что для большого репозитория (> 5000 коммитов) ветвь фильтра работает лучше, чем ребаз по нескольким причинам: 1) это быстрее, 2) не требует вмешательства человека, когда возникает конфликт слияния. 3) он может переписать теги - сохранив их. Обратите внимание, что фильтр-ветвь работает, потому что нет никаких сомнений относительно содержимого каждого коммита - он точно такой же, как и до этого 'rebase'.
Мои шаги:
Обратите внимание, что параметры '--tag-name-filter cat' означают, что теги будут переписаны так, чтобы указывать на вновь созданные коммиты.
источник
Я успешно использовал фрагменты ответа Аристотеля и Кента:
Это также перезапишет все ветви (не только
master
) в дополнение к тегам.источник
refs/original/
и удаляет каждую ссылку. На ссылки, которые он удаляет, уже должна ссылаться какая-то другая ветка, поэтому они на самом деле не уходят, а простоrefs/original/
удаляются.timedatectl set-time '2017-01-01 00:00:00'
давалnewroot
старую метку времени.git rebase --root --onto $emptyrootcommit
должен сделать трюк легко
источник
$emptyrootcommit
переменная оболочки, которая, конечно, ничего не расширяет?Я думаю, что использование
git replace
иgit filter-branch
является лучшим решением, чем использованиеgit rebase
:Идея заключается в следующем:
git filter-branch
Вот скрипт для 2 первых шагов:
Вы можете запустить этот сценарий без риска (даже если создание резервной копии перед выполнением действия, которое вы никогда не выполняли ранее, является хорошей идеей;)), и если результат не тот, который ожидается, просто удалите файлы, созданные в папке
.git/refs/replace
и повторите попытку; )Убедившись, что состояние репозитория соответствует ожидаемому, выполните следующую команду, чтобы обновить историю всех ветвей :
Теперь вы должны увидеть 2 истории: старую и новую (см. Справку
filter-branch
для получения дополнительной информации). Вы можете сравнить 2 и еще раз проверить, все ли в порядке. Если вы удовлетворены, удалите ненужные файлы:Вы можете вернуться в свою
master
ветку и удалить временную ветку:Теперь все должно быть сделано;)
источник
Я был взволнован и написал «идемпотентную» версию этого замечательного скрипта ... он всегда будет вставлять один и тот же пустой коммит, и если вы запустите его дважды, он не изменит ваши хеши коммитов каждый раз. Итак, вот мой взгляд на git-insert-empty-root :
Стоит ли дополнительная сложность? возможно нет, но я буду использовать это.
Это ДОЛЖНО также позволить выполнить эту операцию с несколькими клонированными копиями репозитория, и в конечном итоге получить те же результаты, поэтому они все еще совместимы ... тестирование ... да, это работает, но нужно также удалить и добавить свой снова пульты, например:
источник
Чтобы добавить пустой коммит в начале репозитория, если вы забыли создать пустой коммит сразу после «git init»:
источник
Ну, вот что я придумал:
источник
Вот мой
bash
сценарий, основанный на ответе Кента с улучшениями:master
, когда сделано;git checkout --orphan
работает только с веткой, а не с состоянием отсоединенной головы, поэтому он извлекается достаточно долго, чтобы сделать новый корневой коммит, а затем удаляется;filter-branch
(Кент оставил там заполнитель для ручной замены);filter-branch
операция переписывает только местные отделения, не слишком пультовисточник
Чтобы переключить корневой коммит:
Сначала создайте коммит, который вы хотите первым.
Во-вторых, измените порядок коммитов, используя:
git rebase -i --root
Редактор будет отображаться с коммитами вплоть до корневого коммита, например:
выбрать 1234 старое корневое сообщение
выбрать 0294 коммит в середине
выбрать 5678 коммит вы хотите положить в корень
Затем вы можете поместить нужный коммит первым, поместив его в первую строку. В примере:
выбрать 5678 коммит вы хотите положить в корень
выбрать 1234 старое корневое сообщение
выбрать 0294 коммит в середине
Выйдите из редактора, порядок фиксации будет изменен.
PS: Чтобы изменить редактор, который использует git, запустите:
git config --global core.editor name_of_the_editor_program_you_want_to_use
источник
Сочетание последних и лучших. Никаких побочных эффектов, никаких конфликтов, сохранение тегов.
Обратите внимание, что на GitHub вы потеряете данные запуска CI, и PR может испортиться, если не будут исправлены и другие ветви.
источник
Следующий ответ Аристотель Пагальцис и другие, но с использованием более простых команд
Обратите внимание, что в вашем репо не должно быть локальных изменений, ожидающих подтверждения. Я думаю,
Note
git checkout --orphan
будет работать на новых версиях git.Обратите внимание, что большую часть времени
git status
дает полезные советы.источник
Начать новый репозиторий.
Установите дату обратно на желаемую дату начала.
Делайте все так, как вы хотите, чтобы вы делали это, настраивая системное время так, чтобы отражать, когда вы хотели, чтобы вы делали это таким образом. Извлекайте файлы из существующего репозитория по мере необходимости, чтобы избежать ненужного набора текста.
Когда вы доберетесь до сегодняшнего дня, поменяйте местами репозитории, и все готово.
Если вы просто сумасшедший (устоявшийся), но достаточно умный (вероятно, потому, что вам нужно иметь определенное количество умов, чтобы придумывать сумасшедшие идеи, подобные этой), вы будете писать сценарий процесса.
Это также сделает его более приятным, если вы решите, что прошлое должно было случиться как-то иначе через неделю.
источник
Я знаю, что этот пост старый, но эта страница первая, когда Googling "вставляет коммит git".
Зачем делать простые вещи сложными?
У вас есть ABC, и вы хотите ABZC.
git rebase -i trunk
(или что-нибудь до B)git add ..
git commit
(git commit --amend
который будет редактировать B, а не создавать Z)[Вы можете сделать столько,
git commit
сколько хотите, чтобы вставить больше коммитов. Конечно, у вас могут возникнуть проблемы с шагом 5, но разрешение конфликта слияния с помощью git - это навык, который вы должны иметь. Если нет, практикуйтесь!]git rebase --continue
Просто, не правда ли?
Если вы понимаете
git rebase
, добавление «корневого» коммита не должно быть проблемой.Веселитесь с мерзавцем!
источник
git rebase
не может сделать это.