如何控制源代码易语言反编译成源代码功后才能提交到库里

ubuntu下erlang源代码的编译与安装 - 好记性不如烂博客 - ITeye博客
博客分类:
今天重装了ubuntu系统(ubuntu server),发现开发环境几乎是裸的。再重新编译安装erlang需要一些关键库,去年装过,现在又忘了,记之备查。
当然可以用apt-get直接安装erlang,不过版本有些旧而已,本文说的是如何从源代码编译出一个在ubuntu下可用的erlang。
可以用如下命令察看apt安装erlang所依赖的其它库:
sudo apt-get build-dep erlang
不过这里的许多库其实不是必须的,比如openjdk,fop等等。
1. 基础开发工具的安装
指gcc/g++、make
sudo apt-get install build-essential
2. 其它Erlang依赖的关键库
sudo apt-get install libncurses5-dev
sudo apt-get install libssl-dev
基本上安装以上软件后就可以顺利的编译出一个可用的erlang/OTP及其虚拟机了:
./configure && make
sudo make install
缺省情况下,Erlang Home目录是/usr/local/lib/erlang/
缺少的是:
对systemtap的支持,
JInterface的支持,
wx的GUI库(用不了observer),
ODBC的支持,
Erlang文档的生成
如果还需要以上功能,继续往下看。
3. 老版本的Erlang可能依赖的其它库
现在m4不再是必须的了,老版本的erlang可能需要
sudo apt-get install m4
还有这些,也不是必须的,可能老的版本需要
sudo apt-get install libncursesw5-dev libreadline6-dev
4. 其它不影响erlang源代码编译的非必需软件的安装
4.0 systemtap的支持
首先安装systemtap需要linux内核debug symbols的支持,因此需要重新编译自己的内核。
好在有人为ubuntu-10.xx提供了linux-image-dbgsym的apt安装源,省下了这一步。详见
安装好内核dbgsym后,开始安装systemtap和systemtap-sdt-dev:
sudo apt-get install systemtap systemtap-sdt-dev
在编译Erlang/OTP时要指定systemtap
./configure --with-dynamic-trace=systemtap --enable-vm-probes --enable-native-libs
注意如果只装systemtap,没有安装systemtap-sdt-deb会出现如下错误:
configure: error: No dtrace utility found.
4.1. JDK的安装
因为JInterface的编译需要java编译器javac(JInterface是JDK5的, 若缺省JDK低于1.5,make到JInterface时依然会出错)。
JInterface不是必须的,不过要坚持使用的话就需要安装JDK了。有两种安装方法:
ubuntu可以通过apt-get安装,也可以去oracle官方网站下载安装包手工安装。
4.1.1 apt-get安装
很久以前,ubuntu是可以直接apt-get安装java的:
sudo apt-get install sun-java6-jdk
从Ubuntu 10.04开始,apt-get不再缺省提供sun-jdk,需要自己手动为apt添加JDK源
1) 在Ubuntu 10.04中手动添加源:
sudo apt-add-repository "deb / lucid partner"
2) 在Ubuntu 10.10中,手动添加源:
sudo apt-add-repository "deb /ubuntu maverick partner"
3) 在Ubuntu 11.10中,手动添加源:
sudo add-apt-repository ppa:ferramroberto/java
完成安装:
sudo apt-get update
sudo apt-get install sun-java6-jdk
4) 在Ubuntu 12.10中,手动添加源:
sudo add-apt-repository ppa:webupd8team/java
完成安装:
sudo apt-get update
sudo apt-get install oracle-java6-installer
4.1.2 下载JDK安装包安装
当然也可以去oracle的网站直接下载JDK(需要注册)安装,jrockit和sun的JDK都可以
sun:
/technetwork/java/javase/downloads/index.html
jrockit:
/technetwork/middleware/jrockit/downloads/index.html
4.1.3 安装完成后需要为JDK设置环境变量
一般是设置JAVA_HOME和PATH(我习惯在/etc/profile中设置);
JAVA_HOME=/my/path/to/jdk
PATH=$JAVA_HOME/bin:$PATH
注:
安装完jdk后最好检查一下javac,因为新安装的JDK不一定会自动成为缺省的JDK。检查java编译器的版本:
javac -version
4.2 还有一些其他非关键库
比如关系数据库,图形界面。
sudo apt-get install libc6 (Ubuntu 9.10以后自动带这个,所以不用再装了)
sudo apt-get install unixodbc unixodbc-dev
ODBC方式提供对传统关系数据库支持
erlang的新GUI工具是基于wxWidgets开发的,因此要使用这些工具必须安装wxWidgets
在ubuntu下安装wx:
sudo apt-get install freeglut3-dev libwxgtk2.8-dev
注意只有wx也不会顺利的make出支持GUI的erlang/otp,freeglut3-dev也是必须的,否则提示如下错误:
Can not link the wx driver, wx will NOT be useable
老版本的erlang使用的旧图形工具(如toolbar、appmon、pman、debugger、tv等),都是用的tcl/tk的wish做GUI界面,因此需要安装tk
sudo apt-get install tk8.5
tk不会影响老版本erlang的编译和安装,但是当在开发中想使用toolbar提供的一系列图形监控工具时就会出现问题。
4.3 生成erlang帮助文档所需要的软件
在R13B03后,要想自动生成帮助文件,需要安装xsltproc和fop:
sudo apt-get install xsltproc
sudo apt-get install fop
都挺大的(上百MB),如果不在乎文档,可以不安装,不会影响erlang的make。
5. 安装man手册
官方除了源码包,还提供了man手册的下载,将该man压缩包下载后,解压缩到erlang home目录下,以后可以用erl -man命令察看相关模块的定义和说明了,如察看lists模块:
erl -man lists
6. 卸载
缺省情况下,Erlang home目录是/usr/local/lib/erlang/, 直接删掉该目录即可卸载erlang otp。
如果自己设置了ERL_LIBS之类的环境变量,也记得删掉对应的目录。
cryolite不保证blog文章的稳定性,如有时间和需要随时会修改原文。
7. 其它安装方法
7.1 用clang编译erlang
关于clang可以看这里()的介绍。
ubuntu下有两种clang安装方法
1) 可以apt-get安装clang
sudo apt-get install clang
然后
CC=clang CXX=clang ./configure
2) 也可以去最新的编译好的官方clang,然后
CC=/path/to/clang+llvm-3.0/bin/clang CXX=/path/to/clang+llvm-3.0/bin/clang ./configure
这样完成配置后就可以make R15B了。
make
sudo make install
但是R14B04不能成功make,在Mac OS X下设置CFLAGS 为 -Qunused-arguments编译成功。但在ubuntu下gcc不支持此参数。。。
我比较了下R14B和,发现只有后者有提到clang,估计R14B可能官方不支持clang。
理论上clang也能编译R14B的,有人手动修改编译脚本成功完成编译,但编译出的R14B虚拟机运行时似乎有问题,所以我就不折腾R14B的编译了。
7.2. erlang-solutions官方提供的二进制安装包
现在erlang-solutions开始正式提供编译好的Erlang OTP,见
提供各种平台(Mac OSX,ubuntu,linux,OpenSUSE,CentOS,Debian)上编译好的各个版本Eralng OTP。
就ubuntu而言,它提供的版本要比ubuntu官方的新,而且发布非常及时,新版erlang OTP刚刚正式发布,二进制的就已经编译好了。
不过它要额外安装一些其他依赖,比如,openjdk、还有GUI gtk,wx什么的,即使是在无GUI的server ubuntu下。
可以apt-get,也可以rpm安装。
浏览 11384
浏览: 383113 次
来自: 北京
存储方式的不同吧。gb_tree是平衡树,list是线性结构。 ...
eporf:analyse()写错了,应该改成eprof:an ...
求带 ! 请列出带徒标准
basho的资源 都没办法打开,不过还是有帮助,谢谢。比特客户端
您的位置:
详解大数据
详解大数据
详解大数据
详解大数据
如何让你加快C语言代码的编译速度
关键字:C语言
  1.每个作为一个编译单元,可能会包含上百甚至上千个头文件,而在每一个编译单元,这些头文件都会被从硬盘读进来一遍,然后被解析一遍。
  2.每个编译单元都会产生一个obj文件,然后所以这些obj文件会被link到一起,并且这个过程很难并行。
  这里,问题在于无数头文件的重复load与解析,以及密集的操作。
  下面从各个角度给出一些加快编译速度的做法,主要还是针对上面提出的这个关键问题。
  一、代码角度
  1、在头文件中使用前置声明,而不是直接包含头文件。
  不要以为你只是多加了一个头文件,由于头文件的“被包含”特性,这种效果可能会被无限放大。所以,要尽一切可能使头文件精简。很多时候前置申明某个namespace中的类会比较痛苦,而直接include会方便很多,千万要抵制住这种诱惑;类的成员,函数参数等也尽量用引用,指针,为前置声明创造条件。
  2、使用Pimpl模式
  Pimpl全称为Private Implementation.传统的C++的类的接口与实现是混淆在一起的,而Pimpl这种做法使得类的接口与实现得以完全分离。如此,只要类的公共接口保持不变,对类实现的修改始终只需编译该同时,该类提供给外界的头文件也会精简许多。
  3、高度模块化
  化就是低耦合,就是尽可能的减少相互依赖。这里其实有两个层面的意思。一是文件与文件之间,一个头文件的变化,尽量不要引起其他文件的重新编译;二是工程与工程之间,对一个工程的修改,尽量不要引起太多其他工程的编译。这就要求头文件,或者工程的内容一定要单一,不要什么东西都往里面塞,从而引起不必要的依赖。这也可以说是内聚性吧。
  以头文件为例,不要把两个不相关的类,或者没什么联系的宏定义放到一个头文件里。内容要尽量单一,从而不会使包含他们的文件包含了不需要的内容。记得我们曾经做过这么一个事,把代码中最“hot”的那些头文件找出来,然后分成多个独立的小文件,效果相当可观。
  其实我们去年做过的refactoring,把众多DLL分离成UI与Core两个部分,也是有着相同的效果的 - 提高开发效率。
  4、删除冗余的头文件
  一些代码经过上十年的开发与维护,经手的人无数,很有可能出现包含了没用的头文件,或重复包含的现象,去掉这些冗余的include是相当必要的。当然,这主要是针对cpp的,因为对于一个头文件,其中的某个include是否冗余很难,得看是否在最终的编译单元中用到了,而这样又可能出现在一个编译单元用到了,而在另外一个编译单元中没用到的情况。
  之前曾写过一个Perl脚本用来自动去除这些冗余的头文件,在某个工程中竟然去掉多达了5000多个的include.
  5、特别注意inline和template
  这是C++中两种比较“先进”的机制,但是它们却又强制我们在头文件中包含实现,这对增加头文件的内容,从而减慢编译速度有着很大的贡献。使用之前,权衡一下。
  二、综合技巧
  1、预编译头文件(PCH)
  把一些常用但不常改动的头文件放在预编译头文件中。这样,至少在单个工程中你不需要在每个编译单元里一遍又一遍的load与解析同一个头文件了。
  2、Unity Build
  Unity Build做法很简单,把所有的cpp包含到一个cpp中(all.cpp) ,然后只编译all.cpp.这样我们就只有一个编译单元,这意味着不需要重复load与解析同一个头文件了,同时因为只产生一个obj文件,在链接的时候也不需要那么密集的磁盘操作了,估计能有10x的提高,这个视频感受一下其做法与速度吧。
  3、ccache
  compiler cache, 通过cache上一次编译的结果,使rebuild在保持结果相同的情况下,极大的提高速度。我们知道如果是build,系统会对比源代码与目标代码的时间来决定是否要重新编译某个文件,这个方法其实并不完全可靠(比如从svn上拿了上个版本的代码),而ccache判断的原则则是文件的内容,相对来讲要可靠的多。
  很可惜的是,Visual Studio现在还不支持这个功能 - 其实完全可以加一个新的命令,比如cache build,介于build与rebuild之间,这样,rebuild就可以基本不用了。
  4、不要有太多的Additional Include Directories
  编译器定位你include的头文件,是根据你提供的include directories进行搜索的。可以想象,如果你提供了100个包含目录,而某个头文件是在第100个目录下,定位它的过程是非常痛苦的。组织好你的包含目录,并尽量保持简洁。
  三、编译资源
  要提高速度,要么减少任务,要么加派人手,前面两个方面讲得都是减少任务,而事实上,在提高编译速度这块,加派人手还是有着非常重要的作用的。
  1、并行编译
  买个4核的,或者8核的cpu,每次一build,就是8个文件并行着编,那速度,看着都爽。 要是你们老板不同意,让他读读这篇文章:Hardware is Cheap, Programmers are Expensive
  2、更好的磁盘
  我们知道,编译速度慢很大一部分原因是磁盘操作,那么除了尽可能的减少磁盘操作,我们还可以做的就是加快磁盘速度。比如上面8个核一块工作的时候,磁盘极有可能成为最大的瓶颈。买个15000转的磁盘,或者,或者RAID0的,总之,越快越好。
  3、分布式编译
  一台机子的性能始终是有限的,利用网络中空闲的cpu资源,以及专门用来编译的build server来帮助你编译才能从根本上解决我们编译速度的问题,想想原来要build 1个多小时工程的在2分钟内就能搞定,你就知道你一定不能没有它 - Incredibuild.
  4、并行,其实还可以这么做。
  这是一个比较极端的情况,如果你用了Incredibuild,对最终的编译速度还是不满意,怎么办?其实只要跳出思维的框架,编译速度还是可以有质的飞跃的 - 前提是你有足够多的机器:
  假设你有solution A和solution B,B依赖于A,所以必须在A之后Build B.其中A,B Build各需要1个小时,那么总共要2个小时。可是B一定要在A之后build吗?跳出这个思维框架,你就有了下述:
  ● 同时开始build A和B .
  ● A的build成功,这里虽然B的build失败了,但都只是失败在最后的link上。
  ● 重新link B中的project.
  这样,通过让A的build与B的编译并行,最后link一下B中的project,整个编译速度应该能够控制在1个小时15分钟之内。
