新兵训练营课程——环境与工具Java[转]

原文地址:http://weibo.com/p/1001643874239169320051

程序员在开发过程中会用到很多工具来提升开发和协作效率,这次介绍的是目前微博平台在开发过程中用到的一些工具,文章内容包括如何初始化开发环境,工具的基本使用和原理等。

这篇文章里会介绍到的一些工具:

  • 打包构建:maven

  • 版本管理:git

  • 部署发布:docker

  • 问题排查:wtool

开发环境的初始化

  1. 安装jdk1.7+,地址://java.com/zh_CN/download/faq/develop.xml

  2. 安装maven,地址:https://maven.apache.org

  3. 安装git,地址:https://git-scm.com

  4. 选择Eclipse或Idea作为编译器,并配置统一的代码格式化文件。

  5. 使用linux/mac的同学可以从内网仓库下载初始化脚本自动初始化开发环境,

  6. 使用linux/mac的同学可以安装wtool方便进行问题排查,地址:https://github.com/qdaxb/wtool

maven入门

简介

maven是什么

maven是一个项目构建和管理的工具,目前大部分java工程都选择使用maven作为构建工具。

是否还有其它构建工具

  • gradle目前正在开始流行的新一代构建工具,微博平台部分工程正在使用,可以参考 https://gradle.org

  • ant软件构建工具,过去几年已经逐渐被maven取代,参考:ant.apache.org

  • ant+ivy在ant的基础上提供依赖管理功能,参考://ant.apache.org/ivy/index.html

在这里还是以比较成熟的maven为例子,介绍一下构建管理工具的基本用途和使用方式。

maven能做什么

  • 依赖管理

  • 多模块构建

  • 约定工程结构

  • 约定构建模型

  • 插件系统

maven的概念

maven pom

maven通过xml表示maven项目,一个项目所有的配置都放置在 POM.xml 文件中:定义项目的类型、名字,管理依赖关系,定制插件的行为等等。

<?xml version="1.0" encoding="UTF-8"?>

<project>

     <modelVersion>4.0.0</modelVersion>

     <artifactId>weibo-demo</artifactId>

     <groupId>com.weibo.api</groupId>

     <version>1.0.21</version>

     <packing>jar</packing>

</project>

  • maven使用groupId:artifactId:version三者来唯一标识一个唯一的二进制版本,可以缩写为GAV。

  • packaging代表打包方式,可选的值有:

    • pom, jar, war, ear, custom

    • Default is jar

pom的继承

<?xml version="1.0" encoding="UTF-8"?>

<project>

...

     <parent>

             <artifactId>weibo-api</artifactId>

             <groupId>com.weibo.api</groupId>

             <version>1.13</version>

     </parent>

...

</project>

  • pom可以继承的元素如下:

    • groupId, version

    • Project Config

    • Dependencies

    • Plugin configuration

多模块工程

  • 日常开发中一个工程可能比较庞大,这时可以把这个工程拆分成多个子模块来管理。一个多模块工程包含一个父pom,在其中定义了它的子模块;每个子模块都是一个独立的工程。

<project>

 ...

 <packaging>pom</packaging>

 <modules>

     <module>maven-training</module>

     <module>maven-training-web</module>

 </modules>

</project>

多模块工程的文件夹结构如下:

Maven的约定

  • maven强调“约定优于配置”,具体来说,一个maven工程的约定有如下几个方面:

工程结构的约定

target: 构建输出目录

src: 源码目录

src/main: 源码主目录

src/test: 测试源码主目录

src/main/java: java源文件目录

src/main/webapp: web源码目录,如jsp等

src/main/resources: 不需要编译的文件

src/test/java: java测试源码目录

src/test/resources: 不需要编译的测试文件

构建生命周期的约定

generate-sources/generate-resources

compile

test

package

integration-test (pre and post)

Install

deploy

Maven常用命令

mvn clean 

-清除clean

mvn clean compile

-执行 clean, generate*, compile

mvn clean package

-执行clean ,generate*, compile, test, interation-test, package

mvn install

-执行 generate*, compile, test, integration-test, package, install

mvn test 

-执行 generate*, compile, test 

Maven与依赖

  • 如果当前工程依赖于其它的项目,那么可以在pom里声明如下:

<project>

 ...

 <dependencies>

     <dependency>

         <groupId>javax.servlet</groupId>

         <artifactId>servlet-api</artifactId>

         <version>2.5</version>

         <scope>provided</scope>

     </dependency>

 </dependencies>

</project>

  • scope分为: compile, test, provided (默认为compile)

  • type可以指定: jar, pom, war, ear, zip (默认jar)

依赖仲裁

当maven依赖的路径上出现冲突的时候可以用如下几种方式解决依赖冲突问题:

  • 路径最短:依赖maven总是优先使用路径最短的依赖版本。

  • dependencyManagement:可以通过dependencyMangement指定依赖项目的版本号

  • 父pom:子工程会继承父工程的依赖

  • 强制指定依赖版本:使用[from,to]表示。如[1.0,1.1]代表从1.0到1.1版本;或者[1.0]代表强制使用1.0版本;[1.0,]代表1.0以上的版本;另外也可以用(),表示不包含边界值

解决冲突

  • 查看依赖冲突的命令: $ mvn dependency:tree -Dverbose

  • $ mvn dependency:anaylyze

  • 利用依赖仲裁机制解决冲突

    • 通过dependencyManagement指定版本

    • 通过parent指定版本

    • 在本工程内声明依赖(路径最短)

    • 强制指定版本

  • 在依赖时指定Exclusions,排除有冲突的依赖

  • 在依赖时增加Optional参数,所有依赖由最终打包的工程指定

内部仓库

  • 内部工程的二进制包可以通过deploy命令发布到内部仓库,所有内部工程统一在内部仓库中管理。

总结

这一节介绍了maven的基本使用,包括pom的基本结构、如何执行构建、如何处理依赖冲突等。

todo

  • 创建maven工程,GAV:

  • com.weibo.api:bootcamp_XXX:1.0.0-SNAPSHOT

  • bootcamp工程中包含两个java模块:bootcampapi、bootcampimpl,一个web模块:bootcamp_web

  • bootcamp项目依赖GAV:org.springframework:spring-context:4.2.0.RELEASE

  • bootcampimpl依赖bootcampapi

  • 指定bootcamp_web中spring-context版本为3.2.14.RELEASE

  • 执行一次打包

git与版本管理

为什么要有版本管理

版本控制(Version Control)的作用是追踪文件的变化。为什么需要版本控制?简单说,就是当你出错了,可以很容易地回到没出错时的状态。

git介绍

  • 分布式版本管理系统:可离线使用

  • 每个版本库的镜像都包含完整信息完整信息的概念

    • 历史

    • 分支

    • 标记

let's go!

git一直被大家认为比较难以学习,很多公司也因为git的使用成本比较高所以一直还在用历史比较悠久的svn或其它版本管理工具,微博也花了一段时间由svn过度到git。

其实,只要理解了git的基本原理,配合实践,掌握日常使用的方法其实很简单。这里采用workshop的方式帮助大家理解,大家可以一边学习一边实践。

$ git --version

try it!

# make dir for workshop

cd ~

mkdir git_workshop

cd git_workshop

基本命令

help 查看git帮助信息

git help command

try it!

$ git help config

config 设置git变量

git config [--global] key value

> --global 全局变量  

>> user.name 提交显示的用户名  

>> user.email 提交显示的邮件  

>> postBuffer 提交时的本地buffer大小  

>> core.editor git默认编辑器

try it!

#edit global config

$ git config --global user.name qindi

$ git config --global user.email qindi@staff.sina.com.cn  

$ git config --global postBuffer 50000000

$ git config --global core.editor vi

#check config value

$ git config user.name

init 创建git仓库

> --bare 只创建仓库,不创建工作目录

try it!

# create empty git repository

$ mkdir work_repo

$ cd work_repo

$ git init

$ ls -la

# create empty git bare repository

$ cd ..

$ mkdir bare_repo

$ cd bare_repo

$ git init --bare

$ ls -la

# let's back to working repo

$ cd ../work_repo

$ ls .git

status 显示git工作目录状态

try it!

#show status

$ git status

# add a file to working dir

$ echo 'hello world' >hello.txt

$ git status

本地版本控制

概述

stage是什么(1)

stage=暂存区,又称作index区使用git add命令会将文件增加到暂存区,此时文件内容被缓存,但是没有正式提交到版本库中,此时也没有建立版本号

