0%

git 技巧

整理一些git常用的命令和一些骚操作~

git log

查看提交历史,默认不包含任何参数,或按照提交时间列出所有的更新,最新的排在上面。

查看提交的差异(diff)

可以用-p选项来展开每次提交的内容差异,用-2显示最近的两条更新:

1
git log -p -2

还可以使用—stat来简要显示增改的行数统计:

1
git log -p --stat

精简显示log

--pretty=<format>可以以给定的格式打印提交的日志。其中<format>可以是:

  • oneline
  • short
  • mediu
  • full
  • raw

查看某个文件的改动

可以在git log后面直接跟上文件名,来查看针对这个文件的改动(当前分支),加上-p显示具体改动:

1
git log -p file

如果该文件不在当前目录,需要先切换到目录的文件夹。

中文文件名乱码

git 默认中文文件名是\xxx\xxx等八进制形式。是因为对0x80以上的字符进行quote

只需要将core.quotepath设置为false,即可对中文文件名不再转码。

设置的命令:

1
$ git config --global core.quotepath false

然后在查看git log,文件名将显示正常。

搜索

搜索git记录里面author包含zhang

1
git log --author zhang

搜索git记录提交说明message里面包含table的提交:

1
git log --grep table

只要满足任意条件即可显示出来:

1
git log --author zhang --grep table

同时满足两者才可显示:

1
git log --author zhang --grep table --all-match

查看文件的改动

  • git log --name-status 查看每次修改的文件列表,并显示状态
  • git log --name-only 查看每次修改的文件列表
  • git log --stat 查看每次修改文件的列表,以及文件修改行数的统计。

log显示的时间

默认状态下的时间显示为:Date: Thu Sep 3 14:53:25 2020 +0800,这样很不直观,我们需要更直观的表现形式。

可以设置git config log.date ios这样将时间格式设置为iso的形式:Date: 2020-09-25 13:48:04 +0800

可以全局设置下:

1
$ git config --global log.date iso

常用的时间格式有:

  • relative 显示为与当前时间相对的时间,比如:2 hours ago
  • local 显示为本地时区的时间。
  • iso iso格式的时间
  • short 剪短的只展示日期,不显示时间

git blame

git log可以查看当前所有的改动,后面加上文件参数可以查看对于这个文件的所有改动,那么我们想看一个文件的某一行的改动的话怎么看?

可以使用git blame

git blame可以显示一个文件的每一行的最后一次改动的作者和提交hash。然后我们可以根据hash去查看对应的更改。

重要的参数有:

  • -L <start, end> 比如,想查询某个文件的122行到133行的记录,可以:git blame -L 122,133 login.page.ts
  • -t 显示原始时间戳,即不格式化时间,可以节省横向空间。
  • -S 使用resv-file中的修订,而不是调用git-rev-list,更简化的输出。
  • -color-lines 提交的记录的元数据不同的话就颜色不同区分

git branch

git branch如果不加参数,直接执行,输出本地所有分支。当前所在的分支前会加上*号来标记。

git branch -v 加上 -v参数,可以查看各个分支最后一个提交对象的信息。

git branch --merged 加上--merged参数,可以查看哪些分支已被合并入当前分支

git branch --no-merged 加上--no-merged参数,可以查看哪些分支还没有合并进当前分支

筛选本地分支

我们可以通过grep参数筛选分支名:

1
git branch | grep 'hotfix'

上面通过grep参数筛选分支里面包含hotfix字符串的分支,并显示。

可以加上grep -v 'name'的方式,来反向排除:

1
git branch | grep -v 'hotfix'

上面可以展示除过包含’hotfix’字符串的分支。

其实| grep这种用法并不是git的,而是linux中的标准输入输出的管道操作符。grep的选项常用的还有:

  • -i 忽略字符串大小写的差别
  • -v 反转查找
  • -x 只显示全符合的列

批量删除本地分支

有时候本地分支太多了,太乱,需要删除,但不可能一个个删除,那样也太繁琐了,我们怎么批量删除本地分支?

结合上面的过滤分支,我们可以使用linux管道xargs组合起来实现我们的想法。

xargs命令是给命令传递参数的一个管道,也是组合多个命令的一个工具。思路分两步:

  1. 通过git branch | grep获得要删除的分支名称
  2. 将分支名称通过| xargs传递给git branch -D进行删除

具体实现:

  1. 切换到不用删除的分支(比如master:git checkout master)
  2. 删除
    1. 运行:git branch | grep -v 'master' | xargs branch -d(删除本地已提交的分支)
    2. 全部舍弃本地分支: git branch | grep -v 'master' | xargs branch -D

