文章目录
- 1. 基础概念
- 2. 简单使用
- 2.1 git配置
- 2.1.1 git的配置文件
- 2.1.2 .gitignore文件
- 2.2 创建仓库
- 2.2.1 创建本地仓库
- 2.2.2 github创建远程仓库
- step1:github新建一个代码仓
- step2:创建密钥
- 远程仓库相关指令
- 2.2.3 本地仓库 关联 远程仓库
- 2.3 分支
- 2.3.1 常用指令
- 2.3.2 变基
- 2.4 提交
- 查看本地仓状态
- 添加到暂存区
- 提交到本地仓
- 查看历史记录
- 2.5 差异
- 2.5.1 git diff常用指令
- 2.6 拉取&推送
- 2.7 版本穿梭
- hard模式
- mixed模式
- soft模式
- 操作示例
- 2.8 撤销提交revert
- 2.9 stash
- 2.10 cherry-pick
- 2.11 submodule子模块
- 2.11.1 why need submodule?
- 2.11.2 submodule的使用
- 1. 创建submodule
- 2. 获取submodule
- 3. 子模块内容更新
- 情况1:子模块有未跟踪的内容变动
- 情况2:子模块有版本变化
- 情况3:子模块远程有更新
- 4. 删除子模块
- 2.11.3 summary
- 参考内容
1. 基础概念
【工作区】 -- git add -> 【缓存区】 -- git commit -> 【本地版本库】 -- git push -> 【远程仓库】
- Branch:分支是从主线分离出去的“副本”,可独立操作互不干扰。仓库初始化就有一个默认主干分支master;
- HEAD:HEAD指向当前活动分支的最新版本/最新提交;
- Tag:标签是指某个分支某个特定时间点的状态,可理解为提交记录的别名,常用来标记版本;
- origin/master:表示远程仓库(origin)的master分支
- origin/HEAD:表示远程仓库(origin)的最新提交位置。
P.S.
标签、分支、HEAD都是对提交记录的“指针”引用,即指向这些提交。 - 提交记录之前也存在“指针引用”,每个提交会指向上一个提交;
- Tag标签:对某一提交的固定“指针”引用;
- 分支:指向某一提交记录的“指针”引用,“指针”位置可变,如提交、回滚等;
- HEAD:指向当前活动分支(最新提交)的一个“指针”引用。
每个提交都有一个唯一的标识,主要是提交的hash值,即commitid。标识唯一提交的两种方式:
- commitid:一个40位编码,在指令中使用可只输入前6位;
- HEAD~n
- HEAD表示当前分支的最新版本;
HEAD^
表示上一个版本,HEAD^^
表示上上个版本;HEAD~
或HEAD~1
表示上一个版本,以此类推,HEAD^10
表示最近的第10个版本。(有点儿像数组的下标)HEAD@{1}
在 git reflog 日志中标记的提交记录索引。
2. 简单使用
2.1 git配置
2.1.1 git的配置文件
git的三个主要配置文件:
- 系统全局配置(–system):包含适用于系统所有用户和所有仓库的配置信息。路径:git的安装目录
\Git\etc\gitconfig
; - 用户全局配置(–global):当前系统用户的全局配置。路径:用户目录
C:\UseR\[username]\.gitconfig
; - 仓库配置(–local):仓库的特定配置。路径:仓库目录下
.git/config
这三个配置文件的优先级:3>2>1
git config # 输入该命令回车后,会显示可用的选项
# 查看
git config user.name # 查看用户名
git config user.password # 查看用户密码
git config user.email # 查看用户邮箱
# 设置
# --global use global config file
git config --global user.password "newPassword" # 设置全局新密码
2.1.2 .gitignore文件
在工作区根目录下创建.gitignore
文件,文件中配置无需进行版本管理的文件、文件夹。P.S..gitignore
文件本身是纳入版本管理的。
2.2 创建仓库
2.2.1 创建本地仓库
git init # 在当前目录初始化创建仓库
创建完后会多出一个.git
目录,这就是本地仓git的工作场所。
# 克隆远程仓库
git clone [url]
2.2.2 github创建远程仓库
step1:github新建一个代码仓
step2:创建密钥
在本地创建一个ssh key,然后在github账号中输入后,本地电脑即和github账号关联起来了,这样就可以很方便的通过git bash上传代码等操作。
- 本地创建密钥
ssh-keygen -t rsa -C "这里输入自己的邮箱" # 回车后会打印Create directory的字样,后边儿跟的就是密钥的储存位置
- 进入密钥的存储路径,打开id_rsa.pub或id_rsa文件,复制其中的密钥
- 在github上输入刚刚复制的密钥
远程仓库相关指令
git remote -v # 查看所有远程仓库的详细信息
git remote show [remote] # 显示某个远程仓库的信息
git remote add [name] [url] # 增加一个新的远程仓库,并命名
git remote rename [old] [new] # 修改远程仓库名称
git remote rm [remoteName] # 删除远程仓库
2.2.3 本地仓库 关联 远程仓库
将本地的Git仓库推送到远程仓库的两种方式_git如何把本地仓库的代码推送到新建的远程仓库-CSDN博客
git init
2.3 分支
2.3.1 常用指令
git branch [-v] # 列出所有本地分支,加参数-v显示详细信息
git branch -r # 列出所有远程分支
git branch -a # 列出所有本地分支和远程分支,用不同颜色区分
git branch [branchName] # 新建一个分支,但仍停留在当前分支上
git branch -d [branchName] # 删除指定分支,-D 强制删除
git checkout [branchName] # 切换到指定分支并更新工作区
git checkout . # 撤销工作区的(未暂存)修改,把暂存区恢复到工作区
git checkout HEAD . # 撤销工作区、暂存区的修改,用HEAD指向的当前分支最新版本替换
git checkout -b [branchOld] [branchNew] # 从本地branchOld分支上创建一个branchNew分支,并切换到新分支
git branch [branchName] [commitid] # 新建一个分支,并指定commitid
git branch --track [branchName] [branchRemote] # 新建一个分支,并于指定的远程分支建立关联
git checkout -b [branch1] remote [branch1] # 从远端remote的 branch1 分支创建本地的branch1分支
git branch --set-upstream [branch] [remoteBranch] # 在现有分支branch和指定的远程分支remoteBranch之间建立跟踪关联
git merge [branchName] # 合并指定分支到当前分支
git merge --no-ff [branch] # 合并branch分支到当前分支,--no-ff参数表示禁用快速合并模式,会产生一个新的合并提交记录
git push origin --delete [branchName] # 删除远程分支
git rebase master # 变基,将当前分支变基合并到master分支
2.3.2 变基
git rebase详解(图解+最简单示例,一次就懂)-CSDN博客
整理提交记录:git rebase -i
使用示例:
# 想要合并前2个提交记录为1个
git rebase -i HEAD~2
# 将后边的pick 改为 s
pick db38d7e commit 1
pick 13bbbeb commit 3
改为:
pick db38d7e commit 1
s 13bbbeb commit 3
保存退出后,修改提交记录
2.4 提交
查看本地仓状态
git status
# 输出示例
PS E:\workspace\proj-main> git status
On branch git_test
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: main.c
Untracked files:
(use "git add <file>..." to include in what will be committed)
.vscode/
proj-sub/
no changes added to commit (use "git add" and/or "git commit -a")
添加到暂存区
git add [filename] # 一次性添加所有修改到暂存区:git add .
提交到本地仓
提交之后会生成一个commitid,也即形成了一个历史版本
git commit -m "此次的提交说明"
查看历史记录
git reflog # 查看精简历史记录
git log # 查看详细的历史记录
2.5 差异
2.5.1 git diff常用指令
git diff # 查看暂存区和工作区的差异
git diff [file] # 指定文件,暂存区和工作区的差异
git diff --cached # 查看已暂存的改动,即比较暂存区和新版本HEAD
git diff --cached [file] # 同上,指定文件
git diff --staged # 查看已暂存的改动,即比较暂存区和新版本HEAD
git diff --staged [file] # 同上,指定文件
git diff HEAD # 查看已暂存+未暂存的所有改动,即与最新版本HEAD进行比较
git diff HEAD~ # 同上,与上一个版本比较
git diff [commitid1] [commitid2] # 比较两次提交之间的差异
git diff [branch] # 查看工作区和分支之间的差异
2.6 拉取&推送
git fetch [remote] # 获取远程仓库的所有变动到本地仓库,但不会自动合并,需要手动合并
git pull [remote] [branch] # 拉取远程仓库的变化,并与本地版本合并
git pull # 同上,针对当前分支
git pull --rebase # 使用rebase的模式进行合并
git push # 推动当前分支到远程仓库
git push [remote] [branch] # 推动本地当前分支到远程仓库的指定分支
git push [remote] all # 推动所有分支到远端
git push -u # -u表示与远程分支建立关联,第一次执行时使用,后续不再需要
2.7 版本穿梭
git reset
hard模式
git reset --hard [commitid]
hard模式会在重置HEAD(HEAD指向当前提交)和branch的同时,也会重置暂存区和工作区中的内容。即hard模式下,缓存区和工作区中的内容会被完全重置为 HEAD指向的新位置的内容。
mixed模式
git reset --mixed [commitd]
mixed是 git reset的默认参数,即如果不加参数则默认是mixed模式。
mixed模式下,保留工作区内容,重置暂存区内容。
soft模式
git reset --soft [commitid]
soft模式下,会保留工作区的内容,并将因重置HEAD所带来的新的文件差异放入暂存区。
操作示例
# 当前的提交,HEAD此时指向的commitid 为 2d14ccd
PS E:\workspace\proj-main> git reflog
2d14ccd (HEAD -> git_test) HEAD@{0}: commit: commit 3
08cb34a HEAD@{1}: commit: commit 2
db38d7e HEAD@{2}: commit: commit 1
soft
PS E:\workspace\proj-main> git reset --soft db38d7e
PS E:\workspace\proj-main> git status
On branch git_test
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: main.c
reset到commit1,reset的内容被放入本地仓(commit1的内容覆盖本地仓),而暂存区中依然是commit3的内容。即reset的内容仅覆盖本地仓,保留暂存区和工作区的内容:
mixed:
reset到commit1,reset的内容被放入暂存区(commit1的内容覆盖本地仓和暂存区),而工作区中依然是commit3的内容。
hard:reset到commit1,reset的内容被放入工作区(即commit1的内容不仅覆盖了本地仓和暂存区,还覆盖了工作区的内容)main.c的内容直接被commit1的修改覆盖。
2.8 撤销提交revert
revert用于撤销某一次历史提交,其基本原理是产生一个新的提交,用原提交的逆向操作来完成撤销操作。
git revert [commitid]
2.9 stash
git stash可以把当前工作区、暂存区未提交的内容先“隐藏”起来。这样就可以在未提交修改的情况下切换分支。
git stash # 把未提交的内容隐藏起来,包括未暂存和已暂存,等以后恢复现场后继续工作
git stash list # 查看所有被隐藏的内容列表
git stash pop # 恢复被隐藏的内容,同时删除隐藏记录
git stash save "message" # 同git stash,同时可以备注说明“message”
git stash apply # 恢复被隐藏的文件,但不删除隐藏记录
git stash drop # 删除隐藏记录
2.10 cherry-pick
cherry-pick可以复制一个指定的提交到当前分支,不管这个提交在哪个分支。
git cherry-pick [commitid]
2.11 submodule子模块
2.11.1 why need submodule?
较复杂的项目,可能会将代码根据功能拆分为不同的子模块,主项目对子模块有依赖关系,但并不关心子模块的内部开发流程细节。通常情况下,不会将所有源码放在一个代码仓中管理。
git 的 submodule 功能,就提供了单独管理子模块并建立当前项目与子模块之间的依赖关系的功能。
2.11.2 submodule的使用
假设主项目为 proj-main, 子模块项目为proj-sub,它们分别管理在不同的代码仓。
假设地址分别为:
https://github.com/zjy/proj-main.git
https://github.com/zjy/proj-sub.git
1. 创建submodule
git submodule add [submodule_url]
在主项目下执行上述命令,可以在项目中创建一个子模块。
执行完后,主项目仓中会多出两个文件.gitmodules
和proj-sub
。
# .gitmodules文件中包含了子模块的相关信息,例如
[submodule "proj-sub"]
path = proj-sub
url = https://github.com/zjy/proj-sub
此时.git/config
文件中也会多出一些信息,.git/modules
文件夹下也会多出一份内容。
此时可以git commit -m "add submodule proj-sub
提交一次,表示引入了某个子模块。提交后主项目仓中会显示出子模块文件夹,并带上其所在仓库的版本号。
2. 获取submodule
clone主项目代码到本地,并不会拉取到子模块中的实际代码。
若希望在clone的时候也拉取到子模块的代码,可以在clone的时候加上参数:此时proj-main/proj-sub 目录下有子项目代码,并固定在某个git提交的版本上
git clone https://github.com/zjy/proj-main --recurse-submodules
方法二:在主项目下执行:会根据主项目的配置信息,拉取更新子模块的代码
git submodule init
git submodule update
# 这两个命令可以合并执行
git submodule update --init
# 如果主项目依赖多个子模块,可以在后边儿跟上要更新的子模块名称,例如
git submodule update --init ./proj-sub-1
3. 子模块内容更新
子模块是单独管理的。对于主项目而言,子模块内容变动通常分为:
情况1:子模块有未跟踪的内容变动
如果要修改子模块的代码内容,则在子模块文件夹下,按照子模块内部的版本控制体系提交代码。(推头文件)
提交完后,主项目的状态则进入情况2:子模块发生版本变化
情况2:子模块有版本变化
子模块版本变化时,在主项目中使用git status查看仓库状态时,会显示子模块有新提交。
此时可以使用git add/commit 将其添加到主项目的代码提交中,实际的改动就是子模块文件所表示的版本信息。
- Subproject commit commit_id_old
+ Subproject commit commit_id_new
通常当子项目更新后,主项目修改其所依赖的版本时,会产生类似这种的commit提交信息。
情况3:子模块远程有更新
通常情况下,子模块负责维护自己的版本升级后,推送到远程仓库,并告知主项目可以更新对子模块的版本依赖。
关于git submodule update 更新子模块代码,是当当前主项目文件夹下的子模块内容与当前主项目记录的子模块版本不一致时,会参考后者进行更新。
但情况3,后者当前主项目记录的子模块版本还没有变化,因此主项目看来当前一切正常。
此时,需要在主项目下进入子模块拉取新版代码,进行升级操作:
cd proj-sub
git pull origin master
之后,子模块目录下的代码版本会发生变化,转到情况2进行主项目的提交。
# 若主项目的子项目太多,可以用如下命令执行
git submodule foreach 'git pull origin master'
4. 删除子模块
卸载子模块:
git submodule deinit proj-sub # 卸载子模块,若加上参数--force,则子模块工作区内即使有本地修改,也会被移除
git rm proj-sub
执行git submodule deinit
命令的实际效果,是在.git/confg
中删除了如下内容:
[submodule "proj-sub"]
url = https://github.com/zjy/proj-sub
执行git rm proj-sub
的实际效果是移除了proj-sub文件夹,并自动在.gitmodules
中删除以下内容:
[submodule "proj-sub"]
path = proj-sub
url = https://github.com/zjy/proj-sub
此时,主项目中关于子模块proj-sub的信息已经基本删除,可以提交代码。
2.11.3 summary
git submodule,主项目仓库并不会包含子模块的文件,而是保留一份子模块的配置信息和版本信息,作为主项目版本管理的一部分。
参考内容
- Git代码管理完整流程(没有废话) - lycheezhang - 博客园
- Git入门图文教程(1.5W字40图)🔥🔥–深入浅出、图文并茂 - 安木夕 - 博客园
- Git中submodule的使用 - 知乎