我分叉了一个项目,进行了更改,并创建了一个被接受的拉取请求。新的提交后来被添加到存储库中。我怎样才能把这些承诺交给我?


在分叉存储库的本地克隆中,可以将原始GitHub存储库添加为“远程”。(“Remotes”就像是存储库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

如果您不想重写主分支的历史记录(例如,因为其他人可能已经克隆了它),那么应该用gitmergeupstream/master替换最后一个命令。然而,为了做出尽可能干净的进一步拉取请求,可能最好重新设置基址。


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

git push -f origin master

您只需要在重新启动后第一次使用-f即可。

以下是GitHub关于同步分叉的官方文档:

同步分叉设置在同步之前,需要添加指向上游存储库的远程。您可能在最初分叉时就这样做了。提示:同步fork只更新存储库的本地副本;它不会更新GitHub上的存储库。$git远程-v#列出当前遥控器起源https://github.com/user/repo.git(提取)起源https://github.com/user/repo.git(推)$git远程添加上游https://github.com/otheruser/repo.git#设置新遥控器$git远程-v#验证新远程起源https://github.com/user/repo.git(提取)起源https://github.com/user/repo.git(推)上游https://github.com/otheruser/repo.git(提取)上游https://github.com/otheruser/repo.git(推)正在同步将存储库与上游同步需要两个步骤:首先必须从远程获取,然后必须将所需的分支合并到本地分支。正在获取从远程存储库获取将带来其分支及其各自的提交。这些存储在本地存储库中的特殊分支下。$git获取上游#抓住上游遥控器的分支远程:计数对象:75,完成。远程:压缩对象:100%(53/53),完成。远程:总共62个(增量27),重复使用44个(增量9)拆包对象:100%(62/62),完成。从…起https://github.com/otheruser/repo*[新分支]主->上游/主现在,上游的主分支存储在本地分支上游/主分支中$git分支-va#列出所有本地和远程跟踪分支*master a422352我的本地提交remotes/origin/HEAD->origin/masterremotes/origin/master a422352我的本地提交remotes/upstream/master 5fdff0f一些上游提交合并现在我们已经获取了上游存储库,我们希望将其更改合并到本地分支中。这将使该分支与上游同步,而不会丢失本地更改。$git结帐主机#查看我们当地的主分支机构切换到分支“主”$git合并上游/主#将上游的主机合并到我们自己的主机中正在更新a422352..5fdff0f快进自述文件|9-------阅读.md | 7++++++2个文件已更改,7个插入(+),9个删除(-)删除模式100644 README创建模式100644 README.md如果您的本地分支没有任何唯一的提交,git将执行“快进”:$git合并上游/主正在更新34e91da。。16c56天快进阅读.md | 5+++--1个文件已更改,3个插入(+),2个删除(-)提示:如果您想更新GitHub上的存储库,请按照此处的说明进行操作

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

在GitHub上打开你的分叉。单击拉取请求。单击New Pull Request。默认情况下,GitHub会将原始文件与您的fork进行比较,如果您没有进行任何更改,则不应该有任何可比较的内容。如果看到该链接,请单击切换基础。否则,手动将底叉向下设置到叉上,将头叉设置到上游。现在GitHub将您的分叉与原始分叉进行比较,您应该可以看到所有最新的更改。创建拉取请求并为拉取请求分配一个可预测的名称(例如,从原始请求更新)。向下滚动到Merge pull请求,但不要单击任何内容。

现在您有三个选项,但每个选项都会导致提交历史记录不那么清晰。

默认值将创建难看的合并提交。如果您单击下拉菜单并选择“压缩并合并”,所有中间提交都将被压缩为一个。这通常是你不想要的。如果您单击Rebase并合并,所有提交都将“与”您一起进行,原始PR将链接到您的PR,GitHub将显示This branch is X commits before,Y commits behind<original fork>。

因此,是的,您可以使用GitHub web UI保持回购的上游更新,但这样做会玷污您的提交历史。而是坚持使用命令行-这很简单。

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

将目录更改为本地存储库。如果您不是git结账主管,请切换到master分支将父级添加为远程存储库,git remote Add upstream<repo location>向上游发出git fetch发布git上游/主数据库在这个阶段,您可以通过键入gitstatus来检查提交将要合并的内容发布git推送源主机

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

遵循以下步骤。我试过了,它帮了我。

签出到您的分支机构

语法:gitbranchyourDevelopmentBranch示例:git checkout master

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

语法:git pullhttps://github.com/tastejs/awesome-app-ideas主人示例:git pullhttps://github.com/ORIGINAL_OWNER/ORIGINAL_REPO.git分支名称

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

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

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

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

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

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

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

将“上游”添加到克隆的存储库(“源”):git远程添加上游git@github.com:original_author/project_name.git从“上游”获取提交(和分支):git获取上游切换到分叉的“master”分支(“origin”):切换到主分支停止“主”分支的更改:暂存将“上游”的“主”分支中的更改合并到“源”的“母”分支中:git合并上游/主解决合并冲突(如果有)并提交合并gitcommit-am“从上游合并”将更改推到叉上数字推送找回你藏起来的零钱(如果有的话)吉特藏弹你完了!祝贺

GitHub还提供了有关此主题的说明:同步分叉

如果您使用的是Windows或Mac的GitHub,那么现在他们有一个一键更新fork的功能:

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

截至本答复之日,GitHub在web界面中还没有(或者我应该说不再有?)这一功能。然而,你可以问support@github.com加上你的一票。

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

来源在这里:https://github.com/upriver/upriver.github.io

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

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

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

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

git checkout master
git pull upstream master

假设你从未对师父做过任何事,你应该已经做了。现在,您可以将本地主机推送到源远程GitHub分叉。您还可以将开发分支重新基于当前最新的本地主机。

在初始的上游设置和主签出之后,您需要做的就是运行以下命令以将主设备与上游设备同步:git pull上游主设备。

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

打开https://github.com/<repo>/commits/<hash>,其中repo是您的分叉,hash是提交的完整哈希,您可以在上游web界面中找到。例如,我可以打开https://github.com/max630/linux/commits/0aa0313f9d576affd7747cc3f179feb097d28990,这将linux master作为编写时间。单击“树:……”按钮。键入新分支的名称,然后按Enter键

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

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

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

如果它是一个很大的存储库,您可能希望以一种特殊的方式管理它(例如删除历史记录)。基本上,您可以获取当前版本和上游版本之间的差异,提交它们,然后将它们重新提交给master。

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

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

这假设您已经配置了一个指向源存储库(源是从那里分叉的)的上游远程,并将其与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

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

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

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

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

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

如果您不想在项目中添加另一个远程端点,请使用此选项,如其他解决方案所示。

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

打开菜单VCS→ Git公司

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

重新使用我的GitHub分叉创建拉取请求

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

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

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

$ 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”命令对于保持项目中的最新状态是必不可少的:只有在执行“gitfetch”时,您才会被告知同事对远程服务器所做的更改。

您仍然可以访问此处进行进一步查询

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

1.从fork master创建分支并在那里进行更改。

因此,当您的PullRequest被接受时,您可以安全地删除分支,因为当您使用上游更新它时,您贡献的代码将保存在分叉存储库的主库中。这样,您的主机将始终处于干净状态,以便创建新的分支以进行另一个更改。

2.为fork master创建一个计划作业,以便自动进行更新。

这可以用cron完成。下面是一个示例代码,如果您在linux中执行此操作。

$ crontab -e

将此代码放在crontab文件中,以每小时执行一次作业。

0 * * * * sh ~/cron.sh

然后创建cron.sh脚本文件,并与ssh代理和/或预期的git交互,如下所示

#!/bin/sh
WORKDIR=/path/to/your/dir   
REPOSITORY=<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 $REPOSITORY
eval `ssh-agent` && expect ~/.ssh/agent && ssh-add -l
git clone $MASTER && cd $REPOSITORY && git checkout master
git remote add upstream $UPSTREAM && git fetch --prune upstream
if [ `git rev-list HEAD...upstream/master --count` -eq 0 ]
then
    echo "all the same, do nothing"
else
    echo "update exist, do rebase!"
    git reset --hard upstream/master
    git push origin master --force
fi
cd $WORKDIR && rm -rf $REPOSITORY
eval `ssh-agent -k`

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

此分支与<upstream>:master相等。

如果您设置了上游。用gitremote-v检查一下,这就足够了。

git fetch upstream
git checkout master
git merge --no-edit upstream/master
git push

“拉”应用程序是一个自动设置和忘记的解决方案。它将使fork的默认分支与上游存储库同步。

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

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

我想补充一下@krlmlr的答案。

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

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

version: "1"
rules:
  - base: feature
    upstream: master
    mergeMethod: merge
  - base: master
    upstream: parent_repo:master
    mergeMethod: hardreset

这将使分叉回购的主分支与父回购保持最新。它通过合并分叉回购的主分支来保持分叉回购的特征分支的更新。这假设功能分支是包含配置文件的默认分支。

这里有两种合并方法,一种是硬重置,这有助于将分叉回购的主分支中的更改与父回购同步,另一种方法是合并。此方法用于合并在要素分支中所做的更改和在主分支中由于强制同步而做的更改。如果发生合并冲突,拉取应用程序将允许您在拉取请求期间选择下一个操作过程。

您可以在这里阅读基本和高级配置以及各种合并方法。

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

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

git remote -v
git pull
git fetch upstream
git checkout master
git merge upstream/master --no-ff
git add .
git commit -m"Sync with upstream repository."
git push -v
rm -rf oldrepository
git clone ...

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

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

打开Github Desktop并选择存储库后,

转到“历史记录”选项卡单击搜索栏。它将显示所有可用的分支(包括父存储库的上游分支)选择相应的上游分支(它将是上游/主分支到同步主分支分支)(可选)它将显示上游分支中的所有提交。您可以单击任何提交都可以看到更改。根据您的活动分支,单击主/分支名称中的合并。等待GitHub Desktop发挥作用。

查看下面的GIF作为示例:

从github页面删除远程设备

然后应用这些命令:

1) git branch -D dev
2) git fetch upstream
3) git checkout master
4) git fetch upstream && git fetch upstream --prune && git rebase upstream/master && git push -f origin master
5) git checkout -b dev
6) git push origin dev
7) 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

