1071

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?

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
madlep
  • 41,172
  • 7
  • 39
  • 53
  • 4
    Please note that in the accepted answer, the first solution stages the changes, and the second solution doesn't. https://stackoverflow.com/a/56045704/151841 – user151841 May 08 '19 at 17:01

7 Answers7

1858

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
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
madlep
  • 41,172
  • 7
  • 39
  • 53
  • But wouldn't this overwrite all your changes in the master? – Martin Feb 02 '10 at 11:46
  • 13
    Yes, it would. But that was the intention of the question. – Ikke Feb 02 '10 at 11:54
  • 40
    Probably obvious, but you need to use the complete filename... Wildcards don't work! – Chris Hart Sep 05 '11 at 22:03
  • Is there such handy way to "copy" file from certain commit (not from a branch as shown in this answer)? – milushov Feb 17 '13 at 12:25
  • 7
    although.. it is also nice way: git show commit_id:path/to/file > path/to/file – milushov Feb 17 '13 at 12:29
  • @Chris Hart Wildcards don't work, but relative paths do. Complete filename not always necessary :) – Triptych Aug 01 '13 at 18:10
  • 15
    remote: git checkout origin/otherbranch myfile.txt – Roman Rhrn Nesterov Oct 04 '13 at 11:25
  • @user1448031 by pull I assume you mean that the file exists in a remote branch? `git checkout / ` should work (`git checkout upstream/foo myfile.txt` should "pull" myfile.txt from a forked repo's source repo into your local on the current branch). – Jakob Jingleheimer Sep 02 '14 at 22:54
  • 1
    Is there a way to tell git not to stage the file(s) shown in this way? I just want it to update my working copy, not my index. – erikprice Nov 10 '14 at 15:05
  • For future sleep deprived people, don't forget the full path to file: `git checkout otherbranch path/to/myfile.txt` – jefflab Feb 06 '15 at 03:12
  • This solution works great for committed files, but is there a way to copy a working file to a new branch? The dilemma of course is that you're forced to commit or stash the file before you can switch branches. At times I find myself in the middle of coding something and see the benefit of putting the current working version of that file into a different branch. – Mark Salvatore Jun 24 '15 at 14:28
  • @jefflab, per a quick test with v2.3.3, specifying just the relative path is sufficient. Moreover, assuming the directory is the same, at minimum just the filename alone needs to be specified. – Acumenus Jul 09 '15 at 01:29
  • After executing checkout, do I have to explicitly unstage the `HEAD` so that I can re-add and commit to include to my own commit message? – Srini Apr 05 '16 at 17:43
  • 7
    Using wildcards does work, you just need to wrap them with `''` so they don't get interpreted by the shell. – Wiktor Czajkowski May 21 '18 at 15:06
  • You saved a day! – Herve Mutombo Jul 13 '18 at 11:51
  • This is great, but does not seem to work for deleted files. For example, suppose you have branches `a` and `b` with identical folders `foo/` (and identical folder content): If you delete a file from folder `foo/` on branch `a`, followed by `checkout a foo/` on branch `b` (which has the same file), no changes are applied: the file will remain in place on branch `b`. – djvg Oct 19 '18 at 07:25
  • If there are gaps between both branches, will this action create conflicts later on if you merge? – Ben Carp May 07 '19 at 12:28
91

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
Rob Bednark
  • 19,968
  • 18
  • 67
  • 100
lkraav
  • 2,438
  • 3
  • 24
  • 25
  • 20
    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. – Gonen Aug 14 '14 at 07:46
  • 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. – isaaclw Oct 14 '14 at 17:32
  • 3
    To compare contents before doing the checkout, `git diff ` works well. – Randall Mar 11 '16 at 20:10
  • 5
    @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... – hibbelig Apr 22 '19 at 14:42
66

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

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


Why is it better than other options?

git checkout otherbranch -- path/to/myfile.txt - It copy file to working directory but also to staging area (similar effect as if you would copy this file manually and executed git add on it). git restore doesn't touch staging area (unless told it to by --staged option).

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 you could get broken file if it's binary. With git restore changing files is done all by the git executable.

Another advantage is that you can restore the whole folder with:

git restore --source otherbranch path/to

or with git restore --overlay --source otherbranch path/to if you want to avoid deleting files. 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 good default behaviour, you most likely want the state of directory to be "the same like in otherbranch", not "the same like in otherbranch but with additional files from my current branch".

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Mariusz Pawelski
  • 18,550
  • 7
  • 54
  • 71
  • 1
    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 May 18 '20 at 16:13
  • 2
    @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. – Mariusz Pawelski May 18 '20 at 18:41
  • Ah I see. I don't use Powershell so perhaps shell redirection is np for me. Thanks for the info. – AdmiralAdama May 19 '20 at 16:30
52

Use the checkout command:

  git diff --stat "$branch"
  git checkout --merge "$branch" "$file"
  git diff --stat "$branch"
Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
RzR
  • 2,889
  • 26
  • 25
22
  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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
Mohideen bin Mohammed
  • 14,471
  • 7
  • 86
  • 95
18

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.

Peter Mortensen
  • 28,342
  • 21
  • 95
  • 123
6ft Dan
  • 2,125
  • 27
  • 44
  • 1
    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) – akauppi Jul 22 '15 at 07:35
4

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")
user151841
  • 15,348
  • 28
  • 93
  • 156