You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: book/07-git-tools/sections/advanced-merging.asc
+58-11Lines changed: 58 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -476,17 +476,6 @@ index 0399cd5,59727f0..e1d0799
476
476
hello()
477
477
----
478
478
479
-
==== Other Types of Merges
480
-
481
-
* Subtree (bring back deleted section?)
482
-
* Octopus
483
-
* Squash (git merge --squash)
484
-
* Verify Sigs / Sign Merge
485
-
* Recursive Options
486
-
- Ours / Theirs
487
-
- Ignore-space
488
-
489
-
490
479
[[_undoing_merges]]
491
480
==== Undoing Merges
492
481
@@ -572,3 +561,61 @@ image::images/undomerge-revert3.png[History after re-merging a reverted merge.]
572
561
573
562
In this example, `M` and `^M` cancel out.
574
563
`^^M` effectively merges in the changes from `C3` and `C4`, and `C8` merges in the changes from `C7`, so now `topic` is fully merged.
564
+
565
+
==== Other Types of Merges
566
+
567
+
So far we've covered the normal merge of two branches, normally handled with what is called the ``recursive'' strategy of merging. There are other ways to merge branches together however. Let's cover a few of them quickly.
568
+
569
+
===== Our or Theirs Preference
570
+
571
+
First of all, there is another useful thing we can do with the normal ``recursive'' mode of merging. We've already seen the `ignore-all-space` and `ignore-space-change` options which are passed with a `-X` but we can also tell Git to favor one side or the other when it sees a conflict.
572
+
573
+
By default, when Git sees a conflict between two branches being merged, it will add merge conflict markers into your code and mark the file as conflicted and let you resolve it. If you would prefer for Git to simply choose a specific side and ignore the other side instead of letting you manually merge the conflict, you can pass the `merge` command either a `-Xours` or `-Xtheirs`.
574
+
575
+
If Git sees this, it will not add conflict markers. Any differences that are mergable, it will merge. Any differences that conflict, it will simply choose the side you specify in whole, including binary files.
576
+
577
+
If we go back to the ``hello world'' example we were using before, we can see that merging in our branch causes conflicts.
578
+
579
+
[source,shell]
580
+
----
581
+
$ git merge mundo
582
+
Auto-merging hello.rb
583
+
CONFLICT (content): Merge conflict in hello.rb
584
+
Resolved 'hello.rb' using previous resolution.
585
+
Automatic merge failed; fix conflicts and then commit the result.
586
+
----
587
+
588
+
However if we run it with `-Xours` or `-Xtheirs` it does not.
589
+
590
+
[source,shell]
591
+
----
592
+
$ git merge -Xours mundo
593
+
Auto-merging hello.rb
594
+
Merge made by the 'recursive' strategy.
595
+
hello.rb | 2 +-
596
+
test.sh | 2 ++
597
+
2 files changed, 3 insertions(+), 1 deletion(-)
598
+
create mode 100644 test.sh
599
+
----
600
+
601
+
In that case, instead of getting conflict markers in the file with ``hello mundo'' on one side and ``hola world'' on the other, it will simply pick ``hola world''. However, all the other non-conflicting changes on that branch are merged successfully in.
602
+
603
+
This option can also be passed to the `git merge-file` command we saw earlier by running something like `git merge-file --ours` for individual file merges.
604
+
605
+
If you want to do something like this but not have Git even try to merge changes from the other side in, there is a more draconian option, which is the ``ours'' merge _strategy_. This is different from the ``ours'' recursive merge _option_.
606
+
607
+
This will basically do a fake merge. It will record a new merge commit with both branches as parents, but it will not even look at the branch you're merging in. It will simply record as the result of the merge the exact code in your current branch.
608
+
609
+
[source,shell]
610
+
----
611
+
$ git merge -s ours mundo
612
+
Merge made by the 'ours' strategy.
613
+
$ git diff HEAD HEAD~
614
+
$
615
+
----
616
+
617
+
You can see that there is no difference between the branch we were on and the result of the merge.
618
+
619
+
This can often be useful to basically trick Git into thinking that a branch is already merged when doing a merge later on. For example, say you branched off a ``release'' branch and have done some work on it that you will want to merge back into your ``master'' branch at some point. In the meantime some bugfix on ``master'' needs to be backported into your `release` branch. You can merge the bugfix branch into the `release` branch and also `merge -s ours` the same branch into your `master` branch (even though the fix is already there) so when you later merge the `release` branch again, there are no conflicts from the bugfix.
Copy file name to clipboardExpand all lines: book/07-git-tools/sections/subtree-merges.asc
+23-28Lines changed: 23 additions & 28 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,33 +1,24 @@
1
-
=== Subtree Merging
2
-
3
-
Now that you’ve seen the difficulties of the submodule system, let’s look at an alternate way to solve the same problem.
4
-
When Git merges, it looks at what it has to merge together and then chooses an appropriate merging strategy to use.
5
-
If you’re merging two branches, Git uses a _recursive_ strategy.
6
-
If you’re merging more than two branches, Git picks the _octopus_ strategy.
7
-
These strategies are automatically chosen for you because the recursive strategy can handle complex three-way merge situations – for example, more than one common ancestor – but it can only handle merging two branches.
8
-
The octopus merge can handle multiple branches but is more cautious to avoid difficult conflicts, so it’s chosen as the default strategy if you’re trying to merge more than two branches.
9
-
10
-
However, there are other strategies you can choose as well.
11
-
One of them is the _subtree_ merge, and you can use it to deal with the subproject issue.
12
-
Here you’ll see how to do the same rack embedding as in the last section, but using subtree merges instead.
1
+
===== Subtree Merging
13
2
14
3
The idea of the subtree merge is that you have two projects, and one of the projects maps to a subdirectory of the other one and vice versa.
15
-
When you specify a subtree merge, Git is smart enough to figure out that one is a subtree of the other and merge appropriately – it’s pretty amazing.
4
+
When you specify a subtree merge, Git is often smart enough to figure out that one is a subtree of the other and merge appropriately.
5
+
6
+
We'll go through an example of adding a seperate project into an existing project and then merging the code of the second into a subdirectory of the first.
16
7
17
-
You first add the Rack application to your project.
18
-
You add the Rack project as a remote reference in your own project and then check it out into its own branch:
8
+
First, we'll add the Rack application to our project.
9
+
We'll add the Rack project as a remote reference in our own project and then check it out into its own branch:
@@ -37,7 +28,7 @@ Branch rack_branch set up to track remote branch refs/remotes/rack_remote/master
37
28
Switched to a new branch "rack_branch"
38
29
----
39
30
40
-
Now you have the root of the Rack project in your`rack_branch` branch and your own project in the `master` branch.
31
+
Now we have the root of the Rack project in our`rack_branch` branch and our own project in the `master` branch.
41
32
If you check out one and then the other, you can see that they have different project roots:
42
33
43
34
[source,shell]
@@ -51,28 +42,30 @@ $ ls
51
42
README
52
43
----
53
44
54
-
You want to pull the Rack project into your `master` project as a subdirectory.
55
-
You can do that in Git with `git read-tree`.
45
+
This is sort of a strange concept. Not all the branches in your repository actually have to be branches of the same project. It's not common, because it's rarely helpful, but it's fairly easy to have branches contain completely different histories.
46
+
47
+
In this case, we want to pull the Rack project into our `master` project as a subdirectory.
48
+
We can do that in Git with `git read-tree`.
56
49
You’ll learn more about `read-tree` and its friends in <<_git_internals>>, but for now know that it reads the root tree of one branch into your current staging area and working directory.
57
-
You just switched back to your `master` branch, and you pull the `rack` branch into the `rack` subdirectory of your`master` branch of your main project:
50
+
We just switched back to your `master` branch, and we pull the `rack` branch into the `rack` subdirectory of our`master` branch of our main project:
58
51
59
52
[source,shell]
60
53
----
61
54
$ git read-tree --prefix=rack/ -u rack_branch
62
55
----
63
56
64
-
When you commit, it looks like you have all the Rack files under that subdirectory – as though you copied them in from a tarball.
65
-
What gets interesting is that you can fairly easily merge changes from one of the branches to the other.
66
-
So, if the Rack project updates, you can pull in upstream changes by switching to that branch and pulling:
57
+
When we commit, it looks like we have all the Rack files under that subdirectory – as though we copied them in from a tarball.
58
+
What gets interesting is that we can fairly easily merge changes from one of the branches to the other.
59
+
So, if the Rack project updates, we can pull in upstream changes by switching to that branch and pulling:
67
60
68
61
[source,shell]
69
62
----
70
63
$ git checkout rack_branch
71
64
$ git pull
72
65
----
73
66
74
-
Then, you can merge those changes back into your master branch.
75
-
You can use `git merge -s subtree` and it will work fine; but Git will also merge the histories together, which you probably don’t want.
67
+
Then, we can merge those changes back into our `master` branch.
68
+
We can use `git merge -s subtree` and it will work fine; but Git will also merge the histories together, which we probably don’t want.
76
69
To pull in the changes and prepopulate the commit message, use the `--squash` and `--no-commit` options as well as the `-s subtree` strategy option:
77
70
78
71
[source,shell]
@@ -83,10 +76,12 @@ Squash commit -- not updating HEAD
83
76
Automatic merge went well; stopped before committing as requested
84
77
----
85
78
86
-
All the changes from your Rack project are merged in and ready to be committed locally.
79
+
All the changes from the Rack project are merged in and ready to be committed locally.
87
80
You can also do the opposite – make changes in the `rack` subdirectory of your master branch and then merge them into your `rack_branch` branch later to submit them to the maintainers or push them upstream.
88
81
89
-
To get a diff between what you have in your `rack` subdirectory and the code in your `rack_branch` branch – to see if you need to merge them – you can’t use the normal `diff` command.
82
+
This gives us a way to have a workflow somewhat similar to the submodule workflow without using submodules. We can keep branches with other related projects in our repository and subtree merge them into our project occasionally. It is nice in some ways, for example all the code is committed to a single place. However, it has other drawbacks in that it's a bit more complex and easier to make mistakes in reintegrating changes or accidentally pushing a branch into an unrelated repository.
83
+
84
+
Another slightly weird thing is that to get a diff between what you have in your `rack` subdirectory and the code in your `rack_branch` branch – to see if you need to merge them – you can’t use the normal `diff` command.
90
85
Instead, you must run `git diff-tree` with the branch you want to compare to:
0 commit comments