关于Git:如何更新GitHub分叉存储库?

How do I update a GitHub forked repository?

我最近提出了一个项目并应用了几个修复。然后我创建了一个请求,然后被接受。

几天后,另一位撰稿人又做了一次修改。所以我的叉子不包含那个变化。

我怎么能把零钱放进我的叉子里?当我有进一步的更改要贡献时,是否需要删除并重新创建我的fork?或者有更新按钮?

  • 这也可以从Github用户界面完成。我想表扬一下这张海报。【1】:stackoverflow.com/a/21113181/728141
  • 关于这个的另一篇好的博客文章-保持Github fork的更新
  • 在github帮助文章中找到了这个:help.github.com/articles/syncing-a-fork
  • 这是stackoverflow.com/questions/3903817/hellip;的副本吗?
  • 这是一个使用两个github帐户youtube.com/watch进行演示的视频?V= KPE0GTX4YCE


在分叉存储库的本地克隆中,可以将原始Github存储库添加为"远程"。(例如,"远程"就像是存储库URL的昵称-origin就是其中之一。)然后您可以从上游存储库中提取所有分支,并重新调整您的工作以继续使用上游版本。就命令而言:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Add the remote, call it"upstream":

git remote add upstream https://github.com/whoever/whatever.git

# Fetch all the branches of that remote into remote-tracking branches,
# such as upstream/master:

git fetch upstream

# Make sure that you're on your master branch:

git checkout master

# Rewrite your master branch so that any commits of yours that
# aren't already in upstream/master are replayed on top of that
# other branch:

git rebase upstream/master

如果您不想重写主分支的历史(例如,因为其他人可能克隆了它),那么您应该用git merge upstream/master替换最后一个命令。但是,对于尽可能干净地提出进一步的请求,最好重新平衡。

如果已将分支重新设置为upstream/master,则可能需要强制推送,以便将其推送到Github上您自己的分叉存储库中。你可以这样做:

1
git push -f origin master

