🔗 Git 提示
此页面归档了在 Squid 开发上下文中可能使用的 Git 命令。它并非 Git 或 GitHub 的指南。这里的大多数命令都面向将最终向 Squid 项目提交拉取请求(pull request)的开发者。
许多后面的命令依赖于前面命令(部分)所示的设置。您的设置可能不同;Git 相关的命名约定差异很大。如果您从中间开始,请确保在复制粘贴任何命令之前理解您正在做什么!
🔗 当缺少命令时
使用搜索引擎来解决 Git 和 GitHub 的问题。几乎所有关于 Git 和 GitHub 的基本问题(以及许多高级问题)都可以在网上找到答案。掌握 Git 有帮助,但对于 Squid 开发来说并非必需。对于典型的 Squid 开发所需的 Git 操作,几乎算不上火箭科学。
🔗 在 GitHub 上创建您的公共 Squid 存储库
- 登录 GitHub。
- 导航到 Squid 的 存储库。
- 点击“Fork”按钮。
如果您是某个组织的一部分,该组织可能已经有一个 Squid 存储库的 fork,您应该使用该 fork 而不是直接 fork。
🔗 创建您的本地 Squid 工作区
您的 Git 工作区将是您的公共 Squid 存储库(又名“origin”远程)、官方 Squid 存储库(又名“upstream”远程)以及您的私有(未发布)Squid 分支的组合。
-
将您的 GitHub 上的公共 Squid 存储库克隆到您的本地工作区。默认情况下,Git 会将您的公共存储库称为“origin”。这就是您发布开发分支的地方。要获取第一个命令所需的正确存储库 .git 地址,请在查看 GitHub 上的存储库时点击“clone or download”按钮。“clone or download”按钮提供 https 和 ssh 协议;对于开发工作,您可能会发现 ssh 身份验证更容易使用。下面的示例使用了 ssh 地址。
您可能需要先将您的公共 ssh 密钥上传到您的 GitHub 账户。$ git clone git@github.com:YOUR_GITHUB_LOGIN/squid.git $ cd squid $ git remote -v # Should show you the origin repository address -
指向 GitHub 上的官方 Squid 存储库。这些说明称该存储库为“upstream”,但远程的名称由您决定。您永远不会推送到此存储库,但您会在此基础上提交拉取请求。
$ git remote add -m master upstream git@github.com:squid-cache/squid.git $ git remote -v # Should show you the origin and upstream repository addresses $ git remote set-url --push upstream upstream-push-disabled # prevents and highlights accidental pushes -
可选地,加载 Git 注释以查看原始 Bazaar 版本号、–fixes URL 以及 Git 日志中更多的协作者姓名。
$ git fetch upstream refs/notes/commits:refs/notes/commits
如果您是某个组织的一部分,该组织可能提供其自己的 Squid 注释,您应该加载这些注视为替代或附加于官方注。
🔗 开始处理功能或更改
大多数独立的代码更改都需要一个专用的 Git 分支。如果您想提交您的更改以供官方包含,您必须为每个此类提交(又名拉取请求或 PR)创建一个专用分支。Git 分支非常廉价。每个分支本质上只是一个指向分支最新提交的命名指针。
这些命令假定您的更改基于最新的 官方 master 分支。
-
确保您的 upstream master 是最新的
$ git fetch upstream master -
基于 upstream master 的最新点创建一个新的本地功能分支。此示例使用“support-foobar”作为分支名称。
$ git checkout -b support-foobar upstream/master
现在您可以对您的本地功能分支进行更改并提交。
🔗 将您的更改与官方代码进行比较
-
要与您之前获取的官方代码进行比较
$ git diff upstream/master -
要与创建功能分支时存在的官方代码进行比较
$ fork_point=$(git merge-base --fork-point upstream/master support-foobar) $ git diff $fork_point
使用git diff –check … 来检查基本的空白字符问题。
🔗 将所有功能分支的更改压缩成一个提交
这些命令会重写分支历史。重写历史可能会弄乱甚至永久破坏您的工作!考虑在压缩本地树之前将所有更改推送到您的 GitHub 存储库,并且在确定压缩后的分支包含与最后一次推送的提交相同的代码之前不要发布该分支!
如果您需要同时 rebase 和 squash 您的功能分支,您可以使用交互式 rebase 并将默认的“pick”替换为“squash”命令。生成的压缩提交将获得来自第一个功能分支提交的元数据,如日期,这会混淆读者和一些工具(尤其是在长期存在的功能分支上),但您可以使用类似git commit –amend –date=”$(date)” 的命令来修复它。同时做两件事(即 squashing 和 rebasing)在顺利进行时更快,但发现和修复问题也更困难。此外,rebase 一个已经压缩的分支可能会减少冲突的数量,但也可能产生更复杂的冲突。选择您的毒药。
-
切换到您想要压缩的本地最新功能分支
$ git checkout support-foobar -
找到您的功能分支最初基于的 master 提交,可以通过检查git log support-foobar 或使用以下技巧(据报道在某些情况下会失败)来确定。
$ fork_point=$(git merge-base --fork-point upstream/master support-foobar) -
在进行任何更改之前,请仔细检查您是否找到了正确的 fork 点。例如
$ git show $fork_point和/或
$ git log | less +/$fork_point -
撤销功能分支中直到 fork 点的所有提交,同时保留它们累积的结果,将其暂存到您的工作目录中
$ git reset --soft $fork_point -
用新的提交消息重新提交暂存的结果,该消息总结了功能分支上的所有更改
$ git commit如果您需要查看旧的提交消息,并且如前所述已将未压缩的更改发布到 GitHub,那么您仍然可以轻松地从以下位置获取它们:
$ git log origin/support-foobar -
仔细检查压缩后的结果是否与发布的(未压缩的)功能分支相同
$ git diff --exit-code origin/support-foobar || echo 'Start panicking!' -
在感觉满意后,发布您压缩的更改,永久删除旧的功能分支提交
$ git push # will fail, giving you the last change to check its intended destination before you add --force
🔗 将您的功能分支 rebase 到与当前 upstream master 同步
这些命令会重写分支历史。重写历史可能会弄乱甚至永久破坏您的工作!考虑在 rebase 本地树之前将所有更改推送到您的 GitHub 存储库。
如果您需要同时 rebase 和 squash 您的功能分支,您可以使用下面显示的交互式 rebase 命令,并将默认的“pick”替换为“squash”命令。生成的压缩提交将获得来自第一个功能分支提交的元数据,如日期,这会混淆读者和一些工具(尤其是在长期存在的功能分支上),但您可以使用类似git commit –amend –date=”$(date)” 的命令来修复它。同时做两件事(即 squashing 和 rebasing)在顺利进行时更快,但发现和修复问题也更困难。此外,rebase 一个已经 压缩 的分支可能会减少冲突的数量,但也可能产生更复杂的冲突。选择您的毒药。
-
确保您的 upstream master 是最新的
$ git fetch upstream master -
切换到您想要 rebase 的本地最新功能分支
$ git checkout support-foobar -
开始交互式 rebase 过程。下面的命令应该会启动您的编辑器,以便您可以告诉 Git 如何处理列出的每个提交。在简单的情况下,默认的“pick”操作效果很好。
$ git rebase --interactive upstream/master -
在感觉满意后,发布您 rebase 后的功能分支,永久删除旧的功能分支提交
$ git push # will fail, giving you the last change to check its intended destination before you add --force
🔗 提交拉取请求
-
在您的 GitHub 存储库中发布您的功能分支
$ git push --set-upstream origin -
当您 准备好时
🔗 更新之前提交的拉取请求
-
当您 准备好时,在您的 GitHub 存储库中发布您的更新。
$ git push -
GitHub 会注意到您的公共存储库中的更新,并在官方存储库的拉取请求中反映出来。现在是时候浏览拉取请求中的审阅者评论,并根据需要回应您已解决的问题,使用“Done”、“Fixed”或其他评论。
如果您 rebase 了本地功能分支或以其他方式更改了其先前发布的历史记录,那么您将需要强制推送您的更改。强制推送通常对于您尚未明确与任何人(除通过拉取请求)共享的功能分支是可行的。在大多数其他情况下,强制推送是非常糟糕的主意,因此请确保您知道您在做什么!
🔗 将您的功能分支 rebase 到另一个官方分支
从 master 分支创建的功能分支通常需要 rebase 到一个版本化的 Squid 分支(例如 v4.0),以便可以将该功能移植到特定的 Squid 发行版系列。当您开发了一个,例如 v3.5 的修复,但后来意识到 Squid 项目要求您提交一个针对master 分支的拉取请求时,也会出现类似的需求。
要简单地将官方提交的更改挑选(cherry-pick)到新的功能移植分支,请参阅“git cherry-pick –help”。本节介绍更复杂(且相对罕见)的用例,在这些用例中,rebase 旧的功能分支比将单个提交挑选到新的功能分支更合适。
-
这是一个可能用于切换功能分支基础的第一个步骤。
git rebase --fork-point upstream/master --interactive --onto upstream/v4.0上述命令将基础分支从官方 master 分支切换到名为 v4.0 的官方分支。
如果在 rebase 之前,您的功能分支与官方基础分支不同步,那么您需要使用HEAD~1 或类似的引用/SHA 来识别正确的 fork 点(即您功能分支上的最后一个官方提交)。请注意,此示例假定您功能分支上的所有提交都已位于其基础分支之上。如果您的用例中此假设不成立,那么您需要在切换基础分支之前将分支提交 rebase 到其基础分支之上(那里有另一个 提示)。 -
更改基础分支通常会导致冲突,您需要解决这些冲突。git rebase –continue 命令将使您在 rebase 过程中前进。此外,即使没有冲突,您也可能需要修改代码以使其在另一个代码库中正常工作。此提示不涵盖这些常见的复杂情况。
-
此示例不包含最终的“git push”命令,该命令会在解决所有冲突并将功能在新基础分支上进行测试后使您的更改公开。发布 rebase 后的功能有两个主要选项:
-
将更改推送到旧的 origin 功能分支(这将覆盖该分支上旧的公共更改,并更新任何与该功能分支关联的拉取请求)。此处需要强制推送。
-
或者,您可以创建一个新的 origin 功能分支来专门用于此移植(然后基于这个新创建的功能分支提交一个新的拉取请求)。不需要强制推送。
-
可能会诱惑让 Git 为您找出 fork 点。在大多数处理官方基础分支之间切换的情况下,Git 会找到一个 fork 点,其中目标官方分支(即上面示例中的 v4.0)从另一个官方分支(即上面示例中的 master)分叉出来,导致您 rebase 后的分支包含数百个不需要的官方提交,而不是仅仅您的功能更改。这就是为什么上面的示例明确设置了 fork 点!幸运的是,功能分支的提交很容易隔离(例如,通过查看分支日志),前提是所有这些提交都已经位于当前基础分支之上(这是实现更轻松切换的先决条件)。
🔗 origin/master 会发生什么?
拥有自己的 GitHub 公共存储库的主要目的是让您可以提交拉取请求并与您的协作者或用户共享代码。您分叉存储库中的官方分支副本将变得陈旧,因为您或其他人不需要它们(每个人都应该从上游获取最新的官方代码)。除非您分叉了官方 Squid 存储库来创建分支项目,否则您可以安全地忽略公共 Squid 存储库中 GitHub 上的官方分支副本。您可以偶尔将上游更改拉取到 origin,如下所示,但许多开发者并不 bother 这样做。
$ git push origin upstream/master:master