博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一些git实用技巧
阅读量:5890 次
发布时间:2019-06-19

本文共 4382 字,大约阅读时间需要 14 分钟。

原创 转载请注明作者和出处

这篇文章将通过场景分析的方式讲解一些git的实用技巧。这些技巧的使用频率或许不是很高,但真正需要用到的时候,你可能会感慨相见恨晚。

场景一、罪魁祸首

程序员小A发现源文件B.java中的某一行引发了一个bug。现在小A要找出是谁在什么时间提交了这次修改。那么小A应该怎么做呢?

最直接的想法应该是察看B.java这个文件的提交历史,在一个个commit中找出导致bug的修改。高级一点的话可以使用git bisect进行二分查找。其实git提供了一个简单直接的命令git blame可以帮助我们快速地找到那个“罪魁祸首”。git blame命令会输出指定文件中每一行的最后一次修改的作者、时间以及commit hash. 例如执行git blame B.java的输出如下:

^87fe8e2 (little A 2016-06-18 14:21:23 +0800 1) public class B {^87fe8e2 (little A 2016-06-18 14:21:23 +0800 2) ^87fe8e2 (little A 2016-06-18 14:21:23 +0800 3)         public static void main(String[] args) {51497e8a (someone  2016-06-18 14:22:21 +0800 4)       System.out.println("It is me! Haha!");^87fe8e2 (little A 2016-06-18 14:21:23 +0800 5)   }^87fe8e2 (little A 2016-06-18 14:21:23 +0800 6) }复制代码

可以看到someone就是那个“罪魁祸首”!(好吧,其实我们还是不知道他是谁)

场景二、亡羊补牢1.0

小A刚刚提交了一个commit,但发现提交信息写错了。小A该如何修改这次的提交信息呢?

补救的方法有不少,这里列举两个:

  1. 执行命令git commit --amend, 在vim编辑界面修改提交信息后保存即可。这算是最简单的方法了。

  2. 依次执行

    git reset HEAD~1 git commit -am "new message"复制代码

    这个方法首先将HEAD指针移到最后一个commit之前的那个commit,并且把最后一次commit所做的修改还原到working tree,然后再进行一次新的commit.

场景三、亡羊补牢2.0

现在难度升级,如果小A想修改中间某个commit的提交信息,该怎么办呢?

这时可以使用强大的git rebase -i命令。输入git rebase -i加一个commit hash之后回车,进入一个vim编辑界面。界面上按序列出了指定commit之后的所有commit,类似下面这样:

pick 383fd55 llal pick 1ddcdab update new.txtpick 1519f1f update new.txt 2pick fdc6370 delete new.txtpick 0a8bcf8 add back new.txt# Rebase 2aa6567..0a8bcf8 onto 2aa6567 (5 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复制代码

在每一行的开头可以指定一个你想执行的命令。默认是pick, 也就是不做任何修改。现在我们想修改中间的某个commit信息,只需把该commit所在行的pick替换成reword或者简写r,然后保存。接下来会出现新的编辑界面,然后我们就可以修改提交信息了。

可以看到除了reword还有其他一些命令,后面会用到其中的某几个。

场景四、追悔莫及

小A发现当前分支test上的最后N个commit有问题,想丢弃它们,于是执行了git reset --hard HEAD~N. 过了一段时间,小A突然想起之前丢弃的N个commit里面还有一些重要的修改!那么小A有什么办法找回丢弃的那N个commit呢?

这时可以求助于git提供的ORIG_HEAD这个变量。在进行pullmerge或者reset等操作后,HEAD一般都会移动好几个commit。而ORIG_HEAD就是指向这些操作之前HEAD所指向的那个commit。可以认为ORIG_HEAD是git提供的一剂后悔药。小A要找回之前丢弃的N个commit,可以这么做:

git checkout -b temp ORIG_HEADgit checkout testgit merge temp复制代码

首先创建一个分支temp指向ORIG_HEAD指向的commit。然后切回test分支,merge一下temp,就可以让那N个commit重新回到test分支。

但是,如果小A在丢弃了那几个commit之后又做了pullmerge或者reset等操作,改变了ORIG_HEAD的值,那么上面这个方法就无效了。不过办法总比困难多,这时使用git reflog可以解决这个问题。git会记录HEAD的改变历史,而git reflog就是把这个历史记录输出。这个命令的输出如下:

87fe8e2 HEAD@{0}: reset: moving to HEAD~1d42533e HEAD@{1}: checkout: moving from master to testd42533e HEAD@{2}: commit: another复制代码

