git
一、Git概述
Git 是一个免费的、开源的分布式版本控制系统,可以快速高效地处理从小型到大型的各种 项目。
Git 易于学习,占地面积小,性能极快。 它具有廉价的本地库,方便的暂存区域和多个工作 流分支等特性。其性能优于 Subversion、CVS、Perforce 和 ClearCase 等版本控制工具。
1、什么是版本控制
版本控制是一种记录文件内容变化,以便将来查阅特定版本修订情况的系统。
版本控制其实最重要的是可以记录文件修改历史记录,从而让用户能够查看历史版本, 方便版本切换。
2、为什么需要版本控制
个人开发过渡到团队协作。
3、版本控制工具
- 集中式版本控制工具
CVS、SVN(Subversion) 、VSS……
集中化的版本控制系统诸如 CVS、SVN 等,都有一个单一的集中管理的服务器,保存 所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或 者提交更新。多年以来,这已成为版本控制系统的标准做法。
这种做法带来了许多好处,每个人都可以在一定程度上看到项目中的其他人正在做些什 么。而管理员也可以轻松掌控每个开发者的权限,并且管理一个集中化的版本控制系统,要 远比在各个客户端上维护本地数据库来得轻松容易。
事分两面,有好有坏。这么做显而易见的缺点是中央服务器的单点故障。如果服务器宕 机一小时,那么在这一小时内,谁都无法提交更新,也就无法协同工作。
- 分布式版本控制工具
Git、Mercurial、Bazaar、Darcs……
像 Git 这种分布式版本控制工具,客户端提取的不是最新版本的文件快照,而是把代码 仓库完整地镜像下来(本地库)。这样任何一处协同工作用的文件发生故障,事后都可以用 其他客户端的本地仓库进行恢复。因为每个客户端的每一次文件提取操作,实际上都是一次 对整个文件仓库的完整备份。
分布式的版本控制系统出现之后,解决了集中式版本控制系统的缺陷:
服务器断网的情况下也可以进行开发(因为版本控制是在本地进行的)
每个客户端保存的也都是整个完整的项目(包含历史记录,更加安全)
4、Git简史
5、Git工作机制
6、Git和代码托管中心
代码托管中心是基于网络服务器的远程代码仓库,一般我们简单称为远程库。
局域网
- GitLab
互联网
- GitHub(外网)
- Gitee 码云(国内网站)
二、Git安装
1、查看 GNU 协议,可以直接点击下一步。
2、选择 Git 安装位置,要求是非中文并且没有空格的目录,然后下一步
3、Git 选项配置,推荐默认设置,然后下一步。
4、Git 安装目录名,不用修改,直接点击下一步。
5、Git 的默认编辑器,建议使用默认的 Vim 编辑器,然后点击下一步
6、默认分支名设置,选择让 Git 决定,分支名默认为 master,下一步
7、修改 Git 的环境变量,选第一个,不修改环境变量,只在 Git Bash 里使用 Git
8、选择后台客户端连接协议,选默认值 OpenSSL,然后下一步
9、配置 Git 文件的行末换行符,Windows 使用 CRLF,Linux 使用 LF,选择第一个自动转换,然后继续下一步。
10、选择 Git 终端类型,选择默认的 Git Bash 终端,然后继续下一步。
11、选择 Git pull 合并的模式,选择默认,然后下一步。
12、选择 Git 的凭据管理器,选择默认的跨平台的凭据管理器,然后下一步
13、其他配置,选择默认设置,然后下一步
14、实验室功能,技术还不成熟,有已知的 bug,不要勾选,然后点击右下角的 Install 按钮,开始安装 Git。
15、点击 Finsh 按钮,Git 安装成功!
16、右键任意位置,在右键菜单里选择 Git Bash Here 即可打开 Git Bash 命令行终端
17、在 Git Bash 终端里输入 git --version
查看 git 版本,如图所示,说明 Git 安装成功。
三、Git常用命令
命令 | 作用 |
---|---|
git config --global user.name 用户名 |
设置用户签名 |
git config --global user.email 邮箱 |
设置用户签名 |
git init |
初始化本地仓库 |
git status |
查看本地仓库状态 |
git add |
添加到暂存区 |
git commit -m "日志信息" 文件名 |
提交到本地库 |
git reflog |
查看历史记录 |
git reset --hard 版本号 |
版本穿梭 |
1、设置或修改用户签名
基本语法
1 |
|
1 |
|
查看用户名和邮箱
1 |
|
1 |
|
说明:
签名的作用是区分不同操作者身份。用户的签名信息在每一个版本的提交信息中能够看 到,以此确认本次提交是谁做的。Git 首次安装必须设置一下用户签名,否则无法提交代码。
注意:这里设置用户签名和将来登录 GitHub(或其他代码托管中心)的账号没有任何关系。
2、初始化本地库
基本语法
1 |
|
结果
3、查看本地库状态
基本语法
1 |
|
案例
4、添加暂存区
基本语法
1 |
|
案例
5、提交本地库
基本语法
1 |
|
案例
6、修改文件再查看状态
案例
git add -> git commit后,本地库状态变为 没有文件需要提交
7、查看历史版本
基本语法
查看版本信息
1 |
|
查看版本详细信息
1 |
|
案例
8、版本穿梭
基本语法
1 |
|
案例
Git 切换版本,底层其实是移动的 HEAD 指针,具体原理如下图所示
四、Git 分支操作
命令 | 作用 |
---|---|
git branch 分支名 |
创建分支 |
git branch -v |
查看分支 |
git checkout 分支名 |
切换分支 |
git merge 分支名 |
把指定分支合并到当前分支上 |
1、什么是分支
在版本控制过程中,同时推进多个任务,为每个任务,我们就可以创建每个任务的单独 分支。使用分支意味着程序员可以把自己的工作从开发主线上分离开来,开发自己分支的时 候,不会影响主线分支的运行。对于初学者而言,分支可以简单理解为副本,一个分支就是 一个单独的副本。(分支底层其实也是指针的引用)
分支的好处:
同时并行推进多个功能开发,提高开发效率。各个分支在开发过程中,如果某一个分支开发失败,不会对其他分支有任何影响。失败的分支删除重新开始即可。
2、查看分支
基本语法
1 |
|
案例
3、创建分支
基本语法
1 |
|
案例
4、修改分支
5、切换分支
基本语法
1 |
|
案例
6、合并分支
基本语法
1 |
|
案例:冲突合并
冲突产生的表现:后面状态为 MERGING
冲突产生的原因: 合并分支时,两个分支在同一个文件的同一个位置有两套完全不同的修改。Git 无法替 我们决定使用哪一个。必须人为决定新代码内容。
解决合并冲突
1、编辑有冲突的文件,删除特殊符号,决定要使用的内容
特殊符号:
1 |
|
2、添加到暂存区,提交到本地库,这样就完成了
7、创建分支和切换分支图解
master、dog其实都是指向具体版本记录的指针。当前所在的分支,其实是由 HEAD 决定的。所以创建分支的本质就是多创建一个指针。
HEAD 如果指向 master,那么我们现在就在 master 分支上。
HEAD 如果执行 dog,那么我们现在就在 dog 分支上。
五、团队协作机制
1、团队内协作
2、跨团队协作
六、github远程库
1、创建仓库
2、远程仓库操作
命令 | 作用 |
---|---|
git remote -V |
查看当前所有远程库的别名 |
git remote add 别名 远程库地址 |
起别名 |
git push 别名 分支 |
推送本地分支上的内容到远程仓库 |
git clone 远程库地址 |
将远程仓库的内容克隆到本地 |
git pull 远程库地址(或别名) 远程分支名 |
将远程仓库对于分支最新内容拉下来后与当前本地分支直接合并 |
3、邀请加入团队
1、选择邀请合作者
2、填入想要合作的人
3、复制地址并发送给这个人(QQ,微信)
4、这个人点击邀请的链接,接受邀请
5、这个人可以修改内容并 push 到远程仓库
七、知识提高(2024更新)
7.1 拉取远程分支
要将一个远程分支拉取到本地,而不是合并到当前分支,你可以通过以下步骤来实现。这样可以让你获取指定的远程分支,并创建一个新的本地分支,而不会影响当前的工作状态。
步骤 1:查看远程分支列表
首先,你可以查看远程分支的列表,以确定远程分支的名称。
1 |
|
这将显示所有远程分支。
git fetch
git fetch
:更新远程分支的引用
- 作用:
git fetch
命令从远程仓库获取最新的变更,这些变更包括新的提交、新的分支、更新的引用等,但不会自动合并到你的本地分支中。- 当你执行
git fetch
时,Git 会从远程仓库中拉取所有更新,但不会改变你的本地代码,只会更新远程引用。
- 为什么需要
git fetch
:- 在执行
git branch -r
之前,通常建议运行git fetch
,这样可以确保你看到的是最新的远程分支信息。 - 如果不先运行
git fetch
,那么git branch -r
列出的远程分支列表可能是陈旧的,因为远程仓库中的分支有可能发生了变化(例如新增、删除或更新),而你的本地 Git 未获取到最新的状态。
- 在执行
步骤 2:创建一个本地分支来追踪远程分支
假设你要将远程分支 origin/feature-branch
拉取到本地,而不合并到当前分支,可以通过以下命令来创建一个新的本地分支并拉取内容:
1 |
|
命令解释
git checkout -b feature-branch origin/feature-branch
:git checkout -b
:创建并切换到一个新的本地分支。feature-branch
:本地新分支的名字,你可以选择任意名字。origin/feature-branch
:远程分支的名字,表示从远程的origin
拉取分支feature-branch
的内容。
通过这条命令,你会创建一个名为 feature-branch
的本地分支,并且基于远程的 feature-branch
分支内容。它不会将远程的更改直接合并到你当前的分支。
创建不跟踪远程分支的新分支:
使用以下命令创建一个不关联远程分支的本地分支:
1 |
|
步骤 3:验证是否成功
你可以使用以下命令来验证你当前所在的分支:
1 |
|
这将显示所有本地分支,带有 *
的表示你当前所在的分支。如果 feature-branch
在其中,并且你已切换到它,就说明操作成功。
总结
如果你想将一个远程分支拉取到本地,而不进行合并:
- 使用
git fetch
获取远程分支列表。 - 使用
git checkout -b <local-branch-name> <remote-branch-name>
,创建一个本地分支并切换到它。
这样你就能在本地创建一个新的分支,并基于远程分支的内容,而无需合并它到当前工作分支。
7.2 Merge Request出现冲突
7.3 分支重命名
在 Git 中重命名一个分支,可以按照以下步骤进行操作:
步骤 1:切换到你想要重命名的分支
首先,确保你在要重命名的分支上。如果不是,请切换到该分支。
1 |
|
步骤 2:重命名当前分支
使用 git branch -m
命令来重命名当前分支:
1 |
|
-m
:代表移动或重命名分支。new-branch-name
:你想要给这个分支的新名字。
步骤 3:更新远程分支(如果需要)
如果这个分支已经推送到远程仓库,并且你想要同步更新远程分支的名称,按照以下步骤进行。
步骤 3.1:删除旧的远程分支
首先,将旧的分支名从远程仓库删除:
1 |
|
步骤 3.2:推送新的分支到远程
将重命名后的新分支推送到远程仓库:
1 |
|
步骤 3.3:更新本地分支与远程的关联
为了保持本地分支和远程分支的关联,你需要更新追踪引用:
1 |
|
7.4 tag
7.4.1 查看tag
要查看 Git 仓库中的 Tag,你可以使用以下命令:
1. 查看所有本地 Tag
要查看当前本地仓库中的所有 Tag,可以使用以下命令:
1 |
|
- 这将列出所有本地仓库中创建的 Tag 名称。
如果你希望查看更多关于每个 Tag 的信息,可以加上 -n
参数来显示 Tag 的注释信息,例如:
1 |
|
2. 过滤查看 Tag
如果你想过滤显示某些特定模式的 Tag,可以使用类似的命令:
1 |
|
- 例如,上面的命令将列出所有以
v1.
开头的 Tag。
3. 查看远程仓库中的 Tag
如果你想查看远程仓库中的 Tag,可以先获取远程的 Tag 信息,然后使用 git ls-remote
命令:
1 |
|
origin
:这里表示远程仓库的名称,通常是origin
,可以根据实际情况更改。- 这将列出远程仓库中所有的 Tag,包括它们的哈希值。
4. 查看 Tag 的详细信息
如果你想要查看某个特定 Tag 的详细信息(例如它所指向的提交),可以使用以下命令:
1 |
|
tagname
:替换为你想查看的 Tag 名称,这个命令会显示该 Tag 指向的提交详细信息,包括提交日志、作者、时间等。
7.4.3 删除tag
要删除远程仓库中的 Tag,可以按照以下步骤进行操作:
步骤 1:删除本地 Tag
首先,如果你在本地也有这个 Tag,建议先删除本地的 Tag:
1 |
|
tagname
:要删除的 Tag 的名称。
步骤 2:删除远程仓库中的 Tag
然后删除远程仓库中的 Tag,可以使用 git push
命令:
1 |
|
origin
:表示远程仓库的名称。--delete tag
:指定要删除的 Tag。tagname
:要删除的 Tag 的名称。
示例
假设你想删除名为 v1.0
的 Tag,步骤如下:
- 删除本地的
v1.0
Tag:1
git tag -d v1.0
- 删除远程仓库中的
v1.0
Tag:1
git push origin --delete tag v1.0
删除本地的 Tag 并不是强制性的,但通常这样做有助于保持本地和远程仓库的一致性,避免混淆。
7.5 删除分支
要删除 Git 分支,取决于你要删除的是本地分支还是远程分支,操作步骤略有不同:
- 删除本地分支
要删除本地分支,使用以下命令:
1 |
|
其中,<branch_name>
是你要删除的分支的名称。
- 注意:
git branch -d
只能删除已经合并到当前分支或其他分支的分支。如果分支未被合并,你会收到警告,Git 会拒绝删除。 - 如果你确定要强制删除未合并的分支,可以使用
-D
(大写的D
):
1 |
|
- 删除远程分支
要删除远程分支,使用以下命令:
1 |
|
这将从远程仓库中删除指定的分支。
检查本地和远程分支
-
查看本地分支:
1
git branch [-v]
-
查看远程分支:
1
git branch -r
7.6 取消merge or rebase
要取消当前的 rebase
或 merge
操作,你可以根据当前的情况选择相应的命令:
- 取消 Rebase 操作
如果你在进行 git rebase
操作,并且想要放弃当前的 rebase 并返回到 rebase 之前的状态,使用以下命令:
1 |
|
这将放弃当前的 rebase 操作,并将你的代码恢复到执行 git rebase
之前的状态。
- 取消 Merge 操作
如果你是在进行 git merge
操作并遇到了冲突,想要放弃合并并返回到合并之前的状态,使用以下命令:
1 |
|
这将取消当前的合并操作,并恢复到合并之前的状态。
如果不确定自己是在哪种状态,可以通过 git status
查看当前的操作状态,确认是处于 rebase 还是 merge 过程中。
7.7 git ignore
在使用 Git 进行版本控制时,.gitignore
文件扮演着至关重要的角色。它用于指定哪些文件或目录应被 Git 忽略,不纳入版本控制。正确配置 .gitignore
可以帮助保持代码库的整洁,避免不必要的文件被提交,提高团队协作效率。
- 什么是
.gitignore
.gitignore
是一个文本文件,位于 Git 仓库的根目录或特定子目录中,包含一系列规则,用于告诉 Git 忽略哪些文件和目录。这些规则可以基于文件名、目录名、文件扩展名或模式匹配。
.gitignore
文件的位置
根目录:
- 推荐位置:通常将
.gitignore
文件放在 Git 仓库的根目录下。这确保了整个项目中的所有子目录和文件都受到忽略规则的影响。 - 优点:
- 集中管理忽略规则,简化维护。
- 易于新成员理解和遵循。
子目录:
- 可选位置:在特定子目录中也可以创建
.gitignore
文件,以覆盖或添加更具体的忽略规则。 - 使用场景:
- 某些子目录有特殊的忽略需求,例如生成大量临时文件的目录。
- 需要细粒度控制不同模块或组件的忽略规则。
全局 .gitignore
:
- 适用场景:为所有 Git 仓库设置全局忽略规则,避免在每个仓库中重复配置常见的忽略项。
- 配置方法:
-
创建一个全局
.gitignore
文件,例如~/.gitignore_global
。 -
配置 Git 使用这个全局忽略文件:
1
git config --global core.excludesfile ~/.gitignore_global
-
在
~/.gitignore_global
中添加全局忽略规则。
-
- 常见的
.gitignore
规则
以下是一些常见的 .gitignore
规则,适用于不同的编程语言和工具。你可以根据项目需求选择性地添加这些规则。
Node.js 项目:
1 |
|
Python 项目:
1 |
|
Go 项目:
1 |
|
Java 项目:
1 |
|
Ruby 项目:
1 |
|
通用规则:
1 |
|
特殊文件和目录:
- 日志文件:如
.log
文件,通常不需要纳入版本控制。 - 环境变量文件:如
.env
文件,包含敏感信息,应被忽略以防泄露。 - 构建输出目录:如
dist/
、build/
、target/
等,通常由构建工具自动生成,无需手动管理。
- 创建和编辑
.gitignore
文件
创建 .gitignore
文件:
在项目根目录中创建一个 .gitignore
文件:
1 |
|
编辑 .gitignore
文件:
使用你喜欢的文本编辑器打开并编辑 .gitignore
文件,添加需要忽略的规则。例如:
1 |
|
提交 .gitignore
文件:
将 .gitignore
文件添加到 Git 仓库并提交:
1 |
|
- 已存在文件的忽略
如果在添加 .gitignore
之前,某些文件已经被 Git 跟踪,你需要将它们从暂存区移除才能生效。
移除已跟踪的文件:
例如,要忽略 node_modules/
目录:
1 |
|
检查忽略效果:
使用 git status
查看哪些文件被忽略:
1 |
|
被忽略的文件将不会显示在未暂存的更改中。
- 使用全局
.gitignore
设置全局忽略文件:
-
创建全局
.gitignore
文件:1
touch ~/.gitignore_global
-
配置 Git 使用这个全局忽略文件:
1
git config --global core.excludesfile ~/.gitignore_global
-
在
~/.gitignore_global
中添加常用的忽略规则,例如:1
2
3
4
5
6
7# 操作系统文件
.DS_Store
Thumbs.db
# 编辑器临时文件
*.swp
*.swo
优点:
- 一致性:确保所有 Git 项目都遵循相同的忽略规则,减少重复配置。
- 简化配置:常见的忽略规则只需配置一次,节省时间和精力。
- 高级
.gitignore
使用技巧
模式匹配:
-
通配符
*
:匹配零个或多个字符。*.log
忽略所有.log
文件。temp*
忽略所有以temp
开头的文件或目录。
-
斜杠
/
:用于指定目录。logs/
忽略logs
目录及其所有内容。/config/*.json
只忽略根目录下的config
目录中的.json
文件。
-
感叹号
!
:用于排除某些被忽略的文件。*.log
忽略所有.log
文件。!important.log
但不忽略important.log
文件。
-
双星号
**
:匹配任意层级的目录。**/logs
忽略所有层级中的logs
目录。
注释:
在 .gitignore
文件中使用 #
开头的行作为注释,用于解释或组织忽略规则:
1 |
|
排除特定文件:
如果需要忽略一个目录中的大多数文件,但保留其中的某些文件,可以使用感叹号 !
进行排除:
1 |
|
使用模板:
GitHub 提供了许多针对不同语言和框架的 .gitignore
模板。你可以访问 github/gitignore 仓库,找到适合你项目的 .gitignore
模板,并根据需要进行调整。
实例:综合 .gitignore
:
以下是一个综合的 .gitignore
示例,适用于同时使用 Node.js 和 Python 的项目:
1 |
|
- 常见问题解答
Q1: 为什么 .gitignore
文件不生效?
可能原因:
- 被忽略的文件已经被 Git 跟踪。
.gitignore
规则书写有误。- 文件路径不正确或使用了错误的相对路径。
解决方法:
- 使用
git rm -r --cached <file>
移除已跟踪的文件。 - 检查
.gitignore
语法和规则。 - 确认文件路径和规则是否匹配。
Q2: 如何忽略特定类型的文件?
方法:
在 .gitignore
中使用通配符。例如,要忽略所有 .tmp
文件:
1 |
|
Q3: 如何忽略某个目录下的所有内容?
方法:
在 .gitignore
中指定目录名并以斜杠结尾。例如,要忽略 logs
目录:
1 |
|
Q4: 如何保留被忽略目录中的特定文件?
方法:
使用感叹号 !
排除特定文件。例如,忽略 logs
目录但保留 logs/important.log
:
1 |
|
Q5: 如何查看哪些文件被 Git 忽略?
方法:
使用 git status --ignored
查看被忽略的文件。
1 |
|
- 结论
正确配置 .gitignore
文件是维护干净、高效的 Git 仓库的基础。通过合理的忽略规则,可以避免不必要的文件被提交,减少版本控制系统的负担,提高团队协作的效率。根据项目的需求和使用的技术栈,灵活调整和优化 .gitignore
文件,确保其覆盖所有需要忽略的文件和目录。
推荐资源
通过这些知识和工具,你可以更好地管理你的 Git 仓库,确保代码库的整洁和高效运作。
7.8 场景案例
场景1:同事A的分支feat/branch_a
正在测试环境测试,小B想部署自己的分支feat/branch_b
进行测试
实践做法:
小B git checkout -b feat/branch_b_test
,再 git rebase feat/branch_a
,然后即可直接部署 feat/branch_b_test
,不会影响到同事A的测试。
如果小B想要修改代码并继续测试,可以更新 feat/branch_b
,然后再回到 feat/branch_b_test
, 并 git rebase feat/branch_b
,然后接着部署即可。
场景2:同事A和同事B共同完成一项开发任务
实践做法:
构建一条主干分支 feat/task
, 小A和小B在这个分支上checkout出新的分支feat/task_a
和feat/task_b
,然后要发测试环境测试的时候,再合入主干分支,让对方再重新rebase主干分支