公众号内发送Git获取Git官网PDF教程

版本控制

版本控制是一种记录一个或若干个文件内容变动、以便未来查阅特定版本订正状况的零碎。

本地版本控制系统

很久以前就开发了许多本地版本控制系统、大多都是采纳某种简略的数据库来记录文件的历次更新差别。

其中最风行的一种叫做 RCS、现今许多计算机系统上都还看失去他的踪影。RCS 的工作原理是在硬盘上保留补丁集、通过利用所有的补丁、能够从新计算出各个版本的文件内容。

集中化版本控制系统

让不同零碎上的开发者协同工作、集中化版本控制系统应运而生。有一个繁多的集中管理的服务器、保留所有文件的订正版本、而协同工作的人们都通过客户端连到这台服务器、取出最新的文件或者提交更新。

害处

  • 单点故障
  • 无备份

分布式版本控制系统

在分布式版本控制系统中、客户端不只是提取最新版本的文件快照、而是把代码仓库残缺地镜像下来、包含残缺的历史记录

这么一来、任何一处协同工作用的服务器产生故障、预先都能够用任何一个镜像进去的本地仓库复原。

Git 简史

Git 的设计指标

  • 速度
  • 简略的设计
  • 对非线性开发模式的强力反对(容许成千上万个并行开发分支)
  • 齐全分布式
  • 有能力高效治理相似 Linux 内核一样的超大规模我的项目

间接记录快照、而非差别比拟

Git 喝其余版本控制系统(Subversion) 的次要差异在于 Git 看待数据的办法。

从概念上来说、其余大部分零碎以文件变更列表的形式存储信息、这类零碎将它们存储的信息看作是一组根本文件喝每个文件随工夫逐渐累积的差别,称之为基于差别的版本控制

Git 不依照以上形式看待或保留数据、Git 更像是把数据看作是对小型文件系统的一系列快照。在 Git 中、每当你提交更新或保留我的项目状态时、它基本上就会对过后的全副文件创建一个快照并保留这个快照的索引。为了效率、如果文件没有批改、Git 则不再从新存储文件、只是保留一个指向之前存储的文件。Git 看待数据更像是一个快照流

Git 简直与所有其余版本控制系统的重要区别就是在于这个中央。

近乎所有操作都是本地执行

在 Git 中绝大多数操作都只须要拜访本地文件和资源、个别不须要来自网络上其余计算机的信息。

Git 保障完整性

Git 中所有的数据在存储前都计算测验和、而后以测验和来饮用。

Git 用以计算校验和的机制叫做 SHA-1 散列。是由 40 个十六进制自发组成的字符串、基于 Git 中文件内容或目录构造计算出来的。

Git 个别只增加数据

你执行的 Git 操作、简直只往 Git 数据库中增加数据

三种状态

Git 有三种状态、你的文件可能处于其中的一种

  • 已批改

    示意批改了文件、但没保留到数据库中

  • 已暂存

    示意对一个已批改文件到以后版本做了标记、使之在下次提交到快照中

  • 已提交

    示意数据曾经平安地保留在本地数据库中。

这会让咱们的 Git 我的项目领有三个阶段:工作区、暂存区、Git 目录。

工作区是对我的项目的某个版本独立提取进去的内容。这些从 Git 仓库的压缩数据库中提取进去的文件、放在磁盘供你应用或批改。

暂存区是一个文件、保留了下次将要提交的文件列表信息、个别在 Git 仓库目录中。依照 Git 的术语叫做“索引”。

Git 仓库目录是 Git 用来保留我的项目的元数据和对象数据库的中央。这是Git 中最重要的局部。从其余计算机克隆仓库时、复制的就是这里的数据。

根本的 Git 工作流程如下

  • 在工作区中批改文件
  • 将你想要下次提交的更改选择性地暂存、这样只会将更改的局部增加到暂存区。
  • 提交更新、找到暂存区的文件、将快照永久性存储到 Git 目录。

Git 首次接触

查看版本&查看配置

