git的工作区和暂存区
先说下这两个概念:
工作区,就是你git仓库的目录,你进行修改文件的区域。
暂存区,git从库里面有个.git的隐藏目录,里面”有一块”,可以理解为暂存区。
工作区和缓存区如何联系起来?通过提交代码行为的步骤流程来解读:
- 修改代码文件
git add 修改后的代码文件
此刻的行为将该代码文件从工作区添加到了暂存区git commit -m 'commit 内容'
此刻的行为把暂存区的内容提交到了本地分支上
最后的git push
操作只是一个将本地分支推送到远端的行为,所以先不考虑进去,只考前面三点。
查看工作区和暂存区常用的命令为git status
一般常见的是如下三种情况:
- 在工作区新建了文件或目录,但还未将这些文件或目录
git add
提交到暂存区。这些文件或目录被标记为untracked files。
1 | huangyisan:~/Desktop/github/test $ touch foo bar |
- 对修改后的文件进行了
git add
操作,将这些文件提交到了暂存区,但未执行git commit -m 'xxx'
,未提交到本地分支。此时文件属于Changes to be committed
状态
1 | huangyisan:~/Desktop/github/test $ git add foo |
- 对已经
git add
操作,但未提交到本地分支的文件,继续进行了修改,修改完后未进行git add
,此时文件属于Changes not staged for commit
状态1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19huangyisan:~/Desktop/github/test $ echo 'new line' >> foo
huangyisan:~/Desktop/github/test $ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: foo
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: foo
Untracked files:
(use "git add <file>..." to include in what will be committed)
bar - 已经commit到本地分支的文件,且该文件在工作区没被修改之前,其不会在git status中出现。
git checkout – file
两种情况
若被checkout的文件在暂存区,但工作区修改了,也就是上面的第三种情况,此时执行该命令,被checkout的文件变成和暂存区一样的状态和内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31huangyisan:~/Desktop/github/test $ echo 'first line' > foo
huangyisan:~/Desktop/github/test $ git add foo
huangyisan:~/Desktop/github/test $ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: foo
huangyisan:~/Desktop/github/test $ cat foo
first line
huangyisan:~/Desktop/github/test $ echo 'new line' >> foo
huangyisan:~/Desktop/github/test $ cat foo
first line
new line
huangyisan:~/Desktop/github/test $ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: foo
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: foo
huangyisan:~/Desktop/github/test $ git checkout -- foo
huangyisan:~/Desktop/github/test $ cat foo
first line将foo文件写入’first line’内容后,用
git add foo
,提交到了暂存区,未commit情况下,再写入新内容’new line’,若想还原到暂存区状态,则使用命令git checkout -- foo
被修改文件不在暂存区,此时使用
git checkout -- file
命令,则该文件和当前版本仓库中原先的文件一致。1
2
3
4
5
6
7
8
9
10
11
12huangyisan:~/Desktop/github/test $ git status
On branch master
nothing to commit, working tree clean
huangyisan:~/Desktop/github/test $ cat foo
first line
huangyisan:~/Desktop/github/test $ echo 'new line' >> foo
huangyisan:~/Desktop/github/test $ cat foo
first line
new line
huangyisan:~/Desktop/github/test $ git checkout -- foo
huangyisan:~/Desktop/github/test $ cat foo
first line干净的工作区,修改了foo文件,然后进行checkout操作之后,foo文件还原成了仓库中该文件原先的状态和内容。
git clean
git clean 的对象为untracked files,也就是在工作区新建,但还未执行git add
命令提交到暂存区的文件或目录。
1 | huangyisan:~/Desktop test $ ls |
git clean -n
,干跑模式,可以列出哪些文件会被清除,但不会列出哪些目录会被清除。git clean -f
,若指定文件,则该文件被清除,若不指定文件,则所有未被提交到暂存区的文件都被清除。git clean -df
,若指定目录,则该目录被清除,若不指定目录,则所有未被提交到暂存区的目录都被清除。
git rm
git rm
等价于rm xxx && git add .
。
如果一个文件是被rm删除,则可以使用git checkout -- file
将文件还原回来,而如果是用git rm
删除,则该文件不可以被git checkout -- file
。当然,如果是rm文件,然后git add操作,也是不能被git checkout -- file
还原回来的。
1 | huangyisan:~/Desktop/github/test $ ls |
foo文件起先被rm删除,并未提交到暂存区,所以是可以被checkout还原,后来执行了git rm,所以当使用checkout还原的时候就报错了。
git reset
三种模式
- –mixed 默认方式,将暂存区内容清空,回退到工作区,并且保留工作区的修改内容。
1 | huangyisan:~/Desktop/github/test $ cat foo |
暂存区被清空,工作区的更变被保留下来,foo文件存在new line这行内容。
- –soft 暂存区内容,工作区内容都被保留,HEAD指向指定的commit号,该commit号原先的文件若有变动,则直接被add到暂存区。
1 | huangyisan:~/Desktop/github/test $ ls |
将foo的改动add到暂存区后,使用git reset --soft 8f89d40
,8f89d40这个commit号原先是存在bar这个文件,且foo文件不存在,因为reset之前的内容和之后的比较出现了差异,则这些差异被add到了新的暂存区中。
- –hard HEAD重置到指定commit号,且清空暂存区,工作区的内容和该commit号版本仓库的内容一致。
1 | huangyisan:~/Desktop/github/test $ git reset --hard HEAD |
暂存区被清空,工作区内容成了当前commit号版本仓库的内容,也就是没修改之前的内容,foo文件不存在new line行。
但若工作区存在Untracked files,则这些Untracked files会携带进入到指定的commit号版本仓库的工作区中,所以要恢复到和某个commit号完全一致,还需要git clean -f清空Untracked files。
git reset会将HEAD指向的分支指向reset对应的commit,而git checkout是HEAD直接指向对应的commit。
git revert
仅将某个commit号提交分支的内容撤销,且将此次撤销作为一个新的提交。
1 | huangyisan:~/Desktop/github/test $ git log --oneline |
c11842d是将bar文件提交到了分支,当执行git revert c11842d
,则撤销了提交bar文件到分支,所以执行完后,bar文件不见了,但foo文件依旧存在,所以revert只影响了被撤销的commit的变更内容,而且看git log,多了一个新的commit提交号19e736c。