git思维导图

Git工作区域

为了说明我们日常开发中执行的一系列Git命令的作用是什么,我们需要了解Git的工作区域的概念,几乎每一个常见的Git命令操作都可以通过工作区域来解释。

Git本地有四个工作区域:

  • 工作区(Working Directory):在git init之后的本地的文件目录下,也就是大家写代码的地方

  • 暂存区(Staged/Index):修改了代码之后,需要先将改动add到暂存区,表示将要提交的改动

  • 本地仓库(Local Repository):本地Git仓库,通俗讲就是本地隐藏文件.git目录下,存储着你的所有改动

  • 远程仓库(Remote Repository):远程Git仓库,理论上和本地仓库地位平等,但是主要是用于多个开发者之间pull/push代码的仓库。

四个工作区域

Git 文件状态

接下来我们来看下Git文件的状态:

Git 文件状态
  • UnTracked: 未跟踪,此文件在文件夹中,但并没有加入到git库,不参与版本控制。通过git add 状态变为Staged。

  • UnModify: 文件已经入库,未修改, 即版本库中的文件快照内容与文件夹中完全一致。这种类型的文件有两种去处,如果它被修改,而变为Modified。如果使用git rm移出版本库,则成为UnTracked文件。

  • Modified: 文件已修改,仅仅是修改,并没有进行其他的操作。这个文件也有两个去处,通过git add可进入暂存staged状态,使用git checkout 则丢弃修改过,返回到unmodify状态,这个git checkout即从库中取出文件,覆盖当前修改。

  • Staged: 暂存状态,执行git commit则将修改同步到库中,这时库中的文件和本地文件又变为一致,文件为UnModify状态。执行git reset 取消暂存,文件状态为Modified。

Git 基本命令

在了解Git工作区域、文件状态以及本地仓库的相关信息之后,相信大家对于日常使用的一些命令都有了更加深刻的理解。接下来,我们一起进行一个常用命令总结:

  • git clone:将远程仓库克隆到本地,也就是创建了一个本地仓库,会出现隐藏文件.git

  • git status:查看状态,可以看到哪些文件被修改、哪些是未跟踪的文件

  • git diff:可以看到当前工作区和暂存区staged中的文件diff

  • git add:将未跟踪(新增加)或者修改过的文件从工作区添加到暂存区staged中

  • git commit:将暂存区staged中的内容提交到本地Git仓库中

  • git push:将本地Git仓库中的内容提交到远程Git仓库中

并且如果是单人开发,自己玩的情况下,貌似这些命令就足够了。但是,在实际的开发当中,我们往往会面对更加复杂的场景,需要一些更为复杂的命令来处理,我们接着往下看。

git merge

在当前分支上执行git merge master可以将master的提交合并merge到当前分支,也就是更新本地分支。我们日常开发中,将本地代码推到远程仓库,建立Merge Request,然后点击Merge按钮其实就是在master分支上merge了开发分支。

merge
git fetch

git fetch可以将远程分支拉到本地:

git fetch 会将所有远程分支都拉到本地
git fetch origin sowhat1412  指定拉取远程origin仓库的sowhat1412分支到本地
git pull

当我们想要更新本地分支代码的时候,需要将远程开发分支或者远程master分支代码拉到本地,并且合并到当前开发分支上。所以git pull = git fetch + git merge
在当前开发分sowhat1412上,我们执行如下的命令:

git pull origin master
表示将远程master分支拉到本地并且merge到当前分支sowhat1412上
git rebase

rebase会把你当前分支的 commit 放到公共分支的最后面,所以叫变基。就好像你从公共分支又重新拉出来这个分支一样。
举例:如果你从 master 拉了个feature分支出来,然后你提交了几个 commit,这个时候刚好有人把他开发的东西合并到 master 了,这个时候 master 就比你拉分支的时候多了几个 commit,如果这个时候你 rebase master 的话,就会把你当前的几个 commit,放到那个人 commit 的后面。

git rebeae

merge 会把公共分支和你当前的commit 合并在一起,形成一个新的 commit 提交

git merge
git cherry-pick

对于多分支的代码库,将代码从一个分支转移到另一个分支是常见需求。

这时分两种情况。一种情况是,你需要另一个分支的所有代码变动,那么就采用合并(git merge)。另一种情况是,你只需要部分代码变动(某几个提交),这时可以采用 Cherry pick。

git cherry-pick命令的作用,就是将指定的提交(commit)应用于其他分支。

$ git cherry-pick <commitHash>

