GitHub 初探

1.GitHub 有什么用

学习优秀的开源项目
开源社区一直有一句流行的话叫「不要重复发明轮子」,某种意义上正是因为开源社区的贡献,我们的软件开发才能变得越来越容易,越来越快速。试想你在做项目时,如果每一模块都要自己去写,如网络库、图片加载库、ORM库等等,自己写的好不好是一回事,时间与资源是很大的成本。对于大公司可能会有人力与资源去发明一套自己的轮子,但是对于大部分互联网创业公司来说时间就是一切。而且你在使用开源项目的过程也可以学习他们优秀的设计思想、实现方式,这是最好的学习资料,也是一份提升自己能力的绝佳方式!

多人协作
如果你想发起一个项目,比如翻译一份不错的英文文档,觉得一个人的精力不够,所以你需要更多的人参与进来,这时候 GitHub 是你的最佳选择,感兴趣的人可以参与进来,利用业余时间对这个项目做贡献,然后可以互相审核、合并,简直不要太棒!

搭建博客、个人网站或者公司官网
这个就不用多说了,现在越来越多的博客都是基于 GitHub Pages 来搭建的了,你可以随心所欲的定制自己的样式,可以给你博客买个逼格高的域名,再也不用忍受各大博客网站的约束与各式各样的广告了!

写作
如果你喜欢写作,而且基于 Markdown, 并准备出版书籍,那么推荐你用 Gitbook ,技术写作人的最爱!

个人简历
如果你有一个活跃的 GitHub 账号,上面有自己不错的开源项目,还经常给别的开源项目提问题,push 代码,那么你找工作将是一个非常大的优势,现在程序员的招聘很多公司都很看中你 GitHub 账号,某种意义上 GitHub 就可以算是你的简历了。而且不仅国内,很多国外的科技公司都会通过 GitHub 来寻找优秀的人才,比如我甚至通过 GitHub 收到过 Facebook 的邀请邮件!

2. GitHub 基本概念

Repository
仓库的意思,即你的项目,你想在 GitHub 上开源一个项目,那就必须要新建一个 Repository ,如果你开源的项目多了,你就拥有了多个 Repositories 。

Issue
问题的意思,举个例子,就是你开源了一个项目,别人发现你的项目中有bug,或者哪些地方做的不够好,他就可以给你提个 Issue ,即问题,提的问题多了,也就是 Issues ,然后你看到了这些问题就可以去逐个修复,修复ok了就可以一个个的 Close 掉。

Star
这个好理解,就是给项目点赞,但是在 GitHub 上的点赞远比微博、知乎点赞难的多,如果你有一个项目获得100个star都算很不容易了!

Fork
这个不好翻译,如果实在要翻译我把他翻译成分叉,什么意思呢?你开源了一个项目,别人想在你这个项目的基础上做些改进,然后应用到自己的项目中,这个时候他就可以 Fork 你的项目,这个时候他的 GitHub 主页上就多了一个项目,只不过这个项目是基于你的项目基础(本质上是在原有项目的基础上新建了一个分支,分支的概念后面会在讲解Git的时候说到),他就可以随心所欲的去改进,但是丝毫不会影响原有项目的代码与结构。

Pull Request
发起请求,这个其实是基于 Fork 的,还是上面那个例子,如果别人在你基础上做了改进,后来觉得改进的很不错,应该要把这些改进让更多的人收益,于是就想把自己的改进合并到原有项目里,这个时候他就可以发起一个 Pull Request(简称PR) ,原有项目创建人就可以收到这个请求,这个时候他会仔细review你的代码,并且测试觉得OK了,就会接受你的PR,这个时候你做的改进原有项目就会拥有了。

Watch
这个也好理解就是观察,如果你 Watch 了某个项目,那么以后只要这个项目有任何更新,你都会第一时间收到关于这个项目的通知提醒。

Gist
有些时候你没有项目可以开源,只是单纯的想分享一些代码片段,那这个时候 Gist 就派上用场了!

3. 创建自己的项目

点击顶部导航栏的 + 可以快速创建一个项目,如下图:



创建一个项目需要填写如上的几部分:项目名、项目描述与简单的介绍,你不付费没法选择私有的,所以接着只能选择 public 的,之后勾选「Initialize this repository with a README」,这样你就拥有了你的第一个 GitHub 项目:


image.png

可以看到这个项目只包含了一个 README.md 文件,但是它已经是一个完整的 Git 仓库了,你可以通过对它进行一些操作,如watch、star、fork,还可以 clone 或者下载下来。

这里提一下 README.md ,GitHub 上所有关于项目的详细介绍以及 Wiki 都是基于 Markdown 的,甚至之后在 GitHub 上搭建博客,写博客也是如此,所以如果还不懂 Markdown 语法的,建议先去学习下。推荐一篇学习 Markdown 的文章给你们:

献给写作者的 Markdown 新手指南

4. GitHub 系列之「Git 速成」

GitHub 是基于 Git 的,所以也就意味着 Git 是基础,如果你不会 Git ,那么接下来你完全继续不下去,所以今天的教程就来说说 Git ,争取 Git 速成。

4.1.什么是Git?

