Rollback commit of a single file git reset
我在终端上使用Git。我在一个文件夹中有几个HTML文件。我使用git init创建了一个存储库。
我使用以下方法将index.html添加到临时区域:
1 | git add index.html |
现在,我要从临时区域中删除index.html。我尝试了git reset--head index.html等,但似乎没有任何东西可以将文件从临时区域中取出。
我只想从临时区域中删除index.html文件。
这是运行git reset head后的输出。如您所见,index.html丢失了。
1 2 3 4 5 6 7 8 9 10 | On branch master Untracked files: (use"git add <file>..." to include in what will be committed) landscape.css max-640px.css min-640px.css portrait.css result.html styles.css |
号
这里是git日志输出:
1 2 3 4 | $ git log commit d70e697ed08fbe6709ba3f13d202bade793e7b1a Author: johnson Date: Tue May 30 19:36:12 2017 -0500 |
在我开始之前,让我们先说明第一次提交是特殊的。原因是,在进行第一次提交之前,没有当前提交。出于Git自身的内部目的,Git有时会假装当前提交确实存在,而且它确实是空的:它根本没有文件。(事实上,在每个存储库中都有一个特殊的半秘密Git,仅用于此目的。)好的。
临时区域1位于当前提交(head)和工作树之间:好的。
1 2 3 4 5 | current commit: staging area: work-tree: file1 file1 file1 file2 file2 file2 ... ... ... fileN fileN fileN |
临时区域(总是)保存将进入下一次提交的所有文件。如果您有一个当前提交(您做了/做了);您将其显示在上面,那么临时区域将开始充满该提交中的所有文件。(工作树也是如此:正如您所见,每个文件都有三份副本!通常,其中两个当前提交和临时区域副本被秘密压缩和/或秘密共享。Git可以这样做,因为这两个副本都在Git的控制之下。只有工作树副本才具有您计算机上任何文件的正常格式;Git不能将这些文件保持为花哨、压缩和消除重复的格式。)好的。
换句话说,只要您有一个当前的(
(注:
运行
因为
1 | git rm --cached index.html |
号
现在集结区没有
1 2 3 4 | current commit: staging area: work-tree: foo.css foo.css foo.css index.html --- index.html README README README |
这不是您使用
1仅因为它是Git,临时区域还有两个名称:它也被称为缓存,最常见的是索引。当然,名称索引与
2这是
如果您使用
Git的提交实际上并不存储更改,而是存储快照。既然您有两个提交,那么
1 2 3 4 5 6 7 8 9 10 11 12 | $ mkdir tt $ cd tt $ git init Initialized empty Git repository in ... $ echo test revert of first commit > README $ echo la la la > file $ git add README file $ git commit -m initial [master (root-commit) 2cff9aa] initial 2 files changed, 2 insertions(+) create mode 100644 README create mode 100644 file |
号
到目前为止,还不错:我们有一个初始提交,它(与初始提交之前的空白相比)添加了所有文件。好的。
1 2 3 4 5 6 | $ git revert HEAD [editor session, snipped] [master 92f4eea] Revert"initial" 2 files changed, 2 deletions(-) delete mode 100644 README delete mode 100644 file |
还原将撤消初始提交的效果,因此它将删除所有文件。Git将"上一次提交"与"当前提交"进行比较,发现删除了
1 2 | $ ls $ |
。
工作树现在是空的。所有文件都不见了!这是因为我们已经恢复了它们。好的。
不过别担心!所有的文件都还在那里!他们在第一次交涉中。我们只需要把它们拿回来。现在我们来做:好的。
1 2 3 | $ git log --all --decorate --oneline --graph * 92f4eea (HEAD -> master) Revert"initial" * 2cff9aa initial |
(只有
我们需要从第一次提交(
1 2 3 | $ git checkout 2cff9aa -- . $ ls README file |
。
有一个好处是:两个文件现在都在临时区域,因此将进入下一个提交:好的。
1 2 3 4 5 6 7 8 | $ git status git status On branch master Changes to be committed: (use"git reset HEAD <file>..." to unstage) new file: README new file: file |
。
(发生这种情况是因为
我们想去掉其中一个(在本例中是
现在让我们重置(或
1 2 3 4 5 6 | $ git reset file $ git status --short A README ?? file $ ls README file |
1 2 3 4 5 6 7 8 | $ git commit -m 'this should have been the first commit' [master 0945e1d] this should have been the first commit 1 file changed, 1 insertion(+) create mode 100644 README $ git log --oneline 0945e1d (HEAD -> master) this should have been the first commit 92f4eea Revert"initial" 2cff9aa initial |
号
现在这里有一个问题,也许最好用插图来说明。注意,我们的文件
1 2 3 4 5 | $ git checkout 2cff9aa error: The following untracked working tree files would be overwritten by checkout: file Please move or remove them before you switch branches. Aborting |
假设我们确实设法签出了该提交,例如,使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $ git checkout --force 2cff9aa Note: checking out '2cff9aa'. 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 2cff9aa... initial $ ls README file |
。
现在让我们回到
1 2 3 4 5 | $ git checkout master Previous HEAD position was 2cff9aa... initial Switched to branch 'master' $ ls README |
等等,我们叫
这就是我们创建的陷阱:有一个commit,
这是不可能的。如果该文件处于提交状态,则签出时它将进入临时区域(和工作树)。然后,当您将该提交移到没有该文件的提交时,它将被删除(从这两个相同的位置)。好的。
正如我们上面看到的,Git会在您将要进入该提交时警告您。这会给您一个保存数据的机会。您需要知道必须这样做(保存数据),或者避免签出特定的提交。好的。
唯一的另一个选择是重写您的存储库以完全消除提交。在大多数情况下,大多数存储库中都有大量的历史,也许还有许多克隆,等等,这些都不值得。在一个只有一次提交的新存储库中,这可能是值得的!好的。好啊。