Lets say I branch off master and make a branch called xo-wip
, make 30 commits and stage all the files/changes. Now I want to unstage every single edit I did in the xo-wip
branch but not get rid of it. How would I do that?
Currently I have to make a new branch off master say xo-wip-release
, and then git merge --squash xo-wip
into xo-wip-release
答案 0 :(得分:0)
要暂存文件,请使用git add
。要取消暂存文件,请使用git reset
。但是,直到您正确了解Git的 index ,这一切都无济于事。
这个问题似乎没有任何意义,这使我相信您可能对Git的索引有错误的认识。索引,也称为暂存区或有时称为 cache ,是一种有点隐蔽的数据结构,对于使用Git来说至关重要,但是对于许多Git来说解释不力文档,甚至是一些Git书籍。
您可能已经很熟悉提交和Git关于工作树的想法,但是让我们再次简要地回顾一下它们。 Git中的 commit 包含整个源代码(或您要进行版本控制的任何内容)的完整快照。每个提交都通过其哈希ID 进行唯一标识,这很丑陋:git log
打印提交ID,运行git log
时,您可能会看到,例如:
commit c05048d43925ab8edcb36663752c2b4541911231
Author: Junio C Hamano ...
除了保存源快照外,每个提交还保存上一个或父提交的哈希ID。 Git使用这些链接以反向方式将提交链接在一起,从 last 提交开始并向后工作。像master
或xo-wip
这样的分支名称只是保留了该分支中 last 提交的哈希ID。如果我们使用大写字母来表示较大的丑陋哈希ID,则可以得出这种情况:
I <-- master
/
...--G--H
\
J--K--L <-- xo-wip
此处,名称master
标识提交I
,名称xo-wip
标识提交L
。从L
开始,Git向后依次到K
,然后依次到J
和H
。从I
开始,Git向后退回到H
。 (因此,哪个分支是提交H
或H
之前的任何东西,例如G
,在吗?在Git中,它们同时在两个分支上。。与大多数其他版本控制系统相比,这是使Git彻底变得奇怪的几件事之一。)
由于每个提交都拥有每个文件的完整快照,因此您可能想知道Git如何避免用完所有磁盘空间。答案是,在 提交中存储的文件以特殊的,压缩的,仅Git的格式存储。而且,一旦存储在Git中,文件的每个版本都会被冻结(只读,永久保存),因此共享文件的相同版本的每次提交都可以重新使用压缩的,仅Git的冻结文件。
工作树只是Git将这些文件扩展为正常的日常形式的地方。这使您可以对它们进行操作,因此命名为“工作树”或“工作树”。 git checkout
选择一个提交-您说您想要的哪个提交,Git将该提交提取到您的工作树中。那么该提交就是您的当前提交。当前提交具有特殊名称@
或HEAD
。通常,Git将单词HEAD
附加到分支名称,然后@
是分支名称指向的提交:
I <-- master
/
...--G--H
\
J--K--L <-- xo-wip (HEAD)
当前提交-HEAD
或@
-现在是提交L
。
您还可以将没有存储在Git中的文件放入工作树中。这些文件是未跟踪的,如果文件未跟踪,Git通常会抱怨该文件,因此您可以将特定的未跟踪文件标记为忽略。 (您不能忽略跟踪的文件,只能忽略未跟踪的文件。)
上面的文字图片(和提交的字面图片)不包含称为索引或暂存区的任何内容。这是因为Git的索引至少在很大程度上是不可见的-您不能直接查看它。 1 实际上,一旦知道索引是什么,您就可以想知道为什么Git有一个。其他版本控制系统无处可逃。不过,Git拥有它,并且(如果有任何意义)将其隐喻地推到您的脸上,同时将其隐藏起来。 :-)您必须使用它。
关于索引是的最简单的解释是,它是您构建下一个提交的地方。它位于当前提交和工作树之间。它保存当前提交的每个文件 的副本,格式与Git在提交内部使用的特殊,仅Git的压缩格式相同。至关重要的是,与冻结的提交版本不同,文件的索引副本是可写。
1 您实际上可以使用git ls-files --stage
直接查看索引。但是,这在许多存储库中是不切实际的,因为它会找到每个文件 ,这不是我们关心的。
因此,当您git checkout master
或git checkout xo-lib
时,Git实际上是通过使用最新master
或xo-lib
提交的所有文件填充索引来开始的。换句话说,它会将文件的冻结副本存储到索引中。顺便说一句,它还填充了工作树,将冻结的副本扩展为可用的形式。完成此操作后,您的工作树将拥有所有可供使用的文件。
一旦您对工作树进行了更改,索引和工作树就会有所不同。这是您对文件进行暂存的时间,使用git add
。这一切都是将工作树版本复制到索引中。 Git将文件压缩为特殊的,仅Git的格式,并用新副本替换索引中的所有 。如果文件是全新文件(如果没有索引副本),则将文件放入索引。
如果文件的工作树版本与该文件的索引版本不同,则Git表示该文件不是暂存的。。如果工作树文件与索引版本匹配,但是索引版本与HEAD
版本不匹配,则Git表示该文件已被暂存以进行提交。 所有三个版本的文件可能会有所不同,在这种情况下,文件都已暂存和!不过,您不会用git add
来得到它,因为add
意味着将工作树版本复制到索引,然后它们将匹配。
git commit
的工作方式,包括冻结索引 Git速度的秘密在于,索引已准备好进行下一次提交。 git commit
命令只需要收集您的日志消息,然后冻结所有索引文件并将它们链接到新提交中。完成后,新的提交和索引匹配,因为新的提交是从 索引进行的。
新提交的父提交就是当时的提交。假设我们正在执行如上所述的提交L
,我们将进行新的提交M
:
...--L <-- xo-wip (HEAD)
\
M
,然后Git将更新当前的分支名称,在这种情况下,xo-wip
附加了HEAD
,因此它指向我们的新提交{{1} }:
M
由于...--L--M <-- xo-wip (HEAD)
是根据索引创建的,因此M
的冻结文件与索引匹配。根据定义,没有什么可以取消登台的,因为Git所谓的所有“登台”(某些文件的索引副本与冻结到M
的副本不同的所有内容)现在都冻结在当前提交L
中。 M
和L
匹配的所有其他文件也被冻结到M
中:它们只是共享的。索引已经准备好进行更多的工作和更多的提交。