2016年1月7日星期四

阮一峰的网络日志

阮一峰的网络日志


Commit message 和 Change log 编写指南

Posted: 06 Jan 2016 05:23 AM PST

Git 每次提交代码,都要写 Commit message(提交说明),否则就不允许提交。

  $ git commit -m "hello world"  

上面代码的-m参数,就是用来指定 commit mesage 的。

如果一行不够,可以只执行git commit,就会跳出文本编译器,让你写多行。

  $ git commit  

基本上,你写什么都行(这里这里这里)。

但是,一般来说,commit message 应该清晰明了,说明本次提交的目的。

目前,社区有多种 Commit message 的写法规范。本文介绍Angular 规范(见上图),这是目前使用最广的写法,比较合理和系统化,并且有配套的工具。

一、Commit message 的作用

格式化的Commit message,有几个好处。

(1)提供更多的历史信息,方便快速浏览。

比如,下面的命令显示上次发布后的变动,每个commit占据一行。你只看行首,就知道某次 commit 的目的。

  $ git log <last tag> HEAD --pretty=format:%s  

(2)可以过滤某些commit(比如文档改动),便于快速查找信息。

比如,下面的命令仅仅显示本次发布新增加的功能。

  $ git log <last release> HEAD --grep feature  

(3)可以直接从commit生成Change log。

Change Log 是发布新版本时,用来说明与上一个版本差异的文档,详见后文。

二、Commit message 的格式

每次提交,Commit message 都包括三个部分:Header,Body 和 Footer。

  <type>(<scope>): <subject>  // 空一行  <body>  // 空一行  <footer>  

其中,Header 是必需的,Body 和 Footer 可以省略。

不管是哪一个部分,任何一行都不得超过72个字符(或100个字符)。这是为了避免自动换行影响美观。

2.1 Header

Header部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。

(1)type

type用于说明 commit 的类别,只允许使用下面7个标识。

  • feat:新功能(feature)
  • fix:修补bug
  • docs:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • test:增加测试
  • chore:构建过程或辅助工具的变动

如果typefeatfix,则该 commit 将肯定出现在 Change log 之中。其他情况(docschorestylerefactortest)由你决定,要不要放入 Change log,建议是不要。

(2)scope

scope用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。

(3)subject

