SQLflow:基于python开发的分布式机器学习平台, 支持通过写sql的方式,运行spark, 机器学习算法, 爬虫

项目git:https://github.com/lqkweb/sql…SQLflow (python3+)Sqlflow based on python development, support to Spark, Flink, etc as the underlying distributed computing engine, through a set of unified configuration file to complete the batch, flow calculation, the Rest service development.2019-01-22 更新界面,近期会规范一下代码,写一些注释并加入读写功能主页:结果页面:项目目标基于python开发的分布式机器学习平台, 支持通过写sql的方式,运行spark, 机器学习算法, 爬虫。安装python3环境, 执行项目git clone https://github.com/lqkweb/sql...pip install -r requirements.txt(sqlflow/sqlflow/execute/main.py 中的data.csv需要修改成你电脑中的绝对路径,数据文件在sqlflow/data/中)python manage.py打开http://127.0.0.1:5000 就可以测试了。项目测试在http://127.0.0.1:5000/demo输入框输入:测试1:select * from A limit 3;测试2:select * from A limit 3 as B;新开一个http://127.0.0.1:5000/demo网页, 直接就可以查询数据表B了:select * from B limit 2;as B 相当于创建了一个B临时表。是不是很简单。正在新增sql版机器学习算法功能, 谢谢支持。正在新增sql版爬虫功能, 谢谢支持。记得给个start鼓励一下!Thanks♪(・・)ノ

February 15, 2019 · 1 min · jiezi

5分钟入门git模式开发

本文由云+社区发表作者:唐维黎导语基于gui工具TortoiseGit让你快速进入git开发模式。目前项目已逐步从svn移步到git开发模式,其中也针对git统一协议了适合git的开发规范, 最重要一点就是分支模型的,为了规范开发,不直接在主干上修改代码,一切代码都提交至分支dev,然后再由分支合并到主干master。 首先保证每个仓库下有以下两个常驻分支(永远不删除的分支): master:主干分支,始终保持跟外网服务器一致,只用于外网发布,这样就可以保证文件不会带出去的风险; dev:基于master创建,用于开发新功能和新需求的分支。开发流程如下:1. 基于dev分支创建dev-xxx分支,开始进行普通的常规需求开发,开发完成后,Commit提交代码到本地仓库,如果这个新项目或者功能比较大有多人协同开发,怕会相互影响对方的代码,现从dev-xxx分支创建新分支dev-xxx-user进行开发,前提是dev-xxx分支需要push到线上;2. 开发完成后将dev-xxx分支合并到dev分支,然后部署dev到测试环境进行测试,测试过程中有bug的话修复完后同样合并到dev分支。如果是在多人协同开发的情况下先将dev-xxx-user分支合并到dev-xxx,再将dev-xxx合并到dev分支;3. 测试完成后,将dev分支合并到master分支,然后进行正式发布。发布完成后删除dev-xxx和dev-xxx-user分支; 如果担心在最后一步合并代码到master时有问题,也可以在测试的时候随时更新到本地master(先checkout master分支到本地),但不要push到线上,本地master 如果一定push到线上的话,这就要保证你的需求未测试发布前,别人不会发master与你相关的文件另外,如果是外网BUG或者日常,就可以在master上直接创建分支,修复完成后发布,定时同步dev分支,这样可以提高效率 ~ 下面以一个简单的需求来实际操作下,看看TortoiseGit的使用方法: (前提本地是有安装git和TortoiseGit)1. 克隆代码仓库到本地在指定文件夹下,右键 -> Git Clone.. 点确定后会提示你输入用户名和密码,这个跟svn类似 然后等待一会代码就成功克隆到本地了,速度比svn要快很多,另外也可以直接用命令行的方式git clone XXXXX.git代码克隆后,后续分支都是在本地的同一份代码上进行分支创建,而无需再次克隆2. 创建本地分支创建分支前请实时git pull线上仓库到本地,保证本地dev是最新 进入刚克隆下来的目录,右键 -> TortoiseGit -> Create Branch..3. 查看及切换当前分支右键 -> TortoiseGit -> Switch/Checkout… 切换成功后,可通过Git bash查看是否真的切换过来 也可以在命令行直接git branch查看,高亮的为当前分支 重要:注意在开发的时候请保证当前自己所修改的代码是当前需求的分支4. 开发完成后Commit右键 Git Commit -> ‘dev-xxx’ 提交记录一定要填 ,其它信息可选Commit到本地仓库,Commit这里也可以直接一次性push到线上仓库,但一般情况下不会这么干, 在多人协作的时候,其他人要合并代码到dev-xxx分支时可以直接一键commit+push5. 合并分支首先切换到要合并的目标分支(切换分支见上述3),本次要将dev-xxx合并到dev分支,我们切换到dev分支, 右键 -> TortoiseGit -> Merge…6. 提交到线上仓库右键 -> TortoiseGit -> Push…会要求你输入用户名和密码 提交成功后,提单部署测试环境7. 合并到master主干分支测试通过并完成后,将dev分支合并到master并push到线上仓库,提单发布外网, 合并到master的时候,可以将线上的master分支checkout到本地,然后进行本地的dev和master合并,再push到线上, 也可以直接将本地dev直接合并到线上master(remotes/origin/master)分支,本地合并冲突比较好解决,也不会影响线上。到此本次需求完成此文已由腾讯云+社区在各渠道发布获取更多新鲜技术干货,可以关注我们腾讯云技术社区-云加社区官方号及知乎机构号

February 15, 2019 · 1 min · jiezi

一秒搭建gitbook

gitbook docker 镜像为gitbook docker镜像效果图效果如下图所示使用说明环境准备需要docker环境。使用步骤第一种请先frok本项目frok完成以后,登录主机,输入如下命令,项目拉取下来git clone [您的frok项目地址];进行本地构建,输入如下代码sudo docker build ./ -t gitbook:vo运行该镜像sudo docker run -p 4000:4000 gitbook:vo访问地址http://[服务器ip]:4000/使用自动化工具进行构建(推荐)推荐使用自动化构建工具,在本地自动化构建推荐的工具有 docker hub https://cloud.docker.com/travis-ci https://travis-ci.orgdaocloud https://dashboard.daocloud.io日常使用当自动化构建完成以后,日常使用如下本地clone项目git clone [您的github地址]在work目录下进行编辑使用详见gitbook的使用教程栗子已经有一个已经部署好的啦。访问http://test.iming.info/github地址https://github.com/mySoul8012…

February 13, 2019 · 1 min · jiezi

记录一次过程(1):Building Mosquitto from the git repository

MosquittoMosquittto是针对MQTT 3.1版本和3.1.1版本的一个开源实现的服务器。它包含C和C++的客户端库,以及用于publish/subscribe的实用程序:mosquitto_pub/mosquitto_sub。Mosquitto项目对于如何Building from source描述并不足够清晰,但其实步骤也还算简单。步骤1.cmake使用命令cmake -DWITH_TLS_PSK=OFF -DWITH_TLS=OFF得到– Configuring done– Generating done这两行中间有warning,由于我只是需要搭建一个简单的环境做简单地测试,就没有管warning。2.make使用命令make得到[100%] Linking C executable mosquitto[100%] Built target mosquitto3.sudo make install使用命令sudo make install报错。报错信息如下:Install the project…– Install configuration: “”– Up-to-date: /usr/local/etc/mosquitto/mosquitto.conf– Up-to-date: /usr/local/etc/mosquitto/aclfile.example– Up-to-date: /usr/local/etc/mosquitto/pskfile.example– Up-to-date: /usr/local/etc/mosquitto/pwfile.example– Up-to-date: /usr/local/lib/pkgconfig/libmosquitto.pc– Up-to-date: /usr/local/lib/pkgconfig/libmosquittopp.pc– Installing: /usr/local/lib/libmosquitto.1.5.5.dylib– Up-to-date: /usr/local/lib/libmosquitto.1.dylib– Up-to-date: /usr/local/lib/libmosquitto.dylib– Up-to-date: /usr/local/include/mosquitto.h– Installing: /usr/local/lib/libmosquittopp.1.5.5.dylib– Up-to-date: /usr/local/lib/libmosquittopp.1.dylib– Up-to-date: /usr/local/lib/libmosquittopp.dylib– Up-to-date: /usr/local/include/mosquittopp.h– Installing: /usr/local/bin/mosquitto_pub– Installing: /usr/local/bin/mosquitto_sub– Installing: /usr/local/sbin/mosquitto– Up-to-date: /usr/local/include/mosquitto_broker.h– Up-to-date: /usr/local/include/mosquitto_plugin.hCMake Error at man/cmake_install.cmake:36 (file): file INSTALL cannot find “/Users/xxxx/Desktop/iMac-mosquitto/mosquitto-master/man/mosquitto_passwd.1”.Call Stack (most recent call first): cmake_install.cmake:57 (include)make: * [install] Error 1报错之后首先检查报错信息,google之后仍然有解决方面的困难。这时我们注意到上面加粗的三行,切换到安装目录 /usr/local/include/ 后运行命令 mosquitto发现可以运行,但是在安装目录外就不可以运行。这时候我们的下一步就是配置环境变量,从而使mosquitto的运行不受当前目录的限制。4.添加环境变量环境变量的作用是:可以在操作系统的各个目录下,都能访问到需要的工具目录内的内容。我参考的是Mac OS X 系统的环境变量配置分别将/usr/local/bin/以及/usr/local/sbin/加入环境变量之后(我将路径加入了用户级的~/.bash_profile),就可以运行mosquitto了。但是还有一个烦人的小问题,就是Mac每次都要执行source /.bash_profile,配置的环境变量才生效。解决方法是:在/.zshrc文件最后,增加一行: source ~/.bash_profile5.运行测试先开一个terminal,输入命令mosquitto。打开第二个terminal,输入命令mosquitto_sub -h localhost -t test。打开第三个terminal,输入命令mosquitto_pub -h localhost -t test -m “hello world”。发现在第二个terminal上出现了hello world字符串,即成功。6.思考几个问题,后续解决。直接用cmake .是会由于OpenSSL的路径问题报错的,OpenSSL是干什么用的?我没有去解决OpenSSL的路径问题,而是忽略了它,关闭了TLS直接cmake的。TLS又是什么?起到了什么作用?程序运行起来经过了哪些步骤?一个大型项目是如何安装运行起来的?为什么安装mosquitto的步骤是cmake->make->sudo make install? ...

February 11, 2019 · 1 min · jiezi

一个成功的Git分支模型

本文翻译至:https://nvie.com/posts/a-succ…译者: TopJohn原文连接:https://www.xuanzhangjiong.to…版权归作者所有,商业使用请联系作者一个成功的Git分支模型在这篇文章中,我将介绍一下在一年前非常成功的不仅是工作也包括私人项目的开发模型。我一直想写关于开发模型相关的内容,但是从来没有像现在这么强烈。在这里,我并不想将任何项目的细节,仅仅是想表达关于分支策略以及发布管理相关的内容。为什么选择git?有关Git与集中式源代码控制系统的优缺点讨论,请参阅网站。在代码的控制系统中,硝烟弥漫。作为一个开发者,在今天,相比于其他工具我更喜欢Git。Git真的改变了开发者对合并和分支的想法。从我来看经典的CVS/Subversion世界,合并/分支通常被认为是令人害怕的(“小心合并冲突,它们会咬你!”),而且是每过一段时间都会做的事情。但是对于Git来说,这些操作是极其廉价和简单的,它们真的被认为是您日常工作流程中的核心部分之一。例如,在CVS/Subversion书籍中,分支和合并在后续的章节中首次讨论(而且是对于高级用户),但是在Git书籍中,它们在第三章中就出现了(基础部分)。由于其简单和重复的性质,分支和合并变得不再那么可怕。版本控制工具应该比其他任何东西更有助于分支/合并。当我们有了足够的了解,让我们进入开发模型中去。我将在这里呈现的模型实质上只是一套每个团队成员都应该遵循的软件开发模式。分散但集中我们使用的仓库和分支模型配合得不错,是一个可信的中心化的仓库,这里指的是初始化的远程仓库。不过要注意,这是唯一的一个被认为是中央库的仓库(因为Git是一个分布式的版本管理系统,在技术层面上来讲没有一个中心化的仓库)。我们会把这个仓库称为origin(原始库),因为它的名字对所有用户来说都比较熟悉。每一个开发者将代码拉取或者推送到origin(原始库)中。但是除了集中式的推拉关系之外,每个开发者也可以从其他节点获取变更来形成子团队。举个例子,当两个或者更多的开发者一起开发一个新特性,这将变得非常有用,可以避免过早地将代码推送到原始库中。在上图中,Alice和Bob是一个子团队,Alice和David是一个子团队,Clair和David是一个子团队。在技术上,这意味着Alice定义了一个远程分支,叫做bob,指向了Bob的仓库,反之亦然。主分支在核心部分,开发模式很大程度受到了传统模型的影响。中央库一直维护2个可以无限延伸的分支:master 分支develop 分支在原始库中,master分支应该被所有用户所熟知。和master分支并行的还有另一个分支叫做develop分支。我们把origin/master分支作为主分支,这个分支代码的HEAD指针总是指向生产版本代码的一个准备状态。我们把origin/develop分支作为一个反映下一次需要交付的代码变更的分支。有人会叫develop分支为“集成分支”。这是所有夜间自动构建的出处。当源代码在develop分支中到达一个稳定的状态之后,已经准备好发布了,那么所有的变更应该以某种方式被合并回master分支。同时打上版本号。这个操作会在后续进行详细讲解。因此,每次当变更被合并到主分支的时候,将定义一个新的生产版本。我们对此非常严格,因此从理论上来说,我们可以使用Git hook脚本在每次对master分支进行提交代码的时候进行构建和在你的生产服务器上发布你的软件。辅助分支接下,来,除了master分支和develop分支你的开发模型上需要使用一系列的辅助分支来帮助团队的成员平行地开发,轻松地追踪一些特性,为生产发布做准备,并帮助快速修复生产版本代码的问题。不像主分支,这些分支的生命周期是有限的,因为它们最终将会被移除。我们使用不同类型的分支:Feature 分支Release 分支Hotfix 分支这些分支每一个都有特定的目的以及严格的规则,例如什么分支可以作为它们的原始分支,什么分支可以作为他们合并的目标。接下来我们将展开讨论。从技术角度来讲,这些分支绝对不是“特殊的”。这些分支的类型取决于我们如何去使用它们。它们同样是平凡的Git分支。功能分支(feature branches)功能分支可能从develop分支分离出来,但是必须合并到develop分支中去。功能分支的命名规范:除了master,develop,release-,或者hotfix-之外的名字都可以。功能分支(或者有时候叫做主题分支)是被用来开发即将发布或者未来版本的新功能的分支。在开发新功能的时候,目标的需要合并的发布版本可能在那个时候还不确定。功能分支的本质是它存在于新功能开发的过程中,最终将被合并到develop开发分支中去(为一个发布版本添加一个新特性)或者被丢弃(在实验情况令人失望的情况下)。功能分支通常仅存在于开发人员的仓库中,而不是远程的原始库中。创建一个功能分支当要开发一个新功能的时候,一般都是从develop分支检出一个新分支。$ git checkout -b myfeature developSwitched to a new branch “myfeature"合并一个已经完成的分支到develop分支完成的功能将会被合并到develop分支,以确保将它们添加到即将发布的版本中;$ git checkout developSwitched to branch ‘develop’$ git merge –no-ff myfeatureUpdating ea1b82a..05e9557(Summary of changes)$ git branch -d myfeatureDeleted branch myfeature (was 05e9557).$ git push origin develop–no-ff标志-将导致创建一个新的commit标志,即使合并可以使用fast-forward模式。这可以避免丢失功能分支的历史信息并将新特性和所有的提交合并到一起。比较:在后一种情况,是不可能从Git历史中看到哪些提交记录实现了这个功能-你必须通过手动读取所有的log记录才能获取到相关信息。恢复整个功能(即一组提交),在后一种情况下是真的很头疼,但是如果使用了–no-ff标志就很容易完成。虽然将多处几个(空的)提交记录,但是它的收益远大于成本。发布分支(Release branches)可能一个release分支是从develop分支切出来的,但是它必须被合并到develop或者master分支上去,分支的命名惯例一般是:release-*Release分支用于支持新的生产版本的发布。它允许在最后做一些点缀或者小修改。此外,它们允许修复小错误并且准备发布的元数据(例如版本号,构建日期等)。通过在发布分支上完成所有这些工作,develop分支将更明确地准备下一个大版本的发布。从develop分支创建release分支的关键时刻是develop分支达到了一个想要发布的理想状态。至少这次想要发布的特性必须被合并到develop分支在切出release分支之前。所有打算在未来发布的版本中特性需要在release分支切出来之后在合并进去。在release分支开始的时候为即将发布的版本分配一个版本号–而不是在release分支之前。直到那一刻,develop分支反映的变化都是为了下一次发版,但是至于下一次发版是0.3还是1.0是不清楚的,在release分支切出来之前。这个决定是在release分支开始的时候根据项目的规定定的,版本号也是根据项目的要求定的。创建一个release分支Release分支从develop分支创建。举个例子,假设1.1。5版本是当前的生产分支,我们即将推出一个大版本。目前develop分支的状态是已经好为下一个release做好了准备,并且决定下一个版本将是1.2版(而不是1.1.6或者2.0)。所以我们切出分支,并且附上一个新的版本号:$ git checkout -b release-1.2 developSwitched to a new branch “release-1.2”$ ./bump-version.sh 1.2Files modified successfully, version bumped to 1.2.$ git commit -a -m “Bumped version number to 1.2”[release-1.2 74d9424] Bumped version number to 1.21 files changed, 1 insertions(+), 1 deletions(-)在创建并切换到release分支之后,我们设置了版本号。这里,bump-version.sh虚构了一个shell脚本,改变一些文件来指向一个新的版本。(这里当然可以手动修改一些文件-来表明某些文件变了。)然后,设置的版本号就被提交了。这个新分支会存在一段时间,直到发布版本被正式推出。在这段时间,问题修复将在这个分支进行(而不是在develop分支)。在这里进行一些大的新特性的添加是不被允许的。它们必须被合并到develop分支,等待下一次大版本的发布。完成release分支当release分支的状态到达了一个真正的发布版本的时候,我们需要进行一些操作,以便完成这次发布。首先,release分支需要被合并到master分支中(因为根据定义master上的每一次提交都是一次新的发布,记住)。接下来,在master上的这个提交必须被打上标记,以便将来参考此历史版本。最终,在release分支上的变更需要合并到develop分支上去,以便后续的发布能够包含这些问题修复。Git中的前两步是:$ git checkout masterSwitched to branch ‘master’$ git merge –no-ff release-1.2Merge made by recursive.(Summary of changes)$ git tag -a 1.2这次发布就算完成了,标记将用于未来的引用。编辑:你可能还想以加密方式用-s或者-u <key>标志来对标记进行签名。在Git中,为了保持这次发布中的变更,我们需要将这些变更合并到develop分支中去:$ git checkout developSwitched to branch ‘develop’$ git merge –no-ff release-1.2Merge made by recursive.(Summary of changes)这个步骤可能导致一些合并冲突(可能由于我们改变了版本号)。如果发生了,需要修复重新提交。现在我们已经完成,发布分支或许需要被移除,因为我们不再需要这个分支:$ git branch -d release-1.2Deleted branch release-1.2 (was ff452fe).热修复分支(Hotfix branches)热修复分支可能来源于master分支,但是必须被合并到develop和master分支,分支命名惯例:hotfix-*Hotfix分支非常像release分支,它们都是为一个新的生产分支做准备的,尽管Hotfix是计划之外的。它们源于生产版本一些不被期望的状态。在生产版本出现了严重的错误需要立刻被修复,一个热修复分支需要根据master分支上生产版本的标记进行切出。本质是团队的其他成员可以继续在develop分支上开发,与此同时需要有一个人来在Hotfix分支上进行bugfix。创建热修复分支(hotfix branch)热修复分支从master分支上创建。举个例子,1.2版本是当前运行的生产版本,由于严重的错误导致了一些问题。但是现在develop分支是不稳定的。我们需要切出一个hotfix分支开始修复问题:$ git checkout -b hotfix-1.2.1 masterSwitched to a new branch “hotfix-1.2.1”$ ./bump-version.sh 1.2.1Files modified successfully, version bumped to 1.2.1.$ git commit -a -m “Bumped version number to 1.2.1”[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.11 files changed, 1 insertions(+), 1 deletions(-)在创建完分支之后不要忘记更新版本号!接下来,修复错误,提交一个或者多个记录。$ git commit -m “Fixed severe production problem”[hotfix-1.2.1 abbe5d6] Fixed severe production problem5 files changed, 32 insertions(+), 17 deletions(-)完成热修复分支当完成了,bugfix需要合并到master分支,但是为了保障下次发布版本能够包含bugfix,同样需要被合并到develop分支。这和release分支的实现是类似的。首先,更新master分支并打上发布标签:$ git checkout masterSwitched to branch ‘master’$ git merge –no-ff hotfix-1.2.1Merge made by recursive.(Summary of changes)$ git tag -a 1.2.1编辑:你可能还想以加密方式用-s或者-u <key>标志来对标记进行签名。接下来,将bugfix合并到开发分支,同样:$ git checkout developSwitched to branch ‘develop’$ git merge –no-ff hotfix-1.2.1Merge made by recursive.(Summary of changes)规则的一个例外是:当一个release分支已经存在的情况下,热修复分支的变动需要合并到release分支中,而不是develop分支。在release分支发布完成的时候,如果将错误修复合并到了release分支同样也会反映到develop分支中最终。(如果develop分支立刻需要这个问题修复而且等不及release分支修复,那么你可以安然地合并问题修复到develop分支中。)最终,移除这个临时的hotfix分支:$ git branch -d hotfix-1.2.1Deleted branch hotfix-1.2.1 (was abbe5d6).总结虽然这个分支模型没有什么令人震惊的地方,但是在文章开头的这张大图在你的项目中是异常有用的。这形成了一个优雅的思维模型,而且是非常容易让人理解的,允许团队成员建立一个共同的分支和发布的模型。此处提供一个高质量的PDF版本。把它挂墙上以便随时参考。更新:如果有人需要的话:这里是文章中Git图片的源文件gitflow-model.src.keyPDF ...

February 1, 2019 · 2 min · jiezi

GitNote 基于 Git 的跨平台笔记软件正式发布

GitNote 基于 Git 的跨平台笔记软件为什么自从工作之后,我开始进行笔记记录,这是一个很棒的习惯.我曾经使用过 EDiary Evernote Onenote Wiz 麦库等,都是一些不错的笔记软件,但是都有一些各式各样的问题,不能满足我的使用.2013 年,我用 java 编写了第一款笔记软件 jnote,支持 markdown 和富文本编辑器,但是没有云同步功能.2016 年,我用 electron 和 JavaScript 编写了一个 markdown 编辑器 ndpeditor,不是笔记软件.2017 年,我用 electron 和 JavaScript 编写了基于 git 的 GitNote 笔记软件,这个采用一个 React开发的版本,这是一个没有发布的版本.2018 年,我用 Vue重构了 GitNote,更强大的 GitNote.git 同步git 是一个很棒的工具,GitNote 支持 git 的全部特性,并且不依赖本地 Git 环境. 你可以使用任何支持 Git 的仓库.https://github.com/ 免费版支持无限私有仓库https://BitBucket.com/ 免费版支持私有仓库https://gitlab.com/ 免费版支持私有仓库https://gitee.com/ 免费版支持私有仓库(推荐)https://coding.net/ 免费版支持私有仓库还有很多GitNote 是一款基于 Git 的跨平台笔记软件,内置 git 支持,无须本地有任何 git 环境,拥有 git 的全部特性,可以任意的恢复笔记版本记录,依托 github 的免费不限量私人仓库,你的笔记没有空间的限制,你的数据完全属于你自己.TODO轻量级的 todo 管理,在笔记中快速便捷创建 Todo ,没有复杂管理流程,只需要关注完成和未完成.用极简的方式来管理自己的 todo.富文本编辑器富文本编辑器,不仅支持各种复杂的文字编辑,还支持快捷键、公式、语法高亮、Todo、图片粘贴,等等功能.MARKDOWN不仅是一款漂亮的 markdown 的编辑器,而且还支持编写幻灯片功能,方便你进行幻灯片演讲.附件不仅仅支持各种各样的文件作为附件,还能自动识别图片,将图片插入到笔记中.跨平台Mac windows Linux 全平台支持,未来也会对移动端进行支持.收藏通过浏览器插件,可以收集网络上面的任何内容,自动同步到你的笔记仓库中.扩展提供强大丰富的扩展 API,可以自由的定制功能扩展插件,可以为提供思维脑图,番茄工作法,图床等等功能特色插件思维脑图支持思维脑图,帮助我们用形象化的方式,科学的处理事情,比如记录和激发创意,并且支持多种导出方式.流程图支持制作流程图,流程图,组织结构图,UML,ER 和网络拓扑图等,并且支持多种导出方式.演示文稿使用 markdown 可以很容易的创建出 web 版的演示文档,并支持导出.多图床支持多个图床平台上传,自动插入到笔记中,提供 API 可以自由定制自己的图床.官网地址:https://gitnoteapp.com/下载地址:https://gitnoteapp.com/zh/#do… ...

February 1, 2019 · 1 min · jiezi

关于git的仓库同步指南

关于git的仓库同步指南前言我们都知道,GitHub是一个方便多人协作的托管平台.如何将本地local仓库、个人远程origin仓库(GitHub上的仓库)和远程upstream仓库(在GitHub上fork别人的仓库)进行同步是多人协作的前提.那么我们就来看一下,过程该如何进行情景描述前提:A与B两人协作管理同一个upstream远程仓库,且本次操作A、B同时fork.场景一:现实中我们经常出现这种问题:A fork了远程upstream仓库,几天之后upstream仓库更新了新的版本,此时A的个人仓库与origin仓库已经落后,如果这个时候A 在落后的版本上继续commit,就会频频出错,那么A就需要更新本地仓库,在最新的基础上再操作.场景二:A在最新的版本上进行了自己的修改,并且已经push到upstream仓库,此时upstream版本已被A更新. B想要同步A的此次更新需要fetch远程upstream仓库(此时local 已更新),再将local 仓库push到本地origin仓库.完成同步的操作.图形详解实际操作场景一解决方法获取代码库1 、 fork别人的仓库到自己的GitHub2、将fork到的仓库clone到本地local同步更新代码因为fork并不能将所有东西都复制过来,这个操作只是获取到了路径,所以此时local仓库和upstream远程仓库并不同步,想要同步需先fetch(见操作3)3、使A local仓库和远程upstream仓库的master分支同步$ git fetch upstream$ git rebase upstream/master4、A在本地对代码进行修改之后,在SmartGit进行commit提交操作,然后push到自己的origin仓库$ git push origin master5、去GitHub提pr到此就已经完成了所有操作,如果原作者同意你的pr申请,你就成功的对upstream的代码进行了修改场景二解决方法6、B想要更新到upstream仓库的最新版本,就必须在终端进行fetch,rebase等操作(同上3)7、B的local仓库已同步,需要将最新版本push到B自己的origin仓库,使origin仓库更新结语好啦,到这里我们就能清楚的理解仓库同步的重要性以及如何同步各个仓库了.感谢阅读,下期再会. 原创作者:田晨晨、赵笑漫 日 期:2019年1月31日

January 31, 2019 · 1 min · jiezi

git 常用命令

github创建仓库到本地使用前期准备// 注册github账号// 地址:https://github.com/// 配置密匙// 地址:https://jingyan.baidu.com/article/414eccf6a330926b431f0ac6.html// 创建仓库git-test// git/https 切换到git模式(避免每次重复密匙验证)// 确保已经安装git bash,并打开 创建本地仓库// 在本地创建文件夹mkdir git-test// 复制代码,如以下示例,粘贴到git bash运行echo “# git-test” >> README.mdgit initgit add README.mdgit commit -m “first commit"git remote add origin git@github.com:webjimmylau/git-test.gitgit push -u origin master创建分支// 最好统一先在github上创建分支// 然后才在本地git pull分支git命令文件夹clear // 清空代码pwd // 显示当前目录mkdir fileName // 创建文件夹cd fileName // 进入文件夹git init // 把这个目录变成git可以管理的仓库文件echo xxx >> text.txt // 创建文件并更改或直接更改文件内容rm text.txt // 删除文件cat text.txt // 查看文件内容git diff text.txt // 查看文件修改的内容git diff HEAD – text.txt // 查看工作区和版本库里面最新版本的区别git reset HEAD . // 撤销件到暂存区git checkout – text.txt // 撤销修改文件内容 或 撤销删除文件分支git branch // 查看分支 *代表当前分支git branch dev // 创建分支git branch -d dev // 删除分支git branch -D dev // 强行删除分支git checkout dev // 切换分支git checkout -b dev // 创建并切换分支git checkout -b dev origin/dev // 创建并拉取远程分支dev并切换分支git merge dev // 在当前分支上合并dev内容git merge –no-ff -m ‘xxx’ dev // 合并分支,禁用‘Fast forward’模式,删除后还能保留分支信息版本查看git reflog // 查看全部版本(包括回滚后看不到的版本、误操作等)git log // 详细查看分支提交历史(当前版本的祖先版本)git log –pretty=oneline // 简单查看分支提交历史(去除作者和日期)git log –pretty=oneline –abbrev-commit // 查看精简分支提交历史(缩小版本号长度)git log –graph // 查看分支删除信息版本回滚git reset –hard HEAD^ // 回滚到上一个版本git reset –hard HEAD~100 // 回滚到上100个版本git reset –hard scd51f // 回滚到某版本拉取提交git clone git-test(url) // 克隆git-test项目git remote add origin git-test(url) // 关联一个远程库git pull origin master // 拉取成功 然后手动处理冲突git branch –set-upstream master // 解决分支冲突 git push -u origin master // 把本地master分支和远程master分支关联起来 // 并把本地master分支的最新修改推送到github上git push origin master // 把本地master分支的最新修改推送到github上git push origin :dev // 在远程分支上删除dev分支git remote // 查看远程库的信息 如:origingit remote -v // 查看远程库的详细信息 如:origin隐藏现场git stash // 将当前的工作现场隐藏起来git stash list // 查看隐藏的工作现场git stash apply // 恢复工作现场git stash drop // 删除隐藏的一条工作现场记录git stash pop // 恢复并删除提交到本地git status // 查看是否还有文件未提交git add text.txt // 添加文件到暂存区git commit -m ‘xxx’ // 把暂存区的文件提交到仓库git命令使用方法1、创建/修改/提交cd D: // 进入D盘mkdir www // 创建文件夹wwwcd www // 进入文件夹wwwmkdir git-test // 创建文件夹git-testcd git-test // 进入文件夹git-testpwd // 显示当前目录git init // 把这个目录变成git可以管理的仓库echo 111 >> readme.txt // 创建readme.txt文件 并添加内容111git add readme.txt // 添加readme.txt文件到暂存区里面去git commit -m “add file” // 把暂存区的文件提交到仓库git status // 查看是否还有文件未提交echo 222 >> readme.txt // 创建readme.txt文件并更改或直接更改readme.txt文件内容git status // 查看是否还有文件未提交git diff readme.txt // 查看readme.txt修改了什么内容git add readme.txt // 添加readme.txt文件到暂存区里面去git commit -m “change file” // 把暂存区里面的内容提交到仓库2、版本回退echo 333 >> readme.txt git add readme.txt git commit -m “change file"git log // 查看版本历史记录git log –pretty=oneline // 查看精简版本历史记录git reset –hard HEAD^ // 退回到上一个版本 ^上一个 ^^上两个 ~100上100个cat readme.txt // 查看readme.txt内容git log // 查看版本历史记录,被覆盖的最新版本333已经看不到,按q退出查询git reflog // 可以看到333内容的版本信息和对应的版本号git reset –hard xxxxxx // 恢复到333内容的版本cat readme.txt // 查看readme.txt内容3、理解工作区与暂存区的区别echo 444 >> readme.txt // 修改文件echo test >> test.txt // 新增文件git add readme.txt // 添加文件到暂存区git add test.txt // 添加文件到暂存区git commit -m “add files” // 把暂存区的文件提交到仓库4、撤销修改echo 555 >> readme.txt // 修改文件cat readme.txt // 查看文件git checkout – readme.txt // 把文件在工作区做的修改全部撤销git 666 >> readme.txt // 修改文件git add readme.txt // 添加文件到暂存区echo 777 >> readme.txt // 修改文件cat readme.txt // 查看文件git checkout – readme.txt // 把文件暂存区的修改保留,把工作区为修改全部撤销cat readme.txt // 666还有,777不见了5、删除文件echo b >> b.txt // 新建文件git add b.txt // 添加文件到暂存区git commit -m “change file” // 提交暂存区的文件到仓库rm b.txt // 删除文件git status // 查看文件状态git checkout – b.txt // 撤销删除文件6、远程仓库// 如何添加远程库git remote add origin git-test(url)git push -u origin master // 把本地master分支和远程master分支关联起来 // 并把本地master分支的最新修改推送到github上git push origin master // 把本地master分支的最新修改推送到github上// 如何从远程克隆git clone git-test(url)7、创建与合并分支git branch // 查看分支 *代表当前分支git branch dev // 创建分支git checkout dev // 切换分支git checkout -b dev // 创建并切换分支cat readme.txtecho 777 >> readme.txtcat readme.txtgit add readme.txtgit commit -m ‘xxx’git checkout mastercat readme.txt // 只有之前的内容666git merge dev // 在当前分支上合并dev内容cat readme.txt // master上多了内容777git branch -d dev // 删除dev分支// 如何解决冲突git merge fenzhi1 // 删除冲突,再提交// 分支管理策略 git merge –no-ff -m ’text’ dev // 合并分支,禁用‘Fast forward’模式,删除后还能保留分支信息git branch -d dev git log –graph –pretty=oneline –abbrev-commit // 查询被删除的分支信息8、bug分支git status // 有看到新增和修改的文件git stash // 将当前的工作现场隐藏起来git status // 隐藏之后,查看状态,是干净的git checkout -b issue-404 // 创建和切换分支到issue-404git add readme.txt // 把文件添加到暂存区git commit -m ‘fix some bug’ // 把暂存区的文件提交到仓库git checkout master // 切换分支到mastergit merge –no-ff -m ‘merge issue-404’ issue-404 // 合并issue-404分支cat readme.txt // 当前master分支可以看到issue-404分支的内容,完全一致git branch -d issue-404 // 在master分支上删除issue-404临时分支git checkout dev // 切换到dev分支git status // 查看状态,还是干净的git stash list // 查看隐藏的工作现场git stash apply // 恢复工作现场git stash drop // 删除隐藏的一条工作现场记录git stash pop // 恢复并删除9、多人协作git clone git-test(url) // 克隆git-test项目git pull origin master // 拉取master分支git push origin master // 推送master分支git pull origin dev // 拉取失败git branch –set-upstream dev // 解决分支冲突git pull origin dev // 拉取成功 然后手动处理冲突git push origin dev // 推送dev分支 ...

January 31, 2019 · 3 min · jiezi

Git命令

查看本机git配置:git config –list

January 30, 2019 · 1 min · jiezi

git 分支原理介绍

参考文章git-分支简介工作原理git 的工作原理:git 版本控制是通过保存不同时间点的快照实现的。git 在提交操作时,git 会保存一个提交对象,该提交对象中会包含:用户名邮箱提交信息父指针,自然的,首次提交的对象是没有父指针的,之后提交的对象才有父指针指向树对象的指针(树对象:git 通过计算每个子目录的校验和,将其保存为树对象)目录结构blob 对象索引git 的分支,其实本质上是指向提交对象的可变指针。由于创建分支的高效性,所以,git 鼓励开发人员创建分支!原理说明首先在创建 git 项目的时候,默认会创建 master 分支!这个 master 分支正常应该是指向最新一次提交。 head | master |one <- two <- thr假设这个时候,用户做了些修改,然后提交: head | master |one <- two <- thr <- four从上述两个过程可以看出,master 分支实际就是一个指向某次提交的指针!会根据用户的提交自动向前移动指向最新一次提交。如果用户新创建了一个分支(test)呢:git branch test他的实际结果就是如下: head | master |one <- two <- thr <- four | test因为这个时候用户在 master 分支下,用户再次做出修改提交: test |one <- two <- thr <- four <- five | master | head如果这个时候用户切换到 test 分支(git checkout test),做些修改然后再次提交: head | test | <- five-for-testone <- two <- thr <- four <- five | master产生了一个新的分支!! ...

January 30, 2019 · 1 min · jiezi

MacOS安装git

1。安装brew(可百度brew官网,参考安装)/usr/bin/ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"2.安装gitbrew install git3.备份旧的gitcd /usr/local/binmkdir backup-gitmv git* ./backup-git/4.找到新的git安装目录cd /usr/local/Cellar/git/2.20.15.回到根目录,配置环境变量cd ~vim .bash_profile#输入export GIT=/usr/local/Cellar/git/2.20.1export PATH=$GIT/bin:$PATH:wq6.刷新环境变量,使配置生效source .bash_profile参考资料:[1]: https://www.cnblogs.com/songt…

January 29, 2019 · 1 min · jiezi

sourcetree password required

sourcetree 不停的让输入密码,报 password required1、在终端(terminal)打开你的工程目录2、输入git config credential.helper store3、拉取代码git pull4、输入用户名密码后面就不用再输入了。原文地址:http://zhige.me/2019/01/28/20…

January 29, 2019 · 1 min · jiezi

CentOS 6.9 安装最新版本 git

从 github 上下载最新版的 git 源码打开网址:https://github.com/git/git/点击 releases,找到最新稳定版(不要下载带有-rc的,因为它代表了一个候选发布版本)获取到下载链接,比如:https://github.com/git/git/ar…wget 下载最新版$ wget https://github.com/git/git/archive/v2.19.2.tar.gz解压$ tar -zvxf v2.19.2.tar.gz 安装编译工具与依赖包$ yum groupinstall “Development Tools”$ yum install zlib-devel perl-ExtUtils-MakeMaker asciidoc xmlto openssl-devel编译 git 源码$ cd git-2.19.2$ autoconf$ ./configure$ make && make install添加 git 符号链接$ ls /usr/local/bingit gitk git-shell git-upload-packgit-cvsserver git-receive-pack git-upload-archive$ ln -s /usr/local/bin/git /usr/binln: 创建符号链接 “/usr/bin/git”: 文件已存在$ rm /usr/bin/gitln -s /usr/local/bin/git /usr/bin$ git –versionv2.19.2设置 alias 节约生命$ git config –global alias.st status$ git config –global alias.co checkout$ git config –global alias.ci commit$ git config –global alias.br branch$ git config –global alias.pl pull$ git config –global alias.ps push ...

January 28, 2019 · 1 min · jiezi

使用Git你后悔过吗?

使用Git你后悔了吗?人总会有犯错的时候,值得感激的是Git允许你在任何时候反悔,并且将对应信息从历史记录中抹除,这样的历史记录往往看起来行云流水,令人赏心悦目,严谨的提交信息是对他人的一种尊重。改变最近的一次提交git commit –amend如果你想改变上一个commit的提交信息与文件内容,即可使用–amend命令,它允许你将暂存区的修改合并到上一个commit,从而生成一个新的commit,您也可以仅适用它来修改commit message。需要注意的是,如果已经将commit到远程库,不建议使用ammend命令,因为这样会修改掉最近一次commit的hash值,只能强制推送才能push上去,如果你的commit已经同步到了其他仓库或别人已经拉取之前的提交,这样强推上去就会产生冲突。重置某一次提交内容git revert [<commit>]若当某一次的提交内容导致一些错误发生,通常会进行还原操作,此时revert就派上用场了,它会生成一条新的commit,将指定的commit中包含的更改进行还原。revert是一个十分礼貌的命令,对于多人协作的项目来讲,是十分有用的,因为它会保持HEAD指针在不断的前进,不会产生意想不到的冲突。将最近几个提交合并为一个git rebase -i [<start_commit>] [<end_commit>]在推送到远程分之前,为了保持逻辑清晰可回溯步骤,我们需要会进行许多个小的提交,而到推送到远程库的时候,更希望将其汇总为一个feat提交,这时命令就派上了用场。首先我们来初始化一个git仓库:mkdir gittest && cd gittest && git inittouch a && git add * && git commit -m ‘a’touch b && git add * && git commit -m ‘b’touch c && git add * && git commit -m ‘c’touch d && git add * && git commit -m ’d’这时执行git log可获取到以下信息:commit b9843274e87455a87b16802ebb2b48cf8cb67175 (HEAD -> master) dcommit dc681aadc81491c3d2b2cb2f8ca1d66586f65903 ccommit db9dc842b6c854b7175c03c7fd50bf08a262cfcb bcommit 3bc7dbe4ddfad85606e6dd39c6583d8fa7b353b7 a为了将b、c合成为一个提交,我们需要选取最近3个提交进行才行,需要注意的是指定两个commit范围时区间为前开后闭区间(],如果省略第二个end_commit则会指向HEAD指针,因此以下三个命令是等效的:git rebase -i HEAD~3git rebase -i 3bc7dbe4ddfad85606e6dd39c6583d8fa7b353b7git rebase -i 3bc7dbe4ddfad85606e6dd39c6583d8fa7b353b7 b9843274e87455a87b16802ebb2b48cf8cb67175这时会弹出一个交互界面:pick 3a13544 bpick 3b3d704 cpick 9205e1b d# Rebase 97b2217..9205e1b onto 97b2217 (3 commands)## Commands:# p, pick = use commit# r, reword = use commit, but edit the commit message# e, edit = use commit, but stop for amending# s, squash = use commit, but meld into previous commit# f, fixup = like “squash”, but discard this commit’s log message# x, exec = run command (the rest of the line) using shell# d, drop = remove commit## These lines can be re-ordered; they are executed from top to bottom.## If you remove a line here THAT COMMIT WILL BE LOST.## However, if you remove everything, the rebase will be aborted.## Note that empty commits are commented out注释里已经包含了一切你需要知道的信息,在这里还是简单的描述下:命令会从上到下执行,按时间的先后顺序进行合并commit提交可被重新排序,在这里可交互b与c的顺序后保存退出,打印的commit信息即为:a -> c -> b -> d若删除某行,可移除对应的整个提交内容命令有以下不同的模式:pick:保留该commit(缩写:p)reword:保留该commit,但我需要修改该commit的注释(缩写:r)edit:保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e)squash:将该commit和前一个commit合并(缩写:s)fixup:将该commit和前一个commit合并,但我不要保留该提交的注释信息(缩写:f)exec:执行shell命令(缩写:x)drop:我要丢弃该commit(缩写:d)在选取范围时,我们往往会指定一个start_commit,那么如果commit为第一个提交呢?因为命令为前开区间,这时候就无法选取了,只能通过–root指定:git rebase -i –root。以上命令尽量都自己尝试一遍。回退到指定版本git reset [<mode>] [<commit>]首先应该理清HEAD、暂存区、工作区三者的关系再去使用reset命令。使用reset回退版本通常是通过移动HEAD指针的指向来实现的,HEAD是当前分支引用的指针,它总是指向该分支上的最后一次提交。当HEAD指针发生变化时,有几种模式可以选择:–soft,暂存区与工作区都不会重置,只会重置掉提交。此模式不改变暂存区与工作区的文件内容,仅仅是将HEAD指针位置边了,这样所有在reset指定的提交之后的提交都会被撤销,文件更改集中放在了暂存区。–mixed,重置暂存区,但不会重置工作区。reset会用HEAD指向的快照去更新暂存区的内容,只保留工作区的文件,简单的说,回到了git add之前。–hard,同时重置暂存区和工作区。它会彻底弃用之后的提交,且不可撤销。总结文章只是涉及一些浅显的用法,希望在玩转重写Git时,您也应该掌握:理解Head、Index、Working Directory,即头部索引、暂存区、工作目录之间的联系。使用git reflog随时对进行的操作进行撤销。理清chekout与reset的区别。多多练习rebase各种命令操作。以上只是抛砖引玉,最重要的是能知道自己在做什么,清楚操作带来的影响。参考资料Git - 重置揭密git amend | Atlassian Git Tutorial ...

January 26, 2019 · 2 min · jiezi

GIT - 代码分支管理模型之二

书接上文在前一篇文章GIT 代码分支管理模型之一中,我们一起了解了一种叫做“成功的代码分支管理模型”。在这种模型中,我们确实可以很灵活地应对各种场景下的代码分支管理。理想总是那么美好,而现实偏偏那么蛋疼!要用好这种代码分支管理模型,需要全体开发人员对于GIT有比较深入的了解,比如merge, rebase,而且在每一次GIT的操作的时候要很清楚地知道自己正在开发的功能属于哪个分支的。对于同时开发多个功能点的同事来说,比如同时在开发一个下一版本的功能,以及进行产品线上细微改动的同事来说,确实要非常小心,稍不留神就容易怼错分支。历史背景在我们公司刚开始推行GIT的时候,领导下的指令是要让大家把精力全放在功能开发上,对于GIT只需要知道pull 跟push就可以了,经过一段历史时期的挣扎磨合,无形中我们形成了下面这种分支管理模型,称之为 “简单但啰嗦的分支管理模型"简单但啰嗦的分支管理模型主心骨这个模型主要有两种分支,一种叫DEV,一种叫REL。每一种后面都附加有对应版本号,比如DEV1.0, REL1.0RELx.0每个版本开始开发之前,都会从上一个版本的REL分支创建出一个新的REL分支,比如REL2.0是从REL1.0创建出来。当然第一个版本REL1.0就是从master分支创建出来的。这样就确保了每一个版本都是从上一个版本最新代码创建出来的。RELx.0神圣职责是作为每一个大版本发布的分支,并且是用来部署测试环境,准产品线以及产品线的分支。一般开发人员没有权限直接往RELx.0上面提交代码,只能从对应的DEV分支提交代码,再由集成人员合并到上面去。DEVx.0DEVx.0是与RELx.0对应的开发分支,所有开发人员默认都有权限往这个分支上提交代码。这也是开发人员所需要知道的分支,只需要从这上面pull最新的代码,然后把本地commit的代码push到上面去就可以了。小版本怎么办?在相当长的一段历史时期中,基本稳定在一个版本一个月左右。但有时会遇到有些小功能着急着上,等不及一个月上一次,所以就有了对应RELx.x以及DEVx.x (x > 0). 比如刚发布了REL3.0,这时有VIP客户需要上一个功能,改动不至于很大,但是也等不及下个月再上,于是我们就从REL3.0上面衍生出一条REL3.1的分支。按照之前的规则, REL分支是不允许直接修改代码的,所有对应的我们会创建DEV3.1的分支,给开发人员在上面进行开发。在这个过程中,下一版本4.0其实一直在同步进行开发的,但是这时REL4.0以及DEV4.0的分支上是没有DEV3.1的新功能的,所有在3.1的新功能上线之后,需要由持续集成人员DEV3.1的代码合并到DEV4.0上面去 (为什么不是直接REL3.1到REL4.0呢? 技术上是可行的,但是这样的话,REL4.0需要反向将代码合并会DEV4.0去,比较别扭),持续集成环境会自动将DEV4.0的新代码合并到REL4.0上面去,这样到时发布4.0的时候,才不会丢失了3.1新增的功能没bug的系统是不完整的有bug怎么办?不管是大版本还是小版本,总有可能产品线上有bug需要hotfix。在上次介绍的成功代码分支模型中,可以通过hotfix的分支进行代码修复。但在这个简单模型中,就不会新建hotfix的分支,而是在最新以上线的分支上进行修改。比如当前产品线上是REL3.0的代码,REL4.0是下一个大版本,REL3.1是准备上线的小版本,而这时产品上客户报了Level 1的case,按照SLA需要在三天内修复,我们是等不及REL3.1下周末上的,更不可能等REL4.0到下个月,所有我们要上到3.0的分支上:已上线的REL3.0以及对应的DEV3.0在上线之后就全被锁掉了,所以这时我们要找代码集成人员进行解锁然后在DEV3.0的分支上进行代码修复,直到测试通过后,合并代码分支到REL3.0进行紧急上线简单但啰嗦简单这种模型中,大部分开发人眼只需要记住版本的DEVx.x就可以了,其它REL什么的都可以不用管,不懂也没关系的。啰嗦每一个新版本开发前,管理人员都要新建对应的DEV分支,然后开发人员checkout对应分支进行开发。这样一来,一个版本,无论大小,都需要对应有两条分支,整个代码库看起来就有很多很多的分支,略显啰嗦。there is no free lunch!利弊关系上面已经做了一些简单的介绍,这种模型适合在项目比较大,团队人数较多的情况下使用,好处是开发人员不需要对GIT有过深的理解,只需会简单的pull / push,其它都由分支管理以及对应的权限管理搞定;其缺点也明显,就是整个代码库会有好多好多的分支,看起来比较啰嗦。

January 25, 2019 · 1 min · jiezi

git常用命令

git常用命令1. branch分支文档api记录:分支的新建与合并常用git命令常用命令:// 新建一个 dev 分支,可以使用 git branch 命令git branch dev// 要切换到其他分支,可以执行 git checkout 命令git checkout dev// 新建并切换 [branch-name]git checkout -b iss53// 提交工作区自上次commit之后的变化,直接到仓库区git commit -a -m [message]// 提交时显示所有diff信息git commit -v// 推送到远程仓库git push [remote-name] [branch-name]// 将 master 分支推送到 origin 服务器时git push origin master// 将dev分支合并到mastergit checkout mastergit merge dev// 删除分支hotfixgit branch -d hotfix// git 删除远程分支git push origin –delete <BranchName>// 要看看哪些文件在合并时发生冲突,可以用 git status 查阅git status// git 打taggit tag -a v1.0.0 -m “1.0.0版本"git push origin v1.0.0// 在解决了所有文件里的所有冲突后,运行 git add 将把它们标记为已解决状态(译注:实际上就是来一次快照保存到暂存区域。)。// 因为一旦暂存,就表示冲突已经解决。如果你想用一个有图形界面的工具来解决这些问题,不妨运行 git mergetool,它会调用一个可视化的合并工具并引导你解决所有冲突 ...

January 24, 2019 · 1 min · jiezi

如何使用Git提高研发团队工作效率?

为什么使用Git随着互联网时代的来临与发展,尤其分布式开发的大力引入,对于开发工程师来说,代码管理变成了头等难题。10多个人或者更多的成员的研发团队如何管理同一份代码,异地办公如何跟同事有效的维护同一份代码?下面直接介绍Git,就不对Git和其他的版本管理工具进行比较了。Git属于分布式的版本控制系统,它具有以下特点:Git中每个克隆(clone)的版本库都是平等的。你可以从任何一个版本库的克隆来创建属于你自己的版本库,同时你的版本库也可以作为源提供给他人,只要你愿意。Git的每一次提取操作,实际上都是一次对代码仓库的完整备份。提交完全在本地完成,无须别人给你授权,你的版本库你作主,并且提交总是会成功。甚至基于旧版本的改动也可以成功提交,提交会基于旧的版本创建一个新的分支。Git的提交不会被打断,直到你的工作完全满意了,PUSH给他人或者他人PULL你的版本库,合并会发生在PULL和PUSH过程中,不能自动解决的冲突会提示您手工完成。冲突解决:在需要的时候才进行合并和冲突解决。Git版本库统一放在服务器中可以为 Git 版本库进行授权:谁能创建版本库,谁能向版本库PUSH,谁能够读取(克隆)版本库,即权限配置团队的成员先将服务器的版本库克隆到本地;并经常的从服务器的版本库拉(PULL)最新的更新;团队的成员将自己的改动推(PUSH)到服务器的版本库中,当其他人和版本库同步(PULL)时,会自动获取改变你完全可以在脱离Git服务器所在网络的情况下,如移动办公/出差时,照常使用代码库你只需要在能够接入Git服务器所在网络时,PULL和PUSH即可完成和服务器同步以及提交选择适合团队的工作流分布式工作流程:同传统的集中式版本控制系统(CVCS)不同,Git 的分布式特性使得开发者间的协作变得更加灵活多样。在集中式系统中,每个开发者就像是连接在集线器上的节点,彼此的工作方式大体相像。而在 Git 中,每个开发者同时扮演着节点和集线器的角色——也就是说,每个开发者既可以将自己的代码贡献到其他的仓库中,同时也能维护自己的公开仓库,让其他人可以在其基础上工作并贡献代码。由此,Git 的分布式协作可以为你的项目和团队衍生出种种不同的工作流程,接下来的章节会介绍几种利用了 Git 的这种灵活性的常见应用方式。我们将讨论每种方式的优点以及可能的缺点;你可以选择使用其中的某一种,或者将它们的特性混合搭配使用。Git 提供的有以下三种工作流程集中式工作流集成管理者工作流司令官与副官工作流目前我们团队使用的是最简单的方式,集中式工作流程,随着研发团队的壮大可能会选择使用第二种,下面我们分别介绍下三种工作流1.集中式工作流 集中式系统中通常使用的是单点协作模型——集中式工作流。一个中心集线器,或者说仓库,可以接受代码,所有人将自己的工作与之同步。若干个开发者则作为节点——也就是中心仓库的消费者——并且与其进行同步。这意味着如果两个开发者从中心仓库克隆代码下来,同时作了一些修改,那么只有第一个开发者可以顺利地把数据推送回共享服务器。第二个开发者在推送修改之前,必须先将第一个人的工作合并进来,这样才不会覆盖第一个人的修改。这和 Subversion (或任何 CVCS)中的概念一样,而且这个模式也可以很好地运用到 Git 中。如果在公司或者团队中,你已经习惯了使用这种集中式工作流程,完全可以继续采用这种简单的模式。只需要搭建好一个中心仓库,并给开发团队中的每个人推送数据的权限,就可以开展工作了。Git 不会让用户覆盖彼此的修改。例如 John 和 Jessica 同时开始工作。 John完成了他的修改并推送到服务器。接着 Jessica 尝试提交她自己的修改,却遭到服务器拒绝。她被告知她的修改正通过非快进式(non-fast-forward)的方式推送,只有将数据抓取下来并且合并后方能推送。这种模式的工作流程的使用非常广泛,因为大多数人对其很熟悉也很习惯。当然这并不局限于小团队。利用 Git 的分支模型,通过同时在多个分支上工作的方式,即使是上百人的开发团队也可以很好地在单个项目上协作。2.集成管理者工作流 Git 允许多个远程仓库存在,使得这样一种工作流成为可能:每个开发者拥有自己仓库的写权限和其他所有人仓库的读权限。这种情形下通常会有个代表官方''项目的权威的仓库。要为这个项目做贡献,你需要从该项目克隆出一个自己的公开仓库,然后将自己的修改推送上去。接着你可以请求官方仓库的维护者拉取更新合并到主项目。维护者可以将你的仓库作为远程仓库添加进来,在本地测试你的变更,将其合并入他们的分支并推送回官方仓库。这一流程的工作方式如下所示:项目维护者推送到主仓库。贡献者克隆此仓库,做出修改。贡献者将数据推送到自己的公开仓库。贡献者给维护者发送邮件,请求拉取自己的更新。维护者在自己本地的仓库中,将贡献者的仓库加为远程仓库并合并修改。维护者将合并后的修改推送到主仓库。这是 GitHub 和 GitLab 等集线器式(hub-based)工具最常用的工作流程。人们可以容易地将某个项目派生成为自己的公开仓库,向这个仓库推送自己的修改,并为每个人所见。这么做最主要的优点之一是你可以持续地工作,而主仓库的维护者可以随时拉取你的修改。贡献者不必等待维护者处理完提交的更新——每一方都可以按照自己节奏工作。3.司令官与副官工作流 这其实是多仓库工作流程的变种。一般拥有数百位协作开发者的超大型项目才会用到这样的工作方式,例如著名的 Linux 内核项目。被称为副官(lieutenant)的各个集成管理者分别负责集成项目中的特定部分。所有这些副官头上还有一位称为司令官(dictator)的总集成管理者负责统筹。司令官维护的仓库作为参考仓库,为所有协作者提供他们需要拉取的项目代码。整个流程看起来是这样的普通开发者在自己的特性分支上工作,并根据master分支进行变基。这里是司令官的master分支。副官将普通开发者的特性分支合并到自己的master分支中。司令官将所有副官的master分支并入自己的master分支中。司令官将集成后的master分支推送到参考仓库中,以便所有其他开发者以此为基础进行变基。这种工作流程并不常用,只有当项目极为庞杂,或者需要多级别管理时,才会体现出优势。利用这种方式,项目总负责人(即司令官)可以把大量分散的集成工作委托给不同的小组负责人分别处理,然后在不同时刻将大块的代码子集统筹起来,用于之后的整合。介绍了上面三种工作流,想必你一定有想法使用哪一种了,选择一个适合自己团队的工作流,只要是严格按照这种规则执行的话,相信你的研发团队对于代码的管理一定不会再混乱了,这也会大大提升团队的工作效率。管理 Git 分支几乎所有的版本控制系统都以某种形式支持分支。使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线。在很多版本控制系统中,这是一个略微低效的过程——常常需要完全创建一个源代码目录的副本。对于大项目来说,这样的过程会耗费很多时间。有人把 Git 的分支模型称为它的必杀技特性’’,也正因为这一特性,使得 Git 从众多版本控制系统中脱颖而出。为何 Git 的分支模型如此出众呢? Git 处理分支的方式可谓是难以置信的轻量,创建新分支这一操作几乎能在瞬间完成,并且在不同分支之间的切换操作也是一样便捷。与许多其它版本控制系统不同,Git 鼓励在工作流程中频繁地使用分支与合并,哪怕一天之内进行许多次。理解和精通这一特性,你便会意识到 Git 是如此的强大而又独特,并且从此真正改变你的开发方式。Git 创建分支 Git 是怎么创建新分支的呢?很简单,它只是为你创建了一个可以移动的新的指针。比如,创建一个 testing 分支,你需要使用git branch命令:$ git branch testing这会在当前所在的提交对象上创建一个指针那么,Git 又是怎么知道当前在哪一个分支上呢?也很简单,它有一个名为HEAD的特殊指针。请注意它和许多其它版本控制系统(如 Subversion 或 CVS)里的HEAD概念完全不同。在 Git 中,它是一个指针,指向当前所在的本地分支。在本例中,你仍然在master分支上。因为git branch命令仅仅创建一个新分支,并不会自动切换到新分支中去。你可以简单地使用git log命令查看各个分支当前所指的对象。提供这一功能的参数是–decorate。$ git log –oneline –decoratef30ab (HEAD, master, testing) add feature #32 - ability to add new34ac2 fixed bug #1328 - stack overflow under certain conditions98ca9 initial commit of my project正上,当前master 和testing 分支均指向校验和以f30ab开头的提交对象。分支切换 要切换到一个已存在的分支,你需要使用git checkout命令。我们现在切换到新创建的testing分支去:$ git checkout testing这样HEAD就指向testing分支了。那么,这样的实现方式会给我们带来什么好处呢?现在不妨再提交一次:$ vim test.rb$ git commit -a -m ‘made a change’如上图所示,你的testing分支向前移动了,但是master分支却没有,它仍然指向运行git checkout时所指的对象。这就有意思了,现在我们切换回master分支看看:$ git checkout master这条命令做了两件事。一是使 HEAD 指回master分支,二是将工作目录恢复成master分支所指向的快照内容。也就是说,你现在做修改的话,项目将始于一个较旧的版本。本质上来讲,这就是忽略testing分支所做的修改,以便于向另一个方向进行开发。现在我们稍微再做些修改并commit:$ vim test.rb$ git commit -a -m ‘made other changes’现在,这个项目的提交历史已经产生了分叉。因为刚才你创建了一个新分支,并切换过去进行了一些工作,随后又切换回 master 分支进行了另外一些工作。上述两次改动针对的是不同分支:你可以在不同分支间不断地来回切换和工作,并在时机成熟时将它们合并起来。而所有这些工作,你需要的命令只有branch、checkout和commit。 Git 合并分支接下来咱们举个稍微复杂点的例子,三个分支的分别处理不同的事情,最后合并到一块首先,我们假设你正在你的项目上工作,并且已经有一些提交, 如下图:现在,你已经决定要解决你的公司使用的问题追踪系统中的 #53 问题。想要新建一个分支并同时切换到那个分支上,你可以运行一个带有-b参数的git checkout命令:$ git checkout -b iss53Switched to a new branch “iss53"它是下面两条命令的简写:$ git branch iss53$ git checkout iss53你继续在 #53 问题上工作,并且做了一些提交。在此过程中,iss53分支在不断的向前推进,因为你已经检出到该分支(也就是说,你的HEAD指针指向了iss53分支)$ vim index.html$ git commit -a -m ‘added a new footer [issue 53]‘当你在iss53这个分支上正在顺畅的工作,这时候有个特别紧急的问题需要你来修复,那么为了不影响iss53的正常工作,你需要做的是重新切换到master分支上来,在master分支的基础上再创建一个新的分支 hotfix ,然后在hotfix分支解决紧急的问题。$ git checkout -b hotfixSwitched to a new branch ‘hotfix’$ vim index.html$ git commit -a -m ‘fixed the broken email address’[hotfix 1fb7853] fixed the broken email address 1 file changed, 2 insertions(+)这个时候hotfix分支上的问题彻底解决了,你需要合并到master分支,并且部署上线, 那么你只需要在master分支使用git merge命令就可以了$ git checkout master$ git merge hotfixUpdating f42c576..3a0874cFast-forward index.html | 2 ++ 1 file changed, 2 insertions(+)在合并的时候,你应该注意到了"快进(fast-forward)“这个词。由于当前master分支所指向的提交是你当前提交(有关 hotfix 的提交)的直接上游,所以 Git 只是简单的将指针向前移动。换句话说,当你试图合并两个分支时,如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候,只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧——这就叫做 “快进(fast-forward)”。现在,最新的修改已经在master分支所指向的提交快照中了。关于这个紧急问题的解决方案发布之后,你准备回到被打断之前时的工作中。然而,你应该先删除hotfix分支,因为你已经不再需要它了, master分支已经指向了同一个位置。你可以使用带-d选项的git branch命令来删除分支:$ git branch -d hotfixDeleted branch hotfix (3a0874c).现在你可以切换回你正在工作的分支继续你的工作,也就是针对iss53分支$ git checkout iss53Switched to branch “iss53”$ vim index.html$ git commit -a -m ‘finished the new footer [issue 53]’[iss53 ad82d7a] finished the new footer [issue 53]1 file changed, 1 insertion(+)这个时候 #53 问题解决后你就可以把代码合并到master了,操作跟刚才的htofix分支处理方式一样$ git checkout masterSwitched to branch ‘master’$ git merge iss53Merge made by the ‘recursive’ strategy.index.html | 1 +1 file changed, 1 insertion(+)但是这和你之前合并hotfix分支的时候看起来有一点不一样。在这种情况下,你的开发历史从一个更早的地方开始分叉开来(diverged)。因为,master分支所在提交并不是iss53分支所在提交的直接祖先,Git 不得不做一些额外的工作。出现这种情况的时候,Git 会使用两个分支的末端所指的快照(C4和C5)以及这两个分支的工作祖先(C2),做一个简单的三方合并。和之间将分支指针向前推进所不同的是,Git 将此次三方合并的结果做了一个新的快照并且自动创建一个新的提交指向它。这个被称作一次合并提交,它的特别之处在于他有不止一个父提交。这个时候如何不需要iss53分支的话,你也可以删除iss53分支了 远程分支以github为例,目前很多开源项目以及公司的研发项目代码一般都托管在github,那么就出现了远程仓库,远程分支等这些概念。下面我们从github远程仓库clone下来一份代码如果你在本地的master分支做了一些工作,然而在同一时间,其他人推送提交到git@github.com:glj1102/git_test.git 并更新了它的master分支,那么你的提交历史将向不同的方向前进。也许,只要你不与 origin 服务器连接,你的origin/master指针就不会移动。如果要同步你的工作,运行git pull命令。这个命令是抓取远程分支数据到本地分支,并且更新本地数据库,移动origin/master指针指向新的、更新后的位置。同时你也可以执行 git push命令把你本地修改的数据提交到远程分支。实时跟踪和监控团队代码操作记录我们使用的是 Worktile + github 来管理团队的,平时团队沟通,任务分配都是通过Worktile来做的,那么 Worktile 与github如何关联的呢? Worktile绑定github代码仓储在Worktile的后台管理 > 服务管理中找到github,点击添加下一步会让你选择Worktile的一个聊天群组,之后github的提交记录就会发送到这个群组中:添加服务之后需要进行一些配置,配置方式有两种,一种是授权模式,选择仓储,选择事件, 另一种是普通模式,这种模式Worktile会生成一个Webhook链接,拿到这个链接可以直接在github仓储中进行Webhook配置:具体的配置Worktile后台github服务设置中有教程。 Worktile接收github发送的操作记录根据不配置时选择的事件不同,github会发送不同的记录消息总结通过上面对Git的介绍,对于团队管理者来说,如何使用Git来有效的管理团队代码应该会有最基本的概念,那接下来就需要你真正的花时间来实践了。那么对于Git的命令集网上有很多例子的,下面我这里介绍两本Git的基本入门教程:Git 简易指南 http://www.bootcss.com/p/git-...Git 图解 http://marklodato.github.io/v… ...

January 24, 2019 · 2 min · jiezi

idea 使用 git 教程

idea 使用 git 教程1.下载 git下载地址: https://git-scm.com/download/win 64-bit Git for Windows Portable(简单版本)2.安装 gitbin 目录: E:gitbin3.获取远程仓库地址这个一般是由组长搭建,我们生成自己公钥给他就好,然后就可以拿到 远程仓库地址# 生成公钥ssh-keygen -t rsa -C “邮箱地址”# 输入秘钥密码4.配置全局用户名和邮箱git config –global user.name “孔乙己"git config –global user.email “kyj@gmail.com"注意: 最好邮箱地址一致,用户名是提交代码是备注的用户名5. 将当前项目目录和git远程仓库关联# 将当前项目作为本地仓库git init# 将当前项目添加到git 缓存中git add src# 将缓存中的内容提交到git本地仓库git commit -m “你妹的git” # 将本地仓库和远程仓库关联git remote add origin https://github.com/aaaa/aaa.git# 将本地仓库中的项目提交到git远程仓库git push -u origin master6. 之后再idea 中就可以正常使用git了7. 建议第一次使用git测试的idea用户按照以下流程使用创建项目将当前项目所在的目录作为git本地仓库3.这是项目右键就会出现 <font color=“lightgreen”>git</font> 的选项了输入注释,提交到本地仓库/推送到远程仓库参考资料: https://www.cnblogs.com/nihao… 感谢 <font color=“red”>Nihaorz</font> 的无私分享

January 24, 2019 · 1 min · jiezi

Git合并不同url的项目

本文由云+社区发表作者:工程师小熊摘要:为了让项目能实现Git+Gerrit+Jenkin的持续集成,我们把项目从Git上迁移到了Gerrit上,发现有的同事在老Git提交代码,因为Gerrit做了同步,在Gerrit上有新提交的时候就会刷新老git,这样就会把他提交的代码冲掉。这个时候我就必须要在两个相似项目之间合并提交了。步骤将老Git url加到我们新Git的本地使用命令git remote add [shortname] [url]将老Git url加到我们新Git的本地这里我把他取名为gitoa_web(随便取)查看使用命令git remot -v查看远程仓库的情况可以看到此处我们有三个远程仓库分别名为gerrit、 gitoa_web、origin同步代码使用命令git fetch gitoa_web刷新远程仓库到本地字符串 gitoa_web 指代对应的仓库地址了.比如说,要抓取所有 gitoa_web 有的,但本地仓库没有的信息,可以用合并项目使用命令git merge gitoa_web/master合并项目gitoa_web是指代仓库,master指代分支,当然如果有需要也可以合并别的分支过来 报错发现不同email地址错误不能成功提交因为这个commit不是我的修正错误把email地址更新成我的再提交就成功了小结知识点:git merge还可以合并其他项目的到本项目git fetch 仓库名可以指定同步哪个仓库git remot -v查看本地有哪些远程仓库的情况,包含各个仓库url本次我们对以下命令加深了理解git remote #不带参数,列出已经存在的远程分支git remote -v #(-v是–verbose 的简写,取首字母)列出详细信息,在每一个名字后面列出其远程urlgit remote add [shortname] [url] #添加远程仓库git fetch origin #字符串 origin 指代对应的仓库地址了.比如说,要抓取所有 origin 有的,但本地仓库没有的信息,可以用ps: 这里git remote add以后,我认为还能用cherry-pick来加不同仓库的commit过来,有兴趣的朋友可以自己尝试。附Git常用命令此文已由腾讯云+社区在各渠道发布获取更多新鲜技术干货,可以关注我们腾讯云技术社区-云加社区官方号及知乎机构号

January 23, 2019 · 1 min · jiezi

git入门学习

个人所有文章同步到:https://github.com/zhengzhuan…前言Git(读音为/gt/。)是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。—— 来自git的基本介绍说点废话,这里作者只是在用到git的时候,将自己学习到的东西,在这里进行记录,防止后期忘记,哈哈哈开始第一步首先设置一下Git的user name和email, 这里的用户名和邮箱作者理解成了GitHub的用户名和登录邮箱:$ git config –global user.name “zhengzhuang95”$ git config –global user.email “zheng951203@163.com"第二步第二步生成SSH密钥,这里生成SSh是因为git是有SSH加密验签的:查看是否先cd C:\Users\Administrator.ssh文件夹查看一下看是否已经有了ssh密钥,如果没有密钥则不会有此文件夹,有的话就备份删除生成密钥:$ssh-keygen -t rsa -C “zheng951203@163.com”, 最后得到两个文件 加上原来的一个文件,共3个文件添加密钥到ssh: ssh-add id_rsa.pub 输入之前输入密码在github上添加ssh密钥,这要添加的是"id_rsa.pub"里面的公钥。 登录自己的github,进入到https://github.com/settings/keys New SSH key 复制id_rsa.pub里面的内容到Key里,直接 Add SSH key第三步开始使用github:创建github库在本地创建新文件夹,并在文件夹中生成README.md文件,这里主要用于测试上传打开Git Bash,其实打开CMD也可以,看着也舒服,这里作者就打开CMD进行操作 cd到你自己刚才创建的文件夹中,分别执行git initgit add README.mdgit commit -m “first commit"git remote add origin git@github.com:zhengzhuang95/test.gitgit push -u origin master第四步本地仓库修改同步到远程仓库:git add –allgit commit -m ‘second’git pull origin mastergit push origin master结束语到这里,最基本的git仓库就算创建成功啦

January 23, 2019 · 1 min · jiezi

开发和维护个人开源项目之代码仓库管理

开发和维护个人开源项目之代码仓库管理我将代码仓库管理分为以下几个部分:分支管理策略工作流程tag版本管理提交格式、日志获取代码仓库管理分支管理策略master(稳定分支)(保护分支)master+tag(发布版本,里程碑)hotfix(临时分支,补丁分支)develop(稳定分支)(保护分支)feature(临时分支,功能分支)release(临时分支,预发布分支)master和develop是固定受保护、不能直接push的分支。两者区别:master始终是最后一次发布的稳定版本develop上会有未发布的功能每个分支的功能独立,便于理解。工作流程创建开发分支git checkout -b develop master功能开发git checkout -b feature-x develop功能开发完成,分支合并到develop分支git checkout developgit merge –no-ff feature-xgit branch -d feature-x创建预发布分支git checkout -b release-0.1 develop将预发布合并到master和开发分支git checkout mastergit merge –no-ff release-0.1git tag -a 0.1git checkout developgit merge –no-ff release-0.1git branch -d release-0.1修补buggit checkout -b fixbug-0.1 mastergit checkout master //合并到主线git merge –no-ff fixbug-0.1git tag -a 0.1.1git checkout develop //合并到开发分支git merge –no-ff fixbug-0.1git branch -d fixbug-0.1fork代码,pull request到developtag版本管理上一节提到了用tag打版本,版本号的命名规则:项目立项0.0.0 //主版本.次版本号.修正版本号主版本号:0表示正在开发阶段;次版本号:增加新的功能时增加;修订号:修复bug等改动开发完成1.0.0主版本号:全盘重构时增加;重大功能或方向改变时增加;大范围不兼容之前的时增加;次版本号:增加新功能时增加;修订号:修复bug、功能调整等改动提交格式、日志获取规范化的提交对后续的整理、回溯是很友好的,比如:realse的时候进行一轮日志获取就能生成版本变更信息(版本开发之前应有计划)。规范化commit message提交类型(友好提醒)提交信息格式提交信息验证changelog生成conventional-changelog-cli 工具我是详细实践,请点我:Git commit message和工作流规范总结本文主要对代码仓库的管理作了整理,这个也是每个项目启动之时就应该设计好的。参考链接Git 工作流程Git分支管理策略团队协作中的 Github flow 工作流程Commit message 和 Change log 编写指南如何写好 Git commit messages优雅的提交你的 Git Commit Message接口(Api)版本号命名规则 ...

January 22, 2019 · 1 min · jiezi

Spring 指南(了解Git)

了解GitGit是一个免费开源的分布式版本控制系统(DVCS),它旨在快速、高效地处理任何规模和范围的项目。Git是由Linux创建者Linus Torvalds发明的,用于支持庞大的、不同的Linux开发人员群体,但Git的受欢迎程度与http://github.com关系更紧密,Git已存在多年,但直到GitHub受欢迎程度激增之后,才在Linux社区之外获得广泛认可。GitHub允许你免费托管开源项目,它还提供简单的钩子和友好的用户体验,使Git更容易使用。Mac Homebrew等其他项目也对Git投入很深,Homebrew允许你在Mac上安装开源软件包,构建和管理这些公式的工具利用了Git,用于差异工具、制作补丁、管理资源,以及通过拉取请求提交新的和更新的包。Git与其他DVCS另外两个最受欢迎的DVCS选择是Mercurial和Bazaar,Mercurial有命令行工具hg(以汞的化学符号命名),而Bazaar的命令行工具是bzr。Mercurial与许多开源项目相关联,Ubuntu Linux背后的Canonical公司使用Bazaar,开发人员通常需要熟悉Git、Mercurial和Bazaar。开发人员使用的DVCS通常由开发人员参与的组织决定,而不是由给定的一组功能决定,Git、Mercurial和Bazaar都具有基本功能,例如分支、标签、合并以及不依赖于中央服务器,目前使用Git的开发人员可能会在一年后在Mercurial管理的另一个项目开始工作。关键的挑战是了解每个工具的命令和语言的差异,例如,Mercurial中的hg revert意味着回滚当前更改,恢复为正式版本。git revert意味着添加一个反转先前编辑的新提交,Git有一个命令来支持像Mercurial这样的更改,但它有一个不同的名称。Git与非分布式SCM几个非分布式源代码管理系统(SCM)早于DVCS并仍在使用中:SubversionCVS(并发版本系统)许多专有版本控制系统目前仍在大量使用,例如:Rational ClearCasePerforceVisual SourceSafe这些专有产品通常与其他软件开发工具捆绑在一起,因此在某些软件开发商店中根深蒂固。与DVCS模型相反,这些系统中的关键因素是它们依赖中央服务器来保存跟踪版本和分支所涉及的所有关键数据,从本质上讲,开发人员在家中进行多次提交,与此中央服务器断开连接,然后将其添加到服务器,这不是内置功能,其中一些系统增加了支持此类功能的特性,但它并不是其本质的核心部分。为了说明DVCS和非DVCS的SCM系统之间的区别,请考虑两个人如何分别独立工作,在使用DVCS时如何在某个遥远的地方会面,比如在游轮旅行中,并共享提交。共享提交将具有与中央服务器上相同的权限,使用非分布式SCM时,这两个人只能共享代码差异,而不能提交,为了使提交成为正式提交,必须在到家并访问中央服务器时将提交发布到中央服务器。DVCS的固有优势像Git这样的工具的内置优势在于每个拥有副本的人都拥有重建项目所需的一切,如果中央服务器崩溃且所有数据都丢失,则可以将任何远程副本指定为正式副本,因为它将具有足够的信息以继续,如果开发人员没有最新的提交,则会出现唯一的差异。上一篇:了解REST

January 22, 2019 · 1 min · jiezi

Git 问题,问有多少 tree,多少 blob(附答案)

注:下文的题目来自于极客时间的「玩转Git三剑客」。本文优先在公众号:善始者實繁克終者蓋寡 中发出。目录问题答案推荐一篇 GitHub 文章问题新建一个Git仓库,有且仅有1个commit,仅仅包含 /doc/readme ,请问内含多少个tree,多少个blob?如图:答案一个 commit,两个 tree,一个 blob。推荐一篇 GitHub 文章早上 8:31,团长在「公众号:千古壹号」中发布了一篇文章GitHub 是目前唯一的还有流量的红利的写作平台,推荐给大家看看。

January 21, 2019 · 1 min · jiezi

git实用命令

下面的内容都是我在平时工作中使用频率较高的场景以及对应的代码,分享和记录一下基本操作git init // 初始化git目录git clone // 下载代码到本地 git add [file1] [file2] … // 添加指定文件到暂存区git commit [file1] [file2] … // 提交暂存区的指定文件到仓库区git pull // 从远程仓库拉取代码到本地git push // 推送本地仓库到远程创建分支并提交分支git branch dev //创建本地分支 git checkout dev //切换本地分支 git push origin dev //提交分支到远端 删除分支git branch -d dev //删除本地分支 git push origin –delete dev //删除远程分支 合并分支git merge xxx //合并xxx到当前分支 代码写错分支这个场景用到的挺多的,比如发现了一个Bug,立马动手去改,却发现写到了master或其他分支上,这时候就需要把我们刚写的所有代码搞到对应的bug分支上去:git add . //把所有改动暂存 git stash //把暂存的文件提交到git的暂存栈 git checkout //本该提交代码的分支 git stash apply/pop //将暂存栈中的代码放出来 查看add但没有commit的内容git status查看commit但没有push的内容git diff origin/master合并多次commit信息(git rebase)使用场景:可能我们写完了一些功能之后,git commit 到了本地仓库,之后发现有些地方需要修改或者补充一下,这时候就有了第二次提交,同时有可能出现第三次、第四次提交,这时候git log查看提交日志就会有无用的提交内容,看上去很不美观,这时候我们可以用git rebase来将多次提交合并为一个。git log 查看多次提交的信息// -i 交互式界面进行rebasegit rebase -i 8afbeec // 8afbeec是需要合并的分支的前一个分支的point或者 git rebase -i HEAD~3 // 从HEAD开始,需要合并的分支数之后会出现待合并的提交信息和如下提示:pick:保留该commit(缩写:p)reword:保留该commit,但我需要修改该commit的注释(缩写:r)edit:保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e)squash:将该commit和前一个commit合并(缩写:s)fixup:将该commit和前一个commit合并,但我不要保留该提交的注释信息(缩写:f)exec:执行shell命令(缩写:x)drop:我要丢弃该commit(缩写:d)将提交信息修改为pick d2cf1f9 修改后的信息111squash 47971f6 修改后的信息222squash fb28c8d 修改后的信息333wq保存修改合并修改commit messagewq这时候我们之前提交的多次commit就会合并为一个修改刚刚提交的message使用场景:提交之后,想要修改commit的messagegit commit –amendgit回滚分支使用场景: 。。。git log 查看提交历史 git reset –hard dbf8d691 // 回到指定的提交点git撤销回滚git reflog 查看提交历史(包含已回滚的提交) git reset –hard dbf8d691 // 回到指定的提交点 查看指定分支是基于那个分支创建的使用下边的命令,可以知道某个分支是基于那个分支checkout的,以防止merge的时候,把不需要的内容合并到测试或者正式环境。git reflog –date=local | grep <branchname>未完待续… ...

January 21, 2019 · 1 min · jiezi

pkg版本规范管理自动化最佳实践

前提何为版本?版本即语义版本控制( Semantic version 后面简称为 SemVer )是一种版本控制系统,在过去几年中一直在不断发展。 随着每天都在构建新的插件,插件,扩展和库,拥有通用的软件开发项目版本化方法是一件好事,可以帮助我们跟踪正在发生的事情。SemVer 的格式式为 x.y.z,其中:x代表主要版本( Major )y代表次要版本( Minor )z代表补丁( Patch )SemVer如何工作?通过 SemVer 来确定你应该发布的版本类型是很简单的。如果你修复 bug 或者一些细节修改,那么这将被归类为补丁,在这种情况下你应该升级z。如果你以向后兼容的方式实现新功能,那么你将升级y,因为这就是所谓的次要版本。另一方面,如果你实现了可能破坏现有API的新东西,你需要升级x,因为它是一个主要版本( Major )。想要了解更多请看后面的<更多须知>。开始语义化的版本控制对应用来说是非常重要的,当然,让版本升级就变成了一件看似不重要却非常重要的事情,在我们开发过程中,或者你遇到过这样的情况?由于版本控制概念模糊或者忘记,build 完应用都是随便改的版本或者是完全忘记修改版本。每次 build 完需要改版本太麻烦,懒得改。基于这样的场景下,我开发了这款自动版本升级管理工具 auto-versgithub: https://github.com/zerolty/au…相同库比较项目npm-auto-versionupdate-versionauto-versgit tag支持不支持支持自动更新不支持支持支持提示更新不支持不支持支持手动与auto-vers比较下面是我们需要手动改(前提需要知道改成什么,并且不能忘记修改!)下面是使用了auto-vers的方式。拥有的功能[x] 更新 major, minor, patch, premajor, preminor, prepatch or prerelease[x] 在更新时候提示选择[x] 支持git tag方式[ ] 根据git commit的信息来自动推荐合适的版本使用Node 和 Cli两种引入方式。npm i auto-vers -g Cli基础模式cat package.json{ … “version”: “1.0.0” …}auto-vers -icat package.json{ … “version”: “1.0.1” …}确认模式auto-vers -i -c提示模式auto-vers -t如果你不想更新 , 你可以使用 ctrl + c 去停止。提示和Git组合模式使用这个选项后,在你选择一个版本后,会自动帮你提交一个commit,并且打上一个tag。auto-vers -t -g 直接更改模式auto-vers 1.2.0 orauto-vers -v 1.2.0 optionsauto-vers 1.0.2Auto update version for your applicationUsage: auto-vers [options] <version> [[…]]Options-v –version <version> Can update version directly.-i –inc –increment [<level>] Increment a version by the specified level. Level can be one of: major, minor, patch, premajor, preminor , prepatch or prerelease. Default level is ‘patch’. Only one version may be specified.-e –extra [<value>] This is for prerelease extra data Such as ‘beta’,‘alpha’-c –confirm Do not update the version directly, you can confirm. This is a safe mode.-t –tip Provide choice to you. If you don’t know how to update you can choose this option.-g –git Help you make a tag.(Make you have a git repo)最佳实践在你打包完你的项目同时运行这个命令是一个非常好的选择。基础的方式"script": { “build”: “babel ./src –out-dir ./dist”, “tip”: “npm run build && auto-vers -t”, “version”: “npm run build && auto-vers -t -g”,}在你写好一段打包命令后,紧接着跟上auto-vers -t,将会给你提示需要升级至多少版本,这对你来说会有一定的指示意义。帮助你更好地区判断你需要升级至什么版本。auto-vers -t -g 这个命令适合于你单独发布一个版本,可以一键式的帮助你从修改 package.json -> git commit -> git tag -> git push origin [tagname] 整个流程。中级的方式"script": { “build”: “babel ./src –out-dir ./dist”, “patch”: “npm run build && auto-vers -i -c”, “minor”: “npm run build && auto-vers -i minor -c”, “major”: “npm run build && auto-vers -i major -c”, “beta”: “npm run build && auto-vers -i prerelease -c”,}这个方式针对熟悉这个模式的人,每次需要打包只需要执行对应的命令。(增加参数-c –confirm,这是一个安全的方式去升级,帮助你确认是否升级正确,如果对你而言是一个繁琐的步骤即可去掉。)高级的方式git-hooks如果你没有注册pre-commit和post-commit,可以直接移动进你的.git/hooks目录下mv githook-/ .git/hooks/如果你本地存在hooks,将项目下的hook,手动添加到你的hook下cat githook-*/pre-commit >> .git/hooks/pre-commit当你提交 commit 的时候,会自动跳出选择界面,选择后升级对应的版本。 (注意:如果在你的程序中有相关 commit 命令,请使用–no-verify来跳过此钩子,否则将循环调用)更多须知为什么选择SemVer因为不规范的版本号基本上没有任何意义。从4.1.0 升级4.2? 好的。 为什么? 为什么不是5? 为什么不是4.1.1? 为什么不是4.11? 为什么不是4.1.0-aplha.0?严格的指导原则有助于为版本号提供意义。例如,如果您看到版本1.3.37,那么您将知道这是第一个主要版本,但已经有3个次要版本带来了新功能。 但是,您还会注意到这是此次要版本中的第37个补丁,这意味着涉及很多错误(很少或很大)。它还有助于管理依赖关系,“babel-cli”: “~6.26.0”, 我们引入了babel-cli, 可以得知他的版本是6.26.0,他会锁定x,y 这是一种比较保守的方式, 根据规则可以得知,z的升级不会导致我们api重大的改变以及引入新的功能,。但是如果babel-cli不遵循 SemVer , 在升级z的时候引入了破坏性的变化,这会使得我们的应用出现bug或者变得不可用。正是因为有了 SemVer 的规范,使得我们能够放心地锁定 x,y, 让 z 可以自动升级,因为 z 的升级可能会修复一些小 bug 或者一些细节的改进, 在不破坏我们的应用同时能够对已知bug进行修复。更多技巧既然你已经知道 SemVer 是什么以及自动更新的方法,那么讲一些更新的时候注意事项吧。开始于0.1.0使用SemVer时需要注意的一点是它从0.1.0开始,而不是像我们想象的那样从0.0.1开始。这是有道理的,因为我们不是从补丁开始,而是从一组功能开始,作为项目的初稿,因此版本为0.1.0。在1.0.0之前只是开发阶段每当你构建一个新的软件时,总会有一个迷茫阶段,你一直在问自己:我什么时候应该发布第一个正式的主要版本?以下是一些帮助你回答这个问题的提示:如果您的应用已经在生产中使用或者用户依赖于它,那么你应该已经达到了1.0.0。此外,如果你有打破当前的API,这同样表示你需要升级你的主版本号了。否则,请记住1.0.0以下的版本基 本上是开发热潮时期,你专注于完成你的功能。在1.0.0之前,你不应该害怕任何破坏性的功能,这样当达到1.0.0时,它就会稳定。关于预发布pre-realease在部署主要版本之前,你通常会经历大量需要一次又一次测试的工作,以确保一切正常。 使用SemVer,可以通过在版本中附加标识符来定义预发布。 例如,版本1.0.0的预发行版可能是1.0.0-alpha.1。 然后,如果需要另一个预版本,它将变为1.0.0-alpha.2,依此类推。总结通过了上面的基础介绍,如果你没有使用 SemVer ,没有理由不在你的下一个项目(或当前项目?)上使用它。 它不仅有助于你的项目版本变得有意义,而且还有助于其他可能将你的项目用作依赖项的人。说了这么多,最终还是希望大家能够更加规范地开发项目不仅帮助他人,而且有利于自己。可能我开发的这个项目不是那么完美,但是初衷是来提高大家规范的效率。有bug请多多指出,有功能上的问题也请直言不讳。友情链接蓝色的秋风 无影er参考https://medium.com/fiverr-eng…https://www.sitepoint.com/sem… ...

January 21, 2019 · 2 min · jiezi

Mac OS 下配置多个 SSH Key

大家在工作中可能会遇到需要在一台电脑上配置不同的 SSH Key 的情况,例如我们需要同时使用个人 Github 以及公司的 Gitlab 情况,这时我们就需要配置不同的 SSH Key 了。具体操作步骤如下:1、打开终端,切换到系统的 SSH 目录下cd ~/.ssh2、生成自己 Github 的 SSH Keyssh-keygen -t rsa -C “自己Github账号” -f github_rsa3、输入 Github 账号密码4、Github SSH 公钥获取cat ~/.ssh/id_rsa.pub5、生成公司 Gitlab 的 SSH Keyssh-keygen -t rsa -C “公司Gitlab账号” -f company_rsa6、公司 SSH 公钥获取cat ~/.ssh/id_rsa.pub7、添加配置文件 config (如果有则直接编辑,没有则创建,路径 ~/.ssh/config),配置写法如下:# githubHost github.comHostName github.comPreferredAuthentications publickeyIdentityFile ~/.ssh/github_rsa# gitlabHost gitlab.comHostName gitlab.comPreferredAuthentications publickeyIdentityFile ~/.ssh/company_rsaHost 名称可以随便设置,HostName 就是网站的地址这里要注意的一点是,例如公司 Gitlab 主机地址是http://10.10.10.89:11000,那么 HostName 就是 10.10.10.898、把之前生成的 SSH Key 添加到相应平台9、测试一下是否添加成功# 测试 GitHubssh -T git@github.com# 测试 GitLabssh -T git@gitlab.com10、不同项目切换不同的 ssh取消全局 用户名/邮箱设置,并进入项目文件夹单独设置git config –global –unset user.name git config –global –unset user.email # 单独设置每个repo 用户名/邮箱 git config user.email “xxxx@xx.com” git config user.name “xxxx” ...

January 18, 2019 · 1 min · jiezi

想晋级高级工程师只知道表面是不够的!Git内部原理介绍

本文由云+社区发表作者:腾讯工蜂用户:王二卫从不一样的视角了解git,以便更好的使用git一、git & git 版本库认识git 是一个内容寻址的文件系统,其核心部分是一个简单的键值对数据库(key-value data store),可以向该数据库插入任意类型的内容,它会返回一个40位长的哈希键值。并在此基础上提供了一个版本控制系统的用户界面。git 版本库其实只是一个简单的数据库,其中包含所有用来维护与管理项目的修订版本和历史信息。其不同于subversion,git版本库不仅提供版本库中所有文件的完整副本,还提供版本库本身的副本。在git版本库中,git维护两个主要数据结构:对象库(object store),索引(index)。从整体来看,一个项目的git仓库,就如一张带节点的渔网(该渔网是一张有向网),随着项目的不断推进,该渔网也将不断的向四周扩散。渔网上的节点就像一个个的提交,从某一个正常的节点都能漫游至项目最开始的起点。而分支就如该网上不同节点上的一个特殊标记,分支的演变就是该标记不断的移至其他节点。 分支的合并,根据合并方式的不同,使得这一张网的交叉紧密度越来越高。1.1git对象类型对象库是git版本库实现的心脏,包含四种类型:块(blob,binary lare object),文件的每一个版本表示为一个块。一个blob被视为一个存储任意数据,且内部结构被程序忽略的变量或文件的黑盒。一个blob保存一个文件的数据,但不包含任何关于这个文件的元数据(Metadata,描述数据的数据)。目录树(tree), 一个目录树对象代表一层目录信息。它记录blob标识符、路径名和在一个目录里所有文件的一的元数据。它也可以递归引用其他目录树或子树对象,从而建立一个包含文件和子目录的完整层次结构。提交(commit),一个提交对象保存版本库中每一次变化的元数据,每一个提交对象指向一个目录树对象,这个树对象在一张完整的快照中补货提交时版本库的状态。标签(tag) ,一个标签对象分配一个可读的名字给一个特定的对象,通常是一个提交对象。为了有效的利用磁盘空间和网络带宽名,git把对象压缩并存储在打包文件(pack file)里,这些文件也在对象库里。1.2索引索引是一个临时的、动态的二进制文件,不包含任何文件内容,它仅仅追踪你想要提交的那些内容。使得开发的推进与提交的变更之间能够分离开来。1.3引用引用(ref)是一个保存SHA-1值的文件,该文件的名字指针来替代原始的SHA-1值,一般指向提交对象。本地分支名称、远程跟踪分支名称和标签名都是引用。.git/refs.git/refs/heads.git/refs/tags1.3.1 创建一个引用$ echo “1a410efbd13591db07496601ebc7a059dd55cfe9” > .git/refs/heads/master现在可以通过新建的引用来代替SHA-1的值: $ git log —pretty=oneline master 1a410efbd13591db07496601ebc7a059dd55cfe9 third commit cac0cab538b970a37ea1e769cbbde608743bc96d second commit fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit不提倡直接编辑引用文件,可以通过update-ref更新某个引用 $ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9比如新建一个分支(git分支的本质:一个指向某一系列提交之首的指针或引用) $git update-ref refs/heads/feature-zhangsan cac0ca1.3.2 符号引用符号引用(symbolic reference),间接指向git对象,其实际也是一个引用,不像普通引用那样包含一个SHA-1值,它是一个指向其他引用的指针。 git自动维护几个用于特定目的的特殊符号引用,这些引用可以在使用提交的任何地方使用。HEAD 始终指向当前分支的最近提交,不像普通引用那样包含一个 如: $ cat .git/HEAD ref: refs/heads/master若执行 $ git checkout test,git会这样更新HEAD文件 ref:refs/heads/testORIG_HEAD 某些操作(如:merge、reset),会把调整为新值之前的先前版本的HEAD记录到OERG_HEAD中,只用其可以恢复或回滚之前的状态或做个比较FETCH_HEAD git fech命令将所有抓取分支的头记录到.git/FETCH_HEAD中MERGEHEAD 正在合并进HEAD的提交1.3.3 远程引用如果你添加了一个远程版本库并对其执行过推送操作,Git 会记录下最近一次推送操作时每一个分支所对应的值,并保存在 refs/remotes 目录下。 如:$cat .git/refs/remotes/origin/master ca82a6dff817ec66f44342007202690a93763949 发现添加的远程origin远程库的master分支锁对应的SHA-1值,就是最近一次与服务器通信时master分支所对应的SHA-1值。 远程引用和分支(位于 refs/heads 目录下的引用)之间最主要的区别在于,远程引用是只读的。 虽然可以git checkout 到某个远程引用,但是 Git 并不会将 HEAD 引用指向该远程引用。 因此,你永远不能通过commit 命令来更新远程引用。 Git 将这些远程引用作为记录远程服务器上各分支最后已知位置状态的书签来管理。二、git底层命令cat-file 展示git仓库对象实体的类型、大小和内容ls-remote 显示远程库信息ls-files 显示由工作目录中添加到缓存中的文件的相关信息ls-tree 列出树对象内容read-tree 将给出的树写入索引但不写入缓存write-tree 按照索引区内容创建树对象symbolic-ref 同步引用信息update-index 更新树对象内容至索引三、.git 结构说明HEAD 指示目前被检出的分支index 保存暂存区信息config* 包含项目特有的配置选项description 仅供gitweb程序使用,用户一般不需要关注。hooks 包含客户端和服务端的钩子info 包含全局排除(global excude)文件,存放那些不希望被记录在.gitignore中的忽略模式objects 存储所有数据内容refs 存储指向数据(分支)的提交对象的指针四、git 版本演变准备工作:创建一个没有任何文件的git初始库 $ git init test Initialized empty Git repository in /data/work/test/test/.git/4.1 git数据存储演示hash-object 存储任意类型数据至数据库,并返回hash 键值$ echo ‘test conten’ | git hash-object -w —stdind670460b4b4aece5915caf5c68d12f560a9fe3e4 -w 执行写入数据库操作,若不指定该选项,只会返回hash,不会写入数据库。 –stdin 标准输入输出读取 默认存入是blob类型,通过-t 参数指定$ find .git/objects/ -type f .git/objects//d6/870460b4b4aece5915caf5c68d12f560a9fe3e4一个文件对应一条内容,这个内容的名称以该文件内容加上特定头部信息一起的sha-1校验和。头部信息-对象类型(blob或tree或commit)+一个空格+数据内容长度+一个空字节 git 会通过zlib将文件内容和头部信息拼接一起的内容进行压缩写入磁盘某个对象,并用计算出的sha-1值的前两个字符串作为目录名称,后38个字符串作为子目录内文件的名称。$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4test content4.2 简单版本控制演示4.2.1 创建初始版本$ echo ‘version 1’ > test.txt$ git hash-object -w ./test.txt 83baae61804e65cc73a7201a7252750c76066a304.2.2 更新版本$ echo ‘version 2’ > test.txt$ git hash-object -w ./test.txt 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a此时数据库已经存储了test.txt两个不同的版本,如下:$ find .git/objects/ -type f .git/objects//1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a .git/objects//83/baae61804e65cc73a7201a7252750c76066a30可以通过cat-file -p查看内容,以上都是数据(blob)对象。可以使用 cat-file -t查看。4.3 树对象引入树对像(tree object) 解决文件名和目录保存问题。一个树对象包含了一条或多条树对象记录,每条记录包含一个指向数据对象或子树对象的sha-1指针,以及相应的模式/类型/文件信息。如下所示:$ git cat-file -p master^{tree}100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README 100644 blob 8f94139338f9404f26296befa88755fc2598c289 Rakefile 040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 lib$ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b simplegit.rbmaster^{tree}指向master分支最新提交所指的树对象。 数据对象几种类型100644: 表示一般文件100755: 表示可执行文件120000: 表示 指针—add: 将未跟踪文件加入缓存区—cacheinfo 将数据对象文件加入工作区4.3.1 将文件加入暂存区$ git update-index —add —cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 test.txt4.3.2 生成树对象创建第一个树 $ git write-tree 将暂存区内容生成一个树对象,并输出树对象SHA-1 d8329fc1cc938780ffdd9f94e0d364e0ea74f5794.3.3 演变一个复杂的树$ echo ‘new file’ > new.txt$echo ‘test file2’ > test.txt$git update-index —cacheinfo 100644 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt$ git update-index test.txt$ git update-index —add new.txt创建第二个树$ git write-tree 0155eb4229851634a0f03eb265b69f5a2d56f341$ git cat-file -p 0155eb4229851634a0f03eb265b69f5a2d56f341 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt 100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt此时发现,第一个树丢了,并没有跟第一个树有关系,通过 read-tree进行链接 $ git read-tree —prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579$ git write-tree 3c4e9cd789d88d8d89c1073707c3585e41b0e614$ git cat-file -p 3c4e9cd789d88d8d89c1073707c3585e41b0e614 040000 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579 bak 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt 100644 blob 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a test.txt4.3.4 查看我们生成的树4.4 提交对象引入通过commit对象将这些树对象串起来。 创建第一个提交 $ echo ‘first commit’ | git commit-tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579 fdf4fc3344e67ab068f836878b6c4951e3b15f3d创建第二个提交 $ echo ‘second commit’ | git commit-tree 0155eb -p fdf4fc3 cac0cab538b970a37ea1e769cbbde608743bc96d创建第三个提交 $ echo ‘third commit’ | git commit-tree 3c4e9c -p cac0cab 1a410efbd13591db07496601ebc7a059dd55cfe9版本库目录变化**$ find .git/objects -type f** .git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2 .git/objects/1a/410efbd13591db07496601ebc7a059dd55cfe9 # commit 3 .git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a # test.txt v2 .git/objects/3c/4e9cd789d88d8d89c1073707c3585e41b0e614 # tree 3 .git/objects/83/baae61804e65cc73a7201a7252750c76066a30 # test.txt v1 .git/objects/ca/c0cab538b970a37ea1e769cbbde608743bc96d # commit 2 .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 # ‘test content’ .git/objects/d8/329fc1cc938780ffdd9f94e0d364e0ea74f579 # tree 1 .git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 # new.txt .git/objects/fd/f4fc3344e67ab068f836878b6c4951e3b15f3d # commit 1提交版本图没有执行read-tree$ git log –stat 92387commit 923879712b02f980a2edbe1cee315d883ee72503Author: erweiwang <erweiwang@tencent.com>Date: Tue Jul 17 15:55:53 2018 +0800 second commit new.txt | 1 + test.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)commit e624badd39a25484a08ae74231be65ea50a0fe32Author: erweiwang <erweiwang@tencent.com>Date: Tue Jul 17 15:54:20 2018 +0800 first commit test.txt | 1 + 1 file changed, 1 insertion(+)五、包文件Git 最初向磁盘中存储对象时所使用的格式被称为“松散(loose)”对象格式。 但是,Git 会时不时地将多个这些对象打包成一个称为“包文件(packfile)”的二进制文件,以节省空间和提高效率。 当版本库中有太多的松散对象,或者你手动执行 git gc 命令,或者你向远程服务器执行推送时,Git都会这样做。git 打包对象时,会查找命名及大小相近的文件,并只保存文件不同版本之间的差异内容和文件最新版本的完整内容。六、引用规格引用规格的格式由一个可选的 + 号和紧随其后的 : 组成,其中 是一个模式(pattern),代表远程版本库中的引用; 是那些远程引用在本地所对应的位置。 + 号告诉 Git 即使在不能快进的情况下也要(强制)更新引用。[remote “origin”] url = https://github.com/schacon/simplegit-progit fetch = +refs/heads/*:refs/remotes/origin/如果想让git每次只拉取远程master分支,而不是所有分支,可以将引用规格那一行修改为: fetch = +refs/heads/master:refs/remotes/origin/master七、git clone代码库过程执行git clone后,拉取info/refs文件 => GET info/refs ca82a6dff817ec66f44342007202690a93763949 refs/heads/master确定HEAD引用,明确检出至工作目录的内容 => GET HEAD ref: refs/heads/master 以上说明完成抓取后需要检出master分支从info/refs文件中所提到的ca82a6提交对象开始 => GET objects/ca/82a6dff817ec66f44342007202690a93763949 (179 bytes of binary data)根据ca82a6提取的的父提交对象和树对象开始遍历整个完整版本库。在遍历过程中,若是未能直接找到(非松散对象)某些对象,会去替代版本库或某个包文件获取。八、git推送远端库过程为了上传数据至远端,Git 使用 send-pack 和 receive-pack 进程。 运行在客户端上的 send-pack 进程连接到远端运行的 receive-pack 进程。九、扩展知识9.1维护git gc —auto //整理松散对象并放置包文件,将多个包文件合并为一个大的包文件,移除与任何提交不相关的陈旧对象9.2数据恢复确定需要恢复的版本 git reflog 查看git默默记录的每一次你改变的HEAD的值。 git log -g 可以详细的查看引用日志中各个版本的信息,风方便确定要恢复的提交。 如下所示 commit 1a410efbd13591db07496601ebc7a059dd55cfe9 Reflog: HEAD@{0} Reflog message: updating HEAD third commit commit ab1afef80fac8e34258ff41fc1b867c702daa24b Reflog: HEAD@{1} Reflog message: updating HEAD modified repo.rb a bit创建用于恢复的临时分支$ git branch recover-branch ab1afef通过git fsck检查数据库的完整性(当reflog 也不存在需要恢复的版本)当引用日志所在目录.git/logs/ 被不小心清空时$ git fsck —full Checking object directories: 100% (256/256), done. Checking objects: 100% (18/18), done. dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4 dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9 dangling blob 7108f7ecb345ee9d0084193f147cdad4d29982939.3移除对象该操作使用须谨慎,会导致提交历史不被重写。应用场景,必须对已上库的某些文件(因文件太大或保密信息)进行彻底移除可以使用。定位出问题文件名 保密文件一般是已知的,若是误提交的文件较大需要删除,但又不知道是哪些文件,且又执行过git gc可以通过类似以下命令定位: $ git verify-pack -v .git/objects/pack-29…69 .idx | sort -k 3 -n | tail -3* dadf7258d699da2c8d89b09ef6670edb7d5f91b4 commit 229 159 12 033b4468fa6b2a9547a70d88d1bbe8bf3f9ed0d5 blob 22044 5792 4977696 82c99a3e86bb1267b236a4b6eff7868d97489af1 blob 4975916 4976258 1438 $ git rev-list —objects —all | grep 82c99a3 82c99a3e86bb1267b236a4b6eff7868d97489af1 git.tgz从过去所有树中移除这个文件 查看哪些提交对这个文件做过改动 $ git log —oneline —branches — git.tgz dadf725 oops - removed large tarball 7b30847 add git tarball 从7b30847之后的所有提交历史中完全移除该文件 $ git filter-branch —index-fileter ‘git rm —ignore-unmatch —cached git.tgz’ — 7b30847^… Rewrite 7b30847d080183a1ab7d18fb202473b3096e9f34 (1/2)rm ‘git.tgz’ Rewrite dadf7258d699da2c8d89b09ef6670edb7d5f91b4 (2/2) Ref ‘refs/heads/master’ was rewritten –index-filter 只修改暂存区或索引中的文件 –cached 需要从索引中移除,使得在运行过滤器是,并不会将每个修订版本检出到磁盘 –ignore-unmatch 如果尝试删除的模式不存在时,不提示错误 filter-branch 用于指定从那个提交以来的历史重新打包日志 执行上面操作,本地历史不在包含那个文件的引用,但是,引用日志和 .git/refs/original 通过 filterbranch选项添加的新引用中还存有对这个文件的引用,必须移除它们后重新打包数据库。 $ rm -Rf .git/refs/original $ rm -Rf .git/logs/ $ git gc彻底移除$ git prune –expire now $ git count-objects -v此文已由腾讯云+社区在各渠道发布获取更多新鲜技术干货,可以关注我们腾讯云技术社区-云加社区官方号及知乎机构号 ...

January 18, 2019 · 4 min · jiezi

Git 学习笔记整理

Git起步Git是什么?Git是一个免费的开源分布式版本控制系统,旨在快速,高效地处理从小型到大型项目的所有事务。集中式与分布式的区别:Git几个特性直接记录快照,而非差异比较git会对当时的全部文件制作一个快照并保存这个快照的索引。git对待数据更像是一个 快照流几乎所有操作都是本地执行Git保证完整性git中所有数据存储前都计算校验和,然后用校验和来引用。git用以计算校验和的机制叫做SHA-1 hash。是一个由40个十六进制字符组成的字符串。实际上,git数据库中保存的信息都是以文件内容的哈希值来索引,而非文件名。Git一般只添加数据三种状态git有三种状态:已提交(数据已经保存在本地仓库中)、已修改(已修改文件,但是还未保存到仓库中)、已暂存(对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中)。由此引出三个工作区域的概念:Git仓库、工作目录、暂存区域。Git内部原理首先我们来看一个新的 .git 目录的结构HEADconfig*descriptionhooks/info/objects/refs/description文件仅供GitWeb程序使用,我们无需关心。 config文件包含项目特有的配置选项。info目录包含一个全局性排除(global exclude)文件,用以放置那些不希望被记录在.gitignore 文件中的忽略模式(ignored patterns)。hooks目录包含客户端或服务端的钩子脚本(hook scripts)。剩下的四个条目很重要:HEAD文件、(尚待创建的)index文件,和 objects目录、refs目录。 这些条目是 Git 的核心组成部分。 objects目录存储所有数据内容;refs目录存储指向数据(分支)的提交对象的指针;HEAD文件指示目前被检出的分支;index 文件保存暂存区信息。Git对象Git是一个内容寻址文件系统,它的核心部分是一个简单的键值对数据库。数据对象(blob object)是一块二进制数据,没有其他任何指向或任何属性,甚至连文件名都没有。git会根据文件内容计算出一个hash值,以hash值作为文件索引存储在Git文件系统中树对象(tree object)提交对象(commit object)提交对象是用来保存提交的作者、时间、说明这些信息的,commit-tree除了要指定提交的树对象,也要提供提交说明,至于提交的作者和时间,则是根据环境变量自动生成,并不需要指定。我们运行 git add 和 git commit 命令时, Git 所做的实质工作——将被改写的文件保存为数据对象,更新暂存区,记录树对象,最后创建一个指明了顶层树对象和父提交的提交对象。这三种主要的 Git 对象——数据对象、树对象、提交对象——最初均以单独文件的形式保存在 .git/objects 目录下。Git引用我们可以借助类似于git log 1a410e 这样的命令来浏览完整的提交历史,但为了能遍历那段历史从而找到所有相关对象,你仍须记住 1a410e 是最后一个提交。我们需要一个文件来保存 SHA-1 值,并给文件起一个简单的名字,然后用这个名字指针来替代原始的 SHA-1 值。在 Git 里,这样的文件被称为 引用(references,或缩写为 refs)。你可以在 .git/refs 目录下找到这类含有 SHA-1 值的文件。代码回滚的选择git reset、git checkout、git revert的选择附上感觉讲的不错的一篇文章回滚的选择git reset [type] HEADgit reset用于撤销未被提交到remote的改动,即撤销local的修改。除了移动当前分支的HEAD(提交记录),还可以更改workspace(工作目录)和index(暂存区):–soft:修改HEAD,不修改index和workspace。–mixed:修改HEAD和index,不修改workspace。默认行为。–hard:修改HEAD、index、workspace。git revert通过新建一个commit来撤销一次commit所做的修改,是一种安全的方式,并没有修改commit history总结:命令作用域常用场景git reset提交层面在私有分支上舍弃一些没有提交的更改git reset文件层面将文件从缓存区中移除git checkout提交层面切换分支或查看旧版本git checkout文件层面舍弃工作目录中的更改git revert提交层面在公共分支上回滚更改git revert文件层面 Git Flowgit flow介绍Git Flow常用的分支Production 分支也就是我们经常使用的Master分支,这个分支最近发布到生产环境的代码,最近发布的Release, 这个分支只能从其他分支合并,不能在这个分支直接修改Develop 分支 这个分支是我们是我们的主开发分支,包含所有要发布到下一个Release的代码,这个主要合并与其他分支,比如Feature分支Feature 分支这个分支主要是用来开发一个新的功能,一旦开发完成,我们合并回Develop分支进入下一个ReleaseRelease分支当你需要一个发布一个新Release的时候,我们基于Develop分支创建一个Release分支,完成Release后,我们合并到Master和Develop分支Hotfix分支当我们在Production发现新的Bug时候,我们需要创建一个Hotfix, 完成Hotfix后,我们合并回Master和Develop分支,所以Hotfix的改动会进入下一个Release图解:附录Git常用命令百度云 密码:7ze2Git提交规范git commitfeat:新功能(feature)fix:修补bugdocs:文档(documentation)style: 格式(不影响代码运行的变动)refactor:重构(即不是新增功能,也不是修改bug的代码变动)test:增加测试chore:构建过程或辅助工具的变动 ...

January 18, 2019 · 1 min · jiezi

500行JS代码打造你的专属GIT

这篇短文将介绍如何用500行的Javascript代码,写一个你自己专属的GIT。 这不是一个如何使用GIT的工具,而是GIT的底层实现。目的是希望能加深对GIT的底层实现原理,而不是想换掉GIT,这只是一个GIT的雏形而已代码来自开源,也回流开源,有需要且不嫌弃的可以上去看看 https://github.com/notechsolution/gitdou缘起跟GIT的结缘开始于2011年,公司决定不用原来的IBM Clearcase,改用开源的GIT。作为当时GIT的内部support,确实有很长一段时间跟它厮混在一起。后来还写了几篇如何使用GIT的文章,有空可以翻翻 GIT七年之痒. 前两年回一下炉,又写了几篇 GIT入门.最近看到一个叫Richard Feynman的人说过这么一句话What I cannot create, I do not understand - Richard Feynman嗯嗯,有点意思,扒拉了一下,还有不少人用Javascript写GIT。这次的实现主要也是参考了其中一个叫gitlet的用什么锤子?| 技术栈GIT是Linux Torvalds用C语言写的。小的不才不懂C,那就用Javascript写写吧, ES6 可以让代码可以写得比较简洁。既然重造轮子,那就尽量少用框架吧。但是作为lodash粉,还是忍不住了,最后还是用了lodash~~~. 当然,Pivotal Lab中毒较深,做个练习也离不开TDD,所以这次也用了Ava作为testing框架。 但功力尚浅,有些case也偷懒了,testcase跟代码的函数比例只做到1:1, 500行的代码只有500行的unittest。锤出个什么东东?| 实现哪些功能这次的目的是为了加深对GIT底层实现原理的理解,而不是做出一个真正的产品出来,所以对于用户操作没有做出各种友好的提醒,比如没有像Already up to date 这样的提醒等等,只要实现了GIT的如下核心命令:initaddrmcommitcheckoutbranchremotefetchmergepullpush咋锤的?| 实现过程下面尝试逐一来解释一下每个命令是干什么的。gitdou.init首先是初始化一个GIT的项目。GIT在某种程度上可以理解为一个文件的数据库,里面保存着所有文件的所有版本。初始化的过程也就是创建各个文件以及目录..gitdou├── HEAD├── config├── objects└── refs ├── heads.gitdou: 当前repository的根目录config: 当前repository的配置文件,记录当前repository的各种配置,比如是不是bare,远程协作仓库地址等等HEAD: 存放repository指向哪个branch,由于初始branch为master,所有HEAD的初始值一般为ref: refs/heads/masterobjects : 存放数据库文件的目录refs:存放local branch或者remote branch的当前commit,类似于数据库的游标初始化的过程就是在指定的目录.gitdou下生成这些目录及文件的过程。代码就比较简单,根据目录结构,生成对应的文件树: init: () => { const gitdouStructure = { HEAD: ‘ref: refs/heads/master’, objects: {}, refs: { heads: {} }, config: JSON.stringify({core: {bare: false}}, null, 2) } files.writeFilesFromTree({’.gitdou’: gitdouStructure}, process.cwd()); },add前面说到了git实际是一个数据库,存放了所有文件的所有历史版本。为了更方便高效地查询,数据库都会建立索引。git也不例外,它也有一个index文件,记录所有文件的路径,这些文件的状态以及当前版本的hash值。add 命令就是将指定路径的所有文件的路径,状态以及当前的hash值记录保存到index文件里面。其实现过程就是扫出指定目录下的所有文件,逐一计算他们的hash值,然后写到index文件里面add: path => { const addedFiles = files.listAllMatchedFiles(path); index.updateFilesIntoIndex(addedFiles, {add: true}); }rm有添加命令,对应的也就应该有删除命令。其过程跟add基本一致,只不过多了一步把要删除的文件从当前workingCopy里面删除掉。rm: path => { const deletedFiles = files.listAllMatchedFiles(path); index.updateFilesIntoIndex(deletedFiles, {remove: true}); files.removeFiles(deletedFiles); }commit当任务已经到一段落,我们需要给当前版本做一个快照,方便以后找回。这时我们可以做一个commit。这个commit将会包含一个hash树,这棵树将当前版本的所有文件连起来。当然还包含了一些commit的metadata,比如谁,什么时候commit,commit的备注是什么等等。具体实现大致为:创建一个hash树,将所有文件连起来,并且保存到objects数据库里面创建一个commit对象,包含hash树的hash,commit的消息,commit的时间,如果有父亲hash,也包含进来。同样将这个commit的对象保存到objects数据库里面更新当前branch,指向新的commit hashcommit: option => { // write current index into tree object const treeHash = gitdou.write_tree(); // create commit object based on the tree hash const parentHash = refs.getParentHash(); const commitHash = objects.createCommit({treeHash, parentHash, option}); // point the HEAD to commit hash refs.updateRef({updateToRef: ‘HEAD’, hash: commitHash}) }branchGIT的分支管理是可能稍微复杂一些,不同公司,不同的开发模式会有不同的分支管理,甚至有人将这个上升到分支管理的艺术的高度。最有名的分支管理模型应该就是A successful Git branching model但… 但… branch在GIT的实现里面可以说是最最简单的一个了,所谓创建branch就是在.gitdou\refs\heads创建一个用branch名字命名的文件,文件的内容就是当前的hash. 突然想起某学习机广告:SO EASY~~~ branch : (name, opts) => { const hash = refs.hash(‘HEAD’); refs.updateRef({updateToRef:name, hash}); },checkout不能都是那么容易的啦!要不也不用花这么多时间写!checkout就稍复杂一些。checkout有点类似于还原现场. 将当前workingCopy还原成指定commit或者branch对应的工作环境。前面commit命令的时候说到:创建一个hash树,将所有文件连起来,并且保存到objects数据库里面。所有首先我们要找出指定commit或者branch的hash树。再找出当前代码库版本的hash树。然后站在当前代码库hash树的角度,比较这出哪里改了,哪里删了,哪里新增的。最后将这些不同落实到当前代码库中。当然,别忘了更新HEAD文件指向checkout的commit或者branch checkout: (ref) => { const targetCommitHash = refs.hash(ref); const diffs = diff.diff(refs.hash(‘HEAD’), targetCommitHash); workingCopy.write(diffs); refs.write(‘HEAD’,ref: ${refs.resolveRef(ref)});}remote上面的这些命令基本都是在本地自己玩而已,后面这几个命令就涉及到跟其他人协作了!不过为了简单,协作也是通过文件系统操作而已,没有经过http,但是原理基本一样!remote命令只要是用来管理有远程代码库的配置信息,GIT里面remote命令实现了很多子命令,比如有remote ls,remote show,remote add,remote remove。我们这里只实现刚需的add命令remote add命令将会读出代码库的配置文件.gitdou\config,然后在里面添加remote的属性 remote : (command, name, path) => { const cfg = config.read(); cfg[‘remote’] = cfg[‘remote’] || {}; cfg[‘remote’][name] = path; config.write(cfg); },添加后的.gitdou\config文件内容大致如下 (这里采用的是JSON格式存取){ “core”: { “bare”: false }, “remote”: { “origin”: “git@github” }}fetchremote已经准备好了,接着我们可以拉取其他人的代码库了!在真正GIT的实现中,这时就涉及到跟GIT服务器交互的细节,不过我们这里都是在本地,所有情况比较简单。首先我们要在remote的工作目录下面,读取他objects数据库的所有对象,然后将这些对象写到我们的objects数据库里面,再将最新的hash更新到refs/remotes/origin/${branch} fetch : (remote, branch) => { const remoteUrl = config.read()[‘remote’][remote]; const remoteHash = refs.getRemoteHash(remoteUrl, branch); const remoteObjects = refs.getRemoteObjects(remoteUrl); _.each(remoteObjects, content => objects.write(content)); refs.updateRef({updateToRef:refs.getRemoteRef(remote, branch), hash:remoteHash}); refs.write(“FETCH_HEAD”, ${remoteHash} branch '${branch}' of ${remoteUrl}); return [“From " + remoteUrl, “Count " + remoteObjects.length, branch + " -> " + remote + “/” + branch].join("\n”) + “\n”; }mergefetch的确是拿到了对方的所有对象,但是本地的代码丝毫没有变化,因为还没有将这些合并到我们的代码库里面。merge做的就是这事。这个版本我们只实现了没有冲突的场景,也就是可以fastforward的情况。首先我们拿到remote的hash树,再读取我们当前的hash树,然后判断是否可以fastforward (也就是判断remote是否包含了我们最新的代码),然后跟checkout类似,站在当前代码库的角度,找出两颗hash树的异同点,将这些异同点写到当前代码库。最后更新当前代码库的当前branch,指向最新的commit merge: (ref) => { const receiverHash = refs.hash(‘HEAD’); const giverHash = refs.hash(ref); if(merger.canFastForward({receiverHash, giverHash})){ merger.writeFastForwardMerge({receiverHash, giverHash}); return ‘Fast-forward’; } return ‘Non Fast Foward, not handle now’; } pull有了fetch跟remote命令,pull就躺着数钱了!因为pull(remote, branch) = fetch(remote, branch) + merge(‘FETCH_HEAD’)pull: function(remote, branch) { gitdou.fetch(remote, branch); return gitdou.merge(“FETCH_HEAD”); }push来而不往非礼也!有pull也得有push。push的实现原理有点粗暴!直接跳转到对方的工作目录下,然后把自己的objects里面的所有对象写到对方的代码库里面,再帮对方更新对方的branch引用! 细思极恐,好在真正的GIT不是这样处理的! push: ref => { const onRemote = util.onRemote(remoteUrl); const remoteUrl = config.read()[‘remote’][ref]; const receiverHash = onRemote(refs.hash, ref); const giverHash = refs.hash(‘HEAD’); objects.allObjects().forEach(item => onRemote(objects.write, item)); onRemote(gitdou.updateRef, refs.resolveRef(ref), giverHash); }结语从有用的角度看,这次GITDOU的实现并无卵用!从无用的角度看,这次GITDOU的实现还挺有用! ...

January 18, 2019 · 2 min · jiezi

版本管理工具之Git 和SVN

1.简介Git 是一个免费并且开源的分布式版本控制系统,被设计用来快速、高效的管理一切从小到大的项目。SVN是一个开源的集中式版本控制系统。这些数据放置在一个中央资料档案库(repository) 中。 这个档案库很像一个普通的文件服务器, 不过它会记住每一次文件的变动。 这样你就可以把档案恢复到旧的版本, 或是浏览文件的变动历史。2.区别集中式 VS 分布式那么什么是集中式版本控制系统,什么又是分布式版本控制系统呢?这两者又有什么区别呢?首先先说集中式版本控制系统,它的版本库是存放在中央服务器,但是开发人员用的都是自己的电脑,所以在干活之前,开发人员需要先从中央服务器获取最新的代码,然后才可以工作。工作完了,再把新代码传到中央服务器去。它最大的缺点就是必须联网才可以干活,没网就可以回家睡觉了。而且如果网速慢的话,你想要把代码从服务器下载下来或者提交代码到服务器都会非常慢。那么分布式版本控制系统又有何不同呢?首先所谓的分布式版本控制系统,没有所谓的 “中央服务器” 一说,因为每一台电脑上都有一个完整的版本库,每一台电脑理论上都可以是“中央服务器”。因为每一台电脑都有一个完整的版本库,所以工作时并不需要联网。如果是团队协作的话,只需要把修改的文件推送给对方即可。那么有的人会说,既然如此,为何还有 Git 服务器?其实这个服务器只是非常稳定,24 小时开机,为了方便团队之间不同的人交换大家的修改而已。没有它一样可以正常的工作,而集中式便不行。所以在安全性上也是分布式的更好,如果某一台电脑坏了,只需要拷贝一份版本库即可。而集中式的服务器如果出了故障那就是很大的问题了。当然 Git 相比于 SVN 这种集中式版本控制系统,并不仅有这一点优势,Git 强大的分支管理,快速、高效的处理,便捷的使用,这些优势在我的教程中你会慢慢感受到!3.拓展GitHub 是一个利用 Git 进行版本控制、专门用于存放软件代码与内容的共享虚拟主机服务。Github 社区 - :[ https://github.com]

January 18, 2019 · 1 min · jiezi

GIT - 代码分支管理模型之一

就像人心散,队伍不好带一样,代码版本多,分支也不好管当产品开发到一定程度后,多版本同时开发,各种热修复等等问题,势必会带来版本分支管理的问题。今天我们准备一起来看看第一种代码分支管理方案。这里要先强调一下,分支管理的方式各有千秋,不存在谁一定比谁好,只有谁比谁更适合你而已热门的成功代码分支管理这款人们的分支管理方案只要是从这篇叫A Successful Git Branching Model 衍生出来的。很多企业的项目都是采用这种方式来进行管理。下面这张图涵盖了这种方式的各种分支设计:这个模型基本能满足企业项目开发过程中遇到的各种代码版本管理的需求,下面尝试着把这种模型分解给大家讲讲:咬住青山不放松在上面的图中,大家可以看到有两个分支的名字被加粗了:master 和 develop,这两个是分支当中的中流砥柱。#### master这是新建一个GIT repository之后的第一个分支。在这个模型中,master分支代表的是当前产品线上的版本,它的最后一个commit可能是已经上线了,或者已经经过QA/PD/PO 千万次折磨、分分钟可以上线的功能。换句话说,这条分支要做到 随时都可以上线的! 要是谁把一个开发了一般的功能提交到这个版本上去,有可能会被PO拉去祭天的! 所以如果有严格的权限管理的话,一般会把这个分支给锁起来,有且仅有上线的同事才有权限动它!另外master的每次上线都会打一个tag,表明版本号是多少develop一般灵长类动物都敬畏祭天这样的操作,所以我们需要开辟一篇新天地来大有作为。为了和大部队保持一致,develop的分支是基于master创建出来的C:\githome\github\gitdou (master) (gitdou@0.1.0) git branch* masterC:\githome\github\gitdou (master) (gitdou@0.1.0) git checkout -b developSwitched to a new branch ‘develop’C:\githome\github\gitdou (develop) (gitdou@0.1.0) git show-branch -a –no-name* [develop] add httpUtil.js ! [master] add httpUtil.js ! [origin/HEAD] add httpUtil.js ! [origin/master] add httpUtil.js—-最后的git show-branch -a –no-name 命令的输出可以看到develop的分支是基于master创建出来的如果项目不是特别大,版本管理也比较简单,那么master跟develop这两个分支就基本够用了文体两开花当项目稍微大一些的时候,会遇到各种各样的版本管理需求,但不一定每一种你都需要,当需要的时候可以再建立这些分支,比如有features, release, hotfixfeatures第一种情况比较常见,项目有很多同事并行开发,比如分了多模块给多个小组进行开发,如果各个模块都往develop分支上面丢,那么基本没办法做持续集成(Continue Integration)的操作。虽然最后集成的时候各模块一定会和谐相处的,但是在开发过程当中,不一定每一个commit都是向模块兼容,所以最好能每个模块都自行在一个旮旯捣腾,等最好确定能相亲相爱了,大家再杵到一块去。这是我们可以基于模块创建各种feature分支,有关开发人员就在相应的分支上进行开发就行,等到各个功能分支基本完成了,我们再把这些分支merge到develop上面去如果有了feature分支,那么develop分支基本就成了集成分支了release前面说了master分支代表着当前产品线上的版本,分分钟可以上线部署而不会导致祭天这种结局的。但这有些项目或团队有这样的情况,产品上线前要先部署到准产品线上去玩,内测一周左右,确定完全没有问题了再上到产品线上去。在内测的这一周,如果发现了有问题了,赶紧从develop分支进行修复,再上到准产品线来验证。如果我们用master分支来进行准产品线的部署,在内测的这一周发现问题,而这时我们的产品线上有紧急问题要fix,那么我们就无法直接拿master分支上线,这就做不到我们之前的承诺: master分分钟可以上线而不用祭天所以我们可以创建一个release的分支来进行准产品线的部署和问题修复,知道确认完全没有问题了,我们再同步到master分支去上线hotfix做系统的哪可能没有bug!当产品线上无辜出现bug的时候,我们要去哪个分支做修复呢?master :显然不合适,产品线上由于设计或者考虑不周出现bug一般是不用祭天的,但如果因为这样,在master上面一通乱改,那就有可能要祭天了release:这个是给下一个版本用的呢。如果是上一个版本的话,那新增的修改就破坏了原来版本号的意义了,比如原来分支叫release-1.0.1, 那么加了这个版本还叫这个名字吗?developer: 如果还有一些其它正在开发的功能,那一会上线的时候就会连带这个也稍上去了!feature: 这就有点扯远了看来上面这4种分支都不大合适,那就来款新的,就叫hotfix. hotfix分支是从master分支直接创建出来的,用来做一些产品线上紧急的代码修复,或者临时添加的小功能。开发人员直接在这个分支上进行开发,功能完成后直接上到master分支再上线。记得每次hotfix上线后,要把功能同步回developer,再到各feature的分支上以上就是关于 这款 成功的代码分支管理模型的讲解,基本上能满足大部分企业大部分项目的代码版本管理的需求! 后面会介绍另外一块代码分支管理模型,是指我们公司的一种管理的方式,下回见!

January 18, 2019 · 1 min · jiezi

入门hexo ! 搭配next、GiteePages,轻松免费开发高质量个人博客 ( Linux Deepin )

本文重点介绍Linux deepin下开发hexo 搭配next、GiteePages,免费轻松实现高质量高颜值博客。其他系统的方法大同小异,只是环境配置略有不同,只要有git和npm环境便可轻松入门hexo。最终效果: https://tczmh.gitee.io/hexodemo/一、安装先安装git npm依赖sudo apt install gitsudo apt install npm初始化hexo init blogcd blognpm install启动hexo server打开浏览器访问 http://localhost:4000即可看到第一个hexo页面二、主题换主题 ( 位置还是在blog文件夹内 Linux下默认位置是 /usr/lib/blog )git clone https://github.com/iissnan/hexo-theme-next themes/next配置文件vim _config.ymltheme: landscape 改为 theme: next# Extensions## Plugins: https://hexo.io/plugins/## Themes: https://hexo.io/themes/theme: next部署 重启hexo g -dhexo s效果如图三、发文章发表文章hexo new post “初识hexo"编辑文章vim /usr/lib/blog/source/_posts/初识hexo.md修改内容,语法为markdown(语法问题,所有的 被我替换成了 . 使用的时候要替换回来)---title: testdate: 2019-01-17 09:27:29tags: test---## start----**这是加粗的文字***这是倾斜的文字*这是斜体加粗的文字这是加删除线的文字—-—-<a href=“https://www.jianshu.com/u/1f5ac0cf6a8b" target="_blank”>简书</a>—-姓名|技能|排行–|:–:|–:刘备|哭|大哥关羽|打|二哥张飞|骂|三弟—-…javascript function clean(){ alert(“已完成!”); }…—-…flowst=>start: 开始e=>end: 结束op=>operation: 我的操作cond=>condition: 确认?st->op->condcond(yes)->econd(no)->op…—-##end部署 重启hexo g -dhexo s效果如下https://tczmh.gitee.io/hexodemo/2019/01/17/demo/四、部署线上避坑指南:用户名之后会用来作为二级域名例子:若 用户名为qiaofeng那么 就可以获得一个免费的个人线上地址qiaofeng.gitee.io若 新建项目的时候,项目名如果是blog那么 访问地址就是https://qiaofeng.gitee.io/blog/若项目名与用户名相同也叫qiaofeng那么 可以直接访问二级域名访问 https://qiaofeng.gitee.io 而省略项目名先注册码云(https://gitee.com),新建项目(截图省略)打开【服务】 - 【Gitee Pages】勾选【强制使用 HTTPS】点击【启动】看到“已开启 Gitee Pages 服务,网站地址: https://tczmh.gitee.io/hexodemo” 即可回到本地,修改配置文件vim _config.yml中间修改(这里的url是刚才开启Gitee Pages 服务出现的url,root必须是gitee新建的项目名,如果最后出现读不到js css,显示混乱等问题,就是这一步不对)url: https://tczmh.gitee.io/hexodemoroot: /hexodemo结尾修改deploy: type: git repo: https://gitee.com/tczmh/hexodemo.git branch: master其中repo填写gitee上获得的git地址,在【项目详情】 - 【克隆/下载】 - 【复制】安装依赖npm install hexo-deployer-git –save设置全局git (若邮箱和用户名不知道,可以在gitee的个人设置页面查看)git config –global user.email “你的邮箱"git config –global user.name “你的用户名"清理&更新&部署一条龙命令 (可能需要输入账号密码,就输gitee登录的即可)hexo clean && hexo g && hexo d看到以下内容说明成功remote: Powered By Gitee.com To https://gitee.com/tczmh/hexodemo.git + cfcc494…395648d HEAD -> master (forced update)分支 ‘master’ 设置为跟踪来自 ‘https://gitee.com/tczmh/hexodemo.git' 的远程分支 ‘master’。INFO Deploy done: git访问地址:https://tczmh.gitee.io/hexodemo和本地测试的一样大功告成!之后只需要修改本地配置文件来配置博客,发表文章更多功能访问官方文档https://hexo.io/zh-cn/docs/http://theme-next.iissnan.com/getting-started.html补充一下生成二维码方法(因为开启HTTPS 所以直接支持 微信扫一扫 微信长按二维码识别等)https://cli.im/输入【URL】点击【生成】即可主要就是这些,都是一些基本入门的东西,深入研究可以说是其乐无穷。本篇内容也可以查看我的个人博客:https://zzzmh.cn/single?id=54 ...

January 17, 2019 · 1 min · jiezi

不同项目配置不同的 Git 账号

遇到在一台电脑里,通常会遇到这种情况。有公司的 Git 账号提交公司的 Gitlab,有自己的 Github 账号提交 Github 仓库。比如像我的公司 Git 账号为 xiaojia,但我的 Github 账号为 Linda0821,并且邮件也不一样。当我设置 git 全局 name 和 email 为我的公司 Git 账号时,提交 Github 显示的也是这个账号,而不是我的 Github 账号,这就有点尴尬了。解决由于电脑上 Github 仓库比较多,所以我将全局 name 和 email 设置成我的 Github 账号。$ git config –global user.name “Linda0821”$ git config –global user.email “Linda0821@gmail.com"这时打开电脑上任意一个 Git 仓库,输入:$ git config –list都会看到 user.name 和 user.email 用的都是全局的。然后进入公司项目里,进行特殊设置:$ git config user.name “xiaojia”$ git config user.email “xiaojia@jd.com"再次查看配置:$ git config –list会发现有两个配置,其中一个是全局的,一个是特殊配置的,优先取下面的:…user.name=Linda0821user.email=Linda0821@gmail.com…user.name=xiaojiauser.email=xiaojia@jd.com…这样,就能保证我每次提交仓库时带上的 name 和 email 都跟项目是匹配的了。

January 17, 2019 · 1 min · jiezi

vuex重置所有state(可定制)

在正式场景中我们经常遇到一个问题,就是登出页面或其他操作的时候,我们需要重置所有的vuex,让其变为初始状态,那么,就涉及到了多种方法:1、页面刷新:window.location.reload()这个方法通过路由判断优化或是逻辑优化,始终页面时重新加载,就会导致用户体验很差,对浏览器来说也是一种不必要的负担,所以我尝试之后就放弃了。2、写一个重置的方法然后调取actions.resetVuex = function() { store.commit(state.a, null) store.commit(state.b, null) store.commit(state.c, null) …}store.dispatch(‘resetVuex’)这样又会出现多个module,多个state,需要手动添加多个,工作量巨大且不易维护,而且如果我们state初始是个个数组,一个对象这些更不好操作,更优最多就是我们初始的时候深拷贝一份,但是也需要每个module里进行操作和封装这两种方法是可以解决问题的,但是我还是没有采用这两种方式,因为感觉已经牺牲了某些东西来达成目的了,通过我反复的实践,和摸索我采取了以下方法:首先页面加载,第一次加载引入store的时候,store的所有state肯定是初始值,那么我就做一个本地缓存记录下来:这里我采用了store插件(引用方式参考 https://github.com/nbubna/store)在main.js创建vue实例之前:import _store from ‘store’import createStore from ‘./store’…const store = createStore() //我创建好的 vuex库_store({ initState: store.state }) //缓存一个名为initState的初始状态我们知道main.js是页面载入的时候执行一次的那么缓存的initState就是自己最开始创建store里的state状态(包含了module里的所有state);然后我们在store创建的全局写一个mutation方法这里我采用了store插件(引用方式参考 https://github.com/nbubna/store)这里我采用了lodash插件(引用方式参考 https://www.lodashjs.com/)import _ from ’lodash’import _store from ‘store2’…const store = new Vuex.Store({ state: { token: ’’ }, mutations: { resetAllState (state, payload) { if (payload instanceof Array === false) { // 验证传入的是一个数组 return } const initState = _store(‘initState’) // 取出初始值的缓存 const _initState = payload.length ? _.omit(initState, payload) : initState // 判断传入值有无数据,有数据剔除相对应的值 _.extend(state, _initState) } }, modules: { … } })这个名叫resetAllState的mutation方法里就是讲全局的state替换成我们缓存的state。这里为什么 payload 是一个数组呢?因为这就是标题所描述的可定制,如果页面内重置绝大部分状态,但需要保留其中一些状态的时候我们可以通过我们传递过来的state值来剔除相应的state,使其不被更新。当然我们也可以传入值来更新相应值,其他所有值不进行更新(这里我们就不详细说明)以上,就是我实践思考出来的方法,可能有不足的地方,欢迎大家提问、交流或提出更好的建议。谢谢 ...

January 17, 2019 · 1 min · jiezi

vue-cli中vuex IE兼容

vue-cli中使用vuex的项目 在IE中会出现页面空白 控制台报错的情况:我们只需要安装一个插件,然后在main.js中全局引入即可安装 npm install –save-dev -polyfill引入 import ‘babel-polyfill’

January 16, 2019 · 1 min · jiezi

Pro Git 学习笔记

Pro Git 学习笔记文档地址:Pro Git原文地址:PRO GIT 学习笔记1、Git起步初次运行Git前的配置用户信息git config –global user.name “your user name"git config –global user.email “your email address"文本编辑器设置默认的文本编辑器:git config –global core.editor emacs查看配置信息git config –list2、Git基础创建Git仓库在工作目录中初始化新仓库git init克隆现有仓库git clone urlurl分ssh和https两种,推荐使用ssh。检查当前文件状态git status跟踪最新文件git add 文件名或*.js/css/html…或.忽略不想提交的文件cat .gitignore查看已暂存和未暂存的更新git diffgit diff –cached提交更新git commit -m “提交备注信息"跳过使用暂存区域git commit -a “提交备注信息"在提交时使用git commit -a就会把已跟踪的已暂存文件一起提交,跳过git add步骤,即两个命令进行合并。移除文件git rm从已跟踪文件清单中移除并删除工作目录中的指定文件,先使用git status查看跟踪文件清单,再使用git rm进行精准移除。强制移除使用git rm -f,但不推荐使用。从远程仓库中删除文件,使用:git rm –cached 文件名/.文件后缀/文件夹…移动文件对文件重命名或移动文件,可以使用:git mv file_from file_to查看提交历史git loggit log -p -2-p选项展开显示每次提交的内容差异,用-2显示最近的两次更新。单词层面的对比,使用:git log -p -U1 –word-diff这个命令在代码检查中较少使用,在图文编辑中出现较多。显示摘要信息,使用:git log –stat其他有用的命令:–pretty选项可以指定使用完全不同于默认格式的方式展示提交历史,用oneline将每个提交放在一行显示,这在提交数很大时非常有用:git log –pretty=onlineformat可以定制要显示的记录格式:git log –pretty=format:"%h - %an, %ar : %s"常用的格式占位符写法及其代表的意义选项说明%H提交对象(commit)的完整哈希字串%h提交对象的简短哈希字串%T树对象(tree)的完整哈希字串%t树对象的简短哈希字串%P父对象(parent)的完整哈希字串%p父对象的简短哈希字串%an作者(author)的名字%ae作者的电子邮件地址%ad作者修订日期(可以用-date=选项定制格式)%ar作者修订日期,按多久以前的方式显示%cn提交者(committer)的名字%ce提交者的电子邮件地址%cd提交日期%cr提交日期,按多久以前的方式显示%s提交说明添加ASCII字符串表示的简单图形git log –pretty=format:"%h %s” –graphgit log 命令支持的选项选项说明-p按补丁格式显示每个更新之间的差异。–word-diff按 word diff 格式显示差异。–stat显示每次更新的文件修改统计信息。–shortstat只显示 –stat 中最后的行数修改添加移除统计。–name-only仅在提交信息后显示已修改的文件清单。–name-status显示新增、修改、删除的文件清单。–abbrev-commit仅显示 SHA-1 的前几个字符,而非所有的 40 个字符。–relative-date使用较短的相对时间显示(比如,“2 weeks ago”)。–graph显示 ASCII 图形表示的分支合并历史。–pretty使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)。–oneline–pretty=oneline –abbrev-commit 的简化用法。限制输出长度按照时间作限制的命令:–since和–untilgit log –since=2.weeks搜索条件–author 显示指定作者的提交–grep 搜索提交说明中的关键字–all-match 同时满足这两个选项搜索条件的提交其他常用的类似选项选项说明-(n)仅显示最近的 n 条提交–since, –after仅显示指定时间之后的提交。–until, –before仅显示指定时间之前的提交。–author仅显示指定作者相关的提交。–committer仅显示指定提交者相关的提交。具体示例:git log –pretty="%h - %s” –author=gitster –since=“2018-10-01” \ –before=“2008-11-01” –no-merges – t/撤消操作修改最后一次提交git commit –amend取消已经暂存的文件git reset HEAD 文件名取消对文件的修改这条命令谨慎使用git checkout – 文件名远程仓库的使用查看当前的远程库git remote显示对应的克隆地址git remote -v添加远程仓库git remote add [shortname] url抓取仓库信息git fetch [shortname]从远程仓库抓取数据此命令会从远程仓库抓取数据到本地git fetch [remote-name]抓取克隆的远程仓库的更新数据git fetch originfetch命令只是把远程仓库的数据抓取到本地,并不会自动合并到当前工作分支推荐使用的拉取远程仓库数据,并进行数据合并操作的命令git pull推送数据到远程仓库git push origin master查看远程仓库信息git remote show [remote-name]远程仓库的删除和重命名重命名远程仓库git remote renamegit remote rename vue react移除远程仓库git remote rm vue打标签显示已有的标签git tag设定条件进行搜索git tag -l “v1.4.2.“新建标签轻量级标签git tag含附注的标签git tag -agit tag -a v1.4 -m “my version 1.4"查看相应标签的版本信息git show v1.4签署标签git tag -sgit tag -s v1.5 -m “my signed 1.5 tag"验证标签git tag -v [tag-name]git tag -v v1.4.2.1后期加注标签忘记了加注标签,只要在打标签的时候跟上对应提交对象的校验和即可git tag -a v1.2 9fceb02分享标签git push origin v1.5一次推送所有本地新增标签git push origin –tags技巧和窍门自动补全windows系统下连续按Tab键Git 命令别名git config –global alias.ci commitgit config –global alias.st statusGit 分支新建testing分支git branch testing切换到testing分支git checkout testing分支的新建与合并以上两个命令进行合并git checkout -b testingGit会把工作目录的内容恢复为检出某分支时它所指向的那个提交对象的快照。它会自动添加、删除和修改文件以确保目录的内容和当时提交时完全一样。合并提交内容git mergegit checkout mastergit merge hotfix删除工作分支git branch -d hotfix分支的合并查看冲突 git status调用可视化的合并工具解决冲突git mergetool分支的管理查看各个分支最后一个提交对象的信息git branch -v查看哪些分支已被并入当前分支git branch –merged查看尚未合并的分支git branch –no-merged利用分支进行开发的工作流程长期分支特性分支远程分支同步远程服务器上数据到本地git fetch origin 推送本地分支git push origin master在远程分支上分化出新的分支:git checkout -b serverfix origin/serverfix跟踪远程分支git checkout -b sf origin/serverfix删除远程分支分支的衍合整合分支方法git mergegit rebase从一个特性分支中再分出一个特性分支的历史git rebase –onto master server clientgit checkout mastergit merge server衍合的风险一旦分支中的提交对象发布到公共仓库,就千万不要对该分支进行衍合操作。服务器上的 Git协议Git可以四种主要的传输协议进行数据传输:本地协议、SSH协议、Git协议和HTTP协议。在服务器上部署 Gitgit clone –bare my_project my_project.git把裸仓库移到服务器上未完待续… ...

January 16, 2019 · 2 min · jiezi

React框架Umi实战(3)路由进阶

前面的课程都是使用的约定路由,就是自动生成的,但是我们做项目大部分都是涉及权限控制的,这时就还是得用控制路由,仅今天就来改进一下1 修改配置.umirc.js// ref: https://umijs.org/config/export default { plugins: [ // ref: https://umijs.org/plugin/umi-plugin-react.html [‘umi-plugin-react’, { antd: true, dva: true, dva: { immer: true }, dynamicImport: false, title: ‘umis’, dll: false, hardSource: false, routes: { exclude: [ /model.(j|t)sx?$/, /service.(j|t)sx?$/, /models//, /components//, /services//, ], }, }], ], routes: [ { path: ‘/’, component: ‘../layouts’, }, { path: ‘/users’, component: ‘../layouts’, Routes: [‘src/components/Authorized’], routes: [ { path: ‘/users’, component: ‘./users’ }, ], }, { path: ‘/login’, component: ‘../layouts’, routes: [ { path: ‘/login’, component: ‘./login’ }, ], }, { path: ‘/test’, component: ‘../layouts’, routes: [ { path: ‘/test’, component: ‘./test’ }, ], }, ]}一旦使用了配置路由,那么pages下的文件将不再生成路由。component的路径是相对于src\pages的。在需要权限控制的的路由下使用Routes属性配置。2 鉴权路由组件 components\Authorizedimport React, { Component } from ‘react’import { connect } from ‘dva’;import { Router, Route, Redirect, withRouter } from ‘dva/router’;import { message } from ‘antd’;class AuthRouter extends Component { render() { const { component: Component, …rest } = this.props const isLogged = false if (!isLogged) { message.warning(‘您需要先登陆’); } return ( <Route {…rest} render={props => { return isLogged ? <Component {…props} /> : <Redirect to="/login" /> }} /> ) }}function mapStateToProps(state) { return { state }}// export default ListData;export default connect(mapStateToProps)(withRouter(AuthRouter));里面的判断可以根具你自己的业务来写,我这边是跳转到登陆页面。3 登陆页面import { connect } from ‘dva’;function Login(){ return ( <div> <h1>this is login page</h1> </div> )}function mapStateToProps(state) { console.log(state.login); return { test:‘fhf’ };}export default connect(mapStateToProps)(Login);这样你访问/users 就会重定向到登陆页面:4 总结这样简单的umi使用就结束了,在我看来重点就这么多,大部分还是dva的使用,参考我之前的dva系列学一下就好了。这些框架其实都是比较好上手,关键还是React的基础要掌握好,还有es6的语法。如果你想要直接进入开发,建议不要自己再花时间搭建框架。即使你使用了umi自己按我所写的搭建出来,也没有直接用现成的快。而且重复造轮子,并没有什么意义。建议直接使用ant-design-prohttps://github.com/ant-design…,该有的都已经帮你搭好了,如果你也想开发后台管理的系统。别忘了关注我 mike啥都想搞还有其他后端技术分享在我的公众号。 ...

January 16, 2019 · 1 min · jiezi

Travis CI + github + hexo 自动化部署

Travis CI是目前新兴的开源持续集成构建项目,采用yaml格式,简洁清新独树一帜。目前大多数的github项目都已经移入到Travis CI的构建队列中。Travis-CI会同步你在GitHub上托管的项目,每当你commit push成功之后,就可以根据配置文件进行项目的构建发布。作为一名苦逼(qiongsuan)程序员,想自己搞点什么,又苦于现在什么都收费,于是乎,有了本篇文章,满足了广大和我一样,囊中羞涩却又按耐不住一颗躁动的心的开发者们之前用hexo搭建了一个博客,挂载在自己的github上,之所以选择这两者,因为他们都是开源的(其实为了免费),也因此,github域名无法在百度等搜索引擎备案,我的博客张吉成的博客主页也是毫无访问量可言T_T。之前每次部署都是最基本的手动编译,打包,上传github,搞过一段时间的jenkins(有兴趣的朋友可以移步我的博客),由于没有自己的服务器,每次自己的电脑都要开着作为服务器,实在麻烦。后来无意间发现了Travis,功能强大且配置简单,还是免费的,简直完美,唯一的缺点是只支持github项目。本文记录了配置Travis的全过程,构建步骤为:本地开发完成,提交代码到github仓库;github收到提交的更新,通知Travis;Travis 收到github的提交通知,进行构建;hexo 的安装使用本文就不做介绍了,可以参考之前的文章hexo常用命令,hexo创建文章&文章缩略图及banner&MarkDown注册配置 Travis打开Travis CI官网,进行注册,这里就不做太多赘述,推荐用github账户注册;绑定你的github账户,此时Travis会同步你的github仓库,将你要监听的github仓库名选中,此时Travis会监听该仓库的push操作,并执行指定的脚本文件;添加 .travis.yml当我们提交代码后执行的一系列操作都是在 .travis.yml文件中配置的;language: node_js #設置語言node_js: stable #設置相應的版本cache: apt: true directories: - node_modules # 緩存不經常更改的內容install: # 执行安装操作 …script: # 开始部署 …after_script: # 部署后操作 …branches: # 配置监听的分支 only: - master #只監測master分支,master是我的博客源碼分支的名稱,可根據自己情況設置env: # 环境变量配置 global: - GH_REF: github.com//blog.git #設置GH_REF,注意更改更详细的参数配置可以参考官网如下是我的配置信息:language: node_js #設置語言node_js: stable #設置相應的版本cache: apt: true directories: - node_modules # 緩存不經常更改的內容before_install: - echo 安装hexo相关环境…install: # - npm install -g cnpm –registry=https://registry.npm.taobao.org - cnpm installbefore_script: - echo 正在清空缓存静态文件… - hexo clean # 清除缓存静态文件 - echo 正在生成静态文件… - hexo g # 生成静态文件 - cd ./public - ls -lscript: - echo 开始部署… - git init - git config –global user.name “${GH_username}” # 修改name - git config –global user.email “${GH_useremail}” # 修改email - git add ./ - git commit -m “update” - git push –force –quiet “https://${GH_TOKEN}@${GH_REF}” master:master # GH_TOKEN是在Travis中配置token的名稱after_script: - echo 部署完成!branches: only: - master # 只監測master分支,master是我的博客源碼分支的名稱,可根據自己情況設置env: global: - GH_REF: github.com/<prourl> # 设置 github 项目仓库地址 - GH_username: <yourname> # 设置 github 用户名 - GH_useremail: <youremail> # 设置 github 绑定邮箱地址生成github access Token 并 配置到 Travis此步骤是为了使travis获得对github的操作权限,如git push等生成github access Token如上图所示,登陆github并打开该页面,并新建token如上图进行对应操作,生成token,注意token只显示一次,要保存好备用。配置 access token 到 Travis打开Travis CI 找到setting页面,填写对应的token名及上面步骤生成的token值,如下图:细心的同学可能会发现我的 .travis.yml 文件中有下面这样一段配置after_script: - echo 开始部署… - cd ./public - git init - git config –global user.name “yourname” #修改name - git config –global user.email “youremail” #修改email - git add ./ - git commit -m “update” - git push –force –quiet “https://${GH_TOKEN}@${GH_REF}” master:master #GH_TOKEN是在Travis中配置token的名稱 - echo 部署完成!branches: only: - master #只監測master分支,master是我的博客源碼分支的名稱,可根據自己情況設置env: global: - GH_REF: github.com/yourname/bolg.git #設置GH_REF,注意更改yourname其中有两个变量,GH_REF是在env中配置的,而GH_TOKEN则是我们刚刚在设置中添加的github token,此时执行git push –force –quiet “https://${GH_TOKEN}@${GH_REF}” master:master命令就可以在不用输入用户名密码的情况下进行提交。测试提交代码到github中查看部署情况至此,整个部署完成,赶快自己尝试一下吧! ...

January 16, 2019 · 2 min · jiezi

自动化部署工具Syncd v1.1.0发布,提供二进制安装包

Syncd是一款开源的代码部署工具,它具有简单、高效、易用等特点,可以提高团队的工作效率。项目地址(Github) 项目地址(Gitee) 下载地址 v1.1.0 使用文档特性:Go语言开发,编译简单、运行高效Web界面访问,交互友好灵活的角色权限配置支持Git仓库分支、tag上线部署hook支持完善的上线工作流邮件通知机制更新内容安装脚本通过go env获取GOPATH #8utf8 to utf8mb4 #13支持go modules #4压缩登录背景图 #5添加服务器支持填入域名 #3解决没有添加集群的时候添加项目出错 #7提供二进制安装包

January 16, 2019 · 1 min · jiezi

从0到1开发实战手机站(二):Git提交规范配置

生活不能随意过,代码也不能随意写。前一篇文章我们已经把项目搭建好了,那是不是马上就开始写页面了呀?NO!无论在哪家公司,都会有相应的代码规范。新入职的员工往往第一步就要接受代码规范的学习。既然是实战项目,我们也得在写页面之前把相关的规范配置做好。今天我们先来看看项目中git的使用及相关规范吧。Git规范及项目配置目的统一团队Git Commit标准,便于后续代码review、版本发布、自动化生成change log;可以提供更多更有效的历史信息,方便快速预览以及配合cherry-pick快速合并代码;团队其他成员进行类git blame时可以快速明白代码用意;版本规范1.分支master: 主分支(保护分支),不能直接在master上进行修改代码和提交;develop: 测试分支,所以开发完成需要提交测试的功能合并到该分支;feature-: 新功能开发分支,根据不同需求创建独立的功能分支,开发完成后合并到develop分支;hotfix-: bug修复分支,根据实际情况对已发布的版本进行漏洞修复;release-*: 预发布分支。2.Tag采用三段式,v版本.里程碑.序号,如v1.2.3架构升级或架构重大调整,修改第1位新功能上线或者模块大的调整,修改第2位bug修复上线,修改第3位3.changelog版本正式发布后,需要生产changelog文档,便于后续问题追溯。提交规范Git commit日志基本规范每次提交,Commit message 都包括三个部分:Header,Body 和 Footer。<type>(<scope>): <subject>// 空一行<body>// 空一行<footer>注意冒号后面有空格。其中,Header 是必需的,Body 和 Footer 可以省略。Header:Header部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。type代表某次提交的类型,比如是修复一个bug还是增加一个新的feature。所有的type类型如下:feat: 新增featurefix: 修复bugdocs: 仅仅修改了文档,比如README, CHANGELOG等等style: 仅仅修改了空格、格式缩进等等,不改变代码逻辑refactor: 代码重构,没有加新功能或者修复bugperf: 优化相关,比如提升性能、体验test: 测试用例,包括单元测试、集成测试等revert: 回滚到上一个版本build: 影响构建系统或外部依赖项的更改ci: 主要目的是修改项目继续集成流程chore: 不属于以上类型的其他类型scopescope用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。subjectsubject是 commit 目的的简短描述,不超过50个字符。其他注意事项:以动词开头,使用第一人称现在时,比如change,而不是changed或changes第一个字母小写结尾不加句号(.)Body:Body 部分是对本次 commit 的详细描述,可以分成多行。需要描述的信息包括:为什么这个变更是必须的? 它可能是用来修复一个bug,增加一个feature,提升性能、可靠性、稳定性等等他如何解决这个问题? 具体描述解决问题的步骤是否存在副作用、风险?有两个注意点:使用第一人称现在时,比如使用change而不是changed或changes。永远别忘了第2行是空行Footer:如果需要的话可以添加一个链接到issue地址或者其它文档,或者关闭某个issue。项目配置既然规范已经有了,那我们就按照规范开始实战吧。首先我们新建两个分支:git branch developgit branch feature-git提交规范然后我们切换到新建的功能分支:git checkout feature-git提交规范接下来我们就来添加git提交信息效验的配置。使用commitizen来执行规范全局安装:npm install -g commitizenmac下需在前面加sudo项目目录下执行:commitizen init cz-conventional-changelog –save –save-exact配好后,之后用到git commit命令时,改为使用git cz。这时,就会出现选项,用来生成符合格式的 Commit message。好,我们把刚刚的改动提交一下吧。先把修改加入暂存git add .使用git cz 代替 git commitgit cz结果如下:生成 Change log因为我们的commit使用向导生成完全符合规范,所以发布新版本时, 可以用脚本自动生成Change log。生成的文档包括以下三个部分:New featuresBug fixesBreaking changes.每个部分都会罗列相关的 commit ,并且有指向这些 commit 的链接。当然,生成的文档允许手动修改,所以发布前,你还可以添加其他内容。conventional-changelog 就是生成 Change log 的工具.运行下面的命令即可:全局安装npm install -g conventional-changelog-cli项目目录运行conventional-changelog -p angular -i CHANGELOG.md -s -r 0这时你会发现项目目录里面多了CHANGLOG.md文件我们可以把命令放在script里面:修改package.json文件,在script中添加: “version”: “conventional-changelog -p angular -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md"我们做一次提交来试试看:git add .git commit -m “feat: 添加生成changelog功能"然后运行:npm run version之后我们看到CHANGELOG.md文件有了我们的提交日志:注意,我之前提交过一次,但是type使用的是build,所以不会在日志中体现。最后我们再把CHANGELOG.md的变化做一次提交:git commit -m “docs: 添加CHANGELOG.md文件"细心的朋友可能已经发现,这两次提交我并没有使用git cz而是为了方便直接使用了git commit -m ““这种形式,时刻记着提交信息规范的话使用这种方式也没问题,但是有时候难免失误,比如不小心把feat打成feet,那如何防止失误呢?来看看吧。使用commitlint效验提交信息首先还是安装依赖:npm install –save-dev @commitlint/{cli,config-conventional}npm install –save-dev husky@vue/cli-service 也会安装 yorkie,但yorkie fork 自 husky 且并不和之后的版本兼容。所以这里我还是安装了husky在根目录新建文件commitlint.config.jsmodule.exports = { extends: ["@commitlint/config-conventional”], rules: { “type-enum”: [ 2, “always”, [“feat”, “fix”, “docs”, “style”, “refactor”, “test”, “chore”, “revert”] ], “subject-full-stop”: [0, “never”], “subject-case”: [0, “never”] }};在package.json中添加husky配置"husky”: { “hooks”: { “commit-msg”: “commitlint -e $HUSKY_GIT_PARAMS” } }这样就配好了,现在我们来测试一下:上图可以看到,当我type输错时会报错,这样我们就不怕不小心打错自己没注意到的情况啦。修改之后成功提交。合并提交最后我们把我们今天的工作提交到github上吧git checkout developgit merge feature-git代码提交信息审查git checkout mastergit merge developgit push小结今天花了较大篇幅讲解如何为何配置GIT提交规范及如何配置,实在是小肆深知在实际工作过程中遵守规范是多么重要的一件事.尤其是团队开发或是开源项目,可以说一个程序员的代码素质从他的每一次提交记录就能体现一二,所以还望大家能重视起来。接下来几篇小肆会为大家带来代码效验、自动格式化、手机端适配、判断访问客户端类型等前期准备工作,关注我的公众号"技术放肆聊"持续关注吧!本系列文章目录:用vue-cli3从0到1做一个完整功能手机站(一)从0到1开发实战手机站(二):Git提交规范配置 ...

January 16, 2019 · 1 min · jiezi

GitBash连接GitHub

检查目录是否有SSHKEY文件cd ~/.sshls -al生成KEYssh-keygen -t rsa -C 邮箱//询问保存目录,回车//输入密码(上传不想输入密码,请直接回车)//再次输入密码将密钥添加到SSH AGENTeval ssh-agent -sssh-add ~/.ssh/id_rsa添加SSH KEY到GITHUB复制KEY到剪贴板#win10clip < ~/.ssh/id_rsa.pub#maccat ~/.ssh/id_rsa.pub | pbcopyGitHub -> Account -> SSH KEY -> ADD,粘贴,ADD KEY测试以上配置是否生效ssh -T git@github.com拉代码git clone git://github.com:用户名/项目名.git//采用这种方式,push的时候报错,提示换httpsgit clone git@github.com:用户名/项目名.git新项目关联github仓库git remote add repoName git@github.com:xxuer/xxproject.gitgit pull repoName mastergit push -u repoName master查看远程仓库urlgit remote get-url repoName

January 15, 2019 · 1 min · jiezi

有哪些鲜为人知,但是很有意思的网站?

扩展阅读有哪些鲜为人知,但是很有意思的网站?一份攻城狮笔记每天搜集 Github 上优秀的项目一些有趣的民间故事超好用的谷歌浏览器、Sublime Text、Phpstorm、油猴插件合集工具类看图识花(上传图片识别花的种类):http://stu.iplant.cn/webGridzzly(在线制作自己的网格纸):http://www.gridzzly.com/在线电子书转换器(电子书格式在线转换):http://cn.epubee.com/字体转换器(字体在线转换):http://www.akuziti.com/证件照换底色(一键换底色):https://www.bgconverter.com/OPEN GPS(高精度 IP 定位):https://www.opengps.cn/Default.aspxWindy(在线气象观测):https://www.windy.com/RAMMB(全球实时卫星云图):http://rammb-slider.cira.colostate.eduASD 商品历史价格查询(商品价格曲线):http://asd-price.com/铁路信息查询(全国铁路车站车次信息查询):https://moerail.ml/DesignCap(免费海报在线制作):https://www.designcap.com/app/在线工具箱(各种实用工具聚合):http://tool.mkblog.cn/在线工具箱(各种实用工具聚合):http://www.nicetool.net/长链接生成器:长链接生成器 v2.2图片/视频工具Photopea(网页版 PS):https://www.photopea.com/PHOTOMOSH(给图片视频加特效):https://photomosh.com/Algorithmia(AI 给黑白照片上色):https://demos.algorithmia.com/colorize-photos/Remove.bg(在线一键抠图):https://www.remove.bg/Nod to the Rhythm(让你的照片张嘴唱歌):http://nodtotherhythm.com/makeGfycat(在线制作并托管高清 GIF):https://gfycat.com/应景图(GIF 图片添加字幕水印):http://www.yingjingtu.com/index极速瘦图(图片压缩):http://www.jsysuo.com/Picdiet(图片压缩):https://www.picdiet.com/zh-cnTinyPNG(图片压缩):https://tinypng.com/Squoosh(图片压缩):https://squoosh.app/Needs More JPEG(图片超级压缩):http://needsmorejpeg.com/Waifu2x(图片在线无损放大):http://waifu2x.udp.jp/Bigjpg(图片放大):http://bigjpg.com/ILOVEIMG(在线图片编辑器):https://www.iloveimg.com视频解析网(微博,秒拍,快手,抖音):https://www.parsevideo.com/IT/AI/工具类王斌给您对对联(AI 在线对对联):https://ai.binwang.me/couplet/玄派网 (武侠生成器):http://www.xuanpai.com/Grabient(CSS 代码渐变颜色生成工具):https://www.grabient.com/多彩的颜色(图片色彩分析):https://woshizja.github.io/colorful-color/Emoji 短网址(把网址变成 Emoji 表情):https://e.mezw.com/表情符号生成器(Emoji 表情自定义创建生成):https://phlntn.com/emojibuilder/万象智能鉴黄系统(图片分析):https://cloud.tencent.com/act/event/ci_demo给小动物加光剑(趣味加工):https://giphy.com/search/lightsaber-catsLyrebird(克隆自己的声音,需登录):https://lyrebird.ai/signupWindows93(网页版 windows93 系统):http://www.windows93.net/百度镜子(百度的镜子网站):https://baidujingzi.com/bilibili 镜子(bilibili 的镜子网站)http://www.ilidilid.com/ertdfgcvb(代码特效展示):https://ertdfgcvb.xyz/Silk(互动生成艺术画):http://weavesilk.com/ASCIIFlow Infinity(可视化字符图像绘制):http://asciiflow.com/我知道你下载了什么(BT 下载内容监测):https://iknowwhatyoudownload.com/en/peer/Foxmiguel(游戏直播聚合站):http://www.foxmiguel.com/逗比拯救世界(表情包分享):http://www.bee-ji.com/装逼大全(表情包制作):https://www.zhuangbi.info/音乐/影视类穿帮网(影视剧穿帮镜头赏析):http://www.bug.cn/The Movie title stills collection(电影标题剧照集):http://annyas.com/screenshots/音乐搜索器(音乐聚合搜索下载生成外链):http://tool.mkblog.cn/music/资源帝(在线音乐聚合)http://music.ziyuandi.cn/SUKIER(冷门歌曲推荐):http://www.sukier.com/中国摇滚(中国摇滚年代史):http://www.yaogun.com/Youtube 字幕下载(字幕下载):http://downsub.com/胖鸟电影(最新影视剧蓝光下载站):http://www.pniao.com/爱追剧(电视剧电影追剧下载):http://www.aizhuiju.com/Mov电影天堂(小体积影视剧下载):https://www.dygod.net/高清 MP4ba(最新影视剧下载:复活了):http://www.mp4ba.com/RARBG(美国影视 BT 站):https://rarbgprx.org/torrents.php动漫花园资源网(动漫作品 BT 下载站):https://share.dmhy.org/爱恋动漫(动漫作品 BT 下载站):http://www.kisssub.org/迷你 MP4(最新影视剧下载):http://www.minimp4.com二次元/动漫类萌娘百科:https://zh.moegirl.org/Mainpage神奇宝贝百科:http://wiki.52poke.com/小鸡词典(互联网流行词汇百科网站):https://jikipedia.com/AnimeShot (把动画字幕用于吐槽生活):https://as2.bitinn.net/萌兔本地漫画阅读器(漫画本子在线阅读):http://wusagi.pw/猫耳 FM(二次元声站):https://www.missevan.com/Bilibili 工具箱(弹幕内容查用户名):https://biliquery.typcn.com/PaintsChainer(AI 为你的画自动上色):AI 涂色绘画文艺类时间胶囊(封存自己的记忆):http://p.timepill.net/时光邮局(给未来的自己写一封信):https://www.hi2future.com/I Remember(我记得,一个记忆碎片网站,头脑特工队):http://i-remember.fr/en/海の見える駅(能看见海的车站):https://seaside-station.com/网盘/搜索类快速创建收件夹(百度网盘匿名收件箱):http://xzc.cn/Firefox Send(临时网盘):https://send.firefox.com/Ecosia(搜索引擎,搜索使用的广告收入用于种植树木):https://www.ecosia.org/爱搜资源(百度网盘密码破解分享):https://www.aisouziyuan.com/鸠摩搜书(电子书搜索下载):https://www.jiumodiary.com/GIPHY(GIF 动图搜索网站):https://giphy.com/Similar Site Search(相似网站搜索):https://www.similarsitesearch.com/cn/文学/百科类武侠世界(歪果仁翻译中国小说):https://www.wuxiaworld.com/维基大典(国学百科):維基大典Gallerix(世界名画档案馆):https://gallerix.ru/Internet Archive(互联网档案博物馆):https://archive.org/世界护照大全(领略全球护照风采):https://www.passportindex.org/cn/中国海报(中国历年海报存档):https://chineseposters.net/美丽的化学(化学之美):https://www.beautifulchemistry.net/乡音苑(中国方言活地图):http://phonemica.net/湿在人为(两性博客):http://www.idashi.org/汉典(汉字典书):http://www.zdic.net/书格(传统书籍):https://shuge.org/古诗文网(中国传统古诗文):https://www.gushiwen.org/中少快乐阅读平台(怀旧少儿老杂志):少年儿童杂志全集实用/行政类国家邮政局申诉网站(快递问题投诉专用):http://sswz.spb.gov.cn/无人认领尸体在线查询(慎入):http://www.gzbz.com.cn/dead_men/index.asp药物临床试验登记与信息公示平台(人体实验):http://www.chinadrugtrials.org.cn/德州大学电子图书馆(人体骨骼 X 光标本):http://www.digimorph.org/index.phtml趣味/无聊类Spray.training(FPS 游戏压枪训练工具):http://spray.training/一键六学(网络梗生成器):http://bog.ac/tool/6/#今天中午吃什么?(世纪难题):https://www.zwcsm.com/你好污啊(撩妹金句):https://www.nihaowua.com/Clash(用歌声说出你想说的话,想起了《大黄蜂》):https://clash.me/Windows Update Prank(假装 Windows 升级界面):http://fakeupdate.net/字符跳跃(让你的网址动起来):http://glench.com/hash/#CLICKhappy happy hardcore(治愈小表情):https://happyhappyhardcore.com/经典 DVD(无聊网站):http://itneverhitsthecorner.com/Neave.TV(稀奇古怪的电视频道):https://neave.tv/无聊网站大全(点击进入随机无聊站):https://theuselessweb.com/声音/太空类雨季情绪(下雨的声音):https://rainymood.com/VirtOcean(海洋的声音):http://virtocean.com/Purrli(猫打呼噜的声音):https://purrli.com/这里有猫(Purrli 中文版):https://m.niucodata.com/cat/cat.php?from=wbMeteor showers(太空视角观看流星雨):https://www.meteorshowers.org/怀旧类秘密花园(中文网站考古):http://www.yini.org/Inspirograph(怀旧在线万花尺):https://nathanfriend.io/inspirograph/日本传统色(古典传统配色):http://nipponcolors.com/中国色(日本传统色的中文版):http://zhongguose.com/四大名著小说(名著地图):http://www.sdmz.net/水浒 108 将形象大全(怀旧图片):http://ls.ganquancun.com/shuihuzhuan108/游戏/测试类Am I pretty or ugly?(在线颜值分析):https://www.prettyscale.com/MyAccent(测试你的口音是英式还是美式):口音测试扫雷(网页版扫雷游戏):https://www.saolei.org/信任的进化(人性小游戏):https://www.sekai.co/trust/太鼓达人(日本经典音乐游戏网页版):https://taiko.bui.pm/一画换一画(互动绘画):http://www.sketchswap.com/Lines FRVR(划线小游戏):https://lines.frvr.com/Bad News(虚假新闻是怎样炼成的):https://getbadnews.com/#playLINE RIDER(Flash 小游戏):https://www.linerider.com/QWOP(经典小游戏):http://www.foddy.net/Athletics.htmlMikutap(鼠标音乐游戏):https://aidn.jp/mikutap/Mikutap(鼠标音乐游戏中文版):https://static.hfi.me/mikutap/it’s a(door)able(解锁小游戏):https://ncase.me/door/ScribblerToo(蜘蛛画画)Scribbler TooTexter(字符画):http://tholman.com/texter/Finding Home(音乐解压游戏):http://findingho.me/魔术键盘(解压网站):http://magickeyboard.io/Emojis & Earth Porn(寻找不动的表情):http://emojisandearthporn.com/Staggering Beauty(精神污染):http://www.staggeringbeauty.com/Pica Pic(复古手持游戏合集):http://www.pica-pic.com/在线 DOS 游戏(中文怀旧游戏):https://dos.zczc.cz/中文家用游戏博物馆(中文怀旧游戏):http://www.famicn.com/老男人游戏网(模拟器 ROM 下载网站):http://www.oldmanemu.net/Neave Interactive(互动小游戏合集):https://neave.com/Bestgames(在线小游戏网站):http://www.bestgames.com/IGCD(互联网游戏汽车数据库):http://www.igcd.net/网站之最第一个网站(世界上第一个网站):http://info.cern.ch/水滴(世界上最小的网站):http://www.guimp.com/世界最高(世界上最高的网站):https://worlds-highest-website.com/世界最长(世界上最长,增长最快的网站):http://www.worldslongestwebsite.com/世界之邮(世界上最长的邮箱):世界上最长的邮箱特别推荐福利吧(分享你的福利吧):http://fulibus.net/龙轩导航(可能是最好用的导航网站):http://ilxdh.com/抽屉新热榜(不正经的资讯社区):https://dig.chouti.com有趣网址之家(趣味小站集锦):https://youquhome.com/原文地址有哪些鲜为人知,但是很有意思的网站? ...

January 15, 2019 · 1 min · jiezi

Git 常用命令集

Git 常用命令集个人使用git的一些总结,一下常用命令的互相搭配使用,能非常完美的处理好日常遇到的99%的情况(不敢说100%,得留点余地)。 还有一些使用频率非常低的指令没有记录,至少普通开发者非常不常用,以后可能会补充。话不多说 首先需要先下载git这个还是要说一下的1. 常用命令1.1 最常用/版本对比/其他git status 查看当前分支状态 git reflog 查看每一次的命令,都做过什么 git log 查看此分支完整的提交记录,回车继续看,q停止 git log –oneline 查看此分支简略的提交记录,只展示提交号和提交信息 git show 查看最近一次提交的具体代码变化 git show <提交ID> 查看某次提交的具体代码变化 git diff 查看当前代码add后,会add哪些内容 git diff –staged 查看现在commit提交后,会提交哪些内容 git diff HEAD 查看当前代码add并提交后,会提交哪些内容 git log –oneline –graph 图形化展示合并历史1.2 初始化基本操作git init 初始化仓库,默认为mast分支 git add -A 提交全部文件修改到缓存区 git add <具体某个文件路径+全名> 提交某些文件到缓存区 git commit -m “<注释>” 提交代码到本地仓库,并写提交注释 git commit –a -m “<新注释>” 更改上次提交的注释1.3 分支操作git branch 查看本地所有分支 git branch -r 查看远程所有分支 git branch -a 查看本地和远程所有分支 git merge <分支名> 合并分支 git merge –abort 合并分支出现冲突时,取消合并,一切回到合并前的状态 git branch <新分支名> 基于当前分支,新建一个分支 git checkout –orphan <新分支名> 新建一个空分支(会保留之前分支的所有文件) git branch -D <分支名> 删除本地某个分支 git push <远程库名> :<分支名> 删除远程某个分支 git branch <新分支名称> <提交ID> 从提交历史恢复某个删掉的某个分支 git branch -m <原分支名> <新分支名> 分支更名 git checkout <分支名> 切换到本地某个分支 git checkout <远程库名>/<分支名> 切换到线上某个分支 git checkout -b <新分支名> 把基于当前分支新建分支,并切换为这个分支1.4 推拉操作(push和pull)git pull <远程仓库名> <远程分支名> 拉取远程仓库的分支与本地当前分支合并 git pull <远程仓库名> <远程分支名>:<本地分支名> 拉取远程仓库的分支与本地某个分支合并 git push <远程仓库名> <本地分支名> 推送本地某个分支到远程与其对应的分支上,远程没有则会给远程库新建分支 git push <远程仓库名> <本地分支名>:<远程分支名> 推送本地分支到远程某个分支 git push <远程仓库名> :<远程分支名> 删除远程某个分支 git push -f <同上的命令> 强制提交,覆盖线上 git fetch 获取线上最新版信息记录,不合并,用法和pull类似(一个特殊的操作,比如多人开发分支,其他人提交后,自己看分支的时候,可能还知不道线上的分支已经比自己的新了,需要这个指令,来获取一下线上的最新版本,会拉取,但不会合并,存在本地仓库中)1.5 查看具体文件版本区别(git diff)git diff <文件名> 对比最近提交,和近近次提交的区别,不加文件名,则为整体对比 git diff HEAD^ – <文件名> 同上 git diff HEAD~<一个数字> – <文件名> 上次提交和前第几次提交作对比 git diff <提交ID> <文件名> 上次提交和某次提交作对比 git diff <文件名> 工作区与暂存区比较 git diff HEAD <文件名> 工作区与最近提交比较 git diff <本地分支名> <文件名> 当前分支的文件与其他分支的文件进行比较1.6 回滚操作注意,当回滚代码时,reset和revert都可以使用,下面是两个指令的区别 reset:真实硬性回滚,目标版本后面的提交记录全部丢失了 revert:同样回滚,但实际这个回滚操作,算是一个提交,目标版本后面的提交记录也全部都有,而且会多一次提交,就是这次revert–hard的功能:不加他,文件修改会保留,都会处于add之前的状态;加上他,文件修改会被删除,丢失掉git <reset/revert> <–hard?> HEAD^ 回退到上次提交 git <reset/revert> <–hard?> <提交记录> 回退到之前的某次提交 git <reset/revert> <–hard?> <某个分支> 回退到此分支的提交状态,相当于复制分支过来 git reset <文件完整路径+完整名> 把add过的某个文件撤销到未add的状态 git reset 把add过的所有文件撤销到未add的状态 git checkout <文件完整路径+完整名> 一个还没有add的文件,撤销修改 git checkout . 还没有add的所有文件,撤销修改1.7 远程库和分支的链接操作git remote -v 查看对应的远程仓库地址 git clone <远程仓库地址链接> 克隆某个远程库,默认库名为origin git clone <远程仓库地址链接> <库名> 克隆某个远程库,并自定库名 git remote remove <远程仓库名> 和远程的某个仓库解除绑定关系 git remote add <远程仓库名> <远程仓库地址链接> 和某个远程仓库建立绑定关系 git push –set-upstream <远程仓库名> <远程分支名> 当前分支和远程某个分支建立绑定关系1.8 储藏操作(stash)经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态。 而你想转到其他分支上进行一些工作。 问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。 解决这个问题的办法就是git stash命令。git stash save <注释信息> 当前分支提交到储藏,插到储藏序列的最前面(不包括新建文件) git stash save -u <注释信息> 同上,会包括新建文件,功能更强大 git stash list 查看所有储藏中的工作 git stash drop <储藏的名称> 删除对应的某个储藏 git stash pop 取出储藏中最后存入的工作状态进行恢复,会删除储藏 git stash pop <储藏对应的数字> 取出储藏中对应的工作状态进行恢复,会删除储藏 git stash apply 取出储藏中最后存入的工作状态进行恢复,注意,不会删除储藏 git stash apply <储藏的名称> 取出储藏中对应的工作状态进行恢复,注意,不会删除储藏 git stash branch <新分支名> <储藏的名称> 从储藏中新建分支,会删除储藏 git stash clear 清空所有储藏中的工作1.9 标签操作(tag)tag 是什么,虽然整个开发过程,每个提交都对应一个提交ID,回滚也比较方便,但总有一些重大意义的提交,比如从v0.91升级到了v1.0,这个v1.0是必须要单独摘出来保存的,否则万一出现回滚事故,导致提交记录丢失呢? 虽然可以单独新建分支保存,但分支的功能并不是用来做这个的。冗余的分支在开发时也容易产生误操作。所以tag的用处就来了,他可以把某次提交后的项目,整个单独复制拎出来,命名为一个tag(可以以项目版本或打tag的时间来命名),可以写注释,存在tag列表中,与分支隔离开,除非专门命令操作,否则只要项目存在,他们就不会受到影响。同时,可以使用tag快速回滚项目、基于tag新建分支等,在项目整体的管理上非常方便。git tag 列出本仓库中所有tag列表 git tag <tag名>’ 基于最近的一次提交打tag(轻量tag,不推荐) git tag -a <tag名> -m ‘<此tag的注释>’ 基于最近的一次提交打tag git tag -a <tag名> <提交ID> -m ‘<此tag的注释>’ 基于某次提交打tag git show <tag名> 查看此tag的tag信息 git tag -d <tag名> 删除本地某个tag git push origin :refs/tags/<tag名> 删除远程仓库中的tag git push <远程仓库名> <tag名>’ 推送某个tag至某个远程库 git push <远程仓库名> –tags’ 推送所有tag至某个远程库 git checkout -b <新分支名> <tag名>’ 基于某个tag新建分支2. .gitignore文件在使用Git的过程中,有的文件比如日志、临时文件、编译的中间文件等不要提交到代码仓库,这时就要设置相应的忽略规则,来忽略这些文件的提交。没错就是.gitignore文件了。此文件需要放在.git(默认是隐藏文件,是git的本地仓库)同一目录下写法如下:node_modules/dist/.mapnpm-debug.logyarn-debug.logyarn-error.log这样,当git add的时候,上面定义忽略的那些文件,就会被git忽略,发生了变化git也不会管。然而有时候,是会出现意外的。比如,git已经提交过了,这是后突然说,这里面有个文件需要被忽略,然后我把这个文件写到了.gitignore文件中。。。无效!这个文件仍然没有被忽略!这是就需要如下命令,来删除此文件并忽略git rm -r –cached <文件路径+文件全名> 在git库中删除文件并停止追踪,但实际文件还保留,只是忽略掉。由此,方可。3. 生成SSH公钥绑定一个远程仓库,有两种方式:使用http链接的方式使用ssh加密链接的方式如果远程仓库为公开仓库,则两者在使用上,区别不大; 但如果是私密仓库,则http方式,需要输入用户名和密码登录后,才可建立联系,但这样一来,需要把私密仓库的账号和密码暴露,即使添加了项目团队成员,如果成员的账号密码暴露,任何人在任何设备上,登录账号密码,至少都能对项目进行拉取操作,所以就有了下面更合适的方式—ssh。ssh的话,则只需要本地设备,输入一条git指令,生成一对公钥和私钥,然后把公钥的内容,复制添加到远程库的设置中,让远程库认识此设备,就想当于用户填写了账号和密码,好处是,这种方法在远程库的添加上,只认设备不认账户,这样只用保证设备是安全的,仓库就是安全的。下面为本地设备生成ssh输入ssh-keygen来生成ssh window默认存放在C盘/用户/<用户名称>/.ssh文件夹中 Mac默认存放在硬盘/用户/<用户名称>/.ssh文件夹中 其中两个文件,id_rsa.pub为公钥,需要打开复制其中的内容,粘贴到需要的网站中(另一个为私钥,切记保管好)4. 设置用户名、邮箱、登录账户git config user.name 查看设置的用户名 git config user.email 查看设置的用户邮箱 git config –global user.name <用户名> 设置用户名 git config –global user.email <邮箱> 设置用户邮箱 修改用户登录信息window控制面板 -> 用户账户 -> 管理 Windows 凭据,即可看到普通凭据中有git的账户信息,可编辑更改Mac钥匙串访问.app -> 右上角搜索git,即可看到,可编辑更改 ...

January 14, 2019 · 2 min · jiezi

在VS Code中使用Git进行版本管理及文件上传到Github

GitHub是一个面向开源及私有软件项目的托管平台,只支持git作为唯一的版本库格式进行托管,相信每一个学习前端的人对git和GitHub都不陌生,但是对于刚刚接触前端的人来说,看到这些会觉得很陌生,我刚刚接触的时候就是这样。我在这里详细的说明一下git和GitHub的一些基本使用方法。在进行git命令前我们需要安装git.exe,这个直接到网上搜一下,下载安装就可以了。1.首先,我们需要注册GitHub账号,然后登陆。2.进入GitHub后,我们需要新建一个库,点击New repository,进入之后页面如下在Repository name中对自己的库进行命名,Description处为对此库的描述,可以填也可以不填。3.下面的Public表示公共,Private表示私人,但是选择Private是要花钱的,可能需要绑定银行卡等操作,如果你的代码不需要保密,在这里我们选择Public即可。4.下图中蓝色线画的可以选择也可以不选择,在这里我们选择上,会自动生成一个README文件。5.打开在桌面或其他位置新建一个文件夹,打开VS Code,用VS Code打开刚才建的文件夹,新建自己想要建的文件并保存。6.在VS Code菜单栏中点击终端,并选择新建终端。7.在终端中输入git init对终端中的文件夹进行初始化。8.输入git status查看文件夹中文件的状态。发现文件夹中有两个文件,文件名称为红色。9.输入git add first.html second.wxml将文件夹的文件添加到库中。再次输入git status查看文件的状态这时发现文件名的颜色为绿色,说明已经将文件添加到了库中。10.输入git commit -m ‘second’,此处引号内的名称可以为任意。11.由于第一次使用git,在上一步中会报错,这时我们只需输入git config –global user.name ‘GitHub账户名’运行后再输入git config –global user.email ‘注册GitHub时的邮箱’即可。12.再次输入git status查看文件状态,发现工作树为空,则说明上述操作成功。13.输入git branch查看目前文件所在的分支为master14.以上为git的一些基本操作,下面讲述如何将文件远程提交到GitHub,打开自己刚刚在GitHub上新建的库,点击Clone or download,再点击右侧带箭头的文件图标,将地址复制下来。15.在VS Code中继续输入git remote add origin https://github.com/yhlp/display.git,最后的地址为刚刚在GitHub上复制的地址。16.输入git push -u origin master,运行后我们会发现报错这是因为没有将库中的README.md文件下载下来,这时我们只需输入git pull –rebase origin master,执行结束后我们会发现左侧文件夹中多了一个文件这时我们再执行git push -u origin master,执行结束后文件就已经成功提交到GitHub。到GitHub上查看,发现文件已经成功提交。17.以上为git的一些基本操作及将代码远程提交到GitHub的操作,上述代码也可以在安装好的git bash中进行,Windows系统安装好git.exe后,只需在桌面空白处右键便能看到git bash。

January 13, 2019 · 1 min · jiezi

git解决pre -commit hook failed (add --no-verify to bypass)的问题

在同步本地项目到github是出现这个错误:pre -commit hook failed (add –no-verify to bypass)pre-commit钩子惹的祸当你在终端输入git commit -m “xxx”,提交代码的时候,pre-commit(客户端)钩子,它会在Git键入提交信息前运行做代码风格检查。如果代码不符合相应规则,则报错。2. ‘弱鸡’的解决方案为了省点事,我并没有花功夫去查找代码哪里不符合规范.我是暴力地把pre-commit钩子给删除了!具体步骤:进入项目的.git文件夹(文件夹默认隐藏,可先设置显示或者命令ls查找)再进入hooks文件夹删除pre-commit文件重新git commit -m ‘xxx’ git push即可。SourceTree也可以正常推送总结一句话: 删除.git的提交规则文件: rm -rf ./git/hooks/pre-commit文章转自:https://www.cnblogs.com/soyxi…

January 13, 2019 · 1 min · jiezi

Syncd - 自动化部署工具

syncd是一款开源的代码部署工具,它具有简单、高效、易用等特点,可以提高团队的工作效率.目录特性原理安装使用帮助授权特性Go语言开发,编译简单、运行高效Web界面访问,交互友好灵活的角色权限配置支持Git仓库分支、tag上线部署hook支持完善的上线工作流邮件通知机制原理GitSyncd服务通过git-ssh(或password)方式从仓库中拉取指定tag(分支)代码构建运行配置好的构建脚本, 编译成可上线的软件包在这一环节中,可运行单元测试 (例如 go test php phpunit, 下载依赖 (如 go: glide install php: composer install), 编译软件包 (如 js: npm build go: go build xx.go java: javac xx.java c: cc xx.c) 等.分发通过 scp 命令分发软件包到各机房生产服务器的临时目录, 远程执行 pre-deploy 配置的命令, 执行完毕后解压缩软件包到目标目录,然后执行 post-deploy 命令分发上线过程是串行执行,并且任意步骤执行失败整个上线单会终止上线并将状态置为上线失败,需要点击 再次上线 重试.将来会支持同一集群服务器并行执行, 集群之间串行发布的特性SSH信任生产服务器与部署服务器之间通过ssh-key建立信任配置方法请参考 秘钥配置 章节安装准备工作Go推荐Go1.10以上版本, 用来编译源代码NginxWeb服务依赖NginxMySQL系统依赖Mysql存储持久化数据, 推荐版本 Mysql 5.7Linux + Bash系统会使用到 git, ssh, scp 等命令,所以目前只推荐在Linux上使用, 并且需要提前安装或更新这些命令道最新版本秘钥配置由于部署服务器(Syncd服务所在的服务器)与生产服务器(代码部署目标机)之间通过ssh协议通信,所以需要将部署机的公钥 (一般在这里: /.ssh/id_rsa.pub)加入到生产机的信任列表中(一般在这里 /.ssh/authorized_keys)可使用 ssh-copy-id 命令添加,或手动拷贝. 拷贝后不要忘记进行测试连通性 ssh {生产机用户名}@{生产机地址} 最后建议将以下配置加入到部署服务器ssh配置/etc/ssh/ssh_config中,关闭公钥摘要的显示提示,防止后台脚本运行失败Host * StrictHostKeyChecking no请注意: ssh目录权限需按此设置,否则会出现无法免密登录的情况/.ssh 0700/.ssh/authorized_keys 0600安装运行以下命令curl https://raw.githubusercontent.com/dreamans/syncd/master/install.sh |bash当前路径中若生成 syncd-deploy 或者 syncd-deploy-xxx 目录则表明安装成功生成的 syncd-deploy 目录可拷贝或移动到你想要的地方,但不要试图将此目录拷贝到其他服务器上运行,会造成不可预料的结果.数据库依赖你需要将 github.com/dreamans/syncd/syncd.sql 数据表结构和数据导入到MySQL数据库中修改配置文件修改 syncd-deploy/etc/syncd.ini 中相关配置信息, 具体配置描述可参考注释启动服务cd syncd-deploy➜ syncd-deploy ./bin/syncd -c ./etc/syncd.ini __ _____ __ __ ____ _____ / / / / / / / / / __ \ / / / __ / ( ) / // / / / / / / / / // /// _, / // // ___/ _,/ /___/Service: syncdVersion: 1.0.0Config Loaded: ./etc/syncd.iniLog: stdoutDatabase: 127.0.0.1Mail Enable: 0HTTP Service: :8868Start Running…添加Nginx配置upstream syncdServer { server 127.0.0.1:8868 weight=1;}server { listen 80; server_name deploy.syncd.cc; # 此处替换成你的真实域名 access_log logs/deploy.syncd.cc.log; location / { try_files $uri $uri/ /index.html; root /path/syncd-deploy/public; # 此处/path请替换成真实路径 index index.html index.htm; } location ^~ /api/ { proxy_pass http://syncdServer; proxy_set_header X-Forwarded-Host $host:$server_port; proxy_set_header X-Real-IP $remote_addr; proxy_set_header Origin $host:$server_port; proxy_set_header Referer $host:$server_port; }}重启nginx服务修改hosts若域名未解析,可修改hosts进行临时解析sudo vim /etc/hosts127.0.0.1 deploy.syncd.cc;安装完成打开浏览器,访问 http://deploy.syncd.cc初始账号:用户名: syncd邮箱: syncd@syncd.cc密码: syncd.cc!!!登录后请尽快修改密码使用系统使用流程图使用截图 帮助遇到问题请提 issue或者加微信进讨论群授权本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 LICENSE 文件中 ...

January 12, 2019 · 1 min · jiezi

GIT - 关于文件处理

大家平时在使用GIT的时候,尤其是在Windows平台的时候,一般都不会特别留意跟文件相关的一些问题,比如说 文件权限,大小写问题。这篇文章将给大家介绍在GIT使用中,关于文件处理的两个问题文件权限正常情况下,我们都不用太在乎,甚至不用理会GIT里面文件的权限是否可读,可写,可执行。但如果我们加进GIT的文件是一个可执行的文件,比如一个方便快捷部署的文件deploy.sh. 那么如果没有可执行权限的话,在Linux系统下面是无法执行的。当我们新建一个deploy.sh文件,加到GIT里面,我们通过git ls-files -s可以看到文件是权限是644D:\workspace\blog\demo (master -> origin) git ls-files -s100644 d37be9ba5c2dc1491460e7ce7d0bfdc1c4de6613 0 deploy.sh这样的话,我们在Linux就不能直接执行这个deploy.sh的文件(当然我们可以在Linux强制修改文件的权限,但会导致后续的代码更新出错). 这时我们可以用git update-index –chmod=+x YOUR_FILE的命令,来修改文件的权限D:\workspace\blog\demo (master -> origin) git update-index –chmod=+x deploy.shD:\workspace\blog\demo (master -> origin) git ls-files -s100755 d37be9ba5c2dc1491460e7ce7d0bfdc1c4de6613 0 deploy.shD:\workspace\blog\demo (master -> origin)这时大家就可以提交代码了,Linux环境下就可以执行这个deploy.sh文件了Windows系统下文件名大小写重命名如果大家的开发环境时Windows,而实际部署的环境时Linux的话,就有可能会遇到这个问题:你一开始给某个文件夹起名为 demofolder,里面有个文件httpUtil.js提供get的方法。 过几天大家一起codereview的时候,这个名字被大家吐槽要用驼峰,所以你回来之后就想着给这个名字重命名为demoFolder, 中间的==F==变大写。 于是你就在Windows的目录中,把文件夹名字改名为demoFolder, 然后就准备提交代码。 结果发现git status没有任何代码变更,commit不了!这是怎么回事呢?这是因为GIT默认忽略大小写,git config core.ignorecase 这个值默认为trueD:\workspace\blog\gitdou (master -> origin) (gitdou@0.1.0) git config core.ignorecasetrue我们可以简单地通过git config core.ignorecase false命令把忽略大小写关掉。但是二牛不建议这样做,尤其是在Windows环境下,容易遇到合并分支时由于大小写问题而出现冲突。 建议采用重命名的方式来实现改名。 GIT有个mv的命令来实现文件的重命名. 比如把demofolder改成demoFolder1, 我们可以用git mv demoFolder demoFolder1来实现。但是不能只是改为大小写D:\workspace\build_your_own_x\gitdou (master -> origin) (gitdou@0.1.0) git mv demoFolder demofolderRename from ‘demoFolder’ to ‘demofolder/demoFolder’ failed. Should I try again? (y/n) n原因前面已经说了,GIT默认是忽略大小写的。所以我们可以来个曲线救国,先rename成其它名字,再改回来就可以了D:\workspace\build_your_own_x\gitdou (master -> origin) (gitdou@0.1.0) dir Volume in drive D is DATA Volume Serial Number is 086F-F062 Directory of D:\workspace\build_your_own_x\gitdou01/10/2019 05:34 PM <DIR> .01/10/2019 05:34 PM <DIR> ..06/28/2018 04:41 PM 66 .gitattributes07/18/2018 08:20 AM 935 .gitignore01/10/2019 03:25 PM <DIR> demofolder06/28/2018 04:41 PM 1,070 LICENSE06/29/2018 09:19 AM <DIR> node_modules06/29/2018 10:04 AM 561 package.json06/28/2018 04:57 PM 102 README.md01/10/2019 03:29 PM <DIR> src06/29/2018 10:03 AM <DIR> test 5 File(s) 2,734 bytes 6 Dir(s) 12,081,958,912 bytes freeD:\workspace\build_your_own_x\gitdou (master -> origin) (gitdou@0.1.0) git mv demofolder demoFolder1D:\workspace\build_your_own_x\gitdou (master -> origin) (gitdou@0.1.0) git mv demoFolder1 demoFolderD:\workspace\build_your_own_x\gitdou (master -> origin) (gitdou@0.1.0) git statusOn branch masterYour branch is ahead of ‘origin/master’ by 1 commit. (use “git push” to publish your local commits)Changes to be committed: (use “git reset HEAD <file>…” to unstage) renamed: demofolder/httpUtil.js -> demoFolder/httpUtil.js以上就是关于GIT文件操作的两个问题以及对应的解决方案,希望能在你需要的时候提供一点思路! ...

January 11, 2019 · 1 min · jiezi

git回滚错误合并的分支

场景线上分支:master你开发的分支:dev1同时开发的分支:dev2dev1分支开发的代码已经上线,并且已经merge到master同时dev2分支也已上线,并且已经merge到master这时发现dev1的巨大bug,线上版本要把这个分支的代码全部移除。想要达到的效果我们要撤销所有dev1的合并,并且保留dev2的代码。同时本地dev1的分支不想删除这些代码,还有在这基础上开发。master分支如果使用reset,那么线上的几个提交记录都不会保留,达不到我们想要的效果。这里使用git revert。首先我们要撤销所有dev1的更改,找到dev1的两次commit idgit revert 63db9b1228c9e38a015513f834a42fa55002fca8git revert a407174c5df3e47e1866663e4c3fe611419eb5a8此时master已经达到我们想要的效果:开发分支这时回到我们的dev1分支,修复bug,我还要保留以前提交的代码。但是在上线前总要先merge master,但是master的两次revert是领先你的,一旦merge后你的代码就没有了。下面是当前dev1的提交情况所以我们要在merge master后,再使用revert撤销这次merge。但是这时你发现,在merge完master之后你又在这个分支提交了新代码,这时revert就会报错:git revert ce479b597de6025da4a67ddd4a94d1b8034d8c67error: commit ce479b597de6025da4a67ddd4a94d1b8034d8c67 is a merge but no -m option was given.fatal: revert failed这是因为撤销的是一次合并,git不知道要保存这两个分支中哪个的修改。-m 1 表示保留当前分支的更改-m 2 表示保留master更改我们目的是为了保留dev1的代码,所以要保留当前代码,即使用 -m 1git revert -m 1ce479b597de6025da4a67ddd4a94d1b8034d8c67[dev1 bb363fa] Revert “Merge branch ‘master’ into dev1” 2 files changed, 0 insertions(+), 0 deletions(-) rename dev2 add => b (100%) create mode 100644 c执行完上面的代码,我们就会发现,代码又回来了,和master没有回滚前的代码一样。修完bug,再把当前代码合并到master,然后你就会发现,dev2提交的代码被你的merge干掉了???这是因为你的那次rever合并采用了你的分支代码,但是你的dev1分支并没有dev2的代码…所以我们应该在master回滚前,回到dev1分支,先merge一次最新代码,再执行后面的操作。总结总结起来流程很简单。1.保持你要开发的分支同步了master最新代码。2.revert所有该分支的提交。3.回到你的分支merge master。4.revert merge master的那次提交。

January 11, 2019 · 1 min · jiezi

Git的使用

Git工具的使用1、登录码云后,点击个人中心左侧仓库 > 选择Private > 点击+ 创建2、进入到项目信息填写页面填写好:仓库名称 、 仓库介绍 、 是否开源(看个人原则)、 选择好语言、 添加.gitignore 点击“创建”3、码云上就有了存储仓库4、本地和线上代码做好关联将git工具从官网下载,安装到本地,下一步下一步傻瓜安装就可以。安装完成后在本地测试是否安装成功。 git –version5、生成公钥点击头像,选择设置 > SSH公钥 如何生成公钥https://gitee.com/help/articl…PS:这些指令是linux系统,在windows系统,需要在桌面右击,出现的列表中,选择“Git Bash Here”。执行指令。【注意安装好git后才可以用】6、将项目克复制值到本地点击‘克隆/下载’ > 选择SSH > 复制一定要SSH在项目所在文件下右击‘git bash here’ 执行命令 git clone 把线上代码克隆到本地。git clone git@gitee.com:webmx/xyuanclothes.git7、在本地文件夹中创建VUE项目。

January 11, 2019 · 1 min · jiezi

Git 使用总结 思维导图版

git三个区在初始化git版本库之后会生成一个隐藏的文件 .git,可以将该文件理解为git的版本(repository),而我们自己建立的项目文件夹即工作区(working directory),在.git文件夹里面还有很多文件,其中index文件就是暂存区(stage),同事git还生成了一个分支master以及指向该分支的指针head。例如我们打开开发环境如idea,里面的内容即工作区的内容,在工作区里面有的代码以及配置文件等我们需要提交到版本库里面,最终是到了分支master上面,暂存区只是一个临时保存修改文件的地方。工作区工作区(Working Directory) 是我们直接编辑的地方。暂存区(Stage/Index)数据暂时存放的区域,可在工作区和版本库之间进行数据的友好交流。暂存区只是一个简单的索引文件。暂存区这个索引文件里面包含的是文件的目录树,像一个虚拟的工作区,在这个虚拟工作区的目录树中,记录了文件名、文件的时间戳、文件长度、文件类型以及最重要的SHA-1值,文件的内容并没有存储在其中,所以说 它像一个虚拟的工作区。索引指向的是.git/objects下的文件。暂存区的作用:除非是绕过暂存区直接提交,否则Git想把修改提交上去,就必须将修改存入暂存区最后才能commit。每次提交的是暂存区所对应的文件快照。版本库(commit History)存放已经提交的数据,push的时候,就是把这个区的数据 push到远程仓库了。 #比较的是工作区和暂存区的差别 git diff #比较的是暂存区和版本库的差别 git diff –cached #可以查看工作区和版本库的差别 git diff HEAD 常用概念和命令整理于processon

January 10, 2019 · 1 min · jiezi

Android开发音视频应用之构建媒体浏览器服务

构建媒体浏览器服务您的应用必须MediaBrowserService在其清单中声明带有intent-filter。您可以选择自己的服务名称; 在以下示例中,它是“MediaPlaybackService”。<service android:name=".MediaPlaybackService"> <intent-filter> <action android:name=“android.media.browse.MediaBrowserService” /> </intent-filter></service>注意:推荐的实现MediaBrowserService 是MediaBrowserServiceCompat。这是在media-compat支持库中定义的 。在整个页面中,术语“MediaBrowserService”指的是of的一个实例MediaBrowserServiceCompat。初始化媒体会话当服务收到onCreate()生命周期回调方法时,它应该执行以下步骤:创建并初始化媒体会话设置媒体会话回调设置媒体会话令牌onCreate()下面的代码演示了以下步骤:public class MediaPlaybackService extends MediaBrowserServiceCompat { private static final String MY_MEDIA_ROOT_ID = “media_root_id”; private static final String MY_EMPTY_MEDIA_ROOT_ID = “empty_root_id”; private MediaSessionCompat mMediaSession; private PlaybackStateCompat.Builder mStateBuilder; @Override public void onCreate() { super.onCreate(); // Create a MediaSessionCompat mMediaSession = new MediaSessionCompat(context, LOG_TAG); // Enable callbacks from MediaButtons and TransportControls mMediaSession.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); // Set an initial PlaybackState with ACTION_PLAY, so media buttons can start the player mStateBuilder = new PlaybackStateCompat.Builder() .setActions( PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PLAY_PAUSE); mMediaSession.setPlaybackState(mStateBuilder.build()); // MySessionCallback() has methods that handle callbacks from a media controller mMediaSession.setCallback(new MySessionCallback()); // Set the session’s token so that client activities can communicate with it. setSessionToken(mMediaSession.getSessionToken()); }}管理客户连接MediaBrowserService有两种处理客户端连接的方法: onGetRoot()控制对服务的访问,并 onLoadChildren() 为客户端提供构建和显示MediaBrowserService内容层次结构菜单的能力。使用控制客户端连接 onGetRoot()该onGetRoot()方法返回内容层次结构的根节点。如果方法返回null,则拒绝连接。要允许客户端连接到您的服务并浏览其媒体内容,onGetRoot()必须返回一个非空的BrowserRoot,它是一个表示您的内容层次结构的根ID。要允许客户端在不浏览的情况下连接到MediaSession,onGetRoot()仍必须返回非null的BrowserRoot,但根ID应表示空的内容层次结构。典型的实现onGetRoot()可能如下所示:@Overridepublic BrowserRoot onGetRoot(String clientPackageName, int clientUid, Bundle rootHints) { // (Optional) Control the level of access for the specified package name. // You’ll need to write your own logic to do this. if (allowBrowsing(clientPackageName, clientUid)) { // Returns a root ID that clients can use with onLoadChildren() to retrieve // the content hierarchy. return new BrowserRoot(MY_MEDIA_ROOT_ID, null); } else { // Clients can connect, but this BrowserRoot is an empty hierachy // so onLoadChildren returns nothing. This disables the ability to browse for content. return new BrowserRoot(MY_EMPTY_MEDIA_ROOT_ID, null); }}在某些情况下,您可能希望实施白/黑名单方案来控制连接。有关白名单的示例,请参阅通用Android音乐播放器示例应用程序中的PackageValidator类。注意:您应该考虑提供不同的内容层次结构,具体取决于进行查询的客户端类型。特别是,Android Auto会限制用户与音频应用的互动方式。有关更多信息,请参阅为自动播放音频。您可以查看clientPackageName连接时间以确定客户端类型,并BrowserRoot根据客户端(或者rootHints 如果有)返回不同的客户端类型。与内容沟通内容 onLoadChildren()在客户端连接之后,它可以通过重复调用MediaBrowserCompat.subscribe()来构建UI的本地表示来遍历内容层次结构。该subscribe()方法将回调发送onLoadChildren()到服务,该服务返回MediaBrowser.MediaItem对象列表。每个MediaItem都有一个唯一的ID字符串,它是一个不透明的标记。当客户想要打开子菜单或播放项目时,它会传递ID。您的服务负责将ID与相应的菜单节点或内容项相关联。一个简单的实现onLoadChildren()可能如下所示:@Overridepublic void onLoadChildren(final String parentMediaId, final Result<List<MediaItem>> result) { // Browsing not allowed if (TextUtils.equals(MY_EMPTY_MEDIA_ROOT_ID, parentMediaId)) { result.sendResult(null); return; } // Assume for example that the music catalog is already loaded/cached. List<MediaItem> mediaItems = new ArrayList<>(); // Check if this is the root menu: if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) { // Build the MediaItem objects for the top level, // and put them in the mediaItems list… } else { // Examine the passed parentMediaId to see which submenu we’re at, // and put the children of that menu in the mediaItems list… } result.sendResult(mediaItems);}注意:MediaItem MediaBrowserService传递的对象不应包含图标位图。使用Uri的,而不是调用 setIconUri() 在生成MediaDescription的每个项目有关如何实施的示例onLoadChildren(),请参阅MediaBrowserService和Universal Android Music Player示例应用程序。媒体浏览器服务生命周期Android 服务的行为取决于它是启动还是绑定到一个或多个客户端。创建服务后,可以启动,绑定或同时启用它。在所有这些状态中,它功能齐全,可以执行其设计的工作。不同之处在于服务存在多长时间。绑定的服务在其所有绑定的客户端解除绑定之前不会被销毁。可以显式停止和销毁已启动的服务(假设它不再绑定到任何客户端)。当MediaBrowser另一个活动中的运行连接到a时MediaBrowserService,它会将活动绑定到服务,从而使服务绑定(但不启动)。此默认行为内置于MediaBrowserServiceCompat类中。只有绑定(并且未启动)的服务在其所有客户端解除绑定时销毁。如果此时UI活动断开连接,则服务将被销毁。如果您还没有播放任何音乐,这不是问题。但是,当播放开始时,用户可能希望即使在切换应用后也能继续收听。当您取消绑定UI以使用其他应用程序时,您不希望销毁播放器。因此,您需要确保在通过调用开始播放服务时启动该服务startService()。无论是否绑定,必须明确停止已启动的服务。这可确保即使控制UI活动解除绑定,您的播放器也会继续执行。要停止已启动的服务,请致电Context.stopService()或stopSelf()。系统会尽快停止并销毁服务。但是,如果一个或多个客户端仍然绑定到该服务,则停止该服务的调用将延迟,直到其所有客户端解除绑定。它的生命周期MediaBrowserService由创建方式,绑定到它的客户端数量以及从媒体会话回调接收的调用控制。总结一下:该服务在响应媒体按钮或活动绑定到它(通过其连接后MediaBrowser)启动时创建。媒体会话onPlay()回调应包括调用的代码startService()。这可确保服务启动并继续运行,即使MediaBrowser绑定到它的所有UI 活动都解除绑定。该onStop()回调应该调用stopSelf()。如果服务已启动,则会停止该服务。此外,如果没有绑定的活动,服务将被销毁。否则,服务将保持绑定,直到其所有活动解除绑定。(如果startService()在销毁服务之前收到后续呼叫,则取消挂起停止。)以下流程图演示了如何管理服务的生命周期。变量计数器跟踪绑定客户端的数量:将MediaStyle通知与前台服务一起使用当服务正在播放时,它应该在前台运行。这使系统知道服务正在执行有用的功能,如果系统内存不足,则不应该被杀死。前台服务必须显示通知,以便用户知道它并可以选择控制它。该onPlay()回调应该把服务的前景。(请注意,这是“前景”的特殊含义。虽然Android在前台考虑服务以进行流程管理,但是对于用户,播放器正在后台播放,而其他应用程序在“前景”中可见屏幕。)当服务在前台运行时,它必须显示通知,理想情况下是一个或多个传输控件。通知还应包括会话元数据中的有用信息。在播放器开始播放时构建并显示通知。这样做的最佳位置是MediaSessionCompat.Callback.onPlay()方法内部。以下示例使用 NotificationCompat.MediaStyle专为媒体应用设计的。它显示了如何构建显示元数据和传输控件的通知。便捷方法 getController() 允许您直接从媒体会话创建媒体控制器。// Given a media session and its context (usually the component containing the session)// Create a NotificationCompat.Builder// Get the session’s metadataMediaControllerCompat controller = mediaSession.getController();MediaMetadataCompat mediaMetadata = controller.getMetadata();MediaDescriptionCompat description = mediaMetadata.getDescription();NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId);builder // Add the metadata for the currently playing track .setContentTitle(description.getTitle()) .setContentText(description.getSubtitle()) .setSubText(description.getDescription()) .setLargeIcon(description.getIconBitmap()) // Enable launching the player by clicking the notification .setContentIntent(controller.getSessionActivity()) // Stop the service when the notification is swiped away .setDeleteIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_STOP)) // Make the transport controls visible on the lockscreen .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) // Add an app icon and set its accent color // Be careful about the color .setSmallIcon(R.drawable.notification_icon) .setColor(ContextCompat.getColor(context, R.color.primaryDark)) // Add a pause button .addAction(new NotificationCompat.Action( R.drawable.pause, getString(R.string.pause), MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_PLAY_PAUSE))) // Take advantage of MediaStyle features .setStyle(new MediaStyle() .setMediaSession(mediaSession.getSessionToken()) .setShowActionsInCompactView(0) // Add a cancel button .setShowCancelButton(true) .setCancelButtonIntent(MediaButtonReceiver.buildMediaButtonPendingIntent(context, PlaybackStateCompat.ACTION_STOP)));// Display the notification and place the service in the foregroundstartForeground(id, builder.build());使用MediaStyle通知时,请注意这些NotificationCompat设置的行为:使用时 setContentIntent(),您的服务会在单击通知时自动启动,这是一个方便的功能。在像锁屏这样的“不受信任”情况下,通知内容的默认可见性是 VISIBILITY_PRIVATE 。您可能希望在锁屏上看到传输控件,这样 VISIBILITY_PUBLIC 就可以了。设置背景颜色时要小心。在Android 5.0或更高版本的普通通知中,颜色仅应用于小应用程序图标的背景。但对于Android 7.0之前的MediaStyle通知,颜色用于整个通知背景。测试你的背景颜色。温柔的眼睛,避免极其明亮或荧光的颜色。用于 setMediaSession() 将通知与您的会话相关联。这允许第三方应用和配套设备访问和控制会话。用于 setMediaSession() 将通知与您的会话相关联。这允许第三方应用和配套设备访问和控制会话。用于 setShowActionsInCompactView() 在通知的标准大小的contentView中添加最多3个操作。(此处指定了暂停按钮。)在Android 5.0(API级别21)及更高版本中,一旦服务不再在前台运行,您可以滑动通知以停止播放器。您不能在早期版本中执行此操作。要允许用户在Android 5.0(API级别21)之前删除通知并停止播放,您可以通过调用 setShowCancelButton(true) 和在通知的右上角添加取消按钮 setCancelButtonIntent() 。添加暂停和取消按钮时,您需要PendingIntent附加到播放操作。该方法 MediaButtonReceiver.buildMediaButtonPendingIntent() 执行将PlaybackState操作转换为PendingIntent的工作。总结写的一般,欢迎留言、私信指出问题与不足之处!如回复不及时可加入Android技术交流群:150923287 一起学习探讨Android开发技术! ...

January 9, 2019 · 3 min · jiezi

作为软件工程师,如何进行知识管理

简评:对学到的知识进行整理归纳有助于温故而知新(以下我均指原作者 Bruno Paz)软件开发和技术总的来说是一个快速发展且需要持续学习的领域。在 Twitter、Medium、RSS feeds、Hacker News 等专业网站和社区上浏览几分钟,就足以从论文、案例研究、教程、代码片段、新应用程序等内容中找到大量的有用信息。收集和整理所有这些信息可能是一项艰巨的任务。在这篇文章中,我将介绍一些我进行知识管理的工具。我认为对知识管理非常重要的一点是避免局限在特定平台。我使用的所有工具都允许以标准格式(如 Markdown 和 HTML)导出数据。请注意,我的工作流程并不完美,我一直在寻找新的工具和方法来优化它。每个人的情况都是不同的,所以对我有用的东西不一定适合你。基于 NotionHQ 的知识库对我来说,知识管理的基础部分是建立某种个人知识库/维基,一个你可以系统地保存链接,书签,笔记等信息的地方。我用的工具是 NotionHQ 。我用它来记录各种主题,列了一些资源表,如用编程语言分组的优秀库或教程,为有趣的博客和教程添加书签等等,除了软件开发相关的知识,我还用它记录个人生活。我最喜欢 Notion 的地方是用它创建新内容非常的简单。你可以用 Markdown 格式编写,并将内容组织为树状结构。这是我的“开发”工作区的顶层页面:Notion 还有其他一些很好的特性,比如集成电子表格/数据库和任务板。由于免费功能有限,如果你想深度使用 Notion,就需要购买个人付费版,我认为它物有所值。Notion 允许将整个工作区导出到 Markdown 文件。导出存在一些重要问题,比如丢失页面层次结构,希望 Notion 团队可以改进这一点。如果要用免费的工具,我可能会选择使用 VuePress 或 GitBook。用 Pocket 保存有趣的文章Pocket 是我最喜欢的应用程序之一!使用 Pocket,你可以创建 Internet 上的文章阅读列表。每当我看到一篇有点意思的文章,我都会用 Pocket 的 Chrome 扩展将文章保存到 Pocket,等之后我从头阅读完,发现它足够有用,就用 Pocket 的“归档”功能永久保存该文章并清理我的 Pocket 收件箱。我尽量保持阅读列表足够小,并保存存档我处理过的信息。Pocket 允许你标记文章,以便以后能更轻松地搜索特定主题的文章。为了防止原始站点消失,你还可以将文章的副本保存在 Pocket 服务器中,要使用这个功能需要购买 Pocket Premium。Pocket 还有一个“发现”功能,它会根据你保存的文章推荐类似的文章,这是寻找新内容的好方法。使用 SnippetStore 进行代码片段管理从 GitHub 到 Stack Overflow answers,再到博客文章,常常能找到一些你希望稍后保存的好代码片段。它可能是一些很好的算法实现,一个有用的脚本,或者一个如何在 Y 语言中执行 X 的例子。我尝试了很多应用程序,从简单的 GitHub Gists 到 Boostnote,直到我发现了 SnippetStore。SnippetStore 是一个开源的代码片段管理应用程序。SnippetStore 与其他产品的区别在于它的简单性。你可以按语言或标签组织整理代码片段,并且可以有多个文件片段。它不完美但足以完成我需要的工作。Boostnote 虽然具有更多的功能,但我更喜欢 SnippetStore ,它组织内容的方法的更简单。对于我每天使用的缩写和片段,我更喜欢使用 Editor/IDE 片段功能,因为它更方便。我使用SnippetStore 更像是对代码示例的参考。Cacher 也是一个有趣的选择,因为它集成了许多编辑器,有一个 cli 工具,使用 GitHub Gists 作为后端,但是付费版每个月需要 6 美元,个人认为有点贵。使用 DevHints 管理备忘单Devhints 是由 Rico Sta. Cruz 创建的备忘录表的集合。它是开源的,由 Jekyll 提供支持,Jekyll 是最受欢迎的静态站点生成器之一。备忘单是用 Markdown 编写的,带有一些额外的格式优势,比如对列的支持。我非常喜欢这个界面的外观,Markdown 使得添加新内容并保持更新和版本控制变得非常容易,这与 PDF 或 Image 格式的备忘录不同,这种格式的可以在 Cheatography 等网站上找到。因为它是开源的,所以我创建了自己的分支,删除了一些我不需要的备忘单,并添加了一些。我使用备忘单作为「如何使用一些库或编程语言或记住一些命令」的参考。拥有一个单独的页面非常方便,例如具有特定编程语言的所有基本语法。我仍然在试验这个工具,到目前为止用的挺好。DiigoDiigo 允许你注释和突出显示网站的部分内容。我在研究新主题时用它来注释重要信息,或者从文章、Stack Overflow answers 中保存特定段落或者从 Twitter 中获取带来灵感的引用。以上就是我想介绍的内容。某些工具可能在功能方面有一些重叠,但是正如我在开始时所说的,这是一个不断发展的工作流程,因为我一直在尝试和寻找改进和提高生产力的方法。你是如何管理你的知识的呢?在评论区一起聊聊吧。原文链接:How I organize my knowledge as a Software Engineer ...

January 9, 2019 · 1 min · jiezi

解决packet_write_wait: Connection to...: Broken pipe

问题打算从远程仓库克隆项目到本地时,报错:$ git clone git@github.com:EverChan6/meetingDemo.gitCloning into ‘meetingDemo’…packet_write_wait: Connection to 52.74.223.119 port 22: Broken pipe // <==就是它!!!fatal: Could not read from remote repository.Please make sure you have the correct access rightsand the repository exists.解决1. 从网上看了挺多解决办法,终于找到一个说辞是说由于多日未 进行ssh 登录操作,本地 publickey 失效造成的。所以解决方法就是Adding your SSH key to the ssh-agent$ ssh-add ~/.ssh/id_rsaIdentity added: /c/Users/HP/.ssh/id_rsa (/c/Users/HP/.ssh/id_rsa)2. 如果执行上面的命令出现如下错误Could not open a connection to your authentication agent.则先执行以下命令$ ssh-agent bash

January 8, 2019 · 1 min · jiezi

2018(农历年)封山之作,和我一起嚼烂Git(两万字长文)

本文是『horseshoe·Git专题』系列文章之一,后续会有更多专题推出GitHub地址(持续更新):https://github.com/veedrin/horseshoe博客地址(文章排版真的很漂亮):https://veedrin.com如果觉得对你有帮助,欢迎来GitHub点Star或者来我的博客亲口告诉我我刚开始接触git的时候,完全搞不清楚为什么这个操作要用这个命令,而那个操作要用那个命令。因为git不是一套注重用户体验的工具,git有自己的哲学。你首先要理解它的哲学,才能真正理解它是如何运作的。我也是看了前辈写的文章才在某一刻醍醐灌顶。git有多强大,想必大家都有所耳闻。git有多令人困惑,想必大家也亲身经历过吧。总而言之,学习git有两板斧:其一,理解git的哲学;其二,在复杂实践中积累处理问题的经验。缺一不可。这篇文章就是第一板斧。作者我自己也还在路上,毕竟,这篇文章也只是我的学习心得,仍然需要大量的实践。写git有多个角度,反复权衡,我最终还是决定从命令的角度铺陈,阅读体验也不至于割裂。想分章节阅读请移步我的GitHub或者个人博客。困难年岁,共勉。01) addgit是一个数据库系统,git是一个内容寻址文件系统,git是一个版本管理系统。没错,它都是。不过我们不纠结于git是什么,我们单刀直入,介绍git命令。要将未跟踪的文件和已跟踪文件的改动加入暂存区,我们可以使用git add命令。不过很多人嫌git add命令不够语义化,毕竟这一步操作是加入暂存区呀。所以git又增加了另外一个命令git stage,它们的效果是一模一样的。git仓库、工作区和暂存区进入主题之前,我们先要介绍一下git仓库、工作区和暂存区的概念。git仓库所谓的git仓库就是一个有.git目录的文件夹。它是和git有关的一切故事开始的地方。可以使用git init命令初始化一个git仓库。$ git init也可以使用git clone命令从服务器上克隆仓库到本地。$ git clone git@github.com:veedrin/horseshoe.git然后你的本地就有了一个和服务器上一模一样的git仓库。这里要说明的是,clone操作并不是将整个仓库下载下来,而是只下载.git目录。因为关于git的一切秘密都在这个目录里面,只要有了它,git就能复原到仓库的任意版本。工作区(working directory)工作区,又叫工作目录,就是不包括.git目录的项目根目录。我们要在这个目录下进行手头的工作,它就是版本管理的素材库。你甚至可以称任何与工作有关的目录为工作区,只不过没有.git目录git是不认的。暂存区(stage或者index)stage在英文中除了有舞台、阶段之意外,还有作为动词的准备、筹划之意,所谓的暂存区就是一个为提交到版本库做准备的地方。那它为什么又被称作index呢?因为暂存区在物理上仅仅是.git目录下的index二进制文件。它就是一个索引文件,将工作区中的文件和暂存区中的备份一一对应起来。stage是表意的,index是表形的。你可以把暂存区理解为一个猪猪储钱罐。我们还是孩子的时候,手里有一毛钱就会丢进储钱罐里。等到储钱罐摇晃的声音变的浑厚时,或者我们有一个心愿急需用钱时,我们就砸开储钱罐,一次性花完。类比到软件开发,每当我们写完一个小模块,就可以将它放入暂存区。等到一个完整的功能开发完,我们就可以从暂存区一次性提交到版本库里。这样做的好处是明显的:它可以实现更小颗粒度的撤销。它可以实现批量提交到版本库。另外,添加到暂存区其实包含两种操作。一种是将还未被git跟踪过的文件放入暂存区;一种是已经被git跟踪的文件,将有改动的内容放入暂存区。放入暂存区git默认是不会把工作区的文件放入暂存区的。$ git statusOn branch masterNo commits yetUntracked files: (use “git add <file>…” to include in what will be committed) a.mdnothing added to commit but untracked files present (use “git add” to track)我们看到文件现在被标注为Untracked files。表示git目前还无法追踪它们的变化,也就是说它们还不在暂存区里。那么我们如何手动将文件或文件夹放入暂存区呢?$ git add .上面的命令表示将工作目录所有未放入暂存区的文件都放入暂存区。这时文件的状态已经变成了Changes to be committed,表示文件已经放入暂存区,等待下一步提交。每一次add操作其实就是为加入的文件或内容生成一份备份。下面的命令也能达到相同的效果。$ git add -A假如我只想暂存单个文件呢?后跟相对于当前目录的文件名即可。$ git add README.md暂存整个文件夹也是一样的道理。因为git会递归暂存文件夹下的所有文件。$ git add src把从来没有被标记过的文件放入暂存区的命令是git add,暂存区中的文件有改动也需要使用git add命令将改动放入暂存区。这时状态变成了Changes not staged for commit。$ git statusOn branch masterChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: a.mdno changes added to commit (use “git add” and/or “git commit -a”)针对已经加入暂存区的文件,要将文件改动加入暂存区,还有一个命令。$ git add -a它和git add -A命令的区别在于,它只能将已加入暂存区文件的改动放入暂存区,而git add -A通吃两种情况。跟踪内容假设我们已经将文件加入暂存区,现在我们往文件中添加内容,再次放入暂存区,然后查看状态。$ git statusOn branch masterNo commits yetChanges to be committed: (use “git rm –cached <file>…” to unstage) new file: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: a.md哎,突然变的有意思了。为什么一个文件会同时存在两种状态,它是薛定谔的猫么?想象一下,我想在一个文件中先修复一个bug然后增加一个feather,我肯定希望分两次放入暂存区,这样可以实现颗粒度更细的撤销和提交。但是如果git是基于文件做版本管理的,它就无法做到。所以git只能是基于内容做版本管理,而不是基于文件。版本管理的最小单位叫做hunk,所谓的hunk就是一段连续的改动。一个文件同时有两种状态也就不稀奇了。objectsgit项目的.git目录下面有一个目录objects,一开始这个目录下面只有两个空目录:info和pack。一旦我们执行了git add命令,objects目录下面就会多出一些东西。.git/.git/objects/.git/objects/e6/.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391它多出了一个2个字符命名的目录和一个38个字符命名的文件。加起来正好是40个字符。增加一个2个字符的目录是为了提高检索效率。SHA-1是一种哈希加密算法,它的特点是只要加密的内容相同,得到的校验和也相同。当然这种说法是不准确的,但是碰撞的概率极低。git除了用内容来计算校验和之外,还加入了一些其他信息,目的也是为了进一步降低碰撞的概率。重点是,SHA-1算法是根据内容来计算校验和的,跟前面讲的git跟踪内容相呼应。git被称为一个内容寻址文件系统不是没有道理的。我们可以做个实验。初始化本地仓库两次,每次都新建一个markdown文件,里面写## git is awesome,记下完整的40个字符的校验和,看看它们是否一样。.git/objects/56/46a656f6331e1b30988472fefd48686a99e10f如果你真的做了实验,你会发现即便两个文件的文件名和文件格式都不一样,只要内容一样,它们的校验和就是一样的,并且就是上面列出的校验和。现在大家应该对git跟踪内容这句话有更深的理解了。相同内容引用一个对象虽然开发者要极力避免这种情况,但是如果一个仓库有多个内容相同的文件,git会如何处理呢?我们初始化一个本地仓库,新建两个不同名的文件,但文件内容都是## git is awesome。运行git add .命令之后看看神秘的objects目录下会发生什么?.git/objects/56/46a656f6331e1b30988472fefd48686a99e10f只有一个目录,而且校验和跟之前一模一样。其实大家肯定早就想到了,git这么优秀的工具,怎么可能会让浪费磁盘空间的事情发生呢?既然多个文件的内容相同,肯定只保存一个对象,让它们引用到这里来就好了。文件改动对应新对象现在我们猜测工作区的文件和objects目录中的对象是一一对应起来的。但事实真的是这样吗?我们初始化一个本地仓库,新建一个markdown文件,运行git add .命令。现在objects目录中已经有了一个对象。然后往文件中添加内容## git is awesome。再次运行git add .命令。.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391.git/objects/56/46a656f6331e1b30988472fefd48686a99e10f哎,objects目录中出现了两个对象。第一个对象肯定对应空文件。第二个对象我们太熟悉了,对应的是添加内容后的文件。再次强调,git是一个版本管理系统,文件在它这里不是主角,版本才是。刚才我们暂存了两次,可以认为暂存区现在已经有了两个版本(暂存区的版本实际上是内容备份,并不是真正的版本)。当然就需要两个对象来保存。文件改动全量保存初始化一个本地仓库,往工作区添加lodash.js未压缩版本,版本号是4.17.11,体积大约是540KB。运行git add .命令后objects目录下面出现一个对象,体积大约是96KB。.git/objects/cb/139dd81ebee6f6ed5f5a9198471f5cdc876d70我们对lodash.js文件内容作一个小小的改动,将版本号从4.17.11改为4.17.10,再次运行git add .命令。然后大家会惊奇的发现objects目录下有两个对象了。惊奇的不是这个,而是第二个对象的体积也是大约96KB。.git/objects/cb/139dd81ebee6f6ed5f5a9198471f5cdc876d70.git/objects/bf/c087eec7e61f106df8f5149091b8790e6f3636明明只改了一个数字而已,第二个对象却还是这么大。前面刚夸git会精打细算,怎么到这里就不知深浅了?这是因为多个文件内容相同的情况,引用到同一个对象并不会造成查询效率的降低,而暂存区的多个对象之间如果只保存增量的话,版本之间的查询和切换需要花费额外的时间,这样做是不划算的。但是全量保存也不是个办法吧。然而git鱼和熊掌想兼得,它也做到了。后面会讲到。重命名会拆分成删除和新建两个动作初始化一个本地仓库,新建一个文件,运行git add .命令。然后重命名该文件,查看状态信息。$ git statusOn branch masterNo commits yetChanges to be committed: (use “git rm –cached <file>…” to unstage) new file: a.mdChanges not staged for commit: (use “git add/rm <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) deleted: a.mdUntracked files: (use “git add <file>…” to include in what will be committed) b.md这是由于git的内部机制导致的。生成对象的时候,它发现仓库中叫这个名字的文件不见了,于是标记为已删除,又发现有一个新的文件名是之前没有标记过的,于是标记为未跟踪。因为它只是重命名而已,文件内容并没有改变,所以可以共享对象,并不会影响效率。blob对象git的一切秘密都在.git目录里。因为它拥有项目的完整信息,所以git一定是把备份存在了某个地方。git把它们存在了哪里,又是如何存储它们的呢?这些备份信息,git统一称它们为对象。git总共有四种对象类型,都存在.git/objects目录下。这一次我们只介绍blob对象。它存储文件的内容和大小。当开发者把未跟踪的文件或跟踪文件的改动加入暂存区,就会生成若干blob对象。git会对blob对象进行zlib压缩,以减少空间占用。因为它只存储内容和大小,所以两个文件即便文件名和格式完全不一样,只要内容相同,就可以共享一个blob对象。注意blob对象和工作目录的文件并不是一一对应的,因为工作目录的文件几乎会被多次添加到暂存区,这时一个文件会对应多个blob对象。index仓库的.git目录下面有一个文件,它就是大名鼎鼎的暂存区。是的,暂存区并不是一块区域,只是一个文件,确切的说,是一个索引文件。它保存了项目结构、文件名、时间戳以及blob对象的引用。工作区的文件和blob对象之间就是通过这个索引文件关联起来的。打包还记得我们在文件改动全量保存小节里讲到,git鱼和熊掌想兼得么?又想全量保存,不降低检索和切换速度,又想尽可能压榨体积。git是怎么做到的呢?git会定期或者在推送到远端之前对git对象进行打包处理。打包的时候保存文件最新的全量版本,基于该文件的历史版本的改动则只保存diff信息。因为开发者很少会切换到较早的版本中,所以这时候效率就可以部分牺牲。需要注意的是,所有的git对象都会被打包,而不仅仅是blob对象。git也有一个git gc命令可以手动执行打包。$ git gcCounting objects: 11, done.Delta compression using up to 4 threads.Compressing objects: 100% (9/9), done.Writing objects: 100% (11/11), done.Total 11 (delta 3), reused 0 (delta 0)之前的git对象文件都不见了,pack文件夹多了两个文件。其中 .pack 后缀文件存储的就是打包前git对象文件的实际内容。.git/objects/.git/objects/info/.git/objects/info/packs.git/objects/pack/.git/objects/pack/pack-99b4704a207ea3cc4924c9f0febb6ea45d4cdfd2.idx.git/objects/pack/pack-99b4704a207ea3cc4924c9f0febb6ea45d4cdfd2.pack只能说,git gc的语义化不够好。它的功能不仅仅是垃圾回收,还有打包。02) commitgit是一个版本管理系统。它的终极目的就是将项目特定时间的信息保留成一个版本,以便将来的回退和查阅。我们已经介绍了暂存区,暂存区的下一步就是版本库,而促成这一步操作的是git commit命令。提交暂存区有待提交内容的情况下,如果直接运行git commit命令,git会跳往默认编辑器要求你输入提交说明,你也可以自定义要跳往的编辑器。# Please enter the commit message for your changes. Lines starting# with ‘#’ will be ignored, and an empty message aborts the commit.# On branch master# Initial commit# Changes to be committed:# new file: a.md提交之后我们就看到这样的信息。[master (root-commit) 99558b4] commit for nothing 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 a.md如果我就是不写提交说明呢?Aborting commit due to empty commit message.看到没有,提交信息在git中时必填的。如果提交说明不多,可以加参数-m直接在命令后面填写提交说明。$ git commit -m “commit for nothing"你甚至可以将加入暂存区和提交一并做了。$ git commit -am “commit for nothing"但是要注意,和git add -a命令一样,未跟踪的文件是无法提交上去的。重写提交amend翻译成中文是修改的意思。git commit –amend命令允许你修改最近的一次commit。$ git log –oneline8274473 (HEAD -> master) commit for nothing目前项目提交历史中只有一个commit。我突然想起来这次提交中有一个笔误,我把高圆圆写成了高晓松(真的是笔误)。但是呢,我又不想为了这个笔误增加一个commit,毕竟它仅仅是一个小小的笔误而已。最重要的是我想悄无声息的改正它,以免被别人笑话。这时我就可以使用git commit –amend命令。首先修改高晓松成高圆圆。然后执行git add a.md命令。最后重写提交。git会跳往默认或者自定义编辑器提示你修改commit说明。当然你也可以不改。$ git commit –amendcommit for nothing# Please enter the commit message for your changes. Lines starting# with ‘#’ will be ignored, and an empty message aborts the commit.# Date: Thu Jan 3 09:33:56 2019 +0800# On branch master# Initial commit# Changes to be committed:# new file: a.md我们再来看提交历史。$ git log –oneline8a71ae1 (HEAD -> master) commit for nothing提交历史中同样只有一个commit。但是注意哟,commit已经不是之前的那个commit了,它们的校验和是不一样的。这就是所谓的重写。tree对象和commit对象commit操作涉及到两个git对象。第一是tree对象。它存储子目录和子文件的引用。如果只有blob对象,那版本库将是一团散沙。正因为有tree对象将它们的关系登记在册,才能构成一个有结构的版本库。添加到暂存区操作并不会生成tree对象,这时项目的结构信息存储在index文件中,直到提交版本库操作,才会为每一个目录分别生成tree对象。第二是commit对象。它存储每个提交的信息,包括当前提交的根tree对象的引用,父commit对象的引用,作者和提交者,还有提交信息。所谓的版本,其实指的就是这个commit对象。作者和提交者通常是一个人,但也存在不同人的情况。objects初始化一个git项目,新建一些文件和目录。src/src/a.mdlib/lib/b.md首先运行git add命令。我们清楚,这会在.git/objects目录下生成一个blob对象,因为目前两个文件都是空文件,共享一个blob对象。.git/objects/info/.git/objects/pack/.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391现在我们运行git commit命令,看看有什么变化。.git/objects/info/.git/objects/pack/.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391.git/objects/93/810bbde0f994d41ef550324a2c1ad5f9278e19.git/objects/52/0c9f9f61657ca1e65a288ea77d229a27a8171b.git/objects/0b/785fa11cd93f95b1cab8b9cbab188edc7e04df.git/objects/49/11ff67189d8d5cc2f94904fdd398fc16410d56有意思。刚刚只有一个blob对象,怎么突然蹦出来这么多git对象呢?想一想之前说的commit操作涉及到两个git对象这句话,有没有可能多出来的几个,分别是tree对象和commit对象?我们使用git底层命令git cat-file -t <commit>查看这些对象的类型发现,其中有一个blob对象,三个tree对象,一个commit对象。这是第一个tree对象。$ git cat-file -t 93810bbtree$ git cat-file -p 93810bb100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 b.md这是第二个tree对象。$ git cat-file -t 520c9f9tree$ git cat-file -p 520c9f9100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a.md这是第三个tree对象。$ git cat-file -t 0b785fatree$ git cat-file -p 0b785fa040000 tree 93810bbde0f994d41ef550324a2c1ad5f9278e19 lib040000 tree 520c9f9f61657ca1e65a288ea77d229a27a8171b src可以看到,提交时每个目录都会生成对应的tree对象。然后我们再来看commit对象。$ git cat-file -t 4911ff6commit$ git cat-file -p 4911ff6tree 0b785fa11cd93f95b1cab8b9cbab188edc7e04dfparent c4731cfab38f036c04de93facf07cae496a124a2author veedrin <veedrin@qq.com> 1546395770 +0800committer veedrin <veedrin@qq.com> 1546395770 +0800commit for nothing可以看到,commit会关联根目录的tree对象,因为关联它就可以关联到所有的项目结构信息,所谓擒贼先擒王嘛。它也要关联父commit,也就是它的上一个commit,这样才能组成版本历史。当然,如果是第一个commit那就没有父commit了。然后就是commit说明和一些参与者信息。我们总结一下,git add命令会为加入暂存区的内容或文件生成blob对象,git commit命令会为加入版本库的内容或文件生成tree对象和commit对象。至此,四种git对象我们见识了三种。为啥不在git add的时候就生成tree对象呢?所谓暂存区,就是不一定会保存为版本的信息,只是一个准备的临时场所。git认为在git add的时候生成tree对象是不够高效的,完全可以等版本定型时再生成。而版本定型之前的结构信息存在index文件中就好了。03) branch分支是使得git如此灵活的强大武器,正是因为有巧妙的分支设计,众多的git工作流才成为可能。现在我们已经知道commit对象其实就是git中的版本。那我们要在版本之间切换难道只能通过指定commit对象毫无意义的SHA-1值吗?当然不是。在git中,我们可以通过将一些指针指向commit对象来方便操作,这些指针便是分支。分支在git中是一个模棱两可的概念。你可以认为它仅仅是一个指针,指向一个commit对象节点。你也可以认为它是指针指向的commit对象节点追溯到某个交叉节点之间的commit历史。严格的来说,一种叫分支指针,一种叫分支历史。不过实际使用中,它们在名字上常常不作区分。所以我们需要意会文字背后的意思,它究竟说的是分支指针还是分支历史。大多数时候,它指的都是分支指针。master分支刚刚初始化的git仓库,会发现.git/refs/heads目录下面是空的。这是因为目前版本库里还没有任何commit对象,而分支一定是指向commit对象的。一旦版本库里有了第一个commit对象,git都会在.git/refs/heads目录下面自动生成一个master文件,它就是git的默认分支。不过它并不特殊,只是它充当的是一个默认角色而已。刚刚初始化的git仓库会显示目前在master分支上,其实这个master分支是假的,.git/refs/heads目录下根本没有这个文件。只有等提交历史不为空时才有会真正的默认分支。我们看一下master文件到底有什么。$ cat .git/refs/heads/master6b5a94158cc141286ac98f30bb189b8a83d6134740个字符,明显是某个git对象的引用。再识别一下它的类型,发现是一个commit对象。$ git cat-file -t 6b5a941commit就这么简单,所谓的分支(分支指针)就是一个指向某个commit对象的指针。HEAD指针形象的讲,HEAD就是景区地图上标注你当前在哪里的一个图标。你当前在哪里,HEAD就在哪里。它一般指向某个分支,因为一般我们都会在某个分支之上。因为HEAD是用来标注当前位置的,所以一旦HEAD的位置被改变,工作目录就会切换到HEAD指向的分支。$ git log –onelinef53aaa7 (HEAD -> master) commit for nothing但是也有例外,比如我直接签出到某个没有分支引用的commit。$ git log –onelinecb64064 (HEAD -> master) commit for nothing again324a3c0 commit for nothing$ git checkout 324a3c0Note: checking out ‘324a3c0’.You are in ‘detached HEAD’ state. You can look around, make experimentalchanges and commit them, and you can discard any commits you make in thisstate without impacting any branches by performing another checkout.If you want to create a new branch to retain commits you create, you maydo so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name>HEAD is now at 324a3c0… commit for nothing$ git log –oneline324a3c0 commit for nothing这个时候的HEAD就叫做detached HEAD。要知道,只有在初始提交和某个分支之间的commit才是有效的。当你的HEAD处于detached HEAD状态时,在它之上新建的commit没有被任何分支包裹。一旦你切换到别的分支,这个commit(可能)再也不会被引用到,最终会被垃圾回收机制删除。因此这是很危险的操作。324a3c0 – cb64064(master) \ 3899a24(HEAD)如果不小心这么做了,要么在原地新建一个分支,要么将已有的分支强行移动过来。确保它不会被遗忘。死亡不是终结,遗忘才是。——寻梦环游记创建除了默认的master分支,我们可以随意创建新的分支。$ git branch dev一个dev分支就创建好了。查看或许有时我们也想要查看本地仓库有多少个分支,因为在git中新建分支实在是太容易了。$ git branch dev* master当前分支的前面会有一个号标注。同时查看本地分支和远端分支引用,添加-a参数。$ git branch -a master remotes/origin/HEAD -> origin/master remotes/origin/master删除一般分支合并完之后就不再需要了,这时就要将它删除。$ git branch -d devDeleted branch dev (was 657142d).有时候我们会得到不一样的提示。$ git branch -d deverror: The branch ‘dev’ is not fully merged.If you are sure you want to delete it, run ‘git branch -D dev’.这是git的一种保护措施。is not fully merged是针对当前分支来说的,意思是你要删除的分支还有内容没有合并进当前分支,你确定要删除它吗?大多数时候,当然是要的。$ git branch -D devDeleted branch dev (was 657142d).-D是–delete –force的缩写,你也可以写成-df。需要注意的是,删除分支仅仅是删除一个指针而已,并不会删除对应的commit对象。不过有可能删除分支以后,这一串commit对象就无法再被引用了,从而被垃圾回收机制删除。04) checkout在git中,暂存区里有若干备份,版本库里有若干版本。留着这些东西肯定是拿来用的对吧,怎么用呢?当我需要哪一份的时候我就切换到哪一份。git checkout命令就是用来干这个的,官方术语叫做签出。怎么理解checkout这个词呢?checkout原本指的是消费结束服务员要与你核对一下账单,结完账之后你就可以走了。在git中核对指的是diff,比较两份版本的差异,如果发现没有冲突那就可以切换过来了。底层我们知道HEAD指针指向当前版本,而git checkout命令的作用是切换版本,它们肯定有所关联。目前HEAD指针指向master分支。$ cat .git/HEADref: refs/heads/master如果我切换到另一个分支,会发生什么?$ git checkout devSwitched to branch ‘dev’$ cat .git/HEADref: refs/heads/dev果然,git checkout命令的原理就是改变了HEAD指针。而一旦HEAD指针改变,git就会取出HEAD指针指向的版本作为当前工作目录的版本。签出到一个没有分支引用的commit也是一样的。符号在进入正题之前,我们要先聊聊git中的两个符号和^。如果我们要从一个分支切换到另一个分支,那还好说,足够语义化。但是如果我们要切换到某个commit,除了兢兢业业的找到它的SHA-1值,还有什么办法快速的引用到它呢?比如说我们可以根据commit之间的谱系关系快速定位。$ git log –graph –oneline* 4e76510 (HEAD -> master) c4* 2ec8374 c3|\ | * 7c0a8e3 c2* | fb60f51 c1|/ * dc96a29 c0的作用是在纵向上定位。它可以一直追溯到最早的祖先commit。如果commit历史有分叉,那它就选第一个,也就是主干上的那个。^的作用是在横向上定位。它无法向上追溯,但是如果commit历史有分叉,它能定位所有分叉中的任意一支。HEAD不加任何符号、加0 符号或者加^0符号时,定位的都是当前版本这个不用说,定位当前commit。$ git rev-parse HEAD4e76510fe8bb3c69de12068ab354ef37bba6da9d它表示定位第零代父commit,也就是当前commit。$ git rev-parse HEAD04e76510fe8bb3c69de12068ab354ef37bba6da9d它表示定位当前commit的第零个父commit,也就是当前commit。$ git rev-parse HEAD^04e76510fe8bb3c69de12068ab354ef37bba6da9d用符号数量的堆砌或者数量的写法定位第几代父commit$ git rev-parse HEAD~~fb60f519a59e9ceeef039f7efd2a8439aa7efd4b$ git rev-parse HEAD2fb60f519a59e9ceeef039f7efd2a8439aa7efd4b用^数量的写法定位第几个父commit注意,^定位的是当前基础的父commit。$ git rev-parse HEAD^2ec837440051af433677f786e502d1f6cdeb0a4a$ git rev-parse HEAD^12ec837440051af433677f786e502d1f6cdeb0a4a因为当前commit只有一个父commit,所以定位第二个父commit会失败。$ git rev-parse HEAD^2HEAD^2fatal: ambiguous argument ‘HEAD^2’: unknown revision or path not in the working tree.Use ‘–’ to separate paths from revisions, like this:‘git <command> [<revision>…] – [<file>…]‘用数量^数量的写法或者^数量^数量的写法定位第几代父commit的第几个父commit当前commit的第一代父commit的第零个父commit,意思就是第一代父commit咯。$ git rev-parse HEAD~^02ec837440051af433677f786e502d1f6cdeb0a4a比如这里定位的是当前commit的第一代父commit的第一个父commit。再次注意,^定位的是当前基础的父commit。$ git rev-parse HEAD~^1fb60f519a59e9ceeef039f7efd2a8439aa7efd4b这里定位的是当前commit的第一代父commit的第二个父commit。$ git rev-parse HEAD~^27c0a8e3a325ce1b5a1cdeb8c89bef1ecf17c10c9同样,定位到一个不存在的commit会失败。$ git rev-parse HEAD~^3HEAD~^3fatal: ambiguous argument ‘HEAD~^3’: unknown revision or path not in the working tree.Use ‘–’ to separate paths from revisions, like this:‘git <command> [<revision>…] – [<file>…]‘和不同,^2和^^的效果是不一样的。^2指的是第二个父commit,^^指的是第一个父commit的第一个父commit。切换到HEADgit checkout命令如果不带任何参数,默认会加上HEAD参数。而HEAD指针指向的就是当前commit。所以它并不会有任何签出动作。前面没有提到的是,git checkout命令会有一个顺带效果:比较签出后的版本和暂存区之间的差异。所以git checkout命令不带任何参数,意思就是比较当前commit和暂存区之间的差异。$ git checkoutA b.md$ git checkout HEADA b.md切换到commit开发者用的最多的当然是切换分支。其实checkout后面不仅可以跟分支名,也可以跟commit的校验和,还可以用符号定位commit。$ git checkout devSwitched to branch ‘dev’$ git checkout acb71feNote: checking out ‘acb71fe11f78d230b860692ea6648906153f3d27’.You are in ‘detached HEAD’ state. You can look around, make experimentalchanges and commit them, and you can discard any commits you make in thisstate without impacting any branches by performing another checkout.If you want to create a new branch to retain commits you create, you maydo so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name>HEAD is now at acb71fe… null$ git checkout HEAD2Note: checking out ‘acb71fe11f78d230b860692ea6648906153f3d27’.You are in ‘detached HEAD’ state. You can look around, make experimentalchanges and commit them, and you can discard any commits you make in thisstate without impacting any branches by performing another checkout.If you want to create a new branch to retain commits you create, you maydo so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name>HEAD is now at acb71fe… null创建分支并切换有时候我们在创建分支时希望同时切换到创建后的分支,仅仅git branch <branch>是做不到的。这时git checkout命令可以提供一个快捷操作,创建分支和切换分支一步到位。$ git checkout -b devSwitched to a new branch ‘dev’暂存区文件覆盖工作区文件git checkout不仅可以执行切换commit这种全量切换,它还能以文件为单位执行微观切换。$ git statusOn branch masterNo commits yetChanges to be committed: (use “git rm –cached <file>…” to unstage) new file: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: a.md$ git checkout – a.md$ git statusOn branch masterNo commits yetChanges to be committed: (use “git rm –cached <file>…” to unstage) new file: a.md因为暂存区覆盖了工作区,所以工作区的改动就被撤销了,现在只剩下暂存区的改动等待提交。其实相当于撤销文件在工作区的改动,只不过它的语义是覆盖。这个命令没有任何提示,直接撤销工作区改动,要谨慎使用。我们看到git提示语中有一个git checkout – <file>命令,这又是干嘛用的呢?提醒一下,这个参数的写法不是git checkout –<file>,而是git checkout – <file>。其实它和git checkout <file>的效果是一样的。但是别急,我是说这两个命令想要达到的效果是一样的,但实际效果却有略微的差别。独立的–参数在Linux命令行中指的是:视后面的参数为文件名。当后面跟的是文件名的时候,最好加上独立的–参数,以免有歧义。也就是说,如果该项目正好有一个分支名为a.md(皮一下也不是不行对吧),那加独立的–参数就不会操作分支,而是操作文件。如果你觉得仅仅撤销一个文件在工作区的改动不过瘾,你不是针对谁,你是觉得工作区的改动都是垃圾。那么还有一个更危险的命令。$ git checkout – ..代表当前目录下的所有文件和子目录。这条命令会撤销所有工作区的改动。当前commit文件覆盖暂存区文件和工作区文件如果执行git checkout – <file>的时候加上一个分支名或者commit的校验和,效果就是该文件的当前版本会同时覆盖暂存区和工作区。相当于同时撤销文件在暂存区和工作区的改动。$ git statusOn branch masterChanges to be committed: (use “git reset HEAD <file>…” to unstage) modified: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: a.md$ git checkout HEAD – a.md$ git statusOn branch masternothing to commit, working tree clean最后再提醒一下,运行git checkout命令作用于文件时,即便覆盖内容与被覆盖内容有冲突,也会直接覆盖,所以这真的是闷声打雷式的git命令,一定要抽自己几个耳刮子方可放心食用。05) merge可以方便的创建分支是git如此受欢迎的重要原因,利用git checkout <branch>也让开发者在分支之间穿梭自如。然而百川终入海,其他分支上完成的工作终究是要合并到主分支上去的。所以我们来看看git中的合并操作。首先说明,执行git merge命令之前需要一些准备工作。$ git merge deverror: Your local changes to the following files would be overwritten by merge: a.mdPlease commit your changes or stash them before you merge.Aborting合并操作之前必须保证暂存区内没有待提交内容,否则git会阻止合并。这是因为合并之后,git会将合并后的版本覆盖暂存区。所以会有丢失工作成果的危险。至于工作区有待添加到暂存区的内容,git倒不会阻止你。可能git觉得它不重要吧。不过最好还是保持一个干净的工作区再执行合并操作。不同分支的合并不同分支指的是要合并的两个commit在某个祖先commit之后开始分叉。C0 – C1 – C2(HEAD -> master) \ C3(dev)git merge后跟合并客体,表示要将它合并进来。$ git merge dev进行到这里,如果没有冲突,git会弹出默认或者自定义的编辑器,让你填写commit说明。当然它会给你填写一个默认的commit说明。Merge branch ‘dev’# Please enter a commit message to explain why this merge is necessary,# especially if it merges an updated upstream into a topic branch.## Lines starting with ‘#’ will be ignored, and an empty message aborts# the commit.为什么要你填写commit说明?因为这种情况的git merge实际上会创建一个新的commit对象,记录此次合并的信息,并将当前分支指针移动到它上面来。C0 – C1 – C2 – C4(HEAD -> master)(merge commit) \ / \ / C3(dev)大家常说不同分支的git merge操作是一个三方合并,这里的三方指的是合并主体commit、合并客体commit以及合并主客体的共同祖先commit。所谓的三方和并到底是什么意思呢?git会提取出合并主体commit相对于合并主客体的共同祖先commit的diff与合并客体commit相对于合并主客体的共同祖先commit的diff,再去比较这两份diff有没有修改同一个地方,这里同一个地方的单位是文件的行。如果没有,那就将这两份diff合并生成一个新的commit,当前分支指针向右移。如果有那就要求开发者自行解决。所以在三方合并中,合并主客体的共同祖先commit只是一个参照物。合并主体在合并客体的上游它指的是开发者当前在一个commit节点上,要将同一个分支上更新的commit节点合并进来。C0 – C1 – C2(HEAD -> master) – C3(dev)这时候会发生什么呢?这相当于更新当前分支指针,所以只需要将当前分支指针向下游移动,让合并主体与合并客体指向同一个commit即可。这时并不会产生一个新的commit。用三方合并的概念来理解,合并主体commit与合并主客体的共同祖先commit是同一个commit,合并主体commit相对于合并主客体的共同祖先commit的diff为空,合并客体commit相对于合并主客体的共同祖先commit的diff与空diff合并还是它自己,所以移动过去就行了,并不需要生成一个新的commit。$ git merge devUpdating 9242078..631ef3aFast-forward a.md | 2 ++ 1 file changed, 2 insertions(+)C0 – C1 – C2 – C3(HEAD -> master, dev)这种操作在git中有一个专有名词,叫Fast forward。比如说git pull的时候经常发生这种情况。通常因为远端有更新的commit我们才需要执行git pull命令,这时远端就是合并客体,本地就是合并主体,远端的分支指针在下游,也会触发Fast forward。合并主体在合并客体的下游如果合并主体在合并客体的下游,那合并主体本身就包含合并客体,合并操作并不会产生任何效果。C0 – C1 – C2(dev) – C3(HEAD -> master)$ git merge devAlready up to date.C0 – C1 – C2(dev) – C3(HEAD -> master)依然用三方合并的概念来理解,这时合并客体commit与合并主客体的共同祖先commit是同一个commit,合并客体commit相对于合并主客体的共同祖先commit的diff为空,合并主体commit相对于合并主客体的共同祖先commit的diff与空diff合并还是它自己。但是这回它都不用移动,因为合并后的diff就是它自己原有的diff。注意,这时候dev分支指针会不会动呢?当然不会,git merge操作对合并客体是没有任何影响的。同时合并多个客体如果你在git merge后面跟不止一个分支,这意味着你想同时将它们合并进当前分支。$ git merge aaa bbb cccFast-forwarding to: aaaTrying simple merge with bbbTrying simple merge with cccMerge made by the ‘octopus’ strategy. aaa.md | 0 bbb.md | 0 ccc.md | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 aaa.md create mode 100644 bbb.md create mode 100644 ccc.mdgit合并有多种策略,上面使用的是’octopus’ strategy章鱼策略,因为同时合并的多个分支最终都会指向新的commit,看起来像章鱼的触手。合并有冲突git merge操作并不总是如此顺利的。因为有时候要合并的两个分支不是同一个人的,就会有很大的概率遇到两人同时修改文件某一行的情况。git不知道该用谁的版本,它认为两个分支遇到了冲突。这时就需要开发者手动的解决冲突,才能让git继续合并。$ git merge devAuto-merging a.mdCONFLICT (content): Merge conflict in a.mdAutomatic merge failed; fix conflicts and then commit the result.我们来看一下有冲突的文件是什么样的。<<<<<<< HEADapple=======banana>>>>>>> dev运行git status命令。$ git statusOn branch masterYou have unmerged paths. (fix conflicts and run “git commit”) (use “git merge –abort” to abort the merge)Unmerged paths: (use “git add <file>…” to mark resolution) both modified: a.mdno changes added to commit (use “git add” and/or “git commit -a”)解决完冲突之后,你需要再提交,告诉git可以完成合并了。$ git commit -m “fix merge conflict"U a.mderror: Committing is not possible because you have unmerged files.hint: Fix them up in the work tree, and then use ‘git add/rm <file>‘hint: as appropriate to mark resolution and make a commit.fatal: Exiting because of an unresolved conflict.诶,被拒绝了。是不是想起了自己的情场故事?当我们解决冲突的时候,工作区已经有改动,所以需要先提交到暂存区。$ git add a.md$ git commit -m “fix merge conflict”[master 9b32d4d] fix merge conflict运行git add 命令之后你也可以用git merge –continue来替代git commit命令。它会让后面的行为跟没有冲突时的行为表现的一样。如果你遇到冲突以后不知道如何解决,因为你要去询问你的合作伙伴为什么这样改。这时你肯定想回到合并以前的状态。这对git来说很容易。只需要运行git merge –abort命令即可。$ git merge –abort该命令无法保证恢复工作区的修改,所以最好是在合并之前先让工作区保持干净。06) rebasegit merge命令会生成一个新的合并commit。如果你有强迫症,不喜欢这个新的合并commit,git也有更加清爽的方案可以满足你,它就是git rebase命令。git就是哆啦A梦的口袋。rebase翻译过来是变基。意思就是将所有要合并进来的commit在新的基础上重新提交一次。基础用法git rebase <branch>会计算当前分支和目标分支的最近共同祖先,然后将最近共同祖先与当前分支之间的所有commit都变基到目标分支上,使得提交历史变成一条直线。C0 – C1 – C2 – C3(master) \ C4 – C5 – C6(HEAD -> dev)merge与rebase后跟的分支名是不一样的。合并是合并进来,变基是变基过去,你们感受一下。$ git rebase masterFirst, rewinding head to replay your work on top of it…Applying: C4.mdApplying: C5.mdApplying: C6.mdC0 – C1 – C2 – C3(master) – C4’ – C5’ – C6’(HEAD -> dev) \ C4 – C5 – C6现在最近共同祖先与当前分支之间的所有commit都被复制到master分支之后,并且将HEAD指针与当前分支指针切换过去。这招移花接木玩的很溜啊,如果你置身其中根本分不出区别。原来的commit还在吗?还在,如果你记得它的commit校验和,仍然可以切换过去,git会提示你当前处于detached HEAD状态下。只不过没有任何分支指针指向它们,它们已经被抛弃了,剩余的时光就是等待git垃圾回收命令清理它们。好在,还有人记得它们,不是么?git rebase完并没有结束,因为我变基的目标分支是master,而当前分支是dev。我需要切换到master分支上,然后再合并一次。$ git checkout master$ git merge dev诶,说来说去,还是要合并啊?别急,这种合并是Fast forward的,并不会生成一个新的合并commit。如果我要变基的本体分支不是当前分支行不行?也是可以的。$ git rebase master dev你在任何一个分支上,这种写法都可以将dev分支变基到master分支上,变基完成当前分支会变成dev分支。裁剪commit变基变基有点像基因编辑,git有更精确的工具达到你想要的效果。有了精确的基因编辑技术,妈妈再也不用担心你长的丑啦。C0 – C1 – C2 – C3(master) \ C4 – C5 – C6(dev) \ C7 – C8(HEAD -> hotfix)$ git rebase –onto master dev hotfixFirst, rewinding head to replay your work on top of it…Applying: C7.mdApplying: C8.mdC0 – C1 – C2 – C3(master) – C7’ – C8’(HEAD -> hotfix) \ C4 – C5 – C6(dev) \ C7 – C8–onto参数就是那把基因编辑的剪刀。它会把hotfix分支到hotfix分支与dev分支的最近共同祖先之间的commit裁剪下来,复制到目标基础点上。注意,所谓的之间指的都是不包括最近共同祖先commit的范围,比如这里就不会复制C4commit。$ git rebase –onto master devFirst, rewinding head to replay your work on top of it…Applying: C7.mdApplying: C8.md如果–onto后面只写两个分支(或者commit)名,第三个分支(或者commit)默认就是HEAD指针指向的分支(或者commit)。变基冲突解决变基也会存在冲突的情况,我们看看冲突怎么解决。C0 – C1 – C2(HEAD -> master) \ C3 – C4(dev)$ git rebase master devFirst, rewinding head to replay your work on top of it…Applying: c.mdApplying: a.md add bananaUsing index info to reconstruct a base tree…M a.mdFalling back to patching base and 3-way merge…Auto-merging a.mdCONFLICT (content): Merge conflict in a.mderror: Failed to merge in the changes.Patch failed at 0002 a.md devThe copy of the patch that failed is found in: .git/rebase-apply/patchResolve all conflicts manually, mark them as resolved with"git add/rm <conflicted_files>”, then run “git rebase –continue”.You can instead skip this commit: run “git rebase –skip”.To abort and get back to the state before “git rebase”, run “git rebase –abort”.C2和C4同时修改了a.md的某一行,引发冲突。git已经给我们提示了,大体上和merge的操作一致。我们可以手动解决冲突,然后执行git add和git rebase –continue来完成变基。如果你不想覆盖目标commit的内容,也可以跳过这个commit,执行git rebase –skip。但是注意,这会跳过有冲突的整个commit,而不仅仅是有冲突的部分。后悔药也是有的,执行git rebase –abort,干脆就放弃变基了。cherry-pickgit rebase –onto命令可以裁剪分支以变基到另一个分支上。但它依然是挑选连续的一段commit,只是允许你指定头和尾罢了。别急,git cherry-pick命令虽然是一个独立的git命令,它的效果却还是变基,而且是commit级别的变基。git cherry-pick命令可以挑选任意commit变基到目标commit上。你负责挑,它负责基。用法只需要在git cherry-pick命令后跟commit校验和,就可以将它应用到目标commit上。C0 – C1 – C2(HEAD -> master) \ C3 – C4 – C5(dev) \ C6 – C7(hotfix)将当前分支切换到master分支。$ git cherry-pick C6[master dc342e0] c6 Date: Mon Dec 24 09:13:57 2018 +0800 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 c6.mdC0 – C1 – C2 – C6’(HEAD -> master) \ C3 – C4 – C5(dev) \ C6 – C7(hotfix)C6commit就按原样重新提交到master分支上了。cherry-pick并不会修改原有的commit。同时挑选多个commit也很方便,往后面叠加就行。$ git cherry-pick C4 C7[master ab1e7c7] c4 Date: Mon Dec 24 09:12:58 2018 +0800 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 c4.md[master 161d993] c7 Date: Mon Dec 24 09:14:12 2018 +0800 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 c7.mdC0 – C1 – C2 – C4’ – C7’(HEAD -> master) \ C3 – C4 – C5(dev) \ C6 – C7(hotfix)如果这多个commit正好是连续的呢?$ git cherry-pick C3…C7[master d16c42e] c4 Date: Mon Dec 24 09:12:58 2018 +0800 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 c4.md[master d16c42e] c6 Date: Mon Dec 24 09:13:57 2018 +0800 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 c6.md[master a4d5976] c7 Date: Mon Dec 24 09:14:12 2018 +0800 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 c7.mdC0 – C1 – C2 – C4’ – C6’ – C7’(HEAD -> master) \ C3 – C4 – C5(dev) \ C6 – C7(hotfix)需要注意,git所谓的从某某开始,一般都是不包括某某的,这里也一样。有没有发现操作连续commit的git cherry-pick和git rebase的功能已经非常接近了?所以呀,git cherry-pick也是变基,只不过一边变基一边喂樱桃给你吃。冲突git各种命令解决冲突的方法都大同小异。C0 – C1(HEAD -> master) \ C2(dev)$ git cherry-pick C2error: could not apply 051c24c… bananahint: after resolving the conflicts, mark the corrected pathshint: with ‘git add <paths>’ or ‘git rm <paths>‘hint: and commit the result with ‘git commit’手动解决冲突,执行git add命令然后执行git cherry-pick –continue命令。如果被唬住了想还原,执行git cherry-pick –abort即可。变基还是合并这是一个哲学问题。有一种观点认为,仓库的commit历史应该记录实际发生过什么。所以如果你将一个分支合并进另一个分支,commit历史中就应该有这一次合并的痕迹,因为它是实实在在发生过的。另一种观点则认为,仓库的commit历史应该记录项目过程中发生过什么。合并不是项目开发本身带来的,它是一种额外的操作,会使commit历史变的冗长。我是一个极简主义者,所以我支持首选变基。07) resetgit checkout命令可以在版本之间随意切换,它的本质是移动HEAD指针。那git有没有办法移动分支指针呢?当然有,这就是git reset命令。底层git reset命令与git checkout命令的区别在于,它会把HEAD指针和分支指针一起移动,如果HEAD指针指向的是一个分支指针的话。我们前面说过使用git checkout命令从有分支指向的commit切换到一个没有分支指向的commit上,这个时候的HEAD指针被称为detached HEAD。这是非常危险的。C0 – C1 – C2(HEAD -> master)$ git checkout C1C0 – C1(HEAD) – C2(master)但是git reset命令没有这个问题,因为它会把当前的分支指针也带过去。C0 – C1 – C2(HEAD -> master)$ git reset C1C0 – C1(HEAD -> master) – C2这就是重置的含义所在。它可以重置分支。看另一种情况。如果是从一个没有分支指向的commit切换到另一个没有分支指向的commit上,那它们就是两个韩国妹子,傻傻分不清楚了。这是git checkout命令的效果。C0 – C1 – C2(HEAD) – C3(master)$ git checkout C1C0 – C1(HEAD) – C2 – C3(master)这是git reset命令的效果。C0 – C1 – C2(HEAD) – C3(master)$ git reset C1C0 – C1(HEAD) – C2 – C3(master)同时重置暂存区和工作区的改动当你在 git reset 命令后面加 –hard 参数时,暂存区和工作区的内容都会重置为重置后的commit内容。也就是说暂存区和工作区的改动都会清空,相当于撤销暂存区和工作区的改动。而且是没有确认操作的哟。$ git statusOn branch masterChanges to be committed: (use “git reset HEAD <file>…” to unstage) modified: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: a.md$ git reset –hard HEAD^HEAD is now at 58b0040 commit for nothing$ git statusOn branch masternothing to commit, working tree clean仅重置暂存区的改动git reset 命令后面加 –mixed 参数,或者不加参数,因为–mixed参数是默认值,暂存区的内容会重置为重置后的commit内容,工作区的改动不会清空,相当于撤销暂存区的改动。同样也是没有确认操作的哟。$ git statusOn branch masterChanges to be committed: (use “git reset HEAD <file>…” to unstage) modified: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: a.md$ git reset HEAD^Unstaged changes after reset:M a.md$ git statusOn branch masterChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: a.mdno changes added to commit (use “git add” and/or “git commit -a”)打个趣,如果git reset命令什么都不加会怎样呢?你可以脑补一下,git reset命令不加参数默认就是–mixed,不加操作对象默认就是HEAD,所以单纯的git reset命令相当于git reset –mixed HEAD命令。那这又意味着什么呢?这意味着从当前commit重置到当前commit,没有变化对吧?但是–mixed参数会撤销暂存区的改动对不对,这就是它的效果。同时保留暂存区和工作区的改动如果 git reset 命令后面加 –soft 参数,钢铁直男的温柔,你懂的。仅仅是重置commit而已,暂存区和工作区的改动都会保留下来。更温柔的是,重置前的commit内容与重置后的commit内容的diff也会放入暂存区。$ git statusOn branch masterChanges to be committed: (use “git reset HEAD <file>…” to unstage) modified: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: a.md$ git diff –stageddiff –git a/a.md b/a.mdindex 4a77268..fde8dcd 100644— a/a.md+++ b/a.md@@ -1,2 +1,3 @@ apple banana+cherry$ git reset –soft HEAD^$ git statusOn branch masterChanges to be committed: (use “git reset HEAD <file>…” to unstage) modified: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: a.md$ git diff –stageddiff –git a/a.md b/a.mdindex 4a77268..fde8dcd 100644— a/a.md+++ b/a.md@@ -1 +1,3 @@ apple+banana+cherrybanana就是重置前的commit内容与重置后的commit内容的diff,可以看到,它已经在暂存区了。文件暂存区改动撤回工作区git reset命令后面也可以跟文件名,它的作用是将暂存区的改动重置为工作区的改动,是git add – <file>的反向操作。git reset – <file>命令是git reset HEAD –mixed – <file>的简写。在操作文件时,参数只有默认的–mixed一种。它并不会撤销工作区原有的改动。$ git statusOn branch masterChanges to be committed: (use “git reset HEAD <file>…” to unstage) modified: a.md$ git reset – a.mdUnstaged changes after reset:M a.md$ git statusOn branch masterChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: a.mdno changes added to commit (use “git add” and/or “git commit -a”)git checkout命令后面也可以跟文件名,它的作用是撤销工作区的改动,需要注意区分。文件若干commit版本撤回工作区如果git reset命令后跟一个commit校验和,它会把该commit与所有后代commit的diff重置到工作区。意思就是将该文件重置回你指定的commit版本,但是在你指定的commit之后的改动我也给你留着,就放到工作区里吧。$ git diff –staged# 空git reset HEAD4 – a.mdUnstaged changes after reset:M a.md$ git diff –stageddiff –git a/a.md b/a.mdindex 6f195b4..72943a1 100644— a/a.md+++ b/a.md@@ -1,5 +1 @@ aaa-bbb-ccc-ddd-eeegit diff –staged命令比较工作区和暂存区的内容。可以看到初始工作区和暂存区是一致的,重置文件到4个版本之前,发现工作区比暂存区多了很多改动,这些都是指定commit之后的提交被重置到工作区了。08) revert有时候我们想撤回一个commit,但是这个commit已经在公共的分支上。如果直接修改分支历史,可能会引起一些不必要的混乱。这个时候,git revert命令就派上用场了。revert翻译成中文是还原。我觉得称它为对冲更合理。对冲指的是同时进行两笔行情相关、方向相反、数量相当、盈亏相抵的交易,这么理解git revert命令一针见血。因为它的作用就是生成一个新的、完全相反的commit。命令git revert后跟你想要对冲的commit即可。$ git revert HEADRevert “add c.md"This reverts commit 8a23dad059b60ba847a621b6058fb32fa531b20a.# Please enter the commit message for your changes. Lines starting# with ‘#’ will be ignored, and an empty message aborts the commit.# On branch master# Changes to be committed:# deleted: c.mdgit会弹出默认或者自定义的编辑器要求你输入commit信息。然后一个新的commit就生成了。[master a8c4205] Revert “add c.md” 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 c.md可以看到,原本我添加了一个文件a.md,revert操作就会执行删除命令。在工作目录看起来就像添加文件操作被撤销了一样,其实是被对冲了。它不会改变commit历史,只会增加一个新的对冲commit。这是它最大的优点。冲突反向操作也会有冲突?你逗我的吧。如果你操作的是最新的commit,那当然不会有冲突了。那要操作的是以前的commit呢?C0 – C1 – C2(HEAD -> master)比如a.md在C0内容为空,C1修改文件内容为apple,C2修改文件内容为banana。这时候你想撤销C1的修改。$ git revert HEADerror: could not revert 483b537… applehint: after resolving the conflicts, mark the corrected pathshint: with ‘git add <paths>’ or ‘git rm <paths>‘hint: and commit the result with ‘git commit’我们看一下文件内容。<<<<<<< HEADbanana=======>>>>>>> parent of 483b537… apple手动解决冲突,执行git add命令然后执行git revert –continue命令完成对冲操作。取消revert操作只需要执行git revert –abort即可。09) stash你在一个分支上开展了一半的工作,突然有一件急事要你去处理。这时候你得切换到一个新的分支,可是手头上的工作你又不想立即提交。这种场景就需要用到git的储藏功能。储藏想要储藏手头的工作,只需运行git stash命令。$ git statusOn branch masterChanges to be committed: (use “git reset HEAD <file>…” to unstage) modified: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: b.mdUntracked files: (use “git add <file>…” to include in what will be committed) c.md$ git stashSaved working directory and index state WIP on master: 974a2f2 updateWIP是work in progress的缩写,指的是进行中的工作。$ git statusOn branch masterUntracked files: (use “git add <file>…” to include in what will be committed) c.mdnothing added to commit but untracked files present (use “git add” to track)可以看到,除了未被git跟踪的文件之外,工作区和暂存区的内容都会被储藏起来。现在你可以切换到其他分支进行下一步工作了。查看我们看一下储藏列表。$ git stash liststash@{0}: WIP on master: 974a2f2 applestash@{1}: WIP on master: c27b351 banana恢复等我们完成其他工作,肯定要回到这里,继续进行中断的任务。$ git stash applyOn branch masterChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: a.md modified: b.mdUntracked files: (use “git add <file>…” to include in what will be committed) c.mdno changes added to commit (use “git add” and/or “git commit -a”)诶,等等。怎么a.md的变更也跑到工作区了?是的,git stash默认会将暂存区和工作区的储藏全部恢复到工作区。如果我就是想原样恢复呢?$ git stash apply –indexOn branch masterChanges to be committed: (use “git reset HEAD <file>…” to unstage) modified: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: b.mdUntracked files: (use “git add <file>…” to include in what will be committed) c.md加一个参数–index就会让工作区的归工作区,让暂存区的归暂存区。还有一点需要注意,恢复储藏的操作可以应用在任何分支,它也不关心即将恢复储藏的分支上,工作区和暂存区是否干净。如果有冲突,自行解决就是了。我们浏览过储藏列表,说明git stash apply仅仅是恢复了最新的那一次储藏。$ git stash apply stash@{1}指定储藏的名字,我们就可以恢复列表中的任意储藏了。这个时候我们再看一下储藏列表。$ git stash liststash@{0}: WIP on master: 974a2f2 applestash@{1}: WIP on master: c27b351 banana诶,发现还是两条。我不是已经恢复了一条么?apply这个词很巧妙,它只是应用,它可不会清理。清理想要清理储藏列表,咱们得显式的运行git stash drop命令。$ git stash drop stash@{1}$ git stash liststash@{0}: WIP on master: 974a2f2 apple现在就真的没有了。希望你没有喝酒????。git还给我们提供了一个快捷操作,运行git stash pop命令,同时恢复储藏和清理储藏。$ git stash pop10) view有四个git命令可以用来查看git仓库相关信息。statusgit status命令的作用是同时展示工作区和暂存区的diff、暂存区和当前版本的diff、以及没有被git追踪的文件。$ git statusOn branch masterChanges to be committed: (use “git reset HEAD <file>…” to unstage) modified: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: b.mdUntracked files: (use “git add <file>…” to include in what will be committed) c.md这个命令应该是最常用的git命令之一了,每次提交之前都要看一下。git status -v命令相当于git status命令和git diff –staged之和。$ git status -vOn branch masterChanges to be committed: (use “git reset HEAD <file>…” to unstage) modified: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: b.mdUntracked files: (use “git add <file>…” to include in what will be committed) c.mddiff –git a/a.md b/a.mdindex 5646a65..4c479de 100644— a/a.md+++ b/a.md@@ -1 +1 @@-apple+bananagit status -vv命令相当于git status命令和git diff之和。$ git status -vvOn branch masterChanges to be committed: (use “git reset HEAD <file>…” to unstage) modified: a.mdChanges not staged for commit: (use “git add <file>…” to update what will be committed) (use “git checkout – <file>…” to discard changes in working directory) modified: b.mdUntracked files: (use “git add <file>…” to include in what will be committed) c.mdChanges to be committed:diff –git c/a.md i/a.mdindex 5646a65..4c479de 100644— c/a.md+++ i/a.md@@ -1 +1 @@-apple+banana————————————————–Changes not staged for commit:diff –git i/b.md w/b.mdindex e69de29..637a09b 100644— i/b.md+++ w/b.md@@ -0,0 +1 @@+## git is awesome还有一个-s参数,给出的结果很有意思。$ git status -sM a.md M b.md?? c.md注意看,前面的字母位置是不一样的。第一个位置是该文件在暂存区的状态,第二个位置是该文件在工作区的状态。比如,以下信息显示a.md文件在暂存区有改动待提交,在工作区也有改动待暂存。MM a.md缩写的状态码主要有这么几种:状态码含义M文件内容有改动A文件被添加D文件被删除R文件被重命名C文件被复制U文件冲突未解决?文件未被git追踪!文件被git忽略?和!所代表的状态因为没有进入git版本系统,所以任何时候两个位置都是一样的。就像??或者!!这样。showgit show命令show的是什么呢?git对象。$ git showcommit 2bd3c9d7de54cec10f0896db9af04c90a41a8160Author: veedrin <veedrin@qq.com>Date: Fri Dec 28 11:23:27 2018 +0800 updatediff –git a/README.md b/README.mdindex e8ab145..75625ce 100644— a/README.md+++ b/README.md@@ -5,3 +5,5 @@ one two three++fourgit show相当于git show HEAD,显示当前HEAD指向的commit对象的信息。当然,你也可以查看某个git对象的信息,后面跟上git对象的校验和就行。$ git show 38728d8tree 38728d8README.mddiffgit diff命令可以显示两个主体之间的差异。工作区与暂存区的差异单纯的git diff命令显示工作区与暂存区之间的差异。$ git diffdiff –git a/a.md b/a.mdindex e69de29..5646a65 100644— a/a.md+++ b/a.md@@ -0,0 +1 @@+## git is awesome因为是两个主体之间的比较,git永远将两个主体分别命名为a和b。也可以只查看某个文件的diff。当然这里依然是工作区与暂存区之间的差异。$ git diff a.md暂存区与当前commit的差异git diff –staged命令显示暂存区与当前commit的差异。git diff –cached也可以达到相同的效果,它比较老,不如–staged语义化。$ git diff –stageddiff –git a/b.md b/b.mdindex e69de29..4c479de 100644— a/b.md+++ b/b.md@@ -0,0 +1 @@+apple同样,显示某个文件暂存区与当前commit的差异。$ git diff –staged a.md两个commit之间的差异我们还可以用git diff查看两个commit之间的差异。$ git diff C1 C2diff –git a/a.md b/a.mdindex e69de29..5646a65 100644— a/a.md+++ b/a.md@@ -0,0 +1 @@+## git is awesomediff –git a/b.md b/b.mdnew file mode 100644index 0000000..e69de29注意先后顺序很重要,假如我改一下顺序。$ git diff C2 C1diff –git a/a.md b/a.mdindex 5646a65..e69de29 100644— a/a.md+++ b/a.md@@ -1 +0,0 @@-## git is awesomediff –git a/b.md b/b.mddeleted file mode 100644index e69de29..0000000比较两个commit之间某个文件的差异。$ git diff C1:a.md C2:a.mddiff –git a/a.md b/a.mdindex e69de29..5646a65 100644— a/a.md+++ b/a.md@@ -0,0 +1 @@+## git is awesomeloggit log命令显示提交历史。$ git logcommit 7e2514419ec0f75d1557d3d8165a7e7969f08349Author: veedrin <veedrin@qq.com>Date: Sat Dec 29 11:56:53 2018 +0800 c.mdcommit 4d346773212b208380f71885979f93da65f07ea6Author: veedrin <veedrin@qq.com>Date: Sat Dec 29 11:56:41 2018 +0800 b.mdcommit cde34665b49033d7b8aed3a334c3e2db2200b4ddAuthor: veedrin <veedrin@qq.com>Date: Sat Dec 29 11:54:59 2018 +0800 a.md如果要查看每个commit具体的改动,添加-p参数,它是–patch的缩写。$ git log -pcommit 7e2514419ec0f75d1557d3d8165a7e7969f08349Author: veedrin <veedrin@qq.com>Date: Sat Dec 29 11:56:53 2018 +0800 c.mddiff –git a/c.md b/c.mdnew file mode 100644index 0000000..e69de29commit 4d346773212b208380f71885979f93da65f07ea6Author: veedrin <veedrin@qq.com>Date: Sat Dec 29 11:56:41 2018 +0800 b.mddiff –git a/b.md b/b.mdnew file mode 100644index 0000000..e69de29commit cde34665b49033d7b8aed3a334c3e2db2200b4ddAuthor: veedrin <veedrin@qq.com>Date: Sat Dec 29 11:54:59 2018 +0800 a.mddiff –git a/a.md b/a.mdnew file mode 100644index 0000000..e69de29你还可以控制显示最近几条。$ git log -p -1commit 7e2514419ec0f75d1557d3d8165a7e7969f08349Author: veedrin <veedrin@qq.com>Date: Sat Dec 29 11:56:53 2018 +0800 c.mddiff –git a/c.md b/c.mdnew file mode 100644index 0000000..e69de29-p有点过于冗余,只是想查看文件修改的统计信息的话,可以使用–stat参数。$ git log –statcommit 7e2514419ec0f75d1557d3d8165a7e7969f08349Author: veedrin <veedrin@qq.com>Date: Sat Dec 29 11:56:53 2018 +0800 c.md c.md | 0 1 file changed, 0 insertions(+), 0 deletions(-)commit 4d346773212b208380f71885979f93da65f07ea6Author: veedrin <veedrin@qq.com>Date: Sat Dec 29 11:56:41 2018 +0800 b.md b.md | 0 1 file changed, 0 insertions(+), 0 deletions(-)commit cde34665b49033d7b8aed3a334c3e2db2200b4ddAuthor: veedrin <veedrin@qq.com>Date: Sat Dec 29 11:54:59 2018 +0800 a.md a.md | 0 1 file changed, 0 insertions(+), 0 deletions(-)还觉得冗余?只想看提交说明,有一个–oneline可以帮到你。$ git log –oneline4ad50f6 (HEAD -> master) 添加c.md文件4d34677 添加b.md文件cde3466 添加a.md文件想在命令行工具看git提交历史的树形图表,用–graph参数。$ git log –graph* commit 7e2514419ec0f75d1557d3d8165a7e7969f08349 (HEAD -> master)| Author: veedrin <veedrin@qq.com>| Date: Sat Dec 29 11:56:53 2018 +0800| c.md* commit 4d346773212b208380f71885979f93da65f07ea6| Author: veedrin <veedrin@qq.com>| Date: Sat Dec 29 11:56:41 2018 +0800| b.md* commit cde34665b49033d7b8aed3a334c3e2db2200b4dd Author: veedrin <veedrin@qq.com> Date: Sat Dec 29 11:54:59 2018 +0800 a.md我知道你们肯定又觉得冗余,–graph和–oneline食用更佳哟。$ git log –graph –oneline* 7e25144 (HEAD -> master) c.md* 4d34677 b.md* cde3466 a.md11) position程序遇到bug的时候,我们需要快速定位。定位有两种,第一种是定位bug在哪个提交上,第二种是定位特定文件的某一行是谁最近提交的。bisect有时候我们发现程序有bug,但是回退几个版本都不解决问题。说明这个bug是一次很老的提交导致的,也不知道当时怎么就没察觉。那怎么办呢?继续一个一个版本的回退?估计Linus Torvalds会鄙视你吧。为了专注于工作,不分心来鄙视你,Linus Torvalds在git中内置了一套定位bug的命令。大家都玩过猜数字游戏吧。主持人悄悄写下一个数,给大家一个数字区间,然后大家轮流开始切割,谁切到主持人写的那个数就要自罚三杯了。对,这就是二分法。git利用二分法定位bug的命令是git bisect。使用假设目前的git项目历史是这样的。C0 – C1 – C2 – C3 – C4 – C5 – C6 – C7 – C8 – C9(HEAD -> master)这里面有一次commit藏了一个bug,但幸运的是,你不知道是哪一次。运行git bisect start命令,后跟你要定位的区间中最新的commit和最老的commit。$ git bisect start HEAD C0Bisecting: 4 revisions left to test after this (roughly 2 steps)[ee27077fdfc6c0c9281c1b7f6957ea2b59a461dd] C4然后你就发现HEAD指针自动的指向了C4commit。如果范围是奇数位,那取中间就行了,如果范围是偶数位,则取中间更偏老的那个commit,就比如这里的C4commit。$ git bisect goodBisecting: 2 revisions left to test after this (roughly 1 step)[97cc0e879dc09796bd56cfd7c3a54deb41e447f6] C6HEAD指针指向C4commit后,你应该运行一下程序,如果没问题,那说明有bug的提交在它之后。我们只需要告诉git当前commit以及更老的commit都是好的。然后HEAD指针就自动指向C6commit。继续在C6commit运行程序,结果复现了bug。说明问题就出在C6commit和C4commit之间。$ git bisect badBisecting: 0 revisions left to test after this (roughly 0 steps)[a7e09bd3eab7d1e824c0338233f358cafa682af0] C5将C6commit标记为bad之后,HEAD指针自动指向C5commit。再次运行程序,依然能复现bug。话不多说,标记C5commit为bad。$ git bisect bada7e09bd3eab7d1e824c0338233f358cafa682af0 is the first bad commit因为C4commit和C5commit之间已经不需要二分了,git会告诉你,C5commit是你标记为bad的最早的commit。问题就应该出在C5commit上。git bisect resetPrevious HEAD position was a7e09bd… C5Switched to branch ‘master’既然找到问题了,那就可以退出git bisect工具了。另外,git bisect old和git bisect good的效果相同,git bisect new和git bisect bad的效果相同,这是因为git考虑到,有时候开发者并不是想定位bug,只是想定位某个commit,这时候用good bad就会有点别扭。后悔git bisect确实很强大,但如果我已经bisect若干次,结果不小心把一个goodcommit标记为bad,或者相反,难道我要reset重来么?git bisect还有一个log命令,我们只需要保存bisect日志到一个文件,然后擦除文件中标记错误的日志,然后按新的日志重新开始bisect就好了。git bisect log > log.txt该命令的作用是将日志保存到log.txt文件中。看看log.txt文件中的内容。# bad: [4d5e75c7a9e6e65a168d6a2663e95b19da1e2b21] C9# good: [c2fa7ca426cac9990ba27466520677bf1780af97] add a.mdgit bisect start ‘HEAD’ ‘c2fa7ca426cac9990ba27466520677bf1780af97’# good: [ee27077fdfc6c0c9281c1b7f6957ea2b59a461dd] C4git bisect good ee27077fdfc6c0c9281c1b7f6957ea2b59a461dd# good: [97cc0e879dc09796bd56cfd7c3a54deb41e447f6] C6git bisect good 97cc0e879dc09796bd56cfd7c3a54deb41e447f6将标记错误的内容去掉。# bad: [4d5e75c7a9e6e65a168d6a2663e95b19da1e2b21] C9# good: [c2fa7ca426cac9990ba27466520677bf1780af97] add a.mdgit bisect start ‘HEAD’ ‘c2fa7ca426cac9990ba27466520677bf1780af97’# good: [ee27077fdfc6c0c9281c1b7f6957ea2b59a461dd] C4git bisect good ee27077fdfc6c0c9281c1b7f6957ea2b59a461dd然后运行git bisect replay log.txt命令。$ git bisect replay log.txtPrevious HEAD position was ad95ae3… C8Switched to branch ‘master’Bisecting: 4 revisions left to test after this (roughly 2 steps)[ee27077fdfc6c0c9281c1b7f6957ea2b59a461dd] C4Bisecting: 2 revisions left to test after this (roughly 1 step)[97cc0e879dc09796bd56cfd7c3a54deb41e447f6] C6git会根据log从头开始重新bisect,错误的标记就被擦除了。然后就是重新做人啦。blame一个充分协作的项目,每个文件可能都被多个人改动过。当出现问题的时候,大家希望快速的知道,某个文件的某一行是谁最后改动的,以便厘清责任。git blame就是这样一个命令。blame翻译成中文是归咎于,这个命令就是用来甩锅的。git blame只能作用于单个文件。$ git blame a.md705d9622 (veedrin 2018-12-25 10:09:04 +0800 1) 第一行74eff2ee (abby 2018-12-25 10:16:44 +0800 2) 第二行a65b29bd (bob 2018-12-25 10:17:02 +0800 3) 第三行ee27077f (veedrin 2018-12-25 10:19:05 +0800 4) 第四行a7e09bd3 (veedrin 2018-12-25 10:19:19 +0800 5) 第五行97cc0e87 (veedrin 2018-12-25 10:21:55 +0800 6) 第六行67029a81 (veedrin 2018-12-25 10:22:15 +0800 7) 第七行ad95ae3f (zhangsan 2018-12-25 10:23:20 +0800 8) 第八行4d5e75c7 (lisi 2018-12-25 10:23:37 +0800 9) 第九行它会把每一行的修改者信息都列出来。第一部分是commit哈希值,表示这一行的最近一次修改属于该次提交。第二部分是作者以及修改时间。第三部分是行的内容。如果文件太长,我们可以截取部分行。$ git blame -L 1,5 a.md705d9622 (veedrin 2018-12-25 10:09:04 +0800 1) 第一行74eff2ee (abby 2018-12-25 10:16:44 +0800 2) 第二行a65b29bd (bob 2018-12-25 10:17:02 +0800 3) 第三行ee27077f (veedrin 2018-12-25 10:19:05 +0800 4) 第四行a7e09bd3 (veedrin 2018-12-25 10:19:19 +0800 5) 第五行或者这样写。$ git blame -L 1,+4 a.md705d9622 (veedrin 2018-12-25 10:09:04 +0800 1) 第一行74eff2ee (abby 2018-12-25 10:16:44 +0800 2) 第二行a65b29bd (bob 2018-12-25 10:17:02 +0800 3) 第三行ee27077f (veedrin 2018-12-25 10:19:05 +0800 4) 第四行但是结果不是你预期的那样是吧。1,+4的确切意思是从1开始,显示4行。如果有人重名,可以显示邮箱来区分。添加参数-e或者–show-email即可。$ git blame -e a.md705d9622 (veedrin@qq.com 2018-12-25 10:09:04 +0800 1) 第一行74eff2ee (abby@qq.com 2018-12-25 10:16:44 +0800 2) 第二行a65b29bd (bob@qq.com 2018-12-25 10:17:02 +0800 3) 第三行ee27077f (veedrin@qq.com 2018-12-25 10:19:05 +0800 4) 第四行a7e09bd3 (veedrin@qq.com 2018-12-25 10:19:19 +0800 5) 第五行97cc0e87 (veedrin@qq.com 2018-12-25 10:21:55 +0800 6) 第六行67029a81 (veedrin@qq.com 2018-12-25 10:22:15 +0800 7) 第七行ad95ae3f (zhangsan@qq.com 2018-12-25 10:23:20 +0800 8) 第八行4d5e75c7 (lisi@qq.com 2018-12-25 10:23:37 +0800 9) 第九行12) taggit是一个版本管理工具,但在众多版本中,肯定有一些版本是比较重要的,这时候我们希望给这些特定的版本打上标签。比如发布一年以后,程序的各项功能都趋于稳定,可以在圣诞节发布v1.0版本。这个v1.0在git中就可以通过标签实现。而git标签又分为两种,轻量级标签和含附注标签。轻量级标签和分支的表现形式是一样的,仅仅是一个指向commit的指针而已。只不过它不能切换,一旦贴上就无法再挪动了。含附注标签才是我们理解的那种标签,它是一个独立的git对象。包含标签的名字,电子邮件地址和日期,以及标签说明。创建创建轻量级标签的命令很简单,运行git tag <tag name>。$ git tag v0.3在.git目录中就多了一个指针文件。.git/refs/tags/v0.3创建含附注标签要加一个参数-a,它是–annotated的缩写。$ git tag -a v1.0和git commit一样,如果不加-m参数,则会弹出默认或者自定义的编辑器,要求你写标签说明。不写呢?fatal: no tag message?创建完含附注标签后,.git目录会多出两个文件。.git/refs/tags/v0.3.git/objects/80/e79e91ce192e22a9fd860182da6649c4614ba1含附注标签不仅会创建一个指针,还会创建一个tag对象。我们了解过git有四种对象类型,tag类型是我们认识的最后一种。我们看看该对象的类型。$ git cat-file -t 80e79e9tag再来看看该对象的内容。$ git cat-file -p 80e79e9object 359fd95229532cd352aec43aada8e6cea68d87a9type committag v1.0tagger veedrin <veedrin@qq.com> 1545878480 +0800版本 v1.0它关联的是一个commit对象,包含标签的名称,打标签的人,打标签的时间以及标签说明。我可不可以给历史commit打标签呢?当然可以。$ git tag -a v1.0 36ff0f5只需在后面加上commit的校验和。查看查看当前git项目的标签列表,运行git tag命令不带任何参数即可。$ git tagv0.3v1.0注意git标签是按字母顺序排列的,而不是按时间顺序排列。而且我并没有找到分别查看轻量级标签和含附注标签的方法。查看标签详情可以使用git show <tag name>。$ git show v0.3commit 36ff0f58c8e6b6a441733e909dc95a6136a4f91b (tag: v0.3)Author: veedrin <veedrin@qq.com>Date: Thu Dec 27 11:08:09 2018 +0800 add a.mddiff –git a/a.md b/a.mdnew file mode 100644index 0000000..e69de29$ git show v1.0tag v1.0Tagger: veedrin <veedrin@qq.com>Date: Thu Dec 27 11:08:39 2018 +0800版本 v1.0commit 6dfdb65ce65b782a6cb57566bcc1141923059d2b (HEAD -> master, tag: v1.0)Author: veedrin <veedrin@qq.com>Date: Thu Dec 27 11:08:33 2018 +0800 add b.mddiff –git a/b.md b/b.mdnew file mode 100644index 0000000..e69de29删除虽然git标签不能移动对吧,但我们可以删除它呀。$ git tag -d v0.3Deleted tag ‘v0.3’ (was 36ff0f5)如果标签已经推送到了远端,也是可以删除的。$ git push origin -d v0.3To github.com:veedrin/git.git - [deleted] v0.3推送默认情况下,git push推送到远端仓库并不会将标签也推送上去。如果想将标签推送到远端与别人共享,我们得显式的运行命令git push origin <tag name>。$ git push origin v1.0Counting objects: 1, done.Writing objects: 100% (1/1), 160 bytes | 160.00 KiB/s, done.Total 1 (delta 0), reused 0 (delta 0)To github.com:veedrin/git.git * [new tag] v1.0 -> v1.0这里并不区分轻量级标签和含附注标签。一次性将本地标签推送到远端仓库也是可以的。$ git push origin –tags13) remotegit是分布式版本管理工具,它没有中央仓库。但多人协作时,我们依然需要一个集散地,让协作成员之间统一往集散地推送和拉取更新。否则,点对点的沟通,效率会很低。所以就引出了git中远端仓库的概念。概念我们之前所有的操作都是在本地仓库完成的,和本地仓库对应的是远端仓库。那么本地有若干分支,远端仓库是不是也有对应的若干分支呢?当然。我们探讨一个问题,在离线状态下,git是不是无从知道远端仓库的任何状态?我让网络下线,查询从github克隆下来的本地仓库的状态,结果它告诉我本地仓库的master分支是up to date with ‘origin/master’。$ git statusOn branch masterYour branch is up to date with ‘origin/master’.nothing to commit, working tree clean实际上,git的分支有三种:本地分支,我们可以通过<branch>写法访问它。远端分支,我们可以通过<remote branch>写法访问它。远端分支引用,我们可以通过<remote/branch>写法访问它。实际上它也是本地分支,只不过我们无法操作它,只有git的网络操作才可以更新它。离线状态下,git给的状态就是本地分支和远端分支引用的比较结果。git官方把我所说的远端分支引用称为远端分支。知道谁是谁就行了,名字不重要????我是马蹄疾我们看一下本地的远端分支引用。.git/.git/refs/.git/refs/remotes/.git/refs/remotes/origin/.git/refs/remotes/origin/HEAD.git/refs/remotes/origin/master默认的远端仓库名就叫origin。它也有master分支指针,也有HEAD指针。拉取如果远端仓库有新的提交或者新的分支,我们需要运行git fetch命令来拉取更新。$ git fetchremote: Enumerating objects: 5, done.remote: Counting objects: 100% (5/5), done.remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0Unpacking objects: 100% (3/3), done.From github.com:veedrin/git 3893459..0f80eeb master -> origin/master这个命令是git fetch origin的缩写。因为origin是远端仓库的默认名称,所以可以省略。如果有手动添加的远端仓库,那就必须指定远端仓库的名称了。这个命令做了什么呢?它会把新的提交和新的分支拉取到本地,然后更新本地的远端分支引用到最新的提交。git fetch仅仅是将远端的更新拉取下来,同步本地的远端分支引用,不会对本地分支有任何影响。我们需要手动执行合并操作才能更新本地分支。$ git merge origin/masterOn branch masterYour branch is up to date with ‘origin/master’.nothing to commit, working tree clean当然,有一个更简单的操作。$ git pullremote: Enumerating objects: 5, done.remote: Counting objects: 100% (5/5), done.Unpacking objects: 100% (3/3), done.remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0From github.com:veedrin/git 4fbd1d4..d9785d7 master -> origin/masterUpdating 4fbd1d4..d9785d7Fast-forward README.md | 2 ++ 1 file changed, 2 insertions(+)git pull就是git fetch和git merge的一键操作。推送推送到远端的命令是git push <remote-name> <remote-branch-name>。$ git push origin masterCounting objects: 3, done.Writing objects: 100% (3/3), 261 bytes | 261.00 KiB/s, done.Total 3 (delta 0), reused 0 (delta 0)To github.com:veedrin/git.git 3eaa1ae..2bd3c9d master -> master如果当前分支对远端分支设置了追踪的话,也可以省略分支名。$ git pushCounting objects: 3, done.Writing objects: 100% (3/3), 261 bytes | 261.00 KiB/s, done.Total 3 (delta 0), reused 0 (delta 0)To github.com:veedrin/git.git 3eaa1ae..2bd3c9d master -> master有时候本地分支和远端分支同时有新的提交,直接push是不行的。$ git pushTo github.com:veedrin/git.git ! [rejected] master -> master (fetch first)error: failed to push some refs to ‘git@github.com:veedrin/git.git’hint: Updates were rejected because the remote contains work that you dohint: not have locally. This is usually caused by another repository pushinghint: to the same ref. You may want to first integrate the remote changeshint: (e.g., ‘git pull …’) before pushing again.hint: See the ‘Note about fast-forwards’ in ‘git push –help’ for details.有两种方式解决。第一是先把远端的更新拉下来,有冲突则解决冲突,没冲突则再推送。第二是强推。有时候我们就是想覆盖远端对吧,也不是不行,但是必须十分谨慎。而且不要在公共分支上强制推送。$ git push -fCounting objects: 24, done.Delta compression using up to 4 threads.Compressing objects: 100% (8/8), done.Writing objects: 100% (24/24), 3.72 KiB | 1.24 MiB/s, done.Total 24 (delta 0), reused 3 (delta 0)To github.com:veedrin/git.git + 54d741b…2db10e0 master -> master (forced update)实际开发时我们会建很多特性分支,推送到远端,通过测试后再合入主分支。使用git push <remote-name> <remote-branch-name>每次都要指定远端分支名,如果会有多次推送,我们可以在推送时设置本地分支追踪远端分支,这样下次就可以直接推送了。也可以简写成git push -u <remote-name> <remote-branch-name>。$ git push –set-upstream origin devCounting objects: 3, done.Delta compression using up to 4 threads.Compressing objects: 100% (2/2), done.Writing objects: 100% (3/3), 255 bytes | 255.00 KiB/s, done.Total 3 (delta 0), reused 0 (delta 0)remote: remote: Create a pull request for ‘dev’ on GitHub by visiting:remote: https://github.com/veedrin/git/pull/new/devremote: To github.com:veedrin/git.git * [new branch] dev -> devBranch ‘dev’ set up to track remote branch ‘dev’ from ‘origin’.然后我们在.git/config文件中能看到多了一条配置。[branch “dev”] remote = origin merge = refs/heads/dev查看查看远端仓库的命令是git remote。$ git remoteorigin加-v参数可以查看更为详细的信息,-v是–verbose的缩写。$ git remote -vorigin git@github.com:veedrin/git.git (fetch)origin git@github.com:veedrin/git.git (push)查看某个远端仓库的信息,可以使用命令git remote show <remote-name>。$ git remote show origin* remote origin Fetch URL: git@github.com:veedrin/git-1.git Push URL: git@github.com:veedrin/git-1.git HEAD branch: master Remote branches: dev tracked master tracked Local branches configured for ‘git pull’: dev merges with remote dev master merges with remote master Local refs configured for ‘git push’: master pushes to master (up to date)添加添加新的远端仓库,使用git remote add <shortname> <url>命令。$ git remote add horseshoe https://github.com/veedrin/horseshoe然后本地就多了一个远端仓库。$ git remotehorseshoeorigin除了添加远端仓库,我们还可以添加本地分支对远端分支的追踪。$ git checkout -b dev origin/devBranch ‘dev’ set up to track remote branch ‘dev’ from ‘origin’.Switched to a new branch ‘dev’创建dev分支的同时,也设置了对远端分支dev的追踪,这样下次推送的时候就不需要指定了。当然,远端分支引用必须得存在才行。$ git checkout -b dev origin/devfatal: ‘origin/dev’ is not a commit and a branch ‘dev’ cannot be created from itgit也提供了快捷方式。$ git checkout –track origin/devBranch ‘dev’ set up to track remote branch ‘dev’ from ‘origin’.Switched to a new branch ‘dev’重命名有时候你想修改远端仓库的简写名。比如你将女朋友的名字命名为远端仓库的简写名,然后你们分手了。这真是一个令人悲伤(欣喜)的故事。$ git remote rename nvpengyou gaoyuanyuan查看远端仓库列表。$ git remotegaoyuanyuanorigin删除一般来说,一个git项目有一个远端仓库就行了,其余的大多是临时性的。所以总有一天要删除它。$ git remote rm horseshoe查看远端仓库列表。$ git remoteorigin本文是『horseshoe·Git专题』系列文章之一,后续会有更多专题推出GitHub地址(持续更新):https://github.com/veedrin/horseshoe博客地址(文章排版真的很漂亮):https://veedrin.com如果觉得对你有帮助,欢迎来GitHub点Star或者来我的博客亲口告诉我Git专题一览???? add???? commit???? branch???? checkout???? merge???? rebase???? reset???? revert???? stash???? view???? position???? tag???? remote ...

January 8, 2019 · 21 min · jiezi

elementUI源码修改的爬坑之旅

今天由于项目需要,想在Tree组件的前面增加一个icon图标,根据不同类型增加不同的图标,我修改了elementUI的源代码,发布到npm上去成功使用,记录下过程中所碰到的问题,首先看下最后的效果:下面简单记录下过程和过程中所遇到的问题以及问题的解决方案。首先把elementUI的项目从git上克隆下来:git clone https://github.com/ElemeFE/element.git克隆完成后就会看到有个名叫element的文件夹出现:然后进入element文件夹:cd element安装相关的依赖:npm install第一步已经完成。修改源码,我修改的部分在packages里面,我修改完成后执行:npm run dist就会生成一个lib文件夹,这部分是我们调试用的,刚克隆下来没有run dist之前是没有lib文件夹的,我修改完源码之后,运行run dist 后将生产的lib文件夹拷贝到项目中的node_modules中的element-ui文件夹中去,效果OK。3.上传npm 包。第一次是在网上看大佬说只需要修改里面的config.js文件里面的名字和package.json里面的包名就可以了,我修改了之后上传后结果是报了40多个路径错误,找不到这个找不到那个,看的我是一脸懵。然后我的解决方案是全局全词匹配到element-ui之后进行全局替换为我设置的包名。说下上传包步骤,首先进入element文件夹之后执行:npm init 然后登陆下(没有账户的注册账户):npm login依次根据提示输入username、password、e-mail其他的都可以敲回车完事(记得改element文件夹中package.json文件中的包名和版本号啊)。需要强调的是包名不能重复,不然npm会给你报一堆乱七八糟的错误。最后进行上传:npm publishok上传完成(要是报各种看不懂的错误很大可能是包名重复)。4.到项目中将项目中的package.json中的dependencies中的:“element-ui”: “^2.4.11"修改为:“你的包名”: “^你的版本号”。然后进行依赖安装:npm install 启动项目,效果OK。有不对的地方,各位路过的大佬多多指教。

January 7, 2019 · 1 min · jiezi

GIt 常用命令学习笔记

GIT命令创建和编辑文件mkdir “name” 创建文件vi(visual interface) “name” 编辑文件,也可创建i(Insert mode) 切换到编辑模式esc 退出编辑模式:wq(write and quite) enter 保存并退出编辑创建本地仓git init 创建本地仓mkdir learngit 创建文件夹git add readme.md 创建文件添加到暂存区git add *** 添加指定文件到暂存区git add -A 添加所有内容git add . 添加新增和编辑的内容,不包括删除的文件git add -u 添加编辑和删除的文件,不添加新增文件关联远程仓git remote add origin “address” 关联远程仓git push -u origin master 初始推送至远程仓git push origin master 推送新修改git clone “address” 克隆git remote -v 查看关联信息git pull 推送失败,先抓取远程的新提交版本回退git reset –hard HEAD^ 回退到上一次commit的版本 (注意本地文件可能会被删除)git reset –soft HEAD^ 回退到提交之前,add之后的版本 git reset –hard “codeNum” 回退到指定commit版本git log 查看commit的历史版本记录git reflog 查看命令历史记录,包括回退命令分支git branch 查看分支git branch “name” 创建分支git checkout “name” 切换到指定分支git checkout -b “name” 切换并创建分支初始创建分支后,此时分支还在本地,推送到远程仓需要以下命令:1. git add …2. git commit -m ‘…‘3. git push -u origin “name”,此时分支同步到远程4. git push 此后可以只用push合并和删除分支git merge “branch name” 合并指定分支到当前分支git branch -d “branch name” 删除本地分支git branch -D “name” 强行删除git push origin -d “branch name” 删除远程分支准备合并dev分支,请注意–no-ff参数,表示禁用Fast forward:git merge –no-ff -m “merge with no-ff” dev 标签git tag 查看所有标签git tag “tagname” 用于新建一个标签,默认为 HEAD,也可以知道一个 commit.idgit tag -a “tagname” -m “aaaa” 可以指定标签信息 ...

January 7, 2019 · 1 min · jiezi

git切换分支时,会将未add或未commit的内容切换过去

使用Git时,当前在B分支,B继承自A,修改了一些文件;现需要在A分支修改东西,使用git checkout A,但是此时会将在B分支时修改的东西,带过来,讲过查资料,思路理下,以作记录。一、git基本概念,资料来源于 廖雪峰git1.工作区、缓存区git有工作区、缓存区的概念,工作区即为自身本地的相应文件夹,通过git add命令后,即可将文件放置缓存区;继而通过git commit即可将文件放置于相对应的git分支;2.判断当前文件是在什么区间通过git status,可以判断当前文件所属位置;出现 Untracked files,代表当前文件出在工作区,还未进入缓存区出现new file modified等,代表文件在缓存区,还未进入当前所在分支二、工作区和缓存区内容是公共的,不从属于任何一个分支,资料来源于 这里问题出现的内容就是因为,我没有add ,而工作区和缓存区内容是公共的,不从属于任何一个分支,所以切换到A分支时,仍然将修改的东西带过去了;当既想要在切换分支,又不想add时,可以使用git stash,当使用了git stash后,在其他分支仍然可以通过git stash pop找出来本人也是git新手,如有疑问,非常欢迎留言指正,谢谢

January 7, 2019 · 1 min · jiezi

Windows使用技巧

(持续更新中…)喜欢的Windows软件vscode跨平台轻量IDE,有强大的插件市场chrome前端开发必备浏览器,不多说xshellssh免密快捷登录神器;高级版的是付费的,教育版免费,足以在大部分场景下使用,xShell教育版下载地址scoop安装软件的神器;确保PowerShell已经安装,执行以下命令即可安装scoop:iex (new-object net.webclient).downloadstring(‘https://get.scoop.sh’)scoop安装完成后,就可以使用命令行快速安装程序了,大多数程序安装不需要管理员权限,并且可以自动配置环境变量,例如:scoop install yarnscoop install pythonscoop install curlscoop官网sourcetree跨平台的git可视化管理工具https://www.sourcetreeapp.com/github desktopgithub官方的git工具cmder强大而美观的cli工具http://cmder.net/teamviewer远程控制软件,方便在家远程连公司网络办公,下载地址zoom远程会议,远程桌面演示必备Win10使用技巧截屏/录屏按win+g,可以开启游戏模式,这个模式下会有录屏工具出现点击黑色圆圈可以开始录屏,录屏完成后的视频文件会自动保存到视频/捕获文件夹中手机离开电脑自动锁定电脑需要蓝牙支持

January 7, 2019 · 1 min · jiezi

git常见问题解决

记录在开发过程中遇到的git问题,边解决问题边学习,常见的命令后续找时间再补充,尽量写一个完整的教程。git处理冲突当拉取下来的文件与本地修改的文件有冲突,先提交你的改变,或者先将你的改变暂时存储起来1、将本地修改存储起来git stash2、pull内容 git pull3、还原暂存的内容git stash pop stash@{0}也可以简写git stash pop参考:https://www.cnblogs.com/wteam…git另一个进程还在运行问题描述出现这种情况可能是git在执行的过程中,你中止之后异常,进程一直停留Another git process seems to be running in this repository, e.g.an editor opened by ‘git commit’. Please make sure all processesare terminated then try again. If it still fails, a git processmay have crashed in this repository earlier:remove the file manually to continue.问题原因因为进程的互斥,所以资源被上锁,但是由于进程突然崩溃,所以未来得及解锁,导致其他进程访问不了。问题解决打开隐藏文件夹选项,进入工作区文件目录的隐藏文件.git,把其中的index.lock问价删除掉

January 6, 2019 · 1 min · jiezi

Git仓库代码以及提交记录迁移

背景需求项目的后台是用Node开发,仓库迁移需求如下:1、代码以及提交仓库迁移至新仓库。2、生产服务器上的项目远程仓库更换为新仓库,无需重新部署。1、代码以及迁移首先我们先建好一个新的远程仓库,之后我们需要把代码和commit记录都提交到这个仓库上了。# 本地创建新项目$ mkdir new-project# 克隆旧仓库代码git clone git@old_repository.git# 远端仓库重新命名git remote rename origin old-origin# 添加新的远程仓库git remote add origin git@new_repository.git# 推送代码以、提交记录、标签到新仓库,并指定origin(新仓库)为默认主机# –all: 推送所有分支# –tags: 推送所有本地新增的标签;默认情况下,git push并不会把标签传送到远端服务器上git push -u origin –allgit push -u origin –tags2、服务器更换远程仓库地址# 重设远程仓库地址git remote set-url origin git@new_repository.git# 查看当前远程仓库地址git remote -v

January 5, 2019 · 1 min · jiezi

git 快速入门

git命令也是比较多的,命令的参数也是非常丰富的,下面我只是列举了一些常用的命令,让新手们能够在工作中快速使用git常用配置git config –global color.ui true //设置颜色git config –global user.name “brandon.chen"git config core.filemode false //忽略权限变更git config –global core.autocrlf falsegit config –global core.safecrlf true //为了保证文件的换行符是以安全的方法,避免windows与unix的换行符混用的情况,最好也加上这么一句常用操作git clone 仓库地址 //克隆一个仓库git add 文件,文件 //添加提交的文件git commit -m “描述” //提交描述 git diff //查看文件改的内容git log //查看提交记录git checkout <branch.name> //切换分支git checkout -b <branch.name> //从当前分支复制一个新分支git push origin <branch.name>:<branch.name> //把本地分支推送到远程git push origin :<branch.name> //可以删除 远程分支git pull origin dev //拉取合并远程分支相当于 git fetch origin <branch.name>(拉取) + git merge origin <branch.name>(合并)git branch -d <branch.name> //删除本地分支git push origin –delete <branch.name> //删除远程分支常用扩展git reset HEAD –<file> //回退缓存区的某一个文件git reset –hard HEAD~1 //回到上一次提交git reset –hard id //完成撤销,同时将代码恢复到前一commit_id 对应的版本保存当前工作git stash save “临时保存” 修改内容本地化保存git stash clear //清除所有的暂存(谨慎使用)git stash list //列表保存工作git stash pop //弹出工作扩展git diff [branchA] [branchB] >>diff.diff //会在当前目录下生成一个.diff 文件git log branchA ^branchB //比较A分支中有B分支没有的提交记录git merge –no-ff://不使用fast-forward方式合并,保留分支的commit历史–squash://使用squash方式合并,把多次分支commit历史压缩为一次git log –oneline //查看本地缓存区存储的信息 ID ...

January 5, 2019 · 1 min · jiezi

Centos下搭建git

1.首先安装git,使用yum在线安装[root@localhost ~]# yum install -y git[root@localhost ~]# git –versiongit version 1.7.12.创建一个git用户,来运行git服务[root@localhost home]#adduser git 或者可以使用[root@localhost home]# useradd git [root@localhost home]# passwd git3.创建空仓库cd /home/gitmkdir project.gitcd project.gitgit init –barecd ..chown -R git:git project.git/4.在服务器端开RSA认证 vim /etc/ssh/sshd_config修改以下三个选项并重启RSAAuthentication yesPubkeyAuthentication yesAuthorizedKeysFile .ssh/authorized_keys 重启命令-> systemctl restart sshd.service这里我们所知的是.ssh/authorized_keys这个是公钥存储的地方,是在/home/git/下的.ssh/下存放,实际目录/home/git/.ssh/authorized_keys。如果需要免密登录,需要将自己客户端的id_rsa.pub公钥填写进去改文件(一行一个),如果该文件不存在则自行创建 并且修改权限 为600 例:如我的用户为git来管理git服务器 则还需要将 该文件的拥有者和群组修改 chown git:git authorized_keys5.客户端clone格式:git clone 用户名@xxx.xxx.xx.xx:/home/git/初始化仓库目录文件例子:git clone git@192.168.0.109:/home/git/project.git如果需要免密登录则看上栏配置,与ssh建立信任总结:免密登录是个坑,多半免密登录不了的都是权限没有调整好或没开启RSA认证,仅以此文件避免日后踩坑

January 3, 2019 · 1 min · jiezi

git常用命令学习

学习于https://www.cnblogs.com/chenw…

January 3, 2019 · 1 min · jiezi

Git 小记

Git用master指向最新的提交,再用HEAD指向master.Git鼓励大量使用分支:查看分支:git branch创建分支:git branch <name>切换分支:git checkout <name>创建+切换分支:git checkout -b <name>合并某分支到当前分支:git merge <name>删除分支:git branch -d <name>loggit log –graph 命令可以看到分支合并图git reflog 记录git历史命令暂存git stash 隐藏文件git stash listgit stash pop 拉取最近的远程分支(本地分支push到远程):创建远程分支:git push origin [name]删除远程分支:$ git push origin :[name] (冒号后面没有空格)关联分支:git branch –set-upstream-to=origin/f_test

January 3, 2019 · 1 min · jiezi

在 CentOS 7 上搭建 Jenkins + Maven + Git 持续集成环境

本文以部署 Spring boot + Maven 项目为例,使用码云作为代码托管仓库,在 CentOS 7 上搭建 Jenkins 持续集成环境。1. 准备工作1.1 安装 Java 环境Jenkins 是基于 Java 开发的持续集成工具,需要在 Java 环境下运行。用下面命令查看系统是否已安装 Java:yum list installed | grep jdk如果没有,使用 yum search 命令查找 openjdk 版本,选择合适的 jdk 进行安装:yum search openjdk yum -y install java-1.8.0-openjdk-devel验证 Java 是否安装成功:java -version1.2 安装 Maven依次运行以下两条命令:wget http://repos.fedorapeople.org… -O /etc/yum.repos.d/epel-apache-maven.repo yum -y install apache-maven验证 Maven 是否安装成功:mvn -v1.3 安装 Git直接通过 yum 安装,安装完成后查看版本验证是否安装成功:yum -y install git git –version2. 安装和配置 Jenkins:2.1 安装 Jenkins依次运行以下三条命令:sudo wget https://pkg.jenkins.io/redhat… -O /etc/yum.repos.d/jenkins.repo sudo rpm –import https://pkg.jenkins.io/redhat… yum -y install jenkins如果之前从 Jenkins 导入过 key,那么 rpm –import 将失败,因为已经有一个 key 了。忽略它,继续执行 install 即可。2.2 启动 Jenkins启动 Jenkins,并且设置开机自启动:systemctl start jenkins.service chkconfig jenkins onJenkins 默认使用8080端口,访问以下链接即可看到 Jenkins 的 Web 界面:http://&lt;服务器地址>:8080如果无法访问,检查一下防护墙,是否有开放端口,或使用命令 netstat -ntulp 查看端口是否被占用。2.3 进入 Jenkins首次进入 Jenkins 需要输入管理员密码,使用以下命令查看初始密码:cat /var/lib/jenkins/secrets/initialAdminPassword选择默认的 install suggested plugins 安装插件,等待安装完成后依照步骤创建用户,创建完成后即可登入。2.4 配置 Jenkins进入 Manage Jenkins -> Global Tool Configuration,依次配置 JDK、Git 和 Maven 路径。2.4.1 查看 JDK 路径使用 yum 安装的软件不会帮我们配置环境变量,直接使用命令echo $JAVA_HOME 是看不到路径的。 先用以下命令查看路径:which java看到的结果是 /usr/bin/java ,但实际上这只是个软连接,并不是 JDK 真正的所在目录。 继续使用以下命令查看:ls -l /usr/bin/java看到 /usr/bin/java 指向了 /etc/alternatives/java,很遗憾,还不是我们要找的真正路径。 继续追踪:ls -l /etc/alternatives/java结果指向了 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-1.el7_6.x86_64/jre/bin/java,不同版本的 JDK 目录名可能有些不同,这就是 JDK 真正所在的地方。 同理可获得 Maven 的所在路径。2.4.2 安装和配置插件进入 Manage Jenkins -> Manage Plugins,搜索并安装 Publish Over SSH 和 Maven Integration 两个插件, Git Plugins 插件已经默认安装上了,我们无需再安装。配置 SSH 免密码登录 在配置插件之前,我们先在 Jenkins 服务器上生成密钥对。运行以下命令切换到 jenkins 用户:sudo su jenkins如果无法切换,则打开 /etc/passwd 文件,找到 jenkins 那一行,将 /bin/fasle 改成 /bin/bash。 切换成功后,命令提示符的用户名可能是 bash-4.2$,想要正常显示用户名的话,先切换回 root 用户,执行以下操作:编辑文件 vi /.bash_profile 加入语句 export PS1=’[u@h W]&dollar;’ 立即生效 source /.bash_profile再切换到 jenkins 用户,就显示正常了。接下来运行以下命令生成密钥对:ssh-keygen -t rsa一路按回车完成,会在 /var/lib/jenkins/.ssh/ 目录下生成 id_rsa 和 id_rsa.pub两个文件。 将 id_rsa.pub 文件里的内容追加到应用服务器上的 /root/.ssh/authorized_keys 文件末尾,每行一个 key,注意是应用服务器。重启应用服务器上的 ssh 服务:systemctl restart sshd.service现在 Jenkins 可以免密码登录应用服务器了,以 jenkins 用户身份运行命令来测试一下:ssh root@<应用服务器地址>首次连接会有确认提示,输入 yes 即可。这步很重要,如果第一次没有手动连接确认,Jenkins 会连不上。配置 Public over SSH 插件 进入 Manage Jenkins -> Configure System,填写 Publish over SSH 设置。Path to key:填写刚刚生成的 id_rsa 密钥文件的路径。 Name:服务名,随意填写。 HostName:应用服务器的 IP 地址或域名。 Username:登录应用服务器的用户身份。 Remote Directory:远程目录, 应用服务器上存放应用的目录,Jenkins 会把应用拷贝至此目录下。请确保此目录存在。save3. 部署 Maven 项目点击 New Item 新建任务,随意输入任务名,选择 Maven project, ok。 在General,勾选 Discard old builds,可以设置最多保留构建文件多少天,和最多保留多少个构建文件,不然每次构建生成的文件都会保留,占用磁盘空间。 配置远程代码仓库地址,Jenkins 会从该地址拉取代码。注意此处如果提示无法读取仓库,有可能是:公钥没有添加到远程代码服务器的 authorized_keys 文件里,上面配置 SSH 免登录是 Jenkins 访问应用服务器的,Jenkins 访问代码服务器也同样需要配置,除非应用服务器和代码服务器是同一台机器。如果使用码云或 GitHub 等代码托管平台,会有相应的 SSH key 设置页。公钥已添加到相应文件里,但没有手动连接第一次。解决方法很简单,以 jenkins 用户身份手动 clone 一次仓库,确认 yes 即可。勾选 Add timestamps to the Console Output,在控制台输出构建过程。填写 Maven 打包指令,-DMaven.test.skip=true 表示跳过测试。勾选 Run only if build succeeds,选择 Send files or execute commands over SSH。接下来就是设置 build 完之后,把 jar 包从 Jenkins 服务器拷贝到应用服务器上,并运行。Name:选择之前创建的服务。 Source files:maven 打包后生成的 jar 包,即要拷贝到应用服务器运行的程序,可填多个,英文逗号分隔。 Remove prefix:忽略前缀,我们只需要拷贝 target 下的 jar 包,不需要在应用服务器上生成 target 目录。 Remote directory:目标文件夹,会继承全局设置,例如此处会把 jar 包拷贝到 /usr/local/app/demo 目录下。 Exec command:拷贝完成后,在应用服务器上执行的命令或脚本。save -> build now,构建成功后,打开浏览器访问你的站点吧4. 总结其实整个流程不是很复杂,Jenkins 从远程代码库拉取代码 -> 调用 maven 指令将项目打包 -> Jenkins 将打包好的文件拷贝到远程应用服务器 -> 在远程应用服务器上执行 shell 指令,启动程序。其中 Jenkins 两次远程操作都是通过 SSH 完成的。 通过 yum 安装 Jenkins 和 Java 比较方便,但是在配置的时候相对麻烦,安装路径要自己找,配置 SSH 的时候也是要用 jenkins 用户身份,而不是 root,如果采用解压缩包的方式就比较自由一些。 ...

January 3, 2019 · 2 min · jiezi

git (v2.18.0) error setting certificate

git pull时提示:fatal: unable to access ‘https://xxx/xxx/xxx.git/’: error setting certificate verify locations: CAfile: C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crt CApath: none通过搜索发现ca-bundle.crt真是的目录是C:/soft/Git/mingw64/ssl/certs/ca-bundle.crt因此需要修改gitconfig的文件C:\soft\Git\mingw64\etc\gitconfig最终将sslCAInfo修改成ca-bundle.crt的位置后, git pull 成功[http] sslCAInfo = C:/soft/Git/mingw64/ssl/certs/ca-bundle.crt sslBackend = openssl[diff “astextplain”] textconv = astextplain[filter “lfs”] clean = git-lfs clean – %f smudge = git-lfs smudge – %f process = git-lfs filter-process required = true[credential] helper = manager

January 3, 2019 · 1 min · jiezi

Git常用命令总结

常用的git命令git init git 初始化git config –global user.name “xxx” 配置用户名git config –global user.email “xxx@xxx.com” 配置邮件git add git add . 把所有变化提到暂存区 git add xxx 把制定文件提到暂存区git status 查看当前文件状态git commit -m "" 提交更新git commit -am ‘xxx’ 将add和commit合为一步, 但只能cover到已被track的文件git show commit_id 显示某个提交的详细内容git log 查看commit日志git reset –hard commit_id 回退到某个commitgit revert commit_id 进入到某个commit的代码,并生成新的commitgit remote -v 查看本地关联的远程仓库git remote add xxx 地址 关联远程仓库,名字为xxxgit remote rename oldname newname 修改远程仓库的名字git remote rm name 删除名字为name的远程仓库的关联git pull name branch 拉取名字为name的远程仓库的branch分支git push name branch 推送名字为name的远程仓库的branch分支git checkout -b branch [remote/master] 新建并进入一个名字为branch的分支 可选参数指在某个分支基础上新建git checkout branch 切到名字为branch的分支git branch -D branch 删除名字为branch的分支git branch -a 查看所有分支 包括本地和远程git clone 地址 克隆项目到本地git fetch [name] [branch] 将获取远程仓库的更新取回本地,取回的代码对本地的开发代码没有影响,无参数时默认取所有git merge branch 把branch分支合并到当前分支git push name :branch 删除名字为name的远程的branch分支git rebase -i HEAD~x 或 git rebase -i commi_id (commi_id不参与合并的) 合并多个commit, pick改为s, 如有冲突,解决以后继续 git add . git rebase –continue 取消合并 git rebase –abortgit tag name [commit_id] 增加名字为name的tag, commit_id制定commit处打taggit tag 查看所有tag,按字母排序git tag -d name 删除名字为name的taggit push origin tagname 把名字为tagname的tag推到远程git push –tags 把所有tag推送到远程仓库git push origin :refs/tags/<tagname> 删除远程tag ...

January 2, 2019 · 1 min · jiezi

树莓派搭建git服务器并实现公网访问(二)共2篇—安装git

在某商活动期间购买的云服务器一年当时300多块软妹币,到期后续费要800多。感觉太贵!!平时该服务器主要用做个人svn服务器,利用率比较低,如果买便宜的新机器总是迁移文件也挺烦人的,综合考虑下就不想再续了,正好手里有一台树莓派可以派上用场了。树莓派挂载移动硬盘,并安装git服务,代码到时都上传到移动硬盘里。一、挂载移动硬盘将移动硬盘插好后dh -h 查看当前磁盘设备,笔者的移动硬盘设备名为/dev/sda1,容量1T 笔者的移动硬盘为ntfs格式,为了使centos系统能正常挂载磁盘需要先安装ntfs-3g下载地址:http://www.linuxfromscratch.o…安装略…挂载命令如下:mount -t ntfs-3g /dev/sda1 /mnt/disk1 #/mnt/disk1为挂载的系统目录设置开机自动挂载:更改/etc/fstab,更改前备份下 cp /etc/fstab /etc/fstab.bak/dev/sda1 /mnt/windows ntfs-3g defaults 0 0二、安装git注意:笔者挂载的移动硬盘为ntfs格式的缘故只能root用户访问,首先在root目录下建立到移动硬盘git目录下的软链接ln -s /mnt/disk1/git /rootgit具体安装步骤略,具体请参照网上其他出处…安装完后cd /root/git在该目录下进行仓库初始化操作git init –bare dev.git三、访问树莓派上的git服务参照前一篇文章安装好frp后,我们可以通过公网使用ssh的方式访问我们树莓派上的git服务了!git clone ssh://root@请填写服务器ip地址:6001/root/git/dev.git大功告成!如果觉得移动硬盘ntfs格式不好做权限控制使用不便可以改为fat32格式

December 31, 2018 · 1 min · jiezi

分离头指针

在使用 git 时,会冷不丁弹出一些术语,在之前可能没有听过,突然之间心情就紧张起来了。其中就有一个分离头指针(detacged HEAD)分离头指针有时你在切换分支时,输了一个commit信息git 给你的提示,你现在正在基于这个commit做操作。你现在正处在分离头指针状态,你可以做一些变更然后产生commit,你也可以把生成的commit丢弃掉。也就是说你在分离头指针状态下,可以继续开发,但不影响其他开发,它的本意是:现在正在工作在没有分支的状态下。下面具体演示下分离头指针的操作。现在修改了 style/style.css 文件,并且commit了这时候用git log查看历史信息时,发现之前HEAD这变都会指向一个分支,然而这边却没有。这个就叫分离头指针状态假设这是你接到了一个任务,需要切换分支它会有一个警告说:现在有一个commit没有加到分支上去。也就是说这个commit一会会被垃圾清理掉。我们可以gitk –all来查看有没有add main的commit信息。从上图可以看出,这个commit没有和某个分支绑着,也没有和某个tag绑着,在 git 眼里,这种commit日后都是要被清除的。假如这个时候我醒悟过来了,觉得这个commit很重要,按照它的指示信息建一个分支,将它保留下来。此时你可以看到add main的commit被保留了下来。如果你想要添加到某个分支上,再用merge比如你想添加到master分支上,将HEAD切换到master分支,然后用git merge css,就将这次commit添加到master上了。进一步理解 HEAD 和 branchgit ckeckout -b fix_bug temp //新分支git diff commit信息 commit信息 //比较两个 commit 之间的差异git diff HEAD HEAD^ //等价于下面这条命令git diff HEAD HEAD~1 //等价于上面这条命令

December 29, 2018 · 1 min · jiezi

git常用命令与使用场景

git常用命令按照日常使用场景编写命令组pull项目下拉一个新项目 # 初始化git git init # 远程拉取仓库 url为仓库地址。 git clone url 下拉并更新本地仓库如果远程库更新,本地代码未做修改时 下拉远程仓库并覆盖本地,命令如下:# 更细本地某个分支git pull ’temp’# 更新本地所有分支git pull –allpush项目推送一个新建项目新建项目需要现在github上建立一个空仓库 之后执行以下命令: #提交代码至本地仓库 git add . #提交代码至本地仓库 git commit -m ‘注释’ #指定远程仓库(如果之前指定过地址了跳过本次) git remote add origin url #提交代码至远程仓库 git push -u orgin master 推送覆盖远程仓库如果确认要全部覆盖远程仓库内容时: #提交代码至本地仓库 git add . #提交代码至本地仓库 git commit -m ‘注释’ #指定远程仓库(如果之前指定过地址了跳过本次) git remote add origin url #提交代码至远程仓库 git push -u orgin master –force ···### 推送并选择性更新项目中的内容> 多人共同维护一个项目时,每次提交时需要合并项目再提交。命令如下:远程仓库代码下载到缓存分支git fetch origin master:temp比较两个版本 (查看版本差异)git diff temp合并分支git merge temp手动合并完后提条至远程仓库 并删除本地缓存分支git commit -m ‘注释’git push -u origin mastergit branch -d temp—## 其他常用命令### 配置用户信息#查看配置列表git config list # 设置提交代码时的用户信息 git config [–global] user.name “[name]” git config [–global] user.email “[email address]”—### 增加/删除文件添加指定文件到暂存区git add [file1] [file2] …添加指定目录到暂存区,包括子目录git add [dir]添加当前目录的所有文件到暂存区git add .添加每个变化前,都会要求确认对于同一个文件的多处变化,可以实现分次提交git add -p删除工作区文件,并且将这次删除放入暂存区git rm [file1] [file2] …停止追踪指定文件,但该文件会保留在工作区git rm –cached [file]改名文件,并且将这个改名放入暂存区git mv [file-original] [file-renamed]—### 代码提交提交暂存区到仓库区git commit -m [message]提交暂存区的指定文件到仓库区git commit [file1] [file2] … -m [message]提交工作区自上次commit之后的变化,直接到仓库区git commit -a提交时显示所有diff信息git commit -v使用一次新的commit,替代上一次提交如果代码没有任何新变化,则用来改写上一次commit的提交信息git commit –amend -m [message]重做上一次commit,并包括指定文件的新变化git commit –amend [file1] [file2] …### 分支# 列出所有本地分支git branch# 列出所有远程分支git branch -r# 列出所有本地分支和远程分支git branch -a# 新建一个分支,但依然停留在当前分支git branch [branch-name]# 新建一个分支,并切换到该分支git checkout -b [branch]# 切换到指定分支,并更新工作区git checkout [branch-name]# 合并指定分支到当前分支git merge [branch] # 删除分支git branch -d [branch-name]# 删除远程分支git push origin –delete [branch-name]git branch -dr [remote/branch]—### 远程同步下载远程仓库的所有变动git fetch [remote]显示所有远程仓库git remote -v显示某个远程仓库的信息git remote show [remote]增加一个新的远程仓库,并命名git remote add [shortname] [url]取回远程仓库的变化,并与本地分支合并git pull [remote] [branch]上传本地指定分支到远程仓库git push [remote] [branch]强行推送当前分支到远程仓库,即使有冲突git push [remote] –force推送所有分支到远程仓库git push [remote] –all### 配置SSK生成sshkey命令ssh-keygen之后在C:\Users\danielmlc\.ssh中查找id_rsa.pub文件。将其中的key添加至github账号ssk中管理即可。 ...

December 28, 2018 · 1 min · jiezi

git clone 提示 warning

warning: remote HEAD refers to nonexistent ref, unable to checkout.git clone 时提示wraning, 并且Contacts模块的代码并没有下载到工作区。原因:git目录下.git/refs/heads不存在HEAD指向的文件,这个时候可以用git show-ref命令查看获得如下打印:5fa0b60252ca2c10fa3c2e12780d351c047c802d refs/remotes/origin/branch_qc_origin5fa0b60252ca2c10fa3c2e12780d351c047c802d refs/tags/XXXXXXXXXXXX48dee3a5f7b9cac98349e949275c652e02b0b67e refs/tags/PXXXXV0.0.0B01-bringup505a9bb0c6d815e6db561f7cb7ed0e20cd73ddde refs/tags/PXXXX_02550_201309260427e2b211a3c9d8dabec9fe1018b4f7db5c953832ea refs/tags/PXXXX_bsp_02550_2013092604220848e8b7922c78dbb364aa0e7c1b8375d16a70a3 refs/tags/branch_PXXXX_02550_2013091901027384803be7c8866393b96ebaaa7e1b2b119654e7 refs/tags/branch_PXXXX_02550_201309200102480f444dd26bb238aeaacf15da748ad861ea9378 refs/tags/branch_PXXXX_02550_201309210102……可以看出,全部是标签tag,并没有类似refs/head/branch_name远程仓库可能没有master分支解决办法git branch // 输入出空git branch -a // 输出 remotes/origin/devgit checkout remotes/origin/dev // checkout的是git branch -a输出的内容// 这样通过ll命令查看,Contacts代码下载到工作目录了// 接着创建分支:git checkout -b remotes/origin/devgit branch // 可以看到输出*remotes/origin/dev了,不再为空git branch -m remotes/origin/dev master // 重命名分支叫mastergit show-ref // 命令查看也能看到head了解决成功

December 28, 2018 · 1 min · jiezi

GIT学习笔记

笔记整理自廖雪峰老师Git教程创建本地版本库1、 创建版本库git init2、 把文件添加到仓库(从工作区到暂存区)git add readme.txt``git add .3、 把文件提交到仓库(从暂存区到当前分支)git commit -m 'commit'添加到远程库4、 添加一个远程库:生成 http://xxx.git5、 要查看远程库的信息,用git remote,或者,用git remote -v显示更详细的信息6、 关联已有的本地仓库git remote add origin xxx.git (origin是远程库的名字)7、 把本地库的所有内容推送到远程库上,把当前分支master推送到远程第一次推送master分支,加上-u参数,把本地的master分支和远程的master分支关联起来git push -u origin master 把本地的修改提交到远程的master分支git push origin master如果我们只有一个master分支,就可以直接:git push从远程库拉取项目8、 要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆git clone http://xxx.git熟练使用以上步骤就可以愉快的使用git了,但是想要更进一步,还需要往下看:工作区和暂存区工作区就是你本地的项目文件夹,版本库是工作区里的.git文件。Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。我们使用git提交可以看为三步:第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支;第三步是用git push把本地分支中的修改提交到远程库其他操作9、HEAD指向的版本就是当前版本, Git允许我们在版本的历史之间穿梭,使用命令git reset –hard commit_id10、穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本, 用git log –graph命令可以看到分支合并图11、要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本12、git status查看版本库状态13、用git diff HEAD – readme.txt命令可以查看工作区和版本库里面最新版本的区别14、git checkout – file可以丢弃工作区的修改(用版本库里的版本替换工作区的版本)15、用命令git reset HEAD <file>可以把暂存区的修改撤销掉,重新放回工作区16、命令git rm用于删除一个文件17、查看分支:git branch18、创建分支:git branch <name>19、切换分支:git checkout <name>20、创建+切换分支:git checkout -b <name>21、合并某分支到当前分支:git merge <name>22、删除分支:git branch -d <name>23、如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>强行删除24、Git还提供了一个git stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作25、用git stash list命令查看保存的工作区26、用git stash apply恢复工作现场,但是恢复后,stash内容并不删除27、用git stash drop来删除stash内容28、用git stash pop,恢复的同时把stash内容也删了29、本地新建的分支如果不推送到远程,对其他人就是不可见的,30、从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交31、在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致32、建立本地分支和远程分支的关联,使用git branch –set-upstream branch-name origin/branch-name33、从远程抓取分支,使用git pull,如果有冲突,要先处理冲突34、git rebase操作可以把本地未push的分叉提交历史整理成直线;35、git rebase的目的是使得我们在查看历史提交的变化时更容易,因为分叉的提交需要三方对比36、命令git tag <tagname>用于新建一个标签,默认为HEAD,也可以指定一个commit id37、命令git tag -a <tagname> -m “blablabla…“可以指定标签信息38、命令git tag可以查看所有标签,标签不是按时间顺序列出,而是按字母排序的39、可以用git show <tagname>查看标签信息,可以看到说明文字40、命令git push origin <tagname>可以推送一个本地标签;41、命令git push origin –tags可以推送全部未推送过的本地标签;42、命令git tag -d <tagname>可以删除一个本地标签;43、命令git push origin :refs/tags/<tagname>可以删除一个远程标签。44、忽略某些文件时,需要编写.gitignore;45、.gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!46、被忽略的文件,可以用-f强制添加到Git47、可以用git check-ignore命令检查.gitignore哪个规则写错了配置别名48、配置别名:git config –global alias.st status,–global参数是全局参数,也就是这些命令在这台电脑的所有Git仓库下都有用git config –global alias.lg “log –color –graph –pretty=format:’%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset’ –abbrev-commit"49、每个仓库的Git配置文件都放在.git/config文件中,可以手动修改配置,别名就在[alias]后面,要删除别名,直接把对应的行删掉即可,而当前用户的Git配置文件放在用户主目录下的一个隐藏文件.gitconfig中git命令总结远程拉取版本库git clone http://xxx.gitcd xxx创建新版本库git initgit remote add origin http://xxx.git提交更新git add . //git rm xxxgit commit -m “Initial commit"git push //-u origin master ...

December 28, 2018 · 1 min · jiezi

gitlab 安装、配置

gitlab 安装、配置对于企业级的私有 git 仓库,gitlab 是个不错的选择。今天就来说说 gitlab 的安装、配置。系统配置建议:最低双核 4G 内存。当前针对 gitlab 版本:11.5.3。1. 说明根据官方的安装教程,选取 ubuntu 环境下的社区版进行安装:https://about.gitlab.com/install/#ubuntu?version=ce。如果需要其他的环境(如 CentOS、docker 等)或者企业版,参考这里:https://about.gitlab.com/install/。注:社区版是免费的,企业版是收费的。2. 安装、配置所需依赖sudo apt-get install -y curl openssh-server ca-certificatessudo apt-get install -y postfix3. 添加安装包地址,并安装curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bashsudo EXTERNAL_URL=“http://gitlab.example.com” apt-get install gitlab-ce这里需要把 http://gitlab.example.com 改成你自己的真正对外服务的 gitlab url 地址(也可以安装后在配置文件里面更改)。到这里为止,gitlab 就算安装好了。4. 安装之后gitlab 默认建议安装在一个单独的主机上,默认使用内置的 nginx 服务器,并使用 80 和 8080 两个端口。如果你是按照 gitlab 的默认建议,使用的是单独的主机,直接访问 ip 地址 http://ip,或者把域名解析到这台机器上后直接访问域名 http://gitlab.your.com,然后按照步骤在 web 页面上初始化 gitlab 就可以了。然而,很多情况下,gitlab 并不会部署到一台单独的服务器上,而是像其他很多服务一样(如 jenkins),部署到同一台服务器上,然后使用 nginx 反向代理。5. nginx 反向代理配置添加 nginx 配置:upstream gitlab-workhorse { server unix:/var/opt/gitlab/gitlab-workhorse/socket;}server { listen 0.0.0.0:80; listen [::]:80; server_name gitlab.your.com; server_tokens off; root /opt/gitlab/embedded/service/gitlab-rails/public; access_log /var/log/nginx/gitlab_access.log; error_log /var/log/nginx/gitlab_error.log; location / { client_max_body_size 0; gzip off; proxy_read_timeout 300; proxy_connect_timeout 300; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_pass http://gitlab-workhorse; }}如果想要了解更详细的配置,可以参考:NGINX settings | GitLab。重新加载 nginx 配置:service nginx reload# orservice nginx restart修改 gitlab 配置:vi /etc/gitlab/gitlab.rbexternal_url ‘http://gitlab.your.com’ # 此处修为你自己的 gitlab urlweb_server[’external_users’] = [‘www-data’] # 设置外部 webserver 用户nginx[’enable’] = false # 不使用内置的 nginxsudo usermod -aG gitlab-www www-data # 把 www-data 用户添加到 gitlab-www 组 gitlab 服务默认使用的是 8080 端口,如果 8080 端口已经被其他程序(如 tomcat)占用,需要改成其他端口:unicorn[‘port’] = 8081 # 改成你自己觉得好的端口更新 gitlab 配置,重启服务:gitlab-ctl reconfiguregitlab-ctl restart现在你就可以访问 http://gitlab.your.com,然后按照步骤在 web 页面上初始化 gitlab 就可以了。6. 常用命令gitlab-ctl start # 启动 gitlabgitlab-ctl stop # 停止 gitlabgitlab-ctl restart # 重启 gitlabgitlab-ctl status # 查看服务状态vi /etc/gitlab/gitlab.rb # 修改配置文件gitlab-ctl reconfigure # 重新编译 gitlab 配置gitlab-rake gitlab:check SANITIZE=true –trace # 检查 gitlabgitlab-ctl tail # 查看日志gitlab-ctl tail nginx/gitlab_access.log7. 常用目录/var/log/gitlab/ # 日志地址 /var/opt/gitlab/ # 服务地址 8. 查看版本cat /opt/gitlab/embedded/service/gitlab-rails/VERSION9. 可能遇到的一些问题9.1 File to import not found or unreadable解决:需要 npm 安装一下cd /opt/gitlab/embedded/service/gitlab-railsnpm installgitlab-ctl restart # 重启服务后续更多博客,查看 https://github.com/senntyou/blogs作者:深予之 (@senntyou)版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证) ...

December 28, 2018 · 2 min · jiezi

git常用命令详解

git是我们常用的代码提交工具,但是有很多命令行要记,对于习惯这些命令的新手来说是一件很蛋疼的事,故本人在此记录了一些常用的命令,以供大家参考。如有不对之处,还请各位大虾多多指正。git代码克隆1.主模块代码拉取 主模块拉取的命令很简单,相信用过git的童鞋都会:git clone https://github.com/bendidi/Tracking-with-darkflow.git2.子模块代码拉取 将主模块代码拉取下来以后会发现主体工程代码目录下面有一些空目录,如deep_sort、sort、darkflow,这些子模块均为空目录。原因是这些目录均为submodule,隶属于第三方的git工程。这是为了解决不同git工程之间能够相互引用,而彼此之间又能保证相互独立才引入子模块的概念。拉取子模块的方法如下:git submodule update –init –recursive 如果你细心观察,你会发现包含子模块的工程主目录下都会存在一个.gitmodules(隐藏文件),里面的内容如下:[submodule “deep_sort”]path = deep_sorturl = https://github.com/bendidi/deep_sort.git[submodule “sort”]path = sorturl = https://github.com/bendidi/sort.git[submodule “darkflow”]path = darkflowurl = https://github.com/bendidi/darkflow.git 文件中记录的子模块对应的文件名和git路径,git submodule update –init –recursive就是根据此文件来拉取子模块工程3.同时拉取所有模块代码 看完上面两步之后,估计很多童鞋心里都有个疑问: 我拉取个代码还搞这么麻烦,有没有简单一点的方法,可以一步到位? 这位老细你有运了,我这里刚好有一粒:git clone –recursive https://github.com/bendidi/Tracking-with-darkflow.git给git clone传递–recursive选项,git clone命令会自动初始化并更新仓库中的每一个子模块。正常代码提交流程 git正常的代码提交流程可以分为以下几步:1.文件的增删改 1.git add $(filepath)/filename 在git中增加需要增加或者修改的文件名 2.git rm $(filepath)/filename 在git中删除指定文件路径的文件 3.git mv filename1 filename2 修改移动指定文件名 4.git status 查看当前代码提交状态,可根据提交状态来校对目前的修改跟预期的提交是否相符。2.代码的本地提交 经过第一步的代码的增删改操作后,将进入本地提交环节,提交后代码将保存在本地,但不会上传的git服务器,操作命令如下:git commit 提交时如须添加修改备注,可以在git commit -m “备注信息:xx修改”,也可以在git commit后的命令行中添加。 本地提交之后,有时你会发现,还有其他的改动忘了提交,怎么办呢? 很简单,将忘了提交的改动重新走一遍步骤1,然后使用:git commit –amend 进行追加提交,即可完成本地补充提交代码。3.代码的远程服务器提交 当代码提交到本地后,就可以将代码提交到主干,命令如下:git push origin HEAD:refs/for/master主干上版本更新后如何合并提交自己的代码 按正常提交流流程commit代码后,若主线版本比本地版本新,直接提交代码到主线将会报冲突,此时可以尝试使用如下方法来解决:1. git stash git stash用于将当前工作区的修改暂存起来,就像堆栈一样,可以随时将某一次缓存的修改再重新应用到当前工作区2. git pull 拉取线上最新代码.3.git stash pop 恢复/合并线上代码和自己的代码此时再将代码提交到主干将不会报冲突,但新代码和自己修改的代码有没有相互重叠的修改导致不可预测的后果,需要提交者自己检视代码来保证。代码回退1.git log查看最近代码提交日志,可以按上下箭头浏览,内容如下:2.git checkout $(committed) 使用git checkout $(committed)可以将代码回退到指定的提交版本如果代码回退后需要恢复到当前主线最新版本,可以使用: git reset –hard origin/master 将代码恢复到当前主线最新版本。reset之后如何恢复到上一次commit点1.git reflog使用git reflog查看之前的commit记录,如下所示:$ git reflogb7057a9 HEAD@{0}: reset: moving to b7057a998abc5a HEAD@{1}: commit: more stuff added to foob7057a9 HEAD@{2}: commit (initial): initial commit2.git reset –hard 98abc5areset完后代码即可回退到之前提交的版本reset –hard 和checkout的区别1.git reset –hard $(committed)放弃本地修改,将代码回退到指定commit版本,本地代码的HEAD也会随着本次reset的提交点而移动到对应的分支/主线2.git checkout $(committed)放弃本地修改,将代码回退到指定commit版本,本地代码的HEAD不会随着checkout的commitid移动。区别:1.checkout对工作目录时安全的,它会通过检查来确保不会将已更改的文件弄丢。而 reset –hard 则会不做检查就全面地替换所有东西。2.使用git reset –hard时HEAD会随着commit的不同而移动,而使用git checkout时HEAD不会随着commit点的不同而移动。 ...

December 26, 2018 · 1 min · jiezi

码云git,创建项目步骤和webstorm配置git

1、本地初始化一个项目首先,你需要执行下面两条命令,作为 git 的基础配置,作用是告诉 git 你是谁,你输入的信息将出现在你创建的提交中。git config –global user.name “你的名字或昵称"git config –global user.email “你的邮箱"然后在你的需要初始化版本库的文件夹中执行:git init git remote add origin <你的项目地址> //注:项目地址形式为:https://gitee.com/xxx/xxx.git或者 git@gitee.com:xxx/xxx.git这样就完成了一次版本你的初始化。如果你想克隆一个项目,只需要执行:git clone <项目地址>2、完成第一次提交进入你已经初始化好的或者克隆项目的目录,然后执行:git pull origin master<这里需要修改/添加文件,否则与原文件相比就没有变动>git add .git commit -m “第一次提交"git push origin master3.webstrom配置git配置好git安装路径修改文件后,先pull下码云上的项目,再commit下本地项目,然后把修改的文件push到码云上。

December 26, 2018 · 1 min · jiezi

git 初体验

安装 gitgit官网,这里提供了详细文档,《起步》中的1.5节是 git 的安装方法,它提供了 windows、mac、linux 平台的安装方法。安装成功后,打开终端输入git –version,如果能看到 git 版本,就说明安装成功了。mac 推荐使用 iTerm2 终端软件,windows 推荐使用 git bash。git 最小配置在正式使用 git 之前需要做一些配置,称之为最小配置,也就是说要将参与项目开发人员的 name 和 email 进行设置。每次的变更,在什么时间点,是谁做出了变更,那个这个信息是跟着某个变更信息捆绑在一起的。单引号里面的是需要你自己填写相应的信息,这些信息最好是真实的,方便别人找到你。git config –global user.name ‘your_name’git config –global user.email ‘your_email’这个地方设置了global,那是不是还有别的呢?除了global以外,还可以设置local,system。git config –local //只对某个仓库有效git config –global //对所有仓库有效git config –system //对系统所有登录的用户有效我们在使用 git 时,它会管理我们的文件系统,不是整个操作系统级别的管理,比如说你在某个地方建立了 git 仓库,仓库就相当于一个独立的项目。如果你设置local的话,你设置的信息,比如user_name、user_eamil只会对当前仓库有效,如果你切换到另一个仓库时,local的配置就会无效了,设置global的话,如果我电脑上有十个仓库,那么设置的user_name、user_email就会对这十个仓库都有效设置system的话,是对系统所有登录用户都有效。在工作中为了方便,用global最多,system基本不用。你在做设置之前,想要看下现有配置是什么样的,可以使用list命令git config –list –global //可以查看相关配置,是否设置成功建 git 仓库在实际的工作中,建仓库有两种场景:把已有的项目代码纳入 git 管理cd 项目代码所在的文件夹git init新建的项目直接用 git 管理cd 某文件夹git init your_project //会在当前路径下创建和项目名称同名的文件夹cd your_project我们现在桌面上创建一个git目录,后面关于 git 的学习都将会在这个文件夹下。创建第一个 git 仓库git init git_learning 初始化一个新的 git 仓库,里面有一个.git的隐藏文件夹,它将是我们的核心,后面会慢慢讲解。前面讲了给当前项目设置config,有三种方式,之前已经设置了global,这次设置一个local,看下最终提交时它会用global绑定的信息,还是local绑定的信息。之前global的user.name设置的是tiantian,现在local的user.name设置的是uccs。当我们用git commit命令提交后,可以用git log来查看提交历史,黄颜色的commit是这次提交的id号,Author显示的是uccs,这个作者是刚刚给local设置的绑定信息,由此我们可以看出如果同时存在global和local的绑定信息,local的优先级要高。往仓库里添加文件要进行4次提交,养成 git 的工作习惯暂存区的作用:在工作目录做的变更首先将它添加的到暂存区;你在工作目录做的变更,假设你有了其他方案,你不妨把这次的变更先放到暂存区;然后在尝试用另一套方案,假如第二次的方案还没有第一次好的话,暂存区的方案可以覆盖工作区的方案;暂存区的内容,是暂时存放,还不是作为一个正式的提交,但是它已经被 git 管理了,暂存区的内容可以很容易的被正式提交,如果不合适还可以回退。第一次提交创建了一个index.html使用git status可以查看工作目录和暂存区的状态。现在的提示是没有被 git 管理使用git add index.html,add后面可以添加多个文件或者文件夹再次使用git status,它会提示你已经将文件添加到暂存区去了。git commit -m ‘add index.html’作为第一提交第二次提交我们给当前页面加点样式,创建了一个style.css的文件使用git status发现刚刚创建的文件没有被 git 管理使用git add style,将刚创建的文件添加到暂存区确认无误后,使用git commti -m ‘add style.css’作为第二次提交 第三次提交过程同第二次提交步骤一样第四次提交现在需要对第一提交的index.html进行编辑编辑后使用git status,发现之前绿色的文件又变成了红色。对修改的文件,可以使用git add -u将它添加到暂存区确认无误后,做第四次提交。git 高效重命名文件工作中有时会存在文件重命名的,我们第一反应是,在工作区或者工作目录里面完成,然后将它加到暂存区里去,再用commit的方式去提交mv readme readme.mdgit status //会提示你要删除 readme,同时要添加 readme.md。下图:git rm readmegit add readme.mdgit status下图:最终的状态 git 知道你是在重命名文件按照现在已知的方法是这几个步骤将文件重命名将重命名后的文件添加到暂存区将老文件移除用 git 的命令该怎么做呢?先回到初始的状态,可以用git reset –hard,它会将工作区和暂存区之前的操作全部清空,回到初始状态。此操作比较危险,慎用。git mv readme readme.md下图:一个 git 命令代替上面三个步骤,效果是一样的最后提交一下,用 git 提供的命令重命名,不需要再add了。总结最小配置git config –global user.name ‘user_name’git config –global user.email ‘user_email’初始化仓库git init提交git add xxxgit commit -m ‘‘文件重命名git mv readme readme.md回滚git reset –hard ...

December 26, 2018 · 1 min · jiezi

git上传时去除一些文件

上传到服务器时去除调一些文件git rm -r –cached .git add .git commit -m ‘update .gitignore’

December 23, 2018 · 1 min · jiezi

版本控制

在开发中 git 是最常用的版本控制软件,在学习极客时间苏玲的《玩转 git 三剑客》前,对 git 的使用只停留在add,commit,pull,push上,稍微复杂点的checkout就不会使用了。在一次项目中,用到了merge,让我对git充满了好奇,正好这时极客时间推出了 git 的课程, 我毫不犹豫的购买了。虽然 git 已经烂大街了,再写关于 git 的文章也没什么价值了,但我还是要自己写点文章,一方面记录自己学习的心得,另一封面,也锻炼下自己的写作能力,吴军老师说过:要想让一个人会说,逻辑清晰,首先得会写。很多人肚子里有东西,但是说不出来,表达的别人看不懂,听者看来,和没有没太大区别。所以这也是锻炼自己的方式。什么是版本控制版本控制能够追踪工程蓝图从诞生一直到定案的过程,确保由不同人员所编辑的程序文件都能得到同步。最简单的版本控制是 copy 多份项目,并进行适当的编号,这种方法高度依赖开发者的自我纪律,很容易导致错误。因此自动化的版本控制系统应运而生。大部分版本控制软件都采用差分编码,只保留文件相继版本之间的差异,减少存储空间。中央式系统和分布式系统一个项目中有好几给开发人员同时参与,如果两个人同时改变一个文件,而没有管理访问权限,就会造成代码冲突。所以有两种方法:1、中央式系统,由中央管理访问权限;2、分布式系统,可以同时容许多个单位同时进行。版本控制系统演变历史在版本控制系统出来之前是怎么开发的呢?在服务器上面将文件共享出来,各自建个文件夹,以目录拷贝的方式来区分不同的人开发的东西;自己开发的东西也通过这种文件夹的形式标出1.0、2.0、3.0;这种方法大家开发的公共文件是很容易被覆盖的,还有我在开发的时候,我得不停的跟人家说,我在开发这个,你们先别动,所以沟通成本非常高,项目集成效率低下。以目录形式区别不同版本的形式不仅仅是过去,现在还存在,当然时代在发展,在这几十年当中有很多版本控制系统走入了我们世界,其中像 cvs 和 vsn 这种集中式的控制系统,他曾经被很多团队和公司所接受。集中式的版本控制系统,它有什么样的特征呢?有集中的版本管理服务器,这个服务器存放了每个文件或者文件夹的演变历史。也就是,哪天你本地没有这个项目,你去服务器取也是非常容易的。提供了历史版本的搜索能力,以及不同版本之间比较的能力。具备文件版本管理和分支管理能力。可以让不同的分支做集成,优点:这些特征使得集中式的版本控制系统,比起之前没有版本控制的项目,它的效率在集成方面是有明显的提高的。缺点:客户端必须时刻和服务器相连,因为客户端不具备服务器端一样的目录结构。有很多人认为,集中式的版本控制系统在速度上和性能上是不足的。后来基于集中式的版本控制系统的不足,开发了分布式的版本控制系统。它们最大的区别是,服务端和客户端都有完整的版本库,脱离服务端,客户端照样可以管理版本,查看历史和版本比较等多数操作,都不需要访问服务器,比集中式的VCS更能提高版本管理的效率。git 特点最优的存储能力非凡的性能,得益于林纳斯是非常有喜的linux内核专家以及文件系统管理专家开源的很容易做备份,支持离线操作很容易定制工作流程一个学习 git 的网址以上参考资料来自:维基百科 和 苏玲《玩转 git 三剑客》第一讲

December 23, 2018 · 1 min · jiezi

Git清空操作

用了git就会发现,再也不想用svn了。Note:在执行push操作前,所有的修改都发生在本地,可以使用reset随便回滚本地的提交。但要注意:本地修改一旦回滚,无法找回。在push后,想要回滚到指定的版本,便需要使用revert,这样的代价就是:你的回滚记录被记录在了log中,所有人都可以看见。使用reset回退本质上是commit操作的回退。Git工作流可以简化为三个部分:Working Directory、index、HEAD。后两部分对应的git命令便是add和commit。如果使用的是Sourcetree工具,那么这三部分就更直观了。该命令的具体功能是移动HEAD,即移动分支的指针。将当前的HEAD重新指向之前的版本,本地工作环境也会跟着切换。适用场景:本地已经commit,但尚未push到远端仓库的回滚操作。该命令提供了三个属性:分别是soft、mixed、和hard。soft撤销上一次的commit命令,返回到HEAD前的index状态。mixed撤销了上一次的git add和git commit命令,将index的修改回滚到Working Directory。hard撤销了最后git add 和 git commit 命令以及工作目录中的所有修改。所以reset重写的顺序如下:移动 HEAD 指向的分支(如果是soft,则到此停止)。使索引看起来像 HEAD(如果是mixed,则到此停止)。使工作目录看起来像索引。Example当执行pull命令发生冲突时时,本地代码需要做merge操作。但本地代码只是临时调试修改,并不需要保存提交。执行如下命令,便会清空本地的修改,hard相当于一个版本的指针,origin/master可以替换为具体的版本号git reset –hard origin/mastergit reset –hard version-numbergit reset –hard HEAD获取版本号可以通过git log直接查看。更多详细介绍,可以查看: 高级合并及 重置揭密checkoutstash储藏将==工作区==的修改进行存储,使本地重新成为一个干净的环境,同时方便在之后应用这些改动。可以用于存储==已被索引的文件==、或者==未跟踪的文件==。执行git stash -a 来暂存所有改动的文件。下面是执行的流程:git stash 储藏修改git stash list 查看储藏的列表将储藏重新应用到当前分支:git statsh apply stash@{1}或者git stash pop stash@{1}。后者会在应用暂存之后从堆栈上删除git stash drop stash@{1} 移除暂存使用clean清空用于从==工作区==移除==未被追踪的文件==,执行git clean -d -f来移除所有未被追踪的文件或目录。git clean -d -n 可以用来做一次删除前的演示git clean -d -i 用于交互式的删除文件使用revert我们工作区看到的内容,是所有版本修改合并的结果。如果觉得某个版本的提交有问题,使用revert便可以直接撤销这个版本的修改。本质上通过提交新的版本来撤销修改。–> (modify version 1) –> (modify version 2) –> (modify version3)执行git revert 版本号仅仅是撤销这个版本的修改。如果你想将版本回滚到version 1,你需要执行2次revert操作。且每次执行revert都会有一个新的版本生成。Revert a merge回滚merge提交跟普通的提交是有区别的。我们一般都是在分支上开发,然后将修改合并到主分支上。所以merge的那个提交版本,存在两个parent分支。所以,执行git revert MERGE_HASH是不能正常工作的。原因在于这个提交存在多个parent,它需要有额外的信息来决定哪一个分支作为回滚的主线。参数-m就是用来干这个的。git revert 0cce3a0837da60fb8ef458d98f81feaa97397363error: Commit 603c1333339bc9b5ad4d8b864e948d4bd950bf05 is a merge but no -m option was given.fatal: 还原失败Revert the revert听着这个标题,就感觉很有意思!参考文档:How to revert a merge commit in Git ...

December 20, 2018 · 1 min · jiezi

git学习笔记

从svn转到git版本控制之后,就爱上了它,再配合上github,简直不要太爽,以下是结合多方查询之后,总结出来适用于自己的git笔记!配置配置账号信息git config -e [–global] #编辑Git配置文件git config –global user.name itxccgit config –global user.email itxcc420@gmail.comgit config –list #查看配置的信息git help config #获取帮助信息配置密钥ssh-keygen -t rsa -C itxccc420@gmail.com #生成密钥ssh -T git@github.com #测试是否成功配置别名git config –global alias.st status #git stgit config –global alias.co checkout #git cogit config –global alias.br branch #git brgit config –global alias.ci commit #git ci基础命令git init #初始化git status #文件状态git add [file1] [file2] … #.或*代表全部添加git commit -m “msessage” 备注:- type(文件):‘备注’- - feat:新功能- - fix:修复bug- - style:格式- - refactor:代码重构- - chore:项目构建git push origin 分支名称 #推送到某个分支git log #查看所有提交记录git reflog #不小心删除了东西,先查到commit id,恢复git branch #显示所有本地分支git branch test #新建test分支git push git test #推送test分支到远程git checout test #切换到test分支git merge test #将test分支合并到当前分支git branch -d test #删除test分支git push origin -d test #删除远程test分支git rebase master#将master分之上超前的提交,变基到当前分支git rebase –onto master 169a6 #限制回滚范围,rebase当前分支从169a6以后的提交git rebase –interactive #交互模式 git rebase –continue# 处理完冲突继续合并 git rebase –skip# 跳过 git rebase –abort# 取消合并git tag #列出现有标签 git tag v0.1 [branch|commit] # [从指定位置]新建标签git tag -a v0.1 -m ‘my version 1.4’#新建带注释标签git checkout tagname#切换到标签git push origin v1.5#推送分支到源上git push origin –tags#一次性推送所有分支git tag -d v0.1#删除标签git push origin :refs/tags/v0.1#删除远程标签开发流程一般而言,会有两个公共分支master (项目主分支)dev (测试分支)开发一般是需要在自己的分支进行开发,然后推送到远端,本地则需要git merge 本地分支来进行更新dev分支,如果是多人开发,则需要git pull来更新dev分支在开发需要下拉代码时,远程仓库和本地刚好又有改动,最好先将自己在本地的代码进行 git stash (暂存区),再去进行下拉,在运行git stash pop 把自己的代码释放出来添加taggit tag -a v0.0.0 -m ‘v0.0.0’git push – tag ...

December 20, 2018 · 1 min · jiezi

创建阿里云远程仓库并关联

1.在阿里云code里面新建项目2.创建项目3.创建完成项目后是一个空仓库,需要本地创建项目并关联4.本地搭建项目结构,提交到远程仓库git add .git commitgit push -u origin master

December 20, 2018 · 1 min · jiezi

使用 git alias 提高 git 的使用效率

使用 git alias 提高 git 的使用效率前言git 作为一个版本控制工具,是我们程序员平时工作中不可缺少的一部分。但有一个问题,我们开发完一个小功能或修改了一个 bug,都需要 add 然后 commit 一下,每次都要敲这么多的字符。作为经常使用 git 的我们来说,这是不能忍受的!这个时候,可以使用 git alias!定义自己的 git alias通过命令设置 alias根据 git 官方文档说明,我们可以通过以下命令定义 git alias:git config –global alias.a addgit config –global alias.c commitgit config –global alias.o checkout通过 git 配置文件设置 alias上面那种用命令定义 alias 的方式,需要敲这么多前置的命令,太麻烦了。这个时候,我们可以通过 git 的配置文件来配置 alias在 ~/ 目录下找到 .gitconfig 文件在 .gitconfig 文件末尾添加:[alias]a = addc = commito = checkout# …完成!这样,我们就可以直接使用 git a、git c、git o 来代替 git add、git commit、git o 啦!git alias之前的都是我们自己配置的一些 git alias,当然有别人给我们配好了的:git alias。里面包含了非常非常非常多的 git alias,具体的 alias 所对应的真正的 git 命令,可以查看该项目的 gitalias.txt 文件。# 如:# gitalias.txt 文件中一个单词的 alias a = add b = branch c = commit d = diff f = fetch g = grep l = log m = merge o = checkout p = pull r = remote s = status w = whatchanged安装使用首先将该开源项目中的 gitalias.txt 文件下载下来然后在刚刚我们编辑的 .gitconfig 文件里面加入:[include]path = gitalias.txt这样,gitalias.txt 中的所有 alias,都已被引入,就可以直接使用了!将 git 命令用 g 命令替代打开 ~/.bash_profile 文件在文件末尾添加:alias g=git使用 source /.bash_profile 命令完成这样,git 也可以使用 g 命令来替代了!更多 git alias 工具根据 git alias more ideas 介绍,我们可以使用其他工具来使用 git alias,如:如果有 node 环境(作为前端开发,必须有!),可以使用 git-alias总结完 ...

December 19, 2018 · 1 min · jiezi

Git常用命令速查表

【名词】master :默认开发分区origin :默认远程版本库Index / Stage :暂存区Workspace :工作区Repository :仓库区(本地仓库)Remote :远程仓库一、新建代码库# 在当前目录新建一个 Git 代码库$ git init# 新建一个目录,将其初始化为 Git 代码库$ git init [project-name]# 下载一个项目和它的整个代码历史$ git clone [url]二、配置Git 的配置文件为 .gitconfig,它可以自用户主目录(全局配置),也可以在项目目录下(项目配置)。# 显示当前的 Git 配置$ git config –list# 编辑 Git 配置文件$ git config -e [–global]# 设置提交代码时的用户信息$ git config [–global] user.name “[name]"$ git config [–global] user.email “[email address]“三、增加、删除、修改文件# 查看状态$ git status# 查看变更内容$ git diff# 添加指定文件到暂存区$ git add [file1] [file2] … # 添加指定目录到暂存区,包括子目录$ git add [dir]# 添加当前目录的所有文件到暂存区$ git add . # 添加每个变化前,都会要求确认 # 对于同一个文件的多处变化,可以实现分次提交$ git add -p# 删除工作区文件,并且将这次删除放入暂存区$ git rm [file1] [file2] …# 停止追踪指定文件,但该文件会保留在工作区$ git rm –cached [file]# 改名文件,并且将这个改名放入暂存区$ git mv [file-original] [file-renamed]四、代码提交# 提交暂存区到仓库区$ git commit -m [message]# 提交暂存区的指定文件到仓库区$ git commit [file1] [file2] … -m [message]# 提交工作区自上次 commit 之后的变化,直接到仓库区$ git commit -a # 提交时显示所有 diff 信息$ git commit -v # 使用一次新的 commit,替代上一次提交 # 如果代码没有任何新变化,则用来改写上一次 commit 的提交信息$ git commit –amend -m [message] # 重做上一次 commit,并包括指定文件的新变化$ git commit –amend [file1] [file2] 五、分支# 显示所有本地分支$ git branch# 列出所有远程分支$ git branch -r # 列出所有本地、远程分支$ git branch -a # 新建一个分支,但依然停留在当前分支$ git branch [branch-name] # 新建一个分支,与指定的远程分支建立追踪关系$ git branch –track [branch] [remote-branch] # 删除分支$ git branch -d [branch-name]# 删除远程分支$ git push origin –delete [branch-name] $ git branch -dr [remote/branch] # 新建一个分支,并切换到该分支$ git checkout -b [branch] # 切换到指定分支,并更新工作区$ git checkout [branch-name] # 切换到上一个分支$ git checkout - # 建立追踪关系,在现有分支与指定的远程分支之间$ git branch –set-upstream [branch] [remote-branch] # 合并指定分支到当前分支$ git merge [branch] # 衍[yǎn] 合指定分支到当前分支$ git rebase [branch] # 选择一个 commit,合并进当前分支$ git rebase [branch] 【 merge 与 rebase 区别】作者:Michaelliu_dev 来源:CSDN 原文:https://blog.csdn.net/liuxiao… 版权声明:本文为博主原创文章,转载请附上博文链接!假设有如下图所示仓库,该仓库有master和develop两个分支,且develop是在(3.added merge.txt file)commit处从master拉出来的分支。merge,假设现在HEAD在(6.added hello.txt file)处,也就是在master分支最近的一次提交处,此时执行git merge develop, 结果如下图所示。工作原理就是:git 会自动根据两个分支的共同祖先即 (3.added merge.txt file)这个 commit 和两个分支的最新提交即 (6.added hello.txt file) 和 (5.added test.txt file) 进行一个三方合并,然后将合并中修改的内容生成一个新的 commit,即图二的(7.Merge branch ‘develop’)。 这是merge的效果,简单来说就合并两个分支并生成一个新的提交。rebase,HEAD在(6.added hello.txt file)处,现在执行git rebase develop,结果如下图所示。 可以看见develop分支分出来分叉不见了。下面来解释一下它的工作原理: 在执行git rebase develop之前,HEAD在(6.added hello.txt file)处,当执行rebase操作时,git 会从两个分支的共同祖先 (3.added merge.txt file)开始提取 当前分支(此时是master分支)上的修改,即 (6.added hello.txt file)这个commit,再将 master 分支指向 目标分支的最新提交(此时是develop分支)即(5.added test.txt file) 处,然后将刚刚提取的修改应用到这个最新提交后面。如果提取的修改有多个,那git将依次应用到最新的提交后面,如下两图所示。图四为初始状态图五为执行rebase后的状态简单来说,git rebase提取操作有点像git cherry-pick一样,执行rebase后依次将当前的提交cherry-pick到目标分支上,然后将在原始分支上的已提取的commit删除。六、标签# 列出所有本地标签$ git tag # 基于最新提交创建标签$ git tag <tagname> # 删除标签$ git tag -d <tagname> # 删除远程tag$ git push origin :refs/tags/[tagName] # 查看标签信息$ git show [tag] # 提交指定tag$ git push [remote] [tag] # 提交所有tag$ git push [remote] –tags # 新建一个分支,指向某个tag$ git checkout -b [branch] [tag] 七、查看信息# 显示所有变更的文件$ git status # 显示当前分支的版本历史$ git log # 显示 commit 历史,以及每次 commit 发生变更的文件$ git log –stat # 搜索提交历史$ git log -S [keyword] # 显示某个 commit 之后的所有变动,每个 commit 占据一行$ git log [tag] HEAD –pretty=format:%s # 显示某个 commit 之后的所有变动,其“提交说明”必须符合搜索条件$ git log [tag] HEAD –grep feature # 显示某个文件的历史版本,包括文件改名$ git log –follow [file] $ git whatchanged [file] # 显示指定文件相关的每一次diff$ git log -p [file] # 显示过去5次提交$ git log -5 –pretty –oneline # 显示所有提交过的用户,按提交次数排序$ git shortlog -sn# 显示指定文件是什么人在什么时间修改过$ git blame [file] # 显示暂存区和工作区的差异$ git diff # 显示暂存区和上一个 commit 的差异$ git diff -cached [file] # 显示工作区与当前分支最新 commit 之间的差异$ git diff HEAD # 显示两次提交之间的差异$ git diff [first-branch]…[second-branch] # 显示今天写了多少行代码$ git diff –shortstat “@{0 day ago}”# 显示某次提交的元数据和内容变化$ git show [commit] # 显示某次提交发生变化的文件$ git show –name-only [commit] # 显示某次提交时,某个文件的内容$ git show [commit]:[filename] # 显示当前分支的最近几次提交$ git reflog 八、远程操作# 下载远程仓库的所有变动$ git fetch [remote] # 取回远程仓库的变化,并与本地分支合并$ git pull [remote] [branch] # 显示所有远程仓库$ git remote -v # 显示某个远程仓库的信息$ git remote show [remote] # 显示增加一个新的远程仓库,并命名$ git remote add [shortname] [url] # 上传本地指定分支到远程仓库$ git push [remote] [branch] # 前行推送当前分支到远程仓库,即使有冲突$ git push [remote] –force # 推送所有分支到远程仓库$ git push [remote] –all # 删除远程分支或标签$ git push <remote> :<branch/tag-name> # 上传所有标签$ git push –tags 九、撤销# 撤销工作目录中所有未提交文件的修改内容$ git reset –hard HEAD # 撤销指定的未提交文件的修改内容$ git checkout HEAD <file> # 撤销指定的提交$ git revert <commit> # 退回到之前 1 天的版本$ git log –before=“1 days”# 恢复暂存区的指定文件到工作区$ git checkout [file] # 恢复某个 commit 的指定文件到暂存区和工作区$ git checkout [commit] [file]# 恢复暂存区的所有文件到工作区$ git checkout . # 重置暂存区的指定文件,与上一次 commit 保持一致,但工作区不变$ git reset [file] # 重置暂存区与工作区,与上一次 commit 保持一致$ git reset –hard # 重置当前分支的指针为指定commit,同时重置暂存区,当工作区不变$ git reset [commit] # 重置当前分支的 HEAD 为指定 commit,同时重置暂存区和工作区,与指定 commit 一致$ git reset –hard [commit] # 重置当前分支的 HEAD 为指定 commit,但保持暂存区和工作区不变$ git reset –keep [commit] # 新建一个 commit,用来撤销指定commit # 后者的所有变化都将被前者抵消,并且应用到当前分支$ git revert [commit] # 暂时将未提交的变化移除,随后再移入$ git stash $ git stash pop 十、其他# 生成一个可供发布的压缩包$ git archive ...

December 18, 2018 · 3 min · jiezi

编写git commit信息的最佳实践

翻译自:Write good git commit message写好Git提交信息很长时间以来,我甚至都不知道编写 git 提交(commit)信息也有它自己的“最佳实践”。在我第一次接触 git 时,提交信息的那部分内容被描述为类似这样的话:"…and here you can write something short about what’s going on in the commit"。不好的提交信息请看下面的提交信息。如果你想合并它们,你真的不会知道哪些是添加的内容,哪些是修改的内容,它们做了什么或者你为什么需要它们。如果你想在历史记录中搜索某些内容,那么上述的糟糕情况同样会遇到。你向下滚动日志,但它仍是一团糟,并且浪费时间。cd3e27a contact pageaee9d0d commentseac95e5 list of online users, some other changes because of serverfae5636 little edit好的提交信息现在再看下这些提交信息。是不是感觉好多了?反正我是这么觉得。43ec6aa Fix error when the URL is not reachable4fe84ab Add error message if something went wrong753aa05 Add server fingerprint checkdf3a662 Fix shadow box closing problem如何编写好的提交信息整个 commit 信息应该有它的格式 - 主题、正文以及可选的由已解决/已关闭的问题组成的结论。主题Git 的 commit 帮助页面对提交信息的主题有个很不错的描述:对变更内容进行总结的单行文本(少于50个字符),后跟一个空行。主题应以大写字母开头且不以句点 . 结尾。而且重要的是,这必须是一个强制的形式。Chris Beams 为此写了一个简单的规则:Git 提交信息主题的形式应该总是能够符合这样的句式:如果提交被应用,那么这个提交将“你写的主题”。比如:【译注】这里可以把“你写的主题”理解成一个动词、一个动作。如果被应用,那么这个提交将删除(Delete)不需要的行。如果被应用,那么这个提交将添加(Add) grep 选项。如果被应用,那么这个提交将修复(Fix)协议缺失时错误。对于不好的提交信息,就不会符合这个句式:如果被应用,那么这个提交将Contact page。如果被应用,那么这个提交将list of online users, some other changes because of server。Git 本身就是使用这种方法。当你要合并某些内容时,Git 会生成一个类似这样的提交信息:“Merge branch…",或者回滚时生成 “Revert…"。正文在正文里你可以编写哪些内容被修改了以及为什么修改。正文的每一行不应超过72个字符。当然并不是每次提交都需要有正文。尾行最后,你可以添加此次 commit 修复的或相关的 issue。它可以是一个链接、数字或者如果你在使用 GitHub,你可以这样写:Resolves #N / Closes #N,这里的 N 表示 issue ID。示例这是一个来自我的仓库的提交信息示例:Fix error when protocol is missingFirst, it checks if the protocol is set. If not, it changes the url andadd the basic http protocol on the beginning.Second, it does a “preflight” request and follows all redirects andreturns the last URL. The process then continues with this URL.Resolves #17写在最后感谢你的阅读,希望你从中学到了一些新的东西。如果你有其他的关于如何编写更好的提交消息的提示,或者如何更好地使用此工具,请发表你的评论。生成变更日志这样编写提交信息的另一个好处就是很容易生成变更日志。# show whole commit history$ git log –oneline –decorate –color# show history from one tag to another$ git log 0.0.9..0.0.10 –oneline –decorate –color# show history form tag to headgit log 0.0.9..HEAD –oneline –decorate –color这种命令的结果就是你的提交列表。21629ee Fix getResources bugaa13384 Update docs44de44c Add HSTS checkCommitizen在 GitHub 上有个名叫 Commitizen 的命令行工具,它可以让提交信息的编写变得更容易。当你想提交的时候,你只需键入 git cz,它会问你一组问题,然后为你创建正确的提交信息。参考Git commit manpageClosing issues using keywords on GitHubHow to Write a Git Commit Message post from Chris BeamsAngular Commit Message Format ...

December 18, 2018 · 2 min · jiezi

Python决策权的投票结果诞生了,“指导委员会”模式拔得头筹

2018年12月17日20点,Python 治理提案的投票结果出来了,最终胜出的是 PEP-8016。在几天前,我们推文《最新进展|关于Python治理模式的投票》,已经很明白地预测了这个结果,现在得到了证实。毫无悬念。对于这个结果,暂时没必要多说吧。等过几天,核心开发者们应该会有下一步的计划,到时候,我会关注其后续进展以及带来的影响,再跟大家细谈。此前,我们公众号(Python猫 )连续三篇文章介绍了本次的投票,关注到了多个维度的内容,以下仅附上相关链接,以供阅读。1、Python之父退位后,最高决策权花落谁家?Python 之父退出决策层后,社区里提出了7种治理模式的提案,这些提案各有什么差异点呢?Python 核心开发者 Victor Stinner 做了详细比对,此文可以带你了解各种治理提案的异同。2、这件正在发生的事,关乎所有的Python开发者……本文主要回顾了Python 之父的退位风波、各种治理提案的提出、以及此次事件的重要意义。3、最新进展|关于Python治理模式的投票上周,投票刚进行一半,本文汇总了部分核心开发者的投票意向(主要是Python之父Guido的看法),并做了一个预测。最后,我还注意到了两个小细节:1、共 94 个投票名额,但实际有效投票只有 62 票,也就是总数的 2/3 。实话说,有这么多的无效票/弃权票,我感到很意外,毕竟,整个投票期可是整整 16 天啊!这对投票方案的实施,是否会带来不利的影响呢?2、关于投票时间。首先,投票开启的时间就比几个月前计划的延迟了,而投票结束的时间也有临时的变更——本应结束于17日中午12点,但实际却延迟到晚上8点。这段时间里,发生了什么事情呢?但愿这只是“区区小事”吧……—————–本文原创并首发于微信公众号【Python猫】,后台回复“爱学习”,免费获得20+本精选电子书。

December 17, 2018 · 1 min · jiezi

编辑commit信息的最佳实践

翻译自:Write good git commit message写好Git提交信息很长时间以来,我甚至都不知道编写 git 提交(commit)信息也有它自己的“最佳实践”。在我第一次接触 git 时,提交信息的那部分内容被描述为类似这样的话:"…and here you can write something short about what’s going on in the commit"。不好的提交信息请看下面的提交信息。如果你想合并它们,你真的不会知道哪些是添加的内容,哪些是修改的内容,它们做了什么或者你为什么需要它们。如果你想在历史记录中搜索某些内容,那么上述的糟糕情况同样会遇到。你向下滚动日志,但它仍是一团糟,并且浪费时间。cd3e27a contact pageaee9d0d commentseac95e5 list of online users, some other changes because of serverfae5636 little edit好的提交信息现在再看下这些提交信息。是不是感觉好多了?反正我是这么觉得。43ec6aa Fix error when the URL is not reachable4fe84ab Add error message if something went wrong753aa05 Add server fingerprint checkdf3a662 Fix shadow box closing problem如何编写好的提交信息整个 commit 信息应该有它的格式 - 主题、正文以及可选的由已解决/已关闭的问题组成的结论。主题Git 的 commit 帮助页面对提交信息的主题有个很不错的描述:对变更内容进行总结的单行文本(少于50个字符),后跟一个空行。主题应以大写字母开头且不以句点 . 结尾。而且重要的是,这必须是一个强制的形式。Chris Beams 为此写了一个简单的规则:Git 提交信息主题的形式应该总是能够符合这样的句式:如果提交被应用,那么这个提交将“你写的主题”。比如:【译注】这里可以把“你写的主题”理解成一个动词、一个动作。如果被应用,那么这个提交将删除(Delete)不需要的行。如果被应用,那么这个提交将添加(Add) grep 选项。如果被应用,那么这个提交将修复(Fix)协议缺失时错误。对于不好的提交信息,就不会符合这个句式:如果被应用,那么这个提交将Contact page。如果被应用,那么这个提交将list of online users, some other changes because of server。Git 本身就是使用这种方法。当你要合并某些内容时,Git 会生成一个类似这样的提交信息:“Merge branch…",或者回滚时生成 “Revert…"。正文在正文里你可以编写哪些内容被修改了以及为什么修改。正文的每一行不应超过72个字符。当然并不是每次提交都需要有正文。尾行最后,你可以添加此次 commit 修复的或相关的 issue。它可以是一个链接、数字或者如果你在使用 GitHub,你可以这样写:Resolves #N / Closes #N,这里的 N 表示 issue ID。示例这是一个来自我的仓库的提交信息示例:Fix error when protocol is missingFirst, it checks if the protocol is set. If not, it changes the url andadd the basic http protocol on the beginning.Second, it does a “preflight” request and follows all redirects andreturns the last URL. The process then continues with this URL.Resolves #17写在最后感谢你的阅读,希望你从中学到了一些新的东西。如果你有其他的关于如何编写更好的提交消息的提示,或者如何更好地使用此工具,请发表你的评论。生成变更日志这样编写提交信息的另一个好处就是很容易生成变更日志。# show whole commit history$ git log –oneline –decorate –color# show history from one tag to another$ git log 0.0.9..0.0.10 –oneline –decorate –color# show history form tag to headgit log 0.0.9..HEAD –oneline –decorate –color这种命令的结果就是你的提交列表。21629ee Fix getResources bugaa13384 Update docs44de44c Add HSTS checkCommitizen在 GitHub 上有个名叫 Commitizen 的命令行工具,它可以让提交信息的编写变得更容易。当你想提交的时候,你只需键入 git cz,它会问你一组问题,然后为你创建正确的提交信息。参考Git commit manpageClosing issues using keywords on GitHubHow to Write a Git Commit Message post from Chris BeamsAngular Commit Message Format ...

December 17, 2018 · 2 min · jiezi

GIT备忘手册

开始使用设置身份$ git config –global user.name “Your Name”$ git config –global user.email “email@example.com"注意git config命令的–global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址,不使用–global参数即可。push到远程仓库创建仓库通过git init命令把这个目录变成Git可以管理的仓库,会在当前目录下生成一个.git的目录。$ git init添加到暂存区用命令git add <file>告诉Git,把文件添加到仓库,可反复多次使用,添加多个文件:<!–指定文件–>$ git add file2.txt file3.txt<!–当前目录全部文件–>$ git add .提交到本地仓库用命令git commit -m <message>告诉Git,把文件提交到仓库$ git commit -m “wrote a readme file"推送到远程仓库<!– 添加远程仓库需使用如下命令设置,已添加则不需设置 –>$ git remote add origin <name> <url><!– 推送到远程仓库 –>$ git push <name>git push -u origin master常用命令速查全局配置git config –global user.name “robbin"git config –global user.email “fankai@gmail.com"git config –global color.ui true # 让Git显示颜色git config –global alias.co checkout # 设置别名git config –global alias.ci commitgit config –global alias.st statusgit config –global alias.br branchgit config –global core.editor “mate -w” # 设置Editor使用textmategit config -l # 列举所有配置git config –global credential.helper store # 记住帐号密码,不用每次验证用户的git配置文件~/.gitconfig常用命令查看、添加、提交、删除、找回,重置修改文件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 # 恢复最后一次提交的状态查看文件diffgit diff <file> # 比较当前文件和暂存区文件差异git diffgit diff <$id1> <$id2> # 比较两次提交之间的差异git diff <branch1>..<branch2> # 在两个分支之间比较git diff –staged # 比较暂存区和版本库差异git diff –cached # 比较暂存区和版本库差异git diff –stat # 仅仅比较统计信息查看提交记录git loggit log –graph –pretty=oneline –abbrev-commitgit log <file> # 查看该文件每次提交记录git log -p <file> # 查看每次详细修改内容的diffgit log -p -2 # 查看最近两次详细修改内容的diffgit log –stat # 查看提交统计信息# tig Mac上可以使用tig代替diff和log,brew install tigGit 本地分支管理查看、切换、创建和删除分支git br -r # 查看远程分支git br <new_branch> # 创建新的分支git br -v # 查看各个分支最后提交信息git br –merged # 查看已经被合并到当前分支的分支git br –no-merged # 查看尚未被合并到当前分支的分支git checkout <branch> # 切换到某个分支git checkout -b <new_branch> # 创建新的分支,并且切换过去git checkout -b <new_branch> <branch> # 基于branch创建新的new_branchgit checkout $id # 把某次历史提交记录checkout出来,但无分支信息,切换到其他分支会自动删除git checkout $id -b <new_branch> # 把某次历史提交记录checkout出来,创建成一个分支git br -d <branch> # 删除某个分支git br -D <branch> # 强制删除某个分支 (未被合并的分支被删除的时候需要强制)分支合并和rebasegit merge <branch> # 将branch分支合并到当前分支git merge origin/master –no-ff # 不要Fast-Foward合并,这样可以生成merge提交git rebase master <branch> # 将master rebase到branch,相当于:git checkout <branch> && git rebase master && git co master && git merge <branch>Git远程分支管理git pull # 抓取远程仓库所有分支更新并合并到本地git pull –no-ff # 抓取远程仓库所有分支更新并合并到本地,不要快进合并git branch –set-upstream-to=origin/dev dev # 将本地分支与远程分支关联git fetch origin # 抓取远程仓库更新git merge origin/master # 将远程主分支合并到本地当前分支git checkout –track origin/branch # 跟踪某个远程分支创建相应的本地分支git checkout -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删除远程分支Git补丁管理(方便在多台机器上开发同步时用)git diff > ../sync.patch # 生成补丁git apply ../sync.patch # 打补丁git apply –check ../sync.patch # 测试补丁能否成功Git标签管理一般发布版本可以采用标签形式来创建里程碑。注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签。git tag # 查看所有标签git tag v1.0.0 # 从当前创建标签git tag v1.0.0 <commitId> # 从某个commitId创建标签git tag -a v0.1 -m “version 0.1 released” 1094adb # 创建带有说明的标签git show <tagname> # 查看标签信息git tag -d v0.1 # 删除标签git push origin <tagname> # 推送某个标签到远程git push origin –tags # 推送全部尚未推送到远程的本地标签# 删除远程分支需要两步:git tag -d <tagname> # 1.删除本地标签git push origin :refs/tags/<tagname> # 2.删除远程标签Git储藏管理git stash # 暂存git stash list # 列所有stashgit stash apply [stashName] # 恢复储藏的内容git stash drop # 删除储藏区git stash pop # 恢复并删除储藏内容git stash clear # 清空储藏区Git远程仓库管理git 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> # 删除远程仓库创建远程仓库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分支模型管理策略master 分支master 为主分支,也是用于部署生产环境的分支,确保master分支稳定性。master 分支一般由develop以及hotfix分支合并而来,任何时候都不能直接修改该分支的代码。develop分支develop 为开发分支,始终保持最新完成以及bug修复后的代码。一般开发的新功能时,创建的feature分支都是基于develop分支的。feature 分支开发新功能时,以develop为基础创建feature分支。分支命名: feature/开头的为特性分支, 命名如: feature/user_module、 feature/cart_module。release分支release为预上线分支,发布提测阶段,会以release分支代码为基准提测。当有一组feature开发完成,首先会合并到develop分支,进入提测时,会创建release分支。如果测试过程中若存在bug需要修复,则直接由开发者在release分支修复并提交。当测试完成之后,合并release分支到master和develop分支,此时master为最新代码,用作上线。hotfix 分支分支命名: hotfix/ 开头的为修复分支,它的命名规则与 feature 分支类似。线上出现紧急问题时,需要及时修复,以master分支为基线,创建hotfix分支,修复完成后,需要合并到master分支和develop分支。其中master和develop分支为常设分支,远程仓库中也应包含这两个分支;其他的为临时性分支,使用完成后应该删除,也建议不要推送到远程仓库。具体规范参考:Git分支管理策略GIT 提交规范推荐GIT提交时的粒度应该是一个小功能点或者一个bugFix,这样进行恢复操作时能够将影响范围降到最低。为了方便跟踪工程历史,编写良好的版本发布日志,我们应该编写一个良好的commit messages。建议采用当前广泛应用的 Angular Git CommitGuidelines规范。每次提交,Commit message 可以包括三个部分:Header,Body 和 Footer。<type>(<scope>): <subject> // header// 空一行<body>// 空一行<footer>其中,Header 是必需的,Body 和 Footer 可以省略。不管是哪一个部分,任何一行都不得超过72个字符(或100个字符),这是为了避免自动换行影响日志查阅。HeaderHeader部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。Typetype用于说明 commit 的类别,只允许使用下面7个标识。feat:新功能(feature)fix:修补bugdocs:文档(documentation)style: 格式(不影响代码运行的变动)refactor:重构(即不是新增功能,也不是修改bug的代码变动)test:增加测试chore:构建过程或辅助工具的变动如果type为feat和fix,则该 commit 将肯定出现在 ChangeLog 之中。其他情况,如:docs、chore、style、refactor、test,根据实际情况决定是否放入 ChangeLog,建议不放入。Scopescope用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同,本项目建议采用模块区分,如:模版编辑、数据更新。Subjectsubject是 commit 目的的简短描述,不超过50个字符;以动词开头,使用第一人称现在时,比如change,而不是changed或changes;第一个字母小写,结尾不加句号。BodyBody 部分是对本次 commit 的详细描述,可以分成多行。FooterFooter 部分只用于不兼容变动或关闭 Issue。参考资料:Git官方使用说明Git教程-廖雪峰 ...

December 17, 2018 · 3 min · jiezi

记录一次失败的Git操作

主要解决问题:gitignore不起作用文件太大导致无法上传,但是版本库已经确定获取版本号发生流程在进行素质三连git add -Agit commit -m “up"git push查看日志,发现是文件太大了然后突然发现自己的ignore没有添加,返过去添加,此处有一个坑:在配置完gitignore之后还是无法忽略,此处应该执行一个素质三连之后就可以了:git rm -r –cached .git add .git commit -m ‘update .gitignore’好,理论上这样子是可以push了,但是在执行git push的时候又失败了,还是文件太大。原因:但是此时已经执行了git commit所以当前库已经失效(后面再表)猜想是工作区是不干净的,之前加的已经定形了,进行搜索。得知猜想基本正确但是不只是分工作区那么简单,git是分三个区域 工作区、暂存区、版本库 具体情况点击查看目前是版本库已经确定,那就执行git reset –模式 版本ID此处的版本ID可以通过git log或者git reflog都能看到。然后退回版本,解决。

December 14, 2018 · 1 min · jiezi

git踩坑综合症

使用git真的是让我受尽了折磨,不写个集合都觉得对不起自己踩过的那些坑啊错误一:failed to push some refs to git $ git push -u origin masterTo git@github.com:yangchao0718/cocos2d.git! [rejected] master -> master (non-fast-forward)error: failed to push some refs to ‘git@github.com:yangchao0718/cocos2d.githint: Updates were rejected because the tip of your current branch is behinhint: its remote counterpart. Integrate the remote changes (e.g.hint: ‘git pull …’) before pushing again.出现错误的主要原因是github中的README.md文件不在本地代码目录中可以通过如下命令进行代码合并【注:pull=fetch+merge]git pull –rebase origin master执行上面代码后可以看到本地代码库中多了README.md文件此时再执行语句 git push -u origin master即可完成代码上传到github

December 13, 2018 · 1 min · jiezi

记录一下 Git 对大小写文件名追踪判定的坑

3分钟了解一下 Git 对大小写文件名追踪判定的坑最近业务上,遇到一个关于 Git 对于大小写文件名变动的追踪判定的坑所以这篇文章,记录一下 Git 如何判定文件大小写变化前言我们都知道 Linux 是严格区分大小写的,所以如果 Mac 开发时不小心用文件名是Order.vue,然后在routes配置时写的路径是 ../../../order.vue在部署到Linux时肯定会报错。问题不是很简单吗,修改下文件名就好了,有啥可说的?这里就是文章要说的点了直接修改文件名,会怎样?就是如果你仅仅是把文件名从 Order.vue 修改为 order.vue 然后提交代码。你如果执行git status,会发现提示你没有变化。git statusnothing to commit, working tree clean实际上提交到代码仓库后,你会发现文件的大小写也没有变化。git认为你没有什么变化,文件名依旧是Order.vue那如何触发文件名的变化呢?我尝试了2种方法1.往 Order.vue 里加一句空行或者注释,触发一下这个文件名的变化2.修改 Order.vue 为 Order111.vue, 然后再把 Order111.vue 修改回 order.vue ,触发一下这个文件名的变化结果是都失败了…总结:如果仅仅是修改文件名的大小写的话,Git 不会判定文件名有变化那最后怎么做呢?1.直接修改route.js,就直接用大写Order.vue这个文件名作为路由,不变化文件名了2.先把文件名随便改为 test.vue 提交上去,再提交第二次把文件名改回来,比如改成order.vue。 这样肯定是能判定文件名的修改的以上,就是在业务开发里遇到的一个小坑,小小的记录一下。

December 11, 2018 · 1 min · jiezi

git commit 代码提交规范

git commit 代码提交规范一、为什么需要制定提交规范?在团队协作开发时,每个人提交代码时都会写 commit message。每个人都有自己的书写风格,翻看我们组的git log, 可以说是五花八门,十分不利于阅读和维护。一般来说,大厂都有一套的自己的提交规范,尤其是在一些大型开源项目中,commit message 都是十分一致的。因此,我们需要制定统一标准,促使团队形成一致的代码提交风格,更好的提高工作效率,成为一名有追求的工程师。二、业界通用的 git 提交规范有哪些?1. commitizenAngularJS 在 github上 的提交记录被业内许多人认可,逐渐被大家引用。格式:type(scope) : subject( 1 ) type(必须) : commit 的类别,只允许使用下面几个标识:feat : 新功能fix : 修复bugdocs : 文档改变style : 代码格式改变refactor : 某个已有功能重构perf : 性能优化test : 增加测试build : 改变了build工具 如 grunt换成了 npmrevert : 撤销上一次的 commitchore : 构建过程或辅助工具的变动( 2 ) scope(可选) : 用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。( 3 ) subject(必须) : commit 的简短描述,不超过50个字符。commitizen 是一个撰写合格 Commit message 的工具,遵循 Angular 的提交规范。安装:全局安装 commitizennpm install -g commitizen进入项目文件夹,运行如下命令:commitizen init cz-conventional-changelog –save –save-exact使用:用 git cz 命令取代 git commit(先使用git add),这时会出现如下选项:( 1 )选择 type( 2 )填写 scope(选填)? What is the scope of this change (e.g. component or file name)? (press enter to skip)core( 3 )填写 subject? Write a short, imperative tense description of the change:set a to b完成,运行 git log 命令,查看我们刚才提交的 commit message,如下:fix(core): set a to b优点:符合业内标准(许多项目使用 AngularJS 的commit 规范)提交过程更加规范(使用 commitizen 规范工具,风格统一)能够生成风格统一的 commit log(type(scope):subject)缺点:需要安装 commitizen 工具包,使项目更大、更重了(适合大型开源项目)提交过程受约束较大有一定的学习成本2. 设置 git commit 模板步骤如下:( 1 ) 建立模板文件在项目中建立 .git_template 文件,内容可以自定义:type:scope:subject:( 2 ) 设置模板运行如下命令:git config commit.template .git_template // 当前项目<!– git config commit.template .git_template // 全局设置 –>( 3 ) 提交代码先使用 git add 添加代码使用 git commit 按照模板填写最后 git push 推送到远端优点:规则可配置,更自由配置方式简洁(只需添加配置文件)缺点:便利性差,每次都要用 vim 编辑器填写模板易出错,没有可靠的校验方式三、制定适合我们的 git commit 提交规范第二章中提到的两种业内普遍使用的规范,都不完全适合我们。第一种方式适合大型开源项目,我们如果也照搬会比较麻烦,但我们可以借鉴 type(scope): subject 的提交格式,也算是与大厂同步;第二种方式虽然自由,但是也不比较麻烦,要配置模板。因此,我们只模仿 type(scope): subject 的提交格式,不使用工具 or 模板校验,靠大家自觉遵守即可。格式type: description1. type 类型type 是 commit 的类别,只允许如下几种标识:fix: 修复bugadd: 新功能update: 更新style : 代码格式改变test: 增加测试代码revert: 撤销上一次的commitbuild: 构建工具或构建过程等的变动,如:gulp 换成了 webpack,webpack 升级等2. descriptiondescription 是对本次提交的简短描述。不超过50个字符。推荐以动词开头,如: 设置、修改、增加、删减、撤销等最后,既然制定了规则,大家就遵守起来吧~~~~ ...

December 1, 2018 · 1 min · jiezi

限时抽奖,送2本《深入浅出Python机器学习》

福利规则: 1、本公众号(Python猫)读者,在后台回复 1123 获取抽奖码,即可参与2、书籍:清华大学出版社,《深入浅出Python机器学习》2本3、活动截止时间:2018年11月29日 18:18 4、附加规则:公布结果后24小时,若出现中奖者联系不上、或其自愿放弃领奖的情况,我会将奖品赠送给有过互动(高质量留言)的读者,数量有限,标准随心。5、附加福利:添加图书编辑 暖暖 的微信号(q703882),加入交流群,可以获得与书籍作者 段小手 交流的机会,更有其他作者直播与书籍抽奖等多重福利。福利背景: 前几天,我被邀入一个 Python 学习群,进去后发现这是 清华出版社 图书编辑建的群。群里不仅有Python 学习者,还有已出版书籍的作者。今天送出的《深入浅出Python机器学习》,其作者 段小手 就在这个群里。前几天,他给群友做了一场题为《Python如何帮助我们找到更好的工作》的语音直播。我听了挺有启发。所以,当出版社编辑找我,说可以送书做活动,我毫不犹豫就答应下来了。这次,我不打算写成荐书系列了,因为每期荐书都得花费太多时间阅读和搜集材料,几天前刚写完一期,所以我想放松一次,就简单送送福利好了。简单罗列一下基本信息:作者:段小手,君兮科技创始人,毕业于北京大学。具有10余年国内一线互联网/电子商务公司项目管理经验。其负责的跨境电子商务项目曾获得“国家发改委电子商务示范项目”“中关村现代服务业试点项目”“北京市信息化基础设施提升项目”“北京市外贸综合公共平台”等专项政策支持。目前重点研究领域为机器学习和深度学习等方面。 书籍简介:本书内容涵盖了有监督学习、无监督学习、模型优化、自然语言处理等机器学习领域所必须掌握的知识,从内容结构上非常注重知识的实用性和可操作性。全书采用由浅入深、循序渐进的讲授方式,完全遵循和尊重初学者对机器学习知识的认知规律。本书适合有一定程序设计语言和算法基础的读者学习使用。本公众号创建时间很短,虽然在荐书《黑客与画家》的时候办过一次送书活动。但是,像今天这种“商业合作”的活动,还是第一次办。曾经有过4个“广告商”联系我,但是因为对其“广告内容”不够认可,经过深思熟虑,我最后都婉拒掉了。送 技术书籍 的活动,我十分欢迎,这类的“广告”是真正的福利,对读者、出版社和本公众号是三方共赢。以后有其它出版社来赞助活动的话,我必然还是优先考虑合作的。有些同行公众号在送书的时候,会要求读者给赞赏、留言集赞、或者转发朋友圈,这些小手段或许能有效筛选“忠实”读者,或许能扩大活动效果,随他们去吧。这些做法,我就不跟风了。不过,我也有小小的私心:如果你觉得本公众号的文章不错,请不吝分享给其他可能需要的小伙伴,在此,我先行感谢了! 关于书籍,这里有前六章试读:http://www.tup.tsinghua.edu.c…若想直接购买,京东有售:https://item.jd.com/12401357….

November 24, 2018 · 1 min · jiezi

一篇极好的Git 总结

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦本文由腾讯工蜂发表于云+社区专栏常用命令简单的,常用的命令也就几个。但是想非常熟练使用,怕是要记住几十个。Workspace:工作区(clone或者原始内容)Index/Stage:暂存区(有增删改查后add到临时区)Repository:本地仓库(保存了本地的增删改查记录)Remote:远程仓库(git.code.oa.com,本地的记录提交到远端,供团队所有人查看使用)有意思的事代码更新之Fetch vs Pull二者都是从远程拉取代码到本地fetch:只是拉取到本地pull:不仅拉取到本地,还merge到本地分支中代码合流之Merge vs Rebaserebase:用于把一个分支的修改合并到当前分支假设远程分支上有2个提交,然后基于远程develop,再创建一个分支feature。然后分别在两个分支上做两次提交。git merge这时候,你可以用pull命令把develop分支上的修改拉下来并且和你的修改合并;结果看起来就像一个新的和并提交git rebase$ git checkout feature$ git rebase develop这些命令会把你的feature分支里的每个提交(commit)取消掉,并且把它们临时保存为补丁(patch)(这些补丁放到".git/rebase"目录中)然后把feature分支更新为最新的develop分支最后把保存的这些补丁应用到feature分支上当feature分支更新后,会指向最新的commit,临时存放的就会被删除掉代码回滚之Reset、Revert、 CheckoutReset将一个分支的末端指向另一个提交,可以用来移除当前分支的一些提交。文件层面上,将缓存区的文件同步到指定的那个提交。$ git checkout develop$ git reset HEAD2# 将当前的README.md从缓存区中移除出去$ git reset HEAD README.mddevelop分支末端的两个提交就变成了悬挂提交如果提交还没有push,git reset 是撤销commit的简单方法除了在当前分支上操作,还可以通过其他参数来修改stage或者workspace–soft:stage和workspace都不会被改变–mixed(默认):stage和你指定的提交同步,但workspace不受影响–hard:stage和workspace都同步到你指定的提交# 将当前的改动从stage中移除,但这些改动还保留在workspace中$ git reset –mixed HEAD# 完全舍弃没有提交的改动$ git reset –hard HEADCheckout提交层面上的checkout,可以切换分支,同一分支,可以切换当前HEAD。文件层面上,不会移动HEAD指针,也不会切换到其他分支上,只是更改workspace,而不是stage。# 将HEAD移到新的分支,然后更新工作目录$ git checkout develop# 将HEAD移动到当前commit的前两个commit上,同时更新workspace$ git checkout HEAD2# 将workspace中的README.md同步到最新的提交$ git checkout HEAD README.mdRevert撤销一个提交的同时会创建一个新的提交。# 产生一个新的commit用于撤销倒数第二个commit$ git checkout develop$ git revert HEAD2不会改变提交历史revert可以用在公共分支,reset应该用在私有分支上如果提交已经push,想到达到撤销的目的,应该使用revert命令作用域常用情景git reset提交层面在私有分支上舍弃一些没有提交的更改git reset文件层面将文件从缓存区中移除git checkout提交层面切换分支或查看旧版本git checkout文件层面舍弃工作目录中的更改git revert提交层面在公共分支上回滚更改git revert文件层面(然而并没有)代码暂存之Stashgit stash会把所有未提交的修改(包括暂存和未暂存的)都保存起来,用于日后恢复当前工作目录保存一个不必要但日后又想查看的提交切换分支前先暂存,处理分支的其他事情$ git statusOn branch developChanges to be committed:new file: README.mdChanges not staged for commit:modified: index.html$ git stashSaved working directory and index state WIP on master: 5002d47 …$ git statusOn branch masternothing to commit, working tree cleanstage是本地的,不会上传到git server实际应用中,推荐给每个stash加一个message,使用git stash save 取代 git stash$ git stash save “test stash"Saved working directory and index state On autoswitch: test stashHEAD 现在位于 296e8d4 remove unnecessary postion reset in onResume function$ git stash liststash@{0}: On autoswitch: test stash可以使用git stash list命令,查看stash列表$ git stash liststash@{0}: WIP on master: 049d078 stash_0stash@{1}: WIP on master: c264051 stash_1stash@{2}: WIP on master: 21d80a5 stash_22. 使用git stash apply命令可以通过名字指定那个stash,默认指定最近的(stash@{0})3. 使用git stash pop将stash中第一个stash删除,并将对应修改应用到当前的工作目录中4. 使用git stash drop,后面加上stash名,可以移除相应的stash;或者使用git stash clear清空所有stash默认情况下,git stash会缓存:添加到暂存区的修改(staged changes )Git跟踪但并未添加到暂存区的修改(unstaged changes)但不会缓存:在工作目录中新的文件(untracked files)被忽略的文件(ignored files)此时,使用-u或者–include-untracked可以stash untracked 文件;使用-a或者–all可以stash当前目录下的所有修改(慎用)基础命令初始化# 在当前目录新建一个Git代码库$ git init# 新建一个目录,将其初始化为Git代码库$ git init git_test# 下载一个项目和它的整个代码历史$ git clone http://git.code.oa.com/jaelintu/git_test增加/删除文件# 添加指定文件到暂存区$ git add file1 file2…# 添加指定目录到暂存区,包括子目录$ git add dir# 添加当前目录的所有文件到暂存区$ git add .# 添加每个变化前,都会要求确认# 对于同一个文件的多处变化,可以实现分次提交$ git add -p# 删除工作区文件,并且将这次删除放入暂存区$ git rm file1 file2 …代码提交# 提交暂存区到仓库区$ git commit -m “message”# 提交暂存区的指定文件到仓库区$ git commit file1 file2 … -m “message”# 提交工作区自上次commit之后的变化,直接到仓库区$ git commit -a# 提交时显示所有diff信息$ git commit -v# 使用一次新的commit,替代上一次提交# 如果代码没有任何新变化,则用来改写上一次commit的提交信息$ git commit –amend -m “message”# 重做上一次commit,并包括指定文件的新变化$ git commit –amend file1 file2 …分支# 列出所有本地分支$ git branch# 列出所有远程分支$ git branch -r# 列出所有本地分支和远程分支$ git branch -a# 新建一个分支,但依然停留在当前分支$ git branch name# 新建一个分支,并切换到该分支$ git checkout -b branch# 新建一个分支,指向指定commit$ git branch name commit_SHA# 新建一个分支,与指定的远程分支建立追踪关系$ git branch –track name orgin/name# 切换到指定分支,并更新工作区$ git checkout name# 切换到上一个分支$ git checkout -# 建立追踪关系,在现有分支与指定的远程分支之间$ git branch –set-upstream name origin/name# 合并指定分支到当前分支$ git merge branch-name# 选择一个commit,合并进当前分支$ git cherry-pick commit_SHA# 删除分支$ git branch -d branch-name# 删除远程分支$ git push origin –delete branch-name$ git branch -dr remote/branchtags# 列出所有tag$ git tag# 新建一个tag在当前commit$ git tag tag-name# 新建一个tag在指定commit$ git tag tag-name commit-SHA# 删除本地tag$ git tag -d tag-name# 删除远程tag$ git push origin :refs/tags/tag-Name# 查看tag信息$ git show tag-name# 提交指定tag$ git push origin tag-name# 提交所有tag$ git push origin –tags# 新建一个分支,指向某个tag$ git checkout -b branch-name tag-name查看信息# 显示有变更的文件$ git status# 显示当前分支的版本历史$ git log# 显示commit历史,以及每次commit发生变更的文件$ git log –stat# 搜索提交历史,根据关键词$ git log -S [keyword]# 显示某个commit之后的所有变动$ git log (tag-name||commit-SHA) HEAD# 显示某个文件的版本历史,包括文件改名$ git log –follow file$ git whatchanged file# 显示指定文件相关的每一次diff$ git log -p file# 显示过去5次提交$ git log -5 –pretty –oneline# 显示所有提交过的用户,按提交次数排序$ git shortlog -sn# 显示指定文件是什么人在什么时间修改过$ git blame file# 显示暂存区和工作区的代码差异$ git diff# 显示暂存区和上一个commit的差异$ git diff –cached file# 显示工作区与当前分支最新commit之间的差异$ git diff HEAD# 显示两次提交之间的差异$ git diff [first-branch]…[second-branch]# 显示今天你写了多少行代码$ git diff –shortstat “@{0 day ago}”# 显示某次提交的元数据和内容变化$ git show commit-SHA# 显示某次提交发生变化的文件$ git show –name-only commit-SHA# 显示某次提交时,某个文件的内容$ git show commit-SHA:filename# 显示当前分支的最近几次提交$ git reflog# 从本地master拉取代码更新当前分支:branch 一般为master$ git rebase branch-name远程同步# 下载远程仓库的所有变动$ git fetch origin# 显示所有远程仓库$ git remote -v# 显示某个远程仓库的信息$ git remote show origin# 增加一个新的远程仓库,并命名$ git remote add shortname url# 取回远程仓库的变化,并与本地分支合并$ git pull origin branch-name# 上传本地指定分支到远程仓库$ git push origin branch-name# 强行推送当前分支到远程仓库,即使有冲突$ git push origin –force# 推送所有分支到远程仓库$ git push origin –all撤销# 恢复暂存区的指定文件到工作区$ git checkout file# 恢复某个commit的指定文件到暂存区和工作区$ git checkout commit-SHA file# 恢复暂存区的所有文件到工作区$ git checkout .# 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变$ git reset file# 重置暂存区与工作区,与上一次commit保持一致$ git reset –hard# 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变$ git reset commit-SHA# 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致$ git reset –hard commit-SHA# 重置当前HEAD为指定commit,但保持暂存区和工作区不变$ git reset –keep commit-SHA# 新建一个commit,用来撤销指定commit# 后者的所有变化都将被前者抵消,并且应用到当前分支$ git revert commit-SHA# 暂时将未提交的变化移除,稍后再移入$ git stash$ git stash pop冲突解决rebase过程中,也许会出现冲突(conflict)git会停止rebase,需要解决冲突解决完,使用git add添加冲突的文件,更新暂存区git rebase –continue继续剩下的rebasegit rebase –abort终止rebase行为,并且feature会回到rebase开始之前的状态$ git rebase developCONFLICT (content): Rebase conflict in readme.txtAutomatic rebase failed; fix conflicts and then commit the result.$ git statusOn branch featureYou have unmerged paths. (fix conflicts and run “git rebase –continue”) (use “git merge –abort” to abort the merge)Unmerged paths: (use “git add <file>…” to mark resolution) both modified: readme.txtno changes added to commit (use “git add” and/or “git commit -a”)查看readme.md 内容Git tracks changes of files.<<<<<<< HEADCreating a new branch is quick & simple.=======Creating a new branch is quick AND simple.>>>>>>> feature选择保留HEAD或者feature的版本Git tracks changes of files.Creating a new branch is quick AND simple.在提交:$ git add readme.md$ git rebase –contine推荐的Git GUI工具1. Source Tree(号称最好用):特色支持git flow,一键创建工作流免费功能强大:无论你是新手还是重度用户,SourceTree 都会让你觉得很顺手。对于非常重度用户,Source Tree还支持自定义脚本的执行同时支持 Windows 和 Mac 操作系统同时支持 Git 和 Mercurial 两种 VCS内置GitHub, BitBucket 和 Stash 的支持:直接绑定帐号即可操作远程repo2. Tortoise git:文件的右键菜单很容易上手免费只支持Windows:与文件管理器良好集成中文界面与Tortoise SVN相同的体验相关阅读【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识此文已由作者授权腾讯云+社区发布,更多原文请点击搜索关注公众号「云加社区」,第一时间获取技术干货,关注后回复1024 送你一份技术课程大礼包! ...

November 23, 2018 · 4 min · jiezi

管理多个git生成的ssh key

经常我们可能需要上传github,和gitlab,或者你有多个github账号,我们需要对应不同的账号上传,我们需要配置多个ssh key这里我们就以配置github,gitlab,两个ssh key 为案例1.生成两个不同的ssh生成第一个ssh keyssh-keygen -t rsa -C “yourmail@gmail.com” 这里不要一路回传,让你选择在哪里选择存放key的时候写个名字,比如 id_rsa_github,之后的两个可以回车。上图的红色框框是自己输入的,便于区分生成第二个ssh keyssh-keygen -t rsa -C “yourmail@gmail.com” 一样不要一路回车最终结果是这样子的:图中的config文件是我自己建的,也就是接下来要说的2.配置config新建文件config文件,打开输入一下# gitlabHost gitlab.com HostName gitlab.com PreferredAuthentications publickey IdentityFile ~/.ssh/id_rsa_gitlab User xiaqijian // 输入自己账号名 # githubHost github.com HostName github.com PreferredAuthentications publickey IdentityFile ~/.ssh/id_rsa_github User xiaqijian // 这里输入自己的账号名注意:如果拷贝我的,要把后面的注释去掉然后保存起来分别在github,gitlab填上ssh key填上刚刚生成的,然后你就可以上传文件试试或者用下面方法测试ssh -T git@github.com首发于微信公众号:node前端不妨关注一下,我们一起学习回复:100有福利哦

November 22, 2018 · 1 min · jiezi

重新学习git

一、git的起源因为linux的开发者不想花钱,给cvs、svn等等类似的版本管理平台自己搞了一个git, 其实中间还有个小插曲,就是BitKeeper曾免费授权给他们用,但是他们没有遵守协议,然后才被收回免费使用权。 毕竟咱都是写代码的人,我怕你? 所以两周后git出生了,并在2008github上线二、git优势版本管理一般分分布式和集中式相对分布式开发还有集中式开发,代表就是svn一说到分布式开发,很多人都想说,我git不需要联网就能开发,你svn可以吗?! 就问你怕不怕 但是事实是吗??谁说svn不能离线开?我只要不提交,我都能删库跑路,别说开发。还有谁说git不需要联网?不需要联网怎么协同是不是难道用的是秋波? 此秋波来自 192.110.110.110既然git 和svn都能本地不联网开发,也都是需要联网才能协同工作,那么他们具体的区别在哪里呢?git 可以在本地随意创建或者切换分支, commit代码到自己的本地仓库。 ….svn 可以在本地编辑代码(这么对比是不是很尴尬) 所以说,svn想要想git那种操作,是需要联网的,不管是局域网还是非局域网 都是要网 ,要网,要网~!三、git使用1、git安装linux 上安装安装之前先输入git检测是否已经安装了$ gitThe program ‘git’ is currently not installed. You can install it by typing:sudo apt-get install git如果出现以上这句话,直接在命令行执行sudo apt-get install gitmac 上安装(1)、通过网址下载安装 http://git-scm.com/download/mac。(2)、通过homebrew的方式安装(前提是先安装好homebrew)brew install git注意: linux和unix系统都可以通过 安装oh-my-zsh的插件 这个插件会自动安装gitwindows上安装通过下载安装包吧 。https://git-for-windows.githu…其他方式没弄过也不想弄。毕竟我是不喜欢windows的接下来如果不特别指出是windows 那就是linux和unix系统*2、配置(1)、设置用户名称和邮箱 举个?通过命令行git config –global user.name “spademan” //设置用户名 git config –global user.email “646028751@qq.com” //设置邮箱–global 加上参数会印象整个电脑的所有项目,所以慎用,假如有多个git账号的话如果需要设置某个特定项目的话 去掉–global参数 并且需要进入某个项目里面通过修改文件全局的gitconfig 存在"/.gitconfig"(用户目录下的.gitconfig)中某个项目的gitconfig 存在 .git/config 中通过文本编辑器打开他们就能看到[user]name = nicknameemail = nickname@gmail.com相关信息,修改并且保存即可(2)其他配置设置别名比如git config –global alias.last ‘cat-file commit HEAD’之后可以直接使用git last设置主题所有的color.*选项请参见git config的文档$ git config color.branch auto$ git config color.diff auto$ git config color.interactive auto$ git config color.status auto或者你可以通过color.ui选项把颜色全部打开:$ git config color.ui true配置提交模板git config commit.template ‘/etc/git-commit-template’模板内容举例// git-commit-template时间:新增:修改:删除:分支:执行人:….弊端是不太好用,因为需要用到vim其他配置看详情3、创建本地仓库(1)、clone远程git clone git://github.com/your/repositories.git ‘本地目录’// 本地目录是可选的,没有本地目录就是当前目录(2)、本地创建先在本地创建一个目录比如 myprojectcd myprojectgit init(3)、其他参数–local 表示clone的是本地的仓库–shared 建立一个软链–bare 复制一个裸版本(也就是没有包含工作区的内容)–depth 复制到最后的第几个版本,如果项目过大可以设置这个避免复制时间过长如果使用了depth之后 想要重新 pull以前的相关信息可以执行 git pull –unshallow4、版本管理(1)工作区、暂(缓)存区、版本库、远程的概念工作区:就是指我们本地工作目录,对我们本地仓库进行所有的增删改成操作只要还没有对该文件执行git add/stage,那么所有的改动都还算是在工作区缓存区:一个中间层,存在于工作区和版本库之间,工作区git add/stage之后内容就更新到了缓存区 执行了git commit之后,所有更新的内容都提交到了本地的版本库中版本库:包含所有分支、历史版等等全部的信息远程仓库:本地仓库执行push之后能将本地仓库的信息更新到远程信息更新流: 工作区->缓存区->版本库->远程版本库 (可以逆向更新)小疑问:存在跨去传递信息的吗? 比如工作区的内容能直接更新到版本库吗?(2)、基本操作命令git status查看当前工作区的信息,比如当前所在分支, 当前工作区中有多少更改、删除的文件 以及尚未追踪的文件和远程分支相比落后多少个版本`等等之类的信息git add将增、删、改文件的相关信息添加到缓存区默认情况下之后添加非忽略文件如果需要添加忽略文件 需要设置–force参数可以添加某单个文件也可以执行git add .添加全部文件git pullgit pull 是 git fetch + git merge FETCH_HEAD 的缩写。所以,默认情况下,git pull就是先fetch,然后执行merge 操作,如果加–rebase 参数,就是使用git rebase 代替git merge。git commit将暂存区或者工作区的信息更新到版本库不是说工作区要先提交到暂存区才能再从暂存区更新到版本库的吗?为什么这里的描述能直接把工作区的内容更新到版本库那是因为 commit 有语法糖的写法 比如commit -a 表示执行了git add 之后再执行git commit并且注意 git commit -a只能将当前目录下的跟踪文件添加到缓存区,git add .能将当前目录下所有文件提交到缓存区。常用参数-a 表示将当前目录下所有跟踪文件提交到暂存区–amend 表示修改最近一次提交的message–date 设置提交时间(3)、撤销操作git reset撤销操作–soft,暂存区和工作区不会被更新重置HEAD到另外一个commit,但也到此为止。工作区和缓存区都是保持本来的样子–mixed,暂存区会更新至指定的commit,工作区不会收到影响,这是默认的选项默认选项,将缓存区的数据更新成指定的commit那样,工作区没有影响–hard,暂存区和工作区同时更新到指定的commit强制更新选项,缓存区和工作区都更新成指定的commit那样这是一个比较危险的动作,具有破坏性,数据因此可能会丢失!如果真是发生了数据丢失又希望找回来,那么只有使用:git reflog命令了。makes everything match the commit you have reset to.你的所有本地修改将丢失。如果我们希望彻底丢掉本地修改但是又不希望更改branch所指向的commit,则执行git reset –hard = git reset –hard HEAD.//示例代码git reset HEAD2// 配合参数使用git reset –hard HEAD// 也可以是commit idgit reset –hard commitIdgit checkoutgit checkout head^ 切换分支这个命令实际上是将HEAD指向另外一个分支,并且将工作区更新到那个分支,如果工作区的更新可能会丢失,git会强制你将这些更新提交或者是stash(一般都是不同分支更改了相同的文件就会引起这个提示)如果想强制切换使用–force 参数(是一个危险的操作)切换并新建分支 git checkout -b如果该分支已经存在可以使用-B强制重置该分支为最新分支git checkout xxx 切换某个文件可以将某个分支或者某个指定的commit的某个文件checkout到本地来切换到某个commit在查看工程的某个旧版本的时候,这个命令是很有用的。但是,没有分支指向当前的HEAD,所以分支会处于detached状态。此时加入新的commit会是非常危险的,因为如果切换到其他的分支后,将没有办法回到这次的commit。出于这个原因,在提交commit到detached HEAD之前,应该新建一个分支。git 传入git reset和git checkout的参数决定了它们的作用域。参数中不包含文件路径的话,这两个命令就作用于整个commit。我们将会讨论这样的操作。注意git revert不支持文件级别的操作。参考https://www.liaoxuefeng.com/w…https://www.kancloud.cn/think...https://git-scm.com/docs/git-...e";} ...

November 21, 2018 · 1 min · jiezi

安装 gitlab CI 服务.md

安装 gitlab-ce安装依赖包yum install curl policycoreutils openssh-server openssh-clientssystemctl enable sshdsystemctl start sshdyum install postfixsystemctl enable postfixsystemctl start postfixfirewall-cmd –permanent –add-service=httpsystemctl reload firewalld下载 gitlab-ce 镜像vim /etc/yum.repos.d/gitlab-ce.repo[gitlab-ce]name=Gitlab CE Repositorybaseurl=https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el$releasever/gpgcheck=0enabled=1yum makecacheyum install gitlab-ce配置vi /etc/gitlab/gitlab.rbexternal_url ‘http://ip’启动gitlabgitlab-ctl reconfigure遇到报错Error executing action run on resource ’execute[semodule -i /opt/gitlab/embedded/selinux/rhel/7/gitlab-7.2.0-ssh-keygen.pp]stop gitlabyum install libsemanage-static libsemanage-devel安装CI服务下载安装CIwget https://mirrors.tuna.tsinghua.edu.cn/gitlab-runner/yum/el7/gitlab-runner-10.5.0-1.x86_64.rpmrpm -ivh gitlab-runner-10.5.0-1.x86_64.rpmsudo useradd –comment ‘GitLab Runner’ –create-home gitlab-runner –shell /bin/bashgitlab-runner uninstallgitlab-runner install –working-directory /home/gitlab-runner/ –user gitlab-runnergitlab-runner restartgitlab-runner status注册 runnersudo gitlab-ci-multi-runner register– 输入Gitlab CI地址, (e.g. https://gitlab.xunlei.cn/ci)http://192.168.1.249/gitlab/-- 输入项目CI tokenfuXXXXXXXXXX– 输入 Runner 描述(e.g. home.xl9.xunlei.com 测试runner)测试Runner– 输入 Runner 标签,可以多个,用逗号隔开(e.g. 10.10.34.91-dev)251-dev– 输入 Runner 执行的语言 (e.g. shell)shell– 认证是否注册成功sudo gitlab-ci-multi-runner verify编写脚本在项目下面创建.gitlab-ci.ymlstages: - deploydeploy_dev: stage: deploy tags: - 251-dev only: - develop script: - deploy_stage.sh然后在部署服务器上的 gitlab-runner 用户路径下创建deploy_stage.shecho “delete old xyj-admin-api"sudo rm -rf /raid1/www/testsudo git clone git@192.168.1.249:test/xyj-test-api.git /raid1/www/testsudo git fetch –allsudo git reset –hard origin/testecho “=============重启服务====================“source /etc/profilesudo supervisorctl restart testtime=dateecho “部署结束: $time.“echo “================================================“其中 测试项目是被 supervisorctl 管理的要确保几件事改服务器能够正常从远端克隆数据命令几点要带上sudo用户sudo无密码及在tty下可以使用需要参考 Linux sudo 相关操作如果克隆下来的文件放在挂载盘,需要在 ~/ 路径下执行 clone 然后放到对应路径,否则报错 fatal: could not create work tree dir遇到无法克隆,且 gitlab 日志为gitlab JWT::DecodeError (Nil JSON web token) 修改 nginx 配置upstream gitlab-workhorse { server unix:/var/opt/gitlab/gitlab-workhorse/socket; }…proxy_pass http://gitlab-workhorse;…git push develop 后触发脚本 ...

November 11, 2018 · 1 min · jiezi

对比 Git 与 SVN,这篇讲的很易懂

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由腾讯工蜂发表于云+社区专栏导语本文从 Git 与 SVN 的对比入手,介绍如何通过 Git-SVN 开始使用 Git,并总结平时工作高频率使用到的 Git 常用命令。一、Git vs SVNGit 和 SVN 孰优孰好,每个人有不同的体验。Git是分布式的,SVN是集中式的这是 Git 和 SVN 最大的区别。若能掌握这个概念,两者区别基本搞懂大半。因为 Git 是分布式的,所以 Git 支持离线工作,在本地可以进行很多操作,包括接下来将要重磅推出的分支功能。而 SVN 必须联网才能正常工作。Git复杂概念多,SVN简单易上手所有同时掌握 Git 和 SVN 的开发者都必须承认,Git 的命令实在太多了,日常工作需要掌握add,commit,status,fetch,push,rebase等,若要熟练掌握,还必须掌握rebase和merge的区别,fetch和pull的区别等,除此之外,还有cherry-pick,submodule,stash等功能,仅是这些名词听着都很绕。在易用性这方面,SVN 会好得多,简单易上手,对新手很友好。但是从另外一方面看,Git 命令多意味着功能多,若我们能掌握大部分 Git 的功能,体会到其中的奥妙,会发现再也回不去 SVN 的时代了。Git分支廉价,SVN分支昂贵在版本管理里,分支是很常使用的功能。在发布版本前,需要发布分支,进行大需求开发,需要 feature 分支,大团队还会有开发分支,稳定分支等。在大团队开发过程中,常常存在创建分支,切换分支的需求。Git 分支是指针指向某次提交,而 SVN 分支是拷贝的目录。这个特性使 Git 的分支切换非常迅速,且创建成本非常低。而且 Git 有本地分支,SVN 无本地分支。在实际开发过程中,经常会遇到有些代码没写完,但是需紧急处理其他问题,若我们使用 Git,便可以创建本地分支存储没写完的代码,待问题处理完后,再回到本地分支继续完成代码。二、Git 核心概念Git 最核心的一个概念就是工作流。工作区(Workspace)是电脑中实际的目录。暂存区(Index)类似于缓存区域,临时保存你的改动。仓库区(Repository),分为本地仓库和远程仓库。从 SVN 切换到 Git,最难理解并且最不能理解的是暂存区和本地仓库。熟练使用 Git 后,会发现这简直是神设计,由于这两者的存在,使许多工作变得易管理。通常提交代码分为几步:git add从工作区提交到暂存区git commit从暂存区提交到本地仓库git push或git svn dcommit从本地仓库提交到远程仓库一般来说,记住以下命令,便可进行日常工作了(图片来源于网络): [ Git命令 ]三、Git-SVN常用命令本节命令针对使用 Git-SVN 的开发者,请务必掌握。若服务器使用的 SVN,但是本地想要体验 Git 的本地分支,离线操作等功能,可以使用 Git-SVN功能。常用操作如下(图片来源于网络): [ Git-SVN ]# 下载一个 SVN 项目和它的整个代码历史,并初始化为 Git 代码库$ git svn clone -s [repository]# 查看当前版本库情况$ git svn info# 取回远程仓库所有分支的变化$ git svn fetch# 取回远程仓库当前分支的变化,并与本地分支变基合并$ git svn rebase # 上传当前分支的本地仓库到远程仓库$ git svn dcommit# 拉取新分支,并提交到远程仓库$ svn copy [remote_branch] [new_remote_branch] -m [message]# 创建远程分支对应的本地分支$ git checkout -b [local_branch] [remote_branch]四、初始化从本节开始,除特殊说明,以下命令均适用于 Git 与 Git-SVN。# 在当前目录新建一个Git代码库$ git init# 下载一个项目和它的整个代码历史 [Git only]$ git clone [url]五、配置# 列举所有配置$ git config -l# 为命令配置别名$ git config –global alias.co checkout$ git config –global alias.ci commit$ git config –global alias.st status$ git config –global alias.br branch# 设置提交代码时的用户信息$ git config [–global] user.name “[name]"$ git config [–global] user.email “[email address]“Git 用户的配置文件位于 ~/.gitconfigGit 单个仓库的配置文件位于 ~/$PROJECT_PATH/.git/config六、增删文件# 添加当前目录的所有文件到暂存区$ git add .# 添加指定文件到暂存区$ git add <file1> <file2> …# 添加指定目录到暂存区,包括其子目录$ git add <dir># 删除工作区文件,并且将这次删除放入暂存区$ git rm [file1] [file2] …# 停止追踪指定文件,但该文件会保留在工作区$ git rm –cached [file]# 改名文件,并且将这个改名放入暂存区$ git mv [file-original] [file-renamed]把文件名 file1 添加到 .gitignore 文件里,Git 会停止跟踪 file1 的状态。七、分支# 列出所有本地分支$ git branch# 列出所有本地分支和远程分支$ git branch -a# 新建一个分支,但依然停留在当前分支$ git branch [branch-name]# 新建一个分支,并切换到该分支$ git checkout -b [new_branch] [remote-branch]# 切换到指定分支,并更新工作区$ git checkout [branch-name]# 合并指定分支到当前分支$ git merge [branch]# 选择一个 commit,合并进当前分支$ git cherry-pick [commit]# 删除本地分支,-D 参数强制删除分支$ git branch -d [branch-name]# 删除远程分支$ git push [remote] :[remote-branch]八、提交# 提交暂存区到仓库区$ git commit -m [message]# 提交工作区与暂存区的变化直接到仓库区$ git commit -a# 提交时显示所有 diff 信息$ git commit -v# 提交暂存区修改到仓库区,合并到上次修改,并修改上次的提交信息$ git commit –amend -m [message]# 上传本地指定分支到远程仓库$ git push [remote] [remote-branch]九、拉取# 下载远程仓库的所有变动 (Git only)$ git fetch [remote]# 显示所有远程仓库 (Git only)$ git remote -v# 显示某个远程仓库的信息 (Git only)$ git remote show [remote]# 增加一个新的远程仓库,并命名 (Git only)$ git remote add [remote-name] [url]# 取回远程仓库的变化,并与本地分支合并,(Git only), 若使用 Git-SVN,请查看第三节$ git pull [remote] [branch]# 取回远程仓库的变化,并与本地分支变基合并,(Git only), 若使用 Git-SVN,请查看第三节$ git pull –rebase [remote] [branch]十、撤销# 恢复暂存区的指定文件到工作区$ git checkout [file]# 恢复暂存区当前目录的所有文件到工作区$ git checkout .# 恢复工作区到指定 commit$ git checkout [commit]# 重置暂存区的指定文件,与上一次 commit 保持一致,但工作区不变$ git reset [file]# 重置暂存区与工作区,与上一次 commit 保持一致$ git reset –hard# 重置当前分支的指针为指定 commit,同时重置暂存区,但工作区不变$ git reset [commit]# 重置当前分支的HEAD为指定 commit,同时重置暂存区和工作区,与指定 commit 一致$ git reset –hard [commit]# 新建一个 commit,用于撤销指定 commit$ git revert [commit]# 将未提交的变化放在储藏区$ git stash# 将储藏区的内容恢复到当前工作区$ git stash pop十一、查询# 查看工作区文件修改状态$ git status # 查看工作区文件修改具体内容 $ git diff [file]# 查看暂存区文件修改内容$ git diff –cached [file] # 查看版本库修改记录$ git log # 查看某人提交记录$ git log –author=someone # 查看某个文件的历史具体修改内容$ git log -p [file] # 查看某次提交具体修改内容$ git show [commit]十二、其他写在后面从 SVN 到 Git,除本文列举的基础概念和常用命令,包括但不限于如何从 SVN 服务器切换到 Git 服务器,分支模型管理等也非常重要。本文篇幅有限,针对没有介绍到但很重要的知识点会列举到参考资料里,希望作为本文的延伸阅读。相关阅读【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识 ...

October 31, 2018 · 2 min · jiezi

git常用操作

git常用操作总结仓库在当前目录新建一个Git代码库git init新建一个目录,将其初始化为Git代码库git init [project]下载一个项目git clone [url]配置显示当前的Git配置git config –list设置提交代码时的用户信息git config [–global] user.name “[name]“git config [–global] user.email “[email address]“文件操作添加指定文件到暂存区git add [file]添加指定目录到暂存区,包括子目录git add [dir]添加当前目录的所有文件到暂存区git add .删除工作区文件,并且将这次删除放入暂存区git rm [file]代码提交提交暂存区到仓库区git commit -m [message]提交暂存区的指定文件到仓库区git commit [file] -m [message]分支本地所有分支git branch远程所有分支git branch -r本地所有分支和远程所有分支git branch -a新建一个分支git branch [branch]新建一个分支,并且换到该分支git checkout -b [branch]切换回主分支git checkout master删除分支git branch -d [branch]删除远程分支push origin –delete [branch]git branch -dr [remote/branch]合并指定分支到当前分支git merge [branch]更新与合并更新本地仓库至最新git pull提交本地所有改动到远程仓库(默认master分支)git push提交到远程指定分支git push origin [branch]本地已有项目与远程仓库连接git remote add origin [远程仓库地址]首次将本地代码提交到远程git push -u origin master撤销恢复暂存区的指定文件到工作区git checkout [file]恢复暂存区的所有文件到工作区git checkout .重置暂存区与工作区,与上一次commit保持一致git reset –hard查看信息查看有变更的文件git status查看当前分支的版本历史git log查看暂存区和工作区的差异git diff以上主要是总结git常用的操作,更多git操作请看git ...

October 30, 2018 · 1 min · jiezi

yum 安装 2.x 版本的git

官方教程,在 Linux/Unix 系统中,通过工具在中安装 git,这种方式比较简单,便于升级卸载工具,网上搜到的全是源码编译安装。下面介绍在 CentOS 系统中,通过 yum 来安装 gitRed Hat Enterprise Linux, Oracle Linux, CentOS, Scientific Linux, et al.RHEL and derivatives typically ship older versions of git. You can download a tarball and build from source, or use a 3rd-party repository such as the IUS Community Project to obtain a more recent version of git.官方文档说 git 在 RHEL 和衍生产品通常都会发布旧版本的 git,我们需要源码编译安装,或者使用第三方存储库(如IUS社区项目)。现在我们通过,IUS社区下载 ius-release.rpm 文件进行安装# 注意下载不同的版本,本机 CentOS 7wget https://centos7.iuscommunity.org/ius-release.rpm# 安装rpm文件rpm -ivh ius-release.rpm查看可安装的git安装包repoquery –whatprovides git# git-0:1.8.3.1-13.el7.x86_64# git2u-0:2.16.5-1.ius.centos7.x86_64# git2u-0:2.16.2-1.ius.centos7.x86_64# git2u-0:2.16.4-1.ius.centos7.x86_64# git-0:1.8.3.1-14.el7_5.x86_64卸载我本机的 1.8.3 的 git,安装 2.16.5 的 git# 卸载老的版本yum remove git# 安装新的版本yum install git2u原文收录在这里 ...

October 29, 2018 · 1 min · jiezi

Git 使用指南

git init初始化git initgit clone克隆git clone [远端仓库] [目标文件夹名称(默认:远端仓库名)]git log查看历史提交:按时间先后顺序显示到[校验和]为止git log [校验和(默认:最新提交的校验和)]选项:–oneline:精简至单行版本–stat:增加文件修改信息-p:忽略空格引起的不同-w:忽略空格引起的不同–all –graph:用分支图显示所有历史提交–author="[作者]":显示作者包含[文本]的历史提交–grep="[文本]":显示内容包含[文本]的历史提交希望选项–all –graph成为命令git log的默认参数?在文件.bashrc中加入:git() { if [ “$1” = “log” ] then command git log –all –graph “${@:2}”; else command git “$@”; fi;}Enabling git log parameters by defaultgit shortlog查看历史提交:按作者分类显示git shortloggit show查看[校验和]提交的所有信息git show [校验和(默认:最新提交的校验和)]查看附注标签(Annotated Tag)的内容git tag [标签名]选项同git log。git status查看当前状态git statusgit diff查看尚未加入暂存区的改动git diffgit add将文件从工作区添加到暂存区git add [文件名1 文件名2 文件名3 …]将所有文件(文件.gitignore指示的除外)从工作区添加到暂存区git add .git rm将文件从暂存区移回到工作区git rm –cached [文件名1 文件名2 文件名3 …]git commit将暂存区提交到本地仓库会进入一个 vim 窗口,在此输入提交信息。所有以#开头的行都会被忽略。对于空行的问题无需纠结,因为 git 会忽略所有不必要的空行。git commit键入提交信息并提交git commit -m [提交信息]更新最近的提交(内容和信息)git commit –amend如修改了提交内容,建议先执行:git add .提交信息的书写规范(Udacity)Udacity Git Commit Message Style GuideThe goal is that each commit has a single focus. Each commit should record a single-unit change. Now this can be a bit subjective (which is totally fine), but each commit should make a change to just one aspect of the project.Conversely, a commit shouldn’t include unrelated changes - changes to the sidebar and rewording content in the footer. These two aren’t related to each other and shouldn’t be included in the same commit. Work on one change first, commit that, and then change the second one. That way, if it turns out that one change had a bug and you have to undo it, you don’t have to undo the other change too.The best way that I’ve found to think about what should be in a commit is to think, “What if all changes introduced in this commit were erased?”. If a commit were erased, it should only remove one thing.DO:do keep the message short (less than 60-ish characters)do explain what the commit does (not how or why!)DO NOT:do not explain why the changes are made (more on this below)do not explain how the changes are made (that’s what git log -p is for!)do not use the word “and"if you have to use “and”, your commit message is probably doing too many changes - break the changes into separate commitse.g. “make the background color pink and increase the size of the sidebar"git tag查看所有标签git tag添加轻便标签(Lightweight Tag)git tag [标签名] [校验和(默认:最新提交的校验和)]添加附注标签(Annotated Tag)会进入一个 vim 窗口,在此输入标签内容。所有以#开头的行都会被忽略。对于空行的问题无需纠结,因为 git 会忽略所有不必要的空行。git tag -a [标签名] [校验和(默认:最新提交的校验和)]键入附注标签的内容并提交git tag -a [标签名] [校验和(默认:最新提交的校验和)] -m [附注标签的内容]删除本地标签git tag -d [标签名1 标签名2 标签名3 …]删除指定远端标签git push [远端名] -d refs/tags/[标签名]git push [远端名] :refs/tags/[标签名]推送所有本地标签到远端git push [远端名] –tag从远端拉取所有标签到本地git fetch [远端名] –tag(在远端唯一的情况下,[远端名]可以省略。)git checkout切换git branch [校验和 / 标签名 / 分支名]恢复工作区中的某个文件到上次提交的状态git checkout – [文件名]恢复工作区中的全部文件到上次提交的状态git checkout – .git branch查看所有本地分支git branch查看所有远端分支git branch -r新建分支git branch [分支名] [校验和(默认:最新提交的校验和)]删除分支git branch -d [分支名1 分支名2 分支名3 …]删除分支的前提条件是:该分支不是当前分支。该分支上的最新提交已经合并到另一分支上(如需忽略本条件,请使用-D选项。警告:尚未合并的所有提交将会全部丢失!)。git merge将[分支名]合并到当前分支git merge [分支名]合并操作操作会因为冲突(conflict)而中止,条件是:参与合并的两个分支上,各存在一个提交,它们修改了同一个行范围。如需撤销合并操作,请使用命令git merge –abort。冲突的处理方法(Udacity)Merge Conflict Output ExplainedThe output that shows in the Terminal is:$ git merge heading-updateAuto-merging index.htmlCONFLICT (content): Merge conflict in index.htmlAutomatic merge failed; fix conflicts and then commit the result.Notice that right after the git merge heading-update command, it tries merging the file that was changed on both branches (index.html), but that there was a conflict. Also, notice that it tells you what happened - “Automatic merge failed; fix conflicts and then commit the result”.Remember our good friend git status? Well he’ll come in really handy when working with merge conflicts.$ git statusOn branch masterYou have unmerged paths. (fix conflicts and run “git commit”) (use “git merge –abort” to abort the merge)Unmerged paths: (use “git add <file> …” to mark resolution) both modified: index.htmlThe git status output tells us to that the merge conflict is inside index.html. So check out that file in your code editor!Merge Conflict Indicators Explanation<<<<<<< HEAD everything below this line (until the next indicator) shows you what’s on the current branch||||||| merged common ancestors everything below this line (until the next indicator) shows you what the original lines were> > > > > > > heading-update is the ending indicator of what’s on the branch that’s being merged in (in this case, the heading-update branch)Resolving A Merge ConflictGit is using the merge conflict indicators to show you what lines caused the merge conflict on the two different branches as well as what the original line used to have. So to resolve a merge conflict, you need to:choose which line(s) to keepremove all lines with indicatorsFor some reason, I’m not happy with the word “Crusade” right now, but “Quest” isn’t all that exciting either. How about “Adventurous Quest” as a heading?!?Commit Merge ConflictOnce you’ve removed all lines with merge conflict indicators and have selected what heading you want to use, just save the file, add it to the staging index, and commit it! Just like with a regular merge, this will pop open your code editor for you to supply a commit message. Just like before, it’s common to use the provided merge commit message, so after the editor opens, just close it to use the provided commit message.And that’s it! Merge conflicts really aren’t all that challenging once you understand what the merge conflict indicators are showing you.If a merge conflict occurs in a file and you edit the file, save it, stage it, and commit it but forget to remove the merge conflict indicators, Git will commit the lines with the merge conflict indicators, because they’re just regular characters.git revertgit revert [校验和]设[校验和]提交的前一个提交为PREVIOUS,修改的行范围是range。该命令的作用是回滚range范围内的修改,将会产生一个新的提交。回滚操作操作会因为冲突而中止,条件是:如果range范围内的某一部分在[校验和]提交的某个后续提交中被修改。如需撤销回归操作,请使用命令git revert –abort。冲突的处理方法与git merge相同。git resetgit reset [校验和]该命令的作用是回到[校验和]提交的状态,即撤销[校验和]提交的后续提交的所有修改modification。选项:–mixed:将modification移入工作区(默认)–soft:将modification移入暂存区–hard:忽略(删除)modification执行git reset之后,[校验和]提交的后续提交未被删除。可以通过下列命令查看这些不属于任何分支的提交:git reloggit fsck –unreachable –no-reflog(具体使用方法详见后文。)可以通过切换到提交、新建分支、合并到现有分支的方法恢复这些提交(即回滚git reset操作)。相对引用(Udacity)Relative Commit ReferencesYou already know that you can reference commits by their SHA, by tags, branches, and the special HEAD pointer. Sometimes that’s not enough, though. There will be times when you’ll want to reference a commit relative to another commit. For example, there will be times where you’ll want to tell Git about the commit that’s one before the current commit…or two before the current commit. There are special characters called “Ancestry References” that we can use to tell Git about these relative references. Those characters are:^ – indicates the parent commit~ – indicates the first parent commitHere’s how we can refer to previous commits:the parent commit – the following indicate the parent commit of the current commitHEAD^HEADHEAD1the grandparent commit – the following indicate the grandparent commit of the current commitHEAD^^HEAD2the great-grandparent commit – the following indicate the great-grandparent commit of the current commitHEAD^^^HEAD3The main difference between the ^ and the ~ is when a commit is created from a merge. A merge commit has two parents. With a merge commit, the ^ reference is used to indicate the first parent of the commit while ^2 indicates the second parent.The first parent is the branch you were on when you ran git mergeThe second parent is the branch that was merged in.git remote查看所有远端仓库的 URLgit remote -v关联到远端仓库:[远端仓库的别名]通常被设为origingit remote add [远端仓库的别名] [远端仓库的URL]取消与远端仓库的关联git remote remove [远端仓库的别名]git push这里仅讨论同时满足下列条件的情形:本地分支和远程分支同名。单一远端,通常是 origin。将本地分支推送到远端(完整命令)git push [远端名] [本地分支] [远端分支]省略[远端分支]的情形:将[本地分支]推送到“与之存在追踪关系的”远程分支(通常两者同名),如果该远程分支不存在,则会被新建。git push [远端名] [本地分支]可以为该命令添加-u参数,表示将远端分支设为[本地分支]的 upstream branch。git push -u [远端名] [本地分支]执行上述命令后,就可以在切换到相应分支git checkout [本地分支]之后,直接使用命令git push了。git push选项–all表示推送所有分支到远端,通常添加选项-u以设定所有本地分支的 upstream branch。git push -u –all删除远端分支git push [远端名] -d [远端分支]git push [远端名] :[远端分支]如果出现各种原因导致命令git push不能成功执行(例如:删除并重建本地分支、合并本地的commit),可以使用选项-f进行强行(覆盖)推送。请注意:不要在多人合作的远端分支中慎用,原因参见:团队开发里频繁使用 git rebase 来保持树的整洁好吗?git 如何撤销一次remote的master commit?git push -fgit pull这里仅讨论同时满足下列条件的情形:本地分支和远程分支同名。单一远端,通常是 origin。该命令的用途是:取回远程主机某个分支的更新,再与本地的指定分支合并。因为远端分支 origin/master 通常是本地分支 master 的更新,所以合并操作只是移动 master 引用的位置,通常难以察觉。将远端分支拉取到本地(完整命令,多用于创建和远端分支对应的本地分支)。git pull [远端名] [远端分支]:[本地分支]在满足下列条件的前提下,可以直接使用命令git pull:已使用git checkout将该对应的本地分支切换为当前分支。该分支的 upstream branch 已设置。具体方法为git branch –set-upstream-to=origin/[远端分支] [本地分支]git pullgit fetch这里仅讨论同时满足下列条件的情形:本地分支和远程分支同名。单一远端,通常是 origin。该命令的用途是:取回远程主机某个分支的更新,但是不与本地分支合并。git fetch [远端名] [远端分支]:[本地分支]在满足下列条件的前提下,可以直接使用命令git pull:已使用git checkout将该对应的本地分支切换为当前分支。该分支的 upstream branch 已设置。具体方法为git branch –set-upstream-to=origin/[远端分支] [本地分支]git fetch区别于命令git pull:命令git fetch让用户决定怎样合并远端分支和本地分支。命令git pull自动进行分支合并,在某些情况下可能无法成功执行。problem本地分支和远端分支被同时更新。更新前: master |remote a – 3 – d – f – e – 7============================================================ origin/master |local a – 3 – d – f – e – 7 | master更新后: master |remote a – 3 – d – f – e – 7 – 8============================================================ origin/master |local a – 3 – d – f – e – 7 – b | masterSolution首先先使用命令git fetch,获取远端分支更新。 master |remote a – 3 – d – f – e – 7 – 8============================================================ origin/master | 8 /local a – 3 – d – f – e – 7 – b | master再使用命令git merge origin/master,将远端分支合并到本地分支。 master |remote a – 3 – d – f – e – 7 – 8============================================================ origin/master | 8 / \local a – 3 – d – f – e – 7 – b – 4 | master最后使用命令git push,推送本地分支到远端分支。 master | 8 | / \ |remote a – 3 – d – f – e – 7 – 8 – 4============================================================ origin/master | 8 | / \ |local a – 3 – d – f – e – 7 – b – 4 | master其他https://www.worldhello.net/go…查看(90天内的)操作历史git reflog查看不可达的(unreachable)对象,包括但不限于:暂存区操作时引入的临时对象(以unreachable blob开头)不在分支上的提交(以unreachable commit开头)git fsck –unreachable –no-reflog清除不可达的对象(通常为:暂存区操作时引入的临时对象)如果对象git reflog命令中可见,那么git prune就不能清除它。若一定要清除,则需先使用git reflog expire –expire=now –all清除所有历史(不推荐)。git prune优化仓库git gc ...

October 26, 2018 · 7 min · jiezi