528

I have two branches (A and B) and I want to merge a single file from branch A with a corresponding single file from Branch B.

3
  • 2
    Already discussed here stackoverflow.com/questions/449541/… Commented May 28, 2012 at 12:26
  • 42
    Most of the responses to that other post are about how to selectively merge commits, not files. This makes the selected answer incorrect. The question remains unanswered. Commented Jul 12, 2012 at 16:40
  • 3
    Possible duplicate of How do you merge selective files with git-merge? Commented Mar 8, 2017 at 2:49

14 Answers 14

844

I came across the same problem. To be precise, I have two branches A and B with the same files but a different programming interface in some files. Now the methods of file f, which is independent of the interface differences in the two branches, were changed in branch B, but the change is important for both branches. Thus, I need to merge just file f of branch B into file f of branch A.

A simple command already solved the problem for me if I assume that all changes are committed in both branches A and B:

git checkout A

git checkout --patch B f

The first command switches into branch A, into where I want to merge B's version of the file f. The second command patches the file f with f of HEAD of B. You may even accept/discard single parts (called "hunks") of the patch interactively. Instead of B you can specify any commit here, it does not have to be HEAD.

Community edit: If the file f on B does not exist on A yet, then omit the --patch option. Otherwise, you'll get a "No Change." message.

Sign up to request clarification or add additional context in comments.

20 Comments

What if there's a conflict?
I had to use git checkout --patch B -- f to get this to work.
Just have to add that if you have multiple changes (hunks) in the file and you want to stage all of them, you can press a during interactive phase, instead of pressing y every time. Or use git checkout B -- f command instead.
Is there a way to do this non-interactively? The way the two files are set up make this solution impractical. Ideally, I'd like to get a file with those merge conflict markers I can edit manually.
This successfully shares changesets across branches, but loses the history of commits from the origin branch, AFAICT
|
30

This uses git's internal difftool. Maybe a little work to do but straight forward.

#First checkout the branch you want to merge into
git checkout <branch_to_merge_into>
    
#Then checkout the file from the branch you want to merge from
git checkout <branch_to_merge_from> -- <file> 
    
#Then you have to unstage that file to be able to use difftool
git reset HEAD <file> 

#Now use difftool to chose which lines to keep. Click on the mergebutton in difftool
git difftool

#Save the file in difftool and you should be done.

3 Comments

To clarify the use of -- (empty argument label), git checkout docs: ARGUMENT DISAMBIGUATION say: "use git checkout -- <pathspec> if you want to checkout these paths out of the index." This is because you could have both a branch and a file/path by the same name. In such cases, rather than asking you to disambiguate whether the branch or the path should be checked out when both exist, git will opt to checkout the branch by default. However if -- preceeds git will checkout the file/path instead.
git diff can be used as well to verify the differences.
With git diff one could also use --cached while the file is staged. Btw, could you elaborate on the difference between the git checkout --patch method and this one? Is there any disadvantage of either method? I am more used to this one, but I'm wondering.
22

Here's what I do in these situations. It's a kludge but it works just fine for me.

  1. Create another branch based off of your working branch.
  2. git pull/git merge the revision (SHA1) which contains the file you want to copy. So this will merge all of your changes, but we are only using this branch to grab the one file.
  3. Fix up any Conflicts etc. investigate your file.
  4. checkout your working branch
  5. Checkout the file commited from your merge.
  6. Commit it.

I tried patching and my situation was too ugly for it. So in short it would look like this:

Working Branch: A Experimental Branch: B (contains file.txt which has changes I want to fold in.)

git checkout A

Create new branch based on A:

git checkout -b tempAB

Merge B into tempAB

git merge B

Copy the sha1 hash of the merge:

git log

commit 8dad944210dfb901695975886737dc35614fa94e
Merge: ea3aec1 0f76e61
Author: matthewe <[email protected]>
Date:   Wed Oct 3 15:13:24 2012 -0700

Merge branch 'B' into tempAB

Checkout your working branch:

git checkout A

Checkout your fixed-up file:

git checkout 7e65b5a52e5f8b1979d75dffbbe4f7ee7dad5017 file.txt

And there you should have it. Commit your result.

2 Comments

So we have to do all this just to merge one single file? Wouldn't it just be easier to copy and paste the file into the other branch
@Robin probably not, because merging keeps the changes on the file, that differ between branch A and B. copying the file will overwrite any additional differences between your working branch A, and what you wanted to bring in from B, which may not contain those entrys/edits. e.g. suspect A has diverted from B to begin with, in other ways. Copying will overwite those differences.
10

You could use:

git merge-file

Tip: https://www.kernel.org/pub/software/scm/git/docs/git-merge-file.html

2 Comments

Im trying to merge one file only, but from another branch. I'm not seeing the option to merge from another branch git merge-file
You can merge one file by doing the following: 1. git show <branch-to-merge>:<file-to-merge> > temp-other 2. git show <common-ancestor-branch>:<file-to-merge> > temp-base 3. git merge-file <file-to-merge> temp-base temp-other 4. rm temp-other temp-base.
10

I found this approach simple and useful: How to "merge" specific files from another branch

As it turns out, we’re trying too hard. Our good friend git checkout is the right tool for the job.

git checkout source_branch <paths>...

We can simply give git checkout the name of the feature branch A and the paths to the specific files that we want to add to our master branch.

Please read the whole article for more understanding

UPDATE 5 years after initially posting this: I've read the link attached again and now I think the author meant to just "bring-in" files to master from another branch whether it does overwrite or not.

I do remember doing some testing myself and it seemed to work. At the moment don't have time to re-test his idea or test my new idea, but it could be something like:

