62  버전 관리 시스템 (Version Control System)

깃(Git)과 같이 프로젝트의 모든 변경 사항을 추적할 수 있는 제대로 된 버전 관리 시스템(VCS)을 만들어 봅시다. 파일 시스템의 스냅샷(Snapshot)을 기록하고, 이전 버전으로 돌아가거나 변경 내역을 확인하는 기능을 구현하는 것이 목표입니다.

이 프로젝트는 데이터의 영속성(Persistence)과 차이점 분석(Diff), 그리고 복잡한 파일 시스템 조작 기술을 익히기에 아주 좋은 고난도 과제입니다. 특히 최근 소스 코드 관리에 필수적인 깃의 내부 작동 원리를 깊이 있게 파악하는 과정을 직접 설계해 보세요.

62.1 주요 개발 포인트

  • 파일 시스템 스냅샷 (Commit): 현재 프로젝트 폴더의 모든 파일 상태를 해시(SHA-1 등)와 함께 저장합니다.
  • 변경 사항 추적 및 차이 분석 (Diff): 두 버전 사이의 파일 내용 차이점을 라인 단위로 계산하여 보여줍니다.
  • 브랜치 및 병합 (Branch & Merge): 독립적인 작업 공간(Branch)을 만들고, 서로 다른 변경 사항을 하나로 합치는 로직을 개발합니다.
  • 저장소 초기화 및 관리 (.vcs): 프로젝트 폴더 내에 숨김 폴더를 생성하여 모든 메타데이터와 개체(Objects)를 보관합니다.
  • 사용자 인터페이스 (CLI): vcs init, vcs commit, vcs log, vcs checkout 등의 명령어를 구현하여 쉘에서 조작합니다.

62.2 Python 구현 예시 (간단한 파일 스냅샷 및 해시 생성 시뮬레이션)

import hashlib
import os
import json
from datetime import datetime

class SimpleVCS:
    """
    프로젝트 폴더의 파일 상태를 기록하고 버전으로 관리합니다.
    """
    def __init__(self, repo_dir=".my_vcs"):
        self.repo_dir = repo_dir
        self.objects_dir = os.path.join(repo_dir, "objects")
        self.commits_file = os.path.join(repo_dir, "commits.json")
        self.setup_repo()

    def setup_repo(self):
        """
        저장소 초기화 (숨김 폴더 생성)
        """
        if not os.path.exists(self.repo_dir):
            os.makedirs(self.repo_dir)
            os.makedirs(self.objects_dir)
            with open(self.commits_file, "w") as f:
                json.dump([], f)
            print(f"'{self.repo_dir}' 저장소가 초기화되었습니다.")

    def commit(self, message):
        """
        현재 프로젝트의 모든 파일을 스캔하여 스냅샷(Commit)을 만듭니다.
        """
        print(f"커밋 생성 중: {message}")
        
        # 실제 구현 시 모든 파일의 SHA-1 해시 계산 및 저장
        # hash_val = hashlib.sha1(file_content).hexdigest()
        
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        commit_data = {
            "id": hashlib.sha256(timestamp.encode()).hexdigest()[:8],
            "message": message,
            "timestamp": timestamp
        }
        
        # 커밋 히스토리 업데이트
        with open(self.commits_file, "r+") as f:
            commits = json.load(f)
            commits.append(commit_data)
            f.seek(0)
            json.dump(commits, f, indent=4)
            
        print(f"커밋 완료! ID: {commit_data['id']}")
        return commit_data['id']

if __name__ == "__main__":
    vcs = SimpleVCS()
    
    # 커밋 테스트
    vcs.commit("첫 번째 커밋 - 프로젝트 초기화")
    vcs.commit("두 번째 커밋 - 새로운 기능 추가")
    
    # 팁: 깃의 'Content-addressable storage' 개념을 공부하면 훨씬 견고한 VCS를 만들 수 있습니다.
    print("\n[팁] 'Diff-match-patch' 라이브러리를 활용하면 파일 간의 변경 사항을 라인 단위로 쉽게 계산할 수 있습니다.")