Как получить только один файл из другой ветки

1267

Я использую git и работаю над веткой master. Эта ветка имеет файл с именем app.js.

У меня есть experimentветка, в которой я сделал кучу изменений и кучу коммитов. Теперь я хочу , чтобы объединить все изменения , сделанные только app.jsиз experimentв masterотрасли.

Как я могу это сделать?

Еще раз не хочу слияния. Я просто хочу перенести все изменения app.jsиз experimentветки в masterветку.

Ник Вандербильт
источник
1
Исключенный ответ и другие на сегодняшний день отвечают, как копировать содержимое файла, это то, чего я сам хотел, когда нашел этот. Однако, если прочитать точно, Ник хотел внести изменения, а не полный текст, и файл masterможет отличаться experiment, например, может содержать изменения, объединенные из других ветвей, которые будут потеряны в файле, просто скопированном. PS С другой стороны, он не хочет сливаться, но, насколько я знаю, git mergeтермин относится только к ветке, а не к конкретному файлу, поэтому здесь нет противоречий.
Алексей

Ответы:

1605
git checkout master               # first get back to master
git checkout experiment -- app.js # then copy the version of app.js 
                                  # from branch "experiment"

Смотрите также git, как отменить изменения одного файла?


Обновление августа 2019 года, Git 2.23

С новыми командами git switchи git restoreкомандами это будет:

git switch master
git restore -s experiment -- app.js

По умолчанию восстанавливается только рабочее дерево.
Если вы также хотите обновить индекс (то есть восстановить содержимое файла и добавить его в индекс одной командой):

git restore -s experiment --staged --worktree -- app.js
# shorter:
git restore -s experiment -WS -- app.js

Как отмечает в комментариях Якуб Наребски :

git show experiment:path/to/app.js > path/to/app.js

тоже работает, за исключением того, что, как подробно описано в вопросе SO « Как извлечь отдельный файл из определенной ревизии в Git? », вам нужно использовать полный путь из корневого каталога репозитория.
Отсюда путь / к / app.js, который использовал Якуб в своем примере.

Как Морозный упоминает в комментарии:

вы получите только самое последнее состояние app.js

Но для git checkoutили git showвы можете ссылаться на любую ревизию, которую хотите, как показано в вопросе SO « git checkout revision of the file in git gui »:

$ git show $REVISION:$FILENAME
$ git checkout $REVISION -- $FILENAME

будет то же самое, если $ FILENAME - это полный путь к версионному файлу.

$REVISIONможет быть как показано в git rev-parse:

experiment@{yesterday}:app.js # app.js as it was yesterday 
experiment^:app.js            # app.js on the first commit parent
experiment@{2}:app.js         # app.js two commits ago

и так далее.

Schmijos добавляет в комментариях :

Вы также можете сделать это из тайника:

git checkout stash -- app.js

Это очень полезно, если вы работаете над двумя ветками и не хотите фиксировать.

VonC
источник
13
Одно замечание: вы получите только самое последнее состояние app.js, вы не получите никакой истории, перенесенной из ветви эксперимента.
Морозное
2
@ThomasReggi вы должны иметь возможность импортировать (извлекать) файл из любой ветви в любую текущую ветку. Если вы не можете, это может быть хороший вопрос, чтобы задать здесь, с конкретными деталями, такими как точное сообщение об ошибке и используемая версия Git и ОС.
VonC
2
В подкаталоге вы также можете использовать experiment:./app.js. (Вам не нужно указывать полный путь.) Я узнал об этом благодаря очень полезному сообщению об ошибке, которое git дал мне: «Вы имели в виду« mybranch: full / path / to / my / file.xsl aka »mybranch: ./file.xsl?» Да, я сделал! Я не думаю, что когда-либо был в восторге от фатальной ошибки.
Эван Ленц
1
@TomaszGandor Да, я упоминаю, что в stackoverflow.com/a/21066489/6309 , где git show не будет изменять индекс, но git checkout действительно изменяет индекс.
VonC
1
@FriedBrice Смотрите мой ответ: в эти дни это будетgit restore -s new-feature path/to/app.js
VonC
360

Все намного проще, используйте для этого git checkout.

Предположим, you're on masterветвь, чтобы получить app.js from new-featureветку:

git checkout new-feature path/to/app.js

// note that there is no leading slash in the path!

Это принесет вам содержимое нужного файла. Вы можете, как всегда, использовать часть sha1 вместо имени новой ветки, чтобы получить файл, который был в этом конкретном коммите.

Примечание : new-featureдолжен быть локальный филиал, а не удаленный.

