Можно ли выбрать вишню из другого git-репозитория?


726

Я работаю с git-репозиторием, которому нужен коммит из другого git-репозитория, который ничего не знает о первом.

Обычно я выбираю вишню с помощью команды HEAD@{x}reflog, но, поскольку .gitничего не известно об этой записи reflog (другой физический каталог), как я могу выбрать вишню или я могу?

Я использую git-svn. Мой первый филиал использует git-svnиз trunkиз Subversion репо, а следующий филиал использует git-svnна Subversion ветви.


2
Вот причина, по которой Бен Ли открыл награду за этот вопрос: «Я собираюсь назначить награду за правильный ответ, а не за принятый ответ. Мне просто нужно подождать 24 [часа], чтобы сделать это». Однако я не понимаю, какой из них должен быть «правильным ответом», и почему принятый ответ не «правильный».

1
Не ясно, какова природа проблемы. Как эти разные репо связаны, если вообще? Является ли одна вилка другой? Или это на самом деле два совершенно разных и не связанных проекта?

@Cupcake, принятый ответ хорош, и явно помог ОП, поэтому его следует принять. Под «правильным» я действительно имел в виду «правильно для меня» (и, судя по комментариям, верно и для некоторых других людей). Я просто подумал, что тот, кому я дал награду, заслуживает столько же повторений, сколько и принятый ответ.
Бен Ли

Ответы:


557

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

Как это:

git remote add other https://example.link/repository.git
git fetch other

Теперь у вас есть вся информация, чтобы просто сделать git cherry-pick.

Подробнее о работе с пультами здесь: https://git-scm.com/book/en/v2/Git-Basics-Working-with-Remotes


1
Что если я использую git-svn? моя первая ветвь использует git-svn транка, а следующая - git-svn на ветке (спасибо за быстрый ответ)
gitcoder182

1
Когда вы впервые клонируете репозиторий Subversion, убедитесь, что вы клонировали весь репозиторий, а не только его ствол. Также убедитесь, что вы используете --stdlayoutопцию git-svn, если вы используете стандартную разметку транка / веток / тегов в Subversion. Тогда ветка Subversion будет простой удаленной веткой git.
Вильгельмтелл

33
Если вы используете Github, вы можете извлечь патч, добавив .patch к URL-адресу коммита, а затем применив его с помощью git am < d821j8djd2dj812.patch. За пределами GH, аналогичные концепции могут быть сделаны, как указано в альтернативном ответе ниже.
radicand

2
@радикан, а какой ответ ниже "альтернативный"? Пожалуйста, ссылку на него.

7
Подробные шаги, чтобы выбрать вишню из другого репо: coderwall.com/p/sgpksw/git-cherry-pick-from-another-repository
Т. Ким Нгуен

854

Ответ, как и было дано, заключается в использовании format-patch, но поскольку вопрос заключался в том, как выбрать вишню из другой папки, вот фрагмент кода, предназначенный именно для этого:

$ git --git-dir=../<some_other_repo>/.git \
format-patch -k -1 --stdout <commit SHA> | \
git am -3 -k

(объяснение от @cong ma )

Команда git format-patchсоздает патч из some_other_repoкоммита, указанного его SHA (только -1для одного коммита). Этот патч передан по каналу git am, который применяет патч локально ( -3означает попытку трехстороннего слияния, если патч не может быть применен корректно). Надеюсь, это объясняет.


18
Это на месте, но было бы здорово, если бы кто-то мог расширить это - разбивка того, что происходит (особенно с этими флагами), была бы невероятно полезной.
Ник Ф

46
@NickF, git format-patchкоманда создает патч из some_other_repoкоммита, указанного его SHA (только -1для одного коммита). Этот патч передан по каналу git am, который применяет патч локально ( -3означает попытку трехстороннего слияния, если патч не может быть применен корректно). Надеюсь, это объясняет.
Конг Ма

3
ошибка: патч не удалось: somefile.cs: 85 ошибка: somefile.cs: патч не применяется Вы редактировали свой патч вручную? Это не относится к BLOB-объектам, записанным в его указателе. Невозможно вернуться к трехстороннему слиянию. Ошибка патча в 0001 Добавлены части графического интерфейса. Неудачная копия патча находится в: <some_other_repo> /. Git / rebase-apply / patch Когда вы решили эту проблему, запустите «git am --continue». Если вы предпочитаете пропустить этот патч, запустите "git am --skip". Чтобы восстановить исходную ветку и прекратить исправление, запустите «git am --abort».
Том

8
@ Попробуй использовать --ignore-whitespace. Полная команда: git --git-dir=../<some_other_repo>/.git format-patch -k -1 --stdout <commit SHA> | git am -3 -k --ignore-whitespace
Джейк Грэм Арнольд

7
@BoomShadow Потому что это намного проще. Добавление удаленного и извлечения вносит все изменения в другие репо. Эта командная строка является однократным действием.
Джонатон Рейнхарт

152

Вот пример удаленного извлечения-слияния.

cd /home/you/projectA
git remote add projectB /home/you/projectB
git fetch projectB

Тогда ты можешь:

git cherry-pick <first_commit>..<last_commit>

или вы могли бы даже объединить всю ветку

git merge projectB/master

54
git merge projectB/master очень, очень неправильно , потому что вы не подаете изменения от одной фиксации (как вишневое выбор будет), вы фактически сливаясь все изменения вprojectB/masterкоторые не содержатся в собственнойmasterотрасли.

4
Я предполагал, что это было намерением оригинального плаката. В противном случае, да, это не правильный вариант для них.
Брайан

