Published on

不定期更新的Git经验库

Authors
  • avatar
    Name
    McDaddy(戣蓦)
    Twitter

Git一直用了很多年了,但是大多数情况只是使用图形化操作,坏处就是一旦碰到什么问题就无从下手,今年开始强迫自己放下图形工具,将日常的操作用CLI来一一完成,也从中积累一些经验。

git log

git log有很多命令参数,主要有

git log --stat  # 会显示出每个commit增删的文件和增删的代码量
git log --pretty=oneline # 格式化将所有commit信息放在一行,只包括commitId和message
git log --graph # 展示图形 树状图
git log --author="John" # 指定看某人的commit
git log --abbrev-commit # 使用缩略版的commitId(7位)
git log --pretty=format:'' # 自定义输出内容

所以我们可以用git log --graph --pretty=format:'%h %s %ad' --date=format:'%Y-%m-%d %H:%M这个命令来查看整个commit过程的简略树状图

image-20200515151920006

HEAD -> master 表示当前本地master分支指向的commit origin/master 表示远程master分支目前指向的commit feature/test 表示本地feature/test分支的指向

Git 文件大小写问题

Git默认文件名和文件夹名是不区分大小写的,如果README.md —> readme.md是不会提示有变化的, 需要主动设置config

git config core.ignorecase false

但是如果直接改了大小写然后push, 结果就是远程git上会有两份同名大小写的文件。这个就真的很头疼。 百度到这个分步改名法。实测有效

$ git mv ./Docs ./docs.bak
$ git add .
$ git commit -m "改名(第 1/2 步)"

$ git mv ./docs.bak/ ./docs
$ git add .
$ git commit -m "改名(第 2/2 步)"

$ git push

git log vs git reflog

git log是显示当前分支的历史记录的,但如果有reset操作的话是看不到的。

git reflog 可以看到本地所有对HEAD操作的历史记录,即使是reset, 此外reflog的内容更多,包括切换分支等操作都会被记录下来,但是那些不影响HEAD的操作就不会被记录,比如stash操作

场景1:在branch A上commit代码,然后切到branch B要cherry pick, 打开git log是看不到branch A的commit的,通过git reflog就可以看到。

场景2: 分支被reset回滚了,看git log是看不到那些已经被回滚的commit的,这时候只能git reflog来查看完整的commit记录

场景3:commit被本地drop了,通过git checkout -b xxx ref-sha 就可以恢复到被删除的commit

git pull

git pull = git fetch + git merge
git pull --rebase = git fetch + git rebase

查找commit来自哪个分支

git branch --contains <commit-id>

撤回本地已经commit但是没有push的提交

# 找到要回滚的地方,一般就是HEAD~1
git reflog 
# --soft 结束之后已经commit的代码会回到stage
# --hard 结束之后已经commit的代码会消失
git reset --soft [<commit-id>/HEAD~n>]

修改分支名

git branch -m <oldbranch> <newbranch>

清除本地untracked的files

git clean -n # 列出所有要移除的files
git clean -f # 移除

删除分支

// delete branch locally
git branch -d localBranchName

// delete branch remotely
git push origin --delete remoteBranchName
git push prod --delete feature/remove-ws

同步远程github仓库代码

git fetch upstream && git reset --hard upstream/master && git push -f

将代码推送到不同的源

git push -u origin hotfix/release-1.0 // 在推送时强制指向新的源

强制刷新远程分支列表

git remote update prod --prune

查看远程源列表

git remote -v

多次rebase主分支时,总是遇到要resolve相同冲突的情况

通过配置rerere, 它就会记住同一个冲突的处理方式

git config --global rerere.enabled 1

合并多个commit

git rebase -i HEAD~2 // 合并最近两个commit
git rebase -i develop // 合并从develop到现在所有的commit

// 会出现编辑框,只保留一个commit,剩下的都标成s即squash

查看HEAD位置

cat .git/HEAD
git symbolic-ref HEAD

移动Branch到指定的commit & 移动HEAD

git branch -f master commit-sha
git checkout HEAD^ # 往后移动一个commit
git checkout HEAD~4 # 往后移动4个commit

git config

git config -e 可以直接编辑git的local配置
git config -l 列出所有git配置

查看所有local分支的源

git branch -vv

清理已经在源上删除了的本地分支

通过git fetch -p && git branch -vv 可以看到哪些分支的orgin已经是gone了

image-20210812200803517

git fetch -p && for branch in $(git for-each-ref --format '%(refname) %(upstream:track)' refs/heads | awk '$2 == "[gone]" {sub("refs/heads/", "", $1); print $1}'); do git branch -D $branch; done

如何查看被删除或者被重命名的文件历史

// 查找出所有文件,从中过滤出所有被删除文件,再过滤出大概的名字,这样就能找到被删除前的路径信息
git log --diff-filter=D --summary | grep delete | grep <file-path-name>
// 可以列出所有文件历史,即使是已经删除的
git log --all --full-history -- <file-path-name>
// 如果文件中间被重命名了,加上follow参数,可以一直追溯到最源头
git log --all --follow --full-history -- <file-path-name>

如何把A源的分支推到B源

有的时候我们会直接checkout了remote的分支,写完代码后发现推不上去,因为有权限控制。

事实上,我们本意是checkout一个remote分支,然后作为一个本地分支去改代码,此时可以

git push -u origin // 推到origin同名的branch
git push -u origin // 推到origin指定名称的branch

如何在一台机器上同时管理gitlab和github的账号

.gitconfig

在个人账号的根目录创建一个.gitconfig文件

配置user和email作为全局使用

添加一个includeIf的配置,下面表示当git工程在~/work/github-repo/下面时,需要去找~/.gitconfig_github_work这个配置文件

[user]
	email = chenweitao.mcdaddy@bytedance.com
	name = chenweitao
[includeIf "gitdir:~/work/github-repo/"]
    path = ~/.gitconfig_github_work

然后在~/.gitconfig_github_work里也配置下用户信息,这样就可以在不同的路径下用不同的账号拉代码commit代码

[user]
    name = McDaddy
    email = mcdaddychen@126.com

ssh

一般情况下我们都要配置ssh来做免登录,那么怎么同时给两个域名设置ssh呢

核心在于~/.ssh/config,为不同的host配置不同的IdentityFile即可

Host github
HostName github.com
User mcdaddychen@126.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_ed25519_github

Host gitlab
HostName gitlab.org
User chenweitao.mcdaddy@gitlab.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_ed25519_gitlab

如何在GitHub上删除敏感信息

  • 首先我们要通过git rebase -i HEAD~x来本地Drop掉相关的commit,然后强推,这样在分支中就找不到敏感信息了。但是如果有人保留了历史的commit url那还是可以拿到当时的commit的,比如https://github.com/McDaddy/my-blog/blob/40e15dd93d1964de/site/blogs/routine/Git.md所以清除还是不彻底的
  • 此时需要请求GitHub官方帮助,官方support中输入remove cached views通过弹出的机器人交互,输入要删除的资源链接,然后它会创建一个Ticket去删除,具体执行可能需要12小时到2天,之后这个资源就彻底消失了