知之 | sailorivy 2016-08-17T14:30:53+08:00 ivy5028@gmail.com 港澳台身份证的正则表达式 2016-08-17T00:00:00+08:00 sailorivy http://sailorivy.github.io/2016/08/RegExp-idNumber 港澳台身份证的正则表达式

香港

说明:一个英文+6个数字+(一个校验码,0~9或A)

正则表达式:[A-Z]{1,2}[0-9]{6}([0-9A])

参考:Wikipedia

澳门

说明:第一位1、5、7,后面6个数字,最后带括号的一位校验码0~9

正则表达式:[157][0-9]{6}([0-9])

参考:Wikipedia

台湾

说明:1个英文+9个数字

正则表达式:[A-Z][0-9]{9}

参考:Wikipedia

Groovy片段示例

def matchHK = {
    def matcher = it =~ /^[A-Z]{1,2}[0-9]{6}\([0-9A]\)/
}
def matchMO = {
    def matcher = it =~ /^[157][0-9]{6}\([0-9]\)/
}
def matchTW = {
    def matcher = it =~ /^[A-Z][0-9]{9}/
}

def id = context.getIdNumber()
if (!id) return false
if (id?.trim()?.isEmpty()) return false
return matchHK(id.toUpperCase()).matches() || matchMO(id.toUpperCase()).matches() || matchTW(id.toUpperCase()).matches()
]]>
WebLogic的SSL主机名验证 2015-10-08T00:00:00+08:00 sailorivy http://sailorivy.github.io/2015/10/hostname-verifier-in-weblogic WebLogic中SSL主机名验证

WebLogic提供了一个高级功能——SSL主机名验证,WebLogic上运行的应用作为客户端向第三方服务发起HTTPS请求时,WebLogic会验证所请求的第三方服务URL里的主机名是否是WebLogic可信任的(也就是验证第三方服务URL里的主机名是否和可信任证书里配置的主机名相匹配),如果不匹配,WebLogic就会断开应用和第三方服务之间的SSL连接。

这个功能默认是开启的,只需要将第三方服务的证书导入WebLogic可信任证书里就可以了。WebLogic的可信任证书缺省是演示信任密钥库和Java标准的信任密钥库,最方便的就是导入Java标准的信任秘钥库(可以在管理控制台的“配置-秘钥库-信任-Java标准信任密钥库”查看Java标准信任密钥库的具体位置),命令示例如下:

  1. 导入

    keytool -importcert -noprompt -keystore "Java标准信任密钥库的位置" -storepass changeit -alias alias -file 第三方服务证书的存放位置

  2. 导入后查看、确认

    keytool -list -keystore "Java标准信任密钥库的位置" -storepass changeit

主机名验证器

缺省主机名验证器

缺省情况下,WebLogic使用最严格的主机名验证器(12c的管理控制台上是“BEA主机名验证器”),它会精确匹配主机名,只要不一样就会报错并断开SSL连接,当然localhost、127.0.0.1和本机IP不会验证。

下面是验证失败时报的错:

<2015-9-18 下午02时02分48秒 CST> <Warning> <Security> <BEA-090504> <Certificate chain received from api.xxxx.cn - 60.12.226.18 failed hostname verification check. Certificate contained portal.xxxx.cn but check expected api.xxxx.cn>
<2015-9-18 下午02时02分48秒 CST> <Error> <HTTP> <BEA-101019> <[ServletContext@1257418214[app:apitest module:apitest.war path:null spec-version:3.0]] Servlet failed with an IOException.
    javax.net.ssl.SSLKeyException: Hostname verification failed: HostnameVerifier=weblogic.security.utils.SSLWLSHostnameVerifier, hostname= api.xxxx.cn.

可以看出WebLogic缺省的主机名验证器是weblogic.security.utils.SSLWLSHostnameVerifier。第三方服务URL里的主机名和可信任证书里的主机名都必须是api.xxxx.cn。

通配符主机名验证器

有些第三方服务提供的证书并不会精确指定主机名,提供服务比较多的时候,通常会用通配符,比如*.xxxx.cn。

将第三方服务提供的证书导入WebLogic的信任秘钥库之后,如果仍然使用WebLogic缺省的主机名验证器就会失败:

