Git 拾遗

.git文件目录

➜  .git git:(V.12.0) ls -l
total 1440
-rw-r--r--    1 raojunbo  staff      26 12 15 15:40 COMMIT_EDITMSG
-rw-r--r--    1 raojunbo  staff    1573 12 18 19:12 FETCH_HEAD
-rw-r--r--    1 raojunbo  staff      23 12 18 19:12 HEAD
-rw-r--r--    1 raojunbo  staff      41 12 18 19:12 ORIG_HEAD
-rw-r--r--    1 raojunbo  staff     551 12 12 12:56 config
-rw-r--r--    1 raojunbo  staff      73 11 30 11:39 description
-rw-r--r--    1 raojunbo  staff  311844 12 20 22:54 gitk.cache
drwxr-xr-x   13 raojunbo  staff     416 11 30 11:39 hooks
-rw-r--r--    1 raojunbo  staff  391258 12 20 22:48 index
drwxr-xr-x    3 raojunbo  staff      96 11 30 11:39 info
drwxr-xr-x    4 raojunbo  staff     128 11 30 11:42 logs
drwxr-xr-x  256 raojunbo  staff    8192 12 14 14:58 objects
-rw-r--r--    1 raojunbo  staff    1536 11 30 11:42 packed-refs
drwxr-xr-x    5 raojunbo  staff     160 11 30 11:42 refs
  • HEAD 文件
    存有当前分支的头指针。在切换分支的时候,会跟随分支的变化而变化。当然也可以不与分支挂钩,直接指向一个处理分支状态(任意指向的)也可以。

  • config 文件

    git config -l命令的内容

  • ORIG_HEAD 文件

  • FETCH_HEAD 文件

  • object目录
    对象集,block ,commit,tree,tags;

  • refs

git内部的命令
查看hash所代表的对象类型 `git cat-file -t 005642f3c41eecb8c56b8b77c4f100f1575ccf54

查看hash所代表的对象实际内容git cat-file -p 005642f3c41eecb8c56b8b77c4f100f1575ccf54

commit,tree,block关系

gitbloctree

blob实际就是真实的文件
tree实际就是目录
commit是git里的东西是一个包含“根tree”的东西。commit里有parent(父commit),author(作者),committer(提交者)

分离头指针情况的注意事项(没有与branch进行关联)

➜  GitTestDir git:(master) git checkout 552aa3eba30936d5c4ecf148b38d0cbc89221fbc 
Note: checking out '552aa3eba30936d5c4ecf148b38d0cbc89221fbc'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b <new-branch-name>

HEAD is now at 552aa3e add sty
➜  GitTestDir git:(552aa3e) 

直接切换到一个指定的commit号,直接进入工作后,进行提交,如果在checkout 到其它分支,就会出现分离头指针,也就是没有基于某个分支。在后期,分支的指针会自动被清理掉。

git diff HEAD HEAD^ //head与父亲进行对比
git diff HEAD HEAD^ //head 与父亲的父亲进行对比
git diff HEAD HEAD~1 //head 与父亲进行对比

修改commit的message

对最近一次的message做修改
git commit --amend

rebase操作

修改以往的任何一个commit的message(rebase)

示例

commit3
commit2
commit1

我现在要,修改commit2,那么我就是git rebase -i commit1;以commit1作为基准,去修改其后面的commit信息。
rebase 命令的交互命令里有拿出commit,重新设置messge等操作。
修改后commit的commit号会发生变化。

合并以往的连续的几个commit(rebase)

示例

commit4
commit3
commit2
commit1

合并commit2,与commit3为commit5;这样就会形成一个新的commit;

合并以往的不连续的commit(rebase)

其实与前面一样,只是,列出commit ,然后描述命令

diff操作

  • 比较工作区,索引区,HEAD的差异
    git diff --cached 比较索引区域HEAD的差别比较
    git diff 工作区与索引区的差别

  • 比较不同分支的同一个文件的差异

git diff temp master -- filename
temp是一个分支或者commitid,master是一个分支或者commitid;

恢复工作区,恢复索引区

  • 清空工作区

git checkout file
git checkout .

  • 将加入索引的放入工作区

git reset HEAD

  • 清除最近的几个commit

git reset --hard commitid

删除,重命名文件

  • 重命名文件 git mv filename1 filename2
  • 删除文件 git rm filename

ignore文件

.gitignore告诉哪些不需要加入git的管理里

2018/12/21 posted in  Git工具

C语言拾遗

一:编译

不同的CPU制造商使用的指令系统和编码格式不同。例如Intel Corei7与ARM采用的就是不同的指令集。在编译时,编译器就需要将C语言编译成相应CPU的机器码。

补充说明:汇编语言是为特殊的CPU设计的一系列内部指令,是用助记符号表示,不同的CPU使用不同的汇编指令,就像C语言编译器编译成机器指令

C语言标准定义,C89,C99,C11(2011)等标准,而这种标准实际上是一种抽象。具体的实现是由相应的编译器解释。

编译流程,把源代码文件转换为可执行文件,具体是首先把源代码转换成中间代码(这个中间代码是没有连接其他模块的代码,因为这个中间代码可能用到了其他模块的函数,这个模块可以是其他模块也可是标准库),连接器把中间代码和其他代码合并(这个合并的过程就是连接的过程,是模块之间能正常找到调用),最终生成可执行文件。

GNU编译合集,LLVM项目分别是连个开源编译合集。都支持C的编译,在苹果系统目前采用LLVM项目里的Clang来编译C程序。

哈哈,从上述的整理,终于理解了Xcode里的Architectures(CPU架构),FrameSearchPath,Header SearchPath,Library SearchPath,Apple Clang的编译选项设置。

makefile的编译

在编译一个开源的C库时,比如Objectc的runtime,编译FFmpeg的库时,都会用到makefile文件来进行构建。

make通常被视为一种软件构建工具,是一个命令行工具。该工具主要经由读取一种名为“makefile”或“Makefile”的文件来实现软件的自动化建构程序。makeFile有其自己的语法。

  • 文件包含

include 的实质:实际上是相当于把stdio.h文件中的所有内容都输入该行所在的位置。

预处理

#define PI 3.13444
//带固定参数个数的宏
#define Men(X,Y) ((X)+(Y))  
//可变参数个数的宏
#define PR(...) printf(__VA_ARGS__) //可变参数的宏
PR("Howdy");
PR("weight=%d, shipping=%d",wt,sp);
//文件包含
#include
当预处理器发现#include指令时,会替换源文件中的include指令。
(相当于把被包含的文件的全部内容输入到源文件#include指令所在的位置)
要深度的理解这句话的含义,包含,就是将代码实现替换到这。
头文件提供函数声明或者原型,库选项(也就是真正的库)告诉系统到哪里查找函数代码,或者是到源文件里查找代码。
  • 区分宏定义的函数与函数区别

宏每调用一次,都会展开一次,是一种内联。而函数的调用。是会在一段函数指令里执行一次又一次。

条件编译

#define
#ifdef
#else
#endif
#ifndef
#if
#elif

预定义宏

C标准规定了一些预定义宏
__LINE__
__FILE__
__func__

完整项目多文件编译

二:指针的概念

从核心的去理解指针,就是一个地址值,一个变量的地址值。一个数组的首原始地址值。一个函数代码段的开始地址值。
指针的操作,是根据他们指向的数据的所占空间的大小来操作的。指向整数时,p+1,就是指向下一个整数。

int *p1 //指向int的指针变量(理解成一个整形变量的地址)
double *p2;
  • 指针的应用

有时候,在函数外有个数组,想通过,这个函数修改数组里的值,要将整个修改逻辑放在这里。就需要传地址。(但外面是一个结构体时,有时遇到需要通过一个函数修改这个结构体的值,也会采用传地址的方式)。这是一个非常典型的应用场景。

//在采用传地址时,不允许修改这个数组的内容的值时,可以添加const。
//const修饰指针时,表示内容不允许修改
int sum (const int ar[],int n);
int sum (const int ar[],int n) {
    int i;
    int total = 0;
    for (int = 0;i<n;i++){
        total =+=ar[i];
    }
    return total;
}
  • const修饰的区别的理解
const double *pd1;
double *const pd2;

要区分这两个含义,要从本质上理解,pd1的const修饰的是double *pd1,也就是这个指针变量,这个整体是值。也就是值是常量。
而,pd2的const修饰的pd2这个地址。是这个指针。也就是指针是常量

int val = 10;
const double *pd1 = &val;
*pd1 = 20;//不允许(因为修改了指针所指向内容的值)
double rate[] = {10,20,30};
double *const pc = rate;
 pc = &rate[2];//不允许(因为是修改了指针的值)

哈哈,终于里理解了这个东西。

指针与object的关系

指针与NSObject的关系,要从C的内存管理角度去思考。

指针与数组的关

指针指向的就是数组的首地址。

指针与函数

指向函数的指针中存储着函数代码的起始地址。

void func (char *);
void (*pf) (cahr *);
pf 即是指向函数的指针
void ToUpper(char *);
void ToLower(char *);
pf = ToUpper;//将函数地址赋值给函数指针
pf = ToLower;//将函数地址赋值给函数指针
(*pf)("nihao");//调用函数

三:C中的字符串

  • 字符串常量

这个字符串在编译的时候就已经确定。所以是在静态存储区。

char *str = "nihao";
//实际上"nihao"是一个字符数组。一个在末尾加了\0元素的字符数组。
  • 数组形式指针形式的不同

字符串常量是在编译时就确定好的在静态存储区。

const char ar[] = "something1";
const char *p = "something2";

对比说明:
"something1"是一个字符串常量,在给ar[]赋值时会将其拷贝到这个数组里。
"something2"是一个字符串常量,在静态存储区,在给*p赋值时,直接将静态区字符串的地址值给它。因为它是一个常量,内容没法修改,所以通常在前面加一个const;

四:C的内存管理

三个维度描述变量
链接
作用域
存储区

链接,作用域描述变量的可见性
存储区,描述变量的存储位置

  • 外部变量

(在一个源文件里,在所有函数之外的变量),作用域是本文件,存储是静态存储,链接默认是外部链接,如果用static修饰,就是内部链接。

  • 局部变量

    在块,函数里的是局部变量,作用域是块或者函数内,存储默认是栈上,链接是内部链接。但若用static修饰,就是存储在静态区。

extern 申明这个源文件使用了外部变量。(哈哈,这里才是extern的本质)

动态内存分配

思考:为什么会有动态内存分配?
在我们的编译,执行时,根据已经制定好的内存管理规则,将自动选择作用域与存储区,自己管理内存(静态数据编译时分配,自动数据在执行时分配)。但,我们也可以程序员自己申请内存,自己释放内存,就是动态内存的分配。

五:结构体

结构体在实际的应用中相当重要。一些重要的库的数据描述都是用结构体表示。与结构体指针一同构建起一个大的程序库。比如objc-runtime,ffmpeg库。

struct book {
    char title[10];
    char author[20];
    float value;
} abook;
book 是类型,abook是变量名

将结构体类型当做普通的变量类型就可以了。

struct book aBook;  //结构变量
struct book *b;     //指向结构的指针
aBook.value;//取值
b->value;//取值
  • 结构体了字符数组与字符指针表示的区别
struct names{
    char first[10];
    char last[10];
}
struct pnames {
    char *first;
    char *last;
}

names占用20字节,pnames占用16字节。
names的本身存储位置是在它自己申请的位置。
pnames的first,last存存储在别处。用的时候要特别小心。

示例结构体内部字符指针表示的用法。(很重要)
下面是将结构体力的变量设置成字符指针。因为没有地方存储实际的值,所以需要用动态创建内存。

struct namect {
    char *fname;
    char *lname;
}

void getinfo(struct namect *pst){
    char temp[20];
    scanf("%s",tmp);//将输入的暂时存入tmp
    pst->fanme= (char *)malloc(strlen(temp)+1);//动态创建一个空间
    strcpy(pst->fname,temp);//将tmp的拷贝到动态空间
}

六:抽象数据接口

链表
队列

结语:至此关于C的一些核心概念就都搞清楚了。

七:示例

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SLENGTH 80

struct namect {
    char *fname;
    char *lname;
    int letters;
};

typedef struct namect NAMEct;
//以下都是函数声明
//将结构体指针作为参数传递

void getinfo (struct namect *);
void makeinfo (struct namect *);
void showinfo (const struct namect *);
void cleanup (struct namect *);

char * s_gets(char *st ,int n);

int main () {
    NAMEct person;

    getinfo(&person);
    makeinfo(&person);
    showinfo(&person);//显示信息
    cleanup(&person);//调用该函数时释放内存
}

void getinfo (struct namect *pst){
    char temp[] = "naihao";
    char temp2[] =  "naihao2";

    pst->fname = (char *) malloc(strlen(temp) +1);//申请内存
    strcpy(pst->fname,temp);//将字符拷贝到生成的内存中

    pst->lname = (char *) malloc(strlen(temp2) +1);//申请内存
    strcpy(pst->lname,temp2);
}


void makeinfo (struct namect *pst){
    pst->letters = strlen(pst->fname) + strlen(pst->lname);
}

void showinfo(const struct namect *pst){
    printf("firstName:%s secondName:%s letters:%d",pst->fname,pst->lname,pst->letters);
}

void cleanup (struct namect *pst){
    free(pst->fname);//释放内存
    free(pst->lname);//释放内存
}



2018/12/11 posted in  C语言捡漏

shell脚本知识梳理(八)文本处理

文本处理带真正用到时再研究吧。

2018/12/9 posted in  shell脚本

shell脚本知识梳理 (六)函数

函数

#!/bin/bash
function testFunc(){
    echo $1:$2
    return 100;
}

echo "调用前"
testFunc "rao" "jun";
echo "返回结果$?"
echo "调用后"

函数的传参数与在命令里的传参数基本相同。返回值用$?记录上次函数的返回值。

2018/12/9 posted in  shell脚本

shell脚本知识梳理(零)linux 基础命令

shell的基础命令,列出已经掌握的基本命令

linux的文件权限

-rwxr--r--  1 raojunbo  staff   159 12  8 17:20 file2.sh

chmod 改变文件的权限
chown 改变文件所有者
chgrp 改变文件所属用户

Linux的文件与目录管理

ls 列出文件及目录列表
cd 进入目录
pwd 显示文件路径
touch 创建新文件
file 查看文件类型

目录操作

mkdir
rmdir

文件操作

cp
rm
mv

查看文件

cat
more
less
head
tail

查找文件名

whereis
locate
find

2018/12/9 posted in  shell脚本

shell脚本知识梳理(七)SQL应用处理

导出.cvs格式

2018/12/8 posted in  shell脚本

shell脚本知识梳理(五)输出

echo

printf 格式化输出

[TOC]
- 区别一
print不会自动换行
echo 会自动换行

  • 区别二 print 用于格式打印 echo 用于标准的输出
printf "%-4s%-8s%-4s\n" 姓名 性别 体重
printf "%-4s%-8s%-4s\n" raoraoraorao 男 120
printf "%-4s%-8s%-4s\n" jun 女 130
printf "%-4s%-8s%-4s\n" bo 女 140

格式化输出 "s"表示字符串,一个宽度是10的字符,如果超出也显示,不足10用空白不齐,”-“表示左对齐。

管道

将一个命令的输出做威另一个命令的输入

重定向输出

原来是重定向到控制台输出,现在是重定向输出到文件

文件重定向
以控制台为参照
系统已经存在的文件描述符0(标准输入即键盘),1(标准输出即控制台),2(标准错误),其他是可自定义的文件描述符

白话理解cat命令行重定向
原来是从键盘输入,现在是从文件输入
cat 命令直接输入cat命令,从键盘输入,然后在控制台输出。
cat file 采用cat接收一个非STDIN文件输入,即将输入变成从文件读取
特别说明

重定向不限制于cat命令,任何命令都可以。
就是将一个命令的输出重定向到其他文件或者标准输出。在一个命令的输入时,也可以从一个文件或者标准输入作为输入,即输入重定向

“> ” 重定向输出到一个文件
">>" 重定向输出到一个文件并且是追加到后面

命令行里的输入与输出重定向

案例一:重定向错误输出到一个文件中
当我们的命令发生错误时,shell并不会将错误重定向到输出的重定向文件。重定向时要写上文件描述符

ls -al fileC 2> errfile.sh 

案例二:将正确信息重定向到一个文件,将错误信息重定向到一个文件

ls -al fileA.sh fileC.sh 2> errfile.sh 1> fileD.sh

案例三:将正确与错误输入到同一个文件

ls -al fileA.sh fileC.sh &>  fileD.sh 

脚本文件里的输入与输出重定向

要想在脚本文件里指定文件的输入与输出重定向,需要对这个要输出的内容做标记。告诉要输入或者输出到哪个文件。那么这个文件的描述符就需要在脚本里写出

  • 临时重定向 这里的&2是一种标记,标记其内容将会进入那个重定向,因为只起到临时标记的作用。所以叫临时重定向。这里的临时,永久是在脚本文件里告诉,命令的输入与输入。也就是在脚本文件里告诉有输出,有输入的一个流。
# 临时重定向 在一个shell脚本里,将一个输出设置成临时重定向

echo "hello owrk" >&2;
echo "你好" >&2;
  • 永久重定向 这里的永久重定向,说白点就是一次性标记。
exec 1> fileContent.sh
echo "hello world"
echo "你好"

# 更改为重定向
exec 2> errorfile.sh
echo "我报错了" >&2   
# 将我报错了进行标记 
exec 0< fileContent.sh
# 读物文件的所有行
count=1;
while read line  
do
echo "读取的内容${line},行数${count}";
count=`expr $count + 1`;
done

自定义文件描述符

  • 创建文件读写描述符号示例
#创建文件的读写描述符
exec 3<> fileContent.sh

#读取文件中的一行数据
read line <&3

#打印数据
echo "读取数据:"$line;
echo "哈哈,看写入文件了没wwwww有" >&3
  • 关闭文件描述符 关闭文件描述符后,不能写入文件

exec 3>&-

  • 恢复文件描述符(这个很难理解,实际上是一个暂存)
# 创建一个文件描述符3,执行原有文件描述符1,也就是是控制台输出
exec 3>&1;

# 创建文件描述符1,重定向到一个文件
exec 1> fileContent.sh

echo "工作1";

echo "工作2";

# 将1重定向到预先保存的控制台输出,所左这之后会输出都屏幕,也就是恢复了
exec 1>&3
echo "完成了";

修改输入并恢复输入
exec 6<&0;
exec 0< fileContent.sh

# 系统还是会从0所指向的文件进行读取,输出还是原有的输出
while read line 
do
 echo "文件内容${line}"
done

exec 0<&6;

echo "读取完成";

总结

0,1,2,是系统默认已经指定了的文件描述符,分别指向键盘文件,控台台文件,错误文件。exec的本质是在一个进程里创建一个文件描述符。在shell脚本里可以创建文件描述符指定特定的文件进行输入与输出。
文件描述符的理解,文件描述符只是一个符号

2018/12/6 posted in  shell脚本

shell脚本知识梳理(三) 流程控制

if语句

这里的条件就是上节说的test命令的参数

if [ 条件 ]
then
    代码
fi
if [ 条件]
then
    代码
else
    代码
fi
if [ 条件 ]
then
    代码
elif [ 条件 ]
then
    代码
fi

for语句

for 变量名 in item1 item2 item3
do
    代码    
done
for name in "rao" "jun" "bo"
do
    echo ${name}
done    
//列出当前目录所有文件(用的for in)
file=`pwd`/*;
for name in ${file}
do
    echo ${name}
done
//for 的c形式
for (( i = 0; i < 10; i++ )); do
    echo $i;
    for (( j = 0; j < 10; j++ )); do
        echo $j;
    done
done
//一个一个显示文件列表
for i in `ls `
do
echo "这是文件${i}";
done

while

while [] 
do

done
//示例
var=10;
while [ ${var} -gt 0 ];
do
echo $var;
var=`expr ${var} - 1`;
done

switch case

number=1
case $number in
    1) echo "等于1";;
    2) echo "等于2";;
esac
2018/12/6 posted in  shell脚本

shell脚本知识梳理(二)test命令的条件

算术运算

a=1;
b=2;
c=`expr ${a} + ${b}`;
d=`expr ${a} - ${b}`;
e=`expr ${a} \* ${b}`;
f=`expr ${a} / ${b}`;
echo $c;
echo $d;
echo $e;
echo $f;
a=1;
b=1;

if [ ${a} != ${b} ]
    then
    echo "a不相等b"
fi


if [ ${a} == ${b} ]; then
    echo "a相等b"
fi
a=100;
b=200;
val=`expr $a + $b`;//这个算是最标准的写法吧
echo $val;
a=100;
b=200;
val=$(expr $a + $b);
echo $val;
a=100;
b=200;
val=$[ $a + $b ];
echo $val;

特别说明,上述的拿到一个命令的输出值用一个变量去接收。可以有三种写法。但通常还是低一种写法
特别说明expr即运算表达式计算命令。在命令行里可以直接执行。实际上expr永远不止,运算表达式。里面也可以是关系表达式,逻辑表达式,字符串表达式。只不过shell的的运算比较弱,需要借助这个命令行工具来实现计算。

算术运算bc(浮点解决方案)

在做运算时,可以用expr也可以用bc计算器。bc实际是一个专门的命令。在脚本中,将其当做普通命令就可以了,即使用命令替换就可以得到结果。bc 的输入实际是一个表达式.

bc基本用法

bc计算器
数字,整数,浮点数
示例
直接在命令行输入:bc命令,然后进行计算
解释一下bc命令:在shell脚本语言中提示符下通过bc命令访问bc计算。相当于打开计算器。

quit退出计算器

  • bc 在脚本中的应用
val1=1.314;
val2=0.618;
val3=`echo "$val1 * $val2" | bc`;
val4=`echo "$val3 * $val2" | bc`;
echo $val4;
  • bc的输入重定向之打包计算
val=$(bc << fg
    options
    statements
    expression
    fg
)
val1=1.314;
val2=0.618;
val3=100;
val4=100;
val=$(bc << fg
    a=($val1 *$val2)
    b=($val3 *$val4)
    a * b
    fg
)
echo "val结果:${val}";

数值比较运算

特别说明
这里说的数值运算,布尔运算,逻辑运算,字符串比较运算,文件测试运算实际上都是test命令的条件参数,实际就是test 条件参数的返回结果,在分支语句中都是通过test来计算的。只不过为了简便,分支语句将test 用[] 等替换了。

-eq 检测两个数是否相等(equal);
-ne 检测两个数是否相等(not equal),不相等时返回true;
-gt  检测左边的数是否大于右边的数(greater)
-lt 小于
-elt 小于等于(equal or less than)

布尔运算

! 非运算
-O 或运算(or)
-a 与运算(and)
a=10;
b=20;
if [ $a != $b ]
    then
    echo "a 于b 不相等";
fi
if [ $a -lt 100 -a $b -gt 15 ]
    then
    echo "$a 小于100,并且$b 大于15";
fi

逻辑运算

&&逻辑且
||逻辑或

a=10
b=20

if [[ $a -lt 100 && $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi

字符串运算符

= 两字符串是否相等,相等返回true
!= 两字符串是否相等,不相等返回true
-z 字符串长度是否为0(zero)
-n 字符串长度是否为0

文件测试运算符

屏幕快照 2018-12-06 11.47.58

2018/12/6 posted in  shell脚本

shell脚本知识梳理(四)输入

文件包含

文件包含进来后,当执行这个脚本时都会执行

  • 方式一 #!/bin/bash ./fileA.sh //文件路径 echo "我是文件B"
  • 方式二
source fileA.sh  //文件路径

cat

read

read 输入读取单行数据

  • 方式一
#!/bin/bash
echo "请输入名字";
read name;
echo "您的名字"${name};
  • 方式二(带输入提示,带输入超时时间)
#!/bin/bash

read -p "请输入您的名字" name;
echo "您的名字"${name};
if [ `read -t 3 -p "请输入您的名字" name` ]
    then
    echo ${name}
else
    echo "超时";
fi
  • 方式三(隐藏输入)
read -s  -p "请输入您的名字" name
echo ${name}

这里在实践的过程中,发现条件命令。等有时写不正确,也就是在一些控制语句,[] 里的条件。

2018/12/6 posted in  shell脚本