linux-tutorial/docs/git/git-quickstart.md

532 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
title: git 快速指南
date: 2017-12-06
categories:
- linux
tags:
- linux
- vcs
- git
---
## 简介
### Git 是什么?
Git 是一个开源的分布式版本控制系统。
### 什么是版本控制?
版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。
### 什么是分布式版本控制系统?
介绍分布式版本控制系统前,有必要先了解一下传统的集中式版本控制系统。
**集中化的版本控制系统**,诸如 CVSSubversion 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。
这么做最显而易见的缺点是中央服务器的单点故障。如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。要是中央服务器的磁盘发生故障,碰巧没做备份,或者备份不够及时,就会有丢失数据的风险。最坏的情况是彻底丢失整个项目的所有历史更改记录。
![img](https://git-scm.com/figures/18333fig0102-tn.png)
**分布式版本控制系统**的客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份。
![img](https://git-scm.com/figures/18333fig0103-tn.png)
### 为什么使用 Git
Git 是分布式的。这是 Git 和其它非分布式的版本控制系统,例如 svncvs 等,最核心的区别。分布式带来以下好处:
**工作时不需要联网**
首先分布式版本控制系统根本没有“中央服务器”每个人的电脑上都是一个完整的版本库这样你工作的时候就不需要联网了因为版本库就在你自己的电脑上。既然每个人电脑上都有一个完整的版本库那多个人如何协作呢比方说你在自己电脑上改了文件A你的同事也在他的电脑上改了文件A这时你们俩之间只需把各自的修改推送给对方就可以互相看到对方的修改了。
**更加安全**
集中式版本控制系统,一旦中央服务器出了问题,所有人都无法工作。
分布式版本控制系统,每个人电脑中都有完整的版本库,所以某人的机器挂了,并不影响其它人。
## 原理
### 版本库
当你一个项目到本地或创建一个 git 项目,项目目录下会有一个隐藏的 `.git` 子目录。这个目录是 git 用来跟踪管理版本库的,千万不要手动修改。
### 哈希值
Git 中所有数据在存储前都计算校验和,然后以校验和来引用。 这意味着不可能在 Git 不知情时更改任何文件内容或目录内容。 这个功能建构在 Git 底层,是构成 Git 哲学不可或缺的部分。 若你在传送过程中丢失信息或损坏文件Git 就能发现。
Git 用以计算校验和的机制叫做 SHA-1 散列hash哈希。 这是一个由 40 个十六进制字符0-9 和 a-f组成字符串基于 Git 中文件的内容或目录结构计算出来。 SHA-1 哈希看起来是这样:
```
24b9da6552252987aa493b52f8696cd6d3b00373
```
Git 中使用这种哈希值的情况很多,你将经常看到这种哈希值。 实际上Git 数据库中保存的信息都是以文件内容的哈希值来索引,而不是文件名。
### 文件状态
在 GIt 中,你的文件可能会处于三种状态之一:
- **已修改modified**
已修改表示修改了文件,但还没保存到数据库中。
- **已暂存staged**
已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
- **已提交committed**
已提交表示数据已经安全的保存在本地数据库中。 
### 工作区域
与文件状态对应的,不同状态的文件在 Git 中处于不同的工作区域。
- **工作区working**
当你 `git clone` 一个项目到本地,相当于在本地克隆了项目的一个副本。
工作区是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。
- **暂存区staging**
暂存区是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。 有时候也被称作`‘索引’',不过一般说法还是叫暂存区。
- **本地仓库local**
提交更新,找到暂存区域的文件,将快照永久性存储到 Git 本地仓库。
- **远程仓库remote**
以上几个工作区都是在本地。为了让别人可以看到你的修改,你需要将你的更新推送到远程仓库。
同理,如果你想同步别人的修改,你需要从远程仓库拉取更新。
![git-theory.png](http://oyz7npk35.bkt.clouddn.com//image/linux/git/git-theory.png)
## 安装
### Linux
#### Debian/Ubuntu
如果你使用的系统是 Debian/Ubuntu 安装命令为:
```sh
$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
> libz-dev libssl-dev
$ apt-get install git-core
$ git --version
git version 1.8.1.2
```
#### Centos/RedHat
如果你使用的系统是 Centos/RedHat ,安装命令为:
```sh
$ yum install curl-devel expat-devel gettext-devel \
> openssl-devel zlib-devel
$ yum -y install git-core
$ git --version
git version 1.7.1
```
### Windows
在[Git 官方下载地址](https://git-scm.com/downloads)下载 exe 安装包。按照安装向导安装即可。
建议安装 Git Bash 这个 git 的命令行工具。
### Mac
在[Git 官方下载地址](https://git-scm.com/downloads)下载 mac 安装包。按照安装向导安装即可。
## 配置
Git 自带一个 `git config` 的工具来帮助设置控制 Git 外观和行为的配置变量。 这些变量存储在三个不同的位置:
1. `/etc/gitconfig` 文件: 包含系统上每一个用户及他们仓库的通用配置。 如果使用带有 `--system` 选项的 `git config` 时,它会从此文件读写配置变量。
2. `~/.gitconfig` 或 `~/.config/git/config` 文件:只针对当前用户。 可以传递 `--global` 选项让 Git 读写此文件。
3. 当前使用仓库的 Git 目录中的 `config` 文件(就是 `.git/config`):针对该仓库。
每一个级别覆盖上一级别的配置,所以 `.git/config` 的配置变量会覆盖 `/etc/gitconfig` 中的配置变量。
在 Windows 系统中Git 会查找 `$HOME` 目录下(一般情况下是 `C:\Users\$USER`)的 `.gitconfig` 文件。 Git 同样也会寻找 `/etc/gitconfig` 文件,但只限于 MSys 的根目录下,即安装 Git 时所选的目标位置。
### 用户信息
当安装完 Git 应该做的第一件事就是设置你的用户名称与邮件地址。 这样做很重要,因为每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改:
```
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
```
再次强调,如果使用了 `--global` 选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息。 当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 `--global` 选项的命令来配置。
很多 GUI 工具都会在第一次运行时帮助你配置这些信息。
### .gitignore
`.gitignore` 文件可能从字面含义也不难猜出:这个文件里配置的文件或目录,会自动被 git 所忽略,不纳入版本控制。
在日常开发中,我们的项目经常会产生一些临时文件,如编译 Java 产生的 `*.class` 文件,又或是 IDE 自动生成的隐藏目录Intellij 的 `.idea` 目录、Eclipse 的 `.settings` 目录等)等等。这些文件或目录实在没必要纳入版本管理。在这种场景下,你就需要用到 `.gitignore` 配置来过滤这些文件或目录。
配置的规则很简单,也没什么可说的,看几个例子,自然就明白了。
这里推荐一下 Github 的开源项目https://github.com/github/gitignore
在这里你可以找到很多常用的模板Java、Nodejs、C++ 的 `.gitignore` 模板等等。
## 命令
国外网友制作了一张 Git Cheat Sheet总结很精炼各位不妨收藏一下。
本节选择性介绍 git 中比较常用的命令行场景。
![git-cheat-sheet.png](http://oyz7npk35.bkt.clouddn.com//image/linux/git/git-cheat-sheet.png)
### 创建
#### 克隆一个已创建的仓库
```sh
# 通过 SSH
$ git clone ssh://user@domain.com/repo.git
#通过 HTTP
$ git clone http://domain.com/user/repo.git
```
#### 创建一个新的本地仓库
```sh
$ git init
```
### 添加修改
#### 添加修改到暂存区
```sh
# 把指定文件添加到暂存区
$ git add xxx
# 把当前所有修改添加到暂存区
$ git add .
# 把所有修改添加到暂存区
$ git add -A
```
#### 提交修改到本地仓库
```sh
# 提交本地的所有修改
$ git commit -a
# 提交之前已标记的变化
$ git commit
# 附加消息提交
$ git commit -m 'commit message'
```
#### 储藏
有时,我们需要在同一个项目的不同分支上工作。当需要切换分支时,偏偏本地的工作还没有完成,此时,提交修改显得不严谨,但是不提交代码又无法切换分支。这时,你可以使用 `git stash` 将本地的修改内容作为草稿储藏起来。
官方称之为储藏,但我个人更喜欢称之为存草稿。
```sh
# 1. 将修改作为当前分支的草稿保存
$ git stash
# 2. 查看草稿列表
$ git stash list
stash@{0}: WIP on master: 6fae349 :memo: Writing docs.
# 3.1 删除草稿
$ git stash drop stash@{0}
# 3.2 读取草稿
$ git stash apply stash@{0}
```
### 撤销修改
#### 撤销本地修改
```sh
# 移除缓存区的所有文件i.e. 撤销上次git add
$ git reset HEAD
# 将HEAD重置到上一次提交的版本并将之后的修改标记为未添加到缓存区的修改
$ git reset <commit>
# 将HEAD重置到上一次提交的版本并保留未提交的本地修改
$ git reset --keep <commit>
# 放弃工作目录下的所有修改
$ git reset --hard HEAD
# 将HEAD重置到指定的版本并抛弃该版本之后的所有修改
$ git reset --hard <commit-hash>
# 用远端分支强制覆盖本地分支
$ git reset --hard <remote/branch> e.g., upstream/master, origin/my-feature
# 放弃某个文件的所有本地修改
$ git checkout HEAD <file>
```
##### 删除添加`.gitignore`文件前错误提交的文件
```sh
$ git rm -r --cached .
$ git add .
$ git commit -m "remove xyz file"
```
#### 撤销远程修改
#### 创建一个新的提交,并回滚到指定版本
```sh
$ git revert <commit-hash>
```
#### 彻底删除指定版本
```sh
# 执行下面命令后commit-hash 提交后的记录都会被彻底删除,使用需谨慎
$ git reset --hard <commit-hash>
$ git push -f
```
### 更新与推送
#### 更新
```sh
# 下载远程端版本但不合并到HEAD中
$ git fetch <remote>
# 将远程端版本合并到本地版本中
$ git pull origin master
# 以rebase方式将远端分支与本地合并
$ git pull --rebase <remote> <branch>
```
#### 推送
```sh
# 将本地版本推送到远程端
$ git push remote <remote> <branch>
# 删除远程端分支
$ git push <remote> :<branch> (since Git v1.5.0)
$ git push <remote> --delete <branch> (since Git v1.7.0)
# 发布标签
$ git push --tags
```
### 查看信息
#### 显示工作路径下已修改的文件
```sh
$ git status
```
#### 显示与上次提交版本文件的不同
```sh
$ git diff
```
#### 显示提交历史
```sh
# 从最新提交开始显示所有的提交记录显示hash 作者信息,提交的标题和时间)
$ git log
# 显示某个用户的所有提交
$ git log --author="username"
# 显示某个文件的所有修改
$ git log -p <file>
```
#### 显示搜索内容
```sh
# 从当前目录的所有文件中查找文本内容
$ git grep "Hello"
# 在某一版本中搜索文本
$ git grep "Hello" v2.5
```
### 分支与标签
#### 增删查分支
```sh
# 列出所有的分支
$ git branch
# 列出所有的远端分支
$ git branch -r
# 基于当前分支创建新分支
$ git branch <new-branch>
# 基于远程分支创建新的可追溯的分支
$ git branch --track <new-branch> <remote-branch>
# 删除本地分支
$ git branch -d <branch>
# 强制删除本地分支,将会丢失未合并的修改
$ git branch -D <branch>
```
#### 切换分支
```sh
# 切换分支
$ git checkout <branch>
# 创建并切换到新分支
$ git checkout -b <branch>
```
#### 标签
```sh
# 给当前版本打标签
$ git tag <tag-name>
# 给当前版本打标签并附加消息
$ git tag -a <tag-name>
```
### 合并与重置
> merge 与 rebase 虽然是 git 常用功能,但是强烈建议不要使用 git 命令来完成这项工作。
>
> 因为如果出现代码冲突,在没有代码比对工具的情况下,实在太艰难了。
>
> 你可以考虑使用各种 Git GUI 工具。
#### 合并
```sh
# 将分支合并到当前HEAD中
$ git merge <branch>
```
#### 重置
```sh
# 将当前HEAD版本重置到分支中请勿重置已发布的提交
$ git rebase <branch>
```
### Github
Github 作为最著名的代码开源协作社区,在程序员圈想必无人不知,无人不晓。
这里不赘述 Github 的用法确实有不会用的新手同学可以参考官方教程https://guides.github.com/
#### clone 方式
Git 支持三种协议HTTPS / SSH / GIT
而 Github 上支持 HTTPS 和 SSH。
HTTPS 这种方式要求你每次 push 时都要输入用户名、密码,有些繁琐。
而 SSH 要求你本地生成证书,然后在你的 Github 账户中注册。第一次配置麻烦是麻烦了点,但是以后就免去了每次 push 需要输入用户名、密码的繁琐。
![image.png](http://upload-images.jianshu.io/upload_images/3101171-66f60822aeb2c21c.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
以下介绍以下,如何生成证书,以及在 Github 中注册。
#### 生成 SSH 公钥
如前所述,许多 Git 服务器都使用 SSH 公钥进行认证。 为了向 Git 服务器提供 SSH 公钥,如果某系统用户尚未拥有密钥,必须事先为其生成一份。 这个过程在所有操作系统上都是相似的。 首先,你需要确认自己是否已经拥有密钥。 默认情况下,用户的 SSH 密钥存储在其 `~/.ssh` 目录下。 进入该目录并列出其中内容,你便可以快速确认自己是否已拥有密钥:
```
$ cd ~/.ssh
$ ls
authorized_keys2 id_dsa known_hosts
config id_dsa.pub
```
我们需要寻找一对以 `id_dsa` 或 `id_rsa` 命名的文件,其中一个带有 `.pub` 扩展名。 `.pub` 文件是你的公钥,另一个则是私钥。 如果找不到这样的文件(或者根本没有 `.ssh` 目录),你可以通过运行 `ssh-keygen` 程序来创建它们。在 Linux/Mac 系统中,`ssh-keygen` 随 SSH 软件包提供;在 Windows 上,该程序包含于 MSysGit 软件包中。
```
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/schacon/.ssh/id_rsa):
Created directory '/home/schacon/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/schacon/.ssh/id_rsa.
Your public key has been saved in /home/schacon/.ssh/id_rsa.pub.
The key fingerprint is:
d0:82:24:8e:d7:f1:bb:9b:33:53:96:93:49:da:9b:e3 schacon@mylaptop.local
```
首先 `ssh-keygen` 会确认密钥的存储位置(默认是 `.ssh/id_rsa`),然后它会要求你输入两次密钥口令。如果你不想在使用密钥时输入口令,将其留空即可。
现在,进行了上述操作的用户需要将各自的公钥发送给任意一个 Git 服务器管理员(假设服务器正在使用基于公钥的 SSH 验证设置)。 他们所要做的就是复制各自的 `.pub` 文件内容,并将其通过邮件发送。 公钥看起来是这样的:
```
$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFi9wrf+M7Q== schacon@mylaptop.local
```
在你的 Github 账户中,依次点击 **Settings** > **SSH and GPG keys** > **New SSH key**
然后,将上面生成的公钥内容粘贴到 `Key` 编辑框并保存。至此大功告成。
后面,你在克隆你的 Github 项目时使用 SSH 方式即可。
![The key field](https://help.github.com/assets/images/help/settings/ssh-key-paste.png)
如果觉得我的讲解还不够细致可以参考https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/
## 小结
最后,放一张我总结的脑图总结一下以上的知识点。
![Git.png](http://upload-images.jianshu.io/upload_images/3101171-2044cc669d78eef9.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
## 资料
[git 官网](https://git-scm.com/) | [git 官方 Github](https://github.com/git/git)
[廖雪峰的 git 教程](https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)
[git-cheat-sheet](https://github.com/arslanbilal/git-cheat-sheet)
[github-cheat-sheet](https://github.com/tiimgreen/github-cheat-sheet)
[Github gitignore 模板](https://github.com/github/gitignore)