<2015-9-18 下午02时02分48秒 CST> <Warning> <Security> <BEA-090504> <Certificate chain received from api.xxxx.cn - 60.12.226.18 failed hostname verification check. Certificate contained `*.xxxx.cn` but check expected `api.xxxx.cn`>
<2015-9-18 下午02时02分48秒 CST> <Error> <HTTP> <BEA-101019> <[ServletContext@1257418214[app:apitest module:apitest.war path:null spec-version:3.0]] Servlet failed with an IOException.
    javax.net.ssl.SSLKeyException: Hostname verification failed: HostnameVerifier=weblogic.security.utils.SSLWLSHostnameVerifier, hostname=api.xxxx.cn.

除了缺省的主机名验证器,WebLogic还提供了一个通配符主机名验证器,它支持满足下面要求的主机名:

  1. 至少包含两个点.
  2. 以星号*开头,但不包含其他星号

支持通配符的主机名验证器是weblogic.security.utils.SSLWLSWildcardHostnameVerifier。如果使用缺省主机名验证器时报如下的错误,那就可以将管理控制台的“配置-SSL-高级-主机名验证”改成“定制主机名验证器”,同时将“定制主机名验证器”设置为weblogic.security.utils.SSLWLSWildcardHostnameVerifier

将主机名验证器换成SSLWLSWildcardHostnameVerifier之后,前面的错误就没有了。

定制主机名验证器

如果缺省的和通配符的主机名验证器都不能满足使用要求,可以自定义主机名验证器。WebLogic提供了weblogic.security.SSL.HostnameVerifier接口,建立SSL连接的时候会回调HostnameVerifier接口的实现来验证主机名,进而确定是否允许建立连接。

要做的事情很简单,就是实现weblogic.security.SSL.HostnameVerifier接口。注意:定制主机名验证器要提供public的无参构造函数。

相当于关闭主机名验证功能的定制验证器示例如下:

public class NulledHostnameVerifier implements
                 weblogic.security.SSL.HostnameVerifier {
  public boolean verify(String urlHostname, javax.net.ssl.SSLSession session) {
    return true;
  }
}

然后,将实现类加到WebLogic的ClassPath中,将管理控制台的“配置-SSL-高级-主机名验证”改成“定制主机名验证器”,同时将“定制主机名验证器”设置为自定义的主机名验证器全限定名称就可以了。

关闭主机名验证器

出现主机名验证失败的错误后,最粗放的解决办法就是关闭WebLogic的主机名验证功能(将管理控制台的“配置-SSL-高级-主机名验证”改成“无”)。

但这种方式可能会有安全隐患,所以并不推荐。如果缺省主机名验证器太严格、不能满足实际使用要求,还是根据实际情况选择WebLogic提供的通配符主机名验证器或自己定制的主机名验证器。

]]>
Maven Surefire Plugin的基本使用 2015-09-25T00:00:00+08:00 sailorivy http://sailorivy.github.io/2015/09/maven-surefire-plugin Maven Surefire Plugin

Surefire是个测试框架。Maven提供了Surefire插件,可以在应用构建生命周期的test阶段执行单元测试。

Surefire插件缺省会在${basedir}/target/surefire-reports目录下生成txt格式和xml格式的结果报告。

基本用法

要使用Surefire插件,只需要在pom.xml中定义如下内容就可以了:

<project>
    [...]
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.18.1</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
    [...]
</project>

然后运行下面的命令调用Surefire插件,就会运行应用中定义的单元测试了:

mvn test

测试Provider

如果项目不作要求,大家编写单元测试的时候通常会选择自己常用的单元测试框架,常见的有:

  • TestNG
  • JUnit 3
  • JUnit 4

那使用缺省的Surefire插件配置,能把上面几种单元测试都运行起来么?答案是否定的。

使用TestNG

首先在pom.xml中添加对TestNG的依赖:

<dependencies>
  [...]
    <dependency>
      <groupId>org.testng</groupId>
      <artifactId>testng</artifactId>
      <version>6.8.8</version>
      <scope>test</scope>
    </dependency>
  [...]
</dependencies>

TestNG缺省只运行src/test/java下以Test结尾的单元测试。如果类名有其他命名方式,需要用includes参数指定。

使用JUnit

和TestNG一样,首先要在pom.xml中添加对JUnit的依赖:

