Как применить 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).

  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/'

Патч производится 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

Я думаю, что поддерево - лучшее решение для вашей проблемы

Урок 1

Туориал 2

Другие вопросы по тегам