GIT版本管理:场景命令实战

#0 系列目录#

Git 相比 Subversion,无论概念上还是使用上,复杂度其实是高出一个等级的。为什么这么说?分别看下 git help -a 和 svn help 命令清单的对比,单按这个来看,就如果要掌握所有命令的用法,Git 的学习曲线绝对是比 Subversion 高的。尽管如此,但还是有越来越多项目开始用 Git 来做源码管理了。

实际中,我们用到的的 Git 命令还是很有限的,可能也就 git help 中那些而已。

#1 “新人报道”# 你刚入职一家公司,或新加入某个团队,立马参与到一个项目中,那么就得获取项目代码,开始你的项目生涯。这个时候一般你需要克隆一份项目代码,下面都以 GitHub 上的项目地址为例:

$ git clone git@github.com:akun/pm.git

之后就进入项目目录,运行项目中的构建脚本,然后就可以熟悉代码,展开具体工作了。

当然,有的时候,有一个新项目是由你发起的,你要将初始化的项目工程放到 Git 版本仓库中

$ mkdir pm
$ cd pm
$ git init
$ touch README.md
$ git add README.md
$ git commit

Git是分布式的版本控制系统,所以刚才的操作,算是已经在你本地版本控制起来了,为了推送本地仓库到远程仓库,就还得执行:

$ git remote add origin git@github.com:akun/pm.git
$ git push -u origin master

一般这个时候都会设置下 ~/.gitconfig 或 .git/config 中的配置,最基本的就是用户名和邮箱。

确认当前的 Git 配置信息:

$ git config --list

设置用户名和邮箱:

$ git config user.name akun
$ git config user.email admin@example.com

刚才的命令只是对 .git/config 生效,如果想全局生效,也就是 ~/.gitconfig,就得加上 --global 参数,比如:

$ git config --global user.name akun
$ git config --global user.email admin@example.com

#2 日常工作# 当你已经逐渐融入了一个项目,可能一天的工作场景或完成某个任务的工作周期是这样的:

##2.1 更新## 无论是清早或下午或晚上,开始了你的一天工作,你首先会更新你的工作目录:

$ cd ~/projects/pm
$ git checkout develop  # 我想在 develop 分支上开始一天的工作

更新方式一:

$ git fetch --all  # 从远程仓库获取所有分支的代码变更
$ git merge

更新方式二:

$ git fetch --all
$ git rebase  # 默认就衍合 develop 分支的代码了

更新方式三,可以认为是 fetch 和 merge 的合集:

$ git pull  # 懒得理解 fetch 和 merge 就直接 pull 吧

这样你就可以在最新的项目代码基础上工作了。

注解:

  • git pull --rebase 相当于是前面的方式二的合集

  • 这里说的三种方式,可能每个人或团队都有自己的习惯吧

  • 想了解 Git 中的“衍合”,可以实践下这个文档:Git-分支-分支的衍合

##2.2 修改## 可能你写了一个新的模块,需要纳入项目的版本控制:

$ git add tools.py

可能你发现某个模块已经陈旧了,不再使用了:

$ git rm utils.py

可能你发现一个模块的命名不太合理,需要改名:

$ git mv model.py models.py

可能你要创建一个新的较大的模块,需要归档为目录的方式:

$ mkdir groups
$ touch groups/__init__.py
$ git add groups/__init__.py

注解:

Git 不支持空文件加加入版本控制,非得必要咋办,后续的其它场景会简单说明下。

可能你发现要写的模块代码布局类似于旧的模块,直接复制个代码模版:

$ cp users/tests.py groups/tests.py
$ git add groups/tests.py

注解:

Git 没有自带的所谓 cp 命令

##2.3 检查## 忙碌的一天过去了,或者一个任务完成了,这个时候一般会将你的工作成果,也就是代码更新到版本仓库(分为本地版本仓库和远程版本仓库)。

习惯上会先检查下修改状态:

$ git status

看到一些 Git 状态信息,确认是修改了哪些文件,之后一般会自己 code review 一下代码的改动,可能有的人会习惯直接用 Git 方式来查看:

$ git diff

这里的 diff 只是查看其中“工作目录”和“暂存区域”的区别。要查看“暂存区域”和“本地仓库”的区别,可以用:

$ git diff --staged  # 或 git diff --cached

注解:

最好理解下三个区的概念,以代码角度来理解:

工作目录:git clone 后获得的一份本地的代码,也包括新编辑的,尚未加入版本控制的代码

暂存区域:git add 后暂存起来,尚未 git commit 的代码

