上一节对目录进行了Git的初始化,让Git可以开始管理这个目录。接下来,我们就来看看Git是怎样操作的。
1. 创建文件
$ git status On branch master Initial commit nothing to commit (create/copy files and use "git add" to track)
现在在这个目录中,除了Git生成的那个.git隐藏目录外什么都没有,所以提示“nothing to commit”(现在没有内容可以提交)。接下来,在这个目录中通过系统命令创建一个内容为“hello,git”的文件,并命名为welcome.html:
$ echo "hello, git" > welcome.html
这个步骤使用一般的文本编辑器或由文件管理员来完成都可以,总之在这个目录中创建一个名为welcome.html的文件即可。接着,再次使用git status命令,然后来看一下这个目录的状态:
$ git status On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) welcome.html nothing added to commit but untracked files present (use "git add" to rack)
或者使用SourceTree来查看,如图5-5所示。
图5-5
这时的状态与一开始不太一样了。这个welcome.html文件当前的状态是Untracked files,即这个文件尚未被加到Git版控系统中,还未正式被Git“追踪”,只是刚刚加入这个目录而已。
2. 把文件交给Git
既然文件当前的状态是Untracked,接下来就要把welcome.html文件交给Git,让Git开始“追踪”它。使用的命令是git add,后面加上文件名:
$ git add welcome.html
在终端机执行这个命令不会输出任何结果。如果使用SourceTree,可以在welcome.html文件上右击,然后选择Add to index选项,如图5-6所示。
图5-6
这样就可以把该文件交给Git管控了。再次使用git status命令查看当前的状态:
$ git status On branch master Initial commit Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: welcome.html
从以上信息可以看出,文件状态已从Untracked变成new file。这表示该文件已经被安置到暂存区(Staging Area),稍后将与其他文件一起被存储到存储库中。
这个暂存区也称为下标(Index),所以在图5-6所示的SourceTree快捷菜单中才会显示为Add to index字样。为便于理解,本书将统一使用“暂存区”的称谓。至于为什么要有这样的设计,详见5.3节。
小提示
add命令看起来很简单,其实能做不少事,详情可参阅5.18节。
如果觉得git add welcome.html这样一次只加一个文件有点麻烦,也可以使用万用字元:
$ git add *.html
这样就可把所有后缀名是.html的文件全部加到暂存区。如果想要一口气把全部的文件都加到暂存区,可以直接使用--all参数:
$ git add --all
设想一下下面这样一种情境。
(1)新增了一个文件abc.txt。
(2)执行git add abc.txt命令,把文件加至暂存区。
(3)编辑abc.txt文件。
完成编辑后,可能想要进行Commit,把刚刚改动的内容保存下来。这是新手很容易犯的错误之一,以为执行Commit命令就能把所有的异动都保存下来,事实上这样的想法是不正确的。执行git status命令,看一下当前的状态:
$ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: abc.txt 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: abc.txt
可以发现,abc.txt文件变成了两个,这是为什么?其实步骤(2)的确把abc.txt文件加入暂存区了,但在步骤(3)中又编辑了该文件。对Git来说,编辑的内容并没有再次被加入暂存区,所以此时暂存区中的数据还是步骤(2)中加进来的那个文件。
如果确定这个改动是你想要的,那就再次使用git add abc.txt命令,把abc.txt文件加入暂存区。
小提示
其实,这样的动作会产生一些unreachable的边缘对象。这部分算是进阶的内容,有兴趣的读者可参阅9.4节。
有时可能会听到别人这样说:“git add.命令也可以把所有的文件全部加入暂存区。”这样的说法其实不完全正确,需视具体情况而定。
1. Git版本
在较旧版本的Git(Git 1.x)中,git add.命令会把“新增的文件”(也就是Untracked状态的文件)以及“改动过的文件”加到暂存区,但是不会处理“删除文件”的行为。这里通过表5-1简单说明一下。
表5-1 --all与.参数的区别
不过,在Git 2.x之后变成了这样,如表5-2所示。
表5-2 --all与.参数的区别(Git 2.x之后)
也就是说,在Git 2.x之后,这两个参数在功能上就没什么区别了。
2. 执行命令时的目录位置
如图5-7所示,项目根目录下的index.html文件以及css目录下的main.css文件都有改动,如果在根目录下执行git add命令,这两个文件都会被加入暂存区,但如果在css目录下执行该命令,仅会加入main.css文件,index.html文件的状态不会改变。
图5-7
这是因为git add.命令会把当前目录,以及它的子目录、子子目录、子子子目录……中的异动全部加到暂存区,但在该目录以外的就不归它管了;而git add--all命令就没有这个问题,该命令不管在项目的哪一层目录执行,效果都是一样的,这个项目中所有的异动都会被加入暂存区。
所以,回到原来的问题——“--all”与“。”参数有什么不一样?答案会因所使用的Git版本以及执行命令时的目录而有所差异。
如果仅是通过git add命令把异动加到暂存区,还不算是完成整个流程。如果想让暂存区的内容永久保存下来,就要使用git commit命令:
$ git commit -m "init commit" [master (root-commit) dfccf0c] init commit 1 file changed, 1 insertion(+) create mode 100644 welcome.html
在后面加上“-m "init commit"”是要说明“这次的Commit做了什么事”,只要使用简单、清楚的文本说明即可,中英文都可以,重点是要说清楚,能让自己和别人很快明白就行。
如果使用SourceTree,单击左上角的Commit按钮,就可以开始输入信息了,如图5-8所示。
图5-8
输入完信息,单击右下角的Commit按钮,即可完成本次Commit。
完成了这个动作后,对Git来说就是“把暂存区的内容存放到存储库(Repository)中”了。换言之,就是“我完成一个存档(或备份)的动作了”,即创建了一个第1章中提到的“版本”。关于存储库,将在5.3节中详细介绍。
注意!
要完成Commit命令才算是完成整个流程!
1. 到底Commit了哪些东西
首先要记住一个很重要的观念:Git每次的Commit都只会处理暂存区中的内容。也就是说,在执行git commit命令时,那些还没有被加到暂存区中的文件不会被Commit到存储库中。
例如,如果新增了一个文件,但没有执行git add命令把它加至暂存区,那么在执行git commit命令时,该文件就不会被加至存储库中。
2. 输入的信息很重要吗
对,很重要!很重要!很重要!
在Commit时,如果没有输入这个信息,Git默认是不会完成Commit的。它最主要的目的就是告诉你自己及其他人“这次的改动做了什么”。以下是几点关于信息的建议。
(1)尽量不要使用太过情绪化的字眼,以避免不必要的问题。
(2)英文、中文都可以,重点是要简单、清楚。
(3)尽量不要使用类似bug fixed这样模糊的描述,因为没有人知道你修正了什么bug。但如果搭配其他的系统使用,则可使用类似#34 bug fixed这样的描述,因为这样可以知道这次的Commit修正了第34号bug。
3. 等等,怎么弹出了一个奇怪的窗口
在执行git commit命令时,如果没有在后面加上信息参数,默认会弹出一个黑色的画面,也就是编辑器——Vim。该编辑器对新手不太友好,可参考3.2节,或者直接使用SourceTree之类的图形界面工具来处理输入及提交信息的问题。
4. 一定要有内容才能Commit吗
只要加上--allow-empty参数,没有内容也是可以Commit的:
$ git commit --allow-empty -m " 空的 " [master 76a5b84] 空的 $ git commit --allow-empty -m " 空的 " [master f4f568c] 空的 $ git commit --allow-empty -m " 空的 " [master 7653117] 空的
这样就做了3个空的Commit出来,它们基本上没什么意义,但在上Git课的时候会很方便,可以不用新增文件就快速产生Commit来练习合并。