Git使用对于我们来说是熟悉不过的了,但总有一些技术,即便我们日日相见,但离清清楚楚总有很远的距离,更可怕的是,这个距离似乎并没有缩短的趋势。

那么,我是要写些能够让git变得清清楚楚的东西么?额,并不是,要弄清楚,还是得花时间去看官方文档,去看原理,以上只是提醒一下大家。

其实,对于我个人而言,我是没有系统学习过git的(当然这是十分不可取的),当时是在使用SVN,后来公司切成了Git,然后看了几个命令就直接开始使用了,相信这也是很多人的开端。初初使用时,总不自觉去与SVN做对标,但是,其实对的很艰难,幸而我忘性比较大,没几天就忘了SVN命令了,才使得Git的使用更加顺畅。

Git的一些优质特性,总结起来就是完全分散式、快速、低成本分支等等,不再赘述,现在它在我眼中就是版本管理工具应有的样子(毕竟我已经忘了SVN)。

本文仅仅记录了一些我在Git使用过程中的一些实战经验,各个命令有写详细的注释,可以关注一下,整体内容不系统,但会持续更新。

冷启动

刚刚提到,我是"被迫"使用Git的,就不得不提一下,我的Git冷启动。记得我第一次使用的时候看同事写了一个类似下面的一些命令的wiki,虽然很久以后才明白这些命令都是个啥,但丝毫没影响我用的飞起,且很长时间都没需要查其他命令。

# 这是一套比较常用的开始一个新项目的git命令集

# 克隆远程仓库到本地
git clone http://gitlab.sftcwl.com/fe/knight.git

# 在使用gitlab时,我们一般是在gitlab页面上直接新增远程分支,这时需要在本地建立远程分支的跟踪分支【1.6.2以上版本】;
git checkout --track origin/develop

# 此时自动切到分支develop上,just coding

# 将所有文件纳入版本控制,多数使用是都直接"add .";
git add .

# 提交,附带注释
git commit -m "some commit info"

# 与远程仓库交互
# 完整的命令是 git push [远程名] [本地分支名]:[远程分支名],但是由于我们建立的是跟踪分支,可以直接推送;同时注意,如果远程分支不存在,此命令会自动创建同名远程分支;
git push

# 与远程仓库交互
# 将远端数据拉到本地仓库,并不自动合并到当前工作分支
git fetch

# 与远程仓库交互
# git pull 可以理解为使用给定的参数运行 git fetch 命令,并调用 git merge 进行合并;
# 同 git push 一样,这也是建立跟踪分支后的简写;
git pull

这套命令下来非常简单,理论上,只要你一直一个人开发一个项目,这一套命令就足足的了;但现实中,多数情况下是很多个人在一个项目上一起造,这也正是版本管理更直接的意义;

下面是我在开发中遇到的一些情况,希望对大家有所帮助;

删除文件

对于前端来说,node_modules是用来存放第三方代码的,一般并不纳入版本管理,但是在首次提交时,有时会忘记在.gitignore中添加忽略,导致node_modules被上传到git仓库,此时怎样处理比较方便、恰当呢?

# rm是与add相对应的命令,加cached参数的意思是将node_modules从版本控制中移除,但并非真正在硬碟上删除node_modules,-r的意义就显而易见了;
git rm --cached node_modules -r

# 在.gitignore文件中将node_modules加入忽略;

# 常规提交代码;
git add .
git commit -m "add node_modules in ignore file"
git push

合并

无论是在开发分支上需要时不时同步master分支代码,还是上线前需要将开发分支代码合入到master,我们都需要经常使用合并命令。

# 奇怪的是,这个命令运行完,每次的提示可能都不一样,这是为什么呢?
git merge branch-name

在运行git merge命令时,有时会出现『Fast forward』的提示,这是由于当前分支所在的提交对象是要并入的分支的直接上游,Git此时只需要把分支指针直接移至下游,所以这种合并过程可以称为快进(Fast forward),最幸福的merge;

当merge的两个分支,并非简单的上下游关系,Git会使用两个分支的共同祖先,及两个分支各自末端的提交对象,进行一个三方合并计算,并自动创建一个新的提交对象;此时是有可能会出现冲突,需要人手动合并的。