git --versiongit config --list// 查看独自某项配置git config user.name

配置

git config --global user.name "coderLi"git config --global user.email "coderLi@xxx.com"

如果应用了 --global 选项、那么该命令只须要运行一次、因为之后无论你在该零碎上做任何事件、Git 都会应用那些信息。

因为 Git 会从多个文件中读取同一配置的变量的不同值。能够通过查问 Git 中该变量的原始值、它会通知你哪一个配置文件最初设置了该值

git config --show-origin user.namefile:/Users/coderLi/.gitconfig    coderLi

获取帮忙

git help <verb>git <verb>--helpman git-<verb>git add -h

Git 根底

  • 配置并初始化一个仓库
  • 开始或进行跟踪文件
  • 暂存或提交更改

获取仓库

获取 Git 仓库通常有两种形式

  • 将尚未进行版本控制的本地目录转为 Git 仓库
  • 从其余服务器克隆一个已存在的 Git 仓库
初始化仓库
cd /Users/user/my-projectgit init

该命令创立一个名为 .git 的字幕了、这个子目录有你初始化 Git 仓库中所有的必须文件、这些文件是 Git 的仓库骨干。

如果该文件夹下有问价须要进行版本控制、你应该开始追踪这些文件并进行初始提交。

能够通过 git add 命令来制订所需的文件进行追踪、而后执行 git commit

git add *.javagit add readme.mdgit commit -m 'initial project version'
克隆现有的仓库

这时就要应用 Git clone 命令、如果你对其余 VCS很相熟、请注意一下你所应用的命令是 “clone” 而不是 “checkout” 。这是 Git 区别于其余吧版本控制系统的一个重要个性、Git 克隆的是 Git仓库服务器上的简直所有数据、而不是仅仅复制实现你的工作所须要的文件。当执行 git clone 命令时、默认配置下原创 Git 仓库中的每一个文件的每一个版本都将被拉取下来。事实上、如果你的服务器磁盘坏掉了、你通常能够应用任何一个克隆下来的用户端重建服务器上的仓库

# git clone <url>git clone https://github.com/libgit2/libgit2

会在当前目录下创立一个名为 libgit2 的目录、并在这个目录下初始化一个.git 文件夹、从近程仓库拉取下所有数据放入.git 文佳佳、而后从中读取最新版本的文件拷贝。如果你进入到新建的这个libgit2 文件夹中、你会发现所有的我的项目文件曾经在外面了、准备就绪等后续开发和应用。

如果你想自定义本地仓库等名字、能够通过额定参数指定

git clone https://github.com/libgit2/libgit2 mylibgit

本地仓库名就变为了 mylibgit

记录每次更新到仓库

工作目录下的每个文件都不外乎这两种状态:

  • 已跟踪、是指那些被纳入了版本控制的文件、在上一次快照中有它们的记录、在工作一段时间之后、它们的状态可能是未修改、已批改或曾经放入暂存区。简而言之、已跟踪的文件就是 GIt 曾经晓得的文件
  • 工作目录中除已跟踪文件外其余的文件都属于未跟踪文件、它们既不存在上一次的快照中、也米有被放入暂存区。首次克隆某个仓库时、工作目录中的所有文件都属于已跟踪文件、并处于未修改状态

检测以后文件状态

git status 命令产看哪些文件处于什么状态

跟踪新文件

git add README

应用 git add 开始跟踪一个文件、并将其放入到暂存区。如果此时提交、那么该文件在你运行 git add 时的版本将被留存在后续的历史记录中。git add 命令应用文件或目录的门路作为参数、如果参数时目录的门路、该命令将递归地跟踪该目录下的所有文件

暂存已批改的文件

git add 是一个多功能命令、能够用它来跟踪新文件、或者把已跟踪的文件放入暂存区、还能用于合并时把有抵触的文件标为已解决状态。

这个命令能够了解为:准确地将内容增加到下一次提交中。

状态概览

git status 命令输入非常具体、但其用于有些繁琐、应用 git status -s 简化输入形式

