Git的配置
在使用Git之前需要设置用户名和用户email。这些是提交代码的签名,每次的提交记录例都会包含这些信息。使用git config命令进行配置:
$ git config --global user.name "clldaxigua"
$ git config --global user.email "clldaxigua@126.com"
在执行了上面的命令以后,会在用户目录下(~/)生成一个.gitconfig文件。该文件就是Git全局的配置文件,内容如下:
[user]
name = clldaxigua
email = clldaxigua@126.com
Git的一般配置方法是git config --global <配置名称> <配置的值>
。如果想是项目里的某个值与全局配置有区别,可以在项目中使用不带—global选项的git config
命令来设置。此时就会在当前的项目目录下创建.git/config,该配置文件仅对该项目有效。
获得一个Git仓库
在设置好Git的配置以后,就需要一个Git仓库。有两种方法可以获得Git仓库:一种是从已有的Git仓库中clone;还有一种是新建一个仓库,实现对项目文件的版本控制。
Clone一个仓库
为了获得一个项目的拷贝,我们需要知道这个项目仓库的地址(Git URL)。Git支持多种通讯协议,包括ssh, http, git等。
实验楼提供了一个测试用的共有仓库,可以使用下面的方法进行克隆:
$ git clone http://git.shiyanlou.com/shiyanlou/gitproject
Clone操作完成后,当前目录下多出一个gitproject目录,这个目录中的内容就是git clone获得到的。由于gitproject仅是测试项目,里面只有一个README.md文件。
初始化一个新的仓库
可以对一个已存在的目录用下面的命令对该目录进行版本控制。
$ cd ~
$ mkdir project
$ cd project
$ git init
Initialized empty Git repository in /home/chen/project/.git/
.git目录的内容可以参考《Git Community Book中文版》。
'Git目录'是为你的项目存储所有历史和元信息的目录,包括所有的对(commits, trees, blobs, tags),这些对象指向不同的分支。
每一个项目只能有一个'Git目录'(这和SVN,CVS的每个子目录中都有此类目录相反), 这个叫'.git'的目录在你项目的根目录下(这是默认设置,但并不是必须的). 如果你查看这个目录的内容, 你可以看所有的重要文件:
$ tree -L 1
.
|-- HEAD # 这个git项目当前处在哪个分支里
|-- config # 项目的配置信息,git config命令会改动它
|-- description # 项目的描述信息
|-- hooks/ # 系统默认钩子脚本目录
|-- index # 索引文件
|-- logs/ # 各个refs的历史信息
|-- objects/ # Git本地仓库的所有对象 (commits, trees, blobs, tags)
|-- refs/ # 标识你项目里的每个分支指向了哪个提交(commit)
正常的工作流程
Git的基本流程如下:
- 创建或者修改文件。
- 使用git add命令添加新建或者修改的文件到本地的缓存区(Index)。
- 使用git commit命令提交到本地代码库。
- 使用git push命令将本地代码库同步到远端代码库(可选)。
一个示例
进入project目录,分别创建3个文件file1, file2, file3,并为3个文件添加内容:
$ cd project
$ touch file1 file2 file3
$ echo "test content file1" >> file1
$ echo "test content file2" >> file2
$ echo "test content file3" >> file3
此时可以用git status
查看当前git仓库的状态:
$ git status
On branch master
Initial commit
Untracked files:
(use "git add <file>..." to include in what will be committed)
file1
file2
file3
nothing added to commit but untracked files present (use "git add" to track)
此时有3个文件处于untracked状态,下一步需要用git add命令将他们添加到缓存区:
$ git add file1 file2 file3
然后再次执行git status
就会发现新的变化:
$ git status
On branch master
Initial commit
Changes to be committed:
(use "git rm --cached <file>..." to onstage)
new file: file1
new file: file2
new file: file3
此时可以使用git diff --cached
命令查看缓存区中哪些文件被修改,如下所示:
$ echo "append" >> file1
$ git diff --cached
diff --git a/file1 b/file1
new file mode 100644
index 0000000..61a4d74
--- /dev/null
+++ b/file1
@@ -0,0 +1 @@
+test content file1
diff --git a/file2 b/file2
new file mode 100644
index 0000000..4367933
--- /dev/null
+++ b/file2
@@ -0,0 +1 @@
+test content file2
diff --git a/file3 b/file3
new file mode 100644
index 0000000..6cd7bad
--- /dev/null
+++ b/file3
@@ -0,0 +1 @@
+test content file3
如果没有—cached参数,则会显示当先所有已做但是没有加入到缓存区里的修改。
$ git diff
diff --git a/file1 b/file1
index 61a4d74..2260863 100644
--- a/file1
+++ b/file1
@@ -1 +1,2 @@
test content file1
+append
在这里需要特别说明的是git diff
命令只会显示不在缓存区中的修改,而不会显示不在缓存区的新建文件。也就是说,如果在project文件下新建一个file4,执行git diff
命令并不会显示file4。
此时,可以通过commit命令将缓存区中的代码提交到本地代码仓库中:
$ git commit -m "add 3 files"
[master (root-commit) b148ad6] add 3 files
3 files changed, 3 insertions(+)
create mode 100644 file1
create mode 100644 file2
create mode 100644 file3
再次输入git status
查看状态,会发现当前的缓存区中已经没有待提交的文件。至此,第一次代码提交已经完成。之后如果需要添加或者修改文件,则需要将添加或者修改的文件git add
到缓存区中才可以提交。如果是删除文件,则使用git rm
命令删除后会自动将已删除文件添加到缓存区,此时执行git commit
命令后就会将仓库中的对应文件删除。
这个时候,如果本地的仓库连接到远程的Git服务器,则可以使用下面的命令将本地仓库同步到远端服务器:
$ git push origin master
分支与合并
Git的分支可以实现在主线(master分支)之外进行代码提交,同时又不会影响代码库主线。分支的作用体现在多人协作开发中。比如在一个软件项目的开发过程中,一个程序员负责独立的一个功能需要一个月的时间来完成,那就可以创建一个分支,只把该功能的代码提交到这个分支,而其他同事仍然可以继续使用主线开发。这样一来,支线版本中的提交不会对他们造成任何影响。当该功能模块功能实现并经过测试后,再把分支代码合并到主线中。
分支
一个Git仓库可以维护很多开发分支。现在我们来创建一个新的叫 experimental的分支:
$ git branch experimental
运行git branch
命令可以查看当前的分支列表,已经目前的开发环境处在哪个分支上:
$ git branch
experimental
* master
experimental 分支是刚才创建的分支,master分支是Git系统默认创建的主分支。星号标识当前的工作分支。输入git checkout [branch name]
可以切换到其他分支:
$ git checkout experimental
Switched to branch 'experimental'
切换到experimental分支,切换完成后,先编辑里面的一个文件,再提交(commit)改动,最后切换回 “master”分支:
# 修改文件file1
$ echo "update" >> file1
# 添加并提交file1的修改
$ git add file1
# 提交代码
$ git commit -m "update file1"
# 查看experimental分支中file1的内容
$ cat file1
test
update
# 切换到master分支
$ git checkout master
# 查看master分支中file1的内容
$ cat file1
test
此时查看file1中的内容会发现,刚才做的修改已经消失。因为刚才的修改时在experimental分支下,现在切换回了master分支,目录下的文件都是master分支上的文件了。现在可以在master分支下再作一些不同的修改:
# 修改文件file2
$ echo "update" >> file2
# 添加并提交file2的修改
$ git add file2
$ git commit -m "update file2"
# 查看file2的内容
$ cat file2
test
update again
合并
这时,两个分支就有了各自不同的修改,分支的内容都已经不同。可以通过git merge
命令来合并experimental到主线分支master:
# 切换到master分支
$ git checkout master
# 将experimental分支合并到master
$ git merge -m 'merge experimental branch' experimental
由于两个branch修改了两个不同的文件,所以合并时不会有冲突,执行上面的命令就可以完成代码的合并。
合并冲突
如果有冲突,比如两个分支修改同一个文件,则合并时会失败。首先在master分支上修改file3文件并提交:
# 切换到master分支
$ git checkout master
# 修改file3文件
$ echo "master: update file3" >> file3
# 提交到master分支
$ git commit -a -m 'update file3 on master'
然后切换到experimental,修改file3并提交:
# 切换到experimental分支
$ git checkout experimental
# 修改file3文件
$ echo "experimental: update file3" >> file3
# 提交到master分支
$ git commit -a -m 'update file3 on experimental'
切换到master进行合并:
$ git checkout master
$ git merge experimental
Auto-merging file3
CONFLICT (content): Merge conflict in file3
Automatic merge failed; fix conflicts and then commit the result.
合并失败后先用git status
查看状态,会发现file3显示为both modified,查看file3内容会发现:
$ cat file3
test
<<<<<<< HEAD
master: update file3
=======
experimental: update file3
>>>>>>> experimental
上面的内容也可以使用git diff查看,先前已经提到git diff不加参数可以显示未提交到缓存区中的修改内容。
$ git diff
diff --cc file3
index 9e160c6,1b26a67..0000000
--- a/file3
+++ b/file3
@@@ -1,2 -1,2 +1,6 @@@
test3
++<<<<<<< HEAD
+master: update
++=======
+ experimental: update
++>>>>>>> experimental
同时,冲突的内容都被添加到了file3中。
$ cat file3
test3
<<<<<<< HEAD
master: update
=======
experimental: update
>>>>>>> experimental
可以使用vim编辑这个文件,去掉git自动产生标志冲突的<<<<<<等符号后,根据需要只保留我们需要的内容后保存,然后使用git add file3
和git commit
命令来提交合并后的file3内容,这个过程是手动解决冲突的流程。
删除分支
当我们完成合并后,不再需要experimental时,可以使用下面的命令删除:
$ git branch -d experimental
git branch -d
只能删除那些已经被当前分支的合并的分支. 如果你要强制删除某个分支的话就用git branch –D
。
撤销一个合并
如果你觉得你合并后的状态是一团乱麻,想把当前的修改都放弃,你可以用下面的命令回到合并之前的状态:
$ git reset --hard HEAD^
快速向前合并
还有一种需要特殊对待的情况,在前面没有提到。通常,一个合并会产生一个合并提交(commit), 把两个父分支里的每一行内容都合并进来。
但是,如果当前的分支和另一个分支没有内容上的差异,就是说当前分支的每一个提交(commit)都已经存在另一个分支里了,git 就会执行一个“快速向前"(fast forward)操作;git 不创建任何新的提交(commit),只是将当前分支指向合并进来的分支。
Git日志
查看日志
git log命令可以显示所有的提交(commit):
$ git log
日志统计
如果用--stat选项使用'git log',它会显示在每个提交(commit)中哪些文件被修改了, 这些文件分别添加或删除了多少行内容,这个命令相当于打印详细的提交记录:
$ git log --stat
格式化日志
你可以按你的要求来格式化日志输出。--pretty 参数可以使用若干表现格式。格式化输出的格式支持oneline, short, medium, full, fuller, email 或raw。 此外,也可以用--pretty=format参数定义格式。
--graph 选项可以可视化提交图(commit graph),利用ASCII字符画出一个提交历史(commit history)线:
$ git log --graph --pretty=oneline
日志排序
日志记录可以按不同的顺序来显示。如果需要指定一个特定的顺序,可以为git log命令添加顺序参数。
按默认情况,提交会按逆时间顺序显示,可以指定--topo-order参数,让提交按拓扑顺序来显示(就是子提交在它们的父提交前显示);也可以用 --reverse参数来逆向显示所有提交日志。