RSS Feed

Posts Tagged ‘技巧’

  1. 如何让Git的clone实现断点续传

    February 10, 2012 by xudifsd

    在下载大文件时最重要的功能恐怕就是断点续传了。如果在一个网络环境十分不稳定的环境下使用git克隆一个大型代码库绝对是个痛苦的经历,一旦下载中断,之前下载的内容全都不复存在。

    git提供断点续传的难处

    根据git的传输协议,在使用非HTTP进行传输时客户端和服务器端会进行一个复杂的通信:首先服务器端会列出它的所有内容,然后客户端根据服务器端的提示找出自己需要哪些数据,再向服务器索取,之后服务器端再调用“git upload-pack”将客户端想要的commits进行打包并传输。整个过程比较复杂,而且传输协议也不像HTTP协议那么简单,并且最麻烦的就是git传输的不是静态文件而是动态生成的,这样就造成了git的传输很难修改成支持断点续传。

    解决方法

    用HTTP来获取静态的文件时使用断点续传实在是再简单不过的了,只要在HTTP头加一行RANGE属性即可。所以如果能将git的整个仓库转换成一个静态文件再使用普通的HTTP协议传输就能非常简单地实现断点续传了。

    git其实有packfile这样的文件格式,这种文件会在运行“git gc”时或进行传输时生成,生成之后的文件包括了整个git所管理的全部内容,但仅仅只靠这样一个文件还是不能解决问题,因为这种文件只包含仓库中所有对象的内容和SHA1值,除此之外没有任何仓库元信息(分支,tag等)。所以就算得到了packfile也不能重建一个仓库。

    但是git除了packfile外还有另外一种格式的文件:bundle,这种文件只是在packfile的基础上再包括刚刚提到的仓库的元信息,所以根据bundle文件我们可以完整地clone出一个仓库。

    不过这和断点续传有什么关系呢?因为bundle可以用来将整个仓库变成一个静态文件,所以如果在服务器上创建bundle再用普通的HTTP来得到这个文件,就可以重创整个仓库,这也是android仓库的做法。不过这个方法需要服务器端提供clone.bundle文件,一旦服务器提供不一样的文件名这样的方法就失效了。而且这样的方法需要用户对服务器有控制权,如果不能控制服务器这一切都是空谈。一般用户常常只是在github这样的网站托管仓库,或者想要克隆一个Linux内核代码,这样只要服务器端不提供bundle,就算用户知道有这个东西也不能利用它来进行断点续传。不过为何不让别人帮你创建bundle呢?最终的解决方案就是这个网站,它接受你提供的代码仓库的url,之后它会将你想要的仓库克隆并创建一个bundle文件,之后你只需从该服务器上下载静态的bundle文件即可。下载完整个bundle文件后根据这里的举例就能得到整个仓库了,不过之后需要使用“git remote”修改一下远程仓库的地址,修改完后为了确保仓库内容最新最好还要执行一下“git pull”。


  2. 记一次Linux grub恢复

    November 16, 2011 by xudifsd

    今天同学遇到了一个很多Linux使用者常见的问题:恢复grub。他的情况是这样的:硬盘上有两个操作系统,一个Windows 7,一个Ubuntu,由于Windows中毒(既然Windows容易坏为什么还要用。。),所以把Windows重装一遍,重装一遍后会发现在启动选项中没有Ubuntu了,这很正常,因为Windows的引导程序不能识别Ubuntu系统(这就是为什么Ubuntu要在Windows装后再装的原因),而重装系统会清掉原来的引导程序。为了能重新启动硬盘上的Ubuntu需要将Ubuntu的引导程序也就是grub装上。

    首先从Ubuntu安装盘启动,选择试用模式,启动好之后打开终端,输入以下命令:

    sudo fdisk -l

    它会列出当前硬盘的所有分区,如下图:fdisk -l结果

    我分了多个Linux分区,分别为/dev/sda{6..11},其中sda9是我的根目录,sda6是我的/boot目录

    由于是从CD启动的,硬盘上的分区都还没有挂载,所以先要将需要修改的一些分区挂载上来,执行以下命令:

    sudo mount /dev/sda9 /mnt
    sudo mount /dev/sda6 /mnt/boot

    其中第二个命令需要根据自己的情况运行,由于我将boot单独分一个区,所以我需要挂载boot分区来修改它,如果你没给boot单独分区,那么就不用执行第二条命令。

    之后需要将一些虚拟的文件系统挂载到/mnt目录下,这样是为了模拟出从硬盘启动的所有文件系统的环境:

    sudo mount --bind /proc /mnt/proc
    sudo mount --bind /dev /mnt/dev
    sudo mount --bind /sys /mnt/sys

    之后便是一条非常重要的命令,如果你在进行grub-install时出现了/usr/sbin/grub-probe: error: cannot stat ‘aufs’提示,那么很有可能就是因为你没有执行下面这条命令:

    sudo chroot /mnt

    执行了这条命令之后你的终端已经几乎完全模拟出从硬盘启动的终端了,之后你执行的命令都对应的修改硬盘而不是修改不会保存的CD虚拟的文件系统了(对于一些特殊情况就不满足这条件了,比如需要修改/etc但是你将etc单独分区并且没有挂载到/mnt)。
    之后执行以下命令:

    update-grub
    grub-install /dev/sdX	#sdX中的X对于你硬盘的号,一般是sda,注意不是sda7这样的分区号,而是直接指定整个硬盘,如果不是主硬盘就是sdb,以此类推

    之后直接重启就行了。

    联想

    最近总是在思考过程式编程和纯函数式编程有什么区别,我觉得这是一个很好的例子。在这个还原grub的过程中我们做了很多的mount,并且还用到了几乎不会用到的chroot,这么多多余的步骤就是为了创造出一个正确的文件系统环境,好让我们在这个模拟的环境中执行没有参数的update-grub。从编程的角度来讲update-grub是个函数,但是这个函数写得非常不好,它竟然不靠参数来运行而是依赖于全局变量,这个全局变量就是我们刚刚费了很大劲才创造出来的文件系统环境,如果update-grub靠参数来运行(也就是说update-grub类似于纯函数式编程只靠参数运行而不依赖于全局变量),我们就只需要挂载boot分区再指定boot分区的位置就行,而不用为了这个依赖全局变量的函数而模拟出整个环境。我觉得这也算是函数式编程的一个好处之一了吧。