jgit git pull_如何使用JGit管理Git子模块

jgit git pull

对于使用Git的大型项目,您可能会发现自己想要在多个存储库之间共享代码。 无论是项目之间的共享库,还是模板之间的共享库,都可以在多个不同产品之间使用。 这个问题的Git内置答案是子模块。 它们允许将另一个存储库的副本作为存储库中的子目录放置(有时也称为超级项目)。 子模块本身就是一个存储库。 您可以像在任何其他存储库中一样在其中进行提交,分支,变基等操作。

JGit提供了实现大多数Git子模块命令的API。 我想向您介绍这个API。

设置

本文中使用的代码段被编写为学习测试 1 。 简单的测试可以帮助您了解第三方代码的工作方式并采用新的API。 可以将它们视为受控实验,使您能够准确发现第三方代码的行为。

一个有益的副作用是,如果保留测试,它们可以帮助您验证第三方代码的新版本。 如果您的测试涵盖了如何使用该库,那么第三方代码中不兼容的更改将在早期显示出来。

返回主题:所有测试共享相同的设置。 有关详细信息,请参见完整的源代码 。 有一个名为parent的空存储库。 旁边有一个图书馆资料库。 测试会将其作为子模块添加到父级。 库存储库具有一个初始提交,其中包含名为readme.txt的文件。 setUp方法将创建两个存储库,如下所示:

Git git = Git.init().setDirectory( "/tmp/path/to/repo" ).call();

存储库通过字段Git类型的parent和library表示。 此类包装存储库,并提供对JGit中所有可用命令的访问。 如前所述 ,每个Command类都对应一个本地的Git pocelain命令。 要调用命令,将使用构建器模式。 例如,Git.commit()方法的结果实际上是一个CommitCommand。 提供任何必要的参数后,您可以调用其call()方法。

添加一个子模块

显而易见的第一步是将子模块添加到现有存储库中。 使用上面概述的设置,应该将库存储库作为子模块添加到父存储库的modules / library目录中。

@Test
public void testAddSubmodule() throws Exception {
  String uri 
    = library.getRepository().getDirectory().getCanonicalPath();
  SubmoduleAddCommand addCommand = parent.submoduleAdd();
  addCommand.setURI( uri );
  addCommand.setPath( "modules/library" );
  Repository repository = addCommand.call();
  repository.close();

  F‌ile workDir = parent.getRepository().getWorkTree();
  F‌ile readme = new F‌ile( workDir, "modules/library/readme.txt" );
  F‌ile gitmodules = new F‌ile( workDir, ".gitmodules" );
  assertTrue( readme.isF‌ile() );
  assertTrue( gitmodules.isF‌ile() );
}

SubmoduleAddCommand需要知道的两件事是:从哪里克隆子模块以及应该从哪里存储子模块。 URI(不应该称为URL?)属性表示要从其克隆命令克隆的存储库的位置。 路径属性指定子模块应放在哪个目录中(相对于父存储库的工作目录根目录)。 运行命令后,父存储库的工作目录如下所示:

子模块树 库存储库位于modules / library目录中,其工作树已检出。 call()返回一个Repository对象,您可以像常规存储库一样使用它。 这也意味着您必须显式关闭返回的存储库,以避免泄漏文件句柄。

该图像显示SubmoduleAddCommand还做了另一件事。 它在父存储库工作目录的根目录中创建了一个.gitmodules文件,并将其添加到索引中。

[submodule "modules/library"]
path = modules/library
url = git@example.com:path/to/lib.git

如果您查看过Git配置文件,则将识别语法。 该文件列出了从该存储库引用的所有子模块。 对于每个子模块,它存储存储库的URL和被拉入的本地目录之间的映射。 提交并推送此文件后,克隆存储库的每个人都知道从何处获取子模块(有关更多信息)。

库存

添加子模块后,我们可能想知道父存储库实际上已知道它。 第一个测试进行了幼稚的检查,以验证是否存在某些文件和目录。 但是,还有一个API可以列出存储库的子模块。 这是下面的代码的作用:

@Test
public void testListSubmodules() throws Exception {
  addLibrarySubmodule();

  Map<String,SubmoduleStatus> submodules 
    = parent.submoduleStatus().call();

  assertEquals( 1, submodules.size() );
  SubmoduleStatus status = submodules.get( "modules/library" );
  assertEquals( INITIALIZED, status.getType() );
}

SubmoduleStatus命令返回存储库中所有子模块的映射,其中键是子模块的路径,值是SubmoduleStatus。 通过上面的代码,我们可以验证刚刚添加的子模块是否确实存在并已初始化。 该命令还允许添加一个或多个路径以将状态报告限制为该路径。

