写点什么

你需要知道的 12 个 Git 高级命令

  • 2016-01-29
  • 本文字数:3137 字

    阅读完需:约 10 分钟

众所周知,Git 目前已经是分布式版本控制领域的翘楚,围绕着 Git 形成了完整的生态圈。学习 Git,首先当然是学习 Git 的基本工作流。相比于SVN 等传统版本控制系统来说,Git 是专为分布式版本控制而生的强大工具。使用Git 时常用的命令有pull、commit、push 等,貌似很简单。不过,有时你会遇到合并冲突的情况,Git 这时会将冲突标记出来,需要你手工来解决。有时,你会不小心将代码提交到错误的分支上,并且又推送到了远程仓库。还有些时候,你需要切换到不同的分支,但Git 却不让你这么做,因为还有未保存的修改。如果需要通过另一个分支的提交来为代码打补丁该怎么做呢?本文就将介绍12 个Git 高级命令,合理使用这些命令可以大大提升应用Git 的效率。

1. 使用 rebase 而非 merge 来拉取上游修改

分支合并会被记录为一次合并提交,这种做法是很有意义的。比如说,可以通过这种方式来标识一个新特性被合并到了发布分支中。不过,当多个团队成员工作在一个项目中并使用常规的 git pull 来同步分支时,提交时间线就会被不必要的合并提交所污染。更好的做法则是使用 git rebase 将一个 feature 分支变基到 master 分支:

复制代码
$ git checkout feature
$ git rebase master

这么做会将整个 feature 分支移动到 master 分支的起点,它会合并 master 分支上所有新的提交。不过,相比于使用合并提交来说,变基会通过在原来的分支中为每次提交创建全新提交来重写项目历史。变基的主要好处在于你会得到一个更加整洁的项目历史。此外,这里还有关于变基的陷阱的一些讨论。

2. 在执行 git rebase 后解决合并冲突

正如能力越大责任就越大一样。在执行 git rebase 时,你可能会遇到合并冲突的情况。合并冲突表示两个提交修改了同一个文件的同一行,Git 不知道该应用哪一个修改。这会导致如下所示的错误消息:

Git 会为你提供 3 个选择来修复导致冲突的提交(fa39187):

  • 可以运行 git rebase --abort 来完全取消变基。这么做会取消变基修改,并将分支置回到执行 git rebase 之前的状态。
  • 可以运行 git rebase --skip 来完全忽略该提交。这样,有问题的提交所引入的变化就不会被添加到历史中。
  • 可以使用与合并冲突相同的标准步骤来解决冲突。

3. 临时性保存修改

在工作进行中时,有些东西常常会处于凌乱的状态。如果这时需要切换到不同的分支该怎么办呢?Git 是不允许你这么做的,因为还有尚未保存的修改。坦率地说,你并不想将半成品提交上去,后面再来修改。这个问题的解决之道就是使用 git stash 命令。Stash 会接收工作目录的当前状态(比如说,修改了的追踪文件与暂存区的修改等),并将其保存到未完成的修改栈中,这样后面随时可以再来修改。可以通过如下命令来暂存你的工作:

复制代码
$ git stash
Saved working directory and index state WIP on feature: 3fc175f fix race condition
HEAD is now at 3fc175f fix race condition

现在,工作目录就是干净的了:

复制代码
$ git status
# On branch feature
nothing to commit, working directory clean

这时就可以安全地切换分支做别的事情了。不过不必担心,暂存的提交依旧还在:

复制代码
$ git stash list
stash@{0}: WIP on feature: 3fc175f fix race condition

稍后,在回到 feature 分支后,你就可以取回所有暂存的变更了:

复制代码
$ git stash pop
On branch feature
Changes not staged for commit:
(use "git add ..." to update what will be committed)
modified: index.html
Dropped refs/stash@{0} (ac2321cc3a33ba712b8e50c99a99d3c20da9d6b8)

