Git
本地修改了分支-远程分支已有新提交-如何拉取🌸
暂存后拉取
提交本地更改:
使用
git add和git commit将本地更改提交到本地仓库。确保本地代码没有未提交的更改。拉取远程分支:
# your_branch_name 更改为本地分支名称(如 master/main/develop) git pull origin <your_branch_name>解决冲突:
如果在执行
git pull时发生冲突,Git 会提示你解决冲突。手动解决冲突并保存修改。提交合并:
一旦冲突解决完毕,使用
git add命令将解决后的文件添加到暂存区,并使用git commit提交合并的更改。推送到远程分支:
git push origin <your_branch_name>
使用 git stash
如果本地想在不执行commit的情况下拉取远程最新提交,需要使用 git stash 储藏工作区修改,再执行拉取操作,最后恢复修改。
储藏本地修改
git stash push -m "暂存本地修改(不包含未跟踪文件)"git stash push:将工作目录和暂存区的修改保存到“储藏栈”中,工作区会恢复到上次提交的干净状态。-m "描述":可选,添加备注便于识别(推荐使用)。
拉取远程最新提交
# your_branch_name 更改为本地分支名称(如 master/main/develop) git pull origin <your_branch_name>- 此时工作区无本地修改,可安全拉取远程最新代码。
恢复本地修改
git stash pop- 将最近一次储藏的修改恢复到工作区,并自动删除该储藏记录(若有冲突则不会自动删除)。
- 若恢复时发生冲突(文件被远程修改且本地也修改了),需手动解决冲突(冲突文件会包含
<<<<<<<标记)。
重要
当执行
git stash pop时,Git 会尝试将暂存的修改应用到当前工作目录。文件会有以下状态:四种状态
- Auto-merging
- 含义: 表示 Git 成功自动合并 这些文件。远程和
stash中的修改互不干扰,Git 能够自动将这些修改合并。 - 举例:
stash中的一个文件,修改了第10行;git pull下来的版本修改了第20行。这两处修改 Git 就会自动合并。
- 含义: 表示 Git 成功自动合并 这些文件。远程和
- Changes to be committed
- 含义: 这表示在您执行
git stash时,有些修改已经使用git add添加到了暂存区。在pop之后,这些修改被成功地、自动地恢复到了暂存区状态,等待您提交。 - 举例: 先修改了
a.txt并git add了它,然后执行了git stash。当pop时,这个对a.txt的修改就会直接出现在暂存区,而不是工作区。
- 含义: 这表示在您执行
- Unmerged paths
- 含义: 这是最关键的一项。表示 发生了合并冲突。有些文件在
stash的版本和git pull后的当前版本中,对 相同的位置 进行了修改,Git 无法自动决定该保留哪个修改,因此需要手动解决这些冲突。 - 文件状态: 这些文件会被标记为
both modified。 - 处理方式: 您需要打开这些文件,解决标记为
<<<<<<<,=======,>>>>>>>的冲突部分,然后使用git add命令将解决后的文件标记为已解决。
- 含义: 这是最关键的一项。表示 发生了合并冲突。有些文件在
- Untracked files
- 含义: 这表示在您执行
git stash时,工作目录中存在一些新增的、未被Git跟踪的文件。默认的git stash不会保存这些未跟踪文件(除非使用git stash -u或-a选项)。这里的提示可能是在告诉您这些文件依然存在,或者是从stash中恢复出来的(如果您用了-u)。
- 含义: 这表示在您执行
当发生冲突时
存在 Unmerged paths(合并冲突),
apply操作被认为是没有“完全成功”的。Git 出于安全考虑,中断了自动删除的步骤,并给您留下了提示:警告
"The stash entry is kept in case you need it again."
这是由于:
git stash pop在应用存储时遇到了合并冲突不会自动删除stash。这个命令实际上是两个操作的组合:
git stash apply: 尝试将存储的修改应用到当前工作目录。git stash drop: 只有在apply成功完成(没有产生任何冲突)的情况下,才会自动删除对应的存储条目。
在您的情况下,由于存在 “Unmerged paths” (合并冲突),
apply操作被认为是没有“完全成功”的。Git 出于安全考虑,中断了自动删除的步骤,并给您留下了提示:这样做的目的是:
- 给您一个回退的机会: 如果您在解决冲突的过程中搞砸了,或者想放弃这次合并,您可以通过
git stash apply重新应用这个被保留的 stash,或者使用git checkout来撤销对冲突文件的修改,然后换个方式重新尝试。 - 防止数据丢失: 在冲突完全解决之前,Git 无法确定您的最终意图,因此它选择保留原始的存储内容,确保您的工作成果不会因为一次失败的自动合并而丢失。
⚠️ 关键注意事项
未跟踪文件(Untracked Files)
git stash默认不保存未跟踪文件(如新创建未git add的文件)。若需保存,使用:git stash push -u -m "暂存所有修改(含未跟踪文件)"-u参数会包含未跟踪文件。多批次储藏
可多次执行
git stash push保存多组修改,通过git stash list查看记录。恢复时用:git stash pop stash@{0} # 恢复指定储藏(0 为栈索引)若
git stash pop后出现冲突:- 手动编辑冲突文件(搜索
<<<<<<<标记)。 - 解决后执行
git add 冲突文件名标记为已解决。 - 最后
git stash drop删除储藏记录(pop失败时需手动删除)。
- 手动编辑冲突文件(搜索
替代方案(谨慎使用)
git commit -am "临时提交" # 将修改临时提交 git pull --rebase # 变基拉取(将临时提交置于最新提交之上) git reset HEAD~1 # 撤销临时提交,保留修改在工作区- 适用于熟悉
rebase的用户,操作更复杂但可避免储藏栈管理。
- 适用于熟悉
💡 操作流程图解
冲突处理
查看冲突文件状态,查看被标记为冲突(Unmerged paths) 的文件
git status手动解决文件冲突
用编辑器打开冲突文件:
code src/lib/components/layout/Sidebar/UserMenu.svelte在文件中查找冲突标记:
<<<<<<< Updated upstream // 以下是远程版本的代码(来自最新拉取的提交) // 远程修改内容... ======= // 以下是您本地修改的代码(来自 stash) // 本地修改内容... >>>>>>> Stashed changes手动编辑文件:选择保留远程版本/本地版本,或合并两者,并删除所有冲突标记:
<<<<<<<、=======、>>>>>>>。
标记冲突已解决
# 此命令告知 Git 该文件冲突已解决 git add src/lib/components/layout/Sidebar/UserMenu.svelte完成
stash恢复重要
再此之前应该先执行
git status确认冲突文件已经全部解决。git stash drop- 手动删除被保留的
stash条目(因为pop未自动完成,Git 不会自动删除最近一条stash记录。) - 使用
git stash list可查看所有储藏记录。
- 手动删除被保留的
恢复工作区更改
在使用 git stash pop 恢复储藏区更改遇到冲突之后,仓库处于混合状态:
- 已应用:
stash中的部分修改 - 冲突中(如果有):与远程更新冲突的文件
- 已更新:
git pull成功拉取的远程内容
使用 git restore 放弃对已追踪文件的修改(推荐)Git 2.23+ 引入
# 恢复所有文件到最新一次提交的状态
git restore .
# 重新应用最新的一次 `stash`
git stash apply stash@{0}
.表示当前目录
提示
传统命令(Git 1.6.0+)
git checkout -- .
--是一个分隔符,表示"后面是文件路径,而不是分支名".表示当前目录
使用 git reset 撤销恢复(不推荐)
重要
放弃当前冲突恢复(恢复工作区到执行 git stash pop 之前的状态),它彻底清除了工作目录和暂存区中所有未提交的更改。这包括:
- 执行
stash pop之前已经存在于工作目录但尚未提交的本地修改。 stash pop操作试图应用的来自暂存区的修改。stash pop操作产生的所有冲突标记。
git reset --hard HEAD
# 重新应用 `stash`
git stash apply stash@{0}
冲突预防建议:
# 下次 `stash` 时添加详细描述
git stash push -m "修改描述_日期"
# 拉取前检查差异
git diff origin/main...HEAD # 替换 main 为您的分支名
上传本地代码到 GitHub
在 GitHub 上创建仓库:
- 打开 GitHub 网站,登录你的账号。
- 点击页面右上角的加号图标,选择 "New repository"(或类似选项)。
- 输入仓库名称、描述和其他设置,并选择公开或私有仓库。
- 点击 "Create repository" 创建新的远程仓库。
初始化本地仓库:
- 在你的本地计算机上,进入你想要上传到 GitHub 的项目文件夹。
- 打开命令行终端。
初始化 Git 仓库:
- 执行
git init命令来初始化一个新的 Git 仓库。
- 执行
添加远程仓库链接:
- 执行
git remote add origin <remote_repository_url>命令,将你在 GitHub 上创建的远程仓库链接与本地仓库关联。<remote_repository_url>:仓库的 HTTPS 或 SSH 链接。
- 执行
添加和提交代码:
- 执行
git add .命令将所有本地文件添加到暂存区。 - 执行
git commit -m "Initial commit"命令将暂存区的更改提交到本地仓库。你可以自定义提交信息以描述本次提交的内容。
重要
如果远程仓库有初始化好的README.md等文件,先拉取仓库最新文件:
使用
git fetch origin master拉取远程仓库代码使用
git merge origin/master合并远程master分支到本地master分支如果你希望将远程
origin/master分支的更改合并到一个新的本地分支,可以使用以下命令:git checkout -b new_branch origin/master
重新执行第5步
- 执行
推送到远程仓库:
运行
git push -u origin master(如果你的主分支是master)将本地仓库的代码推送到远程仓库。提示
-u参数是--set-upstream的简写。设置上游分支关联:将本地的
master分支与远程的origin/master分支建立跟踪关系简化后续操作:设置关联后,以后执行
git push和git pull时就不需要指定远程仓库和分支名了
git command list✨
好的,以下是修改后的Git命令表格,使用<>和[]括住需要参数的部分:
| 命令 | 命令示例 | 详细解释 |
|---|---|---|
| git init | git init | 在当前目录初始化一个新的Git仓库 |
| git clone <repository_url> | git clone https://github.com/user/repo.git | 克隆远程仓库到本地 |
| git add <file_path> | git add file.txt | 将文件添加到暂存区 |
| git commit -m "<commit_message>" | git commit -m "Add new feature" | 将暂存区的内容提交到本地仓库 |
| git status | git status | 显示工作树的状态 |
| git push <remote_name> <branch_name> | git push origin master | 将本地仓库的内容推送到远程仓库 |
| git pull <remote_name> <branch_name> | git pull origin master | 从远程仓库拉取内容到本地仓库 |
| git branch | git branch | 显示本地分支列表 |
| git checkout <branch_name> | git checkout main_branch | 切换到指定分支 |
| git merge <branch_name> | git merge feature_branch | 将指定分支合并到当前分支 |
| git remote | git remote | 显示远程仓库的别名列表 |
| git fetch <remote_name> | git fetch origin | 从远程仓库获取最新内容,但不合并到本地仓库 |
| git log | git log | 显示提交历史记录 |
| git reset <commit_hash> | git reset commit_hash | 将HEAD指针指向特定的提交,可选地重置暂存区和工作树 |
| git revert <commit_hash> | git revert commit_hash | 创建一个新的提交,撤销指定提交的更改 |
| git stash | git stash push -m "暂存本地修改" git stash pop | 将当前工作树中的变更保存到堆栈中,以便稍后恢复 |
| git cherry-pick <commit_hash> | git cherry-pick commit_hash | 选择一个特定的提交并将其应用到当前分支 |
| git remote add <remote_name> <repository_url> | git remote add origin https://github.com/user/repo.git | 添加远程仓库别名 |
| git remote remove <remote_name> | git remote remove origin | 移除指定的远程仓库别名 |
| git diff | git diff | 显示暂存区和工作树之间的差异 |
| git diff <commit_old_hash> <commit_new_hash> | git diff 343e12b1 ad494be0 --stat | 查看new相对于old提交之间的差异,加上 --stat 参数则只输出统计信息; |
| git tag <tag_name> | git tag v1.0.0 | 创建一个新的标签 |
| git push --tags | git push --tags | 将本地标签推送到远程仓库 |
| git config --global <config_param> "<config_value>" | git config --global user.name "John Doe" | 配置Git的全局设置 |
| git log --graph | git log --graph | 以图形方式显示提交历史记录 |
| git clean [-n] | git clean -n | 显示将要删除的未跟踪文件列表,使用-f进行实际删除 |
| git rm <file_path> | git rm file.txt | 从Git中删除文件 |
| git show <commit_hash> | git show commit_hash | 显示特定提交的详细信息 |
| git rebase <branch_name> | git rebase main_branch | 将当前分支的更改在指定分支上重新应用 |
请注意,尖括号<>表示必需参数,而方括号[]表示可选参数。这样更容易理解每个Git命令所需的参数。
在命令行参数符号意思
<>尖括号:- 一般代表命令必填参数,即在执行命令时必须提供的参数。
- 示例:
command <required_parameter>
[]方括号:- 一般代表命令可选参数,即在执行命令时可以选择性地提供的参数,但不是必需的。
- 示例:
command [optional_parameter]
{}花括号:- 有时也用于表示命令必填参数,与尖括号类似。这种用法可能因具体的命令规范而异。
- 示例:
command {required_parameter}
()圆括号:- 圆括号在命令行中通常用于表示一组选项,用户可以从中选择一个。
- 示例:
command (option1 | option2 | option3)
|管道符号:- 管道符号用于将一个命令的输出作为另一个命令的输入。不表示参数本身,但是在命令行操作中很常见。
- 示例:
command1 | command2
...省略号:- 省略号表示参数可以重复出现多次。
- 示例:
command <required_parameter> ...
远程分支名称解析
在 Git 中,远程分支名称如 origin/main 的命名规则和本地分支 main 的关系,是由 Git 的分支管理机制决定的,核心原因在于 命名空间隔离 和 远程跟踪分支(Remote-Tracking Branch) 的设计。以下是详细解释:
1. 为什么远程分支叫 origin/main?
origin是远程仓库的别名:
当你克隆仓库时,Git 默认将远程仓库命名为origin(可自定义)。origin代表远程仓库的 URL 地址。- 斜杠
/是命名空间分隔符:origin/main表示“远程仓库origin上的main分支”。斜杠的作用是:- 避免本地分支与远程分支同名冲突(例如本地可同时存在
main和origin/main)。 - 明确标识分支的来源(远程仓库名 + 分支名)。
- 避免本地分支与远程分支同名冲突(例如本地可同时存在
2. 为什么拉取后本地分支叫 main?
- 远程跟踪分支(Remote-Tracking Branch):
origin/main是一个本地存在的引用,它记录远程仓库origin上main分支的最新状态。它不是真正的本地分支,而是 Git 在本地创建的“影子分支”,用于跟踪远程变化。 - 创建本地分支:
当你运行git checkout main(或git switch main)时,Git 会:- 查找本地是否存在
main分支。 - 若不存在,则自动基于
origin/main创建同名的本地分支main,并建立跟踪关系(Tracking Relationship)。
# 示例:拉取远程 main 分支到本地 git checkout main # 等价于:git checkout -b main --track origin/main - 查找本地是否存在
3. 关键概念解析
| 类型 | 名称示例 | 作用 |
|---|---|---|
| 远程仓库别名 | origin | 指向远程仓库 URL 的简称(默认为 origin) |
| 远程跟踪分支 | origin/main | 本地存储的远程分支状态,只读(通过 git fetch 更新) |
| 本地分支 | main | 用户实际操作的开发分支,可提交代码 |
| 跟踪关系(Tracking) | main → origin/main | 本地分支与远程分支的关联,git pull/git push 无需指定远程分支 |
4. 设计目的与优势
- 隔离性:
远程分支(origin/main)和本地分支(main)物理分离,防止误操作覆盖远程分支。 - 清晰的状态管理:
git status会提示本地分支与origin/main的提交差异(例如领先或落后)。git branch -a可同时查看本地分支和远程跟踪分支(以remotes/origin/开头)。
- 简化协作流程:
通过跟踪关系,git pull=git fetch(更新origin/main) +git merge origin/main(合并到本地分支)。
5. 常见操作示例
- 查看远程跟踪分支:
git branch -r # 显示所有远程跟踪分支(如 origin/main) - 手动建立跟踪关系:
git branch -u origin/main # 将当前本地分支跟踪到 origin/main - 删除远程跟踪分支(当远程分支已删除):
git fetch origin --prune # 清理本地失效的远程跟踪分支
总结
origin/main是 Git 在本地创建的远程跟踪分支,用于记录远程仓库状态,命名格式为<远程仓库名>/<分支名>。main是用户操作的本地分支,通过git checkout基于origin/main创建并自动建立跟踪关系。- 斜杠
/是 Git 的命名约定,确保本地与远程分支的命名空间互不冲突。
这种设计既保证了远程分支状态的独立性,又简化了本地开发流程,是 Git 分布式架构的核心特性之一。
——————————
文件状态
在Git中,文件的状态可以分为以下几种:
- 未跟踪(Untracked):文件是新的,Git之前没有跟踪过。
- 已修改(Modified):文件被修改了,但还没有被暂存(unstaged changes)。
- 已暂存(Staged):文件被修改并且已经通过
git add命令添加到了暂存区,等待提交。 - 未修改(Unmodified):文件没有修改,或者修改已经被提交。
在 VS Code 的 Git 窗口中,文件被分为 "Staged Changes" 和 "Changes" 两类,这是 Git 工作流程的核心设计,具体区别如下:
Changes(未暂存的修改)
- 含义:文件已被修改(或新增),但尚未添加到 Git 的暂存区(Staging Area)。
- 状态特点:
- 文件处于工作目录(Working Directory)中。
- 这些修改不会被包含在下一次
git commit中。 - 在 VS Code 中显示为 "Changes" 分组(通常位于顶部)。
- 操作建议:
- 点击文件旁的 "+" 图标 或右键选择 "Stage Changes" 可将其移至暂存区(相当于
git add)。 - 直接编辑文件会导致此分组动态更新。
- 点击文件旁的 "+" 图标 或右键选择 "Stage Changes" 可将其移至暂存区(相当于
Staged Changes(已暂存的修改)
- 含义:文件已通过
git add添加到暂存区,准备被提交。 - 状态特点:
- 文件已进入 Git 的暂存区(Index)。
- 这些修改会被包含在下一次
git commit中。 - 在 VS Code 中显示为 "Staged Changes" 分组(位于 "Changes" 下方)。
- 操作建议:
- 点击文件旁的 "-" 图标 或右键选择 "Unstage Changes" 可移回未暂存状态(相当于
git restore --staged)。 - 点击 √ 提交按钮 会提交此分组的所有文件。
- 点击文件旁的 "-" 图标 或右键选择 "Unstage Changes" 可移回未暂存状态(相当于
- 含义:文件已通过
⚙️ 设计目的:精准控制提交内容
Git 通过分离 工作目录 → 暂存区 → 版本库 的三级流程,实现:
- 选择性提交:仅暂存部分文件(如只提交功能 A 的代码,暂不提交调试日志)。
- 分批提交:将大改动拆解为多个逻辑独立的提交。
- 减少误提交:避免未完成的修改意外进入版本历史。
💡 VS Code 操作对比表
| 状态 | VS Code 显示分组 | 操作 | 等效 Git 命令 |
|---|---|---|---|
| 未暂存的修改 | Changes | 点击 + | git add <file> |
| 已暂存的修改 | Staged Changes | 点击 - | git restore --staged <file> |
提示
示例场景
假设你修改了 a.js 和 b.js:
- 初始状态 → 两文件均显示在 "Changes" 分组。
- 点击
a.js旁的 "+" →a.js移动到 "Staged Changes"。 - 点击提交按钮 → 仅提交
a.js,b.js仍保留在未暂存状态。
Repo
Repo 基于git的工具,它用来管理多个git代码库。把所有的代码用一个git库管理已经越来越力不从心。这个时候的一个很自然的思路就是分而治之,把整个project按模块分成一个个单独的git库,再用一个统一的工具管理,repo因此应运而生。
规范
常用 Commit 标签描述
| 标签 | 描述 | 示例 |
|---|---|---|
feat | 新功能 | feat: 添加用户注册端点 |
fix | 修复 bug | fix: 修复首页数据无法加载的问题 |
docs | 仅文档更改 | docs: 更新 API 接口文档 |
style | 代码风格调整(不影响代码运行) | style: 修正变量命名缩进 |
refactor | 代码重构(既非新功能,也非修 bug) | refactor: 使用策略模式重构支付逻辑 |
perf | 性能优化 | perf: 使用 memo 缓存组件减少重复渲染 |
test | 添加或修改测试用例 | test: 为用户服务添加单元测试 |
build | 影响构建系统或外部依赖的更改 | build: 升级 webpack 到 v5 |
ci | 持续集成配置和脚本的更改 | ci: 在 GitHub Actions 中增加 SonarQube 检查 |
chore | 其他不修改源码或测试文件的杂项变更 | chore: 更新依赖包版本 |
revert | 回滚之前的提交 | revert: 回滚提交 abc123 |
例如:
feat: 添加用户登录功能
- 实现用户名密码登录
- 添加记住密码功能
- 优化登录错误提示
Closes #123
命令
查看待commit的文件路径
待commit:已添加到暂存区
git diff --name-only --cached
提示
命令执行之后
- 键入:q 退出命令
- 键入:s 输入文件名称保存到项目根路径
git pull 和 git fetch 区别
提示
先总结:
git pull是从远程仓库获取最新代码并 直接合并 到当前分支的操作。git fetch是仅从远程仓库获取最新代码但 不进行合并 的操作。
具体区别
git pull:git pull=git fetch+git merge。# 假设远程仓库别名为origin 分支名为main git pull origin main # 相当于 git fetch git merge origin/main如果有冲突,你需要解决冲突后才能完成合并。
git pull的执行过程会直接更新当前分支的工作目录。
git fetch:git fetch从远程仓库获取最新的提交记录和分支信息,但不会将这些更改直接合并到当前分支。- 它只会将获取的远程分支更新到本地仓库的
.git目录下,而不会修改工作目录中的文件。 git fetch可以帮助你了解远程仓库的最新状态,你可以通过查看远程分支来了解它的提交记录,然后决定是否要进行合并操作。
git merge
将远程分支的更新合并到当前的分支,需要手动执行 git merge 或者其他合并命令(例如 git rebase)来将这些更新应用到你的工作目录和分支。
下面是一种常见的步骤来将远程分支的更新合并到你当前的分支:
git fetch: 从远程仓库获取最新提交记录和分支信息。git merge origin/your_remote_branch: 将远程分支合并到你当前的分支。your_remote_branch是你想合并的远程分支的名称。这个命令会将远程分支的更改合并到你的当前分支中。
或者,如果你喜欢使用 git pull,你也可以用 git pull 命令来达到相同的目的,因为 git pull 实际上包含了 git fetch 和 git merge 的操作:
git pull origin your_remote_branch
无论是使用 git fetch 和手动 git merge,还是直接使用 git pull,都要确保在执行合并操作之前没有未提交的更改,以免可能产生冲突。如果有冲突,你需要先解决冲突后再提交合并的更改。
git stash
当需要 切换到其他分支 或 本地已经做了修改需要拉取远程代码 时,不希望携带当前工作区内未commit的内容时,stash就派上了用场,它可以储藏当前未commit的数据。
重要
在 Windows 终端或某些 shell 中,stash@{0} 中的花括号 {} 可能被错误解析。实际使用时,可以直接使用数字索引,Git2.11.0+(2016-11-29发布) 会自动识别。只需要键入 index 对应的阿拉伯数字即可。另外提供老版本兼容办法:
- 可以使用
^号进行转义:stash^@{index} - 加双引号:
"stash@{index}"
注:最近一次 stash 记录的 index 值总是 0 。
例如:
>git stash list
stash@{0}: On main: 版本2 # 最近 `stash` 的记录
stash@{1}: On main: 版本1 # 最早 `stash` 的记录
# 查看stash{0}与当前工作区的详细行变更
## `-p` 参数表示以补丁格式显示,包含具体的代码变更
> git stash show -p 0
用法:
储藏工作区内的修改,并给此次
stash命名git stash push -m '暂存提交'重要
如果需要包含以下三种文件,使用
-u选项:- 已暂存文件(已经
git add过的) - 未暂存文件(工作区内修改)
- 未跟踪文件(刚新增还未跟踪的文件)
git stash push -m '暂存提交' -u提示
对比
git stash save的优势?git stash push支持一个非常重要的特性:路径限定符-- <pathspec>。这允许你只暂存工作目录中特定文件或路径的更改,而不是整个工作目录。例如:git stash push -m "暂存src/的修改" -- src/ git stash push -m "暂存file.txt" -- file.txt- 已暂存文件(已经
查看所有的
stashgit stash list查看特定的
stashgit stash show -p stash@{index} # 例如 git stash show -p 0-p:以补丁格式显示,包含具体的代码变更。(不加则仅查看改动了几个文件,一共新增/删除多少行,类似git diff --stat)
恢复最近一次储藏的修改,并将其从
stash列表中移除git stash pop重要
相当于
# 恢复最新的储藏,并在成功恢复之后删除它。 git stash apply && git stash drop如果恢复发生了冲突,Git不会自动删除这个stash,需要手动进行冲突处理。
恢复特定的
stashgit stash apply stash@{index}删除特定的
stash,但不会恢复其中的修改git stash drop stash@{index} # 例如 git stash drop 0删除所有暂存的
stashgit stash clear
git diff
用于比较 Git 仓库中不同版本、文件或分支之间差异的核心命令。
- 比较工作区与暂存区
- 查看已修改但未暂存(未
git add)的文件内容变化:git diff
- 比较暂存区与最新提交
- 查看已暂存但未提交(已
git add)的更改:git diff --staged # 或 git diff --cached
- 比较两个提交之间的差异
- 指定两个提交的哈希值或引用:
git diff <commit1> <commit2>
- 比较分支之间的差异
- 查看两个分支的最新提交差异:
git diff <branch1> <branch2> - 比较当前分支与另一分支:
git diff <branch_name>
- 比较特定文件的更改
- 限定只查看某个文件的差异:
git diff <file_path> - 跨分支比较指定文件:
git diff <branch1> <branch2> -- <file_path>
- 其他常用选项
- 统计变更摘要(增/删行数):
git diff --stat - 显示单词级差异(而非行级):
git diff --word-diff
代理
配置代理
# Set HTTP proxy
git config --global http.proxy "http://127.0.0.1:7890"
# Set HTTPS proxy
git config --global https.proxy "http://127.0.0.1:7890"
# 验证
git config --get http.proxy
git config --get https.proxy
取消代理
# Unset HTTP proxy
git config --global --unset http.proxy
IDEA的 Update Project
场景一:默认/使用 Merge 方式更新
相当于:;这是最传统、最安全的方式。
执行的 Git 指令序列大致如下:
git fetch origin- 这是最关键的一步。它从远程仓库(通常是
origin)获取所有最新的分支、标签信息,但不会自动合并到你的当前工作分支。它只是让你本地知道远程仓库现在是什么样子。
- 这是最关键的一步。它从远程仓库(通常是
git merge origin/your-current-branch-name(例如git merge origin/main)- 在
fetch获取到远程的最新信息后,IDEA 会将远程分支(origin/main)合并 到你当前检出的本地分支(main)。
- 在
简单来说,Merge 方式 = git fetch + git merge
结果: 如果远程有新的提交,你的本地分支会生成一个额外的 合并提交,将两条开发线汇合。
场景二:使用 Rebase 方式更新
这是一种更线性和整洁的更新方式,也是目前很多团队推荐的做法。
执行的 Git 指令序列大致如下:
git fetch origin- 同样,第一步永远是先获取远程的最新信息。
git rebase origin/your-current-branch-name(例如git rebase origin/main)- 在
fetch之后,IDEA 不是执行合并,而是执行 变基。它会将你本地尚未推送到远程的提交“暂时取下”,然后基于远程最新的提交重新应用你的提交。
- 在
简单来说,Rebase 方式 = git fetch + git rebase
结果: 你的本地提交会“移动”到项目最新提交的顶端,形成一条直线式的历史,没有合并提交。
如何查看和配置更新类型?
在 IDEA 中,路径是:
File -> Settings -> Version Control -> Git
在右侧找到 Update Method 进行选择。
- Merge: 默认选项。
- Rebase: 更干净的提交历史。
- Branch Default: 使用为该分支配置的默认策略。
特殊情况下的行为
- 如果当前分支有未提交的更改:
IDEA 非常智能,它不会直接执行merge或rebase,因为这会与未提交的更改冲突。它会先尝试 Stash(储藏) 你的更改。- 相当于执行:
git stash push -m "IDEA Stash before Update" - 然后执行
git fetch+git merge/rebase - 最后再尝试 Unstash(应用储藏):
git stash pop - 如果应用储藏时发生冲突,IDEA 会提示你解决冲突。
- 相当于执行:
- 如果当前分支在远程没有对应的上游分支:
IDEA 的 Update Project 按钮可能会变灰或无法正常工作,因为它不知道要和哪个远程分支进行同步。
总结对比
| 特性 | Merge 方式 | Rebase 方式 |
|---|---|---|
| 等效命令 | git fetch + git merge | git fetch + git rebase |
| 提交历史 | 保留合并提交,呈网状 | 线性整洁,像一条直线 |
| 安全性 | 较高,不重写历史 | 较低,重写了本地提交历史 |
| 适用场景 | 公共分支(如 main/master),团队新手友好 | 个人功能分支,追求清晰历史 |
多Remote
(一个本地项目,关联两个远程仓库)
1. 准备本地仓库
可以用现有仓库,也可以新建一个:
git init
如果已经连接了 GitHub 或其他远程,执行:
git remote -v
会看到类似输出:
origin git@github.com:username/repo.git (fetch)
origin git@github.com:username/repo.git (push)
2. 添加第二个远程仓库
假设第二个远程是 GitLab,远程名可以自定义,常见如 origin2 或 gitlab,这里用清晰的 gitlab :
git remote add gitlab git@gitlab.com:username/repo.git
再次查看:
git remote -v
输出会是:
origin git@github.com:username/repo.git (fetch)
origin git@github.com:username/repo.git (push)
gitlab git@gitlab.com:username/repo.git (fetch)
gitlab git@gitlab.com:username/repo.git (push)
这样你就同时关联了两个远程。
3. 同时推送到两个远程仓库
有两种方式:
方式一:手动分别推送
git push origin main
git push gitlab main
灵活且安全,但要多执行一次命令。
方式二:配置多推送地址,实现一次命令推送两个远程
编辑 .git/config,在 [remote "origin"] 下添加多条 pushurl:
[remote "origin"]
url = git@github.com:username/repo.git
fetch = +refs/heads/*:refs/remotes/origin/*
pushurl = git@github.com:username/repo.git
pushurl = git@gitlab.com:username/repo.git
此后执行:
git push origin main
就会同步推送到 GitHub 和 GitLab 两个仓库。
警告
如果用于 CI/CD,请确保两个仓库的流水线不会因同一提交重复触发,这点很重要。
额外操作:重命名或删除远程
重命名远程:
git remote rename origin github1
删除远程:
git remote remove gitlab1
提示
为什么要用两个远程?
- 备份:GitHub 崩了,GitLab 还在;
- 迁移:试用新平台,旧平台继续线上运行;
- 镜像:想多地方展示代码,简单又直观;
- CI/CD 分离:GitHub 管理代码,GitLab 管理部署。
Submodule
介绍
Git Submodule 允许你在一个 Git 仓库中引用另一个 Git 仓库,作为其子目录(子模块)。这个子目录实际上是一个指向另一个 Git 仓库的指针(哈希值),而不是实际的文件。这样,你就可以在父仓库中维护一个或多个子模块仓库,每个子模块仓库都有自己的版本历史、分支和标签。
项目中经常使用别人维护的模块,在git中使用子模块的功能能够大大提高开发效率。
使用子模块后,不必负责子模块的维护,只需要在必要的时候同步更新子模块即可。使用子模块后,不必负责子模块的维护,只需要在必要的时候同步更新子模块即可。
提示
子模块有自己的分支和标签,与父仓库的分支和标签是分开的。你可以在子模块中切换到不同的分支,进行开发或测试。但是,在父仓库中,你只能通过更新子模块的提交ID来引用子模块的不同版本。
git 将 submodule 有关的信息保存在两个地方:
.gitmodules:在仓库中,有版本控制,修改之后会同步到其他仓库,使用submodule相关命令的时候会自动更新.git/config:在本地,需要手动更新,或者执行git submodule sync将新的配置从.gitmodules拷贝到.git/config.git submodule sync: 会将submodule远程的url配置设置到.gitmodules,并且只会影响.git/config已经有url的条目,指定–recursive,将会递归更新注册的submodule。
添加
git submodule add <repository> <path>
# 通过 -b 指定对应分支
git submodule add -b master [URL to Git repo];
其中 <repository> 是子模块仓库的 URL,<path> 是子模块在父仓库中的路径。
注
示例:
# 在 libs 目录下添加一个子模块
git submodule add https://github.com/example/library.git libs/mylibrary
# 初始提交
# 添加子模块后,需要提交 .gitmodules 文件和子模块目录
git add .gitmodules libs/mylibrary
git commit -m "添加子模块: mylibrary"
执行成功后
git status会看到项目中修改了.gitmodules,并增加了一个新文件(为刚刚添加的路径)git diff --cached查看修改内容可以看到增加了子模块,并且新文件下为子模块的提交hash摘要git commit提交即完成子模块的添加。
clone 含有 submodule 的仓库
完整克隆(推荐)
# 一次性克隆主项目和所有子模块
git clone --recurse-submodules <repository_url>
分步克隆
当 clone 的项目中带有 submodule 时,默认 submodule 的内容并不会自动下载,有两种方法:
# 1. 先克隆主项目 git clone <repository_url> cd <project_name> # 2. 初始化子模块配置 git submodule init # 3. 拉取子模块最新内容 git submodule update# 一次性初始化并更新所有子模块 git submodule update --init # 或 # 递归初始化所有嵌套子模块 git submodule update --init --recursive
执行后,子模块目录下就有了源码,再执行相应的makefile即可。
更新
子模块的维护者提交了更新后,使用子模块的项目必须手动更新才能包含最新的提交。
主项目中更新所有子模块
git submodule update --remote更新单个子模块
cd libs/mylibrary git pull [origin] [main] # 查看相应提交 git log # 返回主目录 cd ../.. # 添加子模块新增内容 git add libs/mylibrary git commit -m "更新子模块版本"
修改分支
如果创建子模块时没有指定分支,可以使用以下命令切换分支
其中 projectName 为主项目名, submoduleA 为子模块名, git checkout 切换到我们的对应分支,然后拉取对应分支代码
cd libs/mylibrary
git checkout master
cd ../..
# 批量操作所有子模块
git submodule foreach git pull
cd ..
指定子模块分支
# 在 .gitmodules 中设置分支
git config -f .gitmodules submodule.libs/mylibrary.branch main
# 更新时使用指定分支
git submodule update --remote --remote
批量操作所有子模块
# 在所有子模块中执行命令
git submodule foreach git pull
# 示例:检查所有子模块状态
git submodule foreach git status
删除子模块
删除子模块条目
git submodule deinit -f libs/mylibrary从工作区删除文件
rm -rf .git/modules/libs/mylibrary git rm -f libs/mylibrary提交更改
git commit -m "删除子模块 mylibrary"
识别项目中的 Submodule
查看子模块信息
# 查看所有子模块状态
git submodule status
# 查看子模块摘要信息
git submodule summary
# 查看 .gitmodules 文件内容
cat .gitmodules
# 或使用 git 命令查看
git config --file .gitmodules --list
识别子模块文件夹
# 子模块文件夹通常显示为特殊模式
ls -la
# 子模块文件夹显示为:@b9b8c6f libs/mylibrary
# 查看 git 跟踪的文件类型
git ls-tree -r HEAD --name-only
子模块更新冲突
# 如果子模块更新出现冲突,可以重置
git submodule update --init --force
# 或进入子模块手动解决冲突
cd libs/mylibrary
# 查看冲突
git status
# 解决冲突后提交
