指令
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
是永久的还是仅限当前会话.