<dependencies>
  [...]
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  [...]
</dependencies>

使用JUnit的时候,最好显式指定使用的Provider。下面示例是使用junit4:

<plugins>
[...]
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.18.1</version>
    <dependencies>
      <dependency>
        <groupId>org.apache.maven.surefire</groupId>
        <artifactId>surefire-junit4</artifactId>
        <version>2.18.1</version>
      </dependency>
    </dependencies>
  </plugin>
[...]
</plugins>

不指定的话,Surefire会按照下面的算法选择JUnit Provider版本:

  1. 如果JUnit的版本大于等于4.7,并且配置了parallel属性,就使用junit47 provider
  2. 如果JUnit的版本大于等于4.0,使用junit4 provider
  3. 上述条件都不满足的话,使用junit3.8.1 provider

上面是Surefire文档里讲的,我自己测试的时候虽然指定了JUnit 4.11,但运行的时候仍然不会运行JUnit 4的测试用例,使用的还是junit3.8.1 provider。后来还是显式指定了一下JUnit Provider,所有的JUnit单元测试才运行起来。

测试用例的包含和排除

包含

Surefire插件的文档说会自动运行和下面模式匹配的测试类:

  • Test*.java
  • *Test.java
  • *TestCase.java

没有一一测试,至少TestNG的测试类如果不是以Test结尾,Surefire插件是不会运行的。

如果测试类在指定Provider之后仍然不运行,可以使用includes包含进来。include既支持精确匹配,也支持正则表达式:

<project>
  [...]
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.18.1</version>
        <configuration>
          <includes>
            <include>Sample.java</include>
            <!-- %regex[正则表达式] -->
           <include>%regex[.*[Cat|Dog].*Test.*]</include>
          </includes>
        </configuration>
      </plugin>
    </plugins>
  </build>
  [...]
</project>

排除

不运行的测试用例,可以使用excludes来排除:

<project>
  [...]
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.18.1</version>
        <configuration>
          <excludes>
            <exclude>**/TestCircle.java</exclude>
            <exclude>**/TestSquare.java</exclude>
          </excludes>
        </configuration>
      </plugin>
    </plugins>
  </build>
  [...]
</project>

配置classpath

Surefire插件编译、运行测试用例时,classpath依次是:

  1. test-classes目录
  2. classes目录
  3. 项目依赖
  4. 补充的classpath

在不同环境下,classpath的设置可能不一样,编译、运行测试用例就会有不同的结果。比如项目A的测试用例需要使用项目B的类和资源,在IDE里项目A可以直接依赖项目B,运行项目A的测试用例是没有问题的,但在命令行下使用Surefire插件运行项目A的测试用例时,如果pom.xml里没有依赖项目B,编译、运行就会失败。这种情况下,可以配置classpath来确保测试用例的顺利执行:

<project>
  [...]
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.18.1</version>
        <configuration>
          <additionalClasspathElements>
            <additionalClasspathElement>path/to/additional/resources</additionalClasspathElement>
            <additionalClasspathElement>path/to/additional/jar</additionalClasspathElement>
          </additionalClasspathElements>
        </configuration>
      </plugin>
    </plugins>
  </build>
  [...]
</project>
]]>
Cassandra起步 2015-07-02T00:00:00+08:00 sailorivy http://sailorivy.github.io/2015/07/how-to-build-cassandra Cassandra

Cassandra是一套高可扩展、最终一致、分布式的结构化键值存储系统。

Cassandra结合了Dynamo的分布技术和Google的BigTable数据模型,具有Dynamo的最终一致性,并提供了与Google的Bigtable相似的、基于ColumnFamily的数据模型。

编译

工具

Cassandra的源码使用Git管理,使用Ant进行编译。下面是v2.2编译使用工具的版本要求:

  • Git:1.8.0_45
  • JDK:1.9.4
  • Ant:2.3.5

编译

  1. 获取源码

     git clone git://git.apache.org/cassandra.git cassandra
     cd cassandra
    

    执行上面的命令获取到的是Cassandra的trunk,trunk比较活跃,每天都有更新,不太利于学习和源码分析。不过要是已经对Cassandra比较熟悉了,可以跟进trunk:

     git pull
    

    Cassandra目前最新的正式版本是v2.1.7,也推出了v2.2.0的RC1版本。后面选择v2.1.x进行学习和分析,所以检出v2.1.x对应的分支:

     git checkout cassandra-2.1
    
  2. 调用Ant进行编译

    ant
    
  3. 调用Ant编译cassandra-stress工具

     ant stress-build        
    

