优秀的编程知识分享平台

网站首页 > 技术文章 正文

入职第一课:Git(入职第一课座谈会)

nanyue 2024-07-18 03:57:10 技术文章 7 ℃

前言

作为技术岗,Git可以说有着举足轻重的地位。如果Git不了解,甚至用的不熟,恐怕多多少少会让工作中的自己有些手忙脚乱。今天的文章让我们通过一个故事,一起走进Git的世界~

故事的开始

小M凭借着自己扎实的Android基础,找到了一个自己心仪的实习岗位。

今天是小M入职的第一天,他见到了他的导师W哥。

W哥:"小M呐,你作为实习生呢,咱公司也不会给你安排强度特别大的工作,一会你先拉一下公司的代码。熟悉熟悉公司的规范,然后自己开发一个微信出来。"

小M:"哈?"

B哥(资深开发,打酱油):"看把人家小伙子吓得。放心,咱们是搞视频应用的,怎么可能搞微信,你要搞的是优酷。"

小M:"哈?"

W哥:"先拉一下代码吧,git地址是:xxxx。记得切换到feature分支,feature是咱们的开发分支。"

如果大家对Git没有一点概念的话,可能这篇文章看起来会比较的吃力。如果有一定git基础,可以直接进入[小M的Git之旅]

让我们先暂停一下故事,讲一讲git这个工具~

开始之前先思考一个问题“”如果我们开发了一个V1版本的软件,后来想在此基础上开发一个V2版本,但是前途未卜,准备随时回滚到V1状态。这种情况下,我们会怎么办?也许我们会复制一个V1,再在其中一份上开发。

这里我们在想一个场景,如果我们这个V2版本开发中途,发现V1版本需要临时上一个需求,为了避免污染代码,我们可能又复制一份,开发V1.1版本。但如果我们小版本众多,难道我们要不停的复制么?git的强大便在于此。

Git就是帮我们完成上边我们所遇到的一切问题。对于不停的复制文件,git提供了branch分支[^1]的方式,其外Git会帮我们追踪所有改变的代码(字符变动),这个变化是针对于commit[^2]的。我们可以很简单的对当前管理的代码进行回退,重置的操作。并且git对每一个commit都会生成节点[^3],有了这个节点,我们就可以轻易的把代码状态切换到任意节点上。

[^1]branch分支:分支是git这套工具中的一个概念,它的作用就相当于帮我们把文件复制一份~不同的分支是不同的复制文件,可以随意修改且不影响其他复制的文件。(git的原理不是复制,还是记录文件修改的快照)

[^2]什么是commit:我们每写完一个小功能,可能想保存一份,那么这里可以使用git的commit命令,将当前git追踪到的代码变化,全部提到到git的版本库中,生成一个节点[^3]。

[^3]节点:git是一种树形的结构,每次commit都会生成一个节点,节点是git用于快速切换代码状态的利器。我们的代码快照保存在节点中,git通过移动HEAD指针(参考下图),来快速在各节点直接进行切换,已达到切换不同的代码状态。

不知道这么解释,大家有没有对git有一个初步的了解。如果感觉还是有点懵,建议小伙伴们可以先去官网看一下git的基础教程。在回过头来感受实战~


小M的Git之旅

虽然小M,没有真正在企业级开发中使用过Git,但是他在学校里边和一些同学合作时也是用过Git的。平时在自己的电脑上进行本地代码管理时,都是使用**git init**。但既然是拉取公司的代码,那就肯定不需要在本地操作init过程啦。

接到W哥的指示后,小M想了想这一系列操作所需要的命令,快速的在Terminal中敲出了如下的几行:

git clone xxxx(克隆线上代码)

git branch -a(查看线上分支情况)

git checkout -b feature origin/feature(把线上的feature切换到本地的feature分支上)

完成上边的命令后,小M打开AndroidStudio,open了这个项目,等待gradle编译。编译结束后,项目一片红,很多类竟然找不到,并且小M发现:项目依赖的子库竟然是空的!

小M心中暗惊:难道我刚才...一顿操作瞎xx操作,把代码都删了

小M遇到的这种情况比较特殊,是因为主git工程依赖了子git工程,其实一般很少会依赖子git库情况,只有子库需要频繁修改时,才会依赖子git库。一般子库都是比较稳定的,所以下述内容,各位小伙伴选看吧。或者直接 [跳过]。

W哥发现了小M的异样,凭借那双让他在秋名山从未翻车的眼睛,一眼就发现了问题的所在。嗖,拉过键盘,啪啪啪,极短的时间俩行命令出现在荧光屏中:

git submodule init

git submodule update

W哥解释道:"咱们的项目依赖了另一个子库,这个库也是一个git库,它是我们base库,一些通用操作全部被封装进去了。clone主工程是不会去同步clone子库的,你需要手动操作。

注意:如果你进入子库你会发现,子库的节点是一个游离节点,这是为了保证线上项目的不被轻易改变。因此你此时改动子库的内容实际上是错误,一般情况子库是由专门人员去维护管理。如果你非要改子库,你可以手动切换子库分支修改并push(有权限的情况下)。不然会把线上节点改的稀碎...不过你就记住不要乱改子库就行,会有专人去维护子库。

这里你只需要记住:pull完代码,git status发现子库modified时,并不一定表示子git库被修改,有可能是你拉下来的新节点所依赖的子库节点和你本地不同了,这个时候只需要git submodule update即可。也就是把本地的子git库,更新到和主git工程相同。

你看代码的时候记得加一些注释吧,一算对你的考核,二也算让后来的同学更快的了解公司情况。"

