Bijdragen aan een project
Je weet wat de verschillende werkwijzen zijn, en je zou een goed beeld moeten hebben van fundamenteel Git gebruik. 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 gebeurd. 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 actieve bijdrage grootte, gekozen werkwijze, je commit toegang, een mogelijk de externe bijdrage methode.
De eerste variabele is de actieve bijdrage grootte. 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 slaperige projecten. Voor zeer grote bedrijven of projecten kan het aantal ontwikkelaars in de duizenden zijn, 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 toegepast kan worden of eenvoudig samengevoegd kan worden. Wijzigingen die je toevoegt kunnen verouderd of zwaar beschadigd raken door werk dat samengevoegd 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 volgende variabele is de gebruikte werkwijze in je project. Is het gecentraliseerd, waarbij iedere ontwikkelaar gelijkwaardige schrijftoegang heeft tot de hoofd codebasis? Heeft het project een eigenaar of integrator die alle patches nakijkt? Zijn alle patches gereviewed en goedgekeurd? Ben jij betrokken bij dat proces? Is er een luitenanten systeem in werking, 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 wel schrijftoegang hebt tot het project dan als je dat niet hebt. Als je geen schrijftoegang hebt, wat heeft het project dan als voorkeur om bijdragen te ontvangen? Heeft het wel 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 van ieder van deze aspecten wat behandelen in een aantal gevallen, 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 construeren vanuit deze voorbeelden.
Commit richtlijnen
Voordat je gaat kijken naar de specifieke gebruiksscenario’s, volgt hier een kort stukje over commit berichten. Het hebben van een goede richtlijn voor het maken commits en je daar aan houden maakt het werken met Git en samenwerken met anderen een stuk makkelijker. Het Git project levert een document waarin een aantal tips staan voor het maken van commits van waar je patches uit kunt indienen – je kunt het lezen in de Git broncode in het Documentation/SubmittingPatches
bestand.
Als eerste wil je geen witruimte fouten indienen. Git geeft je een eenvoudige manier om hierop te controleren – voordat je commit, voer git diff --check
uit, wat mogelijke witruimte fouten identificeert en ze voor je afdrukt. Hier is een voorbeeld, waarbij ik een rode terminal kleur hebt vervangen door X
en:
$ git diff --check
lib/simplegit.rb:5: trailing whitespace.
+ @git_dir = File.expand_path(git_dir)XX
lib/simplegit.rb:7: trailing whitespace.
+ XXXXXXXXXXX
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 andere ontwikkelaars boos kunnen maken.
Daarna, probeer om iedere van 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). Het snapshot van het project is gelijk of je nu één commit doet of vijf, zolang alle wijzigingen maar toegevoegd zijn op een bepaald punt, 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 op te halen 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 applicaties om te helpen een schone en begrijpelijke historie op te bouwen.
Het laatste ding 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. Als een algemene regel, zouden je berichten moeten beginnen met een enkele regel, die niet langer is dan 50 karakters en die de set wijzigingen beknopt omschrijft, gevolgd door een lege regel. Daarna volgt de 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
Gedetailleerdere tekst uitleg, als nodig. Laat het in ongeveer 72
karakters afbreken. In sommige contexten, wordt de eerste regel
behandeld als het onderwerp van een email en de rest als inhoud.
De lege regel die de samenvatting scheidt van de inhoud is van
kritiek belang (tenzij je de inhoud helemaal weglaat); applicaties
zoals rebase kunnen in de war raken als je ze samenvoegt.
Vervolg paragrafen komen na lege regels.
- Aandachtspunten zijn ook goed.
- Typisch wordt een streepje of sterretje gebruikt als punt, voorafgegaan
door een enkele spatie, met ertussen lege regels, maar de conventies
variëren hierin.
Als al je commit berichten er zo uit zien, dan zullen de dingen een stuk eenvoudiger zijn voor jou en de ontwikkelaars waar je mee werkt. Het Git project heeft goed geformatteerde commit berichten – ik raad je aan om git log --no-merges
uit te voeren om te zien hoe een goed geformatteerde project-commit historie eruit ziet.
In de volgende voorbeelden, en verder door de rest van dit boek, zal ik omwille van bondigheid de berichten niet zo netjes als dit formatteren; in plaats daarvan gebruik ik de -m
optie voor git commit
. Doe wat ik zeg, niet wat ik doe.
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 terugzet toegang op het 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 samenvoegen, maar de werkwijze kan erg vergelijkbaar zijn; het grote verschil is dat het samenvoegen 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
Initialized empty Git repository in /home/john/simplegit/.git/
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'removed invalid default value'
[master 738ee87] removed invalid default value
1 files changed, 1 insertions(+), 1 deletions(-)
De tweede ontwikkelaar, Jessica, doet hetzelfde – cloned de repository en commit een wijziging:
# Jessica's Machine
$ git clone jessica@githost:simplegit.git
Initialized empty Git repository in /home/jessica/simplegit/.git/
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'add reset task'
[master fbff5bc] add reset task
1 files changed, 1 insertions(+), 0 deletions(-)
Nu zet Jessica haar werk terug op de server:
# Jessica's Machine
$ git push origin master
...
To jessica@githost:simplegit.git
1edee6b..fbff5bc master -> master
John probeert ook zijn werk terug te zetten:
# John's Machine
$ git push origin master
To john@githost:simplegit.git
! [rejected] master -> master (non-fast forward)
error: failed to push some refs to 'john@githost:simplegit.git'
John mag niet terugzetten omdat Jessica in de tussentijd teruggezet heeft. Dit is in het bijzonder belangrijk om te begrijpen als je gewoon bent aan Subversion, omdat het je zal opvallen dat de twee ontwikkelaars niet hetzelfde bestand hebben aangepast. Alhoewel Subversion automatisch zo’n samenvoeging op de server doet, als verschillende bestanden zijn aangepast, moet je in Git de commits lokaal samenvoegen. John moet Jessica’s wijzigingen ophalen en ze samenvoegen voor hij terug mag zetten:
$ git fetch origin
...
From john@githost:simplegit
+ 049d078...fbff5bc master -> origin/master
Op dit punt ziet John’s lokale repository er ongeveer uit zoals Figuur 5-4.