快速开始

配置

Cassandra的配置文件位于conf目录下。主要的配置文件有:

  • cassandra.yaml——存储配置。里面会设置集群名称、失败处理策略、监听地址、传输端口等信息,以及Cassandra使用的目录,包括数据文件、提交日志、缓存的存放目录。这些目录默认在Cassandra的data目录下,如果要自己设置,需要确保设置的目录存在并有写权限。
  • logback.xml——日志的相关配置。
  • cassandra-env.sh——可以配置JVM的设置。

运行节点

高可扩展的集群也是由多个单节点组成的,先看看单节点的操作。

启动

按照手册,执行下面的命令就可以在前台启动Cassandra:

./bin/cassandra -f

bin/cassandra默认会读取bin/cassandra.in.sh和conf/cassandra-env.sh中的内容。

Mac下的问题

20150613 pull下来的代码编译后,在Mac下运行上面的命令会有下面的错误:

-bash: ./bin/cassandra: /bin/sh^M: bad interpreter: No such file or directory

这是因为bin/cassandra的换行符是Dos格式的,在Mac下无法执行。所以先修改换行符:

vi bin/cassandra
:set ff?
(结果为fileformat=dos)
:set ff=unix
:wq

再次启动会遇到下面的错误:

: command not foundsh: line 16: 
'/bin/cassandra.in.sh: line 43: syntax error near unexpected token `do
'/bin/cassandra.in.sh: line 43: `for jar in "$CASSANDRA_HOME"/lib/*.jar; do
You must set the CASSANDRA_CONF and CLASSPATH vars

这是因为bin/cassandra默认会调用bin/cassandra.in.sh,bin/cassandra.in.sh的换行符也是Dos格式的,在Mac下执行会出错。同样,采用上面的步骤修改换行符。


再次启动,标准输出一开始会有下面的内容:

: command not foundndra-env.sh: line 16: 
'/bin/../conf/cassandra-env.sh: line 17: syntax error near unexpected token `
'/bin/../conf/cassandra-env.sh: line 17: `calculate_heap_sizes()

conf/cassandra-env.sh里设置了JVM的配置,bin/cassandra会调用conf/cassandra-env.sh。而conf/cassandra-env.sh的换行符也是Dos格式的,同样,采用上面的步骤修改换行符。


继续启动,标准输出里还是有WARN和ERROR:

WARN  13:02:48 JNA link failure, one or more native method will be unavailable.
WARN  13:02:48 JMX is not enabled to receive remote connections. Please see cassandra-env.sh for more info.
ERROR 13:02:48 Error starting local jmx server: 
java.io.IOException: Cannot bind to URL [rmi://localhost:7199/jmxrmi]:  javax.naming.ServiceUnavailableException [Root exception is     java.rmi.ConnectException: Connection refused to host: localhost; nested exception is: 
    java.net.ConnectException: Connection refused]
    ......
Caused by: javax.naming.ServiceUnavailableException: null
    ......
Caused by: java.rmi.ConnectException: Connection refused to host: localhost; nested exception is: 
    java.net.ConnectException: Connection refused
    ......
Caused by: java.net.ConnectException: Connection refused
    ......

JNA的警告暂时没有解决。

至于JMX,我们对conf/cassandra-env.sh进行如下修改:

1. 注释掉LOCAL_JMX=yes。Cassandra默认只能从localhost访问JMX,要允许远程连接,就注释掉LOCAL_JMX=yes。
2. 如果允许远程连接,Cassandra默认不启用ssl、但启用认证。我们不进行安全处理,所以:
    * 将JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=true"改成JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
    * 注释JVM_OPTS="$JVM_OPTS -Dcom.sun.management.jmxremote.password.file=/etc/cassandra/jmxremote.password"

继续启动,标准输出里还是有ERROR:

ERROR 02:44:32 Exception encountered during startup
java.lang.RuntimeException: Unable to gossip with any seeds
    ......
java.lang.RuntimeException: Unable to gossip with any seeds
    ......
