版本控制最重要的就是历史记录
集中化的版本控制系统诸如 cvs,svn以及 perforce 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新
优点:每个人都可以在一定程度上看到项目中的其他人正在做些什么。而管理员也可以轻松掌控每个开发者的权限,并且管理一个集中化的版本控制系统; 要远比在各个客户端上维护本地数据库来得轻松容易
缺点:
① 中央服务器的单点故障。如果服务器宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作
② 中央服务器的磁盘发生故障,碰巧没做备份,或者备份不够及时,就会有丢失数据的风险
③ 最坏的情况是彻底丢失整个项目的所有历史更改记录
在这类系统中,像 Git,BitKeeper 等,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。因为每一次的提取操作,实际上都是一次对代码仓库的完整备份。
分布式的版本控制系统在管理项目时 **存放的不是项目版本与版本之间的差异.**它存的是索引(所需磁盘空间很少所以每个客户端都可以放下整个项目的历史记录)
解决了集中式版本控制系统的缺陷:
① 断网的情况下可以进行开发(因为版本控制是在本地进行的),连不上服务器也可以进行开发!
② 每个客户端保存的也都是整个完整的项目(包含历史记录的! 更加安全)
三条主线:
1. 集中式版本控制系统 vs 分布式版本控制系统
2. 工作目录 暂存区 版本库
workspace : 工作目录
.git/index: 暂存区
.git/objects: 版本库
3. git对象 树对象 提交对象
git对象: git存储内容的最基本单位;一个git对象代表一个文件的版本
缺点: 没有存储文件名;记住git对象的hash不太现实
树对象: 是暂存区在某一时刻的快照;一个树对象代表一个项目的版本
缺点: 没有项目版本的注释;记住树对象的hash不太现实
提交对象: 是对树对象的包裹;记住提交对象的hash不太现实
缺点: 记住提交对象的hash不太现实
分支: 本质就是一个提交对象
可以不用再记提交对象的hash;记住当前所处的分支即可(默认主分支master)
hooks 目录包含客户端或服务端的钩子脚本;
info 包含一个全局性排除文件
logs 保存日志信息
objects 目录存储所有数据内容(版本库)
refs 存所有分支
config 文件包含项目特有的配置选项
description 用来显示对仓库的描述信息
HEAD 当前所处分支
index 暂存区信息
Git 的核心部分是一个简单的键值对数据库。你可以向该数据库插入任意类型的内容,它会返回一个键值,通过该键值可以在任意时刻再次检索该内容
创建一个新文件并将其内容存入数据库:
echo 'version 1' > test.txt : 创建一个新文件
git hash-object -w 文件路径;(将文件内容以bolb的格式存储到git的版本库中)
git hash-object 文件路径 :返回对应文件的键值 hash值
查看数据内容:
find .git/objects -type f : git存储数据
git cat-file -p hash ; 通过hash拉取对应的内容
git cat-file -t hash ; 通过hash拉取对应的内容的类型
问题:
① 记住文件的每一个版本所对应的 SHA-1 值并不现实
② 在Git中,文件名并没有被保存——我们仅保存了文件的内容
解决:树对象
树对象(tree object),它能解决文件名保存的问题,也允许我们将多个文件组织到一起。一个树对象包含了一条或多条记录(每条记录含有一个指向git对象或者子树对象的 SHA-1 指针,以及相应的模式、类型、文件名信息)。一个树对象也可以包含另一个树对象
创建首个版本-创建一个暂存区
echo 'version 1' > test.txt
git hash-object -w test.txt
git update-index --add --cacheinfo 100644 git对象的hash 文件名:修改暂存区
git write-tree : 生成树对象
将两个版本塞入暂存区
echo 'new file' > new.txt
.....编辑test.text
git update-index --add 文件名(new.txt)
等价于下面两个:
git hash-object -w test.txt 生成new.txt对应的hash
git update-index --add --cacheinfo 100644 git对象的hash new.txt
git update-index --add test.txt
git write-tree 第二个树对象
将第一个树对象加入第二个树对象,使其成为新的树对象
git read-tree -prefix=bak hash 把树对象读入暂存区
git write-tree
git ls-files -s : 查看暂存区
我们可以通过调用 commit-tree 命令创建一个提交对象,为此需要指定一个树对象的 SHA-1 值,以及该提交的父提交对象(如果有的话 第一次将暂存区做快照就没有父对象)
创建提交对象:
echo "注释" | git commit-tree 树对象的hash -p 上一次的提交对象的hash
echo 'second commit' | git commit-tree 0155eb -p fdf4fc3
查看提交对象:
git cat-file -p hash
注意:
git commit-tree不但生成提交对象而且会将对应的快照(树对象)提交到本地库中
git init : 初始化git仓库;生成一个.git目录
.git/objects : 版本库
.git/index : 暂存区
.git/HEAD : 版本库当前所处的分支
git add ./ : 将当前目录下的所有文件加入到版本库生成对应的git对象
再将每一个git对象及其对应的文件名注册到暂存区
相当于 git hash-object & git update-index的结合
git commit -m "注释" : 对暂存区做快照生成对应的树对象;
对树对象进行包裹注释;生成对应的提交对象
将当前生成的提交对象的hash赋值给主分支
相当于 git write-tree & git commit-tree的结合
cls : 清除屏幕
clear :清除屏幕
echo 'test content':往控制台输出信息
echo 'test content' > test.txt : 创建文件并将控制台的信息放到该文件中
ll :将当前目录下的 子文件&子目录平铺在控制台
find 目录名: 将对应目录下的子孙文件&子孙目录平铺在控制台
find 目录名 -type f :将对应目录下的文件平铺在控制台
cat 文件的url : 查看对应文件的内容
mv 源文件 重命名文件: 重命名
rm 文件名 : 删除文件
vim 文件的url(在英文模式下)
按 i 进插入模式 进行文件的编辑
按 esc键再按:键 进行命令的执行
q! 强制退出(不保存)
wq 保存退出
set nu 设置行号
初始化仓库:git init
查看文件状态:git status
加入暂存区: git add ./
提交到版本库: git commit -m "注释"
跳过暂存区进行提交(对应的文件已经被提交过一次) git commit -a -m "注释"
git status:查阅新增和修改的文件
git add ./ & git commit -m "注释"
git status:查阅新增和修改的文件
git add ./ & git commit -m "注释" 或者 git commit -a -m "注释"
删除工作目录中对应的文件 & git add ./
git commit -m "注释" 或者 git rm 对应的文件
git commit -m "注释"
git status:查看项目中文件的状态
红:文件没有被纳入到暂存区
绿:文件纳入到暂存区但是还未提交
空:文件已经被提交
git log --oneline:查看提交链 (当前分支所拥有的提交链,看不到完整的提交链)
git diff : 当前做的哪些事情还没有暂存
git diff --staged :有哪些更新已经暂存起来准备下次提交
git reflog
重命名对应的文件 & git add ./
git commit -m "注释"
或者
git mv 原文件名 新文件名
git commit -m "注释"
git congif --list : 查看本地的git配置,所有alias开头的都是别名配置
git config --global alias.damu status : 新增别名
git congfig --global --unset alias.damu : 删除别名
配置别名:
$ 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 config --global alias.lol “log --oneline --decorate --graph --all”
可以看到完整的分支图
git branch
git branch name 指向当前所处分支所指向的提交对象
git branch -merged 查看哪些分支已经合并到当前分支
git branch --no-merged 查看所有包含未合并工作的分支
git branch name commitHash 新建一个分支并且使分支指向对应的提交对象
git checkout name (不用考虑上下级关系)
最佳实践:一定要在最干净的状态下切换(没有提交到仓库)git st 查看
如果在切换分支的时候,状态不干净,又必须得切,要使用git存储
git checkout -b name 切换并新建分支
最佳实践:不要再空分支上切换分支
切换分支的时候动了几个区域?
① HEAD ② index(暂存区) ③工作目录
git stash:将当前内容存储起来
git stash list:查看存储
git stash apply 存储名: 应用存储
git stash drop 存储名:删除存储
git stash pop 应用栈顶存储并删除
git merge 分支名 分清谁合并谁 上级合并下级,并删除下级
快进合并:永远都不会产生冲突,也不会生成新的提交对象
典型合并:可能会产生冲突,一定会生成新的提交对象
git branch -d name
git branch -D 强制删除
原有代码:master.txt 是稳定的代码,不要动。初始化开发
分支代码:dev.txt
git checkout -b dev
git branch ----master dev
git chenkout -b wang 在dev上新建切换wang.txt 并提交 修改再保存 git status
git stash git st 保存起来
git checkout master git log --oneline 不能直接改
git chenkout -b hotbug 重新切一个 修改并提交 查看git log --oneline
git checkout master git merge hotbug 在主分支上进行合并(快进合并)
git branch -d hotbug 在主分支上删除紧急分支 查看git status
git stash list
git stash pop 拿到并删除
进行最终的提交
git log --oneline 只能查看当前文件下的对象
git lol(lol是别名)
git checkout dev 在dev上合并并进行删除
git merge wang
git branch -d wang
git checkout master(记得检查是够干净模式)
git merge dev 会生成一个新的提交对象 进入vim模式 i(插入) esc wq!(保存退出)
git branch -d dev
演示冲突:
在master创建v1.txt并提交 修改再次提交 git lol
git co -b a 修改再次提交
切到master git co -b b
再次修改 提交 git lol
在masret 快速合并 git merge b 删除git br -d b git lol
git merge a 产生了冲突 沟通好后手动修改提交即可git add ./ git commit -m ""
制定提交对象创建分支
git branch name(分支名) commithash(提交对象的hash)
git lol
git ls-files -s 查看暂存区内容 git cat-file -p hash
cat .git/HEAD 查看head内容
git reset --soft commithash(HEAD~) 动HEAD
git reset --mixed HEAD~ 动了两个区域 动HEAD index
git reset --hard HEAD~ 动了三个区域 动HEAD index 工作目录
切换分支:git checkout 分支名 也是动了三个区域 但是有保护机制,防止数据丢失
git reset --soft HEAD~ filepath :不允许进行路径重置的
git reset [--mixed] commithash filepath:支持路径重置,动index,不建议指定提交对象
建议使用 git reset filepath 相当于 git reset HEAD filepath
git reset --hard commithash filepath:
不允许进行路径重置,可以hard的变种checkout支持,只动index,工作目录
git checkout 分支名 filepath 相当于 git reset --hard 分支名对应的提交对象 filepath
git checkout -- filepath 相当于 git reset --hard HEAD filepath
git checkout -h 信息查询
git checkout 路径(可以是文件也可以是文件夹)
git reset file
git commit ---amend -m "重新填注释"
相当于 git reset --soft HEAD~ 加 git commmit -m "重新填注释"
git log 看不到上次的提交
git reflog
git add ./
git commit --amend -m "重新填注释"
版本的回滚
git st
git reset --hard hash
回滚到之前的版本
git reflog
git reset --hard hash
① 直接记录快照,而非差异比较
② 近乎所有操作都是本地执行
③ 时刻保持数据完整性
④ 文件的三种状态
远程仓库是指托管在因特网或其他网络中的你的项目的版本库。与他人协作涉及管理远程仓库以及根据需要推送或拉取数据。
本地创建的master,dev等
远程仓库的别名/分支名 存在于本地仓库
在git push ..远程仓库的别名 分支名 的时候,git会在本地帮助我们生成跟踪分支
远程仓库的master,dev等
推送:git push 远程仓库别名 分支名
拉取更新数据到跟踪分支:git fetch 远程仓库别名
本地分支合并跟踪分支获取更新: git merge 跟踪分支
① 在第一次往远程仓库推送分支的时候,可以建立关系
git push -u 远程仓库的别名 分支名
② 错过上述情况
git branch -u 跟踪分支
③ 克隆仓库
master分支自动跟踪
④ 克隆仓库
git checkout 分支名(必须存在对应的跟踪分支)
git branch -vv
git clone 远程仓库地址
git push 远程别名 --delete 分支名
git remote prune 远程别名 --dry-run 列出仍在远程跟踪但是远程已被删除的无用分支
git remote prune 远程别名 清楚上面命令列出来的远程跟踪
码云 github gitlab…
初始化仓库: git init
在master分支上 上传基本代码
基于master分支切出dev分支 上传一些需求等...
基于dev分支切出自己的个性化分支 进行需求开发
需求开发完成之后 切到dev分支合并自己的个性化分支....
切到dev,合并dev和个性化分支 :git merge 个性化分支 查看:git lol
1. 查看别名 : git remote -v
2. 新增别名 : git remote add 别名 仓库地址
3. 删除别名 : git remote rm 别名
git push 远程仓库的别名 分支名 (不会建立跟踪关系)
git branch -u 跟踪分支(jd/dev) (重新建立本地与跟踪分支的一对一关系)
等价于
git push -u 远程仓库的别名 分支名
git branch -vv:查询有没有关系
git remote -v:查看别名
git push
git pull
git clone url :
1. 将远程仓库的所有内容都下载到本地 git lol
2. 在本地新建所有与远程对应的跟踪分支 git br -vv
3. 默认建立master分支与其对应的跟踪分支之间的一对一关系
git checkout dev :
1. 在本地新建dev分支
2. 建立dev分支与其对应的跟踪分支之间的一对一关系
3. 将远程dev分支的数据拉取到本地dev上
4. 切换到dev分支
基于dev分支切出自己的个性化分支 进行需求开发
需求开发完成之后 切到dev分支合并自己的个性化分支....
git push
git pull(git fetch + git merge)
eg:git fetch jd:将远程更新拉取到跟踪分支
git merge jd/dev 合并跟踪分支
git br -u jd/dev 关联dev关系 git branch -vv
先看看控制面板里的用户账户--凭据管理器有没有地址
先做主分支 提交,再做dev分支(新建文件dev.mk,提交)
在dev上创建分支wang分支 创建文件wang.html再次提交
切到dev,合并 git merge wang git lol
配置:git remote add https://gitee.com/wangxiu216/jdong.git git remote -v
推送:git push jd master git push jd dev
项目经理修改dev.md内容,再次提交,但是远程没有更新
git branch -vv:查询有没有关系 git push jd dev:需要指定分支 此操作是在本地上
在仓库里直接修改dev.md并提交 但是本地不知道 没有建立一对一关系
git fetch jd将远程的更新拉取到跟踪分支上 git merge jd/dev合并即可看到更新的内容
git br -u jd/dev:关联dev关系 git branch -vv :有蓝颜色的跟踪分支
本地修改dev.md 提交 git st git push :建立了跟踪关系,就可以直接push
远程修改 就可以直接git pull 将master也进行跟踪
克隆:git br -vv 主分支默认跟踪 切换 git co dev
为第三方库做贡献
公司项目遇到了很大的问题,团队问题解决不了,需要请外援
① fork目标仓库
② 克隆frok完仓库 新建自己的个性化分支 进行修改并提交
③ 进行代码的合并 在dev上进行合并 git push 到远程
④ push代码 提pr
⑤ 目标仓库审核检验
⑥ 合并br
⑦ fork仓库使用fetch命令订阅目标仓库的更新
git remote add 别名 地址
git fetch 别名
git merge 跟踪分支
删除新建的个性化分支
再次新建分支进行业务开发
注意点:
每次在发起新的Pull Request时 要去拉取(git pull)最新的源仓库的代码 而不是自己fork的那个仓库。
Git 可以给历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点(v1.0 等) 也是一个提交对象,跟分支的本质一样
git tag
轻量标签很像一个不会改变的分支 - 它只是一个特定提交的引用
git tag vx.y.z hash(可以默认) X(库产生巨大的改变) Y(新增API) Z(解决bug)
附注标签是存储在 Git 数据库中的一个完整对象,可以被检验。
git tag -a vx.y.z
git show v.0.0
git br vx hash
git co -b vx
git push 远程别名 vx.y.z
git push 远程别名 --tags 一次性推送很多标签
git tag -d vx.y.z
git push origin :refs/tags/v1.4 更新远程仓库
https://www.toptal.com/developers/gitignore
https://github.com/github/gitignore
一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件模式。