一, 了解 Git
1,Git 是什么?
Git 是目前世界上最先进的分布式版本控制系统 (没有之一), 由 Linus 公司(创建了开源的 Linux) 开发而成.
2, 分布式版本控制系统是什么意思? 具体表现在哪?
Git 就是分布式管理系统, 于其对应的集中式版本控制系统有 SVN, 简单的说, 分布式的版本控制就是每个人都可以创建一个独立的代码仓库, 用于管理, 各种版本控制的操作都可以在本地完成, 每个人修改的代码都可以合并推送到另一个代码仓库中.
而像 SVN 这样, 只有一个中央服务器, 所有的开发人员都必须依赖与这个代码仓库, 每次版本控制的操作也必须连接到服务器才能完成, 很多公司喜欢用集中式的版本控制是为了更好的控制代码, 如果个人开发, 一般选择 Git 这种分布式系统.
3,Git 的作用?
举个例子: 如果你使用 Word 文件编写一个东西的时候, 肯定有这样一个经历, 想要删除一个段落, 但是想要恢复删除的段落, 又怕找不回来了, 这时候你可能会将这个文件另存一份, 然后接着改, 改到一定程度, 又接着改, 如果一直这样下去, 可能你满桌面都是个 Word 文档的修改版, 等过了一周你想要找回被是删除的文字, 但是已经记不清楚删除前保存在哪个文件里面了, 只好一个一个去找, 这就比较麻烦了.
于是你想, 如果有一个软件, 不但能自动帮我记录每次文件的改动, 还可以让同事协作编辑, 这样就不用自己管理一堆类似的文件了, 也不需要把文件传来传去. 如果想查看某次改动, 只需要在软件里看一眼就可以了, 岂不是很方便?
这个软件看起来应该像这样子, 能记录每次文件的改动:
4, 集中式和分布式?
Linus 一直痛恨的 CVS 及 SVN 都是集中式的版本控制系统, 而 Git 是分布式版本控制系统, 集中式和分布式版本控制系统有什么区别呢?
集中式版本控制系统:
版本库是集中存放在中央服务器的, 而干活的时候, 用的都是自己的电脑, 所以要先从中央服务器取得最新的版本, 然后开始干活, 干完活了, 再把自己的活推送给中央服务器. 中央服务器就好比是一个图书馆, 你要先从图书馆借出来, 然后回到家自己改, 改完了, 再放回图书馆.
集中式版本控制系统的缺点:
集中式版本控制系统最大的毛病就是必须联网才能工作, 如果在局域网内还好, 带宽够大, 速度够快, 可如果在互联网上, 遇到网速慢的话, 可能提交一个 10M 的文件就需要 5 分钟, 那肯定是无法接受的.
分布式版本控制系统:
分布式版本控制系统根本没有 "中央服务器", 每个人的电脑上都是一个完整的版本库, 这样, 你工作的时候, 就不需要联网了, 因为版本库就在自己的电脑上. 既然每个人电脑上都有一个完整的版本库, 那多个人如何协作呢? 比如说你在自己电脑上改了文件 A, 你的同事也在他的电脑上改了文件 A, 这时, 你们俩之前只需把各自的修改推送给对方, 就可互相看到对方的修改了.
和集中式版本控制系统相比, 分布式版本控制系统的安全性要高很多, 因为每个人电脑里都有一个完整的版本库, 某一个人的电脑坏掉了不要紧, 随便从其他人那里复制一个就可以了. 而集中式版本控制系统的中央服务器要是出了问题, 那么所有员工都无法工作了.
在实际使用分布式版本控制系统的时候, 其实很少在两个人之间的电脑上推送版本库的修改, 因为可能你们俩不在一个局域网内, 两台电脑互相访问不了, 也可能今天你的同事病了, 他的电脑压根就没有开机. 因此, 分布式版本控制系统通常也有一台充当 "中央服务器" 的电脑, 但这个服务器的作用仅仅是用来方便 "交换" 大家的修改, 没有它也一样干活, 只是交换修改不方便而已.
当然, Git 的优势不单是不必联网这个简单, 后面我们还会看到 Git 极其强大的分支管理, 把 SVN 等集中式控制系统远远抛在了后边.
总结:
集中式版本控制系统(CVS,SVN 等): 有一个中央服务器, 需要在联网的的情况下才能使用, 上传速度慢, 如果中央服务器挂掉, 将无法工作.
分布式版本控制系统(Git): 无须中央服务器, 每个人的电脑上都有一个版本库, 安全性高, 上传速度快, 并且具有强大的分支管理.
二, 安装并使用 Git
1, 安装 Git
最早 Git 是在 Linux 上开发的, 很长一段时间内, Git 也只能在 Linux 和 Unix 系统上跑. 不过, 慢慢地有人把它移植到了 Windows 上, 现在, Git 可以在 Linux,Unix,Mac 和 Windows 这几大平台上正常运行.
[[email protected] ~]$ sudo yum -y install Git
安装完成后, 还需要最后一步配置, 在命令行输入:
- [[email protected] ~]$ Git config --global user.name "jonson"
- [[email protected] ~]$ Git config --global user.email "xxxxxxx.163.com"
因为 Git 是分布式版本控制系统, 所以, 每个机器都必须自报家门:"你的名字和 Email 地址".
注意: Git config 命令的 --global 参数, 用来和这个参数, 表示你这台机器上所有的 Git 仓库都会使用这个配置, 当然也可以对某个仓库指定不同的用户名和 Email 地址.
2, 创建版本库
什么是版本库呢? 版本库又名仓库(repository), 你可以简单理解成一个目录, 这个目录里面的所有文件都可以被 Git 管理起来, 每个文件的修改, 删除, Git 都能跟踪, 以便任何时候都可以追踪历史, 或者在将来某个时刻可以 "还原".
- # 首先, 创建一个目录用作版本库:
- [[email protected] ~]$ mkdir mygit
- [[email protected] ~]$ cd mygit/
- # 将目录变成 Git 管理的仓库(初始化 Git 仓库)
- [[email protected] mygit]$ Git init
- Initialized empty Git repository in /home/jonson/mygit/.Git/
- [[email protected] mygit]$ ls -a
. .. .Git
3, 将文件添加到版本库
- # 创建一个名为 "test" 的文件
- [[email protected] mygit]$ echo "test1 git"> test.txt
- [[email protected] mygit]$ cat test.txt
- test1 Git
- // 注意: 文件一定要放在当前目录下(子目录也行), 因为这个一个 Git 仓库, 否则将无法找到该文件.
把一个文件存放到 Git 仓库需要两步
- # 第一步, 用命令 `git add` 告诉 Git, 把文件添加到仓库:
- [[email protected] mygit]$ Git add test.txt
- # 第二步, 用命令 `git commit ` 告诉 Git, 把文件提交到仓库:
- [[email protected] mygit]$ Git commit -m "this is first version"
- [master (root-commit) 504e5b2] this is first version
- 1 file changed, 1 insertion(+) #提示一个文件被改动, 并且插入了一行内容
- create mode 100644 test.txt
参数解释: Git commit 命令,-m 后面输入的是本次提交的说明, 可以自定义有特点的内容, 这样就能从历史记录里方便地找到改动记录.
小结:
Git init: 初始化一个 Git 仓库
Git add <filename>: 添加文件到 Git 仓库
Git commit -m <自定义内容>: 提交文件到 Git 仓库
4, 时光穿梭机(代码库回滚)
- # 我们继续修改 test.txt 文件, 改成如下内容:
- [[email protected] mygit]$ echo "test2 git">> test.txt
- [[email protected] mygit]$ cat test.txt
- test1 Git
- test2 Git
- # 查看 Git 版本状态, 运行 Git status 命令看看结果:
Git status 命令可以让我们时刻掌握仓库当前的状态, 上面的命令输出告诉我们, test.txt 被修改过, 但还没有准备提交的修改.
虽然 Git 告诉我们该文件被修改了, 但如果能看看具体修改了什么内容, 自然是很好的. 比如你休假两周从国外回来, 第一天上班时, 已经记不清上次怎么修改的 test.txt, 所以, 需要用 Git diff 这个命令看看:
Git diff 顾名思义即使查看 difference(差异对比), 显示的格式正是 Unix 通用的 diff 格式, 可以从上面的命令输出看到, 我们在最后一行添加了 "test2 git" 内容.
知道了对 test.txt 做了什么修改后, 接下来我们就需要把它提交到仓库了, 提交修改和提交新文件是一样的两步:
- [[email protected] mygit]$ Git add test.txt
- [[email protected] mygit]$ Git commit -m "this is second version"
- [master 2d19893] this is second version
- 1 file changed, 1 insertion(+)
- # 提交后, 我们再用 Git status 命令看看仓库对的当前状态:
- [[email protected] mygit]$ Git status
- # On branch master
- nothing to commit, working directory clean
Git 告诉我们当前没有需要提交的修改, 而且, 工作目录是干净的(working directory clean).
小结:
Git status: 查看工作区的状态
Git diff: 查看修改的内容
4.1, 版本回退
- # 先再次修改文件的内容:
- [[email protected] mygit]$ echo "test3 git">> test.txt
- [[email protected] mygit]$ cat test.txt
- test1 Git
- test2 Git
- test3 Git
- # 提交修改到仓库:
- [[email protected] mygit]$ Git add test.txt
- [[email protected] mygit]$ Git commit -m "this is three version"
- [master 31acb21] this is three version
- 1 file changed, 1 insertion(+)
像这样, 你不断对文件进行修改, 然后不断提交到到版本库里. 不用担心数据的找不到或者丢失的问题, 因为每当你觉得文件修改到一定程度的时候, 就可以 "保存一个快照", 这个快照在 Git 中被称为 "commit", 一旦你把文件改乱了, 或者误删了文件, 还可以从最近的一个 commit 恢复, 然后继续工作, 不会造成数据丢失.
在实际工作中, 我们肯定记不得每次修改的内容, 所以我们可以用 Git log 命令来查看历史记录:
Git log 命令显示了最近到最远的提交日志, 我们可以看到 3 次提交.
如果嫌输出信息太多, 可以加上 --pretty=oneline 参数:
可以看到第一段是一大串 commit id(版本号), 和 SVN 不一样, Git 的 commit id 不是 1,2,3... 递增的数字, 而是一个 SHA1 计算出来的一个非常大的数字, 用十六进制表示. 为什么 commit id 需要用这么一大串数字表示呢? 因为 Git 是分布式的版本控制系统, 后面我们还会研究多人在同一个版本库里工作, 如果大家都用 1,2,3.... 作为版本号, 那肯定就冲突了.
# 进行版本回退:
首先, Git 必须知道当前版本是哪个版本, 在 Git 中, 用 HEAD 表示当前版本, 上一个版本就是 HEAD^, 上上个版本就是 HEAD^^, 如果往上 100 或者 1000 个版本可以用 HEAD~100 表示.
- # 现在我们把当前版本回退到上一个版本, 使用 Git reset 命令:
- [[email protected] mygit]$ Git reset --hard HEAD^
- HEAD is now at 2d19893 this is second version
- # 查看文件内容, 可以看到回退到了上一个版本:
- [[email protected] mygit]$ cat test.txt
- test1 Git
- test2 Git
查看日志, 发现最新的那个版本已经看不到了, 如果你又想恢复到刚刚的版本, 那么还有办法将其还原吗? 办法其实还是有的, 前提是你必须要找到那个最新版本的 commit id,Git 提供了一个命令 Git reflog 用来记录你的每一次命令:
- [[email protected] mygit]$ Git reset --hard 31acb21
- HEAD is now at 31acb21 this is three version
- [[email protected] mygit]$ cat test.txt
- test1 Git
- test2 Git
- test3 Git
现在, 你又回到了刚刚的版本环境.
小结:
- # 版本回退
- Git reset --hard HEAD [^|^^|~xx]
- Git reset --hard <commit id>
- # 查看提交历史:
Git log 或者 Git log --pretty=oneline
- # 查看命令历史:
- Git reflog
5, 工作区和暂存区
Git 和其他版本控制系统 (如 SVN) 的一个不同之处就是有暂存区的概念.
工作区(Working Directory): 就是你在电脑能看到的目录, 比如我 mygit 目录就是一个工作区.
版本库 (Repository):Git 版本库存放了很多东西, 其中最重要的就是 stage(或者叫 index) 的暂存区, 还有 Git 为我们自动创建的第一个分支 master, 以及指向 master 的一个指针叫 HEAD.
我们知道把文件往 Git 版本库里添加的时候, 是分两步执行的:
第一步用 Git add 把文件添加进去, 实际上就是把文件修改添加到暂存区.
第二步用 Git commit 提交更改, 实际上就是把暂存区的所有内容提交到当前分支.
这里就不做实例了, 大家可以从上边的例子就可以弄明白暂存区的概念了, 弄明白了暂存区, 就明白了 Git 的很多的操作到底干什么.
6, 管理修改
接下来我们要了解的是, 为什么 Git 比其他版本控制系统设计得优秀, 因为 Git 跟踪并管理的是修改, 而非文件.
什么是修改? 比如你新增了一行, 这就是修改, 删除了一行, 也是一个修改, 更改了某些字符, 也是一个修改, 创建了新文件也算一个修改.
为什么说 Git 管理的是修改, 而不是文件呢? 我们通过下边的例子的来理解.
1)对 test.txt 做一个修改, 比如加一行内容:
- [[email protected] mygit]$ echo "test4 git">> test.txt
- [[email protected] mygit]$ cat test.txt
- test1 Git
- test2 Git
- test3 Git
- test4 Git
然后, 将文件添加到暂存区:
- [[email protected] mygit]$ Git add test.txt
- [[email protected] mygit]$ Git status
- # On branch master
- # Changes to be committed:
- # (use "git reset HEAD <file>..." to unstage)
- #
- # modified: test.txt
- #
然后, 再修改 test.txt:
- [[email protected] mygit]$ sed -i 's/test4/test5/' test.txt
- [[email protected] mygit]$ cat test.txt
- test1 Git
- test2 Git
- test3 Git
- test5 Git
修改完, 直接进行提交:
- [[email protected] mygit]$ Git commit -m "add new git"
- [master 76e49ac] add new Git
- 1 file changed, 1 insertion(+)
提交后, 在看看状态:
可以发现, 刚刚第二次的修改竟然没有被提交?
让我们回顾一下操作过程:
第一次修改 -->Git add--> 第二次修改 --> Git commit
你看, 我们前面讲了, Git 管理的是修改, 当你使用 Git add 命令后, 在工作区的第一次修改被放入暂存区, 准备提交, 但是, 在工作区的第二次修改并没有放入暂存区, 所以, Git commit 只负责把暂存区的修改提交了, 也就是第一次的修改被提交了, 第二次的修改不会被提交.
提交后, 用
Git diff HEAD -- test.txt
命令可以查看工作区和版本库里面最新版本的区别:
可见, 第二次的修改确实没有被提交.
那么怎么提交第二次的修改呢? 我们可以继续执行 Git add 再执行 Git commit 就可以了, 所以一般情况下, 我们先别着急提交第一次的修改, 先 Git add 第二次修改, 再 Git commit, 就相当于把两次修改合并到一块提交了:
第一次修改 -> Git add -> 第二次修改 -> Git add -> Git commit
7, 撤销修改
在工作的过程, 难免会有修改错误的地方, 比如现在凌晨两点, 你在赶一份报告, 在 test.txt 文件中添加了一行:
- [[email protected] mygit]$ echo "test6 git">> test.txt
- [[email protected] mygit]$ cat test.txt
- test1 Git
- test2 Git
- test3 Git
- test5 Git
- test6 Git
在准备 Git add 提交之前, 你突然发现, 你添加的内容有 bug, 如果提交可能遭到老板的批评. 既然错误发现得很及时, 就可以很容易
地纠正它. 你可以删掉最后一行, 或者手动把文件恢复到上一个版本的状态, 如果用 Git status 查看一下:
你可以发现, Git 会告诉你,
Git checkout -- file
可以丢弃工作区的修改:
[[email protected] mygit]$ Git checkout -- test.txt
以上执行的命令就是把 test.txt 文件在工作区的修改全部撤销, 这里有两种情况:
一种是 test.txt 自修改后还没有被放到暂存区, 现在, 撤销修改就回到和版本库一模一样的状态.
一种是 test.txt 已经添加到暂存区后, 又做了修改, 现在, 撤销修改就回到添加到暂存区后的状态.
撤销修改后, 看看当前 test.txt 文件的内容:
- [[email protected] mygit]$ cat test.txt
- test1 Git
- test2 Git
- test3 Git
- test5 Git
文件内容果然复原了.
注意: Git checkout -- file 命令中的 -- 很重要, 没有 -- , 就变成了 "切换到另一个分支" 的命令.
现在假定是凌晨 3 点, 你突然发现你添加的内容有 bug, 还 Git add 到暂存区了:
- [[email protected] mygit]$ echo "new test ha ha">> test.txt
- [[email protected] mygit]$ cat test.txt
- test1 Git
- test2 Git
- test3 Git
- test5 Git
- new test ha ha
- [[email protected] mygit]$ Git add test.txt
庆幸的是, 在 commit 之前, 你发现了这个问题. 用 Git status 查看一下, 修改只是添加到了暂存区, 还没有提交:
并且 Git 还告诉我们, 用命令 "git reset HEAD <file>" 可以把暂存区的修改撤销掉(unstage), 重新放回工作区:
- [[email protected] mygit]$ Git reset HEAD test.txt
- Unstaged changes after reset:
- M test.txt
Git reset 命令既可以回退版本, 也可以把暂存区的修改回退到工作区. 当我们用 HEAD 时, 表示最新的版本.
再用 Git status 查看一下, 现在暂存区是干净的, 工作区有修改:
所以接下来, 就可以用之前丢弃工作区的修改来恢复:
- [[email protected] mygit]$ Git checkout -- test.txt
- [[email protected] mygit]$ cat test.txt
- test1 Git
- test2 Git
- test3 Git
- test5 Git
可以, 看到又恢复到了工作区之前的状态了.
小结:
场景 1: 当你改乱了工作区某个文件的内容, 想直接丢弃工作区的修改时, 用命令 "git checkout -- <file>"
场景 2: 当你不但该乱了工作区某个文件的内容, 还添加到了暂存区时, 想丢弃修改, 分两步, 第一步用命令 "git reset HEAD <file>", 就回到了场景 1, 第二步按场景 1 操作.
8, 删除文件
在 Git 中, 删除也是一个修改操作, 接下来我们实践一下.
- # 先添加一个新文件 test.txt 到 Git 并且提交:
- [[email protected] mygit]$ Git add test.txt
- [[email protected] mygit]$ Git commit -m "add last git"
- # On branch master
- nothing to commit, working directory clean #提示工作区是干净的
一般情况下, 我们直接通过 rm 命令将文件删除即可:
[[email protected] mygit]$ rm test.txt
这个时候, Git 知道你删除了文件, 因此, 工作区和版本库就不一致了, Git status 命令会立刻告诉你哪些文件被删除了:
现在你有两个选择, 一是确定了要删除该文件(不是误删除), 那就用命令 Git rm 删掉, 并且 Git commit:
- [[email protected] mygit]$ Git rm test.txt
- rm 'test.txt'
- [[email protected] mygit]$ Git commit -m "remove git"
- [master 8392779] remove Git
- 1 file changed, 4 deletions(-)
- delete mode 100644 test.txt
- [[email protected] mygit]$ Git status
- # On branch master
- nothing to commit, working directory clean
现在, 文件就从版本库中被删除了.
另一种情况是由于自己的误删除, 因为版本库里还有呢, 所以可以很轻松地把误删的文件恢复到最新版, 执行以下命令:
Git checkout -- test.txt
Git checkout 其实是用版本库里的版本来替换工作区的版本, 无论工作区是修改还是删除, 都可以 "一键还原".
小结:
命令 Git rm 用于删除一个文件. 如果一个文件已经被提交到版本库, 那么可以不用担心误删, 但是要小心, 你只能恢复文件到最新版本, 就会丢失最近一次提交后你修改的内容.
分布式版本控制系统(Git 基础)
来源: http://www.bubuko.com/infodetail-3492271.html