前言

为什么写这篇Git文章?

在日常的需求开发中,发现部分同学不太熟悉Git命令,往往是通过idea自带的一些工具来执行简单的Git命令,遇到一些突发问题的时候,往往不知所措。

简单来说,就是Git基础知识匮乏,不明白每一行Git命令背后的具体含义。所以,本人对Git基础知识进行简单总结与科普,希望可以帮助到大家。

本文阅读前提:

  • 在日常工作中,会使用简单的Git命令
  • 了解简单命令,不熟悉复杂一点的命令操作
  • 大概了解Git的基础知识,对命令实际行为不甚了解

正文

Git是什么?

Git是个开源的分布式版本控制系统,最初的目的是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。Gitlab、Github、Gitee指的是业界流行的代码托管平台,都是基于git进行代码仓库管理。

Git怎么玩?

接下来,我们以Github为例,看看正常情况下我们是怎么玩Git的。

点击新建Repository,如下所示:

仓库创建成功之后,会出现如下的提示:

这些指令的意思是说:(本地操作)

  • 生成一个README.md文件
  • 将当前目录初始化为Git仓库
  • 将文件add到暂存区(index)
  • 将本次修改提交到本地仓库
  • 将当前分支master重命名为main分支
  • 添加远程origin仓库
  • 将本地Git仓库中的内容推送到远程origin仓库的main分支上

当然了这种Git操作是一个项目工程从0 -> 1的过程,也就是当我们需要新建一个项目工程的时候需要执行的一系列操作。

在实际的工作开发中,我们更多的时候是直接通过git clone命令将已经存在的远程仓库中的项目工程克隆到本地。

Git工作区域

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

Git本地有四个工作区域:

  • 工作区(Working Directory):在git init之后的本地的文件目录下,也就是大家写代码的地方
  • 暂存区(Staged/Index):修改了代码之后,需要先将改动add到暂存区,表示将要提交的改动
  • 本地仓库(Local Repository):本地Git仓库,通俗讲就是本地隐藏文件.git目录下,存储着你的所有改动
  • 远程仓库(Remote Repository):远程Git仓库,理论上和本地仓库地位平等,但是主要是用于多个开发者之间pull/push代码的仓库。

Git四个区域之间的转换关系如下:

上述的工作区域之间的变动都是常见的一些Git命令,我们在此不进行详细的介绍了。接下来我们看下文件在多个工作区域变动的时候都有哪些状态吧。

在一个Git仓库,我们执行git status命令,如下所示:

  • On branch ywq_news_0702告诉我们当前在哪个分支上
  • Changes not staged for commit:告诉我们目前有哪些文件时Changed但是没有被放到暂存区staged的,并且下边两行括号中时告诉我们可以采取的操作:
    • git add可以将改动添加到staged中for commit
    • git restore可以将在工作区的改动丢弃掉
  • Untracked files:未跟踪的文件,表示这是一个新文件,还没有被加入到Git仓库中,也就不参与版本控制:
    • 通过git add命令可以将其包含在staged中for commit

所以我们来看下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 clone一个项目或者在本地新建一个Git项目执行git init之后,当前目录下会出现一个隐藏的.git文件,这就是Git本地仓库,里边存储着你的所有改动等信息。

  • HEAD:存储的当前分支的HEAD信息
ywq@yangwenqiangdeMacBook-Pro .git % cat HEAD
ref: refs/heads/ywq_news_0702
  • refs:存储着各个分支最新的commitId
ywq@yangwenqiangdeMacBook-Pro .git % cat HEAD
ref: refs/heads/ywq_news_0702
ywq@yangwenqiangdeMacBook-Pro .git % cat refs/heads/ywq_news_0702
e821909206034c15a7f087885db5d47ef0462dd2

e821909206034c15a7f087885db5d47ef0462dd2这个就是本地ywq_news_0702分支上的最新提交HEAD

  • config:存储着Git仓库的配置文件
  • objects:Git本地仓库存储的所有对象,Tree、Commit、Blob类型

    可以看到我们每一次提交都是产生了一个40位的commitId,objects里边存储了一个个的Tree,会以commitId的前两位作为tree,如下所示:

    对文件进行add -> commit 之后,objects文件目录会发生变化,也就是说 Git 在每次对本地版本库进行commit的时候,就会对数据 进行一次保存,这是会生成 commit对象,tree对象以及blob对象。
    Git 存储数据内容的方式是为每份内容生成一个文件,取得该内容与头信息的 SHA-1 校验和,创建以该校验和前两个字符为名称的子目录,并以 (校验和) 剩下 38 个字符为文件命名 (保存至子目录下)。通过 cat-file 命令可以将数据内容取回。该命令是查看 Git 对象的瑞士军刀。
    如下所示:
  • index:存储着Git索引文件
  • logs:存储着每一次的commit操作:

