和一个长期使用 IDE(eclipse)集成 git 进行代码版本管理的人交流项目,博文内容将采用类似《大话设计模式》的对话体进行,场景真实,有代入感。

正文部分前面是对方参照我写的 readme 搭建基于 vue-cli 的 demo 项目,安装 node 并通过 npm 安装项目依赖并本地启动项目等等,由于对方为后端 Java 开发,对新前端技术栈了解比较少,在搭建环境和启动项目过程中滋生一些趣事。

比如使用 npm 启动项目后如何在浏览器访问项目,我为了让其醒目意识到我们的项目首页就是未经改动的 Vue-cli 首页,于是我将首页改动并推到远程 master 分支,后面便是我们的搞笑对话。

正文

暂定对方昵称为lzz

Begin

我:“你再从 master 拉一下最新的代码,然后重跑一下”

lzz:“速度教一波拉代码,我没操作过命令行”

我:“git pull origin master”

lzz:“我天天在 eclipse 操作”

lzz:“要在项目目录下吗”

我:“嗯”

lzz:“这是 pull 下来吧,接下来的呢,ok 了?”

我:“pull 会自动合并进当前分支,fetch 只拉,还需要手动 merge”

此处涉及 git pull 和 git fetch & git merge 的区别

lzz:“怎么上传分支”

我:“你新建分支了吗,我瞅瞅”

lzz:“如何瞅,命令行在哪看”

我:“截图,git checkout -b 新建的分支名”

我:“git branch 看现在在哪个分支”

lzz:“你的分支”

lzz:“我拉你的分支还是从主分支上拉比较好”

我:“当然主分支,你为啥在我的分支”

lzz:“我看看怎么拉主分支”

我:“git checkout master”(我因得知他在我的分支上,所以让他先切到主分支上去)

lzz:“我又没上传这个分支”

我:“切换到主分支,你为啥会到我的分支”

lzz:“不知道”

我:“骚操作”

lzz:“昨晚 zz 教我拉的时候拉的吧”

我:“不学好”

lzz:”fxxk,还要提交,我直接把这个分支删了吧“(我内心 os:"… 为啥要删我分支 …")

我:”你改啥了,你改动后删不掉的,git status“

这里涉及使用git status查看本地仓库文件状态

lzz:”fxxk you“

我:”fxxk you too“

我:”git status, 看看改啥了“

lzz:”嗯“

我:”git checkout .“

我:”git checkout master“

我:”git checkout -b lzz“

我:”git push origin lzz“

lzz:”我还原了,这是依赖吧“

然后我看到他的控制台还有 package.json 和 package-lock.json 文件为已修改状态,于是提示他撤销全部

我:”git checkout .“

lzz:”npm clean?“

我:”no“

lzz:”你这是重放个位置了“

我:”你执行就是了“

lzz:”没鸟用,是../吧“

我:”git status“

他了一张截图,提示他所在目录不是一个 git 目录,因为他已经通过..到了项目上一级目录,自然不是 git 目录

我:”回到项目目录“

lzz:”git init?“

我:”你乱跑啥“

我:”cd ./项目目录名“

我:”init 你妹“

此时他已回到项目目录再次 git status,提示工作树干净(working tree clean)

我:”git checkout master“

我:”git checkout -b lzz“

我:”git push origin lzz“

我:”赶紧,让我看到你的分支,刷个存在感“

经过操作,他在远端仓库推送了新的分支 lzz 到项目

我:”不容易“

lzz:”这个主分支和你的分支就 index.html 不一样吗“(因为他看到的是旧的 master,他并没有按照我的要求使用 git pull origin master 拉取我新提交的 master)

我:”你就没改东西,一毛一样,现在三个分支内容一样“

lzz:”页面不一样“

我:”一样的,master 我改了,你刚才看到的就是 master 的“

lzz:”嗯,提交就是,git push origin lzz?“

严谨来说这里并不一定,因为 origin 只是 git 约定俗成的远程主机名,其实这个参数可以自定义,比如你需要推到多个远程仓库时,需要在 origin 之外自定义远程主机名

我:”不是“

lzz:”还是直接 git push“

我:”这是把本地分支推到远程“

lzz:”嗯“

