Чи можна вишнево вибрати комісію з іншого сховища git?


724

Я працюю зі сховищем git, яке потребує фіксації з іншого сховища git, яке нічого не знає.

Як правило, я б HEAD@{x}вибирав вишню за допомогою рефлогу, але оскільки це .gitнічого не знає з цього запису рефлогів (різний фізичний каталог), як я можу це вибрати, чи я можу?

Я використовую git-svn. Мій перший філія використовує git-svnз trunkз Subversion репо, а наступний філія використовує git-svnна Subversion гілки.


2
Це є причиною, яку Бен Лі відкрив з винагороди за це питання: "Я буду присуджувати винагороду за правильну відповідь, а не прийняту відповідь. Для цього мені просто потрібно чекати 24 години". Однак я не розумію, яка з них повинна бути "правильною відповіддю", і чому прийнята відповідь не "правильна".

1
Незрозуміло, в чому суть проблеми. Як пов'язані ці різні репости, якщо вони взагалі є? Один вилок іншого? Або це насправді два абсолютно окремих та не пов'язаних між собою проекти?

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

Відповіді:


554

Вам потрібно буде додати інше сховище як віддалене, а потім отримати його зміни. Звідти ви бачите коміт і можете його вибрати.

Щось схоже на те:

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.
wilhelmtell

33
Якщо ви використовуєте Github, ви можете витягнути патч, додавши .patch до URL-адреси фіксації, а потім застосувавши його за допомогою git am < d821j8djd2dj812.patch. Поза GH, подібні концепції можна зробити, як зазначено в альтернативній відповіді нижче.
радиканд

2
@radicand яка відповідь нижче "альтернативна"? Будь ласка, посилання на нього.

7
Детальні кроки до вибору вишні з іншого репо: coderwall.com/p/sgpksw/git-cherry-pick-from-another-repository
Т. Кім Нгуен

854

Відповідь, як дано, полягає у використанні формату-патча, але оскільки питання полягало у тому, як вибрати вишню з іншої папки, ось такий фрагмент коду зробити саме це:

$ 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«s Комміт визначається його SHA ( -1для однієї єдиної зробити в поодинці). Цей патч є накладеним на папку git am, що застосовує патч локально ( -3означає спробувати тристороннє злиття, якщо патч не вдається чітко застосувати). Сподіваюся, що це пояснює.


18
Це місце на місці, але було б чудово, якби хто-небудь міг розширити цю проблему - розбиття саме того, що відбувається (особливо з тими прапорами) було б неймовірно корисним.
Нік Ф

45
@NickF, git format-patchкоманда створює патч із some_other_repo" комміту", визначеного його SHA (лише -1для однієї фіксації). Цей патч є накладеним на папку git am, що застосовує патч локально ( -3означає спробувати тристороннє злиття, якщо патч не вдається чітко застосувати). Сподіваюся, що це пояснює.
Cong Ma

3
помилка: патч не вдався: somefile.cs: 85 помилка: somefile.cs: патч не застосовується. Ви вручну редагували свій патч? Це не стосується крапок, записаних у його індексі. Неможливо повернутися до тристороннього злиття. Не вдалося виконати виправлення на 0001 Додано частини GUI. Копія невдалого виправлення знаходиться в: <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 Тому що це простіше. Додавання пульта та отримання даних вносять усі зміни в репо-репо. Цей командний рядок - це разова дія.
Джонатан Райнхарт

151

Ось приклад віддаленого вилучення-злиття.

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_HEADgit 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-адреса гілки] [Відділити до вишеньки з вишні] && git cherry-pick [ID ID]


1
Ура, не потрібна була ssh://частина, лише дляhttps://
Лева,

5

Так. Отримайте сховище, а потім вишню виберіть із віддаленого відділення.


1

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

Це дозволить Repo B отримати доступ до всіх об'єктів git з репо A, і зробить вишмову роботу для вас.


0

Моя ситуація полягала в тому, що у мене є голе репо, яке підштовхує команда, і клон того, хто сидить поруч. Цей набір рядків у Makefile працює для мене правильно:

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

Зберігаючи майстра голого репо, ми можемо вишнево вибрати запропоновану зміну, опубліковану на голому репо. Також у нас є (більш складний) спосіб вишні з декількох брекетів для консолідованого огляду та тестування.

Якщо "нічого не знає" означає, що "не можна використовувати як пульт", то це не допомагає, але це питання виникло, коли я гуглю навколо, щоб придумати цей робочий процес, тож я подумав, що буду сприяти.


-n означає відсутність фіксації відповідно до 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.