Git 入门学习笔记

2026-05-05 第一次完整学 Git,记录全程知识点和踩坑经历。

一、Git 到底是什么

Git 是一个版本管理工具,核心就是给文件夹打"快照":

1
2
你写代码 → git add → 暂存区 → git commit → 本地仓库 → git push → 远程仓库
存草稿 准备提交 打完收工 备份到服务器
  • "快照"就是某时刻你所有文件的状态
  • 打一次快照 = 一个 version
  • 以后可以随时回到任意一个旧版本

二、第一步:初始化仓库

1
2
cd E:\project\物理动画9
git init

执行完之后,这个文件夹里多了一个 .git 隐藏文件夹。这就是 Git 的"小本本",里面记着所有版本信息。

💡 不要删 .git 文件夹,删了就什么都没了。


三、配置身份(为什么需要?)

你遇到的报错:

1
2
Author identity unknown
fatal: unable to auto-detect email address (got 'jerry@Jerry.(none)')

Git 不认识你是谁。每次 git commit 都会在记录里写下是谁提交的,像这样:

1
2
3
4
commit a1b2c3d4e5f6...
Author: 小熙 <xiaoxi@example.com>
Date: 2026-05-05
解决动滑轮转向Bug

如果不配置,Git 就不知道写谁的名字。

解决方法:

1
2
git config --global user.name "小熙"
git config --global user.email "xiaoxi@example.com"

--global 的意思是这台电脑上所有 Git 项目都用这个配置,只配一次就行。如果去掉 --globalgit config --local),那就只对当前项目生效。

💡 如果用 GitHub,邮箱要和 GitHub 注册邮箱一致,这样 GitHub 能正常显示你的头像和提交记录。


四、.gitignore —— 排除不该提交的文件

为什么需要它

git add . 会把所有文件都加到暂存区。但有些文件不应该被 Git 管理:

文件 为什么不该提交
node_modules/ 里面有成百上千个包,又大又没用。别人拉代码后 npm install 就有
tmp_* 临时测试文件,只在你电脑上有意义
*.log 日志文件
.DS_Store Mac 系统的缓存文件

第一个大坑:Notepad 创建 .gitignore

1
notepad .gitignore

结果: Notepad 给文件名加了 .txt 后缀,变成了 .gitignore.txt。但你检查的时候只看得到 .gitignore(Windows 默认隐藏已知扩展名)。

所以虽然你写了内容,但实际文件是 .gitignore.txt,Git 压根没读取它。

💡 正确做法:直接用 PowerShell 创建,不要用 Notepad。

第二个大坑:PowerShell 的 > 编码问题

1
echo "node_modules/" > .gitignore

PowerShell 的 >(其实是 Out-File 的别名)默认输出 UTF-16 LE with BOM 编码。但 Git 只认 UTF-8 without BOM。所以 Git 虽然读到了文件名 .gitignore,但看不懂里面的内容——等于没写。

要记得,Windows 里常见的"文本文件"可能有好几种编码:

编码 Git 能否识别
UTF-8 without BOM ✅ 能
UTF-8 with BOM ⚠️ 部分场景会翻车
UTF-16 LE with BOM ❌ 不能,PS 默认输出这个
ANSI/GBK ⚠️ 含中文可以,但不推荐

正确的创建方法

1
2
3
4
5
6
7
8
9
10
11
12
13
# 方法一:Set-Content 指定 UTF-8(推荐)
@"
node_modules/
tmp_*
.DS_Store
*.log
"@ | Set-Content .gitignore -Encoding UTF8

# 方法二:通过 cmd 的 echo 绕开 PS 编码
cmd /c "echo node_modules/> .gitignore"
cmd /c "echo tmp_*>> .gitignore"
cmd /c "echo .DS_Store>> .gitignore"
cmd /c "echo *.log>> .gitignore"

检测它是否生效

1
git check-ignore -v node_modules/随便一个文件

