Вставить коммит перед корневым коммитом в Git?

Раньше я спрашивал, как раздавить первые два коммита в репозитории git.

Хотя решения довольно интересны и не так сложны, как некоторые другие вещи в git, они по-прежнему представляют собой пресловутый мешок боли, если вам нужно повторять процедуру много раз в процессе разработки вашего проекта.

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

В таком случае я хочу иметь пустую начальную фиксацию, которая существует исключительно для того, чтобы быть первой. Ни кода, ни ничего. Просто занимает место, так что он может быть базой для перебазирования.

Тогда мой вопрос: имея существующий репозиторий, как мне вставить новую пустую фиксацию перед первой и переместить всех остальных вперед?


person kch    schedule 14.03.2009    source источник
comment
;) Думаю, это в любом случае требует ответа. Я как бы изучаю множество способов сойти с ума, одержимо редактируя историю. Не волнуйтесь, это не общий репозиторий.   -  person kch    schedule 14.03.2009
comment
От одного одержимого, безумного редактора истории к другому, спасибо за вопрос! ; D   -  person Marco    schedule 02.07.2011
comment
В частности, я смотрю на некоторые из репозиториев SVN, которые я конвертирую в Git.   -  person deterb    schedule 26.08.2011
comment
В защиту @kch, я нахожусь в одной вполне законной причине: добавление снимка исторической версии, которая никогда не была зафиксирована в репо.   -  person Old McStopher    schedule 04.07.2012
comment
У меня есть еще одна законная причина! Добавление пустого коммита перед первым, чтобы иметь возможность перенастроить первый коммит и удалить двоичное раздувание, добавленное в начальный коммит репозитория (:   -  person pospi    schedule 13.09.2012
comment
Подождите, как часто вам придется раздавить первые два коммита в проекте? Я не понимаю этого вопроса   -  person Casebash    schedule 30.01.2014
comment
Фактически, я просто добавляю .gitignore в качестве корневого коммита git   -  person Robin Hsu    schedule 18.01.2019


Ответы (15)


Для этого есть 2 шага:

  1. Создать новую пустую фиксацию
  2. Перепишите историю, чтобы начать с этого пустого коммита

Мы поместим новую пустую фиксацию во временную ветку newroot для удобства.

1. Создайте новую пустую фиксацию

Есть несколько способов сделать это.

Использование только сантехники

Самый чистый подход - использовать встроенную систему Git, чтобы просто создать фиксацию напрямую, что позволяет избежать касания рабочей копии или индекса, а также того, какая ветка извлечена и т. Д.

  1. Создайте объект дерева для пустого каталога:

    tree=`git hash-object -wt tree --stdin < /dev/null`
    
  2. Оберните вокруг него коммит:

    commit=`git commit-tree -m 'root commit' $tree`
    
  3. Создайте ссылку на него:

    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
comment
Хороший. Похоже, вы пропустили начальную пустую фиксацию, или я что-то упустил? Кроме того, я немного попробовал, не создавая новый репозиторий, но перебазирование сошло с ума от наборов изменений, касающихся подмодулей. Вы что-нибудь заметили? - person kch; 15.03.2009
comment
Спасибо за указатель - да, я пропустил пустой коммит. Фиксированный. Я не использовал подмодули, поэтому не знаю, как это получается. - person Aristotle Pagaltzis; 15.03.2009
comment
Я использовал это решение с подмодулями, и у меня с ним не было проблем. Как и все: чтобы не сказать, что их нет, просто я никого не ударил. - person kch; 20.05.2009
comment
Эта --onto newroot опция избыточна; вы можете обойтись без него, потому что аргумент, который вы ему передаете, newroot, совпадает с аргументом восходящего потока - newroot. - person wilhelmtell; 27.06.2010
comment
cherry-pick и rebase можно упростить в одну команду: git rebase --onto newroot --root master, см. Мой ответ ниже - person Antony Hatchkins; 16.03.2012
comment
Вау! Аккуратное и эффектное решение. Каждый день я обнаруживаю, что мои знания о git все мельче и мельче по сравнению с возможностями инструмента. Думаю, это тоже заставляет меня защищаться :-). Спасибо за вопрос, спасибо за аккуратный ответ! - person m-ric; 12.10.2012
comment
Почему бы не использовать фарфор вместо сантехнических команд ?. Я бы заменил git symbolic-ref HEAD refs / Heads / newroot на git checkout --orphan newroot - person albfan; 13.10.2012
comment
@nenopera: потому что этот ответ был написан до того, как git-checkout получил этот переключатель. Я обновил его, чтобы в первую очередь упомянуть этот подход, спасибо за указатель. - person Aristotle Pagaltzis; 03.04.2013
comment
Метки времени новой корневой фиксации опережают ее потомков, поэтому в некоторых реализациях пользовательского интерфейса Git (например, SourceTree) кажется, что новый корень отделен от остальных коммитов и находится в самом верху хронологически упорядоченной фиксации. Посмотреть. Если это заставляет вас дергаться, вы можете снова перенастроить свои ветки на новый корень, чтобы обновить их временные метки, или обновить временные метки нового корня до времени до того, как были сделаны все остальные коммиты. На SO есть несколько решений, за которые активно проголосовали. - person Jeff; 08.05.2015
comment
Я пробовал это решение, но оно не сработало. Мне нужно сначала вставить непустую фиксацию, но все остальные деревья фиксации должны оставаться такими же. Но git rebase пытается объединить вставленную фиксацию с root и изменяет все другие деревья фиксации. - person Alexander Kuzin; 10.02.2017
comment
Помните, что git rm -rf . изменяет ваше рабочее дерево. Чтобы избежать этого, сделайте подходящую пустую фиксацию подходящего репозитория, например: git fetch https://github.com/hilbix/empty.git rc; git rebase --onto FETCH_HEAD --keep-empty --root master - person Tino; 11.03.2017
comment
Или вы всегда можете просто добавить --cached в git rm, если не хотите, чтобы он касался вашей рабочей копии. - person Aristotle Pagaltzis; 02.05.2017
comment
@AlexanderKuzin: тогда нужен подход, основанный на git filter-branch. Вы можете использовать ответ Кента, и я также расскажу об этом (но немного иначе и немного лучше, ИМО) в этом ответе, когда у меня будет время. - person Aristotle Pagaltzis; 02.05.2017
comment
Первый абзац после исторического ответа отлично мне подошел! Это кажется намного проще, чем то, что обозначено как ответ середины 2017 года. Сбивает с толку - person Stiggler; 26.05.2017
comment
Если ваш новый корневой каталог не пуст, используйте git rebase --merge -s recursive -X theirs --onto newroot --root master для автоматического разрешения всех конфликтов (см. этот ответ). @AlexanderKuzin - person user; 22.06.2017
comment
@user Зачем нужно перебазировать? Почему не добавляются файлы путем внесения изменений в корневую фиксацию? - person Geremia; 01.10.2019
comment
@Geremia Вы можете изменить только последний коммит, поэтому, если ваш репозиторий содержит только корневой коммит, он может работать, в противном случае вам все равно придется перебазировать все другие коммиты в репо поверх измененного корневого коммита. Но даже в этом случае тема подразумевает, что вы не хотите изменять корневой коммит, а вместо этого хотите вставить другой перед существующим корневым. - person user; 02.10.2019
comment
@user спасибо. Я не знал, что изменение работает только с последней фиксацией. - person Geremia; 03.10.2019
comment
Как ни странно, у меня возникли конфликты перебазирования с использованием любого из подходов. - person tartaruga_casco_mole; 04.04.2020
comment
@tartaruga_casco_mole: Попробуйте метод перезаписи истории, который я только что добавил. - person Aristotle Pagaltzis; 05.04.2020
comment
Каждая фиксация в мастере теперь имеет новый хэш после следования пути перезаписи истории. Если это ожидается (почему?), Давайте прямо укажем на это в ответе. - person Corio; 14.09.2020
comment
Добавление пустой одиночной фиксации работает нормально. Но вариант перезаписи истории, похоже, дублирует все коммиты, я получаю одну правильную главную ветвь и вторую ветку, как и главную ветку, но помеченную (refs / original / refs / Head / master) на листе и (замененную) рядом с дубликат оригинального коммита. Опция rebase отлично работала в моем репозитории для тестов, но теперь, когда я запустил ее в своем реальном репо, похоже, что на это уйдет много времени. Изменить: видел stackoverflow.com/a/30558271/3720673, как удалять дубликаты. Может быть, добавлю это к своему ответу. - person Nobody; 02.10.2020

