What is the format of a git tag object and how to calculate its SHA?

前端 未结 4 834
小蘑菇
小蘑菇 2020-12-11 10:45

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

相关标签:
4条回答
  • 2020-12-11 10:53

    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.

    0 讨论(0)
  • 2020-12-11 10:57

    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 ".

    0 讨论(0)
  • 2020-12-11 11:00

    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.

    0 讨论(0)
  • 2020-12-11 11:05

    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)?

    Take a look at libgit2 and its various bindings.

    0 讨论(0)
提交回复
热议问题