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

TortoiseGit 常用菜单

当你在任一目录点击右键时, TortoiseGit 会出现两种菜单:

  • 你所点击的目录不是一个 git 的工作目录,则出现如下图1所示菜单.

git 菜单1

图1

  • 你所点击的目录是一个 git 工作目录时,则出现如下图2所示的菜单.

git 菜单2

图2

配置

配置用户

点击图1或图2中的 settings ,打开如下窗口.

git 用户配置

按照上图进行设置,然后”确定”即可.

配置ssh key

TortoiseGit 使用扩展名为ppk的密钥,而不是ssh-keygen生成的rsa密钥。 也就是说使用ssh-keygen -C “username@email.com” -t rsa产生的密钥在TortoiseGit中不能用。 而基于 github 或 gitlab 的开发必须要用到rsa密钥,因此需要用到TortoiseGit的putty key generator工具来生成密钥,配置步骤如下:

1.运行TortoiseGit开始菜单中的puttygen程序,如下图示

putty key 生成器

2.点击“Generate”按钮,鼠标在上图的空白地方来回移动直到进度条完毕,就会自动生一个随机的key,如下图示

putty key 生成

如有需要,可以为密钥设置对应的访问密码,就是修改上图中“Key passphrase”和“Confirm passphrase”的值。

3.将上图中多行文本框的内容全选、复制,并粘贴到github/gitlab账户的 SSH public key中。

4.点击上图中的“Save private key”按钮,将生成的key保存为适用于TortoiseGit的私钥(扩展名为.ppk)。

5.运行TortoiseGit开始菜单中的Pageant程序,程序启动后将自动停靠在任务栏中,双击该图标putty key ico,弹出key管理列表,如下图示

putty key 管理器

6.点击上图中的“Add Key”按钮,将第4步保存的ppk私钥添加进来,关闭对话框即可

7.经上述配置后,你就可以使用TortoiseGit进行push、pull操作了。

若没有设置 ssh key,则每次推送代码时,都会提示输入 github/gitlab 的用户和密码。

创建新库

在空文件夹下点击右键,然后选择图1中的 “Git Create repository here…“即可.

克隆仓库

在空文件夹下点击右键,然后选择图1中的 “Git Clone …“将打开如下图的窗口.

git 克隆仓库

其中 URL 为仓库源地址, Directory 为新建仓库的所在路径.

工作流程

基本工作流程如下:

1. 检出与切换

从本地仓库中检出或切换至 develop 分支的文件到工作目录进行修改:在图2中点击”Switch/Checkout…“,打开如下图的窗口.

git 切换分支

然后选择你想要切换的分支/标签,点击OK.

该界面亦可创建分支.

git 鼓励在工作流程中频繁使用分支与合并.即当要进行代码修改时,应该建立一个分支,当代码完成后再将该分支合并回主分支.

2. 提交

将暂存区的文件提交至本地仓库(在”Tortoisegit”中运行”Commit”操作会同时执行”git add”操作):在图2中点击”“,打开如下窗口.

git 提交

在”Message”处输入提交相关信息的描述,然后点击OK.

git 建议:在编写提交信息时,第一行应为标题,概括提交内容,然后空一行,再在第3行处进行详细描述.

注意:该操作并不提交到远端仓库.要提交到远端仓库,请看下面的”推送”.

推送

将本地的变更提交到远端仓库:在图2中点击”Push”,打开如下图窗口.

git 推送选择

其中:

Local 为本地的分支名称.

Remote 为远端仓库的分支名称.

选择”Push all branches”后会将本地所有分支推送到远端仓库.

Remote 为远端仓库,可通过”Manage”按钮进行设置,点击该按钮(或者在图1/图2中选择 “setting”)会出现如下图的窗口.

git 远端仓库设置

可在这里定义远端仓库.

所有选项选择完后,点击OK,即开始向远端仓库推送数据,如下图.

git 推送数据

更新与合并

要更新你的本地仓库至最新或从远程仓库拉取项目代码到本地库,可在图2中点击”Pull”或”Fetch”,打开如下图窗口进行操作.

git 拉取

“Pull”操作会合并你的工作目录和远端的改动。 而”Fetch”不会合并,但会丢弃你在本地的所有改动与提交。

要合并其他分支到你的当前分支(例如 master):在图2中点击”Merge”,打开如下窗口进行操作.

git 合并

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

标签

在图2中点击”Create Tag…“,打开如下图窗口

git 标签

历史

在图2中点击”Show log”,可显示项目的历史信息,如下图.

git Show log

进行比较

右键点击历史信息中的记录可以进行比较,如下图.

git diff

常用操作界面

在图2中点击”git Sync…“,打开如下窗口.

git 常用操作

该窗口包含了 git 的常用操作,如 Pull,Push,log,Commit等.


参考

TortoiseGit密钥的配置


Read More