Exception encountered during startup: Unable to gossip with any seeds

这个错误是因为节点监听的地址没有纳入集群,节点监听地址用listen_address配置,而集群中的节点要互相发现,就要把节点的地址配置到seeds中。cassandra.yaml中的相关配置如下:

listen_address: localhost
......
seed_provider:
    - class_name: org.apache.cassandra.locator.SimpleSeedProvider
      parameters:
         - seeds: "127.0.0.1"

将 localhost 和 127.0.0.1 都改成IP地址 

停止

Cassandra手册上说如果指定-f选项启动的话,按"Control-C"就可以停止节点,但v2.1并不支持这种方式。

在bin目录下有一个stop-server脚本,修改换行符后执行,它会让我们阅读脚本内容,实际上启动不指定-p选项的话,Cassandra节点的停止就是用kill -9命令去杀进程。

cqlsh的使用

Cassandra提供了查询语言CQL(Cassandra Query Language),使用CQL可以定义Schema、插入数据、执行查询。

bin/cqlsh提供了交互式执行方式,我们可以运行cqlsh脚本来执行CQL。Mac上先修改bin/cqlsh的换行符,并将里面DEFAULT_HOST的值改成节点所在机器的IP地址。

bin/cqlsh

连接成功的话会有下面的提示:

Connected to Test Cluster at 192.168.6.166:9042.
[cqlsh 5.0.1 | Cassandra 2.1.7-SNAPSHOT | CQL spec 3.2.0 | Native protocol v3]
Use HELP for help.
cqlsh> 

可以参照Cassandra官方Getting Started里的CQL示例进行测试。

]]>
在Mac上使用tree命令 2015-05-28T00:00:00+08:00 sailorivy http://sailorivy.github.io/2015/05/use-tree-on-mac 在终端上显示一个目录的结构可以使用tree命令。在Ubuntu上安装tree非常方便:

sudo apt-get install tree

然后就可以在终端里查看一个目录的结构:

.
└── org
    └── dmg
        └── pmml
            ├── pmml_4_1
            │   ├── bindings.xjb
            │   ├── bindings.xml
            │   └── pmml-4-1.xsd
            └── pmml_4_2
                ├── bindings.xjb
                ├── bindings.xml
                └── pmml-4-2.xsd

5 directories, 6 files

那要在Mac下使用tree该怎么做呢?

最实用的方法就是编译、安装tree源码的

  1. 下载源码:curl -O ftp://mama.indstate.edu/linux/tree/tree-1.7.0.tgz
  2. 解压源码:tar xzvf tree-1.7.0.tgz
  3. 进入tree-1.7.0目录:cd tree-1.7.0
  4. 修改Makefile文件:vi Makefile

tree源码的默认编译环境是Linux,在Mac里面要注释掉Linux的编译选项、启用Mac的编译选项

# Linux defaults:
#CFLAGS=-ggdb -Wall -DLINUX -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
#CFLAGS=-O4 -Wall  -DLINUX -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
#LDFLAGS=-s

# Uncomment for OS X:
CC=cc
CFLAGS=-O2 -Wall -fomit-frame-pointer -no-cpp-precomp
LDFLAGS=
MANDIR=/usr/share/man/man1
OBJS+=strverscmp.o

接下来make,然后[sudo] make install就可以了。

]]>
Git常用命令 2015-05-04T00:00:00+08:00 sailorivy http://sailorivy.github.io/2015/05/git-common-commands Git的环境变量

Git的环境变量可以在三个地方设置:

  • /etc/gitconfig文件:对所有用户适用,使用git config命令时指定‘–system’选项。
  • ~/.gitconfig文件:只适用于当前用户,使用git config命令时指定‘–global’选项。
  • 当前项目目录中的.git/config文件:仅对当前项目有效,不用指定任何选项。

每个级别的配置都会覆盖上层的相同配置,.git/config里的配置会覆盖/etc/gitconfig中的同名变量。

用户信息

配置个人的用户名称和电子邮件。Git在每次提交时都会引用这两条信息,说明是谁提交了,这两条配置会随更新内容一起被纳入历史记录。

$ git config [--global] user.name <user_name>
$ git config [--global] user.email <user_email>

查看配置信息

查看已有的配置信息

$ git config --list

