原文:https://www.escapelife.site/posts/f6ffe82b.html
如果我们希望能够快速了解或体验一下
Git
的操作的话,我这里推荐搭建前往这个网站进行学习,其不需要我们安装工具,而且我们的每一步操作都可以在右侧实时看到状态,对于我们学习和理解Git
工作方式和原理非常有帮助的。
Git 实用技巧
主要介绍,企业中常用的 Git 工作流程!
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yxCttnam-1648042484409)(https://www.escapelife.site/images/git-prue-use-pretty-01.png)]
Git 实用技巧 - GitFlow
Git 实用技巧 - GithubFlow
Git 实用技巧 - GitlabFlow
总结日常工作中应该遵循的 Git 使用方式和方法!
subject
和 body
内容,使用空行隔开subject
一般不超过 50
个字符body
每一行的长度控制在 72
个字符subject
结尾不需要使用句号或者点号结尾body
用来详细解释此次提交具体做了什么.gitignore
文件来排除无用文件fork
的开发模式release
分支和 tag
标记进行版本管理release
分支发布代码和版本维护 (release/1.32
)tag
来标记版本 (A - 大feature
功能. B - 小feature
功能. C - 只修bug
)日常使用只要记住
6
个命令就可以了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tvP7EmdW-1648042484412)(https://www.escapelife.site/images/my-learn-git-book-02.png)]
Git 实用技巧 - 常用命令汇总整理
$ git add <file/dir>
$ git commit -m "some info"
$ git push origin master
$ git checkout -- <file>
$ git reset HEAD <file>
$ git clone <git_url>
$ git fetch upstream master
$ git pull upstream master
$ git pull --rebase upstream master
$ git reset <commit>
$ git reset --mixed <commit>
$ git reset --soft <commit>
$ git reset --hard <commit>
虽然配置比较简单,但是非常有用!
$ git config --global user.name "your_name"
$ git config --global user.email "your_email"
$ git config --global core.editor "nvim"
$ git config --global core.pager "more"
$ git config --global alias.gs "git status"
$ git config --global help.autocorrect 1
$ git config --list
$ git config user.name
$ git config user.name "your_name"
$ cat .git/config
[user]
name = "your_name"
......
到底什么时候使用 merge 操作,什么时候使用 rebase 操作呢?
支持使用 merge
的开发者,他们认为仓库的提交历史就是记录实际发生过什么,它是针对于历史的一个文档,本身其实是有价值的,我们不应该随意修改。我们改变历史的话,就相当于使用 “谎言” 来掩盖实际发生过的事情,而这些痕迹是应该被保留的。可能,这样并不是很好。
* 62a322d - (HEAD->master) Merge branch 'hotfix3' into master
|\
| * 6fa8f4a - (hotfix3) 3rd commit in hotfix3
* | 548d681 - 3rd commit in master
|/
* 6ba4a08 - 2nd commit
* 22afcc1 - 1st commit
支持使用 rebase
的开发者,他们认为提交历史是项目过程中发生过的事情,需要项目的主干非常的干净。而使用 merge
操作会生成一个 merge
的 commit
对象,让提交历史多了一些非常多余的内容。
当我们后期,使用 log
命令参看提交历史的话,会发现主干的提交历史非常的尴尬。比如,同样的修改内容重复提交了两次,这显然是分支合并导致的问题。
* 697167e - (HEAD -> master, hotfix) 3rd commit
* 6ba4a08 - 2nd commit (2 minutes ago)
* 22afcc1 - 1st commit (3 minutes ago)
总的原则就是,只对尚未推送或分享给其他人的本地修改执行变基操作清理历史,从不对已经推送到仓库的提交记录执行变基操作,这样,你才可能享受到两种方式带来的便利。
Git
提供了一些工具,可以帮助我们完善版本库中的提交内容,比如:
commit
提交记录日常开发中,我们为了完成一个功能或者特性,提交很多个
commit
记录。但是在最后,提交PR
之前,一般情况下,我们是应该整理下这些提交记录的。有些commit
需要合并起来,或者需要将其删除掉,等等。
$ git rebase -i HEAD~5
$ git rebase -i 5af4zd35
reword c2aeb6e 3rd commit
squash 25a3122 4th commit
pick 5d36f1d 5th commit
fixup bd5d32f 6th commit
drop 581e96d 7th commit
$ git log
* ce813eb - (HEAD -> master) 5th commit
* aa2f043 - 3rd commit -> modified
* 6c5418f - 2nd commit
* c8f7dea - 1st commit
编号 | 选项列表 | 对应含义解释 |
---|---|---|
1 | p/pick | 使用这个 commit 记录 |
2 | r/reword | 使用这个 commit 记录;并且修改提交信息 |
3 | e/edit | 使用这个 commit 记录;rebase 时会暂停允许你修改这个 commit |
4 | s/squash | 使用这个 commit 记录;会将当前 commit 与上一个 commit 合并 |
5 | f/fixup | 与 squash 选项相同;但不会保存当前 commit 的提交信息 |
6 | x/exec | 执行其他 shell 命令 |
7 | d/drop | 移除这个 commit 记录 |
有时候提交之后,我们才发现提交的历史记录中存在这一些问题,而这个时候我们又不想新生成一个
commit
记录,且达到一个修改的目录。即,修改之前的commit
提交记录。
bash
$ git --no-pager log --oneline -1
d5e96d9 (HEAD -> master) say file
$ echo "hello" > say.txt
$ git add -u
$ git commit --amend
$ git commit --amend --no-edit
$ git commit --amend -m "some_info"
$ git --no-pager log --oneline -1
9e1e0eb (HEAD -> master) say file
commit
中的部分提交我们开发了一个功能,而在上线的时候,产品经理说这个功能的部分特性已经不需要了,即相关特性的提交记录和内容就可以忽略 / 删除掉了。
$ git revert 3zj5sldl
commit
提交我们不希望合并整个分支,而是需要合并该分支的某些提交记录就可以了。
$ git cherry-pick -x z562e23d
如何找回我们丢失的内容和记录?
$ git reset --hard <commit>
$ git push origin master -f
$ git branch -D <branch_name>
Git
给我们留了一个后门,就是使用 relflog
命令来找回之前的内容,只不过是相对来说麻烦一些。而原理也很简答,就是在我们使用 Git
命令操作仓库的时候,Git
偷偷地帮助我们把所有的操作记录了下来。$ git --no-pager log --oneline -1
4bc8703 (HEAD -> master) hhhh
$ git reset --hard HEAD~1
$ git reflog
6a89f1b (HEAD -> master) HEAD@{0}: reset: moving to HEAD~1
4bc8703 HEAD@{1}: commit (amend): hhhh
$ git cherry-pick 4bc8703
批量修改历史提交虽然不常用,但是理解的话可以省下很多时间!
之前我们学习到的命令都是针对于一个或者多个
commit
提交信息进行修改的,如果我们需要全局修改历史提交呢?当然,Git
中也是支持全局修改历史提交的,比如全局修改邮箱地址,或者将一个文件从全局历史中删除或修改。
这里我们可以使用
filter-brach
的方式进行修改,但是建议在使用之前,新建一个分支,在上面进行测试没有问题之后,再在主干上操作,防止出现问题,背个大锅在身上。
$ git branch -b testing
$ git filter-branch --commit-filter '
if [ "$GIT_AUTHOR_EMAIL" == "escape@escapelife.site" ]; then
GIT_AUTHOR_;
GIT_AUTHOR_EMAIL="escape@gmail.com";
git commit-tree "$@"
else
git commit-tree "$@"
fi' HEAD
主要介绍. git/hooks 目录下面的示例钩子函数!
Git
里面有两类,分别对应客户端和服务端钩子函数。客户端的钩子函数,是在执行提交和合并之类的操作时调用的。而服务端钩子函数,就是当服务端收到代码提交之后,可以出发代码检查和持续集成的步骤。作为开发者我们并不会搭建 Git
服务器,所以基本不会涉及。Git
自带的钩子脚本,但是自带的都以 .sample
作为后缀,表示并没有启用,表示为一个示例。如果需要启用的话,将 .sample
作为后缀删除掉,即可。而其钩子脚本的对应内容,都是使用 Shell
语法进行编写的。➜ ll .git/hooks
total 112
-rwxr-xr-x applypatch-msg.sample
-rwxr-xr-x commit-msg.sample
-rwxr-xr-x fsmonitor-watchman.sample
-rwxr-xr-x post-update.sample
-rwxr-xr-x pre-applypatch.sample
-rwxr-xr-x pre-commit.sample
-rwxr-xr-x pre-merge-commit.sample
-rwxr-xr-x pre-push.sample
-rwxr-xr-x pre-rebase.sample
-rwxr-xr-x pre-receive.sample
-rwxr-xr-x prepare-commit-msg.sample
-rwxr-xr-x update.sample
PR
请求并通过 Github
的 CI
检查,接下来进行代码评审,最后被合并入主干。但是,好的一个习惯就是,在代码提交之前就应该保证代码不会出现语法错误等基础问题,比如通过 flake8
和 PEP8
标准等。pre-commit
这个 Github
的开源项目了,其本质就是给项目添加钩子函数的一个脚本,可以保证我们在提交代码或者推送代码之前,先检查代码的质量。pre-commit-hooks
这个项目里面包含的就是,现在所支持的钩子脚本,即开箱即用的钩子脚本集合。而其钩子脚本的对应内容,都是使用 Python
语法进行编写的。$ pip install pre-commit
$ pre-commit install -f --hook-type pre-push
$ cat .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.9.2
hooks:
- id: trailing-whitespace
- id: flake8
$ git push origin master
在大项目中工作中,拉取代码非常占时间!
Linux
或 Python
这样的大型项目贡献提交的时候,首先遇到的问题就是,如果快速的 clone
该项目到本地。因为改项目提交历史超多且仓库巨大,加了国内网络的问题,可能等项目完全拉下来的时候,我们的热情都消减下去了。Git
也帮我们想到了这样的问题,我们可以使用 --depth
参数值拉取远程仓库上面最新一次的提交历史,并不包含项目历史记录,即 .git/objects/
目录下的对象只是本地的,并不包含之前的多次修改产生的对象。$ git clone http://xxx.xx.xxx/xxx --depth=1
clone
仓库中的某个 tag
版本对应下的内容。如果我们直接使用 clone
命令是无法做到的,需要执行如下操作,即可完美解决。$ git init xxx-15-0-1
$ git remote add origin http://xxx.xx.xxx/xxx
$ git -c protocol.version=2 fetch origin 15.0.1 --depth=1
$ git checkout FETCH_HEAD
lfs
文件,现在 clone
又会变得非常慢。可以使用如下操作来避免,Git
工具主动拉去 lfs
文件,来达到目录。$ GIT_LFS_SKIP_SMUDGE=1 git clone http://xxx.xx.xxx/xxx
如果在多路运转的时候,还能够高效的进行开发!
bug
需要让你来修复下。但是,此时我们添加的小功能并没有完成。bug
之后,再继续工作。Git
也帮我们想到了这样的问题,我们可以使用 stash
子命令帮助我们将当前工作区、暂存区当中的修改都保存到堆栈之中。等到需要处理的时候,再弹出堆栈中的内容,我们再次进行开发。➜ git stash -h
usage: git stash list [<options>]
or: git stash show [<options>] [<stash>]
or: git stash drop [-q|--quiet] [<stash>]
or: git stash ( pop | apply ) [--index] [-q|--quiet] [<stash>]
or: git stash branch <branchname> [<stash>]
or: git stash clear
or: git stash [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
[-u|--include-untracked] [-a|--all] [-m|--message <message>]
[--pathspec-from-file=<file> [--pathspec-file-nul]]
[--] [<pathspec>...]]
or: git stash save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
[-u|--include-untracked] [-a|--all] [<message>]
$ git stash
$ git stash -u
$ git stash list
$ git stash apply <stash@{n}>
$ git stash drop <stash@{n}>
$ git stash pop
$ git stash clear
$ git checkout <stash@{n}> -- <file-path>
push
并保存到远程仓库里面。这样的好处在于,可以远端备份我们的修改,不会害怕本地文件丢失等问题。等到我们需要继续开发的时候,拉下对应内容,再想办法进行补救,比如使用 --amend
或者 reset
命令。$ git commit --amend
$ git commit --amend -m "some_info"
$ git reset a87f328
$ git reset HEAD~
$ git reset HEAD~2
$ git reset <tag>~2
$ git reset --mixed <commit/reference>
$ git reset --soft <commit/reference>
$ git reset --hard <commit/reference>