466

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.

alex
  • 5,636
  • 9
  • 47
  • 97
Isuru
  • 7,435
  • 8
  • 29
  • 38
  • 2
    Already discussed here http://stackoverflow.com/questions/449541/how-do-you-merge-selective-files-with-git-merge – positron May 28 '12 at 12:26
  • 36
    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. –  Jul 12 '12 at 16:40
  • 1
    Possible duplicate of [How do you merge selective files with git-merge?](http://stackoverflow.com/questions/449541/how-do-you-merge-selective-files-with-git-merge) – phuclv Mar 08 '17 at 02:49
  • 1
    This answer is the way to go, IMO. `git diff branch_name > patch` `git apply patch` . https://stackoverflow.com/a/9473543/1091853 – blamb Nov 22 '19 at 16:55

11 Answers11

763

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 of the patch. 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.

Mark Lakata
  • 19,008
  • 5
  • 97
  • 119
loup
  • 7,789
  • 1
  • 11
  • 6
  • Very helpful. I added some info about merging from remotes, they work the same as branches but not everyone is aware of that. – Soup Nov 20 '12 at 04:43
  • 11
    This only works if you want to update a file. What if I want to add a new file from branch B to branch A? – Umair A. Feb 04 '14 at 15:57
  • 33
    @UmairAshraf you should be able to add a new file from B to A by removing the --patch option. – bbak Feb 11 '14 at 22:07
  • This works when `B` is a SHA-1 object name too. Thanks! – rickhg12hs Oct 01 '14 at 07:25
  • 1
    What if there's a conflict? – Evernoob Dec 04 '14 at 13:56
  • 10
    Hmmm... when I try this I get the message "no changes", but there clearly are changes. OK, I needed to be in the folder where the relevant file was. Edit: This could quite possibly be my favourite solution to a problem I've seen on stackoverflow :-D – mal Dec 11 '14 at 08:59
  • 9
    I had to use `git checkout --patch B -- f` to get this to work. – user545424 Jan 27 '15 at 16:33
  • 9
    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. – Dmitry Gonchar Nov 02 '15 at 17:54
  • 3
    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. –  Feb 10 '16 at 14:02
  • @Neutralizer If you just want to add a file from another branch then do `git checkout B f` (without the --patch) – Marcelo Bielsa Aug 24 '17 at 19:09
  • 1
    After doing this the file is listed by "git status" as being modified in the destination branch? I was hoping for a way to do a FF merge. – Tom Russell Sep 20 '17 at 11:49
  • 1
    This successfully shares changesets across branches, but loses the history of commits from the origin branch, AFAICT – Dubslow Dec 08 '17 at 00:25
  • 2
    This wasn't really a "merge" for me: it stomped on the changes I had made to 'f' in my branch (A here). B is master, and A is my feature branch. When I was merging the other way, merging A back to B (master), there was a conflict. When I do this to sync the files, my changes made in A are gone and git does not report a conflict. – Wilbur Whateley Jan 25 '18 at 00:54
  • 1
    There's a list of commands for interactive merging in https://stackoverflow.com/a/33168094/1132250 which is applicable here. – fbmd Jan 31 '18 at 14:29
  • What if the files exist on different path on each branch. Say I have file `file.ext` under `path/to/file/file.ext` on branch `master` and I have the same file on branch `refactor` but in a different directory under `another/path/to/the/file/file.ext`. How can I merge changes to `master`/`file.ext` into `refactor`/`file.ext`? – goofle Feb 07 '19 at 08:48
  • Give me this error `ambiguous argument 'B': both revision and filename`, I had to use `git checkout --patch B -- f` then accept/discard changes – pldg Jul 19 '19 at 23:33
  • 1
    It worked for folders newly (created in the branch) also. `git checkout `. It adds all contents in the folder as well to the current branch in which I do this operation. – vineeshvs Oct 19 '19 at 07:02
  • I found using e in the interactive mode was enough like resolving a merge conflict manually to fit my needs. @fbdm's reminder here helped. – Aaron Surrain Apr 27 '20 at 17:59
26

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.
davmos
  • 8,924
  • 4
  • 39
  • 42
Mikael Kellgren
  • 261
  • 3
  • 2
  • 1
    To clarify the use of `--` (empty argument label), git checkout docs: [ARGUMENT DISAMBIGUATION](https://git-scm.com/docs/git-checkout) say: "use `git checkout -- ` 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. – SherylHohman Apr 25 '18 at 21:21
  • `git diff` can be used as well to verify the differences. – Pedro OS May 16 '21 at 18:03
19

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 <matthewe@matthewe.com>
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.

eggmatters
  • 1,146
  • 12
  • 25
  • 5
    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 Jun 19 '18 at 18:46
  • 2
    @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. – blamb Nov 22 '19 at 00:29
11

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

Community
  • 1
  • 1
Pawel Cioch
  • 2,652
  • 1
  • 25
  • 29
  • 17
    This overwrites the files, it doesn't merge them – Alex G Nov 12 '19 at 08:24
  • 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. – Pawel Cioch Nov 12 '19 at 19:27
  • 2
    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. – blamb Nov 22 '19 at 00:40
  • 1
    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 – Pawel Cioch Nov 22 '19 at 17:57
  • 2
    Overwrites, and you don't.. care? Absolutely misleading, downvoted. – MrR Jun 22 '21 at 16:28
  • MrR then what is the solution? – Kowsigan Atsayam Aug 19 '21 at 15:13
9

You could use:

    git merge-file

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

geralOE
  • 484
  • 4
  • 7
  • 3
    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` – blamb Nov 22 '19 at 00:37
5

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

user1854182
  • 631
  • 1
  • 9
  • 11
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

Salami
  • 2,459
  • 4
  • 23
  • 33
0

My edit got rejected, so I'm attaching how to handle merging changes from a remote branch here.

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.
Soup
  • 1,649
  • 15
  • 28
0

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.

jbirkel
  • 17
  • 2
0

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

sean
  • 867
  • 10
  • 16
Noob
  • 1
-2
git checkout <target_branch>
git checkout <source_branch> <file_path>
Aslam Shaik
  • 1,279
  • 8
  • 9
  • 3
    Isn't that already what [Pawel's answer](https://stackoverflow.com/a/55403131/2227743) is explaining? – Eric Aya Dec 09 '20 at 15:44