如何在GitHub上更新或同步分叉存储库?

我分叉了一个项目,进行了更改,并创建了一个被接受的拉取请求。后来将新的提交添加到存储库中。我如何将这些提交放入我的分叉?

1142304 次浏览

在分叉存储库的本地克隆中,您可以将原始GitHub存储库添加为“远程”。(“远程”就像存储库URL的昵称——例如,origin就是一个。)然后,您可以从上游存储库获取所有分支,并重新调整您的工作以继续在上游版本上工作。就命令而言,可能如下所示:

# 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
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

如果您不想重写master分支的历史记录(例如,因为其他人可能已经克隆了它),那么您应该将最后一个命令替换为git merge upstream/master。但是,为了尽可能干净地进行进一步的拉取请求,最好是重新建立基础。


如果你已经将分支重新基于upstream/master,你可能需要强制推送才能将其推送到你自己在GitHub上的分叉存储库。你可以这样做:

git push -f origin master

你只需要在第一次重设后使用-f

以下是GitHub在同步分叉上的官方文档:

同步分叉

的设置

在您可以同步之前,您需要添加一个指向上游存储库的远程。您可能在最初分叉时已经这样做了。

提示:同步分叉只会更新存储库的本地副本;它不会更新GitHub上的存储库。

$ git remote -v# List the current remotesorigin  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 remoteorigin    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)

同步

将存储库与上游同步需要两个步骤:首先您必须从远程获取,然后您必须将所需的分支合并到本地分支中。

从远程存储库获取将引入其分支及其各自的提交。这些存储在您的本地存储库中的特殊分支下。

$ git fetch upstream# Grab the upstream remote's branchesremote: 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

我们现在将上游的master分支存储在本地分支上游/master中

$ git branch -va# List all local and remote-tracking branches* master                  a422352 My local commitremotes/origin/HEAD     -> origin/masterremotes/origin/master   a422352 My local commitremotes/upstream/master 5fdff0f Some upstream commit

合并

现在我们已经获取了上游存储库,我们想要将其更改合并到我们的本地分支中。这将使该分支与上游同步,而不会丢失我们的本地更改。

$ git checkout master# Check out our local master branchSwitched to branch 'master'
$ git merge upstream/master# Merge upstream's master into our ownUpdating a422352..5fdff0fFast-forwardREADME                    |    9 -------README.md                 |    7 ++++++2 files changed, 7 insertions(+), 9 deletions(-)delete mode 100644 READMEcreate mode 100644 README.md

如果您的本地分支没有任何唯一的提交,git将执行“快进”:

$ git merge upstream/masterUpdating 34e91da..16c56adFast-forwardREADME.md                 |    5 +++--1 file changed, 3 insertions(+), 2 deletions(-)

提示:如果您想在GitHub上更新您的存储库,请按照此处的说明进行操作

从2014年5月开始,可以直接从GitHub更新分叉。截至2017年9月,这仍然有效,但是它将导致脏提交历史记录。

  1. 在GitHub上打开你的分叉。
  2. 点击拉取请求
  3. 单击新建拉取请求。默认情况下,GitHub会将原始版本与您的分叉进行比较,如果您没有进行任何更改,就不应该有任何可以比较的内容。
  4. 如果您看到该链接,请单击切换基地。否则,请手动将底叉下拉设置为您的分叉,将头叉设置为上游。现在GitHub会将您的分叉与原始分叉进行比较,您应该会看到所有最新的更改。输入图片描述
  5. 创建拉取请求并为您的拉取请求分配一个可预测的名称(例如Update from original)。
  6. 向下滚动到合并拉取请求,但不要单击任何内容。

现在您有三个选项,但每个选项都将导致不太干净的提交历史记录。

  1. 默认值将创建一个丑陋的合并提交。
  2. 如果您单击下拉列表并选择“压扁并合并”,则所有中间的提交都将被压扁为一个。这通常是您不想要的。
  3. 如果您单击重新定位和合并,所有提交都将“与”您一起完成,原始PR将链接到您的PR,GitHub将显示This branch is X commits ahead, Y commits behind <original fork>

所以,是的,你可以使用GitHub Web UI保持你的存储库与上游一起更新,但这样做会玷污你的提交历史记录。坚持的命令行-这很容易。

