版本控制
1、集中化:单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。
优点: 代码存放在单一的服务器上 便于项目的管理
缺点: 服务器宕机: 员工写的代码得不到保障;服务器炸了: 整个项目的历史记录都会丢失
2、分布式(git):客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。每一次的提取操作,实际上都是一次对代码仓库的完整备份
优点: 完全的分布式
缺点: 学习起来比SVN陡峭
Git 简史
Linus和Git由同一个人创造
Git 安装
1、window:https://git-scm.com/download/win
下载完安装包之后,双击 exe 安装包,可以看到如下图窗口界面,一直点击
完成安装之后,就可以使用命令行的 git 工具(已经自带了 ssh 客户端);
2、 git --version,如果可以看到 git 的版本信息,则说明安装成功,
3、Git 初始化配置
每次 Git 提交时都会引用这两条信息,说明是谁提交了更新
$ git config --global user.name “xxx”
$ git config --global user.email xx@example.com
$ git config --list 检查已有的配置信息
$ git config --global --unset user.email 删除配置信息
Git 底层概念(底层命令)
1、基础的 linux 命令
clear :清除屏幕
echo ‘test content’:往控制台输出信息 echo ‘test content’ > test.txt
ll :将当前目录下的 子文件&子目录平铺在控制台
find 目录名: 将对应目录下的子孙文件&子孙目录平铺在控制台
find 目录名 -type f :将对应目录下的文件平铺在控制台
rm 文件名 : 删除文件
mv 源文件 重命名文件: 重命名
cat 文件的 url : 查看对应文件的内容
vim 文件的 url(在英文模式下)
------按 i 进插入模式 进行文件的编辑
------按 esc 键&按:键 进行命令的执行
---------- q! 强制退出(不保存)
---------- wq 保存退出
---------- set nu 设置行号
2、初始化新仓库
git init:在Windows电脑中新建一个文件夹;想使用git来管理这个文件夹,在该文件夹中右键打开git窗口使用git init生成.git文件夹(查看->勾选隐藏项目可见)
hooks 目录包含客户端或服务端的钩子脚本;
info 包含一个全局性排除文件
logs 保存日志信息
objects 目录存储所有数据内容;
refs 目录存储指向数据的提交对象的指针(分支)
config 文件包含项目特有的配置选项
description 用来显示对仓库的描述信息
HEAD 文件指示目前被检出的分支
index 文件保存暂存区信息
git对象:
Git 是如何存储数据的?
将提供的内容生成一个key(hash值):val(压缩后的文件内容)键值对存到.git/objects;键为哈希值(取哈希值的前两位为文件夹名,后部分为被压缩过的文件),值即为内容
1、你可以把哈希值简单地理解成是一段数据(某个文件,或者是字符串)的DNA,或者身份证;
2、通过一定的哈希算法(典型的有MD5,SHA-1等),将一段较长的数据映射为较短小的数据,这段小数据就是大数据的哈希值。他有这样一个特点,他是唯一的,一旦大数据发生了变化,哪怕是一个微小的变化,他的哈希值也会发生变化。另外一方面,既然是DNA,那就保证了没有两个数据的哈希值是完全相同的。
3、正是因为这样的特点,它常常用来判断两个文件是否相同。
git对象就是git中的blod类型;即数据都是以对象的形式存入到数据库中
树对象
不同: 树对象对应项目快照(版本),而git对象只对应文件版本
作用: 往暂存区添加一条记录(让git对象 对应 上文件名)存到.git/index,生成树对象存到.git/objects
当我们的工作区有任何更改同步到暂存区时。就会向暂存区内容写入一个树对象,返回一个 hash 指向树对象
提交对象
需要指定一个树对象的 hash 值,以及该提交的父提交对象;
git commit-tree 不但生成提交对象 而且会将对应的快照(树对象)加上提交信息包装成提交对象最后提交到本地库中;一次提交必然只有一个提交对象、一个树对象和一个以上git对象;
Git 本地操作(高层命令)
git add . 命令的底层原理是,工作目录先生成git对象到版本库,再到暂存区;不考虑底层原理的话,普遍认为的流程是先暂存区,再版本库;
git操作最基本的流程
创建工作目录 对工作目录进行修改
git add ./
git hash-object -w 文件名(修改了多少个工作目录中的文件 此命令就要被执行多少次)
git update-index ...
git commit -m "注释内容"
git write-tree
git commit-tree
git高层命令(CRUD)
git init 初始化仓库
git status 查看文件的状态, 确定文件当前处于什么状态
git diff 查看哪些修改还没有暂存
git diff --staged 查看哪些修改以及被暂存了 还没提交
git log --pretty=oneline 查看提交的历史记录 有完整哈希
git log --oneline 查看提交的历史记录
git add ./ 将修改添加到暂存区
git rm 文件名 删除工作目录中对应的文件 再将修改添加到暂存区
git mv 原文件名 新文件名 将工作目录中的文件进行重命名 再将修改添加到暂存区
git commit // 这种方式会启动文本编辑器以便输入本次提交的说明, 开头还有一空行,供你输入提交说明
git commit -a //-a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,跳过 git add 步骤
git commit -a -m 注释
将暂存区提交到版本库
git高层命令(分支)
创建分支 : git branch branchname
切换分支 : git checkout branchname
创建&切换分支 : git checkout -b branchname
**版本穿梭(时光机)** : git branch branchname commitHash 新建一个分支并且使分支指向对应的提交对象, 然后切换到branchname分支
// 通过 git log --oneline --decorate --graph --all 命令得到 commitHash,
普通删除分支 : git branch -d branchname // 删分支前先回到master分支,-d选项在删除前会提醒没合并
强制删除分支 : git branch -D branchname
合并分支 : git merge branchname
快进合并 --> 不会产生冲突
典型合并 --> 有机会产生冲突
解决冲突 --> 打开冲突的文件 进行修改 add commit
分支本质是一个提交对象,所有的分支都会有机会被HEAD所引用(HEAD一个时刻只会指向一个分支)当我们有新的提交的时候 HEAD会携带当前持有的分支往前移动
命令:git branch
作用:为你创建了一个可以移动的新的指针。 比如,创建一个 testing 分 支:git branch testing。这会在当前所在的提交对象上创建一个指针
git checkout testing 切换分支
总结!!!
安装
git --version
初始化配置
git config --global user.name "damu"
git config --global user.email damu@example.com
git config --list
初始化仓库
git init
C(新增)
在工作目录中新增文件
git status
git add ./
git commit -m "msg"
U(修改)
在工作目录中修改文件
git status
git add ./
git commit -m "msg"
D(删除 & 重命名)
git rm 要删除的文件 git mv 老文件 新文件
git status git status
git commit -m "msg" git commit -m "msg"
R(查询)
git status : 查看工作目录中文件的状态(已跟踪(已提交 已暂存 已修改) 未跟踪)
git diff : 查看未暂存的修改
git diff --cache : 查看未提交的暂存
git log --oneline : 查看提交记录
分支
分支的本质其实就是一个提交对象!!!
HEAD:
是一个指针 它默认指向master分支 切换分支时其实就是让HEAD指向不同的分支
每次有新的提交时 HEAD都会带着当前指向的分支 一起往前移动
git log --oneline --decorate --graph --all : 查看整个项目的分支图
git branch : 查看分支列表
git branch -v: 查看分支指向的最新的提交
git branch name : 在当前提交对象上创建新的分支
git branch name commithash: 在指定的提交对象上创建新的分支(时光机)
git checkout name : 切换分支
git checkout -b name 新建分支并切换 // git branch name ; git checkout name
git branch -d name : 删除空的分支 删除已经被合并的分支
git branch -D name : 强制删除分支
将分支的代码合并到master,先切到主分支master,再执行merge
合并分支 : git merge branchname
快进合并 --> 不会产生冲突
典型合并 --> 有机会产生冲突
解决冲突 --> 打开冲突的文件 进行修改 add 和 commit 操作
查看分支列表 : git branch
查看合并到当前分支的分支列表: git branch --merged
一旦出现在这个列表中 就应该删除
查看没有合并到当前分支的分支列表: git branch --no-merged
一旦出现在这个列表中 就应该观察一下是否需要合并
git分支的注意点
在切换的时候 一定要保证当前分支是干净的!!!(不然在未提交的当前分支上修改会被带到切换的目标分支上, 分支可以切换成功 但是这种操作可能会污染其他分支)
允许切换分支:
分支上所有的内容处于 已提交状态
(避免)分支上的内容是初始化创建 处于未跟踪状态
(避免)分支上的内容是初始化创建 第一次处于已暂存状态
不允许切分支:
分支上所有的内容处于 已修改状态 或 第二次以后的已暂存状态
不提交也可以切换分支
在分支上的工作做到一半时 如果有切换分支的需求, 我们应该将现有的工作存储起来
git stash : 会将当前分支上的工作推到一个栈(先进后出)中
分支切换 进行其他工作 完成其他工作后 切回原分支
git stash list : 查看存储 (建议一般栈只存一条记录)
git status // 可以切换了 git checkout 看提交记录可以看出stash本质上是提交了
git stash apply : 将栈顶的工作内容还原 但不让任何内容出栈
git stash drop : 取出栈顶的工作内容后 就应该将其删除(出栈)
git stash pop : 应用储藏然后立即从栈上扔掉它 , git stash apply + git stash drop ()
一般用这个pop命令
后悔药
撤销工作目录的修改 : git checkout -- filename
撤销暂存区的修改 : git reset HEAD filename
撤销提交 : git commit --amend
1.注释写错了,重新给用户一次机会改注释
// git commit --amend 这个命令会将暂存区中的文件提交。
如果自上次提交以来你还未做任何修改(例如,在上次提交后马上执
行了此命令),那么快照会保持不变,而你所修改的只是提交信息
如果你提交后发现忘记了暂存某些需要的修改,可以像下面这样操作
git commit -m 'initial commit'
git add forgotten_file
git commit –amend
最终你只会有一个提交 - 第二次提交将代替第一次提交的结果
reset三部曲 (后悔药实现原理)
git reset --soft commithash ---> 用commithash的内容重置HEAD内容
git reset [--mixed] commithash ---> 用commithash的内容重置HEAD内容 重置暂存区
git reset --hard commithash ---> 用commithash的内容重置HEAD内容 重置暂存区 重置工作目录
git log :
git reflog : 主要是HEAD有变化 那么git reflog机会记录下来
三部曲 (HEAD~ 表示上一次提交,也可以用commithash 代替)
第一部: git rest --soft HEAD~ // 与后悔药中的 git commit --amend 类似
只动HEAD (带着分支一起移动) , 现在你可以更新索引并再次运行 git commit 来完成 git commit --amend 所要做的事情了。
第二部: git reset --mixed HEAD~ // git reset [--mixed] HEAD~ []中括号表示可选
动HEAD (带着分支一起移动) // 与 后悔药中的撤销暂存区的修改 : git reset HEAD filename类似
动了暂存区
理解一下发生的事情:它依然会撤销一上次 提交,但还会 取消暂存 所有的东西。 于是,我们回滚到了所有 git add 和 git commit 的命令执行之前。
第三部: git reset --hard HEAD~
动HEAD (带着分支一起移动)
动了暂存区
动了工作目录
撤销了最后的提交、git add 和 git commit 命令以及工作目录中的所有工作。 必须注意,--hard 标记是 reset 命令唯一的危险用法,它也是 Git 会真正地销毁数据的仅有的几个操作之一。
第一部曲:带着分支一起移动;
重置回到v3,通过git reflog 查看v3的哈希值,再执行 git reset --soft commithash;
可能执行git commit -m "xxx"也可以,相当于只修改注释;或者
路径reset
所有的路径reset都要省略第一步!!!
第一步是重置HEAD内容 我们知道HEAD本质指向一个分支 分支的本质是一个提交对象
提交对象 指向一个树对象 树对象又很有可能指向多个git对象 一个git对象代表一个文件!!!
HEAD可以代表一系列文件的状态!!!!
git reset [--mixed] commithash filename
用commithash中filename的内容重置暂存区
checkout深入理解
git checkout brancname 跟 git reset --hard commithash特别像
共同点
都需要重置 HEAD 暂存区 工作目录
区别
checkout对工作目录是安全的 reset --hard是强制覆盖
checkout动HEAD时不会带着分支走而是切换分支
reset --hard时是带着分支走
checkout + 路径
git checkout commithash filename
重置暂存区
重置工作目录
git checkout -- filename
重置工作目录