关于暂存,还有其他一些选项可用,如下所示:

复制代码
$ git stash save "describe it" # give the stash a name
$ git stash clear # delete a stashed commit
$ git stash save --keep-index # stash only unstaged files

4. 克隆一个特定的远程分支

如果想要从远程仓库中克隆一个特定的分支该怎么做呢?通常你会使用 git clone,不过这么做会将所有其他分支都一并克隆下来。一个便捷的方式是使用 git remote add:

复制代码
$ git init
$ git remote add -t <remotebranchname> -f origin <remoterepourlpath>
$ git checkout <localbranchname></localbranchname></remoterepourlpath></remotebranchname>

5. 将 cherry-pick 远程提交合并到自己的分支中

更有甚者,如果只想将远程仓库的一个特定提交合并到自己的分支中该怎么做呢?可以使用 git cherry-pick 来选择给定 SHA 值的提交,然后将其合并到当前分支中:

复制代码
$ git cherry-pick <commitsha></commitsha>

6. 应用来自于不相关的本地仓库的补丁

如果需要将另一个不相关的本地仓库的提交补丁应用到当前仓库该怎么做呢?答案就是下面这条命令:

复制代码
$ git --git-dir=<pathtootherlocalrepo>/.git format-patch -k -1 --stdout <otherlocalcommitsha> | git am -3 -k
</otherlocalcommitsha></pathtootherlocalrepo>

7. 忽略追踪文件中的变更

如果你和你的同事操纵的是相同分支,那么很有可能需要频繁执行 git merge 或是 git rebase。不过,这么做可能会重置一些与环境相关的配置文件,这样在每次合并后都需要修改。与之相反,你可以通过如下命令永久性地告诉 Git 不要管某个本地文件:

复制代码
$ git update-index --assume-unchanged <pathtolocalfile></pathtolocalfile>

8. 每隔 X 秒运行一次 git pull

通常,合并冲突出现的原因在于你正在工作的本地仓库不再反映远程仓库的当前状态。这正是我们为什么每天早晨要首先执行一次 git pull 的缘故。此外,你还可以在后台通过脚本(或是使用 GNU Screen)每隔 X 秒调用一次 git pull:

复制代码
$ screen
$ for((i=1;i<=10000;i+=1)); do sleep X && git pull; done

9. 将子目录分隔为新的仓库

有时,你可能需要将 Git 仓库中某个特定的目录转换为一个全新的仓库。这可以通过 git filter-branch 来实现:

复制代码
$ git filter-branch --prune-empty --subdirectory-filter <foldername> master
# Filter the master branch to your directory and remove empty commits
Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (89/89)
Ref 'refs/heads/master' was rewritten
</foldername>

现在,仓库会包含指定子目录中的所有文件。虽然之前的所有文件都会被删除,但他们依旧存在于 Git 历史中。现在可以将新的本地仓库推送到远程了。

10. 清理

有时,Git 会提示“untracked working tree files”会“overwritten by checkout”。造成这种情况的原因有很多。不过通常来说,我们可以使用如下命令来保持工作树的整洁,从而防止这种情况的发生:

复制代码
$ git clean -f # remove untracked files
$ git clean -fd # remove untracked files/directories
$ git clean -nfd # list all files/directories that would be removed

11. 将项目文件打成 tar 包,并且排除.git 目录

有时,你需要将项目副本提供给无法访问 GitHub 仓库的外部成员。最简单的方式就是使用 tar 或 zip 来打包所有的项目文件。不过,如果不小心,隐藏的.git 目录就会包含到 tar 文件中,这会导致文件体积变大;同时,如果里面的文件与接收者自己的 Git 仓库弄混了,那就更加令人头疼了。轻松的做法则是自动从 tar 文件中排除掉.git 目录:

复制代码
$ tar cJf <projectname>.tar.xz <projectfolder>/ --exclude-vcs
</projectfolder></projectname>

12. 查找修改者

