Git
Chapters ▾ 2nd Edition

3.5 Клонове в Git - Отдалечени клонове

Отдалечени клонове

Отдалечените референции са указатели към вашите отдалечени хранилища, вкл. клонове, тагове и др. Можете да получите списък на всички отдалечени указатели изрично с командата git ls-remote [remote], или git remote show [remote] за отдалечени клонове и друга информация. Най-използваната функционалност от разработчиците е да се възползват от предимствата на remote-tracking клоновете.

Remote-tracking клоновете са указатели към състоянието на отдалечените клонове код. Това са локални референции, които не можете да местите, те се преместват автоматично за вас в резултат от някакви мрежови комуникации, така че да е сигурно, че те акуратно отразяват статуса на отдалеченото хранилище. Служат като отметки за да ви напомнят в какво състояние са били отдалечените клонове код последния път, когато сте се свързвали с тях.

Те следват конвенцията <remote>/<branch>. Например, ако искате да видите в какво състояние е бил master клона на вашето отдалечено хранилище origin последния път, когато сте комуникирали с него, можете да го направите посредством клона origin/master. Ако съвместно с ваш колега работите по даден проблем и той е публикувал нещо в клона iss53, вие можете да имате локален такъв със същото име, но клонът на сървъра ще е достъпен през референцията origin/iss53.

Това може да е объркващо, така че нека го разгледаме с пример. Нека кажем, че имате Git сървър в мрежата ви на адрес git.ourcompany.com. Ако клонирате хранилище от него, clone командата на Git автоматично ще го именува с името origin, ще издърпва всички данни от него, ще създаде указател към мястото където е master клона на това хранилище и ще го съхрани като origin/master локално при вас. Git също така създава локален master клон, който сочи към същото място в проекта, така че да имате от къде да започнете локалната си работа.

Note
“origin” не е специална дума

Точно както и master - думата origin няма никакво специално значение в Git. Докато “master” е името по подразбиране за началния клон когато изпълните git init, то “origin” се ползва по подразбиране, когато изпълнявате git clone. Това е единствената причина за толкова разпространеното ползване на тези две думи. Ако изпълните git clone -o booyah вместо просто git clone, тогава ще имате booyah/master като ваш отдалечен клон по подразбиране.

Сървърното и локалното хранилище след клониране.
Figure 30. Сървърното и локалното хранилище след клониране

Ако вие вършите някаква работа в локалния си master клон и междувременно някой друг изпрати нещо към git.ourcompany.com и промени master клона там, тогава вашите истории на промените ще се движат напред по различни начини. Също така, докато не контакувате с вашия origin сървър, указателят origin/master не се премества самичък.

Локалната и отдалечената работа могат да се разделят.
Figure 31. Локалната и отдалечената работа могат да се разделят

За да синхронизирате работата си така, че да отразява промените на сървъра, използвайте командата git fetch <remote> (в нашия случай git fetch origin). Тази команда установява кой е адреса на сървъра “origin” (в случая git.ourcompany.com), издърпва всички данни, които все още нямате локално и обновява локалната база данни, така че указателят origin/master вече да сочи към нова, по-актуална позиция от историята.

`git fetch` обновява отдалечените ви референции.
Figure 32. git fetch обновява отдалечените ви референции

За да демонстрираме какво е да имате много отдалечени сървъри и как изглеждат клоновете на съответните отдалечени проекти, нека приемем, че имате още един вътрешнофирмен Git сървър, който се използва само за разработка от някой от вашите sprint екипи. Сървърът е на адрес git.team1.ourcompany.com. Можете да го добавите като нова отдалечена референция към проекта, в който работите, с командата git remote add, която разгледахме в Основи на Git. Наречете това отдалечено хранилище teamone, което ще е краткото име за целия URL.

Добавяне на нов remote.
Figure 33. Добавяне на нов remote

