Posts tagged ‘version control systems’

One Thing that Git Does Better: Rebranching

2013-05-04 0:06

Much can be said about similarities between two popular, distributed version control systems: Git and Mercurial. For the most part, choosing between them can be a matter of taste. And because Git seems to have considerably more proponents in the Cool Kids camp, it doesn’t necessarily follow it’s a better option.

But I have found at least one specific and common scenario where Git clearly outshines Hg. Suppose you have coded yourself into a dead end: the feature you planned doesn’t pan out the way you wanted it; or you have some compatibility issues you cannot easily resolve; or you just need to escape the refactoring bathtub.

Rebranching in Git (start)

In any case, you just want to step back a few commits and pretend nothing happened, for now. The mishap might be useful later, though, so it’d be nice if we left it marked for the future.

In Git, this is easily done. You would start by creating a new branch that points to your dead end:

  1. $ git checkout my_feature
  2. $ git branch __my_feature__dead_end__

Afterwards, both my_feature and __my_feature__dead_end__ refer to the same, head commit. We would then move the former a little back, sticking it to one of the earlier hashes. Let’s find a suitable target:

  1. $ git log
  2. commit 130fe41a3a0587a48c1ef8797030ae2e682c6fb4
  3. Author: John Doe <>
  4. Date:   Fri May 3 21:39:32 2013 +0200
  6.     I don't like this adventure. Not one bit.
  8. commit f834a10d199f5c23fa14ed0ebfcf89226d9c21a1
  9. Author: John Doe <>
  10. Date:   Fri May 3 21:25:46 2013 +0200
  12.     Let's try this, maybe...
  14. commit 9d877d32f3a08f416615f9a051ad3985e6e4d2ad
  15. Author: John Doe <>
  16. Date:   Fri May 3 21:18:57 2013 +0200
  18.     Shiny!
  19. $ git checkout 9d877
  20. Note: checking out '9d877'.
  21. # trimmed for brevity

If it looks right, we can reset the my_feature branch so it points to this specific commit:

  1. $ git reset --hard 9d877

Our final situation would then looks like this:

Rebranching in Git (end)

which is exactly what we wanted. Note how any further commits starting from the referent of my_feature would fork at that point, diverging from development line which has lead us into dead end.

Why the same thing is not so easily done in Mercurial?… In general, this is mostly because of its one fundamental design decision: every commit belongs to one branch, forever and for always. Branch designation is actually part of the changeset’s metadata, just like the commit message or diff. Moving things around – like we did above – is therefore equivalent to changing history and requires tools that are capable of doing so, such as hg strip.

Tags: , , ,
Author: Xion, posted under Programming » 5 comments

Disjoint Branches in Git

2011-12-30 12:18

Great services like GitHub encourage to share projects and collaborate on them publicly. But not every piece of code feels like it deserves its own repository. Thus it’s quite reasonable to keep a “miscellaneous” repo which collects smaller, often unrelated hacks.

But how to set up such a repository and what structure should it have? Possible options include separate branches or separate folders within single branch. Personally, I prefer the former approach, as it keeps both the commit history and working directory cleaner. It also makes it rather trivial to promote a project into its own repo.
I speak from experience here, since I did exactly this with my repository of presentation slides. So far, it serves me well.

It’s not hard to arrange a new Git repository in such manner. The idea is to keep the master branch either completely empty, or only store common stuff there – such as a README file:

  1. $ git init
  2. $ echo "This is my repo with miscellaneous hacks." > README
  3. $ git add . && git commit -m "Initial commit"

The actual content will be kept in separate branches, with no relation to each other and to the master one. Such entities are sometimes referred to as root branches. We create them as usual – for example via git checkout:

  1. $ git checkout -b foo

However, this is not nearly enough. We don’t want to base the new branch upon the content from master, but we still have it in the working directory. And even if we were to clean it up manually (using a spell such as ls | xargs rm -r to make sure the .git subdirectory is preserved), the removal would have to be registered as a commit in the new branch. Certainly, it would go against our goal to make it independent from master.

But the working copy is just one thing. In order to have truly independent, root branch we also need to disconnect its history from everything else in the repo. Otherwise, any changesets added before the branch was created would carry over and appear in its log.
Fortunately, making the history clear is very easy – although somewhat scary. We need to reach out to internal .git directory and remove the index file:

  1. $ rm .git/index

Don’t worry, this doesn’t touch any actual data, which is mostly inside .git/objects directory. What we removed is a “table of contents” for current branch, making it pristine clear – just like the master right after git init.

As a nice side effect, the whole content of working directory is now unknown to Git. Once we removed the index, every file and directory has became untracked. Now it’s possible to remove all of them in one go using git clean:

  1. $ git clean -xdf

And that’s it. We now have a branch that has nothing in common with rest of the repository. If we need more, we can simply repeat those three steps, starting from a clean working copy (not necessarily from master branch).

Coded4: Time-based Statistics for Git/Hg Repos

2011-12-24 16:23

As the ubiquitous spirit of laziness relaxation permeates the holiday season, a will to do any serious and productive coding seems appallingly low. Instead of fighting it, I went along and tried to write something just for pure fun.

And guess what: it worked pretty well. Well enough, in fact, that the result seems to be worthy of public exposure – which I’m hereby doing. Behold the coded4 project:

  1. $ git clone
  2. $ coded4 jquery

  1. name                   commits time        
  2. -------------------------------------------
  3. John Resig             1211    5d 09:11:59
  4. jeresig                503     2d 07:50:02
  5. Jörn Zaefferer         309     1d 09:05:53
  6. Brandon Aaron          247     1d 01:34:29
  7. Dave Methvin           235     22:17:27    
  8. jaubourg               221     22:22:31    
  9. timmywil               221     23:00:56    
  10. Ariel Flesler          200     22:10:46    
  12. ...

What exactly is this thing? It’s a “time sheet” for the marvelous jQuery project, reconstructed from commit timestamps in its Git repository. coded4 created this result by analyzing repo’s history, grouping changesets by contributors, and running some heuristics to approximate timespans of their coding sessions.

And of course, this can be done for any Git (or Hg) repository. Pretty neat for a mere *pops up shell and types coded4 .* 3 hours of casual coding, eh?

Terminologia rozproszonych systemów kontroli wersji

2011-06-06 19:31

W ostatnich latach rozproszone systemy kontroli wersji (w skrócie DVCS) stały się popularne, zwłaszcza w środowiskach związanych z open source. Warto je jednak znać nie tylko wtedy, gdy pracujemy nad projektami z otwartym źródłem. Jak bowiem pisałem wcześniej, mogą być one przydatne chociażby do małych jednoosobowych projektów. Ponadto bywają nierzadko używane w większych oraz mniejszych firmach. Ogólnie mamy więc duże szanse, aby prędzej lub później zetknąć się z takimi systemami.
Ten post jest adresowany przede wszystkim do osób, które nie miały wcześniej dłuższej styczności rozproszonymi systemami kontroli wersji. Ma on na celu wyjaśnienie wielu spośród tych tajemniczo brzmiących słówek, na jakie nieustannie można się natknąć, gdy pracujemy z DVCS-ami. Istnieje oczywiście szansa, że bardziej zaawansowani użytkownicy również wyciągną nowe wiadomości z lektury (albo chociaż przejrzenia) niniejszej notki. A jeśli nawet nie, to powtórzenie znanej sobie wiedzy na pewno im nie zaszkodzi ;)

Tags: , ,
Author: Xion, posted under Applications, Programming » 3 comments

Duże i małe commity

2011-01-29 23:49

Mam ciekawą obserwację związaną ze sposobem używania różnych systemów kontroli wersji. Dokładniej mówiąc, chodzi o dość wyraźną różnicę w częstotliwości commitów między zwykłymi a rozproszonymi VCS-ami. Do tych pierwszych kod commituje się stosunkowo rzadko, ponieważ każda zmiana jest od razu widoczna w publicznym repozytorium. To ma zaś daleko idące konsekwencje, jak choćby natychmiastowa dostępność naszych modyfikacji dla innych osób pracujących nad projektem. Dlatego też trzeba starać się, aby nie wypuścić bubla. Minimalnym wymaganiem jest kompilowalność commitowanego kodu, a dobrze by było, żebyśmy też poddali go choćby wstępnemu testowaniu.

