Git官网介绍文档:https://git-scm.com/book/zh/v2
一、集中式版本管理系统有:CVS,SVN,VSS
1.特点:
有一个单一的集中管理的服务器,保存所有文件的修订版本,所有代码库。
对网络的依赖性强,必须联网才能工作,上传速度受网络状况、带宽影响。
客户端记录文件内容的具体差异,每次记录有哪些文件做了更新,以及更新了哪些行的什么内容。
2.缺点: 中央服务器的单点故障。 如果中央服务器发生宕机,所有客户端将无法提交更新、还原、对比等,也就无法协同工作。如果磁盘发生故障,信息尚无备份,还会有数据丢失的风险。
二、常见的分布式版本管理系统有:Git、Mercurial、Bazaar 以及 Darcs 等
1.工作流程:分布式版本控制系统是没有“中央服务器”,每个人的电脑上都是一个完整的版本库,工作的时候,不再需要联网。开始工作前,在客户端克隆出完整的代码仓库,然后就可以在家、在公交车等等随心所欲地修改代码并提交了,提交到本地电脑,等到有网的时候就可以一次性地将本地仓库推送到远端仓库(临时中心服务器)中,这样一来,每个人都可以独立进行改动资料,并且所有的改动都是在完整资料信息的环境下进行的。
2.特点:
本地客户机进行操作,离线工作,快速。
安全性高,每个人电脑里都有完整的版本库,一个人的电脑换了复制其他人的一份就可以了。
原子性提交,提交不会被打断(git)。
工作模式非常灵活(传统的集中式工作流 + 特殊工作流 + 特殊工作流和集中式工作流的组合)。
3.缺点: 缺少权限管理、命令复杂混乱
总结:分布式版本控制系统的出现解决了集中式需要联网操作的弊端
Git安装后的配置
用户信息
当安装完 Git 应该做的第一件事就是设置你的用户名称与邮件地址。 这样做很重要,因为每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改:
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
再次强调,如果使用了 --global
选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息。 当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 --global
选项的命令来配置。
检查配置信息
如果想要检查你的配置,可以使用 git config --list
命令来列出所有 Git 当时能找到的配置。
Git分布式版本管理系统
1.Git 有三种状态,你的文件可能处于其中之一:已提交(committed)、已修改(modified)和已暂存(staged)。已提交表示数据已经安全的保存在本地数据库中。 已修改表示修改了文件,但还没保存到数据库中。 已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
基本的 Git 工作流程如下:
-
在工作目录中修改文件。
-
暂存文件,将文件的快照放入暂存区域。
-
提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录。
如果 Git 目录中保存着的特定版本文件,就属于已提交状态。 如果作了修改并已放入暂存区域,就属于已暂存状态。 如果自上次取出后,作了修改但还没有放到暂存区域,就是已修改状态。
2.若你使用 Git 时需要获取帮助,有三种方法可以找到 Git 命令的使用手册:
$ git help <verb>
$ git <verb> --help
$ man git-<verb>
3.在现有目录中初始化仓库
如果你打算使用 Git 来对现有的项目进行管理,你只需要进入该项目目录并输入:
$ git init
git init 将一个目录初始化为 git 仓库。方法是在目录中执行git init,执行之后在该项目目录中有个 .git 的子目录,这就是git仓库,所有相关的此项目的快照数据都将存放在这里
rimideiMac-51:Desktop admin$ mkdir git_test
rimideiMac-51:Desktop admin$ cd git_test
rimideiMac-51:git_test admin$ vim test.py
rimideiMac-51:git_test admin$ git init (在现有目录中初始化仓库)
rimideiMac-51:git_test admin$ git status (查看哪些文件处于什么状态,也可以使用git status -s 输出结果比较简洁)
rimideiMac-51:git_test admin$ git add test.py (使用命令 git add
开始跟踪一个文件,即将文件添加到暂存区staged;git add后面可以是文件或者目录,如果是目录路径,该命令将递归地跟踪该目录下的所有文件,git add . 即表示将该目录下所有文件追踪添加到暂存区)
rimideiMac-51:git_test admin$ git status
rimideiMac-51:git_test admin$ git commit -m '初始化git仓库'
4.克隆现有的仓库
如果你想获得一份已经存在了的 Git 仓库的拷贝,就要用到 git clone
命令。克隆仓库的命令格式是 git clone [url]
。Git 克隆的是该 Git 仓库服务器上的几乎所有数据,而不是仅仅复制完成你的工作所需要文件。PS:
$ git clone https://github.com/libgit2/libgit2
如果你想在克隆远程仓库的时候,自定义本地仓库的名字,你可以使用如下命令:
$ git clone https://github.com/libgit2/libgit2 mylibgit
这将执行与上一个命令相同的操作,不过在本地创建的仓库名字变为 mylibgit
。
5.修改已被跟踪暂存的文件
如果你修改了一个名为 CONTRIBUTING.md
的已被跟踪的文件,使用git status查看状态将会看到现在 CONTRIBUTING.md
文件同时出现在暂存区和非暂存区,如果你现在提交,CONTRIBUTING.md
的版本是你最后一次运行 git add
命令时的那个版本,而不是你运行 git commit
时,在工作目录中的当前版本。 所以,运行了 git add
之后又作了修订的文件,需要重新运行 git add
把最新版本重新暂存起来
6.忽略文件
一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。在这种情况下,我们可以创建一个名为 .gitignore
的文件,然后编辑该文件列出要忽略的文件模式。 比如要忽略以o和a,还有~结尾的文件,来看一个实际的例子:
$ cat .gitignore
*.[oa]
*~
7.查看未暂存和已暂存的修改具体内容
有时候我们需要查看文件具体修改了什么内容,对于已暂存和未暂存的文件查询命令有所不同
1)要查看尚未暂存的文件更新了哪些部分,不加参数直接输入 git diff命令
file是未暂存的文件,my project是更新的内容
2)若要查看已暂存的将要添加到下次提交里的内容,可以用 git diff --cached
命令
README是已暂存的文件,My project是更新的内容
8.提交更新 git commit -m
可以看到,当前是在哪个分支(
master
)提交的,本次提交的完整 SHA-1 校验和是什么(463dc4f
)也是版本号,以及在本次提交中,4 files changed有多少文件修订过,3 insertions(+)多少行添加和删改过。请记住,提交时记录的是放在暂存区域的快照。
8.跳过使用暂存区域
Git 提供了一个跳过使用暂存区域的方式, 只要在提交的时候,给 git commit
加上 -a
选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交(就是前面已经添加到暂存区,后面又更新了的文件),从而跳过 git add
步骤。
9.移除文件 git rm
1)从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域移除),然后提交。 可以用 git rm
命令完成此项工作,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。
2)git rm --cached file 从暂存区域移除,但是不删除文件,PS:下面该命令为删除以 ~
结尾的所有文件。
$ git rm \*~
10.移动文件 git mv
运行 git mv
就相当于运行了下面三条命令:
$ mv README.md README
$ git rm README.md
$ git add README
有时候用其他工具批处理改名的话,要记得在提交前删除老的文件名,再添加新的文件名。
11.查看提交历史
git log 回顾下提交历史,会按提交时间列出所有的更新,最近的更新排在最上面,会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明
git log -2 查看最近两次提交
git log --stat 查看每次提交的简略的统计信息
git log -p 用来显示每次提交的内容差异。 你也可以加上 -2
来仅显示最近两次提交内容差异(git log -p -2)
git log --pretty 指定使用不同于默认格式的方式展示提交历史
1)git log --pretty=oneline 每个提交放在一行显示,查看的提交数很大时非常有用
2)git log --pretty=short
3)git log --pretty=full
4)git log --pretty=fuller
git log --graph --since='2018.10.20' --after='2018.10.1' 筛选一个时间段的提交历史
git log --pretty=format:"%h - %an, %ar : %s" 定制要显示的记录格式
git log --author=admin 查看指定作者的提交
git log --grep=第一次提交 通过提交时备注的关键字查看
Author作者 和 commit提交者 之间究竟有何差别, 其实作者指的是实际作出修改的人,提交者指的是最后将此工作成果提交到仓库的人。
12.撤销操作 git commit --amend
git commit --amend 有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 --amend
选项的提交命令尝试重新提交
你提交后发现忘记了暂存某些需要的修改,可以像下面这样操作:
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
最终你只会有一个提交 - 第二次提交将代替第一次提交的结果。
13.取消暂存的文件 git reset HEAD <file>...
1)将文件使用git add 添加到了暂存区,需要取消暂存的话就执行: git reset HEAD <file>...
14.撤消对文件的修改,文件修改后想撤销修改还原到以前的样子,可执行下面命令
git checkout -- 文件名 撤消之前对该文件所做的修改
远程仓库的使用
git remote 查看你已经配置的远程仓库服务器,会列出你指定的每一个远程服务器的简写名称
git remote -v 会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL
git remote add <shortname> <url>
添加一个新的远程 Git 仓库(即将在本地创建的git仓库添加到远程服务器上),同时指定一个你可以轻松引用的简写 (shortname就是对远程仓库自定义的一个简写,使用git fetch url拉取时可直接使用该简写代替,连接之后即可将本地仓库文件push推送上去
)
git remote add <shortname> <url> 也可以用作连接远程Git仓库。
git fetch url/remote-name 从远程仓库中抓取与拉取,这个命令会访问远程仓库,从中拉取所有你还没有的数据。 执行完成后,你将会拥有那个远程仓库中所有分支的引用,可以随时合并或查看。如果你使用 clone
命令克隆了一个仓库,命令会自动将其添加为远程仓库并默认以 “origin” 为简写。 所以,git fetch origin
会抓取克隆(或上一次抓取)后新推送的所有工作。必须注意 git fetch
命令会将数据拉取到你的本地仓库 - 它并不会自动合并或修改你当前的工作。
git pull
命令来自动的抓取然后合并远程分支到当前分支,通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。
总结:git fetch从远程仓库拉取数据和git clone克隆仓库用法:git fetch一般是在你克隆了远程仓库,之后该远程仓库有更新新的文件数据,你本地的该仓库没有,此时只需要git fetch url拉取一次即可,不过获取到的数据与本地的不会合并,若需要合并需要你手动操作。git fetch和git pull拉取数据的区别:git fetch从远程仓库抓取数据到本地仓库不会自动合并或修改当前的工作;git pull从远程仓库抓取数据并会自动尝试合并到当前所在的分支。
git push [remote-name] [branch-name] 推送到远程仓库。ps:git push origin master ;origin仓库简称,master分支名称;
1)当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。 你必须先将他们的工作拉取下来并将其合并进你的工作后才能推送。
git remote show [remote-name] 查看远程仓库 PS:git remote show origin
它同样会列出远程仓库的 URL 与跟踪分支的信息。 这些信息非常有用,它告诉你正处于 master 分支。
git remote rename
修改一个远程仓库的简写名:
PS:git remote rename origin test(将原origin改为test)
git remote rm remote-name 移除一个远程仓库
Git 基础 - 打标签
创建标签
Git 使用两种主要类型的标签:轻量标签(lightweight)与附注标签(annotated)。
git show v1.4 查看对应标签信息与对应的提交信息
1.附注标签:
$ git tag -a v1.4 -m 'my version 1.4'
$ git tag
v0.1
v1.3
v1.4
-m
选项指定了一条将会存储在标签中的信息。 如果没有为附注标签指定一条信息,Git 会运行编辑器要求你输入信息。
git show查看对应标签信息与对应的提交信息,
输出显示了打标签者的信息、打标签的日期时间、附注信息,然后显示具体的提交信息。
2. 轻量标签:
git tag v1.4
轻量标签本质上是将提交校验和存储到一个文件中 - 没有保存任何其他信息。 创建轻量标签,不需要使用 -a
、-s
或 -m
选项,只需要提供标签名字 ;这时,如果在标签上运行 git show
,你不会看到额外的标签信息。
3.后期打标签
4.git push origin [tagname] 推送共享标签,git push
命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上
5.git push origin --tags 一次推送多个即所有服务器没有的标签
6.git tag -d <tagname> 删除标签,删除的是一个轻量标签;上述命令并不会从任何远程仓库中移除这个标签,你必须使用 git push remote-name :refs/tags/<tagname>
来更新你的远程仓库
7.检出标签 git checkout 标签名 或 git checkout -b 分支名 标签名
git checkout +标签名 这命令会产生“分离头指针”状态,有些不好的副作用,如果你做了某些更改然后提交它们,标签不会发生变化,但你的新提交将不属于任何分支,并且将无法访问,除非确切的提交哈希。因此,如果你需要进行更改——比如说你正在修复旧版本的错误——这通常需要创建一个新分支:git checkout -b 分支名 标签名 这样来检出标签。
git checkout -b 分支名 创建并切换到一个新的分支(若分支已经存在则会创建失败)
git checkout 分支名 切换分支
Git 别名
如果不想每次都输入完整的 Git 命令,可以通过 git config
文件来轻松地为每一个命令设置一个别名。 这里有一些例子你可以试试:
$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
这意味着,当要输入 git commit
时,只需要输入 git ci
。 为了解决取消暂存文件的易用性问题,可以向 Git 中添加你自己的取消暂存别名:
$ git config --global alias.unstage 'reset HEAD --'
Git 分支 - 分支简介
Git 的默认分支名字是 master
。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master
分支。 它会在每次的提交操作中自动向前移动。Git 的 “master” 分支并不是一个特殊分支。 它就跟其它分支完全没有区别。 之所以几乎每一个仓库都有 master 分支,是因为 git init
命令默认创建它,并且大多数人都懒得去改动它。
git branch +分支名 创建分支,但不切换到分支
git checkout -b 分支名 创建并切换到一个新的分支(若分支已经存在则会创建失败,git checkout -b实际等于两条命令:git branch 先创建,然后git checkout 切换 )
分支及其提交历史
1.如何查看分支指向的是commit提交的哪一个版本
使用git log --decorate或者git log --oneline --decorate,你在哪一个分支上提交的,即可看到版本所对应的分支;如下图所示,如使用branch1提交的更新,则branch1向前移动了,master不会移动,还是指向原来的版本3a32e1a。
后面你还可以切换回原来master分支重新做修改,上述两次改动针对的是不同分支:你可以在不同分支间不断地来回切换和工作,并在时机成熟时将它们合并起来。
注意的是:指回 master
分支,二是将工作目录恢复成 master
分支所指向的快照内容。 也就是说,你现在做修改的话,项目将始于一个较旧的版本。 本质上来讲,这就是忽略 branch1
分支所做的修改
分支的新建与合并
让我们来看一个简单的分支新建与分支合并的例子,实际工作中你可能会用到类似的工作流。 你将经历如下步骤:
-
开发某个网站。
-
为实现某个新的需求,创建一个分支。
-
在这个分支上开展工作。
正在此时,你突然接到一个电话说有个很严重的问题需要紧急修补。 你将按照如下方式来处理:
-
切换到你的线上分支(production branch)。(即原主分支master)
-
为这个紧急任务新建一个分支,并在其中修复它。
-
在测试通过之后,切换回线上分支,然后合并这个修补分支,最后将改动推送到线上分支。
-
切换回你最初工作的分支上,继续工作。
下面是操作步骤:
首先,我们假设你正在你的项目上工作,你已经决定要解决你的公司使用的问题追踪系统中的 #53 问题。 想要新建一个分支并同时切换到那个分支上进行工作
git checkout -b repair53
处理#53问题时,现在你接到那个电话,有个紧急问题等待你来解决。这时不必和#53问题混在一起修改,你所要做的仅仅是切换回 master
分支。在你这么做之前,要留意你的工作目录和暂存区里那些还没有被提交的修改,它可能会和你即将检出的分支产生冲突从而阻止 Git 切换到该分支,即在切换之前先在#53问题的分支上全部提交了。
git checkout master
然后再创建一个新分支专心修复紧急问题,在该分支上工作直到问题解决,然后git commit提交,之后将其合并回你的 master
分支来部署到线上,可以使用 git merge,是master合并创建的新分支
,因此需要先切换回master,步骤如下:
git checkout -b hotfix
git checkout master
git merge hotfix
合并之后 master和hotfix分支否指向的是同一个位置,因此可以删除hotfix分支了:
git checkout -d hotfix
现在你可以切换回你正在工作的分支继续你的工作,也就是针对 #53 问题的那个分支(iss53 分支)。你在 hotfix
分支上所做的工作并没有包含到 iss53
分支中。 如果你需要拉取 hotfix
所做的修改,你可以使用 git merge master
命令将 master
分支合并入 iss53
分支。
接下来假设你已经修正了 #53 问题,并且打算将你的工作合并入 master
分支,这和之前合并 hotfix
分支一样操作。合并完成之后与hotfix一样,#53的工作分支也没有存在的必要,可以直接删除。
遇到冲突时的分支合并
如果你在两个不同的分支中,对同一个文件的同一个部分进行了不同的修改,Git 就没法干净的合并它们。 如果你对 #53 问题的修改和有关 hotfix
的修改都涉及到同一个文件的同一处,在合并它们的时候就会产生合并冲突,你可以在合并冲突后的任意时刻使用 git status
命令来查看那些因包含合并冲突而处于未合并(unmerged)状态的文件:
$ git status
On branch master
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: index.html
no changes added to commit (use "git add" and/or "git commit -a")
冲突解决之后,执行git add 标记为冲突已解决添加到暂存区,最后执行git commit 提交即可。
Git 分支 - 分支管理
git branch 查看当前存在的所有分支
git branch -v 查看每一个分支的最后一次提交:
git branch --merged 查看哪些分支已经合并到当前分支,哪些已经被合并了的分支根据情况也可以选择删除了,反正都合并了:
git branch --no-merged 查看所有包含未合并工作的分支
git branch -d branch1 删除分支,若是该分支上有文件做个修改还没合并,通常会删除失败,可以使用-D强制删除。
git branch -D branch1 强制删除
Git 分支 - 远程分支
git fetch origin
命令。 这个命令查找 “origin” 是哪一个服务器,从中抓取本地没有的数据,并且更新本地数据库,移动 origin/master
指针指向新的、更新后的位置。
git push origin serverfix:awesomebranch
来将本地的 serverfix
分支推送到远程仓库上的 awesomebranch
分支。
git push origin --delete 分支名 删除远程分支;基本上这个命令做的只是从服务器上移除这个指针。 Git 服务器通常会保留数据一段时间直到垃圾回收运行,所以如果不小心删除掉了,通常是很容易恢复的。