View Javadoc
1   /*
2    * Copyright (C) 2009, Google Inc.
3    * Copyright (C) 2008, Robin Rosenberg
4    * and other copyright owners as documented in the project's IP log.
5    *
6    * This program and the accompanying materials are made available
7    * under the terms of the Eclipse Distribution License v1.0 which
8    * accompanies this distribution, is reproduced below, and is
9    * available at http://www.eclipse.org/org/documents/edl-v10.php
10   *
11   * All rights reserved.
12   *
13   * Redistribution and use in source and binary forms, with or
14   * without modification, are permitted provided that the following
15   * conditions are met:
16   *
17   * - Redistributions of source code must retain the above copyright
18   *   notice, this list of conditions and the following disclaimer.
19   *
20   * - Redistributions in binary form must reproduce the above
21   *   copyright notice, this list of conditions and the following
22   *   disclaimer in the documentation and/or other materials provided
23   *   with the distribution.
24   *
25   * - Neither the name of the Eclipse Foundation, Inc. nor the
26   *   names of its contributors may be used to endorse or promote
27   *   products derived from this software without specific prior
28   *   written permission.
29   *
30   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
31   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
32   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
35   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
37   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43   */
44  
45  package org.eclipse.jgit.merge;
46  
47  import static org.junit.Assert.assertEquals;
48  import static org.junit.Assert.assertFalse;
49  import static org.junit.Assert.assertTrue;
50  
51  import org.eclipse.jgit.dircache.DirCache;
52  import org.eclipse.jgit.dircache.DirCacheBuilder;
53  import org.eclipse.jgit.junit.RepositoryTestCase;
54  import org.eclipse.jgit.lib.CommitBuilder;
55  import org.eclipse.jgit.lib.FileMode;
56  import org.eclipse.jgit.lib.ObjectId;
57  import org.eclipse.jgit.lib.ObjectInserter;
58  import org.eclipse.jgit.lib.PersonIdent;
59  import org.eclipse.jgit.treewalk.TreeWalk;
60  import org.junit.Test;
61  
62  public class CherryPickTest extends RepositoryTestCase {
63  	@Test
64  	public void testPick() throws Exception {
65  		// B---O
66  		// \----P---T
67  		//
68  		// Cherry-pick "T" onto "O". This shouldn't introduce "p-fail", which
69  		// was created by "P", nor should it modify "a", which was done by "P".
70  		//
71  		final DirCache treeB = db.readDirCache();
72  		final DirCache treeO = db.readDirCache();
73  		final DirCache treeP = db.readDirCache();
74  		final DirCache treeT = db.readDirCache();
75  		{
76  			final DirCacheBuilder b = treeB.builder();
77  			final DirCacheBuilder o = treeO.builder();
78  			final DirCacheBuilder p = treeP.builder();
79  			final DirCacheBuilder t = treeT.builder();
80  
81  			b.add(createEntry("a", FileMode.REGULAR_FILE));
82  
83  			o.add(createEntry("a", FileMode.REGULAR_FILE));
84  			o.add(createEntry("o", FileMode.REGULAR_FILE));
85  
86  			p.add(createEntry("a", FileMode.REGULAR_FILE, "q"));
87  			p.add(createEntry("p-fail", FileMode.REGULAR_FILE));
88  
89  			t.add(createEntry("a", FileMode.REGULAR_FILE));
90  			t.add(createEntry("t", FileMode.REGULAR_FILE));
91  
92  			b.finish();
93  			o.finish();
94  			p.finish();
95  			t.finish();
96  		}
97  
98  		final ObjectInserter ow = db.newObjectInserter();
99  		final ObjectId B = commit(ow, treeB, new ObjectId[] {});
100 		final ObjectId O = commit(ow, treeO, new ObjectId[] { B });
101 		final ObjectId P = commit(ow, treeP, new ObjectId[] { B });
102 		final ObjectId T = commit(ow, treeT, new ObjectId[] { P });
103 
104 		ThreeWayMerger twm = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
105 		twm.setBase(P);
106 		boolean merge = twm.merge(new ObjectId[] { O, T });
107 		assertTrue(merge);
108 
109 		final TreeWalk tw = new TreeWalk(db);
110 		tw.setRecursive(true);
111 		tw.reset(twm.getResultTreeId());
112 
113 		assertTrue(tw.next());
114 		assertEquals("a", tw.getPathString());
115 		assertCorrectId(treeO, tw);
116 
117 		assertTrue(tw.next());
118 		assertEquals("o", tw.getPathString());
119 		assertCorrectId(treeO, tw);
120 
121 		assertTrue(tw.next());
122 		assertEquals("t", tw.getPathString());
123 		assertCorrectId(treeT, tw);
124 
125 		assertFalse(tw.next());
126 	}
127 
128 	@Test
129 	public void testRevert() throws Exception {
130 		// B---P---T
131 		//
132 		// Revert P, this should result in a tree with a
133 		// from B and t from T as the change to a in P
134 		// and addition of t in P is reverted.
135 		//
136 		// We use the standard merge, but change the order
137 		// of the sources.
138 		//
139 		final DirCache treeB = db.readDirCache();
140 		final DirCache treeP = db.readDirCache();
141 		final DirCache treeT = db.readDirCache();
142 		{
143 			final DirCacheBuilder b = treeB.builder();
144 			final DirCacheBuilder p = treeP.builder();
145 			final DirCacheBuilder t = treeT.builder();
146 
147 			b.add(createEntry("a", FileMode.REGULAR_FILE));
148 
149 			p.add(createEntry("a", FileMode.REGULAR_FILE, "q"));
150 			p.add(createEntry("p-fail", FileMode.REGULAR_FILE));
151 
152 			t.add(createEntry("a", FileMode.REGULAR_FILE, "q"));
153 			t.add(createEntry("p-fail", FileMode.REGULAR_FILE));
154 			t.add(createEntry("t", FileMode.REGULAR_FILE));
155 
156 			b.finish();
157 			p.finish();
158 			t.finish();
159 		}
160 
161 		final ObjectInserter ow = db.newObjectInserter();
162 		final ObjectId B = commit(ow, treeB, new ObjectId[] {});
163 		final ObjectId P = commit(ow, treeP, new ObjectId[] { B });
164 		final ObjectId T = commit(ow, treeT, new ObjectId[] { P });
165 
166 		ThreeWayMerger twm = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
167 		twm.setBase(P);
168 		boolean merge = twm.merge(new ObjectId[] { B, T });
169 		assertTrue(merge);
170 
171 		final TreeWalk tw = new TreeWalk(db);
172 		tw.setRecursive(true);
173 		tw.reset(twm.getResultTreeId());
174 
175 		assertTrue(tw.next());
176 		assertEquals("a", tw.getPathString());
177 		assertCorrectId(treeB, tw);
178 
179 		assertTrue(tw.next());
180 		assertEquals("t", tw.getPathString());
181 		assertCorrectId(treeT, tw);
182 
183 		assertFalse(tw.next());
184 	}
185 
186 	private static void assertCorrectId(DirCache treeT, TreeWalk tw) {
187 		assertEquals(treeT.getEntry(tw.getPathString()).getObjectId(), tw
188 				.getObjectId(0));
189 	}
190 
191 	private static ObjectId commit(final ObjectInserter odi,
192 			final DirCache treeB,
193 			final ObjectId[] parentIds) throws Exception {
194 		final CommitBuilder c = new CommitBuilder();
195 		c.setTreeId(treeB.writeTree(odi));
196 		c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
197 		c.setCommitter(c.getAuthor());
198 		c.setParentIds(parentIds);
199 		c.setMessage("Tree " + c.getTreeId().name());
200 		ObjectId id = odi.insert(c);
201 		odi.flush();
202 		return id;
203 	}
204 }