本文演示了下列命令的常见使用方式:
git clean
git checkout
git reset
1. git clean
清除工作区所有未纳入版本管理的目录、文件。
git clean -f
:强制清除工作区根目录下未纳入版本管理的文件。
git clean -d -f
:强制清除未纳入版本管理的目录和文件,会从根目录递归所有子目录。
2. git checkout
git checkout
:撤销工作区指定文件的修改。用该文件暂存区的快照替换(如果该文件是untracked的,此命令不会处理)。
git checkout HEAD
:撤销指定文件在工作区和暂存区的所有修改,用版本库最近一次提交的版本来替换。
以gitsample的README.md文件为例。当前此文件的内容:
# gitsample
This line is the first time modified.
This line is the second time modified.
我们在文件中新加入一行文字,内容变成:
# gitsample
This line is the first time modified.
This line is the second time modified.
demo for checkout file.
此时在Git bash命令行中使用git diff
比较下工作区和暂存区文件的差异:
$ git diff
diff --git a/README.md b/README.md
index 8d42e6b..cde90e6 100644
--- a/README.md
+++ b/README.md
@@ -2,4 +2,6 @@
This line is the first time modified.
-This line is the second time modified.
\ No newline at end of file
+This line is the second time modified.
+
+demo for checkout.
\ No newline at end of file
接下来撤销工作区的修改:
$ git checkout README.md
再来查看差异:
$ git diff
工作区和暂存区没有差异了,README.md文件也变回最初的内容,刚才对工作区README.md文件的操作成功的被撤回了。
3. git reset
git reset HEAD [--]
:撤销指定路径在暂存区的尚未提交到版本库的内容。如果指定的路径从未提交到版本库,那么就直接将该路径从暂存区撤销;否则会用该路径在版本库中最近一次的提交来覆盖该路径的暂存区。
git reset --soft [
:撤销版本库到指定的commit id。可以用HEAD来代替commit id:HEAD^代表回撤最近一次的提交(和HEAD~1等效),HEAD^^表示回撤最近两次(和HEAD~2等效),以此类推;
git reset --mixed [
:撤销版本库提交和暂存区到指定的commit id。--mixed是默认参数,git reset --mixed HEAD^
和git reset HEAD^
等效;
git reset --hard [
:撤销版本库、暂存区和工作区到指定的commit id。注意:此命令会直接撤销工作区的修改,这个操作是不可逆的!使用之前最好用git status来比较下确认工作区的修改可以放弃。
我们先在gitsample仓库中准备一下数据:
在文件夹内新建一个demo_reset.txt文件;
在文件内增加一行“Rev. 1”保存、在Git bash中运行git add .
、git commit -m "demo reset Rev. 1"
将文件提交到版本库;
在文件内增加一行“Rev. 2”保存、git add .
、git commit -m "demo reset Rev. 2"
将文件提交到版本库;
在文件内增加一行“Rev. 3”保存、git add .
、git commit -m "demo reset Rev. 3"
将文件提交到版本库。
然后再文件内增加一行文字“Rev. 4”、然后git add .
添加到暂存区。此时使用git diff demo_reset.txt
查看状态:
$ git diff demo_reset.txt
从diff信息可以看到工作区的文件和暂存区的比较起来没有不同。此时回撤暂存区的操作:
$ git reset HEAD demo_reset.txt
然后再执行git diff
查看:
$ git diff demo_reset.txt
diff --git a/demo_reset.txt b/demo_reset.txt
index 9820ed9..22aeec4 100644
--- a/demo_reset.txt
+++ b/demo_reset.txt
@@ -1,3 +1,4 @@
Rev. 1
Rev. 2
-Rev. 3
\ No newline at end of file
+Rev. 3
+Rev. 4
\ No newline at end of file
从diff的结果来看暂存区的内容已经回撤了,和工作区的文件已经不一样了。
接下来通过练习看下下git reset --hard [
的效果:
$ git reset --hard HEAD^
HEAD is now at 97bd7c9 demo reset Rev. 2
命令的返回信息提示版本库已经回撤到“demo reset Rev. 2”这一次的提交了,看下git status的结果:
$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
工作区和暂存区、暂存区和版本库都是一致的。说明暂存区和工作区的操作也都回撤了。用记事本打开文件会发现内容也只有Rev. 1和Rev. 2两行了。
接下来在Git bash中运行$ git reset --soft HEAD^
,然后用git status
看下效果:
$ git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
Changes to be committed:
(use "git reset HEAD ..." to unstage)
modified: demo_reset.txt
可以看到,暂存区的demo_reset.txt有待提交的内容了。此时暂存区和工作区的文件内容都有Rev.1和Rev.2,而版本库已经回撤到Rev. 1这个版本了。如果现在又想将版本库回到最初的提交(或者过程中的某次提交),应该怎么办呢?还是使用reset命令,只要直到目的版本的commit id就能够返回。可以通过git log --reflog -3
(只返回最近3次的提交操作)查看commit id:
$ git log --reflog -3 --pretty=oneline
df531846649c39baa68784ee40c907dd58e5c7da demo reset Rev. 3
97bd7c98ec0c0c8944dbd22c0711770564a7a762 demo reset Rev. 2
02e093b6513651c0e6e41d0710280a14e30b1d7c (HEAD -> master) demo reset Rev. 1
可以看到Rev. 3版本的commit id是df531846649c39baa68784ee40c907dd58e5c7da
。现在将版本库的提交返回到这里:
$ git reset --hard df5318
HEAD is now at df53184 demo reset Rev. 3
从返回的结果可以看到,版本库的最近一次提交已经返回到Rev. 3了。
4. git commit --amend
有时候我们提交完了才发现有几个文件应该一起提交但是忘记添加,或者有的文件不应该提交,又或者提交的信息写的有问题。此时想修正这个问题,不想将原本应该在一起提交的变成两次提交,可以使用git commit -amend
命令。
先要将需要一起提交的文件加入到暂存区,将不应该提交的文件撤回到原先的状态。然后在Git bash中运行命令:
git commit --amend
命令运行后会启动文本编辑器,提示修改commit message:
demo reset Rev. 3
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Mon Aug 19 00:04:47 2019 +0800
#
# On branch master
# Your branch is ahead of 'origin/master' by 3 commits.
# (use "git push" to publish your local commits)
#
# Changes to be committed:
# modified: demo_reset.txt
#
将原来的message”demo reset Rev. 3“修改为“demo reset Rev. 3 --amend”。然后退出文本编辑器。
$ git commit --amend
hint: Waiting for your editor to close the file...
[main 2019-08-18T16:40:46.426Z] update#setState idle
[master ca497af] demo reset Rev. 3 --amend
Date: Mon Aug 19 00:04:47 2019 +0800
1 file changed, 2 insertions(+), 1 deletion(-)
从命令行返回结果可以看到,提交已经覆盖。我们再用git log --reflog
验证下:
$ git log --reflog -3 --pretty=oneline
ca497afbba7b6eaefea0d96827875ddae4cb0791 (HEAD -> master) demo reset Rev. 3 --amend
df531846649c39baa68784ee40c907dd58e5c7da demo reset Rev. 3
97bd7c98ec0c0c8944dbd22c0711770564a7a762 demo reset Rev. 2
对比下之前的log:
$ git log --reflog -3 --pretty=oneline
df531846649c39baa68784ee40c907dd58e5c7da demo reset Rev. 3
97bd7c98ec0c0c8944dbd22c0711770564a7a762 demo reset Rev. 2
02e093b6513651c0e6e41d0710280a14e30b1d7c (HEAD -> master) demo reset Rev. 1
可以明显的看到,git commit --amend
命令运行后,并没有新增一条提交操作,而是覆盖了最近一次的提交:commit id和message都被替换了。
需要注意的是git commit --amend
命令会改变最近一次提交的commit id,所以当最近一次的提价已经推送到远程仓库之后,要特别谨慎的使用这个命令,否则容易引起同其它开发人员的版本冲突。