精通Git--进阶

第一篇《精通Git–基础》已经对 Git 的基本使用有了了解,接下来这一篇来看一下平时工作中会遇到的一些比较棘手的问题。

GitHub 操作演示

远程 git 仓库

在 GitHub 创建仓库有两种方式,一种是当前没有仓库,我们需要新建一个 git 仓库:

还有一种情况,我们事先已经有了一个仓库,需要迁移过来,就可以使用 GitHub 的迁移功能:

本地 git 仓库

当我们远程 Git 仓库创建好后,有两种情况:

第一种情况,本地什么代码都没有,需要新建仓库,新建一个文件夹,例如我们叫 myGitWork,然后进入该目录执行如下命令:

在此之前你也可以添加一些文件,比如 READEME.md, 添加一些内容:

1
echo "# testGit" >> README.md
1
2
3
4
5
git init
git add README.md
git commit -m "first commit"
git remote add origin git@github.com:lxqxsyu/testGit.git
git push -u origin master

此时我们可能不太理解这个 git push -u 中的 -u 参数,使用 git help push 命令查看帮助:

这个 -u 参数在推送本地文件到远程仓库 origin 的同时,指定了 origin 为默认远程主机,后面就不用再加参数,直接使用 git push 命令了。

还有一种情况,我们本地已有仓库,此时只需要给添加远程仓库地址即可:

1
2
git remote add origin git@github.com:lxqxsyu/testGit.git
git push -u origin master

版本回退

工作区回退

假设我们此时我们修改了 README.md 文件,新增了一句话:

1
2
3
# testGit

这个是测试 Git 的例子

如果我们要撤销,很简单,执行 git checkout -- <file>:

1
git checkout -- README.md

这个命令会撤销所有你对该文件的修改,回到本地仓库中的文件状态。

暂存区回退

假设上面的 README.md 文件已经修改,而且我们执行了 git add . 将该文件添加到了暂存区:

1
2
3
4
5
6
7
8
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

modified: README.md

我们如果要回退到工作区,则使用上面建议的 git reset HEAD <file> 命令即可:

1
git reset HEAD README.md

本地仓库回退

假设我们上面的 README.md 文件的修改我们提交到了本地仓库 git commit -m "change",我们如何回退到之前的版本呢。

首先,我们使用 git log 查看一下最近提交的信息:

1
2
3
4
5
6
7
8
9
10
11
12
$ git log
commit ee3f15b78078da32e65c8fcbfba31c939995b479 (HEAD -> master)
Author: lxqxsyu <lxq_xsyu@163.com>
Date: Tue Aug 13 10:39:30 2019 +0800

change

commit ebf060a6a67b003c2fd0609a5e50ca322248489f (origin/master)
Author: lxqxsyu <lxq_xsyu@163.com>
Date: Tue Aug 13 10:22:43 2019 +0800

first commit

接下来使用命令 git reset --hard 来回退到某个版本(使用 commit 的 id 前几位即可):

1
2
$ git reset --hard ebf0
HEAD is now at ebf060a first commit

此时就强制回退到了上次提交的状态。假设我们还想让上一个版本的修改存在于暂存区怎么办?

1
$ git reset --soft ebf0

远程仓库回退

实际上远程仓库回退和本地仓库回退是一样的,因为都要通过本地回退,然后 push 到远程仓库,但是 push 的时候会出错:

1
2
3
4
5
6
7
8
$ git push
To github.com:lxqxsyu/testGit.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'git@github.com:lxqxsyu/testGit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

此时要使用 git push origin HEAD --force 推到远程仓库:

1
git push origin HEAD --force

回退的原理

回顾一下上一篇提到的分支部分的示意图, 我们已经知道每一次提交都会产生一个新对象(commit 对象)指向我们的文件新快照,而 HEAD 游标指向的分支(下图的 master 和 testing 是两个分支)会指向这个新的对象,假设当前分支是 master 则 master 分支会向前移动指向新的 commit 对象。

Git分支示意图

HEAD 是当前分支引用的指针,它总是指向该分支上的最后一次提交。 这表示 HEAD 将是下一次提交的父结点。 通常,理解 HEAD 的最简方式,就是将它看做 你的上一次提交 的快照。