查看某个环境变量的设置,直接指定该环境变量的名称就可以:

$ git config user.name

获取帮助

$ git help <verb>
$ git <verb> --help
$ man git-<verb>

常用命令

本地操作

克隆现有仓库

$ git clone <url>

查看当前文件的状态

$ git status

跟踪新文件/暂存已修改的文件

$ git add <file>

查看未暂存的改动

$ git diff

查看已暂存的改动

$ git diff --cached

删除文件

$ git rm <file_path>

移动/重命名文件

    Git的元数据并不跟踪移动/重命名操作,但它能推断出是移动/重命名操作。

$ git mv <file_from> <file_to>
或者
$ mv <file_from> <file_to>
$ git rm <file_from>
$ git add <file_to>

提交更新(已暂存的改动)

$ git commit -m '<commit_log>'

提交已经跟踪过的文件的更新(跳过git add步骤,一步就暂存并提交)

$ git commit -a -m '<commit_log>'

查看提交历史

$ git log

    使用-p选项可以显示每次提交的内容差异。

    另外还有--pretty选项,可以指定不同于默认格式的方式展示提交历史。

    在--pretty选项指定为oneline或format的时候,结合--graph选项可以看到开头会多出一些ASCII字符串表示的简单图形,展示每个提交所在的分支及其分化衍合情况。

    还可以指定--since和--until设置时间范围,用--author选项指定作者(只显示该作者的提交)

    如果只关心某些文件或目录的历史提交,可以在git log选项的最后指定路径(path)

撤销commit

$ git reset --hard <commit_id>

取消已经暂存的文件

$ git reset HEAD <file>

取消对文件的修改

$ git checkout -- <file>

打标签

// 给HEAD加标签
$ git tag -a <tag_name> -m '<message>'
// 后期对早先的某次提交加标签
$ git tag -a <tag_name> <commit_checksum>

查看标签

// 列出已有的tag
$ git tag
// 显示指定tag的版本信息和提交对象
$ git show <tag_name>

分享标签

$ git push origin <tag_name>
// 一次推送所有本地新增的标签
$ git push origin --tags

分支操作

新建并切换分支

$ git branch <branch_name>
$ git checkout <branch_name>
或者
$ git checkout -b <branch_name>

    在切换分支之前,需要保持一个清洁的工作区域(暂存区和工作目录),那些还没有提交的修改会和即将检出的分支产生冲突从而阻止Git为你切换分支。但现实工作中,工作区域不可能一直保持清洁,解决办法见后面的“冲突处理”。

推送本地新建分支到远程仓库

$ git push --set-upstream <remote_name> <branch_name>

推送数据到远程仓库

$ git push <remote_name> <branch_name>

把本地分支推送到某个命名不同的远程分支

$ git push <remote_name> <branch_name>:<remote_branch_name>

合并分支

$ git checkout <target_branch_name>
$ git merge <source_branch_name>

冲突处理

  1. 如果在合并时或git pull时发生冲突,可以用git status查阅哪些文件出现了冲突。
  2. 接着手工定位并解决这些冲突(Git会在有冲突的文件里加入标准的冲突解决标记)。 也可以运行git mergetool,调用一个可视化的合并工具来引导你解决所有冲突。
  3. 解决了所有文件里的所有冲突后,运行git add将把它们标记为已解决状态(暂存就表示冲突已经解决)。
  4. 再运行一次git status,确认所有冲突都已解决。
  5. 用git commit完成合并提交。

删除分支

$ git branch -d <branch_name>

列出当前所有的分支,并显示当前所在的分支

$ git branch

查看各个分支最后一个提交对象的信息

$ git branch -v

查看哪些分支已被并入当前分支(一般来说,列表中没有*的分支通常都可以用git branch -d删掉)

$ git branch --merged

查看尚未合并的分支

$ git branch --no-merged

    对于尚未合并的分支,删除的时候(git branch -d )会提示错误,确定改动没用的话可以强制删除(git branch -D )。

储藏

    当你正在进行某一部分工作,里面的东西比较杂乱,这时候需要转到其他分支上进行一些工作,但又不能提交进行了一半的工作。这种情况怎么办?

$ git stash

    “储藏”可以获取工作目录的中间状态(也就是修改过的被追踪的文件和暂存的变更),并将它保存到一个未完结变更的堆栈中,以便以后重新应用。