许多答案最终会移动父存储库的分叉一个承诺。这个答案总结了找到这里的步骤,这将将分叉移动到与父级相同的提交

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

    • 切换到主分支,如果你不是git checkout master
  2. 将父级添加为远程存储库,git remote add upstream <repo-location>

  3. 问题git fetch upstream
  4. 问题git rebase upstream/master

    • 在这个阶段,您检查是否提交了将通过键入git status合并的内容
  5. 问题git push origin master

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

按照下面的步骤做。我试过了,它对我很有帮助。

结帐到您的分行

语法: git分支你的开发分支
示例:git check out master

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

语法: git ullhttps://github.com/tastejs/awesome-app-ideas master
示例:git ullhttps://github.com/ORIGINAL_OWNER/ORIGINAL_REPO.gitBRANCH_NAME

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

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

注意:由于功能请求是非官方的,因此建议联系support@github.com添加您对要实现的此类功能的支持。上面的非官方功能请求可以用作对此正在实现的兴趣的证据。

前言:您的分叉是“起源”,您分叉的存储库是“上游”。

让我们假设您已经使用以下命令将分叉克隆到您的计算机:

git clone git@github.com:your_name/project_name.gitcd project_name

如果给出了,那么你需要按照这个顺序继续:

  1. 将“上游”添加到您的克隆存储库(“源”):

    git remote add upstream git@github.com:original_author/project_name.git
  2. Fetch the commits (and branches) from the "upstream":

    git fetch upstream
  3. Switch to the "master" branch of your fork ("origin"):

    git checkout master
  4. Stash the changes of your "master" branch:

    git stash
  5. Merge the changes from the "master" branch of the "upstream" into your the "master" branch of your "origin":

    git merge upstream/master
  6. Resolve merge conflicts if any and commit your merge

    git commit -am "Merged from upstream"
  7. Push the changes to your fork

    git push
  8. Get back your stashed changes (if any)

    git stash pop
  9. You're done! Congratulations!

GitHub also provides instructions for this topic: Syncing a fork

如果您使用的是适用于Windows或Mac的GitHub,那么现在他们有一个一键式功能来更新分叉:

  1. 在UI中选择存储库。
  2. 单击顶部的“从用户/分支更新”按钮。

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

与此同时,GitHub用户bardiharborow创建了一个工具来做到这一点:https://upriver.github.io/

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

如果,像我一样,你永远不要把任何东西直接交给师父,你真的应该,你可以做以下事情。

从分叉的本地克隆中,创建上游遥控器。你只需要执行一次:

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

然后,每当您想赶上上游存储库主分支时,您需要:

git checkout mastergit pull upstream master

假设您自己从未在master上提交任何内容,您应该已经完成了。现在您可以将本地master推送到您的原始远程GitHub分叉。您还可以将您的开发分支重新建立在现在最新的本地master上。

通过初始上游设置和master签出,您需要做的就是运行以下命令以将您的master与上游同步:git拉流上游主机

实际上,可以从浏览器中上游的任何提交创建一个分支:

在此处输入图片描述

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

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

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

如果它是一个相当大的存储库,你可能想以一种特殊的方式管理它(例如删除历史记录)。基本上,你可以获得当前版本和上游版本之间的差异,提交它们,然后选择回主版本。

尝试阅读这一个。它描述了如何处理大型Git存储库以及如何使用最新更改上游它们。

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

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

然后运行:

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

此命令的第一部分列出上游远程存储库中的所有头,并删除SHA-1后跟refs/heads/分支名称前缀。

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

这些分支同步命令中的任何一个都可能由于以下原因之一而失败:上游分支已被重写,或者您已将该分支上的提交推送到您的分叉。在第一种情况下,您没有向分叉上的分支提交任何内容,强制推送是安全的(添加-f开关;即上面命令中的git push -f)。在另一种情况下,这是正常的,因为您的分叉分支已经发散,并且您不能期望同步命令在您的提交被合并回上游之前工作。

我用这一行更新我的分叉存储库:

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

如果您不想向您的项目添加另一个远程终结点,请使用此选项,如此处发布的其他解决方案。

Android Studio现在已经学会了使用GitHub分叉存储库(您甚至不必通过控制台命令添加“上游”远程存储库)。

打开菜单VCSgit

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

  • 重新构建我的GitHub分支

  • 创建拉取请求

尝试它们。我使用第一个来同步我的本地存储库。无论如何,单击“Rebase my GitHub fork”后,来自父远程存储库(“上游”)的分支将在Android Studio中访问,您将能够轻松使用它们。

(我使用带有“Git集成”和“GitHub”插件的Android Studio 3.0。)

在此输入图片描述

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

$ 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

