跳转至

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;
  1. Main 分支(蓝色)

    • 图中用蓝色表示;
    • A0:最初的 Initial commit,作为项目的起点;
    • B0:在 main 上进行的 Setup project structure,为项目搭建基础框架;
    • Main 分支是项目的主干分支,最终所有功能都会被合并到这里。
  2. Feature/config 分支开发(绿色)

    • 图中绿色表示 feature 分支;
    • 该分支用于开发配置功能模块;
    • 开发流程:

      • C1:添加 loadConfig 函数;
      • C2:将 defaultConfig 提取到单独模块;
      • C3:添加 watchConfig 和 saveConfig 功能
    • 这些 commit 构成 feature/config 分支的开发历史。

  3. Develop 分支(橙色)

    • 图中橙色表示 develop 分支,用于整合开发中的 feature;
    • D0:develop 分支起点,基于 main;
    • D1:普通 merge(normal merge)将 feature/config 的所有 commit 合并到 develop;
    • 在这里,feature/config 的开发历史被完整保留
  4. Main 分支初始化

    • E0:main 分支的初始化 commit;
    • develop 分支的整合结果(D1)可以作为 main 的后续基础
  5. 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 的功能

  6. Feature/ui 分支开发(绿色)

    • 新增功能的分支,开发 UI 功能;
    • 开发流程:

      • G1:添加登录界面;
      • G2:添加主题切换功能
    • 完整开发历史在分支上可见。

  7. 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 配置问题
  1. 初始化 Git 仓库并推送到 GitLab

    经过下述一组操作,本地代码就会和远程 GitLab 仓库同步起来,后续可以方便地推送更新和拉取远程改动,这组命令的完整流程:
    1). 初始化本地 Git 仓库;
    2). 关联远程 GitLab 仓库;
    3). 把当前目录所有文件添加到版本控制;
    4). 创建首次提交;
    5). 将本地提交推送到远程仓库的 main 分支并建立跟踪

    # 初始化一个新的 Git 仓库
    # 在当前目录创建一个隐藏的 .git 文件夹,这个文件夹包含所有 Git 用来跟踪版本历史的元数据和对象
    # 这一步是将一个普通目录变成 Git 可管理的仓库的第一步
    # 使用场景:在你刚开始一个项目,或者想用 Git 来管理一个现有项目时执行。
    $ git init
    hint: Using 'master' as the name for the initial branch. This default branch name
    hint: is subject to change. To configure the initial branch name to use in all
    hint: of your new repositories, which will suppress this warning, call:
    hint: 
    hint:   git config --global init.defaultBranch <name>
    hint: 
    hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
    hint: 'development'. The just-created branch can be renamed via this command:
    hint: 
    hint:   git branch -m <name>
    Initialized empty Git repository in /home/wangjiankun/scripts/.git/
    $
    

    上述信息给出了两个 Git 重要的操作:

    1). 全局配置 git init 操作的分支名称 git config --global init.defaultBranch <name>
    2). 本库修改分支名称 git branch -m <name>

    Note

    GitLab 代码库的默认分支名称为 master

    1
    2
    3
    4
    5
    6
    # 给本地仓库添加一个远程仓库,名字叫 origin,地址是你指定的 GitLab 仓库 URL
    # remote 是 Git 用来管理远程仓库的命令
    # add 表示添加一个新的远程仓库
    # origin 是远程仓库的默认名字(当然你也可以叫别的名字,但一般都用 origin), 后面跟着远程仓库的地址(HTTP 或 SSH URL)
    # 使用场景:本地仓库初始化后,想关联一个远程仓库以便推送或拉取代码
    $ git remote add origin https://gitlab.example.com/yourname/gitlab-usage-doc.git
    
    1
    2
    3
    4
    5
    # 把当前目录下所有文件(包括新建、修改的文件)添加到 Git 暂存区(Stage area)
    # . 表示当前目录及子目录的所有文件
    # 只有被添加到暂存区的文件,才能被提交(commit)
    # 使用场景:修改或新增文件后,准备把这些改动提交到版本库时执行
    $ git add .
    
    1
    2
    3
    4
    5
    # 把暂存区的文件打包成一个新的提交(commit),并附加提交说明
    # -m "init mkdocs" 指定提交说明(message),这里的说明是 "init mkdocs"
    # 提交是 Git 版本控制的基本单位,代表项目的一次快照
    # 使用场景:你确认暂存区内容没问题,准备记录项目历史时执行
    $ git commit -m "init mkdocs"
    
    # 把本地 main 分支的提交推送到远程仓库 origin 的同名分支,并设置上游分支
    # push 是上传本地代码到远程仓库
    # -u(或 --set-upstream)选项表示设置本地 main 分支与远程 origin/main 分支的跟踪关系
    # 后续只需用 git push 或 git pull 即可自动对应
    # origin 是远程仓库名
    # main 是你推送的分支名(现代 Git 默认分支名通常是 main,老项目可能是 master)
    # 使用场景:初始化仓库后,将首次提交推送到远程服务器,确保远程仓库有最新代码
    $ git push -u origin main
        error: src refspec main does not match any
        error: failed to push some refs to 'https://gitlab.oprting.com/plat-admin/debian-scripts.git'
    

    Failure

    本地并没有名为 main 的分支,所以 Git 无法推送。大概率是因为:你当前分支的名字不是 main(可能还是 master 或其他名字)。

    1
    2
    3
    4
    5
    6
    7
    8
    $ git branch                            # 查看当前分支
    * master
    $ git branch -m master main             # 把 master 改名为 main
    $ git add .
    $ git commit -m "init"
    On branch main
    nothing to commit, working tree clean
    $ git push -u origin main
    

    Git 保护机制

    Failure

    这个错误是 Git 保护机制:远程仓库的 main 分支已经有提交了,你本地的 main 分支没有同步这些提交,所以直接推送会被拒绝。

    $ git push -u origin main
    To https://gitlab.oprting.com/plat-admin/debian-scripts.git
    ! [rejected]        main -> main (fetch first)
    error: failed to push some refs to 'https://gitlab.oprting.com/plat-admin/debian-scripts.git'
    hint: Updates were rejected because the remote contains work that you do
    hint: not have locally. This is usually caused by another repository pushing
    hint: to the same ref. You may want to first integrate the remote changes
    hint: (e.g., 'git pull ...') before pushing again.
    hint: See the 'Note about fast-forwards' in 'git push --help' for details.
    $
    

    解决方法:合并远程提交(保留远程历史), 适用于远程上已有文件或别人提交过的情况。

    $ git pull --rebase origin main     # 拉取远程 main 分支
    $ git push -u origin main
    

    Note

    在 git pull --rebase origin main 里,--rebase 的意思是:
    当你从远程分支(这里是 origin/main)拉取最新提交时,不用默认的 merge(合并提交)方式,而是用 rebase(变基)方式把你的本地提交“接到”最新远程提交之后

    $ git pull --rebase origin main
    remote: Enumerating objects: 9, done.
    remote: Counting objects: 100% (6/6), done.
    remote: Compressing objects: 100% (5/5), done.
    remote: Total 9 (delta 1), reused 0 (delta 0), pack-reused 3 (from 1)
    Unpacking objects: 100% (9/9), 3.85 KiB | 1.93 MiB/s, done.
    From https://gitlab.oprting.com/plat-admin/debian-scripts
    * branch            main       -> FETCH_HEAD
    * [new branch]      main       -> origin/main
    Successfully rebased and updated refs/heads/main.
    $
    
    $ git push -u origin main
    Enumerating objects: 4, done.
    Counting objects: 100% (4/4), done.
    Delta compression using up to 4 threads
    Compressing objects: 100% (3/3), done.
    Writing objects: 100% (3/3), 1.66 KiB | 1.66 MiB/s, done.
    Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
    To https://gitlab.oprting.com/plat-admin/debian-scripts.git
    55bb518..d3076b2  main -> main
    branch 'main' set up to track 'origin/main'.
    $
    

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
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint: 
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint: 
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal: Need to specify how to reconcile divergent branches.
$ 

