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