使用 Git 提交
本文档面向 PostgreSQL 项目 提交者。常规项目贡献者应该查看有关 提交补丁 的介绍。这不是有关使用 git 的完整教程。请参阅 使用 Git 或 git 文档。提交者可能还想查看 提交清单 页面。
常见设置
1. 要连接到 gitmaster 仓库,您需要将 PostgreSQL SSH 密钥加载到 SSH 代理中,或将其放置在 SSH 知道要查找的位置,例如~/.ssh/authorized_keys.
2. 由于合并提交可能不会被推送,因此最好将您的仓库设置为变基而不是合并。如果没有这样做,如果有人在您拉取后并在您推送之前推送了提交,您的本地仓库将包含一个合并提交,您需要在推送之前手动删除它。
cd postgresql git config branch.master.rebase true git config branch.autosetuprebase always
这些命令中的最后一个确保您创建的任何后续跟踪分支将自动配置 branch.<name>.rebase。
3. 您推送的任何提交都必须具有匹配的作者和提交者标签,您的姓名和电子邮件地址必须与服务器上配置的地址匹配。因此,如果您是Foo Bar <[email protected]>,请执行
git config user.name "Foo Bar" git config user.email [email protected]
如果您对所有提交的 git 仓库都使用相同的电子邮件地址,您可以在全局范围内对其进行配置(或可能已经配置);这将更新~/.gitconfig而不是当前仓库的.git/config。
git config --global user.name "Foo Bar" git config --global user.email [email protected]
4. 在真正执行之前,始终使用 "git push --dry-run" 选项!
使用单个克隆提交
1. 克隆主仓库。请注意,这与公共仓库不同;但是,来自主仓库的更改会定期推送到公共仓库。
git clone ssh://[email protected]/postgresql.git
2. 要将补丁提交到 master 分支(相当于 CVS HEAD),您可以使用任何正常的 git 命令。例如,如果您手动修改了文件或应用了来自邮件列表的补丁,该补丁修改了现有文件但没有创建任何新文件,您只需执行
git commit -a
如果您添加了新文件,您必须首先git add它们。
git add file1 file2 file3 git commit -a
或者,如果要提交的更改在本地分支上,您可以使用以下命令将分支上的提交折叠成跟踪分支上的单个提交
git merge --squash branchname
确保使用--squash,否则您将最终得到一个合并提交。
3. 要进行回溯,您可以检出适当的分支;本地跟踪分支将自动创建。例如
git checkout REL9_0_STABLE ...hack, hack... git commit -a
4. 最后,您必须将更改推送到服务器。
git push
这将推送您更新的所有分支中的更改,但只会推送远程侧也存在的分支;因此,您可以拥有不会被推送的本地工作分支。或者,为了避免错误,您可以将您的仓库配置为仅推送当前分支
git config push.default tracking
5. 要拉取其他人提交的更改,当然可以使用
git pull
如果您对服务器上已更改的任何分支有任何未推送的更改,那么 (1) git 会自动尝试对当前签出的分支进行变基(因为您在步骤 #2 中进行了配置),以及 (2) 每个需要变基的其他分支将与服务器不同步。解决此问题的最简单方法是只需检出有问题的分支并重新拉取,例如
git checkout REL9_0_STABLE git pull
6. 如果您的一个跟踪分支以某种方式被搞乱了(例如,您不小心将其合并到其中,或者提交了带有错误的作者姓名/标签的内容),并且您不知道如何修复它,您只需将其恢复到它在主服务器上存在的状态,丢弃您的本地更改,例如
git checkout master git reset --hard origin/master
确保在两个命令中都使用相同的分支名称。
使用多个克隆提交
在将补丁应用于多个分支时,不断切换分支可能会很乏味;能够并排查看所有不同版本会很不错。此外,PostgreSQL 构建系统不够智能,无法在您切换主要版本而不清理所有中间文件时执行正确的事情,因此,如果您确实切换分支,您需要每次都进行完整的重建。(git clean -dfx是清理仓库中所有杂乱文件的有效方法,但请注意您那里没有要保留的任何未跟踪文件。)
使用git clone --reference不推荐使用,除非是短期、临时副本,因为随后的git gc会导致数据丢失。相反,请使用下面描述的技术之一。
每个分支独立克隆
使用多个克隆提交的最简单方法是按照上面针对单个克隆的说明创建它们,并在每个副本中保留不同的分支签出。您可以将每个克隆配置为仅拉取您在该克隆中关心的分支。例如,对于 REL9_0_STABLE 分支
git clone ssh://[email protected]/postgresql.git REL9_0_STABLE cd REL9_0_STABLE git checkout REL9_0_STABLE git config branch.REL9_0_STABLE.rebase true git config user.name "Foo Bar" git config user.email [email protected] git config remote.origin.fetch '+refs/heads/REL9_0_STABLE:refs/remotes/origin/REL9_0_STABLE' git branch -D master
这种方法的一个缺点是您将使用更多磁盘空间:截至撰写本文时,每个仓库的.git目录略大于 220MB。如果这是一个问题,请使用下面描述的方法之一。
每个分支依赖克隆,从本地仓库推送和拉取
Git 在克隆存储在本地机器上的仓库时会自动使用硬链接。因此,您可以执行以下操作
git clone --bare --mirror ssh://[email protected]/postgresql.git git clone postgresql REL9_0_STABLE cd REL9_0_STABLE git checkout REL9_0_STABLE git config branch.REL9_0_STABLE.rebase true git config user.name "Foo Bar" git config user.email [email protected] git config remote.origin.fetch '+refs/heads/REL9_0_STABLE:refs/remotes/origin/REL9_0_STABLE' git branch -D master
除了第一个步骤之外,所有这些步骤都应该为您希望维护克隆的每个分支重复。(如果您的用户名和/或电子邮件是全局配置的,您不需要为每个新仓库重新配置它们。)
通过这种方法,REL9_0_STABLE 仓库将从本地 postgresql 仓库拉取并推送到它,而本地 postgresql 仓库又会从主服务器拉取并推送到它。因此,您必须执行以下操作才能更新(假设两个仓库都在您的主目录中)
cd ~/postgresql.git git fetch cd ~/REL9_0_STABLE git pull
要推送,您必须执行以下操作
cd ~/REL9_0_STABLE git push cd ~/postgresql.git git push
如果您打算定期执行此操作并使用多个分支,则最好将其编写为脚本。
本地克隆,重新指向源
上一节中描述的解决方案可能不方便,因为它需要两次推送和拉取每个提交。一种避免此问题的可能方法是从主服务器创建单个克隆,然后在本地多次克隆它,然后将每个本地克隆的源服务器重新指向主服务器。在初始克隆时存在的历史记录将在所有本地克隆之间共享(使用硬链接),但任何在初始设置后获取的新历史记录将在每个本地克隆中占用单独的存储空间。这仍然可以节省大量的磁盘空间,同时避免了推送和拉取两次的不便。
要执行此操作,请按照上一节中的说明设置每个克隆,然后执行以下其他步骤
git remote set-url origin ssh://[email protected]/postgresql.git git remote update git remote prune origin
每个分支依赖克隆,从本地仓库拉取,并推送到远程仓库
这种方法类似于 "每个分支依赖克隆,从本地仓库推送和拉取" 的方法,但您无需推送到本地仓库,而是通过在本地镜像的每个克隆中执行以下操作,将其设置为直接推送到远程仓库
git remote set-url --push origin ssh://[email protected]/postgresql.git
这需要一个相当新的版本的 git。
您还可以通过使用 shell 别名来避免将 fetch 推送到镜像,然后在单独的步骤中拉取到克隆中。以下是一个与 bash 一起使用的函数,可以将这些步骤合并起来
function pgpull () { pushd /path/to/mirror > /dev/null git fetch popd > /dev/null git pull }
使用单个克隆和多个工作目录提交
注意:在较新的 git 版本中,据称 'git worktree' 命令可以用于以更官方支持的方式完成此操作。
这种方法类似于使用单个克隆的方法,但您可以始终保持每个活动分支签出。
1. 创建一个目录来保存所有克隆的仓库和所有工作目录(这使您更容易记住它们都链接到同一个克隆)。
mkdir pgsql-git; cd pgsql-git
2. 克隆主仓库。请注意,这与公共仓库不同;但是,来自主仓库的更改会定期推送到公共仓库。
git clone ssh://[email protected]/postgresql.git
这将创建一个名为 "postgresql" 的目录,master 分支会自动签出到该工作目录。克隆的 git 仓库位于 "postgresql/.git" 中,它与我们稍后创建的所有其他工作目录共享。
3. 阻止自动 git 垃圾回收。
git --git-dir=postgresql/.git/ config gc.auto 0
基本原理:使用这种方法,您从单个仓库中签出了多个版本,但 "git gc" 不了解其他工作目录。这通常不是问题,但如果您在 master 工作目录以外的工作目录中运行 "git gc",而您已暂存但未提交,则这些更改可能会丢失。这是git-new-workdir的已知限制,请参阅 [1]。确保在所有后端分支签出处于非干净状态时不要运行 "git gc",这样您应该是安全的。
4. 为所有活动后端分支创建工作目录。该git-new-workdir工具位于 git contrib 目录中,下面示例中的路径适用于 Debian
sh /usr/share/doc/git/contrib/workdir/git-new-workdir postgresql/.git/ 90stable cd 90stable git checkout -b REL9_0_STABLE origin/REL9_0_STABLE cd ..
<repeat for every active back-branch>
5. 您现在可以像在 CVS 上一样分别在签出上工作。所有本地分支(跟踪相应的远程分支)都位于所有工作目录共享的仓库中。要将补丁提交到任何分支,您可以使用任何正常的 git 命令。例如,如果您手动修改了文件或应用了来自邮件列表的补丁,该补丁修改了现有文件但没有创建任何新文件,您只需执行
git commit -a
如果您添加了新文件,您必须首先git add它们。
git add file1 file2 file3 git commit -a
或者,如果要提交的更改在本地分支上,您可以使用以下命令将分支上的提交折叠成跟踪分支上的单个提交
git merge --squash branchname
确保使用--squash,否则您将最终得到一个合并提交。
6. 最后,您必须将更改推送到服务器。这将推送您已提交到 *所有* 分支中的更改
git push --dry-run
这将显示要推送的内容,但不会执行任何操作。使用 "git log" 和 "git diff" 以及打印出来的提交 ID 范围仔细检查更改。一旦您满意,就真正推送它们
git push
7. 要拉取其他人提交的更改,当然可以使用
git pull
如果您对服务器上已更改的任何分支有任何未推送的更改,那么 (1) git 会自动尝试对当前签出的分支进行变基(因为您之前进行了配置),以及 (2) 每个需要变基的其他分支将与服务器不同步。解决此问题的最简单方法是只需检出有问题的分支并重新拉取,例如
git checkout REL9_0_STABLE git pull
8. 如果你的某个跟踪分支莫名其妙地乱了(例如,你意外地合并到它,或者用错误的作者姓名/标签提交了一些东西),而你又不知道如何修复它,你可以直接把它恢复到它在主分支上的状态,丢弃你的本地更改,例如:
git checkout master git reset --hard origin/master
确保在两个命令中使用的分支名称与你所在的目录匹配。
在 origin 上创建一个新的发布分支
要从当前的 master 尖端在 gitmaster 仓库中创建一个新分支,请执行以下操作:
git pull # be sure you have the latest "master" git push origin master:refs/heads/"new-branch-name"
例如
git push origin master:refs/heads/REL_12_STABLE
之后,按照你使用的任何之前的安排在本地检出分支。
按照惯例,只有发布分支应该被推送到 gitmaster 仓库;不要将实验性分支或功能分支推送到那里。