Libin's profile绿色家园PhotosBlogLists Tools Help

绿色家园

Green World(本空间文章,未经原作者同意,请勿做商业用途。未注明的文章均为转载。)

Libin Sui

No content has been added yet.

Custom HTML

点击图标和我联系!
May 30

介绍qmake

qmake是用来为不同的平台的开发项目创建makefile的Trolltech开发一个易于使用的工具。qmake简化了makefile的生成,所以为了创建一个makefile只需要一个只有几行信息的文件。qmake可以供任何一个软件项目使用,而不用管它是不是用Qt写的,尽管它包含了为支持Qt开发所拥有的额外的特征。

qmake基于一个项目文件这样的信息来生成makefile。项目文件可以由开发者生成。项目文件通常很简单,但是如果需要它是非常完善的。不用修改项目文件,qmake也可以为为Microsoft Visual Studio生成项目。

qmake的概念

QMAKESPEC环境变量

举例来说,如果你在Windows下使用Microsoft Visual Studio,然后你需要把QMAKESPEC环境变量设置为win32-msvc。如果你在Solaris上使用gcc,你需要把QMAKESPEC环境变量设置为solaris-g++

在qt/mkspecs中的每一个目录里面,都有一个包含了平台和编译器特定信息的qmake.conf文件。这些设置适用于你要使用qmake的任何项目,请不要修改它,除非你是一个专家。例如,假如你所有的应用程序都必须和一个特定的库连接,你可以把这个信息添加到相应的qmake.conf文件中。

项目(.pro)文件

一个项目文件是用来告诉qmake关于为这个应用程序创建makefile所需要的细节。例如,一个源文件和头文件的列表、任何应用程序特定配置、例如一个必需要连接的额外库、或者一个额外的包含路径,都应该放到项目文件中。

“#”注释

你可以为项目文件添加注释。注释由“#”符号开始,一直到这一行的结束。

模板

模板变量告诉qmake为这个应用程序生成哪种makefile。下面是可供使用的选择:

  • app - 建立一个应用程序的makefile。这是默认值,所以如果模板没有被指定,这个将被使用。

  • lib - 建立一个库的makefile。

  • vcapp - 建立一个应用程序的Visual Studio项目文件。

  • vclib - 建立一个库的Visual Studio项目文件。

  • subdirs - 这是一个特殊的模板,它可以创建一个能够进入特定目录并且为一个项目文件生成makefile并且为它调用make的makefile。

“app”模板

“app”模板告诉qmake为建立一个应用程序生成一个makefile。当使用这个模板时,下面这些qmake系统变量是被承认的。你应该在你的.pro文件中使用它们来为你的应用程序指定特定信息。

  • HEADERS - 应用程序中的所有头文件的列表。

  • SOURCES - 应用程序中的所有源文件的列表。

  • FORMS - 应用程序中的所有.ui文件(由Qt设计器生成)的列表。

  • LEXSOURCES - 应用程序中的所有lex源文件的列表。

  • YACCSOURCES - 应用程序中的所有yacc源文件的列表。

  • TARGET - 可执行应用程序的名称。默认值为项目文件的名称。(如果需要扩展名,会被自动加上。)

  • DESTDIR - 放置可执行程序目标的目录。

  • DEFINES - 应用程序所需的额外的预处理程序定义的列表。

  • INCLUDEPATH - 应用程序所需的额外的包含路径的列表。

  • DEPENDPATH - 应用程序所依赖的搜索路径。

  • VPATH - 寻找补充文件的搜索路径。

  • DEF_FILE - 只有Windows需要:应用程序所要连接的.def文件。

  • RC_FILE - 只有Windows需要:应用程序的资源文件。

  • RES_FILE - 只有Windows需要:应用程序所要连接的资源文件。

你只需要使用那些你已经有值的系统变量,例如,如果你不需要任何额外的INCLUDEPATH,那么你就不需要指定它,qmake会为所需的提供默认值。例如,一个实例项目文件也许就像这样:

TEMPLATE = app
DESTDIR = c:\helloapp
HEADERS += hello.h
SOURCES += hello.cpp
SOURCES += main.cpp
DEFINES += QT_DLL
CONFIG += qt warn_on release

如果条目是单值的,比如template或者目的目录,我们是用“=”,但如果是多值条目,我们使用“+=”来为这个类型添加现有的条目。使用“=”会用新值替换原有的值,例如,如果我们写了DEFINES=QT_DLL,其它所有的定义都将被删除。

“lib”模板

“lib”模板告诉qmake为建立一个库而生成makefile。当使用这个模板时,除了“app”模板中提到系统变量,还有一个VERSION是被支持的。你需要在为库指定特定信息的.pro文件中使用它们。

  • VERSION - 目标库的版本号,比如,2.3.1。

“subdirs”模板

“subdirs”模板告诉qmake生成一个makefile,它可以进入到特定子目录并为这个目录中的项目文件生成makefile并且为它调用make。

在这个模板中只有一个系统变量SUBDIRS可以被识别。这个变量中包含了所要处理的含有项目文件的子目录的列表。这个项目文件的名称是和子目录同名的,这样qmake就可以发现它。例如,如果子目里是“myapp”,那么在这个目录中的项目文件应该被叫做myapp.pro

CONFIG变量

配置变量指定了编译器所要使用的选项和所需要被连接的库。配置变量中可以添加任何东西,但只有下面这些选项可以被qmake识别。

下面这些选项控制着使用哪些编译器标志:

  • release - 应用程序将以release模式连编。如果“debug”被指定,它将被忽略。

  • debug - 应用程序将以debug模式连编。

  • warn_on - 编译器会输出尽可能多的警告信息。如果“warn_off”被指定,它将被忽略。

  • warn_off - 编译器会输出尽可能少的警告信息。

下面这些选项定义了所要连编的库/应用程序的类型:

  • qt - 应用程序是一个Qt应用程序,并且Qt库将会被连接。

  • thread - 应用程序是一个多线程应用程序。

  • x11 - 应用程序是一个X11应用程序或库。

  • windows - 只用于“app”模板:应用程序是一个Windows下的窗口应用程序。

  • console - 只用于“app”模板:应用程序是一个Windows下的控制台应用程序。

  • dll - 只用于“lib”模板:库是一个共享库(dll)。

  • staticlib - 只用于“lib”模板:库是一个静态库。

  • plugin - 只用于“lib”模板:库是一个插件,这将会使dll选项生效。

例如,如果你的应用程序使用Qt库,并且你想把它连编为一个可调试的多线程的应用程序,你的项目文件应该会有下面这行:

    CONFIG += qt thread debug

注意,你必须使用“+=”,不要使用“=”,否则qmake就不能正确使用连编Qt的设置了,比如没法获得所编译的Qt库的类型了。

May 29

编译meshlab 1.21全接触


1. 编译环境:

       a. visual studio 2008 perfessional edition,因为已经安装了sp1,所以不确定它会对编译有何影响。

       b. QT opensource v4.50,只编译了其动态库文件(静态库无法编译完全)。

执行“Visual Studio 2008 命令提示 ”控制台工具后,在QT根目录执行QT编译环境设置脚本,该脚本同时为meshlab生成vc 项目工程的环境。一下为该脚本原文:

@echo off

set cur_dir=%cd%\

set QTDIR=%cur_dir%

set QMAKESPEC=win32-msvc2008

set ConfPara=-debug-and-release -opensource -fast -no-dbus -no-webkit

 

set PATH=%QTDIR%/bin;%PATH%

set INCLUDE=%MINGWDIR%/include;%QTDIR%/include;%QWTDIR%/src;%LOG4QTDIR%/src;%INCLUDE%

set LIB=%MINGWDIR%/lib;%QTDIR%/lib;%QWTDIR%/lib;%LIB%

 

echo ***********************************************************************

echo Created By gmail:bygreencn.gmail.com

echo Includes  : QT 4.5.0Visual Studio 2008

echo QT        : %QTDIR%

echo QMAKESPEC: %QMAKESPEC%

echo ConfPara: %ConfPara%

echo ***********************************************************************

@REM pause

@REM nmake clean

@REM nmake confclean

@REM configure.exe %ConfPara%

 

@REM pause

@REM echo build it now?

@REM nmake clean

cmd /k

 

       c.下载MeshLab's source code version 1.2.1,我下载的是All Inclusive package

2. 生成所需的VC项目工程文件

a. 上一步的控制台,进入.\ meshlab\src\external,执行qmake -tp vc -recursive external.pro

b. 上一步的控制台,进入.\ meshlab\src,执行qmake -tp vc -recursive meshlabv12.pro

3. 编译meshlab

       a. 首先编译external library。用vc打开.\ meshlab\src\external\external.sln,进入配置管理器,选择编译debugrelease版本,在选择生成解决方案,等待编译全部通过,它会生成三个库文件。bz.lib,3ds.libmuparser.lib,我发现3ds.lib的生成有些问题,会使得meshlabLINK时无法正确连接函数,我在lib3ds\type.h做了一下修改:

//#ifdef _MSC_VER

//#ifdef LIB3DS_EXPORTS

//#define LIB3DSAPI __declspec(dllexport)

//#else              

//#define LIB3DSAPI __declspec(dllimport)

//#endif           

//#else

#define LIB3DSAPI

//#endif

       b.编译meshlabmeshlab所有的plugin工程的设置有些问题,这些工程都制定输出为动态库,但是输出文件却指定为输出为*****.lib,这导致所有的plugins的工程都失败。我的做法是把指定输出为*****.dll,这里应该必须为dll,因为New的对话框中会根据plugins文件夹下的内容动态生成,因为这些应该也是动态加载的,因为静态库是不行的了。

