Git的使用简介

简介

Git 是目前世界上最先进的分布式版本控制系统。对应的是以SVN为代表的集中式控制系统。

集中式(SVN) 分布式(Git)
是否有中央服务器 有。开发人员需要从中央服务器获得最新版本的项目然后在本地开发,开发完推送给中央服务器。因此脱离服务器开发者是几乎无法工作的 没有中央服务器,开发人员本地都有 Local Repository
网络依赖 必须要联网才能工作,而且对网络的依赖性较强,如果推送的文件比较大而且网络状况欠佳,则提交文件的速度会受到很大的限制。 分布式在没有网络的情况下也可以执行commit、查看版本提交记录、以及分支操作,在有网络的情况下执行 push 到 Remote Repository。
文件存储格式 按照原始文件存储,体积较大 按照元数据方式存储,体积很小
是否有版本号 没有
分支操作的影响 创建新的分支则所有的人都会拥有和你一样的分支 分支操作不会影响其他开发人员
提交 提交的文件会直接记录到中央版本库 提交是本地操作,需要执行push操作才会到主要版本库

安装

1
2
3
4
5
6
7
8
9
10
11
12
// 检查电脑是否安装 git (Mac OS)
$ git
// 以下信息提示未安装
The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git
// 如果显示以下信息,表示git已经安装过,可以直接使用
usage: git [--version] [--help] [-C <path>] [-c name=value]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p | --paginate | --no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
<command> [<args>]
...

使用Mac做开发,有两种安装Git的方法。

一是安装homebrew,然后通过homebrew安装Git,具体方法请参考homebrew的文档:http://brew.sh/

第二种方法更简单,也是推荐的方法,就是直接从AppStore安装Xcode,Xcode集成了Git,不过默认没有安装,你需要运行Xcode,选择菜单“Xcode”->“Preferences”,在弹出窗口中找到“Source Control”,选择安装。

创建版本库

版本库又名仓库,英文名repository,可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

1
2
3
4
5
6
7
// 先选择一个合适的文件夹(目录)
$ cd /Users/new/LearnGit
// 通过 git init 命令把这个目录变成Git可以管理的仓库
$ git init
// 下边信息表示版本库创建成功,第一行是创建一个空的库,第二行是已有的版本库重新初始化
Initialized empty Git repository in /Users/new/LearnGit/.git/
Reinitialized existing Git repository in /Users/new/LearnGit/.git/

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// 把修改的文件提交到仓库暂存区,可反复多次使用,添加多个文件
$ git add <fileName>
// 把文件提交到仓库
$ git commit -m "这些写提交描述"
// 查看仓库当前的状态
$ git status
// 对比修改
$ git diff <fileName>

// 查看版本控制系统历史记录
$ git log
$ git log --pretty=oneline
$ git log --graph --pretty=oneline --abbrev-commit
// 查看每次命令记录
$ git reflog

// 版本回退
$ git reset --hard HEAD^ // 回退到上个版本
$ git reset --hard 1094a // 会退到指定版本
// 丢弃工作区的修改, 让这个文件回到最近一次git commit或git add时的状态
$ git checkout -- <fileName>
// 删除文件
$ git rm <fileName>

// 创建SSH Key (在用户主目录下,看看有没有.ssh(隐藏文件,使用 com + shift + . 显示)目录,如果有,再看看这个目录下有没有id_rsa和id_rsa.pub这两个文件,如果没有则需要创建)
$ ssh-keygen -t rsa -C "自己的邮件地址"

// 关联远程库,远程库的名字默认是 origin
$ git remote add origin git@server-name:path/repo-name.git
// 把本地库的所有内容推送到远程库(把当前分支master推送到远程,第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来)
$ git push -u origin master
$ git push origin master
// 当你第一次使用Git的clone或者push命令连接GitHub时,会得到一个警告:这是因为Git使用SSH连接,而SSH连接在第一次验证GitHub服务器的Key时,需要你确认GitHub的Key的指纹信息是否真的来自GitHub的服务器,输入yes回车即可。
The authenticity of host 'github.com (xx.xx.xx.xx)' can't be established.
RSA key fingerprint is xx.xx.xx.xx.xx.
Are you sure you want to continue connecting (yes/no)?
// Git会输出一个警告,告诉你已经把GitHub的Key添加到本机的一个信任列表里了。警告只会出现一次,后面的操作就不会有任何警告了
Warning: Permanently added 'github.com' (RSA) to the list of known hosts.

