开发者社区> faywong> 正文

场景化学习 git

简介: Linux 之父的第二件作品—— git 自从诞生后就改变了软件生产和协作的面貌,gitlab、github、bitbucket、 gitbook、gerrit 等项目的出现都极大地丰富了现代化软件工程实践。业界介绍 git 各种用法的书已经是汗牛充栋,本文的特色在于通过问答化场景来串联 git 实践中的常用功能及背后原理。 如果你期望让自己的 git 学习之旅更加有趣、记忆深刻,可以通过克
+关注继续查看

Linux 之父的第二件作品—— git 自从诞生后就改变了软件生产和协作的面貌,gitlab、github、bitbucket、 gitbook、gerrit 等项目的出现都极大地丰富了现代化软件工程实践。业界介绍 git 各种用法的书已经是汗牛充栋,本文的特色在于通过问答化场景来串联 git 实践中的常用功能及背后原理。

如果你期望让自己的 git 学习之旅更加有趣、记忆深刻,可以通过克隆样例仓库并 checkout 到每一节的 tag 来和我一起学习:

git clone git@github.com:faywong/master_git_by_scenes.git
cd master_git_by_scenes
git checkout {s1-s5} # check out 每一节标题中的 s1-s5 作为你练手的起点

重写提交记录(tag: s1)

  • 场景:小明刚修改完一个 bug, commit 完才想起忘记写明修复的 bug 的 url
  • 解决方案:git commit —amend 可以重写最近一次提交的提交记录
  • 输出:

重写前:

commit 0bed9c296fc253b06b77faf3a6ce481389a0b736
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:13:16 2017 +0800

    s1:01: fix bug #101

通过git commit --amend重写后:

commit fef0d8f4ac2fc0caccd65439bcae5154a94a46a3
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:13:16 2017 +0800

    s1:01: fix bug #101, bug url: http://faywong.com/bugs/101

有心的童鞋一定发现 commit sha 值发生了变化,那这里引申出了一个注意点:

git 中一个 commit 的 sha 值由提交记录提交者提交日期创作者创作日期提交时的文件树父提交 生成,这些因素中任意一项发生改变,都会导致 sha 发生变化。其中父提交这个因素要注意下,它在后文场景"该用 rebase 还是 merge 同步代码"中也是重要的一个因子。

注:以上重写提交记录的技巧也可以用来解决 git user.email 不符合团队规定时导致提交被拒的问题。

找回丢失的提交(tag:s2)

  • 场景:小明刚为 test.c 添加了一个函数 some_func,结果在一次错误的 git reset HEAD^ —hard 后不小心弄丢了这个提交,想要找回先前的提交
  • 解决方案:git reflog可以让你回溯最近的 git 操作记录,从而找回丢失的提交
  • 输出:

    sid-macbookpro:master_git_by_scenes faywong$ git reflog
    fef0d8f HEAD@{0}: reset: moving to HEAD^
    29c8ead HEAD@{1}: commit: s2:01: add some_func function
    fef0d8f HEAD@{2}: commit (amend): s1:01: fix bug #101, bug url: http://faywong.com/bugs/101
    0bed9c2 HEAD@{3}: commit (amend): s1:01: fix bug #101
    4ca0df1 HEAD@{4}: commit: bugfix: fix bug #101
    220e514 HEAD@{5}: reset: moving to HEAD^
    c040ff7 HEAD@{6}: commit: bugfix: fix bug #101
    220e514 HEAD@{7}: clone: from git@github.com:faywong/master_git_by_scenes.git

可见29c8ead便是小明想要恢复的提交。到底如何恢复呢,请接着看下一节

注:git reflog 依赖于 git 仓库的 gc 状况,并不一定总是能帮上忙,所以无论何时丢失后及时 git reflog 都是明智之举。

追加单个提交(tag:s3)

  • 场景:小明想要追加已存在但并不在当前工作分支上的提交29c8ead
  • 解决方案:git cherry-pick {target_commit}即可将 target-commit追加到当前分支
  • 输出:

    sid-macbookpro:master_git_by_scenes faywong$ git cherry-pick 29c8ead
    [master 6b108a7] s2:01: add some_func function
     Date: Thu Mar 2 19:31:30 2017 +0800
     1 file changed, 5 insertions(+)
    sid-macbookpro:master_git_by_scenes faywong$ git log
    commit 6b108a7e584abf3fc9fea6fe3d9715caae0535bb
    Author: faywong <philip584521@gmail.com>
    Date:   Thu Mar 2 19:31:30 2017 +0800
    
        s2:01: add some_func function
    ......

该用 rebase 还是 merge 同步代码(tag:s4)

  • 场景:小明所在的组,有 2 位其他同学和他一起开发一个 c 语言项目,有的同学喜欢在从 master 分支同步代码时用 master,有的同学喜欢用 rebase,这让小明很痛苦,莫衷一是,到底应该如何抉择呢?
  • 解决方案:

让我们先来看下 rebase vs merge 各自对代码 commit 链的影响:

### rebase 前 master 分支的状态

