Maven库依赖机制及添加自定义库

一.Maven库依赖机制 Maven的库依赖机制可以帮助我们自动下载依赖的库文件,并且还能更新版本。。 考虑一个情境来理解机制的工作原理,假设我们要使用Log4J库作为项目的日志记录。以下是我们要做的 1.传统的方式 1)访问Log4J网站http://logging.apache.org/log4j/2.x/ 2)下载Log4J的jar包 3)复制进项目的classpath里 4)手工包含到项目的依赖里 看到没,你要从头做到尾,如果Log4J更新了,你得再来一遍。。 2.Maven的方式 1)需要知道Log4J的Maven坐标(coordinates,这个暂时没想到好名字),就是这样的东西 <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.14</version> 然后Maven就会自动下载1.2.14版本的Log4J了。如果version这个元素没有,那么如果有了新版本,Maven会自动下载新版本的。 2)在pom.xml里声明这个Maven坐标 <dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.14</version> </dependency> </dependencies> 3)当Maven编译或者build的时候,Log4J会自动下载,放入本地仓库里 4)Maven全部接管 3.解释 搜索顺序前面说过了。本地-》中央-》远程仓库 Maven坐标咋来的,当然去中央仓库搜索之了,搜索结果清晰的令人发指 二.添加自定义库到本地仓库 有两个情况,需要我们包含自定义的库到本地仓库里 1是你想使用的jar文件不再中央仓库 2是你创建了一个自定义的jar包,需要另一个项目使用这个jar 比如,kaptche,一个第三方的java库,生成验证码,现在中央仓库没有了。 我们想要加到本地仓库里 1.mvn安装 下载kaptche,解压并且拷贝kaptcha-version.jar到其他任何你喜欢的地方,比如c盘,然后输入如下格式的命令 mvn install:install-file -Dfile=c:\kaptcha-{version}.jar -DgroupId=com.google.code -DartifactId=kaptcha -Dversion={version} -Dpackaging=jar 这里我这样输入 D:&gt;mvn install:install-file -Dfile=c:\kaptcha-2.3.jar -DgroupId=com.google.code -DartifactId=kaptcha -Dversion=2.3 -Dpackaging=jar [INFO] Scanning for projects… [INFO] Searching repository for plugin with prefix: ‘install’. [INFO] ———————————————————————— [INFO] Building Maven Default Project [INFO] task-segment: install:install-file [INFO] ———————————————————————— [INFO] [install:install-file] [INFO] Installing c:\kaptcha-2. [Read More]