add 添加文件到暂存区

git add [options] [--] [<pathspec>...]

> -i 交互式添加  

> -u 添加所有修改(非新增)的文件到暂存区

$ git add hello.txt

$ git status

# edit file after it is staged

$ echo 'hello2' >>hello.txt

# hello.txt is both in 'to be commit' and 'not staged'

$ git status

# add the file into staged area again 

$ git add .

如何忽略某些类型的文件:.gitignore

.settings/

.project

.classpath

bin/

commit 将暂存区提交到版本库

git commit [options]

> -a  提交所有更新过的文件(已在版本库的)    

> -m  提交注释  

> --amend  合并到上次提交

try it!

# commit the change

$ git commit -m 'add hello'

$ git status

# see the history

$ git log

# edit the file again, commit it with -m and --amend option

$ echo 'hello3' >>hello.txt

$ git add -u

$ git commit -m 'edit again' --amend

$ git log

reset 重置版本库

git reset [tree-ish] [path]

> 重置staged区中的某个文件

`git reset [mode] [commit]`

> --soft 只重置HEAD指针   

> --mixed  重置staged area(默认)  

> --hard  重置staged,branch和working目录

HEAD是什么

HEAD可以认为是指向当前分支顶部的指针,

reset做了什么(1)

reset命令指定文件路径的话,功能是把历史中版本中的某些文件恢复到暂存区,

reset做了什么(2)

如果没有指定文件路径,reset可以恢复分支指针、暂存区或工作区

try it!

$ echo 'reset' >>hello.txt

$ git add -u

$ git status

#reset file in staged area,default to HEAD

$ git reset -- hello.txt

$ git status

#reset branch,staged area and working directory

$ git reset --hard HEAD 

$ git status

# reset staged area to previous version

$ git reset HEAD^ hello.txt

$ git status

# show the content in working directory

$ cat hello.txt

# show the content in git repository

$ git show HEAD:hello.txt

# ":" will show the content in staged area

$ git show :hello.txt

checkout 从版本库签出文件(1)

git checkout [commit] <path>

checkout做了什么(1)

如果命令中指定了文件路径,则会从历史版本中取出对应的文件

checkout做了什么(2)

如果命令中没有指定文件路径,则在取出文件的同时还回修改head指针,

try it!

# reset all area to HEAD 

$ git reset --hard HEAD

# update staged area

$ echo 'checkout' >>hello.txt

$ git add -u

# update working directory

$ echo 'checkout2' >>hello.txt

$ git status

# checkout default replace working directory with staged area

$ git checkout hello.txt

$ git status

$ cat hello.txt

$ echo 'checkout2' >>hello.txt

# checkout with commit will replace both working directory and staged area

$ git checkout HEAD hello.txt

$ git status

$ cat hello.txt

rm 从版本库中删除

git rm [options] [--] [<pathspec>...]

> --cached 从staged area中删除

try it!

# add a new file to staged area

$ echo 'rm' >rm.txt

$ git add rm.txt

$ git status

# remove it from staged area

$ git rm --cached rm.txt

$ git status

# remove the file

$ rm rm.txt

# remove hello.txt in git

$ git rm hello.txt

$ git status

$ git commit

$ ls

本地仓库状态图

刚才说的都是在本地仓库进行提交和恢复的路径图,初次接触git的同学可能看的有点晕,可以对照下面的图理解一下:

分支与合并

分支概述

分支(branch)功能可以看成是一个更大的测试版本。你将整个的代码做一份拷贝,然后再起一个独立的名字,追踪其变化,与原版本脱离关系,这就是分支。以后,你还可以将分支版本再并入源版本,这就是合并(merge),如下图:

checkout 切换分支(2)

git checkout <branch>

> -b 创建并切换分支

这是checkout的第三个功能,当checkout后面跟的参数是分支名时,会进行分支切换,

try it!

# reset working directory

$ git reset --hard HEAD

# show branchs in git repository

$ git branch

# -b means create new branch

$ git checkout -b branch1

# show branchs again

$ git branch

# commit in branch1

$ echo 'branch1' >> hello.txt

$ git commit -am 'test branch1'

$ git log

# switch to master again

$ git checkout master

$ git log

merge 合并分支

git merge [options] [<branch>]

> --no-ff  不使用fast-forward模式  

