Git学习笔记

zxl19 2021-08-14

我的Git学习笔记。

基本概念

  1. 工作目录/工作区:持有实际文件;
  2. 暂存区(Index):缓存区域,临时保存改动;
  3. HEAD:指向最后一次提交的结果;

常用命令

  1. 创建新仓库:

     # 在仓库文件夹中
     git init
    
  2. 检出仓库:

     # 创建一个本地仓库的克隆版本
     git clone /path/to/repository
     # 创建远程服务器上仓库的克隆版本
     git clone username@host:/path/to/repository
    
  3. 添加和提交:

     # 添加单个文件到暂存区
     git add <filename>
     # 添加所有文件到暂存区
     git add *
     # 提交改动到HEAD
     git commit -m "代码提交信息"
    
     # 修改上次的提交内容和提交信息
     git commit --amend
    
  4. 推送改动:

     # 提交改动到远程服务器上仓库的master分支
     # 远程服务器的默认名为origin
     git push origin master
    
     # 强制推送,会覆盖远程分支,需要谨慎使用!
     git push -f
     # 防止覆盖远程分支中的新增提交,建议使用
     git push --force-with-lease
    
     # 显示远程服务器的名称和URL地址
     git remote -v
     # 添加远程服务器
     git remote add <name> <url>
     # 删除远程服务器
     git remote remove <name>
     # 修改远程服务器的名称
     git remote rename <old> <new>
     # 修改远程服务器的URL地址
     git remote set-url <name> <new url>
     # 显示远程服务器的详细信息
     git remote show <name>
    
  5. 分支:将特性开发绝缘,默认主分支为master自2020年10月1日起,GitHub将新仓库的默认主分支改为main

     # 新建分支并切换
     # 相当于git branch + git checkout
     git checkout -b <branch>
     # 切换回主分支
     git checkout master
     # 删除本地分支
     git branch -d <branch>
     # 删除远程分支
     git push origin -d <branch>
     # 推送分支到远程仓库,使其对他人可见
     git push origin <branch>
    
     # 在本地暂存当前分支工作目录和暂存区中所有未提交的修改
     # 默认不包括未跟踪的文件和被忽略的文件
     git stash [-u] [-a]
     # 暂存并添加信息
     git stash save "代码暂存信息"
     # 查看暂存的修改
     # stash@{0}为最新暂存的内容
     git stash list
     # 下面的命令如果不使用stash@{i}指定,默认对于stash@{0}操作,缓存栈先进后出
     # 应用暂存的修改,但是不删除缓存栈中的对应内容
     git stash apply [stash@{i}]
     # 删除暂存的修改
     git stash drop [stash@{i}]
     # 恢复暂存的修改,并删除缓存栈中的对应内容
     # 相当于git stash apply + git stash drop
     # 注意当前分支是否与暂存时的分支一致,通过git reset --hard撤回
     git stash pop [stash@{i}]
     # 删除所有暂存的修改
     git stash clear
    
  6. 更新与合并:

     # 更新本地仓库至最新改动
     # 相当于git fetch + git merge
     git pull
     # 合并其他分支到当前分支
     git merge <branch>
     # 终止当前合并过程并恢复合并前的状态
     git merge --abort
     # 合并冲突后手动添加文件到暂存区
     git add <filename>
     # 预览差异
     git diff <source_branch> <target_branch>
    
     # 挑选若干个提交进行合并
     # 单个提交
     git cherry-pick <id>
     # 多个提交
     git cherry-pick <id1> <id2>
     # 提交区间
     git cherry-pick <id1>..<id2>
     # 合并冲突的处理方式
     # --continue:手动解决冲突后继续合并
     # --abort:放弃合并,恢复原始状态
     # --quit:放弃合并,保持现有状态
    
     # 以指定分支为基础,将当前分支的提交合并,并将提交记录变成线性的
     # 难以追踪修改历史,需要谨慎使用!
     # 建议在master分支合并feature分支时使用git merge,在feature分支合并master分支时使用git rebase
     git rebase <branch>
     # 合并冲突的处理方式
     # --continue:手动解决冲突后继续合并
     # --abort:放弃合并,恢复原始状态
     # --quit:放弃合并,保持现有状态
     # 以指定提交为基础,交互式合并之后的提交,支持选择合并方式
     git rebase -i <id>
     # 选择合并方式
     # p, pick = use commit
     # r, reword = use commit, but edit the commit message
     # e, edit = use commit, but stop for amending
     # s, squash = use commit, but meld into previous commit
     # f, fixup = like "squash", but discard this commit's log message
     # x, exec = run command (the rest of the line) using shell
     # d, drop = remove commit
    
  7. 标签:

     # 创建标签
     git tag 1.0.0 [ID前十位]
     # 获取提交ID
     git log
    
  8. 替换本地改动:

     # 使用HEAD中的最新内容替换掉工作目录中的文件
     # 已添加到暂存区的改动以及新文件都不会受到影响
     git checkout -- <filename>
     # 丢弃本地的所有改动与提交
     # 到服务器上获取最新的版本历史并将本地主分支指向它
     git fetch origin
     git reset --hard origin/master
    
     # 回退到某次提交,删除这次提交后的全部提交记录
     git reset <id>
     # --soft:回退修改的内容在暂存区
     # --mixed:回退修改的内容在工作区(默认)
     # --hard:回退修改的内容被删除
     # 撤回某次提交的修改,增加新的提交记录
     git revert <id>
    
  9. 实用小贴士:

    • 内建的图形化git:

        gitk
      
    • 彩色的git输出:

        git config color.ui true
      
    • 显示历史记录时,每个提交的信息只显示一行:

        git config format.pretty oneline
      
    • 交互式添加文件到暂存区:

        git add -i
      

