01、认识一下Git!—简介
Git是目前最先进、最主流的分布式版本控制系统,并且免费开源。核心功能是版本控制。具体来说,就是代码文件版本控制。记录和管理代码更改历史记录。这意味着您可以随时恢复到之前的状态。 Git 已成为程序员的必备技能,因为支持跨地域协作是团队项目开发的重要基础。
主要特点:
开源、免费且广泛使用。强大的文档(代码)历史版本控制,直接记录完整快照(全部内容,无差异),并支持回滚和比较。分布式、多人协作代码开发。几乎所有操作都在本地进行,并且支持代码合并和代码同步。简单易用的分支管理,支持高效的分支创建和分支合并。
Git是Linux之父为了解决Linux混乱的代码管理而被迫开发的。 Linux 和Git 之父Linus Benedic Torvalds 于1969 年来自芬兰。
02、Git是干什么的?—基础概念
首先,了解Git 的基本概念、基本框架和工作流程。
2.1、Git概念汇总
概念名称描述工作区是计算机上可见的代码库目录,其中新添加和修改的文件被发送到临时存储(阶段或索引)以供临时使用。文件更改。它实际上只是一个存储要发送的文件列表信息的文件(.git/index)。存储库Git 的管理仓库、版本控制数据库、文件和目录的状态以及保存所有内容更改(版本)的位置。服务器/远程仓库(Origin或Remote) 服务器端版本库,专用的Git服务器提供多用户共享的服务,承担中央服务器的角色。本地仓库通过push命令将代码推送到服务器仓库。直接在本地仓库用户机器上使用的存储库分支(branch)是主线的独立“副本”,可以独立工作,互不干扰。 仓库初始化时存在默认的主分支主控。头(HEAD) HEAD就像一个“指针”,指向当前活动分支的最新版本。 Commit将暂存区的所有变更提交到当前仓库的活动分支。推送将版本从本地仓库推送到服务器(远程)仓库并与其他仓库共享。 Pull 将更新从服务器(远程)仓库检索到本地仓库,并检索其他人可以共享的更新。从服务器(远程)仓库获取更新。它的功能和pull一样,不同的是它不会自动合并。冲突:当多个用户对同一文件的工作副本进行更改并将这些更改合并到仓库中时,就会发生冲突并需要手动合并过程。 Merge 合并冲突的文件。 Git 手动处理它无法自动处理的冲突。标签是指某个分支在特定时间点的状态,可以理解为提交记录的别名,常用于标记版本。 Master(或Main) 仓库的“master”分支,默认的主分支,在仓库初始化时可用。在Github上创建的仓库的默认名称是“main”。 origin/master 代表远程仓库(origin)的“master”分支。 origin/HEAD 代表远程仓库(origin)最近的提交位置。这通常等于“Origin/Master”
2.2、工作区/暂存区/仓库
工作区、暂存区、存储库是Git最基本的概念,它们的关系如下:
命令行:Git命令通过系统命令行工具或Git提供的命令行工具(C:\\Program Files\\Git\\git-bash.exe)执行。 GUI工具:Windows(GUI)、Mac(GUI)工具,必须分开。 安装更容易,使用更方便。
运行命令git –version 查看安装的版本号。
$ git –versiongit 版本2.33.0.windows.2
虽然本文是在Windows平台上完成的,但是并不影响学习Git。
2.3、Git基本流程(图)
Git 有三个主要的配置文件。三个配置文件的优先级顺序为。
系统全局配置(–system):包含适用于系统上所有用户和所有仓库(项目)的配置信息,位于Git安装目录C:\\Program Files\\Git\\etc\\gitconfig中。已保存。 用户全局配置(–global):当前系统用户的全局配置。保存在用户目录:C:\\Users\\[系统用户名]\\.gitconfig。 仓库/项目配置(–local):仓库(项目)的具体配置。它将保存在您的项目目录.git/config 中。
#显示git配置git config –listgit config -l#显示系统配置git config –system –list#当前用户(全局) 显示全局配置git config –list –global#当前仓库显示配置信息git config – -本地–列表
仓库配置是上述配置的集合。
$ git config –list$ git config -ldiff.astextplain.textconv=astextplainhttp.sslbackend=opensslhttp.sslcainfo=C:/Program Files/Git/mingw64/ssl/certs/ca-bundle.crtcore.autocrlf=truecore.fscache=truecore .symlinks=falsepull.rebase=falsecredential.helper=manager-corecredential.https://dev.azure.com.usehttppath=trueinit.defaultbranch=masteruser.name=Kandinguser.email=123anding@163.com
2.4、Git状态(图)
安装Git时要做的第一件事是配置您的用户信息。 —— 你在Git 中是谁?设置你的用户名和电子邮件地址,以便每次发送文件时,你都会知道是谁发送的。
配置用户信息。
$ git config –global user.name \’你的名字\’$ git config –global user.email \’email@example.com\’# 配置完成后,查看用户配置文件: $ cat \’C:\\Users\\Kwongad\\ 。 gitconfig\'[用户]name=Kandingemail=123anding@163.com
user.name 是您的用户名,user.email 是您的电子邮件地址。 –global:配置参数。指示用户的全局设置。如果要配置特定仓库的用户信息,可以使用参数–localconfiguration或者直接在仓库配置文件.git/config中修改。
03、起步:Git安装配置
并非工作目录中的每个文件都需要包含在版本控制中。例如日志、临时文件、私有配置文件等不需要纳入版本控制。那么我们应该做什么呢?
在工作空间的根目录中创建“.gitignore”文件,并在该文件中设置不需要版本控制的文件和文件夹。 “.gitignore”文件本身包含在版本控制中并且可以共享。规则如下:
注释以# 符号开头。您可以使用Linux 通配符。
星号(*) 表示任意数量的字符,问号(?) 表示单个字符,方括号([abc]) 表示可选的字符范围,大括号({string1, string2,} )代表一个字符串。表示可选字符,例如String。以感叹号(!)开头:表示例外规则,不会被忽略。路径分隔符(/f)以:开头,表示忽略根目录下的文件f。路径分隔符(f/)以:结尾,表示忽略文件夹f下的所有文件。
#用于注释*.txt #忽略所有以“.txt”结尾的文件!lib.txt #除了lib.txt/temp #项目根目录下,除了其他目录的临时文件仅忽略临时文件。 temp”build/忽略#build/目录下的所有文件doc/*.txt 忽略#doc/notes.txt 但忽略doc/server/arch.txt
各种语言项目中常用的.gitignore 文件结构: GitHub – github/gitignore: 有用的.gitignore 模板集合
3.1、Git的配置文件
如果不想使用命令行工具,可以安装Git GUI工具,更简单易用。你不必记住那么多命令,上手也很容易,但你仍然需要学习Git 的基础知识。
对于Git来说,真正理解Git思想的最好方法就是使用命令行。
其实它们只是工具。最好选择适合自己的。不用担心。
TortoiseGit:小乌龟,SVN时代非常流行的代码管理GUI工具。
仅Windows版本支持中文,需要单独下载安装中文语言包。 开源、免费,并且与文件管理器完美集成。 内置冲突解决工具。 Sourcetree:SourceTree是老牌的Git GUI管理工具,也被誉为最好的Git GUI工具。
适用于Windows和Mac系统,内置中文版本,并具有自动语言识别功能。 免费、强大且易于使用。 它功能丰富,设计得无论是基础操作还是高级操作都非常流畅,适合初学者,并且支持Git Flow。一个无冲突的比较工具,支持第三方组件的配置。 GitHub Desktop:Github官方创建的Git管理工具。 GitKraken:GitKraken 是一个跨平台GUI Git 客户端,提供免费版、专业版和企业版,并支持多种功能。
3.2、配置-初始化用户
从SourceTree官网下载安装包,支持Windows和Mac系统。按照提示完成安装。
SourceTree支持管理多个仓库,您可以使用+按钮以多种方式添加仓库。
其次是可视化仓库管理,可视化操作,无需记忆繁琐的指令(参数)。
3.3、配置-忽略.gitignore
从TortoiseGit官网下载安装包和中文语言包,按照提示完成安装。小乌龟的Git集成在操作系统中,您可以右键单击文件夹来执行Git操作。
首先进入设置。右键文件夹菜单——TortoiseGit——点击Settings进入设置,设置中文语言。小乌龟的各种Git操作都位于一个右键菜单中,该菜单深度集成到操作系统的资源管理器中,文件图标还显示Git状态,方便区分。
04、Git的GUI工具们
VSCode 附带的Git 工具本质上同时提供可视化和命令,因此一旦习惯了它们,就不需要安装任何其他GUI 工具。但是,您可以安装一些VSCode 插件来增强Git 功能。
GitLens:非常实用,对于团队项目开发至关重要。这用于快速查看代码的发布历史记录,显示最近的更改信息,包括海报。仅推荐这一点。
Git History:一款可以轻松快速查看Git文件操作历史记录的工具,展示直观,操作简单。
4.1、SourceTree
4.2、TortoiseGit
有两种方法可以创建本地存储库。
一是新建仓库。 git init 初始化当前目录下的仓库。另一种选择是克隆远程存储库: git clone [url]
# 准备“KwebNote”文件夹作为仓库目录,进入该文件夹Kwongad@Kwongad-T14 MINGW64 ~$ cd d:Kwongad@Kwongad-T14 MINGW64 /d$ cd Project_FilesKwongad@Kwongad-T14 MINGW64 /d/Project_Files# 多次cd 命令进入仓库目录KwebNote:“cd 目录名”命令进入目录,“cd .”返回上一级目录(含空格) Kwongad@Kwongad-T14 MINGW64 /d /Project_Files/github.kwong/KwebNote # 开始初始化项目。您还可以指定目录: git init [文件目录]$ git initInitialized 空Git 存储库(D:/Project_Files/github.Kwong/KwebNote/.git/)
注意:您必须在仓库目录中运行Git 命令。
创建后,将创建一个额外的隐藏.git 目录。这是本地仓库Git的工作位置。
克隆远程存储库,例如在github 上创建的存储库“https://github.com/kwonding/KWebNote.git”。
$ git clone \’https://github.com/kwonanding/KWebNote.gitClone to “KWebNote\’. 枚举remote:对象: 108,done.remote:对象计数: 100%(108/108),done.remote:对象压缩: 100% (60/60),完成。 Remote: 总共108 个(增量48),重用88 个(增量34),包重用0 个收到的对象: 100% (108/108),9.36 KiB/s,已完成。达美: 100% (48/48),已完成。
将在当前目录中创建一个“KWebNote”项目目录。
4.3、VSCode中的Git
git add 命令可以简单理解为将所有想要发送的变更放入一个暂存区(Stage),然后运行一次git commit 将暂存区中的所有变更一次性发送到仓库。
指令说明git add [file1] [file2] 将文件(包括修改的文件和新文件)添加到临时存储中。 git add [dir] 将目录(包括子目录)添加到临时存储中,如上所述。 git add 与上面相同。 add all 修改文件(不跟踪)并将其添加到暂存区。 git rm [file] 删除工作区文件并将删除的内容放置在暂存区域中。
# 将指定文件添加到暂存区,包括修改的文件$ git add [file1] [file2] . # 将当前目录下的所有文件添加到暂存区$ git add .# 删除工作区文件并将这些删除$ git rm [file1] [file2] .# 重命名文件并将其名称放入临时存储$ git mv [file-original] [file-renamed]
对文件“R.md”的修改暂时不保存。
运行git add.Staging。
05、Git使用入门
Git 提交提交按时间顺序存储在数据库中,类似于游戏关卡。每次提交都会生成一条包含ID + 描述+ 快照内容的记录。
Commit ID:使用摘要算法(SHA1)根据修改文件的内容计算出不重复的40个字符。由于Git 是分布式的,因此通常只有前几个字符在本地可用,以确保唯一性和完整性。位(6)。多年后,您仍然可以通过您的ID 找到以前的内容和更改,因此您永远不必担心再次丢失它们。描述:与代码中的任何注释一样,此提交的描述非常重要,我们建议您准确输入。快照:一个文件的完整版本,以对象树结构存储在仓库下的\\.git\\objects目录下。这也是Git高效率的秘诀之一。
SHA1 是一种哈希算法,可用于生成数据摘要。 Git 不适合大型非文本文件,并且会影响摘要和快照计算的性能。
多次提交形成一个时间表。每次发送都会移动当前分支主机和HEAD“指针”位置。
Sourcetree的历史:
一般来说,每个小函数或者步骤都可以发送一次,形成一个比较清晰的历史记录。
命令:
指令说明git commit -m \’description\’ 参数-m 设置提交的描述信息。如果不指定该参数,则进入描述编辑模式。 -a 表示直接从工作区发送到版本。跳过git add 步骤并排除新文件。 git commit [file] 将暂存中的指定文件发送到仓库区。使用git commit –amend -m。新的提交将替换上次更改的提交。 提交哈希值(ID) git log -n20 显示日志(最后20 条)。如果不指定参数-n,则显示所有日志。 git log -n20 –oneline 参数\’–oneline\’可以用来使日志输出更加简洁(一行)。 git log -n20 –graph 参数“–graph”直观地显示分支关系。 git log –follow [file] 显示特定文件的版本历史记录。 file gitblame [file] 以列表格式显示指定文件的变更记录gitreflog 显示所有可用的历史版本记录(实际上是HEAD 变更记录)(包括回滚记录)(重要) 在git status 命令中,比较常用的是显示本地仓库状态,添加参数-s 简单模式
使用git log 命令查看发送记录日志可以让您轻松查看每次发送中哪些文件和内容发生了变化,并执行恢复或其他操作。
# 将临时存储区域发送到仓库区域$ git commit -m [message] # 将所有更改发送到仓库$ git commit -a -m \’更改README中的版权信息\’ # 临时存储指定文件发送到区域$ git commit [file1] [file2] . -m [message]# 使用新的提交来替换上次提交# 如果代码没有新的更改,则用于重写提交信息最后一次提交$ git commit –amend -m [message] $ git log -n2commit 412b56448568ff362ef312507e78797befcf2846(头- 主)作者: Kanding 123anding@163.comDate: 星期四12月1日19:02:22 00commit c0ef 58e3738f7d54545d 8c13d603cddeee328fcbAuthor: Kanding 123anding@163.comDate: December Tree 1 16:52:56 2022 +0800# 可以使用参数“–oneline”来制作日志输出更简洁(1 行) $ git log -n2 –oneline5444126 (HEAD – main,origin/main,origin/HEAD) 更新README.md228362e 合并github.com:kwonganding/KWebNote 分支\’main\’
5.1、创建仓库
Git 中最重要的是发送记录。标签、分支、HEAD等都是指并指向发送记录的“指针”。了解这一点很重要。
提交记录之间还存在“指针”引用,每个提交都指向前一个提交。标签是指向特定传输记录的固定“指针”引用。别名可以让您更容易记住一些关键节点。它保存在工作区根目录下的.git\\refs\\tags 中。分支也是指向特定提交记录的“指针”引用,并且“指针”的位置在提交、更新、回滚等过程中是可变的。它保存在工作区根目录中的.git\\refs\\heads 中。 HEAD:指向当前活动分支(最新提交)的“指针”引用。 “.git/HEAD”文件中存在和保存的内容是“
ref: refs/heads/master”。
上图中:
HEAD始终指向当前活动分支,多个分支只能有一个处于活动状态。标签t1在某一个提交上创建后,就不会变了。而分支、HEAD的位置会改变。
打开这些文件内容看看,就更容易理解这些“指针”的真面目了。
# tag$ git tag -a \’v1\’ -m\’v1版本\’$ cat .git/refs/tags/v1a2e2c9caea35e176cf61e96ad9d5a929cfb82461# main分支指向最新的提交$ cat .git/refs/heads/main8f4244550c2b6c23a543b741c362b13768442090# HEAD指向当前活动分支$ cat .git/HEADref: refs/heads/main# 切换到dev分支,HEAD指向了dev$ git switch devSwitched to branch \’dev\’$ cat .git/HEADref: refs/heads/dev
这里的主分支名字为“main”,是因为该仓库是从Github上克隆的,Github上创建的仓库默认主分支名字就是“main”,本地创建的仓库默认主分支名字为“master”。
📢“指针”引用:之所以用引号的“指针”,是为了便于统一和理解。和指针原理类似,都是一个指向,只是实际上可能更复杂一点,且不同的“指针”引用会有区别。
5.5、提交的唯一标识id,HEAD~n是什么意思?
每一个提交都有一个唯一标识,主要就是提交的hash值commit id,在很多指令中会用到,如版本回退、拣选提交等,需要指定一个提交。那标识唯一提交有两种方式:
首先就是commit id,一个40位编码,指令中使用的时候可以只输入前几位(6位)即可。还有一种就是HEAD~n,是基于当前HEAD位置的一个相对坐标。
HEAD 表示当前分支的最新版本,是比较常用的参数。HEAD^上一个版本,HEAD^^ 上上一个版本。HEAD~ 或HEAD~1 表示上一个版本,以此类推,HEAD^10 为最近第10个版本。HEAD@{2}在git reflog日志中标记的提交记录索引。
通过git log、git reflog可以查看历史日志,可以看每次提交的唯一编号(hash)。区别是git reflog可以查看所有操作的记录(实际是HEAD变更记录),包括被撤销回退的提交记录。
$ git reflog -n105acc914 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~738748b (dev) HEAD@{1}: reset: moving to HEAD~9312c3e HEAD@{2}: reset: moving to HEAD~db03fcb HEAD@{3}: reset: moving to HEAD~1b81fb3 HEAD@{4}: reset: moving to HEAD~41ea423 HEAD@{5}: reset: moving to HEAD~d3e15f9 HEAD@{6}: reset: moving to d3e15f91b81fb3 HEAD@{7}: reset: moving to HEAD~141ea423 HEAD@{8}: reset: moving to HEAD~d3e15f9 HEAD@{9}: reset: moving to HEAD~
5.6、比较diff
git diff用来比较不同文件版本之间的差异。
指令描述git diff查看暂存区和工作区的差异git diff [file]同上,指定文件git diff –cached查看已暂存的改动,就是暂存区与新版本HEAD进行比较git diff –staged同上git diff –cached [file]同上,指定文件git diff HEAD查看已暂存的+未暂存的所有改动,就是与最新版本HEAD进行比较git diff HEAD~同上,与上一个版本比较。HEAD~表示上一个版本,HEAD~10为最近第10个版本git diff [id] [id]查看两次提交之间的差异git diff [branch]查看工作区和分支直接的差异
☘️画个图更清晰些:
# 查看文件的修改$ git diff README.md# 查看两次提交的差异$ git diff 8f4244 1da22# 显示今天你写了多少行代码:工作区+暂存区$ git diff –shortstat \”@{0 day ago}\”
06、远程仓库
Git作为分布式的版本管理系统,每个终端都有自己的Git仓库。但团队协作还需一个中间仓库,作为中心,同步各个仓库。于是服务端(远程)仓库就来承担这个职责,服务端不仅有仓库,还配套相关管理功能。
可以用公共的Git服务器,也可以自己搭建一套Git服务器。
公共Git服务器,如Github、Gitlab、码云Gitee、腾讯Coding等。搭建私有Git服务器,如开源的Gitlab、Gitea、等。
6.1、远程用户登录
Git服务器一般提供两种登录验证方式:
HTTS:基于HTTPS连接,使用用户名、密码身份验证。
每次都要输入用户名、密码,当然可以记住。地址形式:https://github.com/kwonganding/KWebNote.gitSSL:采用SSL通信协议,基于公私钥进行身份验证,所以需要额外配置公私秘钥。
不用每次输入用户名、密码,比较推荐的方法。地址形式:git@github.com:kwonganding/KWebNote.git
#查看当前远程仓库使用的那种协议连接:$ git remote -vorigin git@github.com:kwonganding/KWebNote.git (fetch)origin https://github.com/kwonganding/KWebNote.git (push)# 更改为https地址,即可切换连接模式。还需要禁用掉SSL, 才能正常使用https管理gitgit config –global http.sslVerify false
🔑远程用户登录:HTTS
基于HTTPS的地址连接远程仓库,Github的共有仓库克隆、拉取(pull)是不需要验证的。
$ git clone \’https://github.com/kwonganding/KWebNote.git\’Cloning into \’KWebNote\’…# 仓库配置文件“.git/config”[remote \”origin\”]url = https://github.com/kwonganding/KWebNote.gitfetch = +refs/heads/*:refs/remotes/origin/*pushurl = https://github.com/kwonganding/KWebNote.git
推送(push)代码的时候就会提示输入用户名、密码了,否则无法提交。记住用户密码的方式有两种:
🔸URL地址配置:在原本URL地址上加上用户名、密码,https://后加用户名:密码@
# 直接修改仓库的配置文件“.git/config”[remote \”origin\”]url = https://用户名:密码@github.com/kwonganding/KWebNote.gitfetch = +refs/heads/*:refs/remotes/origin/*pushurl = https://github.com/kwonganding/KWebNote.git
🔸本地缓存:会创建一个缓存文件.git-credentials,存储输入的用户名、密码。
# 参数“–global”全局有效,也可以针对仓库设置“–local”# store 表示永久存储,也可以设置临时存储git config –global credential.helper store# 存储内容如下,打开文件“仓库\\.git\\.git-credentials”https://kwonganding:[加密内容付费可见]@github.com
🔑远程用户登录:SSH
SSH(Secure Shell,安全外壳)是一种网络安全协议,通过加密和认证机制实现安全的访问和文件传输等业务,多用来进行远程登录、数据传输。SSH通过公钥、私钥非对称加密数据,所以SSH需要生成一个公私钥对,公钥放服务器上,私有自己留着进行认证。
① 生成公私钥:通过Git指令ssh-keygen -t rsa生成公私钥,一路回车即可完成。生成在“C:\\Users\\用户名\\.ssh”目录下,文件id_rsa.pub的内容就是公钥。
② 配置公钥:打开id_rsa.pub文件,复制内容。Github上,打开Setting➤ SSH and GPG keys ➤ SSH keys ➤ 按钮New SSH key,标题(Title)随意,秘钥内容粘贴进去即可。
SSH配置完后,可用ssh -T git@github.com来检测是否连接成功。
$ ssh -T git@github.comHi kwonganding! You\’ve successfully authenticated, but GitHub does not provide shell access.
6.2、远程仓库指令🔥
指令描述git clone [git地址]从远程仓库克隆到本地(当前目录)git remote -v查看所有远程仓库,不带参数-v只显示名称git remote show [remote]显示某个远程仓库的信息git remote add [name] [url]增加一个新的远程仓库,并命名git remote rename [old] [new]修改远程仓库名称git pull [remote] [branch]取回远程仓库的变化,并与本地版本合并git pull同上,针对当前分支git fetch [remote]获取远程仓库的所有变动到本地仓库,不会自动合并!需要手动合并git push推送当前分支到远程仓库git push [remote] [branch]推送本地当前分支到远程仓库的指定分支git push [remote] –force/-f强行推送当前分支到远程仓库,即使有冲突,⚠️很危险!git push [remote] –all推送所有分支到远程仓库git push –u参数–u表示与远程分支建立关联,第一次执行的时候用,后面就不需要了git remote rm [remote-name]删除远程仓库git pull –rebase使用rebase的模式进行合并
6.3、推送push/拉取pull
git push、git pull是团队协作中最常用的指令,用于同步本地、服务端的更新,与他人协作。
🔸推送(push):推送本地仓库到远程仓库。
如果推送的更新与服务端存在冲突,则会被拒绝,push失败。一般是有其他人推送了代码,导致文件冲突,可以先pull代码,在本地进行合并,然后再push。
🔸拉取(pull):从服务端(远程)仓库更新到本地仓库。
git pull:拉取服务端的最新提交到本地,并与本地合并,合并过程同分支的合并。git fetch:拉取服务端的最新提交到本地,不会自动合并,也不会更新工作区。
6.4、fetch与pull有什么不同?
两者都是从服务端获取更新,主要区别是fetch不会自动合并,不会影响当前工作区内容。
git pull = git fetch + git merge
如下面图中,git fetch只获取了更新,并未影响master、HEAD的位置。要更新master、HEAD的位置需要手动执行git merge合并。
# fetch只更新版本库$ git fetchremote: Enumerating objects: 5, done.remote: Counting objects: 100% (5/5), done.remote: Compressing objects: 100% (3/3), done.remote: Total 3 (delta 2), reused 0 (delta 0), pack-reused 0Unpacking objects: 100% (3/3), 663 bytes | 44.00 KiB/s, done.From github.com:kwonganding/KWebNote2ba12ca..c64f5b5 main -> origin/main# 执行合并,合并自己$ git mergeUpdating 2ba12ca..c64f5b5Fast-forwardREADME.md | 2 +-1 file changed, 1 insertion(+), 1 deletion(-)
07、Git利器-分支
分支是从主线分离出去的“副本”,分支就像是平行宇宙,可独立发展,独立编辑、提交,也可以和其他分支合并。分支是Git的核心必杀利器之一,分支创建、切换、删除都非常快,他非常的轻量。所以,早建分支!多用分支!
7.1、分支Branch
比如有一个项目团队,准备10月份发布新版本,要新开发一堆黑科技功能,占领市场。你和小伙伴“小美”一起负责开发一个新功能A,开发周期2周,在这两周你们的代码不能影响其他人,不影响主分支。这个时候就可以为这个新功能创建一个分支,你们两在这个分支上干活,2周后代码开发完了、测试通过,就可以合并进要发版的开发分支了。安全、高效,不影响其他人工作,完美!
在实际项目中,一般会建几个主线分支。
🔸master:作为主分支,存放稳定的代码,就是开发后测试通过的代码,不允许随便修改和合并。🔸开发分支:用于团队日常开发用,比如团队计划10月份开发10个功能并发版,则在此分支上进行,不影响主分支的稳定。🔸功能A分支:开发人员根据自己的需要,可以创建一些临时分支用于特定功能的开发,开发完毕后再合并到开发分支,并删除该分支。
分支就是指向某一个提交记录的“指针”引用,因此创建分支是非常快的,不管仓库多大。当我们运行git branch dev创建了一个名字为dev的分支,Git实际上是在.git\\refs\\heads下创建一个dev的引用文件(没有扩展名)。
$ git branch dev$ cat .git/refs/heads/devca88989e7c286fb4ba56785c2cd8727ea1a07b97
7.2、分支指令🔥
指令描述git branch列出所有本地分支,加参数-v显示详细列表,下同git branch -r列出所有远程分支git branch -a列出所有本地分支和远程分支,用不同颜色区分git branch [branch-name]新建一个分支,但依然停留在当前分支git branch -d dev删除dev分支,-D(大写)强制删除git checkout -b dev从当前分支创建并切换到dev分支git checkout -b feature1 dev从本地dev分支代码创建一个 feature1分支,并切换到新分支git branch [branch] [commit]新建一个分支,指向指定commit idgit branch –track [branch] [remote-branch]新建一个分支,与指定的远程分支建立关联git checkout -b hotfix remote hotfix从远端remote的hotfix分支创建本地hotfix分支git branch –set-upstream [branch] [remote-branch]在现有分支与指定的远程分支之间建立跟踪关联:
git branch –set-upstream hotfix remote/hotfixgit checkout [branch-name]切换到指定分支,并更新工作区git checkout .撤销工作区的(未暂存)修改,把暂存区恢复到工作区。git checkout HEAD .撤销工作区、暂存区的修改,用HEAD指向的当前分支最新版本替换git merge [branch]合并指定分支到当前分支git merge –no-ff dev合并dev分支到当前分支,参数–no-ff禁用快速合并模式git push origin –delete [branch-name]删除远程分支git rebase master将当前分支变基合并到master分支✅switch:新的分支切换指令切换功能和checkout一样,switch只单纯的用于切换git switch master切换到已有的master分支git switch -c dev创建并切换到新的dev分支
📢关于 checkout 指令:checkout是Git的底层指令,比较常用,也比较危险,他会重写工作区。支持的功能比较多,能撤销修改,能切换分支,这也导致了这个指令比较复杂。在Git 2.23版本以后,增加了git switch、git reset指令。
git switch:专门用来实现分支切换。git reset:专门用来实现本地修改的撤销,更多可参考后续“reset”内容。
$ git branchdev* main# 列出了当前的所有分支,星号“*”开头的“main”为当前活动分支。
7.3、分支的切换checkout
代码仓库可以有多个分支,master为默认的主分支,但只有一个分支在工作状态。所以要操作不同分支,需要切换到该分支,HEAD就是指向当前正在活动的分支。
# 切换到dev分支,HEAD指向了dev# 此处 switch 作用同 checkout,switch只用于切换,不像checkout功能很多$ git switch devSwitched to branch \’dev\’$ cat .git/HEADref: refs/heads/dev
使用 git checkout dev切换分支时,干了两件事:
①、HEAD指向dev:修改HEAD的“指针”引用,指向dev分支。②、还原工作空间:把dev分支内容还原到工作空间。
此时的活动分支就是dev了,后续的提交就会更新到dev分支了。
❓切换时还没提交的代码怎么办?
如果修改(包括未暂存、已暂存)和待切换的分支没有冲突,则切换成果,且未提交修改会一起带过去,所以要注意!如果有冲突,则会报错,提示先提交或隐藏,关于隐藏可查看后续章节内容“stash”。
7.4、合并merge&冲突
把两个分支的修改内容合并到一起,常用的合并指令git merge [branch],将分支[branch]合并到当前分支。根据要合并的内容的不同,具体合并过程就会有多种情况。
🔸快速合并(Fast forward)
如下图,master分支么有任何提交,“git merge dev”合并分支dev到master,此时合并速度就非常快,直接移动master的“指针”引用到dev即可。这就是快速合并(Fast forward),不会产生新的提交。
合并dev到master,注意要先切换到master分支,然后执行git merge dev,把dev合并到当前分支。
📢强制不用快速合并:git merge –no-ff -m \”merge with no-ff\” dev,参数–no-ff不启用快速合并,会产生一个新的合并提交记录。
🔸普通合并
如果master有变更,存在分支交叉,则会把两边的变更合并成一个提交。
如果两边变更的文件不同,没有什么冲突,就自动合并了。如果有修改同一个文件,则会存在冲突,到底该采用哪边的,程序无法判断,就换产生冲突。冲突内容需要人工修改后再重新提交,才能完成最终的合并。
上图中,创建dev分支后,两个分支都有修改提交,因此两个分支就不在一条顺序线上了,此时合并dev到master就得把他们的修改进行合并操作了。
v5、v7共同祖先是v4,从这里开始分叉。Git 会用两个分支的末端v6 和 v8以及它们的共同祖先v4进行三方合并计算。合并之后会生成一个新(和并)提交v9。合并提交v9就有两个祖先v6、v8。
🔸处理冲突<<<<<<< HEAD
在有冲突的文件中,<<<<<<< HEAD开头的内容就表示是有冲突的部分,需要人工处理,可以借助一些第三方的对比工具。人工处理完毕后,完成合并提交,才最终完成此次合并。=======分割线上方是当前分支的内容,下方是被合并分支的变更内容。
7.5、变基rebase
把两个分支的修改内容合并到一起的办法有两种:merge 和 rebase,作用都是一样的,区别是rebase的提交历史更简洁,干掉了分叉,merge的提交历史更完整。
在dev上执行“git rebase master”变基,将dev分支上分叉的v7、v8生成补丁,然后在master分支上应用补丁,产生新的v7\’、v8\’新的提交。然后回到master分支,完成合并git merge dev,此时的合并就是快速合并了。最终的提交记录就没有分叉了。
$ git rebase master$ git checkout master$ git merge dev
08、标签管理
标签(Tags)指的是某个分支某个特定时间点的状态,是对某一个提交记录的的固定“指针”引用。一经创建,不可移动,存储在工作区根目录下.git\\refs\\tags。可以理解为某一次提交(编号)的别名,常用来标记版本。所以发布时,一般都会打一个版本标签,作为该版本的快照,指向对应提交commit。
当项目达到一个关键节点,希望永远记住那个特别的提交快照,你可以使用 git tag给它打上标签。比如我们今天终于完成了V1.1版本的开发、测试,并成功上线了,那就可给今天最后这个提交打一个标签“V1.1”,便于版本管理。
默认标签是打在最新提交的commit上的,如果希望在指定的提交上打标签则带上提交编号(commit id):git tag v0.9 f52c633
指令描述git tag查看标签列表git tag -l \’a*\’查看名称是“a”开头的标签列表,带查询参数git show [tagname]查看标签信息git tag [tagname]创建一个标签,默认标签是打在最新提交的commit上的git tag [tagname] [commit id]新建一个tag在指定commit上git tag -a v5.1 -m\’v5.1版本\’创建标签v5.1.1039,-a指定标签名,-m指定说明文字git tag -d [tagname]删除本地标签git checkout v5.1.1039切换标签,同切换分支git push [remote] v5.1推送标签,标签不会默认随代码推送推送到服务端git push [remote] –tags提交所有tag
如果要推送某个标签到远程,使用命令git push origin [tagname],或者,一次性推送全部到远程:git push origin –tags
📢注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签。
# tag$ git tag -a \’v1\’ -m\’v1版本\’$ cat .git/refs/tags/v1a2e2c9caea35e176cf61e96ad9d5a929cfb82461# 查看标签列表$ git tagv1
09、后悔药-怎么撤销变更?
发现写错了要回退怎么办?看看下面几种后悔指令吧!
❓还没提交的怎么撤销? —— checkout、reset
还未提交的修改(工作区、暂存区)不想要了,用签出指令(checkout)进行撤销清除。或者用checkout的新版回滚指令reset。❓已提交但么有push的提交如何撤销?—— reset、revert❓已push的提交如何撤销?—— 同上,先本地撤销,然后强制推送git push origin -f,⚠️注意慎用! 记得先pull获取更新。
9.1、后悔指令🔥
指令描述git checkout .撤销工作区的(未暂存)修改,把暂存区恢复到工作区。不影响暂存区,如果没暂存,则撤销所有工作区修改git checkout [file]同上,file指定文件git checkout HEAD .撤销工作区、暂存区的修改,用HEAD指向的当前分支最新版本替换工作区、暂存区git checkout HEAD [file]同上,file指定文件git reset撤销暂存区状态,同git reset HEAD,不影响工作区git reset HEAD [file]同上,指定文件file,HEAD可省略git reset [commit]回退到指定版本,清空暂存区,不影响工作区。工作区需要手动git checkout签出git reset –soft [commit]移动分支master、HEAD到指定的版本,不影响暂存区、工作区,需手动git checkout签出更新git reset –hard HEAD撤销工作区、暂存区的修改,用当前最新版git reset –hard HEAD~回退到上一个版本,并重置工作区、暂存区内容。git reset –hard [commit]回退到指定版本,并重置工作区、暂存区内容。git revert[commit]撤销一个提交,会用一个新的提交(原提交的逆向操作)来完成撤销操作,如果已push则重新push即可
git checkout .、git checkout [file] 会清除工作区中未添加到暂存区的修改,用暂存区内容替换工作区。git checkout HEAD .、git checkout HEAD [file] 会清除工作区、暂存区的修改,用HEAD指向的当前分支最新版本替换暂存区、工作区。
# 只撤销工作区的修改(未暂存)$ git checkout .Updated 1 path from the index# 撤销工作区、暂存区的修改$ git checkout HEAD .Updated 1 path from f951a96
9.2、回退版本reset
reset是专门用来撤销修改、回退版本的指令,支持的场景比较多,多种撤销姿势,所以参数组合也比较多。简单理解就是移动master分支、HEAD的“指针”地址,理解这一点就基本掌握reset了。
如下图:
回退版本git reset –hard v4 或 git reset –hard HEAD~2,master、HEAD会指向v4提交,v5、v6就被废弃了。也可以重新恢复到v6版本:git reset –hard v6,就是移动master、HEAD的“指针”地址。
reset有三种模式,对应三种参数:mixed(默认模式)、soft、hard。三种参数的主要区别就是对工作区、暂存区的操作不同。
mixed为默认模式,参数可以省略。只有hard模式会重置工作区、暂存区,一般用这个模式会多一点。
模式名称\\描述HEAD的位置暂存区工作区soft回退到某一个版本,工作区不变,需手动git checkout修改不修改不修改mixed(默认)撤销暂存区状态,不影响工作区,需手动git checkout修改修改不修改hard重置未提交修改(工作区、暂存区)修改修改修改
穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。
git reset [–soft | –mixed | –hard] [HEAD]# 撤销暂存区$ git resetUnstaged changes after reset:M R.md# 撤销工作区、暂存区修改$ git reset –hard HEAD# 回退版本库到上一个版本,并重置工作区、暂存$ git reset –hard HEAD~# 回到原来的版本(恢复上一步的撤销操作),并重置工作区、暂存$ git reset –hard 5f8b961# 查看所有历史提交记录$ git reflogccb9937 (HEAD -> main, origin/main, origin/HEAD) HEAD@{0}: commit: 报表新增导入功能8f61a60 HEAD@{1}: commit: bug:修复报表导出bug4869ff7 HEAD@{2}: commit: 用户报表模块开发4b1028c HEAD@{3}: commit: 财务报表模块开发完成
9.3、撤销提交revert
安全的撤销某一个提交记录,基本原理就是生产一个新的提交,用原提交的逆向操作来完成撤销操作。注意,这不同于reset,reset是回退版本,revert只是用于撤销某一次历史提交,操作是比较安全的。
如上图:
想撤销v4的修改,执行git revert v4,会产生一个新的提交v-4,是v4的逆向操作。同时更新maser、HEAD“指针”位置,以及工作区内容。如果已push则重新push即可。
# revert撤销指定的提交,“-m”附加说明$ git revert 41ea42 -m\’撤销对***的修改\'[main 967560f] Revert \”123\”1 file changed, 1 deletion(-)
9.4、checkout/reset/revert总结
标题 \\ 指令checkoutresetrevert主要作用(撤销)撤销工作区、暂存区未提交修改回退版本,重置工作区、暂存区撤销某一次提交撤销工作区git checkout [file]git reset HEAD [file]撤销工作区、暂存区git checkout HEAD [file]git reset –hard HEAD [file]回退版本git reset –hard [commit]安全性只针对未提交修改,安全如回退了已push提交,不安全安全
可看出reset完全可以替代checkout来执行撤销、回退操作,reset本来也是专门用来干这个事情的,可以抛弃checkout了(撤销的时候)。
10、工作中的Git实践
10.1、Git flow
Git flow(Git工作流程)是指软件项目中的一种Git分支管理模型,经过了大量的实践和优化,被认为是现代敏捷软件开发和DevOps(开发、技术运营和质量保障三者的交集)的最佳实践。Git flow主要流程及关键分支:原图地址-processon
✅主分支:master,稳定版本代码分支,对外可以随时编译发布的分支,不允许直接Push代码,只能请求合并(pull request),且只接受hotfix、release分支的代码合并。
✅热修复分支:hotfix,针对线上紧急问题、bug修复的代码分支,修复完后合并到主分支、开发分支。
① 切换到hotfix分支,从master更新代码;② 修复bug;③ 合并代码到dev分支,在本地Git中操作即可;④ 合并代码到master分支。
✅发版分支:release,版本发布分支,用于迭代版本发布。迭代开发完成后,合并dev代码到release,在release分支上编译发布版本,以及修改bug(定时同步bug修改到dev分支)。测试完成后此版本可以作为发版使用,然后把稳定的代码push到master分支,并打上版本标签。
✅开发分支:dev,开发版本分支,针对迭代任务开发的分支,日常开发原则上都在此分支上面,迭代完成后合并到release分支,开发、发版两不误。
✅其他开发分支:dev-xxx,开发人员可以针对模块自己创建本地分支,开发完成后合并到dev开发分支,然后删除本地分支。
10.2、金屋藏娇stash
当你正在dev分支开发一个功能时,代码写了一半,突然有一个线上的bug急需要马上修改。dev分支Bug没写完,不方便提交,就不能切换到主分支去修复线上bug。Git提供一个stash功能,可以把当前工作区、暂存区 未提交的内容“隐藏”起来,就像什么都没发生一样。
# 有未提交修改,切换分支时报错$ git checkout deverror: Your local changes to the following files would be overwritten by checkout:README.mdPlease commit your changes or stash them before you switch branches.Aborting# 隐藏$ git stashSaved working directory and index state WIP on main: 2bc012c s# 查看被隐藏的内容$ git stash liststash@{0}: WIP on main: 2bc012c s# 比较一下,什么都没有,一切都没有发生过!$ git diff# 去其他分支修改bug,修复完成回到当前分支,恢复工作区$ git stash pop
在上面示例中,有未提交修改,切换分支时报错。错误提示信息很明确了,commit提交或stash隐藏:Please commit your changes or stash them before you switch branches.
📢 如果切换分支时,未提交修改的内容没有冲突,是可以成功切换的,未提交修改会被带过去。
指令描述git stash把未提交内容隐藏起来,包括未暂存、已暂存。 等以后恢复现场后继续工作git stash list查看所有被隐藏的内容列表git stash pop恢复被隐藏的内容,同时删除隐藏记录git stash save \”message\”同git stash,可以备注说明messagegit stash apply恢复被隐藏的文件,但是隐藏记录不删除git stash drop删除隐藏记录
🪧当然这里先提交到本地也是可以的,只是提交不是一个完整的功能代码,而是残缺的一部分,影响也不大。
拣选提交cherry-pick
当有一个紧急bug,在dev上修复完,我们需要把dev上的这个bug修复所做的修改“复制”到master分支,但不想把整个dev合并过去。为了方便操作,Git专门提供了一个cherry-pick命令,让我们能复制一个特定的提交到当前分支,而不管这个提交在哪个分支。
如上图,操作过程相当于将该提交导出为补丁文件,然后在当前HEAD上重放,形成无论内容还是提交说明都一致的提交。
希望把dev分支上的v7提交的内容合并到master,但不需要其他的内容。在master分支上执行指令git cherry-pick v7,会产生一个新的v7\’提交,内容和v7相同。同时更新master、HEAD,以及工作区。
# 选择一个commit,合并进当前分支$ git cherry-pick [commit]
#以上关于浅显易懂的git教程的相关内容来源网络仅供参考,相关信息请以官方公告为准!
原创文章,作者:CSDN,如若转载,请注明出处:https://www.sudun.com/ask/93261.html