好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

【C#】纯托管实现一个Git服务端

【C#】纯托管实现一个Git服务端

【C#】纯托管实现一个Git服务端

 有传闻说,这年头不用Git就不是个程序员。传闻归传闻,近些年来Git的发展是如火如荼。除了一些公共的Git平台外,大多的Git服务端都是在Linux上的,Windows的可选方案实在甚少。作为一个.Net码农,当然希望能有个纯托管代码的Git服务端。经过一晚上的学习,用纯托管代码写了个Git服务端供大家参考。

    学习资料:暂无。

    接下来开始码代码。首先加入引用:GitSharp.Core,GitSharp。可以从 git://github.com/henon/GitSharp.git 获取。然后,

    1:    using  GitSharp.Core.Transport;
    2:    using  System;
    3:    using  System.IO;
    4:    using  System.Net;
    5:    using  System.Text;
    6:    using  System.Text.RegularExpressions;
    7:    
    8:    namespace  SampleGitServer
    9:   {
   10:        class  Program
   11:       {
   12:            const   string  PREFIX =  @"http://localhost:2034/" ;
   13:            const   string  REPOSITORY_PATH =  @"F:\Repositories\git-debug-ONLY" ;
   14:    
   15:            readonly   static  Regex GetInfoRefsRegex =  new  Regex(PREFIX +  @"\w{3,10}/info/refs\?service=.*" );
   16:            readonly   static  Regex GitUploadPackRegex =  new  Regex(PREFIX +  @"\w{3,10}/git-upload-pack" );
   17:            readonly   static  Regex GitRecivePackRegex =  new  Regex(PREFIX +  @"\w{3,10}/git-receive-pack" );
   18:    
   19:            static   void  Main( string [] args)
   20:           {
   21:               var listener =  new  HttpListener();
   22:               listener.Prefixes.Add(PREFIX);
   23:    
   24:               Console.WriteLine( "Listening: "  + PREFIX);
   25:               listener.Start();
   26:    
   27:                while  ( true )
   28:               {
   29:                   var context = listener.GetContext();
   30:                   var url = context.Request.Url.ToString();
   31:    
   32:                   Console.WriteLine(url);
   33:    
   34:                    if  (GetInfoRefsRegex.Match(url).Success)
   35:                       GetInfoRefs(context);
   36:                    else   if  (GitUploadPackRegex.Match(url).Success)
   37:                       GitUploadPack(context);
   38:                    else   if  (GitRecivePackRegex.Match(url).Success)
   39:                       GitRecivePack(context);
   40:               }
   41:           }
   42:    
   43:            private   static   void  GetInfoRefs(HttpListenerContext context)
   44:           {
   45:               var Request = context.Request;
   46:               var Response = context.Response;
   47:               var project = Request.Url.PathAndQuery.Split( '/' )[1];
   48:               var service = Request.QueryString[ "service" ];
   49:    
   50:               var directory = GetDirectoryInfo(project);
   51:                if  (GitSharp.Repository.IsValid(directory.FullName,  true ))
   52:               {
   53:                   Response.StatusCode = 200;
   54:                   Response.ContentType = String.Format( "application/x-{0}-advertisement" , service);
   55:                   SetNoCache(Response);
   56:    
   57:                   var sb =  new  StringBuilder();
   58:                   sb.Append(FormatMessage(String.Format( "# service={0}\n" , service)));
   59:                   sb.Append(FlushMessage());
   60:                   var bytes = Encoding.ASCII.GetBytes(sb.ToString());
   61:                   Response.OutputStream.Write(bytes, 0, bytes.Length);
   62:    
   63:                    using  (var repository =  new  GitSharp.Repository(directory.FullName))
   64:                   {
   65:                        if  (String.Equals( "git-receive-pack" , service, StringComparison.InvariantCultureIgnoreCase))
   66:                       {
   67:                            using  (var pack =  new  ReceivePack(repository))
   68:                           {
   69:                               pack.SendAdvertisedRefs( new  RefAdvertiser.PacketLineOutRefAdvertiser( new  PacketLineOut(Response.OutputStream)));
   70:                           }
   71:    
   72:                       }
   73:                        else   if  (String.Equals( "git-upload-pack" , service, StringComparison.InvariantCultureIgnoreCase))
   74:                       {
   75:                            using  (var pack =  new  UploadPack(repository))
   76:                           {
   77:                               pack.SendAdvertisedRefs( new  RefAdvertiser.PacketLineOutRefAdvertiser( new  PacketLineOut(Response.OutputStream)));
   78:                           }
   79:                       }
   80:                   }
   81:               }
   82:                else 
   83:               {
   84:                   Response.StatusCode = 404;
   85:               }
   86:               Response.Close();
   87:           }
   88:    
   89:            private   static   void  GitUploadPack(HttpListenerContext context)
   90:           {
   91:               var Request = context.Request;
   92:               var Response = context.Response;
   93:               var project = Request.Url.PathAndQuery.Split( '/' )[1];
   94:    
   95:               Response.ContentType =  "application/x-git-upload-pack-result" ;
   96:               SetNoCache(Response);
   97:    
   98:               var directory = GetDirectoryInfo(project);
   99:                if  (GitSharp.Repository.IsValid(directory.FullName,  true ))
  100:               {
  101:                    using  (var repository =  new  GitSharp.Repository(directory.FullName))
  102:                    using  (var pack =  new  UploadPack(repository))
  103:                   {
  104:                       pack.setBiDirectionalPipe( false );
  105:                       pack.Upload(Request.InputStream, Response.OutputStream, Response.OutputStream);
  106:                   }
  107:               }
  108:                else 
  109:               {
  110:                   Response.StatusCode = 404;
  111:               }
  112:               Response.Close();
  113:           }
  114:    
  115:            private   static   void  GitRecivePack(HttpListenerContext context)
  116:           {
  117:               var Request = context.Request;
  118:               var Response = context.Response;
  119:               var project = Request.Url.PathAndQuery.Split( '/' )[1];
  120:    
  121:               Response.ContentType =  "application/x-git-receive-pack-result" ;
  122:               SetNoCache(Response);
  123:    
  124:               var directory = GetDirectoryInfo(project);
  125:                if  (GitSharp.Repository.IsValid(directory.FullName,  true ))
  126:               {
  127:                    using  (var repository =  new  GitSharp.Repository(directory.FullName))
  128:                    using  (var pack =  new  ReceivePack(repository))
  129:                   {
  130:                       pack.setBiDirectionalPipe( false );
  131:                       pack.receive(Request.InputStream, Response.OutputStream, Response.OutputStream);
  132:                   }
  133:               }
  134:                else 
  135:               {
  136:                   Response.StatusCode = 404;
  137:               }
  138:               Response.Close();
  139:           }
  140:    
  141:            private   static  String FormatMessage(String input)
  142:           {
  143:                return  (input.Length + 4).ToString( "X" ).PadLeft(4,  '0' ) + input;
  144:           }
  145:    
  146:            private   static  String FlushMessage()
  147:           {
  148:                return   "0000" ;
  149:           }
  150:    
  151:            private   static  DirectoryInfo GetDirectoryInfo(String project)
  152:           {
  153:                return   new  DirectoryInfo(Path.Combine(REPOSITORY_PATH, project));
  154:           }
  155:    
  156:            private   static   void  SetNoCache(HttpListenerResponse Response)
  157:           {
  158:               Response.AddHeader( "Expires" ,  "Fri, 01 Jan 1980 0 GMT" );
  159:               Response.AddHeader( "Pragma" ,  "no-cache" );
  160:               Response.AddHeader( "Cache-Control" ,  "no-cache, max-age=0, must-revalidate" );
  161:           }
  162:       }
  163:   }

    好吧,你看完代码会有一种上当的感觉。我必须承认我只是实现了服务端的接口而已。PS,我不会告诉你这点代码都是抄来的。

      重点是,所有的代码都是托管代码。在Github.com上有个正在发展中的ASP.NET MVC + EF + Sqlite实现的Git服务端(Dudu推荐: 用开源 ASP.NET MVC 程序 Bonobo Git Server 搭建 Git 服务器 )。经过几天的试用之后觉得比较稳定。重点的重点是此服务端正处在发展初期,你完全可以根据自己需求打造一个最适合自己的Git服务端。PS,此repo的主人最近很活跃。