Слияние ответов Аристотеля Пагальциса и Уве Кляйне-Кенига и комментария Ричарда Броноски.

git symbolic-ref HEAD refs/heads/newroot
git rm --cached -r .
git clean -f -d
# touch .gitignore && git add .gitignore # if necessary
git commit --allow-empty -m 'initial'
git rebase --onto newroot --root master
git branch -d newroot

(просто чтобы собрать все в одном месте)

person Antony Hatchkins    schedule 16.03.2012
comment
Это отлично. Было бы неплохо, если бы это могло быть то, что git rebase -i --root сделал внутри. - person aredridel; 08.07.2012
comment
Да, я был удивлен, узнав, что это не так. - person Antony Hatchkins; 09.07.2012
comment
Мне пришлось изменить команду rebase на git rebase newroot master из-за ошибки. - person marbel82; 25.07.2019
comment
@ antony-hatchkins благодарит за это. У меня есть репозиторий git, и (по разным причинам, о которых я не буду здесь рассказывать) я пытаюсь добавить NON-EMPTY git commit в качестве своего первого коммита. Поэтому я заменил git commit --allow-empty -m 'initial' на git add .; git commit -m начальная фиксация laravel; git push; И затем этот шаг перебазирования: git rebase --onto newroot --root master терпит неудачу из-за ТОННЫ конфликтов слияния. Любой совет? : (( - person kp123; 31.12.2019
comment
@ kp123 попробуйте пустую фиксацию :) - person Antony Hatchkins; 31.12.2019

Мне нравится ответ Аристотеля. Но обнаружено, что для большого репозитория (> 5000 коммитов) filter-branch работает лучше, чем rebase по нескольким причинам: 1) он быстрее 2) не требует вмешательства человека при конфликте слияния. 3) может переписывать теги - сохраняя их. Обратите внимание, что filter-branch работает, потому что нет вопросов о содержимом каждого коммита - оно точно такое же, как и до этого «перебазирования».