Git 是 Linux 发明者 Linus 开发的一款新时代的版本控制系统,那什么是版本控制系统呢?怎么理解?网上一大堆详细的介绍,但是大多枯燥乏味,对于新手也很难理解,这里我只举几个例子来帮助你们理解。

熟悉编程的知道,我们在软件开发中源代码其实是最重要的,那么对源代码的管理变得异常重要:

比如为了防止代码的丢失,肯定本地机器与远程服务器都要存放一份,而且还需要有一套机制让本地可以跟远程同步;

又比如我们经常是好几个人做同一个项目,都要对一份代码做更改,这个时候需要大家互不影响,又需要各自可以同步别人的代码;

又比如我们开发的时候免不了有bug,有时候刚发布的功能就出现了严重的bug,这个时候需要紧急对代码进行还原;

又比如随着我们版本迭代的功能越来越多,但是我们需要清楚的知道历史每一个版本的代码更改记录,甚至知道每个人历史提交代码的情况;

等等等类似以上的情况,这些都是版本控制系统能解决的问题。所以说,版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统,对于软件开发领域来说版本控制是最重要的一环,而 Git 毫无疑问是当下最流行、最好用的版本控制系统。

4.2. Git 安装

上面说了,Git 是一个版本控制系统,你也可以理解成是一个工具,跟 Java 类似,使用之前必须得先下载安装,所以第一步必须要安装,我用的是 Mac , Mac 上其实系统自带 Git 的,不过这里统一提供一下各平台的安装方式,这部分就不过多介绍,相信大家这里搞的定。

4.3 如何学习 Git ?

安装好 Git 之后,怎么学习是个问题,其实关于 Git 有很多图形化的软件可以操作,但是我强烈建议大家从命令行开始学习理解,我知道没接触过命令行的人可能会很抵触,但是我的亲身实践证明,只有一开始学习命令行,之后你对 Git 的每一步操作才能理解其意义,而等你熟练之后你想用任何的图形化的软件去操作完全没问题。

我一开始教我们团队成员全是基于命令行的,事后证明他们现在已经深深爱上命令行无法自拔,他们很理解 Git 每一步操作的具体含义,以致于在实际项目很少犯错,所以我这里也是基于命令行去教你们学习理解。

4.4 Git 命令列表

怎么判断你 Git 有没有安装成功?请在命令行里输入 git ,如果出现以下提示证明你已经安装成功了。
Git 所有的操作命令开头都要以 git 开头,上面列举了最常用的一些 Git 命令,紧接着会有一句英文解释这个命令的意义,都不是很难的单词,不妨试着看一下,不过没有实际操作你仍然不好理解,下面我们来以一个实际的操作来介绍下一些常用命令的含义。

4.5 Git 具体命令

第一步,我们先新建一个文件夹,在文件夹里新建一个文件(我是用 Linux 命令去新建的,Windows用户可以自己手动新建)

mkdir test (创建文件夹test)
cd test (切换到test目录)
touch a.md (新建a.md文件)

这里提醒下:在进行任何 Git 操作之前,都要先切换到 Git 仓库目录,也就是先要先切换到项目的文件夹目录下。
这个时候我们先随便操作一个命令,比如 git status ,可以看到如下提示(别纠结颜色之类的,配置与主题不一样而已):



意思就是当前目录还不是一个 Git 仓库。

git init

这个时候用到了第一个命令,代表初始化 git 仓库,输入 git init 之后会提示:

可以看到初始化成了,至此 test 目录已经是一个 git 仓库了。

git status

紧接着我们输入 git status 命令,会有如下提示:

默认就直接在 master 分支,关于分支的概念后面会提,这时最主要的是提示 a.md 文件 Untracked files ,就是说 a.md 这个文件还没有被跟踪,还没有提交在 git 仓库里呢,而且提示你可以使用 git add <file> 去操作你想要提交的文件。

git status 这个命令顾名思义就是查看状态,这个命令可以算是使用最频繁的一个命令了,建议大家没事就输入下这个命令,来查看你当前 git 仓库的一些状态。

git add

上面提示 a.md 文件还没有提交到 git 仓库里,这个时候我们可以随便编辑下 a.md 文件,然后输入 git add a.md ,然后再输入 git status :

image.png

此时提示以下文件 Changes to be committed , 意思就是 a.md 文件等待被提交,当然你可以使用 git rm --cached 这个命令去移除这个缓存。

git commit

接着我们输入 git commit -m 'first commit' ,这个命令什么意思呢? commit 是提交的意思,-m 代表是提交信息,执行了以上命令代表我们已经正式进行了第一次提交。

这个时候再输入 git status ,会提示 nothing to commit。

git log

这个时候我们输入 git log 命令,会看到如下:

image.png

git log 命令可以查看所有产生的 commit 记录,所以可以看到已经产生了一条 commit 记录,而提交时候的附带信息叫 'first commit' 。

git add & git commit

看到这里估计很多人会有疑问,我想要提交直接进行 commit 不就行了么,为什么先要再 add 一次呢?首先 git add 是先把改动添加到一个「暂存区」,你可以理解成是一个缓存区域,临时保存你的改动,而 git commit 才是最后真正的提交。这样做的好处就是防止误提交,当然也有办法把这两步合并成一步,不过后面再介绍,建议新手先按部就班的一步步来。

