Git的高效使用 git的基础 高级用法
前言
什么是Git
在日常的软件开发过程中,软件版本的管理都离不开使用Git,Git是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。 也是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源码的版本控制软件。常见的软件版本管理工具还有SVN
git和svn的区别
两者区别
1、Git是分布式的,SVN是集中式的
2、Git复杂概念多,SVN简单易上手
3、Git分支廉价,SVN分支昂贵
4、SVN更适用于项目管理, Git仅适用于代码管理
git和svn适用范围
svn和git适用范围
1、适用对象不同。Git适用于参与开源项目的开发者,注重效率;SVN适合普通的公司开发团队,使用简单且权限管理很细致
2、使用的场合不同。Git适用于通过Internet,有多个开发角色的单个项目开发(同样也试用于多项目);SVN适合企业内部由项目经理统一协调的多个并行项目的开发
3、分支(branch)的使用范围不一样。Git中,你只能针对整个仓库作branch;而SVN中,branch可以针对任何子目录,它本质上是一个拷贝操作
4、局部更新,局部还原。SVN由于是在每个文件夹建立一个.svn文件夹来实现管理,所以可以很简单实现局部更新或者还原。当然git也可以通过历史版本还原,但是无法简单地实现局部还原。
基础使用
git核心概念
1、工作区(Workspace)
类比电脑中实际的目录。
2、暂存区(Index)
类似于缓存区域,临时保存你的改动。
3、仓库区(Repository)
分为本地仓库和远程仓库
基础命令
- clone(克隆): 从远程仓库中克隆代码到本地仓库
- checkout (检出):从本地仓库中检出一个仓库分支然后进行修订
- add(添加): 在提交前先将代码提交到暂存区
- commit(提交): 提交到本地仓库。本地仓库中保存修改的各个历史版本
- fetch (抓取) : 从远程库,抓取到本地仓库,不进行任何的合并动作,一般操作比较少。
- pull (拉取) : 从远程库拉到本地库,自动进行合并(merge),然后放到到工作区,相当于 fetch+merge
- push(推送) : 修改完成后,需要和团队成员共享代码时,将代码推送到远程仓库
工作流程
1.从远程仓库中克隆或拉取代码到本地仓库(clone/pull)
2.从本地进行代码修改
3.在提交前先将代码提交到暂存区
4.提交到本地仓库。本地仓库中保存修改的各个历史版本
5.修改完成后,需要和团队成员共享代码时,将代码push到远程仓库
开发中分支使用原则及流程
几乎所有的版本控制系统都以某种形式支持分支。 使用分支意味着你可以把你的工作从开发主线上分离开来进行重大的Bug修改、开发新的功能,以免影响开发主线。在开发中,一般有如下分支使用原则与流程:
- master (生产) 分支 线上分支,主分支,中小规模项目作为线上运行的应用对应的分支;
- develop(开发)分支 是从master创建的分支,一般作为开发部门的主要开发分支,如果没有其他并行开发不同期上线要求,都可以在此版本进行开发,阶段开发完成后,需要是合并到master分支,准备上线。
- feature/xxxx 分支 从develop创建的分支,一般是同期并行开发,但不同期上线时创建的分支,分支上的研发任务完成后合并到develop分支。
- hotfix/xxxx 分支 从master派生的分支,一般作为线上bug修复使用,修复完成后需要合并到master、test、develop分支。 - 还有一些其他分支,在此不再详述,例如test分支(用于代码测试)、pre分支(预上线分支)等等。
高级用法
stash
官方解释:
当您想记录工作目录和索引的当前状态,但又想返回一个干净的工作目录时,请使用git stash。该命令将保存本地修改,并恢复工作目录以匹配头部提交。
stash 命令能够将还未 commit 的代码存起来,让你的工作目录变得干净。
应用场景
某一天你正在 feature 分支开发新需求,突然产品经理跑过来说线上有bug,必须马上修复。而此时你的功能开发到一半,于是你急忙想切到 master 分支,然后你就会看到以下报错:
因为当前有文件更改了,需要提交commit保持工作区干净才能切分支。由于情况紧急,你只有急忙 commit 上去,commit 信息也随便写了个“暂存代码”,于是该分支提交记录就留了一条黑历史…(这种虽然能解决问题,但是是不正确的用法,)
如果你学会 stash,就不用那么狼狈了。
你只需要:git stash
恢复代码:git stash apply
相关命令
当有多条 stash,可以指定操作stash,首先使用stash list 列出所有记录:
然后指定对应的记录进行相应操作
reset --soft
官方解释
完全不接触索引文件或工作树(但会像所有模式一样,将头部重置为某个状态)。这使您的所有更改的文件更改为“要提交的更改”。
回退你已提交的 commit,并将 commit 的修改内容放回到暂存区。一般我们在使用 reset 命令时,git reset --hard 会被提及的比较多,它能让 commit 记录强制回溯到某一个节点。而 git reset --soft 的作用正如其名,–soft (柔软的) 除了回溯节点外,还会保留节点的修改内容。
应用场景
应用场景1:有时候手滑不小心把不该提交的内容 commit 了,这时想改回来,只能再 commit 一次,又多一条“黑历史”。
应用场景2:规范些的团队,一般对于 commit 的内容要求职责明确,颗粒度要细,便于后续出现问题排查。本来属于两块不同功能的修改,一起 commit 上去,这种就属于不规范。这次恰好又手滑了,一次性 commit 上去。
reset --soft 相当于后悔药,给你重新改过的机会。对于上面的场景,就可以再次修改重新提交,保持干净的 commit 记录。
以上说的是还未 push 的commit。对于已经 push 的 commit,也可以使用该命令,不过再次 push 时,由于远程分支和本地分支有差异,需要强制推送 git push -f 来覆盖被 reset 的 commit。
举个栗子
commit 记录有 c、b、a。(右图)
reset 到 a。
此时的 HEAD 到了 a,而 b、c 的修改内容都回到了暂存区。
cherry-pick
官方解释
给定一个或多个现有提交,应用每个提交引入的更改,为每个提交记录一个新的提交。这需要您的工作树清洁
将已经提交的 commit,复制出新的 commit 应用到分支里
应用场景
应用场景1:有时候版本的一些优化需求开发到一半,可能其中某一个开发完的需求要临时上,或者某些原因导致待开发的需求卡住了已开发完成的需求上线。这时候就需要把 commit 抽出来,单独处理。
应用场景2:有时候开发分支中的代码记录被污染了,导致开发分支合到线上分支有问题,这时就需要拉一条干净的开发分支,再从旧的开发分支中,把 commit 复制到新分支。
举例子
复制单个,举个栗子:现在有一条feature分支,commit 记录如右图:(复制多个,可以参考git cherry-pick commit1 commit2; 复制区间,可以参考git cherry-pick commit1^…commit2)
需要把 b 复制到另一个分支,首先把 commitHash 复制下来,然后切到 master 分支。
当前 master 最新的记录是 a,使用 cherry-pick 把 b 应用到当前分支。
完成后看下最新的 log,b 已经应用到 master,作为最新的 commit 了。可以看到 commitHash 和之前的不一样,但是提交时间还是保留之前的。
revert
官方解释
给定一个或多个现有提交,恢复相关提交引入的更改,并记录一些这些更改的新提交。这就要求你的工作树是干净的
将现有的提交还原,恢复提交的内容,并生成一条还原记录。
应用场景
应用场景1:有一天测试突然跟你说,你开发上线的功能有问题,需要马上撤回,否则会影响到系统使用。这时可能会想到用 reset 回退,可是你看了看分支上最新的提交还有其他同事的代码,用 reset 会把这部分代码也撤回了。由于情况紧急,又想不到好方法,如果任性的使用 reset,然后再让同事把他的代码合一遍(同事听到想打人)。
举例子
revert 普通提交
现在 master 记录如下:
revert 掉自己提交的 commit。
因为 revert 会生成一条新的提交记录,这时会让你编辑提交信息,编辑完后 :wq 保存退出就好了。
再来看下最新的 log,生成了一条 revert 记录,虽然自己之前的提交记录还是会保留着,但你修改的代码内容已经被撤回了。
reflog
官方解释
此命令管理重录中记录的信息
如果说 reset --soft 是后悔药,那 reflog 就是强力后悔药。它记录了所有的 commit 操作记录,便于错误操作后找回记录。
应用场景
应用场景1:某天你眼花,发现自己在其他人分支提交了代码还推到远程分支,这时因为分支只有你的最新提交,就想着使用 reset --hard,结果紧张不小心记错了 commitHash,reset 过头,把同事的 commit 搞没了。没办法,reset --hard 是强制回退的,找不到 commitHash 了,只能让同事从本地分支再推一次(同事瞬间拳头就硬了,怎么又是你)。
举例子
命令使用
分支记录如右,想要 reset 到 b。
误操作 reset 过头,b 没了,最新的只剩下 a。
这时用 git reflog 查看历史记录,把错误提交的那次 commitHash 记下。
再次 reset 回去,就会发现 b 回来了。