Мои шаги:

# first you need a new empty branch; let's call it `newroot`
git symbolic-ref HEAD refs/heads/newroot
git rm --cached -r .
git clean -f -d

# then you apply the same steps
git commit --allow-empty -m 'root commit'

# then use filter-branch to rebase everything on newroot
git filter-branch --parent-filter 'sed "s/^\$/-p <sha of newroot>/"' --tag-name-filter cat master

Обратите внимание, что опция '--tag-name-filter cat' означает, что теги будут переписаны, чтобы указывать на вновь созданные коммиты.

person Kent    schedule 29.03.2013
comment
Это не помогает создавать непустые коммиты, что также является интересным вариантом использования. - person ceztko; 22.04.2015
comment
По сравнению с другими решениями у вашего есть только один незначительный побочный эффект: он меняет хеши, но вся история остается нетронутой. Спасибо! - person Vladyslav Savchenko; 08.11.2016

Я думаю, что использование git replace и git filter-branch - лучшее решение, чем использование git rebase:

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

Идея заключается в следующем:

  1. Создать новую пустую фиксацию в далеком прошлом
  2. Замените старую корневую фиксацию на фиксацию точно так же, за исключением того, что новая корневая фиксация добавляется как родительская.
  3. Убедитесь, что все в порядке, и запустите git filter-branch
  4. Еще раз убедитесь, что все в порядке, и очистите ненужные файлы git.