这段命令的意思是"检查 node_modules 里的某个文件是否被忽略规则匹配到了":

  • 有输出 比如 .gitignore:1:node_modules/ node_modules/xxx → ✅ 生效了
  • 没输出 → ❌ 没生效,要么文件名不对、要么编码不对、要么路径不对

第三个大坑:文件已经被跟踪了,.gitignore 管不了

这是新手最容易晕的地方。.gitignore 的规则是:

只对「还没有被 Git 跟踪」的文件生效。

如果你先 git add .node_modules/ 加进去了,然后再创建 .gitignore 写上 node_modules/,但这时 node_modules/ 已经被 Git 记住(跟踪)了,.gitignore 拦不住它。

你需要先把它们从 Git 的"花名册"里移除:

1
git rm -r --cached .

这条命令是什么意思:

部分 含义
git rm 移除文件
-r 递归(recursive),包括子文件夹
--cached 只从 Git 的缓存/跟踪列表里删,不删你硬盘上的原文件
. 所有文件

💡 这个 .git add . 里的 . 是同一个意思,表示"当前目录"

但你可能遇到这个报错:

1
2
error: the following file has staged content different from both the
file and the HEAD: .gitignore

为什么: .gitignore 这个文件本身在暂存区里有一份(之前 git add 过的),而你后来又修改了它(编辑内容),所以 Git 检测到"暂存区里的版本"和"硬盘上的版本"不一样,为了安全拒绝直接移除。

解决:-f(force)

1
git rm -r --cached -f .

然后用 .gitignore 过滤好的内容重新加入:

1
git add .

此时 node_modules/tmp_* 应该都不在里面了(用 git status 确认)

巨坑:core.excludesFile 干扰

为了解决 .gitignore 不生效的问题,我教你设了一个配置:

1
git config --local core.excludesFile "$PWD\.gitignore"

本意是"显式告诉 Git 从哪个文件读忽略规则"。但设了这个之后,反而让 Git 的行为变得奇怪——它可能覆盖了默认的 .gitignore 查找逻辑。最后用 --unset 删掉就好了:

1
git config --local --unset core.excludesFile

教训: .gitignore 不需要任何额外配置。把它放在项目根目录,Git 会自动读取。不要画蛇添足。


五、.gitattributes —— 换行符问题

为什么 Git 会烦你

Windows 和 Linux/Mac 用不同的换行符:

系统 换行符 说明
Windows CRLF(\r\n 回车+换行,占两个字符
Linux/Mac LF(\n 换行,一个字符

Git 默认有一个设置 core.autocrlf=true,意思是:

"你在 Windows 上干活?那我帮你把仓库里的 LF 文件转成 CRLF 放你硬盘上,这样你用 Windows 记事本不会乱。"

你看到的报错:

1
warning: in the working copy of 'node_modules/wrappy/LICENSE', LF will be replaced by CRLF the next time Git touches it

这个 warning 本身不是错误,但刷几百条很烦人。

为什么不建议直接关掉 core.autocrlf

1
git config --global core.autocrlf false

关掉当然可以,但只对你这一台电脑有效。如果其他人 clone 这个项目,操作系统不同(Mac / Linux / Windows),换行符行为还是不一样,可能有人用 Windows 提交了 CRLF,有人用 Mac 提交了 LF,混在一起就很乱。

行业标准做法:.gitattributes

在项目根目录创建一个 .gitattributes 文件,放在项目里,任何电脑上 clone 都会自动遵守

1
2
3
4
5
6
7
8
9
10
11
12
@"
# 所有文本文件默认 LF(不在 autocrlf 控制下)
* text eol=lf

# 二进制文件(别碰)
*.png binary
*.jpg binary
*.gif binary
*.ico binary
*.woff binary
*.woff2 binary
"@ | Set-Content .gitattributes -Encoding UTF8

逐行详细解释:

第一行:* text eol=lf

1
2
3
4
5
*        text         eol=lf
│ │ │
│ │ └─ 统一用 LF(\n)换行
│ └─ 标记为「文本文件」
└─ 匹配规则,* 代表「所有文件」

这行是整个文件的核心。拆开看:

部分 作用
* 通配符,匹配所有文件——不管后缀是什么(.js.ts.tsx.py.json.md.html.css.scss.env.yml.toml.sh.c.cpp……甚至没有后缀的文件如 .gitignoreMakefileDockerfile),全部命中
text 告诉 Git:这是一个文本文件,不是二进制文件。Git 会对其做 diff、merge、统计行数等操作
eol=lf 强制指定换行符为 LF。无论 clone 到 Windows、Mac 还是 Linux,工作目录里都是 \n任何系统都不会弹换行符 warning

💡 为什么不用 * text=auto

auto 只是让 Git 自动猜一个文件是不是文本,但换行符仍然受 core.autocrlf 影响,Windows 上照弹 warning。 eol=lf直接锁死,不受 autocrlf 干扰。

后续几行:*.png binary

1
2
3
4
*.png       binary
│ │
│ └─ 标记为「二进制文件」
└─ 所有 .png 文件
部分 作用
*.png 匹配所有 .png 后缀文件
binary 告诉 Git:这是二进制文件,不要动它。Git 不会尝试换行符转换,不会做文本 diff(只在 commit 里存 hash),也不会在 git diff 时显示内容

图片、字体文件如果被当作文本处理,里面的二进制字节会被换行符转换破坏,导致文件损坏。所以必须标 binary

这条规则覆盖了哪些文件

因为第一行是 * text eol=lf(星号匹配所有),所以你的项目里:

类型 举例 是否被 * 覆盖
JavaScript app.js, utils.mjs
TypeScript page.ts, layout.tsx
JSON package.json, tsconfig.json
Markdown README.md
CSS globals.css, tailwind.scss
HTML index.html
配置文件 .gitignore, .env, .env.example, .prettierrc, .eslintrc, next.config.mjs
Shell/Python/C setup.sh, main.py, app.c
无后缀文件 Makefile, Dockerfile
图片 logo.png, bg.jpg ⚠️ 被 * 命中过,但下面 *.png binary 覆盖了

关键点:不需要单独列每种文件类型* 通配符一网打尽,只有二进制文件需要单独标 binary 来排除。

设置完后执行:

1
git add --renormalize .

这会扫描所有文件,按 .gitattributes 的规则统一换行符。之后 git add . 就不会再刷换行符警告了。

设置前后对比

改之前 改之后
警告方向 LF will be replaced by CRLF CRLF will be replaced by LF
含义 要把 LF 转成 Windows 的 CRLF 要把 CRLF 转成 Linux 的 LF
仓库存储 可能混着 CRLF 和 LF 统一 LF ✅

可以看到警告仅在第一次 git add --renormalize 时出现一次,之后就没有了。

LF 在 Windows 上会不会出问题

以前只有老版 Windows 记事本不认识 LF(打开全挤在一行)。现代编辑器(VS Code、WebStorm、Sublime Text、Notepad++)全部兼容 LF,完全没有问题。所以放心用。


六、提交(commit)

做好了 .gitignore.gitattributes 之后:

1
2
git add .
git commit -m "解决动滑轮的运行一些bug"

-m 后面写备注,描述这次改了什么。好的备注习惯:

不好
"更新" "修复动滑轮钩子转向Bug"
"改了好多" "添加 15 个测试场景,修复浮点溢出"
"final" "添加 .gitignore 排除 node_modules"

七、查看状态和历史

git status(最常用)

1
git status

告诉你当前工作目录和暂存区的状态。看到:

  • "Changes to be committed" → 已经 git add 了在等 commit
  • "Changes not staged for commit" → 改了但没 add
  • "Untracked files" → 新增文件,还没让 Git 管

git log

1
2
git log
git log --oneline # 简洁版,一行一个提交
1
2
3
a1b2c3d 解决动滑轮转向问题
e4f5g6h 添加测试场景
j7k8l9m 初始提交

最左边那串乱码(a1b2c3d)是 commit hash,版本号。以后回滚、对比、查看都要用到它。

git log 进阶用法

1
2
3
4
5
6
7
8
# 只看最近 3 次提交
git log -3

# 图形化查看分支结构
git log --oneline --graph --all

# 查看某个文件的修改历史
git log --follow 文件名.js

八、回滚操作(详细版)

先说说 commit 的结构

每次 git commit 就是一个快照。用 git log --oneline 可以看到一串提交历史:

1
2
3
a1b2c3d (HEAD -> main) 解决动滑轮转向问题
e4f5g6h 添加测试场景
j7k8l9m 初始提交
  • 最左边那串乱码(a1b2c3d)叫 commit hash,Git 自动生成的唯一编号
  • HEAD 是一个指针,永远指向你当前所在的版本
  • main主分支的名字
  • HEAD -> main 表示你在 main 分支上,当前在 a1b2c3d 这个版本

场景 1:改坏了还没 commit

你改了一堆代码,但还没 git add 也没 git commit,想回到之前的安全状态:

1
git checkout .

这个点 . 代表当前目录所有文件。git checkout 的意思是"把工作目录里的文件替换成上一次 commit 的版本"。

或者只恢复某个文件:

1
git checkout 文件名.js

场景 2:刚 commit 了,发现写错了

1
git reset --soft HEAD~1
部分 含义
reset 重置
--soft 温和模式,只动 commit 记录,不动你的修改
HEAD 当前版本(那个短横线箭头)
~1 往前一个版本

git reset --soft HEAD~1 的意思是:撤回最近一次 commit,但保留所有代码变更。你还可以继续改,改好了重新 git add . && git commit

如果不想要改了,暴力模式:

1
git reset --hard HEAD~1

--hard 连文件修改一起丢掉。慎用!这个没法找回。

场景 3:回到了错误的版本想回来

如果不小心 git reset --hard 回错了,想恢复最后一次 commit:

1
git reflog

git reflog 会显示所有的 HEAD 移动记录,包括你 reset 之前的那个位置:

1
2
3
a1b2c3d HEAD@{0}: reset: moving to HEAD~1
e4f5g6h HEAD@{1}: commit: 解决动滑轮转向问题 ← 原来在这里
j7k8l9m HEAD@{2}: commit: 添加测试场景

找到你想要的 commit hash,然后 git reset --hard 回去:

1
git reset --hard e4f5g6h

⚠️ git reflog 只能找回几天内的记录。git reflog 没有时效,只在你删掉 .git 文件夹时才会丢失。

场景 4:回到很久以前的某个版本

1
git checkout a1b2c3d

这会进入"detached HEAD"状态(游离状态),意思是"你回到了历史版本看看,不在主分支上了"。

当你在 detached HEAD 状态下,千万不要修改文件并 commit! 如果这样做了:

1
2
a1b2c3d (HEAD)
e4f5g6h (main)

你的新 commit 没有挂在任何分支上,切回 main 后就找不到了。要提交的话应该先建一个分支:

1
2
3
git checkout a1b2c3d
git switch -c 旧版本修复
# 现在可以修改了,这个分支叫"旧版本修复"

看完了想回来:

1
git checkout main

场景 5:安全撤销某个历史提交(推荐)

1
git revert a1b2c3d

git revert 不会删掉那个提交,而是创建一个反向操作的提交

比如你的历史是:

1
2
3
a1b2c3d 添加了一个危险功能
e4f5g6h 优化性能
j7k8l9m 初始提交

执行 git revert a1b2c3d 后:

1
2
3
4
新提交   撤销:添加了一个危险功能
a1b2c3d 添加了一个危险功能
e4f5g6h 优化性能
j7k8l9m 初始提交

历史不会丢失,只是多了一个"反着做的提交"。团队协作时推荐用 revert 而不是 reset,因为 reset 会改写历史,别人已经拉下去的话会冲突。

场景 6:先看改了啥再决定要不要回滚

1
2
3
4
5
6
7
8
# 还没 add:看看改了什么
git diff

# 已经 add 了:看看暂存区里改了什么
git diff --cached

# 和某个历史版本对比
git diff a1b2c3d

对比结果示例:

1
2
- console.log("调试用")    ← 红色:删掉的
+ alert("正式版") ← 绿色:新增的

场景 7:暂时存起来,不想提交

你正在改代码,突然要切出去干别的事,但改到一半不想 commit:

1
git stash

你的修改被"藏"起来了,工作目录恢复到干净的 commit 状态。

想找回来:

1
git stash pop

场景 8:打标签 —— 标记重要版本

1
2
git tag v1.0
git tag v1.0-beta

以后回到这个版本:

1
git checkout v1.0

推送到远程:

1
2
git push origin v1.0      # 推送单个标签
git push origin --tags # 推送所有标签

回滚总结

情况 命令 影响
改坏了没 commit git checkout . 全盘恢复,改动全丢
只恢复一个文件 git checkout 文件名 该文件回到 commit 状态
刚 commit 想重来 git reset --soft HEAD~1 commit 撤回,改的代码还在
commit 和改动都扔 git reset --hard HEAD~1 找不回代码
reset 回错了 git reflog 找到旧 hash 只要记得哈希值就能恢复
安全撤销历史提交 git revert 版本号 新增反向提交,不删历史 ✅
先看改了啥 git diff / git diff --cached 对比改动,不实际执行
暂存(不提交) git stash / git stash pop 藏起来 / 拿回来
打标签标记版本 git tag v1.0 稳定版本的锚点

九、远程仓库(详细版)

什么是远程仓库

远程仓库就是"另一台电脑上存的 Git 仓库"。你的代码在本地,同时存一份到远程(GitHub / 阿里云)作为备份和协作点。

git push = 本地推到远程 git pull = 从远程拉到本地 git clone = 从远程完整复制一个仓库到本地(第一次拉)

9.0 认证方式:HTTPS + Access Token

远程仓库有两类地址格式:

1
2
HTTPS 格式:https://git.shinebook.net/用户/仓库.git
SSH 格式: git@git.shinebook.net:用户/仓库.git

SSH 需要配密钥对,临时电脑上比较麻烦。HTTPS + Access Token 更简单。

什么是 Access Token?

Token 就是一个临时代替密码的字符串。大多数 Git 托管平台(GitHub、Gitea、GitLab 等)都支持。

和密码比的区别: | | 密码 | Token | |------|------|------| | 永久有效 | ✅ | 可以设有效期 | | 权限控制 | 全权 | 可以限制只读/只写/某些仓库 | | 泄露后 | 改所有服务 | 删掉这一个 Token 就行 | | 二次验证 | 可能要走 | 不需要 |

怎么创建 Token

Gitea(自建 Git 服务): 打开 https://你的域名/user/settings/applications,"生成新的令牌",勾选仓库读写权限,复制生成的 Token。

GitHub: Settings → Developer settings → Personal access tokens → Generate new token,勾选 repo 权限。

克隆时直接用 Token(推荐)

1
2
# 格式:用户名:Token@仓库地址
git clone https://space:e39f54776da4c1cb3e692441859bf0cd455200a8@git.shinebook.net/Galaxy/xxx.git

这样克隆后,origin 的 URL 里已经带了 Token,之后 git push / git pull 不用再输任何密码

如果已经克隆了,修改已有地址嵌入 Token

1
2
3
4
5
# 查看当前远程地址
git remote -v

# 把 Token 嵌入已有地址
git remote set-url origin https://用户名:Token值@git.shinebook.net/用户/仓库.git

另一个办法:让 Git 记住密码

1
git config --global credential.helper store

然后在第一次 push 时输入用户+Token,之后 Git 会存到本地文件(~/.git-credentials),不会再问。

⚠️ 这个文件是明文存的,只在你自己电脑上用,公共电脑不要开。

9.1 git remote 完整指令(详解)

git remote 管理本地的"远程仓库通讯录"。每个远程地址在本地的别名叫 origin 或你起的其他名字。

git remote -v(查看所有远程)

1
git remote -v

输出示例:

1
2
origin  https://github.com/用户名/项目.git (fetch)
origin https://github.com/用户名/项目.git (push)
  • (fetch) = 拉取时用的地址
  • (push) = 推送时用的地址
  • 两个通常一样,也可以配不一样

git remote add(添加新远程)

1
2
git remote add 别名 地址
git remote add origin https://git.shinebook.net/Galaxy/xxx.git
部分 含义
remote add "往通讯录里加一条"
origin 这条记录的别名——你想叫什么都行(别人习惯叫 origin)
https://... 实际的仓库地址

可以加多个远程

1
2
3
4
5
6
7
git remote add origin  https://github.com/xxx/xxx.git   # 叫 origin
git remote add gitea https://git.shinebook.net/xxx.git # 叫 gitea
git remote add aliyun root@服务器:/srv/git/xxx.git # 叫 aliyun

# 推到不同的远程
git push origin main # 推 GitHub
git push gitea main # 推你的 Gitea

💡 git remote add新建一条记录。如果 origin 已经存在,会报 fatal: remote origin already exists

git remote set-url(修改已有远程地址)

1
git remote set-url origin https://新地址.git

场景 1:换了服务器地址

1
2
# 比如从 HTTP 切到 HTTPS
git remote set-url origin https://git.shinebook.net/xxx.git

场景 2:URL 里嵌入 Token

1
2
3
# 原来:https://git.shinebook.net/Galaxy/xxx.git
# 改成带 Token 的,以后不用输密码
git remote set-url origin https://space:Token值@git.shinebook.net/Galaxy/xxx.git

git remote add vs set-url 核心区别

git remote add git remote set-url
干什么 新增一条通讯录 覆盖已有通讯录的地址
什么时候用 还没有 origin 已经有 origin,想改地址
origin 已存在 ❌ 报错 ✅ 静默覆盖

git remote rename(改别名)

1
2
git remote rename origin github
# 把 origin 改名叫 github

git remote remove(删除远程)

1
2
git remote remove gitea
# 从通讯录里删掉 gitea 这条记录

💡 只删本地记录,不会影响远程服务器上的仓库。

git remote show(查看某个远程详情)

1
git remote show origin

输出示例:

1
2
3
4
5
6
7
8
9
10
* remote origin
Fetch URL: https://git.shinebook.net/Galaxy/xxx.git
Push URL: https://git.shinebook.net/Galaxy/xxx.git
HEAD branch: main
Remote branch:
main tracked
Local branch configured for 'git pull':
main merges with remote main
Local ref configured for 'git push':
main pushes to main (up to date)

可以看到:fetch/push 地址、远程有哪些分支、本地分支和远程分支的对应关系。

第一步:在 GitHub 网页上创建空仓库

  1. 打开 github.com,登录
  2. 点右上角 +New repository
  3. 仓库名随便填(如 physics-animation-9
  4. 务必选 Private(私人仓库,别人看不到)
  5. 不要勾 "Add a README" / ".gitignore" / "license"
  6. Create repository

创建后 GitHub 会显示一个页面,上面有几行命令,那就是你要在本地执行的。

第二步:在本地关联远程仓库

1
git remote add origin https://github.com/你的用户名/physics-animation-9.git

这条命令做了什么? - git remote add = "添加一个远程地址" - origin = 给这个远程地址起的名字,习惯叫 origin(来源的意思) - https://... = 远程仓库的地址

起名的好处:以后不用再打一长串 URL,直接说 git push origin 就行。

第三步:把本地 main 分支推到远程

1
2
git branch -M main
git push -u origin main
  • -M = 强制改名(把默认分支名从 master 改成 main)
  • -u = 关联(--set-upstream),告诉 Git "以后这个本地 main 分支就和远程 origin 的 main 分支绑定了"
  • 设了 -u 之后,下次 git push 就可以直接 git push,不用再写 origin main

可能会遇到的登录问题:

1
2
3
4
5
6
7
8
9
10
# 如果用 HTTPS 方式,Git 会弹窗让你登 GitHub
# 现在 GitHub 不支持密码登录了,要用 Personal Access Token

# 在 GitHub 上生成 token:
# Settings → Developer settings → Personal access tokens → Generate new token
# 勾选 repo 权限,复制生成的 token

# 登录时用 token 当密码
Username: 你的GitHub用户名
Password: 粘贴你的token(不显示是正常的)

不想每次输密码可以缓存:

1
git config --global credential.helper store

第四步:后续日常推送

1
2
3
git add .
git commit -m "改了什么"
git push # 因为第一次 -u 了,所以不用写 origin main

9.2 推送到阿里云服务器

第一步:在服务器上初始化裸仓库(只需做一次)

1
2
3
4
ssh root@你的服务器IP
mkdir -p /srv/git/物理动画9.git
cd /srv/git/物理动画9.git
git init --bare

--bare (裸仓库)是什么意思?普通仓库既存代码文件也存版本历史,但远程仓库不需要"工作目录",它只需要接收 push 和提供 pull。--bare 就是「只有版本历史,不存代码文件」的仓库。

第二步:在本地添加远程地址

1
git remote add aliyun root@服务器IP:/srv/git/物理动画9.git

这次用的是 SSH 协议(root@IP:路径)而不是 HTTPS。好处:配了 SSH 免密登录后,每次 push 不用输密码。

第三步:推送到阿里云

1
git push aliyun main

第一次可能会提示输入服务器密码。不想每次都输的话,配 SSH 免密:

1
2
3
4
5
6
7
8
9
10
# 本地生成密钥(如果没有的话)
ssh-keygen -t ed25519 -C "你的邮箱"

# 查看公钥
type C:\Users\你的用户名\.ssh\id_ed25519.pub
# 复制输出的一整串内容

# 登录阿里云,粘贴公钥
ssh root@服务器IP
echo "你复制的那一串" >> ~/.ssh/authorized_keys

配好后 git push aliyun main 就不需要输密码了。

9.3 同时用 GitHub 和阿里云

1
git remote -v

会显示:

1
2
3
4
aliyun  root@服务器IP:/srv/git/物理动画9.git (fetch)
aliyun root@服务器IP:/srv/git/物理动画9.git (push)
origin https://github.com/用户名/physics-animation-9.git (fetch)
origin https://github.com/用户名/physics-animation-9.git (push)

两个远程地址都可以推:

1
2
git push origin main      # 推 GitHub
git push aliyun main # 推阿里云

9.4 git clone — 从远程下载仓库

如果你在另一台电脑上,想拉这个项目下来:

1
2
3
4
5
# 从 GitHub 下载
git clone https://github.com/用户名/physics-animation-9.git

# 从阿里云下载
git clone root@服务器IP:/srv/git/物理动画9.git

git clone 会自动: - 创建一个文件夹(名字和仓库名一样) - 初始化 .git - 拉下所有代码和版本历史 - 远程地址自动配好,直接就能 git push

9.5 git pull vs git fetch

命令 作用 区别
git fetch 从远程下载最新版本信息 不会自动合并到你当前的代码里
git pull 下载 + 自动合并 等于 git fetch + git merge
1
2
3
4
5
6
7
# 推荐新手先用 fetch 看看情况
git fetch origin # 下载远程的最新信息
git log --oneline main..origin/main # 看看远程比本地多了什么
git merge origin/main # 确认没问题后再合并

# 简单做法(一步到位)
git pull origin main # 下载 + 合并,一步完成

9.6 常见远程报错

报错 1:fatal: remote origin already exists

远程 origin 已经存在了。说明你已经 git remote add 过一次。要么用另一个名字,要么 set-url 覆盖:

1
git remote set-url origin https://github.com/用户名/项目名.git

报错 2:fatal: refusing to merge unrelated histories

本地仓库和远程仓库没有共同的提交历史。常见于你在平台上建仓库时勾选了 README / .gitignore。解决:

1
git pull origin main --allow-unrelated-histories

💡 以后建远程仓库不要勾任何初始文件,保持完全空仓。

报错 3:Updates were rejected because the remote contains work that you do not have locally

远程有本地没有的提交(别人推了,或者你换了电脑)。先 pull 再 push:

1
2
3
4
git pull origin main
# 如果有冲突,解决后
git add . && git commit
git push origin main

十、补充知识点

关于 2>/dev/null

1
git rm -r --cached tmp_* 2>/dev/null

2>/dev/null 是 Linux/Unix 的写法: - 2 = stderr(错误输出流) - > = 重定向 - /dev/null = Linux 黑洞,所有扔进去的东西都消失

意思: 把错误信息扔进黑洞,不显示。

但这个写法在 PowerShell 不兼容。PowerShell 里应该这么写:

1
git rm -r --cached tmp_* 2>$null

$null 是 PowerShell 里的"空"。或者更干脆不加,报错了才知道具体哪里不对。

关于 git config 的作用域

1
2
git config --global xxx    # 全局,这台电脑所有项目
git config --local xxx # 本地,仅当前项目

优先级:--local > --global。也就是说,项目自己的配置会覆盖全局配置。

查看当前所有配置:

1
2
3
git config --list
git config --list --local # 只看当前项目
git config --list --global # 只看全局

关于 .gitignore 已跟踪文件的解除

已跟踪的文件必须先 git rm -r --cached . 再从 Git 的花名册中移除,否则 .gitignore 对它们无效。加 -f 强制,加 . 表示所有文件。

--cached 不会删硬盘文件,只管解除跟踪。这是安全的。


十一、完整操作流程(下次新建项目直接照搬)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 1. 初始化
cd 你的项目文件夹
git init

# 2. 配置身份(如果还没配过)
git config --global user.name "小熙"
git config --global user.email "xiaoxi@example.com"

# 3. 创建 .gitignore
@"
node_modules/
tmp_*
.DS_Store
*.log
"@ | Set-Content .gitignore -Encoding UTF8

# 4. 创建 .gitattributes
@"
* text eol=lf
*.png binary
*.jpg binary
*.gif binary
"@ | Set-Content .gitattributes -Encoding UTF8

# 5. 首次提交
git add .
git commit -m "初始提交"

# 6. 推远程(选一个或两个都要)
git remote add origin https://github.com/用户名/项目名.git
git push -u origin main

十二、今天遇到的报错速查表

# 报错 / 现象 原因 解决
1 notepad .gitignore 找不到文件 Notepad 自动加了 .txt 后缀 用 PowerShell 创建
2 .gitignore 设了但没效果 > 输出 UTF-16 改用 Set-Content -Encoding UTF8
3 2>/dev/null 报错 PowerShell 不是 bash 改用 2>$null 或不加
4 LF→CRLF 刷屏 core.autocrlf=true .gitattributeseol=lf
5 Author identity unknown 没配 name/email git config --global
6 node_modules 还在被跟踪 已跟踪的文件 .gitignore 无效 git rm -r --cached . 先解除
7 .gitignore 冲突 staged content different 文件版本不一致 -f 强制
8 git check-ignore 永远没输出 之前设了 core.excludesFile 干扰 --unset core.excludesFile
9 找不到 .gitignore 隐藏文件默认看不到 资源管理器 → 查看 → 隐藏的项目
10 remote origin already exists 远程已存在同名远程 换名或用 set-url 覆盖
11 refusing to merge unrelated histories 本地和远程没有共同历史 --allow-unrelated-histories
12 Updates were rejected 远程比本地新 git pull 再推送

写完这份笔记,相当于 Git 新手路上的弯弯绕绕都记下来了。下次建新项目直接照着流程来,不会再踩同样的坑。

有问题随时问 🌟


Git 入门学习笔记
https://blog.shinebook.net/2026/05/05/编程/Git学习笔记/
作者
X
发布于
2026年5月5日
许可协议