Make Tag class only for writing

The Tag class now only supports the creation of an annotated tag
object.  To read an annotated tag, applictions should use RevTag.
This permits us to have exactly one implementation, and RevTag's
is faster and more bug-free.

Change-Id: Ib573f7e15f36855112815269385c21dea532e2cf
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
This commit is contained in:
Shawn O. Pearce 2010-08-20 15:18:25 -07:00
parent b46b635c03
commit 707912b35d
11 changed files with 201 additions and 354 deletions

View File

@ -397,9 +397,8 @@ public CommitBuilder commit() {
* @throws Exception
*/
public RevTag tag(final String name, final RevObject dst) throws Exception {
final Tag t = new Tag(db);
t.setType(Constants.typeString(dst.getType()));
t.setObjId(dst.toObjectId());
final Tag t = new Tag();
t.setObjectId(dst);
t.setTag(name);
t.setTagger(new PersonIdent(committer, new Date(now)));
t.setMessage("");

View File

@ -44,6 +44,7 @@ expectedNumberOfbytes=Expected {0} bytes.
exporting=Exporting {0}
failedToCommitIndex=failed to commit index
failedToLockIndex=failed to lock index
failedToLockTag=Failed to lock tag {0}: {1}
fatalError=fatal: {0}
fatalErrorTagExists=fatal: tag '{0}' exists
fatalThisProgramWillDestroyTheRepository=fatal: This program will destroy the repository\nfatal:\nfatal:\nfatal: {0}\nfatal:\nfatal: To continue, add {1} to the command line\nfatal:

View File

@ -97,6 +97,7 @@ public static CLIText get() {
/***/ public String exporting;
/***/ public String failedToCommitIndex;
/***/ public String failedToLockIndex;
/***/ public String failedToLockTag;
/***/ public String fatalError;
/***/ public String fatalErrorTagExists;
/***/ public String fatalThisProgramWillDestroyTheRepository;

View File

@ -51,8 +51,10 @@
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.RefUpdate;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
@ -80,19 +82,45 @@ protected void run() throws Exception {
if (!tagName.startsWith(Constants.R_TAGS))
tagName = Constants.R_TAGS + tagName;
String shortName = tagName.substring(Constants.R_TAGS.length());
if (!force && db.resolve(tagName) != null) {
throw die(MessageFormat.format(CLIText.get().fatalErrorTagExists
, tagName.substring(Constants.R_TAGS.length())));
, shortName));
}
final ObjectLoader ldr = db.open(object);
final ObjectInserter inserter = db.newObjectInserter();
final ObjectId id;
try {
org.eclipse.jgit.lib.Tag tag = new org.eclipse.jgit.lib.Tag();
tag.setObjectId(object, ldr.getType());
tag.setTagger(new PersonIdent(db));
tag.setMessage(message.replaceAll("\r", ""));
tag.setTag(shortName);
id = inserter.insert(Constants.OBJ_TAG, inserter.format(tag));
inserter.flush();
} finally {
inserter.release();
}
org.eclipse.jgit.lib.Tag tag = new org.eclipse.jgit.lib.Tag(db);
tag.setObjId(object);
tag.setType(Constants.typeString(ldr.getType()));
tag.setTagger(new PersonIdent(db));
tag.setMessage(message.replaceAll("\r", ""));
tag.setTag(tagName.substring(Constants.R_TAGS.length()));
tag.tag();
RefUpdate ru = db.updateRef(tagName);
ru.setForceUpdate(force);
ru.setNewObjectId(id);
ru.setRefLogMessage("tagged " + shortName, false);
switch (ru.update()) {
case NEW:
case FAST_FORWARD:
case FORCED:
break;
case REJECTED:
throw die(MessageFormat.format(CLIText.get().fatalErrorTagExists,
shortName));
default:
throw die(MessageFormat.format(CLIText.get().failedToLockTag,
shortName, ru.getResult()));
}
}
}

View File

