安装

CentOS 6

下载和安装

wget https://downloads-packages.s3.amazonaws.com/centos-6.5/gitlab-7.0.0_omnibus-1.el6.x86_64.rpm
sudo yum install openssh-server
sudo yum install postfix # Select 'Internet Site', using sendmail or exim is also OK
sudo rpm -i gitlab-7.0.0_omnibus-1.el6.x86_64.rpm

开启防火墙

sudo lokkit -s http -s ssh

编辑配置文件

sudo vi /etc/gitlab/gitlab.rb

初始化配置

sudo gitlab-ctl reconfigure

检查运行情况

sudo gitlab-ctl status

初始化用户和密码

  • username:root

  • password:5iveL!fe

卸载

sudo gitlab-ctl uninstall
sudo rpm -e gitlab

目录结构

  • /opt/gitlab Gitlab 的应用程序代码和依赖都存放在此.
  • /var/opt/gitlab Gitlab-ctl reconfigure 将配置文件以及应用程序数据保存在这里.
  • /etc/gitlab Gitlab 应用程序的配置文件存放在这里. These are the only files that you should ever have to edit manually.
  • /var/log/gitlab Gitlab 的所有日志都存放在这里.

启动与停止

启动

sudo gitlab-ctl start

停止服务

sudo gitlab-ctl stop

重启

sudo gitlab-ctl restart

备份

运行以下命令:

sudo gitlab-rake gitlab:backup:create

该命令将在 /var/opt/gitlab/backups 目录下创建一个 tar 的备份文件.备份文件名类似 1393513186_gitlab_backup.tar,其中 1393513186 是时间戳.

定时备份

sudo su -
crontab -e

然后编辑该文件:

0 2 * * * /opt/gitlab/bin/gitlab-rake gitlab:backup:create

每天凌晨2点进行备份.

恢复备份

首先保证备份文件存在于 /var/opt/gitlab/backups 目录下. 然后指定你要恢复的备份文件的时间戳.

# Stop processes that are connected to the database
sudo gitlab-ctl stop unicorn
sudo gitlab-ctl stop sidekiq

# This command will overwrite the contents of your GitLab database!
sudo gitlab-rake gitlab:backup:restore BACKUP=1393513186

# Start GitLab
sudo gitlab-ctl start

配置

Gitlab 几乎都是通过编辑文件 /etc/gitlab/gitlab.rb 来进行配置的.修改完该文件后必须运行 gitlab-ctl reconfigure 来变更确认新配置.

gitlab.rb 与 其他配置文件的对应

例如:

gitlab.yml 文件中有如下配置

production: &base
  gitlab:
	default_projects_limit: 10

转换为 gitlab.rb 时为

gitlab_rails['gitlab_default_projects_limit'] = 10

又如:

修改备份目录以及备份保存时间

gitlab_rails['backup_path'] = "/mnt/gitlab/backups"
gitlab_rails['backup_keep_time'] = 604800	#(备份保留7天)

URL

编辑文件 /etc/gitlab/gitlab.rb

external_url "http://gitlab.example.com"

更改 git 的数据存放路径

编辑文件 /etc/gitlab/gitlab.rb

git_data_dir "mnt/nas/git-data"

更改路径后的数据迁移问题参见备份

LDAP

HTTPS

编辑文件 /etc/gitlab/gitlab.rb

external_url "https://gitlab.example.com"
nginx['redirect_http_to_https'] = true

更改端口

增加默认ssl证书

email / SMTP

gitlab_rails['smtp_enable'] = true
gitlab_rails['smtp_address'] = "smtp.server"
gitlab_rails['smtp_port'] = 456
gitlab_rails['smtp_user_name'] = "smtp user"
gitlab_rails['smtp_password'] = "smtp password"
gitlab_rails['smtp_domain'] = "example.com"
gitlab_rails['smtp_authentication'] = "login"
gitlab_rails['smtp_enable_starttls_auto'] = true

日志

# Tail all logs; press Ctrl-C to exit
sudo gitlab-ctl tail

# Drill down to a sub-directory of /var/log/gitlab
sudo gitlab-ctl tail gitlab-rails

