写在前面
长期以来,我一直用的是git命令行管理代码,当只有一个人时,这完全没问题,但参与团队协作,命令行就显得令不从心,这并不是说命令后做不到,只是命令需要记住太多的命令,学习成本太高,而且在解决冲突上面,如果只靠命令后,那种感觉你体验过一次就再也不想体验。在花了一两天时间研究idea的git工具后,我就决定彻底放弃命令行拥抱gui,因此这边将这两天的研究成果记录下来,供大家学习参考。
创建仓库
创建远程仓库
第一步需要在github或者gitee代码管理平台创建好仓库,这里以github为例
- 输入仓库名称
- 选择仓库类型,public表示所有人都可见,private表示只有授权过才有权限
仓库创建好后,默认是一个空仓库,这时候界面会提示如何往仓库推送代码
注意到界面上有个仓库地址,地址有ssh和https,这两个有什么区别呢
- https:通过http协议进行代码的管理,需要使用用户名密码
- ssh:通过ssh协议进行代码管理,使用的是密钥(你可以理解为一个凭证)
推送仓库的操作后面会详细说明,这里就不介绍。
关联本地仓库
如果是本地已有项目需要关联刚创建的远程仓库,具体步骤如下
- 初始化项目
在菜单栏选择VCS -> Import into Version Control -> Create Git Repository
,选择后会弹出文件夹选择窗口选择当前文件夹即可
选择文件夹后idea会在当前目录下创建一个.git
的文件夹,表示该项目已经是一个使用git版本控制的项目,如果你的终端是比较友好的终端(如Oh My ZSH),这时候会显示当前分支,默认是master分支
➜ git-learning git:(master) ✗
- 关联远程仓库
远程仓库称在git中称为Remote
,一个项目可以关联多个reomte,也就是你的项目可以同时推送到多个远程仓库,这个是很有用的,比如我们的代码既要推送到客户仓库进行集成,又要推送到公司的仓库进行代码审查,这时候就可以使用多remote进行推送,点击VCS -> Git -> Remotes
添加远程仓库,如果是第一仓库,名称默认origin,建议不要修改该名称
这样我们就完成了本地仓库和远程仓库的关联,后续就可以进行代码的提交,分支的创建等操作。
克隆仓库
如果是别人创建好并提交过代码的仓库,你需要同步到本地,那么就需要对仓库进行克隆(clone)操作,选择File -> New -> Project from Version Control
,输入远程仓库代码地址即可
gitignore
在项目中有些工程文件或者程序运行时文件我们不希望提交到仓库里,那么我们就需要准备一个名为.gitignore
的文件,将不希望提交的文件都写到该文件里,git就不会对这些文件进行提交和管理。
一个.gitignore样例
/out/
/classes/
.mvn
/node_modules/
.idea
*.iws
*.iml
*.ipr
.DS_Store
/target/
可以在文件或者文件夹上右键将其添加到gitignore上
提交代码
代码修改后需提交到本地仓库,这个过程称为Commit
,代码提交到本地仓库后就可以将commit提交到远程仓库,这个过程称为push
,从远处仓库更新代码的过程称为pull
,这三个git操作是最常用的三个操作,在idea的右上角有这三个操作对应的按钮
- ① 更新代码,pull操作
- ② 提交到本地仓库,commit操作
- ③ 提交到远程仓库,push操作
点击commit图标就可以提交代码,提交代码界面如下
- ① 本次提交涉及到修改的文件
- ② 提交信息,提交信息是必填,每一次提交都需写明本次修改了哪些内容,原则上每一次不同的目的的修改都应对应一次commit,关于如何写好commit可以参考以下两篇文章
- https://github.com/joelparkerhenderson/git-commit-message
- https://github.com/RomuloOliveira/commit-messages-guide
注意到①文件前面都有一个复选框,如果是新添加的文件,没有特殊配置的话是不会自动勾选的,新添加的文件需要手动勾选才能提交,可以直接对顶层文件夹全选即可,commit后需要进行push才能同步到远程仓库,点击push按钮
push成功后就可以登录远程仓库查看最新的代码
注意到系统提示我们添加一个README文件,README是一个名称为README.md
的文件,位于项目根目录下,一个好的README文件有助于其他人快速了解项目情况,关于如何写好README文件,可以参考以下文档
修改代码后,在提交的界面还会对本地提交和上一次提交进行对比,方便我们查看修改的内容
回滚代码
git回滚代码有两种方式
- reset
- revert
这两种有什么区别呢,假设我们提交了三次commit
commit1 -> commit2 -> commit3
如果我想会滚到commit2,如果用reset的话,那么commit2之后的所有修改都会被丢弃,也就是把commit2之后的commit全部砍掉了,revert有点像undo,会把commit2做的操作反做一遍,也就是undo,并且生成一个新的commit,变成
commit1 -> commit2 -> commit3 ->4
具体应用在什么场景呢,举个例子,比如我们在调试的时候可能要加一些调试语句,比如system.out,当调试完毕,我们希望能够移除这些调试语句就可以在调试前提交一次commit,调试完毕后reset到该次commit就行,当然你也可以通过分支来实现,调试完毕把分支删掉即可。
我们的系统在不断的迭代,突然某一天,产品经理说之前已经上线的一个功能不要了,那么就可以找到该功能对应的commit进行revert,这样既移除对应的功能又能保留后续的新功能。
reset
在idea地步工具栏,点击Git
工具栏,切换到Log
标签页,可以看到本地commit日志和远程commit日志,在指定commit上右键选择Reset Current Branch to Hear
就可以以reset的方式回滚到该commit上
有四种回滚的模式
<img src="http://zhengjianfeng.cn/images/R2byAplCbygdWlcNS98tcHuYiflKF4FC.jpg" style="zoom:60%;" />
选择Hard
模式,将会清除本地版本,强制回滚到指定commit状态,但是通过reset是无法进行push操作,因为本地的版本比远程版本要低,此时可以强制push到远程分支
idea默认是禁止在master分支上进行强制push,如果是master分支需要强制push可以在终端使用命令行
git push --force
force push是一种非常不好的习惯,除非你清楚的意识到force push带来的后果,不然千万不要执行force push
revert
revert可以将指定的commit所做的修改全部撤销掉,而不影响其他commit的修改,假设我们有三个文件,分别为file1.txt,file2.txt,file3.txt,现在提交三个commit,三个commit分别为
- Commit1:向file1.txt中添加内容
- Commit2:向file2.txt中添加内容
- Commit3:向file3.txt中添加内容
现在我们在Commit2:文件2修改
这个commit上面右键选择Revert Commit
,这时候会弹出提交窗口,idea会自动提交一次新的commit,commit后我们发现文件2的内容没有了,也就是撤销了commit2修改的内容,commit后执行push操作就能推送到远程仓库了,因为是生成了新的commit,所以无需force push就能提交到远程仓库
revert操作会经常碰到代码冲突的情况,这时候就需要手动去解决冲突,解决方法下面也会详细说明
分支管理
分支是git中非常重要的概念,假设没有git的情况下,我们系统上线了,在线上稳定运行,这时候你需要开发后续的功能但又想保留目前线上版本的代码,因为可能线上有紧急bug需要修复,你需要使用当时的版本进行修改,所以你可能会copy一份代码做备份,等新功能开发完,你还需要将这段时间在备份的代码上修改的代码整合过来,如果这个过程是人工进行的,非常容易出错,所以git提供了分支解决这个问题,线上运行的代码可以在主分支上,比如master分支,开发新功能可以从master分支切一个分支出来,比如dev分支,修复bug也可以从master分支上切一个分支出来,比如fix分支,当bug修复完毕,将fix分支整合(merge)到master分支上,当新功能开发完毕后,将dev分支整合到master分支,就完成了上述所有的操作。
新建分支
在idea右下角显示当前分支
点开就可以在当前分支下新建一个分支
你也可以从某个commit切出一个分支,具体做法在commit日志上右键New Branch
即可
切换分支
如果想要切换到其他分支,点击要切换的分支,选择Checkout
切换分支前需要把当前分支的修改提交或者暂存,暂存后续也会提到
分支合并
比如我要把fix分支合并到dev分支上,那么将当前分支切换到dev上,选择fix分支Merge into Current
合并过程可能会产生冲突,需要解决完冲突才能完成合并,解决冲突下文也会提到
合并完分支后,建议把fix分支进行删除,避免误将分支提交到远程仓库,导致分支混乱。
rebase
注意到上面菜单中在Merge上面还有一个Rebase Current onto Selected
的选择,合并有两种方式,一种是merge,一种是rebase,这两种有什么区别呢,如下午,1时rebase方式合并,2和3是merge方式合并
- merge会保留分支提交信息
- merge会创建一次Merge branch的commit信息
- 相比merge,rebase会将分支上的commit整合到当前分支上,让整个代码周期更为清晰
- 相比merge,rebase并不会产生多余的commit信息
具体用rebase和merge,各有各的好处,取决于项目的规范要求。
冲突解决
不管是rebase还是merge,在进行合并时难免会产生冲突,所谓的冲突是指两个分支上的代码对同一个地方进行修改,系统无法判断该保留哪一份代码,需要人工进行干预解决冲突的过程。如果有冲突产生,在进行合并时会列出所有冲突的代码
这时候有三个选项可以选择
- Accept Yours:保留当前分支代码,丢弃被合并的分支代码
- Accept Theirs:保留被合并分支代码,丢失当前分支代码
- Merge:手工进行合并
选择Merge后进入手工合并代码界面
- ① 当前分支代码
- ② 合并后的代码
- ③ 被合并的分支代码
idea会把两边不同的进行高亮显示,你可以根据实际情况进行合并
合并后会弹出一个确认框,如果所有的冲突都解决完毕,可以点击Apply Change and Mark Resolved
,表示冲突已解决
标签管理
创建标签
一般我们在发布一个新版本时会对项目打一个标签(tag),以表示其重要性,在gihub上我们也经常看到项目发布新版本时都会打上标签
在commit的log上右键commit就以为为该commit创建一个标签,标签名称一般为版本号,比如v1.0 v1.1
等
在push代码时可以选择将标签一起提交至远程仓库
这样我们就能在远程仓库中看到标签,并且系统会自动将标签对应的commit当时的代码进行打包归档
根据标签拉取代码
比如需要对v1.0的代码进行修复,我们需要拉取v1.0的代码,并且修复完毕后需要合并到当前分支
- 根据tag拉取代码
输入标签名称就可以拉取到代码,但此时的分支名称是分支对应的commit编号,说白了就是一个commit,我们需要在该分支上再创建一个分支才能对代码进行修改,创建的方法和上面一样,就是点击分支名称,New Branch
即可,修改后提交,按照正常分支合并即可。
补丁
patch
可以为一个或多个commit创建一个补丁(Patch),idea会创建一个.patch的文件,里面记录了文件的变化
在分支上可以将补丁进行导入,VCS -> Apply Patch
打补丁也是一种合并的方式,也需解决代码冲突问题
cherry-pick
和打补丁类似,cherry-pick可以直接将其他分支的一个或者多个commit应用到当前分支,无需导出patch文件
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。