梦里键指如飞

规格严格,功夫到家


  • Home

  • Archives

Java线程

Posted on 2018-11-17

线程状态及转换

java线程状态图

Java线程相关的方法

方法 定义所在类/接口 作用 说明
run java.lang.Runnable 启动线程,之后线程状态变为可运行,等待CPU调度 抽象方法,实现类实现,线程运行的代码块
start java.lang.Thread 同run方法 调用 new Thread( target:RunnableImpl)指定的target的run方法
sleep java.lang.Thread 休眠指定时间(millis), 出让CPU使用权 不会释放锁资源(monitor)
join java.lang.Thread 等待(如指定时间,则最多等待这么多时间)指定线程退出 内部调用 java.lang.Object.wait()方法
yield java.lang.Thread 与sleep类似,只在不低于该线程优先级的线程才可执行 不可指定时间
wait java.lang.Object 使当前线程休眠一段时间直到其他线程调用notify/notifyAll 必须在synchronized块中使用,之后进程状态为等待或计时等待
notify java.lang.Object 唤起等待队列中(等待或计时等待)线程以获取当前锁对象(monitor)
notifyAll java.lang.Object 唤起所有等待队列中的线程 后续具体哪个被唤起的线程可执行,取决于CPU调度

springboot应用启动过程分析(基于springboot 1.5.4)

Posted on 2018-11-08

示例

springboot程序通过SpringBootApplication注解和Runner类中入口方法main执行SpringApplication.run()就可以执行起来,如下:

1
2
3
4
5
6
7
@SpringBootApplication
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

内部代码分析

通过DemoApplication main方法进入之后,过掉各种中间多态或抽象的过程,主要包括两个方法: initializer和run

在启动过程中的各种Spring context和bean的配置,主要在spring-boot的 META-INF/spring.factories文件中

META-INF中这个文件也是开发springboot插件的一个方式

initializer方法

1
2
3
4
5
6
7
8
9
10
11
@SuppressWarnings({ "unchecked", "rawtypes" })
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}

主要包含如下几个过程:

  1. 判断是否为web环境
  2. 设置初始化类(initializers, springboot 封装的 spring-context中的ApplicationContext列表)
  3. 设置监听器(listeners, spring封装的spring-context中的ApplicationListener列表)

webEnvironment的过程

判断是否为web环境,主要是看有没有加载javax.servlet.Servlet 和 org.springframework.web.context.ConfigurableWebApplicationContext相关的类
另外,在DemoApplication的main方法中手动设置webEnvironment也会直接生效,如下:

1
2
3
4
5
public static void main(String[] args) {
SpringApplication application = new SpringApplication(DemoApplication.class);
application.setWebEnvironment(false);
application.run(args);
}

设置初始化类

设置初始化类是通过SpringApplication中的方法getSpringFactoriesInstances(),参数为 ApplicationContextInitializer.class

1
2
3
4
5
6
7
8
9
10
11
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}

SpringFactoriesLoader.loadFactoryNames方法,获取了spring-boot包下的META-INF/spring.factories中的ApplicationListeners,主要包括:

1
2
3
4
5
6
7
8
9
org.springframework.boot.ClearCachesApplicationListener
org.springframework.boot.builder.ParentContextCloserApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
org.springframework.boot.context.config.ConfigFileApplicationListener
org.springframework.boot.context.config.DelegatingApplicationListener
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
org.springframework.boot.logging.ClasspathLoggingApplicationListener
org.springframework.boot.logging.LoggingApplicationListener

//TODO

run方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}

======== 未完待续 =========

Java并发编程概要

Posted on 2018-11-06

Java并发编程主要用到java.util.concurrent包下的类,主要结构如下:

1
2
3
4
java.util.concurrent
|----atomic
|----locks
|----各种类

如果再深入,还需要了解sun.misc.Unsafe、CAS、内存可见性、JMM重排序等。

Java并发包概述

java.util.concurrent.atomic

主要为线程安全的原子性类,Atomic开头,如AtomicInteger

java.util.concurrent.locks

锁,最主要的是AbstractQueuedSynchronizer这个抽象类,另外是ReentrantLock、ReentrantReadWriteLock等用于实现锁的类

java.util.concurrent.*

多线程的工具类,可以分为以下几类:

