I'm going to concentrate on the subset of this problem that was of interest to me: I have two branches and I want to pseudo-merge one file from one into the other.
(I say "pseudo-merge" because I don't need or want a merge commit; I just want to combine the contributions of both versions of the file, in the way that I see fit.)
My approach is based on the approach taken in https://mcmap.net/q/45879/-git-merge-only-single-file-from-master-into-current-branch-duplicate. Unfortunately that question is closed as a duplicate (wrongly, in my opinion: it's not a duplicate of this question, and it is wrong to answer-and-close-as-duplicate which is what the answerer did there). But there are some things wrong with that answer, so I've modernized and cleaned up the approach. Instead of checkout
and reset
, I use restore
, and I don't bother to commit anything I don't have to.
Okay, so imagine I have three files:
$ ls
a b f
But I only want to pseudo-merge one of them, a
, from otherbranch
. Let's peek at them to see what the situation will look like. Here's my version:
$ cat a
line one
line two
line three
line four
line five
Here's otherbranch's version:
$ git show otherbranch:a
line one
line two edited
line three
line four
line five
line six
Now the trick here is that we're going to use the index as a scratch pad (which is, after all, what it is for). So we start (STEP 1) by making sure that our version is copied into the index:
$ git add a
Now (STEP 2) we can use restore
to fetch the version from otherbranch
(nowadays, restore
is better than checkout
as it lets us talk more clearly):
$ git restore --source otherbranch a
At first blush, this looks bad. We have now completely overwritten our a with the version from otherbranch
, as you can see:
$ cat a
line one
line two edited
line three
line four
line five
line six
But not to worry! The previous version of a is still in the index, as you can see:
$ git diff a
diff --git a/a b/a
index abf51fa..333614b 100644
--- a/a
+++ b/a
@@ -1,6 +1,7 @@
line one
-line two
+line two edited
line three
line four
line five
+line six
Very well, now we're ready for the key move (STEP 3). We do an interactive patch add
of our file from the working tree to the index.
We could say git add -p a
to start the interactive patch process, in which case we are fed hunks one at a time. But in this case there is just one hunk, and I want to edit it anyway, so I say:
$ git add --e a
The result is that we open a patch file of diffs in our editor! It looks like this:
line one
-line two
+line two edited
line three
line four
line five
+line six
By careful editing we can now decide what parts we want to accept and what parts we don't. Let's accept "line six" but not "line two edited". So we edit to look like this:
line one
line two
line three
line four
line five
+line six
We close the editor and the patch is applied to the index version of a. But we are not quite finished! The otherbranch
version of a is still sitting in the working tree:
$ cat a
line one
line two edited
line three
line four
line five
line six
The version we like is in the index, remember? To get it, (STEP 4) we just call git restore
plain and simple (again, this the modern way; restore
is nicer than reset
and can apply to a single file):
$ git restore a
Now our a is correct, and we're all finished:
$ cat a
line one
line two
line three
line four
line five
line six
We could at this point commit, but we don't have to; we've accomplished what we set out to accomplish.
git merge -s ours --no-commit
followed by somegit read-tree
be a good solution for this? See #1215406 – Seigler