您可以开始了。主存储库中的所有更新更改都将被推送到您的分叉存储库中。

“获取”命令对于保持项目的最新状态是必不可少的:只有在执行“获取”时,您才会被告知同事推送到远程服务器的更改。

您仍然可以访问这里进行进一步查询

保持分叉存储库始终更新有两个主要方面。

1.创建分支从分叉主和在那里做改变

因此,当您的拉取请求被接受时,您可以安全地删除该分支,因为当您使用上游更新它时,您贡献的代码将存在于分叉存储库的主库中。通过这种方式,您的主库将始终处于干净状态,可以创建一个新分支来进行另一次更改。

2.创建计划作业为分叉主机到做自动更新

这可以用cron完成。这是一个示例代码,如果你在linux中这样做。

$ crontab -e

将此代码放在crontab file上以按小时执行作业。

0 * * * * sh ~/cron.sh

然后创建cron.sh脚本文件和git交互,其中ssh代理和/或期望如下所示

#!/bin/shWORKDIR=/path/to/your/dirREPOSITORY=<name of your repo>MASTER="git@github.com:<username>/$REPOSITORY.git"UPSTREAM=git@github.com:<upstream>/<name of the repo>.git
cd $WORKDIR && rm -rf $REPOSITORYeval `ssh-agent` && expect ~/.ssh/agent && ssh-add -lgit clone $MASTER && cd $REPOSITORY && git checkout mastergit remote add upstream $UPSTREAM && git fetch --prune upstreamif [ `git rev-list HEAD...upstream/master --count` -eq 0 ]thenecho "all the same, do nothing"elseecho "update exist, do rebase!"git reset --hard upstream/mastergit push origin master --forceficd $WORKDIR && rm -rf $REPOSITORYeval `ssh-agent -k`

检查您的分叉存储库。它会不时显示此通知:

这个分支与#0: master相等.

在此处输入图片描述

如果你设置你的上游。用git remote -v检查,这就足够了。

git fetch upstreamgit checkout mastergit merge --no-edit upstream/mastergit push

拉取app是一个自动设置和忘记的解决方案。它将与上游存储库同步分叉的默认分支。

访问URL,单击绿色的“安装”按钮,然后选择要启用自动同步的存储库。

该分支直接在GitHub上每小时更新一次,在您的本地机器上,您需要拉取主分支以确保您的本地副本同步。

我想添加到@krlmlr的回答

最初,分叉存储库有一个名为master的分支。如果您正在开发新功能或修复程序,您通常会创建一个新分支feature并进行更改。

如果您希望分叉存储库与父存储库同步,您可以为拉取应用在功能分支)设置一个配置文件(pull.yml),如下所示:

version: "1"rules:- base: featureupstream: mastermergeMethod: merge- base: masterupstream: parent_repo:mastermergeMethod: hardreset

这使分叉存储库的master分支与父存储库保持最新。它通过合并分叉存储库的master分支来更新分叉存储库的feature分支。这假设feature分支是包含配置文件的默认分支。

这里有两个mergemethods在起作用,一个是hardreset,它有助于强制同步分叉存储库master分支中与父存储库的更改,另一个方法是merge。此方法用于合并您在feature分支中完成的更改和由于在master分支中强制同步而完成的更改。在合并冲突的情况下,拉取应用程序将允许您在拉取请求期间选择下一个操作过程。

您可以阅读基本和高级配置以及各种mergemethods这里

我目前正在我的分叉存储库这里中使用此配置,以确保请求这里的增强保持更新。

使用这些命令(在幸运的情况下)

git remote -vgit pullgit fetch upstreamgit checkout mastergit merge upstream/master --no-ffgit add .git commit -m"Sync with upstream repository."git push -v
rm -rf oldrepositorygit clone ...

可能有更微妙的选择,但这是我确信我的本地存储库与上游相同的唯一方法。

如果您使用GitHub Desktop,只需6个步骤(实际上只有5个步骤)即可轻松完成。

一旦您打开Github Desktop并选择您的存储库,

  1. 转到历史标签
  2. 单击搜索栏。它会显示所有可用的分支(包括来自父存储库的上游分支)
  3. 选择相应的上游分支(它将是上游/主同步主分支)
  4. (可选)它会显示上游分支中的所有提交。您可以单击任何提交以查看更改。
  5. 根据您的活动分支单击合并master/branch-name
  6. 等待GitHub Desktop来施展魔法。

查看下面的GIF作为示例:

