git am error: “патч не застосовується”


76

Я намагаюся перенести кілька комітів з одного проекту на другий, подібний, за допомогою git.

Тож я створив патч, що містить 5 комітів:

git format-patch 4af51 --stdout > changes.patch

Потім перемістіть патч у папку другого проекту та захочете застосувати патч:

git am changes.patch 

... але це видає мені помилку:

Applying: Fixed products ordering in order summary.
error: patch failed: index.php:17
error: index.php: patch does not apply
Patch failed at 0001 Fixed products ordering in order summary.
The copy of the patch that failed is found in:
   c:/.../project2/.git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".

Тож я відкрив index.php, але там нічого не змінилося. Я припускаю, що деякі >>>>>>>позначки тощо, наприклад, при вирішенні конфлікту злиття, але у файлі не було позначено жодного конфлікту. git statusдав мені також порожній список змінених файлів (тільки changes.patchтам був). Тож я запускаю git am --continue, але з’являється ще одна помилка:

Applying: Fixed products ordering in order summary.
No changes - did you forget to use 'git add'?
If there is nothing left to stage, chances are that something else
already introduced the same changes; you might want to skip this patch.
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort". 

Я використовую Windows 7 і найновішу версію git "1.9.4.msysgit.1"

PS Після кількох годин гуглиння я знайшов кілька рішень, але мені нічого не вдається:


git am -3 changes.patch 

видає дивну помилку "інформація sha1":

Applying: Fixed products ordering in order summary.
fatal: sha1 information is lacking or useless (index.php).
Repository lacks necessary blobs to fall back on 3-way merge.
Cannot fall back to three-way merge.
Patch failed at 0001 Fixed products ordering in order summary.
The copy of the patch that failed is found in:
   c:/.../project2/.git/rebase-apply/patch
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort". 

git am changes.patch --ignore-whitespace --no-scissors --ignore-space-change

видає першу помилку, як зазначено вище: "помилка: помилка виправлення: index.php: 17", але ніяких позначок конфлікту в не index.phpбуло додано.


5
Я теж боровся з цим. Але в деяких випадках це було спричинено файлами (наприклад, із джерел WIndows), здійсненими, коли CRLF був у закінченнях рядків. Здається, git не любить закінчення рядків CRLF, незважаючи на таку функцію налаштування, як eol.crlf. Зразок посилання щодо проблем з cr / lf: stackoverflow.com/questions/1510798/…
Роб

1
Чудово. Просто довелося перетворити закінчення рядків патча, який я отримав, у стиль "Unix", і після цього він спрацював. Це заробляє прихильність.
user2808624

Відповіді:


106

Що таке патч?

Патч - це трохи більше (див. Нижче), ніж ряд інструкцій: "додати це сюди", "видалити те там", "змінити цю третю річ на четверту". Ось чому git каже вам:

The copy of the patch that failed is found in:
c:/.../project2/.git/rebase-apply/patch

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

Трохи більше

Тристороннє злиття вводить "трохи більше" інформації, ніж звичайна "серія інструкцій": воно повідомляє вам, якою була оригінальна версія файлу. Якщо ваше сховище має оригінальну версію, ваш git може порівняти те, що ви зробили з файлом, і те, що патч каже зробити з файлом.

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

Використовуючи --reject

Коли вам потрібно застосувати виправлення вручну, все ще можливо, що git може застосувати більшу частину виправлення для вас автоматично і залишити лише кілька частин для сутності з можливістю міркувати про код (або що завгодно, що потребує виправлення) . Додаючи, це робить --rejectgit, і залишає "непридатні" частини виправлення у файлах відхилення. Якщо ви використовуєте цю опцію, ви все одно повинні застосувати вручну кожну невдалу виправлення та з’ясувати, що робити з відхиленими частинами.

Після того, як ви внесли необхідні зміни, ви можете git addмодифіковані файли і використовувати, git am --continueщоб сказати git зафіксувати зміни та перейти до наступного патчу.

Що робити, якщо нічого не робити?

Оскільки у нас немає вашого коду, я не можу сказати, чи це так, але іноді ви закінчуєте одним із патчів, говорячи про речі, які складають, наприклад, "виправте написання слова на рядку 42" коли правопис там уже був виправлений.

У цьому конкретному випадку ви, подивившись на патч і поточний код, повинні сказати собі: "ага, цей патч потрібно просто повністю пропустити!" Ось тоді ви використовуєте іншу пораду git, вже надруковану:

If you prefer to skip this patch, run "git am --skip" instead.

