Как превратить набор исправленных коммитов (сохраненных в reflog) в реальные коммиты
Я занимался рефакторингом и просто продолжал вносить поправки каждый раз, когда добивался приличного прогресса. Все прошло очень хорошо, и я понял, что было бы неплохо показать людям, как я справился с таким огромным рефакторингом (множество маленьких шагов, просто подталкивание кода, с зеленым набором тестов в каждой точке).
Коммиты все в моем рефлоге. Есть ли способ превратить каждый из этих исправленных коммитов в свой реальный коммит (извините, не знаю терминологию), чтобы пользователи могли видеть каждый шаг, а не только агрегированные, в строках 81 и 57? Мне не нужны уникальные сообщения для коммитов или чего-то еще, просто они запечатлены в истории.
Это все еще в моем местном репо.
3 ответа
Восстановление reflog может быть не таким сложным, как кажется на первый взгляд. Вы можете регенерировать коммиты reflog в разные ветки, или вы можете использовать git read-tree
генерировать один newbranch
содержащий часть рефлога.
Одно решение для каждой ветви:
Предположим, вы хотели разные ветви для каждого коммита. Сначала скопируйте ваш репозиторий. Вы собираетесь изменить ваш reflog в этом процессе, так что вы могли бы также использовать одноразовую версию. Во-вторых, изучите ваш reflog и найдите коммит, с которого вы хотите начать. Это будет выглядеть как HEAD@{n}
, Предположим, это было HEAD@{49}
, Затем попробуйте этот скрипт, заменив head -50
с head -<n + 1>
Что бы это ни было в вашем случае:
#!/bin/sh
reflog=$(git reflog | head -50 | awk '{ print $1 }')
i=0
for ref in $reflog; do
git checkout -B "reflog_$i" $ref
i=$(expr $i + 1)
done
Это захватывает историю коммитов вашего reflog один раз, затем перебирает ее, генерируя reflog_$i
ветви по пути. Вы можете выбирать, объединять или манипулировать ими, как хотите. Если это просто для презентации, вы можете написать короткий скрипт, который выполняет git checkout
в ветках запускает набор тестов и показывает зелень весь путь. Помните, reflog_1
представляет самую актуальную историю; reflog_<n+1>
Старейший.
#!/bin/sh
for i in $(seq 50 1); do
git checkout "reflog_$i"
./test-suite.sh
done
Бросьте его на проектор, пока вы объясняете свой метод коммита, и это будет хорошим фоном.
Если вы хотите объединить все ветви, вы можете запустить этот скрипт ruby, чтобы применить их по порядку (или создать эквивалент на любом удобном для вас языке). Позвольте мне повторить, что вы должны сделать резервную копию своего каталога, потому что это довольно разрушительно.
#!/usr/bin/env ruby
n = 50
n.downto 0 do |i|
system "
git read-tree reflog_#{i}
git commit -m 'Refactoring #{n - i}'
git checkout -- .
git br -D refog_#{i}
"
end
Помещение всех коммитов в одну ветку с помощьюgit read-tree
Сначала скопируйте ваш репозиторий. Затем используйте скрипт, подобный приведенному ниже. Согласно обсуждению в первом решении, измените два <n + 1>
на любую глубину, которую вы хотите в вашем журнале, плюс один. Обратите внимание на дополнительную трубу для sed
, Вы должны использовать его или что-то вроде этого, чтобы reflog не применялся к newbranch
в обратном хронологическом порядке. Конечно, есть способ сделать это, не используя оба awk
а также sed
, но это работает:
#!/bin/sh
reflog=$(git reflog | head -<n + 1> | awk '{ print $1 }' | sed -n '1!G;h;$p')
git checkout -B newbranch HEAD@{<n + 1>}
for ref in $reflog; do
git read-tree "$ref"
git commit --no-verify -m "Adding commit $ref"
git checkout -- .
done
Окончательный результат будет newbranch
, который должен содержать все коммиты между HEAD@{0}
а также HEAD@{n}
на основе коммита HEAD@{n+1}
,
Это возможно, но, вероятно, сложно.
Каждый раз, когда вы сделали --amend
Вы, по сути, "выбросили" предыдущий коммит и заменили его новым измененным коммитом, который содержит предыдущие изменения плюс все, что было изменено.
Так:
A<--B (master)
Теперь передайте --amend:
---B
/
A<--C (master)
Теперь передайте --amend снова:
--B
/
A<--D (master)
\
--C
Коммиты B и C все еще существуют. Тем не менее, они ни на что не указывают и в конечном итоге будут собирать мусор.
Итак, чтобы получить график, который вы хотите:
git checkout master
git reset --hard A
git cherry-pick B
git cherry-pick C
git cherry-pick D
Листья:
A<--B'<--C'<--D' (master)
(Обратите внимание на простой символ (апостроф) - это новые коммиты с новыми хэшами)
Теперь я не уверен, есть ли у вас конфликты. Я полагаю, что так и будет, поскольку каждый из последующих коммитов содержит некоторые из тех же изменений, что и предыдущие коммиты, учитывая, что в них были внесены изменения. Если это так, вам придется решить их.
Имейте в виду, учитывая то, как работает git, если вы попробуете это, а это не сработает, вернуться туда, где вы сейчас находитесь, очень просто:
git reset --hard D
Вы можете создать новую ветвь из первой записи reflog, а затем для каждой записи reflog git оформить дерево для рабочей области и затем зафиксировать его.
Таким образом, вы не должны получать никаких конфликтов, потому что вы, по сути, переписываете дерево рабочей области только с новым деревом reflog.