疏忽文件

个别咱们总有一些文件无需纳入 Git 的治理、也不心愿它们呈现在未跟踪文件列表中。在这种状况下、咱们能够创立一个名为.gitignore的文件、列出要疏忽的文件的模式。

*.[oa]*~

第一行通知 Git 疏忽所有以.o或.a 结尾的文件。

第二行通知咱们疏忽所有名字以~结尾的文件。

查看已暂存和未暂存的批改

git diff 比拟的是工作目录中以后文件和暂存区快照之间的差别、也就是批改之后还没暂存起来的变动内容。

若要查看已暂存的将要增加都下次提交里的内容、能够应用 git diff --staged 命令、git diff --cached

须要留神的是、git diff 自身只事实尚未暂存的改变、而不是自上次提交以来所做的所有改变。所以如果你一下子暂存了所有更新过的文件、运行 git diff 后却什么也没有、就是这个起因。

提交更新

当初暂存区曾经准备就绪、能够提交了。

git commit -m 'information'

跳过应用暂存区

只管应用暂存区域的形式能够精心筹备要提交的细节、但有时候这么做显得繁琐、Git 提供了一个跳过应用暂存区域的形式、只有在提交时、在 git commit 加上 -a 选项、Git 就会主动把所有曾经追踪过的文件暂存起来一并提交、从而逃过 git add 步骤。

移除文件

从 Git 中移除某个文件、就必须从暂存区中移除、而后提交。git rm 命令能够实现此项工作、并连带从工作目录中删除置顶文件、这样当前就不会呈现在未跟踪文件清单中了。

$ls DijkstraJourneyGeneratorTest.java    cassandra                redisGeneric.java                ehcache                    repository$git rm Generic.java$git statusChanges to be committed:  (use "git restore --staged <file>..." to unstage)    deleted:    Generic.java

如果只是单纯的在工作目录中删除文件、而没有对齐进行提交、是不能在 Git 中删除该文件的

$lsDijkstraJourneyGeneratorTest.java    cassandra                redisGeneric.java                ehcache                    repository$rm Generic.java$git statusChanges not staged for commit:  (use "git add/rm <file>..." to update what will be committed)  (use "git restore <file>..." to discard changes in working directory)    deleted:    Generic.java

这个时候你还是要执行 git rm Generic.java 来将这个删除增加到暂存区

如果要删除曾经放到暂存区的文件、则必须应用强制删除项 -f

$ vi Generic.java $ git add Generic.java 

第一步咱们批改了 Generic.java 这个文件、而后将其放入到暂存区、然而这个时候咱们想删除这个 Generic.java 文件并且想将此次提交到暂存区的版本也删除掉

$git rm -f Generic.java$git statusChanges to be committed:  (use "git restore --staged <file>..." to unstage)    deleted:    Generic.java

这个时候、咱们工作目录下也删除了 Generic.java 的问价、并且刚刚批改Generic.java的版本也在暂存区中删除了。

挪动文件

git mv file_from file_to
$git mv Generic.java Generic01.java$git statusChanges to be committed:  (use "git restore --staged <file>..." to unstage)    renamed:    Generic.java -> Generic01.java

其实运行 git mv就相当于运行了上面三条命了

$mv Generic.java Generic01.java$git rm Generic.java$git add Generic01.java

查看提交历史

git log 在不传入任何参数的默认状况下、git log 会按工夫先后顺序列出所有的提交、最精的更新排在最下面。

git log 有很多选项帮忙你搜查你所要查找的提交、其中最有用的就是 -p/-patch 选项、它会显示每次提交所引入的差别(按补丁格局显示)。

也能够限度显示日志的条目数量、例如应用 -2 显示最近的两次提交。

撤销操作

在任何一个阶段、你都有可能想要撤销某些操作。有时候咱们提交完了才发现漏掉了几个文件没有增加、或者提交信息写错了、此时、能够应用带有 --amend 选项来提交命令从新提交

git commit -m 'renew' -amend

