Git代码托管与版本管理
安装
官网下载安装即可,安装配置基本默认。
常用命令
| 命令 | 描述 |
|---|---|
git config --global user.name 用户名 |
设置用户签名 |
git config --global user.email 邮箱 |
设置用户签名 |
git init |
初始化本地库 |
git status |
查看本地库状态 |
git add 文件名 |
添加到暂存区 |
git commit -m "日志信息" 文件名 |
提交到本地库 |
git reflog / git log |
查看历史记录 |
git reset --hard 版本号 |
版本穿梭 |
基本操作
设置用户签名
|
|
git config --global 命令的作用范围是针对 该设备上所有 Git 仓库 的全局配置。
所以只要配置一次就好了。
要查看当前的 Git 全局配置,可以使用以下命令:
|
|
查看特定配置项
如果你只想查看某个特定的全局配置项,可以使用以下命令:
|
|
例如:
|
|
这将只显示全局配置中的用户名。
初始化本地库
|
|
在对应项目文件夹目录下创建Git仓库,总的来说会执行2个动作:
- 创建名为
.git的子目录,含有初始化Git仓库中所有的必须文件,这些文件是Git仓库的骨干,但是项目里的文件还没有被跟踪; - 一个没有任何commit(提交记录)的初始分支,这一分支默认名称为
master。
这里有一个很逗的点,在初始化完有概率遇到一条warning:大意是说默认分支叫master,你可以 git branch -m old-name new-name改为新main。
为什么会有这条莫名其妙的警告呢,因为master/slave主从分支在政治上是不正确的,所以现在很多git托管网站都是用main做默认分支名。
查看本地状态
|
|
git status 命令用于显示当前 Git 仓库的状态。它会告诉你哪些文件被修改了、哪些文件被添加到暂存区(staging area)、哪些文件未被跟踪等信息。
以下是 git status 可能显示的一些关键信息:
- 当前分支:
- 显示你当前所在的分支名称。
- 本地更改:
- 未跟踪的文件:显示仓库中尚未添加到暂存区的新文件。
- 修改过的文件:显示自上次提交以来已被修改的文件。
- 暂存区更改:
- 已暂存的更改:显示已被添加到暂存区的文件,这些更改将在下一次提交时被包含。
- 已暂存但修改过的文件:显示已暂存但自暂存后又被修改的文件。
- 冲突:
- 如果你在合并或拉取时遇到冲突,
git status会显示这些冲突文件,提示你需要手动解决这些冲突。
- 如果你在合并或拉取时遇到冲突,
- 分支状态:
- 如果你的分支与远程分支有差异,
git status会显示这些差异,例如本地分支领先、落后或与远程分支同步。
- 如果你的分支与远程分支有差异,
- 未暂存的更改:
- 显示自上次提交以来未被添加到暂存区的文件更改。
- 提示信息:
- 根据当前状态,
git status可能会提供一些有用的提示信息,例如如何添加文件到暂存区或如何提交更改。
- 根据当前状态,
例如:
干净的工作区(无任何修改)
|
|
同时存在已暂存、未暂存和未跟踪的文件
|
|
添加到暂存区
|
|
git add 是一个 Git 命令,用于将更改添加到暂存区(staging area),这是提交(commit)更改到本地仓库之前的一个必备步骤。它允许你精确控制哪些更改应该包含在下一次提交中。
暂存区是一个文件,保存了下次将提交到本地仓库的更改列表。
-
添加单个文件:
1git add <文件名>这会将指定文件的更改添加到暂存区。
-
添加多个文件:
1git add <文件1> <文件2> ...你可以一次性添加多个文件到暂存区。
-
添加所有更改:
1git add .或者
1git add -A这会将所有新的、修改的和删除的文件(不包括未跟踪的文件)添加到暂存区。
提交到本地库
git commit 用于将暂存区(staging area)的更改提交(commit)到本地仓库。提交是版本控制中保存项目历史记录的基本单元。
|
|
这将提交暂存区的更改,并使用提供的提交信息。-m 选项允许你在命令行中直接添加提交信息,而不需要打开文本编辑器。
查看历史记录
git reflog 和 git log 都是 Git 中用于查看项目历史记录的命令,但它们的用途和显示的信息有所不同。
git reflog
git reflog 命令显示了所有引用(包括分支和标签)的更新历史。它记录了HEAD和分支引用的每一次移动,无论这些移动是否由提交引起。
git reflog 可以显示由于各种操作(如提交、回退、创建分支、切换分支等)引起的引用变化。
|
|
这将显示一个按时间排序的列表,列出了HEAD和分支引用的每一次更新。
git log
git log 命令显示了提交历史,包括每次提交的作者、日期、提交信息等详细信息。它主要用于查看项目的提交历史。
|
|
默认会进入分页器(less),按 q 退出;Space 下翻页,b 上翻页。
若不希望分页,使用:git --no-pager log。
这将显示项目的提交历史,包括每次提交的哈希值、作者、日期和提交信息。并且git log还支持多种格式:可以通过选项自定义输出格式,如简洁格式、一行列格式等,并且支持过滤:可以通过选项过滤特定的提交,如按作者、日期、路径等过滤。
常用选项
-
--oneline:以一行列格式显示提交信息,只显示哈希值和提交信息。 -
查看简洁的提交历史:
1git log --oneline -
--graph:显示分支合并图。 -
查看带有分支合并图的提交历史:
1git log --graph --oneline -
--since和--until:按时间过滤提交。 -
--author:按作者过滤提交。 -
--grep:搜索提交信息中的关键词。 -
搜索特定作者的提交:
1git log --author="用户名" -
查看特定时间段内的提交:
1git log --since="2024-01-01" --until="2024-12-31"
版本穿梭
|
|
上述命令用于将当前分支和工作目录重置到指定的版本号,即某个特定的提交(commit)。这个命令会改变当前分支的 HEAD 指针,并且会重置工作目录和暂存区,使其与指定的提交完全一致。注意,这意味着所有在该提交之后所做的更改都将丢失,包括未提交的更改和暂存的更改,这是不可逆的。
你需要找到你想要回退到的版本号,可以通过 git log 命令查看提交历史,找到对应的提交哈希值。
忽略文件
有些文件是不需要(不应该)加入版本控制的,例如编译的临时文件、日志文件。通过创建 .gitignore 文件来配置要忽略的文件模式。
文件 .gitignore 的格式规范如下:
- 所有空行或者以 # 开头的行都会被 Git 忽略
- 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中
- 匹配模式可以以 / 开头防止递归
- 匹配模式可以以 / 结尾指定目录
- 要忽略指定模式以外的文件或目录,可以在模式前加上叹号 ! 取反
|
|
分支操作
分支的好处
- 同时并进行多个功能开发,提高了开发效率
- 各个分支再开发过程中,如果某个分支开发失败,不会对其他分支有任何影响,失败的分支删除重新开始即可
分支常用命令
| 命令 | 描述 |
|---|---|
git branch 分支名 |
创建分支 |
git branch -v |
查看分支 |
git checkout 分支名 |
切换分支 |
git merge 需要合并的分支名 |
把指定的分支合并到当前分支上 |
查看分支
|
|
git branch -v 命令用于列出 Git 仓库中的所有分支,并显示每个分支的最新提交信息。这个命令是 git branch 命令的一个变体,其中的 -v 选项代表“verbose”,即详细模式。
创建分支
|
|
git branch 分支名 是一个用于创建新分支的 Git 命令。当你想要从当前开发线(通常是主分支)创建一个新的开发线时,这个命令非常有用。
这将在当前 HEAD 指向的提交处创建一个新分支,但不会自动切换到该分支。
切换分支
|
|
这将切换到指定的分支,并更新工作目录以反映该分支的状态。
也可以使用较新的命令:
git switch 分支名,专用于分支切换。
重命名分支
如果你当前就在要重命名的分支上,可以使用:
|
|
例如,将当前分支 old-name 重命名为 new-name(假设你已在 old-name 分支):
|
|
如果你不在要重命名的分支上,可以指定原分支名和新分支名:
|
|
例如:
|
|
注意事项:
-
-m是--move的缩写,表示移动(重命名)分支。 -
如果你已经将旧分支推送到远程仓库,重命名本地分支后,还需要更新远程分支:
1 2 3 4 5# 删除远程旧分支 git push origin --delete old-name # 推送新分支并设置上游 git push origin -u new-name -
重命名分支不会影响提交历史,只是更改了分支的引用名称。
删除分支
- 删除本地分支(已合并建议用
-d,未合并需强制-D):
|
|
- 删除远程分支:
|
|
- 清理本地过期的远程跟踪引用:
|
|
合并分支
|
|
git merge 用于将一个分支的更改合并到当前分支。这通常用于合并功能分支到主分支(如 main 或 master),或者合并修复分支到开发分支。
合并过程中的冲突
在合并过程中,如果存在冲突(即两个分支对同一文件的同一部分进行了不同的更改),Git 会停止合并并让你手动解决这些冲突。你需要:
- 手动解决冲突:打开冲突的文件,手动编辑以解决冲突。
- 标记冲突已解决:使用
git add命令将解决冲突后的文件标记为已解决。 - 完成合并:使用
git commit命令完成合并。
进阶操作
标签(Tags)
- 创建轻量标签与附注标签:
|
|
- 查看与推送标签:
|
|
- 删除标签:
|
|
暂存工作(stash)
|
|
- 只暂存部分文件:
git stash push -m "msg" 路径/文件 - 从暂存创建分支:
git stash branch feature/fix-login stash@{0}
拣选提交(cherry-pick)
|
|
- 多个提交:
git cherry-pick A..B或git cherry-pick A^..B - 保留来源信息:
git cherry-pick -x <commit> - 仅引入变更不提交:
git cherry-pick --no-commit <commit>
变基(rebase)与合并(merge)
- 变基让历史“线性化”,便于阅读;合并保留真实分叉与合并点。
- 避免对“已公开的分支”做 rebase,以免破坏他人历史。
|
|
撤销提交(revert)
- “安全回滚”某次提交,保留历史:
|
|
- 撤销一段提交(可能产生冲突需手动解决):
|
|
restore 与 checkout 的差异
git restore:用于恢复文件内容(工作区/暂存区),不切换分支。git checkout:既能切分支又能恢复文件,功能较多、语义不够直观。- 推荐:分支相关用
git switch,文件恢复用git restore。
|
|
远程仓库的操作
添加远程库地址
|
|
git remote add origin 远程库地址 用于将远程仓库添加到你的本地 Git 仓库中。当你创建一个新的本地仓库并希望将其与远程仓库(如 Gitee、GitHub、GitLab 等)关联时,这个命令非常有用。
命令解释
git remote:这是用于管理远程仓库引用的命令。add:这个子命令用于添加一个新的远程仓库引用。origin:这是远程仓库的默认短名称。Git 使用origin作为远程仓库的默认名称,但你也可以使用其他名称。远程库地址:这是远程仓库的 URL 地址。
验证远程仓库
添加远程仓库后,你可以使用以下命令来查看所有远程仓库的 URL:
|
|
这将列出所有远程仓库的名称和对应的 URL。
获取远程仓库信息
git fetch <代码库名>(通常是origin) 是从远程仓库拉取最新的数据(比如提交、分支、标签等),但不会自动合并到你的本地代码中。
执行 git fetch origin 后,Git 会做以下事情:
- 从远程仓库(如
origin)拉取所有新的提交、分支、标签等信息 - 把这些信息保存在本地,但不会影响你当前的工作目录
- 更新本地对远程分支的引用(例如
origin/main)
这样你就知道:“哦,别人已经在 main 分支上提交了新代码”,但你自己的代码还是原来的,没变。
场景 1:你想先看看别人改了什么,再决定是否合并
|
|
现在你可以查看远程有哪些变化:
|
|
这会显示:别人提交了哪些你还没有的改动。
然后你可以选择:
- 如果没问题 →
git merge origin/main - 如果有问题 → 先修复冲突或回滚
⚠️ 而
git pull是直接拉 + 合并,没有缓冲,容易出错!
场景 2:团队协作中避免意外覆盖
如果你刚写了一半的功能,同事突然推送了新代码,你不想立刻合并,可以:
|
|
→ 看看有没有冲突,再决定要不要合并。
修改远程仓库 URL
如果你需要修改远程仓库的 URL(例如,从 HTTPS 更改为 SSH),你可以使用以下命令:
|
|
将 新的远程库地址 替换为你新的远程仓库 URL。
删除远程仓库
如果你不再需要某个远程仓库,你可以使用以下命令删除它:
|
|
这将删除名为 origin 的远程仓库引用。
拉取远程库文件
|
|
这个命令会从远程仓库的 master 分支拉取最新的更改,并尝试将这些更改合并到你当前所在的本地分支。(有时是用main分支)
简言之就是从远程库拉取文件到工作区。
上传远程库文件
|
|
上传前要执行git add 将更改添加到暂存区(staging area)。
|
|
再执行git commit 将暂存区(staging area)的更改提交(commit)到本地仓库。
|
|
最后执行git push将本地库文件上传到远程库。
|
|
这条命令做了两件事:
- 推送分支:将您的本地分支推送到远程仓库
origin。 - 设置上游分支:
-u参数将远程分支设置为本地分支的上游分支,这样您以后可以直接使用git push或git pull命令而不需要指定远程仓库和分支名。
代码冲突
协作场景
假设有这么一个场景,你和同事协作,你的同事push了新的代码,而你也在开发中,进行了pull:
-
远程仓库(比如
origin/main):有你本地没有的新提交(比如同事推送了代码)。 -
你的本地分支(比如
main):有你远程没有的新提交(比如你写了一些新功能)。
此时你执行了:
|
|
实际上你执行了
|
|
fetch:把远程的新提交拉到本地(更新origin/main)。merge:尝试把origin/main合并到你当前的本地分支(比如main)。
那么可能有两种情况:
-
情况一:没有冲突 → 自动创建合并提交
Git 能自动把两边的修改“合”在一起。你会看到类似这样的输出:
1 2 3 4Auto-merging README.md Merge made by the 'ort' strategy. README.md | 2 ++ 1 file changed, 2 insertions(+)
Git 会自动创建一个 合并提交(merge commit),包含两个“父母”:本地提交和远程的新提交。 结果:代码合并成功,历史变成“分叉再合并”的样子。
-
情况二:有冲突 → 合并失败,需要手动解决
如果你和远程修改了同一个文件的同一部分,Git 不知道该保留谁的,就会报冲突。
-
输出类似:
1 2 3Auto-merging src/app.js CONFLICT (content): Merge conflict in src/app.js Automatic merge failed; fix conflicts and then commit the result. -
此时:
-
你的工作区处于 “合并中”状态(
MERGING) -
文件里会出现冲突标记:
1 2 3 4 5<<<<<<< HEAD console.log("my local change"); ======= console.log("remote change from colleague"); >>>>>>> origin/main
-
此时需要手动操作:
- 编辑文件,决定保留哪部分(或融合两者)
- 删除冲突标记(
<<<<<<<,=======,>>>>>>>) git add解决完冲突的文件git commit完成合并(Git 会自动生成合并提交信息)
完成后,本地就同时包含了你和远程的修改。
-
所以每天开工前最好先pull,减少冲突概率。