在GitHub上,导航到要与上游存储库同步的分叉存储库的主页面。选择“获取上游”下拉列表。

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


选项2-GitHub CLI

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

$ gh repo sync owner/cli-fork

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

如何安装GitHub CLIGitHub CLI手册


选项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查看fork的本地默认分支-在本例中,我们使用main。

$ git checkout main
> Switched to branch 'main'

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

$ 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)

之后转到main:

git checkout main

并从上游合并到干管:

git merge upstream/main

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

参观https://github.com/me/foobar/compare/master...someone:master如果您看到绿色文本“能够合并”,请按Create pull request在下一页上,滚动到页面底部,然后单击合并请求和确认合并。

使用以下代码段生成链接以同步分叉存储库:

新Vue({el:“#app”,数据:{yourFork:'https://github.com/me/foobar',原始回购:'https://github.com/someone/foobar'},计算:{syncLink:函数(){const yourFork=新URL(this.yourFork).pathname.split('/')const originalRepo=新URL(this.originalRepo).pathname.split('/')如果(yourFork[1]&&yourFork[2]&&originalRepo[1]){返回`https://github.com/${yourFork[1]}/${yourFork[2]}/compare/master${originalRepo[1]}:主`}return“数据不足”}}})<script src=“https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js“></script><div id=“app”>您的分叉URL:<inputsize=50v-model=“yourFork”/><br/>原始存储库URL:<input v-model=“originalRepo”size=50/><br/>用于同步分叉的链接:<a:href=“syncLink”>{syncLink}</a></div>

$ git remote add upstream https://github.com/....

$ git pull upstream main

$ git push

GitHub现在引入了一个功能,可以通过单击按钮同步分叉。

转到您的分叉,单击“上游获取”,然后单击“获取并合并”以直接将分叉与其父回购同步。

您也可以单击“比较”按钮在合并之前比较更改。

参考:GitHub的文档

尝试此操作,单击“获取上游”以从上游主机同步分叉的回购。