这样,除过master分支之外,其他分支都被删除了。

本地分支跟踪远程分支

在本地创建分支,然后推送到远程,然后拉取的时候,会说本地分支没有跟踪远程分支,需要建立下连接:

1
git branch --set-upstream-to=origin/<branch> you-local-branch

省去这一步,可以在推送远程分支的时候直接加上跟踪当前分支的参数:

1
git push --set-upstream origin you-local-branch

这样,既把本地分支推送到了远程,同时也将本地分支跟踪了远程分支。

查看某个提交属于哪个分支

有时候代码合并之后,忘记了需要去追踪这个提交在哪个分支上存在

1
git branch --contains commitID

git show

对于一次提交来讲,它展示日志消息和文本差异。

1
git show d28737d250651514d629ba8e4e240530505c98dc 

remote 远程库的操作

查看远程url

1
git remote show origin

显示远程库的源地址, 例如:

1
2
3
4
5
6
7
8
9
10
11
╰─$ git remote show origin 
* remote origin
Fetch URL: http://xxxxxxxxx.git
Push URL: http://xxxxxxxxx.git
HEAD branch: master
Remote branches:
master tracked
Local branches configured for 'git pull':
master merges with remote master
Local refs configured for 'git push':
master pushes to master (up to date)

可以列出当前库的远程url,以及本地分支和远程跟踪分支的状态。

或者可以直接简单的查看远程url:

1
git remote -v

输出:

1
2
3
╰─$ git remote -v
origin http://xxxxxxxxx.git (fetch)
origin http://xxxxxxxxx.git (push)

修剪远程已删除的分支

prune的意思是清理、修剪。有时候我们在远程上删除某些分支,但是在本地工程里,例如使用git checkout的时候还是会看到远程已删除的分支。

1
git remote prune

查看远程库里已经删除的分支:

1
git remote prune origin --dry-run

注:后面带着参数dry-run是为了只列出,不删除

如果要列出并删除,那么不带dry-run参数即可:

1
git remote prune origin

修改远程的url

1
git remote set-url origin new-url

比如我们的git是用ssh拉取的,但是ssh太慢了,需要换成http的,那我们只需要:

1
git remote set-url origin http://xxxxxxxxx.git

然后查看换了的url:

1
git remote -v

查看branch的提交信息

当本地有很多分支的时候,我们想找到某个分支,但是又会混乱到底哪个分支的内容是啥,这时候就比较捉急了.

我们一般用git branch 这个命令,但是会单独的跳出一个新的窗口,然后只能看到branch的名字.只有我们切过去后才能通过git log查看这个分支对应的commitl信息,这样很不方便.

我们可以用for-each-ref结合shell命令来做一个集成的命令,快速展示各个分支的最后一个提交信息.

~/.gitconfig中配置我们的命令:

1
2
[alias]
branchs-info = "!f() { git for-each-ref --sort=-committerdate --format='%(refname:short)' refs/heads/ | while read branch; do commit=$(git show -s --format='%h' \"$branch\"); subject=$(git show -s --format='%s' \"$branch\"); date=$(git show -s --format='%ci' \"$branch\" | awk -F ' ' '{print $1, $2, $3}' | awk -F '-' '{print $1 \"-\"$2 \"-\"$3}'); echo \"$branch: $subject - $date\"; done; }; f"

这样我们就可以使用git branchs-info这个命令来快速的查看当前每个分支的信息:

1
2
3
4
$ git branchs-info

main: fix - 2024-04-07 21:48:47 +0800
deploy: add theme - 2023-07-27 22:10:31 +0800

这样能够方便快速的找到我们需要的branch,并切在删掉长久不用的分支的时候也很有用.

git tag

打tag

可以方便快速的打tag:

1
git tag v1.0.0

也可以带上描述信息:

1
git tag -a v1.0.0 -m '测试打tag'

将本地tag推送远程:

1
git push origin v1.0.0

删除tag

有时候tag打错了,需要删除:

1
git tag -d v1.0.0

同时也要删除远程的tag:

1
git push origin --delete v1.0.1

获得最近打的tag

获得sit上的最后一个tag:

1
git describe --tags `git rev-list --tags --grep prod --max-count=1`

回滚

最麻烦的莫过于合错了或是提交错了,这种情况需要回滚。

本分支修改,还没提交

可以用checkout来将本地未commit的记录丢弃。

  • git checkout .将本地所有未暂存的记录丢弃
  • git checkout file-path将固定路径的文件的未暂存的修改丢弃
  • git checkout HEAD 将本地分支还原到当前的HEAD,已暂存的也会被丢弃

