Git 客户端,采用 C# 编写。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

202 lines
7.0 KiB

using System;
using System.Collections.Generic;
using System.Text;
namespace GitCommands
{
public class CommitInformation
{
/// <summary>
/// Private constructor
/// </summary>
private CommitInformation (string header, string body)
{
Header = header;
Body = body;
}
public string Header {get; private set;}
public string Body{get; private set;}
/// <summary>
/// Gets branches which contain the given commit.
/// If both local and remote branches are requested, remote branches are prefixed with "remotes/"
/// (as returned by git branch -a)
/// </summary>
/// <param name="sha1">The sha1.</param>
/// <param name="getLocal">Pass true to include local branches</param>
/// <param name="getLocal">Pass true to include remote branches</param>
/// <returns></returns>
public static IEnumerable<string> GetAllBranchesWhichContainGivenCommit(string sha1, bool getLocal, bool getRemote)
{
string args = "--contains " + sha1;
if (getRemote && getLocal)
args = "-a "+args;
else if (getRemote)
args = "-r "+args;
else if (!getLocal)
return new string[]{};
string info = GitCommandHelpers.RunCmd(Settings.GitCommand, "branch "+args);
if (info.Trim().StartsWith("fatal") || info.Trim().StartsWith("error:"))
return new List<string>();
string[] result = info.Split(new[] { '\r', '\n', '*' }, StringSplitOptions.RemoveEmptyEntries);
// Remove symlink targets as in "origin/HEAD -> origin/master"
for (int i = 0; i < result.Length; i++)
{
string item = result[i].Trim();
int idx;
if (getRemote && ((idx = item.IndexOf(" ->")) >= 0))
{
item = item.Substring(0, idx);
}
result[i] = item;
}
return result;
}
/// <summary>
/// Gets all tags which contain the given commit.
/// </summary>
/// <param name="sha1">The sha1.</param>
/// <returns></returns>
public static IEnumerable<string> GetAllTagsWhichContainGivenCommit(string sha1)
{
string info = GitCommandHelpers.RunCmd(Settings.GitCommand, "tag --contains " + sha1);
if (info.Trim().StartsWith("fatal") || info.Trim().StartsWith("error:"))
return new List<string>();
return info.Split(new[] { '\r', '\n', '*', ' ' }, StringSplitOptions.RemoveEmptyEntries);
}
/// <summary>
/// Gets the commit info.
/// </summary>
/// <param name="sha1">The sha1.</param>
/// <returns></returns>
public static CommitInformation GetCommitInfo(string sha1)
{
string info = GitCommandHelpers.RunCachableCmd(
Settings.GitCommand,
string.Format(
"show -s --pretty=format:\"{0}:\t\t%aN (%aE)%n{1}:\t%ar (%ad)%n{2}:\t%cN (%cE)%n{3}:\t%cr (%cd)%n{4}:\t%H%n%n%s%n%n%b\" {5}",
Strings.GetAuthorText(),
Strings.GetAuthorDateText(),
Strings.GetCommitterText(),
Strings.GetCommitterDateText(),
Strings.GetCommitHashText(), sha1));
if (info.Trim().StartsWith("fatal"))
return new CommitInformation("Cannot find commit" + sha1, "");
info = RemoveRedundancies(info);
int index = info.IndexOf(sha1) + sha1.Length;
if (index < 0)
return new CommitInformation("Cannot find commit" + sha1, "");
if (index >= info.Length)
return new CommitInformation(info, "");
string commitHeader = info.Substring(0, index);
string commitMessage = info.Substring(index);
//We need to recode the commit message because of a bug in Git.
//We cannot let git recode the message to Settings.Encoding which is
//needed to allow the "git log" to print the filename in Settings.Encoding
Encoding logoutputEncoding = GitCommandHelpers.GetLogoutputEncoding();
if (logoutputEncoding != Settings.Encoding)
commitMessage = logoutputEncoding.GetString(Settings.Encoding.GetBytes(commitMessage));
return new CommitInformation(commitHeader,
commitMessage);
}
private static string RemoveRedundancies(string info)
{
string author = GetField(info, Strings.GetAuthorText() + ":");
string committer = GetField(info, Strings.GetCommitterText() + ":");
if (String.Equals(author, committer, StringComparison.CurrentCulture))
{
info = RemoveField(info, Strings.GetCommitterText() + ":");
}
string authorDate = GetField(info, Strings.GetAuthorDateText() + ":");
string commitDate = GetField(info, Strings.GetCommitterDateText() + ":");
if (String.Equals(authorDate, commitDate, StringComparison.CurrentCulture))
{
info =
RemoveField(info, Strings.GetCommitterDateText() + ":").Replace(
Strings.GetAuthorDateText() + ":\t", Strings.GetDateText() + ":\t\t");
}
return info;
}
private static string RemoveField(string data, string header)
{
int headerIndex = data.IndexOf(header);
if (headerIndex == -1)
return data;
int endIndex = data.IndexOf('\n', headerIndex);
if (endIndex == -1)
endIndex = data.Length - 1;
int length = endIndex - headerIndex + 1;
return data.Remove(headerIndex, length);
}
private static string GetField(string data, string header)
{
int valueIndex = IndexOfValue(data, header);
if (valueIndex == -1)
return null;
int length = LengthOfValue(data, valueIndex);
return data.Substring(valueIndex, length);
}
private static int LengthOfValue(string data, int valueIndex)
{
if (valueIndex == -1)
return 0;
int endIndex = data.IndexOf('\n', valueIndex);
if (endIndex == -1)
endIndex = data.Length - 1;
return endIndex - valueIndex;
}
private static int IndexOfValue(string data, string header)
{
int headerIndex = data.IndexOf(header);
if (headerIndex == -1)
return -1;
int valueIndex = headerIndex + header.Length;
while (data[valueIndex] == '\t')
{
valueIndex++;
if (valueIndex == data.Length)
return -1;
}
return valueIndex;
}
}
}