1、创建仓库(git init 、git clone URL)
有两种新建 Git 项目仓库的方法。第一种是在本地通过初始化来创建新的 Git 仓库。第二种是从已有的 Git 远程仓库中克隆出一个仓库。
1.1、通过初始化创建新仓库
要对现有的某个项目开始用 Git 管理,只需在该项目的根目录下,执行以下命令:
$ git init
Git 的大部分命令都需要在 Git 仓库的目录下(即项目的根目录下)运行,git init 是使用 Git 仓库的第一个命令。初始化后,在项目的根目录下会生成一个名为 .git 的文件夹,该目录包含了所有 Git 需要的数据和资源。
初始化后还没有开始跟踪管理项目中的任何一个文件,如果当前目录下有几个文件想要纳入版本控制,需要先用 git add
命令告诉 Git 开始对这些文件进行跟踪并放入了暂存区,然后可以进行提交,比如下面操作:
$ git add *.c $ git add README $ git commit -m 'initial project version'
1.2、通过克隆取到远程仓库的镜像
通过 git clone
命令能复制出一份远程仓库,Git 克隆下来的项目包括项目的所有历史版本,服务器上有的数据克隆之后本地也都会有。克隆仓库的命令格式为 git clone URL
//比如:要克隆 Ruby 语言的 Git 代码仓库 Grit, $ git clone git://github.com/schacon/grit.git
默认会在执行克隆命令的目录下生成项目文件,可以发现项目文件中包含一个 .git
的文件,用于保存下载下来的所有版本记录,然后从中取出最新版本的文件拷贝。
如果希望在克隆的时候,自己定义项目名称,可以在上面的命令末尾指定新的名字:
//自定义项目名称并不会影响向远程仓库提交代码,因为提交时只是提交项目里的文件 $ git clone git://github.com/schacon/grit.git mygrit
2、文件状态
工作目录下面的所有文件都不外乎这两种状态:已跟踪、未跟踪(untracked)。
已跟踪的文件是指已经被纳入版本控制管理的文件,目前它们的状态可能是未更新(unmodified,查看文件状态时默认是不显示出来的),已修改(modified)或者已放入暂存区(staged)。未跟踪文件(untracked)一般是新建的,它们并没有出现在前面的版本中,也不在当前的暂存区域。初次克隆某个仓库时,工作目录中的所有文件都属于已跟踪文件,且状态为未修改。
在编辑过某些文件之后,Git 将这些文件标为已修改(modified)。我们逐步把这些修改过的文件放到暂存区域,直到最后一次性提交所有这些暂存起来的文件,如此重复。所以使用 Git 时的文件状态变化周期如下图:
3、检查当前项目中文件状态(git status)
要确定哪些文件当前处于什么状态,可以用 git status
命令。以下是使用 git status 命令时可能会出现的一些情况
(你也可以使用 git status -s 命令来检查状态,但此时是用状态码来表示文件状态,状态码解释参考:https://blog.csdn.net/weixin_42239374/article/details/80368448)
3.1、nothing to commit
如果在克隆仓库之后立即执行此命令,会看到类似这样的输出:
这说明现在的工作目录很干净,所有已跟踪文件在上次提交后都未被更改过,并且没有出现未跟踪的文件,即没有新建文件。
3.2、Changes to be committed
这条状态表示下面的文件都已存入暂存区,在提交到本地仓库时会将这些变更提交到本地仓库中。
newfile:新增XXX文件
deleted:删除了XXX文件
3.4、Changes not staged for commit
见3.3的图
这条状态表示下面的文件都未存入暂存区。在使用commit命令进行提交操作时,若未使用 -a 参数的话(即使用 git commit -am 命令:使用了-a参数时相当于同时也执行了git add. 命令),则以下文件不会提交到本地仓库中。
modified:修改了XXX文件
3.5、Untracked files
表示以下文件还没有被追踪,一般是新建的文件。Git 不会自动将新建文件纳入跟踪范围,除非你主动使用了命令行来追踪该文件,因而不用担心把临时文件什么的也归入版本管理。
当出现这种情况时,不论是 git commit –m 还是git commit –am 命令都不能将文件提交到本地仓库中,必须执行git add . 命令,先将文件存入暂存区中,再执行提交命令,才可以将文件提交到本地仓库中。
4、跟踪新文件(即放入暂存区:git add)
使用命令 git add
开始跟踪一个新文件或者把一个经修改过的文件放入暂存区。git add后面可以直接跟文件名,也可以跟目录,如果是目录的话,就说明要跟踪该目录下的所有文件(不允许在目录后面还有文件名,那样会显示在该目录下找不到任何文件,因为它把整个当成一个目录路径)。git不仅能判断出 <path>
中,修改(不包括已删除)的文件,还能判断出新添的文件,并把它们的信息添加到暂存区中。
$ git add filename $ git add <path> //目录的路径是相对于根目录的相对路径,比如:git add ./aaa/bbb 当然前面可以不用 ./
当我们把一个文件放入了暂存区,但是并没有提交,后来又对它进行了修改时,这时我们查看状态这个文件会出现在两个状态里
假如我们在将demo.js 文件放入暂存区后,又对其进行了修改,添加了一行注释,查看状态时如下图:
同一个文件出现了两次,一次算未暂存,一次算已暂存。实际上 Git 只不过暂存了你运行 git add
命令后的版本,如果现在提交,那么提交的是添加注释前的版本,而非当前工作目录中的版本。所以,但凡文件进行了修改,都应该将其放入暂存区,以免将来提交的时候版本不对。
4.1、git add的一些语法
$ git add filename $ git add <path> $ git add . // 表示将所有修改添加到暂存区(包括删除的、新建立的文件等所有) $ git add Hello* // 表示将所有以Hello开头的文件的修改添加到暂存区 例如:HelloWorld.txt,Hello.java $ git add -u [<path>] // 表示把<path>中所有已被跟踪的文件中被修改过或已删除文件的信息添加到索引库。它不会处理untracted的文件。如果省略<path>表示当前目录。 $ git add -A: [<path>] // 表示把path中所有已被跟踪文件中被修改过或已删除文件和所有未跟踪的文件信息添加到索引库。省略<path>表示当前目录。
5、.gitignore 文件
一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。这时我们可以创建一个名为 .gitignore
的文件,列出要忽略的文件模式。要养成一开始就设置好 .gitignore 文件的习惯,以免将来误提交这类无用的文件。
5.1、.gitignore 文件创建方法
(1)在需要创建 .gitignore 文件的项目根目录下, 右键选择Git Bash 进入命令行(2)输入 touch .gitignore ,生成“.gitignore”文件,然后就可以进行编辑了
在window上直接创建 .gitignore 文件会出错。
5.2、.gitignore 文件规范
.gitignore 文件的规范:
- 所有空行或者以注释符号
#
开头的行都会被 Git 忽略,不会当做 .gitignore 文件里的内容 - 可以使用 shell 所使用的简化了的正则表达式来匹配。
- 匹配模式最后跟反斜杠(
/
)说明要忽略的是目录。 - 要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(
!
)取反。
shell 所使用的简化了的正则表达式:星号(*
)匹配零个或多个任意字符;[abc]
匹配任何一个列在方括号中的字符(这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c);问号(?
)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符,表示所有在这两个字符范围内的都可以匹配(比如 [0-9]
表示匹配所有 0 到 9 的数字)。
.gitignore
文件内容实例:
# 以 # 开头的是注释,下面表示忽略aaa.txt文件
aaa.txt
# 忽略以 .a 结尾的文件
*.a
# 但 lib.a 除外
!lib.a
# 仅仅忽略项目根目录下的 TODO 文件,不包括 subdir/TODO
/TODO
# 忽略 build/ 目录下的所有文件
build/
# 忽略根目录下的 node_modules 文件
/node_modules
# 会忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目录下所有扩展名为 txt 的文件
doc/**/*.txt
6、查看文件的内容变动(git diff)
git status 命令是用来查看哪些文件发生了变动,要想查看文件具体修改了什么地方,可以用 git diff
命令。git diff
会使用文件补丁的格式显示具体添加和删除的行。
6.1、工作区与暂存区的比较( git diff )
git diff 命令比较的是工作区和暂存区的比较,如果该文件目前没有在暂存区(即都提交了),那么比较的就是工作区和最新版本库里的该文件。比如:你先把 a.js 文件放入了暂存区,然后又修改了 a.js 文件,里面添加了一行注释,这时候比较的差别就是这行注释;如果你把 a.js 文件已经提交了,然后再进行修改,这时候 a.js 文件并没有在暂存区里,这时候比较的就是工作区和版本库里的修改。
有时候运行 git diff 后什么显示都没有,那可能是因为所有文件都已经存入暂存区了,或者没有修改任何文件。注意,git diff 命令并不比较任何没有被追踪的文件。使用 git diff --stat 只显示摘要。
git diff 命令输出的信息意思:
(第一行)diff --git 表示结果为 git 格式的 diff ;a/demo02.js b/demo02.js 表示 a版本的demo02.js(即变动前)和b版本的 demo02.js(即变动后)。
(第二行)index ccde7a7..9278e9c 100644 :表示两个版本的git哈希值(index 区域的ccde7a7 对象,与工作目录区域的9278e9c 对象进行比较),最后的六位数字是对象的模式(普通文件,644权限)。
(第三、四行)表示进行比较的两个文件。"---"表示变动前的版本,"+++"表示变动后的版本。
其它的可以参考:http://www.ruanyifeng.com/blog/2012/08/how_to_read_diff.html 中第五个:合并格式的diff
6.2、暂存区与版本库的比较(git diff --cached 或者 git diff --staged)
git diff 命令比较的是暂存区和最新的版本库的文件内容,输出信息含义可见 6.1 。
6.3、查看已缓存的与未缓存的所有改动(git diff HEAD)
git diff HEAD 显示已缓存的与未缓存的所有改动,相当于同时执行了 git diff 和 git diff --cached 。
当执行 git diff HEAD 时,有可能出现内容太多显示不完全,只需要不断按 Enter 键让它继续显示接下来的内容。到最后可能会卡在 (END) 命令行上,这时候只要按 q 键退出即可。( q 键是 GIT 中的退出键)
7、提交更新(git commit)
git commit 命令将在暂存区的文件提交上去。在提交之前,一定要确认还有什么修改过的或新建的文件还没有放入暂存区,否则提交的时候不会提交那些还没暂存起来的变化。任何修改过的文件没有暂存起来,在提交过后该文件的修改并没有提交上去,而且该文件还是保持已修改状态,可以在下次提交时纳入版本管理。
如果修改文件过后,但是没有把任何文件放入暂存区,这时候提交会报错,不会成功。但凡暂存区里有文件就能提交成功,而是只把暂存区里的文件提交上去。
7.1、git commit (不带参数弹出文本编辑器)
直接使用 git commit 命令时,会启动文本编辑器以便输入本次提交的说明。(默认会启用 shell 的环境变量 $EDITOR
所指定的软件,一般都是 vim 或 emacs。也可以使用 git config --global core.editor
命令设定自己喜欢的编辑软件。)
默认会显示下面的内容:
(1)按 i 键,最下方显示:插入,即可编辑。(2)编辑完后按 Esc 键退出编辑,可以看到此时光标在最左下方。(3)输入 ":wq" ,退出编辑界面(不要漏了前面的 : 符号)
可以看到,默认的提交消息包含最后一次运行 git status
的输出,不过是放在注释行里(提交时并不会把这些当做说明提交上去),另外开头还有一空行,供你输入提交说明。
提交后它会告诉你,当前是在哪个分支(master)提交的,本次提交的完整 SHA-1 校验和是什么(463dc4f
),以及在本次提交中,有多少文件修订过,多少行添改和删改过。
有时候使用 git commit 不加选项时可能会提示:Please supply the message using either -m or -F option
这是因为系统的默认的文本编辑器 vi 有问题,我们可以为 git 换一个默认的编辑器,比如 vim。输入下面命令:
git config --global core.editor "vim"
然后就可以使用不带参数的 git commit 命令了。提交后如果你也不在文本编辑器中输入版本信息而是直接提交的话,此时的提交信息就会由系统自动生成,比如是:Merge branch xxx of xxx into xxx 之类的合并提示信息。
7.2、git commit -m '这里写该版本的说明'
git commit -m '这里写该版本的说明' 可以直接写版本的说明信息,不会跳转到编辑界面,推荐使用。
7.3、git commit -am ' '(或者git commit -a -m ' ')
Git 提供了一个跳过使用暂存区域的方式即 git commit -am(或者git commit -a -m)命令,使用这两个命令时Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而可以不用手写 git add
命令。
不过该命令并不会将新建的文件也放至暂存区并提交,而是只会提交已经跟踪过的文件。
7.4、git commit --amend(修改上次提交的版本)
使用 git commit --amend 命令可以修改你最近一次提交的版本的说明信息,并且该命令还有一个作用就是能将一些最新的修改合并至上一个版本当中。
比如说你最新一次提交的版本说明信息不合规范,你就可以使用该命令来修改说明信息。执行该命令后 git 会弹出文本编辑器并且会基于上次的提交信息来让你进行修改
git commit --amend 命令的另一个作用就是可以让你将本地的修改追加至最近的一次提交当中。比如说你刚提交了版本:aaa,然后你又进行了一些修改操作,然后你想把这些修改追加至刚才提交的版本:aaa 当中,而不想再重新提交一个版本,这时你就可以先执行 git add . ,然后再执行 git commit --amend 命令,git 会弹出文本编辑器来让你再次修改版本说明信息,由此就可以将这些新修改和上次提交的版本合并为一个版本。
请注意:git commit --amend 命令不会自动帮你执行 git add 命令,你要想将本地修改合并至上一版本中,需先执行 git add 命令
git commit --amend 命令还有其他几个参数:
git commit --amend --no-edit:无需修改版本说明信息
git commit --amend -m '新版本说明信息' :直接修改版本说明信息而不用弹出文本编辑器
8、Git 中弹出的文本编辑器
在 git 中提交一个版本,如果没有输入版本说明信息的话 git 就可能会弹出文本编辑器,如上面的 7.1 所示。
操作文本编辑器的命令其实是 Linux 的命令,文本编辑器有三种工作模式:命令模式、输入模式、末行模式。
默认在命令模式:
弹出的文本编辑框默认是在命令模式下,命令模式下是不能直接编辑文本的,你输入的字母会被当作命令执行。
进入输入模式:
在命令模式下,输入 i、o、a 键会进入输入模式,此时弹出框下方会显示 -- INSERT--,游标会定位在最上方,此时我们就可以进行编辑。编辑完成后我们可以按 ESC 键,此时会退出到命令模式。我们必须得先进入命令模式才能退出,因为我们不能直接进入末行模式。
进入末行模式:
在末行模式下,先输入 :,然后再 wq,就可以保存文件并且退出文本编辑器了。
9、删除文件(git rm)
如果只是简单地从工作目录中手动删除文件,运行 git status
时文件会显示在 “Changes not staged for commit” 部分。此时可以先 git add . 把文件放入暂存区,然后再提交。
我们可以使用 git rm filename 命令直接删除文件,并且此时查看状态该文件并不会出现在 “Changes not staged for commit” 部分(其实相当于既在工作目录上删除了该文件,又使用git add filename 将删除操作放入了暂存区),最后提交的时候,该文件就不再提交至版本库了。
9.1、强制删除已修改过的文件(git rm -f filename)
如果文件修改过,不管是否已经放入暂存区,直接使用 git rm filename 命令时都会报错。此时应使用强制删除命令:git rm -f filename 如下图所示:
9.2、仅删除暂存区中的文件(git rm --cached filename)
如果我们想把文件从暂存区中删除,但仍然希望保留在当前工作目录中(如果该文件不存在暂存区中,那么也会从跟踪清单中将其删除,下次提交时不会将该文件提交),换句话说,仅是从跟踪清单中删除。
比如一些大型日志文件或者一堆 .a
编译文件,不小心纳入仓库后,要移除跟踪但又不想把文件从工作目录中删除,以便稍后在 .gitignore
文件中加上以忽略提交,这时我们用 --cached
选项即可。
rm 命令后面也可以列出文件或者目录的名字,也可以使用glob 模式匹配。
9.3、对 git 项目中的文件改名
当你对Git 项目中的文件重命名后,git中并不会识别到这是重命名操作,而是认为你删除了之前那个文件,又重新建立了一个新文件。
比如下面我对demo.txt 文件重命名为 demo02.txt ,查看文件状态时: