feat: 新增 Git 增量同步并补充中文注释
- 在 GitClientService 中新增增量同步入口 - 增量同步改为仅新增和覆盖文件,不删除仓库已有旧文件 - 抽取公共的 add/commit/push 提交流程 - 补充全量同步与增量同步的中文注释说明 - 新增测试覆盖增量同步保留旧文件的场景
This commit is contained in:
parent
c22eff8950
commit
3ff3cc89de
@ -1,7 +1,9 @@
|
|||||||
package com.ftptool.sync.service;
|
package com.ftptool.sync.service;
|
||||||
|
|
||||||
import com.ftptool.sync.config.GitRepoProperties;
|
import com.ftptool.sync.config.GitRepoProperties;
|
||||||
|
import com.ftptool.sync.util.FileHashUtils;
|
||||||
import com.ftptool.sync.util.FileTreeUtils;
|
import com.ftptool.sync.util.FileTreeUtils;
|
||||||
|
import org.eclipse.jgit.api.CreateBranchCommand;
|
||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.api.ListBranchCommand;
|
import org.eclipse.jgit.api.ListBranchCommand;
|
||||||
import org.eclipse.jgit.api.Status;
|
import org.eclipse.jgit.api.Status;
|
||||||
@ -23,15 +25,17 @@ import java.nio.file.Path;
|
|||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Service
|
|
||||||
/**
|
/**
|
||||||
* Git 客户端服务。
|
* Git 客户端服务,负责仓库准备、分支切换、快照导出以及内容回写。
|
||||||
* 负责 clone / pull / checkout / commit / push 等仓库操作。
|
|
||||||
*/
|
*/
|
||||||
|
@Service
|
||||||
public class GitClientService {
|
public class GitClientService {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(GitClientService.class);
|
private static final Logger log = LoggerFactory.getLogger(GitClientService.class);
|
||||||
@ -44,11 +48,11 @@ public class GitClientService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 准备仓库并返回指定分支当前 HEAD。
|
* 准备本地仓库并返回目标分支当前 HEAD。
|
||||||
*/
|
*/
|
||||||
public String prepareRepositoryAndGetHead(String branch) throws IOException, GitAPIException {
|
public String prepareRepositoryAndGetHead(String branch) throws IOException, GitAPIException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
// 同一套本地仓库会被多个定时任务复用,这里串行化避免分支切换互相踩工作区。
|
// 同一份本地仓库会被多个任务复用,这里串行化避免分支切换互相污染工作区。
|
||||||
try (Git git = openOrCloneRepository()) {
|
try (Git git = openOrCloneRepository()) {
|
||||||
checkoutBranch(git, branch);
|
checkoutBranch(git, branch);
|
||||||
pullIfRemoteBranchExists(git, branch);
|
pullIfRemoteBranchExists(git, branch);
|
||||||
@ -62,7 +66,7 @@ public class GitClientService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 列出远端所有匹配正则的版本分支名。
|
* 拉取远端分支列表,并返回匹配正则的分支名。
|
||||||
*/
|
*/
|
||||||
public List<String> listMatchingBranches(String branchRegex) throws IOException, GitAPIException {
|
public List<String> listMatchingBranches(String branchRegex) throws IOException, GitAPIException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
@ -97,14 +101,13 @@ public class GitClientService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出指定分支的工作树快照,供后续打包或哈希计算使用。
|
* 导出指定分支的工作区快照,显式排除 .git 目录。
|
||||||
*/
|
*/
|
||||||
public Path exportBranchSnapshot(String branch, Path targetDirectory) throws IOException, GitAPIException {
|
public Path exportBranchSnapshot(String branch, Path targetDirectory) throws IOException, GitAPIException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try (Git git = openOrCloneRepository()) {
|
try (Git git = openOrCloneRepository()) {
|
||||||
checkoutBranch(git, branch);
|
checkoutBranch(git, branch);
|
||||||
pullIfRemoteBranchExists(git, branch);
|
pullIfRemoteBranchExists(git, branch);
|
||||||
// 导出纯工作树内容,显式排除 .git,避免把仓库内部文件带入同步包。
|
|
||||||
FileTreeUtils.deleteRecursively(targetDirectory);
|
FileTreeUtils.deleteRecursively(targetDirectory);
|
||||||
FileTreeUtils.ensureDirectory(targetDirectory);
|
FileTreeUtils.ensureDirectory(targetDirectory);
|
||||||
copyWorkingTreeWithoutGit(getRepositoryPath(), targetDirectory);
|
copyWorkingTreeWithoutGit(getRepositoryPath(), targetDirectory);
|
||||||
@ -113,7 +116,22 @@ public class GitClientService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 全量同步:用 sourceDirectory 整体覆盖目标分支工作区内容。
|
||||||
|
*/
|
||||||
public boolean syncDirectoryToBranch(Path sourceDirectory, String branch, String message) throws IOException, GitAPIException {
|
public boolean syncDirectoryToBranch(Path sourceDirectory, String branch, String message) throws IOException, GitAPIException {
|
||||||
|
return syncDirectoryToBranch(sourceDirectory, branch, message, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增量同步:只新增或覆盖 sourceDirectory 中出现的文件,不删除仓库中已有旧文件。
|
||||||
|
*/
|
||||||
|
public boolean syncDirectoryToBranchIncrementally(Path sourceDirectory, String branch, String message) throws IOException, GitAPIException {
|
||||||
|
return syncDirectoryToBranch(sourceDirectory, branch, message, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean syncDirectoryToBranch(Path sourceDirectory, String branch, String message, boolean incrementalUpdate)
|
||||||
|
throws IOException, GitAPIException {
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
try (Git git = openOrCloneRepository()) {
|
try (Git git = openOrCloneRepository()) {
|
||||||
checkoutBranch(git, branch);
|
checkoutBranch(git, branch);
|
||||||
@ -121,35 +139,22 @@ public class GitClientService {
|
|||||||
if (!Files.exists(repositoryPath.resolve(".git"))) {
|
if (!Files.exists(repositoryPath.resolve(".git"))) {
|
||||||
throw new IOException("Git repository does not exist: " + repositoryPath);
|
throw new IOException("Git repository does not exist: " + repositoryPath);
|
||||||
}
|
}
|
||||||
// 生产快照回写采用“整目录覆盖”语义,确保 Git 分支内容与当前生产快照一致。
|
|
||||||
FileTreeUtils.deleteChildrenExcept(repositoryPath, ".git");
|
// 统一走同一套提交与推送流程,只区分工作区内容如何写入。
|
||||||
FileTreeUtils.copyDirectory(sourceDirectory, repositoryPath);
|
if (incrementalUpdate) {
|
||||||
git.add().addFilepattern(".").call();
|
applyIncrementalWorkingTreeSync(sourceDirectory, repositoryPath, branch);
|
||||||
git.add().setUpdate(true).addFilepattern(".").call();
|
} else {
|
||||||
Status status = git.status().call();
|
replaceWorkingTree(sourceDirectory, repositoryPath);
|
||||||
if (status.isClean()) {
|
|
||||||
log.info("No Git changes detected on branch {}", branch);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
PersonIdent personIdent = new PersonIdent(
|
|
||||||
gitRepoProperties.getCommitAuthorName(),
|
return commitAndPushIfNeeded(git, branch, message);
|
||||||
gitRepoProperties.getCommitAuthorEmail()
|
|
||||||
);
|
|
||||||
git.commit()
|
|
||||||
.setMessage(message)
|
|
||||||
.setAuthor(personIdent)
|
|
||||||
.setCommitter(personIdent)
|
|
||||||
.call();
|
|
||||||
git.push()
|
|
||||||
.setCredentialsProvider(credentialsProvider())
|
|
||||||
.setRemote("origin")
|
|
||||||
.setRefSpecs(new RefSpec("refs/heads/" + branch + ":refs/heads/" + branch))
|
|
||||||
.call();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地仓库不存在时先 clone,存在时直接打开。
|
||||||
|
*/
|
||||||
private Git openOrCloneRepository() throws IOException, GitAPIException {
|
private Git openOrCloneRepository() throws IOException, GitAPIException {
|
||||||
Path repositoryPath = getRepositoryPath();
|
Path repositoryPath = getRepositoryPath();
|
||||||
if (Files.exists(repositoryPath.resolve(".git"))) {
|
if (Files.exists(repositoryPath.resolve(".git"))) {
|
||||||
@ -164,7 +169,7 @@ public class GitClientService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 切换到目标分支,不存在时按远端或本地新建分支。
|
* 切换到目标分支;若本地分支不存在,则优先跟踪远端同名分支。
|
||||||
*/
|
*/
|
||||||
private void checkoutBranch(Git git, String branch) throws GitAPIException, IOException {
|
private void checkoutBranch(Git git, String branch) throws GitAPIException, IOException {
|
||||||
Repository repository = git.getRepository();
|
Repository repository = git.getRepository();
|
||||||
@ -172,12 +177,11 @@ public class GitClientService {
|
|||||||
Ref remoteRef = repository.findRef("refs/remotes/origin/" + branch);
|
Ref remoteRef = repository.findRef("refs/remotes/origin/" + branch);
|
||||||
if (localRef == null) {
|
if (localRef == null) {
|
||||||
if (remoteRef != null) {
|
if (remoteRef != null) {
|
||||||
// 本地不存在分支时优先跟踪远端分支,保持与仓库约定一致。
|
|
||||||
git.checkout()
|
git.checkout()
|
||||||
.setCreateBranch(true)
|
.setCreateBranch(true)
|
||||||
.setName(branch)
|
.setName(branch)
|
||||||
.setStartPoint("origin/" + branch)
|
.setStartPoint("origin/" + branch)
|
||||||
.setUpstreamMode(org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode.TRACK)
|
.setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK)
|
||||||
.call();
|
.call();
|
||||||
} else {
|
} else {
|
||||||
git.checkout()
|
git.checkout()
|
||||||
@ -190,11 +194,14 @@ public class GitClientService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅在远端分支存在时执行 pull,避免首次本地新建分支时出现无意义拉取。
|
||||||
|
*/
|
||||||
private void pullIfRemoteBranchExists(Git git, String branch) throws GitAPIException, IOException {
|
private void pullIfRemoteBranchExists(Git git, String branch) throws GitAPIException, IOException {
|
||||||
Repository repository = git.getRepository();
|
Repository repository = git.getRepository();
|
||||||
Ref remoteRef = repository.findRef("refs/remotes/origin/" + branch);
|
Ref remoteRef = repository.findRef("refs/remotes/origin/" + branch);
|
||||||
if (remoteRef == null) {
|
if (remoteRef == null) {
|
||||||
// 首次启动时本地未必有远端分支缓存,先显式 fetch 一次。
|
// 本地未必已有远端分支缓存,先显式 fetch 一次再判断。
|
||||||
git.fetch()
|
git.fetch()
|
||||||
.setCredentialsProvider(credentialsProvider())
|
.setCredentialsProvider(credentialsProvider())
|
||||||
.setRemote("origin")
|
.setRemote("origin")
|
||||||
@ -219,7 +226,96 @@ public class GitClientService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 复制仓库工作树内容,显式排除 .git 目录。
|
* 全量覆盖工作区,仅保留仓库元数据目录 .git。
|
||||||
|
*/
|
||||||
|
private void replaceWorkingTree(Path sourceDirectory, Path repositoryPath) throws IOException {
|
||||||
|
FileTreeUtils.deleteChildrenExcept(repositoryPath, ".git");
|
||||||
|
FileTreeUtils.copyDirectory(sourceDirectory, repositoryPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增量写入工作区:
|
||||||
|
* 1. 源目录中不存在的仓库文件保持不动;
|
||||||
|
* 2. 源目录中新增的文件复制到仓库;
|
||||||
|
* 3. 同一路径内容变化时执行覆盖。
|
||||||
|
*/
|
||||||
|
private void applyIncrementalWorkingTreeSync(Path sourceDirectory, Path repositoryPath, String branch) throws IOException {
|
||||||
|
Map<Path, String> sourceFileHashes = collectRelativeFileHashes(sourceDirectory, true);
|
||||||
|
Map<Path, String> repositoryFileHashes = collectRelativeFileHashes(repositoryPath, true);
|
||||||
|
|
||||||
|
List<Path> filesToCopy = new ArrayList<Path>();
|
||||||
|
for (Map.Entry<Path, String> sourceFile : sourceFileHashes.entrySet()) {
|
||||||
|
String repositoryHash = repositoryFileHashes.get(sourceFile.getKey());
|
||||||
|
if (repositoryHash == null || !repositoryHash.equals(sourceFile.getValue())) {
|
||||||
|
filesToCopy.add(sourceFile.getKey());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!filesToCopy.isEmpty()) {
|
||||||
|
// copySelectedFiles 内部使用 REPLACE_EXISTING,因此同路径文件会被覆盖。
|
||||||
|
log.info(
|
||||||
|
"Applying incremental Git sync on branch {}. copyCount={}",
|
||||||
|
branch,
|
||||||
|
filesToCopy.size()
|
||||||
|
);
|
||||||
|
FileTreeUtils.copySelectedFiles(sourceDirectory, repositoryPath, filesToCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工作区有变更时统一执行 add / commit / push;无变更时直接返回 false。
|
||||||
|
*/
|
||||||
|
private boolean commitAndPushIfNeeded(Git git, String branch, String message) throws GitAPIException {
|
||||||
|
git.add().addFilepattern(".").call();
|
||||||
|
git.add().setUpdate(true).addFilepattern(".").call();
|
||||||
|
Status status = git.status().call();
|
||||||
|
if (status.isClean()) {
|
||||||
|
log.info("No Git changes detected on branch {}", branch);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PersonIdent personIdent = new PersonIdent(
|
||||||
|
gitRepoProperties.getCommitAuthorName(),
|
||||||
|
gitRepoProperties.getCommitAuthorEmail()
|
||||||
|
);
|
||||||
|
git.commit()
|
||||||
|
.setMessage(message)
|
||||||
|
.setAuthor(personIdent)
|
||||||
|
.setCommitter(personIdent)
|
||||||
|
.call();
|
||||||
|
git.push()
|
||||||
|
.setCredentialsProvider(credentialsProvider())
|
||||||
|
.setRemote("origin")
|
||||||
|
.setRefSpecs(new RefSpec("refs/heads/" + branch + ":refs/heads/" + branch))
|
||||||
|
.call();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 收集目录下普通文件的相对路径与内容哈希,用于判断是否需要复制。
|
||||||
|
*/
|
||||||
|
private Map<Path, String> collectRelativeFileHashes(Path rootDirectory, boolean excludeGitDirectory) throws IOException {
|
||||||
|
Map<Path, String> fileHashes = new LinkedHashMap<Path, String>();
|
||||||
|
try (Stream<Path> stream = Files.walk(rootDirectory)) {
|
||||||
|
List<Path> files = stream
|
||||||
|
.filter(Files::isRegularFile)
|
||||||
|
.filter(path -> !excludeGitDirectory || !isGitInternalPath(rootDirectory, path))
|
||||||
|
.sorted()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
for (Path file : files) {
|
||||||
|
fileHashes.put(rootDirectory.relativize(file), FileHashUtils.sha256(file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fileHashes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isGitInternalPath(Path rootDirectory, Path path) {
|
||||||
|
Path relativePath = rootDirectory.relativize(path);
|
||||||
|
return relativePath.getNameCount() > 0 && ".git".equals(relativePath.getName(0).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出工作区内容时跳过 .git,避免把仓库元数据带入外部目录。
|
||||||
*/
|
*/
|
||||||
private void copyWorkingTreeWithoutGit(Path repositoryPath, Path targetDirectory) throws IOException {
|
private void copyWorkingTreeWithoutGit(Path repositoryPath, Path targetDirectory) throws IOException {
|
||||||
try (Stream<Path> stream = Files.list(repositoryPath)) {
|
try (Stream<Path> stream = Files.list(repositoryPath)) {
|
||||||
|
|||||||
126
src/test/java/com/ftptool/sync/service/GitClientServiceTest.java
Normal file
126
src/test/java/com/ftptool/sync/service/GitClientServiceTest.java
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
package com.ftptool.sync.service;
|
||||||
|
|
||||||
|
import com.ftptool.sync.config.GitRepoProperties;
|
||||||
|
import org.eclipse.jgit.api.CreateBranchCommand;
|
||||||
|
import org.eclipse.jgit.api.Git;
|
||||||
|
import org.eclipse.jgit.lib.PersonIdent;
|
||||||
|
import org.eclipse.jgit.transport.RefSpec;
|
||||||
|
import org.eclipse.jgit.transport.URIish;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
class GitClientServiceTest {
|
||||||
|
|
||||||
|
@TempDir
|
||||||
|
Path tempDir;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldSyncDirectoryToBranchIncrementallyWithoutDeletingExistingFiles() throws Exception {
|
||||||
|
Path remoteRepository = tempDir.resolve("remote.git");
|
||||||
|
Path localRepository = tempDir.resolve("local-repo");
|
||||||
|
initializeRemoteRepository(remoteRepository);
|
||||||
|
|
||||||
|
GitClientService gitClientService = new GitClientService(buildProperties(remoteRepository, localRepository));
|
||||||
|
|
||||||
|
Path initialSource = tempDir.resolve("source-initial");
|
||||||
|
writeFile(initialSource, "same.txt", "same");
|
||||||
|
writeFile(initialSource, "changed.txt", "before");
|
||||||
|
writeFile(initialSource, "deleted/nested.txt", "remove");
|
||||||
|
|
||||||
|
assertTrue(gitClientService.syncDirectoryToBranchIncrementally(initialSource, "feature/incremental", "initial"));
|
||||||
|
|
||||||
|
Path incrementalSource = tempDir.resolve("source-incremental");
|
||||||
|
writeFile(incrementalSource, "same.txt", "same");
|
||||||
|
writeFile(incrementalSource, "changed.txt", "after");
|
||||||
|
writeFile(incrementalSource, "added/new.txt", "new");
|
||||||
|
|
||||||
|
assertTrue(gitClientService.syncDirectoryToBranchIncrementally(
|
||||||
|
incrementalSource,
|
||||||
|
"feature/incremental",
|
||||||
|
"incremental update"
|
||||||
|
));
|
||||||
|
assertFalse(gitClientService.syncDirectoryToBranchIncrementally(
|
||||||
|
incrementalSource,
|
||||||
|
"feature/incremental",
|
||||||
|
"no-op update"
|
||||||
|
));
|
||||||
|
|
||||||
|
Path verifyDirectory = tempDir.resolve("verify");
|
||||||
|
checkoutRemoteBranch(remoteRepository, "feature/incremental", verifyDirectory);
|
||||||
|
|
||||||
|
assertEquals("same", readFile(verifyDirectory, "same.txt"));
|
||||||
|
assertEquals("after", readFile(verifyDirectory, "changed.txt"));
|
||||||
|
assertEquals("new", readFile(verifyDirectory, "added/new.txt"));
|
||||||
|
assertEquals("remove", readFile(verifyDirectory, "deleted/nested.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private GitRepoProperties buildProperties(Path remoteRepository, Path localRepository) {
|
||||||
|
GitRepoProperties properties = new GitRepoProperties();
|
||||||
|
properties.setRemoteUri(remoteRepository.toUri().toString());
|
||||||
|
properties.setLocalPath(localRepository.toString());
|
||||||
|
properties.setUsername("");
|
||||||
|
properties.setPassword("");
|
||||||
|
properties.setCommitAuthorName("tester");
|
||||||
|
properties.setCommitAuthorEmail("tester@example.com");
|
||||||
|
properties.setPullRebase(false);
|
||||||
|
return properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeRemoteRepository(Path remoteRepository) throws Exception {
|
||||||
|
try (Git ignored = Git.init().setBare(true).setDirectory(remoteRepository.toFile()).call()) {
|
||||||
|
// Bare repository only needs to exist here.
|
||||||
|
}
|
||||||
|
|
||||||
|
Path seedRepository = tempDir.resolve("seed-repo");
|
||||||
|
try (Git git = Git.init().setDirectory(seedRepository.toFile()).call()) {
|
||||||
|
writeFile(seedRepository, "README.md", "seed");
|
||||||
|
git.add().addFilepattern(".").call();
|
||||||
|
PersonIdent author = new PersonIdent("tester", "tester@example.com");
|
||||||
|
git.commit()
|
||||||
|
.setMessage("seed")
|
||||||
|
.setAuthor(author)
|
||||||
|
.setCommitter(author)
|
||||||
|
.call();
|
||||||
|
git.remoteAdd()
|
||||||
|
.setName("origin")
|
||||||
|
.setUri(new URIish(remoteRepository.toUri().toString()))
|
||||||
|
.call();
|
||||||
|
git.push()
|
||||||
|
.setRemote("origin")
|
||||||
|
.setRefSpecs(new RefSpec("refs/heads/master:refs/heads/master"))
|
||||||
|
.call();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkoutRemoteBranch(Path remoteRepository, String branch, Path workingDirectory) throws Exception {
|
||||||
|
try (Git git = Git.cloneRepository()
|
||||||
|
.setURI(remoteRepository.toUri().toString())
|
||||||
|
.setDirectory(workingDirectory.toFile())
|
||||||
|
.call()) {
|
||||||
|
git.checkout()
|
||||||
|
.setCreateBranch(true)
|
||||||
|
.setName(branch)
|
||||||
|
.setStartPoint("origin/" + branch)
|
||||||
|
.setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK)
|
||||||
|
.call();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeFile(Path root, String relativePath, String content) throws Exception {
|
||||||
|
Path file = root.resolve(relativePath);
|
||||||
|
Files.createDirectories(file.getParent());
|
||||||
|
Files.write(file, content.getBytes(StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readFile(Path root, String relativePath) throws Exception {
|
||||||
|
return new String(Files.readAllBytes(root.resolve(relativePath)), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user