I am familiar with how Git creates SHA1 hashes for files (blobs), but not how they are created for tag objects. I assume they are, if I create an annotated tag, but what is the recipe? And how might I replicate it outside of Git (e.g., in Perl or Python)?
The content of a tag object is as follows:
object <commit-sha1>
type commit
tag <tag-name>
tagger <author-with-timestamp>
<tag-message>
Based on that text the SHA1 value is calculated.
how might I replicate it outside of Git (e.g., in Perl or Python)?
Reverse engineer the format from a minimal example
First we determine what the format for tags is:
git tag -as -m abc mytag
cat .git/refs/tags/mytag
outputs the tag sha:
c1d7720e99f9dd1d1c8aee625fd6ce09b3a81fef
so we do as explained at How to DEFLATE with a command line tool to extract a git object? :
python -c "import zlib,sys;sys.stdout.write(zlib.decompress(sys.stdin.read()))" \
<.git/objects/c1/d7720e99f9dd1d1c8aee625fd6ce09b3a81fef | hd
which gives:
00000000 74 61 67 20 37 39 38 00 6f 62 6a 65 63 74 20 61 |tag 798.object a|
00000010 30 32 63 35 30 32 39 65 30 38 66 37 37 65 61 65 |02c5029e08f77eae|
00000020 35 37 64 62 63 38 31 38 38 61 37 31 31 62 63 39 |57dbc8188a711bc9|
00000030 65 39 62 32 39 30 61 0a 74 79 70 65 20 63 6f 6d |e9b290a.type com|
00000040 6d 69 74 0a 74 61 67 20 6d 79 74 61 67 0a 74 61 |mit.tag mytag.ta|
00000050 67 67 65 72 20 43 69 72 6f 20 53 61 6e 74 69 6c |gger Ciro Santil|
00000060 6c 69 20 3c 63 69 72 6f 2e 73 61 6e 74 69 6c 6c |li <ciro.santill|
00000070 69 40 67 6d 61 69 6c 2e 63 6f 6d 3e 20 31 35 33 |i@blebl.com> 153|
00000080 36 31 37 36 39 30 36 20 2b 30 31 30 30 0a 0a 61 |6176906 +0100..a|
00000090 62 63 0a 2d 2d 2d 2d 2d 42 45 47 49 4e 20 50 47 |bc.-----BEGIN PG|
000000a0 50 20 53 49 47 4e 41 54 55 52 45 2d 2d 2d 2d 2d |P SIGNATURE-----|
000000b0 0a 0a 69 51 47 7a 42 41 41 42 43 67 41 64 46 69 |..iQGzBAABCgAdFi|
000000c0 45 45 50 6b 64 79 57 72 30 33 4f 6d 39 64 4d 41 |EEPkdyWr03Om9dMA|
000000d0 61 47 51 32 7a 61 2f 4d 2b 77 30 77 30 46 41 6c |aGQ2za/M+w0w0FAl|
000000e0 75 51 4d 77 6f 41 43 67 6b 51 51 32 7a 61 2f 4d |uQMwoACgkQQ2za/M|
000000f0 2b 77 0a 30 77 33 77 69 67 76 38 43 6c 31 35 43 |+w.0w3wigv8Cl15C|
00000100 78 4f 6e 71 2f 6c 49 2b 33 4b 47 5a 6e 47 45 66 |xOnq/lI+3KGZnGEf|
00000110 56 47 4b 71 43 46 7a 69 39 4f 66 63 51 48 4d 49 |VGKqCFzi9OfcQHMI|
00000120 77 59 39 6f 78 44 2f 35 68 30 56 37 7a 6b 4a 70 |wY9oxD/5h0V7zkJp|
00000130 78 2f 5a 0a 79 72 52 6d 37 62 41 2f 2f 2b 5a 37 |x/Z.yrRm7bA//+Z7|
00000140 54 59 6c 73 2f 36 54 44 6c 56 53 2f 44 69 72 79 |TYls/6TDlVS/Diry|
00000150 53 39 4d 38 7a 59 45 48 76 44 65 65 71 32 2f 78 |S9M8zYEHvDeeq2/x|
00000160 43 31 71 53 37 47 4e 59 5a 7a 30 36 50 76 2b 79 |C1qS7GNYZz06Pv+y|
00000170 4a 43 54 77 0a 6c 68 32 41 61 6d 7a 33 75 48 55 |JCTw.lh2Aamz3uHU|
00000180 64 6e 4f 37 51 79 70 6f 63 4f 54 6f 5a 4e 53 4a |dnO7QypocOToZNSJ|
00000190 72 44 2b 2b 48 55 6e 36 77 70 34 54 6f 55 41 35 |rD++HUn6wp4ToUA5|
000001a0 73 37 34 63 46 79 52 58 49 2f 30 49 32 65 59 67 |s74cFyRXI/0I2eYg|
000001b0 44 2b 6b 49 7a 0a 4e 57 64 2b 45 4a 5a 61 52 74 |D+kIz.NWd+EJZaRt|
000001c0 63 55 75 4a 49 55 65 79 75 7a 68 31 64 49 77 6b |cUuJIUeyuzh1dIwk|
000001d0 73 56 32 52 6e 42 31 37 64 5a 2f 4e 47 57 39 37 |sV2RnB17dZ/NGW97|
000001e0 37 4f 30 69 30 6f 6a 6f 50 6e 74 4e 6e 48 6f 61 |7O0i0ojoPntNnHoa|
000001f0 68 5a 2b 44 6e 4e 0a 71 78 41 37 36 4d 74 6d 43 |hZ+DnN.qxA76MtmC|
00000200 71 41 66 45 6d 68 2b 6b 49 55 74 61 42 44 61 5a |qAfEmh+kIUtaBDaZ|
00000210 51 36 32 45 66 55 65 76 6c 34 78 6b 72 38 79 4b |Q62EfUevl4xkr8yK|
00000220 4a 46 6d 53 69 4d 39 76 4c 34 73 7a 4a 75 69 61 |JFmSiM9vL4szJuia|
00000230 4b 56 58 43 71 2b 71 0a 71 33 6d 68 41 41 7a 73 |KVXCq+q.q3mhAAzs|
00000240 70 39 63 6d 32 2b 55 6d 47 7a 70 6b 37 52 51 6f |p9cm2+UmGzpk7RQo|
00000250 4d 36 50 44 45 73 61 37 43 68 77 52 47 71 53 42 |M6PDEsa7ChwRGqSB|
00000260 78 34 46 48 2f 32 7a 4d 75 49 49 4e 4c 72 72 72 |x4FH/2zMuIINLrrr|
00000270 36 46 64 59 2b 4c 36 71 0a 34 4d 78 67 66 46 38 |6FdY+L6q.4MxgfF8|
00000280 61 6e 47 31 38 42 43 56 65 6d 47 44 65 6d 69 34 |anG18BCVemGDemi4|
00000290 42 71 58 53 4d 73 61 77 35 45 70 77 36 4f 78 43 |BqXSMsaw5Epw6OxC|
000002a0 6c 34 2f 65 33 74 43 48 4b 39 58 78 63 6d 7a 4d |l4/e3tCHK9XxcmzM|
000002b0 70 62 6a 37 66 77 42 7a 7a 0a 41 76 63 6e 34 48 |pbj7fwBzz.Avcn4H|
000002c0 41 67 52 75 6b 77 7a 54 53 4f 53 59 30 6e 73 74 |AgRukwzTSOSY0nst|
000002d0 67 6b 79 6c 54 4b 69 4d 48 6d 42 4c 4f 2b 49 6b |gkylTKiMHmBLO+Ik|
000002e0 58 63 4e 47 66 51 6b 46 51 41 67 49 59 67 4d 57 |XcNGfQkFQAgIYgMW|
000002f0 4e 4f 45 2f 68 59 76 73 2b 71 0a 46 51 4d 34 6e |NOE/hYvs+q.FQM4n|
00000300 6a 45 63 0a 3d 32 50 51 32 0a 2d 2d 2d 2d 2d 45 |jEc.=2PQ2.-----E|
00000310 4e 44 20 50 47 50 20 53 49 47 4e 41 54 55 52 45 |ND PGP SIGNATURE|
00000320 2d 2d 2d 2d 2d 0a |-----.|
00000327
from which we deduce the format is:
tag ${size}\0object ${sha_of_commit_it-points-to}
type ${type_of_object_it_points_to}
tag ${name_of_tag}
tagger ${username_and_email} ${seconds_since_utc} ${timezone}
${commit_message_including_gpg}
From the hd
we see that the full output is 0x326 == 806 bytes long which minus eight bytes from the prefix: tag 798.
makes the size 798
.
Analogous analysis for Git commit objects: What is the file format of a git commit object?
Minimal Python script that creates a tag object and gets its SHA
To ensure that we understood it correctly, here is a Python script that generates a working git repo from scratch, including a tag:
- the key function: https://github.com/cirosantilli/test-git-web-interface/blob/8770bcb84eeac2b3cc17aea6775e6c45c396cb54/other-test-repos/util.py#L94
- usage example: https://github.com/cirosantilli/test-git-web-interface/blob/8770bcb84eeac2b3cc17aea6775e6c45c396cb54/other-test-repos/tag-test.py
You can then cd
into it and verify that all works normally with git
commands.
Tested on git 2.16.1, Ubuntu 18.04.
It's pretty much the same, although the smallish header prepended to the commit object is different. You can use git cat-file
to see the actual format.
The pattern is basically:
sha1("tag " + datasize + "\0" + data)
Where data
is the output of git cat-file
. One can produce this by piping that output to git-hash-object
like so:
git cat-file tag v0.30 | git hash-object -t tag --stdin
And the equivalent a perl one-liner is:
git cat-file tag v0.30 | perl -MDigest::SHA1 -E '$/=undef;$_=<>;say Digest::SHA1->new->add("tag ".length()."\0".$_)->hex digest'
It seems that one can do this same thing with any of the types objects simply by replacing "tag "
with the proper object name: "blob "
, "tree "
, or "commit "
.
来源:https://stackoverflow.com/questions/10986615/what-is-the-format-of-a-git-tag-object-and-how-to-calculate-its-sha