--soft

--soft 参数更新引用指针并停止重置。
但是,它不会影响暂存索引和工作目录。

git reset --soft
git status
#On branch master
#Changes to be committed:
#(use "git reset HEAD ..." to unstage)
#modified: edited_file
git ls-files -s
#123126 32a252710639e5da6b515416fd779d0741e4561a 0 edited_file

软重置仅重置提交历史记录。
默认情况下,它以 HEAD 作为目标提交调用。
现在让我们创建一个新的提交来尝试使用非 HEAD 的目标提交来尝试 --soft:

git commit -m "add changes to edited_file"

现在我们的存储库有三个提交。
为了找到第一个,我们需要检查它的 ID,这可以通过查看 git log 的输出来完成。

git log
#commit 62e793f6941c7e0d4ad9a1345a175fe8f45cb9df
#Author: onitroad
#Date: Fri Nov 1 14:02:07 2019 -0800
#add changes to edited_file
#commit ab23324a6da9f0dec51ed16d3d8823f28e1a72a
#Author: onitroad
#Date: Fri Nov 1 11:31:58 2019 -0800
#change content of edited_file
#commit 780411da3b47117270c0e3a8d5dcfd11d28d04a4
#Author: onitroad
#Date: Thu Sep 31 18:40:29 2019 -0800
#initial commit

这是初始提交的 ID。
现在它将用作软复位的目标。
之前,我们需要检查存储库的当前状态:

git status && git ls-files -s
#On branch master
#nothing to commit, working tree clean
#123126 32a252710639e5da6b515416fd779d0741e4561a  0 edited_file

现在我们可以软重置第一次提交:

git reset --soft 780411da3b47117270c0e3a8d5dcfd11d28d04a4
git status && git ls-files -s
#On branch master
#Changes to be committed:
#(use "git reset HEAD ..." to unstage)
#modified: edited_file
#123126 32a252710639e5da6b515416fd779d0741e4561a  0 edited_file

在上面的示例中,我们进行了软重置,并调用了 git status 和 git ls-files 组合命令,输出存储库的状态。
git status 命令显示对edited_file 进行了一些更改,将它们突出显示为为下一次提交暂存的更改。
git ls-files 输入显示暂存索引保持不变并保留 SHA 32a252710639e5da6b515416fd779d0741e4561a。
让我们在 git log 的帮助下另外检查软重置后存储库的状态:

git log
#commit 780411da3b47117270c0e3a8d5dcfd11d28d04a4
#Author: onitroad
#Date: Thu Sep 31 18:40:29 2019 -0800
#initial commit

正如我们所看到的,上面的输出表明提交历史中的单个提交。
与所有 git reset 调用一样,首先 --soft 重置提交树。

与都反对 HEAD 的 --hard 和 --mixed 不同,软重置使提交树及时返回。

git工作目录

第一棵树是工作目录。
它代表计算机文件系统上的文件,可用于代码编辑器使更改生效。
工作目录被认为是检出项目的特定提交。
当项目被检出时,这意味着它的文件已经从 Git 存储库中解压出来的版本。

echo 'hello git reset' > edited_file
git status 
#On branch master 
#Changes not staged for commit: 
#(use "git add ..." to update what will be committed) 
#(use "git checkout -- ..." to discard changes in working directory) 
#modified: edited_file

主要选项

默认情况下, git reset 命令具有 --mixed 和 HEAD 的常量参数。
因此,调用 git reset 与调用 git reset --mixed HEAD 相同。
这里的 HEAD 是声明的提交。
我们可以使用任何 Git SHA-1 提交哈希代替它。

Git reset

例子

使用以下命令从暂存区中删除指定的文件,但不更改工作目录。
它将取消暂存文件而不覆盖更改:

git reset <file>

使用以下命令将暂存区重置为与上次提交相对应,但保持工作目录不变。
它将在不覆盖更改的情况下取消所有文件的暂存,使我们可以从头开始重建暂存快照:

git reset

使用以下内容重置暂存区和工作目录以对应于最后一次提交。
它也会取消暂存更改,覆盖工作目录中的所有更改:

git reset --hard

使用以下内容将分支提示及时移回提交,重置暂存区以匹配,但不接触工作目录:

git reset <commit>

使用以下将当前分支提示向后移动到 <commit> 并重置暂存区和工作目录以匹配:

