指令
Git Bash 使用 ssh 登陆
配置 Git Bash:
1 | git config --global user.name <name> |
以下是我的一些配置:
1 | $ git config --list |
配置 ssh:
1 | # 查看版本 (我的版本比较新, 老版本的指令略有不同) |
然后登陆 Github, 复制公钥:
1 | clip < ~/.ssh/id_rsa.pub |
登陆后 https://github.com/settings/keys -> New SSH Key, 'Title' 随意, 在 'Key' 粘贴.
然后测试一下连接 (初次使用以下指令会多一段对话(如下), 输入 "yes"):
1 | $ ssh -T git@github.com |
提交三部曲
直接偷懒把当前时间作为本次提交版本的 "提交说明", 每次都要思考 "提交说明" 怎么写真是太累了 (真实项目别这么干).
Bash:
1 | # 获取当前时间作为 "提交说明" |
PowerShell:
1 | $date = Get-Date -Format 'yyyyMMdd-HH:mm:ss' |
分支操作
1 | git branch # 查看分支 |
找不同
1 | git status # 找出不同的文件、文件夹 |
分支合并
1 | git checkout <branch_1> # 转到分支1 |
从远程更新到本地
1 | git pull <host> <remote_branch>:<local_branch> |
撤销
1 | # 撤销未 git add 的文件的修改 |
踩坑
Git Bash 中文乱码
例如对于 git status 指令, 中文文件 "新建文本文档.txt" 会被显示为 1
\346\226\260\345\273\272\346\226\207\346\234\254\346\226\207\346\241\243.txt
解决方法如下:

然后
1 | # 解决 Windows Git Bash、Linux 下的中文转码问题 |
Powershell 中文乱码
例如对于 git log 指令, 中文的 Commit Message 会被显示为: 1
<E8><BF><87><E6><BB><A4><E5><8A><9F><E8><83><BD><E5><9F><BA><E6><9C><AC><E5><AE><8C><E6><88><90>
解决方法如下, 在 Powershell 输入:
1 | git config --global core.quotepath false |
然后设置系统环境变量, 设置 LESSCHARSET 为 utf-8.

Git Bash 命令提示符的 $ 总是另起一行
命令前的那一串叫 "系统终端命令提示符 (Prompt Sign)" (就是那一串包含用户名, 工作目录和 $ 符号的东西). Windows 下的 Git Bash 的命令提示符的 $ 总是另起一行.

这玩意由 $PS1 控制. 输入 echo "$PS1", 可得:
1 | # 我的PS1被 conda 修改过, 所以前面有个 "(base)" |
修改它就能修改提示符样式.
而 Ubuntu 下的 $PS1 为:
1 | xie@xie-vm:~$ echo "$PS1" |
那么依葫芦画瓢改一改. 用 vim 或 code (vscode) 命令打开 ~/.bash_profile, 添加一行:
1 | export PS1="\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[32m\]\u@\h\[\033[00m\]:\[\033[33m\]\w\[\033[00m\]\$ " |
保存重启 Git Bash即可.

