CINXE.COM
Git - Отдалечени клонове
<!DOCTYPE html> <html lang="bg"> <head> <meta charset='utf-8'> <meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible'> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Git - Отдалечени клонове</title> <link href="/favicon.ico" rel='shortcut icon' type='image/x-icon'> <link rel="stylesheet" href="/application.min.css"> <script src="/js/modernizr.js"></script> <script src="/js/modernize.js"></script> </head> <body id="documentation"> <div class="inner"> <header> <a href="/"><img src="/images/logo@2x.png" width="110" height="46" alt="Git" /></a> <span id="tagline"></span> <script type="text/javascript"> const taglines = [ "fast-version-control", "everything-is-local", "distributed-even-if-your-workflow-isnt", "local-branching-on-the-cheap", "distributed-is-the-new-centralized" ]; var tagline = taglines[Math.floor(Math.random() * taglines.length)]; document.getElementById('tagline').innerHTML = '--' + tagline; </script> <form id="search" action="/search/results"> <input id="search-text" name="search" placeholder="Type / to search entire site…" autocomplete="off" type="text" /> </form> <div id="search-results"></div> </header> </div> <div class="inner"> <div id="content-wrapper"> <div tabindex="1" class="sidebar-btn"></div> <aside class="sidebar" id="sidebar"> <nav> <ul> <li> <a href="/about">About</a> <ul> </ul> </li> <li> <a href="/doc" class="active">Documentation</a> <ul class="expanded"> <li> <a href="/docs">Reference</a> </li> <li> <a href="/book" class="active">Book</a> </li> <li> <a href="/videos">Videos</a> </li> <li> <a href="/doc/ext">External Links</a> </li> </ul> </li> <li> <a href="/downloads">Downloads</a> <ul > <li> <a href="/downloads/guis">GUI Clients</a> </li> <li> <a href="/downloads/logos">Logos</a> </li> </ul> </li> <li> <a href="/community">Community</a> </li> </ul> <hr class="sidebar"> <p> This book is available in <a href="/book/en/v2/Git-Branching-Remote-Branches">English</a>. </p> <p> Full translation available in <table> <tr><td><a href="/book/az/v2/Git%e2%80%99d%c9%99-Branch-Uzaq-Branch%e2%80%99lar">azərbaycan dili</a>,</td></tr> <tr><td><a href="/book/bg/v2/%d0%9a%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%b2-Git-%d0%9e%d1%82%d0%b4%d0%b0%d0%bb%d0%b5%d1%87%d0%b5%d0%bd%d0%b8-%d0%ba%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5">български език</a>,</td></tr> <tr><td><a href="/book/de/v2/Git-Branching-Remote-Branches">Deutsch</a>,</td></tr> <tr><td><a href="/book/es/v2/Ramificaciones-en-Git-Ramas-Remotas">Español</a>,</td></tr> <tr><td><a href="/book/fr/v2/Les-branches-avec-Git-Branches-de-suivi-%c3%a0-distance">Français</a>,</td></tr> <tr><td><a href="/book/gr">Ελληνικά</a>,</td></tr> <tr><td><a href="/book/ja/v2/Git-%e3%81%ae%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81%e6%a9%9f%e8%83%bd-%e3%83%aa%e3%83%a2%e3%83%bc%e3%83%88%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81">日本語</a>,</td></tr> <tr><td><a href="/book/ko/v2/Git-%eb%b8%8c%eb%9e%9c%ec%b9%98-%eb%a6%ac%eb%aa%a8%ed%8a%b8-%eb%b8%8c%eb%9e%9c%ec%b9%98">한국어</a>,</td></tr> <tr><td><a href="/book/nl/v2/Branchen-in-Git-Branches-op-afstand-Remote-branches">Nederlands</a>,</td></tr> <tr><td><a href="/book/ru/v2/%d0%92%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-Git-%d0%a3%d0%b4%d0%b0%d0%bb%d1%91%d0%bd%d0%bd%d1%8b%d0%b5-%d0%b2%d0%b5%d1%82%d0%ba%d0%b8">Русский</a>,</td></tr> <tr><td><a href="/book/sl/v2/Veje-Git-Oddaljene-veje">Slovenščina</a>,</td></tr> <tr><td><a href="/book/tl/v2/Pag-branch-ng-Git-Remote-na-mga-Branch">Tagalog</a>,</td></tr> <tr><td><a href="/book/uk/v2/%d0%93%d0%b0%d0%bb%d1%83%d0%b6%d0%b5%d0%bd%d0%bd%d1%8f-%d0%b2-git-%d0%92%d1%96%d0%b4%d0%b4%d0%b0%d0%bb%d0%b5%d0%bd%d1%96-%d0%b3%d1%96%d0%bb%d0%ba%d0%b8">Українська</a></td></tr> <tr><td><a href="/book/zh/v2/Git-%e5%88%86%e6%94%af-%e8%bf%9c%e7%a8%8b%e5%88%86%e6%94%af">简体中文</a>,</td></tr> </table> </p> <p> Partial translations available in <table> <tr><td><a href="/book/cs/v2/V%c4%9btve-v-syst%c3%a9mu-Git-Vzd%c3%a1len%c3%a9-v%c4%9btve">Čeština</a>,</td></tr> <tr><td><a href="/book/mk/v2/%d0%93%d1%80%d0%b0%d0%bd%d0%b5%d1%9a%d0%b5-%d0%b2%d0%be-Git-%d0%94%d0%b0%d0%bb%d0%b5%d1%87%d0%b8%d0%bd%d1%81%d0%ba%d0%b8-%d0%b3%d1%80%d0%b0%d0%bd%d0%ba%d0%b8">Македонски</a>,</td></tr> <tr><td><a href="/book/pl/v2/Ga%c5%82%c4%99zie-Gita-Ga%c5%82%c4%99zie-zdalne">Polski</a>,</td></tr> <tr><td><a href="/book/sr/v2/%d0%93%d1%80%d0%b0%d0%bd%d0%b0%d1%9a%d0%b5-%d1%83-%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d1%83-%d0%93%d0%b8%d1%82-%d0%a3%d0%b4%d0%b0%d1%99%d0%b5%d0%bd%d0%b5-%d0%b3%d1%80%d0%b0%d0%bd%d0%b5">Српски</a>,</td></tr> <tr><td><a href="/book/uz/v2/Git-%d0%b4%d0%b0-%d1%82%d0%b0%d1%80%d0%bc%d0%be%d2%9b%d0%bb%d0%b0%d0%bd%d0%b8%d1%88-%d0%a3%d0%b7%d0%be%d2%9b-%d0%bc%d0%b0%d1%81%d0%be%d1%84%d0%b0%d0%b4%d0%b0%d0%b3%d0%b8-%d1%82%d0%b0%d1%80%d0%bc%d0%be%d2%9b%d0%bb%d0%b0%d1%80">Ўзбекча</a>,</td></tr> <tr><td><a href="/book/zh-tw/v2/%e4%bd%bf%e7%94%a8-Git-%e5%88%86%e6%94%af-%e9%81%a0%e7%ab%af%e5%88%86%e6%94%af">繁體中文</a>,</td></tr> </table> </p> <p> Translations started for <table> <tr><td><a href="/book/be/v2/Git-Branching-Remote-Branches">Беларуская</a>,</td></tr> <tr><td><a href="/book/fa/v2/%d8%b4%d8%a7%d8%ae%d9%87%e2%80%8c%d8%b3%d8%a7%d8%b2%db%8c-%d8%af%d8%b1-%da%af%db%8c%d8%aa-%d8%b4%d8%a7%d8%ae%d9%87%e2%80%8c%d9%87%d8%a7%db%8c-%d8%b1%db%8c%d9%85%d9%88%d8%aa" dir="rtl">فارسی</a>,</td></tr> <tr><td><a href="/book/id/v2/Git-Branching-Remote-Branches">Indonesian</a>,</td></tr> <tr><td><a href="/book/it/v2/Git-Branching-Remote-Branches">Italiano</a>,</td></tr> <tr><td><a href="/book/ms/v2/Git-Branching-Remote-Branches">Bahasa Melayu</a>,</td></tr> <tr><td><a href="/book/pt-br/v2/Branches-no-Git-Branches-remotos">Português (Brasil)</a>,</td></tr> <tr><td><a href="/book/pt-pt/v2/Ramifica%c3%a7%c3%a3o-do-Git-Remote-Branches">Português (Portugal)</a>,</td></tr> <tr><td><a href="/book/sv/v2/Git-f%c3%b6rgreningar-Fj%c3%a4rrgrenar">Svenska</a>,</td></tr> <tr><td><a href="/book/tr/v2/Git-Dallar%c4%b1-Uzak-Dallar">Türkçe</a>.</td></tr> </table> </p> <hr class="sidebar"/> <p> The source of this book is <a href="https://github.com/progit/progit2-bg">hosted on GitHub.</a></br> Patches, suggestions and comments are welcome. </p> </nav> </aside> <div id="content"> <div id="book-chapters"> <a class="dropdown-trigger" id="book-chapters-trigger" data-panel-id="chapters-dropdown" href="#">Chapters ▾</a> <div class='dropdown-panel' id='chapters-dropdown'> <div class='three-column'> <div class="column-left"> <ol class='book-toc'> <li class='chapter'> <h2>1. <a href="/book/bg/v2/%d0%9d%d0%b0%d1%87%d0%b0%d0%bb%d0%be-%d0%97%d0%b0-Version-Control-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b8%d1%82%d0%b5">Начало</a></h2> <ol> <li> 1.1 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%87%d0%b0%d0%bb%d0%be-%d0%97%d0%b0-Version-Control-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b8%d1%82%d0%b5">За Version Control системите</a> </li> <li> 1.2 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%87%d0%b0%d0%bb%d0%be-%d0%9a%d1%80%d0%b0%d1%82%d0%ba%d0%b0-%d0%b8%d1%81%d1%82%d0%be%d1%80%d0%b8%d1%8f-%d0%bd%d0%b0-Git">Кратка история на Git</a> </li> <li> 1.3 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%87%d0%b0%d0%bb%d0%be-%d0%9a%d0%b0%d0%ba%d0%b2%d0%be-%d0%b5-Git">Какво е Git</a> </li> <li> 1.4 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%87%d0%b0%d0%bb%d0%be-%d0%9a%d0%be%d0%bd%d0%b7%d0%be%d0%bb%d0%b0%d1%82%d0%b0-%d0%bd%d0%b0-Git">Конзолата на Git</a> </li> <li> 1.5 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%87%d0%b0%d0%bb%d0%be-%d0%98%d0%bd%d1%81%d1%82%d0%b0%d0%bb%d0%b8%d1%80%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git">Инсталиране на Git</a> </li> <li> 1.6 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%87%d0%b0%d0%bb%d0%be-%d0%9f%d1%8a%d1%80%d0%b2%d0%be%d0%bd%d0%b0%d1%87%d0%b0%d0%bb%d0%bd%d0%b0-%d0%bd%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-%d0%bd%d0%b0-Git">Първоначална настройка на Git</a> </li> <li> 1.7 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%87%d0%b0%d0%bb%d0%be-%d0%9f%d0%be%d0%bc%d0%be%d1%89%d0%bd%d0%b0-%d0%b8%d0%bd%d1%84%d0%be%d1%80%d0%bc%d0%b0%d1%86%d0%b8%d1%8f-%d0%b2-Git">Помощна информация в Git</a> </li> <li> 1.8 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%87%d0%b0%d0%bb%d0%be-%d0%9e%d0%b1%d0%be%d0%b1%d1%89%d0%b5%d0%bd%d0%b8%d0%b5">Обобщение</a> </li> </ol> </li> <li class='chapter'> <h2>2. <a href="/book/bg/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-%d0%bd%d0%b0-Git-%d0%a1%d1%8a%d0%b7%d0%b4%d0%b0%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-%d1%85%d1%80%d0%b0%d0%bd%d0%b8%d0%bb%d0%b8%d1%89%d0%b5">Основи на Git</a></h2> <ol> <li> 2.1 <a href="/book/bg/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-%d0%bd%d0%b0-Git-%d0%a1%d1%8a%d0%b7%d0%b4%d0%b0%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-%d1%85%d1%80%d0%b0%d0%bd%d0%b8%d0%bb%d0%b8%d1%89%d0%b5">Създаване на Git хранилище</a> </li> <li> 2.2 <a href="/book/bg/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-%d0%bd%d0%b0-Git-%d0%97%d0%b0%d0%bf%d0%b8%d1%81-%d0%bd%d0%b0-%d0%bf%d1%80%d0%be%d0%bc%d0%b5%d0%bd%d0%b8-%d0%b2-%d1%85%d1%80%d0%b0%d0%bd%d0%b8%d0%bb%d0%b8%d1%89%d0%b5%d1%82%d0%be">Запис на промени в хранилището</a> </li> <li> 2.3 <a href="/book/bg/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-%d0%bd%d0%b0-Git-%d0%9f%d1%80%d0%b5%d0%b3%d0%bb%d0%b5%d0%b4-%d0%bd%d0%b0-%d0%b8%d1%81%d1%82%d0%be%d1%80%d0%b8%d1%8f%d1%82%d0%b0-%d0%bd%d0%b0-%d0%b4%d0%b5%d0%b9%d1%81%d1%82%d0%b2%d0%b8%d1%8f%d1%82%d0%b0">Преглед на историята на действията</a> </li> <li> 2.4 <a href="/book/bg/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-%d0%bd%d0%b0-Git-%d0%92%d1%8a%d0%b7%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d1%8f%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-%d0%bd%d0%b0%d0%bf%d1%80%d0%b0%d0%b2%d0%b5%d0%bd%d0%b8-%d0%b4%d0%b5%d0%b9%d1%81%d1%82%d0%b2%d0%b8%d1%8f">Възстановяване на направени действия</a> </li> <li> 2.5 <a href="/book/bg/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-%d0%bd%d0%b0-Git-%d0%a0%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d0%be%d1%82%d0%b4%d0%b0%d0%bb%d0%b5%d1%87%d0%b5%d0%bd%d0%b8-%d1%85%d1%80%d0%b0%d0%bd%d0%b8%d0%bb%d0%b8%d1%89%d0%b0">Работа с отдалечени хранилища</a> </li> <li> 2.6 <a href="/book/bg/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-%d0%bd%d0%b0-Git-%d0%a2%d0%b0%d0%b3%d0%be%d0%b2%d0%b5-%d0%b2-Git">Тагове в Git</a> </li> <li> 2.7 <a href="/book/bg/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-%d0%bd%d0%b0-Git-%d0%9f%d1%81%d0%b5%d0%b2%d0%b4%d0%be%d0%bd%d0%b8%d0%bc%d0%b8-%d0%b2-Git">Псевдоними в Git</a> </li> <li> 2.8 <a href="/book/bg/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-%d0%bd%d0%b0-Git-%d0%9e%d0%b1%d0%be%d0%b1%d1%89%d0%b5%d0%bd%d0%b8%d0%b5">Обобщение</a> </li> </ol> </li> <li class='chapter'> <h2>3. <a href="/book/bg/v2/%d0%9a%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%b2-Git-%d0%9d%d0%b0%d0%ba%d1%80%d0%b0%d1%82%d0%ba%d0%be-%d0%b7%d0%b0-%d1%80%d0%b0%d0%b7%d0%ba%d0%bb%d0%be%d0%bd%d0%b5%d0%bd%d0%b8%d1%8f%d1%82%d0%b0">Клонове в Git</a></h2> <ol> <li> 3.1 <a href="/book/bg/v2/%d0%9a%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%b2-Git-%d0%9d%d0%b0%d0%ba%d1%80%d0%b0%d1%82%d0%ba%d0%be-%d0%b7%d0%b0-%d1%80%d0%b0%d0%b7%d0%ba%d0%bb%d0%be%d0%bd%d0%b5%d0%bd%d0%b8%d1%8f%d1%82%d0%b0">Накратко за разклоненията</a> </li> <li> 3.2 <a href="/book/bg/v2/%d0%9a%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%b2-Git-%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-%d0%bd%d0%b0-%d0%ba%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5%d1%82%d0%b5-%d0%ba%d0%be%d0%b4-%d0%b8-%d1%81%d0%bb%d0%b8%d0%b2%d0%b0%d0%bd%d0%b5%d1%82%d0%be">Основи на клоновете код и сливането</a> </li> <li> 3.3 <a href="/book/bg/v2/%d0%9a%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%b2-Git-%d0%a3%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%bd%d0%b0-%d0%ba%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5">Управление на клонове</a> </li> <li> 3.4 <a href="/book/bg/v2/%d0%9a%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%b2-Git-%d0%a1%d1%82%d1%80%d0%b0%d1%82%d0%b5%d0%b3%d0%b8%d0%b8-%d0%b7%d0%b0-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d0%ba%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%ba%d0%be%d0%b4">Стратегии за работа с клонове код</a> </li> <li> 3.5 <a href="/book/bg/v2/%d0%9a%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%b2-Git-%d0%9e%d1%82%d0%b4%d0%b0%d0%bb%d0%b5%d1%87%d0%b5%d0%bd%d0%b8-%d0%ba%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5" class="active">Отдалечени клонове</a> </li> <li> 3.6 <a href="/book/bg/v2/%d0%9a%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%b2-Git-%d0%a3%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%bd%d0%b0-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82">Управление на проект</a> </li> <li> 3.7 <a href="/book/bg/v2/%d0%9a%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%b2-Git-%d0%9e%d0%b1%d0%be%d0%b1%d1%89%d0%b5%d0%bd%d0%b8%d0%b5">Обобщение</a> </li> </ol> </li> <li class='chapter'> <h2>4. <a href="/book/bg/v2/GitHub-%d0%a1%d1%8a%d0%b7%d0%b4%d0%b0%d0%b2%d0%b0%d0%bd%d0%b5-%d0%b8-%d0%bd%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-%d0%bd%d0%b0-%d0%b0%d0%ba%d0%b0%d1%83%d0%bd%d1%82">GitHub</a></h2> <ol> <li> 4.1 <a href="/book/bg/v2/GitHub-%d0%a1%d1%8a%d0%b7%d0%b4%d0%b0%d0%b2%d0%b0%d0%bd%d0%b5-%d0%b8-%d0%bd%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-%d0%bd%d0%b0-%d0%b0%d0%ba%d0%b0%d1%83%d0%bd%d1%82">Създаване и настройка на акаунт</a> </li> <li> 4.2 <a href="/book/bg/v2/GitHub-%d0%9a%d0%b0%d0%ba-%d0%b4%d0%b0-%d1%81%d1%8a%d1%82%d1%80%d1%83%d0%b4%d0%bd%d0%b8%d1%87%d0%b8%d0%bc-%d0%b2-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82">Как да сътрудничим в проект</a> </li> <li> 4.3 <a href="/book/bg/v2/GitHub-%d0%a3%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%bd%d0%b0-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82">Управление на проект</a> </li> <li> 4.4 <a href="/book/bg/v2/GitHub-%d0%a3%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%bd%d0%b0-%d0%be%d1%80%d0%b3%d0%b0%d0%bd%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d1%8f">Управление на организация</a> </li> <li> 4.5 <a href="/book/bg/v2/GitHub-%d0%90%d0%b2%d1%82%d0%be%d0%bc%d0%b0%d1%82%d0%b8%d0%b7%d0%b8%d1%80%d0%b0%d0%bd%d0%b5-%d1%81-GitHub">Автоматизиране с GitHub</a> </li> <li> 4.6 <a href="/book/bg/v2/GitHub-%d0%9e%d0%b1%d0%be%d0%b1%d1%89%d0%b5%d0%bd%d0%b8%d0%b5">Обобщение</a> </li> </ol> </li> </ol> </div> <div class='column-middle'> <ol class='book-toc'> <li class='chapter'> <h2>5. <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%98%d0%b7%d0%b1%d0%be%d1%80-%d0%bd%d0%b0-%d0%ba%d1%8a%d0%bc%d0%b8%d1%82%d0%b8">Git инструменти</a></h2> <ol> <li> 5.1 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%98%d0%b7%d0%b1%d0%be%d1%80-%d0%bd%d0%b0-%d0%ba%d1%8a%d0%bc%d0%b8%d1%82%d0%b8">Избор на къмити</a> </li> <li> 5.2 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%98%d0%bd%d1%82%d0%b5%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%b2%d0%bd%d0%be-%d0%b8%d0%bd%d0%b4%d0%b5%d0%ba%d1%81%d0%b8%d1%80%d0%b0%d0%bd%d0%b5">Интерактивно индексиране</a> </li> <li> 5.3 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Stashing-%d0%b8-Cleaning">Stashing и Cleaning</a> </li> <li> 5.4 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%9f%d0%be%d0%b4%d0%bf%d0%b8%d1%81%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-%d0%b2%d0%b0%d1%88%d0%b0%d1%82%d0%b0-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0">Подписване на вашата работа</a> </li> <li> 5.5 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%a2%d1%8a%d1%80%d1%81%d0%b5%d0%bd%d0%b5">Търсене</a> </li> <li> 5.6 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%9c%d0%b0%d0%bd%d0%b8%d0%bf%d1%83%d0%bb%d0%b0%d1%86%d0%b8%d1%8f-%d0%bd%d0%b0-%d0%b8%d1%81%d1%82%d0%be%d1%80%d0%b8%d1%8f%d1%82%d0%b0">Манипулация на историята</a> </li> <li> 5.7 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%9c%d0%b8%d1%81%d1%82%d0%b5%d1%80%d0%b8%d1%8f%d1%82%d0%b0-%d0%bd%d0%b0-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b0%d1%82%d0%b0-Reset">Мистерията на командата Reset</a> </li> <li> 5.8 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%a1%d0%bb%d0%b8%d0%b2%d0%b0%d0%bd%d0%b5-%d0%b7%d0%b0-%d0%bd%d0%b0%d0%bf%d1%80%d0%b5%d0%b4%d0%bd%d0%b0%d0%bb%d0%b8">Сливане за напреднали</a> </li> <li> 5.9 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Rerere">Rerere</a> </li> <li> 5.10 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%94%d0%b5%d0%b1%d1%8a%d0%b3%d0%b2%d0%b0%d0%bd%d0%b5-%d1%81-Git">Дебъгване с Git</a> </li> <li> 5.11 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%9f%d0%be%d0%b4%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d0%b8">Подмодули</a> </li> <li> 5.12 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%9f%d0%b0%d0%ba%d0%b5%d1%82%d0%b8-%d0%b2-Git-Bundling">Пакети в Git (Bundling)</a> </li> <li> 5.13 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%97%d0%b0%d0%bc%d0%b5%d1%81%d1%82%d0%b2%d0%b0%d0%bd%d0%b5">Заместване</a> </li> <li> 5.14 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Credential-Storage-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b0">Credential Storage система</a> </li> <li> 5.15 <a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%9e%d0%b1%d0%be%d0%b1%d1%89%d0%b5%d0%bd%d0%b8%d0%b5">Обобщение</a> </li> </ol> </li> <li class='chapter'> <h2>6. <a href="/book/bg/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-Git-%d0%ba%d0%be%d0%bd%d1%84%d0%b8%d0%b3%d1%83%d1%80%d0%b0%d1%86%d0%b8%d0%b8">Настройване на Git</a></h2> <ol> <li> 6.1 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-Git-%d0%ba%d0%be%d0%bd%d1%84%d0%b8%d0%b3%d1%83%d1%80%d0%b0%d1%86%d0%b8%d0%b8">Git конфигурации</a> </li> <li> 6.2 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-Git-%d0%b0%d1%82%d1%80%d0%b8%d0%b1%d1%83%d1%82%d0%b8">Git атрибути</a> </li> <li> 6.3 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-Git-Hooks">Git Hooks</a> </li> <li> 6.4 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-%d0%9f%d1%80%d0%b8%d0%bc%d0%b5%d1%80%d0%bd%d0%b0-Git-Enforced-%d0%bf%d0%be%d0%bb%d0%b8%d1%82%d0%b8%d0%ba%d0%b0">Примерна Git-Enforced политика</a> </li> <li> 6.5 <a href="/book/bg/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-%d0%9e%d0%b1%d0%be%d0%b1%d1%89%d0%b5%d0%bd%d0%b8%d0%b5">Обобщение</a> </li> </ol> </li> <li class='chapter'> <h2>7. <a href="/book/bg/v2/Git-%d0%b8-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b8-Git-%d0%ba%d0%b0%d1%82%d0%be-%d0%ba%d0%bb%d0%b8%d0%b5%d0%bd%d1%82">Git и други системи</a></h2> <ol> <li> 7.1 <a href="/book/bg/v2/Git-%d0%b8-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b8-Git-%d0%ba%d0%b0%d1%82%d0%be-%d0%ba%d0%bb%d0%b8%d0%b5%d0%bd%d1%82">Git като клиент</a> </li> <li> 7.2 <a href="/book/bg/v2/Git-%d0%b8-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b8-%d0%9c%d0%b8%d0%b3%d1%80%d0%b0%d1%86%d0%b8%d1%8f-%d0%ba%d1%8a%d0%bc-Git">Миграция към Git</a> </li> <li> 7.3 <a href="/book/bg/v2/Git-%d0%b8-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b8-%d0%9e%d0%b1%d0%be%d0%b1%d1%89%d0%b5%d0%bd%d0%b8%d0%b5">Обобщение</a> </li> </ol> </li> <li class='chapter'> <h2>8. <a href="/book/bg/v2/Git-%d0%bd%d0%b0-%d0%bd%d0%b8%d1%81%d0%ba%d0%be-%d0%bd%d0%b8%d0%b2%d0%be-Plumbing-%d0%b8-Porcelain-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8">Git на ниско ниво</a></h2> <ol> <li> 8.1 <a href="/book/bg/v2/Git-%d0%bd%d0%b0-%d0%bd%d0%b8%d1%81%d0%ba%d0%be-%d0%bd%d0%b8%d0%b2%d0%be-Plumbing-%d0%b8-Porcelain-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8">Plumbing и Porcelain команди</a> </li> <li> 8.2 <a href="/book/bg/v2/Git-%d0%bd%d0%b0-%d0%bd%d0%b8%d1%81%d0%ba%d0%be-%d0%bd%d0%b8%d0%b2%d0%be-Git-%d0%be%d0%b1%d0%b5%d0%ba%d1%82%d0%b8">Git обекти</a> </li> <li> 8.3 <a href="/book/bg/v2/Git-%d0%bd%d0%b0-%d0%bd%d0%b8%d1%81%d0%ba%d0%be-%d0%bd%d0%b8%d0%b2%d0%be-Git-%d1%80%d0%b5%d1%84%d0%b5%d1%80%d0%b5%d0%bd%d1%86%d0%b8%d0%b8">Git референции</a> </li> <li> 8.4 <a href="/book/bg/v2/Git-%d0%bd%d0%b0-%d0%bd%d0%b8%d1%81%d0%ba%d0%be-%d0%bd%d0%b8%d0%b2%d0%be-Packfiles">Packfiles</a> </li> <li> 8.5 <a href="/book/bg/v2/Git-%d0%bd%d0%b0-%d0%bd%d0%b8%d1%81%d0%ba%d0%be-%d0%bd%d0%b8%d0%b2%d0%be-Refspec-%d1%81%d0%bf%d0%b5%d1%86%d0%b8%d1%84%d0%b8%d0%ba%d0%b0%d1%86%d0%b8%d0%b8">Refspec спецификации</a> </li> <li> 8.6 <a href="/book/bg/v2/Git-%d0%bd%d0%b0-%d0%bd%d0%b8%d1%81%d0%ba%d0%be-%d0%bd%d0%b8%d0%b2%d0%be-%d0%a2%d1%80%d0%b0%d0%bd%d1%81%d0%bf%d0%be%d1%80%d1%82%d0%bd%d0%b8-%d0%bf%d1%80%d0%be%d1%82%d0%be%d0%ba%d0%be%d0%bb%d0%b8">Транспортни протоколи</a> </li> <li> 8.7 <a href="/book/bg/v2/Git-%d0%bd%d0%b0-%d0%bd%d0%b8%d1%81%d0%ba%d0%be-%d0%bd%d0%b8%d0%b2%d0%be-%d0%9f%d0%be%d0%b4%d0%b4%d1%80%d1%8a%d0%b6%d0%ba%d0%b0-%d0%b8-%d0%b2%d1%8a%d0%b7%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d1%8f%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-%d0%b4%d0%b0%d0%bd%d0%bd%d0%b8">Поддръжка и възстановяване на данни</a> </li> <li> 8.8 <a href="/book/bg/v2/Git-%d0%bd%d0%b0-%d0%bd%d0%b8%d1%81%d0%ba%d0%be-%d0%bd%d0%b8%d0%b2%d0%be-Environment-%d0%bf%d1%80%d0%be%d0%bc%d0%b5%d0%bd%d0%bb%d0%b8%d0%b2%d0%b8">Environment променливи</a> </li> <li> 8.9 <a href="/book/bg/v2/Git-%d0%bd%d0%b0-%d0%bd%d0%b8%d1%81%d0%ba%d0%be-%d0%bd%d0%b8%d0%b2%d0%be-%d0%9e%d0%b1%d0%be%d0%b1%d1%89%d0%b5%d0%bd%d0%b8%d0%b5">Обобщение</a> </li> </ol> </li> <li class='chapter'> <h2>9. <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-A:-Git-%d0%b2-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d1%80%d0%b5%d0%b4%d0%b8-%d0%93%d1%80%d0%b0%d1%84%d0%b8%d1%87%d0%bd%d0%b8-%d0%b8%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d0%b8">Приложение A: Git в други среди</a></h2> <ol> <li> 9.1 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-A:-Git-%d0%b2-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d1%80%d0%b5%d0%b4%d0%b8-%d0%93%d1%80%d0%b0%d1%84%d0%b8%d1%87%d0%bd%d0%b8-%d0%b8%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d0%b8">Графични интерфейси</a> </li> <li> 9.2 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-A:-Git-%d0%b2-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d1%80%d0%b5%d0%b4%d0%b8-Git-%d0%b2%d1%8a%d0%b2-Visual-Studio">Git във Visual Studio</a> </li> <li> 9.3 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-A:-Git-%d0%b2-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d1%80%d0%b5%d0%b4%d0%b8-Git-%d0%b2%d1%8a%d0%b2-Visual-Studio-Code">Git във Visual Studio Code</a> </li> <li> 9.4 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-A:-Git-%d0%b2-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d1%80%d0%b5%d0%b4%d0%b8-Git-in-IntelliJ-/-PyCharm-/-WebStorm-/-PhpStorm-/-RubyMine">Git in IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine</a> </li> <li> 9.5 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-A:-Git-%d0%b2-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d1%80%d0%b5%d0%b4%d0%b8-Git-%d0%b2-Sublime-Text">Git в Sublime Text</a> </li> <li> 9.6 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-A:-Git-%d0%b2-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d1%80%d0%b5%d0%b4%d0%b8-Git-%d0%b2-Bash">Git в Bash</a> </li> <li> 9.7 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-A:-Git-%d0%b2-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d1%80%d0%b5%d0%b4%d0%b8-Git-%d0%b2-Zsh">Git в Zsh</a> </li> <li> 9.8 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-A:-Git-%d0%b2-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d1%80%d0%b5%d0%b4%d0%b8-Git-%d0%b2-PowerShell">Git в PowerShell</a> </li> <li> 9.9 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-A:-Git-%d0%b2-%d0%b4%d1%80%d1%83%d0%b3%d0%b8-%d1%81%d1%80%d0%b5%d0%b4%d0%b8-%d0%9e%d0%b1%d0%be%d0%b1%d1%89%d0%b5%d0%bd%d0%b8%d0%b5">Обобщение</a> </li> </ol> </li> </ol> </div> <div class='column-right'> <ol class='book-toc'> <li class='chapter'> <h2>10. <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d0%b3%d1%80%d0%b0%d0%b6%d0%b4%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-%d0%b2-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-Git-%d0%be%d1%82-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b5%d0%bd-%d1%80%d0%b5%d0%b4">Приложение B: Вграждане на Git в приложения</a></h2> <ol> <li> 10.1 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d0%b3%d1%80%d0%b0%d0%b6%d0%b4%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-%d0%b2-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-Git-%d0%be%d1%82-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b5%d0%bd-%d1%80%d0%b5%d0%b4">Git от команден ред</a> </li> <li> 10.2 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d0%b3%d1%80%d0%b0%d0%b6%d0%b4%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-%d0%b2-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-Libgit2">Libgit2</a> </li> <li> 10.3 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d0%b3%d1%80%d0%b0%d0%b6%d0%b4%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-%d0%b2-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-JGit">JGit</a> </li> <li> 10.4 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d0%b3%d1%80%d0%b0%d0%b6%d0%b4%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-%d0%b2-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-go-git">go-git</a> </li> <li> 10.5 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d0%b3%d1%80%d0%b0%d0%b6%d0%b4%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-Git-%d0%b2-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-Dulwich">Dulwich</a> </li> </ol> </li> <li class='chapter'> <h2>A1. <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b8-%d0%b8-%d0%ba%d0%be%d0%bd%d1%84%d0%b8%d0%b3%d1%83%d1%80%d0%b0%d1%86%d0%b8%d1%8f">Приложение C: Git команди</a></h2> <ol> <li> A1.1 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b8-%d0%b8-%d0%ba%d0%be%d0%bd%d1%84%d0%b8%d0%b3%d1%83%d1%80%d0%b0%d1%86%d0%b8%d1%8f">Настройки и конфигурация</a> </li> <li> A1.2 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-%d0%98%d0%b7%d0%b4%d1%8a%d1%80%d0%bf%d0%b2%d0%b0%d0%bd%d0%b5-%d0%b8-%d1%81%d1%8a%d0%b7%d0%b4%d0%b0%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b8">Издърпване и създаване на проекти</a> </li> <li> A1.3 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Snapshotting">Snapshotting</a> </li> <li> A1.4 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-%d0%9a%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%b8-%d1%81%d0%bb%d0%b8%d0%b2%d0%b0%d0%bd%d0%b5">Клонове и сливане</a> </li> <li> A1.5 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-%d0%a1%d0%bf%d0%be%d0%b4%d0%b5%d0%bb%d1%8f%d0%bd%d0%b5-%d0%b8-%d0%be%d0%b1%d0%bd%d0%be%d0%b2%d1%8f%d0%b2%d0%b0%d0%bd%d0%b5-%d0%bd%d0%b0-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b8">Споделяне и обновяване на проекти</a> </li> <li> A1.6 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-%d0%98%d0%bd%d1%81%d0%bf%d0%b5%d0%ba%d1%86%d0%b8%d1%8f-%d0%b8-%d1%81%d1%80%d0%b0%d0%b2%d0%bd%d0%b5%d0%bd%d0%b8%d0%b5">Инспекция и сравнение</a> </li> <li> A1.7 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-%d0%94%d0%b5%d0%b1%d1%8a%d0%b3%d0%b2%d0%b0%d0%bd%d0%b5">Дебъгване</a> </li> <li> A1.8 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Patching">Patching</a> </li> <li> A1.9 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Email-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8">Email команди</a> </li> <li> A1.10 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-%d0%92%d1%8a%d0%bd%d1%88%d0%bd%d0%b8-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b8">Външни системи</a> </li> <li> A1.11 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-%d0%90%d0%b4%d0%bc%d0%b8%d0%bd%d0%b8%d1%81%d1%82%d1%80%d0%b0%d1%82%d0%b8%d0%b2%d0%bd%d0%b8-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8">Административни команди</a> </li> <li> A1.12 <a href="/book/bg/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-Git-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Plumbing-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8">Plumbing команди</a> </li> </ol> </li> </ol> </div> </div> </div> <span class="light" id="edition"> 2nd Edition </span> </div> <div id="main" data-pagefind-filter="category:book" data-pagefind-meta="category:Book" data-pagefind-weight="0.05" data-pagefind-body class="book edition2"> <h1>3.5 Клонове в Git - Отдалечени клонове</h1> <div> <h2 id="_remote_branches">Отдалечени клонове</h2> <div class="paragraph"> <p> Отдалечените референции са указатели към вашите отдалечени хранилища, вкл. клонове, тагове и др. Можете да получите списък на всички отдалечени указатели изрично с командата <code>git ls-remote <remote></code>, или <code>git remote show <remote></code> за отдалечени клонове и друга информация. Най-използваната функционалност от разработчиците е да се възползват от предимствата на remote-tracking клоновете.</p> </div> <div class="paragraph"> <p>Remote-tracking клоновете са указатели към състоянието на отдалечените клонове код. Това са локални референции, които не можете да местите, те се преместват автоматично за вас в резултат от някакви мрежови комуникации, така че да е сигурно, че те акуратно отразяват статуса на отдалеченото хранилище. Служат като отметки за да ви напомнят в какво състояние са били отдалечените клонове код последния път, когато сте се свързвали с тях.</p> </div> <div class="paragraph"> <p>Те следват конвенцията <code><remote>/<branch></code>. Например, ако искате да видите в какво състояние е бил <code>master</code> клона на вашето отдалечено хранилище <code>origin</code> последния път, когато сте комуникирали с него, можете да го направите посредством клона <code>origin/master</code>. Ако съвместно с ваш колега работите по даден проблем и той е публикувал нещо в клона <code>iss53</code>, вие можете да имате локален такъв със същото име, но клонът на сървъра ще е достъпен през референцията <code>origin/iss53</code>.</p> </div> <div class="paragraph"> <p>Това може да е объркващо, така че нека го разгледаме с пример. Нека кажем, че имате Git сървър в мрежата ви на адрес <code>git.ourcompany.com</code>. Ако клонирате хранилище от него, <code>clone</code> командата на Git автоматично ще го именува с името <code>origin</code>, ще издърпва всички данни от него, ще създаде указател към мястото където е <code>master</code> клона на това хранилище и ще го съхрани като <code>origin/master</code> локално при вас. Git също така създава локален <code>master</code> клон, който сочи към същото място в проекта, така че да имате от къде да започнете локалната си работа.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">Забележка</div> </td> <td class="content"> <div class="title">“origin” не е специална дума</div> <div class="paragraph"> <p>Точно както и <code>master</code> - думата <code>origin</code> няма никакво специално значение в Git. Докато “master” е името по подразбиране за началния клон когато изпълните <code>git init</code>, то “origin” се ползва по подразбиране, когато изпълнявате <code>git clone</code>. Това е единствената причина за толкова разпространеното ползване на тези две думи. Ако изпълните <code>git clone -o booyah</code> вместо просто <code>git clone</code>, тогава ще имате <code>booyah/master</code> като ваш отдалечен клон по подразбиране.</p> </div> </td> </tr> </table> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/remote-branches-1.png" alt="Сървърното и локалното хранилище след клониране."> </div> <div class="title">Фигура 30. Сървърното и локалното хранилище след клониране</div> </div> <div class="paragraph"> <p>Ако вие вършите някаква работа в локалния си <code>master</code> клон и междувременно някой друг изпрати нещо към <code>git.ourcompany.com</code> и промени <code>master</code> клона там, тогава вашите истории на промените ще се движат напред по различни начини. Също така, докато не контакувате с вашия <code>origin</code> сървър, указателят <code>origin/master</code> не се премества самичък.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/remote-branches-2.png" alt="Локалната и отдалечената работа могат да се разделят"> </div> <div class="title">Фигура 31. Локалната и отдалечената работа могат да се разделят</div> </div> <div class="paragraph"> <p>За да синхронизирате работата си така, че да отразява промените на сървъра, използвайте командата <code>git fetch <remote></code> (в нашия случай <code>git fetch origin</code>). Тази команда установява кой е адреса на сървъра “origin” (в случая <code>git.ourcompany.com</code>), издърпва всички данни, които все още нямате локално и обновява локалната база данни, така че указателят <code>origin/master</code> вече да сочи към нова, по-актуална позиция от историята.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/remote-branches-3.png" alt="`git fetch` обновява отдалечените ви референции"> </div> <div class="title">Фигура 32. <code>git fetch</code> обновява отдалечените ви референции</div> </div> <div class="paragraph"> <p>За да демонстрираме какво е да имате много отдалечени сървъри и как изглеждат клоновете на съответните отдалечени проекти, нека приемем, че имате още един вътрешнофирмен Git сървър, който се използва само за разработка от някой от вашите sprint екипи. Сървърът е на адрес <code>git.team1.ourcompany.com</code>. Можете да го добавите като нова отдалечена референция към проекта, в който работите, с командата <code>git remote add</code>, която разгледахме в <a href="/book/bg/v2/ch00/ch02-git-basics-chapter">Основи на Git</a>. Наречете това отдалечено хранилище <code>teamone</code>, което ще е краткото име за целия URL.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/remote-branches-4.png" alt="Добавяне на нов remote"> </div> <div class="title">Фигура 33. Добавяне на нов remote</div> </div> <div class="paragraph"> <p>Сега можете да изпълните <code>git fetch teamone</code> за да изтеглите всичко, което този сървър има, а вие все още нямате локално. Понеже този сървър съхранява подмножество от данните на вашия <code>origin</code> сървър, Git всъщност не тегли от него нищо, а просто създава remote-tracking клон наречен <code>teamone/master</code>, който сочи към последния къмит, който <code>teamone</code> има за своя <code>master</code> клон.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/remote-branches-5.png" alt="Remote tracking клон за `teamone/master`"> </div> <div class="title">Фигура 34. Remote tracking клон за <code>teamone/master</code> </div> </div> <div class="sect3"> <h3 id="_pushing_branches">Изпращане към сървъра (pushing)</h3> <div class="paragraph"> <p> Когато искате да споделите работата от ваш локален клон с другите си колеги, трябва да го изпратите към отдалечено хранилище, към което имате права за писане. Вашите локални клонове не се синхронизират автоматично с регистрираните отдалечени хранилища — вие трябва изрично да ги изпратите към тях. По този начин, можете да си имате частни клонове код само за вас и които не желаете да споделяте, а да споделяте само topic клоновете, към които допринасяте.</p> </div> <div class="paragraph"> <p>Ако имате клон наречен <code>serverfix</code>, който искате да споделите с другите, можете да го изпратите по същия начин, по който изпратихте първия си клон. Изпълнете <code>git push <remote> <branch></code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ 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</code></pre> </div> </div> <div class="paragraph"> <p>Това е един вид съкращение. Git автоматично разширява името на клона <code>serverfix</code> до <code>refs/heads/serverfix:refs/heads/serverfix</code>, което означава, “Вземи локалния ми клон serverfix и го изпрати към отдалеченото хранилище, обновявайки отдалечения клон serverfix”. Ще разгледаме частта <code>refs/heads/</code> в подробности в <a href="/book/bg/v2/ch00/ch10-git-internals">Git на ниско ниво</a>, засега не ѝ обръщайте внимание. Можете също да изпълните <code>git push origin serverfix:serverfix</code>, което върши същата работа, тази команда означава “Вземи локалния ми клон serverfix и го слей с отдалечения със същото име”. Можете да използвате този формат, за да слеете локален клон с отдалечен, който се казва по различен начин. Ако не желаете отдалеченият да се казва <code>serverfix</code> в сървърното хранилище, можете да изпълните например <code>git push origin serverfix:awesomebranch</code> и отдалечения клон ще се казва <code>awesomebranch</code>.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">Забележка</div> </td> <td class="content"> <div class="title">Не пишете паролата си всеки път</div> <div class="paragraph"> <p>Ако използвате HTTPS URL за изпращане, Git сървърът ще ви пита за име и парола всеки път когато изпращате към него. По подразбиране ще получите запитване в терминала, така че сървърът да знае дали можете да записвате на него</p> </div> <div class="paragraph"> <p>Ако не желаете това, можете да направите т. нар. “credential cache”. Най-лесно е да запомните паролата в кеша за известно време, което можете да направите с командата <code>git config --global credential.helper cache</code>.</p> </div> <div class="paragraph"> <p>За повече информация за различните опции за този кеш, вижте <a href="/book/bg/v2/ch00/_credential_caching">Credential Storage система</a>.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Следващият път, когато колегите ви теглят от сървъра, ще получат референция към точката в която сочи сървърната версия на клона <code>serverfix</code> под формата на отдалечен за тях клон <code>origin/serverfix</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ 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</code></pre> </div> </div> <div class="paragraph"> <p>Важно е да се запомни, че когато изпълните <code>git fetch</code> за да изтеглите новосъздадени remote-tracking клонове, вие не получавате автоматично техни редактируеми копия! С други думи, в този случай няма да имате действителното съдържание на клона <code>serverfix</code>, а само указателят <code>origin/serverfix</code>, който не можете да променяте.</p> </div> <div class="paragraph"> <p>За да стане това, трябва да го слеете в текущия си клон с <code>git merge origin/serverfix</code>. Ако не желаете това да стане в текущия клон, а в нов локален такъв с име <code>serverfix</code>, можете да го базирате на remote-tracking клона:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b serverfix origin/serverfix Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch 'serverfix'</code></pre> </div> </div> <div class="paragraph"> <p>Това ви дава локален клон, в който да работите и който стартира от точката, в която е <code>origin/serverfix</code>.</p> </div> </div> <div class="sect3"> <h3 id="_tracking_branches">Проследяване на клонове</h3> <div class="paragraph"> <p> Извличането на локален клон от remote-tracking такъв автоматично създава т. нар. “tracking branch” (и клонът, който той следи се нарича “upstream branch”). Проследяващите клонове са локални такива, които имат директна връзка с отдалечен клон. Ако сте в такъв проследяващ клон и изпълните <code>git pull</code>, Git автоматично знае кой сървър да ползва за изтегляне и в кой клон да слее разликите.</p> </div> <div class="paragraph"> <p>Когато клонирате хранилище, системата създава автоматично <code>master</code> клон, който проследява <code>origin/master</code>. Обаче, ако желаете, можете да създадете и други проследяващи клонове - такива, които следят клонове от други отдалечени хранилища или пък не следят точно <code>master</code> клона от сървъра. Прост случай е примерът, който току що видяхте, изпълнявайки <code>git checkout -b <branch> <remote>/<branch></code>. Това е често случваща се операция, за която Git осигурява <code>--track</code> съкращение:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout --track origin/serverfix Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch 'serverfix'</code></pre> </div> </div> <div class="paragraph"> <p>В действителност, това е толкова често срещано, че съществува съкращение на съкратената версия. Ако клонът с името, към който се опитвате да превключите, не съществува локално, но съвпада по име с такъв от точно едно отдалечено хранилище, Git ще създаде проследяващ клон за вас:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout serverfix Branch serverfix set up to track remote branch serverfix from origin. Switched to a new branch 'serverfix'</code></pre> </div> </div> <div class="paragraph"> <p>Ако искате да създадете клон с различно име от това, което е в отдалеченото хранилище, можете лесно да ползвате първата версия с различно име за локалния клон:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b sf origin/serverfix Branch sf set up to track remote branch serverfix from origin. Switched to a new branch 'sf'</code></pre> </div> </div> <div class="paragraph"> <p>Сега, локалният ви клон <code>sf</code> автоматично ще тегли от <code>origin/serverfix</code>.</p> </div> <div class="paragraph"> <p>Ако ли пък имате локален клон и искате да го накарате да следи клона, който току що изтеглихте, или пък искате да смените upstream клона, можете да използвате <code>-u</code> или <code>--set-upstream-to</code> опциите на <code>git branch</code> за да укажете изрично името.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git branch -u origin/serverfix Branch serverfix set up to track remote branch serverfix from origin.</code></pre> </div> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">Забележка</div> </td> <td class="content"> <div class="title">Upstream съкращение</div> <div class="paragraph"> <p>Когато имате настроен проследяващ клон, можете да се обръщате към неговия upstream клон със съкращенията <code>@{upstream}</code> или <code>@{u}</code>. Така, ако сте на <code>master</code> клона и той следи <code>origin/master</code>, можете да използвате <code>git merge @{u}</code> вместо <code>git merge origin/master</code>, ако ви е по-удобно.</p> </div> <div class="paragraph"> <p>За да отпечатате какви проследявани клонове имате, използвайте параметъра <code>-vv</code> на <code>git branch</code>. Това ще изведе списък с локалните клонове с повече информация, вкл. какво следи всеки клон и дали той е напред/назад или и двете в сравнение с локалната версия.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git branch -vv iss53 7e424c3 [origin/iss53: ahead 2] Add forgotten brackets master 1ae2a45 [origin/master] Deploy index fix * serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] This should do it testing 5ea463a Try something new</code></pre> </div> </div> <div class="paragraph"> <p>Така можем да видим, че нашият <code>iss53</code> локален клон проследява <code>origin/iss53</code> и че е напред с две, което значи, че локално имаме два къмита, които не са изпратени към сървъра. Можем също да видим, че <code>master</code> клона следи <code>origin/master</code> и е актуален. След това виждаме, че <code>serverfix</code> следи <code>server-fix-good</code> клона от отдалеченото хранилище <code>teamone</code> и е напред с три и назад с едно, което значи, че на сървъра има един къмит, който още не сме слели локално и три локални къмита, които не са пратени на сървъра. Накрая, виждаме че локалния ни клон <code>testing</code> не следи нито един отдалечен клон.</p> </div> <div class="paragraph"> <p>Важно е да запомним, че тези цифри са актуални към момента на последното изпълнение на <code>git fetch</code> за всеки сървър. Командата не се свързва със сървърите, а само ни казва какво е кеширала локално от последната комуникация с всеки от тях. Ако желаете актуални ahead/behind статистики, преди нея трябва да обновите кеша с отдалечения статус:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git fetch --all; git branch -vv</code></pre> </div> </div> <div class="paragraph"> <p>==== Pulling (изтегляне и сливане)</p> </div> <div class="paragraph"> <p> Вече казахме, че командата <code>git fetch</code> изтегля от сървъра всички промени, които все още нямате локално, но не променя нищо в работната директория. Тя просто ще изтегли данните и ще ви позволи да ги слеете сами. Обаче, съществува команда <code>git pull</code>, която по същество е <code>git fetch</code> последвана от автоматично изпълнение на <code>git merge</code> в повечето случаи. Ако имате проследяващ клон създаден по начина по-горе, изрично посочен от вас или автоматично създаден като следствие от командите <code>clone</code> или <code>checkout</code>, то <code>git pull</code> последователно ще потърси кое отдалечено хранилище и клон са следени от текущия локален клон, след това ще изтегли информацията от тях и ще се опита да я слее автоматично в локалния клон.</p> </div> <div class="paragraph"> <p>В общия случай е по-добре да използвате <code>fetch</code> и <code>merge</code>, защото понякога магията на <code>git pull</code> може да създаде недоразумения.</p> </div> <div id="_delete_branches" class="paragraph"> <p>==== Изтриване на отдалечени клонове</p> </div> <div class="paragraph"> <p> Да допуснем, че сте готови с отдалечения клон - да кажем че колегите ви са свършили работа по определена функционалност и са я слели в отдалечения ви <code>master</code> клон (или както и да се казва клона, в който е стабилния код). Можете да изтриете отдалечения клон с параметъра <code>--delete</code> на <code>git push</code>. Ако искате да изтриете <code>serverfix</code> клона от сървъра, изпълнете:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push origin --delete serverfix To https://github.com/schacon/simplegit - [deleted] serverfix</code></pre> </div> </div> <div class="paragraph"> <p>Всичко, което това прави е да изтрие указателя от сървъра. Git сървърът в повечето случаи ще пази данните за известно време докато мине garbage collection системата му, така че случайно изтритите данни често могат лесно да се възстановят.</p> </div> <div id="_rebasing" class="paragraph"> <p>=== Пребазиране на клонове</p> </div> <div class="paragraph"> <p> В Git съществуват два основни начина за интегриране на промени от един клон код в друг: сливане (<code>merge</code>) и пребазиране (<code>rebase</code>). В тази секция ще научите какво е пребазирането, как да го правите, защо е мощен инструмент и кои са случаите, в които не бихте искали да го използвате.</p> </div> <div class="paragraph"> <p>==== Просто пребазиране</p> </div> <div class="paragraph"> <p>Ако се върнете назад до по-ранния пример в <a href="/book/bg/v2/ch00/_basic_merging">Сливане</a>, можете да си припомните, че работата ви се разклонява и вие правихте къмити в два различни клона.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/basic-rebase-1.png" alt="Проста история на разклоняването"> </div> <div class="title">Фигура 35. Проста история на разклоняването</div> </div> <div class="paragraph"> <p>Най-лесният начин за интегрирането на клоновете, както вече разгледахме, беше командата <code>merge</code>. Тя изпълнява трипосочно сливане между най-новите snapshot-и от клоновете (<code>C3</code> и <code>C4</code>) и най-близкия им общ предшественик (<code>C2</code>) създавайки нов snapshot (и къмит).</p> </div> <div id="rebasing-merging-example" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/basic-rebase-2.png" alt="Сливане за интегриране на разклонена работна история"> </div> <div class="title">Фигура 36. Сливане за интегриране на разклонена работна история</div> </div> <div class="paragraph"> <p>Обаче, съществува и друг начин да направите това: можете да вземете patch на промените, които са въведени с <code>C4</code> и да ги приложите върху <code>C3</code>. В Git това се нарича пребазиране, <em>rebasing</em>. С командата <code>rebase</code>, вие вземате всички промени къмитнати в един клон и ги пускате в друг такъв.</p> </div> <div class="paragraph"> <p>В този пример, ще извлечете клона <code>experiment</code> и ще го пребазирате върху <code>master</code> по следния начин:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout experiment $ git rebase master First, rewinding head to replay your work on top of it... Applying: added staged command</code></pre> </div> </div> <div class="paragraph"> <p>Това става, като се намери най-близкия общ предшестващ къмит на двата клона (този върху, който сте в момента и този, който ще пребазирате), вземат се разликите въведени от всеки къмит на клона, върху който сте, разликите се записват във временни файлове, текущият клон се ресетва към същия къмит, в който е клона, който ще се пребазира, и накрая се прилага всяка промяна поред.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/basic-rebase-3.png" alt="Пребазиране на промяната от `C4` в `C3`"> </div> <div class="title">Фигура 37. Пребазиране на промяната от <code>C4</code> в <code>C3</code> </div> </div> <div class="paragraph"> <p>В този момент, можете да се върнете към <code>master</code> клона и да направите fast-forward сливане.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout master $ git merge experiment</code></pre> </div> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/basic-rebase-4.png" alt="Fast-forwarding на клона `master`"> </div> <div class="title">Фигура 38. Fast-forwarding на клона <code>master</code> </div> </div> <div class="paragraph"> <p>Сега snapshot-ът, към който сочи <code>C4'</code> е точно същият като този, към който сочеше <code>C5</code> в <a href="/book/bg/v2/ch00/rebasing-merging-example">the merge example</a>. Няма разлика в крайния резултат от интеграцията, но пребазирането прави историята по-чиста. Ако изследвате лога на един пребазиран клон код, той ще прилича на линейна история, цялата работа изглежда като случила се на серии, дори когато в действителност е била паралелна.</p> </div> <div class="paragraph"> <p>Често ще правите това за да се уверите, че вашите къмити се прилагат безпроблемно върху отдалечен клон — вероятно проект, към който се опитвате да допринесете, но който не поддържате като автор. В този случай, вие вършите своята дейност в собствен клон и след това пребазирате работата си върху <code>origin/master</code>, когато сте готови да изпратите своите поправки в основния проект. По този начин, поддръжащият проекта разработчик не трябва да върши никаква работа по интеграцията на промените ви — просто ще направи fast-forward.</p> </div> <div class="paragraph"> <p>Отбележете отново, че snapshot-ът, към който сочи финалния получил се къмит (бил той последния от пребазираните къмити за rebase или пък новосъздадения в резултат от merge) е един и същи и в двата случая — разликата е само в историята. Пребазирането прилага промените от една линия на разработка в друга по реда, в който те са били направени, докато сливането взема двата края на два клона и ги слива в едно.</p> </div> <div class="paragraph"> <p>==== Други интересни пребазирания</p> </div> <div class="paragraph"> <p>Едно пребазиране може да бъде приложено и върху друг освен върху целевия му клон. Например, вижте фигурата <a href="/book/bg/v2/ch00/rbdiag_e">История с topic клон произлизащ от друг topic клон</a>. Създали сте един topic клон (<code>server</code>) за да добавите някаква сървърна функционалност към проекта си и сте направили къмит. След това, ползвайки този клон за отправна точка, сте създали нов такъв (<code>client</code>) за да направите някакви промени по клиентската част и сте къмитнали няколко пъти. Накрая, върнали сте се обратно към сървърния клон и сте направили още няколко къмита.</p> </div> <div id="rbdiag_e" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/interesting-rebase-1.png" alt="История с topic клон произлизащ от друг topic клон"> </div> <div class="title">Фигура 39. История с topic клон произлизащ от друг topic клон</div> </div> <div class="paragraph"> <p>Да кажем, че решавате да слеете клиентските промени в <code>master</code> клона за публикуване, но желаете да си запазите server-side промените за допълнително тестване. Можете да вземете промените в клиентската част, които не присъстват на сървъра (<code>C8</code> and <code>C9</code>) и да ги приложите върху <code>master</code> клона чрез параметъра <code>--onto</code> на командата <code>git rebase</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git rebase --onto master server client</code></pre> </div> </div> <div class="paragraph"> <p>Това звучи така, “Вземи клона <code>client</code>, разбери кои са промените в него след момента, в който този клон се е разклонил от <code>server</code> клона и ги приложи отново в него сякаш той е бил базиран първоначално на <code>master</code> клона.” Изглежда доста объркано, но резултатът е впечатляващ.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/interesting-rebase-2.png" alt="Пребазиране на topic клон от друг topic branch"> </div> <div class="title">Фигура 40. Пребазиране на topic клон от друг topic branch</div> </div> <div class="paragraph"> <p>Сега можете да направите fast-forward на <code>master</code> клона (виж <a href="/book/bg/v2/ch00/rbdiag_g">Fast-forwarding на <code>master</code> клона за включване на промените от клона client</a>):</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout master $ git merge client</code></pre> </div> </div> <div id="rbdiag_g" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/interesting-rebase-3.png" alt="Fast-forwarding на `master` клона за включване на промените от клона client"> </div> <div class="title">Фигура 41. Fast-forwarding на <code>master</code> клона за включване на промените от клона client</div> </div> <div class="paragraph"> <p>Нека кажем, че решите да интегрирате и промените от server клона. Можете да пребазирате <code>server</code> клона върху <code>master</code> без да се налага да превключвате към него изпълнявайки <code>git rebase <basebranch> <topicbranch></code> — което вместо вас ще превключи към topicbranch (в този случай <code>server</code>) и ще го приложи върху base branch (в случая <code>master</code>):</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git rebase master server</code></pre> </div> </div> <div class="paragraph"> <p>Това прилага вашите <code>server</code> промени върху <code>master</code> клона както е показано в <a href="/book/bg/v2/ch00/rbdiag_h">Пребазиране на server клона в <code>master</code> клона</a>.</p> </div> <div id="rbdiag_h" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/interesting-rebase-4.png" alt="Пребазиране на server клона в `master` клона"> </div> <div class="title">Фигура 42. Пребазиране на server клона в <code>master</code> клона</div> </div> <div class="paragraph"> <p>След което, можете да превъртите основния клон (<code>master</code>):</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout master $ git merge server</code></pre> </div> </div> <div class="paragraph"> <p>Сега можете да изтриете клоновете <code>client</code> и <code>server</code>, защото те са интегрирани и не ви трябват повече, което ще направи историята на целия процес да изглежда така <a href="/book/bg/v2/ch00/rbdiag_i">Историята на финалния къмит</a>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git branch -d client $ git branch -d server</code></pre> </div> </div> <div id="rbdiag_i" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/interesting-rebase-5.png" alt="Историята на финалния къмит"> </div> <div class="title">Фигура 43. Историята на финалния къмит</div> </div> <div id="_rebase_peril" class="paragraph"> <p>==== Опасности при пребазиране</p> </div> <div class="paragraph"> <p> Както можете да се досетите, пребазирането си има и недостатъци, които могат да се обобщят в едно изречение:</p> </div> <div class="paragraph"> <p><strong>Не пребазирайте къмити, които съществуват извън вашето собствено хранилище и върху които други хора може да са базирали работата си.</strong></p> </div> <div class="paragraph"> <p>Послушате ли този съвет, ще сте ОК. Не го ли направите, ще ви намразят.</p> </div> <div class="paragraph"> <p>Когато пребазирате неща, вие зарязвате съществуващи къмити и създавате нови, които са подобни, но не съвсем същите. Ако изпратите къмитите някъде и други ваши колеги ги издърпат и използват като изходна точка за тяхната работа, а след това вие ги презапишете с <code>git rebase</code> и ги изпратите отново, то колегите ви ще трябва да слеят отново тяхната работа и нещата бързо ще придобият грозен вид, когато пък вие се опитате да изтеглите тяхната работа обратно за ваше ползване.</p> </div> <div class="paragraph"> <p>Нека видим един пример, как пребазирането на публична работа може да доведе до проблеми. Да допуснем, че клонирате от централен сървър и вършите някаква работа след това. Историята на къмитите ви изглежда по подобен начин:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/perils-of-rebasing-1.png" alt="Клонирайте хранилище и направете промени по него."> </div> <div class="title">Фигура 44. Клонирайте хранилище и направете промени по него</div> </div> <div class="paragraph"> <p>Сега, някой друг върши друга работа, която включва сливане и я изпраща към централния сървър. Вие я издърпвате и сливате новия отдалечен клон във вашата работа, така че историята придобива подобен вид:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/perils-of-rebasing-2.png" alt="Издърпвате още къмити и ги сливате във вашата работа."> </div> <div class="title">Фигура 45. Издърпвате още къмити и ги сливате във вашата работа</div> </div> <div class="paragraph"> <p>След това човекът, който е изпратил слетите си промени, решава да се върне назад и да пребазира работата си изпълнявайки <code>git push --force</code> за да презапише историята на сървъра. Вие от своя страна, издърпвате отново от сървъра получавайки новите къмити.</p> </div> <div id="_pre_merge_rebase_work" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/perils-of-rebasing-3.png" alt="Някой изпраща към сървъра пребазирани къмити, изоставяйки тези, върху които вие сте базирали работата си."> </div> <div class="title">Фигура 46. Някой изпраща към сървъра пребазирани къмити, изоставяйки тези, върху които вие сте базирали работата си</div> </div> <div class="paragraph"> <p>Сега и двамата сте в бъркотия. Ако направите <code>git pull</code>, ще се създаде merge commit, който включва и двете линни история и хранилището ви ще изглежда така:</p> </div> <div id="_merge_rebase_work" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/perils-of-rebasing-4.png" alt="Вие сливате в същата работа отново, в нов merge commit"> </div> <div class="title">Фигура 47. Вие сливате в същата работа отново, в нов merge commit</div> </div> <div class="paragraph"> <p>Ако пуснете <code>git log</code> в история като тази, ще видите два къмита с един и същи автор, дата и съобщение, което ще е доста смущаващо. По-нататък, ако изпратите тази история обратно към сървъра, ще запишете допълнително в него всички тези пребазирани къмити, което би объркало допълнително хората в бъдеще. Безопасно е да предположите, че другият ви колега не желае <code>C4</code> и <code>C6</code> да присъстват в историята - в края на краищата това е причината той да направи пребазирането.</p> </div> <div id="_rebase_rebase" class="paragraph"> <p>==== Пребазиране по време на пребазиране</p> </div> <div class="paragraph"> <p>Ако <strong>се</strong> окажете в подобна ситуация, Git разполага с допълнителни средства, които да ви помогнат. Ако някой от вашия екип форсирано изпрати промени, които презаписват нещата, които служат за база на вашата работа, трудността за вас ще е да откриете кое е ваше и какво е било презаписано.</p> </div> <div class="paragraph"> <p>Оказва се, че в допълнение към SHA-1 чексумата на къмита, Git също така калкулира и чексума, която е базирана на поправката (patch-ът) въведена от него. Това се нарича “patch-id”.</p> </div> <div class="paragraph"> <p>Ако издърпате работа, която е била пренаписана и я пребазирате върху новите къмити на вашия колега, Git често може успешно да определи кое е изцяло ваше и да ги приложи обратно върху новия клон.</p> </div> <div class="paragraph"> <p>Например, в предишния сценарий, ако вместо да правим сливане докато сме в момента показан на фигурата <a href="/book/bg/v2/ch00/_pre_merge_rebase_work">Някой изпраща към сървъра пребазирани къмити, изоставяйки тези, върху които вие сте базирали работата си</a>, изпълним <code>git rebase teamone/master</code>, Git ще направи следното:</p> </div> <div class="ulist"> <ul> <li> <p>Ще определи коя работа е уникална за нашия клон (C2, C3, C4, C6, C7)</p> </li> <li> <p>Ще определи кои от къмитите не са (C2, C3, C4)</p> </li> <li> <p>Ще определи кои къмити не са били презаписани в целевия клон (само C2 и C3, защото C4 е същият patch като C4')</p> </li> <li> <p>Ще приложи тези къмити върху <code>teamone/master</code></p> </li> </ul> </div> <div class="paragraph"> <p>Така вместо резултатите, които виждаме във <a href="/book/bg/v2/ch00/_merge_rebase_work">Вие сливате в същата работа отново, в нов merge commit</a>, ще получим нещо приличащо повече на <a href="/book/bg/v2/ch00/_rebase_rebase_work">Пребазиране върху форсирано изпратена пребазирана работа</a></p> </div> <div id="_rebase_rebase_work" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/perils-of-rebasing-5.png" alt="Пребазиране върху форсирано изпратена пребазирана работа"> </div> <div class="title">Фигура 48. Пребазиране върху форсирано изпратена пребазирана работа</div> </div> <div class="paragraph"> <p>Това работи само, ако <code>C4</code> и <code>C4</code>, направени от колегата ви са почти един и същи patch. В противен случай, пребазирането няма да може да установи, че това е дублиране и ще добави още един подобен на C4 patch (който вероятно няма да може да се приложи чисто, понеже промените вече ще са поне някъде там).</p> </div> <div class="paragraph"> <p>Можете също така да опростите това изпълнявайки <code>git pull --rebase</code>, вместо нормален <code>git pull</code>. Или можете да го направите ръчно с <code>git fetch</code> последвана от <code>git rebase teamone/master</code> в този случай.</p> </div> <div class="paragraph"> <p>Ако използвате <code>git pull</code> и искате да включите <code>--rebase</code> аргумента по подразбиране, можете да зададете <code>pull.rebase</code> конфигурационната стойност с <code>git config --global pull.rebase true</code>.</p> </div> <div class="paragraph"> <p>Ако пребазирате само къмити, които никога не са били публични, а са съществували само в локалния компютър - тогава няма да имате проблеми. Ако пребазирате публикувани вече къмити, за които знаете че никога не са използвани от някой друг - тогава също няма проблем. Ако обаче пребазирате къмити, които вече са изпратени и може би използвани като основа за работата на някой друг в екипа, тогава очаквайте много проблеми и негативно отношение в съвместната ви работа с колегите.</p> </div> <div class="paragraph"> <p>Ако вие или ваш колега установи към даден момент, че това е необходимо - уверете се, че поне всеки знае и пуска <code>git pull --rebase</code> за да се намалят неудобствата, когато проблемите дойдат.</p> </div> <div class="paragraph"> <p>==== Пребазиране или сливане</p> </div> <div class="paragraph"> <p> Сега, когато видяхте в действие пребазирането и сливането, може би се питате кое от двете е по-добро. Преди да отговорим, нека се върнем малко назад и да поговорим за това какво означава историята.</p> </div> <div class="paragraph"> <p>Една възможна дефиниция е, че историята на къмитите във вашето хранилище е <strong>запис на това какво в действителност се е случвало.</strong> Това е исторически документ, ценен сам по себе си, който не бива да се модифицира. Погледнато по този начин, излиза че промяната на историята на къмитите е почти богохулство - вие <em>лъжете</em> за това какво се е случвало всъщност. А какво ще е ако имахте разхвърляни серии от merge къмити? Ами - просто така са протекли нещата и хранилището следва да пази този факт за идните поколения.</p> </div> <div class="paragraph"> <p>Обратната гледна точка приема историята като <strong>хронология на това как проектът ви е бил създаден</strong>. Например, не бихте публикували първата чернова на една книга и ръководството за това как да поддържате вашия софтуер заслужава внимателно редактиране. Когато работите върху проект, може да ви трябва запис на всичките ви погрешни стъпки, но когато дойде време да споделите проекта с останалите, вероятно ще искате да покажете съвсем ясно как сте стигнали от точка А до точка В. Това е гледната точка на поддръжниците на инструменти като <code>rebase</code> и <code>filter-branch</code>, които искат да разкажат историята на проекта не буквално каквато е била, а каквато би била най-полезна за тези, които ще го поемат в бъдеще.</p> </div> <div class="paragraph"> <p>Обратно на въпроса кое е по-добро, пребазирането или сливането? Надяваме се виждате и сами, че отговорът не може да е еднозначен. Git е мощна система, която ви позволява да правите много неща с историята на проекта, но няма еднакви екипи и няма еднакви проекти. Накратко, най-добрият отговор на въпроса е, че трябва сами да решите кой подход е най-добър според конретната специфична ситуация.</p> </div> <div class="paragraph"> <p>Ако се колебаете, но искате да се възползвате от предимствата и на двата подхода, просто помнете това правило - спокойно използвайте пребазиране за локални промени, които сте направили, но не са публични. Така ще си подредите историята в чист вид. Но никога не пребазирайте нещо, което вече сте изпратили за споделено ползване.</p> </div> <div class="paragraph"> <p>=== Обобщение</p> </div> <div class="paragraph"> <p>Разгледахме основите на разклоненията и сливанията в Git. Би следвало сега да умеете с лекота да създавате и превключвате клонове, както и да сливате локални клонове заедно. Също така, би следвало да можете да споделяте клоновете си код изпращайки ги към общ сървър, да работите с други колеги по споделени клонове код и да пребазирате вашите клонове преди споделянето им. Следва да разгледаме какви ви е необходимо за да си пуснете свой собствен хостинг сървър за Git хранилища.</p> </div> <div id="ch04-git-on-the-server" class="paragraph"> <p>== Git на сървъра</p> </div> <div class="paragraph"> <p> На този етап, би следвало да можете да вършите повечето си ежедневна работа, за която ви е нужен Git. Обаче, за да участвате с вашия труд в какъвто и да било вид съвместна работа с Git, ще ви е нужно отдалечено Git хранилище. Въпреки, че теоретично можете да пращате и издърпвате промени към хранилищата на индивидуални отделни колеги, това не е препоръчително, защото лесно можете да объркате нещата, върху които те работят, ако не сте внимателни. Освен това, вероятно искате вашите колеги да имат достъп до хранилището ви дори когато компютърът ви е без връзка с мрежата. Затова, препоръчителният начин да сътрудничите с други разработчици е да настроите междинно хранилище, към което да имат достъп всички, и да теглите и изпращате код през него.</p> </div> <div class="paragraph"> <p>Да пуснете Git сървър е сравнително лесно. Първо, избирате протоколите, които желаете той да поддържа за комуникация с клиентите. Първата секция от тази глава ще разгледа наличните протоколи в едно с предимствата и недостатъците им. Следващите части ще обяснят някои типични настройки свързани с тези протоколи. Накрая, ще преминем през няколко хоствани опции, в случай че нямате нищо против кода ви да се съхранява на външен сървър и не ви се занимава с настройката и поддръжката на собствен такъв.</p> </div> <div class="paragraph"> <p>Ако е така, можете да преминете директно към последната част на тази глава, за да разгледате какви са опциите за създаване на хостван акаунт и след това да разгледате следващата глава, където дискутираме предимствата и недостатъците на това да работите в distributed source control среда.</p> </div> <div class="paragraph"> <p>Отдалеченото хранилище накратко казано е <em>bare repository</em> –- Git хранилище без работна директория. Понеже то се ползва само като обща точка за сътрудничество между членовете на екипа, няма необходимост в него да има snapshot от данните разположен на диска, там присъстват само Git данните. Казано възможно най-просто, едно голо (bare) хранилище има само съдържанието на директорията <code>.git</code> от вашия проект и нищо повече.</p> </div> <div class="paragraph"> <p>=== Комуникационни протоколи</p> </div> <div class="paragraph"> <p>Git може да използва 4 основни протокола за трансфер на данни: локален, HTTP, Secure Shell (SSH) и Git. Сега ще погледнем какво представляват те и по какви причини бихте желали да ги използвате (или избягвате).</p> </div> <div class="paragraph"> <p>==== Локален протокол</p> </div> <div class="paragraph"> <p> Най-простият от четирите е <em>локалният протокол</em>, при който отдалеченото хранилище се намира просто в друга директория на диска. Това често се ползва, ако всички в екипа ви имат достъп до споделена файлова система от рода на <a href="https://en.wikipedia.org/wiki/Network_File_System" target="_blank" rel="noopener">NFS</a> споделено устройство или пък, в по-редки случаи, когато всички се логват на един и същи компютър. Последното не е препоръчително, защото всички копия на хранилището ще се пазят на едно място и рискът от загубата на данни при хардуерна повреда е значително по-голям.</p> </div> <div class="paragraph"> <p>Ако имате споделена монтирана файлова система, тогава вие клонирате, изпращате и изтегляте данни от локално, файлово-базирано хранилище. За да клонирате хранилище от този вид или за да добавите такова като отдалечено към съществуващ проект, използвайте пътя до хранилището вместо URL. Например, за да клонирате, може да изпълните нещо подобно:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone /srv/git/project.git</code></pre> </div> </div> <div class="paragraph"> <p>Или пък така:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone file:///srv/git/project.git</code></pre> </div> </div> <div class="paragraph"> <p>Git работи малко по-различно ако изрично укажете <code>file://</code> като префикс на пътя. Ако укажете само пътя, системата се опитва да използва hardlinks или директно копира файловете, които са нужни. Ако укажете <code>file://</code>, Git ще стартира процеси, които нормално се използват за мрежов трансфер, което е една идея по-малко ефективен метод за трансфер на данни. Главната причина да използвате префикса <code>file://</code> е, че можете да искате чисто копие на хранилището, без неприсъщи референции или обекти в него - основно при импорт от други VCS системи или нещо подобно (вижте <a href="/book/bg/v2/ch00/ch10-git-internals">Git на ниско ниво</a> за повече подробности). Тук ние ще използваме нормални пътища, защото това почти винаги работи по-бързо.</p> </div> <div class="paragraph"> <p>За да добавите локално хранилище като remote към съществуващ Git проект, можете да направите това:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git remote add local_proj /srv/git/project.git</code></pre> </div> </div> <div class="paragraph"> <p>След това, можете да изпращате и издърпвате от него използвайки името му <code>local_proj</code> по същия начин, по който ако то беше в мрежа.</p> </div> <div class="paragraph"> <p>===== Предимствата</p> </div> <div class="paragraph"> <p>Предимствата на файл-базираните хранилища са в това, че са прости и използват наличните права за файловете и мрежовия достъп. Ако вече имате споделена файлова система, до която има достъп целия ви екип, създаването на хранилище е много просто. Пазите копие от bare хранилището някъде, където всички имат достъп и задавате права за чете и писане като на всяка друга споделена директория. Ще дискутираме как да експортирате копие от хранилището като bare копие за целта в <a href="/book/bg/v2/ch00/_getting_git_on_a_server">[_getting_git_on_a_server]</a>.</p> </div> <div class="paragraph"> <p>Това също е полезен начин за бързо изтегляне на работата на друг човек от неговото работещо хранилище. Ако с ваш колега работите по един и същи проект и той поиска да погледнете нещо по неговата работа, то една команда от рода на <code>git pull /home/john/project</code> вероятно ще е по-лесна опция от това той да изпрати нещо до мрежовото хранилище и вие след това да го теглите при вас.</p> </div> <div class="paragraph"> <p>===== Недостатъци</p> </div> <div class="paragraph"> <p>Неудобствата при този подход се състоят в това, че споделеният достъп в повечето случаи се настройва и достъпва от различни локации по-трудно в сравнение със стандартния мрежов достъп. Ако искате да изпратите данни от домашния си лаптоп, докато сте вкъщи, ще трябва да монтирате отдалечения диск, което често може да е трудно и досадно бавно.</p> </div> <div class="paragraph"> <p>Също така трябва да посочим, че локалният протокол не винаги е най-бързата опция, ако използвате споделен монтиран ресурс от някои видове. Локалното хранилище е бързо само, ако имате бърз достъп до данните. Едно хранилище разположено върху NFS ресурс често е по-бавно от SSH такова на същия сървър (което освен това позволява на Git да работи през локалните дискове на всеки от компютрите).</p> </div> <div class="paragraph"> <p>Накрая, този протокол не защитава хранилището от непредвидени поражения. Всеки потребител разполага с пълен шел достъп до “отдалеченото” хранилище и нищо не пречи на един невнимателен колега да промени или изтрие служебни Git файлове, което от своя страна да повреди цялото хранилище.</p> </div> <div class="paragraph"> <p>==== HTTP протоколите</p> </div> <div class="paragraph"> <p>Git може да работи през HTTP в два различни режима. Преди Git версия 1.6.6, начинът беше само един и то доста опростен и в общия случай - read-only. С тази версия обаче, беше представен нов, по-усъвършенстван протокол, който позволява на Git интелигентно да уговаря транфера на данни по маниер подобен на този, който се използва през SSH. В последните няколко години този нов HTTP протокол придоби голяма популярност, защото е по-прост за потребителя и по-интелигентен в механизма на комуникация. Тази нова версия често е наричана <em>Smart</em> HTTP протокол, докато старата е известна като <em>Dumb</em> HTTP. Ще разгледаме първо smart HTTP протокола.</p> </div> <div class="paragraph"> <p>===== Smart HTTP</p> </div> <div class="paragraph"> <p> Протоколът smart HTTP работи много подобно на SSH или Git протоколите, но използва стандартните HTTP/S портове и може да използва различни механизми за HTTP автентикация, което често го прави по-лесен за много потребители, защото можете да използвате неща като оторизиране с име и парола, вместо създаване на SSH ключове.</p> </div> <div class="paragraph"> <p>Този протокол в момента е най-популярния начин за използване в Git, понеже може да работи както анонимно, подобно на протокола <code>git://</code>, така и с криптиране подобно на SSH и автентикация. Вместо да създавате различни URLи за тези неща, сега можете да използвате единичен URL за всички тях. Ако се опитате да изпратите данни към хранилище настроено да изисква оторизация (както би следвало да е), сървърът може да ви попита за потребителско име и парола за достъп. Същото важи и за достъпа само за четене.</p> </div> <div class="paragraph"> <p>На практика, в услуги като GitHub, URL-ът който ползвате за да разглеждате хранилището в браузъра (например, <a href="https://github.com/schacon/simplegit" class="bare" target="_blank" rel="noopener">https://github.com/schacon/simplegit</a>) е същият URL, който можете да използвате за клонирането му или пък за изпращане на промени към него (ако имате права за това).</p> </div> <div class="paragraph"> <p>===== Dumb HTTP</p> </div> <div class="paragraph"> <p> Ако сървърът не разполага с Git HTTP smart услуга, Git клиентът ще се опита да използва протокола <em>dumb</em> HTTP. Този вид комуникация очаква bare Git хранилището да се обслужва като нормални файлове от уеб сървъра. Красотата на dumb протокола се крие в простотата на настройката му. В общи линии, всичко което трябва да направите е да копирате едно bare Git хранилище там където уеб сървърът има достъп и да настроите специфичен <code>post-update</code> hook, след което сте готови (вижте <a href="/book/bg/v2/ch00/_git_hooks">Git Hooks</a>). Сега всички, които имат достъп до уеб сървъра, ще могат да клонират хранилището ви. За да позволите достъп за четене до хранилището през HTTP, направете нещо такова:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cd /var/www/htdocs/ $ git clone --bare /path/to/git_project gitproject.git $ cd gitproject.git $ mv hooks/post-update.sample hooks/post-update $ chmod a+x hooks/post-update</code></pre> </div> </div> <div class="paragraph"> <p>Това е всичко. Инструментът <code>post-update</code>, който идва с Git, по подразбиране изпълнява съответната команда (<code>git update-server-info</code>) така че HTTP издърпването и клонирането да работят коректно. Тази команда се изпълнява, когато изпращате към това хранилище, вероятно през SSH, след което други потребители могат да клонират посредством нещо такова:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone https://example.com/gitproject.git</code></pre> </div> </div> <div class="paragraph"> <p>В този специфичен случай, ние използваме <code>/var/www/htdocs</code> пътя, който е стандартен за Apache инсталациите, но вие можете да ползвате който и да е статичен уеб сървър — просто сложете bare хранилището в неговия път. Git данните се обслужват като базови статични файлове (вижте <a href="/book/bg/v2/ch00/ch10-git-internals">Git на ниско ниво</a> за повече информация как точно става това).</p> </div> <div class="paragraph"> <p>Kато обобщение, имате два избора, да пуснете read/write Smart HTTP сървър или read-only такъв с Dumb HTTP. Рядко се случва да се прави комбинация от двете.</p> </div> <div class="paragraph"> <p>===== Предимствата</p> </div> <div class="paragraph"> <p>Ще разгледаме предимствата на Smart HTTP версията на протокола.</p> </div> <div class="paragraph"> <p>Простотата да имате единичен URL за всички видове достъп и да оставите сървърът да пита за име и парола, когато се налага, прави нещата много по-лесни за крайния потребител. Възможността за оторизация с име и парола е голямо предимство сравнена с SSH, защото потребителите няма нужда да генерират SSH ключове локално и да изпращат публичния си ключ към сървъра преди да могат да комуникират с него. За по-неопитните потребители или за потребителите на системи, в които SSH не се ползва интензивно, това може да бъде голямо улеснение по отношение на лекотата на ползване. В допълнение, протоколът е бърз и ефективен, подобно на SSH.</p> </div> <div class="paragraph"> <p>Можете също да обслужвате хранилищата си само за четене през HTTPS, което значи че можете да криптирате съдържанието на трансфера или дори да стигнете и до по-рестриктивни мерки, като например да изисквате от клиентите да използват специфични signed SSL сертификати.</p> </div> <div class="paragraph"> <p>Друго предимство е и факта, че HTTP и HTTPS са толкова разпространени протоколи, че корпоративните защитни стени често вече са настроени да пропускат трафика през техните портове.</p> </div> <div class="paragraph"> <p>===== Недостатъци</p> </div> <div class="paragraph"> <p>Git през HTTP/S може да е една идея по-сложен за настройване в сравнение с SSH на някои сървъри. Отделно от това, съществува съвсем леко предимство, което другите протоколи за обслужване на Git имат, в сравнение със Smart HTTP.</p> </div> <div class="paragraph"> <p>Ако използвате HTTP за автентикирано изпращане на промени към хранилището, изпращането на името и паролата понякога може да е малко по-сложно отколкото използването на SSH ключове. Обаче, съществуват няколко credential caching инструменти, които можете да ползвате, включително Keychain access на OSX или Credential Manager под Windows, за да си улесните нещата. Погледнете <a href="/book/bg/v2/ch00/_credential_caching">Credential Storage система</a> за да видите как да настроите системата за защитено кеширане на HTTP пароли.</p> </div> <div class="paragraph"> <p>==== SSH протоколът</p> </div> <div class="paragraph"> <p> Често използван протокол за Git при self-hosting инсталации е SSH. Това е защото SSH достъпът до сървърите е много разпространен и настроен на повечето от тях - а и да не е, лесно може да се пусне. SSH също така е автентикиран мрежов протокол, повсеместно използван и лесно управляем.</p> </div> <div class="paragraph"> <p>За да клонирате Git хранилище през SSH, използвайте <code>ssh://</code> URL като този:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone ssh://[user@]server/project.git</code></pre> </div> </div> <div class="paragraph"> <p>Или, може да предпочетете съкратения, подобен на scp синтаксис:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone [user@]server:project.git</code></pre> </div> </div> <div class="paragraph"> <p>И в двата случая отгоре, ако не укажете потребителско име, Git ще използва това, с което сте логнати в системата.</p> </div> <div class="paragraph"> <p>===== Предимствата</p> </div> <div class="paragraph"> <p>Предимствата на SSH са много. Първо, SSH е сравнително лесен за настройка - SSH демоните са често използвани и познати, повечето системни администратори имат опит с тях и повечето OS дистрибуции идват с настроен SSH или имат съответните средства за настройка и управление на SSH комуникация. След това, комуникацията е сигурна - целият трансфер през SSH е криптиран и оторизиран. Последно, подобно на HTTP/S, Git и Local протоколите, SSH е ефективен и прави данните максимално компактни преди да ги изпрати.</p> </div> <div class="paragraph"> <p>===== Недостатъци</p> </div> <div class="paragraph"> <p>Негативната страна на SSH е, че не можете да имате анонимен достъп. Потребителите трябва да имат достъп до машината ви през SSH, за да се доберат до хранилището ви, дори и в режим само за четене, което не прави SSH толкова подходящ за проекти с отворен код. Ако го използвате само в рамките на корпоративната мрежа, SSH може да е единственият протокол, с който се налага да работите. Ако искате да позволите анонимен достъп само за четене до вашите проекти и същевременно искате да ползвате SSH, ще трябва да настроите SSH за вас, за да изпращате до хранилището, но за колегите, които ще теглят - ще трябва да настроите друг метод.</p> </div> <div class="paragraph"> <p>==== Git протокол</p> </div> <div class="paragraph"> <p> Следва протоколът Git. Той е реализиран чрез специален daemon, който идва заедно с Git, слуша на специфичен порт (9418) и осигурява услуга подобна на тази на SSH, но без абсолютно никаква автентикация. Ако искате хранилището ви да е достъпно през този протокол, трябва да създадете файл <code>git-daemon-export-ok</code>, иначе daemon-ът няма да го обслужва. Това е единственият вид защита при този протокол. Такова Git хранилище няма опции - или е достъпно за клониране от всички или не е. Това означава, че по подразбиране при този протокол не можете да изпращате данни към хранилището (pushing). Можете да го разрешите, но предвид тоталната липса на автентикация, това не е добра идея - всеки в Интернет, който се сдобие с URLа на хранилището ви, ще може да го променя. Достатъчно е да се каже, че това е рядкост.</p> </div> <div class="paragraph"> <p>===== Предимства</p> </div> <div class="paragraph"> <p>Git протоколът често е най-бързия мрежов протокол. Ако обслужвате голям трафик за публичен проект, или пък проектът е много голям и не изисква автентикация за четене, вероятно ще си заслужава да пуснете Git daemon. Той използва същия механизъм за трансфер на данни като SSH, но без забавянето за криптиране и автентикация.</p> </div> <div class="paragraph"> <p>===== Недостатъци</p> </div> <div class="paragraph"> <p>Недостатъкът на Git протокола е липсата на автентикация. Като цяло е нежелателно Git протоколът да е единствения протокол за достъп до вашия проект. В повечето случаи, може да го ползвате в комбинация с SSH или HTTPS за достъп от ваши сътрудници, които трябва да имат права за запис в хранилището, а всички останали - read-only достъп през <code>git://</code>. Освен това, Git вероятно е най-трудния за настройка протокол. Той трябва да пусне свой собствен daemon, което може да изисква <code>xinetd</code>/<code>systemd</code> конфигурация или нещо подобно, а това не е сред най-приятните неща за един системен администратор. Също така, протоколът изисква защитната стена да пропуска трафик през порт 9418, което не е стандартна опция за корпоративните такива и обикновено се блокира.</p> </div> <div id="_getting_git_on_a_server" class="paragraph"> <p>=== Достъп до Git на сървъра</p> </div> <div class="paragraph"> <p>Сега ще разгледаме настройката на Git услуга, ползваща тези протоколи на ваш собствен сървър.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Тук ще демонстрираме командите и стъпките за базови опростени инсталации на Linux базиран сървър, но разбира се, възможно е това да стане на macOS и Windows машини. В действителност, изграждането на production сървър в рамките на вашата инфраструктура ще изисква различни стъпки по отношение на мерките за сигурност или според конкретните инструменти на операционната ви система, но да се надяваме, че тези стъпки ще ви дадат първоначална насока за това какво се изисква.</p> </div> <div class="exampleblock"> <div class="content"> <div class="paragraph"> <p>Като първа стъпка, за да получите Git на сървъра, ще трябва да експортирате налично хранилище в ново, bare хранилище - това е хранилище, което не съдържа работна директория. Това обикновено е съвсем лесно. Използвайте командата за клониране с параметър <code>--bare</code>. По конвенция, директориите за bare хранилището завършват на <code>.git</code>, например така:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone --bare my_project my_project.git Cloning into bare repository 'my_project.git'... done.</code></pre> </div> </div> <div class="paragraph"> <p>Сега трябва да имате копие от Git директорията във вашата директория <code>my_project.git</code>.</p> </div> <div class="paragraph"> <p>Това е приблизително еквивалентно на резултата от командата:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cp -Rf my_project/.git my_project.git</code></pre> </div> </div> <div class="paragraph"> <p>Съществуват някои незначителни разлики в конфигурационния файл, но за нашите цели резултатът е почти един и същ. Командата взема Git хранилището, без работната му директория и създава директория специално за него.</p> </div> <div id="_bare_repo" class="paragraph"> <p>==== Изпращане на Bare хранилище към сървъра</p> </div> <div class="paragraph"> <p>След като вече имате копие на хранилището, всичко което трябва да сторите е да го копирате на сървъра и да настроите съответния протокол/протоколи за достъп. Нека кажем, че имате сървър наречен <code>git.example.com</code>, към който имате SSH достъп и искате да пазите всичките си Git хранилища в директорията <code>/srv/git</code>. Като приемаме, че <code>/srv/git</code> съществува на сървъра, можете да създадете ново хранилище копирайки наличното такова:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ scp -r my_project.git user@git.example.com:/srv/git</code></pre> </div> </div> <div class="paragraph"> <p>В този момент, другите потребители с SSH достъп до същия сървър и права за четене към <code>/srv/git</code> директорията му, вече могат да клонират вашето хранилище изпълнявайки:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone user@git.example.com:/srv/git/my_project.git</code></pre> </div> </div> <div class="paragraph"> <p>Ако някой от тях има и права за писане до директорията <code>/srv/git/my_project.git</code>, то той ще има автоматично и push права до хранилището.</p> </div> <div class="paragraph"> <p>Git автоматично ще добави group write права до хранилището по коректен начин, ако изпълните <code>git init</code> с параметъра <code>--shared</code>. Изпълнението на тази команда не унищожава никакви къмити, референции или други обекти</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ ssh user@git.example.com $ cd /srv/git/my_project.git $ git init --bare --shared</code></pre> </div> </div> <div class="paragraph"> <p>Виждате колко лесно е да вземете Git хранилище, да създадете bare версия и да го поставите в сървър, към който колегите ви имат SSH достъп. Сега сте готови да работите съвместно по проекта.</p> </div> <div class="paragraph"> <p>Важно е да посочим, че това буквално е всичко, от което имате нужда за да пуснете използваем Git сървър - просто добавете акаунти с SSH достъп за колегите ви и копирайте едно bare хранилище там, където те имат права за четене и писане. Сега сте готови, не трябва нищо повече.</p> </div> <div class="paragraph"> <p>В следващите секции ще видим как да направим по-модерни конфигурации. Ще направим обзор на това как да настроите нещата така, че да не се нуждаете от отделни акаунти за всеки потребител, как да добавим публичен достъп за четене до хранилища, настройване на уеб потребителски интерфейси и др. Обаче, просто помнете, че това са допълнения - всичко, което ви <em>трябва</em> за да работите съвместно по частен проект е SSH сървър и bare хранилище.</p> </div> <div class="paragraph"> <p>==== Малки конфигурации</p> </div> <div class="paragraph"> <p>Ако сте малък екип или просто тествате Git във вашата организация и имате само няколко разработчика, нещата могат да са простички за вас. Един от най-сложните аспекти в настройката на Git сървъра е управлението на потребителите. Ако искате някои хранилища да са само за четене за определени потребители, а други да са достъпни за писане, то настройките на достъпа и съответните права могат да са по-трудни за наместване.</p> </div> <div class="paragraph"> <p>===== SSH достъп</p> </div> <div class="paragraph"> <p> Ако имате сървър, към който всичките ви колеги имат SSH достъп, най-лесно е да разположите хранилищата си в него, защото както видяхме в предната секция - няма да имате почти никаква работа по настройките. Ако искате по-комплексен контрол на достъпа, можете да се справите с нормалните средства за достъп до файловата система, които операционната система предлага.</p> </div> <div class="paragraph"> <p>Ако искате да разположите хранилищата си на сървър, който няма акаунти за всички в екипа ви, за които допускате, че ще е нужен достъп с права за писане, тогава трябва да настроите SSH достъп за тях. Допускаме, че ако имате сървър с който да правите това, вече имате инсталиран SSH за достъп до него.</p> </div> <div class="paragraph"> <p>Има няколко начина да дадете достъп на всеки от екипа. Първо, можете да създадете акаунти за всички колеги, което е лесно, но може да е досадно. Може да не искате да изпълнявате <code>adduser</code>/<code>useradd</code> и да правите временни пароли за всеки колега.</p> </div> <div class="paragraph"> <p>Втори начин е да създадете единичен 'git' потребител на машината, да помолите всеки ваш колега, който трябва да има права за писане да ви изпрати свой SSH публичен ключ, и да добавите ключовете във файла <code>~/.ssh/authorized_keys</code> на потребителя 'git'. Така всеки от колегите ви ще има достъп до машината през потребителското име 'git'. Това не засяга по никакъв начин commit данните — SSH потребителят, с който се свързвате към машината не се отразява на записаните къмити.</p> </div> <div class="paragraph"> <p>Друг начин е да настроите вашия SSH сървър да автентикира потребителите през LDAP сървър или някакъв друг централизиран източник за автентикация, който може да имате. Докато всеки от потребителите може да получи шел-достъп на машината, всеки SSH оторизационен механизъм за който се сещате, би трябвало да работи.</p> </div> <div id="_generate_ssh_key" class="paragraph"> <p>=== Генериране на SSH публичен ключ</p> </div> <div class="paragraph"> <p> Много Git сървъри автентикират достъпа ползвайки SSH публични ключове. За да осигури такъв ключ, всеки потребител на системата ви трябва първо да си го генерира. Процесът е подобен за всички операционни системи. Първо, трябва да проверите дали вече нямате ключ. По подразбиране, генерираните от потребителя SSH ключове се пазят в директория <code>~/.ssh</code> в домашната му папка. Може лесно да проверите дали имате ключове като просто отворите директорията и покажете съдържанието ѝ:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cd ~/.ssh $ ls authorized_keys2 id_dsa known_hosts config id_dsa.pub</code></pre> </div> </div> <div class="paragraph"> <p>Търсите чифт файлове с имена от рода на <code>id_dsa</code> или <code>id_rsa</code> и съответен файл с разширение <code>.pub</code>. Файлът с разширение <code>.pub</code> е публичният ви ключ, а другият е секретния. Ако нямате тези файлове (или дори не разполагате с <code>.ssh</code> директория), можете да ги създадете с програмата <code>ssh-keygen</code>, която идва с пакета SSH под Linux/macOS и също така с Git for Windows:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ ssh-keygen -o Generating public/private rsa key pair. Enter file in which to save the key (/home/schacon/.ssh/id_rsa): Created directory '/home/schacon/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/schacon/.ssh/id_rsa. Your public key has been saved in /home/schacon/.ssh/id_rsa.pub. The key fingerprint is: d0:82:24:8e:d7:f1:bb:9b:33:53:96:93:49:da:9b:e3 schacon@mylaptop.local</code></pre> </div> </div> <div class="paragraph"> <p>Програмата първо пита къде да съхранява ключа (<code>.ssh/id_rsa</code>) и след това пита два пъти за парола, която можете да оставите празна, ако не желаете да я въвеждате всеки път, когато използвате ключа. Обаче, ако използвате парола, уверете се че сте добавили флага <code>-o</code>; това ще съхрани частния ключ във формат, който е по-устойчив на brute-force атаки за пароли в сравнение с формата по подразбиране. Може също да използвате <code>ssh-agent</code> инструмента за да избегнете въвеждането на паролата всеки път.</p> </div> <div class="paragraph"> <p>След това, всеки потребител трябва да изпрати публичния си ключ на вас или който администрира Git сървъра (подразбираме, че използвате схема, при която SSH сървърът изисква публични ключове). Всичко което трябва да се направи е да се копира съдържанието на <code>.pub</code> файла и да се изпрати по имейл. Публичните ключове изглеждат по подобен начин:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cat ~/.ssh/id_rsa.pub ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3 Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx NrRFi9wrf+M7Q== schacon@mylaptop.local</code></pre> </div> </div> <div class="paragraph"> <p>За повече информация и детайлно упътване за създаване на SSH ключове на множество операционни системи, погледнете GitHub SSH keys страницата на адрес <a href="https://docs.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent" class="bare" target="_blank" rel="noopener">https://docs.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent</a>.</p> </div> <div id="_setting_up_server" class="paragraph"> <p>=== Настройка на сървъра</p> </div> <div class="paragraph"> <p>Нека преминем през настройката на SSH достъпа от страна на сървъра. В този пример, ще използвате метода <code>authorized_keys</code> за автентикиране на вашите потребители. Подразбираме също така, че използвате стандартна Linux дистрибуция, например Ubuntu.</p> </div> </div> </div> <div class="paragraph"> <p>Голяма част от описаното тук може да се автоматизира с командата <code>ssh-copy-id</code>, вместо чрез ръчно копиране и инсталиране на публични ключове.</p> </div> <div class="exampleblock"> <div class="content"> <div class="paragraph"> <p>Първо, създавате <code>git</code> потребител и <code>.ssh</code> директория за него.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ sudo adduser git $ su git $ cd $ mkdir .ssh && chmod 700 .ssh $ touch .ssh/authorized_keys && chmod 600 .ssh/authorized_keys</code></pre> </div> </div> <div class="paragraph"> <p>След това, трябва да добавите няколко публични ключа на разработчици към файла <code>authorized_keys</code> на потребителя <code>git</code>. Нека кажем, че имате няколко такива ключа и ги съхранявате във временни файлове. Да припомним, публичните ключове изглеждат така:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cat /tmp/id_rsa.john.pub ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4L ojG6rs6hPB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4k Yjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9Ez Sdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myiv O7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPq dAv8JggJICUvax2T9va5 gsg-keypair</code></pre> </div> </div> <div class="paragraph"> <p>Просто трябва да ги добавите към <code>authorized_keys</code> файла на потребителя <code>git</code> в <code>.ssh</code> директорията му:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys $ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys $ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys</code></pre> </div> </div> <div class="paragraph"> <p>Сега можете да инициализирате празно хранилище за тях изпълнявайки <code>git init</code> с опцията <code>--bare</code>, което ще създаде хранилище без работна директория:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cd /srv/git $ mkdir project.git $ cd project.git $ git init --bare Initialized empty Git repository in /srv/git/project.git/</code></pre> </div> </div> <div class="paragraph"> <p>След като направите това, John, Josie, или Jessica могат да изпратят първата версия на своя проект в това хранилище като го добавят като отдалечено и изпратят някой клон. Отбележете, че е необходимо някой да се логва в тази машина и да създава празно хранилище всеки път, когато искате да добавите проект. Нека ползваме <code>gitserver</code> за име на сървъра, който настроихме. Ако го използвате само локално и настроите DNS сървъра си да сочи към адреса му, тогава може да използвате командите буквално така (подразбираме, че <code>myproject</code> е съществуващ проект с файлове):</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># от компютъра на John $ cd myproject $ git init $ git add . $ git commit -m 'Initial commit' $ git remote add origin git@gitserver:/srv/git/project.git $ git push origin master</code></pre> </div> </div> <div class="paragraph"> <p>Сега вече другите могат да клонират проекта и да изпращат промени към него също така лесно:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone git@gitserver:/srv/git/project.git $ cd project $ vim README $ git commit -am 'Fix for README file' $ git push origin master</code></pre> </div> </div> <div class="paragraph"> <p>Ползвайки този подход можете лесно да пуснете read/write Git сървър за малък екип разработчици.</p> </div> <div class="paragraph"> <p>Следва да сте забелязали, че сега всички тези потребители могат също така да се логнат на сървъра като потребител <code>git</code>. Ако искате да ограничите това, ще трябва да смените шела на <code>git</code> с нещо различно във файла <code>/etc/passwd</code>.</p> </div> <div class="paragraph"> <p>Можете лесно да ограничите <code>git</code> потребителя само до Git дейности с рестриктивния инструмент <code>git-shell</code>, който идва с Git. Ако го използвате за login шел за вашия <code>git</code> потребител, то той ще има доста по-ограничени права в сървъра. Просто използвайте <code>git-shell</code> вместо <code>bash</code> или <code>csh</code> за шел на потребителя. За да го направите, първо трябва да добавите <code>git-shell</code> към <code>/etc/shells</code>, ако той вече не е там:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cat /etc/shells # проверявате дали git-shell е вече във файла и ако не е... $ which git-shell # уверете се, че git-shell е инсталиран на системата $ sudo -e /etc/shells # и добавете пътя до него, който показва командата which</code></pre> </div> </div> <div class="paragraph"> <p>Сега можете да редактирате шела за даден потребител изпълнявайки <code>chsh <username> -s <shell></code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ sudo chsh git -s $(which git-shell)</code></pre> </div> </div> <div class="paragraph"> <p>Сега вече <code>git</code> потребителят може да използва SSH комуникация само за да изтегля и изпраща Git хранилища и няма да има пълноценен шел достъп в машината. Ако пробвате, ще получите отказ:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ ssh git@gitserver fatal: Interactive git shell is not enabled. hint: ~/git-shell-commands should exist and have read and execute access. Connection to gitserver closed.</code></pre> </div> </div> <div class="paragraph"> <p>В този момент обаче, потребителите все още могат да използват SSH port forwarding за достъп до всеки хост, който git сървърът вижда. Ако искате да избегнете това, може да редактирате файла <code>authorized_keys</code> и да добавите следните опции за всеки ключ, който искате да ограничите:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty</code></pre> </div> </div> <div class="paragraph"> <p>Резултатът трябва да изглежда така:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cat ~/.ssh/authorized_keys no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4LojG6rs6h PB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4kYjh6541N YsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9EzSdfd8AcC IicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myivO7TCUSBd LQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPqdAv8JggJ ICUvax2T9va5 gsg-keypair no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEwENNMomTboYI+LJieaAY16qiXiH3wuvENhBG...</code></pre> </div> </div> <div class="paragraph"> <p>Сега мрежовите команди на Git ще работят нормално, но потребителите няма да имат шел достъп. Както се вижда от изхода на командата, можете също така да направите директория в домашната такава на потребителя <code>git</code>, което ще специализира малко <code>git-shell</code> командата. Например, можете да ограничите наличните Git команди, които сървърът приема или да промените съобщението, които потребителите виждат, ако се опитат да се логнат през SSH. Изпълнете <code>git help shell</code> за повече информация за настройване на шела.</p> </div> <div class="paragraph"> <p>=== Git Daemon</p> </div> <div class="paragraph"> <p> Следващата стъпка е да настроим демон, който обслужва хранилища чрез “Git” протокола. Това е често срещан избор за бърз достъп до вашите Git данни, без автентикация. Помнете, че в този случай данните ви са публично достъпни в рамките на съответната мрежа.</p> </div> <div class="paragraph"> <p>Ако използвате протокола на сървър извън защитната стена, това следва да става само за публично достъпни проекти. Ако сте зад защитна стена обаче, бихте могли да го ползвате за проекти, до които достъп за четене трябва да имат голям брой сътрудници и за които не желаете да настройвате SSH ключове поотделно.</p> </div> <div class="paragraph"> <p>Независимо от случая, Git протоколът е сравнително лесен за настройка. В общи линии, трябва да изпълните долната команда в daemonized режим:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git daemon --reuseaddr --base-path=/srv/git/ /srv/git/</code></pre> </div> </div> <div class="paragraph"> <p>Опцията <code>--reuseaddr</code> позволява сървърът да се рестартира без да изчаква таймаут на старите конекции, а <code>--base-path</code> позволява на хората да клонират проекти без да трябва да указват пълния път. Пътят в края на командата указва на Git демона къде да следи за хранилища за експорт. Ако използвате защитна стена, ще трябва също така да разрешите достъпа до порт 9418 на сървъра.</p> </div> <div class="paragraph"> <p>Пускането на демона може да се прави по различни начини в зависимост от използваната операционна система.</p> </div> <div class="paragraph"> <p>Понеже <code>systemd</code> вече е най-разпространената init система в модерните Linux дистрибуции, бихте могли да я ползвате за целта. Просто създайте файл <code>/etc/systemd/system/git-daemon.service</code> със следното съдържание:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">[Unit] Description=Start Git Daemon [Service] ExecStart=/usr/bin/git daemon --reuseaddr --base-path=/srv/git/ /srv/git/ Restart=always RestartSec=500ms StandardOutput=syslog StandardError=syslog SyslogIdentifier=git-daemon User=git Group=git [Install] WantedBy=multi-user.target</code></pre> </div> </div> <div class="paragraph"> <p>Може да видите, че Git демонът се пуска с потребител и група <code>git</code>. Ако се налага, променете ги според вашите нужди и се уверете, че потребителят който сте написали съществува в системата. Също така, проверете дали изпълнимият файл се намира в <code>/usr/bin/git</code> и го коригирайте, ако не е.</p> </div> <div class="paragraph"> <p>Накрая трябва да изпълните <code>systemctl enable git-daemon</code> за да пуснете услугата автоматично при рестарт на компютъра. Ръчното пускане и спиране на услугата се прави с командите <code>systemctl start git-daemon</code> и <code>systemctl stop git-daemon</code>, съответно.</p> </div> <div class="paragraph"> <p>На други системи, може да искате да ползвате <code>xinetd</code>, скрипт в <code>sysvinit</code> системата или пък нещо друго като похват — трябва просто да пуснете командата като демон и да наблюдавате статуса ѝ.</p> </div> <div class="paragraph"> <p>Остава да кажете на Git в кои хранилища трябва да се разреши свободния достъп през Git протокола. Можете да направите това във всяко хранилище създавайки файл с име <code>git-daemon-export-ok</code>.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cd /path/to/project.git $ touch git-daemon-export-ok</code></pre> </div> </div> <div class="paragraph"> <p>Наличието му казва на Git, че е ОК да обслужва съответния проект без автентикация.</p> </div> <div class="paragraph"> <p>=== Smart HTTP</p> </div> <div class="paragraph"> <p> Вече имаме автентикиран достъп през SSH и неавтентикиран през <code>git://</code> протокола, но съществува и протокол, който може да прави и двете едновременно. Процесът по настройка на Smart HTTP всъщност се свежда до разрешаването на CGI скрипт, който идва с Git и е известен като <code>git-http-backend</code> на сървъра. Този скрипт ще чете пътя и хедърите изпратени от <code>git fetch</code> или <code>git push</code> към HTTP URL и ще разбере дали клиентът може да комуникира през http (което е така за всеки клиент след версия 1.6.6). Ако CGI скриптът види, че клиентът е смарт, той ще комуникира с него по интелигентен начин. В противен случай, ще се върне към по-опростения способ (така че да е обратно съвместим с по-старите клиенти).</p> </div> <div class="paragraph"> <p>Нека минем през съвсем простата настройка. Ще използваме Apache като CGI сървър. Ако нямате настроен Apache, можете да го направите в Linux система приблизително така:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ sudo apt-get install apache2 apache2-utils $ a2enmod cgi alias env</code></pre> </div> </div> <div class="paragraph"> <p>Това ще разреши модулите <code>mod_cgi</code>, <code>mod_alias</code>, и <code>mod_env</code>, които са необходими за нашите цели.</p> </div> <div class="paragraph"> <p>Ще трябва също така да промените групата на директориите в <code>/srv/git</code> на <code>www-data</code>, така че уеб сървърът да има права за четене и писане в хранилищата, защото инстанцията на Apache, която ще изпълнява CGI скрипта, ще работи по подразбиране като този потребител:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ chgrp -R www-data /srv/git</code></pre> </div> </div> <div class="paragraph"> <p>След това трябва да променим някои неща по конфигурацията на Apache, така че да използва <code>git-http-backend</code> скрипта като средство за обработка на всички заявки, идващи в <code>/git</code> пътя на уеб сървъра.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">SetEnv GIT_PROJECT_ROOT /srv/git SetEnv GIT_HTTP_EXPORT_ALL ScriptAlias /git/ /usr/lib/git-core/git-http-backend/</code></pre> </div> </div> <div class="paragraph"> <p>Ако оставите променливата <code>GIT_HTTP_EXPORT_ALL</code>, тогава Git ще допуска неавтентикираните потребители само до хранилищата, съдържащи файла <code>git-daemon-export-ok</code> - точно както го прави и Git демона.</p> </div> <div class="paragraph"> <p>Накрая, ще искаме да накараме Apache да позволява заявки от автентикирани потребители с права на запис към <code>git-http-backend</code> с блок подобен на следния:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"><Files "git-http-backend"> AuthType Basic AuthName "Git Access" AuthUserFile /srv/git/.htpasswd Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#) Require valid-user </Files></code></pre> </div> </div> <div class="paragraph"> <p>Това значи, че трябва да създадете <code>.htpasswd</code> файл, съдържащ паролите за всички валидни потребители. Ето пример за добавен потребител “schacon” в такъв файл:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ htpasswd -c /srv/git/.htpasswd schacon</code></pre> </div> </div> <div class="paragraph"> <p>Има много различни начини да накарате Apache да автентикира потребители, просто трябва да изберете подходящия за вас. Тук просто посочихме един от най-простите варианти. Вероятно също ще искате да настроите достъп през SSL, така че комуникацията да е криптирана.</p> </div> <div class="paragraph"> <p>Няма да навлизаме по-навътре в конфигурационните детайли на Apache, тъй като може да използвате различни похвати за автентикация или изцяло различен уеб сървър. Идеята е, че Git идва с CGI скрипт наречен <code>git-http-backend</code>, който когато бъде извикан, ще поеме цялата комуникация по приемането и изпращането на данни през HTTP. Самият скрипт не извършва сам по себе си никаква автентикация, но това може лесно да бъде контролирано при уеб сървъра, който го извиква. Можете да го използвате почти с всеки CGI уеб сървър, така че изберете този, който предпочитате.</p> </div> </div> </div> <div class="paragraph"> <p>За повече информация за настройка на Apache, вижте документацията тук: <a href="https://httpd.apache.org/docs/current/howto/auth.html" class="bare" target="_blank" rel="noopener">https://httpd.apache.org/docs/current/howto/auth.html</a></p> </div> <div class="exampleblock"> <div class="content"> <div class="paragraph"> <p>=== GitWeb</p> </div> <div class="paragraph"> <p> Сега, когато имате базисен read/write и read-only достъп до вашия проект, може да искате да добавите прост уеб базиран визуализатор. Git предоставя CGI скрипт наречен GitWeb, който понякога се ползва за целта.</p> </div> <div id="gitweb" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/git-instaweb.png" alt="GitWeb уеб базиран потребителски интерфейс"> </div> <div class="title">Фигура 49. GitWeb уеб базиран потребителски интерфейс</div> </div> <div class="paragraph"> <p>Ако искате да проверите как ще изглежда GitWeb за вашия проект, Git предлага команда с която да пуснете временна инстанция при условие че системата ви има инсталиран олекотен уеб сървър като <code>lighttpd</code> или <code>webrick</code>. На Linux машини, <code>lighttpd</code> често идва предварително инсталиран, така че може да го стартирате с командата <code>git instaweb</code> в директорията на проекта. Ако сте на Mac, Leopard идва с инсталиран Ruby, така че <code>webrick</code> може да е удобна опция. За да пуснете <code>instaweb</code> с non-lighttpd сървър, можете да я изпълните с аргумента <code>--httpd</code>.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git instaweb --httpd=webrick [2009-02-21 10:02:21] INFO WEBrick 1.3.1 [2009-02-21 10:02:21] INFO ruby 1.8.6 (2008-03-03) [universal-darwin9.0]</code></pre> </div> </div> <div class="paragraph"> <p>Това ще ви пусне HTTPD сървър на порт 1234 и след това автоматично ще се стартира уеб браузър, който отваря тази страница. Лесно е от ваша страна. Когато сте готови и искате да спрете сървъра, изпълнете командата с аргумента <code>--stop</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git instaweb --httpd=webrick --stop</code></pre> </div> </div> <div class="paragraph"> <p>Ако пък искате уеб интерфейсът да е постоянно достъпен, например за екипа ви или за проект с отворен код, ще трябва да направите така, че CGI скриптът да се обслужва от нормален уеб сървър. Някои Linux дистрибуции имат пакета <code>gitweb</code>, който може да се инсталира през <code>apt</code> или <code>dnf</code>, така че може да ползвате и този начин. Ще преминем набързо през инсталацията на GitWeb. Първо, ще ви трябва сорс кода на Git, с който идва GitWeb и след това генерирате custom CGI скрипт:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone git://git.kernel.org/pub/scm/git/git.git $ cd git/ $ make GITWEB_PROJECTROOT="/srv/git" prefix=/usr gitweb SUBDIR gitweb SUBDIR ../ make[2]: `GIT-VERSION-FILE' is up to date. GEN gitweb.cgi GEN static/gitweb.js $ sudo cp -Rf gitweb /var/www/</code></pre> </div> </div> <div class="paragraph"> <p>Отбележете, че трябва да кажете на командата къде да намира Git хранилищата ви посредством променливата <code>GITWEB_PROJECTROOT</code>. След това, трябва да накарате Apache да използва CGI за този скрипт, за което може да добавите виртуален хост:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"><VirtualHost *:80> ServerName gitserver DocumentRoot /var/www/gitweb <Directory /var/www/gitweb> Options +ExecCGI +FollowSymLinks +SymLinksIfOwnerMatch AllowOverride All order allow,deny Allow from all AddHandler cgi-script cgi DirectoryIndex gitweb.cgi </Directory> </VirtualHost></code></pre> </div> </div> <div class="paragraph"> <p>Да кажем пак, GitWeb може да се обслужва с произволен CGI или Perl съвместим уеб сървър; ако предпочитате различен от Apache, няма проблем да го ползвате. В този момент трябва да можете да отворите адреса <code><a href="http://gitserver/" class="bare">http://gitserver/</a></code> за да видите хранилищата си онлайн.</p> </div> <div class="paragraph"> <p>=== GitLab</p> </div> <div class="paragraph"> <p> GitWeb е доста семпъл вариант за визуализация. Ако търсите по-модерен, напълно функционален Git сървър, съществуват няколко проекта с отворен код, които са на ваше разположение. Понеже GitLab е един от най-популярните, ще разгледаме него за пример. Това е малко по-сложно от GitWeb и вероятно ще изисква повече поддръжка, но е и много по-пълноценна алтернатива.</p> </div> <div class="paragraph"> <p>==== Инсталация</p> </div> <div class="paragraph"> <p>GitLab е уеб приложение използващо база данни, така че инсталацията му изисква малко повече усилия сравнена с някои други Git сървъри. За щастие, този процес е много добре документиран и проектът активно се поддържа. GitLab горещо препоръчва инсталирането на сървъра ви да се прави през официалния Omnibus GitLab пакет.</p> </div> <div class="paragraph"> <p>Другите опции за инсталиране са:</p> </div> <div class="ulist"> <ul> <li> <p>GitLab Helm chart, за ползване с Kubernetes.</p> </li> <li> <p>Dockerized GitLab пакети за използване с Docker.</p> </li> <li> <p>От сорс-файлове.</p> </li> <li> <p>От облачен доставчик като AWS, Google Cloud Platform, Azure, OpenShift и Digital Ocean.</p> </li> </ul> </div> <div class="paragraph"> <p>За повече информация прочетете <a href="https://gitlab.com/gitlab-org/gitlab-foss/-/blob/master/README.md" target="_blank" rel="noopener">GitLab Community Edition (CE) ръководството</a>.</p> </div> <div class="paragraph"> <p>==== Администрация</p> </div> <div class="paragraph"> <p>Административният интерфейс на GitLab е достъпен през браузър. Отворете страницата на IP адреса на машината, на която е инсталиран GitLab и се логнете като администратор. Фабричното потребителско име е <code>admin@local.host</code>, а паролата <code>5iveL!fe</code> (ще бъдете помолени да я промените веднага след входа). След това натиснете иконата “Admin area” в менюто в горния десен край.</p> </div> <div id="gitlab_menu" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/gitlab-menu.png" alt="“Admin area” елемента в менюто на GitLab"> </div> <div class="title">Фигура 50. Елементът “Admin area” в менюто на GitLab</div> </div> <div class="paragraph"> <p>===== Потребители</p> </div> <div class="paragraph"> <p>Потребителите в GitLab са акаунти, които съответстват на хора. Самите акаунти не са сложни; в основни линии представляват колекция от персонални данни прикачени към логин информацията. Всеки потребителски акаунт притежава <strong>namespace</strong>, за логическо групиране на проектите, които притежава. Така, ако потребител с име jane има проект с име project, то този проект ще е с url <code><a href="http://server/jane/project" class="bare">http://server/jane/project</a></code>.</p> </div> <div id="gitlab_users" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/gitlab-users.png" alt="Административният екран на GitLab за управление на потребители"> </div> <div class="title">Фигура 51. Административният екран на GitLab за управление на потребители</div> </div> <div class="paragraph"> <p>Изтриването на потребител може да стане по два начина: “Блокирането” на потребител забранява логването му в GitLab инстанцията, но всички данни в съответния namespace ще бъдат запазени и всички къмити подписани с имейл адреса на този потребител ще сочат все още към съответния потребителски профил.</p> </div> <div class="paragraph"> <p>“Изтриването” от своя страна, тотално унищожава потребителя от базата данни и файловата система. Всички проекти и данните в съответния namespace се изтриват и всички групи, които потребителят притежава, също се изтриват. Очевидно тази втора опция е много по-деструктивна и се използва рядко.</p> </div> <div id="_gitlab_groups_section" class="paragraph"> <p>===== Групи</p> </div> <div class="paragraph"> <p>GitLab групата представлява съвкупност от проекти плюс информация за това как потребителите имат достъп до тях. Всяка група има namespace за проектите (по същия начин като потребителите), така че ако групата training съдържа проект materials, то неговият url ще бъде <code><a href="http://server/training/materials" class="bare">http://server/training/materials</a></code>.</p> </div> <div id="gitlab_groups" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/gitlab-groups.png" alt="Административният екран за групите в GitLab"> </div> <div class="title">Фигура 52. Административният екран за групите в GitLab</div> </div> <div class="paragraph"> <p>Всяка група е асоциирана с множество потребители, всеки от които разполага с ниво на достъп до групата и проектите в нея. То варира от “Guest” (с достъп до issues и chat) до “Owner” (пълен контрол над групата, членовете ѝ и нейните проекти). Типовете права са твърде много, за да ги изброяваме всичките, но GitLab има полезни линкове за помощ в административния интерфейс.</p> </div> <div class="paragraph"> <p>===== Проекти</p> </div> <div class="paragraph"> <p>Един GitLab проект приблизително съответства на единично Git хранилище. Всеки проект принадлежи на един namespace, потребителски или на група. Ако проектът принадлежи на потребител, то този потребител има пряк контрол върху това кой ще има достъп до него; ако е в група, то тогава user-level правата на групата ще се приложат съответно.</p> </div> <div class="paragraph"> <p>Всеки проект има също така ниво на видимост, което контролира кой има права за четене на страниците и хранилището му. Ако един проект е <em>Private</em>, то собственикът му трябва изрично да даде права за достъп на него до потребителите, които пожелае да го виждат. <em>Internal</em> проектите са видими за всеки логнат потребител, а <em>Public</em> проектите са видими за всички. Това контролира както <code>git fetch</code> достъпа, така и достъпа до уеб UI интерфейса за този проект.</p> </div> <div class="paragraph"> <p>===== Hooks</p> </div> <div class="paragraph"> <p>GitLab подържа hooks като способ за сигнализация, на ниво проект и система. За всеки от тях, GitLab сървърът ще направи HTTP POST заявка с описателна JSON-фирматирана информация, когато възникнат съответните събития. Това е полезен начин да свържете вашите Git хранилища и GitLab инстанцията си към останалата част от автоматизацията на разработките като например CI сървъри, чат стаи или deployment инструменти.</p> </div> <div class="paragraph"> <p>==== Използване</p> </div> <div class="paragraph"> <p>Вероятно най-напред ще искате да създадете GitLab проект. Това се прави чрез иконата “+” на лентата с инструменти. Ще трябва да въведете име за проекта, към кой namespace ще принадлежи той и какво ниво на видимост ще има. Повечето от тези неща не са перманентни и могат да се редактират по-късно. Натиснете “Create Project” и сте готови.</p> </div> <div class="paragraph"> <p>След като проектът съществува, вероятно ще искате да го свържете с локално Git хранилище. Всеки проект е достъпен през HTTPS или SSH и всеки от тези протоколи може да се използва като Git remote. Адресите са видими в горната част на страницата на проекта. В налично локално Git хранилище, тази команда ще създаде отдалечена референция с име <code>gitlab</code> към хостваната локация:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git remote add gitlab https://server/namespace/project.git</code></pre> </div> </div> <div class="paragraph"> <p>Ако нямате локално копие на хранилището, може просто да изпълните:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone https://server/namespace/project.git</code></pre> </div> </div> <div class="paragraph"> <p>Уеб интерфейсът осигурява достъп до множество удобни изгледи на самото хранилище. Домашната страница на всеки проект показва последната активност и линковете в горната част ще ви преведат до изгледи на файловете в проекта и историята на къмитите.</p> </div> <div class="paragraph"> <p>==== Съвместна работа</p> </div> <div class="paragraph"> <p>Най-простият начин за съвместна работа в GitLab е да дадете на друг потребител директно push права за достъп до Git хранилището ви. Можете да добавите потребител към проекта от секцията “Members” в настройките на проекта, където може да асоциирате и ниво на достъп за него (различните нива на достъп се разглеждат по-подробно в <a href="/book/bg/v2/ch00/_gitlab_groups_section">[_gitlab_groups_section]</a>). Давайки на потребителя ниво “Developer” или по-високо, вие му позволявате свободно да изпраща къмити и клонове директно в хранилището.</p> </div> <div class="paragraph"> <p>Друг метод за колаборация е чрез използването на merge requests. Тази функция позволява на всеки потребител, който вижда даден проект, да сътрудничи в него по контролиран начин. Потребителите с директен достъп могат просто да създадат клон, да изпратят в него къмити и да отворят merge request от техния клон обратно в <code>master</code> или който и да е друг клон. Потребителите без push права за дадено хранилище могат да го клонират при себе си (“fork”), да правят къмити в <em>това</em> тяхно копие и да отворят merge request от него обратно към основния проект. Този модел на работа позволява на собственика на проекта да има пълен контрол върху това какво и кога влиза в хранилището и едновременно с това да позволява сътрудничество от непознати потребители.</p> </div> <div class="paragraph"> <p>Merge requests и issues са основните обекти на дискусиите в GitLab. Всеки merge request позволява line-by-line дискусия на предложената промяна (което поддържа олекотен вид code review), както и обща дискусионна нишка. И двата обекта могат да се асоциират към потребители или да се организират в milestones.</p> </div> <div class="paragraph"> <p>Тази секция е фокусирана основно върху Git функциите на GitLab, но като един наистина зрял проект, той предлага много други възможности за съвместна работа на екипа ви като например множество wiki за проектите и инструменти за системна поддръжка. Едно от предимствата на GitLab е в това, че веднъж настроен и пуснат, рядко ще ви се налага да променяте конфигурационен файл или да влизате в сървъра през SSH; повечето административни задачи се осъществяват през уеб интерфейса.</p> </div> <div class="paragraph"> <p>=== Други опции за хостване</p> </div> <div class="paragraph"> <p>Ако не желаете да се занимавате с работата по инсталация и поддръжка на собствен Git сървър, налице са доста опции за хостване на Git проектите ви на външен такъв. Това си има предимства: обикновено хостваната услуга е лесна за създаване и поддържане на проекти и освен това не се нуждае да правите поддръжка и мониторинг. Дори и да сте си инсталирали собствен сървър, може все още да искате да се възползвате от публичните хостинг услуги за съхранение на проектите ви с отворен код – така по-лесно ще бъдете в контакт с общността от open source разработчици.</p> </div> <div class="paragraph"> <p>В днешни дни броят на хостинг опциите е достатъчно голям, така че да изберете вашата претегляйки предимствата и недостатъците им. Актуален списък на вариантите се поддържа в страницата GitHosting в основното wiki на Git на адрес <a href="https://git.wiki.kernel.org/index.php/GitHosting" class="bare" target="_blank" rel="noopener">https://git.wiki.kernel.org/index.php/GitHosting</a>.</p> </div> <div class="paragraph"> <p>Ще разгледаме в детайли GitHub в главата <a href="/book/bg/v2/ch00/ch06-github">GitHub</a>, понеже е най-голямата хостинг система в момента и вероятно ще искате да я ползвате така или иначе. Но съществуват и дузини други варианти, ако не желаете да инсталирате и поддържате собствен Git сървър.</p> </div> <div class="paragraph"> <p>=== Обобщение</p> </div> <div class="paragraph"> <p>Разполагате с няколко опции за създаване и ползване на отдалечени Git хранилища, чрез които да сътрудничите заедно с екипа разработчици.</p> </div> <div class="paragraph"> <p>Пускането на собствен сървър ви дава висока степен на контрол и ви позволява да го разположите зад собствена защитна стена, но пък изисква известно време за настройка и регулярна поддръжка. Ако разположите кода си на хостван сървър, тогава първоначалната настройка и поддръжката не изискват никакви усилия, но от друга страна - не всички организации са съгласни на такъв един подход.</p> </div> <div class="paragraph"> <p>Би следвало да е лесно да изберете кое решение (или комбинация от решения) е подходящо за вашата организация.</p> </div> <div id="ch05-distributed-git" class="paragraph"> <p>== Git в разпределена среда</p> </div> <div class="paragraph"> <p> Сега, когато вече имате настроено отдалечено Git хранилище като обща точка за всички разработчици по даден проект и сте достатъчно сигурни в познанията за основните Git команди в процеса на локална работа, ще се спрем на това как да ползваме някои разпределени похвати за работа.</p> </div> <div class="paragraph"> <p>В тази глава ще видите как се работи с Git в разпределена работна среда като сътрудник и интегратор. Това включва инструкции за това как да допринасяте успешно със свой код в общ проект по възможно най-лесния начин за вас и за автора на проекта, а също така и как самите вие да поддържате успешно проект, по който работят множество разработчици.</p> </div> <div class="paragraph"> <p>=== Разпределени работни процеси</p> </div> <div class="paragraph"> <p> За разлика от централизираните Version Control Systems (CVCSs), разпределената натура на Git позволява по-голяма гъвкавост по отношение на това как разработчиците сътрудничат в проектите. В централизираните системи всеки разработчик е нещо като възел работещ повече или по-малко с един централен хъб. В Git обаче, всеки разработчик може потенциално да бъде и хъб и възел – това значи, че може както да сътрудничи в други хранилища, така и да поддържа свое собствено публично такова, на което негови колеги да базират работата си и да сътрудничат. Това отваря доста възможности за структуриране на работните процеси за проекта и/или екипа, така че ще разгледаме някои познати парадигми, които съществуват благодарение на тази гъвкавост. Ще погледнем силните и слаби страни на всеки дизайн, а вие може да изберете един от тях или да смесвате възможности от различни такива.</p> </div> <div class="paragraph"> <p>==== Централизиран работен процес</p> </div> <div class="paragraph"> <p> В централизираните системи съществува единичен модел за съвместна работа – централизираният работен процес. Един централен хъб, <em>хранилище</em>, може да приема код и всеки трябва да синхронизира работата си с него. Множеството разработчици са възлите, консуматорите в този хъб и те трябва да се синхронизират с неговия статус.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/centralized_workflow.png" alt="Централизиран работен процес"> </div> <div class="title">Фигура 53. Централизиран работен процес</div> </div> <div class="paragraph"> <p>Това ще рече, че ако двама души клонират от централното хранилище и направят промени, то само първият от тях, който изпрати обратно промените си, ще може да направи това без проблем. Закъснелият разработчик ще трябва първо да слее при себе си работата на първия си колега, преди да публикува своите промени - така първите направени промени не се презаписват. Тази концепция работи както при Git, така и при Subversion (или всяка друга CVCS).</p> </div> <div class="paragraph"> <p>Ако вече се чувствате в свои води с този стил на работа във вашата компания или екип, можете лесно да продължите да го следвате и с Git. Просто направете единично хранилище и дайте на всеки от екипа си push достъп; Git няма да позволи на колегите да се презаписват един друг.</p> </div> <div class="paragraph"> <p>Да кажем, че John и Jessica започват да работят едновременно. John завършва промените си и ги изпраща към сървъра. След това Jessica опитва да публикува своите, но сървърът отказва това. Тя ще бъде уведомена, че се опитва да публикува non-fast-forward промени и че няма да може да го направи докато първо не изтегли и слее работата на John. Този работен процес е популярен, защото следва познати на много хора парадигми на работа.</p> </div> <div class="paragraph"> <p>Освен това не е ограничен до малки екипи. С модела за разклоняване на Git е възможно стотици разработчици успешно да работят едновременно по единичен проект през множество различни клонове код.</p> </div> <div id="_integration_manager" class="paragraph"> <p>==== Integration-Manager работен процес</p> </div> <div class="paragraph"> <p> Понеже Git позволява да имате множество отдалечени хранилища, възможно е да имате работен процес, при който всеки разработчик има достъп за писане до собственото си публично хранилище и достъп само за четене до всички останали. Този сценарий често включва canonical хранилище, което представлява “официалния” проект. За да сътрудничите в него, вие създавате собствено публично негово копие и публикувате промените си в него. След това, можете да изпратите заявка до собственика на canonical проекта за интегриране на вашите промени. Тогава този автор може да добави вашето хранилище като свое отдалечено такова, да тества локално промените ви, да ги слее в собствен клон и накрая да ги публикува в публичното хранилище така че да са достъпни за всички. Процесът работи така (вижте <a href="/book/bg/v2/ch00/wfdiag_b">Integration-manager работен процес</a>):</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Поддържащият проекта изпраща промени в публично хранилище.</p> </li> <li> <p>Сътрудник клонира хранилището и прави собствени промени по него.</p> </li> <li> <p>Сътрудникът публикува промените си в собственото си публично копие.</p> </li> <li> <p>Сътрудникът изпраща на поддържащия проекта съобщение със заявка за интегриране на промените.</p> </li> <li> <p>Поддържащият проекта добавя хранилището на сътрудника като отдалечено, издърпва и слива промените локално при себе си.</p> </li> <li> <p>Поддържащият проекта публикува слетите промени обратно в главното хранилище.</p> </li> </ol> </div> <div id="wfdiag_b" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/integration-manager.png" alt="Integration-manager работен процес"> </div> <div class="title">Фигура 54. Integration-manager работен процес</div> </div> <div class="paragraph"> <p> Това е доста разпространен начин на работа в хъб-базираните платформи като GitHub или Gitlab, където е лесно да клонирате проект и да публикувате промените си в него така, че всички да ги виждат. Едно от най-съществените предимства на този подход е, че позволява да продължите работата си, а поддържащият централното хранилище може да интегрира промените ви по всяко време. Сътрудниците не е нужно да чакат промените им да бъдат интегрирани – всяка страна може да работи със собствени темпове.</p> </div> <div class="paragraph"> <p>==== Dictator and Lieutenants работен процес</p> </div> <div class="paragraph"> <p> Това е вариант на работа с множество хранилища. Обикновено се използва в проекти от много голям мащаб, със стотици сътрудници; един пример за такъв е ядрото на Linux. Различни интегриращи мениджъри се грижат за определени части от хранилището; те се наричат <em>лейтенанти</em>. Всеки от лейтенантите има един интегриращ мениджър, известен като благосклонен диктатор (benevolent dictator). Този диктатор публикува код от собствена директория към референтно хранилище, от което всички сътрудници трябва да теглят. Процесът работи така (вижте <a href="/book/bg/v2/ch00/wfdiag_c">Benevolent dictator работен процес</a>):</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Обикновените разработчици работят по своя topic клон и пребазират работата си върху <code>master</code>. <code>master</code> клонът е този от референтното хранилище, към което диктаторът публикува.</p> </li> <li> <p>Лейтенантите сливат topic клоновете на разработчиците в своя <code>master</code> клон.</p> </li> <li> <p>Диктаторът слива <code>master</code> клоновете на лейтенантите в своя <code>master</code> клон.</p> </li> <li> <p>Накрая, диктаторът изпраща този <code>master</code> клон към референтното хранилище, така че разработчиците могат да се пребазират по него.</p> </li> </ol> </div> <div id="wfdiag_c" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/benevolent-dictator.png" alt="Benevolent dictator работен процес"> </div> <div class="title">Фигура 55. Benevolent dictator работен процес</div> </div> <div class="paragraph"> <p>Този процес на работа се ползва рядко, но може да е полезен в много големи проекти или в йерархични работни среди. Той позволява на лидера на проекта (диктатора) да делегира повече работа и да събира големи подмножества от код от много локации преди да ги интегрира.</p> </div> <div id="_patterns_for_managing_source_code_branches" class="paragraph"> <p>==== Patterns for Managing Source Code Branches</p> </div> </div> </div> <div class="paragraph"> <p>Martin Fowler е автор на ръководството "Patterns for Managing Source Code Branches". То обхваща всички популярни работни процеси в Git и обяснява как и кога да се използват. Налична е и глава сравняваща high и low integration frequencies.</p> </div> <div class="paragraph"> <p><a href="https://martinfowler.com/articles/branching-patterns.html" class="bare" target="_blank" rel="noopener">https://martinfowler.com/articles/branching-patterns.html</a></p> </div> <div class="exampleblock"> <div class="content"> <div class="paragraph"> <p>==== Обобщение</p> </div> <div class="paragraph"> <p>Това са част от популярните работни процеси, които могат да се реализират с разпределена система като Git, но може да видите, че са възможни голям брой варианти, които да съответстват на вашата специфична работна среда. Сега, след като (надяваме се) можете да изберете варианта, който е най-подходящ за вас, ще разгледаме някои по-специфични примери за това как да изпълняваме основните роли, които съставляват тези работни процеси. В следващата секция ще посочим няколко основни правила за това как да сътрудничим в проект.</p> </div> <div id="_contributing_project" class="paragraph"> <p>=== Как да сътрудничим в проект</p> </div> <div class="paragraph"> <p> Основната трудност с обяснението на това как се допринася към проект са големия брой варианти как да го направите. Понеже Git е много гъвкав, хората могат (и го правят) да си вършат работата по различни начини – затова е проблематично да се даде съвет как да постъпите – всеки проект си има специфики. Сред факторите, които влияят са броя разработчици, избрания вид работен процес, вашите права за достъп до хранилището и вероятно външния метод за съвместна работа.</p> </div> <div class="paragraph"> <p>Първата неизвестна е броят разработчици – колко са много активните колеги и колко често сътрудничат? В много случаи ще имате двама или трима програмисти с малко къмити на ден, или дори и по-малко при не толкова интензивни проекти. В големи компании или проекти обаче, могат да съществуват хиляди сътрудници със стотици или хиляди къмити на ден. Това е важно, защото с увеличаването на броя програмисти, ще срещате повече проблеми с това да се уверите, че кодът се прилага чисто или може лесно да се слива. Промените, които предлагате могат да се окажат остарели или несъвместими с друга работа, която е била слята докато сте работили или докато сте чакали вашия код да бъде одобрен. Възниква въпросът как да поддържате кода си актуален и къмитите си валидни?</p> </div> <div class="paragraph"> <p>Следващият фактор е избраният вид работен процес. Дали той е централизиран, при който всеки разработчик има еднакъв достъп за писане до основното хранилище? Дали проектът има поддържащ потребител или интегриращ мениджър, които да проверяват всички пачове? Дали всички пачове се разглеждат и одобряват колективно? Дали вие участвате в този процес? Съществува ли lieutenant-система и трябва ли първо да изпращате работата си на вашия лейтенант?</p> </div> <div class="paragraph"> <p>Следват правата ви на достъп. Последователността на работа, когато трябва да участвате в проект е доста различна в зависимост от това дали имате права за писане или не. Ако нямате права за писане, как този проект предпочита да приема външна помощ? Дали въобще съществува политика за това? Какво количество работа изпращате всеки път? Колко често правите това?</p> </div> <div class="paragraph"> <p>Всички тези въпроси могат да се отразят на начина, по който вие допринасяте към даден проект и какви работни процеси са предпочитани или достъпни за вас. Ще разгледаме различните аспекти в серия от примери, започвайки от прости към по-сложни и в края би следвало да си изградите представа какъв похват ще ви е необходим в различните случаи от реалната практика.</p> </div> <div id="_commit_guidelines" class="paragraph"> <p>==== Упътвания за къмитване</p> </div> <div class="paragraph"> <p>Преди да се фокусираме върху конкретни примери, едно малко отклонение касаещо къмит съобщенията. Да имате добра насока за създаване на къмити и да се придържате към нея ще направи работата ви с Git и сътрудничеството с колегите много по-лесни. Самият проект Git предоставя документ формулиращ множество добри съвети за създаване на къмити, от които да изпращате пачове — можете да го прочетете в сорс кода на Git, във файла Documentation/SubmittingPatches`.</p> </div> <div class="paragraph"> <p> Първо, вашите промени не трябва да съдържат никакви whitespace грешки. Git осигурява лесен начин да проверите това — преди да къмитнете, изпълнете командата <code>git diff --check</code>, която намира възможните whitespace грешки и ви ги показва.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/git-diff-check.png" alt="Изход от `git diff --check`"> </div> <div class="title">Фигура 56. Изход от <code>git diff --check</code> </div> </div> <div class="paragraph"> <p>Ако я изпълните преди да къмитнете, можете да разберете дали не вкарвате в проекта излишни интервали, които да отегчат останалите ви колеги.</p> </div> <div class="paragraph"> <p>След това, опитайте се да направите от всеки един къмит логически отделена, самостоятелна и специфична за даден проблем промяна. Ако можете, опитайте да правите промените си по-компактни — не програмирайте цял уикенд по пет различни задачи и после да ги изпращате като един масивен къмит в понеделник. Дори ако през уикенда не сте къмитвали, използвайте индексната област в понеделник за да разделите работата си на няколко къмита, всеки от които обслужва конкретен решен проблем и съдържа съответното подходящо съобщение. Ако някои от промените засягат един и същи файл, опитайте да използвате <code>git add --patch</code> за да индексирате файловете частично (показано в подробности в <a href="/book/bg/v2/ch00/_interactive_staging">Интерактивно индексиране</a>). В края на краищата, snapshot-тът на края на клона ви ще е идентичен независимо дали сте направили един или пет къмита, така че пробвайте да улесните живота на вашите колеги, когато започнат да разглеждат работата ви.</p> </div> <div class="paragraph"> <p>Този подход също така ви позволява по-късно да премахнете или коригирате само част от промените си, ако се наложи. <a href="/book/bg/v2/ch00/_rewriting_history">Манипулация на историята</a> описва няколко полезни Git трика за презапис на историята и интерактивно индексиране на файлове — използвайте тези инструменти като помощ за поддържане на чиста и разбираема история преди да изпратите работата си към някой друг.</p> </div> <div class="paragraph"> <p>Последното нещо, което също не трябва да се пренебрегва, е къмит съобщението. Изработете си навик да създавате качествени къмит съобщения и ще работите с Git и колегите си много по-приятно. Като основно правило, съобщенията ви трябва да започват с един ред не по-дълъг от 50 символа, описващ стегнато промените, следван от празен ред, след което може да се разположат по-дългите обяснения. Git проектът например изисква подробното описание да включва мотивите ви за дадената промяна и да обяснява разликите с оригиналния вариант на кода — и това е добро правило, което може да следвате. Пишете съобщенията си в императивна форма: "Fix bug" а не "Fixed bug" или "Fixes bug" Тук има един <a href="https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html" target="_blank" rel="noopener">шаблон, написан отначало от Tim Pope, който леко преработихме</a>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-text" data-lang="text">Кратко (50 или по-малко символа), изписано с големи букви описание на промените По-детайлно описание, ако е нужно. Пренасяйте го на около 72 символа. В някои случаи, първият ред се третира като subject на email и останалото от текста като тяло. Празният ред разделящ двете е много важен (освен ако не пропускате тялото изцяло); инструменти като rebase може да се объркат ако пуснете двете заедно. Напишете съобщението си в императивна форма: "Fix bug" а не "Fixed bug" или "Fixes bug". Тази конвенция съответства на къмит съобщенията генерирани от команди като git merge и git revert. Следващите абзаци се разделят с празни редове. - точките (Bullet) също са ОК - Обикновено за bullet се използва звездичка или тире следвани от един интервал, с празни редове помежду им, но правилата тук варират - Използвайте hanging indent</code></pre> </div> </div> <div class="paragraph"> <p>Ако всички ваши къмит съобщения следват този модел, нещата между вас и колегите ви разработчици ще вървят по-гладко. Git проектът има добре форматирани къмит съобщения — пробвайте да пуснете <code>git log --no-merges</code> в хранилището и ще видите колко добре форматирана е историята на проекта.</p> </div> </div> </div> <div class="paragraph"> <p>Много от примерите в тази книга съвсем не съдържат добре форматирани къмит съобщения; ние използваме <code>-m</code> параметъра към <code>git commit</code> за по-кратко.</p> </div> <div class="paragraph"> <p>Накратко, следвайте правилото за добра практика, а не гледайте какво сме направили ние.</p> </div> <div class="exampleblock"> <div class="content"> <div id="_private_team" class="paragraph"> <p>==== Малък частен екип</p> </div> <div class="paragraph"> <p> Най-простата схема, на която може да попаднете е частен проект с един или двама разработчици. “Частен,” в този смисъл, означава със затворен код — недостъпен за външния свят. Вие всички имате достъп за писане до хранилището.</p> </div> <div class="paragraph"> <p>В такава среда, можете да следвате работен процес подобен на този, който бихте ползвали в Subversion или друга централизирана система. Може все още да използвате предимствата на неща като офлайн къмитване и съвсем прости разклонявания и сливания, но работният процес може да е много подобен; основната разлика е, че сливанията се случват от страна на клиента, вместо на сървъра по време на къмита. Нека видим как би могло да изглежда това, когато двама разработчика започнат съвместна работа със споделено хранилище. Първият програмист, John, клонира хранилището, прави промяна и къмитва локално. Протоколните съобщения са заменени с <code>…</code> в тези примери за да ги съкратим.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># John's Machine $ git clone john@githost:simplegit.git Cloning into 'simplegit'... ... $ cd simplegit/ $ vim lib/simplegit.rb $ git commit -am 'Remove invalid default value' [master 738ee87] Remove invalid default value 1 files changed, 1 insertions(+), 1 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>Вторият разработчик, Jessica, прави същото нещо — клонира хранилището и къмитва промяна:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># Jessica's Machine $ git clone jessica@githost:simplegit.git Cloning into 'simplegit'... ... $ cd simplegit/ $ vim TODO $ git commit -am 'Add reset task' [master fbff5bc] Add reset task 1 files changed, 1 insertions(+), 0 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>Сега, Jessica публикува работата си на сървъра и това работи безпроблемно:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># Jessica's Machine $ git push origin master ... To jessica@githost:simplegit.git 1edee6b..fbff5bc master -> master</code></pre> </div> </div> <div class="paragraph"> <p>Последният ред от изхода отгоре показва полезно съобщение за резултата от push операцията. Основният формат е <code><oldref>..<newref> fromref → toref</code>, където <code>oldref</code> означава референция към предишния къмит, <code>newref</code> - към текущия, <code>fromref</code> е името на локалния клон, който се изпраща, и <code>toref</code> - на отдалечения, който се обновява. Ще виждате подобен изход по-натам в дискусиите, така че да имате представа какво означава това ще е полезно в осмислянето на различните статуси на хранилищата. Повече подробности има в документацията на командата <a href="https://git-scm.com/docs/git-push" target="_blank" rel="noopener">git-push</a>.</p> </div> <div class="paragraph"> <p>Продължаваме с този пример. Скоро след това, John прави някакви промени, къмитва ги в локалното си хранилище и се опитва да ги изпрати в същия сървър:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># 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'</code></pre> </div> </div> <div class="paragraph"> <p>В този случай, опитът му завършва с неуспех, защото Jessica е изпратила <em>нейните</em> промени по-рано. Това е особено важно да се разбере, ако сте ползвали Subversion, защото вероятно забелязвате, че двамата разработчици не са редактирали един и същи файл. Въпреки че Subversion ще направи автоматично сливане на сървъра в случаи като този (променени различни файлове), при Git вие трябва <em>първо</em> да слеете къмитите локално. С други думи, John трябва първо да изтегли upstream промените на Jessica, да ги слее в локалното си хранилище и едва след това ще може да изпраща към сървъра.</p> </div> <div class="paragraph"> <p>Като първа стъпка, John изтегля работата на Jessica (командата отдолу само <em>изтегля</em> последната работа на Jessica, не я слива автоматично):</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git fetch origin ... From john@githost:simplegit + 049d078...fbff5bc master -> origin/master</code></pre> </div> </div> <div class="paragraph"> <p>В този момент, локалното хранилище на John изглежда подобно на това:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/small-team-1.png" alt="Разклонена история на John"> </div> <div class="title">Фигура 57. Разклонена история на John</div> </div> <div class="paragraph"> <p>Следва командата за сливане в локалното хранилище:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git merge origin/master Merge made by the 'recursive' strategy. TODO | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>След като това локално сливане мине гладко, обновената история на John ще изглежда така:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/small-team-2.png" alt="Хранилището на John след сливането на `origin/master`"> </div> <div class="title">Фигура 58. Хранилището на John след сливането на <code>origin/master</code> </div> </div> <div class="paragraph"> <p>В този момент, John може да поиска да провери дали новия код не засяга по някакъв начин неговата работа и след като всичко е нормално, може да изпрати всичко към сървъра:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push origin master ... To john@githost:simplegit.git fbff5bc..72bbc59 master -> master</code></pre> </div> </div> <div class="paragraph"> <p>В края, историята на къмитите на John ще изглежда така:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/small-team-3.png" alt="Историята на John след изпращане към `origin` сървъра"> </div> <div class="title">Фигура 59. Историята на John след изпращане към <code>origin</code> сървъра</div> </div> <div class="paragraph"> <p>Междувременно, Jessica създава нов topic клон наречен <code>issue54</code> и прави три къмита в него. Тя все още не е издърпала промените на John, така че историята ѝ изглежда така:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/small-team-4.png" alt="Topic клонът на Jessica"> </div> <div class="title">Фигура 60. Topic клонът на Jessica</div> </div> <div class="paragraph"> <p>Внезапно Jessica научава, че John е публикувал някакви нови промени и иска да ги погледне, така че може да издърпа от сървъра:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># Jessica's Machine $ git fetch origin ... From jessica@githost:simplegit fbff5bc..72bbc59 master -> origin/master</code></pre> </div> </div> <div class="paragraph"> <p>Това ще изтегли промените на John и историята на Jessica изглежда така:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/small-team-5.png" alt="Историята на Jessica след изтегляне на промените на John"> </div> <div class="title">Фигура 61. Историята на Jessica след изтегляне на промените на John</div> </div> <div class="paragraph"> <p>Jessica решава, че нейният topic клон вече е готов, но иска да знае коя част от работата на John трябва да слее със своята, така че да може да публикува. За целта тя изпълнява командата <code>git log</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git log --no-merges issue54..origin/master commit 738ee872852dfaa9d6634e0dea7a324040193016 Author: John Smith <jsmith@example.com> Date: Fri May 29 16:01:27 2009 -0700 Remove invalid default value</code></pre> </div> </div> <div class="paragraph"> <p>Синтаксисът <code>issue54..origin/master</code> е филтър, който указва на Git да покаже само тези къмити, които са налични във втория клон (в случая <code>origin/master</code>), но липсват в първия (<code>issue54</code>). Ще разгледаме в подробности този синтаксис в <a href="/book/bg/v2/ch00/_commit_ranges">Обхвати от къмити</a>.</p> </div> <div class="paragraph"> <p>От горния изход можем да видим, че съществува един къмит направен от John, който Jessica не е сляла в локалното си копие. Ако тя слее <code>origin/master</code>, това ще е единственият къмит, който би променил локалната ѝ работа.</p> </div> <div class="paragraph"> <p>Сега тя може да слее своя topic клон в <code>master</code> клона си, да слее работата на John (<code>origin/master</code>) пак в него и накрая да публикува всички промени към сървъра.</p> </div> <div class="paragraph"> <p>Първо (след като е къмитнала всичко в <code>issue54</code> клона), Jessica превключва обратно към <code>master</code> клона си:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout master Switched to branch 'master' Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.</code></pre> </div> </div> <div class="paragraph"> <p>Jessica може да слее първо <code>origin/master</code> или <code>issue54</code> — и двата са upstream, така че редът е без значение. Крайният snapshot трябва да е идентичен, само историята ще се различава. Тя решава да слее първо <code>issue54</code> клона:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git merge issue54 Updating fbff5bc..4af4298 Fast forward README | 1 + lib/simplegit.rb | 6 +++++- 2 files changed, 6 insertions(+), 1 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>Не възникват проблеми, това е просто fast-forward сливане. Jessica сега завършва процеса по локално сливане като вмъква и работата на John от клона <code>orgin/master</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git merge origin/master Auto-merging lib/simplegit.rb Merge made by the 'recursive' strategy. lib/simplegit.rb | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>Всичко минава чисто и историята на Jessica сега изглежда така:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/small-team-6.png" alt="Историята на Jessica след сливане на промените от John"> </div> <div class="title">Фигура 62. Историята на Jessica след сливане на промените от John</div> </div> <div class="paragraph"> <p>Сега <code>origin/master</code> е достъпен от <code>master</code> клона на Jessica, така че тя може успешно да публикува промените (приемаме, че междувременно John не е изпращал нови такива):</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push origin master ... To jessica@githost:simplegit.git 72bbc59..8059c15 master -> master</code></pre> </div> </div> <div class="paragraph"> <p>Сега всеки разработчик е къмитнал по няколко пъти и успешно е слял работата на колегата си.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/small-team-7.png" alt="Историята на Jessica след изпращането на всички промени към сървъра"> </div> <div class="title">Фигура 63. Историята на Jessica след изпращането на всички промени към сървъра</div> </div> <div class="paragraph"> <p>Това е един от най-простите процеси на работа. Вие работите известно време (обикновено в topic клон) и сливате работата си в <code>master</code> клона, когато е свършена. Когато желаете да споделите тази работа, вие изтегляте и сливате вашия <code>master</code> с <code>origin/master</code>, ако той е променен, накрая публикувате <code>master</code> клона си в сървъра. Общата последователност изглежда подобно:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/small-team-flow.png" alt="Обичайна последователност от събития при прост работен процес с няколко разработчици в Git"> </div> <div class="title">Фигура 64. Обичайна последователност от събития при прост работен процес с няколко разработчици в Git</div> </div> <div class="paragraph"> <p>==== Работа в управляван екип</p> </div> <div class="paragraph"> <p> В този сценарий, ще разгледаме как да допринасяме в по-голям частен екип от разработчици. Ще разберете как да работите в обкръжение, в което малки групи си сътрудничат по определени функционалности, след което резултатът от работата на тези групи се интегрира в проекта от трети човек.</p> </div> <div class="paragraph"> <p>Нека приемем, че John и Jessica работят по функционалността “feature A”, докато Jessica и друг програмист, Josie, работят по друга опция, “feature B”. В този случай, компанията използва работен процес от тип integration-manager, при който работата на индивидуалните групи се интегрира само от определени хора и <code>master</code> клонът на главното хранилище може да се обновява само от тези хора. В сценарий като този, цялата работа се върши в екипни клонове, които интеграторите събират по-късно.</p> </div> <div class="paragraph"> <p>Нека проследим работата на Jessica, защото тя работи по две неща, в паралел с двама различни разработчици. Допускаме, че тя вече има клонирано своето хранилище и решава да започне работа първо по <code>featureA</code>. Тя създава нов клон и работи по него тук:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># 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(-)</code></pre> </div> </div> <div class="paragraph"> <p>В този момент, тя трябва да сподели работата си с John, така че изпраща къмитите от клона <code>featureA</code> към сървъра. Тя обаче няма push достъп до <code>master</code> клона, само интеграторите имат такъв — ето защо трябва да публикува в друг клон, за да работи съвместно с John:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push -u origin featureA ... To jessica@githost:simplegit.git * [new branch] featureA -> featureA</code></pre> </div> </div> <div class="paragraph"> <p>Jessica изпраща на John съобщение за това, че е изпратила своята работа в клон наречен <code>feature A</code> и сега той може да го погледне. Докато чака за мнението на John, Jessica решава да започне работа по <code>feature B</code> с Josie. За да започне, тя стартира нов feature клон, базирайки го на <code>master</code> клона от сървъра:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># Jessica's Machine $ git fetch origin $ git checkout -b featureB origin/master Switched to a new branch 'featureB'</code></pre> </div> </div> <div class="paragraph"> <p>Сега тя прави няколко къмита в клона <code>featureB</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ vim lib/simplegit.rb $ git commit -am 'Make ls-tree function recursive' [featureB e5b0fdc] Make 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(-)</code></pre> </div> </div> <div class="paragraph"> <p>Хранилището на Jessica сега изглежда така:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/managed-team-1.png" alt="Първоначалните къмити на Jessica"> </div> <div class="title">Фигура 65. Първоначалните къмити на Jessica</div> </div> <div class="paragraph"> <p>Готова е да изпрати своята работа, но в този момент получава имейл от Josie, в който се съобщава, че на сървъра вече има създаден клон с някаква предварително свършена работа по “featureB”. Този клон се казва <code>featureBee</code>. Jessica сега трябва първо да слее тези промени със своите собствени преди да може да изпрати към сървъра. Тя изтегля промените на Josie с <code>git fetch</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git fetch origin ... From jessica@githost:simplegit * [new branch] featureBee -> origin/featureBee</code></pre> </div> </div> <div class="paragraph"> <p>Приемайки, че локално тя е все още в клона <code>featureB</code>, тя може да слее работата на Josie с <code>git merge</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git merge origin/featureBee Auto-merging lib/simplegit.rb Merge made by the 'recursive' strategy. lib/simplegit.rb | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>В този момент, тя иска да изпрати цялата си слята работа от “featureB” обратно към сървъра, но не иска да го направи просто изпращайки своя собствен <code>featureB</code> клон. Вместо това, понеже Josie вече е направил upstream <code>featureBee</code> клон, Jessica ще иска да изпраща промените си именно към <em>този</em> клон, затова тя прави така:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push -u origin featureB:featureBee ... To jessica@githost:simplegit.git fba9af8..cd685d1 featureB -> featureBee</code></pre> </div> </div> <div class="paragraph"> <p>Това се нарича <em>refspec</em>, указване на референция. Вижте <a href="/book/bg/v2/ch00/_refspec">Refspec спецификации</a> за повече детайли относно Git refspecs и различните възможности, които ви се предоставят с тях. Отбележете също <code>-u</code> флага; това е съкращение за <code>--set-upstream</code>, който аргумент конфигурира клоновете за лесно дърпане и изпращане.</p> </div> <div class="paragraph"> <p>Внезапно Jessica получава имейл от John, който ѝ казва, че е публикувал някои промени по <code>featureA</code> клона, по който си сътрудничат и моли Jessica да ги погледне. Отново, Jessica изпълнява <code>git fetch</code> за да изтегли <em>цялото</em> ново съдържание от сървъра, включително последните промени на John:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git fetch origin ... From jessica@githost:simplegit 3300904..aad881d featureA -> origin/featureA</code></pre> </div> </div> <div class="paragraph"> <p>Jessica може да покаже историята на промените на John сравнявайки съдържанието на новоизвлечения <code>featureA</code> клон с локалното копие на същия такъв:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git log featureA..origin/featureA commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6 Author: John Smith <jsmith@example.com> Date: Fri May 29 19:57:33 2009 -0700 Increase log output to 30 from 25</code></pre> </div> </div> <div class="paragraph"> <p>Ако Jessica харесва това, което вижда, тя може да слее промените от John в локалния си <code>featureA</code> клон:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ 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(-)</code></pre> </div> </div> <div class="paragraph"> <p>Накрая, Jessica може да желае да направи няколко малки корекции към цялото това слято съдържание, така че е свободна да ги реализира, да ги къмитне в локалния <code>featureA</code> клон, и да публикува финалния резултат на сървъра:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git commit -am 'Add small tweak to merged content' [featureA 774b3ed] Add small tweak to merged content 1 files changed, 1 insertions(+), 1 deletions(-) $ git push ... To jessica@githost:simplegit.git 3300904..774b3ed featureA -> featureA</code></pre> </div> </div> <div class="paragraph"> <p>Сега историята на къмитите на Jessica ще изглежда по подобен начин:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/managed-team-2.png" alt="Историята на Jessica след къмитите във feature клона"> </div> <div class="title">Фигура 66. Историята на Jessica след къмитите във feature клона</div> </div> <div class="paragraph"> <p>В даден момент, Jessica, Josie и John информират интеграторите, че <code>featureA</code> и <code>featureBee</code> клоновете на сървъра са готови за интегриране. След като интеграторите слеят тези клонове в основния проект, едно изтегляне ще предостави новия merge къмит, променяйки историята така:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/managed-team-3.png" alt="Историята на Jessica след сливането на двата ѝ topic клона"> </div> <div class="title">Фигура 67. Историята на Jessica след сливането на двата ѝ topic клона</div> </div> <div class="paragraph"> <p>Много екипи преминават към Git поради възможностите за паралелна работа на множество тимове и сливане на различните работни нишки по-късно в процеса. Възможността малки подгрупи от един екип да работят съвместно чрез отдалечени клонове без да е необходимо да въвличат в това целия екип или да възпрепятстват работата на другите, е огромно преимущество с Git. Последователността на работния процес, който описахме, би могла да се илюстрира така:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/managed-team-flow.png" alt="Последователност на действията в managed-team работен процес"> </div> <div class="title">Фигура 68. Последователност на действията в managed-team работен процес</div> </div> <div id="_public_project" class="paragraph"> <p>==== Клониран публичен проект</p> </div> <div class="paragraph"> <p> Допринасянето към публични проекти е малко по-различно. Понеже нямате права директно да обновявате клоновете на един такъв проект, по някакъв начин трябва да изпратите работата си до хората, които го поддържат. Този първи пример описва как се сътрудничи чрез клониране на Git хостове, които поддържат easy forking. Много от публичните хостинг платформи (вкл. GitHub, BitBucket, repo.or.cz, и други), както и много от поддържащите дадени проекти, очакват именно такъв подход за външна помощ. Следващата секция се занимава с проекти, които предпочитат да приемат предложените пачове чрез имейл.</p> </div> <div class="paragraph"> <p>Първо, вероятно ще искате да клонирате главното хранилище, да създадете topic клон за пача или серията пачове, които планирате да предложите, и да работите в него. Последователността изглежда така:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone <url> $ cd project $ git checkout -b featureA ... work ... $ git commit ... work ... $ git commit</code></pre> </div> </div> </div> </div> <div class="paragraph"> <p>Може да искате да използвате <code>rebase -i</code> за да съберете работата си в единичен къмит, или пък да реорганизирате нещата в множество къмити, така че мениджърът на проекта по-лесно да я разгледа — вижте <a href="/book/bg/v2/ch00/_rewriting_history">Манипулация на историята</a> за повече информация за интерактивното пребазиране.</p> </div> <div class="exampleblock"> <div class="content"> <div class="paragraph"> <p>Когато работата ви по клона е завършена и сте готови да я предложите на поддържащите проекта, отидете обратно в неговата страница и използвайте бутона “Fork”, така че да си направите свое собствено копие от проекта в сайта, с права за писане в него. След това трябва да добавите URL-а на копието като нова отдалечена референция за локалното ви хранилище, за този пример - нека да я наречем <code>myfork</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git remote add myfork <url></code></pre> </div> </div> <div class="paragraph"> <p>След това трябва да публикувате локалната си работа в това отдалечено хранилище. Най-лесно е да публикувате topic клона, по който работите, вместо първо са го сливате в <code>master</code> клона и да публикувате него. Причината за това е, че ако работата не бъде приета или е cherry-picked, няма да има нужда да превъртате обратно вашия <code>master</code> клон (<code>cherry-pick</code> операцията на Git се разглежда в повече подробности в <a href="/book/bg/v2/ch00/_rebase_cherry_pick">Rebasing и Cherry-Picking работни процеси</a>). Ако поддържащите проекта <code>слеят</code>, <code>пребазират</code>, или <code>cherry-pick</code>-нат вашата работа, в крайна сметка ще я получите обратно чрез издърпване от тяхното хранилище.</p> </div> <div class="paragraph"> <p>Във всеки случай, можете да публикувате работата си чрез:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push -u myfork featureA</code></pre> </div> </div> <div class="paragraph"> <p> След като работата ви е била публикувана във вашето клонирано онлайн хранилище, ще трябва да уведомите поддържащите оригиналния проект, че имате промени, които бихте искали да интегрират. Това често се нарича <em>pull request</em> и обикновено такава заявка се генерира или директно през уеб сайта — GitHub има собствен “Pull Request” механизъм, който ще видим в <a href="/book/bg/v2/ch00/ch06-github">GitHub</a> — или пък с командата <code>git request-pull</code> чийто изход трябва да изпратите по имейл на мениджъра на проекта ръчно.</p> </div> <div class="paragraph"> <p>Командата <code>git request-pull</code> взема за параметри базовия клон, в който искате промените ви да бъдат интегрирани и адреса на Git хранилището, от което тези промени да бъдат изтеглени, след което изготвя списък с всички промени, които искате да бъдат изтеглени. Например, ако Jessica иска да изпрати на John pull request и е направила два къмита в topic клона, който току що е публикувала, тя може да изпълни следното:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git request-pull origin/master myfork The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40: Jessica Smith (1): Create new function are available in the git repository at: git://githost/simplegit.git featureA Jessica Smith (2): Add limit to log function Increase log output to 30 from 25 lib/simplegit.rb | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>Този изход може да се изпрати към поддържащия проекта — той ще покаже откъде е разклонена работата, обобщава къмитите и указва откъде може да се изтегли новата работа.</p> </div> <div class="paragraph"> <p>В проект, който не поддържате, обикновено е по-лесно да имате клон като <code>master</code>, който винаги следи <code>origin/master ` и да вършите работата си в topic клонове, които лесно можете да премахнете, в случай че бъдат отхвърлени. Изолирането на работата в topic клонове също така прави по-лесно пребазирането на вашата работа, ако "върха" на главното хранилище се премести междувременно и къмитите ви вече не се прилагат чисто. Например, ако искате да изпратите втора промяна в проекта, не продължавайте да работите в topic клона, който вече сте изпратили — започнете от `master</code> клона на главното хранилище:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b featureB origin/master ... work ... $ git commit $ git push myfork featureB $ git request-pull origin/master myfork ... email generated request pull to maintainer ... $ git fetch origin</code></pre> </div> </div> <div class="paragraph"> <p>Сега, всяка от промените ви се съдържа в силоз — подобно на опашка от пачове — които можете да пренапишете, пребазирате и променяте без различните теми да се преплитат или да зависят една от друга:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/public-small-1.png" alt="Първоначална история на къмитите с `featureB`"> </div> <div class="title">Фигура 69. Първоначална история на къмитите с <code>featureB</code> </div> </div> <div class="paragraph"> <p>Да кажем, че мениджърът на проекта е интегрирал множество други пачове и е опитал вашия първи клон, който обаче вече не се слива чисто. В този случай, можете да пробвате да пребазирате този клон върху <code>origin/master</code>, да оправите конфликтите и да изпратите повторно промените си:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout featureA $ git rebase origin/master $ git push -f myfork featureA</code></pre> </div> </div> <div class="paragraph"> <p>Това ще промени историята ви така:</p> </div> <div id="psp_b" class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/public-small-2.png" alt="Историята след работа по `featureA`"> </div> <div class="title">Фигура 70. Историята след работа по <code>featureA</code> </div> </div> <div class="paragraph"> <p>Понеже пребазирахте клона, трябва да подадете параметъра <code>-f</code> към push командата за да можете да замените <code>featureA</code> клона на сървъра с къмит, който не е негов наследник. Като алтернатива, можете да публикувате тази нова работа към различен клон в сървъра (например <code>featureAv2</code>).</p> </div> <div class="paragraph"> <p>Нека погледнем още един възможен сценарий: поддържащият проекта е погледнал работата във втория ви клон и харесва идеята ви, но би желал да промените малко имплементацията. Вие също ще се възползвате от тази възможност за да преместите работата си така, че да е базирана на текущия <code>master</code> клон на проекта. Стартирате нов клон базиран на текущия <code>origin/master</code>, премествате <code>featureB</code> промените в него, решавате евентуалните конфликти, променяте имплементацията и го публикувате като нов клон:</p> </div> <div class="paragraph"> <p></p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b featureBv2 origin/master $ git merge --squash featureB ... change implementation ... $ git commit $ git push myfork featureBv2</code></pre> </div> </div> <div class="paragraph"> <p>Опцията <code>--squash</code> взема цялата работа от слетия клон и я събира в едно множество промени, в резултат на което статусът на хранилището ще изглежда така сякаш е станало реално сливане, без в действителност да се прави merge къмит. Това означава, че бъдещият ви къмит ще има само един родител и ви позволява да въведете всички промени от друг клон и да направите още такива преди да запишете новия къмит. Също така, опцията <code>--no-commit</code> може да е полезна за отлагане на merge къмита в случай на нормален процес по сливане.</p> </div> <div class="paragraph"> <p>В този момент, можете да уведомите поддържащия проекта, че сте направили поисканите промени и те могат да се намерят в клона <code>featureBv2</code>.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/bg/v2/images/public-small-3.png" alt="Историята след работата по `featureBv2`"> </div> <div class="title">Фигура 71. Историята след работата по <code>featureBv2</code>.</div> </div> <div id="_project_over_email" class="paragraph"> <p>==== Публичен проект с комуникация по имейл</p> </div> <div class="paragraph"> <p> Много проекти имат установени процедури за приемане на пачове — ще трябва да проверите специфичните изисквания според вашия случай. Понеже все още съществуват множество по-стари, големи по мащаб проекти, които приемат пачовете през мейлинг лист за разработчици, ще дадем и един пример за такъв случай.</p> </div> <div class="paragraph"> <p>Работният процес е подобен на предишния — вие създавате topic клонове за всяка серия от пачове, по която работите. Разликата е в това как ги изпращате към проекта. Вместо да клонирате проекта и да публикувате във вашата версия, в която имате права за писане, вие генерирате имейл версии на всяка серия къмити и ги изпращате към мейлинг лист:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b topicA ... work ... $ git commit ... work ... $ git commit</code></pre> </div> </div> <div class="paragraph"> <p> Сега имате два къмита, които искате да пратите. Използвате <code>git format-patch</code> командата, за да генерирате mbox-форматирани файлове, които можете да пратите към списъка — тя превръща всеки къмит в имейл съобщение със subject отговарящ на първия ред от къмит съобщението и останалата част от съобщението плюс пача - като тяло на имейла. Хубавото на това е, че прилагането на пач от имейл съобщение генерирано с тази команда запазва коректно цялата информация за къмита.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git format-patch -M origin/master 0001-add-limit-to-log-function.patch 0002-increase-log-output-to-30-from-25.patch</code></pre> </div> </div> <div class="paragraph"> <p>Командата <code>format-patch</code> отпечатва имената на пач-файловете, които създава. Параметърът <code>-M</code> казва на Git да търси за преименувания. Файловете изглеждат така:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ 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') -- 2.1.0</code></pre> </div> </div> <div class="paragraph"> <p>Можете също да редактирате пач файловете за да добавите допълнителна информация за мейлинг листата, която не желаете да се показва в къмит съобщението. Ако добавите текст между реда <code>---</code> и началото на пача (реда <code>diff --git</code>), то разработчиците могат да я четат, но това съдържание ще бъде игнорирано от процеса по пачването.</p> </div> <div class="paragraph"> <p>За да изпратите това към листата, можете или да копирате файла в имейл програмата си или да използвате програма за изпращане на поща от команден ред. Копирането на текст често предизвиква проблеми с форматирането, особено с “по-умните” клиенти, които не запазват новите редове и празните символи коректно. За щастие, Git предоставя инструмент за изпращане на правилно форматирани пачове през IMAP, което може да е по-лесно за вас. Ще покажем как да изпращаме пач през Gmail, тъй като е много популярна услуга, но можете да намерите детайлни инструкции за използването на много други имейл клиенти в края на гореспоменатия файл <code>Documentation/SubmittingPatches</code> в сорс кода на Git.</p> </div> <div class="paragraph"> <p> Първо, трябва да подготвите imap секцията във вашия <code>~/.gitconfig</code> файл. Можете да настроите всяка стойност отделно чрез серия от <code>git config</code> команди или пък да ги въведете ръчно, но независимо от подхода, конфигурационният файл ще изглежда по подобен начин:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-ini" data-lang="ini">[imap] folder = "[Gmail]/Drafts" host = imaps://imap.gmail.com user = user@gmail.com pass = YX]8g76G_2^sFbd port = 993 sslverify = false</code></pre> </div> </div> <div class="paragraph"> <p>Ако IMAP сървърът ви не използва SSL, то последните два реда вероятно няма да са нужни и стойността за хоста ще започва с <code>imap://</code> вместо с <code>imaps://</code>. Когато това е готово, можете да използвате командата <code>git imap-send</code> за да поставите пачовете в Drafts папката на указания IMAP сървър:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ 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</code></pre> </div> </div> <div class="paragraph"> <p>В този момент, би трябвало да можете да отворите Drafts папката, да смените To полето към адреса на мейлинг-листата, към която изпращате пача, вероятно да добавите CC поле за поддържащия проекта или човекът, който отговаря за тази секция и да изпратите пощата.</p> </div> <div class="paragraph"> <p>Можете да изпращате и през SMTP сървър. Както и преди, ще трябва да отразите промените в <code>~/.gitconfig</code>, в секцията му sendemail, ръчно или с <code>git config</code> команди:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-ini" data-lang="ini">[sendemail] smtpencryption = tls smtpserver = smtp.gmail.com smtpuser = user@gmail.com smtpserverport = 587</code></pre> </div> </div> <div class="paragraph"> <p>След това, използвайте командата <code>git send-email</code> за да изпратите пачовете си:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git send-email *.patch 0001-add-limit-to-log-function.patch 0002-increase-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</code></pre> </div> </div> <div class="paragraph"> <p>След това Git показва множество лог информация, която изглежда по подобен начин за всеки от пачовете:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-text" data-lang="text">(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] Add 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</code></pre> </div> </div> </div> </div> <div class="paragraph"> <p>За повече информация относно конфигурирането на вашата система за работа с имейли, съвети и трикове, както и sandbox за изпращане на примерни пачове по електронна поща, посетете <a href="https://git-send-email.io" target="_blank" rel="noopener">git-send-email.io</a>.</p> </div> </div> <div class="sect3"> <h3 id="_обобщение_3">Обобщение</h3> <div class="paragraph"> <p>В тази секция разгледахме различни работни процеси и разликите в работата в малък екип с closed-source проекти и тази при сътрудничество в голям публиен проект. Сега знаете, че трябва да проверявате за white-space грешки преди къмитването и да пишете перфектни къмит съобщения. Научихме как да форматираме пачове и да ги разпращаме по пощата до мейлинг-листа на разработчиците. В контекста на различните работни процеси обърнахме внимание и на особеностите при сливане. Сега сме достатъчно подготвени да сътрудничим в произволен проект.</p> </div> <div class="paragraph"> <p>Следва да погледнем от обратната страна на монетата: поддържането на Git проект. Ще научите как да изпълнявате ролите на benevolent dictator или integration manager.</p> </div> </div> <div id="nav"><a href="/book/bg/v2/Клонове-в-Git-Стратегии-за-работа-с-клонове-код">prev</a> | <a href="/book/bg/v2/Клонове-в-Git-Управление-на-проект">next</a></div> </div> </div> </div> </div> <footer> <div class="site-source"> <a href="/site">About this site</a><br> Patches, suggestions, and comments are welcome. </div> <div class="sfc-member"> Git is a member of <a href="/sfc">Software Freedom Conservancy</a> </div> </footer> <a href="#top" class="no-js scrollToTop" id="scrollToTop" data-label="Scroll to top"> <img src="/images/icons/chevron-up@2x.png" width="20" height="20" alt="scroll-to-top"/> </a> <script src="/js/jquery-1.7.1.min.js"></script> <script src="/js/jquery-ui-1.8.18.custom.min.js"></script> <script src="/js/jquery.defaultvalue.js"></script> <script src="/js/session.min.js"></script> <script src="/js/application.min.js"></script> </div> </body> </html>