Aby chronić nadgarstki postanowiłem korzystać z poruszania kursorem pod windowsami za pomocą klawiszy H, J, K, L, podobnie jak ma to miejsce w Vim. Klawiszem dodatkowym miał być LWin. Niestety począwszy od Visty LWin + L powoduje lock screen. Nie da się nadpisać tej kombinacji przy użyciu AutoHotkey. Aby temu zaradzić postanowiłem zmienić miejscami klawisze Context Key z LWin przy użyciu programu KeyTweak. Program ten nie jest rezydentny a jedynie modyfikuje rejestry. Teraz wystarczy wprowadzić małe zmiany w skrypcie AutoHotkey.

;Map to left arrow or ctrl left arrow
AppsKey & h::
GetKeyState, state, shift, P
if state = D
send, ^{left}
else
send, {left}
return

;Map to right arrow or ctrl right arrow
AppsKey & l::
GetKeyState, state, shift, P
if state = D
send, ^{right}
else
send, {right}
return

;Map to up arrow
AppsKey & k::
GetKeyState, state, shift, P
if state = D
send, {shift}+{up}
else
send, {up}
return

;Map to down arrow
AppsKey & j::
GetKeyState, state, shift, P
if state = D
send, {shift}+{down}
else
send, {down}
return

Moje ustawienia dla AutoHotkey zawsze można znaleźć aktualne na moim GitHub repository.

W projekcie nad którym pracuje korzystam z biblioteki Rhino.Mocks w wersji 3.5. Projekt ten jest napisany dla NET 2.0 przy użyciu Visual Studio 2005. Przejscie na Visual Studio 2008 nie sprawiało żanych problemów. Czas przyszedł na Visual Studio 2010. I pojawił się problem w postaci ostrzeżenia:

Warning 4 The primary reference “Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f, processorArchitecture=MSIL” could not be resolved because it has an indirect dependency on the framework assembly “System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″ which could not be resolved in the currently targeted framework. “.NETFramework,Version=v2.0″. To resolve this problem, either remove the reference “Rhino.Mocks, Version=3.5.0.1337, Culture=neutral, PublicKeyToken=0b3305902db7183f, processorArchitecture=MSIL” or retarget your application to a framework version which contains “System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089″.

(więcej…)

Powstało wiele opisów jak importować repozytoria z svn do git. Niestety żaden z nich nie uwzględnia dosyć istotnej rzeczy, zakończenia lini tekstu. Domyślnie, repozytoria svn przechowują pliki w taki sposób jak są one wprowadzone. W wiekszości sytuacji nie stanowi to żadnego problemu gdy nasze projekty są rozwijane przy użyciu jednego typu platformy np. Windows. W takim wypadku zakończenie lini tekstu we wszystkich plikach tekstowych to CRLF. Co jednak zrobić z projektem, który jest rozwijany na wielu typach platform np. za pomocą mono na Linux-ie? Może dojść do niezłego bałaganu. Część plików w repozytorium może mieć zakończenia CRLF a część LF. Podkreślam w repozytorium. Jeżeli mamy ustawione props svn:eol-style jako native, wówczas klient svn automatycznie przekonwertuje na aktualny typ systemu. Teoretycznie wszystko jest w najlepszym porzadku. Problem pojawia się gdy importujemy takie repozytorium do git. Taki problem mają własnie programiści projektu Castle. Opisują to w wątku Git line endings ale o tym za chwilę.

Repozytoria git zachowują się podobnie. Przyjmują pliki tak jak są one dostarczone. Jednak ogólnie przyjęło się aby zakończenia dla plików tekstowych w repozytorium były zawsze LF. Aby uzyskać taki efekt, klienci Windows powinni mieć ustawiony atrybut core.autocrlf=true (domyślne ustawienie dla msysgit). Atrybut ten powoduje konwersję w locie, w trakcie commit z CRLF na LF oraz w trakcie checkout z LF na CLRF. Dzięki temu na Windows wszystkie tekstowe pliki robocze będą miały zakończenia CRLF, a na Linux LF.