上面 git pull 报错的原因是:
本地分支和远程分支出现了分歧(divergent branches),Git 不知道该用 merge、rebase 还是只接受 fast-forward 来合并

解决办法有几种:

  1. 如果想直接合并 (merge)

    本地会产生一个新的合并提交:

    $ git pull --no-rebase
    

    或者设置默认:

    $ git config pull.rebase false       # 当前仓库
    $ git config --global pull.rebase false   # 全局
    
  2. 如果你想保持直线历史 (rebase)

    本地提交会“搬到”远程最新提交之后:

    $ git pull --rebase
    

    或者设置默认:

    $ git config pull.rebase true            # 当前仓库
    $ git config --global pull.rebase true   # 全局
    

  3. 如果你只接受快进 (fast-forward only)

    即如果有分歧就报错(不会产生 merge commit):

    $ git pull --ff-only
    

    或者设置默认:

    $ git config pull.ff only
    

推荐做法:

  • 如果是个人项目,建议 --rebase,历史更清晰;
  • 如果多人协作且不怕 merge commit,可以用默认 merge;
  • 如果你希望保持绝对干净的历史,要求大家不乱提交,就用 --ff-only

检查分支的分歧情况

$ git fetch
$ git log --oneline --graph --all
这个命令会显示出所有分支的提交历史,帮助你更好地理解分歧的原因

