1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 package org.eclipse.jgit.api;
44
45 import static org.junit.Assert.assertEquals;
46 import static org.junit.Assert.assertTrue;
47
48 import java.io.File;
49 import java.io.IOException;
50
51 import org.eclipse.jgit.api.CheckoutCommand.Stage;
52 import org.eclipse.jgit.api.errors.JGitInternalException;
53 import org.eclipse.jgit.dircache.DirCache;
54 import org.eclipse.jgit.dircache.DirCacheEntry;
55 import org.eclipse.jgit.errors.NoWorkTreeException;
56 import org.eclipse.jgit.junit.RepositoryTestCase;
57 import org.eclipse.jgit.lib.ConfigConstants;
58 import org.eclipse.jgit.lib.ObjectReader;
59 import org.eclipse.jgit.lib.RepositoryState;
60 import org.eclipse.jgit.lib.StoredConfig;
61 import org.eclipse.jgit.revwalk.RevCommit;
62 import org.junit.Before;
63 import org.junit.Test;
64
65
66
67
68 public class PathCheckoutCommandTest extends RepositoryTestCase {
69
70 private static final String FILE1 = "f/Test.txt";
71
72 private static final String FILE2 = "Test2.txt";
73
74 private static final String FILE3 = "Test3.txt";
75
76 Git git;
77
78 RevCommit initialCommit;
79
80 RevCommit secondCommit;
81
82 @Override
83 @Before
84 public void setUp() throws Exception {
85 super.setUp();
86 git = new Git(db);
87 writeTrashFile(FILE1, "1");
88 writeTrashFile(FILE2, "a");
89 git.add().addFilepattern(FILE1).addFilepattern(FILE2).call();
90 initialCommit = git.commit().setMessage("Initial commit").call();
91 writeTrashFile(FILE1, "2");
92 writeTrashFile(FILE2, "b");
93 git.add().addFilepattern(FILE1).addFilepattern(FILE2).call();
94 secondCommit = git.commit().setMessage("Second commit").call();
95 writeTrashFile(FILE1, "3");
96 writeTrashFile(FILE2, "c");
97 git.add().addFilepattern(FILE1).addFilepattern(FILE2).call();
98 git.commit().setMessage("Third commit").call();
99 }
100
101 @Test
102 public void testUpdateWorkingDirectory() throws Exception {
103 CheckoutCommand co = git.checkout();
104 File written = writeTrashFile(FILE1, "");
105 assertEquals("", read(written));
106 co.addPath(FILE1).call();
107 assertEquals("3", read(written));
108 assertEquals("c", read(new File(db.getWorkTree(), FILE2)));
109 }
110
111 @Test
112 public void testCheckoutFirst() throws Exception {
113 CheckoutCommand co = git.checkout();
114 File written = writeTrashFile(FILE1, "");
115 co.setStartPoint(initialCommit).addPath(FILE1).call();
116 assertEquals("1", read(written));
117 assertEquals("c", read(new File(db.getWorkTree(), FILE2)));
118 }
119
120 @Test
121 public void testCheckoutSecond() throws Exception {
122 CheckoutCommand co = git.checkout();
123 File written = writeTrashFile(FILE1, "");
124 co.setStartPoint("HEAD~1").addPath(FILE1).call();
125 assertEquals("2", read(written));
126 assertEquals("c", read(new File(db.getWorkTree(), FILE2)));
127 }
128
129 @Test
130 public void testCheckoutMultiple() throws Exception {
131 CheckoutCommand co = git.checkout();
132 File test = writeTrashFile(FILE1, "");
133 File test2 = writeTrashFile(FILE2, "");
134 co.setStartPoint("HEAD~2").addPath(FILE1).addPath(FILE2).call();
135 assertEquals("1", read(test));
136 assertEquals("a", read(test2));
137 }
138
139 @Test
140 public void testUpdateWorkingDirectoryFromIndex() throws Exception {
141 CheckoutCommand co = git.checkout();
142 File written = writeTrashFile(FILE1, "3a");
143 git.add().addFilepattern(FILE1).call();
144 written = writeTrashFile(FILE1, "");
145 assertEquals("", read(written));
146 co.addPath(FILE1).call();
147 assertEquals("3a", read(written));
148 assertEquals("c", read(new File(db.getWorkTree(), FILE2)));
149 }
150
151 @Test
152 public void testUpdateWorkingDirectoryFromHeadWithIndexChange()
153 throws Exception {
154 CheckoutCommand co = git.checkout();
155 File written = writeTrashFile(FILE1, "3a");
156 git.add().addFilepattern(FILE1).call();
157 written = writeTrashFile(FILE1, "");
158 assertEquals("", read(written));
159 co.addPath(FILE1).setStartPoint("HEAD").call();
160 assertEquals("3", read(written));
161 assertEquals("c", read(new File(db.getWorkTree(), FILE2)));
162 }
163
164 @Test
165 public void testUpdateWorkingDirectoryFromIndex2() throws Exception {
166 CheckoutCommand co = git.checkout();
167 fsTick(git.getRepository().getIndexFile());
168
169 File written1 = writeTrashFile(FILE1, "3(modified)");
170 File written2 = writeTrashFile(FILE2, "a(modified)");
171 fsTick(written2);
172
173
174 writeTrashFile(FILE3, "foo");
175 git.add().addFilepattern(FILE3).call();
176 fsTick(git.getRepository().getIndexFile());
177
178 git.add().addFilepattern(FILE1).addFilepattern(FILE2).call();
179 fsTick(git.getRepository().getIndexFile());
180
181 writeTrashFile(FILE1, "3(modified again)");
182 writeTrashFile(FILE2, "a(modified again)");
183 fsTick(written2);
184
185 co.addPath(FILE1).setStartPoint(secondCommit).call();
186
187 assertEquals("2", read(written1));
188 assertEquals("a(modified again)", read(written2));
189
190 validateIndex(git);
191 }
192
193 public static void validateIndex(Git git) throws NoWorkTreeException,
194 IOException {
195 DirCache dc = git.getRepository().lockDirCache();
196 try (ObjectReader r = git.getRepository().getObjectDatabase()
197 .newReader()) {
198 for (int i = 0; i < dc.getEntryCount(); ++i) {
199 DirCacheEntry entry = dc.getEntry(i);
200 if (entry.getLength() > 0)
201 assertEquals(entry.getLength(), r.getObjectSize(
202 entry.getObjectId(), ObjectReader.OBJ_ANY));
203 }
204 } finally {
205 dc.unlock();
206 }
207 }
208
209 public void testCheckoutMixedNewlines() throws Exception {
210
211 StoredConfig config = git.getRepository().getConfig();
212 config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
213 ConfigConstants.CONFIG_KEY_AUTOCRLF, true);
214 config.save();
215
216 File written = writeTrashFile(FILE1, "4\r\n4");
217 assertEquals("4\r\n4", read(written));
218
219 git.add().addFilepattern(FILE1).call();
220
221 git.commit().setMessage("CRLF").call();
222
223 written = writeTrashFile(FILE1, "4\n4");
224 assertEquals("4\n4", read(written));
225
226 git.add().addFilepattern(FILE1).call();
227
228 git.checkout().addPath(FILE1).call();
229
230 Status status = git.status().call();
231 assertEquals(0, status.getAdded().size());
232 assertEquals(0, status.getChanged().size());
233 assertEquals(0, status.getConflicting().size());
234 assertEquals(0, status.getMissing().size());
235 assertEquals(0, status.getModified().size());
236 assertEquals(0, status.getRemoved().size());
237 assertEquals(0, status.getUntracked().size());
238 }
239
240 @Test
241 public void testCheckoutRepository() throws Exception {
242 CheckoutCommand co = git.checkout();
243 File test = writeTrashFile(FILE1, "");
244 File test2 = writeTrashFile(FILE2, "");
245 co.setStartPoint("HEAD~2").setAllPaths(true).call();
246 assertEquals("1", read(test));
247 assertEquals("a", read(test2));
248 }
249
250
251 @Test(expected = JGitInternalException.class)
252 public void testCheckoutOfConflictingFileShouldThrow()
253 throws Exception {
254 setupConflictingState();
255
256 git.checkout().addPath(FILE1).call();
257 }
258
259 @Test
260 public void testCheckoutOurs() throws Exception {
261 setupConflictingState();
262
263 git.checkout().setStage(Stage.OURS).addPath(FILE1).call();
264
265 assertEquals("3", read(FILE1));
266 assertStageOneToThree(FILE1);
267 }
268
269 @Test
270 public void testCheckoutTheirs() throws Exception {
271 setupConflictingState();
272
273 git.checkout().setStage(Stage.THEIRS).addPath(FILE1).call();
274
275 assertEquals("Conflicting", read(FILE1));
276 assertStageOneToThree(FILE1);
277 }
278
279 @Test
280 public void testCheckoutOursWhenNoBase() throws Exception {
281 String file = "added.txt";
282
283 git.checkout().setCreateBranch(true).setName("side")
284 .setStartPoint(initialCommit).call();
285 writeTrashFile(file, "Added on side");
286 git.add().addFilepattern(file).call();
287 RevCommit side = git.commit().setMessage("Commit on side").call();
288
289 git.checkout().setName("master").call();
290 writeTrashFile(file, "Added on master");
291 git.add().addFilepattern(file).call();
292 git.commit().setMessage("Commit on master").call();
293
294 git.merge().include(side).call();
295 assertEquals(RepositoryState.MERGING, db.getRepositoryState());
296
297 DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
298 assertEquals("Expected add/add file to not have base stage",
299 DirCacheEntry.STAGE_2, cache.getEntry(file).getStage());
300
301 assertTrue(read(file).startsWith("<<<<<<< HEAD"));
302
303 git.checkout().setStage(Stage.OURS).addPath(file).call();
304
305 assertEquals("Added on master", read(file));
306
307 cache = DirCache.read(db.getIndexFile(), db.getFS());
308 assertEquals("Expected conflict stages to still exist after checkout",
309 DirCacheEntry.STAGE_2, cache.getEntry(file).getStage());
310 }
311
312 @Test(expected = IllegalStateException.class)
313 public void testStageNotPossibleWithBranch() throws Exception {
314 git.checkout().setStage(Stage.OURS).setStartPoint("master").call();
315 }
316
317 private void setupConflictingState() throws Exception {
318 git.checkout().setCreateBranch(true).setName("conflict")
319 .setStartPoint(initialCommit).call();
320 writeTrashFile(FILE1, "Conflicting");
321 RevCommit conflict = git.commit().setAll(true)
322 .setMessage("Conflicting change").call();
323
324 git.checkout().setName("master").call();
325
326 git.merge().include(conflict).call();
327 assertEquals(RepositoryState.MERGING, db.getRepositoryState());
328 assertStageOneToThree(FILE1);
329 }
330
331 private void assertStageOneToThree(String name) throws Exception {
332 DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
333 int i = cache.findEntry(name);
334 DirCacheEntry stage1 = cache.getEntry(i);
335 DirCacheEntry stage2 = cache.getEntry(i + 1);
336 DirCacheEntry stage3 = cache.getEntry(i + 2);
337
338 assertEquals(DirCacheEntry.STAGE_1, stage1.getStage());
339 assertEquals(DirCacheEntry.STAGE_2, stage2.getStage());
340 assertEquals(DirCacheEntry.STAGE_3, stage3.getStage());
341 }
342 }