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