259

I have 2 git branches branch1 and branch2 and I want to merge file.py in branch2 into file.py in branch1 and only that file.

In essence I just want to work on the file.py in branch1 but want to take advantage of the merge command. What is the best way to do this?

rwolst
  • 11,944
  • 16
  • 48
  • 69
  • 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
  • Possible duplicate of [How do I merge changes to a single file, rather than merging commits?](https://stackoverflow.com/questions/10784523/how-do-i-merge-changes-to-a-single-file-rather-than-merging-commits) – fbmd Jan 31 '18 at 14:30

13 Answers13

276

When content is in file.py from branch2 that is no longer applies to branch1, it requires picking some changes and leaving others. For full control do an interactive merge using the --patch switch:

$ git checkout --patch branch2 file.py

The interactive mode section in the man page for git-add(1) explains the keys that are to be used:

y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk nor any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk nor any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

The split command is particularly useful.

Dave Jarvis
  • 29,586
  • 38
  • 176
  • 304
pdp
  • 3,734
  • 1
  • 16
  • 16
147

Although not a merge per se, sometimes the entire contents of another file on another branch are needed. Jason Rudolph's blog post provides a simple way to copy files from one branch to another. Apply the technique as follows:

$ git checkout branch1 # ensure in branch1 is checked out and active
$ git checkout branch2 file.py

Now file.py is now in branch1.

Dave Jarvis
  • 29,586
  • 38
  • 176
  • 304
Matthew Turner
  • 3,368
  • 2
  • 19
  • 21
36

None of the other current answers will actually "merge" the files, as if you were using the merge command. (At best they'll require you to manually pick diffs.) If you actually want to take advantage of merging using the information from a common ancestor, you can follow a procedure based on one found in the "Advanced Merging" section of the git Reference Manual.

For this protocol, I'm assuming you're wanting to merge the file 'path/to/file.txt' from origin/master into HEAD - modify as appropriate. (You don't have to be in the top directory of your repository, but it helps.)

# Find the merge base SHA1 (the common ancestor) for the two commits:
git merge-base HEAD origin/master

# Get the contents of the files at each stage
git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
git show HEAD:path/to/file.txt > ./file.ours.txt
git show origin/master:path/to/file.txt > ./file.theirs.txt

# You can pre-edit any of the files (e.g. run a formatter on it), if you want.

# Merge the files
git merge-file -p ./file.ours.txt ./file.common.txt ./file.theirs.txt > ./file.merged.txt

# Resolve merge conflicts in ./file.merged.txt
# Copy the merged version to the destination
# Clean up the intermediate files

git merge-file should use all of your default merge settings for formatting and the like.

Also note that if your "ours" is the working copy version and you don't want to be overly cautious, you can operate directly on the file:

git merge-base HEAD origin/master
git show <merge-base SHA1>:path/to/file.txt > ./file.common.txt
git show origin/master:path/to/file.txt > ./file.theirs.txt
git merge-file path/to/file.txt ./file.common.txt ./file.theirs.txt
R.M.
  • 3,205
  • 1
  • 18
  • 38
  • This is indeed the only option that *actually* merges the changes. I used it in a bash loop to do this for several files: `for file in {file1,file2,etc}; do git show $(git merge-base HEAD dev-mysql-to-pdo):$file > common.tmp; git show HEAD:$file > current.tmp; git show dev-mysql-to-pdo:$file > other.tmp; git merge-file -p current.tmp common.tmp other.tmp > $file; rm current.tmp other.tmp common.tmp; done` – DMJ Sep 28 '21 at 23:00
18

Are all the modifications to file.py in branch2 in their own commits, separate from modifications to other files? If so, you can simply cherry-pick the changes over:

git checkout branch1
git cherry-pick <commit-with-changes-to-file.py>

Otherwise, merge does not operate over individual paths...you might as well just create a git diff patch of file.py changes from branch2 and git apply them to branch1:

git checkout branch2
git diff <base-commit-before-changes-to-file.py> -- file.py > my.patch
git checkout branch1
git apply my.patch
10

You can stash and stash pop the file:

git checkout branch1
git checkout branch2 file.py
git stash
git checkout branch1
git stash pop
Martin G
  • 16,009
  • 9
  • 78
  • 91
  • 6
    This overwrites branch1/file.py with the content of branch2/file.py instead of a merge that should raise a merge conflict to resolve. – maininformer Nov 26 '19 at 22:09
  • Doesn't "merge" the file, just replaces it... The last three statements change the outcome by literally nothing... – agent18 Aug 31 '21 at 14:30
5

The solution I found that caused me the least headaches:

git checkout <b1>
git checkout -b dummy
git merge <b2>
git checkout <b1>
git checkout dummy <path to file>

After doing that the file in path to file in b2 is what it would be after a full merge with b1.

Makogan
  • 6,665
  • 6
  • 40
  • 87
4

The simplest solution is:

git checkout the name of the source branch and the paths to the specific files that we want to add to our current branch

git checkout sourceBranchName pathToFile
Jackkobec
  • 4,782
  • 28
  • 29
2

To merge only the changes from branch2's file.py, make the other changes go away.

git checkout -B wip branch2
git read-tree branch1
git checkout branch2 file.py
git commit -m'merging only file.py history from branch2 into branch1'
git checkout branch1
git merge wip

Merge will never even look at any other file. You might need to '-f' the checkouts if the trees are different enough.

Note that this will leave branch1 looking as if everything in branch2's history to that point has been merged, which may not be what you want. A better version of the first checkout above is probably

git checkout -B wip `git merge-base branch1 branch2`

in which case the commit message should probably also be

git commit -m"merging only $(git rev-parse branch2):file.py into branch1"
jthill
  • 48,781
  • 4
  • 72
  • 120
2

Matthew Turner's solution is the easiest but gives an error if branch1 and file have the same name. In that case, replace the second line with

git checkout branch2 -- file.py

Claire. D
  • 21
  • 1
1

If you only care about the conflict resolution and not about keeping the commit history, the following method should work. Say you want to merge a.py b.py from BRANCHA into BRANCHB. First, make sure any changes in BRANCHB are either committed or stashed away, and that there are no untracked files. Then:

git checkout BRANCHB
git merge BRANCHA
# 'Accept' all changes
git add .
# Clear staging area
git reset HEAD -- .
# Stash only the files you want to keep
git stash push a.py b.py
# Remove all other changes
git add .
git reset --hard
# Now, pull the changes
git stash pop

git won't recognize that there are conflicts in a.py b.py, but the merge conflict markers are there if there were in fact conflicts. Using a third-party merge tool, such as VSCode, one will be able to resolve conflicts more comfortably.

0

I am in same situation, I want to merge a file from a branch which has many commits on it on 2 branch. I tried many ways above and other I found on the internet and all failed (because commit history is complex) so I decide to do my way (the crazy way).

git merge <other-branch>
cp file-to-merge file-to-merge.example
git reset --hard HEAD (or HEAD^1 if no conflicts happen)
cp file-to-merge.example file-to-merge
Trac Nguyen
  • 476
  • 4
  • 7
0

What I've done is a bit manual, but I:

  1. Merged the branches normally; Reverted the merge with revert;
  2. Checked out all my files to HEAD~1, that is, their state in the merge commit;
  3. Rebased my commits to hide this hackery from the commit history.

Ugly? Yes. Easy to remember? Also yes.

Lucas Lima
  • 772
  • 9
  • 21
0

If git checkout --patch branch2 file.py is going to be accepted, then I should share that we can also use:

git difftool <branch> [-- <file>]

([] means optional.)

If configured for diff.tool, merge tools like meld will allow you to manually merge two files using a graphical interface.

One weakness is that it won't be able to copy or remove a file if it doesn't exist in one of the branches. In that case, we need to git checkout branch2 -- file.py.

git difftool doesn't preserve history either.

techniao
  • 141
  • 1
  • 9