Как изменить путь к файлу в наборе патчей Git?
Я работаю над репо Git, которое было вытащено из репо SVN с помощью git svn
. Много лет назад репо SVN было создано из исходного архива исходного (восходящего) проекта. В исходном проекте была файловая структура, подобная следующей:
/
COPYING
README
src/
...many source files...
Однако, когда было создано репо SVN, файлы README и т.д. были удалены, а приложение было создано с помощью src/
в качестве корня, поэтому теперь репо выглядит следующим образом:
/
...many source files
Недавно я преобразовал этот SVN-репо в репозиторий Git. Исходный проект также находится в репозитории Git, и я хотел бы начать отслеживать изменения в восходящем потоке, чтобы я мог легко увидеть, какие пользовательские изменения были сделаны (и отправить исправления обратно в исходный проект, если это применимо). Я нашел коммит в восходящем репо, из которого было создано наше SVN-репо, поэтому теперь я хотел бы применить наши изменения к этой фиксации (в ветке). Я могу легко создать набор исправлений с помощью git format-patch
и применить их к клонированному репозиторию вверх... кроме того, что структуры файлов разные, поэтому патчи больше не указывают на правильные файлы. Есть ли способ применить патчи от git format-patch
к каталогу src/
в клонированном репо? (Обратите внимание, что в патчах Git также есть необходимая информация, например, имя оригинального автора, адрес электронной почты и дата, которые я также хотел бы применить и не нужно делать вручную, т.е. Возиться с GIT_AUTHOR_EMAIL
, и др.)
Ответы
Ответ 1
Мне кажется, что вы должны использовать git filter-branch
для изменения путей в репозитории, ранее клонированных из SVN. Затем, после того, как все пути к файлам были обновлены, теперь вы можете просто использовать git format-patch
для создания патчей, которые будут применяться к повторному клонированию с последующим репо.
Try:
git filter-branch --tree-filter 'mkdir src; git ls-tree --name-only $GIT_COMMIT | xargs -I files mv files src'
Ответ 2
У меня недавно была аналогичная проблема. Моим решением было создать новый целевой репозиторий с подкаталогом src
, затем я создал набор исправлений в исходном репозитории:
/data/source-repository$ git format-patch -k --root
то эти исправления были применены к директории src
в целевом репозитории:
/data/target-repository$ git am -k --committer-date-is-author-date --directory src ../source-repository/*.patch
Все исправления из исходного репозитория завершились в src
в целевом репозитории, т.е. все пути были соответствующим образом изменены.
Оттуда вы можете снова создавать патчи и импортировать их в восходящий репозиторий внутри ветки.
Ответ 3
Мне приходилось делать что-то очень похожее однажды, было некрасиво, но это было управляемо. То, что я закончил, было:
git format-patch <commitish> --stdout > patches-for-upstream.mbox
$EDITOR patches-for-upstream.mbox
Внутри редактора я посмотрел, какие биты были обычными и нужно изменить, чтобы сделать "git am" делать то, что я хотел. Это оказалось три строки, за каждый файл, зафиксированный в каждой фиксации:
- строка, начинающаяся с
diff --git a/path/to/file b/path/to/file
- строка, начинающаяся с
--- a/path/to/file
- строка, начинающаяся с
+++ b/path/to/file
То, что должен сделать редактор на этом этапе, - это пройти через эти строки и внести необходимые изменения, чтобы все исправления применялись к другому репозиторию Git.
Я сделал это в Vim, используя три быстро типизированных макроса, YMMV. Что-то вроде:
- перейти к следующей строке, начинающейся с
diff --git a/
- перейти к этой косой черте после
a
- измените путь так, как вам нужно.
- перейдите к косой черте после
b/
(перейдите в следующее пространство из файла a
, затем /
)
- измените путь так же, как
- следующая строка (
---
)
- перейдите к
a/
- изменить путь
- следующая строка (
+++
)
- перейдите к
b/
- изменить путь
Повторяйте, пока файл не будет выполнен. В Vim речь шла о том, чтобы получить его в макросе один раз (qq<long string of commands>q
), попробовав его один раз (@q
), а затем выполнив его для всего файла ([email protected]
).
Сохраните файл, перейдите в другое репо Git и попробуйте git am
его.