6  版本控制与协作

7 版本控制与协作

在科学研究中,代码和数据的版本管理是确保可重复性的关键环节。本章介绍 Git 版本控制系统和 GitHub 协作平台的使用方法。

7.1 为什么需要版本控制?

你是否遇到过这样的情况?

论文_v1.docx
论文_v2.docx
论文_v2_导师修改.docx
论文_v3_最终版.docx
论文_v3_最终版_真的最终版.docx
论文_v3_最终版_打死不改了.docx

版本控制系统(Version Control System, VCS)就是为了解决这个问题。Git 是目前最流行的版本控制工具,它能:

  • 记录文件的每一次修改历史
  • 随时回退到任意历史版本
  • 多人协作时自动合并修改
  • 追踪每个人的贡献

7.2 Git 基本概念

7.2.1 仓库(Repository)

仓库是 Git 管理的项目文件夹。分为:

  • 本地仓库:在你电脑上的项目文件夹
  • 远程仓库:托管在 GitHub 等平台上的副本

7.2.2 工作区、暂存区、版本库

工作区(Working Directory)
    ↓  git add
暂存区(Staging Area)
    ↓  git commit
版本库(Repository)
    ↓  git push
远程仓库(Remote)
  • 工作区:你正在编辑的文件
  • 暂存区:准备提交的文件(git add 后)
  • 版本库:已提交的历史记录(git commit 后)

7.3 首次使用 Git:初始配置

安装 Git 后,第一件事是告诉 Git 你是谁。这些信息会记录在每次提交中:

# 设置用户名和邮箱(只需执行一次)
git config --global user.name "你的名字"
git config --global user.email "你的邮箱@example.com"

# 验证设置
git config --list
Warning邮箱要和 GitHub 账号一致

user.email 应该填你注册 GitHub 时使用的邮箱,否则 GitHub 无法正确关联你的提交记录。

7.4 常用 Git 命令

7.4.1 初始化与克隆

# 在当前文件夹初始化 Git 仓库
git init

# 克隆远程仓库到本地
git clone https://github.com/username/repo-name.git

7.4.2 日常工作流

# 查看当前状态(哪些文件被修改了)
git status

# 将修改添加到暂存区
git add filename.R          # 添加单个文件
git add .                   # 添加所有修改

# 提交到版本库(附带说明信息)
git commit -m "添加数据清洗脚本"

# 推送到远程仓库
git push origin main

# 从远程仓库拉取最新代码
git pull origin main

7.4.3 查看历史

# 查看提交历史
git log --oneline

# 查看某个文件的修改历史
git log --oneline -- analysis.R

# 查看具体修改内容
git diff
Tip写好提交信息

好的提交信息应该简洁明了,说明”做了什么”:

  • 添加土壤pH数据清洗脚本
  • 修复物种名称拼写错误
  • 更新图表配色方案
  • 修改了一些东西
  • update
  • ...

7.5 GitHub 协作

7.5.1 Fork 与 Pull Request

在团队协作中,常用的工作流程是:

  1. Fork:将别人的仓库复制一份到自己的 GitHub 账号
  2. Clone:将 Fork 的仓库克隆到本地
  3. 修改:在本地进行修改并提交
  4. Push:推送到自己的 GitHub 仓库
  5. Pull Request(PR):向原仓库发起合并请求
# 1. Fork 后克隆自己的仓库(替换为你的 GitHub 用户名)
git clone https://github.com/your-username/repo-name.git

# 2. 创建新分支进行修改
git checkout -b feature/add-analysis

# 3. 修改文件并提交
git add .
git commit -m "添加多样性分析脚本"

# 4. 推送到自己的仓库
git push origin feature/add-analysis

# 5. 在 GitHub 网页上创建 Pull Request

7.5.2 Issue

Issue 是 GitHub 上的问题追踪工具,可以用来:

  • 报告 Bug
  • 提出新功能需求
  • 讨论项目方向
  • 记录待办事项

7.6 在 RStudio 中使用 Git

RStudio 内置了 Git 图形界面,不需要记命令行:

7.6.1 创建 Git 项目

  1. File → New Project → Version Control → Git
  2. 输入远程仓库 URL
  3. 选择本地存放路径
  4. 点击 Create Project

7.6.2 日常操作

RStudio 右上角的 Git 面板提供了常用操作:

  1. 查看修改:Git 面板会显示所有被修改的文件
  2. 暂存文件:勾选文件前的复选框(等同于 git add
  3. 提交:点击 Commit 按钮,输入提交信息(等同于 git commit
  4. 推送/拉取:点击 Push/Pull 按钮(等同于 git push/git pull
NoteRStudio 中的 Git 快捷键
  • Ctrl + Alt + M:打开 Commit 窗口
  • Ctrl + Alt + D:查看 Diff(文件差异)

7.7 常见问题与错误处理

7.7.1 合并冲突(Merge Conflict)

当两个人同时修改了同一个文件的同一部分,Git 无法自动合并,就会产生合并冲突。这是初学者最常遇到的问题。

执行 git pull 时如果出现冲突,Git 会在文件中标记冲突位置:

<<<<<<< HEAD
# 你的修改
mean_height <- mean(data$height, na.rm = TRUE)
=======
# 队友的修改
mean_height <- median(data$height, na.rm = TRUE)
>>>>>>> origin/main

解决步骤:

  1. 打开冲突文件,找到 <<<<<<<=======>>>>>>> 标记
  2. 决定保留哪个版本(或合并两者),删除所有标记符号
  3. 保存文件后提交:
git add filename.R
git commit -m "解决合并冲突:统一使用均值计算株高"
Tip预防冲突的好习惯
  • 每次开始工作前先 git pull 拉取最新代码
  • 团队成员尽量编辑不同的文件
  • 频繁提交、频繁推送,减少冲突范围

7.7.2 常见错误及解决方法

推送被拒绝(push rejected)

! [rejected] main -> main (fetch first)

原因:远程仓库有你本地没有的新提交。先拉取再推送:

git pull origin main
# 如果有冲突,解决冲突后再推送
git push origin main

误提交了不该提交的文件

# 从暂存区移除(文件本身不删除)
git reset HEAD filename.csv

# 如果已经 commit 了,撤销最近一次提交(保留修改)
git reset --soft HEAD~1

修改了文件但想恢复原样

# 丢弃工作区的修改,恢复到上次提交的状态
git restore filename.R
Warninggit restore 不可撤销

git restore 会丢弃你未提交的修改,且无法恢复。使用前请确认你确实不需要这些修改。

7.8 .gitignore 文件

有些文件不应该被 Git 追踪(如大型数据文件、临时文件、密钥等)。在项目根目录创建 .gitignore 文件:

# R 临时文件
.Rhistory
.RData
.Rproj.user/

# 数据文件(太大不适合放 Git)
data/raw/*.csv
data/raw/*.xlsx

# 系统文件
.DS_Store
Thumbs.db

# 编译产物
docs/
_freeze/
Warning不要把敏感信息提交到 Git

API 密钥、密码、个人隐私数据等绝对不能提交到 Git 仓库,尤其是公开仓库。一旦提交,即使删除文件,历史记录中仍然可以找到。

7.9 项目文件组织规范

一个规范的数据分析项目应该有清晰的文件结构:

my-project/
├── README.md           # 项目说明
├── .gitignore          # Git 忽略规则
├── data/
│   ├── raw/            # 原始数据(不修改)
│   └── processed/      # 处理后的数据
├── scripts/
│   ├── 01-clean.R      # 数据清洗
│   ├── 02-analyze.R    # 数据分析
│   └── 03-visualize.R  # 数据可视化
├── output/
│   ├── figures/         # 图表
│   └── tables/          # 表格
└── docs/
    └── report.qmd       # 分析报告

关键原则:

  • 原始数据只读data/raw/ 中的文件永远不修改
  • 脚本有编号:按执行顺序编号,方便他人复现
  • 输出可重建output/ 中的所有文件都能通过运行脚本重新生成
  • 有 README:说明项目目的、数据来源、运行方法

7.10 实践:分组创建项目仓库

按照以下步骤完成本章实践:

  1. 在 GitHub 上创建一个新仓库,命名为 ecology-data-project
  2. 添加 README.md 和 .gitignore(选择 R 模板)
  3. 克隆到本地(使用 RStudio)
  4. 按照上面的规范创建文件夹结构
  5. 添加一个简单的 R 脚本(如读取 iris 数据并保存描述性统计)
  6. 提交并推送到 GitHub
  7. 邀请组员作为 Collaborator
  8. 组员各自克隆仓库,添加自己的分析脚本,提交推送

7.11 课后练习

  1. 完成 Git 初始配置(user.nameuser.email
  2. 在 GitHub 上创建个人项目仓库,包含完整的文件夹结构
  3. 练习 git addgit commitgit push 的完整流程
  4. 查看 git log 确认提交历史
  5. 创建 .gitignore 文件,排除不需要追踪的文件
  6. 尝试在 RStudio 中使用 Git 面板完成一次提交和推送
  7. (进阶)与同学协作制造一次合并冲突,练习解决冲突的流程