1、如 ConcurrentHashMap、ArrayBlockingQueue、ConcurrentLinkedQueue等;
2、线程池相关,如ThreadPoolExecutor;
3、多线程协作的并发类,如FutureTask、CountDownLatch、CyclicBarrier等

Java并发包类层次关系

1
TODO 待续

Java加解密技术

Posted on 2018-09-08

说在前面

Java加解密技术是在Java中对密码学的一种实现,但密码学本身是有很多方面的内容。

什么是加解密技术

以下是维基上密码学的定义:

Cryptography or cryptology is the practice and study of techniques for secure communication in the presence of third parties called adversaries. More generally, cryptography is about constructing and analyzing protocols that prevent third parties or the public from reading private messages; various aspects in information security such as data confidentiality, data integrity, authentication, and non-repudiation are central to modern cryptography. Modern cryptography exists at the intersection of the disciplines of mathematics, computer science, electrical engineering, communication science, and physics. Applications of cryptography include electronic commerce, chip-based payment cards, digital currencies, computer passwords, and military communications.

密码学是针对信息不被第三方获得的安全传输实践和研究。通常,密码学是关于构造和分析协议,以防止第三方或公众读取私有消息;在信息安全的各个方面,如数据机密性、数据完整性、身份验证和不可否认性,是现代密码学的核心。现代密码学存在于数学、计算机科学、电子工程、通信科学。。。

以上讲了三点:

信息
传输
安全

简单一句话:密码学就是安全地把信息传给对方(不相关的第三方无法获取你传出去的真实内容)

密码学有一套丰富的参考模型,里面包含了八大安全机制:

  1. 加密机制
  2. 数字签名机制
  3. 访问控制机制
  4. 数据完整性机制
  5. 认证机制
  6. 业务流填充机身
  7. 路由控制机制
  8. 公证机制

这里面只讨论加密钥相关的内容(你加密完,我收到后解密成原来的内容),针对密码学中的其他内容,后续文章再做讨论。

加解密的分类

按密码体制

这是一般常说的一种分法,主要是对称密码体制和非对称密码体制

  1. 对称:加密和解密所用的密钥相同
  2. 非对称:加密和密钥所用的不同,密钥分别叫做公钥、私钥。公钥向可以公开,私钥是保密的。

按明文的处理方法

主要分为分组密码和流密码

  1. 分组密码:加密的时候把明文分成固定长度的几块,用同一个密钥和算法,将不同的分组块用这同一个密钥和算法进行加密处理。
  2. 流密码:加密的时候按位或字节加密明文。

Java对密码学的支持

主要三方面: 1. java API,2. JavaEE容器, 3. Java工具

Java API

Java中有很多接口和实现类上的支持,如

  1. MessageDigest类,做信息的一个摘要,一般有MD5和SHA
  2. Mac和Cipher两个类, Mac类,构建HMAC加密算法,Cipher可以构建DES、AES、RSA等加密算法
  3. Signature类,用于做数字签名和验证
  4. Certificate类,主要操作证书。

JavaEE容器

比如Tomcat,只需要简单做一些基本的配置,就可以实现HTTPS的应用。

Java工具

keytool命令(跟javac等一起在JDK中)可以实现密钥、证书的管理,如生成、导出等。

Java中几种常见加解密的实现

一些说明

理论上,密钥的长度是范围比较广的,但由于美国出口的限制(JCE),一些长度JDK中默认不支持的,如果需要,可以通过替换JRE中JCE(local_policy.jar, US_export_policy.jar 两个文件, 可在Oracle官网下载) 来支持其他长度。
当然,本地JDK/JRE中的java.security文件中最好也关注一下。

算法 理论长度 实际支持长度 说明
DES 值域:{56, 128} 56 JCE限制
AES 值域:{128, 192, 256} 128 JCE限制
RSA 区间: [512, 16384]

密钥的生成

主要包括对称加,非对称和椭圆签名算法。
以下用到的两个第三方类为:
org.apache.commons.codec.binary.Base64
org.bouncycastle.jce.provider.BouncyCastleProvider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