使用 ssh 执行 git clone 报错
1 | $ git clone git@github.com:xxx/xxx.git |
此时如果测试连接, 却显示正常:
1 | $ ssh -T git@github.com |
网上的解决方案大多是说 ssh 配置出了问题. 但我这里不是这个原因. 原因是勾选了 https://github.com/settings/emails -> Keep my email addresses private, 好像是我的隐私邮箱被系统更换了, 所以就挂了. 解决方案同下面的 Push 时报错 push declined due to email privacy restrictions
Push 时报错 push declined due to email privacy restrictions
从某天开始突然不能 push 了, 错误信息:
1 | ! [remote rejected] master -> master (push declined due to email privacy restrictions) |
原因是勾选了 https://github.com/settings/emails -> Keep my email addresses private, 可能是因为它重置了隐私邮箱吧.
复制 Keep my email addresses private 下给的邮箱 (数字+名字@users.noreply.github.com),
1 | git config --global user.email 12345678+XieNaoban@users.noreply.github.com |
就好了.
Windows 下 Clone 的文件以 LF 为换行符而非 CRLF
设置:
1 | git config --global core.autocrlf input # 提交时转换为 LF, 签出时不转换 |
以下载 LF 的版本. 折腾完了改回去 (毕竟 Win 下还是默认开着好):
1 | git config --global core.autocrlf true # 提交时转换为 LF, 签出时转换为 CRLF |
解决方案: 直接干脆把文件统一成 LF, 不要转来转去了, 反正在 Win 下用 LF 大多数软件也支持.
Win 下 warning: LF will be replaced by CRLF
Windows 以 CRLF 为换行符, Linux 以 LF 为换行符, Git 仓库以 LF 为换行符. 从 Win 上 git clone 时, Git 会自动把仓库里所有的文件从 LF 转为 CRLF. 当提交时, 又会把 CRLF 转回 LF. 如果提交文件是纯 LF 文件, 会显示一个警告: warning: LF will be replaced by CRLF in xxx..
直接关了这个 warning:
1 | git config --global core.safecrlf false # 默认是 'warn' |
git reset 与 git revert 区别
git reset 回滚到某 commit, 后面的 commmit 都抛弃了. 而 git revert 创建一个新 commit, 中和之前的提交.
用 git reset 后 git push 会报错, 提示你当前本地版本落后于远程版本. 需要强制推送 (git push -f).
保留空文件夹
在提交时, 空文件夹 (或者文件夹内所有文件均被gitignore忽略) 不会被提交, 所以 git clone 时将没有那个文件夹. 如果希望提交时保留空文件夹, 可以在该文件夹下新建一个空白文件, 并取名 .gitkeep... 原理也很简单, 有了这个文件, 该文件夹就不是空的了... 所以其实取什么名字都行, 只不过 .gitkeep 比较约定俗成, 比如 IntelliJ 的文件目录视图貌似会自动忽略这个文件.
删除历史中的所有大文件
年少无知的我没写 .gitignore, 把一堆巨大的 json 文件一并 add 到了历史里, 期间这些 json 还改动过好几次, 于是乎我的 .git 文件夹就理所当然地膨胀到了 100MB... 现在我很后悔, 发现这些 json 从一开始就不应该 add, 于是想把它们统统从历史中删除.
参考了不少博客, Github 官方也有文档: Removing sensitive data from a repository - GitHub Help.
先看一下Git历史数据占地面积:
1 | git count-objects -v |
得到:
1 | count: 119 |
然后找出所有大文件, 用的大佬写好的 bash 脚本 (findBigFile.sh):
1 |
|
脚本运行结果大致如下: 1
2
3
4
5
6size pack SHA location
60832 2900 a8b382af350184d5ead001b1e91c66cea62c54b7 path/to/your/file1
33288 4034 e7bba187e68f752e88664c49b95e5ba18e022dca path/to/your/file2
13804 572 c0c7383de6e9b28e97822a896199b11174ade578 path/to/your/file3
13751 571 2609b4429eb13a2a9885a27073b608e8bdecb3d0 path/to/your/file4
...
默认展示 10 条, 如果想要展示 233 条更多只要把脚本里的 head 改为 head -233 即可. 核心就是 objects 那句, 大佬注释写的挺完整, 在此不解释了.
然后就是最核心的删除语句:
1 | git filter-branch --force --index-filter "git rm --cached --ignore-unmatch path/to/your/file" --prune-empty --tag-name-filter cat -- --all |
这行指令原理应该是遍历你的所有 commit, 如果该 commit 有这个目录有这个文件, 就删除. 运行结果如下 (运行速度挺慢的):
1 | WARNING: git-filter-branch has a glut of gotchas generating mangled history |
然后强制 push:
1 | git push origin --force --all |
有些教程到这就结束了, 有些还有后续 (清理、压缩 .git 等), 后续各不相同, 我综合整理了个自己的版本:
1 | rm -rf .git/refs/original/ |
其中 git repack -A -d 和 git gc --aggressive --prune=now 输出的 log 几乎一样, 可能只执行其中一个就行?
整理了个自动删除大文件的脚本 (事先找好要删的文件放在 rm_list 里):
1 |
|
删了 30 多个 json, 最后把 100MB 的 .git 清理到了 10MB (捂脸). 删除过程贼慢, 最后 push 时 "Writing objects" 也贼慢.
.gitignore 对已 track 文件不起作用
当一个文件已经被 commit 后才被发现这个文件是应该 ignore 的, 此时再把它添加入 .gitignore 的话, git 依然会追踪它. 修改该文件, 然后你会发现 git 仍然记录了这个文件的修改. 原因是 .gitignore 仅对新文件生效, 已被 track 的文件不受影响. 解决方法:
- 强制清除对所有文件的追踪 (只清除不想追踪的文件应该也行, 没试)
1
git rm -r -f --cache .
- 更新你的 .gitignore (或者在上述指令之前更新也没关系)
- 重新
add、commit.
给 Git SSH 上 Socks5 代理
如果是使用 http/https 给 git 上代理, 那方法很多, 比如给终端上代理或者直接给 git 设置代理:
1 | git config --global http.proxy socks5://127.0.0.1:10808 |
但是我现在想用 ssh 进行 git clone (git clone git@github.com:xxx/xxx.git), 针对 http/https 的代理对 ssh 是无效的. 所以要通过配置 ssh 自身来实现代理.
方法是打开 ~/.ssh/config (Win下就是 个人文件夹\.ssh\config), 如果没有就新建这个文件.
然后写入一行代理指令, Win 和 Linux 指令不同:
1 | # Linux (如果无 nc 请先安装. 但是 Win 下压根没有 nc) |
以上指令效果是全局的, 局部的稍微麻烦一点, 要在指令里指定主机和用户, 懒得弄了.
当然, 直接在控制台像这样设置也行:
1 | # -o 即 option 的意思 |
不过我对ssh 不太熟, 也没去试, 暂不知道 -o 是永久的还是仅限当前会话.