From dd6488cbb96a276303e47e7c515c988b0f3b1859 Mon Sep 17 00:00:00 2001 From: Jean-Noel Avila Date: Fri, 30 Aug 2013 23:07:34 +0200 Subject: [PATCH 001/478] enable parallel check of languages Use parallel to spawn as many subprocesses as possible to accelerate the tests. --- Gemfile | 2 +- Rakefile | 127 ++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 80 insertions(+), 49 deletions(-) diff --git a/Gemfile b/Gemfile index 79f6c3029..aa6b79223 100644 --- a/Gemfile +++ b/Gemfile @@ -2,4 +2,4 @@ source 'https://rubygems.org' gem 'maruku', '0.6.1' gem 'redcarpet' -gem 'rdiscount' +gem 'parallel' diff --git a/Rakefile b/Rakefile index 03c0bb9e7..836f5044b 100644 --- a/Rakefile +++ b/Rakefile @@ -168,7 +168,78 @@ class StderrDecorator end end +def test_lang(lang) + error_code = false + chapter_figure = { + "01-introduction" => 7, + "02-git-basics" => 2, + "03-git-branching" => 39, + "04-git-server" => 15, + "05-distributed-git" => 27, + "06-git-tools" => 1, + "07-customizing-git" => 3, + "08-git-and-other-scms" => 0, + "09-git-internals" => 4} + mark = '' + source_files = FileList.new(File.join(lang, '0*', '*.markdown')).sort + source_files.each do |mk_filename| + mk_file = File.open(mk_filename, 'r') do |mk| + mark+= mk.read.encode("UTF-8") + end + src_file = File.open(mk_filename, 'r') + figure_count = 0 + until src_file.eof? + line = src_file.readline + matches = line.match /^#/ + if matches + if line.match /^(#+).*#[[:blank:]]+$/ + print "\nBadly formatted title in #{mk_filename}: #{line}\n" + error_code = true + end + end + if line.match /^\s*Insert\s(.*)/ + figure_count = figure_count + 1 + end + end + # This extraction is a bit contorted, because the pl translation renamed + # the files, so the match is done on the directories. + tab_fig_count = chapter_figure[File.basename(File.dirname(mk_filename))] + expected_figure_count = tab_fig_count ? tab_fig_count:0 + if figure_count > expected_figure_count + print "\nToo many figures declared in #{mk_filename}\n" + error_code = true + end + end + begin + require 'maruku' + code = Maruku.new(mark, :on_error => :raise, :error_stream => StderrDecorator.new) + rescue + print $! + error_code = true + end + error_code +end + namespace :ci do + desc "Parallel Continuous integration" + task :parallel_check do + require 'parallel' + langs = FileList.new('??')+FileList.new('??-??') + results = Parallel.map(langs) do |lang| + Rake::Task["ci:" +lang+"_check"].execute + 0 + end + fail "At least one language conversion failed" if results.any? { |result| result!=0} + end + + (FileList.new('??')+FileList.new('??-??')).each do |lang| + desc "testing " + lang + task (lang+"_check").to_sym do + error_code = test_lang(lang) + fail "processing #{lang} KO\n" if error_code + print "processing #{lang} OK\n" + end + end desc "Continuous Integration" task :check do @@ -184,59 +255,19 @@ namespace :ci do end langs -= excluded_langs end - error_code = false - chapter_figure = { - "01-introduction" => 7, - "02-git-basics" => 2, - "03-git-branching" => 39, - "04-git-server" => 15, - "05-distributed-git" => 27, - "06-git-tools" => 1, - "07-customizing-git" => 3, - "08-git-and-other-scms" => 0, - "09-git-internals" => 4} + global_error_code = false langs.each do |lang| print "processing #{lang} " - mark = '' - source_files = FileList.new(File.join(lang, '0*', '*.markdown')).sort - source_files.each do |mk_filename| - mk_file = File.open(mk_filename, 'r') do |mk| - mark+= mk.read.encode("UTF-8") - end - src_file = File.open(mk_filename, 'r') - figure_count = 0 - until src_file.eof? - line = src_file.readline - matches = line.match /^#/ - if matches - if line.match /^(#+).*#[[:blank:]]+$/ - print "\nBadly formatted title in #{mk_filename}: #{line}\n" - error_code = true - end - end - if line.match /^\s*Insert\s(.*)/ - figure_count = figure_count + 1 - end - end - # This extraction is a bit contorted, because the pl translation renamed - # the files, so the match is done on the directories. - tab_fig_count = chapter_figure[File.basename(File.dirname(mk_filename))] - expected_figure_count = tab_fig_count ? tab_fig_count:0 - if figure_count > expected_figure_count - print "\nToo many figures declared in #{mk_filename}\n" - error_code = true - end - end - begin - code = Maruku.new(mark, :on_error => :raise, :error_stream => StderrDecorator.new) - print "OK\n" - rescue + error_code=test_lang(lang) + if error_code print "KO\n" - print $! - error_code = true + else + print "OK\n" end + global_error_code|=error_code + end - fail "At least one language conversion failed" if error_code + fail "At least one language conversion failed" if global_error_code end end From e36c02acad6d7fd7ab356f90842ad17ac1c3d9e8 Mon Sep 17 00:00:00 2001 From: Jean-Noel Avila Date: Sun, 27 Oct 2013 11:50:11 +0100 Subject: [PATCH 002/478] Change Maruku check to fully functional mode this is cleans up the code. --- Rakefile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Rakefile b/Rakefile index 836f5044b..7d3039367 100644 --- a/Rakefile +++ b/Rakefile @@ -180,12 +180,8 @@ def test_lang(lang) "07-customizing-git" => 3, "08-git-and-other-scms" => 0, "09-git-internals" => 4} - mark = '' source_files = FileList.new(File.join(lang, '0*', '*.markdown')).sort source_files.each do |mk_filename| - mk_file = File.open(mk_filename, 'r') do |mk| - mark+= mk.read.encode("UTF-8") - end src_file = File.open(mk_filename, 'r') figure_count = 0 until src_file.eof? @@ -211,6 +207,8 @@ def test_lang(lang) end end begin + mark = (source_files.map{|mk_filename| File.open(mk_filename, 'r'){ + |mk| mk.read.encode("UTF-8")}}).join('') require 'maruku' code = Maruku.new(mark, :on_error => :raise, :error_stream => StderrDecorator.new) rescue From cc1d0d6ace74ea67222d5684997e2d6932c2748a Mon Sep 17 00:00:00 2001 From: Jean-Noel Avila Date: Wed, 30 Oct 2013 22:44:32 +0100 Subject: [PATCH 003/478] Force output of Rake messages to stderr --- Rakefile | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/Rakefile b/Rakefile index 7d3039367..8e8f9eac3 100644 --- a/Rakefile +++ b/Rakefile @@ -160,15 +160,19 @@ namespace :pdf do end class StderrDecorator + def initialize(out) + @out = out + end + def <<(x) - $stderr<< "#{x}" + @out << "#{x}" if x.match /REXML/ raise "" end end end -def test_lang(lang) +def test_lang(lang, out) error_code = false chapter_figure = { "01-introduction" => 7, @@ -189,7 +193,7 @@ def test_lang(lang) matches = line.match /^#/ if matches if line.match /^(#+).*#[[:blank:]]+$/ - print "\nBadly formatted title in #{mk_filename}: #{line}\n" + out<< "\nBadly formatted title in #{mk_filename}: #{line}\n" error_code = true end end @@ -202,7 +206,7 @@ def test_lang(lang) tab_fig_count = chapter_figure[File.basename(File.dirname(mk_filename))] expected_figure_count = tab_fig_count ? tab_fig_count:0 if figure_count > expected_figure_count - print "\nToo many figures declared in #{mk_filename}\n" + out << "\nToo many figures declared in #{mk_filename}\n" error_code = true end end @@ -210,7 +214,7 @@ def test_lang(lang) mark = (source_files.map{|mk_filename| File.open(mk_filename, 'r'){ |mk| mk.read.encode("UTF-8")}}).join('') require 'maruku' - code = Maruku.new(mark, :on_error => :raise, :error_stream => StderrDecorator.new) + code = Maruku.new(mark, :on_error => :raise, :error_stream => StderrDecorator.new(out)) rescue print $! error_code = true @@ -218,22 +222,29 @@ def test_lang(lang) error_code end +$out = $stdout + namespace :ci do desc "Parallel Continuous integration" task :parallel_check do require 'parallel' langs = FileList.new('??')+FileList.new('??-??') results = Parallel.map(langs) do |lang| - Rake::Task["ci:" +lang+"_check"].execute - 0 + error_code = test_lang(lang, $out) + if error_code + print "processing #{lang} KO\n" + else + print "processing #{lang} OK\n" + end + error_code end - fail "At least one language conversion failed" if results.any? { |result| result!=0} + fail "At least one language conversion failed" if results.any? end (FileList.new('??')+FileList.new('??-??')).each do |lang| desc "testing " + lang task (lang+"_check").to_sym do - error_code = test_lang(lang) + error_code = test_lang(lang, $out) fail "processing #{lang} KO\n" if error_code print "processing #{lang} OK\n" end @@ -253,19 +264,17 @@ namespace :ci do end langs -= excluded_langs end - global_error_code = false - langs.each do |lang| + errors = langs.each do |lang| print "processing #{lang} " - error_code=test_lang(lang) + error_code=test_lang(lang, $out) if error_code print "KO\n" else print "OK\n" end - global_error_code|=error_code - + error_code end - fail "At least one language conversion failed" if global_error_code + fail "At least one language conversion failed" if errors.any? end end From 33b648fd1a1c1883a5b02e5856e8e34acf4776ac Mon Sep 17 00:00:00 2001 From: Petr Prikryl Date: Sun, 5 Jan 2014 19:42:17 +0100 Subject: [PATCH 004/478] [cs] Typos and formulation changes in Ch. 1 up to 1.3 included. --- cs/01-introduction/01-chapter1.markdown | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/cs/01-introduction/01-chapter1.markdown b/cs/01-introduction/01-chapter1.markdown index 44fdd2521..b1b60c735 100644 --- a/cs/01-introduction/01-chapter1.markdown +++ b/cs/01-introduction/01-chapter1.markdown @@ -3,7 +3,7 @@ Tato kapitola vám ve stručnosti představí systém Git. Začneme od samého začátku. Nahlédneme do historie nástrojů ke správě verzí, poté se budeme věnovat tomu, jak spustit systém Git ve vašem počítači, a nakonec se podíváme na možnosti úvodního nastavení. V této kapitole se dozvíte, k čemu Git slouží a proč byste ho měli používat. Kromě toho se také naučíte, jak Git nastavit podle svých potřeb. ## Správa verzí ## - +hi Co je to správa verzí a proč by vás měla zajímat? Správa verzí je systém, který zaznamenává změny souboru nebo sady souborů v průběhu času, a uživatel tak může kdykoli obnovit jeho/jejich konkrétní verzi (tzv. verzování). Příklady verzovaných souborů jsou v této knize ilustrovány na zdrojovém kódu softwaru, avšak ve skutečnosti lze verzování provádět téměř se všemi typy souborů v počítači. Pokud jste grafik nebo webdesigner a chcete uchovávat všechny verze obrázku nebo všechna rozložení stránky (což jistě není k zahození), je pro vás systém správy verzí (zkráceně VCS z angl. Version Control System) ideálním nástrojem. VCS umožňuje vrátit jednotlivé soubory nebo celý projekt do předchozího stavu, porovnávat změny provedené v průběhu času, zjistit, kdo naposledy upravil něco, co nyní možná způsobuje problémy, kdo vložil jakou verzi a kdy a mnoho dalšího. Používáte-li verzovací systém, většinou to také znamená, že snadno obnovíte soubory, které jste ztratili nebo v nichž byly provedeny nežádoucí změny. Všechny funkcionality verzovacího systému můžete navíc používat velice jednoduchým způsobem. @@ -37,11 +37,11 @@ V tomto místě přicházejí ke slovu tzv. distribuované systémy správy verz Insert 18333fig0103.png Obrázek 1-3. Diagram distribuované správy verzí -Mnoho z těchto systémů navíc bez větších obtíží pracuje i s několika vzdálenými repozitáři, a vy tak můžete v rámci jednoho projektu spolupracovat na různých úrovních s rozdílnými skupinami lidí. Díky tomu si můžete vytvořit několik typů pracovních postupů, což není v centralizovaných systémech (např. v hierarchických modelech) možné. +Mnoho z těchto systémů navíc bez větších obtíží pracuje i s několika vzdálenými repozitáři, takže můžete v rámci jednoho projektu různým způsobem spolupracovat s různými skupinami lidí najednou. Můžete zavést několik typů pracovních postupů, které nejsou v centralizovaných systémech možné — jako jsou například hierarchické modely. ## Stručná historie systému Git ## -Tak jako mnoho velkých věcí v lidské historii se i systém Git zrodil z kreativní destrukce a vášnivého sporu. Jádro Linuxu je software s otevřeným kódem a širokou škálou využití. V letech 1991 — 2002 bylo jádro Linuxu spravováno formou záplat a archivních souborů. V roce 2002 začal projekt vývoje linuxového jádra využívat komerční systém DVCS s názvem Bit-Keeper. +Tak jako mnoho velkých věcí v lidské historii se i systém Git zrodil z kreativní destrukce a vášnivého sporu. Jádro Linuxu je software celkém velkého rozsahu, s otevřeným kódem. V letech 1991 — 2002 bylo jádro Linuxu spravováno formou záplat a archivních souborů. V roce 2002 začal projekt vývoje linuxového jádra využívat komerční systém DVCS s názvem BitKeeper. V roce 2005 se zhoršily vztahy mezi komunitou, která vyvíjela jádro Linuxu, a komerční společností, která vyvinula BitKeeper, a společnost přestala tento systém poskytovat zdarma. To přimělo komunitu vývojářů Linuxu (a zejména Linuse Torvaldse, tvůrce Linuxu), aby vyvinula vlastní nástroj, založený na poznatcích, které nasbírala při užívání systému BitKeeper. Mezi požadované vlastnosti systému patřily zejména: @@ -55,7 +55,7 @@ Od svého vzniku v roce 2005 se Git vyvinul a vyzrál v snadno použitelný syst ## Základy systému Git ## -Jak bychom tedy mohli Git charakterizovat? Odpověď na tuto otázku je velmi důležitá, protože pokud pochopíte, co je Git a na jakém principu pracuje, budete ho bezpochyby moci používat mnohem efektivněji. Při seznámení se systémem Git se pokuste zapomenout na vše, co už možná víte o jiných systémech VCS, např. Subversion nebo Perforce. Vyhnete se tak nežádoucím vlivům, které by vás mohly při používání systému Git mást. Ačkoli je uživatelské rozhraní velmi podobné, Git ukládá a zpracovává informace poněkud odlišně od ostatních systémů. Pochopení těchto rozdílů vám pomůže předejít nejasnostem, které mohou vzniknout při používání systému Git. +Jak bychom tedy mohli Git charakterizovat? Odpověď na tuto otázku je velmi důležitá, protože pokud pochopíte, co je Git a na jakém principu pracuje, budete ho bezpochyby moci používat mnohem efektivněji. Při seznámení se systémem Git se pokuste zapomenout na vše, co už možná víte o jiných systémech VCS, např. Subversion nebo Perforce. Vyhnete se tak nežádoucím vlivům, které by vás mohly při používání systému Git mást. Ačkoli je uživatelské rozhraní velmi podobné, Git ukládá a zpracovává informace poněkud odlišně od ostatních systémů. Pochopení těchto rozdílů vám pomůže předejít nejasnostem, které mohou při používání systému Git vzniknout. ### Snímky, nikoli rozdíly ### @@ -69,31 +69,31 @@ Git zpracovává data jinak. Chápe je spíše jako sadu snímků (snapshots) vl Insert 18333fig0105.png Obrázek 1-5. Git ukládá data jako snímky projektu proměnlivé v čase. -Toto je důležitý rozdíl mezi systémem Git a téměř všemi ostatními systémy VCS. Git díky tomu znovu zkoumá skoro každý aspekt správy verzí, které ostatní systémy kopírovaly z předchozí generace. Git je tak z obyčejného VCS spíše povýšen na vlastní systém správy souborů s řadou skutečně výkonných nástrojů, jež stojí na jeho vrcholu. Některé přednosti, které tato metoda správy dat nabízí, si podrobně ukážeme na systému větvení v kapitole 3. +Toto je důležitý rozdíl mezi systémem Git a téměř všemi ostatními systémy VCS. Git díky tomu znovu zkoumá skoro každý aspekt správy verzí, které ostatní systémy kopírovaly z předchozí generace. Git se podobá malému systému souborů (spíše než obyčejnému VCS) s řadou skutečně výkonných nástrojů, jež stojí na jeho vrcholu. Některé přednosti, které tato metoda správy dat nabízí, si podrobně ukážeme na systému větvení v kapitole 3. ### Téměř každá operace je lokální ### Většina operací v systému Git vyžaduje ke své činnosti pouze lokální soubory a zdroje a nejsou potřeba informace z jiných počítačů v síti. Pokud jste zvyklí pracovat se systémy CVCS, kde je většina operací poznamenána latencí sítě, patrně vás při práci v systému Git napadne, že mu bohové rychlosti dali do vínku nadpřirozené schopnosti. Protože máte celou historii projektu uloženou přímo na svém lokálním disku, probíhá většina operací takřka okamžitě. -Pokud chcete například procházet historii projektu, Git kvůli tomu nemusí vyhledávat informace na serveru — načte ji jednoduše přímo z vaší lokální databáze. Znamená to, že se historie projektu zobrazí téměř neprodleně. Pokud si chcete prohlédnout změny provedené mezi aktuální verzí souboru a týmž souborem před měsícem, Git vyhledá měsíc starý soubor a provede lokální výpočet rozdílů, aniž by o to musel žádat vzdálený server nebo stahovat starší verzi souboru ze vzdáleného serveru a poté provádět lokální výpočet. +Pokud chcete například procházet historii projektu, Git kvůli tomu nemusí vyhledávat informace na serveru — načte je jednoduše přímo z vaší lokální databáze. Znamená to, že se historie projektu zobrazí téměř hned. Pokud si chcete prohlédnout změny provedené mezi aktuální verzí souboru a týmž souborem před měsícem, Git vyhledá měsíc starý soubor a provede lokální výpočet rozdílů, aniž by o to musel žádat vzdálený server nebo stahovat starší verzi souboru ze vzdáleného serveru a poté provádět lokální výpočet. -To také znamená, že je jen velmi málo operací, které nemůžete provádět offline nebo bez připojení k VPN. Jste-li v letadle nebo ve vlaku a chcete pokračovat v práci, můžete beze všeho zapisovat nové revize. Ty se odešlou ve chvíli, kdy se opět připojíte k síti. Jestliže přijedete domů a zjistíte, že VPN klient nefunguje, stále můžete pracovat. V mnoha jiných systémech je takový postup nemožný nebo přinejmenším obtížný. Například v systému Perforce toho lze bez připojení k serveru dělat jen velmi málo, v systémech Subversion a CVS můžete sice upravovat soubory, ale nemůžete zapisovat změny do databáze, neboť ta je offline. Možná to vypadá jako maličkost, ale divili byste se, jaký je to velký rozdíl. +To také znamená, že je jen velmi málo operací, které nemůžete provádět offline nebo bez připojení k VPN. Jste-li v letadle nebo ve vlaku a chcete pokračovat v práci, můžete beze všeho zapisovat nové revize. Ty odešlete až po opětovném připojení k síti. Jestliže přijedete domů a zjistíte, že VPN klient nefunguje, stále můžete pracovat. V mnoha jiných systémech je takový postup nemožný nebo přinejmenším obtížný. Například v systému Perforce toho lze bez připojení k serveru dělat jen velmi málo, v systémech Subversion a CVS můžete sice upravovat soubory, ale nemůžete zapisovat změny do databáze, neboť ta je offline. Možná to vypadá jako maličkost, ale divili byste se, jak velký je v tom rozdíl. ### Git pracuje důsledně ### -Než je v systému Git cokoli uloženo, je nejprve proveden kontrolní součet, který je potom používán k identifikaci uloženého souboru. Znamená to, že není možné změnit obsah jakéhokoli souboru nebo adresáře, aniž by o tom Git nevěděl. Tato funkce je integrována do systému Git na nejnižších úrovních a je v souladu s jeho filozofií. Nemůže tak dojít ke ztrátě informací při přenosu dat nebo k poškození souboru, aniž by to byl Git schopen zjistit. +Než je v systému Git cokoli uloženo, je nejprve proveden kontrolní součet, který je potom používán k identifikaci uloženého souboru. Znamená to, že není možné změnit obsah jakéhokoli souboru nebo adresáře, aniž by o tom Git nevěděl. Tato funkce je integrována do systému Git na nejnižších úrovních a je nedílnou součástí jeho filozofie. Nemůže tak dojít ke ztrátě informací při přenosu dat nebo k poškození souboru, aniž by to byl Git schopen zjistit. Mechanismus, který Git k tomuto kontrolnímu součtu používá, se nazývá otisk SHA-1 (SHA-1 hash). Jedná se o řetězec o 40 hexadecimálních znacích (0–9; a–f) vypočítaný na základě obsahu souboru nebo adresářové struktury systému Git. Otisk SHA-1 může vypadat například takto: 24b9da6552252987aa493b52f8696cd6d3b00373 -S těmito otisky se budete setkávat ve všech úložištích systému Git, protože je používá opravdu často. Neukládá totiž soubory podle jejich názvu, ale ve své databázi podle otisku (hashe) jeho obsahu. +S těmito otisky se budete setkávat ve všech úložištích systému Git, protože je používá opravdu často. Git nic neukládá podle názvu souboru. Místo toho používá databázi adresovatelnou hodnotou otisku, který odpovídá obsahu souboru. ### Git většinou jen přidává data ### Jednotlivé operace ve většině případů jednoduše přidávají data do Git databáze. Přimět systém, aby udělal něco, co nelze vzít zpět, nebo aby smazal jakákoli data, je velice obtížné. Stejně jako ve všech systémech VCS můžete ztratit nebo nevratně zničit změny, které ještě nebyly zapsány. Jakmile však jednou zapíšete snímek do systému Git, je téměř nemožné ho ztratit, zvlášť pokud pravidelně zálohujete databázi do jiného repozitáře. -Díky tomu vás bude práce se systémem Git bavit. Budete pracovat s vědomím, že můžete experimentovat, a neriskujete přitom nevratné zničení své práce. Podrobnější informace o tom, jak Git ukládá data a jak lze obnovit zdánlivě ztracenou práci, najdete v kapitole 9 „Git pod pokličkou“. +Díky tomu vás bude práce se systémem Git bavit. Budete pracovat s vědomím, že můžete experimentovat, a neriskujete přitom nevratné zničení své práce. Podrobnější informace o tom, jak Git ukládá data a jak lze obnovit zdánlivě ztracenou práci, najdete v kapitole 9. ### Tři stavy ### @@ -104,9 +104,9 @@ Z toho vyplývá, že projekt je v systému Git rozdělen do tří hlavních č Insert 18333fig0106.png Obrázek 1-6. Pracovní adresář, oblast připravených změn a adresář Git -V adresáři Git ukládá systém databázi metadat a objektů k projektu. Je to nejdůležitější část systému Git a zároveň adresář, který se zkopíruje, když klonujete repozitář z jiného počítače. +Adresář Git (repozitář) je místo, kde Git uchovává metadata a databázi objektů vašeho projektu. Je to nejdůležitější část systému Git a zároveň adresář, který se zkopíruje, když klonujete repozitář z jiného počítače. -Pracovní adresář obsahuje lokální kopii jedné verze projektu. Tyto soubory jsou staženy ze zkomprimované databáze v adresáři Git a umístěny na disk, abyste je mohli upravovat. +Pracovní adresář obsahuje lokální kopii jedné verze projektu. Tyto soubory jsou staženy ze zkomprimované databáze v adresáři Git a umístěny na disk, kde je můžete používat nebo upravovat. Oblast připravených změn je jednoduchý soubor, většinou uložený v adresáři Git, který obsahuje informace o tom, co bude obsahovat příští revize. Soubor se někdy označuje také anglickým výrazem „index“, ale oblast připravených změn (staging area) je už dnes termín běžnější. From e076aae4e88dfa60a706cb014486e6b236c8b3bb Mon Sep 17 00:00:00 2001 From: Davide Fiorentino lo Regio Date: Wed, 12 Feb 2014 23:11:25 -0600 Subject: [PATCH 005/478] [it] reviewed translation chapter2 --- it/02-git-basics/01-chapter2.markdown | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/it/02-git-basics/01-chapter2.markdown b/it/02-git-basics/01-chapter2.markdown index 25de9ca5e..6c2b29368 100644 --- a/it/02-git-basics/01-chapter2.markdown +++ b/it/02-git-basics/01-chapter2.markdown @@ -1,26 +1,26 @@ # Basi di Git # -Se puoi leggere solo un capitolo per capire l'uso di Git, questo fa per te. Questo capitolo illustra tutti i comandi base per fare la stragrande maggioranza delle cose impiegando al meglio il tuo tempo con Git. Alla fine del capitolo, dovresti essere in grado di configurare ed inizializzare un repository, avviare e fermare il tracciamento dei file e mettere in stage o eseguire il commit dei cambiamenti. Vedremo come impostare Git per ignorare certi file o pattern di file, come correggere gli errori velocemente e facilmente, come navigare nella storia del tuo progetto e vedere i cambiamenti tra i vari commit e come fare il push ed il pull da repository remoti. +Se puoi leggere un solo capitolo per imparare Git, leggi questo. Questo capitolo illustra tutti i comandi base di cui hai bisogno per la stragrande maggioranza delle cose che farai con Git. Alla fine del capitolo sarai in grado di configurare e creare un repository, iniziare e interrompere il tracciamento dei file e mettere in stage e committare le modifiche. Vedremo come impostare Git per ignorare certi file o pattern, come annullare velocemente e facilmente gli errori, come navigare la cronologia del tuo progetto e vedere le modifiche tra le varie commit e come fare il push ed il pull da repository remoti. -## Ottenere un Repository Git ## +## Repository Git ## -Puoi creare un progetto Git usando due approcci principali. Il primo prende un progetto esistente o una directory e la importa in Git. Il secondo clona un repository Git esistente da un altro server. +Puoi creare un progetto Git principalmente con due approcci. Il primo prende un progetto esistente o una directory e la importa in Git. Il secondo clona un repository Git esistente, su un altro server. -### Inizializzare un Repository in una Directory Esistente ### +### Creare un repository in una directory preesistente ### -Se stai iniziando a tracciare un progetto esistente con Git, devi posizionarti nella directory del progetto e digitare: +Se vuoi iniziare a tenere traccia con Git di un progetto esistente, devi andare nella directory del progetto e digitare: $ git init -Questo creerà una nuova sottodirectory chiamata .git che conterrà tutti i file necessari per il repository — uno scheletro del repository Git. A questo punto, niente del tuo progetto è già tracciato. (Vedi il Capitolo 9 per avere maggiori informazioni esatte sui file che sono contenuti nella directory `.git` che hai appena creato.) +Questo creerà una nuova sottodirectory chiamata .git che conterrà tutti i file necessari per il tuo repository: una struttura del repository Git. A questo punto non è ancora stato tracciato niente del tuo progetto. (Vedi il *Capitolo 9* per sapere quali file sono contenuti nella directory `.git` che hai appena creato.) -Se vuoi iniziare a tracciare i file esistenti (al contrario di una directory vuota), dovresti iniziare a monitorare questi file eseguendo un commit iniziale. Lo puoi fare con pochi comandi che specificano quali file vuoi controllare, seguiti da un commit: +Se vuoi iniziare a tracciare i file esistenti (a differenza di una directory vuota), dovresti iniziare a monitorare questi file con una commit iniziale. Lo puoi fare con pochi comandi `git add`, che specificano quali file vuoi tracciare, seguiti da un commit: $ git add *.c $ git add README $ git commit -m 'initial project version' -Vedremo in seguito velocemente cosa fanno questi comandi. A questo punto hai un repository Git con dei file tracciati ed un commit iniziale. +Tra un minuto vedremo cosa fanno questi comandi. A questo punto hai un repository Git con dei file tracciati e una commit iniziale. ### Clonare un Repository Esistente ### From 31c0a17a0869ac302c47505a577e04b10a3c0ce8 Mon Sep 17 00:00:00 2001 From: cor Date: Fri, 14 Feb 2014 21:17:52 +0100 Subject: [PATCH 006/478] [nl] Chapter 02. Review, include new command output and add header. Reviewed translations and made them more consistent and in line with the recommendations of the Dutch language institute. Added a header to that effect to the file. Included the new modified command output. --- nl/02-git-basics/01-chapter2.markdown | 530 ++++++++++++++------------ 1 file changed, 293 insertions(+), 237 deletions(-) diff --git a/nl/02-git-basics/01-chapter2.markdown b/nl/02-git-basics/01-chapter2.markdown index 4871c86a3..48f865390 100644 --- a/nl/02-git-basics/01-chapter2.markdown +++ b/nl/02-git-basics/01-chapter2.markdown @@ -1,20 +1,35 @@ + # De basis van Git # -Als je slechts één hoofdstuk kunt lezen om met Git aan de slag te gaan, dan is dit het. Dit hoofdstuk behandelt elk van de basiscommando's, die je nodig hebt om het leeuwendeel van de dingen te doen waarmee je uiteindelijk je tijd met Git zult doorbrengen. Als je dit hoofdstuk doorgenomen hebt, zul je een archief (repository) kunnen configureren en initialiseren, bestanden beginnen en stoppen te volgen en veranderingen te ‘stagen’ en ‘committen’. We laten ook zien hoe je Git kunt instellen zodat het bepaalde bestanden en bestandspatronen negeert, hoe je vergissingen snel en gemakkelijk ongedaan kunt maken, hoe je de geschiedenis van je project kan doorlopen en wijzigingen tussen commits kunt zien, en hoe je kunt pushen en pullen van en naar andere repositories. +Als je slechts één hoofdstuk kunt lezen om met Git aan de slag te gaan, dan is deze het. In dit hoofdstuk worden alle basiscommando's behandeld, die je nodig hebben om het leeuwendeel van de dingen te doen waarmee je uiteindelijk je tijd met Git zult doorbrengen. Als je dit hoofdstuk doorgenomen hebt, zul je een repository kunnen configureren en initialiseren, bestanden beginnen en stoppen te volgen en veranderingen te ‘stagen’ en ‘committen’. We laten ook zien hoe je Git kunt instellen zodat het bepaalde bestanden en bestandspatronen negeert, hoe je vergissingen snel en gemakkelijk ongedaan kunt maken, hoe je de geschiedenis van je project kan doorlopen en wijzigingen tussen commits kunt zien, en hoe je kunt pushen en pullen van en naar repositories. ## Een Git repository verkrijgen ## -Je kunt op twee manieren een Git project verkrijgen. De eerste maakt gebruik van een bestaand project of map en importeert dit in Git. De tweede maakt een kloon (clone) van een bestaande Git repository op een andere server. +Je kunt op twee manieren een Git project verkrijgen. De eerste maakt gebruik van een bestaand project of directory en importeert dit in Git. De tweede maakt een kloon (clone) van een bestaande Git repository op een andere server. -### Een repository initialiseren in een bestaande map ### +### Een repository initialiseren in een bestaande directory ### -Als je een bestaand project in Git wilt volgen (track), dan moet je naar de projectmap gaan en het volgende typen +Als je een bestaand project in Git wilt volgen (tracken), dan moet je naar de projectdirectory gaan en het volgende typen $ git init -Dit maakt een nieuwe submap aan genaamd `.git`, die alle noodzakelijke repository bestanden bevat — een Git repository skelet. Op dit punt wordt nog niets in je project gevolgd. (Zie Hoofdstuk 9 voor meer informatie over welke bestanden er precies in de `.git` map staan, die je zojuist gemaakt hebt.) +Dit maakt een nieuwe subdirectory met de naam `.git` aan, die alle noodzakelijke repository bestanden bevat, een Git repository raamwerk. Op dit moment wordt nog niets in je project gevolgd. (Zie *Hoofdstuk 9* voor meer informatie over welke bestanden er precies in de `.git` directory staan, die je zojuist gemaakt hebt.) -Als je de versies van bestaande bestanden wilt gaan beheren (in plaats van een lege map), dan zul je waarschijnlijk die bestanden beginnen te volgen en een eerste commit willen doen. Dit kun je bereiken door een paar git add commando's die de te volgen bestanden specificeren, gevolgd door een commit: +Als je de versies van bestaande bestanden wilt gaan beheren (in plaats van een lege directory), dan zul je die bestanden moeten beginnen te tracken en een eerste commit doen. Dit kun je bereiken door een paar `git add` commando's waarin je de te volgen bestanden specificeert, gevolgd door een commit: $ git add *.c $ git add README @@ -22,44 +37,44 @@ Als je de versies van bestaande bestanden wilt gaan beheren (in plaats van een l We zullen zodadelijk beschrijven wat deze commando's doen. Op dit punt heb je een Git repository met gevolgde (tracked) bestanden en een initiële commit. -### Een bestaand repository klonen ### +### Een bestaand repository clonen ### -Als je een kopie wilt van een bestaande Git repository — bijvoorbeeld een project waaraan je wilt bijdragen — dan is `git clone` het commando wat je nodig hebt. Als je bekend bent met andere versie-beheersystemen zoals Subversion, dan valt je op dat het commando `clone` is en niet `checkout`. Dit is een belangrijk verschil — Git ontvangt een kopie van bijna alle data die de server heeft. Iedere versie van ieder bestand van de hele geschiedenis van een project wordt binnengehaald als je `git clone` doet. In feite kun je, als je disk kapot gaat, iedere kloon van iedere client gebruiken om de server terug in de status te brengen op het moment van klonen (al zou je wel wat hooks en dergelijke verliezen, maar alle versies van alle bestanden zouden er zijn — zie *Hoofdstuk 4* voor meer informatie). +Als je een kopie wilt van een bestaande Git repository, bijvoorbeeld een project waaraan je wilt bijdragen, dan is `git clone` het commando dat je nodig hebt. Als je bekend bent met andere versie-beheersystemen zoals Subversion, dan zal het je opvallen dat het commando `clone` is en niet `checkout`. Dit is een belangrijk verschil: Git ontvangt een kopie van bijna alle gegevens die de server heeft. Elke versie van ieder bestand in de hele geschiedenis van een project wordt binnengehaald als je `git clone` doet. In feite kun je als de schijf van de server kapot gaat, een clone van een willekeurige client gebruiken om de server terug in de status te brengen op het moment van clonen (al zou je wel wat hooks aan de kant van de server en dergelijke verliezen, maar alle versies van alle bestanden zullen er zijn; zie *Hoofdstuk 4* voor meer informatie). -Je kloont een repository met `git clone [url]`. Bijvoorbeeld, als je de Ruby Git bibliotheek genaamd Grit wilt klonen, kun je dit als volgt doen: +Je cloned een repository met `git clone [url]`. Bijvoorbeeld, als je de Ruby Git bibliotheek genaamd Grit wilt clonen, kun je dit als volgt doen: $ git clone git://github.com/schacon/grit.git -Dat maakt een map genaamd `grit` aan, initialiseert hierin een `.git` map, haalt alle data voor dat repository binnen, en doet een checkout van een werkkopie van de laatste versie. Als je in de nieuwe `grit` map gaat, zul je de project bestanden vinden, klaar om gebruikt of aan gewerkt te worden. Als je de repository in een map met een andere naam dan grit wilt klonen, dan kun je dit met het volgende commando specificeren: +Dat maakt een directory genaamd `grit` aan, initialiseert hierin een `.git` directory, haalt alle data voor die repository binnen en doet een checkout van een werkkopie van de laatste versie. Als je in de nieuwe `grit` directory gaat kijken zal je de project bestanden vinden, klaar om gebruikt of aan gewerkt te worden. Als je de repository in een directory met een andere naam dan grit wilt clonen, dan kun je dit met het volgende commando specificeren: $ git clone git://github.com/schacon/grit.git mygrit -Dat commando doet hetzelfde als het vorige, maar dan heet de doelmap `mygrit`. +Dat commando doet hetzelfde als het vorige, maar dan heet de doeldirectory `mygrit`. -Git heeft een aantal verschillende transport protocollen die je kunt gebruiken. Het vorige voorbeeld maakt gebruik van het `git://` protocol, maar je kunt ook `http(s)://` of `gebruiker@server:/pad.git` tegenkomen, dat het SSH transport protocol gebruikt. *Hoofdstuk 4* zal alle beschikbare opties introduceren die de server kan gebruiken om je Git repository aan te kunnen, met daarbij de voors en tegens van elk. +Git heeft een aantal verschillende transport protocollen die je kunt gebruiken. Het vorige voorbeeld maakt gebruik van het `git://` protocol, maar je kunt ook `http(s)://` of `gebruiker@server:/pad.git` tegenkomen, dat het SSH transport protocol gebruikt. *Hoofdstuk 4* zal alle beschikbare opties introduceren die de server kan inrichten om je toegang tot de Git repositories te geven, met daarbij de voors en tegens van elk. ## Wijzigingen aan het repository vastleggen ## -Je hebt een bonafide Git repository en een checkout of werkkopie van de bestanden voor dat project. Je moet wat wijzigingen maken en deze committen in je repository, iedere keer zodra het project een status bereikt die je wilt vastleggen. +Je hebt een eersteklas Git repository en een checkout of werkkopie van de bestanden binnen dat project. Als je wijzigingen maakt dan moet je deze committen in je repository op elk momend dat het project een status bereikt die je wilt vastleggen. -Onthoud dat ieder bestand in je werkmap in twee statussen kan verkeren: *gevolgd (tracked)* of *niet gevolgd (untracked)*. *Gevolgde* bestanden zijn bestanden die in het laatste snapshot zaten; ze kunnen *ongewijzigd*, *gewijzigd* of *staged zijn*. *Niet gevolgde* bestanden zijn al het andere - ieder bestand in je werkmap dat niet in je laatste snapshot en niet in je staging gebied zit. Als je voor het eerst een repository kloont, zullen al je bestanden gevolgd en ongewijzigd zijn, omdat je ze zojuist ge-checkout en niet gewijzigd hebt. +Onthoud dat elk bestand in je werkdirectory in een van twee statussen kan verkeren: *gevolgd (tracked)* of *niet gevolgd (untracked)*. *Tracked* bestanden zijn bestanden die in het laatste snapshot zaten; ze kunnen *ongewijzigd (unmodified)*, *gewijzigd (modified)* of *staged* zijn. *untracked* bestanden zijn al het andere; elk bestand in je werkdirectory dat niet in je laatste snapshot en niet in je staging area zit. Als je een repository voor het eerst cloned, zullen alle bestanden tracked en unmodified zijn, omdat je ze zojuist uitgechecked hebt en nog niets gewijzigd hebt. -Zodra je bestanden wijzigt, ziet Git ze als gewijzigd omdat je ze veranderd hebt sinds je laatste commit. Je *staged* deze gewijzigde bestanden en commit al je ge-stagede wijzigingen, en de cyclus herhaalt zichzelf. Deze cyclus wordt in Figuur 2-1 geïllustreerd. +Zodra je bestanden wijzigt, ziet Git ze als modified omdat je ze veranderd hebt sinds je laatste commit. Je *staged* deze gewijzigde bestanden en commit al je gestagede wijzigingen, en de cyclus begint weer van voor af aan. Deze cyclus wordt in Figuur 2-1 geïllustreerd. Insert 18333fig0201.png Figuur 2-1. De levenscyclus van de status van je bestanden. ### De status van je bestanden controleren ### -Het hoofdcommando dat je zult gebruiken om te bepalen welk bestand zich in welke status bevindt is `git status`. Als je dit commando direct na het klonen uitvoert, dan zul je zoiets als het volgende zien: +Het commando dat je voornamelijk zult gebruiken om te bepalen welk bestand zich in welke status bevindt is `git status`. Als je dit commando direct na het clonen uitvoert, dan zal je zoiets als het volgende zien: $ git status # On branch master nothing to commit (working directory clean) -Dit betekent dat je een schone werkmap hebt — met andere woorden, er zijn geen gevolgde en gewijzigde bestanden. Git ziet ook geen ongevolgde bestanden, anders zouden ze hier getoond worden. Als laatste vertelt het commando op welke tak (branch) je nu zit. Voor nu is dit altijd `master`, dat is de standaard; maak je je hier nog niet druk om. Het volgende hoofdstuk gaat in detail over takken en referenties. +Dit betekent dat je een schone werkdirectory hebt, met andere woorden er zijn geen untracked bestanden die gewijzigd zijn. Git ziet ook geen untracked bestanden, anders zouden ze hier getoond worden. Als laatste vertelt het commando op welke tak (branch) je nu zit. Voor nu is dit altijd `master`, dat is de standaard; besteed daar voor nu nog geen aandacht aan. In het volgende hoofdstuk wordt gedetaileerd ingegaan op branches en referenties. -Stel dat je een nieuw bestand toevoegt aan je project, een simpel README bestand. Als het bestand voorheen nog niet bestond, en je doet `git status`, dan zul je je ongevolgde bestand zo zien: +Stel dat je een nieuw bestand toevoegt aan je project, een simpel README bestand. Als het bestand voorheen nog niet bestond, en je doet `git status`, dan zul je het niet getrackte bestand op deze manier zien: $ vim README $ git status @@ -70,15 +85,15 @@ Stel dat je een nieuw bestand toevoegt aan je project, een simpel README bestand # README nothing added to commit but untracked files present (use "git add" to track) -Je kunt zien dat je nieuwe README bestand ongevolgd is, omdat het onder de “Untracked files” kop staat in je status output. Ongevolgd betekent eigenlijk dat Git een bestand ziet dat je niet in het vorige snapshot (commit) had; Git zal het niet in je commit snapshots toevoegen totdat jij haar er expliciet om vraagt. Ze doet dit zodat jij niet per ongeluk gegenereerde binaire bestanden toevoegt, of andere bestanden die je niet wou toevoegen. Je wilt dit README bestand wel toevoegen, dus laten we het gaan volgen. +Je kunt zien dat het nieuwe README bestand untrackt is, omdat het onder de “Untracked files” kop staat in je status output. Untrackt betekent eigenlijk dat Git een bestand ziet dat je niet in het vorige snapshot (commit) had; Git zal het niet in je commit snapshots toevoegen totdat jij dit expliciet aangeeft. Dit wordt zo gedaan zodat je niet per ongeluk gegenereerde binaire bestanden toevoegt, of andere bestanden die je niet wilt toevoegen. Je wilt dit README bestand wel meenemen, dus laten we het gaan tracken. ### Nieuwe bestanden volgen (tracking) ### -Om een nieuw bestand te beginnen te volgen, gebruik je het commando `git add`. Om de README te volgen, kun je dit uitvoeren: +Om een nieuw bestand te beginnen te tracken, gebruik je het commando `git add`. Om de README te tracken, voer je dit uit: $ git add README -Als je je status commando nogmaals uitvoert, zie je dat je README bestand nu gevolgd en ge-staged is: +Als je het status commando nogmaals uitvoert, zie je dat je README bestand nu getrackt en ge-staged is: $ git status # On branch master @@ -88,26 +103,27 @@ Als je je status commando nogmaals uitvoert, zie je dat je README bestand nu gev # new file: README # -Je kunt zien dat het ge-staged is, omdat het onder de kop “Changes to be committed” staat. Als je op dit punt een commit doet, zal de versie van het bestand zoals het wat ten tijde van je `git add` commando in de historische snapshot toegevoegd worden. Je zult je misschien herinneren dat, toen je `git init` eerder uitvoerde, je daarna `git add` (bestanden) uitvoerde — dat was om bestanden in je map te beginnen te volgen. Het `git add` commando neemt een padnaam voor een bestand of een map; als het een map is, dan voegt het commando alle bestanden in die map recursief toe. +Je kunt zien dat het gestaged is, omdat het onder de kop “Changes to be committed” staat. Als je nu een commit doet, zal de versie van het bestand zoals het was ten tijde van je `git add` commando in de historische snapshot toegevoegd worden. Je zult je misschien herinneren dat, toen je `git init` eerder uitvoerde, je daarna `git add (bestanden)` uitvoerde; dat was om bestanden in je directory te beginnen te tracken. Het `git add` commando beschouwt een padnaam als een bestand of een directory. Als de padnaam een directory is, dan voegt het commando alle bestanden in die directory recursief toe. ### Gewijzigde bestanden stagen ### -Laten we een gevolgd bestand wijzigen. Als je een voorheen gewijzigd bestand genaamd `benchmarks.rb` wijzigt, en dan je `status` commando nog eens uitvoert, krijg je iets dat er zo uitziet: +Laten we een getrackte bestand wijzigen. Als je een reeds getrackt bestand genaamd `benchmarks.rb` wijzigt, en dan je `status` commando nog eens uitvoert, krijg je iets dat er zo uitziet: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README -Het `benchmarks.rb` bestand verschijnt onder een sectie genaamd “Changes not staged for commit” — wat betekent dat een bestand dat gevolgd wordt gewijzigd is in de werkmap, maar nog niet ge-staged. Om het te stagen, voer je het `git add` commando uit (het is een veelzijdig commando — je gebruikt het om bestanden te volgen, om bestanden te stagen, en andere dingen zoals een bestand met een mergeconflict als opgelost te markeren). Laten we `git add` nu uitvoeren om het `benchmarks.rb` bestand nu te stagen, en dan nog eens `git status` uitvoeren: + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Het `benchmarks.rb` bestand verschijnt onder een sectie genaamd “Changes not staged for commit”, wat inhoudt dat een bestand dat wordt getrackt is gewijzigd in de werkdirectory, maar nog niet is gestaged. Om het te stagen, voer je het `git add` commando uit (het is een veelzijdig commando: je gebruikt het om bestanden te laten tracken, om bestanden te stagen, en om andere dingen zoals een bestand met een mergeconflict als opgelost te markeren). Laten we nu `git add` uitvoeren om het `benchmarks.rb` bestand te stagen, en dan nog eens `git status` uitvoeren: $ git add benchmarks.rb $ git status @@ -119,24 +135,25 @@ Het `benchmarks.rb` bestand verschijnt onder een sectie genaamd “Changes not s # modified: benchmarks.rb # -Beide bestanden zijn ge-staged en zullen in je volgende commit gaan. Stel dat je je op dit punt herinnert dat je een kleine wijziging in `benchmarks.rb` wil maken voor je volgende commit. Je kunt het opnieuw openen en die wijziging maken, en dan ben je klaar voor de commit. Maar, laten we `git status` nog een keer uitvoeren: +Beide bestanden zijn gestaged en zullen met je volgende commit meegaan. Stel nu dat je je herinnert dat je nog een kleine wijziging in `benchmarks.rb` wilt maken voordat je het commit. Je kunt het opnieuw openen en die wijziging maken, en dan ben je klaar voor de commit. Alhoewel, laten we `git status` nog een keer uitvoeren: $ vim benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # - -Hé! Nu staat `benchmarks.rb` zowel bij de staged en unstaged. Hoe kan dat? Het blijkt dat Git een bestand staged precies zoals het is wanneer je het `git add` commando uitvoert. Als je nu commit, dan zal de versie van benchmarks.rb zoals het was toen je voor 't laatst `git add` uitvoerde worden toegevoegd in de commit, en niet de versie van het bestand zoals ie eruit ziet in je map wanneer je git commit uitvoert. Als je een bestand wijzigt nadat je `git add` uitvoert, dan moet je `git add` nogmaals uitvoeren om de laatste versie van het bestand te stagen: + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Asjemenou?! Nu staat `benchmarks.rb` zowel bij de staged en unstaged genoemd. Hoe is dat mogelijk? Het blijkt dat Git een bestand precies zoals het is staged wanneer je het `git add` commando uitvoert. Als je nu commit, dan zal de versie van `benchmarks.rb` zoals het was toen je voor 't laatst `git add` uitvoerde worden toegevoegd in de commit, en niet de versie van het bestand zoals het eruit ziet in je werkdirectory toen je `git commit` uitvoerde. Als je een bestand wijzigt nadat je `git add` uitvoert, dan moet je `git add` nogmaals uitvoeren om de laatste versie van het bestand te stagen: $ git add benchmarks.rb $ git status @@ -150,22 +167,22 @@ Hé! Nu staat `benchmarks.rb` zowel bij de staged en unstaged. Hoe kan dat? Het ### Bestanden negeren ### -Vaak zul je een klasse bestanden hebben waarvan je niet wilt dat Git deze automatisch toevoegt of zelfs maar als ongevolgd toont. Dit zijn doorgaans automatisch gegenereerde bestanden zoals logbestanden of bestanden die geproduceerd worden door je bouwsysteem. In die gevallen kun je een bestand genaamd `.gitignore` maken, waarin patronen staan die die bestanden passen. Hier is een voorbeeld van een `.gitignore` bestand: +Vaak zul je een klasse bestanden hebben waarvan je niet wilt dat Git deze automatisch toevoegt of zelfs maar als untracked toont. Dit zijn doorgaans automatisch gegenereerde bestanden zoals logbestanden of bestanden die geproduceerd worden door je bouwsysteem. In die gevallen kun je een bestand genaamd `.gitignore` maken, waarin patronen staan die die bestanden passen. Hier is een voorbeeld van een `.gitignore` bestand: $ cat .gitignore *.[oa] *~ -De eerste regel verteld Git om ieder bestand dat eindigt op een `.o` of `.a` — *object* en *archief* bestanden die het product kunnen zijn van het bouwen van je code. De tweede regel vertelt Git dat ze alle bestanden die eindigen op een tilde (`~`), wat gebruikt wordt door editors zoals Emacs om tijdelijke bestanden te markeren, mag negeren. Je mag ook `log`, `tmp` of een `pid` map toevoegen, automatisch gegenereerde documentatie, enzovoort. Een `.gitignore` bestand aanmaken voordat je gaat beginnen is over 't algemeen een goed idee, zodat je niet per ongeluk bestanden commit die je echt niet in je repository wilt hebben. +De eerste regel vertelt Git om ieder bestand te negeren waarvan de naam eindigt op een `.o` of `.a` (*object* en *archief* bestanden die het product kunnen zijn van het bouwen van je code). De tweede regel vertelt Git dat ze alle bestanden die eindigen op een tilde (`~`), wat gebruikt wordt door editors zoals Emacs om tijdelijke bestanden aan te geven, moet negeren. Je mag ook `log`, `tmp` of een `pid` directory toevoegen, automatisch gegenereerde documentatie, enzovoort. Een `.gitignore` bestand aanmaken voordat je gaat beginnen is over 't algemeen een goed idee, zodat je niet per ongeluk bestanden commit die je echt niet in je repository wilt hebben. De regels voor patronen die je in het `.gitignore` bestand kunt zetten zijn als volgt: * Lege regels of regels die beginnen met een `#` worden genegeerd. -* Standaard expansie patronen werken. -* Je mag patronen laten eindigen op een schuine streep (`/`) om een map te specificeren. +* Standaard expansie (glob) patronen werken. +* Je mag patronen laten eindigen op een schuine streep (`/`) om een directory te specificeren. * Je mag een patroon ontkennend maken door het te laten beginnen met een uitroepteken (`!`). -Expansie (`glob`) patronen zijn vereenvoudigde reguliere expressies die shell omgevingen gebruiken. Een asterisk (`*`) komt overeen met nul of meer karakters; `[abc]` komt overeen met ieder karakter dat tussen de blokhaken staat (in dit geval a, b of c); een vraagteken (`?`) komt overeen met een enkel karakter, en blokhaken waar tussen karakters staan die gescheiden zijn door een streepje (`[0-9]`) komen overeen met ieder karakter wat tussen die karakters zit (in dit geval 0 tot en met 9). +Expansie (`glob`) patronen zijn vereenvoudigde reguliere expressies die in shell omgevingen gebruikt worden. Een asterisk (`*`) komt overeen met nul of meer karakters, `[abc]` komt overeen met ieder karakter dat tussen de blokhaken staat (in dit geval `a`, `b` of `c`), een vraagteken (`?`) komt overeen met een enkel karakter en blokhaken waartussen karakters staan die gescheiden zijn door een streepje (`[0-9]`) komen overeen met ieder karakter wat tussen die karakters zit (in dit geval 0 tot en met 9). Hier is nog een voorbeeld van een `.gitignore` bestand: @@ -181,24 +198,27 @@ Hier is nog een voorbeeld van een `.gitignore` bestand: # ignore doc/notes.txt, but not doc/server/arch.txt doc/*.txt +Een `**/` patroon is sinds versie 1.8.2 beschikbaar in Git. + ### Je staged en unstaged wijzigingen zien ### -Als het `git status` commando te vaag is voor je — je wilt precies weten wat je veranderd hebt, niet alleen welke bestanden veranderd zijn — dan kun je het `git diff` commando gebruiken. We zullen `git diff` later in meer detail bespreken; maar je zult het het meest gebruiken om deze twee vragen te beantwoorden: Wat heb je veranderd maar nog niet gestaged? En wat heb je gestaged en sta je op het punt te committen? Alhoewel `git status` deze vragen heel algemeen beantwoordt, laat `git diff` je de exacte toegevoegde en verwijderde regels zien — de patch, als het ware. +Als het `git status` commando te vaag is voor je, je wilt precies weten wat je veranderd hebt en niet alleen welke bestanden veranderd zijn, dan kun je het `git diff` commando gebruiken. We zullen `git diff` later in meer detail bespreken, maar je zult dit commando het meest gebruiken om deze twee vragen te beantwoorden: Wat heb je veranderd maar nog niet gestaged? En wat heb je gestaged en sta je op het punt te committen? Waar `git status` deze vragen heel algemeen beantwoordt, laat `git diff` je de exacte toegevoegde en verwijderde regels zien, de patch, als het ware. Stel dat je het `README` bestand opnieuw verandert en staged, en dan het `benchmarks.rb` bestand verandert zonder het te stagen. Als je je `status` commando uitvoert, dan zie je nogmaals zoiets als dit: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Om te zien wat je gewijzigd maar nog niet gestaged hebt, typ `git diff` in zonder verdere argumenten: @@ -219,7 +239,7 @@ Om te zien wat je gewijzigd maar nog niet gestaged hebt, typ `git diff` in zonde log = git.commits('master', 15) log.size -Dat commando vergelijkt wat er in je werkmap zit met wat er in je staging gebied zit. Het resultaat laat je zien welke wijzigingen je gedaan hebt, die je nog niet gestaged hebt. +Dat commando vergelijkt wat er in je werkdirectory zit met wat er in je staging area zit. Het resultaat laat je zien welke wijzigingen je gedaan hebt, die je nog niet gestaged hebt. Als je wilt zien wat je gestaged hebt en in je volgende commit zal zitten, dan kun je `git diff –-cached` gebruiken. (In Git versie 1.6.1 en nieuwer kun je ook `git diff --staged` gebruiken, wat misschien beter te onthouden is.) Dit commando vergelijkt je staged wijzigingen met je laatste commit: @@ -236,23 +256,25 @@ Als je wilt zien wat je gestaged hebt en in je volgende commit zal zitten, dan k + +Grit is a Ruby library for extracting information from a Git repository -Het is belangrijk om te zien dat `git diff` zelf niet alle wijzigingen sinds je laatste commit laat zien — alleen wijzigingen die nog niet gestaged zijn. Dit kan verwarrend zijn, omdat als je al je wijzigingen gestaged hebt, `git diff` geen output zal geven. +Het is belangrijk om te zien dat `git diff` zelf niet alle wijzigingen sinds je laatste commit laat zien, alleen wijzigingen die nog niet gestaged zijn. Dit kan verwarrend zijn, omdat als je al je wijzigingen gestaged hebt, `git diff` geen output zal geven. -Nog een voorbeeld. Als je het `benchmarks.rb` bestand staged, en vervolgens verandert, dan kun je `git diff` gebruiken om de wijzigingen in het bestand te zien dat gestaged is en de wijzigingen die niet gestaged zijn: +Nog een voorbeeld. Als je het `benchmarks.rb` bestand staged en vervolgens verandert, dan kun je `git diff` gebruiken om de wijzigingen in het bestand te zien dat gestaged is en de wijzigingen die niet gestaged zijn: $ git add benchmarks.rb $ echo '# test line' >> benchmarks.rb $ git status - # On branch master - # - # Changes to be committed: - # - # modified: benchmarks.rb - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Nu kun je `git diff` gebruiken om te zien wat nog niet gestaged is @@ -288,12 +310,12 @@ en `git diff --cached` om te zien wat je tot nog toe gestaged hebt: ### Je wijzigingen committen ### -Nu dat je staging gebied ingesteld is op de manier zoals jij het wilt, kun je je wijzigingen committen. Onthoud dat alles wat niet gestaged is — ieder bestand dat je gemaakt of gewijzigd hebt en waarop je nog geen `git add` op uitgevoerd hebt — niet in deze commit mee zal gaan. Ze zullen als gewijzigde bestanden op je disk blijven staan. +Nu je staging area gevuld is zoals jij het wilt, kun je de wijzigingen committen. Onthoud dat alles wat niet gestaged is, dus ieder bestand dat je gemaakt of gewijzigd hebt en waarop je nog geen `git add` uitgevoerd hebt, niet in deze commit mee zal gaan. Ze zullen als gewijzigde bestanden op je schijf blijven staan. In dit geval zag je de laatste keer dat je `git status` uitvoerde, dat alles gestaged was. Dus je bent er klaar voor om je wijzigingen te committen. De makkelijkste manier om te committen is om `git commit` in te typen: $ git commit -Dit start de door jou gekozen editor op. (Dit wordt bepaald door de `$EDITOR` omgevingsvariabele in je shell — meestal vim of emacs, alhoewel je dit kunt instellen op welke je ook wilt gebruiken met het `git config --global core.editor` commando zoals je in *Hoofdstuk 1* gezien hebt). +Dit start de door jou gekozen editor op. (Dit wordt bepaald door de `$EDITOR` omgevingsvariabele in je shell, meestal vim of emacs, alhoewel je dit kunt instellen op welke editor je wilt gebruiken met het `git config --global core.editor` commando zoals je in *Hoofdstuk 1* gezien hebt). De editor laat de volgende tekst zien (dit voorbeeld is een Vim scherm): @@ -301,60 +323,62 @@ De editor laat de volgende tekst zien (dit voorbeeld is een Vim scherm): # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # # new file: README # modified: benchmarks.rb + # ~ ~ ~ ".git/COMMIT_EDITMSG" 10L, 283C -Je kunt zien dat de standaard commit boodschap de laatste output van het `git status` commando in commentaar bevat en een lege regel bovenaan. Je kunt deze commentaren verwijderen en je eigen commit boodschap intypen, of je kunt ze laten staan om je eraan te helpen herinneren wat je aan het committen bent. (Om een meer expliciete herinnering van je wijzigingen te zien kun je de `-v` optie meegeven aan `git commit`. Als je dit doet zet git de diff van je verandering in je editor zodat je precies kunt zien wat je gedaan hebt.) Als je de editor verlaat, creëert Git je commit boodschap (zonder de commentaren of de diff). +Je kunt zien dat de standaard commit boodschap de laatste output van het `git status` commando als commentaar bevat en een lege regel bovenaan. Je kunt deze commentaren verwijderen en je eigen commit boodschap intypen, of je kunt ze laten staan om je eraan te helpen herinneren wat je aan het committen bent. (Om een meer expliciete herinnering van je wijzigingen te zien kun je de `-v` optie meegeven aan `git commit`. Als je dit doet zet Git de diff van je veranderingen in je editor zodat je precies kunt zien wat je gedaan hebt.) Als je de editor verlaat, creëert Git je commit boodschap (zonder de commentaren of de diff). -Als alternatief kun je je commit boodschap met het `commit` commando meegeven door hem achter de `-m` optie te specificeren, zoals hier: +Als alternatief kun je de commit boodschap met het `commit` commando meegeven door hem achter de `-m` optie te specificeren, zoals hier: $ git commit -m "Story 182: Fix benchmarks for speed" - [master]: created 463dc4f: "Fix benchmarks for speed" - 2 files changed, 3 insertions(+), 0 deletions(-) + [master 463dc4f] Fix benchmarks for speed + 2 files changed, 3 insertions(+) create mode 100644 README Nu heb je je eerste commit gemaakt! Je kunt zien dat de commit je wat output over zichzelf heeft gegeven: op welke branch je gecommit hebt (`master`), welke SHA-1 checksum de commit heeft (`463dc4f`), hoeveel bestanden er veranderd zijn, en statistieken over toegevoegde en verwijderde regels in de commit. -Onthoud dat de commit de snapshot, die je in je staging gebied ingesteld hebt, opslaat. Alles wat je niet gestaged hebt staat daar nog steeds gewijzigd; je kunt een volgende commit doen om het aan je geschiedenis toe te voegen. Iedere keer dat je een commit doet, leg je een snapshot van je project vast dat je later terug kunt draaien of mee kunt vergelijken. +Onthoud dat de commit de snapshot, die je in je staging area ingesteld hebt, opslaat. Alles wat je niet gestaged hebt staat nog steeds gewijzigd; je kunt een volgende commit doen om het aan je geschiedenis toe te voegen. Iedere keer dat je een commit doet, leg je een snapshot van je project vast dat je later terug kunt draaien of mee kunt vergelijken. -### Het staging gebied overslaan ### +### De staging area overslaan ### -Alhoewel het ontzettend makkelijk kan zijn om commits precies zoals je wilt te maken, is het staging gebied soms iets ingewikkelder dan je in je manier van werken nodig hebt. Als je het staging gebied wilt overslaan, dan biedt Git een makkelijke route binnendoor. Door de `-a` optie aan het `git commit` commando mee te geven, zal Git automatisch ieder bestand dat al getracked wordt voor de commit stagen, zodat je het `git add` gedeelte kunt overslaan: +Alhoewel het ontzettend makkelijk kan zijn om commits precies zoals je wilt te maken, is de staging area soms iets ingewikkelder dan je in je workflow nodig hebt. Als je de staging area wilt overslaan, dan kan je met Git makkelijk de route inkorten. Door de `-a` optie aan het `git commit` commando mee te geven zal Git automatisch ieder bestand dat al getrackt wordt voor de commit stagen, zodat je het `git add` gedeelte kunt overslaan: $ git status - # On branch master - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + no changes added to commit (use "git add" and/or "git commit -a") $ git commit -a -m 'added new benchmarks' [master 83e38c7] added new benchmarks - 1 files changed, 5 insertions(+), 0 deletions(-) + 1 files changed, 5 insertions(+) -Let op dat je nu geen `git add` op het `benchmarks.rb` bestand hoeft te doen voordat je commit. +Merk op dat je nu geen `git add` op het `benchmarks.rb` bestand hoeft te doen voordat je commit. ### Bestanden verwijderen ### -Om een bestand van Git te verwijderen, moet je het van de tracked bestanden verwijderen (om precies te zijn, verwijderen van je staging gebied) en dan een commit doen. Het `git rm` commando doet dat, en verwijdert het bestand ook van je werkmap zodat je het de volgende keer niet als een untracked bestand ziet. +Om een bestand van Git te verwijderen, moet je het van de getrackte bestanden verwijderen (of om precies te zijn: verwijderen van je staging area) en dan een commit doen. Het `git rm` commando doet dat, en verwijdert het bestand ook van je werkdirectory zodat je het de volgende keer niet als een untrackt bestand ziet. -Als je het bestand simpelweg verwijdert uit je werkmap, zal het te zien zijn onder het “Changes not staged for commit” (dat wil zeggen, _unstaged_) gedeelte van je `git status` output: +Als je het bestand simpelweg verwijdert uit je werkdirectory, zal het te zien zijn onder het “Changes not staged for commit” (dat wil zeggen, _unstaged_) gedeelte van je `git status` output: $ rm grit.gemspec $ git status - # On branch master - # - # Changes not staged for commit: - # (use "git add/rm ..." to update what will be committed) - # - # deleted: grit.gemspec - # + On branch master + Changes not staged for commit: + (use "git add/rm ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + deleted: grit.gemspec + + no changes added to commit (use "git add" and/or "git commit -a") Als je daarna `git rm` uitvoert, zal de verwijdering van het bestand gestaged worden: @@ -369,25 +393,25 @@ Als je daarna `git rm` uitvoert, zal de verwijdering van het bestand gestaged wo # deleted: grit.gemspec # -Als je de volgende keer een commit doet, zal het bestand verdwenen zijn en niet meer getracked worden. Als je het bestand veranderd hebt en al aan de index toegevoegd hebt, dan zul je de verwijdering moeten forceren met de `-f` optie. Dit is een veiligheidsmaatregel om te voorkomen dat je per ongeluk data die nog niet in een snapshot zit, en dus niet teruggehaald kan worden uit Git, weggooit. +Als je de volgende keer een commit doet, zal het bestand verdwenen zijn en niet meer getrackt worden. Als je het bestand veranderd hebt en al aan de index toegevoegd, dan zul je de verwijdering moeten forceren met de `-f` optie. Dit is een veiligheidsmaatregel om te voorkomen dat je per ongeluk data die nog niet in een snapshot zit, en dus niet teruggehaald kan worden uit Git, weggooit. -Een ander handigheidje wat je misschien wilt doen is het bestand in je werkmap houden, maar van je staging gebied verwijderen. Met andere woorden, je wilt het bestand misschien op je harde schijf bewaren, maar niet dat Git het bestand nog tracked. Dit is erg handig als je iets vergeten bent aan je `.gitignore` bestand toe te voegen, en het per ongeluk toegevoegd hebt. Zoals een groot logbestand, of een serie `.a` gecompileerde bestanden. Gebruik de `--cached` optie om dit te doen: +Een ander handigheidje wat je misschien wilt gebruiken is het bestand in je werkdirectory houden, maar van je staging area verwijderen. Met andere woorden, je wilt het bestand misschien op je harde schijf bewaren, maar niet dat Git het bestand nog trackt. Dit is erg handig als je iets vergeten bent aan je `.gitignore` bestand toe te voegen, en het per ongeluk toegevoegd hebt. Zoals een groot logbestand, of een serie `.a` gecompileerde bestanden. Gebruik de `--cached` optie om dit te doen: $ git rm --cached readme.txt -Je kunt bestanden, mappen en bestandspatronen aan het `git rm` commando meegeven. Dat betekent dat je zoiets als dit kunt doen +Je kunt bestanden, directories en bestandspatronen aan het `git rm` commando meegeven. Dat betekent dat je zoiets als dit kunt doen $ git rm log/\*.log -Let op de backslash (`\`) voor de `*`. Dit is nodig omdat Git zijn eigen bestandsnaam expansie doet, naast die van je shell. In de Windows systeemconsole moet de backslash worden weggelaten. Dit commando verwijdert alle bestanden die de `.log` extensie hebben in de `log/` map. Of, je kunt zoiets als dit doen: +Let op de backslash (`\`) voor de `*`. Dit is nodig omdat Git zijn eigen bestandsnaam expansie doet, naast die van je shell. In de Windows systeemconsole moet de backslash worden weggelaten. Dit commando verwijdert alle bestanden die de `.log` extensie hebben in de `log/` directory. Of, je kunt zoiets als dit doen: $ git rm \*~ -Dit commando verwijderd alle bestanden die eindigen met `~`. +Dit commando verwijdert alle bestanden die eindigen met `~`. ### Bestanden verplaatsen ### -Anders dan vele andere VCS systemen, traceert Git niet expliciet verplaatsingen van bestanden. Als je een bestand een nieuwe naam geeft in Git, is er geen metadata opgeslagen in Git die vertelt dat je het bestand hernoemd hebt. Maar, Git is slim genoeg om dit alsnog te zien — we zullen bestandsverplaatsing detectie wat later behandelen. +Anders dan vele andere VCS systemen, traceert Git niet expliciet verplaatsingen van bestanden. Als je een bestand een nieuwe naam geeft in Git, is er geen metadata opgeslagen in Git die vertelt dat je het bestand hernoemd hebt. Maar Git is slim genoeg om dit alsnog te zien, we zullen bestandsverplaatsing detectie wat later behandelen. Het is daarom een beetje verwarrend dat Git een `mv` commando heeft. Als je een bestand wilt hernoemen in Git, kun je zoiets als dit doen @@ -397,26 +421,24 @@ en dat werkt prima. Sterker nog, als je zoiets als dit uitvoert en naar de statu $ git mv README.txt README $ git status - # On branch master - # Your branch is ahead of 'origin/master' by 1 commit. - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # renamed: README.txt -> README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + renamed: README.txt -> README + -Maar, dat is gelijk aan het volgende uitvoeren: +Maar dat is gelijk aan het uitvoeren van het volgende: $ mv README.txt README $ git rm README.txt $ git add README -Git komt er impliciet achter dat het om een hernoemd bestand gaat, dus het maakt niet uit of je een bestand op deze manier hernoemt of met het `mv` commando. Het enige echte verschil is dat het `mv` commando slechts één commando is in plaats van drie. En belangrijker nog is dat je iedere applicatie kunt gebruiken om een bestand te hernoemen, en de add/rm later kunt afhandelen, voordat je commit. +Git komt er impliciet achter dat het om een hernoemd bestand gaat, dus het maakt niet uit of je een bestand op deze manier hernoemt of met het `mv` commando. Het enige echte verschil is dat het `mv` commando slechts één commando is in plaats van drie. En belangrijker nog is dat je iedere applicatie kunt gebruiken om een bestand te hernoemen, en de add/rm later kunt afhandelen voordat je commit. ## De commit geschiedenis bekijken ## -Nadat je een aantal commits gecreëerd hebt, of als je een repository met een bestaande commit geschiedenis gekloond hebt, zul je waarschijnlijk terug willen zien wat er gebeurd is. Het meest basale en krachtige tool om dit te doen is het `git log` commando. +Nadat je een aantal commits gemaakt hebt, of als je een repository met een bestaande commit geschiedenis gecloned hebt, zul je waarschijnlijk terug willen zien wat er gebeurd is. Het meest basale en krachtige tool om dit te doen is het `git log` commando. Deze voorbeelden maken gebruik van een eenvoudig project genaamd simplegit dat ik vaak voor demonstraties gebruikt. Om het project op te halen, voer dit uit @@ -443,7 +465,7 @@ Als je `git log` in dit project uitvoert, zou je output moeten krijgen die er on first commit -Zonder argumenten toont `git log` de commits die gedaan zijn in dat repository, in omgekeerde chronologische volgorde. Dat wil zeggen, de meest recente commits worden als eerste getoond. Zoals je kunt zien, toont dit commando iedere commit met zijn SHA-1 checksum, de naam van de auteur en zijn e-mail, de datum van opslaan, en de commit boodschap. +Zonder argumenten toont `git log` de commits die gedaan zijn in die repository, in omgekeerde chronologische volgorde. Dat wil zeggen: de meest recente commits worden als eerste getoond. Zoals je kunt zien, toont dit commando iedere commit met zijn SHA-1 checksum, de naam van de auteur en zijn e-mail, de datum van opslaan, en de commit boodschap. Een gigantisch aantal en variëteit aan opties zijn beschikbaar voor het `git log` commando om je precies te laten zien waar je naar op zoek bent. Hier laten we je de meest gebruikte opties zien. @@ -487,7 +509,28 @@ Een van de meest behulpzame opties is `-p`, wat de diff laat zien van de dingen -end \ No newline at end of file -Deze optie toont dezelfde informatie, maar dan met een diff volgend op ieder item. Dit is erg handig voor een code review, of om snel te zien wat er tijdens een serie commits gebeurd is die een medewerker toegevoegd heeft. +Deze optie toont dezelfde informatie, maar dan met een diff volgend op ieder item. Dit is erg handig voor een code review, of om snel te zien wat er tijdens een reeks commits gebeurd is die een medewerker toegevoegd heeft. + +Soms is het handiger om wijzigingen na te kijken op woordniveau in plaats van op regelniveau. Er is een `--word-diff` optie beschikbaar in Git, die je aan het `git log -p` commando kan toevoegen om een woord diff te krijgen inplaats van de reguliere regel voor regel diff. Woord diff formaat is nogal nutteloos als het wordt toegepast op broncode, maar is erg handig als het wordt toegepast op grote tekstbestanden, zoals boeken of een dissertatie. Hier is een voorbeeld. + + $ git log -U1 --word-diff + commit ca82a6dff817ec66f44342007202690a93763949 + Author: Scott Chacon + Date: Mon Mar 17 21:52:11 2008 -0700 + + changed the version number + + diff --git a/Rakefile b/Rakefile + index a874b73..8f94139 100644 + --- a/Rakefile + +++ b/Rakefile + @@ -7,3 +7,3 @@ spec = Gem::Specification.new do |s| + s.name = "simplegit" + s.version = [-"0.1.0"-]{+"0.1.1"+} + s.author = "Scott Chacon" + +Zoals je kunt zien zijn er geen toegevoegde of verwijderde regels in deze uitvoer zoals in een normale diff. Wijzigingen worden daarentegen binnen de regel getoond. Je kunt het toegevoegde woord zien binnen een `{+ +}` en verwijderde binnen een `[- -]`. Je kunt ook kiezen om de gebruikelijke 3 regels context in de diff uitvoer tot één regel te verminderen, omdat de context nu woorden is, en geen regels. Je kunt dit doen met `-U1` zoals hierboven in het voorbeeld. + Je kunt ook een serie samenvattende opties met `git log` gebruiken. Bijvoorbeeld, als je wat verkorte statistieken bij iedere commit wilt zien, kun je de `--stat` optie gebruiken: $ git log --stat @@ -498,7 +541,7 @@ Je kunt ook een serie samenvattende opties met `git log` gebruiken. Bijvoorbeeld changed the version number Rakefile | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon @@ -507,7 +550,7 @@ Je kunt ook een serie samenvattende opties met `git log` gebruiken. Bijvoorbeeld removed unnecessary test code lib/simplegit.rb | 5 ----- - 1 files changed, 0 insertions(+), 5 deletions(-) + 1 file changed, 5 deletions(-) commit a11bef06a3f659402fe7563abf99ad00de2209e6 Author: Scott Chacon @@ -518,17 +561,17 @@ Je kunt ook een serie samenvattende opties met `git log` gebruiken. Bijvoorbeeld README | 6 ++++++ Rakefile | 23 +++++++++++++++++++++++ lib/simplegit.rb | 25 +++++++++++++++++++++++++ - 3 files changed, 54 insertions(+), 0 deletions(-) + 3 files changed, 54 insertions(+) Zoals je ziet, drukt de `--stat` optie onder iedere commit een lijst gewijzigde bestanden af, hoeveel bestanden gewijzigd zijn, en hoeveel regels in die bestanden zijn toegevoegd en verwijderd. Het toont ook een samenvatting van de informatie aan het einde. -Een andere handige optie is `--pretty`. Deze optie veranderd de log output naar een ander formaat dan de standaard. Er zijn al een paar voorgebouwde opties voor je beschikbaar. De `oneline` optie drukt iedere commit op een enkele regel af, wat handig is als je naar een hoop commits kijkt. Daarnaast tonen de `short`, `full` en `fuller` optie de output in grofweg hetzelfde formaat, maar met minder of meer informatie, respectievelijk: +Een andere handige optie is `--pretty`. Deze optie verandert de log output naar een ander formaat dan de standaard. Er zijn al een paar voorgebouwde opties voor je beschikbaar. De `oneline` optie drukt iedere commit op een eigen regel af, wat handig is als je naar een hoop commits kijkt. Daarnaast tonen de `short`, `full` en `fuller` opties de output in grofweg hetzelfde formaat, maar met minder of meer informatie, respectievelijk: $ git log --pretty=oneline ca82a6dff817ec66f44342007202690a93763949 changed the version number 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test code a11bef06a3f659402fe7563abf99ad00de2209e6 first commit -De meest interessante optie is `format`, waarmee je je eigen log formaat kunt specificeren. Dit is in het bijzonder handig als je output aan het genereren bent voor automatische verwerking — omdat je expliciet het formaat kan specificeren, weet je dat het niet zal veranderen bij volgende versies van Git: +De meest interessante optie is `format`, waarmee je je eigen log uitvoer formaat kunt specificeren. Dit is in het bijzonder handig als je output aan het genereren bent voor automatische verwerking; omdat je expliciet het formaat kan specificeren, weet je dat het niet zal veranderen bij volgende versies van Git: $ git log --pretty=format:"%h - %an, %ar : %s" ca82a6d - Scott Chacon, 11 months ago : changed the version number @@ -536,6 +579,10 @@ De meest interessante optie is `format`, waarmee je je eigen log formaat kunt sp a11bef0 - Scott Chacon, 11 months ago : first commit Tabel 2-1 toont een aantal handige opties die aan format gegeven kunnen worden. + Optie Omschrijving van de Output %H Commit hash @@ -554,7 +601,7 @@ Tabel 2-1 toont een aantal handige opties die aan format gegeven kunnen worden. %cr Committer datum, relatief %s Onderwerp -Je zult je misschien afvragen wat het verschil is tussen _author_ en _committer_. De _auteur_ is de persoon die het werk oorspronkelijk geschreven heeft, en de _committer_ is de persoon die het werk als laatste toegevoegd heeft. Dus als je een patch naar een project stuurt en een van de kernleden voegt de patch toe, dan krijgen jullie beiden de eer — jij als de auteur en het kernlid als de committer. We gaan hier wat verder op in in *Hoofdstuk 5*. +Je zult je misschien afvragen wat het verschil is tussen _author_ en _committer_. De _author_ is de persoon die de patch oorspronkelijk geschreven heeft, en de _committer_ is de persoon die de patch als laatste heeft toegepast. Dus als je een patch naar een project stuurt en een van de kernleden past de patch toe, dan krijgen jullie beiden de eer, jij als de auteur en het kernlid als de committer. We gaan hier wat verder op in in *Hoofdstuk 5*. De `oneline` en `format` opties zijn erg handig in combinatie met een andere `log` optie genaamd `--graph`. Deze optie maakt een mooie ASCII grafiek waarin je branch en merge geschiedenis getoond worden, die we kunnen zien in onze kopie van het Grit project repository: @@ -570,11 +617,17 @@ De `oneline` en `format` opties zijn erg handig in combinatie met een andere `lo * d6016bc require time for xmlschema * 11d191e Merge branch 'defunkt' into local -Dat zijn slechts een paar simpele output formaat opties voor `git log` — er zijn er nog veel meer. Tabel 2-2 toont de opties waarover we het tot nog toe gehad hebben, en wat veel voorkomende formaat opties die je misschien handig vindt, samen met hoe ze de output van het log commando veranderen. +Dat zijn slechts een paar simpele output formaat opties voor `git log`; er zijn er nog veel meer. Tabel 2-2 toont de opties waarover we het tot nog toe gehad hebben, en wat veel voorkomende formaat opties die je misschien handig vindt, samen met hoe ze de output van het `log` commando veranderen. + + Optie Omschrijving -p Toon de patch geïntroduceerd bij iedere commit. - --stat Toon statistieken voor gewijzigde bestanden in iedere commit. + --word-diff Toon de patch in een woord diff formaat. + --stat Toon statistieken voor gewijzigde bestanden per commit. --shortstat Toon alleen de gewijzigde/ingevoegde/verwijderde regel van het --stat commando. --name-only Toon de lijst van bestanden die gewijzigd zijn na de commit informatie. --name-status Toon ook de lijst van bestanden die beïnvloed zijn door de toegevoegde/gewijzigde/verwijderde informatie. @@ -582,20 +635,21 @@ Dat zijn slechts een paar simpele output formaat opties voor `git log` — er zi --relative-date Toon de datum in een relatief formaat (bijvoorbeeld, "2 weken geleden"), in plaats van het volledige datum formaat. --graph Toon een ASCII grafiek van de branch en merge geschiedenis naast de log output. --pretty Toon commits in een alternatief formaat. De opties bevatten oneline, short, full, fuller, en format (waarbij je je eigen formaat specificeert). + --oneline Een gemaks-optie, staat voor `--pretty=oneline --abbrev-commit`. ### Log output limiteren ### -Naast het formatteren van de output, heeft `git log` nog een aantal bruikbare limiterende opties — dat wil zeggen, opties die je een subset van de commits tonen. Je hebt zo'n optie al gezien — de `-2` optie, die slechts de laatste twee commits laat zien. In feite kun je `-` doen, waarbij `n` ieder heel getal is wat de laatste `n` commits laat zien. In feite zul je deze vorm weinig gebruiken, omdat Git standaard alle output door een pager (pagineer applicatie) stuurt zodat je slechts één pagina log output per keer ziet. +Naast het formatteren van de output, heeft `git log` nog een aantal bruikbare limiterende opties; dat wil zeggen, opties die je een subset van de commits tonen. Je hebt zo'n optie al gezien: de `-2` optie, die slechts de laatste twee commits laat zien. Sterker nog: je kunt `-` doen, waarbij `n` een heel getal is om de laatste `n` commits te laten zien. In feite zul je deze vorm weinig gebruiken, omdat Git standaard alle output door een pager (pagineer applicatie) stuurt zodat je de log-uitvoer pagina voor pagina ziet. -Maar, de tijd limiterende opties zoals `--since` en `--until` zijn erg handig. Dit commando bijvoorbeeld, geeft een lijst met commits die gedaan zijn gedurende de laatste twee weken: +Dat gezegd hebbende, zijn de tijd limiterende opties zoals `--since` en `--until` erg handig. Dit commando bijvoorbeeld, geeft een lijst met commits die gedaan zijn gedurende de laatste twee weken: $ git log --since=2.weeks -Dit commando werkt met veel formaten — je kunt een specifieke datum kiezen ("2008-01-15”) of een relatieve datum zoals "2 jaar 1 dag en 3 minuten geleden". +Dit commando werkt met veel formaten: je kunt een specifieke datum kiezen ("2008-01-15”) of een relatieve datum zoals "2 jaar 1 dag en 3 minuten geleden". Je kunt ook de lijst met commits filteren op bepaalde criteria. De `--author` optie laat je filteren op een specifieke auteur, en de `--grep` optie laat je op bepaalde zoekwoorden filteren in de commit boodschappen. (Let op dat als je zowel auteur als grep opties wilt specificeren, je `--all-match` moet toevoegen of anders zal het commando ook commits met één van de twee criteria selecteren.) -De laatste echt handige optie om aan `git log` als filter mee te geven is een pad. Als je een map of bestandsnaam opgeeft, kun je de log output limiteren tot commits die een verandering introduceren op die bestanden. Dit is altijd de laatste optie en wordt over het algemeen vooraf gegaan door dubbele streepjes (`--`) om de paden van de opties te scheiden. +De laatste echt handige optie om aan `git log` als filter mee te geven is een pad. Als je een directory of bestandsnaam opgeeft, kun je de log output limiteren tot commits die een verandering introduceren op die bestanden. Dit is altijd de laatste optie en wordt over het algemeen vooraf gegaan door dubbele streepjes (`--`) om de paden van de opties te scheiden. In Tabel 2-3 laten we deze en een paar andere veel voorkomende opties zien als referentie. @@ -621,16 +675,16 @@ Van de bijna 20.000 commits in de Git broncode historie, laat dit commando de 6 ### Een grafische interface gebruiken om de historie te visualiseren ### -Als je een meer grafische applicatie wilt gebruiken om je commit historie te visualiseren, wil je misschien een kijkje nemen naar het Tcl/Tk programma genaamd `gitk` dat met Git meegeleverd wordt. Gitk is eigenlijk een visuele `git log`, en het accepteert bijna alle filter opties die `git log` ook accepteert. Als je `gitk` in op de commandoregel in je project typt, zou je zoiets als in Figuur 2-2 moeten zien. +Als je een meer grafische applicatie wilt gebruiken om je commit historie te visualiseren, wil je misschien een kijkje nemen naar het Tcl/Tk programma genaamd `gitk` dat met Git meegeleverd wordt. Gitk is eigenlijk een visuele `git log` tool, en het accepteert bijna alle filter opties die `git log` ook accepteert. Als je `gitk` in op de commandoregel in je project typt, zou je zoiets als in Figuur 2-2 moeten zien. Insert 18333fig0202.png Figuur 2-2. De gitk historie visualiseerder. -Je kunt de commit historie in de bovenste helft van het scherm zien, samen met een afkomst graaf. De diff in de onderste helft van het scherm laat je de veranderingen zien die bij iedere commit die je aanklikt geïntroduceerd zijn. +Je kunt de commit historie in de bovenste helft van het scherm zien, samen met een afkomst graaf. De diff in de onderste helft van het scherm laat je de veranderingen zien die geïntroduceerd zijn bij iedere commit die je aanklikt. ## Dingen ongedaan maken ## -Op enig moment wil je misschien iets ongedaan maken. Hier zullen we een aantal basis toepassingen laten zien om veranderingen die je gemaakt hebt weer ongedaan te maken. Let op, je kunt niet altijd het ongedaan maken weer ongedaan maken. Dit is één van de weinige gedeeltes in Git waarbij je werk kwijt kunt raken als je het verkeerd doet. +Op enig moment wil je misschien iets ongedaan maken. Hier zullen we een aantal basis tools laten zien om veranderingen die je gemaakt hebt weer ongedaan te maken. Maar pas op, je kunt niet altijd het ongedaan maken weer ongedaan maken. Dit is één van de weinige gedeeltes in Git waarbij je werk kwijt kunt raken als je het verkeerd doet. ### Je laatste commit veranderen ### @@ -638,94 +692,95 @@ Een van de veel voorkomende acties die ongedaan gemaakt moeten worden vinden pla $ git commit --amend -Dit commando neemt je staging gebied en gebruikt dit voor de commit. Als je geen veranderingen sinds je laatste commit hebt gedaan (bijvoorbeeld, je voert dit commando meteen na je laatste commit uit), dan zal je snapshot er precies hetzelfde uitzien en zal je commit boodschap het enige zijn dat je verandert. +Dit commando neemt je staging area en gebruikt dit voor de commit. Als je geen veranderingen sinds je laatste commit hebt gedaan (bijvoorbeeld, je voert dit commando meteen na je laatste commit uit), dan zal je snapshot er precies hetzelfde uitzien en zal je commit boodschap het enige zijn dat je verandert. Dezelfde commit-boodschap editor start op, maar deze bevat meteen de boodschap van je vorige commit. Je kunt de boodschap net als andere keren aanpassen, maar het overschrijft je vorige commit. Bijvoorbeeld, als je commit en je dan realiseert dat je vergeten bent de veranderingen in een bestand dat je wou toevoegen in deze commit te stagen, dan kun je zoiets als dit doen: $ git commit -m 'initial commit' - $ git add forgotten_file + $ git add vergeten_bestand $ git commit --amend -Alledrie van deze commando's eindigen met één commit — de tweede commit vervangt de resultaten van de eerste. +Na deze drie commando's eindig je met één commit; de tweede commit vervangt de resultaten van de eerste. ### Een staged bestand unstagen ### -De volgende twee paragrafen laten zien hoe je je staging gebied en veranderingen in je werkmappen aanpakt. Het fijne gedeelte is dat het commando dat je gebruikt om de status van die gebieden te bepalen, je ook herinnert hoe je de veranderingen eraan ongedaan kunt maken. Bijvoorbeeld, stel dat je twee bestanden gewijzigd hebt en je wilt ze committen als twee aparte veranderingen, maar je typt per ongeluk `git add *` en staged ze allebei. Hoe kun je één van de twee nu unstagen? Het `git status` commando herinnert je eraan: +De volgende twee paragrafen laten zien hoe je de staging area en veranderingen in je werkdirectories aanpakt. Het prettige hier is dat het commando dat je gebruikt om de status van die gebieden te bepalen, je er ook aan herinnert hoe je de veranderingen eraan weer ongedaan kunt maken. Bijvoorbeeld, stel dat je twee bestanden gewijzigd hebt en je wilt ze committen als twee aparte veranderingen, maar je typt per ongeluk `git add *` en staged ze allebei. Hoe kun je één van de twee nu unstagen? Het `git status` commando herinnert je eraan: $ git add . $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + modified: benchmarks.rb + -Recht onder de "Changes to be committed" tekst, staat dat je `git reset HEAD ...` moet gebruiken om te unstagen. Laten we dat advies volgen om het `benchmarks.rb` bestand te unstagen: +Direct onder de "Changes to be committed" tekst, staat dat je `git reset HEAD ...` moet gebruiken om te unstagen. Laten we dat advies volgen om het `benchmarks.rb` bestand te unstagen: $ git reset HEAD benchmarks.rb - benchmarks.rb: locally modified + Unstaged changes after reset: + M benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # - -Het commando is een beetje vreemd, maar het werkt. Het benchmarks.rb bestand is gewijzigd maar weer ge-unstaged. - -### Een gewijzigd bestand ongedaan maken ### - -Wat als je je realiseert dat je je wijzigingen aan het `benchmarks.rb` bestand niet wilt behouden? Hoe kun je dit makkelijk ongedaan maken — terug brengen in de staat waarin het was toen je voor het laatst gecommit hebt (of initieel gekloond, of hoe je het ook in je werkmap gekregen hebt)? Gelukkig vertelt `git status` je ook hoe je dat moet doen. In de laatste voorbeeld output, ziet het unstaged gebied er zo uit: - - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # - -Het vertelt je behoorlijk expliciet hoe je je veranderingen moet weggooien (tenminste, de nieuwere versies van Git, 1.6.1 of nieuwer, doen dit — als je een oudere versie hebt, raden we je ten zeerste aan om het te upgraden zodat je een aantal van deze fijne bruikbaarheidsopties krijgt). Laten we eens doen wat er staat: + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Het commando is een beetje vreemd, maar het werkt. Het benchmarks.rb bestand is gewijzigd maar weer geunstaged. + +### Een gewijzigd bestand weer ongewijzigd maken ### + +Wat als je je realiseert dat je de wijzigingen aan het `benchmarks.rb` bestand niet wilt behouden? Hoe kun je dit makkelijk ongedaan maken; terug brengen in de staat waarin het was toen je voor het laatst gecommit hebt (of initieel gecloned, of hoe je het ook in je werkdirectory gekregen hebt)? Gelukkig vertelt `git status` je ook hoe je dat moet doen. In de laatste voorbeeld output, ziet het unstaged gebied er zo uit: + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Het vertelt je behoorlijk expliciet hoe je je veranderingen moet weggooien (tenminste, de nieuwere versies van Git, 1.6.1 of nieuwer, doen dit. Als je een oudere versie hebt, raden we je ten zeerste aan om het te upgraden zodat je een aantal van deze fijne bruikbaarheidsopties krijgt). Laten we eens doen wat er staat: $ git checkout -- benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + -Je kunt zien dat de veranderingen teruggedraaid zijn. Je moet je ook realiseren dat dit een gevaarlijk commando is: alle veranderingen die je aan dat bestand gedaan hebt zijn weg — je hebt er zojuist een ander bestand overheen gezet. Gebruik dit commando dan ook nooit, tenzij je heel zeker weet dat je het bestand niet wilt. Als je het alleen maar uit de weg wilt hebben, gebruik dan branching of stashing wat we behandelen in het volgende hoofdstuk; dit zijn vaak de betere opties. +Je kunt zien dat de veranderingen teruggedraaid zijn. Je moet je ook beseffen dat dit een gevaarlijk commando is: alle veranderingen die je aan dat bestand gedaan hebt zijn weg; je hebt er zojuist een ander bestand overheen gezet. Gebruik dit commando dan ook nooit, tenzij je heel zeker weet dat je het bestand niet wilt. Als je het alleen maar uit de weg wilt hebben, gebruik dan branching of stashing wat we behandelen in het volgende hoofdstuk; dit zijn vaak de betere opties. Onthoud, alles dat in Git gecommit is kan bijna altijd weer hersteld worden. Zelfs commits die op reeds verwijderde branches gedaan zijn, of commits die zijn overschreven door een `--amend` commit, kunnen weer hersteld worden (zie *Hoofdstuk 9* voor data herstel). Maar, alles wat je verliest dat nog nooit was gecommit is waarschijnlijk voor altijd verloren. ## Werken met remotes ## -Om samen te kunnen werken op ieder Git project, moet je weten hoe je je remote repositories moet beheren. Remote repositories zijn versies van je project, die worden beheerd op het Internet of ergens op een netwerk. Je kunt er meerdere hebben, waarvan ieder ofwel alleen leesbaar, of lees- en schrijfbaar is voor jou. Samenwerken met anderen houdt in dat je deze remote repositories kunt beheren en data kunt pushen en pullen op het moment dat je werk moet delen. -Remote repositories beheren houdt ook in hoe je ze moet toevoegen, ongeldige repositories moet verwijderen, meerdere remote branches moet beheren en ze als tracked of niet kunt definiëren, en meer. In deze sectie zullen we deze remote-beheer vaardigheden behandelen. +Om samen te kunnen werken op eender welke Git project, moet je weten hoe je de remote repositories moet beheren. Remote repositories zijn versies van je project, die worden beheerd op het Internet of ergens op een netwerk. Je kunt er meerdere hebben, waarvan over het algemeen ieder ofwel alleen leesbaar, of lees- en schrijfbaar is voor jou. Samenwerken met anderen houdt in dat je deze remote repositories kunt beheren en data kunt pushen en pullen op het moment dat je werk moet delen. +Remote repositories beheren houdt ook in weten hoe je ze moet toevoegen, ongeldige repositories moet verwijderen, meerdere remote branches moet beheren en ze als tracked of niet kunt definiëren, en meer. In deze sectie zullen we deze remote-beheer vaardigheden behandelen. ### Laat je remotes zien ### -Om te zien welke remote servers je geconfigureerd hebt, kun je het `git remote` commando uitvoeren. Het laat de verkorte namen van iedere remote alias zien die je gespecificeerd hebt. Als je je repository gekloond hebt, dan zul je op z'n minst de *origin* zien — dat is de standaard naam die Git aan de server geeft waarvan je gekloond hebt: +Om te zien welke remote servers je geconfigureerd hebt, kun je het `git remote` commando uitvoeren. Het laat de verkorte namen van iedere remote alias zien die je gespecificeerd hebt. Als je de repository gecloned hebt, dan zul je op z'n minst de *origin* zien; dat is de standaard naam die Git aan de server geeft waarvan je gecloned hebt: $ git clone git://github.com/schacon/ticgit.git - Initialized empty Git repository in /private/tmp/ticgit/.git/ - remote: Counting objects: 595, done. - remote: Compressing objects: 100% (269/269), done. - remote: Total 595 (delta 255), reused 589 (delta 253) - Receiving objects: 100% (595/595), 73.31 KiB | 1 KiB/s, done. - Resolving deltas: 100% (255/255), done. + Cloning into 'ticgit'... + remote: Reusing existing pack: 1857, done. + remote: Total 1857 (delta 0), reused 0 (delta 0) + Receiving objects: 100% (1857/1857), 374.35 KiB | 193.00 KiB/s, done. + Resolving deltas: 100% (772/772), done. + Checking connectivity... done. $ cd ticgit $ git remote origin @@ -733,7 +788,8 @@ Om te zien welke remote servers je geconfigureerd hebt, kun je het `git remote` Je kunt ook `-v` specificeren, wat je de URL laat zien die Git bij de verkorte naam heeft opgeslagen om naar geëxpandeerd te worden: $ git remote -v - origin git://github.com/schacon/ticgit.git + origin git://github.com/schacon/ticgit.git (fetch) + origin git://github.com/schacon/ticgit.git (push) Als je meer dan één remote hebt, dan laat het commando ze allemaal zien. Bijvoorbeeld, mijn Grit repository ziet er ongeveer zo uit. @@ -745,11 +801,11 @@ Als je meer dan één remote hebt, dan laat het commando ze allemaal zien. Bijvo koke git://github.com/koke/grit.git origin git@github.com:mojombo/grit.git -Dit betekent dat we vrij gemakkelijk de bijdragen van ieder van deze gebruikers naar binnen kunnen pullen. Let op dat alleen de origin een SSH URL is, dus dat is de enige waar ik naartoe kan pushen (we laten het waarom zien in *Hoofdstuk 4*). +Dit betekent dat we vrij gemakkelijk de bijdragen van ieder van deze gebruikers naar binnen kunnen pullen. Maar merk ook op dat alleen de origin een SSH URL is, dus dat is de enige waar ik naartoe kan pushen (we laten in *Hoofdstuk 4* zien waarom dat zo is). ### Remote repositories toevoegen ### -Ik heb het toevoegen van remote repositories al genoemd en getoond in vorige secties, maar hier toon ik het expliciet. Om een nieuw Git remote repository als een makkelijk te refereren alias toe te voegen, voer `git remote add [verkorte naam] [url]` uit: +Ik heb het toevoegen van remote repositories al genoemd en getoond in vorige paragrafen, maar hier toon ik expliciet hoe dat gedaan wordt. Om een nieuw Git remote repository als een makkelijk te refereren alias toe te voegen, voer je `git remote add [verkorte naam] [url]` uit: $ git remote origin @@ -758,7 +814,7 @@ Ik heb het toevoegen van remote repositories al genoemd en getoond in vorige sec origin git://github.com/schacon/ticgit.git pb git://github.com/paulboone/ticgit.git -Nu kun je de naam pb in de shell gebruiken in plaats van de hele URL. Bijvoorbeeld, als je alle informatie die Paul wel, maar jij niet in je repository wilt fetchen, dan kun je git fetch pb uitvoeren: +Nu kun je de naam pb op de commandoregel gebruiken in plaats van de hele URL. Bijvoorbeeld, als je alle informatie die Paul wel, maar jij niet in je repository wilt fetchen, dan kun je git fetch pb uitvoeren: $ git fetch pb remote: Counting objects: 58, done. @@ -769,7 +825,7 @@ Nu kun je de naam pb in de shell gebruiken in plaats van de hele URL. Bijvoorbee * [new branch] master -> pb/master * [new branch] ticgit -> pb/ticgit -Paul zijn master branch is lokaal toegankelijk als `pb/master` — je kunt het in een van jouw branches mergen, of je kunt een lokale branch uitchecken op dat punt als je het wil zien. +Paul zijn master branch is lokaal toegankelijk als `pb/master`; je kunt het in een van jouw branches mergen, of je kunt een lokale branch uitchecken op dat punt als je het wil zien. ### Van je remotes fetchen en pullen ### @@ -777,19 +833,19 @@ Zoals je zojuist gezien hebt, kun je om data van je remote projecten te halen di $ git fetch [remote-name] -Het commando gaat naar het remote project en haalt alle data van dat remote project dat jij nog niet hebt. Nadat je dit gedaan hebt, zou je references (referenties) naar alle branches van dat remote moeten hebben, die je op ieder tijdstip kunt mergen en bekijken. (We zullen zien wat branches precies zijn, en hoe je ze moet gebruiken in meer detail in *Hoofdstuk 3*.) +Het commando gaat naar het remote project en haalt alle data van dat remote project dat jij nog niet hebt. Nadat je dit gedaan hebt, zou je references (referenties) naar alle branches van dat remote moeten hebben, die je op ieder tijdstip kunt mergen en bekijken. (We zullen in meer detail zien wat branches precies zijn, en hoe je ze moet gebruiken in *Hoofdstuk 3*.) -Als je een repository kloont, voegt dat commando dat remote repository automatisch toe onder de naam *origin*. Dus `git fetch origin` fetched (haalt) ieder nieuw werk dat gepusht is naar die server sinds je gekloond hebt (of voor het laatst ge-fetched hebt). Het is belangrijk om te weten dat het fetch commando de data naar je locale repository haalt — het merged niet automatisch met je werk of verandert waar je momenteel aan zit te werken. Je kunt het handmatig in je werk mergen als je er klaar voor bent. +Als je een repository cloned, voegt dat commando die remote repository automatisch toe onder de naam *origin*. Dus `git fetch origin` fetcht (haalt) ieder nieuw werk dat gepusht is naar die server sinds je gecloned hebt (of voor het laatst gefetcht hebt). Het is belangrijk om te weten dat het fetch commando de data naar je locale repository haalt; het merged niet automatisch met je werk of verandert waar je momenteel aan zit te werken. Je moet het handmatig in je werk mergen wanneer je er klaar voor bent. -Als je een branch geconfigureerd hebt om een remote branch te tracken (volgen) (zie de volgende sectie en *Hoofdstuk 3* voor meer informatie), dan kun je het `git pull` commando gebruiken om automatisch een remote branch te fetchen en mergen in je huidige branch. Dit kan makkelijker of meer comfortabel zijn voor je werkwijze; en standaard stelt het `git clone` commando je lokale master branch zo in dat het de remote master branch van de server waarvan je gekloond hebt volgt (aangenomen dat de remote een master branch heeft). Over het algemeen zal een `git pull` dat van de server waarvan je origineel gekloond hebt halen en proberen het automatisch in de code waar je op dat moment aan zit te werken te mergen. +Als je een branch geconfigureerd hebt om een remote branch te volgen (tracken) (zie de volgende paragraaf en *Hoofdstuk 3* voor meer informatie), dan kun je het `git pull` commando gebruiken om automatisch een remote branch te fetchen en mergen in je huidige branch. Dit kan makkelijker of meer comfortabele workflow zijn voor je; en standaard stelt het `git clone` commando je lokale master branch zo in dat het de remote master branch van de server waarvan je gecloned hebt volgt (aangenomen dat de remote een master branch heeft). Over het algemeen zal een `git pull` dat van de server waarvan je origineel gecloned hebt halen en proberen het automatisch in de code waar je op dat moment aan zit te werken te mergen. -### Je remotes pushen ### +### Naar je remotes pushen ### -Wanneer je je project op een punt krijgt dat je het wilt delen, dan moet je het stroomopwaarts pushen. Het commando hiervoor is simpel: `git push [remote-name] [branch-name]`. Als je je master branch naar je `origin` server wilt pushen (nogmaals, over het algemeen zet klonen beide namen automatisch goed voor je), dan kun je dit uitvoeren om je werk terug op de server te pushen: +Wanneer je jouw project op een punt hebt dat je het wilt delen, dan moet je het stroomopwaarts pushen. Het commando hiervoor is simpel: `git push [remote-name] [branch-name]`. Als je de master branch naar je `origin` server wilt pushen (nogmaals, over het algemeen zet clonen beide namen automatisch goed voor je), dan kun je dit uitvoeren om je werk terug op de server te pushen: $ git push origin master -Dit commando werkt alleen als je gekloond hebt van een server waarop je schrijfrechten hebt, en als niemand in de tussentijd gepusht heeft. Als jij en iemand anders op hetzelfde tijdstip gekloond hebben en zij pushen stroomopwaarts en dan jij, dan zal je push terecht geweigerd worden. Je zult eerst hun werk moeten pullen en in jouw werk verwerken voordat je toegestaan wordt te pushen. Zie *Hoofdstuk 3* voor meer gedetailleerde informatie over hoe je naar remote servers moet pushen. +Dit commando werkt alleen als je gecloned hebt van een server waarop je schrijfrechten hebt, en als niemand in de tussentijd gepusht heeft. Als jij en iemand anders op hetzelfde tijdstip gecloned hebben en zij pushen eerder stroomopwaarts dan jij, dan zal je push terecht geweigerd worden. Je zult eerst hun werk moeten pullen en in jouw werk verwerken voordat je toegestaan wordt te pushen. Zie *Hoofdstuk 3* voor meer gedetailleerde informatie over hoe je naar remote servers moet pushen. ### Een remote inspecteren ### @@ -804,9 +860,9 @@ Als je meer informatie over een bepaalde remote wilt zien, kun je het `git remot master ticgit -Het toont de URL voor de remote repository, samen met de tracking branch informatie. Het commando vertelt je behulpzaam dat als je op de master branch zit, en je voert `git pull` uit, dan zal het automatisch de master branch op de remote mergen nadat het alle remote references opgehaald heeft. Het toont ook alle remote referenties die het gepulled heeft. +Het toont de URL voor de remote repository samen met de tracking branch informatie. Het commando vertelt je behulpzaam dat als je op de master branch zit en je voert `git pull` uit, dat Git dan automatisch de master branch van de remote zal mergen nadat het alle remote references opgehaald heeft. Het toont ook alle remote referenties die het gepulled heeft. -Dat is een eenvoudig voorbeeld dat je vaak tegenkomt. Als je Git meer intensief gebruikt, zul je veel meer informatie van `git remote show` krijgen: +Dat is een eenvoudig voorbeeld dat je vaak zult tegenkomen. Als je Git echter intensiever gebruikt, zul je veel meer informatie van `git remote show` krijgen: $ git remote show origin * remote origin @@ -841,19 +897,19 @@ Als je een referentie wilt hernoemen, dan kun je in nieuwere versie van Git `git origin paul -Het is de moeite om te melden dat dit ook je remote branch naam verandert. Wat voorheen gerefereerd werd als `pb/master` is nu `paul/master`. +Het is de moeite waard om te melden dat dit ook je remote branch naam verandert. Wat voorheen gerefereerd werd als `pb/master` is nu `paul/master`. -Als je om een of andere reden een referentie wilt verwijderen — je hebt de server verplaatst of je gebruikt een bepaalde spiegel niet meer, of een medewerker doet niet meer mee — dan kun je `git remote rm` gebruiken: +Als je om een of andere reden een referentie wilt verwijderen, je hebt de server verplaatst of je gebruikt een bepaalde mirror niet meer, of een medewerker doet niet meer mee, dan kun je `git remote rm` gebruiken: $ git remote rm paul $ git remote origin -## Labelen ## +## Labelen (Taggen) ## -Zoals de meeste VCS'en, heeft git de mogelijkheid om specifieke punten in de history als belangrijk te taggen (labelen). Over het algemeen gebruiken mensen deze functionaliteit om versie punten te markeren (v1.0, en verder). In deze sectie zul je leren hoe de beschikbare tags te tonen, hoe nieuwe tags te creëren, en wat de verschillende typen tags zijn. +Zoals de meeste VCS'en, heeft git de mogelijkheid om specifieke punten in de history als belangrijk te labelen (taggen). Over het algemeen gebruiken mensen deze functionaliteit om versie punten te markeren (`v1.0`, en zo). In deze paragraaf zul je leren hoe de beschikbare tags te tonen, hoe nieuwe tags te creëren, en wat de verschillende typen tags zijn. -### Je tags laten zien ### +### Jouw tags laten zien ### De beschikbare tags in Git laten zien is rechttoe rechtaan. Type gewoon `git tag`: @@ -861,7 +917,7 @@ De beschikbare tags in Git laten zien is rechttoe rechtaan. Type gewoon `git tag v0.1 v1.3 -Dit commando toont de tags in alfabetische volgorde; de volgorde waarin ze verschijnen heeft geen echt belang. +Dit commando toont de tags in alfabetische volgorde; de volgorde waarin ze verschijnen heeft geen echte betekenis. Je kunt ook zoeken op tags met een bepaald patroon. De Git bron repository, bijvoorbeeld, bevat meer dan 240 tags. Als je alleen geïnteresseerd bent om naar de 1.4.2 serie te kijken, kun je dit uitvoeren: @@ -873,11 +929,11 @@ Je kunt ook zoeken op tags met een bepaald patroon. De Git bron repository, bijv ### Tags creëren ### -Git gebruikt twee soorten tags: lightweight (lichtgewicht) en annotated (beschreven). Een lichtgewicht tag komt overeen met een branch die niet verandert — het is slechts een wijzer naar een specifieke commit. Beschreven tags daarentegen, zijn als volwaardige objecten in de Git database opgeslagen. Ze worden gechecksummed, bevatten de naam van de tagger, e-mail en datum, hebben een tag boodschap, en kunnen gesigneerd en geverifieerd worden met GNU Privacy Guard (GPG). Het wordt over het algemeen aangeraden om beschreven tags te maken zodat je deze informatie hebt; maar als je een tijdelijke tag wilt of om een of andere reden de andere informatie niet wilt houden, dan zijn er ook lichtgewicht tags. +Git gebruikt twee soorten tags: lichtgewicht (lightweight) en beschreven (annotated). Een lightweight tag komt overeen met een branch die niet verandert: het is slechts een wijzer naar een specifieke commit. Annotated tags daarentegen, zijn als volwaardige objecten in de Git database opgeslagen. Ze worden gechecksummed, bevatten de naam van de tagger, e-mail en datum, hebben een tag boodschap, en kunnen gesigneerd en geverifieerd worden met GNU Privacy Guard (GPG). Het wordt over het algemeen aangeraden om annotated tags te maken zodat je deze informatie hebt; maar als je een tijdelijke tag wilt of om een of andere reden de andere informatie niet wilt houden, dan zijn er ook lichtgewicht tags. -### Beschreven tags ### +### Annotated tags ### -Een beschreven tag in Git maken is eenvoudig. Het makkelijkst is om de `-a` optie te specificeren als je het `tag` commando uitvoert: +Een annotated tag in Git maken is eenvoudig. Het makkelijkst is om de `-a` optie te specificeren als je het `tag` commando uitvoert: $ git tag -a v1.4 -m 'my version 1.4' $ git tag @@ -937,9 +993,9 @@ Als je `git show` op die tag uitvoert, dan kun je jouw GPG handtekening eraan va Verderop zul je leren hoe je ondertekende tags kunt verifiëren. -### Lichtgewicht tags ### +### Lightweight tags ### -Een andere manier om een tag te committen is met behulp van een lichtgewicht tag. Dit is in principe de commit checksum in een bestand opgeslagen — er wordt geen andere informatie bijgehouden. Om een lichtgewicht tag te maken voeg je niet de `-a`, `-s` of de `-m` optie toe: +Een andere manier om een tag te committen is met behulp van een lightweight tag. Dit is in principe de commit checksum in een bestand opgeslagen; er wordt geen andere informatie bijgehouden. Om een lightweight tag te maken voeg je niet de `-a`, `-s` noch de `-m` optie toe: $ git tag v1.4-lw $ git tag @@ -985,7 +1041,7 @@ Als je de publieke sleutel van degene die getekend heeft niet hebt, dan krijg je ### Later taggen ### -Je kunt ook commits taggen nadat je verder gegaan bent. Stel dat je commit historie er zo uitziet: +Je kunt ook commits taggen waar je al voorbij bent. Stel dat je commit historie er zo uitziet: $ git log --pretty=oneline 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment' @@ -999,7 +1055,7 @@ Je kunt ook commits taggen nadat je verder gegaan bent. Stel dat je commit histo 964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo 8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme -Nu, stel dat je vergeten bent het project op v1.2 te taggen, daar waar de "updated rakefile" commit was. Je kunt dit nadien toevoegen. Om die commit te taggen, specificeer je de commit boodschap (of een gedeelte daarvan) aan het einde van het commando: +Stel nu dat je vergeten bent het project op v1.2 te taggen, daar waar de "updated rakefile" commit was. Je kunt dit nadien toevoegen. Om die commit te taggen, specificeer je de commit boodschap (of een gedeelte daarvan) aan het einde van het commando: $ git tag -a v1.2 9fceb02 @@ -1038,7 +1094,7 @@ Standaard zal het `git push` commando geen tags naar remote servers versturen. J To git@github.com:schacon/simplegit.git * [new tag] v1.5 -> v1.5 -Als je veel tags hebt die je ineens wilt pushen, kun je ook de `--tags` optie aan het `git push` commando toevoegen. Dit zal al je tags, die nog niet op de remote server zijn, in een keer er naartoe sturen. +Als je veel tags hebt die je ineens wilt pushen, kun je ook de `--tags` optie aan het `git push` commando toevoegen. Dit zal al je tags, die nog niet op de remote server zijn, in één keer er naartoe sturen. $ git push origin --tags Counting objects: 50, done. @@ -1052,7 +1108,7 @@ Als je veel tags hebt die je ineens wilt pushen, kun je ook de `--tags` optie aa * [new tag] v1.4-lw -> v1.4-lw * [new tag] v1.5 -> v1.5 -Als nu iemand anders van jouw repository kloont of pulled, dan zullen zij al jouw tags ook krijgen. +Als nu iemand anders van jouw repository cloned of pulled, dan zullen zij al jouw tags ook krijgen. ## Tips en trucs ## @@ -1060,22 +1116,22 @@ Voordat we dit hoofdstuk over de basis van Git afsluiten laten we je nog wat kle ### Auto-aanvulling ### -Als je de Bash shell gebruikt, heeft Git een fijn auto-aanvulling script dat je aan kunt zetten. Download de Git broncode, en kijk in de `contrib/completion` map; daar zou een bestand genaamd `git-completion.bash` moeten staan. Kopieer dit bestand naar je home map, en voeg dit aan je `.bashrc` bestand toe: +Als je de Bash shell gebruikt, heeft Git een prettige auto-aanvulling script dat je aan kunt zetten. Download het direct van de Git broncode op https://github.com/git/git/blob/master/contrib/completion/git-completion.bash. Kopieer dit bestand naar je home directory, en voeg dit aan je `.bashrc` bestand toe: source ~/.git-completion.bash -Als je Git wilt instellen dat het automatische Bash shell aanvulling heeft voor alle gebruikers, kopieer dit script dan naar de `/opt/local/etc/bash_completion.d` map op Mac systemen, of naar de `/etc/bash_completion.d/` map op Linux systemen. Dit is een map met scripts dat Bash automatisch zal laden om shell aanvullingen aan te bieden. +Als je Git wilt instellen dat het automatische Bash shell aanvulling heeft voor alle gebruikers, kopieer dit script dan naar de `/opt/local/etc/bash_completion.d` directory op Mac systemen, of naar de `/etc/bash_completion.d/` directory op Linux systemen. Dit is een directory met scripts dat Bash automatisch zal laden om shell aanvullingen aan te bieden. Als je Windows gebruikt met Git Bash, wat de standaard is als je Git op Windows installeert met msysGit, dan zou auto-aanvulling voorgeconfigureerd moeten zijn. -Druk de Tab toets als je een Git commando aan het typen bent, en het zou een set suggesties voor je moeten teruggeven: +Druk de Tab toets als je een Git commando aan het typen bent, en het zou een lijstje suggesties voor je moeten teruggeven: $ git co commit config -In dit geval zal git co en dan de Tab toets twee keer indrukken git commit en config voorstellen. `m` toevoegen, vult `git commit` automatisch aan. +In dit geval zal git co en dan de Tab toets twee keer indrukken git commit en config voorstellen. Als je daarna `m` toevoegt, wordt het automatisch tot `git commit` gecompleteerd. -Dit werkt ook met opties, wat waarschijnlijk meer bruikbaar is. Bijvoorbeeld, als je een `git log` commando uitvoert en je niet meer kunt herinneren wat een van de opties is, dan kun je beginnen met het te typen en Tab indrukken om te zien wat er past: +Dit werkt ook met opties, wat nog bruikbaarder is. Bijvoorbeeld, als je een `git log` commando uitvoert en je een van de opties niet meer kunt herinneren, dan kun je beginnen met het te typen en Tab indrukken om te zien wat er past: $ git log --s --shortstat --since= --src-prefix= --stat --summary @@ -1084,16 +1140,16 @@ Dat is een erg handig trucje en zal je misschien wat tijd en documentatie lezen ### Git aliassen ### -Git zal geen commando's raden als je het gedeeltelijk intypt. Als je niet de hele tekst van ieder Git commando wilt intypen, kun je gemakkelijk een alias voor ieder commando configureren door `git config` te gebruiken. Hier zijn een aantal voorbeelden die je misschien wilt instellen: +Git zal geen commando's afleiden uit wat gedeeltelijk intypt. Als je niet de hele tekst van ieder Git commando wilt intypen, kun je gemakkelijk een alias voor ieder commando configureren door `git config` te gebruiken. Hier zijn een aantal voorbeelden die je misschien wilt instellen: $ git config --global alias.co checkout $ git config --global alias.br branch $ git config --global alias.ci commit $ git config --global alias.st status -Dit betekent dat je, bijvoorbeeld, in plaats van `git commit` je alleen `git ci` hoeft in te typen. Als je verder gaat met Git, zul je waarschijnlijk andere commando's ook vaker gaan gebruiken; in dat geval, schroom je niet om nieuwe aliassen te maken. +Dit betekent dat je, bijvoorbeeld, in plaats van `git commit` je alleen `git ci` hoeft in te typen. Als je verder gaat met Git, zul je waarschijnlijk andere commando's ook vaker gaan gebruiken; in dat geval: schroom niet om nieuwe aliassen te maken. -Deze techniek kan ook makkelijk zijn om commando's te maken waarvan je vindt dat ze moeten bestaan. Bijvoorbeeld, om het bruikbaarheidsprobleem wat je met het unstagen van een bestand hebt op te lossen, kun je je eigen unstage alias aan Git toevoegen: +Deze techniek kan ook makkelijk zijn om commando's te maken waarvan je vindt dat ze zouden moeten bestaan. Bijvoorbeeld, om het bruikbaarheidsprobleem wat je met het unstagen van een bestand tegenkwam op te lossen, kun je jouw eigen unstage alias aan Git toevoegen: $ git config --global alias.unstage 'reset HEAD --' @@ -1102,7 +1158,7 @@ Dit maakt de volgende twee commando's equivalent: $ git unstage fileA $ git reset HEAD fileA -Het lijkt wat helderder. Het is ook gebruikelijk om een `last` commando toe te voegen: +Het lijkt wat duidelijker. Het is ook gebruikelijk om een `last` commando toe te voegen: $ git config --global alias.last 'log -1 HEAD' @@ -1117,10 +1173,10 @@ Op deze manier kun je de laatste commit makkelijk zien: Signed-off-by: Scott Chacon -Zoals je kunt zien, vervangt Git eenvoudigweg het nieuwe commando met waarvoor je het gealiassed hebt. Maar, misschien wil je een extern commando uitvoeren, in plaats van een Git subcommando. In dat geval begin je het commando met een `!` karakter. Dit is handig als je je eigen applicaties maakt die met een Git repository werken. We kunnen dit demonstreren door `git visual` een `gitk` te laten uitvoeren: +Zoals je kunt zien, vervangt Git eenvoudigweg het nieuwe commando met hetgeen waarvoor je het gealiassed hebt. Maar, misschien wil je een extern commando uitvoeren, in plaats van een Git subcommando. In dat geval begin je het commando met een `!` karakter. Dit is handig als je je eigen applicaties maakt die met een Git repository werken. We kunnen dit demonstreren door `git visual` een `gitk` te laten uitvoeren: $ git config --global alias.visual '!gitk' ## Samenvatting ## -Op dit punt kun je alle basis locale Git operaties doen – een repository creëren of klonen, wijzigingen maken, de wijzigingen stagen en committen, en de historie bekijken van alle veranderingen die de repository ondergaan heeft. Als volgende gaan we Gits beste optie bekijken: het branching model. +Op dit punt kun je alle basis locale Git operaties doen: een repository creëren of clonen, wijzigingen maken, de wijzigingen stagen en committen en de historie bekijken van alle veranderingen die de repository ondergaan heeft. Als volgende gaan we de beste eigenschap van Git bekijken: het branching model. From e9fcfae7a6bfb26c8b0fd287134a3d71ac95cb79 Mon Sep 17 00:00:00 2001 From: JLuc Date: Fri, 14 Feb 2014 21:38:59 +0100 Subject: [PATCH 007/478] accord avec "la plupart" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cf http://fr.wiktionary.org/wiki/plupart#Note sauf archaïsme, le verbe est au pluriel --- fr/01-introduction/01-chapter1.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fr/01-introduction/01-chapter1.markdown b/fr/01-introduction/01-chapter1.markdown index 73cb6bee2..fbc0ef1ad 100644 --- a/fr/01-introduction/01-chapter1.markdown +++ b/fr/01-introduction/01-chapter1.markdown @@ -118,7 +118,7 @@ Nous explorerons les bénéfices qu'il y a à penser les données de cette mani ### Presque toutes les opérations sont locales ### -La plupart des opérations de Git ne nécessite que des fichiers et ressources locaux — généralement aucune information venant d'un autre ordinateur du réseau n'est nécessaire. +La plupart des opérations de Git ne nécessitent que des fichiers et ressources locaux — généralement aucune information venant d'un autre ordinateur du réseau n'est nécessaire. Si vous êtes habitué à un CVCS où toutes les opérations sont ralenties par la latence des échanges réseau, cet aspect de Git vous fera penser que les dieux de la vitesse ont octroyé leurs pouvoirs à Git. Comme vous disposez de l'historique complet du projet localement sur votre disque dur, la plupart des opérations semblent instantanées. From f7d948183ea03ec1d8595eb5ebd85ca3297a4824 Mon Sep 17 00:00:00 2001 From: cor Date: Fri, 14 Feb 2014 21:17:52 +0100 Subject: [PATCH 008/478] [nl] Chapter 02. Review, include new command output and add header. Reviewed translations and made them more consistent and in line with the recommendations of the Dutch language institute. Added a header to that effect to the file. Included the new modified command output. --- nl/02-git-basics/01-chapter2.markdown | 530 ++++++++++++++------------ 1 file changed, 293 insertions(+), 237 deletions(-) diff --git a/nl/02-git-basics/01-chapter2.markdown b/nl/02-git-basics/01-chapter2.markdown index 4871c86a3..48f865390 100644 --- a/nl/02-git-basics/01-chapter2.markdown +++ b/nl/02-git-basics/01-chapter2.markdown @@ -1,20 +1,35 @@ + # De basis van Git # -Als je slechts één hoofdstuk kunt lezen om met Git aan de slag te gaan, dan is dit het. Dit hoofdstuk behandelt elk van de basiscommando's, die je nodig hebt om het leeuwendeel van de dingen te doen waarmee je uiteindelijk je tijd met Git zult doorbrengen. Als je dit hoofdstuk doorgenomen hebt, zul je een archief (repository) kunnen configureren en initialiseren, bestanden beginnen en stoppen te volgen en veranderingen te ‘stagen’ en ‘committen’. We laten ook zien hoe je Git kunt instellen zodat het bepaalde bestanden en bestandspatronen negeert, hoe je vergissingen snel en gemakkelijk ongedaan kunt maken, hoe je de geschiedenis van je project kan doorlopen en wijzigingen tussen commits kunt zien, en hoe je kunt pushen en pullen van en naar andere repositories. +Als je slechts één hoofdstuk kunt lezen om met Git aan de slag te gaan, dan is deze het. In dit hoofdstuk worden alle basiscommando's behandeld, die je nodig hebben om het leeuwendeel van de dingen te doen waarmee je uiteindelijk je tijd met Git zult doorbrengen. Als je dit hoofdstuk doorgenomen hebt, zul je een repository kunnen configureren en initialiseren, bestanden beginnen en stoppen te volgen en veranderingen te ‘stagen’ en ‘committen’. We laten ook zien hoe je Git kunt instellen zodat het bepaalde bestanden en bestandspatronen negeert, hoe je vergissingen snel en gemakkelijk ongedaan kunt maken, hoe je de geschiedenis van je project kan doorlopen en wijzigingen tussen commits kunt zien, en hoe je kunt pushen en pullen van en naar repositories. ## Een Git repository verkrijgen ## -Je kunt op twee manieren een Git project verkrijgen. De eerste maakt gebruik van een bestaand project of map en importeert dit in Git. De tweede maakt een kloon (clone) van een bestaande Git repository op een andere server. +Je kunt op twee manieren een Git project verkrijgen. De eerste maakt gebruik van een bestaand project of directory en importeert dit in Git. De tweede maakt een kloon (clone) van een bestaande Git repository op een andere server. -### Een repository initialiseren in een bestaande map ### +### Een repository initialiseren in een bestaande directory ### -Als je een bestaand project in Git wilt volgen (track), dan moet je naar de projectmap gaan en het volgende typen +Als je een bestaand project in Git wilt volgen (tracken), dan moet je naar de projectdirectory gaan en het volgende typen $ git init -Dit maakt een nieuwe submap aan genaamd `.git`, die alle noodzakelijke repository bestanden bevat — een Git repository skelet. Op dit punt wordt nog niets in je project gevolgd. (Zie Hoofdstuk 9 voor meer informatie over welke bestanden er precies in de `.git` map staan, die je zojuist gemaakt hebt.) +Dit maakt een nieuwe subdirectory met de naam `.git` aan, die alle noodzakelijke repository bestanden bevat, een Git repository raamwerk. Op dit moment wordt nog niets in je project gevolgd. (Zie *Hoofdstuk 9* voor meer informatie over welke bestanden er precies in de `.git` directory staan, die je zojuist gemaakt hebt.) -Als je de versies van bestaande bestanden wilt gaan beheren (in plaats van een lege map), dan zul je waarschijnlijk die bestanden beginnen te volgen en een eerste commit willen doen. Dit kun je bereiken door een paar git add commando's die de te volgen bestanden specificeren, gevolgd door een commit: +Als je de versies van bestaande bestanden wilt gaan beheren (in plaats van een lege directory), dan zul je die bestanden moeten beginnen te tracken en een eerste commit doen. Dit kun je bereiken door een paar `git add` commando's waarin je de te volgen bestanden specificeert, gevolgd door een commit: $ git add *.c $ git add README @@ -22,44 +37,44 @@ Als je de versies van bestaande bestanden wilt gaan beheren (in plaats van een l We zullen zodadelijk beschrijven wat deze commando's doen. Op dit punt heb je een Git repository met gevolgde (tracked) bestanden en een initiële commit. -### Een bestaand repository klonen ### +### Een bestaand repository clonen ### -Als je een kopie wilt van een bestaande Git repository — bijvoorbeeld een project waaraan je wilt bijdragen — dan is `git clone` het commando wat je nodig hebt. Als je bekend bent met andere versie-beheersystemen zoals Subversion, dan valt je op dat het commando `clone` is en niet `checkout`. Dit is een belangrijk verschil — Git ontvangt een kopie van bijna alle data die de server heeft. Iedere versie van ieder bestand van de hele geschiedenis van een project wordt binnengehaald als je `git clone` doet. In feite kun je, als je disk kapot gaat, iedere kloon van iedere client gebruiken om de server terug in de status te brengen op het moment van klonen (al zou je wel wat hooks en dergelijke verliezen, maar alle versies van alle bestanden zouden er zijn — zie *Hoofdstuk 4* voor meer informatie). +Als je een kopie wilt van een bestaande Git repository, bijvoorbeeld een project waaraan je wilt bijdragen, dan is `git clone` het commando dat je nodig hebt. Als je bekend bent met andere versie-beheersystemen zoals Subversion, dan zal het je opvallen dat het commando `clone` is en niet `checkout`. Dit is een belangrijk verschil: Git ontvangt een kopie van bijna alle gegevens die de server heeft. Elke versie van ieder bestand in de hele geschiedenis van een project wordt binnengehaald als je `git clone` doet. In feite kun je als de schijf van de server kapot gaat, een clone van een willekeurige client gebruiken om de server terug in de status te brengen op het moment van clonen (al zou je wel wat hooks aan de kant van de server en dergelijke verliezen, maar alle versies van alle bestanden zullen er zijn; zie *Hoofdstuk 4* voor meer informatie). -Je kloont een repository met `git clone [url]`. Bijvoorbeeld, als je de Ruby Git bibliotheek genaamd Grit wilt klonen, kun je dit als volgt doen: +Je cloned een repository met `git clone [url]`. Bijvoorbeeld, als je de Ruby Git bibliotheek genaamd Grit wilt clonen, kun je dit als volgt doen: $ git clone git://github.com/schacon/grit.git -Dat maakt een map genaamd `grit` aan, initialiseert hierin een `.git` map, haalt alle data voor dat repository binnen, en doet een checkout van een werkkopie van de laatste versie. Als je in de nieuwe `grit` map gaat, zul je de project bestanden vinden, klaar om gebruikt of aan gewerkt te worden. Als je de repository in een map met een andere naam dan grit wilt klonen, dan kun je dit met het volgende commando specificeren: +Dat maakt een directory genaamd `grit` aan, initialiseert hierin een `.git` directory, haalt alle data voor die repository binnen en doet een checkout van een werkkopie van de laatste versie. Als je in de nieuwe `grit` directory gaat kijken zal je de project bestanden vinden, klaar om gebruikt of aan gewerkt te worden. Als je de repository in een directory met een andere naam dan grit wilt clonen, dan kun je dit met het volgende commando specificeren: $ git clone git://github.com/schacon/grit.git mygrit -Dat commando doet hetzelfde als het vorige, maar dan heet de doelmap `mygrit`. +Dat commando doet hetzelfde als het vorige, maar dan heet de doeldirectory `mygrit`. -Git heeft een aantal verschillende transport protocollen die je kunt gebruiken. Het vorige voorbeeld maakt gebruik van het `git://` protocol, maar je kunt ook `http(s)://` of `gebruiker@server:/pad.git` tegenkomen, dat het SSH transport protocol gebruikt. *Hoofdstuk 4* zal alle beschikbare opties introduceren die de server kan gebruiken om je Git repository aan te kunnen, met daarbij de voors en tegens van elk. +Git heeft een aantal verschillende transport protocollen die je kunt gebruiken. Het vorige voorbeeld maakt gebruik van het `git://` protocol, maar je kunt ook `http(s)://` of `gebruiker@server:/pad.git` tegenkomen, dat het SSH transport protocol gebruikt. *Hoofdstuk 4* zal alle beschikbare opties introduceren die de server kan inrichten om je toegang tot de Git repositories te geven, met daarbij de voors en tegens van elk. ## Wijzigingen aan het repository vastleggen ## -Je hebt een bonafide Git repository en een checkout of werkkopie van de bestanden voor dat project. Je moet wat wijzigingen maken en deze committen in je repository, iedere keer zodra het project een status bereikt die je wilt vastleggen. +Je hebt een eersteklas Git repository en een checkout of werkkopie van de bestanden binnen dat project. Als je wijzigingen maakt dan moet je deze committen in je repository op elk momend dat het project een status bereikt die je wilt vastleggen. -Onthoud dat ieder bestand in je werkmap in twee statussen kan verkeren: *gevolgd (tracked)* of *niet gevolgd (untracked)*. *Gevolgde* bestanden zijn bestanden die in het laatste snapshot zaten; ze kunnen *ongewijzigd*, *gewijzigd* of *staged zijn*. *Niet gevolgde* bestanden zijn al het andere - ieder bestand in je werkmap dat niet in je laatste snapshot en niet in je staging gebied zit. Als je voor het eerst een repository kloont, zullen al je bestanden gevolgd en ongewijzigd zijn, omdat je ze zojuist ge-checkout en niet gewijzigd hebt. +Onthoud dat elk bestand in je werkdirectory in een van twee statussen kan verkeren: *gevolgd (tracked)* of *niet gevolgd (untracked)*. *Tracked* bestanden zijn bestanden die in het laatste snapshot zaten; ze kunnen *ongewijzigd (unmodified)*, *gewijzigd (modified)* of *staged* zijn. *untracked* bestanden zijn al het andere; elk bestand in je werkdirectory dat niet in je laatste snapshot en niet in je staging area zit. Als je een repository voor het eerst cloned, zullen alle bestanden tracked en unmodified zijn, omdat je ze zojuist uitgechecked hebt en nog niets gewijzigd hebt. -Zodra je bestanden wijzigt, ziet Git ze als gewijzigd omdat je ze veranderd hebt sinds je laatste commit. Je *staged* deze gewijzigde bestanden en commit al je ge-stagede wijzigingen, en de cyclus herhaalt zichzelf. Deze cyclus wordt in Figuur 2-1 geïllustreerd. +Zodra je bestanden wijzigt, ziet Git ze als modified omdat je ze veranderd hebt sinds je laatste commit. Je *staged* deze gewijzigde bestanden en commit al je gestagede wijzigingen, en de cyclus begint weer van voor af aan. Deze cyclus wordt in Figuur 2-1 geïllustreerd. Insert 18333fig0201.png Figuur 2-1. De levenscyclus van de status van je bestanden. ### De status van je bestanden controleren ### -Het hoofdcommando dat je zult gebruiken om te bepalen welk bestand zich in welke status bevindt is `git status`. Als je dit commando direct na het klonen uitvoert, dan zul je zoiets als het volgende zien: +Het commando dat je voornamelijk zult gebruiken om te bepalen welk bestand zich in welke status bevindt is `git status`. Als je dit commando direct na het clonen uitvoert, dan zal je zoiets als het volgende zien: $ git status # On branch master nothing to commit (working directory clean) -Dit betekent dat je een schone werkmap hebt — met andere woorden, er zijn geen gevolgde en gewijzigde bestanden. Git ziet ook geen ongevolgde bestanden, anders zouden ze hier getoond worden. Als laatste vertelt het commando op welke tak (branch) je nu zit. Voor nu is dit altijd `master`, dat is de standaard; maak je je hier nog niet druk om. Het volgende hoofdstuk gaat in detail over takken en referenties. +Dit betekent dat je een schone werkdirectory hebt, met andere woorden er zijn geen untracked bestanden die gewijzigd zijn. Git ziet ook geen untracked bestanden, anders zouden ze hier getoond worden. Als laatste vertelt het commando op welke tak (branch) je nu zit. Voor nu is dit altijd `master`, dat is de standaard; besteed daar voor nu nog geen aandacht aan. In het volgende hoofdstuk wordt gedetaileerd ingegaan op branches en referenties. -Stel dat je een nieuw bestand toevoegt aan je project, een simpel README bestand. Als het bestand voorheen nog niet bestond, en je doet `git status`, dan zul je je ongevolgde bestand zo zien: +Stel dat je een nieuw bestand toevoegt aan je project, een simpel README bestand. Als het bestand voorheen nog niet bestond, en je doet `git status`, dan zul je het niet getrackte bestand op deze manier zien: $ vim README $ git status @@ -70,15 +85,15 @@ Stel dat je een nieuw bestand toevoegt aan je project, een simpel README bestand # README nothing added to commit but untracked files present (use "git add" to track) -Je kunt zien dat je nieuwe README bestand ongevolgd is, omdat het onder de “Untracked files” kop staat in je status output. Ongevolgd betekent eigenlijk dat Git een bestand ziet dat je niet in het vorige snapshot (commit) had; Git zal het niet in je commit snapshots toevoegen totdat jij haar er expliciet om vraagt. Ze doet dit zodat jij niet per ongeluk gegenereerde binaire bestanden toevoegt, of andere bestanden die je niet wou toevoegen. Je wilt dit README bestand wel toevoegen, dus laten we het gaan volgen. +Je kunt zien dat het nieuwe README bestand untrackt is, omdat het onder de “Untracked files” kop staat in je status output. Untrackt betekent eigenlijk dat Git een bestand ziet dat je niet in het vorige snapshot (commit) had; Git zal het niet in je commit snapshots toevoegen totdat jij dit expliciet aangeeft. Dit wordt zo gedaan zodat je niet per ongeluk gegenereerde binaire bestanden toevoegt, of andere bestanden die je niet wilt toevoegen. Je wilt dit README bestand wel meenemen, dus laten we het gaan tracken. ### Nieuwe bestanden volgen (tracking) ### -Om een nieuw bestand te beginnen te volgen, gebruik je het commando `git add`. Om de README te volgen, kun je dit uitvoeren: +Om een nieuw bestand te beginnen te tracken, gebruik je het commando `git add`. Om de README te tracken, voer je dit uit: $ git add README -Als je je status commando nogmaals uitvoert, zie je dat je README bestand nu gevolgd en ge-staged is: +Als je het status commando nogmaals uitvoert, zie je dat je README bestand nu getrackt en ge-staged is: $ git status # On branch master @@ -88,26 +103,27 @@ Als je je status commando nogmaals uitvoert, zie je dat je README bestand nu gev # new file: README # -Je kunt zien dat het ge-staged is, omdat het onder de kop “Changes to be committed” staat. Als je op dit punt een commit doet, zal de versie van het bestand zoals het wat ten tijde van je `git add` commando in de historische snapshot toegevoegd worden. Je zult je misschien herinneren dat, toen je `git init` eerder uitvoerde, je daarna `git add` (bestanden) uitvoerde — dat was om bestanden in je map te beginnen te volgen. Het `git add` commando neemt een padnaam voor een bestand of een map; als het een map is, dan voegt het commando alle bestanden in die map recursief toe. +Je kunt zien dat het gestaged is, omdat het onder de kop “Changes to be committed” staat. Als je nu een commit doet, zal de versie van het bestand zoals het was ten tijde van je `git add` commando in de historische snapshot toegevoegd worden. Je zult je misschien herinneren dat, toen je `git init` eerder uitvoerde, je daarna `git add (bestanden)` uitvoerde; dat was om bestanden in je directory te beginnen te tracken. Het `git add` commando beschouwt een padnaam als een bestand of een directory. Als de padnaam een directory is, dan voegt het commando alle bestanden in die directory recursief toe. ### Gewijzigde bestanden stagen ### -Laten we een gevolgd bestand wijzigen. Als je een voorheen gewijzigd bestand genaamd `benchmarks.rb` wijzigt, en dan je `status` commando nog eens uitvoert, krijg je iets dat er zo uitziet: +Laten we een getrackte bestand wijzigen. Als je een reeds getrackt bestand genaamd `benchmarks.rb` wijzigt, en dan je `status` commando nog eens uitvoert, krijg je iets dat er zo uitziet: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README -Het `benchmarks.rb` bestand verschijnt onder een sectie genaamd “Changes not staged for commit” — wat betekent dat een bestand dat gevolgd wordt gewijzigd is in de werkmap, maar nog niet ge-staged. Om het te stagen, voer je het `git add` commando uit (het is een veelzijdig commando — je gebruikt het om bestanden te volgen, om bestanden te stagen, en andere dingen zoals een bestand met een mergeconflict als opgelost te markeren). Laten we `git add` nu uitvoeren om het `benchmarks.rb` bestand nu te stagen, en dan nog eens `git status` uitvoeren: + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Het `benchmarks.rb` bestand verschijnt onder een sectie genaamd “Changes not staged for commit”, wat inhoudt dat een bestand dat wordt getrackt is gewijzigd in de werkdirectory, maar nog niet is gestaged. Om het te stagen, voer je het `git add` commando uit (het is een veelzijdig commando: je gebruikt het om bestanden te laten tracken, om bestanden te stagen, en om andere dingen zoals een bestand met een mergeconflict als opgelost te markeren). Laten we nu `git add` uitvoeren om het `benchmarks.rb` bestand te stagen, en dan nog eens `git status` uitvoeren: $ git add benchmarks.rb $ git status @@ -119,24 +135,25 @@ Het `benchmarks.rb` bestand verschijnt onder een sectie genaamd “Changes not s # modified: benchmarks.rb # -Beide bestanden zijn ge-staged en zullen in je volgende commit gaan. Stel dat je je op dit punt herinnert dat je een kleine wijziging in `benchmarks.rb` wil maken voor je volgende commit. Je kunt het opnieuw openen en die wijziging maken, en dan ben je klaar voor de commit. Maar, laten we `git status` nog een keer uitvoeren: +Beide bestanden zijn gestaged en zullen met je volgende commit meegaan. Stel nu dat je je herinnert dat je nog een kleine wijziging in `benchmarks.rb` wilt maken voordat je het commit. Je kunt het opnieuw openen en die wijziging maken, en dan ben je klaar voor de commit. Alhoewel, laten we `git status` nog een keer uitvoeren: $ vim benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # - -Hé! Nu staat `benchmarks.rb` zowel bij de staged en unstaged. Hoe kan dat? Het blijkt dat Git een bestand staged precies zoals het is wanneer je het `git add` commando uitvoert. Als je nu commit, dan zal de versie van benchmarks.rb zoals het was toen je voor 't laatst `git add` uitvoerde worden toegevoegd in de commit, en niet de versie van het bestand zoals ie eruit ziet in je map wanneer je git commit uitvoert. Als je een bestand wijzigt nadat je `git add` uitvoert, dan moet je `git add` nogmaals uitvoeren om de laatste versie van het bestand te stagen: + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Asjemenou?! Nu staat `benchmarks.rb` zowel bij de staged en unstaged genoemd. Hoe is dat mogelijk? Het blijkt dat Git een bestand precies zoals het is staged wanneer je het `git add` commando uitvoert. Als je nu commit, dan zal de versie van `benchmarks.rb` zoals het was toen je voor 't laatst `git add` uitvoerde worden toegevoegd in de commit, en niet de versie van het bestand zoals het eruit ziet in je werkdirectory toen je `git commit` uitvoerde. Als je een bestand wijzigt nadat je `git add` uitvoert, dan moet je `git add` nogmaals uitvoeren om de laatste versie van het bestand te stagen: $ git add benchmarks.rb $ git status @@ -150,22 +167,22 @@ Hé! Nu staat `benchmarks.rb` zowel bij de staged en unstaged. Hoe kan dat? Het ### Bestanden negeren ### -Vaak zul je een klasse bestanden hebben waarvan je niet wilt dat Git deze automatisch toevoegt of zelfs maar als ongevolgd toont. Dit zijn doorgaans automatisch gegenereerde bestanden zoals logbestanden of bestanden die geproduceerd worden door je bouwsysteem. In die gevallen kun je een bestand genaamd `.gitignore` maken, waarin patronen staan die die bestanden passen. Hier is een voorbeeld van een `.gitignore` bestand: +Vaak zul je een klasse bestanden hebben waarvan je niet wilt dat Git deze automatisch toevoegt of zelfs maar als untracked toont. Dit zijn doorgaans automatisch gegenereerde bestanden zoals logbestanden of bestanden die geproduceerd worden door je bouwsysteem. In die gevallen kun je een bestand genaamd `.gitignore` maken, waarin patronen staan die die bestanden passen. Hier is een voorbeeld van een `.gitignore` bestand: $ cat .gitignore *.[oa] *~ -De eerste regel verteld Git om ieder bestand dat eindigt op een `.o` of `.a` — *object* en *archief* bestanden die het product kunnen zijn van het bouwen van je code. De tweede regel vertelt Git dat ze alle bestanden die eindigen op een tilde (`~`), wat gebruikt wordt door editors zoals Emacs om tijdelijke bestanden te markeren, mag negeren. Je mag ook `log`, `tmp` of een `pid` map toevoegen, automatisch gegenereerde documentatie, enzovoort. Een `.gitignore` bestand aanmaken voordat je gaat beginnen is over 't algemeen een goed idee, zodat je niet per ongeluk bestanden commit die je echt niet in je repository wilt hebben. +De eerste regel vertelt Git om ieder bestand te negeren waarvan de naam eindigt op een `.o` of `.a` (*object* en *archief* bestanden die het product kunnen zijn van het bouwen van je code). De tweede regel vertelt Git dat ze alle bestanden die eindigen op een tilde (`~`), wat gebruikt wordt door editors zoals Emacs om tijdelijke bestanden aan te geven, moet negeren. Je mag ook `log`, `tmp` of een `pid` directory toevoegen, automatisch gegenereerde documentatie, enzovoort. Een `.gitignore` bestand aanmaken voordat je gaat beginnen is over 't algemeen een goed idee, zodat je niet per ongeluk bestanden commit die je echt niet in je repository wilt hebben. De regels voor patronen die je in het `.gitignore` bestand kunt zetten zijn als volgt: * Lege regels of regels die beginnen met een `#` worden genegeerd. -* Standaard expansie patronen werken. -* Je mag patronen laten eindigen op een schuine streep (`/`) om een map te specificeren. +* Standaard expansie (glob) patronen werken. +* Je mag patronen laten eindigen op een schuine streep (`/`) om een directory te specificeren. * Je mag een patroon ontkennend maken door het te laten beginnen met een uitroepteken (`!`). -Expansie (`glob`) patronen zijn vereenvoudigde reguliere expressies die shell omgevingen gebruiken. Een asterisk (`*`) komt overeen met nul of meer karakters; `[abc]` komt overeen met ieder karakter dat tussen de blokhaken staat (in dit geval a, b of c); een vraagteken (`?`) komt overeen met een enkel karakter, en blokhaken waar tussen karakters staan die gescheiden zijn door een streepje (`[0-9]`) komen overeen met ieder karakter wat tussen die karakters zit (in dit geval 0 tot en met 9). +Expansie (`glob`) patronen zijn vereenvoudigde reguliere expressies die in shell omgevingen gebruikt worden. Een asterisk (`*`) komt overeen met nul of meer karakters, `[abc]` komt overeen met ieder karakter dat tussen de blokhaken staat (in dit geval `a`, `b` of `c`), een vraagteken (`?`) komt overeen met een enkel karakter en blokhaken waartussen karakters staan die gescheiden zijn door een streepje (`[0-9]`) komen overeen met ieder karakter wat tussen die karakters zit (in dit geval 0 tot en met 9). Hier is nog een voorbeeld van een `.gitignore` bestand: @@ -181,24 +198,27 @@ Hier is nog een voorbeeld van een `.gitignore` bestand: # ignore doc/notes.txt, but not doc/server/arch.txt doc/*.txt +Een `**/` patroon is sinds versie 1.8.2 beschikbaar in Git. + ### Je staged en unstaged wijzigingen zien ### -Als het `git status` commando te vaag is voor je — je wilt precies weten wat je veranderd hebt, niet alleen welke bestanden veranderd zijn — dan kun je het `git diff` commando gebruiken. We zullen `git diff` later in meer detail bespreken; maar je zult het het meest gebruiken om deze twee vragen te beantwoorden: Wat heb je veranderd maar nog niet gestaged? En wat heb je gestaged en sta je op het punt te committen? Alhoewel `git status` deze vragen heel algemeen beantwoordt, laat `git diff` je de exacte toegevoegde en verwijderde regels zien — de patch, als het ware. +Als het `git status` commando te vaag is voor je, je wilt precies weten wat je veranderd hebt en niet alleen welke bestanden veranderd zijn, dan kun je het `git diff` commando gebruiken. We zullen `git diff` later in meer detail bespreken, maar je zult dit commando het meest gebruiken om deze twee vragen te beantwoorden: Wat heb je veranderd maar nog niet gestaged? En wat heb je gestaged en sta je op het punt te committen? Waar `git status` deze vragen heel algemeen beantwoordt, laat `git diff` je de exacte toegevoegde en verwijderde regels zien, de patch, als het ware. Stel dat je het `README` bestand opnieuw verandert en staged, en dan het `benchmarks.rb` bestand verandert zonder het te stagen. Als je je `status` commando uitvoert, dan zie je nogmaals zoiets als dit: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Om te zien wat je gewijzigd maar nog niet gestaged hebt, typ `git diff` in zonder verdere argumenten: @@ -219,7 +239,7 @@ Om te zien wat je gewijzigd maar nog niet gestaged hebt, typ `git diff` in zonde log = git.commits('master', 15) log.size -Dat commando vergelijkt wat er in je werkmap zit met wat er in je staging gebied zit. Het resultaat laat je zien welke wijzigingen je gedaan hebt, die je nog niet gestaged hebt. +Dat commando vergelijkt wat er in je werkdirectory zit met wat er in je staging area zit. Het resultaat laat je zien welke wijzigingen je gedaan hebt, die je nog niet gestaged hebt. Als je wilt zien wat je gestaged hebt en in je volgende commit zal zitten, dan kun je `git diff –-cached` gebruiken. (In Git versie 1.6.1 en nieuwer kun je ook `git diff --staged` gebruiken, wat misschien beter te onthouden is.) Dit commando vergelijkt je staged wijzigingen met je laatste commit: @@ -236,23 +256,25 @@ Als je wilt zien wat je gestaged hebt en in je volgende commit zal zitten, dan k + +Grit is a Ruby library for extracting information from a Git repository -Het is belangrijk om te zien dat `git diff` zelf niet alle wijzigingen sinds je laatste commit laat zien — alleen wijzigingen die nog niet gestaged zijn. Dit kan verwarrend zijn, omdat als je al je wijzigingen gestaged hebt, `git diff` geen output zal geven. +Het is belangrijk om te zien dat `git diff` zelf niet alle wijzigingen sinds je laatste commit laat zien, alleen wijzigingen die nog niet gestaged zijn. Dit kan verwarrend zijn, omdat als je al je wijzigingen gestaged hebt, `git diff` geen output zal geven. -Nog een voorbeeld. Als je het `benchmarks.rb` bestand staged, en vervolgens verandert, dan kun je `git diff` gebruiken om de wijzigingen in het bestand te zien dat gestaged is en de wijzigingen die niet gestaged zijn: +Nog een voorbeeld. Als je het `benchmarks.rb` bestand staged en vervolgens verandert, dan kun je `git diff` gebruiken om de wijzigingen in het bestand te zien dat gestaged is en de wijzigingen die niet gestaged zijn: $ git add benchmarks.rb $ echo '# test line' >> benchmarks.rb $ git status - # On branch master - # - # Changes to be committed: - # - # modified: benchmarks.rb - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Nu kun je `git diff` gebruiken om te zien wat nog niet gestaged is @@ -288,12 +310,12 @@ en `git diff --cached` om te zien wat je tot nog toe gestaged hebt: ### Je wijzigingen committen ### -Nu dat je staging gebied ingesteld is op de manier zoals jij het wilt, kun je je wijzigingen committen. Onthoud dat alles wat niet gestaged is — ieder bestand dat je gemaakt of gewijzigd hebt en waarop je nog geen `git add` op uitgevoerd hebt — niet in deze commit mee zal gaan. Ze zullen als gewijzigde bestanden op je disk blijven staan. +Nu je staging area gevuld is zoals jij het wilt, kun je de wijzigingen committen. Onthoud dat alles wat niet gestaged is, dus ieder bestand dat je gemaakt of gewijzigd hebt en waarop je nog geen `git add` uitgevoerd hebt, niet in deze commit mee zal gaan. Ze zullen als gewijzigde bestanden op je schijf blijven staan. In dit geval zag je de laatste keer dat je `git status` uitvoerde, dat alles gestaged was. Dus je bent er klaar voor om je wijzigingen te committen. De makkelijkste manier om te committen is om `git commit` in te typen: $ git commit -Dit start de door jou gekozen editor op. (Dit wordt bepaald door de `$EDITOR` omgevingsvariabele in je shell — meestal vim of emacs, alhoewel je dit kunt instellen op welke je ook wilt gebruiken met het `git config --global core.editor` commando zoals je in *Hoofdstuk 1* gezien hebt). +Dit start de door jou gekozen editor op. (Dit wordt bepaald door de `$EDITOR` omgevingsvariabele in je shell, meestal vim of emacs, alhoewel je dit kunt instellen op welke editor je wilt gebruiken met het `git config --global core.editor` commando zoals je in *Hoofdstuk 1* gezien hebt). De editor laat de volgende tekst zien (dit voorbeeld is een Vim scherm): @@ -301,60 +323,62 @@ De editor laat de volgende tekst zien (dit voorbeeld is een Vim scherm): # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # # new file: README # modified: benchmarks.rb + # ~ ~ ~ ".git/COMMIT_EDITMSG" 10L, 283C -Je kunt zien dat de standaard commit boodschap de laatste output van het `git status` commando in commentaar bevat en een lege regel bovenaan. Je kunt deze commentaren verwijderen en je eigen commit boodschap intypen, of je kunt ze laten staan om je eraan te helpen herinneren wat je aan het committen bent. (Om een meer expliciete herinnering van je wijzigingen te zien kun je de `-v` optie meegeven aan `git commit`. Als je dit doet zet git de diff van je verandering in je editor zodat je precies kunt zien wat je gedaan hebt.) Als je de editor verlaat, creëert Git je commit boodschap (zonder de commentaren of de diff). +Je kunt zien dat de standaard commit boodschap de laatste output van het `git status` commando als commentaar bevat en een lege regel bovenaan. Je kunt deze commentaren verwijderen en je eigen commit boodschap intypen, of je kunt ze laten staan om je eraan te helpen herinneren wat je aan het committen bent. (Om een meer expliciete herinnering van je wijzigingen te zien kun je de `-v` optie meegeven aan `git commit`. Als je dit doet zet Git de diff van je veranderingen in je editor zodat je precies kunt zien wat je gedaan hebt.) Als je de editor verlaat, creëert Git je commit boodschap (zonder de commentaren of de diff). -Als alternatief kun je je commit boodschap met het `commit` commando meegeven door hem achter de `-m` optie te specificeren, zoals hier: +Als alternatief kun je de commit boodschap met het `commit` commando meegeven door hem achter de `-m` optie te specificeren, zoals hier: $ git commit -m "Story 182: Fix benchmarks for speed" - [master]: created 463dc4f: "Fix benchmarks for speed" - 2 files changed, 3 insertions(+), 0 deletions(-) + [master 463dc4f] Fix benchmarks for speed + 2 files changed, 3 insertions(+) create mode 100644 README Nu heb je je eerste commit gemaakt! Je kunt zien dat de commit je wat output over zichzelf heeft gegeven: op welke branch je gecommit hebt (`master`), welke SHA-1 checksum de commit heeft (`463dc4f`), hoeveel bestanden er veranderd zijn, en statistieken over toegevoegde en verwijderde regels in de commit. -Onthoud dat de commit de snapshot, die je in je staging gebied ingesteld hebt, opslaat. Alles wat je niet gestaged hebt staat daar nog steeds gewijzigd; je kunt een volgende commit doen om het aan je geschiedenis toe te voegen. Iedere keer dat je een commit doet, leg je een snapshot van je project vast dat je later terug kunt draaien of mee kunt vergelijken. +Onthoud dat de commit de snapshot, die je in je staging area ingesteld hebt, opslaat. Alles wat je niet gestaged hebt staat nog steeds gewijzigd; je kunt een volgende commit doen om het aan je geschiedenis toe te voegen. Iedere keer dat je een commit doet, leg je een snapshot van je project vast dat je later terug kunt draaien of mee kunt vergelijken. -### Het staging gebied overslaan ### +### De staging area overslaan ### -Alhoewel het ontzettend makkelijk kan zijn om commits precies zoals je wilt te maken, is het staging gebied soms iets ingewikkelder dan je in je manier van werken nodig hebt. Als je het staging gebied wilt overslaan, dan biedt Git een makkelijke route binnendoor. Door de `-a` optie aan het `git commit` commando mee te geven, zal Git automatisch ieder bestand dat al getracked wordt voor de commit stagen, zodat je het `git add` gedeelte kunt overslaan: +Alhoewel het ontzettend makkelijk kan zijn om commits precies zoals je wilt te maken, is de staging area soms iets ingewikkelder dan je in je workflow nodig hebt. Als je de staging area wilt overslaan, dan kan je met Git makkelijk de route inkorten. Door de `-a` optie aan het `git commit` commando mee te geven zal Git automatisch ieder bestand dat al getrackt wordt voor de commit stagen, zodat je het `git add` gedeelte kunt overslaan: $ git status - # On branch master - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + no changes added to commit (use "git add" and/or "git commit -a") $ git commit -a -m 'added new benchmarks' [master 83e38c7] added new benchmarks - 1 files changed, 5 insertions(+), 0 deletions(-) + 1 files changed, 5 insertions(+) -Let op dat je nu geen `git add` op het `benchmarks.rb` bestand hoeft te doen voordat je commit. +Merk op dat je nu geen `git add` op het `benchmarks.rb` bestand hoeft te doen voordat je commit. ### Bestanden verwijderen ### -Om een bestand van Git te verwijderen, moet je het van de tracked bestanden verwijderen (om precies te zijn, verwijderen van je staging gebied) en dan een commit doen. Het `git rm` commando doet dat, en verwijdert het bestand ook van je werkmap zodat je het de volgende keer niet als een untracked bestand ziet. +Om een bestand van Git te verwijderen, moet je het van de getrackte bestanden verwijderen (of om precies te zijn: verwijderen van je staging area) en dan een commit doen. Het `git rm` commando doet dat, en verwijdert het bestand ook van je werkdirectory zodat je het de volgende keer niet als een untrackt bestand ziet. -Als je het bestand simpelweg verwijdert uit je werkmap, zal het te zien zijn onder het “Changes not staged for commit” (dat wil zeggen, _unstaged_) gedeelte van je `git status` output: +Als je het bestand simpelweg verwijdert uit je werkdirectory, zal het te zien zijn onder het “Changes not staged for commit” (dat wil zeggen, _unstaged_) gedeelte van je `git status` output: $ rm grit.gemspec $ git status - # On branch master - # - # Changes not staged for commit: - # (use "git add/rm ..." to update what will be committed) - # - # deleted: grit.gemspec - # + On branch master + Changes not staged for commit: + (use "git add/rm ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + deleted: grit.gemspec + + no changes added to commit (use "git add" and/or "git commit -a") Als je daarna `git rm` uitvoert, zal de verwijdering van het bestand gestaged worden: @@ -369,25 +393,25 @@ Als je daarna `git rm` uitvoert, zal de verwijdering van het bestand gestaged wo # deleted: grit.gemspec # -Als je de volgende keer een commit doet, zal het bestand verdwenen zijn en niet meer getracked worden. Als je het bestand veranderd hebt en al aan de index toegevoegd hebt, dan zul je de verwijdering moeten forceren met de `-f` optie. Dit is een veiligheidsmaatregel om te voorkomen dat je per ongeluk data die nog niet in een snapshot zit, en dus niet teruggehaald kan worden uit Git, weggooit. +Als je de volgende keer een commit doet, zal het bestand verdwenen zijn en niet meer getrackt worden. Als je het bestand veranderd hebt en al aan de index toegevoegd, dan zul je de verwijdering moeten forceren met de `-f` optie. Dit is een veiligheidsmaatregel om te voorkomen dat je per ongeluk data die nog niet in een snapshot zit, en dus niet teruggehaald kan worden uit Git, weggooit. -Een ander handigheidje wat je misschien wilt doen is het bestand in je werkmap houden, maar van je staging gebied verwijderen. Met andere woorden, je wilt het bestand misschien op je harde schijf bewaren, maar niet dat Git het bestand nog tracked. Dit is erg handig als je iets vergeten bent aan je `.gitignore` bestand toe te voegen, en het per ongeluk toegevoegd hebt. Zoals een groot logbestand, of een serie `.a` gecompileerde bestanden. Gebruik de `--cached` optie om dit te doen: +Een ander handigheidje wat je misschien wilt gebruiken is het bestand in je werkdirectory houden, maar van je staging area verwijderen. Met andere woorden, je wilt het bestand misschien op je harde schijf bewaren, maar niet dat Git het bestand nog trackt. Dit is erg handig als je iets vergeten bent aan je `.gitignore` bestand toe te voegen, en het per ongeluk toegevoegd hebt. Zoals een groot logbestand, of een serie `.a` gecompileerde bestanden. Gebruik de `--cached` optie om dit te doen: $ git rm --cached readme.txt -Je kunt bestanden, mappen en bestandspatronen aan het `git rm` commando meegeven. Dat betekent dat je zoiets als dit kunt doen +Je kunt bestanden, directories en bestandspatronen aan het `git rm` commando meegeven. Dat betekent dat je zoiets als dit kunt doen $ git rm log/\*.log -Let op de backslash (`\`) voor de `*`. Dit is nodig omdat Git zijn eigen bestandsnaam expansie doet, naast die van je shell. In de Windows systeemconsole moet de backslash worden weggelaten. Dit commando verwijdert alle bestanden die de `.log` extensie hebben in de `log/` map. Of, je kunt zoiets als dit doen: +Let op de backslash (`\`) voor de `*`. Dit is nodig omdat Git zijn eigen bestandsnaam expansie doet, naast die van je shell. In de Windows systeemconsole moet de backslash worden weggelaten. Dit commando verwijdert alle bestanden die de `.log` extensie hebben in de `log/` directory. Of, je kunt zoiets als dit doen: $ git rm \*~ -Dit commando verwijderd alle bestanden die eindigen met `~`. +Dit commando verwijdert alle bestanden die eindigen met `~`. ### Bestanden verplaatsen ### -Anders dan vele andere VCS systemen, traceert Git niet expliciet verplaatsingen van bestanden. Als je een bestand een nieuwe naam geeft in Git, is er geen metadata opgeslagen in Git die vertelt dat je het bestand hernoemd hebt. Maar, Git is slim genoeg om dit alsnog te zien — we zullen bestandsverplaatsing detectie wat later behandelen. +Anders dan vele andere VCS systemen, traceert Git niet expliciet verplaatsingen van bestanden. Als je een bestand een nieuwe naam geeft in Git, is er geen metadata opgeslagen in Git die vertelt dat je het bestand hernoemd hebt. Maar Git is slim genoeg om dit alsnog te zien, we zullen bestandsverplaatsing detectie wat later behandelen. Het is daarom een beetje verwarrend dat Git een `mv` commando heeft. Als je een bestand wilt hernoemen in Git, kun je zoiets als dit doen @@ -397,26 +421,24 @@ en dat werkt prima. Sterker nog, als je zoiets als dit uitvoert en naar de statu $ git mv README.txt README $ git status - # On branch master - # Your branch is ahead of 'origin/master' by 1 commit. - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # renamed: README.txt -> README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + renamed: README.txt -> README + -Maar, dat is gelijk aan het volgende uitvoeren: +Maar dat is gelijk aan het uitvoeren van het volgende: $ mv README.txt README $ git rm README.txt $ git add README -Git komt er impliciet achter dat het om een hernoemd bestand gaat, dus het maakt niet uit of je een bestand op deze manier hernoemt of met het `mv` commando. Het enige echte verschil is dat het `mv` commando slechts één commando is in plaats van drie. En belangrijker nog is dat je iedere applicatie kunt gebruiken om een bestand te hernoemen, en de add/rm later kunt afhandelen, voordat je commit. +Git komt er impliciet achter dat het om een hernoemd bestand gaat, dus het maakt niet uit of je een bestand op deze manier hernoemt of met het `mv` commando. Het enige echte verschil is dat het `mv` commando slechts één commando is in plaats van drie. En belangrijker nog is dat je iedere applicatie kunt gebruiken om een bestand te hernoemen, en de add/rm later kunt afhandelen voordat je commit. ## De commit geschiedenis bekijken ## -Nadat je een aantal commits gecreëerd hebt, of als je een repository met een bestaande commit geschiedenis gekloond hebt, zul je waarschijnlijk terug willen zien wat er gebeurd is. Het meest basale en krachtige tool om dit te doen is het `git log` commando. +Nadat je een aantal commits gemaakt hebt, of als je een repository met een bestaande commit geschiedenis gecloned hebt, zul je waarschijnlijk terug willen zien wat er gebeurd is. Het meest basale en krachtige tool om dit te doen is het `git log` commando. Deze voorbeelden maken gebruik van een eenvoudig project genaamd simplegit dat ik vaak voor demonstraties gebruikt. Om het project op te halen, voer dit uit @@ -443,7 +465,7 @@ Als je `git log` in dit project uitvoert, zou je output moeten krijgen die er on first commit -Zonder argumenten toont `git log` de commits die gedaan zijn in dat repository, in omgekeerde chronologische volgorde. Dat wil zeggen, de meest recente commits worden als eerste getoond. Zoals je kunt zien, toont dit commando iedere commit met zijn SHA-1 checksum, de naam van de auteur en zijn e-mail, de datum van opslaan, en de commit boodschap. +Zonder argumenten toont `git log` de commits die gedaan zijn in die repository, in omgekeerde chronologische volgorde. Dat wil zeggen: de meest recente commits worden als eerste getoond. Zoals je kunt zien, toont dit commando iedere commit met zijn SHA-1 checksum, de naam van de auteur en zijn e-mail, de datum van opslaan, en de commit boodschap. Een gigantisch aantal en variëteit aan opties zijn beschikbaar voor het `git log` commando om je precies te laten zien waar je naar op zoek bent. Hier laten we je de meest gebruikte opties zien. @@ -487,7 +509,28 @@ Een van de meest behulpzame opties is `-p`, wat de diff laat zien van de dingen -end \ No newline at end of file -Deze optie toont dezelfde informatie, maar dan met een diff volgend op ieder item. Dit is erg handig voor een code review, of om snel te zien wat er tijdens een serie commits gebeurd is die een medewerker toegevoegd heeft. +Deze optie toont dezelfde informatie, maar dan met een diff volgend op ieder item. Dit is erg handig voor een code review, of om snel te zien wat er tijdens een reeks commits gebeurd is die een medewerker toegevoegd heeft. + +Soms is het handiger om wijzigingen na te kijken op woordniveau in plaats van op regelniveau. Er is een `--word-diff` optie beschikbaar in Git, die je aan het `git log -p` commando kan toevoegen om een woord diff te krijgen inplaats van de reguliere regel voor regel diff. Woord diff formaat is nogal nutteloos als het wordt toegepast op broncode, maar is erg handig als het wordt toegepast op grote tekstbestanden, zoals boeken of een dissertatie. Hier is een voorbeeld. + + $ git log -U1 --word-diff + commit ca82a6dff817ec66f44342007202690a93763949 + Author: Scott Chacon + Date: Mon Mar 17 21:52:11 2008 -0700 + + changed the version number + + diff --git a/Rakefile b/Rakefile + index a874b73..8f94139 100644 + --- a/Rakefile + +++ b/Rakefile + @@ -7,3 +7,3 @@ spec = Gem::Specification.new do |s| + s.name = "simplegit" + s.version = [-"0.1.0"-]{+"0.1.1"+} + s.author = "Scott Chacon" + +Zoals je kunt zien zijn er geen toegevoegde of verwijderde regels in deze uitvoer zoals in een normale diff. Wijzigingen worden daarentegen binnen de regel getoond. Je kunt het toegevoegde woord zien binnen een `{+ +}` en verwijderde binnen een `[- -]`. Je kunt ook kiezen om de gebruikelijke 3 regels context in de diff uitvoer tot één regel te verminderen, omdat de context nu woorden is, en geen regels. Je kunt dit doen met `-U1` zoals hierboven in het voorbeeld. + Je kunt ook een serie samenvattende opties met `git log` gebruiken. Bijvoorbeeld, als je wat verkorte statistieken bij iedere commit wilt zien, kun je de `--stat` optie gebruiken: $ git log --stat @@ -498,7 +541,7 @@ Je kunt ook een serie samenvattende opties met `git log` gebruiken. Bijvoorbeeld changed the version number Rakefile | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon @@ -507,7 +550,7 @@ Je kunt ook een serie samenvattende opties met `git log` gebruiken. Bijvoorbeeld removed unnecessary test code lib/simplegit.rb | 5 ----- - 1 files changed, 0 insertions(+), 5 deletions(-) + 1 file changed, 5 deletions(-) commit a11bef06a3f659402fe7563abf99ad00de2209e6 Author: Scott Chacon @@ -518,17 +561,17 @@ Je kunt ook een serie samenvattende opties met `git log` gebruiken. Bijvoorbeeld README | 6 ++++++ Rakefile | 23 +++++++++++++++++++++++ lib/simplegit.rb | 25 +++++++++++++++++++++++++ - 3 files changed, 54 insertions(+), 0 deletions(-) + 3 files changed, 54 insertions(+) Zoals je ziet, drukt de `--stat` optie onder iedere commit een lijst gewijzigde bestanden af, hoeveel bestanden gewijzigd zijn, en hoeveel regels in die bestanden zijn toegevoegd en verwijderd. Het toont ook een samenvatting van de informatie aan het einde. -Een andere handige optie is `--pretty`. Deze optie veranderd de log output naar een ander formaat dan de standaard. Er zijn al een paar voorgebouwde opties voor je beschikbaar. De `oneline` optie drukt iedere commit op een enkele regel af, wat handig is als je naar een hoop commits kijkt. Daarnaast tonen de `short`, `full` en `fuller` optie de output in grofweg hetzelfde formaat, maar met minder of meer informatie, respectievelijk: +Een andere handige optie is `--pretty`. Deze optie verandert de log output naar een ander formaat dan de standaard. Er zijn al een paar voorgebouwde opties voor je beschikbaar. De `oneline` optie drukt iedere commit op een eigen regel af, wat handig is als je naar een hoop commits kijkt. Daarnaast tonen de `short`, `full` en `fuller` opties de output in grofweg hetzelfde formaat, maar met minder of meer informatie, respectievelijk: $ git log --pretty=oneline ca82a6dff817ec66f44342007202690a93763949 changed the version number 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test code a11bef06a3f659402fe7563abf99ad00de2209e6 first commit -De meest interessante optie is `format`, waarmee je je eigen log formaat kunt specificeren. Dit is in het bijzonder handig als je output aan het genereren bent voor automatische verwerking — omdat je expliciet het formaat kan specificeren, weet je dat het niet zal veranderen bij volgende versies van Git: +De meest interessante optie is `format`, waarmee je je eigen log uitvoer formaat kunt specificeren. Dit is in het bijzonder handig als je output aan het genereren bent voor automatische verwerking; omdat je expliciet het formaat kan specificeren, weet je dat het niet zal veranderen bij volgende versies van Git: $ git log --pretty=format:"%h - %an, %ar : %s" ca82a6d - Scott Chacon, 11 months ago : changed the version number @@ -536,6 +579,10 @@ De meest interessante optie is `format`, waarmee je je eigen log formaat kunt sp a11bef0 - Scott Chacon, 11 months ago : first commit Tabel 2-1 toont een aantal handige opties die aan format gegeven kunnen worden. + Optie Omschrijving van de Output %H Commit hash @@ -554,7 +601,7 @@ Tabel 2-1 toont een aantal handige opties die aan format gegeven kunnen worden. %cr Committer datum, relatief %s Onderwerp -Je zult je misschien afvragen wat het verschil is tussen _author_ en _committer_. De _auteur_ is de persoon die het werk oorspronkelijk geschreven heeft, en de _committer_ is de persoon die het werk als laatste toegevoegd heeft. Dus als je een patch naar een project stuurt en een van de kernleden voegt de patch toe, dan krijgen jullie beiden de eer — jij als de auteur en het kernlid als de committer. We gaan hier wat verder op in in *Hoofdstuk 5*. +Je zult je misschien afvragen wat het verschil is tussen _author_ en _committer_. De _author_ is de persoon die de patch oorspronkelijk geschreven heeft, en de _committer_ is de persoon die de patch als laatste heeft toegepast. Dus als je een patch naar een project stuurt en een van de kernleden past de patch toe, dan krijgen jullie beiden de eer, jij als de auteur en het kernlid als de committer. We gaan hier wat verder op in in *Hoofdstuk 5*. De `oneline` en `format` opties zijn erg handig in combinatie met een andere `log` optie genaamd `--graph`. Deze optie maakt een mooie ASCII grafiek waarin je branch en merge geschiedenis getoond worden, die we kunnen zien in onze kopie van het Grit project repository: @@ -570,11 +617,17 @@ De `oneline` en `format` opties zijn erg handig in combinatie met een andere `lo * d6016bc require time for xmlschema * 11d191e Merge branch 'defunkt' into local -Dat zijn slechts een paar simpele output formaat opties voor `git log` — er zijn er nog veel meer. Tabel 2-2 toont de opties waarover we het tot nog toe gehad hebben, en wat veel voorkomende formaat opties die je misschien handig vindt, samen met hoe ze de output van het log commando veranderen. +Dat zijn slechts een paar simpele output formaat opties voor `git log`; er zijn er nog veel meer. Tabel 2-2 toont de opties waarover we het tot nog toe gehad hebben, en wat veel voorkomende formaat opties die je misschien handig vindt, samen met hoe ze de output van het `log` commando veranderen. + + Optie Omschrijving -p Toon de patch geïntroduceerd bij iedere commit. - --stat Toon statistieken voor gewijzigde bestanden in iedere commit. + --word-diff Toon de patch in een woord diff formaat. + --stat Toon statistieken voor gewijzigde bestanden per commit. --shortstat Toon alleen de gewijzigde/ingevoegde/verwijderde regel van het --stat commando. --name-only Toon de lijst van bestanden die gewijzigd zijn na de commit informatie. --name-status Toon ook de lijst van bestanden die beïnvloed zijn door de toegevoegde/gewijzigde/verwijderde informatie. @@ -582,20 +635,21 @@ Dat zijn slechts een paar simpele output formaat opties voor `git log` — er zi --relative-date Toon de datum in een relatief formaat (bijvoorbeeld, "2 weken geleden"), in plaats van het volledige datum formaat. --graph Toon een ASCII grafiek van de branch en merge geschiedenis naast de log output. --pretty Toon commits in een alternatief formaat. De opties bevatten oneline, short, full, fuller, en format (waarbij je je eigen formaat specificeert). + --oneline Een gemaks-optie, staat voor `--pretty=oneline --abbrev-commit`. ### Log output limiteren ### -Naast het formatteren van de output, heeft `git log` nog een aantal bruikbare limiterende opties — dat wil zeggen, opties die je een subset van de commits tonen. Je hebt zo'n optie al gezien — de `-2` optie, die slechts de laatste twee commits laat zien. In feite kun je `-` doen, waarbij `n` ieder heel getal is wat de laatste `n` commits laat zien. In feite zul je deze vorm weinig gebruiken, omdat Git standaard alle output door een pager (pagineer applicatie) stuurt zodat je slechts één pagina log output per keer ziet. +Naast het formatteren van de output, heeft `git log` nog een aantal bruikbare limiterende opties; dat wil zeggen, opties die je een subset van de commits tonen. Je hebt zo'n optie al gezien: de `-2` optie, die slechts de laatste twee commits laat zien. Sterker nog: je kunt `-` doen, waarbij `n` een heel getal is om de laatste `n` commits te laten zien. In feite zul je deze vorm weinig gebruiken, omdat Git standaard alle output door een pager (pagineer applicatie) stuurt zodat je de log-uitvoer pagina voor pagina ziet. -Maar, de tijd limiterende opties zoals `--since` en `--until` zijn erg handig. Dit commando bijvoorbeeld, geeft een lijst met commits die gedaan zijn gedurende de laatste twee weken: +Dat gezegd hebbende, zijn de tijd limiterende opties zoals `--since` en `--until` erg handig. Dit commando bijvoorbeeld, geeft een lijst met commits die gedaan zijn gedurende de laatste twee weken: $ git log --since=2.weeks -Dit commando werkt met veel formaten — je kunt een specifieke datum kiezen ("2008-01-15”) of een relatieve datum zoals "2 jaar 1 dag en 3 minuten geleden". +Dit commando werkt met veel formaten: je kunt een specifieke datum kiezen ("2008-01-15”) of een relatieve datum zoals "2 jaar 1 dag en 3 minuten geleden". Je kunt ook de lijst met commits filteren op bepaalde criteria. De `--author` optie laat je filteren op een specifieke auteur, en de `--grep` optie laat je op bepaalde zoekwoorden filteren in de commit boodschappen. (Let op dat als je zowel auteur als grep opties wilt specificeren, je `--all-match` moet toevoegen of anders zal het commando ook commits met één van de twee criteria selecteren.) -De laatste echt handige optie om aan `git log` als filter mee te geven is een pad. Als je een map of bestandsnaam opgeeft, kun je de log output limiteren tot commits die een verandering introduceren op die bestanden. Dit is altijd de laatste optie en wordt over het algemeen vooraf gegaan door dubbele streepjes (`--`) om de paden van de opties te scheiden. +De laatste echt handige optie om aan `git log` als filter mee te geven is een pad. Als je een directory of bestandsnaam opgeeft, kun je de log output limiteren tot commits die een verandering introduceren op die bestanden. Dit is altijd de laatste optie en wordt over het algemeen vooraf gegaan door dubbele streepjes (`--`) om de paden van de opties te scheiden. In Tabel 2-3 laten we deze en een paar andere veel voorkomende opties zien als referentie. @@ -621,16 +675,16 @@ Van de bijna 20.000 commits in de Git broncode historie, laat dit commando de 6 ### Een grafische interface gebruiken om de historie te visualiseren ### -Als je een meer grafische applicatie wilt gebruiken om je commit historie te visualiseren, wil je misschien een kijkje nemen naar het Tcl/Tk programma genaamd `gitk` dat met Git meegeleverd wordt. Gitk is eigenlijk een visuele `git log`, en het accepteert bijna alle filter opties die `git log` ook accepteert. Als je `gitk` in op de commandoregel in je project typt, zou je zoiets als in Figuur 2-2 moeten zien. +Als je een meer grafische applicatie wilt gebruiken om je commit historie te visualiseren, wil je misschien een kijkje nemen naar het Tcl/Tk programma genaamd `gitk` dat met Git meegeleverd wordt. Gitk is eigenlijk een visuele `git log` tool, en het accepteert bijna alle filter opties die `git log` ook accepteert. Als je `gitk` in op de commandoregel in je project typt, zou je zoiets als in Figuur 2-2 moeten zien. Insert 18333fig0202.png Figuur 2-2. De gitk historie visualiseerder. -Je kunt de commit historie in de bovenste helft van het scherm zien, samen met een afkomst graaf. De diff in de onderste helft van het scherm laat je de veranderingen zien die bij iedere commit die je aanklikt geïntroduceerd zijn. +Je kunt de commit historie in de bovenste helft van het scherm zien, samen met een afkomst graaf. De diff in de onderste helft van het scherm laat je de veranderingen zien die geïntroduceerd zijn bij iedere commit die je aanklikt. ## Dingen ongedaan maken ## -Op enig moment wil je misschien iets ongedaan maken. Hier zullen we een aantal basis toepassingen laten zien om veranderingen die je gemaakt hebt weer ongedaan te maken. Let op, je kunt niet altijd het ongedaan maken weer ongedaan maken. Dit is één van de weinige gedeeltes in Git waarbij je werk kwijt kunt raken als je het verkeerd doet. +Op enig moment wil je misschien iets ongedaan maken. Hier zullen we een aantal basis tools laten zien om veranderingen die je gemaakt hebt weer ongedaan te maken. Maar pas op, je kunt niet altijd het ongedaan maken weer ongedaan maken. Dit is één van de weinige gedeeltes in Git waarbij je werk kwijt kunt raken als je het verkeerd doet. ### Je laatste commit veranderen ### @@ -638,94 +692,95 @@ Een van de veel voorkomende acties die ongedaan gemaakt moeten worden vinden pla $ git commit --amend -Dit commando neemt je staging gebied en gebruikt dit voor de commit. Als je geen veranderingen sinds je laatste commit hebt gedaan (bijvoorbeeld, je voert dit commando meteen na je laatste commit uit), dan zal je snapshot er precies hetzelfde uitzien en zal je commit boodschap het enige zijn dat je verandert. +Dit commando neemt je staging area en gebruikt dit voor de commit. Als je geen veranderingen sinds je laatste commit hebt gedaan (bijvoorbeeld, je voert dit commando meteen na je laatste commit uit), dan zal je snapshot er precies hetzelfde uitzien en zal je commit boodschap het enige zijn dat je verandert. Dezelfde commit-boodschap editor start op, maar deze bevat meteen de boodschap van je vorige commit. Je kunt de boodschap net als andere keren aanpassen, maar het overschrijft je vorige commit. Bijvoorbeeld, als je commit en je dan realiseert dat je vergeten bent de veranderingen in een bestand dat je wou toevoegen in deze commit te stagen, dan kun je zoiets als dit doen: $ git commit -m 'initial commit' - $ git add forgotten_file + $ git add vergeten_bestand $ git commit --amend -Alledrie van deze commando's eindigen met één commit — de tweede commit vervangt de resultaten van de eerste. +Na deze drie commando's eindig je met één commit; de tweede commit vervangt de resultaten van de eerste. ### Een staged bestand unstagen ### -De volgende twee paragrafen laten zien hoe je je staging gebied en veranderingen in je werkmappen aanpakt. Het fijne gedeelte is dat het commando dat je gebruikt om de status van die gebieden te bepalen, je ook herinnert hoe je de veranderingen eraan ongedaan kunt maken. Bijvoorbeeld, stel dat je twee bestanden gewijzigd hebt en je wilt ze committen als twee aparte veranderingen, maar je typt per ongeluk `git add *` en staged ze allebei. Hoe kun je één van de twee nu unstagen? Het `git status` commando herinnert je eraan: +De volgende twee paragrafen laten zien hoe je de staging area en veranderingen in je werkdirectories aanpakt. Het prettige hier is dat het commando dat je gebruikt om de status van die gebieden te bepalen, je er ook aan herinnert hoe je de veranderingen eraan weer ongedaan kunt maken. Bijvoorbeeld, stel dat je twee bestanden gewijzigd hebt en je wilt ze committen als twee aparte veranderingen, maar je typt per ongeluk `git add *` en staged ze allebei. Hoe kun je één van de twee nu unstagen? Het `git status` commando herinnert je eraan: $ git add . $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + modified: benchmarks.rb + -Recht onder de "Changes to be committed" tekst, staat dat je `git reset HEAD ...` moet gebruiken om te unstagen. Laten we dat advies volgen om het `benchmarks.rb` bestand te unstagen: +Direct onder de "Changes to be committed" tekst, staat dat je `git reset HEAD ...` moet gebruiken om te unstagen. Laten we dat advies volgen om het `benchmarks.rb` bestand te unstagen: $ git reset HEAD benchmarks.rb - benchmarks.rb: locally modified + Unstaged changes after reset: + M benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # - -Het commando is een beetje vreemd, maar het werkt. Het benchmarks.rb bestand is gewijzigd maar weer ge-unstaged. - -### Een gewijzigd bestand ongedaan maken ### - -Wat als je je realiseert dat je je wijzigingen aan het `benchmarks.rb` bestand niet wilt behouden? Hoe kun je dit makkelijk ongedaan maken — terug brengen in de staat waarin het was toen je voor het laatst gecommit hebt (of initieel gekloond, of hoe je het ook in je werkmap gekregen hebt)? Gelukkig vertelt `git status` je ook hoe je dat moet doen. In de laatste voorbeeld output, ziet het unstaged gebied er zo uit: - - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # - -Het vertelt je behoorlijk expliciet hoe je je veranderingen moet weggooien (tenminste, de nieuwere versies van Git, 1.6.1 of nieuwer, doen dit — als je een oudere versie hebt, raden we je ten zeerste aan om het te upgraden zodat je een aantal van deze fijne bruikbaarheidsopties krijgt). Laten we eens doen wat er staat: + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Het commando is een beetje vreemd, maar het werkt. Het benchmarks.rb bestand is gewijzigd maar weer geunstaged. + +### Een gewijzigd bestand weer ongewijzigd maken ### + +Wat als je je realiseert dat je de wijzigingen aan het `benchmarks.rb` bestand niet wilt behouden? Hoe kun je dit makkelijk ongedaan maken; terug brengen in de staat waarin het was toen je voor het laatst gecommit hebt (of initieel gecloned, of hoe je het ook in je werkdirectory gekregen hebt)? Gelukkig vertelt `git status` je ook hoe je dat moet doen. In de laatste voorbeeld output, ziet het unstaged gebied er zo uit: + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Het vertelt je behoorlijk expliciet hoe je je veranderingen moet weggooien (tenminste, de nieuwere versies van Git, 1.6.1 of nieuwer, doen dit. Als je een oudere versie hebt, raden we je ten zeerste aan om het te upgraden zodat je een aantal van deze fijne bruikbaarheidsopties krijgt). Laten we eens doen wat er staat: $ git checkout -- benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + -Je kunt zien dat de veranderingen teruggedraaid zijn. Je moet je ook realiseren dat dit een gevaarlijk commando is: alle veranderingen die je aan dat bestand gedaan hebt zijn weg — je hebt er zojuist een ander bestand overheen gezet. Gebruik dit commando dan ook nooit, tenzij je heel zeker weet dat je het bestand niet wilt. Als je het alleen maar uit de weg wilt hebben, gebruik dan branching of stashing wat we behandelen in het volgende hoofdstuk; dit zijn vaak de betere opties. +Je kunt zien dat de veranderingen teruggedraaid zijn. Je moet je ook beseffen dat dit een gevaarlijk commando is: alle veranderingen die je aan dat bestand gedaan hebt zijn weg; je hebt er zojuist een ander bestand overheen gezet. Gebruik dit commando dan ook nooit, tenzij je heel zeker weet dat je het bestand niet wilt. Als je het alleen maar uit de weg wilt hebben, gebruik dan branching of stashing wat we behandelen in het volgende hoofdstuk; dit zijn vaak de betere opties. Onthoud, alles dat in Git gecommit is kan bijna altijd weer hersteld worden. Zelfs commits die op reeds verwijderde branches gedaan zijn, of commits die zijn overschreven door een `--amend` commit, kunnen weer hersteld worden (zie *Hoofdstuk 9* voor data herstel). Maar, alles wat je verliest dat nog nooit was gecommit is waarschijnlijk voor altijd verloren. ## Werken met remotes ## -Om samen te kunnen werken op ieder Git project, moet je weten hoe je je remote repositories moet beheren. Remote repositories zijn versies van je project, die worden beheerd op het Internet of ergens op een netwerk. Je kunt er meerdere hebben, waarvan ieder ofwel alleen leesbaar, of lees- en schrijfbaar is voor jou. Samenwerken met anderen houdt in dat je deze remote repositories kunt beheren en data kunt pushen en pullen op het moment dat je werk moet delen. -Remote repositories beheren houdt ook in hoe je ze moet toevoegen, ongeldige repositories moet verwijderen, meerdere remote branches moet beheren en ze als tracked of niet kunt definiëren, en meer. In deze sectie zullen we deze remote-beheer vaardigheden behandelen. +Om samen te kunnen werken op eender welke Git project, moet je weten hoe je de remote repositories moet beheren. Remote repositories zijn versies van je project, die worden beheerd op het Internet of ergens op een netwerk. Je kunt er meerdere hebben, waarvan over het algemeen ieder ofwel alleen leesbaar, of lees- en schrijfbaar is voor jou. Samenwerken met anderen houdt in dat je deze remote repositories kunt beheren en data kunt pushen en pullen op het moment dat je werk moet delen. +Remote repositories beheren houdt ook in weten hoe je ze moet toevoegen, ongeldige repositories moet verwijderen, meerdere remote branches moet beheren en ze als tracked of niet kunt definiëren, en meer. In deze sectie zullen we deze remote-beheer vaardigheden behandelen. ### Laat je remotes zien ### -Om te zien welke remote servers je geconfigureerd hebt, kun je het `git remote` commando uitvoeren. Het laat de verkorte namen van iedere remote alias zien die je gespecificeerd hebt. Als je je repository gekloond hebt, dan zul je op z'n minst de *origin* zien — dat is de standaard naam die Git aan de server geeft waarvan je gekloond hebt: +Om te zien welke remote servers je geconfigureerd hebt, kun je het `git remote` commando uitvoeren. Het laat de verkorte namen van iedere remote alias zien die je gespecificeerd hebt. Als je de repository gecloned hebt, dan zul je op z'n minst de *origin* zien; dat is de standaard naam die Git aan de server geeft waarvan je gecloned hebt: $ git clone git://github.com/schacon/ticgit.git - Initialized empty Git repository in /private/tmp/ticgit/.git/ - remote: Counting objects: 595, done. - remote: Compressing objects: 100% (269/269), done. - remote: Total 595 (delta 255), reused 589 (delta 253) - Receiving objects: 100% (595/595), 73.31 KiB | 1 KiB/s, done. - Resolving deltas: 100% (255/255), done. + Cloning into 'ticgit'... + remote: Reusing existing pack: 1857, done. + remote: Total 1857 (delta 0), reused 0 (delta 0) + Receiving objects: 100% (1857/1857), 374.35 KiB | 193.00 KiB/s, done. + Resolving deltas: 100% (772/772), done. + Checking connectivity... done. $ cd ticgit $ git remote origin @@ -733,7 +788,8 @@ Om te zien welke remote servers je geconfigureerd hebt, kun je het `git remote` Je kunt ook `-v` specificeren, wat je de URL laat zien die Git bij de verkorte naam heeft opgeslagen om naar geëxpandeerd te worden: $ git remote -v - origin git://github.com/schacon/ticgit.git + origin git://github.com/schacon/ticgit.git (fetch) + origin git://github.com/schacon/ticgit.git (push) Als je meer dan één remote hebt, dan laat het commando ze allemaal zien. Bijvoorbeeld, mijn Grit repository ziet er ongeveer zo uit. @@ -745,11 +801,11 @@ Als je meer dan één remote hebt, dan laat het commando ze allemaal zien. Bijvo koke git://github.com/koke/grit.git origin git@github.com:mojombo/grit.git -Dit betekent dat we vrij gemakkelijk de bijdragen van ieder van deze gebruikers naar binnen kunnen pullen. Let op dat alleen de origin een SSH URL is, dus dat is de enige waar ik naartoe kan pushen (we laten het waarom zien in *Hoofdstuk 4*). +Dit betekent dat we vrij gemakkelijk de bijdragen van ieder van deze gebruikers naar binnen kunnen pullen. Maar merk ook op dat alleen de origin een SSH URL is, dus dat is de enige waar ik naartoe kan pushen (we laten in *Hoofdstuk 4* zien waarom dat zo is). ### Remote repositories toevoegen ### -Ik heb het toevoegen van remote repositories al genoemd en getoond in vorige secties, maar hier toon ik het expliciet. Om een nieuw Git remote repository als een makkelijk te refereren alias toe te voegen, voer `git remote add [verkorte naam] [url]` uit: +Ik heb het toevoegen van remote repositories al genoemd en getoond in vorige paragrafen, maar hier toon ik expliciet hoe dat gedaan wordt. Om een nieuw Git remote repository als een makkelijk te refereren alias toe te voegen, voer je `git remote add [verkorte naam] [url]` uit: $ git remote origin @@ -758,7 +814,7 @@ Ik heb het toevoegen van remote repositories al genoemd en getoond in vorige sec origin git://github.com/schacon/ticgit.git pb git://github.com/paulboone/ticgit.git -Nu kun je de naam pb in de shell gebruiken in plaats van de hele URL. Bijvoorbeeld, als je alle informatie die Paul wel, maar jij niet in je repository wilt fetchen, dan kun je git fetch pb uitvoeren: +Nu kun je de naam pb op de commandoregel gebruiken in plaats van de hele URL. Bijvoorbeeld, als je alle informatie die Paul wel, maar jij niet in je repository wilt fetchen, dan kun je git fetch pb uitvoeren: $ git fetch pb remote: Counting objects: 58, done. @@ -769,7 +825,7 @@ Nu kun je de naam pb in de shell gebruiken in plaats van de hele URL. Bijvoorbee * [new branch] master -> pb/master * [new branch] ticgit -> pb/ticgit -Paul zijn master branch is lokaal toegankelijk als `pb/master` — je kunt het in een van jouw branches mergen, of je kunt een lokale branch uitchecken op dat punt als je het wil zien. +Paul zijn master branch is lokaal toegankelijk als `pb/master`; je kunt het in een van jouw branches mergen, of je kunt een lokale branch uitchecken op dat punt als je het wil zien. ### Van je remotes fetchen en pullen ### @@ -777,19 +833,19 @@ Zoals je zojuist gezien hebt, kun je om data van je remote projecten te halen di $ git fetch [remote-name] -Het commando gaat naar het remote project en haalt alle data van dat remote project dat jij nog niet hebt. Nadat je dit gedaan hebt, zou je references (referenties) naar alle branches van dat remote moeten hebben, die je op ieder tijdstip kunt mergen en bekijken. (We zullen zien wat branches precies zijn, en hoe je ze moet gebruiken in meer detail in *Hoofdstuk 3*.) +Het commando gaat naar het remote project en haalt alle data van dat remote project dat jij nog niet hebt. Nadat je dit gedaan hebt, zou je references (referenties) naar alle branches van dat remote moeten hebben, die je op ieder tijdstip kunt mergen en bekijken. (We zullen in meer detail zien wat branches precies zijn, en hoe je ze moet gebruiken in *Hoofdstuk 3*.) -Als je een repository kloont, voegt dat commando dat remote repository automatisch toe onder de naam *origin*. Dus `git fetch origin` fetched (haalt) ieder nieuw werk dat gepusht is naar die server sinds je gekloond hebt (of voor het laatst ge-fetched hebt). Het is belangrijk om te weten dat het fetch commando de data naar je locale repository haalt — het merged niet automatisch met je werk of verandert waar je momenteel aan zit te werken. Je kunt het handmatig in je werk mergen als je er klaar voor bent. +Als je een repository cloned, voegt dat commando die remote repository automatisch toe onder de naam *origin*. Dus `git fetch origin` fetcht (haalt) ieder nieuw werk dat gepusht is naar die server sinds je gecloned hebt (of voor het laatst gefetcht hebt). Het is belangrijk om te weten dat het fetch commando de data naar je locale repository haalt; het merged niet automatisch met je werk of verandert waar je momenteel aan zit te werken. Je moet het handmatig in je werk mergen wanneer je er klaar voor bent. -Als je een branch geconfigureerd hebt om een remote branch te tracken (volgen) (zie de volgende sectie en *Hoofdstuk 3* voor meer informatie), dan kun je het `git pull` commando gebruiken om automatisch een remote branch te fetchen en mergen in je huidige branch. Dit kan makkelijker of meer comfortabel zijn voor je werkwijze; en standaard stelt het `git clone` commando je lokale master branch zo in dat het de remote master branch van de server waarvan je gekloond hebt volgt (aangenomen dat de remote een master branch heeft). Over het algemeen zal een `git pull` dat van de server waarvan je origineel gekloond hebt halen en proberen het automatisch in de code waar je op dat moment aan zit te werken te mergen. +Als je een branch geconfigureerd hebt om een remote branch te volgen (tracken) (zie de volgende paragraaf en *Hoofdstuk 3* voor meer informatie), dan kun je het `git pull` commando gebruiken om automatisch een remote branch te fetchen en mergen in je huidige branch. Dit kan makkelijker of meer comfortabele workflow zijn voor je; en standaard stelt het `git clone` commando je lokale master branch zo in dat het de remote master branch van de server waarvan je gecloned hebt volgt (aangenomen dat de remote een master branch heeft). Over het algemeen zal een `git pull` dat van de server waarvan je origineel gecloned hebt halen en proberen het automatisch in de code waar je op dat moment aan zit te werken te mergen. -### Je remotes pushen ### +### Naar je remotes pushen ### -Wanneer je je project op een punt krijgt dat je het wilt delen, dan moet je het stroomopwaarts pushen. Het commando hiervoor is simpel: `git push [remote-name] [branch-name]`. Als je je master branch naar je `origin` server wilt pushen (nogmaals, over het algemeen zet klonen beide namen automatisch goed voor je), dan kun je dit uitvoeren om je werk terug op de server te pushen: +Wanneer je jouw project op een punt hebt dat je het wilt delen, dan moet je het stroomopwaarts pushen. Het commando hiervoor is simpel: `git push [remote-name] [branch-name]`. Als je de master branch naar je `origin` server wilt pushen (nogmaals, over het algemeen zet clonen beide namen automatisch goed voor je), dan kun je dit uitvoeren om je werk terug op de server te pushen: $ git push origin master -Dit commando werkt alleen als je gekloond hebt van een server waarop je schrijfrechten hebt, en als niemand in de tussentijd gepusht heeft. Als jij en iemand anders op hetzelfde tijdstip gekloond hebben en zij pushen stroomopwaarts en dan jij, dan zal je push terecht geweigerd worden. Je zult eerst hun werk moeten pullen en in jouw werk verwerken voordat je toegestaan wordt te pushen. Zie *Hoofdstuk 3* voor meer gedetailleerde informatie over hoe je naar remote servers moet pushen. +Dit commando werkt alleen als je gecloned hebt van een server waarop je schrijfrechten hebt, en als niemand in de tussentijd gepusht heeft. Als jij en iemand anders op hetzelfde tijdstip gecloned hebben en zij pushen eerder stroomopwaarts dan jij, dan zal je push terecht geweigerd worden. Je zult eerst hun werk moeten pullen en in jouw werk verwerken voordat je toegestaan wordt te pushen. Zie *Hoofdstuk 3* voor meer gedetailleerde informatie over hoe je naar remote servers moet pushen. ### Een remote inspecteren ### @@ -804,9 +860,9 @@ Als je meer informatie over een bepaalde remote wilt zien, kun je het `git remot master ticgit -Het toont de URL voor de remote repository, samen met de tracking branch informatie. Het commando vertelt je behulpzaam dat als je op de master branch zit, en je voert `git pull` uit, dan zal het automatisch de master branch op de remote mergen nadat het alle remote references opgehaald heeft. Het toont ook alle remote referenties die het gepulled heeft. +Het toont de URL voor de remote repository samen met de tracking branch informatie. Het commando vertelt je behulpzaam dat als je op de master branch zit en je voert `git pull` uit, dat Git dan automatisch de master branch van de remote zal mergen nadat het alle remote references opgehaald heeft. Het toont ook alle remote referenties die het gepulled heeft. -Dat is een eenvoudig voorbeeld dat je vaak tegenkomt. Als je Git meer intensief gebruikt, zul je veel meer informatie van `git remote show` krijgen: +Dat is een eenvoudig voorbeeld dat je vaak zult tegenkomen. Als je Git echter intensiever gebruikt, zul je veel meer informatie van `git remote show` krijgen: $ git remote show origin * remote origin @@ -841,19 +897,19 @@ Als je een referentie wilt hernoemen, dan kun je in nieuwere versie van Git `git origin paul -Het is de moeite om te melden dat dit ook je remote branch naam verandert. Wat voorheen gerefereerd werd als `pb/master` is nu `paul/master`. +Het is de moeite waard om te melden dat dit ook je remote branch naam verandert. Wat voorheen gerefereerd werd als `pb/master` is nu `paul/master`. -Als je om een of andere reden een referentie wilt verwijderen — je hebt de server verplaatst of je gebruikt een bepaalde spiegel niet meer, of een medewerker doet niet meer mee — dan kun je `git remote rm` gebruiken: +Als je om een of andere reden een referentie wilt verwijderen, je hebt de server verplaatst of je gebruikt een bepaalde mirror niet meer, of een medewerker doet niet meer mee, dan kun je `git remote rm` gebruiken: $ git remote rm paul $ git remote origin -## Labelen ## +## Labelen (Taggen) ## -Zoals de meeste VCS'en, heeft git de mogelijkheid om specifieke punten in de history als belangrijk te taggen (labelen). Over het algemeen gebruiken mensen deze functionaliteit om versie punten te markeren (v1.0, en verder). In deze sectie zul je leren hoe de beschikbare tags te tonen, hoe nieuwe tags te creëren, en wat de verschillende typen tags zijn. +Zoals de meeste VCS'en, heeft git de mogelijkheid om specifieke punten in de history als belangrijk te labelen (taggen). Over het algemeen gebruiken mensen deze functionaliteit om versie punten te markeren (`v1.0`, en zo). In deze paragraaf zul je leren hoe de beschikbare tags te tonen, hoe nieuwe tags te creëren, en wat de verschillende typen tags zijn. -### Je tags laten zien ### +### Jouw tags laten zien ### De beschikbare tags in Git laten zien is rechttoe rechtaan. Type gewoon `git tag`: @@ -861,7 +917,7 @@ De beschikbare tags in Git laten zien is rechttoe rechtaan. Type gewoon `git tag v0.1 v1.3 -Dit commando toont de tags in alfabetische volgorde; de volgorde waarin ze verschijnen heeft geen echt belang. +Dit commando toont de tags in alfabetische volgorde; de volgorde waarin ze verschijnen heeft geen echte betekenis. Je kunt ook zoeken op tags met een bepaald patroon. De Git bron repository, bijvoorbeeld, bevat meer dan 240 tags. Als je alleen geïnteresseerd bent om naar de 1.4.2 serie te kijken, kun je dit uitvoeren: @@ -873,11 +929,11 @@ Je kunt ook zoeken op tags met een bepaald patroon. De Git bron repository, bijv ### Tags creëren ### -Git gebruikt twee soorten tags: lightweight (lichtgewicht) en annotated (beschreven). Een lichtgewicht tag komt overeen met een branch die niet verandert — het is slechts een wijzer naar een specifieke commit. Beschreven tags daarentegen, zijn als volwaardige objecten in de Git database opgeslagen. Ze worden gechecksummed, bevatten de naam van de tagger, e-mail en datum, hebben een tag boodschap, en kunnen gesigneerd en geverifieerd worden met GNU Privacy Guard (GPG). Het wordt over het algemeen aangeraden om beschreven tags te maken zodat je deze informatie hebt; maar als je een tijdelijke tag wilt of om een of andere reden de andere informatie niet wilt houden, dan zijn er ook lichtgewicht tags. +Git gebruikt twee soorten tags: lichtgewicht (lightweight) en beschreven (annotated). Een lightweight tag komt overeen met een branch die niet verandert: het is slechts een wijzer naar een specifieke commit. Annotated tags daarentegen, zijn als volwaardige objecten in de Git database opgeslagen. Ze worden gechecksummed, bevatten de naam van de tagger, e-mail en datum, hebben een tag boodschap, en kunnen gesigneerd en geverifieerd worden met GNU Privacy Guard (GPG). Het wordt over het algemeen aangeraden om annotated tags te maken zodat je deze informatie hebt; maar als je een tijdelijke tag wilt of om een of andere reden de andere informatie niet wilt houden, dan zijn er ook lichtgewicht tags. -### Beschreven tags ### +### Annotated tags ### -Een beschreven tag in Git maken is eenvoudig. Het makkelijkst is om de `-a` optie te specificeren als je het `tag` commando uitvoert: +Een annotated tag in Git maken is eenvoudig. Het makkelijkst is om de `-a` optie te specificeren als je het `tag` commando uitvoert: $ git tag -a v1.4 -m 'my version 1.4' $ git tag @@ -937,9 +993,9 @@ Als je `git show` op die tag uitvoert, dan kun je jouw GPG handtekening eraan va Verderop zul je leren hoe je ondertekende tags kunt verifiëren. -### Lichtgewicht tags ### +### Lightweight tags ### -Een andere manier om een tag te committen is met behulp van een lichtgewicht tag. Dit is in principe de commit checksum in een bestand opgeslagen — er wordt geen andere informatie bijgehouden. Om een lichtgewicht tag te maken voeg je niet de `-a`, `-s` of de `-m` optie toe: +Een andere manier om een tag te committen is met behulp van een lightweight tag. Dit is in principe de commit checksum in een bestand opgeslagen; er wordt geen andere informatie bijgehouden. Om een lightweight tag te maken voeg je niet de `-a`, `-s` noch de `-m` optie toe: $ git tag v1.4-lw $ git tag @@ -985,7 +1041,7 @@ Als je de publieke sleutel van degene die getekend heeft niet hebt, dan krijg je ### Later taggen ### -Je kunt ook commits taggen nadat je verder gegaan bent. Stel dat je commit historie er zo uitziet: +Je kunt ook commits taggen waar je al voorbij bent. Stel dat je commit historie er zo uitziet: $ git log --pretty=oneline 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment' @@ -999,7 +1055,7 @@ Je kunt ook commits taggen nadat je verder gegaan bent. Stel dat je commit histo 964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo 8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme -Nu, stel dat je vergeten bent het project op v1.2 te taggen, daar waar de "updated rakefile" commit was. Je kunt dit nadien toevoegen. Om die commit te taggen, specificeer je de commit boodschap (of een gedeelte daarvan) aan het einde van het commando: +Stel nu dat je vergeten bent het project op v1.2 te taggen, daar waar de "updated rakefile" commit was. Je kunt dit nadien toevoegen. Om die commit te taggen, specificeer je de commit boodschap (of een gedeelte daarvan) aan het einde van het commando: $ git tag -a v1.2 9fceb02 @@ -1038,7 +1094,7 @@ Standaard zal het `git push` commando geen tags naar remote servers versturen. J To git@github.com:schacon/simplegit.git * [new tag] v1.5 -> v1.5 -Als je veel tags hebt die je ineens wilt pushen, kun je ook de `--tags` optie aan het `git push` commando toevoegen. Dit zal al je tags, die nog niet op de remote server zijn, in een keer er naartoe sturen. +Als je veel tags hebt die je ineens wilt pushen, kun je ook de `--tags` optie aan het `git push` commando toevoegen. Dit zal al je tags, die nog niet op de remote server zijn, in één keer er naartoe sturen. $ git push origin --tags Counting objects: 50, done. @@ -1052,7 +1108,7 @@ Als je veel tags hebt die je ineens wilt pushen, kun je ook de `--tags` optie aa * [new tag] v1.4-lw -> v1.4-lw * [new tag] v1.5 -> v1.5 -Als nu iemand anders van jouw repository kloont of pulled, dan zullen zij al jouw tags ook krijgen. +Als nu iemand anders van jouw repository cloned of pulled, dan zullen zij al jouw tags ook krijgen. ## Tips en trucs ## @@ -1060,22 +1116,22 @@ Voordat we dit hoofdstuk over de basis van Git afsluiten laten we je nog wat kle ### Auto-aanvulling ### -Als je de Bash shell gebruikt, heeft Git een fijn auto-aanvulling script dat je aan kunt zetten. Download de Git broncode, en kijk in de `contrib/completion` map; daar zou een bestand genaamd `git-completion.bash` moeten staan. Kopieer dit bestand naar je home map, en voeg dit aan je `.bashrc` bestand toe: +Als je de Bash shell gebruikt, heeft Git een prettige auto-aanvulling script dat je aan kunt zetten. Download het direct van de Git broncode op https://github.com/git/git/blob/master/contrib/completion/git-completion.bash. Kopieer dit bestand naar je home directory, en voeg dit aan je `.bashrc` bestand toe: source ~/.git-completion.bash -Als je Git wilt instellen dat het automatische Bash shell aanvulling heeft voor alle gebruikers, kopieer dit script dan naar de `/opt/local/etc/bash_completion.d` map op Mac systemen, of naar de `/etc/bash_completion.d/` map op Linux systemen. Dit is een map met scripts dat Bash automatisch zal laden om shell aanvullingen aan te bieden. +Als je Git wilt instellen dat het automatische Bash shell aanvulling heeft voor alle gebruikers, kopieer dit script dan naar de `/opt/local/etc/bash_completion.d` directory op Mac systemen, of naar de `/etc/bash_completion.d/` directory op Linux systemen. Dit is een directory met scripts dat Bash automatisch zal laden om shell aanvullingen aan te bieden. Als je Windows gebruikt met Git Bash, wat de standaard is als je Git op Windows installeert met msysGit, dan zou auto-aanvulling voorgeconfigureerd moeten zijn. -Druk de Tab toets als je een Git commando aan het typen bent, en het zou een set suggesties voor je moeten teruggeven: +Druk de Tab toets als je een Git commando aan het typen bent, en het zou een lijstje suggesties voor je moeten teruggeven: $ git co commit config -In dit geval zal git co en dan de Tab toets twee keer indrukken git commit en config voorstellen. `m` toevoegen, vult `git commit` automatisch aan. +In dit geval zal git co en dan de Tab toets twee keer indrukken git commit en config voorstellen. Als je daarna `m` toevoegt, wordt het automatisch tot `git commit` gecompleteerd. -Dit werkt ook met opties, wat waarschijnlijk meer bruikbaar is. Bijvoorbeeld, als je een `git log` commando uitvoert en je niet meer kunt herinneren wat een van de opties is, dan kun je beginnen met het te typen en Tab indrukken om te zien wat er past: +Dit werkt ook met opties, wat nog bruikbaarder is. Bijvoorbeeld, als je een `git log` commando uitvoert en je een van de opties niet meer kunt herinneren, dan kun je beginnen met het te typen en Tab indrukken om te zien wat er past: $ git log --s --shortstat --since= --src-prefix= --stat --summary @@ -1084,16 +1140,16 @@ Dat is een erg handig trucje en zal je misschien wat tijd en documentatie lezen ### Git aliassen ### -Git zal geen commando's raden als je het gedeeltelijk intypt. Als je niet de hele tekst van ieder Git commando wilt intypen, kun je gemakkelijk een alias voor ieder commando configureren door `git config` te gebruiken. Hier zijn een aantal voorbeelden die je misschien wilt instellen: +Git zal geen commando's afleiden uit wat gedeeltelijk intypt. Als je niet de hele tekst van ieder Git commando wilt intypen, kun je gemakkelijk een alias voor ieder commando configureren door `git config` te gebruiken. Hier zijn een aantal voorbeelden die je misschien wilt instellen: $ git config --global alias.co checkout $ git config --global alias.br branch $ git config --global alias.ci commit $ git config --global alias.st status -Dit betekent dat je, bijvoorbeeld, in plaats van `git commit` je alleen `git ci` hoeft in te typen. Als je verder gaat met Git, zul je waarschijnlijk andere commando's ook vaker gaan gebruiken; in dat geval, schroom je niet om nieuwe aliassen te maken. +Dit betekent dat je, bijvoorbeeld, in plaats van `git commit` je alleen `git ci` hoeft in te typen. Als je verder gaat met Git, zul je waarschijnlijk andere commando's ook vaker gaan gebruiken; in dat geval: schroom niet om nieuwe aliassen te maken. -Deze techniek kan ook makkelijk zijn om commando's te maken waarvan je vindt dat ze moeten bestaan. Bijvoorbeeld, om het bruikbaarheidsprobleem wat je met het unstagen van een bestand hebt op te lossen, kun je je eigen unstage alias aan Git toevoegen: +Deze techniek kan ook makkelijk zijn om commando's te maken waarvan je vindt dat ze zouden moeten bestaan. Bijvoorbeeld, om het bruikbaarheidsprobleem wat je met het unstagen van een bestand tegenkwam op te lossen, kun je jouw eigen unstage alias aan Git toevoegen: $ git config --global alias.unstage 'reset HEAD --' @@ -1102,7 +1158,7 @@ Dit maakt de volgende twee commando's equivalent: $ git unstage fileA $ git reset HEAD fileA -Het lijkt wat helderder. Het is ook gebruikelijk om een `last` commando toe te voegen: +Het lijkt wat duidelijker. Het is ook gebruikelijk om een `last` commando toe te voegen: $ git config --global alias.last 'log -1 HEAD' @@ -1117,10 +1173,10 @@ Op deze manier kun je de laatste commit makkelijk zien: Signed-off-by: Scott Chacon -Zoals je kunt zien, vervangt Git eenvoudigweg het nieuwe commando met waarvoor je het gealiassed hebt. Maar, misschien wil je een extern commando uitvoeren, in plaats van een Git subcommando. In dat geval begin je het commando met een `!` karakter. Dit is handig als je je eigen applicaties maakt die met een Git repository werken. We kunnen dit demonstreren door `git visual` een `gitk` te laten uitvoeren: +Zoals je kunt zien, vervangt Git eenvoudigweg het nieuwe commando met hetgeen waarvoor je het gealiassed hebt. Maar, misschien wil je een extern commando uitvoeren, in plaats van een Git subcommando. In dat geval begin je het commando met een `!` karakter. Dit is handig als je je eigen applicaties maakt die met een Git repository werken. We kunnen dit demonstreren door `git visual` een `gitk` te laten uitvoeren: $ git config --global alias.visual '!gitk' ## Samenvatting ## -Op dit punt kun je alle basis locale Git operaties doen – een repository creëren of klonen, wijzigingen maken, de wijzigingen stagen en committen, en de historie bekijken van alle veranderingen die de repository ondergaan heeft. Als volgende gaan we Gits beste optie bekijken: het branching model. +Op dit punt kun je alle basis locale Git operaties doen: een repository creëren of clonen, wijzigingen maken, de wijzigingen stagen en committen en de historie bekijken van alle veranderingen die de repository ondergaan heeft. Als volgende gaan we de beste eigenschap van Git bekijken: het branching model. From b8ab397df0c319b07ddb104ee6d92ee33729bcfc Mon Sep 17 00:00:00 2001 From: cor Date: Sat, 15 Feb 2014 11:57:58 +0100 Subject: [PATCH 009/478] [nl] Chapter 02. More commands straightened On second viewing there were more commands to be corrected. --- nl/02-git-basics/01-chapter2.markdown | 85 ++++++++++++++------------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/nl/02-git-basics/01-chapter2.markdown b/nl/02-git-basics/01-chapter2.markdown index 48f865390..2e9bb5c5a 100644 --- a/nl/02-git-basics/01-chapter2.markdown +++ b/nl/02-git-basics/01-chapter2.markdown @@ -2,7 +2,7 @@ Ik zou het volgende willen voorstellen: Er zijn bepaalde termen die voor de gemiddelde Nederlandse computer gebruiker veel beter klinken (of bekender voorkomen) als de orginele Engelse term. In het begin zullen deze termen niet vaak voorkomen, maar in de meer diepgaandere hoofdstukken komen deze steeds meer voor. Termen als "Committen", "Mergen" en "Applyen" klinken beter dan "Plegen" of "Toepassen", "Samenvoegen" en "Toepassen" (wat bovendien slecht valt te onderscheiden van de commit-toepassing). De mensen die dit boek lezen zijn, naar mijn bescheiden inschatting, al redelijk op de hoogte van versiebeheer en passen (zie ik in de praktijk) deze termen al toe. Een nieuwe terminologie introduceren lijkt me dan ook niet noodzakelijk. -Verder blijven er altijd kreten over als "directory", wat vertaald zou kunnen worden als "map", maar bij het Engelse werkwoord to map, krijgen we dan weer het probleem: hoe dit weer te vertalen. Daarom zou ik willen voorstellen om deze basis-termen toch onvertaald te laten. +Verder blijven er altijd kreten over als "directory", wat vertaald zou kunnen worden als "map", maar bij het Engelse werkwoord to map krijgen we dan weer het probleem: hoe dit weer te vertalen? Daarom zou ik willen voorstellen om deze basis-termen toch onvertaald te laten. Twijfelgevallen zullen altijd blijven zoals de term "file", daarvan wordt in de praktijk zowel de term file als bestand gebruikt. Ik denk dat we hier moeten kijken hoe het in de context past. Maar ook een term als "tool" en (ik zit zelf nog op een mooie Nederlandse term te broeden) "plumbing", hierbij stel ik voor om eenmalig een Nederlandse vertaling te geven, tussen haakjes de Engelse term te geven en in het vervolg de Engelse term te gebruiken. Wederom is de context hier belangrijk. @@ -55,7 +55,7 @@ Git heeft een aantal verschillende transport protocollen die je kunt gebruiken. ## Wijzigingen aan het repository vastleggen ## -Je hebt een eersteklas Git repository en een checkout of werkkopie van de bestanden binnen dat project. Als je wijzigingen maakt dan moet je deze committen in je repository op elk momend dat het project een status bereikt die je wilt vastleggen. +Je hebt een eersteklas Git repository en een checkout of werkkopie van de bestanden binnen dat project. Als je wijzigingen maakt dan moet je deze committen in je repository op elk moment dat het project een status bereikt die je wilt vastleggen. Onthoud dat elk bestand in je werkdirectory in een van twee statussen kan verkeren: *gevolgd (tracked)* of *niet gevolgd (untracked)*. *Tracked* bestanden zijn bestanden die in het laatste snapshot zaten; ze kunnen *ongewijzigd (unmodified)*, *gewijzigd (modified)* of *staged* zijn. *untracked* bestanden zijn al het andere; elk bestand in je werkdirectory dat niet in je laatste snapshot en niet in je staging area zit. Als je een repository voor het eerst cloned, zullen alle bestanden tracked en unmodified zijn, omdat je ze zojuist uitgechecked hebt en nog niets gewijzigd hebt. @@ -78,11 +78,12 @@ Stel dat je een nieuw bestand toevoegt aan je project, een simpel README bestand $ vim README $ git status - # On branch master - # Untracked files: - # (use "git add ..." to include in what will be committed) - # - # README + On branch master + Untracked files: + (use "git add ..." to include in what will be committed) + + README + nothing added to commit but untracked files present (use "git add" to track) Je kunt zien dat het nieuwe README bestand untrackt is, omdat het onder de “Untracked files” kop staat in je status output. Untrackt betekent eigenlijk dat Git een bestand ziet dat je niet in het vorige snapshot (commit) had; Git zal het niet in je commit snapshots toevoegen totdat jij dit expliciet aangeeft. Dit wordt zo gedaan zodat je niet per ongeluk gegenereerde binaire bestanden toevoegt, of andere bestanden die je niet wilt toevoegen. Je wilt dit README bestand wel meenemen, dus laten we het gaan tracken. @@ -96,12 +97,12 @@ Om een nieuw bestand te beginnen te tracken, gebruik je het commando `git add`. Als je het status commando nogmaals uitvoert, zie je dat je README bestand nu getrackt en ge-staged is: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + Je kunt zien dat het gestaged is, omdat het onder de kop “Changes to be committed” staat. Als je nu een commit doet, zal de versie van het bestand zoals het was ten tijde van je `git add` commando in de historische snapshot toegevoegd worden. Je zult je misschien herinneren dat, toen je `git init` eerder uitvoerde, je daarna `git add (bestanden)` uitvoerde; dat was om bestanden in je directory te beginnen te tracken. Het `git add` commando beschouwt een padnaam als een bestand of een directory. Als de padnaam een directory is, dan voegt het commando alle bestanden in die directory recursief toe. @@ -127,13 +128,13 @@ Het `benchmarks.rb` bestand verschijnt onder een sectie genaamd “Changes not s $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + Beide bestanden zijn gestaged en zullen met je volgende commit meegaan. Stel nu dat je je herinnert dat je nog een kleine wijziging in `benchmarks.rb` wilt maken voordat je het commit. Je kunt het opnieuw openen en die wijziging maken, en dan ben je klaar voor de commit. Alhoewel, laten we `git status` nog een keer uitvoeren: @@ -157,13 +158,13 @@ Asjemenou?! Nu staat `benchmarks.rb` zowel bij de staged en unstaged genoemd. Ho $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + ### Bestanden negeren ### @@ -186,16 +187,16 @@ Expansie (`glob`) patronen zijn vereenvoudigde reguliere expressies die in shell Hier is nog een voorbeeld van een `.gitignore` bestand: - # a comment – this is ignored - # no .a files + # een commentaar – dit wordt genegeerd + # geen .a files *.a - # but do track lib.a, even though you're ignoring .a files above + # maar track lib.a wel, ook al negeer je hierboven .a files !lib.a - # only ignore the root TODO file, not subdir/TODO + # negeer alleen de file TODO in de root, niet de subdirectory /TODO /TODO - # ignore all files in the build/ directory + # negeer alle bestanden in de build/ directory build/ - # ignore doc/notes.txt, but not doc/server/arch.txt + # negeer doc/notes.txt, maar niet doc/server/arch.txt doc/*.txt Een `**/` patroon is sinds versie 1.8.2 beschikbaar in Git. @@ -385,13 +386,12 @@ Als je daarna `git rm` uitvoert, zal de verwijdering van het bestand gestaged wo $ git rm grit.gemspec rm 'grit.gemspec' $ git status - # On branch master - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # deleted: grit.gemspec - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + deleted: grit.gemspec + Als je de volgende keer een commit doet, zal het bestand verdwenen zijn en niet meer getrackt worden. Als je het bestand veranderd hebt en al aan de index toegevoegd, dan zul je de verwijdering moeten forceren met de `-f` optie. Dit is een veiligheidsmaatregel om te voorkomen dat je per ongeluk data die nog niet in een snapshot zit, en dus niet teruggehaald kan worden uit Git, weggooit. @@ -653,6 +653,11 @@ De laatste echt handige optie om aan `git log` als filter mee te geven is een pa In Tabel 2-3 laten we deze en een paar andere veel voorkomende opties zien als referentie. + + Optie Omschrijving -(n) Laat alleen de laatste n commits zien --since, --after Limiteer de commits tot degenen na de gegeven datum. From 455bd902287c4eb6eee0cb2fed30d7a5d2c2bee8 Mon Sep 17 00:00:00 2001 From: cor Date: Sat, 15 Feb 2014 12:47:11 +0100 Subject: [PATCH 010/478] [nl] Chapter 02 Move the comment after first text. Aparently the Maruku test checks whether there is any HTML comment at the start (which is equally formed as the comment given in the English text concerning keeping the tabs unmodified. At this point it is not clear to me what this Maruku check consists of. --- nl/02-git-basics/01-chapter2.markdown | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nl/02-git-basics/01-chapter2.markdown b/nl/02-git-basics/01-chapter2.markdown index 2e9bb5c5a..4626bdf0e 100644 --- a/nl/02-git-basics/01-chapter2.markdown +++ b/nl/02-git-basics/01-chapter2.markdown @@ -1,3 +1,5 @@ +# De basis van Git # + -# De basis van Git # Als je slechts één hoofdstuk kunt lezen om met Git aan de slag te gaan, dan is deze het. In dit hoofdstuk worden alle basiscommando's behandeld, die je nodig hebben om het leeuwendeel van de dingen te doen waarmee je uiteindelijk je tijd met Git zult doorbrengen. Als je dit hoofdstuk doorgenomen hebt, zul je een repository kunnen configureren en initialiseren, bestanden beginnen en stoppen te volgen en veranderingen te ‘stagen’ en ‘committen’. We laten ook zien hoe je Git kunt instellen zodat het bepaalde bestanden en bestandspatronen negeert, hoe je vergissingen snel en gemakkelijk ongedaan kunt maken, hoe je de geschiedenis van je project kan doorlopen en wijzigingen tussen commits kunt zien, en hoe je kunt pushen en pullen van en naar repositories. From 15b817362a288fde80039fda186999248f29f73d Mon Sep 17 00:00:00 2001 From: cor Date: Sat, 15 Feb 2014 12:55:21 +0100 Subject: [PATCH 011/478] [nl] Chapter 02 Try to get past Maruku test --- nl/02-git-basics/01-chapter2.markdown | 43 +++++++++++++++++++-------- 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/nl/02-git-basics/01-chapter2.markdown b/nl/02-git-basics/01-chapter2.markdown index 4626bdf0e..e6c210d69 100644 --- a/nl/02-git-basics/01-chapter2.markdown +++ b/nl/02-git-basics/01-chapter2.markdown @@ -1,20 +1,39 @@ -# De basis van Git # - +# De basis van Git # Als je slechts één hoofdstuk kunt lezen om met Git aan de slag te gaan, dan is deze het. In dit hoofdstuk worden alle basiscommando's behandeld, die je nodig hebben om het leeuwendeel van de dingen te doen waarmee je uiteindelijk je tijd met Git zult doorbrengen. Als je dit hoofdstuk doorgenomen hebt, zul je een repository kunnen configureren en initialiseren, bestanden beginnen en stoppen te volgen en veranderingen te ‘stagen’ en ‘committen’. We laten ook zien hoe je Git kunt instellen zodat het bepaalde bestanden en bestandspatronen negeert, hoe je vergissingen snel en gemakkelijk ongedaan kunt maken, hoe je de geschiedenis van je project kan doorlopen en wijzigingen tussen commits kunt zien, en hoe je kunt pushen en pullen van en naar repositories. From ba70a238ee735926170cab45103fc738b55cf68d Mon Sep 17 00:00:00 2001 From: cor Date: Sat, 15 Feb 2014 13:00:49 +0100 Subject: [PATCH 012/478] [nl] Chapter 01 Try to beat Maruku test --- nl/01-introduction/01-chapter1.markdown | 38 +++++++++++++++++++------ 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/nl/01-introduction/01-chapter1.markdown b/nl/01-introduction/01-chapter1.markdown index c423008e7..b7eca8b91 100644 --- a/nl/01-introduction/01-chapter1.markdown +++ b/nl/01-introduction/01-chapter1.markdown @@ -1,15 +1,37 @@ # Aan de slag # From 6c0fd74c8b7931183c8e848e7a82896c69c3b75a Mon Sep 17 00:00:00 2001 From: cor Date: Sat, 15 Feb 2014 13:10:53 +0100 Subject: [PATCH 013/478] [nl] Chapter01 Add additional enter to avoid failing on Maruku test --- nl/01-introduction/01-chapter1.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/nl/01-introduction/01-chapter1.markdown b/nl/01-introduction/01-chapter1.markdown index b7eca8b91..7b8906914 100644 --- a/nl/01-introduction/01-chapter1.markdown +++ b/nl/01-introduction/01-chapter1.markdown @@ -292,3 +292,4 @@ Als de manpage en dit boek niet genoeg zijn en je persoonlijke hulp nodig hebt, ## Samenvatting ## Je zou nu een beetje een idee moeten hebben wat Git is en op welke manieren het verschilt van het versiebeheersysteem dat je misschien eerder gebruikte. Je zou nu ook een werkende versie van Git op je systeem moeten hebben dat is ingesteld met jouw identiteit. Nu is het tijd om een aantal andere grondbeginselen van Git te gaan leren. + From 0fd163a7d34cbbf28d56eafc8a5087ab2d92aa2b Mon Sep 17 00:00:00 2001 From: cor Date: Sat, 15 Feb 2014 13:16:08 +0100 Subject: [PATCH 014/478] [nl] Chapter 02 Try to pass Maruku test --- nl/02-git-basics/01-chapter2.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/nl/02-git-basics/01-chapter2.markdown b/nl/02-git-basics/01-chapter2.markdown index e6c210d69..7592861c2 100644 --- a/nl/02-git-basics/01-chapter2.markdown +++ b/nl/02-git-basics/01-chapter2.markdown @@ -599,6 +599,7 @@ De meest interessante optie is `format`, waarmee je je eigen log uitvoer formaat a11bef0 - Scott Chacon, 11 months ago : first commit Tabel 2-1 toont een aantal handige opties die aan format gegeven kunnen worden. + + The output for this command is a little confusing. Since `clone` is basically a `git init` then a `git fetch`, we see some output from the `git init` part, which creates an empty directory. The actual object transfer gives no output, but it does happen. You should now have a copy of the Git directory data in your `my_project.git` directory. This is roughly equivalent to something like diff --git a/nl/04-git-server/01-chapter4.markdown b/nl/04-git-server/01-chapter4.markdown index 27f3105f7..d87310e71 100644 --- a/nl/04-git-server/01-chapter4.markdown +++ b/nl/04-git-server/01-chapter4.markdown @@ -1,12 +1,47 @@ + # Git op de server # -Je zou nu de alledaagse taken waarvoor je Git zult gebruiken moeten kunnen uitvoeren. Echter, om enige vorm van samenwerking te hebben in Git is een remote repository nodig. Technisch gezien kun je wijzigingen pushen en pullen van individuele repositories, maar dat wordt afgeraden omdat je vrij gemakkelijk het werk waar anderen mee bezig zijn in de war kunt schoppen als je niet oppast. Daarnaast wil je dat je medewerkers de repository kunnen bereiken, zelfs als jouw computer van het netwerk is – het hebben van een betrouwbare gezamenlijke repository is vaak handig. De voorkeursmethode om met iemand samen te werken is om een tussenliggende repository in te richten waar beide partijen toegang tot hebben en om daar naartoe te pushen en vandaan te pullen. We zullen deze repository de `Git server` noemen, maar je zult zien dat het over het algemeen maar weinig systeembronnen kost om een Git repository te verzorgen, dus je zult er zelden een complete server voor nodig hebben. +Je zou nu de alledaagse taken waarvoor je Git zult gebruiken moeten kunnen uitvoeren. Echter, om enige vorm van samenwerking te hebben in Git is een remote Git repository nodig. Technisch gezien kun je wijzigingen pushen en pullen van individuele repositories, maar dat wordt afgeraden omdat je vrij gemakkelijk het werk waar anderen mee bezig zijn in de war kunt schoppen als je niet oppast. Daarnaast wil je dat je medewerkers de repository kunnen bereiken, zelfs als jouw computer van het netwerk is; het hebben van een betrouwbare gezamenlijke repository is vaak handig. De voorkeursmethode om met iemand samen te werken is om een tussenliggende repository in te richten waar beide partijen toegang tot hebben en om daar naartoe te pushen en vandaan te pullen. We zullen deze repository de "Git server" noemen, maar je zult zien dat het over het algemeen maar weinig systeembronnen kost om een Git repository te verzorgen, dus je zult er zelden een complete server voor nodig hebben. -Een Git server draaien is eenvoudig. Als eerste kies je met welke protocollen je de server wilt laten communiceren. Het eerste gedeelte van dit hoofdstuk zullen we de beschikbare protocollen bespreken met de voor- en nadelen van elk. De daarop volgende paragrafen zullen we een aantal veel voorkomende opstellingen bespreken die van die protocollen gebruik maken en hoe je je server ermee kunt opzetten. Als laatste laten we een paar servers van derden zien, als je het niet erg vindt om je code op de server van een ander te zetten en niet het gedoe wilt hebben van het opzetten en onderhouden van je eigen server. +Een Git server draaien is eenvoudig. Als eerste kies je met welke protocollen je de server wilt laten communiceren. In het eerste gedeelte van dit hoofdstuk zullen we de beschikbare protocollen bespreken met de voor- en nadelen van elk. De daarop volgende paragrafen zullen we een aantal veel voorkomende opstellingen bespreken die van die protocollen gebruik maken en hoe je je server ermee kunt opzetten. Als laatste laten we een paar servers van derden zien, als je het niet erg vindt om je code op de server van een ander te zetten en niet het gedoe wilt hebben van het opzetten en onderhouden van je eigen server. Als je niet van plan bent om je eigen server te draaien, dan kun je de direct naar de laatste paragraaf van dit hoofdstuk gaan om wat mogelijkheden van online accounts te zien en dan door gaan naar het volgende hoofdstuk, waar we diverse zaken bespreken die komen kijken bij het werken met een gedistribueerde versiebeheer omgeving. -Een remote repository is over het algemeen een _bare repository_ (kale repository) – een Git repository dat geen werkmap heeft. Omdat de repository alleen gebruikt wordt als een samenwerkingspunt, is er geen reden om een snapshot op de schijf te hebben; het is alleen de Git data. Een kale repository is eenvoudigweg de inhoud van de `.git` map in je project, en niets meer. +Een remote repository is over het algemeen een _bare repository_ (kale repository): een Git repository dat geen werkmap heeft. Omdat de repository alleen gebruikt wordt als een samenwerkingspunt, is er geen reden om een snapshot op de schijf te hebben; het is alleen de Git data. Een kale repository is eenvoudigweg de inhoud van de `.git` directory in je project, en niets meer. ## De protocollen ## @@ -26,7 +61,7 @@ Of je kunt dit doen: $ git clone file:///opt/git/project.git -Git werkt iets anders als je explicite `file://` aan het begin van de URL zet. Als je alleen het pad specificeert, probeert Git hardlinks te gebruiken, of het kopieert de bestanden die het nodig heeft. Als je `file://` specificeert, dan start Git de processen die het normaal gesproken gebruikt om data te transporteren over een netwerk, wat over het algemeen een minder efficiënte methode is om gegevens over te dragen. De belangrijkste reden om `file://` wel te specificeren is als je een schone kopie van de repository wilt met de vreemde referenties of objecten eruit gelaten – over het algemeen na een import uit een ander versiebeheer systeem of iets dergelijks (zie Hoofdstuk 9 voor onderhoudstaken). We zullen het normale pad hier gebruiken, omdat het bijna altijd sneller is om het zo te doen. +Git werkt iets anders als je expliciet `file://` aan het begin van de URL zet. Als je alleen het pad specificeert, probeert Git hardlinks te gebruiken naar de bestanden die het nodig heeft. Als ze niet op hetzelfde bestandssysteem staan zal Git de objecten die het nodig heeft kopiëren, gebruikmakend van het standaard kopieer mechanisme van het besturingssysteem. Als je `file://` specificeert, dan start Git de processen die het normaal gesproken gebruikt om data te transporteren over een netwerk, wat over het algemeen een minder efficiënte methode is om gegevens over te dragen. De belangrijkste reden om `file://` wel te specificeren is als je een schone kopie van de repository wilt met de vreemde referenties of objecten eruit gelaten; over het algemeen na een import uit een ander versiebeheer systeem of iets dergelijks (zie Hoofdstuk 9 voor onderhoudstaken). We zullen het normale pad hier gebruiken, omdat het bijna altijd sneller is om het zo te doen. Om een lokale repository aan een bestaand Git project toe te voegen, kun je iets als het volgende uitvoeren: @@ -36,33 +71,33 @@ Daarna kun je op gelijke wijze pushen naar, en pullen van die remote als je over #### De voordelen #### -De voordelen van bestands-gebaseerde repositories zijn dat ze eenvoudig zijn en ze maken gebruik van bestaande bestandspermissies en netwerk toegang. Als je al een gedeeld bestandssysteem hebt, waar het hele team al toegang toe heeft, dan is een repository opzetten heel gemakkelijk. Je stopt de kale repository ergens waar iedereen gedeelde toegang tot heeft, en stelt de lees- en schrijfrechten in zoals je dat bij iedere andere gedeelde directory zou doen. In de volgende paragraaf "Git op een Server Krijgen" bespreken we hoe je een kopie van een kale repository kunt exporteren voor dit doeleinde. +De voordelen van bestands-gebaseerde repositories zijn dat ze eenvoudig zijn en ze maken gebruik van bestaande bestandspermissies en netwerk toegang. Als je al een gedeeld bestandssysteem hebt waar het hele team al toegang toe heeft, dan is een repository opzetten heel gemakkelijk. Je stopt de kale repository ergens waar iedereen gedeelde toegang tot heeft, en stelt de lees- en schrijfrechten in zoals je dat bij iedere andere gedeelde directory zou doen. In de volgende paragraaf "Git op een Server Krijgen" bespreken we hoe je een kopie van een kale repository kunt exporteren voor dit doeleinde. Dit is ook een prettige optie om snel werk uit een repository van iemand anders te pakken. Als jij en een collega aan hetzelfde project werken, en hij wil dat je iets bekijkt, dan is het uitvoeren van een commando zoals `git pull /home/john/project` vaak makkelijker dan wanneer hij naar een remote server moet pushen, en jij er van moet pullen. #### De nadelen #### -Een van de nadelen van deze methode is dat gedeelde toegang over het algemeen moeilijker op te zetten en te bereiken is vanaf meerdere lokaties dan simpele netwerk toegang. Als je wilt pushen van je laptop als je thuis bent, dan moet je de remote schijf aankoppelen, wat moeilijk en langzaam kan zijn als je het vergelijkt met netwerk gebaseerde toegang. +Één van de nadelen van deze methode is dat gedeelde toegang over het algemeen moeilijker op te zetten en te bereiken is vanaf meerdere lokaties dan simpele netwerk toegang. Als je wilt pushen van je laptop als je thuis bent, dan moet je de remote schijf aankoppelen, wat moeilijk en langzaam kan zijn in vergelijking met met netwerk gebaseerde toegang. -Het is ook belangrijk om te vermelden dat het niet altijd de snelste optie is, als je een gedeeld koppelpunt (mount) of iets dergelijks gebruikt. Een lokale repository is alleen snel als je snelle toegang tot de data hebt. Een repository op NFS is vaak langzamer dan een repository via SSH op dezelfde server omdat dit Git in staat stelt om op lokale schijven te werken op elk van de betrokken systemen. +Het is ook belangrijk om te vermelden dat het niet altijd de snelste optie is als je een gedeeld koppelpunt (mount) of iets dergelijks gebruikt. Een lokale repository is alleen snel als je snelle toegang tot de data hebt. Een repository op NFS is vaak langzamer dan een repository via SSH op dezelfde server omdat dit Git in staat stelt om op lokale schijven te werken op elk van de betrokken systemen. ### Het SSH protocol ### -Waarschijnlijk het meest voorkomende protocol voor Git is SSH. De reden hiervoor is dat toegang met SSH tot servers in veel plaatsen al geconfigureerd is – en als dat niet het geval is, dan is het eenvoudig om dat te doen. SSH is ook het enige netwerk gebaseerde protocol waarvan je makkelijk kunt lezen en naartoe kunt schrijven. De andere twee netwerk protocollen (HTTP en Git) zijn over het algemeen alleen-lezen, dus zelfs als je ze al beschikbaar hebt voor de ongeïnitieerde massas, dan heb je nog steeds SSH nodig voor je eigen schrijfcommandos. SSH is ook een geauthenticieerd protocol; en omdat het alom aanwezig is, is het over het algemeen eenvoudig om in te stellen en te gebruiken. +Waarschijnlijk het meest voorkomende protocol voor Git is SSH. De reden hiervoor is dat toegang met SSH tot servers in veel plaatsen al geconfigureerd is; en als dat niet het geval is, dan is het eenvoudig om dat te doen. SSH is ook het enige netwerk gebaseerde protocol waarvan je makkelijk kunt lezen en naartoe kunt schrijven. De andere twee netwerk protocollen (HTTP en Git) zijn over het algemeen alleen-lezen, dus zelfs als je ze al beschikbaar hebt voor de ongeïnitieerde massa, dan heb je nog steeds SSH nodig voor je eigen schrijfcommandos. SSH is ook een geauthenticieerd protocol; en omdat het alom aanwezig is, is het over het algemeen eenvoudig om in te stellen en te gebruiken. -Om een Git repository via SSH te klonen, kun je een ssh:// URL opgeven zoals: +Om een Git repository via SSH te clonen, kun je een ssh:// URL opgeven zoals: $ git clone ssh://user@server/project.git -Of je geeft geen protocol op — Git gaat uit van SSH als je niet expliciet bent: +Of je gebruikt de kortere scp-achtige syntax voor het SSH protocol: $ git clone user@server:project.git -Je kunt ook de gebruiker weglaten, en Git gebruikt gegevens van de gebruiker waarmee je op dat moment bent ingelogd. +Je kunt ook de gebruiker weglaten, en Git gebruikt de gegevens van de gebruiker waarmee je op dat moment bent ingelogd. #### De voordelen #### -Er zijn vele voordelen om SSH te gebruiken. Ten eerste moet je het eigenlijk wel gebruiken als je geauthenticeerde schrijftoegang op je repository via een netwerk wilt. Ten tweede is het relatief eenvoudig in te stellen – SSH daemons komen veel voor, veel systeembeheerders hebben er ervaring mee, en veel operating systemen zijn er mee uitgerust of hebben applicaties om ze te beheren. Daarnaast is toegang via SSH veilig – alle data transporten zijn versleuteld en geauthenticeerd. En als laatste is SSH efficiënt, net zoals bij het Git en lokale protocol worden de gegevens zo compact mogelijk gemaakt voordat het getransporteerd wordt. +Er zijn vele voordelen om SSH te gebruiken. Ten eerste moet je het eigenlijk wel gebruiken als je geauthenticeerde schrijftoegang op je repository via een netwerk wilt. Ten tweede is het relatief eenvoudig in te stellen: SSH daemons komen veel voor, veel systeembeheerders hebben er ervaring mee, en veel operating systemen zijn er mee uitgerust of hebben applicaties om ze te beheren. Daarnaast is toegang via SSH veilig: alle data transporten zijn versleuteld en geauthenticeerd. En als laatste is SSH efficiënt, net zoals bij het Git en lokale protocol worden de gegevens zo compact mogelijk gemaakt voordat het getransporteerd wordt. #### De nadelen #### @@ -91,19 +126,19 @@ Als laatste hebben we het HTTP protocol. Het mooie aan het HTTP of HTTPS protoco $ mv hooks/post-update.sample hooks/post-update $ chmod a+x hooks/post-update -Dat is alles. De `post-update` hook, die standaard bij Git geleverd wordt, voert het noodzakelijke commando uit (`git update-server-info`) om HTTP fetching en cloning goed werkend te krijgen en houden. Dit commando wordt uitgevoerd als je via SSH naar deze repository pushed, en andere mensen kunnen clonen met behulp van zoiets als +Dat is alles. De `post-update` hook, die standaard bij Git geleverd wordt, voert het noodzakelijke commando (`git update-server-info`) uit om HTTP fetching en cloning goed werkend te krijgen en houden. Dit commando wordt uitgevoerd als je via SSH naar deze repository pusht, en andere mensen kunnen clonen met behulp van zoiets als $ git clone http://example.com/gitproject.git -In dit specifieke voorbeeld gebruiken we het `/var/www/htdocs` pad wat gebruikelijk is voor Apache opstellingen, maar je kunt iedere statische webserver gebruiken – stop de kale repository in het betreffende pad. De Git data wordt geserveerd als standaard statische bestanden (zie hoofdstuk 9 voor details over hoe het precies geserveerd wordt). +In dit specifieke voorbeeld gebruiken we het `/var/www/htdocs` pad wat gebruikelijk is voor Apache opstellingen, maar je kunt iedere statische webserver gebruiken – gewoon de kale repository in het betreffende pad neerzetten. De Git data wordt geserveerd als standaard statische bestanden (zie hoofdstuk 9 voor details over hoe het precies geserveerd wordt). -Het is mogelijk om Git ook over HTTP te laten pushen, alhoewel dat geen veelgebruikte techniek is en het vereist dat je complexe WebDAV instellingen inricht. Omdat het zelden gebruikt wordt, zullen we het niet in dit boek behandelen. Als je geïnteresseerd bent om de HTTP-push protocollen te gebruiken, dan kun je op `http://www.kernel.org/pub/software/scm/git/docs/howto/setup-git-server-over-http.txt` lezen hoe je een repository kunt maken. Het aardige van Git laten pushen over HTTP is dat je iedere WebDAV server kunt gebruiken zonder specifieke Git funtionaliteit, dus je kunt deze optie gebruiken als je web-hosting provider WebDAV ondersteunt voor het maken van wijzigingen aan je webpagina. +Het is mogelijk om Git ook over HTTP te laten pushen, alhoewel dat geen veelgebruikte techniek is en het vereist dat je complexe WebDAV instellingen inricht. Omdat het zelden gebruikt wordt, zullen we het niet in dit boek behandelen. Als je geïnteresseerd bent om de HTTP-push protocollen te gebruiken, dan kun je op `http://www.kernel.org/pub/software/scm/git/docs/howto/setup-git-server-over-http.txt` lezen hoe je een repository kunt maken. Het aardige van Git laten pushen over HTTP is dat je iedere WebDAV server kunt gebruiken zonder specifieke Git funtionaliteit. Dus je kunt deze optie gebruiken als je web-hosting provider WebDAV ondersteunt voor het maken van wijzigingen aan je webpagina. #### De voordelen #### Het voordeel van het gebruik van het HTTP protocol is dat het eenvoudig in te stellen is. Een handvol benodigde commando's uitvoeren is alles wat er moet gebeuren om de wereld leestoegang te geven tot je Git repository. Het neemt maar een paar minuten van je tijd. Het HTTP protocol is niet erg belastend voor de systeembronnen van je server. Omdat het over het algemeen een statische webserver gebruikt om alle data te verspreiden is het moeilijk om zelfs een kleine server te overbelasten - een normale Apache server kan gemiddeld duizenden bestanden zenden per seconde. -Je kunt ook je repositories alleen-lezen serveren via HTTPS, wat inhoudt dat je het gegevenstransport kunt versleutelen; je kunt zelfs zover gaan dat je clients een specifiek gesigneerd SSL certificaat laat gebruiken. Normaal gesproken als je je deze moeite wilt getroosten, dan is het makkelijker om publieke SSH sleutels te gebruiken; maar het kan in jouw specifieke geval een betere oplossing zijn om gesigneerde SSL certificaten of andere HTTP-gebaseerde authenticatie methoden te gebruiken voor alleen-lezen toegang via HTTPS. +Je kunt ook je repositories alleen-lezen serveren via HTTPS, wat inhoudt dat je het gegevenstransport kunt versleutelen. Je kunt zelfs zover gaan dat je clients een specifiek gesigneerd SSL certificaat laat gebruiken. Normaal gesproken als je je deze moeite wilt getroosten, dan is het makkelijker om publieke SSH sleutels te gebruiken; maar het kan in jouw specifieke geval een betere oplossing zijn om gesigneerde SSL certificaten of andere HTTP-gebaseerde authenticatie methoden te gebruiken voor alleen-lezen toegang via HTTPS. Een andere prettige bijkomstigheid is dat HTTP een dusdanig veel voorkomend protocol is dat bedrijfsfirewalls vaak zo ingesteld zijn dat ze verkeer via deze poort toestaan. @@ -114,30 +149,31 @@ Het nadeel van je repository verspreiden via HTTP is dat het relatief inefficië ## Git op een server krijgen ## Om een Git server initieel op te zetten, moet je een bestaande repository naar een kale repository exporteren – een repository dat geen werkmap bevat. Dit is over het algemeen eenvoudig te doen. -Om je repository te clonen met als doel het maken van een kale repository, voer je het clone commando uit met de `--bare` optie. Als conventie eindigen de namen van kale repository mappen met `.git`, zoals hier: +Om je repository te clonen met als doel het maken van een kale repository, voer je het clone commando uit met de `--bare` optie. Als conventie eindigen de namen van kale repository directories met `.git`, zoals hier: $ git clone --bare my_project my_project.git - Initialized empty Git repository in /opt/projects/my_project.git/ + Cloning into bare repository 'my_project.git'... + done. -De output van dit commando is een beetje verwarrend. Het commando `clone` is eigenlijk een `git init` en dan een `git fetch`, wat we hier zien is de output van het `git init` gedeelte wat een lege map aanmaakt. De eigenlijke object overdracht geeft geen output, maar het gebeurt wel. Nu zou je een kopie van de Git map data in je `my_project.git` map moeten hebben. +De output van dit commando is een beetje verwarrend. Het commando `clone` is eigenlijk een `git init` en dan een `git fetch`, wat we hier zien is de output van het `git init` gedeelte wat een lege directory aanmaakt. De eigenlijke object overdracht geeft geen output, maar het gebeurt wel. Nu zou je een kopie van de Git directory data in je `my_project.git` directory moeten hebben. -Dit is ongeveer gelijk aan +Dit is grofweg gelijk aan dit $ cp -Rf my_project/.git my_project.git -Er zijn een paar kleine verschillen in het configuratie bestand, maar het komt op hetzelfde neer. Het neemt de Git repository zelf, zonder een werkmap, en maakt een directory specifiek hiervoor aan. +Er zijn een paar kleine verschillen in het configuratie bestand, maar het komt op hetzelfde neer. Het neemt de Git repository zelf, zonder een werkdirectory, en maakt een directory specifiek hiervoor aan. ### De Kale Repository op een Server Zetten ### -Nu je een kale kopie van je repository hebt, is het enige dat je moet doen het op een server zetten en je protocollen instellen. Laten we aannemen dat je een server ingericht hebt, die `git.example.com` heet, waar je SSH toegang op hebt, en waar je al je Git repositories wilt opslaan onder de `/opt/git` map. Je kunt je nieuwe repository beschikbaar stellen door je kale repository ernaartoe te kopiëren: +Nu je een kale kopie van je repository hebt, is het enige dat je moet doen het op een server zetten en je protocollen instellen. Laten we aannemen dat je een server ingericht hebt die `git.example.com` heet, waar je SSH toegang op hebt, en waar je al je Git repositories wilt opslaan onder de `/opt/git` directory. Je kunt je nieuwe repository beschikbaar stellen door je kale repository ernaartoe te kopiëren: $ scp -r my_project.git user@git.example.com:/opt/git -Vanaf dat moment kunnen andere gebruikers, die SSH toegang hebben tot dezelfde server en lees-toegang hebben tot de `/opt/git` map, jouw repository clonen door dit uit te voeren: +Vanaf dat moment kunnen andere gebruikers, die SSH toegang hebben tot dezelfde server en lees-toegang hebben tot de `/opt/git` directory, jouw repository clonen door dit uit te voeren: $ git clone user@git.example.com:/opt/git/my_project.git -Als een gebruiker met SSH op een server inlogt en schrijftoegang heeft tot de `/opt/git/my_project.git` map, dan hebben ze automatisch ook push toegang. Git zal automatisch de correcte groep schrijfrechten aan een repository toekennen als je het `git init` commando met de `--shared` optie uitvoert. +Als een gebruiker met SSH op een server inlogt en schrijftoegang heeft tot de `/opt/git/my_project.git` directory, dan hebben ze automatisch ook push toegang. Git zal automatisch de correcte groep schrijfrechten aan een repository toekennen als je het `git init` commando met de `--shared` optie uitvoert. $ ssh user@git.example.com $ cd /opt/git/my_project.git @@ -145,7 +181,7 @@ Als een gebruiker met SSH op een server inlogt en schrijftoegang heeft tot de `/ Je ziet hoe eenvoudig het is om een Git repository te nemen, een kale versie aan te maken, en het op een server plaatsen waar jij en je medewerkers SSH toegang tot hebben. Nu zijn jullie klaar om aan hetzelfde project samen te werken. -Het is belangrijk om op te merken dat dit letterlijk alles is wat je moet doen om een bruikbare Git server te draaien waarop meerdere mensen toegang hebben – maak alleen een paar accounts met SSH toegang aan op een server, en stop een kale repository ergens waar al die gebruikers lees- en schrijftoegang toe hebben. Je bent er klaar voor – je hebt niets anders nodig. +Het is belangrijk om op te merken dat dit letterlijk alles is wat je moet doen om een bruikbare Git server te draaien waarop meerdere mensen toegang hebben: maak alleen een paar accounts met SSH toegang aan op een server, en stop een kale repository ergens waar al die gebruikers lees- en schrijftoegang toe hebben. Je bent er klaar voor – je hebt niets anders nodig. In de volgende paragrafen zul je zien hoe je meer ingewikkelde opstellingen kunt maken. Deze bespreking zal het niet hoeven aanmaken van gebruikers accounts voor elke gebruiker, publieke leestoegang tot repositories, grafische web interfaces, het gebruik van de Gitosis applicatie en meer omvatten. Maar, hou in gedachten dat om samen te kunnen werken met mensen op een privé project, alles wat je _nodig_ hebt een SSH server is en een kale repository. @@ -161,20 +197,20 @@ Als je je repositories op een server wilt zetten, die geen accounts heeft voor i Er zijn een paar manieren waarop je iedereen in je team toegang kunt geven. De eerste is voor iedereen accounts aanmaken, wat rechttoe rechtaan is maar bewerkelijk kan zijn. Je wilt vermoedelijk niet `adduser` uitvoeren en tijdelijke wachtwoorden instellen voor iedere gebruiker. -Een tweede methode is een generieke 'git' gebruiker aan te maken op de machine, aan iedere gebruiker die schijftoegang moet hebben vragen of ze je een publieke SSH sleutel sturen, en die sleutel toevoegen aan het `~/.ssh/authorized_keys` bestand van die nieuwe 'git' gebruiker. Vanaf dat moment zal iedereen toegang hebben op die machine via de 'git' gebruiker. Dit tast de commit data op geen enkele manier aan – de SSH gebruiker waarmee je inlogt zal de commits die je opgeslagen hebt niet beïnvloeden. +Een tweede methode is een enkele 'git' gebruiker aan te maken op de machine, aan iedere gebruiker die schijftoegang moet hebben vragen of ze je een publieke SSH sleutel sturen, en die sleutel toevoegen aan het `~/.ssh/authorized_keys` bestand van die nieuwe 'git' gebruiker. Vanaf dat moment zal iedereen toegang hebben op die machine via de 'git' gebruiker. Dit tast de commit data op geen enkele manier aan – de SSH gebruiker waarmee je inlogt zal de commits die je opgeslagen hebt niet beïnvloeden. Een andere manier waarop je het kunt doen is je SSH server laten authenticeren middels een LDAP server of een andere gecentraliseerde authenticatie bron, die misschien al ingericht is. Zolang iedere gebruiker shell toegang kan krijgen op de machine, zou ieder SSH authenticatie mechanisme dat je kunt bedenken moeten werken. ## Je publieke SSH sleutel genereren ## -Dat gezegd hebbende, zijn er vele Git servers die authenticeren met een publieke SSH sleutel. Om een publieke sleutel te hebben, zal iedere gebruiker in je systeem er een moeten genereren als ze er nog geen hebben. Dit proces is bij alle operating systemen vergelijkbaar. Als eerste moet je controleren of je er niet al een hebt. Standaard staan de SSH sleutels van de gebruikers in hun eigen `~/.ssh` map. Je kunt makkelijk nagaan of je al een sleutel hebt door naar die map te gaan en de inhoud te bekijken: +Dat gezegd hebbende, zijn er vele Git servers die authenticeren met een publieke SSH sleutel. Om een publieke sleutel te kunnen aanleveren, zal iedere gebruiker in je systeem er een moeten genereren als ze er nog geen hebben. Dit proces is bij alle operating systemen vergelijkbaar. Als eerste moet je controleren of je er niet al een hebt. Standaard staan de SSH sleutels van de gebruikers in hun eigen `~/.ssh` directory. Je kunt makkelijk nagaan of je al een sleutel hebt door naar die directory te gaan en de inhoud te bekijken: $ cd ~/.ssh $ ls authorized_keys2 id_dsa known_hosts config id_dsa.pub -Je bent op zoek naar een aantal bestanden genaamd iets en iets.pub, waarbij het `iets` meestal zoiets is als `id_dsa` of `id_rsa`. Het `.pub` bestand is je publieke sleutel en het andere bestand is je private sleutel. Als je deze bestanden niet hebt (of als je zelfs geen `.ssh` map hebt), dan kun je ze aanmaken door een applicatie genaamd `ssh-keygen` uit te voeren, deze wordt met het SSH pakket op Linux/Mac systemen meegeleverd en met het MSysGit pakket op Windows: +Je bent op zoek naar een aantal bestanden genaamd iets en iets.pub, waarbij het iets meestal zoiets is als `id_dsa` of `id_rsa`. Het `.pub` bestand is je publieke sleutel en het andere bestand is je private sleutel. Als je deze bestanden niet hebt (of als je zelfs geen `.ssh` directory hebt), dan kun je ze aanmaken door een applicatie genaamd `ssh-keygen` uit te voeren, deze wordt met het SSH pakket op Linux/Mac systemen meegeleverd en met het MSysGit pakket op Windows: $ ssh-keygen Generating public/private rsa key pair. @@ -198,11 +234,11 @@ Iedere gebruiker die dit doet, moet zijn sleutel sturen naar jou of degene die d mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx NrRFi9wrf+M7Q== schacon@agadorlaptop.local -Voor een uitgebreide tutorial over het aanmaken van een SSH sleutel op meerdere operating systemen, verwijzen ze je naar de GitHub handleiding over SSH sleutels op `http://github.com/guides/providing-your-ssh-key`. +Voor een uitgebreidere tutorial over het aanmaken van een SSH sleutel op meerdere operating systemen, verwijzen we je naar de GitHub handleiding over SSH sleutels op `http://github.com/guides/providing-your-ssh-key`. ## De Server Opzetten ## -Laten we het opzetten van SSH toegang aan de server kant eens doorlopen. In dit voorbeeld zul je de `authorized_keys` methode gebruiken om je gebruikers te authenticeren. We gaan er ook vanuit dat je een standaard Linux distributie gebruikt zoals Ubuntu. Als eerste maak je een 'git' gebruiker aan en een `.ssh` map voor die gebruiker. +Laten we het opzetten van SSH toegang aan de server kant eens doorlopen. In dit voorbeeld zul je de `authorized_keys` methode gebruiken om je gebruikers te authenticeren. We gaan er ook vanuit dat je een standaard Linux distributie gebruikt zoals Ubuntu. Als eerste maak je een 'git' gebruiker aan en een `.ssh` directory voor die gebruiker. $ sudo adduser git $ su git @@ -251,7 +287,7 @@ Vanaf dat moment kunnen de anderen het clonen en wijzigingen even gemakkelijk te Op deze manier kun je snel een lees/schrijf Git server draaiend krijgen voor een handjevol ontwikkelaars. -Als een extra voorzorgsmaatregel kun je de 'git' gebruiker makkelijk beperken tot het doen van alleen Git activiteiten, met een gelimiteerde shell applicatie genaamd `git-shell` die bij Git geleverd wordt. +Als een extra voorzorgsmaatregel kun je de 'git' gebruiker makkelijk beperken tot het doen van alleen Git activiteiten, met een gelimiteerde shell tool genaamd `git-shell` die bij Git geleverd wordt. Als je dit als login shell voor je 'git' gebruiker instelt, dan kan de 'git' gebruiker geen normale shell toegang hebben op je server. Specificeer `git-shell` in plaats van bash of csh voor je gebruikers login shell om dit te gebruiken. Om dit te doen zul je waarschijnlijk het `/etc/passwd` bestand aan moeten passen: $ sudo vim /etc/passwd @@ -274,7 +310,7 @@ Nu kan de 'git' gebruiker de SSH connectie alleen gebruiken om Git repositories Wat als je anonieme leestoegang op je project wil? Misschien wil je geen intern privé project beheren, maar een open source project. Of misschien heb je een aantal geautomatiseerde bouwservers of continue integratie servers die vaak wisselen, en wil je niet doorlopend SSH sleutels hoeven genereren – je wil gewoon eenvoudige anonieme leestoegang toevoegen. -Waarschijnlijk is de eenvoudigste manier voor kleinschalige opstellingen om een statische webserver in te stellen, waarbij de document root naar de plaats van je Git repositories wijst, en dan de `post-update` haak aanzetten waar we het in de eerste paragraaf van dit hoofdstuk over gehad hebben. Laten we eens uitgaan van het voorgaande voorbeeld. Stel dat je je repositories in de `/opt/git` map hebt staan, en er draait een Apache server op je machine. Nogmaals, je kunt hiervoor iedere web server gebruiken: maar als voorbeeld zullen we wat simpele Apache configuraties laten zien, die je het idee weergeven van wat je nodig hebt. +Waarschijnlijk is de eenvoudigste manier voor kleinschalige opstellingen om een statische webserver in te stellen, waarbij de document root naar de plaats van je Git repositories wijst, en dan de `post-update` hook aanzetten waar we het in de eerste paragraaf van dit hoofdstuk over gehad hebben. Laten we eens uitgaan van het voorgaande voorbeeld. Stel dat je je repositories in de `/opt/git` directory hebt staan, en er draait een Apache server op je machine. Nogmaals, je kunt hiervoor iedere web server gebruiken: maar als voorbeeld zullen we wat simpele Apache configuraties laten zien, die je het idee weergeven van wat je nodig hebt. Eerst moet je de haak inschakelen: @@ -282,17 +318,22 @@ Eerst moet je de haak inschakelen: $ mv hooks/post-update.sample hooks/post-update $ chmod a+x hooks/post-update -Als je een lagere versie dan 1.6 van Git gebruikt, dan is het `mv` commando niet nodig — Git is recentelijk pas begonnen met de namen van de haak voorbeelden op .sample te laten eindigen. - Wat doet deze `post-update` haak? Het ziet er eigenlijk als volgt uit: $ cat .git/hooks/post-update #!/bin/sh + # + # An example hook script to prepare a packed repository for use over + # dumb transports. + # + # To enable this hook, rename this file to "post-update". + # + exec git-update-server-info Dit betekent dat wanneer je naar de server via SSH pusht, Git dit commando uitvoert om de benodigde bestanden voor HTTP fetching te verversen. -Vervolgens moet je een VirtualHost regel in je Apache configuratie aanmaken, met de document root als de hoofdmap van je Git projecten. Hier nemen we aan dat je wildcard DNS ingesteld hebt om `*.gitserver` door te sturen naar waar je dit alles draait: +Vervolgens moet je een VirtualHost regel in je Apache configuratie aanmaken, met de document root als de hoofddirectory van je Git projecten. Hier nemen we aan dat je wildcard DNS ingesteld hebt om `*.gitserver` door te sturen naar de machine waar je dit alles draait: ServerName git.gitserver @@ -303,11 +344,11 @@ Vervolgens moet je een VirtualHost regel in je Apache configuratie aanmaken, met -Je zult ook de Unix gebruikers groep van de `/opt/git` mappen moeten zetten op `www-data` zodat je web server leestoegang hebt op de repositories, omdat de Apache instantie het CGI script (standaard) uitvoert als die gebruiker draait: +Je zult ook de Unix gebruikers groep van de `/opt/git` directories moeten zetten op `www-data` zodat je web server leestoegang hebt op de repositories, omdat de Apache instantie het CGI script (standaard) uitvoert als die gebruiker draait: $ chgrp -R www-data /opt/git -Als je Apache herstart, dan zou je je repositories onder die map moeten kunnen klonen door de URL van je project te specificeren: +Als je Apache herstart, dan zou je je repositories onder die directory moeten kunnen clonen door de URL van je project te specificeren: $ git clone http://git.gitserver/project.git @@ -320,7 +361,7 @@ Nu je gewone lees/schrijf en alleen-lezen toegang tot je project hebt, wil je mi Insert 18333fig0401.png Figuur 4-1. De GitWeb web-gebaseerde gebruikers interface. -Als je wil zien hoe GitWeb er voor jouw project uitziet, dan heeft Git een commando waarmee je een tijdelijke instantie op kunt starten als je een lichtgewicht server op je systeem hebt zoals `lighttpd` of `webrick`. Op Linux machines is `lighttpd` vaak geïnstalleerd, dus je kunt het misschien draaiend krijgen door `git instaweb` in te typen in je project map. Als je op een Mac werkt: Leopard heeft Ruby voorgeïnstalleerd, dus `webrick` zou je de meeste kans geven. Om `instaweb` met een server anders dan lighttpd te starten, moet je het uitvoeren met de `--httpd` optie. +Als je wil zien hoe GitWeb er voor jouw project uitziet, dan heeft Git een commando waarmee je een tijdelijke instantie op kunt starten als je een lichtgewicht server op je systeem hebt zoals `lighttpd` of `webrick`. Op Linux machines is `lighttpd` vaak geïnstalleerd, dus je kunt het misschien draaiend krijgen door `git instaweb` in te typen in je project directory. Als je op een Mac werkt: Leopard heeft Ruby voorgeïnstalleerd, dus `webrick` zou je de meeste kans geven. Om `instaweb` met een server anders dan lighttpd te starten, moet je het uitvoeren met de `--httpd` optie. $ git instaweb --httpd=webrick [2009-02-21 10:02:21] INFO WEBrick 1.3.1 @@ -359,7 +400,7 @@ Nogmaals, GitWeb kan geserveerd worden met iedere web server die in staat is CGI De publieke sleutels van alle gebruikers in een `authorized_keys` bestand bewaren voor toegang werkt slechts korte tijd goed. Als je honderden gebruikers hebt, dan is het te bewerkelijk om dat proces te blijven volgen. Je moet iedere keer in de server inloggen, en er is geen toegangscontrole – iedereen in het bestand heeft lees- en schrijftoegang op ieder project. -Op dat moment zou je kunnen overwegen een veelgebruikt software project genaamd Gitosis te gaan gebruiken. Gitosis is in feite een verzameling scripts die je helpen het `authorized_keys` bestand te beheren alsmede eenvoudig toegangscontrole te implementeren. Het interessante hieraan is dat de gebruikers interface voor deze applicatie om mensen toe te voegen en toegang te bepalen, geen web interface is maar een speciale Git repository. Je beheert de informatie in dat project en als je het pushed, dan herconfigureert Gitosis de server op basis van dat project, wat best wel slim bedacht is. +Op dat moment zou je kunnen overwegen een veelgebruikt software project genaamd Gitosis te gaan gebruiken. Gitosis is in feite een verzameling scripts die je helpen het `authorized_keys` bestand te beheren alsmede eenvoudig toegangscontrole te implementeren. Het interessante hieraan is dat de gebruikers interface voor deze applicatie om mensen toe te voegen en toegang te bepalen, geen web interface is maar een speciale Git repository. Je beheert de informatie in dat project en als je het pusht, dan herconfigureert Gitosis de server op basis van dat project, wat best wel slim bedacht is. Gitosis installeren is niet de makkelijkste taak ooit, maar het is ook niet al te moeilijk. Het is het makkelijkste om er een Linux server voor te gebruiken – deze voorbeelden gebruiken een standaard Ubuntu 8.10 server. @@ -373,7 +414,7 @@ Vervolgens kloon en installeer je Gitosis van de hoofdpagina van het project: $ cd gitosis $ sudo python setup.py install -Daarmee worden een aantal bestanden geïnstalleerd, die Gitosis zal gebruiken. Daarna wil Gitosis zijn repositories onder `/home/git` stoppen, wat prima is. Maar je hebt je repositories al in `/opt/git` geconfigureerd, dus in plaats van alles te herconfigureren maken we een symbolische link aan: +Daarmee worden een aantal executables geïnstalleerd, die Gitosis zal gebruiken. Daarna wil Gitosis zijn repositories onder `/home/git` stoppen, wat prima is. Maar je hebt je repositories al in `/opt/git` geconfigureerd, dus in plaats van alles te herconfigureren maken we een symbolische link aan: $ ln -s /opt/git /home/git/repositories @@ -395,7 +436,7 @@ Nu wordt het tijd om Gitosis te initialiseren. Je doet dit door het `gitosis-ini Initialized empty Git repository in /opt/git/gitosis-admin.git/ Reinitialized existing Git repository in /opt/git/gitosis-admin.git/ -Dit staat de gebruiker met die sleutel toe de hoofd Git repository, die de Gitosis setup regelt, aan te passen. Daarna zul je met de hand het execute bit op het `post-update` script moeten aanzetten voor je nieuwe beheer repository. +Dit staat de gebruiker met die sleutel toe de hoofd Git repository die de Gitosis setup regelt, aan te passen. Daarna zul je met de hand het execute bit op het `post-update` script moeten aanzetten voor je nieuwe beheer repository. $ sudo chmod 755 /opt/git/gitosis-admin.git/hooks/post-update @@ -403,15 +444,15 @@ Je bent nu klaar voor de start. Als je alles juist hebt ingesteld, kun je nu met $ ssh git@gitserver PTY allocation request failed on channel 0 - fatal: unrecognized command 'gitosis-serve schacon@quaternion' + ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment. Connection to gitserver closed. -Dat betekent dat Gitosis je herkend heeft, maar je buitensluit omdat je geen Git commando's aan het doen bent. Dus, laten we een echt Git commando doen — je gaat de Gitosis beheer repository klonen: +Dat betekent dat Gitosis je herkend heeft, maar je buitensluit omdat je geen Git commando's aan het doen bent. Dus, laten we een echt Git commando doen; je gaat de Gitosis beheer repository clonen: # op je locale computer $ git clone git@gitserver:gitosis-admin.git -Nu heb je een map genaamd `gitosis-admin`, die twee hoofd gedeeltes heeft: +Nu heb je een directory genaamd `gitosis-admin`, die twee hoofd gedeeltes heeft: $ cd gitosis-admin $ find . @@ -419,7 +460,7 @@ Nu heb je een map genaamd `gitosis-admin`, die twee hoofd gedeeltes heeft: ./keydir ./keydir/scott.pub -Het `gitosis.conf` bestand is het beheer bestand dat je zult gebruiken om gebruikers, repositories en permissies te specificeren. De `keydir` map is de plaats waar je de publieke sleutels opslaat van alle gebruikers die een vorm van toegang tot de repositories hebben – één bestand per gebruiker. De naam van het bestand in `keydir` (in het vorige voorbeeld, `scott.pub`) zal anders zijn in jouw geval – Gitosis haalt de naam uit de beschrijving aan het einde van de publieke sleutel die was geïmporteerd met het `gitosis-init` script. +Het `gitosis.conf` bestand is het beheer bestand dat je zult gebruiken om gebruikers, repositories en permissies te specificeren. De `keydir` directory is de plaats waar je de publieke sleutels opslaat van alle gebruikers die een vorm van toegang tot de repositories hebben – één bestand per gebruiker. De naam van het bestand in `keydir` (in het vorige voorbeeld, `scott.pub`) zal anders zijn in jouw geval – Gitosis haalt de naam uit de beschrijving aan het einde van de publieke sleutel die was geïmporteerd met het `gitosis-init` script. Als je naar het `gitosis.conf` bestand kijkt, zou het alleen informatie over het zojuist gekloonde `gitosis-admin` project mogen bevatten: @@ -441,14 +482,14 @@ Laten we nu een nieuw project voor je toevoegen. Je voegt een nieuwe sectie gena Wanneer je wijzigingen aan het `gitosis-admin` project maakt, moet je de veranderingen committen en terug pushen naar de server voordat ze effect hebben: $ git commit -am 'add iphone_project and mobile group' - [master]: created 8962da8: "changed name" - 1 files changed, 4 insertions(+), 0 deletions(-) - $ git push + [master 8962da8] add iphone_project and mobile group + 1 file changed, 4 insertions(+) + $ git push origin master Counting objects: 5, done. - Compressing objects: 100% (2/2), done. - Writing objects: 100% (3/3), 272 bytes, done. - Total 3 (delta 1), reused 0 (delta 0) - To git@gitserver:/opt/git/gitosis-admin.git + Compressing objects: 100% (3/3), done. + Writing objects: 100% (3/3), 272 bytes | 0 bytes/s, done. + Total 3 (delta 0), reused 0 (delta 0) + To git@gitserver:gitosis-admin.git fb27aec..8962da8 master -> master Je kunt je eerste push naar het nieuwe `iphone_project` doen door je server als een remote aan je locale versie van je project toe te voegen en te pushen. Je hoeft geen bare repositories handmatig meer te maken voor nieuwe projecten op de server — Gitosis maakt ze automatisch als het de eerste push ziet: @@ -457,14 +498,14 @@ Je kunt je eerste push naar het nieuwe `iphone_project` doen door je server als $ git push origin master Initialized empty Git repository in /opt/git/iphone_project.git/ Counting objects: 3, done. - Writing objects: 100% (3/3), 230 bytes, done. + Writing objects: 100% (3/3), 230 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To git@gitserver:iphone_project.git * [new branch] master -> master Merk op dat je geen pad hoeft te specificeren (sterker nog, het wel doen zal niet werken), alleen een dubbele punt en dan de naam van het project — Gitosis zal het voor je vinden. -Je wil samen met je vrienden aan dit project werken, dus je zult hun publieke sleutels weer toe moeten voegen. Maar in plaats van ze handmatig aan het `~/.ssh/authorized_keys` bestand op je server toe te voegen, voeg je ze één sleutel per bestand, aan de `keydir` map toe. Hoe je de sleutels noemt bepaalt hoe je aan de gebruikers refereert in het `gitosis.conf` bestand. Laten we de publieke sleutels voor John, Josie en Jessica toevoegen: +Je wil samen met je vrienden aan dit project werken, dus je zult hun publieke sleutels weer toe moeten voegen. Maar in plaats van ze handmatig aan het `~/.ssh/authorized_keys` bestand op je server toe te voegen, voeg je ze één sleutel per bestand, aan de `keydir` directory toe. Hoe je de sleutels noemt bepaalt hoe je aan de gebruikers refereert in het `gitosis.conf` bestand. Laten we de publieke sleutels voor John, Josie en Jessica toevoegen: $ cp /tmp/id_rsa.john.pub keydir/john.pub $ cp /tmp/id_rsa.josie.pub keydir/josie.pub @@ -501,94 +542,71 @@ Nu kan John het project clonen en updates krijgen, maar Gitosis zal hem niet toe writable = another_iphone_project members = @mobile_committers john -Als je problemen hebt, kan het handig zijn om `loglevel=DEBUG` onder de `[gitosis]` sectie te zetten. Als je je push-toegang bent verloren door een kapotte configuratie te pushen, kun je het handmatig repareren in het bestand `/home/git/.gitosis.conf` op de server – het bestand waar Gitosis zijn informatie vandaan haalt. Een push naar het project neemt het `gitosis.conf` bestand dat je zojuist gepushed hebt en stopt het daar. Als je het bestand handmatig aanpast, zal het zo blijven totdat de volgende succesvolle push gedaan wordt naar het `gitosis-admin` project. +Als je problemen hebt, kan het handig zijn om `loglevel=DEBUG` onder de `[gitosis]` sectie te zetten. Als je je push-toegang bent verloren door een kapotte configuratie te pushen, kun je het handmatig repareren in het bestand `/home/git/.gitosis.conf` op de server – het bestand waar Gitosis zijn informatie vandaan haalt. Een push naar het project neemt het `gitosis.conf` bestand dat je zojuist gepusht hebt en stopt het daar. Als je het bestand handmatig aanpast, zal het zo blijven totdat de volgende succesvolle push gedaan wordt naar het `gitosis-admin` project. ## Gitolite ## -Merk op: de laatste versie van deze paragraaf in het ProGit boek is altijd beschikbaar binnen de [gitolite documentation][gldpg]. De auteur geeft ook nederig aan dat, hoewel deze paragraaf accuraat is, het *kan* (en vaak ook *is*) worden gebruikt om gitolite te installeren zonder enige andere documentatie te lezen, maar dat je er vanuit mag gaan dat het niet compleet is, en het zeker niet de gehele enorme hoeveelheid documentatie kan vervangen dat meegeleverd wordt met gitolite. +Deze paragraaf fungeerrt als een snelle introductie tot Gitolite, en geeft korte installatie en setup instructies. Het kan echter niet de enoreme hoeveelheid [documentatie][gltoc] vervangen waar Gitolite mee wordt geleverd. Er kunnen ook af en toe wijzigingen in deze paragraaf worden gemaakt, dus je kunt wellicht ook [hier][gldpg] kijken voor de laatste versie. -[gldpg]: http://github.com/sitaramc/gitolite/blob/pu/doc/progit-article.mkd +[gldpg]: http://sitaramc.github.com/Gitolite/progit.html +[gltoc]: http://sitaramc.github.com/Gitolite/master-toc.html -Git begint erg populair te worden in het bedrijfsleven, die de neiging heeft nog wat additionele eisen te hebben op het gebied van toegangscontrole. Gitolite was oorspronkelijk gemaakt om bij het vervullen van deze eisen te helpen, maar het blijkt dat het even bruikbaar is in de wereld van de open source: het Fedora Project beheert toegang tot hun package beheer repositories (meer dan 10.000 daarvan!) met gitolite, en het is daarbij waarschijnlijk ook nog eens de grootste gitolite installatie waar dan ook. +Gitolite is een autorisatie-laag boven op Git, waar op ` sshd` of `httpd` wordt vertrouwd voor authenticatie. (Recapitulatie: authenticatie is het identificeren wie de gebruiker is, autoriseren is het besluiten of hetgeen wat deze gebruiker probeert te doen toegestaan is). Gitolite stelt je in staat de permissies niet alleen per repository, maar ook per branch of tag naam binnen elke repository. Dus, je kunt aangeven dat bepaalde mensen (of groepen van mensen) alleen maar bepaalde "refs" (branches of tags) kunnen pushen maar niet andere. ### Installatie ### -Het installeren van Gitolite is zeer eenvoudig, zelfs als je de uitgebreide documentatie, dat erbij geleverd wordt, niet leest. Je hebt een account op een Unix(achtige) server nodig; verschillende Linux smaken en Solaris 10 zijn getest. Je hebt geen root toegang nodig, aangenomen dat git, perl, en een openssh compatible ssh server al zijn geïnstalleerd. In de onderstaande voorbeelden zullen we het `gitolite` account gebruiken op een host genaamd `gitserver`. - -Gitolite is nogal ongebruikelijk in de zin van "server" software -- toegang gaat via ssh, en elke userid op de server is in potentie een "gitolite host". Met als gevolg dat er een notie is van "installeren" van de software zelf, en dan het "opzetten" van een gebruiker als een "gitolist host". - -Gitolite heeft 4 wijzen van installeren. Mensen die Fedora of Debian systemen gebruiken kunnen een RPM of DEB ophalen en deze installeren. Mensen met root toegang kunnen het handmatig installeren. Met deze twee methoden kan elke gebruiker op het systeem een "gitolite host" worden. - -Mensen zonder root toegang kunnen het installeren binnen hun eigen user id. En als laatste: gitlite kan geïnstalleerd worden door een script te starten *op het werkstation*, vanuit een bash-shell. (Zelfs de bash die meegeleverd wordt met msysgit volstaat, voor het geval je je dat afvroeg.) - -We zullen dit laatste in dit stuk beschrijven, voor de overige methoden verwijzen we je naar de documentatie. - -Je begint met het verkrijgen van toegang naar je server op basis van een publieke sleutel, zodat je vanaf je werkstation op de server kan inloggen zonder het intypen van je wachtwoord. De volgende methode werkt op Linux; voor andere werkstation besturingssystemen moet je dit wellicht handmatig doen. We gaan er vanuit dat je al een sleutelpaar hebt gegenereerd met `ssh-keygen`. - - $ ssh-copy-id -i ~/.ssh/id_rsa gitolite@gitserver +Het installeren van Gitolite is zeer eenvoudig, zelfs als je de uitgebreide documentatie, dat erbij geleverd wordt, niet leest. Je hebt een account op een Unix(achtige) server nodig. Je hebt geen root toegang nodig, aangenomen dat Git, perl, en een OpenSSH compatible SSH server al zijn geïnstalleerd. In de onderstaande voorbeelden zullen we het `git` account gebruiken op een host genaamd `gitserver`. -Dit zal je vragen naar een wachtwoord naar het gitolite account, en dan de publieke sleutel toegang opzetten. Dit is **absoluut noodzakelijk** voor het installatiescript, dus controleer dit om er zeker van te zijn dat je een commando kan laten lopen zonder een wachtwoord te hoeven in typen. +Gitolite is nogal ongebruikelijk in de zin van "server" software - toegang gaat via SSH, en elke userid op de server is in potentie een "Gitolite host". We zullen de eenvoudigste installatie methode beschrijven in dit artikel. Voor de overige methodes verwijzen we je naar de documentatie. - $ ssh gitolite@gitserver pwd - /home/gitolite +Om te beginnen: maak een gebruiker genaamd `git` aan op je server en log met deze gebruiker in. Kopieer je SSH publieke sleutel (een bestand genaamd `~/.ssh/id_rsa.pub` als je een gewone `ssh-keygen` met alle standaardwaarden gedaan hebt) van je werkstation, en hernoem deze naar `.pub` (we zullen `scott.pub` gebruiken in onze voorbeelden). En voer dan deze commando's uit: -Vervolgens, clone je Gitolite van de hoofdsite van het project en roept de "easy install" script aan (het derde argument is jouw naam zoals je deze in de resulterende gitolite-admin repository wilt laten verschijnen): + $ git clone git://github.com/sitaramc/Gitolite + $ Gitolite/install -ln + # assumes $HOME/bin exists and is in your $PATH + $ Gitolite setup -pk $HOME/scott.public - $ git clone git://github.com/sitaramc/gitolite - $ cd gitolite/src - $ ./gl-easy-install -q gitolite gitserver sitaram +Dat laatste commando maakt een nieuwe Git repostory genaamd `Gitolite-admin` op de server aan. -En dat is het! Gitolite is nu geïnstalleerd op je server, en je hebt nu een gloednieuwe repository genaamd `gitolite-admin` in de home directory van jouw werkstation. Je beheert je gitolite setup door een wijziging aan te brengen in deze reporitory en deze te pushen. - -Dat laatste commando produceert redelijk wat uitvoer, dat wellicht interessant is om te lezen. Ook wordt er, de eerste keer dat je het commando laat lopen, er een nieuwe sleutelpaar gemaakt; je moet een wachtwoord kiezen of Enter als je er geen wilt. Waarom een tweede sleutelpaar nodig is, en hoe deze wordt gebruikt, wordt uitgelegd in het "ssh troubleshooting" document dat bij Gitolite wordt meegeleverd. (Hey, de documentatie moet *ergens* goed voor zijn!) - -Repositories genaamd `gitolite-admin` en `testing` worden standaard op de server aangemaakt. Als je een van beide lokaal wilt clonen (van een account die SSH console toegang heeft naar het gitolite account via *authorized_keys*) type je: - - $ git clone gitolite:gitolite-admin - $ git clone gitolite:testing - -Om deze zelfde repositories te clonen van een willekeurige ander account: - - $ git clone gitolite@servername:gitolite-admin - $ git clone gitolite@servername:testing +Als laatste, terug op jouw werkstation, voer je het commando `git clone git@gitserver:Gitolite-admin` uit. En klaar is Kees! Gitolite is nu geinstalleerd op de server, en jij hebt nu een gloednieuwe repository genaamd `Gitolite-admin` op jouw werkstation. Jij beheert je Gitolite opstelling door veranderingen in deze repository te maken en die te pushen. ### De Installatie Aanpassen ### -Hoewel de standaard, snelle, installatie werkt voor de meeste mensen, zijn er een aantal manieren om de installatie aan te passen als dat nodig is. Als je het `-q` argument weg laat, krijg je een "verbose" installatie wijze -- gedetaileerde informatie over wat de installatie aan het doen is bij elke stap. De verbose wijze staat je ook toe om bepaalde server-side parameters aan te passen, zoals de locatie van de eigenlijke repositories, door het wijzigen van een "rc" bestand dat de server gebruikt. Dit "rc" bestand is ruimhartig van commentaar voorzien dus je zou in staat moeten zijn om elke wijziging die je nodig vindt vrij snel te maken, op te slaan en door te gaan. Dit bestand bevat ook enkele instellingen die je kunt aanpassen om de meer geavanceerde functies van gitolite aan of uit te zetten. +Hoewel de standaard, snelle, installatie werkt voor de meeste mensen, zijn er een aantal manieren om de installatie aan te passen als dat nodig is. Sommige wijzigingen kunnen simpleweg gemaakt worden door het rc bestand te wijzigen, maar als dat niet volstaat is er documentatie over het aanpassen van Gitolite beschikbaar. ### Config bestand en Beheer van Toegangsregels ### -Zodra de installatie afgerond is, schakel je over naar de `gitolite-admin` repository (die staat in je HOME directory) en begin je rond te snuffelen om te zien wat je daar hebt: +Zodra de installatie afgerond is, schakel je over naar de `Gitolite-admin` repository die je zojuist op je werkstation gemaakt hebt, en begin je rond te snuffelen om te zien wat je daar hebt: - $ cd ~/gitolite-admin/ + $ cd ~/Gitolite-admin/ $ ls conf/ keydir/ $ find conf keydir -type f - conf/gitolite.conf - keydir/sitaram.pub - $ cat conf/gitolite.conf - #gitolite conf - # please see conf/example.conf for details on syntax and features + conf/Gitolite.conf + keydir/scott.pub + $ cat conf/Gitolite.conf - repo gitolite-admin - RW+ = sitaram + repo Gitolite-admin + RW+ = scott repo testing RW+ = @all -Merk op dat "sitaram" (het laatste argument in het `gl-easy-install` commando dat je eerder gegeven hebt) lees en schrijf rechten heeft op de `gitolite-admin` repository en een publiek sleutelbestand met dezelfde naam. +Merk op dat "scott" (de naam van de pubkey in het `Gitolite setup` commando dat je eerder gebruikt hebt) lees- en schrijfrechten heeft op de `Gitolite-admin` repository en een publiek sleutelbestand met dezelfde naam. -De syntax van het config bestand voor gitolite is ruimhartig van documentatie voorzien in `conf/example.conf`, dus we zullen alleen wat hoofdpunten benoemen. +Gebruikers toevoegen is eenvoudig. Om een gebruiker genaamd "alice" toe te voegen, verkrijg haar publieke sleutel, noem deze `alice.pub`, en zet deze in de `keyir` directory van de clone van de `Gitolite-admin` repositroy die je zojuist op je werkstation gemaakt hebt. Voeg de wijziging toe, commit en push de wijziging en de gebruiker is toegevoegd. + +De syntax van het config bestand voor Gitolite is ruimhartig van documentatie voorzien in, dus we zullen ons beperken tot wat hoofdpunten. Je kunt voor het gemak gebruikers of repositories groeperen. De groepnamen zijn vergelijkbaar met macros: als je ze definieert maakt het niet uit of het projecten of gebruikers zijn. Dat onderscheid wordt pas gemaakt als je de "macro" gaat *gebruiken*. - @oss_repos = linux perl rakudo git gitolite + @oss_repos = linux perl rakudo git Gitolite @secret_repos = fenestra pear - @admins = scott # Adams, not Chacon, sorry :) - @interns = ashok # get the spelling right, Scott! + @admins = scott + @interns = ashok @engineers = sitaram dilbert wally alice @staff = @admins @engineers @interns @@ -600,26 +618,26 @@ Je kunt de permissies beheren op het "ref" niveau. In het volgende voorbeeld kun RW refs/tags/rc[0-9] = @engineers RW+ = @admins -De expressie achter de `RW` of `RW+` is een zgn. regular expression (regex) waartegen de refname (ref) die wordt gepushed wordt vergeleken. Dus we gaan we deze uiteraard een "refex" noemen! En natuurlijk kan een refex veel krachtiger zijn dan hier wordt getoond, dus ga het niet overdrijven als je niet al te goed in de perl regexen zit. +De expressie achter de `RW` of `RW+` is een zgn. regular expression (regex) waartegen de refname (ref) die wordt gepusht wordt vergeleken. Dus we gaan we deze uiteraard een "refex" noemen! En natuurlijk kan een refex veel krachtiger zijn dan hier wordt getoond, dus ga het niet overdrijven als je niet al te goed in de Perl regexen zit. Zoals je wellicht al geraden hebt, gebruikt Gitolite de prefix `refs/heads/` als een syntactische handigheid indien de refex niet begint met `refs/`. Een belangrijke eigenschap van de syntax van het config bestand is dat alle regels van een repository niet op één plek hoeft te staan. Je kunt al het generieke spul bij elkaar houden, zoals de regels voor alle `oss_repos` zoals ze hier boven staan, en dan op een latere plaats specifieke regels voor specifieke gevallen, zoals hier: - repo gitolite + repo Gitolite RW+ = sitaram -Deze regel wordt gewoon toegevoegd aan de set met regels voor de `gitolite` repository. +Deze regel wordt gewoon toegevoegd aan de set met regels voor de `Gitolite` repository. Je zou je op dit punt kunnen afvragen hoe de toegangsregels eigenlijk worden toegepast, laten we dat kort behandelen. -Er zijn twee niveaus van toegangsbeheer in gitolite. De eerste is op repository niveau. Als je lees- of schrijfrechten hebt tot *enige* ref in de repository, dan heb je lees (of schrijf) rechten tot de repository. +Er zijn twee niveaus van toegangsbeheer in Gitolite. De eerste is op repository niveau. Als je lees- of schrijfrechten hebt tot *enige* ref in de repository, dan heb je lees (of schrijf)rechten tot de repository. Dit is de enige toegangsbeheer dat Gitosis had. Het tweede niveau, alleen van toepassing voor "schrijf" toegang, is per branch of tag binnen een repository. De gebruikersnaam, het type toegang wat wordt gevraagd (`W` of '+'), en de refname dat wordt gewijzigd (geüpdate) zijn bekend. De toegangsregels worden gecontroleerd in volgorde van voorkomst in het config bestand, en er wordt gekeken naar een treffer voor deze combinatie (maar onthoudt dat de refname middels een regex wordt vergeleken, niet een simpele string-vergelijking). Als er een treffer is, dan slaagt de push. Als er geen treffer wordt gevonden (fallthrough) dan wordt toegang geweigerd. ### Geavanceerde Toegangs Controle met "deny" regels ### -Tot zover hebben we alleen permissies gezien uit het rijtje `R`, `RW` of `RW+`. Echter, gitolite kent een andere permissie: `-`, wat staat voor "deny" (ontken). Dit geeft je veel meer macht, tegen kosten van wat hogere complexiteit omdat een fallthrough nu niet de *enige* manier is waarop toegang kan worden geweigerd; nu wordt *de volgorde van regels belangrijk*! +Tot zover hebben we alleen permissies gezien uit het rijtje `R`, `RW` of `RW+`. Echter, Gitolite kent een andere permissie: `-`, wat staat voor "deny" (ontken). Dit geeft je veel meer macht, tegen kosten van wat hogere complexiteit omdat een fallthrough nu niet de *enige* manier is waarop toegang kan worden geweigerd; nu wordt *de volgorde van regels belangrijk*! Stel dat, in de onderstaande situatie, we de techneuten in staat willen stellen elke branch te laten terugdraaien *behalve* master en integ. Dit is de manier om dat te doen: @@ -631,43 +649,39 @@ Nogmaals, je hoeft slechts de regels van boven naar beneden af te lopen tot je e ### Beperken van pushes bij gewijzigde bestanden ### -Bovenop het beperken van gebruikersrechten op branches voor een gebruiker, kan je ook de rechten van gebruikers beperken op bestanden. Als voorbeeld, misschien is de Makefile (of een ander programma) niet echt bedoeld om te worden gewijzigd door iedereen, omdat een groot aantal dingen afhankelijk ervan zijn of omdat het stuk loopt als de wijzigingen niet *precies goed* gebeuren. Je kunt het gitolite duidelijk maken: +Bovenop het beperken van pushrechten op branches voor een gebruiker, kan je ook de rechten van gebruikers beperken op bestanden. Als voorbeeld, misschien is de Makefile (of een ander programma) niet echt bedoeld om door iedereen te worden gewijzigd, omdat een groot aantal dingen afhankelijk ervan zijn of omdat het stuk loopt als de wijzigingen niet *precies goed* gebeuren. Je kunt het Gitolite duidelijk maken: repo foo - RW = @junior_devs @senior_devs + RW = @junior_devs @senior_devs - RW NAME/ = @senior_devs - - NAME/Makefile = @junior_devs - RW NAME/ = @junior_devs + - VREF/NAME/Makefile = @junior_devs -Deze krachtige eigenschap is gedocumenteerd in `conf/example.conf`. +Gebruikers die migreren van de oudere versie van Gitolite moeten opmerken dat er een significant verschil in het gedrag wat betreft deze eigenschap; zie de migratiegids voor meer details. ### Persoonlijke branches ### Gitolite heeft ook een mogelijkheid van "persoonlijke branches" (of liever gezegd "persoonlijke branch namespace") wat erg nuttig kan zijn in een bedrijfssituatie. -Veel van de code-uitwisselingen in de git-wereld verlopen via zgn. "please pull" aanvragen. In een bedrijfsomgeving echter is ongeauthoriseerde toegang taboe, en het werkstation van een ontwikkelaar kan geen authenticatie doen, dus je moet naar de centrale server pushen en iemand vragen daarvandaan te pullen. +Veel van de code-uitwisselingen in de Git-wereld verlopen via zgn. "please pull" aanvragen. In een bedrijfsomgeving echter is ongeauthoriseerde toegang taboe, en het werkstation van een ontwikkelaar kan geen authenticatie doen, dus je moet naar de centrale server pushen en iemand vragen daarvandaan te pullen. Dit zou normaalgesproken een gelijksoortige branch-brij veroorzaken als in een gecentraliseerde versiebeheersysteem, en daarbij wordt het opzetten van permissies een vervelende klus voor de administrator. -Gitolite stelt je in staat een "personal" of "scratch" namespace prefix voor elke ontwikkelaar te definiëren (bijvoorbeeld `refs/personal//*`); zie ook de "personal branches" paragraaf in `doc/3-faq-tips-etc.mkd` voor details. +Gitolite stelt je in staat een "personal" of "scratch" namespace prefix voor elke ontwikkelaar te definiëren (bijvoorbeeld `refs/personal//*`); we verwijzen naar de documentatie voor details. ### "Wildcard" repositores ### -Gitolite laat je repositories specificeren met wildcards (eigenlijk perl regex expressies), zoals bijvoorbeeld `assignments/s[0-9][0-9]/a[0-9][0-9]`, om maar een willekeurig voorbeeld te nemen. Dit is een *heel* krachtige eigenschap die wordt aangezet door de regel `$GL_WILDREPOS = 1;` in het rc bestand. Het laat je een nieuwe permissiewijze ("C") toe te wijzen welke gebruikers in staat stelt repositories aan te maken die voldoen aan zulke wildcards, automatisch eigenaarsschap toe te wijzen aan de gebruiker die hem heeft aangemaakt, staat deze gebruiker toe om "R" en "RW" permissies aan anderen toe te wijzen om samen te werken, etc. Deze eigenschap is beschreven in `doc/4-wildcard-repositories.mkd`. +Gitolite laat je repositories specificeren met wildcards (eigenlijk Perl regex expressies), zoals bijvoorbeeld `assignments/s[0-9][0-9]/a[0-9][0-9]`, om maar een willekeurig voorbeeld te nemen. Dit stelt je in staat om een nieuwe permissie modus (`C`) toe te wijzen die gebruikers in staat stelt repositories te maken op basis van zulk wildcards, automatisch eigenaarschap toe te wijzen aan de gebruiker die hem heeft aangemaakt, staat deze gebruiker toe om "R" en "RW" permissies aan anderen toe te wijzen om samen te werken, etc. Nogmaals: zie de documentatie voor meer details. ### Andere eigenschappen ### -We ronden deze uiteenzetting af met een passe partout van andere eigenschappen, welke alle (en nog vele andere) tot in de kleinste detail zijn beschreven in de "faqs, tips, etc" en andere documenten. +We ronden deze uiteenzetting af met een passe partout van andere eigenschappen, welke alle (en nog vele andere) tot in de kleinste detail zijn beschreven in de documentatie. **Logging**: Gitolite logt alle succesvolle toegangspogingen. Als je wat te los bent geweest in het toekennen van terugdraai permissies (`RW+`) en een of andere bijdehand heeft "master" vernaggelt, is de log-file een redder in de nood in de zin van snel en eenvoudig achterhalen van de SHA die verdwenen is. -**Git buiten reguliere PATH**: Een ontzettend handige eigenschap in gitolite is het ondersteunen van Git buiten het regulier `$PATH` (dit komt vaker voor dan je zou denken, sommige bedrijfs omgevingen of zelfs sommige hosting providers weigeren dingen systeem-breed te installeren en je eindigt ermee dat je ze in je eigen directories zet). Normaalgesproken ben je gedwongen Git aan de *client-side* op de een of andere manier te vertellen van deze niet-standaard locatie van de git binaries. Met gitolite hoe je alleen een verbose installatie te kiezen en `$GIT_PATH` in de "rc" bestanden in te vullen. Hierna geen wijzigingen aan de kant van de clients nodig :-) - **Rapportage van toegangsrechten**: Nog zo'n handige eigenschap is wat er gebeurt als je gewoon met ssh naar de server gaat. Gitolite laat zien welke repositories je toegang toe hebt en welke soort toegang dat dan is. Hier is een voorbeeld: - hello sitaram, the gitolite version here is v1.5.4-19-ga3397d4 - the gitolite config gives you the following access: + hello scott, this is git@git running gitolite3 v3.01-18-g9609868 on git 1.7.4.4 + R anu-wsd R entrans R W git-notes @@ -676,9 +690,7 @@ We ronden deze uiteenzetting af met een passe partout van andere eigenschappen, R indic_web_input R shreelipi_converter -**Delegeren**: Voor extreem grote installaties kan je de verantwoordelijkheid voor groepen van repositories delegeren aan verschillende mensen en hen het beheer van die delen onafhankelijk laten regelen. Dit vermindert de werkdruk van de hoofd-beheerder, en maakt van hem minder een faalpunt. Deze eigenschap heeft zijn eigen documentatie in de `doc/` directory. - -**Gitweb ondersteuning**: Gitolite ondersteunt gitweb op verschillende manieren. Je kunt aangeven welke repositories zichtbaar zijn via gitweb. Je kunt de "owner" (eigenaar) en "description" (omschrijving) voor gitweb vanuit de gitolite configuratie bestanden definiëren. Gitweb heeft een mechanisme beschikbaar waarmee toegang via HTTP wordt geïmplementeerd, deze kan je het "gecompileerde" config bestand van de gitolite config file laten gebruiken, wat inhoudt dat gitweb en gitolite dezelfde toegangsregels gebruiken (voor lees toegang). +**Delegeren**: Voor extreem grote installaties kan je de verantwoordelijkheid voor groepen van repositories delegeren aan verschillende mensen en hen het beheer van die delen onafhankelijk laten regelen. Dit vermindert de werkdruk van de hoofd-beheerder, en maakt van hem minder een faalpunt. **Mirroring**: Gitolite kan je ondersteunen bij het beheren van meerdere mirrors, en het eenvoudig daartussen overschakelen als de primaire server uitvalt. @@ -722,7 +734,7 @@ Vervolgens zul je je Gitosis server moeten vertellen welke repositories je onaut [repo iphone_project] daemon = yes -Als dat gecommit en gepushed is, dan zou de draaiende daemon verzoeken moeten serveren aan iedereen die toegang heeft op poort 9418 van je server. +Als dat gecommit en gepusht is, dan zou de draaiende daemon verzoeken moeten serveren aan iedereen die toegang heeft op poort 9418 van je server. Als je besluit om Gitosis niet te gebruiken, maar je wilt toch een Git daemon instellen, dan moet je dit op ieder project uitvoeren waarvoor je de Git daemon wilt laten serveren: @@ -744,9 +756,9 @@ Je kunt instellen welke projecten GitWeb gebruikers laat bladeren door een `gitw daemon = yes gitweb = yes -Als je nu het project commit en pushed, begint GitWeb automatisch je iphone project te tonen. +Als je nu het project commit en pusht, begint GitWeb automatisch je `iphone_project` te tonen. -## Hosted Git ## +## Gehoste Git ## Als je niet al het werk wilt doen om je eigen Git server op te zetten, heb je meerdere opties om je Git project op een externe speciale hosting pagina te laten beheren. Dit biedt een aantal voordelen: een ge-hoste pagina is over het algemeen snel in te stellen, eenvoudig om projecten mee op te starten, en er komt geen serverbeheer en -onderhoud bij kijken. Zelfs als je je eigen server intern opgezet hebt, zul je misschien een publieke host pagina voor je open source broncode willen – dat is over het algemeen makkelijker voor de open source commune te vinden en je er mee te helpen. @@ -812,7 +824,7 @@ Als je een lokaal Git repository hebt, voeg dan GitHub als remote toe en push je $ git remote add origin git@github.com:testinguser/iphone_project.git $ git push origin master -Nu wordt je project beheerd op GitHub, en kun je de URL aan iedereen geven waarmee je je project wilt delen. In dit geval is het `http://githup.com/testinguser/iphone_project`. Je kunt aan het begin van elk van je project pagina's zien dat je twee Git URLs hebt (zie Figuur 4-8). +Nu wordt je project gehost op GitHub, en kun je de URL aan iedereen geven waarmee je je project wilt delen. In dit geval is het `http://githup.com/testinguser/iphone_project`. Je kunt aan het begin van elk van je project pagina's zien dat je twee Git URLs hebt (zie Figuur 4-8). Insert 18333fig0408.png Figuur 4-8. Project met een publieke URL en een privé URL. @@ -853,18 +865,18 @@ Als je toegang van individuen moet intrekken, dan kun je de "revoke" link klikke ### Je project ### -Nadat je je project gepushed hebt, of geïmporteerd vanuit Subversion, heb je een hoofd project pagina die er uitziet zoals Figuur 4-13. +Nadat je je project gepusht hebt, of geïmporteerd vanuit Subversion, heb je een hoofd project pagina die er uitziet zoals Figuur 4-13. Insert 18333fig0413.png Figuur 4-13. Een GitHub project hoofdpagina. -Als mensen je project bezoeken, zien ze deze pagina. Het bevat tabs naar de verschillende aspecten van je projecten. De Commits tab laat een lijst van commits in omgekeerde chronologische volgorde zien, vergelijkbaar met de output van het `git log` commando. De Network tab toont alle mensen die je project hebben geforked en bijgedragen hebben. De Downloads tab staat je toe project binaries te uploaden en naar tarballs en gezipte versies van ieder getagged punt in je project te linken. De Wiki tab voorziet in een wiki waar je documentatie kunt schrijven of andere informatie over je project. De Graphs tab heeft wat contributie visualisaties en statistieken over je project. De hoofd Source tab waarop je binnen komt, toont de inhoud van de hoofdmap van je project en toont automatisch het README bestand eronder als je er een hebt. Deze tab toont ook een veld met de laatste commit informatie. +Als mensen je project bezoeken, zien ze deze pagina. Het bevat tabs naar de verschillende aspecten van je projecten. De Commits tab laat een lijst van commits in omgekeerde chronologische volgorde zien, vergelijkbaar met de output van het `git log` commando. De Network tab toont alle mensen die je project hebben geforked en bijgedragen hebben. De Downloads tab staat je toe project binaries te uploaden en naar tarballs en gezipte versies van ieder getagged punt in je project te linken. De Wiki tab voorziet in een wiki waar je documentatie kunt schrijven of andere informatie over je project. De Graphs tab heeft wat contributie visualisaties en statistieken over je project. De hoofd Source tab waarop je binnen komt, toont de inhoud van de hoofddirectory van je project en toont automatisch het README bestand eronder als je er een hebt. Deze tab toont ook een veld met de laatste commit informatie. ### Projecten forken ### -Als je aan een bestaand project waarop je geen push toegang hebt wilt bijdragen, dan moedigt GitHub het forken van een project toe. Als je op een project pagina belandt, die interessant lijkt en je wilt er een beetje op hacken, dan kun je de "fork" knop klikken aan de bovenkant van het project om GitHub dat project te laten kopiëren naar jouw gebruiker zodat je er naar kunt pushen. +Als je aan een bestaand project waarop je geen push toegang hebt wilt bijdragen, dan moedigt GitHub het forken van een project toe. Als je op een project pagina belandt die interessant lijkt en je wilt er een beetje op hacken, dan kun je de "fork" knop klikken aan de bovenkant van het project om GitHub dat project te laten kopiëren naar jouw gebruiker zodat je er naar kunt pushen. -Op deze manier hoeven projecten zich geen zorgen te maken over het toevoegen van medewerkers om ze push toegang te geven. Mensen kunnen een project forken en ernaar pushen, en de hoofdeigenaar van het project kan die wijzigingen pullen door ze als remotes toe te voegen en hun werk te mergen. +Op deze manier hoeven projecten zich geen zorgen te maken over het toevoegen van medewerkers om ze push toegang te geven. Mensen kunnen een project forken en ernaar pushen, en de hoofdbeheerder van het project kan die wijzigingen pullen door ze als remotes toe te voegen en hun werk te mergen. Om een project te forken, bezoek dan de project pagina (in dit geval, mojombo/chronic) en klik de "fork" knop aan de bovenkant (zie Figuur 4-14). From cc729707a2fbf8300fc3790858800f1985b2e814 Mon Sep 17 00:00:00 2001 From: cor Date: Sat, 15 Feb 2014 16:19:44 +0100 Subject: [PATCH 016/478] [nl] Chapter04 Start trying to beat Maruku test... --- nl/04-git-server/01-chapter4.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/nl/04-git-server/01-chapter4.markdown b/nl/04-git-server/01-chapter4.markdown index d87310e71..6f5891a9e 100644 --- a/nl/04-git-server/01-chapter4.markdown +++ b/nl/04-git-server/01-chapter4.markdown @@ -1,3 +1,4 @@ + + 选项 说明 %H 提交对象(commit)的完整哈希字串 %h 提交对象的简短哈希字串 @@ -569,8 +608,14 @@ Insert 18333fig0201.png 以上只是简单介绍了一些 `git log` 命令支持的选项。表 2-2 还列出了一些其他常用的选项及其释义。 + + 选项 说明 -p 按补丁格式显示每个更新之间的差异。 + --word-diff 按 word diff 格式显示差异。 --stat 显示每次更新的文件修改统计信息。 --shortstat 只显示 --stat 中最后的行数修改添加移除统计。 --name-only 仅在提交信息后显示已修改的文件清单。 @@ -579,6 +624,7 @@ Insert 18333fig0201.png --relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)。 --graph 显示 ASCII 图形表示的分支合并历史。 --pretty 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)。 + --oneline `--pretty=oneline --abbrev-commit` 的简化用法。 ### 限制输出长度 ### @@ -596,6 +642,11 @@ Insert 18333fig0201.png 表 2-3 还列出了其他常用的类似选项。 + + 选项 说明 -(n) 仅显示最近的 n 条提交 --since, --after 仅显示指定时间之后的提交。 @@ -653,31 +704,32 @@ Insert 18333fig0202.png $ git add . $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + modified: benchmarks.rb + 就在 “Changes to be committed” 下面,括号中有提示,可以使用 `git reset HEAD ...` 的方式取消暂存。好吧,我们来试试取消暂存 benchmarks.rb 文件: $ git reset HEAD benchmarks.rb - benchmarks.rb: locally modified + Unstaged changes after reset: + M benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + 这条命令看起来有些古怪,先别管,能用就行。现在 benchmarks.rb 文件又回到了之前已修改未暂存的状态。 @@ -685,23 +737,23 @@ Insert 18333fig0202.png 如果觉得刚才对 benchmarks.rb 的修改完全没有必要,该如何取消修改,回到之前的状态(也就是修改之前的版本)呢?`git status` 同样提示了具体的撤消方法,接着上面的例子,现在未暂存区域看起来像这样: - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + 在第二个括号中,我们看到了抛弃文件修改的命令(至少在 Git 1.6.1 以及更高版本中会这样提示,如果你还在用老版本,我们强烈建议你升级,以获取最佳的用户体验),让我们试试看: $ git checkout -- benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + 可以看到,该文件已经恢复到修改前的版本。你可能已经意识到了,这条命令有些危险,所有对文件的修改都没有了,因为我们刚刚把之前版本的文件复制过来重写了此文件。所以在用这条命令前,请务必确定真的不再需要保留刚才的修改。如果只是想回退版本,同时保留刚才的修改以便将来继续工作,可以用下章介绍的 stashing 和分支来处理,应该会更好些。 @@ -709,19 +761,20 @@ Insert 18333fig0202.png ## 远程仓库的使用 ## -要参与任何一个 Git 项目的协作,必须要了解该如何管理远程仓库。远程仓库是指托管在网络上的项目仓库,可能会有好多个,其中有些你只能读,另外有些可以写。同他人协作开发某个项目时,需要管理这些远程仓库,以便推送或拉取数据,分享各自的工作进展。管理远程仓库的工作,包括添加远程库,移除废弃的远程库,管理各式远程库分支,定义是否跟踪这些分支,等等。本节我们将详细讨论远程库的管理和使用。 +要参与任何一个 Git 项目的协作,必须要了解该如何管理远程仓库。远程仓库是指托管在网络上的项目仓库,可能会有好多个,其中有些你只能读,另外有些可以写。同他人协作开发某个项目时,需要管理这些远程仓库,以便推送或拉取数据,分享各自的工作进展。 +管理远程仓库的工作,包括添加远程库,移除废弃的远程库,管理各式远程库分支,定义是否跟踪这些分支,等等。本节我们将详细讨论远程库的管理和使用。 ### 查看当前的远程库 ### 要查看当前配置有哪些远程仓库,可以用 `git remote` 命令,它会列出每个远程库的简短名字。在克隆完某个项目后,至少可以看到一个名为 origin 的远程库,Git 默认使用这个名字来标识你所克隆的原始仓库: $ git clone git://github.com/schacon/ticgit.git - Initialized empty Git repository in /private/tmp/ticgit/.git/ - remote: Counting objects: 595, done. - remote: Compressing objects: 100% (269/269), done. - remote: Total 595 (delta 255), reused 589 (delta 253) - Receiving objects: 100% (595/595), 73.31 KiB | 1 KiB/s, done. - Resolving deltas: 100% (255/255), done. + Cloning into 'ticgit'... + remote: Reusing existing pack: 1857, done. + remote: Total 1857 (delta 0), reused 0 (delta 0) + Receiving objects: 100% (1857/1857), 374.35 KiB | 193.00 KiB/s, done. + Resolving deltas: 100% (772/772), done. + Checking connectivity... done. $ cd ticgit $ git remote origin @@ -729,7 +782,8 @@ Insert 18333fig0202.png 也可以加上 `-v` 选项(译注:此为 `--verbose` 的简写,取首字母),显示对应的克隆地址: $ git remote -v - origin git://github.com/schacon/ticgit.git + origin git://github.com/schacon/ticgit.git (fetch) + origin git://github.com/schacon/ticgit.git (push) 如果有多个远程仓库,此命令将全部列出。比如在我的 Grit 项目中,可以看到: @@ -891,6 +945,7 @@ Git 使用的标签有两种类型:轻量级的(lightweight)和含附注 Date: Mon Feb 9 14:45:11 2009 -0800 my version 1.4 + commit 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge: 4a447f7... a6b4c97... Author: Scott Chacon diff --git a/zh/03-git-branching/01-chapter3.markdown b/zh/03-git-branching/01-chapter3.markdown index aacd93361..643c697cc 100644 --- a/zh/03-git-branching/01-chapter3.markdown +++ b/zh/03-git-branching/01-chapter3.markdown @@ -19,17 +19,17 @@ 现在,Git 仓库中有五个对象:三个表示文件快照内容的 blob 对象;一个记录着目录树内容及其中各个文件对应 blob 对象索引的 tree 对象;以及一个包含指向 tree 对象(根目录)的索引和其他提交信息元数据的 commit 对象。概念上来说,仓库中的各个对象保存的数据和相互关系看起来如图 3-1 所示: -Insert 18333fig0301.png +Insert 18333fig0301.png 图 3-1. 单个提交对象在仓库中的数据结构 作些修改后再次提交,那么这次的提交对象会包含一个指向上次提交对象的指针(译注:即下图中的 parent 对象)。两次提交后,仓库历史会变成图 3-2 的样子: -Insert 18333fig0302.png +Insert 18333fig0302.png 图 3-2. 多个提交对象之间的链接关系 现在来谈分支。Git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针。Git 会使用 master 作为分支的默认名字。在若干次提交后,你其实已经有了一个指向最后一次提交对象的 master 分支,它在每次提交的时候都会自动向前移动。 -Insert 18333fig0303.png +Insert 18333fig0303.png 图 3-3. 分支其实就是从某个提交对象往回看的历史 那么,Git 又是如何创建一个新的分支的呢?答案很简单,创建一个新的分支指针。比如新建一个 testing 分支,可以使用 `git branch` 命令: @@ -38,12 +38,12 @@ Insert 18333fig0303.png 这会在当前 commit 对象上新建一个分支指针(见图 3-4)。 -Insert 18333fig0304.png +Insert 18333fig0304.png 图 3-4. 多个分支指向提交数据的历史 那么,Git 是如何知道你当前在哪个分支上工作的呢?其实答案也很简单,它保存着一个名为 HEAD 的特别指针。请注意它和你熟知的许多其他版本控制系统(比如 Subversion 或 CVS)里的 HEAD 概念大不相同。在 Git 中,它是一个指向你正在工作中的本地分支的指针(译注:将 HEAD 想象为当前分支的别名。)。运行 `git branch` 命令,仅仅是建立了一个新的分支,但不会自动切换到这个分支中去,所以在这个例子中,我们依然还在 master 分支里工作(参考图 3-5)。 -Insert 18333fig0305.png +Insert 18333fig0305.png 图 3-5. HEAD 指向当前所在的分支 要切换到其他分支,可以执行 `git checkout` 命令。我们现在转换到新建的 testing 分支: @@ -52,7 +52,7 @@ Insert 18333fig0305.png 这样 HEAD 就指向了 testing 分支(见图3-6)。 -Insert 18333fig0306.png +Insert 18333fig0306.png 图 3-6. HEAD 在你转换分支时指向新的分支 这样的实现方式会给我们带来什么好处呢?好吧,现在不妨再提交一次: @@ -62,7 +62,7 @@ Insert 18333fig0306.png 图 3-7 展示了提交后的结果。 -Insert 18333fig0307.png +Insert 18333fig0307.png 图 3-7. 每次提交后 HEAD 随着分支一起向前移动 非常有趣,现在 testing 分支向前移动了一格,而 master 分支仍然指向原先 `git checkout` 时所在的 commit 对象。现在我们回到 master 分支看看: @@ -71,7 +71,7 @@ Insert 18333fig0307.png 图 3-8 显示了结果。 -Insert 18333fig0308.png +Insert 18333fig0308.png 图 3-8. HEAD 在一次 checkout 之后移动到了另一个分支 这条命令做了两件事。它把 HEAD 指针移回到 master 分支,并把工作目录中的文件换成了 master 分支所指向的快照内容。也就是说,现在开始所做的改动,将始于本项目中一个较老的版本。它的主要作用是将 testing 分支里作出的修改暂时取消,这样你就可以向另一个方向进行开发。 @@ -83,7 +83,7 @@ Insert 18333fig0308.png 现在我们的项目提交历史产生了分叉(如图 3-9 所示),因为刚才我们创建了一个分支,转换到其中进行了一些工作,然后又回到原来的主分支进行了另外一些工作。这些改变分别孤立在不同的分支里:我们可以在不同分支里反复切换,并在时机成熟时把它们合并到一起。而所有这些工作,仅仅需要 `branch` 和 `checkout` 这两条命令就可以完成。 -Insert 18333fig0309.png +Insert 18333fig0309.png 图 3-9. 不同流向的分支历史 由于 Git 中的分支实际上仅是一个包含所指对象校验和(40 个字符长度 SHA-1 字串)的文件,所以创建和销毁一个分支就变得非常廉价。说白了,新建一个分支就是向一个文件写入 41 个字节(外加一个换行符)那么简单,当然也就很快了。 @@ -111,13 +111,13 @@ Insert 18333fig0309.png 首先,我们假设你正在项目中愉快地工作,并且已经提交了几次更新(见图 3-10)。 -Insert 18333fig0310.png +Insert 18333fig0310.png 图 3-10. 一个简短的提交历史 现在,你决定要修补问题追踪系统上的 #53 问题。顺带说明下,Git 并不同任何特定的问题追踪系统打交道。这里为了说明要解决的问题,才把新建的分支取名为 iss53。要新建并切换到该分支,运行 `git checkout` 并加上 `-b` 参数: $ git checkout -b iss53 - Switched to a new branch "iss53" + Switched to a new branch 'iss53' 这相当于执行下面这两条命令: @@ -126,7 +126,7 @@ Insert 18333fig0310.png 图 3-11 示意该命令的执行结果。 -Insert 18333fig0311.png +Insert 18333fig0311.png 图 3-11. 创建了一个新分支的指针 接着你开始尝试修复问题,在提交了若干次更新后,`iss53` 分支的指针也会随着向前推进,因为它就是当前分支(换句话说,当前的 `HEAD` 指针正指向 `iss53`,见图 3-12): @@ -134,7 +134,7 @@ Insert 18333fig0311.png $ vim index.html $ git commit -a -m 'added a new footer [issue 53]' -Insert 18333fig0312.png +Insert 18333fig0312.png 图 3-12. iss53 分支随工作进展向前推进 现在你就接到了那个网站问题的紧急电话,需要马上修补。有了 Git ,我们就不需要同时发布这个补丁和 `iss53` 里作出的修改,也不需要在创建和发布该补丁到服务器之前花费大力气来复原这些修改。唯一需要的仅仅是切换回 `master` 分支。 @@ -142,20 +142,20 @@ Insert 18333fig0312.png 不过在此之前,留心你的暂存区或者工作目录里,那些还没有提交的修改,它会和你即将检出的分支产生冲突从而阻止 Git 为你切换分支。切换分支的时候最好保持一个清洁的工作区域。稍后会介绍几个绕过这种问题的办法(分别叫做 stashing 和 commit amending)。目前已经提交了所有的修改,所以接下来可以正常转换到 `master` 分支: $ git checkout master - Switched to branch "master" + Switched to branch 'master' 此时工作目录中的内容和你在解决问题 #53 之前一模一样,你可以集中精力进行紧急修补。这一点值得牢记:Git 会把工作目录的内容恢复为检出某分支时它所指向的那个提交对象的快照。它会自动添加、删除和修改文件以确保目录的内容和你当时提交时完全一样。 接下来,你得进行紧急修补。我们创建一个紧急修补分支 `hotfix` 来开展工作,直到搞定(见图 3-13): - $ git checkout -b 'hotfix' - Switched to a new branch "hotfix" + $ git checkout -b hotfix + Switched to a new branch 'hotfix' $ vim index.html $ git commit -a -m 'fixed the broken email address' - [hotfix]: created 3a0874c: "fixed the broken email address" - 1 files changed, 0 insertions(+), 1 deletions(-) + [hotfix 3a0874c] fixed the broken email address + 1 files changed, 1 deletion(-) -Insert 18333fig0313.png +Insert 18333fig0313.png 图 3-13. hotfix 分支是从 master 分支所在点分化出来的 有必要作些测试,确保修补是成功的,然后回到 `master` 分支并把它合并进来,然后发布到生产服务器。用 `git merge` 命令来进行合并: @@ -163,32 +163,32 @@ Insert 18333fig0313.png $ git checkout master $ git merge hotfix Updating f42c576..3a0874c - Fast forward - README | 1 - - 1 files changed, 0 insertions(+), 1 deletions(-) + Fast-forward + README | 1 - + 1 file changed, 1 deletion(-) 请注意,合并时出现了“Fast forward”的提示。由于当前 `master` 分支所在的提交对象是要并入的 `hotfix` 分支的直接上游,Git 只需把 `master` 分支指针直接右移。换句话说,如果顺着一个分支走下去可以到达另一个分支的话,那么 Git 在合并两者时,只会简单地把指针右移,因为这种单线的历史分支不存在任何需要解决的分歧,所以这种合并过程可以称为快进(Fast forward)。 现在最新的修改已经在当前 `master` 分支所指向的提交对象中了,可以部署到生产服务器上去了(见图 3-14)。 -Insert 18333fig0314.png +Insert 18333fig0314.png 图 3-14. 合并之后,master 分支和 hotfix 分支指向同一位置。 在那个超级重要的修补发布以后,你想要回到被打扰之前的工作。由于当前 `hotfix` 分支和 `master` 都指向相同的提交对象,所以 `hotfix` 已经完成了历史使命,可以删掉了。使用 `git branch` 的 `-d` 选项执行删除操作: $ git branch -d hotfix - Deleted branch hotfix (3a0874c). + Deleted branch hotfix (was 3a0874c). 现在回到之前未完成的 #53 问题修复分支上继续工作(图 3-15): $ git checkout iss53 - Switched to branch "iss53" + Switched to branch 'iss53' $ vim index.html $ git commit -a -m 'finished the new footer [issue 53]' - [iss53]: created ad82d7a: "finished the new footer [issue 53]" - 1 files changed, 1 insertions(+), 0 deletions(-) + [iss53 ad82d7a] finished the new footer [issue 53] + 1 file changed, 1 insertion(+) -Insert 18333fig0315.png +Insert 18333fig0315.png 图 3-15. iss53 分支可以不受影响继续推进。 值得注意的是之前 `hotfix` 分支的修改内容尚未包含到 `iss53` 中来。如果需要纳入此次修补,可以用 `git merge master` 把 master 分支合并到 `iss53`;或者等 `iss53` 完成之后,再将 `iss53` 分支中的更新并入 `master`。 @@ -199,20 +199,21 @@ Insert 18333fig0315.png $ git checkout master $ git merge iss53 - Merge made by recursive. - README | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) + Auto-merging README + Merge made by the 'recursive' strategy. + README | 1 + + 1 file changed, 1 insertion(+) 请注意,这次合并操作的底层实现,并不同于之前 `hotfix` 的并入方式。因为这次你的开发历史是从更早的地方开始分叉的。由于当前 `master` 分支所指向的提交对象(C4)并不是 `iss53` 分支的直接祖先,Git 不得不进行一些额外处理。就此例而言,Git 会用两个分支的末端(C4 和 C5)以及它们的共同祖先(C2)进行一次简单的三方合并计算。图 3-16 用红框标出了 Git 用于合并的三个提交对象: -Insert 18333fig0316.png +Insert 18333fig0316.png 图 3-16. Git 为分支合并自动识别出最佳的同源合并点。 这次,Git 没有简单地把分支指针右移,而是对三方合并后的结果重新做一个新的快照,并自动创建一个指向它的提交对象(C6)(见图 3-17)。这个提交对象比较特殊,它有两个祖先(C4 和 C5)。 值得一提的是 Git 可以自己裁决哪个共同祖先才是最佳合并基础;这和 CVS 或 Subversion(1.5 以后的版本)不同,它们需要开发者手工指定合并基础。所以此特性让 Git 的合并操作比其他系统都要简单不少。 -Insert 18333fig0317.png +Insert 18333fig0317.png 图 3-17. Git 自动创建了一个包含了合并结果的提交对象。 既然之前的工作成果已经合并到 `master` 了,那么 `iss53` 也就没用了。你可以就此删除它,并在问题追踪系统里关闭该问题。 @@ -230,25 +231,27 @@ Insert 18333fig0317.png Git 作了合并,但没有提交,它会停下来等你解决冲突。要看看哪些文件在合并时发生冲突,可以用 `git status` 查阅: - [master*]$ git status - index.html: needs merge - # On branch master - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # unmerged: index.html - # + $ git status + On branch master + You have unmerged paths. + (fix conflicts and run "git commit") + + Unmerged paths: + (use "git add ..." to mark resolution) + + both modified: index.html + + no changes added to commit (use "git add" and/or "git commit -a") 任何包含未解决冲突的文件都会以未合并(unmerged)的状态列出。Git 会在有冲突的文件里加入标准的冲突解决标记,可以通过它们来手工定位并解决这些冲突。可以看到此文件包含类似下面这样的部分: - <<<<<<< HEAD:index.html + <<<<<<< HEAD ======= - >>>>>>> iss53:index.html + >>>>>>> iss53 可以看到 `=======` 隔开的上半部分,是 `HEAD`(即 `master` 分支,在运行 `merge` 命令时所切换到的分支)中的内容,下半部分是在 `iss53` 分支中的内容。解决冲突的办法无非是二者选其一或者由你亲自整合到一起。比如你可以通过把这段内容替换为下面这样来解决: @@ -259,12 +262,17 @@ Git 作了合并,但没有提交,它会停下来等你解决冲突。要看 这个解决方案各采纳了两个分支中的一部分内容,而且我还删除了 `<<<<<<<`,`=======` 和 `>>>>>>>` 这些行。在解决了所有文件里的所有冲突后,运行 `git add` 将把它们标记为已解决状态(译注:实际上就是来一次快照保存到暂存区域。)。因为一旦暂存,就表示冲突已经解决。如果你想用一个有图形界面的工具来解决这些问题,不妨运行 `git mergetool`,它会调用一个可视化的合并工具并引导你解决所有冲突: $ git mergetool - merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff - Merging the files: index.html + + This message is displayed because 'merge.tool' is not configured. + See 'git mergetool --tool-help' or 'git help config' for more details. + 'git mergetool' will now attempt to use one of the following tools: + opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge + Merging: + index.html Normal merge conflict for 'index.html': - {local}: modified - {remote}: modified + {local}: modified file + {remote}: modified file Hit return to start merge resolution tool (opendiff): 如果不想用默认的合并工具(Git 为我默认选择了 `opendiff`,因为我在 Mac 上运行了该命令),你可以在上方"merge tool candidates"里找到可用的合并工具列表,输入你想用的工具名。我们将在第七章讨论怎样改变环境中的默认值。 @@ -274,12 +282,12 @@ Git 作了合并,但没有提交,它会停下来等你解决冲突。要看 再运行一次 `git status` 来确认所有冲突都已解决: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: index.html - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: index.html + 如果觉得满意了,并且确认所有冲突都已解决,也就是进入了暂存区,就可以用 `git commit` 来完成这次合并提交。提交的记录差不多是这样: @@ -288,9 +296,9 @@ Git 作了合并,但没有提交,它会停下来等你解决冲突。要看 Conflicts: index.html # - # It looks like you may be committing a MERGE. + # It looks like you may be committing a merge. # If this is not correct, please remove the file - # .git/MERGE_HEAD + # .git/MERGE_HEAD # and try again. # @@ -330,7 +338,7 @@ Git 作了合并,但没有提交,它会停下来等你解决冲突。要看 它会显示还未合并进来的分支。由于这些分支中还包含着尚未合并进来的工作成果,所以简单地用 `git branch -d` 删除该分支会提示错误,因为那样做会丢失数据: $ git branch -d testing - error: The branch 'testing' is not an ancestor of your current HEAD. + error: The branch 'testing' is not fully merged. If you are sure you want to delete it, run 'git branch -D testing'. 不过,如果你确实想要删除该分支上的改动,可以用大写的删除选项 `-D` 强制执行,就像上面提示信息中给出的那样。 @@ -347,12 +355,12 @@ Git 作了合并,但没有提交,它会停下来等你解决冲突。要看 本质上我们刚才谈论的,是随着提交对象不断右移的指针。稳定分支的指针总是在提交历史中落后一大截,而前沿分支总是比较靠前(见图 3-18)。 -Insert 18333fig0318.png +Insert 18333fig0318.png 图 3-18. 稳定分支总是比较老旧。 或者把它们想象成工作流水线,或许更好理解一些,经过测试的提交对象集合被遴选到更稳定的流水线(见图 3-19)。 -Insert 18333fig0319.png +Insert 18333fig0319.png 图 3-19. 想象成流水线可能会容易点。 你可以用这招维护不同层次的稳定性。某些大项目还会有个 `proposed`(建议)或 `pu`(proposed updates,建议更新)分支,它包含着那些可能还没有成熟到进入 `next` 或 `master` 的内容。这么做的目的是拥有不同层次的稳定性:当这些分支进入到更稳定的水平时,再把它们合并到更高层分支中去。再次说明下,使用多个长期分支的做法并非必需,不过一般来说,对于特大型项目或特复杂的项目,这么做确实更容易管理。 @@ -365,12 +373,12 @@ Insert 18333fig0319.png 现在我们来看一个实际的例子。请看图 3-20,由下往上,起先我们在 `master` 工作到 C1,然后开始一个新分支 `iss91` 尝试修复 91 号缺陷,提交到 C6 的时候,又冒出一个解决该问题的新办法,于是从之前 C4 的地方又分出一个分支 `iss91v2`,干到 C8 的时候,又回到主干 `master` 中提交了 C9 和 C10,再回到 `iss91v2` 继续工作,提交 C11,接着,又冒出个不太确定的想法,从 `master` 的最新提交 C10 处开了个新的分支 `dumbidea` 做些试验。 -Insert 18333fig0320.png +Insert 18333fig0320.png 图 3-20. 拥有多个特性分支的提交历史。 现在,假定两件事情:我们最终决定使用第二个解决方案,即 `iss91v2` 中的办法;另外,我们把 `dumbidea` 分支拿给同事们看了以后,发现它竟然是个天才之作。所以接下来,我们准备抛弃原来的 `iss91` 分支(实际上会丢弃 C5 和 C6),直接在主干中并入另外两个分支。最终的提交历史将变成图 3-21 这样: -Insert 18333fig0321.png +Insert 18333fig0321.png 图 3-21. 合并了 dumbidea 和 iss91v2 后的分支历史。 请务必牢记这些分支全部都是本地分支,这一点很重要。当你在使用分支及合并的时候,一切都是在你自己的 Git 仓库中进行的 — 完全不涉及与服务器的交互。 @@ -383,27 +391,27 @@ Insert 18333fig0321.png 可能有点乱,我们不妨举例说明。假设你们团队有个地址为 `git.ourcompany.com` 的 Git 服务器。如果你从这里克隆,Git 会自动为你将此远程仓库命名为 `origin`,并下载其中所有的数据,建立一个指向它的 `master` 分支的指针,在本地命名为 `origin/master`,但你无法在本地更改其数据。接着,Git 建立一个属于你自己的本地 `master` 分支,始于 `origin` 上 `master` 分支相同的位置,你可以就此开始工作(见图 3-22): -Insert 18333fig0322.png +Insert 18333fig0322.png 图 3-22. 一次 Git 克隆会建立你自己的本地分支 master 和远程分支 origin/master,并且将它们都指向 `origin` 上的 `master` 分支。 如果你在本地 `master` 分支做了些改动,与此同时,其他人向 `git.ourcompany.com` 推送了他们的更新,那么服务器上的 `master` 分支就会向前推进,而于此同时,你在本地的提交历史正朝向不同方向发展。不过只要你不和服务器通讯,你的 `origin/master` 指针仍然保持原位不会移动(见图 3-23)。 -Insert 18333fig0323.png +Insert 18333fig0323.png 图 3-23. 在本地工作的同时有人向远程仓库推送内容会让提交历史开始分流。 可以运行 `git fetch origin` 来同步远程服务器上的数据到本地。该命令首先找到 `origin` 是哪个服务器(本例为 `git.ourcompany.com`),从上面获取你尚未拥有的数据,更新你本地的数据库,然后把 `origin/master` 的指针移到它最新的位置上(见图 3-24)。 -Insert 18333fig0324.png +Insert 18333fig0324.png 图 3-24. git fetch 命令会更新 remote 索引。 为了演示拥有多个远程分支(在不同的远程服务器上)的项目是如何工作的,我们假设你还有另一个仅供你的敏捷开发小组使用的内部服务器 `git.team1.ourcompany.com`。可以用第二章中提到的 `git remote add` 命令把它加为当前项目的远程分支之一。我们把它命名为 `teamone`,以便代替完整的 Git URL 以方便使用(见图 3-25)。 -Insert 18333fig0325.png +Insert 18333fig0325.png 图 3-25. 把另一个服务器加为远程仓库 现在你可以用 `git fetch teamone` 来获取小组服务器上你还没有的数据了。由于当前该服务器上的内容是你 `origin` 服务器上的子集,Git 不会下载任何数据,而只是简单地创建一个名为 `teamone/master` 的远程分支,指向 `teamone` 服务器上 `master` 分支所在的提交对象 `31b8e`(见图 3-26)。 -Insert 18333fig0326.png +Insert 18333fig0326.png 图 3-26. 你在本地有了一个指向 teamone 服务器上 master 分支的索引。 ### 推送本地分支 ### @@ -437,8 +445,8 @@ Insert 18333fig0326.png 如果要把该远程分支的内容合并到当前分支,可以运行 `git merge origin/serverfix`。如果想要一份自己的 `serverfix` 来开发,可以在远程分支的基础上分化出一个新的分支来: $ git checkout -b serverfix origin/serverfix - Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "serverfix" + Branch serverfix set up to track remote branch serverfix from origin. + Switched to a new branch 'serverfix' 这会切换到新建的 `serverfix` 本地分支,其内容同远程分支 `origin/serverfix` 一致,这样你就可以在里面继续开发了。 @@ -449,14 +457,14 @@ Insert 18333fig0326.png 在克隆仓库时,Git 通常会自动创建一个名为 `master` 的分支来跟踪 `origin/master`。这正是 `git push` 和 `git pull` 一开始就能正常工作的原因。当然,你可以随心所欲地设定为其它跟踪分支,比如 `origin` 上除了 `master` 之外的其它分支。刚才我们已经看到了这样的一个例子:`git checkout -b [分支名] [远程名]/[分支名]`。如果你有 1.6.2 以上版本的 Git,还可以用 `--track` 选项简化: $ git checkout --track origin/serverfix - Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "serverfix" + Branch serverfix set up to track remote branch serverfix from origin. + Switched to a new branch 'serverfix' 要为本地分支设定不同于远程分支的名字,只需在第一个版本的命令里换个名字: $ git checkout -b sf origin/serverfix - Branch sf set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "sf" + Branch sf set up to track remote branch serverfix from origin. + Switched to a new branch 'sf' 现在你的本地分支 `sf` 会自动将推送和抓取数据的位置定位到 `origin/serverfix` 了。 @@ -478,12 +486,12 @@ Insert 18333fig0326.png 请回顾之前有关合并的一节(见图 3-27),你会看到开发进程分叉到两个不同分支,又各自提交了更新。 -Insert 18333fig0327.png +Insert 18333fig0327.png 图 3-27. 最初分叉的提交历史。 之前介绍过,最容易的整合分支的方法是 `merge` 命令,它会把两个分支最新的快照(C3 和 C4)以及二者最新的共同祖先(C2)进行三方合并,合并的结果是产生一个新的提交对象(C5)。如图 3-28 所示: -Insert 18333fig0328.png +Insert 18333fig0328.png 图 3-28. 通过合并一个分支来整合分叉了的历史。 其实,还有另外一个选择:你可以把在 C3 里产生的变化补丁在 C4 的基础上重新打一遍。在 Git 里,这种操作叫做_衍合(rebase)_。有了 `rebase` 命令,就可以把在一个分支里提交的改变移到另一个分支里重放一遍。 @@ -497,12 +505,12 @@ Insert 18333fig0328.png 它的原理是回到两个分支最近的共同祖先,根据当前分支(也就是要进行衍合的分支 `experiment`)后续的历次提交对象(这里只有一个 C3),生成一系列文件补丁,然后以基底分支(也就是主干分支 `master`)最后一个提交对象(C4)为新的出发点,逐个应用之前准备好的补丁文件,最后会生成一个新的合并提交对象(C3'),从而改写 `experiment` 的提交历史,使它成为 `master` 分支的直接下游,如图 3-29 所示: -Insert 18333fig0329.png +Insert 18333fig0329.png 图 3-29. 把 C3 里产生的改变到 C4 上重演一遍。 现在回到 `master` 分支,进行一次快进合并(见图 3-30): -Insert 18333fig0330.png +Insert 18333fig0330.png 图 3-30. master 分支的快进。 现在的 C3' 对应的快照,其实和普通的三方合并,即上个例子中的 C5 对应的快照内容一模一样了。虽然最后整合得到的结果没有任何区别,但衍合能产生一个更为整洁的提交历史。如果视察一个衍合过的分支的历史记录,看起来会更清楚:仿佛所有修改都是在一根线上先后进行的,尽管实际上它们原本是同时并行发生的。 @@ -515,7 +523,7 @@ Insert 18333fig0330.png 衍合也可以放到其他分支进行,并不一定非得根据分化之前的分支。以图 3-31 的历史为例,我们为了给服务器端代码添加一些功能而创建了特性分支 `server`,然后提交 C3 和 C4。然后又从 C3 的地方再增加一个 `client` 分支来对客户端代码进行一些相应修改,所以提交了 C8 和 C9。最后,又回到 `server` 分支提交了 C10。 -Insert 18333fig0331.png +Insert 18333fig0331.png 图 3-31. 从一个特性分支里再分出一个特性分支的历史。 假设在接下来的一次软件发布中,我们决定先把客户端的修改并到主线中,而暂缓并入服务端软件的修改(因为还需要进一步测试)。这个时候,我们就可以把基于 `server` 分支而非 `master` 分支的改变(即 C8 和 C9),跳过 `server` 直接放到 `master` 分支中重演一遍,但这需要用 `git rebase` 的 `--onto` 选项指定新的基底分支 `master`: @@ -524,7 +532,7 @@ Insert 18333fig0331.png 这好比在说:“取出 `client` 分支,找出 `client` 分支和 `server` 分支的共同祖先之后的变化,然后把它们在 `master` 上重演一遍”。是不是有点复杂?不过它的结果如图 3-32 所示,非常酷(译注:虽然 `client` 里的 C8, C9 在 C3 之后,但这仅表明时间上的先后,而非在 C3 修改的基础上进一步改动,因为 `server` 和 `client` 这两个分支对应的代码应该是两套文件,虽然这么说不是很严格,但应理解为在 C3 时间点之后,对另外的文件所做的 C8,C9 修改,放到主干重演。): -Insert 18333fig0332.png +Insert 18333fig0332.png 图 3-32. 将特性分支上的另一个特性分支衍合到其他分支。 现在可以快进 `master` 分支了(见图 3-33): @@ -532,7 +540,7 @@ Insert 18333fig0332.png $ git checkout master $ git merge client -Insert 18333fig0333.png +Insert 18333fig0333.png 图 3-33. 快进 master 分支,使之包含 client 分支的变化。 现在我们决定把 `server` 分支的变化也包含进来。我们可以直接把 `server` 分支衍合到 `master`,而不用手工切换到 `server` 分支后再执行衍合操作 — `git rebase [主分支] [特性分支]` 命令会先取出特性分支 `server`,然后在主分支 `master` 上重演: @@ -541,7 +549,7 @@ Insert 18333fig0333.png 于是,`server` 的进度应用到 `master` 的基础上,如图 3-34 所示: -Insert 18333fig0334.png +Insert 18333fig0334.png 图 3-34. 在 master 分支上衍合 server 分支。 然后就可以快进主干分支 `master` 了: @@ -554,7 +562,7 @@ Insert 18333fig0334.png $ git branch -d client $ git branch -d server -Insert 18333fig0335.png +Insert 18333fig0335.png 图 3-35. 最终的提交历史 ### 衍合的风险 ### @@ -569,22 +577,22 @@ Insert 18333fig0335.png 下面我们用一个实际例子来说明为什么公开的衍合会带来问题。假设你从一个中央服务器克隆然后在它的基础上搞了一些开发,提交历史类似图 3-36 所示: -Insert 18333fig0336.png +Insert 18333fig0336.png 图 3-36. 克隆一个仓库,在其基础上工作一番。 现在,某人在 C1 的基础上做了些改变,并合并他自己的分支得到结果 C6,推送到中央服务器。当你抓取并合并这些数据到你本地的开发分支中后,会得到合并结果 C7,历史提交会变成图 3-37 这样: -Insert 18333fig0337.png +Insert 18333fig0337.png 图 3-37. 抓取他人提交,并入自己主干。 接下来,那个推送 C6 上来的人决定用衍合取代之前的合并操作;继而又用 `git push --force` 覆盖了服务器上的历史,得到 C4'。而之后当你再从服务器上下载最新提交后,会得到: -Insert 18333fig0338.png +Insert 18333fig0338.png 图 3-38. 有人推送了衍合后得到的 C4',丢弃了你作为开发基础的 C4 和 C6。 下载更新后需要合并,但此时衍合产生的提交对象 C4' 的 SHA-1 校验值和之前 C4 完全不同,所以 Git 会把它们当作新的提交对象处理,而实际上此刻你的提交历史 C7 中早已经包含了 C4 的修改内容,于是合并操作会把 C7 和 C4' 合并为 C8(见图 3-39): -Insert 18333fig0339.png +Insert 18333fig0339.png 图 3-39. 你把相同的内容又合并了一遍,生成一个新的提交 C8。 C8 这一步的合并是迟早会发生的,因为只有这样你才能和其他协作者提交的内容保持同步。而在 C8 之后,你的提交历史里就会同时包含 C4 和 C4',两者有着不同的 SHA-1 校验值,如果用 `git log` 查看历史,会看到两个提交拥有相同的作者日期与说明,令人费解。而更糟的是,当你把这样的历史推送到服务器后,会再次把这些衍合后的提交引入到中央服务器,进一步困扰其他人(译注:这个例子中,出问题的责任方是那个发布了 C6 后又用衍合发布 C4' 的人,其他人会因此反馈双重历史到共享主干,从而混淆大家的视听。)。 diff --git a/zh/04-git-server/01-chapter4.markdown b/zh/04-git-server/01-chapter4.markdown index 4df2c0ce2..ae751aeef 100644 --- a/zh/04-git-server/01-chapter4.markdown +++ b/zh/04-git-server/01-chapter4.markdown @@ -55,7 +55,7 @@ Git 使用的传输协议中最常见的可能就是 SSH 了。这是因为大 $ git clone ssh://user@server/project.git 或者不指明某个协议 — 这时 Git 会默认使用 SSH : - + $ git clone user@server:project.git 如果不指明用户,Git 会默认使用当前登录的用户名连接服务器。 @@ -78,7 +78,8 @@ Git 协议是现存最快的传输协议。如果你在提供一个有很大访 #### 缺点 #### -Git 协议消极的一面是缺少授权机制。用 Git 协议作为访问项目的唯一方法通常是不可取的。一般的做法是,同时提供 SSH 接口,让几个开发者拥有推送(写)权限,其他人通过 `git://` 拥有只读权限。Git 协议可能也是最难架设的协议。它要求有单独的守护进程,需要定制 — 我们将在本章的 “Gitosis” 一节详细介绍它的架设 — 需要设定 `xinetd` 或类似的程序,而这些工作就没那么轻松了。该协议还要求防火墙开放 9418 端口,而企业级防火墙一般不允许对这个非标准端口的访问。大型企业级防火墙通常会封锁这个少见的端口。 +Git 协议消极的一面是缺少授权机制。用 Git 协议作为访问项目的唯一方法通常是不可取的。一般的做法是,同时提供 SSH 接口,让几个开发者拥有推送(写)权限,其他人通过 `git://` 拥有只读权限。 +Git 协议可能也是最难架设的协议。它要求有单独的守护进程,需要定制 — 我们将在本章的 “Gitosis” 一节详细介绍它的架设 — 需要设定 `xinetd` 或类似的程序,而这些工作就没那么轻松了。该协议还要求防火墙开放 9418 端口,而企业级防火墙一般不允许对这个非标准端口的访问。大型企业级防火墙通常会封锁这个少见的端口。 ### HTTP/S 协议 ### @@ -115,7 +116,8 @@ HTTP 协议的消极面在于,相对来说客户端效率更低。克隆或者 开始架设 Git 服务器前,需要先把现有仓库导出为裸仓库 — 即一个不包含当前工作目录的仓库。做法直截了当,克隆时用 `--bare` 选项即可。裸仓库的目录名一般以 `.git` 结尾,像这样: $ git clone --bare my_project my_project.git - Initialized empty Git repository in /opt/projects/my_project.git/ + Cloning into bare repository 'my_project.git'... + done. 该命令的输出或许会让人有些不解。其实 `clone` 操作基本上相当于 `git init` 加 `git fetch`,所以这里出现的其实是 `git init` 的输出,先由它建立一个空目录,而之后传输数据对象的操作并无任何输出,只是悄悄在幕后执行。现在 `my_project.git` 目录中已经有了一份 Git 目录数据的副本。 @@ -165,7 +167,8 @@ HTTP 协议的消极面在于,相对来说客户端效率更低。克隆或者 ## 生成 SSH 公钥 ## -大多数 Git 服务器都会选择使用 SSH 公钥来进行授权。系统中的每个用户都必须提供一个公钥用于授权,没有的话就要生成一个。生成公钥的过程在所有操作系统上都差不多。首先先确认一下是否已经有一个公钥了。SSH 公钥默认储存在账户的主目录下的 `~/.ssh` 目录。进去看看: +大多数 Git 服务器都会选择使用 SSH 公钥来进行授权。系统中的每个用户都必须提供一个公钥用于授权,没有的话就要生成一个。生成公钥的过程在所有操作系统上都差不多。 +首先先确认一下是否已经有一个公钥了。SSH 公钥默认储存在账户的主目录下的 `~/.ssh` 目录。进去看看: $ cd ~/.ssh $ ls @@ -174,11 +177,11 @@ HTTP 协议的消极面在于,相对来说客户端效率更低。克隆或者 关键是看有没有用 `something` 和 `something.pub` 来命名的一对文件,这个 `something` 通常就是 `id_dsa` 或 `id_rsa`。有 `.pub` 后缀的文件就是公钥,另一个文件则是密钥。假如没有这些文件,或者干脆连 `.ssh` 目录都没有,可以用 `ssh-keygen` 来创建。该程序在 Linux/Mac 系统上由 SSH 包提供,而在 Windows 上则包含在 MSysGit 包里: - $ ssh-keygen + $ ssh-keygen Generating public/private rsa key pair. - Enter file in which to save the key (/Users/schacon/.ssh/id_rsa): - Enter passphrase (empty for no passphrase): - Enter same passphrase again: + Enter file in which to save the key (/Users/schacon/.ssh/id_rsa): + Enter passphrase (empty for no passphrase): + Enter same passphrase again: Your identification has been saved in /Users/schacon/.ssh/id_rsa. Your public key has been saved in /Users/schacon/.ssh/id_rsa.pub. The key fingerprint is: @@ -188,7 +191,7 @@ HTTP 协议的消极面在于,相对来说客户端效率更低。克隆或者 现在,所有做过这一步的用户都得把它们的公钥给你或者 Git 服务器的管理员(假设 SSH 服务被设定为使用公钥机制)。他们只需要复制 `.pub` 文件的内容然后发邮件给管理员。公钥的样子大致如下: - $ cat ~/.ssh/id_rsa.pub + $ cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3 Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA @@ -243,6 +246,7 @@ HTTP 协议的消极面在于,相对来说客户端效率更低。克隆或者 这样,其他人的克隆和推送也一样变得很简单: $ git clone git@gitserver:/opt/git/project.git + $ cd project $ vim README $ git commit -am 'fix for the README file' $ git push origin master @@ -279,12 +283,17 @@ HTTP 协议的消极面在于,相对来说客户端效率更低。克隆或者 $ mv hooks/post-update.sample hooks/post-update $ chmod a+x hooks/post-update -如果用的是 Git 1.6 之前的版本,则可以省略 `mv` 命令 — Git 是从较晚的版本才开始在挂钩实例的结尾添加 .sample 后缀名的。 - `post-update` 挂钩是做什么的呢?其内容大致如下: - $ cat .git/hooks/post-update + $ cat .git/hooks/post-update #!/bin/sh + # + # An example hook script to prepare a packed repository for use over + # dumb transports. + # + # To enable this hook, rename this file to "post-update". + # + exec git-update-server-info 意思是当通过 SSH 向服务器推送时,Git 将运行这个 `git-update-server-info` 命令来更新匿名 HTTP 访问获取数据时所需要的文件。 @@ -314,7 +323,7 @@ HTTP 协议的消极面在于,相对来说客户端效率更低。克隆或者 现在我们的项目已经有了可读可写和只读的连接方式,不过如果能有一个简单的 web 界面访问就更好了。Git 自带一个叫做 GitWeb 的 CGI 脚本,运行效果可以到 `http://git.kernel.org` 这样的站点体验下(见图 4-1)。 -Insert 18333fig0401.png +Insert 18333fig0401.png Figure 4-1. 基于网页的 GitWeb 用户界面 如果想看看自己项目的效果,不妨用 Git 自带的一个命令,可以使用类似 `lighttpd` 或 `webrick` 这样轻量级的服务器启动一个临时进程。如果是在 Linux 主机上,通常都预装了 `lighttpd` ,可以到项目目录中键入 `git instaweb` 来启动。如果用的是 Mac ,Leopard 预装了 Ruby,所以 `webrick` 应该是最好的选择。如果要用 lighttpd 以外的程序来启动 `git instaweb`,可以通过 `--httpd` 选项指定: @@ -332,7 +341,7 @@ Figure 4-1. 基于网页的 GitWeb 用户界面 $ git clone git://git.kernel.org/pub/scm/git/git.git $ cd git/ $ make GITWEB_PROJECTROOT="/opt/git" \ - prefix=/usr gitweb/gitweb.cgi + prefix=/usr gitweb $ sudo cp -Rf gitweb /var/www/ 注意,通过指定 `GITWEB_PROJECTROOT` 变量告诉编译命令 Git 仓库的位置。然后,设置 Apache 以 CGI 方式运行该脚本,添加一个 VirtualHost 配置: @@ -400,7 +409,7 @@ Gitosis 将会帮我们管理用户公钥,所以先把当前控制文件改名 $ ssh git@gitserver PTY allocation request failed on channel 0 - fatal: unrecognized command 'gitosis-serve schacon@quaternion' + ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment. Connection to gitserver closed. 说明 Gitosis 认出了该用户的身份,但由于没有运行任何 Git 命令,所以它切断了连接。那么,现在运行一个实际的 Git 命令 — 克隆 Gitosis 的控制仓库: @@ -420,32 +429,32 @@ Gitosis 将会帮我们管理用户公钥,所以先把当前控制文件改名 看一下 `gitosis.conf` 文件的内容,它应该只包含与刚刚克隆的 `gitosis-admin` 相关的信息: - $ cat gitosis.conf + $ cat gitosis.conf [gitosis] [group gitosis-admin] - writable = gitosis-admin members = scott + writable = gitosis-admin 它显示用户 `scott` — 初始化 Gitosis 公钥的拥有者 — 是唯一能管理 `gitosis-admin` 项目的人。 现在我们来添加一个新项目。为此我们要建立一个名为 `mobile` 的新段落,在其中罗列手机开发团队的开发者,以及他们拥有写权限的项目。由于 'scott' 是系统中的唯一用户,我们把他设为唯一用户,并允许他读写名为 `iphone_project` 的新项目: [group mobile] - writable = iphone_project members = scott + writable = iphone_project 修改完之后,提交 `gitosis-admin` 里的改动,并推送到服务器使其生效: $ git commit -am 'add iphone_project and mobile group' - [master]: created 8962da8: "changed name" - 1 files changed, 4 insertions(+), 0 deletions(-) - $ git push + [master 8962da8] add iphone_project and mobile group + 1 file changed, 4 insertions(+) + $ git push origin master Counting objects: 5, done. - Compressing objects: 100% (2/2), done. - Writing objects: 100% (3/3), 272 bytes, done. - Total 3 (delta 1), reused 0 (delta 0) - To git@gitserver:/opt/git/gitosis-admin.git + Compressing objects: 100% (3/3), done. + Writing objects: 100% (3/3), 272 bytes | 0 bytes/s, done. + Total 3 (delta 0), reused 0 (delta 0) + To git@gitserver:gitosis-admin.git fb27aec..8962da8 master -> master 在新工程 `iphone_project` 里首次推送数据到服务器前,得先设定该服务器地址为远程仓库。但你不用事先到服务器上手工创建该项目的裸仓库— Gitosis 会在第一次遇到推送时自动创建: @@ -454,7 +463,7 @@ Gitosis 将会帮我们管理用户公钥,所以先把当前控制文件改名 $ git push origin master Initialized empty Git repository in /opt/git/iphone_project.git/ Counting objects: 3, done. - Writing objects: 100% (3/3), 230 bytes, done. + Writing objects: 100% (3/3), 230 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To git@gitserver:iphone_project.git * [new branch] master -> master @@ -470,20 +479,20 @@ Gitosis 将会帮我们管理用户公钥,所以先把当前控制文件改名 然后把他们都加进 'mobile' 团队,让他们对 `iphone_project` 具有读写权限: [group mobile] - writable = iphone_project members = scott john josie jessica + writable = iphone_project 如果你提交并推送这个修改,四个用户将同时具有该项目的读写权限。 Gitosis 也具有简单的访问控制功能。如果想让 John 只有读权限,可以这样做: [group mobile] - writable = iphone_project members = scott josie jessica + writable = iphone_project [group mobile_ro] - readonly = iphone_project members = john + readonly = iphone_project 现在 John 可以克隆和获取更新,但 Gitosis 不会允许他向项目推送任何内容。像这样的组可以随意创建,多少不限,每个都可以包含若干不同的用户和项目。甚至还可以指定某个组为成员之一(在组名前加上 `@` 前缀),自动继承该组的成员: @@ -491,70 +500,46 @@ Gitosis 也具有简单的访问控制功能。如果想让 John 只有读权限 members = scott josie jessica [group mobile] - writable = iphone_project members = @mobile_committers + writable = iphone_project [group mobile_2] - writable = another_iphone_project members = @mobile_committers john + writable = another_iphone_project 如果遇到意外问题,试试看把 `loglevel=DEBUG` 加到 `[gitosis]` 的段落(译注:把日志设置为调试级别,记录更详细的运行信息。)。如果一不小心搞错了配置,失去了推送权限,也可以手工修改服务器上的 `/home/git/.gitosis.conf` 文件 — Gitosis 实际是从该文件读取信息的。它在得到推送数据时,会把新的 `gitosis.conf` 存到该路径上。所以如果你手工编辑该文件的话,它会一直保持到下次向 `gitosis-admin` 推送新版本的配置内容为止。 ## Gitolite ## -注:本书此段落的最新拷贝始终存在于[gitolite documentation][gldpg]. 作者谦虚地表示,尽管这个段落是精确的,可以(已经)用于安装gitolite而不用阅读其他的文档,但仍有必要不完整,并且不能完全替代随gitolite自带的大量文档。 +This section serves as a quick introduction to Gitolite, and provides basic installation and setup instructions. 不能完全替代随 gitolite 自带的大量文档。 There may also be occasional changes to this section itself, so you may also want to look at the latest version [here][gldpg]. [gldpg]: http://sitaramc.github.com/gitolite/progit.html +[gltoc]: http://sitaramc.github.com/gitolite/master-toc.html -Git已经变成了非常流行的写作环境,并倾向于为了访问控制而增加额外的需求。Gitolite用于帮助这些需求而创建,但它变成了对开源世界同样有用的东西:Fedora项目使用gitolite控制访问他们的包管理仓库 (超过 10,000个包!) , 而且这也可能是最大的gitolite装置。 +Gitolite is an authorization layer on top of Git, relying on `sshd` or `httpd` for authentication. (Recap: authentication is identifying who the user is, authorization is deciding if he is allowed to do what he is attempting to). Gitolite 允许你定义访问许可而不只作用于仓库,而同样于仓库中的每个branch和tag name。你可以定义确切的人 (或一组人) 只能push特定的 "refs" (或者branches或者tags)而不是其他人。 ### 安装 ### -安装 Gitolite非常简单, 你甚至不用读自带的那一大堆文档。你需要一个unix服务器上的账户;许多linux变种和solaris 10都已经试过了。你不需要root访问,假设git,perl,和一个openssh兼容的ssh服务器已经装好了。在下面的例子里,我们会用 `gitolite` 账户在 `gitserver`上. - -Gitolite 是不同于 "server" 的软件 -- 通过ssh访问, 而且每个在服务器上的userid都是一个潜在的 "gitolite host". 因此, "安装" 这个软件的概念意味着安装它自身, 然后"设置" 一个用户作为 "gitolite host". - -Gitolite 有4种安装方法。用 Fedora 或 Debian 的人可以获取一个 RPM或者 DEB安装。有root权限的人可以手动安装。在这两种方法中,任意系统上的用户变成一个 "gitolite host"。 - -没有 root访问权限的人可以安装在他们自己的 userid 下面。最后,gitolite可以用一个“工作站上”的脚本在bash shell安装。(如果你想的话甚至msysgit带的bash就可以。) - -我们要描述这个最后一个方法;其他方法请看文档。 - -首先你要获取一个访问服务器的公钥,你可以从你自己的工作站部属密码访问服务器。下面的方法在linux上管用;其他的工作站系统你可以手动做这些事。我们假设你已经用'ssh-keygen'生成了一对密钥。 - - $ ssh-copy-id -i ~/.ssh/id_rsa gitolite@gitserver - -这会要你 gitolite账户的密码,然后设置公钥访问。这个对安装脚本非常 **重要**,所以试一下保证你可以不输密码: +安装 Gitolite非常简单, 你甚至不用读自带的那一大堆文档。你需要一个unix服务器上的账户;许多linux变种和solaris 10都已经试过了。你不需要root访问,假设git,perl,和一个openssh兼容的ssh服务器已经装好了。在下面的例子里,我们会用 `git` 账户在 `gitserver`上. - $ ssh gitolite@gitserver pwd - /home/gitolite +Gitolite 是不同于 "server" 的软件 -- 通过ssh访问, 而且每个在服务器上的userid都是一个潜在的 "gitolite host". We will describe the simplest install method in this article; for the other methods please see the documentation. -接下俩,你 clone Gitolite从项目的主目录运行 "easy install" 脚本 (第三个参数是你的作为 gitolite-admin仓库用户的名字): +To begin, create a user called `git` on your server and login to this user. Copy your SSH public key (a file called `~/.ssh/id_rsa.pub` if you did a plain `ssh-keygen` with all the defaults) from your workstation, renaming it to `.pub` (we'll use `scott.pub` in our examples). Then run these commands: $ git clone git://github.com/sitaramc/gitolite - $ cd gitolite/src - $ ./gl-easy-install -q gitolite gitserver sitaram + $ gitolite/install -ln + # assumes $HOME/bin exists and is in your $PATH + $ gitolite setup -pk $HOME/scott.pub -然后就完成了!Gitolite已经在服务器上装好了,现在你有一个全新的仓库叫做 `gitolite-admin` 在你工作站的 home目录。你管理你的 gitolite 安装通过改变这个项目和push。 - -最后的命令产生大量的输出,你可能想读一下。而且你第一次运行的时候会产生一对新密钥;你会选择密码或者什么都不输。为什么需要第二个密钥对以及怎么用在Gitolite带的 "ssh troubleshooting" 文件里解释了。 (文档肯定有点什么用!) - -叫做 `gitolite-admin` 和 `testing` 的仓库默认创建在服务器上。如果你想在本地 clone这些 (从一个有ssh控制台 gitolite通过 *authorized_keys*访问的用户),输入: - - $ git clone gitolite:gitolite-admin - $ git clone gitolite:testing - -clone 这些同样的仓库从任意其他账户: - - $ git clone gitolite@servername:gitolite-admin - $ git clone gitolite@servername:testing +That last command creates new Git repository called `gitolite-admin` on the server. +Finally, back on your workstation, run `git clone git@gitserver:gitolite-admin`. And you’re done! Gitolite has now been installed on the server, and you now have a brand new repository called `gitolite-admin` in your workstation. You administer your Gitolite setup by making changes to this repository and pushing. ### 定制安装 ### -默认快速安装对大多数人都管用,还有一些定制安装方法如果你用的上的话。如果你不用 `-q` 参数,则用 "罗嗦" 模式安装 -- 详细信息关于安装的每一步都在做什么。 罗嗦模式也允许你改变服务器端参数,诸如实际仓库的位置,通过编辑服务器使用的 "rc" 文件。这个 "rc" 有好多注释让你编辑的时候变得非常简单,保存退出。这个文件也包括了许多设置你能改变来启用或者禁用一些gitolite的高级功能。 +默认快速安装对大多数人都管用,还有一些定制安装方法如果你用的上的话。Some changes can be made simply by editing the rc file, but if that is not sufficient, there’s documentation on customising Gitolite. ### 配置文件和访问规则 ### @@ -565,18 +550,18 @@ clone 这些同样的仓库从任意其他账户: conf/ keydir/ $ find conf keydir -type f conf/gitolite.conf - keydir/sitaram.pub + keydir/scott.pub $ cat conf/gitolite.conf - #gitolite conf - # please see conf/example.conf for details on syntax and features repo gitolite-admin - RW+ = sitaram + RW+ = scott repo testing RW+ = @all -注意 "sitaram" ( 之前用`gl-easy-install` 命令时候的最后一个参数) 有读写权限而且在 `gitolite-admin` 仓库里有一个同名的公钥文件。 +注意 "scott" ( 之前用`gl-setup` 命令时候的 pubkey 名稱) 有读写权限而且在 `gitolite-admin` 仓库里有一个同名的公钥文件。 + +Adding users is easy. To add a user called "alice", obtain her public key, name it `alice.pub`, and put it in the `keydir` directory of the clone of the `gitolite-admin` repo you just made on your workstation. Add, commit, and push the change, and the user has been added. gitolite配置文件的语法在 `conf/example.conf`里,我们只会提到一些主要的。 @@ -585,8 +570,8 @@ gitolite配置文件的语法在 `conf/example.conf`里,我们只会提到一 @oss_repos = linux perl rakudo git gitolite @secret_repos = fenestra pear - @admins = scott # Adams, not Chacon, sorry :) - @interns = ashok # get the spelling right, Scott! + @admins = scott + @interns = ashok @engineers = sitaram dilbert wally alice @staff = @admins @engineers @interns @@ -632,11 +617,9 @@ gitolite配置文件的语法在 `conf/example.conf`里,我们只会提到一 此外限制用户 push改变到哪条branch的,你也可以限制哪个文件他们可以碰的到。比如, 可能 Makefile (或者其他哪些程序) 真的不能被任何人做任何改动,因为好多东西都靠着它呢,或者如果某些改变刚好不对就会崩溃。你可以告诉 gitolite: repo foo - RW = @junior_devs @senior_devs + RW = @junior_devs @senior_devs - RW NAME/ = @senior_devs - - NAME/Makefile = @junior_devs - RW NAME/ = @junior_devs + - VREF/NAME/Makefile = @junior_devs 这是一个强力的公能写在 `conf/example.conf`里。 @@ -660,12 +643,10 @@ Gitolite 允许你定义带通配符的仓库 (其实还是 perl正则式), 比 **记录**: Gitolite 记录所有成功的访问。如果你太放松给了别人 rewind许可 (`RW+`) 和其他孩子弄没了 "master", 记录文件会救你的命,如果其他简单快速的找到SHA都不管用。 -**Git在通常路径外**: 一个在gitolite里的超级有用的简单功能是支持git安装在通常的 `$PATH`之外 (这个比你想象的还要寻常;一些合作环境或者甚至一些主机提供商拒绝安装系统范围外的东西你只能放在自己的目录里)。通常,你被强迫用 *客户端* 用某种方法找到git 为这个非标准的位置。使用 gitolite,只要选择絮叨安装设置 `$GIT_PATH`在 "rc" 文件里。不用改变客户端然后 :-)。 - **访问权报告**: 另一个方便的功能是你尝试用ssh连接到服务器的时候发生了什么。Gitolite告诉你哪个 repos你访问过,那个访问可能是什么。这里是例子: - hello sitaram, the gitolite version here is v1.5.4-19-ga3397d4 - the gitolite config gives you the following access: + hello scott, this is git@git running gitolite3 v3.01-18-g9609868 on git 1.7.4.4 + R anu-wsd R entrans R W git-notes @@ -676,8 +657,6 @@ Gitolite 允许你定义带通配符的仓库 (其实还是 perl正则式), 比 **委托**:真正的大安装,你可以把责任委托给一组仓库给不同的人然后让他们独立管理那些部分。这个减少了主管理者的负担,让他瓶颈更小。这个功能在他自己的文档目录里的 `doc/`下面。 -**Gitweb 支持**: Gitolite支持 gitweb以几种方式。你可以定义哪个仓库在gitweb可见。你能设置 "拥有者" 和 "描述" gitweb 从 gitolite配置文件里。Gitweb 有一个机制给你来实现基于http认证的访问控制,你能让它用 gitolite产生的 "编译过" 的配置文件,意思是同样的访问规则 (为读访问) 用于 gitweb和 gitolite. - **镜像**: Gitolite可以帮助你维护多个镜像,如果主服务器挂掉的话在他们之间很容易切换。 ## Git 守护进程 ## @@ -771,12 +750,13 @@ Insert 18333fig0402.png 选择一个系统中尚未使用的用户名,提供一个与之相关联的电邮地址,并输入密码(见图 4-3): -Insert 18333fig0403.png +Insert 18333fig0403.png 图 4-3. GitHub 用户注册表单 -如果方便,现在就可以提供你的 SSH 公钥。我们在前文的"小型安装" 一节介绍过生成新公钥的方法。把新生成的公钥复制粘贴到 SSH Public Key 文本框中即可。要是对生成公钥的步骤不太清楚,也可以点击 "explain ssh keys" 链接,会显示各个主流操作系统上完成该步骤的介绍。点击 "I agree,sign me up" 按钮完成用户注册,并转到该用户的 dashboard 页面(见图 4-4): +如果方便,现在就可以提供你的 SSH 公钥。我们在前文的"小型安装" 一节介绍过生成新公钥的方法。把新生成的公钥复制粘贴到 SSH Public Key 文本框中即可。要是对生成公钥的步骤不太清楚,也可以点击 "explain ssh keys" 链接,会显示各个主流操作系统上完成该步骤的介绍。 +点击 "I agree,sign me up" 按钮完成用户注册,并转到该用户的 dashboard 页面(见图 4-4): -Insert 18333fig0404.png +Insert 18333fig0404.png 图 4-4. GitHub 的用户面板 接下来就可以建立新仓库了。 @@ -785,17 +765,17 @@ Insert 18333fig0404.png 点击用户面板上仓库旁边的 "create a new one" 链接,显示 Create a New Repository 的表单(见图 4-5): -Insert 18333fig0405.png +Insert 18333fig0405.png 图 4-5. 在 GitHub 上建立新仓库 当然,项目名称是必不可少的,此外也可以适当描述一下项目的情况或者给出官方站点的地址。然后点击 "Create Repository" 按钮,新仓库就建立起来了(见图 4-6): -Insert 18333fig0406.png +Insert 18333fig0406.png 图 4-6. GitHub 上各个项目的概要信息 由于尚未提交代码,点击项目地址后 GitHub 会显示一个简要的指南,告诉你如何新建一个项目并推送上来,如何从现有项目推送,以及如何从一个公共的 Subversion 仓库导入项目(见图 4-7): -Insert 18333fig0407.png +Insert 18333fig0407.png 图 4-7. 新仓库指南 该指南和本书前文介绍的类似,对于新的项目,需要先在本地初始化为 Git 项目,添加要管理的文件并作首次提交: @@ -811,7 +791,7 @@ Insert 18333fig0407.png 现在该项目就托管在 GitHub 上了。你可以把它的 URL 分享给每位对此项目感兴趣的人。本例的 URL 是 `http://github.com/testinguser/iphone_project`。而在项目页面的摘要部分,你会发现有两个 Git URL 地址(见图 4-8): -Insert 18333fig0408.png +Insert 18333fig0408.png 图 4-8. 项目摘要中的公共 URL 和私有 URL Public Clone URL 是一个公开的,只读的 Git URL,任何人都可以通过它克隆该项目。可以随意散播这个 URL,比如发布到个人网站之类的地方等等。 @@ -822,7 +802,7 @@ Your Clone URL 是一个基于 SSH 协议的可读可写 URL,只有使用与 如果想把某个公共 Subversion 项目导入 Git,GitHub 可以帮忙。在指南的最后有一个指向导入 Subversion 页面的链接。点击它会看到一个表单,包含有关导入流程的信息以及一个用来粘贴公共 Subversion 项目连接的文本框(见图 4-9): -Insert 18333fig0409.png +Insert 18333fig0409.png 图 4-9. Subversion 导入界面 如果项目很大,采用非标准结构,或者是私有的,那就无法借助该工具实现导入。到第 7 章,我们会介绍如何手工导入复杂工程的具体方法。 @@ -833,7 +813,7 @@ Insert 18333fig0409.png 点击项目页面上方的 "edit" 按钮或者顶部的 Admin 标签,进入该项目的管理页面(见图 4-10): -Insert 18333fig0410.png +Insert 18333fig0410.png 图 4-10. GitHub 的项目管理页面 为了给另一个用户添加项目的写权限,点击 "Add another collaborator" 链接,出现一个用于输入用户名的表单。在输入的同时,它会自动跳出一个符合条件的候选名单。找到正确用户名之后,点 Add 按钮,把该用户设为项目协作者(见图 4-11): @@ -843,7 +823,7 @@ Insert 18333fig0411.png 添加完协作者之后,就可以在 Repository Collaborators 区域看到他们的名单(见图 4-12): -Insert 18333fig0412.png +Insert 18333fig0412.png 图 4-12. 项目协作者名单 如果要取消某人的访问权,点击 "revoke" 即可取消他的推送权限。对于将来的项目,你可以从现有项目复制协作者名单,或者直接借用协作者群组。 @@ -852,7 +832,7 @@ Insert 18333fig0412.png 在推送或从 Subversion 导入项目之后,你会看到一个类似图 4-13 的项目主页: -Insert 18333fig0413.png +Insert 18333fig0413.png 图 4-13. GitHub 上的项目主页 别人访问你的项目时看到的就是这个页面。它有若干导航标签,Commits 标签用于显示提交历史,最新的提交位于最上方,这和 `git log` 命令的输出类似。Network 标签展示所有派生了该项目并做出贡献的用户的关系图谱。Downloads 标签允许你上传项目的二进制文件,提供下载该项目各个版本的 tar/zip 包。Wiki 标签提供了一个用于撰写文档或其他项目相关信息的 wiki 站点。Graphs 标签包含了一些可视化的项目信息与数据。默认打开的 Source 标签页面,则列出了该项目的目录结构和概要信息,并在下方自动展示 README 文件的内容(如果该文件存在的话),此外还会显示最近一次提交的相关信息。 @@ -865,12 +845,12 @@ Insert 18333fig0413.png 要派生一个项目,到原始项目的页面(本例中是 mojombo/chronic)点击 "fork" 按钮(见图 4-14): -Insert 18333fig0414.png +Insert 18333fig0414.png 图 4-14. 点击 "fork" 按钮获得任意项目的可写副本 几秒钟之后,你将进入新建的项目页面,会显示该项目派生自哪一个项目(见图 4-15): -Insert 18333fig0415.png +Insert 18333fig0415.png 图 4-15. 派生后得到的项目副本 ### GitHub 小结 ### diff --git a/zh/05-distributed-git/01-chapter5.markdown b/zh/05-distributed-git/01-chapter5.markdown index 2f022503e..772774948 100644 --- a/zh/05-distributed-git/01-chapter5.markdown +++ b/zh/05-distributed-git/01-chapter5.markdown @@ -12,12 +12,13 @@ 通常,集中式工作流程使用的都是单点协作模型。一个存放代码仓库的中心服务器,可以接受所有开发者提交的代码。所有的开发者都是普通的节点,作为中心集线器的消费者,平时的工作就是和中心仓库同步数据(见图 5-1)。 -Insert 18333fig0501.png +Insert 18333fig0501.png 图 5-1. 集中式工作流 如果两个开发者从中心仓库克隆代码下来,同时作了一些修订,那么只有第一个开发者可以顺利地把数据推送到共享服务器。第二个开发者在提交他的修订之前,必须先下载合并服务器上的数据,解决冲突之后才能推送数据到共享服务器上。在 Git 中这么用也决无问题,这就好比是在用 Subversion(或其他 CVCS)一样,可以很好地工作。 -如果你的团队不是很大,或者大家都已经习惯了使用集中式工作流程,完全可以采用这种简单的模式。只需要配置好一台中心服务器,并给每个人推送数据的权限,就可以开展工作了。但如果提交代码时有冲突, Git 根本就不会让用户覆盖他人代码,它直接驳回第二个人的提交操作。这就等于告诉提交者,你所作的修订无法通过快近(fast-forward)来合并,你必须先拉取最新数据下来,手工解决冲突合并后,才能继续推送新的提交。绝大多数人都熟悉和了解这种模式的工作方式,所以使用也非常广泛。 +如果你的团队不是很大,或者大家都已经习惯了使用集中式工作流程,完全可以采用这种简单的模式。只需要配置好一台中心服务器,并给每个人推送数据的权限,就可以开展工作了。但如果提交代码时有冲突, Git 根本就不会让用户覆盖他人代码,它直接驳回第二个人的提交操作。这就等于告诉提交者,你所作的修订无法通过快近(fast-forward)来合并,你必须先拉取最新数据下来,手工解决冲突合并后,才能继续推送新的提交。 +绝大多数人都熟悉和了解这种模式的工作方式,所以使用也非常广泛。 ### 集成管理员工作流 ### @@ -30,7 +31,7 @@ Insert 18333fig0501.png 5. 维护者在自己本地的 integration manger 仓库中,将贡献者的仓库加为远程仓库,合并更新并做测试。 6. 维护者将合并后的更新推送到主仓库 blessed repository。 -Insert 18333fig0502.png +Insert 18333fig0502.png 图 5-2. 集成管理员工作流 在 GitHub 网站上使用得最多的就是这种工作流。人们可以复制(fork 亦即克隆)某个项目到自己的列表中,成为自己的公共仓库。随后将自己的更新提交到这个仓库,所有人都可以看到你的每次更新。这么做最主要的优点在于,你可以按照自己的节奏继续工作,而不必等待维护者处理你提交的更新;而维护者也可以按照自己的节奏,任何时候都可以过来处理接纳你的贡献。 @@ -44,7 +45,7 @@ Insert 18333fig0502.png 3. 司令官(dictator)将所有副官的 master 分支并入自己的 master 分支。 4. 司令官(dictator)将集成后的 master 分支推送到共享仓库 blessed repository 中,以便所有其他开发者以此为基础进行衍合。 -Insert 18333fig0503.png +Insert 18333fig0503.png 图 5-3. 司令官与副官工作流 这种工作流程并不常用,只有当项目极为庞杂,或者需要多级别管理时,才会体现出优势。利用这种方式,项目总负责人(即司令官)可以把大量分散的集成工作委托给不同的小组负责人分别处理,最后再统筹起来,如此各人的职责清晰明确,也不易出错(译注:此乃分而治之)。 @@ -83,7 +84,8 @@ Insert 18333fig0503.png 接下来,请将每次提交限定于完成一次逻辑功能。并且可能的话,适当地分解为多次小更新,以便每次小型提交都更易于理解。请不要在周末穷追猛打一次性解决五个问题,而最后拖到周一再提交。就算是这样也请尽可能利用暂存区域,将之前的改动分解为每次修复一个问题,再分别提交和加注说明。如果针对两个问题改动的是同一个文件,可以试试看 `git add --patch` 的方式将部分内容置入暂存区域(我们会在第六章再详细介绍)。无论是五次小提交还是混杂在一起的大提交,最终分支末端的项目快照应该还是一样的,但分解开来之后,更便于其他开发者复阅。这么做也方便自己将来取消某个特定问题的修复。我们将在第六章介绍一些重写提交历史,同暂存区域交互的技巧和工具,以便最终得到一个干净有意义,且易于理解的提交历史。 -最后需要谨记的是提交说明的撰写。写得好可以让大家协作起来更轻松。一般来说,提交说明最好限制在一行以内,50 个字符以下,简明扼要地描述更新内容,空开一行后,再展开详细注解。Git 项目本身需要开发者撰写详尽注解,包括本次修订的因由,以及前后不同实现之间的比较,我们也该借鉴这种做法。另外,提交说明应该用祈使现在式语态,比如,不要说成 “I added tests for” 或 “Adding tests for” 而应该用 “Add tests for”。下面是来自 tpope.net 的 Tim Pope 原创的提交说明格式模版,供参考: +最后需要谨记的是提交说明的撰写。写得好可以让大家协作起来更轻松。一般来说,提交说明最好限制在一行以内,50 个字符以下,简明扼要地描述更新内容,空开一行后,再展开详细注解。Git 项目本身需要开发者撰写详尽注解,包括本次修订的因由,以及前后不同实现之间的比较,我们也该借鉴这种做法。另外,提交说明应该用祈使现在式语态,比如,不要说成 “I added tests for” 或 “Adding tests for” 而应该用 “Add tests for”。 +下面是来自 tpope.net 的 Tim Pope 原创的提交说明格式模版,供参考: 本次更新的简要描述(50 个字符以内) @@ -91,7 +93,7 @@ Insert 18333fig0503.png 某些情况下,第一行的简要描述将用作邮件标题,其余部分作为邮件正文。 其间的空行是必要的,以区分两者(当然没有正文另当别论)。 如果并在一起,rebase 这样的工具就可能会迷惑。 - + 另起空行后,再进一步补充其他说明。 - 可以使用这样的条目列举式。 @@ -107,14 +109,15 @@ Insert 18333fig0503.png 我们从最简单的情况开始,一个私有项目,与你一起协作的还有另外一到两位开发者。这里说私有,是指源代码不公开,其他人无法访问项目仓库。而你和其他开发者则都具有推送数据到仓库的权限。 -这种情况下,你们可以用 Subversion 或其他集中式版本控制系统类似的工作流来协作。你仍然可以得到 Git 带来的其他好处:离线提交,快速分支与合并等等,但工作流程还是差不多的。主要区别在于,合并操作发生在客户端而非服务器上。让我们来看看,两个开发者一起使用同一个共享仓库,会发生些什么。第一个人,John,克隆了仓库,作了些更新,在本地提交。(下面的例子中省略了常规提示,用 `...` 代替以节约版面。) +这种情况下,你们可以用 Subversion 或其他集中式版本控制系统类似的工作流来协作。你仍然可以得到 Git 带来的其他好处:离线提交,快速分支与合并等等,但工作流程还是差不多的。主要区别在于,合并操作发生在客户端而非服务器上。 +让我们来看看,两个开发者一起使用同一个共享仓库,会发生些什么。第一个人,John,克隆了仓库,作了些更新,在本地提交。(下面的例子中省略了常规提示,用 `...` 代替以节约版面。) # John's Machine $ git clone john@githost:simplegit.git Initialized empty Git repository in /home/john/simplegit/.git/ ... $ cd simplegit/ - $ vim lib/simplegit.rb + $ vim lib/simplegit.rb $ git commit -am 'removed invalid default value' [master 738ee87] removed invalid default value 1 files changed, 1 insertions(+), 1 deletions(-) @@ -126,7 +129,7 @@ Insert 18333fig0503.png Initialized empty Git repository in /home/jessica/simplegit/.git/ ... $ cd simplegit/ - $ vim TODO + $ vim TODO $ git commit -am 'add reset task' [master fbff5bc] add reset task 1 files changed, 1 insertions(+), 0 deletions(-) @@ -156,7 +159,7 @@ John 的推送操作被驳回,因为 Jessica 已经推送了新的数据上去 此刻,John 的本地仓库如图 5-4 所示: -Insert 18333fig0504.png +Insert 18333fig0504.png 图 5-4. John 的仓库历史 虽然 John 下载了 Jessica 推送到服务器的最近更新(fbff5),但目前只是 `origin/master` 指针指向它,而当前的本地分支 `master` 仍然指向自己的更新(738ee),所以需要先把她的提交合并过来,才能继续推送数据: @@ -168,7 +171,7 @@ Insert 18333fig0504.png 还好,合并过程非常顺利,没有冲突,现在 John 的提交历史如图 5-5 所示: -Insert 18333fig0505.png +Insert 18333fig0505.png 图 5-5. 合并 origin/master 后 John 的仓库历史 现在,John 应该再测试一下代码是否仍然正常工作,然后将合并结果(72bbc)推送到服务器上: @@ -180,12 +183,12 @@ Insert 18333fig0505.png 最终,John 的提交历史变为图 5-6 所示: -Insert 18333fig0506.png +Insert 18333fig0506.png 图 5-6. 推送后 John 的仓库历史 而在这段时间,Jessica 已经开始在另一个特性分支工作了。她创建了 `issue54` 并提交了三次更新。她还没有下载 John 提交的合并结果,所以提交历史如图 5-7 所示: -Insert 18333fig0507.png +Insert 18333fig0507.png 图 5-7. Jessica 的提交历史 Jessica 想要先和服务器上的数据同步,所以先下载数据: @@ -198,7 +201,7 @@ Jessica 想要先和服务器上的数据同步,所以先下载数据: 于是 Jessica 的本地仓库历史多出了 John 的两次提交(738ee 和 72bbc),如图 5-8 所示: -Insert 18333fig0508.png +Insert 18333fig0508.png 图 5-8. 获取 John 的更新之后 Jessica 的提交历史 此时,Jessica 在特性分支上的工作已经完成,但她想在推送数据之前,先确认下要并进来的数据究竟是什么,于是运行 `git log` 查看: @@ -235,7 +238,7 @@ Insert 18333fig0508.png 所有的合并都非常干净。现在 Jessica 的提交历史如图 5-9 所示: -Insert 18333fig0509.png +Insert 18333fig0509.png 图 5-9. 合并 John 的更新后 Jessica 的提交历史 现在 Jessica 已经可以在自己的 `master` 分支中访问 `origin/master` 的最新改动了,所以她应该可以成功推送最后的合并结果到服务器上(假设 John 此时没再推送新数据上来): @@ -247,12 +250,12 @@ Insert 18333fig0509.png 至此,每个开发者都提交了若干次,且成功合并了对方的工作成果,最新的提交历史如图 5-10 所示: -Insert 18333fig0510.png +Insert 18333fig0510.png 图 5-10. Jessica 推送数据后的提交历史 以上就是最简单的协作方式之一:先在自己的特性分支中工作一段时间,完成后合并到自己的 `master` 分支;然后下载合并 `origin/master` 上的更新(如果有的话),再推回远程服务器。一般的协作流程如图 5-11 所示: -Insert 18333fig0511.png +Insert 18333fig0511.png 图 5-11. 多用户共享仓库协作方式的一般工作流程时序 ### 私有团队间协作 ### @@ -298,7 +301,7 @@ Jessica 发邮件给 John 让他上来看看 `featureA` 分支上的进展。在 现在 Jessica 的更新历史如图 5-12 所示: -Insert 18333fig0512.png +Insert 18333fig0512.png 图 5-12. Jessica 的更新历史 Jessica 正准备推送自己的进展上去,却收到 Josie 的来信,说是她已经将自己的工作推到服务器上的 `featureBee` 分支了。这样,Jessica 就必须先将 Josie 的代码合并到自己本地分支中,才能再一起推送回服务器。她用 `git fetch` 下载 Josie 的最新代码: @@ -354,26 +357,26 @@ Jessica 正准备推送自己的进展上去,却收到 Josie 的来信,说 Jessica 稍做一番修整后同步到服务器: $ git commit -am 'small tweak' - [featureA ed774b3] small tweak + [featureA 774b3ed] small tweak 1 files changed, 1 insertions(+), 1 deletions(-) $ git push origin featureA ... To jessica@githost:simplegit.git - 3300904..ed774b3 featureA -> featureA + 3300904..774b3ed featureA -> featureA 现在的 Jessica 提交历史如图 5-13 所示: -Insert 18333fig0513.png +Insert 18333fig0513.png 图 5-13. 在特性分支中提交更新后的提交历史 现在,Jessica,Josie 和 John 通知集成管理员服务器上的 `featureA` 及 `featureBee` 分支已经准备好,可以并入主线了。在管理员完成集成工作后,主分支上便多出一个新的合并提交(5399e),用 fetch 命令更新到本地后,提交历史如图 5-14 所示: -Insert 18333fig0514.png +Insert 18333fig0514.png 图 5-14. 合并特性分支后的 Jessica 提交历史 许多开发小组改用 Git 就是因为它允许多个小组间并行工作,而在稍后恰当时机再行合并。通过共享远程分支的方式,无需干扰整体项目代码便可以开展工作,因此使用 Git 的小型团队间协作可以变得非常灵活自由。以上工作流程的时序如图 5-15 所示: -Insert 18333fig0515.png +Insert 18333fig0515.png 图 5-15. 团队间协作工作流程基本时序 ### 公开的小型项目 ### @@ -433,7 +436,7 @@ Insert 18333fig0515.png 现在,A、B 两个特性分支各不相扰,如同竹筒里的两颗豆子,队列中的两个补丁,你随时都可以分别从头写过,或者衍合,或者修改,而不用担心特性代码的交叉混杂。如图 5-16 所示: -Insert 18333fig0516.png +Insert 18333fig0516.png 图 5-16. featureB 以后的提交历史 假设项目管理员接纳了许多别人提交的补丁后,准备要采纳你提交的第一个分支,却发现因为代码基准不一致,合并工作无法正确干净地完成。这就需要你再次衍合到最新的 `origin/master`,解决相关冲突,然后重新提交你的修改: @@ -444,7 +447,7 @@ Insert 18333fig0516.png 自然,这会重写提交历史,如图 5-17 所示: -Insert 18333fig0517.png +Insert 18333fig0517.png 图 5-17. featureA 重新衍合后的提交历史 注意,此时推送分支必须使用 `-f` 选项(译注:表示 force,不作检查强制重写)替换远程已有的 `featureA` 分支,因为新的 commit 并非原来的后续更新。当然你也可以直接推送到另一个新的分支上去,比如称作 `featureAv2`。 @@ -461,7 +464,7 @@ Insert 18333fig0517.png 好了,现在可以请管理员抓取 `featureBv2` 上的最新代码了,如图 5-18 所示: -Insert 18333fig0518.png +Insert 18333fig0518.png 图 5-18. featureBv2 之后的提交历史 ### 公开的大型项目 ### @@ -484,7 +487,7 @@ Insert 18333fig0518.png `format-patch` 命令依次创建补丁文件,并输出文件名。上面的 `-M` 选项允许 Git 检查是否有对文件重命名的提交。我们来看看补丁文件的内容: - $ cat 0001-add-limit-to-log-function.patch + $ cat 0001-add-limit-to-log-function.patch From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001 From: Jessica Smith Date: Sun, 6 Apr 2008 10:17:23 -0700 @@ -509,7 +512,7 @@ Insert 18333fig0518.png end def ls_tree(treeish = 'master') - -- + -- 1.6.2.rc1.20.g8c5b.dirty 如果有额外信息需要补充,但又不想放在提交消息中说明,可以编辑这些补丁文件,在第一个 `---` 行之前添加说明,但不要修改下面的补丁正文,比如例子中的 `Limit log functionality to the first 20` 部分。这样,其它开发者能阅读,但在采纳补丁时不会将此合并进来。 @@ -526,19 +529,39 @@ Insert 18333fig0518.png port = 993 sslverify = false -如果你的 IMAP 服务器没有启用 SSL,就无需配置最后那两行,并且 host 应该以 `imap://` 开头而不再是有 `s` 的 `imaps://`。保存配置文件后,就能用 `git send-email` 命令把补丁作为邮件依次发送到指定的 IMAP 服务器上的文件夹中(译注:这里就是 Gmail 的 `[Gmail]/Drafts` 文件夹。但如果你的语言设置不是英文,此处的文件夹 Drafts 字样会变为对应的语言。): +如果你的 IMAP 服务器没有启用 SSL,就无需配置最后那两行,并且 host 应该以 `imap://` 开头而不再是有 `s` 的 `imaps://`。 +保存配置文件后,就能用 `git send-email` 命令把补丁作为邮件依次发送到指定的 IMAP 服务器上的文件夹中(译注:这里就是 Gmail 的 `[Gmail]/Drafts` 文件夹。但如果你的语言设置不是英文,此处的文件夹 Drafts 字样会变为对应的语言。): + + $ cat *.patch |git imap-send + Resolving imap.gmail.com... ok + Connecting to [74.125.142.109]:993... ok + Logging in... + sending 2 messages + 100% (2/2) done + +At this point, you should be able to go to your Drafts folder, change the To field to the mailing list you’re sending the patch to, possibly CC the maintainer or person responsible for that section, and send it off. + +You can also send the patches through an SMTP server. As before, you can set each value separately with a series of `git config` commands, or you can add them manually in the sendemail section in your `~/.gitconfig` file: + + [sendemail] + smtpencryption = tls + smtpserver = smtp.gmail.com + smtpuser = user@gmail.com + smtpserverport = 587 + +After this is done, you can use `git send-email` to send your patches: $ git send-email *.patch 0001-added-limit-to-log-function.patch 0002-changed-log-output-to-30-from-25.patch - Who should the emails appear to be from? [Jessica Smith ] + Who should the emails appear to be from? [Jessica Smith ] Emails will be sent from: Jessica Smith Who should the emails be sent to? jessica@example.com Message-ID to be used as In-Reply-To for the first email? y 接下来,Git 会根据每个补丁依次输出类似下面的日志: - (mbox) Adding cc: Jessica Smith from + (mbox) Adding cc: Jessica Smith from \line 'From: Jessica Smith ' OK. Log says: Sendmail: /usr/sbin/sendmail -i jessica@example.com @@ -553,8 +576,6 @@ Insert 18333fig0518.png Result: OK -最后,到 Gmail 上打开 Drafts 文件夹,编辑这些邮件,修改收件人地址为邮件列表地址,另外给要抄送的人也加到 Cc 列表中,最后发送。 - ### 小结 ### 本节主要介绍了常见 Git 项目协作的工作流程,还有一些帮助处理这些工作的命令和工具。接下来我们要看看如何维护 Git 项目,并成为一个合格的项目管理员,或是集成经理。 @@ -565,13 +586,14 @@ Insert 18333fig0518.png ### 使用特性分支进行工作 ### -如果想要集成新的代码进来,最好局限在特性分支上做。临时的特性分支可以让你随意尝试,进退自如。比如碰上无法正常工作的补丁,可以先搁在那边,直到有时间仔细核查修复为止。创建的分支可以用相关的主题关键字命名,比如 `ruby_client` 或者其它类似的描述性词语,以帮助将来回忆。Git 项目本身还时常把分支名称分置于不同命名空间下,比如 `sc/ruby_client` 就说明这是 `sc` 这个人贡献的。现在从当前主干分支为基础,新建临时分支: +如果想要集成新的代码进来,最好局限在特性分支上做。临时的特性分支可以让你随意尝试,进退自如。比如碰上无法正常工作的补丁,可以先搁在那边,直到有时间仔细核查修复为止。创建的分支可以用相关的主题关键字命名,比如 `ruby_client` 或者其它类似的描述性词语,以帮助将来回忆。Git 项目本身还时常把分支名称分置于不同命名空间下,比如 `sc/ruby_client` 就说明这是 `sc` 这个人贡献的。 +现在从当前主干分支为基础,新建临时分支: - $ git branch sc/ruby_client master + $ git branch sc/ruby_client master 另外,如果你希望立即转到分支上去工作,可以用 `checkout -b`: - $ git checkout -b sc/ruby_client master + $ git checkout -b sc/ruby_client master 好了,现在已经准备妥当,可以试着将别人贡献的代码合并进来了。之后评估一下有没有问题,最后再决定是不是真的要并入主干。 @@ -589,7 +611,7 @@ Insert 18333fig0518.png 在实际打补丁之前,可以先用 `git apply --check` 查看补丁是否能够干净顺利地应用到当前分支中: - $ git apply --check 0001-seeing-if-this-helps-the-gem.patch + $ git apply --check 0001-seeing-if-this-helps-the-gem.patch error: patch failed: ticgit.gemspec:1 error: ticgit.gemspec: patch does not apply @@ -612,7 +634,7 @@ Insert 18333fig0518.png 如果贡献者将 `format-patch` 生成的补丁文件上传到类似 Request Ticket 一样的任务处理系统,那么可以先下载到本地,继而使用 `git am` 应用该补丁: - $ git am 0001-limit-log-function.patch + $ git am 0001-limit-log-function.patch Applying: add limit to log function 你会看到它被干净地应用到本地分支,并自动创建了新的提交对象。作者信息取自邮件头 `From` 和 `Date`,提交消息则取自 `Subject` 以及正文中补丁之前的内容。来看具体实例,采纳之前展示的那个 mbox 电邮补丁后,最新的提交对象为: @@ -632,7 +654,7 @@ Insert 18333fig0518.png 有时,我们也会遇到打不上补丁的情况。这多半是因为主干分支和补丁的基础分支相差太远,但也可能是因为某些依赖补丁还未应用。这种情况下,`git am` 会报错并询问该怎么做: - $ git am 0001-seeing-if-this-helps-the-gem.patch + $ git am 0001-seeing-if-this-helps-the-gem.patch Applying: seeing if this helps the gem error: patch failed: ticgit.gemspec:1 error: ticgit.gemspec: patch does not apply @@ -644,13 +666,13 @@ Insert 18333fig0518.png Git 会在有冲突的文件里加入冲突解决标记,这同合并或衍合操作一样。解决的办法也一样,先编辑文件消除冲突,然后暂存文件,最后运行 `git am --resolved` 提交修正结果: $ (fix the file) - $ git add ticgit.gemspec + $ git add ticgit.gemspec $ git am --resolved Applying: seeing if this helps the gem 如果想让 Git 更智能地处理冲突,可以用 `-3` 选项进行三方合并。如果当前分支未包含该补丁的基础代码或其祖先,那么三方合并就会失败,所以该选项默认为关闭状态。一般来说,如果该补丁是基于某个公开的提交制作而成的话,你总是可以通过同步来获取这个共同祖先,所以用三方合并选项可以解决很多麻烦: - $ git am -3 0001-seeing-if-this-helps-the-gem.patch + $ git am -3 0001-seeing-if-this-helps-the-gem.patch Applying: seeing if this helps the gem error: patch failed: ticgit.gemspec:1 error: ticgit.gemspec: patch does not apply @@ -667,7 +689,7 @@ Git 会在有冲突的文件里加入冲突解决标记,这同合并或衍合 -------------------------- seeing if this helps the gem -------------------------- - Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all + Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all 在多个补丁要打的情况下,这是个非常好的办法,一方面可以预览下补丁内容,同时也可以有选择性的接纳或跳过某些补丁。 @@ -731,7 +753,7 @@ Git 会在有冲突的文件里加入冲突解决标记,这同合并或衍合 $ git merge-base contrib master 36c7dba2c95e6bbb78dfa822519ecfec6e1ca649 - $ git diff 36c7db + $ git diff 36c7db 但这么做很麻烦,所以 Git 提供了便捷的 `...` 语法。对于 `diff` 命令,可以把 `...` 加在原始分支(拥有共同祖先)和当前分支之间: @@ -747,7 +769,7 @@ Git 会在有冲突的文件里加入冲突解决标记,这同合并或衍合 一般最简单的情形,是在 `master` 分支中维护稳定代码,然后在特性分支上开发新功能,或是审核测试别人贡献的代码,接着将它并入主干,最后删除这个特性分支,如此反复。来看示例,假设当前代码库中有两个分支,分别为 `ruby_client` 和 `php_client`,如图 5-19 所示。然后先把 `ruby_client` 合并进主干,再合并 `php_client`,最后的提交历史如图 5-20 所示。 -Insert 18333fig0519.png +Insert 18333fig0519.png 图 5-19. 多个特性分支 Insert 18333fig0520.png @@ -757,27 +779,28 @@ Insert 18333fig0520.png 对于大型项目,至少需要维护两个长期分支 `master` 和 `develop`。新代码(图 5-21 中的 `ruby_client`)将首先并入 `develop` 分支(图 5-22 中的 `C8`),经过一个阶段,确认 `develop` 中的代码已稳定到可发行时,再将 `master` 分支快进到稳定点(图 5-23 中的 `C8`)。而平时这两个分支都会被推送到公开的代码库。 -Insert 18333fig0521.png +Insert 18333fig0521.png 图 5-21. 特性分支合并前 -Insert 18333fig0522.png +Insert 18333fig0522.png 图 5-22. 特性分支合并后 -Insert 18333fig0523.png +Insert 18333fig0523.png 图 5-23. 特性分支发布后 -这样,在人们克隆仓库时就有两种选择:既可检出最新稳定版本,确保正常使用;也能检出开发版本,试用最前沿的新特性。你也可以扩展这个概念,先将所有新代码合并到临时特性分支,等到该分支稳定下来并通过测试后,再并入 `develop` 分支。然后,让时间检验一切,如果这些代码确实可以正常工作相当长一段时间,那就有理由相信它已经足够稳定,可以放心并入主干分支发布。 +这样,在人们克隆仓库时就有两种选择:既可检出最新稳定版本,确保正常使用;也能检出开发版本,试用最前沿的新特性。 +你也可以扩展这个概念,先将所有新代码合并到临时特性分支,等到该分支稳定下来并通过测试后,再并入 `develop` 分支。然后,让时间检验一切,如果这些代码确实可以正常工作相当长一段时间,那就有理由相信它已经足够稳定,可以放心并入主干分支发布。 #### 大项目的合并流程 #### Git 项目本身有四个长期分支:用于发布的 `master` 分支、用于合并基本稳定特性的 `next` 分支、用于合并仍需改进特性的 `pu` 分支(pu 是 proposed updates 的缩写),以及用于除错维护的 `maint` 分支(maint 取自 maintenance)。维护者可以按照之前介绍的方法,将贡献者的代码引入为不同的特性分支(如图 5-24 所示),然后测试评估,看哪些特性能稳定工作,哪些还需改进。稳定的特性可以并入 `next` 分支,然后再推送到公共仓库,以供其他人试用。 -Insert 18333fig0524.png +Insert 18333fig0524.png 图 5-24. 管理复杂的并行贡献 仍需改进的特性可以先并入 `pu` 分支。直到它们完全稳定后再并入 `master`。同时一并检查下 `next` 分支,将足够稳定的特性也并入 `master`。所以一般来说,`master` 始终是在快进,`next` 偶尔做下衍合,而 `pu` 则是频繁衍合,如图 5-25 所示: -Insert 18333fig0525.png +Insert 18333fig0525.png 图 5-25. 将特性并入长期分支 并入 `master` 后的特性分支,已经无需保留分支索引,放心删除好了。Git 项目还有一个 `maint` 分支,它是以最近一次发行版为基础分化而来的,用于维护除错补丁。所以克隆 Git 项目仓库后会得到这四个分支,通过检出不同分支可以了解各自进展,或是试用前沿特性,或是贡献代码。而维护者则通过管理这些分支,逐步有序地并入第三方贡献。 @@ -788,7 +811,7 @@ Insert 18333fig0525.png 另一个引入代码的方法是挑拣。挑拣类似于针对某次特定提交的衍合。它首先提取某次提交的补丁,然后试着应用在当前分支上。如果某个特性分支上有多个commits,但你只想引入其中之一就可以使用这种方法。也可能仅仅是因为你喜欢用挑拣,讨厌衍合。假设你有一个类似图 5-26 的工程。 -Insert 18333fig0526.png +Insert 18333fig0526.png 图 5-26. 挑拣(cherry-pick)之前的历史 如果你希望拉取`e43a6`到你的主干分支,可以这样: @@ -800,7 +823,7 @@ Insert 18333fig0526.png 这将会引入`e43a6`的代码,但是会得到不同的SHA-1值,因为应用日期不同。现在你的历史看起来像图 5-27. -Insert 18333fig0527.png +Insert 18333fig0527.png 图 5-27. 挑拣(cherry-pick)之后的历史 现在,你可以删除这个特性分支并丢弃你不想引入的那些commit。 diff --git a/zh/06-git-tools/01-chapter6.markdown b/zh/06-git-tools/01-chapter6.markdown index a3bc97a41..078a4ac05 100644 --- a/zh/06-git-tools/01-chapter6.markdown +++ b/zh/06-git-tools/01-chapter6.markdown @@ -53,8 +53,6 @@ Git 可以为你的 SHA-1 值生成出简短且唯一的缩写。如果你传递 通常在一个项目中,使用八到十个字符来避免 SHA-1 歧义已经足够了。最大的 Git 项目之一,Linux 内核,目前也只需要最长 40 个字符中的 12 个字符来保持唯一性。 - - ### 关于 SHA-1 的简短说明 ### 许多人可能会担心一个问题:在随机的偶然情况下,在他们的仓库里会出现两个具有相同 SHA-1 值的对象。那会怎么样呢? @@ -65,7 +63,6 @@ Git 可以为你的 SHA-1 值生成出简短且唯一的缩写。如果你传递 现在举例说一下怎样才能产生一次 SHA-1 冲突。如果地球上 65 亿的人类都在编程,每人每秒都在产生等价于整个 Linux 内核历史(一百万个 Git 对象)的代码,并将之提交到一个巨大的 Git 仓库里面,那将花费 5 年的时间才会产生足够的对象,使其拥有 50% 的概率产生一次 SHA-1 对象冲突。这要比你编程团队的成员同一个晚上在互不相干的意外中被狼袭击并杀死的机率还要小。 - ### 分支引用 ### 指明一次提交的最直接的方法要求有一个指向它的分支引用。这样,你就可以在任何需要一个提交对象或者 SHA-1 值的 Git 命令中使用该分支名称了。如果你想要显示一个分支的最后一次提交的对象,例如假设 `topic1` 分支指向 `ca82a6d`,那么下面的命令是等价的: @@ -108,7 +105,7 @@ Git 可以为你的 SHA-1 值生成出简短且唯一的缩写。如果你传递 $ git log -g master commit 734713bc047d87bf7eac9674765ae793478c50d3 Reflog: master@{0} (Scott Chacon ) - Reflog message: commit: fixed refs handling, added gc auto, updated + Reflog message: commit: fixed refs handling, added gc auto, updated Author: Scott Chacon Date: Fri Jan 2 18:32:33 2009 -0800 @@ -132,10 +129,10 @@ Git 可以为你的 SHA-1 值生成出简短且唯一的缩写。如果你传递 $ git log --pretty=format:'%h %s' --graph * 734713b fixed refs handling, added gc auto, updated tests * d921970 Merge commit 'phedders/rdocs' - |\ + |\ | * 35cfb2b Some rdoc changes * | 1c002dd added some blame and merge stuff - |/ + |/ * 1c36188 ignore *.gem * 9b29157 add open3_detach to gemspec file list @@ -193,7 +190,7 @@ Git 可以为你的 SHA-1 值生成出简短且唯一的缩写。如果你传递 最常用的指明范围的方法是双点的语法。这种语法主要是让 Git 区分出可从一个分支中获得而不能从另一个分支中获得的提交。例如,假设你有类似于图 6-1 的提交历史。 -Insert 18333fig0601.png +Insert 18333fig0601.png 图 6-1. 范围选择的提交历史实例 你想要查看你的试验分支上哪些没有被提交到主分支,那么你就可以使用 `master..experiment` 来让 Git 显示这些提交的日志——这句话的意思是“所有可从experiment分支中获得而不能从master分支中获得的提交”。为了使例子简单明了,我使用了图标中提交对象的字母来代替真实日志的输出,所以会显示: @@ -253,7 +250,6 @@ Insert 18333fig0601.png 有了以上工具,让Git知道你要察看哪些提交就容易得多了。 - ## 交互式暂存 ## Git提供了很多脚本来辅助某些命令行任务。这里,你将看到一些交互式命令,它们帮助你方便地构建只包含特定组合和部分文件的提交。在你修改了一大批文件然后决定将这些变更分布在几个各有侧重的提交而不是单个又大又乱的提交时,这些工具非常有用。用这种方法,你可以确保你的提交在逻辑上划分为相应的变更集,以便于供和你一起工作的开发者审阅。如果你运行`git add`时加上`-i`或者`--interactive`选项,Git就进入了一个交互式的shell模式,显示一些类似于下面的信息: @@ -267,7 +263,7 @@ Git提供了很多脚本来辅助某些命令行任务。这里,你将看到 *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help - What now> + What now> 你会看到这个命令以一个完全不同的视图显示了你的暂存区——主要是你通过`git status`得到的那些信息但是稍微简洁但信息更加丰富一些。它在左侧列出了你暂存的变更,在右侧列出了未被暂存的变更。 @@ -295,7 +291,7 @@ Git提供了很多脚本来辅助某些命令行任务。这里,你将看到 每个文件旁边的`*`表示选中的文件将被暂存。如果你在`update>>`提示后直接敲入回车,Git会替你把所有选中的内容暂存: - Update>> + Update>> updated 2 paths *** Commands *** @@ -377,7 +373,7 @@ Git提供了很多脚本来辅助某些命令行任务。这里,你将看到 end def blame(path) - Stage this hunk [y,n,a,d,/,j,J,g,e,?]? + Stage this hunk [y,n,a,d,/,j,J,g,e,?]? 此处你有很多选择。输入`?`可以显示列表: @@ -508,7 +504,6 @@ apply 选项只尝试应用储藏的工作——储藏的内容仍然在栈上 $ #... work work work $ git stash-unapply - ### 从储藏中创建分支 ### 如果你储藏了一些工作,暂时不去理会,然后继续在你储藏工作的分支上工作,你在重新应用工作时可能会碰到一些问题。如果尝试应用的变更是针对一个你那之后修改过的文件,你会碰到一个归并冲突并且必须去化解它。如果你想用更方便的方法来重新检验你储藏的变更,你可以运行 `git stash branch`,这会创建一个新的分支,检出你储藏工作时的所处的提交,重新应用你的工作,如果成功,将会丢弃储藏。 @@ -540,7 +535,6 @@ apply 选项只尝试应用储藏的工作——储藏的内容仍然在栈上 改变最近一次提交也许是最常见的重写历史的行为。对于你的最近一次提交,你经常想做两件基本事情:改变提交说明,或者改变你刚刚通过增加,改变,删除而记录的快照。 - 如果你只想修改最近一次提交说明,这非常简单: $ git commit --amend @@ -561,7 +555,6 @@ apply 选项只尝试应用储藏的工作——储藏的内容仍然在栈上 再次提醒这是一个衍合命令——`HEAD~3..HEAD`范围内的每一次提交都会被重写,无论你是否修改说明。不要涵盖你已经推送到中心服务器的提交——这么做会使其他开发者产生混乱,因为你提供了同样变更的不同版本。 - 运行这个命令会为你的文本编辑器提供一个提交列表,看起来像下面这样 pick f7f3f6d changed my name a bit @@ -702,7 +695,6 @@ Git在脚本中应用了最后一次提交(`a5f4a0d`),你的历史看起 这个经常发生。有些人不经思考使用`git add .`,意外地提交了一个巨大的二进制文件,你想将它从所有地方删除。也许你不小心提交了一个包含密码的文件,而你想让你的项目开源。`filter-branch`大概会是你用来清理整个历史的工具。要从整个历史中删除一个名叫password.txt的文件,你可以在`filter-branch`上使用`--tree-filter`选项: - $ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD Rewrite 6b9b3cf04e7c5686a9cb838c3f36a8cb6a0fc2bd (21/21) Ref 'refs/heads/master' was rewritten @@ -725,7 +717,6 @@ Git在脚本中应用了最后一次提交(`a5f4a0d`),你的历史看起 另一个常见的案例是你在开始时忘了运行`git config`来设置你的姓名和电子邮件地址,也许你想开源一个项目,把你所有的工作电子邮件地址修改为个人地址。无论哪种情况你都可以用`filter-branch`来更换多次提交里的电子邮件地址。你必须小心一些,只改变属于你的电子邮件地址,所以你使用`--commit-filter`: - $ git filter-branch --commit-filter ' if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ]; then @@ -746,7 +737,7 @@ Git 同样提供了一些工具来帮助你调试项目中遇到的问题。由 如果你在追踪代码中的缺陷想知道这是什么时候为什么被引进来的,文件标注会是你的最佳工具。它会显示文件中对每一行进行修改的最近一次提交。因此,如果你发现自己代码中的一个方法存在缺陷,你可以用`git blame`来标注文件,查看那个方法的每一行分别是由谁在哪一天修改的。下面这个例子使用了`-L`选项来限制输出范围在第12至22行: - $ git blame -L 12,22 simplegit.rb + $ git blame -L 12,22 simplegit.rb ^4832fe2 (Scott Chacon 2008-03-15 10:31:28 -0700 12) def show(tree = 'master') ^4832fe2 (Scott Chacon 2008-03-15 10:31:28 -0700 13) command("git show #{tree}") ^4832fe2 (Scott Chacon 2008-03-15 10:31:28 -0700 14) end @@ -754,7 +745,7 @@ Git 同样提供了一些工具来帮助你调试项目中遇到的问题。由 9f6560e4 (Scott Chacon 2008-03-17 21:52:20 -0700 16) def log(tree = 'master') 79eaf55d (Scott Chacon 2008-04-06 10:15:08 -0700 17) command("git log #{tree}") 9f6560e4 (Scott Chacon 2008-03-17 21:52:20 -0700 18) end - 9f6560e4 (Scott Chacon 2008-03-17 21:52:20 -0700 19) + 9f6560e4 (Scott Chacon 2008-03-17 21:52:20 -0700 19) 42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 20) def blame(path) 42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 21) command("git blame #{path}") 42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 22) end @@ -763,8 +754,8 @@ Git 同样提供了一些工具来帮助你调试项目中遇到的问题。由 另一件很酷的事情是在 Git 中你不需要显式地记录文件的重命名。它会记录快照然后根据现实尝试找出隐式的重命名动作。这其中有一个很有意思的特性就是你可以让它找出所有的代码移动。如果你在`git blame`后加上`-C`,Git会分析你在标注的文件然后尝试找出其中代码片段的原始出处,如果它是从其他地方拷贝过来的话。最近,我在将一个名叫`GITServerHandler.m`的文件分解到多个文件中,其中一个是`GITPackUpload.m`。通过对`GITPackUpload.m`执行带`-C`参数的blame命令,我可以看到代码块的原始出处: - $ git blame -C -L 141,153 GITPackUpload.m - f344f58d GITServerHandler.m (Scott 2009-01-04 141) + $ git blame -C -L 141,153 GITPackUpload.m + f344f58d GITServerHandler.m (Scott 2009-01-04 141) f344f58d GITServerHandler.m (Scott 2009-01-04 142) - (void) gatherObjectShasFromC f344f58d GITServerHandler.m (Scott 2009-01-04 143) { 70befddd GITServerHandler.m (Scott 2009-03-22 144) //NSLog(@"GATHER COMMI @@ -832,7 +823,6 @@ Git 发现在你标记为正常的提交(v1.0)和当前的错误版本之间有 经常有这样的事情,当你在一个项目上工作时,你需要在其中使用另外一个项目。也许它是一个第三方开发的库或者是你独立开发和并在多个父项目中使用的。这个场景下一个常见的问题产生了:你想将两个项目单独处理但是又需要在其中一个中使用另外一个。 - 这里有一个例子。假设你在开发一个网站,为之创建Atom源。你不想编写一个自己的Atom生成代码,而是决定使用一个库。你可能不得不像CPAN install或者Ruby gem一样包含来自共享库的代码,或者将代码拷贝到你的项目树中。如果采用包含库的办法,那么不管用什么办法都很难去定制这个库,部署它就更加困难了,因为你必须确保每个客户都拥有那个库。把代码包含到你自己的项目中带来的问题是,当上游被修改时,任何你进行的定制化的修改都很难归并。 Git 通过子模块处理这个问题。子模块允许你将一个 Git 仓库当作另外一个Git仓库的子目录。这允许你克隆另外一个仓库到你的项目中并且保持你的提交相对独立。 @@ -862,7 +852,7 @@ Git 通过子模块处理这个问题。子模块允许你将一个 Git 仓库 首先你注意到有一个`.gitmodules`文件。这是一个配置文件,保存了项目 URL 和你拉取到的本地子目录 - $ cat .gitmodules + $ cat .gitmodules [submodule "rack"] path = rack url = git://github.com/chneukirchen/rack.git @@ -1000,7 +990,6 @@ Git 通过子模块处理这个问题。子模块允许你将一个 Git 仓库 ### 上层项目 ### - 有时候,开发者想按照他们的分组获取一个大项目的子目录的子集。如果你是从 CVS 或者 Subversion 迁移过来的话这个很常见,在那些系统中你已经定义了一个模块或者子目录的集合,而你想延续这种类型的工作流程。 在 Git 中实现这个的一个好办法是你将每一个子目录都做成独立的 Git 仓库,然后创建一个上层项目的 Git 仓库包含多个子模块。这个办法的一个优势是你可以在上层项目中通过标签和分支更为明确地定义项目之间的关系。 @@ -1038,7 +1027,6 @@ Git 通过子模块处理这个问题。子模块允许你将一个 Git 仓库 最后一个需要引起注意的是关于从子目录切换到子模块的。如果你已经跟踪了你项目中的一些文件但是想把它们移到子模块去,你必须非常小心,否则Git会生你的气。假设你的项目中有一个子目录里放了 rack 的文件,然后你想将它转换为子模块。如果你删除子目录然后运行`submodule add`,Git会向你大吼: - $ rm -Rf rack/ $ git submodule add git@github.com:schacon/rack.git rack 'rack' already exists in the index @@ -1077,7 +1065,6 @@ Git 通过子模块处理这个问题。子模块允许你将一个 Git 仓库 子树归并的思想是你拥有两个工程,其中一个项目映射到另外一个项目的子目录中,反过来也一样。当你指定一个子树归并,Git可以聪明地探知其中一个是另外一个的子树从而实现正确的归并——这相当神奇。 - 首先你将 Rack 应用加入到项目中。你将 Rack 项目当作你项目中的一个远程引用,然后将它检出到它自身的分支: $ git remote add rack_remote git@github.com:schacon/rack.git @@ -1109,7 +1096,6 @@ Git 通过子模块处理这个问题。子模块允许你将一个 Git 仓库 要将 Rack 项目当作子目录拉取到你的`master`项目中。你可以在 Git 中用`git read-tree`来实现。你会在第9章学到更多与`read-tree`和它的朋友相关的东西,当前你会知道它读取一个分支的根目录树到当前的暂存区和工作目录。你只要切换回你的`master`分支,然后拉取`rack_branch`到你主项目的`master`分支的`rack`子目录: - $ git read-tree --prefix=rack/ -u rack_branch 当你提交的时候,看起来就像你在那个子目录下拥有Rack的文件——就像你从一个tarball里拷贝的一样。有意思的是你可以比较容易地归并其中一个分支的变更到另外一个。因此,如果 Rack 项目更新了,你可以通过切换到那个分支并执行拉取来获得上游的变更: diff --git a/zh/07-customizing-git/01-chapter7.markdown b/zh/07-customizing-git/01-chapter7.markdown index 092312c18..e2d361fed 100644 --- a/zh/07-customizing-git/01-chapter7.markdown +++ b/zh/07-customizing-git/01-chapter7.markdown @@ -156,13 +156,13 @@ diff包装脚本首先确定传递过来7个参数,随后把其中2个传递 由于你仅仅需要`old-file`和`new-file`参数,用diff包装脚本来传递它们吧。 - $ cat /usr/local/bin/extDiff + $ cat /usr/local/bin/extDiff #!/bin/sh [ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5" 确认这两个脚本是可执行的: - $ sudo chmod +x /usr/local/bin/extMerge + $ sudo chmod +x /usr/local/bin/extMerge $ sudo chmod +x /usr/local/bin/extDiff 现在来配置使用你自定义的比较和合并工具吧。这需要许多自定义设置:`merge.tool`通知 Git 使用哪个合并工具;`mergetool.*.cmd`规定命令运行的方式;`mergetool.trustExitCode`会通知 Git 程序的退出是否指示合并操作成功;`diff.external`通知 Git 用什么命令做比较。因此,你能运行以下4条配置命令: @@ -184,12 +184,12 @@ diff包装脚本首先确定传递过来7个参数,随后把其中2个传递 external = extDiff 设置完毕后,运行diff命令: - + $ git diff 32d1776b1^ 32d1776b1 命令行居然没有发现diff命令的输出,其实,Git 调用了刚刚设置的P4Merge,它看起来像图7-1这样: -Insert 18333fig0701.png +Insert 18333fig0701.png Figure 7-1. P4Merge. 当你设法合并两个分支,结果却有冲突时,运行`git mergetool`,Git 会调用P4Merge让你通过图形界面来解决冲突。 @@ -197,7 +197,7 @@ Figure 7-1. P4Merge. 设置包装脚本的好处是你能简单地改变diff和merge工具,例如把`extDiff`和`extMerge`改成KDiff3,要做的仅仅是编辑`extMerge`脚本文件: $ cat /usr/local/bin/extMerge - #!/bin/sh + #!/bin/sh /Applications/kdiff3.app/Contents/MacOS/kdiff3 $* 现在 Git 会使用KDiff3来做比较、合并和解决冲突。 @@ -271,7 +271,7 @@ Git默认情况下不会在推送期间检查所有对象的一致性。虽然 要禁用这样的强制更新功能,可以设置`receive.denyNonFastForwards`: - $ git config --system receive.denyNonFastForwards true + $ git config --system receive.denyNonFastForwards true 稍后你会看到,用服务器端的接收钩子也能达到同样的目的。这个方法可以做更细致的控制,例如:禁用特定的用户做强制更新。 @@ -279,7 +279,7 @@ Git默认情况下不会在推送期间检查所有对象的一致性。虽然 规避`denyNonFastForwards`策略的方法之一就是用户删除分支,然后推回新的引用。在更新的 Git 版本中(从1.6.1版本开始),把`receive.denyDeletes`设置为true: - $ git config --system receive.denyDeletes true + $ git config --system receive.denyDeletes true 这样会在推送过程中阻止删除分支和标签 — 没有用户能够这么做。要删除远程分支,必须从服务器手动删除引用文件。通过用户访问控制列表也能这么做,在本章结尾将会介绍这些有趣的方式。 @@ -299,75 +299,137 @@ Git默认情况下不会在推送期间检查所有对象的一致性。虽然 让 Git 把所有`pbxproj`文件当成二进制文件,在`.gitattributes`文件中设置如下: - *.pbxproj -crlf -diff + *.pbxproj -crlf -diff 现在,Git 会尝试转换和修正CRLF(回车换行)问题,也不会当你在项目中运行git show或git diff时,比较不同的内容。在Git 1.6及之后的版本中,可以用一个宏代替`-crlf -diff`: - *.pbxproj binary + *.pbxproj binary #### 比较二进制文件 #### -在Git 1.6及以上版本中,你能利用 Git 属性来有效地比较二进制文件。可以设置 Git 把二进制数据转换成文本格式,用通常的diff来比较。 +在 Git 中,你能利用 Git 属性来有效地比较二进制文件。可以设置 Git 把二进制数据转换成文本格式,用通常的diff来比较。 + +We'll make use of the both described approaches to get usable diffs for some widely used binary formats. + +Side note: There are different kinds of binary formats with a text content, which are hard to find usable converter for. In such a case you could try to extract a text from your file with the `strings` program. Some of these files may use an UTF-16 encoding or other "codepages" and `strings` won’t find anything useful in there. Your mileage may vary. However, `strings` is available on most Mac and Linux systems, so it may be a good first try to do this with many binary formats. + +##### MS Word files ##### 这个特性很酷,而且鲜为人知,因此我会结合实例来讲解。首先,要解决的是最令人头疼的问题:对Word文档进行版本控制。很多人对Word文档又恨又爱,如果想对其进行版本控制,你可以把文件加入到 Git 库中,每次修改后提交即可。但这样做没有一点实际意义,因为运行`git diff`命令后,你只能得到如下的结果: - $ git diff - diff --git a/chapter1.doc b/chapter1.doc - index 88839c4..4afcb7c 100644 - Binary files a/chapter1.doc and b/chapter1.doc differ + $ git diff + diff --git a/chapter1.doc b/chapter1.doc + index 88839c4..4afcb7c 100644 + Binary files a/chapter1.doc and b/chapter1.doc differ 你不能直接比较两个不同版本的Word文件,除非进行手动扫描,不是吗? Git 属性能很好地解决此问题,把下面的行加到`.gitattributes`文件: - *.doc diff=word + *.doc diff=word 当你要看比较结果时,如果文件扩展名是"doc",Git 调用"word"过滤器。什么是"word"过滤器呢?其实就是 Git 使用`strings` 程序,把Word文档转换成可读的文本文件,之后再进行比较: - $ git config diff.word.textconv strings + $ git config diff.word.textconv catdoc + +This command adds a section to your `.git/config` that looks like this: + + [diff "word"] + textconv = catdoc 现在如果在两个快照之间比较以`.doc`结尾的文件,Git 对这些文件运用"word"过滤器,在比较前把Word文件转换成文本文件。 下面展示了一个实例,我把此书的第一章纳入 Git 管理,在一个段落中加入了一些文本后保存,之后运行`git diff`命令,得到结果如下: - $ git diff - diff --git a/chapter1.doc b/chapter1.doc - index c1c8a0a..b93c9e4 100644 - --- a/chapter1.doc - +++ b/chapter1.doc - @@ -8,7 +8,8 @@ re going to cover Version Control Systems (VCS) and Git basics - re going to cover how to get it and set it up for the first time if you don - t already have it on your system. - In Chapter Two we will go over basic Git usage - how to use Git for the 80% - -s going on, modify stuff and contribute changes. If the book spontaneously - +s going on, modify stuff and contribute changes. If the book spontaneously - +Let's see if this works. + $ git diff + diff --git a/chapter1.doc b/chapter1.doc + index c1c8a0a..b93c9e4 100644 + --- a/chapter1.doc + +++ b/chapter1.doc + @@ -128,7 +128,7 @@ and data size) + Since its birth in 2005, Git has evolved and matured to be easy to use + and yet retain these initial qualities. It’s incredibly fast, it’s + very efficient with large projects, and it has an incredible branching + -system for non-linear development. + +system for non-linear development (See Chapter 3). Git 成功且简洁地显示出我增加的文本"Let’s see if this works"。虽然有些瑕疵,在末尾显示了一些随机的内容,但确实可以比较了。如果你能找到或自己写个Word到纯文本的转换器的话,效果可能会更好。 `strings`可以在大部分Mac和Linux系统上运行,所以它是处理二进制格式的第一选择。 +##### OpenDocument Text files ##### + +The same approach that we used for MS Word files (`*.doc`) can be used for OpenDocument Text files (`*.odt`) created by OpenOffice.org. + +Add the following line to your `.gitattributes` file: + + *.odt diff=odt + +Now set up the `odt` diff filter in `.git/config`: + + [diff "odt"] + binary = true + textconv = /usr/local/bin/odt-to-txt + +OpenDocument files are actually zip’ped directories containing multiple files (the content in an XML format, stylesheets, images, etc.). We’ll need to write a script to extract the content and return it as plain text. Create a file `/usr/local/bin/odt-to-txt` (you are free to put it into a different directory) with the following content: + + #! /usr/bin/env perl + # Simplistic OpenDocument Text (.odt) to plain text converter. + # Author: Philipp Kempgen + + if (! defined($ARGV[0])) { + print STDERR "No filename given!\n"; + print STDERR "Usage: $0 filename\n"; + exit 1; + } + + my $content = ''; + open my $fh, '-|', 'unzip', '-qq', '-p', $ARGV[0], 'content.xml' or die $!; + { + local $/ = undef; # slurp mode + $content = <$fh>; + } + close $fh; + $_ = $content; + s/]*>//g; # remove spans + s/]*>/\n\n***** /g; # headers + s/]*>\s*]*>/\n -- /g; # list items + s/]*>/\n\n/g; # lists + s/]*>/\n /g; # paragraphs + s/<[^>]+>//g; # remove all XML tags + s/\n{2,}/\n\n/g; # remove multiple blank lines + s/\A\n+//; # remove leading blank lines + print "\n", $_, "\n\n"; + +And make it executable + + chmod +x /usr/local/bin/odt-to-txt + +Now `git diff` will be able to tell you what changed in `.odt` files. + +##### Image files ##### + 你还能用这个方法比较图像文件。当比较时,对JPEG文件运用一个过滤器,它能提炼出EXIF信息 — 大部分图像格式使用的元数据。如果你下载并安装了`exiftool`程序,可以用它参照元数据把图像转换成文本。比较的不同结果将会用文本向你展示: - $ echo '*.png diff=exif' >> .gitattributes - $ git config diff.exif.textconv exiftool + $ echo '*.png diff=exif' >> .gitattributes + $ git config diff.exif.textconv exiftool 如果在项目中替换了一个图像文件,运行`git diff`命令的结果如下: - diff --git a/image.png b/image.png - index 88839c4..4afcb7c 100644 - --- a/image.png - +++ b/image.png - @@ -1,12 +1,12 @@ - ExifTool Version Number : 7.74 - -File Size : 70 kB - -File Modification Date/Time : 2009:04:21 07:02:45-07:00 - +File Size : 94 kB - +File Modification Date/Time : 2009:04:21 07:02:43-07:00 - File Type : PNG - MIME Type : image/png - -Image Width : 1058 - -Image Height : 889 - +Image Width : 1056 - +Image Height : 827 - Bit Depth : 8 - Color Type : RGB with Alpha + diff --git a/image.png b/image.png + index 88839c4..4afcb7c 100644 + --- a/image.png + +++ b/image.png + @@ -1,12 +1,12 @@ + ExifTool Version Number : 7.74 + -File Size : 70 kB + -File Modification Date/Time : 2009:04:17 10:12:35-07:00 + +File Size : 94 kB + +File Modification Date/Time : 2009:04:21 07:02:43-07:00 + File Type : PNG + MIME Type : image/png + -Image Width : 1058 + -Image Height : 889 + +Image Width : 1056 + +Image Height : 827 + Bit Depth : 8 + Color Type : RGB with Alpha 你会发现文件的尺寸大小发生了改变。 @@ -377,15 +439,15 @@ Git 成功且简洁地显示出我增加的文本"Let’s see if this works"。 首先,你能够把blob的SHA-1校验和自动注入文件的`$Id$`字段。如果在一个或多个文件上设置了此字段,当下次你签出分支的时候,Git 用blob的SHA-1值替换那个字段。注意,这不是提交对象的SHA校验和,而是blob本身的校验和: - $ echo '*.txt ident' >> .gitattributes - $ echo '$Id$' > test.txt + $ echo '*.txt ident' >> .gitattributes + $ echo '$Id$' > test.txt 下次签出文件时,Git 入了blob的SHA值: - $ rm text.txt - $ git checkout -- text.txt - $ cat test.txt - $Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $ + $ rm test.txt + $ git checkout -- test.txt + $ cat test.txt + $Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $ 然而,这样的显示结果没有多大的实际意义。这个SHA的值相当地随机,无法区分日期的前后,所以,如果你在CVS或Subversion中用过关键字替换,一定会包含一个日期值。 @@ -399,40 +461,40 @@ Insert 18333fig0703.png 这里举一个简单的例子:在暂存前,用`indent`(缩进)程序过滤所有C源代码。在`.gitattributes`文件中设置"indent"过滤器过滤`*.c`文件: - *.c filter=indent + *.c filter=indent 然后,通过以下配置,让 Git 知道"indent"过滤器在遇到"smudge"和"clean"时分别该做什么: - $ git config --global filter.indent.clean indent - $ git config --global filter.indent.smudge cat + $ git config --global filter.indent.clean indent + $ git config --global filter.indent.smudge cat 于是,当你暂存`*.c`文件时,`indent`程序会被触发,在把它们签出之前,`cat`程序会被触发。但`cat`程序在这里没什么实际作用。这样的组合,使C源代码在暂存前被`indent`程序过滤,非常有效。 另一个例子是类似RCS的`$Date$`关键字扩展。为了演示,需要一个小脚本,接受文件名参数,得到项目的最新提交日期,最后把日期写入该文件。下面用Ruby脚本来实现: - #! /usr/bin/env ruby - data = STDIN.read - last_date = `git log --pretty=format:"%ad" -1` - puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$') + #! /usr/bin/env ruby + data = STDIN.read + last_date = `git log --pretty=format:"%ad" -1` + puts data.gsub('$Date$', '$Date: ' + last_date.to_s + '$') 该脚本从`git log`命令中得到最新提交日期,找到文件中的所有`$Date$`字符串,最后把该日期填充到`$Date$`字符串中 — 此脚本很简单,你可以选择你喜欢的编程语言来实现。把该脚本命名为`expand_date`,放到正确的路径中,之后需要在 Git 中设置一个过滤器(`dater`),让它在签出文件时调用`expand_date`,在暂存文件时用Perl清除之: - $ git config filter.dater.smudge expand_date - $ git config filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"' + $ git config filter.dater.smudge expand_date + $ git config filter.dater.clean 'perl -pe "s/\\\$Date[^\\\$]*\\\$/\\\$Date\\\$/"' 这个Perl小程序会删除`$Date$`字符串里多余的字符,恢复`$Date$`原貌。到目前为止,你的过滤器已经设置完毕,可以开始测试了。打开一个文件,在文件中输入`$Date$`关键字,然后设置 Git 属性: - $ echo '# $Date$' > date_test.txt - $ echo 'date*.txt filter=dater' >> .gitattributes + $ echo '# $Date$' > date_test.txt + $ echo 'date*.txt filter=dater' >> .gitattributes 如果暂存该文件,之后再签出,你会发现关键字被替换了: - $ git add date_test.txt .gitattributes - $ git commit -m "Testing date expansion in Git" - $ rm date_test.txt - $ git checkout date_test.txt - $ cat date_test.txt - # $Date: Tue Apr 21 07:26:52 2009 -0700$ + $ git add date_test.txt .gitattributes + $ git commit -m "Testing date expansion in Git" + $ rm date_test.txt + $ git checkout date_test.txt + $ cat date_test.txt + # $Date: Tue Apr 21 07:26:52 2009 -0700$ 虽说这项技术对自定义应用来说很有用,但还是要小心,因为`.gitattributes`文件会随着项目一起提交,而过滤器(例如:`dater`)不会,所以,过滤器不会在所有地方都生效。当你在设计这些过滤器时要注意,即使它们无法正常工作,也要让整个项目运作下去。 @@ -446,7 +508,7 @@ Git属性在导出项目归档时也能发挥作用。 例如,在`test/`子目录中有一些测试文件,在项目的压缩包中包含他们是没有意义的。因此,可以增加下面这行到 Git 属性文件中: - test/ export-ignore + test/ export-ignore 现在,当运行git archive来创建项目的压缩包时,那个目录不会在归档中出现。 @@ -454,15 +516,15 @@ Git属性在导出项目归档时也能发挥作用。 还能对归档做一些简单的关键字替换。在第2章中已经可以看到,可以以`--pretty=format`形式的简码在任何文件中放入`$Format:$` 字符串。例如,如果想在项目中包含一个叫作`LAST_COMMIT`的文件,当运行`git archive`时,最后提交日期自动地注入进该文件,可以这样设置: - $ echo 'Last commit date: $Format:%cd$' > LAST_COMMIT - $ echo "LAST_COMMIT export-subst" >> .gitattributes - $ git add LAST_COMMIT .gitattributes - $ git commit -am 'adding LAST_COMMIT file for archives' + $ echo 'Last commit date: $Format:%cd$' > LAST_COMMIT + $ echo "LAST_COMMIT export-subst" >> .gitattributes + $ git add LAST_COMMIT .gitattributes + $ git commit -am 'adding LAST_COMMIT file for archives' 运行`git archive`后,打开该文件,会发现其内容如下: - $ cat LAST_COMMIT - Last commit date: $Format:Tue Apr 21 08:38:48 2009 -0700$ + $ cat LAST_COMMIT + Last commit date: $Format:Tue Apr 21 08:38:48 2009 -0700$ ### 合并策略 ### @@ -470,13 +532,13 @@ Git属性在导出项目归档时也能发挥作用。 如果项目的一个分支有歧义或比较特别,但你想从该分支合并,而且需要忽略其中某些文件,这样的合并策略是有用的。例如,你有一个数据库设置文件database.xml,在2个分支中他们是不同的,你想合并一个分支到另一个,而不弄乱该数据库文件,可以设置属性如下: - database.xml merge=ours + database.xml merge=ours 如果合并到另一个分支,database.xml文件不会有合并冲突,显示如下: - $ git merge topic - Auto-merging database.xml - Merge made by recursive. + $ git merge topic + Auto-merging database.xml + Merge made by recursive. 这样,database.xml会保持原样。 @@ -682,7 +744,7 @@ update 脚本和 `pre-receive` 脚本十分类似。不同之处在于它会为 exit 1 end end - end + end end check_directory_perms @@ -717,9 +779,9 @@ update 脚本和 `pre-receive` 脚本十分类似。不同之处在于它会为 Writing objects: 100% (3/3), 323 bytes, done. Total 3 (delta 1), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. - Enforcing Policies... + Enforcing Policies... (refs/heads/master) (8338c5) (c5b616) - [POLICY] Cannot push a non-fast-forward reference + [POLICY] Cannot push a non fast-forward reference error: hooks/update exited with error code 1 error: hook declined to update refs/heads/master To git@gitserver:project.git @@ -728,8 +790,8 @@ update 脚本和 `pre-receive` 脚本十分类似。不同之处在于它会为 这里有几个有趣的信息。首先,我们可以看到挂钩运行的起点: - Enforcing Policies... - (refs/heads/master) (fb8c72) (c56860) + Enforcing Policies... + (refs/heads/master) (8338c5) (c5b616) 注意这是从 update 脚本开头输出到标准你输出的。所有从脚本输出的提示都会发送到客户端,这点很重要。 @@ -855,7 +917,7 @@ update 脚本和 `pre-receive` 脚本十分类似。不同之处在于它会为 target_shas.each do |sha| remote_refs.each do |remote_ref| shas_pushed = `git rev-list ^#{sha}^@ refs/remotes/#{remote_ref}` - if shas_pushed.split(“\n”).include?(sha) + if shas_pushed.split("\n").include?(sha) puts "[POLICY] Commit #{sha} has already been pushed to #{remote_ref}" exit 1 end diff --git a/zh/08-git-and-other-scms/01-chapter8.markdown b/zh/08-git-and-other-scms/01-chapter8.markdown index 34fa376f6..1aae0d2a3 100644 --- a/zh/08-git-and-other-scms/01-chapter8.markdown +++ b/zh/08-git-and-other-scms/01-chapter8.markdown @@ -29,14 +29,14 @@ Git 中所有 Subversion 桥接命令的基础是 `git svn` 。所有的命令 然后,允许所有用户修改 revprop —— 简单的做法是添加一个总是以 0 作为返回值的 pre-revprop-change 脚本: - $ cat /tmp/test-svn/hooks/pre-revprop-change + $ cat /tmp/test-svn/hooks/pre-revprop-change #!/bin/sh exit 0; $ chmod +x /tmp/test-svn/hooks/pre-revprop-change 现在可以调用 `svnsync init` 加目标仓库,再加源仓库的格式来把该项目同步到本地了: - $ svnsync init file:///tmp/test-svn http://progit-example.googlecode.com/svn/ + $ svnsync init file:///tmp/test-svn http://progit-example.googlecode.com/svn/ 这将建立进行同步所需的属性。可以通过运行以下命令来克隆代码: @@ -281,7 +281,7 @@ Git 通过搜寻提交历史中 Subversion 分支的头部来决定 dcommit 的 ------------------------------------------------------------------------ r85 | schacon | 2009-05-02 16:00:09 -0700 (Sat, 02 May 2009) | 2 lines - + updated the changelog 关于 `git svn log` ,有两点需要注意。首先,它可以离线工作,不像 `svn log` 命令,需要向 Subversion 服务器索取数据。其次,它仅仅显示已经提交到 Subversion 服务器上的 commit。在本地尚未 dcommit 的 Git 数据不会出现在这里;其他人向 Subversion 服务器新提交的数据也不会显示。等于说是显示了最近已知 Subversion 服务器上的状态。 @@ -290,19 +290,19 @@ Git 通过搜寻提交历史中 Subversion 分支的头部来决定 dcommit 的 类似 `git svn log` 对 `git log` 的模拟,`svn annotate` 的等效命令是 `git svn blame [文件名]`。其输出如下: - $ git svn blame README.txt + $ git svn blame README.txt 2 temporal Protocol Buffers - Google's data interchange format 2 temporal Copyright 2008 Google Inc. 2 temporal http://code.google.com/apis/protocolbuffers/ - 2 temporal + 2 temporal 22 temporal C++ Installation - Unix 22 temporal ======================= - 2 temporal + 2 temporal 79 schacon Committing in git-svn. - 78 schacon + 78 schacon 2 temporal To build and install the C++ Protocol Buffer runtime and the Protocol 2 temporal Buffer compiler (protoc) execute the following: - 2 temporal + 2 temporal 同样,它不显示本地的 Git 提交以及 Subversion 上后来更新的内容。 @@ -369,7 +369,7 @@ Git 通过搜寻提交历史中 Subversion 分支的头部来决定 dcommit 的 为 `git svn` 提供该文件可以然它更精确的映射作者数据。你还可以在 `clone` 或者 `init`后面添加 `--no-metadata` 来阻止 `git svn` 包含那些 Subversion 的附加信息。这样 `import` 命令就变成了: - $ git-svn clone http://my-project.googlecode.com/svn/ \ + $ git svn clone http://my-project.googlecode.com/svn/ \ --authors-file=users.txt --no-metadata -s my_project 现在 `my_project` 目录下导入的 Subversion 应该比原来整洁多了。原来的 commit 看上去是这样: @@ -396,15 +396,13 @@ Git 通过搜寻提交历史中 Subversion 分支的头部来决定 dcommit 的 要把标签变成合适的 Git 标签,运行 - $ cp -Rf .git/refs/remotes/tags/* .git/refs/tags/ - $ rm -Rf .git/refs/remotes/tags + $ 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` 下面剩下的索引变成本地分支: - $ cp -Rf .git/refs/remotes/* .git/refs/heads/ - $ rm -Rf .git/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 现在所有的旧分支都变成真正的 Git 分支,所有的旧标签也变成真正的 Git 标签。最后一项工作就是把新建的 Git 服务器添加为远程服务器并且向它推送。下面是新增远程服务器的例子: @@ -413,6 +411,7 @@ Git 通过搜寻提交历史中 Subversion 分支的头部来决定 dcommit 的 为了让所有的分支和标签都得到上传,我们使用这条命令: $ git push origin --all + $ git push origin --tags 所有的分支和标签现在都应该整齐干净的躺在新的 Git 服务器里了。 @@ -512,7 +511,7 @@ Git 通过搜寻提交历史中 Subversion 分支的头部来决定 dcommit 的 next if File.file?(dir) # 进入目标目录 - Dir.chdir(dir) do + Dir.chdir(dir) do last_mark = print_export(dir, last_mark) end end @@ -575,7 +574,8 @@ Git 通过搜寻提交历史中 Subversion 分支的头部来决定 dcommit 的 唯一剩下的就是每一个快照的内容了。这简单的很,因为它们分别处于一个目录——你可以输出 `deleeall` 命令,随后是目录中每个文件的内容。Git 会正确的记录每一个快照: puts 'deleteall' - Dir.glob("**/*").each do |file| next if !File.file?(file) + Dir.glob("**/*").each do |file| + next if !File.file?(file) inline_data(file) end @@ -607,7 +607,7 @@ Git 通过搜寻提交历史中 Subversion 分支的头部来决定 dcommit 的 搞定了。现在运行该脚本,你将得到如下内容: - $ ruby import.rb /opt/import_from + $ ruby import.rb /opt/import_from commit refs/heads/master mark :1 committer Scott Chacon 1230883200 -0700 diff --git a/zh/09-git-internals/01-chapter9.markdown b/zh/09-git-internals/01-chapter9.markdown index 2f1b11229..e112727ef 100644 --- a/zh/09-git-internals/01-chapter9.markdown +++ b/zh/09-git-internals/01-chapter9.markdown @@ -326,7 +326,7 @@ Git 用 zlib 对数据内容进行压缩,在 Ruby 中可以用 zlib 库来实 现在,你的 Git 数据库应该看起来像图 9-4 一样。 -Insert 18333fig0904.png +Insert 18333fig0904.png 图 9-4. 包含分支引用的 Git 目录对象 每当你执行 `git branch (分支名称)` 这样的命令,Git 基本上就是执行 `update-ref` 命令,把你现在所在分支中最后一次提交的 SHA-1 值,添加到你要创建的分支的引用。 @@ -451,8 +451,8 @@ Git 用 zlib 压缩文件内容,因此这些文件并没有占用太多空间 然后可以用 `git cat-file` 命令查看这个对象有多大: - $ git cat-file -s 9bc1dc421dcd51b4ac296e3e5b6e2a99cf44391e - 12898 + $ du -b .git/objects/9b/c1dc421dcd51b4ac296e3e5b6e2a99cf44391e + 4102 .git/objects/9b/c1dc421dcd51b4ac296e3e5b6e2a99cf44391e 稍微修改一下些文件,看会发生些什么: @@ -470,8 +470,8 @@ Git 用 zlib 压缩文件内容,因此这些文件并没有占用太多空间 blob 对象与之前的已经不同了。这说明虽然只是往一个 400 行的文件最后加入了一行内容,Git 却用一个全新的对象来保存新的文件内容: - $ git cat-file -s 05408d195263d853f09dca71d55116663690c27c - 12908 + $ du -b .git/objects/05/408d195263d853f09dca71d55116663690c27c + 4109 .git/objects/05/408d195263d853f09dca71d55116663690c27c 你的磁盘上有了两个几乎完全相同的 12K 的对象。如果 Git 只完整保存其中一个,并保存另一个对象的差异内容,岂不更好? From a753033793125f1c6b971d0c1a1e2bc77c56396d Mon Sep 17 00:00:00 2001 From: Cor Date: Mon, 17 Feb 2014 13:59:46 +0100 Subject: [PATCH 024/478] [nl] Chapter03 first part of review --- nl/03-git-branching/01-chapter3.markdown | 47 +++++++++++++++--------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/nl/03-git-branching/01-chapter3.markdown b/nl/03-git-branching/01-chapter3.markdown index 78dc75ca0..7adb409d0 100644 --- a/nl/03-git-branching/01-chapter3.markdown +++ b/nl/03-git-branching/01-chapter3.markdown @@ -1,23 +1,36 @@ + # Branchen in Git # Bijna elk versiebeheersysteem ondersteunt een bepaalde vorm van branchen. Branchen komt erop neer dat je een tak afsplitst van de hoofd ontwikkellijn en daar verder mee gaat werken zonder aan de hoofdlijn te komen. Bij veel VCS'en is dat nogal een duur proces, vaak wordt er een nieuwe kopie gemaakt van de directory waar je broncode in staan, wat lang kan duren voor grote projecten. -Sommige mensen verwijzen naar het branch model in Git als de "killer eigenschap", en het onderscheidt Git zeker in de VCS gemeenschap. Waarom maakt het zo bijzonder? De manier waarop Git branched is ongelooflijk lichtgewicht, waardoor branch operaties vrijwel instant zijn en het wisselen tussen de branches over het algemeen net zo snel. In tegenstelling to vele andere VCS's, moedigt Git juist een werkwijze aan die vaak branched en merged, zelfs meerdere keren per dag. Deze eigenschap begrijpen en de techniek beheersen geeft je een krachtig en uniek gereedschap en kan letterlijk de manier waarop je ontwikkelt veranderen. +Sommige mensen verwijzen naar het branch model in Git als de "killer eigenschap", en het onderscheidt Git zeker in de VCS gemeenschap. Waarom is het zo bijzonder? De manier waarop Git brancht is ongelooflijk lichtgewicht, waardoor branch operaties vrijwel instant zijn en het wisselen tussen de branches over het algemeen net zo snel. In tegenstelling to vele andere VCS's, moedigt Git juist een workflow aan waarbij vaak gebranched en gemerged wordt, zelfs meerdere keren per dag. Deze eigenschap begrijpen en de techniek beheersen geeft je een krachtig en uniek gereedschap en kan letterlijk de manier waarop je ontwikkelt veranderen. ## Wat een branch is ## -Om de manier waarop Git branched echt te begrijpen, moeten we een stap terug doen en onderzoeken hoe Git zijn gegevens opslaat. Zoals je misschien herinnert van Hoofdstuk 1, slaat Git zijn gegevens niet op als een reeks van wijzigingen of delta's, maar in plaats daarvan als een serie snapshots. +Om de manier waarop Git brancht echt te begrijpen, moeten we een stap terug doen en onderzoeken hoe Git zijn gegevens opslaat. Zoals je misschien herinnert van Hoofdstuk 1, slaat Git zijn gegevens niet op als een reeks van wijzigingen of delta's, maar in plaats daarvan als een serie snapshots. Als je in Git commit, dan slaat Git een commit object op dat een verwijzing bevat naar het snapshot van de inhoud die je gestaged hebt, de auteur en bericht metagegevens, en nul of meer verwijzingen naar de commit of commits die de directe ouders van deze commit waren: nul ouders voor de eerste commit, één ouder voor een normale commit, en meerdere ouders voor een commit die het resultaat is van een merge van twee of meer branches. -Om dit te visualiseren, gaan we aannemen dat je een directory hebt met drie bestanden, en je staged en commit ze allemaal. Door de bestanden te stagen krijgen ze allemaal een checksum (de SHA-1 hash waar we het in Hoofdstuk 1 over hadden), bewaart die versie van het bestand in het Git repository (Git noemt ze blobs), en voegt die checksum toe aan het stage gebied: +Om dit te visualiseren, gaan we aannemen dat je een directory hebt met drie bestanden, en je staged en commit ze allemaal. Door de bestanden te stagen krijgen ze allemaal een checksum (de SHA-1 hash waar we het in Hoofdstuk 1 over hadden), bewaart die versie van het bestand in het Git repository (Git noemt ze blobs), en voegt die checksum toe aan de staging area: $ git add README test.rb LICENSE $ git commit -m 'initial commit of my project' -Als je de commit aanmaakt door `git commit` uit te voeren zal Git iedere project directory van een checksum voorzien en slaat ze als boomstructuur (`tree`) objecten in de Git repository op. Daarna creëert Git een `commit` object dat de metagegevens bevat en een verwijzing naar de hoofd project `tree`-object zodat Git deze snapshot kan opnieuw kan maken als dat nodig is. +Als je de commit aanmaakt door `git commit` uit te voeren zal Git iedere project directory van een checksum voorzien en slaat ze als boomstructuur (`tree`) objecten in de Git repository op. Daarna creëert Git een `commit` object dat de metagegevens bevat en een verwijzing naar de hoofd project `tree`-object zodat Git deze snapshot kan opnieuw kan oproepen als dat nodig is. -Je Git repository bevat nu vijf objecten: een blob voor de inhoud van ieder van de drie bestanden, een tree die de inhoud van de directory weergeeft en specificeert welke bestandsnamen opgeslagen zijn als welke blobs, en een commit met de verwijzing naar die hoofd tree en alle commit metagegevens. Conceptueel zien de gegevens in je Git repository eruit zoals in Figuur 3-1. +Je Git repository bevat nu vijf objecten: een blob voor de inhoud van ieder van de drie bestanden, een tree die de inhoud van de directory weergeeft en specificeert welke bestandsnamen opgeslagen zijn als welke blobs, en een commit met de verwijzing naar die hoofd-tree en alle commit metagegevens. Conceptueel zien de gegevens in je Git repository eruit zoals in Figuur 3-1. Insert 18333fig0301.png Figuur 3-1. Repository gegevens van een enkele commit. @@ -41,7 +54,7 @@ Dit maakt een nieuwe verwijzing naar dezelfde commit waar je nu op zit (zie Figu Insert 18333fig0304.png Figuur 3-4. Meerdere branches wijzend naar de commit gegevens historie. -Hoe weet Git op welke branch je nu zit? Het houdt een speciale verwijzing bij genaamd HEAD. Let op dat dit heel anders is dan het concept van HEAD in andere VCS's waar je misschien gewend aan bent, zoals bijvoorbeeld Subversion of CVS. In Git, is dit een verwijzing naar de lokale branch waar je nu op zit. In dit geval, zit je nog steeds op master. Het git branch commando heeft alleen een nieuwe branch aangemaakt — het is nog niet overgeschakeld naar die branch (zie Figuur 3-5). +Hoe weet Git op welke branch je nu zit? Het houdt een speciale verwijzing bij genaamd HEAD. Let op dat dit heel anders is dan het concept van HEAD in andere VCS's waar je misschien gewend aan bent, zoals Subversion of CVS. In Git is dit een verwijzing naar de lokale branch waar je nu op zit. In dit geval zit je nog steeds op master. Het git branch commando heeft alleen een nieuwe branch aangemaakt, we zijn nog niet overgeschakeld naar die branch (zie Figuur 3-5). Insert 18333fig0305.png Figuur 3-5. HEAD bestand wijzend naar de branch waar je op zit. @@ -74,27 +87,27 @@ Figuur 3-8 toont het resultaat. Insert 18333fig0308.png Figuur 3-8. HEAD verschuift naar een andere branch bij een checkout. -Dat commando heeft twee dingen gedaan. Het verplaatste de HEAD verwijzing terug naar de `master` branch, en het draaide de bestanden in je werkdirectory terug naar het snapshot waar die `master` naar wijst. Dit betekent ook dat de wijzigingen die je vanaf dit punt maakt uiteen zullen gaan lopen met een oudere versie van het project. In essentie betekent dat het werk dat je in je testing branch hebt gedaan tijdelijk wordt teruggedraait, zodat je een andere richting op kunt gaan. +Dat commando heeft twee dingen gedaan. Het verplaatste de HEAD verwijzing terug naar de `master` branch, en het draaide de bestanden in je werkdirectory terug naar het snapshot waar die `master` naar wijst. Dit betekent ook dat de wijzigingen die je vanaf dit punt maakt uiteen zullen gaan lopen met een oudere versie van het project. In essentie betekent dat het werk dat je in je testing branch hebt gedaan tijdelijk wordt teruggedraaid, zodat je een andere richting op kunt gaan. Laten we een paar wijzigingen maken en nog eens committen: $ vim test.rb $ git commit -a -m 'made other changes' -Nu is je project historie uiteen gelopen (zie Figuur 3-9). Je hebt een branch gemaakt en bent er naartoe overgeschakeld, hebt er wat werk op gedaan, en bent toen teruggeschakeld naar je hoofd branch en hebt nog wat ander werk gedaan. Al die veranderingen zijn geïsoleerd van elkaar in aparte branches: je kunt heen en weer schakelen tussen de branches en ze mergen als je klaar bent. En je hebt dat alles gedaan met eenvoudige `branch` en `checkout` commando's. +Nu is je project historie uiteen gelopen (zie Figuur 3-9). Je hebt een branch gemaakt en bent er naartoe overgeschakeld, hebt er wat werk op gedaan, en bent toen teruggeschakeld naar je hoofd-branch en hebt nog wat ander werk gedaan. Al die veranderingen zijn geïsoleerd van elkaar in aparte branches: je kunt heen en weer schakelen tussen de branches en ze mergen als je klaar bent. En je hebt dat alles gedaan met eenvoudige `branch` en `checkout` commando's. Insert 18333fig0309.png Figuur 3-9. De branch histories zijn uiteen gaan lopen. Omdat een branch in Git in feite een eenvoudig bestand is dat de 40 karakter lange SHA-1 checksum van de commit bevat waar het naar wijst, zijn branches goedkoop om te maken en weer weg te gooien. Een nieuwe branch aanmaken is zo snel en eenvoudig als 41 bytes naar een bestand schrijven (40 karakters en een harde return). -Dit is in scherp contrast met de wijze waarop de meeste VCS applicaties branchen, wat vaak het kopiëren van alle project bestanden naar een tweede map inhoudt. Dit kan enkele seconden of zelfs minuten duren, afhankelijk van de grootte van het project, daarentegen is het in Git altijd vrijwel meteen klaar. En omdat we de ouders opslaan terwijl we committen, wordt het vinden van een goed punt dat kan dienen als basis voor het mergen automatisch voor ons gedaan en is dat over het algemeen eenvoudig om te doen. Deze eigenschappen helpen ontwikkelaars met vertrouwen branches vaak aan te maken en te gebruiken. +Dit is in scherp contrast met de wijze waarop de meeste VCS applicaties branchen, wat vaak het kopiëren van alle project bestanden naar een tweede map inhoudt. Dit kan enkele seconden of zelfs minuten duren, afhankelijk van de grootte van het project, daarentegen is het in Git altijd vrijwel meteen klaar. En omdat we de ouders opslaan terwijl we committen, wordt het vinden van een goed punt dat kan dienen als basis voor het mergen automatisch voor ons gedaan en is dat over het algemeen eenvoudig om te doen. Deze eigenschappen helpen ontwikkelaars aan te moedigen vaak branches aan te maken en te gebruiken. Laten we eens kijken waarom je dat zou moeten doen. ## Eenvoudig branchen en mergen ## -Laten we eens door een eenvoudig voorbeeld van branchen en mergen stappen met een werkwijze die je zou kunnen gebruiken in de echte wereld. Je zult deze stappen volgen: +Laten we eens door een eenvoudig voorbeeld van branchen en mergen stappen met een workflow die je zou kunnen gebruiken in de echte wereld. Je zult deze stappen volgen: 1. Werken aan een website. 2. Een branch aanmaken voor een nieuw verhaal waar je aan werkt. @@ -102,9 +115,9 @@ Laten we eens door een eenvoudig voorbeeld van branchen en mergen stappen met ee Dan ontvang je een telefoontje dat je een ander probleem direct moet repareren. Je zult het volgende doen: -1. Terugdraaien naar je productie branch. +1. Terugschakelen naar je productie branch. 2. Een branch aanmaken om de snelle reparatie toe te voegen. -3. Nadat het getest is, de snelle reparatie branch samenvoegen, en dat naar productie terugzetten. +3. Nadat het getest is de snelle reparatie branch mergen, en dat naar productie terugzetten. 4. Terugschakelen naar je originele verhaal en doorgaan met werken. ### Eenvoudig branchen ### @@ -114,7 +127,7 @@ Als eerste, laten we zeggen dat je aan je project werkt en al een paar commits h Insert 18333fig0310.png Figuur 3-10. Een korte en eenvoudige commit historie. -Je hebt besloten dan je gaat werken aan probleem #53 in wat voor systeem je bedrijf ook gebruikt om problemen te registreren. Voor de duidelijkheid: Git is niet verbonden met een probleem beheersysteem in het bijzonder, maar omdat probleem #53 een specifiek onderwerp is waar je aan wilt werken, zul je een nieuwe branch aanmaken waarin je gaat werken. Om een branch aan te maken en er meteen naartoe te schakelen, kun je het `git checkout` commando uitvoeren met de `-b` optie: +Je hebt besloten dan je gaat werken aan probleem #53 in wat voor systeem je bedrijf ook gebruikt om problemen te registreren. Voor de duidelijkheid: Git is niet verbonden met een probleem beheersysteem in het bijzonder. En omdat probleem #53 een specifiek onderwerp is waar je aan gaat werken, maak je een nieuwe branch aan waarin je aan de slag gaat. Om een branch aan te maken en er meteen naartoe te schakelen, kun je het `git checkout` commando uitvoeren met de `-b` optie: $ git checkout -b iss53 Switched to a new branch "iss53" @@ -139,7 +152,7 @@ Figuur 3-12. De iss53 branch is vooruit gegaan met je werk. Nu krijg je het telefoontje dan er een probleem is met de web site, en je moet het meteen repareren. Met Git hoef je de reparatie niet tegelijk uit te leveren met de `iss53` wijzigingen die je gemaakt hebt, en je hoeft ook niet veel moeite te doen om die wijzigingen terug te draaien voordat je kunt werken aan het toepassen van je reparatie in productie. Het enige wat je moet doen in terugschakelen naar je master branch. -Maar voordat je dat doet, let op dat als je werk directory of staging gebied wijzigingen bevat die nog niet gecommit zijn en conflicteren met de branch die je gaat uitchecken, Git je niet toestaat om te schakelen. Het is het beste om een schone werk status te hebben als je tussen branches gaat schakelen. Er zijn manieren om hier mee om te gaan (te weten, stashen en commit ammending) die we later gaan behandelen. Voor nu heb je alle wijzigingen gecommit, zodat je terug kunt schakelen naar je master branch: +Maar voordat je dat doet, let op dat als je werk directory of staging area wijzigingen bevat die nog niet gecommit zijn en conflicteren met de branch die je gaat uitchecken, Git je niet laat om te schakelen. Het beste is om een schone werk status te hebben als je tussen branches gaat schakelen. Er zijn manieren om hier mee om te gaan (te weten, stashen en commit ammending) die we later gaan behandelen. Voor nu heb je alle wijzigingen gecommit, zodat je terug kunt schakelen naar je master branch: $ git checkout master Switched to branch "master" @@ -337,15 +350,15 @@ Dit toont je andere branch. Omdat het werk bevat dat nog niet samengevoegd is, z Als je de branch echt wilt verwijderen en dat werk wilt verliezen, dan kun je het forceren met `-D`, zoals het behulpzame bericht je al meldt. -## Branch werkwijzen ## +## Branch workflows ## -Nu dat je de basis van het branchen en samenvoegen onder de knie hebt, wat kan of zou je met ze kunnen doen? In deze paragraaf gaan we een aantal veel voorkomende werkwijzen die deze lichtgewicht branches mogelijk maken behandelen, zodat je kunt besluiten of je ze wilt toepassen in jouw ontwikkel cyclus. +Nu dat je de basis van het branchen en samenvoegen onder de knie hebt, wat kan of zou je met ze kunnen doen? In deze paragraaf gaan we een aantal veel voorkomende workflows die deze lichtgewicht branches mogelijk maken behandelen, zodat je kunt besluiten of je ze wilt toepassen in jouw ontwikkel cyclus. ### Lang-lopende branches ### Omdat Git gebruik maakt van een eenvoudige drieweg merge, is het meerdere keren mergen vanuit een branch in een andere gedurende een langere periode over het algemeen eenvoudig te doen. Dit betekent dat je meerdere branches kunt hebben, die altijd open staan en die je voor verschillende delen van je ontwikkel cyclus gebruikt; je kunt regelmatig een aantal mergen in andere. -Veel Git ontwikkelaars hebben een werkwijze die deze aanpak omarmt, zoals het hebben van alleen volledig stabiele code in hun `master` branch — waarschijnlijk alleen code die is of zal worden vrijgegeven. Ze hebben een andere parallelle branch "develop" of "next" genaamd waarop ze werken of die ze gebruiken om stabiliteit te testen — het is niet noodzakelijk altijd stabiel, maar zodra het in een stabiele status verkeert, kan het worden gemerged in `master`. Het wordt gebruikt om topic branches (branches met een korte levensduur, zoals jou eerdere `iss53` branch) te pullen zodra die klaar zijn, om er zich ervan te verzekeren dat alle testen slagen en er geen fouten worden geïntroduceerd. +Veel Git ontwikkelaars hebben een workflow die deze aanpak omarmt, zoals het hebben van alleen volledig stabiele code in hun `master` branch — waarschijnlijk alleen code die is of zal worden vrijgegeven. Ze hebben een andere parallelle branch "develop" of "next" genaamd waarop ze werken of die ze gebruiken om stabiliteit te testen — het is niet noodzakelijk altijd stabiel, maar zodra het in een stabiele status verkeert, kan het worden gemerged in `master`. Het wordt gebruikt om topic branches (branches met een korte levensduur, zoals jou eerdere `iss53` branch) te pullen zodra die klaar zijn, om er zich ervan te verzekeren dat alle testen slagen en er geen fouten worden geïntroduceerd. In essentie praten we over verwijzingen die zich verplaatsen over de lijn van de commits die je maakt. De stabiele branches zijn verder naar achter in je commit historie, en de splinternieuwe branches zijn verder naar voren in de historie (zie Figuur 3-18). From 33820f55ce9e90e62dd61be3b00bcc60ecb787af Mon Sep 17 00:00:00 2001 From: cor Date: Mon, 17 Feb 2014 21:30:28 +0100 Subject: [PATCH 025/478] [nl] Chapter 05 - Remove yet more typos Reviewed contents against the en version and removed language errors. Also clarified some sentences. Finally: corrected hexadecimal characters (especially diacritics). --- nl/05-distributed-git/01-chapter5.markdown | 253 ++++++++++++--------- 1 file changed, 144 insertions(+), 109 deletions(-) diff --git a/nl/05-distributed-git/01-chapter5.markdown b/nl/05-distributed-git/01-chapter5.markdown index 25c320dc3..6ce3eb1ac 100644 --- a/nl/05-distributed-git/01-chapter5.markdown +++ b/nl/05-distributed-git/01-chapter5.markdown @@ -1,70 +1,105 @@ + # Gedistribueerd Git # -Nu dat je een remote Git repository hebt ingesteld als een plaats waar alle ontwikkelaars hun code kunnen delen, en je bekend bent met fundamentele Git commando's in een lokale werkwijze, zul je hier zien hoe je een paar gedistribueerde werkwijzen kunt gebruiken die je met Git kunt bereiken. +Nu je een remote Git repository hebt ingesteld als een plaats waar alle ontwikkelaars hun code kunnen delen, en je bekend bent met fundamentele Git commando's in een lokale workflow, zul je hier zien hoe je een paar gedistribueerde workflows kunt gebruiken die je met Git kunt bereiken. In dit hoofdstuk zul je zien hoe je met Git kunt werken in een gedistribueerde omgeving als een bijdrager (contributor) en als een integrator. Dat wil zeggen, je zult leren hoe je succesvol code kunt bijdragen aan een project en hoe je het zo makkelijk mogelijk maakt voor jou en de onderhouder van het project, en ook hoe je een project succesvol kunt onderhouden waarbij een aantal ontwikkelaars bijdragen. -## Gedistribueerde werkwijzen ## +## Gedistribueerde workflows ## -In tegenstelling tot gecentraliseerde versiebeheersystemen (CVCSen), stelt de gedistribueerde aard van Git je in staat om veel flexibeler te zijn in de manier waarop ontwikkelaars samenwerken in projecten. Bij gecentraliseerde systemen is iedere ontwikkelaar een knooppunt dat min of meer gelijkwaardig werkt op een centraal punt. In Git is iedere ontwikkelaar zowel een knooppunt als een spil - dat wil zeggen, iedere ontwikkelaar kan zowel code bijdragen aan andere repositories, als ook een publiek repository beheren waarop andere ontwikkelaars hun werk baseren en waaraan zij kunnen bijdragen. Dit stelt je project en/of je team in staat om een enorm aantal werkwijzen er op na te houden, dus ik zal een aantal veel voorkomende manieren behandelen die gebruik maken van deze flexibiliteit. Ik zal de sterke en mogelijke zwakke punten van ieder ontwerp behandelen; je kunt er een kiezen om te gebruiken, of je kunt van iedere wijze een paar eigenschappen overnemen en mengen. +In tegenstelling tot gecentraliseerde versiebeheersystemen (CVCSen), stelt de gedistribueerde aard van Git je in staat om veel flexibeler te zijn in de manier waarop ontwikkelaars samenwerken in projecten. Bij gecentraliseerde systemen is iedere ontwikkelaar een knooppunt dat min of meer gelijkwaardig werkt op een centraal punt. In Git is iedere ontwikkelaar zowel een knooppunt als een spil - dat wil zeggen, iedere ontwikkelaar kan zowel code bijdragen aan andere repositories, als ook een publiek repository beheren waarop andere ontwikkelaars hun werk baseren en waaraan zij kunnen bijdragen. Dit stelt je project en/of je team in staat om een enorm aantal workflows er op na te houden, dus ik zal een aantal veel voorkomende manieren behandelen die gebruik maken van deze flexibiliteit. Ik zal de sterke en mogelijke zwakke punten van ieder ontwerp behandelen; je kunt er een kiezen om te gebruiken, of je kunt van iedere wijze een paar eigenschappen overnemen en mengen. -### Gecentraliseerde werkwijze ### +### Gecentraliseerde workflow ### -In gecentraliseerde systemen is er over het algemeen een enkel samenwerkingsmodel - de gecentraliseerde werkwijze. Eén centraal punt, of repository, kan code aanvaarden, en iedereen synchroniseert zijn werk daarmee. Een aantal ontwikkelaars zijn knopen - gebruikers van dat centrale punt - en synchroniseren met die plaats (zie Figuur 5-1). +In gecentraliseerde systemen is er over het algemeen een enkel samenwerkingsmodel - de gecentraliseerde workflow. Één centraal punt, of repository, kan code aanvaarden, en iedereen synchroniseert zijn werk daarmee. Een aantal ontwikkelaars zijn knopen - gebruikers van dat centrale punt - en synchroniseren met die plaats (zie Figuur 5-1). Insert 18333fig0501.png -Figuur 5-1. Gecentraliseerde Werkwijze. +Figuur 5-1. Gecentraliseerde workflow. -Dit betekent dat als twee ontwikkelaars klonen van het gecentraliseerde punt en beide wijzigingen doen, de eerste ontwikkelaar zijn wijzigingen terug kan zetten zonder problemen. De tweede ontwikkelaar zal het werk van de eerste in het zijne moeten samenvoegen voordat hij het zijne kan terugzetten, om zo niet het werk van de eerste te overschrijven. Dit concept werkt in Git zoals het ook werkt in Subversion (of ieder ander CVCS), en dit model werkt prima in Git. +Dit betekent dat als twee ontwikkelaars clonen van het gecentraliseerde punt en beiden wijzigingen doen, de eerste ontwikkelaar zijn wijzigingen zonder problemen kan pushen. De tweede ontwikkelaar zal het werk van de eerste in het zijne moeten mergen voordat hij het zijne kan pushen, om zo niet het werk van de eerste te overschrijven. Dit concept werkt in Git zoals het ook werkt in Subversion (of ieder ander CVCS), en dit model werkt prima in Git. -Als je een klein team hebt, of al vertrouwd bent met een gecentraliseerde werkwijze in je bedrijf of team, dan kun je eenvoudig doorgaan met het gebruiken van die werkwijze met Git. Stel eenvoudigweg een enkele repository in, en geef iedereen in je team push-toegang; Git zal gebruikers niet toestaan om elkaars wijzigingen te overschrijven. Als een ontwikkelaar kloont, wijzigingen maakt, en dan probeert zijn wijzigingen terug te zetten terwijl een andere ontwikkelaar de zijne in de tussentijd heeft teruggezet, dan zal de server de wijzigingen van die ontwikkelaar weigeren. Ze zullen verteld worden dat ze een "non-fast-forward-wijziging" proberen te pushen en dat ze dat niet wordt toegestaan totdat ze hebben gefetched en gemerged. -Deze werkwijze is voor een hoop mensen aantrekkelijk omdat het er een is waarmee veel mensen bekend zijn en zich op hun gemak bij voelen. +Als je een klein team hebt, of al vertrouwd bent met een gecentraliseerde workflow in je bedrijf of team, dan kun je eenvoudig doorgaan met het gebruiken van die workflow met Git. Stel eenvoudigweg een enkele repository in, en geef iedereen in je team push-toegang; Git zal gebruikers niet toestaan om elkaars wijzigingen te overschrijven. Als een ontwikkelaar cloned, wijzigingen maakt, en dan probeert zijn wijzigingen te pushen terwijl een andere ontwikkelaar de zijne in de tussentijd heeft gepusht, dan zal de server de wijzigingen van die ontwikkelaar weigeren. Ze zullen verteld worden dat ze een "non-fast-forward-wijziging" proberen te pushen en dat ze dat niet wordt toegestaan totdat ze hebben gefetched en gemerged. +Deze workflow is voor een hoop mensen aantrekkelijk omdat het er een is waarmee veel mensen bekend zijn en zich op hun gemak bij voelen. -### Integratie-manager werkwijze ### +### Integratie-manager workflow ### -Omdat Git je toestaat om meerdere remote repositories te hebben, is het mogelijk om een werkwijze te hebben waarbij iedere ontwikkelaar schrijftoegang heeft tot zijn eigen publieke repository en leestoegang op de andere. Dit scenario heeft vaak een gezagdragend (canonical) repository dat het "officiële" project voorstelt. Om bij te kunnen dragen tot dat project, maak je je eigen publieke kloon van het project en zet je wijzigingen daarin terug. Daarna stuur je een verzoek naar de eigenaar van het hoofdproject om jouw wijzigingen binnen te halen (pull request). Hij kan je repository toevoegen als een remote, je wijzigingen lokaal testen, ze in zijn branch mergen, en naar zijn repository terugzetten. Het proces werkt als volgt (zie Figuur 5-2): +Omdat Git je toestaat om meerdere remote repositories te hebben, is het mogelijk om een workflow te hebben waarbij iedere ontwikkelaar schrijftoegang heeft tot zijn eigen publieke repository en leestoegang op de andere. Dit scenario heeft vaak een gezagdragend (canonical) repository dat het "officiële" project voorstelt. Om bij te kunnen dragen tot dat project, maak je je eigen publieke clone van het project en pusht je wijzigingen daarin terug. Daarna stuur je een verzoek naar de eigenaar van het hoofdproject om jouw wijzigingen binnen te halen (pull request). Hij kan je repository toevoegen als een remote, je wijzigingen lokaal testen, ze in zijn branch mergen, en dan naar zijn repository pushen. Het proces werkt als volgt (zie Figuur 5-2): -1. De projecteigenaar pushed naar de publieke repository. -2. Een bijdrager kloont die repository en maakt wijzigingen. -3. De bijdrager pushed naar zijn eigen publieke kopie. +1. De projecteigenaar pusht naar de publieke repository. +2. Een bijdrager cloned die repository en maakt wijzigingen. +3. De bijdrager pusht naar zijn eigen publieke kopie. 4. De bijdrager stuurt de eigenaar een e-mail met de vraag om de wijzigingen binnen te halen (pull request). 5. De eigenaar voegt de repo van de bijdrager toe als een remote en merged lokaal. -6. De eigenaar pushed de gemergde wijzigingen terug in de hoofdrepository. +6. De eigenaar pusht de gemergde wijzigingen terug in de hoofdrepository. Insert 18333fig0502.png -Figuur 5-2. Integratie-manager werkwijze. +Figuur 5-2. Integratie-manager workflow. -Dit is een veel voorkomende werkwijze bij websites zoals GitHub, waarbij het eenvoudig is om een project af te splitsen (fork) en je wijzigingen terug te zetten in jouw afgesplitste project waar iedereen ze kan zien. Een van de grote voordelen van deze aanpak is dat je door kunt gaan met werken, en de eigenaar van de hoofdrepository jouw wijzigingen op ieder moment binnen kan halen. Bijdragers hoeven niet te wachten tot het project hun bijdragen invoegt - iedere partij kan op zijn eigen tempo werken. +Dit is een veel voorkomende workflow bij websites zoals GitHub, waarbij het eenvoudig is om een project af te splitsen (fork) en je wijzigingen te pushen in jouw afgesplitste project waar iedereen ze kan zien. Een van de grote voordelen van deze aanpak is dat je door kunt gaan met werken, en de eigenaar van de hoofdrepository jouw wijzigingen op ieder moment kan pullen. Bijdragers hoeven niet te wachten tot het project hun bijdragen invoegt - iedere partij kan op zijn eigen tempo werken. -### Dictator en luitenanten werkwijze ### +### Dictator en luitenanten workflow ### -Dit is een variant op de multi-repository werkwijze. Het wordt over het algemeen gebruikt bij enorme grote projecten met honderden bijdragers; een bekend voorbeeld is de Linux-kernel. Een aantal integrators geven de leiding over bepaalde delen van het repository, zij worden luitenanten genoemd. Alle luitenanten hebben één integrator die bekend staat als de welwillende dictator. De repository van de welwillende dictator dient als het referentierepository vanwaar alle bijdragers dienen binnen te halen. Het proces werkt als volgt (zie Figuur 5-3): +Dit is een variant op de multi-repository workflow. Het wordt over het algemeen gebruikt bij enorme grote projecten met honderden bijdragers; een bekend voorbeeld is de Linux-kernel. Een aantal integrators geven de leiding over bepaalde delen van de repository, zij worden luitenanten genoemd. Alle luitenanten hebben één integrator die bekend staat als de welwillende dictator. De repository van de welwillende dictator dient als het referentierepository vanwaar alle bijdragers dienen binnen te halen. Het proces werkt als volgt (zie Figuur 5-3): 1. Reguliere ontwikkelaars werken op hun eigen onderwerp (topic) branch en rebasen hun werk op de master. De masterbranch is die van de dictator. 2. Luitenanten mergen de topic branches van de ontwikkelaars in hun masterbranch. 3. De dictator merged de masterbranches van de luitenanten in de masterbranch van de dictator. -4. De dictator pushed zijn masterbranch terug naar het referentierepository zodat de andere ontwikkelaars kunnen rebasen. +4. De dictator pusht zijn masterbranch terug naar het referentierepository zodat de andere ontwikkelaars kunnen rebasen. Insert 18333fig0503.png Figuur 5-3. Welwillende-dictatorwerkwijze. Deze manier van werken is niet gewoon, maar kan handig zijn in hele grote projecten of in zeer hiërarchische omgevingen, omdat het de projectleider (de dictator) in staat stelt om het meeste werk te delegeren en grote subsets van code te verzamelen op meerdere punten alvorens ze te integreren. -Dit zijn veel voorkomende werkwijzen die mogelijk zijn met een gedistribueerd systeem als Git, maar je kunt zien dat er veel variaties mogelijk zijn om ze te laten passen bij jouw specifieke werkwijze. Nu dat je (naar ik hoop) in staat bent om te bepalen welke combinatie van werkwijzen voor jou werkt, zal ik wat specifiekere voorbeelden behandelen over hoe je de belangrijkste rollen kunt vervullen, die in de verschillende werkwijzen voorkomen. +Dit zijn veel voorkomende workflows die mogelijk zijn met een gedistribueerd systeem als Git, maar je kunt zien dat er veel variaties mogelijk zijn om ze te laten passen bij jouw specifieke workflow. Nu dat je (naar ik hoop) in staat bent om te bepalen welke combinatie van workflows voor jou werkt, zal ik wat specifiekere voorbeelden behandelen hoe je de belangrijkste rollen kunt vervullen die in de verschillende workflows voorkomen. ## Bijdragen aan een project ## -Je weet wat de verschillende werkwijzen zijn, en je zou het fundamentele gebruik van Git in de vingers moeten hebben. In dit gedeelte zul je leren over een aantal voorkomende patronen voor het bijdragen aan een project. +Je weet wat de verschillende workflows zijn, en je zou het fundamentele gebruik van Git in de vingers moeten hebben. In dit gedeelte zul je leren over een aantal voorkomende patronen voor het bijdragen aan een project. -De grote moeilijkheid bij het beschrijven van dit proces is dat er een enorm aantal variaties mogelijk zijn in hoe het gebeurt. Om dat Git erg flexibel is, kunnen en zullen mensen op vele manieren samenwerken, en het is lastig om te beschrijven hoe je zou moeten bijdragen aan een project - ieder project is een beetje anders. Een aantal van de betrokken variabelen zijn de grote van actieve bijdragen, gekozen werkwijze, je commit toegang, een mogelijk de manier waarop externe bijdragen worden gedaan. +De grote moeilijkheid bij het beschrijven van dit proces is dat er een enorm aantal variaties mogelijk zijn in hoe het gebeurt. Om dat Git erg flexibel is, kunnen en zullen mensen op vele manieren samenwerken, en het is lastig om te beschrijven hoe je zou moeten bijdragen aan een project - ieder project is een beetje anders. Een aantal van de betrokken variabelen zijn de grote van actieve bijdragen, gekozen workflow, je commit toegang, en mogelijk de manier waarop externe bijdragen worden gedaan. -De eerste variabele is de grootte van actieve bijdrage. Hoeveel gebruikers dragen actief code bij aan dit project, en hoe vaak? In veel gevallen zul je twee of drie ontwikkelaars met een paar commits per dag hebben, of misschien minder voor wat meer slapende projecten. Voor zeer grote bedrijven of projecten kan het aantal ontwikkelaars in de duizenden lopen, met tientallen of zelfs honderden patches die iedere dag binnenkomen. Dit is belangrijk omdat met meer en meer ontwikkelaars, je meer en meer problemen tegenkomt met het zeker zijn dat code netjes gepatched of eenvoudig gemerged kan worden. Wijzigingen die je indient kunnen verouderd of zwaar beschadigd raken door werk dat gemerged is terwijl je er aan het werken was of terwijl je wijzigingen in de wacht stonden voor goedkeuring of toepassing. Hoe kun je je code consequent bij de tijd en je patches geldig houden? +De eerste variabele is de grootte van actieve bijdrage. Hoeveel gebruikers dragen actief code bij aan dit project, en hoe vaak? In veel gevallen zal je twee of drie ontwikkelaars met een paar commits per dag hebben, of misschien minder voor wat meer slapende projecten. Voor zeer grote bedrijven of projecten kan het aantal ontwikkelaars in de duizenden lopen, met tientallen of zelfs honderden patches die iedere dag binnenkomen. Dit is belangrijk omdat met meer en meer ontwikkelaars, je meer en meer problemen tegenkomt bij het je verzekeren dat code netjes gepatched of eenvoudig gemerged kan worden. Wijzigingen die je indient kunnen verouderd of zwaar beschadigd raken door werk dat gemerged is terwijl je ermee aan het werken was, of terwijl je wijzigingen in de wacht stonden voor goedkeuring of toepassing. Hoe kun je jouw code consequent bij de tijd en je patches geldig houden? -De volgende variabele is de gebruikte werkwijze in het project. Is het gecentraliseerd, waarbij iedere ontwikkelaar gelijkwaardige schrijftoegang heeft tot de hoofd codebasis? Heeft het project een eigenaar of integrator die alle patches controleert? Worden alle patches gereviewed en goedgekeurd? Ben jij betrokken bij dat proces? Is er een luitenanten systeem neergezet, en moet je je werk eerst bij hen inleveren? +De volgende variabele is de gebruikte workflow in het project. Is het gecentraliseerd, waarbij iedere ontwikkelaar gelijkwaardige schrijftoegang heeft tot de hoofd codebasis? Heeft het project een eigenaar of integrator die alle patches controleert? Worden alle patches gereviewed en goedgekeurd? Ben jij betrokken bij dat proces? Is er een luitenanten systeem neergezet, en moet je je werk eerst bij hen inleveren? -Het volgende probleem is je commit toegang. De benodigde werkwijze om bij te dragen aan een project is heel verschillend als je schrijftoegang hebt tot het project dan wanneer je dat niet hebt. Als je geen schrijftoegang hebt, wat heeft de voorkeur van het project om bijdragen te ontvangen? Is er wel een beleid? Hoeveel werk draag je per keer bij? Hoe vaak draag je bij? +Het volgende probleem is je commit toegang. De benodigde workflow om bij te dragen aan een project is heel verschillend als je schrijftoegang hebt tot het project dan wanneer je dat niet hebt. Als je geen schrijftoegang hebt, wat is de voorkeur van het project om bijdragen te ontvangen? Is er überhaupt een beleid? Hoeveel werk draag je per keer bij? Hoe vaak draag je bij? -Al deze vragen kunnen van invloed zijn op hoe je effectief bijdraagt aan een project en welke werkwijzen de voorkeur hebben of die beschikbaar zijn voor je. Ik zal een aantal van deze aspecten behandelen in een aantal voorbeelden, waarbij ik van eenvoudig tot complex zal gaan; je zou in staat moeten zijn om de specifieke werkwijzen die je in de praktijk hebt te kunnen herleiden vanuit deze voorbeelden. +Al deze vragen kunnen van invloed zijn op hoe je effectief bijdraagt aan een project en welke workflows de voorkeur hebben of die beschikbaar zijn voor je. Ik zal een aantal van deze aspecten behandelen in een aantal voorbeelden, waarbij ik van eenvoudig tot complex zal gaan. Je zou in staat moeten zijn om de specifieke workflows die je in jouw praktijk nodig hebt te kunnen herleiden vanuit deze voorbeelden. ### Commit richtlijnen ### @@ -80,11 +115,11 @@ Als eerste wil je geen witruimte fouten indienen. Git geeft je een eenvoudige ma lib/simplegit.rb:26: trailing whitespace. + def command(git_cmd)XXXX -Als je dat commando uitvoert alvorens te committen, kun je al zien of je op het punt staat witruimte problemen te committen die waaraan andere ontwikkelaars zich zullen ergeren. +Als je dat commando uitvoert alvorens te committen, kun je al zien of je op het punt staat witruimte problemen te committen waaraan andere ontwikkelaars zich zullen ergeren. -Probeer vervolgens om van elke commit een logische set wijzigingen te maken. Probeer, als het je lukt, om je wijzigingen verteerbaar te maken - ga niet het hele weekend zitten coderen op vijf verschillende problemen om dat vervolgens op maandag als een gigantische commit in te dienen. Zelfs als je gedurende het weekend niet commit, gebruik dan het staging gebied op maandag om je werk in ten minste één commit per probleem op te splitsen, met een bruikbaar bericht per commit. Als een paar van de wijzigingen één bestand veranderen, probeer dan `git add --patch` te gebruiken om bestanden gedeeltelijk te stagen (wordt in detail behandeld in Hoofdstuk 6). De laatste snapshot van het project is gelijk of je nu één commit doet of vijf, zolang alle wijzigingen op een gegeven momment maar toegevoegd zijn, dus probeer om het je mede-ontwikkelaars makkelijk te maken als ze je wijzigingen moeten bekijken. Deze aanpak maakt het ook makkelijker om één wijziging te pullen of terug te draaien, mocht dat later nodig zijn. Hoofdstuk 6 beschrijft een aantal handige Git trucs om geschiedenis te herschrijven en bestanden interactief te stagen - gebruik deze gereedschappen een schone en begrijpelijke historie te helpen op te bouwen. +Probeer vervolgens om van elke commit een logische set wijzigingen te maken. Probeer, als het je lukt, om je wijzigingen verteerbaar te maken - ga niet het hele weekend zitten coderen op vijf verschillende problemen om dat vervolgens op maandag als een gigantische commit in te dienen. Zelfs als je gedurende het weekend niet commit, gebruik dan het staging gebied op maandag om je werk in ten minste één commit per probleem op te splitsen, met een bruikbaar bericht per commit. Als een paar van de wijzigingen één bestand veranderen, probeer dan `git add --patch` te gebruiken om bestanden gedeeltelijk te stagen (wordt in detail behandeld in Hoofdstuk 6). De snapshot aan de kop van het project is gelijk of je nu één commit doet of vijf, zolang alle wijzigingen op een gegeven moment maar toegevoegd zijn, dus probeer om het je mede-ontwikkelaars makkelijk te maken als ze je wijzigingen moeten bekijken. Deze aanpak maakt het ook makkelijker om één wijziging eruit te selecteren of terug te draaien, mocht dat later nodig zijn. Hoofdstuk 6 beschrijft een aantal handige Git trucs om geschiedenis te herschrijven en bestanden interactief te stagen - gebruik deze gereedschappen als hulp om een schone en begrijpelijke historie op te bouwen. -Het laatste om in gedachten te houden is het commit bericht. Als je er een gewoonte van maakt om een goede kwaliteit commit berichten aan te maken, dan maakt dat het gebruik van en samenwerken in Git een stuk eenvoudiger. In het algemeen, zouden je berichten moeten beginnen met een enkele regel, die niet langer is dan 50 karakters en die de wijzigingen beknopt omschrijft, gevolgd door een lege regel en daarna een meer gedetailleerde uitleg. Het Git project vereist dat de meer gedetailleerde omschrijving ook je motivatie voor de verandering bevat, en de nieuwe implementatie tegen het oude gedrag afzet. Dit is een goede richtlijn om te volgen. Het is ook een goed idee om de gebiedende wijs te gebruiken in deze berichten. Met andere woorden, gebruik commando's. In plaats van "Ik heb testen toegevoegd voor" of "Testen toegevoegd voor" gebruik je "Voeg testen toe voor". +Het laatste om in gedachten te houden is het commit bericht. Als je er een gewoonte van maakt om een goede kwaliteit commit berichten aan te maken, dan maakt dat het gebruik van en samenwerken in Git een stuk eenvoudiger. In het algemeen zouden je berichten moeten beginnen met een enkele regel die niet langer is dan 50 karakters en die de wijzigingen beknopt omschrijft, gevolgd door een lege regel en daarna een meer gedetailleerde uitleg. Het Git project vereist dat de meer gedetailleerde omschrijving ook je motivatie voor de verandering bevat, en de nieuwe implementatie tegen het oude gedrag afzet. Dit is een goede richtlijn om te volgen. Het is ook een goed idee om de gebiedende wijs te gebruiken in deze berichten. Met andere woorden, gebruik commando's. In plaats van "Ik heb testen toegevoegd voor" of "Testen toegevoegd voor" gebruik je "Voeg testen toe voor". Hier is een sjabloon dat origineel geschreven is door Tim Pope op tpope.net: Kort (50 karakters of minder) samenvatting van wijzigingen @@ -111,10 +146,10 @@ In de volgende voorbeelden, en verder door de rest van dit boek, zal ik omwille ### Besloten klein team ### -De eenvoudigste opzet die je waarschijnlijk zult tegenkomen is een besloten project met één of twee andere ontwikkelaars. Met besloten bedoel ik gesloten broncode - zonder leestoegang voor de buitenwereld. Jij en de andere ontwikkelaars hebben allemaal push toegang op het repository. +De eenvoudigste opzet die je waarschijnlijk zult tegenkomen is een besloten project met één of twee andere ontwikkelaars. Met besloten bedoel ik gesloten broncode - zonder leestoegang voor de buitenwereld. Jij en de andere ontwikkelaars hebben allemaal push toegang op de repository. -In deze omgeving kun je een werkwijze aanhouden die vergelijkbaar is met wat je zou doen als je Subversion of een andere gecentraliseerd systeem zou gebruiken. Je hebt nog steeds de voordelen van zaken als offline committen en veel eenvoudiger branchen en mergen, maar de werkwijze kan erg vergelijkbaar zijn. Het grote verschil is dat het mergen aan de client-kant gebeurt tijdens het committen in plaats van aan de server-kant. -Laten we eens kijken hoe het er uit zou kunnen zien als twee ontwikkelaars samen beginnen te werken met een gedeelde repository. De eerste ontwikkelaar, John, kloont de repository, maakt een wijziging, en commit lokaal. (Ik vervang de protocol berichten met `...` in deze voorbeelden om ze iets in te korten.) +In deze omgeving kan je een workflow aanhouden die vergelijkbaar is met wat je zou doen als je Subversion of een andere gecentraliseerd systeem zou gebruiken. Je hebt nog steeds de voordelen van zaken als offline committen en veel eenvoudiger branchen en mergen, maar de workflow kan erg vergelijkbaar zijn. Het grootste verschil is dat het mergen aan de client-kant gebeurt tijdens het committen in plaats van aan de server-kant. +Laten we eens kijken hoe het er uit zou kunnen zien als twee ontwikkelaars samen beginnen te werken met een gedeelde repository. De eerste ontwikkelaar, John, cloned de repository, maakt een wijziging, en commit lokaal. (Ik vervang de protocol berichten met `...` in deze voorbeelden om ze iets in te korten.) # John's Machine $ git clone john@githost:simplegit.git @@ -126,7 +161,7 @@ Laten we eens kijken hoe het er uit zou kunnen zien als twee ontwikkelaars samen [master 738ee87] removed invalid default value 1 files changed, 1 insertions(+), 1 deletions(-) -De tweede ontwikkelaar, Jessica, doet hetzelfde - kloont de repository en commit een wijziging: +De tweede ontwikkelaar, Jessica, doet hetzelfde - cloned de repository en commit een wijziging: # Jessica's Machine $ git clone jessica@githost:simplegit.git @@ -138,7 +173,7 @@ De tweede ontwikkelaar, Jessica, doet hetzelfde - kloont de repository en commit [master fbff5bc] add reset task 1 files changed, 1 insertions(+), 0 deletions(-) -Nu pushed Jessica haar werk naar de server: +Nu pusht Jessica haar werk naar de server: # Jessica's Machine $ git push origin master @@ -154,7 +189,7 @@ John probeert ook zijn werk te pushen: ! [rejected] master -> master (non-fast forward) error: failed to push some refs to 'john@githost:simplegit.git' -John mag niet pushen omdat Jessica in de tussentijd gepushed heeft. Dit is belangrijk om te begrijpen als je gewend bent aan Subversion, omdat het je zal opvallen dat de twee ontwikkelaars niet hetzelfde bestand hebben aangepast. Waar Subversion automatisch zo'n merge op de server doet, als verschillende bestanden zijn aangepast, moet je in Git de commits lokaal mergen. John moet Jessica's wijzigingen ophalen (fetch) en ze mergen voor hij mag pushen: +John mag niet pushen omdat Jessica in de tussentijd gepusht heeft. Dit is belangrijk om te begrijpen als je gewend bent aan Subversion, omdat het je zal opvallen dat de twee ontwikkelaars niet hetzelfde bestand hebben aangepast. Waar Subversion automatisch zo'n merge op de server doet als verschillende bestanden zijn aangepast, moet je in Git de commits lokaal mergen. John moet Jessica's wijzigingen ophalen (fetch) en ze mergen voor hij mag pushen: $ git fetch origin ... @@ -166,7 +201,7 @@ Hierna ziet John's lokale repository er ongeveer uit zoals Figuur 5-4. Insert 18333fig0504.png Figuur 5-4. John's initiële repository. -John heeft een referentie naar de wijzigingen die Jessica gepushed heeft, maar hij moet ze mergen met zijn eigen werk voordat hij het mag pushen: +John heeft een referentie naar de wijzigingen die Jessica gepusht heeft, maar hij moet ze mergen met zijn eigen werk voordat hij het mag pushen: $ git merge origin/master Merge made by recursive. @@ -176,9 +211,9 @@ John heeft een referentie naar de wijzigingen die Jessica gepushed heeft, maar h Het mergen gaat soepeltjes - de commit historie van John ziet er nu uit als Figuur 5-5. Insert 18333fig0505.png -Figuur 5-5. John's repository na het mergen van origin/master. +Figuur 5-5. John's repository na het mergen van `origin/master`. -Nu kan John zijn code testen om er zeker van te zijn dat het nog steeds goed werkt, en dan kan hij zijn nieuwe gemergede werk pushen naar de server: +Nu kan John zijn code testen om er zeker van te zijn dat alles nog steeds goed werkt, en dan kan hij zijn nieuwe gemergede werk pushen naar de server: $ git push origin master ... @@ -188,7 +223,7 @@ Nu kan John zijn code testen om er zeker van te zijn dat het nog steeds goed wer Tenslotte ziet John's commit historie eruit als Figuur 5-6. Insert 18333fig0506.png -Figuur 5-6. John's historie na gepushed te hebben naar de origin van de server. +Figuur 5-6. John's historie na gepusht te hebben naar de origin server. In de tussentijd heeft Jessica gewerkt op een topic branch. Ze heeft een topic branch genaamd `issue54` aangemaakt en daar drie commits op gedaan. Ze heeft John's wijzigingen nog niet opgehaald, dus haar commit historie ziet er uit als Figuur 5-7. @@ -203,10 +238,10 @@ Jessica wil met John synchroniseren, dus ze haalt de wijzigingen op: From jessica@githost:simplegit fbff5bc..72bbc59 master -> origin/master -Dit haalt het werk op dat John in de tussentijd gepushed heeft. Jessica's historie ziet er nu uit als Figuur 5-8. +Dit haalt het werk op dat John in de tussentijd gepusht heeft. Jessica's historie ziet er nu uit als Figuur 5-8. Insert 18333fig0508.png -Figuur 5-8. Jessica's historie na het ophalen van John's wijzigingen. +Figuur 5-8. Jessica's historie na het fetchen van John's wijzigingen. Jessica denkt dat haar topic branch nu klaar is, maar ze wil weten wat ze in haar werk moet mergen zodat ze kan pushen. Ze voert `git log` uit om dat uit te zoeken: @@ -223,7 +258,7 @@ Nu kan Jessica het werk van haar onderwerp mergen in haar `master` branch, John' Switched to branch "master" Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded. -Ze kan of `origin/master` of `issue54` als eerste samenvoegen - ze zijn beide stroomopwaarts dus de volgorde maakt niet uit. Op het eind zou de snapshot gelijk moeten zijn ongeacht welke volgorde ze kiest; alleen de geschiedenis zal iets verschillen. Ze kiest ervoor om `issue54` eerst samen te voegen: +Ze kan `origin/master` of `issue54` als eerste mergen - ze zijn beide stroomopwaarts dus de volgorde maakt niet uit. Uiteindelijk zou de snapshot gelijk moeten zijn ongeacht welke volgorde ze kiest; alleen de geschiedenis zal iets verschillen. Ze kiest ervoor om `issue54` eerst samen te voegen: $ git merge issue54 Updating fbff5bc..4af4298 @@ -245,7 +280,7 @@ Alles merged netjes, en Jessica's historie ziet er uit als Figuur 5-9. Insert 18333fig0509.png Figuur 5-9. Jessica's historie na het mergen van John's wijzigingen. -Nu is `origin/master` bereikbaar vanuit Jessica's `master` branch, dus ze zou in staat moeten zijn om succesvol te pushen (even aangenomen dat John in de tussentijd niets gepushed heeft): +Nu is `origin/master` bereikbaar vanuit Jessica's `master` branch, dus ze zou in staat moeten zijn om succesvol te pushen (even aangenomen dat John in de tussentijd niets gepusht heeft): $ git push origin master ... @@ -257,18 +292,18 @@ Iedere ontwikkelaar heeft een paar keer gecommit en elkaars werk succesvol samen Insert 18333fig0510.png Figuur 5-10. Jessica's historie na alle wijzigingen teruggezet te hebben op de server. -Dit is één van de eenvoudigste werkwijzen. Je werkt een tijdje, over het algemeen in een topic branch, en merged in je `master` branch als het klaar is om te worden geïntegreerd. Als je dat werk wilt delen, dan merge je het in je eigen `master` branch, en vervolgens fetch je `origin/master` en merge je deze als het gewijzigd is, en als laatste push je deze naar de `master` branch op de server. De algemene volgorde is zoiets als die getoond in Figuur 5-11. +Dit is één van de eenvoudigste workflows. Je werkt een tijdje, over het algemeen in een topic branch, en merged dit in je `master` branch als het klaar is om te worden geïntegreerd. Als je dat werk wilt delen, dan merge je het in je eigen `master` branch, en vervolgens fetch je `origin/master` en merge je deze als het gewijzigd is, en als laatste push je deze naar de `master` branch op de server. De algemene volgorde is zoiets als die getoond in Figuur 5-11. Insert 18333fig0511.png -Figuur 5-11. Algemene volgorde van gebeurtenissen voor een eenvoudige multi-ontwikkelaar Git werkwijze. +Figuur 5-11. Algemene volgorde van gebeurtenissen voor een eenvoudige multi-ontwikkelaar Git workflow. ### Besloten aangestuurd team ### -In het volgende scenario zul je kijken naar de rol van de bijdragers in een grotere besloten groep. Je zult leren hoe te werken in een omgeving waar kleine groepen samenwerken aan functies, waarna die team-gebaseerde bijdragen worden ge�ntegreerd door een andere partij. +In het volgende scenario zul je kijken naar de rol van de bijdragers in een grotere besloten groep. Je zult leren hoe te werken in een omgeving waar kleine groepen samenwerken aan functies, waarna die team-gebaseerde bijdragen worden geïntegreerd door een andere partij. -Stel dat John en Jessica samen werken aan een functie, terwijl Jessica en Josie aan een tweede aan het werken zijn. In dit geval gebruikt het bedrijf een integratie-manager achtige werkwijze, waarbij het werk van de individuele groepen alleen wordt geïntegreerd door bepaalde ontwikkelaars, en de `master` branch van het hoofd repo alleen kan worden vernieuwd door die ontwikkelaars. In dit scenario wordt al het werk gedaan in team-gebaseerde branches en later door de integrators samengevoegd. +Stel dat John en Jessica samen werken aan een functie, terwijl Jessica en Josie aan een tweede aan het werken zijn. In dit geval gebruikt het bedrijf een integratie-manager achtige workflow, waarbij het werk van de individuele groepen alleen wordt geïntegreerd door bepaalde ontwikkelaars, en de `master` branch van het hoofd repo alleen kan worden vernieuwd door die ontwikkelaars. In dit scenario wordt al het werk gedaan in team-gebaseerde branches en later door de integrators samengevoegd. -Laten we Jessica's werkwijze volgen terwijl ze aan haar twee functies werkt, in parallel met twee verschillende ontwikkelaars in deze omgeving. We nemen even aand dat ze haar repository al gekloond heeft, en dat ze besloten heeft als eerste te werken aan `featureA`. Ze maakt een nieuwe branch aan voor de functie en doet daar wat werk: +Laten we Jessica's workflow volgen terwijl ze aan haar twee features werkt, in parallel met twee verschillende ontwikkelaars in deze omgeving. We nemen even aan dat ze haar repository al gecloned heeft, en dat ze besloten heeft als eerste te werken aan `featureA`. Ze maakt een nieuwe branch aan voor de functie en doet daar wat werk: # Jessica's Machine $ git checkout -b featureA @@ -278,14 +313,14 @@ Laten we Jessica's werkwijze volgen terwijl ze aan haar twee functies werkt, in [featureA 3300904] add limit to log function 1 files changed, 1 insertions(+), 1 deletions(-) -Op dit punt, moet ze haar werk delen met John, dus ze pushed haar commits naar de `featureA` branch op de server. Jessica heeft geen push toegang op de `master` branch - alleen de integratoren hebben dat - dus ze moet naar een andere branch pushen om samen te kunnen werken met John: +Op dit punt, moet ze haar werk delen met John, dus ze pusht haar commits naar de `featureA` branch op de server. Jessica heeft geen push toegang op de `master` branch - alleen de integratoren hebben dat - dus ze moet naar een andere branch pushen om samen te kunnen werken met John: $ git push origin featureA ... To jessica@githost:simplegit.git * [new branch] featureA -> featureA -Jessica mailt John om hem te zeggen dat ze wat werk gepushed heeft in een branch genaamd `featureA` en dat hij er nu naar kan kijken. Terwijl ze op terugkoppeling van John wacht, besluit Jessica te beginnen met het werken aan `featureB` met Josie. Om te beginnen start ze een nieuwe functie branch, gebaseerd op de `master` branch van de server: +Jessica mailt John om hem te zeggen dat ze wat werk gepusht heeft in een branch genaamd `featureA` en dat hij er nu naar kan kijken. Terwijl ze op terugkoppeling van John wacht, besluit Jessica te beginnen met het werken aan `featureB` met Josie. Om te beginnen start ze een nieuwe functie branch, gebaseerd op de `master` branch van de server: # Jessica's Machine $ git fetch origin @@ -308,7 +343,7 @@ Jessica's repository ziet eruit als Figuur 5-12. Insert 18333fig0512.png Figuur 5-12. Jessica's initiële commit historie. -Ze is klaar om haar werk te pushen, maar ze krijgt een mail van Josie dat een branch met wat initieel werk erin al gepushed is naar de server in de `featureBee` branch. Jessica moet die wijzigingen eerst mergen met die van haar voordat ze kan pushen naar de server. Ze kan dan Josie's wijzigingen ophalen met `git fetch`: +Ze is klaar om haar werk te pushen, maar ze krijgt een mail van Josie dat een branch met wat initieel werk erin al gepusht is naar de server in de `featureBee` branch. Jessica moet die wijzigingen eerst mergen met die van haar voordat ze kan pushen naar de server. Ze kan dan Josie's wijzigingen ophalen met `git fetch`: $ git fetch origin ... @@ -323,7 +358,7 @@ Jessica kan dit nu mergen in het werk wat zij gedaan heeft met `git merge`: lib/simplegit.rb | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) -Er is wel een klein probleempje - ze moet het gemergde werk in haar `featureB` branch naar de `featureBee` branch op de server zetten. Ze kan dat doen door de lokale branch te specificeren aan het `git push` commando, gevolgd door een dubbele punt (:), gevolgd door de remote branch: +Er is wel een klein probleempje - ze moet het gemergde werk in haar `featureB` branch naar de `featureBee` branch op de server zetten. Ze kan dat doen door de lokale branch door te geven aan het `git push` commando, gevolgd door een dubbele punt (:), gevolgd door de remote branch: $ git push origin featureB:featureBee ... @@ -332,7 +367,7 @@ Er is wel een klein probleempje - ze moet het gemergde werk in haar `featureB` b Dit wordt een _refspec_ genoemd. Zie Hoofdstuk 9 voor een gedetailleerdere behandeling van Git refspecs en de verschillende dingen die je daarmee kan doen. -Vervolgens mailt John naar Jessica om te zeggen dat hij wat wijzigingen naar de `featureA` branch gepushed heeft, en om haar te vragen die te verifiëren. Ze voert een `git fetch` uit om die wijzigingen op te halen: +Vervolgens mailt John naar Jessica om te zeggen dat hij wat wijzigingen naar de `featureA` branch gepusht heeft, en om haar te vragen die te verifiëren. Ze voert een `git fetch` uit om die wijzigingen op te halen: $ git fetch origin ... @@ -358,7 +393,7 @@ Uiteindelijk merged ze John's werk in haar eigen `featureA` branch: lib/simplegit.rb | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) -Jessica wil iets kleins wijzigen, dus doet ze nog een commit en pushed dit naar de server: +Jessica wil iets kleins wijzigen, dus doet ze nog een commit en pusht dit naar de server: $ git commit -am 'small tweak' [featureA ed774b3] small tweak @@ -371,24 +406,24 @@ Jessica wil iets kleins wijzigen, dus doet ze nog een commit en pushed dit naar Jessica's commit historie ziet er nu uit zoals Figuur 5-13. Insert 18333fig0513.png -Figuur 5-13. Jessica's historie na het committen op een functie branch. +Figuur 5-13. Jessica's historie na het committen op een feature branch. -Jessica, Josie en John informeren de integrators nu dat de `featureA` en `featureBee` branches op de server klaar zijn voor integratie in de hoofdlijn. Nadat zij die branches in de hoofdlijn ge�ntegreerd hebben, zal een fetch de nieuwe merge commits ophalen, waardoor de commit historie er uit ziet zoals Figuur 5-14. +Jessica, Josie en John informeren de integrators nu dat de `featureA` en `featureBee` branches op de server klaar zijn voor integratie in de hoofdlijn. Nadat zij die branches in de hoofdlijn geïntegreerd hebben, zal een fetch de nieuwe merge commits ophalen, waardoor de commit historie er uit ziet zoals Figuur 5-14. Insert 18333fig0514.png -Figuur 5-14. Jessica's historie na het samenvoegen van allebei haar onderwerp branches. +Figuur 5-14. Jessica's historie na het mergen van allebei haar onderwerp branches. -Veel groepen schakelen om naar Git juist vanwege de mogelijkheid om meerdere teams in parallel te kunnen laten werken, waarbij de verschillende lijnen van werk laat in het proces gemerged worden. De mogelijkheid van kleinere subgroepen of een team om samen te werken via remote branches zonder het hele team erin te betrekken of te hinderen is een enorm voordeel van Git. De volgorde van de werkwijze die je hier zag is ongeveer zoals Figuur 5-15. +Veel groepen schakelen om naar Git juist vanwege de mogelijkheid om meerdere teams in parallel te kunnen laten werken, waarbij de verschillende lijnen van werk laat in het proces gemerged worden. De mogelijkheid van kleinere subgroepen of een team om samen te werken via remote branches zonder het hele team erin te betrekken of te hinderen is een enorm voordeel van Git. De volgorde van de workflow die je hier zag is ongeveer zoals Figuur 5-15. Insert 18333fig0515.png -Figuur 5-15. Eenvoudige volgorde in de werkwijze van dit aangestuurde team. +Figuur 5-15. Eenvoudige volgorde in de workflow van dit aangestuurde team. ### Klein openbaar project ### Het bijdragen aan openbare, of publieke, projecten gaat op een iets andere manier. Omdat je niet de toestemming hebt om de branches van het project rechtstreeks te updaten, moet je het werk op een andere manier naar de beheerders krijgen. Dit eerste voorbeeld beschrijft het bijdragen via afsplitsen (forken) op Git hosts die het eenvoudig aanmaken van forks ondersteunen. De repo.or.cz en GitHub hosting sites ondersteunen dit beide, en veel project beheerders verwachten deze manier van bijdragen. De volgende paragraaf behandelt projecten die de voorkeur hebben om bijdragen in de vorm van patches via e-mail te ontvangen. -Eerst zal je waarschijnlijk de hoofdrepository klonen, een topic branch maken voor de patch of reeks patches die je van plan bent bij te dragen, en je werk daarop doen. De te volgen stappen zien er zo uit: +Eerst zal je waarschijnlijk de hoofdrepository clonen, een topic branch maken voor de patch of reeks patches die je van plan bent bij te dragen, en je werk daarop doen. De te volgen stappen zien er zo uit: $ git clone (url) $ cd project @@ -404,13 +439,13 @@ Als je werk op de branch af is, en je klaar bent om het over te dragen aan de be $ git remote add myfork (url) -Je moet je werk daar naartoe pushen. Het is het makkelijkst om de remote branch waar je op zit te werken te pushen naar je repository, in plaats van het samenvoegen in je master branch en die te pushen. De reden hiervan is, dat als het werk niet wordt geaccepteerd of alleen ge-cherry picked (deels overgenomen), je jouw master branch niet hoeft terug te draaien. Als de beheerders je werk mergen, rebasen of cherry picken, dan krijg je het uiteindelijk toch binnen door hun repository te pullen: +Je wilt je werk daar naartoe pushen. Het is het makkelijkst om de remote branch waar je op zit te werken te pushen naar je repository, in plaats van het te mergen in je master branch en die te pushen. De reden hiervan is, dat als het werk niet wordt geaccepteerd of alleen ge-cherry picked (deels overgenomen), je jouw master branch niet hoeft terug te draaien. Als de beheerders je werk mergen, rebasen of cherry picken, dan krijg je het uiteindelijk toch binnen door hun repository te pullen: $ git push myfork featureA -Als jouw werk gepushed is naar jouw fork, dan moet je de beheerder inlichten. Dit wordt een pull request (haal-binnen-verzoek) genoemd, en je kunt deze via de website genereren - GitHub heeft een "pull request" knop die de beheerder automatisch een bericht stuurt - of het `git request-pull` commando uitvoeren en de uitvoer handmatig naar de projectbeheerder mailen. +Als jouw werk gepusht is naar jouw fork, dan moet je de beheerder inlichten. Dit wordt een pull request (haal-binnen-verzoek) genoemd, en je kunt deze via de website genereren - GitHub heeft een "pull request" knop die de beheerder automatisch een bericht stuurt - of het `git request-pull` commando uitvoeren en de uitvoer handmatig naar de projectbeheerder mailen. -Het `request-pull` commando neemt de basis branch waarin je de topic branch gepulled wil hebben, en de URL van de Git repository waar je ze uit wil laten pullen, en maakt een samenvatting van alle wijzigingen die je gepulled wenst te hebben. Bijvoorbeeld, als Jessica John een pull request wil sturen, en ze heeft twee commits gedaan op de topic branch die ze zojuist gepushed heeft, dan kan ze dit uitvoeren: +Het `request-pull` commando neemt de basis branch waarin je de topic branch gepulled wil hebben, en de URL van de Git repository waar je ze uit wil laten pullen, en maakt een samenvatting van alle wijzigingen die je gepulled wenst te hebben. Bijvoorbeeld, als Jessica John een pull request wil sturen, en ze heeft twee commits gedaan op de topic branch die ze zojuist gepusht heeft, dan kan ze dit uitvoeren: $ git request-pull origin/master myfork The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40: @@ -428,9 +463,9 @@ Het `request-pull` commando neemt de basis branch waarin je de topic branch gepu lib/simplegit.rb | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) -De uitvoer kan naar de beheerders gestuurd worden: het verteld ze waar het werk vanaf gebranched is, vat de commits samen en verteld waar vandaan ze dit werk kunnen pullen. +De uitvoer kan naar de beheerders gestuurd worden: het vertelt ze waar het werk vanaf gebranched is, vat de commits samen en vertelt waar vandaan ze dit werk kunnen pullen. -Bij een project waarvan je niet de beheerder bent, is het over het algemeen eenvoudiger om een branch zoals `master` altijd de `origin/master` te laten volgen, en je werk te doen in topic branches die je eenvoudig weg kunt gooien als ze geweigerd worden. Als je je werkthema's gescheiden houdt in topic branches maakt dat het ook eenvoudiger voor jou om je werk te rebasen als de punt van het hoofd repository in de tussentijd verschoven is en je commits niet langer netjes toegepast kunnen worden. Bijvoorbeeld, als je een tweede onderwerp wilt bijdragen aan een project, ga dan niet verder werken op de topic branch die je zojuist gepushed hebt - begin opnieuw vanaf de `master` branch van het hoofd repository: +Bij een project waarvan je niet de beheerder bent, is het over het algemeen eenvoudiger om een branch zoals `master` altijd de `origin/master` te laten tracken, en je werk te doen in topic branches die je eenvoudig weg kunt gooien als ze geweigerd worden. Als je je werkthema's gescheiden houdt in topic branches maakt dat het ook eenvoudiger voor jou om je werk te rebasen als de punt van de hoofd-repository in de tussentijd verschoven is en je commits niet langer netjes toegepast kunnen worden. Bijvoorbeeld, als je een tweede onderwerp wilt bijdragen aan een project, ga dan niet verder werken op de topic branch die je zojuist gepusht hebt - begin opnieuw vanaf de `master` branch van het hoofd repository: $ git checkout -b featureB origin/master $ (work) @@ -439,12 +474,12 @@ Bij een project waarvan je niet de beheerder bent, is het over het algemeen eenv $ (email maintainer) $ git fetch origin -Nu zijn al je onderwerpen opgeslagen in een silo - vergelijkbaar met een patch reeks (queue) - die je kunt herschrijven, rebasen en wijzigen zonder dat de onderwerpen elkaar be�nvloeden of van elkaar afhankelijk zijn zoals in Figuur 5-16. +Nu zijn al je onderwerpen opgeslagen in een silo - vergelijkbaar met een patch reeks (queue) - die je kunt herschrijven, rebasen en wijzigen zonder dat de onderwerpen elkaar beïnvloeden of van elkaar afhankelijk zijn zoals in Figuur 5-16. Insert 18333fig0516.png Figuur 5-16. Initiële commit historie met werk van featureB. -Stel dat de project beheerder een verzameling andere patches binnengehaald heeft en jouw eerste branch geprobeerd heeft, maar dat die niet meer netjes merged. In dat geval kun je proberen die branch te rebasen op de punt van `origin/master`, de conflicten op te lossen voor de beheerder, en dan je wijzigingen opnieuw aanbieden: +Stel dat de project-beheerder een verzameling andere patches binnengehaald heeft en jouw eerste branch geprobeerd heeft, maar dat die niet meer netjes merged. In dat geval kun je proberen die branch te rebasen op `origin/master`, de conflicten op te lossen voor de beheerder, en dan je wijzigingen opnieuw aanbieden: $ git checkout featureA $ git rebase origin/master @@ -457,7 +492,7 @@ Figuur 5-17. Commit historie na werk van featureA. Omdat je de branch gerebased hebt, moet je de `-f` specificeren met je push commando om in staat te zijn de `featureA` branch op de server te vervangen met een commit die er geen afstammeling van is. Een alternatief zou zijn dit nieuwe werk naar een andere branch op de server te pushen (misschien `featureAv2` genaamd). -Laten we eens kijken naar nog een mogelijk scenario: de beheerder heeft je werk bekeken in je tweede branch en vind het concept goed, maar zou willen dat je een implementatie detail verandert. Je moet deze gelegenheid meteen gebruiken om het werk te baseren op de huidige `master` branch van het project. Je begint een nieuwe branch gebaseerd op de huidige `origin/master` branch, squashed de `featureB` wijzigingen er naartoe, lost conflicten op, doet de implementatie wijziging en pushed deze terug als een nieuwe branch: +Laten we eens kijken naar nog een mogelijk scenario: de beheerder heeft je werk bekeken in je tweede branch en vind het concept goed, maar zou willen dat je een implementatie detail verandert. Je moet deze gelegenheid meteen gebruiken om het werk te baseren op de huidige `master` branch van het project. Je begint een nieuwe branch gebaseerd op de huidige `origin/master` branch, squashed de `featureB` wijzigingen er naartoe, lost conflicten op, doet de implementatie wijziging en pusht deze terug als een nieuwe branch: $ git checkout -b featureBv2 origin/master $ git merge --no-commit --squash featureB @@ -467,16 +502,16 @@ Laten we eens kijken naar nog een mogelijk scenario: de beheerder heeft je werk De `--squash` optie pakt al het werk op de gemergde branch en perst dat samen in één non-merge commit bovenop de branch waar je op zit. De `--no-commit` optie vertelt Git dat hij niet automatisch een commit moet doen. Dit stelt je in staat om alle wijzigingen van een andere branch te introduceren en dan meer wijzigingen te doen, alvorens de nieuwe commit te doen. -Nu kun je de beheerder een bericht sturen dat je de gevraagde wijzigingen gemaakt hebt en dat ze die wijzigingen kunnen vinden in je `featureBv2` branch (zie Figuur 5-18). +Je kunt de beheerder nu een bericht sturen dat je de gevraagde wijzigingen gemaakt hebt en dat ze die wijzigingen kunnen vinden in je `featureBv2` branch (zie Figuur 5-18). Insert 18333fig0518.png Figuur 5-18. Commit historie na het featureBv2 werk. ### Openbaar groot project ### -Veel grote projecten hebben vastgestelde procedures voor het accepteren van patches - je zult de specifieke regels voor ieder project goed moeten bekijken, omdat ze verschillend zullen zijn. Veel grote projecten accepteren patches veelal via ontwikkelaar maillijsten, daarom zal ik zo'n voorbeeld nu laten zien. +Veel grote projecten hebben vastgestelde procedures voor het accepteren van patches - je zult de specifieke regels voor ieder project goed moeten bekijken, omdat ze verschillend zullen zijn. Veel grote projecten accepteren patches veelal via ontwikkelaar-maillijsten, daarom zal ik zo'n voorbeeld nu laten zien. -De werkwijze is vergelijkbaar met het vorige geval - je maakt topic branches voor iedere patch waar je aan werkt. Het verschil is hoe je die aanlevert bij het project. In plaats van het project te forken en naar je eigen schrijfbare versie te pushen, genereer je e-mail versies van iedere reeks commits en mailt die naar de ontwikkelaar maillijst: +De workflow is vergelijkbaar met het vorige geval - je maakt topic branches voor iedere patch waar je aan werkt. Het verschil is hoe je die aanlevert bij het project. In plaats van het project te forken en naar je eigen schrijfbare versie te pushen, genereer je e-mail versies van iedere reeks commits en mailt die naar de ontwikkelaar-maillijst: $ git checkout -b topicA $ (work) @@ -484,7 +519,7 @@ De werkwijze is vergelijkbaar met het vorige geval - je maakt topic branches voo $ (work) $ git commit -Nu heb je twee commits die je wil sturen naar de maillijst. Je gebruikt `git format-patch` om de mbox-geformatteerde bestanden te genereren die je kunt mailen naar de lijst. Dit vormt iedere commit om naar een e-mail bericht met de eerste regel van het commit bericht als de onderwerp regel, en de rest van het bericht plus de patch die door de commit wordt ge�ntroduceerd als de inhoud. Het prettige hieraan is dat met het toepassen van een patch uit een mail die gegenereerd is met `format-patch` alle commit informatie blijft behouden. In de volgende paragraaf zal je hiervan meer zien, als je deze commits gaat toepassen: +Nu heb je twee commits die je wil sturen naar de maillijst. Je gebruikt `git format-patch` om de mbox-geformatteerde bestanden te genereren die je kunt mailen naar de lijst. Dit vormt iedere commit om naar een e-mail bericht met de eerste regel van het commit bericht als het onderwerp, en de rest van het bericht plus de patch die door de commit wordt geïntroduceerd als de inhoud. Het prettige hieraan is dat met het toepassen van een patch uit een mail die gegenereerd is met `format-patch` alle commit informatie blijft behouden. In de volgende paragraaf zal je hiervan meer zien, als je deze commits gaat toepassen: $ git format-patch -M origin/master 0001-add-limit-to-log-function.patch @@ -520,9 +555,9 @@ Het `format-patch` commando drukt de namen af van de patch bestanden die het maa -- 1.6.2.rc1.20.g8c5b.dirty -Je kunt deze patch bestanden ook aanpassen om meer informatie, die je niet in het commit bericht wil laten verschijnen, voor de maillijst toe te voegen . Als je tekst toevoegt tussen de `---` regel en het begin van de patch (de `lib/simplegit.rb` regel), dan kunnen ontwikkelaars dit lezen, maar tijdens het toepassen van de patch wordt dit weggelaten. +Je kunt deze patch bestanden ook aanpassen om meer informatie, die je niet in het commit bericht wilt laten verschijnen, voor de maillijst toe te voegen . Als je tekst toevoegt tussen de `---` regel en het begin van de patch (de `lib/simplegit.rb` regel), dan kunnen ontwikkelaars dit lezen, maar tijdens het toepassen van de patch wordt dit weggelaten. -Om dit te mailen naar een maillijst, kun je het bestand in je mail applicatie plakken of het sturen via een commandoregel programma. Het plakken van de tekst veroorzaakt vaak formaterings problemen, in het bijzonder bij "slimmere" clients die de newlines en andere witruimte niet juist behouden. Gelukkig levert Git een gereedschap die je helpt om juist geformatteerde patches via IMAP te versturen, wat het alweer een stuk makkelijker voor je maakt. Ik zal zal je laten zien hoe je een patch via Gmail stuurt, wat de mail applicatie is die ik toevallig gebruik. Je kunt gedetailleerde instructies voor een aantal mail programma's vinden aan het eind van het voornoemde `Documentation/SubmittingPatches` bestand in de Git broncode. +Om dit te mailen naar een maillijst, kan je het bestand in je mail-applicatie plakken of het sturen via een commandoregel programma. Het plakken van de tekst veroorzaakt vaak formaterings problemen, in het bijzonder bij "slimmere" clients die de newlines en andere witruimte niet juist behouden. Gelukkig levert Git een gereedschap die je helpt om juist geformatteerde patches via IMAP te versturen, wat het alweer een stuk makkelijker voor je maakt. Ik zal zal je laten zien hoe je een patch via Gmail stuurt, wat de mail-applicatie is die ik toevallig gebruik. Je kunt gedetailleerde instructies voor een aantal mail programma's vinden aan het eind van het voornoemde `Documentation/SubmittingPatches` bestand in de Git broncode. Eerst moet je de imap sectie in je `~/.gitconfig` bestand instellen. Je kunt iedere waarde apart instellen met een serie `git config` commando's, of je kunt ze handmatig toevoegen, maar uiteindelijk moet je config bestand er ongeveer zo uitzien: @@ -544,7 +579,7 @@ Als dat ingesteld is, kun je `git send-email` gebruiken om de patch reeks in de sending 2 messages 100% (2/2) done -Nu kan je naar die Drafts folder gaan, het To veld te wijzigen naar de maillijst waar je de patch naartoe stuurt en misschien de beheerder of verantwoordelijke voor dat deel in de CC zetten en dan versturen. +Nu kan je naar jouw Drafts folder gaan, het To veld wijzigen naar de maillijst waar je de patch naartoe stuurt en misschien de beheerder of verantwoordelijke voor dat deel in de CC zetten en dan versturen. Je kunt de patches ook via een SMTP server sturen. Zoals eerder kan je elke waarde apart instellen met een serie `git config` commando's, of je kunt ze handmatig in de sendmail sectie in je `~/.gitconfig` bestand zetten: @@ -554,7 +589,7 @@ Je kunt de patches ook via een SMTP server sturen. Zoals eerder kan je elke waar smtpuser = user@gmail.com smtpserverport = 587 -Als dit gebeurd is, kan je `git send-email` gebruiken om je patches te sturen: +Als dit gedaan is, kan je `git send-email` gebruiken om je patches te sturen: $ git send-email *.patch 0001-added-limit-to-log-function.patch @@ -583,7 +618,7 @@ Dan spuuwt Git een bergje log-informatie uit voor elke patch die je stuurt, wat ### Samenvatting ### -In dit hoofdstuk is een aantal veel voorkomende werkwijzen behandeld, die je kunt gebruiken om te kunnen werken in een aantal zeer verschillende typen Git projecten die je misschien zult tegenkomen, en een aantal nieuwe gereedschappen geïntroduceerd die je helpen om dit proces te beheren. Wat hierna volgt zal je laten zien hoe je aan de andere kant van de tafel werkt: een Git project beheren. Je zult leren hoe een welwillende dictator of integratie manager te zijn. +In dit hoofdstuk is een aantal veel voorkomende workflows behandeld, die je kunt gebruiken om te kunnen werken in een aantal zeer verschillende typen Git projecten die je misschien zult tegenkomen. En er zijn een aantal nieuwe gereedschappen geïntroduceerd die je helpen om dit proces te beheren. Wat hierna volgt zal je laten zien hoe je aan de andere kant van de tafel werkt: een Git project beheren. Je zult leren hoe een welwillende dictator of integratie manager te zijn. ## Het beheren van een project ## @@ -591,7 +626,7 @@ Naast weten hoe effectief bij te dragen aan een project, moet je waarschijnlijk ### Werken in topic branches ### -Als je overweegt om nieuw werk te integreren, is het over het algemeen een goed idee om het uit te proberen in een topic branch - een tijdelijke branch, speciaal gemaakt om dat nieuwe werk uit te proberen. Op deze manier is het handig om een patch individueel te behandelen en het even opzij te zetten als het niet werkt, totdat je tijd hebt om er op terug te komen. Als je een eenvoudige branchnaam maakt, gebaseerd op het onderwerp van het werk dat je aan het proberen bent, bijvoorbeeld `ruby_client` of zoiets beschrijvends, dan is het makkelijk om te herinneren als je het voor een tijdje opzij moet leggen en er later op terug komt. De beheerder van het Git project heeft de neiging om deze branches ook van een naamsruimte (namespace) te voorzien - zoals `sc/ruby_client`, waarbij `sc` een afkorting is van de persoon die het werk heeft bijgedragen. +Als je overweegt om nieuw werk te integreren, is het over het algemeen een goed idee om het uit te proberen in een topic branch - een tijdelijke branch, speciaal gemaakt om dat nieuwe werk uit te proberen. Op deze manier is het handig om een patch individueel te behandelen en het even opzij te zetten als het niet werkt, totdat je tijd hebt om er op terug te komen. Als je een eenvoudige branchnaam maakt, gebaseerd op het onderwerp van het werk dat je aan het proberen bent, bijvoorbeeld `ruby_client` of zoiets beschrijvends, dan is het makkelijk om te herinneren als je het voor een tijdje opzij legt en er later op terug komt. De beheerder van het Git project heeft de neiging om deze branches ook van een naamsruimte (namespace) te voorzien - zoals `sc/ruby_client`, waarbij `sc` een afkorting is van de persoon die het werk heeft bijgedragen. Zoals je je zult herinneren, kun je de branch gebaseerd op je master branch zo maken: $ git branch sc/ruby_client master @@ -604,7 +639,7 @@ Nu ben je klaar om het bijgedragen werk in deze topic branch toe te voegen, en t ### Patches uit e-mail toepassen ### -Als je een patch per e-mail ontvangt, en je moet die integreren in je project, moet je de patch in je topic branch toepassen om het te evalueren. Er zijn twee manieren om een ge-mailde patch toe te passen: met `git apply` of met `git am`. +Als je een patch per e-mail ontvangt, en je moet die integreren in je project, moet je de patch in je topic branch toepassen om het te evalueren. Er zijn twee manieren om een gemailde patch toe te passen: met `git apply` of met `git am`. #### Een patch toepassen met apply #### @@ -612,7 +647,7 @@ Als je de patch ontvangen hebt van iemand die het gegenereerd heeft met de `git $ git apply /tmp/patch-ruby-client.patch -Dit wijzigt de bestanden in je werk directory. Het is vrijwel gelijk aan het uitvoeren van een `patch -p1` commando om de patch toe te passen, alhoewel het meer paranoïde is en minder "fuzzy matches" accepteert dan patch. Het handelt ook bestandstoevoegingen af, -verwijderingen, en hernoemingen als ze beschreven staan in het `git diff` formaat, wat `patch` niet doet. Als laatste volgt `git apply` een "pas alles toe of laat alles weg" model waarbij alles of niets wordt toegepast. Dit in tegenstelling tot `patch` die gedeeltelijke patches kan toepassen, waardoor je werk directory in een vreemde status achterblijft. Over het algemeen is `git apply` meer paranoïde dan `patch`. Het zal geen commit voor je aanmaken; na het uitvoeren moet je de geïntroduceerde wijzigingen handmatig stagen en committen. +Dit wijzigt de bestanden in je werk directory. Het is vrijwel gelijk aan het uitvoeren van een `patch -p1` commando om de patch toe te passen, alhoewel het meer paranoïde is en minder "fuzzy matches" accepteert dan patch. Het handelt ook het toevoegen, verwijderen, en hernoemen van bestanden af als ze beschreven staan in het `git diff` formaat, wat `patch` niet doet. Als laatste volgt `git apply` een "pas alles toe of laat alles weg" model waarbij alles of niets wordt toegepast. Dit in tegenstelling tot `patch` die gedeeltelijke patches kan toepassen, waardoor je werkdirectory in een vreemde status achterblijft. Over het algemeen is `git apply` meer paranoïde dan `patch`. Het zal geen commit voor je aanmaken: na het uitvoeren moet je de geïntroduceerde wijzigingen handmatig stagen en committen. Je kunt ook git apply gebruiken om te zien of een patch netjes kan worden toepast voordat je het echt doet; je kunt `git apply --check` uitvoeren met de patch: @@ -637,7 +672,7 @@ Om een patch gegenereerd met `format-patch` toe te passen, gebruik je `git am`. Dit is het begin van de uitvoer van het format-patch commando dat je gezien hebt in de vorige paragraaf. Dit is ook een geldig mbox e-mail formaat. Als iemand jou de patch correct gemaild heeft door gebruik te maken van git send-email en je downloadt dat in een mbox formaat, dan kan je het git am naar dat mbox bestand verwijzen, en het zal beginnen met alle patches die het tegenkomt toe te passen. Als je een mail client gebruikt die meerdere e-mails kan opslaan in mbox formaat, dan kun je hele reeksen patches in een bestand opslaan en dan git am gebruiken om ze één voor één toe te passen. -Maar, als iemand een patch bestand heeft ge�pload die gegenereerd is met `format-patch` naar een ticket systeem of zoiets, kun je het bestand lokaal opslaan en dan dat opgeslagen bestand aan `git am` doorgeven om het toe te passen: +Maar, als iemand een patch bestand heeft geüpload die gegenereerd is met `format-patch` naar een ticket systeem of zoiets, kun je het bestand lokaal opslaan en dan dat opgeslagen bestand aan `git am` doorgeven om het te applyen: $ git am 0001-limit-log-function.patch Applying: add limit to log function @@ -655,7 +690,7 @@ Je ziet dat het netjes is toegepast, en automatisch een nieuwe commit voor je he Limit log functionality to the first 20 -De `Commit` informatie toont de persoon die de patch toepaste en de tijd waarop het is toegepast. De `Author` informatie de persoon die de patch oorspronkelijk gemaakt heeft en wanneer het gemaakt is. +De `Commit` informatie toont de persoon die de patch toegepast heeft en de tijd waarop het is toegepast. De `Author` informatie de persoon die de patch oorspronkelijk gemaakt heeft en wanneer het gemaakt is. Maar het is mogelijk dat de patch niet netjes toegepast kan worden. Misschien is jouw hoofdbranch te ver afgeweken van de branch waarop de patch gebouwd is, of is de patch afhankelijk van een andere patch, die je nog niet hebt toegepast. In dat geval zal het `git am` proces falen en je vragen wat je wilt doen: @@ -675,7 +710,7 @@ Dit commando zet conflict markeringen in alle bestanden waar het problemen mee h $ git am --resolved Applying: seeing if this helps the gem -Als je wil dat Git iets meer intelligentie toepast om het conflict op te lossen, kun je een `-3` optie eraan meegeven, dit zorgt ervoor dat Git een driewegs-merge probeert. Deze optie staat standaard niet aan omdat het niet werkt als de commit waarvan de patch zegt dat het op gebaseerd is niet in je repository zit. Als je die commit wel hebt - als de patch gebaseerd was op een publieke commit - dan is de `-3` over het algemeen veel slimmer in het toepassen van een conflicterende patch: +Als je wilt dat Git iets meer intelligentie toepast om het conflict op te lossen, kun je een `-3` optie eraan meegeven, dit zorgt ervoor dat Git een driewegs-merge probeert. Deze optie staat standaard niet aan omdat het niet werkt als de commit waarvan de patch zegt dat het op gebaseerd is niet in je repository zit. Als je die commit wel hebt - als de patch gebaseerd was op een publieke commit - dan is de `-3` over het algemeen veel slimmer in het toepassen van een conflicterende patch: $ git am -3 0001-seeing-if-this-helps-the-gem.patch Applying: seeing if this helps the gem @@ -685,9 +720,9 @@ Als je wil dat Git iets meer intelligentie toepast om het conflict op te lossen, Falling back to patching base and 3-way merge... No changes -- Patch already applied. -In dit geval, probeerde ik een patch toe te passen die ik al eerder toegepast had. Zonder de `-3` optie ziet het eruit als een conflict. +In dit geval, probeerde ik een patch te applyen die ik al eerder toegepast had. Zonder de `-3` optie ziet het eruit als een conflict. -Als je een aantal patches van een mbox toepast, kun je ook het `am` commando in een interactieve modus uitvoeren, wat bij iedere patch die het vind stopt en je vraagt of je het wilt toepassen: +Als je een aantal patches van een mbox toepast, kun je ook het `am` commando in een interactieve modus uitvoeren, wat bij iedere patch die het vind stopt en je vraagt of je het wilt applyen: $ git am -3 -i mbox Commit Body is: @@ -696,13 +731,13 @@ Als je een aantal patches van een mbox toepast, kun je ook het `am` commando in -------------------------- Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all -Dit is prettig als je een aantal patches bewaard hebt, omdat je de patch eerst kunt zien als je je niet kunt herinneren wat het is, of de patch niet wilt toepassen omdat je dat al eerder gedaan hebt. +Dit is prettig als je een aantal patches bewaard hebt, omdat je de patch eerst kunt zien als je niet kunt herinneren wat het is, of de patch niet wilt toepassen omdat je dat al eerder gedaan hebt. Als alle patches voor je topic branch zijn toegepast en gecommit zijn op je branch, kan je besluiten of en hoe ze te integreren in een branch met een langere looptijd. ### Remote branches uitchecken ### -Als je bijdrage van een Git gebruiker komt die zijn eigen repository opgezet heeft, een aantal patches daarin gepushed heeft, en jou de URL naar de repository gestuurd heeft en de naam van de remote branch waarin de wijzigingen zitten, kan je ze toevoegen als een remote en het mergen lokaal doen. +Als je bijdrage van een Git gebruiker komt die zijn eigen repository opgezet heeft, een aantal patches daarin gepusht heeft, en jou de URL naar de repository gestuurd heeft en de naam van de remote branch waarin de wijzigingen zitten, kan je ze toevoegen als een remote en het mergen lokaal doen. Bijvoorbeeld, als Jessica je een e-mail stuurt waarin staat dat ze een prachtig mooie nieuwe feature in de `ruby-client` branch van haar repository heeft, kun je deze testen door de remote toe te voegen en die branch lokaal te bekijken: @@ -716,7 +751,7 @@ Dit is meest practisch als je vaak met een persoon werkt. Als iemand een enkele Het andere voordeel van deze aanpak is dat je de historie van de commits ook krijgt. Alhoewel je misschien terechte merge problemen hebt, weet je op welk punt in de historie hun werk is gebaseerd; een echte drieweg merge is de standaard in plaats van een `-3` te moeten meegeven en hopen dat de patch gegenereerd was van een publieke commit waar je toegang toe hebt. -Als je maar af en toe met een persoon werkt, maar toch op deze manier van hen wilt pullen, dan kun je de URL van de remote repository geven aan het `git pull` commando. Dit haalt eenmalig op en bewaart de URL niet als een remote referentie: +Als je maar af en toe met een persoon werkt, maar toch op deze manier van hen wilt pullen, dan kun je de URL van de remote repository geven aan het `git pull` commando. Dit doet een eenmalig pull en bewaart de URL niet als een remote referentie: $ git pull git://github.com/onetimeguy/project.git From git://github.com/onetimeguy/project @@ -725,7 +760,7 @@ Als je maar af en toe met een persoon werkt, maar toch op deze manier van hen wi ### Bepalen wat geïntroduceerd wordt ### -Je hebt een topic branch dat bijgedragen werk bevat. Nu kan je bepalen wat je er mee wilt doen. Deze paragraaf bekijkt een paar commando's nogmaals om te laten zien hoe je ze kunt gebruiken om precies te reviewen wat je zult introduceren als je dit merged in je hoofd branch. +Je hebt een topic branch dat bijgedragen werk bevat. Nu kan je besluiten wat je er mee wilt doen. Deze paragraaf behandelt een paar commando's nogmaals om te laten zien hoe je ze kunt gebruiken om precies te reviewen wat je zult introduceren als je dit merged in je hoofd branch. Het is vaak handig om een review te krijgen van alle commits die in deze branch zitten, maar die niet in je master branch zitten. Je kunt commits weglaten die al in de master branch zitten door de `--not` optie mee te geven voor de branch naam. Bijvoorbeeld, als je bijdrager je twee patches stuurt, je hebt een branch genaamd `contrib` gemaakt en hebt die patches daar toegepast, dan kun je dit uitvoeren: @@ -742,7 +777,7 @@ Het is vaak handig om een review te krijgen van alle commits die in deze branch updated the gemspec to hopefully work better -Om te zien welke wijzigingen door iedere commit worden geïntroduceerd, onthoud dan dat je de `-p` optie kunt meegeven aan `git log` en dan zal het de diff weergeven die bij iedere commit wordt geïntroduceerd. +Om te zien welke wijzigingen door een commit worden geïntroduceerd, onthoud dan dat je de `-p` optie kunt meegeven aan `git log` en dan zal het de geïntroduceerde diff erachter plakken bij iedere commit. Om een volledige diff te zien van wat zou gebeuren als je deze topic branch merged met een andere branch, zul je misschien een vreemde truc moeten toepassen om de juiste resultaten te krijgen. Je zult misschien denken om dit uit te voeren: @@ -764,15 +799,15 @@ Maar, dat is niet handig, dus levert Git een andere verkorte manier om hetzelfde $ git diff master...contrib -Dit commando laat alleen het werk zien dat je huidige topic branch heeft ge�ntroduceerd sinds de gezamenlijke voorouder met master. Dat is een erg handige syntax om te onthouden. +Dit commando laat alleen het werk zien dat je huidige topic branch heeft geïntroduceerd sinds de gezamenlijke voorouder met master. Dat is een erg handige syntax om te onthouden. ### Bijgedragen werk integreren ### -Als al het werk in je onderwerp branch klaar is om te worden geïntegreerd in een hogere branch, dan is de vraag hoe het te doen. En daarbij, welke werkwijze wil je gebruiken om je project te beheren? Je hebt een aantal keuzes, dus ik zal er een paar behandelen. +Als al het werk in je onderwerp branch klaar is om te worden geïntegreerd in een hogere branch, dan is de vraag hoe het te doen. En daarbij, welke workflow wil je gebruiken om je project te beheren? Je hebt een aantal keuzes, dus ik zal er een paar behandelen. -#### Merge werkwijzen #### +#### Mergende workflows #### -Een eenvoudige werkwijze merged je werk in de `master` branch. In dit scenario, heb je een `master` branch die feitelijk de stabiele code bevat. Als je werk in een topic branch hebt waaraan je gewerkt hebt, of dat iemand anders heeft bijgedragen en wat je hebt nagekeken, dan merge je het in de master branch, verwijdert de topic branch en vervolgt het proces. Als we een repository hebben met werk in twee branches genaamd `ruby_client` en `php_client`, wat eruit ziet zoals Figuur 5-19 en mergen eerst `ruby_client` en daarna `php_client`, dan zal je historie er uit gaan zien zoals in Figuur 5-20. +Een eenvoudige workflow merged je werk in de `master` branch. In dit scenario heb je een `master` branch die feitelijk de stabiele code bevat. Als je werk in een topic branch hebt waaraan je gewerkt hebt, of dat iemand anders heeft bijgedragen en je hebt dat nagekeken, dan merge je het in de master branch, verwijdert de topic branch en vervolgt het proces. Als we een repository hebben met werk in twee branches genaamd `ruby_client` en `php_client`, wat eruit ziet zoals Figuur 5-19 en mergen eerst `ruby_client` en daarna `php_client`, dan zal je historie er uit gaan zien zoals in Figuur 5-20. Insert 18333fig0519.png Figuur 5-19. Historie met een aantal topic branches. @@ -780,9 +815,9 @@ Figuur 5-19. Historie met een aantal topic branches. Insert 18333fig0520.png Figuur 5-20. Na het mergen van een topic branch. -Dat is waarschijnlijk de eenvoudigste werkwijze, maar het wordt problematisch als je werkt met grotere repositories of projecten. +Dat is waarschijnlijk de eenvoudigste workflow, maar het wordt problematisch als je werkt met grotere repositories of projecten. -Als je meer ontwikkelaars hebt of een groter project, dan zul je waarschijnlijk minstens een twee-fasen merge cyclus willen toepassen. In dat geval heb je twee langlopende branches, `master` en `develop`, waarbij je bepaalt dat `master` alleen vernieuwd wordt als een zeer stabiele release is gemaakt en alle nieuwe code geïntegreerd is in de `develop` branch. Je pushed beide branches op regelmatige basis naar de publieke repository. Iedere keer als je een nieuw topic branch hebt om te mergen (Figuur 5-21), merge je het in `develop` (Figuur 5-22). En als je een tag gemaakt heb van een release, doe je een fast-forward van `master` naar waar de nu stabiele `develop` branch is (Figuur 5-23). +Als je meer ontwikkelaars hebt of een groter project, dan zul je waarschijnlijk minstens een twee-fasen merge cyclus willen toepassen. In dat geval heb je twee langlopende branches, `master` en `develop`, waarbij je bepaalt dat `master` alleen vernieuwd wordt als een zeer stabiele release is gemaakt en alle nieuwe code geïntegreerd is in de `develop` branch. Je pusht beide branches op regelmatige basis naar de publieke repository. Iedere keer als je een nieuw topic branch hebt om te mergen (Figuur 5-21), merge je het in `develop` (Figuur 5-22). En als je een tag gemaakt heb van een release, doe je een fast-forward van `master` naar waar de nu stabiele `develop` branch is (Figuur 5-23). Insert 18333fig0521.png Figuur 5-21. Voor een merge van een topic branch. @@ -793,12 +828,12 @@ Figuur 5-22. Na een merge van een topic branch. Insert 18333fig0523.png Figuur 5-23. Na een release van een topic branch. -Op deze manier, als mensen de repository van je project klonen, dan kunnen ze kiezen om master uit checken en daarmee de laatste stabiele versie te bouwen en die eenvoudig up-to-date kunnen houden, of ze kunnen develop uit checken waar het nieuwere materiaal in staat. +Op deze manier, als mensen de repository van je project clonen, dan kunnen ze kiezen om master uit checken en daarmee de laatste stabiele versie te bouwen en die eenvoudig up-to-date te houden, of ze kunnen develop uit checken waar het nieuwere materiaal in staat. Je kunt dit concept ook verder doorvoeren, waarbij je een integratie branch hebt waar al het werk gemerged wordt. Als de codebasis op die branch stabiel is en de alle tests daar slagen, dan merge je het in een develop branch. Pas als het daar een periode stabiel is gebleken, dan fast-forward je de master branch. -#### Werkwijzen met grote merges #### +#### workflows met grote merges #### -Het Git project heeft vier langlopende branches: `master`, `next`, en `pu` (proposed updates, voorgestelde vernieuwingen) voor nieuw spul, en `maint` voor onderhoudswerk. Als nieuw werk wordt geïntroduceerd door bijdragers, wordt het samengeraapt in topic branches in de repository van de beheerder op een manier die lijkt op wat ik omschreven heb (zie Figuur 5-24). Hier worden de topics geëvalueerd om te bepalen of ze veilig zijn en klaar voor verdere verwerking of dat ze nog wat werk nodig hebben. Als ze veilig zijn, worden ze in `next` gemerged, en wordt die branch gepushed zodat iedereen de geïntegreerde topics kan uitproberen. +Het Git project heeft vier langlopende branches: `master`, `next`, en `pu` (proposed updates, voorgestelde vernieuwingen) voor nieuw spul, en `maint` voor onderhoudswerk (maintenance backports). Als nieuw werk wordt geïntroduceerd door bijdragers, wordt het samengeraapt in topic branches in de repository van de beheerder op een manier die lijkt op wat ik omschreven heb (zie Figuur 5-24). Hier worden de topics geëvalueerd om te bepalen of ze veilig zijn en klaar voor verdere verwerking of dat ze nog wat werk nodig hebben. Als ze veilig zijn, worden ze in `next` gemerged, en wordt die branch gepusht zodat iedereen de geïntegreerde topics kan uitproberen. Insert 18333fig0524.png Figuur 5-24. Een complexe serie van parallel bijgedragen topic branches beheren. @@ -808,9 +843,9 @@ Als de topics nog werk nodig hebben, dan worden ze in plaats daarvan gemerged in Insert 18333fig0525.png Figuur 5-25. Bijgedragen topic branches mergen in langlopende integratie branches. -Als een onderwerp branch uiteindelijk is gemerged in `master`, dan wordt het verwijderd van het repository. Het Git project heeft ook een `main` branch, die geforked is van de laatste release om teruggewerkte (backported) patches te leveren in het geval dat een onderhoudsrelease nodig is. Dus als je de Git repository kloont, dan heb je vier branches die je kunt uitchecken om het project in verschillende stadia van ontwikkeling te evalueren, afhankelijk van hoe nieuw je alles wilt hebben of hoe je wil bijdragen. En de beheerders hebben een gestructureerde werkwijze om ze te helpen nieuwe bijdragen aan de tand te voelen. +Als een onderwerp branch uiteindelijk is gemerged in `master`, dan wordt het verwijderd van de repository. Het Git project heeft ook een `maint` branch, die geforked is van de laatste release om teruggewerkte (backported) patches te leveren in het geval dat een onderhoudsrelease nodig is. Dus als je de Git repository cloned, dan heb je vier branches die je kunt uitchecken om het project in verschillende stadia van ontwikkeling te evalueren, afhankelijk van hoe nieuw je alles wilt hebben of hoe je wil bijdragen. En de beheerders hebben een gestructureerde workflow om ze te helpen nieuwe bijdragen aan de tand te voelen. -#### Rebasen en cherry pick werkwijzen #### +#### Rebasende en cherry pick workflows #### Andere beheerders geven de voorkeur aan rebasen of bijgedragen werk te cherry picken naar hun master branch in plaats van ze erin te mergen, om een vrijwel lineaire historie te behouden. Als je werk in een topic branch hebt en hebt besloten dat je het wil integreren, dan ga je naar die branch en voert het rebase commando uit om de wijzigingen op je huidige master branch te baseren (of `develop`, enzovoorts). Als dat goed werkt, dan kun je de `master` branch fast-forwarden, en eindig je met een lineaire project historie. @@ -835,14 +870,14 @@ Nu kun je de topic branch verwijderen en de commits die je niet wilde pullen weg ### Je releases taggen ### -Als je hebt besloten om een release te maken, zul je waarschijnlijk een tag willen aanmaken zodat je die release op elk moment in de toekomst kunt namaken. Je kunt een nieuwe tag maken zoals ik heb beschreven in Hoofdstuk 2. Als je besluit om de tag als de beheerder te signeren, dan ziet het taggen er misschien zo uit: +Als je hebt besloten om een release te maken, zul je waarschijnlijk een tag willen aanmaken zodat je die release op elk moment in de toekomst opnieuw kunt maken. Je kunt een nieuwe tag maken zoals ik heb beschreven in Hoofdstuk 2. Als je besluit om de tag als de beheerder te signeren, dan ziet het taggen er misschien zo uit: $ git tag -s v1.5 -m 'my signed 1.5 tag' You need a passphrase to unlock the secret key for user: "Scott Chacon " 1024-bit DSA key, ID F721C45A, created 2009-02-09 -Als je tags signeert, dan heb je misschien een problem om de publieke PGP sleutel, die gebruikt is om de tags te signeren, te distribueren. De beheerder van het Git project heeft dit probleem opgelost door hun publieke sleutel als een blob in het repository mee te nemen en een tag te maken die direct naar die inhoud wijst. Om dit te doen kun je uitvinden welke sleutel je wilt door `gpg --list-keys` uit te voeren: +Als je tags signeert, dan heb je misschien een problem om de publieke PGP sleutel, die gebruikt is om de tags te signeren, te distribueren. De beheerder van het Git project heeft dit probleem opgelost door hun publieke sleutel als een blob in de repository mee te nemen en een tag te maken die direct naar die inhoud wijst. Om dit te doen kun je uitvinden welke sleutel je wilt door `gpg --list-keys` uit te voeren: $ gpg --list-keys /Users/schacon/.gnupg/pubring.gpg @@ -856,7 +891,7 @@ Daarna kun je de sleutel direct in de Git database importeren, door het te expor $ gpg -a --export F721C45A | git hash-object -w --stdin 659ef797d181633c87ec71ac3f9ba29fe5775b92 -Nu dat je de inhoud van je sleutel in Git hebt, kun je een tag aanmaken die direct daar naar wijst door de nieuw SHA-1 waarde die het `hash-object` commando je gaf te specificeren: +Nu je de inhoud van je sleutel in Git hebt, kun je een tag aanmaken die direct daar naar wijst door de nieuw SHA-1 waarde die het `hash-object` commando je gaf te specificeren: $ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92 @@ -868,14 +903,14 @@ Ze kunnen die sleutel gebruiken om al je gesigneerde tags te verifiëren. Als je ### Een bouw nummer genereren ### -Omdat Git geen monotone oplopende nummers heeft zoals 'v123' of iets gelijkwaardigs om bij iedere commit mee te worden genomen, en je een voor mensen leesbare naam wilt hebben bij een commit, kan je `git describe` uitvoeren op die commit. Git geeft je de naam van de dichtstbijzijnde tag met het aantal commits achter die tag en een gedeeltelijke SHA-1 waarde van de commit die je omschrijft: +Omdat Git geen monotoon oplopende nummers heeft zoals 'v123' of iets gelijkwaardigs om bij iedere commit mee te worden genomen, en je een voor mensen leesbare naam wilt hebben bij een commit, kan je `git describe` uitvoeren op die commit. Git geeft je de naam van de dichtstbijzijnde tag met het aantal commits achter die tag en een gedeeltelijke SHA-1 waarde van de commit die je omschrijft: $ git describe master v1.6.2-rc1-20-g8c5b85c -Op deze manier kun je een snapshot of "build" exporteren en het vernoemen naar iets dat begrijpelijk is voor mensen. Sterker nog: als je Git, gekloond van het Git repository, vanaf broncode bouwt geeft `git --version` je iets dat er zo uitziet. Als je een commit omschrijft die je direct getagged hebt, dan krijg je de tag naam. +Op deze manier kun je een snapshot of "build" exporteren en het vernoemen naar iets dat begrijpelijk is voor mensen. Sterker nog: als je Git, gecloned van het Git repository, vanaf broncode gebouwd hebt geeft `git --version` je iets dat er zo uitziet. Als je een commit omschrijft die je direct getagged hebt, dan krijg je de tag naam. -Het `git describe` commando geeft beschreven tags de voorkeur (tags gemaakt met de `-a` of `-s` vlag), dus release tags moeten op deze manier aangemaakt worden als je `git describe` gebruikt, om er zeker van te zijn dat de commit juist benoemd wordt als het omschreven wordt. Je kunt deze tekst ook gebruiken als het doel van een checkout of show commando, alhoewel het afhankelijk is van de verkorte SHA-1 waarde aan het einde, dus het zou niet eeuwig geldig kunnen zijn. Bijvoorbeeld, de Linux kernel sprong recentelijk van 8 naar 10 karakters om er zeker van de zijn dat de SHA-1 uniek zijn, oudere `git describe` commando's werden daardoor ongeldig. +Het `git describe` commando geeft beschreven tags de voorkeur (tags gemaakt met de `-a` of `-s` vlag), dus release tags moeten op deze manier aangemaakt worden als je `git describe` gebruikt, om er zeker van te zijn dat de commit juist benoemd wordt als het omschreven wordt. Je kunt deze tekst ook gebruiken als het doel van een checkout of show commando, alhoewel het afhankelijk is van de verkorte SHA-1 waarde aan het einde, dus het zou niet eeuwig geldig kunnen zijn. Bijvoorbeeld, de Linux kernel sprong recentelijk van 8 naar 10 karakters om er zeker van de zijn dat de SHA-1 uniek zijn, oudere `git describe` commando uitvoernamen werden daardoor ongeldig. ### Een release voorbereiden ### @@ -914,4 +949,4 @@ Je krijgt een opgeschoonde samenvatting van alle commits sinds v1.0.1, gegroepee ## Samenvatting ## -Je zou je nu redelijk op je gemak moeten voelen om aan een project bij te dragen met Git, maar ook om je eigen project te beheren of de bijdragen van andere gebruikers te integreren. Gefeliciteerd, je bent nu een effectieve Git ontwikkelaar! In het volgende hoofdstuk zul je nog krachtigere tools en trucs leren voor het omgaan met complexe situaties, die je een echte Git meester zullen maken. +Je zou je nu redelijk op je gemak moeten voelen om aan een project bij te dragen met Git, maar ook om je eigen project te beheren of de bijdragen van andere gebruikers te integreren. Gefeliciteerd, je bent nu een effectieve Git ontwikkelaar! In het volgende hoofdstuk vindt je nog krachtigere tools en tips om met complexe situaties om te gaan, waarmee je een echte Git meester zullen worden. From c418e2ea78e789b5299a80352ad8fc2e1fc4461a Mon Sep 17 00:00:00 2001 From: Cor Date: Tue, 18 Feb 2014 10:06:34 +0100 Subject: [PATCH 026/478] [nl] Chapter 03 - Review and retranslate where necessary Retranslated chapter 03, brought command output in line with en version. Also corrected English base document to bring text in line with actual output shown. --- en/03-git-branching/01-chapter3.markdown | 2 +- nl/03-git-branching/01-chapter3.markdown | 277 +++++++++++++---------- 2 files changed, 154 insertions(+), 125 deletions(-) diff --git a/en/03-git-branching/01-chapter3.markdown b/en/03-git-branching/01-chapter3.markdown index 6dd13bc27..0ab31e938 100644 --- a/en/03-git-branching/01-chapter3.markdown +++ b/en/03-git-branching/01-chapter3.markdown @@ -276,7 +276,7 @@ If you want to use a graphical tool to resolve these issues, you can run `git me {remote}: modified file Hit return to start merge resolution tool (opendiff): -If you want to use a merge tool other than the default (Git chose `opendiff` for me in this case because I ran the command on a Mac), you can see all the supported tools listed at the top after “merge tool candidates”. Type the name of the tool you’d rather use. In Chapter 7, we’ll discuss how you can change this default value for your environment. +If you want to use a merge tool other than the default (Git chose `opendiff` for me in this case because I ran the command on a Mac), you can see all the supported tools listed at the top after “... one of the following tools:”. Type the name of the tool you’d rather use. In Chapter 7, we’ll discuss how you can change this default value for your environment. After you exit the merge tool, Git asks you if the merge was successful. If you tell the script that it was, it stages the file to mark it as resolved for you. diff --git a/nl/03-git-branching/01-chapter3.markdown b/nl/03-git-branching/01-chapter3.markdown index 7adb409d0..76fcb44e1 100644 --- a/nl/03-git-branching/01-chapter3.markdown +++ b/nl/03-git-branching/01-chapter3.markdown @@ -1,34 +1,56 @@ # Branchen in Git # Bijna elk versiebeheersysteem ondersteunt een bepaalde vorm van branchen. Branchen komt erop neer dat je een tak afsplitst van de hoofd ontwikkellijn en daar verder mee gaat werken zonder aan de hoofdlijn te komen. Bij veel VCS'en is dat nogal een duur proces, vaak wordt er een nieuwe kopie gemaakt van de directory waar je broncode in staan, wat lang kan duren voor grote projecten. -Sommige mensen verwijzen naar het branch model in Git als de "killer eigenschap", en het onderscheidt Git zeker in de VCS gemeenschap. Waarom is het zo bijzonder? De manier waarop Git brancht is ongelooflijk lichtgewicht, waardoor branch operaties vrijwel instant zijn en het wisselen tussen de branches over het algemeen net zo snel. In tegenstelling to vele andere VCS's, moedigt Git juist een workflow aan waarbij vaak gebranched en gemerged wordt, zelfs meerdere keren per dag. Deze eigenschap begrijpen en de techniek beheersen geeft je een krachtig en uniek gereedschap en kan letterlijk de manier waarop je ontwikkelt veranderen. +Sommige mensen verwijzen naar het branch model in Git als de "killer eigenschap", en het onderscheidt Git zeker in de VCS gemeenschap. Waarom is het zo bijzonder? De manier waarop Git brancht is ongelooflijk lichtgewicht, waardoor branch operaties vrijwel instant zijn en het wisselen tussen de branches over het algemeen net zo snel. In tegenstelling to vele andere VCS's, moedigt Git juist een workflow aan waarbij vaak gebrancht en gemerged wordt, zelfs meerdere keren per dag. Deze eigenschap begrijpen en de techniek beheersen geeft je een krachtig en uniek gereedschap en kan letterlijk de manier waarop je ontwikkelt veranderen. -## Wat een branch is ## +## Wat is een branch ## Om de manier waarop Git brancht echt te begrijpen, moeten we een stap terug doen en onderzoeken hoe Git zijn gegevens opslaat. Zoals je misschien herinnert van Hoofdstuk 1, slaat Git zijn gegevens niet op als een reeks van wijzigingen of delta's, maar in plaats daarvan als een serie snapshots. Als je in Git commit, dan slaat Git een commit object op dat een verwijzing bevat naar het snapshot van de inhoud die je gestaged hebt, de auteur en bericht metagegevens, en nul of meer verwijzingen naar de commit of commits die de directe ouders van deze commit waren: nul ouders voor de eerste commit, één ouder voor een normale commit, en meerdere ouders voor een commit die het resultaat is van een merge van twee of meer branches. -Om dit te visualiseren, gaan we aannemen dat je een directory hebt met drie bestanden, en je staged en commit ze allemaal. Door de bestanden te stagen krijgen ze allemaal een checksum (de SHA-1 hash waar we het in Hoofdstuk 1 over hadden), bewaart die versie van het bestand in het Git repository (Git noemt ze blobs), en voegt die checksum toe aan de staging area: +Om dit te visualiseren, gaan we aannemen dat je een directory hebt met drie bestanden, en je staged en commit ze allemaal. Je gaat de bestanden stagen waardoor ze allemaal een checksum krijgen (de SHA-1 hash waar we het in Hoofdstuk 1 over hadden), bewaart die versie van het bestand in het Git repository (Git noemt ze blobs), en voegt die checksum toe aan de staging area: $ git add README test.rb LICENSE $ git commit -m 'initial commit of my project' -Als je de commit aanmaakt door `git commit` uit te voeren zal Git iedere project directory van een checksum voorzien en slaat ze als boomstructuur (`tree`) objecten in de Git repository op. Daarna creëert Git een `commit` object dat de metagegevens bevat en een verwijzing naar de hoofd project `tree`-object zodat Git deze snapshot kan opnieuw kan oproepen als dat nodig is. +Als je de commit aanmaakt door `git commit` uit te voeren zal Git iedere directory in het project van een checksum voorzien en slaat ze als boomstructuur (`tree`) objecten in de Git repository op. Daarna creëert Git een `commit` object dat de metagegevens bevat en een verwijzing naar de hoofd `tree`-object van het project zodat Git deze snapshot kan opnieuw kan oproepen als dat nodig is. Je Git repository bevat nu vijf objecten: een blob voor de inhoud van ieder van de drie bestanden, een tree die de inhoud van de directory weergeeft en specificeert welke bestandsnamen opgeslagen zijn als welke blobs, en een commit met de verwijzing naar die hoofd-tree en alle commit metagegevens. Conceptueel zien de gegevens in je Git repository eruit zoals in Figuur 3-1. @@ -45,7 +67,7 @@ Een branch in Git is simpelweg een lichtgewicht verplaatsbare verwijzing naar ee Insert 18333fig0303.png Figuur 3-3. Branch wijzend in de commit gegevens historie. -Wat gebeurt er als je een nieuwe branch maakt? Door dat te doen wordt een nieuwe verwijzing voor jou aangemaakt die je dan kunt verplaatsen. Laten we zeggen dat je een nieuwe branch genaamd testing maakt. Je doet dit met het `git branch` commando: +Wat gebeurt er als je een nieuwe branch maakt? Door dat te doen wordt een nieuwe verwijzing voor je aangemaakt die je dan kunt verplaatsen. Laten we zeggen dat je een nieuwe branch genaamd testing maakt. Je doet dit met het `git branch` commando: $ git branch testing @@ -54,7 +76,7 @@ Dit maakt een nieuwe verwijzing naar dezelfde commit waar je nu op zit (zie Figu Insert 18333fig0304.png Figuur 3-4. Meerdere branches wijzend naar de commit gegevens historie. -Hoe weet Git op welke branch je nu zit? Het houdt een speciale verwijzing bij genaamd HEAD. Let op dat dit heel anders is dan het concept van HEAD in andere VCS's waar je misschien gewend aan bent, zoals Subversion of CVS. In Git is dit een verwijzing naar de lokale branch waar je nu op zit. In dit geval zit je nog steeds op master. Het git branch commando heeft alleen een nieuwe branch aangemaakt, we zijn nog niet overgeschakeld naar die branch (zie Figuur 3-5). +Hoe weet Git op welke branch je nu zit? Het houdt een speciale verwijzing bij genaamd HEAD. Let op dat dit heel anders is dan het concept van HEAD in andere VCS's waar je misschien gewend aan bent, zoals Subversion of CVS. In Git is dit een verwijzing naar de lokale branch waar je nu op zit. In dit geval zit je nog steeds op master. Het git branch commando heeft alleen een nieuwe branch aangemaakt - we zijn nog niet overgeschakeld naar die branch (zie Figuur 3-5). Insert 18333fig0305.png Figuur 3-5. HEAD bestand wijzend naar de branch waar je op zit. @@ -87,7 +109,7 @@ Figuur 3-8 toont het resultaat. Insert 18333fig0308.png Figuur 3-8. HEAD verschuift naar een andere branch bij een checkout. -Dat commando heeft twee dingen gedaan. Het verplaatste de HEAD verwijzing terug naar de `master` branch, en het draaide de bestanden in je werkdirectory terug naar het snapshot waar die `master` naar wijst. Dit betekent ook dat de wijzigingen die je vanaf dit punt maakt uiteen zullen gaan lopen met een oudere versie van het project. In essentie betekent dat het werk dat je in je testing branch hebt gedaan tijdelijk wordt teruggedraaid, zodat je een andere richting op kunt gaan. +Dat commando heeft twee dingen gedaan. Het verplaatste de HEAD verwijzing terug naar de `master` branch, en het draaide de bestanden in je werkdirectory terug naar de snapshot waar die `master` naar wijst. Dit betekent ook dat de wijzigingen die je vanaf dit punt maakt uiteen zullen gaan lopen met een oudere versie van het project. In essentie betekent het dat het werk dat je in je testing branch hebt gedaan tijdelijk wordt teruggedraaid, zodat je een andere richting op kunt gaan. Laten we een paar wijzigingen maken en nog eens committen: @@ -101,7 +123,7 @@ Figuur 3-9. De branch histories zijn uiteen gaan lopen. Omdat een branch in Git in feite een eenvoudig bestand is dat de 40 karakter lange SHA-1 checksum van de commit bevat waar het naar wijst, zijn branches goedkoop om te maken en weer weg te gooien. Een nieuwe branch aanmaken is zo snel en eenvoudig als 41 bytes naar een bestand schrijven (40 karakters en een harde return). -Dit is in scherp contrast met de wijze waarop de meeste VCS applicaties branchen, wat vaak het kopiëren van alle project bestanden naar een tweede map inhoudt. Dit kan enkele seconden of zelfs minuten duren, afhankelijk van de grootte van het project, daarentegen is het in Git altijd vrijwel meteen klaar. En omdat we de ouders opslaan terwijl we committen, wordt het vinden van een goed punt dat kan dienen als basis voor het mergen automatisch voor ons gedaan en is dat over het algemeen eenvoudig om te doen. Deze eigenschappen helpen ontwikkelaars aan te moedigen vaak branches aan te maken en te gebruiken. +Dit is in scherp contrast met de wijze waarop de meeste VCS applicaties branchen, wat vaak het kopiëren van alle project bestanden naar een tweede map inhoudt. Dit kan enkele seconden of zelfs minuten duren, afhankelijk van de grootte van het project, daarentegen is het in Git altijd vrijwel meteen klaar. En omdat we de ouders opslaan terwijl we committen, wordt het vinden van een goed punt dat kan dienen als basis voor het mergen automatisch voor ons gedaan en is dat over het algemeen eenvoudig om te doen. Deze eigenschappen moedigen ontwikkelaars aan om vaak branches aan te maken en te gebruiken. Laten we eens kijken waarom je dat zou moeten doen. @@ -122,15 +144,15 @@ Dan ontvang je een telefoontje dat je een ander probleem direct moet repareren. ### Eenvoudig branchen ### -Als eerste, laten we zeggen dat je aan je project werkt en al een paar commits hebt (zie Figuur 3-10). +Als eerste, laten we zeggen dat je aan je project werkt en al een paar commits hebt staan (zie Figuur 3-10). Insert 18333fig0310.png Figuur 3-10. Een korte en eenvoudige commit historie. -Je hebt besloten dan je gaat werken aan probleem #53 in wat voor systeem je bedrijf ook gebruikt om problemen te registreren. Voor de duidelijkheid: Git is niet verbonden met een probleem beheersysteem in het bijzonder. En omdat probleem #53 een specifiek onderwerp is waar je aan gaat werken, maak je een nieuwe branch aan waarin je aan de slag gaat. Om een branch aan te maken en er meteen naartoe te schakelen, kun je het `git checkout` commando uitvoeren met de `-b` optie: +Je hebt besloten dan je gaat werken aan probleem #53 in wat voor systeem je bedrijf ook gebruikt om problemen te registreren. Voor de duidelijkheid: Git is niet verbonden met een specifiek probleem beheersysteem. Omdat probleem #53 een onderwerp is waar je gericht aan gaat werken, maak je een nieuwe branch aan waarin je aan de slag gaat. Om een branch aan te maken en er meteen naartoe te schakelen, kun je het `git checkout` commando uitvoeren met de `-b` optie: $ git checkout -b iss53 - Switched to a new branch "iss53" + Switched to a new branch 'iss53' Dit is een afkorting voor: @@ -152,7 +174,7 @@ Figuur 3-12. De iss53 branch is vooruit gegaan met je werk. Nu krijg je het telefoontje dan er een probleem is met de web site, en je moet het meteen repareren. Met Git hoef je de reparatie niet tegelijk uit te leveren met de `iss53` wijzigingen die je gemaakt hebt, en je hoeft ook niet veel moeite te doen om die wijzigingen terug te draaien voordat je kunt werken aan het toepassen van je reparatie in productie. Het enige wat je moet doen in terugschakelen naar je master branch. -Maar voordat je dat doet, let op dat als je werk directory of staging area wijzigingen bevat die nog niet gecommit zijn en conflicteren met de branch die je gaat uitchecken, Git je niet laat om te schakelen. Het beste is om een schone werk status te hebben als je tussen branches gaat schakelen. Er zijn manieren om hier mee om te gaan (te weten, stashen en commit ammending) die we later gaan behandelen. Voor nu heb je alle wijzigingen gecommit, zodat je terug kunt schakelen naar je master branch: +Maar voordat je dat doet, merk op dat als je werk directory of staging area wijzigingen bevat die nog niet gecommit zijn en conflicteren met de branch die je gaat uitchecken, Git je niet laat om te schakelen. Het beste is om een schone werk status te hebben als je tussen branches gaat schakelen. Er zijn manieren om hier mee om te gaan (te weten, stashen en commit ammending) die we later gaan behandelen. Voor nu heb je alle wijzigingen gecommit, zodat je terug kunt schakelen naar je master branch: $ git checkout master Switched to branch "master" @@ -162,32 +184,32 @@ Hierna, is je project werk directory precies zoals het was voordat je begon te w Vervolgens heb je een snelle reparatie (hotfix) te doen. Laten we een reparatie branch maken om op te werken totdat het af is (zie Figuur 3-13): $ git checkout -b hotfix - Switched to a new branch "hotfix" + Switched to a new branch 'hotfix' $ vim index.html $ git commit -a -m 'fixed the broken email address' - [hotfix]: created 3a0874c: "fixed the broken email address" - 1 files changed, 0 insertions(+), 1 deletions(-) + [hotfix 3a0874c] fixed the broken email address + 1 files changed, 1 deletion(-) Insert 18333fig0313.png -Figuur 3-13. snelle reparatie branch gebaseerd op de tip van je master branch. +Figuur 3-13. snelle reparatie branch gebaseerd op de positie van je master branch. Je kunt je tests draaien, je erzelf van verzekeren dat de reparatie is wat je wil, en het mergen in je master branch en het naar productie uitrollen. Je doet dit met het `git merge` commando: $ git checkout master $ git merge hotfix Updating f42c576..3a0874c - Fast forward - README | 1 - - 1 files changed, 0 insertions(+), 1 deletions(-) + Fast-forward + README | 1 - + 1 file changed, 1 deletion(-) -Je zult de uitdrukking "Fast forward" zien in die merge. Omdat de commit van de branch waar je mee samenvoegde direct stroomopwaarts was van de commit waar je op zit, zal Git de verwijzing vooruit verplaatsen. Om het op een andere manier te zeggen, als je een commit probeert te mergen met een commit die bereikt kan worden door de historie van eerste commit te volgen, zal Git de dingen vereenvoudigen door de verwijzing vooruit te verplaatsen omdat er geen afwijkend werk is om rte mergen; dit wordt een "fast forward" genoemd. +Je zult de uitdrukking "Fast forward" zien in die merge. Omdat de commit van de branch waar je mee mergede direct stroomopwaarts is van de commit waar je op zit, zal Git de verwijzing vooruit verplaatsen. Om het op een andere manier te zeggen, als je een commit probeert te mergen met een commit die bereikt kan worden door de historie van eerste commit te volgen, zal Git de dingen vereenvoudigen door de verwijzing vooruit te verplaatsen omdat er geen afwijkend werk is om rte mergen; dit wordt een "fast forward" genoemd. Je wijziging zit nu in het snapshot van de commit waar de `master` branch naar wijst, en je kunt je wijziging uitrollen (zie Figuur 3-14). Insert 18333fig0314.png -Figuur 3-14. Je master branch wijst naar dezelfde plek als de snelle reparatie branch na de wijziging. +Figuur 3-14. Je master branch wijst na de merge naar dezelfde plek als de hotfix branch. -Nadat je super-belangrijke reparatie uitgerold is, ben je klaar om terug te schakelen naar het werk dat je deed voordat je onderbroken werd. Maar, eerst zul je de snelle reparatie branch verwijderen, omdat je die niet langer nodig hebt: de `master` branch wijst naar dezelfde plek. Je kunt het verwijderen met de `-d` optie op `git branch`: +Nadat je super-belangrijke reparatie uitgerold is, ben je klaar om terug te schakelen naar het werk dat je deed voordat je onderbroken werd. Maar, eerst ga je de hotfix branch verwijderen, omdat je die niet langer nodig hebt - de `master` branch wijst naar dezelfde plek. Je kunt het verwijderen met de `-d` optie op `git branch`: $ git branch -d hotfix Deleted branch hotfix (3a0874c). @@ -195,38 +217,39 @@ Nadat je super-belangrijke reparatie uitgerold is, ben je klaar om terug te scha Nu kun je terugschakelen naar je werk in uitvoering branch voor probleem #53 en doorgaan met daar aan te werken (zie Figuur 3-15): $ git checkout iss53 - Switched to branch "iss53" + Switched to branch 'iss53' $ vim index.html $ git commit -a -m 'finished the new footer [issue 53]' - [iss53]: created ad82d7a: "finished the new footer [issue 53]" - 1 files changed, 1 insertions(+), 0 deletions(-) + [iss53 ad82d7a] finished the new footer [issue 53] + 1 file changed, 1 insertion(+) Insert 18333fig0315.png Figuur 3-15. Je iss53 branch kan onafhankelijk vooruit bewegen. -Het is nuttig om hier op te merken dat het werk dat je in je snelle reparatie branch gedaan hebt, niet in de bestanden van je `iss53` branch zit. Als je dat binnen moet halen, dan kun je de `master` branch in de `iss53` branch merge door `git merge master` uit te voeren, of je kunt wachten met die wijzigingen te integreren tot het moment dat je het besluit neemt de `iss53` branch in de `master` te trekken. +Het is nuttig om hier op te merken dat het werk dat je in de hotfix branch gedaan hebt, niet in de bestanden van je `iss53` branch zit. Als je dat binnen moet halen, dan kun je de `master` branch in de `iss53` branch mergen door `git merge master` uit te voeren, of je kunt wachten met die wijzigingen te integreren tot het moment dat je het besluit neemt de `iss53` branch in de `master` te trekken. ### Eenvoudig samenvoegen ### -Stel dat je besloten hebt dat je probleem #53 werk gereed is en klaar bent om het te mergen in de `master` branch. Om dat te doen, zul je je `iss53` branch mergen zoals je die snelle reparatie branch eerder hebt gemerged. Het enige dat je hoeft te doen is de branch uit te checken waar je in wenst te mergen en dan het `git merge` commando uit te voeren: +Stel dat je besloten hebt dat je probleem #53 werk gereed is en klaar bent om het te mergen in de `master` branch. Om dat te doen, zul je de `iss53` branch mergen zoals je die hotfix branch eerder hebt gemerged. Het enige dat je hoeft te doen is de branch uit te checken waar je in wenst te mergen en dan het `git merge` commando uit te voeren: $ git checkout master $ git merge iss53 - Merge made by recursive. - README | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) + Auto-merging README + Merge made by the 'recursive' strategy. + README | 1 + + 1 file changed, 1 insertion(+) -Dit ziet er iets anders uit dan de snelle reparatie merge die je eerder deed. In dit geval is je ontwikkelingshistorie afgeweken van een eerder punt. Omdat de commit op de branch waar je op zit geen directe voorouder is van de branch waar je in merged, moet Git wat werk doen. In dit geval, doet Git een eenvoudige drieweg merge, gebruikmakend van de twee snapshots waarnaar gewezen wordt door de branch punten en de gezamenlijke voorouder van die twee. Figuur 3-16 markeert de drie snapshots die Git gebruikt om de merge te doen in dit geval te doen. +Dit ziet er iets anders uit dan de `hotfix` merge die je eerder gedaan hebt. In dit geval is je ontwikkelhistorie afgeweken van een eerder punt. Omdat de commit op de branch waar je op zit geen directe voorouder is van de branch waar je in merged, moet Git wat werk doen. In dit geval, doet Git een eenvoudige drieweg merge, gebruikmakend van de twee snapshots waarnaar gewezen wordt door de uiteinden van de branch en de gezamenlijke voorouder van die twee. Figuur 3-16 markeert de drie snapshots die Git gebruikt om de merge te doen in dit geval te doen. Insert 18333fig0316.png -Figuur 3-16. Git identificeert automatisch de beste gezamenlijke voorouder als basis voor het mergen van de branches. +Figuur 3-16. Git identificeert automatisch de meest geschikte gezamenlijke voorouder als basis voor het mergen van de branches. -In plaats van de branch verwijzing vooruit te verplaatsen, maakt Git een nieuw snapshot dat resulteert uit deze drieweg merge en maakt automatisch een nieuwe commit die daar naar wijst (zie Figuur 3-17). Dit wordt een mergecommit genoemd, en is bijzonder in die zin dat het meer dan één ouder heeft. +In plaats van de branch verwijzing vooruit te verplaatsen, maakt Git een nieuw snapshot dat het resultaat is van deze drieweg merge en maakt automatisch een nieuwe commit die daar naar wijst (zie Figuur 3-17). Dit wordt een merge-commit genoemd, en is bijzonder in die zin dat het meer dan één ouder heeft. -Het is belangrijk om erop te wijzen dat Git de beste gezamenlijke voorouder bepaalt om te gebruiken als merge basis; dit is anders dan CVS of Subversion (voor versie 1.5), waar het de ontwikkelaar die de merge doet degene is die de beste merge basis moest uitzoeken. Dit maakt het mergen in Git een behoorlijk stuk eenvoudiger dan in deze andere systemen. +Het is belangrijk om erop te wijzen dat Git de meest geschikte gezamenlijke voorouder bepaalt om te gebruiken als merge basis; dit is anders dan CVS of Subversion (voor versie 1.5), waar het de ontwikkelaar die de merge doet ook degene is die de beste merge basis moest uitzoeken. Dit maakt het mergen in Git een behoorlijk stuk eenvoudiger in vergelijking met deze andere systemen. Insert 18333fig0317.png -Figuur 3-17. Git maakt automatisch een nieuw commit object aan die het samengevoegde werk bevat. +Figuur 3-17. Git maakt automatisch een nieuw commit object aan die het gemergede werk bevat. Nu dat je werk gemerged is, is er geen verdere noodzaak meer voor de `iss53` branch. Je kunt het verwijderen en daarna handmatig de ticket in het ticket-volg systeem sluiten: @@ -234,34 +257,36 @@ Nu dat je werk gemerged is, is er geen verdere noodzaak meer voor de `iss53` bra ### Eenvoudige merge conflicten ### -Af en toe verloopt dit proces niet soepel. Als je hetzelfde gedeelte van hetzelfde bestand anders hebt gewijzigd in twee branches die je merged, dan zal Git niet in staat zijn om ze netjes te mergen. Als je reparatie voor probleem #53 hetzelfde gedeelte van een bestand heeft gewijzigd als de snelle reparatie, dan krijg je een merge conflict dat er ongeveer zo uit ziet: +Af en toe verloopt dit proces niet zo soepel. Als je hetzelfde gedeelte van hetzelfde bestand op een andere manier hebt gewijzigd in twee branches die je merged, dan zal Git niet in staat zijn om ze netjes te mergen. Als je reparatie voor probleem #53 hetzelfde gedeelte van een bestand heeft gewijzigd als de `hotfix`, dan krijg je een merge conflict dat er ongeveer zo uit ziet: $ git merge iss53 Auto-merging index.html CONFLICT (content): Merge conflict in index.html Automatic merge failed; fix conflicts and then commit the result. -Git heeft niet automatisch een nieuwe merge commit gemaakt. Het heeft het proces gestopt zodat jij het conflict kan oplossen. Als je wilt zien welke bestanden nog niet zijn gemerged op ieder punt na een merge conflict, dan kun je `git status` uitvoeren: - - [master*]$ git status - index.html: needs merge - # On branch master - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # unmerged: index.html - # - -Alles wat merge conflicten heeft en wat nog niet is opgelost wordt getoond als unmerged. Git voegt standaard conflict-oplossings markeringen toe aan de bestanden die conflicten hebben, zodat je ze handmatig kunt openen en die conflicten kunt oplossen. Je bestand bevat een gedeelte die er zo ongeveer uit ziet: +Git heeft geen nieuwe merge commit gemaakt. Het heeft het proces gepauzeerd zolang jij het conflict aan het oplossen bent. Als je wilt zien welke bestanden nog niet zijn gemerged op enig punt na een merge conflict, dan kun je `git status` uitvoeren: - <<<<<<< HEAD:index.html + $ git status + On branch master + You have unmerged paths. + (fix conflicts and run "git commit") + + Unmerged paths: + (use "git add ..." to mark resolution) + + both modified: index.html + + no changes added to commit (use "git add" and/or "git commit -a") + +Alles wat merge conflicten heeft en wat nog niet is opgelost wordt getoond als unmerged. Git voegt standaard conflict-oplossings markeringen toe aan de bestanden die conflicten hebben, zodat je ze handmatig kunt openen en die conflicten kunt oplossen. Je bestand bevat een sectie die er zo ongeveer uit ziet: + + <<<<<<< HEAD ======= - >>>>>>> iss53:index.html + >>>>>>> iss53 Dit betekent dat de versie in HEAD (jouw master branch, omdat dat degene was dat je uitgechecked had toen je het merge commando uitvoerde) is het bovenste gedeelte van dat blok (alles boven de `======`), terwijl de versie in je `iss53` branch eruit ziet zoals alles in het onderste gedeelte. Om het conflict op te lossen, moet je één van de twee gedeeltes kiezen of de inhoud zelf mergen. Je zou bijvoorbeeld dit conflict op kunnen lossen door het hele blok met dit te vervangen: @@ -269,32 +294,36 @@ Dit betekent dat de versie in HEAD (jouw master branch, omdat dat degene was dat please contact us at email.support@github.com -Deze oplossing bevat een stukje uit beide secties, en ik heb de `<<<<<<<`, `=======`, en `>>>>>>>` regels volledig verwijderd. Nadat je elk van deze secties opgelost hebt in elk conflicterend bestand, voer dan `git add` uit voor ieder bestand om het als opgelost te markeren. Het bestand stagen markeert het als opgelost in Git. +Deze oplossing bevat een stukje uit beide secties, en ik heb de `<<<<<<<`, `=======`, en `>>>>>>>` regels volledig verwijderd. Nadat je elk van deze secties opgelost hebt in elk conflicterend bestand, voer dan `git add` uit voor elk van die bestanden om het als opgelost te markeren. Het bestand stagen markeert het als opgelost in Git. Als je een grafische applicatie wil gebruiken om deze problemen op te lossen, kun je `git mergetool` uitvoeren, wat een toepasselijk grafische merge applicatie opstart dat je door de conflicten heen leidt: $ git mergetool - merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff - Merging the files: index.html + + This message is displayed because 'merge.tool' is not configured. + See 'git mergetool --tool-help' or 'git help config' for more details. + 'git mergetool' will now attempt to use one of the following tools: + opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge + Merging: + index.html Normal merge conflict for 'index.html': - {local}: modified - {remote}: modified + {local}: modified file + {remote}: modified file Hit return to start merge resolution tool (opendiff): -Als je een ander merge applicatie wil gebruiken dan de standaard (Git koos `opendiff` voor me in dit geval, omdat ik het commando uitvoerde op een Mac), dan kun je alle ondersteunde applicaties opgenoemd zien na "merge tool candidates". Type de naam van de applicatie die je liever gebruikt. In Hoofdstuk 7 zullen we bespreken hoe je deze standaard waarde voor jouw omgeving kunt wijzigen. +Als je een andere dan de standaard merge tool wilt gebruiken (Git koos `opendiff` voor me in dit geval, omdat ik het commando uitvoerde op een Mac), dan kun je alle ondersteunde applicaties opgenoemd zien na "... one of the following tools:". Type de naam van de applicatie die je liever gebruikt. In Hoofdstuk 7 zullen we bespreken hoe je deze standaard waarde voor jouw omgeving kunt wijzigen. Nadat je de merge applicatie afsluit, vraagt Git je of de merge succesvol was. Als je het script vertelt dat dit het geval is, dan staged dit script het bestand voor je om het als opgelost te markeren. Je kunt `git status` nogmaals uitvoeren om er zeker van te zijn dat alle conflicten opgelost zijn: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: index.html - # - + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: index.html + Als je het daar mee eens bent, en je gecontroleerd hebt dat alles waar conflicten in zat gestaged is, dan kun je `git commit` typen om de merge commit af te ronden. Het commit bericht ziet er standaard ongeveer zo uit: Merge branch 'iss53' @@ -308,7 +337,7 @@ Als je het daar mee eens bent, en je gecontroleerd hebt dat alles waar conflicte # and try again. # -Je kunt dat bericht aanpassen met details over hoe je het conflict opgelost hebt, als je denkt dat dat behulpzaam zal zijn voor anderen die in de toekomst naar deze samenvoeging kijken; waarom je heb je gedaan wat je gedaan hebt, als dat niet vanzelfsprekend is. +Je kunt dat bericht aanpassen met details over hoe je het conflict opgelost hebt, als je denkt dat dat behulpzaam zal zijn voor anderen die in de toekomst naar deze merge kijken - waarom je hebt gedaan wat je gedaan hebt, als dat niet vanzelfsprekend is. ## Branch beheer ## @@ -328,14 +357,14 @@ Merk op dat het `*` karakter vooraf gaat aan de `master` branch: het geeft de br * master 7a98805 Merge branch 'iss53' testing 782fd34 add scott to the author list in the readmes -Een andere handige optie om uit te vogelen in welke staat je branches zijn, is om deze lijst te filteren op branches die je wel of nog niet gemerged hebt in de branch waar je nu op zit. De handige `--merged` en `--no-merged` opties zijn voor dit doel beschikbaar in Git. Om te zien welke branches al gemerged zijn in de branch waar je nu op zit, kun je `git branch --merged` uitvoeren: +Een andere handige optie om uit te vinden in welke staat je branches zijn, is om deze lijst te filteren op branches die je wel of nog niet gemerged hebt in de branch waar je nu op zit. De handige `--merged` en `--no-merged` opties zijn voor dit doel beschikbaar in Git. Om te zien welke branches al gemerged zijn in de branch waar je nu op zit, kun je `git branch --merged` uitvoeren: $ git branch --merged iss53 * master -Omdat je `iss53` al eerder hebt gemerged, zie je het terug in je lijst. Branches op deze lijst zonder de `*` ervoor zijn over het algemeen zonder problemen te verwijderen met `git branch -d`: je hebt hun werk al in een andere branch zitten, dus je zult niets kwijtraken. +Omdat je `iss53` al eerder hebt gemerged, zie je het terug in je lijst. Branches op deze lijst zonder de `*` ervoor zijn over het algemeen zonder problemen te verwijderen met `git branch -d`; je hebt hun werk al in een andere branch zitten, dus je zult niets kwijtraken. Om alle branches te zien die werk bevatten dat je nog niet gemerged hebt, kun je `git branch --no-merged` uitvoeren: @@ -352,15 +381,15 @@ Als je de branch echt wilt verwijderen en dat werk wilt verliezen, dan kun je he ## Branch workflows ## -Nu dat je de basis van het branchen en samenvoegen onder de knie hebt, wat kan of zou je met ze kunnen doen? In deze paragraaf gaan we een aantal veel voorkomende workflows die deze lichtgewicht branches mogelijk maken behandelen, zodat je kunt besluiten of je ze wilt toepassen in jouw ontwikkel cyclus. +Nu je de basis van het branchen en mergen onder de knie hebt, wat kan of zou je daarmee kunnen doen? In deze paragraaf gaan we een aantal veel voorkomende workflows die deze lichtgewicht branches mogelijk maken behandelen, zodat je kunt besluiten of je ze wilt toepassen in je eigen ontwikkel cyclus. ### Lang-lopende branches ### -Omdat Git gebruik maakt van een eenvoudige drieweg merge, is het meerdere keren mergen vanuit een branch in een andere gedurende een langere periode over het algemeen eenvoudig te doen. Dit betekent dat je meerdere branches kunt hebben, die altijd open staan en die je voor verschillende delen van je ontwikkel cyclus gebruikt; je kunt regelmatig een aantal mergen in andere. +Omdat Git gebruik maakt van een eenvoudige drieweg merge, is het meerdere keren mergen vanuit een branch in een andere gedurende een langere periode over het algemeen eenvoudig te doen. Dit betekent dat je meerdere branches kunt hebben, die altijd open staan en die je voor verschillende delen van je ontwikkel cyclus gebruikt; je kunt regelmatig vanuit een aantal mergen in andere. -Veel Git ontwikkelaars hebben een workflow die deze aanpak omarmt, zoals het hebben van alleen volledig stabiele code in hun `master` branch — waarschijnlijk alleen code die is of zal worden vrijgegeven. Ze hebben een andere parallelle branch "develop" of "next" genaamd waarop ze werken of die ze gebruiken om stabiliteit te testen — het is niet noodzakelijk altijd stabiel, maar zodra het in een stabiele status verkeert, kan het worden gemerged in `master`. Het wordt gebruikt om topic branches (branches met een korte levensduur, zoals jou eerdere `iss53` branch) te pullen zodra die klaar zijn, om er zich ervan te verzekeren dat alle testen slagen en er geen fouten worden geïntroduceerd. +Veel Git ontwikkelaars hebben een workflow die deze aanpak omarmt, zoals het hebben van alleen volledig stabiele code in hun `master` branch — mogelijk alleen code die is of zal worden vrijgegeven. Ze hebben een andere parallelle branch "develop" of "next" genaamd waarop ze werken of die ze gebruiken om stabiliteit te testen — het is niet noodzakelijkerwijs altijd stabiel, maar zodra het in een stabiele status verkeert, kan het worden gemerged in `master`. Deze wordt gebruikt om topic branches (branches met een korte levensduur, zoals jou eerdere `iss53` branch) te pullen zodra die klaar zijn, om er zich ervan te overtuigen dat alle testen slagen en er geen fouten worden geïntroduceerd. -In essentie praten we over verwijzingen die zich verplaatsen over de lijn van de commits die je maakt. De stabiele branches zijn verder naar achter in je commit historie, en de splinternieuwe branches zijn verder naar voren in de historie (zie Figuur 3-18). +Feitelijk praten we over verwijzingen die worden verplaatst over de lijn van de commits die je maakt. De stabiele branches zijn verder naar achterop in je commit historie, en de splinternieuwe branches zijn verder naar voren in de historie (zie Figuur 3-18). Insert 18333fig0318.png Figuur 3-18. Meer stabiele branches zijn over het algemeen verder naar achter in de commit historie. @@ -370,44 +399,44 @@ Ze zijn misschien makkelijker voor te stellen als werk silo's, waar sets van com Insert 18333fig0319.png Figuur 3-19. Het kan handig zijn om je branches voor te stellen als silo's. -Je kunt dit blijven doen voor elk niveaus van toegenomen stabiliteit. Sommige grotere projecten hebben ook een `proposed` of `pu` (proposed updates) branch die branches geïntegreerd heeft die wellicht nog niet klaar zijn om in de `next` of `master` branch te gaan. Het idee erachter is dat de branches op verschillende niveaus van stabiliteit zitten. Zodra ze een meer stabiel niveau bereiken, worden ze in de branch boven hun gemerged. -Nogmaals, het hebben van langlopende branches is niet noodzakelijk maar het helpt vaak wel, in het bijzonder als je te maken hebt met zeer grote of complexe projecten. +Je kunt dit blijven doen voor elk niveau van stabiliteit. Sommige grotere projecten hebben ook een `proposed` of `pu` (proposed updates) branch die branches geïntegreerd heeft die wellicht nog niet klaar zijn om in de `next` of `master` branch te gaan. Het idee erachter is dat de branches op verschillende niveaus van stabiliteit zitten. Zodra ze een meer stabiel niveau bereiken, worden ze in de branch boven hen gemerged. +Nogmaals, het hebben van langlopende branches is niet noodzakelijk, maar het helpt vaak wel; in het bijzonder als je te maken hebt met zeer grote of complexe projecten. ### Topic branches ### Topic branches zijn nuttig in projecten van elke grootte. Een topic branch is een kortlopende branch die je maakt en gebruikt om een specifieke functie te realiseren of daaraan gerelateerd werk te doen. Dit is iets wat je waarschijnlijk nooit eerder met een VCS gedaan hebt, omdat het over het algemeen te duur is om branches aan te maken en te mergen. Maar in Git is het niet ongebruikelijk om meerdere keren per dag branches aan te maken, daarop te werken, en ze te verwijderen. -Je zag dit in de vorige paragraaf met de `iss53` en `hotfix` branches die je gemaakt had. Je hebt een aantal commits op ze gedaan en ze meteen verwijderd zodra je ze gemerged had in je hoofd branch. Deze techniek staat je toe om snel en volledig van context te veranderen — omdat je werk is onderverdeeld in silo's waar alle wijzigingen te maken hebben met het onderwerp van die branch, is het makkelijker te zien wat er is gebeurd tijdens een code review en dergelijke. Je kunt de wijzigingen daar minuten, dagen of maanden bewaren, en ze mergen als ze er klaar voor zijn, ongeacht de volgorde waarin ze gemaakt of aan gewerkt zijn. +Je zag dit in de vorige paragraaf met de `iss53` en `hotfix` branches die je gemaakt had. Je hebt een aantal commits op ze gedaan en ze meteen verwijderd nadat je ze gemerged had in je hoofd branch. Deze techniek stelt je in staat om snel en volledig van context te veranderen — omdat je werk is onderverdeeld in silo's waar alle wijzigingen in die branch te maken hebben met dat onderwerp, is het makkelijker te zien wat er is gebeurd tijdens een code review en dergelijke. Je kunt de wijzigingen daar minuten-, dagen- of maandenlang bewaren, en ze mergen als ze er klaar voor zijn, ongeacht de volgorde waarin ze gemaakt of aan gewerkt zijn. -Neem als voorbeeld een situatie waarbij wat werk gedaan wordt (op `master`), er wordt een branche gemaakt voor een probleem (`iss91`) daar wordt wat aan gewerkt, er wordt een tweede branch gemaakt om op een andere manier te proberen hetzelfde op te lossen (`iss91v2`); even teruggaan naar de master branch om daar een tijdje te werken, en dan vanaf daar branchen om wat werk te doen waarvan je niet zeker weet of het wel een goed idee is (`dumbidea` branch). Je commit historie zal er uit zien als Figuur 3-20. +Neem als voorbeeld een situatie waarbij wat werk gedaan wordt (op `master`), er wordt een branche gemaakt voor een probleem (`iss91`) en daar wordt wat aan gewerkt, er wordt een tweede branch gemaakt om op een andere manier te proberen hetzelfde op te lossen (`iss91v2`); weer even wordt teruggegaan naar de master branch om daar een tijdje te werken, en dan vanaf daar wordt gebrancht om wat werk te doen waarvan je niet zeker weet of het wel zo'n slim idee is (`dumbidea` branch). Je commit historie zal er uit zien als Figuur 3-20. Insert 18333fig0320.png Figuur 3-20. Je commit geschiedenis met meerdere topic branches. -Laten we zeggen dat je besluit dat je de tweede oplossing voor je probleem het beste vindt (`iss91v2`), en je hebt de `dumbidea` branch aan je collega's laten zien en het blijkt geniaal te zijn. Je kunt dan de oorspronkelijke `iss91` weggooien (waardoor je commits C5 en C6 kwijt raakt), en de andere twee mergen. Je historie ziet er dan uit als Figuur 3-21). +Laten we zeggen dat je besluit dat je de tweede oplossing voor je probleem het beste vindt (`iss91v2`), en je hebt de `dumbidea` branch aan je collega's laten zien en het blijkt geniaal te zijn. Je kunt dan de oorspronkelijke `iss91` weggooien (waardoor je commits C5 en C6 kwijt raakt), en de andere twee mergen. Je historie ziet er dan uit als Figuur 3-21. Insert 18333fig0321.png -Figuur 3-21. Je historie na het samenvoegen van dumbidea en iss91v2. +Figuur 3-21. Je historie na het mergen van dumbidea en iss91v2. -Het is belangrijk om te beseffen dat tijdens al deze handelingen, al deze branches volledig lokaal zijn. Als je aan het branchen of mergen bent, dan wordt alles alleen in jouw Git repository gedaan, dus er vindt geen server communicatie plaats. +Het is belangrijk om te beseffen dat tijdens al deze handelingen, al deze branches volledig lokaal zijn. Als je aan het branchen of mergen bent, dan wordt alles alleen in jouw Git repository gedaan - dus er vindt geen server communicatie plaats. ## Remote branches ## Remote branches zijn referenties naar de staat van de branches op remote repositories. Ze zijn lokale branches die jij niet kunt verplaatsen; ze worden automatisch verplaatst zodra je er netwerk communicatie plaatsvindt. Remote branches gedragen zich als boekenleggers om je eraan te helpen herinneren wat de staat van de branches was op je remote repositories toen je voor het laatst met ze in contact was. -Ze hebben de vorm `(remote)/(branch)`. Bijvoorbeeld, als je wil zien hoe de `master` branch op je `origin` de laatste keer dat je er mee communiceerde er uit zag, dan zal je de `origin/master` branch moeten bekijken. Als je aan het werk bent met een probleem samen met een partner en zij heeft een `iss53` branch gepushed, kan je je eigen lokale `iss53` hebben, maar de branch op de server zou wijzen naar de commit op `origin/iss53`. +Ze hebben de vorm `(remote)/(branch)`. Bijvoorbeeld, als je wil zien hoe de `master` branch op je `origin` de laatste keer dat je er mee communiceerde er uit zag, dan zal je de `origin/master` branch moeten bekijken. Als je samen met een partner aan het werk bent met een probleem en zij heeft een `iss53` branch gepushed, zou je je een eigen lokale `iss53` kunnen hebben, maar de branch op de server zal wijzen naar de commit op `origin/iss53`. -Dit is wat verwarrend, dus laten we eens naar een voorbeeld kijken. Stel dat je een Git server op je netwerk hebt op `git.ourcompany.com`. Als je hiervan kloont dan wordt die automatisch `origin` voor je genoemd, Git haalt alle gegevens binnen, maakt een verwijzing naar waar de `master` branch is en noemt dat lokaal `origin/master`, en deze kan je niet verplaatsen. Git geeft je ook een eigen `master` branch, beginnend op dezelfde plaats als de `master` branch van origin, zodat je iets hebt om vanaf te werken (zie Figuur 3-22). +Dit kan wat verwarrend zijn, dus laten we eens naar een voorbeeld kijken. Stel dat je een Git server op je netwerk hebt op `git.ourcompany.com`. Als je hiervan cloned dan wordt die door Git automatisch `origin` voor je genoemd, Git haalt alle gegevens binnen, maakt een verwijzing naar waar de `master` branch is en noemt dat lokaal `origin/master`, en deze kan je niet verplaatsen. Git geeft je ook een eigen `master` branch, beginnend op dezelfde plaats als de `master` branch van origin, zodat je iets hebt om vanaf te werken (zie Figuur 3-22). Insert 18333fig0322.png Figuur 3-22. Een Git clone geeft je een eigen master branch en origin/master wijzend naar de master branch van origin. -Als je wat werk doet op je lokale master branch, en in de tussentijd pushed iemand anders iets naar `git.ourcompany.com` en daarmee die master branch vernieuwd, dan zijn jullie histories verschillend vooruit geschoven. En, zolang je geen contact hebt met de origin server, zal jouw `origin/master` verwijzing niet verplaatsen (zie Figuur 3-23). +Als je wat werk doet op je lokale master branch, en in de tussentijd pusht iemand anders iets naar `git.ourcompany.com` waardoor die master branch wordt vernieuwd, dan zijn jullie histories verschillend vooruit geschoven. En zolang je geen contact hebt met de origin server, zal jouw `origin/master` verwijzing niet verplaatsen (zie Figuur 3-23). Insert 18333fig0323.png -Figuur 3-23. Lokaal werken terwijl iemand anders naar je remote server pushed laat elke historie anders vooruit gaan. +Figuur 3-23. Lokaal werken terwijl iemand anders naar je remote server pusht laat elke historie anders vooruit gaan. -Om je werk te synchroniseren, voer je een `git fetch origin` commando uit. Dit commando bekijkt welke op server origin is (in dit geval is het `git.ourcompany.com`), haalt gegevens er vanaf die je nog niet hebt en vernieuwt je lokale database, waarbij je `origin/master` verwijzing naar zijn nieuwe positie verplaatst wordt (zie Figuur 3-24). +Om je werk te synchroniseren, voer je een `git fetch origin` commando uit. Dit commando bekijkt welke server origin is (in dit geval is het `git.ourcompany.com`), haalt gegevens er vanaf die je nog niet hebt en vernieuwt je lokale database, waarbij je `origin/master` verwijzing naar zijn nieuwe positie verplaatst wordt die meer up-to-date is (zie Figuur 3-24). Insert 18333fig0324.png Figuur 3-24. Het git fetch commando vernieuwt je remote referenties. @@ -417,14 +446,14 @@ Om het hebben van meerdere remote servers te tonen en hoe remote branches voor d Insert 18333fig0325.png Figuur 3-25. Een andere server als een remote toevoegen. -Nu kun je `git fetch teamone` uitvoeren om alles op te halen dat wat de `teamone` remote server heeft en jij nog niet. Omdat die server een subset heeft van de gegevens die jouw `origin` server op dit moment heeft, haalt Git geen gegevens maar maakt een remote branch genaamd `teamone/master` aan en laat die wijzen naar de commit die `teamone` heeft als zijn `master` branch (zie Figuur 3-26). +Nu kun je `git fetch teamone` uitvoeren om alles op te halen dat wat de `teamone` remote server heeft en jij nog niet. Omdat die server een subset heeft van de gegevens die jouw `origin` server op dit moment heeft, haalt Git geen gegevens op maar maakt een remote branch genaamd `teamone/master` aan en laat die wijzen naar de commit die `teamone` heeft als zijn `master` branch (zie Figuur 3-26). Insert 18333fig0326.png Figuur 3-26. Je krijgt lokaal een referentie naar de master branch positie van teamone. ### Pushen ### -Als je een branch wil delen met de rest van de wereld, dan moet je het naar een remote terugzetten waar je schrijftoegang op hebt. Je lokale branches worden niet automatisch gesynchroniseerd met de remotes waar je naar schrijft, je moet de branches die je wilt delen uitdrukkelijk pushen. Op die manier kun je privé branches gebruiken voor het werk dat je niet wil delen, en alleen die topic branches pushen waar je op wilt samenwerken. +Als je een branch wil delen met de rest van de wereld, dan moet je het naar een remote terugzetten waar je schrijftoegang op hebt. Je lokale branches worden niet automatisch gesynchroniseerd met de remotes waar je naar schrijft - je moet de branches die je wilt delen uitdrukkelijk pushen. Op die manier kun je privé branches gebruiken voor het werk dat je niet wil delen, en alleen die topic branches pushen waar je op wilt samenwerken. Als je een branch genaamd `serverfix` hebt waar je met anderen aan wilt werken, dan kun je die op dezelfde manier pushen als waarop je dat voor de eerste branch hebt gedaan. Voer `git push (remote) (branch)` uit: @@ -436,7 +465,7 @@ Als je een branch genaamd `serverfix` hebt waar je met anderen aan wilt werken, To git@github.com:schacon/simplegit.git * [new branch] serverfix -> serverfix -Dit is een verkorte manier. Git zal de `serverfix` branchnaam automatisch expanderen naar `refs/heads/serverfix:refs/heads/serverfix`, wat staat voor "Neem mijn lokale serverfix branch en push die om de serverfix branch van de remote te vernieuwen.". We zullen het `refs/heads` gedeelte gedetaileerd behandelen in Hoofdstuk 9, maar je kunt het normaalgesproken weglaten. Je kun ook `git push origin serverfix:serverfix` doen, wat hetzelfde doet. Dit staat voor "Neem mijn serverfix en maak het de serverfix van de remote." Je kunt dit formaat gebruiken om een lokale branch te pushen naar een remote branch die anders heet. Als je niet wil dat het `serverfix` heet aan de remote kant, kan je in plaats daarvan `git push origin serverfix:awesomebranch` gebruiken om je lokale `serverfix` branch naar de `awesomebranch` op het remote project te pushen. +Dit is een beetje de bocht afsnijden. Git zal de `serverfix` branchnaam automatisch expanderen naar `refs/heads/serverfix:refs/heads/serverfix`, wat staat voor "Neem mijn lokale serverfix branch en push die om de serverfix branch van de remote te vernieuwen.". We zullen het `refs/heads` gedeelte gedetaileerd behandelen in Hoofdstuk 9, maar je kunt het normaalgesproken weglaten. Je kun ook `git push origin serverfix:serverfix` doen, wat hetzelfde doet. Dit staat voor "Neem mijn serverfix en maak het de serverfix van de remote." Je kunt dit formaat gebruiken om een lokale branch te pushen naar een remote branch die anders heet. Als je niet wil dat het `serverfix` heet aan de remote kant, kan je in plaats daarvan `git push origin serverfix:awesomebranch` gebruiken om je lokale `serverfix` branch naar de `awesomebranch` op het remote project te pushen. De volgende keer dat één van je medewerkers van de server fetched zal deze een referentie krijgen naar de versie van `serverfix` op de server, onder de remote branch `origin/serverfix`: @@ -448,37 +477,37 @@ De volgende keer dat één van je medewerkers van de server fetched zal deze een From git@github.com:schacon/simplegit * [new branch] serverfix -> origin/serverfix -Het is belangrijk om op te merken dat als je een fetch doet die nieuwe remote branches ophaalt, je niet automatisch lokale aanpasbare kopieën daarvan hebt. In andere woorden, in dit geval heb je geen nieuwe `serverfix` branch, je hebt alleen een `origin/serverfix` verwijzing die je niet kunt aanpassen. +Het is belangrijk om op te merken dat wanneer je een fetch doet die nieuwe remote branches ophaalt, je niet automatisch lokale aanpasbare kopieën daarvan hebt. In andere woorden, in dit geval heb je geen nieuwe `serverfix` branch - je hebt alleen een `origin/serverfix` verwijzing die je niet kunt aanpassen. Om dit werk in je huidige werk branch te mergen, kun je `git merge origin/serverfix` uitvoeren. Als je een eigen `serverfix` branch wilt waar je op kunt werken, dan kun je deze op je remote branch baseren: $ git checkout -b serverfix origin/serverfix - Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "serverfix" + Branch serverfix set up to track remote branch serverfix from origin. + Switched to a new branch 'serverfix' Dit maakt een lokale branch aan waar je op kunt werken, die begint met waar `origin/serverfix` is. ### Tracking branches ### -Een lokale branch uitchecken van een remote branch creëert automatisch een zogenaamde _volg branch_ (_tracking branch_). Tracking branches zijn lokale branches die een directe releatie met een remote branch hebben. Als je op een tracking branch zit en `git push` typt, dat weet Git automatisch naar welke server en branch hij moet pushen. En, als je op een van die branches zit zal het uitvoeren van `git pull` alle remote referenties ophalen en automatisch naar de corresponderende remote branch mergen. +Een lokale branch uitchecken van een remote branch creëert automatisch een zogenaamde _volg branch_ (_tracking branch_). Tracking branches zijn lokale branches die een directe releatie met een remote branch hebben. Als je op een tracking branch zit en `git push` typt, dat weet Git automatisch naar welke server en branch hij moet pushen. En, als je op een van die branches zit zal het uitvoeren van `git pull` alle remote referenties ophalen en automatisch de corresponderende remote branch erin mergen. -Als je een repository kloont, zal het over het algemeen automatisch een `master` branch aanmaken, die `origin/master` tracked. Daarom werken `git push` en `git pull` zo uit het doosje, zonder verdere argumenten. Maar je kan ook andere tracking branches instellen als je dat wilt, andere die niet branches volgen op `origin` en niet de `master` branch tracken. Een eenvoudig voorbeeld is wat je zojuist gezien hebt: `git checkout -b [branch] [remotenaam]/[branch]` uitvoeren. Als je Git versie 1.6.2 of nieuwer hebt, kun je ook de `--track` afkorting gebruiken: +Als je een repository cloned, zal het over het algemeen automatisch een `master` branch aanmaken die `origin/master` tracked. Daarom werken `git push` en `git pull` zo uit het doosje, zonder verdere argumenten. Maar je kan ook andere tracking branches aanmaken als je dat wilt, andere die niet branches tracken op `origin` en niet de `master` branch tracken. Een eenvoudig voorbeeld is wat je zojuist gezien hebt: `git checkout -b [branch] [remotenaam]/[branch]` uitvoeren. Als je Git versie 1.6.2 of nieuwer hebt, kun je ook de `--track` afkorting gebruiken: $ git checkout --track origin/serverfix - Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "serverfix" + Branch serverfix set up to track remote branch serverfix from origin. + Switched to a new branch 'serverfix' Om een lokale branch te maken met een andere naam dan de remote branch, kun je simpelweg de eerste variant met een andere lokale branch naam gebruiken: $ git checkout -b sf origin/serverfix - Branch sf set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "sf" + Branch sf set up to track remote branch serverfix from origin. + Switched to a new branch 'sf' Nu zal je lokale `sf` branch automatisch pullen en pushen van origin/serverfix. ### Remote branches verwijderen ### -Stel dat je klaar bent met een remote branch, stel dat jij en je medewerkers klaar zijn met een feature en het hebben gemerged in de `master` branch van de remote (of welke branch je stabiele code ook in zit). Dan kun je een remote branch verwijderen door de nogal botte syntax `git push [remotenaam] :[branch]` te gebruiken. Als je de `serverfix` branch van de server wilt verwijderen, dan voer je het volgende uit: +Stel dat je klaar bent met een remote branch - zeg maar, jij en je medewerkers zijn klaar met een feature en het hebben gemerged in de `master` branch van de remote (of welke branch jullie stabiele code ook in zit). Dan kun je een remote branch verwijderen door de nogal botte syntax `git push [remotenaam] :[branch]` te gebruiken. Als je de `serverfix` branch van de server wilt verwijderen, dan voer je het volgende uit: $ git push origin :serverfix To git@github.com:schacon/simplegit.git @@ -488,7 +517,7 @@ Boem. Geen branch meer op je server. Je zult deze pagina wel een ezelsoortje wil ## Rebasen ## -In Git zijn er twee hoofdmanieren om wijzigingen te integreren van de ene branch in een andere: de `merge` en de `rebase`. In deze paragraaf zul je leren wat rebasen is, hoe je dat moet doen, waarom het een zeer bijzondere toepassing is en in welke gevallen je het niet wilt gebruiken. +In Git zijn er twee hoofdmanieren om wijzigingen te integreren van de ene branch in een andere: de `merge` en de `rebase`. In deze paragraaf ga je leren wat rebasen is, hoe je dat moet doen, waarom het een zeer bijzondere stukje gereedschap is en in welke gevallen je het niet wilt gebruiken. ### De simpele rebase ### @@ -500,7 +529,7 @@ Figuur 3-27. Je initiële uiteengelopen historie. De simpelste manier om de branches te integreren, zoals we al hebben besproken, is het `merge` commando. Het voert een drieweg merge uit tussen de twee laatste snapshots van de branches (C3 en C4), en de meest recente gezamenlijke voorouder van die twee (C2), en maakt een nieuw snapshot (en commit) zoals getoond in Figuur 3-28. Insert 18333fig0328.png -Figuur 3-28. Een branch merge om de uiteengelopen werk histories te integreren. +Figuur 3-28. Een branch mergen om de uiteengelopen werk histories te integreren. Maar, er is nog een manier: je kunt de patch van de wijziging die werd geïntroduceerd in C3 pakken en die opnieuw toepassen op C4. In Git, wordt dit _rebasen_ genoemd. Met het `rebase` commando kan je alle wijzigingen pakken die zijn gecommit op de ene branch, en ze opnieuw afspelen op een andere. @@ -511,7 +540,7 @@ In dit voorbeeld, zou je het volgende uitvoeren: First, rewinding head to replay your work on top of it... Applying: added staged command -Het gebeurt door naar de gezamenlijke voorouder van de twee branches te gaan (degene waar je op zit en degene waar je op rebased), de diff te nemen die geïntroduceerd is voor elke losse commit op de branch waar je op zit, die diffs in tijdelijke bestanden te bewaren, de huidige branch terug te zetten naar dezelfde commit als de branch waar je op rebased, en uiteindelijk elke diff om de beurt toe te passen, Figuur 3-29 toont dit proces. +Het gebeurt door naar de gezamenlijke voorouder van de twee branches te gaan (degene waar je op zit en degene waar je op rebased), de diff te nemen die geïntroduceerd is voor elke losse commit op de branch waar je op zit, die diffs in tijdelijke bestanden te bewaren, de huidige branch terug te zetten naar dezelfde commit als de branch waar je op rebased, en uiteindelijk elke diff om de beurt te applyen, Figuur 3-29 toont dit proces. Insert 18333fig0329.png Figuur 3-29. De wijzigingen die geïntroduceerd zijn in C3 rebasen op C4. @@ -521,11 +550,11 @@ Hierna kan je terug gaan naar de master branch en een fast-forward merge doen (z Insert 18333fig0330.png Figuur 3-30. De master branch Fast-forwarden. -Nu is het snapshot waar C3' naar wijst precies dezelfde als degene waar C5 naar wees in het merge voorbeeld. Er zit geen verschil in het eindresultaat van de integratie, maar rebasen zorgt voor een duidelijkere historie. Als je de log van een gerebasdte branch bekijkt, ziet het eruit als een lineaire historie: het lijkt alsof al het werk in serie is gebeurt, zelfs wanneer het in werkelijkheid in parallel gedaan is. +Nu is het snapshot waar C3' naar wijst precies dezelfde als degene waar C5 naar wees in het merge voorbeeld. Er zit geen verschil in het eindresultaat van de integratie, maar rebasen zorgt voor een duidelijkere historie. Als je de log van een branch die gerebased is bekijkt, ziet het eruit als een lineaire historie: het lijkt alsof al het werk in serie heeft plaatsgevonden, zelfs wanneer het in werkelijkheid parallel eraan gedaan is. -Vaak zal je dit doen om er zeker van te zijn dat je commits netjes toegepast kunnen worden op een remote branch, misschien in een project waar je aan probeert bij te dragen, maar dat je niet beheert. In dit geval zou je het werk in een branch uitvoeren en dan je werk rebasen op `origin/master` als je klaar ben om je patches in te sturen naar het hoofd project. Op die manier hoeft de beheerder geen integratie werk te doen maar gewoon een fast-forward of een gewone apply. +Vaak zal je dit doen om er zeker van te zijn dat je commits netjes toegepast kunnen worden op een remote branch - misschien in een project waar je aan probeert bij te dragen, maar dat je niet beheert. In dit geval zou je het werk in een branch uitvoeren en dan je werk rebasen op `origin/master` als je klaar ben om je patches in te sturen naar het hoofd project. Op die manier hoeft de beheerder geen integratie werk te doen - gewoon een fast-forward of een schone apply. -Merk op dat de snapshot waar de laatste commit op het eind naar wijst, of het de laatste van de gerebasete commits voor een rebase is of de laatste merge commit na een merge, detzelfde snapshot is; alleen de historie is verschillend. Rebasen speelt veranderingen van een werklijn opnieuw af op een andere, in de volgorde waarin ze gemaakt zijn, terwijl mergen de eindresultaten pakt en die samenvoegt. +Merk op dat de snapshot waar de laatste commit op het eind naar wijst, of het de laatste van de gerebasede commits voor een rebase is of de laatste merge commit na een merge, detzelfde snapshot is - alleen de historie is verschillend. Rebasen speelt veranderingen van een werklijn opnieuw af op een andere, in de volgorde waarin ze gemaakt zijn, terwijl mergen de eindresultaten pakt en die samenvoegt. ### Interessantere rebases ### @@ -534,7 +563,7 @@ Je kunt je rebase ook opnieuw laten afspelen op iets anders dan de rebase branch Insert 18333fig0331.png Figuur 3-31. Een historie met een topic branch vanaf een andere topic branch. -Stel dat je beslist dat je de client-kant wijzigingen wilt mergen in je hoofdlijn voor een release, maar je wilt de server-kant wijzigingen nog laten wachten totdat het verder getest is. Je kunt de wijzigingen van client pakken, die nog niet op server zitten (C8 en C9) en die opnieuw afspelen op je master branch door de `--onto` optie te gebruiken van `git rebase`: +Stel nu, je besluit dat je de client-kant wijzigingen wilt mergen in je hoofdlijn voor een release, maar je wilt de server-kant wijzigingen nog vasthouden totdat het verder getest is. Je kunt de wijzigingen van client pakken, die nog niet op server zitten (C8 en C9) en die opnieuw afspelen op je master branch door de `--onto` optie te gebruiken van `git rebase`: $ git rebase --onto master server client @@ -551,7 +580,7 @@ Nu kun je een fast-forward doen van je master branch (zie Figuur 3-33): Insert 18333fig0333.png Figuur 3-33. Je master branch fast-forwarden om de client branch wijzigingen mee te nemen. -Stel dat je besluit om de server branch ook te pullen. Je kunt de server branch rebasen op de master branch zonder het eerst te hoeven uitchecken door `git rebase [basisbranch] [topicbranch]` uit te voeren, wat de topic branch voor je uitchecked (in dit geval, `server`) en het opnieuw afspeelt om de basis branch (`master`): +Stel dat je besluit om de server branch ook te pullen. Je kunt de server branch rebasen op de master branch zonder het eerst te hoeven uitchecken door `git rebase [basisbranch] [topicbranch]` uit te voeren - wat de topic branch voor je uitcheckt (in dit geval, `server`) en het opnieuw afspeelt om de basis branch (`master`): $ git rebase master server @@ -577,35 +606,35 @@ Figuur 3-35. Uiteindelijke commit historie. Ahh, maar de zegeningen van rebasen zijn niet geheel zonder nadelen, samengevat in één enkele regel: -**Rebase geen commits die je gepushed hebt naar een publiek repository.** +**Rebase geen commits die je gepusht hebt naar een publiek repository.** -Als je die richtlijn volgt, dan zal je niets overkomen. Als je dat niet doet, zullen mensen je haten en je zult door vrienden en familie uitgehoond worden. +Als je die richtlijn volgt, kan je weinig gebeuren. Als je dat niet doet, zullen mensen je haten en je zult door vrienden en familie uitgehoond worden. -Als je spullen rebaset, zet je bestaande commits buitenspel en maak je nieuwe aan die vergelijkbaar zijn maar anders. Als je commits ergens pushed en andere pullen deze en baseren daar werk op, en vervolgens herschrijf je die commits met `git rebase` en pushed deze weer, dan zullen je medewerkers hun werk opnieuw moeten mergen en zal de boel erg vervelend worden als je hun werk probeert te pullen in het jouwe. +Als je spullen rebased, zet je bestaande commits buitenspel en maak je nieuwe aan die vergelijkbaar zijn maar anders. Als je commits ergens pusht en andere pullen deze en baseren daar werk op, en vervolgens herschrijf je die commits met `git rebase` en pusht deze weer, dan zullen je medewerkers hun werk opnieuw moeten mergen en zal het allemaal erg vervelend worden als je hun werk probeert te pullen in het jouwe. -Laten we eens kijken naar een voorbeeld hoe werk rebasen dat je publiek gemaakt hebt problemen kan veroorzaken. Stel dat je van een centrale server kloont en dan daar wat werk aan doet. Je commit historie ziet er uit als Figuur 3-36. +Laten we eens kijken naar een voorbeeld hoe werk rebasen dat je publiek gemaakt hebt problemen kan veroorzaken. Stel dat je van een centrale server cloned en dan daar wat werk aan doet. Je commit historie ziet er uit als Figuur 3-36. Insert 18333fig0336.png -Figuur 3-36. Kloon een repository, en doe wat werk daarop. +Figuur 3-36. Clone een repository, en doe wat werk daarop. -Nu doet iemand anders wat meer werk dat een merge bevat, en pushed dat werk naar de centrale server. Je fetched dat en merged de nieuwe remote branch in jouw werk, zodat je historie er uit ziet zoals Figuur 3-37. +Nu doet iemand anders wat meer werk wat een merge bevat, en pusht dat werk naar de centrale server. Je fetcht dat en merged de nieuwe remote branch in jouw werk, zodat je historie er uit ziet zoals Figuur 3-37. Insert 18333fig0337.png Figuur 3-37. Haal meer commits op, en merge ze in je werk. -Daarna, beslist de persoon die het werk gepushed heeft om terug te gaan en hun werk te gaan rebasen; ze voeren een `git push --force` uit om de historie op de server te herschrijven. Je pulled daarna van die server, waarbij je de nieuwe commits binnen krijgt. +Daarna, beslist de persoon die het werk gepusht heeft om erop terug te komen en in plaats daarvan zijn werk te gaan rebasen; hij voeren een `git push --force` uit om de historie op de server te herschrijven. Je pulled daarna van die server, waarbij je de nieuwe commits binnen krijgt. Insert 18333fig0338.png -Figuur 3-38. Iemand pushed gerebasete commits, daarbij commits buitenspel zettend waar jij werk op gebaseerd hebt. +Figuur 3-38. Iemand pusht gerebasede commits, daarbij commits buitenspel zettend waar jij werk op gebaseerd hebt. -Nu moet je dit werk opnieuw mergeen, hoewel je dat al gedaan hebt. Rebasen verandert de SHA-1 hashes van deze commits, dus voor Git zien ze er uit als nieuwe commits, terwijl je in feite het C4 werk al in je historie hebt (zie Figuur 3-39). +Nu moet je dit werk opnieuw mergen, terwijl je dat al gedaan hebt. Rebasen verandert de SHA-1 hashes van deze commits, dus voor Git zien ze er uit als nieuwe commits, terwijl je in feite het C4 werk al in je historie hebt (zie Figuur 3-39). Insert 18333fig0339.png -Figuur 3-39. Je merge hetzelfde werk opnieuw in een nieuwe merge commit. +Figuur 3-39. Je merget hetzelfde werk opnieuw in een nieuwe merge commit. -Je moet dat werk op een bepaald punt mergen, zodat je in de toekomst bij kunt blijven met de andere ontwikkelaar. Nadat je dat gedaan hebt, zal je history zowel de C4 als de C4' commits bevatten, die verschillende SHA-1 hashes hebben, maar die hetzelfde werk introduceren en dezelfde commit bericht hebben. Als je een `git log` uitvoert als je historie er zo uitziet, dan zul je twee commits zien die dezelfde auteur, datum en bericht hebben, wat verwarring geeft. Daarnaast zal je, als je deze historie pushed naar de server, al die gerebasete commits opnieuw introduceren op de centrale server, wat mensen nog meer kan verwarren. +Je moet dat werk op een gegeven moment mergen, zodat je in de toekomst bij kunt blijven met de andere ontwikkelaar. Nadat je dat gedaan hebt, zal je history zowel de C4 als de C4' commits bevatten, die verschillende SHA-1 hashes hebben, maar die hetzelfde werk introduceren en hetzelfde commit bericht hebben. Wanneer je een `git log` uitvoert als je historie er zo uitziet, dan zul je twee commits zien die dezelfde auteur, datum en bericht hebben, wat alleen maar verwarring geeft. Daarnaast zal je, als je deze historie pusht naar de server, al die gerebasede commits opnieuw introduceren op de centrale server, wat mensen nog meer kan verwarren. -Als je rebasen behandelt als een manier om commits op te ruimen ze bewerken voordat je ze pushed, en als je alleen commits rebaset die nog nooit publiekelijk beschikbaar zijn geweest, dan zal er niets aan de hand zijn. Als je commits rebaset die al publiekelijk gepushed zijn, en mensen kunnen werk gebaseerd hebben op die commits, bereid je dan maar voor op een aantal frustrerende problemen. +Als je rebasen behandelt als een manier om commits op te ruimen en ze te bewerken voordat je ze pusht, en als je alleen commits rebaset die nog nooit publiekelijk beschikbaar zijn geweest, dan zal er niets aan de hand zijn. Als je commits rebaset die al publiekelijk gepusht zijn, en mensen kunnen werk gebaseerd hebben op die commits, bereid je dan maar voor op een aantal frustrerende problemen. ## Samenvatting ## From 44936fd310fa33f7da16529fb782d0c817d0f06a Mon Sep 17 00:00:00 2001 From: Cor Date: Thu, 20 Feb 2014 12:55:31 +0100 Subject: [PATCH 027/478] [en] Chapter 06 Correct quotes and make suggestions for adjustments --- en/06-git-tools/01-chapter6.markdown | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/en/06-git-tools/01-chapter6.markdown b/en/06-git-tools/01-chapter6.markdown index 3eef10757..36459d56e 100644 --- a/en/06-git-tools/01-chapter6.markdown +++ b/en/06-git-tools/01-chapter6.markdown @@ -59,7 +59,7 @@ A lot of people become concerned at some point that they will, by random happens If you do happen to commit an object that hashes to the same SHA-1 value as a previous object in your repository, Git will see the previous object already in your Git database and assume it was already written. If you try to check out that object again at some point, you’ll always get the data of the first object. -However, you should be aware of how ridiculously unlikely this scenario is. The SHA-1 digest is 20 bytes or 160 bits. The number of randomly hashed objects needed to ensure a 50% probability of a single collision is about 2^80 (the formula for determining collision probability is `p = (n(n-1)/2) * (1/2^160))`. 2^80 is 1.2 x 10^24 or 1 million billion billion. That’s 1,200 times the number of grains of sand on the earth. +However, you should be aware of how ridiculously unlikely this scenario is. The SHA-1 digest is 20 bytes or 160 bits. The number of randomly hashed objects needed to ensure a 50% probability of a single collision is about 2^80 (the formula for determining collision probability is `p = (n(n-1)/2) * (1/2^160)`). 2^80 is 1.2 x 10^24 or 1 million billion billion. That’s 1,200 times the number of grains of sand on the earth. Here’s an example to give you an idea of what it would take to get a SHA-1 collision. If all 6.5 billion humans on Earth were programming, and every second, each one was producing code that was the equivalent of the entire Linux kernel history (1 million Git objects) and pushing it into one enormous Git repository, it would take 5 years until that repository contained enough objects to have a 50% probability of a single SHA-1 object collision. A higher probability exists that every member of your programming team will be attacked and killed by wolves in unrelated incidents on the same night. @@ -498,7 +498,7 @@ Again, if you don’t specify a stash, Git assumes the most recent stash: $ git stash show -p | git apply -R -You may want to create an alias and effectively add a `stash-unapply` command to your git. For example: +You may want to create an alias and effectively add a `stash-unapply` command to your Git. For example: $ git config --global alias.stash-unapply '!git stash show -p | git apply -R' $ git stash @@ -590,6 +590,10 @@ You need to edit the script so that it stops at the commit you want to edit. To When you save and exit the editor, Git rewinds you back to the last commit in that list and drops you on the command line with the following message: + + $ git rebase -i HEAD~3 Stopped at 7482e0d... updated the gemspec to hopefully work better You can amend the commit now, with From 5c49f5d9208933183d87bb8e28481cd4725f948f Mon Sep 17 00:00:00 2001 From: Cor Date: Thu, 20 Feb 2014 12:56:55 +0100 Subject: [PATCH 028/478] [nl] Chapter 06 - Review and retranslate --- nl/06-git-tools/01-chapter6.markdown | 249 +++++++++++++++------------ 1 file changed, 143 insertions(+), 106 deletions(-) diff --git a/nl/06-git-tools/01-chapter6.markdown b/nl/06-git-tools/01-chapter6.markdown index 9dbbf4cca..dbde96ed1 100644 --- a/nl/06-git-tools/01-chapter6.markdown +++ b/nl/06-git-tools/01-chapter6.markdown @@ -1,20 +1,55 @@ + # Git tools # Nu heb je de meeste commando's en werkwijzen geleerd die je dagelijks nodig hebt om een Git repository voor je broncode te beheren en te onderhouden. Je hebt de basistaken van het tracken en committen van bestanden onder de knie, en je hebt de kracht van de staging area en lichtgewicht topic branching en mergen in de vingers. -Nu ga je een aantal zeer krachtige dingen verkennen die Git kan, die je niet per se dagelijks gebruikt, maar die je op een bepaald moment toch nodig kunt gaan hebben. +Nu ga je een aantal zeer krachtige dingen verkennen die Git voor je kan doen, die je niet per se dagelijks gebruikt, maar die je op een bepaald moment toch nodig kunt gaan hebben. ## Revisie selectie ## -Git stelt je in staat om specifieke commits of een serie commits op diverse manieren te specificeren. Ze zijn niet per se voor de hand liggend, maar behulpzaam om te weten. +Git stelt je in staat om specifieke commits of een serie commits op diverse manieren te specificeren. Ze zijn niet meteen voor de hand liggend, maar behulpzaam om te weten. ### Enkele revisies ### -Natuurlijk kun je naar een commit refereren door de SHA-1 hash die het toegekend is, maar er zijn ook meer mensvriendelijke manieren om naar een commit te refereren. In deze paragraaf worden diverse manieren getoond waarop je naar een enkele commit kunt refereren. +Natuurlijk kun je naar een commit refereren met de SHA-1 hash die het toegekend is, maar er zijn ook meer mensvriendelijke manieren om naar een commit te refereren. In deze paragraaf worden diverse manieren getoond waarop je naar een enkele commit kunt refereren. ### Korte SHA ### -Git is slim genoeg om uit te vinden welke commit je bedoelde te typen als je het de eerste karakters geeft, zolang je gedeeltelijke SHA-1 minstens vier karakters lang en ondubbelzinnig is; dat wil zeggen dat slechts één object in de huidige repository begint met die gedeeltelijke SHA-1. +Git is slim genoeg om uit te vinden welke commit je bedoelde te typen als je het de eerste paar karakters geeft, zolang je gedeeltelijke SHA-1 maar minstens vier karakters lang en ondubbelzinnig is; dat wil zeggen dat slechts één object in de huidige repository begint met die gedeeltelijke SHA-1. Bijvoorbeeld, stel dat je om een specifieke commit te zien een `git log` commando uitvoert en de commit identificeert waarin je een bepaalde functionaliteit hebt toegevoegd: @@ -38,13 +73,13 @@ Bijvoorbeeld, stel dat je om een specifieke commit te zien een `git log` command added some blame and merge stuff -In dit geval, kiezen we `1c002dd....`. Als je op die commit `git show` uitvoert, dan zijn de volgende commando's gelijkwaardig (aangenomen dat de kortere versies ondubbelzinnig zijn): +Kies in dit geval `1c002dd....`. Als je op die commit `git show` uitvoert, dan zijn de volgende commando's gelijkwaardig (aangenomen dat de kortere versies ondubbelzinnig zijn): $ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b $ git show 1c002dd4b536e7479f $ git show 1c002d -Git kan met een korte unieke afkorting voor je SHA-1 waarde uit de voeten. Als je `--abbrev-commit` meegeeft aan het `git log` commando, dan zal de output kortere waarden gebruiken maar ze uniek houden; het gebruikt standaard zeven karakters maar maakt ze langer indien nodig om de SHA-1 ondubbelzinnig te houden: +Git kan met een korte unieke afkorting van een SHA-1 waarde uit de voeten. Als je `--abbrev-commit` meegeeft aan het `git log` commando, dan zal de output kortere waarden gebruiken maar ze uniek houden; het gebruikt standaard zeven karakters maar maakt ze langer indien nodig om de SHA-1 ondubbelzinnig te houden: $ git log --abbrev-commit --pretty=oneline ca82a6d changed the version number @@ -57,27 +92,28 @@ Over het algemeen zijn acht tot tien karakters meer dan voldoende om binnen een Veel mensen beginnen bezorgd te raken dat ze op een bepaald moment door puur toeval, twee objecten in hun repository hebben die naar dezelfde SHA-1 waarde hashen. Wat dan? -Mocht je een object committen dat hashed naar dezelfde SHA-1 waarde als een vorig object in je repository, dan zal Git het vorige reeds aanwezige object in je Git database zien en aannemen dat het al geschreven was. Als je dat object opnieuw probeert uit te checken op een bepaald moment, dan zul je altijd de gegevens van het eerste object krijgen. +Mocht je een object committen dat hashed naar dezelfde SHA-1 waarde als een vorig object in je repository, dan zal Git het vorige reeds aanwezige object in je Git database zien en aannemen dat het al geschreven was. Als je op een bepaald moment dat object opnieuw probeert uit te checken, dan zal je altijd de gegevens van het eerste object krijgen. -Maar, je moet je bewust zijn hoe vreselijk onwaarschijnlijk dit scenario is. De SHA-1 waarde is 20 bytes, of 160 bits. Het aantal benodigde random gehashte objecten om een 50% waarschijnlijkheid van een botsing te garanderen is ongeveer 2^80 (de formule om botsingswaarschijnlijkheid te bepalen is `p = (n(n-1)/2) * (1/2^160)`). 2^80 is 1.2 x 10^24 of 1 miljoen miljard miljard. Dat is 1.200 keer het aantal zandkorrels op de aarde. + +Maar wat je moet beseffen is hoe vreselijk onwaarschijnlijk dit scenario is. De SHA-1 waarde is 20 bytes, oftewel 160 bits. Het aantal benodigde random gehashte objecten om een 50% waarschijnlijkheid van een botsing te garanderen is ongeveer 2^80 (de formule om botsingswaarschijnlijkheid te bepalen is `p = (n(n-1)/2) * (1/2^160)`). 2^80 is 1.2 x 10^24 of 1 miljoen miljard miljard. Dat is 1.200 keer het aantal zandkorrels op aarde. -Hier is een voorbeeld om je een idee te geven wat er voor nodig is om een SHA-1 botsing te krijgen. Als alle 6.5 miljard mensen op aarde zouden programmeren, en iedere seconde zou ieder van hen code genereren die gelijk was aan de hele Linux kernel-geschiedenis (1 miljoen Git objecten) en dat in één gigantische Git repository pushen, dan zou het vijf jaar duren voordat die repository genoeg objecten zou bevatten om een 50% waarschijnlijkheid van één enkele SHA-1 object botsing te krijgen. Er bestaat een grotere kans dat elk lid van je programmeerteam zal worden aangevallen en gedood door wolven in ongerelateerde incidenten op dezelfde avond. +Hier is een voorbeeld om je een idee te geven wat er voor nodig is om een SHA-1 botsing te krijgen. Als alle 6.5 miljard mensen op aarde zouden programmeren, en iedere seconde zou ieder van hen code genereren die gelijk was aan de hele Linux kernel-geschiedenis (1 miljoen Git objecten) en dat in één gigantische Git repository pushen, dan zou het vijf jaar duren voordat die repository genoeg objecten zou bevatten om een 50% waarschijnlijkheid van één enkele SHA-1 object botsing te krijgen. De kans is groter dat elk lid van je programmeerteam zal worden aangevallen en gedood door wolven bij ongerelateerde incidenten op dezelfde avond. ### Branch referenties ### -De meest eenvoudige manier om een commit te specificeren heeft als voorwaarde dat je er een branchreferentie naar hebt wijzen. Dan kun je een branchnaam in ieder Git commando gebruiken dat een commitobject of SHA-1 waarde verwacht. Bijvoorbeeld, als je het laatste commitobject op een branch wil tonen, dan zijn de volgende commando's gelijk, aangenomen dat de `topic1` branch naar `ca82a6d` wijst: +De meest eenvoudige manier om een commit te specificeren heeft als voorwaarde dat je er een branchreferentie naar hebt wijzen. Dan kun je een branchnaam in ieder Git commando gebruiken dat een commitobject of SHA-1 waarde verwacht. Bijvoorbeeld, als je het laatste commitobject op een branch wil tonen, dan zijn de volgende commando's gelijkwaardig, aangenomen dat de `topic1` branch naar `ca82a6d` wijst: $ git show ca82a6dff817ec66f44342007202690a93763949 $ git show topic1 -Als je wil zien naar welke specifieke SHA een branch wijst, of als je wil zien wat ieder van deze voorbeelden in termen van SHA's voorstellen, dan kun je een Git sanitaire voorzieningen (plumbin) tool genaamd `rev-parse` gebruiken. Je kunt in Hoofdstuk 9 kijken voor meer informatie over plumbingtools, eigenlijk is `rev-parse` er voor low-level operaties en is niet ontworpen voor dagelijks gebruik. Maar het kan behulpzaam zijn op momenten dat je moet zien wat er echt aan de hand is. Hier kun je `rev-parse` uitvoeren op je branch. +Als je wilt zien naar welke specifieke SHA een branch wijst, of als je wil zien wat ieder van deze voorbeelden in termen van SHA's voorstellen, dan kun je een Git sanitaire voorzieningen (plumbing) tool genaamd `rev-parse` gebruiken. Je kunt in Hoofdstuk 9 kijken voor meer informatie over plumbingtools, eigenlijk is `rev-parse` er voor low-level operaties en is niet ontworpen voor dagelijks gebruik. Maar het kan behulpzaam zijn op momenten dat je moet zien wat er echt aan de hand is. Hier kun je `rev-parse` uitvoeren op je branch. $ git rev-parse topic1 ca82a6dff817ec66f44342007202690a93763949 -### RefLog verkorte namen ### +### RefLog afkortingen ### -Een van de dingen die Git in de achtergrond doet terwijl jij zit te werken is een reflog bijhouden: een log waar de staat van HEAD en branchreferenties in de laatste paar maanden in is vastgelegd. +Een van de dingen die Git in de achtergrond doet terwijl jij lekker zit te werken is een reflog bijhouden: een log waarin is vastgelegd naar welke referenties de HEAD en de branches de laatste paar maanden hebben gewezen. Je kunt je reflog zien door `git reflog` te gebruiken: @@ -94,7 +130,7 @@ Iedere keer als de punt van je branch om een of andere reden is gewijzigd, dan b $ git show HEAD@{5} -Je kunt deze syntax ook gebruiken om te zien waar een branch een bepaalde hoeveelheid tijd geleden was. Bijvoorbeeld, om te zien waar je `master` branch gisteren was, kun je dit typen +Je kunt deze syntax ook gebruiken om te zien waar een branch een bepaalde tijd geleden was. Bijvoorbeeld, om te zien waar je `master` branch gisteren was, kun je dit typen $ git show master@{yesterday} @@ -119,11 +155,11 @@ Om reflog informatie te zien, in hetzelfde formaat als de `git log` output, kun Merge commit 'phedders/rdocs' -Het is belangrijk om te zien dat deze informatie strikt lokaal is, het is een log van wat je hebt gedaan in jouw repository. De referenties zullen niet hetzelfde zijn in de kopie van de repository die iemand anders gemaakt heeft, en meteen nadat je een eerste kloon van een repository hebt gemaakt heb je een lege reflog, omdat er nog geen activiteit is geweest in je repository. `git show HEAD@{2.months.ago}` uitvoeren werkt alleen als je het project minstens twee maanden geleden gekloond hebt, als je het vijf minuten geleden gekloond hebt krijg je geen resultaten. +Het is belangrijk om op te merken dat deze informatie strikt lokaal is - het is een log van wat jij hebt gedaan in jouw repository. De referenties zullen niet hetzelfde zijn in de kopie van de repository die iemand anders gemaakt heeft; en meteen nadat je een eerste clone van een repository hebt gemaakt heb je een lege reflog, omdat er nog geen activiteit is geweest in je repository. `git show HEAD@{2.months.ago}` uitvoeren werkt alleen als je het project minstens twee maanden geleden gecloned hebt, als je het vijf minuten geleden gecloned hebt krijg je geen resultaten. ### Voorouder referenties ### -De andere veelgebruikte manier om een commit te specificeren is via zijn voorouders. Als je een `^` aan het einde van een referentie zet zal Git hieruit herleiden dat het de ouder van die commit betekent. +De andere veelgebruikte manier om een commit te specificeren is via zijn voorouders. Als je een `^` aan het einde van een referentie zet, zal Git hieruit herleiden dat het de ouder van die commit betekent. Stel dat je naar de geschiedenis van je project kijkt: $ git log --pretty=format:'%h %s' --graph @@ -146,7 +182,7 @@ Dan zie je de vorige commit door `HEAD^` te specificeren, wat "de ouder van HEAD Merge commit 'phedders/rdocs' -Je kunt ook een getal na de `^` zetten, bijvoorbeeld `d921970^2` betekent "de tweede ouder van d921970." Deze syntax is alleen bruikbaar voor merge commits, die meer dan één ouder hebben. De eerste ouder is de branch waar jij op was toen je mergede, en de andere is de commit op de branch die je gemerged hebt: +Je kunt ook een getal na de `^` zetten, bijvoorbeeld `d921970^2` betekent "de tweede ouder van d921970." Deze syntax is alleen nuttig voor merge commits, omdat die meer dan één ouder hebben. De eerste ouder is de branch waar jij op was toen je mergede, en de andere is de commit op de branch die je gemerged hebt: $ git show d921970^ commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b @@ -162,7 +198,7 @@ Je kunt ook een getal na de `^` zetten, bijvoorbeeld `d921970^2` betekent "de tw Some rdoc changes -De andere manier om voorouders mee te specificeren is de `~`. Dit refereert ook naar de eerste ouder, dus `HEAD~` en `HEAD^` zijn gelijk. Het verschil wordt pas duidelijk als je een getal specificeert. `HEAD~2` betekent "de eerste ouder van de eerste ouder", of "de grootouder", het doorloopt de eerste ouders het aantal keren dat je specificeert. Bijvoorbeeld, in de geschiedenis die eerder getoond werd, zou `HEAD~3` het volgende resultaat geven +De andere manier om voorouders mee te specificeren is de `~`. Dit refereert ook naar de eerste ouder, dus `HEAD~` en `HEAD^` zijn gelijk. Het verschil wordt pas duidelijk als je een getal specificeert. `HEAD~2` betekent "de eerste ouder van de eerste ouder", of "de grootouder" - het doorloopt de eerste ouders het aantal keren dat je specificeert. Bijvoorbeeld, in de geschiedenis die eerder getoond werd, zou `HEAD~3` het volgende resultaat geven $ git show HEAD~3 commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d @@ -184,43 +220,43 @@ Je kunt deze syntaxen combineren: je kunt de tweede ouder van de vorige referent ### Commit reeksen ### -Nu je individuele commits kunt specificeren, laten we zien hoe je reeksen van commits kunt specificeren. Dit is vooral erg bruikbaar bij het beheren van je branches; als je veel branches hebt, kan je reeks-specificaties gebruiken om vragen te beantwoorden als: "Wat voor werk zit er op deze branch dat ik nog niet in mijn hoofdbranch heb?" +Nu je individuele commits kunt specificeren, laten we zien hoe je reeksen van commits kunt specificeren. Dit is vooral erg nuttig bij het beheren van je branches - als je veel branches hebt, kan je reeks-specificaties gebruiken om vragen te beantwoorden als: "Wat voor werk zit er op deze branch dat ik nog niet in mijn hoofdbranch gemerged heb?" #### Dubbel-punt #### -De meest voorkomende reeks specificatie is de dubbel-punt syntax. Dit vraagt Git een reeks commits op te zoeken, die bereikbaar zijn van de ene commit maar niet vanuit een ander. Bijvoorbeeld, stel dat je een commit-geschiedenis hebt die eruit ziet zoals in Figuur 6-1. +De meest voorkomende reeks specificatie is de dubbel-punt syntax. Eigenlijk vraag je hiermee aan Git een reeks commits op te zoeken, die bereikbaar zijn van de ene commit maar niet vanuit een ander. Bijvoorbeeld, stel dat je een commit-geschiedenis hebt die eruit ziet zoals in Figuur 6-1. Insert 18333fig0601.png Figuur 6-1. Voorbeeldgeschiedenis voor reeks-selectie. -Je wilt zien wat er in je experimentele branch zit dat nog niet in je hoofdbranch gemerged is. Je kunt Git vragen om je een log te tonen van alleen die commits met `master..experiment`, wat zoveel betekent als "alle commits die bereikbaar zijn voor experiment, die niet bereikbaar zijn voor master". Om de voorbeelden kort en duidelijk te houden zal ik de letters van de commitobjecten in het diagram gebruiken in plaats van de echte log output, in de volgorde waarin ze getoond zouden worden: +Je wilt zien wat er in je experimentele branch zit dat nog niet in je hoofdbranch gemerged is. Je kunt Git vragen om een log te tonen van alleen die commits met `master..experiment`, wat zoveel betekent als "alle commits die bereikbaar zijn voor experiment, die niet bereikbaar zijn voor master". Om de voorbeelden kort en duidelijk te houden zal ik de letters van de commitobjecten in het diagram gebruiken in plaats van de echte log output, in de volgorde waarin ze getoond zouden worden: $ git log master..experiment D C -Als je echter het tegenovergestelde wilt zien: alle commits in `master` die niet bereikbaar zijn in `experiment`, dan moet je de branchnamen omdraaien. `experiment..master` toont je alles in `master` wat niet bereikbaar is vanuit `experiment`: +Als je echter het tegenovergestelde wilt zien - alle commits in `master` die niet in `experiment` zitten - dan moet je de branchnamen omdraaien. `experiment..master` toont je alles in `master` wat niet bereikbaar is vanuit `experiment`: $ git log experiment..master F E -Dit is handig als je de `experiment` branch up to date wilt houden en vast wilt zien wat je op het punt staat te mergen. Een ander veel voorkomend gebruik van deze syntax is zien wat je op het punt staat naar een remote de pushen: +Dit is handig als je de `experiment` branch up to date wilt houden en alvast wilt zien wat je op het punt staat te mergen. Een ander veel voorkomend gebruik van deze syntax is zien wat je op het punt staat naar een remote de pushen: $ git log origin/master..HEAD -Dit commando toont je alle commits in je huidige branch, die niet in de `master` branch op je remote `origin` zitten. Als je een `git push` uitvoert, en je huidige branch volgt de `origin/master`, dan zijn de commits die getoond worden door `git log origin/master..HEAD` de commits die verstuurd zullen worden naar de server. -Je kunt ook één kant van de syntax weglaten om Git de HEAD laten aannemen. Bijvoorbeeld, je krijgt dezelfde resultaten als in het vorige voorbeeld door `git log origin/master..` te typen; Git vult HEAD in als er één kant ontbreekt. +Dit commando toont je alle commits in je huidige branch, die niet in de `master` branch op de remote `origin` zitten. Als je een `git push` uitvoert, en je huidige branch volgt de `origin/master`, dan zijn de commits die getoond worden door `git log origin/master..HEAD` de commits die verstuurd zullen worden naar de server. +Je kunt ook één kant van de syntax weglaten om Git de HEAD laten aannemen. Bijvoorbeeld, je krijgt dezelfde resultaten als in het vorige voorbeeld door `git log origin/master..` te typen - Git vult HEAD in als er één kant ontbreekt. -#### Meerdere punten #### +#### Dubbele punten #### -De syntax met de dubbel-punt is makkelijk als een afkorting, maar misschien wil je meer dan twee branches specificeren om je revisie aan te geven, zoals het zien welke commits in één van een serie branches zit, die nog niet in de branch zit waar je nu op zit. Git laat je dit doen door of het `^` karakter te gebruiken, of `--not` voor iedere referentie waarvan je de bereikbare commits niet wilt zien. Dus deze drie commando's zijn gelijk: +De syntax met de dubbel-punt is makkelijk als een afkorting, maar misschien wil je meer dan twee branches specificeren om je revisie aan te geven, zoals het zien welke commits in één van de branches in een reeks zitten, die nog niet in de branch zitten waar je nu op werkt. Git laat je dit doen door of het `^` karakter of `--not`, te gebruiken voor iedere referentie waarvan je de bereikbare commits niet wilt zien. Dus deze drie commando's zijn gelijk: $ git log refA..refB $ git log ^refA refB $ git log refB --not refA -Dit is prettig omdat met deze syntax je meer dan twee referenties in je vraag kunt specificeren, wat je niet met de dubbel punt syntax kan. Bijvoorbeeld, als je alle commits wilt zien die bereikbaar zijn vanuit `refA` of `refB`, maar niet vanuit `refC`, dan kun je één van deze intypen: +Dit is prettig omdat met deze syntax je meer dan twee referenties in je vraag kunt specificeren, wat je niet met de dubbel punt syntax kan doen. Bijvoorbeeld, als je alle commits wilt zien die bereikbaar zijn vanuit `refA` of `refB`, maar niet vanuit `refC`, dan kun je één van deze intypen: $ git log refA refB ^refC $ git log refA refB --not refC @@ -252,7 +288,7 @@ Met deze tools, kun je Git eenvoudiger laten weten welke commit of commits je wi ## Interactief stagen ## -Bij Git zitten een aantal scripts, die sommige commandline taken makkelijker maken. Hier zul je een aantal interactieve commando's zien, die je kunnen helpen om je commits zo te maken dat ze alleen bepaalde combinaties en delen van bestanden bevatten. Deze tools zijn erg nuttig als je een serie bestanden aanpast en dan besluit dat je deze veranderingen in een aantal gefocuste commits wilt hebben in plaats van één grote rommelige commit. Op deze manier ben je er zeker van dat je commits logische aparte wijzigingensets zijn en makkelijk gereviewed kunnen worden door je mede-ontwikkelaars. +Bij Git worden een aantal scripts geleverd, die sommige commandline taken makkelijker maken. Hier zul je een aantal interactieve commando's zien, die je kunnen helpen om je commits zo samen te stellen dat ze alleen bepaalde combinaties en delen van bestanden bevatten. Deze tools zijn erg nuttig als je een reeks bestanden aanpast en dan besluit dat je deze wijzigingen in een aantal gefocuste commits wilt hebben in plaats van één grote rommelige commit. Op deze manier ben je er zeker van dat je commits logische aparte wijzigingensets zijn en makkelijk gereviewed kunnen worden door je mede-ontwikkelaars. Als je `git add` uitvoert met de `-i` of `--interactive` optie, dan schakelt Git over naar een interactieve shell modus, waarbij zoiets als dit getoond wordt: $ git add -i @@ -266,9 +302,9 @@ Als je `git add` uitvoert met de `-i` of `--interactive` optie, dan schakelt Git 5: patch 6: diff 7: quit 8: help What now> -Je kunt zien dat dit commando je een heel andere kijk op je staging area geeft: eigenlijk dezelfde informatie die je krijgt met het `git status` commando, maar dan compacter en meer informatief. Het toont links de wijzigingen die je gestaged hebt, en de niet gestagede wijzigingen rechts. +Je kunt zien dat dit commando je een heel andere kijk op je staging area geeft - eigenlijk dezelfde informatie die je krijgt met het `git status` commando, maar dan compacter en meer informatief. Het toont links de wijzigingen die je gestaged hebt, en de niet gestagede wijzigingen rechts. -Hierna volgt een commando-sectie. Hier kun je een aantal dingen doen, staging bestanden toevoegen, bestanden unstagen, delen van bestanden stagen, ongevolgde bestanden toevoegen, en diffs zien van wat gestaged is. +Hierna volgt een commando-sectie. Hier kun je een aantal dingen doen waaronder bestanden stagen, bestanden unstagen, delen van bestanden stagen, ungetrackte bestanden toevoegen, en diffs zien van wat gestaged is. ### Bestanden stagen en unstagen ### @@ -290,7 +326,7 @@ Om de TODO en index.html bestanden te stagen, kun je de getallen typen: 3: unchanged +5/-1 lib/simplegit.rb Update>> -De `*` naast ieder bestand geeft aan dat het bestand geselecteerd staat om gestaged te worden. Als je Enter indrukt na niets getypt te hebben op de `Update>>` prompt, dan zal Git alles wat geselecteerd staat pakken en voor je stagen: +De `*` naast ieder bestand geeft aan dat het bestand geselecteerd is om gestaged te worden. Als je Enter indrukt na niets getypt te hebben op de `Update>>` prompt, dan zal Git alles wat geselecteerd staat pakken en voor je stagen: Update>> updated 2 paths @@ -304,7 +340,7 @@ De `*` naast ieder bestand geeft aan dat het bestand geselecteerd staat om gesta 2: +1/-1 nothing index.html 3: unchanged +5/-1 lib/simplegit.rb -Nu kun je zien dat de TODO en index.html bestanden gestaged zijn, en het simplegit.rb bestand nog unstaged is. Als je het TODO bestand wilt unstagen op dit punt, dan gebruik je de `3` of `r` (voor revert) optie: +Nu kun je zien dat de TODO en index.html bestanden gestaged zijn, en het simplegit.rb bestand nog steeds unstaged is. Als je het TODO bestand nu wilt unstagen, dan gebruik je de `3` of `r` (voor revert) optie: *** Commands *** 1: status 2: update 3: revert 4: add untracked @@ -333,7 +369,7 @@ Als je nu nog eens naar je Git status kijkt, kun je zien dat je het TODO bestand 2: +1/-1 nothing index.html 3: unchanged +5/-1 lib/simplegit.rb -Om de diff te zien van wat je gestaged hebt, kun je het `6` of `d` (voor diff) commando gebruiken. Het toont je een lijst van je gestagede bestanden, en je kunt diegenen selecteren waarvan je de gestagede diff wilt zien. Dit is vergelijkbaar met het specificeren van `git diff --cached` op de commando regel: +Om de diff te zien van wat je gestaged hebt, kun je het `6` of `d` (voor diff) commando gebruiken. Het toont je een lijst van je gestagede bestanden, en je kunt de bestanden selecteren waarvan je de gestagede diff wilt zien. Dit is vergelijkbaar met het specificeren van `git diff --cached` op de commando regel: *** Commands *** 1: status 2: update 3: revert 4: add untracked @@ -355,7 +391,7 @@ Om de diff te zien van wat je gestaged hebt, kun je het `6` of `d` (voor diff) c