Сега можете да изпълните git fetch teamone за да изтеглите всичко, което този сървър има, а вие все още нямате локално. Понеже този сървър съхранява подмножество от данните на вашия origin сървър, Git всъщност не тегли от него нищо, а просто създава remote-tracking клон наречен teamone/master, който сочи към последния къмит, който teamone има за своя master клон.

Remote tracking клон за `teamone/master`.
Figure 34. Remote tracking клон за teamone/master

Изпращане към сървъра (pushing)

Когато искате да споделите работата от ваш локален клон с другите си колеги, трябва да го изпратите към отдалечено хранилище, към което имате права за писане. Вашите локални клонове не се синхронизират автоматично с регистрираните отдалечени хранилища — вие трябва изрично да ги изпратите към тях. По този начин, можете да си имате частни клонове код само за вас и които не желаете да споделяте, а да споделяте само topic клоновете, към които допринасяте.

Ако имате клон наречен serverfix, който искате да споделите с другите, можете да го изпратите по същия начин, по който изпратихте първия си клон. Изпълнете git push <remote> <branch>:

$ git push origin serverfix
Counting objects: 24, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done.
Total 24 (delta 2), reused 0 (delta 0)
To https://github.com/schacon/simplegit
 * [new branch]      serverfix -> serverfix

Това е един вид съкращение. Git автоматично разширява името на клона serverfix до refs/heads/serverfix:refs/heads/serverfix, което означава, “Вземи локалния ми клон serverfix и го изпрати към отдалеченото хранилище, обновявайки отдалечения клон serverfix.” Ще разгледаме частта refs/heads/ в подробности в Git на ниско ниво, засега не ѝ обръщайте внимание. Можете също да изпълните git push origin serverfix:serverfix, което върши същата работа, тази команда означава “Вземи локалния ми клон serverfix и го слей с отдалечения със същото име.” Можете да използвате този формат, за да слеете локален клон с отдалечен, който се казва по различен начин. Ако не желаете отдалеченият да се казва serverfix в сървърното хранилище, можете да изпълните например git push origin serverfix:awesomebranch и отдалечения клон ще се казва awesomebranch.

Note
Не пишете паролата си всеки път

Ако използвате HTTPS URL за изпращане, Git сървърът ще ви пита за име и парола всеки път когато изпращате към него. По подразбиране ще получите запитване в терминала, така че сървърът да знае дали можете да записвате на него

Ако не желаете това, можете да направите т. нар. “credential cache”. Най-лесно е да запомните паролата в кеша за известно време, което можете да направите с командата git config --global credential.helper cache.

За повече информация за различните опции за този кеш, вижте Credential Storage система.

Следващият път, когато колегите ви теглят от сървъра, ще получат референция към точката в която сочи сървърната версия на клона serverfix под формата на отдалечен за тях клон origin/serverfix:

$ git fetch origin
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/schacon/simplegit
 * [new branch]      serverfix    -> origin/serverfix

Важно е да се запомни, че когато изпълните git fetch за да изтеглите новосъздадени remote-tracking клонове, вие не получавате автоматично техни редактируеми копия! С други думи, в този случай няма да имате действителното съдържание на клона serverfix, а само указателят origin/serverfix, който не можете да променяте.

За да стане това, трябва да го слеете в текущия си клон с git merge origin/serverfix. Ако не желаете това да стане в текущия клон, а в нов локален такъв с име serverfix, можете да го базирате на remote-tracking клона:

$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

Това ви дава локален клон, в който да работите и който стартира от точката, в която е origin/serverfix.

Проследяване на клонове

Проследяващите клонове са локални такива, които имат директна връзка с отдалечен клон. Ако сте в такъв проследяващ клон и изпълните git pull, Git автоматично знае кой сървър да ползва за изтегляне и в кой клон да слее разликите.

Когато клонирате хранилище, системата създава автоматично master клон, който проследява origin/master. Обаче, ако желаете, можете да създадете и други проследяващи клонове - такива, които следят клонове от други отдалечени хранилища или пък не следят точно master клона от сървъра. Прост случай е примерът, който току що видяхте, изпълнявайки git checkout -b <branch> <remote>/<branch>. Това е често случваща се операция, за която Git осигурява --track съкращение:

