修复GIT存储库上的历史记录

修复GIT存储库上的历史记录,git,git-branch,git-merge,master,git-revert,Git,Git Branch,Git Merge,Master,Git Revert,我的GIT存储库中有以下情况。有人在做改动之前忘了拉主人,然后向他当地的主人承诺。之后,出于某种原因,他将源代码/主代码合并到其本地主代码中,然后将其推送。结果是,原籍/主人与他当地的主人“交换了位置”。我说得通吗? 以下是一个例子: 推前 x----x-----x----x----x----x----x-----x----x (MASTER) 推后 ---------------------------------------------x---x (MASTER) |

我的GIT存储库中有以下情况。有人在做改动之前忘了拉主人,然后向他当地的主人承诺。之后,出于某种原因,他将源代码/主代码合并到其本地主代码中,然后将其推送。结果是,原籍/主人与他当地的主人“交换了位置”。我说得通吗? 以下是一个例子:

推前

x----x-----x----x----x----x----x-----x----x (MASTER)
推后

 ---------------------------------------------x---x (MASTER)
|                                                 |
x----x-----x----x----x----x----x-----x----x-------

这有点搞砸了存储库,因为所有的历史现在似乎都在一个分支上

在那之后,有一些新的提交被推送到了新的主机上,然后出于一个现在并不重要的原因,我们决定不需要这些提交,所以我们设法删除了我们不想要的提交,同时将de-master恢复到原来的位置。像这样:

以前

 ---------------------------------------------x---x---x---x---x (MASTER)
|                                                 |
x----x-----x----x----x----x----x-----x----x-------
之后

                                             (2)
 ---------------------------------------------x---x---x---x---x-- 
|                                               |                |
x----x-----x----x----x----x----x-----x----x-----x----------------x (MASTER)
                                         (1)                    (3)
正如你所看到的,现在这个忘记了tu pull的家伙所做的承诺已经被合并到原来的大师身上。这是这样实现的:

git checkout <HASH OF COMMIT MARKED AS (1) >
git checkout -b refactor_master
git merge --no-ff <HASH OF COMMIT MARKED AS (2) >
git push origin refactor_master
git merge --strategy=ours mastergit checkout master
git merge refactor_master
git push origin master
git签出
git签出-b重构\u主控
git合并--无ff
git推送源重构\u主机
git合并--策略=我们的主git签出主
git合并重构\u主机
git推送源主机
这有效地使这些提交合并的更改与主控不再相似,也使主控变成了过去的样子。然而,我现在有一个不应该存在的“分支”。事实上,最后一次提交(标记为(3))不会进行任何更改。它只“切换”主控。有没有办法使这些提交变得不相似?

git分支只是一个指向单个提交的标签。提交不知道当前指向它的分支;它也不知道以前有哪些分支机构指向它。因此,唯一真正重要的事情(对更改来说并不重要)是提交历史本身

清除此问题的最简单方法可能是:找到您认为代表代码库合理状态的最新提交,然后运行以下命令(假设提交的哈希为
123abc
):

这将使
master
在本地(运行这些命令的机器上)和服务器上指向
123abc
。当其他开发人员运行
git fetch
时,他们的
origin/master
将移动到
123abc
,他们可以使用
git checkout-B master origin/master
将其签出并移动到那里(不过,我不能完全确定这个命令的语法,我手头也没有git存储库。)


警告:除非您有一个分支指向比
123abc
更新的提交,否则这些提交似乎将消失。如果您希望稍后查看其内容以清理并重新提交,您应该从创建分支开始对于那些提交,例如git branch tempbranch 567def,这是有道理的:他所做的是违反了“开发的主线是第一父级”规则

请注意,git本身没有任何东西可以强制执行此规则。这是不可能的,原因很简单:谁定义哪一行是“主线”?这个问题唯一可能的答案是“你”,其中“你”的意思是“谁运行git来操纵提交图”。所以这不是一个真正的git规则,而是一个“使用git的人”规则

无论何时运行
git merge
(或者在本例中是“he”运行它),您都会选择当前分支作为开发主线,选择正在合并的分支作为正在合并的备用行。因此,如果您这样做:

$ git checkout master
$ make-some-change; git add ...; git commit -m message

$ git fetch origin # and let's assume this brings in a new commit
$ git merge origin/master
您告诉git将您的master作为主线,并将上游更改合并为分支线

请注意,最后两个命令-
git fetch
后跟
git merge
,是默认情况下,
git pull
所做的。这反过来意味着“主线是第一个父级”通常被违反,除非你非常严格/小心,否则不能依赖它


有没有办法让这些[合并]提交消失

是的,但只需要写一行新的提交(“重写历史”)

让我看一下您的最终图形(不必担心您是如何到达的),并对图形进行一些小的更改,以获得更紧凑的表示:

  ------------------------A---M1--B--C--D
 /                           /           \
o--o--o--o--o--o--o--o--o---x-------------M2   <-- master
这里
A'
的第一个也是唯一的父项是commit
x
,这是
master
在事情第一次“出错”时的提示commit。然后
B'
的第一个也是唯一的父项是A',依此类推

如果一旦有了此图形,您从白板提交
A
M2
擦除,并使
master
指向提交
D'
,您将得到以下结果:

o--o--o--o--o--o--o--o--o---x
                             \
                              A'--B'--C'--D'   <-- master
o--o--o--o--o--o--o--o--o--o--x
\

A'--B'--C'--D'我不确定我是否完全明白你的意思,但我要说的是:Git没有“哪个分支”的概念提交来自。在您的第二个图形中,它可能是由第一行上的大多数x和第二行上的两个x呈现的;它以这种方式表示相同的提交图形。为什么不在所有不好的事情发生之前将master还原到最后一次提交?这意味着“所有历史现在似乎都在一个分支上”是什么意思?还有什么地方?主分支怎么可能位于错误的位置?分支是否有物理位置?“现在所有的历史记录似乎都在一个分支上”…这是定义。git
中的所有提交将至少出现在一个分支上-那些没有被垃圾收集的分支。我如何“擦除”对straigthen行的承诺?我没有得到那部分。从技术上说你没有:你不能(好吧,没有一些更复杂的低级git的东西),但你也不必。这是一个分支标签
  ------------------------A---M1--B--C--D
 /                           /           \
o--o--o--o--o--o--o--o--o---x-------------M2   <-- master
                             \
                              A'--B'--C'--D'   <-- new-master
o--o--o--o--o--o--o--o--o---x
                             \
                              A'--B'--C'--D'   <-- master