How to get just one file from another branch
Asked Answered
F

15

2018

I have a main branch with a file called app.js. I made changes to this file on an experiment branch.

I want to apply only the changes made to app.js from experiment onto the main branch.

Fowl answered 2/3, 2010 at 15:15 Comment(2)
this is a duplicate of How do I copy a version of a single file from one git branch to another?Brannen
Excepted answer and others as of today answer how to copy file's contents, that's what I wanted myself when I found that one. However, if read exactly, Nick wanted to bring changes, not full text, and file in master may diverge from experiment, e.g. can contain changes merged from other branches which would be lost in file is just copied. P.S. on the other hand he does not want to merge, but as far as I know git merge term is for branch only, not for specific file, so no contradiction here.Blink
W
2452
git checkout main                 # first get back to main
git checkout experiment -- app.js # then copy the version of app.js 
                                  # from branch "experiment"

See also Undo working copy modifications of one file in Git.


Update August 2019, Git 2.23

With the new git switch and git restore commands, that would be:

git switch main
git restore --source experiment -- app.js

By default, only the working tree is restored.
If you want to update the index as well (meaning restore the file content, and add it to the index in one command):

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

As Jakub Narębski mentions in the comments:

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

works too, except that, as detailed in the SO question "How to retrieve a single file from specific revision in Git?", you need to use the full path from the root directory of the repo.
Hence the path/to/app.js used by Jakub in his example.

As Frosty mentions in the comment:

you will only get the most recent state of app.js

But, for git checkout or git show, you can actually reference any revision you want, as illustrated in the SO question "git checkout revision of a file in git gui":

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

would be the same is $FILENAME is a full path of a versioned file.

$REVISION can be as shown in 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

and so on.

schmijos adds in the comments:

you also can do this from a stash:

git checkout stash -- app.js

This is very useful if you're working on two branches and don't want to commit.

Waggery answered 2/3, 2010 at 15:23 Comment(19)
One note: you will only get the most recent state of app.js, you will not get any history carried over from the experiment branch.Zygo
In a sub-directory, you can also use experiment:./app.js. (You don't have to specify the full path.) I learned this thanks to the very helpful error message git gave me: "Did you mean 'mybranch:full/path/to/my/file.xsl' aka 'mybranch:./file.xsl'?" Yes, I did! I don't think I've ever been so delighted by a fatal error message.Apoplectic
@vehsakul the syntax is for a checkout of a file on any branch: git checkout $REVISION -- $FILENAME. experiment@{yesterday} means the version as of yesterday on the branch experiment, even if you are on master branch.Waggery
I see that the checkout file is immediately added to index after this operation (as in "Changes to be commited").Phenylalanine
@TomaszGandor Yes, I mention that in https://mcmap.net/q/11466/-why-do-checkout-and-reset-change-the-index, where git show would not modify the index, but git checkout does modify the index.Waggery
Why do you use --, I've done the same without it. Am I missing something ?Goldberg
@Goldberg It is to separate options from arguments: https://mcmap.net/q/11419/-deleting-a-badly-named-git-branchWaggery
While on master I tried git checkout some_branch -- my.file but it gave me fatal: invalid reference: some_branch. Had to first do git checkout some_branch, then git checkout master, then git checkout some_branch -- my.file to only get that file from branch.Vashti
@lid probably because you only had origin/some_branch.Waggery
@Waggery Yes, origin/some_branch works. It also gets me the latest version of the file on the branch, which is what I wanted. Thanks!Vashti
I'd like to mention here, that you also can do this from a stash: git checkout stash -- app.js. This is very useful if you're working on two branches and don't want to commit.Mouse
@Mouse Thank you. I have included your comment in the answer for more visibility.Waggery
Is that just copying a file? What happens if we merge?Function
@TerryTan "What happens if we merge?": nothing more (or less) than if you manually copied over the content of that file in your branch: if there is no further modification (for that file) in both branches, a merge will ignore said file.Waggery
@PhilipRego I would like to see that case illustrated in a new separate question: that way, I will know what to fix.Waggery
I found it. It should be covered in this answer. See that I get "invalid reference", but im able to fetch the branch. $ git checkout issue/2020.07.04 -- pom.xml fatal: invalid reference: issue/2020.07.04 $ git fetch origin issue/2020.07.04 From example.com * branch issue/2020.07.04 -> FETCH_HEADConcertino
@PhilipRego Interesting. For testing, I still think a separate question illustrating the bug in more details (with OS and Git version) would be useful. Once we all understand what is going wrong, I will edit this answer.Waggery
Can we use the git checkout command for multiple files at the same time? (maybe separating multiple paths with spaces on after the other?)Mandeville
@Mandeville First, not git checkout, which is obsolete, and replaced (in your case) with [ git restore](https://mcmap.net/q/12502/-how-to-reset-all-files-from-working-directory-but-not-from-staging-area). Second, you can specify multiple files: git restore -- file1 file2 file3 or git restore -- *.css. See git restore for additional examples. On the double-hyphen convention, see here.Waggery
A
628

Everything is much simpler. Use git checkout for that.

Suppose you're on the master branch. To get app.js from the new-feature branch, do:

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

// Note that there isn't any leading slash in the path!

This will bring you the contents of the desired file. You can, as always, use part of the SHA-1 hash value instead of the new-feature branch name to get the file as it was in that particular commit.

Note: new-feature needs to be a local branch, not a remote one.

Aschim answered 5/4, 2012 at 8:48 Comment(8)
I find it helpful to always specify the origin git checkout origin/source_branch path/to/file because if you have neglected to update the source branch of your local repo, you might get an old version of the file...Ask me how I know. ;)Freemasonry
Should'nt we do git checkout origin source_branch path/to/file to get the branch on the remote? So it is VERY the last version of the file? See this link for difference between these two commands : #26125662Vaticinate
@Vaticinate the question did not mention remotes, thus the assumption that it is a purely local repoAschim
Will this command bring the file's history, or just the last version of the file?Dhammapada
@Dhammapada this command will put the file as it was in the particular commit you specify or the head of the branch you specify. There is no such a thing as "history of a file", all history information is only stored in branches.Aschim
@Freemasonry - but if you haven't pulled or fetched, you'll be toast anyway. After fetch it's good to do a git push . origin/otherbranch:otherbranch anyway (update local branch without checking it out, but use only for fast-forward).Phenylalanine
This seems to automatically stage the checked-out file. Is it possible to do the same without staging?Follicle
git fetch before checkoutYvette
W
99
git checkout branch_name file_name

Example:

git checkout master App.java

This will not work if your branch name has a period in it.

git checkout "fix.june" alive.html
error: pathspec 'fix.june' did not match any file(s) known to git.
Waterless answered 11/5, 2018 at 9:43 Comment(2)
@PhilipRego This answer is correct. I'm guessing there is different capitalization or punctuation in your branch, or you only have a remote branch and not a local one. See the git checkout doc: git-scm.com/docs/git-checkout#Documentation/…Patricapatrice
@Patricapatrice I found it doesn't work when the branch name has a period. I suggested an editConcertino
N
96

All about checking out files or directories in git

1. How to check out one or more files or directories from another branch or commit hash into your currently-checked-out branch:

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

Source: http://nicolasgallagher.com/git-checkout-specific-files-from-another-branch/.

See also man git checkout.

Examples:

# 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"
# - WARNING!: If you have uncommitted changes in this dir, they will be
#   permanently lost when you run this command! See my lamentations in my
#   comment here:
#   https://mcmap.net/q/11444/-git-how-to-undo-a-checkout-of-unstaged-files-which-discards-local-changes/2689318?noredirect=1#comment135379081_2689318
git checkout my_branch -- path/to/dir

If you don't specify, the branch_name it is automatically assumed to be HEAD, which is your most-recent commit of the currently-checked-out branch. So, you can also just do this to check out "somefile.c" and have it overwrite any local, uncommitted changes:

# 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

If you have some staged deletions of the file you are trying to check out (via a previous rm somefile.c && git add somefile.c), however, then you may see this error from git:

$ git checkout -- somefile.c
error: pathspec 'somefile.c' did not match any file(s) known to git

In that case, you have to be explicit and specify a branch or commit, such as HEAD:

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

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

2. Going Further: How to check out any file or folder from any branch or commit hash into any location on your computer (VERY USEFUL!):

For individual files

# 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

Source where I learned this: @Jakub Narębski's answer to: git-checkout older revision of a file under a new name

For whole directories

You can't use git show like that for whole directories, but you can do these sequential steps instead to get an equivalent effect, so long as git status is clean and you don't have any uncommitted changes:

# Check out the commit of interest
git checkout my_branch_or_commit_hash

# Copy the directory of interest to a temporary location
mkdir temp
cp -r path/to/dir_to_copy temp/

# Check out back to your original branch
# - Note that `-` here means "the previous branch you were on". It can also be
#   written as `@{-1}`. 
#   - Therefore, calling `git checkout -` or `git checkout @{-1}` repeatedly 
#     will just keep toggling back and forth between the same two branches.
git checkout -

If your goal is just to reference a lot of old, deleted, or previous contents, however, it might be easier to just clone the repo again in a separate spot and check out the old branch in it. This way you can have one repo open for active work, and another open for referencing old data.

3. What if you're in the middle of resolving git merge, git cherry-pick, git rebase, or git revert changes?

Well, in that case, you better do the following. Note: to know which commit hash or branch --theirs and --ours are in each context, see my answer here: Who is "us" and who is "them" according to Git?:

# 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

Do NOT do the regular checkout form in the previous section before this, unless that's what you really want to do. See the "WARNING WARNING WARNING" section in my answer referenced above: Who is "us" and who is "them" according to Git?.

DEALING WITH path does not have our version or path does not have their version ERRORS:

If you ever see errors like this:

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

...when running the commands above, then you simply need to git rm those files first and then try the git checkout --ours or git checkout --theirs command again. See my answer here for a detailed explanation of these commands, including a form to automatically find and delete those errored files for you: git checkout --ours when file spec includes deleted file.

4. What if you want to reset a certain file or directory to exactly match that file or directory's state in another commit or branch?

In this case, git checkout my_branch -- some_file_or_dir is NOT enough, because if you have files in the specified directory which exist in your currently-checked-out branch or commit but do NOT exist in my_branch, then you'd like them to be deleted locally, but git checkout does NOT delete any files which exist locally but not on the specified commit, rather, it only overwrites files locally with their versions from the specified commit. So, to also delete files locally which should not be there, so that what you end up with locally is an exact copy of what you have on commit or branch my_branch, you must do the following:

# How to "hard reset" "path/to/some/file_or_dir" to its state exactly as it was
# at commit or branch `my_branch`
#
# WARNING: `git status` should be TOTALLY CLEAN before beginning this process!
# Otherwise, you risk PERMANENTLY LOSING any uncommitted changes shown by 
# `git status`, since `git clean -fd` 'f'orce deletes ALL files
# and 'd'irectories which are in your current working tree (file system), but
# which are *not* in the path you specify below in commit or branch `my_branch`.
# Therefore, anything NOT already committed gets **permanently lost** as though
# you had used `rm` on it!

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

See my own answer here for more details on this: Why git can't do hard/soft resets by path?

See also:

  1. Quick links to my answers I reference frequently and consider to be "git fundamentals":
    1. Various ways to create a branch in git from another branch
    2. All about checking out files or directories in git
    3. Who is "us" and who is "them" according to Git?
  2. I show some more of these examples of git checkout in my answer here: Who is "us" and who is "them" according to Git?.
  3. [my answer on "How to do a --soft or --hard git reset by path"] Why git can't do hard/soft resets by path?
  4. git-checkout older revision of a file under a new name
  5. [my answer] git checkout --ours when file spec includes deleted file
  6. [my answer] Using git, how do you reset the working tree (local file system state) to the state of the index ("staged" files)?
Nanon answered 11/12, 2020 at 21:22 Comment(2)
WARNING!! Never ever do git clean -fd without first understanding what it will do. Mercifully Jetbrains kept backups of these files for me. Think, \rm -rf *...Autograph
@jtlz2, I added a long WARNING block in a comment above that code. Does that cover it?Nanon
Y
62

Supplemental to VonC's and chhh's answers:

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

# If your current working directory is relative, then just use:
git show experiment:app.js > app.js

or

git checkout experiment -- app.js
Yoruba answered 8/12, 2015 at 2:22 Comment(3)
Cool! I hate specifying long paths. Is the double dash (--) between the branch name and paths optional? Is it only to prevent paths, which would start with a dash, from being treated as options / switches?Phenylalanine
Honestly I don't know. I didn't even notice that I had forgotten the double dash until you pointed this out.Yoruba
@TomaszGandor The -- is optional, but it's more useful to avoid conflict with branch names. For example, git checkout -- foo means "check out file foo from HEAD" (ie. overwrite local changes in foo, ie. a subset of git reset --hard), but git checkout foo could mean that or "let's go to branch foo".Ermaermanno
R
28

To restore a file from another branch, simply use the following command from your working branch:

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

The -s flag is short for source i.e. the branch from where you want to pull the file.

(The chosen answer is very informative but also a bit overwhelming.)

Roice answered 3/9, 2020 at 20:15 Comment(1)
Agreed regarding having discrete answers for different solutionsLuff
S
9

Or if you want all the files from another branch:

git checkout <branch name> -- .
Smallsword answered 2/2, 2017 at 18:51 Comment(4)
The initial queston contains "just one file".Frond
this replaces existing files rather than mergingLemniscus
This . makes a huge difference: instead of moving to another branch it copies all files from there while still leaving you on the current one. You get contents from other branch without going into it.Broadnax
Why -1: first. this is an answer, but not to the question asked. Second, this overwriting all files in the current directory and all subdirectories unconditionally. Perhaps you shouldn't assume that the OP is a Git pro. Many people, in my experience, treat Git command like magic spells, and this form of the command is really dangerous. IMO, if you also allow me an advice not asked for, you'll make the community a better service by removing your answer.Hypogeal
M
7

If you want the file from a particular commit (any branch), say 06f8251f

git checkout 06f8251f path_to_file

For example, on Windows:

git checkout 06f8251f C:\A\B\C\D\file.h
Mirellamirelle answered 25/7, 2019 at 9:10 Comment(2)
Thanks for taking the time to answer! But this does not answer the question, and a good answer that is very detailled has already been posted 9 years ago. There is no need to bump the question.Peekaboo
This is a valid practical scenario . The answer deals correctly with the branch , but what about looking at a particular commit of the branch .Mirellamirelle
O
7
git checkout <branch_name> -- <paths>

More info

Oiler answered 15/4, 2022 at 17:47 Comment(1)
The link may break at any time. An explanation would be in order. E.g., what is the idea/gist? From the Help Center: "...always explain why the solution you're presenting is appropriate and how it works". Please respond by editing (changing) your answer, not here in comments (*** *** *** *** *** *** *** *** *** *** *** *** *** *** without *** *** *** *** *** "Edit:", "Update:", or similar - the answer should appear as if it was written today).Sanfred
O
5

Review the file on GitHub and pull it from there

This is a pragmatic approach which doesn't directly answer the original post, but some have found useful:

If the branch in question is on GitHub, then you can navigate to the desired branch and file using any of the many tools that GitHub offers, then click 'Raw' to view the plain text, and (optionally) copy and paste the text as desired.

I like this approach because it lets you look at the remote file in its entirety before pulling it to your local machine.

Olatha answered 6/4, 2019 at 22:36 Comment(1)
However copy and pasting the raw file is likely to cause unwanted character changes in your git diff. It's safer to save the file directly to your project to ensure no changes.Concertino
S
4

There is also a simple solution for all who like to avoid unknown Git commands or are afraid to wreck something:

  1. check out to the branch that the file is in
  2. copy that file to somewhere else on your computer
  3. check out to the branch the file needs to get to
  4. paste the file in place

It probably takes longer than the appropriate Git command... but it works and is easy to understand.

Sig answered 3/12, 2021 at 8:57 Comment(0)
S
3

Another way is to create a patch with the differences and apply it in the master branch. For instance, let's say the last commit hash value before you started working on app.js is 00000aaaaa and the commit hash value containing the version you want is 00000bbbbb.

Then you run this on the experiment branch:

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

This will create a file with all the differences between those two commits for app.js that you can apply wherever you want. You can keep that file anywhere outside the project.

Then, in master you just run:

git apply ~/app_changes.git

Now you are going to see the changes in the projects as if you had made them manually.

Selima answered 30/4, 2020 at 19:23 Comment(1)
This solution also works when the file doesn't exist in the current branchAverir
L
2

To checkout a file from another branch is a simple one line command:

git checkout branch C:\path\to\file.cs

If you'd like multiple files

git checkout branch C:\path\to\file1.cs C:\path\to\file2.cs
Lock answered 7/9, 2021 at 19:12 Comment(0)
U
0
  1. Make sure you are on the branch where you want to place the file. You can switch to the desired branch using git checkout <branch_name> if you're not already on it.

    git checkout <branch_name>
    
  2. Use git checkout to retrieve the file from another branch. Replace <branch_name> with the name of the branch you want to get the file from and <path_to_file> with the path to the file within that branch.

    git checkout <branch_name> -- <path_to_file>
    
Utopian answered 12/9, 2023 at 7:16 Comment(1)
Why not using git switch and git restore that I mentioned in my answer? They are clearer than using the same command (checkout) both for branch operation and file operation.Waggery
H
-3

Use:

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>
Hamitosemitic answered 26/7, 2019 at 12:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.