commit 8f919e54656f6b3e42932db689b7f7358555777f
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:50:49 2017 +0800

    s4:03:添加来自master分支的修改

commit f2c45e9fcd9715324ac576a862dc8ef08160b0b2
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:31:30 2017 +0800

    s2:01: add some_func function

commit fef0d8f4ac2fc0caccd65439bcae5154a94a46a3
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:13:16 2017 +0800

    s1:01: fix bug #101, bug url: http://faywong.com/bugs/101

commit 220e514ebe5fa1d74cd322e1d13f37bde30e4f09
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 18:59:32 2017 +0800

    Initial commit
    

### rebase 前 base 分支的状态

git log base
sid-macbookpro:master_git_by_scenes faywong$ git log
commit 0a3b7ab9c04387a5f8ac69a44415de87d5077efb
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 20:02:17 2017 +0800

    s4:02:来自base分支的修改——添加文件test2.c
    
commit 2f8f3fc27eb938a63b1c7caae73a28e555f18310
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:55:32 2017 +0800

    s4:01:来自base分支的修改——添加文件test1.c

commit f2c45e9fcd9715324ac576a862dc8ef08160b0b2 
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:31:30 2017 +0800

    s2:01: add some_func function

commit fef0d8f4ac2fc0caccd65439bcae5154a94a46a3
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:13:16 2017 +0800

    s1:01: fix bug #101, bug url: http://faywong.com/bugs/101

commit 220e514ebe5fa1d74cd322e1d13f37bde30e4f09
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 18:59:32 2017 +0800

    Initial commit

### 进行 rebase 操作:

站在 master 分支 rebase base 分支

git checkout master
git rebase base

### rebase 后 master 分支的状态

commit 345447ca7f65c4f134bb2496092e4881cec2c66e
Author: faywong <philip584521@gmail.com> ### 这是来自 master 分支的修改 03
Date:   Thu Mar 2 19:50:49 2017 +0800

    s4:03:添加来自master分支的修改

commit 0a3b7ab9c04387a5f8ac69a44415de87d5077efb ### 这是来自 base 分支的修改 02
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 20:02:17 2017 +0800

    s4:02:来自base分支的修改——添加文件test2.c

commit 2f8f3fc27eb938a63b1c7caae73a28e555f18310 ### 这是来自 base 分支的修改 01
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:55:32 2017 +0800

    s4:01:来自base分支的修改——添加文件test1.c

commit f2c45e9fcd9715324ac576a862dc8ef08160b0b2 ### 分支 master & base 的共同祖先
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:31:30 2017 +0800

    s2:01: add some_func function

commit fef0d8f4ac2fc0caccd65439bcae5154a94a46a3
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:13:16 2017 +0800

    s1:01: fix bug #101, bug url: http://faywong.com/bugs/101

commit 220e514ebe5fa1d74cd322e1d13f37bde30e4f09
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 18:59:32 2017 +0800

    Initial commit

可见在分支 master 上 rebase 分支 base 的实际操作是:

  1. 分从 master 分支的 HEAD(最新的一个提交)和 base 分支的 HEAD(最新的一个提交)各自往 parent 方向回溯找到两者的共同 parent commit: f2c45e9fcd9715324ac576a862dc8ef08160b0b2
  2. 将当前代码回撤到 f2c45e9fcd9715324ac576a862dc8ef08160b0b2
  3. 应用共同 parent commit 之后 base 分支的改动:2f8f3fc27eb938a63b1c7caae73a28e555f18310 和0a3b7ab9c04387a5f8ac69a44415de87d5077efb
  4. 应用共同 parent commit 之后 master 分支的改动:345447ca7f65c4f134bb2496092e4881cec2c66e

    其中 2、3、4 步是一个三方合并过程。

    同时也可以看出 master 分支上的修改:s4:03:添加来自master分支的修改 对应的 sha 由先前的:

    8f919e54656f6b3e42932db689b7f7358555777f 变成了 345447ca7f65c4f134bb2496092e4881cec2c66e,这是由于它的父提交发生了改变导致的。

    对于 git 来说,只认识这些生硬的 sha 值,并不知道真正的修改是否完全一样,而这一点需要人来辨别。

    所以可以看出 rebase 别的分支会导致本分支上在中间强行插入一些 commit 从而提交记录不是在尾部单向追加,本分支上尾部的 commit 的 sha 值会“被动”改变。基于这个特征,可以总结出选择 rebase 还是merge 时的黄金法则

选择 rebase 或 merge 的黄金法则

  1. 上游分支合并下游分支用 merge
  2. 下游分支频繁同步(比如每天,分支间差异较小)上游分支改动用 rebase
  3. 下游分支不频繁同步(比如一年,分支间差异极大)上游分支改动用 merge
  4. 作为团队工作起点的主干分支,不要 rebase 其他分支

压缩一系列提交(tag:s5)

  • 场景:近期进修过《程序员的自我修养》后的小明最近在修复一个极其顽固的线上闪退,结果一共提交了 3 次才 code review 通过,小明想将这三个 commit 合并为一个 commit,因为这个三个 commit 逻辑上属于一个 commit。这该怎么实现呢?