1). 需要为io_lib指定其需要的lib3ds.lib(external library)

2). 需要为io_epoch指定其需要的bz2.lib和头文件的位置(external library)

如果哪个plugin工程出现类似这个错误:

1>Project : error PRJ0019: 某个工具从以下位置返回了错误代码: "MOC v3dImportDialog.h"

1>项目: warning PRJ0018 : 未找到下列环境变量:

1>$(QTDIR)

只需要用生成VC项目的那个控制台环境进入相应的plugin目录,执行qmake -tp vc -recursive xxxxxx.pro来重新生成该工程即可。

 

编译整个项目,大概需要十多分钟。然后就可以进入.\meshlab\src\meshlab\debug或者.\meshlab\src\meshlab\release执行meshlab.exe;记得要把QTDLL库文件拷贝到这个目录或者将QTDLL库所在目录加入到系统PATH中啊。

 

May 13

破解无线路由器密码

Posted by chinahang 2009年5月13日

随着社会的进步!WIFI上网日益普及,特别是大城市中随便在一个小区搜索一下就能找到好多热点,搜索到热点然后链接上去那么我们就可以尽情的享受免费上网服务了。
不过除了公共场所以及菜鸟用户之外几乎所有的WIFI信号都是加密的,很简单换作是你你也不愿意把自己的带宽免费拿出来给别人用,所以如果你搜索到你附近有热点想免费上网的话请仔细往下学习...
                                                           

                                                       破解静态WEP KEY全过程

 

 

发现

首先通过NetStumbler确认客户端已在某AP的覆盖区内,并通过AP信号的参数进行‘踩点’(数据搜集)。

NetStumbler 下载地址  

通 过上图的红色框框部分内容确定该SSID名为demonalex的AP为802.11b类型设 备,Encryption属性为‘已加密’,根据802.11b所支持的算法标准,该算法确定为WEP。有一点需要注意:NetStumbler对任何有 使用加密算法的STA[802.11无线站点]都会在Encryption属性上标识为WEP算法,如上图中SSID为gzpia的AP使用的加密算法是 WPA2-AES。

破解

下载Win32AirCrack程序集---WinAirCrackPack工具包(下载地址:http://www.demonalex.net/download/wireless/aircrack/WinAircrackPack.zip)。解压缩后得到一个大概4MB的目录,其中包括六个EXE文件:

aircrack.exe  WIN32aircrack程序

airdecap.exe      WEP/WPA解码程序

airodump.exe  数据帧捕捉程序

Updater.exe WIN32aircrack的升级程序

WinAircrack.exe      WIN32aircrack图形前端

wzcook.exe 本地无线网卡缓存中的WEPKEY记录程序

 

我们本次实验的目的是通过捕捉适当的数据帧进行IV(初始化向量)暴力破解得到WEP KEY,因此只需要使用airodump.exe(捕捉数据帧用)与WinAircrack.exe(破解WEP KEY用)两个程序就可以了。

首先打开ariodump.exe程序,按照下述操作:

 
首 先程序会提示本机目前存在的所有无线网卡接口,并要求你输入需要捕捉数据帧的无线网卡接口编号,在这里我选择使用支持通用驱动的BUFFALO WNIC---编号‘26’;然后程序要求你输入该WNIC的芯片类型,目前大多国际通用芯片都是使用‘HermesI/Realtek’子集的,因此选 择‘o’;然后需要输入要捕捉的信号所处的频道,我们需要捕捉的AP所处的频道为‘6’;提示输入捕捉数据帧后存在的文件名及其位置,若不写绝对路径则文 件默认存在在winaircrack的安装目录下,以.cap结尾,我在上例中使用的是‘last’; 最后winaircrack提示:‘是否只写入/记录IV[初始化向量]到cap文件中去?’,我在这里选择‘否/n’;确定以上步骤后程序开始捕捉数据 包。

下 面的过程就是漫长的等待了,直至上表中‘Packets’列的总数为300000时即可满足实验要求。根据实验的经验所得:当该AP的通信数据流量极度频 繁、数据流量极大时,‘Packets’所对应的数值增长的加速度越大。当程序运行至满足‘Packets’=300000的要求时按Ctrl+C结束该 进程。 此时你会发现在winaircrack的安装目录下将生成last.cap与last.txt两个文件。其中last.cap为通用嗅探器数据包记录文件 类型,可以使用ethereal程序打开查看相关信息;last.txt为此次嗅探任务最终的统计数据(使用‘记事本/notepad’打开 last.txt后得出下图)。

下面破解工作主要是针对last.cap进行。首先执行WinAirCrack.exe文件:

单击上图红色框框部分的文件夹按钮,弹出*.cap选定对话框,选择last.cap文件,然后通过点击右方的‘Wep’按钮切换主界面至WEP破解选项界面:

选 择‘Key size’为64(目前大多数用户都是使用这个长度的WEP KEY,因此这一步骤完全是靠猜测选定该值),最后单击主界面右下方的‘Aircrack the key…’按钮,此时将弹出一个内嵌在cmd.exe下运行的进程对话框,并在提示得出WEP KEY:

利用

打开无线网卡的连接参数设置窗口,设置参数为:

SSIDdemonalex

频道:6

WEP KEY111112222264位)

OK,现在可以享受连入别人WLAN的乐趣了。

April 28

让VS 2008支持Subversion插件Ankhsvn

