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

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

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

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

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


person Nick Vanderbilt    schedule 02.03.2010    source источник
comment
comment
Исключенный ответ и другие на сегодняшний день ответят, как скопировать содержимое файла, это то, что я хотел сам, когда нашел его. Однако при точном чтении Ник хотел внести изменения, а не полный текст, и файл в master может отличаться от experiment, например. может содержать изменения, слитые из других веток, которые будут потеряны при копировании файла. P.S. с другой стороны, он не хочет объединяться, но, насколько я знаю, термин git merge предназначен только для ветки, а не для конкретного файла, поэтому здесь нет противоречия.   -  person Alexei Martianov    schedule 11.04.2019


Ответы (11)


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 --source experiment -- app.js

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

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

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

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

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

Как упоминает Frosty в комментарии:

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

Но для git checkout или git show вы можете ссылаться на любую нужную ревизию, как показано в вопросе SO git checkout версия файла в 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

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

person VonC    schedule 02.03.2010
comment
Одно замечание: вы получите только самое последнее состояние app.js, вы не получите никакой истории, перенесенной из ветки эксперимента. - person Frosty; 02.03.2010
comment
Поэтому я не могу импортировать файл из мастера в другую ветку, только из других веток в мастер. Мысли? - person ThomasReggi; 06.06.2014
comment
@ThomasReggi, вы должны иметь возможность импортировать (оформить заказ) файл из любой ветки в любую текущую ветку. Если вы не можете, это может быть хорошим вопросом, который можно задать здесь, с конкретными деталями, такими как точное сообщение об ошибке и используемая версия Git и ОС. - person VonC; 06.06.2014
comment
У меня все заработало, я хотел импортировать файл, который не скачивал с github. Извините, @VonC! Значит, это был всего лишь импорт того же файла. - person ThomasReggi; 07.06.2014
comment
В подкаталоге вы также можете использовать experiment:./app.js. (Вам не нужно указывать полный путь.) Я узнал об этом благодаря очень полезному сообщению об ошибке, которое мне дал git: Возможно, вы имели в виду mybranch: full / path / to / my / file.xsl 'aka' mybranch :. /file.xsl '? Да! Не думаю, что я когда-либо был так обрадован сообщением о фатальной ошибке. - person Evan Lenz; 08.07.2015
comment
@EvanLenz - великолепно звучит! Какую версию Git вы используете? - person VonC; 08.07.2015
comment
@vehsakul синтаксис предназначен для извлечения файла из любой ветки: git checkout $REVISION -- $FILENAME. experiment@{yesterday} означает вчерашнюю версию ветки experiment, даже если вы находитесь в ветке master. - person VonC; 21.11.2015
comment
Я вижу, что файл проверки сразу же добавляется в индекс после этой операции (как в случае внесения изменений). - person Tomasz Gandor; 05.08.2016
comment
@TomaszGandor Да, я упоминаю, что в stackoverflow.com/a/21066489/6309, где git show не изменяет индекс , но git checkout изменяет индекс. - person VonC; 05.08.2016
comment
Зачем вы используете --, я сделал то же самое и без него. Я что-то упускаю ? - person wviana; 09.02.2017
comment
@wviana Для отделения параметров от аргументов: stackoverflow.com/a/1192194/6309 - person VonC; 09.02.2017
comment
На мастере я пробовал git checkout some_branch -- my.file, но он дал мне fatal: invalid reference: some_branch. Пришлось сначала сделать git checkout some_branch, затем git checkout master, затем git checkout some_branch -- my.file, чтобы получить этот файл только из ветки. - person Lidia; 24.03.2017
comment
@lid, вероятно, потому что у вас был только origin / some_branch. - person VonC; 24.03.2017
comment
@VonC Да, origin / some_branch работает. Он также дает мне последнюю версию файла в ветке, что я и хотел. Спасибо! - person Lidia; 24.03.2017
comment
Я хотел бы упомянуть здесь, что вы также можете сделать это из тайника: git checkout stash -- app.js. Это очень полезно, если вы работаете над двумя ветвями и не хотите коммитить. - person schmijos; 14.11.2018
comment
@schmijos Спасибо. Я включил ваш комментарий в ответ для большей наглядности. - person VonC; 14.11.2018
comment
Это просто копирование файла? Что будет, если мы объединимся? - person Terry Tan; 02.02.2019
comment
@TerryTan Что произойдет, если мы объединимся ?: не более (или менее), чем если бы вы вручную скопировали содержимое этого файла в своей ветке: если в обеих ветвях нет дальнейших изменений (для этого файла), при слиянии будет проигнорировано указанное файл. - person VonC; 02.02.2019
comment
@PhilipRego Я бы хотел проиллюстрировать этот случай в новом отдельном вопросе: так я буду знать, что исправить. - person VonC; 21.05.2019
comment
не мог воспроизвести - person Philip Rego; 21.05.2019
comment
Я нашел это. Это должно быть рассмотрено в этом ответе. Видите, я получаю недействительную ссылку, но не могу получить ветку. $ git checkout issue / 2020.07.04 - pom.xml fatal: недопустимая ссылка: issue / 2020.07.04 $ git fetch origin issue / 2020.07.04 От example.com * проблема ветки / 2020.07.04 -› FETCH_HEAD - person Philip Rego; 21.05.2019
comment
@PhilipRego Интересно. Для тестирования я все же думаю, что был бы полезен отдельный вопрос, более подробно иллюстрирующий ошибку (с ОС и версией Git). Как только мы все поймем, что происходит не так, я отредактирую этот ответ. - person VonC; 21.05.2019
comment
Стек больше не позволяет мне задавать вопросы. git версия 2.17.1.windows.2 Windows 7 - person Philip Rego; 21.05.2019
comment
@PhilipRego Как я уже упоминал, этот вопрос лучше решить как новый. Вы можете подумать о создании новой учетной записи только для этой цели (и запросить слияние этой новой учетной записи позже) - person VonC; 05.06.2019
comment
См. Ответ Дмитрия Автономова. - person Fried Brice; 05.12.2019
comment
@FriedBrice Посмотрите мой ответ: в наши дни это было бы git restore -s new-feature path/to/app.js - person VonC; 05.12.2019
comment
Что делать, если мне нужно изменить папку, в которую я хочу скопировать мой код? - person Pooja Sonkar; 10.06.2021
comment
@PoojaSonkar Полагаю, вам нужно сначала восстановить, а затем переименовать папку. Если я неверно истолковал ваш комментарий, задайте новый вопрос с наглядным примером. - person VonC; 10.06.2021