/**
* 生成对称加密密钥
* algorithm支持 DES, AES两个
*/
public static String symmetricKeyGenerator(String algorithm, int keySize)
throws Exception {

Provider provider = new BouncyCastleProvider();
KeyGenerator generator = KeyGenerator.getInstance(algorithm);
generator.init(keySize);
SecretKey secretKey = generator.generateKey();
return Base64.encodeBase64String(secretKey.getEncoded());
}
/**
* 生成非对称加密密钥
* algorithm支持 RSA
*/
public static Map<String,String> asymmetricKeyPairGenerator(String algorithm, int keySize)
throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
keyPairGenerator.initialize(keySize);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
Map<String, String> keys = new HashMap();
keys.put("privateKey", Base64.encodeBase64String(keyPair.getPrivate().getEncoded());
keys.put("publicKey", Base64.encodeBase64String(keyPair.getPublic().getEncoded());
return keys;
}



/**
* 生成椭圆验签密钥
* algorithm支持 ECDSA
*/
public static Map<String,String> ecdsaKeyPairGenerator(String algorithm, int keySize)
throws Exception {
Provider provider = new BouncyCastleProvider();
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm, provider);
keyPairGenerator.initialize(keySize);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
Map<String, String> keys = new HashMap();
keys.put("privateKey", Base64.encodeBase64String(keyPair.getPrivate().getEncoded());
keys.put("publicKey", Base64.encodeBase64String(keyPair.getPublic().getEncoded());
return keys;
}
}

加密与解密

DES加密与解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public String encrypt(String data, String key)
throws NoSuchPaddingException,
NoSuchAlgorithmException,
InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException,
IOException{

byte[] keyBytes;
keyBytes = new BASE64Decoder().decodeBuffer(key);
Key k = new SecretKeySpec(keyBytes, "DES");
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, k);
return new BASE64Encoder().encode(cipher.doFinal(data.getBytes()));
}

public String decrypt(String data, String key)
throws NoSuchPaddingException,
NoSuchAlgorithmException,
InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException,
IOException{

byte[] keyBytes;
keyBytes = new BASE64Decoder().decodeBuffer(key);
Key k = new SecretKeySpec(keyBytes, "DES");
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.DECRYPT_MODE, k);
return new String(cipher.doFinal(new BASE64Decoder().decodeBuffer(data)));
}

AES加密与解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public String encrypt(String data, String key)
throws NoSuchPaddingException,
NoSuchAlgorithmException,
InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException,
IOException{

byte[] keyBytes;
keyBytes = new BASE64Decoder().decodeBuffer(key);
Key k = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, k);
return new BASE64Encoder().encode(cipher.doFinal(data.getBytes()));
}

public String decrypt(String data, String key)
throws NoSuchPaddingException,
NoSuchAlgorithmException,
InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException,
IOException{

byte[] keyBytes;
keyBytes = new BASE64Decoder().decodeBuffer(key);
Key k = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, k);
return new String(cipher.doFinal(new BASE64Decoder().decodeBuffer(data)));
}

RSA加密与解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public String encrypt(String body, String keyString) 
throws NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeySpecException,
InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException,
IOException{

byte[] keyBytes;
keyBytes = new BASE64Decoder().decodeBuffer(keyString);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Cipher cipher = Cipher.getInstance("RSA");

PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
Key key = keyFactory.generatePrivate(keySpec);
cipher.init(Cipher.ENCRYPT_MODE, key);
return new BASE64Encoder().encode(cipher.doFinal(body.getBytes()));
}

public String decrypt(String body, String keyString)
throws NoSuchAlgorithmException,
NoSuchPaddingException,
InvalidKeySpecException,
InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException,
IOException {

byte[] keyBytes;
keyBytes = new BASE64Decoder().decodeBuffer(keyString);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Cipher cipher = Cipher.getInstance("RSA");

Key key;

X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
key = keyFactory.generatePublic(keySpec);
cipher.init(Cipher.DECRYPT_MODE, key);
return new String(cipher.doFinal(new BASE64Decoder().decodeBuffer(body)));
}

加签与验签

RSA加签与验签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public String sign(String body, String keyString) 
throws NoSuchAlgorithmException,
InvalidKeySpecException,
InvalidKeyException,
SignatureException,
IOException {

byte[] keyBytes;
keyBytes = new BASE64Decoder().decodeBuffer(keyString);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);

