CINXE.COM

Git - Git как клиент

<!DOCTYPE html> <html lang="ru"> <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-ru">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/ru/v2/%d0%92%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%9e-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b5-%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">Введение</a></h2> <ol> <li> 1.1 <a href="/book/ru/v2/%d0%92%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%9e-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d0%b5-%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">О системе контроля версий</a> </li> <li> 1.2 <a href="/book/ru/v2/%d0%92%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%9a%d1%80%d0%b0%d1%82%d0%ba%d0%b0%d1%8f-%d0%b8%d1%81%d1%82%d0%be%d1%80%d0%b8%d1%8f-Git">Краткая история Git</a> </li> <li> 1.3 <a href="/book/ru/v2/%d0%92%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%a7%d1%82%d0%be-%d1%82%d0%b0%d0%ba%d0%be%d0%b5-Git%3F">Что такое Git?</a> </li> <li> 1.4 <a href="/book/ru/v2/%d0%92%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%bd%d0%b0%d1%8f-%d1%81%d1%82%d1%80%d0%be%d0%ba%d0%b0">Командная строка</a> </li> <li> 1.5 <a href="/book/ru/v2/%d0%92%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%a3%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d0%ba%d0%b0-Git">Установка Git</a> </li> <li> 1.6 <a href="/book/ru/v2/%d0%92%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%9f%d0%b5%d1%80%d0%b2%d0%be%d0%bd%d0%b0%d1%87%d0%b0%d0%bb%d1%8c%d0%bd%d0%b0%d1%8f-%d0%bd%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-Git">Первоначальная настройка Git</a> </li> <li> 1.7 <a href="/book/ru/v2/%d0%92%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%9a%d0%b0%d0%ba-%d0%bf%d0%be%d0%bb%d1%83%d1%87%d0%b8%d1%82%d1%8c-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%3F">Как получить помощь?</a> </li> <li> 1.8 <a href="/book/ru/v2/%d0%92%d0%b2%d0%b5%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%97%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5">Заключение</a> </li> </ol> </li> <li class='chapter'> <h2>2. <a href="/book/ru/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d1%8b-Git-%d0%a1%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-Git-%d1%80%d0%b5%d0%bf%d0%be%d0%b7%d0%b8%d1%82%d0%be%d1%80%d0%b8%d1%8f">Основы Git</a></h2> <ol> <li> 2.1 <a href="/book/ru/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d1%8b-Git-%d0%a1%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-Git-%d1%80%d0%b5%d0%bf%d0%be%d0%b7%d0%b8%d1%82%d0%be%d1%80%d0%b8%d1%8f">Создание Git-репозитория</a> </li> <li> 2.2 <a href="/book/ru/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d1%8b-Git-%d0%97%d0%b0%d0%bf%d0%b8%d1%81%d1%8c-%d0%b8%d0%b7%d0%bc%d0%b5%d0%bd%d0%b5%d0%bd%d0%b8%d0%b9-%d0%b2-%d1%80%d0%b5%d0%bf%d0%be%d0%b7%d0%b8%d1%82%d0%be%d1%80%d0%b8%d0%b9">Запись изменений в репозиторий</a> </li> <li> 2.3 <a href="/book/ru/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d1%8b-Git-%d0%9f%d1%80%d0%be%d1%81%d0%bc%d0%be%d1%82%d1%80-%d0%b8%d1%81%d1%82%d0%be%d1%80%d0%b8%d0%b8-%d0%ba%d0%be%d0%bc%d0%bc%d0%b8%d1%82%d0%be%d0%b2">Просмотр истории коммитов</a> </li> <li> 2.4 <a href="/book/ru/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d1%8b-Git-%d0%9e%d0%bf%d0%b5%d1%80%d0%b0%d1%86%d0%b8%d0%b8-%d0%be%d1%82%d0%bc%d0%b5%d0%bd%d1%8b">Операции отмены</a> </li> <li> 2.5 <a href="/book/ru/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d1%8b-Git-%d0%a0%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d1%83%d0%b4%d0%b0%d0%bb%d1%91%d0%bd%d0%bd%d1%8b%d0%bc%d0%b8-%d1%80%d0%b5%d0%bf%d0%be%d0%b7%d0%b8%d1%82%d0%be%d1%80%d0%b8%d1%8f%d0%bc%d0%b8">Работа с удалёнными репозиториями</a> </li> <li> 2.6 <a href="/book/ru/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d1%8b-Git-%d0%a0%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d1%82%d0%b5%d0%b3%d0%b0%d0%bc%d0%b8">Работа с тегами</a> </li> <li> 2.7 <a href="/book/ru/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d1%8b-Git-%d0%9f%d1%81%d0%b5%d0%b2%d0%b4%d0%be%d0%bd%d0%b8%d0%bc%d1%8b-%d0%b2-Git">Псевдонимы в Git</a> </li> <li> 2.8 <a href="/book/ru/v2/%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d1%8b-Git-%d0%97%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5">Заключение</a> </li> </ol> </li> <li class='chapter'> <h2>3. <a href="/book/ru/v2/%d0%92%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-Git-%d0%9e-%d0%b2%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b8-%d0%b2-%d0%b4%d0%b2%d1%83%d1%85-%d1%81%d0%bb%d0%be%d0%b2%d0%b0%d1%85">Ветвление в Git</a></h2> <ol> <li> 3.1 <a href="/book/ru/v2/%d0%92%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-Git-%d0%9e-%d0%b2%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b8-%d0%b2-%d0%b4%d0%b2%d1%83%d1%85-%d1%81%d0%bb%d0%be%d0%b2%d0%b0%d1%85">О ветвлении в двух словах</a> </li> <li> 3.2 <a href="/book/ru/v2/%d0%92%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-Git-%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d1%8b-%d0%b2%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d1%8f-%d0%b8-%d1%81%d0%bb%d0%b8%d1%8f%d0%bd%d0%b8%d1%8f">Основы ветвления и слияния</a> </li> <li> 3.3 <a href="/book/ru/v2/%d0%92%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-Git-%d0%a3%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2%d0%b5%d1%82%d0%ba%d0%b0%d0%bc%d0%b8">Управление ветками</a> </li> <li> 3.4 <a href="/book/ru/v2/%d0%92%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-Git-%d0%a0%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d0%b2%d0%b5%d1%82%d0%ba%d0%b0%d0%bc%d0%b8">Работа с ветками</a> </li> <li> 3.5 <a href="/book/ru/v2/%d0%92%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-Git-%d0%a3%d0%b4%d0%b0%d0%bb%d1%91%d0%bd%d0%bd%d1%8b%d0%b5-%d0%b2%d0%b5%d1%82%d0%ba%d0%b8">Удалённые ветки</a> </li> <li> 3.6 <a href="/book/ru/v2/%d0%92%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-Git-%d0%9f%d0%b5%d1%80%d0%b5%d0%b1%d0%b0%d0%b7%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5">Перебазирование</a> </li> <li> 3.7 <a href="/book/ru/v2/%d0%92%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-Git-%d0%97%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5">Заключение</a> </li> </ol> </li> <li class='chapter'> <h2>4. <a href="/book/ru/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d0%b5-%d0%9f%d1%80%d0%be%d1%82%d0%be%d0%ba%d0%be%d0%bb%d1%8b">Git на сервере</a></h2> <ol> <li> 4.1 <a href="/book/ru/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d0%b5-%d0%9f%d1%80%d0%be%d1%82%d0%be%d0%ba%d0%be%d0%bb%d1%8b">Протоколы</a> </li> <li> 4.2 <a href="/book/ru/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d0%b5-%d0%a3%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d0%ba%d0%b0-Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80">Установка Git на сервер</a> </li> <li> 4.3 <a href="/book/ru/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d0%b5-%d0%93%d0%b5%d0%bd%d0%b5%d1%80%d0%b0%d1%86%d0%b8%d1%8f-%d0%be%d1%82%d0%ba%d1%80%d1%8b%d1%82%d0%be%d0%b3%d0%be-SSH-%d0%ba%d0%bb%d1%8e%d1%87%d0%b0">Генерация открытого SSH ключа</a> </li> <li> 4.4 <a href="/book/ru/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d0%b5-%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%b0%d0%b8%d0%b2%d0%b0%d0%b5%d0%bc-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80">Настраиваем сервер</a> </li> <li> 4.5 <a href="/book/ru/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d0%b5-Git-%d0%b4%d0%b5%d0%bc%d0%be%d0%bd">Git-демон</a> </li> <li> 4.6 <a href="/book/ru/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d0%b5-%d0%a3%d0%bc%d0%bd%d1%8b%d0%b9-HTTP">Умный HTTP</a> </li> <li> 4.7 <a href="/book/ru/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d0%b5-GitWeb">GitWeb</a> </li> <li> 4.8 <a href="/book/ru/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d0%b5-GitLab">GitLab</a> </li> <li> 4.9 <a href="/book/ru/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d0%b5-Git-%d1%85%d0%be%d1%81%d1%82%d0%b8%d0%bd%d0%b3">Git-хостинг</a> </li> <li> 4.10 <a href="/book/ru/v2/Git-%d0%bd%d0%b0-%d1%81%d0%b5%d1%80%d0%b2%d0%b5%d1%80%d0%b5-%d0%97%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5">Заключение</a> </li> </ol> </li> <li class='chapter'> <h2>5. <a href="/book/ru/v2/%d0%a0%d0%b0%d1%81%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d1%91%d0%bd%d0%bd%d1%8b%d0%b9-Git-%d0%a0%d0%b0%d1%81%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d1%91%d0%bd%d0%bd%d1%8b%d0%b9-%d1%80%d0%b0%d0%b1%d0%be%d1%87%d0%b8%d0%b9-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d1%81%d1%81">Распределённый Git</a></h2> <ol> <li> 5.1 <a href="/book/ru/v2/%d0%a0%d0%b0%d1%81%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d1%91%d0%bd%d0%bd%d1%8b%d0%b9-Git-%d0%a0%d0%b0%d1%81%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d1%91%d0%bd%d0%bd%d1%8b%d0%b9-%d1%80%d0%b0%d0%b1%d0%be%d1%87%d0%b8%d0%b9-%d0%bf%d1%80%d0%be%d1%86%d0%b5%d1%81%d1%81">Распределённый рабочий процесс</a> </li> <li> 5.2 <a href="/book/ru/v2/%d0%a0%d0%b0%d1%81%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d1%91%d0%bd%d0%bd%d1%8b%d0%b9-Git-%d0%a3%d1%87%d0%b0%d1%81%d1%82%d0%b8%d0%b5-%d0%b2-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b5">Участие в проекте</a> </li> <li> 5.3 <a href="/book/ru/v2/%d0%a0%d0%b0%d1%81%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d1%91%d0%bd%d0%bd%d1%8b%d0%b9-Git-%d0%a1%d0%be%d0%bf%d1%80%d0%be%d0%b2%d0%be%d0%b6%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b0">Сопровождение проекта</a> </li> <li> 5.4 <a href="/book/ru/v2/%d0%a0%d0%b0%d1%81%d0%bf%d1%80%d0%b5%d0%b4%d0%b5%d0%bb%d1%91%d0%bd%d0%bd%d1%8b%d0%b9-Git-%d0%97%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5">Заключение</a> </li> </ol> </li> </ol> </div> <div class='column-middle'> <ol class='book-toc'> <li class='chapter'> <h2>6. <a href="/book/ru/v2/GitHub-%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-%d0%b8-%d0%ba%d0%be%d0%bd%d1%84%d0%b8%d0%b3%d1%83%d1%80%d0%b0%d1%86%d0%b8%d1%8f-%d1%83%d1%87%d1%91%d1%82%d0%bd%d0%be%d0%b9-%d0%b7%d0%b0%d0%bf%d0%b8%d1%81%d0%b8">GitHub</a></h2> <ol> <li> 6.1 <a href="/book/ru/v2/GitHub-%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-%d0%b8-%d0%ba%d0%be%d0%bd%d1%84%d0%b8%d0%b3%d1%83%d1%80%d0%b0%d1%86%d0%b8%d1%8f-%d1%83%d1%87%d1%91%d1%82%d0%bd%d0%be%d0%b9-%d0%b7%d0%b0%d0%bf%d0%b8%d1%81%d0%b8">Настройка и конфигурация учётной записи</a> </li> <li> 6.2 <a href="/book/ru/v2/GitHub-%d0%92%d0%bd%d0%b5%d1%81%d0%b5%d0%bd%d0%b8%d0%b5-%d1%81%d0%be%d0%b1%d1%81%d1%82%d0%b2%d0%b5%d0%bd%d0%bd%d0%be%d0%b3%d0%be-%d0%b2%d0%ba%d0%bb%d0%b0%d0%b4%d0%b0-%d0%b2-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d1%8b">Внесение собственного вклада в проекты</a> </li> <li> 6.3 <a href="/book/ru/v2/GitHub-%d0%a1%d0%be%d0%bf%d1%80%d0%be%d0%b2%d0%be%d0%b6%d0%b4%d0%b5%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%b0">Сопровождение проекта</a> </li> <li> 6.4 <a href="/book/ru/v2/GitHub-%d0%a3%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%be%d1%80%d0%b3%d0%b0%d0%bd%d0%b8%d0%b7%d0%b0%d1%86%d0%b8%d0%b5%d0%b9">Управление организацией</a> </li> <li> 6.5 <a href="/book/ru/v2/GitHub-%d0%a1%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d1%81%d1%86%d0%b5%d0%bd%d0%b0%d1%80%d0%b8%d0%b5%d0%b2-GitHub">Создание сценариев GitHub</a> </li> <li> 6.6 <a href="/book/ru/v2/GitHub-%d0%97%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5">Заключение</a> </li> </ol> </li> <li class='chapter'> <h2>7. <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%92%d1%8b%d0%b1%d0%be%d1%80-%d1%80%d0%b5%d0%b2%d0%b8%d0%b7%d0%b8%d0%b8">Инструменты Git</a></h2> <ol> <li> 7.1 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%92%d1%8b%d0%b1%d0%be%d1%80-%d1%80%d0%b5%d0%b2%d0%b8%d0%b7%d0%b8%d0%b8">Выбор ревизии</a> </li> <li> 7.2 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%98%d0%bd%d1%82%d0%b5%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%b2%d0%bd%d0%be%d0%b5-%d0%b8%d0%bd%d0%b4%d0%b5%d0%ba%d1%81%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5">Интерактивное индексирование</a> </li> <li> 7.3 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%9f%d1%80%d0%b8%d0%bf%d1%80%d1%8f%d1%82%d1%8b%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%b8-%d0%be%d1%87%d0%b8%d1%81%d1%82%d0%ba%d0%b0">Припрятывание и очистка</a> </li> <li> 7.4 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%9f%d0%be%d0%b4%d0%bf%d0%b8%d1%81%d1%8c">Подпись</a> </li> <li> 7.5 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%9f%d0%be%d0%b8%d1%81%d0%ba">Поиск</a> </li> <li> 7.6 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%9f%d0%b5%d1%80%d0%b5%d0%b7%d0%b0%d0%bf%d0%b8%d1%81%d1%8c-%d0%b8%d1%81%d1%82%d0%be%d1%80%d0%b8%d0%b8">Перезапись истории</a> </li> <li> 7.7 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%a0%d0%b0%d1%81%d0%ba%d1%80%d1%8b%d1%82%d0%b8%d0%b5-%d1%82%d0%b0%d0%b9%d0%bd-reset">Раскрытие тайн reset</a> </li> <li> 7.8 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%9f%d1%80%d0%be%d0%b4%d0%b2%d0%b8%d0%bd%d1%83%d1%82%d0%be%d0%b5-%d1%81%d0%bb%d0%b8%d1%8f%d0%bd%d0%b8%d0%b5">Продвинутое слияние</a> </li> <li> 7.9 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-Rerere">Rerere</a> </li> <li> 7.10 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%9e%d0%b1%d0%bd%d0%b0%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-%d0%be%d1%88%d0%b8%d0%b1%d0%be%d0%ba-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-Git">Обнаружение ошибок с помощью Git</a> </li> <li> 7.11 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%9f%d0%be%d0%b4%d0%bc%d0%be%d0%b4%d1%83%d0%bb%d0%b8">Подмодули</a> </li> <li> 7.12 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%a1%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d0%bf%d0%b0%d0%ba%d0%b5%d1%82%d0%be%d0%b2">Создание пакетов</a> </li> <li> 7.13 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%97%d0%b0%d0%bc%d0%b5%d0%bd%d0%b0">Замена</a> </li> <li> 7.14 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%a5%d1%80%d0%b0%d0%bd%d0%b8%d0%bb%d0%b8%d1%89%d0%b5-%d1%83%d1%87%d1%91%d1%82%d0%bd%d1%8b%d1%85-%d0%b4%d0%b0%d0%bd%d0%bd%d1%8b%d1%85">Хранилище учётных данных</a> </li> <li> 7.15 <a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%97%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5">Заключение</a> </li> </ol> </li> <li class='chapter'> <h2>8. <a href="/book/ru/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-Git-%d0%9a%d0%be%d0%bd%d1%84%d0%b8%d0%b3%d1%83%d1%80%d0%b0%d1%86%d0%b8%d1%8f-Git">Настройка Git</a></h2> <ol> <li> 8.1 <a href="/book/ru/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-Git-%d0%9a%d0%be%d0%bd%d1%84%d0%b8%d0%b3%d1%83%d1%80%d0%b0%d1%86%d0%b8%d1%8f-Git">Конфигурация Git</a> </li> <li> 8.2 <a href="/book/ru/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-Git-%d0%90%d1%82%d1%80%d0%b8%d0%b1%d1%83%d1%82%d1%8b-Git">Атрибуты Git</a> </li> <li> 8.3 <a href="/book/ru/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-Git-%d0%a5%d1%83%d0%ba%d0%b8-%d0%b2-Git">Хуки в Git</a> </li> <li> 8.4 <a href="/book/ru/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-Git-%d0%9f%d1%80%d0%b8%d0%bc%d0%b5%d1%80-%d0%bf%d1%80%d0%b8%d0%bd%d1%83%d0%b4%d0%b8%d1%82%d0%b5%d0%bb%d1%8c%d0%bd%d0%be%d0%b9-%d0%bf%d0%be%d0%bb%d0%b8%d1%82%d0%b8%d0%ba%d0%b8-Git">Пример принудительной политики Git</a> </li> <li> 8.5 <a href="/book/ru/v2/%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-Git-%d0%97%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5">Заключение</a> </li> </ol> </li> <li class='chapter'> <h2>9. <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">Git и другие системы контроля версий</a></h2> <ol> <li> 9.1 <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" class="active">Git как клиент</a> </li> <li> 9.2 <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-%d0%9f%d0%b5%d1%80%d0%b5%d1%85%d0%be%d0%b4-%d0%bd%d0%b0-Git">Переход на Git</a> </li> <li> 9.3 <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-%d0%97%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5">Заключение</a> </li> </ol> </li> <li class='chapter'> <h2>10. <a href="/book/ru/v2/Git-%d0%b8%d0%b7%d0%bd%d1%83%d1%82%d1%80%d0%b8-%d0%a1%d0%b0%d0%bd%d1%82%d0%b5%d1%85%d0%bd%d0%b8%d0%ba%d0%b0-%d0%b8-%d0%a4%d0%b0%d1%80%d1%84%d0%be%d1%80">Git изнутри</a></h2> <ol> <li> 10.1 <a href="/book/ru/v2/Git-%d0%b8%d0%b7%d0%bd%d1%83%d1%82%d1%80%d0%b8-%d0%a1%d0%b0%d0%bd%d1%82%d0%b5%d1%85%d0%bd%d0%b8%d0%ba%d0%b0-%d0%b8-%d0%a4%d0%b0%d1%80%d1%84%d0%be%d1%80">Сантехника и Фарфор</a> </li> <li> 10.2 <a href="/book/ru/v2/Git-%d0%b8%d0%b7%d0%bd%d1%83%d1%82%d1%80%d0%b8-%d0%9e%d0%b1%d1%8a%d0%b5%d0%ba%d1%82%d1%8b-Git">Объекты Git</a> </li> <li> 10.3 <a href="/book/ru/v2/Git-%d0%b8%d0%b7%d0%bd%d1%83%d1%82%d1%80%d0%b8-%d0%a1%d1%81%d1%8b%d0%bb%d0%ba%d0%b8-%d0%b2-Git">Ссылки в Git</a> </li> <li> 10.4 <a href="/book/ru/v2/Git-%d0%b8%d0%b7%d0%bd%d1%83%d1%82%d1%80%d0%b8-Pack-%d1%84%d0%b0%d0%b9%d0%bb%d1%8b">Pack-файлы</a> </li> <li> 10.5 <a href="/book/ru/v2/Git-%d0%b8%d0%b7%d0%bd%d1%83%d1%82%d1%80%d0%b8-%d0%a1%d0%bf%d0%b5%d1%86%d0%b8%d1%84%d0%b8%d0%ba%d0%b0%d1%86%d0%b8%d0%b8-%d1%81%d1%81%d1%8b%d0%bb%d0%be%d0%ba">Спецификации ссылок</a> </li> <li> 10.6 <a href="/book/ru/v2/Git-%d0%b8%d0%b7%d0%bd%d1%83%d1%82%d1%80%d0%b8-%d0%9f%d1%80%d0%be%d1%82%d0%be%d0%ba%d0%be%d0%bb%d1%8b-%d0%bf%d0%b5%d1%80%d0%b5%d0%b4%d0%b0%d1%87%d0%b8-%d0%b4%d0%b0%d0%bd%d0%bd%d1%8b%d1%85">Протоколы передачи данных</a> </li> <li> 10.7 <a href="/book/ru/v2/Git-%d0%b8%d0%b7%d0%bd%d1%83%d1%82%d1%80%d0%b8-%d0%9e%d0%b1%d1%81%d0%bb%d1%83%d0%b6%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d1%80%d0%b5%d0%bf%d0%be%d0%b7%d0%b8%d1%82%d0%be%d1%80%d0%b8%d1%8f-%d0%b8-%d0%b2%d0%be%d1%81%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b4%d0%b0%d0%bd%d0%bd%d1%8b%d1%85">Обслуживание репозитория и восстановление данных</a> </li> <li> 10.8 <a href="/book/ru/v2/Git-%d0%b8%d0%b7%d0%bd%d1%83%d1%82%d1%80%d0%b8-%d0%9f%d0%b5%d1%80%d0%b5%d0%bc%d0%b5%d0%bd%d0%bd%d1%8b%d0%b5-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f">Переменные окружения</a> </li> <li> 10.9 <a href="/book/ru/v2/Git-%d0%b8%d0%b7%d0%bd%d1%83%d1%82%d1%80%d0%b8-%d0%97%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5">Заключение</a> </li> </ol> </li> </ol> </div> <div class='column-right'> <ol class='book-toc'> <li class='chapter'> <h2>A1. <a href="/book/ru/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%85-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f%d1%85-%d0%93%d1%80%d0%b0%d1%84%d0%b8%d1%87%d0%b5%d1%81%d0%ba%d0%b8%d0%b5-%d0%b8%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d1%8b">Приложение A: Git в других окружениях</a></h2> <ol> <li> A1.1 <a href="/book/ru/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%85-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f%d1%85-%d0%93%d1%80%d0%b0%d1%84%d0%b8%d1%87%d0%b5%d1%81%d0%ba%d0%b8%d0%b5-%d0%b8%d0%bd%d1%82%d0%b5%d1%80%d1%84%d0%b5%d0%b9%d1%81%d1%8b">Графические интерфейсы</a> </li> <li> A1.2 <a href="/book/ru/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%85-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f%d1%85-Git-%d0%b2-Visual-Studio">Git в Visual Studio</a> </li> <li> A1.3 <a href="/book/ru/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%85-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f%d1%85-Git-%d0%b2-Visual-Studio-Code">Git в Visual Studio Code</a> </li> <li> A1.4 <a href="/book/ru/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%85-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f%d1%85-Git-%d0%b2-Eclipse">Git в Eclipse</a> </li> <li> A1.5 <a href="/book/ru/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%85-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f%d1%85-Git-%d0%b2-IntelliJ-/-PyCharm-/-WebStorm-/-PhpStorm-/-RubyMine">Git в IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine</a> </li> <li> A1.6 <a href="/book/ru/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%85-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f%d1%85-Git-%d0%b2-Sublime-Text">Git в Sublime Text</a> </li> <li> A1.7 <a href="/book/ru/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%85-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f%d1%85-Git-%d0%b2-Bash">Git в Bash</a> </li> <li> A1.8 <a href="/book/ru/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%85-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f%d1%85-Git-%d0%b2-Zsh">Git в Zsh</a> </li> <li> A1.9 <a href="/book/ru/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%85-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f%d1%85-Git-%d0%b2-PowerShell">Git в PowerShell</a> </li> <li> A1.10 <a href="/book/ru/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%85-%d0%be%d0%ba%d1%80%d1%83%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f%d1%85-%d0%97%d0%b0%d0%ba%d0%bb%d1%8e%d1%87%d0%b5%d0%bd%d0%b8%d0%b5">Заключение</a> </li> </ol> </li> <li class='chapter'> <h2>A2. <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d1%81%d1%82%d1%80%d0%b0%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-Git-%d0%b2-%d0%b2%d0%b0%d1%88%d0%b8-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-Git-%d0%b8%d0%b7-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%bd%d0%be%d0%b9-%d1%81%d1%82%d1%80%d0%be%d0%ba%d0%b8">Приложение B: Встраивание Git в ваши приложения</a></h2> <ol> <li> A2.1 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d1%81%d1%82%d1%80%d0%b0%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-Git-%d0%b2-%d0%b2%d0%b0%d1%88%d0%b8-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-Git-%d0%b8%d0%b7-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d0%bd%d0%be%d0%b9-%d1%81%d1%82%d1%80%d0%be%d0%ba%d0%b8">Git из командной строки</a> </li> <li> A2.2 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d1%81%d1%82%d1%80%d0%b0%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-Git-%d0%b2-%d0%b2%d0%b0%d1%88%d0%b8-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-Libgit2">Libgit2</a> </li> <li> A2.3 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d1%81%d1%82%d1%80%d0%b0%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-Git-%d0%b2-%d0%b2%d0%b0%d1%88%d0%b8-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-JGit">JGit</a> </li> <li> A2.4 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d1%81%d1%82%d1%80%d0%b0%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-Git-%d0%b2-%d0%b2%d0%b0%d1%88%d0%b8-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-go-git">go-git</a> </li> <li> A2.5 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-B:-%d0%92%d1%81%d1%82%d1%80%d0%b0%d0%b8%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-Git-%d0%b2-%d0%b2%d0%b0%d1%88%d0%b8-%d0%bf%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d1%8f-Dulwich">Dulwich</a> </li> </ol> </li> <li class='chapter'> <h2>A3. <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-%d0%b8-%d0%ba%d0%be%d0%bd%d1%84%d0%b8%d0%b3%d1%83%d1%80%d0%b0%d1%86%d0%b8%d1%8f">Приложение C: Команды Git</a></h2> <ol> <li> A3.1 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%9d%d0%b0%d1%81%d1%82%d1%80%d0%be%d0%b9%d0%ba%d0%b0-%d0%b8-%d0%ba%d0%be%d0%bd%d1%84%d0%b8%d0%b3%d1%83%d1%80%d0%b0%d1%86%d0%b8%d1%8f">Настройка и конфигурация</a> </li> <li> A3.2 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%9a%d0%bb%d0%be%d0%bd%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5-%d0%b8-%d1%81%d0%be%d0%b7%d0%b4%d0%b0%d0%bd%d0%b8%d0%b5-%d1%80%d0%b5%d0%bf%d0%be%d0%b7%d0%b8%d1%82%d0%be%d1%80%d0%b8%d0%b5%d0%b2">Клонирование и создание репозиториев</a> </li> <li> A3.3 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%9e%d1%81%d0%bd%d0%be%d0%b2%d0%bd%d1%8b%d0%b5-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b">Основные команды</a> </li> <li> A3.4 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%92%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b8-%d1%81%d0%bb%d0%b8%d1%8f%d0%bd%d0%b8%d1%8f">Ветвление и слияния</a> </li> <li> A3.5 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%a1%d0%be%d0%b2%d0%bc%d0%b5%d1%81%d1%82%d0%bd%d0%b0%d1%8f-%d1%80%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d0%b8-%d0%be%d0%b1%d0%bd%d0%be%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d0%be%d0%b2">Совместная работа и обновление проектов</a> </li> <li> A3.6 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%9e%d1%81%d0%bc%d0%be%d1%82%d1%80-%d0%b8-%d1%81%d1%80%d0%b0%d0%b2%d0%bd%d0%b5%d0%bd%d0%b8%d0%b5">Осмотр и сравнение</a> </li> <li> A3.7 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%9e%d1%82%d0%bb%d0%b0%d0%b4%d0%ba%d0%b0">Отладка</a> </li> <li> A3.8 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%92%d0%bd%d0%b5%d1%81%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b8%d1%81%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9">Внесение исправлений</a> </li> <li> A3.9 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%a0%d0%b0%d0%b1%d0%be%d1%82%d0%b0-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-%d1%8d%d0%bb%d0%b5%d0%ba%d1%82%d1%80%d0%be%d0%bd%d0%bd%d0%be%d0%b9-%d0%bf%d0%be%d1%87%d1%82%d1%8b">Работа с помощью электронной почты</a> </li> <li> A3.10 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%92%d0%bd%d0%b5%d1%88%d0%bd%d0%b8%d0%b5-%d1%81%d0%b8%d1%81%d1%82%d0%b5%d0%bc%d1%8b">Внешние системы</a> </li> <li> A3.11 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%90%d0%b4%d0%bc%d0%b8%d0%bd%d0%b8%d1%81%d1%82%d1%80%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d0%b5">Администрирование</a> </li> <li> A3.12 <a href="/book/ru/v2/%d0%9f%d1%80%d0%b8%d0%bb%d0%be%d0%b6%d0%b5%d0%bd%d0%b8%d0%b5-C:-%d0%9a%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b-Git-%d0%9d%d0%b8%d0%b7%d0%ba%d0%be%d1%83%d1%80%d0%be%d0%b2%d0%bd%d0%b5%d0%b2%d1%8b%d0%b5-%d0%ba%d0%be%d0%bc%d0%b0%d0%bd%d0%b4%d1%8b">Низкоуровневые команды</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 и другие системы контроля версий - Git как клиент</h1> <div> <p>Наш мир несовершенен. Как правило, вы не можете быстро перевести свой проект на использование Git. Иногда вам придётся иметь дело с проектами, использующими другую систему контроля версий, хотя вам и не нравится, что это не Git. В первой части этого раздела вы узнаете о способах использования Git в качестве клиента для работы с проектом, размещённом в другой системе контроля версий.</p><p>В какой-то момент, вы, возможно, захотите перевести свой существующий проект на Git. Во второй части главы вы узнаете о том, как провести миграцию в Git из некоторых специфических систем, а также познакомитесь с методом, который будет работать в нестандартных ситуациях, когда готовых инструментов миграции не существует.</p> <h2 id="_git_как_клиент">Git как клиент</h2> <div class="paragraph"> <p> Git оказывает настолько положительное впечатление на разработчиков, что многие из них придумывают способы, как использовать его на своём компьютере, в случае если остальная часть команды использует другую систему контроля версий. Для этого разработан целый ряд специальных адаптеров, называемых «мостами» («bridges»). Здесь мы рассмотрим те, с которыми вы, скорее всего, столкнётесь при работе над реальными проектами.</p> </div> <div class="sect3"> <h3 id="r_git_svn">Git и Subversion</h3> <div class="paragraph"> <p> Весомая часть проектов разработки с открытым исходным кодом, равно как и огромное количество корпоративных проектов, до сих пор используют Subversion (SVN) для управления исходным кодом. Он существует уже более десяти лет и большую часть этого времени был <em>де-факто</em> единственной системой контроля версий для проектов с открытым исходным кодом. Он также во многом похож на CVS, своего предка — «крёстного отца» всех современных систем управления версиями.</p> </div> <div class="paragraph"> <p> Одна из многих замечательных вещей в Git — это поддержка двусторонней интеграции с SVN через <code>git svn</code>. Этот инструмент позволяет использовать Git в качестве полноценного SVN клиента; вы можете использовать всю функциональность Git для работы с локальным репозиторием, скомпоновать ревизии и отправить их на сервер, словно вы использовали обычный SVN. Да, вы не ослышались: можно создавать локальные ветки, производить слияния, использовать индекс для неполного применения изменений, перемещать коммиты и повторно применять их (cherry-pick) и т. д., в то время как ваши коллеги, использующие SVN, застряли в палеолите. Это отличный способ по-партизански внедрить Git в процесс разработки и помочь соратниками стать более продуктивными, а затем потребовать от инфраструктуры полной поддержки Git. <code>git svn</code> — это первый укол наркотика «DVCS», вызывающего сильнейшее привыкание.</p> </div> <div class="sect4"> <h4 id="_git_svn"><code>git svn</code></h4> <div class="paragraph"> <p>Основная команда для работы с 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="_установка_2">Установка</h4> <div class="paragraph"> <p>Чтобы попробовать <code>git svn</code> в деле вам понадобится обычный SVN репозиторий с правом на запись. Если вы хотите попробовать примеры ниже, вам понадобится копия нашего тестового репозитория. К счастью, в Subversion есть инструмент <code>svnsync</code>, который упростит перенос. Для тестов мы создали новый Subversion репозиторий на Google Code, являющийся частичной копией проекта <code>protobuf</code> — библиотеки для сериализации структурированных данных для передачи по сети.</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>Затем, позвольте всем пользователям изменять т. н. <code>revprops</code>; самый простой способ сделать это — добавить скрипт <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>, передав входной и выходной репозитории:</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>Наконец (SVN вам ещё не надоел?), можно запустить саму синхронизацию. Затем можно будет клонировать собственно код, выполнив:</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>На всё про всё у вас уйдёт несколько минут, но на самом деле вам ещё повезло: если бы вы копировали данные не на свой компьютер, а в другой удалённый репозиторий, понадобился бы почти час, несмотря на то, что в тестовом проекте меньше сотни ревизий. Subversion копирует данные последовательно, скачивая по одной ревизии и отправляя в другой репозиторий — это поразительно неэффективно, но как есть, так есть.</p> </div> </div> <div class="sect4"> <h4 id="_начало_работы">Начало работы</h4> <div class="paragraph"> <p>Теперь, когда у вас есть Subversion репозиторий с правами на запись, можно опробовать типичные приёмы работы с ним через <code>git svn</code> Начнём с команды <code>git svn clone</code>, которая клонирует Subversion репозиторий целиком в локальный Git репозиторий. Разумеется, при переносе реального Subversion репозитория нужно будет заменить <code>file:///tmp/test-svn</code> на настоящий URL:</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 =&gt; 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 вынужден последовательно скачивать SVN ревизии и превращать их в Git коммиты по одной за раз. Для проекта с сотней или тысячей ревизий это может занять часы или даже дни!</p> </div> <div class="paragraph"> <p>Параметры <code>-T trunk -b branches -t tags</code> говорят Git о том, что клонируемый репозиторий следует стандартному, принятому в Subversion, расположению каталогов с транком, ветками и тегами. Если же каталоги названы по-другому, можно указать их явно, используя эти параметры. Большинство Subversion репозиториев следуют этому соглашению, поэтому для этой комбинации параметров существует сокращение <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>Обратите внимание, как <code>git svn</code> представляет метки Subversion в виде ссылок. Давайте посмотрим на это повнимательней, используя команду <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 поступает иначе, вот как выглядит 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>, но в случае с Subversion репозиторием они трактуются как удалённые ветки.</p> </div> </div> <div class="sect4"> <h4 id="_отправка_изменений_в_subversion">Отправка изменений в Subversion</h4> <div class="paragraph"> <p>Теперь, когда вы настроили репозиторий, можно проделать некую работу и отправить изменения обратно в Subversion, используя 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 сервер, следует выполнить команду <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 ревизию, а затем переписывает их, добавляя уникальный идентификатор. Это важно, потому что изменяются SHA-1 хеши коммитов. Это одна из причин, почему не рекомендуется смешивать Subversion и Git сервер в одном проекте. Если посмотреть на последний коммит, вы увидите, что добавилась строка <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 &lt;ben@0b684db3-b064-4277-89d1-21af03df0a68&gt; 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>, которая заберёт все ревизии с сервера, которых у вас пока нет, и переместит (rebase) ваши локальные наработки на них:</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>Теперь история линейна и вы можете успешно выполнить <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 сервером дела обстоят иначе: перед отправкой изменений в удалённый репозиторий вы можете полностью протестировать проект локально, в то время как в Subversion вы не можете быть уверенными, что состояние проекта до и после коммита было одинаковым.</p> </div> <div class="paragraph"> <p>Даже если вы не готовы зафиксировать собственные изменения, следует почаще забирать изменения с Subversion сервера. Для синхронизации можно использовать <code>git svn fetch</code>, или <code>git svn rebase</code>; последняя команда не только забирает все изменения из Subversion, но и переносит ваши локальные коммиты наверх.</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> актуализирует состояние локального репозитория. Для выполнения этой команды ваш рабочий каталог не должен содержать незафиксированных изменений. Если это не так, вам следует либо «припрятать» (stash) свои наработки, либо на время зафиксировать: иначе <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 — в нём принята несколько иная концепция ветвления и слияния — так что <code>git svn</code> учитывает лишь первого родителя любого коммита при преобразовании её в SVN формат.</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> на ветке с уже слитой историй пройдёт успешно, за исключением того момента, что при просмотре истории вы заметите, что коммита из ветки <code>experiment</code> не были переписаны один за другим; вместо этого они схлопнулись в один коммит слияния.</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; используйте его как можно реже. Тем не менее, используя <code>git svn</code>, вы можете создавать Subversion-ветки и фиксировать изменения в них.</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 =&gt; 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>Это эквивалентно выполнению команды <code>svn copy trunk branches/opera</code> в Subversion, при этом действия совершаются на Subversion сервере. Обратите внимание, что создание SVN ветки не переключает вас на неё; если сейчас зафиксировать какие-либо изменения и отправить их на сервер, они попадут в ветку <code>trunk</code>, а не <code>opera</code>.</p> </div> </div> <div class="sect4"> <h4 id="_переключение_активных_веток">Переключение активных веток</h4> <div class="paragraph"> <p>Git определяет ветку, в которую он отправит ваши коммиты при выполнении <code>dcommit</code>, ища верхушку Subversion-ветки в вашей истории — она должна быть одна и она должна быть последней в текущей истории веток, имеющей метку <code>git-svn-id</code>.</p> </div> <div class="paragraph"> <p>Если вы хотите работать одновременно с несколькими ветками, вы можете настроить локальные ветки на внесение изменений через <code>dcommit</code> в конкретные ветки Subversion, отпочковывая их из импортированных SVN-ревизий нужных веток. Если вам нужна ветка <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 коммиты, которые вы ещё не отправили с помощью <code>dcommit</code>, не будут отображаться, равно как и коммиты, отправленные на Subversion сервер другими людьми с момента последнего выполнения <code>dcommit</code>. Результат действия этой команды скорее похож на последнее известное состояние изменений на 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> — выводит на стандартный вывод строки, которые следует включить в файл <code>.gitignore</code>; вы можете попросту перенаправить вывод этой команды в файл исключений:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git svn show-ignore &gt; .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-сервера. Однако, стоит воспринимать их как «функционально урезанный» Git, ибо при использовании всех возможностей 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), неудивительно, что работа с Mercurial-репозиторием происходит через своего рода обёртку над «удалённым репозиторием». Проект, добавляющий такую интероперабельность, называется <code>git-remote-hg</code> и расположен по адресу <a href="https://github.com/felipec/git-remote-hg" class="bare" target="_blank" rel="noopener">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>. Ничего особенного — просто поместите файл в любое место, откуда он будет виден другим программам, типа:</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>. Есть ещё одна зависимость: библиотека <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" target="_blank" rel="noopener">https://www.python.org/</a>.)</p> </div> <div class="paragraph"> <p>Ну и наконец понадобится сам клиент Mercurial. Если он ещё не установлен — скачайте и установите с <a href="https://www.mercurial-scm.org/" class="bare" target="_blank" rel="noopener">https://www.mercurial-scm.org/</a>.</p> </div> <div class="paragraph"> <p>Теперь можно отжигать! Всё что потребуется — репозиторий Mercurial с которым вы можете работать. К счастью, подойдёт любой, так что мы воспользуемся репозиторием «привет, мир», используемом для обучения работе с 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>Как и всегда, вначале мы клонируем репозиторий:</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>Наверняка вы обратили внимание, что мы использовали обыкновенный <code>git clone</code>. Это потому, что <code>git-remote-hg</code> работает на довольно низком уровне, подобно тому, как в Git реализован HTTP/S протокол (<code>git-remote-hg</code> служит как бы в качестве «помощника» для работы с удалённым репозиторием по новому протоколу (<code>hg</code>), расширяя базовые возможности 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><code>git-remote-hg</code> пытается нивелировать различия между Git и Mercurial, преобразовывая форматы за кулисами. Ссылки на объекты в удалённом репозитории хранятся в каталоге <code>refs/hg</code>. Например, <code>refs/hg/origin/branches/default</code> — это Git-ссылка, содержащая SHA-1 <code>ac7955c</code> — коммит на который ссылается ветка <code>master</code>. Таким образом, каталог <code>refs/hg</code> — это что-то типа <code>refs/remotes/origin</code>, с той разницей, что здесь же отдельно хранятся закладки и ветки Mercurial.</p> </div> <div class="paragraph"> <p>Файл <code>notes/hg</code> — отправная точка для выяснения соответствия между хешами коммитов в 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 &lt;&gt; 1408066400 -0800 committer remote-hg &lt;&gt; 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> указывает на дерево, которое содержит список других объектов и имён. Команда <code>git ls-tree</code> выводит права доступа, тип, хеш и имя файла для содержимого дерева. Наконец, добравшись до первого элемента дерева, мы обнаружим, что это блоб с названием <code>ac9117f</code> (SHA-1 коммита, на которую указывает ветка <code>master</code>), содержащий <code>0a04b98</code> (идентификатор последней ревизии ветки <code>default</code> в Mercurial).</p> </div> <div class="paragraph"> <p>Всё это немного запутанно, но хорошие новости в том, что, по большому счёту, нам не нужно беспокоится об организации данных в git-remote-hg. В целом, работа с Mercurial сервером не сильно отличается от работы с Git сервером.</p> </div> <div class="paragraph"> <p>Ещё одна вещь, которую следует учитывать: список игнорируемых файлов. Mercurial и Git используют очень похожие механизмы для таких списков, но всё же хранить <code>.gitignore</code> в Mercurial репозитории — не самая удачная идея. К счастью, в Git есть механизм игнорирования специфичных для локальной копии репозитория файлов, а формат списка исключений в Mercurial совместим с Git, так что можно просто скопировать <code>.hgignore</code> кое-куда:</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="_рабочий_процесс">Рабочий процесс</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 -&gt; origin/master ac7955c..df85e87 branches/default -&gt; 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», используемые внутри <code>git-remote-hg</code>, можно не обращать на них внимания. В остальном, ничего необычного: <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 -&gt; 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> внесены <code>git-remote-hg</code> после отправки изменений, сделанных через 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 &lt;ben@straub.cc&gt; date: Thu Aug 14 20:06:38 2014 -0700 summary: More documentation</code></pre> </div> </div> <div class="paragraph"> <p>Обратите внимание на строку, начинающуюся с «branch». Git устроен по-другому (на самом деле, оба типа веток могут быть представлены как ссылки в Git), но <code>git-remote-hg</code> вынужден понимать разницу, потому что нацелен на работу с 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 -&gt; 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 — просто поместите Git ветку в пространство имён <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 -&gt; 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 &lt;ben@straub.cc&gt; | date: Thu Aug 14 20:21:09 2014 -0700 | summary: A permanent change | | @ changeset: 6:8f65e5e02793 |/ branch: develop | user: Ben Straub &lt;ben@straub.cc&gt; | 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 &lt;ben@straub.cc&gt; | | 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 работа с обеими типами Mercurial веток выглядит одинаково: переключаемся на ветку, фиксируем изменения, забираем чужие наработки, производим слияния и отправляем изменения в репозиторий как обычно. И ещё: 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="_заключение_12">Заключение</h4> <div class="paragraph"> <p>Git и Mercurial довольно похожи, их относительно просто можно «подружить». Если вы будете избегать изменения уже опубликованной истории (это в целом хорошая идея, не только в контексте взаимодействия с Mercurial), вы даже не заметите что работаете с другой системой контроля версий.</p> </div> </div> </div> <div class="sect3"> <h3 id="_git_и_bazaar">Git и Bazaar</h3> <div class="paragraph"> <p>Ещё одна известная распределённая система контроля версий <a href="https://bazaar.canonical.com" target="_blank" rel="noopener">Bazaar</a>. Bazaar — это бесплатная система с открытым исходным кодом, являющаяся частью проекта <a href="https://www.gnu.org" target="_blank" rel="noopener">GNU Project</a>.</p> </div> <div class="paragraph"> <p>Её поведение сильно отличается от Git. Иногда, чтобы сделать то же самое, что и в Git, следует использовать другое ключевое слово, а некоторые такие же ключевые слова имеют другое значение. В частности, управления ветками сильно отличается и может вызвать путаницу, особенно для кого-нибудь из вселенной Git. Тем не менее, с Bazaar репозиторием возможно работать из Git.</p> </div> <div class="paragraph"> <p>Существует много проектов, которые позволяют использовать Git как клиент Bazaar. Далее, мы будем использовать проект Филипа Контрераса, который можно найти здесь <a href="https://github.com/felipec/git-remote-bzr" class="bare" target="_blank" rel="noopener">https://github.com/felipec/git-remote-bzr</a>. Для установки достаточно просто скачать файл <code>git-remote-bzr</code> и поместить его в один из каталогов вашего <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>Так же вам понадобится установленный Bazaar. И всё!</p> </div> <div class="sect4"> <h4 id="_создание_репозитория_git_из_репозитория_bazaar">Создание репозитория Git из репозитория Bazaar</h4> <div class="paragraph"> <p>Им просто пользоваться. Чтобы клонировать Bazaar репозиторий достаточно добавить префикс <code>bzr::</code>. Так как Git и Bazaar полностью клонируют репозиторий на ваш компьютер, то можно добавить клон Git к локальному клону Bazaar, но так делать не рекомендуется. Гораздо проще связать клон Git с центральным хранилищем — тем же местом, с которым связан клон Bazaar.</p> </div> <div class="paragraph"> <p>Предположим, что вы работали с удалённым репозиторием, находящимся по адресу <code>bzr+ssh://developer@mybazaarserver:myproject</code>. Чтобы его клонировать, нужно выполнить следующие команды:</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>На текущий момент, созданный Git репозиторий использует дисковое пространство не оптимально. Поэтому вы должны очистить и сжать его, особенно если репозиторий большого размера:</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">Ветки в Bazaar</h4> <div class="paragraph"> <p>Bazaar позволяет клонировать только ветки, при этом репозиторий может содержать их несколько, а <code>git-remote-bzr</code> может клонировать все. Например, чтобы клонировать ветку выполните:</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>Чтобы клонировать весь репозиторий, выполните команду:</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>Последняя команда клонирует все ветки репозитория emacs; тем не менее, конфигурацией допускается указывать только некоторые из них:</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>Некоторые удалённые репозитории не позволяют просматривать список веток, поэтому их перечисление в конфигурации для команды клонирования может оказаться проще в использовании:</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="_игнорируем_то_что_игнорируется_в_bzrignore">Игнорируем то, что игнорируется в .bzrignore</h4> <div class="paragraph"> <p>При работе с проектом под управлением Bazaar вы не должны создавать файл <code>.gitignore</code>, потому что можете случайно добавить его в отслеживаемые, чем могут возмутиться другие пользователи, работающие с Bazaar. Решением может выступать создание файла <code>.git/info/exclude</code>, который может быть как символической ссылкой, так и обычным файлом. Позже мы рассмотрим пример решения этой проблемы.</p> </div> <div class="paragraph"> <p>Bazaar использует ту же модель игнорирования файлов что и Git, за исключением двух особенностей, не имеющих эквивалента в Git. Полное описание можно найти в <a href="http://doc.bazaar.canonical.com/bzr.2.7/en/user-reference/ignore-help.html" target="_blank" rel="noopener">документации</a>. Эти два отличия следующие:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p><code>!!</code> позволяет игнорировать определённые шаблоны файлов, даже если они указаны со знаком <code>!</code></p> </li> <li> <p><code>RE:</code> в начале строки позволяет указать <a href="https://docs.python.org/3/library/re.html" target="_blank" rel="noopener">регулярное выражение Python</a>. Git допускает только шаблоны оболочки.</p> </li> </ol> </div> <div class="paragraph"> <p>Следовательно, возможны две ситуации:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Если файл <code>.bzrignore</code> не содержит специфических префиксов, то можно просто создать символическую ссылку на него: <code>ln -s .bzrignore .git/info/exclude</code></p> </li> <li> <p>Иначе, нужно создать файл <code>.git/info/exclude</code> и адаптировать его в соответствии с <code>.bzrignore</code> так, чтобы игнорировались те же файлы.</p> </li> </ol> </div> <div class="paragraph"> <p>Вне зависимости от ситуации, вам нужно следить за изменениями в <code>.bzrignore</code>, чтобы файл <code>.git/info/exclude</code> всегда соответствовал <code>.bzrignore</code>. На самом деле, если в файл <code>.bzrignore</code> будут добавлены изменения в виде одной или нескольких строк с <code>!!</code> или <code>RE:</code> вначале, то Git просто не сможет их интерпретировать и вам понадобиться изменить файл <code>.git/info/exclude</code> так, чтобы игнорировались те же файлы. Более того, если файл <code>.git/info/exclude</code> был символической ссылкой, то сначала нужно его удалить, скопировать <code>.bzrignore</code> в <code>.git/info/exclude</code> и адаптировать последний. Однако, будьте осторожны с его созданием, потому что в Git невозможно повторно включить файл в индекс, если исключен родительский каталог этого файла.</p> </div> </div> <div class="sect4"> <h4 id="_получение_изменений_с_удалённого_репозитория">Получение изменений с удалённого репозитория</h4> <div class="paragraph"> <p>Используя обычные команды 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 pull --rebase origin</code></pre> </div> </div> </div> <div class="sect4"> <h4 id="_отправка_в_удалённый_репозиторий">Отправка в удалённый репозиторий</h4> <div class="paragraph"> <p>Поскольку Bazaar так же имеет концепцию коммитов слияния, то проблем не возникнет при отправке такого коммита. Таким образом, вы можете работать в ветке, сливать изменения в <code>master</code> и отправлять их. Вы можете создавать ветки, делать коммиты и тестировать изменения как обычно. Наконец, вы отправляете проделанную работу в репозиторий Bazaar:</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="_предупреждение">Предупреждение</h4> <div class="paragraph"> <p>Существуют ограничения на выполнение операций с удалённым репозиторием. В частности, следующие команды не работают:</p> </div> <div class="ulist"> <ul> <li> <p>git push origin :branch-to-delete (Bazaar не понимает удаление ссылок таким способом.)</p> </li> <li> <p>git push origin old:new (будет отправлена 'old')</p> </li> <li> <p>git push --dry-run origin branch (push будет выполнен)</p> </li> </ul> </div> </div> <div class="sect4"> <h4 id="_заключение_13">Заключение</h4> <div class="paragraph"> <p>Поскольку модели Git и Bazaar схожи, то не так много усилий требуется для их совместной работы. Всё будет в порядке пока вы следите за ограничениями и знаете, что удалённый репозиторий изначально не Git.</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>Существует два варианта совместного использования Git и Perforce. Первый — Git Fusion от разработчиков Perforce — позволяет выставлять поддеревья Perforce-депо в качестве удалённых Git репозиториев. Второй — <code>git-p4</code> — клиентская обёртка над Perforce для Git; она не требует дополнительной настройки Perforce сервера.</p> </div> <div class="sect4"> <h4 id="r_p4_git_fusion">Git Fusion</h4> <div class="paragraph"> <p> У создателей Perforce есть продукт, именуемый Git Fusion (доступен на <a href="http://www.perforce.com/git-fusion" class="bare" target="_blank" rel="noopener">http://www.perforce.com/git-fusion</a>), который синхронизирует Perforce сервер с Git репозиторием на стороне сервера.</p> </div> <div class="sect5"> <h6 id="_установка_3">Установка</h6> <div class="paragraph"> <p>Для примера мы воспользуемся простейшим способом настройки Git Fusion — подготовленным образом для виртуальной машины с предустановленным Perforce демоном и собственно Git Fusion. Вы можете скачать образ на <a href="http://www.perforce.com/downloads/Perforce/20-User" class="bare" target="_blank" rel="noopener">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/ru/v2/images/git-fusion-boot.png" alt="Экран виртуальной машины Git Fusion"> </div> <div class="title">Рисунок 145. Экран виртуальной машины Git Fusion</div> </div> <div class="paragraph"> <p>Запомните IP адрес, он пригодится в будущем. Далее, создадим пользователя Perforce. Выберите внизу опцию «Login» и нажмите <code>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>Первая команда откроет редактор для уточнения данных пользователя, но вы можете принять настройки по умолчанию, введя <code>:wq</code> и нажав <code>Enter</code>. Вторая команда дважды попросит ввести пароль. Это всё, что требовалось выполнить в оболочке ОС, можете завершить сессию.</p> </div> <div class="paragraph"> <p>Следующим шагом необходимо запретить Git проверять SSL сертификаты. Хотя виртуальная машина Git Fusion поставляется с сертификатом, он не привязан к домену и IP адресу виртуальной машины, так что Git будет отвергать соединения как небезопасные. Если вы собираетесь использовать эту виртуальную машину на постоянной основе, обратитесь к руководству по 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 пользователей. Параметр <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>Таким образом, если ваше отображение включает изменения в структуре каталогов, вы можете реплицировать эти изменения здесь.</p> </div> <div class="paragraph"> <p>Последний файл, который мы обсудим, это <code>users/p4gf_usermap</code>; в нём задаётся отображение пользователей Perforce на пользователей Git. Возможно, вам не пригодится этот файл.</p> </div> <div class="paragraph"> <p>Когда Git Fusion преобразовывает набор изменений Perforce в Git коммит, он находит пользователя в этом файле и использует хранящиеся здесь адрес электронной почты и полное имя для заполнения полей «автор» и «применяющий изменения» в Git. При обратном процессе ищется пользователь Perforce с адресом электронной почты из поля «автор» Git коммитов и используется далее для изменения.</p> </div> <div class="paragraph"> <p>В большинстве случаев это нормальное поведение, но что будет, если соответствия выглядят так:</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>&lt;user&gt; &lt;email&gt; "&lt;full name&gt;"</code> и задаёт соответствие для одного пользователя. Первые две строчки отображают два разных адреса электронной почты на одного и того же пользователя. Это может быть полезным если вы фиксировали изменения в Git, используя разные адреса, или если вы поменяли адрес, но хотите отобразить эти изменения на одного и того же Perforce пользователя. При создании Git коммитов Perforce используется информация из первой совпавшей строки.</p> </div> <div class="paragraph"> <p>Последние две строки скрывают настоящие имена Боба и Джо в созданных Git коммитах. Это может быть полезным, если вы хотите отдать внутренний проект в open-source, но не хотите раскрывать информацию о сотрудниках. Адреса электронной почты и полные имена должны быть уникальными если вы хотите хоть как-то различать авторов в полученном Git репозитории.</p> </div> </div> <div class="sect5"> <h6 id="_рабочий_процесс_2">Рабочий процесс</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 -&gt; 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 -&gt; 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> не видно, но на самом деле коммит с SHA-1 <code>6afeb15</code> был создан Perforce клиентом. Он выглядит так же, как и любой другой коммит, и это именно то, для чего создан 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 -&gt; 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/ru/v2/images/git-fusion-perforce-graph.png" alt="Граф ревизий Perforce после отправки данных из Git"> </div> <div class="title">Рисунок 146. Граф ревизий Perforce после отправки данных из Git</div> </div> <div class="paragraph"> <p>Если вы ни разу не работали с Perforce это окно может показаться вам запутанным, но его концепция аналогичная <code>gitk</code>. Мы просматриваем историю файла <code>README</code>, так что дерево каталогов слева вверху показывает этот файл в разных ветках. Справа вверху мы видим граф зависимости разных ревизий файла, справа внизу этот же граф показан целиком для быстрого ориентирования. Оставшаяся часть окна отображает детали выбранной ревизии (в нашем случае это ревизия <code>2</code>).</p> </div> <div class="paragraph"> <p>Граф выглядит в точности как в Git. У Perforce не было именованной ветки для сохранения коммитов <code>1</code> и <code>2</code>, так что он создал «анонимную» ветку в каталоге <code>.git-fusion</code>. Git Fusion поступит так же для именованных Git веток не соответствующих веткам в Perforce, но вы можете задать соответствие в конфигурационном файле.</p> </div> <div class="paragraph"> <p>Большинство происходящей магии скрыто от посторонних глаз, а в результате кто-то в команде может использовать 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. Вы даже можете использовать подмодули Git (хотя они и будут выглядеть странными для Perforce пользователей) и сливать ветки (на стороне Perforce это будет выглядеть как интеграция).</p> </div> <div class="paragraph"> <p>И даже в том случае, если вы не можете уговорить администратора настроить Git Fusion есть способ использовать Git и Perforce вместе.</p> </div> </div> </div> <div class="sect4"> <h4 id="_git_p4">Git-p4</h4> <div class="paragraph"> <p> Git-p4 — это двусторонний мост между Git и Perforce. Он работает на стороне клиента, так что вам не нужен будет доступ к 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>Исполняемый файл <code>p4</code> должен быть доступен в <code>PATH</code> для использования <code>git-p4</code>. На момент написания книги он свободно доступен на <a href="http://www.perforce.com/downloads/Perforce/20-User" class="bare" target="_blank" rel="noopener">http://www.perforce.com/downloads/Perforce/20-User</a>.</p> </div> </td> </tr> </table> </div> <div class="sect5"> <h6 id="_настройка">Настройка</h6> <div class="paragraph"> <p>Мы будем использовать описанный выше образ виртуальной машины Git Fusion, но мы будем напрямую обращаться к Perforce, минуя Git Fusion.</p> </div> <div class="paragraph"> <p>Для того, чтобы использовать команду <code>p4</code> (от которой зависит <code>git-p4</code>), вам нужно будет установить следующие переменные окружения:</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="_начало_работы_2">Начало работы</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 мы получим так называемую «поверхностную» копию: выкачивается лишь последняя ревизия. Помните, 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>Обратите внимание на наличие удалённого репозитория <code>p4</code>, соответствующего 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>В этом репозитории нет удалённых серверов. <code>git-p4</code> создал несколько ссылок для представления состояния на сервере, и они выглядят как удалённый сервер для <code>git log</code>, но таковым не являются и вы не можете отправлять изменения в них.</p> </div> </div> <div class="sect5"> <h6 id="_рабочий_процесс_3">Рабочий процесс</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, отправка слияний в Perforce не имеет смысла. <code>git-p4</code> рекомендует перемещать коммиты и даже предоставляет команду для этого:</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 @@ &lt;/td&gt; &lt;td valign=top&gt; Source and documentation for -&lt;a href="http://www.perforce.com/jam/jam.html"&gt; +&lt;a href="jam.html"&gt; Jam/MR&lt;/a&gt;, a software build tool. &lt;/td&gt;</code></pre> </div> </div> <div class="paragraph"> <p>Это практически те же данные, что вы увидели бы, запустив <code>p4 submit</code>, за исключением нескольких строк в конце, любезно вставленных <code>git-p4</code>. <code>git-p4</code> старается учитывать Git и Perforce настройки когда нужно предоставить имя для коммита, но в некоторых случаях вы захотите изменить его. Например, если коммит в Git был создан человеком, у которого нет Perforce аккаунта, вы всё равно захотите сделать автором коммита его, а не себя.</p> </div> <div class="paragraph"> <p><code>git-p4</code> вставил сообщение из коммита 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; если вы хотите слепить их воедино, вы можете сделать это с помощью интерактивного переноса коммитов до выполнения <code>git p4 submit</code>. Ещё один важный момент: SHA-1 хеши коммитов, превращённых в наборы изменений Perforce изменились: это произошло из-за того, что <code>git-p4</code> добавил строку в конец каждого сообщения:</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 &lt;john@example.com&gt; 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, по одной для каждой не являющейся слиянием коммита в Git. Звучит логично, давайте посмотрим что произойдёт на самом деле:</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="r_git_p4_branches">Ветвление</h6> <div class="paragraph"> <p>Если в вашем Perforce проекте несколько веток, не переживайте: <code>git-p4</code> может организовать работу с ними, не сложнее, чем с обычными 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><code>git-p4</code> может автоматически распознать эту ситуацию и выполнить нужные действия:</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>Обратите внимание на <code>@all</code> в пути; она говорит <code>git-p4</code> клонировать не только последнюю ревизию для указанного поддерева, но все ревизии, затрагивающие указанные пути. Это ближе к оригинальной концепции клонирования в Git, но если вы работаете с большим репозиторием, это может занять некоторое время.</p> </div> <div class="paragraph"> <p>Флаг <code>--detect-branches</code> указывает <code>git-p4</code> использовать настройки веток Perforce для отображения на Git ветки. Если же таких настроек на Perforce сервере нет (что вполне корректно для Perforce), вы можете указать их <code>git-p4</code> вручную, получив аналогичный результат:</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> мы указали <code>git-p4</code>, что «main» и «dev» — это ветки, и что вторая является потомком первой.</p> </div> <div class="paragraph"> <p>Если мы теперь выполним <code>git checkout -b dev p4/project/dev</code> и зафиксируем в ветке <code>dev</code> некоторые изменения, <code>git-p4</code> будет достаточно смышлёным, чтобы догадаться, в какую ветку отправлять изменения при выполнении <code>git p4 submit</code>. К сожалению, <code>git-p4</code> не позволяет использовать несколько веток в поверхностных копиях репозиториев; если у вас есть большой проект и вы хотите работать более чем в одной ветке, вам придётся выполнять <code>git p4 clone</code> для каждой ветки, в которую вы хотите отправлять изменения.</p> </div> <div class="paragraph"> <p>Для создания и интеграции веток вам нужно будет использовать Perforce клиент. <code>git-p4</code> может только забирать изменения из Perforce и отправлять линейную историю обратно. Если вы произведёте слияние двух веток в Git и отправите изменения в Perforce, сохранятся лишь данные об изменении файлов, все метаданные об исходных ветках, участвующих в интеграции, будут потеряны.</p> </div> </div> </div> <div class="sect4"> <h4 id="_заключение_по_git_и_perforce">Заключение по Git и Perforce</h4> <div class="paragraph"> <p><code>git-p4</code> позволяет использовать Git для работы с Perforce и он достаточно хорош в этом. Тем не менее, не стоит забывать, что источником данных по-прежнему остаётся Perforce, а Git используется лишь для локальной работы. Будьте осторожны с публикацией Git коммитов: если у вас есть удалённый репозиторий, который используют другие люди, не публикуйте в нём коммиты, не отправленные на Perforce сервер.</p> </div> <div class="paragraph"> <p>Если вы хотите свободно смешивать Git и Perforce для контроля версий, уговорите администратора установить Git Fusion — он позволяет использовать Git в качестве полноценного клиента для Perforce сервера.</p> </div> </div> </div> <div id="nav"><a href="/book/ru/v2/Настройка-Git-Заключение">prev</a> | <a href="/book/ru/v2/Git-и-другие-системы-контроля-версий-Переход-на-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>

Pages: 1 2 3 4 5 6 7 8 9 10