查看 HEAD 快照:

1
2
3
4
5
6
$ git cat-file -p HEAD
tree ac029782a50527dc4e717dad7572cc3b2afb5ad8
author lxqxsyu <lxq_xsyu@163.com> 1565662963 +0800
committer lxqxsyu <lxq_xsyu@163.com> 1565662963 +0800

first commit

除了上面的 HEAD 指针外,还有一个 索引 的概念,索引是你的 预期的下一次提交。 我们也会将这个概念引用为 Git 的 暂存区域,这就是当你运行 git commit 时 Git 看起来的样子。

我们前面提到的文件快照(文件的变化)都保存在 .git 文件夹中,工作区,暂存区,HEAD游标的关系如图:

Git工作中指针的变化过程

你可以这样理解,上图中的文件的三个状态都对应着一个文件快照树,我们的状态改变只不过是这个索引的改变而已,或者说是指针的移动而已。

接下来我们来以指针角度分析一下仓库文件变化的过程:

1
git init

此时 HEAD 和 master (有可能 master 还不存在) 都处于游离状态,没有固定指向。假设我们现在放入一个文件:

1
echo "# testGit" >> README.md

此时处于工作区,和暂存区(索引),本地仓库(HEAD)没有任何的关系:

1
git add README.md

此时暂存区的索引指向了此次 git add 的文件快照树:

1
git commit -m "change"

这个时候 HEAD 索引指向的分支(此时是 master 分支)指向暂存区索引的文件快照树:

接下来修改文件内容:

1
2
3
# testGit

这个是测试 Git 的例子

此时指向 git status 会检查工作区的文件快照和暂存区的文件快照是否一致,不一致就会显示 modified: README.md

此时再执行 git add README.md 暂存区的索引就会指向工作区新的文件快照树的根。

接下来我们执行 git reset 命令:

1
git reset HEAD README.md

reset(重置) 命令的本质是移动 HEAD 所指向的分支的指针,上面的 git reset HEAD 等价于 git reset --mixed HEAD , 它会把暂存区清空,并把原节点和 reset 节点的差异的文件放在工作目录,总而言之就是,工作目录的修改、暂存区的内容以及由 reset 所导致的新的文件差异,都会被放进工作目录。

我们上面尝试 git reset --hard 来回退本地仓库的代码:

1
2
$ git reset --hard ebf0
HEAD is now at ebf060a first commit

这里的 --hard 参数的意思是重置 HEAD 和指向的分支指针位置,同时重置暂存区和工作目录的内容。所以你使用 git status 会看到仓库回退后暂存区和工作区都清空了。

如果我们使用 --soft 参数就可以保留暂存区,并把重置 HEAD 所带来的新的差异放进暂存区,而且会保留工作区内容, 下方示意图的 4 和 3 的差异:

1
$ git reset --soft ebf0

这里我们已经大概能总结出 git reset 的一些特点了:

操作仓库(commit 状态)

  1. 如果加参数 git reset --hard <commitId> <file> 会清空工作目录和暂存区的改动,回退到上一个 commit.
  2. 如果加参数 git reset --soft <commitId> <file> 会保留工作目录和回退的 commit 版本与 HEAD 指向的 commit 版本的差异保留在暂存区。
  3. 如果不加参数 git reset <commitId> <file> 默认是 --mixed , 则会保留工作区,清空暂存区,将会把所有差异放入工作区。

操作暂存区(stage 状态)

  1. 如果不加参数 git reset HEAD <file> 等效于 git reset --mixed HEAD <file> 是重置暂存区,并把差异放入工作区。

评论

