CINXE.COM

Git - Contributing to a Project

<!DOCTYPE html> <html lang="id"> <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 - Contributing to a Project</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/Distributed-Git-Contributing-to-a-Project">English</a>. </p> <p> Full translation available in <table> <tr><td><a href="/book/az/v2/Paylanm%c4%b1%c5%9f-Git-Layih%c9%99y%c9%99-T%c3%b6hf%c9%99-verm%c9%99k">azərbaycan dili</a>,</td></tr> <tr><td><a href="/book/bg/v2/Git-%d0%b8%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-%d0%98%d0%bd%d1%82%d0%b5%d1%80%d0%b0%d0%ba%d1%82%d0%b8%d0%b2%d0%bd%d0%be-%d0%b8%d0%bd%d0%b4%d0%b5%d0%ba%d1%81%d0%b8%d1%80%d0%b0%d0%bd%d0%b5">български език</a>,</td></tr> <tr><td><a href="/book/de/v2/Verteiltes-Git-An-einem-Projekt-mitwirken">Deutsch</a>,</td></tr> <tr><td><a href="/book/es/v2/Git-en-entornos-distribuidos-Contribuyendo-a-un-Proyecto">Español</a>,</td></tr> <tr><td><a href="/book/fr/v2/Git-distribu%c3%a9-Contribution-%c3%a0-un-projet">Français</a>,</td></tr> <tr><td><a href="/book/gr">Ελληνικά</a>,</td></tr> <tr><td><a href="/book/ja/v2/Git-%e3%81%a7%e3%81%ae%e5%88%86%e6%95%a3%e4%bd%9c%e6%a5%ad-%e3%83%97%e3%83%ad%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e3%81%b8%e3%81%ae%e8%b2%a2%e7%8c%ae">日本語</a>,</td></tr> <tr><td><a href="/book/ko/v2/%eb%b6%84%ec%82%b0-%ed%99%98%ea%b2%bd%ec%97%90%ec%84%9c%ec%9d%98-Git-%ed%94%84%eb%a1%9c%ec%a0%9d%ed%8a%b8%ec%97%90-%ea%b8%b0%ec%97%ac%ed%95%98%ea%b8%b0">한국어</a>,</td></tr> <tr><td><a href="/book/nl/v2/Gedistribueerd-Git-Bijdragen-aan-een-project">Nederlands</a>,</td></tr> <tr><td><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>,</td></tr> <tr><td><a href="/book/sl/v2/Porazdeljeni-Git-Prispevek-k-projektu">Slovenščina</a>,</td></tr> <tr><td><a href="/book/tl/v2/Distributed-Git-Contributing-to-a-Project">Tagalog</a>,</td></tr> <tr><td><a href="/book/uk/v2/%d0%a0%d0%be%d0%b7%d0%bf%d0%be%d0%b4%d1%96%d0%bb%d0%b5%d0%bd%d0%b8%d0%b9-Git-%d0%92%d0%bd%d0%b5%d1%81%d0%b5%d0%bd%d0%bd%d1%8f-%d0%b7%d0%bc%d1%96%d0%bd-%d0%b4%d0%be-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82%d1%83">Українська</a></td></tr> <tr><td><a href="/book/zh/v2/%e5%88%86%e5%b8%83%e5%bc%8f-Git-%e5%90%91%e4%b8%80%e4%b8%aa%e9%a1%b9%e7%9b%ae%e8%b4%a1%e7%8c%ae">简体中文</a>,</td></tr> </table> </p> <p> Partial translations available in <table> <tr><td><a href="/book/cs/v2/Distribuovan%c3%bd-Git-P%c5%99isp%c3%adv%c3%a1n%c3%ad-do-projektu">Čeština</a>,</td></tr> <tr><td><a href="/book/mk/v2/%d0%94%d0%b8%d1%81%d1%82%d1%80%d0%b8%d0%b1%d1%83%d0%b8%d1%80%d0%b0%d0%bd-Git-%d0%9f%d1%80%d0%b8%d0%b4%d0%be%d0%bd%d0%b5%d1%81-%d0%ba%d0%be%d0%bd-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82">Македонски</a>,</td></tr> <tr><td><a href="/book/pl/v2/Rozproszony-Git-Wgrywanie-zmian-do-projektu">Polski</a>,</td></tr> <tr><td><a href="/book/sr/v2/%d0%94%d0%b8%d1%81%d1%82%d1%80%d0%b8%d0%b1%d1%83%d0%b8%d1%80%d0%b0%d0%bd%d0%b8-%d0%93%d0%b8%d1%82-%d0%9a%d0%b0%d0%ba%d0%be-%d1%81%d0%b5-%d0%b4%d0%b0%d1%98%d0%b5-%d0%b4%d0%be%d0%bf%d1%80%d0%b8%d0%bd%d0%be%d1%81-%d0%bf%d1%80%d0%be%d1%98%d0%b5%d0%ba%d1%82%d1%83">Српски</a>,</td></tr> <tr><td><a href="/book/uz/v2/Distributed-Git-Contributing-to-a-Project">Ўзбекча</a>,</td></tr> <tr><td><a href="/book/zh-tw/v2/%e5%88%86%e6%95%a3%e5%bc%8f%e7%9a%84-Git-%e5%b0%8d%e5%b0%88%e6%a1%88%e9%80%b2%e8%a1%8c%e8%b2%a2%e7%8d%bb">繁體中文</a>,</td></tr> </table> </p> <p> Translations started for <table> <tr><td><a href="/book/be/v2/Distributed-Git-Contributing-to-a-Project">Беларуская</a>,</td></tr> <tr><td><a href="/book/fa/v2/%da%af%db%8c%d8%aa-%d8%aa%d9%88%d8%b2%db%8c%d8%b9%e2%80%8c%d8%b4%d8%af%d9%87-%d9%85%d8%b4%d8%a7%d8%b1%da%a9%d8%aa-%d8%af%d8%b1-%db%8c%da%a9-%d9%be%d8%b1%d9%88%da%98%d9%87" dir="rtl">فارسی</a>,</td></tr> <tr><td><a href="/book/id/v2/Distributed-Git-Contributing-to-a-Project">Indonesian</a>,</td></tr> <tr><td><a href="/book/it/v2/Distributed-Git-Contributing-to-a-Project">Italiano</a>,</td></tr> <tr><td><a href="/book/ms/v2/Distributed-Git-Contributing-to-a-Project">Bahasa Melayu</a>,</td></tr> <tr><td><a href="/book/pt-br/v2/Distributed-Git-Contribuindo-com-um-Projeto">Português (Brasil)</a>,</td></tr> <tr><td><a href="/book/pt-pt/v2/Git-Distribu%c3%addo-Contributing-to-a-Project">Português (Portugal)</a>,</td></tr> <tr><td><a href="/book/sv/v2/Distribuerade-Git-Medverka-i-ett-projekt">Svenska</a>,</td></tr> <tr><td><a href="/book/tr/v2/Da%c4%9f%c4%b1t%c4%b1k-Git-Projenin-Geli%c5%9fiminde-Rol-Almak">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-id">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/id/v2/Memulai-Tentang-Version-Control">Memulai</a></h2> <ol> <li> 1.1 <a href="/book/id/v2/Memulai-Tentang-Version-Control">Tentang Version Control</a> </li> <li> 1.2 <a href="/book/id/v2/Memulai-Sejarah-Singkat-Git">Sejarah Singkat Git</a> </li> <li> 1.3 <a href="/book/id/v2/Memulai-Dasar-dasar-Git">Dasar-dasar Git</a> </li> <li> 1.4 <a href="/book/id/v2/Memulai-Command-Line">Command Line</a> </li> <li> 1.5 <a href="/book/id/v2/Memulai-Memasang-Git">Memasang Git</a> </li> <li> 1.6 <a href="/book/id/v2/Memulai-Pengaturan-Awal-Git">Pengaturan Awal Git</a> </li> <li> 1.7 <a href="/book/id/v2/Memulai-Mendapatkan-Bantuan">Mendapatkan Bantuan</a> </li> <li> 1.8 <a href="/book/id/v2/Memulai-Kesimpulan">Kesimpulan</a> </li> </ol> </li> <li class='chapter'> <h2>2. <a href="/book/id/v2/Git-Basics-Mendapatkan-Repository-Git">Git Basics</a></h2> <ol> <li> 2.1 <a href="/book/id/v2/Git-Basics-Mendapatkan-Repository-Git">Mendapatkan Repository Git</a> </li> <li> 2.2 <a href="/book/id/v2/Git-Basics-Recording-Changes-to-the-Repository">Recording Changes to the Repository</a> </li> <li> 2.3 <a href="/book/id/v2/Git-Basics-Viewing-the-Commit-History">Viewing the Commit History</a> </li> <li> 2.4 <a href="/book/id/v2/Git-Basics-Undoing-Things">Undoing Things</a> </li> <li> 2.5 <a href="/book/id/v2/Git-Basics-Working-with-Remotes">Working with Remotes</a> </li> <li> 2.6 <a href="/book/id/v2/Git-Basics-Tagging">Tagging</a> </li> <li> 2.7 <a href="/book/id/v2/Git-Basics-Alias-Git">Alias Git</a> </li> <li> 2.8 <a href="/book/id/v2/Git-Basics-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>3. <a href="/book/id/v2/Git-Branching-Branches-in-a-Nutshell">Git Branching</a></h2> <ol> <li> 3.1 <a href="/book/id/v2/Git-Branching-Branches-in-a-Nutshell">Branches in a Nutshell</a> </li> <li> 3.2 <a href="/book/id/v2/Git-Branching-Basic-Branching-and-Merging">Basic Branching and Merging</a> </li> <li> 3.3 <a href="/book/id/v2/Git-Branching-Branch-Management">Branch Management</a> </li> <li> 3.4 <a href="/book/id/v2/Git-Branching-Branching-Workflows">Branching Workflows</a> </li> <li> 3.5 <a href="/book/id/v2/Git-Branching-Remote-Branches">Remote Branches</a> </li> <li> 3.6 <a href="/book/id/v2/Git-Branching-Rebasing">Rebasing</a> </li> <li> 3.7 <a href="/book/id/v2/Git-Branching-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>4. <a href="/book/id/v2/Git-di-Server-Protokol">Git di Server</a></h2> <ol> <li> 4.1 <a href="/book/id/v2/Git-di-Server-Protokol">Protokol</a> </li> <li> 4.2 <a href="/book/id/v2/Git-di-Server-Getting-Git-on-a-Server">Getting Git on a Server</a> </li> <li> 4.3 <a href="/book/id/v2/Git-di-Server-Generating-Your-SSH-Public-Key">Generating Your SSH Public Key</a> </li> <li> 4.4 <a href="/book/id/v2/Git-di-Server-Setting-Up-the-Server">Setting Up the Server</a> </li> <li> 4.5 <a href="/book/id/v2/Git-di-Server-Git-Daemon">Git Daemon</a> </li> <li> 4.6 <a href="/book/id/v2/Git-di-Server-Smart-HTTP">Smart HTTP</a> </li> <li> 4.7 <a href="/book/id/v2/Git-di-Server-GitWeb">GitWeb</a> </li> <li> 4.8 <a href="/book/id/v2/Git-di-Server-GitLab">GitLab</a> </li> <li> 4.9 <a href="/book/id/v2/Git-di-Server-Third-Party-Hosted-Options">Third Party Hosted Options</a> </li> <li> 4.10 <a href="/book/id/v2/Git-di-Server-Ringkasan">Ringkasan</a> </li> </ol> </li> <li class='chapter'> <h2>5. <a href="/book/id/v2/Distributed-Git-Distributed-Workflows">Distributed Git</a></h2> <ol> <li> 5.1 <a href="/book/id/v2/Distributed-Git-Distributed-Workflows">Distributed Workflows</a> </li> <li> 5.2 <a href="/book/id/v2/Distributed-Git-Contributing-to-a-Project" class="active">Contributing to a Project</a> </li> <li> 5.3 <a href="/book/id/v2/Distributed-Git-Maintaining-a-Project">Maintaining a Project</a> </li> <li> 5.4 <a href="/book/id/v2/Distributed-Git-Summary">Summary</a> </li> </ol> </li> </ol> </div> <div class='column-middle'> <ol class='book-toc'> <li class='chapter'> <h2>6. <a href="/book/id/v2/GitHub-Pengaturan-dan-Konfigurasi-Akun">GitHub</a></h2> <ol> <li> 6.1 <a href="/book/id/v2/GitHub-Pengaturan-dan-Konfigurasi-Akun">Pengaturan dan Konfigurasi Akun</a> </li> <li> 6.2 <a href="/book/id/v2/GitHub-Contributing-to-a-Project">Contributing to a Project</a> </li> <li> 6.3 <a href="/book/id/v2/GitHub-Maintaining-a-Project">Maintaining a Project</a> </li> <li> 6.4 <a href="/book/id/v2/GitHub-Mengelola-Organization">Mengelola Organization</a> </li> <li> 6.5 <a href="/book/id/v2/GitHub-Scripting-GitHub">Scripting GitHub</a> </li> <li> 6.6 <a href="/book/id/v2/GitHub-Ringkasan">Ringkasan</a> </li> </ol> </li> <li class='chapter'> <h2>7. <a href="/book/id/v2/Git-Tools-Revision-Selection">Git Tools</a></h2> <ol> <li> 7.1 <a href="/book/id/v2/Git-Tools-Revision-Selection">Revision Selection</a> </li> <li> 7.2 <a href="/book/id/v2/Git-Tools-Interactive-Staging">Interactive Staging</a> </li> <li> 7.3 <a href="/book/id/v2/Git-Tools-Stashing-and-Cleaning">Stashing and Cleaning</a> </li> <li> 7.4 <a href="/book/id/v2/Git-Tools-Signing-Your-Work">Signing Your Work</a> </li> <li> 7.5 <a href="/book/id/v2/Git-Tools-Searching">Searching</a> </li> <li> 7.6 <a href="/book/id/v2/Git-Tools-Rewriting-History">Rewriting History</a> </li> <li> 7.7 <a href="/book/id/v2/Git-Tools-Reset-Demystified">Reset Demystified</a> </li> <li> 7.8 <a href="/book/id/v2/Git-Tools-Advanced-Merging">Advanced Merging</a> </li> <li> 7.9 <a href="/book/id/v2/Git-Tools-Rerere">Rerere</a> </li> <li> 7.10 <a href="/book/id/v2/Git-Tools-Debugging-with-Git">Debugging with Git</a> </li> <li> 7.11 <a href="/book/id/v2/Git-Tools-Submodules">Submodules</a> </li> <li> 7.12 <a href="/book/id/v2/Git-Tools-Bundling">Bundling</a> </li> <li> 7.13 <a href="/book/id/v2/Git-Tools-Replace">Replace</a> </li> <li> 7.14 <a href="/book/id/v2/Git-Tools-Credential-Storage">Credential Storage</a> </li> <li> 7.15 <a href="/book/id/v2/Git-Tools-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>8. <a href="/book/id/v2/Kostumisasi-Git-Konfigurasi-Git">Kostumisasi Git</a></h2> <ol> <li> 8.1 <a href="/book/id/v2/Kostumisasi-Git-Konfigurasi-Git">Konfigurasi Git</a> </li> <li> 8.2 <a href="/book/id/v2/Kostumisasi-Git-Git-Attributes">Git Attributes</a> </li> <li> 8.3 <a href="/book/id/v2/Kostumisasi-Git-Git-Hooks">Git Hooks</a> </li> <li> 8.4 <a href="/book/id/v2/Kostumisasi-Git-An-Example-Git-Enforced-Policy">An Example Git-Enforced Policy</a> </li> <li> 8.5 <a href="/book/id/v2/Kostumisasi-Git-Ringkasan">Ringkasan</a> </li> </ol> </li> <li class='chapter'> <h2>9. <a href="/book/id/v2/Git-and-Other-Systems-Git-as-a-Client">Git and Other Systems</a></h2> <ol> <li> 9.1 <a href="/book/id/v2/Git-and-Other-Systems-Git-as-a-Client">Git as a Client</a> </li> <li> 9.2 <a href="/book/id/v2/Git-and-Other-Systems-Migrating-to-Git">Migrating to Git</a> </li> <li> 9.3 <a href="/book/id/v2/Git-and-Other-Systems-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>10. <a href="/book/id/v2/Git-Internals-Plumbing-and-Porcelain">Git Internals</a></h2> <ol> <li> 10.1 <a href="/book/id/v2/Git-Internals-Plumbing-and-Porcelain">Plumbing and Porcelain</a> </li> <li> 10.2 <a href="/book/id/v2/Git-Internals-Git-Objects">Git Objects</a> </li> <li> 10.3 <a href="/book/id/v2/Git-Internals-Git-References">Git References</a> </li> <li> 10.4 <a href="/book/id/v2/Git-Internals-Packfiles">Packfiles</a> </li> <li> 10.5 <a href="/book/id/v2/Git-Internals-The-Refspec">The Refspec</a> </li> <li> 10.6 <a href="/book/id/v2/Git-Internals-Transfer-Protocols">Transfer Protocols</a> </li> <li> 10.7 <a href="/book/id/v2/Git-Internals-Maintenance-and-Data-Recovery">Maintenance and Data Recovery</a> </li> <li> 10.8 <a href="/book/id/v2/Git-Internals-Environment-Variables">Environment Variables</a> </li> <li> 10.9 <a href="/book/id/v2/Git-Internals-Summary">Summary</a> </li> </ol> </li> </ol> </div> <div class='column-right'> <ol class='book-toc'> <li class='chapter'> <h2>A1. <a href="/book/id/v2/Appendix-A:-Git-in-Other-Environments-Graphical-Interfaces">Appendix A: Git in Other Environments</a></h2> <ol> <li> A1.1 <a href="/book/id/v2/Appendix-A:-Git-in-Other-Environments-Graphical-Interfaces">Graphical Interfaces</a> </li> <li> A1.2 <a href="/book/id/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Visual-Studio">Git in Visual Studio</a> </li> <li> A1.3 <a href="/book/id/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Eclipse">Git in Eclipse</a> </li> <li> A1.4 <a href="/book/id/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Bash">Git in Bash</a> </li> <li> A1.5 <a href="/book/id/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Zsh">Git in Zsh</a> </li> <li> A1.6 <a href="/book/id/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Powershell">Git in Powershell</a> </li> <li> A1.7 <a href="/book/id/v2/Appendix-A:-Git-in-Other-Environments-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>A2. <a href="/book/id/v2/Appendix-B:-Embedding-Git-in-your-Applications-Command-line-Git">Appendix B: Embedding Git in your Applications</a></h2> <ol> <li> A2.1 <a href="/book/id/v2/Appendix-B:-Embedding-Git-in-your-Applications-Command-line-Git">Command-line Git</a> </li> <li> A2.2 <a href="/book/id/v2/Appendix-B:-Embedding-Git-in-your-Applications-Libgit2">Libgit2</a> </li> <li> A2.3 <a href="/book/id/v2/Appendix-B:-Embedding-Git-in-your-Applications-JGit">JGit</a> </li> </ol> </li> <li class='chapter'> <h2>A3. <a href="/book/id/v2/Appendix-C:-Git-Commands-Setup-and-Config">Appendix C: Git Commands</a></h2> <ol> <li> A3.1 <a href="/book/id/v2/Appendix-C:-Git-Commands-Setup-and-Config">Setup and Config</a> </li> <li> A3.2 <a href="/book/id/v2/Appendix-C:-Git-Commands-Getting-and-Creating-Projects">Getting and Creating Projects</a> </li> <li> A3.3 <a href="/book/id/v2/Appendix-C:-Git-Commands-Basic-Snapshotting">Basic Snapshotting</a> </li> <li> A3.4 <a href="/book/id/v2/Appendix-C:-Git-Commands-Branching-and-Merging">Branching and Merging</a> </li> <li> A3.5 <a href="/book/id/v2/Appendix-C:-Git-Commands-Sharing-and-Updating-Projects">Sharing and Updating Projects</a> </li> <li> A3.6 <a href="/book/id/v2/Appendix-C:-Git-Commands-Inspection-and-Comparison">Inspection and Comparison</a> </li> <li> A3.7 <a href="/book/id/v2/Appendix-C:-Git-Commands-Debugging">Debugging</a> </li> <li> A3.8 <a href="/book/id/v2/Appendix-C:-Git-Commands-Patching">Patching</a> </li> <li> A3.9 <a href="/book/id/v2/Appendix-C:-Git-Commands-Email">Email</a> </li> <li> A3.10 <a href="/book/id/v2/Appendix-C:-Git-Commands-External-Systems">External Systems</a> </li> <li> A3.11 <a href="/book/id/v2/Appendix-C:-Git-Commands-Administration">Administration</a> </li> <li> A3.12 <a href="/book/id/v2/Appendix-C:-Git-Commands-Plumbing-Commands">Plumbing Commands</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>5.2 Distributed Git - Contributing to a Project</h1> <div> <h2 id="_contributing_project">Contributing to a Project</h2> <div class="paragraph"> <p> The main difficulty with describing how to contribute to a project is that there are a huge number of variations on how it’s done. Because Git is very flexible, people can and do work together in many ways, and it’s problematic to describe how you should contribute – every project is a bit different. Some of the variables involved are active contributor count, chosen workflow, your commit access, and possibly the external contribution method.</p> </div> <div class="paragraph"> <p>The first variable is active contributor count – how many users are actively contributing code to this project, and how often? In many instances, you’ll have two or three developers with a few commits a day, or possibly less for somewhat dormant projects. For larger companies or projects, the number of developers could be in the thousands, with hundreds or thousands of commits coming in each day. This is important because with more and more developers, you run into more issues with making sure your code applies cleanly or can be easily merged. Changes you submit may be rendered obsolete or severely broken by work that is merged in while you were working or while your changes were waiting to be approved or applied. How can you keep your code consistently up to date and your commits valid?</p> </div> <div class="paragraph"> <p>The next variable is the workflow in use for the project. Is it centralized, with each developer having equal write access to the main codeline? Does the project have a maintainer or integration manager who checks all the patches? Are all the patches peer-reviewed and approved? Are you involved in that process? Is a lieutenant system in place, and do you have to submit your work to them first?</p> </div> <div class="paragraph"> <p>The next issue is your commit access. The workflow required in order to contribute to a project is much different if you have write access to the project than if you don’t. If you don’t have write access, how does the project prefer to accept contributed work? Does it even have a policy? How much work are you contributing at a time? How often do you contribute?</p> </div> <div class="paragraph"> <p>All these questions can affect how you contribute effectively to a project and what workflows are preferred or available to you. We’ll cover aspects of each of these in a series of use cases, moving from simple to more complex; you should be able to construct the specific workflows you need in practice from these examples.</p> </div> <div class="sect3"> <h3 id="_commit_guidelines">Commit Guidelines</h3> <div class="paragraph"> <p>Before we start looking at the specific use cases, here’s a quick note about commit messages. Having a good guideline for creating commits and sticking to it makes working with Git and collaborating with others a lot easier. The Git project provides a document that lays out a number of good tips for creating commits from which to submit patches – you can read it in the Git source code in the <code>Documentation/SubmittingPatches</code> file.</p> </div> <div class="paragraph"> <p> First, you don’t want to submit any whitespace errors. Git provides an easy way to check for this – before you commit, run <code>git diff --check</code>, which identifies possible whitespace errors and lists them for you.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/git-diff-check.png" alt="Output of `git diff -check`."> </div> <div class="title">Figure 57. Output of <code>git diff -check</code>.</div> </div> <div class="paragraph"> <p>If you run that command before committing, you can tell if you’re about to commit whitespace issues that may annoy other developers.</p> </div> <div class="paragraph"> <p>Next, try to make each commit a logically separate changeset. If you can, try to make your changes digestible – don’t code for a whole weekend on five different issues and then submit them all as one massive commit on Monday. Even if you don’t commit during the weekend, use the staging area on Monday to split your work into at least one commit per issue, with a useful message per commit. If some of the changes modify the same file, try to use <code>git add --patch</code> to partially stage files (covered in detail in <a href="/book/id/v2/ch00/_interactive_staging">Interactive Staging</a>). The project snapshot at the tip of the branch is identical whether you do one commit or five, as long as all the changes are added at some point, so try to make things easier on your fellow developers when they have to review your changes. This approach also makes it easier to pull out or revert one of the changesets if you need to later. <a href="/book/id/v2/ch00/_rewriting_history">Rewriting History</a> describes a number of useful Git tricks for rewriting history and interactively staging files – use these tools to help craft a clean and understandable history before sending the work to someone else.</p> </div> <div class="paragraph"> <p>The last thing to keep in mind is the commit message. Getting in the habit of creating quality commit messages makes using and collaborating with Git a lot easier. As a general rule, your messages should start with a single line that’s no more than about 50 characters and that describes the changeset concisely, followed by a blank line, followed by a more detailed explanation. The Git project requires that the more detailed explanation include your motivation for the change and contrast its implementation with previous behavior – this is a good guideline to follow. It’s also a good idea to use the imperative present tense in these messages. In other words, use commands. Instead of “I added tests for” or “Adding tests for,” use “Add tests for.” Here is a template originally written by Tim Pope:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-text" data-lang="text">Short (50 chars or less) summary of changes More detailed explanatory text, if necessary. Wrap it to about 72 characters or so. In some contexts, the first line is treated as the subject of an email and the rest of the text as the body. The blank line separating the summary from the body is critical (unless you omit the body entirely); tools like rebase can get confused if you run the two together. Further paragraphs come after blank lines. - Bullet points are okay, too - Typically a hyphen or asterisk is used for the bullet, preceded by a single space, with blank lines in between, but conventions vary here</code></pre> </div> </div> <div class="paragraph"> <p>If all your commit messages look like this, things will be a lot easier for you and the developers you work with. The Git project has well-formatted commit messages – try running <code>git log --no-merges</code> there to see what a nicely formatted project-commit history looks like.</p> </div> <div class="paragraph"> <p>In the following examples, and throughout most of this book, for the sake of brevity this book doesn’t have nicely-formatted messages like this; instead, we use the <code>-m</code> option to <code>git commit</code>. Do as we say, not as we do.</p> </div> </div> <div class="sect3"> <h3 id="_private_team">Private Small Team</h3> <div class="paragraph"> <p> The simplest setup you’re likely to encounter is a private project with one or two other developers. “Private,” in this context, means closed-source – not accessible to the outside world. You and the other developers all have push access to the repository.</p> </div> <div class="paragraph"> <p>In this environment, you can follow a workflow similar to what you might do when using Subversion or another centralized system. You still get the advantages of things like offline committing and vastly simpler branching and merging, but the workflow can be very similar; the main difference is that merges happen client-side rather than on the server at commit time. Let’s see what it might look like when two developers start to work together with a shared repository. The first developer, John, clones the repository, makes a change, and commits locally. (The protocol messages have been replaced with <code>...</code> in these examples to shorten them somewhat.)</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># John's Machine $ git clone john@githost:simplegit.git Initialized empty Git repository in /home/john/simplegit/.git/ ... $ cd simplegit/ $ vim lib/simplegit.rb $ git commit -am 'removed invalid default value' [master 738ee87] removed invalid default value 1 files changed, 1 insertions(+), 1 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>The second developer, Jessica, does the same thing – clones the repository and commits a change:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># Jessica's Machine $ git clone jessica@githost:simplegit.git Initialized empty Git repository in /home/jessica/simplegit/.git/ ... $ cd simplegit/ $ vim TODO $ git commit -am 'add reset task' [master fbff5bc] add reset task 1 files changed, 1 insertions(+), 0 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>Now, Jessica pushes her work up to the server:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># Jessica's Machine $ git push origin master ... To jessica@githost:simplegit.git 1edee6b..fbff5bc master -&gt; master</code></pre> </div> </div> <div class="paragraph"> <p>John tries to push his change up, too:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># John's Machine $ git push origin master To john@githost:simplegit.git ! [rejected] master -&gt; master (non-fast forward) error: failed to push some refs to 'john@githost:simplegit.git'</code></pre> </div> </div> <div class="paragraph"> <p>John isn’t allowed to push because Jessica has pushed in the meantime. This is especially important to understand if you’re used to Subversion, because you’ll notice that the two developers didn’t edit the same file. Although Subversion automatically does such a merge on the server if different files are edited, in Git you must merge the commits locally. John has to fetch Jessica’s changes and merge them in before he will be allowed to push:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git fetch origin ... From john@githost:simplegit + 049d078...fbff5bc master -&gt; origin/master</code></pre> </div> </div> <div class="paragraph"> <p>At this point, John’s local repository looks something like this:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/small-team-1.png" alt="John’s divergent history."> </div> <div class="title">Figure 58. John’s divergent history.</div> </div> <div class="paragraph"> <p>John has a reference to the changes Jessica pushed up, but he has to merge them into his own work before he is allowed to push:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git merge origin/master Merge made by recursive. TODO | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>The merge goes smoothly – John’s commit history now looks like this:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/small-team-2.png" alt="John’s repository after merging `origin/master`."> </div> <div class="title">Figure 59. John’s repository after merging <code>origin/master</code>.</div> </div> <div class="paragraph"> <p>Now, John can test his code to make sure it still works properly, and then he can push his new merged work up to the server:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push origin master ... To john@githost:simplegit.git fbff5bc..72bbc59 master -&gt; master</code></pre> </div> </div> <div class="paragraph"> <p>Finally, John’s commit history looks like this:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/small-team-3.png" alt="John’s history after pushing to the `origin` server."> </div> <div class="title">Figure 60. John’s history after pushing to the <code>origin</code> server.</div> </div> <div class="paragraph"> <p>In the meantime, Jessica has been working on a topic branch. She’s created a topic branch called <code>issue54</code> and done three commits on that branch. She hasn’t fetched John’s changes yet, so her commit history looks like this:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/small-team-4.png" alt="Jessica’s topic branch."> </div> <div class="title">Figure 61. Jessica’s topic branch.</div> </div> <div class="paragraph"> <p>Jessica wants to sync up with John, so she fetches:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># Jessica's Machine $ git fetch origin ... From jessica@githost:simplegit fbff5bc..72bbc59 master -&gt; origin/master</code></pre> </div> </div> <div class="paragraph"> <p>That pulls down the work John has pushed up in the meantime. Jessica’s history now looks like this:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/small-team-5.png" alt="Jessica’s history after fetching John’s changes."> </div> <div class="title">Figure 62. Jessica’s history after fetching John’s changes.</div> </div> <div class="paragraph"> <p>Jessica thinks her topic branch is ready, but she wants to know what she has to merge into her work so that she can push. She runs <code>git log</code> to find out:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git log --no-merges issue54..origin/master commit 738ee872852dfaa9d6634e0dea7a324040193016 Author: John Smith &lt;jsmith@example.com&gt; Date: Fri May 29 16:01:27 2009 -0700 removed invalid default value</code></pre> </div> </div> <div class="paragraph"> <p>The <code>issue54..origin/master</code> syntax is a log filter that asks Git to only show the list of commits that are on the latter branch (in this case <code>origin/master</code>) that are not on the first branch (in this case <code>issue54</code>). We’ll go over this syntax in detail in <a href="/book/id/v2/ch00/_commit_ranges">Commit Ranges</a>.</p> </div> <div class="paragraph"> <p>For now, we can see from the output that there is a single commit that John has made that Jessica has not merged in. If she merges <code>origin/master</code>, that is the single commit that will modify her local work.</p> </div> <div class="paragraph"> <p>Now, Jessica can merge her topic work into her master branch, merge John’s work (<code>origin/master</code>) into her <code>master</code> branch, and then push back to the server again. First, she switches back to her master branch to integrate all this work:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout master Switched to branch 'master' Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.</code></pre> </div> </div> <div class="paragraph"> <p>She can merge either <code>origin/master</code> or <code>issue54</code> first – they’re both upstream, so the order doesn’t matter. The end snapshot should be identical no matter which order she chooses; only the history will be slightly different. She chooses to merge in <code>issue54</code> first:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git merge issue54 Updating fbff5bc..4af4298 Fast forward README | 1 + lib/simplegit.rb | 6 +++++- 2 files changed, 6 insertions(+), 1 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>No problems occur; as you can see it was a simple fast-forward. Now Jessica merges in John’s work (<code>origin/master</code>):</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git merge origin/master Auto-merging lib/simplegit.rb Merge made by recursive. lib/simplegit.rb | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>Everything merges cleanly, and Jessica’s history looks like this:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/small-team-6.png" alt="Jessica’s history after merging John’s changes."> </div> <div class="title">Figure 63. Jessica’s history after merging John’s changes.</div> </div> <div class="paragraph"> <p>Now <code>origin/master</code> is reachable from Jessica’s <code>master</code> branch, so she should be able to successfully push (assuming John hasn’t pushed again in the meantime):</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push origin master ... To jessica@githost:simplegit.git 72bbc59..8059c15 master -&gt; master</code></pre> </div> </div> <div class="paragraph"> <p>Each developer has committed a few times and merged each other’s work successfully.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/small-team-7.png" alt="Jessica’s history after pushing all changes back to the server."> </div> <div class="title">Figure 64. Jessica’s history after pushing all changes back to the server.</div> </div> <div class="paragraph"> <p>That is one of the simplest workflows. You work for a while, generally in a topic branch, and merge into your master branch when it’s ready to be integrated. When you want to share that work, you merge it into your own master branch, then fetch and merge <code>origin/master</code> if it has changed, and finally push to the <code>master</code> branch on the server. The general sequence is something like this:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/small-team-flow.png" alt="General sequence of events for a simple multiple-developer Git workflow."> </div> <div class="title">Figure 65. General sequence of events for a simple multiple-developer Git workflow.</div> </div> </div> <div class="sect3"> <h3 id="_private_managed_team">Private Managed Team</h3> <div class="paragraph"> <p> In this next scenario, you’ll look at contributor roles in a larger private group. You’ll learn how to work in an environment where small groups collaborate on features and then those team-based contributions are integrated by another party.</p> </div> <div class="paragraph"> <p>Let’s say that John and Jessica are working together on one feature, while Jessica and Josie are working on a second. In this case, the company is using a type of integration-manager workflow where the work of the individual groups is integrated only by certain engineers, and the <code>master</code> branch of the main repo can be updated only by those engineers. In this scenario, all work is done in team-based branches and pulled together by the integrators later.</p> </div> <div class="paragraph"> <p>Let’s follow Jessica’s workflow as she works on her two features, collaborating in parallel with two different developers in this environment. Assuming she already has her repository cloned, she decides to work on <code>featureA</code> first. She creates a new branch for the feature and does some work on it there:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># Jessica's Machine $ git checkout -b featureA Switched to a new branch 'featureA' $ vim lib/simplegit.rb $ git commit -am 'add limit to log function' [featureA 3300904] add limit to log function 1 files changed, 1 insertions(+), 1 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>At this point, she needs to share her work with John, so she pushes her <code>featureA</code> branch commits up to the server. Jessica doesn’t have push access to the <code>master</code> branch – only the integrators do – so she has to push to another branch in order to collaborate with John:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push -u origin featureA ... To jessica@githost:simplegit.git * [new branch] featureA -&gt; featureA</code></pre> </div> </div> <div class="paragraph"> <p>Jessica e-mails John to tell him that she’s pushed some work into a branch named <code>featureA</code> and he can look at it now. While she waits for feedback from John, Jessica decides to start working on <code>featureB</code> with Josie. To begin, she starts a new feature branch, basing it off the server’s <code>master</code> branch:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># Jessica's Machine $ git fetch origin $ git checkout -b featureB origin/master Switched to a new branch 'featureB'</code></pre> </div> </div> <div class="paragraph"> <p>Now, Jessica makes a couple of commits on the <code>featureB</code> branch:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ vim lib/simplegit.rb $ git commit -am 'made the ls-tree function recursive' [featureB e5b0fdc] made the ls-tree function recursive 1 files changed, 1 insertions(+), 1 deletions(-) $ vim lib/simplegit.rb $ git commit -am 'add ls-files' [featureB 8512791] add ls-files 1 files changed, 5 insertions(+), 0 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>Jessica’s repository looks like this:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/managed-team-1.png" alt="Jessica’s initial commit history."> </div> <div class="title">Figure 66. Jessica’s initial commit history.</div> </div> <div class="paragraph"> <p>She’s ready to push up her work, but gets an e-mail from Josie that a branch with some initial work on it was already pushed to the server as <code>featureBee</code>. Jessica first needs to merge those changes in with her own before she can push to the server. She can then fetch Josie’s changes down with <code>git fetch</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git fetch origin ... From jessica@githost:simplegit * [new branch] featureBee -&gt; origin/featureBee</code></pre> </div> </div> <div class="paragraph"> <p>Jessica can now merge this into the work she did with <code>git merge</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git merge origin/featureBee Auto-merging lib/simplegit.rb Merge made by recursive. lib/simplegit.rb | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>There is a bit of a problem – she needs to push the merged work in her <code>featureB</code> branch to the <code>featureBee</code> branch on the server. She can do so by specifying the local branch followed by a colon (:) followed by the remote branch to the <code>git push</code> command:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push -u origin featureB:featureBee ... To jessica@githost:simplegit.git fba9af8..cd685d1 featureB -&gt; featureBee</code></pre> </div> </div> <div class="paragraph"> <p>This is called a <em>refspec</em>. See <a href="/book/id/v2/ch00/_refspec">The Refspec</a> for a more detailed discussion of Git refspecs and different things you can do with them. Also notice the <code>-u</code> flag; this is short for <code>--set-upstream</code>, which configures the branches for easier pushing and pulling later.</p> </div> <div class="paragraph"> <p>Next, John e-mails Jessica to say he’s pushed some changes to the <code>featureA</code> branch and ask her to verify them. She runs a <code>git fetch</code> to pull down those changes:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git fetch origin ... From jessica@githost:simplegit 3300904..aad881d featureA -&gt; origin/featureA</code></pre> </div> </div> <div class="paragraph"> <p>Then, she can see what has been changed with <code>git log</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git log featureA..origin/featureA commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6 Author: John Smith &lt;jsmith@example.com&gt; Date: Fri May 29 19:57:33 2009 -0700 changed log output to 30 from 25</code></pre> </div> </div> <div class="paragraph"> <p>Finally, she merges John’s work into her own <code>featureA</code> branch:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout featureA Switched to branch 'featureA' $ git merge origin/featureA Updating 3300904..aad881d Fast forward lib/simplegit.rb | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>Jessica wants to tweak something, so she commits again and then pushes this back up to the server:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git commit -am 'small tweak' [featureA 774b3ed] small tweak 1 files changed, 1 insertions(+), 1 deletions(-) $ git push ... To jessica@githost:simplegit.git 3300904..774b3ed featureA -&gt; featureA</code></pre> </div> </div> <div class="paragraph"> <p>Jessica’s commit history now looks something like this:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/managed-team-2.png" alt="Jessica’s history after committing on a feature branch."> </div> <div class="title">Figure 67. Jessica’s history after committing on a feature branch.</div> </div> <div class="paragraph"> <p>Jessica, Josie, and John inform the integrators that the <code>featureA</code> and <code>featureBee</code> branches on the server are ready for integration into the mainline. After the integrators merge these branches into the mainline, a fetch will bring down the new merge commit, making the history look like this:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/managed-team-3.png" alt="Jessica’s history after merging both her topic branches."> </div> <div class="title">Figure 68. Jessica’s history after merging both her topic branches.</div> </div> <div class="paragraph"> <p>Many groups switch to Git because of this ability to have multiple teams working in parallel, merging the different lines of work late in the process. The ability of smaller subgroups of a team to collaborate via remote branches without necessarily having to involve or impede the entire team is a huge benefit of Git. The sequence for the workflow you saw here is something like this:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/managed-team-flow.png" alt="Basic sequence of this managed-team workflow."> </div> <div class="title">Figure 69. Basic sequence of this managed-team workflow.</div> </div> </div> <div class="sect3"> <h3 id="_public_project">Forked Public Project</h3> <div class="paragraph"> <p> Contributing to public projects is a bit different. Because you don’t have the permissions to directly update branches on the project, you have to get the work to the maintainers some other way. This first example describes contributing via forking on Git hosts that support easy forking. Many hosting sites support this (including GitHub, BitBucket, Google Code, repo.or.cz, and others), and many project maintainers expect this style of contribution. The next section deals with projects that prefer to accept contributed patches via e-mail.</p> </div> <div class="paragraph"> <p>First, you’ll probably want to clone the main repository, create a topic branch for the patch or patch series you’re planning to contribute, and do your work there. The sequence looks basically like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git clone (url) $ cd project $ git checkout -b featureA # (work) $ git commit # (work) $ git commit</code></pre> </div> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">Note</div> </td> <td class="content"> <div class="paragraph"> <p>You may want to use <code>rebase -i</code> to squash your work down to a single commit, or rearrange the work in the commits to make the patch easier for the maintainer to review – see <a href="/book/id/v2/ch00/_rewriting_history">Rewriting History</a> for more information about interactive rebasing.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>When your branch work is finished and you’re ready to contribute it back to the maintainers, go to the original project page and click the “Fork” button, creating your own writable fork of the project. You then need to add in this new repository URL as a second remote, in this case named <code>myfork</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git remote add myfork (url)</code></pre> </div> </div> <div class="paragraph"> <p>Then you need to push your work up to it. It’s easiest to push the topic branch you’re working on up to your repository, rather than merging into your master branch and pushing that up. The reason is that if the work isn’t accepted or is cherry picked, you don’t have to rewind your master branch. If the maintainers merge, rebase, or cherry-pick your work, you’ll eventually get it back via pulling from their repository anyhow:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git push -u myfork featureA</code></pre> </div> </div> <div class="paragraph"> <p> When your work has been pushed up to your fork, you need to notify the maintainer. This is often called a pull request, and you can either generate it via the website – GitHub has it’s own Pull Request mechanism that we’ll go over in <a href="/book/id/v2/ch00/_github">GitHub</a> – or you can run the <code>git request-pull</code> command and e-mail the output to the project maintainer manually.</p> </div> <div class="paragraph"> <p>The <code>request-pull</code> command takes the base branch into which you want your topic branch pulled and the Git repository URL you want them to pull from, and outputs a summary of all the changes you’re asking to be pulled in. For instance, if Jessica wants to send John a pull request, and she’s done two commits on the topic branch she just pushed up, she can run this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git request-pull origin/master myfork The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40: John Smith (1): added a new function are available in the git repository at: git://githost/simplegit.git featureA Jessica Smith (2): add limit to log function change log output to 30 from 25 lib/simplegit.rb | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-)</code></pre> </div> </div> <div class="paragraph"> <p>The output can be sent to the maintainer–it tells them where the work was branched from, summarizes the commits, and tells where to pull this work from.</p> </div> <div class="paragraph"> <p>On a project for which you’re not the maintainer, it’s generally easier to have a branch like <code>master</code> always track <code>origin/master</code> and to do your work in topic branches that you can easily discard if they’re rejected. Having work themes isolated into topic branches also makes it easier for you to rebase your work if the tip of the main repository has moved in the meantime and your commits no longer apply cleanly. For example, if you want to submit a second topic of work to the project, don’t continue working on the topic branch you just pushed up – start over from the main repository’s <code>master</code> branch:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b featureB origin/master # (work) $ git commit $ git push myfork featureB # (email maintainer) $ git fetch origin</code></pre> </div> </div> <div class="paragraph"> <p>Now, each of your topics is contained within a silo – similar to a patch queue – that you can rewrite, rebase, and modify without the topics interfering or interdepending on each other, like so:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/public-small-1.png" alt="Initial commit history with `featureB` work."> </div> <div class="title">Figure 70. Initial commit history with <code>featureB</code> work.</div> </div> <div class="paragraph"> <p>Let’s say the project maintainer has pulled in a bunch of other patches and tried your first branch, but it no longer cleanly merges. In this case, you can try to rebase that branch on top of <code>origin/master</code>, resolve the conflicts for the maintainer, and then resubmit your changes:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout featureA $ git rebase origin/master $ git push -f myfork featureA</code></pre> </div> </div> <div class="paragraph"> <p>This rewrites your history to now look like <a href="/book/id/v2/ch00/psp_b">Commit history after <code>featureA</code> work.</a>.</p> </div> <div id="psp_b" class="imageblock"> <div class="content"> <img src="/book/id/v2/images/public-small-2.png" alt="Commit history after `featureA` work."> </div> <div class="title">Figure 71. Commit history after <code>featureA</code> work.</div> </div> <div class="paragraph"> <p>Because you rebased the branch, you have to specify the <code>-f</code> to your push command in order to be able to replace the <code>featureA</code> branch on the server with a commit that isn’t a descendant of it. An alternative would be to push this new work to a different branch on the server (perhaps called <code>featureAv2</code>).</p> </div> <div class="paragraph"> <p>Let’s look at one more possible scenario: the maintainer has looked at work in your second branch and likes the concept but would like you to change an implementation detail. You’ll also take this opportunity to move the work to be based off the project’s current <code>master</code> branch. You start a new branch based off the current <code>origin/master</code> branch, squash the <code>featureB</code> changes there, resolve any conflicts, make the implementation change, and then push that up as a new branch:</p> </div> <div class="paragraph"> <p></p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b featureBv2 origin/master $ git merge --no-commit --squash featureB # (change implementation) $ git commit $ git push myfork featureBv2</code></pre> </div> </div> <div class="paragraph"> <p>The <code>--squash</code> option takes all the work on the merged branch and squashes it into one non-merge commit on top of the branch you’re on. The <code>--no-commit</code> option tells Git not to automatically record a commit. This allows you to introduce all the changes from another branch and then make more changes before recording the new commit.</p> </div> <div class="paragraph"> <p>Now you can send the maintainer a message that you’ve made the requested changes and they can find those changes in your <code>featureBv2</code> branch.</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/id/v2/images/public-small-3.png" alt="Commit history after `featureBv2` work."> </div> <div class="title">Figure 72. Commit history after <code>featureBv2</code> work.</div> </div> </div> <div class="sect3"> <h3 id="_project_over_email">Public Project over E-Mail</h3> <div class="paragraph"> <p> Many projects have established procedures for accepting patches – you’ll need to check the specific rules for each project, because they will differ. Since there are several older, larger projects which accept patches via a developer mailing list, we’ll go over an example of that now.</p> </div> <div class="paragraph"> <p>The workflow is similar to the previous use case – you create topic branches for each patch series you work on. The difference is how you submit them to the project. Instead of forking the project and pushing to your own writable version, you generate e-mail versions of each commit series and e-mail them to the developer mailing list:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout -b topicA # (work) $ git commit # (work) $ git commit</code></pre> </div> </div> <div class="paragraph"> <p> Now you have two commits that you want to send to the mailing list. You use <code>git format-patch</code> to generate the mbox-formatted files that you can e-mail to the list – it turns each commit into an e-mail message with the first line of the commit message as the subject and the rest of the message plus the patch that the commit introduces as the body. The nice thing about this is that applying a patch from an e-mail generated with <code>format-patch</code> preserves all the commit information properly.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git format-patch -M origin/master 0001-add-limit-to-log-function.patch 0002-changed-log-output-to-30-from-25.patch</code></pre> </div> </div> <div class="paragraph"> <p>The <code>format-patch</code> command prints out the names of the patch files it creates. The <code>-M</code> switch tells Git to look for renames. The files end up looking like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ cat 0001-add-limit-to-log-function.patch From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001 From: Jessica Smith &lt;jessica@example.com&gt; Date: Sun, 6 Apr 2008 10:17:23 -0700 Subject: [PATCH 1/2] add limit to log function Limit log functionality to the first 20 --- lib/simplegit.rb | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/lib/simplegit.rb b/lib/simplegit.rb index 76f47bc..f9815f1 100644 --- a/lib/simplegit.rb +++ b/lib/simplegit.rb @@ -14,7 +14,7 @@ class SimpleGit end def log(treeish = 'master') - command("git log #{treeish}") + command("git log -n 20 #{treeish}") end def ls_tree(treeish = 'master') -- 2.1.0</code></pre> </div> </div> <div class="paragraph"> <p>You can also edit these patch files to add more information for the e-mail list that you don’t want to show up in the commit message. If you add text between the <code>---</code> line and the beginning of the patch (the <code>diff --git</code> line), then developers can read it; but applying the patch excludes it.</p> </div> <div class="paragraph"> <p>To e-mail this to a mailing list, you can either paste the file into your e-mail program or send it via a command-line program. Pasting the text often causes formatting issues, especially with “smarter” clients that don’t preserve newlines and other whitespace appropriately. Luckily, Git provides a tool to help you send properly formatted patches via IMAP, which may be easier for you. We’ll demonstrate how to send a patch via Gmail, which happens to be the e-mail agent we know best; you can read detailed instructions for a number of mail programs at the end of the aforementioned <code>Documentation/SubmittingPatches</code> file in the Git source code.</p> </div> <div class="paragraph"> <p> First, you need to set up the imap section in your <code>~/.gitconfig</code> file. You can set each value separately with a series of <code>git config</code> commands, or you can add them manually, but in the end your config file should look something like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-ini" data-lang="ini">[imap] folder = "[Gmail]/Drafts" host = imaps://imap.gmail.com user = user@gmail.com pass = p4ssw0rd port = 993 sslverify = false</code></pre> </div> </div> <div class="paragraph"> <p>If your IMAP server doesn’t use SSL, the last two lines probably aren’t necessary, and the host value will be <code>imap://</code> instead of <code>imaps://</code>. When that is set up, you can use <code>git send-email</code> to place the patch series in the Drafts folder of the specified IMAP server:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git send-email *.patch 0001-added-limit-to-log-function.patch 0002-changed-log-output-to-30-from-25.patch Who should the emails appear to be from? [Jessica Smith &lt;jessica@example.com&gt;] Emails will be sent from: Jessica Smith &lt;jessica@example.com&gt; Who should the emails be sent to? jessica@example.com Message-ID to be used as In-Reply-To for the first email? y</code></pre> </div> </div> <div class="paragraph"> <p>Then, Git spits out a bunch of log information looking something like this for each patch you’re sending:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-text" data-lang="text">(mbox) Adding cc: Jessica Smith &lt;jessica@example.com&gt; from \line 'From: Jessica Smith &lt;jessica@example.com&gt;' OK. Log says: Sendmail: /usr/sbin/sendmail -i jessica@example.com From: Jessica Smith &lt;jessica@example.com&gt; To: jessica@example.com Subject: [PATCH 1/2] added limit to log function Date: Sat, 30 May 2009 13:29:15 -0700 Message-Id: &lt;1243715356-61726-1-git-send-email-jessica@example.com&gt; X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty In-Reply-To: &lt;y&gt; References: &lt;y&gt; Result: OK</code></pre> </div> </div> <div class="paragraph"> <p>At this point, you should be able to go to your Drafts folder, change the To field to the mailing list you’re sending the patch to, possibly CC the maintainer or person responsible for that section, and send it off.</p> </div> </div> <div class="sect3"> <h3 id="_summary_3">Summary</h3> <div class="paragraph"> <p>This section has covered a number of common workflows for dealing with several very different types of Git projects you’re likely to encounter, and introduced a couple of new tools to help you manage this process. Next, you’ll see how to work the other side of the coin: maintaining a Git project. You’ll learn how to be a benevolent dictator or integration manager.</p> </div> </div> <div id="nav"><a href="/book/id/v2/Distributed-Git-Distributed-Workflows">prev</a> | <a href="/book/id/v2/Distributed-Git-Maintaining-a-Project">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