init: allow specifying the initial branch name for the new repository

Add option --initial-branch/-b to InitCommand and the CLI init command.
This is the first step to implement support for the new option
init.defaultBranch. Both were added to git in release 2.28.

See https://git-scm.com/docs/git-init#Documentation/git-init.txt--bltbranch-namegt

Bug: 564794
Change-Id: Ia383b3f90b5549db80f99b2310450a7faf6bce4c
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
This commit is contained in:
Matthias Sohn 2021-01-25 01:54:03 +01:00
parent 64cb7148ac
commit cb8924a80d
8 changed files with 144 additions and 2 deletions

View File

@ -11,11 +11,14 @@
package org.eclipse.jgit.pgm; package org.eclipse.jgit.pgm;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import java.io.File; import java.io.File;
import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.CLIRepositoryTestCase; import org.eclipse.jgit.lib.CLIRepositoryTestCase;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.TemporaryFolder; import org.junit.rules.TemporaryFolder;
@ -54,4 +57,22 @@ public void testInitDirectory() throws Exception {
assertArrayEquals(expecteds, result); assertArrayEquals(expecteds, result);
} }
@Test
public void testInitDirectoryInitialBranch() throws Exception {
File workDirectory = tempFolder.getRoot();
File gitDirectory = new File(workDirectory, Constants.DOT_GIT);
String[] result = execute(
"git init -b main '" + workDirectory.getCanonicalPath() + "'");
String[] expecteds = new String[] {
"Initialized empty Git repository in "
+ gitDirectory.getCanonicalPath(),
"" };
assertArrayEquals(expecteds, result);
try (Repository repo = new FileRepository(gitDirectory)) {
assertEquals("refs/heads/main", repo.getFullBranch());
}
}
} }

View File

@ -432,6 +432,7 @@ usage_updateRef=reference to update
usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository usage_updateRemoteRefsFromAnotherRepository=Update remote refs from another repository
usage_useNameInsteadOfOriginToTrackUpstream=use <name> instead of 'origin' to track upstream usage_useNameInsteadOfOriginToTrackUpstream=use <name> instead of 'origin' to track upstream
usage_checkoutBranchAfterClone=check out named branch instead of remote's HEAD usage_checkoutBranchAfterClone=check out named branch instead of remote's HEAD
usage_initialBranch=initial branch in the newly created repository (default 'master')
usage_viewCommitHistory=View commit history usage_viewCommitHistory=View commit history
usage_orphan=Create a new orphan branch. The first commit made on this new branch will have no parents and it will be the root of a new history totally disconnected from other branches and commits. usage_orphan=Create a new orphan branch. The first commit made on this new branch will have no parents and it will be the root of a new history totally disconnected from other branches and commits.
usernameFor=Username for {0}: usernameFor=Username for {0}:

View File

@ -24,6 +24,7 @@
import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.pgm.internal.CLIText; import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.util.StringUtils;
import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option; import org.kohsuke.args4j.Option;
@ -32,6 +33,10 @@ class Init extends TextBuiltin {
@Option(name = "--bare", usage = "usage_CreateABareRepository") @Option(name = "--bare", usage = "usage_CreateABareRepository")
private boolean bare; private boolean bare;
@Option(name = "--initial-branch", aliases = { "-b" },
metaVar = "metaVar_branchName", usage = "usage_initialBranch")
private String branch;
@Argument(index = 0, metaVar = "metaVar_directory") @Argument(index = 0, metaVar = "metaVar_directory")
private String directory; private String directory;
@ -54,6 +59,9 @@ protected void run() {
} }
Repository repository; Repository repository;
try { try {
if (!StringUtils.isEmptyOrNull(branch)) {
command.setInitialBranch(branch);
}
repository = command.call().getRepository(); repository = command.call().getRepository();
outw.println(MessageFormat.format( outw.println(MessageFormat.format(
CLIText.get().initializedEmptyGitRepositoryIn, CLIText.get().initializedEmptyGitRepositoryIn,

View File

@ -9,6 +9,7 @@
*/ */
package org.eclipse.jgit.api; package org.eclipse.jgit.api;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -42,7 +43,23 @@ public void testInitRepository()
InitCommand command = new InitCommand(); InitCommand command = new InitCommand();
command.setDirectory(directory); command.setDirectory(directory);
try (Git git = command.call()) { try (Git git = command.call()) {
assertNotNull(git.getRepository()); Repository r = git.getRepository();
assertNotNull(r);
assertEquals("refs/heads/master", r.getFullBranch());
}
}
@Test
public void testInitRepositoryMainInitialBranch()
throws IOException, JGitInternalException, GitAPIException {
File directory = createTempDirectory("testInitRepository");
InitCommand command = new InitCommand();
command.setDirectory(directory);
command.setInitialBranch("main");
try (Git git = command.call()) {
Repository r = git.getRepository();
assertNotNull(r);
assertEquals("refs/heads/main", r.getFullBranch());
} }
} }
@ -72,6 +89,23 @@ public void testInitBareRepository() throws IOException,
Repository repository = git.getRepository(); Repository repository = git.getRepository();
assertNotNull(repository); assertNotNull(repository);
assertTrue(repository.isBare()); assertTrue(repository.isBare());
assertEquals("refs/heads/master", repository.getFullBranch());
}
}
@Test
public void testInitBareRepositoryMainInitialBranch()
throws IOException, JGitInternalException, GitAPIException {
File directory = createTempDirectory("testInitBareRepository");
InitCommand command = new InitCommand();
command.setDirectory(directory);
command.setBare(true);
command.setInitialBranch("main");
try (Git git = command.call()) {
Repository repository = git.getRepository();
assertNotNull(repository);
assertTrue(repository.isBare());
assertEquals("refs/heads/main", repository.getFullBranch());
} }
} }

