一、git是什么?
git简单来说就是一款功能强大容易使用的版本管理控制工具。
若你理解了 Git 的思想和基本工作原理,用起来就会知其所以然,游刃有余。 在学习 Git 时,请尽量理清你对其它版本管理系统已有的认识,如 CVS、Subversion 或 Perforce, 这样能帮助你使用工具时避免发生混淆。尽管 Git 用起来与其它的版本控制系统非常相似, 但它在对信息的存储和认知方式上却有很大差异,理解这些差异将有助于避免使用中的困惑。
二、git的三种状态
Git 用三种形式表示文件的状态,已修改(modified) 、 已暂存(staged)、已提交(committed)
已修改表示修改了文件,但还没保存到数据库中。
已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
已提交表示数据已经安全地保存在本地数据库中
这会让我们的 Git 项目拥有三个阶段:工作区、暂存区以及 Git 目录。
工作目录、暂存区域以及 Git 仓库。
工作区是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。
暂存区是一个文件,保存了下次将要提交的文件列表信息,一般在 Git 仓库目录中。 按照 Git 的术语叫做“索引”,不过一般说法还是叫“暂存区”。
Git 仓库目录是 Git 用来保存项目的元数据和对象数据库的地方。 这是 Git 中最重要的部分,从其它计算机克隆仓库时,复制的就是这里的数据。
基本的 Git 工作流程如下:
在工作区中修改文件。
将你想要下次提交的更改选择性地暂存,这样只会将更改的部分添加到暂存区。
提交更新,找到暂存区的文件,将快照永久性存储到 Git 目录。
如果 Git 目录中保存着特定版本的文件,就属于 已提交 状态。 如果文件已修改并放入暂存区,就属于 已暂存 状态。 如果自上次检出后,作了修改但还没有放到暂存区域,就是 已修改 状态。在 Git 基础open in new window 一章,你会进一步了解这些状态的细节, 并学会如何根据文件状态实施后续操作,以及怎样跳过暂存直接提交。
三、git保证完整性
Git 中所有的数据在存储前都计算校验和,然后以校验和来引用。 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 这个功能建构在 Git 底层,是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件,Git 就能发现。
Git 用以计算校验和的机制叫做 SHA-1 散列(hash,哈希)。 这是一个由 40 个十六进制字符(0-9 和 a-f)组成的字符串,基于 Git 中文件的内容或目录结构计算出来。 SHA-1 哈希看起来是这样:
24b9da6552252987aa493b52f8696cd6d3b00373
Git 中使用这种哈希值的情况很多,你将经常看到这种哈希值。 实际上,Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名。
四、git的安装和使用
不同系统的安装方式
windows安装:进入网站https://git-scm.com/下载安装,然后在cmd命令行配置
安装直接下一步就好,如果不想装在c盘就自己选择就好。
ubuntu配置:apt-get install git
centos配置:yum install git
2.初始化git
第一步:安装完成之后可以打开cmd窗口输入以下命令配置你的全局用户名信息
git config --global user.name "用户名"
git config --global user.email "邮箱"
配置成功之后可以输入命令查看配置信息
git config --list
Git 自带一个 git config 的工具来帮助设置控制 Git 外观和行为的配置变量。在 Windows 系统中,Git 会查找 $HOME 目录下(一般情况下是 C:\Users\$USER )的 .gitconfig 文件。
你可以通过以下命令查看所有的配置以及它们所在的文件:
git config --list --show-origin
3.创建一个git目录体验一下流程
自己可以在桌面创建一个文件夹作为本地目录,之后进入文件夹鼠标右键点击---》git bash here
// 初始化 仓库
git init// 添加一个文件
touch a.txt
echo 123> a.txt// 提交至缓存区(添加多个可以使用命令 git add .)
git add a.txt// 提交到本地仓库
git commit -m '版本描述信息'
4.基础命令
//查看git当前的状态(修改或暂存和提交)
git status//将修改的文件添加到暂存区
git add 指定文件名 或者 使用.(表示多个文件)//将缓冲区的内容提交到git仓库
git commit -m '版本描述信息'
如果代码报错:git上传代码报错
-The file will have its original line endings in your working directory,
原因是因为文件中换行符的差别导致的。
这里需要知道CRLF和LF的区别:
windows下的换行符是CRLF而Unix的换行符格式是LF。git默认支持LF。
上面的报错的意思是会把CRLF(也就是回车换行)转换成Unix格式(LF),这些是转换文件格式的警告,不影响使用。一般commit代码时git会把CRLF转LF,pull代码时LF换CRLF。可以输入以下命令解决:
git rm -r --cached .
git config core.autocrlf false
然后重新上传代码即可。
为true时,Git会将你add的所有文件视为文本问价你,将结尾的CRLF转换为LF,而checkout时会再将文件的LF格式转为CRLF格式。
为false时,line endings不做任何改变,文本文件保持其原来的样子。
为input时,add时Git会把CRLF转换为LF,而check时仍旧为LF,所以Windows操作系统不建议设置此值。
//查看git历史操作记录
git log//有图形样式
git log --graph//精简样式,一行显示一个快照记录
git log --decorate --oneline
5.版本回退、版本对比、文件删除与忽略
//版本回退reset,(一个~代表回退到上一个版本,~有多少个就回退多少个版本)
git reset head~
4种回退类型
--hard : 回退版本库,暂存区,工作区。(回滚后,本地代码就是你回退版本的代码)
--mixed: 回退版本库,暂存区。(--mixed为git reset的默认参数,即当任何参数都不加的时候的参数,
回滚后,不仅移动了本地库的指针,同时暂存区的东西也没了,意思就是你上次添加到暂存区的文件没了)
--soft: 回退版本库。(回滚后,仅仅是把本地库的指针移动了,暂存区和你本地的代码是没有做任何的改变。
而你上次改动已提交committed到本地库的代码显示是绿色即未提交的状态(一般都用这个))
--keep:在idea中可以选择的方式,回滚后,本地代码就是你回退版本的代码,而暂存区是没有做任何改变的,换句话说就是:本地代码是当前回退的版本代码(类似于hard操作),但是还没有提交的更改内容依旧还在(跟hard操作的区别)
//表示硬回退到上一个版本
git reset --hard head~//查看git每一次操作的版本id号
git reflog//表示硬回退到指定快照id号的版本(reset使用id号可以回滚也能回到最新的版本)
git reset --hard id号//版本对比,查看暂存区与工作树的内容有哪些不同
git diff//工作树和最新提交对比
git diff head//两个(id号)历史快照对比
git diff 5da78a4 c7c0e3b//暂存区和指定快照对比
git diff --cached c7c0e3b//手动删除文件恢复命令
git checkout a.txt//永久删除文件a.txt(可以使用版本回退(git reset --hard 快照id号)恢复)
git rm a.txt//文件改名
git mv b.txt c.txt//创建一个.gitignore 文件,并让 Git 忽略所有 .temp 后缀的文件:
echo *.temp > .gitignore//将gitignore也忽略
echo .gitignore > gitignore
6.创建和切换分支
分支是什么?
简单理解分支就是在一个完整的项目模块中独立出来一个模块进行开发,等开发完成没问题之后再合并到原来的项目模块中,为了保险起见不破坏原有的模块所以要创建分支。默认主分支为master
//创建分支,一般命名feature-xxx
git branch 分支名//切换分支
git checkout feature-xxx//创建新的分支并切换
git checkout -b feature-xxx//合并分支(注意当前选择的分支与哪个分支合并)
git merge feature-xxx
解决分支冲突
当一个子分支的使命完结之后,它就应该回归到主分支中去。
当两个分支进行合并的时候,都对同一个文件进行修改就会发生冲突,git不知道要采用哪个,所以需要你自己来决定,解决冲突之后分支才能合并。
//合并分支(注意当前分支要跟哪个分支合并)
git merge feature-xxx//合并成功之后要add一下添加到暂存区再提交
git add .
git commit -m 'mergeOK'
注意:如果试图删除未合并的分支,Git 会提示你“该分支未完全合并,如果你确定要删除,请使用 git branch -D 分支名 命令。
//删除分支
git branch -d feature-xxx
变基
当我们开发一个功能时,可能会在本地有无数次commit,而你实际上在你的master分支上只想显示每一个功能测试完成后的一次完整提交记录就好了,其他的提交记录并不想将来全部保留在你的master分支上,那么rebase将会是一个好的选择,他可以在rebase时将本地多次的commit合并成一个commit,还可以修改commit的描述等
// 合并前两次的commit
git rebase -i head~~//在指定的id号版本合并到最新的commit版本
git rebaser -i id快照号
五、远程版本控制管理仓库
github、码云gitee、gitlab(独立部署仓库)可以分布式进行管理,如 CVS、Subversion 或Perforce目前用的很少了。
git网址:https://gitee.com/
基本上操作原理都差不多,gitee国内的网络访问比较友好,这里选用gitee
首先注册账号之后进入首页新建仓库,跟着流程提示创建就行了,git远程仓库创建好之后有教程,跟着git的提示创建本地仓库,太简单就不上图了。
//其中这条命令就是添加一个远程仓库
git remote add origin https://gitee.com/用户名/仓库名
如果当前分支与多个主机存在追踪关系,将本地的master分支推送到origin主机,同时使用-u参数指定origin为默认主机,后面就可以不加任何参数使用git push了。
不带任何参数的git push,默认只推送当前分支,这叫做simple方式,还有一种matching方式,会推送所有有对应的远程分支的本地分支。Git 2.0版本之前,默认采用matching方法,现在改为默认采用simple方式。
如果想更改设置,可以使用git config命令。git config --global push.default matching OR git config --global push.default simple;可以使用git config -l 查看配置
//把代码推送到远程仓库(只要指定过origin为默认主机以后推送只需要git push)
git push -u origin master
当遇到这种情况就是不管是否存在对应的远程分支,将本地的所有分支都推送到远程主机,这时需要 -all
选项,可以使用这个命令:
git push --all origin
git push的时候需要本地先git pull更新到跟服务器版本一致,如果本地版本库比远程服务器上的低,那么一般会提示你git pull更新,如果一定要强行提交,那么可以使用这个命令(一般不推荐):
git push --force origin
本地仓库创建好了之后就可以在本地操作远程仓库了
//列出所有的远程仓库
git remote -v//显示某个远程仓库信息
git remote show [remote-name]//删除本地仓库的分支
git push --delete 分支名//删除远程仓库主机的分支,以下命令表示删除 origin 主机的 master 分支:
git push origin --delete master//获取远程仓库最新代码更新本地代码(一般都是先git pull一下再git push)
git pull
日常要使用的命令不多,其他功能可以自己试着玩玩。
六、一般的协同开发流程
1、仓库
(1)源仓库(线上版本库)
在项目的开始,项目的发起者构建起一个项目的最原始的仓库,称为origin。
源仓库的有两个作用:
汇总参与该项目的各个开发者的代码
存放趋于稳定和可发布的代码
源仓库应该是受保护的,开发者不应该直接对其进行开发工作。只有项目管理者能对其进行较高权限的操作。
(2)开发者仓库(本地仓库)
任何开发者都不会对源仓库进行直接的操作,源仓库建立以后,每个开发者需要做的事情就是把源仓库的“复制”一份,作为自己日常开发的仓库。这个复制是gitlab上面的fork。
每个开发者所fork的仓库是完全独立的,互不干扰,甚至与源仓库都无关。每个开发者仓库相当于一个源仓库实体的影像,开发者在这个影像中进行编码,提交到自己的仓库中,这样就可以轻易地实现团队成员之间的并行开发工作。而开发工作完成以后,开发者可以向源仓库发送pull request,请求管理员把自己的代码合并到源仓库中,这样就实现了分布式开发工作和集中式的管理
2、分支划分(Branch)
(1)master branch:主分支
master:主分支从项目一开始便存在,它用于存放经过测试,已经完全稳定代码;在项目开发以后的任何时刻当中,master存放的代码应该是可作为产品供用户使用的代码。所以,应该随时保持master仓库代码的清洁和稳定,确保入库之前是通过完全测试和代码reivew的。master分支是所有分支中最不活跃的,大概每个月或每两个月更新一次,每一次master更新的时候都应该用git打上tag,来说明产品有新版本发布。
(2)develop branch:开发分支
develop:开发分支,一开始从master分支中分离出来,用于开发者存放基本稳定代码。每个开发者的仓库相当于源仓库的一个镜像,每个开发者自己的仓库上也有master和develop。开发者把功能做好以后,是存放到自己的develop中,当测试完以后,可以向管理者发起一个pull request,请求把自己仓库的develop分支合并到源仓库的develop中。所有开发者开发好的功能会在源仓库的develop分支中进行汇总,当develop中的代码经过不断的测试,已经逐渐趋于稳定了,接近产品目标了。这时候,就可以把develop分支合并到master分支中,发布一个新版本。
注:任何人不应该向master直接进行无意义的合并、提交操作。正常情况下,master只应该接受develop的合并,也就是说,master所有代码更新应该源于合并develop的代码。
(3)feature branch:功能分支
feature:功能性分支,是用于开发项目的功能的分支,是开发者主要战斗阵地。开发者在本地仓库从develop分支分出功能分支,在该分支上进行功能的开发,开发完成以后再合并到develop分支上,这时候功能性分支已经完成任务,可以删除。功能性分支的命名一般为feature-*,|*为需要开发的功能的名称。
(4)协议选择
HTTP和SSH哪个好
git可以使用四种主要的协议来传输资料: 本地协议(Local),HTTP 协议,SSH(Secure Shell)协议及 git 协议。其中,本地协议由于目前大都是进行远程开发和共享代码所以一般不常用,而git协议由于缺乏授权机制且较难架设所以也不常用。
最常用的便是HTTP(S)和SSH协议。git关联远程仓库可以使用http协议或者ssh协议。
HTTPS优缺点
优点1: 相比 SSH 协议,可以使用用户名/密码授权是一个很大的优势,这样用户就不必须在使用 Git 之前先在本地生成 SSH 密钥对再把公钥上传到服务器。 对非资深的使用者,或者系统上缺少 SSH 相关程序的使用者,HTTP 协议的可用性是主要的优势。 与 SSH 协议类似,HTTP 协议也非常快和高效
优点2: 企业防火墙一般会打开 80 和 443 这两个常见的http和https协议的端口,使用http和https的协议在架设了防火墙的企业里面就可以绕过安全限制正常使用git,非常方便
缺点: 使用http/https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令. 但是现在操作系统或者其他git工具都提供了 keychain 的功能,可以把你的账户密码记录在系统里,例如OSX 的 Keychain 或者 Windows 的凭证管理器。所以也只需要输一次密码就搞定了。
SSH的优缺点
优点1: 架设 Git 服务器时常用 SSH 协议作为传输协议。 因为大多数环境下已经支持通过 SSH 访问 —— 即时没有也比较很容易架设。 SSH 协议也是一个验证授权的网络协议;并且,因为其普遍性,架设和使用都很容易。
缺点1: SSH服务端一般使用22端口,企业防火墙可能没有打开这个端口。
缺点2: SSH 协议的缺点在于你不能通过他实现匿名访问。 即便只要读取数据,使用者也要有通过 SSH 访问你的主机的权限,这使得 SSH 协议不利于开源的项目。 如果你只在公司网络使用,SSH 协议可能是你唯一要用到的协议。 如果你要同时提供匿名只读访问和 SSH 协议,那么你除了为自己推送架设 SSH 服务以外,还得架设一个可以让其他人访问的服务。
总结
HTTPS利于匿名访问,适合开源项目可以方便被别人克隆和读取(但他没有push权限);毕竟为了克隆别人一个仓库学习一下你就要生成个ssh-key折腾一番还是比较麻烦,所以github除了支持ssh协议必然提供了https协议的支持。
而SSH协议使用公钥认证比较适合内部项目。 当然了现在的代码管理平台例如github、gitliab,两种协议都是支持的,基本上看自己喜好和需求来选择就可以了。
使用SSH协议需要生成/添加SSH公钥
SSH Key和 SSH 公钥
Gitee 提供了基于SSH协议的Git服务,在使用SSH协议访问仓库仓库之前,需要先配置好账户/仓库的SSH公钥。
你可以按如下命令来生成 SSHKey:
//生成的 sshkey 的名称,并不约束或要求具体的名称
ssh-keygen -t rsa -C "keyName"
# Generating public/private rsa key pair...
按照提示完成三次回车,即可生成 ssh key。通过查看 ~/.ssh/id_rsa.pub 文件内容,获取到你的 public key
cat ~/.ssh/id_rsa.pub
# ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6eNtGpNGwstc....
复制生成后的 ssh key,通过仓库主页 「管理」->「部署公钥管理」->「添加部署公钥」 ,添加生成的 public key 添加到仓库中。
添加后,在终端(Terminal)中输入
ssh-T git@gitee.com
首次使用需要确认并添加主机到本机SSH可信列表。若返回Hi XXX! You've successfully authenticated, but Gitee.com does not provide shell access.内容,则证明添加成功。
添加成功后,就可以使用SSH协议对仓库进行操作了。
ssh-T git@gitee.com
仓库公钥和可部署公钥
为了便于用户在多个项目仓库下使用一套公钥,免于重复部署和管理的繁琐,Gitee 推出了「可部署公钥」功能,支持在一个仓库空间下使用当前账户名下/参与的另一个仓库空间的部署公钥,实现公钥共用。
部署公钥允许以只读的方式访问仓库,主要用于仓库在生产服务器的部署上,免去HTTP方式每次操作都要输入密码和普通SSH方式担心不小心修改仓库代码的麻烦。
部署公钥配置后的机器,只支持clone与pull等只读操作。如果您想要对仓库进行写操作,请 添加个人公钥
个人公钥的添加地址:
3、实战
(1)多人合作开发流程
首先初始化仓库建,一般会建立两个分支,一个master分支,一个develop分支。对各分支设置保护行为,添加项目组员。
张三的开发流程
将项目克隆到本地
切换到develop分支
在develop分支创建一个功能分支进行开发
开发完成之后在develop分支与功能分支进行合并,如果不需要功能分支可以删除
拉取最新的代码git pull,也就是和git远程仓库的develop进行合并,发现有冲突,解决冲突
解决完冲突之后,再推送到(git push)git远程仓库
# 克隆git远程仓库项目到本地
>>> git clone 仓库地址# 切换到`develop`分支
>>> git checkout develop# 创建一个功能分支并切换
>>> git checkout -b feature-order# order.java就是我们开发的功能代码
>>> touch order.java# 提交更改,commit到本地仓库
>>> git add .
>>> git commit -m 'finish order feature'# 切换回develop分支
>>> git checkout develop# 把做好的功能合并到develop中
>>> git merge feature-order# 删除功能性分支
>>> git branch -d feature-order# 先获取远程仓库最新版本
>>> git pull# 最后将develop分支提交到远程仓库中
>>> git push origin develop
其他人也是一样的流程,这只是其中一种多人开发的解决方案。
(2)分布式跨团队合作开发
跨团队成员的合作流程
将git远程目标仓库的项目fork到自己的远程仓库
将远程仓库的代码克隆(git clone)到本地
可以自行开发也可以多人进行开发
开发完成之后提交(git push)到自己的远程仓库
发起pull request 请求给目标远程仓库管理员
仓库管理员查看请求、审核代码(review code)、测试通过之后进行合并
4、idea使用git
1.打开idea配置git
2.从远程仓库拉取项目
填入远程仓库的url地址
项目拉取下来之后就能看到idea自带了git的图形化功能页面
在idea有图形化页面上使用git就是如此简单。
最后要注意的是开发的时候不要随便乱动别人的代码,每次开发和提交之前先pull一下拉取最新的代码!
这样可以避免一些烦人的冲突。