subject是 commit 目的的简短描述,不超过50个字符。

  • 以动词开头,使用第一人称现在时,比如change,而不是changedchanges
  • 第一个字母小写
  • 结尾不加句号(.

2.2 Body

Body 部分是对本次 commit 的详细描述,可以分成多行。下面是一个范例。

  More detailed explanatory text, if necessary.  Wrap it to   about 72 characters or so.     Further paragraphs come after blank lines.    - Bullet points are okay, too  - Use a hanging indent  

有两个注意点。

(1)使用第一人称现在时,比如使用change而不是changedchanges

(2)应该说明代码变动的动机,以及与以前行为的对比。

2.3 Footer

Footer 部分只用于两种情况。

(1)不兼容变动

如果当前代码与上一个版本不兼容,则 Footer 部分以BREAKING CHANGE开头,后面是对变动的描述、以及变动理由和迁移方法。

  BREAKING CHANGE: isolate scope bindings definition has changed.        To migrate the code follow the example below:        Before:        scope: {        myAttr: 'attribute',      }        After:        scope: {        myAttr: '@',      }        The removed `inject` wasn't generaly useful for directives so there should be no code using it.  

(2)关闭 Issue

如果当前 commit 针对某个issue,那么可以在 Footer 部分关闭这个 issue 。

  Closes #234  

也可以一次关闭多个 issue 。

  Closes #123, #245, #992  

2.4 Revert

还有一种特殊情况,如果当前 commit 用于撤销以前的 commit,则必须以revert:开头,后面跟着被撤销 Commit 的 Header。

  revert: feat(pencil): add 'graphiteWidth' option    This reverts commit 667ecc1654a317a13331b17617d973392f415f02.  

Body部分的格式是固定的,必须写成This reverts commit &lt;hash>.,其中的hash是被撤销 commit 的 SHA 标识符。

如果当前 commit 与被撤销的 commit,在同一个发布(release)里面,那么它们都不会出现在 Change log 里面。如果两者在不同的发布,那么当前 commit,会出现在 Change log 的Reverts小标题下面。

三、Commitizen

Commitizen是一个撰写合格 Commit message 的工具。

安装命令如下。

  $ npm install -g commitizen  

然后,在项目目录里,运行下面的命令,使其支持 Angular 的 Commit message 格式。

  $ commitizen init cz-conventional-changelog --save --save-exact  

以后,凡是用到git commit命令,一律改为使用git cz。这时,就会出现选项,用来生成符合格式的 Commit message。

四、validate-commit-msg

validate-commit-msg 用于检查 Node 项目的 Commit message 是否符合格式。

它的安装是手动的。首先,拷贝下面这个JS文件,放入你的代码库。文件名可以取为validate-commit-msg.js

接着,把这个脚本加入 Git 的 hook。下面是在package.json里面使用 ghooks,把这个脚本加为commit-msg时运行。

    "config": {      "ghooks": {        "commit-msg": "./validate-commit-msg.js"      }    }  

然后,每次git commit的时候,这个脚本就会自动检查 Commit message 是否合格。如果不合格,就会报错。

  $ git add -A   $ git commit -m "edit markdown"   INVALID COMMIT MSG: does not match "<type>(<scope>): <subject>" ! was: edit markdown  

五、生成 Change log

如果你的所有 Commit 都符合 Angular 格式,那么发布新版本时, Change log 就可以用脚本自动生成(例1例2例3)。

生成的文档包括以下三个部分。

  • New features
  • Bug fixes
  • Breaking changes.

每个部分都会罗列相关的 commit ,并且有指向这些 commit 的链接。当然,生成的文档允许手动修改,所以发布前,你还可以添加其他内容。

conventional-changelog 就是生成 Change log 的工具,运行下面的命令即可。

  $ npm install -g conventional-changelog  $ cd my-project  $ conventional-changelog -p angular -i CHANGELOG.md -w  

上面命令不会覆盖以前的 Change log,只会在CHANGELOG.md的头部加上自从上次发布以来的变动。

如果你想生成所有发布的 Change log,要改为运行下面的命令。

  $ conventional-changelog -p angular -i CHANGELOG.md -w -r 0  

为了方便使用,可以将其写入package.jsonscripts字段。

  {    "scripts": {      "changelog": "conventional-changelog -p angular -i CHANGELOG.md -w -r 0"    }  }  

以后,直接运行下面的命令即可。

  $ npm run changelog  

(完)

文档信息

2016年1月3日星期日

阮一峰的网络日志

阮一峰的网络日志


网站的肥胖症危机

Posted: 03 Jan 2016 02:58 AM PST

最近,有一篇文章正在疯传。

它是上个月,Maciej Ceglowski在澳大利亚的一次演讲,名为《网站的肥胖症危机》(文本视频),反思了互联网开发的现状。

该文非常值得一读,Hacker News排行榜高居榜首,得到了1000多人的推荐。

下面就是我的中文节译版。

===============================

网站的肥胖症危机(节译版)

作者:Maciej Ceglowski

译者:阮一峰

原文网址:The Website Obesity Crisis

1.

大多数网站的主要内容是文本,更准确地说,是简短的文本。

文本本身并不大,但是展示它们的网页,正变得越来越大。Twitter展示单条评论(140个字符)的页面,超过900KB。Medium的一篇文章大约400个词,页面大小是1.2MB。

如果这种趋势持续下去,2020年,网页的体积平均将超过5MB,比一本俄罗斯长篇小说还大。比如,陀思妥耶夫斯基的《罪与罚》,文本压缩后不到800KB。

TechTimes.com有一篇报道,介绍Google正在为大网页做标记。但是,这篇报道的网页,体积为18MB,外加一个3MB的视频。

2015年5月,Facebook引入了"Instant Articles",帮助用户快速浏览新闻。但是,介绍这个功能的页面,体积为6.8MB,外加一个41MB的视频。你想了解这个功能的细节,唯一的方法就是去看这个视频。

2.

网页真的有必要这么大吗?明明200KB就足够,为什么要做成2MB?

因为我们要往里面塞很多不需要的东西:广告、高清图片、视频、用户追踪系统、社交媒体的代码......你不塞,公司就可能解雇你。

如今的时代,你跟雇主说,想做一张体积只有几百KB的网页,就好像跟SUV车主谈论省油的经济型轿车。

有人会说,这是免费内容的代价。但是,我想问,谁会从海量的互联网广告获利?广告主,还是消费者?真正获得暴利的是网络服务提供商和互联网广告公司,其他人都付出了巨大的成本。

3.

我们都忘了健康的网页,应该是什么样子。

  • 值得阅读的文本,配上结构良好的标签。
  • 适度的图片和视觉设计。
  • 一层CSS
  • 少量的JavaScript,只在必需时使用

但是,2015年真实的网页,却是下面这样。

  • 一层HTML
  • 一大堆垃圾
  • 顶部还有一层监控代码

4.

宽带和光纤上网并不解决问题,实际上还鼓励了人们往网页上添加更多的东西。

为了平衡网页体积,工程师想出了很多方法:首屏快速渲染、压缩文件、异步加载、批量HTTP请求、管道发送等等......

网站开发越来越依赖代码精简、压缩、缓存、服务器配置这些中间步骤,这使得找出错误越来越困难,成本越来越高。

5.

复杂性让聪明人上瘾。

即使我们知道复杂不是好事,但难以抵抗。复杂的东西总是显得很酷,让人情不自禁想继续干下去。

大多数网站都过度复杂了。

我们做的每件事,都使得创造网站或编辑网页变得困难。把一篇文章放上网,正在变得需要一个专家团队才能完成。

新手越来越难通过源码学习。我们抽走了人们学习互联网的梯子。

6.

其实只需要两步,就可以大大缩小网页体积,提高性能。

第一步,确保最重要的内容,首先下载和渲染;

第二步,就此结束。

你不需要那些多余的垃圾,对最简主义保持信心就行。

7.

让我们保持互联网是一个超链接构成的媒体,不要把它变成另一种东西。

(完)

文档信息

2015年12月24日星期四

阮一峰的网络日志

阮一峰的网络日志


Git 协作流程

Posted: 23 Dec 2015 10:15 PM PST

Git 作为一个源码管理系统,不可避免涉及到多人协作。

协作必须有一个规范的流程,让大家有效地合作,使得项目井井有条地发展下去。"协作流程"在英语里,叫做"workflow"或者"flow",原意是水流,比喻项目像水流那样,顺畅、自然地向前流动,不会发生冲击、对撞、甚至漩涡。

本文介绍三种广泛使用的协作流程:

  • Git flow
  • Github flow
  • Gitlab flow

如果你对Git还不是很熟悉,可以先阅读下面的文章。

一、功能驱动

本文的三种协作流程,有一个共同点:都采用"功能驱动式开发"(Feature-driven development,简称FDD)。

它指的是,需求是开发的起点,先有需求再有功能分支(feature branch)或者补丁分支(hotfix branch)。完成开发后,该分支就合并到主分支,然后被删除。

二、Git flow

最早诞生、并得到广泛采用的一种协作流程,就是Git flow

2.1 特点

它最主要的特点有两个。

首先,项目存在两个长期分支。

  • 主分支master
  • 开发分支develop

前者用于存放对外发布的版本,任何时候在这个分支拿到的,都是稳定的分布版;后者用于日常开发,存放最新的开发版。

其次,项目存在三种短期分支。

  • 功能分支(feature branch)
  • 补丁分支(hotfix branch)
  • 预发分支(release branch)

一旦完成开发,它们就会被合并进developmaster,然后被删除。

Git flow 的详细介绍,请阅读我翻译的中文版《Git 分支管理策略》

2.2 评价

Git flow的优点是清晰可控,缺点是相对复杂,需要同时维护两个长期分支。大多数工具都将master当作默认分支,可是开发是在develop分支进行的,这导致经常要切换分支,非常烦人。

更大问题在于,这个模式是基于"版本发布"的,目标是一段时间以后产出一个新版本。但是,很多网站项目是"持续发布",代码一有变动,就部署一次。这时,master分支和develop分支的差别不大,没必要维护两个长期分支。

三、Github flow

Github flow 是Git flow的简化版,专门配合"持续发布"。它是 Github.com 使用的协作流程。

3.1 流程

它只有一个长期分支,就是master,因此用起来非常简单。

官方推荐的流程如下。

第一步:根据需求,从master拉出新分支,不区分功能分支或补丁分支。

第二步:新分支开发完成后,或者需要讨论的时候,就向master发起一个pull reqest(简称PR)。

第三步:Pull Request既是一个通知,让别人注意到你的请求,又是一种对话机制,大家一起评审和讨论你的代码。对话过程中,你还可以不断提交代码。

第四步:你的Pull Request被接受,合并进master,重新部署后,原来你拉出来的那个分支就被删除。(先部署再合并也可。)

3.2 评价

Github flow 的最大优点就是简单,对于"持续发布"的产品,可以说是最合适的流程。

问题在于它的假设:master分支的更新与产品的发布是一致的。也就是说,master分支的最新代码,默认就是当前的线上代码。

可是,有些时候并非如此,代码合并进入master分支,并不代表它就能立刻发布。比如,苹果商店的APP提交审核以后,等一段时间才能上架。这时,如果还有新的代码提交,master分支就会与刚发布的版本不一致。另一个例子是,有些公司有发布窗口,只有指定时间才能发布,这也会导致线上版本落后于master分支。

上面这种情况,只有master一个主分支就不够用了。通常,你不得不在master分支以外,另外新建一个production分支跟踪线上版本。

四、Gitlab flow

Gitlab flow 是 Git flow 与 Github flow 的综合。它吸取了两者的优点,既有适应不同开发环境的弹性,又有单一主分支的简单和便利。它是 Gitlab.com 推荐的做法。

4.1 上游优先

Gitlab flow 的最大原则叫做"上游优先"(upsteam first),即只存在一个主分支master,它是所有其他分支的"上游"。只有上游分支采纳的代码变化,才能应用到其他分支。

Chromium项目就是一个例子,它明确规定,上游分支依次为:

  1. Linus Torvalds的分支
  2. 子系统(比如netdev)的分支
  3. 设备厂商(比如三星)的分支

4.2 持续发布

Gitlab flow 分成两种情况,适应不同的开发流程。

对于"持续发布"的项目,它建议在master分支以外,再建立不同的环境分支。比如,"开发环境"的分支是master,"预发环境"的分支是pre-production,"生产环境"的分支是production

开发分支是预发分支的"上游",预发分支又是生产分支的"上游"。代码的变化,必须由"上游"向"下游"发展。比如,生产环境出现了bug,这时就要新建一个功能分支,先把它合并到master,确认没有问题,再cherry-pickpre-production,这一步也没有问题,才进入production

只有紧急情况,才允许跳过上游,直接合并到下游分支。

4.3 版本发布

对于"版本发布"的项目,建议的做法是每一个稳定版本,都要从master分支拉出一个分支,比如2-3-stable2-4-stable等等。

以后,只有修补bug,才允许将代码合并到这些分支,并且此时要更新小版本号。

五、一些小技巧

5.1 Pull Request

功能分支合并进master分支,必须通过Pull Request(Gitlab里面叫做 Merge Request)。

前面说过,Pull Request本质是一种对话机制,你可以在提交的时候,@相关人员团队,引起他们的注意。

5.2 Protected branch

master分支应该受到保护,不是每个人都可以修改这个分支,以及拥有审批 Pull Request 的权力。

GithubGitlab 都提供"保护分支"(Protected branch)这个功能。

5.3 Issue

Issue 用于 Bug追踪和需求管理。建议先新建 Issue,再新建对应的功能分支。功能分支总是为了解决一个或多个 Issue。

功能分支的名称,可以与issue的名字保持一致,并且以issue的编号起首,比如"15-require-a-password-to-change-it"。

开发完成后,在提交说明里面,可以写上"fixes #14"或者"closes #67"。Github规定,只要commit message里面有下面这些动词 + 编号,就会关闭对应的issue。

  • close
  • closes
  • closed
  • fix
  • fixes
  • fixed
  • resolve
  • resolves
  • resolved

这种方式还可以一次关闭多个issue,或者关闭其他代码库的issue,格式是username/repository#issue_number

Pull Request被接受以后,issue关闭,原始分支就应该删除。如果以后该issue重新打开,新分支可以复用原来的名字。

5.4 Merge节点

Git有两种合并:一种是"直进式合并"(fast forward),不生成单独的合并节点;另一种是"非直进式合并"(none fast-forword),会生成单独节点。

前者不利于保持commit信息的清晰,也不利于以后的回滚,建议总是采用后者(即使用--no-ff参数)。只要发生合并,就要有一个单独的合并节点。

5.5 Squash 多个commit

为了便于他人阅读你的提交,也便于cherry-pick或撤销代码变化,在发起Pull Request之前,应该把多个commit合并成一个。(前提是,该分支只有你一个人开发,且没有跟master合并过。)

这可以采用rebase命令附带的squash操作,具体方法请参考我写的《Git 使用规范流程》

(完)

文档信息

2015年12月15日星期二

阮一峰的网络日志

阮一峰的网络日志


有没有安全的工作?

Posted: 14 Dec 2015 06:12 PM PST

如果你经常使用互联网,可能知道有一种东西叫做Flash。

它是一种软件,用来制作网页游戏、动画,以及视频播放器。只要观看网络视频,基本都会用到它。

七八年前,它是最热门的互联网技术之一。如果不安装Flash,很多网站根本打不开。那时还流行用它制作动画,随便一个作品,就有几十万、上百万的浏览量。电视台甚至开辟栏目,播放网上流行的Flash动画。各大互联网公司都有专门的Flash工程师,还是属于那种比较抢手、收入较高的工程师。我记得那个时候,社会上也有大量的Flash培训班,它们的招生广告都写着保证就业。

后来,Flash就不行了。2010年,乔布斯宣布,苹果手机不会使用Flash,因为影响手机性能。再后来,新的技术兴起,它就开始没落了。上个月,BBC发表一篇报道,名字就叫《Flash还能活多久?》。话音刚落,一周后,这项技术的拥有者Adobe公司宣布,放弃Flash这个名字,软件将重新定位,只用来制作动画。

说了这么多,我并不是感叹Flash这项技术的没落,这也是很正常的事,而是感叹那些从事Flash开发的工程师,他们该怎么办呢?你在一个领域钻研多年,都成了专家,突然之间那个领域过时了,你的所学所长没人需要了,那将是怎样的处境?

那些年里,我在上海遇见过一个朋友。他开了一家软件公司,专门面向海外市场开发Flash游戏。公司不大,十几个人,那时正是最好的年景,每个月都有几十万、甚至上百万人民币进账,看上去前景一片大好。可是,谁能想到Flash技术突然就会不行了呢?开始时,公司还能维持,后来手机游戏起来了,Flash游戏的市场顿时萎缩。我见过他的招聘广告,改招手机游戏的开发者。再后来,就再没听到过他的消息。

当一种技术消亡的时候,与它相关的工作岗位也就消亡了。这种事情在技术行业特别多,因为技术的升级换代太快了。

我再举一个例子。苹果手机出现之前,最流行的手机都使用Nokia公司开发的"塞班"操作系统。你可能还记得,它的典型标志就是"九宫格"菜单。那时,塞班工程师也是非常抢手的,彻底掌握它那一套开发技术,我估计至少要一两年时间。后来,智能手机流行,塞班一败涂地。2010年,诺基亚宣布放弃塞班,改用微软的操作系统。再后来,Nokia自己也没了,所有手机工程师都遣散了。我知道,Nokia中国有一个资深工程师,选择重进大学去读MBA学位。

试想一下,你花了多年的心血,孜孜不倦地投入和练习,终于掌握了一门赖以谋生的手艺,还进入了世界排名第一位的通信业跨国公司。就在你觉得人生终于有一点安全感的时候,一切就变了,几年之间,曾经的巨无霸土崩瓦解,不仅你的职位没了,更可怕的是,以前的产品已经没人用了,全世界现在不生产任何塞班设备。你的手艺的价值变成了零。

有人说,可以再学习、然后重新就业啊,塞班不行了,可以学习苹果手机开发。没错,说得完全正确。但是,你以前的积累没了,需要从零开始。跟现在刚刚走出校门的学生,站在同一条起跑线上,学习同样的东西。说实话,虽然你有几年开发经验,但很可能并没有那些20岁的年轻人学得快。在一个高速变化的行业,经验有时候不是帮助,而是障碍,因为以前的那套行不通了。退一步说,就算你重新学习了,但苹果手机的开发也在变,你得不停地追赶新东西 。一个人的人生,能经受得起多少次从零开始呢?

"终身学习"这个词完全没错,但是想通过"终身学习"保持职业竞争力,我觉得不太可能。

程序员,乃至其他很多技术岗位,其实是青春饭。只有底层的技术,还有一些稳定性,越接近应用层,技术的升级换代就越快。你学会一门技术,然后吃上三十年,这种事情越来越少见了。更常见的是,几年以后,你会的东西就淘汰了,你被迫重新学习新东西,或者重新就业。

为什么中国很少见35岁以上的程序员?因为他们上学时学习的东西都淘汰了,必须和年轻人一起学习新技术。你很难比年轻人更有竞争力,其中最关键的是,雇佣刚走出校门的学生,比雇佣你便宜得多。

其他行业的升级换代,不如技术行业那么夸张和激进。职业的安全感可以保持得更久一些,但远不是高枕无忧。技术正在取代人力劳动,比如财务会计这样的行业,随着电子支付的兴起,将来肯定不会需要这么多财务人员。"互联网+"从某个方面说,就是使用互联网技术取代一部分人力,更便宜地服务更多的顾客。

回到本文的题目,世界上有没有安全的工作?应该是有的吧,但真的不多。公务员可能比较安全,因为这个职业改变得比较缓慢,而且没有技术升级的压力。医生和律师,也比较安全,因为对于这些行业,经验很重要,但技术正在把它们的成本降下来。厨师和物流,也是比较安全的行业,因为技术再进步,也总需要人来做饭和送货,但是它们是纯粹的体力劳动,没有进入门槛,供给非常大,想拿到高工资不容易。

最终来说,人类社会的就业形态正在发生深刻的改变,"终生职业"越来越少了。每个人都应该尽早打算,如果明天你的职业消失了,你该怎么办?

[说明] 原文发表在《财新周刊》(2015年12月11日)的专栏。

(完)

文档信息

2015年12月9日星期三

阮一峰的网络日志

阮一峰的网络日志


常用 Git 命令清单

Posted: 08 Dec 2015 05:54 PM PST

我每天使用 Git ,但是很多命令记不住。

一般来说,日常使用只要记住下图6个命令,就可以了。但是熟练使用,恐怕要记住60~100个命令。

下面是我整理的常用 Git 命令清单。几个专用名词的译名如下。

  • Workspace:工作区
  • Index / Stage:暂存区
  • Repository:仓库区(或本地仓库)
  • Remote:远程仓库

一、新建代码库

  # 在当前目录新建一个Git代码库  $ git init    # 新建一个目录,将其初始化为Git代码库  $ git init [project-name]    # 下载一个项目和它的整个代码历史  $ git clone [url]  

二、配置

Git的设置文件为.gitconfig,它可以在用户主目录下(全局配置),也可以在项目目录下(项目配置)。

  # 显示当前的Git配置  $ git config --list    # 编辑Git配置文件  $ git config -e [--global]    # 设置提交代码时的用户信息  $ git config [--global] user.name "[name]"  $ git config [--global] user.email "[email address]"  

三、增加/删除文件

  # 添加指定文件到暂存区  $ git add [file1] [file2] ...    # 添加指定目录到暂存区,包括子目录  $ git add [dir]    # 添加当前目录的所有文件到暂存区  $ git add .    # 删除工作区文件,并且将这次删除放入暂存区  $ git rm [file1] [file2] ...    # 停止追踪指定文件,但该文件会保留在工作区  $ git rm --cached [file]    # 改名文件,并且将这个改名放入暂存区  $ git mv [file-original] [file-renamed]  

四、代码提交

  # 提交暂存区到仓库区  $ git commit -m [message]    # 提交暂存区的指定文件到仓库区  $ git commit [file1] [file2] ... -m [message]    # 提交工作区自上次commit之后的变化,直接到仓库区  $ git commit -a    # 提交时显示所有diff信息  $ git commit -v    # 使用一次新的commit,替代上一次提交  # 如果代码没有任何新变化,则用来改写上一次commit的提交信息  $ git commit --amend -m [message]    # 重做上一次commit,并包括指定文件的新变化  $ git commit --amend   ...  

五、分支

  # 列出所有本地分支  $ git branch    # 列出所有远程分支  $ git branch -r    # 列出所有本地分支和远程分支  $ git branch -a    # 新建一个分支,但依然停留在当前分支  $ git branch [branch-name]    # 新建一个分支,并切换到该分支  $ git checkout -b [branch]    # 新建一个分支,指向指定commit  $ git branch [branch] [commit]    # 新建一个分支,与指定的远程分支建立追踪关系  $ git branch --track [branch] [remote-branch]    # 切换到指定分支,并更新工作区  $ git checkout [branch-name]    # 建立追踪关系,在现有分支与指定的远程分支之间  $ git branch --set-upstream [branch] [remote-branch]    # 合并指定分支到当前分支  $ git merge [branch]    # 选择一个commit,合并进当前分支  $ git cherry-pick [commit]    # 删除分支  $ git branch -d [branch-name]    # 删除远程分支  $ git push origin --delete   $ git branch -dr   

六、标签

  # 列出所有tag  $ git tag    # 新建一个tag在当前commit  $ git tag [tag]    # 新建一个tag在指定commit  $ git tag [tag] [commit]    # 查看tag信息  $ git show [tag]    # 提交指定tag  $ git push [remote] [tag]    # 提交所有tag  $ git push [remote] --tags    # 新建一个分支,指向某个tag  $ git checkout -b [branch] [tag]  

七、查看信息

  # 显示有变更的文件  $ git status    # 显示当前分支的版本历史  $ git log    # 显示commit历史,以及每次commit发生变更的文件  $ git log --stat    # 显示某个文件的版本历史,包括文件改名  $ git log --follow [file]  $ git whatchanged [file]    # 显示指定文件相关的每一次diff  $ git log -p [file]    # 显示指定文件是什么人在什么时间修改过  $ git blame [file]    # 显示暂存区和工作区的差异  $ git diff    # 显示暂存区和上一个commit的差异  $ git diff --cached []    # 显示工作区与当前分支最新commit之间的差异  $ git diff HEAD    # 显示两次提交之间的差异  $ git diff [first-branch]...[second-branch]    # 显示某次提交的元数据和内容变化  $ git show [commit]    # 显示某次提交发生变化的文件  $ git show --name-only [commit]    # 显示某次提交时,某个文件的内容  $ git show [commit]:[filename]    # 显示当前分支的最近几次提交  $ git reflog  

八、远程同步

  # 下载远程仓库的所有变动  $ git fetch [remote]    # 显示所有远程仓库  $ git remote -v    # 显示某个远程仓库的信息  $ git remote show [remote]    # 增加一个新的远程仓库,并命名  $ git remote add [shortname] [url]    # 取回远程仓库的变化,并与本地分支合并  $ git pull [remote] [branch]    # 上传本地指定分支到远程仓库  $ git push [remote] [branch]    # 强行推送当前分支到远程仓库,即使有冲突  $ git push [remote] --force    # 推送所有分支到远程仓库  $ git push [remote] --all  

九、撤销

  # 恢复暂存区的指定文件到工作区  $ git checkout [file]    # 恢复某个commit的指定文件到工作区  $ git checkout [commit] [file]    # 恢复上一个commit的所有文件到工作区  $ git checkout .    # 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变  $ git reset [file]    # 重置暂存区与工作区,与上一次commit保持一致  $ git reset --hard    # 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变  $ git reset [commit]    # 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致  $ git reset --hard [commit]    # 重置当前HEAD为指定commit,但保持暂存区和工作区不变  $ git reset --keep [commit]    # 新建一个commit,用来撤销指定commit  # 后者的所有变化都将被前者抵消,并且应用到当前分支  $ git revert [commit]  

十、其他

  # 生成一个可供发布的压缩包  $ git archive  

(完)

文档信息