乱码三千 – 分享实用IT技术

乱码三千 – 码出一个新世界


  • 首页

  • 归档

  • 搜索

Python跨平台之将Python 程序打包成Windows和Linux可执行文件

发表于 2020-09-07

通常执行 python 程序要有相应的 Python 环境,但某些特定场景下,我们可能并不愿意这么麻烦的去配置这些环境(比如将写好的脚本发给客户进行操作),如果可以提前将程序打包成 Windows平台的 .exe 文件或者是Linux下的 .sh 脚本,那么使用起来就会方便很多,py2exe 和 PyInstaller 这两款工具都是干这么个事的,下面以 hello.py 脚本(代码内容如下)为例进行介绍。

1
2
age = input("How old are you?\n")
print("A: " + age)

提示:PyInstaller 可以在 Windows 和 Linux 下使用,更推荐使用,而 py2exe 暂不支持 Linux 平台 而且只支持python低版本环境

PyInstaller

  1. 安装
1
pip install pyinstaller
  1. 使用

常见的用法有:

  • 生成单个可执行文件:pyinstaller -F hello.py
  • 生成指定icon的可执行文件:pyinstaller -i xxx.ico hello.py

在当前目录下的 dist 文件夹内可以找到生成后的可执行文件(脚本),更多用法请参考说明

py2exe

  1. 安装
1
pip install py2exe
  1. 使用

如上图,打包失败了,留意到这里说不支持 python3.6,果断放弃,有兴趣的可以自行降低到 python3.4 或 python3.5 进行尝试。

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

wireshark怎么抓包、wireshark抓包详细图文教程

发表于 2020-09-07

wireshark是非常流行的网络封包分析软件,功能十分强大。可以截取各种网络封包,显示网络封包的详细信息。使用wireshark的人必须了解网络协议,否则就看不懂wireshark了。
为了安全考虑,wireshark只能查看封包,而不能修改封包的内容,或者发送封包。

wireshark能获取HTTP,也能获取HTTPS,但是不能解密HTTPS,所以wireshark看不懂HTTPS中的内容,总结,如果是处理HTTP,HTTPS 还是用Fiddler, 其他协议比如TCP,UDP 就用wireshark.

wireshark 开始抓包

开始界面

img

wireshark是捕获机器上的某一块网卡的网络包,当你的机器上有多块网卡的时候,你需要选择一个网卡。

点击Caputre->Interfaces.. 出现下面对话框,选择正确的网卡。然后点击”Start”按钮, 开始抓包

img

Wireshark 窗口介绍

img

WireShark 主要分为这几个界面

\1. Display Filter(显示过滤器), 用于过滤

\2. Packet List Pane(封包列表), 显示捕获到的封包, 有源地址和目标地址,端口号。 颜色不同,代表

\3. Packet Details Pane(封包详细信息), 显示封包中的字段

\4. Dissector Pane(16进制数据)

\5. Miscellanous(地址栏,杂项)

img

使用过滤是非常重要的, 初学者使用wireshark时,将会得到大量的冗余信息,在几千甚至几万条记录中,以至于很难找到自己需要的部分。搞得晕头转向。

过滤器会帮助我们在大量的数据中迅速找到我们需要的信息。

过滤器有两种,

一种是显示过滤器,就是主界面上那个,用来在捕获的记录中找到所需要的记录

一种是捕获过滤器,用来过滤捕获的封包,以免捕获太多的记录。 在Capture -> Capture Filters 中设置

保存过滤

在Filter栏上,填好Filter的表达式后,点击Save按钮, 取个名字。比如”Filter 102”,

img

Filter栏上就多了个”Filter 102” 的按钮。

img

过滤表达式的规则

表达式规则

\1. 协议过滤

比如TCP,只显示TCP协议。

\2. IP 过滤

比如 ip.src ==192.168.1.102 显示源地址为192.168.1.102,

ip.dst==192.168.1.102, 目标地址为192.168.1.102

\3. 端口过滤

tcp.port ==80, 端口为80的

tcp.srcport == 80, 只显示TCP协议的愿端口为80的。

\4. Http模式过滤

http.request.method==”GET”, 只显示HTTP GET方法的。

\5. 逻辑运算符为 AND/ OR

常用的过滤表达式

