Rebase

假设我们的分支结构如下:

rebase 会把从 Merge Base 以来的所有提交,以补丁的形式一个一个重新达到目标分支上。这使得目标分支合并该分支的时候会直接 Fast Forward,即不会产生任何冲突。提交历史是一条线,这对强迫症患者可谓是一大福音。

如果我们想要看 rebase 实际上做了什么,有一个方法,那就是用“慢镜头”来看rebase的整个操作过程。rebase 提供了交互式选项(参数 -i),我们可以针对每一个patch,选择你要进行的操作。

通过这个交互式选项,我们可以”单步调试”rebase操作。

经过测试,其实 rebase 主要在 .git/rebase-merge 下生成了两个文件,分别为 git-rebase-todo 和 done 文件,这两个文件的作用光看名字就可以看得出来。git-rebase-todo 存放了 rebase 将要操作的 commit。而 done 存放正在操作或已经操作完毕的 commit。比如我们这里,git-rebase-todo 存放了 4、5、6,三个提交。

首先 git 将 sha-1 为 4 的 commit 放入 done。表示正在操作 4,然后将 4 以补丁的形式打到 3 上,形成了新的提交 4’。这一步是可能产生冲突的,如果有冲突,需要解决完冲突之后才能继续操作。

接着讲 sha-1 为 5 的提交放入 done 文件,然后将 5 以补丁的形式打到 4’ 上,形成 5’。

再接着将 sha-1 为 6 的提交放入 done 文件,然后将 6 以补丁的形式打到 5’ 上,形成 6’。最后移动分支指针,使其指向最新的提交 6’ 上。这就完成了 rebase 的操作。

我们看一下真实的 rebase 文件。

pick e0f56d9 update gitignore
pick e370289 add a # 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

该文件一共有三列,第一列表示要进行的操作,所有可以进行的操作,在下面注释里都列了出来,比如 pick 表示使用该提交,reword 表示使用该提交,但修改其提交的 message,edit 表示使用该提交,但是要对该提交进行一些修改,其它的就不一一说了。

而 done 文件的形式如下,和 git-rebase-todo 是一样的:

pick e0f56d9 update gitignore
pick e370289 add a

从刚才的图中,我们就可以看到 rebase 的一个缺点,那就是修改了分支的历史提交。如果已经将分支推送到了远程仓库,会导致无法将修改后的分支推送上去,必须使用 -f 参数(force)强行推送。

所以使用 rebase 最好不要在公共分支上进行操作。

stash

有时,我们在一个分支上做了一些工作,修改了很多代码,而这时需要切换到另一个分支干点别的事。但又不想将只做了一半的工作提交。在曾经这样做过,将当前的修改做一次提交,message 填写 half of work,然后切换另一个分支去做工作,完成工作后,切换回来使用 reset —soft 或者是 commit amend。

git 为了帮我们解决这种需求,提供了 stash 命令。

stash 将工作区与暂存区中的内容做一个提交,保存起来,然后使用reset hard选项恢复工作区与暂存区内容。我们可以随时使用 stash apply 将修改应用回来。

stash 实现思路将我们的修改提交到本地仓库,使用特殊的分支指针(.git/refs/stash)引用该提交,然后在恢复的时候,将该提交恢复即可。我们可以更进一步,看看 stash 做的提交是什么样的结构。

如图所示,如果我们提供了 —include-untracked 选项,git 会将 untracked 文件做一个提交,但是该提交是一个游离的状态,接着将暂存区的内容做一个提交。最后将工作区的修改做一个提交,并以untracked 的提交、暂存区 的提交、基础提交为父提交。

搞这么复杂,是为了提供更灵活地选项,我们可以选择性的恢复其中的内容。比如恢复 stash 时,可以选择是否重建 index,即与 stash 操作时完全一致的状态。

bisect

项目发布到线上的项目出现了bug,而经过排查,却找不到问 bug 的源头。我们还有一种方法,那就是先找到上一次好的版本,从上一次到本次之间的所有提交依次尝试,一一排查。直到找到出现问题的那一次提交,然后分析 bug 原因。

git 为我们想到了这样的场景,同样是刚才的思路,但是使用二分法进行查找。这就是 bisect 命令。

使用该命令很简单,

git bisect start
git bisect bad HEAD
git bisect good v4.1

git 会计算中间的一个提交,然后我们进行测试。

根据测试结果,使用 git bisect good or bad 进行标记,git 会自动切换到下一个提交。不断的重复这个步骤,直到找到最初引入 bug 的那一次提交。

我们知道二分法的效率是很高的,2的10次方就已经1024了,因此我们测试一般最多是10次,再多就是11次、12次。其实这就要求我们优化测试的方法,使得简单的操作就能使 bug 重现。如果重新的操作非常简单,简单到我们可以使用脚本就能测试,那就更轻松了,可以使用 git bisect run ./test.sh,一步到位。

