使用git Rebase让历史变得清晰,合并git历史

当多人协作开发一个分支时,历史记录通常如下方左图所示,比较凌乱。如果希望能像右图那样呈线性提交,就需要学习git rebase的用法。

“Merge branch”提交的产生

我们的工作流程是:修改代码→提交到本地仓库→拉取远程改动→推送。正是在git pull这一步产生的Merge branch提交。事实上,git pull等效于get fetch origin和get merge origin/master这两条命令,前者是拉取远程仓库到本地临时库,后者是将临时库中的改动合并到本地分支中。

要避免Merge branch提交也有一个“土法”:先pull、再commit、最后push。不过万一commit和push之间远程又发生了改动,还需要再pull一次,就又会产生Merge branch提交。

使用git pull –r
修改代码→commit→git pull –rebase→git push 也就是将git merge origin/master替换成了git rebase origin/master,它的过程是先将HEAD指向origin/master,然后逐一应用本地的修改,这样就不会产生Merge branch提交了。具体过程见下文扩展阅读。

使用git rebase是有条件的,你的本地仓库要“足够干净”。可以用git status命令查看当前改动::

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

本地没有任何未提交的改动,这是最“干净”的。稍差一些的是这样:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
  (use "git add <file>..." to include in what will be committed)
    test.txt
nothing added to commit but untracked files present (use "git add" to track)

即本地只有新增文件未提交,没有改动文件。我们应该尽量保持本地仓库的“整洁”,这样才能顺利使用git rebase。特殊情况下也可以用git stash来解决问题,有兴趣的可自行搜索。

修改git pull的默认行为

每次都加–-rebase似乎有些麻烦,我们可以指定某个分支在执行git pull时默认采用rebase方式:

$ git config branch.master.rebase true

如果你觉得所有的分支都应该用rebase,那就设置:

$ git config --global branch.autosetuprebase always

这样对于新建的分支都会设定上面的rebase=true了。已经创建好的分支还是需要手动配置的。

扩展阅读[1]:git rebase工作原理

在做项目开发时会用到分支,合并时采用以下步骤:

$ git checkout feature-branch
$ git rebase master
$ git checkout master
$ git merge --no-ff feature-branch
$ git push origin master

历史就成了这样:
转载自 http://www.cnblogs.com/UnGeek/p/5737653.html

git push 401错误,安装新版的git

解决git clone时报错:The requested URL returned error: 401 Unauthorized while accessing

版本问题,最直接的解决办法就是重新编辑安装git吧:

下载安装源码

下载:wget -O git.zip https://github.com/git/git/archive/master.zip
解压:unzip git.zip
进入git目录:cd git-master

编译安装:

autoconf
./configure --prefix=/usr/bin/git
make
/usr/bin/perl Makefile.PL PREFIX='/usr/bin' INSTALL_BASE='' --localedir='/usr/bin/share/locale'
Can't locate ExtUtils/MakeMaker.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at Makefile.PL line 3.
BEGIN failed--compilation aborted at Makefile.PL line 3.
make[1]: *** [perl.mak] 错误 2
make: *** [perl/perl.mak] 错误 2

make报错了,git 需要perl来编译。然后重新make执行如下

yum install perl-ExtUtils-MakeMaker package

再make,又报错

make
 tclsh failed; using unoptimized loading
    MSGFMT    po/bg.msg make[1]: *** [po/bg.msg] 错误 127
make: *** [all] 错误 2

执行如下

yum install tcl build-essential tk gettext

再make,遇到如下错误

In file included from credential-store.c:1:
cache.h:40:18: warning: zlib.h: No such file or directory
In file included from credential-store.c:1:
cache.h:42: error: expected specifier-qualifier-list before ‘z_stream’
make: *** [credential-store.o] Error 1

安装zlib和zlib-devel

yum install zlib zlib-devel -y

安装之后使用https操作git 出现 :fatal: Unable to find remote helper for 'https'</li>

