Git Forks 和 Upstreams:操作方法和实用提示

拷贝项目来进行自己的变更可以让您轻松整合自己的贡献。但是,如果您不将这些变更发送回上游(这意味着将其发送回父项存储库),则可能会丢失对它们的跟踪,这可能会导致存储库中的行分歧。为确保所有贡献者都来自同一个地方,您需要了解 git forking 如何与 git upstream 交互的一些原则。在这篇博客中,我将向您介绍基础知识、陷阱,甚至还有一个很酷的提示,助您走在潮流前线。

Git 上游:保持最新状态并做出贡献

首先,我们来详细了解与 upstream 存储库交互的常见设置和最基本的工作流。

在标准设置中,您通常有一个 origin 和一个 upstream远程存储库,后者是项目的把关者,或者是您想要贡献代码的事实来源。

首先,确认您已经为 upstream 存储库设置了远程存储库,最好还设置了 origin 库:

git remote -v

origin  git@bitbucket.org:my-user/some-project.git (fetch)
origin  git@bitbucket.org:my-user/some-project.git (push)

如果您没有 upstream,可以用 remote 命令轻松添加:

git remote add upstream git@bitbucket.org:some-gatekeeper-maintainer/some-project.git

验证是否正确添加了远程存储库:

git remote -v

origin    git@bitbucket.org:my-user/some-project.git (fetch)
origin    git@bitbucket.org:my-user/some-project.git (push)
upstream  git@bitbucket.org:some-gatekeeper-maintainer/some-project.git (fetch)
upstream  git@bitbucket.org:some-gatekeeper-maintainer/some-project.git (push)

现在,您可以使用 fetch 收集 upstream 存储库的最新变更。每次想要获取更新时都要重复此操作:

(如果项目中有尚未合并到主分支的标记,您也应该这样做:git fetch upstream --tags)

git fetch upstream

通常,您希望将本地 main 分支保持为 upstreammain 分支的近似镜像,并在功能分支中执行任何工作,因为它们以后可能会变成拉取请求。

此时,使用 merge 还是 rebase 都没关系,因为结果通常是相同的。我们使用 merge

git checkout main
git merge upstream/main

当您想与 main 分支的 upstream 维护人员分享一些工作时,可以创建一个功能分支。等您觉得满意后,将其推送到您的远程存储库。

您也可以改用 rebase,然后 merge 以确保 upstream 有一组干净的提交(最好是一个)需要评估:

git checkout -b feature-x

#some work and some commits happen
#some time passes

git fetch upstream
git rebase upstream/main

使用 git fork 发布

完成上述步骤后,只需 push 一下,即可在远程拷贝中发布您的工作:

git push origin feature-x
git push -f origin feature-x

就我个人而言,我更喜欢保持历史记录尽可能简洁并选择选项三,但是不同的团队有不同的工作流程。注意:只有在使用自己的拷贝时才应这样做。您永远都不应该重写共享存储库和分支的历史记录

每日提示:提示中的领先/落后数字

fetch 后,git status 会显示您在同步的 remote 分支前面或后面有多少提交。如果您能在忠实的命令提示符下看到这些信息,那不是很好吗?我也这么想,所以我开始用 bash 尝试并逐渐完善。

配置完成后,它在提示符上的显示效果如下:

nick-macbook-air:~/dev/projects/stash[1|94]$

这就是您需要添加到您的 .bashrc 中的内容或等效函数——只是一个函数:

function ahead_behind {
    curr_branch=$(git rev-parse --abbrev-ref HEAD);
    curr_remote=$(git config branch.$curr_branch.remote);
    curr_merge_branch=$(git config branch.$curr_branch.merge | cut -d / -f 3);
    git rev-list --left-right --count $curr_branch...$curr_remote/$curr_merge_branch | tr -s '\t' '|';
}
export PS1="\h:\w[\$(ahead_behind)]$"

内部运作

对于那些喜欢细节和解释的人,以下是它的工作原理:

我们活动当前 HEAD 的符号名称,即当前分支:

curr_branch=$(git rev-parse --abbrev-ref HEAD);

我们得到了当前分支所指向的远程存储库:

curr_remote=$(git config branch.$curr_branch.remote);

我们得到了应该合并这个远程存储库的分支(用一个便宜的 Unix 技巧来丢弃包括最后一个斜杠 [/] 在内的所有内容):

curr_merge_branch=$(git config branch.$curr_branch.merge | cut -d / -f 3);

现在我们有了收集领先或落后提交的计数次数所需的东西:

git rev-list --left-right --count $curr_branch...$curr_remote/$curr_merge_branch | tr -s '\t' '|';

我们使用古老的 Unix trTAB 转换为分隔符 |

git upstream 入门

这是 git upstream 的基本演练——如何在 git 上游设置 git、创建新分支、收集变更、使用 git 拷贝发布,以及远程分支在前面/后面有多少提交的小提示。

Bitbucket Data Center 包括克隆同步,这基本上减轻了开发人员随时了解其克隆最新状态的所有负担,而 Bitbucket Cloud 则提供了一个简单的一步同步,来看看吧!

为您推荐

Bitbucket 博客

DevOps 学习路径

了解有关 Git 的更多信息

在此中心查找更多 Git 指南和资源。