Beispiel #1
0
 public void test002_ParseIdent()
 {
     string i = "A U Thor <*****@*****.**> 1142878501 -0500";
     var p = new PersonIdent(i);
     Assert.AreEqual(i, p.ToExternalString());
     Assert.AreEqual("A U Thor", p.Name);
     Assert.AreEqual("*****@*****.**", p.EmailAddress);
     Assert.AreEqual(1142878501000L, p.When);
 }
Beispiel #2
0
        public void test001_NewIdent()
        {
            PersonIdent p;
            p = new PersonIdent("A U Thor", "*****@*****.**", 1142878501000L.MillisToUtcDateTime(),
                                    (int)new TimeSpan(-5, 0, 0).TotalMinutes);

            Assert.AreEqual("A U Thor", p.Name);
            Assert.AreEqual("*****@*****.**", p.EmailAddress);
            Assert.AreEqual(1142878501000L, p.When);
            Assert.AreEqual("A U Thor <*****@*****.**> 1142878501 -0500", p.ToExternalString());
        }
Beispiel #3
0
 public void test001_NewIdent()
 {
     PersonIdent p;
     try
     {
         p = new PersonIdent("A U Thor", "*****@*****.**", 1142878501L.UnixTimeToDateTime(),
                                 TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"));
     }
     catch (TimeZoneNotFoundException)
     {
         p = new PersonIdent("A U Thor", "*****@*****.**", 1142878501L.UnixTimeToDateTime(),
                                 TimeZoneInfo.FindSystemTimeZoneById("US/Eastern"));
     }
     Assert.AreEqual("A U Thor", p.Name);
     Assert.AreEqual("*****@*****.**", p.EmailAddress);
     Assert.AreEqual(1142878501000L, p.When);
     Assert.AreEqual("A U Thor <*****@*****.**> 1142878501 -0500", p.ToExternalString());
 }
Beispiel #4
0
            public Entry(byte[] raw, int pos)
            {
                oldId = ObjectId.FromString(raw, pos);
                pos += Constants.OBJECT_ID_STRING_LENGTH;
                if (raw[pos++] != ' ')
                    throw new ArgumentException("Raw log message does not parse as log entry");
                newId = ObjectId.FromString(raw, pos);
                pos += Constants.OBJECT_ID_STRING_LENGTH;
                if (raw[pos++] != ' ')
                    throw new ArgumentException("Raw log message does not parse as log entry");
                who = RawParseUtils.parsePersonIdentOnly(raw, pos);
                int p0 = RawParseUtils.next(raw, pos, (byte)'\t');

                if (p0 == -1)
                    throw new ArgumentException("Raw log message does not parse as log entry");

                int p1 = RawParseUtils.nextLF(raw, p0);
                if (p1 == -1)
                    throw new ArgumentException("Raw log message does not parse as log entry");

                comment = RawParseUtils.decode(raw, p0, p1 - 1);
            }
        public void log(RefUpdate update, string msg, bool deref)
        {
            ObjectId oldId = update.getOldObjectId();
            ObjectId newId = update.getNewObjectId();
            Ref      @ref  = update.getRef();

            PersonIdent ident = update.getRefLogIdent();

            if (ident == null)
            {
                ident = new PersonIdent(parent);
            }
            else
            {
                ident = new PersonIdent(ident);
            }

            var r = new StringBuilder();

            r.Append(ObjectId.ToString(oldId));
            r.Append(' ');
            r.Append(ObjectId.ToString(newId));
            r.Append(' ');
            r.Append(ident.ToExternalString());
            r.Append('\t');
            r.Append(msg);
            r.Append('\n');
            byte[] rec = Constants.encode(r.ToString());

            if (deref && @ref.isSymbolic())
            {
                log(@ref.getName(), rec);
                log(@ref.getLeaf().getName(), rec);
            }
            else
            {
                log(@ref.getName(), rec);
            }
        }
Beispiel #6
0
        private void Decode()
        {
            if (_raw == null)
            {
                return;
            }

            int pos = 0;

            ByteArrayExtensions.ParsedLine res = _raw.ReadLine(pos);
            if (res.Buffer == null || !res.Buffer.StartsWith("tree ".getBytes()))
            {
                throw new CorruptObjectException(CommitId, "no tree");
            }

            bool skip;

            do
            {
                skip = false;

                res = _raw.ReadLine(res.NextIndex);

                if ((res.Buffer == null) || !res.Buffer.StartsWith("parent ".getBytes()))
                {
                    skip = true;
                }
            } while (!skip);

            const string authorPrefix = "author ";

            if (res.Buffer == null || !res.Buffer.StartsWith(authorPrefix.getBytes()))
            {
                throw new CorruptObjectException(CommitId, "no author");
            }

            byte[] rawAuthor = ExtractTrailingBytes(res.Buffer, authorPrefix);

            res = _raw.ReadLine(res.NextIndex);

            const string committerPrefix = "committer ";

            if (res.Buffer == null || !res.Buffer.StartsWith(committerPrefix.getBytes()))
            {
                throw new CorruptObjectException(CommitId, "no committer");
            }

            byte[] rawCommitter = ExtractTrailingBytes(res.Buffer, committerPrefix);

            res = _raw.ReadLine(res.NextIndex);

            const string encodingPrefix = "encoding ";

            if (res.Buffer != null && res.Buffer.StartsWith(encodingPrefix.getBytes()))
            {
                byte[] rawEncoding = ExtractTrailingBytes(res.Buffer, encodingPrefix);
                Encoding = Charset.forName(new ASCIIEncoding().GetString(rawEncoding));
            }
            else if (res.Buffer == null || res.Buffer.Length != 0)
            {
                throw new CorruptObjectException(CommitId, "malformed header:" + new ASCIIEncoding().GetString(res.Buffer ?? new byte[0]));
            }

            pos = res.NextIndex;

            var readBuf = new byte[_raw.Length - pos];

            Array.Copy(_raw, pos, readBuf, 0, _raw.Length - pos);
            int msgstart = readBuf.Length != 0 ? (readBuf[0] == '\n' ? 1 : 0) : 0;

            // If encoding is not specified, the default for commit is UTF-8
            if (Encoding == null)
            {
                Encoding = Constants.CHARSET;
            }

            // TODO: this isn't reliable so we need to guess the encoding from the actual content
            Author    = new PersonIdent(Encoding.GetString(rawAuthor));
            Committer = new PersonIdent(Encoding.GetString(rawCommitter));
            Message   = Encoding.GetString(readBuf, msgstart, readBuf.Length - msgstart);

            _raw = null;
        }
Beispiel #7
0
 public void test007_ParseIdent()
 {
     string i = "A U Thor<*****@*****.**>1142878501 +0230 ";
     var p = new PersonIdent(i);
     Assert.AreEqual("A U Thor", p.Name);
     Assert.AreEqual("*****@*****.**", p.EmailAddress);
     Assert.AreEqual(1142878501000L, p.When);
 }
Beispiel #8
0
 /// <summary>
 /// Copy a <seealso cref="PersonIdent"/>.
 /// </summary>
 /// <param name="pi">Original <seealso cref="PersonIdent"/>.</param>
 public PersonIdent(PersonIdent pi)
     : this(pi.Name, pi.EmailAddress)
 {
 }
Beispiel #9
0
 /// <summary>
 /// Copy a PersonIdent, but alter the clone's time stamp
 /// </summary>
 /// <param name="pi">Original <seealso cref="PersonIdent"/>.</param>
 /// <param name="when">Local date time in milliseconds (since Epoch).</param>
 /// <param name="tz">Time zone offset in minutes.</param>
 public PersonIdent(PersonIdent pi, long when, int tz)
     : this(pi.Name, pi.EmailAddress, when, tz)
 {
 }
Beispiel #10
0
 /// <summary>
 /// Copy a <seealso cref="PersonIdent"/>, but alter the clone's time stamp
 /// </summary>
 /// <param name="pi">Original <seealso cref="PersonIdent"/>.</param>
 /// <param name="when">Local date time in milliseconds (since Epoch).</param>
 public PersonIdent(PersonIdent pi, DateTime when)
     : this(pi.Name, pi.EmailAddress, when.ToMillisecondsSinceEpoch(), pi.tzOffset)
 {
 }
        /** Increment the {@link #author} and {@link #committer} times. */
        protected void tick() {
            long delta = (long)TimeSpan.FromMinutes(5).TotalMilliseconds;
            long now = author.When + delta;
            int tz = mockSystemReader.getTimezone(now);

            author = new PersonIdent(author, now, tz);
            committer = new PersonIdent(committer, now, tz);
        }
        public virtual void setUp(){
            recursiveDelete(testName() + " (SetUp)", trash, false, true);

            mockSystemReader = new MockSystemReader();
            mockSystemReader.userGitConfig = new FileBasedConfig(new FileInfo(Path.Combine(trash.FullName, "usergitconfig")));
            SystemReader.setInstance(mockSystemReader);

            long now = mockSystemReader.getCurrentTime();
            int tz = mockSystemReader.getTimezone(now);
            author = new PersonIdent("J. Author", "*****@*****.**");
            author = new PersonIdent(author, now, tz);

            committer = new PersonIdent("J. Committer", "*****@*****.**");
            committer = new PersonIdent(committer, now, tz);

            WindowCacheConfig c = new WindowCacheConfig();
            c.PackedGitLimit = (128 * WindowCacheConfig.Kb);
            c.PackedGitWindowSize = (8 * WindowCacheConfig.Kb);
            c.PackedGitMMAP = (useMMAP);
            c.DeltaBaseCacheLimit = (8 * WindowCacheConfig.Kb);
            WindowCache.reconfigure(c);
        }
 /// <summary>
 /// Set the identity of the user appearing in the reflog.
 /// <para/>
 /// The timestamp portion of the identity is ignored. A new identity with the
 /// current timestamp will be created automatically when the update occurs
 /// and the log record is written.
 /// </summary>
 /// <param name="pi">
 /// identity of the user. If null the identity will be
 /// automatically determined based on the repository
 /// configuration.
 /// </param>
 public void setRefLogIdent(PersonIdent pi)
 {
     refLogIdent = pi;
 }
Beispiel #14
0
 /// <summary>
 /// Set the identity of the user appearing in the reflog.
 /// <para/>
 /// The timestamp portion of the identity is ignored. A new identity with the
 /// current timestamp will be created automatically when the rename occurs
 /// and the log record is written.
 /// </summary>
 /// <param name="pi">
 /// identity of the user. If null the identity will be
 /// automatically determined based on the repository
 /// configuration.
 /// </param>
 public void setRefLogIdent(PersonIdent pi) {
     destination.setRefLogIdent(pi);
 }
Beispiel #15
0
        private void decode()
        {
            // FIXME: handle I/O errors
            if (raw == null) return;

            using (var br = new StreamReader(new MemoryStream(raw)))
            {
                string n = br.ReadLine();
                if (n == null || !n.StartsWith("object "))
                {
                    throw new CorruptObjectException(TagId, "no object");
                }
                Id = ObjectId.FromString(n.Substring(7));
                n = br.ReadLine();
                if (n == null || !n.StartsWith("type "))
                {
                    throw new CorruptObjectException(TagId, "no type");
                }
                TagType = n.Substring("type ".Length);
                n = br.ReadLine();

                if (n == null || !n.StartsWith("tag "))
                {
                    throw new CorruptObjectException(TagId, "no tag name");
                }
                TagName = 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, "no tagger header");

                if (n.Length > 0)
                    if (n.StartsWith("tagger "))
                        Tagger = new PersonIdent(n.Substring("tagger ".Length));
                    else
                        throw new CorruptObjectException(TagId, "no tagger/bad header");

                // Message should start with an empty line, but
                StringBuilder tempMessage = new StringBuilder();
                char[] readBuf = new char[2048];
                int readLen;
                int readIndex = 0;
                while ((readLen = br.Read(readBuf, readIndex, readBuf.Length)) > 0)
                {
                    //readIndex += readLen;
                    tempMessage.Append(readBuf, 0, readLen);
                }
                message = tempMessage.ToString();
                if (message.StartsWith("\n"))
                    message = message.Substring(1);
            }

            raw = null;
        }
