目录:
git 简介
git 安装
git的基本构成
git的基本操作
基本命令
vi命令
创建版本库
添加文件
提交文件
查看状态
查看提交日志
查看更改对比
版本回滚
撤销操作
删除操作
远程仓库
认识github
克隆远程仓库
推送与拉取
分支
分支的基本概念
分支的常用命令
创建分支
切换分支
创建并切换分支
查看分支
合并分支
删除分支
分支的注意事项
分支冲突
多人协作
bug 分支
标签
标签的概念
标签的常用命令
自定义
用户信息与加密key
命令语法着色
文件忽略
自定义命令
修改配置文件
git常见问题
git 简介
git是由 Linus 开发的一种“分布式版本控制”软件,而在此之前,版本控制基本上都是“集中式版本控制”,如:CVS,SVN 等。
下图可以很好的帮助我们区分这两者:
"集中式版本控制系统"中,版本库是集中存放在中央服务器中的,开发人员在干活的时候,要先去访问中央服务器调取项目代码,然后才能修改,最后再提交到中央服务器中,供别人拉取使用。因此它有一个很大的缺点,那就是必须链接到中央服务器才能够正常工作。
相比较“集中式版本控制”,“分布式版本控制” 并没有真正意义上的中央服务器,而是开发者的每台电脑都可以作为一个中央节点来使用,因此工作时就无需链接主机,更不需要在只有有网络的环境下才能工作,而且分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。如果集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。
“分布式版本控制”也有中央节点的概念,这是因为在实际使用“分布式版本控制系统”的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
git 安装
git的安装很简单,只需要下载git的程序安装包,安装好后即可,如果你是window系统,可以直接在自带的gitbash
中执行相应的git命令,gitbash
默认便有相应的语法着色,如果你是mac系统,则在自己的终端中执行git命令,这里我推荐通过配置的方式设置git的语法作色,可以参考最后一章“自定义”。
git的基本构成
git的整体框架主要由两部分组成,它们分别是“工作区”和“版本库”。“工作区”就是我们本地的工作目录,而版本库则是我们通过 git init
命令创建的git仓库。
“版本库”用于监控文件的更改状态。它又有两个主要的部分构成,它们分别是:“暂存区”与“分支”,“暂存区”中保存的就是本地进行修改后等待提交的文件,而分支则是用于记录已经提交但是等待推送的文件。git默认的分支只有一个,那就是 master
分支,但是git也支持多个分支,并且分支之间可以切换,可以合并。而 HEAD
便是分支的索引标识,类似于一个指针,用于确定当前活动的分支。
总的来说在git中发布一个版本,必须要经过以下几个步骤:
1. 在工作区中新建,编辑,保存文件。
2. 将编辑好的文件,添加至暂存区缓存
3. 确认无误后,将暂存区中的文件提交到分支中,等待推送。
4. 发布版本后,将本地仓库的文件推送至远程,以供别人拉取使用。
而在没有推送之前,这个文件的修改在“工作区”与“版本库”之间是可以相互重置撤销的。
git的基本操作
基本命令
下面是我们通过命令行工具来进行本地目录与文件操作的常用命令。
命令 | 功能 |
---|---|
cd | 进入到指定的目录。eg: cd d:/work/test |
dir | 列表化显示目录与文件。 |
ls | 列表化显示目录与文件,但 win-cmd不支持 |
ls -a | 列表化显示目录与文件包括隐藏文件,但 win-cmd不支持 |
mkdir | 创建一个目录。eg:mkdir dirName |
touch | 创建一个空的文件。eg:touch fileName.txt |
vi | 使用内置vi编辑器来编辑文件。eg:vi fileName.txt |
rm | 删除文件。eg: rm fileName.txt |
rm | 删除目录。eg: rm -rf dirName |
cat | 查看文件内容。eg: cat fileName.txt |
mv | 移动文件或目录。eg: mv a.txt ../ |
find | 搜索当前目录下的文件。eg: find *.txt |
pwd | 显示当前目录的路径。 |
vi命令
vi
是Unix及Linux系统下标准的编辑器,由美国加州大学伯克利分校的Bill Joy所创立。
我们可以在支持 vi
编辑器的命令行工具中,直接调用vi来编辑文件。vi
有两种状态是我们经常使用到的,分别是“命令模式”以及“编辑模式”。vi
默认的模式就是命令模式,通过在命令行中输入命令 a
便可以进入编辑模式,在编辑模式,按下 esc
键,再通过 shift+;
(这里以window系统为例) 组合键,便又可返回命令模式。
下面是vi常用的命令:
命令 | 功能 |
---|---|
a | 进入编辑模式 |
q | 退出vi编辑器 |
q! | 强制退出vi编辑器 |
w | 保存文件 |
wq | 保存并退出 |
wq filename | 保存文件退出并命名文件名称 |
yyp | 复制光标所在的行再插入到下一行 |
dd | 删除光标所在的行 |
u | 返回上一次操作 |
set number | 在编辑器中显示行号 |
set nonumber | 在编辑器中隐藏行号 |
h | 左移一个字符 |
l | 右移一个字符 |
j | 上移一行 |
k | 下移一行 |
创建版本库
什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
git创建版本库非常简单,首先选择一个目录,然后执行以下命令即可。
Administrator@LS1412PC0008 MINGW64 /
$ cd d:/work/
Administrator@LS1412PC0008 MINGW64 /d/work
$ mkdir test
Administrator@LS1412PC0008 MINGW64 /d/work
$ cd test
Administrator@LS1412PC0008 MINGW64 /d/work/test
$ git init
Initialized empty Git repository in D:/work/test/.git/
瞬间Git就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),细心的读者可以发现当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。
如果你没有看到.git目录,那是因为这个目录默认是隐藏的,用 ls -a
命令就可以看见。
另外git仓库也不是全能的,它只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。
不幸的是,Microsoft的Word格式是二进制格式,因此,版本控制系统是没法跟踪Word文件的改动的,前面我们举的例子只是为了演示,如果要真正使用版本控制系统,就要以纯文本方式编写文件,并且强烈推荐文件的编码为UTF-8。
添加文件
添加文件是指将文件添加至版本库中的暂存区(stage),而暂存区中存放的内容,便是等待提交的内容。
Administrator@LS1412PC0008 MINGW64 /d/work/test (master)
$ touch name.txt
Administrator@LS1412PC0008 MINGW64 /d/work/test (master)
$ vi name.txt
Administrator@LS1412PC0008 MINGW64 /d/work/test (master)
$ git add name.txt
如果想一次性的将所有文件都添加至暂存区,可以用以下命令:
Administrator@LS1412PC0008 MINGW64 /d/work/test (master)
git add .
提交文件
如果暂存区中的文件确认无误的话,便可可使用以下命令将内容提交至分支中:
[email protected] MINGW64 /d/work/test (master)
$ git commit name.txt -m ‘commit name.txt‘
[master (root-commit) 0c2dc57] commit name.txt
1 file changed, 1 insertion(+)
create mode 100644 name.txt
其中 -m
是本次提交的注释内容,这个必须填写
如果你想将暂存区中的所有内容都提交到分支中,可以这么写
[email protected] MINGW64 /d/work/test (master)
$ git commit -m ‘commit all stage‘
[master d27ea06] commit all stage
1 file changed, 1 insertion(+), 1 deletion(-)
除此之外,你还可以将 add
与 commit
结合在一起使用
[email protected] MINGW64 /d/work/test (master)
$ git commit -a -m ‘add & commit‘
[master b602d26] add & commit
1 file changed, 1 insertion(+), 1 deletion(-)
查看状态
git status命令可以列出当前目录所有还没有被git管理的文件或者是被git管理且被修改但还未提交(commit)的文件。
[email protected] MINGW64 /d/work/test (master)
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: name.txt
如果想看简明扼要一点的状态信息,可以加一个 -s
参数
[email protected] MINGW64 /d/work/test (master)
$ git status -s
M name.txt
查看提交日志
在提交了若干版本之后,想回顾下提交历史,可以使用 git log
命令查看。
Administrator@LS1412PC0008 MINGW64 /d/work/test (master)
$ git log
commit b602d2600c2a4f84d427ff2a414a90384e77dfed
Author: guotaoShen <shenguotao@iwgame.com>
Date: Thu Mar 30 11:00:19 2017 +0800
add & commit
commit d27ea06b28a91095921ac55b2fb3c1f078e10a9b
Author: guotaoShen <shenguotao@iwgame.com>
Date: Thu Mar 30 10:58:56 2017 +0800
commit all stage
commit 0c2dc5716fc3b1ba0b8690a91e5dcad5d2b1dd24
Author: guotaoShen <shenguotao@iwgame.com>
Date: Thu Mar 30 10:56:30 2017 +0800
commit name.txt
在通过 git log
命令 打印的信息中,我们可以看到,git会按照提交时间去排序历史记录,最后一次提交排在最前面,除此之外,你还可以看到关于提交的一些标识,作者,时间,以及提交的说明等信息。
git log
命令提供了很多可供自定义提交日志输出的格式,这里,我就选择几个最常用到的
一行显示提交历史记录
通过使用git log
命令我们知道,打印出来的提交信息会占据多行,一旦提交次数变多到时候,这必将影响我们浏览。
[email protected] MINGW64 /d/work/test (master)
$ git log --pretty=oneline
b602d2600c2a4f84d427ff2a414a90384e77dfed add & commit
d27ea06b28a91095921ac55b2fb3c1f078e10a9b commit all stage
0c2dc5716fc3b1ba0b8690a91e5dcad5d2b1dd24 commit name.txt
显示提交文件的更改信息
[email protected] MINGW64 /d/work/test (master)
$ git log --pretty=oneline --stat
b602d2600c2a4f84d427ff2a414a90384e77dfed add & commit
name.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
d27ea06b28a91095921ac55b2fb3c1f078e10a9b commit all stage
name.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
0c2dc5716fc3b1ba0b8690a91e5dcad5d2b1dd24 commit name.txt
name.txt | 1 +
1 file changed, 1 insertion(+)
显示提交文件的更改信息与更改内容
[email protected] MINGW64 /d/work/test (master)
$ git log --pretty=oneline -p -2
b602d2600c2a4f84d427ff2a414a90384e77dfed add & commit
diff --git a/name.txt b/name.txt
index 7e94c2b..9e0c614 100644
--- a/name.txt
+++ b/name.txt
@@ -1 +1 @@
-my name is shentao - 123
+my name is shentao - 1234
d27ea06b28a91095921ac55b2fb3c1f078e10a9b commit all stage
diff --git a/name.txt b/name.txt
index d137a88..7e94c2b 100644
--- a/name.txt
+++ b/name.txt
@@ -1 +1 @@
-my name is shentao - 12
+my name is shentao - 123
其中 -2
可以指定只显示前两条的提交信息,这个参数很实用,比如:
[email protected] MINGW64 /d/work/test (master)
$ git log --pretty=oneline -1
b602d2600c2a4f84d427ff2a414a90384e77dfed add & commit
查看更改对比
如果我们想比较一个文件在工作区与暂存区的更改状态,我们可以使用 git diff
命令。
[email protected] MINGW64 /d/work/test (master)
$ git diff name.txt
diff --git a/name.txt b/name.txt
index 465f661..d48e0e5 100644
--- a/name.txt
+++ b/name.txt
@@ -1,3 +1,4 @@
my name is shentao - 12345
new add line
new add line 2
+new add line 3
如果想查看该文件在暂存区与分支中的更改对比,可以通过附加 --cached
实现
[email protected] MINGW64 /d/work/test (master)
$ git diff --cached
diff --git a/name.txt b/name.txt
index 8535cbf..465f661 100644
--- a/name.txt
+++ b/name.txt
@@ -1,2 +1,3 @@
my name is shentao - 12345
new add line
+new add line 2
若是想直接查看工作区与分支的对比状态,则可以附加 HEAD
参数。
[email protected] MINGW64 /d/work/test (master)
$ git diff HEAD
diff --git a/name.txt b/name.txt
index 8535cbf..d48e0e5 100644
--- a/name.txt
+++ b/name.txt
@@ -1,2 +1,4 @@
my name is shentao - 12345
new add line
+new add line 2
+new add line 3
版本回滚
通过 git reset
命令我们可以重置分支中最新的提交。
首先,我们先通过 git log --pertty=oneline
来查看提交的历史记录。
[email protected] MINGW64 /d/work/test (master)
$ git log --pretty=oneline
b602d2600c2a4f84d427ff2a414a90384e77dfed commit1
d27ea06b28a91095921ac55b2fb3c1f078e10a9b commit2
0c2dc5716fc3b1ba0b8690a91e5dcad5d2b1dd24 commit3
其中像 b602d2600c2a4f84d427ff2a414a90384e77dfed
的这样一串字母与数字的混合,就是该提交的索引,一般我们取前6位 b602d2
,便可以供我们使用了。
拿到提交索引,我们便可以告诉git重置到那个提交版本。
[email protected] MINGW64 /d/work/test (master)
$ git reset --hard d27ea0
HEAD is now at d27ea0 commit2
此时我们便将分支中保存的最新提交 commit1 重置为了 commit2了。此时如果再使用 git log
去查看提交历史记录,便会惊讶的发现,commit1版本已经看不到了,但是如果你现在又要重新返回到 commit1版怎么办呢?
不要担心,虽然 git log
无法查看之前的版本,但是通过 git reflog
命令还是可以看到的提交的命令记录。
Administrator@LS1412PC0008 MINGW64 /d/work/test (master)
$ git reflog
b602d26 [email protected]{26}: commit: commit1
d27ea06 [email protected]{27}: commit: commit2
0c2dc57 [email protected]{28}: commit: commit3
在常规的使用时,git的版本重置还有一种简写方式。git reset --hard HEAD ^ //返回到当前版本下一个版本
撤销操作
这里说的撤销操作,是指将暂存区的内容或者是提交后的内容撤销到工作区的操作。
首先我们准备一下要撤销的环境,这里我以 name.txt
为例,我会让该文件在不同的区域其内容不同。
在工作区:
add line to working
在暂存区:
add line to working
add line to staged
提交后再分支中:
add line to working
add line to staged
add line to staged
现在我们开始我们的撤销操作
Administrator@LS1412PC0008 MINGW64 /d/work/test (master)
$ cat name.txt
add line to working
Administrator@LS1412PC0008 MINGW64 /d/work/test (master)
$ git checkout name.txt
Administrator@LS1412PC0008 MINGW64 /d/work/test (master)
$ cat name.txt
add line to working
add line to staged
Administrator@LS1412PC0008 MINGW64 /d/work/test (master)
$ git checkout HEAD name.txt
Administrator@LS1412PC0008 MINGW64 /d/work/test (master)
$ cat name.txt
add line to working
add line to staged
add line to branch
删除操作
在gitbash中,我们可以通过 rm
命令来删除文件以及目录。
rm name.txt //删除文件
rm -rf .git //删除本地版本库目录
相同的git也自带了删除命令,使用者可以选择是否将工作区与暂存区的文件同时删除,还是保留工作区只删除暂存区。
git rm name.txt
同时删除工作区与暂存区
git rm --cached name.txt
删除暂存区,但保留工作区。
远程仓库
所谓的远程仓库,就是git的中央节点,也就是远程服务器上的git版本库,与我们本地并没有什么区别,纯粹为了7x24小时开机并交换大家的修改。
git的远程仓库或者是中央节点,既可以我们自己搭建一个内部的git服务器,也可以使用目前网上流行的github远程项目托管平台。
认识github
github 是一个面向开源及私有软件项目的托管平台,因为只支持 Git 作为唯一的版本库格式进行托管,故名github。
github 不仅仅单纯托管git版本库,还提供了跨平台的web操作界面,因此深受很多开发者喜爱。
github 上的代码项目都是公开的开源的,如果你想私有不公开你的项目代码,那么就需要缴纳一定的金额才能开通私有功能。
github的官网地址是:https://github.com/,想使用github的具体功能,你需要有一个账号。
克隆远程仓库
我们既可以将远程的版本库直接克隆到本地,也可以先创建本地的git版本库,然后再与远程的git仓库进行关联,具体使用哪一种,就看你个人的选择。通常来说,直接克隆的方式是最简单的,但是你不能确认在你开发之前,远程的git仓库就已经建好供你使用了。
需要说明的是,以下示例中的远程版本库都是以github上的远程仓库为例。
直接克隆远程版本库
Administrator@LS1412PC0008 MINGW64 /d/work
$ git clone https://github.com/shenguotao2015/fdasfdsafsaf.git
这种方式会将远程版本库克隆一个副本到本地,并且可以自动将本地版本库与远程版本库自动关联。
关联远程版本库
Administrator@LS1412PC0008 MINGW64 /d/work
$ mkdir test
Administrator@LS1412PC0008 MINGW64 /d/work
$ git init
Initialized empty Git repository in D:/work/.git/
Administrator@LS1412PC0008 MINGW64 /d/work (master)
$ git remote add origin https://github.com/shenguotao2015/test.git
这种方式先在本地创建一个git仓库,然后再通过 git remote
命令与远程版本库进行关联。
但如果我们关联的远程版本库有误的话,就需要先删除remote的origin再从新设定remote的origin
git rm remote origin
git remote add origin URL
推送与拉取
指定分支推送并关联远程库
$ git push -u origin master
Username for ‘https://github.com‘: shenguotao2015
Counting objects: 3, done.
Writing objects: 100% (3/3), 209 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
Branch master set up to track remote branch master from origin.
To https://github.com/shenguotao2015/fdasfdsafsaf.git
* [new branch] master -> master
默认分支推送
git push
这种方式默认推送的就是当前分支中的提交内容。
拉取指定分支的项目代码
git pull origin master
拉取默认分支
git pull
关于分支,我们下一节会详细的说到。
分支
分支的基本概念
前面我们已经说过 HEAD
它类似于指针和索引的概念,在git中,HEAD
指向的是分支,分支用于保存提交结果,并面向最后的推送。
git默认的分支是 master
分支,在没有其它分支的情况下,所有的提交操作都会被保存保存到master
分支上,最终这个分支的时间线会不断的进行延伸。但不变的是 HEAD
指向master
,master
再面向最后的推送。
分支的优势在于其类似于一个平行独立的个体,不同的分支可以用来保存不同的提交和推送结果,从而避免在开发时产生的代码冲突。
分支的常用命令
下面是分支常用的命令集合
创建分支
git branch <branchname>
切换分支
git checkout <branchname>
创建并切换分支
git checkout -b <branchname>
查看分支
查看本地分支git branch
查看远程分支
//查看所有分支
git branch -a
//查看远程分支
git branch -r
合并分支
fast forward 模式合并git merge <branchname>
非fast forward 模式合并git merge --no-ff -m "merge width no-ff" <branchname>
fast forward 与非 fast foward模式在于前者属于一种快速合并方式,不会保存历史记录,而后者会在合并时,创建commit提交,从而保留被合并分支之前的记录,通过 git log --graph --pretty=oneline --abbrev-commit
命令可以查看--no-ff模式下的合并提交记录。
删除分支
一般删除git git branch -d <branchname>
强行删除git branch -D <branchName>
删除远程分支git branch -r -a <branchName>
分支的注意事项
git 中的分支分为本地分支与远程分支,本地分支就是使用者自己在本地仓库中创建的分支,所以远程分支便是使用者自己在远程仓库中建立的分支,具体示例如下图:
先简单的介绍本地分支的操作流程,当我们在本地的git中创建一个 dev
的分支时,在没有切换下,HEAD
依然指向的是默认的分支 master
,当我们通过 git checkout dev
切换到 dev
分支时,HEAD
便会指向 dev
分支。然后我们进行的提交操作,都会保存到 dev
分支中再面向最后的推送(push),如果此时再通过git命令切换到 master
分支,那么HEAD
就会自然的再指向 master
, 然后 master
面向提交,当我们在 master
基础上合并 dev
分支时,git就会将dev分
支上的参数信息合并到master上,这样master上就可以看到之前的dev分支的所有提交内容了。
接着再介绍一下远程分支的概念,虽然我们说git中的分支分为“本地分支”与“远程分支”,但实际上这个区分并不突出,这是因为我们在本地git仓库中创建的分支,只要本地仓库origin与远程仓库origin是相连的情况下,git会自动帮我们将本地与远程同名的分支进行关联,除此之外,在进行 fetch
操作时,git也会将本地的分支自动同步到远程仓库总。除此之外当我们 直接切换本地不存在但远程存在的分支时,git都会自动帮我们创建,切换并进行关联。
示例:
git checkout dev
//如果远程仓库存在dev分支,git会自动帮我们创建,关联与切换dev分支
需要注意的一点是,在本地同一个机器下创建的多个分支,其工作区中的文件是可以共享的,但是一旦该文件在某个分支中推送到了远程对应的分支时,那么该文件边只会是该分支独有的文件。
最后,关于分支的使用和注意事项,我做了几条简单的总结:
1. 远程分支中的内容是独立的,但是对于同一个机器的本地分支而言,所创建的资源文件都是共享的。但是如果本地分支中的内容,推送到对应的远程文件,那么该内容在其它分支将会不可见。
2. 每个分支都会保存自己的提交状态。
3. 分支面向最后的推送,而推送的内容不会影响其它分支下的同文件。但是一旦分支合并后,那么在参与合并的这几个分支下,该文件便会是相同的内容。
4. 当前的分支如果文件发生了变更时,是无法进行分支切换的,只有提交操作后才能够切换。
分支冲突
分支再合并的时候,有可能会产生冲突。
冲突的产生是因为在合并的时候,不同分支修改了相同的位置。所以在合并的时候git不知道那个到底是你想保留的,所以就提出疑问(冲突提醒)让你自己手动选择想要保留的内容,从而解决冲突。
错误提示如下:
[email protected] MINGW64 /d/work/test (master)
$ git merge feature
Auto-merging branch.txt
CONFLICT (content): Merge conflict in branch.txt
Automatic merge failed; fix conflicts and then commit the result.
[email protected] MINGW64 /d/work/test (master|MERGING)
$ git status
On branch master
Your branch is ahead of ‘origin/master‘ by 1 commit.
(use "git push" to publish your local commits)
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: branch.txt
no changes added to commit (use "git add" and/or "git commit -a")
解决冲突的方法也很简单,通过 git bash
自带的命令工具,修改冲突的文件内容即可,然后再重新提交,推送!
示例:
//第一步:
git checkout -b feature
vi readme.txt // 修改内容为 feature branch
git commit -a -m ‘commit‘
git checkout master
vi readme.txt //修改内容为 feature branch & master branch
git commit -a -m ‘commit‘
//第二步:
git merge feature
// 此时应该会提示冲突(CONFLICT)
git status
// 查看状态会看到更多的冲突提示信息。
//第三步:重新编辑冲突文件,然后提交 [略]
多人协作
分支可以很好的帮助我们进行多人协同开发,我们知道每个分支可以保存不同的提交结果,我们可以将正式版保存在一个分支下,将测试版的提交保存到另一个分支下,还可以让每个开发者都有自己的分支,每个开发者都在自己的分支上负责自己的工作,最后再合并分支,而这些分支的特性便为多人协同开发提供了坚强的支撑基础。
前面我们也学到了分支的常规操作,以及分支冲突的解决,这里我们就简单的来说下,多人协作下的分支开发是一种什么样的情况。
首先,在多人协作开发中,分支应该分为三种,一种是版本分支(master),专门用于发布稳定的版本,二是开发分支(dev),开发人员的代码会不断的合并到该分支,最后便是用户分支(user-*)每个开发者都会有自己的工作分支。
具体如图所示:
master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
多人协作时,大家都会往master和dev分支上推送各自的修改。
现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆:
$ git clone git@xxxxx.com/test.git
Cloning into ‘learngit‘...
remote: Counting objects: 46, done.
remote: Compressing objects: 100% (26/26), done.
remote: Total 46 (delta 16), reused 45 (delta 15)
Receiving objects: 100% (46/46), 15.69 KiB | 6 KiB/s, done.
Resolving deltas: 100% (16/16), done.
当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。不信可以用git branch命令看看:
$ git branch
* master
现在,你的小伙伴要在dev分支上开发,就必须创建远程origin的dev分支到本地,于是他用这个命令创建本地dev分支:
$ git checkout -b dev origin/dev
实际上,如果我们直接git chekout dev
也是可以自动创建,切换并关联dev分支的。
现在,他就可以在dev上继续修改,然后,时不时地把dev分支push到远程:
git commit -m "add /usr/bin/env"
总的来说,多人协作的工作模式通常是这样:
- 首先,可以试图用git push origin branch-name推送自己的修改;
- 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
- 如果合并有冲突,则解决冲突,并在本地提交;
- 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream branch-name origin/branch-name。
这就是多人协作的工作模式,一旦熟悉了,就非常简单。
bug 分支
首先让我们代入一个问题去思考!如何在一个多人协作的开发情况下去修复一个bug呢?我想,我们会想到的是,现本地 pull
一下,然后找到那个bug所在的文件,然后修改bug,最后在与dev分支合并分支。
是的,基本的步骤就是如此,但现实情况却总是那么骨感,比如你现在已经在你当前的分支上进行某项功能的开发,而且离你能完成的时间最少还需要1天,但是这个bug又需要立刻修掉,这种情况下你便不能直接用你当前的分支去修改,然后合并了,这会将你正在进行的工作也合并到dev,那么我们应该怎么去修复bug呢?
思路是一样的,这种情况下,我们依然通过分支去修bug,但是我们会在暂存当前分支的工作状态,然后新建并切换一个临时分支去修复bug,然后与dev进行分支合并,最终再恢复之前工作状态。
首先检查自己工作分支的状态
[email protected] MINGW64 /d/work/test (shentao)
$ git status
On branch shentao
Untracked files:
(use "git add <file>..." to include in what will be committed)
shenguotao2.txt
nothing added to commit but untracked files present (use "git add" to track)
发现当前分支有更改,但是目前不需要合并到开发环境,所以保存工作状态,建立临时分支
Administrator@LS1412PC0008 MINGW64 /d/work/test (shentao)
$ git stash
No local changes to save
Administrator@LS1412PC0008 MINGW64 /d/work/test (shentao)
$ git checkout -b issue-01
Switched to a new branch ‘issue-01‘
然后切换到临时分支,再去修改bug文件,这里我随便添加点内容,然后切换到dev分支
Administrator@LS1412PC0008 MINGW64 /d/work/test (issue-01)
$ vi shenguotao.txt
Administrator@LS1412PC0008 MINGW64 /d/work/test (issue-01)
$ git add *
Administrator@LS1412PC0008 MINGW64 /d/work/test (issue-01)
$ git commit -m ‘repair bug‘
[issue-01 af1d81f] repair bug
1 file changed, 1 insertion(+)
Administrator@LS1412PC0008 MINGW64 /d/work/test (issue-01)
$ git checkout dev
Switched to branch ‘dev‘
再将临时分支与dev分支进行分支合并,然后删除临时分支
[email protected] MINGW64 /d/work/test (dev)
$ git merge issue-01
Updating 587b031..af1d81f
Fast-forward
shenguotao.txt | 1 +
1 file changed, 1 insertion(+)
[email protected] MINGW64 /d/work/test (dev)
$ git branch -d issue-01
Deleted branch issue-01 (was af1d81f).
最后我们再切换到自己工作的分支,查看当前的分支状态是干净的,所以要恢复之前的工作状态
[email protected] MINGW64 /d/work/test (shentao)
$ git status
On branch dev
nothing to commit, working tree clean
[email protected] MINGW64 /d/work/test (shentao)
$ git stash pop
On branch dev
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: shenguotao2.txt
Dropped refs/[email protected]{0} (4323cae5c4f94b6df6c10b3abcacc71c0cf47f01)
这里的重点一是掌握通过分支解决bug的思路,二是掌握保存,删除,恢复分支工作状态的命令
** 保存当前分支的工作状态**git stash
** 查看当前分支的工作状态列表**git stash list
恢复分支最新的工作状态git stash pop
恢复分支指定的工作状态git stash appy [email protected]{0}
注:该命令可结合 git stash list
使用
删除分支状态git stash drop
标签
标签的概念
git 中的tag是标签的意思,它就像是指向某个commit的指针,用于跟某个具体的提交绑定在一起。
git 有commit,为什么还要引入tag?
“请把上周一的那个版本打包发布,commit号是6a5819e...”
“一串乱七八糟的数字不好找!”
如果换一个办法:
“请把上周一的那个版本打包发布,版本号是v1.2”
“好的,按照tag v1.2查找commit就行!”
所以tag 又类似于别名,因此在发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。
tag 与 branch的区别就在与一个是标识commit另一个则是存储commit,所以标签的数量是未知的,而分支的数量是可知的。
标签的常用命令
下面是关于tag的相关操作命令
创建标签
git tag <tagName>
注意:默认的是为最新的 commit 创建tag。
为指定的commit创建标签
git tag <tagName> [commitID]
//示例:git tag v0.9 6224937
创建带注释说明的标签
git tag -a <tagName> -m ‘note content‘
查看标签
git tag
查看指定标签的信息
git show <tagName>
删除标签
git tag -d <tagName>
推送标签到远程
git push origin <tagName>
将本地所有标签推送到远程
git push origin --tags
删除远程标签
git push origin :refs/tags/v0.9
自定义
用户信息与加密key
在我们本地的git中,可以配置使用者的相关信息
git config --global user.name "shenguotao"
git config --global user.email "[email protected]"
然后可以通过git config --list
去查看信息。
如果我们担心在拉取或推送远程仓库时,会有人冒充,那么便可以使用ssh方式,并将自己的公钥上传到指定服务器上,供第一次链接时进行验证使用。
首先生成本地电脑的私钥与公钥。
$ ssh-keygen -t rsa -C "[email protected]"
你需要把邮件地址换成你自己的邮件地址,然后一路回车即可,并无需设置密码。
如果一切顺利的话,可以在用户主目录里找到 .ssh
目录,里面有id_rsa
和 id_rsa.pub
两个文件,这两个就是SSH Key的秘钥对,id_rsa
是私钥,不能泄露出去,id_rsa.pub
是公钥,可以放心地告诉任何人。
最后,登录的你github,打开“Account settings”,“SSH Keys”页面:
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容便可。
为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。
最后友情提示,在GitHub上免费托管的Git仓库,任何人都可以看到喔(但只有你自己才能改)。所以,不要把敏感信息放进去。
命令语法着色
可以在config中配置相关命令,使语法着色,让命令更加突出。
git config --global color.ui true
文件忽略
对于不想提交的文件,我们可以建一个.gitignore文件来设置那些文件是要被忽略的。然后再把.gitignore文件提交上去即可。
一般.gitignore文件编写如下示例:
//.gitignore
example.png //忽略指定的文件
test //忽略整个目录
*.md //忽略所有的.md文件
如果想强制将.gitignore文件中设定的忽略文件提交到版本库中,可以使用以下命令:
git add -f <fileName>
如果想查看某个忽略声明在.gitignore文件的那一行,可以使用如下命令:
git check-ignore -v example.png
自定义命令
如果你觉得git默认的命令过于繁杂难以记忆,那么你可以自定义git的命令
git config --global alias.st status
其它的有:
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
说明:--global
用于设置该配置是否对全局都产生作用。
超推荐:
git config --global alias.lg "log --color --graph --pretty=format:‘%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset‘ --abbrev-commit"
修改配置文件
git中的配置信息是保存在配置文件中的,配置文件根绝作用范围不同,分为当前版本库的配置文件,其路径,就是:.git/config
,另一个则是全局的git配置文件,是对所有的版本库都起作用,它默认在操作系统的用户目录,文件名为 ‘.gitconfig‘ 。
cd .git
cat config
//-----
cd c:/Users
cat .gitconfig
在配置文件中,就可以修改 remote,alias等吧。
git常见问题
空的git仓库不能提交到远程库
[email protected] MINGW64 /d/work/test (master)
$ git push -u origin master
error: src refspec master does not match any.
error: failed to push some refs to ‘https://github.com/shenguotao2015/fdasfdsafsaf.git‘
解决方法:建一个readme文件!
git报错无法push
这是由于远程repository和我本地的repository冲突造成,通常发生在多人协作的开发过程中
$git push
To gitkt:abroadweb
![rejected] master -> master(non-fast-forward)
error:failed to push some refs to ‘gitkt:abroadweb‘
hint:Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: ‘git pull..‘) before pushing again ...
解决方法:
1.使用强制push的方法:
git push -u origin master -f
这样会使远程修改丢失,一般是不可取的
2.push前先将远程repository修改pull下来
git pull origin master
git push -u origin master
3.若不想merge远程和本地修改,可以先创建新的分支:
git branch [name]
git push -u origin [name]
多人协作的开发过程,一般推荐熟练使用分支功能来进行代码的托管,这样就会避免冲突的发生。
postBuffer 超出
error: RPC failed; curl 18 transfer closed with outstanding read data remaining
fatal: The remote end hung up unexpectedly
fatal: early EOF
fatal: unpack-objects failed
错误原因:
postBuffer是请求缓存区的意思,它的功能是当我们去 git clone
某个项目的时候,实际上git会有一个临时的缓存区去保存克隆的内容,当确定所有的内容都下载好后,才会保存到本地,但是如果这个缓存区设置的大小小于项目本身大小时,就会产生以上错误。
解决方法:
将postBuffer的大小设置的更大一些。
git config --global http.postBuffer 524288000
这里我们就讲postBuffer的缓存区设置为500MB
强烈推荐廖雪峰的git教程
http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
linux的常用命令
http://www.cnblogs.com/laov/p/3541414.html
vi的百度百科
http://baike.baidu.com/item/Vi/8987313
http://www.cnblogs.com/HCJJ/p/6650038.html