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.lib.Constants.CHARSET;
46 import static org.hamcrest.CoreMatchers.equalTo;
47 import static org.hamcrest.CoreMatchers.not;
48 import static org.hamcrest.MatcherAssert.assertThat;
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.assertFalse;
51 import static org.junit.Assert.assertNotNull;
52 import static org.junit.Assert.assertTrue;
53 import static org.junit.Assert.fail;
54
55 import java.io.BufferedReader;
56 import java.io.File;
57 import java.io.FileInputStream;
58 import java.io.IOException;
59 import java.io.InputStreamReader;
60 import java.util.Collections;
61 import java.util.Iterator;
62 import java.util.List;
63
64 import org.eclipse.jgit.api.MergeResult.MergeStatus;
65 import org.eclipse.jgit.api.RebaseCommand.InteractiveHandler;
66 import org.eclipse.jgit.api.RebaseCommand.Operation;
67 import org.eclipse.jgit.api.RebaseResult.Status;
68 import org.eclipse.jgit.api.errors.InvalidRebaseStepException;
69 import org.eclipse.jgit.api.errors.RefNotFoundException;
70 import org.eclipse.jgit.api.errors.UnmergedPathsException;
71 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
72 import org.eclipse.jgit.diff.DiffEntry;
73 import org.eclipse.jgit.dircache.DirCacheCheckout;
74 import org.eclipse.jgit.errors.AmbiguousObjectException;
75 import org.eclipse.jgit.errors.IllegalTodoFileModification;
76 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
77 import org.eclipse.jgit.errors.MissingObjectException;
78 import org.eclipse.jgit.junit.RepositoryTestCase;
79 import org.eclipse.jgit.lib.AbbreviatedObjectId;
80 import org.eclipse.jgit.lib.ConfigConstants;
81 import org.eclipse.jgit.lib.Constants;
82 import org.eclipse.jgit.lib.ObjectId;
83 import org.eclipse.jgit.lib.ObjectLoader;
84 import org.eclipse.jgit.lib.PersonIdent;
85 import org.eclipse.jgit.lib.RebaseTodoLine;
86 import org.eclipse.jgit.lib.RebaseTodoLine.Action;
87 import org.eclipse.jgit.lib.RefUpdate;
88 import org.eclipse.jgit.lib.ReflogEntry;
89 import org.eclipse.jgit.lib.RepositoryState;
90 import org.eclipse.jgit.merge.MergeStrategy;
91 import org.eclipse.jgit.revwalk.RevCommit;
92 import org.eclipse.jgit.revwalk.RevSort;
93 import org.eclipse.jgit.revwalk.RevWalk;
94 import org.eclipse.jgit.treewalk.TreeWalk;
95 import org.eclipse.jgit.treewalk.filter.TreeFilter;
96 import org.eclipse.jgit.util.FileUtils;
97 import org.eclipse.jgit.util.IO;
98 import org.eclipse.jgit.util.RawParseUtils;
99 import org.junit.Before;
100 import org.junit.Test;
101
102 public class RebaseCommandTest extends RepositoryTestCase {
103 private static final String GIT_REBASE_TODO = "rebase-merge/git-rebase-todo";
104
105 private static final String FILE1 = "file1";
106
107 protected Git git;
108
109 @Override
110 @Before
111 public void setUp() throws Exception {
112 super.setUp();
113 this.git = new Git(db);
114 }
115
116 private void checkoutCommit(RevCommit commit) throws IllegalStateException,
117 IOException {
118 RevCommit head;
119 try (RevWalk walk = new RevWalk(db)) {
120 head = walk.parseCommit(db.resolve(Constants.HEAD));
121 DirCacheCheckout dco = new DirCacheCheckout(db, head.getTree(),
122 db.lockDirCache(), commit.getTree());
123 dco.setFailOnConflict(true);
124 dco.checkout();
125 }
126
127 RefUpdate refUpdate = db.updateRef(Constants.HEAD, true);
128 refUpdate.setNewObjectId(commit);
129 refUpdate.setRefLogMessage("checkout: moving to " + head.getName(),
130 false);
131 refUpdate.forceUpdate();
132 }
133
134 @Test
135 public void testFastForwardWithNewFile() throws Exception {
136
137 writeTrashFile(FILE1, FILE1);
138 git.add().addFilepattern(FILE1).call();
139 RevCommit first = git.commit().setMessage("Add file1").call();
140
141 assertTrue(new File(db.getWorkTree(), FILE1).exists());
142
143 createBranch(first, "refs/heads/topic");
144
145 File file2 = writeTrashFile("file2", "file2");
146 git.add().addFilepattern("file2").call();
147 RevCommit second = git.commit().setMessage("Add file2").call();
148 assertTrue(new File(db.getWorkTree(), "file2").exists());
149
150 checkoutBranch("refs/heads/topic");
151 assertFalse(new File(db.getWorkTree(), "file2").exists());
152
153 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
154 assertTrue(new File(db.getWorkTree(), "file2").exists());
155 checkFile(file2, "file2");
156 assertEquals(Status.FAST_FORWARD, res.getStatus());
157
158 List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
159 .getReverseEntries();
160 List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic")
161 .getReverseEntries();
162 List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master")
163 .getReverseEntries();
164 assertEquals("rebase finished: returning to refs/heads/topic", headLog
165 .get(0).getComment());
166 assertEquals("checkout: moving from topic to " + second.getName(),
167 headLog.get(1).getComment());
168 assertEquals(2, masterLog.size());
169 assertEquals(2, topicLog.size());
170 assertEquals(
171 "rebase finished: refs/heads/topic onto " + second.getName(),
172 topicLog.get(0).getComment());
173 }
174
175 @Test
176 public void testFastForwardWithMultipleCommits() throws Exception {
177
178 writeTrashFile(FILE1, FILE1);
179 git.add().addFilepattern(FILE1).call();
180 RevCommit first = git.commit().setMessage("Add file1").call();
181
182 assertTrue(new File(db.getWorkTree(), FILE1).exists());
183
184 createBranch(first, "refs/heads/topic");
185
186 File file2 = writeTrashFile("file2", "file2");
187 git.add().addFilepattern("file2").call();
188 git.commit().setMessage("Add file2").call();
189 assertTrue(new File(db.getWorkTree(), "file2").exists());
190
191 writeTrashFile("file2", "file2 new content");
192 git.add().addFilepattern("file2").call();
193 RevCommit second = git.commit().setMessage("Change content of file2")
194 .call();
195
196 checkoutBranch("refs/heads/topic");
197 assertFalse(new File(db.getWorkTree(), "file2").exists());
198
199 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
200 assertTrue(new File(db.getWorkTree(), "file2").exists());
201 checkFile(file2, "file2 new content");
202 assertEquals(Status.FAST_FORWARD, res.getStatus());
203
204 List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
205 .getReverseEntries();
206 List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic")
207 .getReverseEntries();
208 List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master")
209 .getReverseEntries();
210 assertEquals("rebase finished: returning to refs/heads/topic", headLog
211 .get(0).getComment());
212 assertEquals("checkout: moving from topic to " + second.getName(),
213 headLog.get(1).getComment());
214 assertEquals(3, masterLog.size());
215 assertEquals(2, topicLog.size());
216 assertEquals(
217 "rebase finished: refs/heads/topic onto " + second.getName(),
218 topicLog.get(0).getComment());
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245 @Test
246 public void testRebaseShouldIgnoreMergeCommits()
247 throws Exception {
248
249 writeTrashFile(FILE1, FILE1);
250 git.add().addFilepattern(FILE1).call();
251 RevCommit a = git.commit().setMessage("Add file1").call();
252 assertTrue(new File(db.getWorkTree(), FILE1).exists());
253
254
255 createBranch(a, "refs/heads/topic");
256
257
258 writeTrashFile(FILE1, "blah");
259 git.add().addFilepattern(FILE1).call();
260 RevCommit b = git.commit().setMessage("updated file1 on master").call();
261
262 checkoutBranch("refs/heads/topic");
263 writeTrashFile("file3", "more changess");
264 git.add().addFilepattern("file3").call();
265 RevCommit c = git.commit()
266 .setMessage("update file3 on topic").call();
267
268
269 createBranch(c, "refs/heads/side");
270
271
272 writeTrashFile("file2", "file2");
273 git.add().addFilepattern("file2").call();
274 RevCommit d = git.commit().setMessage("Add file2").call();
275 assertTrue(new File(db.getWorkTree(), "file2").exists());
276
277
278 checkoutBranch("refs/heads/side");
279 writeTrashFile("file3", "more change");
280 git.add().addFilepattern("file3").call();
281 RevCommit e = git.commit().setMessage("update file2 on side")
282 .call();
283
284
285 checkoutBranch("refs/heads/topic");
286 MergeResult result = git.merge().include(e.getId())
287 .setStrategy(MergeStrategy.RESOLVE).call();
288 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
289 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
290 assertEquals(Status.OK, res.getStatus());
291
292 try (RevWalk rw = new RevWalk(db)) {
293 rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
294 assertDerivedFrom(rw.next(), e);
295 assertDerivedFrom(rw.next(), d);
296 assertDerivedFrom(rw.next(), c);
297 assertEquals(b, rw.next());
298 assertEquals(a, rw.next());
299 }
300
301 List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
302 .getReverseEntries();
303 List<ReflogEntry> sideLog = db.getReflogReader("refs/heads/side")
304 .getReverseEntries();
305 List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic")
306 .getReverseEntries();
307 List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master")
308 .getReverseEntries();
309 assertEquals("rebase finished: returning to refs/heads/topic", headLog
310 .get(0).getComment());
311 assertEquals("rebase: update file2 on side", headLog.get(1)
312 .getComment());
313 assertEquals("rebase: Add file2", headLog.get(2).getComment());
314 assertEquals("rebase: update file3 on topic", headLog.get(3)
315 .getComment());
316 assertEquals("checkout: moving from topic to " + b.getName(), headLog
317 .get(4).getComment());
318 assertEquals(2, masterLog.size());
319 assertEquals(2, sideLog.size());
320 assertEquals(5, topicLog.size());
321 assertEquals("rebase finished: refs/heads/topic onto " + b.getName(),
322 topicLog.get(0).getComment());
323 }
324
325 static void assertDerivedFrom(RevCommit derived, RevCommit original) {
326 assertThat(derived, not(equalTo(original)));
327 assertEquals(original.getFullMessage(), derived.getFullMessage());
328 }
329
330 @Test
331 public void testRebasePreservingMerges1() throws Exception {
332 doTestRebasePreservingMerges(true);
333 }
334
335 @Test
336 public void testRebasePreservingMerges2() throws Exception {
337 doTestRebasePreservingMerges(false);
338 }
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357 private void doTestRebasePreservingMerges(boolean testConflict)
358 throws Exception {
359
360 writeTrashFile(FILE1, FILE1);
361 git.add().addFilepattern(FILE1).call();
362 RevCommit a = git.commit().setMessage("commit a").call();
363
364
365 createBranch(a, "refs/heads/topic");
366
367
368 writeTrashFile(FILE1, "blah");
369 writeTrashFile("conflict", "b");
370 git.add().addFilepattern(".").call();
371 RevCommit b = git.commit().setMessage("commit b").call();
372
373 checkoutBranch("refs/heads/topic");
374 writeTrashFile("file3", "more changess");
375 git.add().addFilepattern("file3").call();
376 RevCommit c = git.commit().setMessage("commit c").call();
377
378
379 createBranch(c, "refs/heads/side");
380
381
382 writeTrashFile("file2", "file2");
383 if (testConflict)
384 writeTrashFile("conflict", "d");
385 git.add().addFilepattern(".").call();
386 RevCommit d = git.commit().setMessage("commit d").call();
387 assertTrue(new File(db.getWorkTree(), "file2").exists());
388
389
390 checkoutBranch("refs/heads/side");
391 writeTrashFile("file3", "more change");
392 if (testConflict)
393 writeTrashFile("conflict", "e");
394 git.add().addFilepattern(".").call();
395 RevCommit e = git.commit().setMessage("commit e").call();
396
397
398 checkoutBranch("refs/heads/topic");
399 MergeResult result = git.merge().include(e.getId())
400 .setStrategy(MergeStrategy.RESOLVE).call();
401 final RevCommit f;
402 if (testConflict) {
403 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
404 assertEquals(Collections.singleton("conflict"), git.status().call()
405 .getConflicting());
406
407 writeTrashFile("conflict", "f resolved");
408 git.add().addFilepattern("conflict").call();
409 f = git.commit().setMessage("commit f").call();
410 } else {
411 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
412 try (RevWalk rw = new RevWalk(db)) {
413 f = rw.parseCommit(result.getNewHead());
414 }
415 }
416
417 RebaseResult res = git.rebase().setUpstream("refs/heads/master")
418 .setPreserveMerges(true).call();
419 if (testConflict) {
420
421 assertEquals(Status.STOPPED, res.getStatus());
422 assertEquals(Collections.singleton("conflict"), git.status().call()
423 .getConflicting());
424 assertTrue(read("conflict").contains("\nb\n=======\nd\n"));
425
426 writeTrashFile("conflict", "d new");
427 git.add().addFilepattern("conflict").call();
428 res = git.rebase().setOperation(Operation.CONTINUE).call();
429
430
431 assertEquals(Status.STOPPED, res.getStatus());
432 assertEquals(Collections.singleton("conflict"), git.status().call()
433 .getConflicting());
434 assertTrue(read("conflict").contains("\nb\n=======\ne\n"));
435
436 writeTrashFile("conflict", "e new");
437 git.add().addFilepattern("conflict").call();
438 res = git.rebase().setOperation(Operation.CONTINUE).call();
439
440
441 assertEquals(Status.STOPPED, res.getStatus());
442 assertEquals(Collections.singleton("conflict"), git.status().call()
443 .getConflicting());
444 assertTrue(read("conflict").contains("\nd new\n=======\ne new\n"));
445
446 writeTrashFile("conflict", "f new resolved");
447 git.add().addFilepattern("conflict").call();
448 res = git.rebase().setOperation(Operation.CONTINUE).call();
449 }
450 assertEquals(Status.OK, res.getStatus());
451
452 if (testConflict)
453 assertEquals("f new resolved", read("conflict"));
454 assertEquals("blah", read(FILE1));
455 assertEquals("file2", read("file2"));
456 assertEquals("more change", read("file3"));
457
458 try (RevWalk rw = new RevWalk(db)) {
459 rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
460 RevCommit newF = rw.next();
461 assertDerivedFrom(newF, f);
462 assertEquals(2, newF.getParentCount());
463 RevCommit newD = rw.next();
464 assertDerivedFrom(newD, d);
465 if (testConflict)
466 assertEquals("d new", readFile("conflict", newD));
467 RevCommit newE = rw.next();
468 assertDerivedFrom(newE, e);
469 if (testConflict)
470 assertEquals("e new", readFile("conflict", newE));
471 assertEquals(newD, newF.getParent(0));
472 assertEquals(newE, newF.getParent(1));
473 assertDerivedFrom(rw.next(), c);
474 assertEquals(b, rw.next());
475 assertEquals(a, rw.next());
476 }
477 }
478
479 private String readFile(String path, RevCommit commit) throws IOException {
480 try (TreeWalk walk = TreeWalk.forPath(db, path, commit.getTree())) {
481 ObjectLoader loader = db.open(walk.getObjectId(0),
482 Constants.OBJ_BLOB);
483 String result = RawParseUtils.decode(loader.getCachedBytes());
484 return result;
485 }
486 }
487
488 @Test
489 public void testRebasePreservingMergesWithUnrelatedSide1() throws Exception {
490 doTestRebasePreservingMergesWithUnrelatedSide(true);
491 }
492
493 @Test
494 public void testRebasePreservingMergesWithUnrelatedSide2() throws Exception {
495 doTestRebasePreservingMergesWithUnrelatedSide(false);
496 }
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522 private void doTestRebasePreservingMergesWithUnrelatedSide(
523 boolean testConflict) throws Exception {
524 try (RevWalk rw = new RevWalk(db)) {
525 rw.sort(RevSort.TOPO);
526
527 writeTrashFile(FILE1, FILE1);
528 git.add().addFilepattern(FILE1).call();
529 RevCommit a = git.commit().setMessage("commit a").call();
530
531 writeTrashFile("file2", "blah");
532 git.add().addFilepattern("file2").call();
533 RevCommit b = git.commit().setMessage("commit b").call();
534
535
536 createBranch(b, "refs/heads/topic");
537 checkoutBranch("refs/heads/topic");
538
539 writeTrashFile("file3", "more changess");
540 writeTrashFile(FILE1, "preparing conflict");
541 git.add().addFilepattern("file3").addFilepattern(FILE1).call();
542 RevCommit c = git.commit().setMessage("commit c").call();
543
544 createBranch(a, "refs/heads/side");
545 checkoutBranch("refs/heads/side");
546 writeTrashFile("conflict", "e");
547 writeTrashFile(FILE1, FILE1 + "\n" + "line 2");
548 git.add().addFilepattern(".").call();
549 RevCommit e = git.commit().setMessage("commit e").call();
550
551
552 checkoutBranch("refs/heads/topic");
553 MergeResult result = git.merge().include(e)
554 .setStrategy(MergeStrategy.RESOLVE).call();
555
556 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
557 assertEquals(result.getConflicts().keySet(),
558 Collections.singleton(FILE1));
559 writeTrashFile(FILE1, "merge resolution");
560 git.add().addFilepattern(FILE1).call();
561 RevCommit d = git.commit().setMessage("commit d").call();
562
563 RevCommit f = commitFile("file2", "new content two", "topic");
564
565 checkoutBranch("refs/heads/master");
566 writeTrashFile("fileg", "fileg");
567 if (testConflict)
568 writeTrashFile("conflict", "g");
569 git.add().addFilepattern(".").call();
570 RevCommit g = git.commit().setMessage("commit g").call();
571
572 checkoutBranch("refs/heads/topic");
573 RebaseResult res = git.rebase().setUpstream("refs/heads/master")
574 .setPreserveMerges(true).call();
575 if (testConflict) {
576 assertEquals(Status.STOPPED, res.getStatus());
577 assertEquals(Collections.singleton("conflict"), git.status().call()
578 .getConflicting());
579
580 writeTrashFile("conflict", "e");
581 git.add().addFilepattern("conflict").call();
582 res = git.rebase().setOperation(Operation.CONTINUE).call();
583 }
584 assertEquals(Status.OK, res.getStatus());
585
586 assertEquals("merge resolution", read(FILE1));
587 assertEquals("new content two", read("file2"));
588 assertEquals("more changess", read("file3"));
589 assertEquals("fileg", read("fileg"));
590
591 rw.markStart(rw.parseCommit(db.resolve("refs/heads/topic")));
592 RevCommit newF = rw.next();
593 assertDerivedFrom(newF, f);
594 RevCommit newD = rw.next();
595 assertDerivedFrom(newD, d);
596 assertEquals(2, newD.getParentCount());
597 RevCommit newC = rw.next();
598 assertDerivedFrom(newC, c);
599 RevCommit newE = rw.next();
600 assertEquals(e, newE);
601 assertEquals(newC, newD.getParent(0));
602 assertEquals(e, newD.getParent(1));
603 assertEquals(g, rw.next());
604 assertEquals(b, rw.next());
605 assertEquals(a, rw.next());
606 }
607 }
608
609 @Test
610 public void testRebaseParentOntoHeadShouldBeUptoDate() throws Exception {
611 writeTrashFile(FILE1, FILE1);
612 git.add().addFilepattern(FILE1).call();
613 RevCommit parent = git.commit().setMessage("parent comment").call();
614
615 writeTrashFile(FILE1, "another change");
616 git.add().addFilepattern(FILE1).call();
617 git.commit().setMessage("head commit").call();
618
619 RebaseResult result = git.rebase().setUpstream(parent).call();
620 assertEquals(Status.UP_TO_DATE, result.getStatus());
621
622 assertEquals(2, db.getReflogReader(Constants.HEAD).getReverseEntries()
623 .size());
624 assertEquals(2, db.getReflogReader("refs/heads/master")
625 .getReverseEntries().size());
626 }
627
628 @Test
629 public void testUpToDate() throws Exception {
630
631 writeTrashFile(FILE1, FILE1);
632 git.add().addFilepattern(FILE1).call();
633 RevCommit first = git.commit().setMessage("Add file1").call();
634
635 assertTrue(new File(db.getWorkTree(), FILE1).exists());
636
637 RebaseResult res = git.rebase().setUpstream(first).call();
638 assertEquals(Status.UP_TO_DATE, res.getStatus());
639
640 assertEquals(1, db.getReflogReader(Constants.HEAD).getReverseEntries()
641 .size());
642 assertEquals(1, db.getReflogReader("refs/heads/master")
643 .getReverseEntries().size());
644 }
645
646 @Test
647 public void testUnknownUpstream() throws Exception {
648
649 writeTrashFile(FILE1, FILE1);
650 git.add().addFilepattern(FILE1).call();
651 git.commit().setMessage("Add file1").call();
652
653 assertTrue(new File(db.getWorkTree(), FILE1).exists());
654
655 try {
656 git.rebase().setUpstream("refs/heads/xyz").call();
657 fail("expected exception was not thrown");
658 } catch (RefNotFoundException e) {
659
660 }
661 }
662
663 @Test
664 public void testConflictFreeWithSingleFile() throws Exception {
665
666 File theFile = writeTrashFile(FILE1, "1\n2\n3\n");
667 git.add().addFilepattern(FILE1).call();
668 RevCommit second = git.commit().setMessage("Add file1").call();
669 assertTrue(new File(db.getWorkTree(), FILE1).exists());
670
671 writeTrashFile(FILE1, "1master\n2\n3\n");
672 checkFile(theFile, "1master\n2\n3\n");
673 git.add().addFilepattern(FILE1).call();
674 RevCommit lastMasterChange = git.commit().setMessage(
675 "change file1 in master").call();
676
677
678 createBranch(second, "refs/heads/topic");
679 checkoutBranch("refs/heads/topic");
680
681 checkFile(theFile, "1\n2\n3\n");
682
683 assertTrue(new File(db.getWorkTree(), FILE1).exists());
684
685 writeTrashFile(FILE1, "1\n2\n3\ntopic\n");
686 git.add().addFilepattern(FILE1).call();
687 RevCommit origHead = git.commit().setMessage("change file1 in topic")
688 .call();
689
690 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
691 assertEquals(Status.OK, res.getStatus());
692 checkFile(theFile, "1master\n2\n3\ntopic\n");
693
694 assertEquals("refs/heads/topic", db.getFullBranch());
695 try (RevWalk rw = new RevWalk(db)) {
696 assertEquals(lastMasterChange, rw.parseCommit(
697 db.resolve(Constants.HEAD)).getParent(0));
698 }
699 assertEquals(origHead, db.readOrigHead());
700 List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
701 .getReverseEntries();
702 List<ReflogEntry> topicLog = db.getReflogReader("refs/heads/topic")
703 .getReverseEntries();
704 List<ReflogEntry> masterLog = db.getReflogReader("refs/heads/master")
705 .getReverseEntries();
706 assertEquals(2, masterLog.size());
707 assertEquals(3, topicLog.size());
708 assertEquals("rebase finished: refs/heads/topic onto "
709 + lastMasterChange.getName(), topicLog.get(0).getComment());
710 assertEquals("rebase finished: returning to refs/heads/topic", headLog
711 .get(0).getComment());
712 }
713
714 @Test
715 public void testDetachedHead() throws Exception {
716
717 File theFile = writeTrashFile(FILE1, "1\n2\n3\n");
718 git.add().addFilepattern(FILE1).call();
719 RevCommit second = git.commit().setMessage("Add file1").call();
720 assertTrue(new File(db.getWorkTree(), FILE1).exists());
721
722 writeTrashFile(FILE1, "1master\n2\n3\n");
723 checkFile(theFile, "1master\n2\n3\n");
724 git.add().addFilepattern(FILE1).call();
725 RevCommit lastMasterChange = git.commit().setMessage(
726 "change file1 in master").call();
727
728
729 createBranch(second, "refs/heads/topic");
730 checkoutBranch("refs/heads/topic");
731
732 checkFile(theFile, "1\n2\n3\n");
733
734 assertTrue(new File(db.getWorkTree(), FILE1).exists());
735
736 writeTrashFile(FILE1, "1\n2\n3\ntopic\n");
737 git.add().addFilepattern(FILE1).call();
738 RevCommit topicCommit = git.commit()
739 .setMessage("change file1 in topic").call();
740 checkoutBranch("refs/heads/master");
741 checkoutCommit(topicCommit);
742 assertEquals(topicCommit.getId().getName(), db.getFullBranch());
743
744 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
745 assertEquals(Status.OK, res.getStatus());
746 checkFile(theFile, "1master\n2\n3\ntopic\n");
747 try (RevWalk rw = new RevWalk(db)) {
748 assertEquals(lastMasterChange, rw.parseCommit(
749 db.resolve(Constants.HEAD)).getParent(0));
750 }
751
752 List<ReflogEntry> headLog = db.getReflogReader(Constants.HEAD)
753 .getReverseEntries();
754 assertEquals(8, headLog.size());
755 assertEquals("rebase: change file1 in topic", headLog.get(0)
756 .getComment());
757 assertEquals("checkout: moving from " + topicCommit.getName() + " to "
758 + lastMasterChange.getName(), headLog.get(1).getComment());
759 }
760
761 @Test
762 public void testFilesAddedFromTwoBranches() throws Exception {
763
764 writeTrashFile(FILE1, FILE1);
765 git.add().addFilepattern(FILE1).call();
766 RevCommit masterCommit = git.commit().setMessage("Add file1 to master")
767 .call();
768
769
770 createBranch(masterCommit, "refs/heads/file2");
771 checkoutBranch("refs/heads/file2");
772 writeTrashFile("file2", "file2");
773 git.add().addFilepattern("file2").call();
774 RevCommit addFile2 = git.commit().setMessage(
775 "Add file2 to branch file2").call();
776
777
778 createBranch(masterCommit, "refs/heads/file3");
779 checkoutBranch("refs/heads/file3");
780 writeTrashFile("file3", "file3");
781 git.add().addFilepattern("file3").call();
782 git.commit().setMessage("Add file3 to branch file3").call();
783
784 assertTrue(new File(db.getWorkTree(), FILE1).exists());
785 assertFalse(new File(db.getWorkTree(), "file2").exists());
786 assertTrue(new File(db.getWorkTree(), "file3").exists());
787
788 RebaseResult res = git.rebase().setUpstream("refs/heads/file2").call();
789 assertEquals(Status.OK, res.getStatus());
790
791 assertTrue(new File(db.getWorkTree(), FILE1).exists());
792 assertTrue(new File(db.getWorkTree(), "file2").exists());
793 assertTrue(new File(db.getWorkTree(), "file3").exists());
794
795
796 assertEquals("refs/heads/file3", db.getFullBranch());
797 try (RevWalk rw = new RevWalk(db)) {
798 assertEquals(addFile2, rw.parseCommit(
799 db.resolve(Constants.HEAD)).getParent(0));
800 }
801
802 checkoutBranch("refs/heads/file2");
803 assertTrue(new File(db.getWorkTree(), FILE1).exists());
804 assertTrue(new File(db.getWorkTree(), "file2").exists());
805 assertFalse(new File(db.getWorkTree(), "file3").exists());
806 }
807
808 @Test
809 public void testStopOnConflict() throws Exception {
810
811 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
812 "2", "3");
813
814 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
815 checkFile(FILE1, "1master", "2", "3");
816
817 createBranch(firstInMaster, "refs/heads/topic");
818 checkoutBranch("refs/heads/topic");
819
820 checkFile(FILE1, "1", "2", "3");
821
822
823 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
824 "3", "topic4");
825
826
827 RevCommit conflicting = writeFileAndCommit(FILE1,
828 "change file1 in topic", "1topic", "2", "3", "topic4");
829
830 RevCommit lastTopicCommit = writeFileAndCommit(FILE1,
831 "change file1 in topic again", "1topic", "2", "3", "topic4");
832
833 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
834 assertEquals(Status.STOPPED, res.getStatus());
835 assertEquals(conflicting, res.getCurrentCommit());
836 checkFile(FILE1,
837 "<<<<<<< Upstream, based on master\n1master\n=======\n1topic",
838 ">>>>>>> e0d1dea change file1 in topic\n2\n3\ntopic4");
839
840 assertEquals(RepositoryState.REBASING_MERGE, db
841 .getRepositoryState());
842 assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
843
844
845 assertEquals(1, countPicks());
846
847
848 try {
849 git.rebase().setUpstream("refs/heads/master").call();
850 fail("Expected exception was not thrown");
851 } catch (WrongRepositoryStateException e) {
852
853 }
854
855
856 res = git.rebase().setOperation(Operation.ABORT).call();
857 assertEquals(res.getStatus(), Status.ABORTED);
858 assertEquals("refs/heads/topic", db.getFullBranch());
859 checkFile(FILE1, "1topic", "2", "3", "topic4");
860 try (RevWalk rw = new RevWalk(db)) {
861 assertEquals(lastTopicCommit,
862 rw.parseCommit(db.resolve(Constants.HEAD)));
863 }
864 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
865
866
867 assertFalse(new File(db.getDirectory(), "rebase-merge").exists());
868 }
869
870 @Test
871 public void testStopOnConflictAndAbortWithDetachedHEAD() throws Exception {
872
873 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
874 "2", "3");
875
876 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
877 checkFile(FILE1, "1master", "2", "3");
878
879 createBranch(firstInMaster, "refs/heads/topic");
880 checkoutBranch("refs/heads/topic");
881
882 checkFile(FILE1, "1", "2", "3");
883
884
885 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
886 "3", "topic4");
887
888
889 RevCommit conflicting = writeFileAndCommit(FILE1,
890 "change file1 in topic", "1topic", "2", "3", "topic4");
891
892 RevCommit lastTopicCommit = writeFileAndCommit(FILE1,
893 "change file1 in topic again", "1topic", "2", "3", "topic4");
894
895 git.checkout().setName(lastTopicCommit.getName()).call();
896
897 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
898 assertEquals(Status.STOPPED, res.getStatus());
899 assertEquals(conflicting, res.getCurrentCommit());
900 checkFile(FILE1,
901 "<<<<<<< Upstream, based on master\n1master\n=======\n1topic",
902 ">>>>>>> e0d1dea change file1 in topic\n2\n3\ntopic4");
903
904 assertEquals(RepositoryState.REBASING_MERGE,
905 db.getRepositoryState());
906 assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
907
908
909 assertEquals(1, countPicks());
910
911
912 try {
913 git.rebase().setUpstream("refs/heads/master").call();
914 fail("Expected exception was not thrown");
915 } catch (WrongRepositoryStateException e) {
916
917 }
918
919
920 res = git.rebase().setOperation(Operation.ABORT).call();
921 assertEquals(res.getStatus(), Status.ABORTED);
922 assertEquals(lastTopicCommit.getName(), db.getFullBranch());
923 checkFile(FILE1, "1topic", "2", "3", "topic4");
924 try (RevWalk rw = new RevWalk(db)) {
925 assertEquals(lastTopicCommit,
926 rw.parseCommit(db.resolve(Constants.HEAD)));
927 }
928 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
929
930
931 assertFalse(new File(db.getDirectory(), "rebase-merge").exists());
932 }
933
934 @Test
935 public void testStopOnConflictAndContinue() throws Exception {
936
937 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
938 "2", "3");
939
940 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
941
942 checkFile(FILE1, "1master", "2", "3");
943
944 createBranch(firstInMaster, "refs/heads/topic");
945 checkoutBranch("refs/heads/topic");
946
947 checkFile(FILE1, "1", "2", "3");
948
949
950 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
951 "3", "4topic");
952
953
954 writeFileAndCommit(FILE1,
955 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
956 "3", "4topic");
957
958
959 writeFileAndCommit(FILE1, "change file1 in topic again", "1topic",
960 "2topic", "3", "4topic");
961
962 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
963 assertEquals(Status.STOPPED, res.getStatus());
964
965
966 try {
967 res = git.rebase().setOperation(Operation.CONTINUE).call();
968 fail("Expected Exception not thrown");
969 } catch (UnmergedPathsException e) {
970
971 }
972
973
974 writeFileAndAdd(FILE1, "1topic", "2", "3", "4topic");
975
976 res = git.rebase().setOperation(Operation.CONTINUE).call();
977 assertNotNull(res);
978 assertEquals(Status.OK, res.getStatus());
979 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
980
981 ObjectId headId = db.resolve(Constants.HEAD);
982 try (RevWalk rw = new RevWalk(db)) {
983 RevCommit rc = rw.parseCommit(headId);
984 RevCommit parent = rw.parseCommit(rc.getParent(0));
985 assertEquals("change file1 in topic\n\nThis is conflicting", parent
986 .getFullMessage());
987 }
988 }
989
990 @Test
991 public void testStopOnConflictAndContinueWithNoDeltaToMaster()
992 throws Exception {
993
994 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
995 "2", "3");
996
997 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
998
999 checkFile(FILE1, "1master", "2", "3");
1000
1001 createBranch(firstInMaster, "refs/heads/topic");
1002 checkoutBranch("refs/heads/topic");
1003
1004 checkFile(FILE1, "1", "2", "3");
1005
1006
1007 writeFileAndCommit(FILE1,
1008 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1009 "3", "4topic");
1010
1011 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1012 assertEquals(Status.STOPPED, res.getStatus());
1013
1014
1015 try {
1016 res = git.rebase().setOperation(Operation.CONTINUE).call();
1017 fail("Expected Exception not thrown");
1018 } catch (UnmergedPathsException e) {
1019
1020 }
1021
1022
1023 writeFileAndAdd(FILE1, "1master", "2", "3");
1024
1025 res = git.rebase().setOperation(Operation.CONTINUE).call();
1026 assertNotNull(res);
1027 assertEquals(Status.NOTHING_TO_COMMIT, res.getStatus());
1028 assertEquals(RepositoryState.REBASING_MERGE,
1029 db.getRepositoryState());
1030
1031 git.rebase().setOperation(Operation.SKIP).call();
1032
1033 ObjectId headId = db.resolve(Constants.HEAD);
1034 try (RevWalk rw = new RevWalk(db)) {
1035 RevCommit rc = rw.parseCommit(headId);
1036 assertEquals("change file1 in master", rc.getFullMessage());
1037 }
1038 }
1039
1040 @Test
1041 public void testStopOnConflictAndFailContinueIfFileIsDirty()
1042 throws Exception {
1043
1044 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1045 "2", "3");
1046
1047 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1048
1049 checkFile(FILE1, "1master", "2", "3");
1050
1051 createBranch(firstInMaster, "refs/heads/topic");
1052 checkoutBranch("refs/heads/topic");
1053
1054 checkFile(FILE1, "1", "2", "3");
1055
1056
1057 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1058 "3", "4topic");
1059
1060
1061 writeFileAndCommit(FILE1,
1062 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1063 "3", "4topic");
1064
1065
1066 writeFileAndCommit(FILE1, "change file1 in topic again", "1topic",
1067 "2topic", "3", "4topic");
1068
1069 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1070 assertEquals(Status.STOPPED, res.getStatus());
1071
1072 git.add().addFilepattern(FILE1).call();
1073 File trashFile = writeTrashFile(FILE1, "Some local change");
1074
1075 res = git.rebase().setOperation(Operation.CONTINUE).call();
1076 assertNotNull(res);
1077 assertEquals(Status.STOPPED, res.getStatus());
1078 checkFile(trashFile, "Some local change");
1079 }
1080
1081 @Test
1082 public void testStopOnLastConflictAndContinue() throws Exception {
1083
1084 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1085 "2", "3");
1086
1087 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1088
1089 checkFile(FILE1, "1master", "2", "3");
1090
1091 createBranch(firstInMaster, "refs/heads/topic");
1092 checkoutBranch("refs/heads/topic");
1093
1094 checkFile(FILE1, "1", "2", "3");
1095
1096
1097 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1098 "3", "4topic");
1099
1100
1101 writeFileAndCommit(FILE1,
1102 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1103 "3", "4topic");
1104
1105 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1106 assertEquals(Status.STOPPED, res.getStatus());
1107
1108
1109 writeFileAndAdd(FILE1, "1topic", "2", "3", "4topic");
1110
1111 res = git.rebase().setOperation(Operation.CONTINUE).call();
1112 assertNotNull(res);
1113 assertEquals(Status.OK, res.getStatus());
1114 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1115 }
1116
1117 @Test
1118 public void testStopOnLastConflictAndSkip() throws Exception {
1119
1120 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1121 "2", "3");
1122
1123 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1124
1125 checkFile(FILE1, "1master", "2", "3");
1126
1127 createBranch(firstInMaster, "refs/heads/topic");
1128 checkoutBranch("refs/heads/topic");
1129
1130 checkFile(FILE1, "1", "2", "3");
1131
1132
1133 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1134 "3", "4topic");
1135
1136
1137 writeFileAndCommit(FILE1,
1138 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1139 "3", "4topic");
1140
1141 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1142 assertEquals(Status.STOPPED, res.getStatus());
1143
1144
1145 writeFileAndAdd(FILE1, "1topic", "2", "3", "4topic");
1146
1147 res = git.rebase().setOperation(Operation.SKIP).call();
1148 assertNotNull(res);
1149 assertEquals(Status.OK, res.getStatus());
1150 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1151 }
1152
1153 @Test
1154 public void testMergeFirstStopOnLastConflictAndSkip() throws Exception {
1155
1156 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1157 "2", "3");
1158
1159 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1160
1161 checkFile(FILE1, "1master", "2", "3");
1162
1163 createBranch(firstInMaster, "refs/heads/topic");
1164 checkoutBranch("refs/heads/topic");
1165
1166 checkFile(FILE1, "1", "2", "3");
1167
1168
1169 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1topic",
1170 "2", "3", "4topic");
1171
1172
1173 writeFileAndCommit(FILE1,
1174 "change file1 in topic\n\nThis is conflicting", "1topicagain",
1175 "2", "3", "4topic");
1176
1177 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1178 assertEquals(Status.STOPPED, res.getStatus());
1179
1180 writeFileAndAdd(FILE1, "merged");
1181
1182 res = git.rebase().setOperation(Operation.CONTINUE).call();
1183 assertEquals(Status.STOPPED, res.getStatus());
1184
1185 res = git.rebase().setOperation(Operation.SKIP).call();
1186 assertNotNull(res);
1187 assertEquals(Status.OK, res.getStatus());
1188 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1189 checkFile(FILE1, "merged");
1190 }
1191
1192 @Test
1193 public void testStopOnConflictAndSkipNoConflict() throws Exception {
1194
1195 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1196 "2", "3");
1197
1198 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1199
1200 checkFile(FILE1, "1master", "2", "3");
1201
1202 createBranch(firstInMaster, "refs/heads/topic");
1203 checkoutBranch("refs/heads/topic");
1204
1205 checkFile(FILE1, "1", "2", "3");
1206
1207
1208 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1209 "3", "4topic");
1210
1211
1212 writeFileAndCommit(FILE1,
1213 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1214 "3", "4topic");
1215
1216
1217 writeFileAndCommit(FILE1, "change file1 in topic again", "1topic", "2",
1218 "3topic", "4topic");
1219
1220 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1221 assertEquals(Status.STOPPED, res.getStatus());
1222
1223 res = git.rebase().setOperation(Operation.SKIP).call();
1224
1225 checkFile(FILE1, "1master", "2", "3topic", "4topic");
1226 assertEquals(Status.OK, res.getStatus());
1227 }
1228
1229 @Test
1230 public void testStopOnConflictAndSkipWithConflict() throws Exception {
1231
1232 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1233 "2", "3", "4");
1234
1235 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2",
1236 "3master", "4");
1237
1238 checkFile(FILE1, "1master", "2", "3master", "4");
1239
1240 createBranch(firstInMaster, "refs/heads/topic");
1241 checkoutBranch("refs/heads/topic");
1242
1243 checkFile(FILE1, "1", "2", "3", "4");
1244
1245
1246 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1247 "3", "4", "5topic");
1248
1249
1250 writeFileAndCommit(FILE1,
1251 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1252 "3", "4", "5topic");
1253
1254
1255 writeFileAndCommit(FILE1, "change file1 in topic again", "1topic", "2",
1256 "3topic", "4", "5topic");
1257
1258 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1259 assertEquals(Status.STOPPED, res.getStatus());
1260
1261 res = git.rebase().setOperation(Operation.SKIP).call();
1262
1263 checkFile(
1264 FILE1,
1265 "1master\n2\n<<<<<<< Upstream, based on master\n3master\n=======\n3topic",
1266 ">>>>>>> 5afc8df change file1 in topic again\n4\n5topic");
1267 assertEquals(Status.STOPPED, res.getStatus());
1268 }
1269
1270 @Test
1271 public void testStopOnConflictCommitAndContinue() throws Exception {
1272
1273 RevCommit firstInMaster = writeFileAndCommit(FILE1, "Add file1", "1",
1274 "2", "3");
1275
1276 writeFileAndCommit(FILE1, "change file1 in master", "1master", "2", "3");
1277
1278 checkFile(FILE1, "1master", "2", "3");
1279
1280 createBranch(firstInMaster, "refs/heads/topic");
1281 checkoutBranch("refs/heads/topic");
1282
1283 checkFile(FILE1, "1", "2", "3");
1284
1285
1286 writeFileAndCommit(FILE1, "add a line to file1 in topic", "1", "2",
1287 "3", "4topic");
1288
1289
1290 writeFileAndCommit(FILE1,
1291 "change file1 in topic\n\nThis is conflicting", "1topic", "2",
1292 "3", "4topic");
1293
1294
1295 writeFileAndCommit(FILE1, "change file1 in topic again", "1topic", "2",
1296 "3topic", "4topic");
1297
1298 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1299 assertEquals(Status.STOPPED, res.getStatus());
1300
1301
1302 try {
1303 res = git.rebase().setOperation(Operation.CONTINUE).call();
1304 fail("Expected Exception not thrown");
1305 } catch (UnmergedPathsException e) {
1306
1307 }
1308
1309
1310 writeFileAndCommit(FILE1, "A different commit message", "1topic", "2",
1311 "3", "4topic");
1312
1313 res = git.rebase().setOperation(Operation.CONTINUE).call();
1314 assertNotNull(res);
1315
1316
1317
1318
1319 assertEquals(Status.NOTHING_TO_COMMIT, res.getStatus());
1320 assertEquals(RepositoryState.REBASING_MERGE,
1321 db.getRepositoryState());
1322
1323 git.rebase().setOperation(Operation.SKIP).call();
1324
1325 ObjectId headId = db.resolve(Constants.HEAD);
1326 try (RevWalk rw = new RevWalk(db)) {
1327 RevCommit rc = rw.parseCommit(headId);
1328 RevCommit parent = rw.parseCommit(rc.getParent(0));
1329 assertEquals("A different commit message", parent.getFullMessage());
1330 }
1331 }
1332
1333 private RevCommit writeFileAndCommit(String fileName, String commitMessage,
1334 String... lines) throws Exception {
1335 StringBuilder sb = new StringBuilder();
1336 for (String line : lines) {
1337 sb.append(line);
1338 sb.append('\n');
1339 }
1340 writeTrashFile(fileName, sb.toString());
1341 git.add().addFilepattern(fileName).call();
1342 return git.commit().setMessage(commitMessage).call();
1343 }
1344
1345 private void writeFileAndAdd(String fileName, String... lines)
1346 throws Exception {
1347 StringBuilder sb = new StringBuilder();
1348 for (String line : lines) {
1349 sb.append(line);
1350 sb.append('\n');
1351 }
1352 writeTrashFile(fileName, sb.toString());
1353 git.add().addFilepattern(fileName).call();
1354 }
1355
1356 private void checkFile(String fileName, String... lines) throws Exception {
1357 File file = new File(db.getWorkTree(), fileName);
1358 StringBuilder sb = new StringBuilder();
1359 for (String line : lines) {
1360 sb.append(line);
1361 sb.append('\n');
1362 }
1363 checkFile(file, sb.toString());
1364 }
1365
1366 @Test
1367 public void testStopOnConflictFileCreationAndDeletion() throws Exception {
1368
1369 writeTrashFile(FILE1, "Hello World");
1370 git.add().addFilepattern(FILE1).call();
1371
1372 File file2 = writeTrashFile("file2", "Hello World 2");
1373 git.add().addFilepattern("file2").call();
1374
1375 File file3 = writeTrashFile("file3", "Hello World 3");
1376 git.add().addFilepattern("file3").call();
1377
1378 RevCommit firstInMaster = git.commit()
1379 .setMessage("Add file 1, 2 and 3").call();
1380
1381
1382 File file4 = writeTrashFile("file4", "Hello World 4");
1383 git.add().addFilepattern("file4").call();
1384
1385 deleteTrashFile("file2");
1386 git.add().setUpdate(true).addFilepattern("file2").call();
1387
1388
1389 writeTrashFile("folder6/file1", "Hello World folder6");
1390 git.add().addFilepattern("folder6/file1").call();
1391
1392 git.commit().setMessage(
1393 "Add file 4 and folder folder6, delete file2 on master").call();
1394
1395
1396 createBranch(firstInMaster, "refs/heads/topic");
1397 checkoutBranch("refs/heads/topic");
1398
1399 deleteTrashFile("file3");
1400 git.add().setUpdate(true).addFilepattern("file3").call();
1401
1402 File file5 = writeTrashFile("file5", "Hello World 5");
1403 git.add().addFilepattern("file5").call();
1404 git.commit().setMessage("Delete file3 and add file5 in topic").call();
1405
1406
1407 writeTrashFile("folder6", "Hello World 6");
1408 git.add().addFilepattern("folder6").call();
1409
1410 File file7 = writeTrashFile("file7", "Hello World 7");
1411 git.add().addFilepattern("file7").call();
1412
1413 deleteTrashFile("file5");
1414 git.add().setUpdate(true).addFilepattern("file5").call();
1415 RevCommit conflicting = git.commit().setMessage(
1416 "Delete file5, add file folder6 and file7 in topic").call();
1417
1418 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
1419 assertEquals(Status.STOPPED, res.getStatus());
1420 assertEquals(conflicting, res.getCurrentCommit());
1421
1422 assertEquals(RepositoryState.REBASING_MERGE, db
1423 .getRepositoryState());
1424 assertTrue(new File(db.getDirectory(), "rebase-merge").exists());
1425
1426
1427 assertEquals(0, countPicks());
1428
1429 assertFalse(file2.exists());
1430 assertFalse(file3.exists());
1431 assertTrue(file4.exists());
1432 assertFalse(file5.exists());
1433 assertTrue(file7.exists());
1434
1435
1436 res = git.rebase().setOperation(Operation.ABORT).call();
1437 assertEquals(res.getStatus(), Status.ABORTED);
1438 assertEquals("refs/heads/topic", db.getFullBranch());
1439 try (RevWalk rw = new RevWalk(db)) {
1440 assertEquals(conflicting, rw.parseCommit(db.resolve(Constants.HEAD)));
1441 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1442 }
1443
1444
1445 assertFalse(new File(db.getDirectory(), "rebase-merge").exists());
1446
1447 assertTrue(file2.exists());
1448 assertFalse(file3.exists());
1449 assertFalse(file4.exists());
1450 assertFalse(file5.exists());
1451 assertTrue(file7.exists());
1452
1453 }
1454
1455 @Test
1456 public void testAuthorScriptConverter() throws Exception {
1457
1458 PersonIdent ident = new PersonIdent("Author name", "a.mail@some.com",
1459 123456789123L, -60);
1460 String convertedAuthor = git.rebase().toAuthorScript(ident);
1461 String[] lines = convertedAuthor.split("\n");
1462 assertEquals("GIT_AUTHOR_NAME='Author name'", lines[0]);
1463 assertEquals("GIT_AUTHOR_EMAIL='a.mail@some.com'", lines[1]);
1464 assertEquals("GIT_AUTHOR_DATE='@123456789 -0100'", lines[2]);
1465
1466 PersonIdent parsedIdent = git.rebase().parseAuthor(
1467 convertedAuthor.getBytes(CHARSET));
1468 assertEquals(ident.getName(), parsedIdent.getName());
1469 assertEquals(ident.getEmailAddress(), parsedIdent.getEmailAddress());
1470
1471 assertEquals(123456789000L, parsedIdent.getWhen().getTime());
1472 assertEquals(ident.getTimeZoneOffset(), parsedIdent.getTimeZoneOffset());
1473
1474
1475 ident = new PersonIdent("Author name", "a.mail@some.com",
1476 123456789123L, +570);
1477 convertedAuthor = git.rebase().toAuthorScript(ident);
1478 lines = convertedAuthor.split("\n");
1479 assertEquals("GIT_AUTHOR_NAME='Author name'", lines[0]);
1480 assertEquals("GIT_AUTHOR_EMAIL='a.mail@some.com'", lines[1]);
1481 assertEquals("GIT_AUTHOR_DATE='@123456789 +0930'", lines[2]);
1482
1483 parsedIdent = git.rebase().parseAuthor(
1484 convertedAuthor.getBytes(CHARSET));
1485 assertEquals(ident.getName(), parsedIdent.getName());
1486 assertEquals(ident.getEmailAddress(), parsedIdent.getEmailAddress());
1487 assertEquals(123456789000L, parsedIdent.getWhen().getTime());
1488 assertEquals(ident.getTimeZoneOffset(), parsedIdent.getTimeZoneOffset());
1489 }
1490
1491 @Test
1492 public void testRepositoryStateChecks() throws Exception {
1493 try {
1494 git.rebase().setOperation(Operation.ABORT).call();
1495 fail("Expected Exception not thrown");
1496 } catch (WrongRepositoryStateException e) {
1497
1498 }
1499 try {
1500 git.rebase().setOperation(Operation.SKIP).call();
1501 fail("Expected Exception not thrown");
1502 } catch (WrongRepositoryStateException e) {
1503
1504 }
1505 try {
1506 git.rebase().setOperation(Operation.CONTINUE).call();
1507 fail("Expected Exception not thrown");
1508 } catch (WrongRepositoryStateException e) {
1509
1510 }
1511 }
1512
1513 @Test
1514 public void testRebaseWithUntrackedFile() throws Exception {
1515
1516 writeTrashFile(FILE1, "file1");
1517 git.add().addFilepattern(FILE1).call();
1518 RevCommit commit = git.commit().setMessage("commit1").call();
1519
1520
1521 createBranch(commit, "refs/heads/topic");
1522 checkoutBranch("refs/heads/topic");
1523 writeTrashFile("file2", "file2");
1524 git.add().addFilepattern("file2").call();
1525 git.commit().setMessage("commit2").call();
1526
1527
1528 checkoutBranch("refs/heads/master");
1529 writeTrashFile(FILE1, "modified file1");
1530 git.add().addFilepattern(FILE1).call();
1531 git.commit().setMessage("commit3").call();
1532
1533
1534 checkoutBranch("refs/heads/topic");
1535 writeTrashFile("file3", "untracked file3");
1536
1537
1538 assertEquals(Status.OK, git.rebase().setUpstream("refs/heads/master")
1539 .call().getStatus());
1540 }
1541
1542 @Test
1543 public void testRebaseWithUnstagedTopicChange() throws Exception {
1544
1545 writeTrashFile(FILE1, "file1");
1546 git.add().addFilepattern(FILE1).call();
1547 RevCommit commit = git.commit().setMessage("commit1").call();
1548
1549
1550 createBranch(commit, "refs/heads/topic");
1551 checkoutBranch("refs/heads/topic");
1552 writeTrashFile("file2", "file2");
1553 git.add().addFilepattern("file2").call();
1554 git.commit().setMessage("commit2").call();
1555
1556
1557 checkoutBranch("refs/heads/master");
1558 writeTrashFile(FILE1, "modified file1");
1559 git.add().addFilepattern(FILE1).call();
1560 git.commit().setMessage("commit3").call();
1561
1562
1563 checkoutBranch("refs/heads/topic");
1564 writeTrashFile("file2", "unstaged file2");
1565
1566
1567 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1568 .call();
1569 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1570 assertEquals(1, result.getUncommittedChanges().size());
1571 assertEquals("file2", result.getUncommittedChanges().get(0));
1572 }
1573
1574 @Test
1575 public void testRebaseWithUncommittedTopicChange() throws Exception {
1576
1577 writeTrashFile(FILE1, "file1");
1578 git.add().addFilepattern(FILE1).call();
1579 RevCommit commit = git.commit().setMessage("commit1").call();
1580
1581
1582 createBranch(commit, "refs/heads/topic");
1583 checkoutBranch("refs/heads/topic");
1584 writeTrashFile("file2", "file2");
1585 git.add().addFilepattern("file2").call();
1586 git.commit().setMessage("commit2").call();
1587
1588
1589 checkoutBranch("refs/heads/master");
1590 writeTrashFile(FILE1, "modified file1");
1591 git.add().addFilepattern(FILE1).call();
1592 git.commit().setMessage("commit3").call();
1593
1594
1595 checkoutBranch("refs/heads/topic");
1596 File uncommittedFile = writeTrashFile("file2", "uncommitted file2");
1597 git.add().addFilepattern("file2").call();
1598
1599
1600 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1601 .call();
1602 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1603 assertEquals(1, result.getUncommittedChanges().size());
1604 assertEquals("file2", result.getUncommittedChanges().get(0));
1605
1606 checkFile(uncommittedFile, "uncommitted file2");
1607 assertEquals(RepositoryState.SAFE, git.getRepository().getRepositoryState());
1608 }
1609
1610 @Test
1611 public void testRebaseWithUnstagedMasterChange() throws Exception {
1612
1613 writeTrashFile(FILE1, "file1");
1614 git.add().addFilepattern(FILE1).call();
1615 RevCommit commit = git.commit().setMessage("commit1").call();
1616
1617
1618 createBranch(commit, "refs/heads/topic");
1619 checkoutBranch("refs/heads/topic");
1620 writeTrashFile("file2", "file2");
1621 git.add().addFilepattern("file2").call();
1622 git.commit().setMessage("commit2").call();
1623
1624
1625 checkoutBranch("refs/heads/master");
1626 writeTrashFile(FILE1, "modified file1");
1627 git.add().addFilepattern(FILE1).call();
1628 git.commit().setMessage("commit3").call();
1629
1630
1631 checkoutBranch("refs/heads/topic");
1632 writeTrashFile(FILE1, "unstaged modified file1");
1633
1634
1635 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1636 .call();
1637 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1638 assertEquals(1, result.getUncommittedChanges().size());
1639 assertEquals(FILE1, result.getUncommittedChanges().get(0));
1640 }
1641
1642 @Test
1643 public void testRebaseWithUncommittedMasterChange() throws Exception {
1644
1645 writeTrashFile(FILE1, "file1");
1646 git.add().addFilepattern(FILE1).call();
1647 RevCommit commit = git.commit().setMessage("commit1").call();
1648
1649
1650 createBranch(commit, "refs/heads/topic");
1651 checkoutBranch("refs/heads/topic");
1652 writeTrashFile("file2", "file2");
1653 git.add().addFilepattern("file2").call();
1654 git.commit().setMessage("commit2").call();
1655
1656
1657 checkoutBranch("refs/heads/master");
1658 writeTrashFile(FILE1, "modified file1");
1659 git.add().addFilepattern(FILE1).call();
1660 git.commit().setMessage("commit3").call();
1661
1662
1663 checkoutBranch("refs/heads/topic");
1664 writeTrashFile(FILE1, "uncommitted modified file1");
1665 git.add().addFilepattern(FILE1).call();
1666
1667
1668
1669 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1670 .call();
1671 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1672 assertEquals(1, result.getUncommittedChanges().size());
1673 assertEquals(FILE1, result.getUncommittedChanges().get(0));
1674 }
1675
1676 @Test
1677 public void testRebaseWithUnstagedMasterChangeBaseCommit() throws Exception {
1678
1679 writeTrashFile("file0", "file0");
1680 writeTrashFile(FILE1, "file1");
1681 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1682 RevCommit commit = git.commit().setMessage("commit1").call();
1683
1684
1685 createBranch(commit, "refs/heads/topic");
1686 checkoutBranch("refs/heads/topic");
1687 writeTrashFile("file2", "file2");
1688 git.add().addFilepattern("file2").call();
1689 git.commit().setMessage("commit2").call();
1690
1691
1692 checkoutBranch("refs/heads/master");
1693 writeTrashFile(FILE1, "modified file1");
1694 git.add().addFilepattern(FILE1).call();
1695 git.commit().setMessage("commit3").call();
1696
1697
1698 checkoutBranch("refs/heads/topic");
1699 writeTrashFile("file0", "unstaged modified file0");
1700
1701
1702 assertEquals(Status.UNCOMMITTED_CHANGES,
1703 git.rebase().setUpstream("refs/heads/master")
1704 .call().getStatus());
1705 }
1706
1707 @Test
1708 public void testRebaseWithUncommittedMasterChangeBaseCommit()
1709 throws Exception {
1710
1711 File file0 = writeTrashFile("file0", "file0");
1712 writeTrashFile(FILE1, "file1");
1713 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1714 RevCommit commit = git.commit().setMessage("commit1").call();
1715
1716
1717 createBranch(commit, "refs/heads/topic");
1718 checkoutBranch("refs/heads/topic");
1719 writeTrashFile("file2", "file2");
1720 git.add().addFilepattern("file2").call();
1721 git.commit().setMessage("commit2").call();
1722
1723
1724 checkoutBranch("refs/heads/master");
1725 writeTrashFile(FILE1, "modified file1");
1726 git.add().addFilepattern(FILE1).call();
1727 git.commit().setMessage("commit3").call();
1728
1729
1730 checkoutBranch("refs/heads/topic");
1731 write(file0, "unstaged modified file0");
1732 git.add().addFilepattern("file0").call();
1733
1734
1735
1736 String indexState = indexState(CONTENT);
1737
1738
1739 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1740 .call();
1741 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1742 assertEquals(1, result.getUncommittedChanges().size());
1743
1744 assertEquals(indexState, indexState(CONTENT));
1745 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1746 }
1747
1748 @Test
1749 public void testRebaseWithUnstagedMasterChangeOtherCommit()
1750 throws Exception {
1751
1752 writeTrashFile("file0", "file0");
1753 git.add().addFilepattern("file0").call();
1754 git.commit().setMessage("commit0").call();
1755
1756 writeTrashFile(FILE1, "file1");
1757 git.add().addFilepattern(FILE1).call();
1758 RevCommit commit = git.commit().setMessage("commit1").call();
1759
1760
1761 createBranch(commit, "refs/heads/topic");
1762 checkoutBranch("refs/heads/topic");
1763 writeTrashFile("file2", "file2");
1764 git.add().addFilepattern("file2").call();
1765 git.commit().setMessage("commit2").call();
1766
1767
1768 checkoutBranch("refs/heads/master");
1769 writeTrashFile(FILE1, "modified file1");
1770 git.add().addFilepattern(FILE1).call();
1771 git.commit().setMessage("commit3").call();
1772
1773
1774 checkoutBranch("refs/heads/topic");
1775 writeTrashFile("file0", "unstaged modified file0");
1776
1777
1778 assertEquals(Status.UNCOMMITTED_CHANGES,
1779 git.rebase().setUpstream("refs/heads/master")
1780 .call().getStatus());
1781 }
1782
1783 @Test
1784 public void testRebaseWithUncommittedMasterChangeOtherCommit()
1785 throws Exception {
1786
1787 File file0 = writeTrashFile("file0", "file0");
1788 git.add().addFilepattern("file0").call();
1789 git.commit().setMessage("commit0").call();
1790
1791 writeTrashFile(FILE1, "file1");
1792 git.add().addFilepattern(FILE1).call();
1793 RevCommit commit = git.commit().setMessage("commit1").call();
1794
1795
1796 createBranch(commit, "refs/heads/topic");
1797 checkoutBranch("refs/heads/topic");
1798 writeTrashFile("file2", "file2");
1799 git.add().addFilepattern("file2").call();
1800 git.commit().setMessage("commit2").call();
1801
1802
1803 checkoutBranch("refs/heads/master");
1804 writeTrashFile(FILE1, "modified file1");
1805 git.add().addFilepattern(FILE1).call();
1806 git.commit().setMessage("commit3").call();
1807
1808
1809 checkoutBranch("refs/heads/topic");
1810 write(file0, "unstaged modified file0");
1811 git.add().addFilepattern("file0").call();
1812
1813
1814
1815 String indexState = indexState(CONTENT);
1816
1817
1818 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1819 .call();
1820 assertEquals(Status.UNCOMMITTED_CHANGES, result.getStatus());
1821
1822 assertEquals(1, result.getUncommittedChanges().size());
1823 assertEquals("unstaged modified file0", read(file0));
1824
1825 assertEquals(indexState, indexState(CONTENT));
1826 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1827 }
1828
1829 @Test
1830 public void testFastForwardRebaseWithModification() throws Exception {
1831
1832 writeTrashFile("file0", "file0");
1833 writeTrashFile(FILE1, "file1");
1834 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1835 RevCommit commit = git.commit().setMessage("commit1").call();
1836
1837
1838 createBranch(commit, "refs/heads/topic");
1839
1840
1841 writeTrashFile(FILE1, "modified file1");
1842 git.add().addFilepattern(FILE1).call();
1843 git.commit().setMessage("commit2").call();
1844
1845
1846 checkoutBranch("refs/heads/topic");
1847 writeTrashFile("file0", "modified file0 in index");
1848 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1849
1850 writeTrashFile("file0", "modified file0");
1851
1852
1853 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1854 .call();
1855 assertEquals(Status.FAST_FORWARD, result.getStatus());
1856 checkFile(new File(db.getWorkTree(), "file0"), "modified file0");
1857 checkFile(new File(db.getWorkTree(), FILE1), "modified file1");
1858 assertEquals("[file0, mode:100644, content:modified file0 in index]"
1859 + "[file1, mode:100644, content:modified file1]",
1860 indexState(CONTENT));
1861 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1862 }
1863
1864 @Test
1865 public void testRebaseWithModificationShouldNotDeleteData()
1866 throws Exception {
1867
1868 writeTrashFile("file0", "file0");
1869 writeTrashFile(FILE1, "file1");
1870 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1871 RevCommit commit = git.commit().setMessage("commit1").call();
1872
1873
1874 createBranch(commit, "refs/heads/topic");
1875
1876
1877 writeTrashFile(FILE1, "modified file1");
1878 git.add().addFilepattern(FILE1).call();
1879 git.commit().setMessage("commit2").call();
1880
1881
1882 checkoutBranch("refs/heads/topic");
1883 writeTrashFile(FILE1, "modified file1 on topic");
1884 git.add().addFilepattern(FILE1).call();
1885 git.commit().setMessage("commit3").call();
1886
1887 writeTrashFile("file0", "modified file0");
1888
1889 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1890 .call();
1891
1892
1893
1894 if (result.getStatus() == Status.STOPPED)
1895 git.rebase().setOperation(Operation.ABORT).call();
1896
1897 checkFile(new File(db.getWorkTree(), "file0"), "modified file0");
1898 checkFile(new File(db.getWorkTree(), FILE1),
1899 "modified file1 on topic");
1900 assertEquals("[file0, mode:100644, content:file0]"
1901 + "[file1, mode:100644, content:modified file1 on topic]",
1902 indexState(CONTENT));
1903 }
1904
1905 @Test
1906 public void testRebaseWithUncommittedDelete() throws Exception {
1907
1908 File file0 = writeTrashFile("file0", "file0");
1909 writeTrashFile(FILE1, "file1");
1910 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
1911 RevCommit commit = git.commit().setMessage("commit1").call();
1912
1913
1914 createBranch(commit, "refs/heads/topic");
1915
1916
1917 writeTrashFile(FILE1, "modified file1");
1918 git.add().addFilepattern(FILE1).call();
1919 git.commit().setMessage("commit2").call();
1920
1921
1922 checkoutBranch("refs/heads/topic");
1923 git.rm().addFilepattern("file0").call();
1924
1925
1926
1927 RebaseResult result = git.rebase().setUpstream("refs/heads/master")
1928 .call();
1929 assertEquals(Status.FAST_FORWARD, result.getStatus());
1930 assertFalse("File should still be deleted", file0.exists());
1931
1932 assertEquals("[file1, mode:100644, content:modified file1]",
1933 indexState(CONTENT));
1934 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1935 }
1936
1937 @Test
1938 public void testRebaseWithAutoStash()
1939 throws Exception {
1940
1941 db.getConfig().setBoolean(ConfigConstants.CONFIG_REBASE_SECTION, null,
1942 ConfigConstants.CONFIG_KEY_AUTOSTASH, true);
1943 writeTrashFile("file0", "file0");
1944 git.add().addFilepattern("file0").call();
1945 git.commit().setMessage("commit0").call();
1946
1947 writeTrashFile(FILE1, "file1");
1948 git.add().addFilepattern(FILE1).call();
1949 RevCommit commit = git.commit().setMessage("commit1").call();
1950
1951
1952 createBranch(commit, "refs/heads/topic");
1953 checkoutBranch("refs/heads/topic");
1954 writeTrashFile("file2", "file2");
1955 git.add().addFilepattern("file2").call();
1956 git.commit().setMessage("commit2").call();
1957
1958
1959 checkoutBranch("refs/heads/master");
1960 writeTrashFile(FILE1, "modified file1");
1961 git.add().addFilepattern(FILE1).call();
1962 git.commit().setMessage("commit3").call();
1963
1964
1965 checkoutBranch("refs/heads/topic");
1966 writeTrashFile("file0", "unstaged modified file0");
1967
1968
1969 assertEquals(Status.OK,
1970 git.rebase().setUpstream("refs/heads/master").call()
1971 .getStatus());
1972 checkFile(new File(db.getWorkTree(), "file0"),
1973 "unstaged modified file0");
1974 checkFile(new File(db.getWorkTree(), FILE1), "modified file1");
1975 checkFile(new File(db.getWorkTree(), "file2"), "file2");
1976 assertEquals("[file0, mode:100644, content:file0]"
1977 + "[file1, mode:100644, content:modified file1]"
1978 + "[file2, mode:100644, content:file2]",
1979 indexState(CONTENT));
1980 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1981 }
1982
1983 @Test
1984 public void testRebaseWithAutoStashConflictOnApply() throws Exception {
1985
1986 db.getConfig().setBoolean(ConfigConstants.CONFIG_REBASE_SECTION, null,
1987 ConfigConstants.CONFIG_KEY_AUTOSTASH, true);
1988 writeTrashFile("file0", "file0");
1989 git.add().addFilepattern("file0").call();
1990 git.commit().setMessage("commit0").call();
1991
1992 writeTrashFile(FILE1, "file1");
1993 git.add().addFilepattern(FILE1).call();
1994 RevCommit commit = git.commit().setMessage("commit1").call();
1995
1996
1997 createBranch(commit, "refs/heads/topic");
1998 checkoutBranch("refs/heads/topic");
1999 writeTrashFile("file2", "file2");
2000 git.add().addFilepattern("file2").call();
2001 git.commit().setMessage("commit2").call();
2002
2003
2004 checkoutBranch("refs/heads/master");
2005 writeTrashFile(FILE1, "modified file1");
2006 git.add().addFilepattern(FILE1).call();
2007 git.commit().setMessage("commit3").call();
2008
2009
2010 checkoutBranch("refs/heads/topic");
2011 writeTrashFile("file1", "unstaged modified file1");
2012
2013
2014 assertEquals(Status.STASH_APPLY_CONFLICTS,
2015 git.rebase().setUpstream("refs/heads/master").call()
2016 .getStatus());
2017 checkFile(new File(db.getWorkTree(), "file0"), "file0");
2018 checkFile(
2019 new File(db.getWorkTree(), FILE1),
2020 "<<<<<<< HEAD\nmodified file1\n=======\nunstaged modified file1\n>>>>>>> stash\n");
2021 checkFile(new File(db.getWorkTree(), "file2"), "file2");
2022 assertEquals(
2023 "[file0, mode:100644, content:file0]"
2024 + "[file1, mode:100644, stage:1, content:file1]"
2025 + "[file1, mode:100644, stage:2, content:modified file1]"
2026 + "[file1, mode:100644, stage:3, content:unstaged modified file1]"
2027 + "[file2, mode:100644, content:file2]",
2028 indexState(CONTENT));
2029 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
2030
2031 List<DiffEntry> diffs = getStashedDiff();
2032 assertEquals(1, diffs.size());
2033 assertEquals(DiffEntry.ChangeType.MODIFY, diffs.get(0).getChangeType());
2034 assertEquals("file1", diffs.get(0).getOldPath());
2035 }
2036
2037 @Test
2038 public void testFastForwardRebaseWithAutoStash() throws Exception {
2039
2040 db.getConfig().setBoolean(ConfigConstants.CONFIG_REBASE_SECTION, null,
2041 ConfigConstants.CONFIG_KEY_AUTOSTASH, true);
2042 writeTrashFile("file0", "file0");
2043 git.add().addFilepattern("file0").call();
2044 git.commit().setMessage("commit0").call();
2045
2046 writeTrashFile(FILE1, "file1");
2047 git.add().addFilepattern(FILE1).call();
2048 RevCommit commit = git.commit().setMessage("commit1").call();
2049
2050
2051 createBranch(commit, "refs/heads/topic");
2052
2053
2054 checkoutBranch("refs/heads/master");
2055 writeTrashFile(FILE1, "modified file1");
2056 git.add().addFilepattern(FILE1).call();
2057 git.commit().setMessage("commit3").call();
2058
2059
2060 checkoutBranch("refs/heads/topic");
2061 writeTrashFile("file0", "unstaged modified file0");
2062
2063
2064 assertEquals(Status.FAST_FORWARD,
2065 git.rebase().setUpstream("refs/heads/master")
2066 .call().getStatus());
2067 checkFile(new File(db.getWorkTree(), "file0"),
2068 "unstaged modified file0");
2069 checkFile(new File(db.getWorkTree(), FILE1), "modified file1");
2070 assertEquals("[file0, mode:100644, content:file0]"
2071 + "[file1, mode:100644, content:modified file1]",
2072 indexState(CONTENT));
2073 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
2074 }
2075
2076 private List<DiffEntry> getStashedDiff() throws AmbiguousObjectException,
2077 IncorrectObjectTypeException, IOException, MissingObjectException {
2078 ObjectId stashId = db.resolve("stash@{0}");
2079 RevWalk revWalk = new RevWalk(db);
2080 RevCommit stashCommit = revWalk.parseCommit(stashId);
2081 List<DiffEntry> diffs = diffWorkingAgainstHead(stashCommit, revWalk);
2082 return diffs;
2083 }
2084
2085 private TreeWalk createTreeWalk() {
2086 TreeWalk walk = new TreeWalk(db);
2087 walk.setRecursive(true);
2088 walk.setFilter(TreeFilter.ANY_DIFF);
2089 return walk;
2090 }
2091
2092 private List<DiffEntry> diffWorkingAgainstHead(final RevCommit commit,
2093 RevWalk revWalk)
2094 throws IOException {
2095 RevCommit parentCommit = revWalk.parseCommit(commit.getParent(0));
2096 try (TreeWalk walk = createTreeWalk()) {
2097 walk.addTree(parentCommit.getTree());
2098 walk.addTree(commit.getTree());
2099 return DiffEntry.scan(walk);
2100 }
2101 }
2102
2103 private int countPicks() throws IOException {
2104 int count = 0;
2105 File todoFile = getTodoFile();
2106 try (BufferedReader br = new BufferedReader(new InputStreamReader(
2107 new FileInputStream(todoFile), CHARSET))) {
2108 String line = br.readLine();
2109 while (line != null) {
2110 int firstBlank = line.indexOf(' ');
2111 if (firstBlank != -1) {
2112 String actionToken = line.substring(0, firstBlank);
2113 Action action = null;
2114 try {
2115 action = Action.parse(actionToken);
2116 } catch (Exception e) {
2117
2118 }
2119 if (Action.PICK.equals(action))
2120 count++;
2121 }
2122 line = br.readLine();
2123 }
2124 return count;
2125 }
2126 }
2127
2128 @Test
2129 public void testFastForwardWithMultipleCommitsOnDifferentBranches()
2130 throws Exception {
2131
2132 writeTrashFile(FILE1, FILE1);
2133 git.add().addFilepattern(FILE1).call();
2134 RevCommit first = git.commit().setMessage("Add file1").call();
2135 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2136
2137
2138 createBranch(first, "refs/heads/topic");
2139
2140
2141 writeTrashFile("file2", "file2");
2142 git.add().addFilepattern("file2").call();
2143 RevCommit second = git.commit().setMessage("Add file2").call();
2144 assertTrue(new File(db.getWorkTree(), "file2").exists());
2145
2146
2147 createBranch(second, "refs/heads/side");
2148
2149
2150 writeTrashFile(FILE1, "blah");
2151 git.add().addFilepattern(FILE1).call();
2152 git.commit().setMessage("updated file1 on master")
2153 .call();
2154
2155
2156 checkoutBranch("refs/heads/side");
2157 writeTrashFile("file2", "more change");
2158 git.add().addFilepattern("file2").call();
2159 RevCommit fourth = git.commit().setMessage("update file2 on side")
2160 .call();
2161
2162
2163 checkoutBranch("refs/heads/master");
2164 MergeResult result = git.merge().include(fourth.getId())
2165 .setStrategy(MergeStrategy.RESOLVE).call();
2166 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
2167
2168
2169 checkoutBranch("refs/heads/topic");
2170 RebaseResult res = git.rebase().setUpstream("refs/heads/master").call();
2171 assertTrue(new File(db.getWorkTree(), "file2").exists());
2172 checkFile(new File(db.getWorkTree(), "file2"), "more change");
2173 assertEquals(Status.FAST_FORWARD, res.getStatus());
2174 }
2175
2176 @Test
2177 public void testRebaseShouldLeaveWorkspaceUntouchedWithUnstagedChangesConflict()
2178 throws Exception {
2179 writeTrashFile(FILE1, "initial file");
2180 git.add().addFilepattern(FILE1).call();
2181 RevCommit initial = git.commit().setMessage("initial commit").call();
2182 createBranch(initial, "refs/heads/side");
2183
2184 writeTrashFile(FILE1, "updated file");
2185 git.add().addFilepattern(FILE1).call();
2186 git.commit().setMessage("updated FILE1 on master").call();
2187
2188
2189 checkoutBranch("refs/heads/side");
2190 writeTrashFile(FILE1, "side update");
2191 git.add().addFilepattern(FILE1).call();
2192 git.commit().setMessage("updated FILE1 on side").call();
2193
2194 File theFile = writeTrashFile(FILE1, "dirty the file");
2195
2196
2197 RebaseResult rebaseResult = git.rebase()
2198 .setUpstream("refs/heads/master").call();
2199 assertEquals(Status.UNCOMMITTED_CHANGES, rebaseResult.getStatus());
2200 assertEquals(1, rebaseResult.getUncommittedChanges().size());
2201 assertEquals(FILE1, rebaseResult.getUncommittedChanges().get(0));
2202
2203 checkFile(theFile, "dirty the file");
2204
2205 assertEquals(RepositoryState.SAFE, git.getRepository()
2206 .getRepositoryState());
2207 }
2208
2209 @Test
2210 public void testAbortShouldAlsoAbortNonInteractiveRebaseWithRebaseApplyDir()
2211 throws Exception {
2212 writeTrashFile(FILE1, "initial file");
2213 git.add().addFilepattern(FILE1).call();
2214 git.commit().setMessage("initial commit").call();
2215
2216 File applyDir = new File(db.getDirectory(), "rebase-apply");
2217 File headName = new File(applyDir, "head-name");
2218 FileUtils.mkdir(applyDir);
2219 write(headName, "master");
2220 db.writeOrigHead(db.resolve(Constants.HEAD));
2221
2222 git.rebase().setOperation(Operation.ABORT).call();
2223
2224 assertFalse("Abort should clean up .git/rebase-apply",
2225 applyDir.exists());
2226 assertEquals(RepositoryState.SAFE, git.getRepository()
2227 .getRepositoryState());
2228 }
2229
2230 @Test
2231 public void testRebaseShouldBeAbleToHandleEmptyLinesInRebaseTodoFile()
2232 throws IOException {
2233 String emptyLine = "\n";
2234 String todo = "pick 1111111 Commit 1\n" + emptyLine
2235 + "pick 2222222 Commit 2\n" + emptyLine
2236 + "# Comment line at end\n";
2237 write(getTodoFile(), todo);
2238
2239 List<RebaseTodoLine> steps = db.readRebaseTodo(GIT_REBASE_TODO, false);
2240 assertEquals(2, steps.size());
2241 assertEquals("1111111", steps.get(0).getCommit().name());
2242 assertEquals("2222222", steps.get(1).getCommit().name());
2243 }
2244
2245 @Test
2246 public void testRebaseShouldBeAbleToHandleLinesWithoutCommitMessageInRebaseTodoFile()
2247 throws IOException {
2248 String todo = "pick 1111111 \n" + "pick 2222222 Commit 2\n"
2249 + "# Comment line at end\n";
2250 write(getTodoFile(), todo);
2251
2252 List<RebaseTodoLine> steps = db.readRebaseTodo(GIT_REBASE_TODO, false);
2253 assertEquals(2, steps.size());
2254 assertEquals("1111111", steps.get(0).getCommit().name());
2255 assertEquals("2222222", steps.get(1).getCommit().name());
2256 }
2257
2258 @Test
2259 public void testRebaseShouldNotFailIfUserAddCommentLinesInPrepareSteps()
2260 throws Exception {
2261 commitFile(FILE1, FILE1, "master");
2262 RevCommit c2 = commitFile("file2", "file2", "master");
2263
2264
2265 commitFile(FILE1, "blah", "master");
2266 RevCommit c4 = commitFile("file2", "more change", "master");
2267
2268 RebaseResult res = git.rebase().setUpstream("HEAD~2")
2269 .runInteractively(new InteractiveHandler() {
2270 @Override
2271 public void prepareSteps(List<RebaseTodoLine> steps) {
2272 steps.add(0, new RebaseTodoLine(
2273 "# Comment that should not be processed"));
2274 }
2275
2276 @Override
2277 public String modifyCommitMessage(String commit) {
2278 fail("modifyCommitMessage() was not expected to be called");
2279 return commit;
2280 }
2281 }).call();
2282
2283 assertEquals(RebaseResult.Status.FAST_FORWARD, res.getStatus());
2284
2285 RebaseResult res2 = git.rebase().setUpstream("HEAD~2")
2286 .runInteractively(new InteractiveHandler() {
2287 @Override
2288 public void prepareSteps(List<RebaseTodoLine> steps) {
2289 try {
2290
2291 steps.get(0).setAction(Action.COMMENT);
2292 } catch (IllegalTodoFileModification e) {
2293 fail("unexpected exception: " + e);
2294 }
2295 }
2296
2297 @Override
2298 public String modifyCommitMessage(String commit) {
2299 fail("modifyCommitMessage() was not expected to be called");
2300 return commit;
2301 }
2302 }).call();
2303
2304 assertEquals(RebaseResult.Status.OK, res2.getStatus());
2305
2306 ObjectId headId = db.resolve(Constants.HEAD);
2307 try (RevWalk rw = new RevWalk(db)) {
2308 RevCommit rc = rw.parseCommit(headId);
2309
2310 ObjectId head1Id = db.resolve(Constants.HEAD + "~1");
2311 RevCommit rc1 = rw.parseCommit(head1Id);
2312
2313 assertEquals(rc.getFullMessage(), c4.getFullMessage());
2314 assertEquals(rc1.getFullMessage(), c2.getFullMessage());
2315 }
2316 }
2317
2318 @Test
2319 public void testParseRewordCommand() throws Exception {
2320 String todo = "pick 1111111 Commit 1\n"
2321 + "reword 2222222 Commit 2\n";
2322 write(getTodoFile(), todo);
2323
2324 List<RebaseTodoLine> steps = db.readRebaseTodo(GIT_REBASE_TODO, false);
2325
2326 assertEquals(2, steps.size());
2327 assertEquals("1111111", steps.get(0).getCommit().name());
2328 assertEquals("2222222", steps.get(1).getCommit().name());
2329 assertEquals(Action.REWORD, steps.get(1).getAction());
2330 }
2331
2332 @Test
2333 public void testEmptyRebaseTodo() throws Exception {
2334 write(getTodoFile(), "");
2335 assertEquals(0, db.readRebaseTodo(GIT_REBASE_TODO, true).size());
2336 assertEquals(0, db.readRebaseTodo(GIT_REBASE_TODO, false).size());
2337 }
2338
2339 @Test
2340 public void testOnlyCommentRebaseTodo() throws Exception {
2341 write(getTodoFile(), "# a b c d e\n# e f");
2342 assertEquals(0, db.readRebaseTodo(GIT_REBASE_TODO, false).size());
2343 List<RebaseTodoLine> lines = db.readRebaseTodo(GIT_REBASE_TODO, true);
2344 assertEquals(2, lines.size());
2345 for (RebaseTodoLine line : lines)
2346 assertEquals(Action.COMMENT, line.getAction());
2347 write(getTodoFile(), "# a b c d e\n# e f\n");
2348 assertEquals(0, db.readRebaseTodo(GIT_REBASE_TODO, false).size());
2349 lines = db.readRebaseTodo(GIT_REBASE_TODO, true);
2350 assertEquals(2, lines.size());
2351 for (RebaseTodoLine line : lines)
2352 assertEquals(Action.COMMENT, line.getAction());
2353 write(getTodoFile(), " \r\n# a b c d e\r\n# e f\r\n#");
2354 assertEquals(0, db.readRebaseTodo(GIT_REBASE_TODO, false).size());
2355 lines = db.readRebaseTodo(GIT_REBASE_TODO, true);
2356 assertEquals(4, lines.size());
2357 for (RebaseTodoLine line : lines)
2358 assertEquals(Action.COMMENT, line.getAction());
2359 }
2360
2361 @Test
2362 public void testLeadingSpacesRebaseTodo() throws Exception {
2363 String todo = " \t\t pick 1111111 Commit 1\n"
2364 + "\t\n"
2365 + "\treword 2222222 Commit 2\n";
2366 write(getTodoFile(), todo);
2367
2368 List<RebaseTodoLine> steps = db.readRebaseTodo(GIT_REBASE_TODO, false);
2369
2370 assertEquals(2, steps.size());
2371 assertEquals("1111111", steps.get(0).getCommit().name());
2372 assertEquals("2222222", steps.get(1).getCommit().name());
2373 assertEquals(Action.REWORD, steps.get(1).getAction());
2374 }
2375
2376 @Test
2377 public void testRebaseShouldTryToParseValidLineMarkedAsComment()
2378 throws IOException {
2379 String todo = "# pick 1111111 Valid line commented out with space\n"
2380 + "#edit 2222222 Valid line commented out without space\n"
2381 + "# pick invalidLine Comment line at end\n";
2382 write(getTodoFile(), todo);
2383
2384 List<RebaseTodoLine> steps = db.readRebaseTodo(GIT_REBASE_TODO, true);
2385 assertEquals(3, steps.size());
2386
2387 RebaseTodoLine firstLine = steps.get(0);
2388
2389 assertEquals("1111111", firstLine.getCommit().name());
2390 assertEquals("Valid line commented out with space",
2391 firstLine.getShortMessage());
2392 assertEquals("comment", firstLine.getAction().toToken());
2393
2394 try {
2395 firstLine.setAction(Action.PICK);
2396 assertEquals("1111111", firstLine.getCommit().name());
2397 assertEquals("pick", firstLine.getAction().toToken());
2398 } catch (Exception e) {
2399 fail("Valid parsable RebaseTodoLine that has been commented out should allow to change the action, but failed");
2400 }
2401
2402 assertEquals("2222222", steps.get(1).getCommit().name());
2403 assertEquals("comment", steps.get(1).getAction().toToken());
2404
2405 assertEquals(null, steps.get(2).getCommit());
2406 assertEquals(null, steps.get(2).getShortMessage());
2407 assertEquals("comment", steps.get(2).getAction().toToken());
2408 assertEquals("# pick invalidLine Comment line at end", steps.get(2)
2409 .getComment());
2410 try {
2411 steps.get(2).setAction(Action.PICK);
2412 fail("A comment RebaseTodoLine that doesn't contain a valid parsable line should fail, but doesn't");
2413 } catch (Exception e) {
2414
2415 }
2416
2417 }
2418
2419 @SuppressWarnings("unused")
2420 @Test
2421 public void testRebaseTodoLineSetComment() throws Exception {
2422 try {
2423 new RebaseTodoLine("This is a invalid comment");
2424 fail("Constructing a comment line with invalid comment string should fail, but doesn't");
2425 } catch (IllegalArgumentException e) {
2426
2427 }
2428 RebaseTodoLine validCommentLine = new RebaseTodoLine(
2429 "# This is a comment");
2430 assertEquals(Action.COMMENT, validCommentLine.getAction());
2431 assertEquals("# This is a comment", validCommentLine.getComment());
2432
2433 RebaseTodoLine actionLineToBeChanged = new RebaseTodoLine(Action.EDIT,
2434 AbbreviatedObjectId.fromString("1111111"), "short Message");
2435 assertEquals(null, actionLineToBeChanged.getComment());
2436
2437 try {
2438 actionLineToBeChanged.setComment("invalid comment");
2439 fail("Setting a invalid comment string should fail but doesn't");
2440 } catch (IllegalArgumentException e) {
2441 assertEquals(null, actionLineToBeChanged.getComment());
2442 }
2443
2444 actionLineToBeChanged.setComment("# valid comment");
2445 assertEquals("# valid comment", actionLineToBeChanged.getComment());
2446 try {
2447 actionLineToBeChanged.setComment("invalid comment");
2448 fail("Setting a invalid comment string should fail but doesn't");
2449 } catch (IllegalArgumentException e) {
2450
2451
2452
2453 assertEquals("# valid comment", actionLineToBeChanged.getComment());
2454 }
2455 try {
2456 actionLineToBeChanged.setComment("# line1 \n line2");
2457 actionLineToBeChanged.setComment("line1 \n line2");
2458 actionLineToBeChanged.setComment("\n");
2459 actionLineToBeChanged.setComment("# line1 \r line2");
2460 actionLineToBeChanged.setComment("line1 \r line2");
2461 actionLineToBeChanged.setComment("\r");
2462 actionLineToBeChanged.setComment("# line1 \n\r line2");
2463 actionLineToBeChanged.setComment("line1 \n\r line2");
2464 actionLineToBeChanged.setComment("\n\r");
2465 fail("Setting a multiline comment string should fail but doesn't");
2466 } catch (IllegalArgumentException e) {
2467
2468 }
2469
2470 actionLineToBeChanged.setComment("# valid comment");
2471 assertEquals("# valid comment", actionLineToBeChanged.getComment());
2472
2473 actionLineToBeChanged.setComment("# \t \t valid comment");
2474 assertEquals("# \t \t valid comment",
2475 actionLineToBeChanged.getComment());
2476
2477 actionLineToBeChanged.setComment("# ");
2478 assertEquals("# ", actionLineToBeChanged.getComment());
2479
2480 actionLineToBeChanged.setComment("");
2481 assertEquals("", actionLineToBeChanged.getComment());
2482
2483 actionLineToBeChanged.setComment(" ");
2484 assertEquals(" ", actionLineToBeChanged.getComment());
2485
2486 actionLineToBeChanged.setComment("\t\t");
2487 assertEquals("\t\t", actionLineToBeChanged.getComment());
2488
2489 actionLineToBeChanged.setComment(null);
2490 assertEquals(null, actionLineToBeChanged.getComment());
2491 }
2492
2493 @Test
2494 public void testRebaseInteractiveReword() throws Exception {
2495
2496 writeTrashFile(FILE1, FILE1);
2497 git.add().addFilepattern(FILE1).call();
2498 git.commit().setMessage("Add file1").call();
2499 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2500
2501
2502 writeTrashFile("file2", "file2");
2503 git.add().addFilepattern("file2").call();
2504 git.commit().setMessage("Add file2").call();
2505 assertTrue(new File(db.getWorkTree(), "file2").exists());
2506
2507
2508 writeTrashFile(FILE1, "blah");
2509 git.add().addFilepattern(FILE1).call();
2510 git.commit().setMessage("updated file1 on master").call();
2511
2512 writeTrashFile("file2", "more change");
2513 git.add().addFilepattern("file2").call();
2514 git.commit().setMessage("update file2 on side").call();
2515
2516 RebaseResult res = git.rebase().setUpstream("HEAD~2")
2517 .runInteractively(new InteractiveHandler() {
2518
2519 @Override
2520 public void prepareSteps(List<RebaseTodoLine> steps) {
2521 try {
2522 steps.get(0).setAction(Action.REWORD);
2523 } catch (IllegalTodoFileModification e) {
2524 fail("unexpected exception: " + e);
2525 }
2526 }
2527
2528 @Override
2529 public String modifyCommitMessage(String commit) {
2530 return "rewritten commit message";
2531 }
2532 }).call();
2533 assertTrue(new File(db.getWorkTree(), "file2").exists());
2534 checkFile(new File(db.getWorkTree(), "file2"), "more change");
2535 assertEquals(Status.OK, res.getStatus());
2536 Iterator<RevCommit> logIterator = git.log().all().call().iterator();
2537 logIterator.next();
2538 String actualCommitMag = logIterator.next().getShortMessage();
2539 assertEquals("rewritten commit message", actualCommitMag);
2540 }
2541
2542 @Test
2543 public void testRebaseInteractiveEdit() throws Exception {
2544
2545 writeTrashFile(FILE1, FILE1);
2546 git.add().addFilepattern(FILE1).call();
2547 git.commit().setMessage("Add file1").call();
2548 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2549
2550
2551 writeTrashFile("file2", "file2");
2552 git.add().addFilepattern("file2").call();
2553 git.commit().setMessage("Add file2").call();
2554 assertTrue(new File(db.getWorkTree(), "file2").exists());
2555
2556
2557 writeTrashFile(FILE1, "blah");
2558 git.add().addFilepattern(FILE1).call();
2559 git.commit().setMessage("updated file1 on master").call();
2560
2561 writeTrashFile("file2", "more change");
2562 git.add().addFilepattern("file2").call();
2563 git.commit().setMessage("update file2 on side").call();
2564
2565 RebaseResult res = git.rebase().setUpstream("HEAD~2")
2566 .runInteractively(new InteractiveHandler() {
2567 @Override
2568 public void prepareSteps(List<RebaseTodoLine> steps) {
2569 try {
2570 steps.get(0).setAction(Action.EDIT);
2571 } catch (IllegalTodoFileModification e) {
2572 fail("unexpected exception: " + e);
2573 }
2574 }
2575
2576 @Override
2577 public String modifyCommitMessage(String commit) {
2578 return "";
2579 }
2580 }).call();
2581 assertEquals(Status.EDIT, res.getStatus());
2582 RevCommit toBeEditted = git.log().call().iterator().next();
2583 assertEquals("updated file1 on master", toBeEditted.getFullMessage());
2584
2585
2586 writeTrashFile("file1", "edited");
2587 git.commit().setAll(true).setAmend(true)
2588 .setMessage("edited commit message").call();
2589
2590 res = git.rebase().setOperation(Operation.CONTINUE).call();
2591
2592 checkFile(new File(db.getWorkTree(), "file1"), "edited");
2593 assertEquals(Status.OK, res.getStatus());
2594 Iterator<RevCommit> logIterator = git.log().all().call().iterator();
2595 logIterator.next();
2596 String actualCommitMag = logIterator.next().getShortMessage();
2597 assertEquals("edited commit message", actualCommitMag);
2598 }
2599
2600 @Test
2601 public void testParseSquashFixupSequenceCount() {
2602 int count = RebaseCommand
2603 .parseSquashFixupSequenceCount("# This is a combination of 3 commits.\n# newline");
2604 assertEquals(3, count);
2605 }
2606
2607 @Test
2608 public void testRebaseInteractiveSingleSquashAndModifyMessage() throws Exception {
2609
2610 writeTrashFile(FILE1, FILE1);
2611 git.add().addFilepattern(FILE1).call();
2612 git.commit().setMessage("Add file1\nnew line").call();
2613 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2614
2615
2616 writeTrashFile("file2", "file2");
2617 git.add().addFilepattern("file2").call();
2618 git.commit().setMessage("Add file2\nnew line").call();
2619 assertTrue(new File(db.getWorkTree(), "file2").exists());
2620
2621
2622 writeTrashFile(FILE1, "blah");
2623 git.add().addFilepattern(FILE1).call();
2624 git.commit().setMessage("updated file1 on master\nnew line").call();
2625
2626 writeTrashFile("file2", "more change");
2627 git.add().addFilepattern("file2").call();
2628 git.commit().setMessage("update file2 on master\nnew line").call();
2629
2630 git.rebase().setUpstream("HEAD~3")
2631 .runInteractively(new InteractiveHandler() {
2632
2633 @Override
2634 public void prepareSteps(List<RebaseTodoLine> steps) {
2635 try {
2636 steps.get(1).setAction(Action.SQUASH);
2637 } catch (IllegalTodoFileModification e) {
2638 fail("unexpected exception: " + e);
2639 }
2640 }
2641
2642 @Override
2643 public String modifyCommitMessage(String commit) {
2644 final File messageSquashFile = new File(db
2645 .getDirectory(), "rebase-merge/message-squash");
2646 final File messageFixupFile = new File(db
2647 .getDirectory(), "rebase-merge/message-fixup");
2648
2649 assertFalse(messageFixupFile.exists());
2650 assertTrue(messageSquashFile.exists());
2651 assertEquals(
2652 "# This is a combination of 2 commits.\n# The first commit's message is:\nAdd file2\nnew line\n# This is the 2nd commit message:\nupdated file1 on master\nnew line",
2653 commit);
2654
2655 try {
2656 byte[] messageSquashBytes = IO
2657 .readFully(messageSquashFile);
2658 int end = RawParseUtils.prevLF(messageSquashBytes,
2659 messageSquashBytes.length);
2660 String messageSquashContent = RawParseUtils.decode(
2661 messageSquashBytes, 0, end + 1);
2662 assertEquals(messageSquashContent, commit);
2663 } catch (Throwable t) {
2664 fail(t.getMessage());
2665 }
2666
2667 return "changed";
2668 }
2669 }).call();
2670
2671 try (RevWalk walk = new RevWalk(db)) {
2672 ObjectId headId = db.resolve(Constants.HEAD);
2673 RevCommit headCommit = walk.parseCommit(headId);
2674 assertEquals(headCommit.getFullMessage(),
2675 "update file2 on master\nnew line");
2676
2677 ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
2678 RevCommit head1Commit = walk.parseCommit(head2Id);
2679 assertEquals("changed", head1Commit.getFullMessage());
2680 }
2681 }
2682
2683 @Test
2684 public void testRebaseInteractiveMultipleSquash() throws Exception {
2685
2686 writeTrashFile("file0", "file0");
2687 git.add().addFilepattern("file0").call();
2688 git.commit().setMessage("Add file0\nnew line").call();
2689 assertTrue(new File(db.getWorkTree(), "file0").exists());
2690
2691
2692 writeTrashFile(FILE1, FILE1);
2693 git.add().addFilepattern(FILE1).call();
2694 git.commit().setMessage("Add file1\nnew line").call();
2695 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2696
2697
2698 writeTrashFile("file2", "file2");
2699 git.add().addFilepattern("file2").call();
2700 git.commit().setMessage("Add file2\nnew line").call();
2701 assertTrue(new File(db.getWorkTree(), "file2").exists());
2702
2703
2704 writeTrashFile(FILE1, "blah");
2705 git.add().addFilepattern(FILE1).call();
2706 git.commit().setMessage("updated file1 on master\nnew line").call();
2707
2708 writeTrashFile("file2", "more change");
2709 git.add().addFilepattern("file2").call();
2710 git.commit().setMessage("update file2 on master\nnew line").call();
2711
2712 git.rebase().setUpstream("HEAD~4")
2713 .runInteractively(new InteractiveHandler() {
2714
2715 @Override
2716 public void prepareSteps(List<RebaseTodoLine> steps) {
2717 try {
2718 steps.get(1).setAction(Action.SQUASH);
2719 steps.get(2).setAction(Action.SQUASH);
2720 } catch (IllegalTodoFileModification e) {
2721 fail("unexpected exception: " + e);
2722 }
2723 }
2724
2725 @Override
2726 public String modifyCommitMessage(String commit) {
2727 final File messageSquashFile = new File(db.getDirectory(),
2728 "rebase-merge/message-squash");
2729 final File messageFixupFile = new File(db.getDirectory(),
2730 "rebase-merge/message-fixup");
2731 assertFalse(messageFixupFile.exists());
2732 assertTrue(messageSquashFile.exists());
2733 assertEquals(
2734 "# This is a combination of 3 commits.\n# The first commit's message is:\nAdd file1\nnew line\n# This is the 2nd commit message:\nAdd file2\nnew line\n# This is the 3rd commit message:\nupdated file1 on master\nnew line",
2735 commit);
2736
2737 try {
2738 byte[] messageSquashBytes = IO
2739 .readFully(messageSquashFile);
2740 int end = RawParseUtils.prevLF(messageSquashBytes,
2741 messageSquashBytes.length);
2742 String messageSquashContend = RawParseUtils.decode(
2743 messageSquashBytes, 0, end + 1);
2744 assertEquals(messageSquashContend, commit);
2745 } catch (Throwable t) {
2746 fail(t.getMessage());
2747 }
2748
2749 return "# This is a combination of 3 commits.\n# The first commit's message is:\nAdd file1\nnew line\n# This is the 2nd commit message:\nAdd file2\nnew line\n# This is the 3rd commit message:\nupdated file1 on master\nnew line";
2750 }
2751 }).call();
2752
2753 try (RevWalk walk = new RevWalk(db)) {
2754 ObjectId headId = db.resolve(Constants.HEAD);
2755 RevCommit headCommit = walk.parseCommit(headId);
2756 assertEquals(headCommit.getFullMessage(),
2757 "update file2 on master\nnew line");
2758
2759 ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
2760 RevCommit head1Commit = walk.parseCommit(head2Id);
2761 assertEquals(
2762 "Add file1\nnew line\nAdd file2\nnew line\nupdated file1 on master\nnew line",
2763 head1Commit.getFullMessage());
2764 }
2765 }
2766
2767 @Test
2768 public void testRebaseInteractiveMixedSquashAndFixup() throws Exception {
2769
2770 writeTrashFile("file0", "file0");
2771 git.add().addFilepattern("file0").call();
2772 git.commit().setMessage("Add file0\nnew line").call();
2773 assertTrue(new File(db.getWorkTree(), "file0").exists());
2774
2775
2776 writeTrashFile(FILE1, FILE1);
2777 git.add().addFilepattern(FILE1).call();
2778 git.commit().setMessage("Add file1\nnew line").call();
2779 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2780
2781
2782 writeTrashFile("file2", "file2");
2783 git.add().addFilepattern("file2").call();
2784 git.commit().setMessage("Add file2\nnew line").call();
2785 assertTrue(new File(db.getWorkTree(), "file2").exists());
2786
2787
2788 writeTrashFile(FILE1, "blah");
2789 git.add().addFilepattern(FILE1).call();
2790 git.commit().setMessage("updated file1 on master\nnew line").call();
2791
2792 writeTrashFile("file2", "more change");
2793 git.add().addFilepattern("file2").call();
2794 git.commit().setMessage("update file2 on master\nnew line").call();
2795
2796 git.rebase().setUpstream("HEAD~4")
2797 .runInteractively(new InteractiveHandler() {
2798
2799 @Override
2800 public void prepareSteps(List<RebaseTodoLine> steps) {
2801 try {
2802 steps.get(1).setAction(Action.FIXUP);
2803 steps.get(2).setAction(Action.SQUASH);
2804 } catch (IllegalTodoFileModification e) {
2805 fail("unexpected exception: " + e);
2806 }
2807 }
2808
2809 @Override
2810 public String modifyCommitMessage(String commit) {
2811 final File messageSquashFile = new File(db
2812 .getDirectory(), "rebase-merge/message-squash");
2813 final File messageFixupFile = new File(db
2814 .getDirectory(), "rebase-merge/message-fixup");
2815
2816 assertFalse(messageFixupFile.exists());
2817 assertTrue(messageSquashFile.exists());
2818 assertEquals(
2819 "# This is a combination of 3 commits.\n# The first commit's message is:\nAdd file1\nnew line\n# The 2nd commit message will be skipped:\n# Add file2\n# new line\n# This is the 3rd commit message:\nupdated file1 on master\nnew line",
2820 commit);
2821
2822 try {
2823 byte[] messageSquashBytes = IO
2824 .readFully(messageSquashFile);
2825 int end = RawParseUtils.prevLF(messageSquashBytes,
2826 messageSquashBytes.length);
2827 String messageSquashContend = RawParseUtils.decode(
2828 messageSquashBytes, 0, end + 1);
2829 assertEquals(messageSquashContend, commit);
2830 } catch (Throwable t) {
2831 fail(t.getMessage());
2832 }
2833
2834 return "changed";
2835 }
2836 }).call();
2837
2838 try (RevWalk walk = new RevWalk(db)) {
2839 ObjectId headId = db.resolve(Constants.HEAD);
2840 RevCommit headCommit = walk.parseCommit(headId);
2841 assertEquals(headCommit.getFullMessage(),
2842 "update file2 on master\nnew line");
2843
2844 ObjectId head2Id = db.resolve(Constants.HEAD + "^1");
2845 RevCommit head1Commit = walk.parseCommit(head2Id);
2846 assertEquals("changed", head1Commit.getFullMessage());
2847 }
2848 }
2849
2850 @Test
2851 public void testRebaseInteractiveSingleFixup() throws Exception {
2852
2853 writeTrashFile(FILE1, FILE1);
2854 git.add().addFilepattern(FILE1).call();
2855 git.commit().setMessage("Add file1\nnew line").call();
2856 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2857
2858
2859 writeTrashFile("file2", "file2");
2860 git.add().addFilepattern("file2").call();
2861 git.commit().setMessage("Add file2\nnew line").call();
2862 assertTrue(new File(db.getWorkTree(), "file2").exists());
2863
2864
2865 writeTrashFile(FILE1, "blah");
2866 git.add().addFilepattern(FILE1).call();
2867 git.commit().setMessage("updated file1 on master\nnew line").call();
2868
2869 writeTrashFile("file2", "more change");
2870 git.add().addFilepattern("file2").call();
2871 git.commit().setMessage("update file2 on master\nnew line").call();
2872
2873 git.rebase().setUpstream("HEAD~3")
2874 .runInteractively(new InteractiveHandler() {
2875
2876 @Override
2877 public void prepareSteps(List<RebaseTodoLine> steps) {
2878 try {
2879 steps.get(1).setAction(Action.FIXUP);
2880 } catch (IllegalTodoFileModification e) {
2881 fail("unexpected exception: " + e);
2882 }
2883 }
2884
2885 @Override
2886 public String modifyCommitMessage(String commit) {
2887 fail("No callback to modify commit message expected for single fixup");
2888 return commit;
2889 }
2890 }).call();
2891
2892 try (RevWalk walk = new RevWalk(db)) {
2893 ObjectId headId = db.resolve(Constants.HEAD);
2894 RevCommit headCommit = walk.parseCommit(headId);
2895 assertEquals("update file2 on master\nnew line",
2896 headCommit.getFullMessage());
2897
2898 ObjectId head1Id = db.resolve(Constants.HEAD + "^1");
2899 RevCommit head1Commit = walk.parseCommit(head1Id);
2900 assertEquals("Add file2\nnew line",
2901 head1Commit.getFullMessage());
2902 }
2903 }
2904
2905 @Test
2906 public void testRebaseInteractiveFixupWithBlankLines() throws Exception {
2907
2908 writeTrashFile(FILE1, FILE1);
2909 git.add().addFilepattern(FILE1).call();
2910 git.commit().setMessage("Add file1\nnew line").call();
2911 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2912
2913
2914 writeTrashFile("file2", "file2");
2915 git.add().addFilepattern("file2").call();
2916 git.commit().setMessage("Add file2").call();
2917 assertTrue(new File(db.getWorkTree(), "file2").exists());
2918
2919
2920 writeTrashFile(FILE1, "blah");
2921 git.add().addFilepattern(FILE1).call();
2922 git.commit().setMessage("updated file1 on master\n\nsome text").call();
2923
2924 git.rebase().setUpstream("HEAD~2")
2925 .runInteractively(new InteractiveHandler() {
2926
2927 @Override
2928 public void prepareSteps(List<RebaseTodoLine> steps) {
2929 try {
2930 steps.get(1).setAction(Action.FIXUP);
2931 } catch (IllegalTodoFileModification e) {
2932 fail("unexpected exception: " + e);
2933 }
2934 }
2935
2936 @Override
2937 public String modifyCommitMessage(String commit) {
2938 fail("No callback to modify commit message expected for single fixup");
2939 return commit;
2940 }
2941 }).call();
2942
2943 try (RevWalk walk = new RevWalk(db)) {
2944 ObjectId headId = db.resolve(Constants.HEAD);
2945 RevCommit headCommit = walk.parseCommit(headId);
2946 assertEquals("Add file2",
2947 headCommit.getFullMessage());
2948 }
2949 }
2950
2951 @Test(expected = InvalidRebaseStepException.class)
2952 public void testRebaseInteractiveFixupFirstCommitShouldFail()
2953 throws Exception {
2954
2955 writeTrashFile(FILE1, FILE1);
2956 git.add().addFilepattern(FILE1).call();
2957 git.commit().setMessage("Add file1\nnew line").call();
2958 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2959
2960
2961 writeTrashFile("file2", "file2");
2962 git.add().addFilepattern("file2").call();
2963 git.commit().setMessage("Add file2\nnew line").call();
2964 assertTrue(new File(db.getWorkTree(), "file2").exists());
2965
2966 git.rebase().setUpstream("HEAD~1")
2967 .runInteractively(new InteractiveHandler() {
2968
2969 @Override
2970 public void prepareSteps(List<RebaseTodoLine> steps) {
2971 try {
2972 steps.get(0).setAction(Action.FIXUP);
2973 } catch (IllegalTodoFileModification e) {
2974 fail("unexpected exception: " + e);
2975 }
2976 }
2977
2978 @Override
2979 public String modifyCommitMessage(String commit) {
2980 return commit;
2981 }
2982 }).call();
2983 }
2984
2985 @Test(expected = InvalidRebaseStepException.class)
2986 public void testRebaseInteractiveSquashFirstCommitShouldFail()
2987 throws Exception {
2988
2989 writeTrashFile(FILE1, FILE1);
2990 git.add().addFilepattern(FILE1).call();
2991 git.commit().setMessage("Add file1\nnew line").call();
2992 assertTrue(new File(db.getWorkTree(), FILE1).exists());
2993
2994
2995 writeTrashFile("file2", "file2");
2996 git.add().addFilepattern("file2").call();
2997 git.commit().setMessage("Add file2\nnew line").call();
2998 assertTrue(new File(db.getWorkTree(), "file2").exists());
2999
3000 git.rebase().setUpstream("HEAD~1")
3001 .runInteractively(new InteractiveHandler() {
3002
3003 @Override
3004 public void prepareSteps(List<RebaseTodoLine> steps) {
3005 try {
3006 steps.get(0).setAction(Action.SQUASH);
3007 } catch (IllegalTodoFileModification e) {
3008 fail("unexpected exception: " + e);
3009 }
3010 }
3011
3012 @Override
3013 public String modifyCommitMessage(String commit) {
3014 return commit;
3015 }
3016 }).call();
3017 }
3018
3019 @Test
3020 public void testRebaseEndsIfLastStepIsEdit() throws Exception {
3021
3022 writeTrashFile(FILE1, FILE1);
3023 git.add().addFilepattern(FILE1).call();
3024 git.commit().setMessage("Add file1\nnew line").call();
3025 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3026
3027
3028 writeTrashFile("file2", "file2");
3029 git.add().addFilepattern("file2").call();
3030 git.commit().setMessage("Add file2\nnew line").call();
3031 assertTrue(new File(db.getWorkTree(), "file2").exists());
3032
3033 git.rebase().setUpstream("HEAD~1")
3034 .runInteractively(new InteractiveHandler() {
3035
3036 @Override
3037 public void prepareSteps(List<RebaseTodoLine> steps) {
3038 try {
3039 steps.get(0).setAction(Action.EDIT);
3040 } catch (IllegalTodoFileModification e) {
3041 fail("unexpected exception: " + e);
3042 }
3043 }
3044
3045 @Override
3046 public String modifyCommitMessage(String commit) {
3047 return commit;
3048 }
3049 }).call();
3050 git.commit().setAmend(true)
3051 .setMessage("Add file2\nnew line\nanother line").call();
3052 RebaseResult result = git.rebase().setOperation(Operation.CONTINUE)
3053 .call();
3054 assertEquals(Status.OK, result.getStatus());
3055
3056 }
3057
3058 @Test
3059 public void testRebaseShouldStopForEditInCaseOfConflict()
3060 throws Exception {
3061
3062 writeTrashFile(FILE1, FILE1);
3063 git.add().addFilepattern(FILE1).call();
3064 git.commit().setMessage("Add file1\nnew line").call();
3065 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3066
3067
3068 writeTrashFile(FILE1, FILE1 + "a");
3069 git.add().addFilepattern(FILE1).call();
3070 git.commit().setMessage("Change file1").call();
3071
3072
3073 writeTrashFile(FILE1, FILE1 + "b");
3074 git.add().addFilepattern(FILE1).call();
3075 git.commit().setMessage("Change file1").call();
3076
3077 RebaseResult result = git.rebase().setUpstream("HEAD~2")
3078 .runInteractively(new InteractiveHandler() {
3079
3080 @Override
3081 public void prepareSteps(List<RebaseTodoLine> steps) {
3082 steps.remove(0);
3083 try {
3084 steps.get(0).setAction(Action.EDIT);
3085 } catch (IllegalTodoFileModification e) {
3086 fail("unexpected exception: " + e);
3087 }
3088 }
3089
3090 @Override
3091 public String modifyCommitMessage(String commit) {
3092 return commit;
3093 }
3094 }).call();
3095 assertEquals(Status.STOPPED, result.getStatus());
3096 git.add().addFilepattern(FILE1).call();
3097 result = git.rebase().setOperation(Operation.CONTINUE).call();
3098 assertEquals(Status.EDIT, result.getStatus());
3099
3100 }
3101
3102 @Test
3103 public void testRebaseShouldStopForRewordInCaseOfConflict()
3104 throws Exception {
3105
3106 writeTrashFile(FILE1, FILE1);
3107 git.add().addFilepattern(FILE1).call();
3108 git.commit().setMessage("Add file1\nnew line").call();
3109 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3110
3111
3112 writeTrashFile(FILE1, FILE1 + "a");
3113 git.add().addFilepattern(FILE1).call();
3114 git.commit().setMessage("Change file1").call();
3115
3116
3117 writeTrashFile(FILE1, FILE1 + "b");
3118 git.add().addFilepattern(FILE1).call();
3119 git.commit().setMessage("Change file1").call();
3120
3121 RebaseResult result = git.rebase().setUpstream("HEAD~2")
3122 .runInteractively(new InteractiveHandler() {
3123
3124 @Override
3125 public void prepareSteps(List<RebaseTodoLine> steps) {
3126 steps.remove(0);
3127 try {
3128 steps.get(0).setAction(Action.REWORD);
3129 } catch (IllegalTodoFileModification e) {
3130 fail("unexpected exception: " + e);
3131 }
3132 }
3133
3134 @Override
3135 public String modifyCommitMessage(String commit) {
3136 return "rewritten commit message";
3137 }
3138 }).call();
3139 assertEquals(Status.STOPPED, result.getStatus());
3140 git.add().addFilepattern(FILE1).call();
3141 result = git.rebase().runInteractively(new InteractiveHandler() {
3142
3143 @Override
3144 public void prepareSteps(List<RebaseTodoLine> steps) {
3145 steps.remove(0);
3146 try {
3147 steps.get(0).setAction(Action.REWORD);
3148 } catch (IllegalTodoFileModification e) {
3149 fail("unexpected exception: " + e);
3150 }
3151 }
3152
3153 @Override
3154 public String modifyCommitMessage(String commit) {
3155 return "rewritten commit message";
3156 }
3157 }).setOperation(Operation.CONTINUE).call();
3158 assertEquals(Status.OK, result.getStatus());
3159 Iterator<RevCommit> logIterator = git.log().all().call().iterator();
3160 String actualCommitMag = logIterator.next().getShortMessage();
3161 assertEquals("rewritten commit message", actualCommitMag);
3162
3163 }
3164
3165 @Test
3166 public void testRebaseShouldSquashInCaseOfConflict() throws Exception {
3167
3168 writeTrashFile(FILE1, FILE1);
3169 git.add().addFilepattern(FILE1).call();
3170 git.commit().setMessage("Add file1\nnew line").call();
3171 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3172
3173
3174 writeTrashFile("file2", "file2");
3175 git.add().addFilepattern("file2").call();
3176 git.commit().setMessage("Change file2").call();
3177
3178
3179 writeTrashFile(FILE1, FILE1 + "a");
3180 git.add().addFilepattern(FILE1).call();
3181 git.commit().setMessage("Change file1").call();
3182
3183
3184 writeTrashFile(FILE1, FILE1 + "b");
3185 git.add().addFilepattern(FILE1).call();
3186 git.commit().setMessage("Change file1").call();
3187
3188 RebaseResult result = git.rebase().setUpstream("HEAD~3")
3189 .runInteractively(new InteractiveHandler() {
3190
3191 @Override
3192 public void prepareSteps(List<RebaseTodoLine> steps) {
3193 try {
3194 steps.get(0).setAction(Action.PICK);
3195 steps.remove(1);
3196 steps.get(1).setAction(Action.SQUASH);
3197 } catch (IllegalTodoFileModification e) {
3198 fail("unexpected exception: " + e);
3199 }
3200 }
3201
3202 @Override
3203 public String modifyCommitMessage(String commit) {
3204 return "squashed message";
3205 }
3206 }).call();
3207 assertEquals(Status.STOPPED, result.getStatus());
3208 git.add().addFilepattern(FILE1).call();
3209 result = git.rebase().runInteractively(new InteractiveHandler() {
3210
3211 @Override
3212 public void prepareSteps(List<RebaseTodoLine> steps) {
3213 try {
3214 steps.get(0).setAction(Action.PICK);
3215 steps.remove(1);
3216 steps.get(1).setAction(Action.SQUASH);
3217 } catch (IllegalTodoFileModification e) {
3218 fail("unexpected exception: " + e);
3219 }
3220 }
3221
3222 @Override
3223 public String modifyCommitMessage(String commit) {
3224 return "squashed message";
3225 }
3226 }).setOperation(Operation.CONTINUE).call();
3227 assertEquals(Status.OK, result.getStatus());
3228 Iterator<RevCommit> logIterator = git.log().all().call().iterator();
3229 String actualCommitMag = logIterator.next().getShortMessage();
3230 assertEquals("squashed message", actualCommitMag);
3231 }
3232
3233 @Test
3234 public void testRebaseShouldFixupInCaseOfConflict() throws Exception {
3235
3236 writeTrashFile(FILE1, FILE1);
3237 git.add().addFilepattern(FILE1).call();
3238 git.commit().setMessage("Add file1").call();
3239 assertTrue(new File(db.getWorkTree(), FILE1).exists());
3240
3241
3242 writeTrashFile("file2", "file2");
3243 git.add().addFilepattern("file2").call();
3244 git.commit().setMessage("Change file2").call();
3245
3246
3247 writeTrashFile(FILE1, FILE1 + "a");
3248 git.add().addFilepattern(FILE1).call();
3249 git.commit().setMessage("Change file1").call();
3250
3251
3252 writeTrashFile(FILE1, FILE1 + "b");
3253 writeTrashFile("file3", "file3");
3254 git.add().addFilepattern(FILE1).call();
3255 git.add().addFilepattern("file3").call();
3256 git.commit().setMessage("Change file1, add file3").call();
3257
3258 RebaseResult result = git.rebase().setUpstream("HEAD~3")
3259 .runInteractively(new InteractiveHandler() {
3260
3261 @Override
3262 public void prepareSteps(List<RebaseTodoLine> steps) {
3263 try {
3264 steps.get(0).setAction(Action.PICK);
3265 steps.remove(1);
3266 steps.get(1).setAction(Action.FIXUP);
3267 } catch (IllegalTodoFileModification e) {
3268 fail("unexpected exception: " + e);
3269 }
3270 }
3271
3272 @Override
3273 public String modifyCommitMessage(String commit) {
3274 return commit;
3275 }
3276 }).call();
3277 assertEquals(Status.STOPPED, result.getStatus());
3278 git.add().addFilepattern(FILE1).call();
3279 result = git.rebase().runInteractively(new InteractiveHandler() {
3280
3281 @Override
3282 public void prepareSteps(List<RebaseTodoLine> steps) {
3283 try {
3284 steps.get(0).setAction(Action.PICK);
3285 steps.remove(1);
3286 steps.get(1).setAction(Action.FIXUP);
3287 } catch (IllegalTodoFileModification e) {
3288 fail("unexpected exception: " + e);
3289 }
3290 }
3291
3292 @Override
3293 public String modifyCommitMessage(String commit) {
3294 return "commit";
3295 }
3296 }).setOperation(Operation.CONTINUE).call();
3297 assertEquals(Status.OK, result.getStatus());
3298 Iterator<RevCommit> logIterator = git.log().all().call().iterator();
3299 String actualCommitMsg = logIterator.next().getShortMessage();
3300 assertEquals("Change file2", actualCommitMsg);
3301 actualCommitMsg = logIterator.next().getShortMessage();
3302 assertEquals("Add file1", actualCommitMsg);
3303 assertTrue(new File(db.getWorkTree(), "file3").exists());
3304
3305 }
3306
3307 @Test
3308 public void testInteractiveRebaseWithModificationShouldNotDeleteDataOnAbort()
3309 throws Exception {
3310
3311 writeTrashFile("file0", "file0");
3312 writeTrashFile(FILE1, "file1");
3313 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
3314 git.commit().setMessage("commit1").call();
3315
3316
3317 writeTrashFile(FILE1, "modified file1");
3318 git.add().addFilepattern(FILE1).call();
3319 git.commit().setMessage("commit2").call();
3320
3321
3322 writeTrashFile(FILE1, "modified file1 a second time");
3323 git.add().addFilepattern(FILE1).call();
3324 git.commit().setMessage("commit3").call();
3325
3326
3327 writeTrashFile("file0", "modified file0 in index");
3328 git.add().addFilepattern("file0").addFilepattern(FILE1).call();
3329
3330 writeTrashFile("file0", "modified file0");
3331
3332
3333 RebaseResult result = git.rebase().setUpstream("HEAD~2")
3334 .runInteractively(new InteractiveHandler() {
3335
3336 @Override
3337 public void prepareSteps(List<RebaseTodoLine> steps) {
3338 try {
3339 steps.get(0).setAction(Action.EDIT);
3340 steps.get(1).setAction(Action.PICK);
3341 } catch (IllegalTodoFileModification e) {
3342 fail("unexpected exception: " + e);
3343 }
3344 }
3345
3346 @Override
3347 public String modifyCommitMessage(String commit) {
3348 return commit;
3349 }
3350 }).call();
3351
3352
3353
3354 if (result.getStatus() == Status.EDIT)
3355 git.rebase().setOperation(Operation.ABORT).call();
3356
3357 checkFile(new File(db.getWorkTree(), "file0"), "modified file0");
3358 checkFile(new File(db.getWorkTree(), "file1"),
3359 "modified file1 a second time");
3360 assertEquals("[file0, mode:100644, content:modified file0 in index]"
3361 + "[file1, mode:100644, content:modified file1 a second time]",
3362 indexState(CONTENT));
3363
3364 }
3365
3366 private File getTodoFile() {
3367 File todoFile = new File(db.getDirectory(), GIT_REBASE_TODO);
3368 return todoFile;
3369 }
3370 }