Якщо ви запустите git am --skip, git пропустить цей патч, так що, якщо в поштовій скриньці було п'ять патчів, він закінчиться додаванням лише чотирьох комітів замість п'яти (або трьох замість п'яти, якщо ви пропустите двічі тощо).


11
Дякую за чудову відповідь. git am changes.patch --rejectКраще для мене, тому що він пропонує альтернативу «конфліктних знаки» (знайдених в .rej файлів). Потім git add, git am --continueі все працює нормально :-)
nanuqcz

2
так дякую. для мене було дивно, що я git amне (подобається patch) намагався застосувати зміни, які застосовуються.
Стівен Р. Луміс

Дивно, що git іноді не в змозі застосовувати патчі, створені ним самим. Я використовуюgit log --pretty=email --patch-with-stat --reverse -- filename
Ед Рендалл

3
@EdRandall: якщо ви використовуєте git amабо git apply -3 і у вас є базова версія файлу у вашому сховищі, Git повинен мати можливість тристороннього злиття (з потенційними конфліктами злиття, звичайно). Зверніть увагу, що особа, яка надсилає патч, може знадобитися для його використання --full-indexпід час генерації патча.
Торек

1
@DrumM: злиття та перебазування завжди мають базовий файл, тому їм насправді не потрібен еквівалент, --rejectоскільки вони завжди мають еквівалент -3. Тим не менш, я звик до patchкоманди в стилі GNU , тому я теж зазвичай віддаю перевагу --rejectрежиму, але аргументи я бачу в будь-якому випадку.
torek

4

git format-patchтакож має -Bпрапор.

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

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

Приклад:

git format-patch -B10% --stdout my_tag_name > big_patch.patch
git am -3 -i < big_patch.patch


2

У мене була та сама проблема. Я використовував

git format-patch <commit_hash>

для створення патча. Моєю основною проблемою було те, що патч не працював через деякі конфлікти, але я не міг побачити жодного конфлікту злиття у вмісті файлу. Раніше я git am --3way <patch_file_path>застосовував пластир.

Правильною командою для застосування виправлення має бути:

git am --3way --ignore-space-change <patch_file_path>

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


1
Параметр -3Wayпомилковий, це або -3або --3way. І це не відповідає на питання.
DrumM

1
Це друкарська помилка в розділі коду. Дякуємо, що вказали на це. Якби ви дотримувались повної відповіді, ви могли б помітити, що в текстовому розділі це було згадано --3Way жирним шрифтом. Відповідно до запитання, конфлікти злиття не відображалися після застосування виправлення. У мене була та сама проблема, і я вирішив її, використовуючи лише цю команду.
srs

1) ви розміщуєте --після ...should be:, це вже схоже на друкарську помилку, я легко читаю --і читаю рядок коду нижче. 2) Просто набридаючи, що відповіді на коди не містять правильних відповідей ;-) Краще подати лише той код, який є правильним. 3) друкарська помилка в оригінальному питанні не спричинила його проблеми ...
DrumM

2
Не знаю, чому саме, але --ignore-space-changeопція полягала в тому, що змусило мій файл виправлення працювати.
Sky

1

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

Щоб перевірити це, якщо у вас є патч, який застосовується лише до одного файлу, ви можете спробувати запустити 'unix2dos' або 'dos2unix' лише на цьому файлі (спробуйте обидва, щоб побачити, який з них викликає зміну файлу; ви можете отримати їх утиліти для Windows, а також Unix), потім фіксуйте цю зміну як тестовий коміт, а потім спробуйте застосувати патч ще раз. Якщо це працює, це була проблема.

NB git amзастосовує виправлення як LF за замовчуванням (навіть якщо файл виправлення містить CRLF), тому, якщо ви хочете застосувати виправлення CRLF до файлів CRLF, ви повинні використовувати git am --keep-crвідповідно до цієї відповіді .


0

Якби кілька модулів скаржилися на виправлення, це не стосується. Мені не вистачало того, що гілки застаріли. Після git merge masterзгенерованих файлів виправлення за допомогою git diff master BRANCH > file.patch. Підійшовши до ванільної гілки, я зміг застосувати пластирgit apply file.patch


0

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

[mrdubey @ SNF] $ git log 65f1d63 коміт 65f1d6396315853f2b7070e0e6d99b116ba2b018 Автор: Dubey Mritunjaykumar

Дата: вівторок, 22 січня 12:10:50 2019 +0530

коміт e377ab50081e3a8515a75a3f757d7c5c98a975c6 Автор: Dubey Mritunjaykumar Дата: Пн 21 січня 23:05:48 2019 +0530

Раніше використовувався коміт: git diff new_commit_id..prev_commit_id> 1 diff

Отримала помилку: помилка виправлення: ім'я файлу: 40

робочий: git diff prev_commit_id..latest_commit_id> 1.diff

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