git branch

branch 即分支的意思,分支的概念很重要,尤其是团队协作的时候,假设两个人都在做同一个项目,这个时候分支就是保证两人能协同合作的最大利器了。举个例子,A, B俩人都在做同一个项目,但是不同的模块,这个时候A新建了一个分支叫a, B新建了一个分支叫b,这样A、B做的所有代码改动都各自在各自的分支,互不影响,等到俩人都把各自的模块都做完了,最后再统一把分支合并起来。

执行 git init 初始化git仓库之后会默认生成一个主分支 master ,也是你所在的默认分支,也基本是实际开发正式环境下的分支,一般情况下 master 分支不会轻易直接在上面操作的,你们可以输入 git branch 查看下当前分支情况:

image.png

如果我们想在此基础上新建一个分支呢,很简单,执行 git branch a 就新建了一个名字叫 a 的分支,这时候分支 a 跟分支 master 是一模一样的内容,我们再输入 git branch 查看的当前分支情况:

但是可以看到 master 分支前有个 * 号,即虽然新建了一个 a 的分支,但是当前所在的分支还是在 master 上,如果我们想在 a 分支上进行开发,首先要先切换到 a 分支上才行,所以下一步要切换分支

git checkout a

执行这个命令,然后再输入 git branch 查看下分支情况:

image.png

可以看到当前我们在的分支已经是a了,这个时候 A 同学就可以尽情的在他新建的a分支去进行代码改动了。

那有人就说了,我要先新建再切换,未免有点麻烦,有没有一步到位的,聪明:

git checkout -b a

这个命令的意思就是新建一个a分支,并且自动切换到a分支。

git merge

A同学在a分支代码写的不亦乐乎,终于他的功能完工了,并且测试也都ok了,准备要上线了,这个时候就需要把他的代码合并到主分支master上来,然后发布。git merge 就是合并分支用到的命令,针对这个情况,需要先做两步,第一步是切换到 master 分支,如果你已经在了就不用切换了,第二步执行 git merge a ,意思就是把a分支的代码合并过来,不出意外,这个时候a分支的代码就顺利合并到 master 分支来了。为什么说不出意外呢?因为这个时候可能会有冲突而合并失败,留个包袱,这个到后面进阶的时候再讲。

git branch -d

有新建分支,那肯定有删除分支,假如这个分支新建错了,或者a分支的代码已经顺利合并到 master 分支来了,那么a分支没用了,需要删除,这个时候执行 git branch -d a 就可以把a分支删除了。

git branch -D

有些时候可能会删除失败,比如如果a分支的代码还没有合并到master,你执行 git branch -d a 是删除不了的,它会智能的提示你a分支还有未合并的代码,但是如果你非要删除,那就执行 git branch -D a 就可以强制删除a分支。

git tag

我们在客户端开发的时候经常有版本的概念,比如v1.0、v1.1之类的,不同的版本肯定对应不同的代码,所以我一般要给我们的代码加上标签,这样假设v1.1版本出了一个新bug,但是又不晓得v1.0是不是有这个bug,有了标签就可以顺利切换到v1.0的代码,重新打个包测试了。

所以如果想要新建一个标签很简单,比如 git tag v1.0 就代表我在当前代码状态下新建了一个v1.0的标签,输入 git tag 可以查看历史 tag 记录。

image.png

可以看到我新建了两个标签 v1.0、v1.1。

想要切换到某个tag怎么办?也很简单,执行 git checkout v1.0 ,这样就顺利的切换到 v1.0 tag的代码状态了。

OK,以上全是一些最基本的Git操作,而且全是在本地环境进行操作的,完全没有涉及到远程仓库,下一章节将以远程 GitHub 仓库为例,讲解下本地如何跟远程仓库一起同步协作,另外今天讲的全是最基础最简单的Git操作,一步步来,后续再继续讲解一下Git的高阶以及一些Git的酷炫操作。

5 向 GitHub 上提交你们的第一行代码

5.1 SSH

你拥有了一个 GitHub 账号之后,就可以自由的 clone 或者下载其他项目,也可以创建自己的项目,但是你没法提交代码。仔细想想也知道,肯定不可能随意就能提交代码的,如果随意可以提交代码,那么 GitHub 上的项目岂不乱了套了,所以提交代码之前一定是需要某种授权的,而 GitHub 上一般都是基于 SSH 授权的。

那么什么是 SSH 呢?
简单点说,SSH是一种网络协议,用于计算机之间的加密登录。目前是每一台 Linux 电脑的标准配置。而大多数 Git 服务器都会选择使用 SSH 公钥来进行授权,所以想要在 GitHub 提交代码的第一步就是要先添加 SSH key 配置。

5.2 生成SSH key

Linux 与 Mac 都是默认安装了 SSH ,而 Windows 系统安装了 Git Bash 应该也是带了 SSH 的。大家可以在终端(win下在 Git Bash 里)输入 ssh 如果出现以下提示证明你本机已经安装 SSH, 否则请搜索自行安装下。
紧接着输入 ssh-keygen -t rsa ,什么意思呢?就是指定 rsa 算法生成密钥,接着连续三个回车键(不需要输入密码),然后就会生成两个文件 id_rsa 和 id_rsa.pub ,而 id_rsa 是密钥,id_rsa.pub 就是公钥。