Figuur 5-4. John’s initiële repository.
John heeft een referentie naar de wijzigingen die Jessica teruggezet heeft, maar hij moet ze samenvoegen met zijn eigen werk voordat hij het terug mag zetten:
$ git merge origin/master
Merge made by recursive.
TODO | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
Het samenvoegen gaat soepel – de commit historie van John ziet er nu uit als Figuur 5-5.

Figuur 5-5. John’s repository na het samenvoegen 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 samengevoegde werk terugzetten op de server:
$ git push origin master
...
To john@githost:simplegit.git
fbff5bc..72bbc59 master -> master
Tenslotte ziet John’s commit historie eruit als Figuur 5-6.

Figuur 5-6. John’s historie na teruggezet te hebben op de origin van de server.
In de tussentijd heeft Jessica gewerkt op een onderwerp branch. Ze heeft een onderwerp 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.

Figuur 5-7. Jessica’s initiële commit historie.
Jessica wil met John synchroniseren, dus ze haalt de wijzigingen op:
# Jessica's Machine
$ git fetch origin
...
From jessica@githost:simplegit
fbff5bc..72bbc59 master -> origin/master
Dit haalt het werk op dat John in de tussentijd teruggezet heeft. Jessica’s historie ziet er nu uit als Figuur 5-8.

Figuur 5-8. Jessica’s historie na het ophalen van John’s wijzigingen.
Jessica denkt dat haar onderwerp branch nu klaar is, maar ze wil weten wat ze in haar werk moet samenvoegen zodat ze terug kan zetten. Ze voert git log
uit om dat uit te zoeken:
$ git log --no-merges origin/master ^issue54
commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: John Smith <jsmith@example.com>
Date: Fri May 29 16:01:27 2009 -0700
removed invalid default value
Nu kan Jessica het werk van haar onderwerp samenvoegen in haar master branch, John’s werk (origin/master
) in haar master
branch samenvoegen, en dat naar de server terugzetten. Eerst schakelt ze terug naar haar master branch om al dit werk te integreren:
$ git checkout master
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. De snapshot aan het einde zou 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
Fast forward
README | 1 +
lib/simplegit.rb | 6 +++++-
2 files changed, 6 insertions(+), 1 deletions(-)
Er doen zich geen problemen voor; zoals je kunt zien was het een eenvoudige fast-forward. Nu voegt Jessica John’s werk in (origin/master
):
$ git merge origin/master
Auto-merging lib/simplegit.rb
Merge made by recursive.
lib/simplegit.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
Alles voegt netjes samen, en Jessica’s historie ziet er uit als Figuur 5-9.