用开源 ASP.NET MVC 程序 Bonobo Git Server 搭建 Git 服务器

 

现在不用Git,都不好意思说自己是程序员。

当你想用Git,而源代码服务器是Windows系统时,你将面临一个问题:如何在Windows上搭建Git服务器?

看看这篇文章( Setting up a Msysgit Server with copSSH on Windows )中的配置步骤,你会忘而却步吗?你会感叹“Linux世界的精彩,Windows世界的无奈”?

但程序员的天性是解决问题并以此为乐。不管生活在哪个世界,解决问题才是王道。于是,有程序员解决了这个问题,用ASP.NET MVC写了一个开源的Git服务器程序—— Bonobo Git Server 。

Bonobo Git Server基于.NET Framework 4.0+ASP.NET MVC 3开发,数据库用的是SQLite,Git部分用的是 GitSharp - Git for .NET and Mono 。

运行Bonobo Git Server,只需要IIS+WebDAV(IIS 7.5自带WebDAV, IIS 7.0需要下载安装)。

下面简单分享一下安装配置步骤,该步骤经过实践检验,我们已经成功部署。

第一部分 Bonobo Git Server站点的安装与配置

1. 下载Bonobo Git Server并解压

下载地址: http://www.chodounsky.net/bonobo-git-server/

