| /* |
| * 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()); |
| } |
| |
| } |