Signature signature = Signature.getInstance("MD5withRSA");

signature.initSign(privateKey);
signature.update(body.getBytes());
return Base64.encodeBase64String(signature.sign());
}

public boolean verify(String key, String data, String sign)
throws NoSuchAlgorithmException,
InvalidKeySpecException,
InvalidKeyException,
SignatureException {

X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(key));

Provider provider = new BouncyCastleProvider();

KeyFactory keyFactory = KeyFactory.getInstance("RSA", provider);
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
Signature signature = Signature.getInstance("MD5withRSA", provider);

signature.initVerify(publicKey);
signature.update(data.getBytes());
return signature.verify(Base64.decodeBase64(sign));
}

ECDSA加签与验签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public String sign(String key, String data) 
throws NoSuchAlgorithmException,
InvalidKeySpecException,
InvalidKeyException,
SignatureException {

PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(key));

Provider provider = new BouncyCastleProvider();

KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", provider);
PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
Signature signature = Signature.getInstance("ECDSA", provider);

signature.initSign(privateKey);
signature.update(data.getBytes());
return Base64.encodeBase64String(signature.sign());
}

public boolean verify(String key, String data, String sign)
throws NoSuchAlgorithmException,
InvalidKeySpecException,
InvalidKeyException,
SignatureException {

X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(key));

Provider provider = new BouncyCastleProvider();

KeyFactory keyFactory = KeyFactory.getInstance("ECDSA", provider);
PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
Signature signature = Signature.getInstance("ECDSA", provider);

signature.initVerify(publicKey);
signature.update(data.getBytes());
return signature.verify(Base64.decodeBase64(sign));
}

以上代码都在我的github里面 wangtingbang/cryptography

编程工具及插件

Posted on 2015-09-25

我工作中主要用到Java、Shell,以及后来由于工作需要不得不用的JavaScript,偶尔也会用到Python处理一些脚本性的东西。

在开发的时候,听说过Google style之后,都会将tab制表符换成两个空格,这个对我来说已成惯例。

  1. IDE– Intellij Idea
  2. 文本编辑器 – Vim、Atom
  3. Shell – iTerm2、zsh、mtux、Solarized Dark
  4. Git – git命令行、Github Desktop/SourceTree
  5. 编程字体 – SourceCodePro、mplus(m+)、Anonymous Pro

IDE – IntelliJ Idea

原先是用Eclipse JavaEE版本的,用的时候感觉加载不必要的插件太慢,后来听说Idea后改用了一下,确实挺不错的。
不管是在代码提示、处理性能方面,都比Eclipse要好一些。这是由于Idea后台会运行一些线程做一些工作,将顿卡的问题在后台处理掉,不过这个也有弊端,就是机器发热比较大。

Idea的上手成本可能有点高,他大部分快捷键是Mac风格,跟Eclipse还是有比较大的差异的,不过习惯之后确实非常好用。

Idea有社区版、收费的Ultimate版本,还有教育版本。

文本编辑器 – Vim(MacVim)、Atom

Vim

在接触Vim之后确实恋上了,这个不用多说,大家都知道。用Solarized Dark主题,没有装太多的插件,因为我一般主要是用来处理一些文本的东西,看看日志之类的。

Atom

github旗下的Atom确实很让人喜欢,之前比较喜欢Sublime Text,但在接触Atom之后,就对这个编辑器爱不释手。以Node为核心,完全的一个Web应用但能以App的形式运行,确实让人惊奇。

Atom让我喜欢的地方

  1. 界面
    我是一个喜欢游戏的人,在游戏的载入画面中如果有一些技巧、提示之类的东西,会让我对这个游戏有更好的认同感。
    Atom就是这样一个东西,当你把所有Tab页关掉之后,他有一人各种功能、快捷键的提示。
  2. 快捷键
    Atom快捷键跟我用的其他工具比较接近,用起来感觉顺手一些。这是个见仁见智的问题了吧。
  3. 代码提示
    这个功能确实很爽,在不需要装太多插件的前提下就能实现。
    在之前某处代码有命名一个变量的话,在后续编码过程中只要输入不超过3个字母就能提示这个变量,这确实很吸引我种不喜欢一个字一个字码代码的人。