Все намного проще, используйте для этого 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 имени ветки, чтобы получить файл как именно в этом коммите.

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

person Dmitry Avtonomov    schedule 05.04.2012
comment
Я считаю полезным всегда указывать источник git checkout origin/source_branch path/to/file, потому что, если вы не обновили исходную ветку своего локального репо, вы можете получить старую версию файла ... Спросите меня, откуда я знаю. ;) - person talyric; 15.05.2014
comment
Разве мы не должны делать git checkout origin source_branch path/to/file, чтобы получить ветку на пульте дистанционного управления? Так это ОЧЕНЬ последняя версия файла? См. Эту ссылку, чтобы узнать о различиях между этими двумя командами: stackoverflow.com/questions/26125162/ - person Mymozaaa; 03.02.2016
comment
@Mymozaaa в вопросе не упоминались пульты дистанционного управления, поэтому предполагается, что это чисто локальное репо - person Dmitry Avtonomov; 04.02.2016
comment
Будет ли эта команда отображать историю файла или только последнюю версию файла? - person user1366265; 11.05.2016
comment
@ user1366265 эта команда поместит файл в том виде, в котором он был в конкретном коммите, который вы указали, или в заголовке указанной вами ветви. Не существует такой вещи, как история файла, вся историческая информация хранится только в ветках. - person Dmitry Avtonomov; 11.05.2016
comment
@talyric - но если вы еще не потянули и не принесли, вы все равно будете тостом. После выборки все равно хорошо сделать git push . origin/otherbranch:otherbranch (обновить локальную ветку, не проверяя ее, но использовать только для быстрой перемотки вперед). - person Tomasz Gandor; 05.08.2016
comment
Кажется, это автоматически обрабатывает извлеченный файл. Можно ли сделать то же самое без постановки? - person bluenote10; 14.11.2017
comment
git fetch перед расчетом - person majurageerthan; 17.04.2020

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.
person Sarath    schedule 11.05.2018
comment
@PhilipRego Это правильный ответ. Я предполагаю, что в вашей ветке используются разные заглавные буквы или знаки препинания, или у вас есть только удаленная ветка, а не локальная. См. Документ git checkout: git -scm.com/docs/git-checkout#Documentation/ - person Bret; 12.06.2019
comment
@Bret Я обнаружил, что это не работает, если в названии ветки есть точка. Я предложил отредактировать - person Philip Rego; 12.06.2019
comment
Это лучший ответ. Я бы хотел, чтобы этот ответ был наивысшим. Текущий самый высокий очень запутанный и непростой - person Russell Lego; 30.10.2019

