]> source.dussan.org Git - jgit.git/commitdiff
Fix push to repo with non-fetched refs 94/21094/6
authorJean-Jacques Lafay <jeanjacques.lafay@gmail.com>
Fri, 25 Apr 2014 21:13:25 +0000 (16:13 -0500)
committerMatthias Sohn <matthias.sohn@sap.com>
Wed, 30 Apr 2014 21:43:44 +0000 (17:43 -0400)
When JGit uses bitmaps (which is the case after a gc), the push command
doesn't go through the code where MissingObjectExceptions are caught
for remote objects not found locally.

Fixed by removing earlier non-locally-found remote objects.

This was seen withing gerrit, see:
https://code.google.com/p/gerrit/issues/detail?id=2025

Bug: 426044
Change-Id: Ieda718a0530e3680036edfa0963ab88fdd1362c0
Signed-off-by: Jean-Jacques Lafay <jeanjacques.lafay@gmail.com>
Signed-off-by: Doug Kelly <dougk.ff7@gmail.com>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java

index 7f20bb8f1e52f9d9a86fb9275132d0a91e350990..19f074ea550f3ee05c8c9666b9f4b2cb1d4165e7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010, Chris Aniszczyk <caniszczyk@gmail.com>
+ * Copyright (C) 2010, 2014 Chris Aniszczyk <caniszczyk@gmail.com>
  * and other copyright owners as documented in the project's IP log.
  *
  * This program and the accompanying materials are made available
@@ -44,13 +44,16 @@ package org.eclipse.jgit.api;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
+import java.util.Properties;
 
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.api.errors.TransportException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.lib.Ref;
@@ -268,4 +271,70 @@ public class PushCommandTest extends RepositoryTestCase {
                assertEquals(null, git2.getRepository().resolve("refs/heads/master"));
 
        }
+
+       /**
+        * Check that missing refs don't cause errors during push
+        *
+        * @throws Exception
+        */
+       @Test
+       public void testPushAfterGC() throws Exception {
+               // create other repository
+               Repository db2 = createWorkRepository();
+
+               // setup the first repository
+               final StoredConfig config = db.getConfig();
+               RemoteConfig remoteConfig = new RemoteConfig(config, "test");
+               URIish uri = new URIish(db2.getDirectory().toURI().toURL());
+               remoteConfig.addURI(uri);
+               remoteConfig.update(config);
+               config.save();
+
+               Git git1 = new Git(db);
+               Git git2 = new Git(db2);
+
+               // push master (with a new commit) to the remote
+               git1.commit().setMessage("initial commit").call();
+
+               RefSpec spec = new RefSpec("refs/heads/*:refs/heads/*");
+               git1.push().setRemote("test").setRefSpecs(spec).call();
+
+               // create an unrelated ref and a commit on our remote
+               git2.branchCreate().setName("refs/heads/other").call();
+               git2.checkout().setName("refs/heads/other").call();
+
+               writeTrashFile("a", "content of a");
+               git2.add().addFilepattern("a").call();
+               RevCommit commit2 = git2.commit().setMessage("adding a").call();
+
+               // run a gc to ensure we have a bitmap index
+               Properties res = git1.gc().setExpire(null).call();
+               assertEquals(7, res.size());
+
+               // create another commit so we have something else to push
+               writeTrashFile("b", "content of b");
+               git1.add().addFilepattern("b").call();
+               RevCommit commit3 = git1.commit().setMessage("adding b").call();
+
+               try {
+                       // Re-run the push.  Failure may happen here.
+                       git1.push().setRemote("test").setRefSpecs(spec).call();
+               } catch (TransportException e) {
+                       assertTrue("should be caused by a MissingObjectException", e
+                                       .getCause().getCause() instanceof MissingObjectException);
+                       fail("caught MissingObjectException for a change we don't have");
+               }
+
+               // Remote will have both a and b.  Master will have only b
+               try {
+                       db.resolve(commit2.getId().getName() + "^{commit}");
+                       fail("id shouldn't exist locally");
+               } catch (MissingObjectException e) {
+                       // we should get here
+               }
+               assertEquals(commit2.getId(),
+                               db2.resolve(commit2.getId().getName() + "^{commit}"));
+               assertEquals(commit3.getId(),
+                               db2.resolve(commit3.getId().getName() + "^{commit}"));
+       }
 }
index def6033b8b5281624a2afdd7d53804c7cfca212e..e367ab44c963437dc44e8c37bc42b5ba328ad60c 100644 (file)
@@ -283,8 +283,12 @@ public abstract class BasePackPushConnection extends BasePackConnection implemen
                                local.newObjectReader());
                try {
 
-                       for (final Ref r : getRefs())
-                               remoteObjects.add(r.getObjectId());
+                       for (final Ref r : getRefs()) {
+                               // only add objects that we actually have
+                               ObjectId oid = r.getObjectId();
+                               if (local.hasObject(oid))
+                                       remoteObjects.add(oid);
+                       }
                        remoteObjects.addAll(additionalHaves);
                        for (final RemoteRefUpdate r : refUpdates.values()) {
                                if (!ObjectId.zeroId().equals(r.getNewObjectId()))