Git 奇淫技巧
Git 奇淫技巧
Git clone 加速
有时候我们对 github 的仓库进行 clone 的时候,会发现很慢,甚至是龟速,很不够效率。好在有一个简单且快捷的方法来倍速提升 clone 效率。
1
git clone https://github.com/flutter/flutter.git --config "http.proxy=192.168.1.6:1611"
- 通过
--config "http.proxy=192.168.1.6:1611"
设置代理 - 其中
192.168.1.6:1611
是代理的地址,需要自己搭建或者可用的
上面的配置好,再次执行,基本上可以得到百倍的提效。
修改 Git 提交非当前时间
git revision 的时间是以本地时间记录的,只需要将本机时间修改成你想提交的时间就可以了
修复而非新建提交 (git commit –amend)
假设提交之后,你意识到自己犯了一个拼写错误。你可以重新提交一次,并附上描述你的错误的提交信息 (这样的话,你就有了 2 个 commit 记录)。但是,还有一个更好的方法(前提是提交尚未推送到远程分支),那么按照下面步骤简单操作一下就可以了:
- 修正你的错误(如 build. gradle)
- 将修正的文件暂存
1
git add build.gradle
- 在提交的时候,运行
git commit –amend
命令,将会把最近一次的变更追加到你最新的提交。同时也会给你一个编辑提交信息的机会
1
git commit –amend
- 准备好之后 wq 保存,将干净的分支推送到远程分支。
- SourceTree 勾选
Amend last commit
Git 跨仓库迁移代码文件,并保留 git 历史记录
A 仓库全部迁移到 B 仓库,并保留 git 历史记录
A mirror 方式 push B
比如:我又一个私有仓库在码云上,现在 github 私有仓库免费,我想迁移到 github 上。
- Github 新建一个仓库
TheMonkeyKingAssistant
- 进入到码云所在的代码仓库
- 执行命令:
git push --mirror git@github.com:hacket/TheMonkeyKingAssistant.git
;这样 push 的代码就会带 git log - 去 Github 拉取代码就行了
给 B 添加一个 A 仓库的 remote url
git 项目初始化后,默认情况下会有一个叫 origin 的远程仓库。我们也可以用 git remote add repo_A [repo_A的仓库地址]
来新增一个 “ 远程 “ 仓库,然后使用 git pull,将多个仓库的代码拉下来并 merge。这样便可以实现 A 仓库全部迁移到 B 仓库,并保留 git 历史记录。
注意这里的 [repo_A的仓库地址]
也可以是本地仓库路径。比如我这里添加了两个 repo,repo-A 是位于本地路径的 “ 远程 “ 仓库。
A 仓库中部分子目录文件迁移到 B 仓库,并保留 git 历史记录
Git filter-branch 重写历史
git filter-branch
是 git 提供的重写历史的命令,我们可以用 subdirectory-filter
来实现重写 git 项目子路径的 git 历史记录:
git filter-branch -f --subdirectory-filter <directory>
重写子路径 directory 的 git 历史记录
subdirectory-filter 可以从 git 项目中过滤出给定子目录的 git 历史记录,同时会把给定的子目录作为 git 项目的根目录
对于一个多模块项目,有一天想把其中一个模块迁移成单独的项目,因为有很多提交,所以想带着提交记录一起迁移。本质上就是:git 迁移项目中的某个目录到新项目,包括那一个目录的提交记录。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 克隆一份新的旧项目, 选择一个分支,比如dev分支
$ git clone -b dev 旧项目git地址
$ cd my-project
# 假如我只需要 service 目录下的东西和其提交记录
$ git filter-branch -f --subdirectory-filter AppSamples/SiDebugKit
# 现在,该项目只剩下 AppSamples/SiDebugKit里的东西了
# 推送到新的git地址
$ git push --mirror 新的git地址
# 然后,在新地址里捣鼓,删掉旧的分支的信息
原仓库:
执行 git filter-branch -f --subdirectory-filter AppSamples/SiDebugKit
:
注意:
- 只保留 AppSamples/SiDebugKit 目录下的文件,其他文件会被删除
- 如果新的 git 地址不为空,如果提交到 master,会把之前的给覆盖掉
- 如果有 submodule,非空的目录删除不了
将仓库 A 迁移到仓库 B (仓库 B 已经存在了,且有自己的代码)
- 裁剪仓库 A
1
2
3
4
5
6
# 裁剪仓库A
git filter-branch -f --subdirectory-filter AppSamples/SiDebugKit
# 裁剪后的仓库A,会以AppSamples/SiDebugKit为根目录,怎么样让提交到B仓库是带目录的?
mkdir SiDebugKit
git add.
git commit "add SiDebugKit"
- 合并到仓库 B
1
2
3
4
5
6
7
8
9
# 先进入到仓库B
## 给仓库B添加一个remote,这个remote是本地裁剪后的仓库A
git remote add from_repo_A /Users/xxx/OpenSources/temp/king-assist/
## 查看仓库B所有的remote仓库
git remote -v
## 从from_repo_A的master拉取代码
git pull from_repo_A master --allow-unrelated-histories
## 删除仓库B的remote:from_repo_A
git remote rm from_repo_A
步骤 2 操作完后,仓库 B 存在两个不相关的 remote:origin/master,from_repo_A/master,如果直接将 from_repo_A/master 合并到 master 会报错:
需要加上参数 --allow-unrelated-histories
:
git merge master –allow-unrelated-histories
git-filter-repo 三方库
- 新的仓库需要为空的 git 库
Git 将当前修改提交至其他分支
还未 commit 的
当前处于 A 分支,需要将此次的代码提交至 B 分支则可以进行以下操作
1
2
3
4
5
6
7
8
9
10
11
12
13
//在没有进行commit之前可以进行一下操作
1、通过git stash将工作区恢复到上次提交的内容,同时备份本地所做的修改
git stash
2、然后切换至B分支
git checkout B
3、从git栈中获取到最近一次stash进去的内容,恢复工作区的内容,获取之后,会删除栈中对应的stash
git stash pop
4、在进行正常的提交代码步骤即可
git add /src/main/..
5、git commit -m "功能开发"
6、git pull origin 分支名称
7、git push origin 分支名称
已经 commit 的 cherry pick
v 11.6.0 的已经提交到本地了,现在需要提交到 v 11.7.0 远端分支上
首先切换到本地的 v 11.7.0 分支,然后选中 v 11.6.0 要提交到 v 11.7.0 分支的 commit,
然后 Cherry pick 到 v 11.7.0 分支上,最后 push v 11.7.0 分支到远端分支上。
git 上做文件大小写重命名坑
git 大小写不敏感
设置 git 库为大小写敏感(不建议)
1
git config core.ignorecase false
用这种方法进行重命名,用 git status 就可以识别出修改了,但是不推荐用这种方式,因为在更新这种修改的时候会有麻烦。
使用 git mv 命令(仅当 core. ignorecase 为 true 时可用
1
git mv ABC.java Abc.java
此时的状态是 renamed,git commit 即可。
core.ignorecase
为 false 时,更新时错误
core. ignorecase 不为 true 时会出现如下错误
1
2
3
4
error:
The following untracked working tree files would be overwritten by merge:
Abc.java
或者在切换分支等操作的时候莫名出现这样的错误,解决方法都是将 core. ignorecase 设置为 true,然后再进行操作。
Git 行尾换行符 line-ending(CRLF&LF)
遇到的问题
在 Windows 平台上,会出现如下的 warning:
1
2
3
$ git add app.wxss
warning: LF will be replaced by CRLF in app.wxss.
The file will have its original line endings in your working directory.
Why?
- Windows 在换行的时候,同时使用了回车符 (carriage-return character) 和换行符 (linefeed character);
- Mac 和 Linux 系统 (很老的 mac 系统才是 CR,可以参见 wiki),此时,仅仅使用了换行符 (linefeed character)。
- 同时呢,Windows 的许多编辑器还悄悄滴将 LF 修改成了 CRLF 格式的行结束符,或者在你敲回车的时候,CRLF 格式的行结束符就产生了。当然,这一切都发生在同时存在 Windows 和非 Windows 的跨平台工作中,如果大家都是同一种操作系统,那么,就天下太平了。
warning 中所说的 LF 和 CRLF 分别是 linefeed
和carriage-return&linefeed
。
- Git 为什么 LF->CRLF
Git 有一个针对性的功能:当添加到暂存区时,自动将 CRLF 转换成 LF;反之,当检出时,自动将 LF 转换成 CRLF。
可以通过设置core.autocrlf
来开启这个功能
cherry-pick Git 中只 merge 部分 commit
git cheery-pick(单个 commit)
在 Git 1.7.2 以上的版本引入了一个 cheery-pick 的命令可以只 merge 部分的 commit 而不用直接把整个分支 merge 过来:
1
git cherry-pick <commit 号>
如
1
git cherry-pick e43a6fd3e94888d76779ad79fb568ed180e5fcdf
这样就只会把这个 e43a6fd3e94888d76779ad79fb568ed180e5fcdf
commit 的内容 pull 到当前的分支,不过你会得到一个新的 commit。这样就可以按需 merge 需要的 commit, 而不需要的就可以直接废弃咯。
多个 commit
可以用空格指定多个 commit:
1
git cherry-pick b8dcc42 3370c39
范围 merge
cherry-pick 可以范围 merge ,使用两次版本间使用 ..
连起来:
1
git cherry-pick A..B
这样会把从从版本 A(不包含)到 B(包含)即(A,B] 的版本 pull 到当前分支
甚至,可以使用多段,同样使用空格隔开:
1
git cherry-pick A..B C..D E..F
注:中间需要自己解决冲突,若出现冲突,可以尝试使用 git mergetool 使用 GUI 工具解决