git fetchgit pull 的区别
git fetch 和 git pull 都是用来从远程仓库获取更新的命令,但它们的行为有显著的不同:

  1. git fetch:

    • 作用:git fetch 只是从远程仓库获取最新的提交(通常是通过拉取远程分支的更新),但 不会合并 到当前的本地分支;
    • 执行流程:会把远程的变化下载到本地的远程跟踪分支(如 origin/main),但不会自动合并到当前的工作分支。你可以在确认更新后,手动进行合并(git merge)或重基(git rebase)操作;
    • 典用场景:当你想先了解远程仓库的更新情况,避免直接合并到本地分支时使用。通常在执行 git pull 前使用 git fetch 来查看更新差异;
    • 举例:git fetch 这只会从远程仓库拉取数据,并更新你本地的远程跟踪分支(比如 origin/main),但不会影响当前分支。
  2. 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,其主要区别在于如何将本地的提交与远程仓库的提交结合。目标是相同的 ———— 将远程的更新合并到本地,但它们的使用场景和操作历史的方式不同:

  1. 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
  2. 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"
  3. Rebase(重基)

    • 操作方式:rebase 会将本地提交移到远程分支的末尾,即重写本地提交的历史。这就像把你在本地的提交搬移到远程分支的最新提交之后;
    • 历史重写:使用 rebase 会重写本地的提交历史,让本地的提交像是直接在远程的最新提交后面发生的,没有任何合并提交。不保留合并历史,所有的提交会以线性的方式展示;
    • 特点:

      • 会创建一个清晰、线性的提交历史,让提交看起来像是按照时间顺序依次发生的;
      • 适用于维护整洁、易读的提交历史;
      • 不会留下合并提交(merge commit),所有提交都会直接按时间顺序排列
    • 缺点:

      • 如果你已经将本地提交推送到远程,使用 rebase 会改变历史记录,可能会导致问题。不建议在公开分支上使用 rebase;
      • 如果在使用 rebase 时出现冲突,需要手动解决每个提交的冲突;
    • 命令:

      git pull --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 --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"
          checkout main
          commit id: "E'" 
          commit id: "F'" 
          commit id: "G'"
      (注意:E'、F'、G' 是 feature 分支的本地提交,重新应用过的版本。)

  4. merge 与 rebase 的对比:

    特性 Merge Rebase
    提交历史 保留所有的历史记录,包括合并提交 会重写历史,形成一个线性的提交历史
    合并提交 创建一个合并提交 不会创建合并提交
    工作流 保持本地和远程的历史独立合并,适用于多人合作 提供干净、线性的历史记录,更适合个人开发
    处理冲突 合并时一次性解决所有冲突 在每个提交上解决冲突,逐步重写历史
    适用场景 团队协作开发,需要保留合并历史 个人开发,或希望历史记录简洁的团队
  5. 总结:

    • 使用 merge 时,你会看到一个分支的交汇点,并且提交历史会保留合并提交。这通常适用于多人协作的项目;
    • 使用 rebase 时,提交历史会变得更加简洁,呈现为一条直线,但它会重写本地提交的历史,可能会导致其他协作者的冲突,通常用于需要保持历史清晰的个人开发或者在小范围的协作中使用;
    • 如果你希望 保持清晰的历史,而且你自己的提交还没有推送到远程,rebase 是个不错的选择。反之,如果你在与多人合作并希望保留每个提交的历史,使用 merge 更为合适

Git 分支重命名与远程同步指南

引言

本指南旨在详细解释一套将 Git 本地主分支从 master 更改为 main 并与远程仓库同步的命令流程。这通常是为了遵循行业中将默认分支命名为 main 的最佳实践。我们将逐一解析每个命令的作用、可能遇到的问题以及如何解决。

  1. 切换到本地主分支 (git checkout master)

    1
    2
    3
    $ git checkout master
    Already on 'master'
    Your branch is up to date with 'origin/master'.
    
    • 命令解析: git checkout master 命令用于切换到名为 master 的本地分支;
    • 输出解析:

      • Already on 'master':这表明您当前已经位于 master 分支上,无需进行切换;
      • Your branch is up to date with 'origin/master'.:这表示您的本地 master 分支与远程仓库中的 origin/master 分支是同步的,没有任何需要拉取或推送的提交。
    • 目的:在进行任何分支名称更改之前,确保您位于正确的分支上是至关重要的

  2. 重命名本地分支 (git branch -m main)

    $ git branch -m main
    
    • 命令解析:git branch -m main 用于将当前所在分支的名称从 master 重命名为 main;
    • 输出解析:该命令通常没有直接的输出,执行成功后,您的本地分支名称就会被更改;
    • 目的:将本地分支的名称更新为新的、符合主流规范的名称。
  3. 删除远程旧分支 (git push origin --delete master)

    1
    2
    3
    $ git push origin --delete master
     To gitlab.oprting.com:dev/finai_app.git
     - [deleted]           master
    
    • 命令解析:

      • git push origin --delete master 命令用于将远程仓库中的 master 分支删除;
      • --delete 是一个快捷方式,等同于 git push origin :master
    • 输出解析:- [deleted] master 确认了远程的 master 分支已被成功删除;

    • 目的:清除远程仓库中旧的、不再使用的分支,保持远程仓库的整洁
  4. 推送新分支并设置追踪 (git push -u origin main)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    $ git push -u origin main
    To gitlab.oprting.com:dev/finai_app.git
    ! [rejected]        main -> main (non-fast-forward)
    error: failed to push some refs to 'gitlab.oprting.com:dev/finai_app.git'
    hint: Updates were rejected because the tip of your current branch is behind
    hint: its remote counterpart. If you want to integrate the remote changes,
    hint: use 'git pull' before pushing again.
    hint: See the 'Note about fast-forwards' in 'git push --help' for details.
    $
    
    • 命令解析:

      • git push -u origin main 旨在将本地重命名后的 main 分支推送到远程仓库,并设置追踪关系;
      • -u 参数(等同于 --set-upstream)会将本地的 main 分支关联到远程的 origin/main 分支
    • 输出解析:! [rejected] main -> main (non-fast-forward) 这是一个非常重要的错误。它表明您的推送被拒绝了,因为远程仓库的 main 分支上存在您本地分支所没有的新提交。Git 拒绝直接覆盖远程分支,以防止丢失历史记录。

    • 原因:在您执行这一系列命令的过程中,可能已经有其他人在远程 main 分支上提交了新的代码。因此,您的本地分支已经落后了。
  5. 拉取远程更改 (git pull origin main)

    1
    2
    3
    4
    5
    $ git pull origin main
    From gitlab.oprting.com:dev/finai_app
    * branch              main       -> FETCH_HEAD
    Updating 530f653..227a4d6
    Fast-forward
    
    • 命令解析:git pull origin main 用于从远程仓库的 main 分支拉取最新的提交,并将其合并到您的本地 main 分支。
    • 输出解析:

      • Updating 530f653..227a4d6:显示了更新的提交范围;
      • Fast-forward:这表示 Git 进行了“快进”合并。这意味着远程分支是您本地分支的直接后继,Git 只需要简单地移动指针即可,没有发生任何冲突。
    • 目的:这是解决推送被拒错误的必要步骤。它确保您的本地分支包含了远程仓库的所有最新更改。

  6. 再次推送 (git push -u origin main)

    1
    2
    3
    $ git push -u origin main
    branch 'main' set up to track 'origin/main'.
    Everything up-to-date
    
    • 命令解析:在您成功拉取并合并远程更改后,再次运行 git push -u origin main
    • 输出解析:

      • branch 'main' set up to track 'origin/main'.:确认了本地 main 分支和远程 origin/main 分支之间的追踪关系已经成功建立;
      • Everything up-to-date:这表明您的本地分支与远程分支完全同步,没有新的提交需要推送。
    • 目的:完成将本地更改推送到远程,并建立永久的追踪关系,以便您将来可以只用 git pullgit push 命令。

  7. 验证分支状态 (git branch -a)

    1
    2
    3
    4
    $ git branch -a
    * main
    remotes/origin/HEAD -> origin/main
    remotes/origin/main
    
    • 命令解析:git branch -a 用于查看本地和远程的所有分支。
    • 输出解析:

        • main:星号 (*) 表示您当前位于 main 本地分支;
      • remotes/origin/HEAD -> origin/main:HEAD 是远程仓库的默认分支指针。它指向了 origin/main,再次确认 main 是远程仓库的主分支。
      • remotes/origin/main:列出了远程仓库的 main 分支。
    • 目的:通过这个命令,您可以最终确认所有操作都已成功完成,本地和远程分支的名称和追踪关系都已正确设置。

Git 压缩合并 git merge --squash

git mergegit merge --squash 对比:

特性 git merge git merge --squash
提交历史 保留目标分支的所有 commit 压缩成 1 个 commit
是否自动生成 merge commit 否,需要手动 git commit
历史可读性 较详细,可能冗余 简洁干净
适用场景 需要完整保留开发过程时 只想保留最终结果、保持主分支整洁时
回溯 debug 易于定位到具体 commit 只能看到合并后的整体提交
  1. git merge

    • 用于将一个分支的提交历史合并到当前分支;
    • 如果目标分支有多个提交,这些提交会 完整保留 在当前分支中
    • 特点:
      • 保留分支的详细提交历史。
      • 历史记录较长,可能包含琐碎的 commit。

  1. git merge --squash

    • 会把目标分支上的所有更改 压缩成一个修改集合,然后等待你写一个新的提交;
    • 执行后,Git 不会自动生成 merge commit,而是把改动放在 暂存区 (staging area),需要你手动 git commit
    • 使用示例:
      1
      2
      3
      4
      5
      git checkout main                   # 切换到 main 分支    
      git merge --squash feature/config   # 压缩合并 feature/config 的改动
      
      # 现在改动已暂存,手动写一个新的 commit message
      git commit -m "refactor(electron): modularize main process and secure preload API"
      
      这样,feature/config 分支上的多个 commit 会被合并成 一条干净的提交
  2. 总结

    • 使用 git merge → 保留所有细粒度 commit,适合团队内部开发分支;
    • 使用 git merge --squash → 压缩成单一 commit,适合合并到 main 或 release 分支,保持历史简洁

GitLab

增加导航条

为 GitLab 增加如下导航条:

  • 文档中心
  • Workflow

  • 备份原文件

    $ cd /opt/gitlab/embedded/service/gitlab-rails/app/views/layouts/nav/
    $ sudo cp _top_bar.html.haml _top_bar.html.haml.bak
    
  • 增加代码

    • HAML(.haml) 文件:: HTML Abstraction Markup Language;
    • 一种用于编写 HTML 的简洁标记语言,简化 HTML 的编写。它用缩进表示层级结构,省略了很多 HTML 的冗余标签,使得代码更简洁、更易读;
    • 特点:用缩进和简洁的语法代替繁琐的 HTML 标签结构,常见于 Ruby on Rails 项目中;
    • 简单来说,HAML 是 HTML 的一种缩写语法,常用于 Ruby on Rails 项目中,帮助开发者用更少的代码写出结构清晰的网页模板;
    • 运行方式:HAML 不能直接在浏览器中渲染,需要先通过 HAML 编译器转换成 HTML
    = link_to "文档中心", "https://docs-351763.pages.oprting.com/", target: "_blank", class: "gl-link gl-mr-4"
    = link_to "Workflow", "https://pm.oprting.com/", target: "_blank", class: "gl-link gl-mr-4"
    

    完整的 _top_bar.html.haml 文件为:

    $ sudo cat _top_bar.html.haml
    -# 定义变量 duo_button_enabled,它检查一个名为 ask_duo_button 的局部模板文件是否存在
    -# 并且 GitLab 的 AI 助手 TanukiBot 是否已为当前用户和上下文(项目或群组)启用
    - duo_button_enabled = (partial_exists? "layouts/nav/ask_duo_button") && ::Gitlab::Llm::TanukiBot.show_breadcrumbs_entry_point?(user: current_user, container: @group || @project)
    
    -# 创建主容器 div,用于整个顶部导航栏
    -# 它有 top-bar-fixed 和 container-fluid 等 CSS 类,并包含一个用于测试的 data 属性。
    %div{ class: 'top-bar-fixed container-fluid', data: { testid: 'top-bar' } }
    .top-bar-container.gl-flex.gl-items-center.gl-gap-2{ class: ("gl-group top-bar-duo-button-present" if duo_button_enabled) }
        .gl-grow.gl-basis-0.gl-flex.gl-items-center.gl-justify-start.gl-gap-3
        = render Pajamas::ButtonComponent.new(icon: 'sidebar', category: :tertiary, button_options: { class: 'js-super-sidebar-toggle-expand super-sidebar-toggle -gl-ml-3', aria: { controls: 'super-sidebar', expanded: 'false', label: _('Primary navigation sidebar') } })
        = render "layouts/nav/breadcrumbs/breadcrumbs"
    
        -# 定义一个导航 (nav) 区域,里面包含两个链接:
        -# 一个指向 “文档中心” 的链接,URL 为 https://docs-351763.pages.oprting.com/
        -# 一个指向 “Workflow” 的链接,URL 为 https://pm.oprting.com/
        -# 这两个链接都设置了 target: "_blank",这意味着它们会在新标签页中打开
        = link_to "文档中心", "https://docs-351763.pages.oprting.com/", target: "_blank", class: "gl-link gl-mr-4"
        = link_to "Workflow", "https://pm.oprting.com/", target: "_blank", class: "gl-link gl-mr-4"
    
        -# 条件判断:如果 duo_button_enabled 变量为真,则渲染一个名为 ask_duo_button 的局部模板,这个模板很可能就是 AI 助手的按钮
        - if duo_button_enabled
        .gl-flex-none.gl-flex.gl-items-center.gl-justify-center.gl-gap-3
            = render "layouts/nav/ask_duo_button"
    $
    

    Warning

    _top_bar.html.haml 这个文件对格式要求比较高,尽量不做大的改动!

  • 重启整个 GitLab

    sudo gitlab-ctl restart