小A只需找到执行reset命令的那一行,那么它下面一行最前面的commit hash就是“解药”了。找到了这个commit,之后再仿照上面的步骤操作就可以了。

场景五、挑三拣四1.0

小A对一个文件B做了多处修改。在提交的时候发现有一些修改是需要排除在这次提交之外的。 那么怎么做可以对同一个文件的多处修改进行选择性提交?

这时可以使用git add -p命令。输入此命令(后面可以指定文件名)后,git会对每一个修改区块(一般来讲一段连续的修改算是一个区块)询问需要执行的指令:

Stage this hunk [y,n,q,a,d,/,j,J,g,e,?]?复制代码

其中各指令的含义如下:

y - 将此区块加入indexn - 不加入index,并跳到下一个区块q - 不加入index,同时结束操作a - 将此区块以及当前文件剩余区块都加入index,跳到下一个文件d - 与a相反g - 选择具体的区块进行操作/ - 搜索能够匹配给定正则表达式的区块j - 将此区块标记成“暂定”,跳到下一个“暂定”的区块J - 将此区块标记成“暂定”,跳到下一个区块k - 将此区块标记成“暂定”,跳到前一个“暂定”的区块K - 将此区块标记成“暂定”,跳到前一个区块s - 将当前区块划分成更小的区块e - 进入编辑界面进行更细的选择? - 打印帮助复制代码

如果选择执行指令e则会进入一个新的vim编辑页面,如下所示:

# Manual hunk edit mode -- see bottom for a quick guide@@ -1,3 +1,3 @@ origin-1-2+abc+xyz# ---# To remove '-' lines, make them ' ' lines (context).# To remove '+' lines, delete them.# Lines starting with # will be removed.## If the patch applies cleanly, the edited hunk will immediately be# marked for staging. If it does not apply cleanly, you will be given# an opportunity to edit again. If all lines of the hunk are removed,# then the edit is aborted and the hunk is left unchanged.复制代码

在这个界面可以进行更细致的操作:将某一行开头的-号换成空格,该行的删除修改则不会加入index,但这个删除的修改仍然保留;将以号开头的某一行删除,该行则不会加入index,但添加的这一行仍然保留在文件中。

场景六、挑三拣四2.0

如果上面那个B文件是一个Untracked file,那又该如何进行选择性提交呢?

可以先执行git add -N B命令。现在B里面的内容都变成了unstaged的修改。之后再用上面的方法进行选择性提交。

场景七、万源归一

小A开发出了一款可以自动编程并且提交代码的AI工具。不过有一天小A发现该工具的一个bug引发了一个问题: 它每修改一处就会进行一次commit,这样导致一次功能修改就提交了N多个commit。有什么办法可以合并这些commit变成一个commit?

可以再一次使用git rebase -i. 回顾场景三可以看到vim编辑界面的提示中有两条指令:

# s, squash = use commit, but meld into previous commit# f, fixup = like "squash", but discard this commit's log message复制代码

这两条指令都可以把当前的commit归并到前一个commit中,区别就在于是否保留当前commit的提交信息。

转载于:https://juejin.im/post/5b17a77ae51d45069279e4d9

你可能感兴趣的文章
《世界是数字的》读笔
查看>>
Vue局部注册 或者全局注册 组件时,组件定义要用 分隔命名,用驼峰命名是不生效的...
查看>>
BootStrap 最佳资源合集(转)
查看>>
详解Jquery和AngularJs,Servlet中jsonp解决跨域问题(转)
查看>>
小程序OSS图片上传
查看>>
spring mvc 跨域
查看>>
如何让 node 运行 es6 模块文件,及其原理
查看>>
jsp标准动作
查看>>
alert一般用来调试客户端的javascript代码,以及更好的调试方法
查看>>
【总结】前端面试会问哪些问题?
查看>>
ResultSet的getInt()和getString()方法详解
查看>>
新买了一对充电电池,是该先用光电再充还是先充再用?
查看>>
如何弹出WiFi提示列表。
查看>>
移动端适配字体大小
查看>>
springboot 博客分享
查看>>
第七次作业
查看>>
Python 递归和迭代函数
查看>>
Tips——canvas闪屏问题的处理
查看>>
away3d 4.0.9Gold 学习笔记 Mesh的用法(3)
查看>>
【HDOJ】1153 Magic Bitstrings【组合数学】
查看>>