你的方法是完全错误的。您正在修改您不想修改的内容:您当前的分支(大概是master)。
一个简单的线性 git 存储库是一个这样的提交链
*---A---*---*---B---*---*---C
^ ^
| |
master origin/master
^
|
HEAD
这是您调用git fetch 后存储库的状态。请注意,包含所有中间步骤的整个历史记录都在您的本地硬盘上。只是你只有提交时的状态A 签出(HEAD 指向master 指向A),所以你看到的文件属于那个状态。
现在,如果您只想查看以B 提交的状态,您可以使用git checkout B 查看该提交。这会将您看到的文件更新为B 的状态,并将HEAD 指向该提交:
*---A---*---*---B---*---*---C
^ ^ ^
| | |
master HEAD origin/master
HEAD 始终引用git 认为您所在的提交/分支,并且当您调用git status 时它将与您的工作目录进行比较。
如果您只想查看该提交,简单的git checkout B 就足够了。如果您确实想要做出您提交并想要保留的更改,您应该引入一个新分支来记录这些更改。这是通过在git checkout B 之后的简单git checkout -b newBranch 实现的。这会给你状态
*---A---*---*---B---*---*---C
^ ^ ^
| | |
master newBranch origin/master
^
|
HEAD
这只是为提交B 提供了一个名称,而不是它的哈希值。在更多提交之后,您的状态将如下所示:
*---A---*---*---B---*---*---C
^ | ^
| | |
master \ origin/master
\
*---*---D
^
|
newBranch
^
|
HEAD
关键是,在使用git checkout ... 签出其他分支/提交后,您始终可以通过调用git checkout newBranch 轻松返回到提交D,并且永久引用停止git 垃圾收集提交D.
现在,为什么使用 git reset --hard 不好?首先,它会破坏您尚未提交的所有本地更改,恕不另行通知。其次,如果您不小心,它可能会丢失您的历史记录。
例如,假设您在上次推送到上游存储库后进行了一些更改,并想查看一些历史提交 B。 (与您的问题中的情况有些相反。)历史看起来像这样:
*---A---*---*---B---*---*---C
^ ^
| |
origin/master master
^
|
HEAD
使用git reset --hard B,你会得到这个状态:
*---A---*---*---B-(-*---*---C )
^ ^
| |
origin/master master
^
|
HEAD
括号中的提交不再被任何分支直接或间接引用,并且可能随时被垃圾收集。 git 对垃圾收集可能不是很激进,但如果它在你处于这种状态时进行垃圾收集,你将无法获得提交 C,它将永远丢失。您不希望这种情况发生,因此养成轻率使用git reset --hard 的习惯并不是一个好主意。
如果您改用git checkout,分支master 仍将指向C,您仍然可以使用简单的git checkout master 回到它。