这个命令会将暂存区中的文件提交、如果自上次提交以来你还未做任何批改、那么快照将会放弃不变、而你批改的只是提交信息。

最终只会有一个提交、而第二次提交将会代替第一次提交的后果。 第一次的提交就像从未存在过一、它并不会呈现在仓库的历史中。

勾销暂存的文件

git add -Agit statusChanges to be committed:  (use "git restore --staged <file>..." to unstage)  .....  .....

咱们能够应用该命令将暂存区的版本删除掉

git restore --staged xxx.java

撤销对文件的批改

同样也是应用 git restore xxx.java

撤销commit

当咱们想撤回一个本地的 commit 的时候、怎么办

能够应用 git reset HEAD^ 这样就能够胜利撤销你的 commit

head^ 等同于 head~1 示意git 仓库的上一个版本如果你提交了两个 commit 都想撤回、能够应用 head~2 示意

还能够在这个命令中加上选项参数

  • --mixed 不删除工作空间改变代码、撤销 commit 并且撤销 git add 操作、默认应用就是这个参数
  • --soft 不删除工作空间改变代码、撤销 commit、然而不撤销 git add
  • --hard 删除工作空间改变代码、撤销 commit、撤销 git add 相当于回到上一次commit状态
https://blog.csdn.net/w958796...

git checkout

git checkout 最常见的用法莫过于对工作分支的切换了

git checkout branchName# 该命令会将当前工作分支切换到 branchName中

也能够通过上面的命令在新分支创立的同时切换分支

git checkout -b newBranch

该命令相当于

git branch newBranchgit checkout newBranch

该命令残缺语法为

git checkout -b new-branch-name copy-branch

该命令的次要关联指标其实是.git文件夹下的HEAD文件、HEAD文件记录了以后HEAD的信息

扩大用法

git checkout yyy.javagit checkout origin/master xxx.java

该命令次要用于检出某一个指定文件。如果不填写 commit id、则默认从暂存区检出该文件、如果暂存区为空、则该文件会回滚到最近一次提交状态

也能够指定从近程分支中checkout某个文件

https://www.jianshu.com/p/cad...

近程仓库的应用

查看你曾经配置的近程仓库服务器、能够应用 git remote 命令、它会列出你指定的每一个近程服务器的简写。如果你曾经克隆了本人的仓库、那么至多应该能看到origin、这是 Git 给你克隆仓库服务器的默认名字

git remote# 显示对应的 urlgit remote -v

增加近程仓库能够应用 git remote add <shortname> <url>

从近程仓库中抓取和拉取
  • git fetch 命令只会将数据下载到你的本地仓库--它并不会主动合并或批改你以后的工作空间、当筹备好时你必须手动将其合并
  • git pull 通常会从最后克隆的服务器上抓取数据并主动尝试合并到以后所在的分支

推送到近程分支

git push origin master

能够应用命令查看近程仓库的状况

git remote show orign

打标签

Git 能够给仓库历史中的某个提交打上标签、以示器重。Git 反对两种标签、一种是轻量级标签、一种是附注标签。

轻量级标签很想一个不会扭转的分支--它只是某一个特定提交的饮用

而附注标签是存储在 Git 参考中的一个残缺对象、它是能够被测验的、其中蕴含打标签的行吗、电子邮件地址、日期工夫、还有标签信息。

通常会倡议创立附注标签。

  • 列出标签 git tag -l
  • 创立标签 git tag tagName / git tag -a tagName -m 'message about tag'。加上 -a 创立的是附注标签、不加上的是一个轻量级标签
  • 展现某个标签内容 git show tagName
  • 删除标签 git tag -d tagName

默认状况下、git push 命令并不会传送标签到近程仓库服务器上。在创立万标签后你必须显示地将标签推送到服务器上、这个过程就行你共享近程分支一样。git push orign tagName

Git 分支

简直所有到版本零碎都以某种模式反对分支、应用分支意味着你能够把你的工作从开发主线上分离出来、一面影响开发主线。在很多版本控制系统中、这是一个稍微低效的过程、通常须要实现创立一个源代码的正本。对于大我的项目来说、这样的过程会消耗很多工夫。