Visual Studio 2005 有一个开源的Subversion插件,Ankhsvn  (http://ankhsvn.tigris.org/),安装后,VS 2005中将内置Subversion的支持,可以直接在VS里面提交修改。我经常用它和TortoiseSVN 配合来使用Subversion,十分方便。

可是升级到Visual Studio 2008后,发现Ankhsvn没有集成进来,因为目前的Ankhsvn还不支持VS2008,据说下个版本才会支持VS 2008。

不过这不影响我们在Visual Studio 2008中使用Ankhsvn,我们可以自己动手修改注册表,将Ankhsvn集成进VS 2008。方法很简单。

  1. 运行 regedit
  2. 找到 HKLMSOFTWAREMicrosoftVisualStudio8.0AddinsAnkh
  3. 右键点击它,选择导出,并指定一个文件保存。
  4. 用记事本或者其他文本编辑器打开这个文件,将其中的VisualStudio8.0替换为VisualStudio9.0
  5. 最后,双击这个修改后的注册表文件,提示是否导入进系统注册表,选择是。

再次打开Visual Studio 2008后,就会发现Ankhsvn已经集成进系统了。

为了方便操作,我写了一个vbscript脚本来进行上述操作。使用很简单,将下面的脚本保存到一个文本文件,命名为ankh.vbs,然后双击该文件即可运行。运行后,重新打开Visual Studio 2008,就会发现Ankhsv已经集成进来了。

顺便再推荐几个常用的免费的插件:

[FREE VISUAL STUDIO ADD-INS]
http://searchwindevelopment.techtarget.com/originalContent/0,289142,sid8_gci1262570,00.html


需要提醒的是,注册表操作不慎可能会导致系统崩溃,因此请谨慎修改注册表。

Dim shell, filename, fso, file, content
Set shell = CreateObject("wscript.shell"
)
Set fso = CreateObject("Scripting.FileSystemObject"
)
filename 
= "ankh.reg"


shell.run 
"reg export HKLMSOFTWAREMicrosoftVisualStudio8.0AddinsAnkh " & filename, 1True

Set file = fso.OpenTextFile(filename, 1FalseTrue)
content 
=
 file.ReadAll
content 
= Replace(content, "VisualStudio8.0""VisualStudio9.0"
)
content 
= Replace(content, ".NET 2005"".NET 2008"
)
file.Close()

Set file = fso.OpenTextFile(filename, 2True
)
file.Write content
file.Close()

shell.run 
"reg import " & filename, 1true


fso.DeleteFile filename
April 16

Gpredict is a real-time satellite tracking and orbit prediction application

Gpredict Screenshots

Below you can see some sample screenshots of gpredict in in action. They illustrate the main features of gpredict. I have a whole album dedicated to screenshots of Gpredict in my Media Gallery. You can also post links to your own screenshots and pictures of Gpredict in action on the forum.

Main Window, Modules Layouts, and Views

Gpredict main window Gpredict main window

Gpredict main window Map View

List View List View

Polar View Single Satellite View

Future Pass Predictions

Next Pass: Data Next Pass: Polar

Next Pass: Az/El Next Pass: Data

Upcoming Passes Upcoming Passes

Radio and Antenna Rotator Control

Radio control window Antenna rotator control window

Preferences and Settings

Preferences Dialogue Preferences Dialogue

Preferences Dialogue Preferences Dialogue

Module Configuration

April 14

用VC6.0编译boost 1.38.0

1. 从boost.org下载下1.38.0的源码

2.编译jam

    在boost_1_38_0\tools\jam\src下有个build.bat ,修改其ProgramFiles变量为VC安装的目录。

    执行build.bat msvc,等编译成功,会在\boost_1_38_0\tools\jam\src\bin.ntx86下生成bjam.exe

3.将bjam拷贝到boost_1_38_0\bin,将目录增加环境变量PATH。

4.编译整个boost

    在根目录boost_1_38_0,执行bjam --toolset=msvc-6.0
 

另外:

5. 如果编译boost里面单独的模块,如regex

    进入boost_1_38_0\libs\regex\build

    执行bjam  bjam --toolset=msvc-6.0

    就会在boost_1_38_0\bin.v2\libs\regex\build\msvc-6.0\debug\threading-multi下面生成boost_regex-vc6-mt-gd-1_38_0.dll和boost_regex-vc6-mt-gd-1_38_0.lib库,可以给VC6.0使用。

March 23

Git 中文教程

介绍

Git --- The stupid content tracker, 傻瓜内容跟踪器。Linus 是这样给我们介绍 Git 的。

Git 是用于 Linux 内核开发的版本控制工具。与常用的版本控制工具 CVS, Subversion 等不同, 它采用了分布式版本库的方式,不必服务器端软件支持,使源代码的发布和交流极其方便。 Git 的速度很快,这对于诸如 Linux kernel 这样的大项目来说自然很重要。 Git 最为出色的是它的合并跟踪(merge tracing)能力。

实际上内核开发团队决定开始开发和使用 Git 来作为内核开发的版本控制系统的时候, 世界开源社群的反对声音不少,最大的理由是 Git 太艰涩难懂,从 Git 的内部工作机制来说,的确是这样。 但是随着开发的深入,Git 的正常使用都由一些友好的脚本命令来执行,使 Git 变得非常好用, 即使是用来管理我们自己的开发项目,Git 都是一个友好,有力的工具。 现在,越来越多的著名项目采用 Git 来管理项目开发,例如:wine, U-boot 等,详情看 http://www.kernel.org/git

作为开源自由原教旨主义项目,Git 没有对版本库的浏览和修改做任何的权限限制。 它只适用于 Linux / Unix 平台,没有 Windows 版本,目前也没有这样的开发计划。

本文将以 Git 官方文档 Tutorial core-tutorialEveryday GIT 作为蓝本翻译整理,但是暂时去掉了对 Git 内部工作机制的阐述, 力求简明扼要,并加入了作者使用 Git 的过程中的一些心得体会,注意事项,以及更多的例子。 建议你最好通过你所使用的 Unix / Linux 发行版的安装包来安装 Git, 你可以在线浏览本文 ,也可以通过下面的命令来得到本文最新的版本库,并且通过后面的学习用 Git 作为工具参加到本文的创作中来。

创建一个版本库:git-init-db

创建一个 Git 版本库是很容易的,只要用命令 git-init-db 就可以了。 现在我们来为本文的写作创建一个版本库:

$ mkdir gittutorcn
$ cd gittutorcn
$ git-init-db

git 将会作出以下的回应

defaulting to local storage area

这样,一个空的版本库就创建好了,并在当前目录中创建一个叫 .git 的子目录。 你可以用 ls -a 查看一下,并请注意其中的三项内容:

  • 一个叫 HEAD 的文件,我们现在来查看一下它的内容:

    $ cat .git/HEAD

    现在 HEAD 的内容应该是这样:

    ref: refs/heads/master

    我们可以看到,HEAD 文件中的内容其实只是包含了一个索引信息, 并且,这个索引将总是指向你的项目中的当前开发分支。

  • 一个叫 objects 的子目录,它包含了你的项目中的所有对象,我们不必直接地了解到这些对象内容, 我们应该关心是存放在这些对象中的项目的数据。

    Note
    关于 git 对象的分类,以及 git 对象数据库的说明, 请参看 [Discussion]
  • 一个叫 refs 的子目录,它用来保存指向对象的索引。

具体地说,子目录 refs 包含着两个子目录叫 headstags, 就像他们的名字所表达的意味一样:他们存放了不同的开发分支的的索引, 或者是你用来标定版本的标签的索引。

请注意:master 是默认的分支,这也是为什么 .git/HEAD 创建的时候就指向 master 的原因,尽管目前它其实并不存在。 git 将假设你会在 master 上开始并展开你以后的工作,除非你自己创建你自己的分支。

另外,这只是一个约定俗成的习惯而已,实际上你可以将你的工作分支叫任何名字, 而不必在版本库中一定要有一个叫 master 的分支,尽管很多 git 工具都认为 master 分支是存在的。

现在已经创建好了一个 git 版本库,但是它是空的,还不能做任何事情,下一步就是怎么向版本库植入数据了。

植入内容跟踪信息:git-add

为了简明起见,我们创建两个文件作为练习:

$ echo "Hello world" > hello
$ echo "Silly example" > example

我们再用 git-add 命令将这两个文件加入到版本库文件索引当中:

$ git-add hello example

git-add 实际上是个脚本命令,它是对 git 内核命令 git-update-index 的调用。 因此上面的命令和下面的命令其实是等价的:

$ git-update-index --add hello example

如果你要将某个文件从 git 的目录跟踪系统中清除出去,同样可以用 git-update-index 命令。例如:

$ git-update-index --force-remove foo.c
Note
git-add 可以将某个目录下的所有内容全都纳入内容跟踪之下,例如: git-add ./path/to/your/wanted 。但是在这样做之前, 应该注意先将一些我们不希望跟踪的文件清理掉, 例如,gcc 编译出来的 *.o 文件,vim 的交换文件 .*.swp 之类。

应该建立一个清晰的概念就是,git-addgit-update-index 只是刷新了 git 的跟踪信息,hello 和 example 这两个文件中的内容并没有提交到 git 的内容跟踪范畴之内。

提交内容到版本库:git-commit

既然我们刷新了 Git 的跟踪信息,现在我们看看版本库的状态:

$ git-status

我们能看到 git 的状态提示:

#
# Initial commit
#
#
# Updated but not checked in:
# (will commit)
#
# new file: example
# new file: hello
#

提示信息告诉我们版本库中加入了两个新的文件,并且 git 提示我们提交这些文件, 我们可以通过 git-commit 命令来提交:

$ git-commit -m "Initial commit of gittutor reposistory"

查看当前的工作:git-diff

git-diff 命令将比较当前的工作目录和版本库数据库中的差异。 现在我们编辑一些文件来体验一下 git 的跟踪功能。

$ echo "It's a new day for git" >> hello

我们再来比较一下,当前的工作目录和版本库中的数据的差别。

$ git-diff

差异将以典型的 patch 方式表示出来:

diff --git a/hello b/hello
index a5c1966..bd9212c 100644
--- a/hello
+++ b/hello
@@ -1 +1,2 @@
Hello, world
+It's a new day for git

此时,我们可以再次使用组合命令 git-update-indexgit-commit 将我们的工作提交到版本库中。

$ git-update-index hello
$ git-commit -m "new day for git"

实际上,如果要提交的文件都是已经纳入 git 版本库的文件,那么不必为这些文件都应用 git-update-index 命令之后再进行提交,下面的命令更简捷并且和上面的命令是等价的。

$ git-commit -a -m "new day for git"

管理分支:git-branch

直至现在为止,我们的项目版本库一直都是只有一个分支 master。 在 git 版本库中创建分支的成本几乎为零,所以,不必吝啬多创建几个分支。 下面列举一些常见的分支策略,仅供大家参考:

  • 创建一个属于自己的个人工作分支,以避免对主分支 master 造成太多的干扰, 也方便与他人交流协作。

  • 当进行高风险的工作时,创建一个试验性的分支,扔掉一个烂摊子总比收拾一个烂摊子好得多。

  • 合并别人的工作的时候,最好是创建一个临时的分支,关于如何用临时分支合并别人的工作的技巧, 将会在后面讲述。

创建分支

下面的命令将创建我自己的工作分支,名叫 robin,并且将以后的工作转移到这个分支上开展。

$ git-branch robin
$ git-checkout robin

删除分支

要删除版本库中的某个分支,使用 git-branch -D 命令就可以了,例如:

$ git-branch -D branch-name

查看分支

运行下面的命令可以得到你当前工作目录的分支列表:

$ git-branch

如果你忘记了你现在工作在哪个分支上,运行下面的命令可以告诉你:

$ cat .git/HEAD 

查看项目的发展变化和比较差异

这一节介绍几个查看项目的版本库的发展变化以及比较差异的很有用的命令:

git-show-branch

git-diff

git-whatchanged


我们现在为 robin, master 两个分支都增加一些内容。

$ git-checkout robin
$ echo "Work, work, workd" >> hello
$ git-commit -m "Some workd" -i hello
$ git-checkout master
$ echo "Play, play, play" >> hello
$ echo "Lots of fun" >> example
$ git-commit -m "Some fun" -i hello example

git-show-branch 命令可以使我们看到版本库中每个分支的世系发展状态, 并且可以看到每次提交的内容是否已进入每个分支。

$ git-show-branch 

这个命令让我们看到版本库的发展记录。

* [master] Some fun
! [robin] some work
--
* [master] Some fun
+ [robin] some work
*+ [master^] a new day for git

譬如我们要查看世系标号为 master^robin 的版本的差异情况, 我们可以使用这样的命令:

$ git-diff master^ robin

我们可以看到这两个版本的差异:

diff --git a/hello b/hello
index 263414f..cc44c73 100644
--- a/hello
+++ b/hello
@@ -1,2 +1,3 @@
Hello World
It's a new day for git
+Work, work, work
Note
关于 GIT 版本世系编号的定义,请参看 git-rev-parse

我们现在再用 git-whatchanged 命令来看看 master 分支是怎么发展的。

$ git-checkout master
$ git-whatchanged
diff-tree 1d2fa05... (from 3ecebc0...)
Author: Vortune.Robin
Date: Tue Mar 21 02:24:31 2006 +0800

Some fun

:100644 100644 f24c74a... 7f8b141... M example
:100644 100644 263414f... 06fa6a2... M hello

diff-tree 3ecebc0... (from 895f09a...)
Author: Vortune.Robin
Date: Tue Mar 21 02:17:23 2006 +0800

a new day for git

:100644 100644 557db03... 263414f... M hello

从上面的内容中我们可以看到,在 robin 分支中的日志为 "Some work" 的内容, 并没有在 master 分支中出现。

合并两个分支:git-merge

既然我们为项目创建了不同的分支, 那么我们就要经常地将自己或者是别人在一个分支上的工作合并到其他的分支上去。 现在我们看看怎么将 robin 分支上的工作合并到 master 分支中。 现在转移我们当前的工作分支到 master,并且将 robin 分支上的工作合并进来。

$ git-checkout master
$ git-merge "Merge work in robin" HEAD robin
合并两个分支,还有一个更简便的方式,下面的命令和上面的命令是等价的。
$ git-checkout master
$ git-pull . robin

但是,此时 git 会出现合并冲突提示:

Trying really trivial in-index merge...
fatal: Merge requires file-level merging
Nope.
Merging HEAD with d2659fcf690ec693c04c82b03202fc5530d50960
Merging:
1d2fa05b13b63e39f621d8ee911817df0662d9b7 Some fun
d2659fcf690ec693c04c82b03202fc5530d50960 some work
found 1 common ancestor(s):
3ecebc0cb4894a33208dfa7c7c6fc8b5f9da0eda a new day for git
Auto-merging hello
CONFLICT (content): Merge conflict in hello

Automatic merge failed; fix up by hand

git 的提示指出,在合并作用于文件 hello 的 'Some fun' 和 'some work' 这两个对象时有冲突, 具体通俗点说,就是在 master, robin 这两个分支中的 hello 文件的某些相同的行中的内容不一样。 我们需要手动解决这些冲突,现在先让我们看看现在的 hello 文件中的内容。

$ cat hello

此时的 hello 文件应是这样的,用过其他的版本控制系统的朋友应该很容易看出这个典型的冲突表示格式:

Hello World
It's a new day for git
<<<<<<< HEAD/hello
Play, play, play
=======
Work, work, work
>>>>>>> d2659fcf690ec693c04c82b03202fc5530d50960/hello

我们用编辑器将 hello 文件改为:

Hello World
It's a new day for git
Play, play, play
Work, work, work

现在可以将手动解决了冲突的文件提交了。

$ git-commit -i hello

以上是典型的两路合并(2-way merge)算法,绝大多数情况下已经够用。 但是还有更复杂的三路合并和多内容树合并的情况。详情可参看: git-read-tree git-merge 等文档。

逆转与恢复:git-reset

项目跟踪工具的一个重要任务之一,就是使我们能够随时逆转(Undo)和恢复(Redo)某一阶段的工作。

git-reset 命令就是为这样的任务准备的。 它将当前的工作分支的 定位到以前提交的任何版本中,它有三个重置的算法选项。

命令形式:

git-reset [--mixed | --soft | --hard] [<commit-ish>]

命令的选项:

--mixed
仅是重置索引的位置,而不改变你的工作树中的任何东西(即,文件中的所有变化都会被保留, 也不标记他们为待提交状态),并且提示什么内容还没有被更新了。这个是默认的选项。
--soft
既不触动索引的位置,也不改变工作树中的任何内容,我们只是要求这些内容成为一份好的内容 (之后才成为真正的提交内容)。 这个选项使你可以将已经提交的东西重新逆转至“已更新但未提交(Updated but not Check in)”的状态。 就像已经执行过 git-update-index 命令,但是还没有执行 git-commit 命令一样。
--hard
将工作树中的内容和头索引都切换至指定的版本位置中,也就是说自 <commit-ish> 之后的所有的跟踪内容和工作树中的内容都会全部丢失。 因此,这个选项要慎用,除非你已经非常确定你的确不想再看到那些东西了。

一个重要技巧--逆转提交与恢复

可能有人会问,--soft 选项既不重置头索引的位置,也不改变工作树中的内容, 那么它有什么用呢?现在我们介绍一个 --soft 选项的使用技巧。 下面我们用例子来说明:

$ git-checkout master
$ git-checkout -b softreset
$ git-show-branch

这里我们创建了一个 master 的拷贝分支 softreset, 现在我们可以看到两个分支是在同一起跑线上的。

! [master] Merge branch 'robin'
! [robin] some work
* [softreset] Merge branch 'robin'
---
- - [master] Merge branch 'robin'
+ * [master^] Some fun
++* [robin] some work

我们为 文件增加一些内容并提交。

$ echo "Botch, botch, botch" >> hello
$ git-commit -a -m "some botch"
$ git-show-branch

我们可以看到此时 softresetmaster 推进了一个版本 "some botch" 。

! [master] Merge branch 'robin'
! [robin] some work
* [softreset] some botch
---
* [softreset] some botch
- - [master] Merge branch 'robin'
+ * [master^] Some fun
++* [robin] some work

现在让我们来考虑这样的一种情况,假如我们现在对刚刚提交的内容不满意, 那么我们再编辑项目的内容,再提交的话,那么 "some botch" 的内容就会留在版本库中了。 我们当然不希望将有明显问题的内容留在版本库中,这个时候 --soft 选项就很有用了。 为了深入了解 --soft 的机制,我们看看现在 softreset 分支的头和 ORIG_HEAD 保存的索引。

$ cat .git/refs/heads/softreset .git/ORIG_HEAD

结果如下:

5e7cf906233e052bdca8c598cad2cb5478f9540a
7bbd1370e2c667d955b6f6652bf8274efdc1fbd3

现在用 --soft 选项逆转刚才提交的内容:

git-reset --soft HEAD^

现在让我们再看看 .git/ORIG_HEAD 的中保存了什么?

$ cat .git/ORIG_HEAD

结果如下:

5e7cf906233e052bdca8c598cad2cb5478f9540a

看!现在的 .git/ORIG_HEAD 等于逆转前的 .git/refs/heads/softreset 。 也就是说,git-reset --soft HEAD^ 命令逆转了刚才提交的版本进度, 但是它将那次提交的对象的索引拷贝到了 .git/ORIG_HEAD 中。

我们再编辑 hello 文件成为下面的内容:

Hello World
It's a new day for git
Play, play, play
Work, work, work
Nice, nice, nice

我们甚至可以比较一下现在的工作树中的内容和被取消了的那次提交的内容有什么差异:

$ git-diff ORIG_HEAD

结果如下:

diff --git a/hello b/hello
index f978676..dd02c32 100644
--- a/hello
+++ b/hello
@@ -2,4 +2,4 @@ Hello World
It's a new day for git
Play, play, play
Work, work, work
-Botch, botch, botch
+Nice, nice, nice

接着,我们可以恢复刚才被取消了的那次提交了。

$ git-commit -a -c ORIG_HEAD

注意,这个命令会打开默认的文本编辑器以编辑原来提交的版本日志信息,我们改为 "nice work" 。 大家可以自行用 git-show-branch 命令来查看一下现在的分支状态。 并且我们还可以不断地重复上述的步骤,一直修改到你对这个版本进度满意为止。

git-reset 命令还有很多的用途和技巧,请参考 git-reset ,以及 Everyday GIT with 20 commands or So

提取版本库中的数据

这是个很有用的小技巧,如果你对你现在的工作目录下的东西已经不耐烦了, 随时可以取出你提交过的东西覆盖掉当前的文件,譬如:

$ git-checkout -f foo.c

标定版本

在 git 中,有两种类型的标签,“轻标签”和“署名标签”。

技术上说,一个“轻标签”和一个分支没有任何区别,只不过我们将它放在了 .git/refs/tags/ 目录, 而不是 heads 目录。因此,打一个“轻标签”再简单不过了。

$ git-tag my-first-tag

如果你打算针对某个commit ID来打标签,虽然该命令可以通过gitk里的右键菜单来实现,但是该命令对实际应用是很有帮助的。

$ git-tag mytag f0af6283824688f9d23426031734657661b54388

“署名标签”是一个真正的 git 对象,它不但包含指向你想标记的状态的指针,还有一个标记名和信息, 可选的 PGP 签名。你可以通过 -a 或者是 -s 选项来创建“署名标签”。

$ git-tag -s <tag-name>

合并外部工作

通常的情况下,合并其他的人的工作的情况会比合并自己的分支的情况要多, 这在 git 中是非常容易的事情,和你运行 git-merge 命令没有什么区别。 事实上,远程合并的无非就是“抓取(fetch)一个远程的版本库中的工作到一个临时的标签中”, 然后再使用 git-merge 命令。

可以通过下面的命令来抓取远程版本库:

$ git-fetch <remote-repository>

根据不同的远程版本库所使用的通讯协议的路径来替代上面的 remoted-repository 就可以了。

Rsync

rsync://remote.machine/patch/to/repo.git/

SSH

remote.machine:/path/to/repo.git
or
ssh://remote.machine/patch/to/repo.git/

这是可以上传和下载的双向传输协议,当然,你要有通过 ssh 协议登录远程机器的权限。 它可以找出两端的机器提交过的对象集之中相互缺少了那些对象,从而得到需要传输的最小对象集。 这是最高效地交换两个版本库之间的对象的方式(在 git 兼容的所有传输协议当中)。

下面是个取得 SSH 远程版本库的命令例子:

$ git-fetch robin@192.168.1.168:/path/to/gittutorcn.git  (1)

(1) 这里 robin 是登录的用户名,192.168.1.168 是保存着主版本库的机器的 IP 地址。
Local directory

/path/to/repo.git/

本地目录的情况和 SSH 情况是一样的。

git Native

git://remote.machine/path/to/repo.git/

git 自然协议是设计来用于匿名下载的,它的工作方式类似于 SSH 协议的交换方式。

HTTP(S)

http://remote.machine/path/to/repo.git/

到这里可能有些朋友已经想到, 实际上,我们可以通过 Rsync, SSH 之类的双向传输方式来建立类似 CVS,SVN 这样的中心版本库模式的开发组织形式。

通过电子邮件交换工作

读过上一节之后,有的朋友可能要问,如果版本库是通过单向的下载协议发布的,如 HTTP, 我们就无法将工作上传到公共的版本库中。别人也不能访问我的机器来抓取我的工作,那怎么办呢?

不必担心,我们还有 email !别忘了 git 本来就是为了管理 Linux 的内核开发而设计的。 所以,它非常适合像 Linux Kernel 这样的开发组织形式高度分散,严重依赖 email 来进行交流的项目。

下面模拟你参加到《Git 中文教程》的编写工作中来,看看我们可以怎么通过 email 进行工作交流。 你可以通过下面的命令下载这个项目的版本库。

之后,你会在当前目录下得到一个叫 gittutorcn 的目录, 这就是你的项目的工作目录了。默认地,它会有两个分支: masterorigin,你可以直接在 master 下展开工作, 也可以创建你自己的工作分支,但是千万不要修改 origin 分支,切记! 因为它是公共版本库的镜像,如果你修改了它, 那么就不能生成正确的对公共版本库的 patch 文件了。
Note
如果你的确修改过 origin 分支的内容,那么在生成 patch 文件之前, 请用 git-reset --hard 命令将它逆转到最原始的,没经过任何修改的状态。

你可以直接在 master 下开展工作,也可以创建你自己的工作分支。 当你对项目做了一定的工作,并提交到库中。我们用 git-show-branch 命令先看下库的状态。

* [master] your buddy's contribution
! [origin] degining of git-format-patch example
--
* [master] your buddy's contribution
*+ [origin] degining of git-format-patch example

上面就假设你已经提交了一个叫 "your buddy's contribution" 的工作。 现在我们来看看怎么通过 email 来交流工作了。

$ git-fetch origin    (1)
$ git-rebase origin (2)
$ git-format-patch origin (3)

(1)更新 origin 分支,防止 origin 分支不是最新的公共版本,产生错误的补丁文件;
(2)将你在 master 上提交的工作迁移到新的源版本库的状态的基础上;
(3)生成补丁文件;

上面的几个命令,会在当前目录下生成一个大概名为 0001-your-buddy-s-contribution.txt 补丁文件, 建议你用文本工具查看一下这个文件的具体形式,然后将这个文件以附件的形式发送到项目维护者的邮箱: vortune@gmail.com

当项目的维护者收到你的邮件后,只需要用 git-am 命令,就可以将你的工作合并到项目中来。

$ git-checkout -b buddy-incomming
$ git-am /path/to/0001-your-buddy-s-contribution.txt

用 Git 协同工作

假设 Alice 在一部机器上自己的个人目录中创建了一个项目 /home/alice/project, Bob 想在同一部机器自己的个人目录中为这个项目做点什么。

Bob 首先这样开始:

$ git-clone /home/alice/project myrepo

这样就创建了一个保存着 Alice 的版本库的镜像的新目录 "myrepo"。 这个镜像保存着原始项目的起点和它的发展历程。

接着 Bob 对项目做了些更改并提交了这些更改:

(编辑一些文件)

$ git-commit -a

(如果需要的话再重复这个步骤)

当他搞定之后,他告诉 Alice 将他的东西从 /home/bob/myrepo 中引入,她只需要这样:

$ cd /home/alice/project
$ git pull /home/bob/myrepo

这样就将 Bob 的版本库中的 "master" 分支的变化引入了。 Alice 也可以通过在 pull 命令的后面加入参数的方式来引入其他的分支。

在导入了 Bob 的工作之后,用 "git-whatchanged" 命令可以查看有什么信的提交对象。 如果这段时间里以来,Alice 也对项目做过自己的修改,当 Bob 的修改被合并进来的时候, 那么她需要手动修复所有的合并冲突。

谨慎的 Alice 在导入 Bob 的工作之前,希望先检查一下。 那么她可以先将 Bob 的工作导入到一个新创建的临时分支中, 以方便研究 Bob 的工作:

$ git fetch /home/bob/myrepo master:bob-incoming

这个命令将 Bob 的 master 分支的导入到名为 bob-incoming 的分支中( 不同于 git-pull 命令,git-fetch 命令只是取得 Bob 的开发工作的拷贝, 而不是合并经来)。接着:

$ git whatchanged -p master..bob-incoming

这会列出 Bob 自取得 Alice 的 master 分支之后开始工作的所有变化。 检查过这些工作,并做过必须的调整之后, Alice 就可以将变化导入到她的 master 分支中:

$ git-checkout master
$git-pull . bob-incoming

最后的命令就是将 "bob-incoming" 分支的东西导入到 Alice 自己的版本库中的, 稍后,Bob 就可以通过下面的命令同步 Alice 的最新变化。

$ git-pull

注意不需为这个命令加入 Alice 的版本库的路径,因为当 Bob 克隆 Alice 的版本库的时候, git 已经将这个路径保存到 .git/remote/origin 文件中,它将会是所以的导入操作的默认路径。

Bob 可能已经注意到他并没有在他的版本库中创建过分支(但是分支已经存在了):

$ git branch
* master
origin

"origin" 分支,它是运行 "git-clone" 的时候自动创建的,他是 Alice 的 master 分支的原始镜像, Bob 应该永远不要向这个分支提交任何东西。

如果 Bob 以后决定在另外一部主机上开展工作,那么他仍然需要通过 SSH 协议从新克隆和导入( Alice 的版本库):

$ git-clone alice.org:/home/alice/project/ myrepo

我们可以使用 git 自然协议,或者是 rsync, http 等协议的任何一种,详情请参考 git-pull

Git 同样可以建立类似 CVS 那样的开发模式,也就是所有开发者都向中心版本库提交工作的方式, 详情参考 git_pushgit for CVS users

为版本库打包

在前面,我们已经看到在 .git/objects/??/ 目录中保存着我们创建的每一个 git 对象。 这样的方式对于自动和安全地创建对象很有效,但是对于网络传输则不方便。 git 对象一旦创建了,就不能被改变,但有一个方法可以优化对象的存储,就是将他们“打包到一起”。

$ git repack

上面的命令让你做到这点,如果你一直是做着我们的例子过来的, 你现在大约会在 .git/objects/??/ 目录下积累了17个对象。 git-repack 会告诉你有几个对象被打包了, 并且将他们保存在 .git/objects/pack 目录当中。

Note
你将会看到两个文件,pack-*.pack and pack-*.idx.git/objects/pack 目录。他们的关系是很密切的, 如果你手动将他们拷贝到别的版本库中的话,你要决定将他们一起拷贝。 前者是保存着所有被打包的数据的文件,后者是随机访问的索引。

如果你是个偏执狂,就运行一下 git-verity-pack 命令来检查一下有缺陷的包吧, 不过,其实你无须太多担心,我们的程序非常出色 ;-).