如果某一个提交代码跑不起来,可以使用 git bisect skip 跳过当前提交或者使用 visualize 在 git 给出的列表中手动指定一个提交进行测试。

Git中特别的命令的更多相关文章

  1. Git中的merge命令实现中出现问题及其解决

    Git中的merge命令实现和工作方式 2015年8月17日星期一 丹丹 git代码在合并两个分支的时候总是会出现一下的错误提示,不能正常的完成合并分支,错误提示如图所示: 但是在其他的终端是可以完成 ...

  2. GIT中常用的命令

    最近项目中使用到了GIT,所以记录一下GIT中常用的命令. GIT使用的客户端有Git Bash:http://code.google.com/p/msysgit/ 还有乌龟TortoiseGit:h ...

  3. 总结下git中一些常用命令

    一.目录操作 1.cd 即change directory,改变目录,如 cd d:/www,切换到d盘的www目录. 2.cd .. cd+空格+两个点,回退到上一目录. 3.pwd 即 print ...

  4. Git中的merge命令实现和工作方式

    想象一下有例如以下情形:代码库中存在两个分支,而且每一个分支都进行了改动.最后你想要将当中的一个分支合并到其它的分支中.个人博客网址 http://swinghu.github.com/ 那么要问合并 ...

  5. 实用:Git 中的一些常见错误

    无论是数据科学家.算法工程师还是普通开发人员,在每个团队协作开发任务中,Git 都是必不可少的版本控制工具,因此掌握它的基本操作十分有必要.但即便是教程满天飞的今天,开发人员在使用 Git 时也还是会 ...

  6. Git 日常工作中使用的命令记录

    前言   这篇文章主要是介绍我在使用Git中的有一些忘记了,但是很重要的命令. 20190424 Git 历史信息 username 和 email 更改 git config alias.chang ...

  7. 关于Git中的一些常用的命令

    深入了解git的checkout命令 检出命令(git checkout)是Git最常用的命令之一,同时也是一个很危险的命令. 因为这条命令会重写工作区.检出命令的用法如下: 用法一: git che ...

  8. git中常见的几个命令

    git中常见的几个命令 本地仓库 三个区域 工作目录 暂存区 本地仓库 文件的四个状态 未跟踪 untracked 已暂存 staged 已提交commited 已修改 modified 基本命令 g ...

  9. Git中从远程的分支获取最新的版本到本地——两种命令

    Git中从远程的分支获取最新的版本到本地有这样2个命令: 1. git fetch:相当于是从远程获取最新版本到本地,不会自动merge Git fetch origin master git log ...

随机推荐

  1. FasfDFS intall nginx with image filter

    centOS7 x64 1. install gd-devel 2. ./configure --prefix=/usr/local/nginx --with-http_image_filter_mo ...

  2. order by having group by

    1.group by 和having 的使用 SELECT *, count(`sku_quantity`)  as quantity FROM products  group by sku  hav ...

  3. 基础最短路(模板 bellman_ford)

    Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以现在他们想要寻找最短的从商店 ...

  4. winform窗体程序运行后怎样隐藏?

    运行winform窗体,我们是怎样隐藏的呢? 例子: 1)创建简单winform窗体 2)编写隐藏窗体程序的代码 3)效果演示 1)创建一个简单的winform窗体MainForm,

  5. SGU 124. Broken line 射线法 eps的精准运用,计算几何 难度:3

    124. Broken line time limit per test: 0.25 sec. memory limit per test: 4096 KB There is a closed bro ...

  6. gitlba的搭建与使用

    实验环境继续使用git的实验环境,详情请点击连接https://www.cnblogs.com/cash-su/p/10131632.html 首先给服务器做一个本机的映射 [root@git1 ~] ...

  7. TADOTABLE 永久字段的顺序 和 AppendRecord

    AppendRecord 方法,添加记录的字段到数据库里时,是按照IDE里永久字段的顺序,不是数据库表里的字段顺序. 自动编号 字段,以nil为值. 日期时间 字段,直接now 写法

  8. 宇宙最帅叉叉——第五周博客 for 测试与发布(Alpha版本)

    Alpha版本测试报告 1.在测试过程中总共发现了多少Bug?每个类别的Bug分别为多少个? a.修复的BUG UDP传输 recvfrom 当没有消息来的时候一直循环等待因其阻塞 ,时间戳无效了. ...

  9. JavaScript世界的一等公民 - 函数

    简介 在很多传统语言(C/C++/Java/C#等)中,函数都是作为一个二等公民存在,你只能用语言的关键字声明一个函数然后调用它,如果需要把函数作为参数传给另一个函数,或是赋值给一个本地变量,又或是作 ...

  10. 超级好用的C++万能头文件

    #include<bits/stdc++.h>包含了目前c++所包含的所有头文件 对比: #include <iostream> #include <cstdio> ...