# Drill down to an individual file
sudo gitlab-ctl tail nginx/gitlab_error.log

数据库

相关错误处理

无法使用 ssh 进行 push

提示输入 git@serverip 的密码。

使用 ssh -vT git@serverip 出现如下提示:

 Next authentication method: password

处理办法:

使用 setroubleshoot 查询出错信息,然后根据提示处理.

semanage fcontext -a -t ssh_home_t '/home/git/.ssh(/.*)?'
restorecon -Rv /home/git/.ssh

参考

Gitlab Omnibus Readme


Read More

yum

常用操作

yum search someword

yum list|grouplist packagename [installed]

yum install packagename

yum erase|remove packagename

downloadonly 插件

  • 安装

该插件用于下载 yum 里的软件安装。 最新的版本已内置该插件,无需安装。

# 较旧的版本
yum install yum-downloadonly

# 较新的版本
yum install yum-plugin-doenloadonly
  • 配置

/etc/yum/pluginconf.d/downloadonly.conf 文件。

  • 使用

    yum install –downloadonly –downloaddir=./path packagename

查询相关 locate/which/whereis/find/grep

  • 安装

    yum install mlocate which grep

防火墙相关 lokkit/iptables

例子:

sudo lokkit -s http -s ssh
sudo lokkit -p 2443:tcp

genisoimage / mkisofs

genisoimage [参数] [-o isofile] pathspec [pathspec ...]

参数说明:

-o : 指定映像文件名称

-r : 使用Rock Ridge Extensions(支持文件名字母大小写、符号字符以及长文件名),并开放全部文件的读取权限。

-J : 使用Joliet格式(可显示 64个字符 ,并可使用中文,但是不能被MAC机所读取)的目录与文件名称。

git-cvs

cvs 迁移至 git 工具.

安装

yum install git-cvs

设置 CVSROOT 并登录

export CVSROOT=pserver:username@serverip:/home/cvs
cvs login

导出

git cvsimport -v project_name -C project_name

参数说明

-v : 显示详细信息.

-C : 到处目录名称,没有则新建.

-d : CVSROOT

乱码问题

vi /etc/sysconfig/i18n

将编码转成 cvs 服务器的编码,然后同时将终端编码(putty等)的编码也转换成相同编码.

ffmpeg/mencoder

音视频转换工具。

安装:

yum install ffmpeg libvpx
yum install mencoder

使用:

ffmpeg -i /path/video.vob /path/video.avi

Read More

简介

项目主页: http://junit.org/

JUnit是一个Java语言的单元测试框架。它由Kent Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit的xUnit家族中为最成功的一个。 JUnit有它自己的JUnit扩展生态圈。

多数Java的开发环境都已经集成了JUnit作为单元测试的工具。

使用

public class Example {
	File output;
	@Before
	public void createOutputFile() {
		  output= new File(...);
	}
	@Test
	public void something() {
		  ...
	}
	@After
	public void deleteOutputFile() {
		  output.delete();
	}
}

注解说明

@Before:

使用了该元数据的方法在每个测试方法执行之前都要执行一次。

@After:

使用了该元数据的方法在每个测试方法执行之后要执行一次。

注意:@Before@After 标示的方法只能各有一个。 这个相当于取代了JUnit以前版本中的 setUptearDown 方法,当然你还可以继续叫这个名字,不过JUnit不会霸道的要求你这么做了。

@Test(expected=*.class)

在JUnit4.0之前,对错误的测试,我们只能通过 fail 来产生一个错误,并在try块里面 assertTrue(true) 来测试。现在,通过 @Test 元数据中的 expected 属性。expected 属性的值是一个异常的类型

@Test(timeout=xxx):

该元数据传入了一个时间(毫秒)给测试方法,

如果测试方法在制定的时间之内没有运行完,则测试也失败。

@ignore:

