设置:我已将代码更改为本地和远程,但更改的分支错误。
我的解决方案:
- 已经签出master并创建了一个分支,代码更改应该在该分支中
- Cherry从错误的分支签入中选择了提交并提交到新的分支
- 查看错误的分支。重置为第一次正确提交然后再次强制推送以删除远程上的错误提交分支机构
问题:这是要走的路吗?如果我在谷歌上搜索,我会发现人们使用revert,我不明白为什么,因为它看起来更复杂、更危险。。为什么要使用revert?
当您revert
某个提交时,您会创建否定目标提交的提交。结果与reset
一样,但您不必使用force push
,您可以执行简单的push
,因为您可以添加到历史记录中,而不是从中删除。另一个区别是,您可以提交不是历史记录中最后一个的revert
。在这种情况下不能使用reset
,因为它会导致自目标提交以来丢失所有提交。
你也可以看看这个问题:What';Git Revert、Checkout和Reset之间的区别是什么?
我建议将重设为:,而不是3
git rebase --onto COMMIT_BEFORE_WRONG WRONG_COMMIT branch_with_wrong_commit
git push --force-with-lease
这"削减"了错误的承诺。
添加-i
(对于交互式)时,可以检查是否移动了正确的提交。
也会出现相同的结果
git rebase-i COMMIT_BEFORE_RONG
然后将所呈现的"todo"文件的第一行中的单词CCD_ 9更改为CCD_。
我[看到]人们使用revert,我不明白为什么,因为它看起来更复杂、更危险。。为什么要使用revert?
应该是一个强词。(不如应或必须那么强,但至少相当强。:-)
。。。重置为第一个正确的提交,然后再次强制推送以删除远程分支上的错误提交
每当您必须使用git push --force
或等效产品时,您都会以其他人可能意想不到的方式移动分支名称。(may弱于should:在偏序中,我会说may<may<should<shall/must。
考虑:
$ git checkout <somebranch>
... work ...
$ git add <files> # or --all or . or whatever
$ git commit
git checkout
步骤的作用是将HEAD
附加到一个分支,并将该分支的提示提交(如分支名称所指)复制到Git的索引和工作树中,以便您可以对其进行操作:
... <-F <-G <-H <--branch (HEAD)
名为branch
的分支——其全名为refs/heads/branch
的引用——存储某个提交H
的原始哈希ID。提交H
本身存储其父提交G
的原始哈希ID,后者存储某些提交F
的原始哈希标识,依此类推。因此,我们说名称指向提示提交H
,后者指向早期提交G
,依此类推
git add
步骤更新索引/暂存区域,使其为提交做好准备,git commit
步骤创建一个新的提交。新提交将当前签出的提交H
的哈希ID存储为其父哈希ID。(当然,它将从当前索引/暂存区域生成的冻结快照存储为快照。)然后,作为最后一步,git commit
将新提交的哈希ID写入HEAD
所附的分支名称中:
... <-F <-G <-H <-I <--branch (HEAD)
当人们进行提交时,分支就是这样生长的,一次一个提交。当你在一系列的提交中进行合并时,无论是作为真正的合并还是作为快速的非合并操作,分支也会获得新的提交,可能一次多次,也可能是以非线性的方式,但重要的是,新的提交总是返回到现有的提交:
...--F--G--H--I---M <-- master (HEAD)
/
J--K--L <-- develop
将合并提交M
添加到master
会使提交H
和I
从master
可访问,因为我们可以使用M
中的顶行箭头遵循向后指向的内部提交到提交箭头(此处呈现为线条,因为箭头现在太难在文本中绘制)。(从M
到L
的左箭头和下箭头允许我们从M
到K
或J
。Think Like(a)Git与波特兰的交通系统有很好的相似之处,尽管任何大都市的火车系统都是相似的。)
但假设我们这样做:
...--F--G--H--X <-- master (HEAD)
J--K <-- develop
然后意识到,哦,我们打算把提交X
放在develop
上。我们使用任何适合将X
复制到新提交的方法,如cherry-pick或git rebase --onto
(两者都做相同的工作)。然后,我们使用git checkout master; git reset --hard master~1
将X
推开,使其不再位于master
:上
X
/
...--F--G--H <-- master (HEAD)
J--K--L <-- develop
(这里L
是X
的副本,放在我们想要的地方。)这种分支名称移动使提交X
悬置,无法找到它——至少在我们的存储库中无法找到它。但是,如果我们已经使用git push
将提交X
发送到其他地方,那么一些其他Git也有它的名称。事实上,我们也是这样做的:
X <-- origin/master
/
...--F--G--H <-- master (HEAD)
J--K--L <-- develop
我们的origin/master
是Git在origin
上记住master
的方式,它仍然记得提交X
的存在。这意味着origin
的Git记得X
是他们的master
上的。
事实上,这就是我们必须使用git push --force origin master
的原因:告诉origin
处的Git,它应该放弃其提交的X
。如果我们在其他任何人——任何有权访问该Git的人——也将X
复制到他们的Git存储库之前这样做,我们就没事了:没有人看到X
,所以我们删除X
不会伤害任何人。
如果其他人从另一个Git上抓取了一份副本,问题就会堆积起来。现在有第三个Git存储库仍然有提交X
,可能在他们的master
中。也许他们已经在X
(他们的副本)上构建了他们想要保留的新提交:
...--F--G--H--X--Y--Z <-- master (HEAD)
我们现在要告诉他们:哦,忘记X
,也把它从你的存储库中拿走这要求他们执行自己的git rebase --onto
或类似操作,将他们的Y
和Z
复制到不再返回到X
的新提交中。
简而言之,通过从我们的Git和origin
的Git中删除X
,我们给共享这些Git存储库的其他人带来了负担:他们也必须全部删除X
,并处理任何后果。
在某些项目中,每个人都同意这种情况可能发生——无论是在任何时候发生在任何分支上,还是在任何时间发生在某些特定的分支子集上。在这些项目中,重置分支和强制推送是可以的。有些项目没有其他用户,或者你可以在任何人有机会发现错误之前强制推送;在这些情况下,重置和强制推动也可以。当你开始为那些不准备做很多工作的人做很多工作时,就会出现问题。在这种情况下,做出一个新的承诺,简单地取消在X
中的工作,让他们能够以准备接受的方式融入这项新工作。