过滤表达式 用途
http 只查看HTTP协议的记录
ip.src ==192.168.1.102 or ip.dst==192.168.1.102 源地址或者目标地址是192.168.1.102
snmp && udp.dstport == 162 抓取SNMP Trap包

封包列表(Packet List Pane)

封包列表的面板中显示,编号,时间戳,源地址,目标地址,协议,长度,以及封包信息。 你可以看到不同的协议用了不同的颜色显示。

你也可以修改这些显示颜色的规则, View ->Coloring Rules.

img

封包详细信息 (Packet Details Pane)

这个面板是我们最重要的,用来查看协议中的每一个字段。

各行信息分别为

Frame: 物理层的数据帧概况

Ethernet II: 数据链路层以太网帧头部信息

Internet Protocol Version 4: 互联网层IP包头部信息

Transmission Control Protocol: 传输层T的数据段头部信息,此处是TCP

Hypertext Transfer Protocol: 应用层的信息,此处是HTTP协议

img

TCP包的具体内容

从下图可以看到wireshark捕获到的TCP包中的每个字段。

img

看到这, 基本上对wireshak有了初步了解, 现在我们看一个TCP三次握手的实例

三次握手过程为

img

这图我都看过很多遍了, 这次我们用wireshark实际分析下三次握手的过程。

打开wireshark, 打开浏览器输入 http://www.cr173.com

在wireshark中输入http过滤, 然后选中GET /tankxiao HTTP/1.1的那条记录,右键然后点击”Follow TCP Stream”,

这样做的目的是为了得到与浏览器打开网站相关的数据包,将得到如下图

img

图中可以看到wireshark截获到了三次握手的三个数据包。第四个包才是HTTP的, 这说明HTTP的确是使用TCP建立连接的。

第一次握手数据包

客户端发送一个TCP,标志位为SYN,序列号为0, 代表客户端请求建立连接。 如下图

第二次握手的数据包

服务器发回确认包, 标志位为 SYN,ACK. 将确认序号(Acknowledgement Number)设置为客户的I S N加1以.即0+1=1, 如下图

第三次握手的数据包

客户端再次发送确认包(ACK) SYN标志位为0,ACK标志位为1.并且把服务器发来ACK的序号字段+1,放在确定字段中发送给对方.并且在数据段放写ISN的+1, 如下图:

就这样通过了TCP三次握手,建立了连接

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

使用python利用第三方登录实现自动化简书发布文章

发表于 2020-09-07

话不多说 首先附上代码

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import time

from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait

import re

import linecache


class Main(object):
# init
def __init__(self, file):
self.title = ''
self.content = ''
self.category = ''
self.tags = ''
# OsChina的系统分类, 设个默认值
self.osChina_sys_category = '编程语言'
# CSDN的文章分类, 设个默认值
self.csdn_article_category = '原创'
# CSDN的博客分类, 设个默认值
self.csdn_blog_category = '后端'
self.read_file(file)

# 读取MD中的title, content, self_category, self_tags, osChina_sys_category, csdn_article_category, csdn_blog_category
def read_file(self, markdown_file):
self.title = linecache.getline(markdown_file, 2).split('title: ')[1].strip('\n')
with open(markdown_file, 'r', encoding='UTF-8') as f:
self.content = f.read().split('-->\n')[1]
# 重置文件指针偏移量
f.seek(0)
for line in f.readlines():
if re.search('self_category: ', line) is not None:
self.category = line.split('self_category: ')[1].strip('\n')
elif re.search('self_tags: ', line) is not None:
self.tags = line.split('self_tags: ')[1].strip('\n')
elif re.search('osChina_sys_category: ', line) is not None:
self.osChina_sys_category = line.split('osChina_sys_category: ')[1].strip('\n')
elif re.search('csdn_article_category: ', line) is not None:
self.csdn_article_category = line.split('csdn_article_category: ')[1].strip('\n')
elif re.search('csdn_blog_category: ', line) is not None:
self.csdn_blog_category = line.split('csdn_blog_category: ')[1].strip('\n')




# QQ授权登录, 使用前提是QQ客户端在线
def qq(driver, timeout):
# 切换到最新打开的窗口
window_handles = driver.window_handles
driver.switch_to.window(window_handles[-1])

print('qq authorize title is ', driver.title)

