├── .gitignore ├── LICENSE ├── README.md ├── lecture01 ├── README.md └── figures │ ├── Git_gui.png │ ├── centralized.png │ └── distributed.png ├── lecture02 └── README.md ├── lecture03 ├── README.md └── figures │ ├── brach_message.png │ ├── branch_file.png │ ├── branches.png │ ├── merge.png │ ├── merge_error.png │ └── mergetool.png ├── lecture04 └── README.md ├── lecture05 ├── README.md └── imgs │ └── objects_1.jpg ├── lecture06 ├── README.md └── imgs │ └── gitflow示意图.png ├── lecture07 ├── README.md ├── git-commit.png └── git-hooks-demo.png ├── lecture08 ├── README.md └── imgs │ ├── advanced-search.png │ ├── create-repo.png │ ├── discussion.png │ ├── draft-pr.png │ ├── gitee-import-repo.png │ ├── homepage.png │ ├── issue-tab.png │ ├── issue-template.png │ ├── new-repo-button.png │ ├── new-repo.png │ ├── pr-tab.png │ ├── repo-page.png │ ├── shortcuts.png │ ├── trending.png │ └── watch.png ├── lecture09 ├── Assets │ ├── github_desktop.png │ ├── github_desktop_1.png │ ├── github_desktop_10.png │ ├── github_desktop_11.png │ ├── github_desktop_12.png │ ├── github_desktop_2.png │ ├── github_desktop_3.png │ ├── github_desktop_4.png │ ├── github_desktop_5.png │ ├── github_desktop_6.png │ ├── github_desktop_7.png │ ├── github_desktop_8.png │ ├── github_desktop_9.png │ ├── tgit_1.png │ ├── tgit_10.png │ ├── tgit_11.png │ ├── tgit_12.png │ ├── tgit_13.png │ ├── tgit_14.png │ ├── tgit_15.png │ ├── tgit_16.png │ ├── tgit_17.png │ ├── tgit_18.png │ ├── tgit_19.png │ ├── tgit_2.png │ ├── tgit_20.png │ ├── tgit_21.png │ ├── tgit_22.png │ ├── tgit_3.png │ ├── tgit_4.png │ ├── tgit_5.png │ ├── tgit_6.png │ ├── tgit_7.png │ ├── tgit_8.png │ ├── tgit_9.png │ ├── vsgit_1.png │ ├── vsgit_2.png │ └── vsgit_3.png └── README.md └── lecture10 ├── README.md └── imgs ├── colla.png ├── diff.png └── merge.png /.gitignore: -------------------------------------------------------------------------------- 1 | # General 2 | .DS_Store 3 | 4 | # Thumbnails 5 | ._* 6 | 7 | # Windows 8 | Thumbs.db 9 | 10 | *~ 11 | 12 | # Vim Swap 13 | [._]*.sw[a-p] 14 | 15 | .vscode/* 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Attribution-NonCommercial-ShareAlike 4.0 International 2 | 3 | ======================================================================= 4 | 5 | Creative Commons Corporation ("Creative Commons") is not a law firm and 6 | does not provide legal services or legal advice. Distribution of 7 | Creative Commons public licenses does not create a lawyer-client or 8 | other relationship. Creative Commons makes its licenses and related 9 | information available on an "as-is" basis. Creative Commons gives no 10 | warranties regarding its licenses, any material licensed under their 11 | terms and conditions, or any related information. Creative Commons 12 | disclaims all liability for damages resulting from their use to the 13 | fullest extent possible. 14 | 15 | Using Creative Commons Public Licenses 16 | 17 | Creative Commons public licenses provide a standard set of terms and 18 | conditions that creators and other rights holders may use to share 19 | original works of authorship and other material subject to copyright 20 | and certain other rights specified in the public license below. The 21 | following considerations are for informational purposes only, are not 22 | exhaustive, and do not form part of our licenses. 23 | 24 | Considerations for licensors: Our public licenses are 25 | intended for use by those authorized to give the public 26 | permission to use material in ways otherwise restricted by 27 | copyright and certain other rights. Our licenses are 28 | irrevocable. Licensors should read and understand the terms 29 | and conditions of the license they choose before applying it. 30 | Licensors should also secure all rights necessary before 31 | applying our licenses so that the public can reuse the 32 | material as expected. Licensors should clearly mark any 33 | material not subject to the license. This includes other CC- 34 | licensed material, or material used under an exception or 35 | limitation to copyright. More considerations for licensors: 36 | wiki.creativecommons.org/Considerations_for_licensors 37 | 38 | Considerations for the public: By using one of our public 39 | licenses, a licensor grants the public permission to use the 40 | licensed material under specified terms and conditions. If 41 | the licensor's permission is not necessary for any reason--for 42 | example, because of any applicable exception or limitation to 43 | copyright--then that use is not regulated by the license. Our 44 | licenses grant only permissions under copyright and certain 45 | other rights that a licensor has authority to grant. Use of 46 | the licensed material may still be restricted for other 47 | reasons, including because others have copyright or other 48 | rights in the material. A licensor may make special requests, 49 | such as asking that all changes be marked or described. 50 | Although not required by our licenses, you are encouraged to 51 | respect those requests where reasonable. More considerations 52 | for the public: 53 | wiki.creativecommons.org/Considerations_for_licensees 54 | 55 | ======================================================================= 56 | 57 | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International 58 | Public License 59 | 60 | By exercising the Licensed Rights (defined below), You accept and agree 61 | to be bound by the terms and conditions of this Creative Commons 62 | Attribution-NonCommercial-ShareAlike 4.0 International Public License 63 | ("Public License"). To the extent this Public License may be 64 | interpreted as a contract, You are granted the Licensed Rights in 65 | consideration of Your acceptance of these terms and conditions, and the 66 | Licensor grants You such rights in consideration of benefits the 67 | Licensor receives from making the Licensed Material available under 68 | these terms and conditions. 69 | 70 | 71 | Section 1 -- Definitions. 72 | 73 | a. Adapted Material means material subject to Copyright and Similar 74 | Rights that is derived from or based upon the Licensed Material 75 | and in which the Licensed Material is translated, altered, 76 | arranged, transformed, or otherwise modified in a manner requiring 77 | permission under the Copyright and Similar Rights held by the 78 | Licensor. For purposes of this Public License, where the Licensed 79 | Material is a musical work, performance, or sound recording, 80 | Adapted Material is always produced where the Licensed Material is 81 | synched in timed relation with a moving image. 82 | 83 | b. Adapter's License means the license You apply to Your Copyright 84 | and Similar Rights in Your contributions to Adapted Material in 85 | accordance with the terms and conditions of this Public License. 86 | 87 | c. BY-NC-SA Compatible License means a license listed at 88 | creativecommons.org/compatiblelicenses, approved by Creative 89 | Commons as essentially the equivalent of this Public License. 90 | 91 | d. Copyright and Similar Rights means copyright and/or similar rights 92 | closely related to copyright including, without limitation, 93 | performance, broadcast, sound recording, and Sui Generis Database 94 | Rights, without regard to how the rights are labeled or 95 | categorized. For purposes of this Public License, the rights 96 | specified in Section 2(b)(1)-(2) are not Copyright and Similar 97 | Rights. 98 | 99 | e. Effective Technological Measures means those measures that, in the 100 | absence of proper authority, may not be circumvented under laws 101 | fulfilling obligations under Article 11 of the WIPO Copyright 102 | Treaty adopted on December 20, 1996, and/or similar international 103 | agreements. 104 | 105 | f. Exceptions and Limitations means fair use, fair dealing, and/or 106 | any other exception or limitation to Copyright and Similar Rights 107 | that applies to Your use of the Licensed Material. 108 | 109 | g. License Elements means the license attributes listed in the name 110 | of a Creative Commons Public License. The License Elements of this 111 | Public License are Attribution, NonCommercial, and ShareAlike. 112 | 113 | h. Licensed Material means the artistic or literary work, database, 114 | or other material to which the Licensor applied this Public 115 | License. 116 | 117 | i. Licensed Rights means the rights granted to You subject to the 118 | terms and conditions of this Public License, which are limited to 119 | all Copyright and Similar Rights that apply to Your use of the 120 | Licensed Material and that the Licensor has authority to license. 121 | 122 | j. Licensor means the individual(s) or entity(ies) granting rights 123 | under this Public License. 124 | 125 | k. NonCommercial means not primarily intended for or directed towards 126 | commercial advantage or monetary compensation. For purposes of 127 | this Public License, the exchange of the Licensed Material for 128 | other material subject to Copyright and Similar Rights by digital 129 | file-sharing or similar means is NonCommercial provided there is 130 | no payment of monetary compensation in connection with the 131 | exchange. 132 | 133 | l. Share means to provide material to the public by any means or 134 | process that requires permission under the Licensed Rights, such 135 | as reproduction, public display, public performance, distribution, 136 | dissemination, communication, or importation, and to make material 137 | available to the public including in ways that members of the 138 | public may access the material from a place and at a time 139 | individually chosen by them. 140 | 141 | m. Sui Generis Database Rights means rights other than copyright 142 | resulting from Directive 96/9/EC of the European Parliament and of 143 | the Council of 11 March 1996 on the legal protection of databases, 144 | as amended and/or succeeded, as well as other essentially 145 | equivalent rights anywhere in the world. 146 | 147 | n. You means the individual or entity exercising the Licensed Rights 148 | under this Public License. Your has a corresponding meaning. 149 | 150 | 151 | Section 2 -- Scope. 152 | 153 | a. License grant. 154 | 155 | 1. Subject to the terms and conditions of this Public License, 156 | the Licensor hereby grants You a worldwide, royalty-free, 157 | non-sublicensable, non-exclusive, irrevocable license to 158 | exercise the Licensed Rights in the Licensed Material to: 159 | 160 | a. reproduce and Share the Licensed Material, in whole or 161 | in part, for NonCommercial purposes only; and 162 | 163 | b. produce, reproduce, and Share Adapted Material for 164 | NonCommercial purposes only. 165 | 166 | 2. Exceptions and Limitations. For the avoidance of doubt, where 167 | Exceptions and Limitations apply to Your use, this Public 168 | License does not apply, and You do not need to comply with 169 | its terms and conditions. 170 | 171 | 3. Term. The term of this Public License is specified in Section 172 | 6(a). 173 | 174 | 4. Media and formats; technical modifications allowed. The 175 | Licensor authorizes You to exercise the Licensed Rights in 176 | all media and formats whether now known or hereafter created, 177 | and to make technical modifications necessary to do so. The 178 | Licensor waives and/or agrees not to assert any right or 179 | authority to forbid You from making technical modifications 180 | necessary to exercise the Licensed Rights, including 181 | technical modifications necessary to circumvent Effective 182 | Technological Measures. For purposes of this Public License, 183 | simply making modifications authorized by this Section 2(a) 184 | (4) never produces Adapted Material. 185 | 186 | 5. Downstream recipients. 187 | 188 | a. Offer from the Licensor -- Licensed Material. Every 189 | recipient of the Licensed Material automatically 190 | receives an offer from the Licensor to exercise the 191 | Licensed Rights under the terms and conditions of this 192 | Public License. 193 | 194 | b. Additional offer from the Licensor -- Adapted Material. 195 | Every recipient of Adapted Material from You 196 | automatically receives an offer from the Licensor to 197 | exercise the Licensed Rights in the Adapted Material 198 | under the conditions of the Adapter's License You apply. 199 | 200 | c. No downstream restrictions. You may not offer or impose 201 | any additional or different terms or conditions on, or 202 | apply any Effective Technological Measures to, the 203 | Licensed Material if doing so restricts exercise of the 204 | Licensed Rights by any recipient of the Licensed 205 | Material. 206 | 207 | 6. No endorsement. Nothing in this Public License constitutes or 208 | may be construed as permission to assert or imply that You 209 | are, or that Your use of the Licensed Material is, connected 210 | with, or sponsored, endorsed, or granted official status by, 211 | the Licensor or others designated to receive attribution as 212 | provided in Section 3(a)(1)(A)(i). 213 | 214 | b. Other rights. 215 | 216 | 1. Moral rights, such as the right of integrity, are not 217 | licensed under this Public License, nor are publicity, 218 | privacy, and/or other similar personality rights; however, to 219 | the extent possible, the Licensor waives and/or agrees not to 220 | assert any such rights held by the Licensor to the limited 221 | extent necessary to allow You to exercise the Licensed 222 | Rights, but not otherwise. 223 | 224 | 2. Patent and trademark rights are not licensed under this 225 | Public License. 226 | 227 | 3. To the extent possible, the Licensor waives any right to 228 | collect royalties from You for the exercise of the Licensed 229 | Rights, whether directly or through a collecting society 230 | under any voluntary or waivable statutory or compulsory 231 | licensing scheme. In all other cases the Licensor expressly 232 | reserves any right to collect such royalties, including when 233 | the Licensed Material is used other than for NonCommercial 234 | purposes. 235 | 236 | 237 | Section 3 -- License Conditions. 238 | 239 | Your exercise of the Licensed Rights is expressly made subject to the 240 | following conditions. 241 | 242 | a. Attribution. 243 | 244 | 1. If You Share the Licensed Material (including in modified 245 | form), You must: 246 | 247 | a. retain the following if it is supplied by the Licensor 248 | with the Licensed Material: 249 | 250 | i. identification of the creator(s) of the Licensed 251 | Material and any others designated to receive 252 | attribution, in any reasonable manner requested by 253 | the Licensor (including by pseudonym if 254 | designated); 255 | 256 | ii. a copyright notice; 257 | 258 | iii. a notice that refers to this Public License; 259 | 260 | iv. a notice that refers to the disclaimer of 261 | warranties; 262 | 263 | v. a URI or hyperlink to the Licensed Material to the 264 | extent reasonably practicable; 265 | 266 | b. indicate if You modified the Licensed Material and 267 | retain an indication of any previous modifications; and 268 | 269 | c. indicate the Licensed Material is licensed under this 270 | Public License, and include the text of, or the URI or 271 | hyperlink to, this Public License. 272 | 273 | 2. You may satisfy the conditions in Section 3(a)(1) in any 274 | reasonable manner based on the medium, means, and context in 275 | which You Share the Licensed Material. For example, it may be 276 | reasonable to satisfy the conditions by providing a URI or 277 | hyperlink to a resource that includes the required 278 | information. 279 | 3. If requested by the Licensor, You must remove any of the 280 | information required by Section 3(a)(1)(A) to the extent 281 | reasonably practicable. 282 | 283 | b. ShareAlike. 284 | 285 | In addition to the conditions in Section 3(a), if You Share 286 | Adapted Material You produce, the following conditions also apply. 287 | 288 | 1. The Adapter's License You apply must be a Creative Commons 289 | license with the same License Elements, this version or 290 | later, or a BY-NC-SA Compatible License. 291 | 292 | 2. You must include the text of, or the URI or hyperlink to, the 293 | Adapter's License You apply. You may satisfy this condition 294 | in any reasonable manner based on the medium, means, and 295 | context in which You Share Adapted Material. 296 | 297 | 3. You may not offer or impose any additional or different terms 298 | or conditions on, or apply any Effective Technological 299 | Measures to, Adapted Material that restrict exercise of the 300 | rights granted under the Adapter's License You apply. 301 | 302 | 303 | Section 4 -- Sui Generis Database Rights. 304 | 305 | Where the Licensed Rights include Sui Generis Database Rights that 306 | apply to Your use of the Licensed Material: 307 | 308 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right 309 | to extract, reuse, reproduce, and Share all or a substantial 310 | portion of the contents of the database for NonCommercial purposes 311 | only; 312 | 313 | b. if You include all or a substantial portion of the database 314 | contents in a database in which You have Sui Generis Database 315 | Rights, then the database in which You have Sui Generis Database 316 | Rights (but not its individual contents) is Adapted Material, 317 | including for purposes of Section 3(b); and 318 | 319 | c. You must comply with the conditions in Section 3(a) if You Share 320 | all or a substantial portion of the contents of the database. 321 | 322 | For the avoidance of doubt, this Section 4 supplements and does not 323 | replace Your obligations under this Public License where the Licensed 324 | Rights include other Copyright and Similar Rights. 325 | 326 | 327 | Section 5 -- Disclaimer of Warranties and Limitation of Liability. 328 | 329 | a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE 330 | EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS 331 | AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF 332 | ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, 333 | IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, 334 | WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR 335 | PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, 336 | ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT 337 | KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT 338 | ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. 339 | 340 | b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE 341 | TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, 342 | NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, 343 | INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, 344 | COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR 345 | USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN 346 | ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR 347 | DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR 348 | IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. 349 | 350 | c. The disclaimer of warranties and limitation of liability provided 351 | above shall be interpreted in a manner that, to the extent 352 | possible, most closely approximates an absolute disclaimer and 353 | waiver of all liability. 354 | 355 | 356 | Section 6 -- Term and Termination. 357 | 358 | a. This Public License applies for the term of the Copyright and 359 | Similar Rights licensed here. However, if You fail to comply with 360 | this Public License, then Your rights under this Public License 361 | terminate automatically. 362 | 363 | b. Where Your right to use the Licensed Material has terminated under 364 | Section 6(a), it reinstates: 365 | 366 | 1. automatically as of the date the violation is cured, provided 367 | it is cured within 30 days of Your discovery of the 368 | violation; or 369 | 370 | 2. upon express reinstatement by the Licensor. 371 | 372 | For the avoidance of doubt, this Section 6(b) does not affect any 373 | right the Licensor may have to seek remedies for Your violations 374 | of this Public License. 375 | 376 | c. For the avoidance of doubt, the Licensor may also offer the 377 | Licensed Material under separate terms or conditions or stop 378 | distributing the Licensed Material at any time; however, doing so 379 | will not terminate this Public License. 380 | 381 | d. Sections 1, 5, 6, 7, and 8 survive termination of this Public 382 | License. 383 | 384 | 385 | Section 7 -- Other Terms and Conditions. 386 | 387 | a. The Licensor shall not be bound by any additional or different 388 | terms or conditions communicated by You unless expressly agreed. 389 | 390 | b. Any arrangements, understandings, or agreements regarding the 391 | Licensed Material not stated herein are separate from and 392 | independent of the terms and conditions of this Public License. 393 | 394 | 395 | Section 8 -- Interpretation. 396 | 397 | a. For the avoidance of doubt, this Public License does not, and 398 | shall not be interpreted to, reduce, limit, restrict, or impose 399 | conditions on any use of the Licensed Material that could lawfully 400 | be made without permission under this Public License. 401 | 402 | b. To the extent possible, if any provision of this Public License is 403 | deemed unenforceable, it shall be automatically reformed to the 404 | minimum extent necessary to make it enforceable. If the provision 405 | cannot be reformed, it shall be severed from this Public License 406 | without affecting the enforceability of the remaining terms and 407 | conditions. 408 | 409 | c. No term or condition of this Public License will be waived and no 410 | failure to comply consented to unless expressly agreed to by the 411 | Licensor. 412 | 413 | d. Nothing in this Public License constitutes or may be interpreted 414 | as a limitation upon, or waiver of, any privileges and immunities 415 | that apply to the Licensor or You, including from the legal 416 | processes of any jurisdiction or authority. 417 | 418 | ======================================================================= 419 | 420 | Creative Commons is not a party to its public 421 | licenses. Notwithstanding, Creative Commons may elect to apply one of 422 | its public licenses to material it publishes and in those instances 423 | will be considered the “Licensor.” The text of the Creative Commons 424 | public licenses is dedicated to the public domain under the CC0 Public 425 | Domain Dedication. Except for the limited purpose of indicating that 426 | material is shared under a Creative Commons public license or as 427 | otherwise permitted by the Creative Commons policies published at 428 | creativecommons.org/policies, Creative Commons does not authorize the 429 | use of the trademark "Creative Commons" or any other trademark or logo 430 | of Creative Commons without its prior written consent including, 431 | without limitation, in connection with any unauthorized modifications 432 | to any of its public licenses or any other arrangements, 433 | understandings, or agreements concerning use of licensed material. For 434 | the avoidance of doubt, this paragraph does not form part of the 435 | public licenses. 436 | 437 | Creative Commons may be contacted at creativecommons.org. 438 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # faster-git 2 | 3 | 课程内容: 4 | 5 | 1. [第一章 Git简介](lecture01/README.md) 6 | 1. [第二章 Git基础命令](lecture02/README.md) 7 | 1. [第三章 Git分支管理](lecture03/README.md) 8 | 1. [第四章 Git工具](lecture04/README.md) 9 | 1. [第五章 Git内部原理](lecture05/README.md) 10 | 1. [第六章 GitFlow工作流实战](lecture06/README.md) 11 | 1. [第七章 Git提交规范](lecture07/README.md) 12 | 1. [第八章 Github/Gitee使用说明](lecture08/README.md) 13 | 1. [第九章 Git可视化工具下载](lecture09/README.md) 14 | 1. [第十章 Git团队协作以及合并时的diff工具](lecture10/README.md) 15 | 16 | 课程安排: 17 | | 任务信息 | 18 | |-------------------------------------------------------------| 19 | | Task01:Git基础:第一、二章(2天) | 20 | | Task02:Git分支管理及工具使用:第三、四章(2天) | 21 | | Task03:Git内部原理及工作流实战:第五、六章(3天) | 22 | | Task04:Git提交规范及Github/Gitee的使用:第七、八章(3天) | 23 | | Task05:Git可视化工具下载和团队协作:第九、十章(3天) | 24 | 25 | 课程贡献人员:(排名不分先后,按章节顺序排序) 26 | | 成员  | 个人简介 | 负责章节| 27 | | --------------- | --------------------------------------------------- |-------| 28 | | 牛志康 | Datawhale成员,西安电子科技大学本科生 | lecture01,lecture03| 29 | |朱松青| Datawhale成员,上海交通大学研究生|lecture02| 30 | |徐祥军|在职,互联网金融、后端开发|lecture04| 31 | |李碧涵|Datawhale成员,在职|lecture05| 32 | | 宋泽山 | Datawhale成员,算法开发 | lecture06| 33 | |王晓亮|Datawhale成员,在职|lecture07| 34 | |张翔宇|华东师范大学研究生|lecture08| 35 | | 沈豪 | Datawhale成员,复旦大学网安博士在读 |lecture09| 36 | | 夏峻 | Datawhale成员,上海交通大学研究生 |lecture10| 37 | 38 | # Contributing 39 | 40 | 主分支为`main` 41 | ## Workflow 42 | 43 | 关于本项目中出现的问题或者其他补充材料,我们鼓励大家提出pr和issue,我们将在短时间内进行解答。本项目使用`Forking`工作流,具体参考[atlassian文档](https://www.atlassian.com/git/tutorials/comparing-workflows/forking-workflow) 44 | 45 | 大致步骤如下: 46 | 47 | 1. 在GitHub上Fork本仓库 48 | 1. Clone Fork后的个人仓库 49 | 1. 设置`upstream`仓库地址,并禁用`push` 50 | 1. 使用分支开发,课程分支名为`lecture{#NO}`,`#NO`保持两位,如`lecture07`,对应课程目录 51 | 1. PR之前保持与原始仓库的同步,之后发起PR请求 52 | 53 | 命令示例: 54 | 55 | ```shell 56 | # fork 57 | # clone 58 | git clone git@github.com:USERNAME/faster-git.git 59 | 60 | # set upstream 61 | git remote add upstream git@github.com:datawhalechina/faster-git.git 62 | # disable upstream push 63 | git remote set-url --push upstream DISABLE 64 | # verify 65 | git remote -v 66 | # some sample output: 67 | # origin git@github.com:tomowang/faster-git.git (fetch) 68 | # origin git@github.com:tomowang/faster-git.git (push) 69 | # upstream git@github.com:datawhalechina/faster-git.git (fetch) 70 | # upstream DISABLE (push) 71 | 72 | # do your work 73 | git checkout -b lecture07 74 | # edit and commit and push your changes 75 | git push -u origin lecture07 76 | 77 | # keep your fork up to date 78 | ## fetch upstream main and merge with forked main branch 79 | git fetch upstream 80 | git checkout main 81 | git merge upstream/main 82 | ## rebase brach and force push 83 | git checkout lecture07 84 | git rebase main 85 | git push -f 86 | ``` 87 | 88 | ## Commit Message 89 | 90 | 提交信息使用如下格式:`: ` 91 | 92 | ``` 93 | : 94 | │ │ 95 | │ └─⫸ Summary in present tense. Not capitalized. No period at the end. 96 | │ 97 | └─⫸ Commit Type: lecture{#NO}|others 98 | ``` 99 | 100 | `others`包括非课程相关的改动,如本`README.md`中的变动,`.gitignore`的调整等。 101 | 102 | ## 关注我们 103 |
Datawhale是一个专注AI领域的开源组织,以“for the learner,和学习者一起成长”为愿景,构建对学习者最有价值的开源学习社区。关注我们,一起学习成长。
104 | 105 | ## LICENSE 106 | 知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 107 | 108 | -------------------------------------------------------------------------------- /lecture01/README.md: -------------------------------------------------------------------------------- 1 | # 第一章 Git简介 2 | ## 1.1 版本控制 3 | ### 1.1.1 什么是版本控制系统? 4 | 大家平常有没有遇到这种情况: 5 | 我们的初始代码能跑通,但是随着我们加新的功能时,加着加着发现代码出现了问题。有些同学可能会疯狂ctrl+z进行回退,这种方法太过麻烦。于是,我们想有没有一种系统,可以帮助我们记录我们对代码的变化,并且可以恢复到指定的某个版本的代码。 6 | 7 | 这种系统其实就是版本控制系统,有了它我们就可以将选定的文件回溯到之前的状态,甚至将整个项目都回退到过去某个时间点的状态,我们可以比较文件的变化细节,查出最后是谁修改了哪个地方,从而找出导致怪异问题出现的原因,又是谁在何时报告了某个功能缺陷等等。使用版本控制系统通常还意味着,就算我们乱来一气把整个项目中的文件改的改删的删,我们也照样可以轻松恢复到原先的样子。但额外增加的工作量却微乎其微。 8 | 9 | ### 1.1.2 集中式版本控制vs分布式版本控制系统 10 | 现有的版本控制系统主要有两种形式:集中式和分布式。 11 | 12 | 集中式版本控制系统:集中式版本库集中存放于一个单一的中央服务器的,保存所有文件的修订版本。在协同工作时,人们需要先从中央服务器取得最新的版本,然后开始干活,干完活了,再把自己的活推送给中央服务器。因此,集中式版本控制系统需要在联网的情况下才能工作。 13 | 14 | ![](./figures/centralized.png) 15 | 16 | 集中式版本控制有一个很致命的缺点就是中央服务器的单点故障。 如果宕机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。 如果中心数据库所在的磁盘发生损坏,又没有做恰当备份,毫无疑问你将丢失所有数据——包括项目的整个变更历史,只剩下人们在各自机器上保留的单独快照。 17 | 18 | 分布式版本控制系统: 19 | 分布式版本控制系统根本没有“中央服务器”, 20 | 我们每次是把代码仓库完整地镜像下来,包括完整的历史记录。这使得每个人的电脑上都是一个完整的版本库。这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。同时,我们也不需要像联网就可以进行工作。每个人电脑上都有一个完整的版本库,那多个人如何协作呢?比方说你在自己电脑上改了文件A,你的同事也在他的电脑上改了文件A,这时,你们俩之间只需把各自的修改推送给对方,就可以互相看到对方的修改了。 21 | 22 | 但是在实际使用分布式版本控制系统的时候,其实很少在两人之间的电脑上推送版本库的修改,因为可能我们不在一个局域网内,两台电脑互相访问不了。因此,分布式版本控制系统通常也有一台充当“中央服务器”的电脑或者服务器,但这个服务器的作用仅仅是用来方便“交换”大家的修改,没有它大家也一样干活,只是交换修改不方便而已。这也是我们在GitHub建立repo的原因。 23 | 24 | ![](./figures/distributed.png) 25 | 26 | 27 | ## 1.2 Git简介和历史 28 | 29 | 说到Git的诞生,我们就不得不提一下Linux之父 Linus Torvalds和Linux。Linux 内核开源项目有着为数众多的参与者。 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。到2002年,整个项目组开始启用一个专有的分布式版本控制系统BitKeeper来管理和维护代码。 30 | 31 | 但是到了2005年,开发BitKeeper的商业公司认为Linux开发者内部有人对BitKeeper内部使用的协议进行逆向工程,因此他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。 这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用 BitKeeper 时的经验教训,开发出自己的版本系统。 他们对新的系统制订了若干目标: 32 | 33 | - 速度 34 | 35 | - 简单的设计 36 | 37 | - 对非线性开发模式的强力支持(允许成千上万个并行开发的分支) 38 | 39 | - 完全分布式 40 | 41 | - 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量) 42 | 43 | 于是在Linux之父Linus Torvalds的带领下用了10天编写出了第一个Git版本。自诞生以来,Git 日臻成熟完善,在高度易用的同时,仍然保留着初期设定的目标。 它的速度飞快,极其适合管理大项目,有着令人难以置信的非线性分支管理系统(参见 Git 分支)。 44 | 45 | ## 1.3 Git的安装 46 | 关于Git的安装,我们可以访问Git book所给的下载教程进行下载,我们在下面的几部分也是仅做简要叙述。具体链接 --> [安装 Git](https://git-scm.com/book/zh/v2/%E8%B5%B7%E6%AD%A5-%E5%AE%89%E8%A3%85-Git) 47 | ### 1.3.1 Linux 48 | 我们可以在terminal输入`git`命令查看系统有没有安装git。如果没有安装的话,我们可以访问git关于linux和unix的安装页面,输入对应的安装命令。网页链接 --> [Download for Linux and Unix](https://git-scm.com/download/linux) 49 | 对于常见的Debian和Ubuntu Linux,我们可以通过 50 | ```bash 51 | sudo apt-get install git 52 | ``` 53 | 就可以直接完成Git的安装。 54 | ### 1.3.2 Windows 55 | 在 Windows 上安装 Git 也有几种安装方法。 我们也可以打开 https://git-scm.com/downloads 进行下载安装。安装好后我们可以打开Git bash。 56 | ![](./figures/Git_gui.png) 57 | 另一个简单的方法是安装 GitHub Desktop。 该安装程序包含图形化和命令行版本的 Git。 它也能支持 Powershell,提供了稳定的凭证缓存和健全的换行设置。 58 | ### 1.3.3 macOS 59 | 在 Mac 上安装 Git 有多种方式。 最简单的方法是安装 Xcode Command Line Tools。 Mavericks (10.9) 或更高版本的系统中,在 Terminal 里尝试首次运行 git 命令即可。 60 | ```bash 61 | git --version 62 | ``` 63 | 如果没有我们安装过命令行开发者工具,terminal也会提示你安装。 64 | 65 | 如果我们想安装更新的版本,可以使用二进制安装程序。 官方维护的 macOS Git 安装程序可以在 Git 官方网站下载,网址为 https://git-scm.com/download/mac。 66 | ### 1.3.4 初次运行Git的配置 67 | 当我们安装好Git后,还需要在Git bash或者terminal进行一些相关设置,以下设置仅需设置一次即可。 68 | ```bash 69 | git config --global user.name "Your Name" 70 | git config --global user.email "email@example.com" 71 | ``` 72 | 除此之外,Git还有很多设置,包括常用编辑器等,大家可以键入以下命令查看自己的设置并进行修改。 73 | ```bash 74 | git config --list 75 | ``` 76 | ## 1.4 相关学习资源 77 | 在这里给大家推荐几个学习Git的资源,希望可以帮助大家在未来对Git有着更深的了解。 78 | 79 | - [Git Book](https://git-scm.com/book/zh/v2) 80 | - [廖雪峰Git教程](https://www.liaoxuefeng.com/wiki/896043488029600) 81 | - [Git权威指南](https://gotgit.readthedocs.io/en/latest/index.html) 82 | - [freenode](https://freenode.net/) 83 | - [Github-cheat-sheet](https://github.com/tiimgreen/github-cheat-sheet) 84 | - [动手学Git](https://www.freeaihub.com/git/index.html) 85 | - [learn git branching](https://learngitbranching.js.org/?locale=zh_CN) 86 | -------------------------------------------------------------------------------- /lecture01/figures/Git_gui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/faster-git/08277470cee6e0955f255452a9fe4a0fa7842c43/lecture01/figures/Git_gui.png -------------------------------------------------------------------------------- /lecture01/figures/centralized.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/faster-git/08277470cee6e0955f255452a9fe4a0fa7842c43/lecture01/figures/centralized.png -------------------------------------------------------------------------------- /lecture01/figures/distributed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/faster-git/08277470cee6e0955f255452a9fe4a0fa7842c43/lecture01/figures/distributed.png -------------------------------------------------------------------------------- /lecture02/README.md: -------------------------------------------------------------------------------- 1 | # 第二章 Git基础命令 2 | 3 | ## 2.0 前言 4 | 如果你只想通过阅读一章来学习 Git,那么本章将是你的不二选择。 本章涵盖了你在使用 Git 完成各种工作时将会用到的各种基本命令。 在学习完本章之后,你应该能够配置并初始化一个仓库(repository)、开始或停止跟踪(track)文件、暂存(stage)或提交(commit)更改。 本章也将向你演示了如何配置 Git 来忽略指定的文件和文件模式、如何迅速而简单地撤销错误操作、如何浏览你的项目的历史版本以及不同提交(commits)之间的差异、如何向你的远程仓库推送(push)以及如何从你的远程仓库拉取(pull)文件。 5 | 6 | ## 2.1 获取 Git 仓库 7 | 通常有两种获取 Git 项目仓库的方式: 8 | 9 | 将尚未进行版本控制的本地目录转换为 Git 仓库; 10 | 11 | 从其它服务器 克隆 一个已存在的 Git 仓库。 12 | 13 | 两种方式都会在你的本地机器上得到一个工作就绪的 Git 仓库。 14 | 15 | 在已存在目录中初始化仓库 16 | 如果你有一个尚未进行版本控制的项目目录,想要用 Git 来控制它,那么首先需要进入该项目目录中。 如果你还没这样做过,那么不同系统上的做法有些不同: 17 | 18 | ```shell 19 | 在 Linux 上: 20 | $ cd /home/user/my_project 21 | 22 | 在 macOS 上: 23 | $ cd /Users/user/my_project 24 | 25 | 在 Windows 上: 26 | $ cd /c/user/my_project 27 | 28 | 之后执行: 29 | $ git init 30 | ``` 31 | 该命令将创建一个名为 .git 的子目录,这个子目录含有你初始化的 Git 仓库中所有的必须文件,这些文件是 Git 仓库的骨干。 但是,在这个时候,我们仅仅是做了一个初始化的操作,你的项目里的文件还没有被跟踪。 (参见 Git 内部原理 来了解更多关于到底 .git 文件夹中包含了哪些文件的信息。) 32 | 33 | 如果在一个已存在文件的文件夹(而非空文件夹)中进行版本控制,你应该开始追踪这些文件并进行初始提交。 可以通过 git add 命令来指定所需的文件来进行追踪,然后执行 git commit : 34 | ```shell 35 | $ git add *.c 36 | $ git add LICENSE 37 | $ git commit -m 'initial project version' 38 | ``` 39 | 稍后我们再逐一解释这些指令的行为。 现在,你已经得到了一个存在被追踪文件与初始提交的 Git 仓库。 40 | 41 | 克隆现有的仓库 42 | 如果你想获得一份已经存在了的 Git 仓库的拷贝,比如说,你想为某个开源项目贡献自己的一份力,这时就要用到 git clone 命令。 如果你对其它的 VCS 系统(比如说 Subversion)很熟悉,请留心一下你所使用的命令是"clone"而不是"checkout"。 这是 Git 区别于其它版本控制系统的一个重要特性,Git 克隆的是该 Git 仓库服务器上的几乎所有数据,而不是仅仅复制完成你的工作所需要文件。 当你执行 git clone 命令的时候,默认配置下远程 Git 仓库中的每一个文件的每一个版本都将被拉取下来。 事实上,如果你的服务器的磁盘坏掉了,你通常可以使用任何一个克隆下来的用户端来重建服务器上的仓库 (虽然可能会丢失某些服务器端的钩子(hook)设置,但是所有版本的数据仍在,详见 在服务器上搭建 Git )。 43 | 44 | 克隆仓库的命令是 git clone 。 比如,要克隆 Git 的链接库 libgit2,可以用下面的命令: 45 | ```shell 46 | $ git clone https://github.com/libgit2/libgit2 47 | ``` 48 | 这会在当前目录下创建一个名为 “libgit2” 的目录,并在这个目录下初始化一个 .git 文件夹, 从远程仓库拉取下所有数据放入 .git 文件夹,然后从中读取最新版本的文件的拷贝。 如果你进入到这个新建的 libgit2 文件夹,你会发现所有的项目文件已经在里面了,准备就绪等待后续的开发和使用。 49 | 50 | 如果你想在克隆远程仓库的时候,自定义本地仓库的名字,你可以通过额外的参数指定新的目录名: 51 | ```shell 52 | $ git clone https://github.com/libgit2/libgit2 mylibgit 53 | ``` 54 | 这会执行与上一条命令相同的操作,但目标目录名变为了 mylibgit。 55 | 56 | Git 支持多种数据传输协议。 上面的例子使用的是 https:// 协议,不过你也可以使用 git:// 协议或者使用 SSH 传输协议,比如 user@server:path/to/repo.git 。 在服务器上搭建 Git 将会介绍所有这些协议在服务器端如何配置使用,以及各种方式之间的利弊。 57 | 58 | ## 2.2 记录每次更新到仓库 59 | 现在我们的机器上有了一个 真实项目 的 Git 仓库,并从这个仓库中检出了所有文件的 工作副本。 通常,你会对这些文件做些修改,每当完成了一个阶段的目标,想要将记录下它时,就将它提交到仓库。 60 | 61 | 请记住,你工作目录下的每一个文件都不外乎这两种状态:已跟踪 或 未跟踪。 已跟踪的文件是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后, 它们的状态可能是未修改,已修改或已放入暂存区。简而言之,已跟踪的文件就是 Git 已经知道的文件。 62 | 63 | 工作目录中除已跟踪文件外的其它所有文件都属于未跟踪文件,它们既不存在于上次快照的记录中,也没有被放入暂存区。 初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态,因为 Git 刚刚检出了它们, 而你尚未编辑过它们。 64 | 65 | 编辑过某些文件之后,由于自上次提交后你对它们做了修改,Git 将它们标记为已修改文件。 在工作时,你可以选择性地将这些修改过的文件放入暂存区,然后提交所有已暂存的修改,如此反复。 66 | 67 | ![image](https://user-images.githubusercontent.com/62437804/166645345-fa590f8a-9259-47b3-b5b3-048996014521.png) 68 | 69 | 70 | Git 下文件生命周期图。 71 | Figure 8. 文件的状态变化周期 72 | ### 2.2.1 检查当前文件状态 73 | 可以用 git status 命令查看哪些文件处于什么状态。 如果在克隆仓库后立即使用此命令,会看到类似这样的输出: 74 | 75 | ```shell 76 | $ git status 77 | On branch master 78 | Your branch is up-to-date with 'origin/master'. 79 | nothing to commit, working directory clean 80 | 81 | ``` 82 | 这说明你现在的工作目录相当干净。换句话说,所有已跟踪文件在上次提交后都未被更改过。 此外,上面的信息还表明,当前目录下没有出现任何处于未跟踪状态的新文件,否则 Git 会在这里列出来。 最后,该命令还显示了当前所在分支,并告诉你这个分支同远程服务器上对应的分支没有偏离。 现在,分支名是“master”,这是默认的分支名。 我们在 Git 分支 中会详细讨论分支和引用。 83 | 84 | 现在,让我们在项目下创建一个新的 README 文件。 如果之前并不存在这个文件,使用 git status 命令,你将看到一个新的未跟踪文件: 85 | 86 | 87 | ```shell 88 | $ echo 'My Project' > README 89 | $ git status 90 | On branch master 91 | Your branch is up-to-date with 'origin/master'. 92 | Untracked files: 93 | (use "git add ..." to include in what will be committed) 94 | nothing added to commit but untracked files present (use "git add" to track) 95 | ``` 96 | 在状态报告中可以看到新建的 README 文件出现在 Untracked files 下面。 未跟踪的文件意味着 Git 在之前的快照(提交)中没有这些文件;Git 不会自动将之纳入跟踪范围,除非你明明白白地告诉它“我需要跟踪该文件”。 这样的处理让你不必担心将生成的二进制文件或其它不想被跟踪的文件包含进来。 不过现在的例子中,我们确实想要跟踪管理 README 这个文件。 97 | 98 | ### 2.2.2 跟踪新文件 99 | 使用命令 git add 开始跟踪一个文件。 所以,要跟踪 README 文件,运行: 100 | ```shell 101 | $ git add README 102 | 此时再运行 git status 命令,会看到 README 文件已被跟踪,并处于暂存状态: 103 | 104 | $ git status 105 | On branch master 106 | Your branch is up-to-date with 'origin/master'. 107 | Changes to be committed: 108 | (use "git restore --staged ..." to unstage) 109 | 110 | new file: README 111 | ``` 112 | 只要在 Changes to be committed 这行下面的,就说明是已暂存状态。 如果此时提交,那么该文件在你运行 git add 时的版本将被留存在后续的历史记录中。 你可能会想起之前我们使用 git init 后就运行了 git add 命令,开始跟踪当前目录下的文件。 git add 命令使用文件或目录的路径作为参数;如果参数是目录的路径,该命令将递归地跟踪该目录下的所有文件。 113 | 114 | ### 2.2.3 暂存已修改的文件 115 | 116 | 现在我们来修改一个已被跟踪的文件。 如果你修改了一个名为 CONTRIBUTING.md 的已被跟踪的文件,然后运行 git status 命令,会看到下面内容: 117 | ```shell 118 | $ git status 119 | On branch master 120 | Your branch is up-to-date with 'origin/master'. 121 | Changes to be committed: 122 | (use "git reset HEAD ..." to unstage) 123 | 124 | new file: README 125 | 126 | Changes not staged for commit: 127 | (use "git add ..." to update what will be committed) 128 | (use "git checkout -- ..." to discard changes in working directory) 129 | 130 | modified: CONTRIBUTING.md 131 | ``` 132 | 文件 CONTRIBUTING.md 出现在 Changes not staged for commit 这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区。 要暂存这次更新,需要运行 git add 命令。 这是个多功能命令:可以用它开始跟踪新文件,或者把已跟踪的文件放到暂存区,还能用于合并时把有冲突的文件标记为已解决状态等。 将这个命令理解为“精确地将内容添加到下一次提交中”而不是“将一个文件添加到项目中”要更加合适。 现在让我们运行 git add 将“CONTRIBUTING.md”放到暂存区,然后再看看 git status 的输出: 133 | 134 | ```shell 135 | $ git add CONTRIBUTING.md 136 | $ git status 137 | On branch master 138 | Your branch is up-to-date with 'origin/master'. 139 | Changes to be committed: 140 | (use "git reset HEAD ..." to unstage) 141 | 142 | new file: README 143 | modified: CONTRIBUTING.md 144 | ``` 145 | 现在两个文件都已暂存,下次提交时就会一并记录到仓库。 假设此时,你想要在 CONTRIBUTING.md 里再加条注释。 重新编辑存盘后,准备好提交。 不过且慢,再运行 git status 看看: 146 | 147 | 148 | ```shell 149 | $ vim CONTRIBUTING.md 150 | $ git status 151 | On branch master 152 | Your branch is up-to-date with 'origin/master'. 153 | Changes to be committed: 154 | (use "git reset HEAD ..." to unstage) 155 | 156 | new file: README 157 | modified: CONTRIBUTING.md 158 | 159 | Changes not staged for commit: 160 | (use "git add ..." to update what will be committed) 161 | (use "git checkout -- ..." to discard changes in working directory) 162 | 163 | modified: CONTRIBUTING.md 164 | ``` 165 | 怎么回事? 现在 CONTRIBUTING.md 文件同时出现在暂存区和非暂存区。 这怎么可能呢? 好吧,实际上 Git 只不过暂存了你运行 git add 命令时的版本。 如果你现在提交,CONTRIBUTING.md 的版本是你最后一次运行 git add 命令时的那个版本,而不是你运行 git commit 时,在工作目录中的当前版本。 所以,运行了 git add 之后又作了修订的文件,需要重新运行 git add 把最新版本重新暂存起来: 166 | 167 | ```shell 168 | $ git add CONTRIBUTING.md 169 | $ git status 170 | On branch master 171 | Your branch is up-to-date with 'origin/master'. 172 | Changes to be committed: 173 | (use "git reset HEAD ..." to unstage) 174 | 175 | new file: README 176 | modified: CONTRIBUTING.md 177 | ## 状态简览 178 | git status 命令的输出十分详细,但其用语有些繁琐。 Git 有一个选项可以帮你缩短状态命令的输出,这样可以以简洁的方式查看更改。 如果你使用 git status -s 命令或 git status --short 命令,你将得到一种格式更为紧凑的输出。 179 | ``` 180 | 181 | ```shell 182 | $ git status -s 183 | M README 184 | MM Rakefile 185 | A lib/git.rb 186 | M lib/simplegit.rb 187 | ?? LICENSE.txt 188 | ``` 189 | 新添加的未跟踪文件前面有 ?? 标记,新添加到暂存区中的文件前面有 A 标记,修改过的文件前面有 M 标记。 输出中有两栏,左栏指明了暂存区的状态,右栏指明了工作区的状态。例如,上面的状态报告显示: README 文件在工作区已修改但尚未暂存,而 lib/simplegit.rb 文件已修改且已暂存。 Rakefile 文件已修改,暂存后又作了修改,因此该文件的修改中既有已暂存的部分,又有未暂存的部分。 190 | 191 | ### 2.2.4 忽略文件 192 | 一般我们总会有些文件无需纳入 Git 的管理,也不希望它们总出现在未跟踪文件列表。 通常都是些自动生成的文件,比如日志文件,或者编译过程中创建的临时文件等。 在这种情况下,我们可以创建一个名为 .gitignore 的文件,列出要忽略的文件的模式。 来看一个实际的 .gitignore 例子: 193 | ```shell 194 | $ cat .gitignore 195 | *.[oa] 196 | *~ 197 | ``` 198 | 第一行告诉 Git 忽略所有以 .o 或 .a 结尾的文件。一般这类对象文件和存档文件都是编译过程中出现的。 第二行告诉 Git 忽略所有名字以波浪符(~)结尾的文件,许多文本编辑软件(比如 Emacs)都用这样的文件名保存副本。 此外,你可能还需要忽略 log,tmp 或者 pid 目录,以及自动生成的文档等等。 要养成一开始就为你的新仓库设置好 .gitignore 文件的习惯,以免将来误提交这类无用的文件。 199 | 200 | 文件 .gitignore 的格式规范如下: 201 | 202 | 所有空行或者以 # 开头的行都会被 Git 忽略。 203 | 204 | 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中。 205 | 206 | 匹配模式可以以(/)开头防止递归。 207 | 208 | 匹配模式可以以(/)结尾指定目录。 209 | 210 | 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。 211 | 212 | 所谓的 glob 模式是指 shell 所使用的简化了的正则表达式。 星号(*)匹配零个或多个任意字符;[abc] 匹配任何一个列在方括号中的字符 (这个例子要么匹配一个 a,要么匹配一个 b,要么匹配一个 c); 问号(?)只匹配一个任意字符;如果在方括号中使用短划线分隔两个字符, 表示所有在这两个字符范围内的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的数字)。 使用两个星号(**)表示匹配任意中间目录,比如 a/**/z 可以匹配 a/z 、 a/b/z 或 a/b/c/z 等。 213 | 214 | 我们再看一个 .gitignore 文件的例子: 215 | ```shell 216 | 217 | # 忽略所有的 .a 文件 218 | *.a 219 | 220 | # 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件 221 | !lib.a 222 | 223 | # 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO 224 | /TODO 225 | 226 | # 忽略任何目录下名为 build 的文件夹 227 | build/ 228 | 229 | # 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt 230 | doc/*.txt 231 | 232 | # 忽略 doc/ 目录及其所有子目录下的 .pdf 文件 233 | doc/**/*.pdf 234 | 235 | ``` 236 | Tip 237 | GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表, 你可以在 https://github.com/github/gitignore 找到它。 238 | 239 | Note 240 | 在最简单的情况下,一个仓库可能只根目录下有一个 .gitignore 文件,它递归地应用到整个仓库中。 然而,子目录下也可以有额外的 .gitignore 文件。子目录中的 .gitignore 文件中的规则只作用于它所在的目录中。 (Linux 内核的源码库拥有 206 个 .gitignore 文件。) 241 | 242 | 多个 .gitignore 文件的具体细节超出了本书的范围,更多详情见 man gitignore 。 243 | 244 | ### 2.2.5 查看已暂存和未暂存的修改 245 | 如果 git status 命令的输出对于你来说过于简略,而你想知道具体修改了什么地方,可以用 git diff 命令。 稍后我们会详细介绍 git diff,你通常可能会用它来回答这两个问题:当前做的哪些更新尚未暂存? 有哪些更新已暂存并准备好下次提交? 虽然 git status 已经通过在相应栏下列出文件名的方式回答了这个问题,但 git diff 能通过文件补丁的格式更加具体地显示哪些行发生了改变。 246 | 247 | 假如再次修改 README 文件后暂存,然后编辑 CONTRIBUTING.md 文件后先不暂存, 运行 status 命令将会看到: 248 | 249 | ```shell 250 | $ git status 251 | On branch master 252 | Your branch is up-to-date with 'origin/master'. 253 | Changes to be committed: 254 | (use "git reset HEAD ..." to unstage) 255 | 256 | modified: README 257 | 258 | Changes not staged for commit: 259 | (use "git add ..." to update what will be committed) 260 | (use "git checkout -- ..." to discard changes in working directory) 261 | 262 | modified: CONTRIBUTING.md 263 | ``` 264 | 265 | 要查看尚未暂存的文件更新了哪些部分,不加参数直接输入 git diff: 266 | ```shell 267 | $ git diff 268 | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md 269 | index 8ebb991..643e24f 100644 270 | --- a/CONTRIBUTING.md 271 | +++ b/CONTRIBUTING.md 272 | @@ -65,7 +65,8 @@ branch directly, things can get messy. 273 | Please include a nice description of your changes when you submit your PR; 274 | if we have to read the whole diff to figure out why you're contributing 275 | in the first place, you're less likely to get feedback and have your change 276 | -merged in. 277 | +merged in. Also, split your changes into comprehensive chunks if your patch is 278 | +longer than a dozen lines. 279 | 280 | If you are starting to work on a particular area, feel free to submit a PR 281 | that highlights your work in progress (and note in the PR title that it's 282 | ``` 283 | 284 | 此命令比较的是工作目录中当前文件和暂存区域快照之间的差异。 也就是修改之后还没有暂存起来的变化内容。 285 | 286 | 若要查看已暂存的将要添加到下次提交里的内容,可以用 git diff --staged 命令。 这条命令将比对已暂存文件与最后一次提交的文件差异: 287 | ```shell 288 | $ git diff --staged 289 | diff --git a/README b/README 290 | new file mode 100644 291 | index 0000000..03902a1 292 | --- /dev/null 293 | +++ b/README 294 | @@ -0,0 +1 @@ 295 | +My Project 296 | ``` 297 | 298 | 请注意,git diff 本身只显示尚未暂存的改动,而不是自上次提交以来所做的所有改动。 所以有时候你一下子暂存了所有更新过的文件,运行 git diff 后却什么也没有,就是这个原因。 299 | 300 | 像之前说的,暂存 CONTRIBUTING.md 后再编辑,可以使用 git status 查看已被暂存的修改或未被暂存的修改。 如果我们的环境(终端输出)看起来如下: 301 | ```shell 302 | $ git add CONTRIBUTING.md 303 | $ echo '# test line' >> CONTRIBUTING.md 304 | $ git status 305 | On branch master 306 | Your branch is up-to-date with 'origin/master'. 307 | Changes to be committed: 308 | (use "git reset HEAD ..." to unstage) 309 | 310 | modified: CONTRIBUTING.md 311 | 312 | Changes not staged for commit: 313 | (use "git add ..." to update what will be committed) 314 | (use "git checkout -- ..." to discard changes in working directory) 315 | 316 | modified: CONTRIBUTING.md 317 | ``` 318 | 319 | 现在运行 git diff 看暂存前后的变化: 320 | ```shell 321 | $ git diff 322 | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md 323 | index 643e24f..87f08c8 100644 324 | --- a/CONTRIBUTING.md 325 | +++ b/CONTRIBUTING.md 326 | @@ -119,3 +119,4 @@ at the 327 | ## Starter Projects 328 | 329 | See our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md). 330 | +# test line 331 | 然后用 git diff --cached 查看已经暂存起来的变化( --staged 和 --cached 是同义词): 332 | 333 | $ git diff --cached 334 | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md 335 | index 8ebb991..643e24f 100644 336 | --- a/CONTRIBUTING.md 337 | +++ b/CONTRIBUTING.md 338 | @@ -65,7 +65,8 @@ branch directly, things can get messy. 339 | Please include a nice description of your changes when you submit your PR; 340 | if we have to read the whole diff to figure out why you're contributing 341 | in the first place, you're less likely to get feedback and have your change 342 | -merged in. 343 | +merged in. Also, split your changes into comprehensive chunks if your patch is 344 | +longer than a dozen lines. 345 | 346 | If you are starting to work on a particular area, feel free to submit a PR 347 | that highlights your work in progress (and note in the PR title that it's 348 | ``` 349 | 350 | Note 351 | Git Diff 的插件版本 352 | 在本书中,我们使用 git diff 来分析文件差异。 但是你也可以使用图形化的工具或外部 diff 工具来比较差异。 可以使用 git difftool 命令来调用 emerge 或 vimdiff 等软件(包括商业软件)输出 diff 的分析结果。 使用 git difftool --tool-help 命令来看你的系统支持哪些 Git Diff 插件。 353 | 354 | ### 2.2.6 提交更新 355 | 现在的暂存区已经准备就绪,可以提交了。 在此之前,请务必确认还有什么已修改或新建的文件还没有 git add 过, 否则提交的时候不会记录这些尚未暂存的变化。 这些已修改但未暂存的文件只会保留在本地磁盘。 所以,每次准备提交前,先用 git status 看下,你所需要的文件是不是都已暂存起来了, 然后再运行提交命令 git commit: 356 | 357 | $ git commit 358 | 这样会启动你选择的文本编辑器来输入提交说明。 359 | 360 | Note 361 | 启动的编辑器是通过 Shell 的环境变量 EDITOR 指定的,一般为 vim 或 emacs。 当然也可以按照 起步 介绍的方式, 使用 git config --global core.editor 命令设置你喜欢的编辑器。 362 | 363 | 编辑器会显示类似下面的文本信息(本例选用 Vim 的屏显方式展示): 364 | ```shell 365 | # Please enter the commit message for your changes. Lines starting 366 | # with '#' will be ignored, and an empty message aborts the commit. 367 | # On branch master 368 | # Your branch is up-to-date with 'origin/master'. 369 | # 370 | # Changes to be committed: 371 | # new file: README 372 | # modified: CONTRIBUTING.md 373 | # 374 | ~ 375 | ~ 376 | ~ 377 | ".git/COMMIT_EDITMSG" 9L, 283C 378 | 379 | ``` 380 | 可以看到,默认的提交消息包含最后一次运行 git status 的输出,放在注释行里,另外开头还有一个空行,供你输入提交说明。 你完全可以去掉这些注释行,不过留着也没关系,多少能帮你回想起这次更新的内容有哪些。 381 | 382 | Note 383 | 更详细的内容修改提示可以用 -v 选项查看,这会将你所作的更改的 diff 输出呈现在编辑器中,以便让你知道本次提交具体作出哪些修改。 384 | 385 | 退出编辑器时,Git 会丢弃注释行,用你输入的提交说明生成一次提交。 386 | 387 | 另外,你也可以在 commit 命令后添加 -m 选项,将提交信息与命令放在同一行,如下所示: 388 | ```shell 389 | $ git commit -m "Story 182: Fix benchmarks for speed" 390 | [master 463dc4f] Story 182: Fix benchmarks for speed 391 | 2 files changed, 2 insertions(+) 392 | create mode 100644 README 393 | ``` 394 | 好,现在你已经创建了第一个提交! 可以看到,提交后它会告诉你,当前是在哪个分支(master)提交的,本次提交的完整 SHA-1 校验和是什么(463dc4f),以及在本次提交中,有多少文件修订过,多少行添加和删改过。 395 | 396 | 请记住,提交时记录的是放在暂存区域的快照。 任何还未暂存文件的仍然保持已修改状态,可以在下次提交时纳入版本管理。 每一次运行提交操作,都是对你项目作一次快照,以后可以回到这个状态,或者进行比较。 397 | 398 | ### 2.2.7 跳过使用暂存区域 399 | 尽管使用暂存区域的方式可以精心准备要提交的细节,但有时候这么做略显繁琐。 Git 提供了一个跳过使用暂存区域的方式, 只要在提交的时候,给 git commit 加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤: 400 | ```shell 401 | $ git status 402 | On branch master 403 | Your branch is up-to-date with 'origin/master'. 404 | Changes not staged for commit: 405 | (use "git add ..." to update what will be committed) 406 | (use "git checkout -- ..." to discard changes in working directory) 407 | 408 | modified: CONTRIBUTING.md 409 | 410 | no changes added to commit (use "git add" and/or "git commit -a") 411 | $ git commit -a -m 'added new benchmarks' 412 | [master 83e38c7] added new benchmarks 413 | 1 file changed, 5 insertions(+), 0 deletions(-) 414 | ``` 415 | 看到了吗?提交之前不再需要 git add 文件“CONTRIBUTING.md”了。 这是因为 -a 选项使本次提交包含了所有修改过的文件。 这很方便,但是要小心,有时这个选项会将不需要的文件添加到提交中。 416 | 417 | ### 2.2.8 移除文件 418 | 要从 Git 中移除某个文件,就必须要从已跟踪文件清单中移除(确切地说,是从暂存区域移除),然后提交。 可以用 git rm 命令完成此项工作,并连带从工作目录中删除指定的文件,这样以后就不会出现在未跟踪文件清单中了。 419 | 420 | 如果只是简单地从工作目录中手工删除文件,运行 git status 时就会在 “Changes not staged for commit” 部分(也就是 未暂存清单)看到: 421 | ```shell 422 | $ rm PROJECTS.md 423 | $ git status 424 | On branch master 425 | Your branch is up-to-date with 'origin/master'. 426 | Changes not staged for commit: 427 | (use "git add/rm ..." to update what will be committed) 428 | (use "git checkout -- ..." to discard changes in working directory) 429 | 430 | deleted: PROJECTS.md 431 | 432 | no changes added to commit (use "git add" and/or "git commit -a") 433 | 然后再运行 git rm 记录此次移除文件的操作: 434 | 435 | $ git rm PROJECTS.md 436 | rm 'PROJECTS.md' 437 | $ git status 438 | On branch master 439 | Your branch is up-to-date with 'origin/master'. 440 | Changes to be committed: 441 | (use "git reset HEAD ..." to unstage) 442 | 443 | deleted: PROJECTS.md 444 | ``` 445 | 下一次提交时,该文件就不再纳入版本管理了。 如果要删除之前修改过或已经放到暂存区的文件,则必须使用强制删除选项 -f(译注:即 force 的首字母)。 这是一种安全特性,用于防止误删尚未添加到快照的数据,这样的数据不能被 Git 恢复。 446 | 447 | 另外一种情况是,我们想把文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中。 换句话说,你想让文件保留在磁盘,但是并不想让 Git 继续跟踪。 当你忘记添加 .gitignore 文件,不小心把一个很大的日志文件或一堆 .a 这样的编译生成文件添加到暂存区时,这一做法尤其有用。 为达到这一目的,使用 --cached 选项: 448 | 449 | $ git rm --cached README 450 | git rm 命令后面可以列出文件或者目录的名字,也可以使用 glob 模式。比如: 451 | 452 | $ git rm log/\*.log 453 | 注意到星号 * 之前的反斜杠 \, 因为 Git 有它自己的文件模式扩展匹配方式,所以我们不用 shell 来帮忙展开。 此命令删除 log/ 目录下扩展名为 .log 的所有文件。 类似的比如: 454 | 455 | $ git rm \*~ 456 | 该命令会删除所有名字以 ~ 结尾的文件。 457 | 458 | ### 2.2.9 移动文件 459 | 不像其它的 VCS 系统,Git 并不显式跟踪文件移动操作。 如果在 Git 中重命名了某个文件,仓库中存储的元数据并不会体现出这是一次改名操作。 不过 Git 非常聪明,它会推断出究竟发生了什么,至于具体是如何做到的,我们稍后再谈。 460 | 461 | 既然如此,当你看到 Git 的 mv 命令时一定会困惑不已。 要在 Git 中对文件改名,可以这么做: 462 | 463 | $ git mv file_from file_to 464 | 它会恰如预期般正常工作。 实际上,即便此时查看状态信息,也会明白无误地看到关于重命名操作的说明: 465 | ```shell 466 | $ git mv README.md README 467 | $ git status 468 | On branch master 469 | Your branch is up-to-date with 'origin/master'. 470 | Changes to be committed: 471 | (use "git reset HEAD ..." to unstage) 472 | 473 | renamed: README.md -> README 474 | ``` 475 | 其实,运行 git mv 就相当于运行了下面三条命令: 476 | 477 | $ mv README.md README 478 | $ git rm README.md 479 | $ git add README 480 | 如此分开操作,Git 也会意识到这是一次重命名,所以不管何种方式结果都一样。 两者唯一的区别在于,git mv 是一条命令而非三条命令,直接使用 git mv 方便得多。 不过在使用其他工具重命名文件时,记得在提交前 git rm 删除旧文件名,再 git add 添加新文件名。 481 | 482 | ## 2.3 查看提交历史 483 | 在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史。 完成这个任务最简单而又有效的工具是 git log 命令。 484 | 485 | 我们使用一个非常简单的 “simplegit” 项目作为示例。 运行下面的命令获取该项目: 486 | ```shell 487 | $ git clone https://github.com/schacon/simplegit-progit 488 | 当你在此项目中运行 git log 命令时,可以看到下面的输出: 489 | 490 | $ git log 491 | commit ca82a6dff817ec66f44342007202690a93763949 492 | Author: Scott Chacon 493 | Date: Mon Mar 17 21:52:11 2008 -0700 494 | 495 | changed the version number 496 | 497 | commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 498 | Author: Scott Chacon 499 | Date: Sat Mar 15 16:40:33 2008 -0700 500 | 501 | removed unnecessary test 502 | 503 | commit a11bef06a3f659402fe7563abf99ad00de2209e6 504 | Author: Scott Chacon 505 | Date: Sat Mar 15 10:31:28 2008 -0700 506 | 507 | first commit 508 | ``` 509 | 不传入任何参数的默认情况下,git log 会按时间先后顺序列出所有的提交,最近的更新排在最上面。 正如你所看到的,这个命令会列出每个提交的 SHA-1 校验和、作者的名字和电子邮件地址、提交时间以及提交说明。 510 | 511 | git log 有许多选项可以帮助你搜寻你所要找的提交, 下面我们会介绍几个最常用的选项。 512 | 513 | 其中一个比较有用的选项是 -p 或 --patch ,它会显示每次提交所引入的差异(按 补丁 的格式输出)。 你也可以限制显示的日志条目数量,例如使用 -2 选项来只显示最近的两次提交: 514 | ```shell 515 | $ git log -p -2 516 | commit ca82a6dff817ec66f44342007202690a93763949 517 | Author: Scott Chacon 518 | Date: Mon Mar 17 21:52:11 2008 -0700 519 | 520 | changed the version number 521 | 522 | diff --git a/Rakefile b/Rakefile 523 | index a874b73..8f94139 100644 524 | --- a/Rakefile 525 | +++ b/Rakefile 526 | @@ -5,7 +5,7 @@ require 'rake/gempackagetask' 527 | spec = Gem::Specification.new do |s| 528 | s.platform = Gem::Platform::RUBY 529 | s.name = "simplegit" 530 | - s.version = "0.1.0" 531 | + s.version = "0.1.1" 532 | s.author = "Scott Chacon" 533 | s.email = "schacon@gee-mail.com" 534 | s.summary = "A simple gem for using Git in Ruby code." 535 | 536 | commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 537 | Author: Scott Chacon 538 | Date: Sat Mar 15 16:40:33 2008 -0700 539 | 540 | removed unnecessary test 541 | 542 | diff --git a/lib/simplegit.rb b/lib/simplegit.rb 543 | index a0a60ae..47c6340 100644 544 | --- a/lib/simplegit.rb 545 | +++ b/lib/simplegit.rb 546 | @@ -18,8 +18,3 @@ class SimpleGit 547 | end 548 | 549 | end 550 | - 551 | -if $0 == __FILE__ 552 | - git = SimpleGit.new 553 | - puts git.show 554 | -end 555 | 556 | ``` 557 | 该选项除了显示基本信息之外,还附带了每次提交的变化。 当进行代码审查,或者快速浏览某个搭档的提交所带来的变化的时候,这个参数就非常有用了。 你也可以为 git log 附带一系列的总结性选项。 比如你想看到每次提交的简略统计信息,可以使用 --stat 选项: 558 | 559 | ```shell 560 | $ git log --stat 561 | commit ca82a6dff817ec66f44342007202690a93763949 562 | Author: Scott Chacon 563 | Date: Mon Mar 17 21:52:11 2008 -0700 564 | 565 | changed the version number 566 | 567 | Rakefile | 2 +- 568 | 1 file changed, 1 insertion(+), 1 deletion(-) 569 | 570 | commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 571 | Author: Scott Chacon 572 | Date: Sat Mar 15 16:40:33 2008 -0700 573 | 574 | removed unnecessary test 575 | 576 | lib/simplegit.rb | 5 ----- 577 | 1 file changed, 5 deletions(-) 578 | 579 | commit a11bef06a3f659402fe7563abf99ad00de2209e6 580 | Author: Scott Chacon 581 | Date: Sat Mar 15 10:31:28 2008 -0700 582 | 583 | first commit 584 | 585 | README | 6 ++++++ 586 | Rakefile | 23 +++++++++++++++++++++++ 587 | lib/simplegit.rb | 25 +++++++++++++++++++++++++ 588 | 3 files changed, 54 insertions(+) 589 | ``` 590 | 591 | 正如你所看到的,--stat 选项在每次提交的下面列出所有被修改过的文件、有多少文件被修改了以及被修改过的文件的哪些行被移除或是添加了。 在每次提交的最后还有一个总结。 592 | 593 | 另一个非常有用的选项是 --pretty。 这个选项可以使用不同于默认格式的方式展示提交历史。 这个选项有一些内建的子选项供你使用。 比如 oneline 会将每个提交放在一行显示,在浏览大量的提交时非常有用。 另外还有 short,full 和 fuller 选项,它们展示信息的格式基本一致,但是详尽程度不一: 594 | 595 | ```shell 596 | $ git log --pretty=oneline 597 | ca82a6dff817ec66f44342007202690a93763949 changed the version number 598 | 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test 599 | a11bef06a3f659402fe7563abf99ad00de2209e6 first commit 600 | 最有意思的是 format ,可以定制记录的显示格式。 这样的输出对后期提取分析格外有用——因为你知道输出的格式不会随着 Git 的更新而发生改变: 601 | 602 | $ git log --pretty=format:"%h - %an, %ar : %s" 603 | ca82a6d - Scott Chacon, 6 years ago : changed the version number 604 | 085bb3b - Scott Chacon, 6 years ago : removed unnecessary test 605 | a11bef0 - Scott Chacon, 6 years ago : first commit 606 | git log --pretty=format 常用的选项 列出了 format 接受的常用格式占位符的写法及其代表的意义。 607 | 608 | Table 1. git log --pretty=format 常用的选项 609 | 选项 说明 610 | %H提交的完整哈希值 611 | 612 | %h提交的简写哈希值 613 | 614 | %T树的完整哈希值 615 | 616 | %t树的简写哈希值 617 | 618 | %P父提交的完整哈希值 619 | 620 | %p父提交的简写哈希值 621 | 622 | %an作者名字 623 | 624 | %ae作者的电子邮件地址 625 | 626 | %ad作者修订日期(可以用 --date=选项 来定制格式) 627 | 628 | %ar作者修订日期,按多久以前的方式显示 629 | 630 | %cn提交者的名字 631 | 632 | %ce提交者的电子邮件地址 633 | 634 | %cd提交日期 635 | 636 | %cr提交日期(距今多长时间) 637 | 638 | %s提交说明 639 | ``` 640 | 641 | 642 | 你一定奇怪 作者 和 提交者 之间究竟有何差别, 其实作者指的是实际作出修改的人,提交者指的是最后将此工作成果提交到仓库的人。 所以,当你为某个项目发布补丁,然后某个核心成员将你的补丁并入项目时,你就是作者,而那个核心成员就是提交者。 我们会在 分布式 Git 再详细介绍两者之间的细微差别。 643 | 644 | 当 oneline 或 format 与另一个 log 选项 --graph 结合使用时尤其有用。 这个选项添加了一些 ASCII 字符串来形象地展示你的分支、合并历史: 645 | ```shell 646 | $ git log --pretty=format:"%h %s" --graph 647 | * 2d3acf9 ignore errors from SIGCHLD on trap 648 | * 5e3ee11 Merge branch 'master' of git://github.com/dustin/grit 649 | |\ 650 | | * 420eac9 Added a method for getting the current branch. 651 | * | 30e367c timeout code and tests 652 | * | 5a09431 add timeout protection to grit 653 | * | e1193f8 support for heads with slashes in them 654 | |/ 655 | * d6016bc require time for xmlschema 656 | * 11d191e Merge branch 'defunkt' into local 657 | ``` 658 | 这种输出类型会在我们下一章学完分支与合并以后变得更加有趣。 659 | 660 | 以上只是简单介绍了一些 git log 命令支持的选项。 git log 的常用选项 列出了我们目前涉及到的和没涉及到的选项,以及它们是如何影响 log 命令的输出的: 661 | 662 | ```shell 663 | Table 2. git log 的常用选项 664 | 选项 说明 665 | -p 666 | 667 | 按补丁格式显示每个提交引入的差异。 668 | 669 | --stat 670 | 671 | 显示每次提交的文件修改统计信息。 672 | 673 | --shortstat 674 | 675 | 只显示 --stat 中最后的行数修改添加移除统计。 676 | 677 | --name-only 678 | 679 | 仅在提交信息后显示已修改的文件清单。 680 | 681 | --name-status 682 | 683 | 显示新增、修改、删除的文件清单。 684 | 685 | --abbrev-commit 686 | 687 | 仅显示 SHA-1 校验和所有 40 个字符中的前几个字符。 688 | 689 | --relative-date 690 | 691 | 使用较短的相对时间而不是完整格式显示日期(比如“2 weeks ago”)。 692 | 693 | --graph 694 | 695 | 在日志旁以 ASCII 图形显示分支与合并历史。 696 | 697 | --pretty 698 | 699 | 使用其他格式显示历史提交信息。可用的选项包括 oneline、short、full、fuller 和 format(用来定义自己的格式)。 700 | 701 | --oneline 702 | 703 | --pretty=oneline --abbrev-commit 合用的简写。 704 | ``` 705 | 706 | ### 2.3.1 限制输出长度 707 | 除了定制输出格式的选项之外,git log 还有许多非常实用的限制输出长度的选项,也就是只输出一部分的提交。 之前你已经看到过 -2 选项了,它只会显示最近的两条提交, 实际上,你可以使用类似 - 的选项,其中的 n 可以是任何整数,表示仅显示最近的 n 条提交。 不过实践中这个选项不是很常用,因为 Git 默认会将所有的输出传送到分页程序中,所以你一次只会看到一页的内容。 708 | 709 | 但是,类似 --since 和 --until 这种按照时间作限制的选项很有用。 例如,下面的命令会列出最近两周的所有提交: 710 | 711 | $ git log --since=2.weeks 712 | 该命令可用的格式十分丰富——可以是类似 "2008-01-15" 的具体的某一天,也可以是类似 "2 years 1 day 3 minutes ago" 的相对日期。 713 | 714 | 还可以过滤出匹配指定条件的提交。 用 --author 选项显示指定作者的提交,用 --grep 选项搜索提交说明中的关键字。 715 | 716 | Note 717 | 你可以指定多个 --author 和 --grep 搜索条件,这样会只输出匹配 任意 --author 模式和 任意 --grep 模式的提交。然而,如果你添加了 --all-match 选项, 则只会输出匹配 所有 --grep 模式的提交。 718 | 719 | 另一个非常有用的过滤器是 -S(俗称“pickaxe”选项,取“用鹤嘴锄在土里捡石头”之意), 它接受一个字符串参数,并且只会显示那些添加或删除了该字符串的提交。 假设你想找出添加或删除了对某一个特定函数的引用的提交,可以调用: 720 | 721 | $ git log -S function_name 722 | 最后一个很实用的 git log 选项是路径(path), 如果只关心某些文件或者目录的历史提交,可以在 git log 选项的最后指定它们的路径。 因为是放在最后位置上的选项,所以用两个短划线(--)隔开之前的选项和后面限定的路径名。 723 | 724 | 在 限制 git log 输出的选项 中列出了常用的选项 725 | 726 | Table 3. 限制 git log 输出的选项 727 | 选项 说明 728 | -仅显示最近的 n 条提交。 729 | 730 | --since, --after仅显示指定时间之后的提交。 731 | 732 | --until, --before仅显示指定时间之前的提交。 733 | 734 | --author仅显示作者匹配指定字符串的提交。 735 | 736 | --committer仅显示提交者匹配指定字符串的提交。 737 | 738 | --grep仅显示提交说明中包含指定字符串的提交。 739 | 740 | -S仅显示添加或删除内容匹配指定字符串的提交。 741 | 742 | 来看一个实际的例子,如果要在 Git 源码库中查看 Junio Hamano 在 2008 年 10 月其间, 除了合并提交之外的哪一个提交修改了测试文件,可以使用下面的命令: 743 | ```shell 744 | $ git log --pretty="%h - %s" --author='Junio C Hamano' --since="2008-10-01" \ 745 | --before="2008-11-01" --no-merges -- t/ 746 | 5610e3b - Fix testcase failure when extended attributes are in use 747 | acd3b9e - Enhance hold_lock_file_for_{update,append}() API 748 | f563754 - demonstrate breakage of detached checkout with symbolic link HEAD 749 | d1a43f2 - reset --hard/read-tree --reset -u: remove unmerged new paths 750 | 51a94af - Fix "checkout --track -b newbranch" on detached HEAD 751 | b0ad11e - pull: allow "git pull origin $something:$current_branch" into an unborn branch 752 | ``` 753 | 在近 40000 条提交中,上面的输出仅列出了符合条件的 6 条记录。 754 | 755 | ### 2.3.2 Tip 756 | 隐藏合并提交 757 | 按照你代码仓库的工作流程,记录中可能有为数不少的合并提交,它们所包含的信息通常并不多。 为了避免显示的合并提交弄乱历史记录,可以为 log 加上 --no-merges 选项。 758 | 759 | ## 2.4 撤消操作 760 | 在任何一个阶段,你都有可能想要撤消某些操作。 这里,我们将会学习几个撤消你所做修改的基本工具。 注意,有些撤消操作是不可逆的。 这是在使用 Git 的过程中,会因为操作失误而导致之前的工作丢失的少有的几个地方之一。 761 | 762 | 有时候我们提交完了才发现漏掉了几个文件没有添加,或者提交信息写错了。 此时,可以运行带有 --amend 选项的提交命令来重新提交: 763 | ```shell 764 | $ git commit --amend 765 | ``` 766 | 这个命令会将暂存区中的文件提交。 如果自上次提交以来你还未做任何修改(例如,在上次提交后马上执行了此命令), 那么快照会保持不变,而你所修改的只是提交信息。 767 | 768 | 文本编辑器启动后,可以看到之前的提交信息。 编辑后保存会覆盖原来的提交信息。 769 | 770 | 例如,你提交后发现忘记了暂存某些需要的修改,可以像下面这样操作: 771 | ```shell 772 | $ git commit -m 'initial commit' 773 | $ git add forgotten_file 774 | $ git commit --amend 775 | ``` 776 | 最终你只会有一个提交——第二次提交将代替第一次提交的结果。 777 | 778 | Note 779 | 当你在修补最后的提交时,与其说是修复旧提交,倒不如说是完全用一个 新的提交 替换旧的提交, 理解这一点非常重要。从效果上来说,就像是旧有的提交从未存在过一样,它并不会出现在仓库的历史中。 780 | 781 | 修补提交最明显的价值是可以稍微改进你最后的提交,而不会让“啊,忘了添加一个文件”或者 “小修补,修正笔误”这种提交信息弄乱你的仓库历史。 782 | 783 | ### 2.4.1 取消暂存的文件 784 | 接下来的两个小节演示如何操作暂存区和工作目录中已修改的文件。 这些命令在修改文件状态的同时,也会提示如何撤消操作。 例如,你已经修改了两个文件并且想要将它们作为两次独立的修改提交, 但是却意外地输入 git add * 暂存了它们两个。如何只取消暂存两个中的一个呢? git status 命令提示了你: 785 | ```shell 786 | $ git add * 787 | $ git status 788 | On branch master 789 | Changes to be committed: 790 | (use "git reset HEAD ..." to unstage) 791 | 792 | renamed: README.md -> README 793 | modified: CONTRIBUTING.md 794 | ``` 795 | 在 “Changes to be committed” 文字正下方,提示使用 git reset HEAD ... 来取消暂存。 所以,我们可以这样来取消暂存 CONTRIBUTING.md 文件: 796 | 797 | ```shell 798 | $ git reset HEAD CONTRIBUTING.md 799 | Unstaged changes after reset: 800 | M CONTRIBUTING.md 801 | $ git status 802 | On branch master 803 | Changes to be committed: 804 | (use "git reset HEAD ..." to unstage) 805 | 806 | renamed: README.md -> README 807 | 808 | Changes not staged for commit: 809 | (use "git add ..." to update what will be committed) 810 | (use "git checkout -- ..." to discard changes in working directory) 811 | 812 | modified: CONTRIBUTING.md 813 | ``` 814 | 这个命令有点儿奇怪,但是起作用了。 CONTRIBUTING.md 文件已经是修改未暂存的状态了。 815 | 816 | Note 817 | git reset 确实是个危险的命令,如果加上了 --hard 选项则更是如此。 然而在上述场景中,工作目录中的文件尚未修改,因此相对安全一些。 818 | 819 | 到目前为止这个神奇的调用就是你需要对 git reset 命令了解的全部。 我们将会在 重置揭密 中了解 reset 的更多细节以及如何掌握它做一些真正有趣的事。 820 | 821 | ### 2.4.2 撤消对文件的修改 822 | 如果你并不想保留对 CONTRIBUTING.md 文件的修改怎么办? 你该如何方便地撤消修改——将它还原成上次提交时的样子(或者刚克隆完的样子,或者刚把它放入工作目录时的样子)? 幸运的是,git status 也告诉了你应该如何做。 在最后一个例子中,未暂存区域是这样: 823 | ```shell 824 | 825 | Changes not staged for commit: 826 | (use "git add ..." to update what will be committed) 827 | (use "git checkout -- ..." to discard changes in working directory) 828 | 829 | modified: CONTRIBUTING.md 830 | ``` 831 | 它非常清楚地告诉了你如何撤消之前所做的修改。 让我们来按照提示执行: 832 | ```shell 833 | $ git checkout -- CONTRIBUTING.md 834 | $ git status 835 | On branch master 836 | Changes to be committed: 837 | (use "git reset HEAD ..." to unstage) 838 | 839 | renamed: README.md -> README 840 | ``` 841 | 可以看到那些修改已经被撤消了。 842 | 843 | ### 2.4.3 Important 844 | 请务必记得 git checkout -- 是一个危险的命令。 你对那个文件在本地的任何修改都会消失——Git 会用最近提交的版本覆盖掉它。 除非你确实清楚不想要对那个文件的本地修改了,否则请不要使用这个命令。 845 | 846 | 如果你仍然想保留对那个文件做出的修改,但是现在仍然需要撤消,我们将会在 Git 分支 介绍保存进度与分支,这通常是更好的做法。 847 | 848 | 记住,在 Git 中任何 已提交 的东西几乎总是可以恢复的。 甚至那些被删除的分支中的提交或使用 --amend 选项覆盖的提交也可以恢复 (阅读 数据恢复 了解数据恢复)。 然而,任何你未提交的东西丢失后很可能再也找不到了。 849 | 850 | ## 2.5 远程仓库的使用 851 | 为了能在任意 Git 项目上协作,你需要知道如何管理自己的远程仓库。 远程仓库是指托管在因特网或其他网络中的你的项目的版本库。 你可以有好几个远程仓库,通常有些仓库对你只读,有些则可以读写。 与他人协作涉及管理远程仓库以及根据需要推送或拉取数据。 管理远程仓库包括了解如何添加远程仓库、移除无效的远程仓库、管理不同的远程分支并定义它们是否被跟踪等等。 在本节中,我们将介绍一部分远程管理的技能。 852 | 853 | ### 2.5.1 Note 854 | 远程仓库可以在你的本地主机上 855 | 你完全可以在一个“远程”仓库上工作,而实际上它在你本地的主机上。 词语“远程”未必表示仓库在网络或互联网上的其它位置,而只是表示它在别处。 在这样的远程仓库上工作,仍然需要和其它远程仓库上一样的标准推送、拉取和抓取操作。 856 | 857 | ### 2.5.2 查看远程仓库 858 | 如果想查看你已经配置的远程仓库服务器,可以运行 git remote 命令。 它会列出你指定的每一个远程服务器的简写。 如果你已经克隆了自己的仓库,那么至少应该能看到 origin ——这是 Git 给你克隆的仓库服务器的默认名字: 859 | ```shell 860 | $ git clone https://github.com/schacon/ticgit 861 | Cloning into 'ticgit'... 862 | remote: Reusing existing pack: 1857, done. 863 | remote: Total 1857 (delta 0), reused 0 (delta 0) 864 | Receiving objects: 100% (1857/1857), 374.35 KiB | 268.00 KiB/s, done. 865 | Resolving deltas: 100% (772/772), done. 866 | Checking connectivity... done. 867 | $ cd ticgit 868 | $ git remote 869 | origin 870 | ``` 871 | 你也可以指定选项 -v,会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL。 872 | ```shell 873 | $ git remote -v 874 | origin https://github.com/schacon/ticgit (fetch) 875 | origin https://github.com/schacon/ticgit (push) 876 | 877 | ``` 878 | 如果你的远程仓库不止一个,该命令会将它们全部列出。 例如,与几个协作者合作的,拥有多个远程仓库的仓库看起来像下面这样: 879 | 880 | ```shell 881 | $ cd grit 882 | $ git remote -v 883 | bakkdoor https://github.com/bakkdoor/grit (fetch) 884 | bakkdoor https://github.com/bakkdoor/grit (push) 885 | cho45 https://github.com/cho45/grit (fetch) 886 | cho45 https://github.com/cho45/grit (push) 887 | defunkt https://github.com/defunkt/grit (fetch) 888 | defunkt https://github.com/defunkt/grit (push) 889 | koke git://github.com/koke/grit.git (fetch) 890 | koke git://github.com/koke/grit.git (push) 891 | origin git@github.com:mojombo/grit.git (fetch) 892 | origin git@github.com:mojombo/grit.git (push) 893 | ``` 894 | 895 | 这表示我们能非常方便地拉取其它用户的贡献。我们还可以拥有向他们推送的权限,这里暂不详述。 896 | 897 | 注意这些远程仓库使用了不同的协议。我们将会在 在服务器上搭建 Git 中了解关于它们的更多信息。 898 | 899 | ### 2.5.3 添加远程仓库 900 | 我们在之前的章节中已经提到并展示了 git clone 命令是如何自行添加远程仓库的, 不过这里将告诉你如何自己来添加它。 运行 git remote add 添加一个新的远程 Git 仓库,同时指定一个方便使用的简写: 901 | ```shell 902 | $ git remote 903 | origin 904 | $ git remote add pb https://github.com/paulboone/ticgit 905 | $ git remote -v 906 | origin https://github.com/schacon/ticgit (fetch) 907 | origin https://github.com/schacon/ticgit (push) 908 | pb https://github.com/paulboone/ticgit (fetch) 909 | pb https://github.com/paulboone/ticgit (push) 910 | ``` 911 | 现在你可以在命令行中使用字符串 pb 来代替整个 URL。 例如,如果你想拉取 Paul 的仓库中有但你没有的信息,可以运行 git fetch pb: 912 | ```shell 913 | $ git fetch pb 914 | remote: Counting objects: 43, done. 915 | remote: Compressing objects: 100% (36/36), done. 916 | remote: Total 43 (delta 10), reused 31 (delta 5) 917 | Unpacking objects: 100% (43/43), done. 918 | From https://github.com/paulboone/ticgit 919 | * [new branch] master -> pb/master 920 | * [new branch] ticgit -> pb/ticgit 921 | ``` 922 | 现在 Paul 的 master 分支可以在本地通过 pb/master 访问到——你可以将它合并到自己的某个分支中, 或者如果你想要查看它的话,可以检出一个指向该点的本地分支。 (我们将会在 Git 分支 中详细介绍什么是分支以及如何使用分支。) 923 | 924 | 从远程仓库中抓取与拉取 925 | 就如刚才所见,从远程仓库中获得数据,可以执行: 926 | 927 | $ git fetch 928 | 这个命令会访问远程仓库,从中拉取所有你还没有的数据。 执行完成后,你将会拥有那个远程仓库中所有分支的引用,可以随时合并或查看。 929 | 930 | 如果你使用 clone 命令克隆了一个仓库,命令会自动将其添加为远程仓库并默认以 “origin” 为简写。 所以,git fetch origin 会抓取克隆(或上一次抓取)后新推送的所有工作。 必须注意 git fetch 命令只会将数据下载到你的本地仓库——它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工作。 931 | 932 | 如果你的当前分支设置了跟踪远程分支(阅读下一节和 Git 分支 了解更多信息), 那么可以用 git pull 命令来自动抓取后合并该远程分支到当前分支。 这或许是个更加简单舒服的工作流程。默认情况下,git clone 命令会自动设置本地 master 分支跟踪克隆的远程仓库的 master 分支(或其它名字的默认分支)。 运行 git pull 通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。 933 | 934 | ### 2.5.4 推送到远程仓库 935 | 当你想分享你的项目时,必须将其推送到上游。 这个命令很简单:git push 。 当你想要将 master 分支推送到 origin 服务器时(再次说明,克隆时通常会自动帮你设置好那两个名字), 那么运行这个命令就可以将你所做的备份到服务器: 936 | 937 | $ git push origin master 938 | 只有当你有所克隆服务器的写入权限,并且之前没有人推送过时,这条命令才能生效。 当你和其他人在同一时间克隆,他们先推送到上游然后你再推送到上游,你的推送就会毫无疑问地被拒绝。 你必须先抓取他们的工作并将其合并进你的工作后才能推送。 阅读 Git 分支 了解如何推送到远程仓库服务器的详细信息。 939 | 940 | 查看某个远程仓库 941 | 如果想要查看某一个远程仓库的更多信息,可以使用 git remote show 命令。 如果想以一个特定的缩写名运行这个命令,例如 origin,会得到像下面类似的信息: 942 | ```shell 943 | $ git remote show origin 944 | * remote origin 945 | Fetch URL: https://github.com/schacon/ticgit 946 | Push URL: https://github.com/schacon/ticgit 947 | HEAD branch: master 948 | Remote branches: 949 | master tracked 950 | dev-branch tracked 951 | Local branch configured for 'git pull': 952 | master merges with remote master 953 | Local ref configured for 'git push': 954 | master pushes to master (up to date) 955 | ``` 956 | 它同样会列出远程仓库的 URL 与跟踪分支的信息。 这些信息非常有用,它告诉你正处于 master 分支,并且如果运行 git pull, 就会抓取所有的远程引用,然后将远程 master 分支合并到本地 master 分支。 它也会列出拉取到的所有远程引用。 957 | 958 | 这是一个经常遇到的简单例子。 如果你是 Git 的重度使用者,那么还可以通过 git remote show 看到更多的信息。 959 | ```shell 960 | $ git remote show origin 961 | * remote origin 962 | URL: https://github.com/my-org/complex-project 963 | Fetch URL: https://github.com/my-org/complex-project 964 | Push URL: https://github.com/my-org/complex-project 965 | HEAD branch: master 966 | Remote branches: 967 | master tracked 968 | dev-branch tracked 969 | markdown-strip tracked 970 | issue-43 new (next fetch will store in remotes/origin) 971 | issue-45 new (next fetch will store in remotes/origin) 972 | refs/remotes/origin/issue-11 stale (use 'git remote prune' to remove) 973 | Local branches configured for 'git pull': 974 | dev-branch merges with remote dev-branch 975 | master merges with remote master 976 | Local refs configured for 'git push': 977 | dev-branch pushes to dev-branch (up to date) 978 | markdown-strip pushes to markdown-strip (up to date) 979 | master pushes to master (up to date) 980 | ``` 981 | 这个命令列出了当你在特定的分支上执行 git push 会自动地推送到哪一个远程分支。 它也同样地列出了哪些远程分支不在你的本地,哪些远程分支已经从服务器上移除了, 还有当你执行 git pull 时哪些本地分支可以与它跟踪的远程分支自动合并。 982 | 983 | ### 2.5.5 远程仓库的重命名与移除 984 | 你可以运行 git remote rename 来修改一个远程仓库的简写名。 例如,想要将 pb 重命名为 paul,可以用 git remote rename 这样做: 985 | ```shell 986 | $ git remote rename pb paul 987 | $ git remote 988 | origin 989 | paul 990 | ``` 991 | 值得注意的是这同样也会修改你所有远程跟踪的分支名字。 那些过去引用 pb/master 的现在会引用 paul/master。 992 | 993 | 如果因为一些原因想要移除一个远程仓库——你已经从服务器上搬走了或不再想使用某一个特定的镜像了, 又或者某一个贡献者不再贡献了——可以使用 git remote remove 或 git remote rm : 994 | ```shell 995 | $ git remote remove paul 996 | $ git remote 997 | origin 998 | ``` 999 | 一旦你使用这种方式删除了一个远程仓库,那么所有和这个远程仓库相关的远程跟踪分支以及配置信息也会一起被删除。 1000 | 1001 | ## 2.6 打标签 1002 | 像其他版本控制系统(VCS)一样,Git 可以给仓库历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点( v1.0 、 v2.0 等等)。 在本节中,你将会学习如何列出已有的标签、如何创建和删除新的标签、以及不同类型的标签分别是什么。 1003 | 1004 | ### 2.6.1 列出标签 1005 | 在 Git 中列出已有的标签非常简单,只需要输入 git tag (可带上可选的 -l 选项 --list): 1006 | ```shell 1007 | $ git tag 1008 | v1.0 1009 | v2.0 1010 | ``` 1011 | 这个命令以字母顺序列出标签,但是它们显示的顺序并不重要。 1012 | 1013 | 你也可以按照特定的模式查找标签。 例如,Git 自身的源代码仓库包含标签的数量超过 500 个。 如果只对 1.8.5 系列感兴趣,可以运行: 1014 | ```shell 1015 | $ git tag -l "v1.8.5*" 1016 | v1.8.5 1017 | v1.8.5-rc0 1018 | v1.8.5-rc1 1019 | v1.8.5-rc2 1020 | v1.8.5-rc3 1021 | v1.8.5.1 1022 | v1.8.5.2 1023 | v1.8.5.3 1024 | v1.8.5.4 1025 | v1.8.5.5 1026 | ``` 1027 | Note 1028 | 按照通配符列出标签需要 -l 或 --list 选项 1029 | 如果你只想要完整的标签列表,那么运行 git tag 就会默认假定你想要一个列表,它会直接给你列出来, 此时的 -l 或 --list 是可选的。 1030 | 1031 | 然而,如果你提供了一个匹配标签名的通配模式,那么 -l 或 --list 就是强制使用的。 1032 | 1033 | ### 2.6.2 创建标签 1034 | Git 支持两种标签:轻量标签(lightweight)与附注标签(annotated)。 1035 | 1036 | 轻量标签很像一个不会改变的分支——它只是某个特定提交的引用。 1037 | 1038 | 而附注标签是存储在 Git 数据库中的一个完整对象, 它们是可以被校验的,其中包含打标签者的名字、电子邮件地址、日期时间, 此外还有一个标签信息,并且可以使用 GNU Privacy Guard (GPG)签名并验证。 通常会建议创建附注标签,这样你可以拥有以上所有信息。但是如果你只是想用一个临时的标签, 或者因为某些原因不想要保存这些信息,那么也可以用轻量标签。 1039 | 1040 | ### 2.6.3 附注标签 1041 | 在 Git 中创建附注标签十分简单。 最简单的方式是当你在运行 tag 命令时指定 -a 选项: 1042 | ```shell 1043 | $ git tag -a v1.4 -m "my version 1.4" 1044 | $ git tag 1045 | v0.1 1046 | v1.3 1047 | v1.4 1048 | -m 选项指定了一条将会存储在标签中的信息。 如果没有为附注标签指定一条信息,Git 会启动编辑器要求你输入信息。 1049 | ``` 1050 | 1051 | 通过使用 git show 命令可以看到标签信息和与之对应的提交信息: 1052 | ```shell 1053 | $ git show v1.4 1054 | tag v1.4 1055 | Tagger: Ben Straub 1056 | Date: Sat May 3 20:19:12 2014 -0700 1057 | 1058 | my version 1.4 1059 | 1060 | commit ca82a6dff817ec66f44342007202690a93763949 1061 | Author: Scott Chacon 1062 | Date: Mon Mar 17 21:52:11 2008 -0700 1063 | 1064 | changed the version number 1065 | ``` 1066 | 输出显示了打标签者的信息、打标签的日期时间、附注信息,然后显示具体的提交信息。 1067 | 1068 | ### 2.6.4 轻量标签 1069 | 另一种给提交打标签的方式是使用轻量标签。 轻量标签本质上是将提交校验和存储到一个文件中——没有保存任何其他信息。 创建轻量标签,不需要使用 -a、-s 或 -m 选项,只需要提供标签名字: 1070 | ```shell 1071 | $ git tag v1.4-lw 1072 | $ git tag 1073 | v0.1 1074 | v1.3 1075 | v1.4 1076 | v1.4-lw 1077 | v1.5 1078 | 这时,如果在标签上运行 git show,你不会看到额外的标签信息。 命令只会显示出提交信息: 1079 | 1080 | $ git show v1.4-lw 1081 | commit ca82a6dff817ec66f44342007202690a93763949 1082 | Author: Scott Chacon 1083 | Date: Mon Mar 17 21:52:11 2008 -0700 1084 | 1085 | changed the version number 1086 | ``` 1087 | ### 2.6.5 后期打标签 1088 | 你也可以对过去的提交打标签。 假设提交历史是这样的: 1089 | ```shell 1090 | $ git log --pretty=oneline 1091 | 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment' 1092 | a6b4c97498bd301d84096da251c98a07c7723e65 beginning write support 1093 | 0d52aaab4479697da7686c15f77a3d64d9165190 one more thing 1094 | 6d52a271eda8725415634dd79daabbc4d9b6008e Merge branch 'experiment' 1095 | 0b7434d86859cc7b8c3d5e1dddfed66ff742fcbc added a commit function 1096 | 4682c3261057305bdd616e23b64b0857d832627b added a todo file 1097 | 166ae0c4d3f420721acbb115cc33848dfcc2121a started write support 1098 | 9fceb02d0ae598e95dc970b74767f19372d61af8 updated rakefile 1099 | 964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo 1100 | 8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme 1101 | ``` 1102 | 现在,假设在 v1.2 时你忘记给项目打标签,也就是在 “updated rakefile” 提交。 你可以在之后补上标签。 要在那个提交上打标签,你需要在命令的末尾指定提交的校验和(或部分校验和): 1103 | 1104 | $ git tag -a v1.2 9fceb02 1105 | 可以看到你已经在那次提交上打上标签了: 1106 | ```shell 1107 | $ git tag 1108 | v0.1 1109 | v1.2 1110 | v1.3 1111 | v1.4 1112 | v1.4-lw 1113 | v1.5 1114 | 1115 | $ git show v1.2 1116 | tag v1.2 1117 | Tagger: Scott Chacon 1118 | Date: Mon Feb 9 15:32:16 2009 -0800 1119 | 1120 | version 1.2 1121 | commit 9fceb02d0ae598e95dc970b74767f19372d61af8 1122 | Author: Magnus Chacon 1123 | Date: Sun Apr 27 20:43:35 2008 -0700 1124 | 1125 | updated rakefile 1126 | ... 1127 | 1128 | ``` 1129 | ### 2.6.6 共享标签 1130 | 默认情况下,git push 命令并不会传送标签到远程仓库服务器上。 在创建完标签后你必须显式地推送标签到共享服务器上。 这个过程就像共享远程分支一样——你可以运行 git push origin 。 1131 | ```shell 1132 | $ git push origin v1.5 1133 | Counting objects: 14, done. 1134 | Delta compression using up to 8 threads. 1135 | Compressing objects: 100% (12/12), done. 1136 | Writing objects: 100% (14/14), 2.05 KiB | 0 bytes/s, done. 1137 | Total 14 (delta 3), reused 0 (delta 0) 1138 | To git@github.com:schacon/simplegit.git 1139 | * [new tag] v1.5 -> v1.5 1140 | ``` 1141 | 如果想要一次性推送很多标签,也可以使用带有 --tags 选项的 git push 命令。 这将会把所有不在远程仓库服务器上的标签全部传送到那里。 1142 | 1143 | ```shell 1144 | $ git push origin --tags 1145 | Counting objects: 1, done. 1146 | Writing objects: 100% (1/1), 160 bytes | 0 bytes/s, done. 1147 | Total 1 (delta 0), reused 0 (delta 0) 1148 | To git@github.com:schacon/simplegit.git 1149 | * [new tag] v1.4 -> v1.4 1150 | * [new tag] v1.4-lw -> v1.4-lw 1151 | ``` 1152 | 现在,当其他人从仓库中克隆或拉取,他们也能得到你的那些标签。 1153 | 1154 | Note 1155 | git push 推送两种标签 1156 | 使用 git push --tags 推送标签并不会区分轻量标签和附注标签, 没有简单的选项能够让你只选择推送一种标签。 1157 | 1158 | ### 2.6.7 删除标签 1159 | 要删除掉你本地仓库上的标签,可以使用命令 git tag -d 。 例如,可以使用以下命令删除一个轻量标签: 1160 | 1161 | $ git tag -d v1.4-lw 1162 | Deleted tag 'v1.4-lw' (was e7d5add) 1163 | 注意上述命令并不会从任何远程仓库中移除这个标签,你必须用 git push :refs/tags/ 来更新你的远程仓库: 1164 | 1165 | 第一种变体是 git push :refs/tags/ : 1166 | 1167 | $ git push origin :refs/tags/v1.4-lw 1168 | To /git@github.com:schacon/simplegit.git 1169 | - [deleted] v1.4-lw 1170 | 上面这种操作的含义是,将冒号前面的空值推送到远程标签名,从而高效地删除它。 1171 | 1172 | 第二种更直观的删除远程标签的方式是: 1173 | 1174 | $ git push origin --delete 1175 | ### 2.6.8 检出标签 1176 | 如果你想查看某个标签所指向的文件版本,可以使用 git checkout 命令, 虽然这会使你的仓库处于“分离头指针(detached HEAD)”的状态——这个状态有些不好的副作用: 1177 | ```shell 1178 | $ git checkout 2.0.0 1179 | Note: checking out '2.0.0'. 1180 | 1181 | You are in 'detached HEAD' state. You can look around, make experimental 1182 | changes and commit them, and you can discard any commits you make in this 1183 | state without impacting any branches by performing another checkout. 1184 | 1185 | If you want to create a new branch to retain commits you create, you may 1186 | do so (now or later) by using -b with the checkout command again. Example: 1187 | 1188 | git checkout -b 1189 | 1190 | HEAD is now at 99ada87... Merge pull request #89 from schacon/appendix-final 1191 | 1192 | $ git checkout 2.0-beta-0.1 1193 | Previous HEAD position was 99ada87... Merge pull request #89 from schacon/appendix-final 1194 | HEAD is now at df3f601... add atlas.json and cover image 1195 | ``` 1196 | 在“分离头指针”状态下,如果你做了某些更改然后提交它们,标签不会发生变化, 但你的新提交将不属于任何分支,并且将无法访问,除非通过确切的提交哈希才能访问。 因此,如果你需要进行更改,比如你要修复旧版本中的错误,那么通常需要创建一个新分支: 1197 | ```shell 1198 | $ git checkout -b version2 v2.0.0 1199 | Switched to a new branch 'version2' 1200 | ``` 1201 | 如果在这之后又进行了一次提交,version2 分支就会因为这个改动向前移动, 此时它就会和 v2.0.0 标签稍微有些不同,这时就要当心了。 1202 | 1203 | ## 2.7 Git 别名 1204 | 在我们结束本章 Git 基础之前,正好有一个小技巧可以使你的 Git 体验更简单、容易、熟悉:别名。 我们不会在之后的章节中引用到或假定你使用过它们,但是你大概应该知道如何使用它们。 1205 | 1206 | Git 并不会在你输入部分命令时自动推断出你想要的命令。 如果不想每次都输入完整的 Git 命令,可以通过 git config 文件来轻松地为每一个命令设置一个别名。 这里有一些例子你可以试试: 1207 | ```shell 1208 | $ git config --global alias.co checkout 1209 | $ git config --global alias.br branch 1210 | $ git config --global alias.ci commit 1211 | $ git config --global alias.st status 1212 | ``` 1213 | 这意味着,当要输入 git commit 时,只需要输入 git ci。 随着你继续不断地使用 Git,可能也会经常使用其他命令,所以创建别名时不要犹豫。 1214 | 1215 | 在创建你认为应该存在的命令时这个技术会很有用。 例如,为了解决取消暂存文件的易用性问题,可以向 Git 中添加你自己的取消暂存别名: 1216 | ```shell 1217 | $ git config --global alias.unstage 'reset HEAD --' 1218 | 这会使下面的两个命令等价: 1219 | ``` 1220 | ```shell 1221 | $ git unstage fileA 1222 | $ git reset HEAD -- fileA 1223 | 这样看起来更清楚一些。 通常也会添加一个 last 命令,像这样: 1224 | ``` 1225 | ```shell 1226 | $ git config --global alias.last 'log -1 HEAD' 1227 | 这样,可以轻松地看到最后一次提交: 1228 | ``` 1229 | ```shell 1230 | $ git last 1231 | commit 66938dae3329c7aebe598c2246a8e6af90d04646 1232 | Author: Josh Goebel 1233 | Date: Tue Aug 26 19:48:51 2008 +0800 1234 | 1235 | test for current head 1236 | 1237 | Signed-off-by: Scott Chacon 1238 | ``` 1239 | 可以看出,Git 只是简单地将别名替换为对应的命令。 然而,你可能想要执行外部命令,而不是一个 Git 子命令。 如果是那样的话,可以在命令前面加入 ! 符号。 如果你自己要写一些与 Git 仓库协作的工具的话,那会很有用。 我们现在演示将 git visual 定义为 gitk 的别名: 1240 | ```shell 1241 | $ git config --global alias.visual '!gitk' 1242 | ``` 1243 | -------------------------------------------------------------------------------- /lecture03/README.md: -------------------------------------------------------------------------------- 1 | # 第三章 Git分支管理 2 | ## 3.1 分支的简介 3 | Git最重要的运用场景是多人协同开发,但是如何能保证每个人之间的开发不影响其他人的开发进程,Git 分支的出现就是解决了这个问题,使得每个人之间的开发是独立的,互不影响的。 4 | 5 | 有的人将 Git 的分支模型称为它的“必杀技特性”,也正因为这一特性,使得 Git 从众多版本控制系统中脱颖而出。 为何 Git 的分支模型如此出众呢? 因为Git 处理分支的方式可谓是难以置信的轻量,创建新分支这一操作几乎能在瞬间完成,并且在不同分支之间的切换操作也是一样便捷。 与许多其它版本控制系统不同,Git 鼓励在工作流程中频繁地使用分支与合并,哪怕一天之内进行许多次。 理解和精通这一特性,你便会意识到 Git 是如此的强大而又独特,并且从此真正改变你的开发方式。 6 | 7 | ## 3.2 分支的相关操作 8 | ### 3.2.1 分支的创建 9 | Git分支的创建十分简单,我们可以使用`git branch`来查看现有的分支或创建新的分支。当不带任何命令参数时,输入`git branch`可以帮助我们查看当前项目所拥有的全部分支。并且Git会使用*来标明我们当前所处的分支上。 10 | ```bash 11 | git branch 12 | ``` 13 | ```bash 14 | * master 15 | ``` 16 | 当我们想要新增加新的分支时,只需要在`git branch`命令后面加上我们想要新建的分支的名称即可。 17 | ```bash 18 | # 创建issue102的分支 19 | git branch issue102 20 | # 查看现有的所有分支 21 | git branch 22 | ``` 23 | ```bash 24 | # 现有的分支 25 | issue102 26 | *master 27 | ``` 28 | 我们可以发现虽然创建了`issue102`的分支,但是当前分支还是在master上。我们可以通过`git checkout`命令来进行切换分支。 29 | ### 3.2.2 分支的切换 30 | 在上面的例子中我们发现虽然创建了新的分支,但是当前分支还是在`master`分支上,我们需要通过`git checkout`命令切换到新建的`issue102`分支上,来进行后续的开发操作。 31 | ```bash 32 | git checkout issue102 33 | ``` 34 | ```bash 35 | Switched to branch 'issue102' 36 | ``` 37 | 这是我们可以在查看下当前分支的状态,我们可以发现当前分支已经转换到了`issue102`分支上。 38 | ```bash 39 | git branch 40 | * issue102 41 | master 42 | ``` 43 | 切换分支后,我们就可以进行自己的开发。分支上的文件状态是不同的。我们可以通过下面的例子有着更深入的了解。 44 | ```bash 45 | # 切换分支 46 | git checkout issue102 47 | 48 | # 在分支上创建下新的文件 49 | touch issue102.md 50 | git add issue102.md 51 | git commit -m "update issue102.md" 52 | 53 | touch issue102.html 54 | git add issue102.html 55 | git commit -m "update issue102.html" 56 | ``` 57 | 在完成上述命令后,我们可以通过`git log --oneline`检查下当前Git的记录。 58 | ```bash 59 | cd836b0 (HEAD -> issue102) update issue102.html 60 | 7575f02 update issue102.md 61 | 242c407 (master) update hello.md 62 | ``` 63 | 我们可以发现issue102分支上的记录与master的记录间隔开了。除此之外,当我们切换回主分支后,我们还会发现master分支下没有新建的issue102.md和issue102.html两个文件。正如下图所示: 64 | ![](./figures/branch_file.png) 65 | ### 3.2.3 分支的合并 66 | 当我们在分支上完成来开发工作后,我们需要将我们在当前分支进行的工作合并到主分支上。首先我们需要切回需要合并到的分支上,此处以`issue102`合并到`master`上为例子进行演示。 67 | ```bash 68 | # 切换回主分支 69 | git checkout master 70 | # 使用git merge 进行合并 71 | git merge issue102 72 | # git branch --no-merged 73 | # 查看所有未合并工作的分支 74 | ``` 75 | ![](./figures/merge.png) 76 | 我们可以发现原来在`issue102`分支上的文件已经合并到了主分支上了,并且`issue102`分支还存在。大家可以根据实际的需求进行分支的保留与删除。 77 | 78 | 79 | 有时候分支的合并不会一番顺利,当我们在两个分支中对同一个文件的同一个部分进行了不同的修改,Git就没有办法顺利的合并他们,会在合并的时候产生合并冲突。比如我们在`issue102`分支和`master`分支下对`issue102.md`文件进行了修改,当我们将issue102分支融合到主分支上时就会发生冲突。如下图所示: 80 | ![](./figures/merge_error.png) 81 | 82 | 我们也可以通过`git status`查看命令来查看那些因包含合并冲突而处于未合并(unmerged)状态的文件。当出现矛盾后,合并的文件内容将会出现"<<<<<<","=======",">>>>>>"等分割线来进行标记。如下图所示: 83 | 84 | ![](./figures/brach_message.png) 85 | 86 | 当出现了矛盾时,我们需要进行手动解决或者放弃合并。 87 | - 手动合并 88 | 89 | 手动合并的方法很简单,就是我们选择我们要保留的代码,然后再把>>>>>, ======, <<<<<<这些提示行给去掉。最后重新进行add commit的操作即可。 90 | - 放弃合并 91 | 92 | 当我们发现冲突所导致的改动量很大时,我们可以选择放弃该次的合并。我们可以使用`git merge --abort`放弃此次的融合。如果我们在运行了git merge之后又进行了一些人为的改动,那么在abort之后,所进行的改动也会被回滚掉。 93 | 94 | - mergetool 95 | 96 | 除了手动合并以及放弃合并之外,我们还有一些其他的合并工具。git官方开发了一个专门用来合并的工具,叫做git mergetool(下图所示),它会将找到一份两个分支的祖先代码作为base(基准),然后再将两个分支的改动都列举出来作为对比,让我们在git编辑器当中决定要留下什么。在此处,我们不做过多的阐述,感兴趣的同学可以点击下方链接进行查看。 97 | 98 | 1. [Use vimdiff as git mergetool](https://www.rosipov.com/blog/use-vimdiff-as-git-mergetool/) 99 | 2. [使用vimdiff作为git mergetool](https://kinboyw.github.io/2018/10/09/Use-Vimdiff-As-Git-Mergetool/) 100 | 3. [git-mergetool](https://www.lhsz.xyz/read/git-doc-zh/docs-16.md) 101 | 102 | ![](./figures/mergetool.png) 103 | 104 | ### 3.2.4 分支推送到远程 105 | 在很多情况下,我们都需要将分支推送到远程,在这一部分,我们将讲一些远程的相关操作。 106 | 首先,我们可以使用`git remote -v`查看远程库的详细信息。会显示我们可以抓取或推送的origin地址。 107 | ```bash 108 | $ git remote -v 109 | origin git@github.com:ProjectOwner/ProjectName.git (fetch) 110 | origin git@github.com:ProjectOwner/ProjectName.git (push) 111 | ``` 112 | 当我们需要推送本地分支到远程时,需要指定具体的本地分支。 113 | ```bash 114 | # 推送本地的master分支到远程 115 | git push origin master 116 | # 推送本地的issue102分支到远程 117 | git push origin issue102 118 | ``` 119 | 但是当我们多人协作进行开发的时候,可能会出现远程分支比我们本地更新的情况,这时,我们就需要使用`git pull`的命令来试图合并。如果合并出现冲突时,我们需要解决冲突再提交。在这部分,推荐大家可以看下廖雪峰老师的Git教程中的 120 | [多人协作](https://www.liaoxuefeng.com/wiki/896043488029600/900375748016320),如有侵权,请联系告知。 121 | ### 3.2.5 分支的删除 122 | 在Git中没有什么分支是不可以删除的(除了当前所在的分支不能删除),包括`master`分支也是可以进行删除。 123 | Git的分支删除可以分为删除本地分支和远程分支。 124 | - 删除本地分支 125 | ```bash 126 | # branchName 是需要删除的本地分支名字 127 | git branch -d branchName 128 | ``` 129 | 当我们想强行删除分支时,只需要将参数d改为D即可。 130 | - 删除远程分支 131 | ```bash 132 | # origin 是远程的主机名 133 | # branch 需要删除的远程分支 134 | git push origin --delete branch 135 | ``` 136 | ### 3.2.6 分支的重命名 137 | 当我们需要重命名分支的名称时,我们可以使用`git branch`命令来进行,具体方式如下: 138 | ```bash 139 | # oldBranchName: 旧分支名 140 | # newBranchName :新分支名 141 | git branch -m oldBranchName newBranchName 142 | ``` 143 | 当我们想要将改名后的分支推送到远程时,我们需要进行如下操作: 144 | ```bash 145 | git branch -m oldBranchName newBranchName # 将本地的分支进行重命名 146 | git push origin newBranchName # 将新的分支推送到远程 147 | git push --delete origin oldBranchName # 删除远程的旧的分支 148 | ``` 149 | ## 3.3 分支开发工作流 150 | 当我们已经了解了分支的操作后,我们应该考虑使用一种怎样的方式使我们最大化的使用分支操作的优点。在接下来的这部分中,我们将会介绍一些常见的分支开发工作流程。而正是由于分支管理的便捷,才衍生出这些典型的工作模式,我们以后可以根据项目实际情况进行使用。 151 | 152 | ### 3.3.1 长期分支 153 | 在整个项目开发周期的不同阶段,我们可以同时拥有多个分支;然后我们可以定期地把某些主题分支合并入其他分支中。许多使用 Git 的开发者都喜欢使用这种方式来工作,比如只在 master 分支上保留完全稳定的代码——有可能仅仅是已经发布或即将发布的代码。 他们还有一些名为 develop 或者 next 的平行分支,被用来做后续开发或者测试稳定性——这些分支不必保持绝对稳定,但是一旦达到稳定状态,它们就可以被合并入 master 分支了。这样,在确保这些已完成的主题分支(短期分支,比如之前的 issue102 分支)能够通过所有测试,并且不会引入更多 bug 之后,就可以合并入主干分支中,等待下一次的发布。 154 | ![](./figures/branches.png) 155 | 156 | ### 3.3.2 短期分支 157 | 短期分支也可以叫做主题分支,它的作用是用来实现某一种特性或者相关工作(修复bug,开发产品新特性)。比如当我们的产品出现了bug时,我们应该新建一个分支并起名为bug分支,并在该分支上进行bug的修复,等我们的代码确定不会引起其他bug时,我们就可以合并到主分支上进行修复。当我们看见issue时,我们也可以使用同样的方式来解决issue的问题。常见的短期分支还有上面提到的develop,topic分支。在实际开发中,我们应该按照以下几个基本原则进行分支开发工作流程 158 | 159 | 1. master分支应该是最稳定的,也就是仅用来发布新版本,平时不能直接在上面进行操作,应该保存在远程。 160 | 2. 短期分支是我们干活的分支,短期分支可以不用上传到远程,当我们完成了bug的修复,新功能的开发时才需要合并到主分支上。 161 | 3. 多使用分支来进行开发工作。 162 | 163 | -------------------------------------------------------------------------------- /lecture03/figures/brach_message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/faster-git/08277470cee6e0955f255452a9fe4a0fa7842c43/lecture03/figures/brach_message.png -------------------------------------------------------------------------------- /lecture03/figures/branch_file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/faster-git/08277470cee6e0955f255452a9fe4a0fa7842c43/lecture03/figures/branch_file.png -------------------------------------------------------------------------------- /lecture03/figures/branches.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/faster-git/08277470cee6e0955f255452a9fe4a0fa7842c43/lecture03/figures/branches.png -------------------------------------------------------------------------------- /lecture03/figures/merge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/faster-git/08277470cee6e0955f255452a9fe4a0fa7842c43/lecture03/figures/merge.png -------------------------------------------------------------------------------- /lecture03/figures/merge_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/faster-git/08277470cee6e0955f255452a9fe4a0fa7842c43/lecture03/figures/merge_error.png -------------------------------------------------------------------------------- /lecture03/figures/mergetool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/faster-git/08277470cee6e0955f255452a9fe4a0fa7842c43/lecture03/figures/mergetool.png -------------------------------------------------------------------------------- /lecture04/README.md: -------------------------------------------------------------------------------- 1 | # 第四章 Git 工具 2 | 3 | > Author: Martin 4 | 5 | 本章主要介绍 Git 常用的工具,可能不会经常用到,但是“万一”呢,你说对吧? 看看总归不会有坏处,技多不压身嘛 🐶。 6 | 7 | ## 4.0 开始你的工作 8 | 9 | 我们需要一些简单的文件和目录来演示该章节,如果可以的话,请 fork 这个演示项目至你的个人账号下,来跟我一起动起手来。 10 | 11 | > https://github.com/datawhalechina-git-samples/app 12 | 13 | 后续演示均以这个 repo 操作。 14 | 15 | ## 4.1 引用修订版本 16 | 17 | Git 支持多种方式来引用单个提交、一组提交或一定范围内的提交。 18 | 19 | ### 4.1.1 引用 Commit 的记录 20 | 21 | 你可以通过任意一个提交的 40 位字符的 `SHA-1`散列值来指定它。 22 | 23 | **`$` 是终端交互的提示符,不需要输入。如果系统或者终端不一样,只需输入`$`后的内容即可,本文后续不再累述** 24 | 25 | 切换至本项目工作目录,执行 `git log` 能看到类似提交日志的输出。(shell 通过 pipe `|` 将输出信息传递给 `more` 做多页显示)。 26 | 27 | ```bash 28 | $ git log | more 29 | 30 | commit 44328544187650f2f6ecc253ef3a2b099c51baa5 31 | Author: Martin Xu 32 | Date: Wed May 4 13:41:55 2022 +0800 33 | 34 | add model module 35 | 36 | commit a55ea122894272b13c3a43129ca0b74cfd2b6a4a 37 | Author: Martin Xu 38 | Date: Wed May 4 13:33:17 2022 +0800 39 | 40 | Initial commit 41 | ``` 42 | 43 | 从日志能明显的看到多次提交的记录,每次包括 `commit` + 一串字符、作者、提交时间 和详细信息等。 44 | 45 | 这里的主角就是 commit 后跟的 40 位的字符,这个值是一个 SHA-1 哈希值。它是对内容和头信息 Header 的一个校验和 checksum,Git 使用 SHA-1 并不是为了数据的安全性,而是数据的完整性;它保证,在很多年后,你重新 checkout 某个 commit 时,一定是当时的状态,完全一摸一样。 有兴趣进一步了解这个 SHA-1 的值,可以 [参考这里](https://www.jianshu.com/p/4f8b56d0fd5b)。 46 | 47 | 想查看某次提交信息,可以通过 `git show` 来查看,如: 48 | 49 | ```bash 50 | $ git show 44328544187650f2f6ecc253ef3a2b099c51baa5 51 | 52 | commit 44328544187650f2f6ecc253ef3a2b099c51baa5 (HEAD -> main, origin/main, origin/HEAD) 53 | Author: Martin Xu 54 | Date: Wed May 4 13:41:55 2022 +0800 55 | 56 | add model module 57 | 58 | diff --git a/.gitmodules b/.gitmodules 59 | new file mode 100644 60 | index 0000000..f9d131a 61 | --- /dev/null 62 | +++ b/.gitmodules 63 | @@ -0,0 +1,3 @@ 64 | +[submodule "model"] 65 | + path = model 66 | + url = https://github.com/datawhalechina-git-samples/model 67 | diff --git a/model b/model 68 | new file mode 160000 69 | index 0000000..a8328fd 70 | --- /dev/null 71 | +++ b/model 72 | @@ -0,0 +1 @@ 73 | +Subproject commit a8328fd6ee683ef8f6a2d7c4edfefed2923b0795 74 | 75 | ``` 76 | 77 | 查看所有所有提交 SHA-1 字符串 78 | 79 | ```bash 80 | $ git log|grep '^commit'|awk '{print $2}' 81 | 82 | 44328544187650f2f6ecc253ef3a2b099c51baa5 83 | a55ea122894272b13c3a43129ca0b74cfd2b6a4a 84 | ``` 85 | 86 | Git 非常聪明的知道在没有歧义的情况下,通过前几个字符来替代上述 40 位字符,如上可简化成: 87 | 88 | ```bash 89 | $ git show 4432854 90 | ``` 91 | 92 | 甚至简化成 93 | 94 | ```bash 95 | $ git show 4432 96 | ``` 97 | 98 | 当然你的确保没有歧义。Git 可以为 SHA-1 值生成出简短且唯一的缩写,可以在 `git log` 后加 ` --abbrev-commit` 参数,输出结果就会显示简短且唯一的值了。默认情况使用 7 个字符,有时为来避免歧义,会增加字符数。 99 | 100 | ```bash 101 | $ git log --abbrev-commit 102 | 103 | commit 4432854 (HEAD -> main, origin/main, origin/HEAD) 104 | Author: Martin Xu 105 | Date: Wed May 4 13:41:55 2022 +0800 106 | 107 | add model module 108 | 109 | commit a55ea12 110 | Author: Martin Xu 111 | Date: Wed May 4 13:33:17 2022 +0800 112 | 113 | Initial commit 114 | 115 | ``` 116 | 117 | 通过在 `git log`后增加 `--pretty=oneline`简化输出内容 118 | 119 | ```bash 120 | $ git log --abbrev-commit --pretty=oneline 121 | 122 | 4432854 (HEAD -> main, origin/main, origin/HEAD) add model module 123 | a55ea12 Initial commit 124 | ``` 125 | 126 | ### 4.1.2 引用分支 127 | 128 | 如果你要查看一个分支的最后一次对象,可以通过分支名查看。查看本地分支列表通过`git branch`查看 129 | 130 | ```bash 131 | $ git branch 132 | 133 | develop 134 | main 135 | * stable 136 | ``` 137 | 138 | `*` 表示当前工作的分支 139 | 140 | 查看远程分支通过后加参数`-r` 141 | 142 | ```bash 143 | $ git branch -r 144 | 145 | origin/HEAD -> origin/main 146 | origin/main 147 | origin/stable 148 | ``` 149 | 150 | 我们尝试通过`git show stable`查看指定分支最后一次提交信息 151 | 152 | ```bash 153 | $ git show stable 154 | 155 | commit 11671bae8489621c02a4c99dbcf24b0dede1b1b1 (HEAD -> stable) 156 | Author: Martin Xu 157 | Date: Wed May 4 14:16:00 2022 +0800 158 | 159 | stable model for app 160 | 161 | diff --git a/.gitmodules b/.gitmodules 162 | index f9d131a..47d8924 100644 163 | --- a/.gitmodules 164 | +++ b/.gitmodules 165 | @@ -1,3 +1,4 @@ 166 | [submodule "model"] 167 | path = model 168 | url = https://github.com/datawhalechina-git-samples/model 169 | + branch = stable 170 | diff --git a/model b/model 171 | index a8328fd..ca79fae 160000 172 | --- a/model 173 | +++ b/model 174 | @@ -1 +1 @@ 175 | -Subproject commit a8328fd6ee683ef8f6a2d7c4edfefed2923b0795 176 | +Subproject commit ca79fae869c9b4ddd7999f06ffd48ac25971b9dd 177 | ``` 178 | 179 | 如果你的 branch 的名称和当前目录名称很不巧的重名了,那么应该会出现意外的输出 😭 并没有我们期盼中的结果。 180 | 181 | 创建同名测试目录 182 | 183 | ```bash 184 | $ mkdir stable 185 | ``` 186 | 187 | 再次执行`git show stable` 188 | 189 | ```bash 190 | $ git show stable 191 | 192 | fatal: ambiguous argument 'stable': both revision and filename 193 | Use '--' to separate paths from revisions, like this: 194 | 'git [...] -- [...]' 195 | ``` 196 | 197 | Git 不知道如何处理,我们需要通过 `--` 明确告知. 198 | 199 | - -- 前面的为 revision 可以是分支,tag 等 200 | - -- 后面的为 file 即要操作的文件 201 | 202 | ```bash 203 | $ git show stable -- 204 | ``` 205 | 206 | 我们通过 `git rev-parse`可以查看某个分支指向那个特定的 SHA-1, 并通过 `git show` 去查看这个 SHA-1 值对应的提交信息。 207 | 208 | ```bash 209 | $ git rev-parse stable 210 | 211 | 11671bae8489621c02a4c99dbcf24b0dede1b1b1 212 | 213 | $ git show 11671bae8489621c02a4c99dbcf24b0dede1b1b1 214 | 215 | ``` 216 | 217 | 我们能看到是一致的信息。 218 | 219 | ### 4.1.3 引用日志 220 | 221 | 当你在工作时, Git 会在后台保存一个引用日志(reflog), 引用日志记录了最近几个月你的 HEAD 和分支引用所指向的历史。 222 | 你可以使用 git reflog 来查看引用日志 223 | 224 | ```bash 225 | $ git reflog 226 | 227 | 11671ba (HEAD -> stable, origin/stable) HEAD@{0}: commit: stable model for app 228 | 4432854 (origin/main, origin/HEAD, main, develop) HEAD@{1}: checkout: moving from main to stable 229 | 4432854 (origin/main, origin/HEAD, main, develop) HEAD@{2}: commit: add model module 230 | a55ea12 HEAD@{3}: clone: from https://github.com/datawhalechina-git-samples/app 231 | 232 | ``` 233 | 234 | 每当你的 HEAD 所指向的位置发生了变化,Git 就会将这个信息存储到引用日志这个历史记录里。 你也可以通过 reflog 数据来获取之前的提交历史。 如果你想查看仓库中 HEAD 在 2 次前的所指向的提交,你可以使用 @{n} 来引用 reflog 中输出的提交记录。 235 | 236 | ```bash 237 | $ git show HEAD@{2} 238 | 239 | commit 44328544187650f2f6ecc253ef3a2b099c51baa5 (origin/main, origin/HEAD, main, develop) 240 | Author: Martin Xu 241 | Date: Wed May 4 13:41:55 2022 +0800 242 | 243 | add model module 244 | 245 | diff --git a/.gitmodules b/.gitmodules 246 | new file mode 100644 247 | index 0000000..f9d131a 248 | --- /dev/null 249 | +++ b/.gitmodules 250 | @@ -0,0 +1,3 @@ 251 | +[submodule "model"] 252 | + path = model 253 | + url = https://github.com/datawhalechina-git-samples/model 254 | diff --git a/model b/model 255 | new file mode 160000 256 | index 0000000..a8328fd 257 | --- /dev/nullq 258 | +++ b/model 259 | @@ -0,0 +1 @@ 260 | +Subproject commit a8328fd6ee683ef8f6a2d7c4edfefed2923b0795 261 | ``` 262 | 263 | ## 4.2 交互式暂存 264 | 265 | 当你修改大量文件后,希望将改动拆分成多个提交而不是一起提交的时候,可以通过如下命令操作。 266 | 267 | 如果运行 `git add` 后加 `-i` 或者 `--interactive` 选项的时候,Git 会进入一个交互式命令模式,如: 268 | 269 | ```bash 270 | $ git add -i 271 | 272 | staged unstaged path 273 | 1: +532/-0 nothing src/trace/events.go 274 | 2: +365/-0 nothing src/trace/histogram.go 275 | 3: +325/-0 nothing src/trace/histogram_test.go 276 | 4: +1130/-0 nothing src/trace/trace.go 277 | 5: +178/-0 nothing src/trace/trace_test.go 278 | 279 | *** Commands *** 280 | 1: status 2: update 3: revert 4: add untracked 281 | 5: patch 6: diff 7: quit 8: help 282 | What now> 283 | ``` 284 | 285 | 可以看到这个命令以和平时不同的视图:显示了暂存区。基本上与 git status 是相同的信息,但是更简明扼要一些。 它将暂存的修改列在左侧,未暂存的修改列在右侧。 286 | 287 | 在这块区域后是 `Commands` 命令区域。 在这里你可以做一些工作,包括暂存文件、取消暂存文件、暂存文件的一部分、添加未被追踪的文件、显示暂存内容的区别。 288 | 289 | ### 4.2.1 暂存、取消文件 290 | 291 | 在 `What now>>` 提示符后输入`u`或者`2`,它会提示你要暂存哪个文件 292 | 293 | ```bash 294 | $ git add -i 295 | 296 | staged unstaged path 297 | 1: +532/-0 nothing src/trace/events.go 298 | 2: +365/-0 nothing src/trace/histogram.go 299 | 3: +325/-0 nothing src/trace/histogram_test.go 300 | 4: +1130/-0 nothing src/trace/trace.go 301 | 5: +178/-0 +1/-1 src/trace/trace_test.go 302 | 303 | *** Commands *** 304 | 1: status 2: update 3: revert 4: add untracked 305 | 5: patch 6: diff 7: quit 8: help 306 | 307 | What now> u 308 | staged unstaged path 309 | 1: +178/-0 +1/-1 src/trace/trace_test.go 310 | Update>> 1 311 | staged unstaged path 312 | * 1: +178/-0 +1/-1 src/trace/trace_test.go 313 | Update>> 314 | updated 1 path 315 | 316 | *** Commands *** 317 | 1: status 2: update 3: revert 4: add untracked 318 | 5: patch 6: diff 7: quit 8: help 319 | What now> s 320 | staged unstaged path 321 | 1: +532/-0 nothing src/trace/events.go 322 | 2: +365/-0 nothing src/trace/histogram.go 323 | 3: +325/-0 nothing src/trace/histogram_test.go 324 | 4: +1130/-0 nothing src/trace/trace.go 325 | 5: +178/-0 nothing src/trace/trace_test.go 326 | ``` 327 | 328 | 再输入`u` 后根据提示的文件列表,输入序号,这里我们要暂存`src/trace/trace_test.go`,输入 5, 会看到文件名称有个`*`,意味着选中的文件将被暂存。如果不需要其他操作了,直接按回车,不输入任何东西返回命令行界面。通过命令`s`查看状态,发现`src/trace/trace_test.go` 已经被暂存了。 329 | 330 | 如果想取消暂存,在 `What now>>` 提示符后输入`r`或者`3`,进行撤销,同上的操作。 331 | 332 | 如果想要查看已暂存内容的区别,可以使用 d 或 6(区别)命令。 它会显示暂存文件的一个列表,可以从中选择想要查看的暂存区别。 这跟你在命令行指定 git diff --cached 非常相似: 333 | 334 | ```bash 335 | $ git add -i 336 | 337 | staged unstaged path 338 | 1: +1/-1 nothing src/trace/trace_test.go 339 | 340 | What now> d 341 | staged unstaged path 342 | 1: +1/-1 nothing src/trace/trace_test.go 343 | 344 | Review diff>> 1 345 | 346 | diff --git a/src/trace/trace_test.go b/src/trace/trace_test.go 347 | index 8cc7998..33732e6 100644 348 | --- a/src/trace/trace_test.go 349 | +++ b/src/trace/trace_test.go 350 | @@ -1,7 +1,7 @@ 351 | // Copyright 2015 The Go Authors. All rights reserved. 352 | // Use of this source code is governed by a BSD-style 353 | // license that can be found in the LICENSE file. 354 | - 355 | +// 356 | package trace 357 | 358 | import ( 359 | 360 | ``` 361 | 362 | 通过这些基本命令,可以使用交互式添加模式来轻松地处理暂存区。 363 | 364 | ### 4.2.2 暂存补丁 365 | 366 | Git 也可以暂存文件的特定部分。 例如,如果在 TODO 文件中做了两处修改,但只想要暂存其中的一个而不是另一个,Git 会帮你轻松地完成。 在和上一节一样的交互式提示符中,输入 p 或 5。 367 | 368 | ```bash 369 | $ git add -i 370 | 371 | staged unstaged path 372 | 1: unchanged +2/-1 src/trace/trace_test.go 373 | 374 | *** Commands *** 375 | 1: status 2: update 3: revert 4: add untracked 376 | 5: patch 6: diff 7: quit 8: help 377 | What now> p 378 | staged unstaged path 379 | 1: unchanged +2/-1 src/trace/trace_test.go 380 | 381 | Patch update>> 1 382 | staged unstaged path 383 | * 1: unchanged +2/-1 src/trace/trace_test.go 384 | Patch update>> 385 | 386 | diff --git a/src/trace/trace_test.go b/src/trace/trace_test.go 387 | index 8cc7998..a95f46e 100644 388 | --- a/src/trace/trace_test.go 389 | +++ b/src/trace/trace_test.go 390 | @@ -1,7 +1,8 @@ 391 | // Copyright 2015 The Go Authors. All rights reserved. 392 | // Use of this source code is governed by a BSD-style 393 | // license that can be found in the LICENSE file. 394 | - 395 | +// 396 | +// copy from go framework 397 | package trace 398 | 399 | import ( 400 | (1/1) Stage this hunk [y,n,q,a,d,e,?]? 401 | 402 | ``` 403 | 404 | 输入`p` 后,选择你需要操作的文件后,直接敲回车,会逐一询问你是否需要暂存他们,`(1/1)` 表示当前是第 1 个初变更,共 1 处变更。选项很多,输入?可以查看具体的解释 405 | 406 | ``` 407 | y - stage this hunk 408 | n - do not stage this hunk 409 | q - quit; do not stage this hunk or any of the remaining ones 410 | a - stage this hunk and all later hunks in the file 411 | d - do not stage this hunk or any of the later hunks in the file 412 | g - select a hunk to go to 413 | / - search for a hunk matching the given regex 414 | j - leave this hunk undecided, see next undecided hunk 415 | J - leave this hunk undecided, see next hunk 416 | e - manually edit the current hunk 417 | ? - print help 418 | ``` 419 | 420 | 通过`y`或者`n`来选择是否要暂存每一区块,当然也可以通过`a`暂存从这到后面所有当前文件的修改。暂存成功后,退出交互命令,我们就可以通过`git commit`来提交这部分暂存的文件了。 421 | 422 | ## 4.3 贮藏与清理 423 | 424 | 很多时候,你在当前分支上工作了一段时间后,东西变得很混乱。你想切换至新的分支而又不想放弃放弃的修改,或者纯粹想先做其他分支的事情的时候,就该`git stash`上场了。 425 | 426 | `stash` 会处理工作目录的的状态,跟踪文件的修改和暂存的改动,然后将未完成的修改保存至一个栈上,这样就可以在后续任何时间切换回来。 427 | 428 | ```bash 429 | $ git status 430 | 431 | On branch main 432 | Your branch is up to date with 'origin/main'. 433 | 434 | Changes not staged for commit: 435 | (use "git add ..." to update what will be committed) 436 | (use "git restore ..." to discard changes in working directory) 437 | modified: src/trace/trace_test.go 438 | 439 | no changes added to commit (use "git add" and/or "git commit -a") 440 | 441 | ``` 442 | 443 | 文件被修改了一大坨,但是还没修改完,暂时还不想提交,而我又想切换至新的分支,这时候就需要`stash`,先把变更推送至栈上,运行`git stash` 或者 `git stash push` 444 | 445 | ```bash 446 | $ git stash 447 | 448 | Saved working directory and index state WIP on main: a123887 sample codes for demonstration 449 | ``` 450 | 451 | 然后再查看`git status` 452 | 453 | ```bash 454 | $ git status 455 | 456 | On branch main 457 | Your branch is up to date with 'origin/main'. 458 | 459 | nothing to commit, working tree clean 460 | ``` 461 | 462 | 我们能看到当前目录已经非常干净了,这时候你可以按常规操作一样,做你想做的其他的事情。如切换新的分支,或者我想不到的事情. 463 | 464 | 那么要返回刚才那坨文件该怎么办呢?通过 `git stash list` 查看所有 stash 的列表 465 | 466 | ```bash 467 | $ git stash list 468 | 469 | stash@{0}: WIP on main: 36c4cad sample codes for demonstration 470 | 471 | ``` 472 | 473 | 切换至最后 stash 变更,直接执行 `git stash apply` 即可,当然如果有多个,可以通过 `git stash apply stash@{n}` 中的 n 来获取指定的的变更。 474 | 475 | ```bash 476 | $ git stash apply 477 | 478 | On branch main 479 | Your branch is up to date with 'origin/main'. 480 | 481 | Changes not staged for commit: 482 | (use "git add ..." to update what will be committed) 483 | (use "git restore ..." to discard changes in working directory) 484 | modified: src/trace/trace_test.go 485 | 486 | no changes added to commit (use "git add" and/or "git commit -a") 487 | 488 | ``` 489 | 490 | `git stash apply stash@{0}` 会输出同样的内容。 491 | 492 | 可以通过 `git stash drop` 或者 `git stash pop` 来删除 stash 的内容。 493 | 494 | ```bash 495 | $ git stash drop stash@{0} 496 | 497 | Dropped stash@{0} (36c4cad0bafa4dbbd78ae469b0afa38ae2808102) 498 | ``` 499 | 500 | ### 4.3.2 清理工作目录 501 | 502 | 对于一些不需要的文件或目录,你需要的是清理它而不是保存修改记录,`git clean`就是用来做这个事情的 503 | 504 | 需要注意的是,这个命令会移除未被跟踪的文件,可以考虑执行 `git stash --all` 来移除所有文件并保存到栈上。 505 | 506 | 使用 `git clean -f -d` 命令来移除工作目录中所有未追踪的文件以及空的子目录。 `-f` 意味着强制移除,使用它需要 Git 配置变量 `clean.requireForce` 没有显式设置为 `false`。 507 | 508 | 如果你只是想看下或者删除前小心翼翼的确认: 它到底会删除那些东西. 可以通过`--dry-run`或者`-n`选项来执行命令,这只是告诉你会删除什么,而不会真的删除. 509 | 510 | 创建一些临时文件用于测试 511 | 512 | ```bash 513 | $ touch temp; mkdir log; mkdir target; touch target/main 514 | ``` 515 | 516 | 通过`git clean -n`查看 517 | 518 | ```bash 519 | $ git clean -n 520 | 521 | Would remove temp 522 | ``` 523 | 524 | 默认情况下,git clean 命令只会移除没有忽略的未跟踪文件。 任何与 `.gitignore` 或其他忽略文件中的模式匹配的文件都不会被移除。如果你也想移除,可以通过增加选项`-x` 525 | 526 | ```bash 527 | $ git clean -n -x 528 | 529 | Would remove .DS_Store 530 | Would remove temp 531 | ``` 532 | 533 | 同样增加选项`-d`可以删除目录 534 | 535 | ```bash 536 | $ git clean -n -x -d 537 | 538 | Would remove .DS_Store 539 | Would remove log/ 540 | Would remove target/ 541 | Would remove temp 542 | ``` 543 | 544 | 如果你想交互删除,可以通过选项 `-i`来操作 545 | 546 | ```bash 547 | 548 | Would remove the following items: 549 | .DS_Store log/ target/ temp 550 | 551 | *** Commands *** 552 | 1: clean 2: filter by pattern 3: select by numbers 4: ask each 5: quit 553 | 6: help 554 | What now> 555 | ``` 556 | 557 | 通过`What now`后输入命令或序号交互操作,不知道可以输入 help 查看具体的描述 558 | 559 | ```bash 560 | What now> help 561 | 562 | clean - start cleaning 563 | filter by pattern - exclude items from deletion 564 | select by numbers - select items to be deleted by numbers 565 | ask each - confirm each deletion (like "rm -i") 566 | quit - stop cleaning 567 | help - this screen 568 | ? - help for prompt selection 569 | ``` 570 | 571 | ## 4.4 搜索 572 | 573 | 无论仓库里的代码量有多少,你经常需要查找一个函数是在哪里调用或者定义的,或者显示一个方法的变更历史。 Git 提供了两个有用的工具来快速地从它的数据库中浏览代码和提交。 我们来简单的看一下。 574 | 575 | ### 4.4.1 Git Grep 576 | 577 | Git 提供了一个`grep`命令,可以很方便的从提交历史,工作目录,甚至索引中查找一个字符串或者正则表达式。 578 | 579 | 默认情况下`git grep`会查找你的工作目录文件。 580 | 581 | ```bash 582 | $ git grep a.percentileBoundary 583 | 584 | src/trace/histogram.go:func (h *histogram) percentileBoundary(percentile float64) int64 { 585 | src/trace/histogram.go: return h.percentileBoundary(0.5) 586 | src/trace/histogram_test.go: percentile := a.percentileBoundary(test.fraction) 587 | ``` 588 | 589 | 通过`-n`或者`--line-number`显示匹配的行号 590 | 591 | ``` 592 | $ git grep -n percentileBoundary 593 | 594 | src/trace/histogram.go:120:func (h *histogram) percentileBoundary(percentile float64) int64 { 595 | src/trace/histogram.go:166: return h.percentileBoundary(0.5) 596 | src/trace/histogram_test.go:181: percentile := a.percentileBoundary(test.fraction) 597 | ``` 598 | 599 | 通过`-c`或者`--count`输出统计信息 600 | 601 | ```bash 602 | git grep -c percentileBoundary 603 | 604 | src/trace/histogram.go:2 605 | src/trace/histogram_test.go:1 606 | ``` 607 | 608 | 通过`-p` 或者 `--show-function ` 显示每个匹配字符串所在的方法或函数 609 | 610 | ```bash 611 | git grep -p percentileBoundary 612 | 613 | src/trace/histogram.go=func (h *histogram) standardDeviation() float64 { 614 | src/trace/histogram.go:func (h *histogram) percentileBoundary(percentile float64) int64 { 615 | src/trace/histogram.go=func (h *histogram) median() int64 { 616 | src/trace/histogram.go: return h.percentileBoundary(0.5) 617 | src/trace/histogram_test.go=func TestPercentileBoundary(t *testing.T) { 618 | src/trace/histogram_test.go: percentile := a.percentileBoundary(test.fraction) 619 | ``` 620 | 621 | ### 4.4.2 Git 日志搜索 622 | 623 | 通过`git log`可以很强大的知道一些特定的提交信息。 624 | 625 | 如通过`-S`选项知道内容的新增和删除提交记录,我们这里以 CTP 的 Python 的 wrapper 为例: 626 | 627 | ```bash 628 | $ git log -S percentileBoundary 629 | 630 | a123887 (HEAD -> main, origin/main, origin/HEAD) sample codes for demonstration 631 | ``` 632 | 633 | 通过`-L`选项进行行日志搜索,它可以展示代码中一行或者一个函数的历史。 634 | 635 | ```bash 636 | $ git log -L :percentileBoundary:src/trace/histogram.go 637 | 638 | commit a123887e43424c979b3e47b3cf9c672c579a6faa (HEAD -> main, origin/main, origin/HEAD) 639 | Author: Martin Xu 640 | Date: Wed May 4 14:34:18 2022 +0800 641 | 642 | sample codes for demonstration 643 | 644 | diff --git a/src/trace/histogram.go b/src/trace/histogram.go 645 | --- /dev/null 646 | +++ b/src/trace/histogram.go 647 | @@ -0,0 +120,45 @@ 648 | +func (h *histogram) percentileBoundary(percentile float64) int64 { 649 | + total := h.total() 650 | + 651 | + // Corner cases (make sure result is strictly less than Total()) 652 | + if total == 0 { 653 | + return 0 654 | + } else if total == 1 { 655 | + return int64(h.average()) 656 | + } 657 | ... 658 | 659 | ``` 660 | 661 | 如果 Git 无法匹配到你的函数或者方法,可以通过正则表达式,如这个命令和上面是等效的 662 | 663 | ```bash 664 | $ git log -L '/percentileBoundary/',/^}/:src/trace/histogram.go 665 | 666 | commit a123887e43424c979b3e47b3cf9c672c579a6faa (HEAD -> main, origin/main, origin/HEAD) 667 | Author: Martin Xu 668 | Date: Wed May 4 14:34:18 2022 +0800 669 | 670 | sample codes for demonstration 671 | 672 | diff --git a/src/trace/histogram.go b/src/trace/histogram.go 673 | --- /dev/null 674 | +++ b/src/trace/histogram.go 675 | @@ -0,0 +120,43 @@ 676 | +func (h *histogram) percentileBoundary(percentile float64) int64 { 677 | + total := h.total() 678 | + 679 | + // Corner cases (make sure result is strictly less than Total()) 680 | + if total == 0 { 681 | + return 0 682 | ... 683 | ``` 684 | 685 | ## 4.5 子模块 686 | 687 | 项目中经常会遇到包含另外一个项目,如:第三方库,或者你将自己的项目切分成多个子项目,然后在其他项目中引用,如,将项目中的 model 独立处理,独立维护;其他项目组引用这个项目,并不维护 model。这里我们可以将 model 做子项目添加到当前项目中。 688 | 689 | ### 4.5.1 添加子模块 690 | 691 | 通过 `git submodule add` 添加子模块, 大家可以使用 https://github.com/datawhalechina-git-samples/model 进行测试,如 692 | 693 | ```bash 694 | $ git submodule add https://github.com/datawhalechina-git-samples/model 695 | 696 | Cloning into '/Users/martin/project/datawhalechina/app/model'... 697 | 698 | remote: Enumerating objects: 5, done. 699 | remote: Counting objects: 100% (5/5), done. 700 | remote: Compressing objects: 100% (4/4), done. 701 | remote: Total 5 (delta 0), reused 0 (delta 0), pack-reused 0 702 | Receiving objects: 100% (5/5), done. 703 | 704 | ``` 705 | 706 | 参数同 `clone`,默认是 repo 的名称,如果你想改名,可以在后续增加新的名称或路径。 707 | 708 | 通过 `git status` 能看到新的 model 库。 709 | 710 | ```bash 711 | $ git status 712 | 713 | On branch main 714 | Your branch is up to date with 'origin/main'. 715 | 716 | Changes to be committed: 717 | (use "git restore --staged ..." to unstage) 718 | new file: .gitmodules 719 | new file: model 720 | 721 | ``` 722 | 723 | 能看到有个新增的 `model` 和 `.gitmodules`文件,该配置文件保存了项目 URL 和本地目录的 mapping 关系。 724 | 725 | ```bash 726 | $ cat .gitmodules 727 | 728 | [submodule "model"] 729 | path = model 730 | url = https://github.com/datawhalechina-git-samples/model 731 | 732 | ``` 733 | 734 | 如果有多个子模块,这里会列出多条。 735 | 736 | 通过`git diff`能看到更详细的信息 737 | 738 | ```bash 739 | $ git diff --cached model 740 | 741 | diff --git a/model b/model 742 | new file mode 160000 743 | index 0000000..a8328fd 744 | --- /dev/null 745 | +++ b/model 746 | @@ -0,0 +1 @@ 747 | +Subproject commit a8328fd6ee683ef8f6a2d7c4edfefed2923b0795 748 | ``` 749 | 750 | 虽然 model 是工作目录中的一个子目录,但 Git 还是会将它视作一个子模块。当你不在那个目录中时,Git 并不会跟踪它的内容, 而是将它看作子模块仓库中的某个具体的提交。 751 | 752 | 如果你想看到更漂亮的差异输出,可以给 git diff 传递 --submodule 选项。 753 | 754 | ```bash 755 | $ git diff --cached --submodule 756 | 757 | diff --git a/.gitmodules b/.gitmodules 758 | new file mode 100644 759 | index 0000000..f9d131a 760 | --- /dev/null 761 | +++ b/.gitmodules 762 | @@ -0,0 +1,3 @@ 763 | +[submodule "model"] 764 | + path = model 765 | + url = https://github.com/datawhalechina-git-samples/model 766 | Submodule model 0000000...a8328fd (new submodule) 767 | ``` 768 | 769 | 当你提交时,会看到类似下面的信息: 770 | 771 | ```bash 772 | $ git commit -am 'add model module' 773 | 774 | [main 4432854] add model module 775 | 2 files changed, 4 insertions(+) 776 | create mode 100644 .gitmodules 777 | create mode 160000 model 778 | ``` 779 | 780 | 注意 app 记录的 160000 模式。这是 Git 中的一种特殊模式,它本质上意味着你是将一次提交记作一项目录记录的,而非将它记录成一个子目录或者一个文件。 781 | 782 | 然后推送至服务端 783 | 784 | ```bash 785 | git push origin main 786 | 787 | Enumerating objects: 4, done. 788 | Counting objects: 100% (4/4), done. 789 | Delta compression using up to 12 threads 790 | Compressing objects: 100% (3/3), done. 791 | Writing objects: 100% (3/3), 457 bytes | 457.00 KiB/s, done. 792 | Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 793 | To https://github.com/datawhalechina-git-samples/app 794 | a55ea12..4432854 main -> main 795 | ``` 796 | 797 | ### 4.5.2 克隆含有子模块的项目 798 | 799 | 我们在 clone 一个含子模块的项目时,默认是不会包含子模块内容的,只有目录,如重新 clone 上述的 app 项目 800 | 801 | ```bash 802 | $ git clone https://github.com/datawhalechina-git-samples/app.git new_app 803 | 804 | Cloning into 'new_app'... 805 | remote: Enumerating objects: 8, done. 806 | remote: Counting objects: 100% (8/8), done. 807 | remote: Compressing objects: 100% (7/7), done. 808 | remote: Total 8 (delta 1), reused 3 (delta 0), pack-reused 0 809 | Receiving objects: 100% (8/8), done. 810 | Resolving deltas: 100% (1/1), done. 811 | 812 | $ cd new_app/model 813 | $ ls -alh 814 | 815 | total 0 816 | drwxr-xr-x 2 martin staff 64B May 4 13:46 . 817 | drwxr-xr-x 8 martin staff 256B May 4 13:46 .. 818 | 819 | ``` 820 | 821 | 会发现什么也没有,需要通过如下两个命令来获取内容 822 | 823 | - `git submodule init` 初始化本地配置文件 824 | - `git submodule update` 则从该项目中抓取所有数据并检出父项目中列出的合适的提交。 825 | 826 | ```bash 827 | $ git submodule init 828 | 829 | Submodule 'model' (https://github.com/datawhalechina-git-samples/model) registered for path './' 830 | 831 | $ git submodule update 832 | 833 | Cloning into '/Users/martin/project/datawhalechina/new_app/model'...Cloning into '/Users/martin/project/datawhalechina/new_app/model'... 834 | Submodule path './': checked out 'a8328fd6ee683ef8f6a2d7c4edfefed2923b0795' 835 | ``` 836 | 837 | 不过还有更简单一点的方式。 如果给 git clone 命令传递 --recurse-submodules 选项,它就会自动初始化并更新仓库中的每一个子模块, 包括可能存在的嵌套子模块。 838 | 839 | ```bash 840 | $ git clone --recurse-submodules https://github.com/datawhalechina-git-samples/app.git new_app2 841 | 842 | Cloning into 'new_app2'... 843 | remote: Enumerating objects: 8, done. 844 | remote: Counting objects: 100% (8/8), done. 845 | remote: Compressing objects: 100% (7/7), done. 846 | remote: Total 8 (delta 1), reused 3 (delta 0), pack-reused 0 847 | Receiving objects: 100% (8/8), done. 848 | Resolving deltas: 100% (1/1), done. 849 | Submodule 'model' (https://github.com/datawhalechina-git-samples/model) registered for path 'model' 850 | Cloning into '/Users/martin/project/datawhalechina/new_app/model/new_app2/model'... 851 | ... 852 | 853 | ``` 854 | 855 | 如果你已经克隆了项目但忘记了 `--recurse-submodules`,那么可以运行 `git submodule update --init ` 将 `git submodule init` 和 `git submodule update` 合并成一步。如果还要初始化、抓取并检出任何嵌套的子模块, 请使用简明的 `git submodule update --init --recursive`。 856 | 857 | ### 4.5.2 更新子模块 858 | 859 | 当子模块有更新的时候,执行 ` git submodule update --remote` 860 | 861 | ```bash 862 | $ git submodule update --remote 863 | 864 | ``` 865 | 866 | 该命令默认会更新 main 分支,如果你想设置为其他分支,可以在 `.gitmodules` 文件中设置 (这样其他人也可以跟踪它),也可以只在本地的 `.git/config` 文件中设置,我们在`.gitmodules`中配置它 867 | 868 | ```bash 869 | $ git config -f .gitmodules submodule.model.branch stable 870 | 871 | $ cat .gitmodules 872 | [submodule "model"] 873 | path = model 874 | url = https://github.com/datawhalechina-git-samples/model 875 | branch = stable 876 | ``` 877 | 878 | 很明显很看到 branch 已经变化。当运行 `git submodule update --remote` 时,Git 默认会尝试更新 所有 子模块, 所以如果有很多子模块的话,你可以传递想要更新的子模块的名字。如 `git submodule update --remote model` 879 | 880 | ```bash 881 | $ git submodule update --remote model 882 | 883 | remote: Enumerating objects: 5, done. 884 | remote: Counting objects: 100% (5/5), done. 885 | remote: Compressing objects: 100% (1/1), done. 886 | remote: Total 3 (delta 1), reused 3 (delta 1), pack-reused 0 887 | Unpacking objects: 100% (3/3), 266 bytes | 133.00 KiB/s, done. 888 | From https://github.com/datawhalechina-git-samples/model 889 | a8328fd..ca79fae main -> origin/main 890 | * [new branch] stable -> origin/stable 891 | Submodule path 'model': checked out 'ca79fae869c9b4ddd7999f06ffd48ac25971b9dd' 892 | ``` 893 | 894 | ## 4.6 打包 895 | 896 | Git 提供了多种网络传输的方法,如 SSH、HTTP 等,但是还有种不太常用的功能又什么有效。 897 | 898 | Git 可以就将它的数据"打包"到一个文件中,通过 `git bundle`来实现。`bundle` 命令会将`git push`命令所传输的所有内容打包成一个二进制文件,你可以将这个文件转发给别人,然后解包到仓库中。 899 | 900 | ```bash 901 | $ git bundle create repo.bundle HEAD main 902 | 903 | Enumerating objects: 90, done. 904 | Counting objects: 100% (90/90), done. 905 | Compressing objects: 100% (83/83), done. 906 | Total 90 (delta 12), reused 24 (delta 3), pack-reused 0 907 | 908 | $ ls -alh repo.bundle 909 | 910 | -rw-r--r-- 1 martin staff 6.2M May 4 12:05 repo.bundle 911 | ``` 912 | 913 | 这个 repo.bundle 就是我打包之后的文件,改文件包含了所有重建仓库 main 分支所需要的数据。在使用 bundle 命令时,你需要列出所有你希望打包的引用或者提交的区间。 如果你希望这个仓库可以在别处被克隆,你应该像例子中那样增加一个 HEAD 引用。 914 | 915 | 别人就可以从这个二级制文件 clone 一个目录,就像从`git clone https/ssh` 一样的功能 916 | 917 | ```bash 918 | $ git clone repo.bundle repo 919 | 920 | Cloning into 'repo'... 921 | Receiving objects: 100% (90/90), 6.20 MiB | 88.21 MiB/s, done. 922 | Resolving deltas: 100% (12/12), done. 923 | 924 | $ git log --oneline 925 | ... 926 | ``` 927 | 928 | 如果你在打包时没有包含 HEAD 引用,你还需要在命令后指定一个 `-b main` 或者其他被引入的分支, 否则 Git 不知道应该检出哪一个分支。 929 | 930 | 如果只是要提交最新提交的修改,这需要我们手工计算,可以通过如下的指令计算差别 931 | 932 | ```bash 933 | $ git log --oneline origin/main..main 934 | 935 | ``` 936 | 937 | 或者 938 | 939 | ```bash 940 | $ git log --oneline main ^origin/main 941 | 942 | ``` 943 | 944 | 这里将获得到我们希望被打包的提交列表,将这些提交打包,通过 `git bundle create`操作 945 | 946 | ```bash 947 | $ git bundle create commits.bundle main ^5de18d5 948 | ``` 949 | 950 | 可以将 commits.bundle 文件分享给合作者,他可以将这个文件导入到原始仓库中。在导入前可通过`bundle verify` 命令检查这个文件是否是一个合法的 Git 包,是否拥有共同的祖先。 951 | 952 | ```bash 953 | git bundle verify commits.bundle 954 | 955 | ``` 956 | 957 | 如果打包工具打包的并不是全部的变更,而是最后几个变更,原始仓库则无法导入这个包,因为这个包缺失必要的提交信息。 958 | 959 | ## 4.7 总结 960 | 961 | 这里只是整理一些常用的工具,还有一些高级的功能,如签名、凭证存储、重置、Rerere 等功能,等后续升级版本我们再考虑吧,有缘再见,拜拜~ 962 | -------------------------------------------------------------------------------- /lecture05/README.md: -------------------------------------------------------------------------------- 1 | # 第五章 Git 内部原理 2 | 3 | ## 5.0 引言 4 | 本章相对独立,从底层出发带你了解Git内部是如何运作的。 5 | 6 | 你应该注意到本地仓库下有个名为 `.git` 的隐藏目录,本章将带你了解这个目录下的文件结构和内容。 7 | 8 | > 命令操作说明: 9 | > - 本章演示的命令是使用win10环境下的git bash工具; 10 | > - '\$' 符号所在行是演示命令; 11 | > - 如有内容输出,会在'\$' 符号所在行的下面输出。 12 | 13 | ## 5.1 `.git` 的目录结构 14 | 创建一个名为 `test` 的新仓库 15 | ```shell 16 | $ mkdir test 17 | $ cd test 18 | $ git init 19 | ``` 20 | 新仓库会自动创建一个 `.git` 目录,该目录包含了几乎所有 Git 存储和操作内容。若想备份或复制一个版本库,只需将该目录拷贝至另一处即可。 21 | 22 | 目录结构如下(后续章节会对 `*`开头 的目录详细介绍): 23 | ``` 24 | ├── *config 配置信息(比如本地repo是否大小写敏感, remote端repo的url, 用户名邮箱等) 25 | ├── description 无需关心(仅供GitWeb程序使用) 26 | ├── *HEAD 目前被检出的分支 27 | ├── index 保存暂存区信息 28 | │ 29 | │ 30 | ├── hooks/ 钩子脚本(执行Git命令时自动执行一些特定操作) 31 | ├── info/ 包含一个全局性排除文件 32 | │ └── exclude 放置不希望被记录在 .gitignore 文件中的忽略模式 33 | ├── logs/ 记录所有操作 34 | ├── *objects/ 存储所有数据内容 35 | │ ├── SHA-1/ 保存git对象的目录(三类对象commit, tree和blob) 36 | │ ├── info/ 37 | │ └── pack/ 38 | └── *refs/ 存储指向数据(分支、远程仓库和标签等)的提交对象的指针 39 | ├── heads/ 40 | ├── remotes/ 41 | └── tags/ 42 | ``` 43 | ## 5.2 objects目录 —— 对象存储 44 | 初始化仓库后:objects目录下只有子目录 `pack` 和 `info` ,但均为空。 45 | 46 | 运行以下命令,创建两个文件并提交 47 | ```shell 48 | # 创建了 blob1 49 | $ echo "version1" > test.txt 50 | $ git add . 51 | 52 | # 创建了 blob2 53 | $ mkdir folder1 54 | $ echo "file inside folder1" >folder1/file.txt 55 | $ git add . 56 | 57 | # 创建了 tree1, tree2和commit 58 | $ git commit -m "test" 59 | [master (root-commit) 67f0856] test 60 | 2 files changed, 2 insertions(+) 61 | create mode 100644 folder1/file.txt 62 | create mode 100644 test.txt 63 | ``` 64 | 此时查看objects目录,会发现新增了5个子目录。 65 | ``` 66 | .git/objects 67 | ├── 40 68 | │ └── fa006a9f641b977fc7b3b5accb0171993a3d31 69 | ├── 5b 70 | │ └── dcfc19f119febc749eef9a9551bc335cb965e2 71 | ├── 67 72 | │ └── f0856ccd04627766ca251e5156eb391a4a4ff8 73 | ├── 87 74 | │ └── db2fdb5f60f9a453830eb2ec3cf50fea3782a6 75 | ├── ac 76 | │ └── f63c316ad27e8320a23da194e61f45be040b0b 77 | ├── info 78 | └── pack 79 | ``` 80 | 81 | 让我们来学习一些知识点,来解答以下疑问。 82 | ``` 83 | - 这些长串数字代表什么意思? 84 | - 为什么突然多了5个子目录,分别代表什么呢? 85 | 86 | (info和pack目录将在下一小节介绍) 87 | ``` 88 | 89 | ### 知识点 90 | **1. 什么是对象?** 91 | 92 | objects目录下存储三种对象:数据对象(blob),树对象(tree)和提交对象(commit)。 93 | 94 | 5个子目录的含义如下图所示:2个blob, 2个tree和1个commit 95 |
96 | 97 |
98 | 99 | **2. Git如何存储对象?** 100 | - Git会根据对象内容生成一个 SHA-1 哈希值(称为该文件的校验和) 101 | 102 | 例如:`40fa006a9f641b977fc7b3b5accb0171993a3d31` 103 | - 截取校验和的前两个字符 => 用于命名子目录 104 | 105 | 例如:`40` 106 | - 校验和余下的 38 个字符 => 用于文件名 107 | 108 | 例如:`fa006a9f641b977fc7b3b5accb0171993a3d31` 109 | - 将对象内容存储在 `子目录/文件名` 内 110 | 111 | **3. [小拓展] 如何查看对象的存储内容** 112 | 113 | 可以根据校验和,查看存储的内容及对象类型 114 | ```shell 115 | # 查看文件类型 116 | $ git cat-file -t 40fa006a9f641b977fc7b3b5accb0171993a3d31 117 | blob 118 | 119 | # 查看文件内容 120 | $ git cat-file -p 40fa006a9f641b977fc7b3b5accb0171993a3d31 121 | file inside folder1 122 | ``` 123 | 124 | ## 5.3 objects目录 —— 包文件的存储机制 125 | > Git默认保存文件快照,即保存每个文件每个版本的完整内容。但假设只更改了某大文件中的一个字符,保存两次全部内容是不是有点低效? 126 | 127 | Git最初向磁盘存储对象时采用"松散"对象格式;但为了节省空间和提高效率,Git会时不时将多个对象打包成一个称为"包文件"。 128 | 129 | 当版本库中有太多的"松散"对象,或者手动执行 `git gc` 命令,或者向远程服务器执行推送时,Git 都会进行打包。 130 | 131 | 运行以下命令,手动打包 132 | ```shell 133 | $ git gc 134 | Enumerating objects: 113, done. 135 | Counting objects: 100% (113/113), done. 136 | Delta compression using up to 8 threads 137 | Compressing objects: 100% (92/92), done. 138 | Writing objects: 100% (113/113), done. 139 | Total 113 (delta 15), reused 102 (delta 13), pack-reused 0 140 | ``` 141 | 此时查看objects目录,会发现很多子目录不见了,而 `info` 和 `pack` 目录非空。 142 | ``` 143 | .git/objects 144 | ├── info 145 | │ ├── commit-graph 146 | │ └── packs 147 | └── pack 148 | ├── pack-XXX.idx 149 | └── pack-XXX.pack 150 | ``` 151 | 152 | - 包文件`pack-XXX.pack`:包含了刚才从文件系统中移除的所有对象的内容; 153 | - 索引文件`pack-XXX.idx`:包含了包文件的偏移信息。通过索引文件可以快速定位任意一个指定对象 154 | 155 | ## 5.4 refs目录 —— 引用 156 | Git把一些常用的 `SHA-1` 值存储在文件中,用文件名来替代,这些别名就称为**引用**。有三种引用类型:heads, remotes和tags。 157 | 158 | 运行以下命令,更新refs目录下的内容 159 | ```shell 160 | # 基于当前commit创建新分支test 161 | git branch test 162 | 163 | # 基于commit打tag 164 | git tag -a v1.0 165 | 166 | # 连接远程仓库 167 | git remote add origin https://github.com/datawhalechina/faster-git.git 168 | git fetch 169 | 170 | # 本地修改文件,然后运行git stash 171 | echo "version2" > test.txt 172 | git stash 173 | ``` 174 | 此时查看refs目录,内容如下 175 | ``` 176 | .git/refs 177 | ├── heads 记录本地分支的最后一次提交 178 | │ ├── master 179 | │ └── test 180 | ├── remotes 记录远程仓库各分支的最后一次提交 181 | │ └── origin 182 | │ └── main 183 | ├── tags 184 | │ └── v1.0 185 | └── stash 186 | ``` 187 | 188 | ### 5.4.1 HEAD引用 189 | HEAD引用有两种类型 190 | | | 存储位置 | 指代内容 | 文件内容 | 191 | | ----- | -------------------- | ---------------------------------------- | ---------------------------------- | 192 | | 分支级别 | `.git/refs/heads`目录下 | 本地分支的最后一次提交- **有多少个分支,就有多少个同名的HEAD引用** | commitHash | 193 | | 代码库级别 | `.git/HEAD`文件 | 指代当前代码所处的分支;拓展:也可指代commitHash(称为[分离HEAD](https://git-scm.com/docs/git-checkout#_detached_head)) | 符号引用 - 例如 `ref: refs/heads/master` | 194 | 195 | ### 5.4.2 远程引用 196 | - 存储位置: `.git/refs/remotes` 目录下 197 | - 指代内容:远程仓库各分支的最后一次提交 198 | - 注意点:用于记录远程仓库;文件是只读的,乱改就崩了 199 | 200 | ### 5.4.3 标签引用 201 | > tag主要用于发布版本的管理:一个版本发布之后,我们可以为git打上 v1.0 v2.0 ... 这样的标签 202 | - 存储位置:`.git/refs/heads` 目录下 203 | - 指代内容:tag可以指向任何类型(更多的是指向一个commit,赋予它一个更友好的名字) 204 | - 文件内容:SHA-1值 205 | 206 | ### 5.4.4 stash 207 | - 存储位置:`.git/refs/stash` 文件 208 | - 指代内容:当你想转到其他分支进行其他工作,又不想舍弃当前修改的代码时 - stash可把当前的修改暂存起来 209 | 210 | ## 5.5 config文件 —— 引用规范 211 | 运行以下命令,连接远程仓库 212 | ```shell 213 | git remote add origin https://github.com/datawhalechina/faster-git.git 214 | git fetch 215 | ``` 216 | 此时查看 `.git/config` 文件,会发现新添加了一段小节: 217 | ``` 218 | [remote "origin"] 219 | url = https://github.com/datawhalechina/faster-git.git 220 | fetch = +refs/heads/*:refs/remotes/origin/* 221 | ``` 222 | 223 | **引用规范**由 `git remote add origin` 命令自动生成 224 | - 获取远端 `refs/heads/` 下的所有引用 225 | - 将其写入本地的 `refs/remotes/origin/` 中 226 | - 更新本地的 `.git/config` 文件 227 | 228 | 一些常用命令: 229 | | | 命令 | 230 | | ---------------------------- | ---------------------------------------- | 231 | | 连接远程仓库 | `git remote add <远端名origin> ` | 232 | | 拉取分支 | `git fetch <远端名origin> <远端分支名>:<本地分支名>` | 233 | | 将远程的 main 分支拉到本地的mymaster 分支 | `git fetch origin main:mymaster` | 234 | | 将本地的master分支推送到远端的topic分支 | `git push origin master:topic` | 235 | | 删除远端分支topic | 法1:将\留空
`git push origin :topic`
法2:Git v1.7.0新语法
`git push origin --delete topic` | 236 | 237 | ## 5.6 config文件 —— 环境变量 238 | Git有三种环境变量: 239 | 240 | 1)系统变量 241 | - 适用范围:对所有用户都适用 242 | - 命令选项:`git config --system` 243 | 244 | 2)用户变量 245 | - 适用范围:只适用于该用户 246 | - 命令选项:`git config --global` 247 | 248 | 3)本地项目变量 249 | - 适用范围:只对当前项目有效 250 | - 命令选项:`git config --local` 251 | - 存储位置:`.git/config` 252 | 253 | 一些常用命令: 254 | | | 命令 | 255 | | ------ | --------------------------------------- | 256 | | 查看所有配置 | `git config --list` | 257 | | 配置用户名 | `git config --global user.name "你的用户名"` | 258 | | 配置邮箱 | `git config --global user.email "你的邮箱"` | 259 | 260 | ## 5.7 小练习 261 | ### 5.7.1 远端分支推送 262 | Tom 想把自己的本地分支 `feature1`(当前也为 `HEAD` ),推送到远端分支的 `feature`,应当执行什么命令? 263 | 264 | ``` 265 | A. git push origin/feature1:feature 266 | B. git push origin feature1:feature 267 | C. git push origin HEAD:feature 268 | D. git push origin :feature 269 | ``` 270 | 271 | ### 5.7.2 邮箱配置 272 | Tom工作在多个Git项目上,大部分属于公司的项目,都是使用他的工作邮箱提交。 273 | 274 | 今天他新建了一个私人项目,想使用私人邮箱进行提交。他运行什么命令更合适呢? 275 | ``` 276 | A. git config --system user.email "tom@私人邮箱" 277 | B. git config --global user.email "tom@私人邮箱" 278 | C. git config --local user.email "tom@私人邮箱" 279 | D. 以上选项都可以 280 | ``` 281 | 282 | . 283 | 284 | . 285 | 286 | . 287 | 288 | . 289 | 290 | . 291 | 292 | . 293 | 294 | 8.1 答案:B C 295 | 296 | 8.2 答案:C 只对当前项目有效 -------------------------------------------------------------------------------- /lecture05/imgs/objects_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/faster-git/08277470cee6e0955f255452a9fe4a0fa7842c43/lecture05/imgs/objects_1.jpg -------------------------------------------------------------------------------- /lecture06/README.md: -------------------------------------------------------------------------------- 1 | # 第六章 GitFlow工作流实战 2 | 3 | ## 6.0 引言 4 | 5 | 在实际项目开发工作中,常常会有自测、联调、提测、线上紧急修复等多工作环节,对应可能需要本地、内测、开发、测试、生产等多环境部署代码的需求,对应每个环节会产生不同的分支;本⽂将从Git-Flow模型原理出发,通过命令行演示实际可操作⼿段并进⾏总结,最终希望Git-Flow在实际项⽬中应⽤起来,从⽽⾼效完成代码开发、版本管理等实际⼯作。 6 | 7 | (注:不同的公司或者不同的项目的GitFlow工作流模型标准也不同,具体以实际应用为准;本文提供的为常用模板,较为全面和通用,建议多加练习,达到熟练掌握的程度) 8 | 9 | 10 | 11 | ## 6.1 深⼊理解Git-Flow⼯作流模型原理 12 | 13 | - Git-Flow模型解决什么问题? 14 | 15 | 为了解决实际项⽬中代码开发、代码测试、bug修复、版本发布等⼀系过程列严重耦合从⽽产⽣各种问题,如冲突过度、版本混乱。 16 | 17 | - Git-Flow模型⼜是如何解决上述问题的呢? 18 | 19 | 基于Git定义5种类型的分⽀,各分⽀严格定义其指责、起⽌点等,从⽽使开发、测试、发版等过程有条不紊进⾏。 20 | 21 | 22 | ### 6.1.1 Git-Flow流程图 23 | 24 | 该流程图完整描述Git-Flow模型处理过程,当我们深⼊理解各分⽀,然后结合项⽬阶段与⾃身的⻆⾊(开发/测试/项⽬经理),就会发现每个角色在某个阶段需要关注的可能也就⼀两个分⽀,⽐如在开发阶段,开发⼈员只需关注⾃⼰的新功能分⽀(Feature分支);release阶段,测试⼈员和开发⼈员都只需关注Release分⽀,各⾃的职责有所差异⽽已;具体如下图(建议读者动手手绘一遍该流程图以便于加深理解): 25 | 26 | 27 | 28 | ### 6.1.2 Git-Flow各分⽀的说明 29 | 30 | | 分⽀名称 | 作⽤ | ⽣命周期 | 提交or合并 | 起⽌点 | 31 | | --------------------- | ------------------------- | ------------- | ---------------------------------------- | -------------------------------------- | 32 | | Feature分⽀ | ⽤于某个功能的 | 临时分 ⽀、开发 阶段 | 可提交代码 | 由Develop分⽀产⽣, 最终合并到Develop 分⽀ | 33 | | Develop分⽀ | 记录历史开发功 能 | 贯穿整个 项⽬ | 不能提交,由Feature分 ⽀、Bugfix分⽀、Release 分⽀、Hotfix分⽀合并代码 | 整个项⽬ | 34 | | Release分⽀ | ⽤于本次Release 如⽂档、测试、 bug修复 | 临时分 ⽀、发版 阶段 | 可提交代码 | 由Develop分⽀产⽣, 最终合并到Develop 分⽀和Master分支 | 35 | | Hotfix分⽀ | ⽤于解决线上bug | 临时分 ⽀、紧急 修复阶段 | 可提交代码 | 由Master分⽀产⽣, 最终合并到Develop 分⽀和Master分支 | 36 | | Master(Production) 分⽀ | 记录历史发布版 本 | 贯穿整个 项⽬ | 不能提交,由Release、Hotfix分⽀合并代码 | 整个项⽬ | 37 | 38 | ### 6.1.3 不同⻆度理解各分⽀ 39 | 40 | - ⽣命周期 41 | 42 | Master分⽀和Develop分⽀贯穿项⽬;其他分⽀均为承担特定指责的临时分⽀。 43 | 44 | - 项⽬阶段 45 | 46 | 开发阶段主要涉及Feature分⽀、Develop分⽀; 发布阶段 主要涉及Release分⽀、Production分⽀、Develop分⽀; 紧急修复阶段 主要涉及Hotfix分⽀、Production分⽀、Develop分⽀。 47 | 48 | - 成员关注点 49 | 50 | 开发⼈员 关注Develop分⽀、Feature分⽀以及特殊阶段关注Hotfix、Release分⽀的bug修复; 测试⼈员 关注 Release分⽀、Hotfix分⽀的功能测试;项⽬经理 关注Production分⽀、Release分⽀。 51 | 52 | 另外要说明,项⽬阶段在时间纬度有可能重叠.⽐如:release阶段(当前版本)与下各版本的开发阶段可同时存在,因为当前release阶段的发起同时也就意味着下⼀个release的开发阶段的开始;⼀旦线上出现bug(任何时候都可能出现),紧急修复阶段就可能与开发阶段、发版阶段重叠...因此,要求团队成员都要理解Git-Flow⼯作流,以及⾃身所处的项⽬阶段. 53 | 54 | ## 6.2 命令行演示⼀个完整的Git-Flow流程 55 | 56 | 原理总是枯燥的,接下来实践⼀个从功能开发到版本发布的完整的流程,感受⼀下Git-Flow的具体操作. 57 | 58 | > 特此说明,以下shell命令是在win10环境下,‘/e/PycharmProjects/DatawhaleChina’目录,使用git bash工具进行演示;‘\$’ 符号所在行为演示命令,如有内容输出,会在‘\$’ 符号所在行的下面输出。 59 | 60 | ### 6.2.1 初始化项⽬,创建Develop分⽀ 61 | 62 | ```shell 63 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina 64 | $ pwd 65 | /e/PycharmProjects/DatawhaleChina 66 | 67 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina 68 | $ mkdir git-demo-workflow-project 69 | 70 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina 71 | $ cd git-demo-workflow-project/ 72 | 73 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project 74 | $ touch readme.md 75 | 76 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project 77 | $ git init 78 | Initialized empty Git repository in E:/PycharmProjects/DatawhaleChina/git-demo-workflow-project/.git/ 79 | 80 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (master) 81 | $ git add . 82 | 83 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (master) 84 | $ git commit -m "init" 85 | [master (root-commit) 1ae2455] init 86 | 1 file changed, 0 insertions(+), 0 deletions(-) 87 | create mode 100644 readme.md 88 | 89 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (master) 90 | $ git checkout -b develop master 91 | Switched to a new branch 'develop' 92 | 93 | 94 | ``` 95 | 96 | 97 | 98 | ### 6.2.2 模拟开发阶段过程 99 | 100 | (创建新功能Feature分⽀、实现⼀个⽤户登录模块、然后合并到Develop分⽀、删除功能分⽀) 101 | 102 | ```shell 103 | 104 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (develop) 105 | $ git checkout -b feature-login develop 106 | Switched to a new branch 'feature-login' 107 | 108 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 109 | $ touch LoginUser.html 110 | 111 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 112 | $echo "hi, this is user html" > LoginUser.html 113 | 114 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 115 | $ cat LoginUser.html 116 | hi, this is user html 117 | 118 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 119 | $ ls 120 | LoginUser.html readme.md 121 | 122 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 123 | $ git add . 124 | warning: LF will be replaced by CRLF in LoginUser.html. 125 | The file will have its original line endings in your working directory 126 | 127 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 128 | $ git commit -m "feat: add LoginUser.html" 129 | [feature-login 182444e] feat: add LoginUser.html 130 | 1 file changed, 1 insertion(+) 131 | create mode 100644 LoginUser.html 132 | 133 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 134 | $ touch LoginUser.js 135 | 136 | 137 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 138 | $ echo "hi, this is user js" > LoginUser.js 139 | 140 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 141 | $ git add . 142 | warning: LF will be replaced by CRLF in LoginUser.js. 143 | The file will have its original line endings in your working directory 144 | 145 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 146 | $ git commit -m "feat: add LoginUser.js" 147 | [feature-login b0d494c] feat: add LoginUser.js 148 | 1 file changed, 1 insertion(+) 149 | create mode 100644 LoginUser.js 150 | 151 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 152 | $ git status 153 | On branch feature-login 154 | nothing to commit, working tree clean 155 | 156 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (feature-login) 157 | $ git checkout develop 158 | Switched to branch 'develop' 159 | 160 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (develop) 161 | $ git merge --no-ff feature-login 162 | Merge made by the 'recursive' strategy. 163 | LoginUser.html | 1 + 164 | LoginUser.js | 1 + 165 | 2 files changed, 2 insertions(+) 166 | create mode 100644 LoginUser.html 167 | create mode 100644 LoginUser.js 168 | 169 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (develop) 170 | $ git branch -d feature-login 171 | Deleted branch feature-login (was b0d494c). 172 | 173 | 174 | ``` 175 | 176 | 177 | 178 | ### 6.2.3 模拟Release阶段过程 179 | 180 | (创建Release分⽀、进⾏bug修复、合并到Production分⽀与Develop分⽀) 181 | 182 | ```shell 183 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (develop) 184 | $ git checkout -b release-v0.1 develop 185 | Switched to a new branch 'release-v0.1' 186 | 187 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (release-v0.1) 188 | $ echo "bugifx LoginUser.html" >> LoginUser.html 189 | 190 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (release-v0.1) 191 | $ git add . 192 | warning: LF will be replaced by CRLF in LoginUser.html. 193 | The file will have its original line endings in your working directory 194 | 195 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (release-v0.1) 196 | $ git commit -m "fix: bugfix for LoginUser.html" 197 | [release-v0.1 a37a88c] fix: bugfix for LoginUser.html 198 | 1 file changed, 1 insertion(+) 199 | 200 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (release-v0.1) 201 | $ git checkout master 202 | Switched to branch 'master' 203 | 204 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (master) 205 | $ git merge --no-ff release-v0.1 206 | Merge made by the 'recursive' strategy. 207 | LoginUser.html | 2 ++ 208 | LoginUser.js | 1 + 209 | 2 files changed, 3 insertions(+) 210 | create mode 100644 LoginUser.html 211 | create mode 100644 LoginUser.js 212 | 213 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (master) 214 | $ git tag v0.1 215 | 216 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (master) 217 | $ git checkout develop 218 | Switched to branch 'develop' 219 | 220 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (develop) 221 | $ git merge --no-ff release-v0.1 222 | Merge made by the 'recursive' strategy. 223 | LoginUser.html | 1 + 224 | 1 file changed, 1 insertion(+) 225 | 226 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (develop) 227 | $ git branch -d release-v0.1 228 | Deleted branch release-v0.1 (was a37a88c). 229 | 230 | ``` 231 | 232 | 233 | 234 | ### 6.2.4 模拟线上故障,创建Hotfix分⽀ 235 | 236 | (创建Hotfix分⽀、进⾏bug修复、合并到Production分⽀与Develop分⽀) 237 | 238 | ```shell 239 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (master) 240 | $ git checkout -b hotfix-v0.1.1 master 241 | Switched to a new branch 'hotfix-v0.1.1' 242 | 243 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (hotfix-v0.1.1) 244 | $ git status 245 | On branch hotfix-v0.1.1 246 | nothing to commit, working tree clean 247 | 248 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (hotfix-v0.1.1) 249 | $ echo "hotfix for LoginUser.html" >> LoginUser.html 250 | 251 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (hotfix-v0.1.1) 252 | $ cat LoginUser.html 253 | hi, this is user html 254 | bugifx LoginUser.html 255 | hotfix for LoginUser.html 256 | 257 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (hotfix-v0.1.1) 258 | $ git add . 259 | warning: LF will be replaced by CRLF in LoginUser.html. 260 | The file will have its original line endings in your working directory 261 | 262 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (hotfix-v0.1.1) 263 | $ git commit -m "hotfix: do something for LoginUser.html" 264 | [hotfix-v0.1.1 bcb680e] hotfix: do something for LoginUser.html 265 | 1 file changed, 1 insertion(+) 266 | 267 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (hotfix-v0.1.1) 268 | $ git checkout master 269 | Switched to branch 'master' 270 | 271 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (master) 272 | $ git merge --no-ff hotfix-v0.1.1 273 | Merge made by the 'recursive' strategy. 274 | LoginUser.html | 1 + 275 | 1 file changed, 1 insertion(+) 276 | 277 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (master) 278 | $ git tag v0.1.1 279 | 280 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (master) 281 | $ git checkout develop 282 | Switched to branch 'develop' 283 | 284 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (develop) 285 | $ git merge --no-ff hotfix-v0.1.1 286 | Merge made by the 'recursive' strategy. 287 | LoginUser.html | 1 + 288 | 1 file changed, 1 insertion(+) 289 | 290 | Administrator@WIN MINGW64 /e/PycharmProjects/DatawhaleChina/git-demo-workflow-project (develop) 291 | $ git branch -d hotfix-v0.1.1 292 | Deleted branch hotfix-v0.1.1 (was bcb680e). 293 | 294 | ``` 295 | 296 | 297 | 298 | -------------------------------------------------------------------------------- /lecture06/imgs/gitflow示意图.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datawhalechina/faster-git/08277470cee6e0955f255452a9fe4a0fa7842c43/lecture06/imgs/gitflow示意图.png -------------------------------------------------------------------------------- /lecture07/README.md: -------------------------------------------------------------------------------- 1 | # 第七章 Git提交规范 2 | ## 7.0 前言 3 | 4 | Git是目前程序员必备基础技能,可以用来管理代码、文档、博客,甚至菜谱。个人的私有仓库的提交相对而言可以 5 | 较为随意,但是在团队开发中,还是要遵循相应的规范。本文对Git使用中涉及到提交相关的实践做了些整理, 6 | 供大家参考。 7 | 8 | ![git commit](git-commit.png) 9 | 10 | 如上图所示(截取自Angular commit [970a3b5](https://github.com/angular/angular/commit/970a3b5c70fee29aa40945836ebeb464d75438e4)), 11 | 一个commit包含如下几个信息: 12 | 13 | * commit message - 提交的内容相关描述 14 | * author & committer - 作者及提交者 15 | * changed files - 修改的文件 16 | * hash & parent - 提交内容的hash及在提交树上的位置 17 | 18 | ## 7.1 Commit Message 19 | 20 | 提交消息描述的是当前提交的功能相关信息,一般可以包括`header`,`body`,`footer`, 21 | 22 | ``` 23 |
24 | 25 | 26 | 27 |