0%

deriving限制一些特定trait

  • Clone
  • Copy
  • Debug
  • Default
  • Eq
  • Hash
  • Ord
  • PartialEq
  • PartialOrd

其他一些实现trait

  • 检查相等问题需要实现core::cmp::PartialEq的trait
  • 构造和析构可以实现new方法和Drop traitdrop方法
  • 调用函数可以重载trait系统,有三个,分别是FnFnMutFnOnce
  • 如果需要实现打印输出功能,需要实现fmt::Display trait(std::fmt::Display),错误输出则需要返回fmt::Result
  • 实现错误类型需要实现error::Error trait(std::error)的description方法和cause方法
  • 如果需要重载+运算符可以通过重载Add特性实现 std::ops
  • 想要自定义指针类型,可以通过重载DerefDereMut(std::ops::Deref)特性的deref方法来实现解引用运算符
  • 实现自定义派生属性,则需要在函数前加上#[proc_macro_derive(attr_name)],并且input参数和返回值为TokenStream,实现函数名为derive
    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
    Add +.
    AddAssign +=.
    BitAnd &.
    BitAndAssign &=.
    BitOr |.
    BitOrAssign |=.
    BitXor ^.
    BitXorAssign ^=.
    Deref *v.
    DerefMut *v = 1;.
    Div /.
    DivAssign /=.
    Drop 'destructor'.
    Fn an immutable receiver.
    FnMut a mutable receiver.
    FnOnce a by-value receiver.
    Index (container[index]).
    IndexMut (container[index]).
    Mul *.
    MulAssign *=.
    Neg -.
    Not !.
    RangeBounds RangeBounds is implemented by Rust's built-in range types, produced by range syntax like .., a.., ..b, ..=c, d..e, or f..=g.
    Rem %.
    RemAssign %=.
    Shl <<
    ShlAssign <<=.
    Shr >>
    ShrAssign >>=.
    Sub -.
    SubAssign -=.
    CoerceUnsized Experimental Trait that indicates that this is a pointer or a wrapper for one, where unsizing can be performed on the pointee.
    DispatchFromDyn Experimental This is used for object safety, to check that a method's receiver type can be dispatched on.
    Generator Experimental The trait implemented by builtin generator types.
    Try Experimental A trait for customizing the behavior of the ? operator.

macro_rules片段分类符句法含义:

  • ident:一个标识符。如:x,foo
  • path:一个受限的名字,指代路径。如:T::SpecialA、foo、std::iter等
  • expr:一个表达式。如2+2;f(42)
  • ty:一个类型。如i32;Vec<(char, String)>;&T
  • pat:一个模式。如:Some(t);_
  • stmt:一个单独语句。如:let x = 3
  • block:一个大括号界定的语句序列
  • item:一个项。如fn foo() {}, struct Bar,模块、声明、函数定义、类型定义、结构体定义、impl实现等都是
  • meta:一个元数据项,可以从属性中找到。如:cfg(target_os = “windows”),包含在#[…]或![…]属性内信息
  • tt:TokenTree缩写,指代词条树
  • vis:指代可见性,如pub
  • lifetime:指代生命周期