[ 责任编辑:之极 ]
去年,手机江湖里的竞争格局还是…
甲骨文的云战略已经完成第一阶段…
软件信息化周刊
比特软件信息化周刊提供以数据库、操作系统和管理软件为重点的全面软件信息化产业热点、应用方案推荐、实用技巧分享等。以最新的软件资讯,最新的软件技巧,最新的软件与服务业内动态来为IT用户找到软捷径。
商务办公周刊
比特商务周刊是一个及行业资讯、深度分析、企业导购等为一体的综合性周刊。其中,与中国计量科学研究院合力打造的比特实验室可以为商业用户提供最权威的采购指南。是企业用户不可缺少的智选周刊!
比特网络周刊向企业网管员以及网络技术和产品使用者提供关于网络产业动态、技术热点、组网、建网、网络管理、网络运维等最新技术和实用技巧,帮助网管答疑解惑,成为网管好帮手。
服务器周刊
比特服务器周刊作为比特网的重点频道之一,主要关注x86服务器,RISC架构服务器以及高性能计算机行业的产品及发展动态。通过最独到的编辑观点和业界动态分析,让您第一时间了解服务器行业的趋势。
比特存储周刊长期以来,为读者提供企业存储领域高质量的原创内容,及时、全面的资讯、技术、方案以及案例文章,力求成为业界领先的存储媒体。比特存储周刊始终致力于用户的企业信息化建设、存储业务、数据保护与容灾构建以及数据管理部署等方面服务。
比特安全周刊通过专业的信息安全内容建设,为企业级用户打造最具商业价值的信息沟通平台,并为安全厂商提供多层面、多维度的媒体宣传手段。与其他同类网站信息安全内容相比,比特安全周刊运作模式更加独立,对信息安全界的动态新闻更新更快。
新闻中心热点推荐
新闻中心以独特视角精选一周内最具影响力的行业重大事件或圈内精彩故事,为企业级用户打造重点突出,可读性强,商业价值高的信息共享平台;同时为互联网、IT业界及通信厂商提供一条精准快捷,渗透力强,覆盖面广的媒体传播途径。
云计算周刊
比特云计算周刊关注云计算产业热点技术应用与趋势发展,全方位报道云计算领域最新动态。为用户与企业架设起沟通交流平台。包括IaaS、PaaS、SaaS各种不同的服务类型以及相关的安全与管理内容介绍。
CIO俱乐部周刊
比特CIO俱乐部周刊以大量高端CIO沙龙或专题研讨会以及对明星CIO的深入采访为依托,汇聚中国500强CIO的集体智慧。旨为中国杰出的CIO提供一个良好的互融互通 、促进交流的平台,并持续提供丰富的资讯和服务,探讨信息化建设,推动中国信息化发展引领CIO未来职业发展。
IT专家新闻邮件长期以来,以定向、分众、整合的商业模式,为企业IT专业人士以及IT系统采购决策者提供高质量的原创内容,包括IT新闻、评论、专家答疑、技巧和白皮书。此外,IT专家网还为读者提供包括咨询、社区、论坛、线下会议、读者沙龙等多种服务。
X周刊是一份IT人的技术娱乐周刊,给用户实时传递I最新T资讯、IT段子、技术技巧、畅销书籍,同时用户还能参与我们推荐的互动游戏,给广大的IT技术人士忙碌工作之余带来轻松休闲一刻。
微信扫一扫
关注Chinabyte拒绝访问 |
| 百度云加速
请打开cookies.
此网站 () 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(d3660a-ua98).
重新安装浏览器,或使用别的浏览器源码控制&版本控制工具&--介绍&与&使用
什么是源码控制?
有的时候我们称源码控制为版本控制,有的时候我们又称它为软件配置管理,不管是“软件配置管理”还是“源码管理”,有些时候我们都称为“源码控制”,我总是交替的使用这些术语,并且没有强调他们的区别。(当然,配置管理实际上包含了更多的内涵,我将在后面进行描述。不管怎样说这几个名称,源码控制都是对软件开发团队极为重要的一个实践。在软件开发里面最基本的元素就是我们的源代码。源代码控制工具就是一个用于管理这些代码的系统。现在有很多源码控制工具,他们都是不相同的。但是,不管你用什么工具,看起来现在有的源代码控制工具都提供了下面列出的基本技能中的一些或者所有:提供一个空间存放源代码。提供随时间变化的历史记录。提供一种方式:人们可以并行的进行被分离的任务,然后再合并。在没有其他的方式的时候,为开发人员提供一种协同工作的方式。
A tale of two trees
开始之前先讲解一下基本的术语和操作. 一个是存储区,一个是工作目录.
一个SCM工具提供一个存放源代码的地方,我们称之为"存储区",一般存放在服务器上,并共享给当前团队的所有成员.
每个开发人员都有自己的工作目录,一般存放在工作的机器上,并通过一个客户端程序访问.
所有内容都基于目录层次结构,存储区中的一个文件主要根据其路径来定义描述,就象普通的文件系统中一样。在Vault和SourceSafe中,存放路径必须$开头,如:
$/trunk/src/myLibrary/hello.cs
一个开发人员的基本工作流程看起来应该是这样:
拷贝存储区内的内容到当前工作目录;
在当前工作目录内修改代码;
更新这些变更到存储区;
重复以上步骤.
在此省略了会议、休假之类的事,不过对于一个开发人员而言,使用SCM工具就只有上面那些步骤了。存储区用于保存所有完成的工作。如果存储区内没有一项任务的交付物,则不认为这项工作已经完成。
让我们考虑一下没有工作目录和共享存储区的情况,如果是一个独立的开发人员,则是可以接受的,针对多人的开发小组,则情况会很混乱。
我曾看见有人尝试过。代码存放在一台文件服务器上,每个人都通过windows共享修改代码,当某个人想修改main.cpp时,他们会大声问是否其它人在使用此文件.网络带宽大部分消耗编译代码上,当我向他们推销我的产品时,我感觉就象一个ER医生(译者注:ER
Doctor)。那天晚上回到家里,我真的很高兴,因为我知道我又救了一条"生命".
最佳实践:不要破坏版本树
当存储区被破坏之后,工作目录的好处几乎都失去了.任何时候,存储区应该处于一种让任何成员可以继续工作的状态.如果某个成员签入的代码不能编译或测试通不过,所有成员的工作都受到了影响.
许多团队对破坏者都有相应的"惩罚",并非是很严厉的处罚,需要象征性的提醒其它成员注意.如罚款1美元(积少成多,以后可以做团队费用).另一种惩罚就是让他做公益劳动,只是让他感到不好意思,而不是真的惩罚.
一旦有了SCM工具,多人团队就简单多了.每个开发人员有自己的私有目录,他可以在自己目录里做修改而不用影响他人.
注意:并不是所有SCM工具都与这里使用的术语相同.许多系统使用"目录",而不是"文件夹".VSS使用"数据库",而不是"存储区".In
the context of Vault, these two words have a different
meaning.&& Vault allows multiple
repositories to exist within a single SQL
database.& For this reason, I use the word
"database" only when I am referring to the SQL
database. (这段文字为该产品的说明,不作翻译.)
存储库一般存放在专门的服务器上,而与开发人员的工作目录"远远"分离.之所以说"远",是因为可能相隔几寸,或远在几千公里之外.物理距离其实没什么意义.一般SCM工具提供通过TCP/IP在客户端和服务器之间交流的手段,无论是以太网还是互联网.
由于工作目录和存储区的分开,SCM工具中大多的特征就是帮助开发人员在两者之间来回传送数据,一般有如下操作:
存储区开始时一般是空的,因此我们需要往里面添加东西,在Vault中使用"添加文件"你可以将本地的文件或目录添加到存储区中;
当我们从存储区拷贝内容到工作时,这个操作就叫"Get",要注意的是这个操作主要针对我们不打算修改的文件,这些文件在我们的工作目录是只读状态;
Checkout:&
当我们想取得文件并编辑时,这个操作就叫"签出".这些文件在我们工作目录中会被标记为可读,而SCM服务器会记录我们的签出点;
当我们修改之后要保存到存储区时,我们就使用"签入"操作.本地目录的文件又会被标记为只读,而SCM服务器就会更新存储的内容到新的版本.
上面这些定义只是很简单的初级定义,只是针对SourceSafe或Vault的操作的缺省描述.而后面谈到的工作如CVS会略有不同,当然Vault也可配置为与CVS相同的工作方式.
术语的区别:有些SCM工具可能在字词上有所不同.Vault和SourceSafe使用"checkout"表明要编辑一个文件,而CVS则使用"checkout"得到文件,无论你打算编辑与否.有些SCM工具使用"commit"表示签入,而不是"checkin".事实上,这些术语在Vault中都会使用,在后面的章节中有介绍.
H.G. Wells would be proud
你的存储区并不仅仅是你当前代码版本的一个集合.事实上,它是代码的各个版本的集合.存储区中包含有扬有修改历史,保存了每个文件的所有变更版本号,因此,版本控制看起来就象是一部时间机器.
回退到软件的某一个时间点对一个项目而言是非常有用的,假如我们需要取得代码在的一份拷贝,使用SCM工具是非常容易做到的.
一种更常见的情况是当一段代码看起来有点奇怪,其它人都不易理解的时候,可以回溯这段代码的历史,了解修改的人和时间,及相关变更描述来了解修改的原因.
随着时间的推移,存储区会变得非常庞大和臃肿,因此SCM工具提供了相应的解决机制.在Vault中,提供历史浏览器查看以前的内容,可以搜索和排序.
也许对一个SCM工具而言,最重要的是使用标签.一个标签用于在一个特定时间上对存储内容设置一个有意义的名称,而且可以在以后很容易的根据标签取得当时的所有内容的一个快照.
本章简单的介绍了一下SCM工具能做什么,主要好处有两点:
工作目录给开发人员提供了私有的空间;
存储区的历史记录保存了每次所做的变更和原因.
CVS SVN VSS 使用对比
标签: 版本控制 历史版本 svn cvs vss it&分类: 程序语言
版本控制系统里团队开发不免要用上CVS SVN VSS
ClearCase等工具。至于选择上,则是根据开发团队搭建的平台,使用的编程语言相关联。
如果用.net平台开发,VSS无疑首选,尽管它曾经有不经时事的诟病,现在发展的功能也蛮强的。如果有服务器linux系统,则CVS,SVN都可以选择。现在SVN大有取代CVS之势。然而很多古老的程序员还是对CVS情有独钟。
如下节选一些网上的对比说明,我作以综述。当然,真正要弄懂这些版本控制系统,还是要花费巨大工夫学习研究,不可能在baidu或者google几下就能完成的。
一、Subversion包含绝大部分CVS功能
Subversion 作为CVS 的重写版和改进版,其目标就是作为一个更好的版本控制软件,取代目前流行的CVS。Subversion
的主要开发人员都是业界知名的CVS 专家。Subversion支持绝大部分的CVS 功能/命令;Subversion
的命令风格和界面也与CVS 非常接近。当然,不同的地方正是对CVS 的改进。
二、全局性的版本编号
一个新的版本,并得到一个自增量的版本号N+1,该版本号并不针对某个特定的文件,而是全局性的、针对整个版本库的。因此,我们可以将Subversion
的版本库看作是一个文件系统或文件目录树的数组。
从技术的 角度来说,在Subversion 中,“文件foo.c 的第5 版本”这个说法是错误的;正确的说法应该是:”文件foo.c
在版本库被修改了5 次,即执行5 次commit 后是什么样子?”。显然,在Subversion 中,版本库被修改5 次后foo.c
的内容,和被修改了6 次后foo.c 的内容很可能完全一样,因为版本库的第6
次修改很可能只修改了版本库的其他部分,而并没有对foo.c 的进行修改。相反,在CVS 中,文件foo.c 的第1.1 版本和第1.2
版本总是不同的。
Subversion 的全局性版本编号为Subversion
带来了诸多的优势:如对目录或文件执行拷贝,无论涉及多少文件,Subversion
不需要对单个文件依次执行拷贝命令,仅仅需要建立一个指向相应的全局版本号的一个指针即可。
//////////////////////////////////////////////////////////////////////
CVS, subversion, hg, git 版本控制系统的选择之路 (1)
subversion, hg, git
对于软件开发者或者往大了说,有知识管理或者数据管理需要的数码人&&
,是否使用版本控制系统,肯定已经不再是一个问题。
但是选用什么版本控制系统呢?这真是一个问题。我会告诉我的大部分客户,您可以仍旧选择Subversion作为主要的版本控制工具(CVS早已被我们淘汰了,见附:SVN和CVS的比较),但是分布式版本控制系统,在特定场合诸如:异地协同开发、移动办公/开发、涉密项目的封闭式开发都有着各种不同的应用。
如果采用类似我们公司的开源开发模式或者是内部开源模式,那么 Git 可能是您的首选。
这篇博文以我们群英汇自己公司的版本库变迁历史,和网友共享…
Subversion
Subversion
是群英汇支持的最重要的产品,我们服务的大多数客户,都或多或少的选择了我们的版本控制服务。群英汇为客户提供Subversion版本控制服务,从培训、应用部署、系统整合到售后服务、技术支持。
我们公司的部分项目使用了Subversion版本控制系统,如:
&&pySvnManager:托管在SourceForge上
&&FreeMind-MMX: 托管在SourceForge上
&&WordPress的CoSign-SSO插件:位于官方的Subversion库中
我们公司内部的开发在2007年以前,也主要使用Subversion,但是之后,我们的代码库逐渐的向分布式版本控制系统迁移:
&&先是Hg:Hg是水银的化学元素符号,全称为Mercurial。
&&后来是Git:Git 是 LinusTorvalds
继Linux后的又一个伟大发明,为全人类的另一个伟大贡献
Hg/Mercurial
Hg走入我们的视线,是因为我们研究的项目都一个一个脱离Subversion阵营,转向Hg,使用Hg作为各自项目的版本控制工具。其中一个我们主要研究的项目是:MoinMoin维基。
使用Hg后,困扰我的问题迎刃而解,就是:
&&我们的软件开发模式是基于成熟的开源软件进行定制。项目的原始代码库称为上游,我们自己的代码库称为下游;
&&使用Subersion,我们采用Subversion的Vendor分支(或称卖主分支)来管理我们的代码
&&一但上游软件软件出现新的版本,我们代码的迁移就成了最让人头痛的事情,可能好几天都不能搞定;
Hg可以很好的解决这个问题,原因在于:
&&Hg是分布式版本控制工具,整个代码库都在本地,浏览变更历史速度超快,实际上是本地访问,不再受制于网络。这样我们就可以更快的建立和上游版本库的同步,尽早尽快的解决代码合并问题,而不是要等到新版本发布;
&&Hg的最佳拍当MQ!简直就是为我们的开发模式所设计的。Subversoion的卖主分支和MQ相比就好像马车和火箭的对比。
&&Hg简单,并且使用习惯和Subversion非常相似,这也是为什么我们公司的版本控制系统在转向
Git 后,仍有部分项目在使用 Hg的原因
群英汇的Hg开源代码库:
有了Hg,为什么还要用git?
&&和Subversion代码库同步的需要。
o&虽然svn可以镜像远程代码库,但镜像库不能提交
o&Hg不支持分支,因此无法完全克隆一个Subversion代码库
o&Git有着完备的分支支持,可以将远程svn库镜像为一个本地的git库,而且可以提交甚至远程提交
&&Git速度更快。如果你用过git和hg,你就会对我说的有所感觉:
o&Hg提交/克隆/push/pull,我经常对自己无所事事&&
而感到恼怒,感觉就像傻子一样,完成了多少?1%还是99%?
o&Git速度超快不说,整个过程有着详尽的提示,真是体贴备至。&
&&Git+Topgit很好的支持上下游的协同开发
o&Hg的MQ虽然很好,但是Git有Topgit,而且Git的rebase功能更成熟
o&MQ可能更适合单人开发,但是没有办法对补丁之间建立依赖关系
o&Topgit采用分支来管理补丁,而且可以在分支之间设置依赖,可以是代码更整洁
群英汇的开放Git代码库:
///////////////////////////////////////////////////////////////////////&
CVS(concurrent& version system) 版本控制系统,
在开放源代码开发社区中,用CVS来记录分布式开发者对源代码的修改,该系统可以记录版本变换,谁在何时修改了什么,并且能够从其管理的源文件堆里提取出某此修改时的版本,不但能够在单机上使用,而且CVS能够使许多人一起协同工作,对同一个工程进行操作,CVS的机制是这样的:CVS保留一份最初源文件的副本,这个副本叫做"Repository(源代码档案库)",此后
CVS控制源文件所有的处理,不再对最初的源文件进行处理,这样可以避免发布时开发者覆盖其他人改变的代码
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-tutorial 和 Everyday GIT
作为蓝本翻译整理,但是暂时去掉了对 Git 内部工作机制的阐述,力求简明扼要,并加入了作者使用 Git
的过程中的一些心得体会,注意事项,以及更多的例子。建议你最好通过你所使用的 Unix / Linux 发行版的安装包来安装 Git,
你可以在线浏览本文 ,也可以通过下面的命令来得到本文最新的版本库,并且通过后面的学习用 Git
作为工具参加到本文的创作中来。&
$ git-clone
/git/gittutorcn.git&
创建一个版本库:git-init-db&
创建一个 Git 版本库是很容易的,只要用命令 git-init-db
就可以了。现在我们来为本文的写作创建一个版本库:&
$ mkdir gittutorcn&
$ cd gittutorcn&
$ git-init-db&
git 将会作出以下的回应&
defaulting to local storage
这样,一个空的版本库就创建好了,并在当前目录中创建一个叫 .git 的子目录。你可以用 ls -a
查看一下,并请注意其中的三项内容:&
一个叫 HEAD 的文件,我们现在来查看一下它的内容:&
$ cat .git/HEAD&
现在 HEAD 的内容应该是这样:&
ref: refs/heads/master&
我们可以看到,HEAD
文件中的内容其实只是包含了一个索引信息,并且,这个索引将总是指向你的项目中的当前开发分支。&
一个叫 objects
的子目录,它包含了你的项目中的所有对象,我们不必直接地了解到这些对象内容,我们应该关心是存放在这些对象中的项目的数据。&
关于 git 对象的分类,以及 git 对象数据库的说明,请参看
[Discussion]&
一个叫 refs 的子目录,它用来保存指向对象的索引。&
具体地说,子目录 refs 包含着两个子目录叫 heads 和
tags,就像他们的名字所表达的意味一样:他们存放了不同的开发分支的头的索引,
或者是你用来标定版本的标签的索引。&
请注意:master 是默认的分支,这也是为什么 .git/HEAD 创建的时候就指向 master 的原因,尽管目前它其实并不存在。
git 将假设你会在 master
上开始并展开你以后的工作,除非你自己创建你自己的分支。&
另外,这只是一个约定俗成的习惯而已,实际上你可以将你的工作分支叫任何名字,而不必在版本库中一定要有一个叫 master
的分支,尽管很多 git 工具都认为 master
分支是存在的。&
现在已经创建好了一个 git
版本库,但是它是空的,还不能做任何事情,下一步就是怎么向版本库植入数据了。&
植入内容跟踪信息:git-add&
为了简明起见,我们创建两个文件作为练习:&
$ echo "Hello world" &
$ echo "Silly example" &
我们再用 git-add
命令将这两个文件加入到版本库文件索引当中:&
$ git-add hello example&
git-add 实际上是个脚本命令,它是对 git 内核命令 git-update-index
的调用。因此上面的命令和下面的命令其实是等价的:&
$ git-update-index --add hello
如果你要将某个文件从 git 的目录跟踪系统中清除出去,同样可以用 git-update-index
命令。例如:&
$ git-update-index --force-remove
git-add 可以将某个目录下的所有内容全都纳入内容跟踪之下,例如: git-add ./path/to/your/wanted
。但是在这样做之前,应该注意先将一些我们不希望跟踪的文件清理掉,例如,gcc 编译出来的 *.o 文件,vim 的交换文件
.*.swp 之类。&
应该建立一个清晰的概念就是,git-add 和 git-update-index 只是刷新了 git 的跟踪信息,hello 和
example 这两个文件中的内容并没有提交到 git
的内容跟踪范畴之内。&
提交内容到版本库:git-commit&
既然我们刷新了 Git
的跟踪信息,现在我们看看版本库的状态:&
$ git-status&
我们能看到 git 的状态提示:&
# Initial commit&
# Updated but not checked in:&
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" &&
我们再来比较一下,当前的工作目录和版本库中的数据的差别。&
$ git-diff&
差异将以典型的 patch 方式表示出来:&
diff --git a/hello b/hello&
index a5c1966..bd&
--- a/hello&
+++ b/hello&
@@ -1 +1,2 @@&
Hello, world&
+It's a new day for git&
此时,我们可以再次使用组合命令 git-update-index 和 git-commit
将我们的工作提交到版本库中。&
$ git-update-index hello&
$ git-commit -m "new day for
实际上,如果要提交的文件都是已经纳入 git 版本库的文件,那么不必为这些文件都应用 git-update-index
命令之后再进行提交,下面的命令更简捷并且和上面的命令是等价的。&
$ git-commit -a -m "new day for
管理分支: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-whatchanged&
我们现在为 robin, master
两个分支都增加一些内容。&
$ git-checkout robin&
$ echo "Work, work, workd" &&
$ git-commit -m "Some workd" -i
$ git-checkout master&
$ echo "Play, play, play" &&
$ echo "Lots of fun" &&
$ git-commit -m "Some fun" -i hello
git-show-branch
命令可以使我们看到版本库中每个分支的世系发展状态,并且可以看到每次提交的内容是否已进入每个分支。&
$ git-show-branch&
这个命令让我们看到版本库的发展记录。&
* [master] Some fun&
! [robin] some work&
*& [master] Some
+ [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&
关于 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
:644 f24c74a... 7f8b141... M&
:644 263414f... 06fa6a2... M&
diff-tree 3ecebc0... (from
895f09a...)&
Author: Vortune.Robin&
Date:&& Tue Mar 21 02:17:23 2006
&&& a new day
:644 557db03... 263414f... M&
从上面的内容中我们可以看到,在 robin 分支中的日志为 "Some work" 的内容, 并没有在 master
分支中出现。&
合并两个分支:git-merge&
既然我们为项目创建了不同的分支,那么我们就要经常地将自己或者是别人在一个分支上的工作合并到其他的分支上去。现在我们看看怎么将
robin 分支上的工作合并到 master 分支中。现在转移我们当前的工作分支到 master,并且将 robin
分支上的工作合并进来。&
$ git-checkout master&
$ git-merge "Merge work in robin" HEAD
合并两个分支,还有一个更简便的方式,下面的命令和上面的命令是等价的。&
$ git-checkout master&
$ git-pull . robin&
但是,此时 git 会出现合并冲突提示:&
Trying really trivial in-index
fatal: Merge requires file-level
Merging HEAD with
d2659fcf690ec693c04c82b0d50960&
1d2fa05b13b63e39f621d8ee62d9b7 Some
d2659fcf690ec693c04c82b0d50960 some
found 1 common ancestor(s):&
3ecebc0cbdfa7c7c6fc8b5f9da0eda a new day for
Auto-merging hello&
CONFLICT (content): Merge conflict in
Au fix up by
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&
d2659fcf690ec693c04c82b0d50960/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 [--mixed | --soft | --hard]
[&commit-ish&]&
命令的选项:&
仅是重置索引的位置,而不改变你的工作树中的任何东西(即,文件中的所有变化都会被保留,也不标记他们为待提交状态),并且提示什么内容还没有被更新了。这个是默认的选项。&
既不触动索引的位置,也不改变工作树中的任何内容,我们只是要求这些内容成为一份好的内容(之后才成为真正的提交内容)。这个选项使你可以将已经提交的东西重新逆转至“已更新但未提交(Updated
but not Check in)”的状态。就像已经执行过 git-update-index 命令,但是还没有执行
git-commit 命令一样。&
将工作树中的内容和头索引都切换至指定的版本位置中,也就是说自
&commit-ish&
之后的所有的跟踪内容和工作树中的内容都会全部丢失。因此,这个选项要慎用,除非你已经非常确定你的确不想再看到那些东西了。&
一个重要技巧--逆转提交与恢复&
可能有人会问,--soft 选项既不重置头索引的位置,也不改变工作树中的内容,那么它有什么用呢?现在我们介绍一个 --soft
选项的使用技巧。下面我们用例子来说明:&
$ git-checkout master&
$ git-checkout -b softreset&
$ git-show-branch&
这里我们创建了一个 master 的拷贝分支
softreset,现在我们可以看到两个分支是在同一起跑线上的。&
! [master] Merge branch
! [robin] some work&
& * [softreset] Merge branch
- - [master] Merge branch
+ * [master^] Some fun&
++* [robin] some work&
我们为 文件增加一些内容并提交。&
$ echo "Botch, botch, botch" &&
$ git-commit -a -m "some
$ git-show-branch&
我们可以看到此时 softreset 比 master 推进了一个版本 "some botch"
! [master] Merge branch
! [robin] some work&
& * [softreset] some
& * [softreset] some
- - [master] Merge branch
+ * [master^] Some fun&
++* [robin] some work&
现在让我们来考虑这样的一种情况,假如我们现在对刚刚提交的内容不满意,那么我们再编辑项目的内容,再提交的话,那么 "some
botch" 的内容就会留在版本库中了。我们当然不希望将有明显问题的内容留在版本库中,这个时候 --soft
选项就很有用了。为了深入了解 --soft 的机制,我们看看现在 softreset 分支的头和 ORIG_HEAD
保存的索引。&
$ cat .git/refs/heads/softreset
.git/ORIG_HEAD&
结果如下:&
5e7cfbdca8c598cad2cba&
7bbdd955b6f6652bf8274efdc1fbd3&
现在用 --soft 选项逆转刚才提交的内容:&
git-reset --soft HEAD^&
现在让我们再看看 .git/ORIG_HEAD
的中保存了什么?&
$ cat .git/ORIG_HEAD&
结果如下:&
5e7cfbdca8c598cad2cba&
看!现在的 .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
f0aff9d2342603b54388&
“署名标签”是一个真正的 git 对象,它不但包含指向你想标记的状态的指针,还有一个标记名和信息,可选的 PGP 签名。你可以通过
-a 或者是 -s 选项来创建“署名标签”。&
$ git-tag -s
&tag-name&&
合并外部工作&
通常的情况下,合并其他的人的工作的情况会比合并自己的分支的情况要多,这在 git 中是非常容易的事情,和你运行 git-merge
命令没有什么区别。事实上,远程合并的无非就是“抓取(fetch)一个远程的版本库中的工作到一个临时的标签中”,然后再使用
git-merge 命令。&
可以通过下面的命令来抓取远程版本库:&
$ git-fetch
&remote-repository&&
根据不同的远程版本库所使用的通讯协议的路径来替代上面的 remoted-repository
就可以了。&
rsync://remote.machine/patch/to/repo.git/&
remote.machine:/path/to/repo.git&
ssh://remote.machine/patch/to/repo.git/&
这是可以上传和下载的双向传输协议,当然,你要有通过 ssh
协议登录远程机器的权限。它可以找出两端的机器提交过的对象集之中相互缺少了那些对象,从而得到需要传输的最小对象集。这是最高效地交换两个版本库之间的对象的方式(在
git 兼容的所有传输协议当中)。&
&&& 下面是个取得 SSH
远程版本库的命令例子:&
&&& $ git-fetch
robin@192.168.1.168:/path/to/gittutorcn.git&
&&& (1) 这里 robin
是登录的用户名,192.168.1.168 是保存着主版本库的机器的 IP
Local directory&
/path/to/repo.git/&
&&& 本地目录的情况和 SSH
情况是一样的。&
git Native&
git://remote.machine/path/to/repo.git/&
自然协议是设计来用于匿名下载的,它的工作方式类似于 SSH
协议的交换方式。&
http://remote.machine/path/to/repo.git/&
到这里可能有些朋友已经想到,实际上,我们可以通过 Rsync, SSH 之类的双向传输方式来建立类似 CVS,SVN
这样的中心版本库模式的开发组织形式。&
通过电子邮件交换工作&
读过上一节之后,有的朋友可能要问,如果版本库是通过单向的下载协议发布的,如
HTTP,我们就无法将工作上传到公共的版本库中。别人也不能访问我的机器来抓取我的工作,那怎么办呢?&
不必担心,我们还有 email !别忘了 git 本来就是为了管理 Linux 的内核开发而设计的。所以,它非常适合像 Linux
Kernel 这样的开发组织形式高度分散,严重依赖 email
来进行交流的项目。&
下面模拟你参加到《Git 中文教程》的编写工作中来,看看我们可以怎么通过 email
进行工作交流。你可以通过下面的命令下载这个项目的版本库。&
$ git-clone
/git/gittutorcn.git&
之后,你会在当前目录下得到一个叫 gittutorcn 的目录,这就是你的项目的工作目录了。默认地,它会有两个分支: master 和
origin,你可以直接在 master 下展开工作,也可以创建你自己的工作分支,但是千万不要修改 origin
分支,切记!因为它是公共版本库的镜像,如果你修改了它,那么就不能生成正确的对公共版本库的 patch
如果你的确修改过 origin 分支的内容,那么在生成 patch 文件之前,请用 git-reset --hard
命令将它逆转到最原始的,没经过任何修改的状态。&
你可以直接在 master 下开展工作,也可以创建你自己的工作分支。当你对项目做了一定的工作,并提交到库中。我们用
git-show-branch 命令先看下库的状态。&
* [master] your buddy's
contribution&
! [origin] degining of git-format-patch
*& [master] your buddy's
contribution&
*+ [origin] degining of git-format-patch
上面就假设你已经提交了一个叫 "your buddy's contribution" 的工作。现在我们来看看怎么通过 email
来交流工作了。&
$ git-fetch
$ git-rebase
$ git-format-patch
origin&&&&
(1)更新 origin 分支,防止 origin
分支不是最新的公共版本,产生错误的补丁文件;&
(2)将你在 master
上提交的工作迁移到新的源版本库的状态的基础上;&
(3)生成补丁文件;&
上面的几个命令,会在当前目录下生成一个大概名为 0001-your-buddy-s-contribution.txt 补丁文件,
建议你用文本工具查看一下这个文件的具体形式,然后将这个文件以附件的形式发送到项目维护者的邮箱:
当项目的维护者收到你的邮件后,只需要用 git-am
命令,就可以将你的工作合并到项目中来。&
$ git-checkout -b
buddy-incomming&
/path/to/0001-your-buddy-s-contribution.txt&
用 Git 协同工作&
假设 Alice 在一部机器上自己的个人目录中创建了一个项目 /home/alice/project, Bob
想在同一部机器自己的个人目录中为这个项目做点什么。&
Bob 首先这样开始:&
$ git-clone /home/alice/project
这样就创建了一个保存着 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
文件中,它将会是所以的导入操作的默认路径。&
可能已经注意到他并没有在他的版本库中创建过分支(但是分支已经存在了):&
$ git branch&
"origin" 分支,它是运行 "git-clone" 的时候自动创建的,他是 Alice 的 master 分支的原始镜像,
Bob 应该永远不要向这个分支提交任何东西。&
如果 Bob 以后决定在另外一部主机上开展工作,那么他仍然需要通过 SSH 协议从新克隆和导入( Alice
的版本库):&
$ git-clone alice.org:/home/alice/project/
我们可以使用 git 自然协议,或者是 rsync, http 等协议的任何一种,详情请参考
git-pull。&
Git 同样可以建立类似 CVS 那样的开发模式,也就是所有开发者都向中心版本库提交工作的方式,详情参考 git_push 和 git
for CVS users 。&
为版本库打包&
在前面,我们已经看到在 .git/objects/??/ 目录中保存着我们创建的每一个 git
对象。这样的方式对于自动和安全地创建对象很有效,但是对于网络传输则不方便。 git
对象一旦创建了,就不能被改变,但有一个方法可以优化对象的存储,就是将他们“打包到一起”。&
$ git repack&
上面的命令让你做到这点,如果你一直是做着我们的例子过来的,你现在大约会在 .git/objects/??/ 目录下积累了17个对象。
git-repack 会告诉你有几个对象被打包了,并且将他们保存在 .git/objects/pack
目录当中。&
你将会看到两个文件,pack-*.pack and pack-*.idx 在 .git/objects/pack
目录。他们的关系是很密切的,如果你手动将他们拷贝到别的版本库中的话,你要决定将他们一起拷贝。前者是保存着所有被打包的数据的文件,后者是随机访问的索引。&
如果你是个偏执狂,就运行一下 git-verity-pack 命令来检查一下有缺陷的包吧,不过,其实你无须太多担心,我们的程序非常出色
一旦你已经对那些对象打包了,那么那些已经被打过包的原始的对象,就没有必要保留了。&
$ git prune-packed&
会帮你清楚他们。&
如果你好奇的话,你可以在执行 git-prune-repacked 命令之前和之后,都运行一下 find .git/objects
f,这样你就能看到有多少没有打包的对象,以及节省了多少磁盘空间。&
git pull git-pull 对于 HTTP
传输来说,一个打包过的版本库会将一定数量的相关联的对象放进一个有关联性的打包中。如果你设想多次从 HTTP
公共版本库中导入数据,你也许要频繁地 reapck &
prune,要么就干脆从不这样做。&
如果你此时再次运行 git-repack,它就会说 "Nothing to
pack"。要是你继续开发,并且积累了一定数量的变迁,再运行 git-repack
将会创建一个新的包,它会包含你自上次对库打包以来创建的对象。我们建议你尽快在初始化提交之后打包一下你的版本库(除非你现在的项目是个涂鸦式的草稿项目),并且在项目经历过一段很活跃的时期时,再运行
git-repack 一下。&
当一个版本库通过 git-push 和 git-pull
命令来同步源版本库中打包过的对像的时候,通常保存到目标版本库中的是解包了的对象,除非你使用的是
rsync(远程同步协议)协议的传输方式。正是这种容许你在两头的版本库中有不同的打包策略的方式,他意味着你也许在过一段时间之后,需要在两头的版本库中都重新打包一下。&
发布你的工作&
我们可以通过一个远程的版本库来利用他人的工作,但是,你如何准备一个自己的版本库来供其他人下载呢?你在自己的工作目录下进行工作,这样你的版本库就被作为.git的一个子目录放在你的工作树下。你可以让其他人来远程的访问你的版本库,但是实际上这不是通常的做法。推荐的做法是创建一个公共的版本库,让它可供其他人访问,并且,当你在你的工作目录下做了很好的改动时,你可以更新到公共的版本库中。这通常称为pushing。&
公共版本库是可以被映像的,kernel.org上的git公共版本库也是这样管理的。&
从你的本地的(私有的)版本库中发布改动到你的远程的(公共的)版本库中需要远程机器上的写权限。你需要一个SSH的帐号来运行一个简单的命令,git-receive-pack。首先,你需要在远程机器上创建一个空的版本库来存放你的公共版本库。这个空版本库以后将通过pushing来保持更新。显然,这个版本库之需要在开始的时候创建一次。&
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这个路径下。&
当你直接运行程序的时候,很多sshd的安装版并没有将你的shell作为登陆的shell;这就是说,如果你登陆的shell是bash
的话,被读到的是.bashrc而不是.bash_profile。确认.bashrc设置好了$PATH路径,这样你才可以运行git-receive-pack命令。&
如果你打算通过HTTP来发布这个版本库,这是你就应该运行命令chmod +x
my-git.git/hooks/post-update。这确认了每次你导入数据到这个版本库中,git-update-server-info能够被执行。&
现在你的“公共的版本库”可以接受你的任何改动了。回到你的本地机上,运行命令:&
$ git push :/path/to/my-git.git
该命令将你的公共版本库和你当前的版本库中指定名称的分支头部同步(这里是master)。举一个实际的例子,你可以这样来更新公共的git版本库。Kernel.org的镜像网络也这样来同步其他公共的可访问的机器:&
$ git push
master.kernel.org:/pub/scm/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
+& [diff-fix] Fix rename
detection.&
+& [diff-fix~1] Better common substring
algorithm.&
+&& [commit-fix] Fix commit
message normalization.&
& * [master] Release candidate
++* [diff-fix~2] Pretty-print
messages.&
两个补丁我们都测试好了,到这里,你想将他们俩合并起来,于是你可以先合并 diff-fix ,然后再合并
commit-fix,像这样:&
$ git merge 'Merge fix in diff-fix' master
$ 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] Fix rename
detection.&
+* [diff-fix~1] Better common substring
algorithm.&
& * [master~2] Release candidate
++* [master~3] Pretty-print
messages.&
然而,当你确信你手头上的确是一堆互不相关的项目变化时,就没有任何理由将这堆东西一个个地合并(假如他们的先后顺序很重要,那么他们就不应该被定以为无关的变化),你可以一次性将那两个分支合并到当前的分支中,首先我们将我们刚刚做过的事情逆转一下,我们需要通过将
master 分支重置到 master~2
位置的方法来将它逆转到合并那两个分支之前的状态。&
$ git reset --hard master~2&
你可以用 git-show-branch 来确认一下的确是回到了两次 git-merge
的状态了。现在你可以用一行命令将那两个分支导入的方式来替代两次运行(也就是所谓的 炮制章鱼 -- making an
Octopus)git-merge :&
$ git pull . commit-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
++* [master~2] Pretty-print
messages.&
注意那些不适合制作章鱼的场合,尽管你可以那样做。一只“章鱼”往往可以使项目的提交历史更具可读性,前提是你在同一时间导入的两份以上的变更是互不关联的。然而,如果你在合并任何分支的过程中出现合并冲突,并且需要手工解决的话,那意味着这些分支当中有相互干涉的开发工作在进行,那么你就应该将这个两个冲突先合并,并且记录下你是如何解决这个冲突,以及你首先处理他们的理由。(译者按:处理完冲突之后,你就可以放心制作“章鱼”了)否则的话将会造成项目的发展历史很难跟踪。&
管理版本库&
版本库的管理员可以用下面的工具来建立和维护版本库。&
git-daemon(1) 容许匿名下载版本库。&
git-shell(1) 面向中心版本库模式的用户的类似 受限的 shell
update hook howto
一个很好的管理中心版本库的例子。&
在 /pub/scm 上运行 git 守护进程&
&&& $ grep git
/etc/inet.conf&
nowait& nobody
/usr/bin/git-daemon git-daemon --inetd --syslog --export-all
这个配置行应该在配置文件中用一行来写完。&
仅给开发者 push/pull 的访问权限。&
&&& $ grep git
/etc/passwd (1)&
alice:x:::/home/alice:/usr/bin/git-shell&
bob:x:::/home/bob:/usr/bin/git-shell&
cindy:x:::/home/cindy:/usr/bin/git-shell&
david:x:::/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 来访问机器。&
许多的发行版需要在 /etc/shells 配置文件中列明要用什么 shell 来作为登录
CVS - 模式的公共库。&
&&& $ grep git
/etc/group (1)&
git:x:9418:alice,bob,cindy,david&
/home/devo.git&
&&& $ ls -l
lrwxrwxrwx&& 1 david
Dec& 4 22:40 HEAD -&
refs/heads/master&
drwxrwsr-x&& 2 david
git& 4096 Dec& 4 22:40
-rw-rw-r--&& 1 david
Dec& 4 22:40
-rw-rw-r--&& 1 david
Dec& 4 22:40
description&
drwxrwsr-x&& 2 david
git& 4096 Dec& 4 22:40
-rw-rw-r--&& 1 david git 37504
Dec& 4 22:40
drwxrwsr-x&& 2 david
git& 4096 Dec& 4 22:40
drwxrwsr-x&& 4 david
git& 4096 Dec& 4 22:40
drwxrwsr-x&& 4 david
git& 4096 Nov& 7 14:58
drwxrwsr-x&& 2 david
git& 4096 Dec& 4 22:40
&&& $ ls -l
hooks/update (3)&
-r-xr-xr-x&& 1 david
git& 3536 Dec& 4 22:40
info/allowed-users (4)&
refs/heads/master&&&&&&
alice\|cindy&
refs/heads/doc-update&&
refs/tags/v[0-9]*&&&&&&
将所有的开发人员都作为 git 组的成员。&
并且给予他们公共版本库的写权限。&
&&& (3) 用一个在
Documentation/howto/ 中的 Carl
写的例子来实现版本库的分支控制策略。&
&&& (4) Alice 和
Cindy 可以提交入 master 分支,只有 Bob 能提交入 doc-update
则是发行经理只有他能创建并且 push 版本标签。&
支持默协议传输的 HTTP 服务器。&
&&& dev$ git
update-server-info (1)&
&&& dev$ ftp
user@ (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页)就有很好的介绍(/a2jdg)。&
需要强调的是正真的非常规的开发组织形式, git
这种组织形式,意味着对于工作流程的约束,没有任何强迫性的原则。你不必从唯一一个远程版本库中导入(工作目录)。&
项目领导人(project lead)的工作推介&
在你自己的本地机器上准备好主版本库。你的所有工作都在这里完成。&
准备一个能让大家访问的公共版本库。&
如果其他人是通过默协议的方式(http)来导入版本库的,那么你有必要保持这个 默协议的友好性。 git-init-db
之后,复制自标准模板库的 $GIT_DIR/hooks/post-update 将包含一个对
git-update-server-info 的调用,但是 post-update 默认是不能唤起它自身的。通过 chmod +x
post-update 命令使能它。这样让 git-update-server-info
保证那些必要的文件是最新的。&
将你的主版本库推入公共版本库。&
git-repack 公共版本库。这将建立一个包含初始化提交对象集的打包作为项目的起始线,可能的话,执行一下
git-prune,要是你的公共库是通过 pull
操作来从你打包过的版本库中导入的。&
在你的主版本库中开展工作,这些工作可能是你自己的最项目的编辑,可能是你由 email
收到的一个补丁,也可能是你从这个项目的“子系统负责人”
的公共库中导入的工作等等。&
你可以在任何你喜欢的时候重新打包你的这个私人的版本库。&
将项目的进度推入公共库中,并给大家公布一下。&
尽管一段时间以后,"git-repack"
公共库。并回到第5步继续工作。&
项目的子系统负责人(subsystem
maintainer)也有自己的公共库,工作流程大致如下:&
准被一个你自己的工作目录,它通过 git-clone 克隆自项目领导人的公共库。原始的克隆地址(URL)将被保存在
.git/remotes/origin 中。&
准备一个可以给大家访问的公共库,就像项目领导人所做的那样。&
复制项目领导人的公共库中的打包文件到你的公共库中,除非你的公共库和项目领导人的公共库是在同一部主机上。以后你就可以通过
objects/info/alternates
文件的指向来浏览它所指向的版本库了。&
&& 4. 将你的主版本库推入你的公共版本库,并运行
git-repack,如果你的公共库是通过的公共库是通过 pull 来导入的数据的话,再执行一下 git-prune
在你的主版本库中开展工作。这些工作可能包括你自己的编辑,来自 email
的补丁,从项目领导人,“下一级子项目负责人”的公共库哪里导入的工作等等。&
你可以在任何时候重新打包你的私人版本库。&
将你的变更推入公共库中,并且请“项目领导人”和“下级子系统负责人”导入这些变更。&
每隔一段时间之后,git-repack 公共库。回到第 5
步继续工作。&
“一般开发人员”无须自己的公共库,大致的工作方式是:&
准备你的工作库,它应该用 git-clone
克隆自“项目领导人”的公共库(如果你只是开发子项目,那么就克隆“子项目负责人”的)。克隆的源地址(URL)会被保存到
.git/remotes/origin 中。&
在你的个人版本库中的 master 分支中开展工作。&
每隔一段时间,向上游的版本库运行一下 git-fetch origin 。这样只会做 git-pull
一半的操作,即只克隆不合并。公共版本库的新的头就会被保存到 .git/refs/heads/origins
用 git-cherry origin 命令,看一下你有什么补丁被接纳了。并用 git-rebase origin
命令将你以往的变更迁移到最新的上游版本库的状态中。(关于 git-rebase 命令,请参考
git-rebase)&
&& 5. 用 git-format-patch origin
生成 email 形式的补丁并发给上游的维护者。回到第二步接着工作
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。}

我要回帖

更多关于 小颖java源代码反编译 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信