5
Это прекрасно работает, когда два репозитория связаны между собой.
Ронни Аджер-Уик

1
Я создал копию из репозитория git (просто для того, чтобы «поиграть», не ломая исходное репо), и чтобы держать его в актуальном состоянии с его источником, ответ от Брайана - именно то, что мне было нужно, так что, Cupcake, я Должен сказать, что это не "неправильно", но другой случай использования. Но вам приятно указать на потенциальную катастрофу: D
ferrari2k

6
ИМО это должно быть принятое решение. Кроме того, если вы хотите удалить пульт после того, как вы закончили сбор вишни с него, используйте git remote rm projectB. Также используйте git tag -d tag-nameдля удаления любых тегов, извлеченных из удаленного репо. Удаленные коммиты больше не будут отображаться в вашей истории, а удаление в конечном итоге удалит их из хранилища.
ADTC

130

Вы можете сделать это, но это требует двух шагов. Вот как:

git fetch <remote-git-url> <branch> && git cherry-pick FETCH_HEAD

Замените <remote-git-url>URL или путь к хранилищу, из которого вы хотите выбрать вишню.

Замените <branch>веткой или именем тега, который вы хотите выбрать из удаленного хранилища.

Вы можете заменить FETCH_HEADна git SHA из ветки.

Обновлено: изменено на основе отзывов @ pkalinow.


8
Работает с именем ветки, но не с SHA. Если вы хотите , чтобы вишня-выбрать коммита обозначается его хэш, используйте вместо этого: git fetch <repo-url> <branch> && git cherry-pick <sha>.
pkalinow

Спасибо. Это было как раз то, что мне нужно, чтобы вставить несколько коммитов из одного репозитория в другой, который я создал для этой цели.
wojciii

Это было именно то, что мне было нужно для многих пользовательских реализаций нашего кода для разных клиентов (у каждого из которых есть свои репозитории / вилки), нам нужен был способ получить конкретные коммиты в нашу базу / транк. СПАСИБО!
RedSands

Это должен быть принятый ответ для одноразового выбора вишни через репо. Я использую его все время, когда выбираю между репозиториями, которые уже являются локальными, удаленный URL - это просто путь локальной файловой системы.
Амеди Ван Гассе

61

Вот шаги, чтобы добавить удаленный, получить ветки и вишни выбрать коммит

# Cloning our fork
$ git clone git@github.com:ifad/rest-client.git

# Adding (as "endel") the repo from we want to cherry-pick
$ git remote add endel git://github.com/endel/rest-client.git

# Fetch their branches
$ git fetch endel

# List their commits
$ git log endel/master

# Cherry-pick the commit we need
$ git cherry-pick 97fedac

Источник: https://coderwall.com/p/sgpksw


17

Смотрите Как создать и применить патч с Git . (Из формулировки вашего вопроса я предположил, что этот другой репозиторий предназначен для совершенно другой кодовой базы. Если это репозиторий для той же кодовой базы, вы должны добавить его в качестве удаленного, как предложено @CharlesB. Даже если это для другого кодовая база, я думаю, вы все равно можете добавить его в качестве удаленного, но вы можете не захотеть получить всю ветку в свой репозиторий ...)


11

Вы можете сделать это в одну строку следующим образом. Надеюсь, что вы находитесь в git-репозитории, который нуждается в подобранных изменениях, и вы проверили, чтобы исправить ветку.

git fetch ssh://git@stash.mycompany.com:7999/repo_to_get_it_from.git branchToPickFrom && git cherry-pick 02a197e9533
# 

git fetch [ответвление URL] [ответвление на cherry-pick из] && git cherry-pick [commit ID]


1
Приветствия, не нуждалась в ssh://части, только дляhttps://
Лео

5

Да. Извлеките хранилище, а затем выберите вишню из удаленной ветки.


1

Предполагая, Aчто это репо, из которого вы хотите выбрать вишню, и Bтот, к которому вы хотите выбрать вишню, вы можете сделать это, добавив </path/to/repo/A/>/.git/objectsк </path/to/repo/B>/.git/objects/info/alternates. Создайте эти alternatesфайлы, если они не существуют.

Это заставит репо B получить доступ ко всем git-объектам из репо A и заставит вишневый пик работать на вас.


0

Моя ситуация состояла в том, что у меня есть голое репо, к которому толкает команда, и клон этого сидящего рядом с ним. Этот набор строк в Makefile работает правильно для меня:

git reset --hard
git remote update --prune
git pull --rebase --all
git cherry-pick -n remotes/origin/$(BRANCH)

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

Если «ничего не знает» означает «нельзя использовать в качестве удаленного», то это не помогает, но этот ТАК вопрос возник, когда я начал поискать этот рабочий процесс, поэтому я решил внести свой вклад.


-n означает no-commit согласно git docs, и мне очень важно увидеть изменения перед выполнением коммита
canbax

0

Если вы хотите выбрать несколько коммитов для данного файла, пока не достигнете данного коммита, используйте следующее.

# Directory from which to cherry-pick
GIT_DIR=...
# Pick changes only for this file
FILE_PATH=...
# Apply changes from this commit
FIST_COMMIT=master
# Apply changes until you reach this commit
LAST_COMMIT=...

for sha in $(git --git-dir=$GIT_DIR log --reverse --topo-order --format=%H $LAST_COMMIT_SHA..master -- $FILE_PATH ) ; do 
  git --git-dir=$GIT_DIR  format-patch -k -1 --stdout $sha -- $FILE_PATH | 
    git am -3 -k
done
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.