Дополнение к ответам 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

or

git checkout experiment -- app.js
person AlexLordThorsen    schedule 08.12.2015
comment
Прохладный! Ненавижу указывать длинные пути. Является ли двойной дефис (--) между именем ветки и путями необязательным? Это только для того, чтобы пути, начинающиеся с тире, не рассматривались как опции / переключатели? - person Tomasz Gandor; 05.08.2016
comment
Честно говоря, не знаю. Я даже не заметил, что забыл о двойном тире, пока вы не указали на это. - person AlexLordThorsen; 06.08.2016
comment
@TomaszGandor -- не является обязательным, но его полезнее избегать конфликтов с именами веток. Например, git checkout -- foo означает извлечение файла foo из HEAD (т. Е. Перезапись локальных изменений в foo, т.е. подмножество git reset --hard), но git checkout foo может означать, что или пойдем для перехода к foo. - person Alois Mahdal; 23.02.2018

Все о проверке файлов или каталогов в git

1. Как извлечь один или несколько файлов или каталогов из другой ветки или зафиксировать хэш в текущей извлеченной ветке:

# check out all files in <paths> from branch <branch_name>
git checkout <branch_name> -- <paths>

Источник: http://nicolasgallagher.com/git-checkout-specific-files-from-another-branch/.

См. Также man git checkout.

Примеры:

# Check out "somefile.c" from branch `my_branch`
git checkout my_branch -- somefile.c

# Check out these 4 files from `my_branch`
git checkout my_branch -- file1.h file1.cpp mydir/file2.h mydir/file2.cpp

# Check out ALL files from my_branch which are in
# directory "path/to/dir"
git checkout my_branch -- path/to/dir

Если вы не укажете branch_name, автоматически предполагается, что это HEAD, который является вашей самой последней фиксацией ветки, выбранной в данный момент. Таким образом, вы также можете просто проверить файл somefile.c и перезаписать любые локальные незафиксированные изменения:

# Check out "somefile.c" from `HEAD`, to overwrite any local, uncommitted
# changes
git checkout -- somefile.c

# Or check out a whole folder from `HEAD`:
git checkout -- some_directory

2. Дальше: как извлечь любой файл из любой ветки или зафиксировать хэш в любое место на вашем компьютере (ОЧЕНЬ ПОЛЕЗНО!):

# General form
git show my_branch_or_commit_hash:my_file.cpp > any/path/my_file.cpp

# Example: check out `main.cpp` from 3 commits ago in your currently-checked-out
# branch (3 commits prior to `HEAD`, or `HEAD~3`) into a temporary directory
mkdir ../temp
git show HEAD~3:main.cpp > ../temp/main_old.cpp

Источник, из которого я это узнал: ответ @Jakub Narębski на: git-checkout старая версия файла под новым именем

3. Что делать, если вы находитесь в процессе внесения изменений git merge, git cherry-pick, git rebase или git revert?

Что ж, в таком случае вам лучше сделать так:

# Keep `--theirs` for all conflicts within this file
git checkout --theirs -- path/to/some/file
# OR: keep `--ours` for all conflicts within this file
git checkout --ours -- path/to/some/file

OR:

# Keep `--theirs` for all conflicts within files inside this dir
git checkout --theirs -- path/to/some/dir
# OR: keep `--ours` for all conflicts within files inside this dir
git checkout --ours -- path/to/some/dir

НЕ заполняйте обычную checkout форму в предыдущем разделе перед этим, если только вы этого не хотите. См. раздел ПРЕДУПРЕЖДЕНИЕ ПРЕДУПРЕЖДЕНИЕ ПРЕДУПРЕЖДЕНИЕ в моем ответе здесь: Кто такие мы и кто они согласно Git ?.

РАБОТА С path does not have our version или path does not have their version ОШИБКАМИ:

Если вы когда-нибудь увидите такие ошибки:

error: path 'path/to/some/dir/file1.cpp' does not have our version
# OR
error: path 'path/to/some/dir/file1.cpp' does not have their version

... при выполнении приведенных выше команд вам просто нужно сначала git rm эти файлы, а затем снова попробовать команду git checkout --ours или git checkout --theirs. См. Мой ответ здесь для подробного объяснения этих команд, включая форму для автоматического поиска и удаления этих файлов с ошибками: git checkout - часы, когда спецификация файла включает удаленный файл.

