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 		final DirCache treeB = db.readDirCache();
113 		final DirCache treeO = db.readDirCache();
114 		final DirCache treeT = db.readDirCache();
115 		{
116 			final DirCacheBuilder b = treeB.builder();
117 			final DirCacheBuilder o = treeO.builder();
118 			final DirCacheBuilder t = treeT.builder();
119 
120 			b.add(createEntry("libelf-po/a", FileMode.REGULAR_FILE));
121 			b.add(createEntry("libelf/c", FileMode.REGULAR_FILE));
122 
123 			o.add(createEntry("Makefile", FileMode.REGULAR_FILE));
124 			o.add(createEntry("libelf-po/a", FileMode.REGULAR_FILE));
125 			o.add(createEntry("libelf/c", FileMode.REGULAR_FILE));
126 
127 			t.add(createEntry("libelf-po/a", FileMode.REGULAR_FILE));
128 			t.add(createEntry("libelf/c", FileMode.REGULAR_FILE, "blah"));
129 
130 			b.finish();
131 			o.finish();
132 			t.finish();
133 		}
134 
135 		final ObjectInserter ow = db.newObjectInserter();
136 		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
137 		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
138 		final 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 		final DirCache treeB = db.readDirCache();
167 		final DirCache treeO = db.readDirCache();
168 		final DirCache treeT = db.readDirCache();
169 		{
170 			final DirCacheBuilder b = treeB.builder();
171 			final DirCacheBuilder o = treeO.builder();
172 			final DirCacheBuilder t = treeT.builder();
173 
174 			b.add(createEntry("d/o", FileMode.REGULAR_FILE));
175 			b.add(createEntry("d/t", FileMode.REGULAR_FILE));
176 
177 			o.add(createEntry("d/o", FileMode.REGULAR_FILE, "o !"));
178 			o.add(createEntry("d/t", FileMode.REGULAR_FILE));
179 
180 			t.add(createEntry("d/o", FileMode.REGULAR_FILE));
181 			t.add(createEntry("d/t", FileMode.REGULAR_FILE, "t !"));
182 
183 			b.finish();
184 			o.finish();
185 			t.finish();
186 		}
187 
188 		final ObjectInserter ow = db.newObjectInserter();
189 		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
190 		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
191 		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
192 
193 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
194 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
195 		assertTrue(merge);
196 
197 		try (TreeWalk tw = new TreeWalk(db)) {
198 			tw.setRecursive(true);
199 			tw.reset(ourMerger.getResultTreeId());
200 
201 			assertTrue(tw.next());
202 			assertEquals("d/o", tw.getPathString());
203 			assertCorrectId(treeO, tw);
204 
205 			assertTrue(tw.next());
206 			assertEquals("d/t", tw.getPathString());
207 			assertCorrectId(treeT, tw);
208 
209 			assertFalse(tw.next());
210 		}
211 	}
212 
213 	@Test
214 	public void testTrivialTwoWay_conflictSubtreeChange() throws Exception {
215 		final DirCache treeB = db.readDirCache();
216 		final DirCache treeO = db.readDirCache();
217 		final DirCache treeT = db.readDirCache();
218 		{
219 			final DirCacheBuilder b = treeB.builder();
220 			final DirCacheBuilder o = treeO.builder();
221 			final DirCacheBuilder t = treeT.builder();
222 
223 			b.add(createEntry("d/o", FileMode.REGULAR_FILE));
224 			b.add(createEntry("d/t", FileMode.REGULAR_FILE));
225 
226 			o.add(createEntry("d/o", FileMode.REGULAR_FILE));
227 			o.add(createEntry("d/t", FileMode.REGULAR_FILE, "o !"));
228 
229 			t.add(createEntry("d/o", FileMode.REGULAR_FILE, "t !"));
230 			t.add(createEntry("d/t", FileMode.REGULAR_FILE, "t !"));
231 
232 			b.finish();
233 			o.finish();
234 			t.finish();
235 		}
236 
237 		final ObjectInserter ow = db.newObjectInserter();
238 		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
239 		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
240 		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
241 
242 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
243 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
244 		assertFalse(merge);
245 	}
246 
247 	@Test
248 	public void testTrivialTwoWay_leftDFconflict1() throws Exception {
249 		final DirCache treeB = db.readDirCache();
250 		final DirCache treeO = db.readDirCache();
251 		final DirCache treeT = db.readDirCache();
252 		{
253 			final DirCacheBuilder b = treeB.builder();
254 			final DirCacheBuilder o = treeO.builder();
255 			final DirCacheBuilder t = treeT.builder();
256 
257 			b.add(createEntry("d/o", FileMode.REGULAR_FILE));
258 			b.add(createEntry("d/t", FileMode.REGULAR_FILE));
259 
260 			o.add(createEntry("d", FileMode.REGULAR_FILE));
261 
262 			t.add(createEntry("d/o", FileMode.REGULAR_FILE));
263 			t.add(createEntry("d/t", FileMode.REGULAR_FILE, "t !"));
264 
265 			b.finish();
266 			o.finish();
267 			t.finish();
268 		}
269 
270 		final ObjectInserter ow = db.newObjectInserter();
271 		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
272 		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
273 		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
274 
275 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
276 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
277 		assertFalse(merge);
278 	}
279 
280 	@Test
281 	public void testTrivialTwoWay_rightDFconflict1() throws Exception {
282 		final DirCache treeB = db.readDirCache();
283 		final DirCache treeO = db.readDirCache();
284 		final DirCache treeT = db.readDirCache();
285 		{
286 			final DirCacheBuilder b = treeB.builder();
287 			final DirCacheBuilder o = treeO.builder();
288 			final DirCacheBuilder t = treeT.builder();
289 
290 			b.add(createEntry("d/o", FileMode.REGULAR_FILE));
291 			b.add(createEntry("d/t", FileMode.REGULAR_FILE));
292 
293 			o.add(createEntry("d/o", FileMode.REGULAR_FILE));
294 			o.add(createEntry("d/t", FileMode.REGULAR_FILE, "o !"));
295 
296 			t.add(createEntry("d", FileMode.REGULAR_FILE));
297 
298 			b.finish();
299 			o.finish();
300 			t.finish();
301 		}
302 
303 		final ObjectInserter ow = db.newObjectInserter();
304 		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
305 		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
306 		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
307 
308 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
309 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
310 		assertFalse(merge);
311 	}
312 
313 	@Test
314 	public void testTrivialTwoWay_leftDFconflict2() throws Exception {
315 		final DirCache treeB = db.readDirCache();
316 		final DirCache treeO = db.readDirCache();
317 		final DirCache treeT = db.readDirCache();
318 		{
319 			final DirCacheBuilder b = treeB.builder();
320 			final DirCacheBuilder o = treeO.builder();
321 			final DirCacheBuilder t = treeT.builder();
322 
323 			b.add(createEntry("d", FileMode.REGULAR_FILE));
324 
325 			o.add(createEntry("d", FileMode.REGULAR_FILE, "o !"));
326 
327 			t.add(createEntry("d/o", FileMode.REGULAR_FILE));
328 
329 			b.finish();
330 			o.finish();
331 			t.finish();
332 		}
333 
334 		final ObjectInserter ow = db.newObjectInserter();
335 		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
336 		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
337 		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
338 
339 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
340 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
341 		assertFalse(merge);
342 	}
343 
344 	@Test
345 	public void testTrivialTwoWay_rightDFconflict2() throws Exception {
346 		final DirCache treeB = db.readDirCache();
347 		final DirCache treeO = db.readDirCache();
348 		final DirCache treeT = db.readDirCache();
349 		{
350 			final DirCacheBuilder b = treeB.builder();
351 			final DirCacheBuilder o = treeO.builder();
352 			final DirCacheBuilder t = treeT.builder();
353 
354 			b.add(createEntry("d", FileMode.REGULAR_FILE));
355 
356 			o.add(createEntry("d/o", FileMode.REGULAR_FILE));
357 
358 			t.add(createEntry("d", FileMode.REGULAR_FILE, "t !"));
359 
360 			b.finish();
361 			o.finish();
362 			t.finish();
363 		}
364 
365 		final ObjectInserter ow = db.newObjectInserter();
366 		final ObjectId b = commit(ow, treeB, new ObjectId[] {});
367 		final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
368 		final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
369 
370 		Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
371 		boolean merge = ourMerger.merge(new ObjectId[] { o, t });
372 		assertFalse(merge);
373 	}
374 
375 	private static void assertCorrectId(DirCache treeT, TreeWalk tw) {
376 		assertEquals(treeT.getEntry(tw.getPathString()).getObjectId(), tw
377 				.getObjectId(0));
378 	}
379 
380 	private static ObjectId commit(final ObjectInserter odi,
381 			final DirCache treeB,
382 			final ObjectId[] parentIds) throws Exception {
383 		final CommitBuilder c = new CommitBuilder();
384 		c.setTreeId(treeB.writeTree(odi));
385 		c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
386 		c.setCommitter(c.getAuthor());
387 		c.setParentIds(parentIds);
388 		c.setMessage("Tree " + c.getTreeId().name());
389 		ObjectId id = odi.insert(c);
390 		odi.flush();
391 		return id;
392 	}
393 }