Allow explicit configuration of git directory in InitCommand

Native git's "init" command allows to specify the location of the .git
folder with the option "--separate-git-dir". This allows for example to
setup repositories with a non-standard layout. E.g. .git folder under
/repos/a.git and the worktree under /home/git/a. Both directories
contain pointers to the other side: /repos/a.git/config contains
core.worktree=/home/git/a . And /home/git/a/.git is a file containing
"gitdir: /repos/a.git". This commit adds that option to InitCommand.
This feature is needed to support the new submodule layout where the
.git folder of the submodules is under .git/modules/<submodule>.

Change-Id: I0208f643808bf8f28e2c979d6e33662607775f1f
This commit is contained in:
Christian Halstrick 2014-12-10 17:42:42 +01:00 committed by Matthias Sohn
parent ca7c928eae
commit 03e860a7b7
7 changed files with 233 additions and 14 deletions

View File

@ -90,6 +90,7 @@ public MockSystemReader() {
init(Constants.GIT_AUTHOR_EMAIL_KEY);
init(Constants.GIT_COMMITTER_NAME_KEY);
init(Constants.GIT_COMMITTER_EMAIL_KEY);
setProperty(Constants.OS_USER_DIR, ".");
userGitConfig = new MockConfig(null, null);
systemGitConfig = new MockConfig(null, null);
setCurrentPlatform();

View File

@ -43,6 +43,7 @@
package org.eclipse.jgit.api;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
@ -50,8 +51,12 @@
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.junit.MockSystemReader;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.SystemReader;
import org.junit.Before;
import org.junit.Test;
@ -101,4 +106,109 @@ public void testInitBareRepository() throws IOException,
assertNotNull(repository);
assertTrue(repository.isBare());
}
// non-bare repos where gitDir and directory is set. Same as
// "git init --separate-git-dir /tmp/a /tmp/b"
@Test
public void testInitWithExplicitGitDir() throws IOException,
JGitInternalException, GitAPIException {
File wt = createTempDirectory("testInitRepositoryWT");
File gitDir = createTempDirectory("testInitRepositoryGIT");
InitCommand command = new InitCommand();
command.setDirectory(wt);
command.setGitDir(gitDir);
Repository repository = command.call().getRepository();
addRepoToClose(repository);
assertNotNull(repository);
assertEqualsFile(wt, repository.getWorkTree());
assertEqualsFile(gitDir, repository.getDirectory());
}
// non-bare repos where only gitDir is set. Same as
// "git init --separate-git-dir /tmp/a"
@Test
public void testInitWithOnlyExplicitGitDir() throws IOException,
JGitInternalException, GitAPIException {
MockSystemReader reader = (MockSystemReader) SystemReader.getInstance();
reader.setProperty(Constants.OS_USER_DIR, getTemporaryDirectory()
.getAbsolutePath());
File gitDir = createTempDirectory("testInitRepository/.git");
InitCommand command = new InitCommand();
command.setGitDir(gitDir);
Repository repository = command.call().getRepository();
addRepoToClose(repository);
assertNotNull(repository);
assertEqualsFile(gitDir, repository.getDirectory());
assertEqualsFile(new File(reader.getProperty("user.dir")),
repository.getWorkTree());
}
// Bare repos where gitDir and directory is set will only work if gitDir and
// directory is pointing to same dir. Same as
// "git init --bare --separate-git-dir /tmp/a /tmp/b"
// (works in native git but I guess that's more a bug)
@Test(expected = IllegalStateException.class)
public void testInitBare_DirAndGitDirMustBeEqual() throws IOException,
JGitInternalException, GitAPIException {
File gitDir = createTempDirectory("testInitRepository.git");
InitCommand command = new InitCommand();
command.setBare(true);
command.setDirectory(gitDir);
command.setGitDir(new File(gitDir, ".."));
command.call();
}
// If neither directory nor gitDir is set in a non-bare repo make sure
// worktree and gitDir are set correctly. Standard case. Same as
// "git init"
@Test
public void testInitWithDefaultsNonBare() throws JGitInternalException,
GitAPIException, IOException {
MockSystemReader reader = (MockSystemReader) SystemReader.getInstance();
reader.setProperty(Constants.OS_USER_DIR, getTemporaryDirectory()
.getAbsolutePath());
InitCommand command = new InitCommand();
command.setBare(false);
Repository repository = command.call().getRepository();
addRepoToClose(repository);
assertNotNull(repository);
assertEqualsFile(new File(reader.getProperty("user.dir"), ".git"),
repository.getDirectory());
assertEqualsFile(new File(reader.getProperty("user.dir")),
repository.getWorkTree());
}
// If neither directory nor gitDir is set in a bare repo make sure
// worktree and gitDir are set correctly. Standard case. Same as
// "git init --bare"
@Test(expected = NoWorkTreeException.class)
public void testInitWithDefaultsBare() throws JGitInternalException,
GitAPIException, IOException {
MockSystemReader reader = (MockSystemReader) SystemReader.getInstance();
reader.setProperty(Constants.OS_USER_DIR, getTemporaryDirectory()
.getAbsolutePath());
InitCommand command = new InitCommand();
command.setBare(true);
Repository repository = command.call().getRepository();
addRepoToClose(repository);
assertNotNull(repository);
assertEqualsFile(new File(reader.getProperty("user.dir")),
repository.getDirectory());
assertNull(repository.getWorkTree());
}
// In a non-bare repo when directory and gitDir is set then they shouldn't
// point to the same dir. Same as
// "git init --separate-git-dir /tmp/a /tmp/a"
// (works in native git but I guess that's more a bug)
@Test(expected = IllegalStateException.class)
public void testInitNonBare_GitdirAndDirShouldntBeSame()
throws JGitInternalException, GitAPIException, IOException {
File gitDir = createTempDirectory("testInitRepository.git");
InitCommand command = new InitCommand();
command.setBare(false);
command.setGitDir(gitDir);
command.setDirectory(gitDir);
command.call().getRepository();
}
}