我的Atom插件

  1. VIM-Mode
    像vim一样实现键盘控制,不过目前这个插件还不支持命令模式,经常输入:w发现没有效果。
  2. markdown-preview-plus
    用来写blog, ctrl+shift+m打开,挺好用的,即时查看。
    缺点就是不能移出去,对于我13寸的屏幕来说确实有点拥挤。

Shell

终端 - iTerm2

嗯,这个有什么好的,目前我也还没有体会到,只是当初在网上找的时候发现很多人都说这个错,配合mtux+zsh是神器之类的,所以就开始用了。目前发现确实还是挺好用的,比默认的Terminal之类的要方便一些,毕竟有一些快捷键和功能确实挺不错。

Shell - zsh

以前接触Linx的时候只知道bash,后来找终端的时候看到有人介绍说zsh是很多程序员用必备的一个东西。
等到真正下下来安装完用了一段时间之后,确实感觉离不开了。

  1. 现成的主题,在github上有很多。只要将主题放到 ~/.oh-my-zsh/themes下之后,在 ~/.zshrc中配置一下就可以。不仅有对于git分支的显示,还有靓丽的色彩。
    我的主题配置如下:
    1
    $ ZSH_THEME="robbyrussell"
  1. 对于git的集成。只要进入到git工程目录下,就会有对于git的各种命令行上的提示,比如这种:
    1
    ➜  /Users/wangtingbang/prog/git-work/wangtingbang.github.io git:(master) ✗
  1. tab 党的福音
    像对于各种目录,命令之类,不再需要从第一个字母开始输入,通过输入的几个字符,zsh就能自动匹配到目录、命令,如果有多个目录,多次按tab选定之后回车就行,甚至只要输入一个目录,回车一下就可以进入。

mtux

目前没有感觉到哪有什么好处,对于这个我用得不太多。(感觉自己有点low)

Solarized Dark主题

对于经常熬夜干活的人来说,这个暗色的主题还是挺不错的。

代码管理 – git

用命令行的git基本就已经够用,但是命令行的git在版本对比功能(diff)上个人不太习惯,很多时候要借助于Github Desktop或者SourceTree

自己常用的代码管理过程中的git命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#用于clone远程代码库
git clone $URL

##-----更新代码Start----
#在很多文章甚于于git的各种代码的README中都能看到更新代码用git pull
#但pull的方式个人不习惯于用
#原因是刚开始用的时候这个命令把我自己本地的修改给覆盖了
#将远程代码取到本地,但不会更新到本地代码中
git fetch

#-----将自己代码暂存----
git stash

#rebase,将fetch下来的代码更新到本地,实际上是变了本地代码的头指针
git rebase origin/$BRANCH

#将本地暂存的代码取出来,可能出来以后会发现有很多冲突(confilits)
git stash pop


##----代码维护----
#简单地查看变更记录
git log

#对比本地文件FILE与代码库中的变更,一般用于自己修改过这个文件之类
git diff -- $FILE

#代码冲突解决,或者自己误添加文件到提交中的后,这个用于解决冲突和恢复
git reset HEAD $FILE


##----代码提交----
#添加一个文件到提交中,也可以直接用git add . 这种比较暴力的方式把所有文件添加
git add $FILE

# 提交代码,这个提交只会保留在本地的git库中
git commit -m "message"

#推送代码到远程服务器的BRANCH分支
git push origin HEAD:refs/heads/$BRANCH

#也可以用这种方式推送代码
git push origin $BRANCH #也可以用这种方式推送代码

#当远程分支开启的code review之后以这种方式提交
git push origin HEAD:refs/for/$BRANCH

编程字体

SourceCodePro

在IDE、iTerm2、vim还是Atom中都有很不错的表现。

mplus(m+)

我主要在iTerm2中用,一行中能够显示比较多的字,这个字体的c、p、2c、2p等好多种,从细到粗都有,并且每一种的样式都有比较大的区别。适合在终端中使用,看日志、对比文件之类的时候非常好用。

Anonymous Pro

以前在Eclipse中用,字体整体比较细,略有尖锐的感觉,看上去比较显眼。

=============== 以下无正文 ==============

sigh differ

sigh differ

5 posts
© 2018 sigh differ
Powered by Hexo
|
Theme — NexT.Muse v5.1.4