Сквош первые два коммита в Git? [дубликат]
этот вопрос уже есть ответ здесь:
С git rebase --interactive <commit>
вы можете раздавить любое количество коммитов вместе в один.
Это все здорово, если вы не хотите раздавить коммиты в начальный коммит. Это кажется невозможным делать.
есть ли способы этого добиться?
умеренно, связанных с:
в связанном вопросе мне удалось придумать другой подход к необходимости раздавливания против первого коммита, который, ну, чтобы сделать его вторым.
Если вам интересно: git:как вставить фиксацию в качестве первого, переместив все остальные?
9 ответов:
Обновление Июль 2012 Года (git 1.7.12+)
теперь вы можете перебазировать все коммиты до root и выбрать второй коммит
Y
быть раздавленным первымX
.git rebase -i --root master pick sha1 X squash sha1 Y pick sha1 Z
git rebase [-i] --root $tip
эта команда теперь может быть использована для перезаписи всей истории, ведущей от "
$tip
" к корневой коммит.посмотреть commit df5df20c1308f936ea542c86df1e9c6974168472 на GitHub С Крис Уэбб (
arachsys
).
оригинальный ответ (февраль 2009 года)
я считаю, что вы найдете различные рецепты для этого в так вопрос"как я могу объединить первые два коммита в Git-репозиторий?"
Чарльз Бэйли при условии, что там больше всего подробный ответ!--25-->, напоминая нам, что фиксация является полным деревом (а не просто отличается от предыдущих состояний).
А тут старый комит ("начальная фиксация") и новая фиксация (результат раздавливания) не будут иметь общего предка.
Это означает, что вы не можете "commit --amend
" начальная фиксация в новую, а затем перебазировать на новую начальную фиксацию историю предыдущей начальной фиксации (много конфликтов)(это последнее предложение больше не верно с
git rebase -i --root <aBranch>
)а (с
A
исходная "начальная фиксация", иB
последующая фиксация должна быть раздавлена в первоначальный один):
вернитесь к последнему коммиту, который мы хотим сформировать начальный коммит (отсоединить голову):
git checkout <sha1_for_B>
сбросьте указатель ветви на начальную фиксацию, но оставьте индекс и рабочее дерево нетронутыми:
git reset --soft <sha1_for_A>
изменить начальное дерево, используя дерево из 'B':
git commit --amend
временно пометьте эту новую начальную фиксацию (или вы можете вспомнить новую зафиксировать 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
" (любое количество коммитов может быть раздавлено в начальный таким образом)
я переработал скрипт VonC, чтобы делать все автоматически и не просить меня ни о чем. Вы даете ему два коммита SHA1s, и он раздавит все между ними в один коммит под названием "раздавленная история":
#!/bin/sh # Go back to the last commit that we want # to form the initial commit (detach HEAD) git checkout # reset the branch pointer to the initial commit (= ), # but leaving the index and working tree intact. git reset --soft # amend the initial tree using the tree from 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 onto the new initial commit git rebase --onto $TARGET
для чего это стоит, я избегаю этой проблемы, всегда создавая первый коммит" no-op", в котором единственное, что в репозитории является пустым .пример:
https://github.com/DarwinAwardWinner/git-custom-commands/blob/master/bin/git-myinit
таким образом, никогда нет причин связываться с первым коммитом.
Если вы просто хотите раздавить все коммиты в один, начальный коммит, просто сбросьте репозиторий и измените первый коммит:
git reset hash-of-first-commit git add -A git commit --amend
git reset оставит рабочее дерево нетронутым, так что все еще там. Поэтому просто добавьте файлы с помощью команд git add и измените первую фиксацию с помощью этих изменений. По сравнению с rebase-i Вы потеряете возможность объединить комментарии git.
это раздавит второй коммит в первый:
A-B-C-... -> AB-C-...
git filter-branch --commit-filter ' if [ "$GIT_COMMIT" = <sha1ofA> ]; then skip_commit "$@"; else git commit-tree "$@"; fi ' HEAD
сообщение фиксации для AB будет взято из B (хотя я бы предпочел из A).
имеет тот же эффект, как ответить Уве Кляйн-Кениг, но работает не начальный, а также.
сжатие первой и второй фиксации приведет к перезаписи первой фиксации. Если у вас есть несколько ветвей, основанных на первом коммите, вы бы отрезали эту ветвь.
рассмотрим следующий пример:
a---b---HEAD \ \ '---d
сжатие a и b в новую фиксацию "ab" приведет к двум различным деревьям, которые в большинстве случаев нежелательны, так как git-merge и git-rebase больше не будет работать через два ветви.
ab---HEAD a---d
Если вы действительно хотите этого, это можно сделать. Взгляните на git-filter-branch для мощного (и опасного) инструмента для переписывания истории.
вы можете использовать git filter-branch для этого. например,
git filter-branch --parent-filter \ 'if test $GIT_COMMIT != <sha1ofB>; then cat; fi'
это приводит к тому, что AB-C выбрасывает журнал фиксации A.
вы можете использовать rebase interactive для изменения последних двух коммитов, прежде чем они будут отправлены на удаленный
git rebase HEAD^^ -i
есть более простой способ сделать это. Давайте предположим, что вы находитесь на
master
филиаласоздайте новую осиротевшую ветку, которая удалит всю историю фиксации:
$ git checkout --orphan new_branch
добавьте ваше начальное сообщение фиксации:
$ git commit -a
избавьтесь от старой несвязанной главной ветви:
$ git branch -D master
переименовать текущую ветку
new_branch
доmaster
:$ git branch -m master