097. 编写一个函数,实现简单的版本控制工具

实现一个简单的版本控制工具可以让我们更好地理解版本控制系统的工作原理。虽然完整的版本控制系统(如 Git)非常复杂,但我们可以编写一个简化版的版本控制工具,实现基本的功能,例如:

  1. 初始化版本库:创建一个版本控制目录,用于存储版本信息。
  2. 添加文件到版本库:将文件的当前状态保存到版本库中。
  3. 提交更改:记录文件的更改并保存到版本库。
  4. 查看历史记录:显示文件的版本历史。
  5. 回滚到特定版本:将文件恢复到指定的版本。

示例代码

import os
import shutil
import datetime
import hashlib

class SimpleVersionControl:
    def __init__(self, repo_path):
        """
        初始化版本控制工具
        :param repo_path: 版本库路径
        """
        self.repo_path = repo_path
        self.versions_path = os.path.join(repo_path, ".versions")
        self.history_path = os.path.join(repo_path, ".history.txt")

        if not os.path.exists(self.versions_path):
            os.makedirs(self.versions_path)
        if not os.path.exists(self.history_path):
            with open(self.history_path, 'w') as history_file:
                history_file.write("")

    def add_file(self, file_path):
        """
        添加文件到版本库
        :param file_path: 文件路径
        """
        if not os.path.exists(file_path):
            print(f"Error: File '{file_path}' does not exist.")
            return

        file_name = os.path.basename(file_path)
        version_path = os.path.join(self.versions_path, file_name)
        shutil.copy(file_path, version_path)

        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        version_hash = self._calculate_hash(file_path)

        with open(self.history_path, 'a') as history_file:
            history_file.write(f"{timestamp} | Added file: {file_name} | Hash: {version_hash}\n")

        print(f"File '{file_name}' added to version control.")

    def commit(self, file_path, message=""):
        """
        提交文件更改
        :param file_path: 文件路径
        :param message: 提交信息
        """
        if not os.path.exists(file_path):
            print(f"Error: File '{file_path}' does not exist.")
            return

        file_name = os.path.basename(file_path)
        version_path = os.path.join(self.versions_path, file_name)

        if not os.path.exists(version_path):
            print(f"Error: File '{file_name}' is not in version control.")
            return

        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        version_hash = self._calculate_hash(file_path)

        shutil.copy(file_path, version_path)

        with open(self.history_path, 'a') as history_file:
            history_file.write(f"{timestamp} | Committed file: {file_name} | Hash: {version_hash} | Message: {message}\n")

        print(f"Changes committed for file '{file_name}'.")

    def log(self):
        """
        查看版本历史
        """
        if not os.path.exists(self.history_path):
            print("No history available.")
            return

        with open(self.history_path, 'r') as history_file:
            history = history_file.readlines()

        for entry in history:
            print(entry.strip())

    def checkout(self, file_name, version_hash):
        """
        回滚到特定版本
        :param file_name: 文件名
        :param version_hash: 版本哈希值
        """
        version_path = os.path.join(self.versions_path, file_name)

        if not os.path.exists(version_path):
            print(f"Error: File '{file_name}' is not in version control.")
            return

        with open(self.history_path, 'r') as history_file:
            history = history_file.readlines()

        for entry in history:
            parts = entry.split(" | ")
            if parts[1].strip() == f"Committed file: {file_name}" and parts[2].strip().split(": ")[1] == version_hash:
                shutil.copy(version_path, os.path.join(self.repo_path, file_name))
                print(f"Checked out file '{file_name}' to version {version_hash}.")
                return

        print(f"Error: Version {version_hash} for file '{file_name}' not found.")

    def _calculate_hash(self, file_path):
        """
        计算文件的哈希值
        :param file_path: 文件路径
        :return: 文件的哈希值
        """
        hash_md5 = hashlib.md5()
        with open(file_path, "rb") as file:
            for chunk in iter(lambda: file.read(4096), b""):
                hash_md5.update(chunk)
        return hash_md5.hexdigest()

# 示例用法
if __name__ == "__main__":
    repo_path = "my_repo"
    vcs = SimpleVersionControl(repo_path)

    # 添加文件到版本库
    vcs.add_file("example.txt")

    # 提交更改
    vcs.commit("example.txt", message="Initial commit")

    # 查看历史记录
    vcs.log()

    # 回滚到特定版本
    vcs.checkout("example.txt", "your_version_hash_here")

功能说明

初始化版本库

  • 创建一个 .versions 目录用于存储文件的版本。

  • 创建一个 .history.txt 文件用于记录版本历史。

添加文件到版本库

  • 将文件的当前状态复制到 .versions 目录。

  • 将文件的哈希值和时间戳记录到 .history.txt

提交更改

  • 更新文件的当前状态到 .versions 目录。

  • 将更改记录到 .history.txt

查看历史记录:从 .history.txt 中读取并显示版本历史。

回滚到特定版本

  • 根据文件名和哈希值从 .history.txt 中查找特定版本。

  • 将文件恢复到该版本。

使用方法

  1. 将上述代码保存为一个 .py 文件。
  2. 创建一个目录作为版本库路径(如 my_repo)。
  3. 将需要版本控制的文件放在版本库路径下。
  4. 运行脚本并调用相应的方法来管理版本。

注意事项

  • 这个版本控制工具非常简单,仅用于学习和演示目的。实际的版本控制系统(如 Git)具有更复杂的功能和优化。

  • 如果需要更高级的功能,可以考虑扩展工具,例如支持分支、合并等操作。

视频讲解

BiliBili: 视睿网络-哔哩哔哩视频 (bilibili.com)