Удалить родительский указатель ложной фиксации

Я импортировал репозиторий Bazaar в Git (используя git bzr), но результирующий репозиторий содержит родительскую ссылку spurious commit:

Spurious parent link

Обратите внимание, что тег фиксации 1.02-6 основан на фиксации 1.02-3, но 1.02-1 не обязательно также помечен как родитель. (Примечание: все коммиты в этой части репо отмечены, между показанными не происходит никаких коммитов.)

Я попытался перезагрузить несколько путей (в ветке master: git rebase 1.02-3, git rebase -i upstream-1.02, git rebase --onto 1.02-1 1.02-3, git rebase --root upstream-1.02 --onto=other_branch), но в каждом случае он терпит неудачу с конфликтом слиянием. Кажется, они пытаются сделать больше, чем это необходимо; история правильная, за исключением того, что дополнительный родительский указатель записывается в теге с фиксацией 1.02-6.

Как удалить ссылку, чтобы линеаризовать историю? Есть ли лучший способ, чем ручной вишневый выбор всех коммитов в последовательности?

Ответ 1

Вы можете сделать это вручную, используя внутреннюю команду git commit-tree.

Мы хотим отредактировать фиксацию тега 1.02-6, чтобы удалить ложный родительский указатель (до 56a2f3b5948ab54c9239c2b384a6ea9eb1f410c4).

Сначала прочитайте информацию из существующего объекта фиксации:

[email protected]:/path/repo.git$ git cat-file -p 1.02-6 
tree c658aa1ebcf2bf2a607696c7868b875be72fb01f
parent 56a2f3b5948ab54c9239c2b384a6ea9eb1f410c4
parent 4e671bf1d2298729c9e5cfd8229051cfe2c40831
author James Damour (Suvarov454) <[email protected]> 1146319620 -0400
committer Bazaar Package Importer <[email protected]> 1146319620 -0400

The "main/" in the Section line of debian/control should be assumed.

Извлеките сообщение фиксации с помощью git log --format=%B -n 1 1.02-6.

Теперь создайте новый коммит с тем же содержимым (исключая ложную родительскую ссылку и информацию коммиттера):

git log --format=%B -n 1 1.02-6 | \
    GIT_AUTHOR_NAME="James Damour (Suvarov454)" \
    GIT_AUTHOR_EMAIL="[email protected]" \
    GIT_AUTHOR_DATE="1146319620 -0400" \
    git commit-tree c658aa1ebcf2bf2a607696c7868b875be72fb01f \
        -p 4e671bf1d2298729c9e5cfd8229051cfe2c40831

Это создало новую фиксацию и напечатало ее хэш (cc32e66...). Теперь включите его в новую ветку:

git checkout -b fixed_commit cc32e66

и rebase master на новую ветку:

git checkout master
git rebase fixed_commit

И все готово:

Finished

Вероятно, вы захотите удалить старые ветки и повторно пометить соответствующие коммиты.


На самом деле было бы проще использовать git filter-branch --parent-filter. Я этого не пробовал.

Ответ 2

Самый простой способ сделать это (в git> = 1.6.5) - использовать:

git replace --edit <sha>

и удалите/добавьте/измените Parent: строки.

Как только вы довольны, что изменения верны, вы можете переписать коммиты, чтобы сделать изменение постоянным:

git filter-branch --tag-name-filter cat -- <parent sha>..head

Ответ 3

Это исправит родителей, не изменив ничего (например, даты коммиттера):

git filter-branch --tag-name-filter cat --parent-filter 'test $GIT_COMMIT = [sha of 1.02-6] && echo "-p [sha of 1.02-3]" || cat' -- 1.02-1..master

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

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

Ответ 4

Вы можете попробовать rebase. Есть пример немного вниз (поиск --onto), который, я думаю, похож на ваш случай.

Думаю, вам нужно сделать

git rebase --onto 1.02-1 1.02-3

который должен поместить все после 1.02-3 на 1.02-1, и это, вероятно, то, что вы хотите.

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