如何计算Git树哈希?

16

我需要为一个nodejs项目确定我的文件夹的哈希值以检查版本。实际上,我编写了一个脚本来测试我的代码(没有使用文件系统,直接使用git api进行测试)。但是它只有一半的时间能正常工作。

  • A1有效;
  • A2无效,因为我得到的哈希不同;
  • A3有效;
  • A4有效;

我使用此API获取哈希:https://api.github.com/repos/zestedesavoir/zds-site/branches/dev

制作了一个Perl脚本版本来检查我的JavaScript代码。它返回相同的结果。我认为我的错误在于Object.values(json.tree).forEach(function (blob),这个模式可能与text += blob.mode + " " + blob.path + "\0" + sha;不匹配。我不知道原因。

我的JavaScript脚本:

(在线演示:https://repl.it/repls/FearfulWhiteShelfware)

const crypto = require("crypto"),
      fs = require("fs"),
      path = require("path"),
      getURL = require("./ajax.js").getURL;

const apiJSON = [];
//https://api.github.com/
const hashs = [
  "8d66139b3acf78fa50e16383693a161c33b5e048",
  "4ef57de8e81c8415d6da2b267872e602b1f28cfe",
  "13b54c0bab5e7f7a05398d6d92e65eee2b227136",
  "218a8f506fcd3076fad059ec42d4656c635a8171"
];

let loaded = 0;

const USEAPI = false; /*  becarful low limit on repl.it */

for (let i = 0; i < hashs.length; i++) {
  if (!USEAPI) {
    apiJSON[i] = JSON.parse(fs.readFileSync(`a${i+1}.json`));
    console.log(`A${i+1}:`);
    getTreeSHA(apiJSON[i], false);

    if (i+1 === hashs.length) {
      console.log("\n\nPerl ouput:");
      for (let j = 0; j < hashs.length; j++)
        getTreeSHA(apiJSON[j], true);
    }
  } else {
    getURL("/repos/zestedesavoir/zds-site/git/trees/" + hashs[i], function(json) {
      loaded++; apiJSON[i] = json;
      if (loaded === hashs.length) {
        for (let i = 0; i < hashs.length; i++) {
          console.log(`A${i+1}:`); getTreeSHA(apiJSON[i], false);
        }
        console.log("\n\nPerl ouput:");
        for (let i = 0; i < hashs.length; i++)
          getTreeSHA(apiJSON[i], true);
      }
    });
  }
}

function getTreeSHA(json, getPattern) {
  /*json.tree.sort((a, b) => { ---> not good see A3 & A4
    if (a.type !== b.type)
      if (a.type === "tree")
        return 1;
      else if (b.type === "tree")
        return -1;
    return a.path.charCodeAt(0) - b.path.charCodeAt(0)
  });*/

  let text = "";

  Object.values(json.tree).forEach(function (blob) {
      const sha = Buffer.from(blob.sha, "hex").toString(!getPattern ? "binary" : "hex");
      text += (+blob.mode) + " " + blob.path;
      //       ^ https://dev59.com/5ek5XIcBkEYKwwoY597h#54137728
      text += (!getPattern) ? ("\0" + sha) : (" " + sha + "\n");
  });

  if (getPattern) return console.log(text.replace(/\0/g, ""));

  console.log("Original " + json.sha);
  const pattern = "tree " + text.length + "\0" + text;
  console.log("Actual : " + sha1(pattern));

  function sha1(data) {
      return crypto.createHash("sha1").update(data, "binary").digest("hex");
  }
}

输出:

A1:
Original 8d66139b3acf78fa50e16383693a161c33b5e048
Actual : 8d66139b3acf78fa50e16383693a161c33b5e048
A2:
Original 4ef57de8e81c8415d6da2b267872e602b1f28cfe
Actual : c5c701b8114582e3bb2e353aac157a7febfcd33b <-- not god
A3:
Original 13b54c0bab5e7f7a05398d6d92e65eee2b227136
Actual : 13b54c0bab5e7f7a05398d6d92e65eee2b227136
A4:
Original 218a8f506fcd3076fad059ec42d4656c635a8171
Actual : 218a8f506fcd3076fad059ec42d4656c635a8171

期望输出:

//...
A2:
Original 4ef57de8e81c8415d6da2b267872e602b1f28cfe
Actual: 4ef57de8e81c8415d6da2b267872e602b1f28cfe
//...

A2:

{
  "sha": "4ef57de8e81c8415d6da2b267872e602b1f28cfe",
  "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/4ef57de8e81c8415d6da2b267872e602b1f28cfe",
  "tree": [
    {
      "path": ".coveragerc",
      "mode": "100644",
      "type": "blob",
      "sha": "449170d0faeb75182310345564fd1811c0b9fd73",
      "size": 163,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/449170d0faeb75182310345564fd1811c0b9fd73"
    },
    {
      "path": ".editorconfig",
      "mode": "100644",
      "type": "blob",
      "sha": "75884936ea2d35b531af886acad747d4fd9b2a9e",
      "size": 328,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/75884936ea2d35b531af886acad747d4fd9b2a9e"
    },
    {
      "path": ".flake8",
      "mode": "100644",
      "type": "blob",
      "sha": "69e872e30d30f5c7de3276d289d6aee81ccf4af7",
      "size": 232,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/69e872e30d30f5c7de3276d289d6aee81ccf4af7"
    },
    {
      "path": ".github",
      "mode": "040000",
      "type": "tree",
      "sha": "56b49acad224fdb70fca11809f3e5a4d396cb01c",
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/56b49acad224fdb70fca11809f3e5a4d396cb01c"
    },
    {
      "path": ".gitignore",
      "mode": "100644",
      "type": "blob",
      "sha": "4832b44b973574253cf1b59ba7a66cfc227cd699",
      "size": 1439,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/4832b44b973574253cf1b59ba7a66cfc227cd699"
    },
    {
      "path": ".jshintrc",
      "mode": "100644",
      "type": "blob",
      "sha": "939efa02939437adece1e3a076d597b2557e36b5",
      "size": 319,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/939efa02939437adece1e3a076d597b2557e36b5"
    },
    {
      "path": ".travis.yml",
      "mode": "100644",
      "type": "blob",
      "sha": "6b5e4f43790874e2cf9db23e964f72b99deeb0d1",
      "size": 6040,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/6b5e4f43790874e2cf9db23e964f72b99deeb0d1"
    },
    {
      "path": "AUTHORS",
      "mode": "100644",
      "type": "blob",
      "sha": "0b92b7759ce2dd0a7cacf79b273368bb71ac5397",
      "size": 197,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/0b92b7759ce2dd0a7cacf79b273368bb71ac5397"
    },
    {
      "path": "CODE_OF_CONDUCT.md",
      "mode": "100644",
      "type": "blob",
      "sha": "ae61c31efae6cea565e447467e4377da76125679",
      "size": 2754,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/ae61c31efae6cea565e447467e4377da76125679"
    },
    {
      "path": "CONTRIBUTING.md",
      "mode": "100644",
      "type": "blob",
      "sha": "ac71ad378faf7fb7ae927b20d4d28a57c6085bf9",
      "size": 155,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/ac71ad378faf7fb7ae927b20d4d28a57c6085bf9"
    },
    {
      "path": "COPYING",
      "mode": "100644",
      "type": "blob",
      "sha": "94a9ed024d3859793618152ea559a168bbcbb5e2",
      "size": 35147,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/94a9ed024d3859793618152ea559a168bbcbb5e2"
    },
    {
      "path": "Gulpfile.js",
      "mode": "100644",
      "type": "blob",
      "sha": "5dd951ae61f0913605197fafa018f7db49549a68",
      "size": 6137,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/5dd951ae61f0913605197fafa018f7db49549a68"
    },
    {
      "path": "LICENSE",
      "mode": "100644",
      "type": "blob",
      "sha": "8a171a155d85927b678068becd046194aea777a9",
      "size": 717,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/8a171a155d85927b678068becd046194aea777a9"
    },
    {
      "path": "Makefile",
      "mode": "100644",
      "type": "blob",
      "sha": "cc722c2bc71dfbaa1b025c8c56245ed0fcd61739",
      "size": 3829,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/cc722c2bc71dfbaa1b025c8c56245ed0fcd61739"
    },
    {
      "path": "README.md",
      "mode": "100644",
      "type": "blob",
      "sha": "a6a9013159a3766da62443c4be5e267435469fd9",
      "size": 3280,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/a6a9013159a3766da62443c4be5e267435469fd9"
    },
    {
      "path": "assets",
      "mode": "040000",
      "type": "tree",
      "sha": "1846a32450eb2a7605acb55cab8206028cfb656f",
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/1846a32450eb2a7605acb55cab8206028cfb656f"
    },
    {
      "path": "doc",
      "mode": "040000",
      "type": "tree",
      "sha": "f55b804a2b694db577b20c8e9851ad783fea8ee5",
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/f55b804a2b694db577b20c8e9851ad783fea8ee5"
    },
    {
      "path": "errors",
      "mode": "040000",
      "type": "tree",
      "sha": "b37a18162be2bdae7382fc194f1bf2d0ab89bba3",
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/b37a18162be2bdae7382fc194f1bf2d0ab89bba3"
    },
    {
      "path": "export-assets",
      "mode": "040000",
      "type": "tree",
      "sha": "3a8b85efa969c389ac3c5e7e6ad62206dbddcaca",
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/3a8b85efa969c389ac3c5e7e6ad62206dbddcaca"
    },
    {
      "path": "fixtures",
      "mode": "040000",
      "type": "tree",
      "sha": "89cacb4de6feb81a962b9a992b9434cb44d3b0aa",
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/89cacb4de6feb81a962b9a992b9434cb44d3b0aa"
    },
    {
      "path": "geodata",
      "mode": "040000",
      "type": "tree",
      "sha": "635d29035ae7528231edb9b74eb09887c22dda2a",
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/635d29035ae7528231edb9b74eb09887c22dda2a"
    },
    {
      "path": "manage.py",
      "mode": "100755",
      "type": "blob",
      "sha": "458f6e2df8b431b9fa819c89e82cebf2e0a91260",
      "size": 1536,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/458f6e2df8b431b9fa819c89e82cebf2e0a91260"
    },
    {
      "path": "package.json",
      "mode": "100644",
      "type": "blob",
      "sha": "02d231aa0c0fa299581be07bcece0393dc9a9e47",
      "size": 1402,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/02d231aa0c0fa299581be07bcece0393dc9a9e47"
    },
    {
      "path": "quotes.txt",
      "mode": "100644",
      "type": "blob",
      "sha": "e8e84a048d70bc57c1f725fc12f2101a40c5dcbb",
      "size": 1552,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/e8e84a048d70bc57c1f725fc12f2101a40c5dcbb"
    },
    {
      "path": "requirements-dev.txt",
      "mode": "100644",
      "type": "blob",
      "sha": "7297a894036fcf70a7209062bb51f45db1b71d39",
      "size": 227,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/7297a894036fcf70a7209062bb51f45db1b71d39"
    },
    {
      "path": "requirements-prod.txt",
      "mode": "100644",
      "type": "blob",
      "sha": "2f957115bcf3794fdecf3c4848f21ae8f428c31b",
      "size": 83,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/2f957115bcf3794fdecf3c4848f21ae8f428c31b"
    },
    {
      "path": "requirements.txt",
      "mode": "100644",
      "type": "blob",
      "sha": "805fefa566ef0d8f6a7c7e58d01fa4684078cf50",
      "size": 998,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/805fefa566ef0d8f6a7c7e58d01fa4684078cf50"
    },
    {
      "path": "robots.txt",
      "mode": "100644",
      "type": "blob",
      "sha": "8ca70253a4bb677cb797a7b409df4c4a9c0baa67",
      "size": 948,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/8ca70253a4bb677cb797a7b409df4c4a9c0baa67"
    },
    {
      "path": "scripts",
      "mode": "040000",
      "type": "tree",
      "sha": "f6a251faaaa14ba4fcf702cd0556675e70cc80f3",
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/f6a251faaaa14ba4fcf702cd0556675e70cc80f3"
    },
    {
      "path": "suggestions.txt",
      "mode": "100644",
      "type": "blob",
      "sha": "5e5d11a62a00d3f1aea8f3825c8ec89860d31ad0",
      "size": 285,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/5e5d11a62a00d3f1aea8f3825c8ec89860d31ad0"
    },
    {
      "path": "templates",
      "mode": "040000",
      "type": "tree",
      "sha": "5b6dde8b8b616ba078305584e23e55ad0c5b2299",
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/5b6dde8b8b616ba078305584e23e55ad0c5b2299"
    },
    {
      "path": "update.md",
      "mode": "100644",
      "type": "blob",
      "sha": "734cb67218ac7ad952ffe2f816e4820427efe809",
      "size": 45743,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/734cb67218ac7ad952ffe2f816e4820427efe809"
    },
    {
      "path": "yarn.lock",
      "mode": "100644",
      "type": "blob",
      "sha": "9fed208fbed286860cb606c9904eb3bab2b3d960",
      "size": 193867,
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/blobs/9fed208fbed286860cb606c9904eb3bab2b3d960"
    },
    {
      "path": "zds",
      "mode": "040000",
      "type": "tree",
      "sha": "45b76aa70ad46e116c491a55def4b396b4ecba89",
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/45b76aa70ad46e116c491a55def4b396b4ecba89"
    },
    {
      "path": "zmd",
      "mode": "040000",
      "type": "tree",
      "sha": "89289051d5d1e37ecc12629737d4fc01dd0df06e",
      "url": "https://api.github.com/repos/zestedesavoir/zds-site/git/trees/89289051d5d1e37ecc12629737d4fc01dd0df06e"
    }
  ],
  "truncated": false
}

我制作了一个Perl脚本版本来检查我的代码并理解这个问题。

Perl:

(在线演示: https://repl.it/repls/VainPrizeDebugmonitor)

文件:

output_a1

100644 arborescence-back.rst 05392dacd107b9e2bb931c85632e115ae69c22cb
100644 featured.rst 20084355452644d3a171b54e9331485e73a897ea
100644 forum.rst 82efe44d491fbc69fb99b0fc0829ad349a11aae7
100644 gallery.rst e075f6d1fe182e595b950cc50d1c5701c6c48bb1
100644 member.rst 157a97545f397f02293a95034989f293cda00ee8
100644 pages.rst 30d85eb8babc8608a87272eb02a73685a71623c3
100644 private-message.rst 6e4872283841ddb0edf03f7535003b4cb5e2f3ce
100644 searchv2.rst a31835f3f39b77408b75548c215d06dcd776d3c2
100644 tutorialv2.rst e646fef1203c7c9b8137c6420d990fd40c1255ae
100644 utils.rst 846765fc32bafc05bb58e6b70883acf5de8ae97b

output_a2

100644 .coveragerc 449170d0faeb75182310345564fd1811c0b9fd73
100644 .editorconfig 75884936ea2d35b531af886acad747d4fd9b2a9e
100644 .flake8 69e872e30d30f5c7de3276d289d6aee81ccf4af7
40000 .github 56b49acad224fdb70fca11809f3e5a4d396cb01c
100644 .gitignore 4832b44b973574253cf1b59ba7a66cfc227cd699
100644 .jshintrc 939efa02939437adece1e3a076d597b2557e36b5
100644 .travis.yml 6b5e4f43790874e2cf9db23e964f72b99deeb0d1
100644 AUTHORS 0b92b7759ce2dd0a7cacf79b273368bb71ac5397
100644 CODE_OF_CONDUCT.md ae61c31efae6cea565e447467e4377da76125679
100644 CONTRIBUTING.md ac71ad378faf7fb7ae927b20d4d28a57c6085bf9
100644 COPYING 94a9ed024d3859793618152ea559a168bbcbb5e2
100644 Gulpfile.js 5dd951ae61f0913605197fafa018f7db49549a68
100644 LICENSE 8a171a155d85927b678068becd046194aea777a9
100644 Makefile cc722c2bc71dfbaa1b025c8c56245ed0fcd61739
100644 README.md a6a9013159a3766da62443c4be5e267435469fd9
40000 assets 1846a32450eb2a7605acb55cab8206028cfb656f
40000 doc f55b804a2b694db577b20c8e9851ad783fea8ee5
40000 errors b37a18162be2bdae7382fc194f1bf2d0ab89bba3
40000 export-assets 3a8b85efa969c389ac3c5e7e6ad62206dbddcaca
40000 fixtures 89cacb4de6feb81a962b9a992b9434cb44d3b0aa
40000 geodata 635d29035ae7528231edb9b74eb09887c22dda2a
100755 manage.py 458f6e2df8b431b9fa819c89e82cebf2e0a91260
100644 package.json 02d231aa0c0fa299581be07bcece0393dc9a9e47
100644 quotes.txt e8e84a048d70bc57c1f725fc12f2101a40c5dcbb
100644 requirements-dev.txt 7297a894036fcf70a7209062bb51f45db1b71d39
100644 requirements-prod.txt 2f957115bcf3794fdecf3c4848f21ae8f428c31b
100644 requirements.txt 805fefa566ef0d8f6a7c7e58d01fa4684078cf50
100644 robots.txt 8ca70253a4bb677cb797a7b409df4c4a9c0baa67
40000 scripts f6a251faaaa14ba4fcf702cd0556675e70cc80f3
100644 suggestions.txt 5e5d11a62a00d3f1aea8f3825c8ec89860d31ad0
40000 templates 5b6dde8b8b616ba078305584e23e55ad0c5b2299
100644 update.md 734cb67218ac7ad952ffe2f816e4820427efe809
100644 yarn.lock 9fed208fbed286860cb606c9904eb3bab2b3d960
40000 zds 45b76aa70ad46e116c491a55def4b396b4ecba89
40000 zmd 89289051d5d1e37ecc12629737d4fc01dd0df06e

output_a3

100644 Makefile fd4542fcb89018c3f97901b26992577590db1fe1
100644 make.bat f17fd5b680fc6dafdba3d1adda49389de4ae0b25
40000 source 7425440b50da313c10be22342f8a0f575ca64196

output_a4

40000 includes 52fe1c1c43130c011e78fc7d488ee5cd2d39fc61
100644 opensearch.xml be2e32c0f7c32a22da4c428438ae6f79965ea4ca
100644 search.html 5618f244fee4945eb799022f7e109ec8cbb2c696

Perl脚本:

XX="$(perl -sane '$F[2] =~ s/(..)/\\x$1/g ; print $F[0]." ".$F[1]."\\"."x00".$F[2]' output_a1)"
SIZE=$(echo -en "$XX" | wc -c)

echo "A1:"
echo "original: 8d66139b3acf78fa50e16383693a161c33b5e048"
echo "output :" $(echo -en "tree $SIZE\x00$XX" | sha1sum)

# ...

输出:

A1:
original: 8d66139b3acf78fa50e16383693a161c33b5e048
output  : 8d66139b3acf78fa50e16383693a161c33b5e048
A2:
original: 4ef57de8e81c8415d6da2b267872e602b1f28cfe
output  : c5c701b8114582e3bb2e353aac157a7febfcd33b
A3:
original: 13b54c0bab5e7f7a05398d6d92e65eee2b227136
output  : 13b54c0bab5e7f7a05398d6d92e65eee2b227136
A4:
original: 218a8f506fcd3076fad059ec42d4656c635a8171
output  : 218a8f506fcd3076fad059ec42d4656c635a8171

然后我们发现我的JS和Perl脚本返回的是相同的内容。这意味着我的模式有问题,但我不知道为什么。


3
https://github.com/chris3torek/scripts/blob/master/githash.py 包含计算Git哈希值的Python代码。请仔细阅读! - torek
嗯...我不理解“离题因为...必须在问题本身中包含所需的行为,以便在其中重现。没有清晰的问题陈述对其他读者没有用处。”这个标志是什么意思?我编写了一个Perl脚本来展示我的问题不在哈希函数中。我使用GitHub API而不是文件系统来使我的代码可重现... - user2226755
只是一种猜测,因为对象通常是无序的,并且您会遍历Object.values(json.tree)。也许您的哈希不正确,因为它需要是有序列表。也许,只是也许,您的数组顺序不正确。 - Moritz Roessler
json.tree.sort((a, b) => a.path.charCodeAt(0) - b.path.charCodeAt(0)); 这行代码可以让文件的排序和在 github.com 上仓库中的顺序保持一致。:/ - user2226755
排序方法 json.tree.sort((a, b) => a.path.charCodeAt(0) - b.path.charCodeAt(0)); 有缺陷 - 它仅基于路径的第一个字符进行排序,而不是完全按字典顺序。结果是具有相同路径第一个字符的条目可能会被随机打乱。 - Leon
我禁用了这行代码,因为我认为API已经排序好了。如果我尝试进行排序,A3A4的哈希值不同。 - user2226755
1个回答

13
您的代码存在问题,但修复该问题无法消除A2案例中的差异。
您的代码问题
计算树哈希的官方git算法会从模式字段中删除前导零。在您的示例中,该字段包含值100644040000,而后者被git记录为40000
证明:
$ git cat-file tree 4ef57de8e81c8415d6da2b267872e602b1f28cfe|hexdump -C
00000000  31 30 30 36 34 34 20 2e  63 6f 76 65 72 61 67 65  |100644 .coverage|
00000010  72 63 00 44 91 70 d0 fa  eb 75 18 23 10 34 55 64  |rc.D.p...u.#.4Ud|
00000020  fd 18 11 c0 b9 fd 73 31  30 30 36 34 34 20 2e 65  |......s100644 .e|
00000030  64 69 74 6f 72 63 6f 6e  66 69 67 00 75 88 49 36  |ditorconfig.u.I6|
00000040  ea 2d 35 b5 31 af 88 6a  ca d7 47 d4 fd 9b 2a 9e  |.-5.1..j..G...*.|
00000050  31 30 30 36 34 34 20 2e  66 6c 61 6b 65 38 00 69  |100644 .flake8.i|
00000060  e8 72 e3 0d 30 f5 c7 de  32 76 d2 89 d6 ae e8 1c  |.r..0...2v......|
00000070  cf 4a f7 34 30 30 30 30  20 2e 67 69 74 68 75 62  |.J.40000 .github|
...                                                             ^^^^^
...                                                             !!!!!

然而,将删除前导零1的代码添加到你的perl脚本中仍然无法解决A2情况(尽管计算出来的哈希值发生了变化,但仍与预期的不同):

$ cat main.sh
XX="$(perl -sane '$F[2] =~ s/(..)/\\x$1/g ; $F[0] =~ s/^0+//g ; print $F[0]." ".$F[1]."\\"."x00".$F[2]' output_a1)"
SIZE=$(echo -en "$XX" | wc -c)

echo "original: 8d66139b3acf78fa50e16383693a161c33b5e048 output:"
echo -en "tree $SIZE\x00$XX" | sha1sum

XX="$(perl -sane '$F[2] =~ s/(..)/\\x$1/g ; $F[0] =~ s/^0+//g ; print $F[0]." ".$F[1]."\\"."x00".$F[2]' output_a2)"
SIZE=$(echo -en "$XX" | wc -c)

echo "original: 4ef57de8e81c8415d6da2b267872e602b1f28cfe output:"
echo -en "tree $SIZE\x00$XX" | sha1sum

$ ./main.sh 
original: 8d66139b3acf78fa50e16383693a161c33b5e048 output:
8d66139b3acf78fa50e16383693a161c33b5e048  -
original: 4ef57de8e81c8415d6da2b267872e602b1f28cfe output:
c5c701b8114582e3bb2e353aac157a7febfcd33b  -

GitHub API存在的问题

问题在于A2哈希 4ef57de8e81c8415d6da2b267872e602b1f28cfe 指向的是一个提交对象,而不是一棵树。这个提交对象又引用了哈希值为c5c701b8114582e3bb2e353aac157a7febfcd33b的树形结构,这也正是修复代码所计算出来的值:

$ git cat-file -t 4ef57de8e81c8415d6da2b267872e602b1f28cfe
commit

$ git cat-file -p 4ef57de8e81c8415d6da2b267872e602b1f28cfe
tree c5c701b8114582e3bb2e353aac157a7febfcd33b
parent 502a88b41161ec7dbff0862e3d805db397caf366
...

如果你在A2查询中使用了树而不是提交哈希值(请试试这个),你就不会有任何问题了。 GitHub API的一个争议问题是,它会默默地将提交哈希值解析为底层树,而不是返回错误或在响应中包含发生了什么的指示(例如,通过将sha字段设置为树的哈希值而不是查询值)。
1 快速且简单的修复方法在一种情况下无法正确工作,即模式字段只由零组成的情况。在这种情况下,模式字段将被完全删除,而不是被一个零替换。然而,在实践中,这种情况不可能发生,因为具有这样的模式值的对象将简单地无法访问git。

谢谢!我编辑了我的回答。“GitHub API是静默的”这是不可能做到我想要的吗? - user2226755
@HorsSujet 在你更新的 output_a2 中,.flake8COPYING 这两个条目的位置是错误的。将它们移动到正确的位置会得到预期的树哈希值 c5c701b8114582e3bb2e353aac157a7febfcd33b - Leon
@HorsSujet 关于你的问题“我想做的这件事情不可能吗?” - 反问一下:你为什么会在那种情况下运行(获取一个提交哈希值,然后将其视为树哈希值)?通过避免这种情况或正确处理它(通过自己解析提交哈希值以获得树哈希值),可以消除问题。 - Leon
我想比较本地版本和Github版本,这就是为什么我想要这样做。我想我只会比较文件哈希而不是树哈希。或者我会用另一种方式来做(使用git命令或版本号)。 - user2226755
我没有忘记^^ - user2226755
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接