Gdy z kolei pracujemy z rozproszonymi systemami kontroli wersji, możemy teoretycznie robić dokładnie tak samo. Wówczas jednak nie tylko nie korzystamy z faktu posiadania lokalnego repozytorium, ale wręcz dodajemy sobie pracy. Osiągnięcie tego samego efektu (upublicznienia zmian) wymaga bowiem dwóch kroków – dodatkowym jest push, czyli synchronizacja z globalną bazą kodu. Będąc przyzwyczajonym do scentralizowanych VCS-ów można łatwo o nim zapomnieć.
Dlatego też wydaje mi się, że przy systemie rozproszonym warto nieco zmienić nawyki. Commitów można bowiem dokonywać częściej – znacznie częściej. Ponieważ żaden z nich nie wydostaje się automatycznie poza nasz komputer, nie muszą one dodawać kompletnych funkcjonalności albo w pełni poprawiać znalezione wcześniej błędy. Nie muszą działać. Ba, w zasadzie to nie muszą nawet się kompilować. Grunt, żeby zawierały modyfikacje, które wydają nam się warte zachowania i opatrzenia komentarzem. W praktyce w ciągu dnia można w ten sposób wykonać nawet do kilkudziesięciu commitów – w porównaniu do dwóch lub trzech w przypadku pracy z system scentralizowanym.

Czy taka częstotliwość dobrze wpływa na efektywność kodowania? Z początku nie byłem o tym przekonany, ale teraz widzę, że ma ona niewątpliwe zalety. Wykonując częste commity (a zwłaszcza opisując je), programujemy w sposób bardziej zdyscyplinowany. Trochę trudniej jest wtedy napisać wysublimowany, barokowo skomplikowany i ogólnie przekombinowany moduł albo takąż klasę. Mamy raczej większe szanse na to, że poczynimy jakieś realne postępy w pracy nad projektem. Dodatkowo częste “odhaczanie” wykonanych zadań i poczynionych postępów (nawet jeśli są bardzo drobne) jest bardziej motywujące niż oznaczanie zmian rzadkich a duże.
A co jeśli naszą przeszkodą w wykonywaniu częstych commitów jest brak weny twórczej odnośnie komentarzy do nich?… No cóż, wtedy zawsze można poszukać inspiracji tutaj ;-)

Tags: ,
Author: Xion, posted under Programming, Thoughts » 5 comments

Nie tylko pisanie kodu

2011-01-21 19:25

Gdyby było to fizycznie możliwe, chętnie przeprowadziłbym następujący eksperyment. Z odległej przeszłości – na przykład z połowy lat 90. poprzedniego stulecia – sprowadziłbym w obecne czasy dowolnego ponadprzeciętnie uzdolnionego programistę. Jak szybko odnalazłby się we współczesnym koderskim środowisku pracy?… W celu redukcji złożoności problemu poczyńmy daleko idące uproszczenia i pomińmy wszelkiego typu zmiany związane z postępem technologicznym (jak choćby nieporównywalnie większe znaczenie Internetu wtedy i teraz), a także modyfikacje, które zachodzą w samych językach programowania. Interesuje mnie raczej to, czy ów przybysz z przeszłości doceniłby i uznał za przydatne różnego rodzaju czynności i narzędzia pomocnicze, niebędące edytorem tekstu (lub IDE) ani kompilatorem, i pozostające w luźniejszym związku z samym pisaniem kodu jako takiego.

Jakby bowiem przyjrzeć się dokładnie wachlarzowi tych narzędzi, okazuje się, że jest on już całkiem szeroki. Programowanie, zwłaszcza zespołowe (jeżeli w ogóle istnieje jeszcze jakieś inne) już od dawna przestało ograniczać do tworzenia kodu i czasami wydaje się nawet, że czynność ta stała się poboczną. Coraz więcej czasu zajmuje praca z takimi narzędziami jak systemy kontroli wersji, systemy śledzenia błędów (issue tracking systems), narzędzia automatyzujące proces kompilacji, programy do statycznej analizy kodu, systemy zdalnej kompilacji i pewnie mnóstwo jeszcze innych wynalazków, z którymi nie miałem dotąd okazji się zetknąć.
Między innymi dlatego nie potrafię jednoznacznie określić, czy uważam je wszystkie raczej za przydatne czy raczej za zbędne. Wiążące opinie mogę jak dotąd wyrazić tylko o niektórych.