一旦你已经对那些对象打包了,那么那些已经被打过包的原始的对象,就没有必要保留了。

$ git prune-packed

会帮你清楚他们。

如果你好奇的话,你可以在执行 git-prune-repacked 命令之前和之后, 都运行一下 find .git/objects -type f,这样你就能看到有多少没有打包的对象, 以及节省了多少磁盘空间。

Note
git pull git-pull 对于 HTTP 传输来说,一个打包过的版本库会将一定数量的 相关联的对象放进一个有关联性的打包中。如果你设想多次从 HTTP 公共版本库中导入数据, 你也许要频繁地 reapck & prune,要么就干脆从不这样做。

如果你此时再次运行 git-repack,它就会说 "Nothing to pack"。 要是你继续开发,并且积累了一定数量的变迁,再运行 git-repack 将会创建一个新的包, 它会包含你自上次对库打包以来创建的对象。我们建议你尽快在初始化提交之后打包一下你的版本库( 除非你现在的项目是个涂鸦式的草稿项目),并且在项目经历过一段很活跃的时期时, 再运行 git-repack 一下。

当一个版本库通过 git-pushgit-pull 命令来同步源版本库中打包过的对像的时候, 通常保存到目标版本库中的是解包了的对象,除非你使用的是 rsync(远程同步协议)协议的传输方式。 正是这种容许你在两头的版本库中有不同的打包策略的方式,他意味着你也许在过一段时间之后, 需要在两头的版本库中都重新打包一下。

