虽然很早就接触github,但对git的版本控制并不了解,最近开始学习使用git,对其使用简单做一些整理。

git 介绍

Git是一个开源的分布式版本控制系统,用以有效、高速的处理从很小到非常大的项目版本管理。关于她的特点Git官网是这么介绍的:

Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.

总之,对于开源项目来说,使用Git可以极大地提高了开发效率、扩大了开源项目的参与度、 增强了版本控制系统的安全性,选择Git已是大势所趋。

以下为本人学习git过程中的一些练习和笔记,相关参考:廖雪峰的Git教程

git 本地仓库常用操作

git 创建本地仓库

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
$ mkdir learngit  //创建文件夹  
$ cd learngit  
$ pwd   //查看当前目录  
/Users/michael/learngit

$ git init //将当前文件夹变成git仓库,init后目录下会多出.git文件(默认隐藏) 可以用ls -ah查看  
Initialized empty Git repository in /Users/michael/learngit/.git/

$ git log //显示从最近到最远的提交日志 如果出现end标记可以按q退出历史记录列表  
$ git log --pretty=oneline

$ git reset --hard HEAD^  //回退上个版本  

Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100^比较容易数不过来,所以写成HEAD~100

回退后又想恢复怎么办?

1
2
3
4
5
6
7
8
$ git reset --hard commit_id //即可,但是怎么知道上次回滚的commit_id呢?  
$ git reflog  
289f53a [email protected]{0}: reset: moving to HEAD^  
ba423b7 [email protected]{1}: commit: add a line  
289f53a [email protected]{2}: commit: add file test.txt  
0aa4371 [email protected]{3}: commit: create new file  
339d5bb [email protected]{4}: commit: add a line  
906ce38 [email protected]{5}: commit (initial): add file readme.txt 

git reflog可以查看命令历史,于是我们知道 add a linecommit_idba423b7

git 的撤销修改

1,如果只是在本地做了一些修改,没有执行commit也没有add操作,使用git status可以看到红色字体提示 modified: <file> 这时如果不想保存本地修改,即丢弃工作区修改,直接执行git checkout -- <file>即可(git status有提示)
2,如果已经执行了add还没有commit想回滚,可以执行$ git reset HEAD readme.txt将暂存区修改内容回退到工作区,如果还想撤回本地修改,执行步骤1即可
3,如果已经commit,想回滚到之前的某个版本
​ 执行$ git reset --hard HEAD^ //回退上个版本
​ 在Git中,用HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。

小结:
场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file
场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。
场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。

git 远程仓库

git 远程仓库基本操作

以上所讲只是在一个本地仓库里管理文件历史,我们知道git是一个分布式的版本控制系统,即同一个git仓库可以分布在不同的服务器上,很庆幸github这个网站便可以提供免费的仓库托管服务。

先在github上注册账号登陆后Create a new repo新建一个仓库,例如learngit,于是便在github上新建了一个空仓库
$ git remote add origin https://github.com/jiwenxing/learngit.git
添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

执行$ git push -u origin master输入用户名和密码即可将本地库的内容推送到远程github仓库, 其中-u参数只在第一次提交时使用,表示将本地master分支和远程master分支相关联,再提交时只需执行
$ git push origin master
如果报错让你先fetch,可以强制推送:
$ git push -u origin master --force

注意:
Git支持多种协议,包括sshhttps
ssh路径: [email protected]:jiwenxing/learngit.git
https路径: https://github.com/jiwenxing/learngit.git
通过ssh支持的原生git协议速度最快。但是在某些特定环境ssh端口被封掉时可以采用https,唯一不便的是每次提交都需要输入一下用户名和密码!

git 从远程仓库 clone

1
git clone https://github.com/h5bp/html5-boilerplate.git

git 分支管理

git创建并切换到新分支

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[email protected] /d/git/learngit (master)
$ git branch dev  //创建新分支

[email protected] /d/git/learngit (master)
$ git branch
  dev
* master   //*代表当前分支

[email protected] /d/git/learngit (master)
$ git checkout dev  //切换分支
Switched to branch 'dev'

[email protected] /d/git/learngit (dev)
$ git branch
* dev
  master

下面我在dev分支下对文件test.txt添加一行内容后执行add commit操作后,再次切换到master分支,你会发现刚才做的修改没有了。 也就是说刚才的修改只是针对dev分支,对master分支没有影响。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[email protected] /d/git/learngit (dev)
$ git checkout master  //切回到主分支
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

[email protected] /d/git/learngit (master)
$ git merge dev  //将dev分支合并到当前master主分支
Updating daf105e..b563da8
Fast-forward
 test.txt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

[email protected] /d/git/learngit (master)
$ git branch -d dev //此时可以删除dev分支
Deleted branch dev (was b563da8).