View File

@ -249,6 +249,8 @@ indexFileIsInUse=Index file is in use
indexFileIsTooLargeForJgit=Index file is too large for jgit
indexSignatureIsInvalid=Index signature is invalid: {0}
indexWriteException=Modified index could not be written
initFailedBareRepoDifferentDirs=When initializing a bare repo with directory {0} and separate git-dir {1} specified both folders must point to the same location
initFailedNonBareRepoSameDirs=When initializing a non-bare repo with directory {0} and separate git-dir {1} specified both folders should not point to the same location
inMemoryBufferLimitExceeded=In-memory buffer limit exceeded
inputStreamMustSupportMark=InputStream must support mark()
integerValueOutOfRange=Integer value {0}.{1} out of range

View File

@ -44,13 +44,16 @@
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.concurrent.Callable;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryBuilder;
import org.eclipse.jgit.util.SystemReader;
/**
* Create an empty git repository or reinitalize an existing one
@ -61,6 +64,8 @@
public class InitCommand implements Callable<Git> {
private File directory;
private File gitDir;
private boolean bare;
/**
@ -74,18 +79,36 @@ public Git call() throws GitAPIException {
if (bare)
builder.setBare();
builder.readEnvironment();
if (gitDir != null)
builder.setGitDir(gitDir);
else
gitDir = builder.getGitDir();
if (directory != null) {
File d = directory;
if (!bare)
d = new File(d, Constants.DOT_GIT);
builder.setGitDir(d);
if (bare)
builder.setGitDir(directory);
else {
builder.setWorkTree(directory);
if (gitDir == null)
builder.setGitDir(new File(directory, Constants.DOT_GIT));
}
} else if (builder.getGitDir() == null) {
File d = new File("."); //$NON-NLS-1$
if (d.getParentFile() != null)
d = d.getParentFile();
String dStr = SystemReader.getInstance()
.getProperty("user.dir"); //$NON-NLS-1$
if (dStr == null)
dStr = "."; //$NON-NLS-1$
File d = new File(dStr);
if (!bare)
d = new File(d, Constants.DOT_GIT);
builder.setGitDir(d);
} else {
// directory was not set but gitDir was set
if (!bare) {
String dStr = SystemReader.getInstance().getProperty(
"user.dir"); //$NON-NLS-1$
if (dStr == null)
dStr = "."; //$NON-NLS-1$
builder.setWorkTree(new File(dStr));
}
}
Repository repository = builder.build();
if (!repository.getObjectDatabase().exists())
@ -103,20 +126,67 @@ public Git call() throws GitAPIException {
* @param directory
* the directory to init to
* @return this instance
* @throws IllegalStateException
* if the combination of directory, gitDir and bare is illegal.
* E.g. if for a non-bare repository directory and gitDir point
* to the same directory of if for a bare repository both
* directory and gitDir are specified
*/
public InitCommand setDirectory(File directory) {
public InitCommand setDirectory(File directory)
throws IllegalStateException {
validateDirs(directory, gitDir, bare);
this.directory = directory;
return this;
}
/**
* @param bare
* whether the repository is bare or not
* @param gitDir
* the repository meta directory
* @return this instance
* @throws IllegalStateException
* if the combination of directory, gitDir and bare is illegal.
* E.g. if for a non-bare repository directory and gitDir point
* to the same directory of if for a bare repository both
* directory and gitDir are specified
* @since 3.6
*/
public InitCommand setBare(boolean bare) {
this.bare = bare;
public InitCommand setGitDir(File gitDir)
throws IllegalStateException {
validateDirs(directory, gitDir, bare);
this.gitDir = gitDir;
return this;
}
private static void validateDirs(File directory, File gitDir, boolean bare)
throws IllegalStateException {
if (directory != null) {
if (bare) {
if (gitDir != null && !gitDir.equals(directory))
throw new IllegalStateException(MessageFormat.format(
JGitText.get().initFailedBareRepoDifferentDirs,
gitDir, directory));
} else {
if (gitDir != null && gitDir.equals(directory))
throw new IllegalStateException(MessageFormat.format(
JGitText.get().initFailedNonBareRepoSameDirs,
gitDir, directory));
}
}
}
/**
* @param bare
* whether the repository is bare or not
* @throws IllegalStateException
* if the combination of directory, gitDir and bare is illegal.
* E.g. if for a non-bare repository directory and gitDir point
* to the same directory of if for a bare repository both
* directory and gitDir are specified
* @return this instance
*/
public InitCommand setBare(boolean bare) {
validateDirs(directory, gitDir, bare);
this.bare = bare;
return this;
}
}

View File

@ -308,6 +308,8 @@ public static JGitText get() {
/***/ public String indexFileIsTooLargeForJgit;
/***/ public String indexSignatureIsInvalid;
/***/ public String indexWriteException;
/***/ public String initFailedBareRepoDifferentDirs;
/***/ public String initFailedNonBareRepoSameDirs;
/***/ public String inMemoryBufferLimitExceeded;
/***/ public String inputStreamMustSupportMark;
/***/ public String integerValueOutOfRange;

View File

@ -273,7 +273,8 @@ public void create(boolean bare) throws IOException {
ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_HIDEDOTFILES,
HideDotFiles.DOTGITONLY);
if (hideDotFiles != HideDotFiles.FALSE && !isBare())
if (hideDotFiles != HideDotFiles.FALSE && !isBare()
&& getDirectory().getName().startsWith(".")) //$NON-NLS-1$
getFS().setHidden(getDirectory(), true);
refs.create();
objectDatabase.create();
@ -329,6 +330,25 @@ public void create(boolean bare) throws IOException {
// Java has no other way
cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_PRECOMPOSEUNICODE, true);
if (!bare) {
File workTree = getWorkTree();
if (!getDirectory().getParentFile().equals(workTree)) {
cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_WORKTREE, getWorkTree()
.getAbsolutePath());
LockFile dotGitLockFile = new LockFile(new File(workTree,
Constants.DOT_GIT), getFS());
try {
if (dotGitLockFile.lock()) {
dotGitLockFile.write(Constants.encode(Constants.GITDIR
+ getDirectory().getAbsolutePath()));
dotGitLockFile.commit();
}
} finally {
dotGitLockFile.unlock();
}
}
}
cfg.save();
}

View File

@ -272,7 +272,14 @@ public final class Constants {
*/
public static final String INFO_EXCLUDE = "info/exclude";
/** The environment variable that contains the system user name */
/**
* The system property that contains the system user name
*
* @since 3.6
*/
public static final String OS_USER_DIR = "user.dir";
/** The system property that contains the system user name */
public static final String OS_USER_NAME_KEY = "user.name";
/** The environment variable that contains the author's name */
@ -358,6 +365,13 @@ public final class Constants {
/** Name of the .git/shallow file */
public static final String SHALLOW = "shallow";
/**
* Prefix of the first line in a ".git" file
*
* @since 3.6
*/
public static final String GITDIR = "gitdir: ";
/**
* Create a new digest function for objects.
*