一、概念
1.1 什么是版本控制?
版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统
1.2 三种状态
文件有三种状态:已提交(committed) 、已修改(modified)和已暂存(staged)
- 已提交:表示数据已安全的保存到本地数据库中
- 已修改:表示修改了文件,但还没保存到数据库中
- 已暂存:表示对一个已修改的文件的当前版本做了标记,使之包含在下次提交的快照中
由此引入Git项目的三个工作区域:Git仓库、工作目录、暂存区域。
Git仓库目录用来保存项目的元数据和对象数据库的地方。这是Git最重要的部分,从其他计算机克隆仓库时,拷贝的就是这里的数据。
工作目录是对项目的某个版本提取出来的文件内容。这些从Git仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。
暂存区域是一个文件,保存了下次将提交的文件列表信息,一般在Git仓库目录中。(有时也被称为‘索引’)
基本的Git工作流程:
- 在工作目录中修改文件
- 暂存文件,将文件的快照放入暂存区域
- 提交更新,找到暂存区域的文件,将快照永久性存储到Git仓库目录
1.3 初次运行Git前的配置
Git自带一个git config 的工具来帮助设置控制Git外观和行为的配置变量。
1.3.1 用户信息
安装完Git后第一件事就是设置用户名称和邮件地址。这样做很重要,因为每一个Git提交都会使用这些信息,并且写入到每一次提交中。
$ git config --global user.name "xxx"
$ git config --global user.email "xxx@example.com"
1.3.2 检查配置信息
列出所有配置
$ git config --list
git config
$ git config user.name
XXX
二、Git基础
2.1 获取Git仓库
第一种实在现有项目或目录下导入所有文件到Git中,第二种是从一个服务器克隆一个现有的Git仓库。
2.1.1 在现有目录中初始化仓库
进入到项目目录中输入以下指令:
$ git init
该命令将创建一个名为 .git 的子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件,这些文件是
Git 仓库的骨干 。此时,我们仅仅只是进行了初始化,项目里的文件还没有被跟踪。
如果是在一个已经存在文件的文件夹中初始化Git仓库进行版本控制的话,应该开始跟踪这些文件并提交。可以通过git add
命令来实现对指定文件的跟踪,然后执行git commit
提交。
$ git add *.c
$ git add LICENSE
$ git commit -m 'initial project version'
2.1.2 克隆现有仓库
Git克隆的是该Git仓库服务器上的几乎所有数据,而不是仅仅复制完成你的工作所需文件。当你执行git clone
命令的时候,默认配置下远程Git仓库中的每一个文件的每一个版本都将被拉去下来。
克隆仓库的命令格式git clone [url]
$ git clone https://gitee.com/yacongliu/Gitee.git
2.2 记录每次更新d到仓库
2.2.1 检查当前文件状态
git status
如果在克隆仓库后立即使用此命令,会有以下输出:
$ git status
On branch master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
这说明你现在的工作目录相当干净。换句话说,所有已跟踪文件在上次提交后都未被更改过。 此外,上面的信
息还表明,当前目录下没有出现任何处于未跟踪状态的新文件,否则 Git 会在这里列出来。 最后,该命令还显示
了当前所在分支,并告诉你这个分支同远程服务器上对应的分支没有偏离。 现在,分支名是 “master”,这是默
认的分支名。
2.2.2 跟踪新文件
使用命令git add
开始跟踪一个文件
$ git add test.md
此时在运行git status
命令,会看到test.md文件已经被跟踪,并处于暂存状态。
这个命令理解为“添加内容到下一次提交中”而不是“将一个文件添加到项目中”要更加合适 。
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: test.md
只要在 Changes to be committed 这行下面的,就说明是已暂存状态。 如果此时提交,那么该文件此时此
刻的版本将被留存在历史记录中。 你可能会想起之前我们使用 git init 后就运行了 git add (files) 命
令,开始跟踪当前目录下的文件。 git add 命令使用文件或目录的路径作为参数;如果参数是目录的路径,该
命令将递归地跟踪该目录下的所有文件。
2.2.3 状态简览
git status
命令输出十分详细,但其用于有些繁琐。如果使用git status -s
或git status --short
命令,会得到更为精简的输出。
$ git status -s
M README
MM Rakefile
A lib/git.rb
M lib/simplegit.rb
?? LICENSE.txt
- ?? :新添加的未跟踪文件
- A:新添加到暂存区的文件
- M:修改过的文件。(出现在右边的 M 表示该文件被修改了但是还没放入暂存区,出现在靠左
边的 M 表示该文件被修改了并放入了暂存区 )
2.2.4 提交更新
在提交更新前一定要确认还有什么修改过的或新建的文件还没有git add
过,否则提交的时候不会记录这些还没暂存起来的变化。这些修改过的文件只保留在本地磁盘。 所
以,每次准备提交前,先用 git status 看下,是不是都已暂存起来了, 然后再运行提交命令 git commit
$ git commmit
2.2.5 跳过使用暂存区域
命令:git commit -a -m 'xxx'
或 git commit -am 'xxx'
这种方式可以不用再commit前进行git add xx
2.2.6 移除文件
要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域移除),然后提交。
可以用git rm
命令完成此项工作,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清
单中了。
另外一种情况是,我们想把文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录
中。 换句话说,你想让文件保留在磁盘,但是并不想让 Git 继续跟踪。 当你忘记添加 .gitignore 文件,不小
心把一个很大的日志文件或一堆 .a 这样的编译生成文件添加到暂存区时,这一做法尤其有用。 为达到这一目
的,使用 --cached 选项
$ git rm --cached README
2.3 查看提交历史
回顾提交历史 git log
git log --oneline 显示 ASCII 图形表示的分支合并历史
git log --graph 提交信息以一行进行显示
2.4 撤销操作
有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 --amend 选
项的提交命令尝试重新提交:
$ git commit --amend
这个命令会将暂存区中的文件提交。 如果自上次提交以来你还未做任何修改(例如,在上次提交后马上执行了
此命令),那么快照会保持不变,而你所修改的只是提交信息。
2.4.1 取消暂存的文件
git reset HEAD <file>
取消暂存
$ git reset HEAD Readme.md
2.4.2 撤销对文件的修改
git check out -- <file>
撤销修改,还原成上次提交时的内容。(是一个危险的命令,对文件做的任何修改都会消失)
$ git check out -- a.md
2.5 远程仓库的使用
2.5.1 查看远程仓库
git remote
列出指定的每一个远程服务器的缩写。git remote -v
显示名称及地址
$ git remote
origin
$ git remote -v
origin https://gitee.com/yacongliu/Gitee.git (fetch)
origin https://gitee.com/yacongliu/Gitee.git (push)
origin 仓库服务器的默认名字
2.5.2 添加远程仓库
git remote add <shortname> <url>
添加一个新的远程仓库,同时shortname指定一个轻松访问url的简写
$ git remote
origin
$ git remote add pb https://github.com/paulboone
$ git remote -v
origin https://github.com/schacon/ticgit (fetch
origin https://github.com/schacon/ticgit (push)
pb https://github.com/paulboone/ticgit (fetch)
pb https://github.com/paulboone/ticgit (push)
2.5.3 从远程仓库中爬取与拉取
git fetch [remote-name]
这个命令会访问远程仓库,从中拉取所有你还没有的数据。必须注意 git fetch 命令会将数据拉取到你的本地仓库 - 它并不会自动合并或修改你当前的工作 。
git clone
命令会自动设置本地 master 分支跟踪克隆的远程仓库的 master 分支(或不管是什么名字的默
认分支)
运行 git pull
通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支 。
2.5.4 推送到远程仓库
git push [remote-name][branch-name]
只有当你有所克隆服务器的写入权限,并且之前没有人推送时,这条命令才能生效。
2.5.5 远程仓库的移除与重命名
git remote rename [oldname] [newname]
修改远程仓库的简写名
$ git remote rename pb paul
git remote rm [name]
移除远程仓库
2.6 打标签
Git可以给历史中得某一个提交打上标签,以示重要。
2.6.1 列出标签
git tag
2.6.2 创建标签
轻量标签(lightweight)与附注标签(annotated)
推荐附注标签,记录了详细内容
2.6.2.1 附注标签
$ git tag -a v1.0 -m 'version v1.0'
$ git tag
V1.0
-m 指定一条将会存储再标签中的信息
git show
命令可以查看标签信息与对应的提交信息
$ git show v1.0
tag V1.0
Tagger: yacongliu <2680505646@qq.com>
Date: Mon Jan 28 15:48:45 2019 +0800
version 1.0
commit eb4d5ce8cd32b58c5a33deabf53455b8f72c2ffc (HEAD -> master, tag: V1.0, origin/master, origin/HEAD)
Merge: 9cce9a5 fad7bf9
Author: yacongliu <2680505646@qq.com>
Date: Mon Jan 28 13:39:44 2019 +0800
M:rge branch 'master' of https://gitee.com/yacongliu/Gitee
输出显示了打标签者的信息、打标签的日期时间、附注信息,然后显示具体的提交信息。
2.6.2.2 轻量标签
轻量标签本质上是将提交校验和存储到一个文件中 - 没有保存任
何其他信息。 创建轻量标签,不需要使用 -a、-s 或 -m 选项,只需要提供标签名字
$ git tag v1.4-lw
$ git tag
v0.1
v1.3
v1.4
v1.4-lw
v1.5
这时,如果在标签上运行 git show,你不会看到额外的标签信息。 命令只会显示出提交信息:
$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
changed the version number
2.6.2.3 后期打标签
Git支持对过去的提交打标签
$ git log --pretty=oneline
9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile
964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo
8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme
现在,假设在 v1.2 时你忘记给项目打标签,也就是在 “updated rakefile” 提交。 你可以在之后补上标签。 要
在那个提交上打标签,你需要在命令的末尾指定提交的校验和(或部分校验和 )。
$ git tag -a v1.2 9fceb02
2.6.2.4 共享标签
git push
命令并不会传送标签到远程仓库服务器上。创建完标签后需要显式地推送标签到共享服务器上。运行git push origin [tagname]
一次性推送很多标签,使用带有--tag
选项的 git push
命令 git push origin --tags
2.7 Git分支
Git 仓库中有五个对象:三个 blob 对象(保存着文件快照)、一个树对象(记录着目录结构和 blob 对象
索引)以及一个提交对象(包含着指向前述树对象的指针和所有提交信息)。
Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是 master。 在多次提交操作之
后,你其实已经有一个指向最后那个提交对象的 master 分支。 它会在每次的提交操作中自动向前移动
Git 的 “master” 分支并不是一个特殊分支。 它就跟其它分支完全没有区别。 之所以几乎每
一个仓库都有 master 分支,是因为 git init 命令默认创建它,并且大多数人都懒得去改动
它。
2.7.1 分支管理
-
创建分支
$ git branch testing //testing 为分支名称
-
切换分支
$ git checkout testing
HEAD 指向的是当前分支。分支切换会改变工作目录中的文件。
-
合并分支
$ git merge testing
如果合并的两个分支同时修改了同一个文件的同一个位置内容。合并分支时会提示冲突。此时需要手工进行合并。然后重新
git add
git commmit
-
删除分支
$ git branch -d testing $ git branch -D testing //确定不再需要该分支时,可强制删除
2.7.2 远程分支
远程仓库名字 “origin” 与分支名字 “master” 一样,在 Git 中并没有任何特别的含义一样。同时 “master” 是当你运行 git init 时默认的起始分支名字,原因仅仅是它的广泛使用,“origin” 是当你运行 git clone 时默认的远程仓库名字。 如果你运行 git clone -o booyah,那么你默认的远程分支名字将会是 booyah/master
-
推送本地分支到远程服务器
如果希望和别人一起在名为 testing的分支上工作 。
git push (remote) (branch)
$ git push origin testing
git push --set-upstream origin develop
推送分支
git push -u origin developv2
自动为拉取和推送设置上游。
-
拉取
当
git fetch
命令从服务器上抓取本地没有的数据时,它并不会修改工作目录中的内容。 它只会获取数据然
后让你自己合并。 然而,有一个命令叫作git pull
在大多数情况下它的含义是一个git fetch
紧接着一个git merge
命令。 如果有一个像之前章节中演示的设置好的跟踪分支,不管它是显式地设置还是通过 clone或 checkout 命令为你创建的,git pull
都会查找当前分支所跟踪的服务器与分支,从服务器上抓取数据然后尝试合并入那个远程分支。
由于 git pull 的魔法经常令人困惑所以通常单独显式地使用 fetch 与 merge 命令会更好一些。 -
删除远程分支
如果再远程分支上已经完成了所有工作后,可以删除远程分支。
$ git push origin --delete testing // testing 为远程分支名称