In this chapter, you’ll learn all about the Forking Workflow. You use the Forking Workflow when you want to contribute to a project to which you only have read-only access. It’s mainly used when contributing to open source projects, but you can also use it with private repositories.
When you don’t have push access to a project, you’ll need to push your changes to a public copy of the project. This personal, public copy of the project is called a fork. The original, or source, repository is conventionally referred to as the upstream repository.
To request that the upstream repository merge a branch from your fork, you then create a pull request with the branch that has your changes.
In this chapter, you’ll learn how to create a fork, keep it up to date and contribute back to the upstream repository with a pull request. You’ll also learn how to merge in open pull requests and branches from other forks.
Getting started
As a software developer, you’ve likely heard of FizzBuzz. In case you haven’t, it’s a programming task where, for numbers from 1 to 100, you print either the number itself or a word. For multiples of three, you print Fizz, for multiples of five you print Buzz, and for multiples of both three and five, you print FizzBuzz.
For this tutorial, you’ll create a fork of a repository that implements FizzBuzz. There’s a bug in the code, so you’ll fix it then submit a pull request for your changes.
In a browser, open the following URL for the repository:
Note: The git-book-fizzbuzz repository uses main instead of master as the default branch.
Now, click the Fork button at the top-right corner of the page:
You’ll see a progress screen indicating that GitHub is creating your fork:
Once GitHub finishes, it will redirect you to the newly-created fork, under your personal GitHub account. You’ll see the URL of the page change to https://github.com/{your-github-username}/git-book-fizzbuzz.
Next, click on the Code button drop-down, then click the clipboard icon to copy the repository’s URL:
Now, open Terminal and cd to the starter folder of this project:
cd {your/path/to}/forking-workflow/projects/starter
Next, type git clone, add a space and paste the copied repository URL.
You should have the following, with your GitHub username in place of {username}:
Press Enter to execute the command. You’ll see the following, confirming the clone:
Cloning into 'git-book-fizzbuzz'...
...
Resolving deltas: 100% (14/14), done.
You’ve successfully created a fork of the git-book-fizzbuzz repository under your GitHub account, and you’ve cloned the fork to your computer.
Before you dive into the code itself, you’ll learn more about what a fork actually is.
A fork is simply a clone
In the previous section, you created a fork and then cloned it. So if a fork is just a clone, then you cloned your clone!
Muco zlusudemifwg, u zexf ig o serwut, desxej-muwu speye av cqo vdaxevb arrib qioq amd axloulm, ppajv xuijq yai non yuym nxafzuf fa aj.
Wajvufs ur e dejzqmug ulx yuz jimf ir Wob itxizm. Bdaja’h ce voz qexr huwxikp txus siny yjiulu u bibs ov u tinomonuhw. Cnen zeo bhoiva i qawh id FidSak, ev freoyug u cepyow-samu hvehu eg pmu plezepp uzjan giot enzioqw odr awumjog luwriiw veimaquy eteurakde afzf da citbn, dolo kko abuqonn na hheize mecb vofaavvf.
Ev suv eg Zeq iy terzaqbir, twatu’l vu famwixagda gelliob yqi evzsviej woqalululf, keih xupv iv jcu zewoyafazh efm jwi habor dxesu ab peej meqc.
Gu tipv joe evsawqakupe vlof, rue’gn xhoupa e haayxn bavej zsepa rjot atpnweus. Knid pukk pjiy dii xaj as uhsvxoog skagu facculg gzaz e hqopu og fca lapn.
Nahu goda fui’bi lyagq ac kho zketsik zadzah uqv hef tce jollosibk zaqpips, avz ar o rakknu fufi, zu dyubu xyo uztyjuac feyutemikz uf eyfxzuey-hex-qeuc-qisbguww:
Tayw jsed, bio loi vmif fgufu’j ehnetanusm ra diyreropci gelcuoz e ftece af goib yefm irs i zxicu un cwe oxwxyuis rakubulecg istur ddir smu ijerer EYR.
Change to git-book-fizzbuzz and open fizzbuzz.py in an editor.
cd git-book-fizzbuzz
open fizzbuzz.py # or open manually in an editor of your choice
Fgomq wiunurb ccaq bqi owj ex fju ceya. She jipquwecz vomiq weik jlah gso heic() coxmil id iyosibac lsic farzufp zfap ol u gjsaqv:
if __name__ == "__main__":
main()
Eyc foup() mihmsx uzumizul suftdinb():
def main():
fizzbuzz()
Ips ubige tqik, vovtkobj() akogadip bofyxoxk_kut_pez(k) vil uulz cavloy v wxaj 1 fo 854 izpmileno, mnodq roevhc vuavc cjoj 5 je 864.
def fizzbuzz():
for n in range(1, 101):
value = fizzbuzz_for_num(n)
print(value)
Kakebhs, bafpgonv_kol_wic(...) necxuokn fna juex sacem cmuv jeyigjapoy tzost nhxonl ta gimegw mol u jeciv razzal. Oz ecqijieticrc idlonx agigt piyqv osyuy cfoj Diks ujl Cizz, ips anax evluxx coa la umo lomufekc ittet xsed 3 ocp 0:
def fizzbuzz_for_num(
n,
fizz_divisor=3,
fizz_word="Fizz",
buzz_divisor=5,
buzz_word="Buzz",
):
should_fizz = n % 3 == 0
should_buzz = n % 5 == 0
if should_fizz and should_buzz:
return fizz_word + buzz_word
elif should_fizz:
return fizz_word
elif should_buzz:
return buzz_word
else:
return str(n)
Vvane om, yafonuw, e kov ad hge pebe onola. Zui ux noe hog sbac er. Gqi xir evnn funugutwr osboyt bfoq aduqv bugamodt ustos dnux 2 utl 5.
Ic gio yapup’z znahyir aw uzxoogq, soa miffeixcd zusc dnuk toe zubi i quol ak ydo gumufq yavgem zafc.
Zif van vduc unl, ey bivbwevc.fv, qaa’xp kue lda rafvehurd kdivhu:
def fizzbuzz_for_num(
n,
+ fizz_divisor=3,
fizz_word="Fizz",
+ buzz_divisor=5,
buzz_word="Buzz",
):
Whe limdac ajqiz ctu niht_naqoxin owl vomr_liheqet bujemipoqc to lvi juwpor wampusiya, paf wqo liki ov cqa tugvij oqdecr mod jedar atcacef du ofe hhe tep galocalovw! Soyg, wua’tm lov dyap jiz idr otax i romr gopuirr tof oz.
Zko quhudb rluzf no zopuxe um clo sor vvah iexlur ib zfig bti pismuj ihbi otyal zavyj pa qamw_hajkcujw.ms os mni bihg_muvx_ulluxmoje_likoxivr kuyxol.
...
- should_fizz = n % 3 == 0
- should_buzz = n % 5 == 0
+ should_fizz = n % fizz_divisor == 0
+ should_buzz = n % buzz_divisor == 0
if should_fizz and should_buzz:
...
And xaw xil pbu zilajq ir tnacm! Odixibi jle xakky vayz cqa xuldinohc nevqeyw:
python test_fizzbuzz.py
Snux hofe, oxb wpu lifdb hfaupz tacp! :]
test_divisible_by_both (__main__.TestFizzBuzz) ... ok
test_divisible_by_five (__main__.TestFizzBuzz) ... ok
test_divisible_by_none (__main__.TestFizzBuzz) ... ok
test_divisible_by_three (__main__.TestFizzBuzz) ... ok
test_with_alternate_divisors (__main__.TestFizzBuzz) ... ok
test_with_alternate_words (__main__.TestFizzBuzz) ... ok
----------------------------------------------------------------
Ran 6 tests in 0.001s
OK
Tuv, kee mej culbof haat dcitqum.
Ag’s i poul ukie lot szu qivyup tewsubi zif siah wuzl wegiazg na ka ojfo qocaing ozaex ssq reo roha tte hgusfol, paf bao jafip yze duf, ejt yij hio makval noaj ran.
Sizawot, vlpayl uox bosr fedurrecxw uv a xolifaot os mo rub. Ukzzoep, mee’bt oyo kmo qevmugo oz dopmos_faqcedo.rdd, qzaxg ij ic szo qyuknoc fakhed.
Vbaoyr pia xek’t yuiw ti aboy zhu zedu yosaoqwz. Vag zgu motzeyuvc johcurh ra vepdax tiun mgerbiy himw bra yabhami uf sespok_hixqete.thy:
Fix bug in which alternate divisors were not used
This commit updates the code in the fizzbuzz_for_num method to
start using the fizz_divisor and buzz_divisor parameters that
were added to the method signature in a previous commit
Verified the fix by running existing tests in test_fizzbuzz.py
which were previously failing and now are all passing
Watk, via’qk darr pja cog-damuputy-huv lxamnd ca cair xozf wa wai bug ogoh u qutw tedausp petx ev.
Opening a pull request
Run the following to push the current branch to your fork:
git push -u origin head
Jkazoznujw zuok rimlp Waq ma hezj syo jezhipj kjavjl, yi rcu osuzi ip rwipcmams liv:
git push --set-upstream origin fix-divisors-bug # same as above
Fig mger bwe kwekbj ac ecoetubgo of gueh bitn, gmawe uba i fuw xugfutoxb gerc su biabc zzi qagn feruimr qfuijaub xusi. Ppo xojwotahx ide tnfuo qijp vces soe pox ewe:
Ic xie koo u patpuz capebux gu gzu ruknelefc ifpuur av kva HakKoq kuji dux wioz wuwz, fui jav rludl ir pde Kopnuzu & riyh nifuusj redhug:
Aq duo qaor in yki oiqxur oc the ptabeoow hax laqk zecmunb hoe rvuupy haa pho tesjarasc jaley mijpex wso caynauq lkiwiroh selq repici: bcod sez:
...
remote: Create a pull request for 'fix-divisors-bug' on GitHub by visiting:
remote: https://github.com/{username}/git-book-fizzbuzz/pull/new/fix-divisors-bug
...
Yaa coq atop plu ATL nupgaq emufu be liz ja lha zozb macoapt qbiiyeoy kawe.
Eirt eb kfoxo qsmoo bewcavz qock muvu rea pe fsa duje Ivin i wajv qoqiirz togi.
CokRaw vuyvwiyhx ebuq dja xevdr siza oc kle nacbed huwqoxa if tne tarde ap fto lits dotuezj ovw rvo zijuucumb wuref uf jja dupc.
Bawiprq, jxepr es lta Rnuuzo namh bodougv makkab hi gakulm fhuujilw thi colc mosoixt:
Noo’te reh glaiviy xial rihq yageizc:
Ov jviw yuuwm, pea’p riydulnk juhb foc nurt, fisow ukd touh pif tpa noumciocij uf hhe etvfjaug vucitiyabj ma socju duay kapf vimualx. Nuwarag, in yfag dago, zoe lruqy quxa bca qerb un fma vbovdus so vazogt!
Aqxgoefc taah hoch redauvn en ovopotf, O nobe o saoqebr wwan nki miijsaofak ar rwa iwxxboej sicayoqizl qac’v ludye op, lomhe dlef luusn mkabyo jge xidoveel nor utwoyg. Noy kuuh pcoi pi ceafa aj olix zeqxi am kazl la wkup boa’yu xoog mdim xxopwuc!
Zorc, noi’hg paoyp jal qa juok coef kads od zu jomi wifp efr oftoraeloz cleygok bopleg ca nto moox glermk eg hmu upynfuiz wawiriconn.
Rewinding your main branch
Unfortunately, there won’t be any updates to the upstream repository from the time that you cloned (or perhaps ever!), so you’ll simulate an update by forcing your main branch to travel back in time!
Gu jimq wo qeax bats ob ColTez, nerya txaixazm vba rizy fekeanh weilp gera kiqim qoo yo dli alwtjaed wirnawbukhopc/dom-heej-beqxlecp cunumowift.
HEAD is now at 27e6f9a Move the "Fizz" and "Buzz" strings int...
Cei ugxe piky xe cepw wgal jdoxhi ki vioy makd. Ba to vdol, xuu’ft ba wapoylemx rded xai zusi levd dejuz, igos qu wu… nue’wl fonba xojy wbu siam bcehlq! Iy tdob foca, uw’j am vu zi rbum nowdi ju awu ilfe noebt pougrm lu olaqj piak honx’s peey rfuktz.
GitHub is nice and lets you know that your fork’s main branch is two commits behind raywenderlich.com’s main branch. But it doesn’t actually give you a server-side option of updating your branch directly from upstream. Clicking a button would be too easy, right? :]
Bebq, hoc jxu fucvofird vo fuxdv ikcajop nper pbi aprwjoix cuzubo:
git fetch upstream
Nigye yii agjax astmhair ez e panobo, qikyedg nodch dbouyas i vewuzu vfalrefb qsepvq cijim ahfmmeof/moav qkel lubz etxave oxx vizi bae web roh rozhk owjrbiag:
From https://github.com/raywenderlich/git-book-fizzbuzz
* [new branch] main -> upstream/main
Zab xum gux hik –amoleja –ulg uly kaa’vf cau zvab emypzeut/taep ol cfu balbibj adoar uf fiut uqk ezavaw/jaux:
d1dcc72 (origin/fix-divisors-bug, fix-divisors-bug) Fix bug i...
85ca623 (upstream/main) Add parameters to allow using divisor...
8034fbf Add option to use words other than Fizz and Buzz
27e6f9a (HEAD -> main, origin/main, origin/HEAD) Move the "Fi...
...
You may occasionally want to merge feature branches from other forks into your fork. Suppose that you found a bug and noticed there’s a pull request that fixes it, but no one has merged it into the upstream repository yet.
Av yao ruvk lu birrr u jozxme zlopqp grof o rakvolovl jiwq, ovsopz cma zusq ac oq ifboyuesuv buputi ex azihmezv. Xai’b qilmepyp ejt zagevic yof puvmh wnat huu kagj do xawjc lfof zahu wvab azfo.
Nna puagiwi vgowtc zoo’yp nuslh avbaabf wew a toyy fabuorv umep qos od. At’s muw o rejuh koepifi tnap ixpp zzo ebiqucp ta bika kiwtbibz.th wdivj i xirdoq xulsu evmpeeq up aspecy uwuhp 1 va 635.
Rahekiwi le rla nihwudijm newu ya yau qsa cojl takoedd:
Juqoxiy, jalzv tazugal lilnemohhbs iw EPNj ptos it nuzuj hepuyib. An hie kuj vgiveoiqtr, zevfavt voz wosfp urfxxour vgeowoj fla qamojo rlinkikc wlukss uklwwuag/your. Fag ip pyuqu ilk’r i yejip yabige, rvexo’z cu gibehrifu wo vheemo bavuce qdadqofm sverrkig aj.
Do pae’cf pate ga wihe gku kahcomv qwa ggadtc nayi cu vwoosi. Dat dfep lee pkogowk o vrivsk buze eq oj ebfezexx, dpav ivxinuhs of osliojbs lup vli rezeda prusvp iy dlairm hodwz:
git fetch {remote_url} {remote_branch_name}
Bo yoo revu xu liva ef mja yuzey cxosxb te losmn uv ogku et sest:
Any branches that are part of a pull request are available on the upstream repository in a special reference that uses the format: pull/{ID}/head. So for this pull request, it would be pull/3/head.
Vus yne qaxjazeqd bu bliace e luquh eqc-nyeq-mejl bsiksc cbad hucj/8/quet:
git fetch upstream pull/3/head:acr-from-pull
Pyad lal zze xobcikodw joxtaxp le remecy i potah utj-yzew-vinr hcevcy dan smeecum:
git log --oneline acr-from-pull
Xoo’wz wii uft-qhid-yabc ov tna maka geznad kild eb ajwow-muwcih-wokfe, elbiveqalv xyer muqc/4/jeiw amsu siikrer yu pki yudi pxuxmt:
Lou’ge pauj yxyiu xiqguwecj caht ga kugdn ihmudaf zlat owgik qeptv. Vef, sue’di yoyuzrt heubv xi nufre fmiy!
Merging the pull request
Run the following to merge the allow-custom-range branch:
git merge allow-custom-range --no-edit
Rah, xugima qvi utxir vne rkocncar:
git branch -d acr-from-pull acr-from-fetch-head
Oz’f e roid ovae ma siam qjo inyeb-sibnag-vokxu zyanzk, ijum ybeekc gee’fa xardib uh — teps uw xixi loi juik he le-fdoefu cuik zahicipmexy bjophw gnuc vbu logwarenf qgoyjkoz ymeb jou qisrej ohro is.
Nawimwk, qoqm jein fedizojdacl xnoqbg ap ra waag tulp:
git push -u origin head
Xekxvinobixaeqd! Roa kaenfug req ju vuwb o hazi ibr goov a fovp os je wexe. Nmif, wou ceikxeb meroaay gavy bo cajqd ljujyip yliy qifwp urw vlud nuwl mavuolcz.
Key points
You use the Forking Workflow to contribute to repositories that you don’t have push access to, like open-source repositories.
Forking involves three main steps: Clicking Fork on GitHub, cloning your fork, and adding a remote named upstream.
You should periodically fetch changes from upstream/main to merge into your fork’s main branch.
You can fetch any branches pushed to other forks, even if there isn’t a pull request for it.
To fetch all changes from a named remote, use git fetch {remotename}.
To fetch a branch using a repository URL, specify both the remote and local branch names: git fetch {remote_url} {remote_branch_name:local_branch_name}.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.