git reset --hard <commit>

工作原理

乍一看,git reset 命令与 git checkout 有一些相似之处,因为它们都在 HEAD 上操作。

git checkout 命令只对 HEAD 引用指针进行操作,而 git reset 命令则传递 HEAD 引用指针和当前分支引用指针。
我们将通过下图更好地了解其行为:

此图展示了 master 分支上的提交顺序。
如我们所见,HEAD ref 和 master 分支 ref 目前指向 commit d。
我们将看到图像在 git checkout b 和 git reset b 的情况下如何变化。

git checkout b

在执行 git checkout 命令时,master ref 仍然指向 commit d。
HEAD ref 的内容,它已被移动并更改了指向提交 b 的指针。
因此,存储库现在处于“分离的 HEAD”状态。

git checkout b

git reset 命令将 HEAD 和分支引用切换到定义的提交。
此外,它改变了三棵树的状态。
有三个命令行参数--soft、--mixed 和--hard direct,用于定义临时索引和工作目录树的修改。

--mixed

操作模式默认为 --mixed。
它更新 ref 指针。
暂存索引被重置为指定的提交。
暂存索引中撤消的更改放置在工作目录中。

echo 'new file content' > test_file
git add test_file
echo 'append content' >> edited_file
git add edited_file
git status
#On branch master
#Changes to be committed:
#(use "git reset HEAD ..." to unstage)
#new file: test_file
#modified: edited_file
git ls-files -s
#123126 6a32154a5477b1bf4765946147c49509a4323d32 0 test_file
#123126 3c3262db063f9e9426901092c00a3394b4bd3445 0 edited_file

在上面的例子中,添加了一个 test_file 并且修改了edited_file 的内容。
接下来,这些更改将在 git status 的帮助下应用于暂存索引。
有了这个存储库的状态,现在是时候调用 git reset 了。

git reset --mixed
git status
#On branch master
#Changes not staged for commit:
#(use "git add ..." to update what will be committed)
#(use "git checkout -- ..." to discard changes in working directory)
#modified: edited_file
#Untracked files:
#(use "git add ..." to include in what will be committed)
#test_file
#no changes added to commit (use "git add" and/or "git commit -a")
git ls-files -s
#123126 6c423c1b04b5edd5acfc85de0b592449e5303773 0 edited_file

--mixed 是默认模式。
它与 git reset 具有相同的效果。
git status 显示edited_file 有更改,并且test_file 是未跟踪的文件。
这是确切的混合行为。
暂存索引已重置,挂起的更改已移动到工作目录。

公共历史重置的不可接受性

不要使用 git reset <commit>,当 <commit> 之后有快照时,将其移动到公共存储库。
当我们发布提交时,请考虑其他开发人员也依赖它的事实。
删除其他团队成员正在开发的提交也会导致很多问题。
仅对本地更改使用 git reset <commit>。
要修复公共更改,请使用 git revert 命令。

git取消暂存文件

git reset 命令通常用于制作分阶段快照。
在下面的示例中,我们有 2 个文件,名为 task.txt 和 index.txt。
已添加到存储库中。
Git reset 让我们可以取消与下一次提交无关的更改。

# Edit task.txt and index.txt
# Stage everything in the current directory
git add .
# Realize that the changes in task.txt and index.txt
# should be committed in different snapshots
# Unstage index.txt
git reset common.txt
# Commit only task.txt
git commit -m "Edit task.txt"
# Commit index.txt in a separate snapshot
git add index.txt
git commit -m "Edit index.txt"

--hard

最常用的选项是--hard。
然而,使用它有一些风险。
使用 --hard,提交历史引用指针开始指向声明的提交。
之后,暂存索引和工作目录被重置为对应于声明的提交。
先前挂起对暂存索引和工作目录的更改将重置以匹配提交树状态。
暂存索引和工作目录中的任何挂起提交都将丢失。
下面的示例将演示上述内容。
首先,执行以下命令:

echo 'test content' > test_file
git add test_file
echo 'modified content' >> edited_file

已创建名为 test_file 的新文件并将其添加到存储库中。
此外,edited_file 的内容将被修改。
现在让我们使用 git status 命令检查具有这些更改的存储库状态。

