使用IDEA学习廖雪峰官方Git教程
如果你只是想在开发过程中使用Git,而不是成为一个Git的专业研究者,那么非常推荐你看廖雪峰的官方网站的Git教程。廖老师在他的这个系列教程中的一句话我非常喜欢。
“本教程只会让你成为Git用户,不会让你成为Git专家。很多Git命令只有那些专家才明白(事实上我也不明白,因为我不是Git专家),但我保证这些命令可能你一辈子都不会用到。既然Git是一个工具,就没必要把时间浪费在那些“高级”但几乎永远不会用到的命令上。一旦你真的非用不可了,到时候再自行Google或者请教专家也未迟。”
而现如今,强如idea的编辑器早就将Git的操作图形化,操作起来不要太丝滑,就和使用一款新插件一样。所以我在这里重申廖雪峰老师的话——本教程只会让你成为Git的图形化工具用户,我保证大部分情况你都可以不使用Git指令。
哈哈哈,开玩笑的啦,还是强烈建议大家通读廖雪峰老师的教程,做到知其然,知其所以然。
本系列文章将展示如何使用idea的图形化界面操作Git,内容、案例均来自廖雪峰的官方网站的Git教程。
Git简介
Git的特点和发家史,很有意思,详见廖老师的文章。这里笔者就简单介绍一下Git的原理,知道这些会让你更好的阅读本教程。请看图:
其中Workspace就是工作区,当多人共同完成一个项目,廖老师每个人的电脑都是一个工作区。在工作区里,你可以修改代码。
Index/Stage就是暂存区,他和工作区是孪生兄弟,每个工作区都有一个暂存区。未完成的修改的代码都可以存入暂存区。
Repository就是仓库区(或本地仓库),可以理解为不是暂存区的存储区,一般完成的功能的代码才会存放在这里。
Remote就是远程仓库,所有的人都公用一个远程仓库,不在本机。
我们工作的顺序是先和远程仓库建立联系,然后克隆(clone)一份代码到自己的电脑的本地仓库,然后建立一个工作区,开始工作,修改代码。完成一个小功能后,加入(add)暂存区,当整个功能都完成的时候,提交(commit)到本地仓库。等待其他同伴开发完成他们的功能,推送(push)到远程仓库。
安装Git
可以阅读笔者的Git安装教程。不过别忘了,下载以后还需要配置git.exe。
创建版本库
初始化一个Git的版本库操作如下,会弹出一个浏览文件的对话框,选择需要的目录即可。但是在实际开发中几乎不需要这样的操作。
所以笔者在这里调换了一下廖老师教程的循序,第一步,咱们直接连接远程仓库。
远程仓库
在操作之前你需要完成以下内容
- 安装Git并配置;
- 申请一个GitHub账号,Gitee和GitLab都是一个道理;
- 在idea上登录GitHub
添加远程仓库(remote)
方法一
廖老师的方法太麻烦了,idea直接一步到位。
第一步:创建好你的项目后,如下图点击。
第二步:填写弹出分享项目到GitHub的窗口。
Repository name就是仓库名。Remote就是远程仓库名。origin这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。Description就是项目描述。private是设置是否私有,私有库别人看不见。
第三步:单机Share,会自动进行一个add+commit的操作。就是将创建的代码添加到自动创建的本地仓库(不要在意内容,笔者使用的不是空项目)。
这个对话框的意思就是以后会自动add所有新添加的文件到暂存区。打上不再提醒的对勾,点击Add就大功告成了。
创建完成之后,来到GitHub主页,就可以找到自己的库了。
这样做的好处就是——你可以在本地进行适当的开发,例如环境的配置和项目的初始化,之后再上传Git。而不是连接一个空的远程库,在搭建一个SpringBoot环境。
但是同样有弊端,快捷方式只能分享到GitHub,其他的远程仓库暂不支持,像有的公司在自己的Git库上面开发,自然使用不了。
方法二
所以廖老师的方法也介绍给大家,必须要先创建远程库,获得这个远程库的地址,如下图:
核心就在VCS->Git->Remotes,如下图:
然后在Remotes界面输入远程库地址,进行连接。
如果本地和远程都有文件,想让两者建立关联,如何操作。首先选择本地分支,update一下,会提示没有相关联的远程分支,需要选择一个分支。之后会处理两个分支的冲突,然后就建立了关联。具体如下图
克隆(clone)项目
知道如何自己创建项目了,我们还需要了解如何获取别人的项目。
第一步:
先找到需要克隆的项目的链接,如图所示
第二步:导入
File -> new -> Project from Version Control
版本控制选择git,URL框输入git联接,编辑本地的存储位置,单击clone即可。
廖老师还给我们介绍了https和ssh的区别。
你也许还注意到,GitHub给出的地址不止一个,还可以用https://github.com/michaelliao/gitskills.git这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。
使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https。
删除远程仓库
删除远程仓库的操作必须在GitHub上面进行,方法如下:
打开项目->Setting->Options->(拉到最下面找到)Delete this repository,弹出以下界面,重新输入一下项目名。
还需要输入GitHub密码,就可以删除了。如果是想让本地和远程库失去连接,在remote界面,点这个小减号就行。
时光穿梭机(add+commit)
将一个文件创建并存放到Git的本地仓库的动作叫做提交(commit)。其分为三步,第一步自然是创建文件,第二步是将文件添加(add)到暂存区,然后再commit到本地仓库。
第一步:创建文件,自动add
首先我们新建一个文件readme.txt,由于之前的设置,idea会自动add所有的新建文件,所以在使用idea的过程中我们完全不需要add。
如果需要手动add,也非常简单,使用如下图操作即可。
第二步:commit
点击编辑器右上角的绿色小对勾(也可能在左上角)。
弹出的对话框就是使用git status
指令查看是否有内容被修改的可视化界面,如下(vcs.xml是idea的初始化文件,请无视)
双击你想看的文件,就可以知道有哪些修改了。这和git diff
是一样的
同时提示一下大家,无论是文件还是代码,红色代表没有进行add,绿色代表and但未commit,蓝色代表已经commit且有改动,灰色代表已经删除的但未commit。
在红框中填写提交的信息wrote a readme file,然后我们点击图片上的Commit按钮,即可完成提交。这完全可以理解为Git指令 git commit -m "wrote a readme file"
提交完成后按图示方法即可查看日志。相当于git log
版本回退(reset+revert)
我们用这个的方法在上一个案例的基础上再提交两次。最后的内容应该如下:
版本1:wrote a readme file
Git is a version control system.
Git is free software.
版本2:add distributed
Git is a distributed version control system.
Git is free software.
版本3:append GPL
Git is a distributed version control system.
Git is free software distributed under the GPL.
就有了如下的Git日志
如何做到版本回退呢,廖老师使用了git reset
指令。如果使用idea,可以按照下图的提示点击。
会弹出下面的提示框。
简单翻译一下:
这会重设当前分支的head到选择的commit,并且更新工作树和暂存空间依照选择的模式
- 软:文件不会更改,不同会被储存
- 混合:文件不会更改,不同不会被储存
- 硬:文件会被转换到被选择的提交的状态,提示:任何修改都会丢失
- 保持:文件会被转换到被选择的提交的状态,但是本地的修改会被完整保存
具体的效果大家可以尝试一下,观察一下效果。就如提示的内容一样,这样的操作会丢失数据,虽然可以像廖老师所说,通过git reflog
查看提交的id,再reset
回去。因为目前我们还是在本地单机操作Git,在多人共同编码的时候,这样的回退不仅容易删除别人的代码,而非常容易操作混乱,造成了很多不必要的麻烦。所以在实际开发中,如果我们需要回退某个提交,我们会使用到revert
。
按照下图的提示点击,注意选择名字为append GPL的commit,如果选择其他commit会有融合冲突,这个我们以后再说。
点击之后,会发现文件退回的同时,弹出一个commit的对话框,如下:
这就是 reset 和 revert 的区别。reset只不过是向后移动了Head指针,如下图:
而 revert 是回滚一个commit,再把这个回滚commit,如下图:
总结一下:
- reset 是删除到某个commit,期间所有commit都会被回滚;revert 是回滚某个commit,只回滚一个commit,并且生成一个新的commit;
- reset 时HEAD是向后移动了;revert 只不过是反向提交,它的HEAD是一直向前的;
- reset 会造成大量的冲突,所以适合在本地开发同时没有push到远端的时候使用;而revert造成的冲突非常有限,适合在push到远端的代码进行回滚。
最后还介绍一种回滚,就是undo。
如果你查看源代码,会发现undo就是reset soft
。
但是idea对它进行了一定的限制和提示,它只能作用于最后一个commit,把这个commit从工作树删除,并且保留修改,同时建立一个New Changlist。效果如下:
这个名为append GPL的New Changlist可以将改动的文件分门别类的放置在不同的文件夹中,等全部修改完毕后一起提交,一般在分模块开发时会使用。也就是在开发完一个完整的模块时,将这个模块上改动的代码设置到一个文件夹中,然后再一起提交。
撤销修改
想要撤销修改需要考虑以下四种情况
- 没有add(idea的自动add只能add新创建的内容,修改过后的内容会在commit的时候自动add)
- 已经add但是未commit
按照如下图所示的操作,即可达到git reset HEAD <file>
和git checkout -- file
的操作。让未commit的修改全部消失。
由于idea的特殊机制,我们还可以有一种操作。
按照下图指示,依次点击左边框的绿色条状长条,回滚箭头,即可撤销修改。这和git checkout -- file
非常类似,但是实现原理不同,git checkout -- file
是使用暂存区的文件替换原有文件,而idea使用的是编译器自身的功能,类似ctrl+z
。
消失的内容可以按照下图指示进行查询。
- 已经commit但是未push
可以使用上文介绍的reset和revert回滚。如果已经add但是未commit的内容非常多,也可以先commit,然后再使用reset和revert回滚。
- 已经push到远程仓库
同样可以使用reset和revert回滚,只不过需要commit+push的操作才能通过修改的方式来实现撤销。
删除文件
如果你使用Git指令,那么你需要像添加操作一样,先手动删除文件,然后使用指令git rm test.txt
,将删除操作加载到暂存库,然后再commit到本地仓库。
如果使用idea的图形化版本控制插件,直接删就行,下次commit会把删除的动作也提交上去。
分支管理
分支的概念请大家从廖雪峰老师的教程里面学习。
创建与合并分支
master就是默认的主分支,创建分支非常简单,只需要按照下图提示点击,弹出对话框输入名字即可。
idea在创建完分支后会自动切换,也就是git checkout -b dev
指令的效果。
如何查找自己所在的分支?非常简单,在编辑器的右下角可以查看。等于git branch
的效果
融合分支(merge)也非常简单,首先我们切换到主分支,操作如下:
然后我们选择要合并的分支点击merge into current。
融合完成后,还是在同一个菜单,点击delete即可删除分支。
解决冲突(merge)
创建一个新的分支,和master分支分别commit不同的内容。具体如下:
feature1分支
Git is a distributed version control system.
Git is free software distributed under the GPL.
Creating a new branch is quick AND simple.
master分支
Git is a distributed version control system.
Git is free software distributed under the GPL.
Creating a new branch is quick & simple.
可以看出两个版本有一个不同就是&和AND,如果merge,会发生什么?会弹出一个冲突的界面。
在这个界面中有很多快捷按钮,但都不是我们介绍的重点,我们需要双击readme.txt来查看冲突并解决它,双击结果如下:
我们可以清晰地看出界面分为左中右三个板块,分别是当前分支master、合并后的结果和需要合并的分支feature。同时上方有很多便捷操作的按钮,具体功能大家可以尝试一下,非常简单。我们合并的主要操作就是三个板块相连的间隔中的X
和>>
来实现,X
就是放弃修改,>>
就是选择修改。同时三个板块都是可以编辑的文件,也就是说在合并过程中你都是可以增加代码和注释的。在这里我们需要放弃&,然后保留AND,合成完成的结果如下:
合并完成我们再看Git log,会发现一个分支创建又合并的过程,应该很好理解。是不是非常方便。
分支管理策略
关于Fast forward模式,廖老师这么说。
通常,合并分支时,如果可能,Git会用Fast forward模式,但这种模式下,删除分支后,会丢掉分支信息。
如果要强制禁用Fast forward模式,Git就会在merge时生成一个新的commit,这样,从分支历史上就可以看出分支信息。
在idea中多分支都有修改的情况下,会默认禁用Fast forward模式的,这样你就会看到合并后的Merge branch 'feature1'的commit。
再如分支策略,廖老师讲的非常简单明了,其实这就是Git Flow,是一种对Git操作的约束,用来让大型项目显得仅仅有条。如果想了解,可以阅读 【一篇文章就够了】浅谈GitFlow。
Bug 分支(stash+cherry-pick)
教程中有这么一个场景:
当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交。并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?
解决方法,就是使用stash,很简单的道理,就是隐藏未提交的代码,并保持。
如图所示,可以看出有两个修改,一个是添加了新的文件file.txt,第二个是加了一行代码。而我们的bug就是comment和author的内容写错了。按照图示进行点击,即可实现git stash
指令的效果。
少顷,修改的代码就会消失,如下图。这时我们就可以切换分支修改bug了,注意当前分支如果有未提交的代码是不能切换分支的会导致代码丢失。
教程中新建立了一个issue-101分支然后修改过后再合并到master,我们就直接在master上面修改即可。
又有一个新的场景。
在master分支上修复了bug后,我们要想一想,dev分支是早期从master分支分出来的,所以,这个bug其实在当前dev分支上也存在。
那怎么在dev分支上修复同样的bug?重复操作一次,提交不就行了?
有木有更简单的方法?
有!
答案就是cherry-pick
命令。如图所示即可实现对单个commit的同步操作。
我们再点击Stash Changes...同一菜单的unStash Changes...来查看stash 列表,效果等同于git stash list
。
View:查看隐藏的代码
Drop:删除选中隐藏
Clear:清空所有隐藏
Apply Stash:将隐藏代码恢复
Pop stash:Apply的同时会Drop隐藏
点击Apply Stash就能让隐藏的代码恢复。注意Stash过后的分支如果你又有新的改动一定要commit,如果不commit,当你使用Apply Stash重新获取代码的时候就会失败,也有可能因为操作不当导致代码消失。如果有了新的commit,在apply stash时就会当成融合冲突处理。就比如我们现在,因为我们融合了master上面修改的代码,所以现在的代码和stash时的代码不一样了,就需要处理一下。方法就和之前的merge一样。
然后就发现代码又回来了,如果这里file.txt没有出现,请刷新一下文件。
feature分支
idea的删除操作如果不成功会再使用强制删除指令进行删除。
同时还会给出一些提示,没有融合的提交会被丢弃。然后你可以Restore撤回,View Commit查看提交。
如果已经推到远程仓库的分支,删除之后会弹出提示框,单机Delete Tracked Branch,即可删除远程仓库的分支
如果错过弹窗,可以直接删除。
git指令如下:
多人协作(pull+push)
廖老师教程中的很多操作都被idea一键化了。我们先新建一个文件夹再次拉取代码,这就是为什么之前说电脑中的一个目录代表一个工作区,如果你换个目录就可以模拟两人同时修改代码的操作。
推送和拉取在idea中形象的被两个简单所表示,蓝色的向下的时拉取,绿色的向上的时推送。idea中拉取是update project。git fetch
是抓取远程仓库修改的内容,抓取到后不会改变本地仓库,只有git merge
的时候才会改变。而git pull
就是fetch+merge的组合,和update project效果一样。
推送就是git push
,一模一样。这里push还有一个小技巧,就是在commit的时候可以直接使用push,省去了多一步的操作。
如何拉取远程仓库分支,如下:
效果就是创建一个本地分支,再和远程仓库进行连接,等同于checkout -b dev origin/dev
。
多人操作的情况下,你的每次改动都需要考虑到别人的代码是否也发生了改动,所有在每次push的时候idea都会主动申请一次pull操作,如果有冲突,先处理冲突在push,没有就直接push。
rebase
什么是变基(rebase)?可以参考以下的文章:https://blog.csdn.net/SafeVidulInfo/article/details/113808961。但是在实际开发中很少使用到变基,因为有一定的危险性,所有使用者尤其是新手一定要慎用。具体如何操作,见下文。
情况一:当合并别人的提交时
当多人提交时,我们必须要先融合别人的代码,所以必定会形成下图这种分叉然后再回归的情况。
而我们使用变基(rebase)就可以避免这一情况。在update project的时候选择下面的选项。
就可以了。
情况二:当合并不同分支时
操作如下:
但是一定要注意,这个和merge的不同,merge是将选择的分支合并到当前分支,而rebase是将当前分支变基到选择的分支。也就是说为了达到合并feature1代码的效果,如果我们使用merge,我们应该切换到dev,然后选择feature1进行merge操作。如果我们使用rebase,我们应该切换到feature1,然后选择dev进行rebase操作。
标签管理
所有的Tag操作应该都在这里了。
Push Tag的操作在push commit的操作窗口的右下角。
删除已经提交的Tag需要再删除远程仓库的Tag,单机提示框的delete on Remote即可
其他
之后的使用GitHub、Gitee、配置别名什么的,就没啥可以讲的了,感兴趣的可以看看。
忽略特殊文件,可以从GitHub项目:gitignore中直接复制。选择Global>JetBrains.gitignore + Java.gitignore 基本上就可以满足了。
SourceTree的话,可以参考 SourceTree的使用介绍。但是笔者还是更喜欢Idea的,不需要再下载一个软件。