1436

I've got two branches that are fully merged together.

However, after the merge is done, I realise that one file has been messed up by the merge (someone else did an auto-format, gah), and it would just be easier to change to the new version in the other branch, and then reinsert my one line change after bringing it over into my branch.

So what's the easiest way in Git to do this?

2
  • 10
    Please note that in the accepted answer, the first solution stages the changes, and the second solution doesn't. stackoverflow.com/a/56045704/151841 Commented May 8, 2019 at 17:01
  • 10
    The most up-to-date answer is git restore --source otherbranch path/to/myfile.txt (see explanation in the answer). Commented Jun 12, 2021 at 0:29

9 Answers 9

2345

Run this from the branch where you want the file to end up:

git checkout otherbranch myfile.txt

General formulas:

git checkout <commit_hash> <relative_path_to_file_or_dir>
git checkout <remote_name>/<branch_name> <file_or_dir>

Some notes (from comments):

  • Using the commit hash, you can pull files from any commit
  • This works for files and directories
  • Overwrites the file myfile.txt and mydir
  • Wildcards don't work, but relative paths do
  • Multiple paths can be specified

An alternative:

git show commit_id:path/to/file > path/to/file
Sign up to request clarification or add additional context in comments.

17 Comments

Yes, it would. But that was the intention of the question.
Probably obvious, but you need to use the complete filename... Wildcards don't work!
although.. it is also nice way: git show commit_id:path/to/file > path/to/file
remote: git checkout origin/otherbranch myfile.txt
Using wildcards does work, you just need to wrap them with '' so they don't get interpreted by the shell.
|
277

I would use git restore (available since Git 2.23):

git restore --source otherbranch path/to/myfile.txt

Why is this better than other options?

  • by default git restore modifies files only in the working directory

git checkout otherbranch -- path/to/myfile.txt copies the file to the working directory (your files on disk) but also to the staging area. It has the same effect as if you copied the file manually and executed git add on it. git restore by default changes only the working directory.

To get the same result as for git checkout otherbranch -- path/to/myfile.txt you can write git restore --source otherbranch --staged --worktree path/to/myfile.txt

  • by default git restore deletes files from the working directory when they are absent in the other branch

git restore can be used to restore the whole folder with git restore --source otherbranch path/to/dir. You can do a similar operation with git checkout but git restore by default will delete files that are absent in otherbranch. To get git checkout behaviour use --overlay option.

For example, if there are fewer files on otherbranch than in the current working directory (and these files are tracked) without --overlay option git restore will delete them. But this is a good default behaviour because you most likely want the state of the directory to be "the same as otherbranch", not "the same as otherbranch but with additional files from my current branch".

To really get the same result as for git checkout otherbranch -- path/to/dir you can write git restore --source otherbranch --staged --worktree --overlay path/to/dir

  • git restore doesn't use shell redirection to create file (Powershell only problem)

git show otherbranch:path/to/myfile.txt > path/to/myfile.txt uses standard shell redirection. If you use PowerShell then there might be problem with text encoding or could result in a corrupt file if it's binary (update: fixed in PowerShell 7.4). With git restore changing files is done all by the git executable.

11 Comments

Nice answer. Is there a git restore way to copy a file from the source branch to a new file on the target branch? With git show I can do this with shell redirection (git show otherbranch:path/to/file1.txt > path/to/file2.txt), but I want to avoid shell redirection for the reasons you mentioned.
@AdmiralAdama not really. And I think there is no big chance of getting it in git restore (but who know ;)). This redirection issues are basically Powershell problem, not sure if there is any other shell that have problem with it. I usually go back to "git bash" or even "cmd" where I need to use "git show with redirection" commands. Or use GUI like GitExtensions where you can browse file tree of commit and click "Save as" on any file.
Ah I see. I don't use Powershell so perhaps shell redirection is np for me. Thanks for the info.
Small improvement: better is git restore --source=otherbranch path/to/myfile.txt against git restore --source otherbranch path/to/myfile.txt the reason is because in the second case, tab to list the available branches doesn't work.
Thank you for your "post-checkout-era" response 🙂
|
99

I ended up at this question on a similar search. In my case I was looking to extract a file from another branch into current working directory that was different from the file's original location. Answer:

git show TREEISH:path/to/file > path/to/local/file

4 Comments

The intention of 'git show' is to output data to the terminal in readable format, which is not guarantied to match the content of the file exactly. Same as it is better to copy a word-document as a whole, and not try to Copy-and-Paste its content to another document.
I just wanted to view it so I could compare the contents against the current branch (check some piece of code). I'd like to use vim with this though... for syntax highlighting, etc.
To compare contents before doing the checkout, git diff <other branch> <path to file> works well.
@Gonen: As of git version 2.21.0, the "git show" manual page says "For plain blobs, it shows the plain contents." I'm not sure if this means we're always good. I'm kinda wary to fetch an image that way...
56

Use the checkout command:

  git diff --stat "$branch"
  git checkout --merge "$branch" "$file"
  git diff --stat "$branch"

4 Comments

note merge (2nd command) cannot work if the file does not exist on both branches
Hm. I don't have diffstat. Is that a specific version of a diff tool, because I've never heard of it (and should I switch to it?) :D
git diff supports an --stat argument which basically does the same thing as diffstat.
I had to have both branches checked out locally to get this to work.
37
  1. Ensure you're in branch where you need a copy of the file.

    For example: I want sub branch file in master, so you need to checkout or should be in master git checkout master

  2. Now check out the specific file alone you want from the sub branch into master,

     git checkout sub_branch file_path/my_file.ext
    

    Here sub_branch means where you have that file followed by filename you need to copy.

Comments

24

Following madlep's answer, you can also just copy one directory from another branch with the directory blob.

git checkout other-branch app/**

As to the OP's question if you've only changed one file in there, this will work fine.

1 Comment

Notice that both the branches need to be properly pulled, first, or use origin/other-branch for referring to the repo branch. Basics, but bit me. (the answer is great - no editing required)
7

Sorry, no one mentioned that before restoring a file you really want to preview local changes in relation to that branch, so:

git diff <other-branch-name> -- <filename>

Then when you're accepting a lost (overwritting), you can follow by:

git restore --source <other-branch-name> <filename>
or
git checkout <other-branch-name> <filename>

Comments

6

Please note that in the accepted answer, the first option stages the entire file from the other branch (like git add ... had been performed), and that the second option just results in copying the file, but doesn't stage the changes (as if you had just edited the file manually and had outstanding differences).

Git copy file from another branch without staging it

Changes staged (e.g. git add filename):

$ git checkout directory/somefile.php feature-B

$ git status
On branch feature-A
Your branch is up-to-date with 'origin/feature-A'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   directory/somefile.php

Changes outstanding (not staged or committed):

$ git show feature-B:directory/somefile.php > directory/somefile.php

$ git status
On branch feature-A
Your branch is up-to-date with 'origin/feature-A'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   directory/somefile.php

no changes added to commit (use "git add" and/or "git commit -a")

1 Comment

I get "feature-B is not a file", the branch name comes first, about this -> "> directory/somefile.php" may this change the encoding of the file ?
1

All the git based answers are confusing and works on certain assumptions. I would rather present a more simplistic approach which works for files or folders.

git checkout other_branch

# Copy a single file
cp path/to/file /tmp/

# Copy a folder
cp -r path/to/folder /tmp/

git checkout my_branch

# Copy file/folder from /tmp dir to wherever you like.

If it ain't broken etc...

1 Comment

Can you elaborate on the "certain assumptions" present in the git restore answer?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.