tag,branch,submodule 基本使用
Tag来源1,来源2
git tag <tag-name> # create local tag
git tag -d <tag-name> # delete local tag
git push origin :refs/tags/<tag-name> # delete remote tag
git fsck --unreachable | grep tag && git update-ref refs/tags/<tag_name> <hash> # recover a deleted tag
git describe --tags --abbrev=0 # show the most recent tag on the current branch
git tag --contains <commitid> # find all tags containing a specific commit
Branch
分支不能含空格,见这里。
本地和远程创建空分支
# UPDATE(git > 2.27)
git switch --orphan <new branch>
git commit --allow-empty -m "Initial commit on orphan branch"
git push -u origin <new branch>
## Old Way
# local
git checkout --orphan empty-branch
git rm -rf .
# remote
git commit --allow-empty -m "root commit"
git push origin empty-branch
本地和远程删除分支
# delete branch locally
git branch -d localBranchName
# delete a local branch that has not been merged to the current branch or an upstream
git branch -D localBranchName
# delete branch remotely
git push origin --delete remoteBranchName
# same as
git push origin :remoteBranchName
# delete multiple branches
git branch | grep 'fix/' | xargs git branch -d
# rename current branch
git branch -m new-name
# rename a different(local) branch
git branch -m old-name new-name
# delete the old-name remote branch and push the new-name local branch
git push origin :old_name new_name
克隆特定远程分支
git clone --branch <branchname> <remote-repo-url>
删除仅存在本地(远程仓库中不存在)的分支
$ git branch -a
* main
remotes/origin/articles-main
remotes/origin/gh-pages
remotes/origin/main
# remote branch articles-main, gh-pages has been deleted
$ git remote prune origin
Pruning origin
URL: git@github.com:tianheg/wiki.git
* [pruned] origin/articles-main
* [pruned] origin/gh-pages
Others:
git branch # list local branches
git branch -r # list remote branches
git branch -a # list local and remote branches
git checkout -b <branch> <SHA1_OF_COMMIT> # create a branch from a commit
Submodule
# clone all submodules
git clone --recursive git://github.com/foo/bar.git
# already cloned
git submodule update --init --recursive
移除 Submodule
git submodule deinit submodulename
git rm submodulename
git rm --cached submodulename
rm -rf .git/modules/submodulename
移除子模块
https://stackoverflow.com/a/1260982/12539782
仓库中只有一个子模块:
git rm <path-to-submodule> rm .gitmodules rm -rf .git/modules git config --remove-section submodule.<path-to-submodule>
修改 commit 信息
https://stackoverflow.com/a/1186549/12539782
想修改 bbc643cd
的信息
git rebase --interactive 'bbc643cd^'
在默认编辑器打开后,将 pick 改为 r/reword 后保存,然后就可以修改 commit 信息了。
强制从远程仓库拉取内容到本地
https://stackoverflow.com/q/70710729/12539782
git remote -v # origin git@github.com:tianheg/running_page.git (fetch) # origin git@github.com:tianheg/running_page.git (push) # upstream git@github.com:yihong0618/running_page.git (fetch) # upstream git@github.com:yihong0618/running_page.git (push) git reset --hard upstream/master
Gitea
原生
选择:
- Gitea 1.16.8
- MariaDB 10.7.4
配置数据库
https://docs.gitea.io/en-us/database-prep/
pacman -S mariadb
修改 =bind-address=,登录 root 用户下的数据库。
本地安装 Gitea:
SET old_passwords=0;
CREATE USER 'gitea' IDENTIFIED BY 'gitea';
CREATE DATABASE giteadb CHARACTER SET 'utf8mb4' COLLATE 'utf8mb4_unicode_ci';
GRANT ALL PRIVILEGES ON giteadb.* TO 'gitea';
FLUSH PRIVILEGES;
安装 Gitea
pacman -S gitea gitea # 浏览器打开 http://localhost:3000 进行配置 sudo cp /etc/gitea/app.example.ini /etc/gitea/app.ini systemctl enable --now gitea
无法打开 gitea 服务。无法使用,安装失败。
refer:
Docker
https://docs.gitea.io/en-us/install-with-docker-rootless/
理解 Merge & Rebase
- https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging
- https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#\_advanced\_merging
- https://git-scm.com/book/en/v2/Git-Branching-Rebasing
Merge 是起初两条 branches 后来合并为一条,与此同时保留被合并的分支;
Rebase 则是合并后不保留被合并的分支。
第 2 个链接中的例子还没有完全理解。
Do not rebase commits that exist outside your repository and that people may have based work on.
If you only ever rebase commits that have never left your own computer, you'll be just fine. If you rebase commits that have been pushed, but that no one else has based commits from, you'll also be fine. If you rebase commits that have already been pushed publicly, and people may have based work on those commits, then you may be in for some frustrating trouble, and the scorn of your teammates.
配置代理
git config --global http.proxy http://<proxy-server>:<port>/ git config --global https.proxy https://<proxy-server>:<port>/
参考资料:
对分支重命名(本地 & 远程)
How to Rename Git Local and Remote Branches
## Local git branch -m <old-name> <new-name> ## Remote # delete remote branch git push origin --delete <old-name> # or git push origin :<old-name> # push new remote branch git push origin <new-name> # To reset the upstream branch for the new-name local branch use the -u flag git push origin -u <new-name>
重命名远程代号(origin)
https://support.beanstalkapp.com/article/1000-how-do-i-rename-an-existing-git-remote
git remote rename origin upstream
在历史中查找文件
git log --all --full-history -- <FILE_PATH>
git log --all --full-history -- feeds.csv
设置全局 gitignore
git config --global core.excludesfile '~/.gitignore'
子模块改变地址
https://git-scm.com/docs/git-submodule#Documentation/git-submodule.txt-sync–recursive–ltpathgt82308203
# step 1
# 手动改变 .gitmodules 中的 url
# step 2
git submodule sync
子模块更新
https://git-scm.com/book/en/v2/Git-Tools-Submodules
# way 1
git submodule init
git submodule update
# way 2
git submodule update --init
# way 3
git submodule update --init --recursive # 会 clone 所有子模块(也包括子模块的子模块)
与上游仓库同步
git checkout -b new-branch main
git pull https://github.com/yihong0618/running_page.git upstream-branch
# after pulling, fix the CONFLICT
git checkout main
git merge --no-ff new-branch
git push origin main
使用 dura 每 5s 备份一次仓库
https://github.com/tkellogg/dura
配置
# arch linux
yay -S dura-git
dura serve & # Run it in the background
cd /git/repo/
dura watch
## watch all git repo under /home/user
find ~ -type d -name .git -prune | xargs -I= sh -c "cd =/..; dura watch" # BE CAREFUL!!! use when knowing what you are doing
不 Merge
# Since git version 1.7.4
git merge --abort
# prior git versions
git reset --merge
等待整理
Change the author and committer name/email for multiple commits
https://stackoverflow.com/a/1320317/12539782
NOTE: This operation will modify SHA-1, and commits date.
Steps:
git config --global user.name "New Author Name"
git config --global user.email "email@address.example"
git rebase -r --root --exec "git commit --amend --no-edit --reset-author"
Add Files to A Commit Except A Single File
https://stackoverflow.com/a/4475506/12539782
git add -u
git reset -- file_excepted
Remove Untracked Files from Working Tree
https://stackoverflow.com/a/64966/12539782
# Print out the list of files and directories which will be removed (dry run)
git clean -n -d
# Delete the files from the repository
git clean -f
Push Two Remotes
https://stackoverflow.com/a/14290145
git remote set-url --add --push origin git://original/repo.git
git remote set-url --add --push origin git://another/repo.git
Write good commits
好的 commit 的作用:
- 帮助理解本次操作内容
- 加速和简化 code reviews
- 解释不能只用代码来描述的“为什么”
- 帮助以后的维护者,弄清楚为什么以及改变是怎样产生的,使故障排除和调试更容易
feat: add hat wobble
^--^ ^------------^
| |
| |-> Summary in present tense.
|
|------->Type: chore, docs, feat(option), fix, refactor, style, test, (!)BREAKING CHANGE, build, ci, perf, test
例子:
- chore: add Oyster build script
- docs: explain hat wobble
- feat: add beta sequence
- feat(lang): add polish language
- fix: remove broken confirmation message
- refactor: share logic between 4d3d3d3 and flarhgunnstow
- style: convert tabs to spaces
- test: ensure Tayne retains clothing
GitHub 例子
git commit -m "fix: accept current change https://github.com/tianheg/blog/blob/26af0419337014dea93ada9bf4a3d8bbbcc39619/layouts/shortcodes/music.html#L1" git commit -m "add: ... close #123"
更多资料见这里。
如何从 Git 仓库中完全移除文件
请注意:不要在重要仓库中尝试,可以先新建一个测试 Git 仓库,以熟悉操作步骤(实际上只有一行命令)。
能够达到我的目的的命令(来源):
git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch path_to_file" HEAD git push -f
当使用 filter-branch
命令时,出现以下提示:
WARNING: git-filter-branch has a glut of gotchas generating mangled history rewrites. Hit Ctrl-C before proceeding to abort, then use an alternative filtering tool such as 'git filter-repo' (https://github.com/newren/git-filter-repo/) instead. See the filter-branch manual page for more details; to squelch this warning, set FILTER_BRANCH_SQUELCH_WARNING=1.
大意就是说,=filter-branch= 命令有大量陷阱,会把已有的历史弄乱。按
Ctrl+C 可在未执行命令以前取消,然后使用另一个可供选择的筛选工具
git filter-repo。查看
filter-branch
的手册获取更多信息,略去警告需设置
=FILTER\_BRANCH\_SQUELCH\_WARNING=1=。
了解 git filter-repo
https://github.com/newren/git-filter-repo
git filter-repo
是一个用于重写 Git 仓库历史的多功能工具。它和
git filter-branch
差不多,但是没有导致性能下降的问题,它的功能更强大,而且它的设计可以扩展可用性,而不是简单的重写情况。=git
filter-repo= 现在被 Git 项目推荐,用于代替 =git filter-branch=。
sudo pacman -S git-filter-repo # 安装 ### 演示使用方法 git init test_git_filter_repo && cd $_ # 新建名为 test_git_filter_repo 的 Git 仓库,并打开 touch test # 新建文件 git add test # 添加到暂存区 git commit -m "message" # 提交至 Git 仓库 git log # 检查日志 git filter-repo --path test --force --invert-paths # 删除包含 test 的历史 git log # 检查结果:无 commit 提交 ls -a # 没有文件 test
以上命令行中的演示,是使用 git filter-repo
移除文件的过程,谨记:不要直接在生产环境或重要仓库使用,要先确保自己知道某个命令的执行结果。
云服务器配置 Git 仓库托管并使用 Git Hooks 自动执行脚本
之前的博客更新思路是,本地提交修改至 GitHub,再登陆云服务器,手动执行脚本,达到更新博客内容的目的。但是,从 GitHub 拉取代码较慢,于是想到可以把本地的更改同时推送到 GitHub 和云服务器。再通过 Git Hooks 自动执行「更新博客」的脚本,以此达到提升效率的目的。
更新 Git 至最新版本
云服务器的系统是 Ubuntu 20.04,所以可以通过以下命令安装 Git 的最新版本:
add-apt-repository ppa:git-core/ppa
apt update
apt install git
创建 Git 用户
adduser git # note difference with useradd
passwd git # add password for git user
sudo visudo
修改 /etc/sudoers
:
root ALL=(ALL) ALL ubuntu ALL=(ALL:ALL) NOPASSWD: ALL git ALL=(ALL:ALL) NOPASSWD: ALL # add
配置 ssh 公匙
在本地主机执行以下命令:
ssh-keygen -t ed25519 -C "email"
会生成两个文件:id\_ed25519 和 id\_ed25519.pub。将 id\_ed25519.pub 文件里的内容复制到云服务器的 authorized\_keys 文件中:
su git
mkdir ~/.ssh
vim ~/.ssh/authorized_keys
然后在本地添加私匙:
ssh-add ~/.ssh/ssh_rsa
如果不添加私匙,还是提示输入密码。
注意: ~
代表 /home/git
。只有 git 用户才能使用这个公匙。
修改权限:
cd ~
chmod 600 .ssh/authorized_keys
chmod 700 .ssh
本地测试 git 服务:
ssh -v git@server-ip # Server public network IP
创建博客文件夹
su root # switch to root user
mkdir /home/hugo
chown git:git -R /home/hugo
更改站点目录权限
sudo chown git:git -R /var/www/hugo # for git hook
创建 bare 仓库并配置 Git Hook
su root
cd /home/git
git init --bare blog.git
chown git:git -R blog.git
vim blog.git/hooks/post-receive
chmod +x blog.git/hooks/post-receive
新建文件 blog.git/hooks/post-receive
:
#!/bin/sh git --work-tree=/home/hugo --git-dir=/home/git/blog.git checkout -f cd /var/www/hugo rm -rf * # 删除文件夹下的所有文件以保持最新 cd /home/hugo hugo --minify -d /var/www/hugo
本地配置云服务器仓库
git remote add origin git@server-ip:/home/git/blog.git
git push -u origin main # first push
使用 Docker 配置 Hugo 部署
#!/bin/sh
git --work-tree=/home/www --git-dir=/home/git/blog.git checkout -f
cd /home/www/public
sudo rm -rf * # 删除文件夹下的所有文件以保持最新 & 通过 Docker 生成文件权限为 root 需要加 sudo
cd /home/git/docker-blog
docker compose up -d
/home/git/docker-blog
:
docker-compose.yml nginx.conf
docker-compose.yml
:
version: "3.9" services: nginx: image: nginx:stable volumes: - $PWD/nginx.conf:/etc/nginx/nginx.conf - /etc/letsencrypt:/etc/letsencrypt - /home/www/public:/home/www/public ports: - "80:80" - "443:443" blog: image: tianheg/hugo:0.98.0 volumes: - /home/www:/home/git - /home/www/public:/output environment: - HUGO_BASEURL=https://www.yidajiabei.xyz/
参考资料
只 clone 远程 Git repo 的一部分
git clone --depth 1 --filter=blob:none --sparse REPOSITORY_URL
cd DIRECTORY_NAME
git sparse-checkout init --cone
git sparse-checkout set DIRECTORY_NAME
从历史commit中删除特定文件
Removing sensitive data from a repository - GitHub Docs
git filter-repo --invert-paths --path PATH-TO-YOUR-FILE-WANT-TO-DELETE
git push origin --force --tags
查询commit msg
git log --grep="content_to_search"
git log --grep="html5"
Git - Reference
Guide - gitcredentials[7]
https://git-scm.com/docs/gitcredentials
Credential 的描述
Git 有时需要来自用户的凭证来执行操作;例如,为了通过 HTTP 访问远程存储库,它可能需要请求用户名和密码。本手册描述了 Git 用于请求这些凭据的机制,以及避免重复输入这些凭据的一些特性。
请求凭证
在未定义凭证助手(credential helpers)的情况下,Git 会采用一下策略得到用户名和密码:
- 如果设置了
GIT_ASKPASS
环境变量,变量指定的程序会被触发。命令行会输出一个合理的提示,提醒用户输入用户名和密码 - 如果设置了
core.askPass
配置变量,它的行为如 1 所见 - 如果设置了
SSH_ASKPASS
环境变量,它的行为如 1 所见 - 否则,终端会提示用户
避免冗杂
重复输入某些凭证,令人讨厌。Git 提供了两种解决办法:
- 用于给定验证上下文的用户名的静态配置
- 凭据助手可以缓存或存储密码,或者与系统密码钱包或钥匙链进行交互
https://stackoverflow.com/a/51327559
Git Credential 是为了保存用户名和密码而存在的,然而最安全的办法还是使用 SSH 密钥,不使用用户名和密码。
使用 SSH 密钥
创建好一个 SSH 密钥对,私匙保存在本地,公匙存放在目标服务器。在本地添加私匙到 ssh-agent :
ssh-add ~/.ssh/id_rsa
Caching
git config --global credential.helper cache
# or
git config --global credential.helper 'cache --timeout=3600'
Store
使用该选项,会将用户名和密码保存为纯文本,容易被窃取了。
git config credential.helper store