Вот сценарий для первых двух шагов:

#!/bin/bash
root_commit_sha=$(git rev-list --max-parents=0 HEAD)
git checkout --force --orphan new-root
find . -path ./.git -prune -o -exec rm -rf {} \; 2> /dev/null
git add -A
GIT_COMMITTER_DATE="2000-01-01T12:00:00" git commit --date==2000-01-01T12:00:00 --allow-empty -m "empty root commit"
new_root_commit_sha=$(git rev-parse HEAD)

echo "The commit '$new_root_commit_sha' will be added before existing root commit '$root_commit_sha'..."

parent="parent $new_root_commit_sha"
replacement_commit=$(
 git cat-file commit $root_commit_sha | sed "s/author/$parent\nauthor/" |
 git hash-object -t commit -w --stdin
) || return 3
git replace "$root_commit_sha" "$replacement_commit"

Вы можете запустить этот сценарий без риска (даже если сделать резервную копию перед выполнением действий, которых вы никогда раньше не делали, это хорошая идея;)), и если результат не тот, который ожидался, просто удалите файлы, созданные в папке .git/refs/replace, и повторите попытку. ;)

Убедившись, что состояние репозитория соответствует вашим ожиданиям, выполните следующую команду, чтобы обновить историю всех ветвей:

git filter-branch -- --all

Теперь вы должны увидеть 2 истории, старую и новую (дополнительную информацию см. В справке на filter-branch). Вы можете сравнить 2 и снова проверить, все ли в порядке. Если вас устраивает, удалите ненужные файлы:

rm -rf ./.git/refs/original
rm -rf ./.git/refs/replace

Вы можете вернуться в свою ветку master и удалить временную ветку:

git checkout master
git branch -D new-root

Теперь все должно быть сделано;)

person Philippe    schedule 31.05.2015

Я успешно использовал части ответа Аристотеля и Кента:

# first you need a new empty branch; let's call it `newroot`
git checkout --orphan newroot
git rm -rf .
git commit --allow-empty -m 'root commit'
git filter-branch --parent-filter \
'sed "s/^\$/-p <sha of newroot>/"' --tag-name-filter cat -- --all
# clean up
git checkout master
git branch -D newroot
# make sure your branches are OK first before this...
git for-each-ref --format="%(refname)" refs/original/ | \
xargs -n 1 git update-ref -d

Это также перезапишет все ветки (не только master) в дополнение к тегам.

person ldav1s    schedule 17.04.2014
comment
что делает эта последняя строчка? - person Diederick C. Niehorster; 11.05.2016
comment
Он просматривает refs/original/ и удаляет все ссылки. На удаляемые им ссылки уже должна быть ссылка в какой-то другой ветке, поэтому они не исчезают, просто удаляется refs/original/. - person ldav1s; 11.05.2016
comment
Это сработало для меня. Кроме того, я использовал timedatectl set-time '2017-01-01 00:00:00', чтобы присвоить newroot старую метку времени. - person chrm; 14.05.2017

Чтобы добавить пустую фиксацию в начало репозитория, если вы забыли создать пустую фиксацию сразу после "git init":

git rebase --root --onto $(git commit-tree -m 'Initial commit (empty)' 4b825dc642cb6eb9a060e54bf8d69288fbee4904)
person Rory    schedule 09.12.2017
comment
4b825dc ... это хеш пустого дерева: stackoverflow.com/questions/9765453/ - person mrks; 08.05.2020

git rebase --root --onto $emptyrootcommit

должно с легкостью справиться с задачей

person Uwe Kleine-König    schedule 17.01.2011
comment
$emptyrootcommit - это переменная оболочки, которая, конечно, не расширяется до нуля? - person Flimm; 05.10.2016
comment
@Flimm: $ emptyrootcommit - это sha1 пустой фиксации, которая, похоже, уже есть на исходном плакате. - person Uwe Kleine-König; 30.07.2018

