浅析git笔者在此整理了常见的git命令,git的重要性无需多言,与其再百度海中搜索git命令,不妨尝试收藏笔者的此篇作品。希望对你的学习有所帮助。版本控制系统之gitGit:(一)简介:Git 是一款免费的、开源的、分布式的版本控制系统。旨在快速高效地处理无论规模大小的任何软件工程。每一个 Git克隆 都是一个完整的文件库,含有全部历史记录和修订追踪能力,不依赖于网络连接或中心服务器。其最大特色就是“分支”及“合并”操作非常快速、简便。(二)Git与svn的主要区别:Git是分布式SCM,而SVN是基于服务器的,也就是说每个开发者本地都有一套git库,每个人维护自己的版本(或者合并其他人的版本),而SVN是每个人写完代码后都及时的checkin到服务器上,进行合并。Git的优势:说到优势,那么自然是相对与SVN而言的1.版本库本地化,支持离线提交,相对独立不影响协同开发。每个开发者都拥有自己的版本控制库,在自己的版本库上可以任意的执行提交代码、创建分支等行为。例如,开发者认为自己提交的代码有问题?没关系,因为版本库是自己的,回滚历史、反复提交、归并分支并不会影响到其他开发者。2.更少的“仓库污染”。git对于每个工程只会产生一个.git目录,这个工程所有的版本控制信息都在这个目录中,不会像SVN那样在每个目录下都产生.svn目录。3.把内容按元数据方式存储,完整克隆版本库。所有版本信息位于.git目录中,它是处于你的机器上的一个克隆版的版本库,它拥有中心版本库上所有的东西,例如标签、分支、版本记录等。4.支持快速切换分支方便合并,比较合并性能好。在同一目录下即可切换不同的分支,方便合并,且合并文件速度比SVN快。5.分布式版本库,无单点故障,内容完整性好。内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。本地创建git远程仓库:我这里使用的是:centos7.2、并且在服务器中已经创建git账户;如果没有创建git账户的朋友,需要先创建git,并且在服务器端安装git1.在本地建立一个空白的git仓库:Git –bare init注:–bare参数相当与只创建一个空白的仓库,只包含记录版本库历史记录的.git目录下面的文件,不会包含实际项目源文件的拷贝;2.将本地创建的仓库添加到远程服务器,使用的linux上传命令;Scp –r 文件夹 linux用户名@ip:/文件目录如:scp –r gittest.git root@123.207.172.12:/data./git (这里是将本地的gittest.git文件夹拷贝到服务器中 /data/git文件夹下)3.此时可以直接将本地的gittest文件夹关联远程仓库,也可以在本地再次克隆git仓库;使用命令如下:Git clone git@123.207.172.15:/data/git/gittest.git4.可以直接创建一个文件,进行上传测试;如:cd gittest 进入文件夹vi app.js 然后随便输入字符,esc+wq!进行保存退出;然后将操作添加至暂存区:Git add .创建本地仓库的版本:Git commit –m “haha”提交至远程服务器仓库:Git push origin master;注:如果此时出现此种错误:remote: error: insufficient permission for adding an object to repository database ./objects这时注意自己的服务器git账户是否有写的权限;一般是因为git账户对gittest.git文件夹权限不够;此时登陆自己的服务器,给git账户进行权限的赋予;命令为:Chown –R git:git /data/git/gittest.git权限操作完毕后,再次进行本地仓库与远程仓库的同步,一般此时不再会进行报错;注:服务器git仓库的创建也可以直接在linux操作系统中进行;本地git创建仓库与github的远程仓库相关联:1.首先登陆github官网;进行注册、登录2.创建新的仓库3.在本地创建git仓库mkdir githubtestgit initvi app.js注:https协议和ssh协议的区别就是每次远程操作都需要输入github的用户名和密码;4.https协议:Git remote add origin https://github.com/misterguan...Git add .Git commit –m “haha”Git push –u origin master此时需要输入github的用户名和密码此时会报错: error: failed to push some refs to(此种原因一般为在github的远程仓库有文件,在本地仓库没有,所以此时应该先将远程仓库合并到本地仓库,再进行提交)git pull –rebase origin master注意:这里的rebase和merge的区别,简单理解,rebase在log中无分叉,而merge有再次提交,将会成功;ssh协议:首先需要创建密钥ssh-keygen –t rsa –C 837990335@qq.com可以一路回车;(Enter file in which to save the key (/c/Users/dream/.ssh/id_rsa):这里默认就可以,这是存放ssh密钥的路径)(Enter passphrase (empty for no passphrase):这里为ssh的密码,可以为空)然后到C:Users用户 .ssh中找到id_rsa.pub,然后复制里面的密钥到github例:C:Usersdream.ssh在github的ssh and gpg keys中new ssh keyTitle为此ssh的标记Key为你本地的密钥测试下:ssh git@github.com如果输出You’ve successfully authenticated;说明链接成功;下面的操作跟https的一样:Git的分支管理:查看本地分支:$ git branch查看远程分支:$ git branch -r创建本地分支:$ git branch [name] —-注意新分支创建后不会自动切换为当前分支切换分支:$ git checkout [name]创建新分支并立即切换到新分支:$ git checkout -b [name]删除分支:$ git branch -d [name] —- -d选项只能删除已经参与了合并的分支,对于未有合并的分支是无法删除的。如果想强制删除一个分支,可以使用-D选项合并分支:$ git merge [name] —-将名称为[name]的分支与当前分支合并创建远程分支(本地分支push到远程):$ git push origin [name]删除远程分支:$ git push origin :heads/[name] 或 $ gitpush origin :[name] 项目开发的分支:Master:用于发布版本的分支;(用于大版本号更新时使用)Dev:开发时的主分支;Feature:功能分支;(开发某个局部分支,从dev分支上分出来的)Release:创建一个预发布分支(从dev分支上分出来,合并到master分支上,进行tag标注)Bug:bug分支(从master分支上分出来,修改完毕后合并到master和dev分支)分支合并在git进行分支的合并时如果使用默认的fast-farward merge直接修改当前HEAD指针的指向然后再修改当前HEAD指针,说白了就是修改两个指针的指向,而并没有生成新的commit对象。如果使用—no-ff 进行合并这样会在master分支上创建一个版本;git如何解决代码冲突:1.逻辑冲突git自动处理(合并/应用补丁)成功,但是逻辑上是有问题的。比如另外一个人修改了文件名,但我还使用老的文件名,这种情况下自动处理是能成功的,但实际上是有问题的。又比如,函数返回值含义变化,但我还使用老的含义,这种情况自动处理成功,但可能隐藏着重大BUG。这种问题,主要通过自动化测试来保障。所以最好是能够写出比较完备的自动化测试用例。这种冲突的解决,就是做一次BUG修正。不是真正解决git报告的冲突。2.内容冲突两个用户修改了同一个文件的同一块区域,git会报告内容冲突。我们常见的都是这种,后面的解决办法也主要针对这种冲突。如图中是:app.js冲突:然后手动修改冲突的文件:再次进行文件的提交,版本的创建;3.树冲突文件名修改造成的冲突,称为树冲突。比如,a用户把app.js改名为master.js,b用户把app.js文件改名为test.js,那么b将这两个commit合并时,会产生冲突。此时打开文件,把需要的删除的文件删除掉即可,如把master.js删除掉;然后,再次重新创建版本即可:git常用操作命令:1.查看、添加、提交、删除、找回,重置修改文件git help <command> # 显示command的helpgit show # 显示某次提交的内容 git show $idgit co – <file> # 抛弃工作区修改git co . # 抛弃工作区修改git add <file> # 将工作文件修改提交到本地暂存区git add . # 将所有修改过的工作文件提交暂存区git rm <file> # 从版本库中删除文件git rm <file> –cached # 从版本库中删除文件,但不删除文件git reset <file> # 从暂存区恢复到工作文件git reset – . # 从暂存区恢复到工作文件git reset –hard # 恢复最近一次提交过的状态,即放弃上次提交后的所有本次修改git ci <file> git ci . git ci -a # 将git add, git rm和git ci等操作都合并在一起做 git ci -am “some comments"git ci –amend # 修改最后一次提交记录git revert <$id> # 恢复某次提交的状态,恢复动作本身也创建次提交对象git revert HEAD # 恢复最后一次提交的状态2.查看文件diffgit diff <file> # 比较当前文件和暂存区文件差异 git diffgit diff <id1><id1><id2> # 比较两次提交之间的差异git diff <branch1>..<branch2> # 在两个分支之间比较git diff –staged # 比较暂存区和版本库差异git diff –cached # 比较暂存区和版本库差异git diff –stat # 仅仅比较统计信息3.查看提交记录git log git log <file> # 查看该文件每次提交记录git log -p <file> # 查看每次详细修改内容的diffgit log -p -2 # 查看最近两次详细修改内容的diffgit log –stat #查看提交统计信息tigMac上可以使用tig代替diff和log,brew install tig4.查看、切换、创建和删除分支git br -r # 查看远程分支git br <new_branch> # 创建新的分支git br -v # 查看各个分支最后提交信息git br –merged # 查看已经被合并到当前分支的分支git br –no-merged # 查看尚未被合并到当前分支的分支git co <branch> # 切换到某个分支git co -b <new_branch> # 创建新的分支,并且切换过去git co -b <new_branch> <branch> # 基于branch创建新的new_branchgit co $id # 把某次历史提交记录checkout出来,但无分支信息,切换到其他分支会自动删除git co $id -b <new_branch> # 把某次历史提交记录checkout出来,创建成一个分支git br -d <branch> # 删除某个分支git br -D <branch> # 强制删除某个分支 (未被合并的分支被删除的时候需要强制)5. 分支合并和rebasegit merge <branch> # 将branch分支合并到当前分支git merge origin/master –no-ff # 不要Fast-Foward合并,这样可以生成merge提交git rebase master <branch> # 将master rebase到branch,相当于: git co <branch> && git rebase master && git co master && git merge <branch>6. Git补丁管理(方便在多台机器上开发同步时用)git diff > ../sync.patch # 生成补丁git apply ../sync.patch # 打补丁git apply –check ../sync.patch #测试补丁能否成功7. Git暂存管理git stash # 暂存git stash list # 列所有stashgit stash apply # 恢复暂存的内容git stash drop # 删除暂存区8.Git远程分支管理git pull # 抓取远程仓库所有分支更新并合并到本地git pull –no-ff # 抓取远程仓库所有分支更新并合并到本地,不要快进合并git fetch origin # 抓取远程仓库更新git merge origin/master # 将远程主分支合并到本地当前分支git co –track origin/branch # 跟踪某个远程分支创建相应的本地分支git co -b <local_branch> origin/<remote_branch> # 基于远程分支创建本地分支,功能同上git push # push所有分支git push origin master # 将本地主分支推到远程主分支git push -u origin master # 将本地主分支推到远程(如无远程主分支则创建,用于初始化远程仓库)git push origin <local_branch> # 创建远程分支, origin是远程仓库名git push origin <local_branch>:<remote_branch> # 创建远程分支git push origin :<remote_branch> #先删除本地分支(git br -d <branch>),然后再push删除远程分支9.Git远程仓库管理GitHubgit remote -v # 查看远程服务器地址和仓库名称git remote show origin # 查看远程服务器仓库状态git remote add origin git@ github:robbin/robbin_site.git # 添加远程仓库地址git remote set-url origin git@ github.com:robbin/robbin_site.git # 设置远程仓库地址(用于修改远程仓库地址) git remote rm <repository> # 删除远程仓库10.创建远程仓库git clone –bare robbin_site robbin_site.git # 用带版本的项目创建纯版本仓库scp -r my_project.git git@ git.csdn.net:~ # 将纯仓库上传到服务器上mkdir robbin_site.git && cd robbin_site.git && git –bare init # 在服务器创建纯仓库git remote add origin git@ github.com:robbin/robbin_site.git # 设置远程仓库地址git push -u origin master # 客户端首次提交git push -u origin develop # 首次将本地develop分支提交到远程develop分支,并且trackgit remote set-head origin master # 设置远程仓库的HEAD指向master分支也可以命令设置跟踪远程库和本地库git branch –set-upstream master origin/mastergit branch –set-upstream develop origin/develop项目自动化:现在的前端开发已经不再仅仅只是静态网页的开发了,日新月异的前端技术已经让前端代码的逻辑和交互效果越来越复杂,更加的不易于管理,模块化开发和预处理框架把项目分成若干个小模块,增加了最后发布的困难,没有一个统一的标准,让前端的项目结构千奇百怪。前端自动化构建在整个项目开发中越来越重要。(一)工具化在前端的技术栈发展过程中,出现了很多的工具,形成了工具化,能够用工具完成的绝不要手工完成,来帮助开发者提升效率。前端工作流工具: Gulp,Grunt前端js模块编译工具:Babel,Browserify,Webpack包管理器: npm,bower前端开发系列工具: livereload,数据mock,代码监控,代码检查。(二)工程化工程化是一个发展趋势,以工具化为基础。工程的核心是流程自动化,又称为构建,这些包括了:代码质量检测,代码压缩,代码合并,代码优化,代码编译,单元测试等等部分。构建就是把这些以工作流程的方式组合起来,然后用一个命令行运行这整个流程。它有点像批处理,但是是程序开发中使用的特殊批处理。(三)自动化自动化是以工程化为基础,是在流程自动化上更进一步的自动化。持续集成就是全自动化的一个终极体现。他的主要流程是:版本控制库 ->构建 ->测试 ->报告.(四)代码规范代码规范可以提高代码的可阅读性和避免一些低级错误。为了将代码规范的检查放到前端开发工程中,各种前端语言都有对应的hint或者lint工具。(五)预处理SASS甚至为了避免这一点,引入了各种预编译语言,css的预编译less,现在流行的是sass,功能也更加强大,语法错误无法通过编译,来弥补css这种缺陷。(六)ES6js的预处理语言也有很多,只是为了让有其他语言经验的开发者更容易的上手js的编码。因为浏览器的实现大多还是 ES5 的标准,为了使用最新的 ES6 语法,通常的做法是采用 Babel 将 ES6 编译为 ES5。(七)js模块化amd,cmd,common,es6(八)文件处理通常一个前端项目会分有一个 src 目录和 dist 目录, src 放置源码,dist 放置编译后的代码。所以在前端工程的流程中会涉及到文件的拷贝,删除,移动等流程。(九)开发效率通常的前端开发过程是,修改前端代码,调用命令编译代码,然后浏览器 F5 刷新。这个过程可以做到自动化,通过代码监控工具,指定要监控的目录和文件,如果对应文件有改变,调用编译工具编译源码,然后通过 livereload 自动刷新浏览器。 gulp-browserify也可以实现同样的功能。(十)数据的mock现代化前端项目开发大多是前后端分离的方式,也就是后端基本是提供 API 服务,在真实开发环境中,通常的问题是,后端 API 极其不稳定或者没开发,为了不阻碍前端的开发,通常的做法是,前后端先约定 API 接口定义,然后前端根据定义 mock 接口。(十一)前端工作流为了解决前端工程中复杂的流程,出现了很多开源前端流程处理工具。这些工作流工具不仅仅是其本身,都是一个流程生态体系,每个工具都涉及到对应的插件库,几乎我们能想到的前端工程问题都有对用的插件能够解决。Gulp:Gulp 是基于node.js的一个前端自动化构建工具,开发这可以使用它构建自动化工作流程(前端集成开发环境)。 使用gulp你可以简化工作量,让你把重点放在功能的开发上,从而提高你的开发效率和工作质量。 gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简单,学习起来很容易,而且gulpjs使用的是nodejs中stream来读取和操作数据,其速度更快(一)安装:需要在全局或者项目中同时安装;Cnpm install -g gulp Cnpm install –save-dev gulp(二)配置文件使用gulpfile.js进行配置,基于gulp工作流的项目结构如下:(三)Api:1.gulp.src(globs[, options]) 输出(Emits)符合所提供的匹配模式(glob)或者匹配模式的数组(array of globs)的文件。 将返回一个 Vinyl files 的 stream 它可以被 piped 到别的插件中。文件的入口A.路径匹配:1) :能匹配 a.js,x.y,abc,abc/,但不能匹配a/b.js2). :能匹配 a.js,style.css,a.b,x.y3)//.js :能匹配 a/b/c.js,x/y/z.js,不能匹配a/b.js,a/b/c/d.js4) 能匹配 : abc,a/b.js,a/b/c.js,x/y/z,x/y/z/a.b,能用来匹配所有的目录和文件5)*/.js :能匹配 foo.js,a/foo.js,a/b/foo.js,a/b/c/foo.js6)a//z :能匹配 a/z,a/b/z,a/b/c/z,a/d/g/h/j/k/z7)a/b/z :能匹配 a/b/z,a/sb/z,但不能匹配a/x/sb/z,因为只有单单独出现才能匹配多级目录8)?.js :能匹配 a.js,b.js,c.js9)a?? :能匹配 a.b,abc,但不能匹配ab/,因为它不会匹配路径分隔符10)[xyz].js :只能匹配 x.js,y.js,z.js,不会匹配xy.js,xyz.js等,整个中括号只代表一个字符11)1.js :能匹配 a.js,b.js,c.js等,不能匹配x.js,y.js,z.jsB.匹配多种文件//使用数组的方式来匹配多种文件gulp.src([‘js/.js’,‘css/.css’,’.html’])2.gulp.dest(path[, options]) 能被 pipe 进来,并且将会写文件。并且重新输出(emits)所有数据,因此你可以将它 pipe 到多个文件夹。如果某文件夹不存在,将会自动创建它。输出文件根路径:如果在src中不设置base时,所有的默认根路径,都是从出现匹配符的地方开始截取:如:gulp.src(‘app/src//.css’) //此时base的值为app/src,也就是说它的base路径为app/src //设该模式匹配到了文件 app/src/css/normal.css.pipe(gulp.dest(‘dist’)) //用dist替换掉base路径,最终得到 dist/css/normal.css如果增加base基路径:gulp.src(script/lib/.js, {base:‘script’}) //配置了base参数,此时base路径为script //假设匹配到的文件为script/lib/jquery.js .pipe(gulp.dest(‘build’)) //此时生成的文件路径为 build/lib/jquery.js3.gulp.task(name[, deps], fn) 定义一个使用 Orchestrator 实现的任务(task)。1)参数:Name:任务的名字,如果你需要在命令行中运行你的某些任务,那么,请不要在名字中使用空格。Deps:类型: Array,一个包含任务列表的数组,这些任务会在你当前任务运行之前完成。Fn:该函数定义任务所要执行的一些操作。2)异步任务A.使用callback:var gulp = require(‘gulp’);// 返回一个 callback,因此系统可以知道它什么时候完成gulp.task(‘one’, function(cb) {// 做一些事 – 异步的或者其他的cb(err); // 如果 err 不是 null 或 undefined,则会停止执行,且注意,这样代表执行失败了});// 定义一个所依赖的 task 必须在这个 task 执行之前完成gulp.task(’two’, [‘one’], function() {// ‘one’ 完成后});gulp.task(‘default’, [’two’]);B.使用promisevar gulp = require(‘gulp’);// 返回一个 callback,因此系统可以知道它什么时候完成gulp.task(‘one’, function(cb) {// 做一些事 – 异步的或者其他的return new Promise((res, rej) => { setTimeout(() => { res(1344) }, 5000)})});// 定义一个所依赖的 task 必须在这个 task 执行之前完成gulp.task(’two’, [‘one’], function() {// ‘one’ 完成后console.log(“two开始”)});gulp.task(‘default’, [’two’]);注意:5s后才开始执行的two任务3)对于同步任务: gulp.task(‘one’,function(cb){ var stream = gulp.src(‘client/**/.js’) .pipe(dosomething()) //dosomething()中有某些异步操作 .pipe(gulp.dest(‘build’)); return stream; }); gulp.task(’two’,[‘one’],function(){ console.log(’two is done’); });4.gulp.watch(glob[, opts], tasks)监视文件,并且可以在文件发生改动时做一些事情;1)监听文件改变,并执行相应的task任务var watcher = gulp.watch(‘js//.js’, [‘uglify’, ‘reload’]);watcher.on(‘change’, function(event) {console.log(‘File ’ + event.path + ’ was ’ + event.type + ‘, running tasks…’);});2)监听文件改变,并执行回调函数gulp.watch(‘js//.js’, function(event) {console.log(‘File ’ + event.path + ’ was ’ + event.type + ‘, running tasks…’);});(四)第三方插件:1.gulp-load-plugins:用来加载插件,避免我们再头部声明一堆插件,做到想用就用2.less:用于编译 .less文件3.autoprefixer:自动添加css前缀4.babel:es6 编译成 es55.uglify:JS压缩6.minify:CSS压缩7.rename:重命名8.sourcemaps:资源映射9.concat:合并文件10.del:删除文件、文件夹11.inject:文件注入12.notify:提示信息13.browser-sync:热启动14.http-proxy-middleware:配合browser-sync进行跨域15.changed:只有发生了改变的文件才能进入流中16.sequence:让task按顺序完成17.rev:添加MD518.watch:监听文件变化(五)实现项目自动化构建:使用gulp构建项目,项目中支持:1)js的模块化(可以实现模块化(common与require的切换));2)sass的编译;3)jslint的代码校验;4)划分本地启动配置和线上打包配置;5)实现文件的md5加密;6)实现本地的开发服务;7)实现mock数据8)实现本地实时刷新本篇文章内容还未补全,之后会做更多修改,以期待完成补全,不过对于初学git以及node的同学来说已然是够用了xyz ↩
浅析git
October 31, 2018 · 4 min · jiezi