文章目录
Git
git概念
Git是目前世界上最先进的分布式版本控制系统
知识点:集中式和分布式
一、集中式
先说集中式版本控制系统,版本库是集中存放在中央服务器的,而干活的时候,用的都是自己的电脑,所以要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。中央服务器就好比是一个图书馆,你要改一本书,必须先从图书馆借出来,然后回到家自己改,改完了,再放回图书馆。
集中式版本控制系统最大的毛病就是必须联网才能工作,如果在局域网内还好,带宽够大,速度够快,可如果在互联网上,遇到网速慢的话,可能提交一个10M的文件就需要5分钟,这还不得把人给憋死啊。
二、分布式
那分布式版本控制系统与集中式版本控制系统有何不同呢?首先,分布式版本控制系统根本没有“中央服务器”,每个人的电脑上都是一个完整的版本库,这样,你工作的时候,就不需要联网了,因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
和集中式版本控制系统相比,分布式版本控制系统的安全性要高很多,因为每个人电脑里都有完整的版本库,某一个人的电脑坏掉了不要紧,随便从其他人那里复制一个就可以了。而集中式版本控制系统的中央服务器要是出了问题,所有人都没法干活了。
在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能你们俩不在一个局域网内,两台电脑互相访问不了,也可能今天你的同事病了,他的电脑压根没有开机。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。
git安装
git安装具体可以参考:https://blog.csdn.net/lvkelly/article/details/54666868
在linux系统下,可以直接在命令窗口安装和使用git。但是,在windows系统下,想要达到同样的效果,可以安装git,使用git bash到达效果。具体安装步骤如下:
第一步:官网上下载git
网址:https://git-for-windows.github.io/
第二步:双击下载好的git安装包,弹出提示框,如下图:
第三步: 直接点击“next”进入下一步,选择安装路径,如下图:
第四步:选择好安装路径后,点击“next”进入下一步,弹出安装配置窗口,包括git命令行、git图形窗口等,如下图所示:
第五步:按照上述默认配置,直接点击“next”进入下一步,弹出“选择菜单开始文件”的窗口,如下图所示:
第六步:按照默认路径即可,直接点击“next”,进入下一步,进入“调整路径环境”窗口,如下图所示:
注:该窗口中,各项选项的意思为:
第一项:直接安装,不会配置git命令的环境变量。
第二项:会自动配置好git命令的环境变量。
第三项:git命令和unix工具命令都会添加到环境变量。
第七步:由于第一项不会配置环境变量,第三项会添加可选unix工具,基本没用,所以选第二项,然后点击“next”进入下一步,如下图所示:
第八步:选择第一项,同步下载更新文件时使用windows风格,提交文件时使用unix风格,尽量保证同步兼容。选好后,点击“next”进入下一步,如下图所示:
第九步:选择第一项,安装后git bash的终端使用起来比较好用。选好后,点击“next”进入下一步。如下图所示:
第十步:按照默认配置,直接点击“next”进入下一步。如下图所示:
第十一步:直接点击“install”进行安装即可,安装完成如下图所示:
到此为止,git成功安装。
git安装完成后,找到git bash,打开git bash,如下图所示:
创建版本库
什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
使用Notepad++创建一个TXT文件作为示例存放在仓库中
首先编写readme.txt
然后将该文件放在创建的仓库目录下 javaGit
在使用命令 $ git add readme.txt 将文件添加在仓库中
之后使用命令 $ git commit " " 在引号中可以填写本次提交的说明,也可以不写,
当然也可以向仓库添加多个文件后一起提交
版本回退
提交修改 git commit -m " "
现在对之前提交的readme.txt进行一些列的修改,再提交,如下
查看日志 git log 或者 git log -pretty=oneline
那么如果需要查看所有修改记录,需要使用到一个命令 $ git log 在githash中输入命令git log 就会显示出所有修改的内容,也就是每一次提交git commit -m “ ” 双引号中对本次修改的说明内容,具体如下图所示
或者也可以使用命令 git log –pretty=oneline 那么显示的内容比较整齐,如下图
回退上一版本 git reset --hard HEAD^
如果在提交之后不合适,需要返回到上一个版本,那么也是有办法的,可以使用 git reset命令,在这里需要介绍一些 HEAD ,它表示当前版本,上一个版本 HEAD^ ,上上一个版本 HEAD^^ ,如果是上100个版本那么就使用 HEAD~100,那么下面我们演示一下,如下图
那么此时仓库中的文件内容就是初次提交的文本内容
回到制定版本 git reset --hard 版本id
如果又想回到之前的最新版本了,那么还是可以的,但是必须使用最新版本的commit id
所以如果Githash没有关掉那么就可以直接使用commit id,如下图
此时在到仓库中看修改的文件,你会发现,确实是最新更新的版本
查看所有操作日志 git reflog
但是如果关掉了githash怎么办,没有commit id怎么办,不用着急,还可以使用命令找到commit id,那么可以使用 git reflog 此命令是用来显示所有操作的,也就是会记录你每一条操作的命令,如图:
工作区和暂存区
工作区(Working Directory)就是在电脑中我们所看到的目录,比如我们创建的版本库javaGit,
在工作区中有一个隐藏的目录 .git,它其实是在版本库中的,版本库中包含暂存区index也叫stage,以及git为我们创建的一个分支master,以及指向master的一个指针叫HEAD
下图是一个比较清晰的结构图可以作为参考。
[外链图片转存失败(img-snvY49kC-1566003619225)(/image17.png)]
我们把文件首先放在版本库中,其实就是将文件放在了工作区,
然后再通过命令 git add 将文件添加在暂存区stage或者叫index中
再通过命令 git commit 将文件添加在分支master上
查看该工作区文件状态 git status
现在我们试一下,
首先在工作区创建一个文本文件test,没有add 再将readme修改一次
那么我们在githash中 使用命令 git status 查看工作区文件的状态
如下图:
Readme.txt 被修改了 所以modified(修改的)
Test.txt 没有被添加过,所以Untracked(无路径的)
现在将readme.txt 和 Test.txt 文件都添加 git add,那么就是将文件添加在了暂存区,再进行git commit 那么就将两个文件都添加在了分支master上,最后查看状态 git status 如下图
也就是现在暂存区没有内容了。
管理修改
Git管理的是修改而不是文件本身,比如在文件readme中添加一句内容,删除一句内容,或者修改一句内容都属于修改。那么就是用一个例子来说明:
查看文件内容 cat <filename>
首先查看一下文件readme.txt中的内容如下图:
再对文件进行修改,再查看readme.txt的内容如下图:
将文件添加到缓存区 git add readme.txt再查看状态 $ git status
第一次修改之后显示缓存区存在readme.txt还没有提交,那么再进行第二次修改,查看修改后的内容如下图:
现在我们进行提交,再查看状态
发现第二次修改的还在工作库中没有被提交,而且添加的文件夹也没有提交,那么现在我们需要将readme.txt和文件夹添加在暂存区,再提交
只是将文件添加
将文件夹也添加进去
将文件和文件夹一起提交,再查看状态,此时显示没有可提交的内容了;
有上面的例子可以看出,git管理的是修改,而不是文件本身,只有将修改的内容添加在缓存区并且提交才可以,如果只是修改了,但是没有添加在缓存区,即使提交也不行
撤销修改
工作区撤销修改 git checkout – 文件名
如果我们在写代码的时候,修改错了,那么再add之前也就是代码还在工作区的时候可以使用 $ git checkout – (文件名) 撤销修改的部分与版本库一致,也就是上一次commit的内容一致;
修改的文件内容添加了一句,红色框的部分,结果发现修改错误,那么可以手动删除,也可以使用$ git checkout – readme.txt
如果在返现修改出错了,但是已经将文件 git add readme.txt那么可以使用git reset HEAD readme.txt将文件从缓存区删除掉,使文件回到工作区,再使用 $ git checkout – readme.txt将文件修改撤销。
如果是文件已经添加在缓存区并且还提交了commit了,但是没有推送到远程版本库,那么就可以使用之前的笔记中写到的版本回退,但是如果commit了 而且还推送到了版本库那么就惨了。。。。
添加远程库
登录github官网创建一个自己的账号,然后再创建一个新的仓库
成功以后就是下面的页面
然后将本地仓库与该远程仓库关联
如上面提示的可以使用命令完成
在这里注意:新仓库名称,我的是cxx_res 这样就将本地A_project这个文件目录与github远程仓库关联,然后需要将本地仓库的文件推送到远程仓库
这里会让输入github的用户名和密码
由于远程库是空的,我们第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。
提交成功显示如上
创建新的文件手动放在本地的仓库中,如需要将文件提交到远程仓库那么具体步骤如下
提交成功如下图
点击commit显示每一次提交
从远程仓库克隆代码
从远程仓库克隆代码的话就可以直接在Git Base Here 中执行命令 如下
$ git clone git@github.com:caoxiaoxiang/cxx_res.git
其中caoxiaoxiang 就是github的用户名 cxx_res是github仓库名称可以使要克隆的项目名称
但是在第一次克隆的时候遇到了一个问题:
出现错误:
执行完$ git clone git@github.com:caoxiaoxiang/cxx_res.git会显示
Permissiondenied (publickey).
fatal:Could not read from remote repository.
Pleasemake sure you have the correct access rights
and the repository exists.
那么通过查找资料找到了解决方式:
其实执行命令:git clone git@github.com:caoxiaoxiang/cxx_res.git 是没有问题的(不加–recursive参数),原因是由于你在本地(或者服务器上)没有生成ssh key,你可以在ternimal下执行:
cd ~/.ssh ls来查看是否有文件id_rsa以及文件id_rsa.pub,如下图所示:
下面记录下解决办法:
1.首先,如果你没有ssh key的话,在ternimal下输入命令:ssh-keygen -t rsa -C “youremail@example.com”, youremail@example.com改为自己的邮箱即可,途中会让你输入密码啥的,不需要管,一路回车即可,会生成你的ssh key。(如果重新生成的话会覆盖之前的ssh key。)
2.然后再ternimal下执行命令:
ssh -v git@github.com
最后两句会出现:
No more authentication methods to try.
Permission denied (publickey).
3.这时候再在ternimal下输入:
ssh-agent -s
然后会提示类似的信息:
SSH_AUTH_SOCK=/tmp/ssh-GTpABX1a05qH/agent.404; export SSH_AUTH_SOCK;
SSH_AGENT_PID=13144; export SSH_AGENT_PID;
echo Agent pid 13144;
4.接着再输入:
ssh-add ~/.ssh/id_rsa
这时候应该会提示:
Identity added: …(这里是一些ssh key文件路径的信息)
(注意)如果出现错误提示:
Could not open a connection to your authentication agent.
请执行命令:eval ssh-agent -s
后继续执行命令 ssh-add ~/.ssh/id_rsa,这时候一般没问题啦。若在这里没有成功
5.打开你刚刚生成的id_rsa.pub,将里面的内容复制,进入你的github账号,在settings下,SSH and GPG keys下new SSH key,title随便取一个名字,然后将id_rsa.pub里的内容复制到Key中,完成后Add SSH Key。
根据Git Base Here 中提示的路径可以找到.ssh文件目录
其实就是在c盘下,用户,用户名文件下
打开文件里面有三个文件
打开id_rsa.pub可以复制其中的全部内容
再按照上述步骤继续操作
6.最后一步,验证Key
在ternimal下输入命令:
ssh -T git@github.com
提示:Hi xxx! You’ve successfully authenticated, but GitHub does not provide shell access.
这时候你的问题就解决啦,可以使用命令 git clone --recursive git@github.com:caoxiaoxiang/cxx_res.git 去下载你的代码啦。
创建与合并分支
方法一:
我们创建dev
分支,然后切换到dev
分支
$ git checkout -b dev
Switched to a new branch 'dev'
git checkout
命令加上-b
参数表示创建并切换,相当于以下两条命令:
$ git branch dev
$ git checkout dev
Switched to branch 'dev'
然后,用git branch
命令查看当前分支
$ git branch
* dev
master
git branch
命令会列出所有分支,当前分支前面会标一个*
号。
然后,我们就可以在dev
分支上正常提交,比如对readme.txt
做个修改,加上一行,之后提交,然后切换到master分支
$ git checkout master
Switched to branch 'master'
把dev
分支的工作成果合并到master
分支上
$ git merge dev
Updating d46f35e..b17d20e
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
git merge
命令用于合并指定分支到当前分支。合并后,再查看readme.txt
的内容,就可以看到,和dev
分支的最新提交是完全一样的。
注意到上面的Fast-forward
信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master
指向dev
的当前提交,所以合并速度非常快。
当然,也不是每次合并都能Fast-forward
,我们后面会讲其他方式的合并。
合并完成后,就可以放心地删除dev
分支了:
$ git branch -d dev
Deleted branch dev (was b17d20e).
删除后,查看branch
,就只剩下master
分支了:
$ git branch
* master
方法二:
通常,合并分支时,如果可能,Git会用Fast forward
模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward
模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
下面我们实战一下--no-ff
方式的git merge
:
首先,仍然创建并切换dev
分支:
$ git checkout -b dev
Switched to a new branch 'dev'
在dev上提交代码,然后我们切换回master
:
$ git checkout master
Switched to branch 'master'
准备合并dev
分支,请注意--no-ff
参数,表示禁用Fast forward
:
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
因为本次合并要创建一个新的commit,所以加上-m
参数,把commit描述写进去。
合并后,我们用git log
看看分支历史:
$ git log --graph --pretty=oneline --abbrev-commit
* e1e9c68 (HEAD -> master) merge with no-ff
|\
| * f52c633 (dev) add merge
|/
* cf810e4 conflict fixed
...
创建标签
发布一个版本时,我们通常先在版本库中打一个标签(tag),这样,就唯一确定了打标签时刻的版本。将来无论什么时候,取某个标签的版本,就是把那个打标签的时刻的历史版本取出来。所以,标签也是版本库的一个快照。
Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针(跟分支很像对不对?但是分支可以移动,标签不能移动),所以,创建和删除标签都是瞬间完成的。
Git有commit,为什么还要引入tag?
“请把上周一的那个版本打包发布,commit号是6a5819e…”
“一串乱七八糟的数字不好找!”
如果换一个办法:
“请把上周一的那个版本打包发布,版本号是v1.2”
“好的,按照tag v1.2查找commit就行!”
所以,tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。
在Git中打标签非常简单,首先,切换到需要打标签的分支上:
$ git branch
* dev
master
$ git checkout master
Switched to branch 'master'
然后,敲命令git tag <name>
就可以打一个新标签:
$ git tag v1.0
可以用命令git tag
查看所有标签
$ git tag
v1.0
默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,比如,现在已经是周五了,但应该在周一打的标签没有打,怎么办?
方法是找到历史提交的commit id,然后打上就可以了:
$ git log --pretty=oneline --abbrev-commit
12a631b (HEAD -> master, tag: v1.0, origin/master) merged bug fix 101
4c805e2 fix bug 101
e1e9c68 merge with no-ff
f52c633 add merge
cf810e4 conflict fixed
5dc6824 & simple
14096d0 AND simple
b17d20e branch test
d46f35e remove test.txt
b84166e add test.txt
519219b git tracks changes
e43a48b understand how stage works
1094adb append GPL
e475afc add distributed
eaadf4e wrote a readme file
比方说要对add merge
这次提交打标签,它对应的commit id是f52c633
,敲入命令:
$ git tag v0.9 f52c633
再用命令git tag
查看标签
$ git tag
v0.9
v1.0
注意,标签不是按时间顺序列出,而是按字母排序的。可以用git show <tagname>
查看标签信息:
$ git show v0.9
commit f52c63349bc3c1593499807e5c8e972b82c8f286 (tag: v0.9)
Author: Michael Liao <askxuefeng@gmail.com>
Date: Fri May 18 21:56:54 2018 +0800
add merge
diff --git a/readme.txt b/readme.txt
...
可以看到,v0.9
确实打在add merge
这次提交上。
还可以创建带有说明的标签,用-a
指定标签名,-m
指定说明文字:
$ git tag -a v0.1 -m "version 0.1 released" 1094adb
用命令git show <tagname>
可以看到说明文字:
$ git show v0.1
tag v0.1
Tagger: Michael Liao <askxuefeng@gmail.com>
Date: Fri May 18 22:48:43 2018 +0800
version 0.1 released
commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (tag: v0.1)
Author: Michael Liao <askxuefeng@gmail.com>
Date: Fri May 18 21:06:15 2018 +0800
append GPL
diff --git a/readme.txt b/readme.txt
...
操作标签
如果标签打错了,也可以删除:
$ git tag -d v0.1
Deleted tag 'v0.1' (was f15b0dd)
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
如果要推送某个标签到远程,使用命令git push origin <tagname>
:
$ git push origin v1.0
Total 0 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
* [new tag] v1.0 -> v1.0
或者,一次性推送全部尚未推送到远程的本地标签:
$ git push origin --tags
Total 0 (delta 0), reused 0 (delta 0)
To github.com:michaelliao/learngit.git
* [new tag] v0.9 -> v0.9
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
$ git tag -d v0.9
Deleted tag 'v0.9' (was f52c633)
然后,从远程删除。删除命令也是push,但是格式如下:
$ git push origin :refs/tags/v0.9
To github.com:michaelliao/learngit.git
- [deleted] v0.9
Tortoisegit
需要自己创建一个文件目录作为git仓库
通过下图方式从指定的路径即远程仓库获取代码:
再输入url,指定本地创建的文件目录:此时git目录是http形式的
再点击ok,就可以将代码获取到指定的代码存放路径
当我们修改了一段代码,需要将代码提交到版本库中,一旦创建了版本库代码就要放在版本库里才能使用github去操作
提交代码右击版本库文件目录,选择git commit
然后填写日志信息,
点击提交之后有弹窗
可以点击关闭,也可以推送push,如果是推送的话又会有弹窗,点击确定
如果是其他同事写完一段代码提交之后,我需要获取,那么就需要pull操作
然后选择相应的远端分支
注意:若提交时注释写的不合适想重新修改,那么可以通过命令
–》 git commit --amend
–》i 开始插入即可以编辑
–》修改注释
–》ESC
–》:wq 保存并退出
简单的TortoiseGit的使用
获取本地源码
Git clone—》输入链接—》点击确定
提交本地代码
Git Commit —》同步到云端push
注意:
1.在提交的时候不要提交多余的文件,例如在运行单元测试产生的文件,以及个人本地运行产生的一些文件
2.提交的时候只是提交修改的和新增的文件
3.若是多人开发可能别人提交了代码,防止代码被覆盖,或者需要解决冲突建议先commit,再fetch,再rebase,若此时代码有冲突时在项目文件名上出现黄色三角警告,解决完冲突需要再commit一次,然后再push
4.或者先commit,然后pull,若此时代码有冲突时在项目文件名上出现黄色三角警告,解决完冲突需要再commit一次,然后再push
拉取最新代码
Pull
或者 Fetch + Rebase
Fetch是获取代码,Rebase是合并,此时就会显示冲突,需要解决冲突,再push
注意:
使用命令提交代码分为三步:add commit push
Add是将代码添加在暂存区;commit提交到本地仓库;push推送到远程仓库
分支使用
主分支:master:用于发布版本
开发分支:develop:日常开发分支,需要合并到master分支
临时性分支:功能分支feature,预发布分支release,修复bug分支fixbug
功能分支feature是从功能分支出来的,开发完成后再合并的develop后即可删除,名字采用feature-* 的形式命名;
预发布分支release在正式发布前,需要一个预发布的版本测试。从develop出来,用完后合并到develop分支和master分支;
修改bug分支fixbug从master拉出,完成后合并到master并同步到develop分支
分支的创建
切换分支
切换到新的分支需要执行push操作,在对话框中保持远程分支空白,点击ok,则将在远程分支创建了新的分支
其他成员切换到新的分支开发,首先pull操作,然后进行切换分支
分支合并
注意:合并完分支要push
解决冲突
场景一:
User1:有新的提交
User2:没有pull—》写新代码—》pull—》提示有冲突
解决方法一:
–》stash save(把自己的代码隐藏起来)—》重新pull—》stash pop(把存起来的隐藏代码取出来)—》代码文件显示冲突—》右键选择edit conficts(编辑冲突)解决后点击编辑页面的mark as resolved(标记为解决)commit&push
解决方法二:(尽量少使用,这种方法的优点是在在原编辑器里处理冲突,代码逻辑看得更清楚一些)
-> stash save(把自己的代码隐藏存起来) -> 重新pull -> stash pop(把存起来的隐藏的代码取回来 ) -> 代码文件会显示冲突 -> 右键选择resolve conflict -> 打开文件解决冲突 -> commit&push
解决方法三:首先通过Fetch获取代码,再合并代码Rebase,那么此时就会显示冲突部分,需要解决冲突再commit,push
场景二:
user0 有新提交
user1 没有pull -> 写新代码 -> commit&push -> 提示有冲突
解决办法一:
-> pull -> 代码文件会显示冲突 -> 右键选择edit conficts,解决后点击编辑页面的 mark as resolved -> commit&push
GitFlow
gitflow工作流的简单操作执行流程
https://blog.csdn.net/zsm180/article/details/75291260#11-master%E5%88%86%E6%94%AF
此博客是本博主在通过上网学习git过程中找到的几个不错的学习教程和博客整理的。参考地址:
https://www.liaoxuefeng.com/wiki/896043488029600
https://www.cnblogs.com/Sungeek/p/9152223.html
https://blog.csdn.net/zhouyingge1104/article/details/42393955
https://www.cnblogs.com/wmr95/p/7852832.html