0%

Git 小贴士

git repo 迁移,附带 history

想要将 git repo 从 public 复制到公司的 enterprise 版本的 git 上,但是想要保留历史记录。

1
2
3
4
5
6
7
8
# 复制 repo
git clone https://gitee.com/oldxxx/oldxxx.git
# 删除原有关联
git remote remove origin
# 关联到新 repo
git remote add origin https://gitee.com/newxxx/newxxx.git
# 推送至新 repo
git push

怎么更新 fork repo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 检查 repo 状态
git remote -v
origin git@github.corp:jack/vault.git (fetch)
origin git@github.corp:jack/vault.git (push)

# 关联到原项目
git remote add upstream git@github.corp:platform-core/vault.git
# 检查 repo 状态
git remote -v
origin git@github.corp:jack/vault.git (fetch)
origin git@github.corp:jack/vault.git (push)
upstream git@github.corp:platform-core/vault.git (fetch)
upstream git@github.corp:platform-core/vault.git (push)

# 将原项目改动 sync 到本地
git fetch upstream
# 更新本地分支
git merge upstream/master
# 推送到本地分支的 remote,打完收工
git push

怎么查看一个月之前的版本信息

最近发现一个 bug 不知道是不是自己的代码改出来的,由于是一些 context 的改动不好查。打算直接一点,使用一个月之前(我的改动还没有进去的节点)的 build 起一个服务测试一下, git 支持类似的查找

1
2
3
4
git log --after="2014-02-12T16:36:00-07:00"
git log --before="2014-02-12T16:36:00-07:00"
git log --since="1 month ago"
git log --since="2 weeks 3 days 2 hours 30 minutes 59 seconds ago"

结合 reverse 使用效果更佳 git log --since="1 month ago" --reverse

怎么添加 commited file 到 .gitignore

StackOverflow: applying-gitignore-to-committed-files

1
git rm --cached path/to/file

怎么把local master branch 还原成和 remote 端一致

StackOverflow: reset-local-repository-branch-to-be-just-like-remote-repository-head

1
2
git fetch origin
git reset --hard origin/master

移除本地的 commit

1
git reset HEAD~1

将 remote 会滚到上个 commit

git revert -m 1 commit_hash 将对应的 commit 改动回滚, 很棒!

PS: -m 1 会使用默认的 comment 信息,如果你想自定义 comment 内容,可以将这个参数去掉

reset VS revert

reset 历史记录后退,revert 前进

reset 会将历史记录也一并会滚,这样就会导致记录缺失。不是很好,但是在自己 local branch 做了改动想还原的这种 scenario 还是和合适的。还有 reset --hard commit_hash + git push --force 也可以重置代码,但是会修改历史记录,操作比较危险

revert 会在原有的基础上将对应的 commit 改动重置并添加新的历史记录,路径更完成

这个 文章 比较两者的区别,写的挺清楚的

将本地的 commit 回退到前一个 commit

1
2
3
git reset HEAD~1 # 保留改动,回退到 index 状态(add 之前)
git reset --soft HEAD~1 # 保留改动到 stage 状态 (add 之后,commit 之前)
git reset --hard HEAD~1 # 同时将改动也去掉

将本地的单个文件还原成 master 版本

1
git checkout origin/master -- /path/to/file

将远端删除的文件找回来

1
2
3
git log -- /path/of/deleted/file # 找到删除 commit 的前一个 commit number

git checkout pre-commit-num -- /path/of/deleted/file

将 git add, commit 合并到一个命令中

StackOverflow: git-add-and-commit-in-one-command

1
2
3
4
5
# config git alias
git config --global alias.add-commit '!git add -A && git commit'

# and use it with
git add-commit -m 'My commit message'

Rename local repo

1
2
3
4
5
git checkout <repo need to re-name>
git branch -m <new name>

# or make sure you are not at renamed repo
git branch -m <old repo name> <new repo name>

移除 merge 内容

1
2
3
4
git reset --hard HEAD

# or
git merge --abort

国内 git clone 有时会卡住, 有没有 debug 的选项

StackOverflow: how-can-i-debug-git-git-shell-related-problems

1
GIT_CURL_VERBOSE=1 GIT_TRACE=1 git pull origin master

已创建 repo 添加证书

跳转到项目页面,添加文件 ‘create a new file’ -> 输入 ‘license’ 会给出提示

查看某人的 commit 记录

1
git log --author='jack'

查看 log 反序

1
git log --reverse

对比文件

1
git diff <base-commit> <changed-commit> -- <file-path>

比如我像比较 8ab244e3b2de31ca 相对于 f31762ada1764 有什么改动可以使用

1
2
3
git diff f31762ada1764 8ab244e3b2de31ca -- <file-path>

# 如果是相对于 header 的改动,可以省略第一个 commit 内容

查看被删除文件的历史记录

1
2
3
4
5
6
7
git log -- <file path>

# 或者使用

git log --full-log -- <file path>

# 第二种会包含各种 merge 的信息, 比较全。但是一般第一种就够用了

找到该文件后,可以使用 git blame 9f41d238500 – 查看文件修改记录

查看某个 commit 的改动

git show

查看文件某一行删除记录

1
2
# -G 直接支持正则,-S 需要添加其他参数来支持正则
git log -S/G'key' /path/to/file

已经 check in 的文件夹加入 .gitignore

1
2
3
4
5
# 处理文件夹
git rm -r --cached /folder

# 处理文件
git rm --cached /path/to/file

显示 repo 关联的远端地址

1
git remote show origin

cherry pick 提取某一个 commit 和并到目标分支

情景描述:

我自己有一个分支 A, 同时创建了另一个分支 B 并在上面做了改动,commit 为 c1。我对他的这个 commit 有依赖,又不想自己 CV 代码或者以后有 conflict 什么的,这时可以 checkout 到我自己的分支,然后 git cherry-pick c1 来合并代码。他的代码 merge 之后我也不用解决冲突,美滋滋儿。

PS: 在合并 B 分支上的 commit 的时候我并不需要指定分支名字,是不是从侧面验证了,每个 git commit 都是唯一的,不同分支的 commit 也保证 id 不重复

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
^                  ^                                               
| |
| cherry-pick |
|C1 <--------- |C2
| | |
| | |
|C1' ----- |C1
| |
| |
|Branch-A |Branch-B
|------------------|
^
|
|
|
| Master
|
|

cherry pick revert

1
git reset --hard HEAD^

How to drop

如果本地有改动

1
2
3
git stash
git reset --hard HEAD^
git stash pop

如果没有直接 git reset --hard HEAD^, cherry-pick 本质上就是新加了一个 commit 到 branch 而已。

使用 rebase 来合并自己分支的 commit 记录,强迫症福音

check out 一个测试 branch,修改 readme

1
2
3
4
5
6
echo 'a' >> README.md
git add-commit -m 'edit01'
echo 'b' >> README.md
git add-commit -m 'edit01'
echo 'c' >> README.md
git add-commit -m 'edit01'

git log –oneline 查看 commit 记录

1
2
3
4
dc0a087 (HEAD -> testrebase2) edit03
c6feb2a edit02
0436650 edit01
0dcdaac init porject

现在通过 rebase 将 edit01-03 合并为一个 commit。这里有一个地方要注意的是如果指定 commit id,start point 是你想要合并的 ID 的前一个

1
git rebase -i HEAD~3 或者 git rebase -i 0dcdaac

terminal 给出提示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pick 0436650 edit01
pick c6feb2a edit02
pick dc0a087 edit03

# Rebase 0dcdaac..dc0a087 onto 0dcdaac (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's

将 edit02, 03 的前缀改成 s,然后 :wq 进入下一个界面需改 commit message

1
2
3
pick 0436650 edit01
s c6feb2a edit02
s dc0a087 edit03

提示信息如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# This is a combination of 3 commits.
# This is the 1st commit message:

edit01

# This is the commit message #2:

edit02

# This is the commit message #3:

edit03

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Wed Jul 8 17:10:52 2020 +0800
#
# interactive rebase in progress; onto 0dcdaac
# Last commands done (3 commands done):

带 # 号的行不会显示,只需要修改之前我们自己添加的那些行就行了,这里修改为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
merge commit edit01-03

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Wed Jul 8 17:10:52 2020 +0800
#
# interactive rebase in progress; onto 0dcdaac
# Last commands done (3 commands done):
# squash c6feb2a edit02
# squash dc0a087 edit03
# No commands remaining.
# You are currently rebasing branch 'testrebase2' on '0dcdaac'.
#
# Changes to be committed:
# modified: README.md
#

esc + :wq 退出,终端会给出修改成功的提示

1
2
3
4
[detached HEAD 6c42812] merge commit edit01-03
Date: Wed Jul 8 17:10:52 2020 +0800
1 file changed, 3 insertions(+)
Successfully rebased and updated refs/heads/testrebase2.

这是再使用 git log –oneline 查看,可以发现目标 commit 已经合并成功

1
2
6c42812 (HEAD -> testrebase2) merge commit edit01-03
0dcdaac init porject

怎么避免 branch 上出现很多 merge 的 commit, 强迫症福音 2.0

TODO

Git SS 加速

修改 .gitconfig 文件,添加配置如下

1
2
3
4
5
6
7
# config your `~/.gitconfig` file
[http]
proxy = socks5://127.0.0.1:1080
sslVerify = false

[https]
proxy = socks5://127.0.0.1:1080

或者在终端输入

1
2
3
4
5
6
7
8
# or you can config it by typing terminal
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 http.sslVerify false

# turn off proxy, 开启后 git commit 会受影响
git config --global --unset http.proxy
git config --global --unset https.proxy