发布你的工作

我们可以通过一个远程的版本库来利用他人的工作,但是,你如何准备一个自己的版本库来供其他人下载呢? 你在自己的工作目录下进行工作,这样你的版本库就被作为.git的一个子目录放在你的工作树下。 你可以让其他人来远程的访问你的版本库,但是实际上这不是通常的做法。推荐的做法是创建一个公共的版本库, 让它可供其他人访问,并且,当你在你的工作目录下做了很好的改动时,你可以更新到公共的版本库中。这通常称为pushing。

Note
公共版本库是可以被映像的,kernel.org上的git公共版本库也是这样管理的。

从你的本地的(私有的)版本库中发布改动到你的远程的(公共的)版本库中需要远程机器上的写权限。你需要一个SSH的 帐号来运行一个简单的命令,git-receive-pack。 首先,你需要在远程机器上创建一个空的版本库来存放你的公共版本库。这个空版本库以后将通过pushing来保持更新。 显然,这个版本库之需要在开始的时候创建一次。

Note
git push使用一对命令,git-send-pack在本地机上运行,git-receive-pack在远程机上运行。 这两个命令通过SSH连接来进行通讯。

你本地的版本库的git目录通常是.git,但是你的公共版本库通常还要加上你的项目名,即.git。 让我们来为my-git创建这样一个版本库。首先,登入远程的机器,创建一个空目录(如果你选择HTTP作为发布方法, 这个空目录需要建在web server的根目录下面):

