我对 git 很陌生。我是个白痴,我在不知道自己在做什么的情况下使用它。我不小心用主人覆盖了我本地的所有内容。 36e6aed 是我 9 天前在 master 上执行的提交。我可以恢复我的“重大更新”提交吗?
注意:在此之前我做了 git add 。然后我在那之后输入了一些错误的东西,感到困惑,退出了窗口,然后做了下面打印的操作。
location/of/local/branch (master|MERGING)
$ git stash
Saved working directory and index state WIP on master: 36e6aed Restructure
location/of/local/branch (master)
$ git commit -m 'major updates'
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
location/of/local/branch (master)
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
location/of/local/branch (master)
$ git reflog
36e6aed (HEAD -> master, origin/master) HEAD@{0}: reset: moving to HEAD
36e6aed (HEAD -> master, origin/master) HEAD@{1}: commit: Restructure
b1ad2dc HEAD@{2}: pull origin master: Merge made by the 'ort' strategy.
5173228 HEAD@{3}: commit: tortoise mods
3df3009 HEAD@{4}: commit: Restructure
76a5c29 HEAD@{5}: pull origin master: Fast-forward
da38dd1 HEAD@{6}: pull: Fast-forward
122b86d HEAD@{7}: pull: Merge made by the 'ort' strategy.
bdc9928 HEAD@{8}: commit: In & Out folders
f339839 HEAD@{9}: commit (initial): Initial Commit
回答1
您没有进行 major updates
提交。幸运的是,您确实做出了提交;我们马上就拿回来。这是 Git 在您尝试制作时所说的:
$ git commit -m 'major updates' On branch master Your branch is up to date with 'origin/master'. nothing to commit, working tree clean
这个(不是很有帮助的)Git 消息是说“我什么都没做,因为没有什么可做的。”
这里的诀窍是意识到为什么没有什么可做的,那是在尝试提交之前:
location/of/local/branch (master|MERGING) $ git stash Saved working directory and index state WIP on master: 36e6aed Restructure
git stash
命令大致意味着:提交我现在拥有的,但根本不在分支上,然后删除所有工作,因为它已安全保存在提交中。所以你确实做了一个提交,但它不在任何分支上。要取回它,只需运行 git stash apply
,仔细检查结果以确保您喜欢它,然后——当且仅当你喜欢它时——运行 git stash drop
。
(你可以运行git stash pop
。意思是apply并立即drop。我建议将步骤分开,以便你可以先检查。通常apply很好,drop是正确的,但它有点像闭上眼睛跳下桥希望你降落在湖里而不是湖边的岩石上。)
它比这更多,但在你的情况下,你只想取回隐藏的东西,以便你可以正常提交它。
更多的
在您运行 git stash
之前,您的 shell 提示符显示:
location/of/local/branch (master|MERGING)
这意味着您正在使用一个支持 Git 的 shell 提示包。该特定包注意到您正处于合并中间,可能是由于冲突而暂停的合并。当您调用 git merge
时,git pull
将为您调用 git merge
,这也算作您调用 git merge
-Git 尝试合并工作。 Git 并不总是能够自己做到这一点。
当 Git 尝试将您的工作(您在分支上的提交)与其他人的工作(他们在其分支上的提交1)结合起来时,这可能会顺利进行,也可能不会。如果进展顺利,Git 通常会2 进行新的提交。但是,如果不是,则合并会在中间停止,并且那些提示设置的 shell 插件会插入 |MERGING
符号。
当合并确实像这样在中间停止时,Git 会在工作树中留下一团糟。3 你的工作是解决混乱并运行 git add
。在冲突文件上运行 git add
会告诉 Git 您已正确解决冲突。 Git 假设您知道自己在这里做什么,并将此时工作树副本中的任何内容作为正确的分辨率。
当你运行 git add .
时,你告诉 Git 扫描整个当前目录和子目录——可能是你的整个工作树——以及 git add
每个文件。所以这告诉 Git 你解决了所有的冲突。在你这样做之前,你不能进行新的提交,即使是 git stash
所做的那些。所以你的 git stash
工作是因为你运行了 git add .
。
如果你真的准备好了(已经解决了所有问题),你会做的 git stash pop
或 git stash apply
得到你想要的东西。如果没有,您仍然需要 git stash apply
或 git stash pop
步骤,但之后,您需要继续解决冲突:应用步骤将带回所有未解决的冲突标记部分。 Git 在这里帮不了你,因为你已经告诉 Git 你解决了所有问题,所以 Git 已经忘记了冲突是什么,并且会认为带有冲突标记的工作树文件是正确的解决方案(尽管几乎可以肯定不是)。您只需要仔细检查您计划提交的内容(使用 git diff
和/或 git diff --staged
找出答案)。
1Git 中的分支这个词有一个很大的问题:它至少表示两三个不同的东西,每次有人说或读这个词时,意思就会转换。另请参阅https://stackoverflow.com/q/25068543/1256452在这种情况下,“您的分支”和“他们的分支”可能具有相同的名称——例如,两者都可能被称为 master
——但是它们位于两个不同的存储库中,实际上是不同的分支,至少是“分支”一词的多种含义之一。这一切都非常令人困惑和不幸。
2git merge
命令有时不必进行任何实际的合并,然后不会进行新的提交,除非您强制它这样做。 Git 将此非实际合并操作称为快进合并,即使没有实际合并。这也是令人困惑和不幸的。
3你的工作树或工作树是你工作的地方。 Git 从某个提交中复制文件,使它们成为普通文件;但这些文件实际上不在 Git 中。然后,您处理/使用这些副本。当您准备好将它们用于新的提交时,运行 git add
以获取 Git 以扫描更新的文件并准备它们,然后运行 git commit
以提交扫描的结果,这些结果位于 Git的内部形式,而不是工作树中的文件。
还有一件事
尽管您可能还没有为此做好准备(并且可以在完成工作时忽略它),但您应该知道 git stash
实际上至少进行了两次提交。 git stash
进行的两次提交之一保存了 Git 的索引(也称为暂存区)。 git stash
的另一个提交保存了你的工作树。
然后,完成这两个提交后,git stash
运行 git reset --hard
。这就是删除你所有工作的原因:git stash save
或 git stash push
的 git reset --hard
步骤。4 通常 git reset --hard
具有相当大的破坏性,但事实上 git stash
首先进行了一些提交这没关系(或没关系)。
4这里的 save
和 push
动词之间的区别是历史性的:它们在 stash 的正常情况下都做同样的事情。然而,在 Git 2.9 左右,git stash
学会了“部分隐藏”。为此,Git 人必须创建一个新动词 push
,因为原来的动词 save
计划不周。默认的 git stash
操作是保存或推送操作,当您不使用带有 git stash push
的路径规范时,它会执行完全保存并因此完全重置。当您使用 pathspecs 时,这会将最终清除从 git reset --hard
更改为更具选择性的内容。
这个 git stash push
部分保存代码在早期有很多错误,所以我建议在 Git 2.17 之前不要使用它。好吧,我通常建议完全避免使用 git stash
,除非在一些非常有限的情况下,但我的意思是,如果你要使用 git stash push
并使用部分推送功能,在这些