我克隆了一个存储库并创建了一个新分支。忘了结帐到新分支。是否进行了更改(删除了大多数文件),添加了,提交了然后将其推送到远程。现在我失去了主人。
试图返回到先前的状态:
git checkout master
git reset --hard Tony_branch
git push -f origin master
结果:
Total 0 (delta 0), reused 0 (delta 0)
remote: Processing changes: done
To ssh://<link> can't share the name obviously.
! [remote rejected] master -> master (non-fast forward)
error: failed to push some refs to
所有答案均建议使用“ git pull”。但是它将重新删除文件...
我该如何解决?
编辑:
我试图通过用我在更改前创建的分支覆盖旧的master来检索旧master。当然其他方法可能会更好。
答案 0 :(得分:0)
我不知道您当前存储库的确切状态,因此此答案可能对您不起作用,至少不是开箱即用。相反,一旦您意识到按master
是一个错误,我将采取应遵循的步骤。
首先,从本地master
签出一个新分支:
# from master
git checkout -b Tony_branch_real
然后,将您所做的提交还原到master
:
# again, from master
git revert A^..B
这里A
代表您对master
的第一个意外提交,而B
代表最后的意外提交。 git revert
将向您的master
分支添加一个 new 提交,从功能上撤消A
至B
的所有(包括)提交范围。您的实际命令看起来像这样:
git revert dk93kg93^..k20gjei9
其中A
和B
已被其SHA-1哈希替换。在您的git log
分支上检查master
,找到所需的SHA-1散列。
最后,您只需要定期将master
推送到遥控器:
git push origin master
这应该行得通,因为您在本地所做的就是添加一个新的还原提交。
我们避免在master
上执行诸如硬重置之类的事情的原因是,该分支可能是由其他开发人员共享的。硬重置会重写历史记录,因此对于公共共享分支,我们要避免这种情况。
答案 1 :(得分:0)
看来您的遥控器将不接受git push -f
。因此,除非可以在远程(gitlab,github,bitbucket)上修复分支保护,否则无法撤消master分支。
但是,您可以通过各种方式恢复所做的文件。一种是还原主服务器的所有提交,直到您回到原始状态。
另一种方法是
git checkout master
git reset --hard origin/master
git reset Tony_branch #soft reset on purpose
git add ... # all changes
git commit -m 'Reverting master to state before bad push'
git push origin master
答案 2 :(得分:0)
基本上有两种方法可以解决这种错误。
一种方法是进行历史记录重写。这通常是犯错误的人想要的,因为它几乎完全消除了错误。但这并不总是可行的,有时甚至是不允许的。
其他选择是接受错误作为历史记录的一部分,并对历史记录也进行更正。
至少有两种方法可以完成这些操作。
历史记录重写
听起来您知道执行历史记录重写的合适方法,但是由于push -f
步骤的缘故,它不起作用。如果您控制远程仓库,则可以更改权限/保护设置以允许强制推送到主仓库,但这不一定是个好主意,有两个原因:
首先,保护master分支在大多数情况下可能是一个好主意,即使在这种情况下也是如此。当然,如果这是唯一要考虑的问题,则可以取消保护它,进行重写,然后重新保护它。
第二个可能的问题是,如果任何其他克隆已经将错误的提交拉入master
,则强行从master
的历史记录中删除那些提交将“破坏”这些克隆,并且它们必须采取措施进行恢复。如果他们执行了错误的步骤,则可以轻松地重新引入已删除的提交,尤其是如果他们根据要撤消的提交进行任何新工作时,这尤其值得关注。请参阅“从上游基础恢复中”下的git rebase
文档;即使您所做的并不是本质上的调整,也适用相同的情况。
因此,很可能您需要一种不重写历史记录的解决方案,这是我将在此期间重点关注的问题。
添加更正
您的存储库当前可能看起来像
... x <--(tony_branch)
\
A -- B -- C <--(master)(origin/master)
现在,您要将origin/master
移至x
;这将成为“最干净的”历史记录。 (而且,如果我们说实话,那将避免保留永久的滑倒记录。这并不是说我们有任何理由要保留错误记录;只是想摆脱这种错误。记录可能比记录更重要,而历史记录重写的成本也是如此。)
但是您已经读了很多,因为显然重写origin/master
的历史记录是不可行的。因此,通常人们会建议使用git revert
。这将导致类似
... x <--(tony_branch)
\
A -- B -- C -- ~CBA <--(master)(origin/master)
其中~CBA
撤消对A
,B
和C
所做的更改,而将内容(TREE
对象)保留在master
就像x
一样。那是一种选择;这很简单,并且可以在以后的任何git命令中将其保持为直接状态。
另一种选择是将合并提交用于还原。这使得A
,B
和C
看起来像被废弃的侧支。 “不利的一面”是更容易看到A
.. C
;可以忽略;“不利的一面”是有问题的合并会有点不自然-什么有时称为“邪恶合并”。如果您可能要重新确定这部分提交的内容,那么“邪恶合并”可能是一个问题-但是再说一次,因为我们去那里是因为master
的历史重写不是一回事,也许这不是问题。没关系。无论如何,这最终看起来会更像
... x <--(tony_branch)
|\
| \---------- Y <--(master)(origin/master)
\ /
A -- B -- C
为此,您可以说
git checkout master
git reset --hard tony_branch
git merge -s ours origin/master
git push
请注意,无论采用哪种方式,从A
到C
的提交都将纳入master
的历史记录中。这意味着不再可以通过将那些提交合并到master中来“重新应用”分支的更改-因为它们已经“存在”了。要解决此问题,您可以创建A
至C
的提交副本,并将这些副本放在tony_branch
上。这可以在更新master
之前或之后完成(通过还原或合并);之前可能会更容易一些,但是我没有在其中包含说明,因为在这里解释为什么更加容易。
因此,您要做的是A
至C
的“强制变基”。与流行的看法相反,rebase
不会“替换”源提交,而是复制它们。强制操作只是意味着“即使我并没有真正更改基准或其他任何内容,也要进行复制”。第一步是检出{{1}}。如何执行操作取决于您采取了哪些其他步骤:
(A)将合并应用到C
之后,您可以
master
,这会使您在git checkout master^2
处的合并提交的第二个父级处于分离的HEAD
状态。或
(B)在应用还原后,您可以
master
(如果在单个提交中应用了还原;如果使用了单个还原提交,则类似于git checkout master^
,但是使用了许多实际的还原提交来代替master~3
)。或
(C)在修复3
之前,您可以简单地
master
但是请注意,您要做要以“分离的HEAD”状态结束,以避免git checkout --detach master
分支的错误移动;因此是master
选项。
现在已经签出--detach
,您可以
C
你会得到类似的东西
git rebase -f tony_branch
git branch -f tony_branch
答案 3 :(得分:0)
如果您对重置/还原不满意,我将执行以下步骤,而不是进行重置/还原:
(假设您在更改之前创建的分支名称为“ good-master-branch”)
如果使用的是github或bitbucket之类的工具,则可以在GUI中进行设置。
首先,请确保您不在主分支git checkout good-master-branch
删除本地git branch -D master
删除远程git push origin --delete master
git checkout good-master-branch
git checkout -b master
现在,您有了一个新的干净的master分支!