Git 解决分支的形式堪称是难以置信的轻量、创立分支这一操作简直能在霎时实现、并且在不同分支之间的切换也是一样便捷。与其余版本控制系统不同、Git 激励在工作流中频繁地应用分支与合并。

Git 放弃的不是文件的变动或者差别、而是一系列不同时刻的快照。在进行提交操作时、Git 会保留一个提交对象。

在进行提交操作时、Git 会保留一个提交对象。晓得了Git 保留数据的形式、咱们能够天然的想到--该提交对象会蕴含一个只想暂存内容快照的指针,还蕴含作者的姓名和邮箱、提交输出的信息以及指向它的父对象的指针。首次提交对象没有父对象、一般提交操作产生的提交对象有一个父对象、而由多个分支合并产生的提交对象有多个父对象。

咱们假如当初的工作目录中有三个要被暂存和提交的文件。暂存操作会为每一个文件计算校验和、而后会把以后版本的文件快照保留到暂存区中

git add README test.rb LICENSEgit commit -m 'initial commit of my project'

进行提交时、Git 会先计算每个子目录的测验和、而后在 Git 仓库中将这些测验和保留为树对象。随后 Git 会创立一个提交对象、它除了蕴含下面提到的信息外、还蕴含了指向这个树对象的指针、如此以来、Git 就能够在须要的时候重现此次保留的快照。

当初 Git仓库中蕴含五个对象、三个blob 对象(保留着文件快照)、一个树对象(记录着目录构造和blob对象索引)以及一个提交对象(蕴含指向树对象的指针以及所有提交信息)

做些批改后再次提交、那么这次产生的提交对象会蕴含一个指向上次提交对象的指针

Git 的分支、其实实质上仅仅是一个指向提交对象的可变指针。Git 的默认分支名字是 master。在屡次提交操作之后、你其实曾经有一个指向最初那个提交对象的 master 分支。master 分支会在每次提交时主动向前挪动。

分支创立

git branch testing

Git 创立分支只是为你创立了一个可挪动的新指针、它会在你以后所在的提交对象上创立一个指针

那么 Git 是如何晓得以后在哪个分支上的、它应用一个名为 HEAD 的非凡指针。在 Git 中、它是一个指针、指向以后所在的本地分支。Git Branch 命令仅仅创立一个新分支、并不会主动切换到新分支中去

能够应用 git log --decorate 查看各个分支以后所指的对象

分支切换

切换到一个已存在的分支、能够应用 git checkout 命令

git checkout other-branch

这样 HEAD 就指向了 other-branch 分支了

如果咱们这个时候批改某个文件、再次 commit

testing 分支向前挪动了、然而 master 分支却没有、它依然指向运行 git checkout 时所指的对象。

而后咱们当初切换回 master 分支

git checkout master

这个命令做了两件事、第一件事就是使 HEAD 指回 master 分支、而是将工作目录复原成 master 分支所指向的快照内容。也就是说、你当初所做批改的话、我的项目将回到一个较旧的版本。实质上来说、这就是疏忽 testing 粉做所做的批改。

这个时候咱们在 master 分支上进行一次 commit

分支的新建与合并

新建分支

git checkout -b iss53Switched to a new branch "iss53"

$ vim index.html$ git commit -a -m 'added a new footer [issue 53]'

线上呈现问题、须要紧急修复

git checkout mastergit checkout -b hotfix............git commit -m 'hotfix information'

将hotfix 合并到master 分支而后紧急部署上线

$git checkout master$git merge hotfixUpdating f42c576..3a0874c Fast-forwardindex.html | 2 ++1 file changed, 2 insertions(+)

在合并到时候、能够看到 “fast forward” 快进 这个词。因为想要合并到分支 hotfix 所指向的提交 C4 是 C2 的间接后继、因而 Git 会间接将指针向前挪动。换句话说、当你试图合并两个分支时、如果顺着一个分支走上来可能达到另一个分支、那么 Git 合并它时、只会简略讲指针向前推动。这种状况下的合并没有须要解决的一致、叫做快进。