同步上游分支从父存储库分叉的存储库

从github页面删除您的远程开发

然后应用这些命令:

1) git branch -D dev2) git fetch upstream3) git checkout master4) git fetch upstream && git fetch upstream --prune && git rebase upstream/master && git push -f origin master5) git checkout -b dev6) git push origin dev7) git fetch upstream && git fetch upstream --prune && git rebase upstream/dev && 8) git push -f origin dev

要查看您的配置,请使用此命令:

git remote -v

有三种方法可以做到这一点:从Web UI(选项1)、从GitHub CLI(选项2)或从命令行(选项3)。


选项1-Web UI

  1. 在GitHub上,导航到要与上游存储库同步的分叉存储库的主页。

  2. 选择获取上游下拉列表。

在此处输入图片描述

  1. 查看有关从上游存储库提交的详细信息,然后单击获取并合并。

在此处输入图片描述


选项2-GitHub CLI

要从其父级更新远程分叉,请使用gh repo sync子命令并提供您的分叉名称作为参数。

$ gh repo sync owner/cli-fork

如果上游存储库的更改导致冲突,则GitHub CLI无法同步。您可以设置-force标志来覆盖目标分支。


选项3-命令行

在将一个分支与上游存储库同步之前,必须在Git中配置指向上游存储库的远程

1打开Git Bash。

2将当前工作目录更改为本地项目。

3从上游存储库中获取分支及其各自的提交。对BRANCHNAME的提交将存储在本地分支上游/BRANCHNAME中。

$ git fetch upstream> 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/ORIGINAL_OWNER/ORIGINAL_REPOSITORY>  * [new branch]      main     -> upstream/main

4检查你的分叉的本地默认分支——在这种情况下,我们使用main。

$ git checkout main> Switched to branch 'main'

5将来自上游默认分支(在本例中为上游/main)的更改合并到本地默认分支中。这将使您的分叉的默认分支与上游存储库同步,而不会丢失本地更改。

$ git merge upstream/main> 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

如果一个本地分支没有任何唯一的提交,Git将执行“快进”:

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

注意:同步一个分支只会更新一个存储库的本地副本。要更新GitHub.com的分叉,必须推动变革


来源:GitHub Docs-同步分叉

如果你想让你的GitHub分支与相应的上游保持最新,GitHub也有这个probot程序:https://probot.github.io/apps/pull/来完成这项工作。您需要允许在您的帐户中安装,它将使您的分叉保持最新。

如何在本地机器上更新分叉存储库?

首先,检查您的遥控器/主机

git remote -v

你应该有原点和上游。例如:

origin  https://github.com/your___name/kredis.git (fetch)origin  https://github.com/your___name/kredis.git (push)upstream    https://github.com/rails/kredis.git (fetch)upstream    https://github.com/rails/kredis.git (push)

然后去主:

git checkout main

并从上游合并到主:

git merge upstream/main

假设你的分叉是https://github.com/me/foobar,原始存储库是https://github.com/someone/foobar

  1. 访问https://github.com/me/foobar/compare/master...someone:大师

  2. 如果您看到绿色文本Able to merge,请按创建拉取请求

  3. 在下一页上,滚动到页面底部并单击合并拉取请求确认合并

使用此代码片段生成链接以同步您的分叉存储库:

new Vue ({el: "#app",data: {yourFork: 'https://github.com/me/foobar',originalRepo: 'https://github.com/someone/foobar'},computed: {syncLink: function () {const yourFork = new URL(this.yourFork).pathname.split('/')const originalRepo = new URL(this.originalRepo).pathname.split('/')if (yourFork[1] && yourFork[2] && originalRepo[1]) {return `https://github.com/${yourFork[1]}/${yourFork[2]}/compare/master...${originalRepo[1]}:master`}return 'Not enough data'}}})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script><div id="app">Your fork URL: <input size=50 v-model="yourFork" /> <br />Original repository URL: <input v-model="originalRepo" size=50 /> <br />Link to sync your fork: <a :href="syncLink">\{\{syncLink}}</a></div>

$ git remote add upstream https://github.com/....
$ git pull upstream main
$ git push

GitHub现在引入了一项通过单击按钮来同步分叉的功能

转到您的分叉,单击#0,然后单击#1直接将您的分叉与其父存储库同步。

在此处输入图片描述

您也可以单击#0按钮来比较合并前的更改。

参考: GitHub的留档

试试这个,单击“Fetch上游”以从上游主同步您的分叉存储库。输入图片描述