上面命令就会将指定的提交commitHash,应用于当前分支。这会在当前分支产生一个新的提交,当然它们的哈希值会不一样。

举例来说,代码仓库有master和feature两个分支。

a - b - c - d       Master\e - f - g Feature

现在将提交f应用到master分支。

# 切换到 master 分支
$ git checkout master# Cherry pick 操作
$ git cherry-pick f

上面的操作完成以后,代码库就变成了下面的样子。

a - b - c - d - f  Master\e - f - g   Feature

从上面可以看到,master分支的末尾增加了一个提交f。

git cherry-pick命令的参数,不一定是提交的哈希值,分支名也是可以的,表示转移该分支的最新提交。

$ git cherry-pick feature
上面代码表示将feature分支的最近一次提交,转移到当前分支。

Cherry pick 支持一次转移多个提交。

$ git cherry-pick <HashA> <HashB>

上面的命令将 A 和 B 两个提交应用到当前分支。这会在当前分支生成两个对应的新提交。

如果想要转移一系列的连续提交,可以使用下面的简便语法。

$ git cherry-pick A..B

上面的命令可以转移从 A 到 B 的所有提交。它们必须按照正确的顺序放置:提交 A 必须早于提交 B,否则命令将失败,但不会报错。

注意,使用上面的命令,提交 A 将不会包含在 Cherry pick 中。如果要包含提交 A,可以使用下面的语法。

$ git cherry-pick A^..B
git reset
  • git reset commitId

该命令执行之后,HEAD指针会移动到选中commitId上,并且之前的HEAD ->commitId之间的所有修改的内容会被置于工作区,需要重新add、commit。
  • git reset --soft commitId

该命令执行之后,HEAD指针会移动到选中commitId上,并且之前的HEAD ->commitId之间的所有修改的内容会被直接置于暂存区staged中,也就是后续只需要执行commit操作就OK了
  • git reset --hard commitId

这个--hard很好理解,就是在回滚HEAD指针的时候,很强硬的将所有HEAD ->commitId之间的改动内容“全部删除”!
为什么加引号?因为前边我们说了Git不会丢失任何你提交过的内容(只要你玩的溜),后续我们会分析原因。
git reflog
  1. 新建一个目录git-test,初始化一下仓库,做一次简单的提交

mkdir git-test
cd git-test/
git init
echo 0 > test
git add .
git commit -am "init"
  1. 假设这几个星期你做了三次重要代码的提交:

linux-geek:/home/tmp/git-test # echo "important code0" >> test
linux-geek:/home/tmp/git-test # git commit -am "important code0"
[master 03f85a1] important code0  1 files changed, 1 insertions(+), 0 deletions(-)
linux-geek:/home/tmp/git-test # echo "important code1" >> test
linux-geek:/home/tmp/git-test # git commit -am "important code1"
[master 83547ba] important code1  1 files changed, 1 insertions(+), 0 deletions(-)
linux-geek:/home/tmp/git-test # echo "important code2" >> test
linux-geek:/home/tmp/git-test # git commit -am "important code2"
[master b826ae5] important code2  1 files changed, 1 insertions(+), 0 deletions(-)
linux-geek:/home/tmp/git-test # cat test
0
important code0
important code1
important code2
  1. 就在这个时候,假设你头脑突然短路,用了git reset这条命令:

linux-geek:/home/tmp/git-test # git reset --hard HEAD~3
HEAD is now at 2e71cf6 init

再来看一下代码的情况:

linux-geek:/home/tmp/git-test # cat test
0

有没有什么办法补救呢?答案是肯定的!

  1. 用git reflog来看一下

linux-geek:/home/tmp/git-test # git reflog
2e71cf6 HEAD@{0}: HEAD~3: updating HEAD
b826ae5 HEAD@{1}: commit: important code2
83547ba HEAD@{2}: commit: important code1
03f85a1 HEAD@{3}: commit: important code0
2e71cf6 HEAD@{4}: commit (initial): init

其中,我们可以清楚地看到HEAD每次移动的情况以及哈希值,于是乎我们再采用git reset去试一下:

linux-geek:/home/tmp/git-test # git reset --hard HEAD@{1}
HEAD is now at b826ae5 important code2
  1. 我们再来看一下代码的情况:

linux-geek:/home/tmp/git-test # cat test
0
important code0
important code1
important code2
  1. 此时用 git log 或 git log --pretty=oneline 可以看到全部的历史记录又恢复回来了。

git revert