本地仓库:git commit 后正式被版本控制记录起来的代码

可以看下图,能更好的理解这三个区:

输入图片说明

然后本地运行下相关的单元测试,确认是否有问题。一般来说这个时候,没有什么特殊情况,就直接进入“提交”甚至是“推送”阶段了,然后结束一个工作日或工作周期,但难免会有些特殊情况出现。

##2.4 取消修改## 当你 code review 完后,发现有些改动不满意;或者运行完单元测试,发现有些测试用例没通过,你可能会进行取消这些修改的操作。

如果还没 add,那么可以:

$ git checkout -- main.py

为了避免刚好跟分支名重合,所以加了两个斜杠(虽然概率很低),如果已经 add 了,但还没 commit,那么可以:

$ git reset HEAD main.py

万一刚提交完毕,也就是已经 commit 了,才发现代码有问题,比如:忘记把某个文件提交了,这个时候咋办?Git 好处是可以覆盖上一次提交,那么可以:

$ git add tests.py
$ git commit --amend

上面还只是简单的撤销操作,Git 还能支持更高级的重写历史功能,想掌握高级技能的可以实践下这个文档:Git-工具-重写历史

##2.5 解决冲突## 有时候同别人合作写一个模块的代码,会把对方代码合并或衍合过来,比如:对方修复了某个缺陷,你刚好也需要这个修复;再比如:对方完成了某个特性,你也刚好需要用下这 个特性等等各种情况。

大多数情况,代码的合并或衍合不会冲突,但也有冲突的情况,分两种情况说明,第一种是合并操作时候有冲突

$ git fetch --all
$ git merge bugfix/remove_error
# 这个时候就提示你代码冲突了,处理完冲突的代码后
$ git diff  # code review 下代码
$ git add remove.py
$ git commit
# 日志中就多了一条合并操作的日志了

另一种是衍合操作时有冲突

$ git fetch --all
$ git rebase bugfix/remove_error
# 这个时候就提示你代码冲突了,处理完冲突的代码后
$ git diff  # code review 下代码
$ git rebase --continue  # 有时候会 git rebase --skip
# 直到不用再 rebase 为止

##2.6 提交到本地版本仓库## 最后,一切确认没问题了:code review 完毕,自己觉得代码满意了;有可能也合并完别人的修改并且没有冲突了;运行单元测试也通过了。那么就提交代码吧:

$ git commit

##2.7 推送到远程版本仓库## Git 中的 commit 只是提交到自己本地的版本控制仓库,如果想分享你的代码提交,还需要推送到远程的版本控制仓库:

$ git push

#3 在分支工作# ##3.1 创建新的本地分支## 确定要新开个分支来写代码,这里以贡献新特性为例子:

$ git checkout -b features/batch_remove
$ git branch -a  # 确认已经在新分支中工作了
$ git log  # 可以确认是基于刚才的分支新分出来的

这里已经隐含了自动切换到新分支的动作了。

##3.2 在新的本地分支工作## 类似,“日常工作”中的工作周期操作,这个时候,你就可以在新分支中进行大刀阔斧的工作了,直到分支中代码符合要求。

##3.3 推送成为作为远程分支## 如果想把分支分享给别人,可以推送到远程版本库,这样别人可以根据需要来把你的分支代码更新到他自己的本地仓库,例如:

$ git push origin features/batch_remove

##3.4 合并或衍合远程分支## 在分支中工作一段时间后,确认相关的功能代码、测试代码、文档等都提交完毕了,单元测试通过,大家 code review 一致认为没问题,审核通过,最后该分支的持续集成(CI)完整 build 通过。这个时候,就可以进行合并的操作了。

其实前面也提过类似操作,这里再类似重复一遍,如果用合并:

$ git fetch --all
$ git merge features/batch_remove
# 如果没提示冲突,那就合并成功
# 如果这个时候就提示你代码冲突了,处理完冲突的代码后
$ git diff  # code review 下代码
$ git add batch.py
$ git commit
# 日志中就多了一条合并操作的日志了

如果用衍合:

$ git fetch --all
$ git rebase features/batch_remove
# 如果没提示冲突,那就衍合成功
# 如果这个时候就提示你代码冲突了,处理完冲突的代码后
$ git diff  # code review 下代码
$ git rebase --continue  # 有时候会 git rebase --skip
# 直到不用再 rebase 为止

这里也提下直接合并本地分支,有时候你创建的分支只是自己用用,没有共享给别人,因为本地已经有了这份分支代码了,那么就省去 git fetch 操作,类似上述方式合并或衍合代码就行。