4. Что делать, если вы хотите сбросить определенный файл или каталог, чтобы он точно соответствовал состоянию этого файла или каталога в другой фиксации или ветке?

В этом случае git checkout my_branch -- some_file_or_dir НЕ достаточно, потому что если у вас есть файлы в указанном каталоге, которые существуют в вашей текущей ветке или фиксации, но НЕ существуют в my_branch, тогда вы хотите, чтобы они были удалены локально, но git checkout НЕ удаляет какие-либо файлы, которые существуют локально, но не в указанной фиксации, а только перезаписывает файлы локально их версиями из указанной фиксации. Итак, чтобы также удалить файлы локально, которых там не должно быть, чтобы то, что у вас получилось локально, было точной копией того, что у вас есть на my_branch, вы должен сделать следующее:

git reset my_branch -- path/to/some/file_or_dir
git checkout-index -fa
git clean -fd
git commit -m "hard reset path/to/some/file_or_dir to its state \
as it was at my_branch"

Подробнее см. Мой собственный ответ здесь: Почему git не может выполнять аппаратный / программный сброс по пути?.

Смотрите также:

  1. Я показываю еще несколько примеров git checkout в своем ответе здесь: Кто такие мы и кто они согласно Git?.
  2. [мой ответ на Как выполнить сброс --soft или --hard git по пути] Почему git не может выполнять аппаратный / программный сброс по пути?
  3. git-checkout более старая версия файл под новым именем
  4. [мой ответ] git checkout - часы, когда спецификация файла включает удаленный файл
  5. [мой ответ] Как с помощью git сбросить рабочее дерево (состояние локальной файловой системы) до состояния индекса (поэтапные файлы)?
person Gabriel Staples    schedule 11.12.2020

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

git restore -s my-other-branch -- ./path/to/file

Флаг -s - это сокращение от source, т. Е. Ветки, из которой вы хотите вытащить файл.

(Выбранный ответ очень информативен, но также немного ошеломляет.)

person Conner Smith    schedule 03.09.2020
comment
Это был для меня лучший ответ, короткий и конкретный - person Hosar; 10.06.2021
comment
Должен быть принятый ответ! - person flagman; 09.07.2021

Или, если вам нужны все файлы из другой ветки:

git checkout <branch name> -- .
person Jester    schedule 02.02.2017
comment
Первоначальный квестон содержит всего один файл. - person greatvovan; 11.07.2017
comment
это заменяет существующие файлы, а не объединяет - person Amare; 13.09.2018
comment
Это . имеет огромное значение: вместо перехода в другую ветку он копирует оттуда все файлы, оставляя вас на текущей. Вы получаете содержимое из другой ветки, не заходя в нее. - person Xeverous; 20.09.2018
comment
Почему -1: первое. это ответ, но не на заданный вопрос. Во-вторых, это безоговорочная перезапись всех файлов в текущем каталоге и всех подкаталогах. Возможно, вам не следует думать, что OP - профессионал Git. По моему опыту, многие люди относятся к команде Git как к волшебным заклинаниям, и такая форма команды действительно опасна. ИМО, если вы также позволите мне совет, о котором не спрашивали, вы сделаете сообщество лучше, удалив свой ответ. - person kkm; 26.02.2021

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

Это прагматический подход, который напрямую не отвечает на OP, но некоторые сочли его полезным:

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

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

person fearless_fool    schedule 06.04.2019
comment
Однако копирование и вставка необработанного файла может вызвать нежелательные изменения символов в вашем git diff. Безопаснее сохранить файл прямо в свой проект, чтобы избежать изменений. - person Philip Rego; 05.06.2019

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

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

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

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

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

git apply ~/app_changes.git

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

person Santi    schedule 30.04.2020
comment
Это решение также работает, когда файл не существует в текущей ветке - person Thomio; 19.02.2021

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

git checkout 06f8251f путь_к_файлу

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

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

person arupjbasu    schedule 25.07.2019
comment
Спасибо, что нашли время ответить! Но это не дает ответа на вопрос, и хороший ответ, который очень подробно описан, уже был опубликован 9 лет назад. Нет необходимости задавать вопрос. - person Turtle; 25.07.2019
comment
Это допустимый практический сценарий. Ответ правильно относится к ветке, но как насчет того, чтобы посмотреть на конкретный коммит ветки. - person arupjbasu; 25.07.2019

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> 

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

person Rohit Saini    schedule 26.07.2019