import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileBasedConfig;
+import org.eclipse.jgit.lib.FileRepository;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache;
String uniqueId = System.currentTimeMillis() + "_" + (testCount++);
String gitdirName = "test" + uniqueId + (bare ? "" : "/") + Constants.DOT_GIT;
File gitdir = new File(trash, gitdirName).getCanonicalFile();
- Repository db = new Repository(gitdir);
+ Repository db = new FileRepository(gitdir);
assertFalse(gitdir.exists());
db.create();
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Commit;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileRepository;
import org.eclipse.jgit.lib.GitIndex;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefComparator;
import org.eclipse.jgit.lib.RefUpdate;
-import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.TextProgressMonitor;
import org.eclipse.jgit.lib.Tree;
import org.eclipse.jgit.lib.WorkDirCheckout;
if (gitdir == null)
gitdir = new File(localName, Constants.DOT_GIT);
- db = new Repository(gitdir);
+ db = new FileRepository(gitdir);
db.create();
db.getConfig().setBoolean("core", null, "bare", false);
db.getConfig().save();
import org.kohsuke.args4j.Option;
import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.FileRepository;
@Command(common = true, usage = "usage_CreateAnEmptyGitRepository")
class Init extends TextBuiltin {
protected void run() throws Exception {
if (gitdir == null)
gitdir = new File(bare ? "." : Constants.DOT_GIT);
- db = new Repository(gitdir);
+ db = new FileRepository(gitdir);
db.create(bare);
out.println(MessageFormat.format(CLIText.get().initializedEmptyGitRepositoryIn, gitdir.getAbsolutePath()));
}
import org.eclipse.jgit.awtui.AwtSshSessionFactory;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.FileRepository;
import org.eclipse.jgit.pgm.opt.CmdLineParser;
import org.eclipse.jgit.pgm.opt.SubcommandHandler;
import org.eclipse.jgit.util.CachedAuthenticator;
writer.flush();
System.exit(1);
}
- cmd.init(new Repository(gitdir, gitworktree, objectdir, altobjectdirs, indexfile), gitdir);
+ cmd.init(new FileRepository(gitdir, gitworktree, objectdir, altobjectdirs, indexfile), gitdir);
} else {
cmd.init(null, gitdir);
}
// Create new Repository instance, to reread caches and make sure our
// assumptions are persistent.
- Repository ndb = new Repository(db.getDirectory());
+ Repository ndb = new FileRepository(db.getDirectory());
assertEquals(rb2, ndb.resolve("refs/heads/new/name"));
assertNull(ndb.resolve("refs/heads/b"));
}
public void testIsBare_CreateRepositoryFromArbitraryGitDir()
throws Exception {
File gitDir = getFile("workdir");
- assertTrue(new Repository(gitDir).isBare());
+ assertTrue(new FileRepository(gitDir).isBare());
}
public void testNotBare_CreateRepositoryFromDotGitGitDir() throws Exception {
File gitDir = getFile("workdir", Constants.DOT_GIT);
- Repository repo = new Repository(gitDir);
+ Repository repo = new FileRepository(gitDir);
assertFalse(repo.isBare());
assertWorkdirPath(repo, "workdir");
assertGitdirPath(repo, "workdir", Constants.DOT_GIT);
public void testWorkdirIsParentDir_CreateRepositoryFromDotGitGitDir()
throws Exception {
File gitDir = getFile("workdir", Constants.DOT_GIT);
- Repository repo = new Repository(gitDir);
+ Repository repo = new FileRepository(gitDir);
String workdir = repo.getWorkDir().getName();
assertEquals(workdir, "workdir");
}
public void testNotBare_CreateRepositoryFromWorkDirOnly() throws Exception {
File workdir = getFile("workdir", "repo");
- Repository repo = new Repository(null, workdir);
+ Repository repo = new FileRepository(null, workdir);
assertFalse(repo.isBare());
assertWorkdirPath(repo, "workdir", "repo");
assertGitdirPath(repo, "workdir", "repo", Constants.DOT_GIT);
public void testWorkdirIsDotGit_CreateRepositoryFromWorkDirOnly()
throws Exception {
File workdir = getFile("workdir", "repo");
- Repository repo = new Repository(null, workdir);
+ Repository repo = new FileRepository(null, workdir);
assertGitdirPath(repo, "workdir", "repo", Constants.DOT_GIT);
}
File gitDir = getFile("workdir", "repoWithConfig");
File workTree = getFile("workdir", "treeRoot");
setWorkTree(gitDir, workTree);
- Repository repo = new Repository(gitDir, null);
+ Repository repo = new FileRepository(gitDir, null);
assertFalse(repo.isBare());
assertWorkdirPath(repo, "workdir", "treeRoot");
assertGitdirPath(repo, "workdir", "repoWithConfig");
throws Exception {
File gitDir = getFile("workdir", "repoWithConfig");
setBare(gitDir, true);
- Repository repo = new Repository(gitDir, null);
+ Repository repo = new FileRepository(gitDir, null);
assertTrue(repo.isBare());
}
throws Exception {
File gitDir = getFile("workdir", "repoWithBareConfigTrue", "child");
setBare(gitDir, false);
- Repository repo = new Repository(gitDir, null);
+ Repository repo = new FileRepository(gitDir, null);
assertWorkdirPath(repo, "workdir", "repoWithBareConfigTrue");
}
throws Exception {
File gitDir = getFile("workdir", "repoWithBareConfigFalse", "child");
setBare(gitDir, false);
- Repository repo = new Repository(gitDir, null);
+ Repository repo = new FileRepository(gitDir, null);
assertFalse(repo.isBare());
assertWorkdirPath(repo, "workdir", "repoWithBareConfigFalse");
assertGitdirPath(repo, "workdir", "repoWithBareConfigFalse", "child");
public void testNotBare_MakeBareUnbareBySetWorkdir() throws Exception {
File gitDir = getFile("gitDir");
- Repository repo = new Repository(gitDir);
+ Repository repo = new FileRepository(gitDir);
repo.setWorkDir(getFile("workingDir"));
assertFalse(repo.isBare());
assertWorkdirPath(repo, "workingDir");
public void testExceptionThrown_BareRepoGetWorkDir() throws Exception {
File gitDir = getFile("workdir");
try {
- new Repository(gitDir).getWorkDir();
+ new FileRepository(gitDir).getWorkDir();
fail("Expected IllegalStateException missing");
} catch (IllegalStateException e) {
// expected
public void testExceptionThrown_BareRepoGetIndex() throws Exception {
File gitDir = getFile("workdir");
try {
- new Repository(gitDir).getIndex();
+ new FileRepository(gitDir).getIndex();
fail("Expected IllegalStateException missing");
} catch (IllegalStateException e) {
// expected
public void testExceptionThrown_BareRepoGetIndexFile() throws Exception {
File gitDir = getFile("workdir");
try {
- new Repository(gitDir).getIndexFile();
+ new FileRepository(gitDir).getIndexFile();
fail("Expected Exception missing");
} catch (IllegalStateException e) {
// expected
}
private void setBare(File gitDir, boolean bare) throws IOException {
- Repository repo = new Repository(gitDir, null);
+ Repository repo = new FileRepository(gitDir, null);
repo.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_BARE, bare);
repo.getConfig().save();
}
private void setWorkTree(File gitDir, File workTree) throws IOException {
- Repository repo = new Repository(gitDir, null);
+ Repository repo = new FileRepository(gitDir, null);
repo.getConfig()
.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_WORKTREE,
public void test000_openRepoBadArgs() throws IOException {
try {
- new Repository(null, null);
+ new FileRepository(null, null);
fail("Must pass either GIT_DIR or GIT_WORK_TREE");
} catch (IllegalArgumentException e) {
assertEquals(
*/
public void test000_openrepo_default_gitDirSet() throws IOException {
File repo1Parent = new File(trash.getParentFile(), "r1");
- Repository repo1initial = new Repository(new File(repo1Parent, Constants.DOT_GIT));
+ Repository repo1initial = new FileRepository(new File(repo1Parent, Constants.DOT_GIT));
repo1initial.create();
repo1initial.close();
File theDir = new File(repo1Parent, Constants.DOT_GIT);
- Repository r = new Repository(theDir, null);
+ Repository r = new FileRepository(theDir, null);
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(repo1Parent, r.getWorkDir());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
*/
public void test000_openrepo_default_gitDirAndWorkTreeSet() throws IOException {
File repo1Parent = new File(trash.getParentFile(), "r1");
- Repository repo1initial = new Repository(new File(repo1Parent, Constants.DOT_GIT));
+ Repository repo1initial = new FileRepository(new File(repo1Parent, Constants.DOT_GIT));
repo1initial.create();
repo1initial.close();
File theDir = new File(repo1Parent, Constants.DOT_GIT);
- Repository r = new Repository(theDir, repo1Parent.getParentFile());
+ Repository r = new FileRepository(theDir, repo1Parent.getParentFile());
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(repo1Parent.getParentFile(), r.getWorkDir());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
*/
public void test000_openrepo_default_workDirSet() throws IOException {
File repo1Parent = new File(trash.getParentFile(), "r1");
- Repository repo1initial = new Repository(new File(repo1Parent, Constants.DOT_GIT));
+ Repository repo1initial = new FileRepository(new File(repo1Parent, Constants.DOT_GIT));
repo1initial.create();
repo1initial.close();
File theDir = new File(repo1Parent, Constants.DOT_GIT);
- Repository r = new Repository(null, repo1Parent);
+ Repository r = new FileRepository(null, repo1Parent);
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(repo1Parent, r.getWorkDir());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
File repo1Parent = new File(trash.getParentFile(), "r1");
File workdir = new File(trash.getParentFile(), "rw");
workdir.mkdir();
- Repository repo1initial = new Repository(new File(repo1Parent, Constants.DOT_GIT));
+ Repository repo1initial = new FileRepository(new File(repo1Parent, Constants.DOT_GIT));
repo1initial.create();
repo1initial.getConfig().setString("core", null, "worktree",
workdir.getAbsolutePath());
repo1initial.close();
File theDir = new File(repo1Parent, Constants.DOT_GIT);
- Repository r = new Repository(theDir, null);
+ Repository r = new FileRepository(theDir, null);
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(workdir, r.getWorkDir());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
File repo1Parent = new File(trash.getParentFile(), "r1");
File workdir = new File(trash.getParentFile(), "rw");
workdir.mkdir();
- Repository repo1initial = new Repository(new File(repo1Parent, Constants.DOT_GIT));
+ Repository repo1initial = new FileRepository(new File(repo1Parent, Constants.DOT_GIT));
repo1initial.create();
repo1initial.getConfig()
.setString("core", null, "worktree", "../../rw");
repo1initial.close();
File theDir = new File(repo1Parent, Constants.DOT_GIT);
- Repository r = new Repository(theDir, null);
+ Repository r = new FileRepository(theDir, null);
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(workdir, r.getWorkDir());
assertEqualsPath(new File(theDir, "index"), r.getIndexFile());
File indexFile = new File(trash, "idx");
File objDir = new File(trash, "../obj");
File[] altObjDirs = new File[] { db.getObjectsDirectory() };
- Repository repo1initial = new Repository(new File(repo1Parent, Constants.DOT_GIT));
+ Repository repo1initial = new FileRepository(new File(repo1Parent, Constants.DOT_GIT));
repo1initial.create();
repo1initial.close();
File theDir = new File(repo1Parent, Constants.DOT_GIT);
- Repository r = new Repository(theDir, null, objDir, altObjDirs,
+ Repository r = new FileRepository(theDir, null, objDir, altObjDirs,
indexFile);
assertEqualsPath(theDir, r.getDirectory());
assertEqualsPath(theDir.getParentFile(), r.getWorkDir());
}
public void test007_Open() throws IOException {
- final Repository db2 = new Repository(db.getDirectory());
+ final Repository db2 = new FileRepository(db.getDirectory());
assertEquals(db.getDirectory(), db2.getDirectory());
assertEquals(db.getObjectsDirectory(), db2.getObjectsDirectory());
assertNotSame(db.getConfig(), db2.getConfig());
pw.close();
try {
- new Repository(db.getDirectory());
+ new FileRepository(db.getDirectory());
fail("incorrectly opened a bad repository");
} catch (IOException ioe) {
assertTrue(ioe.getMessage().indexOf("format") > 0);
--- /dev/null
+/*
+ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
+ * Copyright (C) 2008-2010, Google Inc.
+ * Copyright (C) 2006-2010, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+
+import org.eclipse.jgit.JGitText;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.SystemReader;
+
+/**
+ * Represents a Git repository. A repository holds all objects and refs used for
+ * managing source code (could by any type of file, but source code is what
+ * SCM's are typically used for).
+ *
+ * In Git terms all data is stored in GIT_DIR, typically a directory called
+ * .git. A work tree is maintained unless the repository is a bare repository.
+ * Typically the .git directory is located at the root of the work dir.
+ *
+ * <ul>
+ * <li>GIT_DIR
+ * <ul>
+ * <li>objects/ - objects</li>
+ * <li>refs/ - tags and heads</li>
+ * <li>config - configuration</li>
+ * <li>info/ - more configurations</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * <p>
+ * This class is thread-safe.
+ * <p>
+ * This implementation only handles a subtly undocumented subset of git features.
+ *
+ */
+public class FileRepository extends Repository {
+ private final FileBasedConfig userConfig;
+
+ private final FileBasedConfig repoConfig;
+
+ private final RefDatabase refs;
+
+ private final ObjectDirectory objectDatabase;
+
+ /**
+ * Construct a representation of a Git repository.
+ *
+ * The work tree, object directory, alternate object directories and index
+ * file locations are deduced from the given git directory and the default
+ * rules.
+ *
+ * @param d
+ * GIT_DIR (the location of the repository metadata).
+ * @throws IOException
+ * the repository appears to already exist but cannot be
+ * accessed.
+ */
+ public FileRepository(final File d) throws IOException {
+ this(d, null, null, null, null); // go figure it out
+ }
+
+ /**
+ * Construct a representation of a Git repository.
+ *
+ * The work tree, object directory, alternate object directories and index
+ * file locations are deduced from the given git directory and the default
+ * rules.
+ *
+ * @param d
+ * GIT_DIR (the location of the repository metadata). May be
+ * null work workTree is set
+ * @param workTree
+ * GIT_WORK_TREE (the root of the checkout). May be null for
+ * default value.
+ * @throws IOException
+ * the repository appears to already exist but cannot be
+ * accessed.
+ */
+ public FileRepository(final File d, final File workTree) throws IOException {
+ this(d, workTree, null, null, null); // go figure it out
+ }
+
+ /**
+ * Construct a representation of a Git repository using the given parameters
+ * possibly overriding default conventions.
+ *
+ * @param d
+ * GIT_DIR (the location of the repository metadata). May be null
+ * for default value in which case it depends on GIT_WORK_TREE.
+ * @param workTree
+ * GIT_WORK_TREE (the root of the checkout). May be null for
+ * default value if GIT_DIR is provided.
+ * @param objectDir
+ * GIT_OBJECT_DIRECTORY (where objects and are stored). May be
+ * null for default value. Relative names ares resolved against
+ * GIT_WORK_TREE.
+ * @param alternateObjectDir
+ * GIT_ALTERNATE_OBJECT_DIRECTORIES (where more objects are read
+ * from). May be null for default value. Relative names ares
+ * resolved against GIT_WORK_TREE.
+ * @param indexFile
+ * GIT_INDEX_FILE (the location of the index file). May be null
+ * for default value. Relative names ares resolved against
+ * GIT_WORK_TREE.
+ * @throws IOException
+ * the repository appears to already exist but cannot be
+ * accessed.
+ */
+ public FileRepository(final File d, final File workTree, final File objectDir,
+ final File[] alternateObjectDir, final File indexFile) throws IOException {
+ this(d, workTree, objectDir, alternateObjectDir, indexFile, FS.DETECTED);
+ }
+
+ /**
+ * Construct a representation of a Git repository using the given parameters
+ * possibly overriding default conventions.
+ *
+ * @param d
+ * GIT_DIR (the location of the repository metadata). May be null
+ * for default value in which case it depends on GIT_WORK_TREE.
+ * @param workTree
+ * GIT_WORK_TREE (the root of the checkout). May be null for
+ * default value if GIT_DIR is provided.
+ * @param objectDir
+ * GIT_OBJECT_DIRECTORY (where objects and are stored). May be
+ * null for default value. Relative names ares resolved against
+ * GIT_WORK_TREE.
+ * @param alternateObjectDir
+ * GIT_ALTERNATE_OBJECT_DIRECTORIES (where more objects are read
+ * from). May be null for default value. Relative names ares
+ * resolved against GIT_WORK_TREE.
+ * @param indexFile
+ * GIT_INDEX_FILE (the location of the index file). May be null
+ * for default value. Relative names ares resolved against
+ * GIT_WORK_TREE.
+ * @param fs
+ * the file system abstraction which will be necessary to
+ * perform certain file system operations.
+ * @throws IOException
+ * the repository appears to already exist but cannot be
+ * accessed.
+ */
+ public FileRepository(final File d, final File workTree, final File objectDir,
+ final File[] alternateObjectDir, final File indexFile, FS fs)
+ throws IOException {
+
+ if (workTree != null) {
+ workDir = workTree;
+ if (d == null)
+ gitDir = new File(workTree, Constants.DOT_GIT);
+ else
+ gitDir = d;
+ } else {
+ if (d != null)
+ gitDir = d;
+ else
+ throw new IllegalArgumentException(
+ JGitText.get().eitherGIT_DIRorGIT_WORK_TREEmustBePassed);
+ }
+
+ this.fs = fs;
+
+ userConfig = SystemReader.getInstance().openUserConfig(fs);
+ repoConfig = new FileBasedConfig(userConfig, fs.resolve(gitDir, "config"));
+
+ loadUserConfig();
+ loadRepoConfig();
+
+ if (workDir == null) {
+ // if the working directory was not provided explicitly,
+ // we need to decide if this is a "bare" repository or not
+ // first, we check the working tree configuration
+ String workTreeConfig = getConfig().getString(
+ ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_WORKTREE);
+ if (workTreeConfig != null) {
+ // the working tree configuration wins
+ workDir = fs.resolve(d, workTreeConfig);
+ } else if (getConfig().getString(
+ ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_BARE) != null) {
+ // we have asserted that a value for the "bare" flag was set
+ if (!getConfig().getBoolean(ConfigConstants.CONFIG_CORE_SECTION,
+ ConfigConstants.CONFIG_KEY_BARE, true))
+ // the "bare" flag is false -> use the parent of the
+ // meta data directory
+ workDir = gitDir.getParentFile();
+ else
+ // the "bare" flag is true
+ workDir = null;
+ } else if (Constants.DOT_GIT.equals(gitDir.getName())) {
+ // no value for the "bare" flag, but the meta data directory
+ // is named ".git" -> use the parent of the meta data directory
+ workDir = gitDir.getParentFile();
+ } else {
+ workDir = null;
+ }
+ }
+
+ refs = new RefDirectory(this);
+ if (objectDir != null)
+ objectDatabase = new ObjectDirectory(fs.resolve(objectDir, ""),
+ alternateObjectDir, fs);
+ else
+ objectDatabase = new ObjectDirectory(fs.resolve(gitDir, "objects"),
+ alternateObjectDir, fs);
+
+ if (indexFile != null)
+ this.indexFile = indexFile;
+ else
+ this.indexFile = new File(gitDir, "index");
+
+ if (objectDatabase.exists()) {
+ final String repositoryFormatVersion = getConfig().getString(
+ ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION);
+ if (!"0".equals(repositoryFormatVersion)) {
+ throw new IOException(MessageFormat.format(
+ JGitText.get().unknownRepositoryFormat2,
+ repositoryFormatVersion));
+ }
+ }
+ }
+
+ private void loadUserConfig() throws IOException {
+ try {
+ userConfig.load();
+ } catch (ConfigInvalidException e1) {
+ IOException e2 = new IOException(MessageFormat.format(JGitText
+ .get().userConfigFileInvalid, userConfig.getFile()
+ .getAbsolutePath(), e1));
+ e2.initCause(e1);
+ throw e2;
+ }
+ }
+
+ private void loadRepoConfig() throws IOException {
+ try {
+ repoConfig.load();
+ } catch (ConfigInvalidException e1) {
+ IOException e2 = new IOException(JGitText.get().unknownRepositoryFormat);
+ e2.initCause(e1);
+ throw e2;
+ }
+ }
+
+ /**
+ * Create a new Git repository initializing the necessary files and
+ * directories.
+ *
+ * @param bare
+ * if true, a bare repository is created.
+ *
+ * @throws IOException
+ * in case of IO problem
+ */
+ public void create(boolean bare) throws IOException {
+ final FileBasedConfig cfg = getConfig();
+ if (cfg.getFile().exists()) {
+ throw new IllegalStateException(MessageFormat.format(
+ JGitText.get().repositoryAlreadyExists, gitDir));
+ }
+ gitDir.mkdirs();
+ refs.create();
+ objectDatabase.create();
+
+ new File(gitDir, "branches").mkdir();
+
+ RefUpdate head = updateRef(Constants.HEAD);
+ head.disableRefLog();
+ head.link(Constants.R_HEADS + Constants.MASTER);
+
+ cfg.setInt(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0);
+ cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_FILEMODE, true);
+ if (bare)
+ cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_BARE, true);
+ cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, !bare);
+ cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+ ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
+ cfg.save();
+ }
+
+ /**
+ * @return the directory containing the objects owned by this repository.
+ */
+ public File getObjectsDirectory() {
+ return objectDatabase.getDirectory();
+ }
+
+ /**
+ * @return the object database which stores this repository's data.
+ */
+ public ObjectDirectory getObjectDatabase() {
+ return objectDatabase;
+ }
+
+ /** @return the reference database which stores the reference namespace. */
+ public RefDatabase getRefDatabase() {
+ return refs;
+ }
+
+ /**
+ * @return the configuration of this repository
+ */
+ public FileBasedConfig getConfig() {
+ if (userConfig.isOutdated()) {
+ try {
+ loadUserConfig();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ if (repoConfig.isOutdated()) {
+ try {
+ loadRepoConfig();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return repoConfig;
+ }
+
+ /**
+ * Construct a filename where the loose object having a specified SHA-1
+ * should be stored. If the object is stored in a shared repository the path
+ * to the alternative repo will be returned. If the object is not yet store
+ * a usable path in this repo will be returned. It is assumed that callers
+ * will look for objects in a pack first.
+ *
+ * @param objectId
+ * @return suggested file name
+ */
+ public File toFile(final AnyObjectId objectId) {
+ return objectDatabase.fileFor(objectId);
+ }
+
+ /**
+ * Open object in all packs containing specified object.
+ *
+ * @param objectId
+ * id of object to search for
+ * @param curs
+ * temporary working space associated with the calling thread.
+ * @return collection of loaders for this object, from all packs containing
+ * this object
+ * @throws IOException
+ */
+ public Collection<PackedObjectLoader> openObjectInAllPacks(
+ final AnyObjectId objectId, final WindowCursor curs)
+ throws IOException {
+ Collection<PackedObjectLoader> result = new LinkedList<PackedObjectLoader>();
+ openObjectInAllPacks(objectId, result, curs);
+ return result;
+ }
+
+ /**
+ * Open object in all packs containing specified object.
+ *
+ * @param objectId
+ * id of object to search for
+ * @param resultLoaders
+ * result collection of loaders for this object, filled with
+ * loaders from all packs containing specified object
+ * @param curs
+ * temporary working space associated with the calling thread.
+ * @throws IOException
+ */
+ void openObjectInAllPacks(final AnyObjectId objectId,
+ final Collection<PackedObjectLoader> resultLoaders,
+ final WindowCursor curs) throws IOException {
+ objectDatabase.openObjectInAllPacks(resultLoaders, curs, objectId);
+ }
+
+ /**
+ * Objects known to exist but not expressed by {@link #getAllRefs()}.
+ * <p>
+ * When a repository borrows objects from another repository, it can
+ * advertise that it safely has that other repository's references, without
+ * exposing any other details about the other repository. This may help
+ * a client trying to push changes avoid pushing more than it needs to.
+ *
+ * @return unmodifiable collection of other known objects.
+ */
+ public Set<ObjectId> getAdditionalHaves() {
+ HashSet<ObjectId> r = new HashSet<ObjectId>();
+ for (ObjectDatabase d : getObjectDatabase().getAlternates()) {
+ if (d instanceof AlternateRepositoryDatabase) {
+ Repository repo;
+
+ repo = ((AlternateRepositoryDatabase) d).getRepository();
+ for (Ref ref : repo.getAllRefs().values())
+ r.add(ref.getObjectId());
+ r.addAll(repo.getAdditionalHaves());
+ }
+ }
+ return r;
+ }
+
+ /**
+ * Add a single existing pack to the list of available pack files.
+ *
+ * @param pack
+ * path of the pack file to open.
+ * @param idx
+ * path of the corresponding index file.
+ * @throws IOException
+ * index file could not be opened, read, or is not recognized as
+ * a Git pack file index.
+ */
+ public void openPack(final File pack, final File idx) throws IOException {
+ objectDatabase.openPack(pack, idx);
+ }
+
+ /**
+ * Force a scan for changed refs.
+ *
+ * @throws IOException
+ */
+ public void scanForRepoChanges() throws IOException {
+ getAllRefs(); // This will look for changes to refs
+ if (!isBare())
+ getIndex(); // This will detect changes in the index
+ }
+
+ /**
+ * @param refName
+ * @return a {@link ReflogReader} for the supplied refname, or null if the
+ * named ref does not exist.
+ * @throws IOException the ref could not be accessed.
+ */
+ public ReflogReader getReflogReader(String refName) throws IOException {
+ Ref ref = getRef(refName);
+ if (ref != null)
+ return new ReflogReader(this, ref.getName());
+ return null;
+ }
+}
/** If in the header, denotes the file has peeled data. */
public static final String PACKED_REFS_PEELED = " peeled"; //$NON-NLS-1$
- private final Repository parent;
+ private final FileRepository parent;
private final File gitDir;
*/
private final AtomicInteger lastNotifiedModCnt = new AtomicInteger();
- RefDirectory(final Repository db) {
+ RefDirectory(final FileRepository db) {
final FS fs = db.getFS();
parent = db;
gitDir = db.getDirectory();
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.dircache.DirCache;
-import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.IO;
import org.eclipse.jgit.util.RawParseUtils;
-import org.eclipse.jgit.util.SystemReader;
/**
- * Represents a Git repository. A repository holds all objects and refs used for
- * managing source code (could by any type of file, but source code is what
- * SCM's are typically used for).
- *
- * In Git terms all data is stored in GIT_DIR, typically a directory called
- * .git. A work tree is maintained unless the repository is a bare repository.
- * Typically the .git directory is located at the root of the work dir.
- *
- * <ul>
- * <li>GIT_DIR
- * <ul>
- * <li>objects/ - objects</li>
- * <li>refs/ - tags and heads</li>
- * <li>config - configuration</li>
- * <li>info/ - more configurations</li>
- * </ul>
- * </li>
- * </ul>
+ * Represents a Git repository.
* <p>
- * This class is thread-safe.
+ * A repository holds all objects and refs used for managing source code (could
+ * be any type of file, but source code is what SCM's are typically used for).
* <p>
- * This implementation only handles a subtly undocumented subset of git features.
- *
+ * This class is thread-safe.
*/
-public class Repository {
+public abstract class Repository {
private final AtomicInteger useCnt = new AtomicInteger(1);
- private final File gitDir;
+ /** Metadata directory holding the repository's critical files. */
+ protected File gitDir;
- private final FS fs;
-
- private final FileBasedConfig userConfig;
-
- private final FileBasedConfig repoConfig;
-
- private final RefDatabase refs;
-
- private final ObjectDirectory objectDatabase;
+ /** File abstraction used to resolve paths. */
+ protected FS fs;
private GitIndex index;
private final List<RepositoryListener> listeners = new Vector<RepositoryListener>(); // thread safe
static private final List<RepositoryListener> allListeners = new Vector<RepositoryListener>(); // thread safe
- private File workDir;
+ /** If not bare, the top level directory of the working files. */
+ protected File workDir;
- private File indexFile;
+ /** If not bare, the index file caching the working file states. */
+ protected File indexFile;
- /**
- * Construct a representation of a Git repository.
- *
- * The work tree, object directory, alternate object directories and index
- * file locations are deduced from the given git directory and the default
- * rules.
- *
- * @param d
- * GIT_DIR (the location of the repository metadata).
- * @throws IOException
- * the repository appears to already exist but cannot be
- * accessed.
- */
- public Repository(final File d) throws IOException {
- this(d, null, null, null, null); // go figure it out
- }
-
- /**
- * Construct a representation of a Git repository.
- *
- * The work tree, object directory, alternate object directories and index
- * file locations are deduced from the given git directory and the default
- * rules.
- *
- * @param d
- * GIT_DIR (the location of the repository metadata). May be
- * null work workTree is set
- * @param workTree
- * GIT_WORK_TREE (the root of the checkout). May be null for
- * default value.
- * @throws IOException
- * the repository appears to already exist but cannot be
- * accessed.
- */
- public Repository(final File d, final File workTree) throws IOException {
- this(d, workTree, null, null, null); // go figure it out
- }
-
- /**
- * Construct a representation of a Git repository using the given parameters
- * possibly overriding default conventions.
- *
- * @param d
- * GIT_DIR (the location of the repository metadata). May be null
- * for default value in which case it depends on GIT_WORK_TREE.
- * @param workTree
- * GIT_WORK_TREE (the root of the checkout). May be null for
- * default value if GIT_DIR is provided.
- * @param objectDir
- * GIT_OBJECT_DIRECTORY (where objects and are stored). May be
- * null for default value. Relative names ares resolved against
- * GIT_WORK_TREE.
- * @param alternateObjectDir
- * GIT_ALTERNATE_OBJECT_DIRECTORIES (where more objects are read
- * from). May be null for default value. Relative names ares
- * resolved against GIT_WORK_TREE.
- * @param indexFile
- * GIT_INDEX_FILE (the location of the index file). May be null
- * for default value. Relative names ares resolved against
- * GIT_WORK_TREE.
- * @throws IOException
- * the repository appears to already exist but cannot be
- * accessed.
- */
- public Repository(final File d, final File workTree, final File objectDir,
- final File[] alternateObjectDir, final File indexFile) throws IOException {
- this(d, workTree, objectDir, alternateObjectDir, indexFile, FS.DETECTED);
- }
-
- /**
- * Construct a representation of a Git repository using the given parameters
- * possibly overriding default conventions.
- *
- * @param d
- * GIT_DIR (the location of the repository metadata). May be null
- * for default value in which case it depends on GIT_WORK_TREE.
- * @param workTree
- * GIT_WORK_TREE (the root of the checkout). May be null for
- * default value if GIT_DIR is provided.
- * @param objectDir
- * GIT_OBJECT_DIRECTORY (where objects and are stored). May be
- * null for default value. Relative names ares resolved against
- * GIT_WORK_TREE.
- * @param alternateObjectDir
- * GIT_ALTERNATE_OBJECT_DIRECTORIES (where more objects are read
- * from). May be null for default value. Relative names ares
- * resolved against GIT_WORK_TREE.
- * @param indexFile
- * GIT_INDEX_FILE (the location of the index file). May be null
- * for default value. Relative names ares resolved against
- * GIT_WORK_TREE.
- * @param fs
- * the file system abstraction which will be necessary to
- * perform certain file system operations.
- * @throws IOException
- * the repository appears to already exist but cannot be
- * accessed.
- */
- public Repository(final File d, final File workTree, final File objectDir,
- final File[] alternateObjectDir, final File indexFile, FS fs)
- throws IOException {
-
- if (workTree != null) {
- workDir = workTree;
- if (d == null)
- gitDir = new File(workTree, Constants.DOT_GIT);
- else
- gitDir = d;
- } else {
- if (d != null)
- gitDir = d;
- else
- throw new IllegalArgumentException(
- JGitText.get().eitherGIT_DIRorGIT_WORK_TREEmustBePassed);
- }
-
- this.fs = fs;
-
- userConfig = SystemReader.getInstance().openUserConfig(fs);
- repoConfig = new FileBasedConfig(userConfig, fs.resolve(gitDir, "config"));
-
- loadUserConfig();
- loadRepoConfig();
-
- if (workDir == null) {
- // if the working directory was not provided explicitly,
- // we need to decide if this is a "bare" repository or not
- // first, we check the working tree configuration
- String workTreeConfig = getConfig().getString(
- ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_WORKTREE);
- if (workTreeConfig != null) {
- // the working tree configuration wins
- workDir = fs.resolve(d, workTreeConfig);
- } else if (getConfig().getString(
- ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_BARE) != null) {
- // we have asserted that a value for the "bare" flag was set
- if (!getConfig().getBoolean(ConfigConstants.CONFIG_CORE_SECTION,
- ConfigConstants.CONFIG_KEY_BARE, true))
- // the "bare" flag is false -> use the parent of the
- // meta data directory
- workDir = gitDir.getParentFile();
- else
- // the "bare" flag is true
- workDir = null;
- } else if (Constants.DOT_GIT.equals(gitDir.getName())) {
- // no value for the "bare" flag, but the meta data directory
- // is named ".git" -> use the parent of the meta data directory
- workDir = gitDir.getParentFile();
- } else {
- workDir = null;
- }
- }
-
- refs = new RefDirectory(this);
- if (objectDir != null)
- objectDatabase = new ObjectDirectory(fs.resolve(objectDir, ""),
- alternateObjectDir, fs);
- else
- objectDatabase = new ObjectDirectory(fs.resolve(gitDir, "objects"),
- alternateObjectDir, fs);
-
- if (indexFile != null)
- this.indexFile = indexFile;
- else
- this.indexFile = new File(gitDir, "index");
-
- if (objectDatabase.exists()) {
- final String repositoryFormatVersion = getConfig().getString(
- ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION);
- if (!"0".equals(repositoryFormatVersion)) {
- throw new IOException(MessageFormat.format(
- JGitText.get().unknownRepositoryFormat2,
- repositoryFormatVersion));
- }
- }
- }
-
- private void loadUserConfig() throws IOException {
- try {
- userConfig.load();
- } catch (ConfigInvalidException e1) {
- IOException e2 = new IOException(MessageFormat.format(JGitText
- .get().userConfigFileInvalid, userConfig.getFile()
- .getAbsolutePath(), e1));
- e2.initCause(e1);
- throw e2;
- }
- }
-
- private void loadRepoConfig() throws IOException {
- try {
- repoConfig.load();
- } catch (ConfigInvalidException e1) {
- IOException e2 = new IOException(JGitText.get().unknownRepositoryFormat);
- e2.initCause(e1);
- throw e2;
- }
+ /** Initialize a new repository instance. */
+ protected Repository() {
+ // Empty constructor, defined protected to require subclassing.
}
/**
* @throws IOException
* in case of IO problem
*/
- public void create(boolean bare) throws IOException {
- final FileBasedConfig cfg = getConfig();
- if (cfg.getFile().exists()) {
- throw new IllegalStateException(MessageFormat.format(
- JGitText.get().repositoryAlreadyExists, gitDir));
- }
- gitDir.mkdirs();
- refs.create();
- objectDatabase.create();
-
- new File(gitDir, "branches").mkdir();
-
- RefUpdate head = updateRef(Constants.HEAD);
- head.disableRefLog();
- head.link(Constants.R_HEADS + Constants.MASTER);
-
- cfg.setInt(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_REPO_FORMAT_VERSION, 0);
- cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_FILEMODE, true);
- if (bare)
- cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_BARE, true);
- cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, !bare);
- cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_AUTOCRLF, false);
- cfg.save();
- }
+ public abstract void create(boolean bare) throws IOException;
/**
* @return GIT_DIR
/**
* @return the directory containing the objects owned by this repository.
*/
- public File getObjectsDirectory() {
- return objectDatabase.getDirectory();
- }
+ public abstract File getObjectsDirectory();
/**
* @return the object database which stores this repository's data.
*/
- public ObjectDatabase getObjectDatabase() {
- return objectDatabase;
- }
+ public abstract ObjectDatabase getObjectDatabase();
/** @return the reference database which stores the reference namespace. */
- public RefDatabase getRefDatabase() {
- return refs;
- }
+ public abstract RefDatabase getRefDatabase();
/**
* @return the configuration of this repository
*/
- public FileBasedConfig getConfig() {
- if (userConfig.isOutdated()) {
- try {
- loadUserConfig();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- if (repoConfig.isOutdated()) {
- try {
- loadRepoConfig();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- return repoConfig;
- }
+ public abstract FileBasedConfig getConfig();
/**
* @return the used file system abstraction
* @param objectId
* @return suggested file name
*/
- public File toFile(final AnyObjectId objectId) {
- return objectDatabase.fileFor(objectId);
- }
+ public abstract File toFile(AnyObjectId objectId);
/**
* @param objectId
* this object
* @throws IOException
*/
- public Collection<PackedObjectLoader> openObjectInAllPacks(
- final AnyObjectId objectId, final WindowCursor curs)
- throws IOException {
- Collection<PackedObjectLoader> result = new LinkedList<PackedObjectLoader>();
- openObjectInAllPacks(objectId, result, curs);
- return result;
- }
+ public abstract Collection<PackedObjectLoader> openObjectInAllPacks(
+ AnyObjectId objectId, WindowCursor curs)
+ throws IOException;
/**
* Open object in all packs containing specified object.
* temporary working space associated with the calling thread.
* @throws IOException
*/
- void openObjectInAllPacks(final AnyObjectId objectId,
+ abstract void openObjectInAllPacks(final AnyObjectId objectId,
final Collection<PackedObjectLoader> resultLoaders,
- final WindowCursor curs) throws IOException {
- objectDatabase.openObjectInAllPacks(resultLoaders, curs, objectId);
- }
+ final WindowCursor curs) throws IOException;
/**
* @param id
* index file could not be opened, read, or is not recognized as
* a Git pack file index.
*/
- public void openPack(final File pack, final File idx) throws IOException {
- objectDatabase.openPack(pack, idx);
- }
+ public abstract void openPack(File pack, File idx) throws IOException;
public String toString() {
return "Repository[" + getDirectory() + "]";
* @return unmodifiable collection of other known objects.
*/
public Set<ObjectId> getAdditionalHaves() {
- HashSet<ObjectId> r = new HashSet<ObjectId>();
- for (ObjectDatabase d : objectDatabase.getAlternates()) {
- if (d instanceof AlternateRepositoryDatabase) {
- Repository repo;
-
- repo = ((AlternateRepositoryDatabase) d).getRepository();
- for (Ref ref : repo.getAllRefs().values())
- r.add(ref.getObjectId());
- r.addAll(repo.getAdditionalHaves());
- }
- }
- return r;
+ return Collections.emptySet();
}
/**
*
* @throws IOException
*/
- public void scanForRepoChanges() throws IOException {
- getAllRefs(); // This will look for changes to refs
- if (!isBare())
- getIndex(); // This will detect changes in the index
- }
+ public abstract void scanForRepoChanges() throws IOException;
/**
* @param refName
* named ref does not exist.
* @throws IOException the ref could not be accessed.
*/
- public ReflogReader getReflogReader(String refName) throws IOException {
- Ref ref = getRef(refName);
- if (ref != null)
- return new ReflogReader(this, ref.getName());
- return null;
- }
+ public abstract ReflogReader getReflogReader(String refName)
+ throws IOException;
/**
* Return the information stored in the file $GIT_DIR/MERGE_MSG. In this
public Repository open(final boolean mustExist) throws IOException {
if (mustExist && !isGitRepository(path, fs))
throw new RepositoryNotFoundException(path);
- return new Repository(path);
+ return new FileRepository(path);
}
@Override
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileRepository;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.FS;
import org.eclipse.jgit.util.io.MessageWriter;
final Repository dst;
try {
- dst = new Repository(remoteGitDir);
+ dst = new FileRepository(remoteGitDir);
} catch (IOException err) {
throw new TransportException(uri, JGitText.get().notAGitDirectory);
}
final Repository dst;
try {
- dst = new Repository(remoteGitDir);
+ dst = new FileRepository(remoteGitDir);
} catch (IOException err) {
throw new TransportException(uri, JGitText.get().notAGitDirectory);
}