GitLab¶
Git¶
Git Flow 工作流示意图¶
flowchart TD
%% Main branch (蓝色)
A0["Initial commit"]:::main --> B0["Setup project structure"]:::main
%% feature/config 分支开发 (绿色)
subgraph feature/config
C1["Add loadConfig function"]:::feature
C2["Move defaultConfig to separate module"]:::feature
C3["Add watchConfig and saveConfig"]:::feature
C1 --> C2 --> C3
end
%% develop branch (橙色)
D0["develop branch start"]:::develop --> D1["Merge feature/config (normal merge)"]:::develop
C3 --> D1
B0 --> D0
%% main branch初始化 (蓝色)
E0["Initial main commit"]:::main
D1 --> E0
%% squash merge feature/config 到 main
F1["refactor(electron): modularize main process and secure preload API"]:::main
C3 --> F1
E0 --> F1
%% feature/ui 分支开发 (绿色)
subgraph feature/ui
G1["Add login UI"]:::feature
G2["Add theme switcher"]:::feature
G1 --> G2
end
%% squash merge feature/ui 到 main
H1["feat(ui): login & theme UI"]:::main
G2 --> H1
F1 --> H1
%% 分支颜色定义
classDef main fill:#1f77b4,stroke:#000,color:#fff;
classDef develop fill:#ff7f0e,stroke:#000,color:#fff;
classDef feature fill:#2ca02c,stroke:#000,color:#fff;
-
Main 分支(蓝色)
- 图中用蓝色表示;
- A0:最初的 Initial commit,作为项目的起点;
- B0:在 main 上进行的 Setup project structure,为项目搭建基础框架;
- Main 分支是项目的主干分支,最终所有功能都会被合并到这里。
-
Feature/config 分支开发(绿色)
- 图中绿色表示 feature 分支;
- 该分支用于开发配置功能模块;
-
开发流程:
- C1:添加 loadConfig 函数;
- C2:将 defaultConfig 提取到单独模块;
- C3:添加 watchConfig 和 saveConfig 功能
-
这些 commit 构成 feature/config 分支的开发历史。
-
Develop 分支(橙色)
- 图中橙色表示 develop 分支,用于整合开发中的 feature;
- D0:develop 分支起点,基于 main;
- D1:普通 merge(normal merge)将 feature/config 的所有 commit 合并到 develop;
- 在这里,feature/config 的开发历史被完整保留
-
Main 分支初始化
- E0:main 分支的初始化 commit;
- develop 分支的整合结果(D1)可以作为 main 的后续基础
-
Squash Merge feature/config 到 main(蓝色)
- F1:使用 squash merge 将 feature/config 合并到 main;
-
特点:
- 所有 feature/config 的 commit 压缩成一条 commit;
- 历史更简洁,便于维护;
- 提交信息为 refactor(electron): modularize main process and secure preload API
-
合并时,既保留 main 的历史,也引入 feature/config 的功能
-
Feature/ui 分支开发(绿色)
- 新增功能的分支,开发 UI 功能;
-
开发流程:
- G1:添加登录界面;
- G2:添加主题切换功能
-
完整开发历史在分支上可见。
-
Squash Merge feature/ui 到 main(蓝色)
- H1:使用 squash merge 将 feature/ui 合并到 main;
-
特点:
- 压缩为一条 commit;
- 提交信息为 feat(ui): login & theme UI
-
保持 main 历史简洁
总结¶
- 普通 merge(develop 分支合并 feature/config)保留所有 commit 历史,适合团队内部整合开发;
- Squash merge(feature 分支合并到 main)将多个 commit 压缩为一条 commit,保持主干整洁,适合发布和长期维护;
-
分支颜色清晰区分:
- 蓝色:主干(main)
- 橙色:整合分支(develop)
- 绿色:功能分支(feature)
Git 常用命令¶
Git 常用命令
| 命令 | 参数/选项 | 作用/说明 | 推荐使用场景 |
|---|---|---|---|
git --version |
查看 Git 安装版本 | 初次安装 Git 或排查版本问题 | |
which git |
查看 Git 可执行文件路径 | 确认系统使用的是哪个 Git,可用于多版本管理 | |
git config --global user.name "wangjiankun" |
--global |
设置全局用户名,写入 ~/.gitconfig |
第一次配置 Git 用户信息 |
git config --global user.email "wangjiankun@example.com" |
--global |
设置全局邮箱 | 第一次配置 Git 用户信息 |
git config --global core.editor "vim" |
--global |
设置全局编辑器,用于提交信息编辑 | 提交信息编辑时使用终端编辑器 |
git config --global core.editor "vim --nofork" |
--global |
设置 Vim 不 fork,防止 Git 提前执行后续命令 | GUI 编辑器或 Docker 环境中使用 |
git config --global color.ui auto |
--global |
启用 Git 彩色输出 | 增强可读性,推荐所有用户启用 |
git config --global init.defaultBranch main |
--global |
设置新建仓库默认分支为 main |
避免默认 master,新仓库初始化时使用 |
git config --global merge.conflictstyle diff3 |
--global |
合并冲突显示多一行共同祖先版本 | 处理复杂合并冲突时更清晰 |
git config --global core.autocrlf input |
--global |
自动换行处理(Linux/macOS 推荐 input,Windows 推荐 true) | 跨平台协作时防止行尾换行问题 |
git config --global --list |
--global |
查看全局配置列表 | 检查已设置的全局 Git 配置 |
git init |
初始化 Git 仓库,创建 .git/ |
新建项目或将现有目录变为 Git 仓库 | |
git config --local --list |
--local |
查看当前仓库的本地配置 | 检查仓库级配置,排查问题 |
git config --list |
查看所有配置(优先级:local > global > system) | 综合查看当前 Git 的配置环境 | |
git remote -v |
查看远程仓库地址(fetch/push) | 检查远程仓库是否正确配置 | |
git remote add origin <url> |
添加远程仓库地址,默认名称为 origin |
初始化仓库并关联远程仓库 | |
git branch |
查看本地分支,当前分支前有 * |
快速查看当前分支 | |
git branch -a |
查看所有分支(本地 + 远程) | 多分支项目中查看分支结构 | |
git status |
查看当前工作区状态(修改、新文件、暂存区) | 日常操作前检查修改和提交状态 | |
git log --oneline --graph --all |
查看提交历史,简洁图形化显示分支结构 | 快速了解项目提交历史和分支情况 | |
cat ~/.gitconfig |
查看用户全局配置文件内容 | 直接查看 .gitconfig 文件 |
|
git config --system --list |
查看系统级配置文件 /etc/gitconfig(某些系统不存在) |
系统管理员查看全局系统配置 | |
git config user.name "项目临时用户名" |
设置当前仓库的用户名,仅影响本仓库 | 在特定项目使用不同用户名时 | |
git config user.email "project@example.com" |
设置当前仓库邮箱,仅影响本仓库 | 在特定项目使用不同邮箱时 | |
env | grep GIT |
查看 Git 相关环境变量,用于调试 | 调试 Git 环境或 SSH 配置问题 |
-
初始化 Git 仓库并推送到 GitLab
经过下述一组操作,本地代码就会和远程 GitLab 仓库同步起来,后续可以方便地推送更新和拉取远程改动,这组命令的完整流程:
1). 初始化本地 Git 仓库;
2). 关联远程 GitLab 仓库;
3). 把当前目录所有文件添加到版本控制;
4). 创建首次提交;
5). 将本地提交推送到远程仓库的 main 分支并建立跟踪上述信息给出了两个 Git 重要的操作:
1). 全局配置
git init操作的分支名称git config --global init.defaultBranch <name>
2). 本库修改分支名称git branch -m <name>Note
GitLab 代码库的默认分支名称为 master
Failure
本地并没有名为 main 的分支,所以 Git 无法推送。大概率是因为:你当前分支的名字不是 main(可能还是 master 或其他名字)。
Git 保护机制
Failure
这个错误是 Git 保护机制:远程仓库的 main 分支已经有提交了,你本地的 main 分支没有同步这些提交,所以直接推送会被拒绝。
解决方法:合并远程提交(保留远程历史), 适用于远程上已有文件或别人提交过的情况。
Note
在 git pull --rebase origin main 里,--rebase 的意思是:
当你从远程分支(这里是 origin/main)拉取最新提交时,不用默认的 merge(合并提交)方式,而是用 rebase(变基)方式把你的本地提交“接到”最新远程提交之后。
Git 分支管理¶
Git 分支管理常用命令
| # | 命令 | 参数介绍 | 作用说明 |
|---|---|---|---|
| 1 | git branch -m <old> <new> |
-m:move,重命名分支 |
重命名本地分支 <old> 为 <new> |
| 2 | git push -u origin main |
-u:upstream,设置上游分支 |
推送本地分支到远程并设置上游跟踪关系 |
| 3 | git branch -u origin/<branch> <local-branch> |
-u:upstream,设置上游分支 |
设置本地分支 <local-branch> 跟踪远程分支 origin/<branch> |
| 4 | git branch |
无参数 | 列出本地分支 |
| 5 | git branch -a |
-a:all,列出所有分支 |
显示本地和远程所有分支 |
| 6 | git branch -vv |
-vv:verbose,显示详细信息 |
显示本地分支及其对应的远程跟踪分支和最后提交信息 |
| 7 | git fetch origin |
无参数 | 从远程获取最新的分支和提交 |
| 8 | git remote set-head origin -a |
-a:auto,自动设置HEAD指向 |
自动设置远程仓库 origin 的 HEAD 指向默认分支 |
| 9 | git checkout -b <branch> |
-b:branch,创建并切换分支 |
创建新分支 <branch> 并切换到该分支 |
| 10 | git branch -d <branch> |
-d:delete,删除分支 |
删除本地分支 <branch> |
| 11 | git branch -D <branch> |
-D:强制删除分支 |
强制删除本地分支 <branch>,无视未合并状态 |
| 12 | git push origin --delete <branch> |
--delete:删除远程分支 |
删除远程分支 <branch> |
| 13 | git merge <branch> |
无参数 | 将 <branch> 分支合并到当前分支 |
| 14 | git rebase <branch> |
无参数 | 将当前分支变基到 <branch> 上 |
Git 分支合并方式选择
上面 git pull 报错的原因是:
本地分支和远程分支出现了分歧(divergent branches),Git 不知道该用 merge、rebase 还是只接受 fast-forward 来合并
解决办法有几种:
-
如果想直接合并 (merge)
本地会产生一个新的合并提交:
或者设置默认:
-
如果你想保持直线历史 (rebase)
本地提交会“搬到”远程最新提交之后:
或者设置默认:
-
如果你只接受快进 (fast-forward only)
即如果有分歧就报错(不会产生 merge commit):
或者设置默认:
推荐做法:
- 如果是个人项目,建议
--rebase,历史更清晰; - 如果多人协作且不怕
merge commit,可以用默认merge; - 如果你希望保持绝对干净的历史,要求大家不乱提交,就用
--ff-only
检查分支的分歧情况
git fetch 与 git pull 的区别
git fetch 和 git pull 都是用来从远程仓库获取更新的命令,但它们的行为有显著的不同:
-
git fetch:
- 作用:git fetch 只是从远程仓库获取最新的提交(通常是通过拉取远程分支的更新),但 不会合并 到当前的本地分支;
- 执行流程:会把远程的变化下载到本地的远程跟踪分支(如 origin/main),但不会自动合并到当前的工作分支。你可以在确认更新后,手动进行合并(git merge)或重基(git rebase)操作;
- 典用场景:当你想先了解远程仓库的更新情况,避免直接合并到本地分支时使用。通常在执行 git pull 前使用 git fetch 来查看更新差异;
- 举例:
git fetch这只会从远程仓库拉取数据,并更新你本地的远程跟踪分支(比如 origin/main),但不会影响当前分支。
-
git pull:
- 作用:
git pull是一个更为高级的命令,它不仅会从远程仓库获取更新,而且会自动执行合并操作,默认使用git fetch拉取远程更新,然后 自动合并(默认是 merge,但也可以选择 rebase); - 执行流程:
git pull会先执行git fetch,获取远程更新,然后根据配置(merge 或 rebase)将远程更新合并到你当前的工作分支。如果有冲突,Git 会要求你手动解决; - 典用场景:当你希望快速同步远程仓库的变化,并自动合并到本地分支时使用;
- 举例:
git pull这会执行 git fetch 拉取远程更新,并自动尝试合并到当前分支。
- 作用:
总结:
git fetch只是拉取远程更新,但不合并;git pull是拉取并合并远程更新,是 fetch 和合并的组合命令;- 示例:假设远程仓库的 main 分支有更新:
git fetch只会更新本地的远程跟踪分支 origin/main,你可以使用git diff origin/main查看差异,或者用git merge origin/main手动合并; - git pull 会在拉取更新后,直接将 origin/main 的变更合并到你当前的分支;
- 你一般会先用
git fetch看看差异,确认没问题后再决定如何合并;如果不需要确认,直接使用 git pull 更高效
git pull 的三种合并方式 merge、rebase 和 fast-forward
git pull 时使用 merge、rebase 或 fast-forward,其主要区别在于如何将本地的提交与远程仓库的提交结合。目标是相同的 ———— 将远程的更新合并到本地,但它们的使用场景和操作历史的方式不同:
-
Fast-forward 合并 Fast-forward 合并 是 Git 中一种特定的合并方式,只有在没有分叉的情况下才能使用。它会直接把当前分支的指针移动到目标分支的最新提交,简化了历史记录。
什么是 Fast-forward 合并?Fast-forward 合并会在以下情况下发生:
- 目标分支没有新的提交;
- 源分支的提交是目标分支的直接后继;
- 当你在一个分支上进行开发,且主分支(或目标分支)没有其他提交时,Fast-forward 合并非常有效
- 如果目标分支有提交,就无法使用 Fast-forward 合并,需要进行普通的合并或重基(rebase)操作
换句话说,Fast-forward 合并发生在你当前分支的历史是直线型的,并且目标分支没有新的提交。
gitGraph commit id: "A" commit id: "B" commit id: "C" branch feature commit id: "E" commit id: "F" commit id: "G" checkout main commit id: "H" merge feature -
Merge(合并)
- 操作方式:merge 会将远程分支和本地分支的历史进行 合并,创建一个新的 合并提交;
- 历史保留:merge 保持了两个分支的提交历史,因此本地和远程的提交历史会像并行的两个线条一样合并。不会重写历史;
-
特点:
- 创建一个新的合并提交(merge commit),该提交表示两条历史的交汇点;
- 保留了完整的分支历史,适用于团队协作,尤其是分支开发的场景;
- 不改变现有提交的顺序,所有历史记录都能保留
-
缺点:
- 如果频繁使用 merge,提交历史可能会变得较为复杂,尤其是多个合并提交(merge commit)会使得历史记录显得杂乱;
-
命令:
git pull --no-rebase -
合并示例:
gitGraph commit id: "A" commit id: "B" commit id: "C" commit id: "D" branch feature commit id: "E" commit id: "F" commit id: "G"执行 git pull --no-rebase 后,会创建一个合并提交 H:
gitGraph commit id: "A" commit id: "B" commit id: "C" commit id: "D" branch feature commit id: "E" commit id: "F" commit id: "G" checkout main commit id: "H"
-
Rebase(重基)
- 操作方式:rebase 会将本地提交移到远程分支的末尾,即重写本地提交的历史。这就像把你在本地的提交搬移到远程分支的最新提交之后;
- 历史重写:使用 rebase 会重写本地的提交历史,让本地的提交像是直接在远程的最新提交后面发生的,没有任何合并提交。不保留合并历史,所有的提交会以线性的方式展示;
-
特点:
- 会创建一个清晰、线性的提交历史,让提交看起来像是按照时间顺序依次发生的;
- 适用于维护整洁、易读的提交历史;
- 不会留下合并提交(merge commit),所有提交都会直接按时间顺序排列
-
缺点:
- 如果你已经将本地提交推送到远程,使用 rebase 会改变历史记录,可能会导致问题。不建议在公开分支上使用 rebase;
- 如果在使用 rebase 时出现冲突,需要手动解决每个提交的冲突;
-
命令:
git pull --rebase -
重基示例:
执行 git pull --rebase 后,本地的 feature 分支会被“重放”在 main 的最新提交 D 后面:gitGraph commit id: "A" commit id: "B" commit id: "C" commit id: "D" branch feature commit id: "E" commit id: "F" commit id: "G"
(注意:E'、F'、G' 是 feature 分支的本地提交,重新应用过的版本。)gitGraph commit id: "A" commit id: "B" commit id: "C" commit id: "D" branch feature commit id: "E" commit id: "F" commit id: "G" checkout main commit id: "E'" commit id: "F'" commit id: "G'"
-
merge 与 rebase 的对比:
特性 Merge Rebase 提交历史 保留所有的历史记录,包括合并提交 会重写历史,形成一个线性的提交历史 合并提交 创建一个合并提交 不会创建合并提交 工作流 保持本地和远程的历史独立合并,适用于多人合作 提供干净、线性的历史记录,更适合个人开发 处理冲突 合并时一次性解决所有冲突 在每个提交上解决冲突,逐步重写历史 适用场景 团队协作开发,需要保留合并历史 个人开发,或希望历史记录简洁的团队 -
总结:
- 使用 merge 时,你会看到一个分支的交汇点,并且提交历史会保留合并提交。这通常适用于多人协作的项目;
- 使用 rebase 时,提交历史会变得更加简洁,呈现为一条直线,但它会重写本地提交的历史,可能会导致其他协作者的冲突,通常用于需要保持历史清晰的个人开发或者在小范围的协作中使用;
- 如果你希望 保持清晰的历史,而且你自己的提交还没有推送到远程,rebase 是个不错的选择。反之,如果你在与多人合作并希望保留每个提交的历史,使用 merge 更为合适
Git 分支重命名与远程同步指南¶
引言¶
本指南旨在详细解释一套将 Git 本地主分支从 master 更改为 main 并与远程仓库同步的命令流程。这通常是为了遵循行业中将默认分支命名为 main 的最佳实践。我们将逐一解析每个命令的作用、可能遇到的问题以及如何解决。
-
切换到本地主分支 (git checkout master)
- 命令解析:
git checkout master命令用于切换到名为 master 的本地分支; -
输出解析:
- Already on 'master':这表明您当前已经位于 master 分支上,无需进行切换;
- Your branch is up to date with 'origin/master'.:这表示您的本地 master 分支与远程仓库中的 origin/master 分支是同步的,没有任何需要拉取或推送的提交。
-
目的:在进行任何分支名称更改之前,确保您位于正确的分支上是至关重要的。
- 命令解析:
-
重命名本地分支 (git branch -m main)
- 命令解析:
git branch -m main用于将当前所在分支的名称从 master 重命名为 main; - 输出解析:该命令通常没有直接的输出,执行成功后,您的本地分支名称就会被更改;
- 目的:将本地分支的名称更新为新的、符合主流规范的名称。
- 命令解析:
-
删除远程旧分支 (git push origin --delete master)
-
命令解析:
git push origin --delete master命令用于将远程仓库中的 master 分支删除;--delete是一个快捷方式,等同于git push origin :master
-
输出解析:- [deleted] master 确认了远程的 master 分支已被成功删除;
- 目的:清除远程仓库中旧的、不再使用的分支,保持远程仓库的整洁
-
-
推送新分支并设置追踪 (git push -u origin main)
-
命令解析:
git push -u origin main旨在将本地重命名后的 main 分支推送到远程仓库,并设置追踪关系;- -u 参数(等同于 --set-upstream)会将本地的 main 分支关联到远程的 origin/main 分支
-
输出解析:! [rejected] main -> main (non-fast-forward) 这是一个非常重要的错误。它表明您的推送被拒绝了,因为远程仓库的 main 分支上存在您本地分支所没有的新提交。Git 拒绝直接覆盖远程分支,以防止丢失历史记录。
- 原因:在您执行这一系列命令的过程中,可能已经有其他人在远程 main 分支上提交了新的代码。因此,您的本地分支已经落后了。
-
-
拉取远程更改 (git pull origin main)
- 命令解析:
git pull origin main用于从远程仓库的 main 分支拉取最新的提交,并将其合并到您的本地 main 分支。 -
输出解析:
- Updating 530f653..227a4d6:显示了更新的提交范围;
- Fast-forward:这表示 Git 进行了“快进”合并。这意味着远程分支是您本地分支的直接后继,Git 只需要简单地移动指针即可,没有发生任何冲突。
-
目的:这是解决推送被拒错误的必要步骤。它确保您的本地分支包含了远程仓库的所有最新更改。
- 命令解析:
-
再次推送 (git push -u origin main)
- 命令解析:在您成功拉取并合并远程更改后,再次运行
git push -u origin main。 -
输出解析:
- branch 'main' set up to track 'origin/main'.:确认了本地 main 分支和远程 origin/main 分支之间的追踪关系已经成功建立;
- Everything up-to-date:这表明您的本地分支与远程分支完全同步,没有新的提交需要推送。
-
目的:完成将本地更改推送到远程,并建立永久的追踪关系,以便您将来可以只用
git pull或git push命令。
- 命令解析:在您成功拉取并合并远程更改后,再次运行
-
验证分支状态 (git branch -a)
- 命令解析:
git branch -a用于查看本地和远程的所有分支。 -
输出解析:
-
- main:星号 (*) 表示您当前位于 main 本地分支;
- remotes/origin/HEAD -> origin/main:HEAD 是远程仓库的默认分支指针。它指向了 origin/main,再次确认 main 是远程仓库的主分支。
- remotes/origin/main:列出了远程仓库的 main 分支。
-
-
目的:通过这个命令,您可以最终确认所有操作都已成功完成,本地和远程分支的名称和追踪关系都已正确设置。
- 命令解析:
Git 压缩合并 git merge --squash¶
git merge 与 git merge --squash 对比:
| 特性 | git merge |
git merge --squash |
|---|---|---|
| 提交历史 | 保留目标分支的所有 commit | 压缩成 1 个 commit |
| 是否自动生成 merge commit | 是 | 否,需要手动 git commit |
| 历史可读性 | 较详细,可能冗余 | 简洁干净 |
| 适用场景 | 需要完整保留开发过程时 | 只想保留最终结果、保持主分支整洁时 |
| 回溯 debug | 易于定位到具体 commit | 只能看到合并后的整体提交 |
-
git merge- 用于将一个分支的提交历史合并到当前分支;
- 如果目标分支有多个提交,这些提交会 完整保留 在当前分支中
- 特点:
- 保留分支的详细提交历史。
- 历史记录较长,可能包含琐碎的 commit。
-
git merge --squash- 会把目标分支上的所有更改 压缩成一个修改集合,然后等待你写一个新的提交;
- 执行后,Git 不会自动生成 merge commit,而是把改动放在 暂存区 (staging area),需要你手动
git commit - 使用示例: 这样,feature/config 分支上的多个 commit 会被合并成 一条干净的提交
-
总结
- 使用
git merge→ 保留所有细粒度 commit,适合团队内部开发分支; - 使用
git merge --squash→ 压缩成单一 commit,适合合并到 main 或 release 分支,保持历史简洁
- 使用
GitLab¶
增加导航条¶
为 GitLab 增加如下导航条:
- 文档中心
-
备份原文件
-
增加代码
- HAML(.haml) 文件:: HTML Abstraction Markup Language;
- 一种用于编写 HTML 的简洁标记语言,简化 HTML 的编写。它用缩进表示层级结构,省略了很多 HTML 的冗余标签,使得代码更简洁、更易读;
- 特点:用缩进和简洁的语法代替繁琐的 HTML 标签结构,常见于 Ruby on Rails 项目中;
- 简单来说,HAML 是 HTML 的一种缩写语法,常用于 Ruby on Rails 项目中,帮助开发者用更少的代码写出结构清晰的网页模板;
- 运行方式:HAML 不能直接在浏览器中渲染,需要先通过 HAML 编译器转换成 HTML
完整的 _top_bar.html.haml 文件为:
Warning
_top_bar.html.haml 这个文件对格式要求比较高,尽量不做大的改动!
-
重启整个 GitLab