获取推送到TFS Git存储库时提交的文件列表

时间:2016-03-28 01:25:58

标签: git tfs tfs2015

如何在提交/推送中将所有文件迭代到TFS中的Git存储库?我正在编写服务器端插件,需要访问推送期间提交的文件列表。我有插件工作并获取提交消息,但也需要文件列表。

此外,有没有办法在推送到服务器后修改提交消息?我们想要表示ID(#12345)是PBI,任务还是Bug

由于

斯科特

2 个答案:

答案 0 :(得分:3)

  

如何在提交/推送中将所有文件迭代到TFS中的Git存储库?我正在编写服务器端插件,需要访问推送期间提交的文件列表。我有插件工作并获取提交消息,但也需要文件列表。

提交是工作树的完整快照,因此每次提交都包含中的每个文件。我确信这不是你想要的,但它是理解如何获得你想要的东西的关键,也许更重要的是,如何弄明白特别是你想要合并提交的内容。

例如,假设在服务器上,在一个钩子中,你得到一个接收前或接收后的输入行,或者更新钩子的参数,说:

  • 我打算/我确实更改了参考refs/heads/foo
  • 旧值为/ c13f98a...
  • 新值将是/ 0b4a13e...

(这是信息在钩子中到达的方式。在预接收或后接收钩子中,您从标准输入读取一系列行,每行包含新旧散列和引用名称,其中在一个更新钩子中,脚本的三个参数按顺序给出了引用名称和旧的和新的哈希。在预接收和更新钩子中,更新还没有发生,你的脚本可以禁止它,在post-receive钩子中,引用已经更新,你只有第二次机会检查结果。)

最多两个哈希值中的一个可能是全零空哈希。在这种情况下,正在创建或删除引用(分支,标记,注释或其他任何内容)。否则两个哈希都有效并且正在移动引用。

如果引用是分支名称 - 以refs/heads/开头;名称的其余部分(可能包括更多斜杠)是分支名称 - 然后更新可能使某些提交可以访问和/或使其他提交无法从新哈希中访问,即,将一些提交放入和/或删除一些从那个分支提交。 (包括标签在内的所有其他更新也是如此,尽管通常只是完全拒绝标签更新,通常我们不会尝试从标签中遍历提交DAG。)

请注意,尽管某些提交通过名称可以重新访问或无法访问,但无法保证这些提交之前完全无法访问,或者现在完全无法访问。例如,假设在调用钩子之前,现有的提交图包含此片段:

... - E - F - H   <-- refs/heads/foo
        \   /
          G       <-- refs/heads/bar

其中EFH是提交&#34;在分支foo&#34; H是合并提交,EG是提交&#34;在分支bar&#34;上。然后,您会收到一条更新请求,说明&#34;移动bar以指向提交H&#34; (以便foobar都指向同一个提交。合并提交H不是新的,它只是通过分支bar 成为新的:它已经可以通过分支foo到达。后续强制推送会重置bar以指回G(如果原始推送出错)会使H无法访问bar,但仍可从foo访问{1}}。

因此,根据精确您想要的内容,您通常会首先使用设计git rev-list来获取并处理已变得可访问或无法访问的提交ID列表。做到这一点:

for i in $(git rev-list $old..$new); ... done # newly reachable
for i in $(git rev-list $new..$old); ... done # newly unreachable

(您可能会预先获得这些列表,也许可以计算它们。)在预接收挂钩中,您还可以检查是否有任何其他引用更新将使新可达的提交可达(通过其他名称),在预接收或更新挂钩中,您可以查看当前的,尚未更新的引用(例如,使用git for-each-refgit rev-list --all,或者其他你需要)看看是否已经可以通过其他名称访问新的可访问提交。 (在收发后的钩子中,你可以做同样的事情,但由于引用已经更新,因此你需要以编程方式计算他们的预更新值,包括假装恢复任何已删除的引用。)

每个列表中的每个提交$i可以是普通的非合并提交,其具有单个父级;或者它可能是合并提交,根据定义,它有两个或更多父母。

对于普通的非合并提交,与其父相比,获取更改集很容易:只需在两个哈希上运行git diff(使用--name-only--name-status获取我确定您正在寻找的信息。

但是,对于合并提交,它更难,因为合并有两个或更多父母。如果文件xyzzy与合并的一个父项完全相同但又与另一个父项不同,您需要决定它意味着什么,以及您是否关心它与哪个父项不同。您关心的是这些文件与第一个父文件的比较(这意味着您可以使用与非合并相同的代码,使用${i}^获取提交的机会有点好$i git diff执行0b4a13e...的第一位父母,但在这里您需要更多不同或更多内容的机会也不错。

(请注意,我对你已经拥有的软件一无所知,但我可以说许多钩子编写者错误地了解了很多这些细节,因为他们没有考虑(或者甚至不知道)可能性强制推送可能会在删除3时添加5次提交,和/或所谓的&#34; evil&#34;合并可能会隐藏在任何父级中没有出现的更改中(git&#39; s 组合差异旨在找到此类更改。)

  

此外,有没有办法在推送到服务器后修改提交消息?我们想要表示ID(#12345)是PBI,任务还是Bug

没有。修改提交的任何是不可能的,因为提交的哈希ID(git notes)是内容的加密校验和提交。更改任何内容,甚至是一点,并且校验和会发生显着且不可预测的变化(当然,#34;可预测&#34;当然,通过执行新内容的校验和)。这正是使下游用户难以进行上游重组的原因:您没有更改提交,您将其复制到提交并告诉所有人&#34;请忘记那些旧的,并使用这些新的&#34;。

编辑:我忘了提到这种事情(在提交中添加注释)是git log的目的。它们的工作方式不是通过实际修改提交本身,而是通过添加0b4a13e...自动查询的特殊类型的包。实现机制非常棘手,但它归结为这样一个事实:提交由其哈希(git log再次)唯一标识,因此refs/heads/notes可以查看0b4a13e...引用以查看如果有git log的其他信息。如果是这样,--no-notes会将该信息添加到日志中,除非您告诉它不要(--notes=refs/notes/foo)或将其指向不同的引用(例如{{1}})。

答案 1 :(得分:0)

  

如何在提交/推送中将所有文件迭代到TFS中的Git存储库?我正在编写服务器端插件,需要访问推送期间提交的文件列表。我有插件工作并获取提交消息,但也需要文件列表。

ISubscriber接口的一部分是以下方法:

public EventNotificationStatus ProcessEvent(IVssRequestContext requestContext, NotificationType notificationType, object notificationEventArgs, out int statusCode, out string statusMessage, out ExceptionPropertyCollection properties)

这是插件的入口点。此处的notificationEventArgs参数是您订阅的类型之一。如果您订阅Microsoft.TeamFoundation.Git.Server.PushNotification类型,则可以使用以下内容获取文件名:

var repositoryService = requestContext.GetService<ITeamFoundationGitRepositoryService>();
var repository = repositoryService.FindRepositoryById(requestContext, (notificationEventArgs as PushNotification).RepositoryId);
var diffEntries = new List<TfsGitDiffEntry>();
var commits = (notificationEventArgs as PushNotification).IncludedCommits;
foreach(var item in commits)
{
  var gitCommit = repository?.LookupObject(item)?.ResolveToCommit();
  var manifest = gitCommit.GetManifest(true);
  diffEntries.AddRange(manifest.Where(x.NewObjectType == GitObjectType.Blob));
}

var files = diffEntries.Select(d => d.RelativePath).Distinct();

TfsGitDiffEntry对象也可用于确定各种内容,请参阅类引用以获取更多信息:https://msdn.microsoft.com/query/dev14.query?appId=Dev14IDEF1&l=EN-US&k=k(Microsoft.TeamFoundation.Git.Server.TfsGitDiffEntry);k(TargetFrameworkMoniker-.NETFramework,Version%3Dv4.6.1);k(DevLang-csharp)&rd=true

TfsGitDiffEntry获取文件的内容非常简单:

var oldFileContentsStream = repository.LookupObject<TfsGitBlob>(diffEntry.OldObjectId.Value).GetContent();

var newFileContentsStream = repository.LookupObject<TfsGitBlob>(diffEntry.NewObjectId.Value).GetContent();
  

此外,有没有办法在推送到服务器后修改提交消息?我们想要表示ID(#12345)是PBI,任务还是Bug

在我的实验中,我找不到办法做到这一点。