Git工作流
GitFlow工作流
Gitflow工作流(Gitflow Workflow)是2010年由Vincent Driessen在他的一篇博客里提出来的。它定义了一整套完善的基于Git分支模型的框架,结合了版本发布的研发流程,适合管理具有固定发布周期的大型项目。
和特性分支工作流相比,Gitflow工作流并没有引入任何新的概念。不同的地方在于,它强化了对Git分支模型的使用,结合产品或项目发布周期的特定需求,定义了各种不同类型的分支,每一种分支都有它自己特定的职责,并且分支之间什么时候、以什么样的方式交互,也都有相应的规则。下面我们就具体来看一下。
Master分支
Master分支作为唯一一个正式对外发布的分支,是所有分支里最稳定的。这是因为,只有经过了严格审核和测试,并且在当前发布计划里的特性,才会被合并到master分支。当某个版本发布的时候,我们通常还会为master分支加上带有相应版本号的tag。
Develop分支
Develop分支是根据master分支创建出来的,它作为一种集成分支(Integration Branch),是专门用来集成开发完成的各种特性的。Develop分支通常具有更加详细和完整的提交历史,包括一些很细节的提交记录。而master分支则因为是面向版本发布的,所以它的提交历史会略去这些细节,显得比较精简。
Feature分支
Feature分支是根据develop分支创建出来的,Gitflow工作流里的每个新特性都有自己的feature分支,这一点和特性分支工作流是一样的。这些分支除了在开发人员的本地存在以外,也可以被推送到共享的远程Git库,作为工作备份,以及与其他人协同工作的基础。当特性开发结束以后,这些分支上的工作会被合并到develop分支。但feature分支从来不会直接和master分支打交道。
Release分支
当积累了足够多的已完成特性,或者预定的系统发布周期临近的时候,我们就会从develop分支创建出一个release分支,专门用来做和当前版本发布有关的工作。Release分支一旦开出来以后,就不允许再有新的特性被加入到这个分支了,只有bug修复或者文档编辑之类的工作才允许进入该分支。
Release分支上的内容最终会被合并到master分支,等版本发布的时候,我们通常还会为master分支加上带有相应版本号的tag。同时,release分支也会被合并到develop分支。在release分支活跃其间,develop分支也一直处于Open状态。Release分支上的内容代表当前版本在发布之前的准备工作,develop分支上的内容则代表下一个版本的开发工作,两者是可以并行展开的。
Hotfix分支
Hotfix(热补丁)分支不从是develop分支创建出来的,而是直接根据master分支创建得到的,其目的是为了给运行在生产环境中的系统快速提供补丁,同时确保不会给正在其他上分支进行的工作造成影响。当hotfix分支上的工作完成以后,可以合并到master分支和develop分支,以及当前的release分支。如果有版本的更新,也可以为master分支打上相应的tag。
大致关系如图:

具体工作
Vincent Driessen不仅定义了Gitflow的工作流程,还提供了一个相应的命令行工具git-flow。
具体工作流详见:Git工作流面面观——Gitflow工作流 - 晴耕小筑
GitHubFlow
GitHubFlow看名字也知道和GitHub有关,它来源于GitHub团队的工作实践。当代码托管在GitHub上时,则需要使用GitHubFlow。相比GitFlow而言,GitHubFlow没有那么多分支。
GitHubFlow通常只有一个Master分支是固定的,而且GitHubFlow中的Master分支通常是受保护的,只有特定权限的人才可以向Master分支合入代码。
在GitHubFlow中,新功能开发或修复Bug需要从Master分支拉取一个新分支,在这个新分支上进行代码提交;功能开发完成,开发者创建Pull Request(简称PR),通知源仓库开发者进行代码修改review,确认无误后,将由源仓库开发人员将代码合入Master分支。

很多人可能会问,提交代码通常是commit或者push,拉取代码才是pull,为什么GitHubFlow中提交代码提出的是“Pull Request”。因为在GitHubFlow中,PR是通知其他人员到你的代码库去拉取代码至本地,然后由他们进行最终的提交,所以用“pull”而非“push”。
GitHubFlow优点是相对于GitFlow来说比较简单,其缺点是因为只有一条Master分支,万一代码合入后,由于某些因素Master分支不能立刻发布,就会导致最终发布的版本和计划不同。
GitLabFlow
GitLabFlow出现的最晚,GitLabFlow是开源工具GitLab推荐的做法。
GitLabFlow支持GitFlow的分支策略,也支持GitHubFlow的“Pull Request”(在GitLabFlow中被称为“Merge Request”)。
相比于GitHubFlow,GitLabFlow增加了对预生产环境和生产环境的管理,即Master分支对应为开发环境的分支,预生产和生产环境由其他分支(如Pre-Production、Production)进行管理。在这种情况下,Master分支是Pre-Production分支的上游,Pre-Production是Production分支的上游;GitLabFlow规定代码必须从上游向下游发展,即新功能或修复Bug时,特性分支的代码测试无误后,必须先合入Master分支,然后才能由Master分支向Pre-Production环境合入,最后由Pre-Production合入到Production。

GitLabFlow中的Merge Request是将一个分支合入到另一个分支的请求,通过Merge Request可以对比合入分支和被合入分支的差异,也可以做代码的Review。