@ -77,6 +77,7 @@
import org.eclipse.jgit.lib.TreeEntry;
import org.eclipse.jgit.lib.WriteTree;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevTag;
import org.eclipse.jgit.revwalk.RevWalk;
public class T0003_Basic extends SampleDataRepositoryTestCase {
@ -439,33 +440,19 @@ public void test012_SubtreeExternalSorting() throws IOException {
public void test020_createBlobTag() throws IOException {
final ObjectId emptyId = new ObjectWriter(db).writeBlob(new byte[0]);
final Tag t = new Tag(db);
t.setObjId(emptyId);
t.setType("blob");
final Tag t = new Tag();
t.setObjectId(emptyId, Constants.OBJ_BLOB);
t.setTag("test020");
t.setTagger(new PersonIdent(author, 1154236443000L, -4 * 60));
t.setMessage("test020 tagged\n");
t.tag();
insertTag(t);
assertEquals("6759556b09fbb4fd8ae5e315134481cc25d46954", t.getTagId().name());
Tag mapTag = db.mapTag("test020");
assertEquals("blob", mapTag.getType());
assertEquals("test020 tagged\n", mapTag.getMessage());
assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag.getTagger());
assertEquals("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", mapTag.getObjId().name());
}
public void test020b_createBlobPlainTag() throws IOException {
test020_createBlobTag();
Tag t = new Tag(db);
t.setTag("test020b");
t.setObjId(ObjectId.fromString("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"));
t.tag();
Tag mapTag = db.mapTag("test020b");
assertEquals("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", mapTag.getObjId().name());
// We do not repeat the plain tag test for other object types
RevTag mapTag = parseTag(t.getTagId());
assertEquals(Constants.OBJ_BLOB, mapTag.getObject().getType());
assertEquals("test020 tagged\n", mapTag.getFullMessage());
assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag.getTaggerIdent());
assertEquals("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", mapTag.getObject().getId().name());
}
public void test021_createTreeTag() throws IOException {
@ -473,20 +460,19 @@ public void test021_createTreeTag() throws IOException {
final Tree almostEmptyTree = new Tree(db);
almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, "empty".getBytes(), false));
final ObjectId almostEmptyTreeId = new ObjectWriter(db).writeTree(almostEmptyTree);
final Tag t = new Tag(db);
t.setObjId(almostEmptyTreeId);
t.setType("tree");
final Tag t = new Tag();
t.setObjectId(almostEmptyTreeId, Constants.OBJ_TREE);
t.setTag("test021");
t.setTagger(new PersonIdent(author, 1154236443000L, -4 * 60));
t.setMessage("test021 tagged\n");
t.tag();
insertTag(t);
assertEquals("b0517bc8dbe2096b419d42424cd7030733f4abe5", t.getTagId().name());
Tag mapTag = db.mapTag("test021");
assertEquals("tree", mapTag.getType());
assertEquals("test021 tagged\n", mapTag.getMessage());
assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag.getTagger());
assertEquals("417c01c8795a35b8e835113a85a5c0c1c77f67fb", mapTag.getObjId().name());
RevTag mapTag = parseTag(t.getTagId());
assertEquals(Constants.OBJ_TREE, mapTag.getObject().getType());
assertEquals("test021 tagged\n", mapTag.getFullMessage());
assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag.getTaggerIdent());
assertEquals("417c01c8795a35b8e835113a85a5c0c1c77f67fb", mapTag.getObject().getId().name());
}
public void test022_createCommitTag() throws IOException {
@ -500,20 +486,19 @@ public void test022_createCommitTag() throws IOException {
almostEmptyCommit.setMessage("test022\n");
almostEmptyCommit.setTreeId(almostEmptyTreeId);
ObjectId almostEmptyCommitId = insertCommit(almostEmptyCommit);
final Tag t = new Tag(db);
t.setObjId(almostEmptyCommitId);
t.setType("commit");
final Tag t = new Tag();
t.setObjectId(almostEmptyCommitId,Constants.OBJ_COMMIT);
t.setTag("test022");
t.setTagger(new PersonIdent(author, 1154236443000L, -4 * 60));
t.setMessage("test022 tagged\n");
t.tag();
insertTag(t);
assertEquals("0ce2ebdb36076ef0b38adbe077a07d43b43e3807", t.getTagId().name());
Tag mapTag = db.mapTag("test022");
assertEquals("commit", mapTag.getType());
assertEquals("test022 tagged\n", mapTag.getMessage());
assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag.getTagger());
assertEquals("b5d3b45a96b340441f5abb9080411705c51cc86c", mapTag.getObjId().name());
RevTag mapTag = parseTag(t.getTagId());
assertEquals(Constants.OBJ_COMMIT, mapTag.getObject().getType());
assertEquals("test022 tagged\n", mapTag.getFullMessage());
assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag.getTaggerIdent());
assertEquals("b5d3b45a96b340441f5abb9080411705c51cc86c", mapTag.getObject().getId().name());
}
public void test023_createCommitNonAnullii() throws IOException {
@ -549,51 +534,6 @@ public void test024_createCommitNonAscii() throws IOException {
assertEquals("2979b39d385014b33287054b87f77bcb3ecb5ebf", cid.name());
}
public void test025_packedRefs() throws IOException {
test020_createBlobTag();
test021_createTreeTag();
test022_createCommitTag();
if (!new File(db.getDirectory(),"refs/tags/test020").delete()) throw new Error("Cannot delete unpacked tag");
if (!new File(db.getDirectory(),"refs/tags/test021").delete()) throw new Error("Cannot delete unpacked tag");
if (!new File(db.getDirectory(),"refs/tags/test022").delete()) throw new Error("Cannot delete unpacked tag");
// We cannot resolve it now, since we have no ref
Tag mapTag20missing = db.mapTag("test020");
assertNull(mapTag20missing);
// Construct packed refs file
PrintWriter w = new PrintWriter(new FileWriter(new File(db.getDirectory(), "packed-refs")));
w.println("# packed-refs with: peeled");
w.println("6759556b09fbb4fd8ae5e315134481cc25d46954 refs/tags/test020");
w.println("^e69de29bb2d1d6434b8b29ae775ad8c2e48c5391");
w.println("b0517bc8dbe2096b419d42424cd7030733f4abe5 refs/tags/test021");
w.println("^417c01c8795a35b8e835113a85a5c0c1c77f67fb");
w.println("0ce2ebdb36076ef0b38adbe077a07d43b43e3807 refs/tags/test022");
w.println("^b5d3b45a96b340441f5abb9080411705c51cc86c");
w.close();
((RefDirectory)db.getRefDatabase()).rescan();
Tag mapTag20 = db.mapTag("test020");
assertNotNull("have tag test020", mapTag20);
assertEquals("blob", mapTag20.getType());
assertEquals("test020 tagged\n", mapTag20.getMessage());
assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag20.getTagger());
assertEquals("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", mapTag20.getObjId().name());
Tag mapTag21 = db.mapTag("test021");
assertEquals("tree", mapTag21.getType());
assertEquals("test021 tagged\n", mapTag21.getMessage());
assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag21.getTagger());
assertEquals("417c01c8795a35b8e835113a85a5c0c1c77f67fb", mapTag21.getObjId().name());
Tag mapTag22 = db.mapTag("test022");
assertEquals("commit", mapTag22.getType());
assertEquals("test022 tagged\n", mapTag22.getMessage());
assertEquals(new PersonIdent(author, 1154236443000L, -4 * 60), mapTag22.getTagger());
assertEquals("b5d3b45a96b340441f5abb9080411705c51cc86c", mapTag22.getObjId().name());
}
public void test025_computeSha1NoStore() throws IOException {
byte[] data = "test025 some data, more than 16 bytes to get good coverage"
.getBytes("ISO-8859-1");
@ -777,6 +717,29 @@ private RevCommit parseCommit(AnyObjectId id)
}
}
private ObjectId insertTag(final Tag tag) throws IOException,
UnsupportedEncodingException {
ObjectInserter oi = db.newObjectInserter();
try {
ObjectId id = oi.insert(Constants.OBJ_TAG, oi.format(tag));
oi.flush();
tag.setTagId(id);
return id;
} finally {
oi.release();
}
}
private RevTag parseTag(AnyObjectId id) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
RevWalk rw = new RevWalk(db);
try {
return rw.parseTag(id);
} finally {
rw.release();
}
}
/**
* Kick the timestamp of a local file.
* <p>

View File

@ -352,7 +352,6 @@ truncatedHunkLinesMissingForAncestor=Truncated hunk, at least {0} lines missing
truncatedHunkNewLinesMissing=Truncated hunk, at least {0} new lines is missing
truncatedHunkOldLinesMissing=Truncated hunk, at least {0} old lines is missing
unableToCheckConnectivity=Unable to check connectivity.
unableToLockTag=Unable to lock tag {0}
unableToStore=Unable to store {0}.
unableToWrite=Unable to write {0}
unencodeableFile=Unencodeable file: {0}

View File

@ -411,7 +411,6 @@ public static JGitText get() {
/***/ public String truncatedHunkNewLinesMissing;
/***/ public String truncatedHunkOldLinesMissing;
/***/ public String unableToCheckConnectivity;
/***/ public String unableToLockTag;
/***/ public String unableToStore;
/***/ public String unableToWrite;
/***/ public String unencodeableFile;

