aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit
diff options
context:
space:
mode:
authorSimon Eder <simon.eclipse@hotmail.com>2024-07-31 16:21:46 +0200
committerThomas Wolf <twolf@apache.org>2024-12-11 21:58:54 +0100
commitdf7810957c00f3d857c006ff62ea7dd0e5b6fb76 (patch)
tree6003075c1450d87bd6f55585a1623573ac30e115 /org.eclipse.jgit
parent8dfb2a2465c8728649f6224ceab76ac9d8cca407 (diff)
downloadjgit-df7810957c00f3d857c006ff62ea7dd0e5b6fb76.tar.gz
jgit-df7810957c00f3d857c006ff62ea7dd0e5b6fb76.zip
Submodules: use relative paths for worktree and gitdir
Currently absolute paths are used for a submodules 'worktree' and 'gitdir'. This has drawbacks if a git repository containing submodules is copied to a different location. Enable using relative paths when creating a file-based repository. Add optional relative path support to the clone and init commands, and use it in the submodule commands to generate relative paths. The new implementation mimics the cgit behavior which also uses relative paths instead of absolute ones. Bug: jgit-78 Change-Id: I31c5a938d5cbc030d273fc649c94ee0c90b4ce01
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java17
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java23
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java5
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java7
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java44
5 files changed, 86 insertions, 10 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
index 3e034f1a6a..4a536b9534 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -67,6 +67,8 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> {
private boolean bare;
+ private boolean relativePaths;
+
private FS fs;
private String remote = Constants.DEFAULT_REMOTE_NAME;
@@ -264,6 +266,7 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> {
private Repository init() throws GitAPIException {
InitCommand command = Git.init();
command.setBare(bare);
+ command.setRelativeDirs(relativePaths);
if (fs != null) {
command.setFs(fs);
}
@@ -555,6 +558,20 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> {
}
/**
+ * Set whether the cloned repository shall use relative paths for GIT_DIR
+ * and GIT_WORK_TREE
+ *
+ * @param relativePaths
+ * if true, use relative paths for GIT_DIR and GIT_WORK_TREE
+ * @return this instance
+ * @since 7.2
+ */
+ public CloneCommand setRelativePaths(boolean relativePaths) {
+ this.relativePaths = relativePaths;
+ return this;
+ }
+
+ /**
* Set the file system abstraction to be used for repositories created by
* this command.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java
index 240290f4f9..1da71aa6eb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/InitCommand.java
@@ -19,6 +19,7 @@ import org.eclipse.jgit.api.errors.InvalidRefNameException;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.file.FileRepository;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
@@ -44,6 +45,8 @@ public class InitCommand implements Callable<Git> {
private String initialBranch;
+ private boolean relativePaths;
+
/**
* {@inheritDoc}
* <p>
@@ -100,7 +103,11 @@ public class InitCommand implements Callable<Git> {
: initialBranch);
Repository repository = builder.build();
if (!repository.getObjectDatabase().exists())
- repository.create(bare);
+ if (repository instanceof FileRepository) {
+ ((FileRepository) repository).create(bare, relativePaths);
+ } else {
+ repository.create(bare);
+ }
return new Git(repository, true);
} catch (IOException | ConfigInvalidException e) {
throw new JGitInternalException(e.getMessage(), e);
@@ -214,4 +221,18 @@ public class InitCommand implements Callable<Git> {
this.initialBranch = branch;
return this;
}
+
+ /**
+ * * Set whether the repository shall use relative paths for GIT_DIR and
+ * GIT_WORK_TREE
+ *
+ * @param relativePaths
+ * if true, use relative paths for GIT_DIR and GIT_WORK_TREE
+ * @return {@code this}
+ * @since 7.2
+ */
+ public InitCommand setRelativeDirs(boolean relativePaths) {
+ this.relativePaths = relativePaths;
+ return this;
+ }
}
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 401f069e4e..5105dfc2e5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleAddCommand.java
@@ -176,8 +176,9 @@ public class SubmoduleAddCommand extends
CloneCommand clone = Git.cloneRepository();
configure(clone);
clone.setDirectory(moduleDirectory);
- clone.setGitDir(new File(new File(repo.getCommonDirectory(),
- Constants.MODULES), path));
+ clone.setGitDir(new File(
+ new File(repo.getCommonDirectory(), Constants.MODULES), path));
+ clone.setRelativePaths(true);
clone.setURI(resolvedUri);
if (monitor != null)
clone.setProgressMonitor(monitor);
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 751dabcd6b..3524984347 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
@@ -127,9 +127,10 @@ public class SubmoduleUpdateCommand extends
configure(clone);
clone.setURI(url);
clone.setDirectory(generator.getDirectory());
- clone.setGitDir(
- new File(new File(repo.getCommonDirectory(), Constants.MODULES),
- generator.getPath()));
+ clone.setGitDir(new File(
+ new File(repo.getCommonDirectory(), Constants.MODULES),
+ generator.getPath()));
+ clone.setRelativePaths(true);
if (monitor != null) {
clone.setProgressMonitor(monitor);
}
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 84c85659ff..c5c36565d9 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
@@ -2,7 +2,7 @@
* 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 others
+ * Copyright (C) 2006-2024, Shawn O. Pearce <spearce@spearce.org> 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
@@ -215,6 +215,16 @@ public class FileRepository extends Repository {
}
}
+ private String getRelativeDir(File base, File other) {
+ File relPath;
+ try {
+ relPath = base.toPath().relativize(other.toPath()).toFile();
+ } catch (IllegalArgumentException e) {
+ relPath = other;
+ }
+ return FileUtils.pathToString(relPath);
+ }
+
/**
* {@inheritDoc}
* <p>
@@ -223,6 +233,22 @@ public class FileRepository extends Repository {
*/
@Override
public void create(boolean bare) throws IOException {
+ create(bare, false);
+ }
+
+ /**
+ * Create a new Git repository initializing the necessary files and
+ * directories.
+ *
+ * @param bare
+ * if true, a bare repository (a repository without a working
+ * directory) is created.
+ * @param relativePaths
+ * if true, relative paths are used for GIT_DIR and GIT_WORK_TREE
+ * @throws IOException
+ * in case of IO problem
+ */
+ public void create(boolean bare, boolean relativePaths) throws IOException {
final FileBasedConfig cfg = getConfig();
if (cfg.getFile().exists()) {
throw new IllegalStateException(MessageFormat.format(
@@ -293,15 +319,25 @@ public class FileRepository extends Repository {
if (!bare) {
File workTree = getWorkTree();
if (!getDirectory().getParentFile().equals(workTree)) {
+ String workTreePath;
+ String gitDirPath;
+ if (relativePaths) {
+ File canonGitDir = getDirectory().getCanonicalFile();
+ File canonWorkTree = getWorkTree().getCanonicalFile();
+ workTreePath = getRelativeDir(canonGitDir, canonWorkTree);
+ gitDirPath = getRelativeDir(canonWorkTree, canonGitDir);
+ } else {
+ workTreePath = getWorkTree().getAbsolutePath();
+ gitDirPath = getDirectory().getAbsolutePath();
+ }
cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
- ConfigConstants.CONFIG_KEY_WORKTREE, getWorkTree()
- .getAbsolutePath());
+ ConfigConstants.CONFIG_KEY_WORKTREE, workTreePath);
LockFile dotGitLockFile = new LockFile(new File(workTree,
Constants.DOT_GIT));
try {
if (dotGitLockFile.lock()) {
dotGitLockFile.write(Constants.encode(Constants.GITDIR
- + getDirectory().getAbsolutePath()));
+ + gitDirPath));
dotGitLockFile.commit();
}
} finally {