工作流程

  1. 克隆远程仓库到本地:

     git clone username@host:/path/to/repository
    
  2. 如果没有远程仓库主分支的修改权限,则需要在个人分支中进行修改;

    • 如果远程仓库中不存在个人分支,则需要在本地仓库中新建个人分支:

        # 基于远程仓库的主分支在本地仓库中新建个人分支,并自动关联远程仓库的主分支
        git checkout -b <branch> origin/master
        # 基于本地仓库的当前分支新建个人分支,不会关联远程仓库的分支
        git checkout -b <branch>
      
    • 如果远程仓库中存在个人分支,则需要在本地仓库中切换到个人分支:

        # 查看本地仓库和远程仓库的全部分支
        git branch -a
        # 查看远程仓库的全部分支
        git branch -r
        # 切换到个人分支,自动关联远程仓库的分支
        git checkout <branch>
      
  3. 本地修改,提交:

     git add *
     git commit -m "代码提交信息"
    
     # 查看工作区状态
     git status
     # 查看完整修改信息
     git show
    
  4. 拉取远程仓库更新到本地:

    • 指定远程仓库的分支:

        git pull origin <branch>
      
    • 使用与本地仓库的当前分支关联的远程仓库的分支:

        git pull
      
    • 设置与本地仓库的当前分支关联的远程仓库的分支:

        git branch --set-upstream-to=origin/<branch>
      
  5. 在本地仓库合并远程仓库更新并测试;
  6. 推送本地仓库修改到远程仓库:

    • 指定远程仓库的分支,如果远程仓库中不存在指定的分支会自动创建:

        # 远程仓库的分支名与本地仓库的分支名不同
        git push origin <local_branch>:<remote_branch>
        # 远程仓库的分支名与本地仓库的分支名相同
        git push origin <branch>
      
    • 使用与本地仓库的当前分支关联的远程仓库的分支:

        git push
      
    • 设置与本地仓库的当前分支关联的远程仓库的分支并推送:

        git push --set-upstream origin <branch>
        git push -u origin <branch>
      