DMP版本修改工具(C#)

最近在使用oracle导入一个dmp文件的时候,由于不知道dmp文件是如何导出的,是使用exp还是expdp导出的,所以纠结了比较长的时间,最后想到是否可以查看dmp文件的一些辅助信息呢,于是有了这个工具。

在使用dmp导入的时候报如下错误

IMP-00010: 不是有效的导出文件,标题验证失败
IMP-00000: 未成功终止导入
据说有两个可能,1个是文件本身损坏,另一个是版本问题,多出现在高版本导出的数据向低版本导入。解决方法就是修改一下dmp文件就行了。dmp文件头部大概9个字节处标识了版本号用来头部验证。对于非常大的dmp我们不能直接用文本编辑器打开,因此找找资料,写个工具。本机一个12GB的文件已测试。

工具使用很简单,选择文件,识别出来版本,按格式改成导入端oracle的版本值,然后即可正常导入11G-10G测试成功。

下载地址:DMP版本修改工具

 

C#中的Debug类

位于命名空间System.Diagnostics中 1.Debug.Print方法

Debug.Print("Today: {0}", DateTime.Today);

2.Debug.WriteLine方法

Debug.WriteLine("Have a nice day");

3.TraceListener类

DelimitedListTraceListener创建的时候指定一个文件名,当Flush调用的时候,就被覆写到文件里。

TraceListener listener = new DelimitedListTraceListener(@"C:\debugfile.txt");

        // Add listener.
        Debug.Listeners.Add(listener);

        // Write and flush.
        Debug.WriteLine("Welcome");
        Debug.Flush();

4.Debug.Write和WriteIf以及WriteLineIf方法

Debug.WriteLineIf(IsThursday(), "Thursday");

第一个参数一个bool值,为真则输出。

5.Debug.Assert方法

Debug.Assert(value != -1, "Value must never be -1.");

如果表达式为false,则输出。

操作系统中的页面置换算法

最近读完了《现代操作系统》。页面置换算法的读书笔记。其他的笔记慢慢整理一下在博客做个备份。
虚拟内存的基本思想:每个程序都拥有自己的内存空间,这个空间被分割成很多块,每一块称为一页/页面,每一页有连续的地址范围,这些页被映射到物理内。
页面置换算法 1.最优页面置换算法,每个页面都可以用在该页面首次被访问前所需要执行的指令数作为标记。因此我们选择标记最大的页面,也就是把不愉快的事情往后拖延。但是,唯一的问题是无法实现。 2.最近未使用页面置换算法。系统每一个页面设置两个状态位,当页面被访问时设置R位,当被修改时设置M位,包含在页表项中,初始时,都被设置0,R被定期地清零,以区别最近没有被访问和被访问的页面。NRU算法随机的从类编号最小的非空类中挑选一个页面淘汰之, 根据R和W可以将页面分为4类 0没有被访问,没有被修改/1没有被访问,被修改/2已被访问,没有被修改/3已被访问,已被修改。第一类只有在定期清R的时候才会出现。 隐含的意思是,淘汰一个没有被访问的已修改页面要比淘汰一个被频繁使用的干净页面要好。 3.先进先出置换,找出最先进入的替换掉,很少单独使用 4.第二次机会页面置换算法。FIFO可能将经常使用的页面置换出来。为此,检查最老页面的r位,如果R为0,则既老又没有被使用,则就置换掉,如果是1,就清0,放在链表尾,修改装入时间为最新。继续搜索。 5.时钟页面置换算法,第二次机会算法经常要在链表中移动页面,更好的方法是将页面保存在一个类似钟面的环形链表中,表针指向最老的页面。发生缺页时,如果R是0就 淘汰该页面,并插入新页面,然后表针前移,如果是1,就清除R并前移,直到找到一个R位为0的页面。这也是时钟的由来 6.最近最少使用页面置换算法。在发生缺页时,置换未使用时间最长的页面,这个策略称为LRU,最简单的一个实现策略是有一个64位计数器,每条指令执行完加1.每个页表项必须有一个足够容纳这个计数器值的域,每次访问内存后,将C值保存到被访问页面的页表项,一旦中断,检查所有页面项的计数器值,找到最小的即可。 7.NFU最不常用算法,是LRU的软件模拟实现。每个页面与一个软件计数器管理。初值为0,每次时钟中断时,操作系统扫描内存中的所有页面,将每个页面中的R位值加到他的计数器上,计数器的值即为访问的频繁程度。该算法的问题是记住的事情太多,如果第一次执行扫描的时间最长。比如第一次某个页面的值很大。这个很大的值会影响到下一次扫描,结果操作系统将置换有用的页面而不是不再使用的页面。 8.修改一下NFU:R位被加进之前,将计数器右移一位,同时将R加到计数器的左端。即为老化算法 9.工作集页面置换算法。一个进程当前正在使用的页面的集合称作他的工作集。基本思路是找出一个不在工作集中的页面并淘汰它。 10.工作集时钟页面置换算法。基于时钟算法,并且使用了工作集信息。

页面调度算法总结; 最好的两种算法是老化算法和工作集时钟算法,分别基于LRU和工作集。具有良好的页面调度性能。

C# 基础知识系列文章索引

清理GR的加星标项目。分享来自博客园 zhili 的C#基础系列文章。

C#基础知识系列终于告了一个段落了, 本系列中主要和大家介绍了C#1.0到C# 4.0中一些重要的特性,刚开始写这个专题的初衷主要是我觉得掌握了C#这些基础知识之后,对于其他任何的一门语言都是差不多的,这样可以提高朋友们对其他语言的掌握,以及可以让大家更加迅速地掌握.NET的新特性, 并且相信这个系列对于找工作的朋友也是很有帮助的,因为很多公司面试都很看重基础知识是否扎实,是否对C#有一个全面的认识和理解,所以很多公司面试都会问到一些C#基础概念的问题,例如,经常面试会问:你是如何理解委托的,如何理解匿名函数等问题。

然而这个系列中并没有介绍COM互操作性的内容以及.Net 4.5中的一些新特性,所以后面将会对这两个方面的内容进行补充,由于这个系列托的太久了(大概也有3个月吧),所以就先告一段落的,后面将会带来.NET互操作性系列的介绍。下面就为这个系列文章做一个索引,方便大家收藏和查找。

C#基础知识系列索引

C#1.0

1. 深入解析委托——C#中为什么要引入委托

2. 委托本质论

3. 如何用委托包装多个方法——委托链

4. 事件揭秘

5. 当点击按钮时触发Click事件背后发生的事情

C# 2.0

6. 泛型基础篇——为什么引入泛型

7. 泛型深入理解(一)

8. 泛型深入理解(二)

9. 深入理解泛型可变性

10. 全面解析可空类型

11. 匿名方法解析

12. 迭代器

C# 3.0

13. 全面解析对象集合初始化器、匿名类型和隐式类型

14. 深入理解Lambda表达式

15. 全面解析扩展方法

16. Linq介绍

C# 4.0

17. 深入理解动态类型

 

从C#的所有特性可以看出,C#中提出的每个新特性都是建立在原来特性的基础上,并且是对原来特性的一个改进, 做这么多的改进主要是为了方便开发人员更好地使用C#来编写程序,是让我们写更少的代码来实现我们的程序,把一些额外的工作交给编译器去帮我们做,也就是很多人说微软很喜欢搞语法糖的意思(语法糖即让编译器帮我们做一些额外的事情,减少开发人员所考虑的事情,使开发人员放更多的精力放在系统的业务逻辑上面。),大家从C# 3中提出的特性中可以很好的看出这点(指的是玩语法糖),C#3中几乎大部分特性都是C#提供的语法糖,从CLR层面来说(指的是增加新的IL指令),C# 3并没有更新什么,C# 4中提出的动态类型又是建立在表达式树的基础上,包括Linq也是建立在表达式树的基础上,所以每个特性都是层层递进的一个关系。相信C#后面提出的新特性将会更加方便我们开发程序,感觉所有语言的一个统一的思想都是——写更少的代码,却可以做更多的事情。但是我们不能仅仅停住于知道怎么使用它,我们还应该深入研究它的背后的故事,知道新特性是如何实现的和原理。用一句说就是——我们要知其然之气所以然,学习知识应该抱着刨根问底的态度去学习,相信这样的学习方式也可以让大家不感到心虚,写出的程序将会更加自信。

C#与.net 程序员面试笔记

这是前几天读的书。书不难。10-13章跳过了。以后再看。 以前,一个应用程序对应一个进程。并且为该进程指定虚拟内存,这样。进程会消耗很多资源,而且进程之间的通信业比较麻烦 应用程序域可以理解为很多应用程序域都可以运行在同一个.net 进程中,降低内存消耗。同时不同的域之间隔离。安全有保证。通信也简单。 程序集是指包含编译好的。面向.net framework的代码的逻辑单元。是完全自我描述性的一个逻辑单元。可以存储在多个文件中。简单来说,程序集就是几个彼此有关联程序文件的集合。程序集会包含程序的元数据。描述了对应代码中定义的方法和类型。 装箱和拆箱:装箱转换是将一个值类型显式或隐式的转换成一个object对象。并且把这个对象转换成一个被该值类型应用的的接口类型。装箱后的object对象中的数据位于堆中。一般应该避免这种运算。 CLR将值类型的数据包裹到匿名的托管对象中,并将托管对象的引用放在Object类型的变量中。这个过程称为装箱。一般还是使用泛型来代替多好。 值类型和引用类型:值类型实例通常分配在线程的栈上。并且不包含指向任何实例数据的指针。引用类型实例分配在托管堆上。变量保存了实例数据的内存引用。引用类型复制的话会导致引用同一个内存地址。 C#预处理指令是在编译时调用的。预处理指令通知C#编译器要编译哪些代码。并指出如何处理特定的错误和异常。比如用在一些调试的时候。在顶部define一个debug 内部的测试部分写上测试用例。具体示例 //定义条件变量,注意条件变量的定义要在代码的最前面 #define Debug using System; namespace MyConsole { class Preprocesor { public static void Main() { //如果条件变量是Debug则运行单元调试代码,再运行功能模块返回运行结果 #if Debug Console.WriteLine(“运行单元测试模块”); Console.WriteLine(“运行功能模块,返回输出结果”); Console.Read(); #elif Release //如果条件变量是Release,则直接运行功能模块返回运行结果 Console.WriteLine(“运行功能模块,返回输出结果”); Console.Read(); #endif } } } C#中的指针 指针是一个无符号整数。是以当前系统寻址范围为取值范围的整数,CLR支持三种指针类型:受托管指针,非托管指针,非托管函数指针,受托管指针存储在堆上的托管块的引用,一个非托管指针就是传统意义上的指针,要放在unsafe中使用,C#中指针并不继承自Object String 是CLR的类型名称。而string是C#的关键字。其实C#编译时。。会增下如下代码: using string=System.String Array 到ArrayList的转换 1.使用ArrayList.Adapter(ArrayName) 可以直接得到ArrayList 2.使用遍历逐个添加到ArrayList里。 反向的话直接使用(Array[])ArrayListName.ToArray(typeof(Array));即可 checked和unchecked语句用于控制整形算术运算和显示转换的溢出检查上下文。checked关键字用于对整型算术运算和转换显式启用溢出检查。因为默认情况下。如果表达式产生的值超过了类型的范围。则常数表达式将会导致编译时错误。而非常数表达式则在运行时计算并将引发异常。 Asp.Net 中的Request对象主要功能是从客户端得到数据信息。他的属性比较多。比如UserLanguage,TotalBytes,Path,ApplicationPath ViewState是其的一个重要特性。用于把生成页面要用的状态值保存到一个隐藏域里。而不是用cookie/内存 SOAP是Web Service应用的基础协议。他是一种轻量的简单的。基于xml的协议。被设计成在wEb上交换结构化的和固有的信息。 WSDL是一种用于描述web服务和说明如何与Web服务通信的XML语言。WSDL是一种符合XML语法规范的语言。它的设计完全基于Soap协议的实现。当一个WEb Service 服务器期望为使用者提供服务说明时,WSDL语言是最好的选择之一。   对企业的一些认识  千万不要说自己未来的打算是做到管理层,首先对管理层的定义不清楚。职务不清楚。所以保险的答案是我会努力钻研技术。使得能够达到业内的专业人士。深刻理解公司和行业 我是为了找一份长期性的工作。我不喜欢频繁的跳槽我希望在这个利于发展自己的事业。深入学习。向专业人士请教。那。该我想问这个职务是长期的吗? 不要把公司想像成慈善机构。工作的运作方面应该是尽可能快的实现盈利。树立品牌,赢得客户。我的工作就是完成企业的良性运作。 如果被问到是否需要考虑看分数。应该说用人单位确实需要全面考量。也要考虑应聘者的工作积极性/服从性。实际经验/对开发的理解诶。这些也许比分数更有价值。 [Read More]

理解并实现原型模式-实现ICloneable接口.理解深浅拷贝

本文用C#实现原型模式,也会讨论深浅拷贝,已经如何在.net中高效实现ICloneable 接口 介绍 有时候我们需要从上下文得到一个对象的拷贝,然后通过一些独立的操作来处理他。原型模式在这种情况下很适用 GoF 定义原型模式为用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。 Specify the kind of objects to create using a prototypical instance, and create new objects by copying this prototype.” 看一下类图 主要的参与者有 • Prototype: 抽象类或接口,定义了方法来拷贝自己 • ConcretePrototype: 克隆的具体类. • Client: 需要执行拷贝对象的软件对象 然后实现吧 使用代码 为了简化。我以一个著名的偷车游戏作为例子 我们说游戏里有一个注脚。这个主要有着一些定义游戏数据的统计量。保存游戏的时候我们就需要拷贝这个对象,然后序列化到文件中。(仅仅是举个例子,真实的游戏里很少这样做) 下面这个类抽象类就是概念中的Prototype public abstract class AProtagonist { int m_health; int m_felony; double m_money; public int Health { get { return m_health; } set { m_health = value; } } public int Felony { get { return m_felony; } set { m_felony = value; } } public double Money { get { return m_money; } set { m_money = value; } } public abstract AProtagonist Clone(); }   [Read More]

实现IEnumerable接口&理解yield关键字

本文讨论题目的内容。然后讨论IEnumerable接口如何使得foreach语句可以使用。之后会展示如果实现自定义的集合类,该集合类实现了IEnumerable接口。Yield关键字和遍历集合后面也讨论。 背景 一使用集合。就发现遍历集合就跟着来了。遍历集合最好的方式是实现迭代器模式-Understanding and Implementing the Iterator Pattern in C# and C++(这篇文章我过几天翻译一下) ,C#提供foreach来以一种优雅的方式遍历 只要集合实现了IEnumerable 接口就可以用foreach来遍历。 使用代码 首先先看一下内置的集合类如何使用foreach来遍历的。ArrayList实现了IEnumerable 接口。我们看一下 // 看一下实现了IEnumerable 接口的集合如何遍历 ArrayList list = new ArrayList(); list.Add(“1”); list.Add(2); list.Add(“3”); list.Add(‘4’); foreach (object s in list) { Console.WriteLine(s); }   遍历泛型集合类 Arraylist 是一个通用集合类,遍历泛型集合类也可以。因为这些泛型集合类实现了IEnumerable<T>接口,看一下吧。 // 遍历实现了IEnumerable<T>接口的泛型类 List<string> listOfStrings = new List<string>(); listOfStrings.Add(“one”); listOfStrings.Add(“two”); listOfStrings.Add(“three”); listOfStrings.Add(“four”); foreach (string s in listOfStrings) { Console.WriteLine(s); }   发现了吧。我们自定义的集合类或是泛型集合类应该实现IEnumerable和IEnumerable<T>接口。这样就可以遍历了。   理解yield关键字 在写个实现接口的例子之前,先理解一下yield关键字,yield会记录集合位置。当从一个函数返回一个值的时候,yield可以用。 如下的普通的方法。不论调用多少次,都只会返回一个return static int SimpleReturn() { return 1; return 2; return 3; } [Read More]

C#制作进度窗体

介绍 这是我在CodeProject上的第一篇文章。我希望对你有用 当我开发软件的时候。我通常因为一个很耗时是任务需要完成。而请求让用户等待,并且通过也允许用户取消。不论我做何种操作(比如下载文件。保存大文件等等)。我都需要做下面几件事: 通过一个模态对话框来让用户等待操作完成 能让用户看到进度。 能让用户随时取消。 我搜了好久也没找到拿来就能用的窗体控件,也许是我没找到。于是我自己写。。 图1 背景 BackgroundWorker 类包含了我需要完成任务的所有东西。我只需要给他提供一个对话框。 使用代码 ProgressForm 包含了一个BackgroundWorker ,你要做的仅仅就是提供了一个完成工作的方法。 ProgressForm form = new ProgressForm(); form.DoWork += new ProgressForm.DoWorkEventHandler(form_DoWork); //如果想为后台任务提供参数的话 form.Argument = something; 为了开始BackgroundWorker,只需要调用ShowDialog 方法。返回值则取决于任务是怎么完成的。 DialogResult result = form.ShowDialog(); if (result == DialogResult.Cancel) { //用户点击了取消 } else if (result == DialogResult.Abort) { /未处理的异常抛出 //你可以得到异常信息 MessageBox.Show(form.Result.Error.Message); } else if (result == DialogResult.OK) { //正常完成 //结果存储在 form.Result里 }   最后。任务方法看起来是这样的。 void form_DoWork(ProgressForm sender, DoWorkEventArgs e) { //得到参数 object myArgument = e. [Read More]

关于源代码控制的五个误区

上周,在Red Gate好朋友的帮助下。我发起了一个名为小竞赛赢得优秀的SQL  Source Control 5份授权的活动。参加的方式很简单-分享你使用源代码控制过程中,本可以避免的最痛苦的经历

许多痛苦的故事都出现了。但是我认为这五个获奖者的故事值得分享,并且我都做了评论,因为我觉得随着时间的流逝,这些故事依然对我们有所启发。那么,开始享受这些故事吧,我希望这些知识中的闪光点能够帮助你以后不会掉进相同的陷阱里。

给获奖者:希望那些授权可以帮助抚慰你们关于那些已经过去的痛苦记忆。不久我会联系你们关于奖项颁发的相关事宜。

 

1.通过Ctrl-Z来进行源代码控制

第一个故事来自 courtesy of MyChickenNinja ,仅仅文字就看得我头疼。在这个特殊的故事里。应用程序被前员工破坏了。。这非常头疼。但是至少还是有很多方法可以恢复代码的。如果不要求数据的话。。

第一个问题是备份,最近的备份已经是3周前的。这绝对是一个教训—你的环境真的备份了吗?一会我会在另一个故事里简单的再说到这个问题。故事的核心部分是通过Ctrl-Z来进行伪源代码控制

他们运行他们的代码,并且不断地更新,也包括开发环境,并且使用Ctrl-Z来撤销坏的改变

好吧。这实在令人难以置信-如果你的应用程序已经做了一些编辑。然后被关闭了。怎么办?或者PC关机了?等等—他还说他们在哪写代码,哪儿就是开发环境?记住!撤销不是源代码控制!

 

2。多个数据库和集成问题

第二个故事来自Brandon Thompson,他极度不开心,因为他工作在一个有着很多数据库源的环境里,并且,这些数据库都在正在进行的开发项目下面,数据库集成非常困难,这就意味着处理多个数据库备份可能还有个在海外。。

我们的开发团队在海外,因为他们有他们自己的数据库集,这些数据库我从没看到过。但是他们会把改变的文件发给我们来适应我们的开发环境

我发现最痛苦的是简单重复的手工劳动仅仅是使得大家能够协同的更好。这是没有一点创新并且没有任何增值的行为,比如增加新的特性,这就导致除了干这些。没什么时间真正在写代码了。

源代码控制是为了能够保证团队之间平稳尽量无摩擦的一起工作。它是项目的一个润滑剂,和持续集成开发还有自动部署都属于同一类。这些都是软件开发中的“面包和黄油”,是任何成功团队编写代码的基础。

 

3. 依赖未测试的备份

下一个是Barry Anderson,他写了一个我们都曾经经历过的痛苦:不能从备份恢复了!事实上在Barry的故事里。几个月都没备份了。之前备份本身还是坏的。这太糟糕了。但是,对于那些依赖备份的人来说这是一个严重的疏忽。

当然对于这个疏忽也有自己的借口。Barry解释道:

我们的经理(不是存储团队的)后来告诉我们既没时间也没空间来测试备份了。。。

备份是一件很重要的事情。但从备份可以恢复也是同等重要,我最近在配置大量的新环境的时候,备份本应该发生的但是就是没有发生。只有当我坚持要进行恢复测试的时候,问题才浮出水面,对于很多人来说。只有当他们真的需要从一系列的数据丢失中恢复数据的时候,才发现不能恢复了。。测试你的备份,恢复他们,不要相信任何人的说辞.

 

4.人工合并工具

来自Graham Sutherland的故事讲了一个人来做机器工作的故事

我们有一些开发人员,每一个在他们的硬盘上的都有整个项目的一个副本,每一次一个改变发生的时候,我们就会下载技术老大改变的源代码,然后使用diff工具来查看改变。然后手工更新他们。一行一行。。全靠双手。。

这个故事比听起来还要不可思议,在源代码控制工具出现以前这确实是存在的。一个海外开发团队成员就是这样干的。随后他们这样解释:带头的开发者需要在提交前检查其他开发人员的工作进度。

这确实是类似于之前的观点,在有多个数据库集成的情况下;我们有技术来解决这些问题!每当一个人在软件开发中从事任何劳动密集型,重复的过程,你真的不得不停下来问:“有没有更好的方法?”通常是有的。

 

5.剪切和粘贴版本控制

Robin Vessey 让我产生了共鸣,因为它真的是伪VCS(Version Control System)最普遍的方式。剪切或者复制,然后粘贴到新的位置,通过这种方式会包含重复的目录或者文件。因此一般这些文件会被以日期或者其他标识符来标识时间帧。

在Robin的故事里,他打算通过网络移动一个目录结构。

他很简单但高效,我剪贴然后粘贴了一个完整的目录树,任何东西,通过网络发送。但这些文件留在了我这一边。却没有到达另一边。我仍然不知道为什么。

我必须承认,我对任何剪切和粘贴文件的操作的态度是非常谨慎的,因为我看到这种情况在一个本地文件系统中发生了很多次,更不用说通过网络了,在上面的的Robin的故事,就是没有备份被恢复,因为他们一段时间后会停止备份,“因为我们没有更多的空间”。是不是感觉好像和前面某一方法很像。。

 

总结

工作在一个没有源代码控制的环境下是很可怕的。现在就停止吧。伙计们,我们是很优秀,但在在源代码控制下工作是很专业的。并且现在有很多的VCS产品。托管服务,集成工具,真心是没有任何理由不把代码-包括数据库,部署在源代码控制下。

 

原文地址:5-ways-to-do-source-control-really

著作权声明:本文由http://leaver.me 翻译,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!