我在一些软件项目中,我们将代码存储在GitHub上。有一个主人和开发分支的回购。我在我的笔记本电脑上没有连接互联网,我想开始研究另一个功能,所以我做了以下几点:
git init
git remote add origin git://repo_adress
git checkout -b webapp <- created a new branch
我添加了一些文件,文件夹等
然后我做了:
git add .
git commit -m "something"
git push origin webapp
我查了GitHub,现在有3个分支。我想将webapp合并到开发中(没有冲突,我在一个单独的文件夹中工作)。不幸的是,当我尝试git pull
时,发生了这种情况:
* [new branch] development -> origin/development
* [new branch] master -> origin/master
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
现在当我使用git pull origin development
时,会显示:
From github.com:repo_address
* branch development -> FETCH_HEAD
fatal: refusing to merge unrelated histories
我现在能做什么?我应该改变吗?
答案 0 :(得分:4)
你应该创建一个新的分支并挑选你的提交。您可以与--allow-unrelated-histories
合并。无论哪种方式,您至少需要一个新的提交,以绑定到现有的分支。
这部分是问题的关键:
我的笔记本电脑没有连接互联网......
您在笔记本电脑上创建了一个与其他存储库无关的存储库。
git init
我假设您在一个空目录中执行此操作,因此它实际上创建了一个新的空存储库。您的新存储库没有提交,因此没有分支,即使您(在分支master
上(矛盾地)。也就是说,您已经master
,但master
并不存在!
git remote add origin git://repo_address
这会添加一个遥控器,但不会联系遥控器(当然这是不可能的)。因此,您的存储库仍然没有提交。
git checkout -b webapp <- created a new branch
事实上,这还没有创建分支。它所做的就是将您从不存在的master
分支转变为不存在的webapp
分支。
然后我做了:
git add . git commit -m "something"
这是分支实际创建的地方,当你在这个空的存储库中创建它的第一个提交时。并且,由于此是存储库中的第一个提交,因此它具有不具有父提交的特殊属性。 Git称之为 root commit 。
git push origin webapp
当然,这需要访问Internet,因为它会在您提供的URL处调用Git。但是,只要你有访问权限,它所做的就是转移你提交的提交 - 单个root commit-intact,其所有父项(没有)及其所有文件,并在{{1}请求另一个Git更改或创建其分支名称repo_address
以匹配您自己webapp
上的最后一次提交。
webapp
的Git存储库现在有一个提交图,看起来像一个更复杂的版本:
repo_address
我假设了一些提交(因此我可以用单个字母而不是大丑陋的哈希ID对它们进行编号)。提交A--...--M <-- master
\
N <-- development
O <-- webapp
和A
是root提交。所有其他提交都来自O
或A
(但实际上没有任何内容来自O
,除非您在笔记本电脑上进行了多次提交。)
不幸的是,当我尝试
O
时,发生了这种情况:git pull
* [new branch] development -> origin/development
* [new branch] master -> origin/master
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details.
命令只运行git pull
,然后运行第二个Git命令。在这种情况下,它运行git fetch
而没有其他限制(因为您的git fetch origin
存储库中没有设置上游),所以你的Git调用了其他Git,即webapp
上的那个,并下载了他们所拥有的所有提交和分支,此时此作为repo_address
和master
工作,以及那些提交。现在你拥有相同的图表,除了你的Git使用远程跟踪名称而不是分支名称:
development
请注意,您仍然拥有自己的分支机构名称,并且两个名称 - 您的分支名称A--...--M <-- origin/master
\
N <-- origin/development
O <-- webapp (HEAD), origin/webapp
和远程跟踪名称webapp
都会记住其分支名称origin/webapp
- 指向提交webapp
,你的新根提交。
O
运行的第二个命令通常是git pull
。如果您还没有指定要合并的内容,则此合并需要上游设置,并且由于您没有上游并且未指定要合并的内容,因此该部分失败。
然后你跑了:
git merge
指定要合并的内容:由git pull origin development
标识的提交,您自己的Git通过远程跟踪名称development
进行记忆。 (我把它作为提交origin/development
绘制,在我的猜测图中。)
N
命令通过查找共享提交来工作。这是&#34;最近的&#34; (无论这意味着什么:它从图形图中直观)在两个分支上提交。两个分支中的一个是您当前的分支,即您git merge
所附加的分支。另一个分支是从您命名的提交中找到的分支,即提交HEAD
。因此,Git从提交N
返回其根,提交N
,以找到适当的共享提交。它还从提交A
向其根目录返回,以查找共享提交。但是O
是一个根,因此从O
向后移动会在O
停止。没有共享提交!
这是为什么 Git抱怨。附加到提交O
的历史记录包含一个提交,即提交O
本身。提交O
背后有更多的历史记录,但它永远不会导致提交N
。没有共享历史记录,合并没有意义。
挑选樱桃包括将提交 - 这是一个快照 - 变成一个变更集来查看&#34;发生了什么&#34;在该提交中,然后将相同的更改集应用于其他提交。更改集只是差异列表:将一个提交转换为另一个提交的说明。例如,O
显示的内容。要将提交转换为diff,Git会将提交与其父级进行比较。
显然,挑选root提交有点棘手,但Git 可以做到这一点。它的作用是将根提交与空提交进行比较(更确切地说,是empty tree)。生成的diff包含以下命令:添加此新文件;这是内容。
因此,您现在可以查看现有的分支机构名称git diff
,但有一个问题:您不会拥有名为development
的现有分支。记住,你有这个:
development
但A--...--M <-- origin/master
\
N <-- origin/development
O <-- webapp (HEAD), origin/webapp
为您创建一个名为git checkout
的分支,如果您要求它查看development
,因为它会在那里找到&#39 ; s development
看起来像origin/development
,它将继续创建本地名称,指向同一个提交,然后将其设为development
:
HEAD
您现在可以使用A--...--M <-- origin/master
\
N <-- development (HEAD), origin/development
O <-- webapp, origin/webapp
创建另一个新分支,例如webapp2
,也指向提交N
:
git checkout -b webapp2
和现在您可以合并或挑选提交A--...--M <-- origin/master
\
N <-- development, origin/development, webapp2 (HEAD)
O <-- webapp, origin/webapp
。
我将本节的大部分内容外包给另一个StackOverflow问题:What exactly do we mean by "branch"?当我们谈论&#34;分支&#34;在这里,如果我们不是指分支名称,我们指的是以分支提示结尾的一系列提交,如O
和M
。您将希望您的工作(在分支图结构或分支 - 祖先术语中)与这些现有分支相关联。这意味着您希望新的提交链接回提交N
,N
的当前提示。
假设您如上所述创建development
,然后运行webapp2
。 Git将复制提交git cherry-pick webapp
到适用于当前提交O
的新提交O'
。 Git将通过执行所有这些&#34;使用这些内容创建新文件来完成此操作&#34;通过将提交N
与空树进行比较而生成的git diff
的操作。由于新文件不会干扰任何现有文件,因此这一切都可以正常工作。
当Git进行新提交时,它将向前拖动当前分支O
以容纳它,您将拥有:
webapp2
这可能是你一直想要的。现在,您可以删除自己的A--...--M <-- origin/master
\
N <-- development, origin/development, webapp2 (HEAD)
\
O' <-- webapp2 (HEAD)
O <-- webapp, origin/webapp
,然后在webapp
删除其他Git中的webapp
,并在任何地方使用repo_address
,就像您按照自己的方式使用webapp2
一样如果您之前能够访问互联网,那就可以了。
您可以运行git merge --allow-unrelated-histories webapp
。这将告诉Git使用与公共起点相同的空树来制作两个差异。一个比较提交N
的内容:添加每个文件。一个比较提交O
的内容:添加每个文件。 Git然后将操作组合在一起 - 这些操作都在不同的文件名上 - 并与两个父母进行合并提交,:
A--...--M <-- origin/master
\
N <-- development, origin/development, webapp2 (HEAD)
\
P <-- webapp2 (HEAD)
_____/
/
O <-- webapp, origin/webapp
您可以再次删除webapp
。奇怪的是,在您的历史记录(您的提交集)中,您现在拥有这个额外的根提交O
。
git merge --squash
查看git merge --squash
的作用并预测它将如何离开您的存储库。这与樱桃采摘相比如何? (如果你愿意,可以在克隆中试试。)
答案 1 :(得分:0)
简单rebase
也可能无法正常工作,因为它也会尝试查找“上次常见提交”。
最好的机会是树操作员表单
rebase --onto target_branch start_commit_exclusive end_commit_inclusive
其中target_branch
是远程主服务器,start_commit_exclusive
是您无关分支中的第一个提交,end_commit_inclusive
是您不相关分支的HEAD。
问题是你不能包含你的无关分支的“初始”提交,所以你可以选择“首先进入远程主服务器:
git checkout -b master origin/master
git cerry-pick SHA_OF_YOUR_FIRST_COMMIT
git rebase --onto master SHA_OF_YOUR_FIRST_COMMIT webapp