Beispiel #16
0
        private void Decode()
        {
            if (_raw == null) return;

            using (var reader = new StreamReader(new MemoryStream(_raw)))
            {
                string n = reader.ReadLine();
                if (n == null || !n.StartsWith("tree "))
                {
                    throw new CorruptObjectException(CommitId, "no tree");
                }
                while ((n = reader.ReadLine()) != null && n.StartsWith("parent "))
                {
                    // empty body
                }
                if (n == null || !n.StartsWith("author "))
                {
                    throw new CorruptObjectException(CommitId, "no author");
                }
                string rawAuthor = n.Substring("author ".Length);
                n = reader.ReadLine();
                if (n == null || !n.StartsWith("committer "))
                {
                    throw new CorruptObjectException(CommitId, "no committer");
                }
                string rawCommitter = n.Substring("committer ".Length);
                n = reader.ReadLine();

                if (n != null && n.StartsWith("encoding"))
                {
                    Encoding = Charset.forName(n.Substring("encoding ".Length));
                }
                else if (n == null || n.Length!=0)
                {
                    throw new CorruptObjectException(CommitId, "malformed header:" + n);
                }

            #warning This does not currently support custom encodings
                //byte[] readBuf = new byte[br.available()]; // in-memory stream so this is all bytes left
                //br.Read(readBuf);
                //int msgstart = readBuf.Length != 0 ? (readBuf[0] == '\n' ? 1 : 0) : 0;

                if (Encoding != null)
                {
                    // TODO: this isn't reliable so we need to guess the encoding from the actual content
                    throw new NotSupportedException("Custom Encoding is not currently supported.");
                    //_author = new PersonIdent(new string(this.Encoding.GetBytes(rawAuthor), this.Encoding));
                    //_committer = new PersonIdent(new string(rawCommitter.getBytes(), encoding.name()));
                    //_message = new string(readBuf, msgstart, readBuf.Length - msgstart, encoding.name());
                }

                // TODO: use config setting / platform / ascii / iso-latin
                _author = new PersonIdent(rawAuthor);
                _committer = new PersonIdent(rawCommitter);
                //_message = new string(readBuf, msgstart, readBuf.Length - msgstart);
                _message = reader.ReadToEnd();
            }

            _raw = null;
        }