我:”提交是 git commit“

lzz:”1,想起来了“

我:”直接 git push 需要把本地同名分支和远程同名分支绑定“

这里有待考究,我说的这是否是必要条件,但 git 的确是提供了-u 参数用于绑定本地分支与一个默认远程分支,这样仅使用 git pull 和 git push 便可将该远程分支与本地分支进行互动

lzz:”git checkout . 放弃文件的修改吧?“

我:”是,其实是把远端的覆盖本地的“

关于 git checkout 的使用,理解为放弃修改,从效果上看的确是这样的,也是我一开始学习和使用 git 的理解,但从本质上 git checkout 实际还是在执行其本质行为,就是检出远程文件,只不过这样做的确就会将本地的覆盖,达到放弃本地文件的修改的效果

lzz:”我每次重新切换分支,要 npm install 吗?“

我:”新分支需要,已经 install 过的分支不需要“(此处涉及 npm 项目的知识,与本文关系不大)

lzz:”我 push 的时候不会将这些包带着吧“

我:”不会,.gitignore 忽略 node_modules 目录“(这当然是我配置的,不过这个问题问的很好,说明其意识到的 git 对于项目文件的管理细节)

lzz:”貌似没有忽略啊“(他看到 package.json 和 package-lock.json 文件被提示尚未加进暂存区)

我:”这两个文件可以提交,也可以手动忽略,我加一下“(所谓手动忽略当然就是使用 git checkout 检出远程同名文件覆盖本地的修改,我加一下是指其实 package-lock.json 的确不需要提交,而 package.json 随着项目的迭代可能有包的更新,所以项目团队间需要互通,不过如果使用相同的 node 环境,这样的更新每个人在本地都会有及时的感知,所以这两个文件是否要纳入版本管理不重要)

lzz:”上面的.json 文件我并未改动,应该就像 maven 的 pom 文件一样,为什么会变动呢“(此处涉及 npm 对于依赖包的管理)

我:”因为你又 npm install 了,会更新版本“

lzz:”拉下新的版本,拉下我的“

我:”干啥“(其实我已经在远端仓库客户端,我们会使用的 gitee,看见他的修改,一个小小的恶作剧)

lzz:”你瞅瞅我的 master piece“

我:”你发 pull request“

此处涉及 gitee、github 这类用于公共开源,不同于 gitlab 的 merge request,而是通过发起 pull request 将分支合入 master

他给我发了一张他提交记录的截图,标识他已经将自己本地的分支提交到远端仓库

我:”你不提交 pull request,你就只是在自己的分支玩,你看看你能 merge 进 master 吗“

lzz:”你拉我的分支不行吗,你把我的分支拉下来啊“

我:”我干嘛要拉你的分支“

我给他发一张我对于其提交的评论截图(基于 gitee)

lzz:”你这个页面在哪,github 还是码云上“

我:”gitee“

lzz:”什么鬼???“(因为码云这个对于代码评论的功能的确做的看上去和 github 很像)

我:”码云,就是 gitee“

我:”洗洗睡吧“

lzz:”这样?“

他发了一张在操作 pull request 操作的截图,但填写是错误的,源分支为远程 lzz,目标分支为远程 lzz,其实 pull request 是要发起申请将你提交到远程仓库的分支 merge 进远程的 master 分支,经过操作,他最终成功发起了正确的 pull request

lzz:”知道 PR 啥作用了“

我:”目标分支填 master 啊“

lzz:”嗯,知道了,睡觉“

END

总结

整个过程其实就是一个经典的新手入手 git 并结合第三方远程仓库管理个人项目的各种操作,对话看上去愚蠢,但其实基本覆盖了团队基于 git 进行协作的基本操作和重要核心的 git flow

结论

在此过程中虽然我使用 git 有一些经验,但还是觉得仍有部分环节的细节有待深入研究,不过经验就是:使用 git 一定要随时保持清醒,知道自己所处位置(git 仓库、暂存区、本地仓库、远程仓库),对分支的分分合合要有着清醒的头脑,否则很有可能在使用 git 这个管理代码和版本的强大工具之下也会搞的一团糟,它就像一把双刃剑,用好的话可以事倍功半,用不好也可能对代码项目带来严重的灾难