你只需要在重新平衡后的第一次使用-f

  • 我之所以回答这个问题,是因为它可能完成了作者实际需要的问题。但我也处于同样的情况下,我很好奇:有没有什么方法可以真正地从主回购协议"拉"到我的分叉?或者,如果我从上游提取数据后向上推,上游分叉会被更新吗?
  • 因为您的fork只存在于github上,而github没有通过Web界面进行合并的工具,所以正确的答案是在本地进行上游合并,并将更改推回到您的fork上。
  • 下面是我在使用github时发现的一个很好的教程:gun.io/blog/how-to-github-fork-branch-and-pull-request
  • @Timkating Github确实有Web界面来处理来自其他人请求的合并。我想知道如果我在发送请求时交换目的地和回购协议会发生什么。
  • 请注意,您不必重新设置自己的主分支以确保从干净状态开始,而是应该在单独的分支上工作,并从中发出请求。这将使您的主文件在将来的合并中保持干净,并阻止您使用-f重写历史,这会使所有可能克隆您的版本的人都陷入混乱。
  • 在上游接受您的更改后,您需要重复这些步骤:git fetch upstreamgit rebase upstream/mastergit push origin master
  • @情景提要:我不介意将示例URL从git://更改为https://,但您最后的评论是错误的-Git协议在GitHub上仍然可以正常工作;我怀疑您试图从阻止到端口9418的流量的网络或类似的网络进行尝试。我已经删除了你的编辑。
  • 如果您有本地提交,这是否会在每次尝试从上游获取更新时创建难看的"Merge branch 'master' of github.com:user/repo"提交?当然可以重新设置基,但是如果您将更改推送到Github上的分叉回购,意味着下次您不能重新设置基,而不必为每次提交重新生成哈希,因为它会使所有内容变得一团糟。我真的不知道如何在Github上正确地"维护"一个分叉。
  • 如果您希望在本地拥有原始的repo,并且仍然希望更新您的fork,您可以将fork添加为与上面类似的downstream远程,然后推到它:git push -f downstream
  • 这比Github在这里的帮助要好,这里没有上游设置。
  • @Marklongair"在另一个分支上重播"是什么意思?
  • @克里森:好的,这还不太清楚。REBASE将查看历史中每个提交在其原始点引入的更改(补丁),并尝试将该更改应用于不同的父提交(保留相同的消息和作者信息)。有时,这不能很好地应用,您必须解决冲突。所以我所说的你的承诺被"重放在另一个分支之上"的意思是接受你的每一个不在那个分支上的新承诺,并试图一个接一个地重新创建它们,通过对它们的原始父代做同样的更改。
  • @Timkating为什么我不应该将2个URL(一个用于获取,另一个用于推送)设置为sleepycoders.blogspot.de/2012/05/…。我不太清楚为什么我应该使用马克和这篇博文建议的解决方案。
  • 如果简单地删除并重新分叉,可能会更容易、更快。
  • 我没有使用rebase命令,而是使用了以下命令:git merge --no-ff upstream/master,这样您的承诺就不再是最重要的了。
  • @史蒂克多塞里克不能再同意了。非常遗憾的是,这里的人们认为,在一个钢筋网之后强制推一个公开可见的分支是完全正确的或可以接受的。它使你的叉子几乎对跟随你的任何人都没用……
  • 又一个Git失败。如果该工具应该支持分布式协作,那么为什么执行基本工作流如此困难呢?400万人和2200个加票意味着这个工具失败了。"您可以将原来的Github存储库添加为"远程"库——为什么必须这样做?为什么叉子的时候不做?这个工具怎么这么坏?
  • @JWW:你问为什么需要告诉Git关于最初的Github存储库的信息。这是因为Git是一个分散的版本控制系统,并没有以任何方式绑定到GitHub;很明显Git是在GitHub之前创建的。当您在Github上创建一个分叉存储库并克隆它时,Github知道该存储库是一个分叉;Git没有理由这样做,也没有理由这样做。(为什么克隆人不复制git遥控器?Git是分散的;不同的人需要不同的远程设备;这样做毫无意义。)有关Git中的GitHub集成,请参见GitHub.com/GitHub/Hub。
  • @氡是"分叉"一个Github概念,由网站而不是Git本身引入?
  • 辛贾伊是的。一个Git存储库的单独副本彼此之间没有关系,除了一个存在于您的头脑中或者存在于诸如GitHub之类的外部服务中(或者您通过创建远程设备隐式创建的)。
  • @Radonrosborough当然,在Github这样的网站出现之前,有人考虑过创建开源项目派生的想法,不是吗?尽管我认为Git与开源没有任何关系。
  • @辛贾伊是的,当然。这就是为什么Git明确支持从其他人的更改应用补丁,或者直接从其他人的存储库合并提交(由于支持保存的远程程序列表,这使得最后一步非常容易)。Git不做的事情是以标准化的关系结构为存储库托管一个集中的WebService。我认为,很明显,为什么后者超出了Git的范围。这也是Github存在的原因。和GITLAB。和比特桶。等。
  • @Radonrosborough当然,看起来应该有对这些Web服务的明确支持。这不像Git必须将其支持限制为只支持GitHub或BitBucket。这是一个常见的用例,应用起来比需要的要复杂得多。不过,我想简而言之就是吉特。
  • @Sinjai对这些Web服务有明确的支持。它被称为远程系统。指定URL,然后按/拉。从字面上讲,我认为没有对某些特定服务的硬编码支持,它不可能变得更简单。如果Git在不提供这些信息的情况下隐式地理解不同存储库之间的关系,那么它将需要一个集中的数据库。没有合理的方法将此功能集成到分布式修订控制系统中。
  • Git是如此分散的方式,你可以合并一个分支从一个在你的本地机器上托管的回购,没有互联网的访问,然后合并它与另一个在Gitlab上托管的回购分支,最后再将所有这些重新组合成另一个在GitHub上托管的回购。
  • 这个方法还可以像我在这里描述的那样用于恢复Github在一个浅克隆上的图形(ui Network连接吗?


从2014年5月开始,可以直接从Github更新fork。截至2017年9月,这仍然有效,但这将导致肮脏的承诺历史。

  • 在Github上打开你的叉子。
  • 单击PULL REQUESTS
  • 单击new pull request。默认情况下,Github会将原始数据与您的fork进行比较,如果您没有进行任何更改,则不应该有任何可比较的内容。
  • 如果看到该链接,请单击S切换base。否则,手动将base forkbd下拉列表设置为fork,并将head forkbd设置为上游。现在Github将您的fork与原始fork进行比较,您将看到所有最新的更改。enter image description here
  • create pull request并为pull请求分配一个可预测的名称(例如,Update from original)。
  • 向下滚动到merge pull request,但不要单击任何内容。
  • 现在您有三个选项,但每个选项都会导致提交历史记录不干净。

  • 默认设置将创建难看的合并提交。
  • 如果单击下拉列表并选择"挤压并合并",则所有插入的提交都将压缩为一个提交。这通常是你不想要的。
  • 如果单击rebase和merge,所有提交都将"与"您进行,原始的prs将链接到您的pr,Github将显示This branch is X commits ahead, Y commits behind
  • 所以是的,您可以使用GithubWebUI使用其上游来保持repo的更新,但是这样做会玷污您的提交历史。改为使用命令行-这很容易。

    • 这一次效果很好。第二次这个过程的工作方式不一样:没有出现"切换基础"链接。当我点击"点击创建一个拉请求"时,它在源repo上创建了一个pr。不是我想要的……
    • 仍然有效(2015年3月),尽管"切换基础"链接不再存在。您必须更改"基础"下拉列表,这样两个下拉列表都指向您的分叉,然后您将得到一个提示"跨回购比较",这将带您到您想要的地方。
    • 2015年4月。作品。谢谢。我确实得到了"切换到基地"。但是,步骤6是"创建拉请求"->输入注释->"创建拉请求"。最后在原始文件之前提交1个。
    • @卡特兰(或其他人)-是的,它说"这个分支在……之前有一个承诺……"这是值得担心的事情吗?有没有可能去掉那个信息?
    • 当您完成请求请求后,合并本身似乎是1提交,这是正常的。我注意到交换分支不再适用于我。
    • @Renniepet在"this branch is x commit(s)before(original)"消息中,x commit(s)指的是您所做的那些/那些,而上游forkee尚未(尚未)合并。消息中的x将随着您对该分叉的每次提交而增加。
    • @Renniepet如果你遵循这些步骤(主要是步骤3),你就可以以这个分支结束,即使是用:master。
    • 这项工作,但它没有给你的回购带来新的分支机构。
    • 这是可行的,但用户界面非常笨重。它有时建议将相反的操作作为默认操作,即向原始源发送请求。
    • 它可以工作,但它们应该使用"Rebase Fork"和"Push"按钮。这样我觉得很奇怪。不是很直观……
    • 每次这样做,它都会在源代码之前向fork添加一个commit。
    • 这些步骤需要更新;本质上,您需要将分叉作为基础,与原始分叉作为头分叉进行比较。但是,提交历史不会是干净的。您可以合并,也可以挤压+合并,这将留给您一个合并提交,或者"重新平衡和合并",这将给"这个分支是x提交前面,y提交后面",并且每个提交都将是"with"您。
    • 假设我的fork中的更改主要由对文档的编辑组成,这些编辑可以通过Web执行,而不需要克隆。不会执行"坚持命令行-这很容易。"需要通过我的(可能是按流量计费的)互联网连接克隆存储库?
    • 用一个简单的更新或同步按钮,会不会更好!
    • 丑陋的合并承诺有什么缺点?我不明白。合并就完成了。我有什么东西不见了吗?


    以下是Github同步fork的官方文档:

    Syncing a fork

    The Setup

    Before you can sync, you need to add a remote that points to the upstream repository. You may have done this when you originally forked.

    Tip: Syncing your fork only updates your local copy of the repository; it does not update your repository on GitHub.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    $ git remote -v
    # List the current remotes
    origin  https://github.com/user/repo.git (fetch)
    origin  https://github.com/user/repo.git (push)

    $ git remote add upstream https://github.com/otheruser/repo.git
    # Set a new remote

    $ git remote -v
    # Verify new remote
    origin    https://github.com/user/repo.git (fetch)
    origin    https://github.com/user/repo.git (push)
    upstream  https://github.com/otheruser/repo.git (fetch)
    upstream  https://github.com/otheruser/repo.git (push)

    Syncing

    There are two steps required to sync your repository with the upstream: first you must fetch from the remote, then you must merge the desired branch into your local branch.

    Fetching

    Fetching from the remote repository will bring in its branches and their respective commits. These are stored in your local repository under special branches.

    1
    2
    3
    4
    5
    6
    7
    8
    $ git fetch upstream
    # Grab the upstream remote's branches
    remote: Counting objects: 75, done.
    remote: Compressing objects: 100% (53/53), done.
    remote: Total 62 (delta 27), reused 44 (delta 9)
    Unpacking objects: 100% (62/62), done.
    From https://github.com/otheruser/repo
     * [new branch]      master     -> upstream/master

    We now have the upstream's master branch stored in a local branch, upstream/master

    1
    2
    3
    4
    5
    6
    $ git branch -va
    # List all local and remote-tracking branches
    * master                  a422352 My local commit
      remotes/origin/HEAD     -> origin/master
      remotes/origin/master   a422352 My local commit
      remotes/upstream/master 5fdff0f Some upstream commit

    Merging

    Now that we have fetched the upstream repository, we want to merge its changes into our local branch. This will bring that branch into sync with the upstream, without losing our local changes.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    $ git checkout master
    # Check out our local master branch
    Switched to branch 'master'

    $ git merge upstream/master
    # Merge upstream's master into our own
    Updating a422352..5fdff0f
    Fast-forward
     README                    |    9 -------
     README.md                 |    7 ++++++
     2 files changed, 7 insertions(+), 9 deletions(-)
     delete mode 100644 README
     create mode 100644 README.md

    If your local branch didn't have any unique commits, git will instead perform a"fast-forward":

    1
    2
    3
    4
    5
    $ git merge upstream/master
    Updating 34e91da..16c56ad
    Fast-forward
     README.md                 |    5 +++--
     1 file changed, 3 insertions(+), 2 deletions(-)

    Tip: If you want to update your repository on GitHub, follow the instructions here

    • 这更新了我的本地fork,但我在github.com上的fork仍然显示"43提交落后"。我不得不使用Lobzik的技术为自己创建一个拉请求,将主变更合并到我的github.com fork中。
    • @michaelmcginnis在本地合并后,必须将更改推送到github。git push origin master
    • --follow-tags推可能很聪明:stackoverflow.com/a/26438076/667847
    • 我要分别为所有的分支机构做git merge upstream/master,然后结账去开发分支机构,做git merge upstream/develop
    • stackoverflow.com/a/14074925/470749对我很有帮助,因为我在尝试从Facebook上游的Github帐户获取数据时,得到了Permission denied (publickey). fatal: Could not read from remote repository.


    许多答案最终会将fork one提交移到父存储库之前。这个答案总结了这里找到的步骤,这些步骤将把您的fork移动到与父级相同的commit。

  • 将目录更改为本地存储库。

    • 如果您不是git checkout master,请切换到主分支。
  • 将父级添加为远程存储库,git remote add upstream

  • 发行git fetch upstream
  • 发行git rebase upstream/master

    • 在这个阶段,您将通过键入git status来检查提交将要合并的内容。
  • 发行git push origin master

  • 有关这些命令的更多信息,请参阅步骤3。

    • @MT:但是,你在哪里输入这些命令呢?据我所知,这个问题的要点是如何将您的个人Github fork与主项目重新同步,并从Github完成这一切。换句话说,在没有本地存储库的情况下,如何更新远程fork?
    • @johny使用github总是会创建一个额外的提交。您需要在本地回购的shell中完成所有这些操作,以避免额外的提交。


    自2013年11月以来,已经有一个与Github开放的非官方功能请求,要求他们添加一个非常简单和直观的方法来保持本地分叉与上游同步:

    https://github.com/isaacs/github/issues/121

    注意:由于功能请求是非官方的,因此建议联系support@github.com以添加对要实现的类似功能的支持。上面的非官方特性请求可以用来证明在这方面的利益。


    前言:您的分支是"源",您的分支库是"上游"。

    假设您已经使用如下命令将分叉克隆到计算机:

    1
    2
    git clone git@github.com:your_name/project_name.git
    cd project_name

    如果已经给出,则需要按以下顺序继续:

  • 将"上游"添加到克隆的存储库("源"):

    1
    git remote add upstream git@github.com:original_author/project_name.git
  • 从"上游"获取提交(和分支):

    1
    git fetch upstream
  • 切换到分叉的"主"分支("源"):

    1
    git checkout master
  • 隐藏你的"主"分支的更改:

    1
    git stash
  • 将"上游"的"主"分支的更改合并为"源"的"主"分支:

    1
    git merge upstream/master
  • 解决合并冲突(如果有)并提交合并

    1
    git commit -am"Merged from upstream"
  • 把零钱推到你的叉子上

    1
    git push
  • 拿回你藏起来的零钱(如果有的话)

    1
    git stash pop
  • 你完了!祝贺你!

  • Github还提供了有关此主题的说明:同步fork

    • 部分帮助:git remote add upstream git@github.com:original_author/project_name.git只是git remote add upstream https://github.com/original_author/project_name.git的别名吗?
    • 沃尔夫,你现在应该知道了,但对子孙后代来说……它是ssh的格式。help.github.com/articles/configuring-a-remote-for-a-fork
    • 非常感谢你。git stashgit stash pop部分非常有用


    如果你和我一样,从来没有直接向大师承诺过什么,你真的应该这样做,你可以做以下的事情。

    从您的fork的本地克隆,创建您的上游远程。你只需要做一次:

    1
    git remote add upstream https://github.com/whoever/whatever.git

    然后,只要您想赶上上游存储库主分支,就需要:

    1
    2
    git checkout master
    git pull upstream master

    假设你从未对主人做过任何事,你应该已经做了。现在您可以将本地主机推送到源站远程Github分叉。您还可以在现在最新的本地主机上重新设置开发分支。

    因此,在初始的上游设置和主签出之后,您所需要做的就是运行以下命令来将您的主服务器与上游同步:git pull upstream master。


    截至本答复之日,Github还没有(或者我应该不再说吗?)Web界面中的此功能。但是,您可以要求support@github.com添加您对此的投票。

    与此同时,Github用户Bardiharbow已经创建了一个工具来实现这一点:https://upriver.github.io网站/

    资料来源:https://github.com/upriver/upriver.github.io

    • 虽然我确实找到了一个好主意,但现实是它已经被打破了。它只从我的帐户加载20个回购,甚至页脚重定向到一个不存在的网站。如果这是固定的,我将成为一个大提倡者。
    • 到今天为止,我已经成功地使用上游版本来同步fork和上游版本的repo,所以它是为我的目的工作的,我将继续使用它。
    • @Sorin这20个repo/branch限制(现在是30个)来自github默认分页设置。为了处理这个问题,需要对代码进行一些修改。


    如果您使用的是用于Windows的Github,那么现在他们有了一个单击功能来更新forks:

  • 在用户界面中选择存储库。
  • 点击顶部的"从用户/分支更新"按钮。
    • 这也适用于Mac的Github。


    实际上,可以通过浏览器中上游的任何提交在fork中创建分支:

    • 打开https://github.com//commits/,其中repo是您的fork,hash是提交的完整hash,您可以在上游Web界面中找到。例如,我可以打开https://github.com/max630/linux/commits/0aa0313f9d576affd7747cc3f179feb097d28990,它指向linuxmaster作为写入时间。
    • 点击"tree:…"按钮。
    • 键入新分支的名称,然后按enter

    Enter image description here

    然后,您可以将该分支提取到本地克隆,并且在提交之前进行编辑时,不必将所有数据都推回到GitHub。或者使用Web界面更改该分支中的某些内容。

    它是如何工作的(这是一个猜测,我不知道Github到底做了什么):forks共享对象存储并使用名称空间来分隔用户的引用。因此,您可以通过fork访问所有提交,即使它们在fork时不存在。

    • 这太棒了!这样可以避免将这些提交完全无意义地上载到GitHub。


    遵循以下步骤。我试过了,这对我有帮助。

    结帐到你的分行

    Syntax: git branch yourDevelopmentBranch
    Example: git checkout master

    拉源存储库分支以获取最新代码

    Syntax: git pull https://github.com/tastejs/awesome-app-ideas master
    Example: git pull https://github.com/ORIGINAL_OWNER/ORIGINAL_REPO.git BRANCH_NAME

    • 如果您使用的是GitHub,那么您可能还需要将更改推送到GitHub分支。git push HttpsForYourForkOfTheRepo BRANCH_NAME


    我用这一行更新我的分叉回购:

    1
    git pull https://github.com/forkuser/forkedrepo.git branch

    如果您不想向您的项目中添加另一个远程端点,请使用此选项,就像这里发布的其他解决方案一样。

    • 这方面有限制吗?即,它是否仅适用于自上次更新以来未添加提交、合并、拉请求或拉请求已合并到上游的情况?
    • 它的工作方式就像是从一个远程分支上正常拉动。如果您在本地回购上执行了x承诺,而现在您是原始回购背后的y承诺,则它会将y承诺提交给您的本地分支机构,并且可能会让您解决一些冲突。
    • @lightcc这与从以前添加的遥控器中提取没有什么不同,只是您没有添加遥控器。因此,缺点是,每次想要pull时,都必须输入完整的存储库URL。


    作为对这个答案的补充,我正在寻找一种方法来一次性从上游分支更新克隆的repo(源)的所有远程分支。我就是这样做的。

    这假设您已经配置了一个指向源存储库的上游远程(其中源站是从源站分叉的)并已将其与git fetch upstream同步。

    然后运行:

    1
    for branch in $(git ls-remote --heads upstream|sed 's#^.*refs/heads/##'); do git push origin refs/remotes/upstream/$branch:refs/heads/$branch; done

    该命令的第一部分列出了上游远程repo中的所有头文件,并删除了sha-1后面的refs/heads/分支名称前缀。

    然后,对于每个分支,它将上游远程跟踪分支的本地副本(本地端的refs/remotes/upstream/直接推送到源站的远程分支(远程端的refs/heads/上)。

    这些分支同步命令中的任何一个都可能由于以下两个原因之一而失败:要么上游分支已被重写,要么您已将该分支上的提交推送到您的分支。在第一种情况下,如果您没有对分叉上的分支做出任何承诺,则可以安全地用力推(在上面的命令中添加-f开关,即git push -f)。在另一种情况下,这是正常的,因为fork分支已经分离,在提交被合并回上游之前,不能期望sync命令工作。


    克隆了分叉存储库后,转到克隆所在的目录路径以及Git-Bash终端中的几行。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $ cd project-name

    $ git remote add upstream https://github.com/user-name/project-name.git
     # Adding the upstream -> the main repo with which you wanna sync

    $ git remote -v # you will see the upstream here

    $ git checkout master # see if you are already on master branch

    $ git fetch upstream

    你可以走了。主存储库中所有更新的更改都将推送到您的fork存储库中。

    "fetch"命令对于保持项目中的最新状态是必不可少的:只有在执行"git fetch"时,才会通知您的同事对远程服务器所做的更改。

    您仍可以访问此处以获取进一步的查询


    Android Studio现在已经学会了使用Github Fork存储库(甚至不必通过控制台命令添加"上游"远程存储库)。

    打开菜单VCS→Git

    注意最后两个弹出菜单项:

    • 重新设置我的Github分叉

    • 创建拉请求

    试试看。我使用第一个来同步本地存储库。不管怎样,在你点击"重新设置我的Github Fork"后,可以在Android Studio中访问父远程存储库("上游")的分支,并且你可以轻松地使用它们。

    (我将Android Studio 3.0与"Git集成"和"GitHub"插件结合使用。)

    Enter image description here


    这取决于存储库的大小以及如何进行分叉。

    如果它是一个相当大的存储库,那么您可能希望以一种特殊的方式(例如,删除历史记录)来管理它。基本上,您可以获得当前版本和上游版本之间的差异,提交它们,然后将cherry pick返回master。

    试试看这个。它描述了如何处理大型Git存储库,以及如何使用最新的更改对它们进行上游处理。