Git简介
1、Git的诞生:
很多人都知道,Linus(李纳斯)在1991年创建了开源的Linux,从此Linux系统不断发展,已经成为最大的服务器系统软件了,当初使用CVS和SVN进行管理,这些集中式的版本控制系统不但速度慢,而且必须联网才能使用,因此Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!一个月之内,Linux系统的源码已经由Git管理了!牛是怎么定义的呢?大家可以体会一下
Git版本库
1、创建版本库:
mkdir learngit cd learngit pwd
把这个目录变成Git可以管理的仓库:git init
当前目录下多了一个.git的目录,这个目录是Git用来跟踪管理版本库的
2、把文件添加到版本库
首先创建一个readme.txt文件
把文件添加到仓库: git add readme.txt
执行上面的命令,没有任何显示,这就对了,Unix的哲学是“没有消息就是好消息”,说明添加成功
把文件提交到仓库:git commit -m "wrote a readme file"
-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录
为什么Git添加文件需要add,commit一共两步呢?
因为add 是添加到暂存区(仅自己可见这次变动),而commit是提交到分支
3、版本回退
查看结果:git status
查看具体修改了什么内容:git diff readme.txt
git diff顾名思义就是查看difference,显示的格式正是Unix通用的diff格式
查看提交历史记录:git log --pretty=oneline
git log命令显示从最近到最远的提交日志
需要友情提示的是,你看到的一大串类似1094adb…的是commit id(版本号),和SVN不一样,Git的commit id不是1,2,3……递增的数字,而是一个SHA1计算出来的一个非常大的数字,用十六进制表示
回退到上一个版本:git reset --hard HEAD^
在Git中,用HEAD表示当前版本,也就是最新的提交1094adb…(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD,上上一个版本就是HEAD,当然往上100个版本写100个比较容易数不过来,所以写成HEAD~100
查看git文件版本:cat readme.txt
查看每次使用过的指令:git reflog
4、文件提交原理
工作区:代码存放的目录
版本库:隐藏在.git目录下
首先我们的代码是存放在工作区中,工作区里有个.git文件夹叫做版本库,版本库里存放了好多东西,其中最重要的就是称为stage的暂存区,还有git为我们创建的第一个分支master,以及指向master的一个指针叫做HEAD。
首先我们操作add命令是把代码放置到stage暂存区,操作commit命令后把代码提交到HEAD指向的某个分支。
你可以简单理解为,需要提交的文件修改通通放到暂存区,然后一次性提交暂存区的所有修改。
为什么Git比其他版本控制系统设计得优秀?
因为Git跟踪并管理的是修改,而非文件。
比如:第一次修改 -> git add -> 第二次修改 -> git commit
再操作git status命令后会发现提示没有提交,让重新add,然后commit。
你看,我们前面讲了,Git管理的是修改,当你用git add命令后,在工作区的第一次修改被放入暂存区,准备提交,但是在工作区的第二次修改并没有放入暂存区,所以,git commit只负责把暂存区的修改提交了,也就是第一次的修改被提交了,第二次的修改不会被提交。
提交后,用git diff HEAD -- readme.txt命令可以查看工作区和版本库里面最新版本的区别
比较工作区和暂存区:git diff filename
比较工作区和版本库的最新版本:git diff HEAD -- filename
5、撤销修改:git checkout -- filename
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态
一种是readme.txt已经添加到暂存区后,又作了修改,现在撤销修改就回到添加到暂存区后的状态
命令中的–很重要,没有–,就变成了“切换到另一个分支”的命令
6、删除文件:git rm filename
首先新增一个文件,并git提交,然后执行删除命令,操作git status会发现文件被删除,但是该文件还存在版本库中,并未真正删除
一种是你误删的文件可以操作命令:git checkout -- filename进行恢复
一种是真正的删除,此时需要从版本库中删除,可以先删除后再操作git commit命令
远程仓库
1、本地关联远程仓库:
远程仓库是Git区别于SVN的杀手级功能之一
本地仓库关联GitHub并提交内容
1、首先登陆GitHub,点击右上角的加号创建新的仓库;
添加新的名字后点击提交
然后点击https,之后复制里面的内容
在本地的仓库下运行命令关联远程:git remote add origin githubPath
如果本地仓库已经关联远程仓库会报如下错误:
fatal: remote origin already exists.
意思是已经关联远程仓库,需要移除关联仓库,运行如下命令:git remote rm origin
运行命令查看是否关联:git remote -v,然后再重新运行上面的命令
把本地库的所有内容推送到远程库上:git push -u origin master
第一次关联的时候会提示让输入用户名和密码,该用户名就是github的登录时的用户名和密码,把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。
由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
本地修改后提交:git push origin master
2、从远程库克隆到本地
步骤同上,在创建仓库的时候要勾选上初始化仓库,
2、从远程库克隆到本地
步骤同上,在创建仓库的时候要勾选上初始化仓库,
此时在本地库会发现远程库已克隆。
分支管理
1、分支简介
分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另一个你正在另一个平行宇宙里努力学习SVN
如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了Git又学会了SVN!
2、创建与合并分支
一开始时候创建的master分支就是一条线,Git用master指向最新的提交,再用HEAD指向master,每次提交,master分支都会向前移动一步,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,假如我们在dev上的工作完成了,就可以把dev合并到master上,相当于把master指向dev,此时甚至可以删除dev分支
创建dev分支:git branch dev
切换dev分支:git checkout dev
查看当前分支:git branch
git branch命令会列出所有分支,当前分支前面会标一个*号。
创建dev分支并切换到dev:git switch -c dev
合并分支:git merge dev
当我们在dev分支上新增修改后内容后,切回到master分支,执行合并分支命令后,master分支的内容就和dev的内容一致了
删除dev分支:git checkout -b dev
3、解决冲突
当dev分支和master分支修改了相同文件的内容后,进行分支合并的时候,会产生代码冲突,执行git status命令会告诉我们冲突的文件,Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后再提交即可解决冲突
创建新的feature1分支:git checkout -b feature1
修改readme.txt最后一行,改为:Creating a new branch is quick AND simple.
在feature1分支上提交:git add readme.txt git commit -m "AND simple"
切换到master分支:git checkout master
在master分支上把readme.txt文件的最后一行改为:Creating a new branch is quick & simple.
之后提交:git add readme.txt
git commit -m "& simple"
合并分支:git merge feature1
果然冲突了!Git告诉我们,readme.txt文件存在冲突,必须手动解决冲突后再提交
git status也可以告诉我们冲突的文件:git status
我们可以直接查看readme.txt的内容:
Git用<<<<<<<,=======,>>>>>>>标记出不同分支的内容,我们修改如下后保存:
Creating a new branch is quick and simple.
再提交即可。
分支管理策略:
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
强制禁用Fast forward模式:git merge --no-ff -m "merge with no-ff" dev
在合并分支时添加–no-ff参数,,表示禁用Fast forward。
合并后,我们用git log看看分支历史: git log --graph --pretty=oneline --abbrev-commit
可以看到,不使用Fast forward模式,merge后就像这样:
Bug分支:当前分支出现bug,新建一个临时分支修复bug,修复后合并分支,删除临时分支。
当前分支正在开发,突然出现一个bug,该怎么修复?
1、git stash:把当前工作现场“储藏”起来,等以后恢复现场后继续工作
2、假定需要在master分支上修复,就从master创建临时分支issue-101,修改提交合并分支。
git stash list:查看工作现场
git stash apply:恢复工作现场
git stash drop:删除工作现场
git stash pop:恢复的同时删除工作现场
git cherry-pick 4c805e2:复制特定的提交到当前分支
Feature分支:开发新功能,新建一个feature分支,完成后合并,然后删除该分支。
多人协作:
远程仓库的默认名称是origin
git remote:查看远程库的信息
git remote -v:查看更详细的信息,可以抓取和推送的origin的地址
推送分支:把该分支上的所有本地提交推送到远程库
git push origin dev:把本地分支往推送到远程分支
抓取分支:
git clone git@github.com:michaelliao/learngit.git:克隆远程代码
git checkout -b dev origin/dev:创建远程origin的dev分支到本地
同事两个同时修改一个文件时会发生冲突,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送。
git branch --set-upstream-to=origin/dev dev:设置dev和origin/dev的链接
Rebase:
git rebase:把分叉的提交历史变成一条直线
标签管理:发布一个版本时,我们通常先在版本库中打一个标签(tag),将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。
创建标签:首先,切换到需要打标签的分支上,然后再打标签。
git tag v1.0:打一个新标签
git tag:查看所有标签
git tag v0.9 f52c633:对某次提交打标签
git show v0.9:查看标签信息
git tag -a v0.1 -m “version 0.1 released” 1094adb:创建带有说明的标签
操作标签
git tag -d v0.1:删除标签
git push origin v1.0:推送某个标签到远程
git push origin --tags:推送所有标签到远程
删除远程标签:
1、先从本地删除:git tag -d v0.9
2、然后,从远程删除:git push origin :refs/tags/v0.9
修改git分支名称
场景:将旧分支oldbranch 改为新分支 newbranch
步骤:
1、将本地分支oldbranch切一个新分支到本地
git branch -m oldbranch newbranch
2、删除远程分支
git push --delete origin oldbranch
3、将本地新分支推送到远程
git push origin newbranch