View File

@ -15,6 +15,7 @@
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Constants;
@ -38,6 +39,8 @@ public class InitCommand implements Callable<Git> {
private FS fs; private FS fs;
private String initialBranch = Constants.MASTER;
/** /**
* {@inheritDoc} * {@inheritDoc}
* <p> * <p>
@ -87,6 +90,7 @@ public Git call() throws GitAPIException {
builder.setWorkTree(new File(dStr)); builder.setWorkTree(new File(dStr));
} }
} }
builder.setInitialBranch(initialBranch);
Repository repository = builder.build(); Repository repository = builder.build();
if (!repository.getObjectDatabase().exists()) if (!repository.getObjectDatabase().exists())
repository.create(bare); repository.create(bare);
@ -184,4 +188,23 @@ public InitCommand setFs(FS fs) {
this.fs = fs; this.fs = fs;
return this; return this;
} }
/**
* Set the initial branch of the new repository. If not specified
* ({@code null} or empty), fall back to the default name (currently
* master).
*
* @param branch
* initial branch name of the new repository
* @return {@code this}
* @throws InvalidRefNameException
* if the branch name is not valid
*
* @since 5.11
*/
public InitCommand setInitialBranch(String branch)
throws InvalidRefNameException {
this.initialBranch = branch;
return this;
}
} }

View File

@ -243,7 +243,7 @@ && getDirectory().getName().startsWith(".")) //$NON-NLS-1$
RefUpdate head = updateRef(Constants.HEAD); RefUpdate head = updateRef(Constants.HEAD);
head.disableRefLog(); head.disableRefLog();
head.link(Constants.R_HEADS + Constants.MASTER); head.link(Constants.R_HEADS + getInitialBranch());
final boolean fileMode; final boolean fileMode;
if (getFS().supportsExecute()) { if (getFS().supportsExecute()) {

View File

@ -28,6 +28,8 @@
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import org.eclipse.jgit.annotations.NonNull;
import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
@ -38,6 +40,7 @@
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO; import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.RawParseUtils;
import org.eclipse.jgit.util.StringUtils;
import org.eclipse.jgit.util.SystemReader; import org.eclipse.jgit.util.SystemReader;
/** /**
@ -107,6 +110,8 @@ private static File getSymRef(File workTree, File dotGit, FS fs)
private File workTree; private File workTree;
private String initialBranch = Constants.MASTER;
/** Directories limiting the search for a Git repository. */ /** Directories limiting the search for a Git repository. */
private List<File> ceilingDirectories; private List<File> ceilingDirectories;
@ -349,6 +354,43 @@ public File getIndexFile() {
return indexFile; return indexFile;
} }
/**
* Set the initial branch of the new repository. If not specified
* ({@code null} or empty), fall back to the default name (currently
* master).
*
* @param branch
* initial branch name of the new repository. If {@code null} or
* empty the configured default branch will be used.
* @return {@code this}
* @throws InvalidRefNameException
* if the branch name is not valid
*
* @since 5.11
*/
public B setInitialBranch(String branch) throws InvalidRefNameException {
if (StringUtils.isEmptyOrNull(branch)) {
this.initialBranch = Constants.MASTER;
} else {
if (!Repository.isValidRefName(Constants.R_HEADS + branch)) {
throw new InvalidRefNameException(MessageFormat
.format(JGitText.get().branchNameInvalid, branch));
}
this.initialBranch = branch;
}
return self();
}
/**
* Get the initial branch of the new repository.
*
* @return the initial branch of the new repository.
* @since 5.11
*/
public @NonNull String getInitialBranch() {
return initialBranch;
}
/** /**
* Read standard Git environment variables and configure from those. * Read standard Git environment variables and configure from those.
* <p> * <p>

View File

@ -127,6 +127,8 @@ public static ListenerList getGlobalListenerList() {
/** If not bare, the index file caching the working file states. */ /** If not bare, the index file caching the working file states. */
private final File indexFile; private final File indexFile;
private final String initialBranch;
/** /**
* Initialize a new repository instance. * Initialize a new repository instance.
* *
@ -138,6 +140,7 @@ protected Repository(BaseRepositoryBuilder options) {
fs = options.getFS(); fs = options.getFS();
workTree = options.getWorkTree(); workTree = options.getWorkTree();
indexFile = options.getIndexFile(); indexFile = options.getIndexFile();
initialBranch = options.getInitialBranch();
} }
/** /**
@ -1033,6 +1036,16 @@ public String getBranch() throws IOException {
return null; return null;
} }
/**
* Get the initial branch name of a new repository
*
* @return the initial branch name of a new repository
* @since 5.11
*/
protected @NonNull String getInitialBranch() {
return initialBranch;
}
/** /**
* Objects known to exist but not expressed by {@link #getAllRefs()}. * Objects known to exist but not expressed by {@link #getAllRefs()}.
* <p> * <p>