Git tips
Add permission to be executable in repository
Ensure a script is executable across differrent environments
git update-index --chmod=+x gradlew
git chunk header meaning
-
Header Format:
@@ -before_line, number_of_lines, +after_line, numeber_of_lines @@
andouter function_name
-
3 lines of context before
-
Changed Lines have prefix with
-
for deleted,+
for added -
3 lines of context after
@@ -75,6 +103,8 @@ getFoo()
foo
bar
baz
+line1
+line2
more context
and more
and still context
git show all branches details
git branch -va --format='%(HEAD) %(color:yellow)%(refname:short)%(color:reset) - %(color:red)%(objectname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))'
git branch -va --format='%(HEAD) [%(upstream)] %(color:yellow)%(refname:short)%(color:reset) - %(contents:subject) - %(authorname) (%(color:green)%(committerdate:relative)%(color:reset))'
git rebase
To change the last N commits using interactive rebase:
git rebase -i head~N
git rebase -i head~4
From top to bottom, commits are from old to new. This is the replay order. Opposite to git log order.
Drop a commit
Delete the line of the commit
Edit commit message
Change pick
to reword
Squash commits
Change pick
to s
or squash
to squash the commits.
Ref: https://www.baeldung.com/ops/git-squash-commits
git clone --depth 1
只下载最近一次提交记录,节约时间和空间
git clone --depth 1 ...
重新下载完整的提交记录
git pull --unshallow
Rewrite history
Change case of folder
git
最初用于 Linux。Linux 是大小写敏感的,但 Windows 和 MacOS 却是大小写不敏感的,因此需要先重命名为其它名字。
git mv foo foo2
git mv foo2 FOO
git commit -m "Change case of folder"
Three ways to exclude files
-
.gitignore
applies to every clone of this repository -
.git/info/exclude
only applies to your copy (local) -
~/.gitignore
applies to all repositories (local)git config --global core.excludesfile `~/.gitignore`
Remove untracked file
# Dry run
git clean -n
git clean
git clean -f
Add empty folder
.gitignore
# Ignore everything in this directory
*
# Except this file
!.gitignore
checkout accept theirs
or accept ours
git checkout --ours -- <filename>
git checkout --theirs -- <filename>
Pathspec xxx did not match any files known to git
确保提交完代码或做好备份
# Paths are removed from the index
git rm -r --cached .
# Reset
git reset .
Git proxy
Enable and disable proxy for all or a specific URL
git config --global http.proxy 'socks5://127.0.0.1:1000'
git config --global --unset http.proxy
git config --global http.https://github.com.proxy 'socks5://127.0.0.1:1000'
git config --global --unset http.https://github.com.proxy
It's saved in ~/.gitconfig
.
Git gui clients
图形化的 GUI 相对 CMD 更适合展示复杂的相互关联的信息。
-
Editor git plugins
Recover from add+reset file
cd .git/lost-found/other
grep -r 'content' .
git merge / git rebase
git pull
相当于 git fetch
+ git merge
。那么git merge
和 git rebase
有什么区别呢?两者都是对代码进行合并,具体的方式有所不同,最终合并后代码的提交记录也会不同。
fetch
后的代码
- o - o - o - H - A - B - C (master)
\
P - Q - R (origin/master)
merge
后的代码
- o - o - o - H - A - B - C - X (master)
\ /
P - Q - R -- (origin/master)
rebaes
后的代码
- o - o - o - H - P - Q - R - A' - B' - C' (master)
|
(origin/master)
使用git pull
可以启用rebase
合并方式
# config
git config branch.<name>.rebase true
# once
git pull --rebase
git pull VS git fetch Vs git rebase
blame
查看文件每行或某几行最近改动的记录,显示 commit id
git blame [head] README.md
git blame -L 1,5 README.md
查看某几行的提交记录,显示 commit message
git log -u -L 1,5:README.md
log
查看包含某个改动的提交详情
git log -S "some change"
查看用户的提交,部分匹配
git log --author="Name"
# 当前用户
git log --author="$(git config user.name)"
查看某个文件相关的提交
git log -- filepath
# With patch
git log -p -- filepath
Error: Permission denied (publickey)
Error: Permission denied (publickey)
git diff
查看 pull 后的更改
git diff @{1}
查看某个文件的更改
git diff commit-id file
查看特定提交的更改
git diff commit-id~ commit-id
git show commit-id
查看最近提交的更改
最近一次
git diff HEAD~..HEAD
默认和 HEAD 比较,可以省略。@
是 HEAD 的缩写。
git diff HEAD~
git diff @^
git diff commit-id
最近两次更改的文件名和状态
git diff --name-status HEAD~2..HEAD
使用配置的图形化工具查看
git difftool HEAD~..HEAD
HEAD 后的符号 windows:
~
, Linux:^
or~
查看未提交时的更改
git diff
git pull branch
git pull origin <branch>
Merge commits into the branch
git checkout <branch>
git cherry-pick <commit-id>
git clone branch
git clone --single-branch --branch <branch> <remote-repo>
Add empty folder
在该目录中添加 .gitignore
文件。参考
# Ignore everything in this directory
*
# Except this file
!.gitignore
Reduce .git folder?
repack
重新打包内部文件
git repack -a -d --depth=250 --width=250
可以舍弃 commit history 的情况
确认不需要以往历史记录的情况,可以重新生成 master 分支。所有本地仓库都需要重新 clone。
# 新建分支并提交
git checkout --orphan lastest_branch
git add -A
git commit -m "message"
# 删除并替换原 master 分支
git branch -D master
git branch -m master
# 上传,再从远程仓库下载,.git 文件夹会小很多
git push -f origin master
How to write git commit message
How to Write a Git Commit Message
Style, Content, Metadata 三个方面统一规范
- Separate subject from body with a blank line
- Limit the subject line to 50* characters
- Capitalize the subject line
- Do not end the subject line with a period
- Use the imperative mood in the subject line
- Wrap the body at 72 characters
- Use the body to explain what and why vs. how
For example:
- Refactor subsystem X for readability
- Update getting started documentation
- Remove deprecated methods
- Release version 1.0.0
同步其它分支的文件
git checkout master
git checkout gh-pages README.md
回滚到某次提交
# 保留修改
git reset --soft <commit_id>
# 放弃修改
git reset --hard <commit_id>
# 更新远程仓库
git push -f
查看某个提交记录并返回
# 查看记录
git checkout <commit_id>
# 返回分支头部
git checkout <branch_name>
# 返回最近的分支
git checkout -
缓存修改
在一个分支上修改时,如果中途需要临时切换到另一个分支且还不能提交代码,可以使用缓存命令保留修改
# 缓存修改
git stash
# 添加注释 save
git stash save <message>
# 缓存特定文件
git stash push -m <message> file1 file2
# git checkout other_branch
# ...
# git checkout origin_branch
# 恢复修改
git stash pop # 生效后移除缓存
git stash apply # 生效后仍保留缓存
# 查看修改
git stash show -p stash@{0} --name-only
# 列出所有
git stash list
# 移除不要的 stash
git stash drop <id>
git stash drop 0
# 移除所有 stash
git stash clear
当前修改提交到另一个分支
改动在提交前和分支没有关系,
-
未提交,可以直接切换分支后再提交。如果文件有冲突,需要
stash
-
已经提交,
git log # commit-id git checkout branch git cherry-pick <commit-id> git checkout master git reset HEAD~1
删除文件
错误上传文件后,需要删除仓库中的文件
同时删除本地文件和仓库索引
git rm <file>
等价于
rm <file>
git add <file>
不再追踪已经提交的文件(加入.gitignore)
仅删除仓库索引,保留本地文件
# Modify .gitignore
git rm --cached <file>
git add <file>
git commit -m "Message"
根据 commit hash checkout 恢复相应的文件
git checkout c5f567~ -- file/to/restore
未提交
git checkout -- file/to/restore
查看删除的文件
git log --diff-filter=D --summary
未提交
git ls-files --deleted
撤销已经 push 的提交
通过新增一个相反的提交,来抵消某次提交的效果
git revert <commit_id>
git push
syncing a fork
Github fork 过来的仓库如何更新呢?upstream 是原始远程仓库地址。
git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git
git fetch upstream
git checkout master
# 更新自己的本地仓库
git merge upstream/master
# 更新自己的远程仓库
git push origin master
merge, rebase, cherry-pick
假设需要合并 branch 到 master
merge,提交历史保持并行,适合远程和本地的合并
git checkout master
git merge branch
rebase,提交历史变成串行,适合本地合并
git checkout branch
git rebase master
cherry-pick,合并分支中某个指定的提交
git checkout master
git cherry-pick <commit-id-from-branch>
切换分支时,修改过本地文件会被覆盖的错误处理
error: Your local changes to the following files would be overwritten by checkout
在切换回来时,能保留本地文件的修改,可以使用git stash
# on master
git stash save file-name
# do sth with branch
git checkout branch
git checkout master
git stash pop
查看某次提交修改的文件
git diff-tree --no-commit-id --name-only -r <commit-id>
查看某个文件或分支对应的提交
git rev-parse master
git rev-parse master:README.md
分支新建、合并、上传、删除
新建
git checkout -b new_branch
将 new_branch 合并到 master
git checkout master
git merge new_branch
上传
git push origin new_branch:new_branch
删除本地分支
git branch -d new_branch
删除远程分支
git push --delete origin new_branch
查看分支
查看本地
git branch
查看远程
git branch -r
# or
git ls-remote
查看所有
git branch -a
fatal: refusing to merge unrelated histories
GitHub 新建了仓库,并加入证书。同时本地仓库也单独作了提交。合并时会报错
git pull
fatal: refusing to merge unrelated histories
需要添加参数
git pull --allow-unrelated-histories
查找 Github 上 stars 最多的仓库
https://github.com/search?q=stars:>1&s=stars&type=Repositories
不跟踪加到代码库中的文件变化
添加file
git update-index --assume-unchanged file
撤销file
git update-index --no-assume-unchanged file
不同仓库间同步文件修改时间
原理
先记录所有文件的修改时间到文件中,在目标目录中读取该文件来同步时间。
git_cache-meta.sh
#!/bin/sh -e
#git-cache-meta -- simple file meta data caching and applying.
#Simpler than etckeeper, metastore, setgitperms, etc.
#from http://www.kerneltrap.org/mailarchive/git/2009/1/9/4654694
#modified by n1k
# - save all files metadata not only from other users
# - save numeric uid and gid
# 2012-03-05 - added filetime, andris9
# Modify date
# \( -printf 'touch -c -d "%TY-%Tm-%Td %TH:%TM:%TS" %p\n' \) \
# Access date
# \( -printf 'touch -c -d "%AY-%Am-%Ad %AH:%AM:%AS" %p\n' \) \
: ${GIT_CACHE_META_FILE=.git_cache_meta}
case $@ in
--store|--stdout)
case $1 in --store) exec > $GIT_CACHE_META_FILE; esac
find $(git ls-files)\
\( -printf 'chown %U %p\n' \) \
\( -printf 'chgrp %G %p\n' \) \
\( -printf 'touch -c -d "%TY-%Tm-%Td %TH:%TM:%TS" %p\n' \) \
\( -printf 'chmod %#m %p\n' \) ;;
--apply) sh -e $GIT_CACHE_META_FILE;;
*) 1>&2 echo "Usage: $0 --store|--stdout|--apply"; exit 1;;
esac
用法
源目录,记录文件修改时间
sh git-cache-meta --store
目标目录,应用文件修改时间
sh git-cache-meta --apply