获取 Node 中最近一次 git 提交的哈希值

Posted

技术标签:

【中文标题】获取 Node 中最近一次 git 提交的哈希值【英文标题】:Get hash of most recent git commit in Node 【发布时间】:2016-04-03 18:29:52 【问题描述】:

我想获取 NodeJS 中当前分支上最近提交的 id/hash。

在 NodeJS 中,我想获取关于 git 及其提交的最新 id/hash。

【问题讨论】:

您似乎已经找到了正确的节点模块。 Afaik 有例子可以做你想做的事。 @Sirko 希望提供链接。我今天早上搜索了文档,但没有找到。 您可以使用node-git lib 执行此操作。要获取 id,请查看 here,这是获取提交统计信息和哈希提交的示例。 入门:github.com/nodegit/nodegit/blob/master/examples/walk-history.js 另请参阅 nodegit.org/api/reference/#list 和 nodegit.org/api/repository/#getBranchCommit 【参考方案1】:

短解决方案,不需要外部模块(同步替代 Edin 的答案):

revision = require('child_process')
  .execSync('git rev-parse HEAD')
  .toString().trim()

如果要手动指定git项目的根目录,使用execSync的第二个参数传递cwdoption,如execSync('git rev-parse HEAD', cwd: __dirname)

【讨论】:

使用.slice(0, 7); 获取短sha。 @DanielSteigerwald 或git rev-parse --short HEAD 我不得不承认,我有点困惑为什么这个答案比four months before this answer发布的更详尽的答案(其中已经有这个解决方案)有更多的赞成票...跨度> 因为同步选项是两年后在 Edin 的回答中添加的。【参考方案2】:

解决方案 #1(需要 git,带有回调):

require('child_process').exec('git rev-parse HEAD', function(err, stdout) 
    console.log('Last commit hash on this branch is:', stdout);
);

或者,您可以使用execSync() 来避免回调。

解决方案 #2(不需要 git):

获取文件.git/HEAD的内容 如果 git repo 处于 detached head 状态,内容将是哈希 如果 git repo 在某个分支上,内容将类似于:“refs: refs/heads/current-branch-name” 获取.git/refs/heads/current-branch-name的内容 处理此过程中所有可能的错误 直接从master分支获取最新的hash,可以获取文件内容:.git/refs/heads/master

可以这样编码:

const rev = fs.readFileSync('.git/HEAD').toString().trim();
if (rev.indexOf(':') === -1) 
    return rev;
 else 
    return fs.readFileSync('.git/' + rev.substring(5)).toString().trim();

【讨论】:

选择这个是因为我喜欢你不必像 Paulpro 的回答那样指定 path_to_repo 虽然这可行,但@Paulpro 的答案更便携(不依赖于安装 git)、更快(child_process.exec 需要一段时间才能生成),并且保持“在节点中”(如OP想要)。 @CameronTacklind 并非如此,它依赖于编译与 libgit2 的绑定,这需要安装比仅安装 git 本身更多的软件。我已经包含了 w/ 和 w/o git 解决方案,因为这是公认的答案。 @edin-m 哪一部分“不是真的”?我相信我所说的一切都是正确的。当然,有些人会发现安装 NodeGit 比较麻烦,但这并不重要。依赖安装的git 可能不太便携,但不可否认,在实践中,git 相当普遍。正如@hakatashi 指出的那样,保持“节点”的另一种方法是(您已在此处提供)。任何产生/执行另一个二进制文件的东西都不会留在“节点”恕我直言。 鉴于我们正在寻找一个 git 提交,它是仅在 git 管理的目录中才有意义的数据,隐藏的 .git 目录由 git 本身创建(你没有如果你刚刚从 github、gitlab 或任何其他 git 托管服务下载了一个版本),那么 git 将不可用的想法是......令人困惑,充其量是?如果没有安装 git 并管理目录,则 没有 git 提交可供查看。【参考方案3】:

使用nodegit,将path_to_repo 定义为一个字符串,其中包含您要为其获取提交sha 的repo 的路径。如果您想使用运行进程的目录,请将path_to_repo 替换为process.cwd()

var Git = require( 'nodegit' );