小明的三次提交如下:

commit faf8990aa1c5ffd99b98ad8e44e98385116ee19c
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 20:33:24 2017 +0800

    s5:03: 第三次 fix bug #102

commit 3cc7e48c8a38665c81be64c995e79bf4dcad344f
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 20:32:45 2017 +0800

    s5:02: 第二次 fix bug #102

commit 129978226e2bc06a6544b12646cd8def834f6959
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 20:31:39 2017 +0800

    s5:01: 第一次 fix bug #102

commit 345447ca7f65c4f134bb2496092e4881cec2c66e ### git rebase -i 的起点
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:50:49 2017 +0800

    s4:03:添加来自master分支的修改

  • 解决方案:git rebase -i {起点}

起点选择你想修改的最老的(时间上先)提交的 parent。在小明的场景下就是 345447ca7f65c4f134bb2496092e4881cec2c66e

  • 命令:

    git rebase -i 345447ca7f65c4f134bb2496092e4881cec2c66e
  • 输出(git editor 以 vim 为例):

    pick 1299782 s5:01: 第一次 fix bug #102
    pick 3cc7e48 s5:02: 第二次 fix bug #102
    pick faf8990 s5:03: 第三次 fix bug #102
    
    # Rebase 345447c..faf8990 onto 345447c (3 command(s))
    #
    # Commands:
    # p, pick = use commit
    # r, reword = use commit, but edit the commit message
    # e, edit = use commit, but stop for amending
    # s, squash = use commit, but meld into previous commit
    # f, fixup = like "squash", but discard this commit's log message
    # x, exec = run command (the rest of the line) using shell
    # d, drop = remove commit
    #

此时我们将第二次,第三次 commit 前的 pick 改为 s 或 squash,意思即为将该 commit 压缩至前一个提交。

改完,键入:wq保存并退出当前编辑,会来到下一个编辑最终提交记录的界面:

# This is a combination of 3 commits.
# The first commit's message is:
s5:01: 第一次 fix bug #102

# This is the 2nd commit message:

s5:02: 第二次 fix bug #102

# This is the 3rd commit message:

s5:03: 第三次 fix bug #102

我们将它改为:

s5:04: fix bug #102

最终的提交记录变成了:

commit 16d0f0ae8d9a3f1f27115c7640f823976d58ea99 ### 之前的三个提交压缩成了这个提交
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 20:31:39 2017 +0800

    s5:04: fix bug #102

commit 345447ca7f65c4f134bb2496092e4881cec2c66e
Author: faywong <philip584521@gmail.com>
Date:   Thu Mar 2 19:50:49 2017 +0800

    s4:03:添加来自master分支的修改

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
WEBGL学习【十五】利用WEBGL实现三维场景的一般思路总结
版权声明:本文为博主原创文章,未经博主允许不得转载。更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/details/79232119 实现三维场景载入操作的实现步骤: 主要知识点:着色器,纹理贴图,文件载入 实现思路: 获取canvas,初始化WEBGL上下文信息。
1092 0
Git学习--&gt;如何通过Shell脚本自动定时将Gitlab备份文件复制到远程服务器?
一、背景 在我之前的博客 git学习——> Gitlab如何进行备份恢复与迁移? (地址:http://blog.csdn.net/ouyang_peng/article/details/77070977) 里面已经写清楚了如何使用Gitlab自动备份功能。
1919 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
17986 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
24792 0
SAP Leonardo图片处理相关的机器学习服务在SAP智能服务场景中的应用
本文作为Jerry最近正在做的一个项目的工作思路的梳理。 我们假设这样一个服务场景,技师上门维修某设备,发现设备上某零件损坏了,假设这位技师由于种种原因,没能根据自己的经验识别出这个零件的型号。此时技师掏出自己的手机,给零件拍摄一张图片,这张图片通过手机上安装的SAP某智能解决方案,传送到SAP Leonardo平台,通过那里的人工智能服务,自动识别出这张图片上面零件的准确型号,返回给技师。
742 0
3月7日云栖精选夜读:场景化学习 git
云栖社区精选优质文章,每日更新一期,欢迎大家品读!
2152 0
Git学习--&gt;如何通过Shell脚本实现 监控Gitlab备份整个过程并且通过邮件通知得到备份结果?
一、背景 Git学习–>如何通过Shell脚本自动定时将Gitlab备份文件复制到远程服务器? http://blog.csdn.net/ouyang_peng/article/details/77334215 git学习——> Gitlab如何进行备份恢复与迁移? http://blog.
1898 0
+关注
faywong
程序猿一名,Google 粉,Linux 重度用户,精通 c 家族语言和 Lisp、Linux系统。初入嵌入式/芯片行业,后投身互联网行业。小学时代便愈发明显的文艺气息在投入互联网行业后磨灭殆尽,正等一个艳阳天,用互联网思维卖水果。 密切关注并思考着商业、科技、人文。
9
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
OceanBase 入门到实战教程
立即下载
阿里云图数据库GDB,加速开启“图智”未来.ppt
立即下载
实时数仓Hologres技术实战一本通2.0版(下)
立即下载