Как применить git patch из одного хранилища в другое?
У меня есть два репозитория, один из которых является основным репозиторием для библиотеки, а другой - это проект, использующий эту библиотеку.
Если я внесу исправление в проект subservient, я бы хотел простой способ применить этот патч обратно вверх по течению.
Расположение файла отличается в каждом хранилище.
- Главный репо:
www.playdar.org/static/playdar.js
- Проект:
playlick.com/lib/playdar.js
Я пытался с помощью git format-patch -- lib/playdar.js
на проекте плейлика, а затем git am
в основном репозитории playdar, но в разных местах файла патча возникла ошибка.
Есть ли простой способ применить патч из данного коммита для данного файла в другой произвольный файл в другом месте?
Что касается бонусных баллов, что если файл, к которому вы хотите применить патч, отсутствует в репозитории git?
8 ответов
Если редактирование файла патча вручную невозможно или невозможно, это можно сделать с помощью стандартных параметров (доступно в git apply
, git format-patch
и GNU patch
).
-p<n>
удаляетn
ведущие каталоги из путей в патче.После обработки
-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/'
Патч производится git format-patch
это просто текстовый файл - вы можете редактировать заголовки diff, чтобы он изменял другой путь.
Так, например, это произвело бы что-то вроде этого:
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
и т.д. варианты создания переименованных патчей в этом случае, потому что их поддержка не универсальна.
С использованием --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).
Предполагая, что оба проекта являются git-проектами, кажется, что подмодули идеально подойдут для вас. Это позволяет git-проекту динамически связываться с другим git-проектом, по сути выпекая git-репо прямо внутри другого git-репо, причем оба имеют свою собственную жизнь.
Другими словами, добавьте "основное репо" как подмодуль в "проекте". Всякий раз, когда вы фиксируете / толкаете новые вещи в "основном репо", вы просто git pull
их обратно в "проект".
Вы можете добавить новый пульт и вытащить из него. Статья с подробностями.
$ cd <path-to-repoB>
$ git remote add repoA <git-URL-for-repoA>
$ git pull repoA
Чтобы завершить ответ Хенрика и получить бонусный балл
Что делать, если файл, к которому вы хотите применить исправление, отсутствует в репозитории git?
Если у вас есть доступ к каталогам файла-кандидата для патча, поступающего из репозитория git, вы можете сначала преобразовать это дерево каталогов / файлов в сам репозиторий git! ("git init
': репозиторий git - это всего лишь.git в корневом каталоге).
Затем вы установите этот репо как подмодуль для вашего основного проекта.
Вы можете просто временно удалить (переименовать) основной репозиторий.
cd to/main/project
mv .git .git_
cd to/sub/project
git apply patchname
cd -
mv .git_ .git