$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

В действителност, това е толкова често срещано, че съществува съкращение на съкратената версия. Ако клонът с името, към който се опитвате да превключите, не съществува локално, но съвпада по име с такъв от точно едно отдалечено хранилище, Git ще създаде проследяващ клон за вас:

$ git checkout 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 serverfix from origin.
Switched to a new branch 'sf'

Сега, локалният ви клон sf автоматично ще тегли от origin/serverfix.

Ако ли пък имате локален клон и искате да го накарате да следи клона, който току що изтеглихте, или пък искате да смените upstream клона, можете да използвате -u или --set-upstream-to опциите на git branch за да укажете изрично името.

$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Note
Upstream съкращение

Когато имате настроен проследяващ клон, можете да се обръщате към неговия upstream клон със съкращенията @{upstream} или @{u}. Така, ако сте на master клона и той следи origin/master, можете да използвате git merge @{u} вместо git merge origin/master, ако ви е по-удобно.

За да отпечатате какви проследявани клонове имате, използвайте параметъра -vv на git branch. Това ще изведе списък с локалните клонове с повече информация, вкл. какво следи всеки клон и дали той е напред/назад или и двете в сравнение с локалната версия.

$ git branch -vv
  iss53     7e424c3 [origin/iss53: ahead 2] forgot the brackets
  master    1ae2a45 [origin/master] deploying index fix
* serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
  testing   5ea463a trying something new

Така можем да видим, че нашият iss53 локален клон проследява origin/iss53 и че е напред с две, което значи, че локално имаме два къмита, които не са изпратени към сървъра. Можем също да видим, че master клона следи origin/master и е актуален. След това виждаме, че serverfix следи server-fix-good клона от отдалеченото хранилище teamone и е напред с три и назад с едно, което значи, че на сървъра има един къмит, който още не сме слели локално и три локални къмита, които не са пратени на сървъра. Накрая, виждаме че локалния ни клон testing не следи нито един отдалечен клон.

Важно е да запомним, че тези цифри са актуални към момента на последното изпълнение на git fetch за всеки сървър. Командата не се свързва със сървърите, а само ни казва какво е кеширала локално от последната комуникация с всеки от тях. Ако желаете актуални ahead/behind статистики, преди нея трябва да обновите кеша с отдалечения статус:

$ git fetch --all; git branch -vv

Pulling (изтегляне и сливане)

Вече казахме, че командата git fetch изтегля от сървъра всички промени, които все още нямате локално, но не променя нищо в работната директория. Тя просто ще изтегли данните и ще ви позволи да ги слеете сами. Обаче, съществува команда git pull, която по същество е git fetch последвана от автоматично изпълнение на git merge в повечето случаи. Ако имате проследяващ клон създаден по начина по-горе, изрично посочен от вас или автоматично създаден като следствие от командите clone или checkout, то git pull последователно ще потърси кое отдалечено хранилище и клон са следени от текущия локален клон, след това ще изтегли информацията от тях и ще се опита да я слее автоматично в локалния клон.

В общия случай е по-добре да използвате fetch и merge, защото понякога магията на git pull може да създаде недоразумения.

Изтриване на отдалечени клонове

Да допуснем, че сте готови с отдалечения клон - да кажем че колегите ви са свършили работа по определена функционалност и са я слели в отдалечения ви master клон (или както и да се казва клона, в който е стабилния код). Можете да изтриете отдалечения клон с параметъра --delete на git push. Ако искате да изтриете serverfix клона от сървъра, изпълнете:

$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
 - [deleted]         serverfix

Това в общи линии изтрива указателя от сървъра. Git сървърът в повечето случаи ще пази данните за известно време докато мине garbage collection системата му, така че случайно изтритите данни често могат лесно да се възстановят.