跳到主要内容
版本:0.17.0+

git-howto

improve git pull speed

resolution 1: config proxy (vpn required)

how to config:

HTTP_PROXY=localhost:7890
git config --global http.proxy HTTP_PROXY
git config --global https.proxy HTTP_PROXY

confirm config:

picture 116

config result:

picture 115

resolution 2: change url

github.com --> github.com.cnpmjs.org

ref:

improve terminal speed (lagged/delayed by git)

git config --add oh-my-zsh.hide-status 1
git config --add oh-my-zsh.hide-dirty 1

git auth

gitlab 每次都要输入密码的解决方案

分两步解决,首先要把自己的 ssh 公钥加入到 gitlab 用户配置里。

其次,还要设置远程仓库为 git 链接,而非 http(私库)。

# step 1. generate ssh-key if not exist
ssh-keygen -t rsa -C "shawninjuly@gmail.com" -b 4096

# step 2. show the ssh-public-key if generated
cat ~/.ssh/id_rsa.pub

# step 3. copy it into gitlab user settings

# step 4. test connection
ssh -T git@192.168.0.237
# Welcome to GitLab, @markshawn!

# step 5. set repo url to be git format (init first)
git remote set-url origin git@192.168.0.237:markshawn/hmdservice.git

ref:

official password and authentication

ref:

FIXED: GitHub does not provide shell access

Just change the remote url from https to git:

raw:  https://github.com/arpara-vr/arpara-timewarp.git
then: git@github.com:arpara-vr/arpara-timewarp.git
git remote set-url origin git@github.com:arpara-vr/arpara-timewarp.git
git push

ref:

git merge

resolution 1

background:

本来想在surfaceflinger下操作全部 git 的,结果发现最后还是要动到外面的renderengine

picture 113

之前是在native下进行 git 管理的,这本来很 ok,后来因为景喆/西瓜的 hmdservice 放了进来,导致 git 一下就脏了,所以才想到与它的 service 隔离,缩小到 surfaceflinger 范围。

现在发现不可行,不过正好 hmdservice 已经让博文去搞了,所以我又可以了,那就还是在 native 下管理,可是现在 surfaceflinger 下已经有几个 commit 了,所以就涉及到迁移/合并问题。

picture 112

resolution:

这里是否可以把 Bproject 设成/path/to/B 呢?这样是不是就不用生成新的文件夹了?

update:不是,跳过git read-tree步骤就可以。

git remote add -f Bproject /path/to/B
git merge -s ours --no-commit --allow-unrelated-histories Bproject/master
# git read-tree --prefix=dir-B/ -u Bproject/master
git commit -m "Merge B project as our subdirectory"
# git pull -s subtree Bproject master

ref:

FIXME: resolution 2 (maybe can be merged with 1)

!!!warning 这种方法只适合合并 git 追踪的文件,这将很容易导致一些问题,因为那些不被追踪的文件没有合并进来,比如我的 VERSION.txt

If you want to merge project-a into project-b:

cd path/to/project-b
git remote add project-a /path/to/project-a
git fetch project-a --tags
git merge --allow-unrelated-histories project-a/master # or whichever branch you want to merge
git remote remove project-a

ref:

git rebase

通过 glola 可以发现,我们当前的版本,和 upstream 从 2a043ea 开始产生了分歧:

picture 1

所以此时推 upstream 是会被拒绝的,例如:

picture 2

而 git 默认的提示是 使用 git pull,也就是先把最新的 upstream 拉下来,这其实就是一个 merge 的操作。

当我们这样做之后,等于是我们消化了 upstream,等我们改完冲突之后再 push 时,分支树就类似这样走:

picture 3

但其实,这并不是最优雅的动作,因为为了解决你和 upstream 之间的这个 merge 问题,你似乎往回走了一步 (俗称非线性)。

有一种办法可以让整个流程看起来更顺畅,那就是想方设法变成从 upstream 通向你:

picture 4

这就是 rebase

rebase 是一个捏造词,也就是字面意义,重新 base 的意思,base 就是选择一个基底,按照我们的要求,我们只要选择 upstream 作为基底即可。

要使用 rebase 我们得先回到分叉口(或之前):

git checkout 2a043ea # 查询 git log 得知的分叉口

然后 rebase 到 upstream:

git rebase upstream/main

picture 5

git apply/am (git patch)

git patch workflow

ref:

