
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:
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.
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.
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
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.
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
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 -- .
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.
Jeżeli wsystko jest poprawnie to pozostaje nam wykonać aktualizacje
zdalnego repozytorium a atrybutem force.
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.