Perform regular merge without immediate commit, stage only files wanted to be merged, discard all modified files that are not staged, and finally commit only staged/wanted files.

7 Comments

This overwrites the files, it doesn't merge them
For you it might, it depends what are you doing and what are you trying to achieve. The idea here is branch B is fork of A, you modify 4 files in B, but want to merge only 2 from B to A. Regular merge would merge all 4, here you can select. This may look as they were overridden because B contains essentially newer files. You need to support your experience with some evidence.
I agree that it overwrites. i think you meant using the -p option in that command. Which then, overwrites any parts on your worktree file that have previously diverted from the branch your checking out from, prior to the patch changes, unfortunately.
Well the idea was from 2009, chances are new version of git behaves differently and needs -p or anything else but back when I was posting it it was working for me, but again maybe I didn't care about the files being overridden, as latest version was what I needed
Overwrites, and you don't.. care? Absolutely misleading, downvoted.
|
9

The following command will (1) compare the file of the correct branch, to master (2) interactively ask you which modifications to apply.

git checkout --patch master <fn>

2 Comments

I think you meant git checkout --patch master <filespec>.
This is THE ONLY ONE that works.
4

The following will have conflicts recorded in the index just as they would be when merging branches.

export other=<sha1 or branch name of the other commit>
export base=$(git merge-base @ $other)

git diff $base $other <file> [<file> ...] | git apply --cached --3way 

The magic here is the --cached --3way mode of apply. A successful 3-way application of a patch depends on having access to the blobs of the wanted file from both the base commit and the other commit, which is guaranteed if we generate the patch with a diff command run against the same local repository.

This approach is different from, and IMO superior to both checkout --patch where conflicts need to be resolved interactively, and merge-file where conflicts are written in diff3 mode into the working directory. Some IDEs don't support inline worktree conflict markers, but most can very well work with conflicts recorded in the index.

3 Comments

Until around git 2.31 or 2.32, --cached and --3way were incompatible. I'm sort-of stuck at 2.30, but this appears to be exactly what I'm looking for. So I'm building git 2.41.0 from source. I'll confirm when I get it built. I really expected git read-tree --merge -u --prefix= to work, but it refuses.
Can confirm—works great! Even better, you can do it on multiple paths, or entire directories, in a single command! I might suggest editing to add "..." after <file>. It was well worth building git from source to gain this capability. Thanks much!
I'll also recommend this be the accepted answer, if the OP is still around to take note. The use case where interactive approval is desired, rather than a deal-breaker, can be met by combining 'git restore' and 'git add -p'
2

Assuming B is the current branch:

$ git diff A <file-path> > patch.tmp
$ git apply patch.tmp -R

Note that this only applies changes to the local file. You'll need to commit afterwards.

4 Comments

For me this generates a error: <file-path>: already exists in working directory
You should specific file or file path at current directory. I'm use git diff Branch_A <file-path, filename> -- hash_commit > file_name.temp
what does the -R do? A little more explanation would be helpful.
this just worked. thank you!
1

You can checkout the old version of the file to merge, saving it under a different name, then run whatever your merge tool is on the two files.

eg.

git show B:src/common/store.ts > /tmp/store.ts (where B is the branch name/commit/tag)

meld src/common/store.ts /tmp/store.ts

Comments

1

I will do it as

git format-patch branch_old..branch_new file

this will produce a patch for the file.

Apply patch at target branch_old

git am blahblah.patch

3 Comments

Can you easily look into the patch for extra safety?
not sure what I'm doing wrong but I cannot get git to produce the patch file. No error reported though
Yes it works! In git-format-patch(1) the filter-by-file feature is hidden inside the <common diff options>. The only thing I miss is the possibility to exclude some file(s) under a directory selected by the filter. Can achieve this by editing the patch files but it is not nice.
0

If you have to do this after an incorrect merge, you can do something like this:

# If you did a git pull and it broke something, do this first
# Find the one before the merge, copy the SHA1
git reflog
git reset --hard <sha1>

# Get remote updates but DONT auto merge it
git fetch github 

# Checkout to your mainline so your branch is correct.
git checkout develop 

# Make a new branch where you'll be applying matches
git checkout -b manual-merge-github-develop

# Apply your patches
git checkout --patch github/develop path/to/file
...

# Merge changes back in
git checkout develop
git merge manual-merge-github-develop # optionally add --no-ff

# You'll probably have to
git push -f # make sure you know what you're doing.

Comments

0

I've seen others suggesting git checkout -- <file>, and while that overwrites the file instead of merging, I found that using a 'local changes' diff tool in my IDE is more than sufficient (IMHO) to compare the two versions.

Comments

0

To merge a single file, with merge conflict from another branch, you could do it like this:

Branch A:

file_01
file_02
file_03

Branch B:

file_01
file_02
file_03
file_04
file_05

Commands:

git checkout A
git merge B

You will get message about what files you have to manually resolve because they have overlapping code. Files in current branch(A) will be changed and it will contain both code, own code(A), code from B, and it will have <<<<<< HEAD, ======, >>>>>> B; Git merge notations.

git reset
git add file_01
git clean -f -d

You have unstaged all files that were affected when merging B onto A and added only file that you want to merge, file_01 file. After that you delete all unstaged files. Now you can edit file_01 file to get the right code that you need or you can leave it as is. For Git itself, it will not matter if you leave the file unresolved, it will contain overlapping code form both branches with Git merge notations. But you will have to commit, because Git is still in a 'state' of merge and it will close when you commit the changes.

git commit -m "Merge file_01 only"

Note that you can add multiple files before commit, does not have to be only one.

Comments

-2
git checkout <target_branch>
git checkout <source_branch> <file_path>

1 Comment

Isn't that already what Pawel's answer is explaining?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.