参考网页:
https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013743256916071d599b3aed534aaab22a0db6c4e07fd0000
https://git-scm.com/book/zh/v2
本地目录 /d/git/web_learn
1. git的安装
下载地址如下:
https://git-scm.com/download/win
按照默认配置安装即可。
2. git的初始化
安装完成后,在开始菜单里找到“Git”->“Git Bash”,蹦出一个类似命令行窗口的东西,就说明Git安装成功!
安装完成后,还需要最后一步设置,在命令行输入:
git config --global user.name "zhousai"
git config --global user.email "[email protected]"
3.创建版本库
版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
所以,创建一个版本库非常简单,首先,选择一个合适的地方,创建一个空目录:Windows系统,为了避免遇到各种莫名其妙的问题,请确保目录名(包括父目录)不包含中文。
mkdir -p /d/git/web_learn
cd /d/git/web_learn
git init
3.1 把文件添加到版本库
VI 编辑一个文本文件:readme.txt
3.1.1 git add 告诉Git,把文件添加到仓库
git add windows时运行会出现以下warning:
出现该warning 的原因:
Uinx/Linux采用换行符LF表示下一行(LF:LineFeed,中文意思是换行);
Dos和Windows采用回车+换行CRLF表示下一行(CRLF:CarriageReturn LineFeed,中文意思是回车换行);
Mac OS采用回车CR表示下一行(CR:CarriageReturn,中文意思是回车)。
解决办法:
使用下面命令:git config core.autocrlf 来显示当前你的Git中采取哪种对待换行符的方式
此命令会有三个输出,“true”,“false”或者“input”
为true时,Git会将你add的所有文件视为文本问价你,将结尾的CRLF转换为LF,而checkout时会再将文件的LF格式转为CRLF格式。
为false时,line endings不做任何改变,文本文件保持其原来的样子。
为input时,add时Git会把CRLF转换为LF,而check时仍旧为LF,所以Windows操作系统不建议设置此值。
3.1.2 git commit -m "wrote a readme file"
告诉Git,把文件提交到仓库
git commit命令,-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。
git commit命令执行成功后会告诉你,
1 file changed:1个文件被改动(我们新添加的readme.txt文件);
2 insertions:插入了两行内容(readme.txt有两行内容)。
为什么Git添加文件需要add,commit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:
git add file1.txt
git add file2.txt file3.txt
git commit -m "add 3 files."
4. 时光穿梭机
4.1 git log 命令显示从最近到最远的提交日志
4.2 退回到上一个版本
4.2.1 先知道当前是哪个版本
get HEAD # 当前版本
get HEAD^ #上一个版本
get HEAD^^ #上上一个版本
get HEAD~100 # 往上100个版本
4.2.2 回退到上一个版本
git reset -hard HEAD
4.2.3 再回来到原来的版本
先查看原来版本的commit id,eg:
115b96e6659fe6ed4c7ec9b1bee6777bf0b979
执行
git reset --hard 115b96e6659fe6ed4c7ec9b1bee6777bf0b97928
即可回到原来
4.2.4如果忘记id,如下命令可以显示每步骤的操作及id信息
git reflog
这样可以拿到每步的id
4.3 工作区和缓存区
版本库(Repository):
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
git add 实际上就是把文件修改添加到暂存区
git commit 实际上就是把暂存区的所有内容提交到当前分支
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。
git status # 查看状态
Untracked files:表示文件还在缓存区
git commit -m "understand how stage works"执行后,会把缓存区的文件都提交到master 分支上。此时,工作区是干净的。
4.3 管理修改
第一次修改 -> git add -> 第二次修改 -> git add -> git commit
相当于把两次修改合并后一块提交了
如果不用git add到暂存区,那就不会加入到commit中。
git diff HEAD -- readme.txt #命令可以查看工作区和版本库里面最新版本的区别
## 4.4 撤销修改
```shell
git checkout -- readme.txt #不能将缓存区清空
git reset HEAD readme.txt # 可以清空缓存区
意思就是,把readme.txt文件在工作区的修改全部撤销,这里有两种情况:
一种是readme.txt自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;
一种是readme.txt已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。
总之,就是让这个文件回到最近一次git commit或git add时的状态。
git checkout -- file命令中的 -- 很重要,没有 --,就变成了“切换到另一个分支”的命令
4.4 删除文件
- 新建 test.txt
- git add test.txt
- git commit -m "new"
- rm test.txt
此时,目录下没有了test.txt
但是版本库里还有。 - git checkout test.txt 会将版本库里的test.txt 重新复制一份到本地目录。
- git rm -f test.txt会将版本库里的test.txt 强制删除,找不回来了。
5.远程仓库
5.1 添加远程仓库
GitHub 的网站可以作为远程仓库
5.1.1 本地用户主目录(cd ~)是否有.ssh目录
没有的话需要创建:
ssh-keygen -t rsa -C "[email protected]"
密码可以自己设置(z..m2..2)
其他都回车
5.1.2 登录github,Account settings”,“SSH Keys”页面:
然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:
https://github.com/settings/keys
最后成功是这种界面。
为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。
当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。
最后友情提示,在GitHub上免费托管的Git仓库,任何人都可以看到喔(但只有你自己才能改)。所以,不要把敏感信息放进去。
如果你不想让别人看到Git库,有两个办法,一个是交点保护费,让GitHub把公开的仓库变成私有的,这样别人就看不见了(不可读更不可写)。另一个办法是自己动手,搭一个Git服务器,因为是你自己的Git服务器,所以别人也是看不见的。这个方法我们后面会讲到的,相当简单,公司内部开发必备。
5.1.3 添加远程库
-
登录github ,新建 New repository
- 到本地 /d/git/web_learn 目录下
git remote add origin https://github.com/zslcm2012/web_learn.git # 将本地库和远程库关联起来
git push -u origin master #把本地库的所有内容推送到远程库上
git push origin master # 从现在起,只要本地作了提交,就可以把本地master分支的最新修改推送至GitHub
由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
5.2 从远程库克隆
现在,假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆。
- 首先,登陆GitHub,创建一个新的仓库,名字叫gitskills
- 勾选Initialize this repository with a README,这样GitHub会自动为我们创建一个README.md文件。创建完毕后,可以看到README.md文件
- 执行如下命令,clone
git clone https://github.com/zslcm2012/gitskills
如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。
GitHub给出的地址不止一个,还可以用https://github.com/michaelliao/gitskills.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。
使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。
6. 分支管理
创建一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。
6.1 创建与合并分支
截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。
HEAD严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD指向的就是当前分支。
每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长:
当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:
不过,从现在开始,对工作区的修改和提交就是针对dev分支了,比如新提交一次后,dev指针往前移动一步,而master指针不变:
假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:
# 1. 创建dev分支,然后切换到dev分支
git checkout -b dev
#git checkout命令加上-b参数表示创建并切换,相当于以下两条命令
git branch dev
git checkout dev
#2. 查看当前分支
git branch
# git branch命令会列出所有分支,当前分支前面会标一个*号。当前分支是dev
#3. 当前分支修改readme.txt,提交
#4.现在,dev分支的工作完成,我们就可以切换回master分支:
git checkout master
切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变
# 5.把dev分支的工作成果合并到master分支上
git merge dev
#git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。
#注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。
# 6. 合并完成后,就可以放心地删除dev分支了
git branch -d dev
因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。
6.2 解决冲突
#1.新建feature1分支
git checkout -b feature1
#2.在新分支下修改readme.txt
#3.提交
#4.切换到master分支
git checkout master
#5. 在master分支下修改readme.txt。但是两次修改的内容不一致
#6.提交
#7.执行合并。会出现冲突。但是还是会合并,只不过在不同之处会有标记
git merge feature1
git status # 也可以告诉我们充足的文件
#8.可以看到分支合并图
git log --graph --pretty=oneline --abbrev-commit
#9.手动修改后提交。最后以这个为准。
6.3.分支管理策略
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
#1.创建并切换dev分支
git checkout -b dev
#2.修改readme.txt文件,并提交一个新的commit
#3.切换回master
git checkout master
#4.准备合并dev分支,请注意--no-ff参数,表示禁用Fast forward;合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。
git merge --no-ff -m "merge with no-ff" dev
# 5. git log 看一下历史
git log --graph --pretty --abberv-commit
合并分支的原则:
首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。
所以,团队合作的分支看起来就像这样:
6.4 bug 分支
6.4.1 目前正在dev分支上工作,master分支上有了bug,需要去debug
6.4.2 把dev的工作存储起来
- 先查看一下dev工作区的状态:
git status - 将dev目前的工作保存起来
git stash - 再看一下dev工作区的状态
git status
现在dev工作区应该是干净的(除非有没有被Git管理的文件 - 回到master 分支,新建issue-101分支
git checkout master
git checkout -b issue-101 - debug完成之后提交
- 切换到master分支,并完成合并,最后删除issue-101分支
- 切换到dev继续工作
git checkout dev
git status
工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看:
git stash list #工作现场list - 需要恢复现场
有两种方法:
一是用git stash apply恢复,但是恢复后,stash内容并不删除,你需要用git stash drop来删除
另一种方式是用git stash pop,恢复的同时把stash内容也删了
git stash pop
你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash用命令:
git stash apply stash@{0}
小结:当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场
6.5 Feature分支
添加一个新功能时,需要新建一个feature分支,在上面开发,完成后,合并,最后,删除该feature分支。
6.6 多人协作
从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin。
要查看远程库的信息,用git remote -v
6.5.1 推送分支
推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上。
git push origin master
git push origin dev
并不是一定要把本地分支往远程推送:
- master分支是主分支,因此要时刻与远程同步
- dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步
- bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug
- feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发
6.5.2 抓取分支
多人协作时,大家都会往master和dev分支上推送各自的修改。
在本地另外创建了目录,模拟多人环境
当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。
所以要在dev上开发,要创建远程origin的dev分支到本地
git checkout -b dev origin/dev
小伙伴有了本地的dev分支,就可以修改,并push到远程。(git add;git commit -m "test";git push origin dev)
我也对dev分支的同一个文件进行了修改,也去push,但会报错
报错原因:因为你的小伙伴的最新提交和你试图推送的提交有冲突
解决办法:
先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推送。
直接用git pull 会失败,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置dev和origin/dev的链接。
git branch --set-upstream-to=origin/dev dev
再pull 就OK了
因此,多人协作的工作模式通常是这样:
- 首先,可以试图用git push origin
推送自己的修改 - 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并
- 如果合并有冲突,则解决冲突,并在本地提交
- 没有冲突或者解决掉冲突后,再用git push origin
推送就能成功! - 如果git pull提示no tracking information,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream-to
origin/ 。
小结
git remote -v #查看远程库信息
git push origin branch-name #从本地推送分支
git pull #如果推送失败,先抓取远程的新提交
git checkout -b branch-name origin/branch-name #在本地创建和远程分支对应的分支
git branch --set-upstream branch-name origin/branch-name #建立本地分支和远程分支的关联
#从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。
6.7 Rebase (变基)
6.7.1 merge 整合分支的原理:把两个分支的最新快照(C3 和 C4)以及二者最近的共同祖先(C2)进行三方合并,合并的结果是生成一个新的快照(并提交)。
6.7.2另一种合并方法:变基
- 原理:将分支master上的变化记录在临时文件。要在另一个分支(dev)上应用其变化,需要先切换到dev,再将master上的变化应用到dev
具体步骤如下:(将master分支上的变化应用到分支dev上)
vi rebase_02.txt
git add rebase_02.txt
git commit -m "first"
git checkout dev
git rebase master
git push origin dev
变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。
7.标签管理
7.1 创建标签
7.1.1 git commit 后直接添加标签
git add test_file
git commit -m "test tag"
git tag v_test01 # 对当前文件打标签
git tag #查看所有的标签列表
git show v_test01 #查看具体的标签内容
7.1.2 对已经提交的文件打标签
#先找到历史提交的commit id,然后打上就可以了
git log --pretty=oneline --abbrev-commit
git tag v0.9 38d8012 #对commit id为38d8012 的打标签
git tag -a v0.9 -m "test tag" #-a指定标签名,-m指定说明文字
7.2 操作标签
git tag -d v0.9 #删除标签
git push origin v1.0 #推送某个标签到远程
git push origin --tags #一次性推送全部尚未推送到远程的本地标签
git push origin :refs/tags/v0.9 #删除一个远程标签
8.分布式 Git - 分布式工作流程
8.1集中式工作流
集中式系统中通常使用的是单点协作模型——集中式工作流。 一个中心集线器,或者说仓库,可以接受代码,所有人将自己的工作与之同步。 若干个开发者则作为节点——也就是中心仓库的消费者——并且与其进行同步。
8.常用命令的汇总:
git pull -all #将一个分支上的所有文件拖到本地
https://github.com/miguelgrinberg/flasky/compare/2a..2b](https://github.com/miguelgrinberg/flasky/compare/2a..2b #比较2个版本的区别