Beispiel #17
0
 /// <summary>
 /// Set the identity of the user appearing in the reflog.
 /// <para/>
 /// The timestamp portion of the identity is ignored. A new identity with the
 /// current timestamp will be created automatically when the update occurs
 /// and the log record is written.
 /// </summary>
 /// <param name="pi">
 /// identity of the user. If null the identity will be
 /// automatically determined based on the repository
 /// configuration.
 /// </param>
 public void setRefLogIdent(PersonIdent pi)
 {
     refLogIdent = pi;
 }
Beispiel #18
0
 private string iso(PersonIdent id)
 {
     return id.When.MillisToDateTimeOffset(id.TimeZoneOffset).ToIsoDateFormat();
 }
Beispiel #19
0
        private void commit(Core.Tree t, string commitMsg, PersonIdent author,
                            PersonIdent committer)
        {
            Core.Commit commit = new Core.Commit(db);
            commit.Author = (author);
            commit.Committer = (committer);
            commit.Message = (commitMsg);
            commit.TreeEntry = (t);
            //ObjectWriter writer = new ObjectWriter(db);
            //commit.CommitId = (writer.WriteCommit(commit));
            commit.Save();

            int nl = commitMsg.IndexOf('\n');
            RefUpdate ru = db.UpdateRef(Constants.HEAD);
            ru.NewObjectId = (commit.CommitId);
            ru.SetRefLogMessage("commit : "
                                + ((nl == -1) ? commitMsg : commitMsg.Slice(0, nl)), false);
            ru.ForceUpdate();
        }
 private static void putPersonIdent(IDictionary<String, String> env,
                                    string type, PersonIdent who) {
     string ident = who.ToExternalString();
     string date = ident.Substring(ident.IndexOf("> ") + 2);
     env.put("GIT_" + type + "_NAME", who.Name);
     env.put("GIT_" + type + "_EMAIL", who.EmailAddress);
     env.put("GIT_" + type + "_DATE", date);
                                    }
Beispiel #21
0
        private static void AppendOneRecord(ObjectId oldId, ObjectId newId, PersonIdent ident, string msg, Repository db, string refName)
        {
            ident = ident == null ? new PersonIdent(db) : new PersonIdent(ident);

            var r = new StringBuilder();
            r.Append(ObjectId.ToString(oldId));
            r.Append(' ');
            r.Append(ObjectId.ToString(newId));
            r.Append(' ');
            r.Append(ident.ToExternalString());
            r.Append('\t');
            r.Append(msg);
            r.Append('\n');

            byte[] rec = Constants.encode(r.ToString());
            var logdir = new DirectoryInfo(Path.Combine(db.Directory.FullName, Constants.LOGS));
            var reflog = new DirectoryInfo(Path.Combine(logdir.FullName, refName));

            var refdir = reflog.Parent;

            if (!refdir.Exists && !refdir.Mkdirs())
            {
                throw new IOException("Cannot create directory " + refdir);
            }

            using (var @out = new FileStream(reflog.FullName, System.IO.FileMode.Append, FileAccess.Write))
            {
                @out.Write(rec, 0, rec.Length);
            }
        }
Beispiel #22
0
 /// <summary>
 /// Copy a <seealso cref="PersonIdent"/>, but alter the clone's time stamp
 /// </summary>
 /// <param name="pi">Original <seealso cref="PersonIdent"/>.</param>
 /// <param name="when">Local date time in milliseconds (since Epoch).</param>
 public PersonIdent(PersonIdent pi, DateTime when)
     : this(pi.Name, pi.EmailAddress, when.ToMillisecondsSinceEpoch(), pi.tzOffset)
 {
 }
