View Javadoc
1   /*
2    * Copyright (C) 2010, Mathias Kinzler <mathias.kinzler@sap.com> and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.api;
11  
12  import static java.nio.charset.StandardCharsets.UTF_8;
13  import static org.junit.Assert.assertEquals;
14  import static org.junit.Assert.assertFalse;
15  import static org.junit.Assert.assertNotNull;
16  import static org.junit.Assert.assertNull;
17  import static org.junit.Assert.assertTrue;
18  
19  import java.io.ByteArrayOutputStream;
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.io.FileOutputStream;
23  import java.io.IOException;
24  import java.util.concurrent.Callable;
25  
26  import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
27  import org.eclipse.jgit.api.MergeResult.MergeStatus;
28  import org.eclipse.jgit.api.errors.NoHeadException;
29  import org.eclipse.jgit.junit.JGitTestUtil;
30  import org.eclipse.jgit.junit.RepositoryTestCase;
31  import org.eclipse.jgit.lib.Constants;
32  import org.eclipse.jgit.lib.ObjectId;
33  import org.eclipse.jgit.lib.RefUpdate;
34  import org.eclipse.jgit.lib.Repository;
35  import org.eclipse.jgit.lib.RepositoryState;
36  import org.eclipse.jgit.lib.StoredConfig;
37  import org.eclipse.jgit.merge.ContentMergeStrategy;
38  import org.eclipse.jgit.merge.MergeStrategy;
39  import org.eclipse.jgit.revwalk.RevCommit;
40  import org.eclipse.jgit.revwalk.RevSort;
41  import org.eclipse.jgit.revwalk.RevWalk;
42  import org.eclipse.jgit.transport.RefSpec;
43  import org.eclipse.jgit.transport.RemoteConfig;
44  import org.eclipse.jgit.transport.URIish;
45  import org.junit.Before;
46  import org.junit.Test;
47  
48  public class PullCommandTest extends RepositoryTestCase {
49  	/** Second Test repository */
50  	protected Repository dbTarget;
51  
52  	private Git source;
53  
54  	private Git target;
55  
56  	private File sourceFile;
57  
58  	private File targetFile;
59  
60  	@Test
61  	public void testPullFastForward() throws Exception {
62  		PullResult res = target.pull().call();
63  		// nothing to update since we don't have different data yet
64  		assertTrue(res.getFetchResult().getTrackingRefUpdates().isEmpty());
65  		assertTrue(res.getMergeResult().getMergeStatus().equals(
66  				MergeStatus.ALREADY_UP_TO_DATE));
67  
68  		assertFileContentsEqual(targetFile, "Hello world");
69  
70  		// change the source file
71  		writeToFile(sourceFile, "Another change");
72  		source.add().addFilepattern("SomeFile.txt").call();
73  		source.commit().setMessage("Some change in remote").call();
74  
75  		res = target.pull().call();
76  
77  		assertFalse(res.getFetchResult().getTrackingRefUpdates().isEmpty());
78  		assertEquals(res.getMergeResult().getMergeStatus(),
79  				MergeStatus.FAST_FORWARD);
80  		assertFileContentsEqual(targetFile, "Another change");
81  		assertEquals(RepositoryState.SAFE, target.getRepository()
82  				.getRepositoryState());
83  
84  		res = target.pull().call();
85  		assertEquals(res.getMergeResult().getMergeStatus(),
86  				MergeStatus.ALREADY_UP_TO_DATE);
87  	}
88  
89  	@Test
90  	public void testPullMerge() throws Exception {
91  		PullResult res = target.pull().call();
92  		// nothing to update since we don't have different data yet
93  		assertTrue(res.getFetchResult().getTrackingRefUpdates().isEmpty());
94  		assertTrue(res.getMergeResult().getMergeStatus()
95  				.equals(MergeStatus.ALREADY_UP_TO_DATE));
96  
97  		writeToFile(sourceFile, "Source change");
98  		source.add().addFilepattern("SomeFile.txt");
99  		RevCommit sourceCommit = source.commit()
100 				.setMessage("Source change in remote").call();
101 
102 		File targetFile2 = new File(dbTarget.getWorkTree(), "OtherFile.txt");
103 		writeToFile(targetFile2, "Unconflicting change");
104 		target.add().addFilepattern("OtherFile.txt").call();
105 		RevCommit targetCommit = target.commit()
106 				.setMessage("Unconflicting change in local").call();
107 
108 		res = target.pull().call();
109 
110 		MergeResult mergeResult = res.getMergeResult();
111 		ObjectId[] mergedCommits = mergeResult.getMergedCommits();
112 		assertEquals(targetCommit.getId(), mergedCommits[0]);
113 		assertEquals(sourceCommit.getId(), mergedCommits[1]);
114 		try (RevWalk rw = new RevWalk(dbTarget)) {
115 			RevCommit mergeCommit = rw.parseCommit(mergeResult.getNewHead());
116 			String message = "Merge branch 'master' of "
117 					+ db.getWorkTree().getAbsolutePath();
118 			assertEquals(message, mergeCommit.getShortMessage());
119 		}
120 	}
121 
122 	@Test
123 	public void testPullConflict() throws Exception {
124 		PullResult res = target.pull().call();
125 		// nothing to update since we don't have different data yet
126 		assertTrue(res.getFetchResult().getTrackingRefUpdates().isEmpty());
127 		assertTrue(res.getMergeResult().getMergeStatus().equals(
128 				MergeStatus.ALREADY_UP_TO_DATE));
129 
130 		assertFileContentsEqual(targetFile, "Hello world");
131 
132 		// change the source file
133 		writeToFile(sourceFile, "Source change");
134 		source.add().addFilepattern("SomeFile.txt").call();
135 		source.commit().setMessage("Source change in remote").call();
136 
137 		// change the target file
138 		writeToFile(targetFile, "Target change");
139 		target.add().addFilepattern("SomeFile.txt").call();
140 		target.commit().setMessage("Target change in local").call();
141 
142 		res = target.pull().call();
143 
144 		String sourceChangeString = "Source change\n>>>>>>> branch 'master' of "
145 				+ target.getRepository().getConfig().getString("remote",
146 						"origin", "url");
147 
148 		assertFalse(res.getFetchResult().getTrackingRefUpdates().isEmpty());
149 		assertEquals(res.getMergeResult().getMergeStatus(),
150 				MergeStatus.CONFLICTING);
151 		String result = "<<<<<<< HEAD\nTarget change\n=======\n"
152 				+ sourceChangeString + "\n";
153 		assertFileContentsEqual(targetFile, result);
154 		assertEquals(RepositoryState.MERGING, target.getRepository()
155 				.getRepositoryState());
156 	}
157 
158 	@Test
159 	public void testPullConflictTheirs() throws Exception {
160 		PullResult res = target.pull().call();
161 		// nothing to update since we don't have different data yet
162 		assertTrue(res.getFetchResult().getTrackingRefUpdates().isEmpty());
163 		assertTrue(res.getMergeResult().getMergeStatus()
164 				.equals(MergeStatus.ALREADY_UP_TO_DATE));
165 
166 		assertFileContentsEqual(targetFile, "Hello world");
167 
168 		// change the source file
169 		writeToFile(sourceFile, "Source change");
170 		source.add().addFilepattern("SomeFile.txt").call();
171 		source.commit().setMessage("Source change in remote").call();
172 
173 		// change the target file
174 		writeToFile(targetFile, "Target change");
175 		target.add().addFilepattern("SomeFile.txt").call();
176 		target.commit().setMessage("Target change in local").call();
177 
178 		res = target.pull().setStrategy(MergeStrategy.THEIRS).call();
179 
180 		assertTrue(res.isSuccessful());
181 		assertFileContentsEqual(targetFile, "Source change");
182 		assertEquals(RepositoryState.SAFE,
183 				target.getRepository().getRepositoryState());
184 		assertTrue(target.status().call().isClean());
185 	}
186 
187 	@Test
188 	public void testPullConflictXtheirs() throws Exception {
189 		PullResult res = target.pull().call();
190 		// nothing to update since we don't have different data yet
191 		assertTrue(res.getFetchResult().getTrackingRefUpdates().isEmpty());
192 		assertTrue(res.getMergeResult().getMergeStatus()
193 				.equals(MergeStatus.ALREADY_UP_TO_DATE));
194 
195 		assertFileContentsEqual(targetFile, "Hello world");
196 
197 		// change the source file
198 		writeToFile(sourceFile, "a\nHello\nb\n");
199 		source.add().addFilepattern("SomeFile.txt").call();
200 		source.commit().setMessage("Multi-line change in remote").call();
201 
202 		// Pull again
203 		res = target.pull().call();
204 		assertTrue(res.isSuccessful());
205 		assertFileContentsEqual(targetFile, "a\nHello\nb\n");
206 
207 		// change the source file
208 		writeToFile(sourceFile, "a\nSource change\nb\n");
209 		source.add().addFilepattern("SomeFile.txt").call();
210 		source.commit().setMessage("Source change in remote").call();
211 
212 		// change the target file
213 		writeToFile(targetFile, "a\nTarget change\nb\nc\n");
214 		target.add().addFilepattern("SomeFile.txt").call();
215 		target.commit().setMessage("Target change in local").call();
216 
217 		res = target.pull().setContentMergeStrategy(ContentMergeStrategy.THEIRS)
218 				.call();
219 
220 		assertTrue(res.isSuccessful());
221 		assertFileContentsEqual(targetFile, "a\nSource change\nb\nc\n");
222 		assertEquals(RepositoryState.SAFE,
223 				target.getRepository().getRepositoryState());
224 		assertTrue(target.status().call().isClean());
225 	}
226 
227 	@Test
228 	public void testPullWithUntrackedStash() throws Exception {
229 		target.pull().call();
230 
231 		// change the source file
232 		writeToFile(sourceFile, "Source change");
233 		source.add().addFilepattern("SomeFile.txt").call();
234 		source.commit().setMessage("Source change in remote").call();
235 
236 		// write untracked file
237 		writeToFile(new File(dbTarget.getWorkTree(), "untracked.txt"),
238 				"untracked");
239 		RevCommit stash = target.stashCreate().setIndexMessage("message here")
240 				.setIncludeUntracked(true).call();
241 		assertNotNull(stash);
242 		assertTrue(target.status().call().isClean());
243 
244 		// pull from source
245 		assertTrue(target.pull().call().isSuccessful());
246 		assertEquals("[SomeFile.txt, mode:100644, content:Source change]",
247 				indexState(dbTarget, CONTENT));
248 		assertFalse(JGitTestUtil.check(dbTarget, "untracked.txt"));
249 		assertEquals("Source change",
250 				JGitTestUtil.read(dbTarget, "SomeFile.txt"));
251 
252 		// apply the stash
253 		target.stashApply().setStashRef(stash.getName()).call();
254 		assertEquals("[SomeFile.txt, mode:100644, content:Source change]",
255 				indexState(dbTarget, CONTENT));
256 		assertEquals("untracked", JGitTestUtil.read(dbTarget, "untracked.txt"));
257 		assertEquals("Source change",
258 				JGitTestUtil.read(dbTarget, "SomeFile.txt"));
259 	}
260 
261 	@Test
262 	public void testPullLocalConflict() throws Exception {
263 		target.branchCreate().setName("basedOnMaster").setStartPoint(
264 				"refs/heads/master").setUpstreamMode(SetupUpstreamMode.TRACK)
265 				.call();
266 		target.getRepository().updateRef(Constants.HEAD).link(
267 				"refs/heads/basedOnMaster");
268 		PullResult res = target.pull().call();
269 		// nothing to update since we don't have different data yet
270 		assertNull(res.getFetchResult());
271 		assertTrue(res.getMergeResult().getMergeStatus().equals(
272 				MergeStatus.ALREADY_UP_TO_DATE));
273 
274 		assertFileContentsEqual(targetFile, "Hello world");
275 
276 		// change the file in master
277 		target.getRepository().updateRef(Constants.HEAD).link(
278 				"refs/heads/master");
279 		writeToFile(targetFile, "Master change");
280 		target.add().addFilepattern("SomeFile.txt").call();
281 		target.commit().setMessage("Source change in master").call();
282 
283 		// change the file in slave
284 		target.getRepository().updateRef(Constants.HEAD).link(
285 				"refs/heads/basedOnMaster");
286 		writeToFile(targetFile, "Slave change");
287 		target.add().addFilepattern("SomeFile.txt").call();
288 		target.commit().setMessage("Source change in based on master").call();
289 
290 		res = target.pull().call();
291 
292 		String sourceChangeString = "Master change\n>>>>>>> branch 'master' of local repository";
293 
294 		assertNull(res.getFetchResult());
295 		assertEquals(res.getMergeResult().getMergeStatus(),
296 				MergeStatus.CONFLICTING);
297 		String result = "<<<<<<< HEAD\nSlave change\n=======\n"
298 				+ sourceChangeString + "\n";
299 		assertFileContentsEqual(targetFile, result);
300 		assertEquals(RepositoryState.MERGING, target.getRepository()
301 				.getRepositoryState());
302 	}
303 
304 	@Test(expected = NoHeadException.class)
305 	public void testPullEmptyRepository() throws Exception {
306 		Repository empty = createWorkRepository();
307 		RefUpdate delete = empty.updateRef(Constants.HEAD, true);
308 		delete.setForceUpdate(true);
309 		delete.delete();
310 		Git.wrap(empty).pull().call();
311 	}
312 
313 	@Test
314 	public void testPullMergeProgrammaticConfiguration() throws Exception {
315 		// create another commit on another branch in source
316 		source.checkout().setCreateBranch(true).setName("other").call();
317 		sourceFile = new File(db.getWorkTree(), "file2.txt");
318 		writeToFile(sourceFile, "content");
319 		source.add().addFilepattern("file2.txt").call();
320 		RevCommit sourceCommit = source.commit()
321 				.setMessage("source commit on branch other").call();
322 
323 		File targetFile2 = new File(dbTarget.getWorkTree(), "OtherFile.txt");
324 		writeToFile(targetFile2, "Unconflicting change");
325 		target.add().addFilepattern("OtherFile.txt").call();
326 		RevCommit targetCommit = target.commit()
327 				.setMessage("Unconflicting change in local").call();
328 
329 		PullResult res = target.pull().setRemote("origin")
330 				.setRemoteBranchName("other")
331 				.setRebase(false).call();
332 
333 		MergeResult mergeResult = res.getMergeResult();
334 		ObjectId[] mergedCommits = mergeResult.getMergedCommits();
335 		assertEquals(targetCommit.getId(), mergedCommits[0]);
336 		assertEquals(sourceCommit.getId(), mergedCommits[1]);
337 		try (RevWalk rw = new RevWalk(dbTarget)) {
338 			RevCommit mergeCommit = rw.parseCommit(mergeResult.getNewHead());
339 			String message = "Merge branch 'other' of "
340 					+ db.getWorkTree().getAbsolutePath();
341 			assertEquals(message, mergeCommit.getShortMessage());
342 		}
343 	}
344 
345 	@Test
346 	public void testPullMergeProgrammaticConfigurationImpliedTargetBranch()
347 			throws Exception {
348 		// create another commit on another branch in source
349 		source.checkout().setCreateBranch(true).setName("other").call();
350 		sourceFile = new File(db.getWorkTree(), "file2.txt");
351 		writeToFile(sourceFile, "content");
352 		source.add().addFilepattern("file2.txt").call();
353 		RevCommit sourceCommit = source.commit()
354 				.setMessage("source commit on branch other").call();
355 
356 		target.checkout().setCreateBranch(true).setName("other").call();
357 		File targetFile2 = new File(dbTarget.getWorkTree(), "OtherFile.txt");
358 		writeToFile(targetFile2, "Unconflicting change");
359 		target.add().addFilepattern("OtherFile.txt").call();
360 		RevCommit targetCommit = target.commit()
361 				.setMessage("Unconflicting change in local").call();
362 
363 		// the source branch "other" matching the target branch should be
364 		// implied
365 		PullResult res = target.pull().setRemote("origin").setRebase(false)
366 				.call();
367 
368 		MergeResult mergeResult = res.getMergeResult();
369 		ObjectId[] mergedCommits = mergeResult.getMergedCommits();
370 		assertEquals(targetCommit.getId(), mergedCommits[0]);
371 		assertEquals(sourceCommit.getId(), mergedCommits[1]);
372 		try (RevWalk rw = new RevWalk(dbTarget)) {
373 			RevCommit mergeCommit = rw.parseCommit(mergeResult.getNewHead());
374 			String message = "Merge branch 'other' of "
375 					+ db.getWorkTree().getAbsolutePath() + " into other";
376 			assertEquals(message, mergeCommit.getShortMessage());
377 		}
378 	}
379 
380 	private enum TestPullMode {
381 		MERGE, REBASE, REBASE_PREASERVE
382 	}
383 
384 	@Test
385 	/** global rebase config should be respected */
386 	public void testPullWithRebasePreserve1Config() throws Exception {
387 		Callable<PullResult> setup = () -> {
388 			StoredConfig config = dbTarget.getConfig();
389 			config.setString("pull", null, "rebase", "preserve");
390 			config.save();
391 			return target.pull().call();
392 		};
393 		doTestPullWithRebase(setup, TestPullMode.REBASE_PREASERVE);
394 	}
395 
396 	@Test
397 	/** the branch-local config should win over the global config */
398 	public void testPullWithRebasePreserveConfig2() throws Exception {
399 		Callable<PullResult> setup = () -> {
400 			StoredConfig config = dbTarget.getConfig();
401 			config.setString("pull", null, "rebase", "false");
402 			config.setString("branch", "master", "rebase", "preserve");
403 			config.save();
404 			return target.pull().call();
405 		};
406 		doTestPullWithRebase(setup, TestPullMode.REBASE_PREASERVE);
407 	}
408 
409 	@Test
410 	/** the branch-local config should be respected */
411 	public void testPullWithRebasePreserveConfig3() throws Exception {
412 		Callable<PullResult> setup = () -> {
413 			StoredConfig config = dbTarget.getConfig();
414 			config.setString("branch", "master", "rebase", "preserve");
415 			config.save();
416 			return target.pull().call();
417 		};
418 		doTestPullWithRebase(setup, TestPullMode.REBASE_PREASERVE);
419 	}
420 
421 	@Test
422 	/** global rebase config should be respected */
423 	public void testPullWithRebaseConfig1() throws Exception {
424 		Callable<PullResult> setup = () -> {
425 			StoredConfig config = dbTarget.getConfig();
426 			config.setString("pull", null, "rebase", "true");
427 			config.save();
428 			return target.pull().call();
429 		};
430 		doTestPullWithRebase(setup, TestPullMode.REBASE);
431 	}
432 
433 	@Test
434 	/** the branch-local config should win over the global config */
435 	public void testPullWithRebaseConfig2() throws Exception {
436 		Callable<PullResult> setup = () -> {
437 			StoredConfig config = dbTarget.getConfig();
438 			config.setString("pull", null, "rebase", "preserve");
439 			config.setString("branch", "master", "rebase", "true");
440 			config.save();
441 			return target.pull().call();
442 		};
443 		doTestPullWithRebase(setup, TestPullMode.REBASE);
444 	}
445 
446 	@Test
447 	/** the branch-local config should be respected */
448 	public void testPullWithRebaseConfig3() throws Exception {
449 		Callable<PullResult> setup = () -> {
450 			StoredConfig config = dbTarget.getConfig();
451 			config.setString("branch", "master", "rebase", "true");
452 			config.save();
453 			return target.pull().call();
454 		};
455 		doTestPullWithRebase(setup, TestPullMode.REBASE);
456 	}
457 
458 	@Test
459 	/** without config it should merge */
460 	public void testPullWithoutConfig() throws Exception {
461 		Callable<PullResult> setup = target.pull()::call;
462 		doTestPullWithRebase(setup, TestPullMode.MERGE);
463 	}
464 
465 	@Test
466 	/** the branch local config should win over the global config */
467 	public void testPullWithMergeConfig() throws Exception {
468 		Callable<PullResult> setup = () -> {
469 			StoredConfig config = dbTarget.getConfig();
470 			config.setString("pull", null, "rebase", "true");
471 			config.setString("branch", "master", "rebase", "false");
472 			config.save();
473 			return target.pull().call();
474 		};
475 		doTestPullWithRebase(setup, TestPullMode.MERGE);
476 	}
477 
478 	@Test
479 	/** the branch local config should win over the global config */
480 	public void testPullWithMergeConfig2() throws Exception {
481 		Callable<PullResult> setup = () -> {
482 			StoredConfig config = dbTarget.getConfig();
483 			config.setString("pull", null, "rebase", "false");
484 			config.save();
485 			return target.pull().call();
486 		};
487 		doTestPullWithRebase(setup, TestPullMode.MERGE);
488 	}
489 
490 	private void doTestPullWithRebase(Callable<PullResult> pullSetup,
491 			TestPullMode expectedPullMode) throws Exception {
492 		// simple upstream change
493 		writeToFile(sourceFile, "content");
494 		source.add().addFilepattern(sourceFile.getName()).call();
495 		RevCommit sourceCommit = source.commit().setMessage("source commit")
496 				.call();
497 
498 		// create a merge commit in target
499 		File loxalFile = new File(dbTarget.getWorkTree(), "local.txt");
500 		writeToFile(loxalFile, "initial\n");
501 		target.add().addFilepattern("local.txt").call();
502 		RevCommit t1 = target.commit().setMessage("target commit 1").call();
503 
504 		target.checkout().setCreateBranch(true).setName("side").call();
505 
506 		String newContent = "initial\n" + "and more\n";
507 		writeToFile(loxalFile, newContent);
508 		target.add().addFilepattern("local.txt").call();
509 		RevCommit t2 = target.commit().setMessage("target commit 2").call();
510 
511 		target.checkout().setName("master").call();
512 
513 		MergeResult mergeResult = target.merge()
514 				.setFastForward(MergeCommand.FastForwardMode.NO_FF).include(t2)
515 				.call();
516 		assertEquals(MergeStatus.MERGED, mergeResult.getMergeStatus());
517 		assertFileContentsEqual(loxalFile, newContent);
518 		ObjectId merge = mergeResult.getNewHead();
519 
520 		// pull
521 		PullResult res = pullSetup.call();
522 		assertNotNull(res.getFetchResult());
523 
524 		if (expectedPullMode == TestPullMode.MERGE) {
525 			assertEquals(MergeStatus.MERGED, res.getMergeResult()
526 					.getMergeStatus());
527 			assertNull(res.getRebaseResult());
528 		} else {
529 			assertNull(res.getMergeResult());
530 			assertEquals(RebaseResult.OK_RESULT, res.getRebaseResult());
531 		}
532 		assertFileContentsEqual(sourceFile, "content");
533 
534 		try (RevWalk rw = new RevWalk(dbTarget)) {
535 			rw.sort(RevSort.TOPO);
536 			rw.markStart(rw.parseCommit(dbTarget.resolve("refs/heads/master")));
537 
538 			RevCommit next;
539 			if (expectedPullMode == TestPullMode.MERGE) {
540 				next = rw.next();
541 				assertEquals(2, next.getParentCount());
542 				assertEquals(merge, next.getParent(0));
543 				assertEquals(sourceCommit, next.getParent(1));
544 				// since both parents are known do no further checks here
545 			} else {
546 				if (expectedPullMode == TestPullMode.REBASE_PREASERVE) {
547 					next = rw.next();
548 					assertEquals(2, next.getParentCount());
549 				}
550 				next = rw.next();
551 				assertEquals(t2.getShortMessage(), next.getShortMessage());
552 				next = rw.next();
553 				assertEquals(t1.getShortMessage(), next.getShortMessage());
554 				next = rw.next();
555 				assertEquals(sourceCommit, next);
556 				next = rw.next();
557 				assertEquals("Initial commit for source",
558 						next.getShortMessage());
559 				next = rw.next();
560 				assertNull(next);
561 			}
562 		}
563 	}
564 
565 	@Override
566 	@Before
567 	public void setUp() throws Exception {
568 		super.setUp();
569 		dbTarget = createWorkRepository();
570 		source = new Git(db);
571 		target = new Git(dbTarget);
572 
573 		// put some file in the source repo
574 		sourceFile = new File(db.getWorkTree(), "SomeFile.txt");
575 		writeToFile(sourceFile, "Hello world");
576 		// and commit it
577 		source.add().addFilepattern("SomeFile.txt").call();
578 		source.commit().setMessage("Initial commit for source").call();
579 
580 		// configure the target repo to connect to the source via "origin"
581 		StoredConfig targetConfig = dbTarget.getConfig();
582 		targetConfig.setString("branch", "master", "remote", "origin");
583 		targetConfig
584 				.setString("branch", "master", "merge", "refs/heads/master");
585 		RemoteConfig config = new RemoteConfig(targetConfig, "origin");
586 
587 		config
588 				.addURI(new URIish(source.getRepository().getWorkTree()
589 						.getAbsolutePath()));
590 		config.addFetchRefSpec(new RefSpec(
591 				"+refs/heads/*:refs/remotes/origin/*"));
592 		config.update(targetConfig);
593 		targetConfig.save();
594 
595 		targetFile = new File(dbTarget.getWorkTree(), "SomeFile.txt");
596 		// make sure we have the same content
597 		target.pull().call();
598 		assertFileContentsEqual(targetFile, "Hello world");
599 	}
600 
601 	private static void writeToFile(File actFile, String string)
602 			throws IOException {
603 		try (FileOutputStream fos = new FileOutputStream(actFile)) {
604 			fos.write(string.getBytes(UTF_8));
605 		}
606 	}
607 
608 	private static void assertFileContentsEqual(File actFile, String string)
609 			throws IOException {
610 		ByteArrayOutputStream bos = new ByteArrayOutputStream();
611 		byte[] buffer = new byte[100];
612 		try (FileInputStream fis = new FileInputStream(actFile)) {
613 			int read = fis.read(buffer);
614 			while (read > 0) {
615 				bos.write(buffer, 0, read);
616 				read = fis.read(buffer);
617 			}
618 			String content = new String(bos.toByteArray(), UTF_8);
619 			assertEquals(string, content);
620 		}
621 	}
622 }