使用技巧

.gitignore文件

用于说明哪些文件或文件夹不需要被添加到版本管理中,在工程根目录下创建。

  1. GitHub官方提供了模板:github/gitignore,可以根据实际情况选择使用;
  2. 如果相关文件或文件夹已被添加到版本管理中,则.gitignore文件无效,需要先从暂存区中删除:

     # 删除单个文件
     git rm --cached <filename>
     # 删除所有文件
     git rm -r --cached .
    
  3. 如果相关文件或文件夹被.gitignore文件忽略:

    • 可以强制添加:

        git add -f <filename>
      
    • 可以查看被忽略的原因:

        git check-ignore -v <filename>
      

.gitkeep文件

用于添加空文件夹到版本管理中,在需要添加的空文件夹中创建。

如果需要添加的空文件夹已经被添加到.gitignore文件中,则需要强制添加.gitkeep文件到暂存区:

git add -f ./log/.gitkeep

.gitmodules文件

用于记录仓库子模块的信息。

  1. 添加子模块,注意使用相对路径,可以指定子模块的分支,会自动生成.gitmodules文件:

     git submodule add -b <submodule branch> <submodule url> <relative path to submodule>
    

    .gitmodules文件示例:

     [submodule "<relative path to submodule>"]
         path = <relative path to submodule>
         url = <submodule url>
         branch = <submodule branch>
    
  2. 在克隆远程仓库时添加--recursive循环克隆子模块:

     git clone username@host:/path/to/repository --recursive
    
  3. 如果远程仓库已克隆完成,则需要单独克隆子模块:

    • 方法一:

        # 初始化本地配置文件,向.git/config文件中写入子模块信息
        # 可以修改.git/config文件中的子模块URL地址
        git submodule init
        # 按照.git/config文件中的子模块信息检出子模块
        git submodule update
      
    • 方法二:

        # 初始化本地配置文件并检出子模块
        git submodule update --init
      
  4. 如果远程仓库添加了多个子模块,可以使用git submodule foreach命令对于每个子模块进行相同操作:

    • 循环克隆每个子模块内部嵌套的子模块:

        git submodule update --init
        git submodule foreach git submodule update --init
      
    • 循环拉取每个子模块远程仓库的更新(子模块的HEAD指向的是添加时的版本):

        git submodule foreach git pull origin master
      
  5. 在提交修改时,先提交子模块的修改,再提交当前仓库的修改;
  6. 如果子模块存在合并冲突,则需要手动添加子模块:

     git add <relative path to submodule>
    
  7. 删除子模块:

     git submodule deinit <relative path to submodule>
     git rm <relative path to submodule>
    

.gitattributes文件

用于定义文件属性,在工程根目录下创建。

  1. GitHub社区提供了模板:gitattributes/gitattributes,可以根据实际情况选择使用;
  2. 主要用于处理不同操作系统中行尾(End Of Line,EOL)控制字符定义不一致的问题:

    • 回车(Carriage Return,CR)表示将光标移动到当前行的开头,转义序列为\r
    • 换行(Line Feed,LF)表示将光标垂直移动到下一行,转义序列为\n
    • Windows系统使用CRLF;
    • Linux和MacOS系统使用LF;
    • 示例:

        # 所有文件自动检测是否为文本文件,如果是文本文件且未在版本管理中行尾使用CRLF,行尾自动转换为LF
        *           text=auto
        # 所有.txt文件作为文本文件处理
        *.txt       text
        # 所有.vcproj文件作为文本文件处理,行尾自动转换为CRLF
        *.vcproj    text eol=crlf
        # 所有.sh文件作为文本文件处理,行尾自动转换为LF
        *.sh        text eol=lf
        # 所有.jpg文件不作为文本文件处理
        *.jpg       -text
      

教程(包括Git和GitHub)

