git /gɪt/ 是一个开源的分布式版本控制系统git
最初是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件github
版本控制是一种记录一个或若干文件内容变化,以便未来查阅特定版本修订状况的系统。能够对任何类型的文件进行版本控制,便于不一样的开发者协同工做shell
集中式版本控制数据库
集中化的版本控制系统是为了让不一样系统上的开发者协同工做。例如 SVN,它会有一个单一的集中管理的服务器,保存全部文件的修订版本,而协同工做的人经过客户端链接到这台服务器,拉取最新的文件或者是提交更新vim
在这个系统中,每一个人能够看到项目中其余人的工做,管理员也能很好的掌握和分配每一个开发者的权限。但因为版本库是集中在服务器上的,若是出现了中央服务器的单点故障,在这个时间内,谁都没法提交更新,并且整个项目的历史记录被保存在单一位置,就有丢失全部历史更新记录的风险安全
分布式版本控制bash
分布式的版本控制解决了集中化版本控制的一些问题,客户端并不仅提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这么一来,任何一处协同工做用的服务器发生故障,过后均可以用任何一个镜像出来的本地仓库恢复。由于每一次的克隆操做,实际上都是一次对代码仓库的完整备份服务器
更进一步,许多这类系统均可以指定和若干不一样的远端代码仓库进行交互。籍此,你就能够在同一个项目中,分别和不一样工做小组的人相互协做。你能够根据须要设定不一样的协做流程,好比层次模型式的工做流,而这在之前的集中式系统中是没法实现的网络
直接记录快照,而非差别比较ssh
Git 保存的不是文件的变化或者差别,而是一系列不一样时刻的文件快照
Git 把数据看做是对小型文件系统的一组快照。 每次提交更新,或在 Git 中保存项目状态时,它会对当时的所有文件制做一个快照并保存这个快照的索引。 为了高效,若是文件没有修改,Git 再也不从新存储该文件,而是只保留一个连接指向以前存储的文件。Git 对待数据更像是一个快照流
近乎全部操做都是本地执行
在 Git 中的绝大多数操做都只须要访问本地文件和资源,由于你在本地磁盘上就有项目的完整历史,因此大部分操做看起来瞬间完成,
Git 保证完整性
Git 中全部数据在存储前都计算校验和,而后以校验和来引用
Git 通常只添加数据
执行的 Git 操做,几乎只往 Git 数据库中增长数据
Linux 上安装
Linux 上使用 yum 安装,yum install git
$ sudo yum install git
复制代码
Windows 上安装
官网上下载安装包安装便可
配置用户信息
安装完后须要设置用户名称和邮件地址,这样作很重要,由于每个 Git 的提交都会使用这些信息,而且它会写入到你的每一次提交中,不可更改
$ git config --global user.name "zou"
$ git config --global user.email zouxq412@foxmail.com
复制代码
配置完后可使用 git config --list
查看配置信息
使用了 --global 选项,表示全局配置,那么该命令只须要运行一次,由于以后不管你在该系统上作任何事情, Git 都会使用那些信息。 当你想针对特定项目使用不一样的用户名称与邮件地址时,能够在那个项目目录下运行没有 --global 选项的命令来配置
在了解 Git 的基本操做以前,咱们先来了解 Git 工做区、暂存区和版本库的概念
在 Git 中的文件有三种状态:已提交(committed): 表示数据已经安全的保存在本地数据库中;已修改(modified): 表示修改了文件,但还没保存到数据库中;已暂存(staged): 表示对一个已修改文件的当前版本作了标记,使之包含在下次提交的快照中
由此也引入了 Git 项目的三个工做区域的概念:
.git/index
文件中,因此咱们把暂存区有时也叫做索引.git
,这里记录着仓库的版本信息和历史记录下面这个图展现了工做区、版本库中的暂存区和版本库之间的关系:
下面咱们经过建立仓库和基本操做来了解这三个工做区域的关系
仓库也叫版本库(repository),能够简单理解成一个目录,这个目录里面的全部文件均可以被 Git 管理起来,每一个文件的修改、删除,Git都能跟踪,以便任什么时候刻均可以追踪历史,或者在未来某个时刻能够还原
git init
是用来初始化一个 Git 仓库的
git init
复制代码
该命令会在当前目录下建立一个 .git
的目录,这个子目录含有你初始化的 Git 仓库中全部的必须文件。这个时候只是对仓库作了初始化的操做,假如该目录下本来就有文件,须要对这些文件进行版本控制,能够经过 git add <file>
跟踪这些文件并提交 git commit -m <message>
git add .
git commit -m 'initial project version'
复制代码
上面是把目录下的全部文件提交到了仓库中
若是想获取现有 Git 仓库的拷贝,须要用 git clone <repo>
或 git clone <repo> <directory>
repo 是仓库地址,directory 是本地仓库的名称,即目录名称
以下面我要克隆 github 上的一个仓库,并制定本地仓库的名称为 mylibname
git clone https://github.com/xxxx/xxxx mylibname
复制代码
工做目录下的每个文件有这两种状态:
已跟踪
已经归入了版本控制的文件,在上一次快照中有它们的记录,它们的状态可能处于 未修改,已修改 或 已放入暂存区。未跟踪
即尚未加入到版本控制的文件新增的未跟踪文件(untracked),和编辑过被 Git 记为已修改的文件(modified)。 经过 git add
放入暂存区(staged),而后 git commit
提交全部暂存了的修改,提交后的文件即为未修改文件(unmodified),如此反复
操做命令:
git status
查看文件状态git add
添加文件到暂存区,包括未跟踪和修改的文件git diff
查看修改内容git commit
提交更新,添加暂存区的内容到本地仓库git reset HEAD
取消暂存git rm
移除文件git mv
移动文件这里我新建一个 demo 目录做为仓库,并初始化这个仓库
接下来咱们使用上面新建的仓库 demo,并对里面的文件作一些操做
先建立一个新的文件 touch readme.txt
要查看仓库目录下哪些文件处于状态状态,使用 git status
命令
Untracked files
未被跟踪的文件Changes not staged for commit
修改的文件Changes to be committed
暂存状态文件能够看到新建的文件 readme.txt
的文件状态为 untracked
,并提示咱们要经过 git add <file>
命令去跟踪咱们须要提交的文件
若是使用
git status -s
命令或git status --short
命令,将获得一种更为紧凑的格式输出
使用命令 git add <file>
开始跟踪一个文件或暂存修改的文件,会把文件添加到暂存区
git add readme.txt
复制代码
再次使用 git status
命令查看,会看到 readme.txt 文件已经被跟踪,并处于暂存状态。Changes to be committed
下的文件就是处于暂存状态
git add
命令使用文件或目录的路径做为参数;若是参数是目录的路径,该命令将递归地跟踪该目录下的全部文件
该命令还用来暂存已修改的文件,就是 Changes not staged for commit
下的文件
这个时候假如咱们对暂存的文件进行了修改
echo 'My Project' > readme.txt
复制代码
使用 git status
命令查看,咱们能够看到多出了一个未被暂存,被修改状态的文件,而使用 git status
命令并不能看到具体修改的地方,这时能够用 git diff
来查看未暂存的文件更新的部分
输入 git diff
来查看未暂存的文件更新的部分
该命令比较的是工做目录中当前文件和暂存区域快照之间的差别, 也就是修改以后尚未暂存起来的变化内容。若要查看已暂存的将要添加到下次提交里的内容,能够用 git diff --cached
命令
git diff
还没有暂存的改动git diff --cached
查看已暂存的改动当暂存区的文件已经准备稳当能够提交了,能够经过命令 git commit
来提交,或者直接加入说明 git commit -m <message>
git commit
复制代码
这种方式会启动文本编辑器以便输入本次提交的说明(这里的编辑器是 vim)
使用 git commit -m <message>
请记住,提交时记录的是放在暂存区域的快照。 任何还未暂存的仍然保持已修改状态,能够在下次提交时归入版本管理。 每一次运行提交操做,都是对你项目做一次快照,之后能够回到这个状态,或者进行比较
跳过使用暂存区域
Git 提供了一个跳过使用暂存区域的方式, 只要在提交的时候,给
git commit
加上-a
选项,Git 就会自动把全部已经跟踪过的文件暂存起来一并提交,从而跳过git add
步骤
git reset HEAD <file>...
用来取消已暂存的内容
咱们修改下 readme.txt ,并 git add
到暂存区
echo 'modify content' > readme.txt
git add readme.txt
复制代码
经过 git status
能够看到 readme.txt 已经添加到暂存区了
假如这时不想把它提交更新并加入到下一次的快照当中,就能够经过git reset HEAD <file>
去取消已暂存的内容
git reset HEAD readme.txt
复制代码
撤消对文件的修改
若是你想撤销对文件的修改,也就是还原到未修改前的状态,可使用
git checkout -- [file]
命令。该命令会取消你对该文件作的修改内容。
假如咱们如今去删除 readme.txt 这个文件,再经过 git status
查看状态
它是会记录咱们的删除操做,标记为未暂存的文件
而后再运行 git rm <file>
记录这次移除文件的操做
下次提交更新 git commit
以后,该文件就再也不归入版本控制管理中了
若是删除以前修改过而且已经放到暂存区域的话,则必需要用强制删除选项 -f
,即git rm -f <file>
若是把文件从暂存区域移除,但仍然但愿保留在当前工做目录中,换句话说,仅是从跟踪清单中删除,使用 --cached
选项便可
git mv
命令用于移动或重命名一个文件、目录、软链接。
咱们先撤销对 readme.txt 文件的删除
git reset HEAD readme.txt
git checkout -- readme.txt
复制代码
而后使用 git mv
对其重命名
git mv readme.txt README.md
复制代码
上面咱们有关的命名操做都是本地执行,若是须要分享代码或与其余开发人员协同工做,就须要链接远程仓库了。这个远程仓库是指托管在因特网或其余网络中的你的项目的版本库
这里咱们使用 github 做为远程仓库
运行 git remote add <shortname> <url>
添加一个新的远程 Git 仓库
这里是以 github 作为远程仓库为例,本地 Git 仓库和 GitHub 仓库之间的传输是经过SSH加密的,咱们须要先配置验证信息
使用如下命令生成 SSH Key
ssh-keygen -t rsa -C "zouxq412@foxmail.com"
复制代码
这里的邮箱为你 github 帐号绑定的邮箱,生成 SSH Key 后咱们去到它保存的路径 ~/.ssh
下打开 id_rsa.pub
复制里面的公钥
而后咱们去到 github 的设置中心找到 SSH and GPG keys,点击 New SSH key 设置 SSH 公钥
将复制的 SSH 公钥添加并保存
为了验证是否成功,使用命令 ssh -T git@github.com
接下来咱们在 github上去新建一个仓库
建立成功后,显示如下信息
上面会有一些提示,容许咱们建立一个新的本地仓库或把已存在的仓库推到 github仓库上,这里咱们直接把直接的 demo 上传到这个 github 仓库中
git remote add origin https://github.com/Morgan412/demo.git
git push -u origin master
复制代码
第一次会让咱们输入 github 的帐号密码
git push
会把本地仓库的内容推送到远程仓库中,这时能够刷新下 github 的仓库页面,会发现已经有上传的内容了
推送到远程仓库的命令为: git push [remote-name] [branchname]
查看你已经配置的远程仓库服务器,能够运行 git remote
命令, 它会列出你指定的每个远程服务器的简写,也能够指定选项 -v
,会显示须要读写远程仓库使用的 Git 保存的简写与其对应的 URL
若是想要查看某一个远程仓库的更多信息,可使用 git remote show [remote-name]
命令
从远程仓库获取数据的命令
git fetch [remote-name]
复制代码
这个命令会访问远程仓库,从中拉取全部你尚未的数据,git fetch origin
会抓取克隆(或上一次抓取)后新推送的全部工做。 必须注意 git fetch
命令会将数据拉取到你的本地仓库,当它并不会自动合并或修改你当前的工做,这个时候咱们能够运行 git merge [alias]/[branch]
来合并分支
如今咱们在 github 的远程仓库中修改 README.md 文件,而后运行 git fetch origin
能够看到信息提示远程仓库的 master 有更新,这时再运行 git merge origin/master
README.md 文件被合并更新
若是你有一个分支设置为跟踪一个远程分支,可使用
git pull <remote> <branch>
命令来自动的抓取而后合并远程分支到当前分支。默认状况下,git clone
命令会自动设置本地 master 分支跟踪克隆的远程仓库的 master 分支。 运行git pull
一般会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。
git remote rename
去修改一个远程仓库的简写名
git remote rm [name]
能够去移除一个远程仓库
Git 能够给历史中的某一个提交打上标签,可使用这个功能来标记发布结点(如v1.0),标签也是版本库的一个快照
命令:
git tag
查看全部的标签git tag <name>
建立标签git tag -v <name> -m <message>
建立附注标签git push origin [tagname]
推送标签到远程仓库git tag -d <tagname>
删除本地仓库标签git push <remote> :refs/tags/<tagname>
更新远程仓库标签建立标签命令 git tag <name>
git tag -v <name> -m <message>
能够建立一个附注标签
首先咱们要切换到须要打标签的分支上,而后使用建立标签命令 git tag <name>
git tag v1.0.0
复制代码
git tag
能够查看全部的标签
后期打标签
默认状况下,标签是打在最新提交 commit 上的,假如我想对过去的某个历史快照节点打标签呢?其实也是能够的
git log --pretty=oneline --abbrev-commit
查看历史 commit id,而后打上对应标签便可
$ git log --pretty=oneline --abbrev-commit
459f6fc (HEAD -> master, origin/master) Update README.md
e241626 修改内容
a9dec5d first commit
复制代码
如我要给 “修改内容” 此次 commit 打上标签
git tag v1.0.1 e241626
复制代码
共享标签
默认状况下,git push
命令并不会传送标签到远程仓库服务器上。 在建立完标签后你必须显式地推送标签到共享服务器上。 这个过程就像共享远程分支同样,你能够运行 git push origin [tagname]
若是想要一次性推送不少标签,也可使用带有 --tags
选项的 git push
命令。 这将会把全部不在远程仓库服务器上的标签所有传送到那里
删除标签
使用命令 git tag -d <tagname>
能够删除掉本地仓库上的标签
上面的命令并不会从任何远程仓库中移除这个标签,若是要移除远程仓库的标签必须使用 git push <remote> :refs/tags/<tagname>
来更新你的远程仓库
分支就像是科幻电影里面的平行宇宙,当你正在电脑前努力学习Git的时候,另外一个你正在另外一个平行宇宙里努力学习SVN
若是两个平行宇宙互不干扰,那对如今的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了Git又学会了SVN!
在实际工做中,当你须要完成某个须要,而这个需求你可能须要2天才能完成,这时你能够新建一个分支,在分支上的任何改动都是不影响其余分支的,当你完成了需求以后,再合并分支
命令:
git branch
列出分支,当前分支前面会标一个*
号git branch <branchname>
建立分支git checkout <branchname>
切换分支git checkout -b <branchname>
建立并切换分支git merge
合并分支git branch -d <branchname>
删除分支建立分支
git branch <branchname>
git checkout <branchname>
复制代码
想要新建一个分支并同时切换到那个分支上,你能够运行一个带有 -b
参数的 git checkout
命令,等同于上面两个命令
git checkout -b newb
复制代码
git branch
列出分支,当前分支前面会标一个*
号
合并分支
一旦某分支有了独立内容,你终究会但愿将它合并回到你的主分支
使用 git merge
命令将任何分支合并到当前分支中去
假如咱们如今对新的分支内容有了修改,如今要合并到主分支中
合并冲突
当Git没法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成
解决冲突就是把 Git 合并失败的文件手动编辑为咱们但愿的内容,再提交