两者可兼得,在 IDEA 中使用 Git!

写在前面
工欲善其事必先利其器,在工作中我们写的代码大多数都是通过 Git 进行版本控制的。而面对复杂的 git 命令和不太友好的客户端,可能对于初学者是在不太友好,不管是命令还是 git bash,都不太好操作。
IDEA 作为开发神器,当然也是把 git 集成了进去,这篇文章就是针对 IDEA 使用 Git 作为讲解,就算是初学者也能明明白白学会。
Git 基本操作
首先我们入职一家公司,上司一般会给你一个 Gitlab 链接,让你拉代码,我们会用到 git pull,然后熟悉之后在写代码会用到 git add 等等操作。

git add
当我们新建一个类或者文件时,IDEA 一般会自动弹出如下提示,其作用和 git add 相同。
①

但如果你没有点击或者是跳过了,你可以看到新增的文件是红色的。
②

此时你可以右键选择 git add 操作,操作之后就会变成绿色
③

④

git commit
在 add 文件之后,我们需要提交文件。git 和 svn 的区别就是,git 提交是相当于把代码提交到本地仓库,并没有提交到远端分支上面去。
①
右键选择 commit

②
填写提交记录,一般来说新功能以 feat 开头,修复 bug 以 fix 开头。

可以看到提交之后文件颜色变为黑色。
③

通过 alt+9 或者 View 打开 git 控制台,可以看到最新的提交记录。

git push
上面 commit 代码之后,我们需要把本地代码推送到远程分支上。
①

push 之后我们可以去 gitlab 查看记录。
②

git pull
从远程获取最新版本并 merge 到本地。在主项目上面右键操作 git pull。
①

或者是在上方,看个人喜好。
②

git fetch
从远程获取最新版本到本地,不会自动 merge,并且拉取当前项目的所有分支的的提交。
①

在使用 git fetch 之后可以看到最新的其他人的提交记录,而且是 2 个 master 分支和 feat_branch 分支的提交记录,而我们本地的代码是没有变化的。
我们双击不同分支的提交记录,可以看到对应的差别。
②


git merge
上面说到,git fetch 是不会 merge 的,需要我们自己合并。
①

②
选择对应的分支。

③

通过上面的操作,可以理解 git pull,fetch,merge 的关系。

git fetch
是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中。
而git pull
则是将远程主机的最新内容拉下来后直接合并,即:git pull = git fetch + git merge
,这样可能会产生冲突,需要手动解决,遇到冲突,解决冲突。
git rebase
rebase(变基),官方解释比较干燥,很么意思呢,简单来说就是用于把另一个分支的修改合并到当前分支。
dev 分支是我基于 master 分支拉取的新的分支。


在这之前 master 分支有过 4 次提交记录,此时 master 和 dev 分支都在 C4 节点上。

然后我们在 dev 分支生成 2 个 commit,master 分支也生成 2 个 commit,通过 git 控制台查看日志。

此时,2 个分支处于分叉状态。

我们在 master 分支 rebase dev 分支
①

②
在 rebase 的过程中,可能会出现冲突, 在这种情况,Git 会停止 rebase 并会让你去解决冲突,在解决完冲突后,在 push 到远端仓库。

③

④
此时我们在控制台也可以看到 master 分支变成了一条直线。

即

当然,在实际开发中 rebase 尽量的少用,因为会把别人的提交记录冲掉,如果到时候别人的代码有问题,但是最新的 commit 记录又是你的,你懂的。
git revert
在多人开发的过程中,我们有时会出现错误提交的情况,此时我们希望能撤销提交操作,让程序回到提交前的样子。
revert 用来回滚某个 commit,但是保留了前面或者后面的版本。比如我们 commit 了 3 个版本 C1,C2,C3,
但后面发现版本 C2 有 bug,想要撤销 C2,但又不想影响撤销 C3 的提交,就可以用 git revert 命令来操作,同时生成新的版本 C4,C4 版本里会保留 C3 的提交,但撤销了 C2 的提交。
①
commit3 次

②
在 C2 版本右键 revert

③
合并 C1,C3 版本提交


④
日志记录

git reset
回退到某个版本的所有 commit。如 commit 了 3 版本 C1,C2,C3,如果需要回退到 C1,可以使用 reset。
reset 的作用是修改 HEAD 的位置,即将 HEAD 指向的位置改变为之前存在的某个版本。
HEAD:使用 git 的每次提交,Git 都会自动把它们串成一条时间线,这条时间线就是一个分支。如果没有新建分支,那么只有一条时间线,即只有一个分支,在 Git 里,这个分支叫主分支,即 master 分支。有一个 HEAD 指针指向当前分支(只有一个分支的情况下会指向 master,而 master 是指向最新提交)。每个版本都会有自己的版本信息,如特有的版本号、版本名等。如下图,假设只有一个分支:

①
三次提交记录

②

③

④
代码变为 C1 版本,但这个时候远端仓库的代码并没有回退。

⑤
远端仓库,如果需要修改可再次 push 或者重新拉取分支即可。

