我的Git学习笔记。
基本概念
- 工作目录/工作区:持有实际文件;
- 暂存区(Index):缓存区域,临时保存改动;
- HEAD:指向最后一次提交的结果;
常用命令
-
创建新仓库:
# 在仓库文件夹中 git init
-
检出仓库:
# 创建一个本地仓库的克隆版本 git clone /path/to/repository # 创建远程服务器上仓库的克隆版本 git clone username@host:/path/to/repository
-
添加和提交:
# 添加单个文件到暂存区 git add <filename> # 添加所有文件到暂存区 git add * # 提交改动到HEAD git commit -m "代码提交信息"
# 修改上次的提交内容和提交信息 git commit --amend
-
推送改动:
# 提交改动到远程服务器上仓库的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>
-
分支:将特性开发绝缘,默认主分支为
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
-
更新与合并:
# 更新本地仓库至最新改动 # 相当于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
-
标签:
# 创建标签 git tag 1.0.0 [ID前十位] # 获取提交ID git log
-
替换本地改动:
# 使用HEAD中的最新内容替换掉工作目录中的文件 # 已添加到暂存区的改动以及新文件都不会受到影响 git checkout -- <filename> # 丢弃本地的所有改动与提交 # 到服务器上获取最新的版本历史并将本地主分支指向它 git fetch origin git reset --hard origin/master
# 回退到某次提交,删除这次提交后的全部提交记录 git reset <id> # --soft:回退修改的内容在暂存区 # --mixed:回退修改的内容在工作区(默认) # --hard:回退修改的内容被删除 # 撤回某次提交的修改,增加新的提交记录 git revert <id>
-
实用小贴士:
-
内建的图形化git:
gitk
-
彩色的git输出:
git config color.ui true
-
显示历史记录时,每个提交的信息只显示一行:
git config format.pretty oneline
-
交互式添加文件到暂存区:
git add -i
-
工作流程
-
克隆远程仓库到本地:
git clone username@host:/path/to/repository
-
如果没有远程仓库主分支的修改权限,则需要在个人分支中进行修改;
-
如果远程仓库中不存在个人分支,则需要在本地仓库中新建个人分支:
# 基于远程仓库的主分支在本地仓库中新建个人分支,并自动关联远程仓库的主分支 git checkout -b <branch> origin/master # 基于本地仓库的当前分支新建个人分支,不会关联远程仓库的分支 git checkout -b <branch>
-
如果远程仓库中存在个人分支,则需要在本地仓库中切换到个人分支:
# 查看本地仓库和远程仓库的全部分支 git branch -a # 查看远程仓库的全部分支 git branch -r # 切换到个人分支,自动关联远程仓库的分支 git checkout <branch>
-
-
本地修改,提交:
git add * git commit -m "代码提交信息"
# 查看工作区状态 git status # 查看完整修改信息 git show
-
拉取远程仓库更新到本地:
-
指定远程仓库的分支:
git pull origin <branch>
-
使用与本地仓库的当前分支关联的远程仓库的分支:
git pull
-
设置与本地仓库的当前分支关联的远程仓库的分支:
git branch --set-upstream-to=origin/<branch>
-
- 在本地仓库合并远程仓库更新并测试;
-
推送本地仓库修改到远程仓库:
-
指定远程仓库的分支,如果远程仓库中不存在指定的分支会自动创建:
# 远程仓库的分支名与本地仓库的分支名不同 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
文件
用于说明哪些文件或文件夹不需要被添加到版本管理中,在工程根目录下创建。
- GitHub官方提供了模板:github/gitignore,可以根据实际情况选择使用;
-
如果相关文件或文件夹已被添加到版本管理中,则
.gitignore
文件无效,需要先从暂存区中删除:# 删除单个文件 git rm --cached <filename> # 删除所有文件 git rm -r --cached .
-
如果相关文件或文件夹被
.gitignore
文件忽略:-
可以强制添加:
git add -f <filename>
-
可以查看被忽略的原因:
git check-ignore -v <filename>
-
.gitkeep
文件
用于添加空文件夹到版本管理中,在需要添加的空文件夹中创建。
如果需要添加的空文件夹已经被添加到.gitignore
文件中,则需要强制添加.gitkeep
文件到暂存区:
git add -f ./log/.gitkeep
.gitmodules
文件
用于记录仓库子模块的信息。
-
添加子模块,注意使用相对路径,可以指定子模块的分支,会自动生成
.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>
-
在克隆远程仓库时添加
--recursive
循环克隆子模块:git clone username@host:/path/to/repository --recursive
-
如果远程仓库已克隆完成,则需要单独克隆子模块:
-
方法一:
# 初始化本地配置文件,向.git/config文件中写入子模块信息 # 可以修改.git/config文件中的子模块URL地址 git submodule init # 按照.git/config文件中的子模块信息检出子模块 git submodule update
-
方法二:
# 初始化本地配置文件并检出子模块 git submodule update --init
-
-
如果远程仓库添加了多个子模块,可以使用
git submodule foreach
命令对于每个子模块进行相同操作:-
循环克隆每个子模块内部嵌套的子模块:
git submodule update --init git submodule foreach git submodule update --init
-
循环拉取每个子模块远程仓库的更新(子模块的HEAD指向的是添加时的版本):
git submodule foreach git pull origin master
-
- 在提交修改时,先提交子模块的修改,再提交当前仓库的修改;
-
如果子模块存在合并冲突,则需要手动添加子模块:
git add <relative path to submodule>
-
删除子模块:
git submodule deinit <relative path to submodule> git rm <relative path to submodule>
.gitattributes
文件
用于定义文件属性,在工程根目录下创建。
- GitHub社区提供了模板:gitattributes/gitattributes,可以根据实际情况选择使用;
-
主要用于处理不同操作系统中行尾(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
- 回车(Carriage Return,CR)表示将光标移动到当前行的开头,转义序列为
教程(包括Git和GitHub)
网站
GitHub
- tiimgreen/github-cheat-sheet
- git-tips/tips
- geeeeeeeeek/git-recipes
- arslanbilal/git-cheat-sheet
- agis/git-style-guide
- rogerdudler/git-guide
- dictcp/awesome-git
- AntBranch/awesome-github
- MarkLodato/visual-git-guide
客户端
终端客户端
图形化客户端
大文件支持
参考
- git commit –amend修改git提交记录用法详解-玉藻前的文章-知乎
- Git更安全的强制推送,–force-with-lease
- 10月1日之后,你新建的GitHub库默认分支不叫「master」了-机器之心的文章-知乎
- 熟练掌握git-stash用法-linux技术栈的文章-知乎
- Git(六):git stash命令-Aaron Zhu的文章-知乎
- GIT丨git stash pop后有冲突时,如何撤销-CSDN博客
- git教程–git cherry-pick命令-赵andrew的文章-知乎
- git rebase,看这一篇就够了-掘金
- 在开发过程中使用git rebase还是git merge,优缺点分别是什么?-一个小号的回答-知乎
- 为什么你应该停止使用Git rebase命令-KenChoi的文章-知乎
- Git删除中间提交-极客教程
- Git命令reset和revert的区别-Meng小羽的文章-知乎
- git reset和revert的区别-CSDN博客
- Git恢复之前版本的两种方法reset、revert(图文详解)-CSDN博客
- git merge –abort的一种使用情况-CSDN博客
- git创建本地与远程分支的同步与合并-掘金
- git本地新建分支和远程同步-CSDN博客
- git删除远程分支-CSDN博客
- git查看与对比历史提交记录-CSDN博客
- Git忽略文件.gitignore详解-CSDN博客
- .gitignore-简书
- git的ignore文件在c++下的编写-CSDN博客
- 什么是.gitkeep?-CSDN博客
- Git中submodule的使用-孤单彼岸的文章-知乎
- Git子仓库深入浅出-那我懂你意思了的文章-知乎
- How to Use git submodule init-PhoneixNAP
- git子仓库(submodule)操作-CSDN博客
- 克隆子模块-Stack Overflow
- submodule指定对应分支-CSDN博客
- Git clone –recursive-博客园
- 解决子模块的合并冲突-博客园
- 删除子模块-Stack Overflow
- .gitattributes作用详细讲解(git大佬必会技能)-CSDN博客
- 什么是.gitattributes文件中的text=auto的目的-极客教程
- .gitattributes正确使用姿势-掘金
- 什么是.gitattributes?-LinuxSuRen的文章-知乎
- Newline-Wikipedia
- What is the difference between a “line feed” and a “carriage return”?-Stack Overflow
- CRLF和LF的差异-不知味之味的文章-知乎
- 转义字符和控制字符有什么区别?-邱昊宇的回答-知乎
- Git-GUI Clients
- 12个优秀GUI Git客户端,程序员必备!-民工哥的文章-知乎
- 推荐几款好用的Git图形化客户端-掘金
- 详解Git大文件存储(Git LFS)-腾讯技术工程的文章-知乎