该元数据标记的测试方法在测试中会被忽略。 当测试的方法还没有实现,或者测试的方法已经过时,或者在某种条件下才能测试该方法(比如需要一个数据库链接,而在本地测试的时候,数据库并没有连接),那么使用该标签来标示这个方法。 同时,你可以为该标签传递一个String的参数,来表明为什么会忽略这个测试方法。 比如:@ignore(“该方法还没有实现”),在执行的时候,仅会报告该方法没有实现,而不会运行测试方法。

@BeforeClass 和 @AfterClas :

只在测试用例初始化时执行 @BeforeClass 方法,当所有测试执行完毕之后,执行 @AfterClass 进行收尾工作。 在这里要注意一下,每个测试类只能有一个方法被标注为 @BeforeClass@AfterClass,并且该方法必须是 PublicStatic 的。

@RunWith :

@RunWith 是用来修饰类的,而不是用来修饰函数的.指定使用哪个Runer运行测试. 以下是常用的Runer.

  • @RunWith(Parameterized.class) : 参数化测试.用 @Parameters 标注测试数据的集合.

  • @RunWith(Suite.class) : 打包测试,将所有需要运行的测试类集中起来,一次性的运行完毕. 同时还需要另外一个标注 @Suite.SuiteClasses,来表明这个类是一个打包测试类。 我们把需要打包的类作为参数传递给该标注就可以了。


参考

项目文档


Read More

1. 什么是 Mock

在做单元测试的时候,我们会发现我们要测试的方法会引用很多外部依赖的对象,比如:(发送邮件,网络通讯,远程服务, 文件系统等等)。

而我们没法控制这些外部依赖的对象。

为了解决这个问题,我们就需要用到Mock工具来模拟这些外部依赖的对象,来完成单元测试。

2. Mock 工具(for Java)

jMock

EasyMock

Mockito 优点:消除了对期望行为(expectations)的需要.

PowerMock 优点:能mock静态,final,私有方法等.

3. 使用

3.1. 依赖管理

<dependencies>
  <dependency>
	 <groupId>org.powermock</groupId>
	 <artifactId>powermock-module-junit4</artifactId>
	 <version>${powermock.version}</version>
	 <scope>test</scope>
  </dependency>
  <dependency>
	 <groupId>org.powermock</groupId>
	 <artifactId>powermock-api-mockito</artifactId>
	 <version>${powermock.version}</version>
	 <scope>test</scope>
  </dependency>
</dependencies>

其中 powermock-api-mockito 依赖于 mockito-all 包。 而 powermock-core 依赖于 javassistjavassist 包。

编写测试时,须如下:

@RunWith(PowerMockRunner.class)
@PrepareForTest( { YourClassWantToMock.class })	// 待模拟的类
public class YourTestCase {
...
}

3.2. 模拟静态类,静态方法和 final 方法

@RunWith(PowerMockRunner.class)
@PrepareForTest(IdGenerator.class)
public class MyTestClass {
   @Test
   public void demoStaticMethodMocking() throws Exception {
	   // 模拟静态方法的输出
	   mockStatic(IdGenerator.class);
	   when(IdGenerator.generateNewId()).thenReturn(2L);

	   // 待测试方法
	   new ClassUnderTest().methodToTest();

	   // 验证静态方法被调用(可选)
	   verifyStatic();
	   IdGenerator.generateNewId();
   }
}

3.3. 模拟构造函数

@RunWith(PowerMockRunner.class)
@PrepareForTest(DirectoryStructure.class)
public class DirectoryStructureTest {
   @Test
   public void createDirectoryStructureWhenPathDoesntExist() throws Exception {
	   final String directoryPath = "mocked path";

	   // 模拟 File 类
	   File directoryMock = mock(File.class);

	   // 指示 PowerMockito 如何构造 File 对象.
	   whenNew(File.class).withArguments(directoryPath).thenReturn(directoryMock);

	   // 模式方法的输出
	   when(directoryMock.exists()).thenReturn(false);
	   when(directoryMock.mkdirs()).thenReturn(true);

	   // 待测试的方法,该方法内部会调用我们模拟的构造函数
	   assertTrue(new NewFileExample().createDirectoryStructure(directoryPath));

	   // 验证对象被创建(可选)
	   verifyNew(File.class).withArguments(directoryPath);
   }
}