revert 是回滚某个 commit ,不是回滚到某个。git revert是用于反做某一个版本,以达到撤销该版本的修改的目的。比如,我们commit了三个版本(版本一、版本二、 版本三),突然发现版本二不行(如:有bug),想要撤销版本二,但又不想影响撤销版本三的提交,就可以用 git revert 命令来反做版本二,生成新的版本四,这个版本四里会保留版本三的东西,但撤销了版本二的东西。如下图所示:

在这里插入图片描述
  1. 反做,使用“git revert -n 版本号”命令。如下命令,我们反做版本号为8b89621的版本:

git revert -n 8b89621019c9adc6fc4d242cd41daeb13aeb9861
  1. 这里可能会出现冲突,那么需要手动修改冲突的文件。而且要git add 文件名来提交

git commit -m "revert add text.txt"

手动整理commit

有这样一个需求,代码量不多,但是因为你多次提交,会导致在建立Merge Request的时候,出现了几十个commitId,比如:“update”、“bug fix”、“fix again”等,不光看起来很丑,也会给大家一种感觉,这小伙到底行不行呀?一百行代码的开发量,提交了这么多次才搞定。(尴尬.jpg)
为了解决这样的问题,我们可以巧妙的利用git reset。比如当前的commit是这样的A-1-2-3-4-5-6-7-8,你的第一个提交是1,那么我们执行如下的命令:

git reset --soft A // 重置本地分支HEAD指针
git commit -m "XXX逻辑开发"
git push origin ywq_news_0702 -f // 提交到远程分支

-f是什么操作?force的含义,表示强行执行本次操作。当我们git reset之后,本地的HEAD指针指向的commitId会比远程origin对应的落后,直接push会被拒绝。通过-f命令可以强行将本地内容push到远程分支上(切记!如果是多人共同合作的开发分支或者远程master操作,千万不能加-f操作!!!)
经过git reset --soft之后,我们提的Merge Request里就是一个commitId了,发出来的CR会感觉倍儿有面儿。

Git stash 临时储藏

当我们在当前分支开发某个需求的时候,遇到了另一个需求的联调问题,需要切换到另一个分支上去解决问题。怎么办?
正常情况下,我们应该将当前分支工作区的内容add 、commit之后再切换分支。但是问题来了,当前需求开发了一半,我不想生成一次提交怎么办?
放心,这个时候我们的git stash命令可以帮助我们将当前工作区的内容储藏起来。然后切换其他分支,处理完问题之后,再切换到当前分支,执行git stash pop取出来就完事。

git stash list // 查看当前stash里边的内容
git stash // 将当前工作区内容储藏起来
git stash pop // 将stash中栈顶内容pop出来,当然也可以根据顺序直接取第n个

Git 恢复修改文件

对于恢复修改的文件,就是将文件从仓库中拉到本地工作区,即 仓库区 ----> 暂存区 ----> 工作区。

对于修改的文件有两种情况:

  • 只是修改了文件,没有任何 git 操作

只是修改了文件,没有任何 git 操作,直接一个命令就可回退:
$ git checkout -- aaa.txt # aaa.txt为文件名
  • 修改了文件,并提交到暂存区)

即编辑之后,git add 但没有 git commit -m ....
$ git log --oneline    # 可以省略
$ git reset HEAD    # 回退到当前版本
$ git checkout -- aaa.txt    # aaa.txt为文件名
  • 修改了文件,并提交到仓库区

即编辑之后,git add 和 git commit -m ....
$ git log --oneline    # 可以省略
$ git reset HEAD^    # 回退到上一个版本
$ git checkout -- aaa.txt    # aaa.txt为文件名

参考

  • Git十大硬图:https://zhuanlan.zhihu.com/p/132573100

  • Git分支规范:https://zhuanlan.zhihu.com/p/108385922

  • Git思维导图:https://www.jianshu.com/p/e2f553942317

推荐

主流Java进阶技术(学习资料分享)

Java面试题宝典

加入Spring技术开发社区

PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我们吧!

