git: применить изменения, внесенные фиксацией в одном репо, к другому репо

115

У меня кот repo1и repo2на локальной машине. Они очень похожи, но последняя - это какая-то другая ветка ( repo1больше не поддерживается).

/path/to/repo1 $ git log HEAD~5..HEAD~4
<some_sha> Add: Introduce feature X

Как применить изменения, сделанные фиксацией <some_sha>вrepo1 к repo2?

Мне нужно подготовить какой-то патч или можно сделать что-то cherry-pickмежду репозиториями?

Как насчет того же, но для диапазона коммитов?

takeshin
источник
2
Разве вы не можете просто перейти от репо1 к репо2?
zwol
для чуть более конкретного случая, когда вы хотите применить изменения к файлу или файлам, которые были перемещены в один из репозиториев, посмотрите здесь: stackoverflow.com/questions/3491270/…
Брахам Снайдер

Ответы:

31

В качестве взлома вы можете попробовать изменить рецепт для сравнения коммитов в двух разных репозиториях на странице GitTips , то есть:

GIT_ALTERNATE_OBJECT_DIRECTORIES=../repo/.git/objects \
git cherry-pick $(git --git-dir=../repo/.git rev-parse --verify <commit>)

где ../repoпуть к другому репозиторию.

В современном Git вы можете использовать несколько ревизий и диапазонов ревизий с помощью Cherry-Pick .

$(git --git-dir=../repo/.git rev-parse --verify <commit>) Здесь , чтобы перевести <commit>(например HEAD, или v0.2, илиmaster~2 , которые являются значениями во втором хранилище скопированного с) в SHA-1 идентификатор фиксации. Если вам известен SHA-1 изменения, которое вы хотите выбрать, в этом нет необходимости.

Обратите внимание, однако, что Git может пропускать копирование объектов из исходного репозитория, поскольку он не знает, что альтернативный репозиторий объектов является временным для одной операции. Возможно, вам потребуется скопировать объекты из второго репозитория с помощью:

GIT_ALTERNATE_OBJECT_DIRECTORIES=../repo/.git/objects git repack -a -d -f

Это помещает объекты, заимствованные из второго репозитория, в исходное хранилище репозитория.

Не проверено.


Не такое уж хитрое решение - следовать ответу knittl :

  • Перейдите во второй репозиторий, из которого вы хотите скопировать коммиты, и сгенерируйте патчи из нужных коммитов с помощью git format-patch
  • При желании скопируйте патчи (0001- * и т. Д.) В свой репозиторий.
  • Используйте git am --3wayдля применения патчей
Якуб Наребски
источник
1
Хорошо работает. Если у вас возникли проблемы с фиксацией, выполните 'git reset HEAD; git add. '.
gumik
5
это круто - как бы вы сделали ряд коммитов? просто ша1 ... ша2?
hvgotcodes 06
Я тоже получаю, fatal: unable to read tree ...но после того, как git reset HEAD^все работает нормально
jmarceli
@hvgotcodes, это сработало для меня, просто передав диапазон, <commit>но rev-parse --verifyкоманде это не нравится, поскольку она принимает только одиночные значения фиксации. Но поскольку cherry-pickпринимает как одиночные, так и диапазонные значения фиксации, я спрашиваю: зачем это rev-parseнужно?
Chuim
1
@Chuim: git rev-parseнеобходимо , если вы хотите обратиться к фиксации его реф на основе имени в другом хранилище, например master, HEAD^^или что - то в этом роде; rev-parse превращает его в универсальный идентификатор SHA-1.
Якуб Наребски, 01
207

Вы, вероятно, захотите использовать, git format-patchа затем git amприменить этот патч к своему репозиторию.

/path/to/1 $ git format-patch sha1^..sha1
/path/to/1 $ cd /path/to/2
/path/to/2 $ git am -3 /path/to/1/0001-…-….patch

Или в одной строке:

/path/to/2 $ git --git-dir=/path/to/1/.git format-patch --stdout sha1^..sha1 | git am -3
knittl
источник
9
Это решение оказалось проще и безопаснее, чем принятый ответ с использованием прямого выбора вишни GIT_ALTERNATE_OBJECT_DIRECTORIES(это может повредить мой репозиторий).
Chuim
2
Когда возникают конфликты, это не сработает, потому что не удается найти коммиты в другой ветке.
Роджер Фар,
2
Добавление --ignore-whitespaceв git amкоманду может разрешить любые конфликты и избежать необходимости выполнять трехстороннее слияние
Хьюз
98

Вы можете сделать это, cherry-pickесли добавите второе репо в качестве удаленного к первому (а затем fetch).

wRAR
источник
11
На самом деле это правильный способ сделать это.
Wilbert
5
Для меня это тоже правильный путь. Я просто использовал его, и он мне очень понравился.
Рики Нельсон
11
Скорее скажу: делайте git fetch [remote-name]во втором репо, а потом git cherry-pick [sha1].
5
Этот подход отлично сработал для меня, спасибо. Поскольку второе репо также было локальным, просто нужно было использовать URI файла при добавлении его в качестве удаленного.
палимпсестор
2
В моем случае у меня есть два клона гигантского удаленного репозитория git (для обеспечения параллельной работы), то есть вся его история уже загружена и дважды сохраняется на моем жестком диске. Если бы мне также пришлось добавить их как удаленные друг от друга, это создало бы еще две дополнительные копии одной и той же истории и, возможно, потребовало бы синхронизации между ними, прежде чем я смогу это сделать cherry-pick. Таким образом, даже если это может показаться «правильным», это не всегда наиболее практично.
Chuim