3.4. 模拟私有方法

为了实现对类的私有方法的模拟操作,需要 PowerMock 提供的另外一项技术:局部模拟

在使用局部模拟时,被创建出来的模拟对象依然是原系统对象。 虽然可以使用方法 When().thenReturn() 来指定某些具体方法的返回值,但是没有被用此函数修改过的函数依然按照系统原始类的方式来执行。

这种局部模拟的方式的强大之处在于,除开一般方法可以使用之外,私有方法一样可以使用。

被测试代码:

public class PrivatePartialMockingExample {
	public String methodToTest() {
		return methodToMock("input");
	}

	private String methodToMock(String input) {
		return "REAL VALUE = " + input;
	}
 }

为了保持单元测试的纯洁性,在测试方法 methodToTest()时,我们不希望受到私有函数 methodToMock()实现的干扰,为了达到这个目的,我们使用刚提到的局部模拟方法来实现 , 实现方式如下:

@RunWith(PowerMockRunner.class)
@PrepareForTest(PrivatePartialMockingExample.class)
public class PrivatePartialMockingExampleTest {
	@Test
	public void demoPrivateMethodMocking() throws Exception {
		final String expected = "TEST VALUE";
		final String nameOfMethodToMock = "methodToMock";
		final String input = "input";

		PrivatePartialMockingExample underTest = spy(new PrivatePartialMockingExample());

		// 模拟静态方法
		when(underTest, nameOfMethodToMock, input).thenReturn(expected);

		assertEquals(expected, underTest.methodToTest());

		// 验证静态方法被调用
		verifyPrivate(underTest).invoke(nameOfMethodToMock, input);
	}
}

3.5. 设置对象的private属性

需要使用 whiteboxclass 或者对象中赋值。

如我们已经对接口尽行了mock,现在需要将此mock加入到对象中,可以采用如下方法:

Whitebox.setInternalState(Object object, String fieldname, Object… value);

其中 object 为需要设置属性的静态类或对象。

3.6. 处理public void型的静态方法

