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

How do I update a GitHub forked repository?

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

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

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


在分叉存储库的本地克隆中,可以将原始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


从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的更新,但是这样做会玷污您的提交历史。改为使用命令行-这很容易。


    以下是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 one提交移到父存储库之前。这个答案总结了这里找到的步骤,这些步骤将把您的fork移动到与父级相同的commit。

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

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

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

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

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


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

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

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


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

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

    1
    2
    git clone [email protected]:your_name/project_name.git
    cd project_name

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

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

    1
    git remote add upstream [email protected]: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


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

    从您的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界面中的此功能。但是,您可以要求[email protected]添加您对此的投票。

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

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


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

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

  • 实际上,可以通过浏览器中上游的任何提交在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时不存在。


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

    结帐到你的分行

    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


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

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

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


    作为对这个答案的补充,我正在寻找一种方法来一次性从上游分支更新克隆的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存储库,以及如何使用最新的更改对它们进行上游处理。