即使master只包含一个空的README,为什么我不能将git dev分支合并到master?

时间:2019-03-25 22:33:24

标签: git gitlab

我正在结束在dev分支上开发的应用程序的构建,现在想将其添加到master进行生产。

但是,当我结帐到master并运行git merge dev时,收到致命错误refusing to merge unrelated histories。不幸的是,git pull origin master --allow-unrelated-histories didn't help resolve the error

这是master的状态:

  • git status显示我的“分支机构的'origin / master'是最新的”。
  • 回购中的唯一文件是空的README.md
  • GitLab将此标签为“陈旧”分支。
  • 这是一个受保护的分支。

帮助我了解为什么我无法合并。

编辑:我还应该提到git log会产生以下结果:

commit ac22443836aeaf8abe38aa3761970a4cd3835587 (HEAD -> master, origin/master)
Author: // my info
Date:   Fri Dec 21 03:25:26 2018 -0700

    Initial commit
(END)

4 个答案:

答案 0 :(得分:0)

如果必须使用import React from 'react'; import { createStackNavigator, createSwitchNavigator, createAppContainer } from 'react-navigation'; ... const MainStack = createSwitchNavigator( { Home: HomeStack, Auth: AuthStack }, { initialRouteName: 'Home' } ); const AppContainer = createAppContainer(MainStack); class Main extends React.Component { constructor(props) { super(props); } componentDidMount = () => { var that = this; firebase.auth().onAuthStateChanged(async function(user) { if (user) { await that.props.getUserProfile(user.uid); } else { that.navigation.navigate('Auth'); } }) } render() { return ( <AppContainer /> ); } } const mapStateToProps = state => { return { user: state.auth.user } } export default connect(mapStateToProps, {getUserProfile})(Main); ,则意味着您实际上拥有合并在一起的两个不同存储库的等效内容。