Дмитрий Автономов
источник
78
Я считаю полезным всегда указывать источник, git checkout origin/source_branch path/to/fileпотому что, если вы не обновили исходную ветку вашего локального репозитория, вы можете получить старую версию файла ... Спросите меня, откуда я знаю. ;)
Талицкая
3
@Mymozaaa в вопросе не упоминались пульты, поэтому предполагалось, что это чисто локальное репо
Дмитрий Автономов
1
Принесет ли эта команда историю файла или только последнюю версию файла?
user1366265
1
@ user1366265 эта команда поместит файл в том виде, в котором он был указан в конкретном коммите, который вы указали, или в заголовок ветви, которую вы укажете. Нет такой вещи, как «история файла», вся историческая информация хранится только в ветвях.
Дмитрий Автономов
3
Это, кажется, автоматически ставит извлеченный файл. Можно ли сделать то же самое без постановки?
bluenote10
44
git checkout branch_name file_name

Пример:

git checkout master App.java

Это не будет работать, если в названии вашей ветки есть точка.

git checkout "fix.june" alive.html
error: pathspec 'fix.june' did not match any file(s) known to git.
Сарат
источник
@PhilipRego Этот ответ правильный. Я предполагаю, что в вашей ветке есть другая заглавная буква или пунктуация, или у вас есть только удаленная ветка, а не локальная. Смотрите документацию по git checkout: git-scm.com/docs/git-checkout#Documentation/…
Брет
@ Брет Я обнаружил, что это не работает, когда имя ветви имеет точку. Я предложил правку
Филипп Рего
Это лучший ответ. Я бы хотел, чтобы этот ответ был самым высоким. Текущий наивысший уровень очень запутанный и
Рассел Лего
41

Дополнительно к ответам VonC и chhh.

git show experiment:path/to/relative/app.js > app.js
# If your current working directory is relative than just use
git show experiment:app.js > app.js

или

git checkout experiment -- app.js
AlexLordThorsen
источник
2
Круто! Я ненавижу указывать длинные пути. Является ли двойная черта ( --) между именем ветви и путями необязательной? Только для того, чтобы пути, начинающиеся с тире, не рассматривались как опции / переключатели?
Томаш Гандор
Честно говоря, я не знаю. Я даже не заметил, что забыл двойную черту, пока ты не указал на это.
AlexLordThorsen
6
@TomaszGandor --Необязательно, но более полезно избегать конфликтов с именами веток. Например, git checkout -- fooозначает «извлечь файл foo из HEAD» (т. Е. Перезаписать локальные изменения в foo , т. Е. Подмножество git reset --hard), но git checkout fooможет означать это или «давайте перейдем к ветви foo ».
Алоис Махдал
8

Или, если вы хотите, чтобы все файлы из другой ветки:

git checkout <branch name> -- .
шут
источник
24
Начальный квест содержит «только один файл».
Великована
1
это заменяет существующие файлы, а не объединяет их
Amare
3
Это .имеет огромное значение: вместо того, чтобы перемещаться в другую ветку, он копирует все файлы оттуда, оставляя вас в текущей. Вы получаете содержимое из другой ветки, не заходя в нее.
Xeverous
4

Просмотрите файл на github и вытащите его оттуда

Это прагматичный подход, который не отвечает непосредственно на ФП, но некоторые нашли его полезным:

Если соответствующая ветка находится на GitHub, то вы можете перейти к нужной ветке и файлу с помощью любого из множества инструментов, которые предлагает GitHub, затем нажать «Raw», чтобы просмотреть простой текст, и (необязательно) скопировать и вставить текст как желательно.

Мне нравится этот подход, потому что он позволяет вам просмотреть удаленный файл целиком, прежде чем перетащить его на локальный компьютер.

fearless_fool
источник
2
Однако копирование и вставка необработанного файла может вызвать нежелательные изменения символов в вашем git diff. Безопаснее сохранить файл непосредственно в вашем проекте, чтобы гарантировать отсутствие изменений.
Филипп Рего
0

Если вы хотите файл из определенного коммита (любой ветви), скажем 06f8251f

git checkout 06f8251f path_to_file

например, в windows:

git checkout 06f8251f C: \ A \ B \ C \ D \ file.h

arupjbasu
источник
1
Спасибо, что нашли время ответить! Но это не отвечает на вопрос, и хороший, очень подробный ответ был опубликован 9 лет назад. Нет необходимости поднимать вопрос.
Натан
Это действительный практический сценарий. Ответ правильно относится к ветви, но как насчет просмотра конкретного коммита ветви.
Arupjbasu
0

Другой способ - создать патч с отличиями и применить его, например, в основной ветке. Допустим, последний коммит перед тем, как вы начали работать с app.js, был 00000aaaaa, а коммит, связанный с нужной версией, - 00000bbbbb

Вы запускаете это на ветке эксперимента:

git diff 00000aaaaa 00000bbbbb app.js > ~/app_changes.git

Это создаст файл со всеми различиями между этими двумя коммитами для app.js, который вы можете применить где угодно. Вы можете хранить этот файл в любом месте за пределами проекта

Затем в мастере вы просто запускаете:

git apply ~/app_changes.git

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

Santi
источник
-3
git checkout master               -go to the master branch first
git checkout <your-branch> -- <your-file> --copy your file data from your branch.

git show <your-branch>:path/to/<your-file> 

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

Рохит Сайни
источник