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 org.eclipse.jgit.dircache.DirCache;
19  import org.eclipse.jgit.dircache.DirCacheBuilder;
20  import org.eclipse.jgit.junit.RepositoryTestCase;
21  import org.eclipse.jgit.lib.CommitBuilder;
22  import org.eclipse.jgit.lib.FileMode;
23  import org.eclipse.jgit.lib.ObjectId;
24  import org.eclipse.jgit.lib.ObjectInserter;
25  import org.eclipse.jgit.lib.PersonIdent;
26  import org.eclipse.jgit.treewalk.TreeWalk;
27  import org.junit.Test;
28  
29  public class CherryPickTest extends RepositoryTestCase {
30  	@Test
31  	public void testPick() throws Exception {
32  		// B---O
33  		// \----P---T
34  		//
35  		// Cherry-pick "T" onto "O". This shouldn't introduce "p-fail", which
36  		// was created by "P", nor should it modify "a", which was done by "P".
37  		//
38  		final DirCache treeB = db.readDirCache();
39  		final DirCache treeO = db.readDirCache();
40  		final DirCache treeP = db.readDirCache();
41  		final DirCache treeT = db.readDirCache();
42  		{
43  			final DirCacheBuilder b = treeB.builder();
44  			final DirCacheBuilder o = treeO.builder();
45  			final DirCacheBuilder p = treeP.builder();
46  			final DirCacheBuilder t = treeT.builder();
47  
48  			b.add(createEntry("a", FileMode.REGULAR_FILE));
49  
50  			o.add(createEntry("a", FileMode.REGULAR_FILE));
51  			o.add(createEntry("o", FileMode.REGULAR_FILE));
52  
53  			p.add(createEntry("a", FileMode.REGULAR_FILE, "q"));
54  			p.add(createEntry("p-fail", FileMode.REGULAR_FILE));
55  
56  			t.add(createEntry("a", FileMode.REGULAR_FILE));
57  			t.add(createEntry("t", FileMode.REGULAR_FILE));
58  
59  			b.finish();
60  			o.finish();
61  			p.finish();
62  			t.finish();
63  		}
64  
65  		final ObjectInserter ow = db.newObjectInserter();
66  		final ObjectId B = commit(ow, treeB, new ObjectId[] {});
67  		final ObjectId O = commit(ow, treeO, new ObjectId[] { B });
68  		final ObjectId P = commit(ow, treeP, new ObjectId[] { B });
69  		final ObjectId T = commit(ow, treeT, new ObjectId[] { P });
70  
71  		ThreeWayMerger twm = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
72  		twm.setBase(P);
73  		boolean merge = twm.merge(new ObjectId[] { O, T });
74  		assertTrue(merge);
75  
76  		try (TreeWalk tw = new TreeWalk(db)) {
77  			tw.setRecursive(true);
78  			tw.reset(twm.getResultTreeId());
79  
80  			assertTrue(tw.next());
81  			assertEquals("a", tw.getPathString());
82  			assertCorrectId(treeO, tw);
83  
84  			assertTrue(tw.next());
85  			assertEquals("o", tw.getPathString());
86  			assertCorrectId(treeO, tw);
87  
88  			assertTrue(tw.next());
89  			assertEquals("t", tw.getPathString());
90  			assertCorrectId(treeT, tw);
91  
92  			assertFalse(tw.next());
93  		}
94  	}
95  
96  	@Test
97  	public void testRevert() throws Exception {
98  		// B---P---T
99  		//
100 		// Revert P, this should result in a tree with a
101 		// from B and t from T as the change to a in P
102 		// and addition of t in P is reverted.
103 		//
104 		// We use the standard merge, but change the order
105 		// of the sources.
106 		//
107 		final DirCache treeB = db.readDirCache();
108 		final DirCache treeP = db.readDirCache();
109 		final DirCache treeT = db.readDirCache();
110 		{
111 			final DirCacheBuilder b = treeB.builder();
112 			final DirCacheBuilder p = treeP.builder();
113 			final DirCacheBuilder t = treeT.builder();
114 
115 			b.add(createEntry("a", FileMode.REGULAR_FILE));
116 
117 			p.add(createEntry("a", FileMode.REGULAR_FILE, "q"));
118 			p.add(createEntry("p-fail", FileMode.REGULAR_FILE));
119 
120 			t.add(createEntry("a", FileMode.REGULAR_FILE, "q"));
121 			t.add(createEntry("p-fail", FileMode.REGULAR_FILE));
122 			t.add(createEntry("t", FileMode.REGULAR_FILE));
123 
124 			b.finish();
125 			p.finish();
126 			t.finish();
127 		}
128 
129 		final ObjectInserter ow = db.newObjectInserter();
130 		final ObjectId B = commit(ow, treeB, new ObjectId[] {});
131 		final ObjectId P = commit(ow, treeP, new ObjectId[] { B });
132 		final ObjectId T = commit(ow, treeT, new ObjectId[] { P });
133 
134 		ThreeWayMerger twm = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
135 		twm.setBase(P);
136 		boolean merge = twm.merge(new ObjectId[] { B, T });
137 		assertTrue(merge);
138 
139 		try (TreeWalk tw = new TreeWalk(db)) {
140 			tw.setRecursive(true);
141 			tw.reset(twm.getResultTreeId());
142 
143 			assertTrue(tw.next());
144 			assertEquals("a", tw.getPathString());
145 			assertCorrectId(treeB, tw);
146 
147 			assertTrue(tw.next());
148 			assertEquals("t", tw.getPathString());
149 			assertCorrectId(treeT, tw);
150 
151 			assertFalse(tw.next());
152 		}
153 	}
154 
155 	private static void assertCorrectId(DirCache treeT, TreeWalk tw) {
156 		assertEquals(treeT.getEntry(tw.getPathString()).getObjectId(), tw
157 				.getObjectId(0));
158 	}
159 
160 	private static ObjectId commit(final ObjectInserter odi,
161 			final DirCache treeB,
162 			final ObjectId[] parentIds) throws Exception {
163 		final CommitBuilder c = new CommitBuilder();
164 		c.setTreeId(treeB.writeTree(odi));
165 		c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
166 		c.setCommitter(c.getAuthor());
167 		c.setParentIds(parentIds);
168 		c.setMessage("Tree " + c.getTreeId().name());
169 		ObjectId id = odi.insert(c);
170 		odi.flush();
171 		return id;
172 	}
173 }