W trakcie importu z svn do git poszczególne commity są zapisywane w git z tymi samymi końcówkami co były wprowadzane do svn. Jeżeli ktoś teraz sklonuje takie repozytorium oraz będzie miał ustawiony atrybut core.autoclrf=true wówczas wszystkie pliki tekstowe zostaną traktowane jako zmodyfikowane, gdyz zgodnie z atrybutem, git będzie chciał zmienić zakończenia z CRLF na LF. Znalazlem dwa rozwiązania:

  1. Rozwiązanie proponowane przez GitHub jest przedstawione na stronie Dealing with line endings. Polega ono na stworzeniu jednego commitu zmieniającego koncówki z CRLF na LF dla wszystkich plików tekstowych. Dzięki temu mamy sytuacje znormalizowaną jednak tracimy zalety blame.

  2. Zespół programistów Castle proponują wykorzystanie atrybutów w celu wymuszenia stosowania końcówek CLRF zarówno na platformie Windows jak i Linux. Wiąże się to z ustawieniem core.autocrlf=false na ssytemie Windows dla danego repozytorium Nastepnie wystarczy stworzyć plik .gitattributes z zawartością:

    *.cs crlf diff
    *.csproj crlf diff
    *.xml crlf diff

Powyższe rozwiązania można zastosować kiedy już istnieją forks do naszego repozytorium. Alternatywną drogą jest “przepisanie” wszystkich commit-ów tuż po imporcie z svn. Modyfikacja historii wiąże się z brakiem integralności forków, które zostały utworzone przed modyfikacją. Dlatego zalecam wykonanie tego od razu po imporcie. Aby lepiej przedstawić poszczególne kroki posłużę się faktycznym przykładem importu repozytorium svn z google code rod.commons do GitHub.

  1. Po stworzeniu nowego repozytorium, importujemy kod z svn oraz klonujemy go lokalnie. Komenda git st zapewne pokaże nam, że wszystkie pliki tekstowe są zmodyfikowane. Wyłączamy autoclrf dla lokalnego repozytorium

    git config core.autocrlf false
  2. Za pomocą git filter-branch modyfikujemy historię zmian. Zanim to nastąpi należy pobrać skrypt changeLineEndings.sh, który za pomocą dos2unix przekonwertuje zakończenia lini w plikach tekstowych na LF. Przed wykonaniem należy sie upewnić czy skrypt posiada poprawne definicje plików tekstowych. W razie portrzeby dopisać swoje. Teraz można wykonać polecenie z uwzględenieniem ścieżki do pliki changeLineEndings.sh.

    git filter-branch --tree-filter '/pathTo/changeLineEndings.sh' -- --all

    Komendę te wykonujemy spod msysygitowego bash-a.

  3. Nasze repozytorium zawiera teraz dwie wersje historii zmian. Oryginalną oraz tę przed chwilą przepisaną ze zmienionymi zakończeniami linii. Oryginalną można już usunąć zgodnie z dokumentacją do git filter-branch.

    git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
    git reflog expire --expire=now --all
    git gc --prune=now
  4. Teraz wykasujmy nasze wszystkie working files, ustawmy poprawnie autoclrf oraz zróbmy przywrócenie plików.

    git ls-files -z | xargs -0 rm
    git config core.autocrlf true
    git checkout -- .
  5. Jeżeli po wykonaniu komendy git status są pliki zmodyfikowane to zapewne zostały one pominięte przez skrypt changeLineEndings.sh. Dopiszmy rozszerzenia tych plików do skryptu i wykonajmy jeszcze raz dokładnie kroki od 1 do 4.

  6. Jeżeli wsystko jest poprawnie to pozostaje nam wykonać aktualizacje zdalnego repozytorium a atrybutem force.

    git push -f

    Jeżeli akutalizacja się nie powiodła z komunikatem error: denying non-fast forward refs/heads/master (you should pull first). Wówczas należy ustawić denyNonFastforwards w pliku config po stronie repozytorium na false.