View File

@ -367,11 +367,11 @@ public final byte[] format(Tag tag) {
OutputStreamWriter w = new OutputStreamWriter(os, Constants.CHARSET);
try {
w.write("object ");
tag.getObjId().copyTo(w);
tag.getObjectId().copyTo(w);
w.write('\n');
w.write("type ");
w.write(tag.getType());
w.write(Constants.typeString(tag.getObjectType()));
w.write("\n");
w.write("tag ");

View File

@ -317,42 +317,6 @@ public Tree mapTree(final ObjectId id) throws IOException {
}
}
/**
* Access a tag by symbolic name.
*
* @param revstr
* @return a Tag or null
* @throws IOException on I/O error or unexpected type
* @deprecated Use {@link #resolve(String)} and feed its return value to
* {@link org.eclipse.jgit.revwalk.RevWalk#parseTag(AnyObjectId)}.
*/
@Deprecated
public Tag mapTag(String revstr) throws IOException {
final ObjectId id = resolve(revstr);
return id != null ? mapTag(revstr, id) : null;
}
/**
* Access a Tag by SHA'1 id
* @param refName
* @param id
* @return Commit or null
* @throws IOException for I/O error or unexpected object type.
* @deprecated Use {@link org.eclipse.jgit.revwalk.RevWalk#parseTag(AnyObjectId)}.
*/
@Deprecated
public Tag mapTag(final String refName, final ObjectId id) throws IOException {
final ObjectLoader or;
try {
or = open(id);
} catch (MissingObjectException notFound) {
return null;
}
if (or.getType() == Constants.OBJ_TAG)
return new Tag(this, id, refName, or.getCachedBytes());
return new Tag(this, id, refName, null);
}
/**
* Create a command to update, create or delete a ref in this repository.
*

View File

@ -45,224 +45,77 @@
package org.eclipse.jgit.lib;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import org.eclipse.jgit.JGitText;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.ObjectWritingException;
import org.eclipse.jgit.revwalk.RevObject;
/**
* Represents a named reference to another Git object of any type.
* Mutable builder to construct an annotated tag recording a project state.
*
* Applications should use this object when they need to manually construct a
* tag and want precise control over its fields.
*/
public class Tag {
private final Repository objdb;
private ObjectId tagId;
private ObjectId object;
private int type = Constants.OBJ_BAD;
private String tag;
private PersonIdent tagger;
private String message;
private byte[] raw;
private String type;
private String tag;
private ObjectId objId;
/**
* Construct a new, yet unnamed Tag.
*
* @param db
*/
public Tag(final Repository db) {
objdb = db;
}
/**
* Construct a Tag representing an existing with a known name referencing an known object.
* This could be either a simple or annotated tag.
*
* @param db {@link Repository}
* @param id target id.
* @param refName tag name or null
* @param raw data of an annotated tag.
*/
public Tag(final Repository db, final ObjectId id, String refName, final byte[] raw) {
objdb = db;
if (raw != null) {
tagId = id;
objId = ObjectId.fromString(raw, 7);
} else
objId = id;
if (refName != null && refName.startsWith("refs/tags/"))
refName = refName.substring(10);
tag = refName;
this.raw = raw;
}
/**
* @return comment of an annotated tag, or null
*/
public String getMessage() {
decode();
return message;
}
private void decode() {
// FIXME: handle I/O errors
if (raw != null) {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(
new ByteArrayInputStream(raw)));
String n = br.readLine();
if (n == null || !n.startsWith("object ")) {
throw new CorruptObjectException(tagId, JGitText.get().corruptObjectNoObject);
}
objId = ObjectId.fromString(n.substring(7));
n = br.readLine();
if (n == null || !n.startsWith("type ")) {
throw new CorruptObjectException(tagId, JGitText.get().corruptObjectNoType);
}
type = n.substring("type ".length());
n = br.readLine();
if (n == null || !n.startsWith("tag ")) {
throw new CorruptObjectException(tagId, JGitText.get().corruptObjectNoTagName);
}
tag = n.substring("tag ".length());
n = br.readLine();
// We should see a "tagger" header here, but some repos have tags
// without it.
if (n == null)
throw new CorruptObjectException(tagId, JGitText.get().corruptObjectNoTaggerHeader);
if (n.length()>0)
if (n.startsWith("tagger "))
tagger = new PersonIdent(n.substring("tagger ".length()));
else
throw new CorruptObjectException(tagId, JGitText.get().corruptObjectNoTaggerBadHeader);
// Message should start with an empty line, but
StringBuilder tempMessage = new StringBuilder();
char[] readBuf = new char[2048];
int readLen;
while ((readLen = br.read(readBuf)) > 0) {
tempMessage.append(readBuf, 0, readLen);
}
message = tempMessage.toString();
if (message.startsWith("\n"))
message = message.substring(1);
} catch (IOException e) {
e.printStackTrace();
} finally {
raw = null;
}
}
}
/**
* Set the message of an annotated tag
* @param m
*/
public void setMessage(final String m) {
message = m;
}
/**
* Store a tag.
* If author, message or type is set make the tag an annotated tag.
*
* @throws IOException
*/
public void tag() throws IOException {
if (getTagId() != null)
throw new IllegalStateException(MessageFormat.format(JGitText.get().illegalStateExists, getTagId()));
final ObjectId id;
final RefUpdate ru;
if (tagger!=null || message!=null || type!=null) {
ObjectInserter odi = objdb.newObjectInserter();
try {
id = odi.insert(Constants.OBJ_TAG, odi.format(this));
odi.flush();
setTagId(id);
} finally {
odi.release();
}
} else {
id = objId;
}
ru = objdb.updateRef(Constants.R_TAGS + getTag());
ru.setNewObjectId(id);
ru.setRefLogMessage("tagged " + getTag(), false);
if (ru.forceUpdate() == RefUpdate.Result.LOCK_FAILURE)
throw new ObjectWritingException(MessageFormat.format(JGitText.get().unableToLockTag, getTag()));
}
public String toString() {
return "tag[" + getTag() + getType() + getObjId() + " " + getTagger() + "]";
}
/**
* @return SHA-1 of this tag (if annotated and stored).
*/
/** @return this tag's object id. */
public ObjectId getTagId() {
return tagId;
}
/**
* Set SHA-1 of this tag. Used by writer.
* Set the id of this tag object.
*
* @param tagId
* @param id
* the id that we calculated for this object.
*/
public void setTagId(ObjectId tagId) {
this.tagId = tagId;
public void setTagId(ObjectId id) {
tagId = id;
}
/**
* @return creator of this tag.
*/
public PersonIdent getTagger() {
decode();
return tagger;
}
/**
* Set the creator of this tag
*
* @param tagger
*/
public void setTagger(PersonIdent tagger) {
this.tagger = tagger;
}
/**
* @return tag target type
*/
public String getType() {
decode();
/** @return the type of object this tag refers to. */
public int getObjectType() {
return type;
}
/**
* Set tag target type
* @param type
*/
public void setType(String type) {
this.type = type;
/** @return the object this tag refers to. */
public ObjectId getObjectId() {
return object;
}
/**
* @return name of the tag.
* Set the object this tag refers to, and its type.
*
* @param obj
* the object.
* @param objType
* the type of {@code obj}. Must be a valid type code.
*/
public void setObjectId(AnyObjectId obj, int objType) {
object = obj.copy();
type = objType;
tagId = null;
}
/**
* Set the object this tag refers to, and infer its type.
*
* @param obj
* the object the tag will refer to.
*/
public void setObjectId(RevObject obj) {
setObjectId(obj, obj.getType());
}
/** @return short name of the tag (no {@code refs/tags/} prefix). */
public String getTag() {
return tag;
}
@ -270,25 +123,77 @@ public String getTag() {
/**
* Set the name of this tag.
*
* @param tag
* @param shortName
* new short name of the tag. This short name should not start
* with {@code refs/} as typically a tag is stored under the
* reference derived from {@code "refs/tags/" + getTag()}.
*/
public void setTag(String tag) {
this.tag = tag;
public void setTag(String shortName) {
this.tag = shortName;
tagId = null;
}
/** @return creator of this tag. May be null. */
public PersonIdent getTagger() {
return tagger;
}
/**
* @return the SHA'1 of the object this tag refers to.
*/
public ObjectId getObjId() {
return objId;
}
/**
* Set the id of the object this tag refers to.
* Set the creator of this tag.
*
* @param objId
* @param taggerIdent
* the creator. May be null.
*/
public void setObjId(ObjectId objId) {
this.objId = objId;
public void setTagger(PersonIdent taggerIdent) {
tagger = taggerIdent;
tagId = null;
}
/** @return the complete commit message. */
public String getMessage() {
return message;
}
/**
* Set the tag's message.
*
* @param newMessage
* the tag's message.
*/
public void setMessage(final String newMessage) {
message = newMessage;
tagId = null;
}
@Override
public String toString() {
StringBuilder r = new StringBuilder();
r.append("Tag");
if (tagId != null)
r.append("[" + tagId.name() + "]");
r.append("={\n");
r.append("object ");
r.append(object != null ? object.name() : "NOT_SET");
r.append("\n");
r.append("type ");
r.append(object != null ? Constants.typeString(type) : "NOT_SET");
r.append("\n");
r.append("tag ");
r.append(tag != null ? tag : "NOT_SET");
r.append("\n");
if (tagger != null) {
r.append("tagger ");
r.append(tagger);
r.append("\n");
}
r.append("\n");
r.append(message != null ? message : "");
r.append("}");
return r.toString();
}
}

View File

@ -54,7 +54,6 @@
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Tag;
import org.eclipse.jgit.util.MutableInteger;
import org.eclipse.jgit.util.RawParseUtils;
@ -186,17 +185,6 @@ public final String getShortMessage() {
return str;
}
/**
* Parse this tag buffer for display.
*
* @param walk
* revision walker owning this reference.
* @return parsed tag.
*/
public Tag asTag(final RevWalk walk) {
return new Tag(walk.repository, this, tagName, buffer);
}
/**
* Get a reference to the object this tag was placed on.
*