概述
同生活中的许多伟大事件一样,Git 诞生于一个极富纷争大举创新的年代。
Linux 内核开源项目有着为数众广的参与者。绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002 年间)。到 2002 年,Linux 系统已经发展了十年了,代码库之大让 Linus 很难继续通过手工方式管理了,于是整个项目组开始启用分布式版本控制系统 BitKeeper 来管理和维护代码。
到 2005 年的时候,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了免费使用 BitKeeper 的权力。这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds )不得不吸取教训,只有开发一套属于自己的版本控制系统才不至于重蹈覆辙。他们对新的系统订了若干目标:
• 速度快
• 简单的设计
• 对非线性开发模式的强力支持(允许上千个并行开发的分支)
• 完全分布式
• 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)
Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!一个月之内,Linux系统的源码已经由Git管理了!
Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站(基友网站)上线了,它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。
历史就是这么偶然,如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好用的Git了。
SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是自己的电脑,所以首先要从中央服务器哪里得到最新的版本,然后干活,干完后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作,如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就郁闷了。
下图就是标准的集中式版本控制工具管理方式:
集中管理方式在一定程度上看到其他开发人员在干什么,而管理员也可以很轻松掌握每个人的开发权限。
但是相较于其优点而言,集中式版本控制工具缺点很明显:
服务器单点故障
容错性差
Git是分布式版本控制系统,那么它可以没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。既然每个人的电脑都有一个完整的版本库,那多个人如何协作呢?比如说自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。
比较出名的代码托管中心: GitHub 和 码云
确切的说 GitHub 是一家公司,位于旧金山,由 Chris Wanstrath, PJ Hyett 与 Tom Preston-Werner 三位开发者在2008年4月创办。这是它的 Logo:
2008年4月10日,GitHub正式成立,地址:How people build software · GitHub ,主要提供基于git的版本托管服务。一经上线,它的发展速度惊为天人,截止目前,GitHub 已经发展成全球最大的开源社区。所以 Git 只是 GitHub 上用来管理项目的一个工具而已,GitHub 的功能可远不止于此!微软76亿美金收购Github
我们使用GitHub的时候,会感觉比较慢,为什么? 原因就是GitHub在遥远的美国,由于各种原因造成访问速度不怎么好,所以国内的git服务提供商,码云就起来了。
功能 | 码云 Gitee | GitHub |
---|---|---|
代码托管,支持 Git/SVN | √ | √ |
开源项目、代码片段 | √ | √ |
Issue | √ | √ |
Wiki | √ | √ |
Fork + Pull Request | √ | √ |
组织 | √ | √ |
私有仓库免费协作人数 | 5 人 | 3 人 |
保护分支 | 免费 | 收费 |
在线 IDE(Gitee IDE) | √ | 不支持 |
仓库自动备份 | √ | 不支持 |
禁止 Git 强推 | √ | 不支持 |
支持仓库访问 IP 限制 | √ | 不支持 |
企业级研发协作 | 5 人免费 | 收费 |
敏捷开发管理 | √ | |
任务看板(可灵活定义) | √ | |
支持多级任务、关联任务 | √ | |
自动代码质量分析 | √ | |
快捷生成工作周报 | √ | |
代码克隆检测 | √ | |
自动生成 JavaDoc/PHPDoc | √ | |
多语言 README 自动渲染 | √ | |
支持微信/钉钉通知 | √ |
前提
https://git-scm.com/download
安装教程:安装Git服务端
双击安装:
一路“Next”使用默认选项即可。
安装完成后,可以在任意文件夹点右键,看到如下菜单:
新建D:\test文件夹,在test上面,点击Git的控制台,在控制台输入git,可以看到相关的帮助信息:
配置签名: 用户名和邮箱(提交的用户名与邮箱)
git config --global user.name “nameVal”
git config --global user.email “emailVal”
git config --global user.name "xxx"
git config --global user.email "[email protected]"
局部的用户信息放在:当前项目的 .git/config
全局的用户信息放在:系统盘的--用户目录--用户名目录-- .gitconfig文件中
[C:\Users\Administrator\.gitconfig]
什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。由于git是分布式版本管理工具,所以git在不需要联网的情况下也具有完整的版本管理能力。
创建一个版本库非常简单:
此处的hello目录就是我们的:工作区 (work tree),存放所有当前文档。此目录下的文件才会被Git管理,hello中的.git目录就是我们的:本地仓库,管理并保存所有的文档变化及历史状态。
版本库核心文件的解释
目录 | 描述 |
---|---|
config | 该文件主要记录针对该项目的一些配置信息,例如是否以bare方式初始化、remote的信息等,通过git remote add命令增加的远程分支的信息就保存在这里; |
objects | Git中的文件和一些操作都会以git对象来保存,git对象分为BLOB、tree和commit三种类型,例如git commit便是git中的commit对象,而各个版本之间是通过版本树来组织的,比如当前的HEAD会指向某个commit对象,而该commit对象又会指向几个BLOB对象或者tree对象。 |
HEAD | 该文件指明了git branch(即当前分支)的结果,比如当前分支是master,则该文件就会指向master,但是并不是存储一个master字符串,而是分支在refs中的表示,例如ref: refs/heads/master |
index | 该文件保存了暂存区域的信息。该文件某种程度就是缓冲区(staging area),内容包括它指向的文件的时间戳、文件名、sha1值等; |
Refs | 该文件夹存储指向数据(分支)的提交对象的指针。 |
版本控制系统,其目的就是跟踪文本文件的改动,例如我们开发时编写的.java、.properties本质都是文本文件。文件中每一个字符的变化都会被跟踪并且管理。
使用 git commit 命令,将暂存区文件提交到本地仓库
命令解释:
git commit 命令可以将暂存区的文件提交到版本库。
-m 参数,是本次提交的说明信息,用来注释本次提交做了些说明事情。
**总结: **将一个文件添加到本地仓库,分两步:
1)git add 文件/. (到暂存区)
2)git commit -m ‘注释’(到版本库)
工作区:
版本库及暂存区:
第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。
为什么Git会设计暂存区?
Git暂存区的目的在于分段提交:
Git的add是可以选择文件的,commit是不能选择文件的!Git的commit(提交操作)是原子操作,意味着一次提交会把所有文件全部提交,如果失败则一个文件都不提交。如果Git没有暂存区,工作区修改的代码 就只能一次全部提交,而在实际开发过程中,我们在开发过程中可能会出现突发的Bug需要修复,这时我们只需要选择提交修改好的Bug的文件即可,从而实现分段提交的效果。
可以简单理解为,需要提交的文件通通先放到暂存区,然后,一次性提交暂存区到版本库(分支)。
> git diff readme.txt 将工作区的文件和暂存区进行比较差异
可以发现,与版本库中的 readme.txt相比,多了一行文本!
如果不确定自己的哪些文件被修改了,可以使用git status命令,查看当前工作区的状态:
可以清楚的看到:changes not staged for commit(修改没有被缓存,需要使用git add来进行添加操作),我们使用git add 命令,添加到暂存区:
再次查看状态:
这次提示: changes to be commited (修改需要被提交),我们使用git commit 进行提交
再次查看状态:
提示说:工作区很干净,没有任何需要提交
再次修改readme.txt 新增内容: Test version control. 提交到版本库
git log 整体展示,不直观,如果要翻页,一直按enter键进行翻页,按CTRL+C退出
如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline
(一行显示)参数:
可以发现,目前为止,已经在本地仓库中提交了3次,也就是说有3个不同版本。其中,最近的这个版本有一个标示:HEAD ,这就是标记当前分支的当前版本所在位置。本例当中,当前版本即 test version control这次提交。
另外,在log中,每一个版本的前面,都有一长串随即数字:5bc7781319b…192728 ,这是每次提交的commit id ,这是通过SHA1算法得到的值,Git通过这个唯一的id来区分每次提交。
美化的缩小版
git log --oneline
要回到上一级版本,该如何操作呢:
可以通过git reflog命令,看到以前的每次执行动作:
其中红框内的部分,就是第三次提交的日志信息。前面的Obd575f就是第三次提交的 commit id 的前几位数字。
语法: git reset --hard ‘版本号’
git reset --hard 0712188
提示说:HEAD 现在已经被设置到 0712188 的版本,即 modify readme file。
查看readme.txt,果然,版本已经回退了,最新添加的数据“Test version control”已经没了。
此时再次查看日志,发现只剩下2次提交信息了,第三次提交的信息已经没了:
假如后悔了,还想回到第3次提交的版本:
总结:
如果要进行版本回退,一般分两步:
其实版本的回退,仅仅是修改HEAD指针的位置而已,因此Git进行版本的切换,比svn要快的多!
查看状态:
Git提示我们,现在文件已经修改,等待被staged(暂存)。我们有两个选择:
所以,这里我们选择第二种方案:
再次查看状态:
工作区是干净的!查看文件:
修改已经被撤销了!
我们前面说过,git reset 命令可以进行版本回退,此处reset 指定的是HEAD ,而不是其他版本,因此就有撤销缓存修改的作用:
git reset HEAD readme.txt
查看状态:
发现文件的修改被撤回到了工作区,尚未添加到staged(暂存区),我们再次执行git checkout – 即可撤销工作区修改
工作区干净了!查看文件:
文件也恢复了原来的状态!
小结:
撤销修改分两种情况:
git checkout -- readme.txt 撤销工作区修改
git reset head readme.txt 撤销暂存区修改
git reset --hard 文件id(前7位) 回退版本. 提交了,要撤回提交,回到之前的版本
问题
往往在开发的过程中,特别是在多人协作的场景下,可能需要把一些无用的文件不需要提交。GIT是如何来做的的呢?
# 1: 打开`git bash here` 输入如下命令:
vim .gitignore
target
*.iml
.idea
# 2: 保存退出
:wq
gitignore 语法规则:
空行或是以 # 开头的行即 注释行,将会被忽略。
示例如下:
# 忽略所有 .a 文件
*.a
# 递归忽略 build/ 文件夹下的所有文件
build
# 忽略 /doc/notes.txt,不包括 doc/server/arch.txt
doc/*.txt
# 忽略所有的 .pdf 文件 在 doc/ directory 下的
doc/**/*.pdf
问题
上面的文件版本控制都是在本机的本地仓库中进行操作,如何进行团队协作开发,怎么把本地仓库的代码共享出来供团队的其他开发员下载使用呢?
就是:远程仓库。
上面已经说了如何在本机利用git进行文件版本管理,但是如果要想进行多人协作,就必须使用远程仓库。将本地仓库的数据同步到远程仓库,实现多人协作开发。
目前比较热门的代码托管社区:GitHub,网址:https://gtihub.com ,提供了免费的远程git仓库功能。不过网速不是特别流畅。
在国内,有很多的公司使用oschina提供的git服务:码云, https://gitee.com。
创建远程仓库
操作步骤
添加或删除关联远程仓库
git remote add origin url # 为当前本地仓库添加关联的远程仓库
git remote rm origin # 从当前本地仓库中删除关联的远程仓库
origin: 为远程仓库起个别名
url: 远程url
# 执行此命令必须要进入该仓库对应的工作区
# github
git remote add origin https://github.com/xxx/gitdemo.git
# 码云
git remote add origin2 https://gitee.com/xxx/gitdemo.git
# 如果删除之前关联:
git remote rm origin
git remote add origin 改成新的地址
注: 初次关联使用提交代码的时候需要填写,账号和密码信息(为github 或 码云 的登录用户名与密码)。用户名:[email protected] 密码: xxxxx
同步本地仓库到远程仓库的命令:
# 同步本地仓库到远程仓库
# github
git push -u origin master
# 码云
git push -u origin2 master
注:origin 可以理解为远程仓库的别名,master 主分支。
# 克隆远程仓库到本机
# git clone ssh/https
# github
git clone https://github.com/xxxx/gitdemo.git
# 码云
git clone https://gitee.com/xxxx/gitdemo.git
也可以指定clone后到本地的文件夹名称
git clone https://gitee.com/xxxx/gitdemo.git 文件夹名称
# 更新远程仓库到本地仓库
git pull origin master
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'https://gitee.com/kekesam/pingyougou2.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
解决方案
git push -f origin master
说明: 它会把远程仓库中所有的信息全部清空,在把本机仓库版本提交上去。
Git-bash中已经集成了ssh功能,所以我们只需要简单的命令,即可生成密钥:
命令: ssh-keygen -t rsa
一路回车向下走,不要输入任何内容即可!
具体步骤如下:
第一步: 打开命令工具"git bash here" 输入命令 “ssh-keygen -t rsa” 生成密钥和公钥
ssh-keygen -t rsa
第二步: 然后将C:\Users\Administrator\.ssh
生成的公钥文件【id_rsa.pub】内容复制出来
第三步:
第四步: 测试和体验ssh的免密操作
# github
git remote add origin [email protected]:lixiaohua1/gitdemo.git
# 码云
git remote add origin2 [email protected]:leesiuwah/gitdemo.git
```shell
git remote rm origin #删除原来的origin
git remote rm origin2 #删除原来的origin2
# 然后在执行
git remote add origin 你需要更换的远程仓库地址
```
提交代码到远程仓库中:
git push origin master
git push origin2 master
克隆远程仓库到本机:
# github
git clone [email protected]:xxxx/gitdemo.git
# 码云
git clone [email protected]:xxxx/gitdemo.git
注意:新克隆下来的远程仓库访问名称默认为 origin
拉取最新代码到本机
git pull origin master
注意:记得将https地址更换ssh地址。
1)使用ssh-keygen生成公私钥
2)把公钥设置到github或者码云
分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。
文件提交的过程:
新建分支与切换分支:
合并分支:
第一步:创建分支
git branch dev 创建分支 dev
git checkout dev 选中当前分支 dev
# 注:上面两个命令可以组合成一个复合命令
git checkout -b dev
# git checkout -b dev = (git branch dev + git checkout dev)
第二步:查看分支
git branch
第三步:添加文件,提交文件在当前分支
# 创建文件,输入任意内容
vim e.txt
# 提交e.txt文件
git add .
# 提交e.txt文件到dev分支中
git commit -m 'e.txt'
第四步:推送分支到远程仓库中
git push origin dev
第五步:合并分支
# 切换回master分支
git checkout master
# 将dev下面的内容全部合并到master
git merge dev
git push -u origin2 master 把本地分支推送到远程
第六步:删除分支
git branch -d dev 删除本地分支
git push origin2 --delete dev 删除远程分支
一路“Next”使用默认选项即可。
默认选项下会启动配置画面:
由于目前只有英文语言包,默认即可继续下一步。
配置git.exe,在4.2.1中已经安装过git-for-windows了所以在此找到git.exe所在的目录。
配置开发者姓名及邮箱,每次提交代码时都会把此信息包含到提交的信息中。
使用默认配置,点击“完成”按钮完成配置。
完整完毕后在系统右键菜单中会出现git的菜单项。
安装中文语言包并不是必选项。可以根据个人情况来选择安装。
直接“下一步”完整完毕。
鼠标右键选择Settings
语言包安装完毕后可以在TortoiseGit的设置中调整语言
新建一个空的文件夹:tortoise
然后进入tortoise目录,右键操作:
弹出提示,不要勾选:
查看目录,发现生成.git文件夹:
注意: 想看到对应的图标,电脑需要重启。
创建新的文件:
编写内容:
在文件夹中右键操作:
提示:这一步等同于我们的 git add readme.txt
此时直接点击提交,即可完成:git commit 操作:
提示:
再次修改readme.txt,并且提交
查看日志:
假如要回到上一个版本,也就是第2次提交。
选中第2次提交,然后右键,选中:重置“master”到这个版本
弹出菜单,这里选中Hard模式,然后确定:
再次查看日志,只剩下第1和第2次提交了。并且HEAD已经设置到了第2次提交位置
文件也回滚了:
如果想再次回到第3次提交怎么办?现在连日志都没有了!
此时,在空白处点击右键,选中 显示引用记录:
弹出所有操作的日志信息:
现在,找到第3次提交,右键,选中:重置“master”到这个版本
结果,第3次提交又回来了!
文件内容回来了:
现在修改文件:
现在想要还原到修改以前。
可以选中文件,右键。然后选中菜单:还原。
点击确定:
还原成功:
查看文件:
在Idea中配置Git,打开File菜单:
在File --> Settings -> Version Control --> Git -->Path to Git executable选择你的git安装后的git.exe文件
新建一个maven工程
创建Git本地仓库
VCS菜单: VCS --> Import into Version Control --> Create Git Repository…
在弹框中选中项目所在的位置,点击OK,此时项目文件全部变成棕色
项目Git版本已经创建成功。
这里可以手动修改.gitignore文件,也可以通过插件过滤。手动修改:
# 官方忽略
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
# 新增
.classpath
.project
.settings
target
# idea
*.iml
.idea
项目右键选择Git --> add
此时项目文件变成绿色,此时文件只是处于暂存区,并没有真正进入到版本库中。
此时项目文件全部变成绿色。
项目右键Git --> Commit Directory
在弹窗中输入Commit Message,点击commit,此时项目文件从暂存区真正进入版本库中,项目文件变成黑色。
编辑本次提交备注信息,然后点击commit按钮。
此时项目文件全部变成黑色:
要新建一个远程仓库,再push到远程仓库。
因为一个仓库,只能对应一个项目。这就是git!
选择maven导入方式,直到操作完成。
什么情况产生冲突?
|-- 同一个文件 User.java
|-- 同一行 第56行
|-- 出现了不同的代码,就会产生冲突
A. 小明 在User.java 第56行写了代码:9999999999, 提交了代码
B. 小红 在User.java第56行写了代码: 66666666666, 也提交
说明: 提交代码到本地仓库。
然后在master修改提交代码
点击Merge合并策略:
弹出一个对比页面
使用的命令如下:
git init 初始化本地仓库
git add . 把当前目录下的所有文件添加到暂存区(后续才可以提交)
git commit -m '提交日志' 提交并记录日志
git diff reamde 查看工作区与暂存区的区别
git status 查看文件状态
git log --oneline 查看日志
git reset --hard 0712188 回退版本
git checkout -- readme.txt 撤销工作区修改
git reset HEAD readme.txt 撤销暂存区修改
git remote add origin 仓库地址 本地仓库关联远程仓库
git push -u origin master 本地仓库内容推送远程仓库
git clone 仓库地址 克隆仓库,把远程仓库内容下载到本地(并自动初始化本地仓库)
git pull origin master 从远程仓库拉取资源到本地仓库
git branch 查看分支
git branch dev 创建分支
git checkout dev 选中分支
git push origin dev 推送分支到远程库
git merge dev 合并分支
git branch -d dev 删除本地分支
git push origin --delete dev 删除远程仓库分支(origin是别名,表示远程仓库的地址)