Git总结笔记

1   语言编码的区别

  • zh-CN:中国大陆区域的中文。包括各种大方言、小方言、繁体、简体等等都可以被匹配到。
  • zh-Hans:简体中文。适用区域范围是全宇宙用中文简体的地方,内容包括各种用简体的方言等。

2   linux和windows之间的文件换行符

windows中的换行符(dos)是\r\n,而linux中的换行符(unix)是\n。若不转换,git可能会视作为被更改的文件,从而造成大量无意义的commit。此外,windows中bat脚本文件要求换行符为\r\n,否则cmd解释器无法正确解析,导致无法正确执行脚本。

单文件转换:

  • \r\n转\n:dos2unix test.c
  • \n转\r\n:unix2dos test.c

批量转换:

  • \r\n转\n:find . -type f -exec dos2unix {} \;
  • \n转\r\n:find . -type f -exec unix2dos {} \;

详细命令解释:

1
2
3
4
5
6
7
8
9
10
find .: Find anything in this directory, including its subdirectories, and anything in those subdirectories as well (recursion)
-type f: Only return 'regular file' names. Exclude folder names from the results.
-exec: Execute the following command for every result. Everything beyond this point should be treated as part of that command until the ; character is found.
dos2unix: dos2unix will be executed with the following options...
-k: Keep the date stamp of the output file the same as the input file
-s: Skip binary files (images, archives, etc.). This option is included by default, but I use it anyway in case that default were different on some systems (e.g. OS X v. Debian v. CentOS v. Ubuntu v. ...).
-o: Write the changes directly to the file, rather than creating a new file with the data in the new format.
{}: This tells find to insert the filename it has found as a parameter of the dos2unix call.
';': Tell find that the params for dos2unix have ended. Anything beyond this point will again be treated as a parameter of find. 反斜杠\是用于转移分号;
'{}' is a placeholder which indicates where in the command you want the filename(s) to be inserted, and '+' terminates the said command. You can also run dos2unix once for each filename (by changing '+' with ';'), but since dos2unix accepts an arbitrary number of input arguments, it’s better to use it (as it avoids spawning many processes).

2.1   换行符问题导致git同步错误

若出现本地仓库文件和远程仓库文件出现crlf和lf不相同的问题,会导致git代码同步报错。

解决方法:使用editorconfig文件规定文档。

3   Git配置

3.1   编辑git特定的config项

打开%USERPROFILE%\.gitconfig文件,编辑特定的设置项即可。

3.2   代理设置

1
2
3
4
5
6
7
8
git config --global http.proxy http://127.0.0.1:1080
git config --global https.proxy https://127.0.0.1:1080
git config --global http.proxy 'socks5://127.0.0.1:1080'
git config --global https.proxy 'socks5://127.0.0.1:1080'

# 取消代理
git config --global --unset http.proxy
git config --global --unset https.proxy

3.3   关于git的重命名操作

git默认对大小写不敏感,一般可通过两种方式避免git未识别大小写操作。

方式1:中间文件方法

1
2
3
# git mv(重命名索引,文件夹直接大小写重命名可能无法成功,可以用tmp做中间处理,文件直接大小写无问题)
git mv myfolder tmp
git mv tmp MyFolder

方式2:设置git配置

1
git config core.ignorecase false

4   pull(拉取)

4.1   github从远程仓库拉取

1
git pull origin master # 相当于fetch后merge

4.2   github从上游拉取未并入主干的拉取请求(pull request)

1
2
3
4
5
6
7
8
# 添加远程上游,仓库地址填写需要拉取的上游
git remote add upstream https://github.com/USER/repository.git
# ID 填pull-request id,BRANCHNAME填准备拉取到本地的某个分支名
git pull upstream pull/ID/head:BRANCHNAME
# 切换到分支目录
git checkout BRANCHNAME
# push到自己fork之后的上游
git push -u origin BRANCHNAME

5   clone(克隆)

5.1   常规克隆

git clone http链接(可以不包含.git后缀)

5.2   wget从Github仓库下载特定的文件夹

1
2
3
# -O为输出到指定文件,-和-O配合,不输出到具体文件,而是标准输出。可通过管道符|直接给其他命令。
# -x为解压,-z为gzip解压缩,移除目录,-C指定解压路径,--strip根据数字移除后面给定目录结构参数
wget -O - https://github.com/Mister-Kin/PublicResources/archive/refs/heads/main.tar.gz | tar -xz -C path --strip=2 PublicResources-main/test

5.3   克隆特定分支

1
2
3
# 克隆特定分支,-b(--branch)支持输入tag,--recursive包含子仓库
git clone --recursive -b v1.0 url
git clone --recursive -b branch—name url

5.4   克隆远程仓库中的指定文件或者文件夹

以克隆blender手册翻译的简中为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mkdir locale
cd locale
# 为当前目录初始化一个git仓库
git init
# 添加上游git链接
git remote add -f origin https://projects.blender.org/blender/blender-manual-translations.git
# 设置稀疏检出的筛选目录,sparse-checkout文件里写入要拉取的文件或者文件夹。匹配规则类似.gitignore
echo "zh-hans" >> .git/info/sparse-checkout
# 或者使用sparse-checkout set命令设置设置稀疏检出的筛选目录
git sparse-checkout set 'zh-hans'
# 开启稀疏检出
git config core.sparsecheckout true
# 最后执行拉取获得特定文件或者文件夹
git pull origin main

6   commit(提交)

6.1   commit信息的规范化

规范编写的commit message可通过auto changelog发布release:

  • chore
  • fix
  • feat
  • docs

7   release(发布)

7.1   常规发布

github release create -a ../learngit/README.md -m "release my first program" v1.0.1

7.2   release note的规范化

  • Breaking Changes
  • Changes
  • New Features
  • Features
  • Bug Fixes
  • Improvements
  • Documentation(可缩写 Docs)

注:支持……版本,英文用 Support for …… 表示

8   添加子仓库

1
2
3
4
git submodule add https://github.com/Mister-Kin/actions.git

# 启动如下功能,更新主仓,同时会执行submodule update
git config --global submodule.recurse true

9   重写历史

9.1   删除所有commit

1
2
3
4
5
6
rm -rf .git
git init
git remote add origin url(仓库地址) # git remote -v
git add .
git commit -m 'commit message'
git push --force origin master

注意如果使用这种方式,强制推送到远程github仓库的话,实际查看github网站的信息,貌似并没有缩小,可能数据更新有延迟。

还有另外一种方式,在github网站上删除该reop,并重新建立同名repo再推送。

9.2   从所有commit中清除特定文件

1
2
3
4
5
git filter-branch --index-filter 'git rm --cached --ignore-unmatch filename' HEAD #(*.pdf)
rm -rf .git/refs/original #删除git的备份
git reflog expire --all --expire=now #使所有散落的object失效
git fsck --unreachable #检查是否有散落的object, 验证数据库中对象的连接性和有效性
git gc --aggressive --prune=now #git的垃圾清理车最终删除那些对象, --aggressive 此选项将导致git gc更积极地优化存储库

10   分支管理

10.1   常规操作

1
git branch -M master # 创建分支

10.2   多人协作的工作流

多人协作注意版本控制,分支把控好,不能污染上游,开发者每个人单独分支。

10.3   常规分支管理项目

dev分支常规开发,hotfix分支临时修复

1
2
3
4
5
6
7
8
9
10
# Switched to a new branch "dev"
git checkout -b dev
# Switched to a new branch "hotfix"
git checkout -b hotfix
# 切换到主分支
git checkout master
# 合并hotfix分支
git merge hotfix
# 删除hotfix分支
git branch -d hotfix

11   切换分支时有未提交的文件

应用场景:在dev分支进行开发编写,突然发现master分支有bug,想checkout分支(切换分支),但此时dev分支上有未提交的文件,并且也并不想现在提交。

解决方案:

  1. 在dev分支上git stash,储藏当前工作区
  2. checkout到master分支进行bug修复(新建bugfix分支时,完成后合并,删除)
  3. checkout到dev分支,git stash list
  4. git stash pop,恢复工作区(该方式恢复的同时也把stash内容删除)。(另一种方式是git stash apply(恢复)后git stash drop(删除))

12   远程仓库

12.1   重命名分支并推送到远程仓库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Rename the local branch to the new name
git branch -m <old_name> <new_name>

# Delete the old branch on remote - where <remote> is, for example, origin
git push <remote> --delete <old_name>

# Or shorter way to delete remote branch [:]
git push <remote> :<old_name>

# 删除失败时,请更改默认分支

# Prevent git from using the old name when pushing in the next step.
# Otherwise, git will use the old upstream name instead of <new_name>.
git branch --unset-upstream <new_name>

# Push the new branch to remote
git push <remote> <new_name>

# Reset the upstream branch for the new_name local branch
git push <remote> -u <new_name>

12.2   删除已经推送到远程仓库中的包含在.gitignore中的文件

.gitignore文件中添加新的文件过滤,但是该文件在之前已经提交到远程仓库分支里,我们需要将远程分支代码中的这个文件移除。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1.为避免冲突,同步已下远程仓库最新代码
git pull

# 2.在本地项目目录下删除git缓存
git rm -r --cached .

# 3.add所有文件:输入以下命令,再次将项目中所有文件添加到本地仓库缓存中
git add .

# 4.本地commit
git commit -m "filter new files"

# 5.push到远程仓库
git push

12.3   unable to access github: OpenSSL SSL_read: Connection was reset, errno 10054

这是由于Http协议错误,刷新缓存即可解决

使用终端命令窗口运行命令:

1
ipconfig /flushdns

使用终端命令窗口运行命令:

1
2
sudo killall -HUP mDNSResponder
sudo dscacheutil -flushcache

12.4   更改已提交到远程仓库的commit消息(修改错别字或添加信息)

  1. git rebase -i HEAD~n(N为最近n个提交)
  2. git会生成一个文件在编辑器打开,在需要修改的commit那一行中,将pick修改为reword,保存关闭
  3. 之后会弹出一个文件,在编辑器修改后保存关闭
  4. 之后强制push到远程仓库

12.5   RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: CANCEL (err 8)

因为git文件过大造成的错误,默认缓冲区是1M大小。

解决方法:

1
git config --global http.postBuffer 524288000 # 设置为500M

13   Github LFS

Github LFS是收费产品,免费账户只有1G的存储空间和带宽流量(本人已弃用)。

仓库一旦使用LFS存储,无法直接通过wget或者curl工具下载原文件,只会下载到一个文本指针文件,指向LFS的存储云地址。

13.1   为Git启用LFS

Windows Git LFS大文件管理:windows上使用Git for windows客户端程序时,LFS启用命令:git lfs install

ubuntu安装LFS包:sudo apt install git-lfs

13.2   LFS基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 添加LFS需要管理的大文件,如果文件名就是*.txt,则需要用双引号""包含
# 若无引号,通配符*会被shell扩展,导致LFS跟踪所有txt文件
git lfs track test.txt
git lfs track *.txt
git lfs track "*.txt"
# 取消LFS跟踪文件
git lfs untrack *.txt
# 常规git操作都可以处理LFS文件,显式指定lfs命令可提高速度
git clone
git pull origin main
# git lfs clone是检出(checkout)完成后再批量下载所有必需的 Git LFS 文件。利用并行下载的优势,显著减少产生的 HTTP 请求和进程的数量
git lfs clone
# 同样地,lfs提供拉取速度
git lfs pull origin main

# 移除lfs,然后手动删除.gitattribute中关于lfs的条目
git lfs uninstall
# 重组织所有文件,可以使标记为lfs文件恢复到正常状态,但不会影响到不关联的文件。
git add --renormalize .
# 重新提交
git push origin master

14   CI/CD

重复繁琐的工作交予自动CI/CD完成。

15   参考文献

[1] How do I rename both a Git local and remote branch name?[EB/OL]. https://stackoverflow.com/questions/30590083/how‑do‑i‑rename‑both‑a‑git‑local‑and‑remote‑branch‑name.
[2] Git 中 submodule 的使用[EB/OL]. https://zhuanlan.zhihu.com/p/614114699.
[3] Why is git submodule not updated automatically on git checkout?[EB/OL]. https://stackoverflow.com/questions/1899792/why‑is‑git‑submodule‑not‑updated‑automatically‑on‑git‑checkout.
[4] git lfs安装及使用方法[EB/OL]. https://blog.csdn.net/michaelshare/article/details/83183806.
[5] Git克隆远程仓库中的指定文件或者文件夹[EB/OL]. https://blog.csdn.net/fsfsdgsdg/article/details/127177631.
[6] How to run dos2unix on all files with all extensions in a directory and its sun-directories?[EB/OL]. https://stackoverflow.com/questions/67254229/how-to-run-dos2unix-on-all-files-with-all-extensions-in-a-directory-and-its-sun.
[7] How to pull a pull request from upstream in github[EB/OL]. https://stackoverflow.com/questions/54033842/how-to-pull-a-pull-request-from-upstream-in-github.
[8] 详解 Git 大文件存储(Git LFS)[EB/OL]. https://zhuanlan.zhihu.com/p/146683392.
[9] Git Sparse Checkout使用指南[EB/OL]. https://blog.csdn.net/shelutai/article/details/123116973.
[10] git-sparse-checkout[EB/OL]. https://www.git-scm.com/docs/git-sparse-checkout.
[11] Simple steps to uninstall Git LFS from your repository[EB/OL]. https://github.com/git-lfs/git-lfs/issues/3026.
[12] zh-cn 与 zh-hans 是什么关系、有什么区别?[EB/OL]. https://www.zhihu.com/question/21980689.