Git : 每一行命令都算数相关推荐

  1. mysql每一行数据类型_MySQL_MySQL编程中的6个实用技巧,每一行命令都是用分号(;)作为 - phpStudy...

    MySQL编程中的6个实用技巧 每一行命令都是用分号(;)作为结束 对于MySQL,第一件你必须牢记的是它的每一行命令都是用分号(;)作为结束的,但当一行MySQL被插入在PHP代码中时,最好把后面的 ...

  2. linux设备负责执行计划任务,Linux计划任务详解,很详细,每一行命令都有相对应的白话解释。...

    计划任务 计划任务的作用是:做一些周期性的任务,目前最主要的用途是定期备份数据. 计划任务主要分为一次性调度执行at和循环调度执行cron,下面我就围绕着at和cron来讲解. 一次性调度执行at a ...

  3. Git操作常用的命令都在这里了

    转载自 Git操作常用的命令都在这里了 创建仓库 git init 在当前目录执行,会生成 .git目录文件,这个和SVN一致. 提交到仓库 git commit -m "first com ...

  4. git gui 历史版本_这些Git命令都不会,还是不要去面试了

    前言 以下,项目中经常使用的Git命令,汇总到这里以便与你能快速的学习和掌握Git命令,在文章最后有惊喜哟,一定要看到最后啊! 使用的 Git版本:git version 2.24.0 命令 git ...

  5. git gui怎么拉取项目代码_这些Git命令都不会,还是不要去面试了

    前言 以下,项目中经常使用的Git命令,汇总到这里以便与你能快速的学习和掌握Git命令,在文章最后有惊喜哟,一定要看到最后啊! 使用的 Git版本:git version 2.24.0 命令 git ...

  6. Git基础(常用命令)介绍

    版本控制是一种记录若干文件内容变化,以便将来查阅特定版本修订情况的系统. 关于版本控制分为三种:本地版本控制系统,如rcs:集中化的版本控制系统,如CVS.SVN:分布式版本控制系统,如Git. Gi ...

  7. Git系列之git log高级命令

    原文地址 使用任何版本控制工具的目的都在于记录你代码的变化.这可以给予你查看项目历史的能力,去发现谁做出了贡献,弄清楚何时产生了bug,回滚到错误的修改.但是,如果你无法定位,获取这些历史记录将变得毫 ...

  8. 高响应比优先算法代码_以梦为码丨让每一行代码都充满温情

    本期热点 智能校园部招聘专场 小海 小海冲鸭 我们一直在打磨的多款产品在上周海亮教育研究院产品发布会上崭露头角,激动!!! 别说话,我在敲代码 发布了哪些呀? 小海冲鸭 iClass.海亮星课堂.模板 ...

  9. Git操作手册|命令速查表

    Git操作手册|命令速查表 这篇文章主要介绍Git分布式版本管理与集中式管理的一些差异,总结下Git常用命令作为日后的速查表,最后介绍Git进阶的一些案例. 本文分为以下几个部分: Git与SVN差异 ...

最新文章

  1. 通过Auto Layout深入了解SizeClasses的好处和使用
  2. POJ-2948 Martian Mining 动态规划
  3. 如何使div填充剩余的水平空间?
  4. 团队开发冲刺第二阶段_4
  5. 秒懂 CountDownLatch 与 CyclicBarrier 使用场景
  6. asp.net三层架构连接Oracle 11g详解
  7. 【机器学习】逻辑回归代码练习
  8. 维多利亚的秘密 2005-2018年视频合集
  9. 引号 解析 逗号_笔试积累 | 军队文职公共科目真题解析18
  10. Linux中的线程与进程以及调度
  11. 在 Go 语言中使用 Log 包--转自GCTT
  12. 恒流源差分放大电路静态分析_差分放大电路分析
  13. 【C语言编程练习】20050. 计算存款利息
  14. 人脸识别对动画无效,迪士尼打造动画专用人脸识别库
  15. LeetCode常用算法的总结
  16. Android-第九节网络编程
  17. python web前端 java ui学哪个好_学IT选Java还是Python?就业发展有何区别?
  18. 一篇文章搞清楚直播协议RTMP
  19. 三维叉乘怎么算_自然资源管理,三维GIS能做什么?
  20. 彻底弄懂Python标准库源码(一)—— os模块

热门文章

  1. 三星Galaxy S11+电池谍照曝光:5000mAh超大容量 5G 不虚
  2. 5G芯片市场“四强争霸” 未来市场格局谁更胜一筹?
  3. 那些慢慢消失的手机功能,最怀念第一个!
  4. 汽车行业持续亏损?奥迪:不存在的
  5. 支付361万元“家庭抚养费”后,贾跃亭向法院申请与甘薇离婚?
  6. 中国电信9月将率先推出5G新号段:资费也随之曝光 最高599元/月?
  7. 支付宝上线AR扫识别垃圾功能,十大“拎不清”垃圾令小姐姐捂脸
  8. 支付宝也跟上了!免费办理ETC 还提供设备包邮服务
  9. 2018安卓应用安全白皮书:超98%安卓应用存有安全风险
  10. 中国移动:手机上网流量单价累计同比下降62%