Git 使用详解

53 阅读11分钟

Git 使用详解

目录

  1. Git基础概念
  2. 基本配置
  3. 仓库操作
  4. 文件状态管理
  5. 分支管理
  6. 远程仓库操作
  7. 高级功能
  8. 在你的CLI工具中集成Git功能

1. Git基础概念

1.1 什么是Git?

Git是一个分布式版本控制系统,用于跟踪文件变化、协作开发和管理项目历史。

# Git的三个重要概念
工作区 (Working Directory)     # 你当前编辑的文件
暂存区 (Staging Area/Index)    # 准备提交的文件
版本库 (Repository)            # 已提交的历史记录

1.2 Git工作流程

工作区 ──git add──► 暂存区 ──git commit──► 版本库 ──git push──► 远程仓库
  ▲                   │                      │                    │
  │                   │                      │                    │
  └──────git checkout──┘        git reset────┘      git pull──────┘

2. 基本配置

2.1 初始配置

# 设置用户信息
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"

# 设置默认编辑器
git config --global core.editor "code"  # VS Code
git config --global core.editor "vim"   # Vim

# 设置默认分支名
git config --global init.defaultBranch main

# 查看配置
git config --list
git config user.name
git config user.email

# 设置命令别名
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual '!gitk'

2.2 配置文件位置

# 全局配置 (推荐)
~/.gitconfig

# 系统配置
/etc/gitconfig

# 项目配置
.git/config

3. 仓库操作

3.1 创建仓库

# 初始化新仓库
git init
git init my-project

# 克隆现有仓库
git clone https://github.com/user/repo.git
git clone https://github.com/user/repo.git my-folder

# 克隆特定分支
git clone -b branch-name https://github.com/user/repo.git

# 浅克隆 (只克隆最近的提交)
git clone --depth 1 https://github.com/user/repo.git

3.2 仓库状态查看

# 查看仓库状态
git status
git status -s  # 简短格式

# 查看文件差异
git diff                    # 工作区与暂存区的差异
git diff --staged          # 暂存区与最后提交的差异
git diff HEAD              # 工作区与最后提交的差异
git diff branch1 branch2   # 比较两个分支

# 查看提交历史
git log
git log --oneline          # 简洁格式
git log --graph            # 图形化显示
git log --stat             # 显示文件变更统计
git log -p                 # 显示具体变更内容
git log --since="2 weeks ago"  # 时间过滤
git log --author="John"    # 按作者过滤
git log --grep="bug"       # 按提交信息过滤

4. 文件状态管理

4.1 添加文件到暂存区

# 添加文件
git add file.txt           # 添加特定文件
git add *.py              # 添加所有Python文件
git add .                 # 添加所有文件
git add -A                # 添加所有文件 (包括删除的)
git add -u                # 只添加已跟踪的文件

# 交互式添加
git add -i                # 交互模式
git add -p                # 部分添加 (patch模式)

4.2 提交变更

# 提交到版本库
git commit -m "提交信息"
git commit -am "跳过暂存区直接提交"  # 只对已跟踪文件有效

# 修改最后一次提交
git commit --amend -m "新的提交信息"
git commit --amend --no-edit       # 只修改文件,不改提交信息

# 空提交 (用于触发CI/CD)
git commit --allow-empty -m "Empty commit"

4.3 撤销操作

# 撤销工作区的修改
git checkout -- file.txt
git restore file.txt       # 新语法

# 撤销暂存区的文件
git reset HEAD file.txt
git restore --staged file.txt  # 新语法

# 撤销提交
git reset --soft HEAD~1    # 保留工作区和暂存区
git reset --mixed HEAD~1   # 保留工作区,清空暂存区 (默认)
git reset --hard HEAD~1    # 清空工作区和暂存区 (危险!)

# 撤销特定提交 (创建新提交)
git revert commit-hash

5. 分支管理

5.1 分支基本操作

# 查看分支
git branch                 # 本地分支
git branch -r              # 远程分支
git branch -a              # 所有分支

# 创建分支
git branch feature-branch
git checkout -b feature-branch    # 创建并切换
git switch -c feature-branch      # 新语法

# 切换分支
git checkout main
git switch main            # 新语法

# 删除分支
git branch -d feature-branch      # 安全删除
git branch -D feature-branch      # 强制删除

# 重命名分支
git branch -m old-name new-name

5.2 分支合并

# 合并分支
git checkout main
git merge feature-branch

# 快进合并 (Fast-forward)
git merge --ff-only feature-branch

# 强制创建合并提交
git merge --no-ff feature-branch

# 压缩合并 (将多个提交压缩为一个)
git merge --squash feature-branch
git commit -m "Feature: Add new functionality"

5.3 变基操作

# 变基
git rebase main            # 将当前分支变基到main
git rebase main feature    # 将feature分支变基到main

# 交互式变基
git rebase -i HEAD~3       # 修改最近3个提交

# 变基操作选项:
# pick   - 使用提交
# reword - 使用提交,但修改提交信息
# edit   - 使用提交,但停下来修改
# squash - 使用提交,但合并到前一个提交
# drop   - 删除提交

6. 远程仓库操作

6.1 远程仓库管理

# 查看远程仓库
git remote -v

# 添加远程仓库
git remote add origin https://github.com/user/repo.git
git remote add upstream https://github.com/original/repo.git

# 修改远程仓库URL
git remote set-url origin https://github.com/user/new-repo.git

# 删除远程仓库
git remote remove origin

6.2 推送和拉取

# 推送到远程仓库
git push origin main
git push -u origin main    # 设置上游分支
git push --all             # 推送所有分支
git push --tags            # 推送所有标签

# 从远程仓库拉取
git pull origin main       # fetch + merge
git pull --rebase origin main  # fetch + rebase

# 只获取不合并
git fetch origin
git fetch --all

6.3 标签管理

# 创建标签
git tag v1.0.0             # 轻量标签
git tag -a v1.0.0 -m "Version 1.0.0"  # 带注释的标签

# 查看标签
git tag
git tag -l "v1.*"          # 过滤标签

# 推送标签
git push origin v1.0.0
git push origin --tags

# 删除标签
git tag -d v1.0.0          # 删除本地标签
git push origin :refs/tags/v1.0.0  # 删除远程标签

7. 高级功能

7.1 暂存工作区

# 暂存当前工作
git stash
git stash save "Work in progress"

# 查看暂存列表
git stash list

# 恢复暂存
git stash pop              # 恢复并删除最新的暂存
git stash apply            # 恢复但保留暂存
git stash apply stash@{1}  # 恢复特定暂存

# 删除暂存
git stash drop
git stash clear            # 清空所有暂存

7.2 .gitignore文件

# .gitignore 示例
# 忽略文件类型
*.log
*.tmp
*.pyc

# 忽略目录
node_modules/
.vscode/
__pycache__/

# 忽略特定文件
config/secret.ini
.env

# 不忽略特定文件 (例外)
!important.log

# 只忽略根目录下的文件
/TODO

# 忽略任何目录下的文件
**/logs/

7.3 子模块管理

# 添加子模块
git submodule add https://github.com/user/repo.git path/to/submodule

# 克隆包含子模块的仓库
git clone --recurse-submodules https://github.com/user/repo.git

# 更新子模块
git submodule update --init --recursive
git submodule update --remote

# 查看子模块状态
git submodule status

8. 在你的CLI工具中集成Git功能

基于你的 demo.py 文件,让我们添加Git集成功能:

# 在现有代码基础上添加Git功能

import subprocess
import os
import json
from pathlib import Path

class GitIntegration:
    """Git集成功能"""
    
    def __init__(self, repo_path="."):
        self.repo_path = Path(repo_path)
        self.is_git_repo = self._check_git_repo()
    
    def _check_git_repo(self):
        """检查是否为Git仓库"""
        return (self.repo_path / ".git").exists()
    
    def _run_git_command(self, command):
        """执行Git命令"""
        try:
            result = subprocess.run(
                ["git"] + command,
                cwd=self.repo_path,
                capture_output=True,
                text=True,
                check=True
            )
            return {"success": True, "output": result.stdout.strip()}
        except subprocess.CalledProcessError as e:
            return {"success": False, "error": e.stderr.strip()}
        except FileNotFoundError:
            return {"success": False, "error": "Git命令未找到,请确保已安装Git"}
    
    def init_repo(self):
        """初始化Git仓库"""
        if self.is_git_repo:
            return {"success": False, "error": "已经是Git仓库"}
        
        result = self._run_git_command(["init"])
        if result["success"]:
            self.is_git_repo = True
            print("✅ Git仓库初始化成功")
        return result
    
    def get_status(self):
        """获取Git状态"""
        if not self.is_git_repo:
            return {"success": False, "error": "不是Git仓库"}
        
        return self._run_git_command(["status", "--porcelain"])
    
    def add_files(self, files=None):
        """添加文件到暂存区"""
        if not self.is_git_repo:
            return {"success": False, "error": "不是Git仓库"}
        
        if files is None:
            files = ["."]
        
        return self._run_git_command(["add"] + files)
    
    def commit(self, message):
        """提交变更"""
        if not self.is_git_repo:
            return {"success": False, "error": "不是Git仓库"}
        
        return self._run_git_command(["commit", "-m", message])
    
    def get_branches(self):
        """获取分支列表"""
        if not self.is_git_repo:
            return {"success": False, "error": "不是Git仓库"}
        
        return self._run_git_command(["branch"])
    
    def create_branch(self, branch_name):
        """创建分支"""
        if not self.is_git_repo:
            return {"success": False, "error": "不是Git仓库"}
        
        return self._run_git_command(["checkout", "-b", branch_name])
    
    def switch_branch(self, branch_name):
        """切换分支"""
        if not self.is_git_repo:
            return {"success": False, "error": "不是Git仓库"}
        
        return self._run_git_command(["checkout", branch_name])
    
    def get_log(self, count=10):
        """获取提交历史"""
        if not self.is_git_repo:
            return {"success": False, "error": "不是Git仓库"}
        
        return self._run_git_command([
            "log", 
            f"--max-count={count}", 
            "--oneline", 
            "--graph"
        ])
    
    def push(self, remote="origin", branch="main"):
        """推送到远程仓库"""
        if not self.is_git_repo:
            return {"success": False, "error": "不是Git仓库"}
        
        return self._run_git_command(["push", remote, branch])
    
    def pull(self, remote="origin", branch="main"):
        """从远程仓库拉取"""
        if not self.is_git_repo:
            return {"success": False, "error": "不是Git仓库"}
        
        return self._run_git_command(["pull", remote, branch])

class EnhancedTaskManager(TaskManager):
    """增强的任务管理器,添加Git功能"""
    
    def __init__(self, data_file=None):
        super().__init__(data_file)
        self.git = GitIntegration()
        
        # 如果任务文件所在目录不是Git仓库,询问是否初始化
        task_dir = Path(self.data_file).parent
        if not (task_dir / ".git").exists():
            self._maybe_init_git_repo(task_dir)
    
    def _maybe_init_git_repo(self, directory):
        """询问是否初始化Git仓库"""
        if input(f"📁 目录 {directory} 不是Git仓库,是否初始化? (y/N): ").lower() == 'y':
            self.git.repo_path = directory
            result = self.git.init_repo()
            if result["success"]:
                # 创建.gitignore文件
                gitignore_path = directory / ".gitignore"
                if not gitignore_path.exists():
                    with open(gitignore_path, 'w') as f:
                        f.write("# 任务管理工具\n*.tmp\n*.log\n.env\n")
                    print("📝 已创建.gitignore文件")
    
    def git_status(self):
        """显示Git状态"""
        result = self.git.get_status()
        if result["success"]:
            output = result["output"]
            if not output:
                print("✅ 工作区干净,没有需要提交的更改")
            else:
                print("📋 Git状态:")
                for line in output.split('\n'):
                    if line.startswith('??'):
                        print(f"  ❓ {line[3:]} (未跟踪)")
                    elif line.startswith(' M'):
                        print(f"  📝 {line[3:]} (已修改)")
                    elif line.startswith('M '):
                        print(f"  ✅ {line[3:]} (已暂存)")
                    elif line.startswith('A '):
                        print(f"  ➕ {line[3:]} (新文件)")
                    elif line.startswith('D '):
                        print(f"  ➖ {line[3:]} (已删除)")
                    else:
                        print(f"  📄 {line}")
        else:
            print(f"❌ {result['error']}")
    
    def git_commit_task_changes(self, message=None):
        """提交任务相关的更改"""
        # 添加任务文件到暂存区
        add_result = self.git.add_files([str(Path(self.data_file).name)])
        if not add_result["success"]:
            print(f"❌ 添加文件失败: {add_result['error']}")
            return
        
        # 如果没有提供提交信息,生成默认信息
        if not message:
            message = f"更新任务文件 - {self._get_timestamp()}"
        
        # 提交更改
        commit_result = self.git.commit(message)
        if commit_result["success"]:
            print(f"✅ 已提交更改: {message}")
        else:
            print(f"❌ 提交失败: {commit_result['error']}")
    
    def git_log(self, count=10):
        """显示提交历史"""
        result = self.git.get_log(count)
        if result["success"]:
            print(f"\n📚 最近{count}次提交:")
            print("-" * 60)
            print(result["output"])
        else:
            print(f"❌ {result['error']}")
    
    def git_branches(self):
        """显示分支信息"""
        result = self.git.get_branches()
        if result["success"]:
            print("\n🌳 分支列表:")
            print("-" * 30)
            for line in result["output"].split('\n'):
                if line.startswith('*'):
                    print(f"👉 {line[2:]} (当前分支)")
                else:
                    print(f"   {line.strip()}")
        else:
            print(f"❌ {result['error']}")
    
    # 重写add_task方法,自动提交
    def add_task(self, title: str, description: str = "", priority: str = "medium", auto_commit=True):
        """添加任务并可选择自动提交"""
        super().add_task(title, description, priority)
        
        if auto_commit and self.git.is_git_repo:
            self.git_commit_task_changes(f"添加任务: {title}")
    
    # 重写complete_task方法,自动提交
    def complete_task(self, task_id: int, auto_commit=True):
        """完成任务并可选择自动提交"""
        # 获取任务标题用于提交信息
        task_title = None
        for task in self.tasks:
            if task["id"] == task_id:
                task_title = task["title"]
                break
        
        super().complete_task(task_id)
        
        if auto_commit and self.git.is_git_repo and task_title:
            self.git_commit_task_changes(f"完成任务: {task_title}")

def create_git_enhanced_parser():
    """创建支持Git的命令行解析器"""
    parser = create_parser()
    
    # 获取现有的subparsers
    subparsers = None
    for action in parser._subparsers._actions:
        if isinstance(action, argparse._SubParsersAction):
            subparsers = action
            break
    
    if subparsers:
        # Git状态命令
        git_status_parser = subparsers.add_parser(
            "git-status",
            help="显示Git状态",
            description="显示当前Git仓库的状态"
        )
        
        # Git提交命令
        git_commit_parser = subparsers.add_parser(
            "git-commit",
            help="提交任务更改",
            description="手动提交任务文件的更改"
        )
        git_commit_parser.add_argument(
            "-m", "--message",
            help="提交信息",
            default=None
        )
        
        # Git日志命令
        git_log_parser = subparsers.add_parser(
            "git-log",
            help="显示提交历史",
            description="显示Git提交历史"
        )
        git_log_parser.add_argument(
            "-n", "--count",
            type=int,
            default=10,
            help="显示的提交数量 (默认: 10)"
        )
        
        # Git分支命令
        git_branch_parser = subparsers.add_parser(
            "git-branch",
            help="显示分支信息",
            description="显示Git分支列表"
        )
        
        # 添加全局Git选项
        parser.add_argument(
            "--no-auto-commit",
            action="store_true",
            help="禁用自动Git提交"
        )
    
    return parser

def git_enhanced_main():
    """支持Git的主函数"""
    parser = create_git_enhanced_parser()
    args = parser.parse_args()
    
    if not args.command:
        parser.print_help()
        sys.exit(1)
    
    # 创建增强的任务管理器
    task_manager = EnhancedTaskManager(args.data_file)
    auto_commit = not getattr(args, 'no_auto_commit', False)
    
    try:
        if args.command == "git-status":
            task_manager.git_status()
        
        elif args.command == "git-commit":
            task_manager.git_commit_task_changes(args.message)
        
        elif args.command == "git-log":
            task_manager.git_log(args.count)
        
        elif args.command == "git-branch":
            task_manager.git_branches()
        
        elif args.command == "add":
            task_manager.add_task(
                args.title, 
                args.description, 
                args.priority, 
                auto_commit=auto_commit
            )
        
        elif args.command == "complete":
            task_manager.complete_task(args.task_id, auto_commit=auto_commit)
        
        elif args.command == "list":
            task_manager.list_tasks(show_completed=args.all)
        
        elif args.command == "delete":
            task_manager.delete_task(args.task_id)
            if auto_commit and task_manager.git.is_git_repo:
                task_manager.git_commit_task_changes("删除任务")
        
        elif args.command == "search":
            task_manager.search_tasks(args.keyword)
        
        elif args.command == "stats":
            task_manager.stats()
        
        else:
            print(f"❌ 未知命令: {args.command}")
            parser.print_help()
            sys.exit(1)
            
    except KeyboardInterrupt:
        print("\n\n👋 再见!")
        sys.exit(0)
    except Exception as e:
        print(f"❌ 发生错误: {e}")
        sys.exit(1)

# 修改最后的执行部分
if __name__ == "__main__":
    # 检查是否启用Git功能
    if "--with-git" in sys.argv:
        sys.argv.remove("--with-git")
        git_enhanced_main()
    else:
        main()

9. 实用Git命令速查

9.1 日常工作流

# 典型的Git工作流
git status                 # 查看状态
git add .                  # 添加所有修改
git commit -m "Fix bug"    # 提交修改
git push origin main       # 推送到远程

# 拉取最新代码
git pull origin main       # 拉取并合并
git fetch && git rebase origin/main  # 拉取并变基

9.2 问题排查

# 查看文件修改历史
git log --follow -- file.txt
git blame file.txt         # 查看每行的修改者

# 查找特定修改
git log --grep="bug"       # 搜索提交信息
git log -S"function_name"  # 搜索代码变更

# 比较版本
git diff HEAD~1 HEAD       # 比较最近两次提交
git diff branch1..branch2  # 比较分支

9.3 紧急修复

# 快速修复
git stash                  # 暂存当前工作
git checkout -b hotfix     # 创建修复分支
# 进行修复...
git add . && git commit -m "Hotfix"
git checkout main
git merge hotfix
git branch -d hotfix       # 删除修复分支
git stash pop              # 恢复之前的工作

10. 使用示例

# 使用你的Git增强CLI工具
python demo.py --with-git add "学习Git" -d "掌握Git的基本操作"
python demo.py --with-git git-status
python demo.py --with-git git-log -n 5
python demo.py --with-git git-branch

# 禁用自动提交
python demo.py --with-git --no-auto-commit add "临时任务"

# 手动提交
python demo.py --with-git git-commit -m "手动提交任务更改"

# 基本Git命令
git init                   # 初始化仓库
git add README.md          # 添加文件
git commit -m "Initial commit"  # 首次提交
git remote add origin https://github.com/user/repo.git
git push -u origin main    # 推送到远程