# 合并遇到冲突了,git也没有简单的放弃,而是给你汇总出一个结果,方便你去抉择
# 手动将代码修正到你满意的状态后,需要将它们标记为已解决状态
git add filename

# 在提交记录中,标明此次提交为解决冲突
git commit

让你的commit可以被命名

我有一个不好的开发习惯,每次开发时,想起提交来就提交,每次提交的内容非常散乱,没办法概括,经常改好几个bug才想起来提交一次,或者一个bug改到一半提交一下。这当然是很不专业的了,这大概是将git当做一个代码管理工具,而非版本管理了;

让你的commit可以被命名,简单来说就是一次提交只做一件事,而且是一件完整的事情,但是说起来容易,实施时经常是,我以为OK了,提交了,结果发现漏了一些东西,这时要怎么办呢?

git commit -m "add function user management"
git add forgotten_files

# 使用--amend选项,相当于将两次提交合并为同一条,同时此命令还可用于修改提交说明
git commit --amend

可能不能挽回的操作

任何已经提交到Git的数据都可以恢复,即便在已经删除的分支中的提交。但是,这不意味著任何时候你的数据都能够恢复,对于那些没有提交过的数据,Git是无能为力的。

有时存在这样一种场景,当你修改了某个文件,比如说readme文件,并且已经暂存,这时候你觉得这个修改是没必要的,怎么办?

# 一步一步来,首先得撤销暂存;
# 前面有提到过,可以使用rm命令将对文件的跟踪取消掉,但一定要记得加cached参数
git rm --cached readme
# 其实rm命令还是用起来很危险的,更提倡的是使用下面的命令将指定文件变更到unstage状态
git reset HEAD readme

# 下一步将文件代码恢复到修改之前
git checkout -- readme

# 运行完毕,文件回到了修改前,且无法挽回;

分支管理

对于分支的管理,有很多完备的方案,但是我这里想说的并不是一个完备的方案,而是一个在开发中形成的简化方案。

这个方案仅针对中小型项目,10人以内的合作项目。很多分支管理方案,主张维护多个长期分支,其实对于中小型项目是没有必要的,反而由于稳定分支多、流程长,可能导致一些流程上的失误。

我们的方案是,仅仅维护一个长期分支,也就是master分支,所有分支都是从master检出的特性分支,分支命名采用「版本_特性_开发人员代号」的方式,同一个版本的多个分支,在集成测试前合并至同一分支即可,所有分支合完即删(本地分支、远程分支均需删除);在分支命名中加入开发人员代号,也可以使分支的归属更清晰明确,给开发人员一种暗示,敦促其完成分支的合并,并及时检视是否有多余的、未完成的分支。

但是很快会有同学说,那如果开发时有一些公共的组件之类的代码怎么办呢?我们的方案也非常简单,单拉分支,完成公共特性开发,并提merge request给项目的owner,由owner(只有owner有master分支的提交许可权) review代码后,直接合入master。这里不得不提醒大家,这样可能会造成生产环境代码与master代码不一致,但是如果上线打过tag,也没必要担心;

这一套下来,能够满足99%的开发场景,而我们也实在没有必要为1%的可能性,增加我们分支管理的复杂度。

# 上面提到分支的删除,本地分支的删除非常简单;
git branch -d local_branch_name

# 对于远程分支的删除,我们使用什么命令? git push [远程名] :[远程分支名]
# 这个命令真是有点无厘头,据说来源于git push [远程名] [本地分支]:[远程分支],可以理解为把空白推送到远程分支,远程分支就被删除了
git push origin :remote_branch_name

Git Status

搞事情前习惯敲一下 git status 命令,来看一下情况,或者在使用的代码编辑器上引入Git相关的插件,时刻注意自己所在的分支,修改的状态等等;

当你反复被拒绝时

当你各种姿势都提交不了代码,各种方式都合并不了分支,当你反复被拒绝时,仔细阅读它给出的理由,大多数时候它都不是在敷衍你。


推荐阅读:
相关文章