Java 手写一个代码管理工具 要求有pull push branch相关功能
Java代码管理工具实现,包含pullpush和branch等基本功能。这个工具模拟了Git的核心概念,使用文件系统存储数据。
·
Java代码管理工具实现,包含pull、push和branch等基本功能。这个工具模拟了Git的核心概念,使用文件系统存储数据。
import java.io.*;
import java.nio.file.*;
import java.security.MessageDigest;
import java.util.*;
import java.util.stream.Collectors;
public class MiniGit {
private static final String GIT_DIR = ".minigit";
private static final String HEAD_FILE = GIT_DIR + "/HEAD";
private static final String OBJECTS_DIR = GIT_DIR + "/objects";
private static final String REFS_DIR = GIT_DIR + "/refs/heads";
private static final String REMOTE_DIR = GIT_DIR + "/remote";
public static void main(String[] args) throws Exception {
if (args.length < 1) {
System.err.println("Usage: java MiniGit <command> [args]");
return;
}
switch (args[0]) {
case "init" -> init();
case "commit" -> {
if (args.length < 2) commit(args[1]);
else System.err.println("Commit message required");
}
case "branch" -> {
if (args.length >= 2) branch(args[1]);
else listBranches();
}
case "checkout" -> {
if (args.length >= 2) checkout(args[1]);
else System.err.println("Branch name required");
}
case "push" -> push();
case "pull" -> pull();
default -> System.err.println("Unknown command: " + args[0]);
}
}
// 初始化仓库
private static void init() throws IOException {
Files.createDirectories(Paths.get(OBJECTS_DIR));
Files.createDirectories(Paths.get(REFS_DIR));
Files.createDirectories(Paths.get(REMOTE_DIR));
setHead("main");
branch("main"); // 创建默认分支
System.out.println("Initialized empty MiniGit repository");
}
// 创建提交
private static void commit(String message) throws Exception {
String branch = getCurrentBranch();
String parent = getBranchCommit(branch);
// 创建树对象
String treeHash = createTreeObject();
// 创建提交对象
String commit = createCommitObject(treeHash, parent, message);
// 更新分支引用
updateBranchRef(branch, commit);
System.out.println("[" + branch + " " + commit.substring(0, 6) + "] " + message);
}
// 创建/列出分支
private static void branch(String name) throws IOException {
Path branchPath = Paths.get(REFS_DIR, name);
if (!Files.exists(branchPath)) {
String commit = getCurrentCommit();
Files.write(branchPath, commit.getBytes());
System.out.println("Created branch: " + name);
} else {
System.err.println("Branch already exists: " + name);
}
}
private static void listBranches() throws IOException {
String current = getCurrentBranch();
try (var stream = Files.list(Paths.get(REFS_DIR))) {
stream.map(Path::getFileName)
.forEach(p -> System.out.println((p.toString().equals(current) ? "* " : " ") + p));
}
}
// 切换分支
private static void checkout(String branch) throws IOException {
Path branchPath = Paths.get(REFS_DIR, branch);
if (!Files.exists(branchPath)) {
System.err.println("Branch not found: " + branch);
return;
}
String commit = Files.readString(branchPath).trim();
restoreCommit(commit);
setHead(branch);
System.out.println("Switched to branch: " + branch);
}
// 推送到远程
private static void push() throws IOException {
String branch = getCurrentBranch();
String commit = getCurrentCommit();
// 模拟远程存储
Path remoteBranch = Paths.get(REMOTE_DIR, branch);
Files.createDirectories(remoteBranch.getParent());
Files.write(remoteBranch, commit.getBytes());
System.out.println("Pushed " + branch + " to remote (" + commit.substring(0, 6) + ")");
}
// 从远程拉取
private static void pull() throws IOException {
String branch = getCurrentBranch();
Path remoteBranch = Paths.get(REMOTE_DIR, branch);
if (!Files.exists(remoteBranch)) {
System.err.println("Remote branch not found: " + branch);
return;
}
String remoteCommit = Files.readString(remoteBranch).trim();
restoreCommit(remoteCommit);
updateBranchRef(branch, remoteCommit);
System.out.println("Updated " + branch + " to " + remoteCommit.substring(0, 6));
}
// ===== 核心工具方法 =====
private static String createTreeObject() throws Exception {
StringBuilder tree = new StringBuilder();
try (var stream = Files.list(Paths.get(""))) {
for (Path file : stream.filter(Files::isRegularFile).toList()) {
if (file.toString().equals(GIT_DIR)) continue;
byte[] content = Files.readAllBytes(file);
String hash = hashObject(content);
tree.append(file.getFileName()).append(" ").append(hash).append("\n");
}
}
return writeObject("tree", tree.toString().getBytes());
}
private static String createCommitObject(String tree, String parent, String message) throws Exception {
String commit = "tree " + tree + "\n" +
(parent != null ? "parent " + parent + "\n" : "") +
"message " + message + "\n";
return writeObject("commit", commit.getBytes());
}
private static void restoreCommit(String commitHash) throws Exception {
byte[] data = readObject(commitHash);
String content = new String(data);
// 恢复文件
for (String line : content.split("\n")) {
if (line.startsWith("tree")) {
String treeHash = line.split(" ")[1];
restoreTree(treeHash);
}
}
}
private static void restoreTree(String treeHash) throws Exception {
byte[] data = readObject(treeHash);
for (String line : new String(data).split("\n")) {
String[] parts = line.split(" ");
if (parts.length == 2) {
Path file = Paths.get(parts[0]);
byte[] content = readObject(parts[1]);
Files.write(file, content);
}
}
}
private static String writeObject(String type, byte[] data) throws Exception {
String hash = hashObject(data);
Path objectPath = Paths.get(OBJECTS_DIR, hash);
Files.write(objectPath, (type + " " + data.length + "\n").getBytes());
Files.write(objectPath, data, StandardOpenOption.APPEND);
return hash;
}
private static byte[] readObject(String hash) throws IOException {
Path objectPath = Paths.get(OBJECTS_DIR, hash);
byte[] allBytes = Files.readAllBytes(objectPath);
int headerEnd = new String(allBytes).indexOf('\n');
return Arrays.copyOfRange(allBytes, headerEnd + 1, allBytes.length);
}
private static String hashObject(byte[] data) throws Exception {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
byte[] hash = digest.digest(data);
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
hexString.append(String.format("%02x", b));
}
return hexString.toString();
}
private static void setHead(String branch) throws IOException {
Files.write(Paths.get(HEAD_FILE), branch.getBytes());
}
private static String getCurrentBranch() throws IOException {
return Files.readString(Paths.get(HEAD_FILE)).trim();
}
private static String getCurrentCommit() throws IOException {
return getBranchCommit(getCurrentBranch());
}
private static String getBranchCommit(String branch) throws IOException {
Path branchPath = Paths.get(REFS_DIR, branch);
return Files.exists(branchPath) ? Files.readString(branchPath).trim() : null;
}
private static void updateBranchRef(String branch, String commit) throws IOException {
Files.write(Paths.get(REFS_DIR, branch), commit.getBytes());
}
}
功能说明:
-
初始化仓库
init-
创建
.minigit目录和子目录 -
初始化默认分支
main
-
-
提交更改
commit "message"-
创建树对象(记录当前文件状态)
-
创建提交对象(包含树对象、父提交和消息)
-
更新分支引用
-
-
分支管理
branch-
branch:列出所有分支(当前分支前加*) -
branch new-branch:创建新分支
-
-
切换分支
checkout branch-name-
恢复分支指向的提交状态
-
更新HEAD引用
-
-
推送代码
push-
将当前分支状态复制到"远程"(
.minigit/remote)
-
-
拉取代码
pull-
从"远程"恢复分支状态到本地
-
存储结构:
text
复制
下载
.minigit ├── HEAD # 当前分支 ├── objects # 存储所有对象 ├── refs/heads # 分支引用(指向提交) └── remote # 模拟远程仓库
使用示例:
bash
复制
下载
# 初始化仓库 java MiniGit init # 创建文件 echo "Hello" > test.txt # 提交更改 java MiniGit commit "Initial commit" # 创建分支 java MiniGit branch feature # 切换分支 java MiniGit checkout feature # 修改文件并提交 echo "World" >> test.txt java MiniGit commit "Add feature" # 推送到远程 java MiniGit push # 切回主分支并拉取 java MiniGit checkout main java MiniGit pull
注意事项:
-
这是一个简化版实现,不包含:
-
冲突解决
-
差异比较
-
网络通信(远程使用本地目录模拟)
-
完整Git对象模型
-
-
实际文件存储使用SHA-1哈希作为文件名
-
仅支持文本文件,未处理二进制文件
-
每次提交会存储所有文件的完整副本(非增量存储)
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)