如何更新GitHub分叉存储库?
我最近分叉了一个项目并应用了几个修复程序.然后我创建了一个拉取请求,然后被接受.
几天后,另一位撰稿人做出了另一项改变.所以我的fork不包含那个改变.
我怎样才能把这个改变变成我的叉子?当我进行进一步的更改时,是否需要删除并重新创建我的分支?还是有更新按钮?
回答
在forked存储库的本地克隆中,可以将原始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,
# 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上你自己的分叉存储库.你这样做:
git push -f origin master
您只需要-f
在重新定位后第一次使用.
- 因为你的fork只存在于github上,并且github没有通过web界面进行合并的工具,所以正确的答案是在本地进行上游合并并将更改推送回fork.
- 快速说明,您可能应该在单独的分支上工作,而不是必须重新设置自己的主分支以确保从干净状态开始.这可以让你的主人保持清洁,以便将来合并,它可以阻止你用`-f`重写历史记录,这会弄乱每个可能克隆你版本的人.
- 另一个Git失败了.如果这个工具应该支持分布式协作,那么为什么执行基本工作流程如此困难?400万人和2200人表示该工具失败.*"你可以将原来的GitHub存储库添加为"远程"* - 为什么甚至必须这样做?为什么在fork期间没有完成?这个工具有什么破坏?
- 这是我在使用github时找到的一个很棒的教程:http://gun.io/blog/how-to-github-fork-branch-and-pull-request/
- 而不是rebase命令,我使用了以下内容:`git merge --no-ff upstream/master`这样你的提交就不再是最重要了.
- @Sinjai _is_ 明确支持这些网络服务。它被称为远程系统。您指定 URL,然后推/拉。从字面上看,如果没有对某些特定服务的硬编码支持,我认为它不可能变得更简单。如果 Git 要在您不提供这些信息的情况下对不同存储库之间的关系有某种隐式理解,则需要一个集中式数据库。没有合理的方法可以将此功能集成到分布式修订控制系统中。
- 如果你有本地提交,这不会创建丑陋的"github.com:user/repo的合并分支'主人'"`每次尝试从上游获取更新时提交?你可以肯定,但是如果你把你的更改推送到github上的forked repo,就意味着下次你不能在没有为每次提交重新生成哈希值之后重新设置它.我真的不知道如何在github上正确"维护"一个fork.
- @jww:你问为什么Git需要被告知原始的GitHub存储库.这是因为Git是一个分散的版本控制系统,并没有以任何方式与GitHub绑定; 很明显,Git是在GitHub之前创建的.当您在GitHub上创建分叉存储库并克隆它时,GitHub知道存储库是一个分支; Git没有理由,也没有理由.(为什么克隆没有复制Git遥控器?Git是分散的;不同的人会想要不同的遥控器;这样做是没有意义的.)请参阅https://github.com/github/hub以了解Git中的GitHub集成.
- 在上游接受您的更改后,您需要重复这些步骤:`git fetch upstream`; `git rebase upstream/master`; `git push origin master`
- 我+ 1'这个答案,因为它可能完成了作者实际需要的问题.但是我处于相同的情况并且很好奇:有没有办法从主回购中"拉"到我的叉子?或者只有在从上游获取后向上推回上游分支时才会更新上游分支?
- @Steckdoserich 完全同意。非常可悲的是,这里的人们认为在 rebase 之后强制推送一个公开可见的分支是正确的或可以接受的。它使您的叉子对任何跟随的人几乎毫无用处......
从2014年5月开始,可以直接从GitHub更新分支.这仍然适用于2017年9月,但它将导致脏的提交历史.
- 在GitHub上打开你的分叉.
- 点击Pull Requests.
- 点击New Pull Request.默认情况下,GitHub会将原始文件与您的fork进行比较,如果您没有进行任何更改,则不应该进行任何比较.
- switching the base如果您看到该链接,请单击.否则,手动将base fork下拉菜单设置为分叉,然后设置head fork为上游.现在GitHub会将你的分叉与原版进行比较,你应该看到所有最新的变化.
-
Create pull request并为您的拉取请求分配一个可预测的名称(例如
Update from original
). - 向下滚动Merge pull request,但不要点击任何内容.
现在您有三个选项,但每个选项都会导致一个不太干净的提交历史记录.
- 默认情况下会创建一个丑陋的合并提交.
- 如果单击下拉列表并选择"Squash and merge",则所有干预提交将被压缩为一个.这通常是你不想要的.
- 如果你点击Rebase and merge,所有提交将与你","原始PR将链接到您的PR,GitHub将显示
This branch is X commits ahead, Y commits behind <original fork>
.
所以,是的,您可以使用GitHub Web UI保持您的repo更新其上游,但这样做会玷污您的提交历史记录.坚持使用命令行 - 这很容易.
- 仍然有效(Marchi 2015),尽管"切换基础"链接已不再存在.你必须改变"Base"下拉菜单,这样两者都指向你的分叉,然后你会得到一个"比较跨回购"的提示,这将带你到你想要的地方.
- 这次工作很棒.第二次此过程的工作方式不同:"切换基础"链接未显示.当我点击"Click to create pull request"时,它在SOURCE repo上创建了一个PR.不是我想要的..
- 只需更新或同步按钮就不会更好!
- 2015年4月.作品.谢谢.我确实得到了"切换到基地".但是,第6步是"创建拉取请求" - >输入注释 - >"创建拉取请求".最终提前1次提交原件.
- @cartland(或其他人) - 是的,它说"这个分支是提前1次提交......"这有什么值得担心的吗?有可能摆脱那条消息吗?
- 一旦完成拉取请求,合并本身似乎是提前1次提交,这是正常的.我注意到切换分支不再适用于我.
- 每次执行此操作时,它会在fork之前添加一个提交
- 这可行,但UI非常笨重.它有时会将相反的操作建议为默认值,即向原始源发送拉取请求.
- 它可以工作,但他们应该使用"rebase fork"和"push"按钮.这样对我来说似乎很奇怪.不是很直观..
- 这些步骤需要更新; 基本上,你需要比较你的fork作为基础,原始作为头叉.但是,提交历史记录不会是干净的.您可以合并或压缩+合并,这将留下合并提交,或"Rebase and merge",这将给出"此分支是X提交提交,Y提交<原始>",每个提交将"和你.
这是GitHub关于同步fork的官方文档:
同步一个分叉
安装程序
在同步之前,您需要添加指向上游存储库的远程数据库.您最初分叉时可能已经这样做了.
提示:同步fork只会更新存储库的本地副本; 它不会在GitHub上更新您的存储库.
$ 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)
同步
将存储库与上游同步需要两个步骤:首先必须从远程获取,然后必须将所需的分支合并到本地分支中.
取
从远程存储库中获取将引入其分支及其各自的提交.它们存储在特殊分支下的本地存储库中.
$ 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
我们现在将上游的主分支存储在本地分支,上游/主服务器中
$ 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
合并
现在我们已经获取了上游存储库,我们希望将其更改合并到我们的本地分支中.这将使该分支与上游同步,而不会丢失我们的本地更改.
$ 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
如果您的本地分支没有任何唯一提交,git将执行"快进":
$ git merge upstream/master Updating 34e91da..16c56ad Fast-forward README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
提示:如果要在GitHub上更新存储库,请按照此处的说明进行操作
- @MichaelMcGinnis在本地合并之后,你必须将你的更改推送到github.`git push origin master`
- 这更新了我的本地分支,但我在 Github.com 上的分支仍然显示“43 次提交”。我不得不使用 lobzik 的技术为自己创建一个拉取请求,以便将主更改合并到我的 Github.com 分支中。
很多答案最终会在父存储库之前移动fork 一次提交.这个答案总结了这里的步骤,它们将你的fork移动到与父级相同的提交.
-
- 如果不是,请切换到主分支
git checkout master
- 如果不是,请切换到主分支
- 问题
git fetch upstream
-
- 在此阶段,您将检查是否通过键入提交将要合并的内容
git status
- 在此阶段,您将检查是否通过键入提交将要合并的内容
有关这些命令的更多信息,请参阅步骤3.
- @MT:你在哪里输入这些命令?根据我的理解,问题的要点是如何将您的个人*GitHub*fork与主项目重新同步,并且**从GitHub**完成所有这些操作.换句话说,如何在没有*本地存储库的情况下更新远程fork*?
- @JohnY使用GitHub将始终创建额外的提交.您需要在本地存储库的shell中执行所有这些操作以避免额外提交.
自2013年11月以来,有一个非官方的功能请求打开GitHub要求他们添加一个非常简单直观的方法来保持本地fork与上游同步:
https://github.com/isaacs/github/issues/121
注意:由于功能请求是非官方的,因此建议您联系support@github.com
以添加对此类功能的支持以实现.上面的非官方特征请求可以用作对此实施的兴趣量的证据.
前言:您的fork是"origin",您分叉的存储库是"上游".
假设你已经使用如下命令将你的fork克隆到你的计算机:
git clone git@github.com:your_name/project_name.git
cd project_name
如果给出了那么你需要继续这个顺序:
-
git remote add upstream git@github.com:original_author/project_name.git
-
git fetch upstream
-
git checkout master
-
git stash
-
git merge upstream/master
-
git commit -am "Merged from upstream"
-
git push
-
git stash pop
GitHub还提供了有关此主题的说明:同步fork
- [Wolf](/sf/users/205243671/),猜测您现在已经知道了,但是为了后代...这是ssh的格式。https://help.github.com/articles/configuring-a-remote-for-a-fork/
- 非常感谢你。git stash和git stash pop很有帮助
如果像我一样,你永远不会直接掌握任何东西,你应该真的,你可以做到以下几点.
从fork的本地克隆中,创建上游远程.你只需要这样做一次:
git remote add upstream https://github.com/whoever/whatever.git
然后,只要您想要了解上游存储库主分支,您需要:
git checkout master
git pull upstream master
假设你自己从未对主人做过任何事情,你应该已经完成了.现在,您可以将本地主服务器推送到原始远程GitHub fork.您还可以在现在最新的本地主服务器上重新设置开发分支.
因此,在初始上游设置和主校验之后,您需要做的就是运行以下命令将主服务器与上游同步:git pull upstream master.
截至本答复发布之日,GitHub 在Web界面中没有(或者我不再说?)这个功能.但是,您可以要求support@github.com
为此添加投票.
与此同时,GitHub用户bardiharborow创建了一个工具来做到这一点:
https ://upriver.github.io/
来源在这里:https://github.com/upriver/upriver.github.io
- 虽然我确实找到了该工具的一个好主意,但事实是这样的。它确实从我的帐户中仅加载了20个存储库,甚至页脚也重定向到了一个不存在的网站。如果这是固定的,我将是一个坚定的拥护者。
- 从今天开始,我已经成功地使用了upriver来将fork与上游repo进行同步,因此它已经可以满足我的目的,并且我将继续使用它。
如果您正在使用GitHub for Windows,那么他们现在只需一键功能即可更新分支:
- 在UI中选择存储库.
- 单击顶部的"从用户/分支更新"按钮.
- 这也适用于Mac的Github。
- Step by step: https://github.com/desktop/desktop/issues/1785#issuecomment-483011281
有一种方法可以从 GitHub 的 webapp 中做到这一点。
让我们来看看下面的例子。
首先,打开要更新的存储库。
可以看到警告
右侧有两个按钮Pull request
和Compare
。按Compare
。
由于可能没有什么可比较的,请按 switching the base
将出现所有更改的列表,您可以通过按下按钮创建拉取请求 Create pull request
给它一个标题,让我们说“更新回购”
并创建拉取请求。
创建请求后,滚动到底部并按Merge pull request
。
确认合并,就是这样!
- Thanks a lot ! Its as simple as that !
实际上,可以通过浏览器中上游的任何提交在fork中创建一个分支:
- 打开
https://github.com/<repo>/commits/<hash>
,其中repo是你的fork,hash是完整的commit提交,你可以在上游web界面找到它.例如,我可以打开https://github.com/max630/linux/commits/0aa0313f9d576affd7747cc3f179feb097d28990,它指的linux
master
是写作时间. - 单击"树:...."按钮.
- 输入新分支的名称,然后按 Enter
然后,您可以将该分支提取到本地克隆,并且当您在该提交之上进行编辑时,您不必将所有数据推送回GitHub.或使用Web界面更改该分支中的某些内容.
它是如何工作的(这是猜测,我不知道GitHub是如何做到的):forks共享对象存储并使用命名空间来分隔用户的引用.因此,您可以通过fork访问所有提交,即使它们在分叉时不存在.
- 这很棒!这避免了将这些提交完全毫无意义地上传到github。
GitHub 现在推出了一项功能,可以通过单击按钮来同步分叉。
转到您的分叉,单击Fetch upstream
,然后单击Fetch and merge
以直接将您的分叉与其父存储库同步。
您也可以单击Compare
按钮在合并之前比较更改。
参考:GitHub 的推文
请按照以下步骤操作.我尝试了它们,它帮助了我.
结账到您的分行
拉源存储库分支以获取最新代码
作为此答案的补充,我正在寻找一种方法,可以一口气从上游分支更新克隆的回购(源)的所有远程分支。这就是我做的。
假设您已经配置了指向源存储库(源是从其派生的)的上游远程服务器,并且已与同步。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
在上面的命令中)。在另一种情况下,这是正常的,因为您的fork分支已经分叉了,您不能期望sync命令起作用,直到您的提交被合并回上游。
我用这一行更新我的分叉存储库:
git pull https://github.com/forkuser/forkedrepo.git branch
如果您不想在项目中添加另一个远程端点,请使用此选项,如此处发布的其他解决方案一样。
- 这有限制吗?即,它仅适用于自上次更新以来您尚未添加提交,合并,拉取请求或将拉取请求合并到上游的情况吗?
如果你设置你的上游。检查git remote -v
,然后就足够了。
git fetch upstream
git checkout master
git merge --no-edit upstream/master
git push
克隆分叉存储库后,转到克隆所在的目录路径以及 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
你就可以开始了。主存储库中的所有更新更改都将推送到您的 fork 存储库中。
“fetch”命令对于在项目中保持最新状态是必不可少的:只有在执行“git fetch”时,您才会被告知您的同事推送到远程服务器的更改。
您仍然可以访问这里进行进一步的查询
的“拉”的应用程序是自动设置和忘记的解决方案。它将把fork的默认分支与上游存储库同步。
访问URL,单击绿色的“安装”按钮,然后选择要启用自动同步的存储库。
该分支每小时直接在GitHub上更新一次,在您的本地计算机上,您需要拉主分支以确保本地副本是同步的。
- 请注意,使用基本设置,您可能会丢失分叉存储库中所做的更改。要保留更改,请设置配置文件并指定```mergemethod```。在此[此处]的更多信息(/sf/answers/4127654331/)