我怀疑这是因为您在创建dev分支并进行工作之前没有先--allow-unrelated-hhistories原始仓库。我从您的描述中得出的推论是,您做了一个clone,签出了一个git init分支,然后在想要合并时将远程仓库添加为dev(这很有效,因为您的本地仓库没有遥控器。

尝试在此时合并将获得“无关的历史记录”,因为实际上这两个存储库无关。原始文件被创建并推送到GitLab,当您执行origin创建本地文件时,创建了一个完全独立的文件。克隆原始文件将创建与相关的本地存储库,因为它共享了最初的git init提交。

确实,这是解决此问题的唯一方法,一旦您推送到GitLab,本地和远程将同步-但是您应该始终进行克隆以避免出现此问题。

答案 1 :(得分:0)

如果像据说的那样,masterdev没有共同的(父)提交,那么我将尝试从master创建一个新分支,然后全部选中从dev提交到它: git cherry-pick startHash^..endHash 例如git cherry-pick 1234^..5678。 然后,您应该可以将此新分支合并到master

答案 2 :(得分:0)

创建存储库时,您可能已选中“ []使用自述文件创建存储库”。

master确实为空时,我看到以下选项

  • 转到gitlab,将默认分支更改为其他分支,然后在Web界面中删除master分支(可以删除受保护的分支)。或者,

  • 取消保护master

现在,您可以将dev分支强制推到gitlab(例如git push -f dev:master)。

注意:此选项对于分支机构而言是不可行的。其他人使用的存储库。在这种情况下,请执行以下操作:

git fetch gitlab master
git merge -s ours FETCH_HEAD

并推动此分支。

答案 3 :(得分:0)

您已经使用--allow-unrelated-histories修复了(?),没有真正的理由不放弃它。但是如果您仍然想知道...

发生了什么事,以及您(大概)如何到达这里

使用Git的第一个关键是要了解Git与 commits 有关。当然,这还要求您以某种相当深入的方式理解 是什么。它是什么,很简短,很简单:它是一个永久(主要)和不可变(整个)快照和一些元数据。快照包含您的所有文件-以及提交时的所有文件-元数据具有:

  • 您的姓名和电子邮件地址,以及您提交的时间;
  • 您的日志消息,即为什么,您进行了此提交;而且至关重要的是,
  • 此提交之前 的提交的哈希ID,定义为此提交的 parent

每个提交都是唯一的(由于许多原因,包括上述时间戳记),每个唯一提交都具有唯一的哈希ID。该哈希ID(一个大的丑陋的十六进制字符字符串)似乎是随机的,但实际上是提交的 contents 的加密校验和。它实际上也是该提交的真实名称:该ID 表示该提交,并且仅该提交。没有其他提交将具有该哈希ID。该哈希ID始终表示那个提交。

Git实际上通过哈希ID来找到提交。因此,哈希ID至关重要。当然,人类也无法记住。因此,Git为我们提供了一种记住最新哈希ID的方法,这种方式就是分支名称,例如masterdev

名称仅需记住 last 提交,因为每个提交都可以自己记住其父级的哈希。就是说,给定一个只有三个提交的小型存储库,我们用一个大写字母替换实际的哈希ID,我们可以这样绘制:

A <-B <-C   <-- master

名称master记住C的哈希ID。 C本身(通过哈希ID检索的实际提交)会记住B的哈希ID,而B本身会记住A的哈希ID。

当某些东西记住其他提交的哈希ID时,我们说这是指向的提交。因此,名称master指向CC指向B,而B指向A。这三个提交-C,然后是B,然后是A- 是存储库中的历史记录。

请注意,A并未指向任何地方。从字面上讲是不可以的,因为这是第一次提交。没有更早的提交。因此,事实并非如此,Git将此称为 root 提交。所有非空存储库都必须至少具有一个root提交。多数人可能只有一个……而您的却只有两个。

常规分支和合并

让我们快速了解制作分支的更常规方法。假设我们只有master所指向的这三个提交。我们要求Git创建一个 new 分支名称,指向与master相同的提交:

A--B--C   <-- dev (HEAD), master

这两个名称都标识提交C,因此,提交C都在两个分支上,并且都是 tip提交,这两个分支都在这两个分支上。但是现在我们重新提交。使用常规编辑以及git addgit commit进行新提交的过程将创建新快照,添加我们的姓名,电子邮件和时间戳等,并使用 current 提交C作为已保存的哈希,并构建新的提交。新的提交有一些笨拙的哈希ID,但我们将其称为D

A--B--C   <-- dev (HEAD), master
       \
        D

由于D的父母是C,因此D指向C。但是现在神奇的事情发生了:Git将D的哈希ID写入当前的分支名称(附加了一个HEAD),现在我们有了:

A--B--C   <-- master
       \
        D   <-- dev (HEAD)

,瞧,我们有一个新的分支。 (好吧,我们之前曾提到过C。尽管大多数人不喜欢这样思考,但他们想调用D分支。实际上,分支是{{ 1}}!)

随着时间的流逝,我们向两个分支都添加了一些提交:

D-C-B-A

我们A--B--C-----J----K----L <-- master \ D--E--F--G--H--I <-- dev git checkout master。 Git将为我们找到合并基础提交,其中git merge devdev不同。那显然是提交master,因为那是过去两个分支重新结合的地方。 Git将比较CC来了解我们在L上所做的更改,比较masterC来了解我们在I上所做的更改,并合并更改。 Git将 combined 更改应用于 dev 中的快照(应用于合并基础),并进行新的 merge commit {{1 }}照常在我们当前的C分支上进行,更新该分支的名称,以便M指向HEAD

master

M的特殊之处在于它具有两个向后链接:就像所有提交一样,它返回到A--B--C-----J----K----L--M <-- master (HEAD) \ / D--E--F--G--H--I <-- dev ,但是它有第二个父级{{1 }},这是分支M的当前提示提交。但是,除了两个父母之外,它很普通:它具有照常拍摄的快照,以及我们的姓名,电子邮件和时间戳以及一条日志消息。

异常分支

Git中没有任何东西可以阻止您进行额外的root提交。有点棘手。假设以某种方式,您这样做:

L

一旦遇到这种情况,I只会给您一个错误。这是因为查找合并基础的常用方法(从两个分支技巧开始并向后工作)永远找不到共同的提交。

添加dev告诉Git 假装在两个分支之前 有一个特殊的空提交:

A   <-- master

B--C--D--...--L   <-- dev (HEAD)

现在,Git可以比较git checkout master; git merge dev--allow-unrelated-histories来查看您在 A <-- master (HEAD) 0 B--C--D--...--L <-- dev 上所做的更改,以及0A来查看它们在{{ 1}}。在master上,您添加了每个文件。在0上,您还添加了每个文件。只要它们是不同的文件,组合这两个更改的方法就是将L提交的dev文件添加到master提交的{ {1}},将这些更改应用于空的null提交,然后提交结果,并让父母回到devmaster

A

您(大概)如何到达这里

有一个dev选项L,用于设置此状态。但这可能不是您所做的。设置的状态是使用A创建新的空存储库时所处的相同状态:

L

没有分支机构,但是Git会说您是A---------------M <-- master (HEAD) / B--C--D--...--L <-- dev 。您不能git checkout上:它不存在。但是您是,即使它不存在。 Git管理此问题的方式是将名称 git checkout --orphan放入git init(实际上是[no commits] <-- [no branches] )中,而无需首先创建名为on branch master的分支。它无法创建分支,因为分支名称​​必须包含有效的哈希ID,并且没有。

因此,当您运行master时,Git会检测到此异常状态:master表示HEAD.git/HEAD不存在。这就是触发Git进行我们的根提交master的原因。然后,Git将git commit的哈希ID写入分支,它创建分支,现在我们有了:

HEAD

这正是我们想要的。

但是假设,当我们处于这种奇怪的尚未提交状态时,我们运行:

master

这告诉Git:将名称master放入A 中。即使没有A,它也可以毫无抱怨地做到这一点。然后我们进行第一次提交,但出于显而易见的原因,我们选择A <-- master (HEAD) 作为其哈希ID的单字母替代:

git checkout -b dev

同时,先在这里运行dev,然后运行HEAD,然后执行一些操作,然后master,我们将转到$ WebHostingProvider-无论是GitHub还是GitLab或Bitbucket或其他任何东西-并使用其为我建立新的存储库 clicky按钮。它们通常具有一个选项:使用README和/或LICENSE文件等创建初始提交。如果该选项被选中-或者未选中选项-则继续进行第一次提交和B

B   <-- dev (HEAD)

现在,您将存储库连接到他们的存储库,并让Git下载他们没有的任何提交:

git init

您现在可以继续添加大量提交,而无需注意您的git checkout -b dev分支与其git commit分支(您的Git正在调用master)无关。

稍后,您运行:

A   <-- master (HEAD)

您的Git通知您没有 A <-- origin/master B <-- dev (HEAD) ,但是您确实有dev。因此,您的Git为您创建一个master,指向与origin/master相同的提交,并将您的git checkout master 附加到新的master上: / p>

origin/master

,你在泡菜里。