Step 1. 下载 patch 文件

picture 1

Step 2. 解压

picture 2

此时假设文件路径在 FILE.diff,工程路径为frameworks/native/

Step 3. (可选)显示有哪些文件会被改动

git apply --stat $FILE.diff

Step 4. 检测 patch 是否可行

git apply --check $FILE.diff

如果没有输出,说明可行。

否则,说明此 patch 不可行,可能缺少之前的 patch 步骤

Step 5.1 git am --signoff <

git am --signoff < $FILE.diff

该命令也许会有一些 warning,但都是编码质量方面的,只要 check 那步没问题这一步就没问题。

打完之后,不放心可以打开某几个文件检查一下,看看代码是否修改成功。

step 5.2 git apply -3 (solving error: fatal: empty ident name (for \<\>) not allowed)

git apply --reject PATCH_FILE
git apply -3 PATCH_FILE

picture 21

picture 20

ref

merge git patch files

ref:

Step 1. download combinediff

Step 2. build combinediff

  1. extract the xxx.tar.xz

  2. ./configure && make && make install

Step 3. use combinediff
# combine
combinediff FILE1.diff FILE2.diff > merged.diff

# interpolate FILE1 - FILE2
combinediff --interpolate FILE1.diff FILE2.diff > interpolate.diff
Usage of combinediff --interpolate
# drop all the only diffs in patch2
perl -i.bak -0pe "s|^only in patch2.*||smg" interpolate.diff

# drop a specific big diff
# if there is "+++", you should use "\"
perl -i.bak2 -0pe "s|reverted:
--- b/services/surfaceflinger/HmdType6DistortionMesh.cpp.*?(?=reverted)||smg" interpolate.diff

# check the size difference of `xx | xx.bak | xx.bak2`
l | grep interpolate

# show the html
# ref: https://github.com/rtfpessoa/diff2html-cli#setup
diff2html -i file --style side -- interpolate.diff

git submodule

ref:

config submodule

(.pyenv) ➜  mark_keeps_learning git:(master) ✗ cat .gitmodules                                                                  [23-01-22 | 5:39:31]
[submodule "whats-the-best-to-learn"]
path="whats-the-best-to-learn"
url="https://github.com/whats-the-best/whats-the-best-to-learn"

init and push submodule

git submodule init

git push

add submodule

git submodule add URL PATH

git commit

git remove a specific from specific commits

conclusion

FILE="XXX"

git reset --soft HEAD^
git reset HEAD $FILE
git rm -- cached $FILE
git commit --amend

detail

# step 1. stage all the committed files
git reset --soft HEAD^

# step 2. remove file from staging area
git reset HEAD <FILENAME>

# step 3. rm file from cached
git rm -- cached <FILENAME>

# step 4. re-commit
git commit --amend

ref:

git remove specific file from history

# solution 1. using `git filter-branch`
git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch <path to the file or directory>' --prune-empty --tag-name-filter cat -- --all

# solution 2. using `git filter-repo`
pip3 install git-filter-repo
git filter-repo --path <path to the file or directory> --invert-paths

ref:

git merge commits (reset)

ref:

Step 1. reset

# this would reset to before the SHA_ID (i.e. keep the SHA_ID, but remove all the commits before)
git reset --soft SHA_ID && git commit

Step 2. push

# since the commits are changed, the normal `push` won't help, you need to use `--force`
git push -f

git commit amend

!!!warning Use the git commit --amend only when files are not changed, otherwise use a new commit and use the git reset --soft if need to merge the history commits.

git commit --amend

git push -f

ref:

generate diff file from commit

# check sha
git log --oneline

# generate diff
git diff <commit-sha> -p

# generate diff to file
git diff COMMIT_SHA -p > DIFF_FILE

ref:

git reflog

customized git reflog

git reflog --format="%C(auto)%h %<|(17)%gd %C(blue)%ci %C(reset)%an %C(green)%gs"

The core concept is at Git - pretty-formats Documentation, and I explored the following formats relatively satisfying.

  1. --oneline for short and easy to remember

    git reflog --oneline
    picture 89
  2. --date=iso for short and datetime display

    git reflog --date=iso
    picture 90
  3. --format="%h %gd %ci %gs" for full info

    git reflog --format="%h %gd %ci %gs"
    picture 91
  4. for alignment of HEAD, since it may be two-digit

    git reflog --format="%h %<|(17)%gd %ci %gs"
    picture 92
  5. [RECOMMEND] for alignment and color print

    git reflog --format="%C(auto)%h %gd %C(blue)%ci %C(reset)%an %C(green)%gs"
    picture 93
  6. with align

    git reflog --format="%C(auto)%h %<|(17)%gd %C(blue)%ci %C(reset)%an %C(green)%gs"

    I quite love this color scheme!