# 切换iframe
iframe = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_id('ptlogin_iframe'))
driver.switch_to.frame(iframe)

# 点击头像进行授权登录
login = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath('//*[@id="qlogin_list"]/a[1]'))
login.click()
# 简书
class JianShu(object):
@staticmethod
def post(main, timeout, self_timeout=3):
# 1.跳转登陆
login = 'https://www.jianshu.com/sign_in'
driver = webdriver.Chrome()
driver.get(login)

# 2.窗口最大化
driver.maximize_window()

# 3.使用QQ授权登录
driver.find_element_by_xpath('/html/body/div[1]/div[2]/div/div/ul/li[3]/a/i').click()
driver.close()
qq(driver, timeout)

# 4.点击"写文章"
write_blog = WebDriverWait(driver, timeout).until(lambda d: d.find_element_by_xpath('/html/body/nav/div/a[2]'))
write_blog = WebDriverWait(driver, timeout).until(lambda d: d.find_elements_by_class_name('/html/body/nav/div/a[2]'))
write_blog.click()
driver.close()
time.sleep(3)
# window_handles = driver.window_handles
#driver.switch_to.window(window_handles[-1])

# 5.点击指定分类
classify = WebDriverWait(driver, timeout).until(lambda d: d.find_elements_by_class_name('_3DM7w'))
for c in classify:
html = c.get_attribute('innerHTML')
if main.category in html:
c.click()
else:
# TODO 如果分类不存在,还可以直接新建分类
pass

# 6.点击'新建文章'
time.sleep(self_timeout)
new_article = WebDriverWait(driver, timeout).until(
lambda d: d.find_element_by_xpath('//*[@id="root"]/div/div[2]/div[1]/div/div/div/div[1]/i'))
new_article.click()
article = WebDriverWait(driver, timeout).until(
lambda d: d.find_element_by_xpath('//*[@id="root"]/div/div[2]/div[1]/div/div/div/ul/li[1]'))
article.click()

# 7.填写标题, 内容
time.sleep(self_timeout)
title = driver.find_element_by_class_name('_24i7u')
title.clear()
title.send_keys(main.title)
content = driver.find_element_by_id('arthur-editor')
content.clear()
content.send_keys(main.content)

# 8.保存草稿
driver.find_element_by_xpath('//*[@id="root"]/div/div[2]/div[2]/div/div/div/div/ul/li[8]/a').click()
# 8.发布文章
# driver.find_element_by_xpath('//*[@id="root"]/div/div[2]/div[2]/div/div/div/div/ul/li[1]/a').click()


if __name__ == '__main__':
md_file = 'auto.md'
print("Markdown File is ", md_file)

timeout = 30
main = Main(md_file)

# 简书
jian_shu = JianShu()
jian_shu.post(main, timeout)

PS:Selenium操纵浏览器是依赖于浏览器驱动程序的,不同版本的浏览器需要下载不同版本的驱动, 否则程序无法运行, 下面贴出的是谷歌和火狐浏览器驱动程序的下载地址。

Chrome ( chromedriver ) Firefox ( geckodriver )
官方下载 官方下载
淘宝镜像 淘宝镜像
备用下载 备用下载

关于谷歌驱动的下载安装, 详情可参见文章《Web自动化框架selenium的介绍与使用》

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

如何在浏览器中手动设置cookies值实现前端分离调试

发表于 2020-09-07

在前端开发中经常会碰到需要cookies调试的情况, 下面介绍一下如何在浏览器中手动设置cookies值

img

1.查看cookies值

1
document.cookie

2.设置cookies值

1
document.cookie='name=Jack';

3.给cookies设置有效时间 默认浏览器关闭失效

1
2
3
var oDate=new Date();
oDate.setDate(oDate.getDate()+7);//设置为当前时间起算7天后过期
document.cookie='name=Jack;expires='+oDate.toGMTString();

4.移除cookies

1
setCookie(key,"",-1);//把cookie设置为过期

