]> source.dussan.org Git - jgit.git/commitdiff
Allow explicit configuration of git directory in InitCommand 33/37833/7
authorChristian Halstrick <christian.halstrick@sap.com>
Wed, 10 Dec 2014 16:42:42 +0000 (17:42 +0100)
committerMatthias Sohn <matthias.sohn@sap.com>
Sun, 14 Dec 2014 23:22:50 +0000 (00:22 +0100)
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

org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/InitCommandTest.java
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java
org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java

index deca341067459c01a0ab90f0e27178534277fdb9..3d21f9f8adf0f9afe0f3f565b1da578e179bba2f 100644 (file)
@@ -90,6 +90,7 @@ public class MockSystemReader extends SystemReader {
                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();
index 3296717c0ec63bebeb9b50e5b01bc0c0d4fc503b..e8502237627853d1a43d13595c738362dc120db6 100644 (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 java.io.IOException;
 
 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 class InitCommandTest extends RepositoryTestCase {
                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();
+       }
 }
index 76c709422e7ffaba3bb3ac4cd9e3332e62b6aa15..a753188e888dcf5f7050d0455d879e40225e4a08 100644 (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
index bf43e90d4285b822fcb403c669e1457eb165a6b2..37a788e85cf9074f3d9424b9f5cf425eb831a439 100644 (file)
@@ -44,13 +44,16 @@ package org.eclipse.jgit.api;
 
 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 @@ import org.eclipse.jgit.lib.RepositoryBuilder;
 public class InitCommand implements Callable<Git> {
        private File directory;
 
+       private File gitDir;
+
        private boolean bare;
 
        /**
@@ -74,18 +79,36 @@ public class InitCommand implements Callable<Git> {
                        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 class InitCommand implements Callable<Git> {
         * @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 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 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;
        }
-
 }
index d1f0deec9d48656572bd96a3a3129bf35f02e2eb..65272fb0bda6e49d663a2097376b1cd67a70e862 100644 (file)
@@ -308,6 +308,8 @@ public class JGitText extends TranslationBundle {
        /***/ public String indexFileIsTooLargeForJgit;
        /***/ public String indexSignatureIsInvalid;
        /***/ public String indexWriteException;
+       /***/ public String initFailedBareRepoDifferentDirs;
+       /***/ public String initFailedNonBareRepoSameDirs;
        /***/ public String inMemoryBufferLimitExceeded;
        /***/ public String inputStreamMustSupportMark;
        /***/ public String integerValueOutOfRange;
index 9670bf10a2bc6bc2e2667db5106192155cb69e85..995621ee3ecac0f7f8e6043cb51deb3ce38c56af 100644 (file)
@@ -273,7 +273,8 @@ public class FileRepository extends Repository {
                                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 class FileRepository extends Repository {
                        // 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();
        }
 
index d14614dc38abcdefd16558d8c79ae98a314a660c..32ccc7c335a73c9fbb3c71a87d7548e376e8e477 100644 (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.
         *