修复GIT存储库上的历史记录
我的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) |
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'
的第一个也是唯一的父项是commitx
,这是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