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