yum install -y curl curl-devel`

然后重新安装 git

make install

最后别忘了删掉旧的git,并把新版本的git建立软链接到 /usr/local/bin/git

ln -s /usr/bin/git/bin/git /usr/local/bin/git

函数指针数组

#include <stdio.h>
int addition(int i,int j)
{       
        return i + j;
}
int substraction(int i,int j)
{       
        return i - j;
}
int multiplication(int i,int j)
{       
        return i * j;
}
int division(int i,int j)
{       
        return i / j;
}
void menu(void)
{       
        printf("**************************\n");
        printf("**  0 => addition       **\n");
        printf("**  1 => substraction   **\n");
        printf("**  2 => multiplication **\n");
        printf("**  3 => division       **\n");
        printf("**  4 => quit           **\n");
}
int main(void)
{
        // 定义数组,注意这个格式
        int (*actions[])(int,int) = {addition,substraction,multiplication,division};
        int action = 0,max_action_index = sizeof(actions) / sizeof(actions[0]) - 1,left,right,result;
        while(1)
        {
                menu();
                printf("Enter your action:");
                scanf("%d",&action);
                // 清空输出缓冲
                setbuf(stdin,NULL);
                if(action == 4)
                {
                        printf("Bye\n");
                        break;
                }
                if(action > 0 || action < max_action_index)
                {
                        printf("Enter your variables:");
                        scanf("%d %d",&left,&right);
                        result = actions[action](left,right);
                        printf("result is %d\n",result);
                }
                else
                {
                        printf("Bad action!\n");
                }
                // 清空输出缓冲
                while((action = getchar()) != '\n' && c != EOF);
                action = max_action_index;
                //setbuf(stdin,NULL);
        }
}

c 可变参数列表

#include <stdio.h>
#include <stdarg.h>
void average(int length,...)
{       
        // 初始化 va_list 变量用于访问可变参数列表
        va_list list;
        int count;
        float sum=0;
        // 初始化可变参数列表,
        va_start(list,length);
        printf("%p\n",&length);
        printf("%p\n",list);
        printf("%d\n",(int)list - (int)(&length));// 就是在length的地址上加了4个字节
        // 循环获取 va_list 变量的值
        for(count=0;count < length;count++)
        {       
                //printf("%d\n",va_arg(list,int));
                sum+=va_arg(list,int);
        }
        printf("%f\n",sum);
        va_end(list);
}
/* 自己使用指针的方式实现不行了,好像这个实现已经改了  */
void average2(int length,...)
{       
        float sum=0;
        char *p=(char *)(&length);
        p=p+4;
        printf("%p\n",&length);
        printf("%p\n",p);
        printf("%d\n",(int)p - (int)(&length));
        for(int count=1;count<=length;count++)
        {
                //printf("%d => %d\n",count,*p);
                p+=4;
                //sum+=*(p+count);
        }
        //printf("%f\n",*p);
        //printf("%d\n",length);
        //printf("%d\n",sum);
}
int main(void)
{
        printf("average:\n");
        average(5,3,4,5,6,7);
        printf("average2:\n");
        average2(5,3,4,5,6,7);
        int i = 1, j = 2, k = 3, z = 4, num = 4;
        //printf("test1:\n");  
        //test(num, i, j, k, z);   
        return 0;
}

linux IO编程基本知识

一、标准C的I/O和

FILE结构体

typedef struct iobuf{
int cnt; /*剩余的字节数*/
char *ptr; /*下一个字符的位置*/
char *base; /*缓冲区的位置*/
int flag; /*文件访问模式*/
int fd; /*文件描述符*/
}FILE;

便准c的IO都是有缓存的,先把要操作的内容放到缓存中,最后在进行io的操作,譬如把某个字串读取到变量中,或者写数据到文件,可以查看 http://jinblog.com/archives/810.html 这篇文章的详细介绍

标准C的IO缓存类型

1、全缓存

要求填满整个缓存区后才进行I/O 系统调用操作。对于磁盘文件通常使用全缓存访问。

2、 行缓存

1)涉及一个终端时(例如标准输入和标准输出),使用行缓存。
2)行缓存满自动输出
3)碰到换行符自动输出

3、 无缓存

标准错误流stderr 通常是不带缓存区的,这使得错误信息能够尽快地显示出来。

下面的例子简单说明

#include <stdio.h>

int main()
{
        // 如下,执行程序是看不到输出内容的
        printf("Hello world!!!");
        // 加入 \n 是能看到内容的,因为标准输出是行级缓存的
        // printf("Hello world!!!\n");
        // 也可以使用fflush函数刷新输出缓冲,也能看到输出内容
        //fflush(stdout);
        while(1)
        {   
                sleep(1);
        }   
        return 0;
}