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>
This commit is contained in:
Thomas Wolf 2022-02-10 19:04:21 +01:00 committed by Matthias Sohn
parent 504001228b
commit 855a734875
4 changed files with 229 additions and 3 deletions

View File

@ -26,6 +26,7 @@
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 void testPushDefaultSimpleTriangular() throws Exception {
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();
@ -852,6 +852,176 @@ public void testPushDefaultFromConfigDefault() throws Exception {
}
}
/**
* 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
*

View File

@ -33,6 +33,7 @@
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 @@
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 Iterable<PushResult> call() throws GitAPIException,
try {
Config config = repo.getConfig();
remote = determineRemote(config, remote);
if (refSpecs.isEmpty()) {
RemoteConfig rc = new RemoteConfig(config,
getRemote());
@ -181,6 +183,34 @@ public Iterable<PushResult> call() throws GitAPIException,
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);

View File

@ -137,6 +137,18 @@ public String getRemote() {
branchName, ConfigConstants.CONFIG_KEY_REMOTE);
}
/**
* 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
*

View File

@ -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";