Как выбрать только изменения только для одного файла, а не для всего коммита

108

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

как он
источник

Ответы:

137

У вас есть разные варианты в зависимости от того, чего вы хотите достичь:

Если вы хотите, чтобы содержимое файла было таким же, как в целевой ветке, вы можете использовать git checkout <branch> -- <filename>. Однако это не будет «выделять» изменения, произошедшие за один коммит, а просто принимает результирующее состояние указанного файла. Поэтому, если вы добавили строку в коммит, но предыдущие коммиты изменились больше, и вы хотите добавить только эту строку без этих других изменений, то проверка - это не то, что вам нужно.

В противном случае, если вы хотите применить патч, введенный в фиксации, только к одному файлу, у вас есть несколько вариантов. Вы можете запустить git cherry-pick -n, то есть без фиксации, отредактировать фиксацию (например, сбросить все файлы, используя git reset -- .и добавить только тот файл, который вы действительно хотите изменить, используя git add <filename>). Или вы можете создать разницу для файла и затем применить ее:

git diff <branch>^..<branch> -- <filename> | git apply
тыкать
источник
22

Создайте patch fileи примените его.

git diff branchname -- filename > patchfile
git apply patchfile

РЕДАКТИРОВАТЬ:

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

git show sha1 -- filename > patchfile
Сайлеш
источник
1
git diff sha1(или git diff branch- то же самое, если ветвь указывает на тот же хэш) будет производить только различие текущего рабочего каталога по отношению к этому хешу, но не то, что изменяет коммит, введенный сам по себе.
poke
Верный. Отредактировал ответ. Спасибо.
Сайлеш
1
-1 git checkoutс именем файла - правильный молоток для этого гвоздя. Оба эти варианта излишне сложны.
Рейн Хенрихс
7
В данном конкретном случае да. Но в целом, если вы хотите выбрать изменения из фиксации, внесенной в конкретный файл, checkoutэто не сработает, так как это может включать другие нежелательные предыдущие изменения и может не содержать изменений, сделанных в текущей ветке.
Сайлеш
11

Еще одна удобная вещь - получить патч локально, а затем использовать:

git checkout {<name_of_branch>, commit's SHA} <path to the file> 

Но это не вишенки.

0x90
источник
2
Предупреждение: как @poke говорит в своем ответе, это не копирует изменения; он копирует все состояние файла. Поэтому, если вы хотите добавить изменения фиксации в файл, то, проверяя таким образом, вы в конечном итоге перезаписываете любые новые изменения, что нехорошо.
Александр Берд
7

В Git все готово :)

Просто используйте git checkout <sha> <path-to-file>

Раготэм С
источник
4
Это не вишенка - это проверяет файл полностью. Цель состоит в том, чтобы сделать конкретное изменение из фиксации. Часто это одно и то же, но иногда это не так.
AndrewF
6
git checkout the_branch_with_the_change the/path/to/the/file/you/want.extension

это работает, если вы хотите, чтобы один файл из другой ветки был скопирован в текущую рабочую ветку

Исмаил Икбал
источник
1
Будьте осторожны, изменения, внесенные в файл, которых нет в версии из другой ветки, будут потеряны.
Патрик Шлютер
С этим согласен. это полезно, если вам просто нужна копия файла, и вы хотите изменить ее в текущей ветке
Исмаил Икбал,
1
Можно использовать globs (путь / *) и указать более одного пути / файла
Тодд
1

Это то, что вы ищете:

git checkout target-branch sha1 path/to/file

sha1 не является обязательным

Руслан Осипов
источник
11
нет, «выбрать изменения в фиксации» не означает «выбрать весь файл»
Abyx
1

Я обычно использую git ls-tree

просто сделать:

git ls-tree -r <commit-id> |grep 'your filename'
# there will be output that shows a SHA1 of your file
git show ${SHA1 of your file} > 'your filename'

Это напечатает все имена файлов, соответствующие вашему grep, и выдаст ключи SHA1 для файлов в фиксации.

Git show также можно использовать с файлами за пределами вашей ветки. использование >из вашей оболочки для передачи вывода в файл дает вам результат, который вы ищете.

Alex
источник
0

Вы можете попробовать это сделать:

git show COMMIT_ID -- path/to/specific-file | git apply

Например:

git show 3feaf20 -- app/views/home/index.html | git apply
arashb31
источник
-9
git reset HEAD~1

перемещает файлы на стадию предварительной фиксации

git stash

удаляет из памяти

Теперь ваша ветка довольно чистая (возвращена к предыдущей фиксации)

Венката
источник