Powermockito.doNothing.when(T class2mock, String method, <T>… params>

参考

PowerMock 简介

玩花招的PowerMock

使用Powermock进行单元测试,以及常见问题的处理

Read More

什么是 Mock

在做单元测试的时候,我们会发现我们要测试的方法会引用很多外部依赖的对象,比如:(发送邮件,网络通讯,远程服务, 文件系统等等)。

而我们没法控制这些外部依赖的对象。

为了解决这个问题,我们就需要用到Mock工具来模拟这些外部依赖的对象,来完成单元测试。

Mock 工具(for Java)

jMock

EasyMock

Mockito 优点:消除了对期望行为(expectations)的需要.

PowerMock 优点:能mock静态,final,私有方法等.

模拟对象

模拟 LinkedList 的对象

LinkedList mockedList = mock(LinkedList.class);

此时调用 get 方法,是会返回 null ,因为还没有对方法调用的返回值做模拟

System.out.println(mockedList.get(999));

模拟方法调用的返回值

模拟获取第一个元素时,返回字符串 first

when(mockedList.get(0)).thenReturn("first");

此时打印输出 first

System.out.println(mockedList.get(0));

模拟方法调用抛出异常

模拟获取第二个元素时,抛出 RuntimeException

when(mockedList.get(1)).thenThrow(new RuntimeException());

此时将会抛出 RuntimeException

System.out.println(mockedList.get(1));

没有返回值类型的方法也可以模拟异常抛出

doThrow(new RuntimeException()).when(mockedList).clear();

模拟方法调用的参数匹配

anyInt() 匹配任何int参数,这意味着参数为任意值,其返回值均是 element

when(mockedList.get(anyInt())).thenReturn("element");

此时打印是 element

System.out.println(mockedList.get(999));

更灵活的参数匹配,请参见 Mockito Matchers

验证方法调用或调用次数

调用 addList ,其中 addList 方法内部调用了 Listadd 方法

mockService.addList("once");

验证 add 方法是否被调用了

verify(mockedList).add("once");

验证 add 方法是否被调用了一次

verify(mockedList, times(1)).add("once");
verify(mockedList, never()).add("twice");

还可以通过 atLeast(int i)atMost(int i) 来替代 time(int i) 来验证被调用的次数最小值和最大值;never() 验证从未调用。

验证方法执行顺序

Service 对象内部先后调用 List 对象的 add 方法两次.

List firstMock = mock(List.Class);
List secondMock = mock(List.Class);

firstMock.add("first");
secondMock.add("second");

创建 InOrder 对象来验证执行顺序.

InOrder inOrder = InOrder(firstMock, secondMock);
inOrder.verify(firstMock).add("first");
inOrder.verify(secondMock).add("second");

验证超时

使用 timeout(int i) 来验证超时,但不能和 InOrder 一起使用.

verify(mock, timeout(200)).someMethod();

验证超时调用2次.

verify(mock, timeout(200).times(2)).someMethod();

验证超时调用至少2次.

verify(mock, timeout(200).atLeast(2)).someMethod();

自定义验证模型

// TODO 待研究
verify(mock, new Timeout(100, yourOwnVerificationMode)).someMethod();

Spy

局部模拟

在使用局部模拟时,被创建出来的模拟对象依然是原系统对象。 虽然可以使用方法 When().thenReturn() 来指定某些具体方法的返回值,但是没有被用此函数修改过的函数依然按照系统原始类的方式来执行。

callRealMethod

也是局部模拟,但行为与 spy 相反。

使用注解 @Mock, @Captor, @Spy, @InjectMocks

可以使用 @Mock 注解来简化 Mock 对象的创建.

@Mock private List mockList;

可以使用 @Captor 简化 ArgumentCaptor 的创建.

// TODO 待添加实例.

可以使用 @Sqy 代替 spy(Object)

@Spy List spyList = new ArrayList();

可以使用 @InjectMocks 注解自动注入被测试的对象.

@InjectMocks private Service mockService;

注意: 使用以上注解都必须在(基)类中或 test runner 中初始化.

MockitoAnnotations.initMocks(testClass);

参考:

Mockito JavaDoc

Mockito入门


Read More

安装

  • Unzip

  • Add M2_HOME to the “Environment Variables”

  • Add M2 with the value %M2_HOME%\bin

  • Optional:Add MAVEN_OPTS to specify JVM properties,e.g. the value -Xms256m -Xmx512m

  • Update/Create Path, Prepend the value %M2% to add Maven available in the command line

  • Make sure that JAVA_HOME exists

  • Test: mvn --version

配置

设置本地仓库路径

修改安装目录下的/conf/settings.xml文件的<settings>节点下的localRepository节点内容。

// 以后通过 mvn 命令安装的包均放置该目录下
<localRepository>E:\Lib\java\repository</localRepository>

基础

POM

就像 Make 的 Makefile,Ant 的 build.xml 一样,Maven 项目的核心是 pom.xml。

POM(Project Object Model,项目对象模型)定义了项目的基本信息, 用于描述项目如何构建,声明项目依赖,等等。

何为坐标

Maven定义了这样一组规则:世界上任何一个构件都可以使用Maven坐标唯一标识, Maven坐标的元素包括groupId、artifactId、version、packaging、classifier。 如:

groupId=org.testng; artifactId=testng; version=5.8;classifier=jdk15

对应的是 Java5 平台上 TestNG 的 5.8 版本

依赖

// TODO 待整理

常用插件

Maven本质上是一个插件框架,它的核心并不执行任何具体的构建任务,所有这些任务都交给插件来完成,例如编译源代码是由maven- compiler-plugin完成的。 进一步说,每个任务对应了一个插件目标(goal),每个插件会有一个或者多个目标,例如maven- compiler-plugin的compile目标用来编译位于src/main/java/目录下的主源码,testCompile目标用来编译位于src/test/java/目录下的测试源码。

用户可以通过两种方式调用Maven插件目标。 第一种方式是将插件目标与生命周期阶段(lifecycle phase)绑定,这样用户在命令行只是输入生命周期阶段而已,例如Maven默认将maven-compiler-plugin的compile目标与compile生命周期阶段绑定,因此命令mvn compile实际上是先定位到compile这一生命周期阶段,然后再根据绑定关系调用maven-compiler-plugin的compile目标。 第二种方式是直接在命令行指定要执行的插件目标,例如mvn archetype:generate 就表示调用maven-archetype-plugin的generate目标,这种带冒号的调用方式与生命周期无关。

maven-archetype-plugin

Archtype指项目的骨架

  • mvn archetype:generate => 生成一个很简单的项目骨架,帮助开发者快速上手。

maven-help-plugin

  • mvn help:system => 打印所有可用的环境变量和Java系统属性

  • mvn help:effective-pom => 打印项目的有效POM

  • mvn help:effective-settings => 打印项目的有效settings

maven-antrun-plugin

让用户在Maven项目中运行Ant任务。 用户可以直接在该插件的配置以Ant的方式编写Target(<tasks>...</tasks>),然后交给该插件的run目标去执行。 maven-antrun-plugin的run目标通常与生命周期绑定运行。

maven-dependency-plugin

maven-dependency-plugin最大的用途是帮助分析项目依赖

  • mvn dependency:list => 列出项目最终解析到的依赖列表

  • mvn dependency:analyze => 进一步的描绘项目依赖树

  • mvn dependency:tree => 可以告诉你项目依赖潜在的问题,如果你有直接使用到的却未声明的依赖,该目标就会发出警告。

  • mvn dependency:copy-dependencies => 将项目依赖从本地Maven仓库复制到某个特定的文件夹下面。

maven-resources-plugin

Maven区别对待Java代码文件和资源文件,maven-compiler-plugin用来编译Java代码,maven-resources-plugin则用来处理资源文件。

默认的主资源文件目录是src/main/resources,用户若需要添加额外的资源文件目录,这个时候就可以通过配置maven-resources-plugin来实现。

另外还可以进行资源文件过滤.

maven-surefire-plugin

用于执行测试。

只要你的测试类遵循通用的命令约定(以Test结尾、以TestCase结尾、或者以Test开头),就几乎不用知晓该插件的存在。

然而在当你想要跳过测试、排除某些测试类、或者使用一些TestNG特性的时候,了解 maven-surefire-plugin 的一些配置选项就很有用了。

exec-maven-plugin

它能让你运行任何本地的系统程序,在某些特定情况下,运行一个Maven外部的程序可能就是最简单的问题解决方案。

该插件还允许你配置相关的程序运行参数。

除了exec目标之外,exec-maven-plugin 还提供了一个java目标,该目标要求你提供一个mainClass参数,然后它能够利用当前项目的依赖作为classpath,在同一个JVM中运行该mainClass。

有时候,为了简单的演示一个命令行Java程序,你可以在POM中配置好exec-maven-plugin的相关运行参数,然后直接在命令运行 mvn exec:java 以查看运行效果。

jetty-maven-plugin

在进行Web开发的时候,打开浏览器对应用进行手动的测试几乎是无法避免的,这种测试方法通常就是将项目打包成war文件,然后部署到Web容器中,再启动容器进行验证,这显然十分耗时。

为了帮助开发者节省时间,jetty-maven-plugin 应运而生,它完全兼容 Maven项目的目录结构,能够周期性地检查源文件,一旦发现变更后自动更新到内置的Jetty Web容器中。

做一些基本配置后(例如Web应用的 contextPath 和自动扫描变更的时间间隔),你只要执行 mvn jetty:run ,然后在IDE中修改代码,代码经IDE自动编译后产生变更,再由 jetty-maven-plugin 侦测到后更新至Jetty容器,这时你就可以直接测试Web页面了。

需要注意的是, jetty-maven-plugin 并不是宿主于Apache或Codehaus的官方插件,因此使用的时候需要额外的配置 settings.xmlpluginGroups 元素,将 org.mortbay.jetty 这个 pluginGroup 加入。

Other

_maven.repositories 说明

// TODO

参考

Read More

简介

Morris.js 是一个轻量级的 JS 库,使用 jQueryRaphael 来生成各种图表 (目前仅支持 Line,Area,Bar,Donut 4种).

其特点: 使用简单,轻量.

快速开始

在页面中添加 morris.js 和 它的依赖库(jQueryRaphael)

<link rel="stylesheet" href="http://cdn.oesmith.co.uk/morris-0.5.0.min.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="http://cdn.oesmith.co.uk/morris-0.5.0.min.js"></script>

第一个图表

Start by adding a <div> to your page that will contain your chart. Make sure it has an ID so you can refer to it in your Javascript later.

<div id="myfirstchart" style="height: 250px;"></div>

Next add a <script> block to the end of your page, containing the following javascript code:

new Morris.Line({
  // ID of the element in which to draw the chart.
  element: 'myfirstchart',
  // Chart data records -- each entry in this array corresponds to a point on
  // the chart.
  data: [
	{ year: '2008', value: 20 },
	{ year: '2009', value: 10 },
	{ year: '2010', value: 5 },
	{ year: '2011', value: 5 },
	{ year: '2012', value: 20 }
  ],
  // The name of the data record attribute that contains x-values.
  xkey: 'year',
  // A list of names of data record attributes that contain y-values.
  ykeys: ['value'],
  // Labels for the ykeys -- will be displayed when you hover over the
  // chart.
  labels: ['Value'],
  // 默认情况下,Line 的 x 轴会自动格式为时间,可以如下手工取消.
  parseTime: false,
  // x 轴的文本说明倾斜角度
  xLabelAngle: 60,
  // 取消线段的平滑效果
  smooth: false
}).on('click', function(i,row) {
	// 点击事件
	window.location.href = "index.jsp?value=" + row.value;
});

大功告成!

获取更多帮助:主页.


Read More

gitlab 工作流程

gitlab help中建议的工作流程如下图.

gitlab workflow

  1. 开发成员拷贝管理员建立好的项目到自己本地。

  2. 创建自己的分支。

  3. 在自己的分支上写代码,并提交。

  4. 推送到远程服务器,分支是自己的分支。

  5. 在Commit页面上浏览分支。

  6. 创建一个合并请求。

  7. 团队的管理员或者领导者审查并且决定是否合并员工提交的分支到主分支上。

gitlab 角色与权限

gitlab help 中给出的角色与权限如下图.

gitlab permissions

其中

  • Master 对应团队的管理员/领导者.

  • Developer 对应开发成员

分支模型

参考”一个成功的Git分支模型”. 建立如下的分支模型

git branch model

  • master 分支
  • develop 分支
  • feature 分支
  • release 分支
  • hotfix 分支

gitlab 配置

建立 develop 分支

项目属性设置,锁定分支

合并分支(不建议使用gitlab的自动合并功能)

模拟操作

// TODO 待整理

参考


Read More

配置

用户信息

git config --global user.name "xxx xxx"
git config --global user.email "xxxx@example.com"

这两条配置很重要,每次 Git 提交时都会引用这两条信息,说明是谁提交了更新,所以会随更新内容一起被永久纳入历史记录

创建新库

在文件夹中执行:

git init

则,git 将在该文件夹中创建一个空的仓库。

克隆仓库

执行如下命令以创建一个本地仓库的克隆版本:

git clone /path/to/repository

如果是远端服务器上的仓库,可以用以下命令(视服务器协议而定):

git clone username@host:/path/to/repository

git clone https://sitename/path/repository.git
git clone git://sitename/path/repository.git

如果你熟悉其他的 VCS 比如 Subversion,你可能已经注意到这里使用的是 clone 而不是 checkout。 这是个非常重要的差别,Git 获取的是项目历史的所有数据(每一个文件的每一个版本),克隆之后,服务器上有的数据,本地也都有。 实际上,即便服务器的磁盘发生故障,用任何一个克隆出来的客户端都可以重建服务器上的仓库,回到当初克隆时的状态。

工作目录/暂存区/本地库

对于任何一个文件,在 Git 内都只有三种状态:已修改,已暂存和已提交。

三种状态分别对应三个区域:工作目录(working dir),暂存区(staging area),本地仓库(git dir)

Local Operations

工作流程

Git 基本工作流程如下:

  1. 运行命令git checkout branchname,将从本地仓库中检出 branchname 分支的文件到工作目录,然后就可进行修改了.

  2. 运行命令git add filename git add *,将新增的和修改的文件保存到暂存区(若要把删除的也记录入 git ,可运行 git add -A).

  3. 运行命令git commit -m "提交信息",将暂存区的文件提交至本地仓库,但还没到远端仓库.

推送

提交本地仓库后,执行如下命令将本地仓库内容提交到远端程仓库:

git push origin master

可以把 master 换成你想推送的任何分支.

可以使用以下命令为本地仓库添加远端仓库:

git remote add origin 远端仓库地址

如此就能将本地仓库推送到服务器上去了.

如果你使用了 git clone 远端仓库地址 命令克隆生成本地仓库的,git 自动为你增加一个名为 origin 的远端仓库.

分支

分支是用来从开发主线上分离开来的,然后在不影响主线的同时继续工作. Git 鼓励在工作流程中频繁使用分支与合并,哪怕一天之内进行许多次都没有关系。 在你创建仓库的时候,master 是“默认的”分支。 在其他分支上进行开发,完成后再将它们合并到主分支上。

git branch working

创建一个叫做”iss91v2”的分支,并切换过去:

git checkout -b iss91v2

切换回主分支:

git checkout master

删除”iss91v2”分支:

git branch -d iss91v2

除非你将分支推送到远端仓库,不然该分支就是 不为他人所见的:

git push origin iss91v2

更新与合并

要更新你的本地仓库至最新改动,执行:

git pull

该操作会合并你的工作目录和远端的改动(与 git fetch 有别)。

要合并其他分支到你的当前分支(例如 master),执行:

git merge branchname

在这两种情况下,git 都会尝试去自动合并改动。 遗憾的是,这可能并非每次都成功,并可能出现冲突。 这时候就需要你修改这些文件来手动合并这些冲突。 改完之后,你需要执行如下命令以将它们标记为合并成功:

git add filename

在合并改动之前,你可以使用如下命令预览差异:

git diff source_branch target_branch

使用图形化的比较工具可得到更好的效果。

打标签

为软件发布创建标签是推荐的(比如 v1.0 等等)。 执行如下命令创建一个叫做 v1.0 的标签:

git tag v1.0 1b2e1d63ff

1b2e1d63ff 是你想要标记的提交 ID 的前 10 位字符。 可以使用下列命令获取提交 ID:

git log

你也可以使用提交 ID 前几位,只要它的指向具有唯一性。

替换本地改动

假如你操作失误(当然,这最好永远不要发生),你可以使用如下命令替换掉本地改动: git checkout – filename

此命令会使用 HEAD 中的最新内容替换掉你的工作目录中的文件。 但已添加到暂存区的改动以及新文件不受此影响。

假如你想丢弃你在本地的所有改动与提交,可以到服务器上获取最新的版本历史,并将你本地主分支指向它:

git fetch origin
git reset --hard origin/master

参考:


Read More

安装

git Windows 版

git Linux 版

git OSX 版

客户端工具

安装客户端前都需要先安装 Git。

1. TortoiseGit

支持系统:windows

授权协议: GPLv2

TortoiseGit (海龟Git)是TortoiseSVN的Git版本,tortoisegit用于迁移TortoiseSVN到TortoiseGit

2. SourceTree

支持系统:windows7+ / OS X

授权协议: 免费,非开源

SourceTree 界面非常美观,可以方便管理多个 Git 项目,同时还支持 Hg,就是启动速度稍微有些慢,但是总体来说还是很不错的。

3. QGit

支持系统:Windows / Linux / BSD

授权协议: GPL

QGit 是一个基于 Qt/C++ 开发的 GIT 的图形化浏览器。可以用来浏览修订版记录、补丁内容以及更改的文件。

可自定义 diff 工具(diffuse,kompare)。

4. GitEye

支持系统:Windows / OS X / Linux

授权协: 免费,非开源

免费但需要注册。


Read More