-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Based on deritative work done in Andre's work in [1]. This change focuses on adding support for reading the repository state when branches are checked out using git's worktrees. I've refactored original work by removing all unrelevant changes which were mostly around refactoring to extract i.e. constants which mostly created noise for a review. I've tried to address original review comments: - Not adding non-behavioral changes - "HEAD" should get resolved from gitDir - Reftable recently landed in cgit 2.45, see https://github.com/git/git/blob/master/Documentation/RelNotes/2.45.0.txt#L8 We can add worktree support for reftable in a later change. - Some new tests to read from a linked worktree which is created manually as there's no write support. [1] https://git.eclipse.org/r/c/jgit/jgit/+/163940/18 Change-Id: Id077d58fb6c09ecb090eb09d5dbc7edc351a581d
- Loading branch information
Showing
29 changed files
with
520 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
192 changes: 192 additions & 0 deletions
192
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/LinkedWorktreeTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.