Git.Repository.open( path_to_repo ).then( function( repository ) 
  return repository.getHeadCommit( );
 ).then( function ( commit ) 
  return commit.sha();
 ).then( function ( hash ) 
  // use `hash` here
 );

【讨论】:

只是在我的机器上 FIY,这大约比来自@antoine129 的更被接受的答案快 3.2 倍。 execSync 大约需要 6.4 毫秒,而 nodegit 只需要大约 1.8 毫秒 nodegit 在大多数情况下是最佳选择 这应该是公认的答案。它是唯一保持“在节点中”并且对变化的分支具有鲁棒性的答案。 在低于 10 毫秒的范围内需要多长时间真的很重要吗?特别是如果您在 main 开始时执行此操作并将其存储以供以后使用(而不是每次需要时都执行此操作)。添加另一个依赖于477 more dependencies的依赖似乎也有点矫枉过正(如果你只是为此使用它)。但我猜一个空的 Next.js 项目使用的数量大致相同......【参考方案4】:

我受到edin-m's "Solution #2 (no git required)" 的启发,但我不喜欢substring(5) 部分,这感觉像是一个危险的假设。我觉得我的 RegEx 对 git 对该文件的宽松要求所允许的变化更加宽容。

以下演示显示它适用于签出分支和“分离的 HEAD”。

$ cd /tmp

$ git init githash
Initialized empty Git repository in /private/tmp/githash/.git/

$ cd githash

$ cat > githash.js <<'EOF'
const fs = require('fs');

const git_hash = () => 
    const rev = fs.readFileSync('.git/HEAD').toString().trim().split(/.*[: ]/).slice(-1)[0];
    if (rev.indexOf('/') === -1) 
        return rev;
     else 
        return fs.readFileSync('.git/' + rev).toString().trim();
    



console.log(git_hash());

EOF

$ git add githash.js

$ git commit -m 'https://***.com/a/56975550/117471'
[master (root-commit) 164b559] https://***.com/a/56975550/117471
 1 file changed, 14 insertions(+)
 create mode 100644 githash.js

$ node githash.js
164b559e3b93eb4c42ff21b1e9cd9774d031bb38

$ cat .git/HEAD
ref: refs/heads/master

$ git checkout 164b559e3b93eb4c42ff21b1e9cd9774d031bb38
Note: checking out '164b559e3b93eb4c42ff21b1e9cd9774d031bb38'.

You are in 'detached HEAD' state.

$ cat .git/HEAD
164b559e3b93eb4c42ff21b1e9cd9774d031bb38

$ node githash.js
164b559e3b93eb4c42ff21b1e9cd9774d031bb38

【讨论】:

【参考方案5】:

如果你总是在特定的分支上,你可以阅读.git/refs/heads/&lt;branch_name&gt; 以轻松获取提交哈希。

const fs = require('fs');
const util = require('util');

util.promisify(fs.readFile)('.git/refs/heads/master').then((hash) => 
    console.log(hash.toString().trim());
);

【讨论】:

【参考方案6】:

这是我设计的一个使用fs.promisesasync/await 的版本。

import default as fsWithCallbacks from 'fs';
const fs = fsWithCallbacks.promises;

const getGitId = async () => 
  const gitId = await fs.readFile('.git/HEAD', 'utf8');
  if (gitId.indexOf(':') === -1) 
    return gitId;
  
  const refPath = '.git/' + gitId.substring(5).trim();
  return await fs.readFile(refPath, 'utf8');
;

const gitId = await getGitId();

【讨论】:

【参考方案7】:

你也可以使用git-fs(它在npm上叫git-fs,在Github上叫node-git。)

Git('path/to/repo')
Git.getHead((err, sha) => 
    console.log('The hash is: ' + sha)
)

同一模块可以从 repo 中读取目录和文件。

【讨论】:

以上是关于获取 Node 中最近一次 git 提交的哈希值的主要内容,如果未能解决你的问题,请参考以下文章

从分支获取最新 Git 提交哈希的命令

在 Git 中,如何将当前提交哈希写入同一提交中的文件

git将代码提交错了分支

git提交的具体操作

Git Tag 列表,显示提交 sha1 哈希

如何获取按最近提交排序的 Git 分支列表?