Git基础操作
1. 安装配置
1.1. Git与TortoiseGit安装
Git是一种分布式版本控制系统,用于跟踪文件的变化,特别是代码文件。它允许多人协作开发,提供分支和合并功能,便于管理不同版本的代码。
TortoiseGit是一个基于Git版本控制系统的图形化用户界面(GUI)工具,主要用于Windows操作系统。它是TortoiseSVN(一个Subversion客户端)系列的延续,提供了一个易于使用的界面,方便用户在Windows中管理Git仓库,而无需通过cmd操作。
TortoiseGit:https://tortoisegit.org/
1.2. commit-msg hook脚本
commit-msg hook脚本用于在执行git commit命令时自动检查提交信息。通过自定义commit-msg脚本,你可以在每次提交代码时强制执行一些规则,比如格式验证、检查是否包含某些关键字、或者确保提交信息符合项目的命名规范。它可以帮助团队规范化提交信息,提高版本控制的质量和一致性。通过自定义hook脚本,你可以确保所有的提交信息都符合团队约定的格式和标准,避免潜在的错误或不一致。简单来说,就是制定提交规范。
具体实现方法需要修改git安装目录下C:\Program Files\Git\mingw64\share\git-core\templates\hooks文件夹下的commit-msg.sample文件。
使用的时候需要把后缀.sample删除,脚本才会在你执行git commit命令时自动执行,如果提交信息不符合要求,它会显示错误信息,并阻止提交。
# commit-msg
# 获取提交信息
COMMIT_MSG=$(cat "$1")
#echo "$COMMIT_MSG"
msg_rule="(feature|fix)"
# 检查提交信息是否包含 feature 或 fix 开头
if ! echo "$COMMIT_MSG" | grep -qE "$msg_rule" ; then
echo "提交信息必须包含 feature 或 fix 开头"
exit 1
fi
# 如果符合要求,允许提交
exit 0
1.3. 配置ssh到gitlab上
-
生成密钥信息;
-
添加ssh公钥到github的ssh配置上;
-
进入第1步”ssh-keygen -t rsa -C “github上注册的邮箱”“命令中key保存的地址,打开id_rsa.pub,将其中的内容全部复制粘贴到github网页中的个人ssh-key中;
-
可以尝试输入
ssh -T git@gitlab.com命令看是配置成功,如果配置成功会返回 “You’ve successfully authenticated…“; -
TortoiseGit的ssh配置为git的ssh, 右击->TortoiseGit->Settings->SSH client中输入git安装目录下的\usr\bin\ssh.exe路径;
生成密钥信息步骤:
git config --global user.name "github上注册的用户名"
git config --global user.email "github上注册的邮箱"
# 这里会提示输入密码,直接三个Enter就行(可输可不输)
ssh-keygen -t rsa -C "github上注册的邮箱"
2. Git工作原理
Git的工作原理是通过工作区、暂存区和本地仓库的协作来管理文件的版本控制。通过分支和合并的机制,解决在多人协作时版本冲突问题。Git的分布式特性使得每个开发者都可以拥有完整的项目历史,并且支持高效的离线工作。
remote:远程仓库,即gitlab服务器上的仓库,提供了网页访问
repository:本地仓库,即clone到自己本地的仓库
index:暂存区,修改保存或者新文件添加的暂存区域,add之后,commit之前
workspace:工作区,特定分支上的修改
3. Git基本操作
3.1. 分支切换
cmd:git checkout 分支名
Tortoise:所在仓库目录右击 -> TortoiseGit -> switch/checkout下拉框选择需要切换的分支名,也可以切换到某个tag或者commit提交点
# 注意
# 在使用前我们需先理解“HEAD”,可以理解为他是一个指针。指向当前本地分支,就是我们选择的分支
# 这里我们使用chekout进行分支切换,其实这个动作就是把远程仓库的分支拷贝到本地,然后将HEAD指向这个本地的分支。这样我们本地有完成了分支的切换
# 这里分支名可以与远程仓库不一样
# 当选择远程分支的时候,能够选择“Track”,如果选择了跟踪,当push、pull的时候会自动预选远程分支
3.2. 查看当前分支
cmd:git branch -r
Tortoise:所在仓库目录右击 -> TortoiseGit -> show log
3.3. 创建分支
拉分支有三种方式:基于分支拉分支;基于标签拉分支;基于某个提交点拉分支
最简单的方法直接在github页面上操作即可,再git fetch一下,将你本地的仓库的分支切换到你新创建的分支上
同理,也可在本地创建一个新的分支,将新分支推送到远程仓库
cmd:git push origin 分支名称
3.4. 代码四连(更新、添加、提交、推送)
cmd:git pull origin "远程分支名":"本地分支名"
Tortoise:所在仓库目录右击 -> TortoiseGit -> pull
cmd:git add "文件名"(git add . 是表示添加所有文件)
Tortoise:所在仓库目录右击 -> TortoiseGit -> git add
cmd:git commit -m "注释信息"
Tortoise:所在仓库目录右击 -> git commit -> "分支名"
cmd:git push origin "远程分支名":"本地分支名"
Tortoise:所在仓库目录右击 -> TortoiseGit -> push
3.5. 创建合并请求与代码合入
一般在网页上进行操作,实际上就是分支合并。如果没有冲突的话,可以实现分支之间的自动和并。如果存在冲突就需要手动解决冲突后再合并。
3.6. 解决冲突
todo
3.7. 删除分支
合并完成后可以选择删除源分支
此外开发人员需要手动删除自己本地的关联分支。因为远程仓库的分支删除后,本地分支已经失去了和远程分支的联系。后续如果远程仓库创建了同名分支的话,新的同名分支pull到本地时会产生冲突,因此需要手动删除本地分支。
# 首先切换到其他分支,如果当前所在分支是需要删除的分支,是无法进行后续操作的
cmd:git checkout master
# 然后,删除关联的本地分支
cmd:git branch -d 要删除的分支名称
# 最后,删除失效的远程分支
cmd:git fetch -p
# 可以使用git branch -a确认分支是否删除成功
cmd:git branch -a
3.8. 查看日志
Tortoise:所在仓库目录右击 -> TortoiseGit -> show log
Tortoise:双击文件进入,可查看文件变更前后的代码差异情况(二进制文件无法查看)
3.9. 代码回退
3.9.1. revert回退
revert有两种用法:回退工作区(本地已经修改但是还没有commit)的修改;回退已经commit的修改
cmd:git checkout -- 文件名
Tortoise:所在仓库目录右击/需回退的文件 -> TortoiseGit -> Revert change by this commit
cmd:git revert 'commit id'
Tortoise:所在仓库目录右击 -> TortoiseGit -> Show log -> 选择需要回退的点 -> 右击 -> Revert change by this commit
3.9.2. reset回退
git reset回退时,如果commit点已经push到远程分支,必须要有对应远程分支的push权限,且需要加上–force,强推代码修改commit信息
reset分为三种类型:–soft、–mixed(默认)、–hard
- –soft回退只是移动HEDA分支;
- –mixed回退后,是将,确认回退,直接提交生成回退的commit;
- –hard是直接删除对应的commit点和日志;
cmd:git reset --force 'commit id'
Tortoise:所在仓库目录右击 -> TortoiseGit -> Show log -> 选择需要回退的点 -> 右击 -> Reset"分支名" to this commit
4. 其他用法
4.1. git tag标签
git的标签使用,标签可以简单理解为软件的别名,是一个指向某个特定提交的、固定的、易记的指针。通常用于标记版本发布。通过使用标签,可以在任何时候快速地回到特定的历史版本。相比之下,分支可以移动,但标签一旦创建就不会改变。
# 查看标签,列出所有标签
cmd:git tag
# 创建标签
cmd:git tag 标签名
Tortoise:所在仓库目录右击 -> TortoiseGit -> Show log -> 选择任意commit -> 右击 -> 在此基础上创建标签 -> 输入标签名和创建标签方式
# HEAD 基于当前本地分支,最新一次提交创建标签
# 分支 基于指定分支指针当前所指向的提交创建标签,场景:如果你当前在feature/xxx分支上,但你想给develop分支的最新提交打标签
# 标签 基于指定标签创建标签,意味着重命名标签或创建别名标签
# 提交 基于仓库历史中的任意一次提交来打标签
# 创建附注标签
cmd: git tag -a 标签名 -m "注释信息"
# 删除标签
# 删除远程标签第一步先删除本地标签,第二步使用git push命令的 --delete 选项推送删除操作到远程仓库
cmd: git tag -d 标签名
cmd: git push origin --delete 标签名
5. Git常见应用思路
使用Git管理项目。
项目中文件的管理,例如项目中存放规格书。如果使用本地的管理方式,每次的版本更新我们通常都会创建一个副本,并附上版本号。但是这样的结果就是文件的冗余,充斥大量相似文件,很难确定哪个是最新版本。出了版本号很难指导每个地方具体改了什么(不过git对于非文本文档的作用也很有限)。如果使用Git,我们要做的就很简单:
- 永远使用有意义的单一文件名:项目计划书.doc, main.py, index.html;
- 频繁提交:每完成一个小的、有意义的改动就做一次 commit;
- 撰写清晰的提交信息,这是版本控制的核心价值之一。
在交付给最终用户或下游同事时,更新附上版本即可,以便对方清晰识别。
常见问题&解决办法
使用git push时报错 git.exe push –progress “origin” main:main Connection reset by 20.205.243.166 port 22.
git.exe push --progress "origin" main:main Connection reset by 20.205.243.166 port 22
fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists.
出现这个报错我考虑是否是我刚改了git仓库的用户名导致,如果仓库位置发生变化,ssh密钥账户匹配会不变会出问题,引起远程仓库无法访问?
于是我尝试用ssh重新拉一个仓库,成功。但是再push代码改动,还是一样报错。
网上查了下,发现大家遇到这个问题,也尝试很多办法。
重新生成ssh密钥修改22端口为443修改git用户邮箱设置删除 known_hosts 中有关 Github相关行- 将网络切换为手机热点(确实有效,治标不治本,怀疑公司内网问题)
于是我也将目标重新锁定回网络,发现自己开了机场,于是把机场关掉,push成功,但是还是会经常失败
解决办法:参考作者【Wrysmile0308】的文章《使用Git时报错Connection reset by 20.205.243.166 port 22》1,老实配置代理解决。
使用git clone时,使用Tortoise Git的ssh拉取项目失败
git clone fatal: Could not read from remote repository. Please make sure you have the correct access rights and the repository exists.
解决办法:参考1.3章节第五点,需要配置小海龟将默认的sshaskpass.exe改成ssh.exe,才能正常使用ssh下载项目代码。
在Github上面克隆代码仓库出现Failed to connect to 127.0.0.1 port 1080 after 2063 ms: Couldn’t connect to server、Failed to connect to github.com port 443 after 21083 ms: Couldn’t connect to server等提示Couldn’t connect to server错误,无法正常下载。
根据 【fK0pS】在《解决 Failed to connect to github.com port 443:connection timed out》2 中的分析,总结下来就是电脑的代理温柔。需要先把子切换到全局,然后再取消,接着取消全局代理
# 先设置代理,配置的信息会存储在 `.gitconfig`文件中。
git config --global http.proxy http://127.0.0.1:7890
git config --global http.proxy https://127.0.0.1:7890
# 再取消代理
git config --global --unset http.proxy
git config --global --unset https.proxy
因为本地有使用代理工具Clash,不确定是否由于经常开关代理工具,而导致代理端口冲突或者混乱引起。
研究了一下终于对代理有了一点点的理解
我们平时用的梯子(代理),代理是梯子技术中的一种基础手段。代理是你电脑和互联网的中间,当你访问外网的时候你的请求会先发给代理,代理服务器替你访问外网,并将结果返回给你。
如果连接着代理,就配置正确的代理端口号。个人主要用Clash上网,它的默认端口是7890
解决办法是配置全局代理(不建议),或者是只针对github.com配置代理
配置方法是这里是通过在C:\Users\你的用户名\.ssh目录下建立config文件,为什么在这里配置有效果呢?当使用git@github.com进行SSH操作时,系统不会直接连接GitHub的22/433端口,而是通过ProxyCommand指定的代理工具(这里是connect)建立隧道连接
Host github.com
port 22
User git
HostName github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa_github
# 添加下面这一行,端口号为你开启代理的端口号,这里7890是Clash默认端口号
ProxyCommand connect -S 127.0.0.1:7890 -a none %h %p
Host github.com
port 443
User git
HostName github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa_github
# 添加下面这一行,端口号为你开启代理的端口号,这里7890是Clash默认端口号
ProxyCommand connect -S 127.0.0.1:7890 -a none %h %p
本地Git误操作恢复记录
写完代码后,为了整理零散提交记录,于是对提交记录进行整合。图方便使用TortoiseGit处理,操作过过程中准备合并,本来是计划将两次提交合并成一个提交,但是不知道是出了bug还是怎样,跟平时弹出的处理窗口不一样。我也没注意直接跳过了,结果我的提交记录莫名其妙回到最初改动,看代码也已经回退了。瞬间汗流浃背了。。
这个场面还是第一次处理,而且没有手动备份,马上先备份了一下,但是小海龟上完全没有我的操作记录(其实就在show log下面,只是平时从来没用过),本来以为凶多吉少了,搜索后发现有类似问题,参考哗啦啦的yu的文章解决3
本质上就是我的代码还在本地,虽然提交了commit但是没有提交到远程仓库。当执行了reset或切换分支后git log就找不到之前的commit记录了(git log只显示当前HEAD可达的提交,reset后 HEAD移动了,所以看不到)。
这里的关键,查看历史操作:
cmd:git reflog # 这个记录了所有HEAD变更历史(每次commit、reset、checkout、merge、rebase都会被记录),这些记录会保留一段时间(默认90天)
Tortoise:右键 -> TortoiseGit -> Show Reflog
$ git reflog
df94c77 (HEAD -> master) HEAD@{0}: reset: moving to df94c7753803a58aedcc1d8037abad5b2edc433c
b3d9917 HEAD@{1}: commit: <feature> 某硬件小板适配,包括IO点位、功能、BSP修改(表驱动形式)
df94c77 (HEAD -> master) HEAD@{2}: commit: <feature> GBK改UTF8
3cc4ad6 HEAD@{3}: commit: <feature> 新增内容
cc628f1 HEAD@{4}: commit (amend): <feature> 针对硬件型号区分工程管理
747d27d HEAD@{5}: commit: <feature> 硬件管理
5098a68 (origin/master, origin/HEAD) HEAD@{6}: commit: <fix> 同步编译配置改动
622118e HEAD@{7}: commit: <feature> 增加自动编译脚本
9eba305 HEAD@{8}: commit: <feature> 实现cmake+gcc+jlink编译调试功能
4ef4879 HEAD@{9}: commit: <fix> 适配readme.md
4580ddc HEAD@{10}: commit: <feature> 初版
a77e532 HEAD@{11}: clone: from https://gitee.com/yourname/your-project.git
可以看到HEAD@{0}这一行——我刚执行了reset,现在HEAD指向了df94c77,而我要找的b3d9917已经不在当前分支的历史里了。
虽然这个提交不再当前分支历史里,但它仍存在与Git的数据库种,只要reflog里有记录,就还能恢复。
恢复方法:直接reset回去:
git reset --hard b3d9917
如果误操作了且没有发现,可能需要使用cherry-pick命令:
git cherry-pick b3d9917 #这会把b3d9917的改动作为一个新补丁应用到当前HEAD上。
总结:在不确定操作会造成什么后果时,记得先备份!
参考资料
-
Wrysmile0308. (2023). 使用Git时报错Connection reset by 20.205.243.166 port 22. https://blog.csdn.net/Wrysmile0308/article/details/128801870 ↩
-
fK0pS. (2019). 解决 Failed to connect to github.com port 443:connection timed out. https://blog.csdn.net/Hodors/article/details/103226958 ↩
-
哗啦啦的yu. (2025). Git提交丢失?别慌!手把手教你用git reflog找回“消失的代码”. https://juejin.cn/post/7478893378035433508 ↩