Beispiel #23
0
 ///	<summary>
 /// Copy a PersonIdent, but alter the clone's time stamp
 ///	</summary>
 ///	<param name="pi">Original <seealso cref="PersonIdent"/>.</param>
 ///	<param name="when">Local time.</param>
 ///	<param name="tz">Time zone.</param>
 public PersonIdent(PersonIdent pi, DateTime when, TimeZoneInfo tz)
     : this(pi.Name, pi.EmailAddress, when, tz)
 {
 }
Beispiel #24
0
 /// <summary>
 /// Copy a <seealso cref="PersonIdent"/>.
 /// </summary>
 /// <param name="pi">Original <seealso cref="PersonIdent"/>.</param>
 public PersonIdent(PersonIdent pi)
     : this(pi.Name, pi.EmailAddress)
 {
 }
Beispiel #25
0
 ///	<summary>
 /// Copy a PersonIdent, but alter the clone's time stamp
 ///	</summary>
 ///	<param name="pi">Original <seealso cref="PersonIdent"/>.</param>
 ///	<param name="when">Local time stamp.</param>
 ///	<param name="tz">Time zone.</param>
 public PersonIdent(PersonIdent pi, long git_time, int offset_in_minutes)
     : this(pi.Name, pi.EmailAddress, git_time, offset_in_minutes)
 {
 }
Beispiel #26
0
 /// <summary>
 /// Copy a PersonIdent, but alter the clone's time stamp
 /// </summary>
 /// <param name="pi">Original <seealso cref="PersonIdent"/>.</param>
 /// <param name="when">Local date time in milliseconds (since Epoch).</param>
 /// <param name="tz">Time zone offset in minutes.</param>
 public PersonIdent(PersonIdent pi, long when, int tz)
     : this(pi.Name, pi.EmailAddress, when, tz)
 {
 }
Beispiel #27
0
 /// <summary>
 /// Set the identity of the user appearing in the reflog.
 /// <para/>
 /// The timestamp portion of the identity is ignored. A new identity with the
 /// current timestamp will be created automatically when the rename occurs
 /// and the log record is written.
 /// </summary>
 /// <param name="pi">
 /// identity of the user. If null the identity will be
 /// automatically determined based on the repository
 /// configuration.
 /// </param>
 public void setRefLogIdent(PersonIdent pi)
 {
     destination.setRefLogIdent(pi);
 }