说到状态,JGit的StatusCommand与本地Git不在同一级别。 始终将子模块视为命令使用‐‐ignore-submodules = dirty运行 :忽略子模块工作目录的更改。

更新子模块

子模块始终指向它们代表的存储库的特定提交。 将来某个时候克隆父存储库的人将获得完全相同的子模块状态,尽管子模块可能在上游有新的提交。

为了更改修订版,您必须显式更新一个子模块,如下所示:

@Test
public void testUpdateSubmodule() throws Exception {
  addLibrarySubmodule();
  ObjectId newHead = library.commit().setMessage( "msg" ).call();

  File workDir = parent.getRepository().getWorkTree();
  Git libModule = Git.open( new F‌ile( workDir, "modules/library" ) );
  libModule.pull().call();
  libModule.close();
  parent.add().addF‌ilepattern( "modules/library" ).call();
  parent.commit().setMessage( "Update submodule" ).call();

  assertEquals( newHead, getSubmoduleHead( "modules/library" ) );
}

这个相当长的代码片段首先将某些内容提交到库存储库(第4行),然后将库子模块更新为最新的提交(第7至9行)。

要使更新永久生效,必须提交子模块(第10和11行)。 提交将子模块的更新后的提交ID存储在其名称下(在此示例中为模块/库)。 最后,您通常希望推送更改以使其对其他人可用。

更新对父存储库中子模块的更改

从上游获取提交到父存储库也可能会更改子模块配置。 但是,这些子模块不会自动更新。

这就是SubmoduleUpdateCommand解决的问题。 在不进行进一步参数化的情况下使用该命令将更新所有已注册子模块。 该命令将克隆缺少的子模块,并检出配置中指定的提交。 与其他子模块命令一样,有一个addPath()方法仅更新给定路径内的子模块。

使用子模块克隆存储库

同时,您可能已经掌握了模式,与子模块有关的一切都是手工劳动。 克隆具有子模块配置的存储库默认情况下不会克隆子模块。 但是CloneCommand具有cloneSubmodules属性,并将其设置为true,同样,它还会克隆配置的子模块。 在克隆(父)存储库并检出其工作目录之后,在内部递归执行SubmoduleInitCommand和SubmoduleUpdateCommand。

卸下子模块

要删除子模块,您可能希望编写类似

git.submoduleRm().setPath( ... ).call();

不幸的是,本机Git和JGit都没有内置命令来删除子模块。 希望将来能解决。 在此之前,我们必须手动删除子模块。 如果向下滚动到removeSubmodule()方法,您将发现这不是火箭科学。

首先,从.gitsubmodules和.git / config文件中删除相应的子模块部分。 然后,索引中的子模块条目也将被删除。 最后,提交更改-.gitsubmodules和索引中已删除的子模块-并将子模块内容从工作目录中删除。

每个子模块

Native Git提供了git submodule foreach命令来为每个子模块执行一个shell命令。 虽然JGit不完全支持这样的命令,但它提供了SubmoduleWalk 。 此类可用于遍历存储库中的子模块。 以下示例为所有子模块获取上游提交。

@Test
public void testSubmoduleWalk() throws Exception {
  addLibrarySubmodule();

  int submoduleCount = 0;
  Repository parentRepository = parent.getRepository();
  SubmoduleWalk walk = SubmoduleWalk.forIndex( parentRepository );
  while( walk.next() ) {
    Repository submoduleRepository = walk.getRepository();
    Git.wrap( submoduleRepository ).fetch().call();
    submoduleRepository.close();
    submoduleCount++;
  }
  walk.release();

  assertEquals( 1, submoduleCount );
}

使用next(),可以将步移到下一个子模块。 如果没有更多子模块,则该方法返回false。 使用SubmoduleWalk完成后,应通过调用release()释放其分配的资源。 同样,如果您获得子模块的Repository实例,请不要忘记关闭它。

SubmoduleWalk也可以用于收集有关子模块的详细信息。 它的大多数获取器都与当前子模块的属性有关,例如路径,头,远程URL等。

同步远程URL

我们之前已经看到,子模块配置存储在存储库工作目录根目录下的.gitsubmodules文件中。 好吧,至少可以在.git / config中覆盖远程URL。 然后是子模块本身的配置文件。 这又可以具有另一个远程URL。 该SubmoduleSyncCommand可用于所有远程URL重置为.gitmodules设置

如您所见,JGit对子模块的支持几乎与本地Git处于同等水平。 它的大多数命令都可以轻松实现或仿真。 而且,如果您发现某些问题不起作用或缺少,可以随时向友好而乐于助人的JGit社区寻求帮助。

  1. 这个词是从部分采取“探索和学习界限”由罗伯特C. Martin在清洁守则

翻译自: https://www.javacodegeeks.com/2014/04/how-to-manage-git-submodules-with-jgit.html

jgit git pull

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值