git status
#On branch master
#Changes to be committed:
#(use "git reset HEAD ..." to unstage)
#new file: test_file
#Changes not staged for commit:
#(use "git add ..." to update what will be committed)
#(use "git checkout -- ..." to discard changes in working directory)
#modified: edited_file

如我们所见,现在有一些待处理的更改。
暂存索引树的待定更改是添加 test_file,而工作目录的更改是对edited_file 的修改。
现在让我们看看暂存索引的状态:

git ls-files -s
#123126 7a32454a5477b1bf4765946147c49509a431f963 0 test_file
#123126 6c423c1b04b5edd5acfc85de0b592449e5303773 0 edited_file

test_file 已添加到索引中。
edited_file 已更新,但暂存索引 SHA (d7d77c1b04b5edd5acfc85de0b592449e5303770) 保持不变。
这些更改位于工作目录中。
因为我们没有使用 git add 命令,所以它们不会被提升到暂存索引。

此时,我们可以执行 git reset --hard 并查看 repo 的新状态:

git reset --hard
#HEAD is now at ab23324 update content of edited_file
git status
#On branch master
#nothing to commit, working tree clean
git ls-files -s
#123126 6c423c1b04b5edd5acfc85de0b592449e5303773 0 edited_file

--hard 选项执行了“硬重置”。
Git 表明 HEAD 指向最近的提交 ab23324.
然后,使用 git status 检查 repo 的状态。
Git 表示没有挂起的更改。
暂存索引的状态是什么,在添加 test_file 之前已经重置为一个点。
edited_file 更改和 test_file 的添加已被删除。
这种损失无法挽回。

git提交历史

最后一棵树是提交历史。
git commit 命令将更改提交到临时索引的永久快照。

git commit -am "edit content of test_file"
#[master ab23324] edit the content of edited_file
#1 file changed, 1 insertion(+)
git status
#On branch master
#nothing to commit, working tree clean

在上面的示例中,我们可以看到带有消息“edit content of test_file”的新提交。
更改添加到提交历史记录中。
在此阶段,运行 git status 显示任何树都没有即将发生的更改。

调用 git log ,我们将看到提交历史记录。

一旦通过三棵树进行更改,就可以使用 git reset 了。

Git 重置和三棵树

git reset 命令是一个用于撤消更改的工具。
它具有三种调用形式,与 Git 的三个内部状态管理系统相匹配,称为 Git 的三棵树。
这些系统包括 HEAD(提交历史)、暂存索引和工作目录。
我们将研究这些系统中的每一个。

git删除本地提交

如上所述,我们可以使用 git reset 命令删除本地存储库上的提交。
下面的示例演示了 git reset 的这种用法。
git reset HEAD~2 命令通过另外两个提交将当前分支向后推送,并从项目历史记录中删除最近创建的两个快照。

# Create a new file called `yourname.txt` and add some code to it
# Commit it to the project history
git add yourname.txt
git commit -m "Start to develop a project"
# Edit `yourname.txt` again and change some other tracked files, too
# Commit another snapshot
git commit -a -m "Continue developing"
# Scrap the project and remove the related commits
git reset --hard HEAD~2

reset 和 revert 命令的区别

Git revert 被认为是比 git reset 更安全的撤消更改方式。

工作很可能会因重置而丢失。
Git 重置不会删除提交,但它可以使提交“孤立”。
这意味着,没有任何直接的方法可以访问它们。
因此,当 Git 运行内部垃圾收集器时,它会删除所有孤立的提交。
默认情况下,Git 每 30 天运行一次内部垃圾收集器。
孤立的提交通常在 git reflog 命令的帮助下找到。

这两个命令的另一个区别是 git revert 配置为撤消公共提交,而 git reset 配置为撤消对工作目录和暂存索引的本地更改。

git暂存索引(Staging index)

下面的树是暂存索引,它跟踪在工作目录中提交的更改。
通常,Git 对用户隐藏暂存区的性能细节。
有时,在谈论暂存区时,会使用不同的表达方式,例如缓存、目录缓存、暂存文件、暂存区等。

这里我们需要 git ls-files。
命令,它被认为是一个调试工具,用于检查暂存索引的状态。

git ls-files -s
#543644 a32de29bb3c1d643328b29ae775ad8c2e48c3256 0 edited_file
日期:2020-06-02 22:16:34 来源:oir作者:oir