CINXE.COM
Git - Git як клієнт
<!DOCTYPE html> <html lang="uk"> <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 - 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-and-Other-Systems-Git-as-a-Client">English</a>. </p> <p> Full translation available in <table> <tr><td><a href="/book/az/v2/Git-v%c9%99-Dig%c9%99r-Sisteml%c9%99r-Git-M%c3%bc%c5%9ft%c9%99ri-kimi">azərbaycan dili</a>,</td></tr> <tr><td><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>,</td></tr> <tr><td><a href="/book/de/v2/Git-und-andere-VCS-Systeme-Git-als-Client">Deutsch</a>,</td></tr> <tr><td><a href="/book/es/v2/Git-y-Otros-Sistemas-Git-como-Cliente">Español</a>,</td></tr> <tr><td><a href="/book/fr/v2/Git-et-les-autres-syst%c3%a8mes-Git-comme-client">Français</a>,</td></tr> <tr><td><a href="/book/gr">Ελληνικά</a>,</td></tr> <tr><td><a href="/book/ja/v2/Git%e3%81%a8%e3%81%9d%e3%81%ae%e4%bb%96%e3%81%ae%e3%82%b7%e3%82%b9%e3%83%86%e3%83%a0%e3%81%ae%e9%80%a3%e6%90%ba-Git-%e3%82%92%e3%82%af%e3%83%a9%e3%82%a4%e3%82%a2%e3%83%b3%e3%83%88%e3%81%a8%e3%81%97%e3%81%a6%e4%bd%bf%e7%94%a8%e3%81%99%e3%82%8b">日本語</a>,</td></tr> <tr><td><a href="/book/ko/v2/Git%ea%b3%bc-%ec%97%ac%ed%83%80-%eb%b2%84%ec%a0%84-%ea%b4%80%eb%a6%ac-%ec%8b%9c%ec%8a%a4%ed%85%9c-Git:-%eb%b2%94%ec%9a%a9-Client">한국어</a>,</td></tr> <tr><td><a href="/book/nl/v2/Git-en-andere-systemen-Git-als-een-client">Nederlands</a>,</td></tr> <tr><td><a href="/book/ru/v2/Git-%d0%b8-%d0%b4%d1%80%d1%83%d0%b3%d0%b8%d0%b5-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d1%8b-%d0%ba%d0%be%d0%bd%d1%82%d1%80%d0%be%d0%bb%d1%8f-%d0%b2%d0%b5%d1%80%d1%81%d0%b8%d0%b9-Git-%d0%ba%d0%b0%d0%ba-%d0%ba%d0%bb%d0%b8%d0%b5%d0%bd%d1%82">Русский</a>,</td></tr> <tr><td><a href="/book/sl/v2/Git-in-ostali-sistemi-Git-kot-odjemalec">Slovenščina</a>,</td></tr> <tr><td><a href="/book/tl/v2/Ang-Git-at-iba-pang-mga-Sistema-Git-bilang-isang-Kliyente">Tagalog</a>,</td></tr> <tr><td><a href="/book/uk/v2/Git-and-Other-Systems-Git-%d1%8f%d0%ba-%d0%ba%d0%bb%d1%96%d1%94%d0%bd%d1%82">Українська</a></td></tr> <tr><td><a href="/book/zh/v2/Git-%e4%b8%8e%e5%85%b6%e4%bb%96%e7%b3%bb%e7%bb%9f-%e4%bd%9c%e4%b8%ba%e5%ae%a2%e6%88%b7%e7%ab%af%e7%9a%84-Git">简体中文</a>,</td></tr> </table> </p> <p> Partial translations available in <table> <tr><td><a href="/book/cs/v2/Git-a-ostatn%c3%ad-syst%c3%a9my-Git-as-a-Client">Čeština</a>,</td></tr> <tr><td><a href="/book/mk/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%d0%ba%d0%be-%d0%9a%d0%bb%d0%b8%d0%b5%d0%bd%d1%82">Македонски</a>,</td></tr> <tr><td><a href="/book/pl/v2/Git-i-inne-systemy-Git-jako-klient">Polski</a>,</td></tr> <tr><td><a href="/book/sr/v2/%d0%93%d0%b8%d1%82-%d0%b8-%d0%be%d1%81%d1%82%d0%b0%d0%bb%d0%b8-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b8-%d0%93%d0%b8%d1%82-%d0%ba%d0%b0%d0%be-%d0%ba%d0%bb%d0%b8%d1%98%d0%b5%d0%bd%d1%82">Српски</a>,</td></tr> <tr><td><a href="/book/uz/v2/Git-and-Other-Systems-Git-as-a-Client">Ўзбекча</a>,</td></tr> <tr><td><a href="/book/zh-tw/v2/Git-and-Other-Systems-Git-as-a-Client">繁體中文</a>,</td></tr> </table> </p> <p> Translations started for <table> <tr><td><a href="/book/be/v2/Git-and-Other-Systems-Git-as-a-Client">Беларуская</a>,</td></tr> <tr><td><a href="/book/fa/v2/Git-and-Other-Systems-Git-as-a-Client" dir="rtl">فارسی</a>,</td></tr> <tr><td><a href="/book/id/v2/Git-and-Other-Systems-Git-as-a-Client">Indonesian</a>,</td></tr> <tr><td><a href="/book/it/v2/Git-and-Other-Systems-Git-as-a-Client">Italiano</a>,</td></tr> <tr><td><a href="/book/ms/v2/Git-and-Other-Systems-Git-as-a-Client">Bahasa Melayu</a>,</td></tr> <tr><td><a href="/book/pt-br/v2/Git-and-Other-Systems-Git-as-a-Client">Português (Brasil)</a>,</td></tr> <tr><td><a href="/book/pt-pt/v2/O-Git-e-Outros-Sistemas-O-Git-como-Cliente">Português (Portugal)</a>,</td></tr> <tr><td><a href="/book/sv/v2/Git-and-Other-Systems-Git-as-a-Client">Svenska</a>,</td></tr> <tr><td><a href="/book/tr/v2/Git-ve-Di%c4%9fer-Sistemler-%c4%b0stemci-Olarak-Git">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-uk">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/uk/v2/%d0%92%d1%81%d1%82%d1%83%d0%bf-%d0%9f%d1%80%d0%be-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d1%83-%d0%ba%d0%be%d0%bd%d1%82%d1%80%d0%be%d0%bb%d1%8e-%d0%b2%d0%b5%d1%80%d1%81%d1%96%d0%b9">Вступ</a></h2> <ol> <li> 1.1 <a href="/book/uk/v2/%d0%92%d1%81%d1%82%d1%83%d0%bf-%d0%9f%d1%80%d0%be-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d1%83-%d0%ba%d0%be%d0%bd%d1%82%d1%80%d0%be%d0%bb%d1%8e-%d0%b2%d0%b5%d1%80%d1%81%d1%96%d0%b9">Про систему контролю версій</a> </li> <li> 1.2 <a href="/book/uk/v2/%d0%92%d1%81%d1%82%d1%83%d0%bf-%d0%9a%d0%be%d1%80%d0%be%d1%82%d0%ba%d0%b0-%d1%96%d1%81%d1%82%d0%be%d1%80%d1%96%d1%8f-Git">Коротка історія Git</a> </li> <li> 1.3 <a href="/book/uk/v2/%d0%92%d1%81%d1%82%d1%83%d0%bf-%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-Git">Основи Git</a> </li> <li> 1.4 <a href="/book/uk/v2/%d0%92%d1%81%d1%82%d1%83%d0%bf-Git,-%d0%b7%d0%b0%d0%b7%d0%b2%d0%b8%d1%87%d0%b0%d0%b9,-%d1%82%d1%96%d0%bb%d1%8c%d0%ba%d0%b8-%d0%b4%d0%be%d0%b4%d0%b0%d1%94-%d0%b4%d0%b0%d0%bd%d1%96">Git, зазвичай, тільки додає дані</a> </li> <li> 1.5 <a href="/book/uk/v2/%d0%92%d1%81%d1%82%d1%83%d0%bf-%d0%a2%d1%80%d0%b8-%d1%81%d1%82%d0%b0%d0%bd%d0%b8">Три стани</a> </li> <li> 1.6 <a href="/book/uk/v2/%d0%92%d1%81%d1%82%d1%83%d0%bf-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%bd%d0%b8%d0%b9-%d1%80%d1%8f%d0%b4%d0%be%d0%ba">Командний рядок</a> </li> <li> 1.7 <a href="/book/uk/v2/%d0%92%d1%81%d1%82%d1%83%d0%bf-%d0%86%d0%bd%d1%81%d1%82%d0%b0%d0%bb%d1%8f%d1%86%d1%96%d1%8f-Git">Інсталяція Git</a> </li> <li> 1.8 <a href="/book/uk/v2/%d0%92%d1%81%d1%82%d1%83%d0%bf-%d0%9f%d0%be%d1%87%d0%b0%d1%82%d0%ba%d0%be%d0%b2%d0%b5-%d0%bd%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git">Початкове налаштування Git</a> </li> <li> 1.9 <a href="/book/uk/v2/%d0%92%d1%81%d1%82%d1%83%d0%bf-%d0%9e%d1%82%d1%80%d0%b8%d0%bc%d0%b0%d0%bd%d0%bd%d1%8f-%d0%b4%d0%be%d0%bf%d0%be%d0%bc%d0%be%d0%b3%d0%b8">Отримання допомоги</a> </li> <li> 1.10 <a href="/book/uk/v2/%d0%92%d1%81%d1%82%d1%83%d0%bf-%d0%9f%d1%96%d0%b4%d1%81%d1%83%d0%bc%d0%be%d0%ba">Підсумок</a> </li> </ol> </li> <li class='chapter'> <h2>2. <a href="/book/uk/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-Git-%d0%a1%d1%82%d0%b2%d0%be%d1%80%d0%b5%d0%bd%d0%bd%d1%8f-Git-%d1%81%d1%85%d0%be%d0%b2%d0%b8%d1%89%d0%b0">Основи Git</a></h2> <ol> <li> 2.1 <a href="/book/uk/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-Git-%d0%a1%d1%82%d0%b2%d0%be%d1%80%d0%b5%d0%bd%d0%bd%d1%8f-Git-%d1%81%d1%85%d0%be%d0%b2%d0%b8%d1%89%d0%b0">Створення Git-сховища</a> </li> <li> 2.2 <a href="/book/uk/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-Git-%d0%97%d0%b0%d0%bf%d0%b8%d1%81-%d0%b7%d0%bc%d1%96%d0%bd-%d0%b4%d0%be-%d1%80%d0%b5%d0%bf%d0%be%d0%b7%d0%b8%d1%82%d0%be%d1%80%d1%96%d1%8f">Запис змін до репозиторія</a> </li> <li> 2.3 <a href="/book/uk/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-Git-%d0%9f%d0%b5%d1%80%d0%b5%d0%b3%d0%bb%d1%8f%d0%b4-%d1%96%d1%81%d1%82%d0%be%d1%80%d1%96%d1%97-%d0%ba%d0%be%d0%bc%d1%96%d1%82%d1%96%d0%b2">Перегляд історії комітів</a> </li> <li> 2.4 <a href="/book/uk/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-Git-%d0%a1%d0%ba%d0%b0%d1%81%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d1%80%d0%b5%d1%87%d0%b5%d0%b9">Скасування речей</a> </li> <li> 2.5 <a href="/book/uk/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-Git-%d0%92%d0%b7%d0%b0%d1%94%d0%bc%d0%be%d0%b4%d1%96%d1%8f-%d0%b7-%d0%b2%d1%96%d0%b4%d0%b4%d0%b0%d0%bb%d0%b5%d0%bd%d0%b8%d0%bc%d0%b8-%d1%81%d1%85%d0%be%d0%b2%d0%b8%d1%89%d0%b0%d0%bc%d0%b8">Взаємодія з віддаленими сховищами</a> </li> <li> 2.6 <a href="/book/uk/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-Git-%d0%a2%d0%b5%d2%91%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f">Теґування</a> </li> <li> 2.7 <a href="/book/uk/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-Git-%d0%9f%d1%81%d0%b5%d0%b2%d0%b4%d0%be%d0%bd%d1%96%d0%bc%d0%b8-Git">Псевдоніми Git</a> </li> <li> 2.8 <a href="/book/uk/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-Git-%d0%9f%d1%96%d0%b4%d1%81%d1%83%d0%bc%d0%be%d0%ba">Підсумок</a> </li> </ol> </li> <li class='chapter'> <h2>3. <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%93%d1%96%d0%bb%d0%ba%d0%b8-%d1%83-%d0%ba%d1%96%d0%bb%d1%8c%d0%ba%d0%be%d1%85-%d1%81%d0%bb%d0%be%d0%b2%d0%b0%d1%85">Галуження в git</a></h2> <ol> <li> 3.1 <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%93%d1%96%d0%bb%d0%ba%d0%b8-%d1%83-%d0%ba%d1%96%d0%bb%d1%8c%d0%ba%d0%be%d1%85-%d1%81%d0%bb%d0%be%d0%b2%d0%b0%d1%85">Гілки у кількох словах</a> </li> <li> 3.2 <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%9e%d1%81%d0%bd%d0%be%d0%b2%d0%b8-%d0%b3%d0%b0%d0%bb%d1%83%d0%b6%d0%b5%d0%bd%d0%bd%d1%8f-%d1%82%d0%b0-%d0%b7%d0%bb%d0%b8%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f">Основи галуження та зливання</a> </li> <li> 3.3 <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%a3%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d1%96%d0%bd%d0%bd%d1%8f-%d0%b3%d1%96%d0%bb%d0%ba%d0%b0%d0%bc%d0%b8">Управління гілками</a> </li> <li> 3.4 <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%9f%d1%80%d0%be%d1%86%d0%b5%d1%81%d0%b8-%d1%80%d0%be%d0%b1%d0%be%d1%82%d0%b8-%d0%b7-%d0%b3%d1%96%d0%bb%d0%ba%d0%b0%d0%bc%d0%b8">Процеси роботи з гілками</a> </li> <li> 3.5 <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> </li> <li> 3.6 <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%9f%d0%b5%d1%80%d0%b5%d0%b1%d0%b0%d0%b7%d0%be%d0%b2%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f">Перебазовування</a> </li> <li> 3.7 <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%9f%d1%96%d0%b4%d1%81%d1%83%d0%bc%d0%be%d0%ba">Підсумок</a> </li> </ol> </li> <li class='chapter'> <h2>4. <a href="/book/uk/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96-%d0%9f%d1%80%d0%be%d1%82%d0%be%d0%ba%d0%be%d0%bb%d0%b8">Git на сервері</a></h2> <ol> <li> 4.1 <a href="/book/uk/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96-%d0%9f%d1%80%d0%be%d1%82%d0%be%d0%ba%d0%be%d0%bb%d0%b8">Протоколи</a> </li> <li> 4.2 <a href="/book/uk/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96-%d0%9e%d1%82%d1%80%d0%b8%d0%bc%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96">Отримання Git на сервері</a> </li> <li> 4.3 <a href="/book/uk/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96-%d0%93%d0%b5%d0%bd%d0%b5%d1%80%d0%b0%d1%86%d1%96%d1%8f-%d0%b2%d0%b0%d1%88%d0%be%d0%b3%d0%be-%d0%bf%d1%83%d0%b1%d0%bb%d1%96%d1%87%d0%bd%d0%be%d0%b3%d0%be-%d0%ba%d0%bb%d1%8e%d1%87%d0%b0-SSH">Генерація вашого публічного ключа SSH</a> </li> <li> 4.4 <a href="/book/uk/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96-%d0%9d%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d0%a1%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%83">Налаштування Серверу</a> </li> <li> 4.5 <a href="/book/uk/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96-%d0%94%d0%b5%d0%bc%d0%be%d0%bd-Git">Демон Git</a> </li> <li> 4.6 <a href="/book/uk/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96-%d0%a0%d0%be%d0%b7%d1%83%d0%bc%d0%bd%d0%b8%d0%b9-HTTP">Розумний HTTP</a> </li> <li> 4.7 <a href="/book/uk/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96-GitWeb">GitWeb</a> </li> <li> 4.8 <a href="/book/uk/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96-GitLab">GitLab</a> </li> <li> 4.9 <a href="/book/uk/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96-%d0%92%d0%b0%d1%80%d1%96%d0%b0%d0%bd%d1%82%d0%b8-%d1%81%d1%82%d0%be%d1%80%d0%be%d0%bd%d0%bd%d1%8c%d0%be%d0%b3%d0%be-%d1%85%d0%be%d1%81%d1%82%d0%b8%d0%bd%d0%b3%d1%83">Варіанти стороннього хостингу</a> </li> <li> 4.10 <a href="/book/uk/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d1%96-%d0%9f%d1%96%d0%b4%d1%81%d1%83%d0%bc%d0%be%d0%ba">Підсумок</a> </li> </ol> </li> <li class='chapter'> <h2>5. <a href="/book/uk/v2/%d0%a0%d0%be%d0%b7%d0%bf%d0%be%d0%b4%d1%96%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9-Git-%d0%a0%d0%be%d0%b7%d0%bf%d0%be%d0%b4%d1%96%d0%bb%d0%b5%d0%bd%d1%96-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d1%81%d0%b8-%d1%80%d0%be%d0%b1%d0%be%d1%82%d0%b8">Розподілений Git</a></h2> <ol> <li> 5.1 <a href="/book/uk/v2/%d0%a0%d0%be%d0%b7%d0%bf%d0%be%d0%b4%d1%96%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9-Git-%d0%a0%d0%be%d0%b7%d0%bf%d0%be%d0%b4%d1%96%d0%bb%d0%b5%d0%bd%d1%96-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d1%81%d0%b8-%d1%80%d0%be%d0%b1%d0%be%d1%82%d0%b8">Розподілені процеси роботи</a> </li> <li> 5.2 <a href="/book/uk/v2/%d0%a0%d0%be%d0%b7%d0%bf%d0%be%d0%b4%d1%96%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9-Git-%d0%92%d0%bd%d0%b5%d1%81%d0%b5%d0%bd%d0%bd%d1%8f-%d0%b7%d0%bc%d1%96%d0%bd-%d0%b4%d0%be-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d1%83">Внесення змін до проекту</a> </li> <li> 5.3 <a href="/book/uk/v2/%d0%a0%d0%be%d0%b7%d0%bf%d0%be%d0%b4%d1%96%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9-Git-%d0%a1%d1%83%d0%bf%d1%80%d0%be%d0%b2%d0%be%d0%b4%d0%b6%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d1%83">Супроводжування проекту</a> </li> <li> 5.4 <a href="/book/uk/v2/%d0%a0%d0%be%d0%b7%d0%bf%d0%be%d0%b4%d1%96%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9-Git-%d0%9f%d1%96%d0%b4%d1%81%d1%83%d0%bc%d0%be%d0%ba">Підсумок</a> </li> </ol> </li> </ol> </div> <div class='column-middle'> <ol class='book-toc'> <li class='chapter'> <h2>6. <a href="/book/uk/v2/GitHub-%d0%a1%d1%82%d0%b2%d0%be%d1%80%d0%b5%d0%bd%d0%bd%d1%8f-%d1%82%d0%b0-%d0%bd%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d0%be%d0%b1%d0%bb%d1%96%d0%ba%d0%be%d0%b2%d0%be%d0%b3%d0%be-%d0%b7%d0%b0%d0%bf%d0%b8%d1%81%d1%83">GitHub</a></h2> <ol> <li> 6.1 <a href="/book/uk/v2/GitHub-%d0%a1%d1%82%d0%b2%d0%be%d1%80%d0%b5%d0%bd%d0%bd%d1%8f-%d1%82%d0%b0-%d0%bd%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d0%be%d0%b1%d0%bb%d1%96%d0%ba%d0%be%d0%b2%d0%be%d0%b3%d0%be-%d0%b7%d0%b0%d0%bf%d0%b8%d1%81%d1%83">Створення та налаштування облікового запису</a> </li> <li> 6.2 <a href="/book/uk/v2/GitHub-%d0%af%d0%ba-%d0%b7%d1%80%d0%be%d0%b1%d0%b8%d1%82%d0%b8-%d0%b2%d0%bd%d0%b5%d1%81%d0%be%d0%ba-%d0%b4%d0%be-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d1%83">Як зробити внесок до проекту</a> </li> <li> 6.3 <a href="/book/uk/v2/GitHub-%d0%a1%d1%83%d0%bf%d1%80%d0%be%d0%b2%d0%be%d0%b4%d0%b6%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d0%bf%d1%80%d0%be%d1%94%d0%ba%d1%82%d1%83">Супроводжування проєкту</a> </li> <li> 6.4 <a href="/book/uk/v2/GitHub-%d0%9a%d0%b5%d1%80%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d0%be%d1%80%d0%b3%d0%b0%d0%bd%d1%96%d0%b7%d0%b0%d1%86%d1%96%d1%94%d1%8e">Керування організацією</a> </li> <li> 6.5 <a href="/book/uk/v2/GitHub-%d0%a1%d0%ba%d1%80%d0%b8%d0%bf%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-GitHub">Скриптування GitHub</a> </li> <li> 6.6 <a href="/book/uk/v2/GitHub-%d0%9f%d1%96%d0%b4%d1%81%d1%83%d0%bc%d0%be%d0%ba">Підсумок</a> </li> </ol> </li> <li class='chapter'> <h2>7. <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%92%d0%b8%d0%b1%d1%96%d1%80-%d1%80%d0%b5%d0%b2%d1%96%d0%b7%d1%96%d0%b9">Інструменти Git</a></h2> <ol> <li> 7.1 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%92%d0%b8%d0%b1%d1%96%d1%80-%d1%80%d0%b5%d0%b2%d1%96%d0%b7%d1%96%d0%b9">Вибір ревізій</a> </li> <li> 7.2 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%86%d0%bd%d1%82%d0%b5%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%b2%d0%bd%d0%b5-%d1%96%d0%bd%d0%b4%d0%b5%d0%ba%d1%81%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f">Інтерактивне індексування</a> </li> <li> 7.3 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%a5%d0%be%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d1%82%d0%b0-%d1%87%d0%b8%d1%89%d0%b5%d0%bd%d0%bd%d1%8f">Ховання та чищення</a> </li> <li> 7.4 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%9f%d1%96%d0%b4%d0%bf%d0%b8%d1%81%d0%b0%d0%bd%d0%bd%d1%8f-%d0%bf%d1%80%d0%b0%d1%86%d1%96">Підписання праці</a> </li> <li> 7.5 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%9f%d0%be%d1%88%d1%83%d0%ba">Пошук</a> </li> <li> 7.6 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%9f%d0%b5%d1%80%d0%b5%d0%bf%d0%b8%d1%81%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d1%96%d1%81%d1%82%d0%be%d1%80%d1%96%d1%97">Переписування історії</a> </li> <li> 7.7 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%a3%d1%81%d0%b2%d1%96%d0%b4%d0%be%d0%bc%d0%bb%d0%b5%d0%bd%d0%bd%d1%8f-%d1%81%d0%ba%d0%b8%d0%b4%d0%b0%d0%bd%d0%bd%d1%8f-reset">Усвідомлення скидання (reset)</a> </li> <li> 7.8 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%a1%d0%ba%d0%bb%d0%b0%d0%b4%d0%bd%d0%b5-%d0%b7%d0%bb%d0%b8%d1%82%d1%82%d1%8f">Складне злиття</a> </li> <li> 7.9 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-Rerere">Rerere</a> </li> <li> 7.10 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%97%d0%bd%d0%b5%d0%b2%d0%b0%d0%b4%d0%b6%d0%b5%d0%bd%d0%bd%d1%8f-%d0%b7-Git">Зневадження з Git</a> </li> <li> 7.11 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%9f%d1%96%d0%b4%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d1%96">Підмодулі</a> </li> <li> 7.12 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%9f%d0%b0%d0%ba%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f">Пакування</a> </li> <li> 7.13 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%97%d0%b0%d0%bc%d1%96%d0%bd%d0%b0">Заміна</a> </li> <li> 7.14 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%97%d0%b1%d0%b5%d1%80%d0%b5%d0%b6%d0%b5%d0%bd%d0%bd%d1%8f-%d0%bf%d0%be%d1%81%d0%b2%d1%96%d0%b4%d1%87%d0%b5%d0%bd%d0%bd%d1%8f-credential">Збереження посвідчення (credential)</a> </li> <li> 7.15 <a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%9f%d1%96%d0%b4%d1%81%d1%83%d0%bc%d0%be%d0%ba">Підсумок</a> </li> </ol> </li> <li class='chapter'> <h2>8. <a href="/book/uk/v2/%d0%9d%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d0%9a%d0%be%d0%bd%d1%84%d1%96%d0%b3%d1%83%d1%80%d0%b0%d1%86%d1%96%d1%8f-Git">Налаштування Git</a></h2> <ol> <li> 8.1 <a href="/book/uk/v2/%d0%9d%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d0%9a%d0%be%d0%bd%d1%84%d1%96%d0%b3%d1%83%d1%80%d0%b0%d1%86%d1%96%d1%8f-Git">Конфігурація Git</a> </li> <li> 8.2 <a href="/book/uk/v2/%d0%9d%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d0%90%d1%82%d1%80%d0%b8%d0%b1%d1%83%d1%82%d0%b8-Git">Атрибути Git</a> </li> <li> 8.3 <a href="/book/uk/v2/%d0%9d%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d0%93%d0%b0%d0%ba%d0%b8-hooks-Git">Гаки (hooks) Git</a> </li> <li> 8.4 <a href="/book/uk/v2/%d0%9d%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d0%9f%d1%80%d0%b8%d0%ba%d0%bb%d0%b0%d0%b4-%d0%bf%d0%be%d0%bb%d1%96%d1%82%d0%b8%d0%ba%d0%b8-%d0%ba%d0%be%d1%80%d0%b8%d1%81%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d0%b2%d0%b8%d0%ba%d0%be%d0%bd%d1%83%d0%b2%d0%b0%d0%bd%d0%be%d1%97-Git-%d0%be%d0%bc">Приклад політики користування виконуваної Git-ом</a> </li> <li> 8.5 <a href="/book/uk/v2/%d0%9d%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d0%9f%d1%96%d0%b4%d1%81%d1%83%d0%bc%d0%be%d0%ba">Підсумок</a> </li> </ol> </li> <li class='chapter'> <h2>9. <a href="/book/uk/v2/Git-and-Other-Systems-Git-%d1%8f%d0%ba-%d0%ba%d0%bb%d1%96%d1%94%d0%bd%d1%82">Git and Other Systems</a></h2> <ol> <li> 9.1 <a href="/book/uk/v2/Git-and-Other-Systems-Git-%d1%8f%d0%ba-%d0%ba%d0%bb%d1%96%d1%94%d0%bd%d1%82" class="active">Git як клієнт</a> </li> <li> 9.2 <a href="/book/uk/v2/Git-and-Other-Systems-%d0%9c%d1%96%d0%b3%d1%80%d0%b0%d1%86%d1%96%d1%8f-%d0%bd%d0%b0-Git">Міграція на Git</a> </li> <li> 9.3 <a href="/book/uk/v2/Git-and-Other-Systems-%d0%9f%d1%96%d0%b4%d1%81%d1%83%d0%bc%d0%be%d0%ba">Підсумок</a> </li> </ol> </li> <li class='chapter'> <h2>10. <a href="/book/uk/v2/Git-%d0%b7%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%b8%d0%bd%d0%b8-%d0%9a%d1%83%d1%85%d0%be%d0%bd%d0%bd%d1%96-%d1%82%d0%b0-%d0%bf%d0%b0%d1%80%d0%b0%d0%b4%d0%bd%d1%96-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8">Git зсередини</a></h2> <ol> <li> 10.1 <a href="/book/uk/v2/Git-%d0%b7%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%b8%d0%bd%d0%b8-%d0%9a%d1%83%d1%85%d0%be%d0%bd%d0%bd%d1%96-%d1%82%d0%b0-%d0%bf%d0%b0%d1%80%d0%b0%d0%b4%d0%bd%d1%96-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8">Кухонні та парадні команди</a> </li> <li> 10.2 <a href="/book/uk/v2/Git-%d0%b7%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%b8%d0%bd%d0%b8-%d0%9e%d0%b1%e2%80%99%d1%94%d0%ba%d1%82%d0%b8-Git">Об’єкти Git</a> </li> <li> 10.3 <a href="/book/uk/v2/Git-%d0%b7%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%b8%d0%bd%d0%b8-%d0%9f%d0%be%d1%81%d0%b8%d0%bb%d0%b0%d0%bd%d0%bd%d1%8f-Git">Посилання Git</a> </li> <li> 10.4 <a href="/book/uk/v2/Git-%d0%b7%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%b8%d0%bd%d0%b8-%d0%a4%d0%b0%d0%b9%d0%bb%d0%b8-%d0%bf%d0%b0%d0%ba%d1%83%d0%bd%d0%ba%d0%b8">Файли пакунки</a> </li> <li> 10.5 <a href="/book/uk/v2/Git-%d0%b7%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%b8%d0%bd%d0%b8-%d0%a1%d0%bf%d0%b5%d1%86%d0%b8%d1%84%d1%96%d0%ba%d0%b0%d1%86%d1%96%d1%8f-%d0%bf%d0%be%d1%81%d0%b8%d0%bb%d0%b0%d0%bd%d1%8c-refspec">Специфікація посилань (refspec)</a> </li> <li> 10.6 <a href="/book/uk/v2/Git-%d0%b7%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%b8%d0%bd%d0%b8-%d0%9f%d1%80%d0%be%d1%82%d0%be%d0%ba%d0%be%d0%bb%d0%b8-%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d1%87%d1%96">Протоколи передачі</a> </li> <li> 10.7 <a href="/book/uk/v2/Git-%d0%b7%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%b8%d0%bd%d0%b8-%d0%a1%d1%83%d0%bf%d1%80%d0%be%d0%b2%d0%be%d0%b4%d0%b6%d0%b5%d0%bd%d0%bd%d1%8f-%d1%82%d0%b0-%d0%b2%d1%96%d0%b4%d0%bd%d0%be%d0%b2%d0%bb%d0%b5%d0%bd%d0%bd%d1%8f-%d0%b4%d0%b0%d0%bd%d0%b8%d1%85">Супроводження та відновлення даних</a> </li> <li> 10.8 <a href="/book/uk/v2/Git-%d0%b7%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%b8%d0%bd%d0%b8-%d0%97%d0%bc%d1%96%d0%bd%d0%bd%d1%96-%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%be%d0%b2%d0%b8%d1%89%d0%b0">Змінні середовища</a> </li> <li> 10.9 <a href="/book/uk/v2/Git-%d0%b7%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%b8%d0%bd%d0%b8-%d0%9f%d1%96%d0%b4%d1%81%d1%83%d0%bc%d0%be%d0%ba">Підсумок</a> </li> </ol> </li> </ol> </div> <div class='column-right'> <ol class='book-toc'> <li class='chapter'> <h2>A1. <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-A:-Git-%d0%b2-%d1%96%d0%bd%d1%88%d0%b8%d1%85-%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%be%d0%b2%d0%b8%d1%89%d0%b0%d1%85-%d0%93%d1%80%d0%b0%d1%84%d1%96%d1%87%d0%bd%d1%96-%d1%96%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d0%b8">Додаток A: Git в інших середовищах</a></h2> <ol> <li> A1.1 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-A:-Git-%d0%b2-%d1%96%d0%bd%d1%88%d0%b8%d1%85-%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%be%d0%b2%d0%b8%d1%89%d0%b0%d1%85-%d0%93%d1%80%d0%b0%d1%84%d1%96%d1%87%d0%bd%d1%96-%d1%96%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d0%b8">Графічні інтерфейси</a> </li> <li> A1.2 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-A:-Git-%d0%b2-%d1%96%d0%bd%d1%88%d0%b8%d1%85-%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%be%d0%b2%d0%b8%d1%89%d0%b0%d1%85-Git-%d1%83-Visual-Studio">Git у Visual Studio</a> </li> <li> A1.3 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-A:-Git-%d0%b2-%d1%96%d0%bd%d1%88%d0%b8%d1%85-%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%be%d0%b2%d0%b8%d1%89%d0%b0%d1%85-Git-%d0%b2-Eclipse">Git в Eclipse</a> </li> <li> A1.4 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-A:-Git-%d0%b2-%d1%96%d0%bd%d1%88%d0%b8%d1%85-%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%be%d0%b2%d0%b8%d1%89%d0%b0%d1%85-Git-%d1%83-Bash">Git у Bash</a> </li> <li> A1.5 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-A:-Git-%d0%b2-%d1%96%d0%bd%d1%88%d0%b8%d1%85-%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%be%d0%b2%d0%b8%d1%89%d0%b0%d1%85-Git-%d1%83-Zsh">Git у Zsh</a> </li> <li> A1.6 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-A:-Git-%d0%b2-%d1%96%d0%bd%d1%88%d0%b8%d1%85-%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%be%d0%b2%d0%b8%d1%89%d0%b0%d1%85-Git-%d1%83-Powershell">Git у Powershell</a> </li> <li> A1.7 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-A:-Git-%d0%b2-%d1%96%d0%bd%d1%88%d0%b8%d1%85-%d1%81%d0%b5%d1%80%d0%b5%d0%b4%d0%be%d0%b2%d0%b8%d1%89%d0%b0%d1%85-%d0%9f%d1%96%d0%b4%d1%81%d1%83%d0%bc%d0%be%d0%ba">Підсумок</a> </li> </ol> </li> <li class='chapter'> <h2>A2. <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-B:-%d0%92%d0%b1%d1%83%d0%b4%d0%be%d0%b2%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d1%83-%d0%b2%d0%b0%d1%88%d1%96-%d0%b7%d0%b0%d1%81%d1%82%d0%be%d1%81%d1%83%d0%bd%d0%ba%d0%b8-Git-%d0%b7-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%bd%d0%be%d0%b3%d0%be-%d1%80%d1%8f%d0%b4%d0%ba%d0%b0">Додаток B: Вбудовування Git у ваші застосунки</a></h2> <ol> <li> A2.1 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-B:-%d0%92%d0%b1%d1%83%d0%b4%d0%be%d0%b2%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d1%83-%d0%b2%d0%b0%d1%88%d1%96-%d0%b7%d0%b0%d1%81%d1%82%d0%be%d1%81%d1%83%d0%bd%d0%ba%d0%b8-Git-%d0%b7-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%bd%d0%be%d0%b3%d0%be-%d1%80%d1%8f%d0%b4%d0%ba%d0%b0">Git з командного рядка</a> </li> <li> A2.2 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-B:-%d0%92%d0%b1%d1%83%d0%b4%d0%be%d0%b2%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d1%83-%d0%b2%d0%b0%d1%88%d1%96-%d0%b7%d0%b0%d1%81%d1%82%d0%be%d1%81%d1%83%d0%bd%d0%ba%d0%b8-Libgit2">Libgit2</a> </li> <li> A2.3 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-B:-%d0%92%d0%b1%d1%83%d0%b4%d0%be%d0%b2%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d1%83-%d0%b2%d0%b0%d1%88%d1%96-%d0%b7%d0%b0%d1%81%d1%82%d0%be%d1%81%d1%83%d0%bd%d0%ba%d0%b8-JGit">JGit</a> </li> <li> A2.4 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-B:-%d0%92%d0%b1%d1%83%d0%b4%d0%be%d0%b2%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-Git-%d1%83-%d0%b2%d0%b0%d1%88%d1%96-%d0%b7%d0%b0%d1%81%d1%82%d0%be%d1%81%d1%83%d0%bd%d0%ba%d0%b8-go-git">go-git</a> </li> </ol> </li> <li class='chapter'> <h2>A3. <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%9d%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d1%82%d0%b0-%d0%ba%d0%be%d0%bd%d1%84%d1%96%d0%b3%d1%83%d1%80%d0%b0%d1%86%d1%96%d1%8f">Додаток C: Команди Git</a></h2> <ol> <li> A3.1 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%9d%d0%b0%d0%bb%d0%b0%d1%88%d1%82%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d1%82%d0%b0-%d0%ba%d0%be%d0%bd%d1%84%d1%96%d0%b3%d1%83%d1%80%d0%b0%d1%86%d1%96%d1%8f">Налаштування та конфігурація</a> </li> <li> A3.2 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%9e%d1%82%d1%80%d0%b8%d0%bc%d0%b0%d0%bd%d0%bd%d1%8f-%d1%82%d0%b0-%d1%81%d1%82%d0%b2%d0%be%d1%80%d0%b5%d0%bd%d0%bd%d1%8f-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d1%96%d0%b2">Отримання та створення проектів</a> </li> <li> A3.3 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%91%d0%b0%d0%b7%d0%be%d0%b2%d0%b5-%d0%b7%d0%b1%d0%b5%d1%80%d0%b5%d0%b6%d0%b5%d0%bd%d0%bd%d1%8f-%d0%b2%d1%96%d0%b4%d0%b1%d0%b8%d1%82%d0%ba%d1%96%d0%b2">Базове збереження відбитків</a> </li> <li> A3.4 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%93%d0%b0%d0%bb%d1%83%d0%b6%d0%b5%d0%bd%d0%bd%d1%8f-%d1%82%d0%b0-%d0%b7%d0%bb%d0%b8%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f">Галуження та зливання</a> </li> <li> A3.5 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%9f%d0%be%d1%88%d0%b8%d1%80%d0%b5%d0%bd%d0%bd%d1%8f-%d0%b9-%d0%be%d0%bd%d0%be%d0%b2%d0%bb%d0%b5%d0%bd%d0%bd%d1%8f-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d1%96%d0%b2">Поширення й оновлення проектів</a> </li> <li> A3.6 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%9e%d0%b3%d0%bb%d1%8f%d0%b4-%d1%82%d0%b0-%d0%bf%d0%be%d1%80%d1%96%d0%b2%d0%bd%d1%8f%d0%bd%d0%bd%d1%8f">Огляд та порівняння</a> </li> <li> A3.7 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%97%d0%bd%d0%b5%d0%b2%d0%b0%d0%b4%d0%b6%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f">Зневаджування</a> </li> <li> A3.8 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%9b%d0%b0%d1%82%d0%b0%d0%bd%d0%bd%d1%8f-patching">Латання (patching)</a> </li> <li> A3.9 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%95%d0%bb%d0%b5%d0%ba%d1%82%d1%80%d0%be%d0%bd%d0%bd%d0%b0-%d0%bf%d0%be%d1%88%d1%82%d0%b0">Електронна пошта</a> </li> <li> A3.10 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%97%d0%be%d0%b2%d0%bd%d1%96%d1%88%d0%bd%d1%96-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b8">Зовнішні системи</a> </li> <li> A3.11 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%90%d0%b4%d0%bc%d1%96%d0%bd%d1%96%d1%81%d1%82%d1%80%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f">Адміністрування</a> </li> <li> A3.12 <a href="/book/uk/v2/%d0%94%d0%be%d0%b4%d0%b0%d1%82%d0%be%d0%ba-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8-Git-%d0%9a%d1%83%d1%85%d0%be%d0%bd%d0%bd%d1%96-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%b8">Кухонні команди</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>9.1 Git and Other Systems - Git як клієнт</h1> <div> <p>Світ не ідеальний. Зазвичай, ви не зможете швидко перевести будь-який проект, над яким працюєте, на використання Git. Іноді вам доведеться мати справу з проектами, де використовується інша система контролю версій, хоча вам би й хотілося, щоб це був Git. У першій частині цього розділу ви дізнаєтесь про способи використання Git в якості клієнта для роботи з проектом, який розміщений в іншій системі.</p><p>В якусь мить ви, можливо, захочете перевести ваш проект на Git. У другій частині цього розділу ви дізнаєтесь як провести міграцію з деяких поширених систем на Git, а також ознайомитесь з методом, який буде працювати в ситуаціях, коли готових інструментів для міграції не існує.</p> <h2 id="_git_як_клієнт">Git як клієнт</h2> <div class="paragraph"> <p> Git справляє настільки позитивне враження на розробників, що багато з них вигадують способи використання Git на своєму комп’ютері навіть тоді, коли решта команди використовує іншу систему контролю версій. Для цього розроблено багато спеціальних адаптерів, які називаються "мостами" ("bridges"). Тут ми розглянемо ті адаптери, з якими вам, найімовірніше, доведеться мати справу при роботі над реальними проектами.</p> </div> <div class="sect3"> <h3 id="_git_svn">Git та Subversion</h3> <div class="paragraph"> <p> Велика частина проектів з вільним кодом та чимало корпоративних проектів використовують Subversion для керування вихідним кодом. Він існує вже більш ніж десятиріччя, та більшість цього час був <em>де факто</em> вибором СКВ для проектів з вільним кодом. Він також багато в чому дуже схожий на CVS, який був великим цабе у світі керування кодом перед тим.</p> </div> <div class="paragraph"> <p> Однією з чудових функцій Git є двобічний звʼязок з Subversion під назвою <code>git svn</code>. Цей інструмент дозволяє вам використовувати Git як клієнт для сервера Subversion, отже ви можете використовувати весь локальний функціонал Git, а потім надсилати зміни до сервера Subversion, ніби ви використовували Subversion локально. Це означає, що ви можете використовувати локальні гілки та зливання, індекс, перебазування та висмикувавання тощо, доки ваші співробітники продовжують працювати своїми темними старожитними методами. Це гарний спосіб проникнути з Git до корпоративного середовища та допомогти вашим співпрацівникам стати ефективнішими в той час, як ви просуваєте зміну інфраструктури для повної підтримки Git. Міст Subversion — це безкоштовна доза наркотиків у світі розподілених систем керування версіями.</p> </div> <div class="sect4"> <h4 id="_git_svn_2"><code>git svn</code></h4> <div class="paragraph"> <p>Базова команда Git для всіх команд мосту Subversion — <code>git svn</code>. Вона приймає доволі багато команд, отже ми покажемо найпоширеніші під час розгляду декількох простих процесів роботи.</p> </div> <div class="paragraph"> <p>Важливо зазначити, що коли ви використовуєте <code>git svn</code>, то взаємодієте зі Subversion, який є системою, що працює геть іншим чином, порівняно з Git. Хоча ви <strong>можете</strong> виконувати локальне галуження та зливання, зазвичай найкраще зберігати історію якомога лінійнішою за допомогою перебазування, та уникати чогось на кшталт взаємодії з віддаленим сховищем Git.</p> </div> <div class="paragraph"> <p>Не переписуйте історії та не намагайтесь знову надіслати зміни, та не надсилайте до паралельного сховища Git для взаємодії зі співробітниками, які використовують Git. Subversion може мати лише єдину лінійну історію, та заплутати його дуже легко. Якщо ви працюєте в команді, і дехто використовує SVN, а інші — Git, переконайтесь, що всі використовують сервер SVN для взаємодії — це зробить ваше життя легшим.</p> </div> </div> <div class="sect4"> <h4 id="_налаштування">Налаштування</h4> <div class="paragraph"> <p>Задля демонстрації цього функціоналу, вам потрібне звичайне сховище SVN, до якого у вас є доступ на запис. Якщо бажаєте виконувати подальші приклади, вам треба створити копію якогось тестового SVN сховища з правом на запис. Щоб зробити це легко, ви можете використати інструмент під назвою <code>svnsync</code>, який постачається разом зі Subversion.</p> </div> <div class="paragraph"> <p>Щоб схоплювати думку, вам спочатку треба створити локальне сховище Subversion:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ mkdir /tmp/test-svn $ svnadmin create /tmp/test-svn</code></pre> </div> </div> <div class="paragraph"> <p>Потім, дозволити всім користувачам змінювати revprops — це просто зробити, якщо додати скрипт <code>pre-revprop-change</code>, який завжди повертає 0:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cat /tmp/test-svn/hooks/pre-revprop-change #!/bin/sh exit 0; $ chmod +x /tmp/test-svn/hooks/pre-revprop-change</code></pre> </div> </div> <div class="paragraph"> <p>Тепер ви можете синхронізувати цей проект на вашій локальній машині — для цього треба викликати <code>svnsync init</code> з параметрами <code>до якого'' та </code>з якого'' сховища синхронізувати.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ svnsync init file:///tmp/test-svn \ http://your-svn-server.example.org/svn/</code></pre> </div> </div> <div class="paragraph"> <p>Це налаштовує властивості (properties) для виконання синхронізації. Потім треба зробити клонування коду, виконавши</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ svnsync sync file:///tmp/test-svn Committed revision 1. Copied properties for revision 1. Transmitting file data .............................[...] Committed revision 2. Copied properties for revision 2. […]</code></pre> </div> </div> <div class="paragraph"> <p>Хоча ця операція може потребувати лише кілька хвилин, якщо ви спробуєте скопіювати оригінальне сховище до іншого віддаленого, замість локального, процес займе близько години, навіть якщо там менше ніж 100 комітів. Subversion має клонувати одну ревізію за раз та потім надсилати її до іншого сховища — це химерно неефективно, проте це єдиний простий спосіб.</p> </div> </div> <div class="sect4"> <h4 id="_розпочинаємо">Розпочинаємо</h4> <div class="paragraph"> <p>Тепер, коли у вас є сховище Subversion з доступом на запис, ви можете прослідкувати за типовим процесом роботи. Ви почнете з команди <code>git svn clone</code>, яка імпортує весь репозиторій Subversion до локального сховища Git. Памʼятайте: якщо ви імпортуєте зі справжнього розгорнутого (hosted) сховища Subversion, то маєте замінити <code><a href="file:///tmp/test-svn" class="bare">file:///tmp/test-svn</a></code> на URL вашого репозиторія Subversion:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn clone file:///tmp/test-svn -T trunk -b branches -t tags Initialized empty Git repository in /private/tmp/progit/test-svn/.git/ r1 = dcbfb5891860124cc2e8cc616cded42624897125 (refs/remotes/origin/trunk) A m4/acx_pthread.m4 A m4/stl_hash.m4 A java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java A java/src/test/java/com/google/protobuf/WireFormatTest.java … r75 = 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae (refs/remotes/origin/trunk) Found possible branch point: file:///tmp/test-svn/trunk => file:///tmp/test-svn/branches/my-calc-branch, 75 Found branch parent: (refs/remotes/origin/my-calc-branch) 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae Following parent with do_switch Successfully followed parent r76 = 0fb585761df569eaecd8146c71e58d70147460a2 (refs/remotes/origin/my-calc-branch) Checked out HEAD: file:///tmp/test-svn/trunk r75</code></pre> </div> </div> <div class="paragraph"> <p>Це еквівалентно виклику двох команд — <code>git svn init</code> та потім <code>git svn fetch</code> — з URL, який ви надали. Це може бути довгим процесом. Якщо, наприклад, тестовий проект має лише приблизно 75 комітів та невеликий за розміром код, Git все одно має отримати кожну версію, по одній за раз, та створювати коміти для кожної. Для проекту зі сотнями чи тисячами комітів, це може дійсно потребувати годин або навіть днів, щоб завершитись.</p> </div> <div class="paragraph"> <p>Частина <code>-T trunk -b branches -t tags</code> каже Git, що цей репозиторій Subversion розташовує гілки та теґи як заведено. Якщо у вас trunk, гілки чи теґи називаються інакше, ви можете змінити ці опції. Через те, що ця частина дуже розповсюджена, її всю можна замінити на <code>-s</code>, що означає стандартне розташування та означає всі ці опції. Наступна команда еквівалентна попередній:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn clone file:///tmp/test-svn -s</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 branch -a * master remotes/origin/my-calc-branch remotes/origin/tags/2.0.2 remotes/origin/tags/release-2.0.1 remotes/origin/tags/release-2.0.2 remotes/origin/tags/release-2.0.2rc1 remotes/origin/trunk</code></pre> </div> </div> <div class="paragraph"> <p>Завважте, цей інструмент працює з теґами Subversion як з віддаленими посиланнями. Подивімося прискіпливіше за допомогою кухонної команди Git <code>show-ref</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git show-ref 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/heads/master 0fb585761df569eaecd8146c71e58d70147460a2 refs/remotes/origin/my-calc-branch bfd2d79303166789fc73af4046651a4b35c12f0b refs/remotes/origin/tags/2.0.2 285c2b2e36e467dd4d91c8e3c0c0e1750b3fe8ca refs/remotes/origin/tags/release-2.0.1 cbda99cb45d9abcb9793db1d4f70ae562a969f1e refs/remotes/origin/tags/release-2.0.2 a9f074aa89e826d6f9d30808ce5ae3ffe711feda refs/remotes/origin/tags/release-2.0.2rc1 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/remotes/origin/trunk</code></pre> </div> </div> <div class="paragraph"> <p>Git такого не робить, коли клонує з Git сервера; ось як сховище з теґами виглядає відразу після клонування:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git show-ref c3dcbe8488c6240392e8a5d7553bbffcb0f94ef0 refs/remotes/origin/master 32ef1d1c7cc8c603ab78416262cc421b80a8c2df refs/remotes/origin/branch-1 75f703a3580a9b81ead89fe1138e6da858c5ba18 refs/remotes/origin/branch-2 23f8588dde934e8f33c263c6d8359b2ae095f863 refs/tags/v0.1.0 7064938bd5e7ef47bfd79a685a62c1e2649e2ce7 refs/tags/v0.2.0 6dcb09b5b57875f334f61aebed695e2e4193db5e refs/tags/v1.0.0</code></pre> </div> </div> <div class="paragraph"> <p>Git отримує теґи напряму до <code>refs/tags</code>, замість того, щоб працювати з ними, як з віддаленими гілками.</p> </div> </div> <div class="sect4"> <h4 id="_надсилання_змін_назад_до_subversion">Надсилання змін назад до Subversion</h4> <div class="paragraph"> <p>Тепер, коли у вас є робоча тека, ви можете попрацювати над проектом на надіслати свої коміти назад до першоджерела, використовуючи Git фактично як клієнт SVN. Якщо ви відредагували один з файлів та зберегли його в коміті, то маєте коміт, що існує в Git локально, проте не існує на сервері Subversion:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git commit -am 'Adding git-svn instructions to the README' [master 4af61fd] Adding git-svn instructions to the README 1 file changed, 5 insertions(+)</code></pre> </div> </div> <div class="paragraph"> <p>Далі, вам треба надіслати свої зміни до першоджерела. Завважте, як це змінює спосіб роботи з Subversion — ви можете створити декілька комітів локально, та лише потім надіслати їх всіх разом до сервера Subversion. Щоб надіслати до сервера Subversion, треба виконати команду <code>git svn dcommit</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn dcommit Committing to file:///tmp/test-svn/trunk ... M README.txt Committed r77 M README.txt r77 = 95e0222ba6399739834380eb10afcd73e0670bc5 (refs/remotes/origin/trunk) No changes between 4af61fd05045e07598c553167e0f31c84fd6ffe1 and refs/remotes/origin/trunk Resetting to the latest refs/remotes/origin/trunk</code></pre> </div> </div> <div class="paragraph"> <p>Вона бере всі коміти, які ви створили поверху коду з сервера Subversion, робить коміт Subversion для кожного, та потім переписує ваші локальні коміти Git, щоб додати до них унікальний ідентифікатор. Це важливо, оскільки означає, що всі SHA-1 суми ваших комітів зміняться. Частково через це, робота з віддаленою версію проекту, яка працює на Git, та одночасно працювати з сервером Subversion, не є гарною ідеєю. Якщо ви подивитесь на останній коміт, то побачите новий доданий <code>git-svn-id</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git log -1 commit 95e0222ba6399739834380eb10afcd73e0670bc5 Author: ben <ben@0b684db3-b064-4277-89d1-21af03df0a68> Date: Thu Jul 24 03:08:36 2014 +0000 Adding git-svn instructions to the README git-svn-id: file:///tmp/test-svn/trunk@77 0b684db3-b064-4277-89d1-21af03df0a68</code></pre> </div> </div> <div class="paragraph"> <p>Зверніть увагу, що раніше сума SHA-1 починалася з <code>4af61fd</code>, а після коміту починається з <code>95e0222</code>. Якщо ви бажаєте надсилати зміни й до сервера Git, і до сервера Subversion, то маєте спочатку надіслати (<code>dcommit</code>) до Subversion, оскільки ця дія змінює дані комітів.</p> </div> </div> <div class="sect4"> <h4 id="_отримання_нових_змін">Отримання нових змін</h4> <div class="paragraph"> <p>Якщо ви працюєте з іншими розробниками, то колись хтось з вас надішле зміни, потім хтось інших спробує надіслати зміни, які призводять до конфлікту. Ця зміна буде відхилена, доки ви не зіллєте їхню роботу. З <code>git svn</code>, це виглядає так:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn dcommit Committing to file:///tmp/test-svn/trunk ... ERROR from SVN: Transaction is out of date: File '/trunk/README.txt' is out of date W: d5837c4b461b7c0e018b49d12398769d2bfc240a and refs/remotes/origin/trunk differ, using rebase: :100644 100644 f414c433af0fd6734428cf9d2a9fd8ba00ada145 c80b6127dd04f5fcda218730ddf3a2da4eb39138 M README.txt Current branch master is up to date. ERROR: Not all changes have been committed into SVN, however the committed ones (if any) seem to be successfully integrated into the working tree. Please see the above messages for details.</code></pre> </div> </div> <div class="paragraph"> <p>Щоб розвʼязати цю проблему, ви можете виконати <code>git svn rebase</code>, який отримує будь-які зміни на сервері, яких у вас покищо немає, та перебазовує всю роботу, яка у вас є поверху того, що є на сервері:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn rebase Committing to file:///tmp/test-svn/trunk ... ERROR from SVN: Transaction is out of date: File '/trunk/README.txt' is out of date W: eaa029d99f87c5c822c5c29039d19111ff32ef46 and refs/remotes/origin/trunk differ, using rebase: :100644 100644 65536c6e30d263495c17d781962cfff12422693a b34372b25ccf4945fe5658fa381b075045e7702a M README.txt First, rewinding head to replay your work on top of it... Applying: update foo Using index info to reconstruct a base tree... M README.txt Falling back to patching base and 3-way merge... Auto-merging README.txt ERROR: Not all changes have been committed into SVN, however the committed ones (if any) seem to be successfully integrated into the working tree. Please see the above messages for details.</code></pre> </div> </div> <div class="paragraph"> <p>Тепер, вся ваша робота знаходиться поверху того, що є на сервері Subversion, отже ви можете успішно зробити <code>dcommit</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn dcommit Committing to file:///tmp/test-svn/trunk ... M README.txt Committed r85 M README.txt r85 = 9c29704cc0bbbed7bd58160cfb66cb9191835cd8 (refs/remotes/origin/trunk) No changes between 5762f56732a958d6cfda681b661d2a239cc53ef5 and refs/remotes/origin/trunk Resetting to the latest refs/remotes/origin/trunk</code></pre> </div> </div> <div class="paragraph"> <p>Зверніть увагу, що на відміну від Git, який вимагає від вас зливати роботу з першоджерела, якої у вас немає локально перед надсиланням, <code>git svn</code> вимагає від вас цього лише якщо зміни конфліктують (так само, як працює Subversion). Якщо хтось інший надішле зміну до одного файлу, а потім ви надішлете зміну до іншого файлу, ваш <code>dcommit</code> спрацює без проблем:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn dcommit Committing to file:///tmp/test-svn/trunk ... M configure.ac Committed r87 M autogen.sh r86 = d8450bab8a77228a644b7dc0e95977ffc61adff7 (refs/remotes/origin/trunk) M configure.ac r87 = f3653ea40cb4e26b6281cec102e35dcba1fe17c4 (refs/remotes/origin/trunk) W: a0253d06732169107aa020390d9fefd2b1d92806 and refs/remotes/origin/trunk differ, using rebase: :100755 100755 efa5a59965fbbb5b2b0a12890f1b351bb5493c18 e757b59a9439312d80d5d43bb65d4a7d0389ed6d M autogen.sh First, rewinding head to replay your work on top of it...</code></pre> </div> </div> <div class="paragraph"> <p>Це важливо памʼятати, адже призводить до стану проекту, якого не існувало на жодному з клієнтів перед надсиланням. Якщо зміни несумісні, хоча й не конфліктують, ви можете отримати проблеми, які важко виявити. Це відрізняється від користування сервером Git — у Git ви можете повністю перевірити стан на клієнтській системі перед його публікацією, а в SVN, ви навіть не можете бути певні, що стан прямо перед комітом та після нього однакові.</p> </div> <div class="paragraph"> <p>Вам також варто виконати наступну команду, щоб отримати зміни зі сервера Subversion, якщо ви не готові створити коміт. Ви можете виконати <code>git svn fetch</code>, щоб взяти нові дані, проте <code>git svn rebase</code> і отримує дані, і оновлює ваші локальні коміти.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn rebase M autogen.sh r88 = c9c5f83c64bd755368784b444bc7a0216cc1e17b (refs/remotes/origin/trunk) First, rewinding head to replay your work on top of it... Fast-forwarded master to refs/remotes/origin/trunk.</code></pre> </div> </div> <div class="paragraph"> <p>Виконуйте <code>git svn rebase</code> подеколи, щоб переконатися, що ваш код завжди синхронізовано. Втім, вам треба переконатися, що робоча директорія чиста перед виконанням цієї команди. Якщо у вас є локальні зміни, то треба або сховати їх, або тимчасово створити з них коміт перед виконанням <code>git svn rebase</code> — інакше, команда зупиниться, якщо побачить, що перебазування призведе до конфліктів злиття.</p> </div> </div> <div class="sect4"> <h4 id="_проблеми_з_галуженням_git">Проблеми з галуженням Git</h4> <div class="paragraph"> <p>Коли ви звикаєте до процесу роботи Git, ви, вірогідно, створюєте тематичні гілки, працюєте в них, а потім зливаєте їх. Якщо ви надсилаєте до сервера Subversion командою <code>git svn</code>, то можливо ліпше перебазувати вашу роботу поверху однієї гілки замість того, щоб зливати гілки разом. Причина надати перевагу перебазуванню в тому, що Subversion має лінійну історію, та не працює зі зливаннями, як Git, отже <code>git svn</code> слідує лише за першими батьками, коли перетворює відбитки на коміти Subversion.</p> </div> <div class="paragraph"> <p>Припустімо, що ваша історія виглядає наступним чином: ви створили гілку <code>experiment</code>, зробили два коміти, а потім злили їх назад до <code>master</code>. Коли ви зробите <code>dcommit</code>, то побачите щось таке:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn dcommit Committing to file:///tmp/test-svn/trunk ... M CHANGES.txt Committed r89 M CHANGES.txt r89 = 89d492c884ea7c834353563d5d913c6adf933981 (refs/remotes/origin/trunk) M COPYING.txt M INSTALL.txt Committed r90 M INSTALL.txt M COPYING.txt r90 = cb522197870e61467473391799148f6721bcf9a0 (refs/remotes/origin/trunk) No changes between 71af502c214ba13123992338569f4669877f55fd and refs/remotes/origin/trunk Resetting to the latest refs/remotes/origin/trunk</code></pre> </div> </div> <div class="paragraph"> <p>Виконання <code>dcommit</code> на гілці зі злитою історією працює успішно, окрім того, що, якщо подивитись на історію проекту Git, то виявиться, що жоден з комітів, створених у гілці <code>experiment</code>, не переписано — натомість, усі ці зміни зʼявляються у версії SVN як єдиний коміт злиття.</p> </div> <div class="paragraph"> <p>Коли хтось зробить клон цієї праці, усе, що вони побачать — коміт зливання з усіма змінами в ньому, ніби ви виконали <code>git merge --squash</code>; вони не побачать дані про окремі коміти - коли вони були створені чи звідки взялися.</p> </div> </div> <div class="sect4"> <h4 id="_галуження_subversion">Галуження Subversion</h4> <div class="paragraph"> <p>Галуження Subversion не таке, як в Git: якщо ви можете уникнути його використання, то, напевно, найкраще це зробити. Втім, ви можете створювати й надсилати коміти до гілок Subversion за допомогою <code>git svn</code>.</p> </div> </div> <div class="sect4"> <h4 id="_створення_нової_гілки_svn">Створення нової гілки SVN</h4> <div class="paragraph"> <p>Щоб створити нову гілку Subversion, ви можете виконати <code>git svn branch [назва-нової-гілки]</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn branch opera Copying file:///tmp/test-svn/trunk at r90 to file:///tmp/test-svn/branches/opera... Found possible branch point: file:///tmp/test-svn/trunk => file:///tmp/test-svn/branches/opera, 90 Found branch parent: (refs/remotes/origin/opera) cb522197870e61467473391799148f6721bcf9a0 Following parent with do_switch Successfully followed parent r91 = f1b64a3855d3c8dd84ee0ef10fa89d27f1584302 (refs/remotes/origin/opera)</code></pre> </div> </div> <div class="paragraph"> <p>Це рівнозначно команді Subversion <code>svn copy trunk branches/opera</code> та виконується на сервері Subversion. Важливо зазначити, що це не переключає вас до нової гілки; якщо ви зараз створите коміт, цей коміт піде до гілки <code>trunk</code> на сервері, а не до <code>opera</code>.</p> </div> </div> <div class="sect4"> <h4 id="_переключення_активних_гілок">Переключення активних гілок</h4> <div class="paragraph"> <p>Git визначає, до якої гілки dcommit має надсилати ваші зміни наступним чином: знаходить верхівку будь-якої з ваших гілок Subversion в історії — у вас має бути лише одна, та це має бути останній коміт з <code>git-svn-id</code> в історії вашої поточної гілки.</p> </div> <div class="paragraph"> <p>Якщо ви бажаєте працювати більш ніж з однією гілкою одночасно, то можете налаштувати локальні гілки робити <code>dcomit</code> до окремих гілок Subversion, якщо почнете їх за допомогою імпортування коміту з потрібної гілки Subversion. Якщо вам потрібна гілка <code>opera</code>, над якою ви зможете працювати окремо, то можете виконати</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git branch opera remotes/origin/opera</code></pre> </div> </div> <div class="paragraph"> <p>Тепер, якщо ви бажаєте злити свою гілку <code>opera</code> до <code>trunk</code> (ваша гілка <code>master</code>), то можете це зробити звичайним <code>git merge</code>. Проте, ви маєте зробити повідомлення коміту змістовним (за допомогою <code>-m</code>), інакше злиття просто напише ``Merge branch opera'' замість чогось корисного.</p> </div> <div class="paragraph"> <p>Памʼятайте: хоча ви використовуєте <code>git merge</code> для цієї операції, і зливання напевно буде набагато легшим, ніж було б у Subversion (адже Git автоматично знайде відповідну базу для злиття), це не звичайний коміт злиття Git. Ви маєте надіслати ці дані назад до серверу Subversion, який не може впоратись з комітом, який має більше одного батька; отже, після того, як ви його надішлете, він буде виглядати, як коміт, який зварив у собі всю роботу з іншої гілки. Після зливання однієї гілки в іншу, ви не зможете легко повернутись назад та продовжити роботу в тій гілці, як зазвичай у Git. Команда <code>dcommit</code>, яку ви виконуєте, стирає будь-яку інформацію про зливання гілки, отже наступні визначення бази для зливання будуть хибними — <code>dcommit</code> призводить до того, що результат вашого <code>git merge</code> виглядає так, ніби ви виконали <code>git merge --squash</code>. На жаль, не існує доладного способу уникнути цієї ситуації — Subversion не може зберігати цю інформацію, отже ви завжди будете окалічені цими обмеженнями, доки використовуєте його як свій сервер. Щоб уникнути проблем, варто вилучити локальну гілку (у даному випадку, <code>opera</code>) після зливання її до trunk.</p> </div> </div> <div class="sect4"> <h4 id="_команди_subversion">Команди Subversion</h4> <div class="paragraph"> <p>Набір інструментів <code>git svn</code> пропонує чимало команд, щоб полегшити перехід до Git, для чого надає деякий функціонал, схожий на те, що було в Subversion. Ось декілька команд, які надають вам те, що пропонував Subversion.</p> </div> <div class="sect5"> <h6 id="_історія_в_стилі_svn">Історія в стилі SVN</h6> <div class="paragraph"> <p>Якщо ви звикли до Subversion та бажаєте бачити свою історію в стилі SVN, то можете виконати <code>git svn log</code>, щоб побачити історію комітів у форматі SVN:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn log ------------------------------------------------------------------------ r87 | schacon | 2014-05-02 16:07:37 -0700 (Sat, 02 May 2014) | 2 lines autogen change ------------------------------------------------------------------------ r86 | schacon | 2014-05-02 16:00:21 -0700 (Sat, 02 May 2014) | 2 lines Merge branch 'experiment' ------------------------------------------------------------------------ r85 | schacon | 2014-05-02 16:00:09 -0700 (Sat, 02 May 2014) | 2 lines updated the changelog</code></pre> </div> </div> <div class="paragraph"> <p>Ви маєте знати дві важливі речі про <code>git svn log</code>. По-перше, вона працює без мережі, на відміну від справжньої команди <code>svn log</code>, яка робить запит до сервера Subversion. По-друге, вона показує вам лише коміти, які були надіслані до сервера Subversion. Локальні коміти Git, для яких ви ще не виконали dcommit, не показано; як і коміти, які інші надіслали до Subversion за цей час. Це більше схоже на останній відомий стан комітів сервера Subversion.</p> </div> </div> <div class="sect5"> <h6 id="_анотація_svn">Анотація SVN</h6> <div class="paragraph"> <p>Як команда <code>git svn log</code> імітує команду <code>svn log</code> поза мережею, так само ви можете отримати еквівалент <code>svn annotate</code>, якщо виконаєте <code>git svn blame [ФАЙЛ]</code>. Вивід виглядатиме так:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn blame README.txt 2 temporal Protocol Buffers - Google's data interchange format 2 temporal Copyright 2008 Google Inc. 2 temporal http://code.google.com/apis/protocolbuffers/ 2 temporal 22 temporal C++ Installation - Unix 22 temporal ======================= 2 temporal 79 schacon Committing in git-svn. 78 schacon 2 temporal To build and install the C++ Protocol Buffer runtime and the Protocol 2 temporal Buffer compiler (protoc) execute the following: 2 temporal</code></pre> </div> </div> <div class="paragraph"> <p>Ще раз, тут не показано комітів, які ви зробили локально в Git, або які були надіслані до Subversion за цей час.</p> </div> </div> <div class="sect5"> <h6 id="_інформація_про_сервер_svn">Інформація про сервер SVN</h6> <div class="paragraph"> <p>Ви також можете отримати інформацію на кшталт тієї, що надає вам <code>svn info</code>, якщо виконаєте <code>git svn info</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn info Path: . URL: https://schacon-test.googlecode.com/svn/trunk Repository Root: https://schacon-test.googlecode.com/svn Repository UUID: 4c93b258-373f-11de-be05-5f7a86268029 Revision: 87 Node Kind: directory Schedule: normal Last Changed Author: schacon Last Changed Rev: 87 Last Changed Date: 2009-05-02 16:07:37 -0700 (Sat, 02 May 2009)</code></pre> </div> </div> <div class="paragraph"> <p>Це схоже на <code>blame</code> та <code>log</code> у тому, що виконується поза мережею та відповідає лише часу останнього звʼязку зі сервером Subversion.</p> </div> </div> <div class="sect5"> <h6 id="_ігнорування_того_що_ігнорує_subversion">Ігнорування того, що ігнорує Subversion</h6> <div class="paragraph"> <p>Якщо ви створите клон Subversion, який десь має встановлені властивості <code>svn:ignore</code>, ви напевно забажаєте створити відповідні файли <code>.gitignore</code>, щоб випадково не додати файли, які не треба. <code>git svn</code> має дві команди, щоб допомогти з цим. Перша — це <code>git svn create-ignore</code>, яка автоматично створює відповідні файли <code>.gitignore</code>, отже ваш наступний коміт може включити їх.</p> </div> <div class="paragraph"> <p>Другою командою є <code>git svn show-ignore</code>, яка друкує до stdout рядки, які вам треба помістити до файлу <code>.gitignore</code>, щоб ви могли надіслати вивід до файлу exclude вашого проекту:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn show-ignore > .git/info/exclude</code></pre> </div> </div> <div class="paragraph"> <p>Таким чином, вам не доведеться засмічувати проект файлами <code>.gitignore</code>. Це гарна опція, якщо ви єдиний користувач Git у команді Subversion, та ваші співпрацівники не бажають файлів <code>.gitignore</code> у проекті.</p> </div> </div> </div> <div class="sect4"> <h4 id="_підсумок_по_git_svn">Підсумок по git-svn</h4> <div class="paragraph"> <p>Інструменти <code>git svn</code> корисні, якщо ви захрясли зі сервером Subversion, чи іншим чином потрапили в середовище розробки, яке вимагає працюючого сервера Subversion. Втім, ви маєте вважати їх покаліченим Git, інакше можете зіткнутися з проблемами переходу, які можуть спантеличити вас чи ваших співробітників. Щоб уникнути проблем, намагайтесь слідувати таким порадам:</p> </div> <div class="ulist"> <ul> <li> <p>Зберігайте лінійну історію Git, яка не містить комітів злиття, створених <code>git merge</code>. Перебазовуйте будь-яку роботу, що була створена поза головною гілкою поверху неї; не зливайте до неї.</p> </li> <li> <p>Не налаштовуйте співпрацю на окремому сервері Git. Можете мати один, щоб прискорити клонування для нових розробників, проте не надсилайте до нього нічого, що не має <code>git-svn-id</code>. Можливо навіть варто додати гак <code>pre-receive</code>, який перевіряє кожне повідомлення коміту, та відхиляє їх, якщо хтось намагається надіслати якийсь коміт без <code>git-svn-id</code>.</p> </li> </ul> </div> <div class="paragraph"> <p>Якщо ви слідуватимете цим порадам, працю зі сервером Subversion буде легше витримати. Втім, якщо є можливість перейти на справжній сервер Git, то це надасть вашій команді набагато більше переваг.</p> </div> </div> </div> <div class="sect3"> <h3 id="_git_і_mercurial">Git і Mercurial</h3> <div class="paragraph"> <p> Всесвіт розподілених систем контролю версій значно більший, ніж просто Git. Насправді, існує багато інших систем, кожна зі своїм власним поглядом на процес розподіленого контролю версій. Окрім Git, найпопулярнішою з них є Mercurial, і ці дві системи мають багато спільного.</p> </div> <div class="paragraph"> <p>Хорошою новиною є те, що якщо ви надаєте перевагу Git, але вам доводиться працювати з проектами, код яких знаходиться в системі Mercurial, існує спосіб використання Git у якості клієнта для роботи з репозиторієм на Mercurial. Оскільки Git працює з серверами через концепцію "віддалених репозиторіїв" (remotes), не дивно, що цей міст реалізовано за допомогою своєрідного "помічника протоколу" (remote helper) для "віддалених репозиторіїв". Проект, який реалізує вищесказане, називається <code>git-remote-hg</code> і розміщений за адресою <a href="https://github.com/felipec/git-remote-hg" class="bare">https://github.com/felipec/git-remote-hg</a>.</p> </div> <div class="sect4"> <h4 id="_git_remote_hg">git-remote-hg</h4> <div class="paragraph"> <p>Для початку, вам потрібно встановити <code>git-remote-hg</code>. Для цього скопіюйте файл до директорії, що є у вашому <code>PATH</code>, наприклад:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ curl -o ~/bin/git-remote-hg \ https://raw.githubusercontent.com/felipec/git-remote-hg/master/git-remote-hg $ chmod +x ~/bin/git-remote-hg</code></pre> </div> </div> <div class="paragraph"> <p>…припускаючи, що <code>~/bin</code> включений у ваш <code>$PATH</code>. Git-remote-hg має ще одну залежність: бібліотеку <code>mercurial</code> для Python. Якщо у вас встановлено Python, просто виконайте:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ pip install mercurial</code></pre> </div> </div> <div class="paragraph"> <p>(Якщо ж у вас не встановлено Python, перейдіть за посиланням <a href="https://www.python.org/" class="bare">https://www.python.org/</a> і спочатку встановіть його.)</p> </div> <div class="paragraph"> <p>І останнє, що вам знадобиться, це клієнт Mercurial. Перейдіть за посиланням <a href="https://www.mercurial-scm.org/" class="bare">https://www.mercurial-scm.org/</a> і встановіть його, якщо ви цього ще не зробили.</p> </div> <div class="paragraph"> <p>Тепер ви готові побачити магію. Усе, що вам необхідно, це Mercurial-репозиторій, у який ви можете надсилати зміни. На щастя, так можна працювати з кожним Mercurial-репозиторієм, тому ми скористаємось репозиторієм "hello world", який використовується для вивчення Mercurial:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ hg clone http://selenic.com/repo/hello /tmp/hello</code></pre> </div> </div> </div> <div class="sect4"> <h4 id="_основи">Основи</h4> <div class="paragraph"> <p>Тепер, коли в нас є "серверний" репозиторій, ми можемо розглянути типові способи роботи з Mercurial. Як ви побачите згодом, ці дві системи дуже схожі, тому все повинно пройти гладко.</p> </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 clone hg::/tmp/hello /tmp/hello-git $ cd /tmp/hello-git $ git log --oneline --graph --decorate * ac7955c (HEAD, origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master, master) Create a makefile * 65bb417 Create a standard "hello, world" program</code></pre> </div> </div> <div class="paragraph"> <p>Мабуть ви помітили, що для роботи з Mercurial-репозиторієм використовується стандартна команда <code>git clone</code>. Це тому, що git-remote-hg працює на доволі низькому рівні, і використовує механізм, подібний до HTTP/S протоколу в системі Git (помічники протоколу). Оскільки і Git, і Mercurial розраховані на те, що кожен клієнт має повну копію історії репозиторія, вищезгадана команда здійснює повне клонування, включно з усією історією проекту, і робить це досить швидко.</p> </div> <div class="paragraph"> <p>Команда <code>git log</code> показує два коміти, на останній з яких вказує безліч посилань. Насправді, не всі з них реально існують. Погляньмо, що знаходиться всередині директорії <code>.git</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ tree .git/refs .git/refs ├── heads │ └── master ├── hg │ └── origin │ ├── bookmarks │ │ └── master │ └── branches │ └── default ├── notes │ └── hg ├── remotes │ └── origin │ └── HEAD └── tags 9 directories, 5 files</code></pre> </div> </div> <div class="paragraph"> <p>Git-remote-hg намагається нівелювати відмінності між Git та Mercurial, але "під капотом" він керує концептуальними перетвореннями між двома різними системами. У директорії <code>refs/hg</code> знаходяться посилання на об’єкти віддаленого репозиторія. Наприклад, <code>refs/hg/origin/branches/default</code> — це файл-посилання Git, який містить SHA-1, що починається з "ac7955c", який є комітом, на який вказує гілка <code>master</code>. Таким чином, директорія <code>refs/hg</code> — це щось схоже на <code>refs/remotes/origin</code>, але тут окремо зберігаються закладки та гілки.</p> </div> <div class="paragraph"> <p>Файл <code>notes/hg</code> — відправна точка для розуміння того, як git-remote-hg встановлює відповідність між хешами комітів у Git та ідентифікаторами змін у Mercurial. Погляньмо, що там:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cat notes/hg d4c10386... $ git cat-file -p d4c10386... tree 1781c96... author remote-hg <> 1408066400 -0800 committer remote-hg <> 1408066400 -0800 Notes for master $ git ls-tree 1781c96... 100644 blob ac9117f... 65bb417... 100644 blob 485e178... ac7955c... $ git cat-file -p ac9117f 0a04b987be5ae354b710cefeba0e2d9de7ad41a9</code></pre> </div> </div> <div class="paragraph"> <p>Отже, <code>refs/notes/hg</code> вказує на дерево, яке в базі об’єктів Git містить перелік інших об’єктів та їхніх імен. Команда <code>git ls-tree</code> виводить права доступу, тип, хеш та ім’я файлу для елементів дерева. Коли ми дістанемось першого елемента дерева, ми побачимо, що всередині знаходиться блоб з іменем "ac9117f" (SHA-1 хеш коміту, на який вказує гілка <code>master</code>), який містить "0a04b98" (ідентифікатор останньої зміни гілки <code>default</code> у Mercurial).</p> </div> <div class="paragraph"> <p>Хорошою новиною є те, що нам не потрібно турбуватися про все це. Типовий робочий процес не буде значно відрізнятися від роботи з віддаленим репозиторієм Git.</p> </div> <div class="paragraph"> <p>Є ще одна річ, яку ми повинні враховувати, перш ніж продовжувати: ігноровані файли. І Mercurial, і Git використовують для цього схожий механізм, але зберігати файл <code>.gitignore</code> в Mercurial-репозиторії — не найкраща ідея. На щастя, в Git є можливість ігнорувати файли, що знаходяться в локальній копії репозиторія, а формат списку ігнорованих файлів в Mercurial сумісний з Git, тому вам достатньо скопіювати його:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cp .hgignore .git/info/exclude</code></pre> </div> </div> <div class="paragraph"> <p>Файл <code>.git/info/exclude</code> діє подібно до <code>.gitignore</code>, але не включається у коміт.</p> </div> </div> <div class="sect4"> <h4 id="_робочий_процес_2">Робочий процес</h4> <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 log --oneline --graph --decorate * ba04a2a (HEAD, master) Update makefile * d25d16f Goodbye * ac7955c (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Create a makefile * 65bb417 Create a standard "hello, world" program</code></pre> </div> </div> <div class="paragraph"> <p>Наша гілка <code>master</code> на два коміти попереду <code>origin/master</code>, але ці два коміти існують лише на нашій локальній машині. Погляньмо, раптом хтось інший зробив важливі зміни:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git fetch From hg::/tmp/hello ac7955c..df85e87 master -> origin/master ac7955c..df85e87 branches/default -> origin/branches/default $ git log --oneline --graph --decorate --all * 7b07969 (refs/notes/hg) Notes for default * d4c1038 Notes for master * df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation | * ba04a2a (HEAD, master) Update makefile | * d25d16f Goodbye |/ * ac7955c Create a makefile * 65bb417 Create a standard "hello, world" program</code></pre> </div> </div> <div class="paragraph"> <p>Оскільки ми використали <code>--all</code> ми бачимо посилання "notes", які використовуються всередині git-remote-hg, але ми можемо не звертати уваги на них. Все інше — саме те, що ми очікували; <code>origin/master</code> пішов далі на один коміт і наша історія розійшлася. На відміну від інших систем, з якими ми мали справу в цьому розділі, Mercurial вміє працювати зі злиттям, тому нам не потрібно робити жодних фокусів.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git merge origin/master Auto-merging hello.c Merge made by the 'recursive' strategy. hello.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) $ git log --oneline --graph --decorate * 0c64627 (HEAD, master) Merge remote-tracking branch 'origin/master' |\ | * df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation * | ba04a2a Update makefile * | d25d16f Goodbye |/ * ac7955c Create a makefile * 65bb417 Create a standard "hello, world" program</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 push To hg::/tmp/hello df85e87..0c64627 master -> master</code></pre> </div> </div> <div class="paragraph"> <p>І це все! Якщо ви поглянете на Mercurial-репозиторій, ви переконаєтесь, що відбулось саме те, що ми й очікували:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ hg log -G --style compact o 5[tip]:4,2 dc8fa4f932b8 2014-08-14 19:33 -0700 ben |\ Merge remote-tracking branch 'origin/master' | | | o 4 64f27bcefc35 2014-08-14 19:27 -0700 ben | | Update makefile | | | o 3:1 4256fc29598f 2014-08-14 19:27 -0700 ben | | Goodbye | | @ | 2 7db0b4848b3c 2014-08-14 19:30 -0700 ben |/ Add some documentation | o 1 82e55d328c8c 2005-08-26 01:21 -0700 mpm | Create a makefile | o 0 0a04b987be5a 2005-08-26 01:20 -0700 mpm Create a standard "hello, world" program</code></pre> </div> </div> <div class="paragraph"> <p>Набір змін <em>2</em> був здійснений Mercurial’ом, а зміни <em>3</em> та <em>4</em> — за допомогою git-remote-hg шляхом надсилання комітів, зроблених з Git.</p> </div> </div> <div class="sect4"> <h4 id="_гілки_і_закладки">Гілки і закладки</h4> <div class="paragraph"> <p>Git має лише один вид гілок: вказівник, який переміщується при комітах. У Mercurial цей вид вказівника називається "закладка", і вона поводить себе подібно до гілки в Git.</p> </div> <div class="paragraph"> <p>Поняття "гілка" в Mercurial більш складне. Гілка, в якій відбувається зміна, записується <em>всередині кожної зміни</em>, таким чином, вона завжди залишається в історії репозиторія. Ось приклад коміту, який зроблено в гілці <code>develop</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ hg log -l 1 changeset: 6:8f65e5e02793 branch: develop tag: tip user: Ben Straub <ben@straub.cc> date: Thu Aug 14 20:06:38 2014 -0700 summary: More documentation</code></pre> </div> </div> <div class="paragraph"> <p>Зверніть увагу на рядок, що починається з "branch". Git не може насправді відтворити це (і не повинен; обидва типи гілок можуть бути представлені як Git-посилання), але git-remote-hg змушений розуміти цю різницю, оскільки це важливо для Mercurial.</p> </div> <div class="paragraph"> <p>Створення закладок у Mercurial настільки ж просте, як створення гілок у Git. У Git ми робимо наступне:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b featureA Switched to a new branch 'featureA' $ git push origin featureA To hg::/tmp/hello * [new branch] featureA -> featureA</code></pre> </div> </div> <div class="paragraph"> <p>Ось і все, що потрібно. А в Mercurial це виглядає так:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ hg bookmarks featureA 5:bd5ac26f11f9 $ hg log --style compact -G @ 6[tip] 8f65e5e02793 2014-08-14 20:06 -0700 ben | More documentation | o 5[featureA]:4,2 bd5ac26f11f9 2014-08-14 20:02 -0700 ben |\ Merge remote-tracking branch 'origin/master' | | | o 4 0434aaa6b91f 2014-08-14 20:01 -0700 ben | | update makefile | | | o 3:1 318914536c86 2014-08-14 20:00 -0700 ben | | goodbye | | o | 2 f098c7f45c4f 2014-08-14 20:01 -0700 ben |/ Add some documentation | o 1 82e55d328c8c 2005-08-26 01:21 -0700 mpm | Create a makefile | o 0 0a04b987be5a 2005-08-26 01:20 -0700 mpm Create a standard "hello, world" program</code></pre> </div> </div> <div class="paragraph"> <p>Зверніть увагу на нову мітку <code>[featureA]</code> у п’ятій ревізії. Це працює так само, як гілки в Git, але з одним винятком: ви не можете видаляти закладки в Git (це обмеження помічників протоколу).</p> </div> <div class="paragraph"> <p>Ви можете працювати і з "повноцінними" Mercurial-гілками: просто розмістіть гілку в просторі імен <code>branches</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b branches/permanent Switched to a new branch 'branches/permanent' $ vi Makefile $ git commit -am 'A permanent change' $ git push origin branches/permanent To hg::/tmp/hello * [new branch] branches/permanent -> branches/permanent</code></pre> </div> </div> <div class="paragraph"> <p>Ось як це виглядає в Mercurial:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ hg branches permanent 7:a4529d07aad4 develop 6:8f65e5e02793 default 5:bd5ac26f11f9 (inactive) $ hg log -G o changeset: 7:a4529d07aad4 | branch: permanent | tag: tip | parent: 5:bd5ac26f11f9 | user: Ben Straub <ben@straub.cc> | date: Thu Aug 14 20:21:09 2014 -0700 | summary: A permanent change | | @ changeset: 6:8f65e5e02793 |/ branch: develop | user: Ben Straub <ben@straub.cc> | date: Thu Aug 14 20:06:38 2014 -0700 | summary: More documentation | o changeset: 5:bd5ac26f11f9 |\ bookmark: featureA | | parent: 4:0434aaa6b91f | | parent: 2:f098c7f45c4f | | user: Ben Straub <ben@straub.cc> | | date: Thu Aug 14 20:02:21 2014 -0700 | | summary: Merge remote-tracking branch 'origin/master' [...]</code></pre> </div> </div> <div class="paragraph"> <p>Ім’я гілки "permanent" було записано разом зі змінами під номером <em>7</em>.</p> </div> <div class="paragraph"> <p>З боку Git, робота з обома видами гілок однакова: просто переходите на гілку, робите коміт, отримуєте зміни, робите злиття і надсилаєте зміни (checkout, commit, fetch, merge, pull, і push) як завжди. Ще одна річ, про яку вам потрібно знати: Mercurial не підтримує перезапис історії, лише додавання. Ось як наш Mercurial-репозиторій виглядає після інтерактивної зміни історії та примусового надсилання змін:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ hg log --style compact -G o 10[tip] 99611176cbc9 2014-08-14 20:21 -0700 ben | A permanent change | o 9 f23e12f939c3 2014-08-14 20:01 -0700 ben | Add some documentation | o 8:1 c16971d33922 2014-08-14 20:00 -0700 ben | goodbye | | o 7:5 a4529d07aad4 2014-08-14 20:21 -0700 ben | | A permanent change | | | | @ 6 8f65e5e02793 2014-08-14 20:06 -0700 ben | |/ More documentation | | | o 5[featureA]:4,2 bd5ac26f11f9 2014-08-14 20:02 -0700 ben | |\ Merge remote-tracking branch 'origin/master' | | | | | o 4 0434aaa6b91f 2014-08-14 20:01 -0700 ben | | | update makefile | | | +---o 3:1 318914536c86 2014-08-14 20:00 -0700 ben | | goodbye | | | o 2 f098c7f45c4f 2014-08-14 20:01 -0700 ben |/ Add some documentation | o 1 82e55d328c8c 2005-08-26 01:21 -0700 mpm | Create a makefile | o 0 0a04b987be5a 2005-08-26 01:20 -0700 mpm Create a standard "hello, world" program</code></pre> </div> </div> <div class="paragraph"> <p>Були створені зміни <em>8</em>, <em>9</em> та <em>10</em> і тепер вони належать до гілки <code>permanent</code>, але старі зміни досі там. Це може <strong>дуже</strong> спантеличити ваших колег, які використовують Mercurial, тому краще уникати цього.</p> </div> </div> <div class="sect4"> <h4 id="_підсумок_по_mercurial">Підсумок по Mercurial</h4> <div class="paragraph"> <p>Git і Mercurial достатньо подібні для безболісної роботи один з одним. Якщо ви будете уникати змін вже опублікованої історії (що, загалом, рекомендовано), ви навіть не помітите, що працюєте в Mercurial.</p> </div> </div> </div> <div class="sect3"> <h3 id="_git_and_bazaar">Git and Bazaar</h3> <div class="paragraph"> <p>Among the DVCS, another famous one is <a href="http://bazaar.canonical.com/">Bazaar</a>. Bazaar is free and open source, and is part of the <a href="http://www.gnu.org/">GNU Project</a>. It behaves very differently from Git. Sometimes, to do the same thing as with Git, you have to use a different keyword, and some keywords that are common don’t have the same meaning. In particular, the branch management is very different and may cause confusion, especially when someone comes from Git’s universe. Nevertheless, it is possible to work on a Bazaar repository from a Git one.</p> </div> <div class="paragraph"> <p>There are many projects that allow you to use Git as a Bazaar client. Here we’ll use Felipe Contreras' project that you may find at <a href="https://github.com/felipec/git-remote-bzr" class="bare">https://github.com/felipec/git-remote-bzr</a>. To install it, you just have to download the file git-remote-bzr in a folder contained in your <code>$PATH</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ wget https://raw.github.com/felipec/git-remote-bzr/master/git-remote-bzr -O ~/bin/git-remote-bzr $ chmod +x ~/bin/git-remote-bzr</code></pre> </div> </div> <div class="paragraph"> <p>You also need to have Bazaar installed. That’s all!</p> </div> <div class="sect4"> <h4 id="_create_a_git_repository_from_a_bazaar_repository">Create a Git repository from a Bazaar repository</h4> <div class="paragraph"> <p>It is simple to use. It is enough to clone a Bazaar repository prefixing it by <code>bzr::</code>. Since Git and Bazaar both do full clones to your machine, it’s possible to attach a Git clone to your local Bazaar clone, but it isn’t recommended. It’s much easier to attach your Git clone directly to the same place your Bazaar clone is attached to ‒ the central repository.</p> </div> <div class="paragraph"> <p>Let’s suppose that you worked with a remote repository which is at address <code>bzr+ssh://developer@mybazaarserver:myproject</code>. Then you must clone it in the following way:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone bzr::bzr+ssh://developer@mybazaarserver:myproject myProject-Git $ cd myProject-Git</code></pre> </div> </div> <div class="paragraph"> <p>At this point, your Git repository is created but it is not compacted for optimal disk use. That’s why you should also clean and compact your Git repository, especially if it is a big one:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git gc --aggressive</code></pre> </div> </div> </div> <div class="sect4"> <h4 id="_bazaar_branches">Bazaar branches</h4> <div class="paragraph"> <p>Bazaar only allows you to clone branches, but a repository may contain several branches, and <code>git-remote-bzr</code> can clone both. For example, to clone a branch:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone bzr::bzr://bzr.savannah.gnu.org/emacs/trunk emacs-trunk</code></pre> </div> </div> <div class="paragraph"> <p>And to clone the whole repository:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone bzr::bzr://bzr.savannah.gnu.org/emacs emacs</code></pre> </div> </div> <div class="paragraph"> <p>The second command clones all the branches contained in the emacs repository; nevertheless, it is possible to point out some branches:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git config remote-bzr.branches 'trunk, xwindow'</code></pre> </div> </div> <div class="paragraph"> <p>Some remote repositories don’t allow you to list their branches, in which case you have to manually specify them, and even though you could specify the configuration in the cloning command, you may find this easier:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git init emacs $ git remote add origin bzr::bzr://bzr.savannah.gnu.org/emacs $ git config remote-bzr.branches 'trunk, xwindow' $ git fetch</code></pre> </div> </div> </div> <div class="sect4"> <h4 id="_ignore_what_is_ignored_with_bzrignore">Ignore what is ignored with .bzrignore</h4> <div class="paragraph"> <p>Since you are working on a project managed with Bazaar, you shouldn’t create a <code>.gitignore</code> file because you <em>may</em> accidentally set it under version control and the other people working with Bazaar would be disturbed. The solution is to create the <code>.git/info/exclude</code> file either as a symbolic link or as a regular file. We’ll see later on how to solve this question.</p> </div> <div class="paragraph"> <p>Bazaar uses the same model as Git to ignore files, but also has two features which don’t have an equivalent into Git. The complete description may be found in <a href="http://doc.bazaar.canonical.com/bzr.2.7/en/user-reference/ignore-help.html">the documentation</a>. The two features are:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>"!!" allows you to ignore certain file patterns even if they’re specified using a "!" rule.</p> </li> <li> <p>"RE:" at the beginning of a line allows you to specify a <a href="https://docs.python.org/3/library/re.html">Python regular expression</a> (Git only allows shell globs).</p> </li> </ol> </div> <div class="paragraph"> <p>As a consequence, there are two different situations to consider:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>If the <code>.bzrignore</code> file does not contain any of these two specific prefixes, then you can simply make a symbolic link to it in the repository: <code>ln -s .bzrignore .git/info/exclude</code></p> </li> <li> <p>Otherwise, you must create the <code>.git/info/exclude</code> file and adapt it to ignore exactly the same files in <code>.bzrignore</code>.</p> </li> </ol> </div> <div class="paragraph"> <p>Whatever the case is, you will have to remain vigilant against any change of <code>.bzrignore</code> to make sure that the <code>.git/info/exclude</code> file always reflects <code>.bzrignore</code>. Indeed, if the <code>.bzrignore</code> file were to change and contained one or more lines starting with "!!" or "RE:", Git not being able to interpret these lines, you’ll have to adapt your <code>.git/info/exclude</code> file to ignore the same files as the ones ignored with <code>.bzrignore</code>. Moreover, if the <code>.git/info/exclude</code> file was a symbolic link, you’ll have to first delete the symbolic link, copy <code>.bzrignore</code> to <code>.git/info/exclude</code> and then adapt the latter. However, be careful with its creation because with Git it is impossible to re-include a file if a parent directory of that file is excluded.</p> </div> </div> <div class="sect4"> <h4 id="_fetch_the_changes_of_the_remote_repository">Fetch the changes of the remote repository</h4> <div class="paragraph"> <p>To fetch the changes of the remote, you pull changes as usually, using Git commands. Supposing that your changes are on the <code>master</code> branch, you merge or rebase your work on the <code>origin/master</code> branch:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git pull --rebase origin</code></pre> </div> </div> </div> <div class="sect4"> <h4 id="_push_your_work_on_the_remote_repository">Push your work on the remote repository</h4> <div class="paragraph"> <p>Because Bazaar also has the concept of merge commits, there will be no problem if you push a merge commit. So you can work on a branch, merge the changes into <code>master</code> and push your work. Then, you create your branches, you test and commit your work as usual. You finally push your work to the Bazaar repository:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push origin master</code></pre> </div> </div> </div> <div class="sect4"> <h4 id="_caveats">Caveats</h4> <div class="paragraph"> <p>Git’s remote-helpers framework has some limitations that apply. In particular, these commands don’t work:</p> </div> <div class="ulist"> <ul> <li> <p>git push origin :branch-to-delete (Bazaar can’t accept ref deletions in this way.)</p> </li> <li> <p>git push origin old:new (it will push 'old')</p> </li> <li> <p>git push --dry-run origin branch (it will push)</p> </li> </ul> </div> </div> <div class="sect4"> <h4 id="_summary">Summary</h4> <div class="paragraph"> <p>Since Git’s and Bazaar’s models are similar, there isn’t a lot of resistance when working across the boundary. As long as you watch out for the limitations, and are always aware that the remote repository isn’t natively Git, you’ll be fine.</p> </div> </div> </div> <div class="sect3"> <h3 id="_git_і_perforce">Git і Perforce</h3> <div class="paragraph"> <p> Perforce — дуже популярна система контролю версій у корпоративному середовищі. Він з’явився у 1995 році, що робить його найстарішою системою контролю версій з тих, що розглядаються у цьому розділі. Perforce розроблений з обмеженнями тих часів; він передбачає постійне з’єднання з центральним сервером, а локально зберігається лише одна версія файлів. Насправді, його можливості та обмеження добре підходять для вирішення специфічного кола задач, та існує досить багато проектів, які використовують Perforce, але де Git працював би значно краще.</p> </div> <div class="paragraph"> <p>Існують два варіанти сумісного використання Perforce і Git. Перший, який ми розглянемо, — міст ``Git Fusion'' від розробників Perforce, який дозволить вам виставляти піддерева (subtrees) вашого Perforce-депо (Perforce depot) як Git репозиторії з можливістю читання-запису. Другий — git-p4 — клієнтський міст, який дозволяє вам використовувати Git як клієнт Perforce без необхідності здійснювати будь-яке переналаштування сервера Perforce.</p> </div> <div class="sect4"> <h4 id="_p4_git_fusion">Git Fusion</h4> <div class="paragraph"> <p> Perforce забезпечує продукт, який називається Git Fusion (доступний за посиланням <a href="http://www.perforce.com/git-fusion" class="bare">http://www.perforce.com/git-fusion</a>), і синхронізує сервер Perforce з репозиторієм Git на стороні сервера.</p> </div> <div class="sect5"> <h6 id="_налаштування_2">Налаштування</h6> <div class="paragraph"> <p>Для наших прикладів ми використаємо найпростіший метод встановлення Git Fusion, який полягає у завантаженні віртуальної машини, на якій виконується Perforce демон і Git Fusion. Ви можете отримати образ віртуальної машини за посиланням <a href="http://www.perforce.com/downloads/Perforce/20-User" class="bare">http://www.perforce.com/downloads/Perforce/20-User</a>, і коли завантаження буде завершено, імпортувати його у ваше улюблене програмне забезпечення для віртуалізації (ми використаємо VirtualBox).</p> </div> <div class="paragraph"> <p>Під час першого запуску віртуальної машини вам потрібно налаштувати паролі для трьох Linux-користувачів (<code>root</code>, <code>perforce</code> та <code>git</code>) і ввести ім’я хоста, яке буде відрізняти це встановлення від інших в одній мережі. Коли все буде готово, ви побачите наступне:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/uk/v2/images/git-fusion-boot.png" alt="Екран віртуальної машини Git Fusion."> </div> <div class="title">Рисунок 145. Екран віртуальної машини Git Fusion.</div> </div> <div class="paragraph"> <p>Вам потрібно занотувати цю IP адресу, пізніше ми будемо її використовувати. Далі ми створимо користувача Perforce. Виберіть знизу опцію <code>`Login'' та натисніть `Enter</code> (або скористайтесь SSH), і увійдіть як <code>root</code>. Потім використайте ці команди для створення користувача:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ p4 -p localhost:1666 -u super user -f john $ p4 -p localhost:1666 -u john passwd $ exit</code></pre> </div> </div> <div class="paragraph"> <p>Перша команда відкриє редактор VI для редагування користувача, але ви можете прийняти типові налаштування і ввести <code>:wq</code> та натиснути <code>Enter</code>. Друга команда двічі попросить вас ввести пароль. Це все, що нам потрібно виконати в оболонці системи, тому завершіть поточну сесію.</p> </div> <div class="paragraph"> <p>Наступне, що вам потрібно зробити, це заборонити Git перевіряти SSL сертифікати. Образ Git Fusion розповсюджується з сертифікатом, але він для домену, що не відповідає IP адресі вашої віртуальної машини, тому Git відхилить HTTPS-з’єднання. Якщо це встановлення буде використовуватись на постійній основі, зверніться до документації Git Fusion, щоб встановити інший сертифікат; а для нашої навчальної мети підійде наступне:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ export GIT_SSL_NO_VERIFY=true</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://10.0.1.254/Talkhouse Cloning into 'Talkhouse'... Username for 'https://10.0.1.254': john Password for 'https://john@10.0.1.254': remote: Counting objects: 630, done. remote: Compressing objects: 100% (581/581), done. remote: Total 630 (delta 172), reused 0 (delta 0) Receiving objects: 100% (630/630), 1.22 MiB | 0 bytes/s, done. Resolving deltas: 100% (172/172), done. Checking connectivity... done.</code></pre> </div> </div> <div class="paragraph"> <p>Образ віртуальної машини розповсюджується з тестовим проектом, який ви можете клонувати. Тут ми клонуємо проект через HTTPS-з’єднання, з користувачем <code>john</code>, якого ми створили вище; Git запитає пароль для цього з’єднання, але кеш паролів дозволить нам пропускати цей крок для будь-яких наступних запитів.</p> </div> </div> <div class="sect5"> <h6 id="_налаштування_fusion">Налаштування Fusion</h6> <div class="paragraph"> <p>Після встановлення Git Fusion ви, мабуть, захочете налаштувати його. Насправді, це відносно легко зробити з використанням вашого улюбленого клієнта Perforce; просто відобразіть директорію <code>//.git-fusion</code> на сервері Perforce у ваш робочий простір. Структура файлів повинна бути подібною до:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ tree . ├── objects │ ├── repos │ │ └── [...] │ └── trees │ └── [...] │ ├── p4gf_config ├── repos │ └── Talkhouse │ └── p4gf_config └── users └── p4gf_usermap 498 directories, 287 files</code></pre> </div> </div> <div class="paragraph"> <p>Директорія <code>objects</code> використовується Git Fusion для відображення об’єктів Perforce у об’єкти Git і навпаки, вам не варто тут нічого змінювати. Всередині цієї директорії знаходиться глобальний файл <code>p4gf_config</code>, а також по одному для кожного репозиторія - це файли конфігурації, які визначають поведінку Git Fusion. Погляньмо на файл, що знаходиться в корені:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-ini" data-lang="ini">[repo-creation] charset = utf8 [git-to-perforce] change-owner = author enable-git-branch-creation = yes enable-swarm-reviews = yes enable-git-merge-commits = yes enable-git-submodules = yes preflight-commit = none ignore-author-permissions = no read-permission-check = none git-merge-avoidance-after-change-num = 12107 [perforce-to-git] http-url = none ssh-url = none [@features] imports = False chunked-push = False matrix2 = False parallel-push = False [authentication] email-case-sensitivity = no</code></pre> </div> </div> <div class="paragraph"> <p>Ми не будемо детально розглядати ці опції, але зверніть увагу на те, що це звичайний INI-файл, подібний до файлів конфігурації, які використовує Git. Цей файл задає глобальні опції, які можуть бути перевизначені специфічними для кожного репозиторія файлами конфігурації, такими, як <code>repos/Talkhouse/p4gf_config</code>. Якщо ви відкриєте цей файл, то побачите секцію <code>[@repo]</code> з деякими налаштуваннями, які відрізняються від типових глобальних налаштувань. Ви також побачите секції, які виглядають подібно до цього:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-ini" data-lang="ini">[Talkhouse-master] git-branch-name = master view = //depot/Talkhouse/main-dev/... ...</code></pre> </div> </div> <div class="paragraph"> <p>Вони задають відповідність між гілками Perforce та гілками Git. Назви таких секцій можуть бути довільними, поки ці назви залишаються унікальними. Команда <code>git-branch-name</code> дозволяє вам конвертувати недоладний для Git шлях всередині депо, щоб у Git мати більш дружелюбне ім’я. Параметр <code>view</code> керує відображенням файлів Perforce у репозиторії Git з використанням стандартного синтаксису відображення видів. Більш ніж одне відображення можна визначити як у прикладі нижче:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-ini" data-lang="ini">[multi-project-mapping] git-branch-name = master view = //depot/project1/main/... project1/... //depot/project2/mainline/... project2/...</code></pre> </div> </div> <div class="paragraph"> <p>Таким чином, якщо ваше нормальне відображення включає зміни структури директорій, ви можете відтворити це за допомогою Git-репозиторія.</p> </div> <div class="paragraph"> <p>Останній файл, про який ми поговоримо, це <code>users/p4gf_usermap</code>, який відображає користувачів Perforce у користувачів Git, і який, можливо, вам і не знадобиться.</p> </div> <div class="paragraph"> <p>Коли Perforce конвертує набір змін (changeset) у Git коміт, типова поведінка Git Fusion — пошук користувача Perforce і використання адреси його електронної пошти та повного імені для заповнення поля "автор коміту" в Git. При конвертуванні у зворотному напрямку, типова поведінка — пошук користувача Perforce з адресою електронної пошти в полі "автор коміту" у Git, та застосовує набір змін від імені цього користувача (з використанням прав доступу). У більшості випадків така поведінка є нормальною, але розгляньмо наступний файл відповідностей:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code>john john@example.com "John Doe" john johnny@appleseed.net "John Doe" bob employeeX@example.com "Anon X. Mouse" joe employeeY@example.com "Anon Y. Mouse"</code></pre> </div> </div> <div class="paragraph"> <p>Кожний рядок має формат <code><user> <email> "<full name>"</code> і створює відповідність для одного користувача. Перші два рядки відображають дві різні адреси електронної пошти для одного користувача Perforce. Це може бути корисним, якщо ви створили коміти у Git з різних адрес електронної пошти (або змінили свою електронну пошту), але хочете їх відобразити на одного й того ж користувача Perforce. При створенні комітів у Git з набору змін Perforce, перший рядок, який відповідає користувачу Perforce, використовується Git як інформація про авторство.</p> </div> <div class="paragraph"> <p>Останні два рядки маскують справжні імена та адреси електронної пошти Боба і Джо у комітах Git при їх створенні. Це корисно, якщо ви хочете вивести ваш внутрішній проект в open-source, але не хочете публікувати свій каталог співробітників для всього світу. Зауважте, що адреси електронної пошти і повні імена повинні бути унікальними, якщо ви не хочете, щоб всі коміти Git належали одному фіктивному автору.</p> </div> </div> <div class="sect5"> <h6 id="_робочий_процес_3">Робочий процес</h6> <div class="paragraph"> <p>Perforce Git Fusion — це двосторонній міст між системами контролю версій Perforce і Git. Погляньмо, як виглядає робота з боку Git. Нехай ми налаштували відображення проекту ``Jam'' з використанням файла конфігурації, як показано вище, який ми можемо клонувати таким чином:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone https://10.0.1.254/Jam Cloning into 'Jam'... Username for 'https://10.0.1.254': john Password for 'https://john@10.0.1.254': remote: Counting objects: 2070, done. remote: Compressing objects: 100% (1704/1704), done. Receiving objects: 100% (2070/2070), 1.21 MiB | 0 bytes/s, done. remote: Total 2070 (delta 1242), reused 0 (delta 0) Resolving deltas: 100% (1242/1242), done. Checking connectivity... done. $ git branch -a * master remotes/origin/HEAD -> origin/master remotes/origin/master remotes/origin/rel2.1 $ git log --oneline --decorate --graph --all * 0a38c33 (origin/rel2.1) Create Jam 2.1 release branch. | * d254865 (HEAD, origin/master, origin/HEAD, master) Upgrade to latest metrowerks on Beos -- the Intel one. | * bd2f54a Put in fix for jam's NT handle leak. | * c0f29e7 Fix URL in a jam doc | * cc644ac Radstone's lynx port. [...]</code></pre> </div> </div> <div class="paragraph"> <p>Якщо ви робите клонування вперше, це може тривати деякий час. При цьому Git Fusion конвертує усі можливі набори змін з історії Perforce у коміти Git. Це відбувається локально на сервері, тому ця операція здійснюється відносно швидко, але якщо у вас багато історії, цей процес триватиме деякий час. Наступні отримання змін вимагають лише інкрементних перетворень, таким чином, швидкість роботи буде порівняна зі швидкістю роботи з Git.</p> </div> <div class="paragraph"> <p>Як ви бачите, наш репозиторій виглядає як і будь-який інший Git-репозиторій, з яким ви могли працювати. Тут є три гілки і Git доречно створив локальну гілку <code>master</code>, яка відслідковує <code>origin/master</code>. Попрацюймо трохи і створімо кілька нових комітів:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># ... $ git log --oneline --decorate --graph --all * cfd46ab (HEAD, master) Add documentation for new feature * a730d77 Whitespace * d254865 (origin/master, origin/HEAD) Upgrade to latest metrowerks on Beos -- the Intel one. * bd2f54a Put in fix for jam's NT handle leak. [...]</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 fetch remote: Counting objects: 5, done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 2), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From https://10.0.1.254/Jam d254865..6afeb15 master -> origin/master $ git log --oneline --decorate --graph --all * 6afeb15 (origin/master, origin/HEAD) Update copyright | * cfd46ab (HEAD, master) Add documentation for new feature | * a730d77 Whitespace |/ * d254865 Upgrade to latest metrowerks on Beos -- the Intel one. * bd2f54a Put in fix for jam's NT handle leak. [...]</code></pre> </div> </div> <div class="paragraph"> <p>Схоже, хтось таки вносив! Ви не дізнаєтесь цього з виводу команди <code>git fetch</code>, але коміт <code>6afeb15</code> був створений за допомогою клієнта Perforce. Він виглядає як інший звичайний коміт з точки зору Git, для чого й створений Git Fusion. Погляньмо, як сервер Perforce працює з комітом злиття:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git merge origin/master Auto-merging README Merge made by the 'recursive' strategy. README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) $ git push Counting objects: 9, done. Delta compression using up to 8 threads. Compressing objects: 100% (9/9), done. Writing objects: 100% (9/9), 917 bytes | 0 bytes/s, done. Total 9 (delta 6), reused 0 (delta 0) remote: Perforce: 100% (3/3) Loading commit tree into memory... remote: Perforce: 100% (5/5) Finding child commits... remote: Perforce: Running git fast-export... remote: Perforce: 100% (3/3) Checking commits... remote: Processing will continue even if connection is closed. remote: Perforce: 100% (3/3) Copying changelists... remote: Perforce: Submitting new Git commit objects to Perforce: 4 To https://10.0.1.254/Jam 6afeb15..89cba2b master -> master</code></pre> </div> </div> <div class="paragraph"> <p>З боку Git це працює. Погляньмо на історію файла <code>README</code> з боку Perforce, скориставшись графом ревізій <code>p4v</code>:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/uk/v2/images/git-fusion-perforce-graph.png" alt="Граф ревізій Perforce після надсилання даних з Git."> </div> <div class="title">Рисунок 146. Граф ревізій Perforce після надсилання даних з Git.</div> </div> <div class="paragraph"> <p>Якщо ви ніколи такого не бачили, це може вас спантеличити, але його концепція схожа з графічним переглядачем для історії Git. Ми дивимось на історію файла <code>README</code>, тому дерево директорії ліворуч вгорі показує лише цей файл, коли він змінюється в різноманітних гілках. Праворуч вгорі ми бачимо візуалізацію залежностей різних версій файла і повну версію цього графу внизу праворуч. Решта вікна залишена для детального відображення вибраної ревізії (у цьому випадку, другої).</p> </div> <div class="paragraph"> <p>Одна річ, яку потрібно зауважити, граф виглядає так само, як і в історії Git. У Perforce не було іменованої гілки для зберігання комітів <code>1</code> і <code>2</code>, тому він створив <code>`анонімну'' гілку в директорії `.git-fusion</code> для їх збереження. Perforce буде діяти схожим чином і з іменованими гілками Git, які не відповідають іменам гілок Perforce (але ви можете задати для них відповідності у файлі конфігурації Perforce).</p> </div> <div class="paragraph"> <p>Більшість з цього відбувається всередині Git Fusion, але в результаті один член команди може користуватися Git, а інший — Perforce, і жоден з них не буде знати про вибір іншого.</p> </div> </div> <div class="sect5"> <h6 id="_підсумок_по_git_fusion">Підсумок по Git-Fusion</h6> <div class="paragraph"> <p>Якщо у вас є (або ви можете отримати) доступ до вашого сервера Perforce, Git Fusion стане чудовим способом налагодження співпраці між Git та Perforce. Звичайно, для цього потрібно налаштувати конфігурацію, але загалом цей процес не є занадто складним. Це одна з небагатьох секцій цього розділу, де не з’являлись попередження про використання всього функціоналу Git. Але це не означає, що Perforce зможе виконати все, що ви захочете - якщо ви спробуєте перезаписати історію, яка вже надіслана на сервер, Git Fusion відхилить такі зміни - але Git Fusion намагається зробити все можливе, щоб ви не відчували незручностей. Ви можете навіть використовувати підмодулі Git (хоча вони й будуть виглядати дивно для користувачів Perforce), і зливати гілки (з боку Perforce це буде виглядати як інтеграція).</p> </div> <div class="paragraph"> <p>Якщо ви не зможете вмовити адміністратора вашого серверу налаштувати Git Fusion, все одно існує спосіб використання цих інструментів разом.</p> </div> </div> </div> <div class="sect4"> <h4 id="_git_p4_client">Git-p4</h4> <div class="paragraph"> <p> Git-p4 — це двосторонній міст між Git та Perforce. Він працює повністю всередині вашого репозиторія Git, тому вам взагалі не потрібно мати доступ до сервера Perforce (звичайно, вам знадобляться логін і пароль). Git-p4 не такий гнучкий та функціональний, як Git Fusion, але він дозволяє здійснювати більшість з того, що вам буде необхідно, без втручання у середовище сервера.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">Зауваження</div> </td> <td class="content"> <div class="paragraph"> <p>Для роботи з git-p4 вам знадобиться виконуваний файл <code>p4</code>, доступний у вашому <code>PATH</code>. На момент написання книги, він вільно доступний за посиланням <a href="http://www.perforce.com/downloads/Perforce/20-User" class="bare">http://www.perforce.com/downloads/Perforce/20-User</a>.</p> </div> </td> </tr> </table> </div> <div class="sect5"> <h6 id="_налаштування_3">Налаштування</h6> <div class="paragraph"> <p>Для навчальної мети, ми запустимо сервер Perforce з віртуальної машини Git Fusion OVA, як було показано вище, але ми будемо оминати сервер Git Fusion і напряму звертатися до системи контролю версій Perforce.</p> </div> <div class="paragraph"> <p>Для використання клієнта командного рядка <code>p4</code> (від якого залежить git-p4), вам буде потрібно прописати кілька змінних середовища:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ export P4PORT=10.0.1.254:1666 $ export P4USER=john</code></pre> </div> </div> </div> <div class="sect5"> <h6 id="_початок_роботи">Початок роботи</h6> <div class="paragraph"> <p>Як і зазвичай при роботі з Git, перша команда — клонування:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 clone //depot/www/live www-shallow Importing from //depot/www/live into www-shallow Initialized empty Git repository in /private/tmp/www-shallow/.git/ Doing initial import of //depot/www/live/ from revision #head into refs/remotes/p4/master</code></pre> </div> </div> <div class="paragraph"> <p>Ми створили те, що у термінах Git називається ``поверхнева'' (shallow) копія; лише найостанніша ревізія Perforce імпортована у Git; пам’ятайте, що Perforce не призначений віддавати кожну ревізію кожному користувачу. Цього достатньо для використання Git як клієнта Perforce, але цього недостатньо для інших задач.</p> </div> <div class="paragraph"> <p>Коли клонування завершиться, ми будемо мати повнофункціональний репозиторій Git:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cd myproject $ git log --oneline --all --graph --decorate * 70eaf78 (HEAD, p4/master, p4/HEAD, master) Initial import of //depot/www/live/ from the state at revision #head</code></pre> </div> </div> <div class="paragraph"> <p>Зверніть увагу на наявність віддаленого репозиторія ``p4'' для сервера Perforce, але все інше виглядає стандартно для клонованого репозиторія. Насправді, це нас трохи вводить в оману; виявляється, там немає ніякого віддаленого репозиторія.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git remote -v</code></pre> </div> </div> <div class="paragraph"> <p>Ніяких віддалених репозиторіїв не існує взагалі. Git-p4 створив кілька посилань для представлення стану сервера, і вони схожі на посилання віддаленого репозиторія для <code>git log</code>, але вони не обслуговуються Git і ви не можете надсилати зміни у них.</p> </div> </div> <div class="sect5"> <h6 id="_порядок_роботи">Порядок роботи</h6> <div class="paragraph"> <p>Отже, почнімо працювати. Припустимо, ви виконали певний обсяг роботи по дуже важливій задачі, і ви готові показати свою роботу решті команди.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git log --oneline --all --graph --decorate * 018467c (HEAD, master) Change page title * c0fb617 Update link * 70eaf78 (p4/master, p4/HEAD) Initial import of //depot/www/live/ from the state at revision #head</code></pre> </div> </div> <div class="paragraph"> <p>Ми зробити два нових коміти, які вже готові до відправлення на сервер Perforce. Погляньмо, чи хтось інший сьогодні робив зміни:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 sync git p4 sync Performing incremental import into refs/remotes/p4/master git branch Depot paths: //depot/www/live/ Import destination: refs/remotes/p4/master Importing revision 12142 (100%) $ git log --oneline --all --graph --decorate * 75cd059 (p4/master, p4/HEAD) Update copyright | * 018467c (HEAD, master) Change page title | * c0fb617 Update link |/ * 70eaf78 Initial import of //depot/www/live/ from the state at revision #head</code></pre> </div> </div> <div class="paragraph"> <p>Схоже, що так, і гілки <code>master</code> та <code>p4/master</code> розійшлися. Система галудження Perforce <em>абсолютно</em> не схожа на Git, тому відправлення комітів злиття не має жодного сенсу. Git-p4 рекомендує перебазувати ваші коміти, і навіть надає спеціальну команду для цього:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 rebase Performing incremental import into refs/remotes/p4/master git branch Depot paths: //depot/www/live/ No changes to import! Rebasing the current branch onto remotes/p4/master First, rewinding head to replay your work on top of it... Applying: Update link Applying: Change page title index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)</code></pre> </div> </div> <div class="paragraph"> <p>Ви, можливо, скажете, що <code>git p4 rebase</code> — це лише скорочення для <code>git p4 sync</code> з наступним <code>git rebase p4/master</code>. Насправді, ця команда трохи розумніша, особливо при роботі з багатьма гілками, але це вірна здогадка.</p> </div> <div class="paragraph"> <p>Тепер наша історія змін знову лінійна, і ми готові надіслати наші зміни до Perforce. Команда <code>git p4 submit</code> буде намагатися створити нову ревізію Perforce для кожного коміту Git між <code>p4/master</code> і <code>master</code>. Її запуск відкриє ваш улюблений редактор, і вміст файлу буде схожим на це:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># A Perforce Change Specification. # # Change: The change number. 'new' on a new changelist. # Date: The date this specification was last modified. # Client: The client on which the changelist was created. Read-only. # User: The user who created the changelist. # Status: Either 'pending' or 'submitted'. Read-only. # Type: Either 'public' or 'restricted'. Default is 'public'. # Description: Comments about the changelist. Required. # Jobs: What opened jobs are to be closed by this changelist. # You may delete jobs from this list. (New changelists only.) # Files: What opened files from the default changelist are to be added # to this changelist. You may delete files from this list. # (New changelists only.) Change: new Client: john_bens-mbp_8487 User: john Status: new Description: Update link Files: //depot/www/live/index.html # edit ######## git author ben@straub.cc does not match your p4 account. ######## Use option --preserve-user to modify authorship. ######## Variable git-p4.skipUserNameCheck hides this message. ######## everything below this line is just the diff ####### --- //depot/www/live/index.html 2014-08-31 18:26:05.000000000 0000 +++ /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/index.html 2014-08-31 18:26:05.000000000 0000 @@ -60,7 +60,7 @@ </td> <td valign=top> Source and documentation for -<a href="http://www.perforce.com/jam/jam.html"> +<a href="jam.html"> Jam/MR</a>, a software build tool. </td></code></pre> </div> </div> <div class="paragraph"> <p>Це практично ті ж самі дані, які б ви побачили, запустивши <code>p4 submit</code>, за винятком кількох рядків у кінці, які були доречно додані git-p4. Git-p4 намагається враховувати ваші індивідуальні налаштування для Git і Perforce, коли потрібно надати ім’я для коміту або набору змін, але у деяких випадках ви захочете змінити їх. Наприклад, якщо коміт Git, який ви імпортуєте, був створений користувачем, який не має облікового запису Perforce, можливо, ви все одно захочете, щоб кінцевий набір змін виглядав так, ніби він був створений тим користувачем (а не вами).</p> </div> <div class="paragraph"> <p>Git-p4 доречно імпортував повідомлення з коміту Git як вміст для набору змін Perforce, тому все, що нам потрібно зробити, це зберегти і вийти, двічі (по одному разу для кожного коміту). У результаті, вивід командного рядка буде виглядати так:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 submit Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/ Synchronizing p4 checkout... ... - file(s) up-to-date. Applying dbac45b Update link //depot/www/live/index.html#4 - opened for edit Change 12143 created with 1 open file(s). Submitting change 12143. Locking 1 files ... edit //depot/www/live/index.html#5 Change 12143 submitted. Applying 905ec6a Change page title //depot/www/live/index.html#5 - opened for edit Change 12144 created with 1 open file(s). Submitting change 12144. Locking 1 files ... edit //depot/www/live/index.html#6 Change 12144 submitted. All commits applied! Performing incremental import into refs/remotes/p4/master git branch Depot paths: //depot/www/live/ Import destination: refs/remotes/p4/master Importing revision 12144 (100%) Rebasing the current branch onto remotes/p4/master First, rewinding head to replay your work on top of it... $ git log --oneline --all --graph --decorate * 775a46f (HEAD, p4/master, p4/HEAD, master) Change page title * 05f1ade Update link * 75cd059 Update copyright * 70eaf78 Initial import of //depot/www/live/ from the state at revision #head</code></pre> </div> </div> <div class="paragraph"> <p>Результат виглядає так, ніби ми щойно виконали <code>git push</code>, і це дуже близько до того, що насправді відбулося.</p> </div> <div class="paragraph"> <p>Зверніть увагу, що під час цього процесу кожен коміт Git перетворюється у набір змін Perforce; якщо ви хочете зварити їх (squash) в один набір змін, ви можете скористатися інтерактивним перебазуванням перед запуском <code>git p4 submit</code>. Також зазначте, що хеші SHA-1 усіх комітів, перетворених у набори змін, також змінилися; це сталося тому, що git-p4 додає рядок у кінець кожного коміту, який конвертує:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git log -1 commit 775a46f630d8b46535fc9983cf3ebe6b9aa53145 Author: John Doe <john@example.com> Date: Sun Aug 31 10:31:44 2014 -0800 Change page title [git-p4: depot-paths = "//depot/www/live/": change = 12144]</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 log --oneline --all --graph --decorate * 3be6fd8 (HEAD, master) Correct email address * 1dcbf21 Merge remote-tracking branch 'p4/master' |\ | * c4689fc (p4/master, p4/HEAD) Grammar fix * | cbacd0a Table borders: yes please * | b4959b6 Trademark |/ * 775a46f Change page title * 05f1ade Update link * 75cd059 Update copyright * 70eaf78 Initial import of //depot/www/live/ from the state at revision #head</code></pre> </div> </div> <div class="paragraph"> <p>Історія змін Git розійшлась з історією Perforce після <code>775a46f</code>. У Git є два коміти, потім коміт злиття з Perforce, а потім інший коміт. Ми спробуємо надіслати це у набір змін на боці Perforce. Погляньмо, що трапиться, якщо ми спробуємо надіслати зараз:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 submit -n Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/ Would synchronize p4 checkout in /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/ Would apply b4959b6 Trademark cbacd0a Table borders: yes please 3be6fd8 Correct email address</code></pre> </div> </div> <div class="paragraph"> <p>Прапорець <code>-n</code> — це скорочення для <code>--dry-run</code>, який намагається повідомити, що б сталося, якби б відправлення відбулось насправді. У цьому випадку, схоже, ми створили три набори змін Perforce, які відповідають трьом звичайним комітам (крім коміту злиття), які ще не існують на сервері Perforce. Це звучить саме так, як ми й хотіли, погляньмо на вивід:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 submit […] $ git log --oneline --all --graph --decorate * dadbd89 (HEAD, p4/master, p4/HEAD, master) Correct email address * 1b79a80 Table borders: yes please * 0097235 Trademark * c4689fc Grammar fix * 775a46f Change page title * 05f1ade Update link * 75cd059 Update copyright * 70eaf78 Initial import of //depot/www/live/ from the state at revision #head</code></pre> </div> </div> <div class="paragraph"> <p>Наша історія змін стала лінійною, ніби ми перебазувалися перед відправленням (що насправді й відбулося). Це означає, що ви можете вільно створювати, працювати, викидати, і зливати гілки на стороні Git без страху, що ваша історія змін якимось чином стане несумісною з Perforce. Якщо ви можете перебазувати зміни, ви можете відправити їх на сервер Perforce.</p> </div> </div> <div class="sect5"> <h6 id="_git_p4_branches">Галуження</h6> <div class="paragraph"> <p>Якщо ваш проект Perforce має декілька гілок, не турбуйтеся; git-p4 може впоратися з цим так, що ви не відчуєте різниці у порівнянні з Git. Припустімо, ваш репозиторій Perforce має таку структуру:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code>//depot └── project ├── main └── dev</code></pre> </div> </div> <div class="paragraph"> <p>І нехай ви маєте гілку <code>dev</code>, яка налаштована наступним чином:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code>//depot/project/main/... //depot/project/dev/...</code></pre> </div> </div> <div class="paragraph"> <p>Git-p4 може автоматично виявляти такі ситуації і виконувати потрібні дії:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git p4 clone --detect-branches //depot/project@all Importing from //depot/project@all into project Initialized empty Git repository in /private/tmp/project/.git/ Importing revision 20 (50%) Importing new branch project/dev Resuming with change 20 Importing revision 22 (100%) Updated branches: main dev $ cd project; git log --oneline --all --graph --decorate * eae77ae (HEAD, p4/master, p4/HEAD, master) main | * 10d55fb (p4/project/dev) dev | * a43cfae Populate //depot/project/main/... //depot/project/dev/.... |/ * 2b83451 Project init</code></pre> </div> </div> <div class="paragraph"> <p>Зверніть увагу на ``@all'' в шляху; це говорить git-p4 клонувати не лише останній набір змін для цього піддерева, а й усі набори змін, яких стосуються ці шляхи. Це ближче до концепції клонування Git, але якщо ви працюєте над проектом з довгою історією, це може зайняти деякий час.</p> </div> <div class="paragraph"> <p>Прапорець <code>--detect-branches</code> говорить git-p4 використовувати налаштування гілок Perforce для відображення на посилання Git. Якщо таких відображень на сервері Perforce немає (що цілком коректно для Perforce), ви можете вказати git-p4 ці гілки вручну, і отримаєте такий самий результат:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git init project Initialized empty Git repository in /tmp/project/.git/ $ cd project $ git config git-p4.branchList main:dev $ git clone --detect-branches //depot/project@all .</code></pre> </div> </div> <div class="paragraph"> <p>Задавши конфігураційну змінну <code>git-p4.branchList</code> рівною <code>main:dev</code>, ми говоримо git-p4, що і <code>main'' і </code>dev'' є гілками, а друга є нащадком першої.</p> </div> <div class="paragraph"> <p>Якщо ми тепер виконаємо <code>git checkout -b dev p4/project/dev</code> і зробимо кілька комітів, git-p4 достатньо розумний, щоб зрозуміти, у яку гілку надсилати зміни при виконанні команди <code>git p4 submit</code>. На жаль, git-p4 не може використовувати декілька гілок у поверхневих копіях; якщо у вас величезний проект і ви хочете працювати з більш ніж однією гілкою, вам доведеться виконувати <code>git p4 clone</code> для кожної гілки, у яку ви хочете надіслати зміни.</p> </div> <div class="paragraph"> <p>Для створення чи інтеграції гілок ви повинні використовувати клієнт Perforce. Git-p4 може лише синхронізувати і відправляти зміни у гілки, які вже існують, і може це робити лише з одним лінійним набором змін за раз. Якщо ви зіллєте дві гілки у Git та спробуєте надіслати новий набір змін, все, що збережеться — це купа змін у файлах; метадані про гілки, які були змінені при інтеграції, будуть втрачені.</p> </div> </div> </div> <div class="sect4"> <h4 id="_підсумок_по_git_і_perforce">Підсумок по Git і Perforce</h4> <div class="paragraph"> <p>Git-p4 робить можливим використання Git з сервером Perforce, і робить це досить добре. Однак, важливо пам’ятати, що Perforce все одно залишається джерелом даних, і ви використовуєте Git лише для локальної роботи. Будьте дуже обережні при публікації комітів Git; якщо ви маєте віддалений репозиторій, який використовують інші люди, не надсилайте жодних комітів, які ще не надіслані на сервер Perforce.</p> </div> <div class="paragraph"> <p>Якщо ви хочете вільно змішувати Perforce і Git як клієнти для контролю версій, і ви можете переконати адміністратора сервера встановити їх, Git Fusion зробить використання Git у якості клієнта контролю версій для сервера Perforce повноцінним.</p> </div> </div> </div> <div class="sect3"> <h3 id="_git_та_tfs">Git та TFS</h3> <div class="paragraph"> <p> Git популяризується серед Windows розробників і, якщо ви пишете код "під Windows", то є велика ймовірність, що ви також використовуєте Microsoft’s Team Foundation Server (TFS). TFS є набором інструментів для співпраці, що включає в себе облік дефектів, завдань, підтримку Scrum процесу та інших, перегляд коду, та контроль версій. Є трохи плутанини: <strong>TFS</strong> — це сервер, котрий має підтримку контролю коду, користуючись як Git, так і своєю власною СКВ, що має назву <strong>TFVC</strong> (Team Foundation Version Control). Підтримка Git є дещо новою особливістю для TFS (починаючи з 2013 версії), тому всі інструменти, що передували цій появі, звертаються до частини версіонування коду як ``TFS'', незважаючи на те, що насправді працюють з TFVC.</p> </div> <div class="paragraph"> <p>Якщо ви опинетеся в команді, котра користується TFVC, але краще б надали перевагу Git, як системі контролю версій, то для цього існує готовий проект.</p> </div> <div class="sect4"> <h4 id="_який_інструмент">Який інструмент</h4> <div class="paragraph"> <p> Насправді, їх є два: git-tf та git-tfs.</p> </div> <div class="paragraph"> <p>Git-tfs (можна знайти за <a href="https://github.com/git-tfs/git-tfs" class="bare">https://github.com/git-tfs/git-tfs</a>) є .NET проектом та (на момент написання цього тексту) сумісний тільки з Windows. Для роботи з Git сховищами він використовує .NET обгортку над libgit2, бібліотеко-орієнтованою реалізацією Git, що є високопродуктивною та дозволяє багато гнучкості з нутрощами Git сховища. Libgit2 не є повною реалізацією Git, тому git-tfs використовує клієнтську командну стрічку Git для того, щоб закрити недостачу, отже, фактично, немає обмежень в тому, що ця утиліта може робити зі сховищами Git. Її підтримка особливостей TFVC є достить зрілою через те, що вона оперує з сервером через бібліотеки Visual Studio. Це значить, що вам потрібен доступ до цих бібліотек, що, в свою чергу означає, що потрібно встановити недавню версію Visual Studio (будь-яку редакцію, починаючи з версії 2010, включно з Express починаючи з 2012), або Visual Studio SDK.</p> </div> <div class="paragraph"> <p>Git-tf (який живе за адресою <a href="https://gittf.codeplex.com" class="bare">https://gittf.codeplex.com</a>) є Java проектом і через це може працювати на будь-якому комп’ютері з Java середовищем. Він взаємодіє з Git сховищем через JGit (JVM реалізація Git), тобто, практично не має обмежень щодо функціональності Git. Проте, робота TFVC не є повною, порівняно з git-tfs – немає підтримки гілок, для прикладу.</p> </div> <div class="paragraph"> <p>Тому, кожен інструмент має свої сильні та слабкі сторони і є різні ситуації, коли треба надати перевагу одному над іншим. В цій книзі ми розкриємо базове використання обох.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">Зауваження</div> </td> <td class="content"> <div class="paragraph"> <p>Вам знадобиться доступ до сховища TFVC для того, щоб могти слідувати цим інструкціям. А їх не так просто знайти, як, скажімо, сховища Git чи Subversion, тому, можливо, прийдеться створити самому. Для цієї задачі добре підходять Codeplex (<a href="https://www.codeplex.com" class="bare">https://www.codeplex.com</a>) чи Visual Studio Online (<a href="http://www.visualstudio.com" class="bare">http://www.visualstudio.com</a>).</p> </div> </td> </tr> </table> </div> </div> <div class="sect4"> <h4 id="_ознайомлення_з_git_tf">Ознайомлення з <code>git-tf</code> </h4> <div class="paragraph"> <p>По-перше, як і з будь-яким іншим Git проектом, склонуймо. Ось як це виглядає з <code>git-tf</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git tf clone https://tfs.codeplex.com:443/tfs/TFS13 $/myproject/Main project_git</code></pre> </div> </div> <div class="paragraph"> <p>Перший аргумент є URL до TFVC колекцій, другий має формат <code>$/проект/гілка</code>, а третій — це шлях до локального Git сховища, що буде створено (цей аргумент не обов’язковий). Git-tf може працювати лише з одною гілкою одночасно; якщо ви хочете зробити чекіни (checkins) до іншої гілки TFVC, то склонуйте заново з потрібної гілки.</p> </div> <div class="paragraph"> <p>Ось як створити повнофункціональний Git репозиторій:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cd project_git $ git log --all --oneline --decorate 512e75a (HEAD, tag: TFS_C35190, origin_tfs/tfs, master) Checkin message</code></pre> </div> </div> <div class="paragraph"> <p>Це зветься <em>мілким</em> (shallow) клоном, в тому значенні, що завантажено лише найостанніший ченджсет. TFVC не спроектований таким чином, що кожен клієнт має повну копію історії, тому git-tf типово отримає лише останню версію, а це є значно швидшим.</p> </div> <div class="paragraph"> <p>Коли ж у вас вдосталь часу, мабуть, варто клонувати всю історію проекту, за допомогою опції <code>--deep</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git tf clone https://tfs.codeplex.com:443/tfs/TFS13 $/myproject/Main \ project_git --deep Username: domain\user Password: Connecting to TFS... Cloning $/myproject into /tmp/project_git: 100%, done. Cloned 4 changesets. Cloned last changeset 35190 as d44b17a $ cd project_git $ git log --all --oneline --decorate d44b17a (HEAD, tag: TFS_C35190, origin_tfs/tfs, master) Goodbye 126aa7b (tag: TFS_C35189) 8f77431 (tag: TFS_C35178) FIRST 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \ Team Project Creation Wizard</code></pre> </div> </div> <div class="paragraph"> <p>Зверніть увагу на теґи з іменами типу <code>TFS_C35189</code>; за допомогою цієї особливості ви дізнаєтеся який Git коміт та ченджсет TFVC пов’язані між собою. Це є хорошим відображенням, оскільки ви можете за допомогою простої команди <code>log</code> з’ясувати які з ваших комітів також також існують в TFVC. Ці теґи не є обов’язковими (і їх насправді можна вимкнути за допомогою <code>git config git-tf.tag false</code>) – git-tf все одно зберігає реальні зв’язки коміт-ченджсет у файлі <code>.git/git-tf</code>.</p> </div> </div> <div class="sect4"> <h4 id="_ознайомлення_з_git_tfs">Ознайомлення з <code>git-tfs</code> </h4> <div class="paragraph"> <p>Клонування в git-tfs відбувається дещо інакше. Погляньте:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-powershell" data-lang="powershell">PS> git tfs clone --with-branches \ https://username.visualstudio.com/DefaultCollection \ $/project/Trunk project_git Initialized empty Git repository in C:/Users/ben/project_git/.git/ C15 = b75da1aba1ffb359d00e85c52acb261e4586b0c9 C16 = c403405f4989d73a2c3c119e79021cb2104ce44a Tfs branches found: - $/tfvc-test/featureA The name of the local branch will be : featureA C17 = d202b53f67bde32171d5078968c644e562f1c439 C18 = 44cd729d8df868a8be20438fdeeefb961958b674</code></pre> </div> </div> <div class="paragraph"> <p>Зверніть увагу на прапорець <code>--with-branches</code>. Git-tfs має можливість створювати відповідності між гілками TFVC та Git, а цей прапорець вказує на необхідність створювати локальні Git гілки для кожної гілки TFVC. Його використання є рекомендованим якщо ви збираєтеся робити гілки чи зливати в TFS, проте такий підхід не працюватиме з сервером старішим за TFS 2010 – до цього релізу ``гілки'' були просто теками, тому git-tfs не міг відрізнити їх від звичайних тек.</p> </div> <div class="paragraph"> <p>Погляньте на результуюче Git сховище:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-powershell" data-lang="powershell">PS> git log --oneline --graph --decorate --all * 44cd729 (tfs/featureA, featureA) Goodbye * d202b53 Branched from $/tfvc-test/Trunk * c403405 (HEAD, tfs/default, master) Hello * b75da1a New project PS> git log -1 commit c403405f4989d73a2c3c119e79021cb2104ce44a Author: Ben Straub <ben@straub.cc> Date: Fri Aug 1 03:41:59 2014 +0000 Hello git-tfs-id: [https://username.visualstudio.com/DefaultCollection]$/myproject/Trunk;C16</code></pre> </div> </div> <div class="paragraph"> <p>Маємо дві локальні гілки, <code>master</code> та <code>featureA</code>, котрі відображають стартову точку клонування (<code>Trunk</code> в іменуванні TFVC) та дочірню гілку (<code>featureA</code> в TFVC). Ви можете бачити також, що <code>`віддалене сховище'' `tfs</code> має також кілька посилань: <code>default</code> та <code>featureA</code>, які відображають гілки TFVC. Git-tfs робить відповідність між клонованою гілкою та <code>tfs/default</code>, а також інші отримують свої імена.</p> </div> <div class="paragraph"> <p>Ще варто звернути увагу на <code>git-tfs-id:</code> рядки в повідомленнях коміту. Замість теґів, git-tfs використовує ці позначки для зв’язку між TFVC ченджсетами та Git комітами. З цього випливає те, що ваші Git коміти матимуть різні SHA-1 хеші до та після надсилання до TFVC.</p> </div> </div> <div class="sect4"> <h4 id="_процеси_роботи_git_tfs">Процеси роботи Git-tf[s]</h4> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">Зауваження</div> </td> <td class="content"> <div class="paragraph"> <p>Незалежно від того, яким з інстументів ви користуєтеся, налаштуйте ряд конфігураційних значень, задля уникнення неприємностей.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git config set --local core.ignorecase=true $ git config set --local core.autocrlf=false</code></pre> </div> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Очевидно, далі ви б хотіли попрацювати над проектом. TFVC та TFS мають кілька особливостей що можуть ускладнити ваш робочий процес:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Тематичні гілки, що не мають відображення в TFVC додають складнощів. Стається це через <strong>дуже</strong> різний спосіб того, як TFVC та Git тракують гілки.</p> </li> <li> <p>Пам’ятайте, що TFVC дозволяє користувачам ``забирати''(checkout) файли з сервера, замикаючи їх так, що більш ніхто не зможе їх редагувати. Звичайно, це не є перепоною для роботою з цими файлами у вашому локальному сховищі, але може стати такою, коли прийде час надсилання змін до TFVC сервера.</p> </li> <li> <p>TFS має концепцію <code>закритих'' ??? (</code>gated'') чекінів, коли цикл побудова-тести має бути успішно завершеним до того, як дозволено робити чекін. Тут використовується функція відкладених комітів <code>`shelve'' TFVC, яку ми тут детально не розглядатимемо. Ви можете сфабрикувати це вручну з git-tf та git-tfs котрі мають команду `checkintool</code>, що знає про закриті чекіни.</p> </li> </ol> </div> <div class="paragraph"> <p>Для стислості, ми розглянемо лише щасливий шлях, що уникає більшість із згаданих нюансів.</p> </div> </div> <div class="sect4"> <h4 id="_робочий_процес_git_tf">Робочий процес <code>git-tf</code> </h4> <div class="paragraph"> <p>Скажімо, ви виконали деяку роботу, додали кілька комітів до <code>master</code>, а тепер готові ділитися своїми доробками на TFVC сервері. Ось наше Git сховище:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git log --oneline --graph --decorate --all * 4178a82 (HEAD, master) update code * 9df2ae3 update readme * d44b17a (tag: TFS_C35190, origin_tfs/tfs) Goodbye * 126aa7b (tag: TFS_C35189) * 8f77431 (tag: TFS_C35178) FIRST * 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \ Team Project Creation Wizard</code></pre> </div> </div> <div class="paragraph"> <p>Ми хочемо взяти відбиток коміту <code>4178a82</code> та надіслати його на TFVC сервер. Насамперед, подивимося чи хтось із колег долучався до проекту з того часу, як ми востаннє з’єднувалися:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git tf fetch Username: domain\user Password: Connecting to TFS... Fetching $/myproject at latest changeset: 100%, done. Downloaded changeset 35320 as commit 8ef06a8. Updated FETCH_HEAD. $ git log --oneline --graph --decorate --all * 8ef06a8 (tag: TFS_C35320, origin_tfs/tfs) just some text | * 4178a82 (HEAD, master) update code | * 9df2ae3 update readme |/ * d44b17a (tag: TFS_C35190) Goodbye * 126aa7b (tag: TFS_C35189) * 8f77431 (tag: TFS_C35178) FIRST * 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \ Team Project Creation Wizard</code></pre> </div> </div> <div class="paragraph"> <p>Схоже на те, що ще хтось також працює та наші історії розійшлися. Ось де переваги Git очевидні, але ми маємо два способи продовжувати:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Зробити коміт злиття здається природнім для користувача Git (зрештою, <code>git pull</code> саме це й робить), а git-tf може це виконати за допомогою <code>git tf pull</code>. Однак, зауважте, що TFVC не мислить таким самим чином, і, якщо ви надсилаєте коміти злиття, ваша історія виглядатиме по-різному по обидві сторони, що може спантеличувати. Проте, якщо ви збираєтеся надіслати всі свої зміни як один ченджсет, це, мабуть, найлегший спосіб.</p> </li> <li> <p>Перебазовування робить історію лінійною, тобто дає нам можливість перетворити кожен Git коміт на ченджсет TFVC. Оскільки даний спосіб залишає нам найбільше можливостей потім, ми рекомендуємо саме його; git-tf підтримує цю дію за допомогою <code>git tf pull --rebase</code>.</p> </li> </ol> </div> <div class="paragraph"> <p>Вибір за вами. У цьому прикладі ми перебазовуватимемо:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git rebase FETCH_HEAD First, rewinding head to replay your work on top of it... Applying: update readme Applying: update code $ git log --oneline --graph --decorate --all * 5a0e25e (HEAD, master) update code * 6eb3eb5 update readme * 8ef06a8 (tag: TFS_C35320, origin_tfs/tfs) just some text * d44b17a (tag: TFS_C35190) Goodbye * 126aa7b (tag: TFS_C35189) * 8f77431 (tag: TFS_C35178) FIRST * 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \ Team Project Creation Wizard</code></pre> </div> </div> <div class="paragraph"> <p>Тепер ми готові до чекіну в TFVC сервер. Git-tf дає можливість вибрати: створити один ченджсет, що представлятиме всі зміни, починаючи з останньої (<code>--shallow</code>, що є типовою поведінкою) чи створювати по ченджсету на кожен коміт (<code>--deep</code>). Тут ми просто створимо один ченджсет:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git tf checkin -m 'Updating readme and code' Username: domain\user Password: Connecting to TFS... Checking in to $/myproject: 100%, done. Checked commit 5a0e25e in as changeset 35348 $ git log --oneline --graph --decorate --all * 5a0e25e (HEAD, tag: TFS_C35348, origin_tfs/tfs, master) update code * 6eb3eb5 update readme * 8ef06a8 (tag: TFS_C35320) just some text * d44b17a (tag: TFS_C35190) Goodbye * 126aa7b (tag: TFS_C35189) * 8f77431 (tag: TFS_C35178) FIRST * 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \ Team Project Creation Wizard</code></pre> </div> </div> <div class="paragraph"> <p>Створився теґ <code>TFS_C35348</code>, вказуючи що TFVC має такий самий відбиток як відбиток в коміті <code>5a0e25e</code>. Важливо зауважити, що не кожен Git коміт потребує точного відповідника в TFVC; коміт <code>6eb3eb5</code>, наприклад, ніде не існує на сервері.</p> </div> <div class="paragraph"> <p>Таким є основний процес роботи. Ось ще кілька міркувань, що варто пам’ятати:</p> </div> <div class="ulist"> <ul> <li> <p>Робота з гілками не підтримується. Git-tf в змозі створити Git сховище лише з одної гілки TFVC одночасно.</p> </li> <li> <p>Співпрацюйте за допомогою TFVC або Git, але не за допомогою обидвох. Різні git-tf клони одного й того ж TFVC сховища можуть мати різні SHA-1 хеші, що спричинить нескінченні головні болі.</p> </li> <li> <p>Якщо процес вашої команди включає в себе роботу в Git та періодичні синхронізації до TFVC, з’єднуйте до TFVC лише одне Git сховище.</p> </li> </ul> </div> </div> <div class="sect4"> <h4 id="_робочий_процес_git_tfs">Робочий процес <code>git-tfs</code> </h4> <div class="paragraph"> <p>Пройдімо такий самий сценарій з git-tfs. Маємо нові коміти, зроблені в гілку <code>master</code> нашого Git сховища:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-powershell" data-lang="powershell">PS> git log --oneline --graph --all --decorate * c3bd3ae (HEAD, master) update code * d85e5a2 update readme | * 44cd729 (tfs/featureA, featureA) Goodbye | * d202b53 Branched from $/tfvc-test/Trunk |/ * c403405 (tfs/default) Hello * b75da1a New project</code></pre> </div> </div> <div class="paragraph"> <p>Тепер глянемо чи хтось додав якісь зміни, поки ми тут мудрували:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-powershell" data-lang="powershell">PS> git tfs fetch C19 = aea74a0313de0a391940c999e51c5c15c381d91d PS> git log --all --oneline --graph --decorate * aea74a0 (tfs/default) update documentation | * c3bd3ae (HEAD, master) update code | * d85e5a2 update readme |/ | * 44cd729 (tfs/featureA, featureA) Goodbye | * d202b53 Branched from $/tfvc-test/Trunk |/ * c403405 Hello * b75da1a New project</code></pre> </div> </div> <div class="paragraph"> <p>Так, виявляється, що хтось із наших колег додав TFVC ченджсет, який ми бачимо як новий коміт <code>aea74a0</code>, а віддалена гілка <code>tfs/default</code> прогресувала.</p> </div> <div class="paragraph"> <p>Так само як і у випадку git-tf, ми маємо дві фундаментальні опції, щоб розв’язати цю розбіжність:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Перебазуватися та зберегти історію лінійною.</p> </li> <li> <p>Виконати злиття та зберегти що ж насправді трапилося.</p> </li> </ol> </div> <div class="paragraph"> <p>В нашому випадку ми робитимемо ``глибокий'' чекін, тобто кожен Git коміт стає ченджсетом TFVC, тому виберемо варіант з перебазовуванням.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-powershell" data-lang="powershell">PS> git rebase tfs/default First, rewinding head to replay your work on top of it... Applying: update readme Applying: update code PS> git log --all --oneline --graph --decorate * 10a75ac (HEAD, master) update code * 5cec4ab update readme * aea74a0 (tfs/default) update documentation | * 44cd729 (tfs/featureA, featureA) Goodbye | * d202b53 Branched from $/tfvc-test/Trunk |/ * c403405 Hello * b75da1a New project</code></pre> </div> </div> <div class="paragraph"> <p>Тепер ми готові завершити наш вклад, зачекінивши код до TFVC серверу. Будемо використовувати команду <code>rcheckin</code> для того, щоб створювався TFVC ченджсет на кожен Git коміт від HEAD до першого віддаленого посилання <code>tfs</code> (команда <code>checkin</code> створила б просто один ченджсет, щось типу того як працює зчавлення (squashing) комітів).</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-powershell" data-lang="powershell">PS> git tfs rcheckin Working with tfs remote: default Fetching changes from TFS to minimize possibility of late conflict... Starting checkin of 5cec4ab4 'update readme' add README.md C20 = 71a5ddce274c19f8fdc322b4f165d93d89121017 Done with 5cec4ab4b213c354341f66c80cd650ab98dcf1ed, rebasing tail onto new TFS-commit... Rebase done successfully. Starting checkin of b1bf0f99 'update code' edit .git\tfs\default\workspace\ConsoleApplication1/ConsoleApplication1/Program.cs C21 = ff04e7c35dfbe6a8f94e782bf5e0031cee8d103b Done with b1bf0f9977b2d48bad611ed4a03d3738df05ea5d, rebasing tail onto new TFS-commit... Rebase done successfully. No more to rcheckin. PS> git log --all --oneline --graph --decorate * ff04e7c (HEAD, tfs/default, master) update code * 71a5ddc update readme * aea74a0 update documentation | * 44cd729 (tfs/featureA, featureA) Goodbye | * d202b53 Branched from $/tfvc-test/Trunk |/ * c403405 Hello * b75da1a New project</code></pre> </div> </div> <div class="paragraph"> <p>Зверніть увагу на те, як після кожного успішного чекіна до TFVC сервера, git-tfs перебазовує залишкові зміни поверх щойно зробленого. Це тому, що додається поле <code>git-tfs-id</code> в кінці повідомлення коміту, і це змінює SHA-1 хеші. Так і було задумано, не потрібно хвилюватися з цього приводу, просто вам потрібно знати, що це відбувається; особливо, якщо ви ділитеся ідентифікаторами Git комітів з іншими.</p> </div> <div class="paragraph"> <p>TFS має багато особливостей для інтеграції зі своєю системою контролю версій, такі як одиниці роботи (work items), переглядальники коду, закриті (gated) чекіни тощо. Опанувати їх всіх з командного рядка може бути досить хвацькою задачею, але, на щастя, git-tfs має досить швидкий доступ і до більш візуальних інструментів чекіну:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-powershell" data-lang="powershell">PS> git tfs checkintool PS> git tfs ct</code></pre> </div> </div> <div class="paragraph"> <p>Виглядає це якось так:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/uk/v2/images/git-tfs-ct.png" alt="Інструмент чекіну git-tfs."> </div> <div class="title">Рисунок 147. Інструмент чекіну git-tfs.</div> </div> <div class="paragraph"> <p>Це виглядатиме звичним для користувачів TFS, оскільки це той самий діалог, що запускається у Visual Studio.</p> </div> <div class="paragraph"> <p>Git-tfs також дає можливість керувати гілками TFVC з Git сховища. Для прикладу, створимо гілку:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-powershell" data-lang="powershell">PS> git tfs branch $/tfvc-test/featureBee The name of the local branch will be : featureBee C26 = 1d54865c397608c004a2cadce7296f5edc22a7e5 PS> git log --oneline --graph --decorate --all * 1d54865 (tfs/featureBee) Creation branch $/myproject/featureBee * ff04e7c (HEAD, tfs/default, master) update code * 71a5ddc update readme * aea74a0 update documentation | * 44cd729 (tfs/featureA, featureA) Goodbye | * d202b53 Branched from $/tfvc-test/Trunk |/ * c403405 Hello * b75da1a New project</code></pre> </div> </div> <div class="paragraph"> <p>Створення гілки в TFVC означає додавання ченджсету до гілки, що вже існує, і це відображено окремим комітом Git. Також, зверніть увагу, що git-tfs <strong>створив</strong> віддалену гілку <code>tfs/featureBee</code>, але <code>HEAD</code> досі вказує на <code>master</code>. Якщо вам кортить попрацювати з щойно створеною гілкою, потрібно базувати свої нові коміти на коміті <code>1d54865</code>, можливо, створивши тематичну гілку з цього коміту.</p> </div> </div> <div class="sect4"> <h4 id="_git_та_tfs_підсумок">Git та TFS. Підсумок</h4> <div class="paragraph"> <p>Обидві Git-tf та Git-tfs є чудовими інструментами для доступу до сервера TFVC та роботи з ним. Вони дають вам локальну могутність Git, уникають постійних мандрів мережею до центрального сервера TFVC, та спрощують ваше розробницьке життя, без необхідності переходу на Git цілою командою. Якщо ви працюєте з Windows (що дуже ймовірно, коли користуєтеся TFS), то вам, мабуть, більше захочеться обрати git-tfs, через більш повний набір особливостей, а у випадку іншої платформи, ви користуватиметеся git-tf, яка є більш обмеженою. Як і з більшістю інструментів цього розділу, вам потрібно обрати одну з систем контролю версій, яка буде основною, а іншу використовувати ніби підлеглу – будь це Git чи TFVC, потрібно обрати один центр для співпраці, не обидва.</p> </div> </div> </div> <div id="nav"><a href="/book/uk/v2/Налаштування-Git-Підсумок">prev</a> | <a href="/book/uk/v2/Git-and-Other-Systems-Міграція-на-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>