基础
Git 流程图
Workspace
:工作区
Index / Stage
:暂存区
Repository
:仓库区(或本地仓库)
Remote
:远程仓库
配置 Git
查看 Git 信息
git reflog
- 显示的是一个
HEAD
指向发生改变的时间列表。在你切换分支、用git commit
进行提交、以及用git reset
撤销 commit 时,HEAD
指向会改变,但当你进行git checkout -- <filename>
撤销或者git stash
存储文件等操作时,HEAD
并不会改变,这些修改从来没有被提交过,因此reflog
也无法帮助我们恢复它们。
git reflog
不会永远保持,Git 会定期清理那些 “用不到的” 对象,不要指望几个月前的提交还一直在那里。
git log 点线图
- git 中一条分支就是一个指针,新建一条分支就是基于当前指针新建一个指针
- 切换至某个分支 ,就是将 HEAD 指向某条分支(指针)
- 切换至某个 commit ,就是将 HEAD 指向某个 commit
符号解释:
Git 常用命令
Git 常用命令详解
add
将工作区的文件添加到暂存区
git add .
:操作的对象是“当前目录”所有文件变更,"." 表示当前目录。会监控工作区的状态树,使用它会把工作区的所有变化提交到暂存区,包括文件内容修改(modified
)以及新文件(new
),但不包括被删除的文件。
git add -u
:操作的对象是整个工作区已经跟踪的文件变更,无论当前位于哪个目录下。仅监控已经被 add 的文件(即tracked file
),它会将被修改的文件(包括文件删除)提交到暂存区。git add -u
不会提交新文件(untracked file
)。(git add --update
的缩写)
git add -A
:操作的对象是“整个工作区”所有文件的变更,无论当前位于哪个目录下。是上面两个功能的合集(git add --all
的缩写)。
status
commit
git commit --amend
既可以修改上次提交的文件内容,也可以修改上次提交的说明。会用一个新的commit
更新并替换最近一次提交的commit
。如果暂存区有内容,这个新的commit
会把任何修改内容和上一个commit
的内容结合起来。如果暂存区没有内容,那么这个操作就只会把上次的commit
消息重写一遍。永远不要修复一个已经推送到公共仓库中的提交,会拒绝推送到仓库
push & pull
- 分支推送顺序的写法是 <来源地>:<目的地>
branch
merge 三种常用合并方法
fast-forward
:会在当前分支的提交历史中添加进被合并分支的提交历史(得先理解什么时候会发生快速合并,并不是每次 merge 都会发生快速合并);
-no-ff
:会生成一个新的提交,让当前分支的提交历史不会那么乱;
-squash
:不会生成新的提交,会将被合并分支多次提交的内容直接存到工作区和暂存区,由开发者手动去提交,这样当前分支最终只会多出一条提交记录,不会掺杂被合并分支的提交历史
rebase
stash
- 能够将所有未提交的修改保存至堆栈中,用于后续恢复当前工作区内容
- 如果文件没有提交到暂存区(使用 git add . 追踪新的文件),使用该命令会提示
No local changes to save
,无法将修改保存到堆栈中
使用场景: 当你接到一个修复紧急 bug 的任务时候,一般都是先创建一个新的 bug 分支来修复它,然后合并,最后删除。但是,如果当前你正在开发功能中,短时间还无法完成,无法直接提交到仓库,这时候可以先把当前工作区的内容
git stash
一下,然后去修复 bug,修复后,再 git stash pop
,恢复之前的工作内容。diff
remote
tag
常用于发布版本
删除文件
如果在配置 .gitignore 文件之前就把某个文件上传到远程仓库了,这时候想把远程仓库中的该文件删除,此时你配置 .gitignore 文件也没有用,因为该文件已经被追踪了,但又不想在本地删除该文件后再重新提交到远程仓库,这时候可以使用
git rm --cached filename
命令取消该文件的追踪,这样下次提交的时候,git 就不会再提交这个文件,从而远程仓库的该文件也会被删除版本切换 & 重设 & 撤销
- checkout 可以撤销工作区的文件,reset 可以撤销工作区/暂存区的文件
- reset 和 checkout 可以作用于 commit 或者文件,revert 只能作用于 commit
checkout 详解
- 在开发的正常阶段,
HEAD
一般指向 master 或是其他的本地分支,但当你使用git checkout <commit id>
切换到指定的某一次提交的时候,HEAD
就不再指向一个分支了——它直接指向一个提交,HEAD 就会处于 detached 状态(游离状态)。
- 切换到某一次提交后,你可以查看文件,编译项目,运行测试,甚至编辑文件而不需要考虑是否会影响项目的当前状态,你所做的一切都不会被保存到主栈的仓库中。当你想要回到主线继续开发时,使用
git checkout branchName
回到项目初始的状态(这时候会提示你是否需要新建一条分支用于保留刚才的修改)。
- 哪怕你切换到了某一版本的提交,并且对它做了修改后,不小心提交到了暂存区,只要你切换回分支的时候,依然会回到项目的初始状态。(注意:你所做的修改,如果 commit 了,会被保存到那个版本中。切换完分支后,会提示你是否要新建一个分支来保存刚才修改的内容。如果你刚才解决了一个 bug ,这时候可以新建一个临时分支,然后你本地自己的开发主分支去合并它,合并完后删除临时分支)。
- 一般我都是用 checkout 回退版本,查看历史代码,测试 bug 在哪
reset 详解
git reset [--hard|soft|mixed|merge|keep] [<commit>或HEAD]
:将当前的分支重设(reset
)到指定的 <commit>
或者 HEAD
(默认,如果不显示指定 <commit>
,默认是 HEAD
,即最新的一次提交),并且根据 [mode]
有可能更新索引和工作目录。mode
的取值可以是 hard
、soft
、mixed
、merged
、keep
。git reset
有很多种用法。它可以被用来移除提交快照,尽管它通常被用来撤销暂存区和工作区的修改。不管是哪种情况,它应该只被用于本地修改——你永远不应该重设和其他开发者共享的快照。
- 当你用 reset 回滚到了某个版本后,那么在下一次 git 提交时,之前该版本后面的版本会被作为垃圾删掉。
- 当我们回退到一个旧版本后,此时再用 git log 查看提交记录,会发现之前的新版本记录没有了。如果第二天,你又想恢复到新版本怎么办?找不到新版本的 commit_id 怎么办?
我们可以用
git reflog
查看历史命令,这样就可以看到之前新版本的 commit_id ,然后 git reset --hard commit_id
就可以回到之前的新版本代码- 虽然可以用 git reflog 查看本地历史,然后回复到之前的新版本代码,但是在别的电脑上是无法获取你的历史命令的,所以这种方法不安全。万一你的电脑突然坏了,这时候就无法回到未来的版本。
revert 详解
git revert
命令用来撤销某个已经提交的快照(和 reset 重置到某个指定版本不一样)。它是在提交记录最后面加上一个撤销了更改的新提交,而不是从项目历史中移除这个提交,这避免了 Git 丢失项目历史。撤销(revert)应该用在你想要在项目历史中移除某个提交的时候。比如说,你在追踪一个 bug,然后你发现它是由一个提交造成的,这时候撤销就很有用。
撤销(revert)被设计为撤销公共提交的安全方式,重设(reset)被设计为重设本地更改。
因为两个命令的目的不同,它们的实现也不一样:重设完全地移除了一堆更改,而撤销保留了原来的更改,用一个新的提交来实现撤销。千万不要用
git reset
回退已经被推送到公共仓库上的 提交,它只适用于回退本地修改(从未提交到公共仓库中)。如果你需要修复一个公共提交,最好使用 git revert。发布一个提交之后,你必须假设其他开发者会依赖于它。移除一个其他团队成员在上面继续开发的提交在协作时会引发严重的问题。当他们试着和你的仓库同步时,他们会发现项目历史的一部分突然消失了。一旦你在重设之后又增加了新的提交,Git 会认为你的本地历史已经和 origin/master 分叉了,同步你的仓库时的合并提交(merge commit)会使你的同事困惑。
cherry-pick
将指定的提交 commit 应用于当前分支(可以用于恢复不小心撤销(revert/reset)的提交)
git bisect
- 快速找出有 bug 的 commit
- 它的原理很简单,就是将代码提交的历史,按照两分法不断缩小定位。所谓"两分法",就是将代码历史一分为二,确定问题出在前半部分,还是后半部分,不断执行这个过程,直到范围缩小到某一次代码提交。
git submodule 子模块
有种情况我们经常会遇到:某个工作中的项目需要包含并使用另一个项目。也许是第三方库,或者你独立开发的,用于多个父项目的库。 现在问题来了:你想要把它们当做两个独立的项目,同时又想在一个项目中使用另一个。如果将另外一个项目中的代码复制到自己的项目中,那么你做的任何自定义修改都会使合并上游的改动变得困难。Git 通过子模块来解决这个问题,允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。
新建一个 Git 项目的两种方式
1.本地新建好 Git 项目,然后关联远程仓库
2.clone 远程仓库
Git 分支管理规范
- 实际开发的时候,一人一条分支(个人见解:除非是大项目,参与的开发人员很多时,可以采用 feature 分支,否则一般的项目中,一个开发者一条分支够用了)。除此之外还要有一条 develop 开发分支,一条 test 测试分支,一条 release 预发布分支。
- develop:开发分支,开发人员每天都需要拉取/提交最新代码的分支;
- test:测试分支,开发人员开发完并自测通过后,发布到测试环境的分支;
- release:预发布分支,测试环境测试通过后,将测试分支的代码发布到预发环境的分支(这个得看公司支不支持预发环境,没有的话就可以不采用这条分支);
- master:线上分支,预发环境测试通过后,运营/测试会将此分支代码发布到线上环境;
- 大致流程:
- 开发人员每天都需要拉取/提交最新的代码到 develop 分支;
- 开发人员开发完毕,开始 集成测试,测试无误后提交到 test 分支并发布到测试环境,交由测试人员测试;
- 测试环境通过后,发布到 release 分支 上,进行预发环境测试;
- 预发环境通过后,发布到 master 分支上并打上标签(tag);
- 如果线上分支出了 bug ,这时候相关开发者应该基于预发布分支(没有预发环境,就使用 master 分支),新建一个 bug 分支用来临时解决 bug ,处理完后申请合并到 预发布 分支。这样做的好处就是:不会影响正在开发中的功能。
预发布环境的作用: 预发布环境是正式发布前最后一次测试。因为在少数情况下即使预发布通过了,都不能保证正式生产环境可以100%不出问题;预发布环境的配置,数据库等都是跟线上一样;有些公司的预发布环境数据库是连接线上环境,有些公司预发布环境是单独的数据库;如果不设预发布环境,如果开发合并代码有问题,会直接将问题发布到线上,增加维护的成本。
Git 钩子
- Git 基本已经成为项目开发中默认的版本管理软件,在使用 Git 的项目中,我们可以为项目设置 Git Hooks 来帮我们在提交代码的各个阶段做一些代码检查等工作
- 钩子(Hooks) 都被存储在 Git 目录下的 hooks 子目录中。 也就是绝大部分项目中的 .git/hook 目录
- 钩子分为两大类,客户端的和服务器端的
- 客户端钩子主要被提交和合并这样的操作所调用
- 而服务器端钩子作用于接收被推送的提交这样的联网操作,这里主要介绍客户端钩子
4.1 pre-commit
pre-commit
就是在代码提交之前做些东西,比如代码打包,代码检测,称之为钩子(hook)
- 在 commit 之前执行一个函数(callback)。这个函数成功执行完之后,再继续 commit,但是失败之后就阻止 commit
- 在 .git->hooks->下面有个 pre-commit.sample* ,这个里面就是默认的函数(脚本)样本
4.2 安装 pre-commit
4.3 配置脚本
如果没有在
.git->hooks
目录下生成 pre-commit
文件的话,则要手工创建 node ./node_modules/pre-commit/install.js
4.4 跳过 pre-commit 继续提交代码
作者:秋天不落叶链接:https://juejin.cn/post/6844904191203213326来源:稀土掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Loading...