我正在尝试找出多个人要推送到的共享存储库的工作流程。 目标是使人们能够根据自己的意愿进行本地提交,保留有关创建和合并分支的时间的信息,同时保留最终推送到的分支的清晰历史记录。
在git-merge的手册页中指出merge
...将重播自从主分支(即E)分支到主分支之上的当前提交(C)以来,在主题分支上所做的更改,并将结果记录在新的提交中...
>
我想你可以做的是以下事情:
master
branch
,并完成5次提交中的所有工作master
开关将本地分支合并回到--no-ff
,强制创建合并提交(其中包含所有合并提交的更改)。master
执行此操作时得到的本地历史记录如下:
* cada35b - Tue, 26 Feb 2019 08:55:45 +0100 (21 minutes ago) (HEAD -> master, origin/master)
| 6 - dev
* 8391544 - Tue, 26 Feb 2019 08:55:44 +0100 (21 minutes ago)
| 5 - dev
* 4381abd - Tue, 26 Feb 2019 08:55:41 +0100 (21 minutes ago)
| 4 - dev
* 40e21b1 - Tue, 26 Feb 2019 08:54:49 +0100 (22 minutes ago)
|\ #3254 Important Feature - Merge branch 'branch' - dev <-- Merge commit
| * 4f595e8 - Tue, 26 Feb 2019 08:54:38 +0100 (22 minutes ago) (branch)
| | 3.3 - dev
| * ea05ba7 - Tue, 26 Feb 2019 08:54:36 +0100 (22 minutes ago)
| | 3.2 - dev
| * d779583 - Tue, 26 Feb 2019 08:54:34 +0100 (22 minutes ago)
|/ 3.1 - dev
* fab5a25 - Tue, 26 Feb 2019 08:54:20 +0100 (22 minutes ago)
| 3 - dev
* b6ddac3 - Tue, 26 Feb 2019 08:54:19 +0100 (23 minutes ago)
| 2 - dev
* 0abafad - Tue, 26 Feb 2019 08:54:18 +0100 (23 minutes ago)
1 - dev
这是正确的,也是我想要的。我对遥控器的期望(和需求)是这样的历史记录:
* cada35b - Tue, 26 Feb 2019 08:55:45 +0100 (7 minutes ago) (HEAD -> master, origin/master, origin/HEAD)
| 6 - dev
* 8391544 - Tue, 26 Feb 2019 08:55:44 +0100 (7 minutes ago)
| 5 - dev
* 4381abd - Tue, 26 Feb 2019 08:55:41 +0100 (7 minutes ago)
| 4 - dev
* 40e21b1 - Tue, 26 Feb 2019 08:54:49 +0100 (8 minutes ago)
| #3254 Important Feature - Merge branch 'branch' - dev <-- Merge commit
* fab5a25 - Tue, 26 Feb 2019 08:54:20 +0100 (9 minutes ago)
| 3 - dev
* b6ddac3 - Tue, 26 Feb 2019 08:54:19 +0100 (9 minutes ago)
| 2 - dev
* 0abafad - Tue, 26 Feb 2019 08:54:18 +0100 (9 minutes ago)
1 - dev
但是,实际上我得到的是我在本地所做的所有提交,只是没有我没有推送的分支的分支指针:
* cada35b - Tue, 26 Feb 2019 08:55:45 +0100 (7 minutes ago) (HEAD -> master, origin/master, origin/HEAD)
| 6 - dev
* 8391544 - Tue, 26 Feb 2019 08:55:44 +0100 (7 minutes ago)
| 5 - dev
* 4381abd - Tue, 26 Feb 2019 08:55:41 +0100 (7 minutes ago)
| 4 - dev
* 40e21b1 - Tue, 26 Feb 2019 08:54:49 +0100 (8 minutes ago)
|\ #3254 Important Feature - Merge branch 'branch' - dev <-- Merge commit
| * 4f595e8 - Tue, 26 Feb 2019 08:54:38 +0100 (8 minutes ago)
| | 3.3 - dev
| * ea05ba7 - Tue, 26 Feb 2019 08:54:36 +0100 (8 minutes ago)
| | 3.2 - dev
| * d779583 - Tue, 26 Feb 2019 08:54:34 +0100 (8 minutes ago)
|/ 3.1 - dev
* fab5a25 - Tue, 26 Feb 2019 08:54:20 +0100 (9 minutes ago)
| 3 - dev
* b6ddac3 - Tue, 26 Feb 2019 08:54:19 +0100 (9 minutes ago)
| 2 - dev
* 0abafad - Tue, 26 Feb 2019 08:54:18 +0100 (9 minutes ago)
1 - dev
是否有任何方法只能推送合并提交,并且是否包含在本地分支上所做的所有更改?
我知道merge --squash
和rebase -i
存在,但是对于那些您无法看到什么东西在什么时候合并回到分支(merge --squash
)或完全失去本地历史记录({{1} }。
答案 0 :(得分:0)
答案是否,您在这里找不到想要的东西,原因是Git确实是关于 commits 的全部内容,它固定在石头上并永久保存, 1 与其制作时的形状完全相同。这包括它们的提交图链接,因为每个提交都通过其原始哈希ID链接到其父提交。 Git中的push和fetch操作将转移这些提交,并包括使图形完整所需的所有提交。 名称(尤其是分支名称)在很大程度上是不重要且短暂的,只有一个例外。
这里的例外是,为了记住并查找提交,Git需要名称。名称位于图链的 end 。从那里,Git跟随该图查找所有祖先提交。
由于合并提交有两个父级,并且图必须始终完整,所以 2 哪个Git 接收,合并提交也将获得其所有祖先,即合并的“双方”。仅有一个父对象的提交将是具有不同哈希ID的不同提交。
这就是git merge --squash
产生的东西:一个新的,不同的提交,具有不同的哈希ID,但具有相同的 tree (快照),这将产生真正的合并。但是使用git merge --squash
的副作用是,开发分支(您在git merge --squash
的参数中使用的名称)现在实际上已经失效。您没有拥有将其杀死,但您可能应该这样做。请注意,这也是可以的:如果这就是您想要的-如果您想终止开发分支并用单个提交 replace 五个(或很多)提交,那么{{1 }}可能是要走的路。
这里没有正确的工作流程,但是开发人员有一种可能是不将他们的工作合并到下一个上一级分支中,而是将下一级分支合并到他们的工作中。也就是说,我可能从以下开始:
git merge --squash
我从提交...--o--o--*--...? <-- origin/mainline
\
1--2--3--4--5 <-- feature (HEAD)
开始了我的feature
分支,所以我的*
分支包含了所示的五个提交。同时feature
可能已经增长。因此,我运行mainline
更新了git fetch
,现在我看到了:
origin/mainline
这时,我可以选择运行...--o--o--*----o----o----A <-- origin/mainline
\
1--2--3--4--5 <-- feature (HEAD)
在git merge origin/mainline
上创建新的合并提交M1
:
feature
{{1}中的快照与我要创建的快照相同,如果我做了...--o--o--*----o----o----A <-- origin/mainline
\ \
1--2--3--4--5--M1 <-- feature (HEAD)
(从{{1创建自己的M1
}},然后依次是git checkout mainline
和mainline
,然后依次是origin/mainline
和git merge feature
。但是,如果我已经做了,那我现在就会拥有:
git push origin mainline
请注意,git checkout feature
和git branch -D mainline
具有相同的快照,相同的作者和提交者以及相同的父哈希ID,但可能具有不同的时间戳。只是时间戳使...--o--o--*----o---o---A--M2 <-- origin/mainline
\ /
1--2--3--4--5 <-- feature (HEAD)
和M1
本身与众不同!如果要以某种方式在两个不同的Git存储库中,在完全相同的时间中并行执行这两个操作,M2
和M1
将具有 same < / em>哈希,并且-因为 graph 是相同的-唯一的区别是 labels 的集合。我们可以通过以下方式更清楚地绘制这种情况:将图节点摆动一下,然后调用合并M2
,然后删除两个标签:
M1
如果我们将标签M2
或M
粘贴到提交 o-----o-----A
/ \
...--o--o--* M
\ /
1--2--3--4--5
上,并将标签mainline
粘贴到提交origin/mainline
上,则情况#1:将主线合并为功能。如果我们将标签A
或feature
粘贴到提交M
上,并将标签mainline
粘贴到提交origin/mainline
上,则情况2:我将功能合并到主线。
换句话说,除了标签的排列,两个合并的功能完全相同。因此,当我使用M
发送提交图< / em>到feature
的推送存储库中,我采用哪种合并方式都没关系。唯一重要的是我要求5
上的Git使用什么来记住提交git push
:我是否要求它设置其origin
,或者我是否要求它设置其origin
,还是组成一个诸如M
之类的名字?
在 my 存储库中,我有 my 分支名称(feature
,mainline
(如果选择保留一个,torek/feature
如果我选择保留,依此类推)。在feature
上的存储库中,您有您的分支名称。我们都共享 commits ,并且我的Git记得在我的mainline
名称下的您的分支名称(自上次获取或推送以来)。
该图已共享。标签是每个存储库的。(大多数)就是存储库的全部:图形和一些标签。无论谁看着图(和标签),都可以猜测意图是什么,然后从那里开始工作。因此,您必须围绕这些基本事实定义工作流程。 master
命令将发送添加到图中的新提交,然后在origin
的Git中设置一些标签。
如果我合并到origin/whatever
中,则可以继续这样工作:
git push
我的合并origin
可能比我没有进行feature
容易,因为创建...--o--o--*----o----o----A--o--o--o---B <-- origin/mainline
\ \ \
1--2--3--4--5--M1--6--7--8--M2 <-- feature (HEAD)
的合并基础是提交M2
,而我的两个技巧是M1
和M2
的提交。当我制作A
时,我合并了基础8
和分支提示B
和M1
。如果*
最终将被合并为5
,而A
被杀死并提交feature
被遗忘并最终被垃圾回收,则这是一种合理的方法关于该过程。
1 永远太强了。在可以到达时,最后提交。可达性的概念对于Git来说非常重要。参见Think Like (a) Git。分支名称(和标记名称,以及与此相关的任何其他引用)用于使提交可访问。如果没有受到其他名称及其提交祖先的保护,则删除分支名称可能会释放其提交,以供Git的垃圾收集器随身携带并进行收集。
2 Git违反了 shallow 存储库的完整性规则,但实际上并没有帮助您。浅层存储库是一个具有一个或多个提交的库,这些提交 do 的某些父级具有一些哈希ID,但是这些父级提交只是 missing 。有一个名为mainline
的文件,其中包含其父项缺失的提交的哈希ID。当Git即将使用此类提交时,它没有查看其父ID,而是注意到此提交列在feature
中,并且出于某些目的(例如1-2-3-4-5-M1-6-7-8-M2
),我们假装commit没有父母。因此,出于空间和/或时间原因,这使您可以截断一次提交的历史记录,但是就像修剪的树枝一样,它只是截断,之后您可以将其重新植入位置,一切都会好起来,图将是完整的-在任何地方的所有存储库中,因为 commits 是共享的,而且这个不变。