Могу ли я получить совместимый с патчем вывод из git-diff?

160

Я делаю что-то очень простое неправильно. Я пытаюсь подготовить обычный файл патча, чтобы я мог применить некоторые изменения:

$ git diff > before
$ git diff something_here > save.patch
$ git checkout . 
$ patch < save.patch
$ git diff > after
$ diff before after
$

С something_here пустым это почти работает, но имена файлов не верны. Я думаю, что я просто упускаю какой-то вариант.

В реальной жизни я собираюсь сделать слияние после проверки, так что патч может потерпеть неудачу, но вы видите, к чему я клоню.

Отредактируйте Мою ошибку здесь, чтобы задать неправильный вопрос. Вопрос в том, хочу ли я сохранить свои изменения, выполнить слияние, а затем повторно применить изменения, если это возможно? Я спросил это неправильно, потому что я привык использовать патч для решения такого рода проблем и git diffвыглядел так, как будто он хотел, чтобы я это сделал.

На комментарий Чарльза Бейли был правильный ответ. Для меня git-apply - это то, что нужно делать (git-stash выглядит тяжелее, чем мне нужно, а перебазирование и связки определенно выходят за рамки моего текущего уровня навыков.) Я собираюсь принять ответ, который дал Чарльз (потому что вы не могу принять комментарий). Спасибо за все предложения.

Редактировать, 6 лет спустя. Как любой, кто знаком с предметом, знает, я переоценил сложность git stash. Почти каждый день я буду использовать следующую последовательность:

$ git stash
$ git merge
$ git stash pop
Malvolio
источник
8
Есть ли какая-то причина, которую вы хотите использовать, patchа не git apply?
CB Bailey
3
И даже тогда, вам действительно нужны патчи, а не что-то подобное git stashили другие инструменты git?
CB Bailey
3
После редактирования я думаю, что git stashэто самое простое решение для того, что вы пытаетесь сделать, но есть много подходов, которые работают.
CB Bailey
1
@Malvolio: Да, вам даже не нужно думать о временном имени файла для хранения вашего патча.
CB Bailey
4
@ Чарлз, иногда тебе нужно отправить патч кому-то без всего git-репозитория. Например, если используете git-svn.
Элазар Лейбович

Ответы:

139

Если вы хотите использовать патч, вам нужно удалить a/ b/префиксы, используемые git по умолчанию. Вы можете сделать это с --no-prefixопцией (вы также можете сделать это с -pопцией патча ):

git diff --no-prefix [<other git-diff arguments>]

Тем не менее, обычно проще использовать прямую, git diffа затем использовать выход для подачи git apply.

Большую часть времени я стараюсь избегать использования текстовых патчей. Обычно один или несколько временных коммитов объединяются с ребазой, git stashа пакеты проще в управлении.

Для вашего случая использования я думаю, что stashэто наиболее подходит.

# save uncommitted changes
git stash

# do a merge or some other operation
git merge some-branch

# re-apply changes, removing stash if successful
# (you may be asked to resolve conflicts).
git stash pop
CB Bailey
источник
7
git diff --no-prefix master > diff.patchа затемgit checkout master patch -p0 < diff.patch
Натим
1
@Natim Для максимальной безопасности я бы рекомендовал использовать patch --dry-run < diff.patchперед выполнением последней команды.
ᴠɪɴᴄᴇɴᴛ
1
@ ᴠɪɴᴄᴇɴᴛ какая польза от этого? Поскольку мы используем git, мы вряд ли что-то потеряем, не так ли?
Натим
1
@ Natim Как я уже сказал, просто для максимальной безопасности, не нужно ничего отменять в случае ошибки. Я также думал о людях, которые читают это и хотят использовать patchвне git (возможно, используя файл патча, сгенерированный diff) в более общем случае.
ᴠɪɴᴄᴇɴᴛ
Для того , чтобы включить новые файлы в патче вы должны также включать «мерзавец дифф --no-приставка --cached» в патче. Может быть, есть лучший способ?
Джамшид
219

Просто используйте -p1: вам все равно придется использовать -p0в --no-prefixслучае, так что вы можете просто пропустить --no-prefixи использовать -p1:

$ git diff > save.patch
$ patch -p1 < save.patch

$ git diff --no-prefix > save.patch
$ patch -p0 < save.patch
ndim
источник
1
Если вы задаетесь вопросом, почему, этот человек хорошо описывает это - источник .
tutuDajuju
3
Это не будет работать с переименованиями; git diffвыводит строку, которая patchигнорирует git applyэто путь
hraban
17

У git diffs есть дополнительный сегмент пути перед файлами. Вы можете удалить эту запись в пути, указав -p1 с патчем, вот так:

patch -p1 < save.patch
Хенрик Густафссон
источник
10
  1. Я сохраняю diff текущей директории (включая незафиксированные файлы) против текущей HEAD.
  2. Затем вы можете перенести save.patchфайл куда угодно (включая двоичные файлы).
  3. На вашей целевой машине примените патч, используя git apply <file>

Обратите внимание: это также файлы, поставленные в данный момент.

$ git diff --binary --staged HEAD > save.patch
$ git reset --hard
$ <transport it>
$ git apply save.patch
Матей
источник
Хахаха. Забавно. Я задавал этот вопрос почти четыре года назад, и то, как я это делал, развивалось, но если бы вы спросили меня вчера, как это сделать, я бы дал ваш ответ и сказал бы, что получил его от ответов на этот вопрос. (На самом деле я бы, вероятно, использовал бы голые git diff > save.patchи git checkout .вместо сброса, но да ...
Мальволио
О, не заметил, что ему 4 года: P. Кстати, сброс только для того, чтобы продемонстрировать, что он работает .. Я также не вижу, чтобы кто-то использовал git applyили делал diff соответствующим вашему состоянию и указателем на последний доступный коммит. Делать просто git diffничего не сделал
Matej
Да, теперь мне интересно, как я узнал об этом git apply. Суть git diffв (я думаю) в использовании git reset- отношения между репо, индексом и рабочей областью являются проблемой.
Мальволио
8

Полезный прием, позволяющий избежать создания временных файлов исправлений:

git diff | patch -p1 -d [dst-dir]
slowstart
источник
Именно то, что я хотел. Также отлично работает с тайниками! git stash show -p stash@{3} | patch -p1 -d [dst-dir]
17