Git配置
全局配置
1 | git config --global init.defaultBranch main |
git别名
1 | git config --global alias.lg1 "log --graph --abbrev-commit --decorate --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all" |
下载问题
1 | git config --global http.postBuffer 104857600 # 100MB |
乱码问题
1 | git config --global core.quotepath false |
储藏分支
git stash
命令:将当前未提交的修改(即,工作区的修改和暂存区的修改)先暂时储藏起来,这样工作区干净了后,就可以切换切换到master分支下拉一个fix分支。在完成线上bug的修复工作后,重新切换到dev分支下通过git stash pop
命令将之前储藏的修改取出来,继续进行新功能的开发工作1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18# 查看储藏记录列表
git stash list
stash@{index}: WIP on [分支名]: [最近一次的commitID] [最近一次的提交信息]
# 标识储藏记录
git stash save [stashMessage]
# 取出最近一次储藏的修改到工作区
git stash pop
# 取出指定index的储藏的修改到工作区中 git stash apply stash@{index}
git stash apply 0
# 将指定index的储藏从储藏记录列表中删除
git stash drop stash@{index}
# 清空你所有的内容
git stash clear
pull 分支
pull 分支报错
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20$ git pull origin
提示:您有不同的分支,需要指定如何协调它们。
hint: You have divergent branches and need to specify how to reconcile them.
提示:您可以通过在之前某个时间运行以下命令之一来做到这一点
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint: git config pull.rebase false # merge
hint: git config pull.rebase true # rebase
hint: git config pull.ff only # fast-forward only 仅快进
hint:
提示:可以将“git config”替换为“git config——global”来设置默认值
hint: You can replace "git config" with "git config --global" to set a default
提示:首选所有存储库。你也可以传递——rebase,——no-rebase,
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
提示:或命令行上的——ff-only,以覆盖配置的默认per
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
fatal:需要指定如何协调不同的分支。
fatal: Need to specify how to reconcile divergent branches.解决
1
2
3
4
5
6# 默认将pull下来的代码与现有改动的代码进行合并
git config --global pull.rebase false
# 回退到合并之前的代码,在进行pull拉取最新代码
git reset --hard c129513
git pull origin
–rebase
多人使用同一个远程分支合作开发,在 push 代码的时候很可能出现以下问题:
1
2
3
4
5
6
7
8
9
10
11$ git push origin master
# 结果如下
To github.com:hello/demo.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'git@github.com:hello/demo.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.从输出结果中可以明显看出此时远程分支有新的 commit 未同步到本地,无法推送。此时我们一般会执行以下操作:
1
2$ git pull origin master
$ git push origin master确实 push 成功了,但是此时用
git log
查看提交记录:多出了一条 merge commit,这个 commit 就是在执行git pull origin master
的时候自动生成的。如果多人多次如此操作,那么提交记录就会出现很多条这种自动生成的 merge commit,非常难看。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# 结果如下
commit 1aefef1a2bedbd3ebd82db8dcf802011a35a9888 (HEAD -> master, origin/master, origin/HEAD)
Merge: 24cfa5c f318a05
Author: hello <hello@qq.com>
Date: Tue Jul 23 09:53:47 2019 +0800
Merge branch 'master' of github.com:hello/demo
commit 24cfa5c3ad271e85ff0e64793bf2bcc9d700c233
Author: hello <hello@qq.com>
Date: Tue Jul 23 09:50:06 2019 +0800
feat: 新功能提交
commit f318a05b1a4cbc0a6cf8d7dc7d3fb99cbafb0363
Author: world <world@qq.com>
Date: Tue Jul 23 09:48:20 2019 +0800
feat: 其他功能提交解决方案:要解决以上问题,不再出现自动生成的 merge commit,那么只要在执行
git pull origin master
的时候带上--rebase
即可:1
2
3# 等价于:git fetch --all && git rebase branch
$
$ git push origin master注意事项: 执行
git pull --rebase
的时候必须保持本地目录干净。即:不能存在状态为modified
的文件。(存在Untracked files
是没关系的),如果出现冲突,可以选择手动解决冲突后继续rebase
,也可以放弃本次rebase
如果 A、B 同学修改了同一个文件。那么很有可能会出现冲突,当 B 同学来执行命令的时候会出现如下状况:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30$ git pull --rebase
# 结果如下
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From gitlab.lrts.me:fed/gitlab-merge
93a1a93..960b5fc master -> origin/master
First, rewinding head to replay your work on top of it...
Applying: feat: 其他功能提交
Using index info to reconstruct a base tree...
M one.md
Falling back to patching base and 3-way merge...
Auto-merging one.md
CONFLICT (content): Merge conflict in one.md
error: Failed to merge in the changes.
Patch failed at 0001 feat:其他功能提交
hint: Use 'git am --show-current-patch' to see the failed patch
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
# 这种情况下,可以手动打开 one.md 文件解决冲突,然后再执行:
$ git add one.md
$ git rebase --continue
# 也可以用 git rebase --abort 放弃本次 rebase 操作。总结:多人基于同一个远程分支开发的时候,如果想要顺利 push 又不自动生成 merge commit,建议在每次提交都按照如下顺序操作:
1
2
3
4
5
6
7
8
9
10
11# 把本地发生改动的文件贮藏一下
$ git stash
# 把远程最新的 commit 以变基的方式同步到本地
$ git pull --rebase
# 把本地的 commit 推送到远程
$ git push
# 把本地贮藏的文件弹出,继续修改
$ git stash pop
rebase用法
不要通过rebase对任何已经提交到公共仓库中的commit进行修改,
不要在master分支上rebase,在master分支上rebase就会出现游离分支。
正常做法是比如在dev分支开发,然后需要的话在dev分支rebase,然后再merge到master
初始化数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28# 我们初始化一个项目
git init
## 制造一些提交
touch base.txt
git add .
git commit -m "add base"
touch 1.txt
git add .
git commit -m "add 1"
touch 2.txt
git add .
git commit -m "add 2"
touch 3.txt
git add .
git commit -m "add 3"
touch 4.txt
git add .
git commit -m "add 4"
touch 5.txt
git add .
git commit -m "add 5"
合并commit
合并多个commit为一个完整commit,把如下分支B、C、D三个提交记录合并为一个完整的提交,然后再push到公共仓库。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18git rebase -i [startpoint] [endpoint]
-i 的意思是--interactive,即弹出交互式的界面让用户编辑完成合并操作,
[startpoint] [endpoint]则指定了一个编辑区间,如果不指定[endpoint],则该区间的终点默认是当前分支HEAD所指向的commit(注:该区间指定的是一个前开后闭的区间)。
# 在查看到了log日志后,我们运行以下命令:
* 09b85cb - (17 minutes ago) add 5 - XXX (HEAD -> main)
* 0f89d77 - (17 minutes ago) add 4 - XXX
* 6c82fb4 - (17 minutes ago) add 3 - XXX
* 4c4e075 - (17 minutes ago) add 2 - XXX
* eda0aa7 - (17 minutes ago) add 1 - XXX
* e90bc6c - (17 minutes ago) add base - XXX
# 合并最近二次提交 需要选择二次提交的前一个提交
git rebase -i 6c82fb4
# 或者
git rebase -i HEAD~2编辑说明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26pick 0f89d77 add 4
pick 09b85cb add 5
# Rebase 6c82fb4..09b85cb onto 6c82fb4 (2 commands)
#
# Commands:
每一个commit id 前面的pick表示指令类型,git 为我们提供了以下几个命令:
pick:保留该commit(缩写:p)
reword:保留该commit,但我需要修改该commit的注释(缩写:r)
edit:保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e)
squash:将该commit和前一个commit合并(缩写:s)
fixup:将该commit和前一个commit合并,但我不要保留该提交的注释信息(缩写:f)
exec:执行shell命令(缩写:x)
drop:我要丢弃该commit(缩写:d)
## 合并add 5到add 4
pick 0f89d77 add 4
s 09b85cb add 5
## 保存后是注释修改界面,修改保存后查看日志
PS C:\Users\sfuli\Desktop\test> git lg
* 7290f75 - (31 minutes ago) add 4 5 - XXX (HEAD -> main)
* 6c82fb4 - (31 minutes ago) add 3 - XXX
* 4c4e075 - (31 minutes ago) add 2 - XXX
* eda0aa7 - (31 minutes ago) add 1 - XXX
* e90bc6c - (31 minutes ago) add base - XXX
将某commit粘贴到另一个分支上
当我们项目中存在多个分支,有时候我们需要将某一个分支中的一段提交同时应用到其他分支中,就像下图:
我们希望将develop分支中的C~E部分复制到master分支中,这时我们就可以通过rebase命令来实现(如果只是复制某一两个提交到其他分支,建议使用更简单的命令:
git cherry-pick
)。1
2
3
4
5
6
7
8
9
10
11git rebase [startpoint] [endpoint] --onto [branchName]
[startpoint] [endpoint]仍然和上一个命令一样指定了一个编辑区间(前开后闭),
--onto 的意思是要将该指定的提交复制到哪个分支上。
# 为了让这个区间包含C(90bc0045b)提交,我们将区间起始点向后退了一步。C(90bc0045b)和E(5de0da9f2)
git rebase 90bc0045b^ 5de0da9f2 --onto master
# 此时所有分支的状态虽然此时HEAD所指向的内容正是我们所需要的,但是master分支是没有任何变化的,git只是将C~E部分的提交内容复制一份粘贴到了master所指向的提交后面,我们需要做的就是将master所指向的提交id设置为当前HEAD所指向的提交id就可以了,即:应该是这样:
git checkout master
git reset --hard 0c72e64
Git推送
新建仓库
1
2
3
4
5
6
7echo "# README" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:xxx/xxx.git
git push -u origin main已经存在的仓库
1
2
3git remote add origin git@github.com:xxx/xxx.git
git branch -M main
git push -u origin main # git push --set-upstream origin main
指定远程分支
1 | # 删除关联的origin的远程库 |
ssh密钥
RSA 经典且可靠,但性能不够理想。 OpenSSH 版本大于 6.5(2014 年的古早版本),就可以利用 Ed25519 算法生成的密钥对,减少你的登录时间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25# ssh-keygen -t ed25519
ssh-keygen -t ed25519 -C "fl_6145@163.com"
mkdir -p ~/.ssh && cd ~/.ssh
# 我在 GitHub
ssh-keygen -t ed25519 -f my_github_ed25519 -C "me@github"
# 我在 Gitee
ssh-keygen -t ed25519 -f my_gitee_ed25519 -C "me@gitee"
# 我在 GitLab
ssh-keygen -t ed25519 -f my_gitlab_ed25519 -C "me@gitlab"
# 我在企业
ssh-keygen -t ed25519 -f my_company_ed25519 -C "email@example.com"
# RSA
ssh-keygen -t rsa -b 4096 -f my_id -C "email@example.com"
# [-t rsa] 表示使用 RSA 算法。
# [-b 4096] 表示 RSA 密钥长度 4096 bits (默认 2048 bits)。Ed25519 算法不需要指定。
# [-f my_id] 表示在【当前工作目录】下生成一个私钥文件 my_id (同时也会生成一个公钥文件 my_id.pub)。
# [-C "email@example.com"] 表示在公钥文件中添加注释,即为这个公钥“起个别名”(不是 id,可以更改)。
# github上添加ssh key
cat ~/.ssh/id_rsa.pub
# 验证ssh key是否设置成功
ssh -T git@github.com
ssh -T git@gitee.com添加到配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43# 关于别名
# Host 是别名,HostName 是真正的域名。
# 得益于别名,你可以直接以别名访问地址。例如:
# 无别名: git clone git@github.com:torvalds/linux.git
# 有别名: git clone github:torvalds/linux.git
# 本例中使用与域名一致的别名,以免错误的配置导致登录不上。
# 关于代理
# SOCKS 代理格式: ProxyCommand connect -S localhost:1080 %h %p
# HTTP 代理格式: ProxyCommand connect -H localhost:1080 %h %p
## SSH 代理依赖外部程序,这里使用了 Git for Windows 同捆的 connect.exe。
## Linux 下使用该代理方式需要额外安装 connect-proxy。
# 我在 GitHub
Host github.com
Hostname github.com
# ProxyCommand connect -H localhost:1080 %h %p
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/my_github_ed25519
# 我在 GitLab
Host gitlab.com
Hostname gitlab.com
# ProxyCommand connect -H localhost:1080 %h %p
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/my_gitlab_ed25519
# 我在 Gitee
Host gitee.com
Hostname gitee.com
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/my_gitee_ed25519
# 我在企业
Host example.com
Hostname example.com
Port 22
User git
PreferredAuthentications publickey
IdentityFile ~/.ssh/my_company_ed25519
代码行数统计
1 | # 个人提交的代码行数统计 |
大文件清理
斩草除根式
把根目录下面的.git文件夹删除,然后重建,简单粗暴,但如果需要git log历史记录的,请不要这样做
1
2
3
4rm -rf .git
# 删除之后,该目录就不是一个git仓库了,因此需要重建
# 输入rm -rf + github仓库地址 在 github 的对应的库中到 setting 删除库
rm -rf https://github.com/xxx/xxx.git
逐个攻破式
对仓库进行gc操作
1
git gc
查看空间使用,size-pack 是以千字节为单位表示的 packfiles 的
1
2git count-objects -v
du -ah .git/objects运行底层命令 git verify-pack 以识别大对象,对输出的第三列信息即文件大小进行排序.
1
2
3
4
5
6
7
8# 占用空间最多的五个文件
git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5
# 787d86fa5890fa037cca876b7b67d581d424b357 blob 1259085 1168273 16059429
# 第一行的字母其实相当于文件的id,用以下命令可以找出id 对应的文件名:
git rev-list --objects --all | grep 787d86fa5890fa037cca876b7b67d581d424b357
# 使用 rev-list 命令,传入 --objects选项,它会列出所有 commit SHA 值,blob SHA 值及相应的文件路径,这样查看 blob 的文件名。
git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"查找文件
1
2
3
4# 查出文件提交commit记录
git log --pretty=oneline --branches -- ${FILE_PATH}
# 想要知道这条commit id所在的分支,可以使用以下命令
git branch -a --contains <COMMIT ID>删除文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14# 遍历所有提交: commit多了会比较慢
git filter-branch -f --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch <file>' --tag-name-filter cat -- --all
filter-branch命令可以用来重写Git仓库中的提交
-f , --force 假如遇到冲突也让git强制执行
--prune-empty 选项告诉git,如果因为重写导致某些commit变成了空(比如修改的文件全部被删除),那么忽略掉这个commit。
--index-filter参数用来指定一条Bash命令,然后Git会检出(checkout)所有的提交, 执行该命令,然后重新提交。
git rm --cached --ignore-unmatch file 让git删除掉缓存的文件,如果有匹配的话
--tag-name-filter 表示对每一个tag如何重命名,重命名的命令紧跟在后面,当前的tag名会从标注输入送给后面的命令,用cat就表示保持tag名不变。
-- 紧跟着的-- 表示分割符,
--all 表示对所有的文件都考虑在内
# 指定commit修改
git filter-branch -f --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch <file>' -- <commit_id>回收内存
1
2
3
4
5rm -rf .git/refs/original/
git reflog expire --expire=now --all
git fsck --full --unreachable
git repack -A -d # 将所有未被包含在一个pack的松散对象连结成一个pack
git gc --aggressive --prune=now提交到远程仓库
1
2
3git push --force [remote] master
# 让远程仓库变小
git remote prune origin
大仓库clone
1 | # 浅尝clone: depth的参数控制着clone最近多少次的提交。 |
Github更新Fork仓库
首先进入到仓库的目录,进入Pull requests 下面,点击 new pull request 创建一个合并请求
根据箭头的方向,把要合并的仓库设置为自己的仓库( base repository 是你自己的仓库和分支 head repository 是你fork来源的仓库和分支 ):
点击Create pull request,填写合并概要:
点击确认合并:
一键更新同一目录下的多个仓库
1 | # vim ~/git_pull_Batch.sh |