本分支修改,已经提交了

这个时候还没有推送,还是可以挽回的,所以直接找到想要回退的commit的hash,然后使用reset命令:

1
git reset commit-hash

可以传递参数来标记重置的操作:

  • –soft 缓存区和工作目录都不会改变
  • –mixed 默认选项,缓存区和你指定的提交同步,但工作目录不受影响
  • –hard 缓存区和工作目录都同步到你指定的提交

如果想直接舍弃当前的提交,那么就直接用--hard参数即可全部丢弃。

本分支修改,并已经推送到了远程

这种情况就比较麻烦,可以使用Revert命令

1
git revert commit-hash

Revert撤销一个提交的同时会创建一个新的提交,这是一种安全的做法,它不会重写提交历史。

也可以使用reset命令:

1
2
git reset --hard commit-hash
git push --force

一定要确认好,一旦执行了reset并push --force之后,提交记录就抹去了。修改的东西也会没有了。

相比git resetgit revert不会改变现在的提交历史,可以用在公共分支上,而git reset会将前面的记录抹去,应该用在私有分支上执行。

git commit 提交

常用的提交暂存区到仓库区:

1
git commit -m 'xxx'

多行信息提交:

1
git commit

回车后是在vim中编辑提交信息,这里可以提交多行,编辑好后按照vim的保存退出即可。

提交工作区自上次commit之后的变化,直接到仓库区(即不用先git add):

1
git commit -a

将暂存区的文件提交时在vim中的注释中显示所有diff信息:

1
git commit -v

git diff 查看差异

在未提交的情况下,可以直接使用git diff查看我们修改了啥。或者可以加上文件名称来查看具体某个文件的修改:

1
2
$ git diff
$ git diff source/file/name.txt

在已经暂存(staged)的情况下,我们可以加上参数--staged来查看已暂存的文件的比较:

1
2
$ git diff --staged
$ git diff --staged source/file/name.txt

.gitconfig 文件

git 会在安装好后自带一个git config工具来帮助设置控制Git的外观和行为配置变量。这些变量会存在三个不同的位置:

  • /etc/gitconfig 包含系统上每一个用户以及他们仓库的通用配置。如果在执行git config时带上--system选项,那么就会读写该文件中的配置变量。(需要管理员或超级用户权限来修改它)
  • ~/.gitconfig~/.config/git/config,只针对当前用户,可以传递--global选项来读写该文件,这会对你系统上所有的仓库生效。
  • 当前项目仓库的git目录中的config文件(即.git/config),针对该仓库,可以传递--local选项让git强制读写此文件。

每一个级别会覆盖上一级别的配置。

我们主要常用的是当前用户的配置。需要在当前用户的目录下找是否有~/.gitconfig文件,如果没有就新建:

1
touch ~/.gitconfig

然后在.gitconfig文件中编辑我们的一些特定设置:

1
2
3
4
5
6
7
[alias]
st=status
ck=checkout
cp=cherry-pick
cm=commit -m
[user]
name = tony

克隆固定分支

因为特定情景需要,我们可能需要clone一个项目的特定分支,然后去做对应的业务.但是如果项目很庞大,直接用git clone这样下来的话会将整个项目每个分支都拉下来,文件很多,遇到网络问题可能拉取速度只有几十kb,这样会很慢.

因为我们需要的是特定分支的代码,所以我们可以在clone的时候将分支参数带上,就只拉取特定分省去很多不必要的文件:

1
git clone --depth=1 --branch orderly-prod --single-branch git@gitlab.com:xxx.git

一对比真的会省去很多资源文件,速度也变快了.

git clean 清理

有时候搞了很多新文件并且有修改的地方,但是需要舍弃全部,这时候我们用git checkout .只能还原已经跟踪的文件,如果是新建的文件或文件夹,是不会动的.之前是手动一个个使用rm -rf来删除,很傻.

我们可以使用git clean命令来清除未track的文件和文件夹.

git clean -n 传递-n参数会显示将要删除的文件,但只是显示,不会删除.
git clean -f 传递-f参数会删除新增的未track的文件,但不会删除新增文件夹和文件夹里面的文件.
git clean -df 传递-df参数会删除新增的未track的文件和文件夹(包括文件夹下面的文件).
git clean -xdf 传递-xdf参数会删除新增的未track的文件和文件夹(包括文件夹下面的文件),还包括被.gitignore文件过滤的文件或文件夹,所以这个命令是一般不用.

码字辛苦,打赏个咖啡☕️可好?💘