Git命令解析

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

  • git clone:将远程仓库克隆到本地,也就是创建了一个本地仓库,会出现隐藏文件.git
  • git status:查看状态,可以看到哪些文件被修改、哪些是未跟踪的文件
  • git diff:可以看到当前工作区和暂存区staged中的文件diff
  • git add:将未跟踪(新增加)或者修改过的文件从工作区添加到暂存区staged中
  • git commit:将暂存区staged中的内容提交到本地Git仓库中
  • git push:将本地Git仓库中的内容提交到远程Git仓库中

OK,上述是最简单最初级的Git命令,相信我们每一个同学日常都在大量使用。并且如果是单人开发,自己玩的情况下,貌似这些命令就足够了?
是的,够了。但是,在实际的开发当中,我们往往会面对更加复杂的场景,需要一些更为复杂的命令来处理,我们接着往下看。

git merge

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

git fetch

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

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

git pull

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

git pull origin master
表示将远程master分支拉到本地并且merge到当前分支上,也就是使用最新的master代码更新了本地的开发分支ywq_news_0702

git rebase

正如我们上边git merge所描述的,merge操作会导致提交链路形成一个个的钻石链路,看起来不太清晰,并且会出现很多merge操作所造成的commitId。所以,提供了git rebase命令,这是一种变基操作,一般用在git pull之后,如下所示:

git pull origin master --rebase 使用rebase方式更新本地代码

git log

这个命令和厉害了,可以展现出当前分支上所有的版本commitId,当然是从HEAD开始的。有一句话是这么说的“Git不会丢失任何东西”,你的每一次提交都会被记录下来。通过commitId,我们真的可以操作很多,比如将当前HEAD reset到某个提交上、捡取cherry-pick关键的commit到另一个分支上等等。

git cherry-pick

这个操作有点意思,他可以将别的分支上的某一个commit捡取到当前分支上。什么意思呢?就是说别人在其他分支上修复了一个bug,你想把修复bug这一段逻辑挪到你的开发分支上,就可以通过cherry-pick来搞定。
比如说我们在本地ywq_news_0702分支上提交了一个commit,如下所示:

这个时候,我们切换到了ywq_vb_0616上,执行:

git cherry-pick e365a0d268d0
注意,对于Git的commitId,我们只要复制的大于等于8位就可以

可以看到效果如下:

特别提醒:

cherry-pick是一个本地操作,也就是说你要捡取的commitId一定是存在于本地仓库其余分支的。你不能直接找一个远程分支存在,但是尚未fetch到本地仓库的commit来执行捡取操作。

git reset

这又是一个牛逼的命令,可以重置当前分支的HEAD指针,常见的参数如下所示:

  • git reset commitId

  • git reset --soft commitId

  • git reset --hard commitId

    这也算是应届生考察Git常见的八股文系列了吧,但是仍然会有好多人不明白其中具体的区别和用途,这里结合Git工作区域来做一个解释:

  • 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

这个命令那简直就是Git的核心命令之一,干啥的呢?前面我们说了git log可以看到当前分支上的所有commit,通过commitId我们可以进行一些reset、cherry-pick操作。reflog里存储了当前HEAD(包含各个分支)指针曾经指向过的每一个commitId,只要有了commitId,我们就可以回滚操作,也就拥有了“后悔药”。

细心的同学会发现我上边演示git reset操作的时候,反反复复都在操作一个commtId:4e005bec1617。明明已经reset了,我为什么还能反复操作呢?
答:因为我执行了git reflog找到了刚刚的HEAD,并且执行git reset --hard 4e005bec1617将当前分支的HEAD重置回去了。
因为当我们reset HEAD指针之后,git log里只会显示当前分支HEAD之前的所有commitId,所以我们需要借助于git reflog来完成操作。

git revert

为了出售“后悔药”,Git真实煞费苦心!有了git log、git reflog以及git reset还不行。Git提供了revert命令来进行后悔操作。什么场景使用git revert命令呢?
当我们向master merge了一些代码,过了几个小时才发现有bug,整体逻辑都不太对。怎么办?
有同学说,我找到commitId,直接reset --hard就完事呗?No,那可不行,在这段时间内,在你的commitId之后,其余同学都提交了一系列的commit了,你肯定不能影响到别人的提交。
这个时候git revert出场了,直接看示意图:

revert命令实现了HEAD指针的继续前进,新生成的commit和要撤销的目标提交具有相反的操作,实现了“后悔”的操作。

Git常见的一些小技巧

其实,写这篇文章的初衷是讲述一些干货。但是写着写着才发现Git这玩意儿比较零碎,很难写出真正的干货,一不小心就成了一片“万字水文(科普文)”了。接下来,我们讲解一些Git中偏实战的内容吧,希望可以对大家有所帮助。

解决冲突:

这个是最常见的问题了,当我们进行merge、pull、rebase、cherry-pick操作的时候,都可能会产生冲突。代码冲突是啥意思?

冲突是指多个开发者对于同一个位置都做出了修改,导致合并操作的时候无法自动合并的行为。

遇到冲突的时候不要慌,见过一些同学,遇到冲突特别慌,当看到大量冲突的时候,不想解决了,竟然选择了 手动备份本地代码 + 删除本地仓库,重新clone远程仓库的操作 (哭泣.jpg)
遇到冲突的时候,各个命令都会给出明确的提示:

  • git merge操作会告诉你哪些文件是both modified:

    • 需要你解决冲突之后,执行git add、commit
    • 或者直接执行git merge --abort废弃掉本次merge操作
    • 或者执行git reset --hard HEAD来将本地工作区、暂存区内容强行恢复到本地的HEAD上(这条是我加的)
  • git rebase操作会告诉你哪些文件是both modified:
    • 需要你解决冲突之后,执行git add、git rebase --continue命令继续执行rebase操作;
    • 或者直接执行git rebase --abort废弃掉本次rebase操作

冲突,无非就是我们的工作区有了一些代码,如果你了解Git的工作区域和工作流程,废弃掉这些所谓的冲突代码,结束本次操作就是轻而易举的事情。

怎样尽量避免冲突?
多人开发的时候,在一些枚举等场景下会经常出现冲突的情况,有一个小技巧是,在不要求顺序的一些场景下,我们不要在最后的位置继续添加Enum或者ErrorCode等代码,否则极易造成代码冲突(当然了,解决冲突也是很easy的,但是次数多了也很烦)。

手动整理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 pull误操作

背景是这样的:有一个远程开发分支news_slide,多个开发者都在本地的news_slide分支上开发相关逻辑,并且push到远程开发分支上。
小明辛辛苦苦的改动了几十个文件,码了上千行代码。在执行git push origin news_slide的时候,提示,远程代码更加新(因为其余人在此期间将相关代码提交到了远程分支上了),需要执行git pull更新本地开发分支的代码。
小明直接执行了如下命令:

git pull origin master --rebase

执行完毕之后,才发现不对,本来准备拉取的是远程开发分支news_slide的最新代码,结果这次将master代码rebase下来了。这会导致将本地分支推送的时候,提示需要更新当前分支版本,导致必须执行-f操作才可以强行提交,但是这样会将远程别小伙伴提交的代码丢掉。

怎么办?难道只能通过本地备份者一千多行代码了吗?(奔溃.jpg)
当然不是,解决办法如下:

  • 通过git reflog,找到当前HEAD指针上一次指向的commitId,也就是找到你rebase master之前的HEAD commitA。
  • 执行git reset --hard commitA,则代码可以恢复到小明误操作之前。

主要指出的是:当只有你自己开发的时候,更新代码可以使用git pull origin master --rebase,push的时候可以直接-f就完事~

多人合作开发模式

一个项目需要多人合作开发的时候,我们先给出一个案例。
方式一:
远程master分支、本地master分支
执行

  • git pull origin master --rebase 更新本地master分支。
  • git checkout -b news_slide 创建开发分支
  • git push origin news_slide 将当前news_slide推送到远程仓库,作为远程公共开发分支
  • git checkout -b news_slide_1 创建本地个人开发分支1

其余开发同学在自己的工具上,执行

  • git fetch origin news_slide 将远程news_slide分支拉到本地
  • git checkout news_slide 、git checkout -b news_slide_2 创建本地开发分支2

在开发的过程中,将commit从本地开发分支到本地news_slide分支,然后push到远程(当然也可以选择远程建立Merge Request的方式)
将news_slide分支代码更新到本地的开发分支上继续开发。当需要更新master分支上的最新内容时候,前面我们说了不可以使用rebase方式,所以我们可以使用merge master(前提是先切换到master分支更新代码)方式搞定。