对比 Subversion 的分支合并操作,实在是简化不少。

##3.5 删除分支## 如果确认工作完毕的分支不再需要了,那就记得及时清理掉,删除远程分支

$ git push origin :features/batch_remove

删除本地分支:

$ git branch -d features/batch_remove

顺便说下,一段时间后,一定有一堆别人的分支,然后你 git fetch 下来了,这样就出现在本地的分支清单中,但远程版本库中已经删除了,如果想本地分支清单干净些,可以在 git fetch 时候这样执行:

$ git fetch --all -p

#4 发布分支# 可能在平时的研发分支工作一段时间后,并且测试完毕,大家觉得符合发布条件了。终于可以进入到版本发布阶段的工作了。

##4.1 创建发布分支## 一般来说这个时候已经将在某个发布分支上工作了,比如:

$ git checkout -b release-1.2 develop  # develop 就是平时的研发分支
$ release.sh 1.2  # 比如有个执行发布脚本
$ git commit

##4.2 打标签## 确定可以发布了,就开始打标签吧,比如:

$ git checkout master
$ git merge --no-ff release-1.2
$ git tag -a v1.2
$ git tag  # 确认下打上了标签了
$ git push origin v1.2  # 推送标签到远程版本库

#5 其它场景# code review 查看代码,要知道对应代码是由谁写的,好询问了解具体代码的思路:

$ git blame

跟踪问题时候,会查看日志,更方便历史代码定位:

$ git log

觉得完整的 Git 命令太长,想用类似 Subversion 的缩写命令,可以用 alias,比如配置文件中可以写上:

[alias]
    br = branch
    ci = commit
    co = checkout
    diffs = diff --staged
    st = status
    lg = log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%aD%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''%C(white)%s%C(reset) %C(dim white)- %an%C(reset)' --all

有时候合并或衍合代码,但本地有修改了一半的代码没有提交,可以先暂存起来:

$ git stash
# 合并或衍合完毕代码后
$ git stash pop  # 恢复刚才修改了一半的代码

原来的一个项目想拆分多个项目,又想保留版本仓库记录,可以用下 git subtree split,例如:

$ git subtree split --prefix=plugins/sqli

Git 不支持空文件夹加入版本控制,变通方式:

$ mkdir downloads
$ vim downloads/.gitignore  # 增加 * 和 !.gitignore 这两条规则

对于习惯命令行下编程的程序员来说,多看帮助总是好的,直接执行:

$ git help

可以看到 Git 的常用命令,如果想看到更全的 Git 命令,可以执行:

$ git help -a

单独查看某个命令的帮助,可以执行:

$ git help add  # 比如 add 命令

这里顺带说下几个使用 Git 的好习惯,但有的其实跟 Git 联系也不算大,只是顺带提下:

**保持工作目录干净。**或者说工作目录中的代码变更就为了完成一个任务,即一次只做一件事。完成任务后,就直接 git commit 提交到本地版本仓库的某个分支中,而不用担心其它任务作出的代码变更无提交。并且,对于分支切换更方便,而不用担心代码被覆盖或冲突的问题。

**Git 的日志信息足够有效。**足够有效的意思,是说这次提交作出的变更摘要,只要别人阅读了日志就能知道大概,如果为了深入了解变更细节才会去查看具体代码变更。

**git commit 前 code review。**code review 本身就是个好习惯,提交前确认是一种更为严谨的方式,如果觉得自己 code review 发现不了什么问题,那么随便从身边抓个会代码的,跟别人讲解下代码变更的内容,说不定会发现你没考虑到的问题。

**git commit 前跑单元测试。**写单元测试本身也是个不错的习惯,如果项目本身已经有了完备的单元测试覆盖了,那么你对代码的修改,应该能通过单元测试,所以提交前执行一遍是否通过。如果没通过,就得看下是功能代码写的有问题,还是测试代码有问题,比如:功能需求或接口设计有变化,而测试代码没有同步更新。

**有代码变更及时提交。**有 Git 这种版本控制工具,本身就是为了记录研发过程,避免意外导致代码丢失,如果为了完成某个任务需要很长时间,代码也很久没有提交,风险太高。这个时候,一般会自己开个分支,而将代码提交到分支中,既解决代码要及时提交的问题,又解决代码提交频繁,可能造成代码不稳定影响别人的问题,因为那个分支只有你自己在工作。而这一点,Git 分支的功能更为强大,更加鼓励多开分支。

转载于:https://my.oschina.net/xianggao/blog/666867

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值