函数封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function setCookie(key,value,t){
var oDate=new Date();
oDate.setDate(oDate.getDate()+t);
document.cookie=key+"="+value+"; expires="+oDate.toDateString();

}
function getCookie(key){
var arr1=document.cookie.split("; ");//由于cookie是通过一个分号+空格的形式串联起来的,所以这里需要先按分号空格截断,变成[name=Jack,pwd=123456,age=22]数组类型;
for(var i=0;i<arr1.length;i++){
var arr2=arr1[i].split("=");//通过=截断,把name=Jack截断成[name,Jack]数组;
if(arr2[0]==key){
return decodeURI(arr2[1]);
}
}

//封装一个移除cookie的函数
function removeCookie(key){
setCookie(key,"",-1);//把cookie设置为过期

}

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

如何设置通过Postman实现API网关的请求签名与调试

发表于 2020-09-07

前言
Postman是一个非常强大的HTTP发包测试工具, 目前Postman已经提供了Windows/Mac/Linux系统的客户端的下载,使用很方便。不过API网关的调试,需要对HTTP请求进行签名才能调用,无法使用简单的curl等发包工具完成,但我们可以使用Postman工具提供的Pre-request Script脚本来实现API网关的签名功能,实现API的调试功能,本文主要介绍如何使用Postman调试API网关接口。

核心代码如下

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
var appKey = "<YOUR APP KEY>";
var appSecret = "<YOUR APP SECRET>";

var md5 = calcMd5();
var date = new Date().toString();
var nonce = createUuid();

var textToSign = "";
textToSign += request.method + "\n";
textToSign += request.headers["accept"] + "\n";
textToSign += md5 + "\n";
textToSign += request.headers["content-type"] + "\n";
textToSign += date + "\n";

var headers = headersToSign();
var signatureHeaders;
var sortedKeys = Array.from(headers.keys()).sort()
for (var headerName of sortedKeys) {
textToSign += headerName + ":" + headers.get(headerName) + "\n";
signatureHeaders = signatureHeaders ? signatureHeaders + "," + headerName : headerName;
}
textToSign += urlToSign();
console.log("textToSign\n" + textToSign.replace(/\n/g, "#"));
var hash = CryptoJS.HmacSHA256(textToSign, appSecret)
console.log("hash:" + hash)
var signature = hash.toString(CryptoJS.enc.Base64)
console.log("signature:" + signature)

pm.globals.set('AppKey', appKey);
pm.globals.set('Md5', md5);
pm.globals.set("Date", date);
pm.globals.set("Signature", signature);
pm.globals.set("SignatureHeaders", signatureHeaders);
pm.globals.set("Nonce", nonce);

function headersToSign() {
var headers = new Map();
for (var name in request.headers) {
name = name.toLowerCase();
if (!name.startsWith('x-ca-')) {
continue;
}
if (name === "x-ca-signature" || name === "x-ca-signature-headers" || name == "x-ca-key" || name === 'x-ca-nonce') {
continue;
}
var value = request.headers[name];
headers.set(name, value);
}
headers.set('x-ca-key', appKey);
headers.set('x-ca-nonce', nonce);
return headers;
}

function urlToSign() {
var params = new Map();
var contentType = request.headers["content-type"];
if (contentType && contentType.startsWith('application/x-www-form-urlencoded')) {
const formParams = request.data.split("&");
formParams.forEach((p) => {
const ss = p.split('=');
params.set(ss[0], ss[1]);
})
}
const ss = request.url.split('?');
if (ss.length > 1 && ss[1]) {
const queryParams = ss[1].split('&');
queryParams.forEach((p) => {
const ss = p.split('=');
params.set(ss[0], ss[1]);
})
}

var sortedKeys = Array.from(params.keys())
sortedKeys.sort();

var l1 = ss[0].lastIndexOf('/');
var url = ss[0].substring(l1);
var first = true;
var qs
for (var k of sortedKeys) {
var s = k + "=" + params.get(k);
qs = qs ? qs + "&" + s : s;
console.log("key=" + k + " value=" + params.get(k));
}
return qs ? url + "?" + qs : url;
}

function calcMd5() {
var contentType = request.headers["content-type"];
if (request.data && !contentType.startsWith('application/x-www-form-urlencoded')) {
var data = request.data;
var md5 = CryptoJS.MD5(data);
var md5String = md5.toString(CryptoJS.enc.Base64);
console.log("data:" + data + "\nmd5:" + md5String);
return md5String;
} else {
return "";
}
}

function createUuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

关于mv 移动文件时出现Argument list too long的解决方案

发表于 2020-09-03

移动所有文件到指定目录

1
mv 需要移动的目录/* 目标目录/

当出现文件过多时报错:Argument list too long

解决方案:

移动文件:

1
find sourcePath/ -name "*.txt"  -exec mv {} targetPath/  \;

or:

1
find sourcePath/ -type f  -exec mv {} targetPath/  \;

查看所有行目录下所有txt文件的行:

1
find sourcePath/ -name "*.txt" |xargs cat |wc -l

只移动前5个文件

1
mv `ls |sed -n 1,5p  /post

只拷贝前5个文件

1
cp -R `ls |sed -n 1,5p /post

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

关于linux指令sed的使用

发表于 2020-09-01

sed -i 主要作用就是操作文本 如下:

去掉 “行首” 带“@”的首字母@

1
sed -i 's/^@//' file

特定字符串的行前插入新行

1
sed -i '/特定字符串/i 新行字符串' file

特定字符串的行后插入新行

1
sed -i '/特定字符串/a 新行字符串' file

特定字符串的删除

1
sed -i '/字符串/d' file

提示: 以上斜杠可以换成~ 一样实现相同功能

问题场景:

在mac上,使用sed命令把当前目录的test.sql文件内容中的a替换为b,使用命令:sed -i “s/a/b/g” test.sql

遇到报错:sed: 1: “grep …”: extra characters at the end of g command

解决:

在mac中使用sed命令在-i参数后面需要带一对双引号””,正确格式如下:

1
sed -i "" "s/a/b/g" test.sql

原因

sed -i 后面的双引号中可写任意字符串或者为空,含义是用于生成源文件的备份文件的文件名。比如上面的例子:sed -i “_tmp” “s/a/b/g” test.sql,在替换test.sql的同时,还会生成test.sql_tmp的备份文件

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

Git撤销&回滚操作(git reset 和 get revert)

发表于 2020-09-01

git的工作流

工作区:即自己当前分支所修改的代码,git add xx 之前的!不包括 git add xx 和 git commit xxx 之后的。

暂存区:已经 git add xxx 进去,且未 git commit xxx 的。

本地分支:已经git commit -m xxx 提交到本地分支的。
这里写图片描述


代码回滚

在上传代码到远程仓库的时候,不免会出现问题,任何过程都有可能要回滚代码:

1、在工作区的代码

git checkout – a.txt # 丢弃某个文件,或者
git checkout – . # 丢弃全部

注意:git checkout – . 丢弃全部,也包括:新增的文件会被删除、删除的文件会恢复回来、修改的文件会回去。这几个前提都说的是,回到暂存区之前的样子。对之前保存在暂存区里的代码不会有任何影响。对commit提交到本地分支的代码就更没影响了。当然,如果你之前压根都没有暂存或commit,那就是回到你上次pull下来的样子了。

2、代码git add到缓存区,并未commit提交

git reset HEAD . 或者
git reset HEAD a.txt

这个命令仅改变暂存区,并不改变工作区,这意味着在无任何其他操作的情况下,工作区中的实际文件同该命令运行之前无任何变化

3、git commit到本地分支、但没有git push到远程

git log # 得到你需要回退一次提交的commit id
git reset –hard # 回到其中你想要的某个版
或者
git reset –hard HEAD^ # 回到最新的一次提交
或者
git reset HEAD^ # 此时代码保留,回到 git add 之前

4、git push把修改提交到远程仓库
1)通过git reset是直接删除指定的commit

git log # 得到你需要回退一次提交的commit id
git reset –hard
git push origin HEAD –force # 强制提交一次,之前错误的提交就从远程仓库删除

2)通过git revert是用一次新的commit来回滚之前的commit

git log # 得到你需要回退一次提交的commit id
git revert # 撤销指定的版本,撤销也会作为一次提交进行保存

3) git revert 和 git reset的区别
- git revert是用一次新的commit来回滚之前的commit,此次提交之前的commit都会被保留;
- git reset是回到某次提交,提交及之前的commit都会被保留,但是此commit id之后的修改都会被删除

开发过程中,你肯定会遇到这样的场景:

场景一:

糟了,我刚把不想要的代码,commit到本地仓库中了,但是还没有做push操作!

场景二:

彻底完了,刚线上更新的代码出现问题了,需要还原这次提交的代码!

场景三:

刚才我发现之前的某次提交太愚蠢了,现在想要干掉它!

撤销

上述场景一,在未进行git push前的所有操作,都是在“本地仓库”中执行的。我们暂且将“本地仓库”的代码还原操作叫做“撤销”!

情况一:文件被修改了,但未执行git add操作(working tree内撤销)

1
2
3
4
5
git checkout fileName



git checkout .

情况二:同时对多个文件执行了git add操作,但本次只想提交其中一部分文件

1
2
3
4
5
6
7
8
9
10
11
12
13
$ git add *



$ git status



# 取消暂存



$ git reset HEAD <filename>

情况三:文件执行了git add操作,但想撤销对其的修改(index内回滚)

1
2
3
4
5
6
7
8
9
10
11
12
13
# 取消暂存



git reset HEAD fileName



# 撤销修改



git checkout fileName

情况四:修改的文件已被git commit,但想再次修改不再产生新的Commit

1
2
3
4
5
6
7
8
9
# 修改最后一次提交 



$ git add sample.txt



$ git commit --amend -m"说明"

情况五:已在本地进行了多次git commit操作,现在想撤销到其中某次Commit

1
git reset [--hard|soft|mixed|merge|keep] [commit|HEAD]

具体参数和使用说明,请查看:Git Pro深入浅出(二)中的重置揭秘部分

回滚

上述场景二,已进行git push,即已推送到“远程仓库”中。我们将已被提交到“远程仓库”的代码还原操作叫做“回滚”!注意:对远程仓库做回滚操作是有风险的,需提前做好备份和通知其他团队成员!

如果你每次更新线上,都会打tag,那恭喜你,你可以很快的处理上述场景二的情况

1
git checkout <tag>

如果你回到当前HEAD指向

1
git checkout <branch_name>

情况一:撤销指定文件到指定版本

1
2
3
4
5
6
7
8
9
10
11
12
13
# 查看指定文件的历史版本



git log <filename>



# 回滚到指定commitID



git checkout <commitID> <filename>

情况二:删除最后一次远程提交

方式一:使用revert

1
2
3
4
5
git revert HEAD



git push origin master

方式二:使用reset

1
2
3
4
5
git reset --hard HEAD^



git push origin master -f

二者区别:

  • revert是放弃指定提交的修改,但是会生成一次新的提交,需要填写提交注释,以前的历史记录都在;
  • reset是指将HEAD指针指到指定提交,历史记录中不会出现放弃的提交记录。

情况三:回滚某次提交

1
2
3
4
5
6
7
8
9
# 找到要回滚的commitID



git log



git revert commitID

删除某次提交

1
git log --oneline -n5

1
git rebase -i "commit id"^

注意:需要注意最后的^号,意思是commit id的前一次提交

1
git rebase -i "5b3ba7a"^

在编辑框中删除相关commit,如pick 5b3ba7a test2,然后保存退出(如果遇到冲突需要先解决冲突)!

1
git push origin master -f

通过上述操作,如果你想对历史多个commit进行处理或者,可以选择git rebase -i,只需删除对应的记录就好。rebase还可对 commit 消息进行编辑,以及合并多个commit。

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

解决pip下载速度慢的问题

发表于 2020-09-01

在我们经常使用pip安装插件模块的时候,有没有发现下载速度很慢,但有些有强迫症的人面对几k几十k每秒的速度绝对忍不了,是不是,那么,方法来了。

问题描述

一句话就是使用pip下载过慢,想要快起来,起来,来。

解决过程

问题分析

pip下载速度过慢的原因就是pip默认使用的是国外的镜像源,那么,我使用国内的镜像源,问题不就解决了。

有两种方法,方法一临时有效,方法二永久生效。

方法一:下载时加入参数-i [镜像源地址]

1
2
3
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple jieba
或者
pip install jieba -i https://pypi.tuna.tsinghua.edu.cn/simple

方法二:设置源

使用方法一,需要每次在下载时都要带参数,不想麻烦的试试方法二吧。

1
2
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
pip config set install.trusted-host mirrors.aliyun.com

img

附: 国内镜像源地址

1
2
3
4
5
6
7
8
9
# pip国内镜像源。
#
# 阿里云 http://mirrors.aliyun.com/pypi/simple/
# 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/
# 豆瓣 http://pypi.douban.com/simple
# Python官方 https://pypi.python.org/simple/
# v2ex http://pypi.v2ex.com/simple/
# 中国科学院 http://pypi.mirrors.opencas.cn/simple/
# 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

解决homebrew长时间停在Updating Homebrew 这个步骤

发表于 2020-09-01

在国内的网络环境下使用 Homebrew 安装软件的过程中可能会长时间卡在 Updating Homebrew 这个步骤。

例:执行 brew install composer 命令

1
2
➜  ~ brew install composer
Updating Homebrew... # 如果碰到长时间卡在这里,参考以下 2 种处理方法

方法 1:按住 control + c 取消本次更新操作

1
2
3
➜  ~ brew install composer
Updating Homebrew...
^C

按住 control + c 之后命令行会显示 ^C,就代表已经取消了 Updating Homebrew 操作

大概不到 1 秒钟之后就会去执行我们真正需要的安装操作了

1
2
3
4
5
➜  ~ brew install composer
Updating Homebrew...
^C==> Satisfying dependencies
==> Downloading https://getcomposer.org/download/1.7.2/composer.phar
...

这个方法是临时的、一次性的

方法 2:使用 Alibaba 的 Homebrew 镜像源进行加速

平时我们执行 brew 命令安装软件的时候,跟以下 3 个仓库地址有关:

  1. brew.git
  2. homebrew-core.git
  3. homebrew-bottles

通过以下操作将这 3 个仓库地址全部替换为 Alibaba 提供的地址

1. 替换 / 还原 brew.git 仓库地址

1
2
3
4
5
6
7
8
9
# 替换成阿里巴巴的 brew.git 仓库地址:
cd "$(brew --repo)"
git remote set-url origin https://mirrors.aliyun.com/homebrew/brew.git

#=======================================================

# 还原为官方提供的 brew.git 仓库地址
cd "$(brew --repo)"
git remote set-url origin https://github.com/Homebrew/brew.git

2. 替换 / 还原 homebrew-core.git 仓库地址

1
2
3
4
5
6
7
8
9
# 替换成阿里巴巴的 homebrew-core.git 仓库地址:
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://mirrors.aliyun.com/homebrew/homebrew-core.git

#=======================================================

# 还原为官方提供的 homebrew-core.git 仓库地址
cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
git remote set-url origin https://github.com/Homebrew/homebrew-core.git

3. 替换 / 还原 homebrew-bottles 访问地址

这个步骤跟你的 macOS 系统使用的 shell 版本有关系

所以,先来查看当前使用的 shell 版本

1
2
3
4
echo $SHELL

# 如果你的输出结果是 /bin/zsh,参考?的 zsh 终端操作方式
# 如果你的输出结果是 /bin/bash,参考?的 bash 终端操作方式

3.1 zsh 终端操作方式

1
2
3
4
5
6
7
8
9
10
# 替换成阿里巴巴的 homebrew-bottles 访问地址:
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.zshrc
source ~/.zshrc

#=======================================================

# 还原为官方提供的 homebrew-bottles 访问地址
vi ~/.zshrc
# 然后,删除 HOMEBREW_BOTTLE_DOMAIN 这一行配置
source ~/.zshrc

3.2 bash 终端操作方式

1
2
3
4
5
6
7
8
9
10
# 替换 homebrew-bottles 访问 URL:
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.aliyun.com/homebrew/homebrew-bottles' >> ~/.bash_profile
source ~/.bash_profile

#=======================================================

# 还原为官方提供的 homebrew-bottles 访问地址
vi ~/.bash_profile
# 然后,删除 HOMEBREW_BOTTLE_DOMAIN 这一行配置
source ~/.bash_profile

HomeBrew快速安装

自动脚本(全部国内地址)(在Mac os终端中复制粘贴回车下面这句话)

1
/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"

这行命令就是这位大佬发布的:金牛肖马

本文为作者原创 转载时请注明出处 谢谢

乱码三千 – 点滴积累 ,欢迎来到乱码三千技术博客站

1…394041…50

乱码三千

android程序员一枚,擅长java,kotlin,python,金融投资,欢迎交流~

491 日志
143 标签
RSS
© 2025 乱码三千
本站总访问量次
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4
0%