无常是常

分享技术见解、学习心得和生活感悟

最新文章

git commit之后,撤销commit

场景

一般情况下,我们写完代码后会执行:

1
2
git add .
git commit -m "xxx"

但是执行完后,想撤回怎么办?可以执行以下命令:

1
git reset --soft HEAD^

这样就可以撤回你的提交,并且不会丢失提交前修改的内容.

理解

HEAD^ 代表上一个版本,同等于HEAD1,如果进行了两次提交,可以写成HEAD2

参数

--mixed

默认参数,不删除工作空间改动的代码,只撤回提交,并且撤回git add .操作

--soft

不删除工作空间改动的代码,撤销提交,但是不撤回git add . 操作

--hard

删除工作空间改动的代码,撤销commit,撤销git add .,直接回退到上次commit

最后

如果commit注释写错了,只是想改一下注释,只需要:

1
git commit --amend

此时会进入默认vim编辑器,修改注释完毕后保存就好了。

场景

一般情况下,我们写完代码后会执行:

1
2
git add .
git commit -m "xxx"

但是执行完后,想撤回怎么办?可以执行以下命令:

1
git reset --soft HEAD^

这样就可以撤回你的提交,并且不会丢失提交前修改的内容.

理解

HEAD^ 代表上一个版本,同等于HEAD1,如果进行了两次提交,可以写成HEAD2

参数

--mixed

默认参数,不删除工作空间改动的代码,只撤回提交,并且撤回git add .操作

--soft

不删除工作空间改动的代码,撤销提交,但是不撤回git add . 操作

--hard

删除工作空间改动的代码,撤销commit,撤销git add .,直接回退到上次commit

最后

如果commit注释写错了,只是想改一下注释,只需要:

1
git commit --amend

此时会进入默认vim编辑器,修改注释完毕后保存就好了。

git rebase和git merge的区别

Description

git rebasegit merge 一样都是用于从一个分支获取并且合并到当前分支,但是他们采取不同的工作方式,以下面的一个工作场景说明其区别.

如图所示:你在一个feature分支进行新特性的开发,与此同时,master 分支的也有新的提交。

http://oss.buzhidao.cc/b454bf1d01ec3dee808830b24dd87c2e.png
为了将master 上新的提交合并到你的feature分支上,你有两种选择:merging or rebasing

merge

执行以下命令:

1
2
git checkout feature
git merge master

或者执行更简单的:
git merge master feature

那么此时在feature上git 自动会产生一个新的commit(merge commit)
look like this:

http://oss.buzhidao.cc/2cebea59e5f82803cb35f99f85b6653d.png

**merge 特点:**自动创建一个新的commit,如果合并的时候遇到冲突,仅需要修改后重新commit
**优点:**记录了真实的commit情况,包括每个分支的详情
**缺点:**因为每次merge会自动产生一个merge commit,所以在使用一些git 的GUI tools,特别是commit比较频繁时,看到分支很杂乱。

rebase

本质是变基,执行以下命令:

1
2
git checkout feature
git rebase master

http://oss.buzhidao.cc/245938aba30e1d7ff14f759eea81eb37.png
**rebase 特点:**会合并之前的commit历史
**优点:**得到更简洁的项目历史,去掉了merge commit
**缺点:**如果合并出现代码问题不容易定位,因为re-write了history
合并时如果出现冲突需要按照如下步骤解决

  • 修改冲突部分
  • git add
  • git rebase --continue
  • (如果第三步无效可以执行 git rebase --skip)

不要在git add 之后习惯性的执行 git commit命令
The Golden Rule of Rebasing rebase 的黄金法则:
never use it on public branches(不要在公共分支上使用)
比如说如下场景:如图所示
http://oss.buzhidao.cc/ac37304e85f5ddf56f1fc302b9e42781.png

