Сквош первых двух коммитов в Git?
С помощью git rebase --interactive <commit>
вы можете сквоить любое количество коммитов вместе в один.
Это все здорово, если вы не хотите, чтобы сквош фиксировал первоначальную фиксацию. Это кажется невозможным.
Есть ли способы его достижения?
Умеренно связанные:
В связанном вопросе мне удалось придумать другой подход к необходимости раздавить первый коммит, который, кстати, сделает его вторым.
Если вам интересно: git: как вставить фиксацию в качестве первой, сдвигая все остальные?
Ответы
Ответ 1
Обновление Июль 2012 (git 1.7.12+)
Теперь вы можете переустановить все коммиты до корня и выбрать вторую фиксацию Y
для раздачи с первым X
.
git rebase -i --root master
pick sha1 X
squash sha1 Y
pick sha1 Z
git rebase [-i] --root $tip
Теперь эту команду можно использовать для перезаписи всей истории, ведущей от "$tip
" до корневой фиксации.
См. зафиксировать df5df20c1308f936ea542c86df1e9c6974168472 на GitHub из Chris Webb (arachsys
).
Оригинальный ответ (февраль 2009 г.)
Я верю, что вы найдете разные рецепты для этого в вопросе SO " Как объединить первые две записи репозитория git?"
Чарльз Бейли предоставил там подробный ответ, напоминая нам, что фиксация является полным деревом ( не просто отличается от предыдущих состояний).
И здесь старая фиксация ( "первоначальная фиксация" ) и новая фиксация (результат раздавливания) не будут иметь общего предка.
Это означает, что вы не можете "commit --amend
" первоначального коммита в новый, а затем переустановите на новый начальный фиксатор историю предыдущего первоначального коммита (много конфликтов)
(последнее предложение больше не верно с git rebase -i --root <aBranch>
)
Скорее (с A
исходным "первоначальным фиксацией" и B
последующее коммит необходимо передать в начальный):
-
Вернитесь к последнему фиксации, который мы хотим сформировать для первоначальной фиксации (отсоединить HEAD):
git checkout <sha1_for_B>
-
Reset указатель ветвления на начальную фиксацию, но оставив индекс и рабочее дерево целыми:
git reset --soft <sha1_for_A>
-
Изменить исходное дерево, используя дерево из 'B':
git commit --amend
-
Временно пометьте эту новую начальную фиксацию (или вы можете помнить новую команду commit sha1 вручную):
git tag tmp
-
Вернитесь к исходной ветке (возьмите мастер для этого примера):
git checkout master
-
Повторить все коммиты после B на новый начальный коммит:
git rebase --onto tmp <sha1_for_B>
-
Удалить временный тег:
git tag -d tmp
Таким образом, "rebase --onto
" не вводит конфликты во время слияния, так как он переустанавливает историю, сделанную после последнего фиксации (B
), чтобы быть сжатой в начальную (которая была A
) до tmp
(представляющий сжатый новый начальный коммит): тривиальная перемотка вперед просто сливается.
Это работает для "A-B
", но также "A-...-...-...-B
" (любое количество коммитов может быть сжато в исходное таким образом)
Ответ 2
Я переработал VonC script, чтобы делать все автоматически и не спрашивать меня ни о чем. Вы даете ему два commit SHA1, и он будет раздавить все между ними в одно сообщение с именем "squashed history":
#!/bin/sh
# Go back to the last commit that we want
# to form the initial commit (detach HEAD)
git checkout $2
# reset the branch pointer to the initial commit (= $1),
# but leaving the index and working tree intact.
git reset --soft $1
# amend the initial tree using the tree from $2
git commit --amend -m "squashed history"
# remember the new commit sha1
TARGET=`git rev-list HEAD --max-count=1`
# go back to the original branch (assume master for this example)
git checkout master
# Replay all the commits after $2 onto the new initial commit
git rebase --onto $TARGET $2
Ответ 3
Для чего это стоит, я избегаю этой проблемы, всегда создавая первую команду "no-op", в которой единственное, что в репозитории - это пустой .gitignore:
https://github.com/DarwinAwardWinner/git-custom-commands/blob/master/bin/git-myinit
Таким образом, никогда не было причин вмешиваться в первую фиксацию.
Ответ 4
Это приведет к второму фиксации в первом:
A-B-C-... -> AB-C-...
git filter-branch --commit-filter '
if [ "$GIT_COMMIT" = <sha1ofA> ];
then
skip_commit "[email protected]";
else
git commit-tree "[email protected]";
fi
' HEAD
Сообщение об ошибке для AB будет взято из B (хотя я бы предпочел бы от A).
Имеет тот же эффект, что и Uwe Kleine-König, но работает и для не начального A.
Ответ 5
Если вы просто хотите выкопать все коммиты в единую начальную фиксацию, просто reset репозиторий и изменить первый фиксатор:
git reset hash-of-first-commit
git add -A
git commit --amend
Git reset оставит рабочее дерево неповрежденным, поэтому все еще есть. Поэтому просто добавьте файлы, используя команды git add, и внесите изменения в первый коммит с этими изменениями. По сравнению с rebase -i вы потеряете возможность объединить комментарии git.
Ответ 6
Сжатие первой и второй фиксации приведет к перезаписи первого коммита. Если у вас несколько ветвей, основанных на первом фиксации, вы отключили бы эту ветвь.
Рассмотрим следующий пример:
a---b---HEAD
\
\
'---d
Скручивание a и b в новую фиксацию "ab" приведет к двум различным деревьям, которые в большинстве случаев нежелательны, поскольку git -merge и git -rebase больше не будет работать через две ветки.
ab---HEAD
a---d
Если вы действительно этого хотите, это можно сделать. Посмотрите git -фильтр-ветвь для мощного (и опасного) инструмента для перезаписи истории.
Ответ 7
Для этого можно использовать ветвь фильтра git. например.
git filter-branch --parent-filter \
'if test $GIT_COMMIT != <sha1ofB>; then cat; fi'
Это приводит к тому, что AB-C отбрасывает журнал фиксации A.
Ответ 8
Вы можете использовать rebase interactive для изменения последних двух коммитов, прежде чем они будут перенесены на удаленный
git rebase HEAD^^ -i
Ответ 9
Существует более простой способ сделать это. Предположим, что вы находитесь на ветке master
Создайте новую сироту, которая удалит всю историю фиксации:
$ git checkout --orphan new_branch
Добавьте свое начальное сообщение об ошибке:
$ git commit -a
Избавьтесь от старой несвязанной ветки мастера:
$ git branch -D master
Переименуйте текущую ветку new_branch
в master
:
$ git branch -m master