如果想看源代码,请在这里下载: https://github.com/jakubgarfield/Bonobo-Git-Server 。

2. 配置一个IIS站点(比如:git.cnblogs.com),指向Bonobo Git Server所在文件夹。

a) 应用程序池要以.NET Framework 4.0运行。

b) 要安装ASP.NET MVC3。

c) 如果服务器用的是X64的Windows,需要下载64位版本的 System.Data.SQLite 至bin文件夹替换32位版本的。

3. 通过浏览器访问上一步配置的站点,如下图:

4. 输入默认用户名admin与密码admin,进入下图页面:

5. 点击“Global Settings”,设置一下代码库的根目录,并设置好该目录的文件系统权限(需要有写权限):

6. 点击“Respositories” 》“Create new repository”,创建新的代码库:

7. 创建好之后,点击代码库的名称,就能查看该代码库的信息,比如最重要的信息——Git Repository Location。

8. 安装/配置WebDAV

安装

1) 如果是IIS 7.5(Windows 7, Windows Server 2008 R2),WebDAV是自带的,只要添加该组件即可。具体配置方法参见  Installing WebDAV on IIS 7.5 。

2) 如果是IIS 7.0,需要另外下载安装,请参见  Installing WebDAV on IIS 7.0  。

配置

添加一条Authoring Rule:

到此,Git 服务器站点的基本配置就完成了。

第二部分 Git客户端简要操作步骤

现在可以通过Git客户端提交代码了,这里用的是TortoiseGit。

1. 安装TortoiseGit,下载地址: http://code.google.com/p/tortoisegit/ (需要先安装 msysgit ),VS2010插件可以使用 Git Source Control Provider 。

2. 在将要放置代码的文件夹点击右键选择"Git Clone",在Url中输入代码库的地址,确定后输入默认用户名与密码,然后就开始Clone...出现如下画面表示Clone成功。

3. 向这个代码库文件夹添加代码文件,然后通过TortoiseGit的菜单[Git Commint -> "master"...”]提交代码(这个提交只是向本地的代码库提交,并没有提交至服务器,这也是Git与SVN的主要区别之一)。

4. 通过TortoiseGit > Push 提交至Git服务器。

第三部分  Git服务器的其他操作

修改管理员密码,通过左侧的 "Users"链接进入用户管理界面进行修改。 添加新用户并授权,管理员无法直创建帐户,需要通过注册页面先注册一个帐户(登录页面右上角有注册链接),然后在用户管理界面将该用户加入Administrator角色。 如果遇到问题,可以查看App_Data中的错误日志文件Bonobo.Git.Server.Errors.log。  由于是开源程序,有什么不合你意的地方,直接可以修改源代码。

小结

轻松搞定,如愿以偿,现在终于可以理直气壮地说,“我是程序员,我用的是Git!”

 

 

 

标签:  Git

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于【C#】纯托管实现一个Git服务端的详细内容...

  阅读:50次