Як застосувати виправлення Git до файлу з іншим іменем та шляхом?


100

У мене є два сховища. В одному, я вношу зміни у файл ./hello.test. Я фіксую зміни та створюю патч з цього коміту за допомогою git format-patch -1 HEAD. Тепер у мене є другий репозиторій , який містить файл , який має той же зміст , як hello.test але поміщається в іншому каталозі під іншим ім'ям: ./blue/red/hi.test. Як мені застосувати вищезгаданий патч до hi.testфайлу? Я спробував, git am --directory='blue/red' < patch_fileале це, звичайно, скаржиться, що файли називаються не однаково (що, на мою думку, Git не хвилювало?). Я знаю, що, можливо, міг би відредагувати diff, щоб застосувати його до цього конкретного файлу, але я шукаю командне рішення.


Відповіді:


97

Ви можете створити патч за допомогою, git diffа потім застосувати його за допомогою patchутиліти, яка дозволяє вказати файл, до якого потрібно застосувати різницю.

Наприклад:

cd first-repo
git diff HEAD^ -- hello.test > ~/patch_file

cd ../second-repo
patch -p1 blue/red/hi.test ~/patch_file

7
Ах, мило, не думав про це. Однак чи є спосіб зробити це за допомогою команд Git, щоб дані комітів (дата та час, автор комітів, повідомлення комітів) залишалися незмінними?
mart1n

2
Можливо, є щось, що ви можете зробити з amабо apply, але я не можу це знайти. Якщо ви часто дублюєте зміни, можливо, буде краще рішення за допомогою підмодулів або будь-якої вашої вибраної мови для спільного використання коду (наприклад, у Ruby ви можете витягти дублікат коду як самоцвіт).
georgebrock

1
Це насправді пов'язано з документацією (вихідними файлами є XML). Субмодулі насправді не є варіантом, оскільки мені довелося б обгрунтувати їх у нашій існуючій інфраструктурі.
mart1n

52

Існує просте рішення, яке не передбачає ручного редагування виправлення та зовнішнього сценарію.

У першому сховищі (це також може експортувати діапазон комітів, використовуйте, -1якщо ви хочете вибрати лише один коміт):

git format-patch --relative <committish> --stdout > ~/patch

У другому сховищі:

git am --directory blue/red/ ~/patch

Замість використання --relativein git format-patch, іншим рішенням є використання -p<n>option in git amдля вилучення nкаталогів із шляху патчів, як зазначено у відповіді на подібне запитання .

Також можна запустити і git format-patch --relative <committish>без --stdout, і це створить набір .patchфайлів. Ці файли можуть бути подані безпосередньо git amз git am --directory blue/red/ path/to/*.patch.


9
Це все ще спирається на той факт, що імена файлів однакові, так?
mart1n

3
Слід зазначити, що ця --directoryопція вимагає вказати повний шлях до каталогу відносно кореня репо; щось на кшталт, --directory=./поки chdir'd у підкаталог репо не працюватиме.
Рід

1
Використання --3wayдопомагає з does not exist in index:git am --3way --directory (relative-path) (patch)
Брентом Бредберном

Використовуйте -kклавішу в обох командах, щоб не зняти перший рядок повідомлення про коміт.
ruvim

Використання --3wayне лише допомагає з помилками "не існує в індексі" (на що вказує @nobar), але також дозволяє чітко обробляти конфлікти злиття. Замість того, щоб залишати конфліктні файли недоторканими, додається блок конфлікту, який потім можна вирішити.
Даніель Вольф,

11

Відповідь на моє власне запитання сценарієм, який робить саме це: https://github.com/mprpic/apply-patch-to-file

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


5

Спираючись на відповідь @georgebrock, ось рішення, яке я використав:

Спочатку створіть файли виправлень як зазвичай (наприклад, git format-patch commitA..commitB).

Потім переконайтеся, що цільове сховище є чистим (не повинно бути файлів, що змінюються або не відслідковуються) і застосуйте такі виправлення:

cd second-repo
git am ~/00*.patch

Для кожного файлу виправлення ви отримаєте помилку типу "помилка: XYZ не існує в індексі". Тепер ви можете застосувати цей файл виправлення вручну:

patch --directory blue/red < ~/0001-*.patch
git add -a
git am --continue

Вам потрібно виконати ці три кроки для кожного файлу виправлення.

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


1
Гарна відповідь, я вважаю, що це найкраща основа для будь-якого виду "нестандартних" маніпуляцій з виправленнями. Я роблю це в 3 кроки. (1) Прихильність до тексту - git format-patch -1 commitA --stdout > thing.diff; (2) Відредагуйте файл виправлення, поки він не зробить те, що мені потрібно; (3) Текст для фіксації, git am --3way thing.diff який має ту перевагу, що ви можете приймати частини виправлення, які застосовуються чисто, і використовувати gitстандартний процес вирішення конфліктів для частин, які цього не роблять.
We Are All Monica

2

Я розумію, що два файли абсолютно однакові у вашій ситуації, тому виправлення, швидше за все, вдасться.

Однак, якщо ви хочете застосувати виправлення до подібного, але не зовсім того самого файлу, або ви хочете зробити інтерактивне виправлення, ви будете використовувати три способи об’єднання.

Скажімо , ви змінили файл Aпозначать ДАВАЙТЕ , A~1як в попередній версії, і ви хочете застосувати відмінності між A~1до Aв файл B.

Відкрийте тристоронній інструмент злиття, наприклад Beyond Compare, шлях лівої панелі - це A, середня панель - загальний предок, отже шлях - A~1це шлях правої панелі B. Потім нижня панель показує результат застосування відмінностей між A~1до Aв файл B.

Наступна фігура ілюструє ідею.

введіть тут опис зображення


0

FYI: Нещодавно у мене були проблеми при спробі завантажити виправлення з Github і застосувати його до локального файлу (що було "заміною" в новому місці).

git amне застосував би виправлення, оскільки файл не був "в індексі" або "брудний". Але я виявив, що проста patchкоманда може застосувати патч. Це запропонувало мені виправити назву файлу.

У будь-якому разі виконав роботу ...

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