clean reflog (unreachable)

git reflog expire --expire=90.days.ago --expire-unreachable=now --all

before clean:

There are a lot of reflog entries, and a lot of them are unreachable (just a record).

after clean:

It becomes clean.

picture 5

ref:

delete one specific reflog entry

git reflog delete SHA_ID

ref:

git diff

only show file names

git diff XXX --name-only

set tab width to be 4

git config --global core.pager 'less -x1,5'

picture 157

ref:

show config info (global)

git config --list

It's same to run as:

cat ~/.gitconfig

github cli

documentation:

gh | GitHub CLI

usage sample:

git lfs: About Erasing Large File Commit in the Git History

ref:

Conclusion

clear commands

!!!warning 1. 注意grep不支持强化正则,比如 positive/negative lookahead/lookbackward,以及$这些 2. 如果一定要使用这些,推荐尝试perl或者awk

EXCLUDE_RE="life/王者荣耀"

# 有时需要加 `-f` 参数
# 删除全部
git filter-branch --prune-empty --index-filter "git rm --cached -rf --ignore-unmatch ${EXCLUDE_RE}" --tag-name-filter cat -- --all
# 删除从某个commit到ref(比如HEAD)
git filter-branch -f --prune-empty --index-filter "git rm --cached -rf --ignore-unmatch ${EXCLUDE_RE}" --tag-name-filter cat $COMMIT_ID...HEAD

执行成功后将会有修改记录输出,如下:

picture 3

check if file exists in history

git log --graph --decorate --pretty=oneline --abbrev-commit --all --name-status  | grep -E ${EXCLUDE_RE}

check log history

git lola

push if ok

git push

PR: update to use git filter-repo

Details

这个问题的原因找到了,就在于我曾经 add 了大文件,然后又 delete 了,虽然文件已经不在了,最新的 commit 里也没有这个文件了,但是 history 里有,于是 git 不允许我 push commit,要么我采取 lfs(large file storage)的方法,要么想办法把这个记录从 history 里删掉:

git log --graph --decorate --pretty=oneline --abbrev-commit --all --name-status  | grep -E "Electron Framework$|^\*"
picture 1

最后用这个命令,把 git history 中所有与那个大文件相关的(即 node_modules 文件夹)都删除就可以了:

git filter-branch --prune-empty -d ~/temp \
--index-filter "git rm --cached -rf --ignore-unmatch mark_learns_coding/JS/MarkLearningWebpack/demo7/node_modules" \
--tag-name-filter cat -- --all
picture 2picture 3picture 4picture 5

Acknowledgement: 非常感谢 stackoverflow 大佬专业又详细的回答,没有大佬的解答,我可能又要耗费一个通宵才能解决这个相对比较罕见的问题了:https://stackoverflow.com/a/2158271/9422455

另外,他使用的git lola很有用,需要在~/.gitconfig文件中加入以下:

# git lola | Conrad Parker, http://blog.kfish.org/2010/04/git-lola.html
[alias]
lol = log --graph --decorate --pretty=oneline --abbrev-commit
lola = log --graph --decorate --pretty=oneline --abbrev-commit --all
[color]
branch = auto
diff = auto
interactive = auto
status = auto%

这样就可以使用酷酷的git lola命令了(可以显示历史变动情况),如果加上git lola --name-status之后还可以看到每次 git 会对哪些文件产生怎样的影响,非常好用!

ref:

git cancel reset --hard

git reflog # to show the hashId list, select one

git reset --hard HASH-ID
picture 86

ref:

git pull --ff-only

With git pull --ff-only, Git will update your branch only if it can be “fast-forwarded” without creating new commits. If this can’t be done, git pull --ff-only simply aborts with an error message. You can configure your Git client to always use --ff-only by default, so you get this behavior even if you forget the command-line flag:

git config --global pull.ff only ref: https://stackoverflow.com/a/62653400/9422455

git exclude .gitignore file

echo .gitignore >> .git/info/exclude

ref: