Source code management/zh-cn

简介

FreeCAD项目的主要源代码管理工具是Git,它可以很容易地从包管理器或直接从Git的网站安装到大多数操作系统中。建议您在直接使用FreeCAD源代码之前熟悉Git。访问Git文档页面获取参考手册,以及Pro Git书籍来学习以一般方式使用系统。本文档的重点是在FreeCA中使用Git.编译FreeCAD的描述见Compiling

尽管 Git 主要是一个终端应用程序,但也有很多图形化客户端可以简化分支操作、应用补丁以及向主分支提交拉取请求等任务。例如:git-gui(帮助进行暂存和提交,并可启动 gitk)、gitk(显示提交历史,是首个开发的图形界面)、gitg(Gnome 环境)、qgit(Qt 环境)、tig(Ncurses 界面)、集成在 Visual Studio Code 中的源代码管理功能、git-cola 以及 GitKraken(专有软件)。关于此工具的简要介绍,请参阅 使用 GitKraken 开发 FreeCAD

注意:如果这些让你感到头晕,有一个非常好的关于如何使用git和Github的非技术系列,叫做Git and Github for Poets

源码获取

每个人都可以访问并获得FreeCAD源代码的副本,但是只有FreeCAD项目管理人员才有写权限。你可以获得代码的副本,研究它并按照你的意愿修改它,但是如果你希望将更改包含在官方源代码中,则需要对主存储库执行“pull request”,以便管理员可以审查您的修改。这种开发风格被称为Dictator and lieutenants workflow,因为核心开发人员(Dictator)和受信任的开发人员(lieutenants)会过滤由独立开发人员和用户提交的代码。

如果你的源代码改变是重要的,建议你在FreeCAD论坛的pull request部分解释它们。

开发FreeCAD代码的通用工作流;每个人都可以从主存储库获得代码,但是主开发人员拥有审查和合并其他开发人员提交的代码的专有权。

官方GitHub存储库

FreeCAD的源代码托管在Github上,https://github.com/FreeCAD/FreeCAD

为了贡献代码,您需要有一个GitHub 账号.

在过去,源代码是作为SVN存储库托管的, https://free-cad.svn.sourceforge.net/svnroot/free-cad. 在2011年10月10日转移到GitHub,对应commit 120ca87015.

因此,在此之前发生的许多更改没有记录在现代Git提交历史中。在历史页阅读更多信息。

设置你的 Git username

开发人员应该使用他们的GitHub用户名,将代码提交到他们的个人存储库。如果没有设置全局用户名,你可以为当前Git库设置一个本地用户名,如下所示:

git config user.name "YOUR_NAME"
git config user.email GITHUB_USERNAME@users.noreply.github.com

其中"YOUR_NAME"表示您的全名或昵称,用于标识特定提交的作者,GITHUB_USERNAME表示您在GitHub上的帐户名称。

远端仓库

请阅读origin 和 upstream 之间的区别是什么?(Stackoverflow)来帮助你理解在Git上下文中originupstream的区别。本节解释如何为开发设置正确的存储库。 本质上是:

这种区别很重要,因为您应该先在自己的存储库副本中编写代码,然后再将这些更改推送到官方存储库。

根据上述内容,有两种设置 Git 开发环境的方法:

我们推荐第一种方法,因为它快了一步。

第一种方法:在 GitHub 上复刻并将你的复刻仓库克隆到本地

首先,你需要在 GitHub 上复刻 FreeCAD 仓库,然后将这个个人复刻仓库克隆到你的电脑上,最后设置 upstream 仓库。

  • 登录 你的 GitHub 账户。
  • 前往 FreeCAD 官方仓库:https://github.com/FreeCAD/FreeCAD
  • 在页面右上角点击 “Fork” 按钮。这将在你的 GitHub 用户名下创建 FreeCAD 仓库的个人副本:https://github.com/GITHUB_USERNAME/FreeCAD
  • 在你的机器上,克隆你刚刚创建的 FreeCAD 复刻仓库。它会被创建在名为 freecad-source 的目录中。
git clone https://github.com/GITHUB_USERNAME/FreeCAD.git freecad-source
  • 下载完成后,进入新的源代码目录并设置 upstream 仓库。
cd  freecad-source
git remote add upstream https://github.com/FreeCAD/FreeCAD.git
  • 使用 git remote -v 确认你的远程仓库;输出应类似于以下内容
origin	https://github.com/GITHUB_USERNAME/FreeCAD.git (fetch)
origin	https://github.com/GITHUB_USERNAME/FreeCAD.git (push)
upstream	https://github.com/FreeCAD/FreeCAD.git (fetch)
upstream	https://github.com/FreeCAD/FreeCAD.git (push)
  • 现在可以开始开发了。

第二种方法:直接将 FreeCAD 克隆到本地机器

第二种方法:直接将 FreeCAD 克隆到本地机器

首先,你需要在 GitHub 上复刻 FreeCAD 仓库,但你会将原始的 FreeCAD 仓库克隆到本地机器,然后通过终端修改你的远程仓库配置。

  • 登录 你的 GitHub 账户。
  • 前往 FreeCAD 官方仓库:https://github.com/FreeCAD/FreeCAD
  • 在页面右上角点击 “Fork” 按钮。这将在你的 GitHub 用户名下创建 FreeCAD 仓库的个人副本:https://github.com/GITHUB_USERNAME/FreeCAD
  • 克隆原始的 FreeCAD 仓库。它会被创建在名为 freecad-source 的目录中。
git clone https://github.com/FreeCAD/FreeCAD.git freecad-source
  • 下载完成后,进入新的源代码目录并设置 origin 仓库。
cd freecad-source
git remote add origin https://github.com/GITHUB_USERNAME/FreeCAD.git
  • 然后设置 upstream 仓库。
git remote add upstream https://github.com/FreeCAD/FreeCAD.git
  • 使用 git remote -v 确认你的远程仓库;输出应类似于以下内容
origin	https://github.com/GITHUB_USERNAME/FreeCAD.git (fetch)
origin	https://github.com/GITHUB_USERNAME/FreeCAD.git (push)
upstream	https://github.com/FreeCAD/FreeCAD.git (fetch)
upstream	https://github.com/FreeCAD/FreeCAD.git (push)
  • 现在可以开始开发了。

如果出于某种原因,远程仓库存在但指向了错误的地址,你可以通过重命名远程仓库的名称来解决。例如,origin 应该指向你的个人复刻仓库;如果它指向的是原始的 FreeCAD 仓库,则将该远程仓库的名称改为 upstream,然后手动添加 origin 仓库。

git remote rename origin upstream
git remote add origin https://github.com/GITHUB_USERNAME/FreeCAD.git
git remote -v

你也可以使用 show 关键字来显示更多信息。

git remote show origin
git remote show upstream

Git 开发流程

切勿在本地 main 分支上进行开发。请创建一个用于开发的本地分支,然后通过拉取请求(pull request)将该本地分支合并到上游的 main 分支。更多信息请阅读 Git 分支基本分支与合并 以及 GitHub - 参与项目

使用 git 开发 FreeCAD 代码的通用工作流程:在线上复刻主仓库并克隆到本地计算机(0);新建分支(1)用于将代码的本地更改和新增内容提交(2);将分支变基到最新的线上代码(3),然后推送到远程仓库(4);创建拉取请求以便将代码合并到主仓库(5)。之后,用新的主代码更新个人克隆(a);同时将更新后的主代码推送到远程仓库(b),以确保线上和线下的代码保持一致。

分支

Git 的最佳实践建议,不要直接在主版本代码上工作,而是在每次开发新功能时创建一个新分支。分支的成本很低,不会复制整个源代码树,只是在你将要编写代码的基础上创建一个时间点;因此,分支有助于将进行中的工作与主代码隔离开来。

使用新分支需要两个步骤:首先创建分支,然后切换到该分支:

git branch myNewBranch
git checkout myNewBranch

或者,使用一条指令完成这两个步骤:

git checkout -b myNewBranch

现在,你可以随时使用 checkout 在需要时切换分支。要查看项目中的分支以及当前所在分支,可以单独使用 branch 操作,或者加上 -v-vv 获取更多信息:

git branch
git branch -vv

在你进行更改并提交这些更改之后,使用带有以下选项的 log 操作来可视化分支。

git log --oneline --decorate --graph --all

提交

进入新分支后,使用文本编辑器编辑你想要修改的源文件。要查看哪些文件被修改过,可以使用 statusdiff 操作;当对修改感到满意后,使用 commit 操作保存更改:

git status
git diff
git commit -a

与 SVN 不同,你需要明确指定要提交哪些文件;使用 -a 选项可以保存所有被修改文件的更改。你的文本编辑器(例如 nanovim)将会打开,以便你编写提交信息。

或者直接在提交中添加信息:

git commit -a -m "Fix the bug in the clone function."

如果你创建了新的文件或目录,必须先使用 add 操作将它们添加到本地仓库,然后再提交更改。

git add path
git commit -a

其中 path 可以是任意目录或文件。

编写好的提交信息

你应该尽量小步工作,也就是说,在代码中添加一小部分功能后就频繁提交。如果你无法用一句话概括自己的更改,那么很可能距离上次提交已经太久了。

对于较大的更改,提供有用且详实的描述非常重要。FreeCAD 采用了《Pro Git》一书([1])中提到的格式,即一条简短的消息,后跟一个更长的描述段落。

简短(不超过50个字符)的更改摘要

如果需要,可以添加更详细的说明文字。每行大约控制在72个字符左右。在某些情境下,第一行会被视为邮件的主题,其余文本作为正文。摘要与正文之间的空行非常关键(除非你完全省略正文);如果两者连在一起,rebase 等工具可能会产生混淆。

空行之后可以继续写更多段落。

  - 也可以使用项目符号
  - 通常使用连字符或星号作为项目符号,前面加一个空格,符号之间用空行分隔,但具体格式约定各有不同

如果你在某个分支中进行大量相关的开发工作,应该进行多次小提交(参见 论坛帖子)。当你希望将这些更改合并到主分支时,你应该执行

git log main..myNewBranch

查看各个提交信息。然后,在执行合并操作时,你就可以编写一条高质量的合并信息。

当你合并到 main 分支时,请使用 --squash 选项,并附上高质量的提交信息进行提交。这样可以让你在提交时更加自由,同时在不产生过多独立描述的前提下,提供足够详细的提交信息。

压缩提交

压缩(Squashing)指的是将多个连续的提交合并为一个的过程。如果你进行了许多小提交,并希望将它们作为一个单独的提交来呈现(例如,更改单个变量、修正拼写错误、调整代码间距等),那么压缩提交可能是合适的。你应该仅对单个文件的小提交进行压缩;涉及多个文件的大幅度代码更改应当保留完整的提交历史。

使用 git log --oneline 可以按顺序看到许多提交,最新的提交位于顶部。在这个示例中,从“feature A”开始,为了实现“feature B”进行了多次提交;我们希望将所有属于“feature B”的提交压缩成一个。

871adb OK, feature B is fully implemented
1c3317 Whoops, it is not ready yet...
87871a I'm almost ready!
643d0e Code cleanup
af2581 Fix this and that
4e9baa Good implementation
d94e78 Prepare the module for feature B
6394da Feature A

使用带有 --interactive-i 选项的 rebase 操作来选择多个提交并压缩它们。使用你想要压缩的第一个提交前一个提交的哈希值,在本例中即对应“feature A”的那个提交。

git rebase -i 6394da

(提示:如果你知道要编辑多少个提交,可以使用 git rebase -i HEAD~n 来对最近的 n 个提交进行操作)

命令行编辑器(如 nanovim)将打开,再次向你显示这些提交,此时较旧的提交位于顶部。在每个提交之前,会显示 pick 一词。删除 pick,并替换为 squash 或仅字母 s,但第一个条目除外;该提交是最旧的,因此之后的所有提交都将被压缩到它当中。

pick d94e78 Prepare the module for feature B
s 4e9baa Good implementation
s af2581 Fix this and that
s 643d0e Code cleanup
s 87871a I'm almost ready!
s 1c3317 Whoops, it is not ready yet...
s 871adb OK, feature B is fully implemented

保存文件并关闭编辑器。

编辑器将再次打开。现在,你可以添加一条更长的信息,将所有的更改描述为一次单独的提交。保存文件并再次关闭编辑器。这样就会将这些提交合并为一个,并使用你编写的新提交信息。

你可以再次使用 git log --oneline 来查看新的提交历史。在这种情况下,只会显示一个针对“feature B”的提交,位于未修改的“feature A”提交之上。

c83d67 OK, feature B is fully implemented now, with proper module setup, and clean code.
6394da Feature A

在为 FreeCAD 编写代码时,我们要求你在每条提交信息的开头注明所影响的模块。例如,针对草图(Sketcher)模块更改的提交信息可能是:

Sketcher: make straight lines curve a bit

直线有点难看,因此本次提交为它们增加了一点曲度,使它们在视觉上更令人愉悦。同时它们还会略微闪烁,并随时间变换颜色。

修复 bug #1234。

如果你在提交拉取请求(PR)之前,注意使用 rebase 来整理和描述你的提交,那么你的 PR 将更容易被审查,也更快被合并。

将你的工作推送到你的 GitHub 仓库

你计算机上的本地分支不会自动同步到你已指定为 originupstream 的远程服务器(参见 远程仓库);你必须显式地将分支推送到远程服务器,这需要你拥有写权限。一旦你这样做了,分支就会变成公开状态,供其他开发者审查。

对于 FreeCAD,你应该将本地分支推送到 origin 远程仓库,即 https://github.com/GITHUB_USERNAME/FreeCAD。每次推送时都需要输入用户名和密码,除非你已设置 凭据缓存。请阅读 将提交推送到远程仓库 以获取更多信息。

git push origin myNewBranch

当你在单个分支上工作时,可能需要多次进行交互式变基、压缩提交和修正提交。在这种情况下,你的分支历史将不再简单,也就无法将其推送到远程仓库。你可能会收到类似下面的消息,提示无法进行“快进”推送。

error: failed to push some refs to 'https://github.com/USER/FreeCAD.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

为了最终将你的分支推送到远程仓库,你需要进行“强制推送”。这将会用你本地实际的分支完全覆盖你的远程分支。

git push -f origin myNewBranch

普通开发者对 upstream 仓库 https://github.com/FreeCAD/FreeCAD 没有写权限,因此,你绝不应该将代码推送到这个远程服务器。

从 upstream 变基

当你在自己的分支上工作时,官方的 FreeCAD 代码会随着其他开发者的提交不断“向前推进”,因此会开始与你个人复刻仓库中的代码产生分歧。

      .-----A origin/myNewBranch
     / 
-----o-----------Z FreeCAD upstream/main

因此,当你准备好将你的分支合并到 FreeCAD 的主仓库时,你必须对自己的仓库副本进行“变基”(rebase),使其尽可能接近官方仓库。更多信息请参阅 Git 分支 - 变基

git checkout myNewBranch
git pull --rebase upstream main

这将从 upstream 仓库(官方 FreeCAD 源代码)的 main 分支下载代码,并将其与你当前分支(myNewBranch)合并,从而使你的更改位于最新官方代码之上。如果没有人与你修改了相同的文件,那么合并将顺利成功。如果某些文件被不同的人同时修改,则可能会出现需要解决的冲突。

                  .-----A' origin/myNewBranch
                 /
-----o-----------Z FreeCAD upstream/main

总而言之,你需要切换到合适的分支,对上游代码进行变基,然后继续执行推送操作。

git checkout myNewBranch
git pull --rebase upstream main
git push origin myNewBranch

pull 操作相当于先执行 fetch,再执行 merge。当使用 --rebase 选项时,它不会执行简单的 merge,而是运行 rebase 操作。

git pull upstream

git fetch upstream
git merge FETCH_HEAD
git pull --rebase upstream main

git fetch upstream
git rebase main

合并分支(拉取请求)

在你已在本地提交更改、将分支从上游仓库变基、并将分支推送到线上之后,就可以发起一个“拉取请求”(pull request)。拉取请求([2])会告知 FreeCAD 官方仓库的管理员,你希望将分支中的新代码与官方代码合并。

总结一下,开发流程如下:

  1. 复刻 FreeCAD 并获取该复刻的本地副本。
  2. 在你的复刻上创建一个分支,并切换到该分支。
  3. 编写代码!根据需要进行多次或少量提交,写出良好的提交信息以记录你所做的工作。
  4. 当你的工作完成后,使用 git rebase -i HEAD~n(其中 n 是你已提交的总次数)将你的提交压缩成一组逻辑清晰的提交,并附上良好的提交信息(每条信息应以所影响模块的名称开头,例如“Sketcher: make straight lines curve a bit”)。
  5. 按照下面的描述,使用 GitHub 将你的代码作为“拉取请求(PR)”提交。

一旦你将代码推送到你的 origin 仓库 https://github.com/GITHUB_USERNAME/FreeCAD,GitHub 就会为你提供与 upstream 仓库进行比较并创建拉取请求的选项。点击 Compare & pull request 按钮,你将进入一个界面,可以在其中选择作为合并目标的“base”仓库,以及包含你额外代码的“head”仓库。系统会快速检查并告知你修改的文件是否存在冲突;如果你修改的文件没有被其他人改动过,你的分支将能够被干净地合并。

GitHub 会显示一个文本编辑器,供你撰写描述更改的消息:这个编辑器会预先填充一条欢迎消息(你可以删除)、一个检查清单(需要逐项确认)以及一条提醒:在更改被接受后,要在 wiki 上记录相关变更。使用检查清单时,请逐项检查并将 [ ] 改为 [X],表示你已经完成了该步骤。GitHub 还会显示你分支中的提交数量、修改的文件数量,以及一个“base”与“head”之间的差异视图,以便大家能立即看到你打算做的修改。请仔细检查这些内容,留意是否有多余的空行,或者你的 IDE 在后台悄悄做了大幅格式改动。

base repository: FreeCAD/FreeCAD    base: main  <----  head repository: GITHUB_USERNAME/FreeCAD    compare: myNewBranch

Able to merge. These branches can be automatically merged.

点击 Create pull request 继续。此时会出现一条消息,提示需要对代码进行一些检查。这是一个自动编译 FreeCAD 并运行单元测试的系统。如果测试通过,拉取请求被合并到主代码中的可能性会更大;否则,系统会生成一份报告,指出遇到的错误。请参阅 FreeCAD 拉取请求

Some checks haven’t completed yet

* continuous-integration/travis-ci/pr Pending — The Travis CI build is in progress  |Required|

如果测试成功,你会看到类似如下的消息

所有检查均已通过

* continuous-integration/travis-ci/pr — The Travis CI build passed  |Required|

该分支与基础分支没有冲突 只有对该仓库具有写权限的人才能合并拉取请求。

现在你必须等待管理员合并你的分支;合并完成后你会收到通知。

Pull request successfully merged and closed

You’re all set — the GITHUB_USERNAME:myNewBranch branch can be safely deleted.
If you wish, you can also delete your fork of FreeCAD/FreeCAD.

如果你愿意,可以删除刚刚合并的分支,甚至删除整个 FreeCAD 复刻仓库,因为你自己的代码已经包含在主分支的最新代码中了。

-----o-----------Z----A' FreeCAD upstream/main

注意: 在等待合并批准期间,你可以继续在同一个分支上进行开发(使用 git commit -a);如果你再次执行 git push,第二个合并提交将会排入同一个拉取请求的队列中,并再次触发自动化测试。也就是说,在你的合并尚未被管理员批准之前,你可以持续向你的 origin 仓库推送更改,这些更改会以同一个拉取请求的形式排队等待合并到 upstream 仓库。对于小的改动,使用一个拉取请求来排队多个单独的提交通常是理想的做法。对于源代码中的大幅新增内容,你应该创建另一个分支,在该分支上开发你的功能,然后为该分支提交一个单独的拉取请求。

拉取请求界面可以在任何时候使用,当你希望将代码从你自己的仓库提交到 GitHub 上的另一个仓库时。你也可以用它来反向合并代码,比如从别人的分支合并到你的分支,甚至在你自己的分支之间进行合并。在后一种情况下,由于你拥有这些分支,合并可以立即由你自己批准。

base repository: SomeProject/Some_Software  base: main       <----  head repository: GITHUB_USERNAME/Some_Software  compare: add_new_functions
base repository: GITHUB_USERNAME/FreeCAD    base: myNewBranch  <----  head repository: FreeCAD/FreeCAD                compare: main
base repository: GITHUB_USERNAME/FreeCAD    base: myNewBranch  <----  head repository: GITHUB_USERNAME/FreeCAD        compare: fix-many-bugs-branch

保持 GitHub 仓库为最新状态

一旦你复刻了 FreeCAD,你的个人仓库就会独立于原始仓库存在。当原始仓库有了新的提交时,GitHub 会通知你,你的个人仓库在提交数量上已经落后:

This branch is 5 commits behind FreeCAD:main.

类似地,如果你创建了一个包含新代码的开发分支,GitHub 会通知你该分支在提交数量上领先;也就是说,这个分支中有尚未合并到官方 FreeCAD 仓库的更改:

This branch is 3 commits ahead of FreeCAD:main.

在开发过程中,这两种情况都可能出现:你自己的分支可能缺少其他开发者的提交,但包含你自己的新提交。

This branch is 2 commits ahead, 14 commits behind FreeCAD:main.

在开发代码时,建议对你当前工作的分支进行变基(rebase),这样会使你的分支始终领先于 FreeCAD 的主代码。

至于你原本的 main 分支,GitHub 永远不会自动更新它;这需要你亲自操作。切换到 main 分支,然后从 upstream 执行 pull(这会执行一次 fetchmerge),接着将更新后的 main 分支推送到你的远程 origin 仓库。

git checkout main
git pull upstream main
git push origin main

完成此操作后,GitHub 会通知你,你已经与 upstream 仓库保持同步。

This branch is even with FreeCAD:main.

现在你的 main 分支已经是最新状态,你可以选择切换到该分支,并删除之前用于开发某个功能的其他分支。

git checkout main
git branch -d myNewBranch

要删除 origin 远程仓库中的分支,你可以使用 push 操作。通常情况下,推送一个本地分支会创建一个与本地分支同名的远程分支。

git push origin myNewBranch

然而,如果你使用 local_name:remote_name 这种表示法,本地分支会以不同的名称创建在远程仓库中:

git push origin myNewBranch:someRemoteBranch

因此,你可以通过推送一个空的本地分支来删除远程分支:

git push origin :myNewBranch
git push origin :someRemoteBranch

现在你只有一个最新的 main 分支,你可以创建一个新分支,然后重复修改文件、提交、推送、提交拉取请求、合并和更新的步骤。

git checkout main
git checkout -b anotherBranch

如果你不想删除已有的自定义分支,可以强制将其更新为与更新后的 main 分支一致;然后你就可以对该分支进行任何操作,包括添加更多提交并推送到远程 origin 仓库。

git checkout myNewBranch
git reset --hard main
git push -f origin myNewBranch

像这样硬重置分支通常并不需要。在大多数情况下,你应该遵循创建新分支、提交更改、推送更改、合并分支,然后删除分支这一流程。

高级 Git 操作

搜索

一些方便的工具可以帮助你找到所需内容:

搜索文件名

使用 git ls-files 在仓库中搜索文件名包含特定字符串的文件。以下示例将返回所有文件名中包含“dxf”的文件。

git ls-files *dxf*


搜索字符串

使用 git grep 在仓库中搜索文件本身包含特定字符串的文件。以下示例将返回每个文件中包含“dxf”的所有实例。

git grep dxf


解决合并冲突

使用 git merge 合并分支,或者使用 git rebase 对分支进行变基时,有时会遇到冲突,因为文件可能同时被其他作者修改了。如果发生这种情况,你应该查看双方的更改(另一作者的和自己的),然后决定如何以最佳方式将两套更改组合在一起。这通常是一个无法自动化的手动过程;程序员必须理解代码,决定移动、重写或舍弃哪些代码来解决冲突。

一旦发生冲突,可能会出现类似这样的消息。

CONFLICT (content): Merge conflict in src/Mod/source_code.py
error: Failed to merge in the changes.
Patch failed at 1234 Some commit message when editing source_code.py

如果已安装并为 Git 配置了专门的差异比较工具(例如 Gnome 的 Meld),则可以使用 mergetool 操作来检查并解决冲突。

git mergetool

Meld 工具通常显示三列;两侧的两列显示两个冲突文件,而中间的列显示最终将被保存并提交的新代码。因此,需要编辑中间这一列,使其整合两侧列的代码。一旦冲突解决并保存了新的源代码(中间列),就可以关闭 Meld 工具。然后,可以继续执行 mergerebase 操作。

git merge --continue
git rebase --continue

有关合并和解决冲突的更多信息,请参阅:

检查更改

使用 log 操作检查单个文件在多次提交中的历史记录:

git log --patch path

其中 path 可以是任意目录或文件。除了 --patch 之外,也可以使用简写形式 -p-u

检查两个分支之间的更改

使用 logdiff 操作配合分支名称,检查两个分支之间的更改:

git log main..myBranch
git diff main..myBranch

log 操作显示提交记录,而 diff 则显示文件中的实际更改。

重置文件和目录

如果你不小心修改了某个文件或目录,你可能希望完全撤销这些更改,以恢复到源代码之前的状态。

这可以通过使用 checkout 操作快速完成:

git checkout path
git checkout .

这将把 path(一个文件或目录)恢复到其在分支最新提交时的状态,丢弃所有尚未提交的更改。如果 path 是单个点号 .,则会恢复当前目录下的所有文件。

如果你意外添加了文件和目录,可以使用 clean 操作:

git clean -df

这将强制删除所有未被仓库跟踪的文件和目录(-df),即那些之前未通过 add 操作包含进来的文件与目录。

要完全重置仓库,丢弃所有未提交的修改,请使用 reset 操作:

git fetch
git reset --hard FETCH_HEAD

其中 FETCH_HEADupstream 仓库的最新提交指针。也可以使用其他提交。

revert 操作也可以撤销更改。然而,该命令是通过在历史中添加另一个提交来实现这一点;在许多情况下,这并非期望的做法。

修剪旧分支

如果你已经向 upstream 仓库提交了许多分支,并且这些分支已经被合并,你可能希望从本地系统中删除它们。在线的 origin 仓库中的分支可以在合并后立即删除。然后,你可以使用 fetchremote 操作的 --pruneprune 选项,来移除本地对这些分支的引用。

git fetch --prune origin
git remote prune origin

最后,你可以在本地删除这些分支。

git branch -D myBranch

过一段时间后,使用 gc 操作进行垃圾回收也是一个好习惯。这可以清理不必要的文件并压缩本地文件版本,以优化仓库在本地磁盘上的使用空间。

git gc

处理补丁

尽管 Git 允许你通过 git merge(在本地计算机上)或拉取请求(在远程仓库中)合并不同的代码分支,但有时可能需要创建传统的“补丁”,作为附件通过电子邮件发送。以下工作流程说明了如何完成此操作。

创建补丁

git branch -v
git checkout myBranch
git format-patch main --stdout > ../myCode.patch
git format-patch HEAD^
git format-patch HEAD~1

插入符号 ^ 的数量或数字 1 表示应该考虑的提交数量,即 ^^^~3 会为三个提交创建三个补丁。

git format-patch HEAD^

这将创建一个或一系列补丁,并采用以下命名规则。

XXXX-commit-message.patch

其中 XXXX00009999 之间的数字,而提交信息构成了文件名的主要部分,例如:

0001-fix-ViewProjMatrix-getProjectionMatrix.patch

应用补丁

Git 可以合并补丁或差异文件。想了解更多关于此过程的信息,请阅读 使用 Git 应用补丁

如果你的系统中已经有补丁文件,直接应用它即可。

git apply myCode.patch

你可以使用 curl 从网站下载补丁,然后通过 git 应用它。

curl -O https://some.website.org/code/myCode.patch
git apply myCode.patch

在 GitHub 提交、拉取请求或比较视图的 URL 末尾添加 .diff.patch,网站就会显示该页面的纯文本视图。

你可以将 curl 指向仓库中某个特定的提交补丁,然后通过管道直接传递给 git 来应用该补丁。

curl https://github.com/FreeCAD/FreeCAD/commit/c476589652a0f67b544735740e20ff702e8d0621.patch | git apply -

反转补丁

当你应用一个补丁时,会修改一些文件。然而,这些修改在提交更改之前并不是永久性的。因此,如果你想撤销一个补丁,可以使用以下指令。

这将撤销已应用的更改,前提是你仍然能够访问原始的补丁文件。

git apply -R myCode.patch

或者,这将移除分支上尚未提交的更改。

git checkout -f

贮藏 Git 提交

假设你在某个分支上工作,但发现自己对源代码所做的一些修改超出了当前分支的范围;换句话说,这些更改放到另一个分支中会比当前分支更合适。这时可以使用 git stash 命令,将这些尚未提交的本地更改临时存储起来。

git stash

如果将来你想使用那些提交,可以将这些提交从贮藏中“弹出”并放入你的工作分支。

git stash pop

或者,如果你决定不再需要那些保存的提交,也可以将提交从贮藏中完全丢弃。

git stash drop

你可以使用以下命令列出多个贮藏提交:

git stash list

要了解更多信息,请阅读 你可能不知道的 Git stash 实用技巧

在本地检出 GitHub 请求

在本地检出 GitHub 请求

在本地检出 GitHub 拉取请求


Blame 功能

GitHub 上的 Blame 功能可用于查看每一行代码是由哪次提交引入或最后修改的。要启用该功能,在查看文件时从“Code”选项卡切换到“Blame”选项卡,或者选中特定行(点击其行号),按下 ... 按钮并选择“View git blame”。关于 Blame 功能的更多信息,请参阅 本论坛帖子。相关的 git 命令文档请参见 此处

二分查找

git bisect 是一种用于定位引入 bug 的具体提交的方法。

你需要找到两个提交:

然后在终端中输入以下内容:

git bisect start
git bisect good abcd
git bisect bad efgh

结果:git 会检出这两个提交之间的中间点。

下一步是构建并测试代码。如果系统运行正常,则输入以下命令继续该过程:

git bisect good

重复上一步骤,即构建代码并对其进行测试。

如果系统出问题了,请输入:

git bisect bad

根据测试结果,重复之前的步骤,应用 goodbad

最终,git 会告诉你 wxyz 是第一个有问题的提交。

最后,要退出二分查找过程,请输入:

git bisect reset

注意:如果好的提交和坏的提交相隔较远,git bisect 会花费很长时间。

FreeCAD 修订号

与使用连续数字作为修订号的 Subversion 不同,Git 会为每次提交生成一个 SHA-1 哈希值。哈希值是一个长的字母数字字符串,看起来像这样

9b3ffef570596e184006287434fba54a4b03ccc3

最新修订号

要查找特定分支的最新修订号,请使用带有 --count 选项的 rev-list 操作。需提供分支名、远程仓库、标签,或像 HEAD 这样的特殊指针,以指示该特定对象中的最后一次提交。

git rev-list --count main
git rev-list --count HEAD
git rev-list --count origin

或者浏览 GitHub 上的仓库,并查看特定分支中显示的提交数量。

特定提交哈希值的修订号

由于哈希值是一个字母数字字符串,因此用它来判断某个提交相对于另一个哈希值是更旧还是更新并不太方便。要查找特定哈希值的修订号,同样使用 rev-list 操作;输入可以是完整的哈希值,或者是唯一的部分哈希值(通常前 7 位就足够了)。

git rev-list --count ab1520b872821414c6ce4a15fb85d471ac2a2b03
git rev-list --count 9948ee4

特定提交号的修订哈希值

如果我们有一个提交编号,比如 15000,并且想要找到对应的哈希值,我们需要计算从该点到最后一次提交(HEAD)之间的提交数量。首先,获取最新的提交编号。

git rev-list --count HEAD
17465

然后减去我们想要的那个提交。

17465 - 15000 = 2465

然后使用 log 操作来显示所有提交及其哈希值。--skip 选项会跳过我们计算出的提交数量差额,从而直接到达我们正在寻找的哈希值。

git log --skip=2465
commit 44c2f19e380e76b567d114a6360519d66f7a9e24

由于日志可能会显示两个相近的提交,请确认这是正确的提交编号。如果相差一个,只需按顺序选择下一个提交(前一个或后一个)并再次检查。

git rev-list --count 44c2f19e38
15000

修订号在 FreeCAD 界面中的显示

使用 Std About 工具显示的版本号定义在 src/Build/Version.h 中,该文件是在运行 cmake 工具进行编译时生成的。更多信息请阅读 从 git 源代码中提取版本号

添加其他仓库(远程仓库)

FreeCAD 项目的几位协作者拥有自己的 Git 仓库,他们在此进行工作开发,或者在将新想法纳入官方源代码之前进行试验。当这些协作者发起拉取请求时,你可能希望获取他们的源代码,以便亲自测试他们的代码。

使用 git remote 命令添加这些其他仓库,以便你可以 fetchpull 它们的代码。

git checkout main
git remote add OTHER_USER OTHER_URL
git fetch OTHER_USER
git checkout -b OTHER_BRANCH OTHER_USER/OTHER_BRANCH

例如,我们来添加 Bernd 的远程仓库:

git remote add bernd http://github.com/berndhahnebach/FreeCAD_bhb

git fetch 命令会从该远程仓库下载引用。

git fetch bernd

列出你自己仓库中的所有分支,以及你添加的远程仓库中的分支。Bernd 的分支会显示为 remotes/bernd/<branchname>

git branch -a

现在,让我们查看 bernd 的 femdev 分支最近 10 次提交的摘要列表。

git log -10 --oneline remotes/bernd/femdev

现在我们可以切换到想要检查的分支。

git checkout remotes/bernd/femdev

然后我们可以基于该远程分支创建一个本地分支。这个本地分支我们可以进行修改,并添加我们自己的代码。

git checkout -b local_branch_name /remotes/bernd/femdev

你可能希望将新获得的分支通过 git rebase 变基到 upstream/main 分支上,以确保它使用的是最新的代码。如果出现冲突,则需要在此时解决。

git pull --rebase upstream main

新分支已准备好进行修改和编译,如 编译 所述。

请前往 FreeCAD 论坛 的开发板块,以进一步讨论开发相关事宜。

延伸阅读