这两文件默认分别在如下目录里生成:
Linux/Mac 系统 在 ~/.ssh 下,win系统在 /c/Documents and Settings/username/.ssh 下,都是隐藏文件,相信你们有办法查看的。接下来要做的是把 id_rsa.pub 的内容添加到 GitHub 上,这样你本地的 id_rsa 密钥跟 GitHub 上的 id_rsa.pub 公钥进行配对,授权成功才可以提交代码。

5.3 GitHub 上添加 SSH key

第一步先在 GitHub 上的设置页面,点击最左侧 SSH and GPG keys :

然后点击右上角的 New SSH key 按钮:

需要做的只是在 Key 那栏把 id_rsa.pub 公钥文件里的内容复制粘贴进去就可以了(上述示例为了安全粘贴的公钥是无效的),Title 那栏不需要填写,点击 Add SSH key 按钮就ok了。

这里提醒下,怎么查看 id_rsa.pub 文件的内容?

Linux/Mac 用户执行以下命令:

cd ~/.ssh
cat id_rsa.pub

Windows用户,设置显示隐藏文件,可以使用 EditPlus 或者 Sublime 打开复制就行了。

SSH key 添加成功之后,输入 ssh -T git@github.com 进行测试,如果出现以下提示证明添加成功了。

5.4 Push & Pull

在提交代码之前我们先要了解两个命令,因为这两个命令需要跟远程仓库配合。

Push :直译过来就是「推」的意思,什么意思呢?如果你本地代码有更新了,那么就需要把本地代码推到远程仓库,这样本地仓库跟远程仓库就可以保持同步了。

代码示例: git push origin master

意思就是把本地代码推到远程 master 分支。

Pull:直译过来就是「拉」的意思,如果别人提交代码到远程仓库,这个时候你需要把远程仓库的最新代码拉下来,然后保证两端代码的同步。

代码示例: git pull origin master

意思就是把远程最新的代码更新到本地。一般我们在 push 之前都会先 pull ,这样不容易冲突。

5.5 提交代码

添加 SSH key 成功之后,我们就有权限向 GitHub 上我们自己的项目提交代码了,而提交代码有两种方法:

Clone自己的项目
我们以我在 GitHub 上创建的 test 项目为例,执行如下命令:

git clone git@github.com:stormzhang/test.git
这样就把 test 项目 clone 到了本地,你可以把 clone 命令理解为高级点的复制,这个时候该项目本身就已经是一个git 仓库了,不需要执行 git init 进行初始化,而且甚至都已经关联好了远程仓库,我们只需要在这个 test 目录下任意修改或者添加文件,然后进行 commit ,之后就可以执行:

git push origin master
进行代码提交,这种是最简单方便的一种方式。
至于怎么获取项目的仓库地址呢?如下图:

关联本地已有项目
如果我们本地已经有一个完整的 git 仓库,并且已经进行了很多次 commit ,这个时候第一种方法就不适合了。

假设我们本地有个 test2 的项目,我们需要的是在 GitHub 上建一个 test 的项目,然后把本地 test2 上的所有代码 commit 记录提交到 GitHub 上的 test 项目。

第一步就是在 GitHub 上建一个 test 项目,这个想必大家都会了,就不用多讲了。

第二步把本地 test2 项目与 GitHub 上的 test 项目进行关联,切换到 test2 目录,执行如下命令:

git remote add origin git@github.com:stormzhang/test.git

什么意思呢?就是添加一个远程仓库,他的地址是 git@github.com:stormzhang/test.git ,而 origin 是给这个项目的远程仓库起的名字,是的,名字你可以随便取,只不过大家公认的只有一个远程仓库时名字就是 origin ,为什么要给远程仓库取名字?因为我们可能一个项目有多个远程仓库?比如 GitHub 一个,比如公司一个,这样的话提交到不同的远程仓库就需要指定不同的仓库名字了。

查看我们当前项目有哪些远程仓库可以执行如下命令:

git remote -v

接下来,我们本地的仓库就可以向远程仓库进行代码提交了:

git push origin master

就是默认向 GitHub 上的 test 目录提交了代码,而这个代码是在 master 分支。当然你可以提交到指定的分支,这个之后的文章再详细讲解。

对了,友情提醒,在提交代码之前先要设置下自己的用户名与邮箱,这些信息会出现在所有的 commit 记录里,执行以下代码就可以设置:

git config —global user.name "stormzhang"
git config —global user.email "stormzhang.dev@gmail.com"

6 Git 进阶

6.1.用户名和邮箱

我们知道我们进行的每一次commit都会产生一条log,这条log标记了提交人的姓名与邮箱,以便其他人方便的查看与联系提交人,所以我们在进行提交代码的第一步就是要设置自己的用户名与邮箱。执行以下代码:

git config --global user.name "stormzhang"
git config --global user.email "stormzhang.dev@gmail.com"
以上进行了全局配置,当然有些时候我们的某一个项目想要用特定的邮箱,这个时候只需切换到你的项目,以上代码把 --global 参数去除,再重新执行一遍就ok了。

PS:我们在 GitHub 的每次提交理论上都会在 主页的下面产生一条绿色小方块的记录,如果你确认你提交了,但是没有绿色方块显示,那肯定是你提交代码配置的邮箱跟你 GitHub 上的邮箱不一致,GitHub 上的邮箱可以到 Setting -> Emails里查看。

6.2 alias

我们知道我们执行的一些Git命令其实操作很频繁的类似有:

git commit
git checkout
git branch
git status
...
这些操作非常频繁,每次都要输入完全是不是有点麻烦,有没有一种简单的缩写输入呢?比如我对应的直接输入以下:

git c
git co
git br
git s
...
是不是很简单快捷啊?这个时候就用到了alias配置了,翻译过来就是别名的意思,输入以下命令就可以直接满足了以上的需求。

git config --global alias.co checkout # 别名
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.br branch
当然以上别名不是固定的,你完全可以根据自己的习惯去定制,除此之外还可以设置组合,比如:

git config --global alias.psm 'push origin master'
git config --global alias.plm 'pull origin master'
之后经常用到的git push origin master 和 git pull origin master 直接就用 git psm 和 git plm 代替了,是不是很方便?

另外这里给大家推荐一个很强大的 alias 命令,我们知道我们输入 git log 查看日志的时候是类似这样的:

image.png

告诉大家一个比较屌的命令,输入**git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative **然后日志这样了:

是不是比较清晰,整个分支的走向也很明确,但是每次都要输这么一大串是不是也很烦?这时候你就该想到 alias 啊:

git config --global alias.lg "log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative"

这样以后直接输入 git lg 就行了

6.3 其他配置

当然还有一些其他有用的配置,默认情况下 git 用的编辑器是 vi ,如果不喜欢可以改成其他编辑器,比如我习惯 vim 。

git config --global core.editor "vim" # 设置Editor使用vim
你们如果喜欢其他编辑器可自行搜索配置,前提是本机有安装。

有些人纳闷我的终端怎么有各种颜色,自己却不是这样的,那是因为你们没有开启给 Git 着色,输入如下命令即可:

git config --global color.ui true
还有些其他的配置如:

git config --global core.quotepath false # 设置显示中文文件名
以上基本所有的配置就差不多了,默认这些配置都在 ~/.gitconfig 文件下的,你可以找到这个文件查看自己的配置,也可以输入 git config -l 命令查看。

6.4 diff

diff命令算是很常用的,使用场景是我们经常在做代码改动,但是有的时候2天前的代码了,做了哪些改动都忘记了,在提交之前需要确认下,这个时候就可以用diff来查看你到底做了哪些改动,举个例子,比如我有一个 a.md 的文件,我现在做了一些改动,然后输入 git diff 就会看到如下


红色的部分前面有个 - 代表我删除的,绿色的部分前面有个 + 代表我增加的,所以从这里你们很一目了然的知道我到底对这个文件做了哪些改动。

值得一提的是直接输入 git diff 只能比较当前文件和暂存区文件差异,什么是暂存区?就是你还没有执行 git add 的文件。

当然跟暂存区做比较之外,他还可以有其他用法,如比较两次 commit 之间的差异,比较两个分支之间的差异,比较暂存区和版本库之间的差异等,具体用法如下:

git diff <$id1> <$id2>   # 比较两次提交之间的差异
git diff <branch1>..<branch2> # 在两个分支之间比较 
git diff --staged   # 比较暂存区和版本库差异
6.5. checkout

我们知道 checkout 一般用作切换分支使用,比如切换到 develop 分支,可以执行:

git checkout develop

但是 checkout 不只用作切换分支,他可以用来切换tag,切换到某次commit,如:

git checkout v1.0
git checkout ffd9f2dd68f1eb21d36cee50dbdd504e95d9c8f7 # 后面的一长串是commit_id,是每次commit的SHA1值,可以根据 git log 看到。

除了有“切换”的意思,checkout 还有一个撤销的作用,举个例子,假设我们在一个分支开发一个小功能,刚写完一半,这时候需求变了,而且是大变化,之前写的代码完全用不了了,好在你刚写,甚至都没有 git add 进暂存区,这个时候很简单的一个操作就直接把原文件还原:

git checkout a.md

这里稍微提下,checkout 命令只能撤销还没有 add 进暂存区的文件。

6.6 stash

设想一个场景,假设我们正在一个新的分支做新的功能,这个时候突然有一个紧急的bug需要修复,而且修复完之后需要立即发布。当然你说我先把刚写的一点代码进行提交不就行了么?这样理论上当然是ok的,但是这会产品垃圾commit,原则上我们每次的commit都要有实际的意义,你的代码只是刚写了一半,还没有什么实际的意义是不建议就这样commit的,那么有没有一种比较好的办法,可以让我暂时切到别的分支,修复完bug再切回来,而且代码也能保留的呢?

这个时候 stash 命令就大有用处了,前提是我们的代码没有进行 commit ,哪怕你执行了 add 也没关系,我们先执行

git stash