公司的项目跑起来了

这俩行命令之后,项目果然可以正常的运行起来了。小M也渐渐的走上了工作的轨道之上。一会的功夫,小M就看完了一个功能模块,并且顺利的加上了注释,并且使用了:

git add .(将工作区内容全部提交到暂存区)

git commit -m "本次提交的注释"(将工作区内容全部提交)

小M时而多次add,一次commit,时而一次add,一次commit,学的不亦乐乎。

不过,随着深入他也发现了问题,那就是项目比较庞大,很明显是多人协作完成的,可能是review的时候没有注意到,有些代码写得很烂!

烂到小M作为一个实习生都看不下去了,小M就在注释的地方,狠狠的吐槽的这段代码!但是吐槽归吐槽,小M还没傻到把这些内容提交。毕竟他也是看到了“穷逼vip事件”的可怕。

危机出现

小M刚想使用:

git checkout X(吐槽的文件) (把X文件从工作区清掉,也就是放弃所有改动)

就在checkout时,手一哆嗦,打成了add...

小M惊出一身冷汗:"幸亏只是add,不怕不怕,使用git reset HEAD X(吐槽的文件)就可以撤到暂存区,然后再checkout就完事了。"

还没等大脑命令手去reset的时候,这双早该在双11就被剁掉的家伙,竟然打出了commit命令...

空气中弥漫了一丝尴尬...不过好在问题还可以处理,小M虽是个实习生,撤销commit的操作还是知道,他含着泪打出了:

git reset --hard HEAD^回退到上一个节点,当前节点内容全部丢弃。当然我们也可以使用```git reset --hard HEAD```想要回退节点的SHA1)

话外音

但是,我们reset的节点并没有真正的删掉,会一直存在...如果在未来的某一天,一位同事敲出了```git reflog```命令时,这个库的所有提交记录将全部被展示出来,当然也包括小M回退的内容(因此我们可以明白这并非是真正意义的回退操作,而是新的commit而已),因此小M的案发现场又重新被挖掘了出来...

吐槽一时爽,前途火葬场...

新的知识

这时W哥说话了:"小M,代码有了新的提交,你重新拉一下。"

提交的真不是时候,此时小M的注释正添加到了一半,但是也是不能不拉代码,万一新内容对自己有影响,那自己不就是白写了么。

无奈之下小M使用了:

git stash(将工作区 / 暂存区 内容临时保存起来,保证工作区是干净的)

git pull origin/feature

新代码拉了下来,而且没有出现冲突情况,小M长舒一口气。

当线上merge(合并)过来的节点和本地的代码同时改动了同一行内容,会出现冲突,这个时候需要解冲突~因为git不知道要保留谁的改动,它会默认都保留。那冲突是什么样子的?盗用最近比较火的马蜂窝事件:

这一系列的操作全被一旁的W哥看在眼里。

W哥:"小M呐,你刚才的git pull操作没有什么问题,你知道```git pull --rebase```操作么?"

看到小M一脸的懵逼。W哥继续说道。"git pull是将线上的新分支和本地的分支合并成一个新的分支,并产生一个新的merge节点。而```git pull --rebase```则不同:```git pull --rebase```会把线上的每一个节点和本地的节点进行比较然后逐个进行合并。如果出现冲突那么git会在本地创建一个游离节点,你必须要在这个节点上进行解决冲突操作,然后使用```git add .```,```git rebase --continue```之后才可以进行下一个节点的merge。然后会重复这个过程直到所有节点完成merge。当然如果合并时冲突有点多,这个时候就要注意了是不是团队分工有问题,这时可以使```git rebase --abort```,放弃合并,回退到没合并的状态。对了,我在子库进行了提交。你输一下git status,看看有什么不同。"

小M敲了一下git status,小M发现git提示子库(modified)有更改!

W哥:"这里的提示不是代表着本地子库有修改,而是代表了线上的子库有变动,这时你要做的是什么操作?"

小M:"我知道,是git submodule update。"

果然再次,git status时,小M发现工作区很干净什么也没有。更新了线上的内容之后,小M使用git stash pop弹出自己刚才临时存放的代码(有可能会出现冲突,需要解冲突),继续进行他对模块的注释。

一天的时间很快就过去了,看着自己辛苦一天的内容,小M满怀成就的敲出了最后一个命令:

git push origin feature

(当然,如果此时你的工作节点不是最新,是不可能push,需要先进行pull操作;当然这里的前提是工作区必须干净~)

本章节完

因为文章剧情的需要,很多常用的命令并没有提及。如果需要更多样化的操作,可以前往Git官网查看呦~

git checkout --track [remotename]/[branch]:从线上拉下一个分支,在本地创建同名的分支上:

git push [remotename] --delete [branch]:删除线上分支

git log -2:查看2个最新的提交日志

git reflog:查看所有提交日志

git branch -vv:显示当前本地分支对应追踪的线上分支情况

git branch -u [remotename]/[branch:”改变当前分支的追踪对象

git branch:显示当前分支

git branch dev:创建dev分支

git checkout dev:切换到dev分支

git checkout -b dev:创建并切换到dev分支

git branch -d dev:删除当前分支,此条命令的前提:不能删除当前分支,删除的分支必须已经被合并

git branch -D dev:不问青红皂白直接删除

特殊:git cherry-pick sha1 把一个分支的commit节点(sha1)强制拉到当前分支上。

如果有些好用的命令欢迎在评论区留言,然后的git技巧6的飞起。

最后,请听我一言:点赞,转发,评论666~

最近发表
标签列表