Beispiel #28
0
        private void decode()
        {
            // FIXME: handle I/O errors
            if (raw == null)
            {
                return;
            }

            using (var br = new StreamReader(new MemoryStream(raw)))
            {
                string n = br.ReadLine();
                if (n == null || !n.StartsWith("object "))
                {
                    throw new CorruptObjectException(TagId, "no object");
                }
                Id = ObjectId.FromString(n.Substring(7));
                n  = br.ReadLine();
                if (n == null || !n.StartsWith("type "))
                {
                    throw new CorruptObjectException(TagId, "no type");
                }
                TagType = n.Substring("type ".Length);
                n       = br.ReadLine();

                if (n == null || !n.StartsWith("tag "))
                {
                    throw new CorruptObjectException(TagId, "no tag name");
                }
                TagName = 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, "no tagger header");
                }

                if (n.Length > 0)
                {
                    if (n.StartsWith("tagger "))
                    {
                        Tagger = new PersonIdent(n.Substring("tagger ".Length));
                    }
                    else
                    {
                        throw new CorruptObjectException(TagId, "no tagger/bad header");
                    }
                }

                // Message should start with an empty line, but
                StringBuilder tempMessage = new StringBuilder();
                char[]        readBuf     = new char[2048];
                int           readLen;
                int           readIndex = 0;
                while ((readLen = br.Read(readBuf, readIndex, readBuf.Length)) > 0)
                {
                    //readIndex += readLen;
                    tempMessage.Append(readBuf, 0, readLen);
                }
                message = tempMessage.ToString();
                if (message.StartsWith("\n"))
                {
                    message = message.Substring(1);
                }
            }

            raw = null;
        }
Beispiel #29
0
        private void Decode()
        {
            if (_raw == null) return;

            int pos = 0;

            ByteArrayExtensions.ParsedLine res = _raw.ReadLine(pos);
            if (res.Buffer == null || !res.Buffer.StartsWith("tree ".getBytes()))
            {
                throw new CorruptObjectException(CommitId, "no tree");
            }

            bool skip;
            do
            {
                skip = false;

                res = _raw.ReadLine(res.NextIndex);

                if ((res.Buffer == null) || !res.Buffer.StartsWith("parent ".getBytes()))
                {
                    skip = true;
                }

            } while (!skip);

            const string authorPrefix = "author ";
            if (res.Buffer == null || !res.Buffer.StartsWith(authorPrefix.getBytes()))
            {
                throw new CorruptObjectException(CommitId, "no author");
            }

            byte[] rawAuthor = ExtractTrailingBytes(res.Buffer, authorPrefix);

            res = _raw.ReadLine(res.NextIndex);

            const string committerPrefix = "committer ";
            if (res.Buffer == null || !res.Buffer.StartsWith(committerPrefix.getBytes()))
            {
                throw new CorruptObjectException(CommitId, "no committer");
            }

            byte[] rawCommitter = ExtractTrailingBytes(res.Buffer, committerPrefix);

            res = _raw.ReadLine(res.NextIndex);

            const string mergetagPrefix = "mergetag ";
            if (res.Buffer != null && res.Buffer.StartsWith(mergetagPrefix.getBytes()))
            {
                byte[] rawMergetag = ExtractTrailingBytes(res.Buffer, mergetagPrefix);
                do
                    res = _raw.ReadLine(res.NextIndex);
                while (res.NextIndex < _raw.Length && res.Buffer != null && res.Buffer.Length > 0 && res.Buffer[0] == ' ');
            }
            else if (res.Buffer == null || res.Buffer.Length != 0)
            {
                throw new CorruptObjectException(CommitId, "malformed header:" + new ASCIIEncoding().GetString(res.Buffer ?? new byte[0]));
            }

            const string encodingPrefix = "encoding ";
            if (res.Buffer != null && res.Buffer.StartsWith(encodingPrefix.getBytes()))
            {
                byte[] rawEncoding = ExtractTrailingBytes(res.Buffer, encodingPrefix);
                Encoding = Charset.forName(new ASCIIEncoding().GetString(rawEncoding));
            }
            else if (res.Buffer == null || res.Buffer.Length != 0)
            {
                throw new CorruptObjectException(CommitId, "malformed header:" + new ASCIIEncoding().GetString(res.Buffer ?? new byte[0]));
            }

            pos = res.NextIndex;

            var readBuf = new byte[_raw.Length - pos];
            Array.Copy(_raw, pos, readBuf, 0, _raw.Length - pos);
            int msgstart = readBuf.Length != 0 ? (readBuf[0] == '\n' ? 1 : 0) : 0;

            // If encoding is not specified, the default for commit is UTF-8
            if (Encoding == null) Encoding = Constants.CHARSET;

            // TODO: this isn't reliable so we need to guess the encoding from the actual content
            Author = new PersonIdent(Encoding.GetString(rawAuthor));
            Committer = new PersonIdent(Encoding.GetString(rawCommitter));
            Message = Encoding.GetString(readBuf, msgstart, readBuf.Length - msgstart);

            _raw = null;
        }