最后,如果出现混乱的情况,你一定想要找出是谁造成的。如果生产服务器宕机,那么找到罪魁祸首是比较容易的事情:只需执行 git blame。该命令会显示出文件中每一行的作者,提交 hash 则会找出该行的上一次修改,还能看到提交的时间戳:

复制代码
$ git blame <filename></filename>

当然,Git 命令是非常多的,除了上面介绍的 12 个重要命令外,相信各位 InfoQ 读者在日常工作过程中也有自己偏爱且好用的一些命令,不妨以评论的形式与其他读者一同分享。

2016-01-29 02:089433
用户头像

发布了 88 篇内容, 共 268.4 次阅读, 收获喜欢 8 次。

关注

评论 3 条评论

发布
暂无评论
发现更多内容

技术管理者带团队的几个实用技巧

Phoenix

团队管理 企业文化 团队 价值观

Newbe.Claptrap 框架如何实现多级生命周期控制?

newbe36524

架构 微服务 .net core ASP.NET Core

英特尔®AI计算盒参考设计发布 加速智能边缘崛起

最新动态

计算机网络基础(十一)---网络层-OSPF协议

书旅

计算机网络 网络 协议栈 OSPF

云小课 | IPv4枯了,IPv6来了

华为云开发者联盟

IP 公有云 虚拟私有云 华为云 虚拟化

秒杀系统问题与方案设计

superman

秒杀 架构总结

手写一个重入锁

诸葛小猿

synchronized CAS 重入锁 compareAndSwap ReentrantLock

飞天茅台超卖事故:Redis分布式锁请慎用!

程序员生活志

redis 分布式

将信将疑,将中台进行到底

郭华

<<前端进阶篇>> PDF 出炉了 — 「阿宝哥」,精心准备的 6 万多字 170 页的前端进阶资料

阿宝哥

大前端

JVM系列之:JIT中的Virtual Call

程序那些事

Java JVM JIT

实用!一键生成数据库文档,堪称数据库界的Swagger

程序员小富

Java MySQL

数据人必须知道的SQL概念(A—Z)

大唐小生

sql 数据 职场成长

老哥,您看我这篇Java集合,还有机会评优吗?

苹果看辽宁体育

Java 后端

授人以渔:stm32资料查询技巧

华为云开发者联盟

架构 armv8 芯片 华为云 二进制

在人工智能时代追逐的“后浪”

华为云开发者联盟

程序员 AI 开发者 技术社区 华为云

第九周

hdhdh

华为云GaussDB(DWS)内存知识点,你知道吗?

华为云开发者联盟

数据库 大数据 数据 内存 华为云

智能膜切机,解决手机贴膜行业难题

Geek_116789

基于 Golang的侵入式 Opentracing实现全链路追踪 ----实践篇

是老郭啊

财务分析与主要的模型

松子(李博源)

微软苏州集体抵制来自阿里、华为的跳槽者:请停止你的“奋斗逼”行为!网友:看到 955 不加班的公司名单,我酸了

程序员生活志

程序员 加班 996

架构师训练营第八章-作业1

A Matt

《深度工作》学习笔记(3)

石云升

学习 深度工作 工作哲学

你问我答:微服务治理应该如何去做?

BoCloud博云

容器 微服务 PaaS API 博云

Vue中使用装饰器,我是认真的

前端有的玩

Java Vue 装饰器

ARTS打卡 第10周

引花眠

ARTS 打卡计划

系统设计系列之如何设计一个短链服务

看山

架构 面试 分布式 架构设计 短链服务

谈一谈webpack打包

林浩

Java 大前端 webpack

初识分布式:MIT 6.284系列(一)

Kerwin

分布式 MIT 28天写作

什么?不写代码也能做功能开发! -RUOYI 教程二

Java_若依框架教程

Java 无代码开发 若依

你需要知道的12个Git高级命令_语言 & 开发_张龙_InfoQ精选文章