@@ -57,6 +57,7 @@ extension Merge on GitRepository {
57
57
}
58
58
}
59
59
60
+ var baseTree = objStorage.readTree (bases.first.treeHash);
60
61
var headTree = objStorage.readTree (headCommit.treeHash);
61
62
var bTree = objStorage.readTree (commitB.treeHash);
62
63
@@ -70,68 +71,64 @@ extension Merge on GitRepository {
70
71
committer: committer,
71
72
parents: parents,
72
73
message: message,
73
- treeHash: _combineTrees (headTree, bTree),
74
+ treeHash: _combineTrees (headTree, bTree, baseTree ),
74
75
);
75
76
objStorage.writeObject (commit);
76
77
return resetHard (commit.hash);
77
-
78
- // - unborn ?
79
-
80
- // Full 3 way
81
- // https://stackoverflow.com/questions/4129049/why-is-a-3-way-merge-advantageous-over-a-2-way-merge
82
78
}
83
79
84
80
/// throws exceptions
85
- GitHash _combineTrees (GitTree a, GitTree b) {
81
+ GitHash _combineTrees (GitTree a, GitTree b, GitTree base ) {
86
82
// Get all the paths
87
83
var names = a.entries.map ((e) => e.name).toSet ();
88
84
names.addAll (b.entries.map ((e) => e.name));
89
85
90
86
var entries = < GitTreeEntry > [];
91
- for (var name in names) {
87
+ for (var baseEntry in base .entries) {
88
+ var name = baseEntry.name;
92
89
var aIndex = a.entries.indexWhere ((e) => e.name == name);
93
90
var bIndex = b.entries.indexWhere ((e) => e.name == name);
94
91
95
92
var aContains = aIndex != - 1 ;
96
93
var bContains = bIndex != - 1 ;
97
94
98
- if (aContains && ! bContains) {
99
- var aEntry = a.entries[aIndex];
100
- entries.add (aEntry);
95
+ if (! aContains && ! bContains) {
96
+ // both don't contain it!
97
+ continue ;
98
+ } else if (aContains && ! bContains) {
99
+ // Entry deleted in 'b', but exists in 'a'
100
+ // Delete this entry in the merged result
101
+ continue ;
101
102
} else if (! aContains && bContains) {
103
+ // Entry deleted in 'a', but exists in 'b'
102
104
var bEntry = b.entries[bIndex];
103
105
entries.add (bEntry);
104
106
} else {
105
107
// both contain it!
106
108
var aEntry = a.entries[aIndex];
107
109
var bEntry = b.entries[bIndex];
108
110
109
- if (aEntry.mode == GitFileMode .Dir && bEntry.mode == GitFileMode .Dir ) {
110
- var aEntryTree = objStorage.readTree (aEntry.hash);
111
- var bEntryTree = objStorage.readTree (bEntry.hash);
112
-
113
- var newTreeHash = _combineTrees (
114
- aEntryTree,
115
- bEntryTree,
116
- );
117
-
118
- var entry = GitTreeEntry (
119
- mode: GitFileMode .Dir ,
120
- name: aEntry.name,
121
- hash: newTreeHash,
122
- );
123
- entries.add (entry);
124
- continue ;
125
- } else if (aEntry.mode != GitFileMode .Dir &&
126
- bEntry.mode != GitFileMode .Dir ) {
127
- // FIXME: Which one to pick?
128
- var aEntry = a.entries[aIndex];
129
- entries.add (aEntry);
130
- continue ;
131
- }
132
-
133
- throw GitNotImplemented ();
111
+ var newEntry = _resolvConflicts (aEntry, bEntry, baseEntry);
112
+ entries.add (newEntry);
113
+ }
114
+ }
115
+
116
+ for (var entry in [...a.entries, ...b.entries]) {
117
+ var name = entry.name;
118
+
119
+ // If the entry was already in the base
120
+ var baseIndex = base .entries.indexWhere ((e) => e.name == name);
121
+ if (baseIndex != - 1 ) {
122
+ continue ;
134
123
}
124
+
125
+ // If the entry was already in the merged entries
126
+ var mergedIndex = entries.indexWhere ((e) => e.name == name);
127
+ if (mergedIndex != - 1 ) {
128
+ continue ;
129
+ }
130
+
131
+ entries.add (entry);
135
132
}
136
133
137
134
var newTree = GitTree .create (entries);
@@ -140,6 +137,40 @@ extension Merge on GitRepository {
140
137
return newTree.hash;
141
138
}
142
139
140
+ GitTreeEntry _resolvConflicts (
141
+ GitTreeEntry a, GitTreeEntry b, GitTreeEntry base ) {
142
+ if (a.hash == b.hash) {
143
+ return a;
144
+ }
145
+
146
+ // Both are not Directories
147
+ if (a.mode != GitFileMode .Dir && b.mode != GitFileMode .Dir ) {
148
+ return _resolveBlobConflict (a, b, base );
149
+ }
150
+
151
+ if (a.mode == GitFileMode .Dir && b.mode == GitFileMode .Dir ) {
152
+ var aTree = objStorage.readTree (a.hash);
153
+ var bTree = objStorage.readTree (b.hash);
154
+ var baseTree = base .mode == GitFileMode .Dir
155
+ ? objStorage.readTree (base .hash)
156
+ : GitTree .create ();
157
+
158
+ var newTreeHash = _combineTrees (aTree, bTree, baseTree);
159
+ return GitTreeEntry (
160
+ mode: GitFileMode .Dir ,
161
+ name: a.name,
162
+ hash: newTreeHash,
163
+ );
164
+ }
165
+
166
+ throw GitNotImplemented ();
167
+ }
168
+
169
+ GitTreeEntry _resolveBlobConflict (
170
+ GitTreeEntry a, GitTreeEntry b, GitTreeEntry base ) {
171
+ return a;
172
+ }
173
+
143
174
void mergeTrackingBranch ({required GitAuthor author}) {
144
175
var branch = currentBranch ();
145
176
var branchConfig = config.branch (branch);
0 commit comments