View Javadoc
1   /*
2    * Copyright (C) 2010, 2014 Chris Aniszczyk <caniszczyk@gmail.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 org.junit.Assert.assertEquals;
13  import static org.junit.Assert.assertFalse;
14  import static org.junit.Assert.assertNotNull;
15  import static org.junit.Assert.assertThrows;
16  import static org.junit.Assert.assertTrue;
17  import static org.junit.Assert.fail;
18  
19  import java.io.ByteArrayOutputStream;
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.PrintStream;
23  import java.net.URISyntaxException;
24  import java.nio.charset.StandardCharsets;
25  import java.util.Properties;
26  
27  import org.eclipse.jgit.api.errors.DetachedHeadException;
28  import org.eclipse.jgit.api.errors.GitAPIException;
29  import org.eclipse.jgit.api.errors.InvalidRefNameException;
30  import org.eclipse.jgit.api.errors.JGitInternalException;
31  import org.eclipse.jgit.api.errors.TransportException;
32  import org.eclipse.jgit.errors.MissingObjectException;
33  import org.eclipse.jgit.errors.NoRemoteRepositoryException;
34  import org.eclipse.jgit.hooks.PrePushHook;
35  import org.eclipse.jgit.junit.JGitTestUtil;
36  import org.eclipse.jgit.junit.RepositoryTestCase;
37  import org.eclipse.jgit.lib.ObjectId;
38  import org.eclipse.jgit.lib.Ref;
39  import org.eclipse.jgit.lib.RefUpdate;
40  import org.eclipse.jgit.lib.Repository;
41  import org.eclipse.jgit.lib.StoredConfig;
42  import org.eclipse.jgit.revwalk.RevCommit;
43  import org.eclipse.jgit.transport.PushConfig.PushDefault;
44  import org.eclipse.jgit.transport.PushResult;
45  import org.eclipse.jgit.transport.RefLeaseSpec;
46  import org.eclipse.jgit.transport.RefSpec;
47  import org.eclipse.jgit.transport.RemoteConfig;
48  import org.eclipse.jgit.transport.RemoteRefUpdate;
49  import org.eclipse.jgit.transport.TrackingRefUpdate;
50  import org.eclipse.jgit.transport.URIish;
51  import org.eclipse.jgit.util.FS;
52  import org.junit.Test;
53  
54  public class PushCommandTest extends RepositoryTestCase {
55  
56  	@Test
57  	public void testPush() throws JGitInternalException, IOException,
58  			GitAPIException, URISyntaxException {
59  
60  		// create other repository
61  		Repository db2 = createWorkRepository();
62  		addRepoToClose(db2);
63  		final StoredConfig config2 = db2.getConfig();
64  
65  		// this tests that this config can be parsed properly
66  		config2.setString("fsck", "", "missingEmail", "ignore");
67  		config2.save();
68  
69  		// setup the first repository
70  		final StoredConfig config = db.getConfig();
71  		RemoteConfig remoteConfig = new RemoteConfig(config, "test");
72  		URIish uri = new URIish(db2.getDirectory().toURI().toURL());
73  		remoteConfig.addURI(uri);
74  		remoteConfig.update(config);
75  		config.save();
76  
77  		try (Git git1 = new Git(db)) {
78  			// create some refs via commits and tag
79  			RevCommit commit = git1.commit().setMessage("initial commit").call();
80  			Ref tagRef = git1.tag().setName("tag").call();
81  
82  			try {
83  				db2.resolve(commit.getId().getName() + "^{commit}");
84  				fail("id shouldn't exist yet");
85  			} catch (MissingObjectException e) {
86  				// we should get here
87  			}
88  
89  			RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x");
90  			git1.push().setRemote("test").setRefSpecs(spec)
91  					.call();
92  
93  			assertEquals(commit.getId(),
94  					db2.resolve(commit.getId().getName() + "^{commit}"));
95  			assertEquals(tagRef.getObjectId(),
96  					db2.resolve(tagRef.getObjectId().getName()));
97  		}
98  	}
99  
100 	@Test
101 	public void testPrePushHook() throws JGitInternalException, IOException,
102 			GitAPIException, URISyntaxException {
103 
104 		// create other repository
105 		Repository db2 = createWorkRepository();
106 
107 		// setup the first repository
108 		final StoredConfig config = db.getConfig();
109 		RemoteConfig remoteConfig = new RemoteConfig(config, "test");
110 		URIish uri = new URIish(db2.getDirectory().toURI().toURL());
111 		remoteConfig.addURI(uri);
112 		remoteConfig.update(config);
113 		config.save();
114 
115 		File hookOutput = new File(getTemporaryDirectory(), "hookOutput");
116 		writeHookFile(PrePushHook.NAME, "#!/bin/sh\necho 1:$1, 2:$2, 3:$3 >\""
117 				+ hookOutput.toPath() + "\"\ncat - >>\"" + hookOutput.toPath()
118 				+ "\"\nexit 0");
119 
120 		try (Git git1 = new Git(db)) {
121 			// create a commit
122 			RevCommit commit = git1.commit().setMessage("initial commit").call();
123 
124 			RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x");
125 			git1.push().setRemote("test").setRefSpecs(spec).call();
126 			assertEquals("1:test, 2:" + uri + ", 3:\n" + "refs/heads/master "
127 					+ commit.getName() + " refs/heads/x "
128 					+ ObjectId.zeroId().name() + "\n", read(hookOutput));
129 		}
130 	}
131 
132 	@Test
133 	public void testPrePushHookRedirects() throws JGitInternalException,
134 			IOException, GitAPIException, URISyntaxException {
135 
136 		// create other repository
137 		Repository db2 = createWorkRepository();
138 
139 		// setup the first repository
140 		final StoredConfig config = db.getConfig();
141 		RemoteConfig remoteConfig = new RemoteConfig(config, "test");
142 		URIish uri = new URIish(db2.getDirectory().toURI().toURL());
143 		remoteConfig.addURI(uri);
144 		remoteConfig.update(config);
145 		config.save();
146 
147 		writeHookFile(PrePushHook.NAME, "#!/bin/sh\n"
148 				+ "echo \"1:$1, 2:$2, 3:$3\"\n" // to stdout
149 				+ "cat - 1>&2\n" // to stderr
150 				+ "exit 0\n");
151 
152 		try (Git git1 = new Git(db)) {
153 			// create a commit
154 			RevCommit commit = git1.commit().setMessage("initial commit")
155 					.call();
156 
157 			RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x");
158 			try (ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
159 					ByteArrayOutputStream errBytes = new ByteArrayOutputStream();
160 					PrintStream stdout = new PrintStream(outBytes, true,
161 							StandardCharsets.UTF_8);
162 					PrintStream stderr = new PrintStream(errBytes, true,
163 							StandardCharsets.UTF_8)) {
164 				git1.push()
165 						.setRemote("test")
166 						.setRefSpecs(spec)
167 						.setHookOutputStream(stdout)
168 						.setHookErrorStream(stderr)
169 						.call();
170 				String out = outBytes.toString(StandardCharsets.UTF_8);
171 				String err = errBytes.toString(StandardCharsets.UTF_8);
172 				assertEquals("1:test, 2:" + uri + ", 3:\n", out);
173 				assertEquals("refs/heads/master " + commit.getName()
174 						+ " refs/heads/x " + ObjectId.zeroId().name() + '\n',
175 						err);
176 			}
177 		}
178 	}
179 
180 	private File writeHookFile(String name, String data)
181 			throws IOException {
182 		File path = new File(db.getWorkTree() + "/.git/hooks/", name);
183 		JGitTestUtil.write(path, data);
184 		FS.DETECTED.setExecute(path, true);
185 		return path;
186 	}
187 
188 
189 	@Test
190 	public void testTrackingUpdate() throws Exception {
191 		Repository db2 = createBareRepository();
192 
193 		String remote = "origin";
194 		String branch = "refs/heads/master";
195 		String trackingBranch = "refs/remotes/" + remote + "/master";
196 
197 		try (Git git = new Git(db)) {
198 			RevCommit commit1 = git.commit().setMessage("Initial commit")
199 					.call();
200 
201 			RefUpdate branchRefUpdate = db.updateRef(branch);
202 			branchRefUpdate.setNewObjectId(commit1.getId());
203 			branchRefUpdate.update();
204 
205 			RefUpdate trackingBranchRefUpdate = db.updateRef(trackingBranch);
206 			trackingBranchRefUpdate.setNewObjectId(commit1.getId());
207 			trackingBranchRefUpdate.update();
208 
209 			final StoredConfig config = db.getConfig();
210 			RemoteConfig remoteConfig = new RemoteConfig(config, remote);
211 			URIish uri = new URIish(db2.getDirectory().toURI().toURL());
212 			remoteConfig.addURI(uri);
213 			remoteConfig.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/"
214 					+ remote + "/*"));
215 			remoteConfig.update(config);
216 			config.save();
217 
218 
219 			RevCommit commit2 = git.commit().setMessage("Commit to push").call();
220 
221 			RefSpec spec = new RefSpec(branch + ":" + branch);
222 			Iterable<PushResult> resultIterable = git.push().setRemote(remote)
223 					.setRefSpecs(spec).call();
224 
225 			PushResult result = resultIterable.iterator().next();
226 			TrackingRefUpdate trackingRefUpdate = result
227 					.getTrackingRefUpdate(trackingBranch);
228 
229 			assertNotNull(trackingRefUpdate);
230 			assertEquals(trackingBranch, trackingRefUpdate.getLocalName());
231 			assertEquals(branch, trackingRefUpdate.getRemoteName());
232 			assertEquals(commit2.getId(), trackingRefUpdate.getNewObjectId());
233 			assertEquals(commit2.getId(), db.resolve(trackingBranch));
234 			assertEquals(commit2.getId(), db2.resolve(branch));
235 		}
236 	}
237 
238 	/**
239 	 * Check that pushes over file protocol lead to appropriate ref-updates.
240 	 *
241 	 * @throws Exception
242 	 */
243 	@Test
244 	public void testPushRefUpdate() throws Exception {
245 		try (Git git = new Git(db);
246 				Git git2 = new Git(createBareRepository())) {
247 			final StoredConfig config = git.getRepository().getConfig();
248 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
249 			URIish uri = new URIish(git2.getRepository().getDirectory().toURI()
250 					.toURL());
251 			remoteConfig.addURI(uri);
252 			remoteConfig.addPushRefSpec(new RefSpec("+refs/heads/*:refs/heads/*"));
253 			remoteConfig.update(config);
254 			config.save();
255 
256 			writeTrashFile("f", "content of f");
257 			git.add().addFilepattern("f").call();
258 			RevCommit commit = git.commit().setMessage("adding f").call();
259 
260 			assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
261 			git.push().setRemote("test").call();
262 			assertEquals(commit.getId(),
263 					git2.getRepository().resolve("refs/heads/master"));
264 
265 			git.branchCreate().setName("refs/heads/test").call();
266 			git.checkout().setName("refs/heads/test").call();
267 
268 			for (int i = 0; i < 6; i++) {
269 				writeTrashFile("f" + i, "content of f" + i);
270 				git.add().addFilepattern("f" + i).call();
271 				commit = git.commit().setMessage("adding f" + i).call();
272 				git.push().setRemote("test").call();
273 				git2.getRepository().getRefDatabase().getRefs();
274 				assertEquals("failed to update on attempt " + i, commit.getId(),
275 						git2.getRepository().resolve("refs/heads/test"));
276 			}
277 		}
278 	}
279 
280 	/**
281 	 * Check that the push refspec is read from config.
282 	 *
283 	 * @throws Exception
284 	 */
285 	@Test
286 	public void testPushWithRefSpecFromConfig() throws Exception {
287 		try (Git git = new Git(db);
288 				Git git2 = new Git(createBareRepository())) {
289 			final StoredConfig config = git.getRepository().getConfig();
290 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
291 			URIish uri = new URIish(git2.getRepository().getDirectory().toURI()
292 					.toURL());
293 			remoteConfig.addURI(uri);
294 			remoteConfig.addPushRefSpec(new RefSpec("HEAD:refs/heads/newbranch"));
295 			remoteConfig.update(config);
296 			config.save();
297 
298 			writeTrashFile("f", "content of f");
299 			git.add().addFilepattern("f").call();
300 			RevCommit commit = git.commit().setMessage("adding f").call();
301 
302 			assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
303 			git.push().setRemote("test").call();
304 			assertEquals(commit.getId(),
305 					git2.getRepository().resolve("refs/heads/newbranch"));
306 		}
307 	}
308 
309 	/**
310 	 * Check that only HEAD is pushed if no refspec is given.
311 	 *
312 	 * @throws Exception
313 	 */
314 	@Test
315 	public void testPushWithoutPushRefSpec() throws Exception {
316 		try (Git git = new Git(db);
317 				Git git2 = new Git(createBareRepository())) {
318 			final StoredConfig config = git.getRepository().getConfig();
319 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
320 			URIish uri = new URIish(git2.getRepository().getDirectory().toURI()
321 					.toURL());
322 			remoteConfig.addURI(uri);
323 			remoteConfig.addFetchRefSpec(new RefSpec(
324 					"+refs/heads/*:refs/remotes/origin/*"));
325 			remoteConfig.update(config);
326 			config.save();
327 
328 			writeTrashFile("f", "content of f");
329 			git.add().addFilepattern("f").call();
330 			RevCommit commit = git.commit().setMessage("adding f").call();
331 
332 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
333 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
334 
335 			assertEquals(null,
336 					git2.getRepository().resolve("refs/heads/branchtopush"));
337 			assertEquals(null, git2.getRepository()
338 					.resolve("refs/heads/not-pushed"));
339 			assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
340 			git.push().setRemote("test").call();
341 			assertEquals(commit.getId(),
342 					git2.getRepository().resolve("refs/heads/branchtopush"));
343 			assertEquals(null, git2.getRepository()
344 					.resolve("refs/heads/not-pushed"));
345 			assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
346 		}
347 	}
348 
349 	/**
350 	 * Check that pushing from a detached HEAD without refspec throws a
351 	 * DetachedHeadException.
352 	 *
353 	 * @throws Exception
354 	 */
355 	@Test
356 	public void testPushDefaultDetachedHead() throws Exception {
357 		try (Git git = new Git(db);
358 				Git git2 = new Git(createBareRepository())) {
359 			final StoredConfig config = git.getRepository().getConfig();
360 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
361 			URIish uri = new URIish(
362 					git2.getRepository().getDirectory().toURI().toURL());
363 			remoteConfig.addURI(uri);
364 			remoteConfig.addFetchRefSpec(
365 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
366 			remoteConfig.update(config);
367 			config.save();
368 
369 			writeTrashFile("f", "content of f");
370 			git.add().addFilepattern("f").call();
371 			RevCommit commit = git.commit().setMessage("adding f").call();
372 
373 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
374 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
375 			git.checkout().setName(commit.getName()).call();
376 			String head = git.getRepository().getFullBranch();
377 			assertTrue(ObjectId.isId(head));
378 			assertEquals(commit.getName(), head);
379 			assertThrows(DetachedHeadException.class,
380 					() -> git.push().setRemote("test").call());
381 		}
382 	}
383 
384 	/**
385 	 * Check that push.default=nothing without refspec throws an
386 	 * InvalidRefNameException.
387 	 *
388 	 * @throws Exception
389 	 */
390 	@Test
391 	public void testPushDefaultNothing() throws Exception {
392 		try (Git git = new Git(db);
393 				Git git2 = new Git(createBareRepository())) {
394 			final StoredConfig config = git.getRepository().getConfig();
395 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
396 			URIish uri = new URIish(
397 					git2.getRepository().getDirectory().toURI().toURL());
398 			remoteConfig.addURI(uri);
399 			remoteConfig.addFetchRefSpec(
400 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
401 			remoteConfig.update(config);
402 			config.save();
403 
404 			writeTrashFile("f", "content of f");
405 			git.add().addFilepattern("f").call();
406 			git.commit().setMessage("adding f").call();
407 
408 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
409 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
410 
411 			assertEquals(null,
412 					git2.getRepository().resolve("refs/heads/branchtopush"));
413 			assertEquals(null,
414 					git2.getRepository().resolve("refs/heads/not-pushed"));
415 			assertEquals(null,
416 					git2.getRepository().resolve("refs/heads/master"));
417 			assertThrows(InvalidRefNameException.class,
418 					() -> git.push().setRemote("test")
419 							.setPushDefault(PushDefault.NOTHING).call());
420 		}
421 	}
422 
423 	/**
424 	 * Check that push.default=matching without refspec pushes all matching
425 	 * branches.
426 	 *
427 	 * @throws Exception
428 	 */
429 	@Test
430 	public void testPushDefaultMatching() throws Exception {
431 		try (Git git = new Git(db);
432 				Git git2 = new Git(createBareRepository())) {
433 			final StoredConfig config = git.getRepository().getConfig();
434 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
435 			URIish uri = new URIish(
436 					git2.getRepository().getDirectory().toURI().toURL());
437 			remoteConfig.addURI(uri);
438 			remoteConfig.addFetchRefSpec(
439 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
440 			remoteConfig.update(config);
441 			config.save();
442 
443 			writeTrashFile("f", "content of f");
444 			git.add().addFilepattern("f").call();
445 			RevCommit commit = git.commit().setMessage("adding f").call();
446 
447 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
448 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
449 
450 			assertEquals(null,
451 					git2.getRepository().resolve("refs/heads/branchtopush"));
452 			assertEquals(null,
453 					git2.getRepository().resolve("refs/heads/not-pushed"));
454 			assertEquals(null,
455 					git2.getRepository().resolve("refs/heads/master"));
456 			// push master and branchtopush
457 			git.push().setRemote("test").setRefSpecs(
458 					new RefSpec("refs/heads/master:refs/heads/master"),
459 					new RefSpec(
460 							"refs/heads/branchtopush:refs/heads/branchtopush"))
461 					.call();
462 			assertEquals(commit.getId(),
463 					git2.getRepository().resolve("refs/heads/master"));
464 			assertEquals(commit.getId(),
465 					git2.getRepository().resolve("refs/heads/branchtopush"));
466 			assertEquals(null,
467 					git2.getRepository().resolve("refs/heads/not-pushed"));
468 			// Create two different commits on these two branches
469 			writeTrashFile("b", "on branchtopush");
470 			git.add().addFilepattern("b").call();
471 			RevCommit bCommit = git.commit().setMessage("on branchtopush")
472 					.call();
473 			git.checkout().setName("master").call();
474 			writeTrashFile("m", "on master");
475 			git.add().addFilepattern("m").call();
476 			RevCommit mCommit = git.commit().setMessage("on master").call();
477 			// Now push with mode "matching": should push both branches.
478 			Iterable<PushResult> result = git.push().setRemote("test")
479 					.setPushDefault(PushDefault.MATCHING)
480 					.call();
481 			int n = 0;
482 			for (PushResult r : result) {
483 				n++;
484 				assertEquals(1, n);
485 				assertEquals(2, r.getRemoteUpdates().size());
486 				for (RemoteRefUpdate update : r.getRemoteUpdates()) {
487 					assertFalse(update.isMatching());
488 					assertTrue(update.getSrcRef()
489 							.equals("refs/heads/branchtopush")
490 							|| update.getSrcRef().equals("refs/heads/master"));
491 					assertEquals(RemoteRefUpdate.Status.OK, update.getStatus());
492 				}
493 			}
494 			assertEquals(bCommit.getId(),
495 					git2.getRepository().resolve("refs/heads/branchtopush"));
496 			assertEquals(null,
497 					git2.getRepository().resolve("refs/heads/not-pushed"));
498 			assertEquals(mCommit.getId(),
499 					git2.getRepository().resolve("refs/heads/master"));
500 			assertEquals(bCommit.getId(), git.getRepository()
501 					.resolve("refs/remotes/origin/branchtopush"));
502 			assertEquals(null, git.getRepository()
503 					.resolve("refs/remotes/origin/not-pushed"));
504 			assertEquals(mCommit.getId(),
505 					git.getRepository().resolve("refs/remotes/origin/master"));
506 		}
507 	}
508 
509 	/**
510 	 * Check that push.default=upstream without refspec pushes only the current
511 	 * branch to the configured upstream.
512 	 *
513 	 * @throws Exception
514 	 */
515 	@Test
516 	public void testPushDefaultUpstream() throws Exception {
517 		try (Git git = new Git(db);
518 				Git git2 = new Git(createBareRepository())) {
519 			StoredConfig config = git.getRepository().getConfig();
520 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
521 			URIish uri = new URIish(
522 					git2.getRepository().getDirectory().toURI().toURL());
523 			remoteConfig.addURI(uri);
524 			remoteConfig.addFetchRefSpec(
525 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
526 			remoteConfig.update(config);
527 			config.save();
528 
529 			writeTrashFile("f", "content of f");
530 			git.add().addFilepattern("f").call();
531 			RevCommit commit = git.commit().setMessage("adding f").call();
532 
533 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
534 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
535 
536 			config = git.getRepository().getConfig();
537 			config.setString("branch", "branchtopush", "remote", "test");
538 			config.setString("branch", "branchtopush", "merge",
539 					"refs/heads/upstreambranch");
540 			config.save();
541 
542 			assertEquals(null,
543 					git2.getRepository().resolve("refs/heads/branchtopush"));
544 			assertEquals(null,
545 					git2.getRepository().resolve("refs/heads/upstreambranch"));
546 			assertEquals(null,
547 					git2.getRepository().resolve("refs/heads/not-pushed"));
548 			assertEquals(null,
549 					git2.getRepository().resolve("refs/heads/master"));
550 			git.push().setRemote("test").setPushDefault(PushDefault.UPSTREAM)
551 					.call();
552 			assertEquals(null,
553 					git2.getRepository().resolve("refs/heads/branchtopush"));
554 			assertEquals(commit.getId(),
555 					git2.getRepository().resolve("refs/heads/upstreambranch"));
556 			assertEquals(null,
557 					git2.getRepository().resolve("refs/heads/not-pushed"));
558 			assertEquals(null,
559 					git2.getRepository().resolve("refs/heads/master"));
560 			assertEquals(commit.getId(), git.getRepository()
561 					.resolve("refs/remotes/origin/upstreambranch"));
562 			assertEquals(null, git.getRepository()
563 					.resolve("refs/remotes/origin/branchtopush"));
564 		}
565 	}
566 
567 	/**
568 	 * Check that push.default=upstream without refspec throws an
569 	 * InvalidRefNameException if the current branch has no upstream.
570 	 *
571 	 * @throws Exception
572 	 */
573 	@Test
574 	public void testPushDefaultUpstreamNoTracking() throws Exception {
575 		try (Git git = new Git(db);
576 				Git git2 = new Git(createBareRepository())) {
577 			StoredConfig config = git.getRepository().getConfig();
578 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
579 			URIish uri = new URIish(
580 					git2.getRepository().getDirectory().toURI().toURL());
581 			remoteConfig.addURI(uri);
582 			remoteConfig.addFetchRefSpec(
583 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
584 			remoteConfig.update(config);
585 			config.save();
586 
587 			writeTrashFile("f", "content of f");
588 			git.add().addFilepattern("f").call();
589 			git.commit().setMessage("adding f").call();
590 
591 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
592 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
593 
594 			config = git.getRepository().getConfig();
595 			config.setString("branch", "branchtopush", "remote", "test");
596 			config.save();
597 
598 			assertThrows(InvalidRefNameException.class,
599 					() -> git.push().setRemote("test")
600 							.setPushDefault(PushDefault.UPSTREAM).call());
601 		}
602 	}
603 
604 	/**
605 	 * Check that push.default=upstream without refspec throws an
606 	 * InvalidRefNameException if the push remote is not the same as the fetch
607 	 * remote.
608 	 *
609 	 * @throws Exception
610 	 */
611 	@Test
612 	public void testPushDefaultUpstreamTriangular() throws Exception {
613 		try (Git git = new Git(db);
614 				Git git2 = new Git(createBareRepository())) {
615 			StoredConfig config = git.getRepository().getConfig();
616 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
617 			URIish uri = new URIish(
618 					git2.getRepository().getDirectory().toURI().toURL());
619 			remoteConfig.addURI(uri);
620 			remoteConfig.addFetchRefSpec(
621 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
622 			remoteConfig.update(config);
623 			config.save();
624 
625 			writeTrashFile("f", "content of f");
626 			git.add().addFilepattern("f").call();
627 			git.commit().setMessage("adding f").call();
628 
629 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
630 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
631 
632 			config = git.getRepository().getConfig();
633 			// Don't configure a remote; it'll default to "origin".
634 			config.setString("branch", "branchtopush", "merge",
635 					"upstreambranch");
636 			config.save();
637 
638 			assertThrows(InvalidRefNameException.class,
639 					() -> git.push().setRemote("test")
640 							.setPushDefault(PushDefault.UPSTREAM).call());
641 		}
642 	}
643 
644 	/**
645 	 * Check that push.default=simple without refspec pushes only the current
646 	 * branch to the configured upstream name.
647 	 *
648 	 * @throws Exception
649 	 */
650 	@Test
651 	public void testPushDefaultSimple() throws Exception {
652 		try (Git git = new Git(db);
653 				Git git2 = new Git(createBareRepository())) {
654 			StoredConfig config = git.getRepository().getConfig();
655 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
656 			URIish uri = new URIish(
657 					git2.getRepository().getDirectory().toURI().toURL());
658 			remoteConfig.addURI(uri);
659 			remoteConfig.addFetchRefSpec(
660 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
661 			remoteConfig.update(config);
662 			config.save();
663 
664 			writeTrashFile("f", "content of f");
665 			git.add().addFilepattern("f").call();
666 			RevCommit commit = git.commit().setMessage("adding f").call();
667 
668 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
669 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
670 
671 			config = git.getRepository().getConfig();
672 			config.setString("branch", "branchtopush", "remote", "test");
673 			config.setString("branch", "branchtopush", "merge",
674 					"refs/heads/branchtopush");
675 			config.save();
676 
677 			assertEquals(null,
678 					git2.getRepository().resolve("refs/heads/branchtopush"));
679 			assertEquals(null,
680 					git2.getRepository().resolve("refs/heads/not-pushed"));
681 			assertEquals(null,
682 					git2.getRepository().resolve("refs/heads/master"));
683 			git.push().setRemote("test").setPushDefault(PushDefault.SIMPLE)
684 					.call();
685 			assertEquals(commit.getId(),
686 					git2.getRepository().resolve("refs/heads/branchtopush"));
687 			assertEquals(null,
688 					git2.getRepository().resolve("refs/heads/not-pushed"));
689 			assertEquals(null,
690 					git2.getRepository().resolve("refs/heads/master"));
691 			assertEquals(commit.getId(), git.getRepository()
692 					.resolve("refs/remotes/origin/branchtopush"));
693 		}
694 	}
695 
696 	/**
697 	 * Check that push.default=simple without refspec pushes only the current
698 	 * branch to a branch with the same name in a triangular workflow.
699 	 *
700 	 * @throws Exception
701 	 */
702 	@Test
703 	public void testPushDefaultSimpleTriangular() throws Exception {
704 		try (Git git = new Git(db);
705 				Git git2 = new Git(createBareRepository())) {
706 			StoredConfig config = git.getRepository().getConfig();
707 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
708 			URIish uri = new URIish(
709 					git2.getRepository().getDirectory().toURI().toURL());
710 			remoteConfig.addURI(uri);
711 			remoteConfig.addFetchRefSpec(
712 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
713 			remoteConfig.update(config);
714 			config.save();
715 
716 			writeTrashFile("f", "content of f");
717 			git.add().addFilepattern("f").call();
718 			RevCommit commit = git.commit().setMessage("adding f").call();
719 
720 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
721 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
722 
723 			config = git.getRepository().getConfig();
724 			// Don't set remote, it'll default to "origin". Configure a
725 			// different branch name; should be ignored.
726 			config.setString("branch", "branchtopush", "merge",
727 					"refs/heads/upstreambranch");
728 			config.save();
729 
730 			assertEquals(null,
731 					git2.getRepository().resolve("refs/heads/branchtopush"));
732 			assertEquals(null,
733 					git2.getRepository().resolve("refs/heads/upstreambranch"));
734 			assertEquals(null,
735 					git2.getRepository().resolve("refs/heads/not-pushed"));
736 			assertEquals(null,
737 					git2.getRepository().resolve("refs/heads/master"));
738 			git.push().setRemote("test").setPushDefault(PushDefault.SIMPLE)
739 					.call();
740 			assertEquals(commit.getId(),
741 					git2.getRepository().resolve("refs/heads/branchtopush"));
742 			assertEquals(null,
743 					git2.getRepository().resolve("refs/heads/upstreambranch"));
744 			assertEquals(null,
745 					git2.getRepository().resolve("refs/heads/not-pushed"));
746 			assertEquals(null,
747 					git2.getRepository().resolve("refs/heads/master"));
748 			assertEquals(commit.getId(), git.getRepository()
749 					.resolve("refs/remotes/origin/branchtopush"));
750 		}
751 	}
752 
753 	/**
754 	 * Check that push.default=simple without refspec throws an
755 	 * InvalidRefNameException if the current branch has no upstream.
756 	 *
757 	 * @throws Exception
758 	 */
759 	@Test
760 	public void testPushDefaultSimpleNoTracking() throws Exception {
761 		try (Git git = new Git(db);
762 				Git git2 = new Git(createBareRepository())) {
763 			StoredConfig config = git.getRepository().getConfig();
764 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
765 			URIish uri = new URIish(
766 					git2.getRepository().getDirectory().toURI().toURL());
767 			remoteConfig.addURI(uri);
768 			remoteConfig.addFetchRefSpec(
769 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
770 			remoteConfig.update(config);
771 			config.save();
772 
773 			writeTrashFile("f", "content of f");
774 			git.add().addFilepattern("f").call();
775 			git.commit().setMessage("adding f").call();
776 
777 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
778 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
779 
780 			config = git.getRepository().getConfig();
781 			config.setString("branch", "branchtopush", "remote", "test");
782 			config.save();
783 
784 			assertThrows(InvalidRefNameException.class,
785 					() -> git.push().setRemote("test")
786 							.setPushDefault(PushDefault.SIMPLE).call());
787 		}
788 	}
789 
790 	/**
791 	 * Check that push.default=simple without refspec throws an
792 	 * InvalidRefNameException if the current branch has an upstream with a
793 	 * different name.
794 	 *
795 	 * @throws Exception
796 	 */
797 	@Test
798 	public void testPushDefaultSimpleDifferentTracking() throws Exception {
799 		try (Git git = new Git(db);
800 				Git git2 = new Git(createBareRepository())) {
801 			StoredConfig config = git.getRepository().getConfig();
802 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
803 			URIish uri = new URIish(
804 					git2.getRepository().getDirectory().toURI().toURL());
805 			remoteConfig.addURI(uri);
806 			remoteConfig.addFetchRefSpec(
807 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
808 			remoteConfig.update(config);
809 			config.save();
810 
811 			writeTrashFile("f", "content of f");
812 			git.add().addFilepattern("f").call();
813 			git.commit().setMessage("adding f").call();
814 
815 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
816 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
817 
818 			config = git.getRepository().getConfig();
819 			config.setString("branch", "branchtopush", "remote", "test");
820 			config.setString("branch", "branchtopush", "merge",
821 					"refs/heads/upstreambranch");
822 			config.save();
823 
824 			assertThrows(InvalidRefNameException.class,
825 					() -> git.push().setRemote("test")
826 							.setPushDefault(PushDefault.SIMPLE).call());
827 		}
828 	}
829 
830 	/**
831 	 * Check that if no PushDefault is set, the value is read from the git
832 	 * config.
833 	 *
834 	 * @throws Exception
835 	 */
836 	@Test
837 	public void testPushDefaultFromConfig() throws Exception {
838 		try (Git git = new Git(db);
839 				Git git2 = new Git(createBareRepository())) {
840 			StoredConfig config = git.getRepository().getConfig();
841 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
842 			URIish uri = new URIish(
843 					git2.getRepository().getDirectory().toURI().toURL());
844 			remoteConfig.addURI(uri);
845 			remoteConfig.addFetchRefSpec(
846 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
847 			remoteConfig.update(config);
848 			config.setString("push", null, "default", "upstream");
849 			config.save();
850 
851 			writeTrashFile("f", "content of f");
852 			git.add().addFilepattern("f").call();
853 			RevCommit commit = git.commit().setMessage("adding f").call();
854 
855 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
856 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
857 
858 			config = git.getRepository().getConfig();
859 			config.setString("branch", "branchtopush", "remote", "test");
860 			config.setString("branch", "branchtopush", "merge",
861 					"refs/heads/upstreambranch");
862 			config.save();
863 
864 			assertEquals(null,
865 					git2.getRepository().resolve("refs/heads/branchtopush"));
866 			assertEquals(null,
867 					git2.getRepository().resolve("refs/heads/upstreambranch"));
868 			assertEquals(null,
869 					git2.getRepository().resolve("refs/heads/not-pushed"));
870 			assertEquals(null,
871 					git2.getRepository().resolve("refs/heads/master"));
872 			PushCommand cmd = git.push();
873 			cmd.setRemote("test").setPushDefault(null).call();
874 			assertEquals(PushDefault.UPSTREAM, cmd.getPushDefault());
875 			assertEquals(null,
876 					git2.getRepository().resolve("refs/heads/branchtopush"));
877 			assertEquals(commit.getId(),
878 					git2.getRepository().resolve("refs/heads/upstreambranch"));
879 			assertEquals(null,
880 					git2.getRepository().resolve("refs/heads/not-pushed"));
881 			assertEquals(null,
882 					git2.getRepository().resolve("refs/heads/master"));
883 			assertEquals(commit.getId(), git.getRepository()
884 					.resolve("refs/remotes/origin/upstreambranch"));
885 			assertEquals(null, git.getRepository()
886 					.resolve("refs/remotes/origin/branchtopush"));
887 		}
888 	}
889 
890 	/**
891 	 * Check that if no PushDefault is set and none is set in the git config, it
892 	 * defaults to "simple".
893 	 *
894 	 * @throws Exception
895 	 */
896 	@Test
897 	public void testPushDefaultFromConfigDefault() throws Exception {
898 		try (Git git = new Git(db);
899 				Git git2 = new Git(createBareRepository())) {
900 			StoredConfig config = git.getRepository().getConfig();
901 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
902 			URIish uri = new URIish(
903 					git2.getRepository().getDirectory().toURI().toURL());
904 			remoteConfig.addURI(uri);
905 			remoteConfig.addFetchRefSpec(
906 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
907 			remoteConfig.update(config);
908 			config.save();
909 
910 			writeTrashFile("f", "content of f");
911 			git.add().addFilepattern("f").call();
912 			RevCommit commit = git.commit().setMessage("adding f").call();
913 
914 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
915 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
916 
917 			config = git.getRepository().getConfig();
918 			config.setString("branch", "branchtopush", "remote", "test");
919 			config.setString("branch", "branchtopush", "merge",
920 					"refs/heads/branchtopush");
921 			config.save();
922 
923 			assertEquals(null,
924 					git2.getRepository().resolve("refs/heads/branchtopush"));
925 			assertEquals(null,
926 					git2.getRepository().resolve("refs/heads/not-pushed"));
927 			assertEquals(null,
928 					git2.getRepository().resolve("refs/heads/master"));
929 			PushCommand cmd = git.push();
930 			cmd.setRemote("test").setPushDefault(null).call();
931 			assertEquals(PushDefault.SIMPLE, cmd.getPushDefault());
932 			assertEquals(commit.getId(),
933 					git2.getRepository().resolve("refs/heads/branchtopush"));
934 			assertEquals(null,
935 					git2.getRepository().resolve("refs/heads/not-pushed"));
936 			assertEquals(null,
937 					git2.getRepository().resolve("refs/heads/master"));
938 			assertEquals(commit.getId(), git.getRepository()
939 					.resolve("refs/remotes/origin/branchtopush"));
940 		}
941 	}
942 
943 	/**
944 	 * Check that branch.<name>.pushRemote overrides anything else.
945 	 *
946 	 * @throws Exception
947 	 */
948 	@Test
949 	public void testBranchPushRemote() throws Exception {
950 		try (Git git = new Git(db);
951 				Git git2 = new Git(createBareRepository())) {
952 			StoredConfig config = git.getRepository().getConfig();
953 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
954 			URIish uri = new URIish(
955 					git2.getRepository().getDirectory().toURI().toURL());
956 			remoteConfig.addURI(uri);
957 			remoteConfig.addFetchRefSpec(
958 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
959 			remoteConfig.update(config);
960 			config.setString("remote", null, "pushDefault", "test");
961 			config.save();
962 
963 			writeTrashFile("f", "content of f");
964 			git.add().addFilepattern("f").call();
965 			git.commit().setMessage("adding f").call();
966 
967 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
968 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
969 
970 			config = git.getRepository().getConfig();
971 			config.setString("branch", "branchtopush", "remote", "test");
972 			config.setString("branch", "branchtopush", "pushremote", "origin");
973 			config.setString("branch", "branchtopush", "merge",
974 					"refs/heads/branchtopush");
975 			config.save();
976 
977 			assertThrows(InvalidRefNameException.class, () -> git.push()
978 					.setPushDefault(PushDefault.UPSTREAM).call());
979 		}
980 	}
981 
982 	/**
983 	 * Check that remote.pushDefault overrides branch.<name>.remote
984 	 *
985 	 * @throws Exception
986 	 */
987 	@Test
988 	public void testRemotePushDefault() throws Exception {
989 		try (Git git = new Git(db);
990 				Git git2 = new Git(createBareRepository())) {
991 			StoredConfig config = git.getRepository().getConfig();
992 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
993 			URIish uri = new URIish(
994 					git2.getRepository().getDirectory().toURI().toURL());
995 			remoteConfig.addURI(uri);
996 			remoteConfig.addFetchRefSpec(
997 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
998 			remoteConfig.update(config);
999 			config.setString("remote", null, "pushDefault", "origin");
1000 			config.save();
1001 
1002 			writeTrashFile("f", "content of f");
1003 			git.add().addFilepattern("f").call();
1004 			git.commit().setMessage("adding f").call();
1005 
1006 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
1007 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
1008 
1009 			config = git.getRepository().getConfig();
1010 			config.setString("branch", "branchtopush", "remote", "test");
1011 			config.setString("branch", "branchtopush", "merge",
1012 					"refs/heads/branchtopush");
1013 			config.save();
1014 
1015 			assertThrows(InvalidRefNameException.class, () -> git.push()
1016 					.setPushDefault(PushDefault.UPSTREAM).call());
1017 		}
1018 	}
1019 
1020 	/**
1021 	 * Check that ultimately we fall back to "origin".
1022 	 *
1023 	 * @throws Exception
1024 	 */
1025 	@Test
1026 	public void testDefaultRemote() throws Exception {
1027 		try (Git git = new Git(db);
1028 				Git git2 = new Git(createBareRepository())) {
1029 			StoredConfig config = git.getRepository().getConfig();
1030 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
1031 			URIish uri = new URIish(
1032 					git2.getRepository().getDirectory().toURI().toURL());
1033 			remoteConfig.addURI(uri);
1034 			remoteConfig.addFetchRefSpec(
1035 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
1036 			remoteConfig.update(config);
1037 			config.save();
1038 
1039 			writeTrashFile("f", "content of f");
1040 			git.add().addFilepattern("f").call();
1041 			git.commit().setMessage("adding f").call();
1042 
1043 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
1044 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
1045 
1046 			config = git.getRepository().getConfig();
1047 			config.setString("branch", "branchtopush", "merge",
1048 					"refs/heads/branchtopush");
1049 			config.save();
1050 
1051 			PushCommand cmd = git.push().setPushDefault(PushDefault.UPSTREAM);
1052 			TransportException e = assertThrows(TransportException.class,
1053 					() -> cmd.call());
1054 			assertEquals(NoRemoteRepositoryException.class,
1055 					e.getCause().getClass());
1056 			assertEquals("origin", cmd.getRemote());
1057 		}
1058 	}
1059 
1060 	/**
1061 	 * Check that a push without specifying a remote or mode or anything can
1062 	 * succeed if the git config is correct.
1063 	 *
1064 	 * @throws Exception
1065 	 */
1066 	@Test
1067 	public void testDefaultPush() throws Exception {
1068 		try (Git git = new Git(db);
1069 				Git git2 = new Git(createBareRepository())) {
1070 			StoredConfig config = git.getRepository().getConfig();
1071 			RemoteConfig remoteConfig = new RemoteConfig(config, "test");
1072 			URIish uri = new URIish(
1073 					git2.getRepository().getDirectory().toURI().toURL());
1074 			remoteConfig.addURI(uri);
1075 			remoteConfig.addFetchRefSpec(
1076 					new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
1077 			remoteConfig.update(config);
1078 			config.save();
1079 
1080 			writeTrashFile("f", "content of f");
1081 			git.add().addFilepattern("f").call();
1082 			RevCommit commit = git.commit().setMessage("adding f").call();
1083 
1084 			git.checkout().setName("not-pushed").setCreateBranch(true).call();
1085 			git.checkout().setName("branchtopush").setCreateBranch(true).call();
1086 
1087 			config = git.getRepository().getConfig();
1088 			config.setString("branch", "branchtopush", "remote", "test");
1089 			config.save();
1090 
1091 			assertEquals(null,
1092 					git2.getRepository().resolve("refs/heads/branchtopush"));
1093 			assertEquals(null,
1094 					git2.getRepository().resolve("refs/heads/not-pushed"));
1095 			assertEquals(null,
1096 					git2.getRepository().resolve("refs/heads/master"));
1097 			// Should use remote "test", push.default=current
1098 			PushCommand cmd = git.push();
1099 			cmd.call();
1100 			assertEquals("test", cmd.getRemote());
1101 			assertEquals(PushDefault.CURRENT, cmd.getPushDefault());
1102 			assertEquals(commit.getId(),
1103 					git2.getRepository().resolve("refs/heads/branchtopush"));
1104 			assertEquals(null,
1105 					git2.getRepository().resolve("refs/heads/not-pushed"));
1106 			assertEquals(null,
1107 					git2.getRepository().resolve("refs/heads/master"));
1108 			assertEquals(commit.getId(), git.getRepository()
1109 					.resolve("refs/remotes/origin/branchtopush"));
1110 		}
1111 	}
1112 
1113 	/**
1114 	 * Check that missing refs don't cause errors during push
1115 	 *
1116 	 * @throws Exception
1117 	 */
1118 	@Test
1119 	public void testPushAfterGC() throws Exception {
1120 		// create other repository
1121 		Repository db2 = createWorkRepository();
1122 		addRepoToClose(db2);
1123 
1124 		// setup the first repository
1125 		final StoredConfig config = db.getConfig();
1126 		RemoteConfig remoteConfig = new RemoteConfig(config, "test");
1127 		URIish uri = new URIish(db2.getDirectory().toURI().toURL());
1128 		remoteConfig.addURI(uri);
1129 		remoteConfig.update(config);
1130 		config.save();
1131 
1132 		try (Git git1 = new Git(db);
1133 				Git git2 = new Git(db2)) {
1134 			// push master (with a new commit) to the remote
1135 			git1.commit().setMessage("initial commit").call();
1136 
1137 			RefSpec spec = new RefSpec("refs/heads/*:refs/heads/*");
1138 			git1.push().setRemote("test").setRefSpecs(spec).call();
1139 
1140 			// create an unrelated ref and a commit on our remote
1141 			git2.branchCreate().setName("refs/heads/other").call();
1142 			git2.checkout().setName("refs/heads/other").call();
1143 
1144 			writeTrashFile("a", "content of a");
1145 			git2.add().addFilepattern("a").call();
1146 			RevCommit commit2 = git2.commit().setMessage("adding a").call();
1147 
1148 			// run a gc to ensure we have a bitmap index
1149 			Properties res = git1.gc().setExpire(null).call();
1150 			assertEquals(8, res.size());
1151 
1152 			// create another commit so we have something else to push
1153 			writeTrashFile("b", "content of b");
1154 			git1.add().addFilepattern("b").call();
1155 			RevCommit commit3 = git1.commit().setMessage("adding b").call();
1156 
1157 			try {
1158 				// Re-run the push.  Failure may happen here.
1159 				git1.push().setRemote("test").setRefSpecs(spec).call();
1160 			} catch (TransportException e) {
1161 				assertTrue("should be caused by a MissingObjectException", e
1162 						.getCause().getCause() instanceof MissingObjectException);
1163 				fail("caught MissingObjectException for a change we don't have");
1164 			}
1165 
1166 			// Remote will have both a and b.  Master will have only b
1167 			try {
1168 				db.resolve(commit2.getId().getName() + "^{commit}");
1169 				fail("id shouldn't exist locally");
1170 			} catch (MissingObjectException e) {
1171 				// we should get here
1172 			}
1173 			assertEquals(commit2.getId(),
1174 					db2.resolve(commit2.getId().getName() + "^{commit}"));
1175 			assertEquals(commit3.getId(),
1176 					db2.resolve(commit3.getId().getName() + "^{commit}"));
1177 		}
1178 	}
1179 
1180 	@Test
1181 	public void testPushWithLease() throws JGitInternalException, IOException,
1182 			GitAPIException, URISyntaxException {
1183 
1184 		// create other repository
1185 		Repository db2 = createWorkRepository();
1186 		addRepoToClose(db2);
1187 
1188 		// setup the first repository
1189 		final StoredConfig config = db.getConfig();
1190 		RemoteConfig remoteConfig = new RemoteConfig(config, "test");
1191 		URIish uri = new URIish(db2.getDirectory().toURI().toURL());
1192 		remoteConfig.addURI(uri);
1193 		remoteConfig.update(config);
1194 		config.save();
1195 
1196 		try (Git git1 = new Git(db)) {
1197 			// create one commit and push it
1198 			RevCommit commit = git1.commit().setMessage("initial commit").call();
1199 			git1.branchCreate().setName("initial").call();
1200 
1201 			RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x");
1202 			git1.push().setRemote("test").setRefSpecs(spec)
1203 					.call();
1204 
1205 			assertEquals(commit.getId(),
1206 					db2.resolve(commit.getId().getName() + "^{commit}"));
1207 			//now try to force-push a new commit, with a good lease
1208 
1209 			git1.commit().setMessage("second commit").call();
1210 			Iterable<PushResult> results =
1211 					git1.push().setRemote("test").setRefSpecs(spec)
1212 							.setRefLeaseSpecs(new RefLeaseSpec("refs/heads/x", "initial"))
1213 							.call();
1214 			for (PushResult result : results) {
1215 				RemoteRefUpdate update = result.getRemoteUpdate("refs/heads/x");
1216 				assertEquals(update.getStatus(), RemoteRefUpdate.Status.OK);
1217 			}
1218 
1219 			git1.commit().setMessage("third commit").call();
1220 			//now try to force-push a new commit, with a bad lease
1221 
1222 			results =
1223 					git1.push().setRemote("test").setRefSpecs(spec)
1224 							.setRefLeaseSpecs(new RefLeaseSpec("refs/heads/x", "initial"))
1225 							.call();
1226 			for (PushResult result : results) {
1227 				RemoteRefUpdate update = result.getRemoteUpdate("refs/heads/x");
1228 				assertEquals(update.getStatus(), RemoteRefUpdate.Status.REJECTED_REMOTE_CHANGED);
1229 			}
1230 		}
1231 	}
1232 }