Как собрать коммиты из 2-х разных локальных репозиториев в последовательную историю?

Есть 2 локальных репозитория (one, two) с изменениями одного и того же файла.

Я делаю
cd one/
git remote add second ~/git_tests/two
git checkout --orphan second
git pull second second # во второй репе ветка называется second
git switch master
git merge second --allow-unrelated-histories
# решаю конфликты

git log --oneline --graph
# получаю

*   fd37a7e (HEAD -> second, master) Merge branch 'second'
|\  
| * bcf6d21 (second/second) fourth, "three"
| * 0f6a3f0 third, "two"
* d5c58d8 second, "two"
* fcc376b first, "one"


# а хочу добиться

*   fd37a7e (HEAD -> second, master) Merge branch 'second'
|\  
| * bcf6d21 (second/second) fourth, "three"
| * 0f6a3f0 third, "two"
|/
* d5c58d8 second, "two"
* fcc376b first, "one"


То есть я хочу указать у коммита 0f6a3f0 родительским коммитом d5c58d8
Как мне это сделать?
  • Вопрос задан
  • 1004 просмотра
Решения вопроса 2
sergey-kuznetsov
@sergey-kuznetsov Куратор тега Git
Автоматизатор
git checkout --orphan second
git pull second second # во второй репе ветка называется second
git switch master
git merge second --allow-unrelated-histories
# решаю конфликты

Эти манипуляции можно заменить одной командой
git pull second second --allow-unrelated-histories
Результат будет идентичный.

хочу указать у коммита 0f6a3f0 родительским коммитом d5c58d8

Коммиты в гите неизменяемы. Если изначально родителя не было, то вы не прицепите его постфактум. Но вы можете пересадить ветку second на вершину master, пересобрав коммиты заново.

Чтобы получить что вам хочется, следует действовать иначе:
git fetch second # скачать все коммиты из второго репо
git switch second # перейти в ветку second
git rebase master # пересобрать ветку second с вершины ветки master
  dropping 0f6a3f0 third, "two" -- patch contents already upstream
  Successfully rebased and updated refs/heads/second.
git switch master # вернуться в master
git merge second --no-ff # влить second в master

Получим:
git log --oneline --graph
*   13dddb5 (HEAD -> master) Merge branch 'second'
|\
| * 515f80e (second) fourth, "three"
|/
* d5c58d8 second, "two"
* fcc376b first, "one"

Коммит third, "two" исчез из истории (дропнут) во время rebase, так как он полностью повторяет состояние second, "two"

Но если вам надо действительно последовательную историю, то не надо создавать коммит слияния. Не используйте ключ --no-ff в последней команде. Это просто установит указатель master на вершину.
И получится линейная история
git log --oneline --graph
* 515f80e (HEAD -> master, second) fourth, "three"
* d5c58d8 second, "two"
* fcc376b first, "one"
Ответ написан
@andmerk93 Автор вопроса
Ответ ниже от Сергей Кузнецов, я его немного исправил.

Коммиты в гите неизменяемы. Если изначально родителя не было, то вы не прицепите его постфактум. Но вы можете пересадить ветку second на вершину master, пересобрав коммиты заново.

Чтобы получить что вам хочется, следует действовать иначе:
git fetch second  # скачать все коммиты из второго репо
git switch second # перейти в ветку second
git rebase master --committer-date-is-author-date 
# пересобрать ветку second с вершины ветки master
# с заменой даты создания коммита
# для удобного отображения в редакторах
  dropping 0f6a3f0 third, "two" -- patch contents already upstream
  Successfully rebased and updated refs/heads/second.
git switch master         # вернуться в master
git merge second --no-ff  # влить second в master


Получим:
git log --oneline --graph
*   13dddb5 (HEAD -> master) Merge branch 'second'
|\
| * 515f80e (second) fourth, "three"
|/
* d5c58d8 second, "two"
* fcc376b first, "one"


Коммит third, "two" исчез из истории (дропнут) во время rebase, так как он полностью повторяет состояние second, "two"

Но если вам надо действительно последовательную историю, то не надо создавать коммит слияния. Не используйте ключ --no-ff в последней команде. Это просто установит указатель master на вершину.
И получится линейная история
git log --oneline --graph
* 515f80e (HEAD -> master, second) fourth, "three"
* d5c58d8 second, "two"
* fcc376b first, "one"
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
Vapaamies
@Vapaamies
Психанул и снес свои ответы козлам, не отмечающим…
Обычный cherry-pick, не? Слияние (merge) сливает ветку изменений целиком, а тут речь именно про ручной отбор, то есть собирание истории вручную?
git switch master

git cherry-pick second~1
# разрешаем конфликты, если надо
git cherry-pick --continue # если были конфликты

git cherry-pick second
# аналогично с конфликтами и продолжением

Аналогичного результата можно было бы добиться и при помощи перебазирования second на master, но оно приведет к нужному результату только если нет этих самых unrelated histories, ибо при их наличии начнет перетаскивать историю от сотворения мира. Для двух коммитов ручной перенос — самый простой и употребительный вариант, поменяется только дата коммита.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы