Git命令
基本操作
C
- 添加到版本控制:
git add filename.md
- 添加描述并提交:
git commit -m "first init"
R
- 查看图形 log:
git log --graph
- 查看单行 log:
git log --pretty=oneline
- 查看分支合并情况:
git log --graph --pretty=oneline --abbrev-commit
- 查看工作区和版本库最新版本的区别:
git diff HEAD -- test.xml
- 列出每个人的最近 commit 记录:
git shortlog
- 列出每个人的 commit 次数:
git shortlog -sne
U
- 修改提交信息:
git commit --amend
- 取消添加(git add .)的命令:
git reset HEAD test.xml
D
- 移除工作空间的文件:
git rm test.xml
- 丢弃工作区的修改:
git checkout -- test.xml
,其中--
很重要,没有这个--
,就变成了“切换到另一个分支”。
RESET
将 HEAD 指向到某个版本:
git reset --hard commit_id
重返未来,用
git reflog
查看命令历史,以便回到未来的那个版本。git reset 后丢弃远程的提交
1
2
3git log # 获取log的某次提交commit id
git reset --hard 0301382 # 回退到0301382
git push --force # 强制推送到服务器端Git 撤销 git commit 但是未 git push 的修改
git reset commit_id
-
1
git reset --hard HEAD~
How can I undo those commits from the local repository?
https://stackoverflow.com/questions/927358/how-do-i-undo-the-most-recent-local-commits-in-git
1 | git reset HEAD~ |
远程仓库
移除远程仓库:
git remote remove origin
添加远程仓库:
git remote add origin git@github.com:lyloou/lou.git
添加多个远程仓库:
git remote add jquery https://github.com/jquery/jquery.git
远程主机改名:
git remote rename <原主机名> <新主机名>
删除远程主机:
git remote rm <主机名>
显示远程主机详细信息:
git remote show <主机名>
提交到远程仓库:
git push -u origin master
由于远程库是空的,我们第一次推送 master 分支时,加上了-u 参数,Git 不但会把本地的 master 分支内容推送的远程新的
master 分支,还会把本地的 master 分支和远程的 master 分支关联起来,在以后的推送或者拉取时就可以简化命令
(git push origin master
)。http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013752340242354807e192f02a44359908df8a5643103a000拉取并且合并远程分支:
git pull origin master --allow-unrelated-histories
删除远程文件夹或文件,但是本地还保留着:
git rm -r --cached dir2
(-r
参数,表示递归删除文件夹的内容)删除远程文件夹或文件,但是本地还保留着(展示要删除的文件,不是真的删除):
git rm -r -n --cached dir2
pull = fetch + merge
直接修改远程仓库 url
git remote set-url origin git:new.url.here
See this question: Change the URI (URL) for a remote Git repository - Stack Overflowclone repo with its submodule (use the –recursive argument)
git clone –recursive git@github.com:rbind/yihui.git
https://yihui.name/cn/2017/03/git-submodule/- 如果克隆库的时候要初始化子模块,请加上 –recursive 参数,如:
git clone –recursive git@github.com:rbind/yihui.git - 如果已经克隆了主库但没初始化子模块,则用:
git submodule update –init –recursive - 如果已经克隆并初始化子模块,而需要从子模块的源更新这个子模块,则:
git submodule update –recursive –remote - 如果要向一个库中添加一个新的子模块,可以用 git submodule add
git submodule add https://github.com/yihui/hugo-lithium-theme.git themes/hugo-lithium-theme
- 如果克隆库的时候要初始化子模块,请加上 –recursive 参数,如:
分支
创建空白分支
1 | git checkout --orphan gh-pages |
delete a git branch both locally and remotely.
1 | $ git push --delete <remote_name> <branch_name> |
本地分支
- 删除本地分支:
git branch -d {the_local_branch}
远程分支
添加本地分支到远程分支,并关联:
git push -u origin develop
创建远程 origin 的 dev 分支到本地:
git checkout -b dev origin/dev
指定本地 dev 分支与远程 origin/dev 分支的链接:
git branch --set-upstream dev origin/dev
git clone
默认会把远程仓库整个克隆下来,但只会创建master
分支,如果远程还有其他分支,可以通过下面的方式 clone 分支。- 将远程分支获取至本地仓库:git checkout -b python_mail.skin origin/python_mail.skin
- 使用-t 参数,它默认会在本地建立一个和远程分支名字一样的分支:git checkout -t origin/python_mail.skin
- git clone 远程分支 - xqs83 的专栏 - 博客频道 - CSDN.NET
在
git pull
之前,本地分支关联远程分支:git branch --set-upstream feature-A origin/feature-A
提交分支:
git push origin feature-A:feature-A
删除远程分支:
git push origin :feature-A
删除远程分支:
git push --delete {the_remote_branch}
克隆指定分支:
git clone -b rryp https://github.com/bmfe/eros-nexus.git "nexus" --depth=1
合并 merge & rebase
-
If there were uncommitted worktree changes present when the merge started,
git merge --abort
will in some cases be unable to reconstruct these changes
It is therefore recommended to always commit or stash your changes before running git merge.
1 | # 我要新增一個功能,所以在master上開一個branch叫feature1。 |
remove untracked files
1 | $ git clean -d -f |
branch - How to remove local (untracked) files from the current Git working tree? - Stack Overflow
git stash
Git 还提供了一个 stash 功能,可以把当前工作状态“储藏”起来,等以后恢复现场后继续工作。
查看 stash 的列表:
git stash list
恢复:
git stash pop
或者git stash apply
一是用 git stash apply 恢复,但是恢复后,stash 内容并不删除,你需要用 git stash drop 来删除;
另一种方式是用 git stash pop,恢复的同时把 stash 内容也删了:参考资料:
Bug 分支
添加注释的技巧
参考golang.org/x/net
的提交日志:
1 | * 92b859f - ipv6: update icmp parameters (4 days ago) <Mikio Hara> |
名称最好简洁、准确,
可以总结:模块: 动词 + 名词;
动词:
1 | - add |
delete all tags
To delete remote tags (before deleting local tags) simply do:
1 | git tag -l | grep v2 -v | xargs -n 1 git push --delete origin |
and then delete the local copies:
1 | git tag -l | grep v2 -v | xargs git tag -d |
How do you rename a Git tag?
1 | git tag new old |
Remove a file from a Git repository without deleting it from the local filesystem
1 | # For single file: |
git delete remotes: remote refs do not exist - Stack Overflow
1 | # You may need to prune your local "cache" of remote branches first. Try running: |
How to revert multiple git commits? - Stack Overflow
Expanding what I wrote in a comment
The general rule is that you should not rewrite (change) history that you have published, because somebody might have based their work on it. If you rewrite (change) history, you would make problems with merging their changes and with updating for them.
So the solution is to create a new commit which reverts changes that you want to get rid of. You can do this using git revert command.
You have the following situation:
1 | A <-- B <-- C <-- D <-- master <-- HEAD |
(arrows here refers to the direction of the pointer: the “parent” reference in the case of commits, the top commit in the case of branch head (branch ref), and the name of branch in the case of HEAD reference).
What you need to create is the following:
1 | A <-- B <-- C <-- D <-- [(BCD)-1] <-- master <-- HEAD |
where [(BCD)^-1]
means the commit that reverts changes in commits B, C, D. Mathematics tells us that (BCD)-1 = D-1 C-1 B-1, so you can get the required situation using the following commands:
1 | $ git revert --no-commit D |
Works for everything except merge commits.
Alternate solution would be to checkout contents of commit A, and commit this state. Also works with merge commits. Added files will not be deleted, however. If you have any local changes git stash
them first:
1 | $ git checkout -f A -- . # checkout that revision over the top of local files |
Then you would have the following situation:
1 | A <-- B <-- C <-- D <-- A' <-- master <-- HEAD |
The commit A’ has the same contents as commit A, but is a different commit (commit message, parents, commit date).
Alternate solution by Jeff Ferland, modified by Charles Bailey builds upon the same idea, but uses git reset. Here it is slightly modified, this way WORKS FOR EVERYTHING:
1 | $ git reset --hard A |
统计
统计 tag1 和 tag2 之间的行数
1 | git log tag1..tag2 --pretty=tformat: --numstat | gawk '{ add += $1 ; subs += $2 ; loc += $1 + $2 } END { printf "added lines: %s removed lines : %s total lines: %s\n",add,subs,loc }' |
统计某个人修改的代码行数
1 | # 当前作者 |
按个人分别统计
1 | git log --format='%aN' | sort -u | while read name; do echo -en "$name\t"; git log --author="$name" --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' -; done |
统计总行数
1 | git log --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2 } END { printf "added lines: %s, removed lines: %s, total lines: %s\n", add, subs, loc }' - |
按时间范围统计个人行数
1 | git log --since="2020-01-08" --before="2021-11-14" --author="lilou" \ |
仓库提交排名
1 | git log --pretty='%aN' | sort | uniq -c | sort -k1 -n -r | head -n 5 |
贡献者统计
1 | git log --pretty='%aN' | sort -u | wc -l |
提交数统计
1 | git log --oneline | wc -l |
参考链接
《GitHub 入门与实践》
-
1
2
3- `^`代表父提交,当一个提交有多个父提交时,可以通过在`^`后面跟上一个数字,表示第几个父提交,`^`相当于`^1`
- `~`<n>相当于连续的<n>个`^`.
- checkout只会移动HEAD指针,reset会改变HEAD的引用值