命令,什么意思呢?意思就是把当前分支所有没有 commit 的代码先暂存起来,这个时候你再执行 git status 你会发现当前分支很干净,几乎看不到任何改动,你的代码改动也看不见了,但其实是暂存起来了。执行

git stash list

你会发现此时暂存区已经有了一条记录。

这个时候你可以切换会其他分支,赶紧把bug修复好,然后发布。之后一切都解决了,你再切换回来继续做你之前没做完的功能,但是之前的代码怎么还原呢?

git stash apply

你会发现你之前的代码全部又回来了,就好像一切都没发生过一样,紧接着你最好需要把暂存区的这次 stash 记录删除,执行:

git stash drop

就把最近一条的 stash 记录删除了,是不是很方便?其实还有更方便的,你可以使用:

git stash pop

来代替 apply 命令,pop 跟 apply 的唯一区别就是 pop 不但会帮你把代码还原,还自动帮你把这条 stash 记录删除,省的自己再 drop 一次了,为了验证你可以紧接着执行 git stash list 命令来确认是不是已经没有记录了。

最后还有一个命令介绍下:

git stash clear

就是清空所有暂存区的记录,drop 是只删除一条,当然后面可以跟 stash_id 参数来删除指定的某条记录,不跟参数就是删除最近的,而 clear 是清空。

6.7 merge & rebase

我们知道 merge 分支是合并的意思,我们在一个 featureA 分支开发完了一个功能,这个时候需要合并到主分支 master 上去,我们只需要进行如下操作:

git checkout master
git merge featureA

其实 rebase 命令也是合并的意思,上面的需求我们一样可以如下操作:

git checkout master
git rebase featureA

rebase 跟 merge 的区别你们可以理解成有两个书架,你需要把两个书架的书整理到一起去,第一种做法是 merge ,比较粗鲁暴力,就直接腾出一块地方把另一个书架的书全部放进去,虽然暴力,但是这种做法你可以知道哪些书是来自另一个书架的;第二种做法就是 rebase ,他会把两个书架的书先进行比较,按照购书的时间来给他重新排序,然后重新放置好,这样做的好处就是合并之后的书架看起来很有逻辑,但是你很难清晰的知道哪些书来自哪个书架的。

只能说各有好处的,不同的团队根据不同的需要以及不同的习惯来选择就好。

6.8 解决冲突

假设这样一个场景,A和B两位同学各自开了两个分支来开发不同的功能,大部分情况下都会尽量互不干扰的,但是有一个需求A需要改动一个基础库中的一个类的方法,不巧B这个时候由于业务需要也改动了基础库的这个方法,因为这种情况比较特殊,A和B都认为不会对地方造成影响,等两人各自把功能做完了,需要合并的到主分支 master 的时候,我们假设先合并A的分支,这个时候没问题的,之后再继续合并B的分支,这个时候想想也知道就有冲突了,因为A和B两个人同时更改了同一个地方,Git 本身他没法判断你们两个谁更改的对,但是这个时候他会智能的提示有 conflicts ,需要手动解决这个冲突之后再重新进行一次 commit 提交。我随便在项目搞了一个冲突做下示例:


image.png

以上截图里就是冲突的示例,冲突的地方由 ==== 分出了上下两个部分,上部分一个叫 HEAD 的字样代表是我当前所在分支的代码,下半部分是一个叫 baidu_activity 分支的代码,可以看到 HEAD 对 gradle 插件进行了升级,同时新增了一个插件,所以我们很容易判断哪些代码该保留,哪些代码该删除,我们只需要移除掉那些老旧代码,而且同时也要把那些 <<< HEAD、==== 以及 >>>>>>baidu_activity 这些标记符号也一并删除,最后进行一次 commit 就ok了。

我们在开发的过程中一般都会约定尽量大家写的代码不要彼此影响,以减少出现冲突的可能,但是冲突总归无法避免的,我们需要了解并掌握解决冲突的方法。

7 团队合作利器 branch

Git 相比于 SVN 最强大的一个地方就在于「分支」,Git 的分支操作简直不要太方便,而实际项目开发中团队合作最依赖的莫过于分支了,关于分支前面的系列也提到过,但是本篇会详细讲述什么是分支、分支的具体操作以及实际项目开发中到底是怎么依赖分支来进行团队合作的。

7.1 什么是分支?

我知道读者中肯定有些人对分支这个概念比较模糊,其实你们可以这么理解,你们几个人一起去旅行,中间走到一个三岔口,每条路可能有不同的风景,你们约定 3 天之后在某地汇聚,然后各自出发了。而这三条分叉路就可以理解成你们各自的分支,而等你们汇聚的时候相当于把你们的分支进行了合并。

7.2 分支的常用操作

通常我们默认都会有一个主分支叫 master ,下面我们先来看下关于分支的一些基本操作:
新建一个叫 develop 的分支

git branch develop    

这里稍微提醒下大家,新建分支的命令是基于当前所在分支的基础上进行的,即以上是基于 mater 分支新建了一个叫做 develop 的分支,此时 develop 分支跟 master 分支的内容完全一样。如果你有 A、B、C三个分支,三个分支是三位同学的,各分支内容不一样,如果你当前是在 B 分支,如果执行新建分支命令,则新建的分支内容跟 B 分支是一样的,同理如果当前所在是 C 分支,那就是基于 C 分支基础上新建的分支。

