diff --git "a/Day91-100/91.\345\233\242\351\230\237\351\241\271\347\233\256\345\274\200\345\217\221\347\232\204\351\227\256\351\242\230\345\222\214\350\247\243\345\206\263\346\226\271\346\241\210.md" "b/Day91-100/91.\345\233\242\351\230\237\351\241\271\347\233\256\345\274\200\345\217\221\347\232\204\351\227\256\351\242\230\345\222\214\350\247\243\345\206\263\346\226\271\346\241\210.md" index f26d0ec616ee0471bac0ac25bf3af663ba1728d0..9381b4bf990a53820547e78451c5761baafb994d 100644 --- "a/Day91-100/91.\345\233\242\351\230\237\351\241\271\347\233\256\345\274\200\345\217\221\347\232\204\351\227\256\351\242\230\345\222\214\350\247\243\345\206\263\346\226\271\346\241\210.md" +++ "b/Day91-100/91.\345\233\242\351\230\237\351\241\271\347\233\256\345\274\200\345\217\221\347\232\204\351\227\256\351\242\230\345\222\214\350\247\243\345\206\263\346\226\271\346\241\210.md" @@ -77,11 +77,12 @@ Git是诞生于2005年的一个开源分布式版本控制系统,最初是Linus Torvalds(Linux之父) 为了帮助管理Linux内核开发而开发的一个版本控制软件。Git与常用的版本控制工具Subversion等不同,它采用了分布式版本控制的方式,在没有中央服务器支持的环境下也能够实施版本控制。 对于有使用Subversion(以下简称为SVN)经验的人来说,Git和SVN一样摒弃了基于锁定模式的版本控制方案(早期的CVS和VSS使用的就是锁定模式)采用了合并模式,而二者的区别在于: - 1. Git是分布式的,SVN是集中式的,SVN需要中央服务器才能工作。 - 2. Git把内容按元数据方式存储,而SVN是按文件,即把文件的元信息隐藏在一个.svn文件夹里。 - 3. Git分支和SVN的分支不同。 - 4. Git没有一个全局版本号而SVN有。 - 5. Git的内容完整性要优于SVN,Git的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。 + +1. Git是分布式的,SVN是集中式的,SVN需要中央服务器才能工作。 +2. Git把内容按元数据方式存储,而SVN是按文件,即把文件的元信息隐藏在一个.svn文件夹里。 +3. Git分支和SVN的分支不同。 +4. Git没有一个全局版本号而SVN有。 +5. Git的内容完整性要优于SVN,Git的内容存储使用的是SHA-1哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网络问题时降低对版本库的破坏。 #### 安装Git @@ -153,11 +154,7 @@ git add . git status ``` -如果不希望将文件添加到暂存区,可以按照提示,使用下面的命令将文件从暂存区放回到工作区。 - -```Shell -git rm --cached -``` +> **提示**:如果不希望将文件添加到暂存区,可以按照提示,使用`git rm --cached `命令将文件从暂存区放回到工作区。 如果这个时候对工作区的文件又进行了修改使得工作区和暂存区的内容并不相同了,再次执行`git status`可以看到哪个或哪些文件被修改了,如果希望用暂存区的内容恢复工作区,可以使用下面的命令。 @@ -166,7 +163,7 @@ git restore git restore . ``` -> 提示:上面的命令目前仍然处于试验性阶段,在Git较早的版本中对应的命令是`git checkout -- `。由于`git checkout`这个命令还可以用于切换分支,容易引起混淆,所以Git最新版本中将这个命令的两项功能分别赋予两个新的命令,一个就是上面的`git restore`,另一个是`git switch`。 +> **注意**:上面的命令目前仍然处于试验性阶段,在Git较早的版本中对应的命令是`git checkout -- `。由于`git checkout`这个命令还可以用于切换分支,容易引起混淆,所以Git最新版本中将这个命令的两项功能分别赋予两个新的命令,一个就是上面的`git restore`,另一个是`git switch`。 如果第一次使用Git,需要配置用户名和邮箱,然后才能将代码提交到仓库。 @@ -190,16 +187,9 @@ git log git log --graph --pretty=oneline --abbrev-commit ``` -如果要回到历史版本,可以使用下面的命令。 - -```Shell -git reset --hard -git reset --hard HEAD^ -``` - #### Git服务器概述 -Git不像SVN那样一定需要中央服务器才能工作,上面我们演示的版本控制操作都是在本地执行的,但是对于企业开发多人协作这样的环境就必须中央服务器的支持。通常,企业可以选择使用像Github这样的代码托管平台或自己搭建Git私服的方式来建立中央服务器。Github是一个基于Git的代码托管平台,企业用户(付费用户)可以创建私有仓库(仓库内容不对外公开),普通用户只能创建公开仓库(仓库内容对他人可见)。Github创办于2008年4月,目前是全世界最大的代码托管平台,它上面代码库惊人的增长速度也证明了它是非常成功的,在2018年6月被微软以75亿美元的天价收购,目前该平台已经向非企业用户开放了受限使用私有仓库的功能。 +Git不像SVN那样一定需要中央服务器才能工作,上面我们演示的版本控制操作都是在本地执行的,但是对于企业开发多人协作这样的环境就必须中央服务器的支持。通常,企业可以选择使用像Github这样的代码托管平台或自己搭建Git私服的方式来建立中央服务器。Github是一个基于Git的代码托管平台,创办于2008年4月,目前是全世界最大的代码托管网站,支持企业用户(可以创建私有仓库,私有仓库内容不对外界公开)和普通用户(受限的使用私有仓库,不受限的使用公开仓库,公开仓库内容对他人可见)。Github上面代码库惊人的增长速度证明了它是非常成功的,在2018年6月被微软以75亿美元的天价收购。 国内也有不少类似Github的代码托管平台,最有名的当属[码云](https://gitee.com/)和[CODING](https://coding.net/),目前码云和CODING对注册用户都提供了受限的使用私有仓库的功能,支持**Pull Request**(本质是一种对话机制,可以在提交你的工作成果时让相关人员或团队注意到这件事情),同时还提供了对**缺陷管理**、**Web Hook**等功能支持,这些使得版本控制系统还具备了缺陷管理和持续集成的能力。当然,很多公司都不愿意将自己的商业代码托管于别人的平台,对于这样的公司可以使用[Gitlab]()来搭建公司内部的Git私服,具体的做法在下一章为大家介绍。 @@ -227,15 +217,37 @@ Git不像SVN那样一定需要中央服务器才能工作,上面我们演示 #### Git远程操作 -在拥有了Git服务器之后,我们就可以通过Git的远程操作将自己的工作成果推到服务器上,也可以将他人的工作成果从服务器更新到本地,我们还是以刚才在码云上创建的名为`python`的仓库为例来说明如何进行远程操作。 +拥有了Git服务器之后,我们就可以通过Git的远程操作将自己的工作成果推到服务器的仓库中,也可以将他人的工作成果从服务器仓库更新到本地。我们还是以刚才在码云上创建的名为`python`的仓库为例来说明如何进行远程操作。可以在如下所示的页面上看到仓库的地址,如果配置了**SSH Key**就使用SSH方式访问仓库,否则就用HTTPS方式,后者需要在进行远程操作时提供用户名和口令。 + +![](./res/gitee-project-index.png) + +1. 添加远程仓库(Git服务器)。 + + ```Shell + git remote add origin git@gitee.com:jackfrued/python.git + ``` + + 其中`git@gitee.com:jackfrued/python.git`是上图中显示的仓库的URL,而前面的`origin`是替代这个冗长的URL的字符串,简单的说`origin`就是服务器上仓库的别名(如果有多个Git服务器,这个简短的名字也会有多个)。可以用`git remote -v`来查看已经指定的Git服务,也可以用`git remote remove`来删除指定的Git服务器。 + +2. 将本地代码(工作成果)推送到远程仓库。 + + ```Shell + git push -u origin master:master + ``` + + 其中,`-u`是`--set-upstream`的缩写,用来指定推送的服务器仓库,后面的`origin`就是刚才给仓库起的简短的别名,冒号前面的`master`是本地分支名,冒号后面的`master`是远程分支名,如果本地分支`master`已经和远程分支`master`建立过关联,则可以省略冒号以及后面的部分。 + + > **说明**:一般不能直接将工作成果push到master分支,因为它通常是一个受保护分支。 -1. 指定远程主机(Git服务器)。 -2. 将本地代码(工作成果)推送到远程主机。 -3. 从远程主机取回代码。 +3. 从远程仓库取回代码。 + + ```Shell + git pull origin master + ``` #### Git分支操作 -1. 创建分支和切换分支。 +1. 创建和切换分支。下面的命令创建了名为`dev` 的分支并切换到该分支。 ```Shell git branch @@ -248,11 +260,90 @@ Git不像SVN那样一定需要中央服务器才能工作,上面我们演示 git switch -c ``` - > **提示**:在之前的Git版本中,切换分支使用`git checkout `命令,也可以通过`git checkout -b `来创建并切换分支。`git switch`命令目前仍然处于试验性阶段,但很明显这个命令更加清晰的表达了它要做的事情。 + > **注意**:在之前的Git版本中,切换分支使用`git checkout `命令,也可以通过`git checkout -b `来创建并切换分支。`git switch`命令目前仍然处于试验性阶段,但很明显这个命令更加清晰的表达了它要做的事情。 + +2. 关联远程分支。例如:如果当前所在的分支还没有关联到远程分支,可以使用下面的命令为它们建立关联。 + + ```Shell + git branch --set-upstream-to origin/develop + ``` + + 如果需要为指定的分支关联远程分支,可以如下操作。 + + ```Shell + git branch --set-upstream-to origin/develop + ``` + + > 提示:上面的操作假设Git服务器上存在名为`develop`的分支,`--set-upstream-to`可以缩写为`-u`。 + + 当然,在创建分支时,如果使用了`--track`参数,也可以直接指定与本地分支关联的远程分支,如下所示。 + + ```Shell + git branch --track origin/develop + ``` + + 如果需要解除本地分支与远程分支的关联,可以使用下面的命令。 + + ```Shell + git branch --unset-upstream + ``` + +3. 分支合并。例如在`dev`分支上完成开发任务之后,如果希望将`dev`分支上的成果合并到`master`,可以先切回到`master`分支然后使用`git merge`来做分支合并,合并的结果如下图右上方所示。 + + ```Shell + git switch master + git merge dev + ``` + + 使用`git merge`合并分支时,默认使用`Fast Forward`合并,这意味着如果删除了分支,分支上的信息就全都丢掉了,如果希望将分支上的历史版本保留下来,可以使用`--no-ff`参数来禁用`Fast Forward`。 + + 在合并分支时,没有冲突的部分Git会做自动合并。如果发生了冲突(如dev和master分支上都修改了同一个文件),会看到`CONFLICT (content): Merge conflict in . Automatic merge failed; fix conflicts and then commit the result`(自动合并失败,修复冲突之后再次提交)的提示,这个时候我们可以用`git diff`来查看产生冲突的内容。解决冲突通常需要当事人当面沟通之后才能决定保留谁的版本,冲突解决后需要重新提交代码。 + +4. 分支变基。分支合并操作可以将多个分支上的工作成果最终合并到一个分支上,但是再多次合并操作之后,分支可能会变得非常的混乱和复杂,为了解决这个问题,可以使用`git rebase`操作来实现分支变基。如下图所示,当我们希望将`master`和`dev`上的工作成果统一到一起的时候,也可以使用变基操作。 + + ![](./res/git-rebase.png) + + ```Shell + git rebase master + git switch master + git merge dev + ``` + + 当我们在`dev`分支执行`git rebase`命令时,将首先计算`dev`分支和`master`分支的差集,然后应用该差集到`dev`分支,最后我们切回到`master`分支并执行操作合并,这样就看到了如上图右下方所示的干净的分支。 + +5. 删除分支。删除分支可以使用`git branch`加上`-d`参数,如果分支上的工作成果还没有合并,那么在删除分支时会看到`error: The branch '' is not fully merged.`这样的错误提示。如果希望强行删除分支,可以使用`-D`参数。删除分支的操作如下所示。 + + ```Shell + git branch -d + error: The branch '' is not fully merged. + If you are sure you want to delete it, run 'git branch -D '. + git branch -D + ``` + + 如果要删除远程分支,可以使用下面的命令,但是请慎重的操作。 -2. 分支合并和变基。 + ```Shell + git branch -r -d origin/develop + git push origin :develop + ``` -3. +#### Git其他操作 + +1. `git fetch`:下载远程仓库的所有变动,可以将远程仓库下载到一个临时分支,然后再根据需要进行合并操作,`git fetch`命令和`git merge`命令可以看作是之前讲的`git pull`命令的分解动作。 + +2. `git diff`:常用于比较工作区和仓库、暂存区与仓库、两个分支之间有什么差别。 + +3. `git stash`:将当前工作区和暂存区发生的变动放到一个临时的区域,让工作区变干净。这个命令适用于手头工作还没有提交,但是突然有一个更为紧急的任务(如线上bug需要修正)需要去处理的场景。 + +4. `git reset`:回退到指定的版本。该命令主要有三个参数,如下图所示。 + + ![](./res/git-reset.png) + +5. `git cherry-pick`:挑选某个分支的单次提交。 + +6. `git revert`:撤回提交信息。 + +7. `git tag`:打版本标签。 #### Git工作流程(分支管理策略) @@ -263,13 +354,13 @@ Git不像SVN那样一定需要中央服务器才能工作,上面我们演示 1. 克隆服务器上的代码到本地。 ```Shell - git clone + git clone git@gitee.com:jackfrued/python.git ``` 2. 创建并切换到自己的分支。 ```Shell - git switch -c + git switch -c ``` 3. 在自己的分支上开发并在本地做版本控制。 @@ -277,14 +368,14 @@ Git不像SVN那样一定需要中央服务器才能工作,上面我们演示 4. 将自己的分支(工作成果)推到服务器。 ```Shell - git push + git push origin ``` 5. 在线发起一次合并请求(通常称之为**Pull Request**,有的地方称为**Merge Request**),请求将自己的工作成果合并到master分支,合并之后可以删除该分支。 ![](./res/gitee-pull-request.png) -上面这种分支管理策略就是被称为github-flow或PR的流程,它非常简单容易理解,只需要注意以下几点: +上面这种分支管理策略就是被称为**github-flow**或**PR**的流程,它非常简单容易理解,只需要注意以下几点: 1. master的内容都是可以进行发布的内容(不能直接在master上进行修改)。 2. 开发时应该以master为基础建立新分支(日常开发任务在自己的分支上进行)。 @@ -300,7 +391,7 @@ Git不像SVN那样一定需要中央服务器才能工作,上面我们演示 ![](./res/git-flow.png) -在这种模式下,项目有两个长线分支,分别是master和develop,其他都是临时的的辅助分支,包括feature(开发特定功能的分支,开发结束后合并到develop)、release(从develop分离出来的为发布做准备的分支,发布结束后合并到master和develop)和hotfix(产品发布后出现问题时紧急建立的分支,直接从master分离,问题修复后合并到master并打上标签,同时还要合并到develop来避免将来的版本遗漏了这个修复工作,如果此时有正在发布中的release分支,还要合并到release分支)。这套分支管理策略比较容易控制各个分支的状况,但是在运用上github-flow要复杂得多,所以实际使用的时候可以安装名为`gitflow`的命令行工具或者使用图形化的Git工具(如:SmartGit、SourceTree等),这样可以大幅度的简化版本控制操作,具体的可以参考[《git-flow 的工作流程》]()一文。 +在这种模式下,项目有两个长线分支,分别是master和develop,其他都是临时的的辅助分支,包括feature(开发特定功能的分支,开发结束后合并到develop)、release(从develop分离出来的为发布做准备的分支,发布结束后合并到master和develop)和hotfix(产品发布后出现问题时紧急建立的分支,直接从master分离,问题修复后合并到master并打上标签,同时还要合并到develop来避免将来的版本遗漏了这个修复工作,如果此时有正在发布中的release分支,还要合并到release分支)。这套分支管理策略比较容易控制各个分支的状况,但是在运用上github-flow要复杂得多,所以实际使用的时候可以安装名为`gitflow`的命令行工具或者使用图形化的Git工具(如:SmartGit、SourceTree等),这样可以大幅度的简化版本控制操作,具体的可以参考[《git-flow 的工作流程》]()一文,因为这篇文章写得已经很好了,本文不再进行赘述。 ### 缺陷管理 @@ -312,14 +403,6 @@ Git不像SVN那样一定需要中央服务器才能工作,上面我们演示 4. 能够生成各类报表。 5. 能够关联到其他系统,具有可扩展性。 -#### Redmine - -Redmine是基于Ruby on Rails框架的开源缺陷管理系统,提供了问题管理、代码管理、Wiki等必要的功能,而且支持插件系统,扩展起来也非常容易。 - -![](./res/redmine_new_issue.png) - -如果希望了解和使用Redmine,可以关注[Redmine中文网](http://www.redmine.org.cn/),上面提供了视频教程、经验分享以及其他安装和使用上的指导。 - #### 禅道 [禅道]()是国产的专业项目管理软件,它不仅仅是缺陷管理工具,它提供了完整软件生命周期管理功能,支持Scrum敏捷开发,能够实现需求管理、缺陷管理、任务管理等一系列的功能,而且拥有强大的扩展机制和丰富的功能插件。可以从禅道的官方网站提供的[下载链接]()来下载禅道,推荐使用一键安装包。 @@ -352,12 +435,35 @@ tar -xvf ZenTaoPMS.pro8.5.2.zbox_64.tar #### Gitlab +一般的代码托管平台或者是我们之前提到的Git私服Gitlab都提供了缺陷管理的功能,当我们要报告一个bug时,可以在如下图所示的界面创建一个新的问题票(issue ticket)。填写的内容包括: + +1. **[必填]**出现问题的软件版本号、具体的使用环境(如操作系统)等相关信息。 +2. **[必填]**能够稳定重现该问题的相关步骤。 +3. **[必填]**描述此处期待的行为和实际的行为。 +4. **[可选]**你对这个bug的看法(产生bug的原因是什么)。 + +![](./res/gitlab-new-issue.png) +如上图所示,我们在创建问题票时,还需要将问题指派给处理问题的人,如果不清楚应该由谁来修复这个bug,就指派给项目管理者,除此之外还要指定问题的优先级(十分紧急、紧急、普通、不紧急等)、问题的标签(功能缺陷、新特性、改进增强、前瞻研究等)、里程碑(通过里程碑可以将问题与某些特定的项目节点关联起来,之后可以查看每一个里程碑的进展,可以基于软件版本号来建立里程碑,也可以基于迭代周期来建立里程碑)以及需要在哪个时间点以前修复等信息。 + +有些敏捷团队使用问题票来管理产品的需求,称之为“问题驱动开发”,如果要创建一个和需求相关的问题票,应该要填写以下的内容: + +1. **[必填]**简短的描述你的需求,并用它作为标题。 +2. **[必填]**这个需求是解决什么问题的。 +3. **[必填]**这个需求对软件现有功能会造成什么影响。 +4. **[必填]**这个需求应该实现什么样的功能。 +5. **[必填]**这个需求是否依赖其他模块提供相关支持。 +6. **[可选]**这个需求有哪些实现方式。 +7. **[可选]**这些可选的实现方式分别有哪些优缺点。 ### 持续集成 为了快速的产生高品质的软件,在团队开发中,持续集成(CI)也是一个非常重要的基础。按照经典的软件过程模型(瀑布模型),集成的工作一般要等到所有的开发工作都结束后才能开始,但这个时候如果发现了问题,修复问题的代价是非常具体的。基本上,集成实施得越晚,代码量越大,解决问题就越困难。持续集成将版本控制、自动化构建、代码测试融入到一起,让这些工作变得自动化和可协作。由于其频繁重复整个开发流程(在指定时间内多次pull源代码并运行测试代码),所以能帮助开发者提早发现问题。 -在所有的CI工具中,Jenkins和[TravisCI]()是最具有代表性的,前者是基于 Java的开源CI工具,后者是新晋的在线CI工具。我们可以借助Docker来安装Jenkins(下一章节讲解),安装后……。Jenkins不仅能在面板上轻松看出任务成功或失败,还可以借助通知功能将结果以邮件或RSS订阅的形式发给用户。与此同时,Jenkins也允许通过插件进行功能扩展,所需功能可以随用随添加,而且还支持主从式集群,能够轻松的进行水平扩展。 +在所有的CI工具中,Jenkins和[TravisCI]()是最具有代表性的,前者是基于 Java的开源CI工具,后者是新晋的在线CI工具,下图是Jenkins的工作面板。 + +![](./res/jenkins_new_project.png) + +Gitlab也对CI和CD(持续交付)提供了支持,具体内容请大家参考[《GitLab CI/CD基础教程》]()。 -![](./res/jenkins_new_project.png) \ No newline at end of file +> **说明**:本章中的部分插图来自于网易云课堂《人人都会用Git》免费课程,在此表示感谢。 \ No newline at end of file diff --git a/Day91-100/res/git-rebase.png b/Day91-100/res/git-rebase.png new file mode 100644 index 0000000000000000000000000000000000000000..8896bd1aab1c4bc19084d9d0e0433b75ea46bc40 Binary files /dev/null and b/Day91-100/res/git-rebase.png differ diff --git a/Day91-100/res/git-reset.png b/Day91-100/res/git-reset.png new file mode 100644 index 0000000000000000000000000000000000000000..d9f7f2e6b15be645f2fb2d6fca82bf2a598b217b Binary files /dev/null and b/Day91-100/res/git-reset.png differ diff --git a/Day91-100/res/gitee-project-index.png b/Day91-100/res/gitee-project-index.png new file mode 100644 index 0000000000000000000000000000000000000000..6f6e8938949f591d21d3a697607c3ce7eda0df48 Binary files /dev/null and b/Day91-100/res/gitee-project-index.png differ diff --git a/Day91-100/res/gitee-pull-request.png b/Day91-100/res/gitee-pull-request.png new file mode 100644 index 0000000000000000000000000000000000000000..da808aa678c62a6831d5e897c30876ac15602ac0 Binary files /dev/null and b/Day91-100/res/gitee-pull-request.png differ diff --git a/Day91-100/res/gitlab-new-issue.png b/Day91-100/res/gitlab-new-issue.png new file mode 100644 index 0000000000000000000000000000000000000000..e26e9cdc1fcfe19ba8808ae91bc631d1eb21845d Binary files /dev/null and b/Day91-100/res/gitlab-new-issue.png differ diff --git a/Day91-100/res/redmine_new_issue.png b/Day91-100/res/redmine_new_issue.png deleted file mode 100644 index 63971fca4345c215d4c817cbd91e5e410fe57874..0000000000000000000000000000000000000000 Binary files a/Day91-100/res/redmine_new_issue.png and /dev/null differ