Figuur 5-9. Jessica’s historie na het samenvoegen van John’s wijzigingen.
Nu is origin/master
bereikbaar vanuit Jessica’s master
branch, dus ze zou in staat moeten zijn om succesvol terug te kunnen zetten (er vanuit gegaan dat John in de tussentijd niets teruggezet heeft):
$ git push origin master
...
To jessica@githost:simplegit.git
72bbc59..8059c15 master -> master
Iedere ontwikkelaar heeft een paar keer gecommit en elkaars werk succesvol samengevoegd; zie Figuur 5-10.

Figuur 5-10. Jessica’s historie na alle wijzigingen teruggezet te hebben op de server.
Dat is één van de eenvoudigste werkwijzen. Je werkt een tijdje, over het algemeen in een onderwerp branch, en voegt samen in je master branch als het klaar is om te worden geïntegreerd. Als je dat werk wilt delen, dan voeg je het samen in je eigen master branch, en vervolgens haal je origin/master
op en voegt het samen als het gewijzigd is, en als laatste zet je terug op de master
branch op de server. De algemene volgorde is zoiets als die getoond in Figuur 5-11.

Figuur 5-11. Algemene volgorde van gebeurtenissen voor een eenvoudige multi-ontwikkelaar Git werkwijze.
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.
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 ingenieurs, en de master
branch van het hoofd repo alleen kan worden vernieuwd door die ingenieurs. 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 verschillend ontwikkelaars in deze omgeving. Aangenomen dat ze haar repository al gecloned heeft, besluit ze 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
Switched to a new branch "featureA"
$ vim lib/simplegit.rb
$ git commit -am 'add limit to log function'
[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 zet haar commits op de featureA
branch terug naar de server. Jessica heeft geen terugzet toegang op de master
branch – alleen de integratoren hebben dat – dus ze moet naar een andere branch terugzetten om samen te kunnen werken met John:
$ git push origin featureA
...
To jessica@githost:simplegit.git
* [new branch] featureA -> featureA
Jessica e-mailt John om hem te zeggen dat ze wat werk teruggezet 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
$ git checkout -b featureB origin/master
Switched to a new branch "featureB"
Nu doet Jessica een paar commits op de featureB
branch:
$ vim lib/simplegit.rb
$ git commit -am 'made the ls-tree function recursive'
[featureB e5b0fdc] made the ls-tree function recursive
1 files changed, 1 insertions(+), 1 deletions(-)
$ vim lib/simplegit.rb
$ git commit -am 'add ls-files'
[featureB 8512791] add ls-files
1 files changed, 5 insertions(+), 0 deletions(-)
Jessica’s repository ziet eruit als Figuur 5-12.

Figuur 5-12. Jessica’s initiële commit historie.
Ze is klaar om haar werk terug te zetten, maar ze krijgt een e-mail van Josie dat een branch met wat initieel werk erin al teruggezet is naar de server als featureBee
. Jessica moet die wijzigingen eerst samenvoegen met haar eigen voordat ze terug kan zetten naar de server. Ze kan dan Josie’s wijzigingen ophalen met git fetch
:
$ git fetch origin
...
From jessica@githost:simplegit
* [new branch] featureBee -> origin/featureBee
Jessica kan dit nu samenvoegen in haar werk met git merge
:
$ git merge origin/featureBee
Auto-merging lib/simplegit.rb
Merge made by recursive.
lib/simplegit.rb | 4 ++++
1 files changed, 4 insertions(+), 0 deletions(-)
Er is wel een klein probleem – ze moet het samengevoegde 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:
$ git push origin featureB:featureBee
...
To jessica@githost:simplegit.git
fba9af8..cd685d1 featureB -> featureBee
Dit wordt een refspec genoemd. Zie Hoofdstuk 9 voor een gedetailleerdere discussie van Git refspecs en de verschillende dingen die je met ze kan doen.
Vervolgens e-mailt John naar Jessica om te zeggen dat hij wat wijzigingen naar de featureA
branch teruggezet 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
...
From jessica@githost:simplegit
3300904..aad881d featureA -> origin/featureA
Daarna kan ze zien wat er veranderd is met git log
:
$ git log origin/featureA ^featureA
commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6
Author: John Smith <jsmith@example.com>
Date: Fri May 29 19:57:33 2009 -0700
changed log output to 30 from 25
Uiteindelijk voegt ze John’s werk in haar eigen featureA
branch:
$ git checkout featureA
Switched to branch "featureA"
$ git merge origin/featureA
Updating 3300904..aad881d
Fast forward
lib/simplegit.rb | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
Jessica wil iets fijnstellen, dus doet ze nog een commit en zet dit terug naar de server:
$ git commit -am 'small tweak'
[featureA ed774b3] small tweak
1 files changed, 1 insertions(+), 1 deletions(-)
$ git push origin featureA
...
To jessica@githost:simplegit.git
3300904..ed774b3 featureA -> featureA
Jessica’s commit historie ziet er nu uit zoals Figuur 5-13.

Figuur 5-13. Jessica’s historie na het committen op een functie 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 ze die branches in de hoofdlijn geïntegreerd hebben, zal een fetch de nieuwe samenvoeg commits ophalen, waardoor de commit historie er uit ziet zoals Figuur 5-14.

Figuur 5-14. Jessica’s historie na het samenvoegen van allebei haar onderwerp branches.
Veel groepen schakelen om naar Git voor deze mogelijkheid om meerdere teams in parallel te kunnen laten werken, waarbij de verschillende lijnen van werk laat in het proces samengevoegd worden. De mogelijkheid van kleinere subgroepen of een team om samen te werken via remote branches zonder het betrekken of dwarsliggen van het hele team is een enorm voordeel van Git. De volgorde van de werkwijze die je hier zag is ongeveer zoals Figuur 5-15.

Figuur 5-15. Basale volgorde van de werkwijze van dit aangestuurde team.
Klein publiek project
Het bijdragen aan publieke projecten gaat wat anders. Omdat je niet de toestemming hebt om de branches van het project te vernieuwen, moet je het werk op een andere manier naar de beheerders krijgen. Dit eerste voorbeeld beschrijft het bijdragen via afsplitsen op Git hosts die eenvoudig afsplitsen ondersteunen. De repo.or.cz en GitHub hosting sites ondersteunen dit allebei, en veel project beheerders verwachten deze soort bijdrage. Het volgende deel behandelt projecten die de voorkeur hebben aan bijgedragen patches via e-mail.
Eerst wil je waarschijnlijk het hoofdrepository clonen, een onderwerp branch maken voor de patch of patch serie die je van plan bent bij te dragen, en je werk daarop doen. De volgorde ziet er in basis zo uit:
$ git clone (url)
$ cd project
$ git checkout -b featureA
$ (work)
$ git commit
$ (work)
$ git commit
Je wil misschien de rebase -i
optie gebruiken om je werk in één enkele commit samen te persen, of het werk in de commits herschikken om de patch eenvoudiger te kunnen laten reviewen door de beheerders – zie Hoofdstuk 6 voor meer informatie over het interactief rebasen.
Als je werk op de branch af is, en je klaar bent om het bij te dragen aan de beheerders, ga dan naar de originele project pagina en klik op de “Fork” knop, waarmee je een eigen schrijfbare fork van het project maakt. Je moet dit dan in een nieuwe repository URL toevoegen als een tweede remote, in dit geval myfork
genaamd:
$ git remote add myfork (url)
Je moet je werk hier naar terugzetten. Het is het makkelijkst om de remote branch waar je op zit te werken terug te zetten naar je repository, in plaats van het samenvoegen in je master branch en die terug te zetten. De reden is dat als het werk niet wordt geaccepteerd of ge-cherry picked, je je master branch niet hoeft terug te draaien. Als de beheerders je werk samenvoegen, rebasen of cherry picken, dan krijg je het uiteindelijk toch terug door hun repository binnen te halen:
$ git push myfork featureA
Als jouw werk teruggezet is naar je fork, dan moet je de beheerder waarschuwen. Dit wordt vaak een pull request (haal binnen verzoek) genoemd, en je kunt het of 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 beheerder e-mailen.
Het request-pull
commando accepteert de basis branch waarin je je onderwerp branch binnen gehaald wil hebben, en de URL van het Git repository waarvan je ze wil laten halen, en voert een samenvatting uit van alle wijzigingen die je binnengehaald wenst te hebben. Bijvoorbeeld, als Jessica John een pull request wil sturen, en ze heeft twee commits gedaan op de onderwerp branch die ze zojuist teruggezet heeft, dan kan ze dit uitvoeren:
$ git request-pull origin/master myfork
The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40:
John Smith (1):
added a new function
are available in the git repository at:
git://githost/simplegit.git featureA
Jessica Smith (2):
add limit to log function
change log output to 30 from 25
lib/simplegit.rb | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)
De uitvoer kan naar de beheerder gestuurd worden – het verteld ze waar het werk vanaf gebranched is, vat de commits samen, en verteld waar ze dit werk vandaan kunnen halen.
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 onderwerp branches die je eenvoudig weg kunt gooien als ze geweigerd worden. Als je je werk thema’s gescheiden hebt in onderwerp branches maakt dat het ook eenvoudiger voor jou om je werk te rebasen als de punt van het hoof repository in de tussentijd verschoven is en je commits niet langer netjes toegepast kunnen worden. Bijvoorbeeld, als je een tweede onderwerp wil bijdragen aan een project, ga dan niet verder werken op de onderwerp branch die je zojuist teruggezet hebt – begin opnieuw vanaf de master
branch van het hoofd repository:
$ git checkout -b featureB origin/master
$ (work)
$ git commit
$ git push myfork featureB
$ (email maintainer)
$ git fetch origin
Nu zijn al je onderwerpen opgeslagen in een silo – vergelijkbaar met een patch rij – die je kunt herschrijven, rebasen en wijzigen zonder dat de onderwerpen elkaar in de weg zitten of afhankelijk zijn zoals in Figuur 5-16.

Figuur 5-16. Initiële commit historie met werk van featureB.
Stel dat de project beheerder een berg andere patches binnengehaald heeft en je eerste branch geprobeerd heeft, maar dat die niet langer netjes samenvoegt. In dit geval kun je proberen die branch te rebasen op de punt van origin/master
, de conflicten proberen op te lossen voor de beheerder, en dan je wijzigingen opnieuw aanbieden:
$ git checkout featureA
$ git rebase origin/master
$ git push –f myfork featureA
Dit herschrijft je geschiedenis zodat die eruit ziet als in Figuur 5-17.

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 terug te zetten (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 veranderd. Je zult deze kans ook gebruiken om het werk dat gebaseerd is van de huidige master
branch van het project af te halen. Je begint een nieuwe branch gebaseerd op de huidige origin/master
branch, perst de featureB
wijzigingen hier samen, lost conflicten op, doet de implementatie wijziging, en zet dat terug als een nieuwe branch:
$ git checkout -b featureBv2 origin/master
$ git merge --no-commit --squash featureB
$ (change implementation)
$ git commit
$ git push myfork featureBv2
De --squash
optie pakt al het werk op de samengevoegde branch en perst dat samen in één non-merge commit bovenop de branch waar je op zit. De --no-commit
optie verteld Git dat hij niet automatisch een commit moet vastleggen. Dit staat je toe om alle wijzigingen van een andere branch te introduceren en dan meer wijzigingen te doen, alvorens de commit vast te leggen.
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).

Figuur 5-18. Commit historie na het featureBv2 werk.
Publiek groot project
Veel grote projecten hebben procedures voor het accepteren van patches vastgelegd – je zult de specifieke regels voor ieder project moeten bekijken, omdat ze zullen verschillen. Maar, veel grote projecten accepteren patches via ontwikkelaar maillijsten, dus ik zal zo’n voorbeeld nu laten zien.
De werkwijze is vergelijkbaar met het vorige geval – je maakt onderwerp branches voor iedere patch waar je aan werkt. Het verschil is hoe je die indient bij het project. In plaats van het project te forken en naar je eigen schrijfbare versie terug te zetten, genereer je e-mail versies van iedere commit serie en e-mailt die naar de ontwikkelaar maillijst:
$ git checkout -b topicA
$ (work)
$ git commit
$ (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 e-mailen naar de lijst – het vormt ieder 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 de commit introduceert als de inhoud. Het fijne hieraan is dat het toepassen van een patch uit een e-mail die gegenereerd is met format-patch
alle commit informatie goed behoudt, zoals je in het volgende gedeelte meer zult zien als je deze commits toepast:
$ git format-patch -M origin/master
0001-add-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
Het format-patch
commando voert de namen uit van de patch bestanden die het maakt. De -M
optie verteld Git te kijken naar hernoemingen. De bestanden komen er uiteindelijk zo uit te zien:
$ cat 0001-add-limit-to-log-function.patch
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function
Limit log functionality to the first 20
---
lib/simplegit.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 76f47bc..f9815f1 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -14,7 +14,7 @@ class SimpleGit
end
def log(treeish = 'master')
- command("git log #{treeish}")
+ command("git log -n 20 #{treeish}")
end
def ls_tree(treeish = 'master')
--
1.6.2.rc1.20.g8c5b.dirty
Je kunt deze patch bestanden ook aanpassen om meer informatie voor de maillijst toe te voegen, die je niet in het commit bericht wil laten zien. 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 e-mailen naar een maillijst, kun je het bestand in je e-mail applicatie plakken of het sturen via een commandoregel programma. Het plakken van de tekst veroorzaakt vaak formaat problemen, in het bijzonder bij “slimmere” clients die geen harde returns en andere witruimte juist behouden. Gelukkig levert Git een applicatie die je helpt om juist geformatteerde patches via IMAP te versturen, wat makkelijker voor je kan zijn. Ik zal demonstreren hoe je een patch via Gmail stuurt, wat de e-mail applicatie is die ik 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 aan het einde moet je config bestand er ongeveer zo uitzien:
[imap]
folder = "[Gmail]/Drafts"
host = imaps://imap.gmail.com
user = user@gmail.com
pass = p4ssw0rd
port = 993
sslverify = false
Als je IMAP server geen SSL gebruikt, zijn de laatste twee regels waarschijnlijk niet nodig, en de waarde voor host zal imap://
zijn in plaats van imaps://
. Als dat ingesteld is, kun je git send-email
gebruiken om de patch serie in de Drafts map van de gespecificeerde IMAP server te zetten:
$ 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 <jessica@example.com>]
Emails will be sent from: Jessica Smith <jessica@example.com>
Who should the emails be sent to? jessica@example.com
Message-ID to be used as In-Reply-To for the first email? y
Dan spuugt Git een berg log informatie uit, die er zoiets als dit uitziet, voor iedere patch die je stuurt:
(mbox) Adding cc: Jessica Smith <jessica@example.com> from
\line 'From: Jessica Smith <jessica@example.com>'
OK. Log says:
Sendmail: /usr/sbin/sendmail -i jessica@example.com
From: Jessica Smith <jessica@example.com>
To: jessica@example.com
Subject: [PATCH 1/2] added limit to log function
Date: Sat, 30 May 2009 13:29:15 -0700
Message-Id: <1243715356-61726-1-git-send-email-jessica@example.com>
X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty
In-Reply-To: <y>
References: <y>
Result: OK
Op dit punt zou je in staat moeten zijn om naar je Drafts map te gaan, het To veld te wijzigen in de maillijst waarnaar je de patch stuurt, misschien de beheerder of verantwoordelijke persoon voor dat gebied op de CC te zetten, en het weg te sturen.
Samenvatting
Dit gedeelte heeft een aantal vaak voorkomende werkwijzen behandeld, om om te gaan met een aantal zeer verschillende typen Git projecten die je waarschijnlijk zult tegen komen en een aantal nieuwe programma’s geïntroduceerd, die je helpen om dit proces te beheren. Vervolgens zul je zien hoe je aan de andere kant van de medaille werkt: een Git project beheren. Je zult leren hoe een welwillende dictator of integratie manager te zijn.