特别注意:这里我们再次说下为什么不可以使用rebase方式更新master内容?
因为rebase是一种变基操作,新生成的commitId会被认为落后于远程的HEAD,所以必须使用-f来提交,导致丢失其余同学提交的内容的问题出现。

方式二:
其实,我一直觉得方式一看起来有点啰嗦,简洁一点就是说,多个开发者都直接在本地的news_slide分支上开发,不需要创建个人开发分支,只需要在每一次push之前,先将远程开发分支的内容pull下来即可(也就是更新分支的HEAD)

如何查看暂缓区staged中的内容?

当我们执行git add之后,文件会被添加到staged中,这个时候,我们执行git diff会发现没有任何diff出来。怎么办?我就想看现在在staged中的内容是啥?(因为我感觉我add错了一些东西)难道我只能push到远程,建立Merge Request来查看刚刚add了啥吗?
No,我们先来看下git diff是在干嘛?

  • git diff 比较的是当前工作区和最后一次提交到本地仓库(HEAD)的内容的差异
  • git diff --cache 比较的是当前暂存区和最后一次提交到本地仓库(HEAD)的内容的差异
  • git diff --staged 同–cached

实际操作效果如下:

总结:

Git相关知识点太多了,结合自身实际使用,本文给出了一些阐述和介绍。希望大家可以熟悉Git的工作流程以及相关的文件流转状态。在此基础上,我们才可以准备理解每一个命令背后的实际行为,从而可以提高工作效率,减少各种误操作,及时喝下“后悔药水”。

结束语:

“Git就像一条狗,它能闻出你的恐惧”。Git是一个很好的分布式版本控制系统,你的每一次操作都会被记录,如果我们能够熟练使用常见命令就可以轻松玩转Git。

“Git,每一行命令都算数”。在日常的开发中,大量的同学习惯使用图形化界面来操作Git,这样会导致大家对Git命令不甚熟悉,如果出现异常情况会懵逼。对于常年手敲Git命令的我来说,“每一行命令都算数,我只相信我敲出来的命令”。

限于本人水平,文中难免会有不妥甚至错误之处,烦请各位指出。

2021.07.03 夜

谨以此万字长文,献给结束大小周后的第一个双休(开心.jpg)

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

  1. Git : 每一行命令都算数

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

最新文章

  1. linux /etc/fstab文件参数求解释
  2. 使用Vim+Ctags+Cscope阅读源代码
  3. netlogon启动后停止_自耦变压器降压启动原理
  4. jmeter 自定义参数_jmeter参数化并在jenkins上执行
  5. Android JNI 报错(signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr )
  6. C++ 学习之旅(1)——编译器Compiler
  7. Android doc|Getting Started| Training部分 --翻译 Working with System Permissions
  8. Performance Tuning
  9. vue移动端点击事件延迟_去除点击事件300ms延迟 (使用了vue之后)
  10. LaTeX tikz初探——利用emoji画GPS卫星2D分布图(2)
  11. Retrofit + RxJava + OkHttp 让网络请求变的简单-基础篇
  12. 车牌识别系统开发记录(四) 国内车牌特点
  13. mro python_Python的mro
  14. Linux 两种终端分屏工具
  15. VBA宏实现将中文转为拼音(转帖+亲自实践)
  16. Qt编写安防视频监控系统33-onvif云台控制
  17. java设备imei号_java 怎么计算IMEI号码正确性
  18. 定义一个数组存储10个上面描述的小怪兽,每个小怪兽的名字为(小怪兽+数组下标)
  19. HDU 2020 多校第二场 游记
  20. 图像超分辨率重建数据集看这篇就够了——训练 + 测试 | 【云盘分享】

热门文章

  1. 利用canvas制作水印(兼容移动端哦)
  2. windows pe安装系统
  3. ios 简单实现半圆形仪表盘 (进度条)
  4. python实现qq自动点赞_python实现自动点赞
  5. R语言使用survival包的Surv函数创建生存对象、建立Cox回归模型(包含所有协变量)比较不同治疗方法生存率的差异、使用predict函数对cox模型进行新数据的预测和推理(预测死亡风险)
  6. 调用支付宝网页支付被浏览器拦截
  7. 华为P7安装Linux,华为P7插卡步骤图解 华为P7电信/移动/联通版手机sim卡安装使用教程...
  8. 计算机网络网桥模拟课程设计,网桥模拟实验
  9. 【error】RuntimeError: size mismatch
  10. matlab质心定位算法,一种改进的质心定位算法