如果你rebase master 到你的feature分支:
rebase 将所有master的commit移动到你的feature 的顶端。问题是:其他人还在original master上开发,由于你使用了rebase移动了master,git 会认为你的主分支的历史与其他人的有分歧,会产生冲突。
所以在执行git rebase 之前 问问自己,

会有其他人看这个分支么?
IF YES 不要采用这种带有破坏性的修改commit 历史的rebase命令
IF NO OK,随你便,可以使用rebase

Summary 总结

如果你想要一个干净的,没有merge commit的线性历史树,那么你应该选择git rebase
如果你想保留完整的历史记录,并且想要避免重写commit history的风险,你应该选择使用git merge

参考资料

https://www.atlassian.com/git/tutorials/merging-vs-rebasing/conceptual-overview
https://git-scm.com/book/zh/v2/Git-分支-变基
https://git-scm.com/book/zh/v2/Git-分支-分支的新建与合并#_basic_merging

Description

git rebasegit merge 一样都是用于从一个分支获取并且合并到当前分支,但是他们采取不同的工作方式,以下面的一个工作场景说明其区别.

如图所示:你在一个feature分支进行新特性的开发,与此同时,master 分支的也有新的提交。

http://oss.buzhidao.cc/b454bf1d01ec3dee808830b24dd87c2e.png
为了将master 上新的提交合并到你的feature分支上,你有两种选择:merging or rebasing

merge

执行以下命令:

1
2
git checkout feature
git merge master

或者执行更简单的:
git merge master feature

那么此时在feature上git 自动会产生一个新的commit(merge commit)
look like this:

http://oss.buzhidao.cc/2cebea59e5f82803cb35f99f85b6653d.png

**merge 特点:**自动创建一个新的commit,如果合并的时候遇到冲突,仅需要修改后重新commit
**优点:**记录了真实的commit情况,包括每个分支的详情
**缺点:**因为每次merge会自动产生一个merge commit,所以在使用一些git 的GUI tools,特别是commit比较频繁时,看到分支很杂乱。

rebase

本质是变基,执行以下命令:

1
2
git checkout feature
git rebase master

http://oss.buzhidao.cc/245938aba30e1d7ff14f759eea81eb37.png
**rebase 特点:**会合并之前的commit历史
**优点:**得到更简洁的项目历史,去掉了merge commit
**缺点:**如果合并出现代码问题不容易定位,因为re-write了history
合并时如果出现冲突需要按照如下步骤解决

  • 修改冲突部分
  • git add
  • git rebase --continue
  • (如果第三步无效可以执行 git rebase --skip)

不要在git add 之后习惯性的执行 git commit命令
The Golden Rule of Rebasing rebase 的黄金法则:
never use it on public branches(不要在公共分支上使用)
比如说如下场景:如图所示
http://oss.buzhidao.cc/ac37304e85f5ddf56f1fc302b9e42781.png

如果你rebase master 到你的feature分支:
rebase 将所有master的commit移动到你的feature 的顶端。问题是:其他人还在original master上开发,由于你使用了rebase移动了master,git 会认为你的主分支的历史与其他人的有分歧,会产生冲突。
所以在执行git rebase 之前 问问自己,

会有其他人看这个分支么?
IF YES 不要采用这种带有破坏性的修改commit 历史的rebase命令
IF NO OK,随你便,可以使用rebase

Summary 总结

如果你想要一个干净的,没有merge commit的线性历史树,那么你应该选择git rebase
如果你想保留完整的历史记录,并且想要避免重写commit history的风险,你应该选择使用git merge

参考资料

https://www.atlassian.com/git/tutorials/merging-vs-rebasing/conceptual-overview
https://git-scm.com/book/zh/v2/Git-分支-变基
https://git-scm.com/book/zh/v2/Git-分支-分支的新建与合并#_basic_merging

Nginx反向代理配置

使用nginx做反向代理的时候,可以简单的直接把请求原封不动的转发给下一个服务。设置proxy_pass请求只会替换域名,如果要根据不同的url后缀来访问不同的服务,则需要通过如下方法:

方法一:加"/"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 8000;
server_name abc.com;
access_log "pipe:rollback /data/log/nginx/access.log interval=1d baknum=7 maxsize=1G" main;

location ^~/user/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;

proxy_pass http://user/;
}

location ^~/order/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;

proxy_pass http://order/;
}
}

^~/user/表示匹配前缀是user的请求,proxy_pass的结尾有/, 则会把/user/*后面的路径直接拼接到后面,即移除user。

方法二:rewrite

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
location ^~/user/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;

rewrite ^/user/(.*)$ /$1 break;
proxy_pass http://user;
}

location ^~/order/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;

rewrite ^/order/(.*)$ /$1 break;
proxy_pass http://order;
}
}

proxy_pass结尾没有/, rewrite重写了url。

location匹配命令

1
2
3
4
5
~     #波浪线表示执行一个正则匹配,区分大小写
~* #表示执行一个正则匹配,不区分大小写
^~ #^~表示普通字符匹配,如果该选项匹配,只匹配该选项,不匹配别的选项,一般用来匹配目录
= #进行普通字符精确匹配
@ #"@" 定义一个命名的 location,使用在内部定向时,例如 error_page, try_files

location 匹配的优先级(与location在配置文件中的顺序无关)

= 精确匹配会第一个被处理。如果发现精确匹配,nginx停止搜索其他匹配。

普通字符匹配,正则表达式规则和长的块规则将被优先和查询匹配,也就是说如果该项匹配还需去看有没有正则表达式匹配和更长的匹配。

^~ 则只匹配该规则,nginx停止搜索其他匹配,否则nginx会继续处理其他location指令。

最后匹配理带有""和"*"的指令,如果找到相应的匹配,则nginx停止搜索其他匹配;当没有正则表达式或者没有正则表达式被匹配的情况下,那么匹配程度最高的逐字匹配指令会被使用。

使用nginx做反向代理的时候,可以简单的直接把请求原封不动的转发给下一个服务。设置proxy_pass请求只会替换域名,如果要根据不同的url后缀来访问不同的服务,则需要通过如下方法:

方法一:加"/"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 8000;
server_name abc.com;
access_log "pipe:rollback /data/log/nginx/access.log interval=1d baknum=7 maxsize=1G" main;

location ^~/user/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;

proxy_pass http://user/;
}

location ^~/order/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;

proxy_pass http://order/;
}
}

^~/user/表示匹配前缀是user的请求,proxy_pass的结尾有/, 则会把/user/*后面的路径直接拼接到后面,即移除user。

方法二:rewrite

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
location ^~/user/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;

rewrite ^/user/(.*)$ /$1 break;
proxy_pass http://user;
}

location ^~/order/ {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;

rewrite ^/order/(.*)$ /$1 break;
proxy_pass http://order;
}
}

proxy_pass结尾没有/, rewrite重写了url。

location匹配命令

1
2
3
4
5
~     #波浪线表示执行一个正则匹配,区分大小写
~* #表示执行一个正则匹配,不区分大小写
^~ #^~表示普通字符匹配,如果该选项匹配,只匹配该选项,不匹配别的选项,一般用来匹配目录
= #进行普通字符精确匹配
@ #"@" 定义一个命名的 location,使用在内部定向时,例如 error_page, try_files

location 匹配的优先级(与location在配置文件中的顺序无关)

= 精确匹配会第一个被处理。如果发现精确匹配,nginx停止搜索其他匹配。

普通字符匹配,正则表达式规则和长的块规则将被优先和查询匹配,也就是说如果该项匹配还需去看有没有正则表达式匹配和更长的匹配。

^~ 则只匹配该规则,nginx停止搜索其他匹配,否则nginx会继续处理其他location指令。

最后匹配理带有""和"*"的指令,如果找到相应的匹配,则nginx停止搜索其他匹配;当没有正则表达式或者没有正则表达式被匹配的情况下,那么匹配程度最高的逐字匹配指令会被使用。