部门内要做技术分享, 我选择了分享git相关的知识, 现在贴出来, 供大家学习参考.
目录:
Git is a
free and open source
distributed version control system
designed to
handle everything from small to very large projects
with
speed and efficiency.
– https://git-scm.com/
“自由,开源,分布式的版本控制系统?”
– Pony
“快速, 高效?”
– Jack
“一千个读者心里有一千个哈姆雷特”, 1024个攻城狮就有1024个git.
关于什么是git, 当你用熟悉后心里自然会有一个答案, 别人再多的解释都不如自己的理解.
强大的分支模型, 独特的暂存区设计, 分布式特性…
git commit
或者其他操作(如git merge
)会生成一个commit id, 此为一个提交. 实质为将暂存区的修改同步到版本库, 根据语境可分为动词或者名词.git tag v1.0
).下述描述中, 如无特别说明, “版本库"特指"本地版本库”.
略.
个人根据自己系统环境(Linux, MacOS, Win)自行安装.
我的环境:
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/tmp
git version
git version 2.21.0.windows.1
config
# git账户配置
git config --global user.email [email protected]
git config --global user.name gl
# 子命令别名配置
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.cm commit -m
git config --global alias.df diff
git config --global alias.sh stash
git config --global alias.ci commit
git config --global alias.lg log --graph
git config --global alias.lgo log --graph --oneline
git config --global alias.logf log --pretty format:"%h%x09%an%x09%ad%x09%s"
git config --global alias.cpk cherry-pick
git init myrepo # 在当前目录下创建版本库myrepo(自动创建myrepo目录)
git clone [email protected]:my-test-group/git-share.git
git status
# 精简输出
git status -s
git diff # 查看工作区与暂存区的差异
git diff --cached # 查看暂存区和版本库的差异
git diff HEAD # 查看工作区和版本库的差异
git branch -a
git branch
git branch -m new-branch # 创建并切换到新分支
git checkout some-branch # 切换到 some-branch分支
git checkout -b new-branch # 基于当前分支 创建并切换到 new-branch分支
# 用暂存区的main.c覆盖工作区的main.c
# 注意: 工作区中的main.c会被覆盖, 比较危险, 慎用!
git checkout -- main.c
# 用暂存区覆盖整个工作区, 非常危险, 慎用!!!
git checkout -- .
git stash list # 查看有哪些stash
git stash save "为本次临时存储写一些说明" # 推荐此种用法
git stash pop # 取出最近一次stash
git stash apply stash@{1} # 将倒数第二次stash应用到工作区.(stash从0开始编写)
git stash drop stash@{1} # 删除倒数第二次stash, 慎用
git stash clear # 删除所有stash, 慎用
fetch(下载但不合并)
# 下载所有分支
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/project/git-share (feature-share)
$ git fetch -v
From my.gitlab.com:my-test-group/git-share
= [up to date] feature-share -> origin/feature-share
= [up to date] master -> origin/master
# 下载指定分支
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/project/git-share (feature-share)
$ git fetch -v origin master
From my.gitlab.com:my-test-group/git-share
* branch master -> FETCH_HEAD
= [up to date] master -> origin/master
remote (远程仓库管理)
# 为远程版本库[email protected]:my-test-group/git-share.git起个别名(绑定)为origin
git remote add origin [email protected]:my-test-group/git-share.git
# 查看有哪些远程版本库别名
$ git remote
origin
# 上述一条的详细输出
git remote -v
origin [email protected]:my-test-group/git-share.git (fetch)
origin [email protected]:my-test-group/git-share.git (push)
pull(下载并合并)
# 下载并合并master分支
git pull -v origin master
# 下载远程分支dev到本地, 并重新命名为dev-local
# dev-local仅为说明参数顺序, 实际应保持远程和本地分支名称一致.
git pull -v origin dev:dev-local
push(推送)
# 推送本地feature-xxx分支到远程, 并在远程创建同名分支, 并作关联(-u)
git push -u origin feature-xxx:feature-xxx
# 强制推送, 慎用
git push -f
git log
git log --oneline # 简短输出
git log --oneline --graph # 带有"分支树"格式的输出
git log -2 # 查看最近两次提交日志
ref: https://nvie.com/posts/a-successful-git-branching-model/
上面的文章和图建议仔细阅读, 会有不少收获
开发工作流总述:
git工作流是基于git的分支功能而来. 也和开发环境有关系.
一般而言: 会有4个代码环境(根据实际情况, 可能会更多).
注意看上图:
共有5个(确切来说, 有2个长驻(长期存在)的分支: dev和master, 还有三类分支: feature, release, hotfix.
实际使用时, 可以根据需要增加一些其他分支, 如bugfix分支,
是一些测试环境的bug修改, 由于也不是新特性, 所以叫feature也不太好, 如"bugfix-get_user_list_no_response"
可以简单地这样认为:
如果环境没有那么多, 比如没有预发布环境, 需要根据情况取舍(比如预发布和公共测试环境为一套环境)
其中:
准备: 以gitlab为例子, 建立群组(group)my-group, 然后再创建项目demo, 再基于分支master(gitlab自动创建的)建立分支dev. master为默认分支.
此时大概是这样的:
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace
$ cd /d/workspace/
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace
$ git clone [email protected]:my-group/demo.git
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace
$ cd demo/
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
上面我们在 /d/worksapce 目录下, clone了demo项目. git status
查看了下状态.
假设现在我们接到一个需求, 功能有"添加到购物车"和"支付", 版本定为1.0.
基于上述的工作流策略及分支命名规则,
我们可以这样:
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# 查看所有分支, 发现远端有个dev没clone到本地
$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/dev
remotes/origin/master
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# 远端dev分支clone到本地, 并在本地建立同名分支
$ git pull origin dev:dev
From my.gitlab.com:my-group/demo
* [new branch] dev -> dev
Already up to date.
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# 基于dev开一个分支, 代表"添加到购物车"这个功能在这里开发
$ git checkout -b feature-shopping-car dev
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-shopping-car)
# 基于dev开一个分支, 代表"支付"这个功能在这里开发
$ git checkout -b feature-pay dev
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-pay)
# 切换分支到 feature-shopping-car, 准备开发 "添加到购物车"这个功能
$ git checkout feature-shopping-car
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-shopping-car)
# 查看一下现有分支, 我们正处于feature-shopping-car这个分支上
$ git br -a
dev
feature-pay
* feature-shopping-car
master
remotes/origin/HEAD -> origin/master
remotes/origin/dev
remotes/origin/master
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-shopping-car)
# 模拟完成需求
$ echo "添加商品1到购物车" >> shopping-car.txt
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-shopping-car)
$ echo "添加商品N到购物车" >> shopping-car.txt
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-shopping-car)
$ echo "添加完成!" >> shopping-car.txt
# 查看当前状态, st为status的别名, 注意参看本文开始的配置, 下此类情况不再赘述
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-shopping-car)
$ git st
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-shopping-car)
# 工作区变更添加到暂存区
$ git add shopping-car.txt
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-shopping-car)
# 提交到版本库
$ git cm "添加到购物车功能完成"
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-shopping-car)
# 切换到feature-pay分支准备开发"支付功能"
$ git co feature-pay
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-pay)
# 模拟开发支付功能(计算有错误为故意设置, 后面会用到)
$ cat >pay.txt < 计算总价格: 10+20=40
> 计算完成
> 支付
> 支付完成
> EOF
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-pay)
# 添加到暂存区
$ git add pay.txt
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-pay)
# 支付功能开发完成, 提交到版本库
$ git cm "支付功能完成"
上面我们有个需求, 版本定为1.0, 我们根据需求开了两个分支:
“feature-shopping-cart"和"feature-pay”, 实际可以根据需要起名为: “feature-1.0-shopping-car”,
因为可能两个并行的版本有同一个功能都在开发, 以示区分.
feature分支我们没有演示推送(push)操作, 这个看情况, 为了避免"磁盘损坏"导致代码丢失的情况发生,
建议feature分支也推送, 用完删除即可.
上面我们已经开发完了所有功能, 在测试没啥问题后, 就可以进入预发布环境了:
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (feature-pay)
# 进入dev分支准备合并
$ git co dev
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (dev)
# 合并"支付"功能到dev分支, 注意--no-ff会保留分支信息, 下同
$ git merge --no-ff feature-pay
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (dev)
# 合并"添加到购物车"功能到dev分支
$ git merge --no-ff feature-shopping-car
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (dev)
# 查看dev的记录, 可以看到分支合并的信息(分叉), git log --oneline --graph
$ git lgo
* 8efcbc0 (HEAD -> dev) Merge branch 'feature-shopping-car' into dev
|\
| * cd6dde0 (feature-shopping-car) 添加到购物车功能完成
* | 0cde2ea Merge branch 'feature-pay' into dev
|\ \
| |/
|/|
| * 2da3542 (feature-pay) 支付功能完成
|/
* 2471ab4 (origin/master, origin/dev, origin/HEAD, master) Initial commit
# 推送dev到远程
$ git push origin dev
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (dev)
# feature合并完了, 再基于dev开一个release分支出来
# 表示此次需求我们功能已经开发完成, 测试也没啥问题
# 进入预发布阶段
$ git co -b release-shoppin$ git co -b release-shopping
# 合并完成后, 可以删除已经合并过的feature相关分支了
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 删除feature分支
$ git br -d feature-shopping-car
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 删除feature分支
$ git br -d feature-pay
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 看看release分支的文件, 是我们期待的
$ ls
pay.txt README.md shopping-car.txt
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 推送release分支, -u表示关联上游分支
$ git push -u origin release-shopping:release-shopping
......
* [new branch] release-shopping -> release-shopping
Branch 'release-shopping' set up to track remote branch 'release-shopping' from 'origin'.
"feature-*"分支很多时候由开发人员自己控制, 上面根据需求开了两个, 其实可以开更多, 比如
“购物车过期商品过滤”, "支付校验"等.
当众多分支合并到dev时, 导致日志输出可能非常混乱, 难以查看.
建议:
可以自己将feature的提交整理后再合并到dev分支, 可以参考以下几点:
预发布环境只是与正式环境尽可能一致, 当然不可能完全一致, 所以在这里可以再做一些测试.
测试过程中我们发现, 支付时, 金额计算的有误(看上面的支付修改的"代码"):
计算总价格: 10+20=40
在release分支上发现bug是正常的, 因为还没有上线(发到正式)嘛, 我们改下, 再提交
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 为了演示, 用sed而不用vim改对
$ sed -i 's/10+20=40/10+20=30/g' pay.txt
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 确认下, 我们改对了
$ cat pay.txt
计算总价格: 10+20=30
计算完成
支付
支付完成
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 查看下状态, 工作区有发动
$ git st
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 添加到暂存区
$ git add pay.txt
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 提交到版本库
$ git cm "支付计算错误修改"
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 推送到远程版本库, 注意这里没有写成 git push origin release-shopping,
* 是由于我们之前推送到release分支时,使用了 -u 选项, 已经和远程的release-shopping作了关联
$ git push
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 查看下release分支现有的提交记录
$ git lgo
* 5d477fd (HEAD -> release-shopping, origin/release-shopping) 支付计算错误修改
* 8efcbc0 (dev) Merge branch 'feature-shopping-car' into dev
|\
| * cd6dde0 添加到购物车功能完成
* | 0cde2ea Merge branch 'feature-pay' into dev
|\ \
| |/
|/|
| * 2da3542 支付功能完成
|/
* 2471ab4 (origin/master, origin/dev, origin/HEAD, master) Initial commit
经过测试, release分支没啥问题了, 我们来发布.
一般来说, 这一步需要管理员来处理, 毕竟是对master分支有改动的操作.
这里只是为了演示流程:
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (release-shopping)
# 切换到master
$ git co master
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# 将release合并到master, 注意--squash选项是合并提交
# 这样merge后, 需要手动commit一下
$ git merge --squash release-shopping
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# 查看master的日志还是老样子
$ git lgo
* 2471ab4 (HEAD -> master, origin/master, origin/dev, origin/HEAD) Initial commit
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# 查看master的状态, 发现暂存区有变化
$ git st
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD ..." to unstage)
new file: pay.txt
new file: shopping-car.txt
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# 我们手动提交下
$ git cm "v1.1: 添加到购物车, 支付功能"
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# 再查看日志
$ git lgo
* 142bb0b (HEAD -> master) v1.1: 添加到购物车, 支付功能
* 2471ab4 (origin/master, origin/dev, origin/HEAD) Initial commit
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# master尽量做到一次提交(合并)打一个tag, 以后好回退
$ git tag v1.1 -m "添加到购物车, 支付功能"
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# 查看tag
$ git tag -l -n
v1.1 添加到购物车, 支付功能
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# 删除已经合并了的release分支
$ git br -d release-shopping
# 同时删除远程的release分支
$ git push --delete origin release-shopping
To my.gitlab.com:my-group/demo.git
- [deleted] release-shopping
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# master推送到远程
$ git push origin master
gl@DESKTOP-U75AMEJ MINGW64 /d/workspace/demo (master)
# tag也推送上去
$ git push origin v1.1
经过上述的操作, 我们已经看到了一个版本是如何用git工作流来完成的.
最后的结果展示:
git merge --squash
, 来保证提交日志简洁.git merge --no-ff
来合并, 保证dev上保留完整的历史.git help
图片来自互联网, 如有侵权, 请联系博主删除.