常见的使用场景
上面讲了很多 git 操作,其实大部分同学都知道,但在不理想情况下,还是会出现很多问题,比如修改提交记录,多分支合并,代码冲突等等。
git rebase 修改提交记录
假如在某次提交代码太快,还是用的上次的 commit 信息,或者是描述有问题,但是又 commit 了(只 commit 没有 push)
①

此时看 commit 记录是不对的

②

③
通过 rebase 操作修改,选择对应的提交记录,点击 Reword

④
修改后在点击 Start Rebasing

可以看到 commit 信息就修改过来了,此时再去 push 到远端仓库即可
⑤

上面的操作针对的是 commit 操作,并不是 commit&push 操作,也就是说修改的是本地的提交记录。
为什么会有这种情况?
现在很多公司都有代码检查,比如阿里的,或者是 check-style,对应 gitlab 也是可以对 commit 信息做限制的,即 commit 信息未按照指定格式,你执行 commit&push 操作,只会 commit 到本地,而不会 push 到远端。比如我之前的公司 commit 信息的格式为:
上面的冒号规定是英文的,但我手速太快,写成了中文的冒号,此时就不能 push 上去,所以需要修改之后再次 push 即可。
⑥
当然,还有个最简单的办法,右键 commit 的记录,会直接弹出一个修改框。

⑦
修改点击 ok 即可

那就有人问了,那如果是代码检查不通过怎么办?我是需要修改代码再次 commit 的,那我同一个功能,就因为代码检查提交 2 次,日志看起来也比较冗余。看下面👇
git rebase 合并多次提交记录
因为多次重复 commit,代码功能不变,但因为小问题,比如代码检查出直接使用魔幻数字
等,需要把多次 commit 合并为一个,或者是初始的 commit 记录。
①
假如此时有 3 次 commit 记录(未 push)

②
使用 rebase 选中 3 次 commit 记录点击 Squash

③

④
再看提交记录,发现合为了一个 commit 记录,然后再 push 代码就可以了

注意:不要去 rebase 别人的代码
cherry-pick 获取指定的 commit
在多分支代码版本的情况下,经常遇到一个分支的代码转移到另外一个分支。常见的就是 2 个版本,一个开发版 dev,和一个定版 master(或者 release),作为开发者,必定是在 dev 分支上开发新功能并且测试通过之后才会合并得到 master 分支上去,这就涉及到如何合并过去,因为这期间可能有其他人也提交了代码,如果用 merge 会把一个分支的所有代码变动都提交上去,大概离会产生冲突,那我自己合自己的代码就行了。
①
假如我在 dev 开发了一个功能,此时我在 dev 分支上,在 IDEA 走下角可以看到

②
在代码测试通过之后需要上线,此时需要把代码更新到定版,即 dev--->master
首先我们可以在 IDEA 上切换到 master 分支

③
此时可以看到 master 分支也有 commit 记录,并且代码也过来了,然后再 push 上去就可以了

git stash 临时保存和回复修改
当正在 dev 分支上开发某个项目,这时项目中出现一个 bug,需要紧急修复,但是正在开发的内容只完成一半,还不想提交,这时可以用 git stash 命令将修改的内容保存至堆栈区,然后顺利切换到 hotfix 分支进行 bug 修复,修复完成后,再次切回到 dev 分支,从堆栈中恢复(UnStash)刚刚保存的内容。
还有就是在分支之间切换过程中,本应该在 dev 分支开发的内容,却在 master 上进行了开发,需要重新切回到 dev 分支上进行开发,可以用 git stash 将内容保存至堆栈中,切回到 dev 分支后,再次恢复内容即可。
①
假如我现在因为新功能新增了几个 class 类或者修改了文件,但是本来要在 dev 分支开发的,结果却在 master 分支开发了,当我想切换回 dev 分支的时候确报错了。

②
此时我们只需要 stash,把本地改动保存起来即可。

③
然后再切换到 dev 分支,点击 UnStash

④
应用即可

stash 还可以用来解决冲突,一般来说,每天上班的第一件事就是 pull 代码,但有的时候忘记了,直接开始开发,但是别人有 commit 代码,也就是说相当于你本地的代码是落后版本的,当你写完代码再去 pull 发现可能会有冲突,文件要是过多,修改的也多不可能去一个个的 ctrl+z,所以就可以暂存本地,保持代码的干净,在去 pull,然后再回复即可。
总结
Git 现在基本上是必会的知识点,如果记不住命令,那就可以使用工具,不只是 IDEA,还有很多的 git GUI 可以使用,如 TortoiseGit,SourceTree,GitHub for Desktop 等,但不管什么工具,主要在于多用,熟能生巧。
参考
拓展延伸
学会了 Git,SVN 也不能忘记,说说他们之间的区别?
git reset 和 revert 的区别,merge 和 cherry-pick 的区别?
文章首发:两者可兼得,在IDEA中使用Git!
公众号:Javatv

版权声明: 本文为 InfoQ 作者【阿粤Ayue】的原创文章。
原文链接:【http://xie.infoq.cn/article/9bc8826a38e61d690297e9a6f】。文章转载请联系作者。
评论