Для этого есть 2 шага:
- Создать новую пустую фиксацию
- Перепишите историю, чтобы начать с этого пустого коммита
Мы поместим новую пустую фиксацию во временную ветку newroot
для удобства.
1. Создайте новую пустую фиксацию
Есть несколько способов сделать это.
Использование только сантехники
Самый чистый подход - использовать встроенную систему Git, чтобы просто создать фиксацию напрямую, что позволяет избежать касания рабочей копии или индекса, а также того, какая ветка извлечена и т. Д.
Создайте объект дерева для пустого каталога:
tree=`git hash-object -wt tree --stdin < /dev/null`
Оберните вокруг него коммит:
commit=`git commit-tree -m 'root commit' $tree`
Создайте ссылку на него:
git branch newroot $commit
Вы, конечно, можете преобразовать всю процедуру в однострочную, если вы достаточно хорошо знаете свою оболочку.
Без сантехники
С помощью обычных фарфоровых команд вы не можете создать пустую фиксацию, не проверив ветку newroot
и неоднократно обновляя индекс и рабочую копию, без уважительной причины. Но некоторым это будет легче понять:
git checkout --orphan newroot
git rm -rf .
git clean -fd
git commit --allow-empty -m 'root commit'
Обратите внимание, что в очень старых версиях Git, в которых отсутствует переключатель --orphan
на checkout
, вы должны заменить первую строку следующим образом:
git symbolic-ref HEAD refs/heads/newroot
2. Перепишите историю, чтобы начать с этого пустого коммита.
У вас есть два варианта: перебазирование или перезапись чистой истории.
Ребазинг
git rebase --onto newroot --root master
В этом преимущество простоты. Однако он также будет обновлять имя и дату коммиттера при каждой последней фиксации в ветке.
Кроме того, с некоторыми краевыми историями случаев он может даже выйти из строя из-за конфликтов слияния - несмотря на то, что вы выполняете переустановку на фиксацию, которая ничего не содержит.
Переписать историю
Более чистый подход - переписать ветку. В отличие от git rebase
, вам нужно будет посмотреть, с какого коммита начинается ваша ветка:
git replace <currentroot> --graft newroot
git filter-branch master
Очевидно, что переписывание происходит на втором этапе; это первый шаг, требующий объяснения. Что git replace
делает, так это сообщает Git, что всякий раз, когда он видит ссылку на объект, который вы хотите заменить, Git должен вместо этого проверять замену этого объекта.
С переключателем --graft
вы говорите немного иначе, чем обычно. Вы говорите, что у вас еще нет заменяющего объекта, но вы хотите заменить объект <currentroot>
commit его точной копией за исключением, что родительский коммит (и) замены должен быть тем (и) ), который вы указали (т. е. фиксация newroot
). Затем git replace
создает эту фиксацию для вас, а затем объявляет эту фиксацию как замену вашей исходной фиксации.
Теперь, если вы выполните git log
, вы увидите, что все уже выглядит так, как вы хотите: ветвь начинается с newroot
.
Однако обратите внимание, что git replace
на самом деле не изменяет историю - и не распространяется за пределы вашего репозитория. Он просто добавляет локальное перенаправление в ваш репозиторий с одного объекта на другой. Это означает, что никто другой не видит эффекта от этой замены - только вы.
Вот почему необходим filter-branch
шаг. С git replace
вы создаете точную копию с настроенными родительскими коммитами для корневого коммита; git filter-branch
затем повторяет этот процесс для всех следующих коммитов. Вот где история фактически переписывается, чтобы вы могли ею поделиться.
person
Aristotle Pagaltzis
schedule
15.03.2009
.gitignore
в качестве корневого коммита git - person Robin Hsu   schedule 18.01.2019