$ mkdir my-git.git

然后运行git init-db命令将这个目录加入git版本库中,这里,因为这个版本库的名字不是通常的.git, 我们需要稍微改动一下命令:

$ GIT_DIR=my-git.git git-init-db

有很多种传输方式可以发布公共版本库。这里,要确认这个目录可以通过你选择的传输方式来被其他人访问。你也需要确认 你有git-receive-pack这个程序在$PATH这个路径下。

Note
当你直接运行程序的时候,很多sshd的安装版并没有将你的shell作为登陆的shell;这就是说,如果你登陆的shell是bash 的话,被读到的是.bashrc而不是.bash_profile。确认.bashrc设置好了$PATH路径,这样你 才可以运行git-receive-pack命令。
Note
如果你打算通过HTTP来发布这个版本库,这是你就应该运行命令chmod +x my-git.git/hooks/post-update。这确认了每次 你导入数据到这个版本库中,git-update-server-info能够被执行。

现在你的“公共的版本库”可以接受你的任何改动了。回到你的本地机上,运行命令:

$ git push :/path/to/my-git.git master

该命令将你的公共版本库和你当前的版本库中指定名称的分支头部同步(这里是master)。举一个实际的例子,你可以 这样来更新公共的git版本库。Kernel.org的镜像网络也这样来同步其他公共的可访问的机器:

$ git push master.kernel.org:/pub/scm/git/git.git/

将工作捆绑到一起

通过 git 的分支功能,你可以非常容易地做到好像在同一时间进行许多“相关-或-无关”的工作一样。

我们已经通过前面的 "fun and work" 使用两个分支的例子,看到分支是怎么工作的。 这样的思想在多于两个的分支的时候也是一样的,比方说,你现在在 master 的头, 并有些新的代码在 master 中,另外还有两个互不相关的补丁分别在 "commit-fix" 和 "diff-fix" 两个分支中。

$ git show-branch
! [commit-fix] Fix commit message normalization.
! [diff-fix] Fix rename detection.
* [master] Release candidate #1
---
+ [diff-fix] Fix rename detection.
+ [diff-fix~1] Better common substring algorithm.
+ [commit-fix] Fix commit message normalization.
* [master] Release candidate #1
++* [diff-fix~2] Pretty-print messages.

两个补丁我们都测试好了,到这里,你想将他们俩合并起来, 于是你可以先合并 diff-fix ,然后再合并 commit-fix,像这样:

$ git merge 'Merge fix in diff-fix' master diff-fix
$ git merge 'Merge fix in commit-fix' master commit-fix

结果如下:

$ git show-branch
! [commit-fix] Fix commit message normalization.
! [diff-fix] Fix rename detection.
* [master] Merge fix in commit-fix
---
- [master] Merge fix in commit-fix
+ * [commit-fix] Fix commit message normalization.
- [master~1] Merge fix in diff-fix
+* [diff-fix] Fix rename detection.
+* [diff-fix~1] Better common substring algorithm.
* [master~2] Release candidate #1
++* [master~3] Pretty-print messages.

然而,当你确信你手头上的确是一堆互不相关的项目变化时,就没有任何理由将这堆东西一个个地合并( 假如他们的先后顺序很重要,那么他们就不应该被定以为无关的变化), 你可以一次性将那两个分支合并到当前的分支中,首先我们将我们刚刚做过的事情逆转一下, 我们需要通过将 master 分支重置到 master~2 位置的方法来将它逆转到合并那两个分支之前的状态。

$ git reset --hard master~2

