Gitでコミットハッシュとアクティブブランチの名前を取得する

外部参照ライブラリなどディレクトリ以下に大量のリポジトリで管理されているコミットハッシュと、アクティブブランチの名前を取得する方法をご紹介します。

具体的には .git リポジトリのあるディレクトリで下記のコマンドを発行します。

# git のコミットハッシュを取得する.
git rev-parse HEAD

# git のアクティブブランチ名を取得する.
git rev-parse --abbrev-ref HEAD

フォームに下記のコンポーネントを配置してください。

textBox1: 探索するトップのディレクトリのパスを指定
listBox1: ハッシュとアクティブブランチ名を列挙
button1: 探索されたすべてのリポジトリ(ディレクトリ)のハッシュとアクティブブランチ名を取得する

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace aaa
{
	public partial class Form1 : Form
	{
		public Form1()
		{
			InitializeComponent();
		}

		private void Form1_Load( object sender, EventArgs e )
		{
			textBox1.Text = "c:/develop/my_library";
			button1.Text = "button1";
		}

		private void button1_Click( object sender, EventArgs e )
		{

			String dir_top = textBox1.Text.Trim();

			List<string> list_dir_dot_git = new List<string>();

			try
			{

				// トップディレクトリ以下にあるディレクトリを列挙する.
				SearchOption sop = SearchOption.AllDirectories;
				string [] dirs = Directory.GetDirectories( dir_top, "*", sop );

				// 列挙されたディレクトリに .git リポジトリ(ディレクトリ)が含まれているものを列挙する.
				for ( int k = 0; k < dirs.Length; k++ )
				{

					string dir_dot_git = Path.Combine( dirs[k], ".git" );

					if ( Directory.Exists( dir_dot_git ) )
					{
						// 列挙追加する.
						list_dir_dot_git.Add( dirs[k] );
					}

				}

				if ( list_dir_dot_git.Count == 0 )
				{
					MessageBox.Show( "Gitで管理されたディレクトリがありませんでした." );
					return; // warning.
				}

				// リストボックスをクリアする.
				listBox1.Items.Clear();

				// カーソルをウェイトカーソルに変更する.
				Cursor.Current = Cursors.WaitCursor;

				for ( int k = 0; k < list_dir_dot_git.Count; k++ )
				{

					// .git リポジトリを含むディレクトリ.
					String dir_working = list_dir_dot_git[k];

					// A: アクティブブランチのコミットハッシュを取得する.
					// B: アクティブブランチの名前を取得する.
					const String ARGV_A = "rev-parse HEAD";
					const String ARGV_B = "rev-parse --abbrev-ref HEAD";

					// Gitコマンドを実行する.
					List<String> outA = ExecGitCommand( ARGV_A, dir_working );
					List<String> outB = ExecGitCommand( ARGV_B, dir_working );

					// リストボックスに追加する.
					String str_git_hash    = outA[0];
					String str_branch_name = outB[0];
					String str_line = $"{str_git_hash}\t{str_branch_name}\t{dir_working}";
					listBox1.Items.Add( str_line );

				}

			}
			catch ( Exception excp )
			{
				MessageBox.Show( $"Error: {excp.Message}" );
				return; // warning.
			}
			finally
			{
				// カーソルを戻す.
				Cursor.Current = Cursors.Default;
			}

		}

		private List<string> ExecGitCommand( string arguments, string working_directory )
		{

			ProcessStartInfo psi = new ProcessStartInfo();
			psi.FileName               = "git";
			psi.Arguments              = arguments;
			psi.WorkingDirectory       = working_directory;
			psi.RedirectStandardOutput = true;
			psi.RedirectStandardError  = true;
			psi.StandardOutputEncoding = Encoding.UTF8; // ここを指定しないと日本語は文字化けする.
			psi.StandardErrorEncoding  = Encoding.UTF8; // ここを指定しないと日本語は文字化けする.
			psi.UseShellExecute        = false;
			psi.CreateNoWindow         = true;

			List<String> output = new List<string>();

			try
			{

				using ( Process proc = Process.Start( psi ) )
				{

					while ( !proc.StandardOutput.EndOfStream )
					{
						output.Add( proc.StandardOutput.ReadLine() );
					}

					string err = proc.StandardError.ReadToEnd();
					proc.WaitForExit();

					if ( proc.ExitCode != 0 )
					{
						throw new Exception( err );
					}

				}

			}
			catch ( Exception excp )
			{
				output.Add( excp.Message );
			}

			return output;

		}
	}
}

上記コードの82行目の str_line を、テキストファイルに吐き出せば、その後いろいろなことに利用できます。