查看现有的储藏

$ git stash list

重新应用储藏

$ git stash apply <stash_name>
# 不指定stash_name的话,会重新应用最新的储藏
# 这个命令只能重新应用文件的变更,没有重新暂存已被暂存的文件

重新应用被暂存的变更

$ git stash apply --index

从堆栈中移除储藏

    stash apply只尝试应用储藏的工作,储藏的内容仍然在栈上。

$ git stash drop <stash_name>

重新应用储藏并从堆栈中移除储藏

$ git stash pop

忽略某些文件

有些文件不需要纳入Git的管理,比如日志或临时文件等自动生成的内容。大家应该不希望这些文件在每次git status的时候都出现在未跟踪文件列表里,也不希望它们被纳入配置管理。可以创建一个名为.gitignore的文件,列出要忽略的文件模式。

.gitignore的格式规范如下:

  • 空行或者以注释符号#开头的行会被Git忽略。
  • 可以使用标准的glob模式匹配。 glob模式是指Shell使用的简化了的正则表达式。 星号(*)匹配零个或多个任意字符;[abc]匹配任何一个列在方括号中的字符;问号(?)匹配一个任意字符;如果在方括号中使用短横线分隔两个字符,表示这两个字符范围内的都可以匹配。
  • 匹配模式最后跟斜杠(/)说明忽略的是目录。
  • 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。

举例来说:

$ cat .gitignore
# 注释,被Git忽略
# 忽略所有.log结尾的文件
*.log
# 但oom.log除外
!oom.log
# 忽略项目根目录下的test文件,不包括api/test
/test
# 忽略target目录下的所有文件
target/
# 忽略doc目录下的doc文件,但不包括doc/manual/*.doc
doc/*.doc
# 忽略doc目录中的所有txt文件
doc/**/*.txt

初始化新仓库

对现有的某个项目开始用Git管理,只需到此项目所在的目录执行:

$ git init
]]>
用Ant强杀Java进程 2012-11-14T00:00:00+08:00 sailorivy http://sailorivy.github.io/2012/11/ant-kill-process 强杀进程的方式有很多。如果应用程序需要在多个平台下运行,我们可以为不同的平台编写不同的脚本,然后在整体构建/运行的脚本里去分别调用,但这并不太利于维护。我们可以借助Ant、采用统一的方式去完成这件事情。

以强杀Java进程为例,主要思路: 1、使用Java自带的jps命令得到所有Java进程的信息 2、获得符合要求的Java进程的PID 3、调用强杀进程的命令杀死进程

Ant脚本片段:

<property environment="env"/>

<target name="kill-process">  
    <!-- 执行Java自带的jps命令,将所有Java进程的信息(包括PID)写入pid.out文件 -->  
    <exec executable="${env.JAVA_HOME}/bin/jps" output="pid.out">  
        <!-- 用jps命令的参数v,可以获取Java进程的变量信息。  
             如果多个Java进程需要通过变量信息区分,这个参数很有用-->  
        <arg value="-v"/>  
    </exec>  

    <!-- 加载pid.out文件,用filterchain定义条件、得到符合条件的PID -->  
    <loadfile srcfile="pid.out" property="pid">  
        <filterchain>  
            <linecontains>  
                <contains value="Bootstrap"/>  
            </linecontains>  
            <tokenfilter>  
                <replaceregex pattern="^(\d+) Bootstrap (.*)" replace="\1"/>  
                <trim/>  
                <ignoreblank/>  
            </tokenfilter>  
            <striplinebreaks/>  
        </filterchain>  
    </loadfile>  

    <condition property="haveValue">  
        <isset property="pid"/>  
    </condition>  

    <antcall target="pidFound"/>  
    <antcall target="pidNotFound"/>  

    <delete file="pid.out"/>  
</target>

<target name="pidFound" if="haveValue">  
    <echo>Killing process with PID: ${pid}</echo>  
    <!-- 执行强杀进程的命令,这里以Windows自带的tskill为例 -->  
    <exec executable="tskill">  
        <arg value="${pid}"/>  
    </exec>
</target>

<target name="pidNotFound" unless="haveValue">  
    <echo>There is no matched process.</echo>
</target>
]]>