aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LinkedWorktreeTest.java192
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java31
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java8
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java39
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java20
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java116
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java52
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java2
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java16
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java51
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java6
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java4
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java33
29 files changed, 520 insertions, 85 deletions
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
index 52f40c2957..f5de7045d0 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Config.java
@@ -94,7 +94,7 @@ class Config extends TextBuiltin {
if (global || isListAll())
list(SystemReader.getInstance().openUserConfig(null, fs));
if (local || isListAll())
- list(new FileBasedConfig(fs.resolve(getRepository().getDirectory(),
+ list(new FileBasedConfig(fs.resolve(getRepository().getCommonDirectory(),
Constants.CONFIG), fs));
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java
index b937b1f6a9..4c971ffb6b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/EolRepositoryTest.java
@@ -559,7 +559,7 @@ public class EolRepositoryTest extends RepositoryTestCase {
}
if (infoAttributesContent != null) {
- File f = new File(db.getDirectory(), Constants.INFO_ATTRIBUTES);
+ File f = new File(db.getCommonDirectory(), Constants.INFO_ATTRIBUTES);
write(f, infoAttributesContent);
}
config.save();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LinkedWorktreeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LinkedWorktreeTest.java
new file mode 100644
index 0000000000..3b60e1b5c0
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LinkedWorktreeTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2024, Broadcom and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.api;
+
+import static org.eclipse.jgit.lib.Constants.HEAD;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.eclipse.jgit.internal.storage.file.FileRepository;
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ReflogEntry;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FS.ExecutionResult;
+import org.eclipse.jgit.util.RawParseUtils;
+import org.eclipse.jgit.util.TemporaryBuffer;
+import org.junit.Test;
+
+public class LinkedWorktreeTest extends RepositoryTestCase {
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ try (Git git = new Git(db)) {
+ git.commit().setMessage("Initial commit").call();
+ }
+ }
+
+ @Test
+ public void testWeCanReadFromLinkedWorktreeFromBare() throws Exception {
+ FS fs = db.getFS();
+ File directory = trash.getParentFile();
+ String dbDirName = db.getWorkTree().getName();
+ cloneBare(fs, directory, dbDirName, "bare");
+ File bareDirectory = new File(directory, "bare");
+ worktreeAddExisting(fs, bareDirectory, "master");
+
+ File worktreesDir = new File(bareDirectory, "worktrees");
+ File masterWorktreesDir = new File(worktreesDir, "master");
+
+ FileRepository repository = new FileRepository(masterWorktreesDir);
+ try (Git git = new Git(repository)) {
+ ObjectId objectId = repository.resolve(HEAD);
+ assertNotNull(objectId);
+
+ Iterator<RevCommit> log = git.log().all().call().iterator();
+ assertTrue(log.hasNext());
+ assertTrue("Initial commit".equals(log.next().getShortMessage()));
+
+ // we have reflog entry
+ // depending on git version we either have one or
+ // two entries where extra is zeroid entry with
+ // same message or no message
+ Collection<ReflogEntry> reflog = git.reflog().call();
+ assertNotNull(reflog);
+ assertTrue(reflog.size() > 0);
+ ReflogEntry[] reflogs = reflog.toArray(new ReflogEntry[0]);
+ assertEquals(reflogs[reflogs.length - 1].getComment(),
+ "reset: moving to HEAD");
+
+ // index works with file changes
+ File masterDir = new File(directory, "master");
+ File testFile = new File(masterDir, "test");
+
+ Status status = git.status().call();
+ assertTrue(status.getUncommittedChanges().size() == 0);
+ assertTrue(status.getUntracked().size() == 0);
+
+ JGitTestUtil.write(testFile, "test");
+ status = git.status().call();
+ assertTrue(status.getUncommittedChanges().size() == 0);
+ assertTrue(status.getUntracked().size() == 1);
+
+ git.add().addFilepattern("test").call();
+ status = git.status().call();
+ assertTrue(status.getUncommittedChanges().size() == 1);
+ assertTrue(status.getUntracked().size() == 0);
+ }
+ }
+
+ @Test
+ public void testWeCanReadFromLinkedWorktreeFromNonBare() throws Exception {
+ FS fs = db.getFS();
+ worktreeAddNew(fs, db.getWorkTree(), "wt");
+
+ File worktreesDir = new File(db.getDirectory(), "worktrees");
+ File masterWorktreesDir = new File(worktreesDir, "wt");
+
+ FileRepository repository = new FileRepository(masterWorktreesDir);
+ try (Git git = new Git(repository)) {
+ ObjectId objectId = repository.resolve(HEAD);
+ assertNotNull(objectId);
+
+ Iterator<RevCommit> log = git.log().all().call().iterator();
+ assertTrue(log.hasNext());
+ assertTrue("Initial commit".equals(log.next().getShortMessage()));
+
+ // we have reflog entry
+ Collection<ReflogEntry> reflog = git.reflog().call();
+ assertNotNull(reflog);
+ assertTrue(reflog.size() > 0);
+ ReflogEntry[] reflogs = reflog.toArray(new ReflogEntry[0]);
+ assertEquals(reflogs[reflogs.length - 1].getComment(),
+ "reset: moving to HEAD");
+
+ // index works with file changes
+ File directory = trash.getParentFile();
+ File wtDir = new File(directory, "wt");
+ File testFile = new File(wtDir, "test");
+
+ Status status = git.status().call();
+ assertTrue(status.getUncommittedChanges().size() == 0);
+ assertTrue(status.getUntracked().size() == 0);
+
+ JGitTestUtil.write(testFile, "test");
+ status = git.status().call();
+ assertTrue(status.getUncommittedChanges().size() == 0);
+ assertTrue(status.getUntracked().size() == 1);
+
+ git.add().addFilepattern("test").call();
+ status = git.status().call();
+ assertTrue(status.getUncommittedChanges().size() == 1);
+ assertTrue(status.getUntracked().size() == 0);
+ }
+
+ }
+
+ private static void cloneBare(FS fs, File directory, String from, String to) throws IOException, InterruptedException {
+ ProcessBuilder builder = fs.runInShell("git",
+ new String[] { "clone", "--bare", from, to });
+ builder.directory(directory);
+ builder.environment().put("HOME", fs.userHome().getAbsolutePath());
+ StringBuilder input = new StringBuilder();
+ ExecutionResult result = fs.execute(builder, new ByteArrayInputStream(
+ input.toString().getBytes(StandardCharsets.UTF_8)));
+ String stdOut = toString(result.getStdout());
+ String errorOut = toString(result.getStderr());
+ assertNotNull(stdOut);
+ assertNotNull(errorOut);
+ }
+
+ private static void worktreeAddExisting(FS fs, File directory, String name) throws IOException, InterruptedException {
+ ProcessBuilder builder = fs.runInShell("git",
+ new String[] { "worktree", "add", "../" + name, name });
+ builder.directory(directory);
+ builder.environment().put("HOME", fs.userHome().getAbsolutePath());
+ StringBuilder input = new StringBuilder();
+ ExecutionResult result = fs.execute(builder, new ByteArrayInputStream(
+ input.toString().getBytes(StandardCharsets.UTF_8)));
+ String stdOut = toString(result.getStdout());
+ String errorOut = toString(result.getStderr());
+ assertNotNull(stdOut);
+ assertNotNull(errorOut);
+ }
+
+ private static void worktreeAddNew(FS fs, File directory, String name) throws IOException, InterruptedException {
+ ProcessBuilder builder = fs.runInShell("git",
+ new String[] { "worktree", "add", "-b", name, "../" + name, "master"});
+ builder.directory(directory);
+ builder.environment().put("HOME", fs.userHome().getAbsolutePath());
+ StringBuilder input = new StringBuilder();
+ ExecutionResult result = fs.execute(builder, new ByteArrayInputStream(
+ input.toString().getBytes(StandardCharsets.UTF_8)));
+ String stdOut = toString(result.getStdout());
+ String errorOut = toString(result.getStderr());
+ assertNotNull(stdOut);
+ assertNotNull(errorOut);
+ }
+
+ private static String toString(TemporaryBuffer b) throws IOException {
+ return RawParseUtils.decode(b.toByteArray());
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java
index 7fb98ec53b..c41dd81add 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/attributes/AttributesHandlerTest.java
@@ -584,7 +584,7 @@ public class AttributesHandlerTest extends RepositoryTestCase {
}
if (infoAttributesContent != null) {
- File f = new File(db.getDirectory(), Constants.INFO_ATTRIBUTES);
+ File f = new File(db.getCommonDirectory(), Constants.INFO_ATTRIBUTES);
write(f, infoAttributesContent);
}
config.save();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java
index daf4382719..1af42cb229 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java
@@ -171,7 +171,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase {
assertEquals(c2.getResult(), ReceiveCommand.Result.OK);
}
- File packed = new File(diskRepo.getDirectory(), "packed-refs");
+ File packed = new File(diskRepo.getCommonDirectory(), "packed-refs");
String packedStr = new String(Files.readAllBytes(packed.toPath()),
UTF_8);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
index 8baa3cc341..c57295518d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcPackRefsTest.java
@@ -58,7 +58,7 @@ public class GcPackRefsTest extends GcTestCase {
String ref = "dir/ref";
tr.branch(ref).commit().create();
String name = repo.findRef(ref).getName();
- Path dir = repo.getDirectory().toPath().resolve(name).getParent();
+ Path dir = repo.getCommonDirectory().toPath().resolve(name).getParent();
assertNotNull(dir);
gc.packRefs();
assertFalse(Files.exists(dir));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java
index e6c1ee5fd6..29f180d76b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcReflogTest.java
@@ -30,7 +30,7 @@ public class GcReflogTest extends GcTestCase {
BranchBuilder bb = tr.branch("refs/heads/master");
bb.commit().add("A", "A").add("B", "B").create();
bb.commit().add("A", "A2").add("B", "B2").create();
- new File(repo.getDirectory(), Constants.LOGS + "/refs/heads/master")
+ new File(repo.getCommonDirectory(), Constants.LOGS + "/refs/heads/master")
.delete();
stats = gc.getStatistics();
assertEquals(8, stats.numberOfLooseObjects);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
index 2bafde65d3..baa0182b87 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/RefDirectoryTest.java
@@ -90,25 +90,26 @@ public class RefDirectoryTest extends LocalDiskRepositoryTestCase {
@Test
public void testCreate() throws IOException {
// setUp above created the directory. We just have to test it.
- File d = diskRepo.getDirectory();
+ File gitDir = diskRepo.getDirectory();
+ File commonDir = diskRepo.getCommonDirectory();
assertSame(diskRepo, refdir.getRepository());
- assertTrue(new File(d, "refs").isDirectory());
- assertTrue(new File(d, "logs").isDirectory());
- assertTrue(new File(d, "logs/refs").isDirectory());
- assertFalse(new File(d, "packed-refs").exists());
+ assertTrue(new File(commonDir, "refs").isDirectory());
+ assertTrue(new File(commonDir, "logs").isDirectory());
+ assertTrue(new File(commonDir, "logs/refs").isDirectory());
+ assertFalse(new File(commonDir, "packed-refs").exists());
- assertTrue(new File(d, "refs/heads").isDirectory());
- assertTrue(new File(d, "refs/tags").isDirectory());
- assertEquals(2, new File(d, "refs").list().length);
- assertEquals(0, new File(d, "refs/heads").list().length);
- assertEquals(0, new File(d, "refs/tags").list().length);
+ assertTrue(new File(commonDir, "refs/heads").isDirectory());
+ assertTrue(new File(commonDir, "refs/tags").isDirectory());
+ assertEquals(2, new File(commonDir, "refs").list().length);
+ assertEquals(0, new File(commonDir, "refs/heads").list().length);
+ assertEquals(0, new File(commonDir, "refs/tags").list().length);
- assertTrue(new File(d, "logs/refs/heads").isDirectory());
- assertFalse(new File(d, "logs/HEAD").exists());
- assertEquals(0, new File(d, "logs/refs/heads").list().length);
+ assertTrue(new File(commonDir, "logs/refs/heads").isDirectory());
+ assertFalse(new File(gitDir, "logs/HEAD").exists());
+ assertEquals(0, new File(commonDir, "logs/refs/heads").list().length);
- assertEquals("ref: refs/heads/master\n", read(new File(d, HEAD)));
+ assertEquals("ref: refs/heads/master\n", read(new File(gitDir, HEAD)));
}
@Test(expected = UnsupportedOperationException.class)
@@ -1382,7 +1383,7 @@ public class RefDirectoryTest extends LocalDiskRepositoryTestCase {
}
private void deleteLooseRef(String name) {
- File path = new File(diskRepo.getDirectory(), name);
+ File path = new File(diskRepo.getCommonDirectory(), name);
assertTrue("deleted " + name, path.delete());
}
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java
index dc0e749373..eb521ff9eb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogReaderTest.java
@@ -238,7 +238,7 @@ public class ReflogReaderTest extends SampleDataRepositoryTestCase {
private void setupReflog(String logName, byte[] data)
throws FileNotFoundException, IOException {
- File logfile = new File(db.getDirectory(), logName);
+ File logfile = new File(db.getCommonDirectory(), logName);
if (!logfile.getParentFile().mkdirs()
&& !logfile.getParentFile().isDirectory()) {
throw new IOException(
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java
index 8d0e99dea0..8e9b7b84bd 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ReflogWriterTest.java
@@ -48,7 +48,7 @@ public class ReflogWriterTest extends SampleDataRepositoryTestCase {
private void readReflog(byte[] buffer)
throws FileNotFoundException, IOException {
- File logfile = new File(db.getDirectory(), "logs/refs/heads/master");
+ File logfile = new File(db.getCommonDirectory(), "logs/refs/heads/master");
if (!logfile.getParentFile().mkdirs()
&& !logfile.getParentFile().isDirectory()) {
throw new IOException(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
index 8fb5d60b85..401f069e4e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
@@ -176,7 +176,7 @@ public class SubmoduleAddCommand extends
CloneCommand clone = Git.cloneRepository();
configure(clone);
clone.setDirectory(moduleDirectory);
- clone.setGitDir(new File(new File(repo.getDirectory(),
+ clone.setGitDir(new File(new File(repo.getCommonDirectory(),
Constants.MODULES), path));
clone.setURI(resolvedUri);
if (monitor != null)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
index df73164161..751dabcd6b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
@@ -128,7 +128,7 @@ public class SubmoduleUpdateCommand extends
clone.setURI(url);
clone.setDirectory(generator.getDirectory());
clone.setGitDir(
- new File(new File(repo.getDirectory(), Constants.MODULES),
+ new File(new File(repo.getCommonDirectory(), Constants.MODULES),
generator.getPath()));
if (monitor != null) {
clone.setProgressMonitor(monitor);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index 6ae5153c12..fa0a82fd58 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -1647,6 +1647,8 @@ public class DirCacheCheckout {
filterProcessBuilder.directory(repo.getWorkTree());
filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY,
repo.getDirectory().getAbsolutePath());
+ filterProcessBuilder.environment().put(Constants.GIT_COMMON_DIR_KEY,
+ repo.getCommonDirectory().getAbsolutePath());
ExecutionResult result;
int rc;
try {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
index ed2516ddd0..80240e5062 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileReftableDatabase.java
@@ -68,14 +68,14 @@ public class FileReftableDatabase extends RefDatabase {
private final FileReftableStack reftableStack;
FileReftableDatabase(FileRepository repo) throws IOException {
- this(repo, new File(new File(repo.getDirectory(), Constants.REFTABLE),
+ this(repo, new File(new File(repo.getCommonDirectory(), Constants.REFTABLE),
Constants.TABLES_LIST));
}
FileReftableDatabase(FileRepository repo, File refstackName) throws IOException {
this.fileRepository = repo;
this.reftableStack = new FileReftableStack(refstackName,
- new File(fileRepository.getDirectory(), Constants.REFTABLE),
+ new File(fileRepository.getCommonDirectory(), Constants.REFTABLE),
() -> fileRepository.fireEvent(new RefsChangedEvent()),
() -> fileRepository.getConfig());
this.reftableDatabase = new ReftableDatabase() {
@@ -318,7 +318,7 @@ public class FileReftableDatabase extends RefDatabase {
@Override
public void create() throws IOException {
FileUtils.mkdir(
- new File(fileRepository.getDirectory(), Constants.REFTABLE),
+ new File(fileRepository.getCommonDirectory(), Constants.REFTABLE),
true);
}
@@ -615,7 +615,7 @@ public class FileReftableDatabase extends RefDatabase {
FileReftableDatabase newDb = null;
File reftableList = null;
try {
- File reftableDir = new File(repo.getDirectory(),
+ File reftableDir = new File(repo.getCommonDirectory(),
Constants.REFTABLE);
reftableList = new File(reftableDir, Constants.TABLES_LIST);
if (!reftableDir.isDirectory()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
index e5a00d3925..b5d29a3fc8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
@@ -165,7 +165,7 @@ public class FileRepository extends Repository {
throw new IOException(e.getMessage(), e);
}
repoConfig = new FileBasedConfig(userConfig, getFS().resolve(
- getDirectory(), Constants.CONFIG),
+ getCommonDirectory(), Constants.CONFIG),
getFS());
loadRepoConfig();
@@ -193,7 +193,7 @@ public class FileRepository extends Repository {
options.getObjectDirectory(), //
options.getAlternateObjectDirectories(), //
getFS(), //
- new File(getDirectory(), Constants.SHALLOW));
+ new File(getCommonDirectory(), Constants.SHALLOW));
if (objectDatabase.exists()) {
if (repositoryFormatVersion > 1)
@@ -622,16 +622,17 @@ public class FileRepository extends Repository {
* on IO problem
*/
void convertToPackedRefs(boolean writeLogs, boolean backup) throws IOException {
+ File commonDirectory = getCommonDirectory();
List<Ref> all = refs.getRefs();
- File packedRefs = new File(getDirectory(), Constants.PACKED_REFS);
+ File packedRefs = new File(commonDirectory, Constants.PACKED_REFS);
if (packedRefs.exists()) {
throw new IOException(MessageFormat.format(JGitText.get().fileAlreadyExists,
packedRefs.getName()));
}
- File refsFile = new File(getDirectory(), "refs"); //$NON-NLS-1$
+ File refsFile = new File(commonDirectory, "refs"); //$NON-NLS-1$
File refsHeadsFile = new File(refsFile, "heads");//$NON-NLS-1$
- File headFile = new File(getDirectory(), Constants.HEAD);
+ File headFile = new File(commonDirectory, Constants.HEAD);
FileReftableDatabase oldDb = (FileReftableDatabase) refs;
// Remove the dummy files that ensure compatibility with older git
@@ -701,7 +702,7 @@ public class FileRepository extends Repository {
}
if (!backup) {
- File reftableDir = new File(getDirectory(), Constants.REFTABLE);
+ File reftableDir = new File(commonDirectory, Constants.REFTABLE);
FileUtils.delete(reftableDir,
FileUtils.RECURSIVE | FileUtils.IGNORE_ERRORS);
}
@@ -730,8 +731,10 @@ public class FileRepository extends Repository {
@SuppressWarnings("nls")
void convertToReftable(boolean writeLogs, boolean backup)
throws IOException {
- File reftableDir = new File(getDirectory(), Constants.REFTABLE);
- File headFile = new File(getDirectory(), Constants.HEAD);
+ File commonDirectory = getCommonDirectory();
+ File directory = getDirectory();
+ File reftableDir = new File(commonDirectory, Constants.REFTABLE);
+ File headFile = new File(directory, Constants.HEAD);
if (reftableDir.exists() && FileUtils.hasFiles(reftableDir.toPath())) {
throw new IOException(JGitText.get().reftableDirExists);
}
@@ -739,28 +742,28 @@ public class FileRepository extends Repository {
// Ignore return value, as it is tied to temporary newRefs file.
FileReftableDatabase.convertFrom(this, writeLogs);
- File refsFile = new File(getDirectory(), "refs");
+ File refsFile = new File(commonDirectory, "refs");
// non-atomic: remove old data.
- File packedRefs = new File(getDirectory(), Constants.PACKED_REFS);
- File logsDir = new File(getDirectory(), Constants.LOGS);
+ File packedRefs = new File(commonDirectory, Constants.PACKED_REFS);
+ File logsDir = new File(commonDirectory, Constants.LOGS);
List<String> additional = getRefDatabase().getAdditionalRefs().stream()
.map(Ref::getName).collect(toList());
additional.add(Constants.HEAD);
if (backup) {
- FileUtils.rename(refsFile, new File(getDirectory(), "refs.old"));
+ FileUtils.rename(refsFile, new File(commonDirectory, "refs.old"));
if (packedRefs.exists()) {
- FileUtils.rename(packedRefs, new File(getDirectory(),
+ FileUtils.rename(packedRefs, new File(commonDirectory,
Constants.PACKED_REFS + ".old"));
}
if (logsDir.exists()) {
FileUtils.rename(logsDir,
- new File(getDirectory(), Constants.LOGS + ".old"));
+ new File(commonDirectory, Constants.LOGS + ".old"));
}
for (String r : additional) {
- FileUtils.rename(new File(getDirectory(), r),
- new File(getDirectory(), r + ".old"));
+ FileUtils.rename(new File(commonDirectory, r),
+ new File(commonDirectory, r + ".old"));
}
} else {
FileUtils.delete(packedRefs, FileUtils.SKIP_MISSING);
@@ -770,7 +773,7 @@ public class FileRepository extends Repository {
FileUtils.delete(refsFile,
FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
for (String r : additional) {
- new File(getDirectory(), r).delete();
+ new File(commonDirectory, r).delete();
}
}
@@ -784,7 +787,7 @@ public class FileRepository extends Repository {
// Some tools might write directly into .git/refs/heads/BRANCH. By
// putting a file here, this fails spectacularly.
- FileUtils.createNewFile(new File(refsFile, "heads"));
+ FileUtils.createNewFile(new File(refsFile, Constants.HEADS));
repoConfig.setString(ConfigConstants.CONFIG_EXTENSIONS_SECTION, null,
ConfigConstants.CONFIG_KEY_REF_STORAGE,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
index cf26f8d284..4fafc5a088 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
@@ -1047,7 +1047,7 @@ public class GC {
}
private void deleteEmptyRefsFolders() throws IOException {
- Path refs = repo.getDirectory().toPath().resolve(Constants.R_REFS);
+ Path refs = repo.getCommonDirectory().toPath().resolve(Constants.R_REFS);
// Avoid deleting a folder that was created after the threshold so that concurrent
// operations trying to create a reference are not impacted
Instant threshold = Instant.now().minus(30, ChronoUnit.SECONDS);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
index 628bf5db0c..8647b3e664 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
@@ -50,7 +50,7 @@ class GcLog {
*/
GcLog(FileRepository repo) {
this.repo = repo;
- logFile = new File(repo.getDirectory(), "gc.log"); //$NON-NLS-1$
+ logFile = new File(repo.getCommonDirectory(), "gc.log"); //$NON-NLS-1$
lock = new LockFile(logFile);
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
index 11d842b246..e8d442b8fb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/InfoAttributesNode.java
@@ -46,7 +46,7 @@ public class InfoAttributesNode extends AttributesNode {
FS fs = repository.getFS();
- File attributes = fs.resolve(repository.getDirectory(),
+ File attributes = fs.resolve(repository.getCommonDirectory(),
Constants.INFO_ATTRIBUTES);
FileRepository.AttributesNodeProviderImpl.loadRulesFromFile(r, attributes);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index 8e57bf9f2f..604868133e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
@@ -16,6 +16,7 @@ package org.eclipse.jgit.internal.storage.file;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.eclipse.jgit.lib.Constants.HEAD;
import static org.eclipse.jgit.lib.Constants.LOGS;
+import static org.eclipse.jgit.lib.Constants.L_LOGS;
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH;
import static org.eclipse.jgit.lib.Constants.PACKED_REFS;
import static org.eclipse.jgit.lib.Constants.R_HEADS;
@@ -124,6 +125,8 @@ public class RefDirectory extends RefDatabase {
private final File gitDir;
+ private final File gitCommonDir;
+
final File refsDir;
final File packedRefsFile;
@@ -188,6 +191,7 @@ public class RefDirectory extends RefDatabase {
RefDirectory(RefDirectory refDb) {
parent = refDb.parent;
gitDir = refDb.gitDir;
+ gitCommonDir = refDb.gitCommonDir;
refsDir = refDb.refsDir;
logsDir = refDb.logsDir;
logsRefsDir = refDb.logsRefsDir;
@@ -204,10 +208,11 @@ public class RefDirectory extends RefDatabase {
final FS fs = db.getFS();
parent = db;
gitDir = db.getDirectory();
- refsDir = fs.resolve(gitDir, R_REFS);
- logsDir = fs.resolve(gitDir, LOGS);
- logsRefsDir = fs.resolve(gitDir, LOGS + '/' + R_REFS);
- packedRefsFile = fs.resolve(gitDir, PACKED_REFS);
+ gitCommonDir = db.getCommonDirectory();
+ refsDir = fs.resolve(gitCommonDir, R_REFS);
+ logsDir = fs.resolve(gitCommonDir, LOGS);
+ logsRefsDir = fs.resolve(gitCommonDir, L_LOGS + R_REFS);
+ packedRefsFile = fs.resolve(gitCommonDir, PACKED_REFS);
looseRefs.set(RefList.<LooseRef> emptyList());
packedRefs.set(NO_PACKED_REFS);
@@ -1329,7 +1334,12 @@ public class RefDirectory extends RefDatabase {
name = name.substring(R_REFS.length());
return new File(refsDir, name);
}
- return new File(gitDir, name);
+ // HEAD needs to get resolved from git dir as resolving it from common dir
+ // would always lead back to current default branch
+ if (name.equals(HEAD)) {
+ return new File(gitDir, name);
+ }
+ return new File(gitCommonDir, name);
}
static int levelsIn(String name) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
index 21b5a54eb7..f1888eb90f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
@@ -10,6 +10,8 @@
package org.eclipse.jgit.internal.storage.file;
+import static org.eclipse.jgit.lib.Constants.HEAD;
+
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -37,7 +39,9 @@ class ReflogReaderImpl implements ReflogReader {
* {@code Ref} name
*/
ReflogReaderImpl(Repository db, String refname) {
- logName = new File(db.getDirectory(), Constants.LOGS + '/' + refname);
+ File logBaseDir = refname.equals(HEAD) ? db.getDirectory()
+ : db.getCommonDirectory();
+ logName = new File(logBaseDir, Constants.L_LOGS + refname);
}
/* (non-Javadoc)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
index 5dfb648faa..d232be6276 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java
@@ -13,13 +13,17 @@ package org.eclipse.jgit.lib;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BARE;
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WORKTREE;
+import static org.eclipse.jgit.lib.Constants.CONFIG;
import static org.eclipse.jgit.lib.Constants.DOT_GIT;
import static org.eclipse.jgit.lib.Constants.GIT_ALTERNATE_OBJECT_DIRECTORIES_KEY;
import static org.eclipse.jgit.lib.Constants.GIT_CEILING_DIRECTORIES_KEY;
+import static org.eclipse.jgit.lib.Constants.GIT_COMMON_DIR_KEY;
import static org.eclipse.jgit.lib.Constants.GIT_DIR_KEY;
import static org.eclipse.jgit.lib.Constants.GIT_INDEX_FILE_KEY;
import static org.eclipse.jgit.lib.Constants.GIT_OBJECT_DIRECTORY_KEY;
import static org.eclipse.jgit.lib.Constants.GIT_WORK_TREE_KEY;
+import static org.eclipse.jgit.lib.Constants.OBJECTS;
+import static org.eclipse.jgit.lib.Constants.GITDIR_FILE;
import java.io.File;
import java.io.IOException;
@@ -70,7 +74,21 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
&& ref[7] == ' ';
}
- private static File getSymRef(File workTree, File dotGit, FS fs)
+ /**
+ * Read symbolic reference file
+ *
+ * @param workTree
+ * the work tree path
+ * @param dotGit
+ * the .git file
+ * @param fs
+ * th FS util
+ * @return the file read from symbolic reference file
+ * @throws java.io.IOException
+ * the dotGit file is invalid reference
+ * @since 7.0
+ */
+ static File getSymRef(File workTree, File dotGit, FS fs)
throws IOException {
byte[] content = IO.readFully(dotGit);
if (!isSymRef(content)) {
@@ -102,6 +120,8 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
private File gitDir;
+ private File gitCommonDir;
+
private File objectDirectory;
private List<File> alternateObjectDirectories;
@@ -172,6 +192,30 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
}
/**
+ * Set common dir.
+ *
+ * @param gitCommonDir
+ * {@code GIT_COMMON_DIR}, the common repository meta directory.
+ * @return {@code this} (for chaining calls).
+ * @since 7.0
+ */
+ public B setGitCommonDir(File gitCommonDir) {
+ this.gitCommonDir = gitCommonDir;
+ this.config = null;
+ return self();
+ }
+
+ /**
+ * Get common dir.
+ *
+ * @return common dir; null if not set.
+ * @since 7.0
+ */
+ public File getGitCommonDir() {
+ return gitCommonDir;
+ }
+
+ /**
* Set the directory storing the repository's objects.
*
* @param objectDirectory
@@ -396,9 +440,9 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
* Read standard Git environment variables and configure from those.
* <p>
* This method tries to read the standard Git environment variables, such as
- * {@code GIT_DIR} and {@code GIT_WORK_TREE} to configure this builder
- * instance. If an environment variable is set, it overrides the value
- * already set in this builder.
+ * {@code GIT_DIR}, {@code GIT_COMMON_DIR}, {@code GIT_WORK_TREE} etc. to
+ * configure this builder instance. If an environment variable is set, it
+ * overrides the value already set in this builder.
*
* @return {@code this} (for chaining calls).
*/
@@ -410,9 +454,9 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
* Read standard Git environment variables and configure from those.
* <p>
* This method tries to read the standard Git environment variables, such as
- * {@code GIT_DIR} and {@code GIT_WORK_TREE} to configure this builder
- * instance. If a property is already set in the builder, the environment
- * variable is not used.
+ * {@code GIT_DIR}, {@code GIT_COMMON_DIR}, {@code GIT_WORK_TREE} etc. to
+ * configure this builder instance. If a property is already set in the
+ * builder, the environment variable is not used.
*
* @param sr
* the SystemReader abstraction to access the environment.
@@ -425,6 +469,13 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
setGitDir(new File(val));
}
+ if (getGitCommonDir() == null) {
+ String val = sr.getenv(GIT_COMMON_DIR_KEY);
+ if (val != null) {
+ setGitCommonDir(new File(val));
+ }
+ }
+
if (getObjectDirectory() == null) {
String val = sr.getenv(GIT_OBJECT_DIRECTORY_KEY);
if (val != null)
@@ -601,6 +652,7 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
public B setup() throws IllegalArgumentException, IOException {
requireGitDirOrWorkTree();
setupGitDir();
+ setupCommonDir();
setupWorkTree();
setupInternals();
return self();
@@ -658,6 +710,20 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
}
/**
+ * Perform standard common dir initialization.
+ *
+ * @throws java.io.IOException
+ * the repository could not be accessed
+ * @since 7.0
+ */
+ protected void setupCommonDir() throws IOException {
+ // no gitCommonDir? Try to get it from gitDir
+ if (getGitCommonDir() == null) {
+ setGitCommonDir(safeFS().getCommonDir(getGitDir()));
+ }
+ }
+
+ /**
* Perform standard work-tree initialization.
* <p>
* This is a method typically invoked inside of {@link #setup()}, near the
@@ -695,8 +761,12 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
* the repository could not be accessed
*/
protected void setupInternals() throws IOException {
- if (getObjectDirectory() == null && getGitDir() != null)
- setObjectDirectory(safeFS().resolve(getGitDir(), Constants.OBJECTS));
+ if (getObjectDirectory() == null) {
+ File commonDir = getGitCommonDir();
+ if (commonDir != null) {
+ setObjectDirectory(safeFS().resolve(commonDir, OBJECTS));
+ }
+ }
}
/**
@@ -723,12 +793,13 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
* the configuration is not available.
*/
protected Config loadConfig() throws IOException {
- if (getGitDir() != null) {
+ File commonDir = getGitCommonDir();
+ if (commonDir != null) {
// We only want the repository's configuration file, and not
// the user file, as these parameters must be unique to this
// repository and not inherited from other files.
//
- File path = safeFS().resolve(getGitDir(), Constants.CONFIG);
+ File path = safeFS().resolve(commonDir, CONFIG);
FileBasedConfig cfg = new FileBasedConfig(path, safeFS());
try {
cfg.load();
@@ -749,8 +820,29 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re
//
String path = cfg.getString(CONFIG_CORE_SECTION, null,
CONFIG_KEY_WORKTREE);
- if (path != null)
+ if (path != null) {
return safeFS().resolve(getGitDir(), path).getCanonicalFile();
+ }
+
+ /*
+ * We are in worktree's $GIT_DIR folder
+ * ".git/worktrees/&lt;worktree-name&gt;" and want to get the working
+ * tree (checkout) path; so here we have an opposite link in file
+ * "gitdir" showing to the ".git" file located in the working tree read
+ * it and convert it to absolute path if it's relative
+ */
+ File gitDirFile = new File(getGitDir(), GITDIR_FILE);
+ if (gitDirFile.isFile()) {
+ String workDirPath = new String(IO.readFully(gitDirFile)).trim();
+ File workTreeDotGitFile = new File(workDirPath);
+ if (!workTreeDotGitFile.isAbsolute()) {
+ workTreeDotGitFile = new File(getGitDir(), workDirPath)
+ .getCanonicalFile();
+ }
+ if (workTreeDotGitFile != null) {
+ return workTreeDotGitFile.getParentFile();
+ }
+ }
// If core.bare is set, honor its value. Assume workTree is
// the parent directory of the repository.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
index 1835dc76a2..b9c90bda30 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -273,6 +273,20 @@ public final class Constants {
public static final String INFO_REFS = "info/refs";
/**
+ * Name of heads folder or file in refs.
+ *
+ * @since 7.0
+ */
+ public static final String HEADS = "heads";
+
+ /**
+ * Prefix for any log.
+ *
+ * @since 7.0
+ */
+ public static final String L_LOGS = LOGS + "/";
+
+ /**
* Info alternates file (goes under OBJECTS)
* @since 5.5
*/
@@ -358,6 +372,14 @@ public final class Constants {
public static final String GIT_DIR_KEY = "GIT_DIR";
/**
+ * The environment variable that tells us which directory is the common
+ * ".git" directory.
+ *
+ * @since 7.0
+ */
+ public static final String GIT_COMMON_DIR_KEY = "GIT_COMMON_DIR";
+
+ /**
* The environment variable that tells us which directory is the working
* directory.
*/
@@ -459,6 +481,36 @@ public final class Constants {
public static final String GITDIR = "gitdir: ";
/**
+ * Name of the file (inside gitDir) that references the worktree's .git
+ * file (opposite link).
+ *
+ * .git/worktrees/&lt;worktree-name&gt;/gitdir
+ *
+ * A text file containing the absolute path back to the .git file that
+ * points here. This file is used to verify if the linked repository has been
+ * manually removed in which case this directory is no longer needed.
+ * The modification time (mtime) of this file should be updated each time
+ * the linked repository is accessed.
+ *
+ * @since 7.0
+ */
+ public static final String GITDIR_FILE = "gitdir";
+
+ /**
+ * Name of the file (inside gitDir) that has reference to $GIT_COMMON_DIR.
+ *
+ * .git/worktrees/&lt;worktree-name&gt;/commondir
+ *
+ * If this file exists, $GIT_COMMON_DIR will be set to the path specified in
+ * this file unless it is explicitly set. If the specified path is relative,
+ * it is relative to $GIT_DIR. The repository with commondir is incomplete
+ * without the repository pointed by "commondir".
+ *
+ * @since 7.0
+ */
+ public static final String COMMONDIR_FILE = "commondir";
+
+ /**
* Name of the folder (inside gitDir) where submodules are stored
*
* @since 3.6
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
index 8e965c5e9d..a99c64701f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -639,7 +639,7 @@ public class IndexDiff {
// submodule repository in .git/modules doesn't
// exist yet it isn't "missing".
File gitDir = new File(
- new File(repository.getDirectory(),
+ new File(repository.getCommonDirectory(),
Constants.MODULES),
subRepoPath);
if (!gitDir.isDirectory()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
index 4722e29b4c..9dde99fada 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -113,9 +113,12 @@ public abstract class Repository implements AutoCloseable {
final AtomicLong closedAt = new AtomicLong();
- /** Metadata directory holding the repository's critical files. */
+ /** $GIT_DIR: metadata directory holding the repository's critical files. */
private final File gitDir;
+ /** $GIT_COMMON_DIR: metadata directory holding the common repository's critical files. */
+ private final File gitCommonDir;
+
/** File abstraction used to resolve paths. */
private final FS fs;
@@ -137,6 +140,7 @@ public abstract class Repository implements AutoCloseable {
*/
protected Repository(BaseRepositoryBuilder options) {
gitDir = options.getGitDir();
+ gitCommonDir = options.getGitCommonDir();
fs = options.getFS();
workTree = options.getWorkTree();
indexFile = options.getIndexFile();
@@ -220,6 +224,16 @@ public abstract class Repository implements AutoCloseable {
public abstract String getIdentifier();
/**
+ * Get common dir.
+ *
+ * @return $GIT_COMMON_DIR: local common metadata directory;
+ * @since 7.0
+ */
+ public File getCommonDirectory() {
+ return gitCommonDir;
+ }
+
+ /**
* Get the object database which stores this repository's data.
*
* @return the object database which stores this repository's data.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
index 6288447a8d..18366541da 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryCache.java
@@ -450,10 +450,21 @@ public class RepositoryCache {
* Git directory.
*/
public static boolean isGitRepository(File dir, FS fs) {
- return fs.resolve(dir, Constants.OBJECTS).exists()
- && fs.resolve(dir, "refs").exists() //$NON-NLS-1$
- && (fs.resolve(dir, Constants.REFTABLE).exists()
- || isValidHead(new File(dir, Constants.HEAD)));
+ // check if common-dir available or fallback to git-dir
+ File commonDir;
+ try {
+ commonDir = fs.getCommonDir(dir);
+ } catch (IOException e) {
+ commonDir = null;
+ }
+ if (commonDir == null) {
+ commonDir = dir;
+ }
+ return fs.resolve(commonDir, Constants.OBJECTS).exists()
+ && fs.resolve(commonDir, "refs").exists() //$NON-NLS-1$
+ && (fs.resolve(commonDir, Constants.REFTABLE).exists()
+ || isValidHead(
+ new File(commonDir, Constants.HEAD)));
}
private static boolean isValidHead(File head) {
@@ -496,15 +507,31 @@ public class RepositoryCache {
* null if there is no suitable match.
*/
public static File resolve(File directory, FS fs) {
- if (isGitRepository(directory, fs))
+ // the folder itself
+ if (isGitRepository(directory, fs)) {
return directory;
- if (isGitRepository(new File(directory, Constants.DOT_GIT), fs))
- return new File(directory, Constants.DOT_GIT);
-
- final String name = directory.getName();
- final File parent = directory.getParentFile();
- if (isGitRepository(new File(parent, name + Constants.DOT_GIT_EXT), fs))
- return new File(parent, name + Constants.DOT_GIT_EXT);
+ }
+ // the .git subfolder or file (reference)
+ File dotDir = new File(directory, Constants.DOT_GIT);
+ if (dotDir.isFile()) {
+ try {
+ File refDir = BaseRepositoryBuilder.getSymRef(directory,
+ dotDir, fs);
+ if (refDir != null && isGitRepository(refDir, fs)) {
+ return refDir;
+ }
+ } catch (IOException ignored) {
+ // Continue searching if gitdir ref isn't found
+ }
+ } else if (isGitRepository(dotDir, fs)) {
+ return dotDir;
+ }
+ // the folder extended with .git (bare)
+ File bareDir = new File(directory.getParentFile(),
+ directory.getName() + Constants.DOT_GIT_EXT);
+ if (isGitRepository(bareDir, fs)) {
+ return bareDir;
+ }
return null;
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
index 0fc9710ecb..f77b04110d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportGitSsh.java
@@ -254,6 +254,12 @@ public class TransportGitSsh extends SshTransport implements PackTransport {
pb.environment().put(Constants.GIT_DIR_KEY,
directory.getPath());
}
+ File commonDirectory = local != null ? local.getCommonDirectory()
+ : null;
+ if (commonDirectory != null) {
+ pb.environment().put(Constants.GIT_COMMON_DIR_KEY,
+ commonDirectory.getPath());
+ }
return pb;
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java
index 3a06ce5b63..1b9431ce6e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java
@@ -225,6 +225,7 @@ class TransportLocal extends Transport implements PackTransport {
env.remove("GIT_CONFIG"); //$NON-NLS-1$
env.remove("GIT_CONFIG_PARAMETERS"); //$NON-NLS-1$
env.remove("GIT_DIR"); //$NON-NLS-1$
+ env.remove("GIT_COMMON_DIR"); //$NON-NLS-1$
env.remove("GIT_WORK_TREE"); //$NON-NLS-1$
env.remove("GIT_GRAFT_FILE"); //$NON-NLS-1$
env.remove("GIT_INDEX_FILE"); //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index 73a3ddaae7..95e9964192 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -498,6 +498,8 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
filterProcessBuilder.directory(repository.getWorkTree());
filterProcessBuilder.environment().put(Constants.GIT_DIR_KEY,
repository.getDirectory().getAbsolutePath());
+ filterProcessBuilder.environment().put(Constants.GIT_COMMON_DIR_KEY,
+ repository.getCommonDirectory().getAbsolutePath());
ExecutionResult result;
try {
result = fs.execute(filterProcessBuilder, in);
@@ -1332,7 +1334,7 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
IgnoreNode infoExclude = new IgnoreNodeWithParent(
coreExclude);
- File exclude = fs.resolve(repository.getDirectory(),
+ File exclude = fs.resolve(repository.getCommonDirectory(),
Constants.INFO_EXCLUDE);
if (fs.exists(exclude)) {
loadRulesFromFile(infoExclude, exclude);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index a8e1dae10e..6933a6c567 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -2042,6 +2042,8 @@ public abstract class FS {
environment.put(Constants.GIT_DIR_KEY,
repository.getDirectory().getAbsolutePath());
if (!repository.isBare()) {
+ environment.put(Constants.GIT_COMMON_DIR_KEY,
+ repository.getCommonDirectory().getAbsolutePath());
environment.put(Constants.GIT_WORK_TREE_KEY,
repository.getWorkTree().getAbsolutePath());
}
@@ -2137,7 +2139,7 @@ public abstract class FS {
case "post-receive": //$NON-NLS-1$
case "post-update": //$NON-NLS-1$
case "push-to-checkout": //$NON-NLS-1$
- return repository.getDirectory();
+ return repository.getCommonDirectory();
default:
return repository.getWorkTree();
}
@@ -2150,7 +2152,7 @@ public abstract class FS {
if (hooksDir != null) {
return new File(hooksDir);
}
- File dir = repository.getDirectory();
+ File dir = repository.getCommonDirectory();
return dir == null ? null : new File(dir, Constants.HOOKS);
}
@@ -2578,6 +2580,33 @@ public abstract class FS {
}
/**
+ * Get common dir path.
+ *
+ * @param dir
+ * the .git folder
+ * @return common dir path
+ * @throws IOException
+ * if commondir file can't be read
+ *
+ * @since 7.0
+ */
+ public File getCommonDir(File dir) throws IOException {
+ // first the GIT_COMMON_DIR is same as GIT_DIR
+ File commonDir = dir;
+ // now check if commondir file exists (e.g. worktree repository)
+ File commonDirFile = new File(dir, Constants.COMMONDIR_FILE);
+ if (commonDirFile.isFile()) {
+ String commonDirPath = new String(IO.readFully(commonDirFile))
+ .trim();
+ commonDir = new File(commonDirPath);
+ if (!commonDir.isAbsolute()) {
+ commonDir = new File(dir, commonDirPath).getCanonicalFile();
+ }
+ }
+ return commonDir;
+ }
+
+ /**
* This runnable will consume an input stream's content into an output
* stream as soon as it gets available.
* <p>