Я был в восторге и написал «идемпотентную» версию этого красивого скрипта ... он всегда будет вставлять один и тот же пустой коммит, и если вы запустите его дважды, он не изменит хэши ваших коммитов каждый раз. Итак, вот мой взгляд на git-insert-empty-root:

#!/bin/sh -ev
# idempotence achieved!
tmp_branch=__tmp_empty_root
git symbolic-ref HEAD refs/heads/$tmp_branch
git rm --cached -r . || true
git clean -f -d
touch -d '1970-01-01 UTC' .
GIT_COMMITTER_DATE='1970-01-01T00:00:00 +0000' git commit \
  --date='1970-01-01T00:00:00 +0000' --allow-empty -m 'initial'
git rebase --committer-date-is-author-date --onto $tmp_branch --root master
git branch -d $tmp_branch

Стоит ли лишняя сложность? может и нет, но я воспользуюсь этим.

Это ДОЛЖНО также позволить выполнить эту операцию с несколькими клонированными копиями репо и получить те же результаты, поэтому они все еще совместимы ... тестирование ... да, работает, но также необходимо удалить и добавить свой снова пульты, например:

git remote rm origin
git remote add --track master user@host:path/to/repo
person Sam Watkins    schedule 06.02.2013

Чтобы переключить корневую фиксацию:

Сначала создайте фиксацию, которую хотите первым.

Во-вторых, измените порядок коммитов, используя:

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

person tigre200    schedule 18.02.2017
comment
Теперь, когда у rebase есть --root, это, безусловно, лучшее решение. - person Ross Burton; 20.04.2020
comment
Хотел бы я прочитать дальше по странице, чтобы увидеть это в первый раз. Отличный ответ! - person Subfuzion; 23.04.2021

Что ж, вот что я придумал:

# Just setting variables on top for clarity.
# Set this to the path to your original repository.
ORIGINAL_REPO=/path/to/original/repository

# Create a new repository…
mkdir fun
cd fun
git init
# …and add an initial empty commit to it
git commit --allow-empty -m "The first evil."

# Add the original repository as a remote
git remote add previous $ORIGINAL_REPO
git fetch previous

# Get the hash for the first commit in the original repository
FIRST=`git log previous/master --pretty=format:%H  --reverse | head -1`
# Cherry-pick it
git cherry-pick $FIRST
# Then rebase the remainder of the original branch on top of the newly 
# cherry-picked, previously first commit, which is happily the second 
# on this branch, right after the empty one.
git rebase --onto master master previous/master

# rebase --onto leaves your head detached, I don't really know why)
# So now you overwrite your master branch with the newly rebased tree.
# You're now kinda done.
git branch -f master
git checkout master
# But do clean up: remove the remote, you don't need it anymore
git remote rm previous
person kch    schedule 14.03.2009

Вот мой bash сценарий, основанный на ответе Кента с улучшениями:

  • по завершении он проверяет исходную ветвь, а не только master;
  • Я пытался избежать временной ветки, но git checkout --orphan работает только с ветвью, а не с состоянием с отсоединенной головкой, поэтому она проверяется достаточно долго, чтобы сделать новую корневую фиксацию, а затем удалить;
  • он использует хэш нового корневого коммита во время filter-branch (Кент оставил там заполнитель для ручной замены);
  • операция filter-branch перезаписывает только локальные ветки, но не удаленные
  • метаданные автора и коммиттера стандартизированы, поэтому корневой коммит во всех репозиториях идентичен.

#!/bin/bash

# Save the current branch so we can check it out again later
INITIAL_BRANCH=`git symbolic-ref --short HEAD`
TEMP_BRANCH='newroot'

# Create a new temporary branch at a new root, and remove everything from the tree
git checkout --orphan "$TEMP_BRANCH"
git rm -rf .

