Git 学习笔记
本文整理版本控制、Git 的基本概念、常用命令、分支工作流及故障排查。示例中的仓库地址、分支名和文件路径需按实际环境替换。
版本控制
版本控制工具
主流版本:
- Git
- SVN(subversion)
- CVS
- VSS
- TFS
版本控制分类
- 本地版本控制:版本历史保存在本机。
- 集中式版本控制(如 SVN):中央服务器保存主要版本历史,团队通过服务器共享变更。通常需要连接服务器才能同步或提交。
- 分布式版本控制(如 Git):每个克隆仓库都保存项目的提交历史,可以在本地提交、查看历史和创建分支;与其他成员协作时再通过远程仓库交换提交。
Git 基本概念
工作区、暂存区与仓库

- 工作区(working tree):实际编辑文件的目录。
- 暂存区(index / staging area):记录下一次提交准备包含的内容。
- 本地仓库(repository):保存提交历史和对象,通常位于
.git目录。 - 远程仓库(remote):用于与其他人共享提交的仓库,例如 GitHub 上的仓库。
基本工作流程
- 从远程仓库克隆项目。
- 在工作区新增、修改或删除文件。
- 使用
git add将变更加入暂存区。 - 使用
git commit在本地创建提交。 - 使用
git push将本地提交推送到远程仓库。

文件状态
| 状态 | 含义 |
|---|---|
| Untracked(未跟踪) | 文件尚未加入 Git 跟踪;git add 后可进入暂存区。 |
| Unmodified(未修改) | 已跟踪文件与当前提交一致。 |
| Modified(已修改) | 已跟踪文件在工作区发生变化,尚未暂存该变化。 |
| Staged(已暂存) | 变更已加入暂存区,准备在下次提交中保存。 |
git rm 会将删除操作加入暂存区;提交后,该文件才不再被跟踪。取消暂存可用 git restore --staged <文件路径>;丢弃工作区中尚未暂存的修改可用 git restore <文件路径>。后者会丢失对应的工作区修改。
git status
git status -- <文件路径>
Git 配置
# 查看当前生效的配置及其来源
git config --list --show-origin
# 查看或编辑系统级配置
git config --system --list
git config --system --edit
# 查看或编辑用户级配置
git config --global --list
git config --global --edit
# 设置提交身份
git config --global user.name "你的姓名"
git config --global user.email "you@example.com"
创建与连接仓库

创建仓库
初始化当前目录,或从远程克隆仓库:
git init
git clone <仓库地址>
git init 会创建用于保存仓库元数据的 .git 目录;git clone 会取得远程仓库可访问的提交历史。
配置分支和远程仓库
git branch -M main
git remote add origin https://github.com/hangx969/Scripts.git
git branch -M main 会将当前分支重命名为 main;仅在需要时使用。添加前可先运行 git remote -v 检查是否已有 origin。
更换远程仓库地址
需要将 HTTPS 地址改为 SSH 地址时:
git remote -v
git remote set-url origin git@github.com:hangx969/Scripts.git
使用 SSH 连接 GitHub
- 在 GitHub 账号中添加本机 SSH 公钥。
- 克隆时使用 SSH 地址,或将现有 remote 改为 SSH 地址。HTTPS 连接也可用凭据管理器或访问令牌认证,无须每次手动输入凭据。

