CINXE.COM
Git - 变基
<!DOCTYPE html> <html lang="zh"> <head> <meta charset='utf-8'> <meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible'> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Git - 变基</title> <link href="/favicon.ico" rel='shortcut icon' type='image/x-icon'> <link rel="stylesheet" href="/application.min.css"> <script src="/js/modernizr.js"></script> <script src="/js/modernize.js"></script> </head> <body id="documentation"> <div class="inner"> <header> <a href="/"><img src="/images/logo@2x.png" width="110" height="46" alt="Git" /></a> <span id="tagline"></span> <script type="text/javascript"> const taglines = [ "fast-version-control", "everything-is-local", "distributed-even-if-your-workflow-isnt", "local-branching-on-the-cheap", "distributed-is-the-new-centralized" ]; var tagline = taglines[Math.floor(Math.random() * taglines.length)]; document.getElementById('tagline').innerHTML = '--' + tagline; </script> <form id="search" action="/search/results"> <input id="search-text" name="search" placeholder="Type / to search entire site…" autocomplete="off" type="text" /> </form> <div id="search-results"></div> </header> </div> <div class="inner"> <div id="content-wrapper"> <div tabindex="1" class="sidebar-btn"></div> <aside class="sidebar" id="sidebar"> <nav> <ul> <li> <a href="/about">About</a> <ul> </ul> </li> <li> <a href="/doc" class="active">Documentation</a> <ul class="expanded"> <li> <a href="/docs">Reference</a> </li> <li> <a href="/book" class="active">Book</a> </li> <li> <a href="/videos">Videos</a> </li> <li> <a href="/doc/ext">External Links</a> </li> </ul> </li> <li> <a href="/downloads">Downloads</a> <ul > <li> <a href="/downloads/guis">GUI Clients</a> </li> <li> <a href="/downloads/logos">Logos</a> </li> </ul> </li> <li> <a href="/community">Community</a> </li> </ul> <hr class="sidebar"> <p> This book is available in <a href="/book/en/v2/Git-Branching-Rebasing">English</a>. </p> <p> Full translation available in <table> <tr><td><a href="/book/az/v2/Git%e2%80%99d%c9%99-Branch-Rebasing">azərbaycan dili</a>,</td></tr> <tr><td><a href="/book/bg/v2/%d0%9a%d0%bb%d0%be%d0%bd%d0%be%d0%b2%d0%b5-%d0%b2-Git-%d0%a3%d0%bf%d1%80%d0%b0%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%bd%d0%b0-%d0%bf%d1%80%d0%be%d0%b5%d0%ba%d1%82">български език</a>,</td></tr> <tr><td><a href="/book/de/v2/Git-Branching-Rebasing">Deutsch</a>,</td></tr> <tr><td><a href="/book/es/v2/Ramificaciones-en-Git-Reorganizar-el-Trabajo-Realizado">Español</a>,</td></tr> <tr><td><a href="/book/fr/v2/Les-branches-avec-Git-Rebaser-Rebasing">Français</a>,</td></tr> <tr><td><a href="/book/gr">Ελληνικά</a>,</td></tr> <tr><td><a href="/book/ja/v2/Git-%e3%81%ae%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81%e6%a9%9f%e8%83%bd-%e3%83%aa%e3%83%99%e3%83%bc%e3%82%b9">日本語</a>,</td></tr> <tr><td><a href="/book/ko/v2/Git-%eb%b8%8c%eb%9e%9c%ec%b9%98-Rebase-%ed%95%98%ea%b8%b0">한국어</a>,</td></tr> <tr><td><a href="/book/nl/v2/Branchen-in-Git-Rebasen">Nederlands</a>,</td></tr> <tr><td><a href="/book/ru/v2/%d0%92%d0%b5%d1%82%d0%b2%d0%bb%d0%b5%d0%bd%d0%b8%d0%b5-%d0%b2-Git-%d0%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>,</td></tr> <tr><td><a href="/book/sl/v2/Veje-Git-Ponovno-baziranje">Slovenščina</a>,</td></tr> <tr><td><a href="/book/tl/v2/Pag-branch-ng-Git-Pag-rebase">Tagalog</a>,</td></tr> <tr><td><a href="/book/uk/v2/%d0%93%d0%b0%d0%bb%d1%83%d0%b6%d0%b5%d0%bd%d0%bd%d1%8f-%d0%b2-git-%d0%9f%d0%b5%d1%80%d0%b5%d0%b1%d0%b0%d0%b7%d0%be%d0%b2%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f">Українська</a></td></tr> <tr><td><a href="/book/zh/v2/Git-%e5%88%86%e6%94%af-%e5%8f%98%e5%9f%ba">简体中文</a>,</td></tr> </table> </p> <p> Partial translations available in <table> <tr><td><a href="/book/cs/v2/V%c4%9btve-v-syst%c3%a9mu-Git-P%c5%99eskl%c3%a1d%c3%a1n%c3%ad">Čeština</a>,</td></tr> <tr><td><a href="/book/mk/v2/%d0%93%d1%80%d0%b0%d0%bd%d0%b5%d1%9a%d0%b5-%d0%b2%d0%be-Git-%d0%a0%d0%b5%d0%b1%d0%b0%d0%b7%d0%b0">Македонски</a>,</td></tr> <tr><td><a href="/book/pl/v2/Ga%c5%82%c4%99zie-Gita-Zmiana-bazy">Polski</a>,</td></tr> <tr><td><a href="/book/sr/v2/%d0%93%d1%80%d0%b0%d0%bd%d0%b0%d1%9a%d0%b5-%d1%83-%d0%bf%d1%80%d0%be%d0%b3%d1%80%d0%b0%d0%bc%d1%83-%d0%93%d0%b8%d1%82-%d0%a0%d0%b5%d0%b1%d0%b0%d0%b7%d0%b8%d1%80%d0%b0%d1%9a%d0%b5">Српски</a>,</td></tr> <tr><td><a href="/book/uz/v2/Git-%d0%b4%d0%b0-%d1%82%d0%b0%d1%80%d0%bc%d0%be%d2%9b%d0%bb%d0%b0%d0%bd%d0%b8%d1%88-%d2%9a%d0%b0%d0%b9%d1%82%d0%b0-%d0%b0%d1%81%d0%be%d1%81%d0%bb%d0%b0%d0%bd%d0%b8%d1%88">Ўзбекча</a>,</td></tr> <tr><td><a href="/book/zh-tw/v2/%e4%bd%bf%e7%94%a8-Git-%e5%88%86%e6%94%af-%e8%a1%8d%e5%90%88">繁體中文</a>,</td></tr> </table> </p> <p> Translations started for <table> <tr><td><a href="/book/be/v2/Git-Branching-Rebasing">Беларуская</a>,</td></tr> <tr><td><a href="/book/fa/v2/%d8%b4%d8%a7%d8%ae%d9%87%e2%80%8c%d8%b3%d8%a7%d8%b2%db%8c-%d8%af%d8%b1-%da%af%db%8c%d8%aa-%d8%b1%db%8c%d8%a8%db%8c%d8%b3%e2%80%8c%da%a9%d8%b1%d8%af%d9%86" dir="rtl">فارسی</a>,</td></tr> <tr><td><a href="/book/id/v2/Git-Branching-Rebasing">Indonesian</a>,</td></tr> <tr><td><a href="/book/it/v2/Git-Branching-Rebasing">Italiano</a>,</td></tr> <tr><td><a href="/book/ms/v2/Git-Branching-Rebasing">Bahasa Melayu</a>,</td></tr> <tr><td><a href="/book/pt-br/v2/Branches-no-Git-Rebase">Português (Brasil)</a>,</td></tr> <tr><td><a href="/book/pt-pt/v2/Ramifica%c3%a7%c3%a3o-do-Git-Rebasing">Português (Portugal)</a>,</td></tr> <tr><td><a href="/book/sv/v2/Git-f%c3%b6rgreningar-Grenflytt">Svenska</a>,</td></tr> <tr><td><a href="/book/tr/v2/Git-Dallar%c4%b1-Yeniden-Temelleme-rebase">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-zh">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/zh/v2/%e8%b5%b7%e6%ad%a5-%e5%85%b3%e4%ba%8e%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6">起步</a></h2> <ol> <li> 1.1 <a href="/book/zh/v2/%e8%b5%b7%e6%ad%a5-%e5%85%b3%e4%ba%8e%e7%89%88%e6%9c%ac%e6%8e%a7%e5%88%b6">关于版本控制</a> </li> <li> 1.2 <a href="/book/zh/v2/%e8%b5%b7%e6%ad%a5-Git-%e7%ae%80%e5%8f%b2">Git 简史</a> </li> <li> 1.3 <a href="/book/zh/v2/%e8%b5%b7%e6%ad%a5-Git-%e6%98%af%e4%bb%80%e4%b9%88%ef%bc%9f">Git 是什么?</a> </li> <li> 1.4 <a href="/book/zh/v2/%e8%b5%b7%e6%ad%a5-%e5%91%bd%e4%bb%a4%e8%a1%8c">命令行</a> </li> <li> 1.5 <a href="/book/zh/v2/%e8%b5%b7%e6%ad%a5-%e5%ae%89%e8%a3%85-Git">安装 Git</a> </li> <li> 1.6 <a href="/book/zh/v2/%e8%b5%b7%e6%ad%a5-%e5%88%9d%e6%ac%a1%e8%bf%90%e8%a1%8c-Git-%e5%89%8d%e7%9a%84%e9%85%8d%e7%bd%ae">初次运行 Git 前的配置</a> </li> <li> 1.7 <a href="/book/zh/v2/%e8%b5%b7%e6%ad%a5-%e8%8e%b7%e5%8f%96%e5%b8%ae%e5%8a%a9">获取帮助</a> </li> <li> 1.8 <a href="/book/zh/v2/%e8%b5%b7%e6%ad%a5-%e6%80%bb%e7%bb%93">总结</a> </li> </ol> </li> <li class='chapter'> <h2>2. <a href="/book/zh/v2/Git-%e5%9f%ba%e7%a1%80-%e8%8e%b7%e5%8f%96-Git-%e4%bb%93%e5%ba%93">Git 基础</a></h2> <ol> <li> 2.1 <a href="/book/zh/v2/Git-%e5%9f%ba%e7%a1%80-%e8%8e%b7%e5%8f%96-Git-%e4%bb%93%e5%ba%93">获取 Git 仓库</a> </li> <li> 2.2 <a href="/book/zh/v2/Git-%e5%9f%ba%e7%a1%80-%e8%ae%b0%e5%bd%95%e6%af%8f%e6%ac%a1%e6%9b%b4%e6%96%b0%e5%88%b0%e4%bb%93%e5%ba%93">记录每次更新到仓库</a> </li> <li> 2.3 <a href="/book/zh/v2/Git-%e5%9f%ba%e7%a1%80-%e6%9f%a5%e7%9c%8b%e6%8f%90%e4%ba%a4%e5%8e%86%e5%8f%b2">查看提交历史</a> </li> <li> 2.4 <a href="/book/zh/v2/Git-%e5%9f%ba%e7%a1%80-%e6%92%a4%e6%b6%88%e6%93%8d%e4%bd%9c">撤消操作</a> </li> <li> 2.5 <a href="/book/zh/v2/Git-%e5%9f%ba%e7%a1%80-%e8%bf%9c%e7%a8%8b%e4%bb%93%e5%ba%93%e7%9a%84%e4%bd%bf%e7%94%a8">远程仓库的使用</a> </li> <li> 2.6 <a href="/book/zh/v2/Git-%e5%9f%ba%e7%a1%80-%e6%89%93%e6%a0%87%e7%ad%be">打标签</a> </li> <li> 2.7 <a href="/book/zh/v2/Git-%e5%9f%ba%e7%a1%80-Git-%e5%88%ab%e5%90%8d">Git 别名</a> </li> <li> 2.8 <a href="/book/zh/v2/Git-%e5%9f%ba%e7%a1%80-%e6%80%bb%e7%bb%93">总结</a> </li> </ol> </li> <li class='chapter'> <h2>3. <a href="/book/zh/v2/Git-%e5%88%86%e6%94%af-%e5%88%86%e6%94%af%e7%ae%80%e4%bb%8b">Git 分支</a></h2> <ol> <li> 3.1 <a href="/book/zh/v2/Git-%e5%88%86%e6%94%af-%e5%88%86%e6%94%af%e7%ae%80%e4%bb%8b">分支简介</a> </li> <li> 3.2 <a href="/book/zh/v2/Git-%e5%88%86%e6%94%af-%e5%88%86%e6%94%af%e7%9a%84%e6%96%b0%e5%bb%ba%e4%b8%8e%e5%90%88%e5%b9%b6">分支的新建与合并</a> </li> <li> 3.3 <a href="/book/zh/v2/Git-%e5%88%86%e6%94%af-%e5%88%86%e6%94%af%e7%ae%a1%e7%90%86">分支管理</a> </li> <li> 3.4 <a href="/book/zh/v2/Git-%e5%88%86%e6%94%af-%e5%88%86%e6%94%af%e5%bc%80%e5%8f%91%e5%b7%a5%e4%bd%9c%e6%b5%81">分支开发工作流</a> </li> <li> 3.5 <a href="/book/zh/v2/Git-%e5%88%86%e6%94%af-%e8%bf%9c%e7%a8%8b%e5%88%86%e6%94%af">远程分支</a> </li> <li> 3.6 <a href="/book/zh/v2/Git-%e5%88%86%e6%94%af-%e5%8f%98%e5%9f%ba" class="active">变基</a> </li> <li> 3.7 <a href="/book/zh/v2/Git-%e5%88%86%e6%94%af-%e6%80%bb%e7%bb%93">总结</a> </li> </ol> </li> <li class='chapter'> <h2>4. <a href="/book/zh/v2/%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84-Git-%e5%8d%8f%e8%ae%ae">服务器上的 Git</a></h2> <ol> <li> 4.1 <a href="/book/zh/v2/%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84-Git-%e5%8d%8f%e8%ae%ae">协议</a> </li> <li> 4.2 <a href="/book/zh/v2/%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84-Git-%e5%9c%a8%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e6%90%ad%e5%bb%ba-Git">在服务器上搭建 Git</a> </li> <li> 4.3 <a href="/book/zh/v2/%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84-Git-%e7%94%9f%e6%88%90-SSH-%e5%85%ac%e9%92%a5">生成 SSH 公钥</a> </li> <li> 4.4 <a href="/book/zh/v2/%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84-Git-%e9%85%8d%e7%bd%ae%e6%9c%8d%e5%8a%a1%e5%99%a8">配置服务器</a> </li> <li> 4.5 <a href="/book/zh/v2/%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84-Git-Git-%e5%ae%88%e6%8a%a4%e8%bf%9b%e7%a8%8b">Git 守护进程</a> </li> <li> 4.6 <a href="/book/zh/v2/%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84-Git-Smart-HTTP">Smart HTTP</a> </li> <li> 4.7 <a href="/book/zh/v2/%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84-Git-GitWeb">GitWeb</a> </li> <li> 4.8 <a href="/book/zh/v2/%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84-Git-GitLab">GitLab</a> </li> <li> 4.9 <a href="/book/zh/v2/%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84-Git-%e7%ac%ac%e4%b8%89%e6%96%b9%e6%89%98%e7%ae%a1%e7%9a%84%e9%80%89%e6%8b%a9">第三方托管的选择</a> </li> <li> 4.10 <a href="/book/zh/v2/%e6%9c%8d%e5%8a%a1%e5%99%a8%e4%b8%8a%e7%9a%84-Git-%e6%80%bb%e7%bb%93">总结</a> </li> </ol> </li> <li class='chapter'> <h2>5. <a href="/book/zh/v2/%e5%88%86%e5%b8%83%e5%bc%8f-Git-%e5%88%86%e5%b8%83%e5%bc%8f%e5%b7%a5%e4%bd%9c%e6%b5%81%e7%a8%8b">分布式 Git</a></h2> <ol> <li> 5.1 <a href="/book/zh/v2/%e5%88%86%e5%b8%83%e5%bc%8f-Git-%e5%88%86%e5%b8%83%e5%bc%8f%e5%b7%a5%e4%bd%9c%e6%b5%81%e7%a8%8b">分布式工作流程</a> </li> <li> 5.2 <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> </li> <li> 5.3 <a href="/book/zh/v2/%e5%88%86%e5%b8%83%e5%bc%8f-Git-%e7%bb%b4%e6%8a%a4%e9%a1%b9%e7%9b%ae">维护项目</a> </li> <li> 5.4 <a href="/book/zh/v2/%e5%88%86%e5%b8%83%e5%bc%8f-Git-%e6%80%bb%e7%bb%93">总结</a> </li> </ol> </li> </ol> </div> <div class='column-middle'> <ol class='book-toc'> <li class='chapter'> <h2>6. <a href="/book/zh/v2/GitHub-%e8%b4%a6%e6%88%b7%e7%9a%84%e5%88%9b%e5%bb%ba%e5%92%8c%e9%85%8d%e7%bd%ae">GitHub</a></h2> <ol> <li> 6.1 <a href="/book/zh/v2/GitHub-%e8%b4%a6%e6%88%b7%e7%9a%84%e5%88%9b%e5%bb%ba%e5%92%8c%e9%85%8d%e7%bd%ae">账户的创建和配置</a> </li> <li> 6.2 <a href="/book/zh/v2/GitHub-%e5%af%b9%e9%a1%b9%e7%9b%ae%e5%81%9a%e5%87%ba%e8%b4%a1%e7%8c%ae">对项目做出贡献</a> </li> <li> 6.3 <a href="/book/zh/v2/GitHub-%e7%bb%b4%e6%8a%a4%e9%a1%b9%e7%9b%ae">维护项目</a> </li> <li> 6.4 <a href="/book/zh/v2/GitHub-%e7%ae%a1%e7%90%86%e7%bb%84%e7%bb%87">管理组织</a> </li> <li> 6.5 <a href="/book/zh/v2/GitHub-%e8%84%9a%e6%9c%ac-GitHub">脚本 GitHub</a> </li> <li> 6.6 <a href="/book/zh/v2/GitHub-%e6%80%bb%e7%bb%93">总结</a> </li> </ol> </li> <li class='chapter'> <h2>7. <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e9%80%89%e6%8b%a9%e4%bf%ae%e8%ae%a2%e7%89%88%e6%9c%ac">Git 工具</a></h2> <ol> <li> 7.1 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e9%80%89%e6%8b%a9%e4%bf%ae%e8%ae%a2%e7%89%88%e6%9c%ac">选择修订版本</a> </li> <li> 7.2 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e4%ba%a4%e4%ba%92%e5%bc%8f%e6%9a%82%e5%ad%98">交互式暂存</a> </li> <li> 7.3 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e8%b4%ae%e8%97%8f%e4%b8%8e%e6%b8%85%e7%90%86">贮藏与清理</a> </li> <li> 7.4 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e7%ad%be%e7%bd%b2%e5%b7%a5%e4%bd%9c">签署工作</a> </li> <li> 7.5 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e6%90%9c%e7%b4%a2">搜索</a> </li> <li> 7.6 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e9%87%8d%e5%86%99%e5%8e%86%e5%8f%b2">重写历史</a> </li> <li> 7.7 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e9%87%8d%e7%bd%ae%e6%8f%ad%e5%af%86">重置揭密</a> </li> <li> 7.8 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e9%ab%98%e7%ba%a7%e5%90%88%e5%b9%b6">高级合并</a> </li> <li> 7.9 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-Rerere">Rerere</a> </li> <li> 7.10 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e4%bd%bf%e7%94%a8-Git-%e8%b0%83%e8%af%95">使用 Git 调试</a> </li> <li> 7.11 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e5%ad%90%e6%a8%a1%e5%9d%97">子模块</a> </li> <li> 7.12 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e6%89%93%e5%8c%85">打包</a> </li> <li> 7.13 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e6%9b%bf%e6%8d%a2">替换</a> </li> <li> 7.14 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e5%87%ad%e8%af%81%e5%ad%98%e5%82%a8">凭证存储</a> </li> <li> 7.15 <a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e6%80%bb%e7%bb%93">总结</a> </li> </ol> </li> <li class='chapter'> <h2>8. <a href="/book/zh/v2/%e8%87%aa%e5%ae%9a%e4%b9%89-Git-%e9%85%8d%e7%bd%ae-Git">自定义 Git</a></h2> <ol> <li> 8.1 <a href="/book/zh/v2/%e8%87%aa%e5%ae%9a%e4%b9%89-Git-%e9%85%8d%e7%bd%ae-Git">配置 Git</a> </li> <li> 8.2 <a href="/book/zh/v2/%e8%87%aa%e5%ae%9a%e4%b9%89-Git-Git-%e5%b1%9e%e6%80%a7">Git 属性</a> </li> <li> 8.3 <a href="/book/zh/v2/%e8%87%aa%e5%ae%9a%e4%b9%89-Git-Git-%e9%92%a9%e5%ad%90">Git 钩子</a> </li> <li> 8.4 <a href="/book/zh/v2/%e8%87%aa%e5%ae%9a%e4%b9%89-Git-%e4%bd%bf%e7%94%a8%e5%bc%ba%e5%88%b6%e7%ad%96%e7%95%a5%e7%9a%84%e4%b8%80%e4%b8%aa%e4%be%8b%e5%ad%90">使用强制策略的一个例子</a> </li> <li> 8.5 <a href="/book/zh/v2/%e8%87%aa%e5%ae%9a%e4%b9%89-Git-%e6%80%bb%e7%bb%93">总结</a> </li> </ol> </li> <li class='chapter'> <h2>9. <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">Git 与其他系统</a></h2> <ol> <li> 9.1 <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">作为客户端的 Git</a> </li> <li> 9.2 <a href="/book/zh/v2/Git-%e4%b8%8e%e5%85%b6%e4%bb%96%e7%b3%bb%e7%bb%9f-%e8%bf%81%e7%a7%bb%e5%88%b0-Git">迁移到 Git</a> </li> <li> 9.3 <a href="/book/zh/v2/Git-%e4%b8%8e%e5%85%b6%e4%bb%96%e7%b3%bb%e7%bb%9f-%e6%80%bb%e7%bb%93">总结</a> </li> </ol> </li> <li class='chapter'> <h2>10. <a href="/book/zh/v2/Git-%e5%86%85%e9%83%a8%e5%8e%9f%e7%90%86-%e5%ba%95%e5%b1%82%e5%91%bd%e4%bb%a4%e4%b8%8e%e4%b8%8a%e5%b1%82%e5%91%bd%e4%bb%a4">Git 内部原理</a></h2> <ol> <li> 10.1 <a href="/book/zh/v2/Git-%e5%86%85%e9%83%a8%e5%8e%9f%e7%90%86-%e5%ba%95%e5%b1%82%e5%91%bd%e4%bb%a4%e4%b8%8e%e4%b8%8a%e5%b1%82%e5%91%bd%e4%bb%a4">底层命令与上层命令</a> </li> <li> 10.2 <a href="/book/zh/v2/Git-%e5%86%85%e9%83%a8%e5%8e%9f%e7%90%86-Git-%e5%af%b9%e8%b1%a1">Git 对象</a> </li> <li> 10.3 <a href="/book/zh/v2/Git-%e5%86%85%e9%83%a8%e5%8e%9f%e7%90%86-Git-%e5%bc%95%e7%94%a8">Git 引用</a> </li> <li> 10.4 <a href="/book/zh/v2/Git-%e5%86%85%e9%83%a8%e5%8e%9f%e7%90%86-%e5%8c%85%e6%96%87%e4%bb%b6">包文件</a> </li> <li> 10.5 <a href="/book/zh/v2/Git-%e5%86%85%e9%83%a8%e5%8e%9f%e7%90%86-%e5%bc%95%e7%94%a8%e8%a7%84%e8%8c%83">引用规范</a> </li> <li> 10.6 <a href="/book/zh/v2/Git-%e5%86%85%e9%83%a8%e5%8e%9f%e7%90%86-%e4%bc%a0%e8%be%93%e5%8d%8f%e8%ae%ae">传输协议</a> </li> <li> 10.7 <a href="/book/zh/v2/Git-%e5%86%85%e9%83%a8%e5%8e%9f%e7%90%86-%e7%bb%b4%e6%8a%a4%e4%b8%8e%e6%95%b0%e6%8d%ae%e6%81%a2%e5%a4%8d">维护与数据恢复</a> </li> <li> 10.8 <a href="/book/zh/v2/Git-%e5%86%85%e9%83%a8%e5%8e%9f%e7%90%86-%e7%8e%af%e5%a2%83%e5%8f%98%e9%87%8f">环境变量</a> </li> <li> 10.9 <a href="/book/zh/v2/Git-%e5%86%85%e9%83%a8%e5%8e%9f%e7%90%86-%e6%80%bb%e7%bb%93">总结</a> </li> </ol> </li> </ol> </div> <div class='column-right'> <ol class='book-toc'> <li class='chapter'> <h2>A1. <a href="/book/zh/v2/%e9%99%84%e5%bd%95-A:-%e5%9c%a8%e5%85%b6%e5%ae%83%e7%8e%af%e5%a2%83%e4%b8%ad%e4%bd%bf%e7%94%a8-Git-%e5%9b%be%e5%bd%a2%e7%95%8c%e9%9d%a2">附录 A: 在其它环境中使用 Git</a></h2> <ol> <li> A1.1 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-A:-%e5%9c%a8%e5%85%b6%e5%ae%83%e7%8e%af%e5%a2%83%e4%b8%ad%e4%bd%bf%e7%94%a8-Git-%e5%9b%be%e5%bd%a2%e7%95%8c%e9%9d%a2">图形界面</a> </li> <li> A1.2 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-A:-%e5%9c%a8%e5%85%b6%e5%ae%83%e7%8e%af%e5%a2%83%e4%b8%ad%e4%bd%bf%e7%94%a8-Git-Visual-Studio-%e4%b8%ad%e7%9a%84-Git">Visual Studio 中的 Git</a> </li> <li> A1.3 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-A:-%e5%9c%a8%e5%85%b6%e5%ae%83%e7%8e%af%e5%a2%83%e4%b8%ad%e4%bd%bf%e7%94%a8-Git-Visual-Studio-Code-%e4%b8%ad%e7%9a%84-Git">Visual Studio Code 中的 Git</a> </li> <li> A1.4 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-A:-%e5%9c%a8%e5%85%b6%e5%ae%83%e7%8e%af%e5%a2%83%e4%b8%ad%e4%bd%bf%e7%94%a8-Git-IntelliJ-/-PyCharm-/-WebStorm-/-PhpStorm-/-RubyMine-%e4%b8%ad%e7%9a%84-Git">IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine 中的 Git</a> </li> <li> A1.5 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-A:-%e5%9c%a8%e5%85%b6%e5%ae%83%e7%8e%af%e5%a2%83%e4%b8%ad%e4%bd%bf%e7%94%a8-Git-Sublime-Text-%e4%b8%ad%e7%9a%84-Git">Sublime Text 中的 Git</a> </li> <li> A1.6 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-A:-%e5%9c%a8%e5%85%b6%e5%ae%83%e7%8e%af%e5%a2%83%e4%b8%ad%e4%bd%bf%e7%94%a8-Git-Bash-%e4%b8%ad%e7%9a%84-Git">Bash 中的 Git</a> </li> <li> A1.7 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-A:-%e5%9c%a8%e5%85%b6%e5%ae%83%e7%8e%af%e5%a2%83%e4%b8%ad%e4%bd%bf%e7%94%a8-Git-Zsh-%e4%b8%ad%e7%9a%84-Git">Zsh 中的 Git</a> </li> <li> A1.8 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-A:-%e5%9c%a8%e5%85%b6%e5%ae%83%e7%8e%af%e5%a2%83%e4%b8%ad%e4%bd%bf%e7%94%a8-Git-Git-%e5%9c%a8-PowerShell-%e4%b8%ad%e4%bd%bf%e7%94%a8-Git">Git 在 PowerShell 中使用 Git</a> </li> <li> A1.9 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-A:-%e5%9c%a8%e5%85%b6%e5%ae%83%e7%8e%af%e5%a2%83%e4%b8%ad%e4%bd%bf%e7%94%a8-Git-%e6%80%bb%e7%bb%93">总结</a> </li> </ol> </li> <li class='chapter'> <h2>A2. <a href="/book/zh/v2/%e9%99%84%e5%bd%95-B:-%e5%9c%a8%e4%bd%a0%e7%9a%84%e5%ba%94%e7%94%a8%e4%b8%ad%e5%b5%8c%e5%85%a5-Git-%e5%91%bd%e4%bb%a4%e8%a1%8c-Git-%e6%96%b9%e5%bc%8f">附录 B: 在你的应用中嵌入 Git</a></h2> <ol> <li> A2.1 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-B:-%e5%9c%a8%e4%bd%a0%e7%9a%84%e5%ba%94%e7%94%a8%e4%b8%ad%e5%b5%8c%e5%85%a5-Git-%e5%91%bd%e4%bb%a4%e8%a1%8c-Git-%e6%96%b9%e5%bc%8f">命令行 Git 方式</a> </li> <li> A2.2 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-B:-%e5%9c%a8%e4%bd%a0%e7%9a%84%e5%ba%94%e7%94%a8%e4%b8%ad%e5%b5%8c%e5%85%a5-Git-Libgit2">Libgit2</a> </li> <li> A2.3 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-B:-%e5%9c%a8%e4%bd%a0%e7%9a%84%e5%ba%94%e7%94%a8%e4%b8%ad%e5%b5%8c%e5%85%a5-Git-JGit">JGit</a> </li> <li> A2.4 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-B:-%e5%9c%a8%e4%bd%a0%e7%9a%84%e5%ba%94%e7%94%a8%e4%b8%ad%e5%b5%8c%e5%85%a5-Git-go-git">go-git</a> </li> <li> A2.5 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-B:-%e5%9c%a8%e4%bd%a0%e7%9a%84%e5%ba%94%e7%94%a8%e4%b8%ad%e5%b5%8c%e5%85%a5-Git-Dulwich">Dulwich</a> </li> </ol> </li> <li class='chapter'> <h2>A3. <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e8%ae%be%e7%bd%ae%e4%b8%8e%e9%85%8d%e7%bd%ae">附录 C: Git 命令</a></h2> <ol> <li> A3.1 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e8%ae%be%e7%bd%ae%e4%b8%8e%e9%85%8d%e7%bd%ae">设置与配置</a> </li> <li> A3.2 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e8%8e%b7%e5%8f%96%e4%b8%8e%e5%88%9b%e5%bb%ba%e9%a1%b9%e7%9b%ae">获取与创建项目</a> </li> <li> A3.3 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e5%bf%ab%e7%85%a7%e5%9f%ba%e7%a1%80">快照基础</a> </li> <li> A3.4 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e5%88%86%e6%94%af%e4%b8%8e%e5%90%88%e5%b9%b6">分支与合并</a> </li> <li> A3.5 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e9%a1%b9%e7%9b%ae%e5%88%86%e4%ba%ab%e4%b8%8e%e6%9b%b4%e6%96%b0">项目分享与更新</a> </li> <li> A3.6 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e6%a3%80%e6%9f%a5%e4%b8%8e%e6%af%94%e8%be%83">检查与比较</a> </li> <li> A3.7 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e8%b0%83%e8%af%95">调试</a> </li> <li> A3.8 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e8%a1%a5%e4%b8%81">补丁</a> </li> <li> A3.9 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e9%82%ae%e4%bb%b6">邮件</a> </li> <li> A3.10 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e5%a4%96%e9%83%a8%e7%b3%bb%e7%bb%9f">外部系统</a> </li> <li> A3.11 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e7%ae%a1%e7%90%86">管理</a> </li> <li> A3.12 <a href="/book/zh/v2/%e9%99%84%e5%bd%95-C:-Git-%e5%91%bd%e4%bb%a4-%e5%ba%95%e5%b1%82%e5%91%bd%e4%bb%a4">底层命令</a> </li> </ol> </li> </ol> </div> </div> </div> <span class="light" id="edition"> 2nd Edition </span> </div> <div id="main" data-pagefind-filter="category:book" data-pagefind-meta="category:Book" data-pagefind-weight="0.05" data-pagefind-body class="book edition2"> <h1>3.6 Git 分支 - 变基</h1> <div> <h2 id="_rebasing">变基</h2> <div class="paragraph"> <p> 在 Git 中整合来自不同分支的修改主要有两种方法:<code>merge</code> 以及 <code>rebase</code>。 在本节中我们将学习什么是“变基”,怎样使用“变基”,并将展示该操作的惊艳之处,以及指出在何种情况下你应避免使用它。</p> </div> <div class="sect3"> <h3 id="_变基的基本操作">变基的基本操作</h3> <div class="paragraph"> <p>请回顾之前在 <a href="/book/zh/v2/ch00/_basic_merging">分支的合并</a> 中的一个例子,你会看到开发任务分叉到两个不同分支,又各自提交了更新。</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/basic-rebase-1.png" alt="分叉的提交历史。"> </div> <div class="title">Figure 35. 分叉的提交历史</div> </div> <div class="paragraph"> <p>之前介绍过,整合分支最容易的方法是 <code>merge</code> 命令。 它会把两个分支的最新快照(<code>C3</code> 和 <code>C4</code>)以及二者最近的共同祖先(<code>C2</code>)进行三方合并,合并的结果是生成一个新的快照(并提交)。</p> </div> <div id="ebasing-merging-example" class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/basic-rebase-2.png" alt="通过合并操作来整合分叉了的历史。"> </div> <div class="title">Figure 36. 通过合并操作来整合分叉的历史</div> </div> <div class="paragraph"> <p>其实,还有一种方法:你可以提取在 <code>C4</code> 中引入的补丁和修改,然后在 <code>C3</code> 的基础上应用一次。 在 Git 中,这种操作就叫做 <strong>变基(rebase)</strong>。 你可以使用 <code>rebase</code> 命令将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。</p> </div> <div class="paragraph"> <p>在这个例子中,你可以检出 <code>experiment</code> 分支,然后将它变基到 <code>master</code> 分支上:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout experiment $ git rebase master First, rewinding head to replay your work on top of it... Applying: added staged command</code></pre> </div> </div> <div class="paragraph"> <p>它的原理是首先找到这两个分支(即当前分支 <code>experiment</code>、变基操作的目标基底分支 <code>master</code>) 的最近共同祖先 <code>C2</code>,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支指向目标基底 <code>C3</code>, 最后以此将之前另存为临时文件的修改依序应用。 (译注:写明了 commit id,以便理解,下同)</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/basic-rebase-3.png" alt="将 `C4` 中的修改变基到 `C3` 上。"> </div> <div class="title">Figure 37. 将 <code>C4</code> 中的修改变基到 <code>C3</code> 上</div> </div> <div class="paragraph"> <p>现在回到 <code>master</code> 分支,进行一次快进合并。</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout master $ git merge experiment</code></pre> </div> </div> <div class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/basic-rebase-4.png" alt="`master` 分支的快进合并。"> </div> <div class="title">Figure 38. <code>master</code> 分支的快进合并</div> </div> <div class="paragraph"> <p>此时,<code>C4'</code> 指向的快照就和 <a href="/book/zh/v2/ch00/ebasing-merging-example">the merge example</a> 中 <code>C5</code> 指向的快照一模一样了。 这两种整合方法的最终结果没有任何区别,但是变基使得提交历史更加整洁。 你在查看一个经过变基的分支的历史记录时会发现,尽管实际的开发工作是并行的, 但它们看上去就像是串行的一样,提交历史是一条直线没有分叉。</p> </div> <div class="paragraph"> <p>一般我们这样做的目的是为了确保在向远程分支推送时能保持提交历史的整洁——例如向某个其他人维护的项目贡献代码时。 在这种情况下,你首先在自己的分支里进行开发,当开发完成时你需要先将你的代码变基到 <code>origin/master</code> 上,然后再向主项目提交修改。 这样的话,该项目的维护者就不再需要进行整合工作,只需要快进合并便可。</p> </div> <div class="paragraph"> <p>请注意,无论是通过变基,还是通过三方合并,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。 变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。</p> </div> </div> <div class="sect3"> <h3 id="_更有趣的变基例子">更有趣的变基例子</h3> <div class="paragraph"> <p>在对两个分支进行变基时,所生成的“重放”并不一定要在目标分支上应用,你也可以指定另外的一个分支进行应用。 就像 <a href="/book/zh/v2/ch00/bdiag_e">从一个主题分支里再分出一个主题分支的提交历史</a> 中的例子那样。 你创建了一个主题分支 <code>server</code>,为服务端添加了一些功能,提交了 <code>C3</code> 和 <code>C4</code>。 然后从 <code>C3</code> 上创建了主题分支 <code>client</code>,为客户端添加了一些功能,提交了 <code>C8</code> 和 <code>C9</code>。 最后,你回到 <code>server</code> 分支,又提交了 <code>C10</code>。</p> </div> <div id="bdiag_e" class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/interesting-rebase-1.png" alt="从一个主题分支里再分出一个主题分支的提交历史。"> </div> <div class="title">Figure 39. 从一个主题分支里再分出一个主题分支的提交历史</div> </div> <div class="paragraph"> <p>假设你希望将 <code>client</code> 中的修改合并到主分支并发布,但暂时并不想合并 <code>server</code> 中的修改, 因为它们还需要经过更全面的测试。这时,你就可以使用 <code>git rebase</code> 命令的 <code>--onto</code> 选项, 选中在 <code>client</code> 分支里但不在 <code>server</code> 分支里的修改(即 <code>C8</code> 和 <code>C9</code>),将它们在 <code>master</code> 分支上重放:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git rebase --onto master server client</code></pre> </div> </div> <div class="paragraph"> <p>以上命令的意思是:“取出 <code>client</code> 分支,找出它从 <code>server</code> 分支分歧之后的补丁, 然后把这些补丁在 <code>master</code> 分支上重放一遍,让 <code>client</code> 看起来像直接基于 <code>master</code> 修改一样”。这理解起来有一点复杂,不过效果非常酷。</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/interesting-rebase-2.png" alt="截取主题分支上的另一个主题分支,然后变基到其他分支。"> </div> <div class="title">Figure 40. 截取主题分支上的另一个主题分支,然后变基到其他分支</div> </div> <div class="paragraph"> <p>现在可以快进合并 <code>master</code> 分支了。(如图 <a href="/book/zh/v2/ch00/bdiag_g">快进合并 <code>master</code> 分支,使之包含来自 <code>client</code> 分支的修改</a>):</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout master $ git merge client</code></pre> </div> </div> <div id="bdiag_g" class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/interesting-rebase-3.png" alt="快进合并 `master` 分支,使之包含来自 `client` 分支的修改。"> </div> <div class="title">Figure 41. 快进合并 <code>master</code> 分支,使之包含来自 <code>client</code> 分支的修改</div> </div> <div class="paragraph"> <p>接下来你决定将 <code>server</code> 分支中的修改也整合进来。 使用 <code>git rebase <basebranch> <topicbranch></code> 命令可以直接将主题分支 (即本例中的 <code>server</code>)变基到目标分支(即 <code>master</code>)上。 这样做能省去你先切换到 <code>server</code> 分支,再对其执行变基命令的多个步骤。</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git rebase master server</code></pre> </div> </div> <div class="paragraph"> <p>如图 <a href="/book/zh/v2/ch00/bdiag_h">将 <code>server</code> 中的修改变基到 <code>master</code> 上</a> 所示,<code>server</code> 中的代码被“续”到了 <code>master</code> 后面。</p> </div> <div id="bdiag_h" class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/interesting-rebase-4.png" alt="将 `server` 中的修改变基到 `master` 上。"> </div> <div class="title">Figure 42. 将 <code>server</code> 中的修改变基到 <code>master</code> 上</div> </div> <div class="paragraph"> <p>然后就可以快进合并主分支 <code>master</code> 了:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git checkout master $ git merge server</code></pre> </div> </div> <div class="paragraph"> <p>至此,<code>client</code> 和 <code>server</code> 分支中的修改都已经整合到主分支里了, 你可以删除这两个分支,最终提交历史会变成图 <a href="/book/zh/v2/ch00/bdiag_i">最终的提交历史</a> 中的样子:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git branch -d client $ git branch -d server</code></pre> </div> </div> <div id="bdiag_i" class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/interesting-rebase-5.png" alt="最终的提交历史。"> </div> <div class="title">Figure 43. 最终的提交历史</div> </div> </div> <div class="sect3"> <h3 id="_rebase_peril">变基的风险</h3> <div class="paragraph"> <p> 呃,奇妙的变基也并非完美无缺,要用它得遵守一条准则:</p> </div> <div class="paragraph"> <p><strong>如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。</strong></p> </div> <div class="paragraph"> <p>如果你遵循这条金科玉律,就不会出差错。 否则,人民群众会仇恨你,你的朋友和家人也会嘲笑你,唾弃你。</p> </div> <div class="paragraph"> <p>变基操作的实质是丢弃一些现有的提交,然后相应地新建一些内容一样但实际上不同的提交。 如果你已经将提交推送至某个仓库,而其他人也已经从该仓库拉取提交并进行了后续工作,此时,如果你用 <code>git rebase</code> 命令重新整理了提交并再次推送,你的同伴因此将不得不再次将他们手头的工作与你的提交进行整合,如果接下来你还要拉取并整合他们修改过的提交,事情就会变得一团糟。</p> </div> <div class="paragraph"> <p>让我们来看一个在公开的仓库上执行变基操作所带来的问题。 假设你从一个中央服务器克隆然后在它的基础上进行了一些开发。 你的提交历史如图所示:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/perils-of-rebasing-1.png" alt="克隆一个仓库,然后在它的基础上进行了一些开发。"> </div> <div class="title">Figure 44. 克隆一个仓库,然后在它的基础上进行了一些开发</div> </div> <div class="paragraph"> <p>然后,某人又向中央服务器提交了一些修改,其中还包括一次合并。 你抓取了这些在远程分支上的修改,并将其合并到你本地的开发分支,然后你的提交历史就会变成这样:</p> </div> <div class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/perils-of-rebasing-2.png" alt="抓取别人的提交,合并到自己的开发分支。"> </div> <div class="title">Figure 45. 抓取别人的提交,合并到自己的开发分支</div> </div> <div class="paragraph"> <p>接下来,这个人又决定把合并操作回滚,改用变基;继而又用 <code>git push --force</code> 命令覆盖了服务器上的提交历史。 之后你从服务器抓取更新,会发现多出来一些新的提交。</p> </div> <div id="_pre_merge_rebase_work" class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/perils-of-rebasing-3.png" alt="有人推送了经过变基的提交,并丢弃了你的本地开发所基于的一些提交。"> </div> <div class="title">Figure 46. 有人推送了经过变基的提交,并丢弃了你的本地开发所基于的一些提交</div> </div> <div class="paragraph"> <p>结果就是你们两人的处境都十分尴尬。 如果你执行 <code>git pull</code> 命令,你将合并来自两条提交历史的内容,生成一个新的合并提交,最终仓库会如图所示:</p> </div> <div id="_merge_rebase_work" class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/perils-of-rebasing-4.png" alt="你将相同的内容又合并了一次,生成了一个新的提交。"> </div> <div class="title">Figure 47. 你将相同的内容又合并了一次,生成了一个新的提交</div> </div> <div class="paragraph"> <p>此时如果你执行 <code>git log</code> 命令,你会发现有两个提交的作者、日期、日志居然是一样的,这会令人感到混乱。 此外,如果你将这一堆又推送到服务器上,你实际上是将那些已经被变基抛弃的提交又找了回来,这会令人感到更加混乱。 很明显对方并不想在提交历史中看到 <code>C4</code> 和 <code>C6</code>,因为之前就是他把这两个提交通过变基丢弃的。</p> </div> </div> <div class="sect3"> <h3 id="_rebase_rebase">用变基解决变基</h3> <div class="paragraph"> <p>如果你 <strong>真的</strong> 遭遇了类似的处境,Git 还有一些高级魔法可以帮到你。 如果团队中的某人强制推送并覆盖了一些你所基于的提交,你需要做的就是检查你做了哪些修改,以及他们覆盖了哪些修改。</p> </div> <div class="paragraph"> <p>实际上,Git 除了对整个提交计算 SHA-1 校验和以外,也对本次提交所引入的修改计算了校验和——即 “patch-id”。</p> </div> <div class="paragraph"> <p>如果你拉取被覆盖过的更新并将你手头的工作基于此进行变基的话,一般情况下 Git 都能成功分辨出哪些是你的修改,并把它们应用到新分支上。</p> </div> <div class="paragraph"> <p>举个例子,如果遇到前面提到的 <a href="/book/zh/v2/ch00/_pre_merge_rebase_work">有人推送了经过变基的提交,并丢弃了你的本地开发所基于的一些提交</a> 那种情境,如果我们不是执行合并,而是执行 <code>git rebase teamone/master</code>, Git 将会:</p> </div> <div class="ulist"> <ul> <li> <p>检查哪些提交是我们的分支上独有的(C2,C3,C4,C6,C7)</p> </li> <li> <p>检查其中哪些提交不是合并操作的结果(C2,C3,C4)</p> </li> <li> <p>检查哪些提交在对方覆盖更新时并没有被纳入目标分支(只有 C2 和 C3,因为 C4 其实就是 C4')</p> </li> <li> <p>把查到的这些提交应用在 <code>teamone/master</code> 上面</p> </li> </ul> </div> <div class="paragraph"> <p>从而我们将得到与 <a href="/book/zh/v2/ch00/_merge_rebase_work">你将相同的内容又合并了一次,生成了一个新的提交</a> 中不同的结果,如图 <a href="/book/zh/v2/ch00/_rebase_rebase_work">在一个被变基然后强制推送的分支上再次执行变基</a> 所示。</p> </div> <div id="_rebase_rebase_work" class="imageblock"> <div class="content"> <img src="/book/zh/v2/images/perils-of-rebasing-5.png" alt="在一个被变基然后强制推送的分支上再次执行变基。"> </div> <div class="title">Figure 48. 在一个被变基然后强制推送的分支上再次执行变基</div> </div> <div class="paragraph"> <p>要想上述方案有效,还需要对方在变基时确保 <code>C4'</code> 和 <code>C4</code> 是几乎一样的。 否则变基操作将无法识别,并新建另一个类似 <code>C4</code> 的补丁(而这个补丁很可能无法整洁的整合入历史,因为补丁中的修改已经存在于某个地方了)。</p> </div> <div class="paragraph"> <p>在本例中另一种简单的方法是使用 <code>git pull --rebase</code> 命令而不是直接 <code>git pull</code>。 又或者你可以自己手动完成这个过程,先 <code>git fetch</code>,再 <code>git rebase teamone/master</code>。</p> </div> <div class="paragraph"> <p>如果你习惯使用 <code>git pull</code> ,同时又希望默认使用选项 <code>--rebase</code>,你可以执行这条语句 <code>git config --global pull.rebase true</code> 来更改 <code>pull.rebase</code> 的默认配置。</p> </div> <div class="paragraph"> <p>如果你只对不会离开你电脑的提交执行变基,那就不会有事。 如果你对已经推送过的提交执行变基,但别人没有基于它的提交,那么也不会有事。 如果你对已经推送至共用仓库的提交上执行变基命令,并因此丢失了一些别人的开发所基于的提交, 那你就有大麻烦了,你的同事也会因此鄙视你。</p> </div> <div class="paragraph"> <p>如果你或你的同事在某些情形下决意要这么做,请一定要通知每个人执行 <code>git pull --rebase</code> 命令,这样尽管不能避免伤痛,但能有所缓解。</p> </div> </div> <div class="sect3"> <h3 id="_变基_vs_合并">变基 vs. 合并</h3> <div class="paragraph"> <p> 至此,你已在实战中学习了变基和合并的用法,你一定会想问,到底哪种方式更好。 在回答这个问题之前,让我们退后一步,想讨论一下提交历史到底意味着什么。</p> </div> <div class="paragraph"> <p>有一种观点认为,仓库的提交历史即是 <strong>记录实际发生过什么</strong>。 它是针对历史的文档,本身就有价值,不能乱改。 从这个角度看来,改变提交历史是一种亵渎,你使用 <em>谎言</em> 掩盖了实际发生过的事情。 如果由合并产生的提交历史是一团糟怎么办? 既然事实就是如此,那么这些痕迹就应该被保留下来,让后人能够查阅。</p> </div> <div class="paragraph"> <p>另一种观点则正好相反,他们认为提交历史是 <strong>项目过程中发生的事</strong>。 没人会出版一本书的第一版草稿,软件维护手册也是需要反复修订才能方便使用。 持这一观点的人会使用 <code>rebase</code> 及 <code>filter-branch</code> 等工具来编写故事,怎么方便后来的读者就怎么写。</p> </div> <div class="paragraph"> <p>现在,让我们回到之前的问题上来,到底合并还是变基好?希望你能明白,这并没有一个简单的答案。 Git 是一个非常强大的工具,它允许你对提交历史做许多事情,但每个团队、每个项目对此的需求并不相同。 既然你已经分别学习了两者的用法,相信你能够根据实际情况作出明智的选择。</p> </div> <div class="paragraph"> <p>总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。</p> </div> </div> <div id="nav"><a href="/book/zh/v2/Git-分支-远程分支">prev</a> | <a href="/book/zh/v2/Git-分支-总结">next</a></div> </div> </div> </div> </div> <footer> <div class="site-source"> <a href="/site">About this site</a><br> Patches, suggestions, and comments are welcome. </div> <div class="sfc-member"> Git is a member of <a href="/sfc">Software Freedom Conservancy</a> </div> </footer> <a href="#top" class="no-js scrollToTop" id="scrollToTop" data-label="Scroll to top"> <img src="/images/icons/chevron-up@2x.png" width="20" height="20" alt="scroll-to-top"/> </a> <script src="/js/jquery-1.7.1.min.js"></script> <script src="/js/jquery-ui-1.8.18.custom.min.js"></script> <script src="/js/jquery.defaultvalue.js"></script> <script src="/js/session.min.js"></script> <script src="/js/application.min.js"></script> </div> </body> </html>