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.eclipse.jgit.api.ResetCommand.ResetType.HARD;
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertFalse;
48 import static org.junit.Assert.assertNotNull;
49 import static org.junit.Assert.assertNull;
50 import static org.junit.Assert.assertTrue;
51 import static org.junit.Assert.fail;
52
53 import java.io.File;
54 import java.io.IOException;
55
56 import org.eclipse.jgit.api.ResetCommand.ResetType;
57 import org.eclipse.jgit.api.errors.GitAPIException;
58 import org.eclipse.jgit.api.errors.JGitInternalException;
59 import org.eclipse.jgit.dircache.DirCache;
60 import org.eclipse.jgit.dircache.DirCacheBuilder;
61 import org.eclipse.jgit.dircache.DirCacheEntry;
62 import org.eclipse.jgit.errors.AmbiguousObjectException;
63 import org.eclipse.jgit.junit.RepositoryTestCase;
64 import org.eclipse.jgit.lib.Constants;
65 import org.eclipse.jgit.lib.FileMode;
66 import org.eclipse.jgit.lib.ObjectId;
67 import org.eclipse.jgit.lib.Ref;
68 import org.eclipse.jgit.revwalk.RevCommit;
69 import org.eclipse.jgit.revwalk.RevWalk;
70 import org.eclipse.jgit.treewalk.TreeWalk;
71 import org.eclipse.jgit.util.FileUtils;
72 import org.junit.Assert;
73 import org.junit.Test;
74
75 public class ResetCommandTest extends RepositoryTestCase {
76
77 private Git git;
78
79 private RevCommit initialCommit;
80
81 private RevCommit secondCommit;
82
83 private File indexFile;
84
85 private File indexNestedFile;
86
87 private File untrackedFile;
88
89 private DirCacheEntry prestage;
90
91 public void setupRepository() throws IOException, JGitInternalException,
92 GitAPIException {
93
94
95 git = new Git(db);
96 initialCommit = git.commit().setMessage("initial commit").call();
97
98
99 indexFile = writeTrashFile("a.txt", "content");
100
101
102 indexNestedFile = writeTrashFile("dir/b.txt", "content");
103
104
105 git.add().addFilepattern("a.txt").addFilepattern("dir/b.txt").call();
106 secondCommit = git.commit().setMessage("adding a.txt and dir/b.txt").call();
107
108 prestage = DirCache.read(db.getIndexFile(), db.getFS()).getEntry(indexFile.getName());
109
110
111 writeTrashFile("a.txt", "new content");
112 writeTrashFile("dir/b.txt", "new content");
113 git.add().addFilepattern("a.txt").addFilepattern("dir/b.txt").call();
114
115
116 untrackedFile = writeTrashFile("notAddedToIndex.txt", "content");
117 }
118
119 @Test
120 public void testHardReset() throws JGitInternalException,
121 AmbiguousObjectException, IOException, GitAPIException {
122 setupRepository();
123 ObjectId prevHead = db.resolve(Constants.HEAD);
124 ResetCommand reset = git.reset();
125 assertSameAsHead(reset.setMode(ResetType.HARD)
126 .setRef(initialCommit.getName()).call());
127 assertFalse("reflog should be enabled", reset.isReflogDisabled());
128
129 ObjectId head = db.resolve(Constants.HEAD);
130 assertEquals(initialCommit, head);
131
132 assertFalse(indexFile.exists());
133 assertFalse(indexNestedFile.exists());
134 assertTrue(untrackedFile.exists());
135
136 String fileInIndexPath = indexFile.getAbsolutePath();
137 assertFalse(inHead(fileInIndexPath));
138 assertFalse(inIndex(indexFile.getName()));
139 assertReflog(prevHead, head);
140 assertEquals(prevHead, db.readOrigHead());
141 }
142
143 @Test
144 public void testHardResetReflogDisabled() throws Exception {
145 setupRepository();
146 ObjectId prevHead = db.resolve(Constants.HEAD);
147 ResetCommand reset = git.reset();
148 assertSameAsHead(reset.setMode(ResetType.HARD)
149 .setRef(initialCommit.getName()).disableRefLog(true).call());
150 assertTrue("reflog should be disabled", reset.isReflogDisabled());
151
152 ObjectId head = db.resolve(Constants.HEAD);
153 assertEquals(initialCommit, head);
154
155 assertFalse(indexFile.exists());
156 assertFalse(indexNestedFile.exists());
157 assertTrue(untrackedFile.exists());
158
159 String fileInIndexPath = indexFile.getAbsolutePath();
160 assertFalse(inHead(fileInIndexPath));
161 assertFalse(inIndex(indexFile.getName()));
162 assertReflogDisabled(head);
163 assertEquals(prevHead, db.readOrigHead());
164 }
165
166 @Test
167 public void testHardResetWithConflicts_OverwriteUntrackedFile() throws Exception {
168 setupRepository();
169
170 git.rm().setCached(true).addFilepattern("a.txt").call();
171 assertTrue(new File(db.getWorkTree(), "a.txt").exists());
172
173 git.reset().setMode(ResetType.HARD).setRef(Constants.HEAD).call();
174 assertTrue(new File(db.getWorkTree(), "a.txt").exists());
175 assertEquals("content", read(new File(db.getWorkTree(), "a.txt")));
176 }
177
178 @Test
179 public void testHardResetWithConflicts_DeleteFileFolderConflict() throws Exception {
180 setupRepository();
181
182 writeTrashFile("dir-or-file/c.txt", "content");
183 git.add().addFilepattern("dir-or-file/c.txt").call();
184
185 FileUtils.delete(new File(db.getWorkTree(), "dir-or-file"), FileUtils.RECURSIVE);
186 writeTrashFile("dir-or-file", "content");
187
188 git.reset().setMode(ResetType.HARD).setRef(Constants.HEAD).call();
189 assertFalse(new File(db.getWorkTree(), "dir-or-file").exists());
190 }
191
192 @Test
193 public void testResetToNonexistingHEAD() throws JGitInternalException,
194 AmbiguousObjectException, IOException, GitAPIException {
195
196
197 git = new Git(db);
198 writeTrashFile("f", "content");
199
200 try {
201 git.reset().setRef(Constants.HEAD).call();
202 fail("Expected JGitInternalException didn't occur");
203 } catch (JGitInternalException e) {
204
205 }
206 }
207
208 @Test
209 public void testSoftReset() throws JGitInternalException,
210 AmbiguousObjectException, IOException, GitAPIException {
211 setupRepository();
212 ObjectId prevHead = db.resolve(Constants.HEAD);
213 assertSameAsHead(git.reset().setMode(ResetType.SOFT)
214 .setRef(initialCommit.getName()).call());
215
216 ObjectId head = db.resolve(Constants.HEAD);
217 assertEquals(initialCommit, head);
218
219 assertTrue(untrackedFile.exists());
220 assertTrue(indexFile.exists());
221
222 String fileInIndexPath = indexFile.getAbsolutePath();
223 assertFalse(inHead(fileInIndexPath));
224 assertTrue(inIndex(indexFile.getName()));
225 assertReflog(prevHead, head);
226 assertEquals(prevHead, db.readOrigHead());
227 }
228
229 @Test
230 public void testMixedReset() throws JGitInternalException,
231 AmbiguousObjectException, IOException, GitAPIException {
232 setupRepository();
233 ObjectId prevHead = db.resolve(Constants.HEAD);
234 assertSameAsHead(git.reset().setMode(ResetType.MIXED)
235 .setRef(initialCommit.getName()).call());
236
237 ObjectId head = db.resolve(Constants.HEAD);
238 assertEquals(initialCommit, head);
239
240 assertTrue(untrackedFile.exists());
241 assertTrue(indexFile.exists());
242
243 String fileInIndexPath = indexFile.getAbsolutePath();
244 assertFalse(inHead(fileInIndexPath));
245 assertFalse(inIndex(indexFile.getName()));
246
247 assertReflog(prevHead, head);
248 assertEquals(prevHead, db.readOrigHead());
249 }
250
251 @Test
252 public void testMixedResetRetainsSizeAndModifiedTime() throws Exception {
253 git = new Git(db);
254
255 writeTrashFile("a.txt", "a").setLastModified(
256 System.currentTimeMillis() - 60 * 1000);
257 assertNotNull(git.add().addFilepattern("a.txt").call());
258 assertNotNull(git.commit().setMessage("a commit").call());
259
260 writeTrashFile("b.txt", "b").setLastModified(
261 System.currentTimeMillis() - 60 * 1000);
262 assertNotNull(git.add().addFilepattern("b.txt").call());
263 RevCommit commit2 = git.commit().setMessage("b commit").call();
264 assertNotNull(commit2);
265
266 DirCache cache = db.readDirCache();
267
268 DirCacheEntry aEntry = cache.getEntry("a.txt");
269 assertNotNull(aEntry);
270 assertTrue(aEntry.getLength() > 0);
271 assertTrue(aEntry.getLastModified() > 0);
272
273 DirCacheEntry bEntry = cache.getEntry("b.txt");
274 assertNotNull(bEntry);
275 assertTrue(bEntry.getLength() > 0);
276 assertTrue(bEntry.getLastModified() > 0);
277
278 assertSameAsHead(git.reset().setMode(ResetType.MIXED)
279 .setRef(commit2.getName()).call());
280
281 cache = db.readDirCache();
282
283 DirCacheEntry mixedAEntry = cache.getEntry("a.txt");
284 assertNotNull(mixedAEntry);
285 assertEquals(aEntry.getLastModified(), mixedAEntry.getLastModified());
286 assertEquals(aEntry.getLastModified(), mixedAEntry.getLastModified());
287
288 DirCacheEntry mixedBEntry = cache.getEntry("b.txt");
289 assertNotNull(mixedBEntry);
290 assertEquals(bEntry.getLastModified(), mixedBEntry.getLastModified());
291 assertEquals(bEntry.getLastModified(), mixedBEntry.getLastModified());
292 }
293
294 @Test
295 public void testMixedResetWithUnmerged() throws Exception {
296 git = new Git(db);
297
298 String file = "a.txt";
299 writeTrashFile(file, "data");
300 String file2 = "b.txt";
301 writeTrashFile(file2, "data");
302
303 git.add().addFilepattern(file).addFilepattern(file2).call();
304 git.commit().setMessage("commit").call();
305
306 DirCache index = db.lockDirCache();
307 DirCacheBuilder builder = index.builder();
308 builder.add(createEntry(file, FileMode.REGULAR_FILE, 1, ""));
309 builder.add(createEntry(file, FileMode.REGULAR_FILE, 2, ""));
310 builder.add(createEntry(file, FileMode.REGULAR_FILE, 3, ""));
311 assertTrue(builder.commit());
312
313 assertEquals("[a.txt, mode:100644, stage:1]"
314 + "[a.txt, mode:100644, stage:2]"
315 + "[a.txt, mode:100644, stage:3]",
316 indexState(0));
317
318 assertSameAsHead(git.reset().setMode(ResetType.MIXED).call());
319
320 assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]",
321 indexState(0));
322 }
323
324 @Test
325 public void testPathsReset() throws Exception {
326 setupRepository();
327
328 DirCacheEntry preReset = DirCache.read(db.getIndexFile(), db.getFS())
329 .getEntry(indexFile.getName());
330 assertNotNull(preReset);
331
332 git.add().addFilepattern(untrackedFile.getName()).call();
333
334
335
336 assertSameAsHead(git.reset().addPath(indexFile.getName())
337 .addPath(untrackedFile.getName()).call());
338
339 DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS())
340 .getEntry(indexFile.getName());
341 assertNotNull(postReset);
342 Assert.assertNotSame(preReset.getObjectId(), postReset.getObjectId());
343 Assert.assertEquals(prestage.getObjectId(), postReset.getObjectId());
344
345
346 ObjectId head = db.resolve(Constants.HEAD);
347 assertEquals(secondCommit, head);
348
349 assertTrue(untrackedFile.exists());
350 assertTrue(indexFile.exists());
351 assertTrue(inHead(indexFile.getName()));
352 assertTrue(inIndex(indexFile.getName()));
353 assertFalse(inIndex(untrackedFile.getName()));
354 }
355
356 @Test
357 public void testPathsResetOnDirs() throws Exception {
358 setupRepository();
359
360 DirCacheEntry preReset = DirCache.read(db.getIndexFile(), db.getFS())
361 .getEntry("dir/b.txt");
362 assertNotNull(preReset);
363
364 git.add().addFilepattern(untrackedFile.getName()).call();
365
366
367 assertSameAsHead(git.reset().addPath("dir").call());
368
369 DirCacheEntry postReset = DirCache.read(db.getIndexFile(), db.getFS())
370 .getEntry("dir/b.txt");
371 assertNotNull(postReset);
372 Assert.assertNotSame(preReset.getObjectId(), postReset.getObjectId());
373
374
375 ObjectId head = db.resolve(Constants.HEAD);
376 assertEquals(secondCommit, head);
377
378 assertTrue(untrackedFile.exists());
379 assertTrue(inHead("dir/b.txt"));
380 assertTrue(inIndex("dir/b.txt"));
381 }
382
383 @Test
384 public void testPathsResetWithRef() throws Exception {
385 setupRepository();
386
387 DirCacheEntry preReset = DirCache.read(db.getIndexFile(), db.getFS())
388 .getEntry(indexFile.getName());
389 assertNotNull(preReset);
390
391 git.add().addFilepattern(untrackedFile.getName()).call();
392
393
394
395
396 assertSameAsHead(git.reset().setRef(initialCommit.getName())
397 .addPath(indexFile.getName()).addPath(untrackedFile.getName())
398 .call());
399
400
401 ObjectId head = db.resolve(Constants.HEAD);
402 assertEquals(secondCommit, head);
403
404 assertTrue(untrackedFile.exists());
405 assertTrue(indexFile.exists());
406 assertTrue(inHead(indexFile.getName()));
407 assertFalse(inIndex(indexFile.getName()));
408 assertFalse(inIndex(untrackedFile.getName()));
409 }
410
411 @Test
412 public void testPathsResetWithUnmerged() throws Exception {
413 setupRepository();
414
415 String file = "a.txt";
416 writeTrashFile(file, "data");
417
418 git.add().addFilepattern(file).call();
419 git.commit().setMessage("commit").call();
420
421 DirCache index = db.lockDirCache();
422 DirCacheBuilder builder = index.builder();
423 builder.add(createEntry(file, FileMode.REGULAR_FILE, 1, ""));
424 builder.add(createEntry(file, FileMode.REGULAR_FILE, 2, ""));
425 builder.add(createEntry(file, FileMode.REGULAR_FILE, 3, ""));
426 builder.add(createEntry("b.txt", FileMode.REGULAR_FILE));
427 assertTrue(builder.commit());
428
429 assertEquals("[a.txt, mode:100644, stage:1]"
430 + "[a.txt, mode:100644, stage:2]"
431 + "[a.txt, mode:100644, stage:3]"
432 + "[b.txt, mode:100644]",
433 indexState(0));
434
435 assertSameAsHead(git.reset().addPath(file).call());
436
437 assertEquals("[a.txt, mode:100644]" + "[b.txt, mode:100644]",
438 indexState(0));
439 }
440
441 @Test
442 public void testPathsResetOnUnbornBranch() throws Exception {
443 git = new Git(db);
444 writeTrashFile("a.txt", "content");
445 git.add().addFilepattern("a.txt").call();
446
447 assertSameAsHead(git.reset().addPath("a.txt").call());
448
449 DirCache cache = db.readDirCache();
450 DirCacheEntry aEntry = cache.getEntry("a.txt");
451 assertNull(aEntry);
452 }
453
454 @Test(expected = JGitInternalException.class)
455 public void testPathsResetToNonexistingRef() throws Exception {
456 git = new Git(db);
457 writeTrashFile("a.txt", "content");
458 git.add().addFilepattern("a.txt").call();
459 assertSameAsHead(
460 git.reset().setRef("doesnotexist").addPath("a.txt").call());
461 }
462
463 @Test
464 public void testResetDefaultMode() throws Exception {
465 git = new Git(db);
466 writeTrashFile("a.txt", "content");
467 git.add().addFilepattern("a.txt").call();
468 writeTrashFile("a.txt", "modified");
469
470 assertSameAsHead(git.reset().call());
471
472 DirCache cache = db.readDirCache();
473 DirCacheEntry aEntry = cache.getEntry("a.txt");
474 assertNull(aEntry);
475 assertEquals("modified", read("a.txt"));
476 }
477
478 @Test
479 public void testHardResetOnTag() throws Exception {
480 setupRepository();
481 String tagName = "initialtag";
482 git.tag().setName(tagName).setObjectId(secondCommit)
483 .setMessage("message").call();
484
485 DirCacheEntry preReset = DirCache.read(db.getIndexFile(), db.getFS())
486 .getEntry(indexFile.getName());
487 assertNotNull(preReset);
488
489 git.add().addFilepattern(untrackedFile.getName()).call();
490
491 assertSameAsHead(git.reset().setRef(tagName).setMode(HARD).call());
492
493 ObjectId head = db.resolve(Constants.HEAD);
494 assertEquals(secondCommit, head);
495 }
496
497 @Test
498 public void testHardResetAfterSquashMerge() throws Exception {
499 git = new Git(db);
500
501 writeTrashFile("file1", "file1");
502 git.add().addFilepattern("file1").call();
503 RevCommit first = git.commit().setMessage("initial commit").call();
504
505 assertTrue(new File(db.getWorkTree(), "file1").exists());
506 createBranch(first, "refs/heads/branch1");
507 checkoutBranch("refs/heads/branch1");
508
509 writeTrashFile("file2", "file2");
510 git.add().addFilepattern("file2").call();
511 git.commit().setMessage("second commit").call();
512 assertTrue(new File(db.getWorkTree(), "file2").exists());
513
514 checkoutBranch("refs/heads/master");
515
516 MergeResult result = git.merge()
517 .include(db.exactRef("refs/heads/branch1"))
518 .setSquash(true)
519 .call();
520
521 assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
522 result.getMergeStatus());
523 assertNotNull(db.readSquashCommitMsg());
524
525 assertSameAsHead(git.reset().setMode(ResetType.HARD)
526 .setRef(first.getName()).call());
527
528 assertNull(db.readSquashCommitMsg());
529 }
530
531 @Test
532 public void testHardResetOnUnbornBranch() throws Exception {
533 git = new Git(db);
534 File fileA = writeTrashFile("a.txt", "content");
535 git.add().addFilepattern("a.txt").call();
536
537 assertSameAsHead(git.reset().setMode(ResetType.HARD).call());
538
539 DirCache cache = db.readDirCache();
540 DirCacheEntry aEntry = cache.getEntry("a.txt");
541 assertNull(aEntry);
542 assertFalse(fileA.exists());
543 assertNull(db.resolve(Constants.HEAD));
544 }
545
546 private void assertReflog(ObjectId prevHead, ObjectId head)
547 throws IOException {
548
549 String actualHeadMessage = db.getReflogReader(Constants.HEAD)
550 .getLastEntry().getComment();
551 String expectedHeadMessage = head.getName() + ": updating HEAD";
552 assertEquals(expectedHeadMessage, actualHeadMessage);
553 assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
554 .getLastEntry().getNewId().getName());
555 assertEquals(prevHead.getName(), db.getReflogReader(Constants.HEAD)
556 .getLastEntry().getOldId().getName());
557
558
559 String actualMasterMessage = db.getReflogReader("refs/heads/master")
560 .getLastEntry().getComment();
561 String expectedMasterMessage = head.getName() + ": updating HEAD";
562 assertEquals(expectedMasterMessage, actualMasterMessage);
563 assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
564 .getLastEntry().getNewId().getName());
565 assertEquals(prevHead.getName(), db
566 .getReflogReader("refs/heads/master").getLastEntry().getOldId()
567 .getName());
568 }
569
570 private void assertReflogDisabled(ObjectId head)
571 throws IOException {
572
573 String actualHeadMessage = db.getReflogReader(Constants.HEAD)
574 .getLastEntry().getComment();
575 String expectedHeadMessage = "commit: adding a.txt and dir/b.txt";
576 assertEquals(expectedHeadMessage, actualHeadMessage);
577 assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
578 .getLastEntry().getOldId().getName());
579
580
581 String actualMasterMessage = db.getReflogReader("refs/heads/master")
582 .getLastEntry().getComment();
583 String expectedMasterMessage = "commit: adding a.txt and dir/b.txt";
584 assertEquals(expectedMasterMessage, actualMasterMessage);
585 assertEquals(head.getName(), db.getReflogReader(Constants.HEAD)
586 .getLastEntry().getOldId().getName());
587 }
588
589
590
591
592
593
594
595 private boolean inHead(String path) throws IOException {
596 ObjectId headId = db.resolve(Constants.HEAD);
597 try (RevWalk rw = new RevWalk(db);
598 TreeWalk tw = TreeWalk.forPath(db, path,
599 rw.parseTree(headId))) {
600 return tw != null;
601 }
602 }
603
604
605
606
607
608
609
610
611 private boolean inIndex(String path) throws IOException {
612 DirCache dc = DirCache.read(db.getIndexFile(), db.getFS());
613 return dc.getEntry(path) != null;
614 }
615
616
617
618
619
620
621 private void assertSameAsHead(Ref ref) throws IOException {
622 Ref headRef = db.exactRef(Constants.HEAD);
623 assertEquals(headRef.getName(), ref.getName());
624 assertEquals(headRef.getObjectId(), ref.getObjectId());
625 }
626 }