一、 Git介绍
Git是一款分布式版本控制系统,有别于CVS和SVN等集中式版本控制系统,Git可以让研发团队更加高效的协同工作。
每个git仓库都会存在一个.git文件夹,Git相关的所有版本历史记录文件/文件夹都在该目录下,git命令的操作实质上就是修改或读取.git文件夹下的相关文件。
对于Git,工作区和暂存区是两个很重要的概念,理解这两个概念有助于更好的理解git各个命令的工作原理。
暂存区,又被称为stage或index,就存在于.git文件夹下。
工作区,git仓库根目录下除.git文件夹之外的部分被称为工作区。
文件在Git中存在3种基本状态:
(1)已修改(modified) ——> 工作区
(2)已暂存(staged) ——> 暂存区(版本库)
(3)已提交(committed) ——> 本地数据目录(版本库)
除了这3种基本状态之外,Git库中的文件还会存在各种各样处于这3种状态之间的状态,例如新增未添加,添加却未被提交,提交后被修改。
二、Git安装及配置
1、安装git工具
apt-get install git
2、初始化git环境
第一次使用Git,需对git的一些变量进行配置,写入用户的相关信息。
<必配变量>
git config --global user.name “xxxxxx”
git config --global user.email "xxxxxx@xxx.com"
<选配变量——别名>
git config --global alias.st status
git config --global alias.ci commit
git config --global alias.co checkout
git config --global alias.br branch
git配置完成之后就可以正常使用git进行开发了。
三、Git基本操作
1、初始化
git init
通过该命令,我们可以把一个目录瞬间变为Git可以管理的版本库(又称为仓库)。这里多了一个.git目录,该目录就是Git用来管理版本库的。初始化为git库后,就可以对工作区的文件进行编辑。
注意:在还不熟悉各个文件具体功能的情况下不要手动修改.git中的文件,这样会破坏仓库,更不要删除它,否则该目录就是一个普通的目录。
2、暂存
git add <filename>
git add操作被称为暂存,可以理解为是为工作区的项目做一个快照,实质是将工作区中修改态的文件记录到.git目录下暂存区相关的文件中。
git add -A
该命令参数可以把所有没有被添加过的文件一次性全部添加到git库的暂存区,在文件量比较大的情况下可以使用该操作,但注意不要将不需要的文件添加到暂存区,不利于对比查看版本间代码的修改情况。
git rm <filename>
暂存文件不仅仅指添加文件,删除已经被添加过的文件,需要使用git rm命令将文件的删除状态更新的暂存区。
3、查看修改状态
git status
仓库中的文件可能存在各式各样的状态,例如有的是新增未添加,有的是添加却未被提交,有的是已提交被修改。git status命令可以将整体改动的信息显示出来,它可以让我们时刻掌握仓库的当前状态。
4、提交
git commit -m "remark"
git commit操作被称为提交,可以理解为将快照永久写入git仓库中,实质是将暂存区的修改记录到本地数据目录中。
git commit -a
该命令对本地所有变更的文件执行提交操作,包括本地修改和删除的文件,不包括未被版本库跟踪的文件。虽然这个命令可以简化操作,但会丢掉用户通过Git暂存区对提交内容进行控制的能力。
注意:不要使用git commit -a命令!
5、查看提交记录
git log
git log可以记录所有的git commit操作,每次git commit都会产生一条记录,每条记录共有四部分组成。
commit:记录本次操作的唯一标识符。实质是一个由SHA1计算出来的非常大的用十六进制表示的数字。
Author: 提交该版本的作者以及该作者的邮箱。
Date:提交的日期。
最后:最后一行就是关于此次提交的说明,也就是我们git commit -m的内容。
git log -p
该命令会显示每个开发版本代码直接的区别。
git log --pretty=oneline
该命令是将提交的信息在一行中显示出来,减少log显示的行数,方便查看。
6、版本对比
git diff
直接执行该命令,用于比较git add的文件与修改之前的差异,git diff与文件是否被git add有关,跟文件是否被git commit没有关系。
git diff 1e7fac4
命令之后加上commit的唯一标识,表示将当前git add的内容与指定版本进行比较,显示被修改了的内容。
git diff 1e7fac4 1egeb9f
命令之后加上两条commit的唯一标识,表示对比两次提交的内容,显示被修改了的文件的内容。
对比结果中“-”代表修改前的内容(红色部分,最后一次git add时候的内容),“+”代表修改后的内容(绿色部分,也就是当前内容),没有符号代表该内容未被修改(白色部分)。
7、版本切换
Git提供了git reset命令能够回滚到之前提交的某个代码版本,并将其设置为当前最新。可以使用HEAD参数回退到相对位置版本,也可以通过commit的唯一标识回退到指定版本。
git reset --hard HEAD^
HEAD代表的是当前版本,加个^,就表示当前版本之前的版本
git reset --hard HEAD~n
把HEAD^换成了HEAD~n,其中n代表回退n个版本
git reset --hard 1e7fac4
commit唯一标识字符串至少是4位,使用前7位作为默认位数,当然,如果前7位仍不唯一,就需要输入前8位了。
git reset 1e7fac4
如果不添加--hard参数,则只是将.git中的版本信息恢复到指定版本,工作区的文件并未被修改回之前的版本。
git rebase
该命令用于回到最新版本。
8、撤销修改
暂存区有两个优点,一个是“多次修改一次提交”,另一个是可以”撤销修改“,只要修改未被提交都可以通过Git命令撤销修改。
(1)git add之前
修改的内容还没有被git add到暂存区中,想要撤销,我们可以使用丢弃工作区的修改命令:
git checkout -- <filename>
(2)git add之后,git commit之前
文件被增加到了暂存区,需要先把修改撤出暂存区。
git reset HEAD <filename>
撤出了暂存区并没有撤销该修改,只是恢复到了git add之前的状态,需要继续使用丢弃工作区的修改命令来完全撤销该修改。
git checkout -- <filename>
9、撤销删除
想找回被删除的文件,此时跟找回修改前的文件一样,使用git checkout -- <file>。
但找回被删除的文件情况就有很多了。
(1)新文件,从未git commit(版本库中没有该文件)
1)文件未被git add
如果你新建了一个文件,还没有被git add,此时如果删除了这个文件,很遗憾,你无法通过git找回该文件。
2)文件被git add,未被git rm
如果新建的文件已经被git add过,之后又删除了,此时git status的时候就会看到deleted相关信息,此时的deleted信息还未被git rm,所以只要通过git checkout即可恢复。
3)文件被git add,又被git rm
如果新建的文件被git add过,又被git rm过,很遗憾的告诉你,这个文件已经丢失,你无法使用git来恢复了。
(2)文件被git commit过,版本库中有该文件的信息
1)文件未被git add
由于版本库中有该文件,即使文件未被git add,删除该文件也能找回来,但是找回的文件是最后一次入库的文件,最后一次入库到现在之间的修改操作都会全部丢失。
2)文件被git add,未被git rm
此时是最佳状况,我们不但能够使用git checkout恢复文件,而且能够保持文件的原貌。
3)文件被git add,又被git rm
跟状况一类似,虽然仍然可以找回文件,但是只能找回最后一次入库的状态,最后一次入库到现在的修改全部丢失了。
总结:文件被git add过,但没有被git rm是可以被完全恢复的,否则只能恢复到上一次commit时的状态,如果没有被commit过,那所有修改就会全部丢失。
10、查看历史命令
git reflog
记录命令历史,commit和reset都在被记录之列。
四、Git分支管理
分支可以理解为主干的映像,分支与主干在建立分支之前的部分完全一样,他们分别提交的互不影响。
1、建立分支
git branch 分支名
2、查看分支
git branch -a
3、切换分支
git checkout 分支名
4、合并分支
git merge 分支名 -m "remark"
在合并分支到主分支上时,需要先通过git checkout master命令换到主分支,然后执行该命令,并附上合并分支的log信息。
5、删除分支
git branch -d 分支名
-d参数表示会检查是否已经merge到其他分支,在分支已经合并到其他分支的情况下,能够删除该分支。
git branch -D 分支名
-D参数表示无条件删除该分支。
git branch -m <oldbr> <newbr>
-m参数表示会检查是否有重名
git branch -M <oldbr> <newbr>
-M参数表示不会检查是否重名,直接强制重命名
6、图形界面
gitk是一款能够通过图形化来标识分支的建立、合并和删除状态的,可以很方便的查看分支变化。
五、Git远程仓库
1、查看当前的远程仓库
git remote
该命令可以查看当前远程仓库名称。
git remote -v
该命令加上-V参数,可以查看当前远程仓库的具体信息。
2、添加远程仓库
git remote add <自定义远程仓库别名> <远程仓库实际地址>
该命令一般用在本地新建仓库,服务器上还不存在该仓库的任何信息,在将本地仓库推送到远程仓库时,需要通过该命令配置其上传到远程仓库的实际信息。
3、推送到远程仓库
git push <远程仓库名> <本地分支名>:<远程分支名>
git push命令用于将本地分支的更新推送到远程分支,如果不指定远程仓库名和分支的话默认提交到当前分支,第一次将本地仓库push到服务器时,需要指定远程仓库名以及分支名。
4、从远程仓库克隆
git clone gitmanager@GitServerIPAddr:projectName
使用git clone拉取的是带有项目名称的文件夹,并非直接拉取项目下的文件和文件夹,因此选择本地仓库位置的时候需要注意。
5、从远程仓库拉取
当远程仓库的分支超出了本地分支的提交,git push将提示不能推送,此时我们就需要首先拉取远程分支内容,然后和本地分支合并后才能git push。
(1)git fetch+git merge
git fetch origin master
git merge origin master
其中origin为远程仓库名,git fetch用于获取远程仓库的分支内容到本地,git merge则用于合并远程分支内容到本地分支,此时远程分支就和本地分支同步了。
(2)git pull
git pull origin master
git pull是git fetch和git merge两个命令的合体状态,只需要一个命令就能完成上述两步操作,只执行git pull能够拉取默认关联的分支,git push -u可以修改默认绑定的关联。一般我们只需要拉取远程仓库默认的origin的master分支,直接执行git pull即可。
6、删除远程仓库
git remote rm <仓库别名>
该命令能够删除不需要的远程仓库名,但删除时需要注意是否有项目使用该仓库别名。
六、协同使用Git
1、合并推送
在工作协同时,难免出现非快进式推送错误,如果在向服务器推送的过程中,由于他人率先推送了新的提交导致遭遇到非快进式推送的告警,应该如下操作:
用户1:修改, git add, git commit, git push
用户2:修改, git add, git commit, git push
用户2遇到非快推式错误而终止。
用户2: git pull origin master
(1)拉取时未产生冲突
用户2: git push
(2)拉取时产生冲突
用户2:执行pull的时候相当于git fetch和git merge,操作由于遇到冲突导致中断。
用户2:执行git diff命令查看冲突内容,“<<<<<<< HEAD” 到“=======”之间的是本地提交内容, “=======”到“>>>>>>>”之间是远程仓库的内容。
用户2:修改冲突文件, 并git commit提交后,完成冲突修改。
用户2: git push
2、分支的应用
在git版本库中创建分支的成本几乎为零,所以可以借助分支来提高开发的安全性和效率。分支的具体用法有如下几种:
(1) 创建个人工作分支,避免对主分支造成太多干扰,也方便与他人交流协作。
(2)当进行高风险工作时,创建一个实验性的分支,实验成功则可合并到主分支上。
(3)合并别人的工作的时候,最好创建一个临时的分支。
3、合并分支
既然创建了不同分支,那么在完成工作后就要将自己或者别人在分支上的工作合并到其他的分支上去。合并两个分支有如下两钟处理方式:
(1)使用分支合并命令
git checkout br_1
git merge HEAD br_2 -m “br_2 merge into br_1”
该方式是主动将br_2分支合并到br_1分支上,并完成commit提交。
(2)使用远程拉取命令
git checkout br_1
git pull . br_2
该方式是将分支br_2的内容拉取到br_1上进行合并,br_2在本地存在即可,不需要推送到远程仓库。
如果没有冲突的话,merge完成。如果有冲突的话,自动merge失败,则需要手动修改。git会提示哪个文件中有冲突,比如有如下冲突:
<<<<<<< HEAD:test.c
printf (“test1″);
=======
printf (“test2″);
>>>>>>> br_2:test.c
可以看到 ======= 隔开的上半部分,是 HEAD(即 br_1 分支,在运行 merge 命令时检出的分支)中的内容,下半部分是在 br_2分支中的内容。解决冲突的办法无非是二者选其一或者由你亲自整合到一起。在解决了所有文件里的冲突后,运行 git add将把它们标记为已解决(resolved)。因为一旦暂存,就表示冲突已经解决。
如果你想用一个有图形界面的工具来解决这些问题,不妨运行 git mergetool,它会调用一个可视化的合并工具并引导你解决所有冲突。
4、补丁文件交互
版本间可以通过git push和git pull命令来实现交互,这是git的主要交互模式,但并不是全部。使用补丁文件是另外一种交互方式。
git format-patch
该命令可以将提交批量转换为补丁。该命令参数是一个版本范围列表,会将包含在此列表中的提交一一转换为补丁文件,每个补丁文件包含一个序号并从提交说明中提取字符串作为文件名。
git format-patch -s HEAD~3..HEAD
-s参数,会在导出的补丁文件中添加当前用户的签名。这个签名只是将作者姓名添加到提交说明中而已。执行该命令后会将当前分支下的最近3个提交转换为补丁文件。
cat *.patch | git am
将补丁文件拷贝给对方,使用git am命令将补丁打到git本地库,完成文件的交互。
5、里程碑
创建里程碑命令git tag,如下用法:
git tag <tagname> [<commit>]
轻量级里程碑
git tag -a <tagname> [<commit>]
注释tag,打开编辑界面
git tag -m <tagname> [<commit>]
注释tag,直接命令行输入msg
git tag -s <tagname> [<commit>]
git tag -u <key-id> <tagname> [<commit>]
-s和-u都创建带GnuPG签名的里程碑,-u需要指明私钥进行签名
6、REPO
repo是google开发的用于管理android版本库的一个工具。repo并不是用于取代git,而是用python对git进行一定的封装,简化了对多个Git版本库的管理。对于repo管理的任何一个版本库,都需要Git命令进行操作。
简单使用过程:
(1)repo init命令, clone一个清单库
(2)清单库中的manifest.xml文件,罗列出多个版本库的clone方式,版本库地址和工作区地址
(3)对应关系,以及分支的对应关系
运行repo sync命令,开始同步,分别clone多个版本库到本地的工作区中。