// 从远程库克隆一个本地库
$ git clone git@server-name:path/repo-name.git
// 例如 $ git clone git@github.com:michaelliao/gitskills.git
// 还可以使用
$ git clone https://github.com/michaelliao/gitskills.git

// 查看远程库的信息
$ git remote
origin
// 显示更详细的信息
$ git remote -v
// 显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)
// 推送分支。推送时,指定本地分支,Git就会把该分支推送到远程库对应的远程分支上:
$ git push origin master
$ git push origin dev
// 如果推送失败 先抓取远程的新提交
$ git pull
// 在本地创建和远程分支对应的分支,本地和远程分支的名称最好一致
$ git checkout -b branch-name origin/branch-name
// 建立本地分支和远程分支的关联
$ git branch --set-upstream branch-name origin/branch-name

/*
并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?
master 分支是主分支,因此要时刻与远程同步;
dev 分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
bug 分支只用于在本地修复bug,就没必要推到远程了,除非有特殊要求,如老板要看每周到底修复了几个bug;
feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。*/


// 分支管理
// 创建分支
$ git branch <name>
// 切换分支
$ git checkout <name>
// 等价于 创建 + 切换到分支
$ git checkout -b <name>
Switched to a new branch 'dev'

// 查看当前分支,命令会列出所有分支,当前分支前面会标一个*号。
$ git branch
* dev
master

// 合并指定分支到当前分支,例如 把 dev 合并到 master 上,需要在 master 上操作
$ git merge dev
// 合并方式
// Fast forward 快速合并 删除分支后,会丢掉分支信息
// --no-ff 表示禁用Fast forward,合并要创建一个新的commit,所以加上-m参数,把commit描述写进去
$ git merge --no-ff -m "merge with no-ff" dev
// 合并后的分支图
// $ git log --graph --pretty=oneline --abbrev-commit
// * e1e9c68 (HEAD -> master) merge with no-ff
// |\
// | * f52c633 (dev) add merge
// |/
// * cf810e4 conflict fixed
// ...

// 删除分支
$ git branch -d <name>
// 强行删除分支,丢弃一个没有被合并过的分支时使用
$ git branch -D <name>

/* 分支策略
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,master 分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;
那在哪干活呢?干活都在 dev 分支上,也就是说,dev 分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到 master 上,在 master 分支发布1.0版本;
你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。*/

// 贮藏功能,存储当前工作区的修改,清空工作区
$ git stash
// 查看 贮藏 列表
$ git stash list
// 恢复 贮藏的工作区
$ git stash apply // 恢复后,stash内容并不删除
$ git stash pop // 恢复后,删除 stash 内容
$ git stash apply stash@{0} // 恢复到指定 stash
// 删除 stash
git stash drop

// rebase 操作可以把本地未push的分叉提交历史整理成直线;
// rebase 的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比
$ git rebase

// 打标签
$ git tag v1.0
// 查看所有标签
$ git tag
$ git tag v0.9 f52c633
// 创建带有说明的标签,用-a指定标签名,-m指定说明文字
$ git tag -a v0.1 -m "version 0.1 released" 1094adb
// 查看标签信息
$ git show v0.9
// 删除标签
$ git tag -d v0.1
// 推送某个标签到远程
$ git push origin v1.0
// 一次性推送全部尚未推送到远程的本地标签
$ git push origin --tags
// 标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除,然后,从远程删除
$ git tag -d v0.9
$ git push origin :refs/tags/v0.9

自定义设置

1
2
3
4
5
6
7
8
// Git显示颜色
$ git config --global color.ui true
// 给一个命令配置别名。如 status 写成 st
$ git config --global alias.st status
// 修改撤销 reset HEAD 可以设置成 unstage
$ git config --global alias.unstage 'reset HEAD'

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

在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。.gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理

忽略文件的原则是:

  1. 忽略操作系统自动生成的文件,比如缩略图等;
  2. 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
  3. 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。

配置Git的时候,加上--global是针对当前用户起作用的,如果不加,那只针对当前的仓库起作用。

每个仓库的Git配置文件都放在.git/config文件中:

别名就在[alias]后面,要删除别名,直接把对应的行删掉即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ cat .git/config 
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = git@github.com:michaelliao/learngit.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
[alias]
last = log -1

而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中:

1
2
3
4
5
6
7
8
9
$ cat .gitconfig
[alias]
co = checkout
ci = commit
br = branch
st = status
[user]
name = Your Name
email = your@email.com

参考链接