切换到 develop 分支
git checkout develop
如果把以上两步合并,即新建并且自动切换到 develop 分支:

git checkout -b develop    

把 develop 分支推送到远程仓库
git push origin develop
如果你远程的分支想取名叫 develop2 ,那执行以下代码:

git push origin develop:develop2

但是强烈不建议这样,这会导致很混乱,很难管理,所以建议本地分支跟远程分支名要保持一致。

查看本地分支列表
git branch
查看远程分支列表
git branch -r
删除本地分支
git branch -d develop
git branch -D develop (强制删除)
删除远程分支
git push origin :develop
如果远程分支有个 develop ,而本地没有,你想把远程的 develop 分支迁到本地:
git checkout develop origin/develop
同样的把远程分支迁到本地顺便切换到该分支:
git checkout -b develop origin/develop

7.3 基本的团队协作流程

一般来说,如果你是一个人开发,可能只需要 master、develop 两个分支就 ok 了,平时开发在 develop 分支进行,开发完成之后,发布之前合并到 master 分支,这个流程没啥大问题。

如果你是 3、5 个人,那就不一样了,有人说也没多大问题啊,直接可以新建 A、B、C 三个人的分支啊,每人各自开发各自的分支,然后开发完成之后再逐步合并到 master 分支。然而现实却是,你正在某个分支开发某个功能呢,这时候突然发现线上有一个很严重的 bug ,不得不停下手头的工作优先处理 bug ,而且很多时候多人协作下如果没有一个规范,很容易产生问题,所以多人协作下的分支管理规范很重要,就跟代码规范一样重要,以下就跟大家推荐一种我们内部在使用的一种分支管理流程 Git Flow。

7.4 Git Flow

准确的说 Git Flow 是一种比较成熟的分支管理流程,我们先看一张图能清晰的描述他整个的工作流程:


image.png

第一次看上面那个图是不是一脸懵逼?跟我当时一样,不急,我来用简单的话给你们解释下。

一般开发来说,大部分情况下都会拥有两个分支 master 和 develop,他们的职责分别是:

master:永远处在即将发布(production-ready)状态
develop:最新的开发状态

确切的说 master、develop 分支大部分情况下都会保持一致,只有在上线前的测试阶段 develop 比 master 的代码要多,一旦测试没问题,准备发布了,这时候会将 develop 合并到 master 上。

但是我们发布之后又会进行下一版本的功能开发,开发中间可能又会遇到需要紧急修复 bug ,一个功能开发完成之后突然需求变动了等情况,所以 Git Flow 除了以上 master 和 develop 两个主要分支以外,还提出了以下三个辅助分支:

feature: 开发新功能的分支, 基于 develop, 完成后 merge 回 develop
release: 准备要发布版本的分支, 用来修复 bug,基于 develop,完成后 merge 回 develop 和 master
hotfix: 修复 master 上的问题, 等不及 release 版本就必须马上上线. 基于 master, 完成后 merge 回 master 和 develop

什么意思呢?

举个例子,假设我们已经有 master 和 develop 两个分支了,这个时候我们准备做一个功能 A,第一步我们要做的,就是基于 develop 分支新建个分支:

git branch feature/A   

看到了吧,其实就是一个规范,规定了所有开发的功能分支都以 feature 为前缀。

但是这个时候做着做着发现线上有一个紧急的 bug 需要修复,那赶紧停下手头的工作,立刻切换到 master 分支,然后再此基础上新建一个分支:

git branch hotfix/B    

代表新建了一个紧急修复分支,修复完成之后直接合并到 develop 和 master ,然后发布。

然后再切回我们的 feature/A 分支继续着我们的开发,如果开发完了,那么合并回 develop 分支,然后在 develop 分支属于测试环境,跟后端对接并且测试的差不多了,感觉可以发布到正式环境了,这个时候再新建一个 release 分支:

git branch release/1.0    

这个时候所有的 api、数据等都是正式环境,然后在这个分支上进行最后的测试,发现 bug 直接进行修改,直到测试 ok 达到了发布的标准,最后把该分支合并到 develop 和 master 然后进行发布。

以上就是 Git Flow 的概念与大概流程,看起来很复杂,但是对于人数比较多的团队协作现实开发中确实会遇到这么复杂的情况,是目前很流行的一套分支管理流程,但是有人会问每次都要各种操作,合并来合并去,有点麻烦,哈哈,这点 Git Flow 早就想到了,为此还专门推出了一个 Git Flow 的工具,并且是开源的:

GitHub 开源地址:https://github.com/nvie/gitflow

简单点来说,就是这个工具帮我们省下了很多步骤,比如我们当前处于 master 分支,如果想要开发一个新的功能,第一步切换到 develop 分支,第二步新建一个以 feature 开头的分支名,有了 Git Flow 直接如下操作完成了:

git flow feature start A    

这个分支完成之后,需要合并到 develop 分支,然而直接进行如下操作就行:

git flow feature finish A    

如果是 hotfix 或者 release 分支甚至会自动帮你合并到 develop、master 两个分支。