git remote add origin git@github.com:hangx969/k8s-platform-tools.git
git remote -v
已有 origin 时,使用 git remote set-url origin <SSH 地址>,不要再次执行 git remote add。
Git 分支管理
查看分支
# 查看本地分支
git branch
# 查看远程分支
git branch -r
# 查看本地远程所有分支的汇总
git branch -a
更新远程跟踪分支
# 从远程拉取最新的分支/标签信息到本地,顺手清理本地那些"远程已经删除"的origin/xxx分支
git fetch -p
删除本地分支
git branch -d xxx
注意
-d:仅在分支已完全合并到其上游分支(未设置上游时为当前分支)时删除。-D:无论是否合并都删除分支引用;未合并的提交可能因此难以找回。
删除远程分支
git push origin --delete feature-x
分支工作流程
以下以 main 为主分支、dev 为开发分支。实际分支名称和合并策略以仓库约定为准。
- 切换到主分支并获取最新提交:
git switch main
git pull --rebase origin main
- 创建并切换到开发分支:
git switch -c dev
- 暂存、提交并首次推送分支:
git add <文件路径>
git commit -m "描述更改"
git push -u origin dev
查看历史与恢复修改
git log # 查看提交记录
git status # 查看工作区与暂存区状态
git diff -- <文件路径> # 查看尚未暂存的修改
git diff --staged # 查看已暂存的修改
git restore -- <文件路径> # 丢弃未暂存的工作区修改
git restore --staged <文件路径> # 取消暂存
重置与强制推送
git reset --hard 会丢弃已跟踪文件的未提交修改;git reset --hard <commit-id> 还会移动当前分支。重写已共享历史后可能需要 git push --force-with-lease,执行前应与协作者协调并确认目标分支。
常用开发流程
初始化本地仓库并连接远程
如果远程仓库已有提交,优先直接克隆:
git clone <仓库地址>
如果是在已有本地项目中初始化 Git,再添加远程仓库:
git init
git remote add origin <仓库地址>
git fetch origin
确认本地与远程的提交历史关系后,再选择合并或变基。
将本地更改推送到远程
git status
git switch -c aaa-bbb-ccc # 如需新分支,先创建并切换
git add <文件路径> # 按需暂存文件;git add . 会暂存当前目录下的变更
git commit -m "描述更改"
git push -u origin aaa-bbb-ccc # 首次推送并设置上游分支
设置上游分支后,在该分支上通常可直接使用 git push。
合并 Pull Request
将开发分支推送到远程后,可在代码托管平台创建并合并 Pull Request。常见策略:
- Rebase and merge:将 PR 的提交逐个重放到目标分支,通常不创建合并提交。
- Merge commit:创建合并提交,保留分叉与合并的历史。
- Squash and merge:将 PR 的变更压缩为一个提交后合并。
GitHub 和 Azure DevOps 的实际按钮名称、可用策略及分支保护规则可能不同,应以仓库配置为准。
更新本地主分支
远程 PR 合并后,切换到本地 main 并同步:
git switch main
git pull --rebase origin main
确认开发分支已合并且不再需要后,再用 git branch -d aaa-bbb-ccc 删除本地分支。
将 main 的更新纳入开发分支
开发期间如果远程 main 有新提交,可在推送开发分支前同步:
git switch dev
git fetch origin
git rebase origin/main # 将 dev 的提交重放到最新 main 之后
# 或使用 git merge origin/main,保留合并历史
rebase 会改写当前分支上的提交;如果分支已由多人共享,应先协调。若发生冲突,解决后运行 git add <文件路径> 和 git rebase --continue。
为提交打标签
标签用于标记某个特定提交,常用于发布版本,但不一定代表破坏性变更。以下示例在 PR 合并后给最新的 main 提交打标签:
git switch main
git pull --rebase origin main
git tag 0.4.1
git push origin 0.4.1
历史与跟踪清理
重建提交历史
会重写历史
以下操作会改变目标分支的提交历史。先备份仓库并与协作者协调;受保护分支可能禁止强制推送。远程旧对象、其他分支、标签和协作者的克隆不会因重建 main 自动清除。
如果只想让 main 从一个新提交开始,可在仓库中创建孤立分支:
git switch --orphan new-main
git add -A
git commit -m "Initial commit"
git branch -M main
git push --force-with-lease origin main
在确认新分支可用后,再处理不再需要的本地分支。若需从所有相关历史中移除某个文件,应使用 git-filter-repo 等历史重写工具,并处理其他分支、标签和远程副本;仅重建 main 不足以完成全库清理。
重新初始化本地仓库
如果需要舍弃本地仓库元数据并从当前文件重新创建初始提交,可以删除 .git 后重新初始化。此操作会清除本地分支、标签、配置和提交历史;先备份仓库,并确认不需要这些记录。
cd <仓库目录>
rm -rf .git
git init
git config user.name "你的姓名"
git config user.email "you@example.com"
git add -A
git commit -m "Initial commit"
git branch -M main
git remote add origin <远程仓库地址>
git fetch origin main
git push --force-with-lease origin main
这只会重建并更新目标分支;其他远程引用及协作者的克隆不会自动清理。
停止跟踪已被忽略的文件
.gitignore 只会忽略尚未被跟踪的文件;已提交文件需要先从索引中移除,再提交删除记录:
# 先在 .gitignore 中添加相应规则
git rm -r --cached -- Python/python-manuscripts
git commit -m "Stop tracking Python/python-manuscripts files"
git push origin main
--cached 保留工作区文件。不要在后续执行 git add 把这些文件重新纳入跟踪。
Git 代理配置
HTTP(S) 代理
Git 的 http.proxy 配置可用于 HTTP 与 HTTPS 传输。按需设置代理,完成后再移除:
git config --global http.proxy 'socks5://127.0.0.1:7890'
git config --global --unset http.proxy
SSH 代理
SSH 连接使用 ~/.ssh/config 中的 ProxyCommand。以下示例仅针对 github.com,端口需与本机代理一致:
Host github.com
ProxyCommand nc -X 5 -x 127.0.0.1:7890 %h %p
如果 Host github.com 已有身份或端口配置,将这一行加入现有配置块。
常用工具与资源
- 图形客户端:GitKraken、TortoiseGit(Windows)、Fork、Sourcetree。
- 编辑器扩展:VS Code 的 Git Graph。
- 交互式练习:Learn Git Branching。
- 命令别名:可按需使用 Zsh 的 Git 插件。
Git 操作练习
以下练习以默认分支 main、文件 myfile.txt 为例,按顺序演示提交、分支、合并、变基和远程操作。练习素材:Git 教程、视频教程。
初始化与第一次提交
git config --global user.name "你的姓名"
git config --global user.email "you@example.com"
git init
git branch -M main
# 创建并编辑 myfile.txt
git status
git add myfile.txt
git commit -m "first commit"
git log --oneline
可使用 git <子命令> -h 查看简要帮助,或使用 git help <子命令> 打开完整手册。
创建、合并与删除分支
git switch -c issue1
# 修改 myfile.txt
git add myfile.txt
git commit -m "add new content"
git switch main
git merge issue1
git branch -d issue1
此时若 main 没有独立的新提交,合并通常是快进合并。
并行修改与冲突
git switch -c issue2 main
# 修改 myfile.txt 并提交
git add myfile.txt
git commit -m "add content from issue2"
git switch -c issue3 main
# 修改同一位置并提交
git add myfile.txt
git commit -m "add content from issue3"
git switch main
git merge issue2
git merge issue3
如果两条分支修改了同一位置,第二次合并可能产生冲突。手动编辑文件,移除冲突标记并确定最终内容,然后完成合并:
git add myfile.txt
git commit
练习变基
在独立的练习仓库中,可重新构造上述两条分支,从冲突发生前的状态尝试变基。不要在包含未保存工作的仓库中为练习执行 git reset --hard。
git switch issue3
git rebase issue2
# 如遇冲突,编辑 myfile.txt 后继续
git add myfile.txt
git rebase --continue
# 如果要放弃变基,使用 git rebase --abort
变基成功后,可切回 main 并合并 issue3;如果 main 指向 issue2 的提交,通常可以快进合并。变基会改变提交 ID。
连接 GitHub 远程仓库
先在 GitHub 创建仓库,再在本地配置远程地址并推送:
git remote add origin https://github.com/cengxiye/learn-git-2024.git
git push -u origin main
-u 用于设置上游分支,之后在该分支上通常可直接执行 git push 或 git pull。GitHub 仓库页面还提供 About、Issues、Actions、Projects、Wiki、Security、Insights、Settings 和 Releases 等功能。
推送、拉取与克隆
# 修改 myfile.txt 后提交并推送
git add myfile.txt
git commit -m "change file, to be pushed to origin"
git push
# 获取远程更新并整合到当前分支
git pull
# 只获取远程信息,再比较本地与远程分支
git fetch
git diff main origin/main
# 首次获取另一个仓库
git clone https://github.com/cengxiye/sid.github.io.git
git fetch 只获取远程提交和引用,不会自动整合到当前分支;git pull 会先 fetch,再按参数或配置采用快进、合并或变基等方式整合。git clone 用于创建新的本地仓库副本。
故障排查
大文件导致推送失败
如果 GitHub 拒绝包含超限文件的推送,即使工作区已经删除该文件,只要待推送的提交历史仍包含它,推送仍可能失败。先确认报错指出的文件路径,再决定是改用 Git LFS,还是在备份并协调协作者后使用 git-filter-repo 从相关历史中移除它。历史重写后还需检查其他分支、标签和已有克隆。
如果 git pull 出现以下错误,不要直接认定为文件过大:
fetch-pack: unexpected disconnect while reading sideband packet
fatal: early EOF
fatal: fetch-pack: invalid index-pack output
这类错误也可能来自网络中断、代理或传输链路问题。先重试并检查网络、代理及远程服务状态;不要为排查而关闭 TLS 证书校验。
GitHub SSH 22 端口连接超时
出现 ssh: connect to host github.com port 22: Connection timed out 时,先检查 SSH 调试输出:
ssh -vT git@github.com
如果确认是 22 端口被网络阻断,可按 GitHub 官方方案尝试 ssh.github.com 的 443 端口:
ssh -T -p 443 git@ssh.github.com
测试成功后,在 ~/.ssh/config 中配置:
Host github.com
HostName ssh.github.com
User git
Port 443
再次执行 ssh -T git@github.com 验证身份。GitHub 返回“successfully authenticated”且提示不提供 shell 访问时,说明 SSH 认证成功。配置前若已有 Host github.com 块,应合并设置,避免覆盖原有的 IdentityFile 等选项。
多 GitHub 账号的 SSH 密钥冲突
问题背景
在同一台机器上配置了多个 GitHub 账号的 SSH 密钥(例如工作账号 ds-hangxu 和个人账号 hangx969),push 个人仓库时报错:
ERROR: Permission to hangx969/learning-notes.git denied to ds-hangxu.
fatal: Could not read from remote repository.
Please make sure you have the correct access rights and the repository exists.
原因可能是 SSH 在连接时提供了工作账号的密钥,GitHub 因而将连接识别为没有该仓库权限的工作账号。可以用 ssh -vT git@github.com 查看实际尝试的密钥。
解决办法
- 修改
~/.ssh/config,为不同账号配置不同的 Host 别名,并使用IdentitiesOnly yes指定密钥:
# 工作账号
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_ds_github
IdentitiesOnly yes
# 个人账号
Host github-personal
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
- 将个人仓库的 remote URL 改为使用别名:
cd ~/github-repo/learning-notes
git remote set-url origin git@github-personal:hangx969/learning-notes.git
- 验证连接身份:
# 验证工作账号
ssh -T git@github.com
# Hi ds-hangxu! You've successfully authenticated...
# 验证个人账号
ssh -T git@github-personal
# Hi hangx969! You've successfully authenticated...
- 按仓库流程提交并推送更改。
关键点
IdentitiesOnly yes是关键配置,确保 SSH 只使用指定的密钥文件,不会尝试 ssh-agent 中的其他密钥。- Host 别名(如
github-personal)仅用于 SSH 路由,Git 实际连接的仍然是github.com。 - 需要使用个人密钥的仓库,应将相应 remote URL 的主机名改为
github-personal。