Як застосувати патч git з одного сховища до іншого?


80

У мене є два сховища, одне - основне репозиторій для бібліотеки, а друге - це проект, що використовує цю бібліотеку.

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

Розташування файлу в кожному сховищі різне.

  • Основний репо: www.playdar.org/static/playdar.js
  • Проект: playlick.com/lib/playdar.js

Я спробував використати git format-patch -- lib/playdar.jsпроект playlick, а потім git amі основне репозиторій playdar, але різне розташування файлів у файлі виправлення викликало помилку.

Чи є простий спосіб застосувати патч із заданого коміту для даного файлу до іншого довільного файлу в іншому місці?

Щодо бонусних балів, що робити, якщо файл, до якого ви хочете застосувати виправлення, не знаходиться у сховищі git?


аналогічний: питання: stackoverflow.com/questions/3367254 / ...
koppor

Відповіді:


117

Якщо вручну редагувати файл заплатки з питання або нездійсненним, це можна зробити з допомогою стандартних опцій (доступно в git apply, git format-patchі GNU patch).

  1. -p<n>видаляє nпровідні каталоги зі шляхів у патчі.

  2. Після обробки -p, --directory=<root>приєднує rootдо кожного з шляхів в пластирі перед нанесенням.

Приклад

Отже, для вашого прикладу, щоб взяти патч, який був спочатку включений, static/playdar.jsі застосувати його lib/playdar.js, ви запустите:

$ cat patch_file | git am     \ 
          -p1                 \ # remove 1 leading directory ('static/')
         --directory='lib/'     # prepend 'lib/'

1
Будь-який шанс зробити цю найкращу відповідь? Це набагато простіше, ніж редагувати файл виправлення вручну.
weston

Звичайно, це краща / простіша відповідь, хоча відповідь @ araqnid все одно корисно знати.
James Wheare

Ставлюся до налаштування каталогу після першої спроби без --directory: stackoverflow.com/questions/24121709 / ...
Іоанніс Filippidis

38

Виправлення, що створюється, git format-patch- це просто текстовий файл - ви можете редагувати заголовки різниці, щоб він міняв інший шлях.

Так, наприклад, це дало б щось подібне:

diff --git a/lib/playdar.js b/lib/playdar.js
index 1234567..89abcde
-- a/lib/playdar.js
++ b/lib/playdar.js

Все, що вам потрібно зробити, це змінити lib/playdar.jsна, static/playdar.jsа потім запустити патчgit am"

Патч повинен бути доступний для читання з допомогою стандартної утиліти GNU патча для людей , які не мають git--- але не працює format-patchз -M, і -Cтак далі варіантами , щоб зробити перейменування пластирі в цьому випадку, тому що їх підтримка не є універсальною.


1
Перегляд цієї сторінки пізніше ... Це краща відповідь на поставлене запитання, ніж попередній "переможець", який пропонував підмодулі.
James Wheare

4

Якщо припустити, що обидва проекти є git-проектами, схоже, що підмодулі ідеально підійдуть для вас. Це дозволяє проекту git динамічно зв'язуватися з іншим проектом git, по суті, випікаючи репозиторій git прямо всередині іншого репозиторію git, обидва мають своє власне життя.

Іншими словами, додайте "main repo" як підмодуль у "project". Кожного разу, коли ви фіксуєте / штовхаєте нові речі в "основному репо", ви просто git pullповертаєте їх у "проект".


Хм, прочитавши документи підмодуля, це не звучить як «простий спосіб», хоча цілком може бути найнадійнішим. Схоже, мені довелося б створити підмодуль, що містить лише playdar.jsфайл, а потім включити це в обидва інші проекти (я не хочу, щоб усе інше було www.playdar.orgв playlick.comпроекті), я можу просто вдатися до ручного редагування файлів виправлень, якщо чесно . Або продовжуйте копіювати вставку між ними. Ура.
James Wheare

Ось чіткий і ретельний підручник та початок роботи з підмодулем git для тих, хто ще натрапляє
Джеймс Уір,

2

Щоб заповнити відповідь Хенріка та взяти бонусний бал

а якщо файл, до якого ви хочете застосувати виправлення, не знаходиться у сховищі git?

Якщо у вас є доступ до каталогів кандидата на файл для виправлення, що надходить із сховища git, ви можете спочатку перетворити це дерево каталогів / файлів у саме сховище git! (' git init': сховище git - це все-таки просто .git у кореневому каталозі).
Тоді ви встановите цей репо як підмодуль для вашого основного проекту.


2

Використовуючи --relativeопцію, format-patchможна покращити абстракцію (приховати недоречні деталі про сховище, з якого створено патч).

[repository-with-changes]
git format-patch --relative=(path-to-library) (base-commit-for-patch) ## 'HEAD~1'

Я виявив, що --3wayопція потрібна при застосуванні виправлення (щоб уникнути does not exist in indexпомилок) - ваш пробіг може відрізнятися. Використання --directory=(...), ймовірно, необхідне лише у тому випадку, якщо ваш цільовий шлях не є коренем сховища.

[repository-to-update]
git am --3way --directory=(path-to-library) (patch-file)

  • format-patch створить один файл виправлення для кожного коміту до поточної гілки, починаючи з 'base'.

  • У деяких випадках документація до --relativeопції відсутня , але, схоже, вона все одно працює (станом на версію 2.7.4).



1

Ви можете просто тимчасово видалити (перейменувати) головне сховище.

cd to/main/project
mv .git .git_
cd to/sub/project
git apply patchname
cd -
mv .git_ .git

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.