Git - Сквош все коммиты в истории перед конкретным коммитом - PullRequest
0 голосов
/ 03 декабря 2018

У меня есть репозиторий Mercurial, который я конвертирую в Git.История коммитов достаточно велика, и мне не нужна вся история коммитов в новом репо.Как только я преобразую историю коммитов в Git (и перед тем, как перейти к новому репо), я хочу сжать все коммиты перед определенным тегом в один коммит.

Итак, если у меня есть:

commit 6
commit 5
commit 4
commit 3
commit 2
commit 1 -- First commit ever

Я хочу закончить с:

commit 6
commit 5
commit X -- squashed 1, 2, 3, 4

Примечание: Есть тысячи коммитов, которые мне нужно раздавить.Таким образом, ручная выборка / маркировка их по одному не возможна.

Ответы [ 3 ]

0 голосов
/ 03 декабря 2018

Предположим, что исходная ветвь master , а новая ветвь new .

git checkout --orphan new commit4
git commit -m "squash commits"
git branch tmp master
git rebase commit4 tmp --onto new
git checkout new
git merge tmp
git branch -D tmp

Опция "-p" необходима в "git rebase""если вы хотите сохранить коммиты слияния.

0 голосов
/ 03 декабря 2018

Другие ответы на данный момент предполагают перебазирование.Эта может работать, в некоторых случаях, в зависимости от графика фиксации в хранилище, преобразованном в Git.Новый фанатский ребаз с --rebase-merges определенно может это сделать.Но это немного неуклюжий способ сделать это.Идеальный способ сделать это - конвертировать коммиты , начиная с первого, который вы хотите сохранить. То есть экспорт вашего Mercurial экспортируется в Git, как первый коммит Git, ревизияВы хотите притвориться, это корень.Попросите экспортера Mercurial экспортировать потомков этого коммита, по одному в импортер, точно так же, как экспортер всегда собирался выполнять эту работу (каким бы образом это ни было).

Будь икак вы сможете сделать это, зависит от того, какие инструменты вы используете для конвертации.(На самом деле я не делал ни одного из этих преобразований, но большинство людей, похоже, используют hg-fast-export и git fast-import. Я не особо рассматривал внутренние детали hg-fast-export, но нет очевидной причины, по которой не смог сделать это.)


По сути (внутренне), хранилища Mercurial фиксируются как наборы изменений.Это не случай для Git: Git хранит снимки вместо этого.Однако Mercurial извлекает (т.е. извлекает) снимки, суммируя вместе наборы изменений, как требуется, поэтому, если ваш инструмент работает, выполняя hg checkout (или его внутренний эквивалент), здесь нет проблемпервое место: вы просто избегаете проверять ревизии перед первым желаемым снимком и импортируете их в Git, и итоговая история Git начинается в нужной точке.


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

          o-..-o            o--o   <-- br1
         /      \          /
...--o--o--....--o--*--o--o--o--o   <-- br2
      \         /             \
       o--...--o               o   <-- master

, где commit * - это первый коммит, который вы хотели увидеть в своем хранилище Git.(Обратите внимание, что если есть несколько историй, возвращающихся до *, у вас есть другая проблема, и вы не можете выполнить этот вид преобразования в первую очередь без дополнительной модификации истории. Но пока * находится в некотором роде Choke Point , как и на этой диаграмме, здесь легко обрезать график.)

Чтобы удалить все до *, просто используйте git replace, чтобы сделать альтернативный коммит, который оченьочень , как commit *, но не имеет родителя:

git replace --graft <hash-of-*>

Теперь у вас есть замена, которую будет использовать большая часть Git вместо *, у которой нет родительского коммита.Затем запустите git filter-branch для всех веток и тегов с фильтром no-op:

git filter-branch --tag-name-filter cat -- --all

Это скопирует каждый достижимый коммит, включая замену *, но исключая * и его собственную историю, до новых коммитов, затем обновите ваши ветки и имена тегов.Удалите пространство имен refs/originals/ (подробности см. в документации git filter-branch ), принудительно заберите первоначальные объекты, если хотите (дополнительные коммиты со временем исчезнут сами по себе), и выготово.

0 голосов
/ 03 декабря 2018

Хотя git reset --soft может быть опцией для сжатия один набор коммитов ( как здесь ), я бы порекомендовал для нескольких наборов коммитов:

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

Обратите внимание, что это применимо к первому коммиту, через опцию git rebase --root .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...