文件在git中消失/重新出现

文件在git中消失/重新出现,git,Git,我参加了下面提到的git课程。如您所见,当我回到主分支的负责人那里时,git报告说文件y.y已被删除。这已通过ls确认。但是,当我签出之前的提交并返回到master时,文件又出现了 我对git完全是一个初学者,但我一辈子都不明白为什么git checkout master在仅用只读命令分隔时会给出两个不同的结果 rwilson@855:~/ht$ git log --oneline f065234 add y.y 04a7340 2nd commit b6ca522 init commit rw

我参加了下面提到的git课程。如您所见,当我回到主分支的负责人那里时,git报告说文件
y.y
已被删除。这已通过
ls
确认。但是,当我签出之前的提交并返回到
master
时,文件又出现了

我对
git
完全是一个初学者,但我一辈子都不明白为什么
git checkout master
在仅用只读命令分隔时会给出两个不同的结果

rwilson@855:~/ht$ git log --oneline
f065234 add y.y
04a7340 2nd commit
b6ca522 init commit
rwilson@855:~/ht$ git checkout master
D   y.y
Switched to branch 'master'
rwilson@855:~/ht$ ls
x.x  x.y
rwilson@855:~/ht$ git checkout HEAD~1
Note: checking out 'HEAD~1'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at 04a7340... 2nd commit
rwilson@855:~/ht$ ls
x.x  x.y
rwilson@855:~/ht$ git checkout HEAD~1
Previous HEAD position was 04a7340... 2nd commit
HEAD is now at b6ca522... init commit
rwilson@855:~/ht$ ls
x.x
rwilson@855:~/ht$ git checkout master
Previous HEAD position was b6ca522... init commit
Switched to branch 'master'
rwilson@855:~/ht$ ls
x.x  x.y  y.y
这是因为:

  • 当您签出
    HEAD~1
    时,
    y.y
    就在那里
  • 但是,当您再次签出
    master HEAD
    时,
    y.y
    现在被认为是
    HEAD
    中未跟踪的文件:
    • 因为
      y.y
      在工作树中(因为
      HEAD~
    • 由于更新所述工作树时,
      master HEAD
      不必触摸
      y.y
这意味着
y.y
在第二次签出
HEAD
时仍然存在


第二次之后,git签出主机可能会有所帮助。

我猜有一点,但最初我相信您在提交时处于“分离头”模式
f065234
,这是分支名称
master
指向的提交。因此,
git log--oneline
向您展示了commit及其两个祖先

无论出于何种原因,在提交时,您(或您所做的事情)删除了文件
y.y

首先,让我们进入那种状态

$ cd /tmp; mkdir repo; cd repo
$ git init
Initialized empty Git repository in /tmp/repo/.git/
$ echo 'first file x.x' > x.x
$ git add x.x
$ git commit -m 'init commit'
[master (root-commit) 63ddf00] init commit
 1 file changed, 1 insertion(+)
 create mode 100644 x.x
$ echo 'second file x.y' > x.y
$ git add x.y
$ git commit -m '2nd commit'
[master 62cb693] 2nd commit
 1 file changed, 1 insertion(+)
 create mode 100644 x.y
$ echo 'third file y.y' > y.y
$ git add y.y
$ git commit -m 'add y.y'
[master b4c61d1] add y.y
 1 file changed, 1 insertion(+)
 create mode 100644 y.y
$ 
现在我们只需要“分离头部”:

接下来,我们删除
y.y
,并要求git切换到分支
master
。我们将看到文件
y.y
D
状态,正如您所做的那样:

$ rm y.y
$ git checkout master
D   y.y
Switched to branch 'master'
$ 
我执行上面的“detach HEAD”步骤的原因是,如果没有,我将获得稍微不同的输出。我现在可以通过重复
git checkout master
命令向您展示这一点:

$ git checkout master
D   y.y
Already on 'master'
$ 
不过,在这两种情况下,这里的问题是git已经达到了您要求的提交。因此,它根本不必接触工作目录,因此它不会

但还有别的事情发生了!事实上,这是我的
rmy.y
命令。我删除了文件。Git可以看到文件丢失了,所以它用
D
行宣布这一点

接下来,您要求git签出上一次提交(
HEAD~1
aka
master~1
,在您的存储库中是commit
04a7340
,我的存储库是
62cb693
,如上面的
git commit
输出所示,因为我不是您,我的文件可能包含不同的数据,等等:我的存储库不同,这使得我的所有SHA-1都不同)

要切换到该提交,git必须删除文件
y.y
:该文件位于提交
f065234
中,而不是提交
04a7340
。该文件已经丢失,这使得git的工作非常简单:它不做任何操作即可“删除”不存在的文件

从这一点开始,如果你让git签出commit
master
——也就是说,commit
f065234
——git必须将文件
y.y
放入你的工作目录中。你只需额外几个步骤(首先签出
b6ca522
,它也缺少
y.y
,然后才签出
f065234
)但是你到了那里,这意味着git从底层存储库中重新提取了
y.y
,将它放在你的工作目录中


注意:这里要小心,
git checkout
有一种不同的使用模式,可以很容易地删除工作。
这种模式在文档中拼写为
git checkout commit--path
,例如,
git checkout HEAD--x.x
。不幸的是,(在我看来)太容易意外调用此其他使用模式。下一节仅介绍
git checkout commit
,而不是
git checkout commit--path
。在此之后,我将插入一个关于
path
版本的简短部分


作为一般规则,无论您是通过分离还是通过分支名称提交SHA-1,git在要求它签出另一个提交时所做的是通过比较两个提交来查看需要在工作目录中添加、删除或修改哪些文件。(如果两次提交相同,结果很简单:无需更改任何文件。请仔细考虑下面的第一条评论:如果您已经在
1234567
上,并且您
git checkout 1234567
,则无需更改任何文件,因此
git checkout
只需执行
git status

任何不需要任何更改的工作目录文件,git都可以单独使用

对于任何确实需要以某种方式更改的文件,git会检查您是否会丢失工作。丢失工作的一些明显方式包括(还有更多,但我只列出这些):

  • git必须删除该文件,但您已经对其进行了编辑(它与当前提交不匹配,更不用说目标提交了,即删除它)
  • git必须用其他版本替换该文件,但您已对其进行了编辑
  • git必须创建该文件(它在目标提交中,但不是当前提交),但是您自己创建了它,其内容与git将放入的内容不同
在这些情况下,
git checkout
将因错误而停止,除非您给它设置了
--force
标志

但是,在许多情况下,许多工作目录文件都不需要更改。例如,在上述情况下,我可以从
master
切换到
master~1
master~2
,而不更改文件
x.x
:这三个版本都是相同的

这意味着git将允许我修改
x.x
,甚至完全删除它,并且仍然检查其他提交:从
master切换
$ git checkout master
D   y.y
Already on 'master'
$ 
git checkout HEAD -- x.x x.y
git checkout -- x.x
git checkout x.x
git checkout .