Do aktualnego projektu wykorzystuje klasę DateRange z biblioteki MindLib. Klasa ta definiuje w łatwy sposób okres czasu oraz metody do manipulacji okresem. Biblioteka posiada również klasę DateRangeUserType do definicji typu dla NHibernate. Klasa ta dziedziczy pośrednio po ICompositeUserType. Domyślnie na ten typ składają sie dwie kolumny w tabeli bazy danych:

private string[] propertyNames = new string[] {"Start", "End"};
private IType[] propertyTypes = new IType[] {NHibernateUtil.DateTime, NHibernateUtil.DateTime};

Co jeżeli chcielibyśmy wykorzystać dwa razy typ DateRange w naszej encji ? Należy wówczas dla każdego property zdefiniować parę kolumn o różnych nazwach. W pliku mapowania NHibernate wyglądałoby to tak:

<property name="Period"
   type="MindHarbor.TimeDataUtil.DateRangeUserType,MindHarbor.TimeDataUtil">
    <column name="RangeStart"/>
    <column name="RangeEnd" />
</property>

… a za pomocą Fluent NHibernate tak:

mapping.Map(x => x.Period).CustomType<DateRangeUserType>()
    .Columns.Add("RangeStart", "RangeEnd");

Niestety to spowoduje błąd mówiący o tym że za dużo jest kolumn zdefiniowanych dla typu DateRangeUserType. Okazuje się że autorzy Fluent NHibernate automatycznie definiują kolumny dla mapowań implementujących ICompositeUserType:

/// <summary>
/// Specifies that a custom type (an implementation of <see cref="IUserType"/>)
/// should be used for this property for mapping it to/from one or more database
/// columns whose format or type doesn't match this .NET property.
/// </summary>
/// <param name="type">A type which implements <see cref="IUserType"/>.</param>
/// <returns>This property mapping to continue the method chain</returns>
public PropertyPart CustomType(Type type)
{
    if (typeof(ICompositeUserType).IsAssignableFrom(type))
        AddColumnsFromCompositeUserType(type);

    return CustomType(TypeMapping.GetTypeString(type));
}

-- Cut--

private void AddColumnsFromCompositeUserType(Type compositeUserType)
{
    var inst = (ICompositeUserType)Activator.CreateInstance(compositeUserType);

    foreach (var name in inst.PropertyNames)
    {
        Columns.Add(name);
    }
}

Zatem należy wykasować automatycznie stworzone kolumny a dopiero potem zdefiniować własne.

mapping.Map(x => x.Period).CustomType<DateRangeUserType>()
    .Columns.Clear()
    .Columns.Add("RangeStart", "RangeEnd");

Jeżeli używacie dysku systemowego (zazwyczaj C: ) do przechowywania swoich wirtualnych maszyn, to możecie odczuwać pewne spowolnienie podczas operacji dyskowych wewnątrz systemu “gościa”. Okazuje się że wasz plik *.vhd będzie ciągle backupowany przez shadow copy. Jednym z rozwiązań jest wyłączenie “System Restore”, ale ja tego nie polecam. Zamiast tego możemy zrobić – Excluding files from Shadow Copy. To samo może tyczyć się innych plików, których snapshotów nie chcemy przetrzymywać. U mnie wpisy wykluczeń w rejestrach wyglądają tak:

$AllVolumes$\VirtualPC\*.* /s
C:\Downloads\*.* /s
$UserProfile$\Downloads\*.* /s

Update: Po restarcie komputera zdarzyło mi się nadal VirtualPC.exe zapisywał coś do katalogu “System Volume Information”. Dopiero opróżnienie dotychczasowych “restore points” wyeliminowało problem. Być może system w tym katalogu ma nadal zapisane, które pliki ma brać pod uwagę w Shadow Copy.

Calendar

wrzesień 2014
P W Ś C P S N
« stycznia    
1234567
891011121314
15161718192021
22232425262728
2930  

Copyright © 2014 - Greg Johnson