Reputation: 4545
In git I would like to "mark" certain commits. For instance I would like to "mark" commits which break the software's REST API, so that I can remember to bump the major version no. (I use semantic versioning).
Ideally I should be able issue a git command to see if any commits since last release/tag contain a "mark", because then I know that the next version no. should bump the major no.
The "mark" is not a tag (in git terms), since tags are unique. I anticipate, that there could be several identical "marks" since last release, to signal that the API is broken.
The current workaround is to write "MAJOR:" or "MINOR:" in commit messages.
Are there any suggestions on how I can use git for this?
Upvotes: 0
Views: 492
Reputation: 487755
It's true that tag names must be unique—but there are an infinite number1 of unique tag names beginning with mark/
, such as mark/1
, mark/2
, and so on. Or, you can use reference names that are not in refs/tags/
; or you could use Git's "notes", although it's easier to detect whether a tag or other reference is an ancestor of one commit and a descendant of another:
highmark=$(git for-each-ref --format='%(refname)' refs/marks | wc -l)
nextmark=$((highmark + 1)
git update-ref refs/marks/m$nextmark HEAD
(this assumes you never delete, with git update-ref -d
, any of these marks—if you do the "high mark" computation must find the highest existing number instead of simply counting). To test if mark $N is "between" tag T1 and HEAD:
if git merge-base --is-ancestor T1 refs/marks/m$N &&
git merge-base --is-ancestor refs/marks/m$N HEAD; then
... mark N is at or beyond tag T1 and at or before HEAD ...
else
... mark N is not between those two points (inclusive) ...
fi
Alternatively, you might store, in or outside the repository, and if inside the repository, in a plain blob—a blob is Git's internal format for raw file data—a file that simply contains the hash IDs of all "marked" commits. The file itself can be stored in a tagged or otherwise-referenced commit that may, but need not be, on any branch; or you can tag the blob itself. For instance:
git show marks > /tmp/all-marks # extract existing marks
git rev-parse HEAD >> /tmp/all-marks # add a new mark
git tag -f marks $(git hash-object -w --stdin < /tmp/all-marks)
If you store the blob under a commit, you can keep a history of marks by making new commits for each new updated "marked IDs" file. This is in some ways similar to the way git notes
work, but instead of writing files whose names are the IDs of commits, you are simply writing a file named "marks" (stored via a tree that is then pointed-to by the commit, that the mark reference—whether it's a tag like refs/tags/marks
, as in the tag example above, or a reference like refs/marks
, like the m
series references above but only using one reference). Since each commit has a parent pointer, you can save the previous commit, which saves the previous tree, which saves the previous blob/marks-file, and you can even run git log
on these commits, to see who updated the marks, when, etc.
1Well, finite, but limited only by disk space and name patterns. The pattern proposed here, counting decimally within file names in a single name-space, can only count to 10254 on typical Unix-ish file systems, with their 255 byte component-name-length limit. Practically speaking, you'd probably not want to go much past a thousand or so before making the names hierarchical, e.g., refs/marks/123/456/789
once you are into a few million marked commits.
OSes also impose maximum path lengths, but you would run out of commit IDs long before you hit those: 2160 is only 1 461 501 637 330 902 918 203 684 832 716 283 019 655 932 542 976, or about 1.462 sexdecillion in the short scale nomenclature. Worse, your chance of a hash collision gets too high after a few quintillion objects anyway, so we need only count to perhaps 1018.
Upvotes: 1