[email protected] /d/git/learngit (master)
$ git branch
* master

可以看到上面我们将dev分支合并到了当前master分支后再去看test.txt文件,发现刚才做的修改又出现了,这时便可以放心大胆的删除dev分支了。

小结

  • 查看分支:git branch
  • 创建分支:git branch <name>
  • 切换分支:git checkout <name>
  • 创建+切换分支:git checkout -b <name>
  • 合并某分支到当前分支:git merge <name>
  • 删除分支:git branch -d <name>

git 分支冲突

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ git checkout -b feature1  //创建并切换到新分支,并对test文件做修改
fatal: A branch named 'feature1' already exists.
$ git add test.txt  
$ git commit -m "conflict -and"  //在新分支下提交更改
 feature1 651c38a] conflict -and  
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git checkout master  //切回到master分支,对test文件做不同的更改
README.MD  
Switched to branch 'master'  
Your branch is up-to-date with 'origin/master'.  
$ git add test.txt  
$ git commit -m "conflict -&"  //在master下提交更改
 master 0dc1bd3] conflict -&  
 1 file changed, 1 insertion(+), 1 deletion(-)  
$ git merge feature1  //在master分支下合并feature1分支上的更改,显示冲突
CONFLICT (content): Merge conflict in test.txt  
Automatic merge failed; fix conflicts and then commit the result.

在不同分支上对同一文件分别做了不同的更改,合并分支的时候就会报冲突,而这时test.txt文件的内容也变成了如下:

1
2
3
4
5
6
7
8
I am totoro~
who are you?
I am totoro~
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature1

Git<<<<<<<=======>>>>>>>标记出不同分支的差异内容,<<<<<<<标记冲突开始,后面跟的是当前分支中的内容。HEAD指向当前分支末梢的提交。=======之后,>>>>>>>之前是要merge过来的另一条分支上的代码。>>>>>>>之后的feature1是该分支的名字。

手动在文件中将差异内容做一下修改,再次addcommit即可解决冲突,完事还可以查看分支的合并情况:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$ git log --graph --pretty=oneline --abbrev-commit
7f9c092 conflict solved
 \
  * 651c38a conflict -and
  | 0dc1bd3 conflict -&
 /
  cfb3522 readme revise4
  b563da8 branch test
  daf105e readme revise3
  002f01d revise2 readme.md
  5697575 revise readme.md
  28d49b7 add a pic
  ca373c6 add two files

注意:
合并分支指令$ git merge feature1默认使用的是fast forward模式,这样合并并不记录合并历史,而使用指令$ git merge --no-ff -m "merge with no-ff" dev则是使用普通模式合并代码,合并后有历史记录,建议采用后一种。

git 分支管理策略

注:该部分内容参考自文章《Git 分支管理详解》

团队开发中应该如何充分应用git的分支功能呢,通常一个项目较为规范的分支策略如下:

  • 主分支master:代码库应该有一个、且仅有一个主分支。所有提供给用户使用的正式版本,都在这个主分支上发布。
  • 开发分支dev:进行日常开发工作,这个分支可以用来生成代码的最新代码版本。如果想正式对外发布,就在Master分支上,对Dev分支进行”合并”。

  • 功能分支feature:开发某种特定功能,从Dev分支上面分出来的;开发完成后,要再并入Dev
  • 预发布分支release:预发布分支,它是指发布正式版本之前(即合并到Master分支之前),我们可能需要有一个预发布的版本进行测试。预发布分支是从Develop分支上面 分出来的,预发布结束以后,必须合并进DevMaster分支。
  • bug分支fixbug:软件正式发布以后,难免会出现bug。这时就需要创建一个分支,进行bug修补。修补bug分支是从Master分支上面分出来的。修补结束以后,再合并进MasterDev分支。

使用github参与开源项目

访问自己感兴趣的项目主页(例如bootstrap项目https://github.com/twbs/bootstrap), 点右上角的“Fork”就在自己的账号下克隆了一个bootstrap仓库,然后,从自己的账号下clone

1
git clone https://github.com/jiwenxing/bootstrap.git

注意 只有从自己的账号下clone仓库,才能推送修改。
如果你想修复bootstrap的一个bug,或者新增一个功能,立刻就可以开始干活,干完后,往自己的仓库推送。如果你希望bootstrap的官方库能接受你的修改,你就可以在GitHub上发起一个pull request

小结:

  • GitHub上,可以任意Fork开源仓库;
  • 自己拥有Fork后的仓库的读写权限;
  • 可以推送pull request给官方仓库来贡献代码。

结语

虽然很久之前就开始用github,并在上面搭建了博客,但是从没用过其版本控制功能,很多东西也没有完全搞明白,希望在以后的工作中慢慢用起来,后面也会根据自己的实际应用进行更新。