你可以用 git-show-branch 来确认一下的确是回到了两次 git-merge 的状态了。 现在你可以用一行命令将那两个分支导入的方式来替代两次运行( 也就是所谓的 炮制章鱼 -- making an Octopusgit-merge

$ git pull . commit-fix diff-fix
$ git show-branch
! [commit-fix] Fix commit message normalization.
! [diff-fix] Fix rename detection.
* [master] Octopus merge of branches 'diff-fix' and 'commit-fix'
---
- [master] Octopus merge of branches 'diff-fix' and 'commit-fix'
+ * [commit-fix] Fix commit message normalization.
+* [diff-fix] Fix rename detection.
+* [diff-fix~1] Better common substring algorithm.
* [master~1] Release candidate #1
++* [master~2] Pretty-print messages.

注意那些不适合制作章鱼的场合,尽管你可以那样做。一只“章鱼”往往可以使项目的提交历史更具可读性, 前提是你在同一时间导入的两份以上的变更是互不关联的。 然而,如果你在合并任何分支的过程中出现合并冲突,并且需要手工解决的话, 那意味着这些分支当中有相互干涉的开发工作在进行,那么你就应该将这个两个冲突先合并, 并且记录下你是如何解决这个冲突,以及你首先处理他们的理由。(译者按:处理完冲突之后, 你就可以放心制作“章鱼”了) 否则的话将会造成项目的发展历史很难跟踪。

管理版本库

版本库的管理员可以用下面的工具来建立和维护版本库。

  • git-daemon(1) 容许匿名下载版本库。

  • git-shell(1) 面向中心版本库模式 的用户的类似 受限的 shell 的命令。

update hook howto 一个很好的管理中心版本库的例子。

例子

在 /pub/scm 上运行 git 守护进程
$ grep git /etc/inet.conf
git stream tcp nowait nobody \
/usr/bin/git-daemon git-daemon --inetd --syslog --export-all /pub/scm

这个配置行应该在配置文件中用一行来写完。

仅给开发者 push/pull 的访问权限。
$ grep git /etc/passwd (1)
alice:x:1000:1000::/home/alice:/usr/bin/git-shell
bob:x:1001:1001::/home/bob:/usr/bin/git-shell
cindy:x:1002:1002::/home/cindy:/usr/bin/git-shell
david:x:1003:1003::/home/david:/usr/bin/git-shell
$ grep git /etc/shells (2)
/usr/bin/git-shell


(1) 将用户的登录 shell 设定为 /usr/bin/git-shell,
它除了运行 "git-push" 和 "git-pull" 不能做任何事。
这样用户就可以通过 ssh 来访问机器。
(2) 许多的发行版需要在 /etc/shells 配置文件中列明要用什么 shell 来作为登录 shell。
CVS - 模式的公共库。
$ grep git /etc/group (1)
git:x:9418:alice,bob,cindy,david
$ cd /home/devo.git
$ ls -l (2)
lrwxrwxrwx 1 david git 17 Dec 4 22:40 HEAD -> refs/heads/master
drwxrwsr-x 2 david git 4096 Dec 4 22:40 branches
-rw-rw-r-- 1 david git 84 Dec 4 22:40 config
-rw-rw-r-- 1 david git 58 Dec 4 22:40 description
drwxrwsr-x 2 david git 4096 Dec 4 22:40 hooks
-rw-rw-r-- 1 david git 37504 Dec 4 22:40 index
drwxrwsr-x 2 david git 4096 Dec 4 22:40 info
drwxrwsr-x 4 david git 4096 Dec 4 22:40 objects
drwxrwsr-x 4 david git 4096 Nov 7 14:58 refs
drwxrwsr-x 2 david git 4096 Dec 4 22:40 remotes
$ ls -l hooks/update (3)
-r-xr-xr-x 1 david git 3536 Dec 4 22:40 update
$ cat info/allowed-users (4)
refs/heads/master alice\|cindy
refs/heads/doc-update bob
refs/tags/v[0-9]* david

(1) 将所有的开发人员都作为 git 组的成员。
(2) 并且给予他们公共版本库的写权限。
(3) 用一个在 Documentation/howto/ 中的 Carl 写的例子来实现版本库的分支控制策略。
(4) Alice 和 Cindy 可以提交入 master 分支,只有 Bob 能提交入 doc-update 分支,
David 则是发行经理只有他能创建并且 push 版本标签。
支持默协议传输的 HTTP 服务器。
dev$ git update-server-info (1)
dev$ ftp user@isp.example.com (2)
ftp> cp -r .git /home/user/myproject.git

(1) 保证 info/refs 和 object/info/packs 是最新的。
(2) 上传到你的 HTTP 服务器主机。

项目开发的模式推介

尽管 git 是一个正式项目发布系统,它却可以方便地将你的项目建立在松散的开发人员组织形式上。 Linux 内核的开发,就是按这样的模式进行的。在 Randy Dunlap 的著作中("Merge to Mainline" 第17页) 就有很好的介绍(http://tinyurl.com/a2jdg)。

需要强调的是正真的非常规的开发组织形式, git 这种组织形式,意味着对于工作流程的约束,没有任何强迫性的原则。 你不必从唯一一个远程版本库中导入(工作目录)。

项目领导人(project lead)的工作推介

  1. 在你自己的本地机器上准备好主版本库。你的所有工作都在这里完成。

  2. 准备一个能让大家访问的公共版本库。

    如果其他人是通过默协议的方式(http)来导入版本库的,那么你有必要保持这个 默协议的友好性git-init-db 之后,复制自标准模板库的 $GIT_DIR/hooks/post-update 将包含一个对 git-update-server-info 的调用,但是 post-update 默认是不能唤起它自身的。 通过 chmod +x post-update 命令使能它。这样让 git-update-server-info 保证那些必要的文件是最新的。

  3. 将你的主版本库推入公共版本库。

  4. git-repack 公共版本库。这将建立一个包含初始化提交对象集的打包作为项目的起始线, 可能的话,执行一下 git-prune,要是你的公共库是通过 pull 操作来从你打包过的版本库中导入的。

  5. 在你的主版本库中开展工作,这些工作可能是你自己的最项目的编辑, 可能是你由 email 收到的一个补丁,也可能是你从这个项目的“子系统负责人” 的公共库中导入的工作等等。

    你可以在任何你喜欢的时候重新打包你的这个私人的版本库。

  6. 将项目的进度推入公共库中,并给大家公布一下。

  7. 尽管一段时间以后,"git-repack" 公共库。并回到第5步继续工作。

项目的子系统负责人(subsystem maintainer)也有自己的公共库,工作流程大致如下:

  1. 准被一个你自己的工作目录,它通过 git-clone 克隆自项目领导人的公共库。 原始的克隆地址(URL)将被保存在 .git/remotes/origin 中。

  2. 准备一个可以给大家访问的公共库,就像项目领导人所做的那样。

  3. 复制项目领导人的公共库中的打包文件到你的公共库中, 除非你的公共库和项目领导人的公共库是在同一部主机上。 以后你就可以通过 objects/info/alternates 文件的指向来 浏览它所指向的版本库了。

  4. 将你的主版本库推入你的公共版本库,并运行 git-repack, 如果你的公共库是通过的公共库是通过 pull 来导入的数据的话, 再执行一下 git-prune
  5. 在你的主版本库中开展工作。这些工作可能包括你自己的编辑,来自 email 的补丁, 从项目领导人,“下一级子项目负责人”的公共库哪里导入的工作等等。

    你可以在任何时候重新打包你的私人版本库。

  6. 将你的变更推入公共库中,并且请“项目领导人”和“下级子系统负责人”导入这些变更。

  7. 每隔一段时间之后,git-repack 公共库。回到第 5 步继续工作。

“一般开发人员”无须自己的公共库,大致的工作方式是:

  1. 准备你的工作库,它应该用 git-clone 克隆自“项目领导人”的公共库( 如果你只是开发子项目,那么就克隆“子项目负责人”的)。 克隆的源地址(URL)会被保存到 .git/remotes/origin 中。

  2. 在你的个人版本库中的 master 分支中开展工作。

  3. 每隔一段时间,向上游的版本库运行一下 git-fetch origin 。 这样只会做 git-pull 一半的操作,即只克隆不合并。 公共版本库的新的头就会被保存到 .git/refs/heads/origins

  4. git-cherry origin 命令,看一下你有什么补丁被接纳了。 并用 git-rebase origin 命令将你以往的变更迁移到最新的上游版本库的状态中。 (关于 git-rebase 命令,请参考 git-rebase

  5. git-format-patch origin 生成 email 形式的补丁并发给上游的维护者。 回到第二步接着工作。

Last updated 27-Mar-2006 15:20:34 UTC

学习 Git

作者:孔建军

1 Git 介绍

Git 版本控制工具的作者是Linux之父Linus Trovalds,最初是专门针对Linux内核开发的特点编写的,即协作人员异地分布、人数众多、项目规模巨大、复杂度高等。与常用的版本控制 CVS,Subversion等不同,它采用了分布式版本库的方式,不毕服务器断软件支持,使源代码的发布和维护极其方便。Git的本地查询、搜索,补丁 制作、提交和应用,项目跟踪,分支合并等功能,可以大大提高开发效率,具有较强的灵活性。有人认为Git太艰涩难懂,实际上结合一些有用的脚本命令使用, 会使其变得非常好用。
Linux kernel、Wine、U-boot等著名项目都采用Git管理,页面(http://git.kernel.org/)列举的项目全是用git维护的,比较有趣的是Git本身也采用Git进行版本控制,详见:http://git.kernel.org/?p=git/git.git;a=summary

2 Git 配置

Git命令的使用,一般有两种两种形式,一种是git后面带参数(如:git add),另一种是直接减号连接的一条命令(如:git-add),后面讲解全部使用后者,这样可以避免空格的使用带来的问题。

  • $ ssh-keygen -b 1024 -t dsa 生成密钥,用户通信加解密。1024为生成密钥大小,dsa为指定的加密类型。如果接受默认设置,那么私钥和公钥文件分别位于:~/.ssh /id_dsa和~/.ssh/id_dsa.pub。用户需要向服务器管理员提供公钥(id_dsa.pub),在用户同步版本库时对用户进行身份认 证。用户必须妥善保管私钥。
  • $ git-config user.name jianjun 配置用户名,在生成补丁、日志时使用。git-config命令带--global选项是对所有用户信息进行配置,默认只针对对当前用户。
  • $ git-config user.email jianjun@zeuux.org 配置用户邮件,用于发送补丁。
  • $ git-config sendemail.smtpserver /usr/local/bin/msmtp 配置补丁邮件的发送软件,这里也可以用其他的,如sendmail。
  • $ git-config --list 用户可以通过git-config的其他选项来对git做其他配置,--list可以查看用户已经选项。如:
    $ git-config --list
    user.name=jianjun
    user.email=jianjun@zeuux.com
    sendemail.smtpserver=/usr/bin/msmtp
    diff.color=auto
    pack.window=64
    merge.summary=true

3 Git 使用

  • 创建一个版本库
    $ mkdir myDir
    $ cd myDir
    $ git-init-db
    Initialized empty Git repository in .git/
    创建工作目录 myDir,进入工作目录,并初始化版本库。此时会在myDir/目录下生成一个名为.git的目录,里边有三个文件,分别是存放指向项目当前分支索引信息的HEAD文件、包含项目所有对象的object子目录、保存指向对象索引的refs目录。
  • 植入内容跟踪信息
    $ echo "new world" > newfile
    $ git-add newfile
    创建新文件newfile,写入"new world",并用git-add命令将此文件加入到版本库文件索引当中。
  • 提交内容到版本库
    $ git-commit -m "add newfile" newfile
    Created initial commit 5ce224d: add newfile
    1 files changed, 2 insertions(+), 0 deletions(-)
    create mode 100644 newfile
    把前面的修改提交到版本库中,前提是已经用git-add命令把此文件加入到版本库文件索引当中。
  • 查看当前的工作
    $ git-status
    # On branch master
    # Changes to be committed:
    # (use "git reset HEAD ..." to unstage)
    # new file: h
    $ echo "Love zeuux" >> newfile
    $ git-diff
    diff --git a/newfile b/newfile
    index e83176b..7d02259 100644
    --- a/newfile
    +++ b/newfile
    @@ -1 +1,2 @@
    new world
    +Love zeuux
    git-status可查看当前分支状态,git-diff查看当前分支更改情况。
  • 管理分支
    $ git-branch mybranch
    $ git-checkout mybranch
    Switched to branch "mybranch"
    $ git-branch -D mybranch
    Deleted branch mybranch.
    创建名为mybranch的分支,并把以后工作转移到这个分支上开展。git-branch带-D选项为删除指定的分支,不能删除用户所在当前分支,必须用git-checkout切换到其他分支才行。
  • 查看项目的发展变化和比较差异
    $ git-show-branch
    * master
    mybranch
    $ git-whatchanged
    commit 7182ae4912487692d4f91ded1e74d99e0fc12e49
    Author: Jianjun Kong
    Date: Tue Jul 8 23:45:27 2008 +0800
    add new line
    :000000 100644 0000000... 6991a4a... A h
    commit cc08d852365d605520d71a3352841a7eadf64428
    Author: Jianjun Kong
    Date: Tue Jul 8 23:42:52 2008 +0800
    update
    :100644 100644 7d02259... 033d3e5... M newfile
    $ git-diff mybranch
    diff --git a/h b/h
    new file mode 100644
    index 0000000..6991a4a
    --- /dev/null
    +++ b/h
    @@ -0,0 +1,2 @@
    +helo
    git-show-branch用来列出当前版本库中的所有分支,git-whatchanged可以列出项目开发中的修改历史。git-dff mybranch是来比较当前分支与mybranch分支的差异的,当然也可使用 git-diff mybranch anotherbranch对任意两个分支做对比。
  • 合并两个分支
    $ git-checkout master
    $ git-merge "Merge work in mybranch" mybranch
    切换到master分支,并把mybranch上的工作合并到master上来。此时有可能有冲突无法合并,会给出警告,用户可根据提示手动合并一些文件。
  • 逆转与恢复
    $ git-reset --soft HEAD^
    逆转上次提交的版本进度
    $ git-reset --hard 7182ae4912487692d4f91ded1e74d99e0fc12e49
    强行逆转到索引指定的版本,--hard选项要慎重使用,有事可能破坏正常文件。
    $ git-revert
    也可撤销上次对版本库的提交,但这本身也会产生一个commit,用得多了会使log看起来不那么干净。
  • 用 Git 协同工作
    $ git-clone git://repo.or.cz/xylftp.git 
    克隆远程版本库
    $ git-push git+ssh://kongjianjun@repo.or.cz/srv/git/pigeons.git master:master
    将同步本地版本库中master分支同步到远程服务器上版本库的master分支
    $ git-pull git+ssh://kongjianjun@repo.or.cz/srv/git/pigeons.git master:master
    将远程服务器上的版本库中的master分支同步到本地版本库的master分支
    $ git-fetch orign
    克隆上游版本库
    $ git-format-patch -s orign
    0001-add-new-line.patch
    对比当前分支与orign生成补丁,-s选项指定生成补丁中带有Signed-off-by: jianjun
    $ git-send-email --to zeuux-www@zeuux.org --cc wangcong@zeuux.org 0001-add-new-line.patch
    将补丁0001-add-new-line.patch发送到zeuux-www@zeuux.org,并抄送一份给wangcong@zeuux.org
  • 为版本库打包
    $ git-repack
    将对象打包,并保存在 .git/objects/pack 目录当中
    $ git-prune-packed
    清楚那些已经被打过包的原始的对象
  • 特殊文件 工作目录myDir/下有一个名为.gitignore的文件,用来排除一些文件,包括程序编译的中间文件和目标文件等,当然也可包括它自己在内。没用使用git-add添加的文件,不会被跟踪,但会在git-commit等是输出多余信息,也会使日志变得很乱。
    .gitignore
    .*
    *.o
    *.o.*
    *.a
    *.s
    *.ko
    *.so
    *.so.dbg
    *.mod.c
    *.i
    *.lst
    *.symtypes
    *.order

4 Git的项目开发模式

Git作为一个正式项目发布系统,它能够极其有效的组织松散的开发人员,是一种非常规的开发组织形式,对工作流程没有任何强迫性的约束,比较灵活。

  • 项目领导人 1.在自己本地机器上创建主版本库,并在此进行所有工作。
    2.准备一个能让大家访问的公共版本库。
    3.将你的主版本库推入公共版本库。
    4.git-repack 公共版本库。这将建立一个包含初始化提交对象集的打包作为项目的起始线。
    5.在你的主版本库中开展工作,包括自己的工作、收到的邮件补丁、“子系统负责人” 的公共库中导入的工作等等。
    6.将项目的进度推入公共库中,并给大家公布一下。
    7.尽管一段时间以后,"git-repack" 公共库。并回到第5步继续工作。
  • 项目的子系统负责人 1.新建一个你自己的工作目录,通过 git-clone 克隆项目领导人的公共库。
    2.准备一个可以给大家访问的公共库,就像项目领导人所做的那样。
    3.复制项目领导人的公共库中的打包文件到你的公共库中。
    4.将你的主版本库推入你的公共版本库,并运行 git-repack,如果你的公共库是通过的公共库是通过pull来导入的数据的话,再执行一下git-prune。
    5.在你的主版本库中开展工作。这些工作包括自己的工作、收到的邮件补丁、“下一级子项目负责人”的公共库中导入的工作等等。
    6.将你的变更推入公共库中,并且请“项目领导人”和“下级子系统负责人”导入这些变更。
    7.每隔一段时间之后,git-repack 公共库。回到第 5 步继续工作。
  • 一般开发人员 1.通过git-clone克隆“项目领导人”的公共库,作为自己的工作库。
    2.在你的个人版本库中的 master 分支中开展工作。
    3.每隔一段时间,向上游的版本库运行一下 git-fetch origin 。这样只会做 git-pull 一半的操作,即只克隆不合并。
    4.用 git-cherry origin 命令,看一下你有什么补丁被接纳了。并用 git-rebase origin 命令将你以往的变更迁移到最新的上游版本库的状态中。
    5.用git-format-patch origin生成email形式的补丁并发给上游的维护者。回到第二步接着工作。

5 免费git项目注册

网址:http://repo.or.cz
注册用户:http://repo.or.cz/m/reguser.cgi
注册项目:http://repo.or.cz/m/regproj.cgi
注册用户需要提供自己的公钥,可由上面提到的ssh-keygen生成。

0、使用git-init-db在本地创建版本库;
1、使用git-add添加要跟踪的文件;
2、修改,并使用git-commit提交修改到本地版本库;
3、使用git-push命令将本地版本库同步到服务器端;
4、其他用户可使用git-clone来克隆项目,并在本地开展自己的工作。

6 总结

7 参考资料

February 26

Collection Class Notes------especial CTypedPtrList

Collection classes covered are Collection classes not covered are
Arrays  

CArray

CTypedPtrArray

CObArray

CPtrArray

CByteArray

CDWordArray

CStringArray

CUintArray

CWordArray

Lists  

CTypedPtrList

CObList

CPtrList

CStringList
Maps  

CMap

CTypedPtrMap

CMapWordToPtr

CMapPtrToWord

CMapPtrToPtr

CMapStringToPtr

CMapWordToOb

CMapStringToOb

CMapStringToString

Expand the Header Files folder, and open file StdAfx.h. At the end of the file, type:
#include <afxtempl.h>    // MFC templates
/////////////////////////////////////////////////////////////////////////
CTypedPtrList < class BASE_CLASS, class TYPE >

    BASE_CLASS  Base class of the typed pointer list class;
                must be a pointer list class (CObList or CPtrList).

    TYPE        Type of the elements stored in the base-class list.

    The CTypedPtrList class provides a type-safe 
    “wrapper” for objects of class
    CPtrList. When you use CTypedPtrList 
    rather than CObList or CPtrList, the
    C++ type-checking facility helps 
    eliminate errors caused by mismatched
    pointer types.

    In addition, the CTypedPtrList wrapper 
    performs much of the casting that
    would be required if you used CObList or CPtrList.

    ==================================================
    Class Members
    ==================================================
    AddHead
        POSITION AddHead( TYPE newElement );
        void AddHead( CTypedPtrList<BASE_CLASS, TYPE> *pNewList );
    AddTail
        POSITION AddTail( TYPE newElement );
        void AddTail( CTypedPtrList<BASE_CLASS, TYPE> *pNewList );
    GetAt
        TYPE& GetAt( POSITION position );
        TYPE GetAt( POSITION position ) const;
    GetHead
        TYPE& GetHead( );
        TYPE GetHead( ) const;
    GetNext
        TYPE& GetNext( POSITION& rPosition );
        TYPE GetNext( POSITION& rPosition ) const;
    GetPrev
        TYPE& GetPrev(POSITION& rPosition );
        TYPE GetPrev( POSITION& rPosition ) const;
    GetTail
        TYPE& GetTail( );
        TYPE GetTail( ) const;
    RemoveHead
        TYPE RemoveHead( );
    RemoveTail
        TYPE RemoveTail( );
    SetAt
        void SetAt( POSITION pos, TYPE newElement );

    ==================================================
    Create
    ==================================================
    typedef CTypedPtrList<CPtrList, CMyStruct*> CMyStructList;
    CMyStructList m_myPtrList;

    typedef CTypedPtrList<CObList, CMyObject*>  CMyObList;
    CMyObList m_myObList;

    ==================================================
    Insert
    ==================================================
    CMyStruct* pMyStruct = new CMyStruct();
    pMyStruct->m_int = 1234;
    pMyStruct->m_float = 12.34f;
    pMyStruct->m_str.LoadString(IDS_INITIAL_STRING);
    m_myPtrList.AddTail(pMyStruct);

    m_myPtrList.InsertBefore(pos, pMyStruct);

    CMyObject* pMyObject = new CMyObject();
    m_myObList.AddTail(pMyObject);

    ==================================================
    Iterate
    ==================================================
    POSITION pos = m_myPtrList.GetHeadPosition();
    while( pos != NULL )
    {
        CMyStruct* pMyStruct = m_myPtrList.GetNext( pos );
    }

    ==================================================
    Find
    ==================================================
    pos = m_myPtrList.Find(pMyStruct);

    ==================================================
    Update
    ==================================================
    m_myPtrList.SetAt(pos, pMyStruct);

    ==================================================
    Delete
    ==================================================
    m_myPtrList.RemoveAt(pos);

    POSITION pos = m_myPtrList.GetHeadPosition();
    while (pos != NULL)
    {
        delete m_myPtrList.GetNext(pos);
    }
    m_myPtrList.RemoveAll();

    while (!m_myObList.IsEmpty())
    {
        delete m_myObList.GetHead();
        m_myObList.RemoveHead();
    }

    ==================================================
    Serialize
    ==================================================
    nCount = (WORD)m_myPtrList.GetCount();
    if (ar.IsStoring())
    {
        ar << nCount;
        pos = m_myPtrList.GetHeadPosition();
        while (pos != NULL)
        {
            CMyStruct* pMyStruct = m_myPtrList.GetNext(pos);
            w = (WORD)pMyStruct->m_int;
            ar << w;
            ar << pMyStruct->m_float;
            ar << pMyStruct->m_str;
            nCount--;
        }
        ASSERT(nCount == 0);
    }
    else
    {
        ar >> nCount;
        while (nCount-- > 0)
        {
            CMyStruct* pMyStruct = new CMyStruct;
            ar >> w;
            pMyStruct->m_int = w;
            ar >> pMyStruct->m_float;
            ar >> pMyStruct->m_str;
            m_myPtrList.AddTail(pMyStruct);
        }
    }

    m_myObList.Serialize(ar);
    // Note: CMyObject serializes itself
    void CMyObject::Serialize(CArchive& ar)
    {
        CObject::Serialize( ar );
        if( ar.IsStoring() )
            ar << i;
        else
            ar >> i;
    }
January 13

Index.dat Analyzer v2.5

Index.dat Analyzer is a tool to view, examine and delete contents of index.dat files.
Index.dat files are hidden files on your computer that contain all tracks of your online activity, where have you been on internet, what sites you visited, list of URL-s, files and documents you recently accessed. Index.dat files stored on your computer are obviously a potential privacy threat as they can be found and viewed without your knowledge.