部署紧急修复到生产、而后就能够删除 hotfix 分支了、而后切换到 iss53 中持续工作

git branch -d hotfixgit checkout iss53.......git commit -m 'iss53 some commit information'

当初打算将 iss53 合并到 master 分支中、

git checkout mastergit merge iss53

这和之前合并 hotfix 分支的时候不一样、在这种状况下、iss53的开发历史从一个更早的中央开叉进去、因为master 分支所在提交并不是 iss53 所在提交的间接先人、Git 不得不做一些额定工作。

Git 应用两个分支的末端所指的快照(C4 和 C5) 以及这两个分支的公共先人(C2)、做一个简略的三方合并。

和之前分支指针向前举荐所不同的是、Git将此次三方合并的后果做了一个新的快照并主动创立一个新的提交指向它、这个被称作是合并提交、它的特别之处在于它不止有一个父提交。

遇到抵触时的分支合并

有时候合并并不会那么顺利。如果你在两个不同的分支中、对同一文件的同一个局部进行了不同的批改、Git 就无奈洁净的将它们合并。Git 会暂停下来、期待你解决合并产生的重提、在合并抵触的任意时刻应用 git status 命令来查看那些因合并抵触而处于未合并状态的文件。呈现抵触的文件会蕴含一些非凡的区段、看上去如下

这示意 HEAD 所批示的版本在这个区段的上半局部、而 iss53 分支所批示的版本在 ======= 的下半局部。为了解决抵触、你必须抉择应用 ======= 宰割的两局部中的一个、或者你能够自行合并这些内容。

 <div id="footer">please contact us at email.support@github.com </div>

上述的抵触解决方案保留了其中一个分支的批改、并将<<<<<< 和 =======和>>>>>>这些删除掉。

在你解决了所有文件里的抵触之后、对每个文件应用 git add 命令来将其表尾抵触已解决。一旦暂存这些本来有抵触的文件、Git 就会将它们标为抵触已解决。

分支治理

git branch 命令不仅能够创立和删除分支。如果不加任何参数运行它、则会失去以后所有分支的一个列表。

--merged 与 --no-merged 这两个有用的选项能够过滤这个列表中曾经合并或尚未合并到以后分支的分支。

拉取

当 git fetch 命令从服务器上抓取本地没有到数据时、它并不会批改工作目录中的内容。它只会获取数据而后让你合并。而后有一个命令叫做 git pull 在大多数状况下它的含意是一个 git fetch 紧接着一个 git merge命令。git pull 会查找以后所在分支所跟踪的服务器的分支、而后从服务器抓取数据而后尝试合并入那个近程分支。

删除近程分支

git push origin --delete serverBranchName

rebase

在 Git 中整合来自不同分支的批改次要有两种办法:merge 和 rebase。

如果应用 merge 进行整合分支

如果应用rebase 则是提取C4中引入的补丁和批改、而后在 C3 的根底上利用一次。你能够应用rebase 命令将某个分支的所有批改都迁徙到另一分支上。

在这个例子中、能够将 experiment分支 rebase 到 master 分支上

git checkout experimentgit rebase master

它的原理是首先找到这两个分支的最近独特先人C2、而后比照以后分支绝对于先人的历次提交、提取相应的批改保留为临时文件、而后将以后分支指向指标基底C3、最初将之前的临时文件的批改顺次利用。

最初将 master merge 到 experiment

要用 rebase 须要遵循这么一条准则

如果提交存在于你的仓库之外、而他人可能基于这些提交进行开发、那么不要进行rebase

rebase 操作的理论是抛弃一些现有的提交、而后相应地新建一些内容一样但实际上不同的提交。

总的准则就是、只对尚未推送或分享给他人的本地批改执行 rebase 操作清理历史、从不对已推送到别处的提交执行rebase操作。