diff options
author | Thomas Wolf <thomas.wolf@paranor.ch> | 2022-02-10 19:04:21 +0100 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2022-02-14 10:45:15 +0100 |
commit | 855a734875c2f178a8adfd0789527afc8754117f (patch) | |
tree | b488222bb7573e9c06862b7bf1b2832ae92c8eeb | |
parent | 504001228ba6a43179a72e56ce03aa217c2bdea4 (diff) | |
download | jgit-855a734875c2f178a8adfd0789527afc8754117f.tar.gz jgit-855a734875c2f178a8adfd0789527afc8754117f.zip |
PushCommand: determine remote from git config if not given
Add ConfigConstants and expose branch.<name>.pushRemote in the
BranchConfig. Use the branch configuration and remote.pushDefault
if no remote is given explicitly. If nothing is configured, fall
back to "origin".
Bug: 578676
Change-Id: I6bb141ff02c8b04980ec34b26ef248b72614c3c9
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
4 files changed, 229 insertions, 3 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java index 3f8921c152..1a1f5b487e 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PushCommandTest.java @@ -26,6 +26,7 @@ import org.eclipse.jgit.api.errors.InvalidRefNameException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.TransportException; import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.errors.NoRemoteRepositoryException; import org.eclipse.jgit.hooks.PrePushHook; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; @@ -633,8 +634,7 @@ public class PushCommandTest extends RepositoryTestCase { config = git.getRepository().getConfig(); // Don't set remote, it'll default to "origin". Configure a - // different - // branch name; should be ignored. + // different branch name; should be ignored. config.setString("branch", "branchtopush", "merge", "refs/heads/upstreambranch"); config.save(); @@ -853,6 +853,176 @@ public class PushCommandTest extends RepositoryTestCase { } /** + * Check that branch.<name>.pushRemote overrides anything else. + * + * @throws Exception + */ + @Test + public void testBranchPushRemote() throws Exception { + try (Git git = new Git(db); + Git git2 = new Git(createBareRepository())) { + StoredConfig config = git.getRepository().getConfig(); + RemoteConfig remoteConfig = new RemoteConfig(config, "test"); + URIish uri = new URIish( + git2.getRepository().getDirectory().toURI().toURL()); + remoteConfig.addURI(uri); + remoteConfig.addFetchRefSpec( + new RefSpec("+refs/heads/*:refs/remotes/origin/*")); + remoteConfig.update(config); + config.setString("remote", null, "pushDefault", "test"); + config.save(); + + writeTrashFile("f", "content of f"); + git.add().addFilepattern("f").call(); + git.commit().setMessage("adding f").call(); + + git.checkout().setName("not-pushed").setCreateBranch(true).call(); + git.checkout().setName("branchtopush").setCreateBranch(true).call(); + + config = git.getRepository().getConfig(); + config.setString("branch", "branchtopush", "remote", "test"); + config.setString("branch", "branchtopush", "pushremote", "origin"); + config.setString("branch", "branchtopush", "merge", + "refs/heads/branchtopush"); + config.save(); + + assertThrows(InvalidRefNameException.class, () -> git.push() + .setPushDefault(PushDefault.UPSTREAM).call()); + } + } + + /** + * Check that remote.pushDefault overrides branch.<name>.remote + * + * @throws Exception + */ + @Test + public void testRemotePushDefault() throws Exception { + try (Git git = new Git(db); + Git git2 = new Git(createBareRepository())) { + StoredConfig config = git.getRepository().getConfig(); + RemoteConfig remoteConfig = new RemoteConfig(config, "test"); + URIish uri = new URIish( + git2.getRepository().getDirectory().toURI().toURL()); + remoteConfig.addURI(uri); + remoteConfig.addFetchRefSpec( + new RefSpec("+refs/heads/*:refs/remotes/origin/*")); + remoteConfig.update(config); + config.setString("remote", null, "pushDefault", "origin"); + config.save(); + + writeTrashFile("f", "content of f"); + git.add().addFilepattern("f").call(); + git.commit().setMessage("adding f").call(); + + git.checkout().setName("not-pushed").setCreateBranch(true).call(); + git.checkout().setName("branchtopush").setCreateBranch(true).call(); + + config = git.getRepository().getConfig(); + config.setString("branch", "branchtopush", "remote", "test"); + config.setString("branch", "branchtopush", "merge", + "refs/heads/branchtopush"); + config.save(); + + assertThrows(InvalidRefNameException.class, () -> git.push() + .setPushDefault(PushDefault.UPSTREAM).call()); + } + } + + /** + * Check that ultimately we fall back to "origin". + * + * @throws Exception + */ + @Test + public void testDefaultRemote() throws Exception { + try (Git git = new Git(db); + Git git2 = new Git(createBareRepository())) { + StoredConfig config = git.getRepository().getConfig(); + RemoteConfig remoteConfig = new RemoteConfig(config, "test"); + URIish uri = new URIish( + git2.getRepository().getDirectory().toURI().toURL()); + remoteConfig.addURI(uri); + remoteConfig.addFetchRefSpec( + new RefSpec("+refs/heads/*:refs/remotes/origin/*")); + remoteConfig.update(config); + config.save(); + + writeTrashFile("f", "content of f"); + git.add().addFilepattern("f").call(); + git.commit().setMessage("adding f").call(); + + git.checkout().setName("not-pushed").setCreateBranch(true).call(); + git.checkout().setName("branchtopush").setCreateBranch(true).call(); + + config = git.getRepository().getConfig(); + config.setString("branch", "branchtopush", "merge", + "refs/heads/branchtopush"); + config.save(); + + PushCommand cmd = git.push().setPushDefault(PushDefault.UPSTREAM); + TransportException e = assertThrows(TransportException.class, + () -> cmd.call()); + assertEquals(NoRemoteRepositoryException.class, + e.getCause().getClass()); + assertEquals("origin", cmd.getRemote()); + } + } + + /** + * Check that a push without specifying a remote or mode or anything can + * succeed if the git config is correct. + * + * @throws Exception + */ + @Test + public void testDefaultPush() throws Exception { + try (Git git = new Git(db); + Git git2 = new Git(createBareRepository())) { + StoredConfig config = git.getRepository().getConfig(); + RemoteConfig remoteConfig = new RemoteConfig(config, "test"); + URIish uri = new URIish( + git2.getRepository().getDirectory().toURI().toURL()); + remoteConfig.addURI(uri); + remoteConfig.addFetchRefSpec( + new RefSpec("+refs/heads/*:refs/remotes/origin/*")); + remoteConfig.update(config); + config.save(); + + writeTrashFile("f", "content of f"); + git.add().addFilepattern("f").call(); + RevCommit commit = git.commit().setMessage("adding f").call(); + + git.checkout().setName("not-pushed").setCreateBranch(true).call(); + git.checkout().setName("branchtopush").setCreateBranch(true).call(); + + config = git.getRepository().getConfig(); + config.setString("branch", "branchtopush", "remote", "test"); + config.save(); + + assertEquals(null, + git2.getRepository().resolve("refs/heads/branchtopush")); + assertEquals(null, + git2.getRepository().resolve("refs/heads/not-pushed")); + assertEquals(null, + git2.getRepository().resolve("refs/heads/master")); + // Should use remote "test", push.default=current + PushCommand cmd = git.push(); + cmd.call(); + assertEquals("test", cmd.getRemote()); + assertEquals(PushDefault.CURRENT, cmd.getPushDefault()); + assertEquals(commit.getId(), + git2.getRepository().resolve("refs/heads/branchtopush")); + assertEquals(null, + git2.getRepository().resolve("refs/heads/not-pushed")); + assertEquals(null, + git2.getRepository().resolve("refs/heads/master")); + assertEquals(commit.getId(), git.getRepository() + .resolve("refs/remotes/origin/branchtopush")); + } + } + + /** * Check that missing refs don't cause errors during push * * @throws Exception diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java index 0deb7ed29c..4f57f35127 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java @@ -33,6 +33,7 @@ import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.lib.BranchConfig; import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ProgressMonitor; @@ -58,7 +59,7 @@ import org.eclipse.jgit.transport.Transport; public class PushCommand extends TransportCommand<PushCommand, Iterable<PushResult>> { - private String remote = Constants.DEFAULT_REMOTE_NAME; + private String remote; private final List<RefSpec> refSpecs; @@ -114,6 +115,7 @@ public class PushCommand extends try { Config config = repo.getConfig(); + remote = determineRemote(config, remote); if (refSpecs.isEmpty()) { RemoteConfig rc = new RemoteConfig(config, getRemote()); @@ -181,6 +183,34 @@ public class PushCommand extends return pushResults; } + private String determineRemote(Config config, String remoteName) + throws IOException { + if (remoteName != null) { + return remoteName; + } + Ref head = repo.exactRef(Constants.HEAD); + String effectiveRemote = null; + BranchConfig branchCfg = null; + if (head != null && head.isSymbolic()) { + String currentBranch = head.getLeaf().getName(); + branchCfg = new BranchConfig(config, + Repository.shortenRefName(currentBranch)); + effectiveRemote = branchCfg.getPushRemote(); + } + if (effectiveRemote == null) { + effectiveRemote = config.getString( + ConfigConstants.CONFIG_REMOTE_SECTION, null, + ConfigConstants.CONFIG_KEY_PUSH_DEFAULT); + if (effectiveRemote == null && branchCfg != null) { + effectiveRemote = branchCfg.getRemote(); + } + } + if (effectiveRemote == null) { + effectiveRemote = Constants.DEFAULT_REMOTE_NAME; + } + return effectiveRemote; + } + private String getCurrentBranch() throws IOException, DetachedHeadException { Ref head = repo.exactRef(Constants.HEAD); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java index 6da6f1204a..aa613d07eb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchConfig.java @@ -138,6 +138,18 @@ public class BranchConfig { } /** + * Get the remote this branch is configured to push to. + * + * @return the remote this branch is configured to push to, or {@code null} + * if not defined + * @since 6.1 + */ + public String getPushRemote() { + return config.getString(ConfigConstants.CONFIG_BRANCH_SECTION, + branchName, ConfigConstants.CONFIG_KEY_PUSH_REMOTE); + } + + /** * Get the name of the upstream branch as it is called on the remote * * @return the name of the upstream branch as it is called on the remote, or diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java index 205999f8c9..42d8aa5447 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java @@ -329,6 +329,20 @@ public final class ConfigConstants { /** The "remote" key */ public static final String CONFIG_KEY_REMOTE = "remote"; + /** + * The "pushRemote" key. + * + * @since 6.1 + */ + public static final String CONFIG_KEY_PUSH_REMOTE = "pushRemote"; + + /** + * The "pushDefault" key. + * + * @since 6.1 + */ + public static final String CONFIG_KEY_PUSH_DEFAULT = "pushDefault"; + /** The "merge" key */ public static final String CONFIG_KEY_MERGE = "merge"; |