分类: 开发

  • [转]git clone 克隆所有分支

    如下:

     1. #!/bin/bash 
     2. 
     3. #Whenever you clone a repo, you do not clone all of its branches by default. 
     4. #If you wish to do so, use the following script: 
     
     5. 
     
     6. for  branch  in  `git branch  -a  | grep remotes | grep -v HEAD | grep -v master `;  do 
     7.    git branch --track  ${branch#remotes/origin/} $branch 
     8. done
    
  • [转]git拆分子目录作为新仓库并保留log记录

    需求描述:

    现有一个非常之庞大(大的过分)的git仓库,包含了N多个项目的源码,项目各个阶段的文档,原型等。对于新用户来说,clone一次需要很长时间(网速也是槽点)。因此决定将原仓库拆分,将源码子目录作为一个新的仓库,并且需要保留和子目录相关的log记录。

    一.前期准备

    所有的命令在Git-shell中进行

    1. 原仓库在本地的目录结构如下图:

    1524103977(1).png (10.27 KB, 下载次数: 0)

    下载附件  保存到相册

    1 小时前 上传

    2. 描述约定

    为了更好的描述命令,先定义一下命令中占位符的意义

    原仓库:<old-repo>

    新仓库:<new-repo>

    想要分离出来的子文件夹名称: <name-of-folder>

    新的远端地址:<new-git-url>

    注意:如果你在使用 Windows,且该文件夹深度 > 1,你必须使用斜杠  / 作为目录分隔符而不是默认的反斜杠 \

    二.迁移(使用filter-branch命令)

    由于我需要迁移的子目录包含中文名,因此需要使用filter-branch命令来实现迁移,当然,如果不包含中文的目录也可以使用git1.8版本以后的subtree来实现,该方法稍后说明。

    1. 首先,clone 一份原仓库并删掉原来的 remote:(依次执行以下命令)

    (1)git clone <big-repo>  <new-repo>

    (2)cd <new-repo>

    (3)git remote rm origin

    2. 然后运行如下命令(这是重点):

    (1)git filter-branch –tag-name-filter cat –prune-empty –subdirectory-filter <name-of-folder> — –all

    这条命令同样会过滤所有历史提交,只保留所有对指定子目录有影响的提交,并将该子目录设为该仓库的根目录。这里说明各下个参数的作用:

    –tag-name-filter 该参数控制我们要如何处理旧的 tag,cat 即表示原样输出;

    –prune-empty 删除空的(对子目录没有影响的)提交;

    –subdirectory-filter 指定子目录路径;

    — –all 该参数必须跟在  — 后面,表示对所有分支进行操作。如果你只想保存当前分支,也可以不添加此参数。

    3. 清理.git的object

    当上述命令执行完毕后,就可以看到本地的新仓库已经是原仓库子目录中的内容了,且保留了关于该子目录所有的提交历史。不过只是这样的话新仓库中的

    .git 目录里还是保存有不少无用的 object,我们需要将其清除掉以减小新仓库的体积(如果你用subtree 的方法的话是不需要执行这一步的)。

    依次执行以下命令:

    (1)git reset –hard

    (2)git for-each-ref –format="%(refname)" refs/original/ |xargs -n 1 git update-ref -d

    (3)git reflog expire –expire=now –all

    (4)git gc –aggressive –prune=now

    4. 将新的本地仓库推送到远端

    cd到<new-repo>

    (1)添加远端地址:

    git remote add origin <new-git-url>

    (2)推送到远端:

    git push -u origin master

    特别注意:如果当前远端库是空的话,上述命令是好使的,由于我开始手贱,已经在新的git地址clone到本地,并且还新建了一个测试文件夹,因此导致新的git仓库的master不再是最新的了。因此可以先提交到dev分支:git push origin master:dev

    5. 合并dev到master(可选)

    如果第4步已经直接推动到master了。第5步可忽略。

    (1)首先将本地dev合并到本地master

    ①切换到master分支

    ②git merge origan/dev –allow-unrelated-histories

    由于是第一次合并,因此需要加上–allow-unrelated-histories,允许两个没有关联的历史合并在一起。后续的合并就不需要了。

    (2)将本地master push到远端

    (3)

    至此,使用filter-branch方式拆分git库已经完成。有木有心动,去试试吧。

    三.补充subtree方式迁移

    要求拆分的目录没有中文名

    1.首先,进入<big-repo> 所在的目录,创建一个<name-of-new-branch>的临时分支,运行:

    git subtree split -P <name-of-folder> -b <name-of-new-branch>

    2. 然后,我们创建一个新的 git 仓库:

    (1)mkdir  <new-repo>

    (2)git init

    3. 接着把原仓库中的临时分支拉到新仓库中:

    git pull </path/to/big-repo>  <name-of-new-branch>

    好了,完成。现在看看你的新仓库,是不是已经包含了原子文件夹中的所有文件和你之前在原仓库中的所有提交历史呢?后续步骤就可参照第二章中的3,4,5步了。

    虽然网上一搜一大堆,还是希望能帮助有需要的同学,至少可以避免我踩过的坑了。

    参考:https://blessing.studio/splitting-a-subfolder-out-into-a-new-git-repository/

    ———————

    作者:天空神话

    来源:CSDN

    原文:https://blog.csdn.net/wang252949/article/details/80003791

    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 查找MsBuild.exe

    早期

    适用于.net4.0

     set  MSBuild=%windir%\Microsoft.NET\Framework\v4.0.30319\MsBuild.exe
    
    

    Vs2017

     for  /f  "tokens=1,2*"  %%i  in  ( '"reg query "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\SxS\VS7" /v  15.0"' )  do  ( set "Vs17=%%k" )
     
     if "%vs17%"  ==  ""  ( for  /f  "tokens=1,2*"  %%i  in  ( '"reg query "HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7" /v  15.0"' )  do  ( set "Vs17=%%k" ))
     
     
     
     set "MSBuild=%vs17%\MSBuild\15.0\Bin\MsBuild.exe" 
     
    
    

    最新 vswhere

    Find MSBuild Locate Visual Studio 2017 and newer installations. Contribute to microsoft/vswhere development by creating an account on GitHub. https://github.com/microsoft/vswhere/wiki/Find-MSBuild

     @ echo  off
     
     setlocal enabledelayedexpansion
     
     
     
     set "VsWhere=%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" 
     
     
     for  /f  "usebackq tokens=*"  %%i  in  (` "%VsWhere%"  -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\B in \MSBuild.exe`)  do  (
     
     "%%i"  %*
     
     exit  /b !errorlevel!
     
     )
    
    
  • 迁移svn到git遇到的各种问题及解决

    要迁移svn到git ,遇到了很多问题,所幸后来一一解决了。

    没有使用迁移工具subgit,而是按照官网的步骤来做的。

    一. 调用git svn clone 时卡在初始化空的git库。

     Initialized empty Git repository  in  xxx/.git/
    
    

    原因:

    svn 库版本太高,我使用的是visual svn server 最新版本。

    解决方案:

    我是通过创建一个ubuntu 虚拟机,在里面搭建新的svn服务器解决的。也可以通过其它方式搭建低版本subversion解决。

    二. 不规范分支

    svn库中存在一些不标准的分支,这些分支的形式各种各样,总之不是 /branches/xx 的形式,有如 2018/xx/分支名 的不从 branches 开始的分支,有 /branches/xx/分支名 的多级分支,它们都不能在 git svn clone 时被正确识别。

    解决方案:

    这个问题有3种解决方案,都要通过dump文件解决。

    如何导出dump 文件不进行描述,

     svnadmin dump xx > xx.dump
    svnrdump dump svn/remote/url > xx.dump
    
    

    1. 直接使用dump文件。

    直接以文本方式打开dump文件修改 要修改的路径。但这种方式,我总是不成功。而且对大文件操作很慢

    2. svn-dump-reloc

    在网上找到这个工具,可以很方便的修改路径。 问题是这种方式每次修改都需要先Load 到仓库,而不是直接修改 dump文件。安装也很费劲。

    3. sed 命令

    可以直接通过sed 命令修改路径,原理应该也 svn-dump-reloc 差不多

     # 比如要修改 路径 2018/xx 到 branches/2018_xx 
    sed -i  's/Node-path: 2019\/xx/Node-path: branches\/2018_xx/g'  xx.dump
    sed -i  's/Node-copyfrom-path: 2019\/xx/Node-copyfrom-path: branches\/2018_xx/g'  xx.dump
    
    

    注意事项

    不要在git 里清理错误的分支和误传的大文件。这可能会导致加载失败。

    三. 清理分支和标签时旧标签删除不掉

    按照官网的步骤

    你还需要一点 post-import(导入后) 清理工作。最起码的,应该清理一下 git svn 创建的那些怪异的索引结构。首先要移动标签,把它们从奇怪的远程分支变成实际的标签,然后把剩下的分支移动到本地。 要把标签变成合适的 Git 标签,运行

     $ git for-each-ref refs/remotes/tags | cut -d / -f 4- | grep -v @ | while read tagname; do git tag "$tagname" "tags/$tagname"; git branch -r -d "tags/$tagname"; done
    
    

    该命令将原本以 tag/ 开头的远程分支的索引变成真正的(轻巧的)标签。 接下来,把 refs/remotes 下面剩下的索引变成本地分支:

     $ git for-each-ref refs/remotes | cut -d / -f 3- | grep -v @ | while read branchname; do git branch "$branchname" "refs/remotes/$branchname"; git branch -r -d "$branchname"; done
    
    

    按照这个过程来做,可以生成新的分支和标签,但旧的标签和分支删除不掉,新生成的分支也会带一个 origin/

    原因

    官网的脚本对路径计算时,计算的是 refs/remotes/xx 而真实情况是 refs/remotes/origin/xx,需要对路径进行修正 。

    解决方案:

    对脚本 进行修改:

     #标签 
    git  for -each-ref refs/remotes/origin/tags | cut -d / -f 5- | grep -v @ |  while read  tagname;  do  git tag  " $tagname " "origin/tags/ $tagname " ; git branch -r -d  "origin/tags/ $tagname " ;  done #分支 
    git  for -each-ref refs/remotes/origin | cut -d / -f 4- | grep -v @ |  while read  branchname;  do  git branch  " $branchname " "refs/remotes/origin/ $branchname " ; git branch -r -d  "origin/ $branchname " ;  done
    

    现在,就可以得到正确清爽的路径了。

    四. svn库太大无法上传。

    原因:

    svn 时代,对文件大小没有太大限制。而git 对路径有根本的限制。虽然可以在服务器修改,但太大也没有意义。

    解决方案:

    找到大文件,进行修改。 参照官网的办法删除所有分支中的过往。

     #查找文件名并删除 
    git filter-branch -f --tree-filter  "find * -type f -name 'xx*' -delete"  -- --all
    
     #删除指定路径目录 
    git filter-branch -f --tree-filter  "rm -rf '要删除/文件夹'"  -- --all
    
    
    

    补充,找不到大文件路径怎么办

    参照 https://www.cnblogs.com/langzou/p/9877165.html

     git verify-pack -v .git/objects/pack/pack-*.idx | sort -k 3 -g | tail -10
    
    
  • 项目总结-wpf 使用经验

    刚做完一个使用了wpf技术的项目,总结一下项目中使用到的一些以前没用过的技术

    DataGrid 过滤

    nuget库 DataGridExtensions 提供了自定义扩展DataGrid列过滤的方法

    根据例子中的MultipleChoiceFilter 可以自定义任意过滤。

    我的日期过滤控件:

     // xaml: 
     <Control x:Class= "readLog.Views.Filters.DateFilter" 
              x:Name= "Control" 
                  xmlns= "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                  xmlns:x= "http://schemas.microsoft.com/winfx/2006/xaml" 
                  xmlns:mc= "http://schemas.openxmlformats.org/markup-compatibility/2006" 
                  xmlns:d= "http://schemas.microsoft.com/expression/blend/2008" 
                  xmlns:local= "clr-namespace:readLog.Views.Filters" 
                  xmlns:dgx= "urn:tom-englert.de/DataGridExtensions" 
                  xmlns:sys= "clr-namespace:System;assembly=mscorlib" 
                  mc:Ignorable= "d" 
                  d:DesignHeight= "30"  d:DesignWidth= "30" 
              >
     
         <Control.Resources>
     
             <ObjectDataProvider x:Key= "dateTypeEnum"  MethodName= "GetValues" 
                                 ObjectType= "{x:Type sys:Enum}" >
     
                 <ObjectDataProvider.MethodParameters>
     
                     <x:Type TypeName= "local:DateFilterType" ></x:Type>
     
                 </ObjectDataProvider.MethodParameters>
     
             </ObjectDataProvider>
     
         </Control.Resources>
     
         <Control.Template>
     
             <ControlTemplate>
     
                 <Grid>
     
                     <ToggleButton x:Name= "ToggleButton" >
     
                         <StackPanel Orientation= "Horizontal" >
     
                             <TextBlock x:Name= "IsFilterActiveMarker"  Text= "."  Margin= "0,0,-4,0"  Foreground= "{Binding ElementName=FilterSymbol, Path=Foreground}"  FontWeight= "Bold"  />
     
                             <Control x:Name= "FilterSymbol"  Style= "{DynamicResource {x:Static dgx:DataGridFilter.IconStyleKey}}"  />
     
                         </StackPanel>
     
                     </ToggleButton>
     
                     <Popup 
     
                         DataContext= "{Binding ElementName=Control}" 
                            x:Name= "Popup"  IsOpen= "{Binding Path=IsChecked, ElementName=ToggleButton, Mode=TwoWay}" 
                            AllowsTransparency= "True"  StaysOpen= "False" >
     
                         <StackPanel>
     
                             <ComboBox x:Name= "typeBox" 
                                       ItemsSource= "{Binding Source={StaticResource dateTypeEnum}}" 
                                       SelectedItem= "{Binding Path=FilterType}" />
     
     
     
                             <DatePicker x:Name= "begTm" 
                                         Visibility= "{Binding Path=BeginTimeVisible}" 
                                         SelectedDate= "{Binding Path=BeginTime}" 
                                         />
     
                             <DatePicker x:Name= "endTm" 
                                         Visibility= "{Binding Path=EndTimeVisible}" 
                                         SelectedDate= "{Binding Path=EndTime}" 
                             />
     
     
     
                         </StackPanel>
     
                     </Popup>
     
                 </Grid>
     
             </ControlTemplate>
     
         </Control.Template>
     
     </Control>
     
     
    
    
     // 交互 
     /// <summary> 
     ///  DateFilter.xaml 的交互逻辑 
     /// </summary> 
     public partial class DateFilter  :  Control 
         {
     
     public DateFilter ( ) 
     {
     
                 InitializeComponent();
     
             }
     
     
     
     # region  dependency property 
     
     
     public static readonly  DependencyProperty FilterTypeProperty = DependencyProperty.Register(
     
     "FilterType" ,  typeof (DateFilterType),  typeof (DateFilter), 
     
     new  FrameworkPropertyMetadata( default (DateFilterType), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (s, e) => ((DateFilter)s).FilterTypeChange()));
     
     
     
     
     
     private void FilterTypeChange ( ) 
     {
     
     // 可见性 
     switch  (FilterType)
     
                 {
     
     case  DateFilterType.All:
     
     case  DateFilterType.ThisYear:
     
     case  DateFilterType.ThisMonth:
     
     case  DateFilterType.PreYear:
     
     case  DateFilterType.PreMonth:
     
                         BeginTimeVisible = Visibility.Collapsed;
     
                         EndTimeVisible = Visibility.Collapsed;
     
     break ;
     
     case  DateFilterType.Earlier:
     
                         BeginTimeVisible = Visibility.Collapsed;
     
                         EndTimeVisible = Visibility.Visible;
     
     break ;
     
     case  DateFilterType.Later:
     
                         BeginTimeVisible = Visibility.Visible;
     
                         EndTimeVisible = Visibility.Collapsed;
     
     break ;
     
     case  DateFilterType.Between:
     
                         BeginTimeVisible = Visibility.Visible;
     
                         EndTimeVisible = Visibility.Visible;
     
     break ;
     
     default :
     
     throw new  ArgumentOutOfRangeException();
     
                 }
     
     
     
                 RangeChanged();
     
             }
     
     
     
     private void RangeChanged ( ) 
     {
     
                 Filter =  new  ContentFilter(FilterType, BeginTime, EndTime);
     
             }
     
     
     
     
     
     public  DateFilterType FilterType
     
             {
     
     get  => (DateFilterType) GetValue(FilterTypeProperty);
     
     set  => SetValue(FilterTypeProperty,  value );
     
             }
     
     
     
     public static readonly  DependencyProperty FilterProperty = DependencyProperty.Register(
     
     "Filter" ,  typeof (ContentFilter),  typeof (DateFilter), 
     
     new  FrameworkPropertyMetadata( default (ContentFilter), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (s, e) => ((DateFilter)s).FilterChanged()));
     
     
     
     public  ContentFilter Filter
     
             {
     
     get  => (ContentFilter) GetValue(FilterProperty);
     
     set  => SetValue(FilterProperty,  value );
     
             }
     
     
     
     private void FilterChanged ( ) 
     {
     
     var  filter = Filter  as  ContentFilter;
     
     if  ( null  == filter)
     
                 {
     
     return ;
     
                 }
     
     
     
                 FilterType = filter.FilterType;
     
                 BeginTime = filter.BeginTime;
     
                 EndTime = filter.EndTime;
     
             }
     
     
     
     public static readonly  DependencyProperty BeginTimeProperty = DependencyProperty.Register(
     
     "BeginTime" ,  typeof (DateTime),  typeof (DateFilter),
     
     new  FrameworkPropertyMetadata(DateTime.Today, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,(s, e) => ((DateFilter)s).RangeChanged()));
     
     
     
     public  DateTime BeginTime
     
             {
     
     get  => (DateTime) GetValue(BeginTimeProperty);
     
     set  => SetValue(BeginTimeProperty,  value );
     
             }
     
     
     
     public static readonly  DependencyProperty EndTimeProperty = DependencyProperty.Register(
     
     "EndTime" ,  typeof (DateTime),  typeof (DateFilter),
     
     new  FrameworkPropertyMetadata(DateTime.Today, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,(s, e) => ((DateFilter)s).RangeChanged()));
     
     
     
     public  DateTime EndTime
     
             {
     
     get  => (DateTime) GetValue(EndTimeProperty);
     
     set  => SetValue(EndTimeProperty,  value );
     
             }
     
     
     
     public static readonly  DependencyProperty PropertyTypeProperty = DependencyProperty.Register(
     
     "BeginTimeVisible" ,  typeof (Visibility),  typeof (DateFilter),
     
     new  FrameworkPropertyMetadata(Visibility.Collapsed, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (s, e) => ((DateFilter)s).RangeChanged()));
     
     
     
     public  Visibility BeginTimeVisible
     
             {
     
     get  => (Visibility) GetValue(PropertyTypeProperty);
     
     set  => SetValue(PropertyTypeProperty,  value );
     
             }
     
     
     
     public static readonly  DependencyProperty EndTimeVisibleProperty = DependencyProperty.Register(
     
     "EndTimeVisible" ,  typeof (Visibility),  typeof (DateFilter), 
     
     new  FrameworkPropertyMetadata(Visibility.Collapsed, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (s, e) => ((DateFilter)s).RangeChanged()));
     
     
     
     public  Visibility EndTimeVisible
     
             {
     
     get  => (Visibility) GetValue(EndTimeVisibleProperty);
     
     set  => SetValue(EndTimeVisibleProperty,  value );
     
             }
     
     
     
     
     
     
     
     # endregion 
     
     
     public class ContentFilter  :  IContentFilter 
             {
     
     public ContentFilter ( DateFilterType type, DateTime beg, DateTime end ) 
     {
     
                     FilterType = type;
     
                     BeginTime = beg;
     
                     EndTime = end;
     
                 }
     
     
     
     public bool IsMatch ( object value ) 
     {
     
     if  ( null  ==  value )
     
                     {
     
     return false ;
     
                     }
     
     
     
     try 
                     {
     
     var  tm = (DateTime)  value ;
     
     
     
     switch  (FilterType)
     
                         {
     
     case  DateFilterType.All:
     
     return true ;
     
     case  DateFilterType.ThisYear:
     
     return  IsMatchYear(tm, DateTime.Today);
     
     case  DateFilterType.ThisMonth:
     
     return  IsMatchMonth(tm, DateTime.Today);
     
     case  DateFilterType.PreYear:
     
     return  IsMatchYear(tm, DateTime.Today.AddYears( -1 ));
     
     case  DateFilterType.PreMonth:
     
     return  IsMatchMonth(tm, DateTime.Today.AddMonths( -1 ));
     
     case  DateFilterType.Earlier:
     
     return  tm.Date <= EndTime.Date;
     
     case  DateFilterType.Later:
     
     return  tm.Date >= BeginTime.Date;
     
     case  DateFilterType.Between:
     
     return  IsMatchDate(tm, BeginTime, EndTime);
     
     default :
     
     throw new  ArgumentOutOfRangeException();
     
                         }
     
                     }
     
     catch  (Exception e)
     
                     {
     
     return false ;
     
                     }
     
     
     
                 }
     
     
     
     
     
     public  DateFilterType FilterType {  get ; }
     
     
     
     public  DateTime BeginTime {  get ; }
     
     
     
     public  DateTime EndTime {  get ; }
     
     
     
     # region  Datetime 
     private bool IsMatchMonth ( DateTime tm, DateTime toMatch ) 
     {
     
     return  IsMatchDate(tm, GetFirstDayOfMonth(toMatch), GetLastDayOfMonth(toMatch));
     
                 }
     
     
     
     private bool IsMatchDate ( DateTime tm, DateTime beg, DateTime end ) 
     {
     
                     tm = tm.Date;
     
     return  tm <= beg && tm >= end;
     
                 }
     
     
     
     private bool IsMatchYear ( DateTime tm, DateTime toMatch ) 
     {
     
     return  IsMatchDate(tm, GetLastDayOfYear(toMatch), GetFirstDayOfYear(toMatch));
     
                 }
     
     
     
     private  DateTime  GetFirstDayOfMonth ( DateTime dt ) 
     {
     
     var  dtFrom = dt;
     
                     dtFrom = dtFrom.AddDays(-(dtFrom.Day -  1 ));
     
     
     
     return  dtFrom;
     
                 }
     
     
     
     private  DateTime  GetLastDayOfMonth ( DateTime dt ) 
     {
     
     var  dtTo = dt;
     
                     dtTo = dtTo.AddMonths( 1 );
     
                     dtTo = dtTo.AddDays(-(dtTo.Day));
     
     return  dtTo;
     
                 }
     
     
     
     private  DateTime  GetFirstDayOfYear ( DateTime dt ) 
     {
     
     var  dtFrom = dt;
     
                     dtFrom = dtFrom.AddMonths(-(dtFrom.Month -  1 ));
     
     return  GetFirstDayOfMonth(dtFrom);
     
                 }
     
     
     
     private  DateTime  GetLastDayOfYear ( DateTime dt ) 
     {
     
     var  dtTo = dt;
     
                     dtTo = dtTo.AddYears( 1 );
     
                     dtTo = dtTo.AddMonths(-dt.Month);
     
     
     
     return  GetLastDayOfMonth(dtTo);
     
                 }
     
     
     
     
     
     # endregion 
             }
     
         }
     
     
     
         [TypeConverter( typeof (EnumDescriptionTypeConverter))]
     
     public enum  DateFilterType
     
         {
     
             [Description( "所有" )]
     
             All,  // 全部 
             [Description( "今年" )]
     
             ThisYear,
     
             [Description( "本月" )]
     
             ThisMonth,
     
             [Description( "去年" )]
     
             PreYear,
     
             [Description( "上个月" )]
     
             PreMonth,
     
             [Description( "指定日期以前" )]
     
             Earlier,
     
             [Description( "指定日期以后" )]
     
             Later,
     
             [Description( "之间" )]
     
             Between,
     
     
     
     
     
         }
     
     
    
    

    枚举显示

    枚举显示有两个方案,

    1. 转换器, 在xaml中定义一个转换器资源
    2. 定义一个用来显示的字符串属性,界面绑定这个字符串属性。

    读取DataGrid某一行某一列的值

    从控件 DataGridExtensions 中学习到的。拿到的是真实的绑定对象,而不是显示的字符串。一开始用 GetCelllContent(),但对未显示的行无法取到。

     class GetCellValueClass  :  DependencyObject 
             {
     
     /// <summary> 
     ///  Identifies the CellValue dependency property, a private helper property used to evaluate the property path for the list items. 
     /// </summary> 
     private static readonly  DependencyProperty _cellValueProperty =
     
                     DependencyProperty.Register( "_cellValue" ,  typeof ( object ),  typeof (GetCellValueClass));
     
     
     
     public object GetCellValue ( DataGridColumn col,  object  item ) 
     {
     
     var  propertyPath = col.SortMemberPath;
     
     if  ( string .IsNullOrEmpty(propertyPath))
     
     return null ;
     
     
     
                     BindingOperations.SetBinding( this , _cellValueProperty,  new  Binding(propertyPath) { Source = item });
     
     var  propertyValue = GetValue(_cellValueProperty);
     
                     BindingOperations.ClearBinding( this , _cellValueProperty);
     
     
     
     return  propertyValue;
     
                 }
     
     
     
     
     
             }
     
     
    
    

    使用方法:

     new  GetCellValueClass().GetCellValue(col, item);
    
    
  • 遗传算法(genevo算法)学习

    对于NP困难问题,很难通过正向算法来解决,常规解决方案是遗传算法,或者它的各种变体,如模拟退火算法禁忌搜索等。

    遗传算法基本逻辑:

    初始化种群
    loop
    	评价种群适应度
        如果到达停止循环条件则停止
        选择下一个种群
        改变种群(交叉、变异)
      
    

    rust​中想要使用遗传算法,又不想自己实现一遍,所以研究学习一下 innoave/genevo: Execute genetic algorithm (GA) simulations in a customizable and extensible way. (github.com) 算法的思路和逻辑。

    1. 初始化种群

    genevo​ 初始化种群是通过 build_population()​ 函数来实现。这是模块 population​ 中的公开函数,返回一个空的EmptyPopulationBuilder对象:

    pub fn build_population() -> EmptyPopulationBuilder {
        EmptyPopulationBuilder {
            _empty: PhantomData,
        }
    }
    

    EmptyPopulationBuilder​ 需要调用 with_genome_builder()​ 函数来传入一个 GenomeBuilder​ 对象,生成 PopulationWithGenomeBuilderBuilder​ 对象,依次再调用 of_size()​,uniform_at_random()​ 或 using_seed()​ ,最终生成 Population

    1.1 GenomeBuilder

    /// A `GenomeBuilder` defines how to build individuals of a population for
    /// custom `genetic::Genotype`s.
    ///
    /// Typically the individuals are generated randomly.
    pub trait GenomeBuilder<G>: Sync
    where
        G: Genotype,
    {
        /// Builds a new genome of type `genetic::Genotype` for the given
        /// `index` using the given random number generator `rng`.
        fn build_genome<R>(&self, index: usize, rng: &mut R) -> G
        where
            R: Rng + Sized;
    }
    
    

    这个trait 用于生成一个新的基因组,根据index不同生成不同基因组。

    2. 评价适应度

    评价适应度相关的trait​ 是 FitnessFunction

    /// Defines the evaluation function to calculate the `Fitness` value of a
    /// `Genotype` based on its properties.
    pub trait FitnessFunction<G, F>: Clone
    where
        G: Genotype,
        F: Fitness,
    {
        /// Calculates the `Fitness` value of the given `Genotype`.
        fn fitness_of(&self, a: &G) -> F;
    
        /// Calculates the average `Fitness` value of the given `Fitness` values.
        fn average(&self, a: &[F]) -> F;
    
        /// Returns the very best of all theoretically possible `Fitness` values.
        fn highest_possible_fitness(&self) -> F;
    
        /// Returns the worst of all theoretically possible `Fitness` values.
        /// This is usually a value equivalent to zero.
        fn lowest_possible_fitness(&self) -> F;
    }
    

    比较简单,需要能够实现

    1. 对一个基因组进行计算获得 Fitness
    2. 对一组Fitness 进行运算,求平均值,
    3. 获得最高、最低的 Fitness

    库对所有整数实现了 Fitness​,包括有符号整数和无符号整数。Fitness​要求是必须实现 Eq​和Ord,所以浮点数不能作为适应度使用,需要转换为整数使用。

    实现方式是宏:

    macro_rules! implement_fitness_for_signed_integer {
        ( $($t:ty),* ) => {
            $(
                impl Fitness for $t {
                    fn zero() -> $t {
                        0
                    }
    
                    fn abs_diff(&self, other: &$t) -> $t {
                        let diff = self - other;
                        diff.abs()
                    }
                }
    
                impl AsScalar for $t {
                    #[inline]
                    fn as_scalar(&self) -> f64 {
                        *self as f64
                    }
                }
            )*
        }
    }
    
    implement_fitness_for_signed_integer!(i8, i16, i32, i64, isize);
    
    macro_rules! implement_fitness_for_unsigned_integer {
        ( $($t:ty),* ) => {
            $(
                impl Fitness for $t {
                    fn zero() -> $t {
                        0
                    }
    
                    fn abs_diff(&self, other: &$t) -> $t {
                        if self > other {
                            self - other
                        } else {
                            other - self
                        }
                    }
                }
    
                impl AsScalar for $t {
                    #[inline]
                    fn as_scalar(&self) -> f64 {
                        *self as f64
                    }
                }
            )*
        }
    }
    
    implement_fitness_for_unsigned_integer!(u8, u16, u32, u64, usize);
    

    3. 终止条件

    终止条件使用 Termination​ 特性来定义,使用 until​ 函数来输入给 ga算法。

    /// A `Termination` defines a condition when the `Simulation` shall stop.
    ///
    /// One implementation of the trait `Termination` should only handle one
    /// single termination condition. In the simulation multiple termination
    /// conditions can be combined through `combinator`s.
    pub trait Termination<A>
    where
        A: Algorithm,
    {
        /// Evaluates the termination condition and returns a `StopFlag` depending
        /// on the result. The `StopFlag` indicates whether the simulation shall
        /// stop or continue.
        ///
        /// In case the simulation shall be stopped, i.e. a `StopFlag::StopNow` is
        /// returned also a the reason why the simulation shall be stopped is
        /// returned. This reason should explain to the user of the simulation,
        /// why the simulation has been stopped.
        fn evaluate(&mut self, state: &State<A>) -> StopFlag;
    
        /// Resets the state of this `Termination` condition. This function is
        /// called on each `Termination` instance when the simulation is reset.
        ///
        /// This function only needs to be implemented by an implementation of
        /// `Termination` if it has its own state, e.g. for counting or tracking
        /// of progress.
        ///
        /// The default implementation does nothing.
        fn reset(&mut self) {}
    }
    

    对每一组基因以及它的 Fitness​, Termination​ 会评估一个结果, 是否终止: StopNow​ 或Continue

    genevo​库内置了一些条件,包括: FitnessLimit​,达到指定Fitness​后终止;GenerationLimit​,遗传指定次数后终止;TimeLimit, 达到指定时间后终止。

    除此之外,还为不同条件提供了组合: or​、and,来实现不同条件间的组合。

    4. 变换

    变换是遗传算法最复杂的部分,也是这个库最复杂的部分。

    genevo​把变换分成多步进行:Selection​, CrossOver​,Mutation​,ReInsertion 等。

    4.1 Selection

    按照官方的文档直接进行翻译

    从一个族群中根据它们的适应度和选择策略选择一组父基因组。

    通过traitSelectionOp来实现:

    /// A `SelectionOp` defines the function of how to select solutions for being
    /// the parents of the next generation.
    pub trait SelectionOp<G, F>: GeneticOperator
    where
        G: Genotype,
        F: Fitness,
    {
        /// Selects individuals from the given population according to the
        /// implemented selection strategy.
        fn select_from<R>(
            &self,
            population: &EvaluatedPopulation<G, F>,
            rng: &mut R,
        ) -> Vec<Parents<G>>
        where
            R: Rng + Sized;
    }
    

    这里的 EvaluatedPopulation 是已经经过评估的族群信息,从当前族群中,可以选择多组父基因。

    genevo库内置了几种选择方式:

    4.1.1 RouletteWheelSelector

    按照一定概率和数量,进行平均选择。

    selection_ratio​, 选择率,确定选择几组父基因,数量为族群数量​ * selection_ratio

    num_individuals_pre_parents,每组父基因的基因数量。

    默认情况下,每组父基因都是从族群中随机选择一条。

    4.1.2 UniversalSamplingSelector

    随机适应度的选择方式,与RouletteWheelSelector的区别在于,每组父基因中的第一条基因随机获取,其后的每一条基因,通过相同间隔的跳跃获得。

    4.1.3 TournamentSelector

    这是一种称为锦标赛的选择方式,选择最佳个体。

    4.1.4 MaximizeSelector

    选择表现最好的族群。

    4.2 CrossOver

    通过交叉产生新的后代。

    /// A `CrossoverOp` defines a function of how to crossover two
    /// `genetic::Genotype`s, often called parent genotypes, to derive new
    /// `genetic::Genotype`s. It is analogous to reproduction and biological
    /// crossover. Cross over is a process of taking two parent solutions and
    /// producing an offspring solution from them.
    pub trait CrossoverOp<G>: GeneticOperator
    where
        G: Genotype,
    {
        /// Performs the crossover of the `genetic::Parents` and returns the result
        /// as a new vector of `genetic::Genotype` - the `genetic::Children`.
        fn crossover<R>(&self, parents: Parents<G>, rng: &mut R) -> Children<G>
        where
            R: Rng + Sized;
    }
    

    传入一组 Parent​,生成一组新的Children

    4.2.1 UniformCrossBreeder

    产生与父基因数量相同的子基因,产生方式是对要产生的每一个子基因,每一位随机从父类中获取。

    4.2.2 SinglePointCrossBreeder​和 MultiPointCrossover

    它们通过对基因组本身实现的 MultiPointCrossovertrait来实现,

    pub trait MultiPointCrossover: Genotype {
        type Dna;
    
        fn crossover<R>(parents: Parents<Self>, num_cut_points: usize, rng: &mut R) -> Children<Self>
        where
            R: Rng + Sized;
    }
    

    genevo​库对 Vec​类型实现了该特性,原理是将子基因组分成 num_cut_points+1​段,每段取自不同基因组。其中SinglePointCrossBreeder​ 是num_cut_points=1的情况。

    4.2.3 OrderOneCrossover​和PartiallyMappedCrossover

    这两种方式,都通过函数 multi_parents_cyclic_crossover​来进行交叉实现,genevo​库的实现都是针对 usize类型。

    OrderOneCrossover​ 通过函数order_one_crossover 从两个序列中各取一段来进行混合,产生新的序列。

    PartiallyMappedCrossover​ 通过函数 partial_mapped_crossover来调整顺序。

    它们都是用来处理不同对象的顺序的。

    两个父基因组,各取一部分组成一个新的基因组。

    4.3 Mutation

    通过突变来产生新的后代。这种变换方式比较直接,就是直接对一条基因组进行变换,生成新的基因组。

    4.3.1 InsertOrderMutator

    比较简单的突变方式,循环 mutation_rate*length 次,每次随机选择一个基因,插入到一个新的位置。

    4.3.2 SwapOrderMutator

    循环 mutation_rate*length 次,每次随机交换两个基因的位置。

    4.3.3 RandomValueMutator

    主要针对值类型的基因,随机将基因突变为 min_value​ 和max_value​ 之间的值。突变使用 RandomGenomeMutation 特性。

    4.4 Reinsertion

    从后代中选择一些基因,创建新的族群。

    pub trait ReinsertionOp<G, F>: GeneticOperator
    where
        G: Genotype,
        F: Fitness,
    {
        /// Combines the given offspring with the current population to create
        /// the population of the next generation.
        ///
        /// The offspring parameter is passed as mutable borrow. It can be
        /// mutated to avoid cloning. The `genetic::Genotype`s that make it up into
        /// the new population should be moved instead of cloned. After this
        /// function finishes the offspring vector should hold only those
        /// `genetic::Genotype`s that have not been included in the resulting
        /// population. If by the end of this function all `genetic::Genotype`s in
        /// offspring have been moved to the resulting population the offspring
        /// vector should be left empty.
        fn combine<R>(
            &self,
            offspring: &mut Offspring<G>,
            population: &EvaluatedPopulation<G, F>,
            rng: &mut R,
        ) -> Vec<G>
        where
            R: Rng + Sized;
    }
    

    4.4.1 UniformReinserter

    从新族群中随机选择一部分,从旧族群中随机选择一部分,共同组成新族群。

    4.4.2 ElitistReinserter

    精英选择,选择新旧族群中最好的那部分。

    5. 运行

    genevo​库有两种运行方式: run​和step

    5.1 run()

    运行run时,算法进入循环,直到找到终止或出错。

    5.2 step()

    每运行一次 step,算法运行一次,直到终止或出错。

  • 重整仓库

    1. 拆分子目录作为单独的仓库

    参照 : https://blog.csdn.net/wang252949/article/details/80003791

     1. git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter <path-name> -- --all
    
    

    2. 过滤某些目录,只保留部分目录

     1. git filter-branch  -f  --tree-filter  'rm -rf <dir-and-file-to-delete>'  -- --all
    
    

    多次运行,需要加上 -f 表示强制。

    3. 重命名

     1. git filter-branch  -f  --tree-filter  'mv <old-file> <new-file> || true'  -- --all
    
    

    4. 清理仓库

     1. (1)git reset --hard
     
     2. (2)git  for -each-ref --format= "%(refname)"  refs/original/ |xargs -n 1 git update-ref  -d 
     3. (3)git reflog expire --expire=now --all
     
     4. (4)git gc --aggressive --prune=now
     
     
     5. 
    
    
  • Encountered 1 file(s) that should have been pointe

    git错误:

     Encountered  1 file (s)  that  should have been pointers,  but  weren't
    
    

    处理方法: 常规:

     git lfs  uninstall 
     git  reset --hard 
     git lfs  install 
     git lfs pull
    
    

    如果这不起作用:

     git rm  --cached -r . 
     git  reset --hard 
     git rm .gitattributes
     
     git  reset  .
     
     git checkout .
     
     
    
    
  • Visual Studio 多环境并存

    有时会遇到这样的问题,在使用VS 时,对不同的语言,需要不同的插件支持,VS配置。 有一个办法是同时使用多个版本的VS,但这很让人不爽。

    VisualStudio 有一个高级的用法,在命令行后添加 /rootSuffix ,可以创建一个完全不同的环境。在开发 VS插件时,开启调试,会创建一个完全空白的VS并加载这个插件,就是通过这个配置完成的。

    1. 创建一个新的 Visual Studio 的快捷方式

    可以通过复制旧快捷方式完成

    2. 右键属性修改快捷方式启动命令

    此时,启动该快捷方式,得到的就是一个新的vs

    到扩展里安装插件吧。

  • VSCode 使用docker-compose进行golang开发

    O 前言

    在网上搜索使用vscode 进行golang的docker配置,有大量的文章,在官网也有很详细的说明,但我就是看不明白!!

    自己搞了一晚上,总算把所有的坑填上了。记录一下,聊以自慰。

    一、 前置操作

    安装vscode 略

    安装golang 略

    golang使用module 模式而非 GOPATH, 略

    vscode 中安装 remote-containers 插件,略

    二、新建go 项目

    1. 创建文件夹 /golang/study.06, 并使用 vscode 打开。
    2. 新建main.go 我这里使用`
    package main
    
    import (
      "fmt"
      "log"
      "net/http"
    )
    
    func homepage(w http.ResponseWriter, r *http.Request) {
      // 显示内容
      fmt.Fprintf(w, "Hello golang http in docker!")
    }
    
    func main() {
      // 设置路由
      http.HandleFunc("/", homepage)
    
      // 启动web服务,监听 9090
      log.Fatel(http.ListenAndServe(":9090", nil))
    
    }
    
    1. 初始化模块
    # 初始化模块
    go mod init study06
    
    # 下载依赖模块
    go mod tidy
    
    
    1. 测试
    # 启动服务
    go run .
    
    

    在浏览器查看http://localhost:9090 ,可以看到效果。

    1. 文件目录
    study.06
    |-- go.mod
    |-- main.go
    

    三、添加docker-compose支持

    1. 添加模板

    执行 F1Remote-Containers: Add Development Container Configuration Files,依次选择 Godefaultlts(default)确定

    此时,添加了 .devcontainer/.devcontiner.json.devcontaier/Dockerfile两个文件。

    2. 使用docker-compose

    .devcontainer中添加docker-compose.yml,也可以多添加几个配置,如docker-compose.dev.yml

    # docker-compose.yml
    
    version: '3'
    
    services:
      study-06:
        build:
          context: .
          dockerfile: Dockerfile
          
    
    # docker-compose.dev.yml
    
    version: '3'
    
    services:
      study-06:
        build:
          context: .
          dockerfile: Dockerfile
        volumes:
          - ..:/workspace:cached
        ports:
          - 9090:9090
    
        cap_add:
          - SYS_PTRACE
    
        security_opt:
          - seccomp:unconfined
        
        command: /bin/sh -c "while sleep 1000; do :; done"
    
      
    
    
    

    3. 修改 devcontainer.json

    默认配置是使用Dockerfile的,修改devcontainer.json 以使用docker-compose

    // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
    // https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/go
    {
      "name": "Go",
      "dockerComposeFile" : [
        "docker-compose.yml",
        "docker-compose.dev.yml"
      ],
      "service" : "study-06",
      "workspaceFolder": "/workspace",
      "shutdownAction": "stopCompose",
      // "build": {
      //   "dockerfile": "Dockerfile",
      //   "args": {
      //     // Update the VARIANT arg to pick a version of Go: 1, 1.16, 1.17
      //     // Append -bullseye or -buster to pin to an OS version.
      //     // Use -bullseye variants on local arm64/Apple Silicon.
      //     "VARIANT": "1-bullseye",
      //     // Options
      //     "NODE_VERSION": "lts/*"
      //   }
      // },
      // "runArgs": [ "--cap-add=SYS_PTRACE", "--security-opt", "seccomp=unconfined" ],
    
      // Set *default* container specific settings.json values on container create.
      "settings": {
        "go.toolsManagement.checkForUpdates": "local",
        "go.useLanguageServer": true,
        "go.gopath": "/go",
        "go.goroot": "/usr/local/go"
      },
    
      // Add the IDs of extensions you want installed when the container is created.
      "extensions": [
        "golang.Go"
      ],
    
      // Use 'forwardPorts' to make a list of ports inside the container available locally.
      // "forwardPorts": [],
    
      // Use 'postCreateCommand' to run commands after the container is created.
      // "postCreateCommand": "go version",
    
      // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
      "remoteUser": "vscode"
    }
    
    

    4. 修改Dockerfile

    最后添加 Expose 9090 绑定端口

    5. 在容器中打开文件夹

    F1 执行 Open Folder in Container,选择 study.06目录,此时vscode会编译并运行镜像,进入镜像中的环境。

    执行 go run .,就可以在 http://localhost:9090 中看到结果了。

    6. 更新

    如果对docker文件进行任何修改后,可以执行 F1 -> Rebuild 重新生成镜像