# Commit this empty state with generic metadata that will not change - this should result in the same commit hash every time
export GIT_AUTHOR_NAME='nobody'
export GIT_AUTHOR_EMAIL='[email protected]'
export GIT_AUTHOR_DATE='2000-01-01T00:00:00+0000'
export GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"
export GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"
export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
git commit --allow-empty -m 'empty root'
NEWROOT=`git rev-parse HEAD`

# Check out the commit we just made and delete the temporary branch
git checkout --detach "$NEWROOT"
git branch -D "$TEMP_BRANCH"

# Rewrite all the local branches to insert the new root commit, delete the 
# original/* branches left behind, and check out the rewritten initial branch
git filter-branch --parent-filter "sed \"s/^\$/-p $NEWROOT/\"" --tag-name-filter cat -- --branches
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git checkout "$INITIAL_BRANCH"
person luxagen    schedule 07.05.2015

Сочетание новейшего и лучшего. Никаких побочных эффектов, никаких конфликтов, сохранение тегов.

git log --reverse

tree=`git hash-object -wt tree --stdin < /dev/null`
commit=`git commit-tree -m 'Initialize empty repository' $tree`
echo $commit # copy below, interpolation didn't work for me

git filter-branch --parent-filter 'sed "s/^\$/-p <commit>/"' --tag-name-filter cat master

git log --reverse

Обратите внимание, что на GitHub вы потеряете данные запуска CI, и PR может испортиться, если другие ветки также не будут исправлены.

person thisismydesign    schedule 12.09.2019

После ответа Аристотеля Пагальциса и других, но с использованием более простых команд

zsh% git checkout --orphan empty     
Switched to a new branch 'empty'
zsh% git rm --cached -r .
zsh% git clean -fdx
zsh% git commit --allow-empty -m 'initial empty commit'
[empty (root-commit) 64ea894] initial empty commit
zsh% git checkout master
Switched to branch 'master'
zsh% git rebase empty
First, rewinding head to replay your work on top of it...
zsh% git branch -d empty 
Deleted branch empty (was 64ea894).

Обратите внимание, что ваше репо не должно содержать никаких локальных изменений, ожидающих фиксации.
Я полагаю, что git checkout --orphan будет работать в новых версиях git.
Обратите внимание, что в большинстве случаев git status дает полезные подсказки.

person ony    schedule 18.02.2013

Запустить новый репозиторий.

Установите дату обратно на желаемую дату начала.

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

Когда дойдете до сегодняшнего дня, поменяйте местами репозитории, и все готово.

Если вы просто сумасшедший (авторитетный), но достаточно умен (вероятно, потому, что вам нужно иметь определенное количество ума, чтобы придумывать такие сумасшедшие идеи), вы запишете процесс.

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

person MarkusQ    schedule 14.03.2009
comment
Я плохо отношусь к решению, которое требует от вас возиться с системной датой, но вы дали мне идею, которую я немного развил, и, увы, она сработала. Тогда спасибо. - person kch; 14.03.2009

Я знаю, что этот пост старый, но эта страница - первая, когда гуглил "вставка фиксации git".

Зачем усложнять простые вещи?

У вас есть A-B-C, и вы хотите AB-Z-C.

  1. git rebase -i trunk (или что-нибудь до B)
  2. изменить выбор для редактирования в строке B
  3. внесите изменения: git add ..
  4. git commit (git commit --amend, который будет редактировать B, а не создавать Z)

[Вы можете сделать столько git commit, сколько хотите, чтобы вставить больше коммитов. Конечно, у вас могут возникнуть проблемы с шагом 5, но разрешение конфликта слияния с помощью git - это навык, которым вы должны обладать. Если нет, практикуйтесь!]

  1. git rebase --continue

Просто, не правда ли?

Если вы понимаете git rebase, добавление «корневого» коммита не должно быть проблемой.

Удачи с git!

person Alex    schedule 27.06.2011
comment
Вопрос касается вставки первого коммита: от A-B-C вы хотите Z-A-B-C. Прямолинейный git rebase не может этого сделать. - person Petr Viktorin; 30.06.2011