Tym niemniej ciekawi mnie również, czy w dziedzinie wspomagania kodowania (czy ogólnie pracy nad projektami) od strony zautomatyzowanych narzędzi da się wymyślić coś jeszcze…

Rozproszone systemy kontroli wersji

2010-10-20 23:10

Z systemami kontroli wersji (w skrócie VCS) zetknął się każdy programista i dla niemal wszystkich jest to oczywiste narzędzie pracy. Dla wielu jednak wciąż jeszcze kojarzą się one z jednym, centralnym miejscem zawierającym zawierającym bazę kodu projektu (czyli repozytorium) oraz z licznymi kopiami roboczymi, nad którymi pracują programiści. Kiedy zaś chcą połączyć swoje zmiany, wówczas wykonują tylko operację znaną jako commit.

Tak jest w systemach typu CVS czy Subversion, ale obecnie sporą popularność zyskały też inne, działające na nieco innej zasadzie. Nazywają się one rozproszonymi (distributed version control system – DVCS) i zgodnie z tym określeniem ich główną cechą jest brak wydzielonego, centralnego repozytorium. Zamiast tego może być ich dowolna ilość, która w rzeczywistych projektach może łatwo urosnąć do setek, a nawet tysięcy. Najczęściej bowiem swoje własne repozytorium ma na przykład… każdy pracujący nad projektem programista.
Obłęd? Niezupełnie. Wszystko opiera się bowiem na operacji synchronizacji dwóch repozytoriów, którą nazywa się – w zależności od punktu widzenia – push lub pull. Push oznacza wprowadzenie poprawek z naszego repozytorium do innego, zaś pull oznacza ściągnięcie zmian z innego repozytorium do własnego. Jak nietrudno zauważyć, operacja ta jest symetryczna. I chociaż techniczne wszystkie repozytoria są równoważne, w praktyce jedno z nich jest zwykle bazą projektu, zawierającą jego “autorytatywną” wersję. Ponadto z każdym repozytorium można też pracować “normalnie”, tj. przy pomocy znanych i lubianych operacji commit i update.

Działanie rozproszonych systemów kontroli wersji

Po co taka zmiana? Przydaje się ona zwłaszcza w dwóch sytuacjach:

  • Dla projektów typu open source umożliwia względnie niezależne opracowywanie poprawek do projektów. W tym celu wystarczy sklonować główne repozytorium, a następnie w spokoju pracować nad uzyskanym kodem, korzystając z jego kopii. Chcąc następie uczynić zmiany obowiązującymi, możemy wykonać push – ale tylko wtedy, jeśli mamy do tego prawa. Jeśli nie, możliwe jest stworzenie łatki (patch), zawierającej nasze modyfikacje i przekazania jej osobie zarządzającej projektem. Ta zaś może – zapewne po przetestowaniu zmian na własnej kopii repozytorium – wprowadzić je wreszcie do bazy kodu. Podobny akceptowania poprawek występował w projektach open source już od dawna, ale dopiero rozproszone systemy kontroli wsparły go od strony technicznej.
  • Jeśli pracujemy wyłącznie lokalnie nad własnymi projektami, możemy stworzyć sobie takież repozytorium, które będzie przy tym jedynym. Nie synchronizujemy wtedy zmian z żadnym innym repozytorium, ale wciąż możemy korzystać ze standardowych funkcjonalności systemów kontroli wersji.

W średniej skali (takiej, jak przedstawiona na obrazku powyżej) systemy rozproszone sprawdzają się natomiast nieco gorzej – zwłaszcza, gdy częstotliwość zmian jest duża. Wówczas często zachodzi potrzeba łączenia (merge) różnych ścieżek tworzenia aplikacji.

Tym niemniej warto się zainteresować tego rodzaju systemami kontroli wersji, by przekonać się, że poza Subversion też coś istnieje :) Przykładami rozproszonych VCS-ów są np. Mercurcial i Git.

Tags: , , , ,
Author: Xion, posted under Applications, Programming » 3 comments

© 2023 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with