对于原变量后面的记号有额外的规则:

  • expr和stmt变量必须后跟任意一个:=> , ;
  • ty和path变量必须后跟任意一个:=> , = | ; : > [ { as where
  • pat变量必须后跟任意一个:=> , = | if in
  • 其他变量可以跟任何记号

宏系统完全不处理解析模糊

  • 通过在某些记号前面加上记号可以解决问题,如:$(I $i:ident)* E $e:expr

型变

  • 型变(subtype)指根据原始类型子类型关系确定复杂类型子类型关系的规则。型变分为三种形式:
    • 协变(covariant)。保持子类型关系
    • 逆变(contravariant)。逆转子类型关系
    • 不变(invariant)。不保持也不逆转类型关系,即无关
  • Rust中只有生命周期有子类型关系,长类型是短类型的子类型
  • PhantomData<T>是一个零大小类型的标记结构体,也叫幻影类型,它扮演三个角色:
    • 型变
    • 标记拥有关系(drop)
    • 自动trait实现(Send和Sync)

几个重要的型变列表

  • &’a T在'aT上是协变的,对应*const T也是协变
  • &’a mut T在'a上是协变,但在T上是不变的
  • Fn(T)->UT上是不变,在U上是协变
  • Box<T>Vec<T>以及其他集合对于它们包含的类型来说是协变
  • UnsafeCell<T>Cell<T>RefCell<T>Mutex<T>以及其他内部可变类型在T上都是不变,对应* mut T也是不变
  • 对于结构退来说,如果包含的字段都是协变,则结构体是协变,否则为不变。对Phantomdata<T>类型来说,有以下规则:
    • PhantomData<T>,在T上是协变
    • PhantomData<&'a T>,在'aT上是协变
    • PhantomData<&'a mut T>,在'a上是协变,在T上是不变
    • PhantomData<*const T>,在T上是协变
    • PhantomData<*mut T>,在T上是不变
    • PhantomData<fn(T)>,在T上是逆变,如果以后修改语法,会成为不变
    • PhantomData<fn()->T>,在T上是协变
    • PhantomData<fn(T)->T>,在T上是不变
    • PhantomData<Cell<&'a()>>,在'a上是不变
  • 当协变不会引起未定义行为的时候,可以用协变,否则就保证该类型为不变或逆变

安装Rust

1
2
$ curl https://sh.rustup.rs -sSf | sh
# $ curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly -y

修改国内源

1
2
3
# 设置环境变量
export RUSTUP_DIST_SERVER=http://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=http://mirrors.ustc.edu.cn/rust-static/rustup
1
2
3
4
5
6
# ~/.cargo/config
[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"
replace-with = 'ustc'
[source.ustc]
registry = "http://mirrors.ustc.edu.cn/crates.io-index"

Docker中使用

1
2
3
4
5
6
# Dockerfile
FROM phusion/baseimage
ENV RUSTUP_HOME=/rust
ENV CARGO_HOME=/cargo
ENV PATH=/cargo/bin:/rust/bin:$PATH
RUN curl https://sh.rustup.rs -sSf | sh -s -- -- default-toolchain nightly -y

Racer代码补全

1
2
3
$ cargo install racer
$ rustup component add rust-src
export RUST_SRC_PATH="$(rustc --print sysroot)/lib/rustlib/src/rust/src"

抛却vim-spf13后,偷窃了一些配置,拼凑为自己的VIM配置

通过以下命令,安装VIM插件,仅限Manjaro操作系统

1
2
3
4
5
$ git clone https://github.com/ZetZhang/vim-congiration-installer.git
$ cd vim-congiration-installer
$ ./install.sh

### 效果图

tzado9.png

shared_hello.c为例子,里面有函数和main入口

让可执行文件可共享

1
2
3
$ gcc -m32 -pie -fpie -rdynamic -o libshared_hello.so shared_hello.c
$ gcc -m32 -o shared_hello.noc -L./ -lshared_hello
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./ ./shared_hello.noc

让共享库可执行

这种生成方式的程序没有入口

1
2
3
$ gcc -m32 -shared -fpic -o libshared_hello.so shared_hello.c
$ readelf -h libshared_hello.so | grep "Entry point"
$ objdump -d libshared_hello.so | grep 1050 | head -2

解决入口问题也是如此

1
$ gcc -m32 -shared -fpic -o libshared_hello.so shared_hello.c -Wl,-emain

gdb的core dump解析

1
$ ulimit -c unlimited

通过主动链接器跑一下

1
$ /lib/ld-linux.so.2 ./libshared_hello.so

通过程序中加入标准退出函数_exit(0),就能正常执行了


原理

实际入口函数并非main(),而是_start,再改造,编译时连入口都不用指定了

1
2
$ gcc -m32 -g -shared -fpic -o libshared_hello.so shared_hello.c
$ /lib/ld-linux.so.2 ./libshared_hello.so

也可以当共享库使用了

1
2
$ gcc -m32 -o shared_hello.noc -L./ -lshared_hello
$ LD_LIBRARY_PATH=$LD_LIBRARY_PATH:./ ./shared_hello.noc

然后那个asm内嵌汇编解决主动链接问题的跑不起来

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
# ---------- 主要使用方式 ----------
command(arg1 arg2 ...) # 运行命令
set(var_name var_value) # 定义变量,或者赋值
command(arg1 ${var_name}) # 使用变量
# ---------- 工程配置部分 ----------
cmake_minimum_required(VERSION num) # CMake最低版本号要求
project(cur_project_name) # 项目信息
set(CMAKE_CXX_FLAGS "XXX") # 设定编译器版本,如-std=c++11
set(CMAKE_BUILD_TYPE "XXX") # 设定编译模式,如Debug/Release
# ---------- 依赖执行部分 ----------
find_package(std_lib_name VERSION REQUIRED) # 引入外部依赖
add_library(<name> [STATIC|SHARED|MODULE] source1) # 生成库烈性(动态,静态)
include_directories(${std_lib_name_INCLUDE_DIRS}) # 指定头文件include路径,相当于gcc的-l
link_directories(${std_lib_name_INCLUDE_DIRS}) # 指定动态链接库或静态链接库的路径,相当于gcc的-L
add_executable(cur_project_name XXX.cpp) # 指定生成目标
target_link_libraries(${std_lib_name_LIBRARIES}) # 指定libraries路径,放在add_executable
# ---------- 其他辅助部分 ----------
function(function_name arg) # 定义一个函数
add_subdirectory(dir) # 添加一个子目录
AUS_SOURCE_DIRECTORY(. SRC_LIST) # 查找当前目录所有文件,保存到SRC_LIST变量中
FOREACH(one_dir ${SRC_LIST})
MESSAGE(${one_dir}) # 使用message进行打印
ENDFOREACH(onedir)
# ---------- 判断控制部分 ----------
if(expression)
COMMAND1(ARGS)
ELSE(expression)
COMMAND2(ARGS)
ENDIF(expression)
# expression
IF(var)
IF(NOT var)
IF(var1 AND var2)
IF(var1 OR var2)
IF(COMMAND cmd)
IF(EXISTS dir)
IF(EXISTS file)
IF(IS_DIRECTORY dirname)
IF(file1 IS_NEWER_THAN file2)
IF(variable MATCHES regex)
# range
WHILE(condition)
COMMAND1(ARGS)
// ...
ENDWHILE(condition)
# ---------- CMake基本常用指令 ----------
ADD_DEFINITIONS # 为源文件的编译添加由-D引入的宏定义,如add_definitions(-DWin32)
OPTION # 提供可以选择的选项,格式为:option(variable "description" initial_value)
ADD_CUSTOM_COMMAND/TARGET
# [COMMAND]:为工程添加自定义的构建规则
# [TARGET]:给指定名称的目标指定执行的命令,目标没有输出文件,并始终被构建
ADD_DEPENDENCIES # 添加依赖
INSTALL # 用于定义安装规则,安装内容包括目标二进制、动态库、静态库以及文件、目录、脚本
TARGET_INCLUDE_DIRECTORIES # target_include_directories(<target>[SYSTEM][BEFORE]<INTERFACE|PUBLIC|PRIVATE>[items])
SET_TARGET_PROPERTIES # 设置目标oad属性来改变它们构建的方式
ENABLE_TESTING/ADD_TEST
# [enable_testing]:控制Makefile是否构建test目标
# [add_test]:一般和enable_testing配合使用
# 格式ADD_TEST(testname Exename arg1 arg2 ...),生成后make test测试
# ---------- CMake基本常用变量 ----------
CMAKE_INSTALL_PREFIX # 构建install的路径
$ENV{HOME} # HOME环境下的目录路径
PROJECT_NAME # 工程名变量
<PKG>_INCUDE_DIR # 导入包头文件全路径
<PKG>_LIBRARIES # 导入库文件的权路径
PROJECT_SOURCE_DIR # 构建工程的全路径
CMAKE_VERSION # Cmake版本号
CMAKE_SOURCE_DIR # 源码树顶层路径
1
message([SEND_ERROR|STATUS|FATAL_ERROR] "message")

性能指标

  • 带宽MB/s,关心消息量,不管消息数
  • 吞吐量QPS,TPS
  • 延迟
  • 资源使用率

test

  • sysctl -A | grep tcp.*mem # 查看网络缓冲区

  • sysctl -A | grep range # 查看端口范围

  • ntptime # 查看ntp时间

  • ntpq -pn # ntp同步情况,service ntp start启动

  • nc # netcat $ nc ip port | [pipe]

  • tcpdumpWiretshark来性能分析

  • tcpcopy可以用来进行压力测试

  • strace

  • prove

  • perf # 查看程序的性能热点 e.g. perf record bin/memcached footprint ptmalloc 1000000 && perf report

  • netstat -tpna | grep :prot列出某服务客户端地址,netstatlsof找出进程发起的连接

  • nm,查看name mangilng

正确使用TCP

  • SO_REUSERADDR
  • ignore SIGPIPE
  • TCP_NODELAY

read

  • netcat

消息格式

  • Google Protocol Buffers

网络神话

Reactor和Proactor

  • Reactor模式指“non-blocking IO + IO multiplexing”,Proactor模式是另一个。
  • Recator的基本结构是事件循环(event loop)和事件驱动(event-driven)和事件回调实现业务逻辑,提高并发度和吞吐量,适合IO密集型横须
  • CPU密集型程序应该使用线程池,即blocking_queue实现的任务队列

    线程分配

  • 当线程很廉价时,创造多于CPU数目的线程,一线程处理一个TCP连接,通常使用阻塞Blocking IO
  • 当线程很宝贵时,创造跟CPU数目一样多的线程,一个线程处理多个TCP连接上的IO,即”non-blocking IO + IO multiplexing”
  • 进程指fork的产物,线程指pthread_create的宝贵的原生NPTL Pthread线程,每个线程由clone产生,对应内核的task_struct
  • 两种场合必须使用单线程:程序fork和限制程序的CPU占用率。此外,只有单线程能使用fork

    多线程的性能优势

  • 如果很少CPU负载让IO跑满,或很少IO负载就让CPU跑满,那么多线程没有性能优势
  • 多线程适用场景:
    • 多个CPU可用。
    • 线程间共享数据,或者也可进程间共享
    • 可修改的共享数据,或者也可进程间shared memory
    • 提供非均质服务,如处理优先级事件
    • lantency和throughput一样重要,即IO和CPU同样重要
    • 异步操作
    • scale up,能享受到多线程的优势
    • 可预测性能。超过临界点会性能下降,线程数量不随负载变化
    • 多线程划分责任和功能

C++编译链接模型精要

一些记录

  • C++三大约束:C兼容、零开销(与Rust的零成本抽象区别?)原则和值语义
  • 笼统地表示编译过程可分为:preprocessor/compiler/assembler/linker四个步骤,C++没有import或using(C++20可能出现),include头文件将导致当需要使用一个函数时预处理阶段必不可少的导入了一堆不相关的函数
  • 一些编译选项:-Wall、-Wextra、-Werror、-Wconversion、-Wshadow
  • 使用前向生命可以减少include,CCS规定不能重载&&、||、,三个操作符,Google规定不能重载一元operator&(),这样class就不能前向生命了
  • 判断一个C++可执行文件是release还是debug模式可以通过看class template的短函数有没有被inline展开,在nm命令中查看可以发现,开启-O2编译的程序是看不到inline函数的任何信息的
    1
    2
    3
    4
    class Foo;  // 前向生命
    void bar(Foo &foo) {
    Foo *p = &foo; // 取foo地址,重载了意思就变了
    }
  • C++的链接模型相比C多了一些内容,name mangling和vague linkage,即一个符号多份互不冲突。C中不允许重复定义

    一些名词

  • 一次定义原则(ODR),C是的,C++不是的

C++设计

  • POD和非POD
  • 三/五原则:POD类型需要拷贝赋值非平凡类型时,就需要析构函数,而需要析构函数的类也需要拷贝和赋值操作(需要拷贝操作的类也需要赋值操作),否则使用编译器合成的将导致未定义行为或多重析构的危险

  • 程序迁移工具:Porting Advisor,从X86(CISC)到arm kunpeng(RISC)
  • 数据库测试工具:BenchmarkSQL安装ant -> 创建配置文件 -> 配置数据库连接 -> 场景配置 -> 数据准备 -> 执行测试
    • 数据库连接:db、driver、conn、user/password
    • 场景配置:warehouse仓库数量、loadWorkers数据并发数、Terminals并发用户数、runMins测试时间、runTxnsPerTerminal、limitTxns。。。
  • 大数据测试工具套件:HiBench:评估框架速度、吞吐量和系统资源利用率
    • 测试类别:micro、ml、sql、websearch、graph、streaming

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$(VIM_FILEPATH)      #具有完整路径的当前缓冲区的文件名。
$(VIM_FILENAME) #当前缓冲区的文件名,不带路径。
$(VIM_FILEDIR) #当前缓冲区的完整路径,没有文件名。
$(VIM_FILEEXT) #当前缓冲区的文件扩展名。
$(VIM_FILETYPE) #文件类型(在vim中为&ft的值)
$(VIM_FILENOEXT) #当前缓冲区的文件名,不带路径和扩展名。
$(VIM_PATHNOEXT) #当前文件名,具有完整路径,但没有扩展名。
$(VIM_CWD) #当前目录(由:pwd返回)。
$(VIM_RELDIR) #文件路径相对于当前目录。
$(VIM_RELNAME) #文件名相对于当前目录。
$(VIM_ROOT) #项目根目录。
$(VIM_CWORD) #光标下的单词。
$(VIM_CFILE) #光标下的文件名。
$(VIM_CLINE) #当前缓冲区
$(VIM_GUI) #有('gui_runnin')吗?
$(VIM_VERSION) #诉价值:版本。
$(VIM_COLUMNS) #当前的屏幕宽度。
$(VIM_LINES) #当前的屏幕高度。
$(VIM_SVRNAME) #诉值:服务器。
$(VIM_PRONAME) #当前项目根目录的名称
$(VIM_DIRNAME) #当前目录的名称
$(VIM_INIFILE) #当前ini(.tasks)文件的完整路径名。
$(VIM_INIHOME) #当INI文件所在。

1
2
3
4
cd /var/lib/rpm # rpmdb所在目录
rm -f __db.* # 清除原rpmdb文件
rpm --rebuilddb # 重建rpm数据库
yum clean all # 清除所有yum的缓存

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
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
// 安装git版本控制工具
$ sudo apt-get install git // apt get
$ sudo apt-get install git-core // outdate
$ sudo yum install git // yum

// 指定用户和Email地址
$ git config --blobal user.name "Your Name"
$ git config --global user.email "email@example.com"

// Git显示颜色
$ git config --global color.ui true

// 配置命令别名
$ git config --global alias.<order_name> <previous_name>
// $ git config --global alias.st status
// $ git config --global alias.last 'log -l'
// git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

// 查看配置信息
$ git config --list

// 初始化管理仓库
$ git init /Users/michael/learngit/.git/

// 将文件添加到暂缓区
$ git add <file>

// 将文件从暂缓区提交到git仓库
$ git commit -m <message>

// 查看当前git状态
$ git status
// e.g. $ git status -s

// 查看文件是否有新改动
$ git diff <file>
// e.g. $ git diff --staged
// e.g. $ git diff --cached

// 查看修改日志
$ git log
// e.g. git log --pretty=oneline --abbrev-commit
// e.g. git log -p -2 // -p查看修改差异
// e.g. 还可以定制输出格式
$ git log --pretty=format:"%h - %an, %ar : %s"
/*
%H: 提交对象(commit)的完整哈希字串
%h: 提交对象的简短哈希字串
%T: 树对象(tree)的完整哈希字串
%t: 树对象的简短哈希字串
%P: 父对象(parent)的完整哈希字串
%p: 父对象的简短哈希字串
%an: 作者(author)的名字
%ae: 作者的电子邮件地址
%ad: 作者修订日期(可以用 --date= 选项定制格式)
%ar: 作者修订日期,按多久以前的方式显示
%cn: 提交者(committer)的名字
%ce: 提交者的电子邮件地址
%cd: 提交日期
%cr: 提交日期,按多久以前的方式显示
%s: 提交说明
*/

// 返回到上一个版本
$ git reset --hard HEAD^
// e.g. HEAD^^表示上上个版本,HEAD~100返回上100个版本

// 通过指定SHA-1编码恢复版本
$ git reset --hard <code>
// e.g. git reset --hard 1094a

// 查看每一次命令的记录
$ git reflog

// 查看工作区和版本库里最新版本的区别
$ git diff HEAD -- <file>
// e.g. git diff HEAD -- what.cpp

// 将暂存区的修改撤销掉,放回工作区
$ git reset HEAD <file>

// 丢弃工作区的修改
$ git checkout -- <file>

// Git中对文件改名
$ git mv <pre_name> <cur_name>
/* 相当于
$ mv a.left a.right
$ git rm a.left
$ git add a.right
*/

// 删除文件
$ git rm <file>
// e.g. 放到暂存区的要用 git rm -f <file>

// 克隆文件
$ git clone git@github.com:<user>/<Repository_name>.git

// 创建分支,然后切换到该分支
$ git checkout -b <branch_name>
// 相当于以下两条指令
$ git branch <branch_name> // 创建分支
$ git checkout <branch_name>// 选择该分支

// 查看分支
$ git branch
// e.g. git branch -v // 查看每个分支最后一次提交

// 删除分支
$ git branch -d <branch_name>

// 将分支的结果合并到master分支上
$ git merge <branch_name>
// e.g. 合并分支请注意--no-ff参数,表示禁用Fast forward;以普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来了
// e.g. $ git merge --no-ff -m "merge with no-ff" dev

// 查看分支的合并情况
$ git log --graph --pretty=oneline --abbrev-commit

// 如果用户主目录没有.ssh目录、id\_rsa和id\_rsa.pub就创建SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"

// 远程分支它以(remote)/(branch)形式命名

// 关联origin远程库
$ git remote add <remote> git@github.com:<user>/<Repository_name>.git
github仓库
$ git remote add <name> <user>@<Ip_address>:/warehouse/<Repository_name>.git // 个人服务器示例(SSH)
// e.g. origin也可以改成别的,不是固定
// e.g. $ git remote add origin git@github.com:example/test.git

// 远程仓库重命名
$ git remote rename <pre_remote> <cur_remote>

// 远程仓库的移除
$ git remote rm <remote>

// 删除远程分支
$ git push origin --delete <remote-branch>

// 查看远程库的信息
$ git remote -v
// e.g. master dev bug feature

// 查看远程仓库信息
$ git remote show <remote>

// 获得远程引用的完整列表
$ git ls-remote <remote>

// 将本地库的内容推送到远程库上
$ git push -u origin master
// e.g. master是指其中一个branch.可以通过serverfix:awesomebranch方式来将本地的serverfix分支推送到远程仓库上的awesomebranch分支
$ git push origin master:serverfix

// 从远程仓库抓取分支(分离状态的)
$ git fetch <remote> <branch>
// e.g. 本地不会生成可编辑的副本.它不会有serverfix分支,只有一个不可修改的origin/serverfix指针

// 从远程仓库获取并建立<branch>分支
$ git fetch <remote> <remote-branch>:<local-branch>
// e.g. git fetch origin master:test
// e.g. git diff tmp // 对比分支
$ git checkout -b serverfix origin/serverfix
$ git checkout --track origin/serverfix

// 从远程库获取最新版本并merge到本地
$ git pull <remote> <branch>
// e.g. 需要指定本地分支与远程origin/分支的连接.以下以dev分支为例
// $ git branch --set-upstream-to=origin/dev dev

// 比较本地master分支和origin/master分支差别
$ git log -p master ..origin/master

// 将stash储藏起来,等以后恢复stash(dirty)
$ git stash

// 查看stash列表
$ git stash list

// 恢复stash
$ git stash apply

// 恢复指定stash
$ git stash apply stash@{0}

// 删除stash
$ git stash drop

// 恢复stash的同时删除stash内容
$ git stash pop

// 尝试重新应用暂存的修改
$ git stash apply --index

// 不要储藏任何已经通过git add暂存的东西
$ git status -s
$ git status --keep-index

// 储藏任何创建的未跟踪的文件
$ git stash --include-untracked
$ git stash -u

// 交互式提示哪些改动想要储存,哪些改动想要保存工作目录中
$ git stash --patch

// 从储藏创建一个分支
$ git stash branch <branch>

// 变基
$ git rebase
// 跳过server分支,将client分支与master分支合并
$ git rabase -onto master server client
// e.g. 以上命令意思是:"取出client分支,找出处于client分支和server分支的共同祖先之后的修改,然后把他们放在master分支上重放一遍."
$ git rebase master server
// 以上命令可以直接将特性分支变基到目标分支上,即是说,把server分支续到master分支之后,省去得先切到server分支

// 打标签
$ git tag <tag_name> [commit_id]
// e.g. git tag v1.0
// e.g. 再加一个参数是对应的commit id打上标签
// e.g. git tag v1.0 f52c633
// -m 指定说明文字 -a指定标签名

// 查看所有标签
$ git tag

// 查看标签信息
$ git show <tag_name>

// 查看标签所指文件版本
$ git checkout <tag_name>
// e.g. 这会使你的仓库处于分离头指针(detached HEAD)状态.也就是说任何修改标签都不会变化,不属于任何分支,也无法访问.
// e.g. 因此要么在初始阶段创建新分支关联,要么在切走分支时,和提交校验码git branch关联.否则将会丢失它
$ git checkout -b version2 v2.0.0
$ git branch version2 XXXXXXX

// 删除标签
$ git tag -d <tag_name>

// 推送某个标签到远程
$ git push origin <tag_name>

// 一次性推送全部尚未推送到远程的本地标签
$ git push origin --tags

// 删除远程标签
$ git tag -d <tag_name>
$ git push origin :refs/tags/<tag_name>

// 添加被.gitignore忽略的文件:
$ git add -f <file_name>

// 检查.gitignore文件规则
$ git check-ignore -v <file_name>

// 删除工作目录
$ git clean
-n // 提示将要删除什么文件
-d // 移除文件
-x // 不忽略.gitignore文件规则删除所有
-i // 交互式提醒
创建一个运行git的服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 在远程服务器安装git
$ apt-get -y install git

// 创建git用户并输入密码,用来运行git服务
$ adduser git && passwd git

// 导入公钥到authorized_keys文件里

// 选定一个目录作为Git仓库,在目录下创建裸(bare)仓库
$ git init --bare example.git

// 把.git文件的owner改为git:
$ chown -R git:git example.git

// 禁用git用户登录shell
$ vim /etc/passwd
// e.g. 将git条目后的/bin/bash改成/usr/bin/git-shell,这样git用户可以通过ssh使用git但是无法登录shell
忽略特殊文件
1
2
3
4
5
6
7
// 通过在Git工作区根目录下创建特殊文件.gitignore文件,可以把要忽略的文件名填进去,Git会自动忽略这些文件
/*
忽略文件原则是:系统自动生成文件
编译生成的中间文件
可执行文件
带有敏感信息的配置文件
*/

gitignore文件

变基

rebase

rebase和merge的区别就在于:

merge会把两个分支的最新快照分别于它们的共同祖先比对,将拼接出合并的结果,然后生成一个新的快照并提交.

rebase先找到两个分支的最新快照的共同祖先对比其中某一分支,找出经修改的地方存储为临时文件,并将它指向另一分支(基底),并依偎基底将修改应用一次.完成合并.这就是”重放”??