8 发现优秀的开源项目

GitHub 其中一个最重要的作用就是发现全世界最优秀的开源项目,你没事的时候刷刷微博、知乎,人家没事的时候刷刷 GitHub ,看看最近有哪些流行的项目,久而久之,这差距就越来越大,那么如何发现优秀的开源项目呢?这篇文章我就来给大家介绍下。

1. 关注一些活跃的大牛

GitHub 主页有一个类似微博的时间线功能,所有你关注的人的动作,比如 star、fork 了某个项目都会出现在你的时间线上,这种方式适合我这种比较懒的人,不用主动去找项目,而这种基本是我每天获取信息的一个很重要的方式。

2. Trending

点击下图的 Explore 菜单到“发现”页面



这个 Trending 页面是干嘛的呢?直译过来就是趋势的意思,就是说这个页面你可以看到最近一些热门的开源项目,这个页面可以算是很多人主动获取一些开源项目最好的途径,可以选择「当天热门」、「一周之内热门」和「一月之内热门」来查看,并且还可以分语言类来查看,比如你想查看最近热门的 Android 项目,那么右边就可以选择 Java 语言。
这样页面推荐大家每隔几天就去看下,主动发掘一些优秀的开源项目。

3. Search

除了 Trending ,还有一种最主动的获取开源项目的方式,那就是 GitHub 的 Search 功能。

举个例子,你是做 Android 的,接触 GitHub 没多久,那么第一件事就应该输入 android 关键字进行搜索,然后右上角选择按照 star 来排序,结果如下图:


image.png

如果你是学习 iOS 的,那么不妨同样的方法输入 iOS 关键字看看结果:


image.png

可以看到按照 star 数,排名靠前基本是一些比较火的项目,一定是很有用,才会这么火。值得一提的是左侧依然可以选择语言进行过滤。

而对于实际项目中用到一些库,基本上都会第一时间去 GitHub 搜索下有没有类似的库,比如项目中想采用一个网络库,那么不妨输入 android http 关键字进行搜索,因为我只想找到关于 Android 的项目,所以搜索的时候都会加上 android 关键字,按照 star 数进行排序,我们来看下结果:
可以看到 Retrofit、OkHttp、android-async-http 是最流行的网络库,只不过 android-async-http 的作者不维护了,之前很多人问我网络库用哪个比较好?哪怕你对每个网络库都不是很了解,那么单纯的按照这种方式你都该优先选择 Retrofit 或者 OkHttp,而目前绝大部分 Android 开发者确实也都是在用这两个网络库,当然还有部分在用 Volley 的,因为 google 没有选择在 GitHub 开源 volley,所以搜不到 volley 的上榜。

除此之外,GitHub 的 Search 还有一些小技巧,比如你想搜索的结果中 star 数大于1000的,那么可以这样搜索:

android http stars:>1000

当然还有其他小技巧,但是我觉得不是很重要,就不多说了。

有些人如果习惯用 Google 进行搜索,那么想搜索 GitHub 上的结果,不妨前面加 GitHub 关键字就ok了,比如我在 google 里输入 GitHub android http ,每个关键字用空格隔开,然后搜索结果如下:


image.png

可以看到,基本也是我们想要的结果,只不过排序就不是单纯的按照 star 来排序了。

最后的福利

这个项目目前 star 数排名 GitHub 第三,总 star 数超过6w,这个项目整理了所有跟编程相关的免费书籍,而且全球多国语言版的都有,中文版的在这里:free-programm*ing-books-zh,有了这个项目,理论上你可以获取任何编程相关的学习资料,强烈推荐给你们!

GitHub 上有各种 awesome 系列,简单来说就是这个系列搜罗整理了 GitHub 上各领域的资源大汇总,比如有 awesome-android, awesome-ios, awesome-java, awesome-python 等等等,就不截图了,你们自行去感受。

GitHub 的使用有各种技巧,只不过基本的就够我们用了,但是如果你对 GitHub 超级感兴趣,想更多的了解 GitHub 的使用技巧,那么这个项目就刚好是你需要的,每个 GitHub 粉都应该知道这个项目。

推荐阅读更多精彩内容

  • Git 基础 基本原理 客户端并不是只提取最新版本的文件快照,而是把代码仓库完整的镜像下来。这样一来,任何一处协同...
    __silhouette阅读 11,210评论 5 137
  • 今天第一天开始上班,没有任务,于是开始学习Git这一程序猿必须掌握之技能,希望今天的积累过后,对与Git或者...
    CoderTung阅读 6,949评论 2 95
  • Git 命令行学习笔记 Git 基础 基本原理 客户端并不是只提取最新版本的文件快照,而是把代码仓库完整的镜像下来...
    sunnyghx阅读 2,394评论 0 11
  • 2017.12.17.第二次去学校游泳馆 脑子里总是会想起林俊杰的一句歌词“总是学不会....”好吧 咋们明年再来...
    西蒙oni阅读 27评论 0 0
  • 文/佩索阿 我什么都不是。 我将永远什么都不是。 我不能想要成为什么。 但我在我内部有这世界的所有的梦想。 我房间...
    Faker656阅读 107评论 0 0