View Javadoc
1   /*
2    * Copyright (C) 2009, Google Inc.
3    * Copyright (C) 2008, Robin Rosenberg and others
4    *
5    * This program and the accompanying materials are made available under the
6    * terms of the Eclipse Distribution License v. 1.0 which is available at
7    * https://www.eclipse.org/org/documents/edl-v10.php.
8    *
9    * SPDX-License-Identifier: BSD-3-Clause
10   */
11  
12  package org.eclipse.jgit.merge;
13  
14  import static org.junit.Assert.assertEquals;
15  import static org.junit.Assert.assertFalse;
16  import static org.junit.Assert.assertTrue;
17  
18  import java.io.IOException;
19  
20  import org.eclipse.jgit.dircache.DirCache;
21  import org.eclipse.jgit.dircache.DirCacheBuilder;
22  import org.eclipse.jgit.lib.CommitBuilder;
23  import org.eclipse.jgit.lib.FileMode;
24  import org.eclipse.jgit.lib.ObjectId;
25  import org.eclipse.jgit.lib.ObjectInserter;
26  import org.eclipse.jgit.lib.PersonIdent;
27  import org.eclipse.jgit.test.resources.SampleDataRepositoryTestCase;
28  import org.eclipse.jgit.treewalk.TreeWalk;
29  import org.junit.Test;
30  
31  public class SimpleMergeTest extends SampleDataRepositoryTestCase {
32  
33  	@Test
34  	public void testOurs() throws IOException {
35  		Merger ourMerger = MergeStrategy.OURS.newMerger(db);
36  		boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
37  		assertTrue(merge);
38  		assertEquals(db.resolve("a^{tree}"), ourMerger.getResultTreeId());
39  	}
40  
41  	@Test
42  	public void testOurs_noRepo() throws IOException {
43  		try (ObjectInserter ins = db.newObjectInserter()) {
44  			Merger ourMerger = MergeStrategy.OURS.newMerger(ins, db.getConfig());
45  			boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
46  			assertTrue(merge);
47  			assertEquals(db.resolve("a^{tree}"), ourMerger.getResultTreeId());
48  		}
49  	}
50  
51  	@Test
52  	public void testTheirs() throws IOException {
53  		Merger ourMerger = MergeStrategy.THEIRS.newMerger(db);
54  		boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
55  		assertTrue(merge);
56  		assertEquals(db.resolve("c^{tree}"), ourMerger.getResultTreeId());
57  	}
58  
59  	@Test
60  	public void testTheirs_noRepo() throws IOException {
61  		try (ObjectInserter ins = db.newObjectInserter()) {
62  			Merger ourMerger = MergeStrategy.THEIRS.newMerger(db);
63  			boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
64  			assertTrue(merge);
65  			assertEquals(db.resolve("c^{tree}"), ourMerger.getResultTreeId());
66  		}
67  	}
68  
69  	@Test
70  	public void testTrivialTwoWay() throws IOException {
71  		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
72  		boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
73  		assertTrue(merge);
74  		assertEquals("02ba32d3649e510002c21651936b7077aa75ffa9",ourMerger.getResultTreeId().name());
75  	}
76  
77  	@Test
78  	public void testTrivialTwoWay_disjointhistories() throws IOException {
79  		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
80  		boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c~4") });
81  		assertTrue(merge);
82  		assertEquals("86265c33b19b2be71bdd7b8cb95823f2743d03a8",ourMerger.getResultTreeId().name());
83  	}
84  
85  	@Test
86  	public void testTrivialTwoWay_ok() throws IOException {
87  		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
88  		boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a^0^0^0"), db.resolve("a^0^0^1") });
89  		assertTrue(merge);
90  		assertEquals(db.resolve("a^0^0^{tree}"), ourMerger.getResultTreeId());
91  	}
92  
93  	@Test
94  	public void testTrivialTwoWay_noRepo() throws IOException {
95  		try (ObjectInserter ins = db.newObjectInserter()) {
96  			Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(ins, db.getConfig());
97  			boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a^0^0^0"), db.resolve("a^0^0^1") });
98  			assertTrue(merge);
99  			assertEquals(db.resolve("a^0^0^{tree}"), ourMerger.getResultTreeId());
100 		}
101 	}
102 
103 	@Test
104 	public void testTrivialTwoWay_conflict() throws IOException {
105 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
106 		boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("f"), db.resolve("g") });
107 		assertFalse(merge);
108 	}
109 
110 	@Test
111 	public void testTrivialTwoWay_validSubtreeSort() throws Exception {
112 		DirCache treeB = db.readDirCache();
113 		DirCache treeO = db.readDirCache();
114 		DirCache treeT = db.readDirCache();
115 
116 		DirCacheBuilder bTreeBuilder = treeB.builder();
117 		DirCacheBuilder oTreeBuilder = treeO.builder();
118 		DirCacheBuilder tTreeBuilder = treeT.builder();
119 
120 		bTreeBuilder.add(createEntry("libelf-po/a", FileMode.REGULAR_FILE));
121 		bTreeBuilder.add(createEntry("libelf/c", FileMode.REGULAR_FILE));
122 
123 		oTreeBuilder.add(createEntry("Makefile", FileMode.REGULAR_FILE));
124 		oTreeBuilder.add(createEntry("libelf-po/a", FileMode.REGULAR_FILE));
125 		oTreeBuilder.add(createEntry("libelf/c", FileMode.REGULAR_FILE));
126 
127 		tTreeBuilder.add(createEntry("libelf-po/a", FileMode.REGULAR_FILE));
128 		tTreeBuilder
129 				.add(createEntry("libelf/c", FileMode.REGULAR_FILE, "blah"));
130 
131 		bTreeBuilder.finish();
132 		oTreeBuilder.finish();
133 		tTreeBuilder.finish();
134 
135 		ObjectInserter ow = db.newObjectInserter();
136 		ObjectId b = commit(ow, treeB, new ObjectId[] {});
137 		ObjectId o = commit(ow, treeO, new ObjectId[] { b });
138 		ObjectId t = commit(ow, treeT, new ObjectId[] { b });
139 
140 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
141 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
142 		assertTrue(merge);
143 
144 		try (TreeWalk tw = new TreeWalk(db)) {
145 			tw.setRecursive(true);
146 			tw.reset(ourMerger.getResultTreeId());
147 
148 			assertTrue(tw.next());
149 			assertEquals("Makefile", tw.getPathString());
150 			assertCorrectId(treeO, tw);
151 
152 			assertTrue(tw.next());
153 			assertEquals("libelf-po/a", tw.getPathString());
154 			assertCorrectId(treeO, tw);
155 
156 			assertTrue(tw.next());
157 			assertEquals("libelf/c", tw.getPathString());
158 			assertCorrectId(treeT, tw);
159 
160 			assertFalse(tw.next());
161 		}
162 	}
163 
164 	@Test
165 	public void testTrivialTwoWay_concurrentSubtreeChange() throws Exception {
166 		DirCache treeB = db.readDirCache();
167 		DirCache treeO = db.readDirCache();
168 		DirCache treeT = db.readDirCache();
169 
170 		DirCacheBuilder bTreeBuilder = treeB.builder();
171 		DirCacheBuilder oTreeBuilder = treeO.builder();
172 		DirCacheBuilder tTreeBuilder = treeT.builder();
173 
174 		bTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE));
175 		bTreeBuilder.add(createEntry("d/t", FileMode.REGULAR_FILE));
176 
177 		oTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE, "o !"));
178 		oTreeBuilder.add(createEntry("d/t", FileMode.REGULAR_FILE));
179 
180 		tTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE));
181 		tTreeBuilder.add(createEntry("d/t", FileMode.REGULAR_FILE, "t !"));
182 
183 		bTreeBuilder.finish();
184 		oTreeBuilder.finish();
185 		tTreeBuilder.finish();
186 
187 		ObjectInserter ow = db.newObjectInserter();
188 		ObjectId b = commit(ow, treeB, new ObjectId[] {});
189 		ObjectId o = commit(ow, treeO, new ObjectId[] { b });
190 		ObjectId t = commit(ow, treeT, new ObjectId[] { b });
191 
192 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
193 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
194 		assertTrue(merge);
195 
196 		try (TreeWalk tw = new TreeWalk(db)) {
197 			tw.setRecursive(true);
198 			tw.reset(ourMerger.getResultTreeId());
199 
200 			assertTrue(tw.next());
201 			assertEquals("d/o", tw.getPathString());
202 			assertCorrectId(treeO, tw);
203 
204 			assertTrue(tw.next());
205 			assertEquals("d/t", tw.getPathString());
206 			assertCorrectId(treeT, tw);
207 
208 			assertFalse(tw.next());
209 		}
210 	}
211 
212 	@Test
213 	public void testTrivialTwoWay_conflictSubtreeChange() throws Exception {
214 		DirCache treeB = db.readDirCache();
215 		DirCache treeO = db.readDirCache();
216 		DirCache treeT = db.readDirCache();
217 
218 		DirCacheBuilder bTreeBuilder = treeB.builder();
219 		DirCacheBuilder oTreeBuilder = treeO.builder();
220 		DirCacheBuilder tTreeBuilder = treeT.builder();
221 
222 		bTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE));
223 		bTreeBuilder.add(createEntry("d/t", FileMode.REGULAR_FILE));
224 
225 		oTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE));
226 		oTreeBuilder.add(createEntry("d/t", FileMode.REGULAR_FILE, "o !"));
227 
228 		tTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE, "t !"));
229 		tTreeBuilder.add(createEntry("d/t", FileMode.REGULAR_FILE, "t !"));
230 
231 		bTreeBuilder.finish();
232 		oTreeBuilder.finish();
233 		tTreeBuilder.finish();
234 
235 		ObjectInserter ow = db.newObjectInserter();
236 		ObjectId b = commit(ow, treeB, new ObjectId[] {});
237 		ObjectId o = commit(ow, treeO, new ObjectId[] { b });
238 		ObjectId t = commit(ow, treeT, new ObjectId[] { b });
239 
240 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
241 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
242 		assertFalse(merge);
243 	}
244 
245 	@Test
246 	public void testTrivialTwoWay_leftDFconflict1() throws Exception {
247 		DirCache treeB = db.readDirCache();
248 		DirCache treeO = db.readDirCache();
249 		DirCache treeT = db.readDirCache();
250 
251 		DirCacheBuilder bTreeBuilder = treeB.builder();
252 		DirCacheBuilder oTreeBuilder = treeO.builder();
253 		DirCacheBuilder tTreeBuilder = treeT.builder();
254 
255 		bTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE));
256 		bTreeBuilder.add(createEntry("d/t", FileMode.REGULAR_FILE));
257 
258 		oTreeBuilder.add(createEntry("d", FileMode.REGULAR_FILE));
259 
260 		tTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE));
261 		tTreeBuilder.add(createEntry("d/t", FileMode.REGULAR_FILE, "t !"));
262 
263 		bTreeBuilder.finish();
264 		oTreeBuilder.finish();
265 		tTreeBuilder.finish();
266 
267 		ObjectInserter ow = db.newObjectInserter();
268 		ObjectId b = commit(ow, treeB, new ObjectId[] {});
269 		ObjectId o = commit(ow, treeO, new ObjectId[] { b });
270 		ObjectId t = commit(ow, treeT, new ObjectId[] { b });
271 
272 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
273 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
274 		assertFalse(merge);
275 	}
276 
277 	@Test
278 	public void testTrivialTwoWay_rightDFconflict1() throws Exception {
279 		DirCache treeB = db.readDirCache();
280 		DirCache treeO = db.readDirCache();
281 		DirCache treeT = db.readDirCache();
282 
283 		DirCacheBuilder bTreeBuilder = treeB.builder();
284 		DirCacheBuilder oTreeBuilder = treeO.builder();
285 		DirCacheBuilder tTreeBuilder = treeT.builder();
286 
287 		bTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE));
288 		bTreeBuilder.add(createEntry("d/t", FileMode.REGULAR_FILE));
289 
290 		oTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE));
291 		oTreeBuilder.add(createEntry("d/t", FileMode.REGULAR_FILE, "o !"));
292 
293 		tTreeBuilder.add(createEntry("d", FileMode.REGULAR_FILE));
294 
295 		bTreeBuilder.finish();
296 		oTreeBuilder.finish();
297 		tTreeBuilder.finish();
298 
299 		ObjectInserter ow = db.newObjectInserter();
300 		ObjectId b = commit(ow, treeB, new ObjectId[] {});
301 		ObjectId o = commit(ow, treeO, new ObjectId[] { b });
302 		ObjectId t = commit(ow, treeT, new ObjectId[] { b });
303 
304 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
305 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
306 		assertFalse(merge);
307 	}
308 
309 	@Test
310 	public void testTrivialTwoWay_leftDFconflict2() throws Exception {
311 		DirCache treeB = db.readDirCache();
312 		DirCache treeO = db.readDirCache();
313 		DirCache treeT = db.readDirCache();
314 
315 		DirCacheBuilder bTreeBuilder = treeB.builder();
316 		DirCacheBuilder oTreeBuilder = treeO.builder();
317 		DirCacheBuilder tTreeBuilder = treeT.builder();
318 
319 		bTreeBuilder.add(createEntry("d", FileMode.REGULAR_FILE));
320 
321 		oTreeBuilder.add(createEntry("d", FileMode.REGULAR_FILE, "o !"));
322 
323 		tTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE));
324 
325 		bTreeBuilder.finish();
326 		oTreeBuilder.finish();
327 		tTreeBuilder.finish();
328 
329 		ObjectInserter ow = db.newObjectInserter();
330 		ObjectId b = commit(ow, treeB, new ObjectId[] {});
331 		ObjectId o = commit(ow, treeO, new ObjectId[] { b });
332 		ObjectId t = commit(ow, treeT, new ObjectId[] { b });
333 
334 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
335 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
336 		assertFalse(merge);
337 	}
338 
339 	@Test
340 	public void testTrivialTwoWay_rightDFconflict2() throws Exception {
341 		DirCache treeB = db.readDirCache();
342 		DirCache treeO = db.readDirCache();
343 		DirCache treeT = db.readDirCache();
344 
345 		DirCacheBuilder bTreeBuilder = treeB.builder();
346 		DirCacheBuilder oTreeBuilder = treeO.builder();
347 		DirCacheBuilder tTreeBuilder = treeT.builder();
348 
349 		bTreeBuilder.add(createEntry("d", FileMode.REGULAR_FILE));
350 
351 		oTreeBuilder.add(createEntry("d/o", FileMode.REGULAR_FILE));
352 
353 		tTreeBuilder.add(createEntry("d", FileMode.REGULAR_FILE, "t !"));
354 
355 		bTreeBuilder.finish();
356 		oTreeBuilder.finish();
357 		tTreeBuilder.finish();
358 
359 		ObjectInserter ow = db.newObjectInserter();
360 		ObjectId b = commit(ow, treeB, new ObjectId[] {});
361 		ObjectId o = commit(ow, treeO, new ObjectId[] { b });
362 		ObjectId t = commit(ow, treeT, new ObjectId[] { b });
363 
364 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
365 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
366 		assertFalse(merge);
367 	}
368 
369 	private static void assertCorrectId(DirCache treeT, TreeWalk tw) {
370 		assertEquals(treeT.getEntry(tw.getPathString()).getObjectId(), tw
371 				.getObjectId(0));
372 	}
373 
374 	private static ObjectId commit(ObjectInserter odi, DirCache treeB,
375 			ObjectId[] parentIds) throws Exception {
376 		CommitBuilder c = new CommitBuilder();
377 		c.setTreeId(treeB.writeTree(odi));
378 		c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
379 		c.setCommitter(c.getAuthor());
380 		c.setParentIds(parentIds);
381 		c.setMessage("Tree " + c.getTreeId().name());
382 		ObjectId id = odi.insert(c);
383 		odi.flush();
384 		return id;
385 	}
386 }