浅析 git
笔者在此整理了常见的 git 命令,git 的重要性无需多言,与其再百度海中搜索 git 命令,不妨尝试收藏笔者的此篇作品。希望对你的学习有所帮助。
版本控制系统之 git
Git:
(一)简介: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,并且在服务器端安装 git
1. 在本地建立一个空白的 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.git
4. 可以直接创建一个文件,进行上传测试;如: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 tig
4. 查看、切换、创建和删除分支 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.js
B. 匹配多种文件 // 使用数组的方式来匹配多种文件 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. 使用 promise
var 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 ↩