> --abort 取消当前合并

merge做了什么(1)

如果当前提交是另一个分支的祖父节点,就导致fast-forward合并。指向只是简单的移动,并生成一个新的提交。

merge做了什么(2)

如果当前节点与合并节点不是祖先关系,就将当前节点、被合并的节点与他们的共同祖先进行一次三路合并,结果先保存到当前目录和索引,然后做一次新提交。 

merge时冲突了怎么办

> * 解决冲突  

> 1 修改文件,解决冲突  

> 2 把文件添加到stage区  

> 3 commit

> * 放弃合并  

> git merge --abort

try it!

# create new branch branch2, do some update

$ git checkout -b branch2

$ echo 'merge1' >>hello.txt

$ git commit -am 'edit branch2'

# switch to master, merge will in fast-forward mode

$ git checkout master

$ git merge branch2

$ git log

# drop this merge, do it again with no-ff param

$ git reset --hard HEAD^

$ git merge branch2 --no-ff

# let's make some confict

$ echo 'merge confict master' >>hello.txt

$ git commit -am 'edit master for confict'

$ git checkout branch2

$ echo 'merge confict branch2' >>hello.txt

$ git commit -am 'edit branch2 for confict'

$ git merge master

branch 管理分支

git branch [options] [<branch>]

> 无参数 显示所有本地分支  

> -d/D  删除分支/强制删除分支  

> -m/M  重命名分支/强制重命名分支  

try it!

# show all local branch

$ git branch

# rename branch2 to branch2a

$ git branch -m branch2 branch2a

# remove branch2a

$ git branch -d branch2a

tag 管理标记

git tag tagname [commit]

> 无参数 显示所有本地标记  

> -d  删除标记  

try it!

# show all local tag

$ git tag

# make a tag

$ git tag 1.0.0

$ git tag

# delete tag

$ git tag -d 1.0.0

$ git tag

版本库同步命令

git与其他版本管理工具一个比较大的区别就是

clone 克隆版本库

git clone url-to-repository

remote 管理远程仓库

git remote command <name>

> add  

> set-url  

> remove  

> rename

try it!

$ git remote 

$ git remote add origin ~/git_workshop/bare_repo

$ git remote

$ git remote show origin

push 把本地分支推送到远程

git push [options] [<repository> [<refspec>...]]

> --all 所有分支  

> --tags 推送tag  

> --prune 删除本地不存在的远程分支  

> -f 覆盖远程仓库  

> -u 建立本地与远程分支的关联 

try it!

# push local master to remote master

$ git checkout master

$ git push origin master:master 

# local branch is not tracked, push will not work

$ git push 

# push with -u will set upstream for local branch

$ git push -u origin master

$ git push

# -vv shows remote track branch

$ git branch -vv

# push local branch1 to remote branch branch2

$ git push origin branch1:branch2

$ git branch -avv

# branch -u could also set upstream 

$ git branch -u origin/branch2

# --all will push all branchs to remote repository

$ git push --all -u

$ git branch -vv

$ git branch -avv # -a shows remote branchs

$ git remote show origin

# push empty branch will delete remote branch

$ git push origin :branch2

$ git branch -avv

fetch 把远程仓库同步到本地

git fetch [options] [<repository> ]

pull 把远程仓库同步到本地,并更新本地分支

git pull [options] [<repository> [<refspec>...]]

> --rebase 使用rebase方式合并远程更新  

> --prune 删除本地镜像中的过期分支  

> -f 覆盖本地分支  

实践与tips

为什么我用git的时候XXX不了?

  1. 看错误说明!

  2. git status

  3. git help

我的本地分支提交好像有问题!

  1. git checkout -b branch_bak

  2. 随便搞

我的本地库好像被我搞乱了!

  1. cp localRepo localRepo_bak

  2. 随便搞

团队的远程库好像被我搞乱了!

  1. git clone //path_to_repo repo_bak

  2. 与所有团队成员同步状况,解决问题之前不要pull或push

  3. 临时分支异常:建立新分支,利用merge、rebase或cherry-pick更新分支,删除异常分支

  4. 永久分支异常:联系git工程管理员或gitlab管理员修复问题,之后做深刻的自我反省

posted @ 2017-09-18 16:37  jimcsharp  阅读(260)  评论(0编辑  收藏  举报