Add GitService with clone, list, branch, commit, push, pull

Implements all core Git operations using JGit with separate
worktree and git-dir paths. Includes comprehensive unit tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-02-26 08:41:25 +01:00
parent a7d03b3410
commit 239b5367a3
2 changed files with 408 additions and 0 deletions
@@ -0,0 +1,189 @@
package be.seeseepuff.webgit.service;
import be.seeseepuff.webgit.config.WebgitProperties;
import lombok.RequiredArgsConstructor;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Stream;
@Service
@RequiredArgsConstructor
public class GitService
{
private final WebgitProperties properties;
public void cloneRepository(String url, String name) throws GitAPIException, IOException
{
Path worktree = properties.getWorktreePath().resolve(name);
Path gitDir = properties.getGitDirPath().resolve(name);
Files.createDirectories(worktree);
Files.createDirectories(gitDir);
try (Git git = Git.cloneRepository()
.setURI(url)
.setDirectory(worktree.toFile())
.setGitDir(gitDir.toFile())
.call())
{
// clone complete
}
}
public List<String> listRepositories() throws IOException
{
Path gitDirBase = properties.getGitDirPath();
if (!Files.exists(gitDirBase))
return List.of();
try (Stream<Path> dirs = Files.list(gitDirBase))
{
return dirs
.filter(Files::isDirectory)
.map(p -> p.getFileName().toString())
.sorted()
.toList();
}
}
public List<String> listBranches(String name) throws IOException, GitAPIException
{
try (Git git = openRepository(name))
{
return git.branchList()
.call()
.stream()
.map(Ref::getName)
.map(ref -> ref.startsWith("refs/heads/") ? ref.substring("refs/heads/".length()) : ref)
.toList();
}
}
public String getCurrentBranch(String name) throws IOException
{
try (Git git = openRepository(name))
{
return git.getRepository().getBranch();
}
}
public void checkoutBranch(String name, String branch) throws IOException, GitAPIException
{
try (Git git = openRepository(name))
{
git.checkout()
.setName(branch)
.call();
}
}
public void createAndCheckoutBranch(String name, String branch) throws IOException, GitAPIException
{
try (Git git = openRepository(name))
{
git.checkout()
.setCreateBranch(true)
.setName(branch)
.call();
}
}
public List<String> getModifiedFiles(String name) throws IOException, GitAPIException
{
try (Git git = openRepository(name))
{
var status = git.status().call();
return Stream.of(
status.getModified().stream(),
status.getUntracked().stream(),
status.getMissing().stream()
)
.flatMap(s -> s)
.sorted()
.toList();
}
}
public List<String> getStagedFiles(String name) throws IOException, GitAPIException
{
try (Git git = openRepository(name))
{
var status = git.status().call();
return Stream.of(
status.getAdded().stream(),
status.getChanged().stream(),
status.getRemoved().stream()
)
.flatMap(s -> s)
.sorted()
.toList();
}
}
public void stageFiles(String name, List<String> files) throws IOException, GitAPIException
{
try (Git git = openRepository(name))
{
for (String file : files)
{
if (Files.exists(properties.getWorktreePath().resolve(name).resolve(file)))
{
git.add().addFilepattern(file).call();
}
else
{
git.rm().addFilepattern(file).call();
}
}
}
}
public void commit(String name, String message) throws IOException, GitAPIException
{
try (Git git = openRepository(name))
{
git.commit()
.setMessage(message)
.call();
}
}
public void push(String name) throws IOException, GitAPIException
{
try (Git git = openRepository(name))
{
git.push().call();
}
}
public void pull(String name) throws IOException, GitAPIException
{
try (Git git = openRepository(name))
{
git.pull().call();
}
}
private Git openRepository(String name) throws IOException
{
Path gitDir = properties.getGitDirPath().resolve(name);
Path worktree = properties.getWorktreePath().resolve(name);
Repository repo = new FileRepositoryBuilder()
.setGitDir(gitDir.toFile())
.setWorkTree(worktree.toFile())
.build();
return new Git(repo);
}
}