网站

  1. Git-Documentation
  2. Git教程-菜鸟教程
  3. git-简明指南
  4. git-the simple guide
  5. Git五分钟教程
  6. A Visual Git Reference

GitHub

  1. tiimgreen/github-cheat-sheet
  2. git-tips/tips
  3. geeeeeeeeek/git-recipes
  4. arslanbilal/git-cheat-sheet
  5. agis/git-style-guide
  6. rogerdudler/git-guide
  7. dictcp/awesome-git
  8. AntBranch/awesome-github
  9. MarkLodato/visual-git-guide

客户端

终端客户端

  1. jesseduffield/lazygit
  2. Extrawurst/gitui
  3. jonas/tig

图形化客户端

  1. gitk
  2. GitHub Desktop
  3. GitKraken
  4. gitextensions/gitextensions
  5. git-cola/git-cola
  6. soramimi/Guitar

大文件支持

  1. iterative/dvc
  2. git-lfs/git-lfs

参考

  1. git commit –amend修改git提交记录用法详解-玉藻前的文章-知乎
  2. Git更安全的强制推送,–force-with-lease
  3. 10月1日之后,你新建的GitHub库默认分支不叫「master」了-机器之心的文章-知乎
  4. 熟练掌握git-stash用法-linux技术栈的文章-知乎
  5. Git(六):git stash命令-Aaron Zhu的文章-知乎
  6. GIT丨git stash pop后有冲突时,如何撤销-CSDN博客
  7. git教程–git cherry-pick命令-赵andrew的文章-知乎
  8. git rebase,看这一篇就够了-掘金
  9. 在开发过程中使用git rebase还是git merge,优缺点分别是什么?-一个小号的回答-知乎
  10. 为什么你应该停止使用Git rebase命令-KenChoi的文章-知乎
  11. Git删除中间提交-极客教程
  12. Git命令reset和revert的区别-Meng小羽的文章-知乎
  13. git reset和revert的区别-CSDN博客
  14. Git恢复之前版本的两种方法reset、revert(图文详解)-CSDN博客
  15. git merge –abort的一种使用情况-CSDN博客
  16. git创建本地与远程分支的同步与合并-掘金
  17. git本地新建分支和远程同步-CSDN博客
  18. git删除远程分支-CSDN博客
  19. git查看与对比历史提交记录-CSDN博客
  20. Git忽略文件.gitignore详解-CSDN博客
  21. .gitignore-简书
  22. git的ignore文件在c++下的编写-CSDN博客
  23. 什么是.gitkeep?-CSDN博客
  24. Git中submodule的使用-孤单彼岸的文章-知乎
  25. Git子仓库深入浅出-那我懂你意思了的文章-知乎
  26. How to Use git submodule init-PhoneixNAP
  27. git子仓库(submodule)操作-CSDN博客
  28. 克隆子模块-Stack Overflow
  29. submodule指定对应分支-CSDN博客
  30. Git clone –recursive-博客园
  31. 解决子模块的合并冲突-博客园
  32. 删除子模块-Stack Overflow
  33. .gitattributes作用详细讲解(git大佬必会技能)-CSDN博客
  34. 什么是.gitattributes文件中的text=auto的目的-极客教程
  35. .gitattributes正确使用姿势-掘金
  36. 什么是.gitattributes?-LinuxSuRen的文章-知乎
  37. Newline-Wikipedia
  38. What is the difference between a “line feed” and a “carriage return”?-Stack Overflow
  39. CRLF和LF的差异-不知味之味的文章-知乎
  40. 转义字符和控制字符有什么区别?-邱昊宇的回答-知乎
  41. Git-GUI Clients
  42. 12个优秀GUI Git客户端,程序员必备!-民工哥的文章-知乎
  43. 推荐几款好用的Git图形化客户端-掘金
  44. 详解Git大文件存储(Git LFS)-腾讯技术工程的文章-知乎