3D Adapter Ajax Android AndroidStudio Animation Anroid Studio AppBarLayout AsyncTask Babel Banner Buffer Bulma ByteBuffer C++ C11 C89 C99 CDN CMYK CSS Camera Raw Canvas Chrome Class ContentProvider CoordinatorLayout C语言 DML DOM Dagger Dagger2 Darktable Demo Document DownloadManage ES2015 ESLint Element Elements Error Exception Extensions File FileProvider FileSave Flow Fresco GCC Git Git flow GitHub GitLab Github flow Gitlab flow Glide Gradle GrideView Groovy HTML HTML5 Handler HandlerThread Hexo Hilo Hybrid I/O IDEA IO ImageMagick ImageView IntelliJ Intellij Intent Interpolator JCenter JNI JS Java JavaScript JsBridge Kotlin Lab Lambda Lifecycle Lint Linux ListView Looper MQTT MVC MVP Maven MessageQueue Modbus Momentum MySQL NDK NIO Next Nodejs ObjectAnimator Okhttp Oracle VM Permission PhotoShop Physics Process Python RGB RS-232 RTU RecyclerView Remote-SSH Retrofit Runnable RxAndroid RxJava SE0 SQLite SSH SharePreference Spring SpringBoot Statubar Style Task Theme Thread Tkinter UI UIKit UML VM virtualBox VS Code VUE ValueAnimator ViewPropertyAnimator Vue Vue CLI Vue.js Web WebGL Web前端 Workbench Zdog api apk axios background blur bookmark by关键字 cli compileOnly component computed css css3 c语言 databases demo flex flexbox flow gradient hexo hotfix html iOS icarus icarus主题 implementation init jQuery javascript launchModel linear logo merge methods mvp offset photos pug query radial rxjava2 scss servlet shell slot slot-scope svg tkinter tomcat transition unicode utf-8 v-slot vector virtual box vscode watch webpack 七牛 下载 中介者模式 串口 临潼石榴 主题 书签 书籍 事件 享元模式 亮度 仓库 代理模式 位运算 依赖注入 修改,tables 光和色 入坑 入门视频教程 全套视频教程 内存 内核 内部分享 函数 函数式编程 分支 分析 列表 创建 删除 动画 单例模式 发布 可空性 合并 同向性 后期 启动模式 命令 命令模式 响应式 响应式编程 图层 图床 图形图像 图片压缩 图片处理 图片轮播 地球 域名 基础 增加 备忘录模式 外观模式 多线程 大爆炸 天气APP 太白山 头文件 奇点 字符串 字符集 存储引擎 宇宙 宏定义 实践 对比度 属性 属性动画 岐山擀面皮 岐山肉臊子 岐山香醋 工作流 工具 工厂模式 年终总结 开发技巧 开发流程 异常 弱引用 思想 恒星 打包 扫盲 技巧 指令 指针 接口 插件 插值 插槽 摄影 操作系统 攻略 故事 数据存储 数据库 数据类型 数组 文件 新功能 旅行 旋转木马 时序图 时空 时间简史 曲线 最佳实践 服务 杂谈 权限 枚举 架构 查询 标准库 标签选择器 样式 核心 框架 案例 桥接模式 检测工具 模块化 模板 模板引擎 模板方法模式 油泼辣子 泛型 洛川苹果 浅色状态栏 混合模式 渐变 渲染 游戏 源码 源码分析 滤镜 瀑布流 灰度 热修复 版本 版本回退 版本控制 状态栏 状态模式 生活 界面 留言板 直方图 相册 相对论 眉县猕猴桃 知识点 码云 磁盘 科学 笔记 策略模式 类图 系统广播 系统概述 系统,发行版, GNU 索引 组件 组合模式 绑定 结构 结构体 编码 编程 网易云信 网格布局 网站广播 网站通知 网络 美化 联合 背景 背景混合 脚手架 膨胀的宇宙 自学Android 自定义 自定义View 自定义插件 色调 蒙版 虚拟 虚拟机 补码 补齐 表单 表达式 装饰模式 西安 观察者模式 规范 视图 视频 视频教程 解耦器模式 设计 设计原则 设计模式 访问者模式 语法 责任链模式 贪吃蛇 走马灯 转换 软件工程 软引用 过滤器 运算符 进程 迭代子模式 适配器 适配器模式 选择器 通信 通道 配置 链表 锐化 错误 键盘 闭包 降噪 陕西地方特产 面向对象 项目优化 项目构建 饱和度 高斯模糊 黑洞
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×