Git
2020-06-12
搜索提交信息
git log --grep=fix: --oneline --after='2018-07-01' --author=markjour
搜索历史文件
git grep -C3 sign_position $(git rev-list --all)
搜索 diff 内容
git log -G'前置'
git log -G'前置' -p | grep '前置' -C5
git log -G'前置' --oneline --name-status
-S<string> --pickaxe-regex
和 -G<regex>
作用相近,
不过 -S
只会列出搜索内容增删的相关信息,也就是所在行修改了,但是搜索内容没有变化的会忽略
Git Windows
2020-03-22
Git 在团队协作的情况下容易遇到很多小问题,有一类是由于跨平台的系统差异导致的。有人习惯 Windows 下开发,有人习惯 Linux 下开发。
最常见的是这么四个问题:
- 文件权限问题
- 基本上我还没有遇到有需要给仓库中的文件设置权限的情况,但是由于权限的变更导致提交进来没有内容更改的文件就完全没有必要
- 所以非常必要设置
core.filemode false
chmod 644 *.md
- 换行符问题
- Windows 新建的文件都是
\r\n
换行,Linux 则是 \n
core.autocrlf true
可以在 checkout 的时候根据系统自动转换换行符
- 但是我觉得这个可能放到 hook 里面,在提交检查的时候一起做更加合适
dos2unix *.md
-
软链接问题
-
Linux 下的软链接切到 Windows 下之后,变成了一个普通文本,内容是链接的路径
core.symlinks true
可以解决这个问题,这也是默认值,可是有些时候我们的环境中配置的就是 false
- 我的 Git for Windows 不知道为什么,system 配置就是设置成 false 了
- 有些情况下,项目配置似乎就默认是 false
- 如果已经成为现实了,软链是个文本,我们改配置,重新添加,然后 pull 到本地可以
core.symlinks
If false, symbolic links are checked out as small plain files that contain the link text. git-update-index
and git-add
will not change the recorded type to regular file. Useful on filesystems like FAT that do not support symbolic links.
The default is true, except git-clone
or git-init
will probe and set core.symlinks
false if appropriate when the repository is created.
- 文件名大小写问题
- Linux 大小写敏感,比如 Apple.txt 和 apple.txt 可以在同一个目录,Windows 环境克隆下来,只能看到一个文件 apple.txt
- 没什么好的办法,应该也是在提交的时候作为风格检查
$ git config --list --global | grep sym
$ git config --list --system | grep sym
core.symlinks=false
$ git config --list --local | grep sym
core.symlinks=false
关于链接的另一个办法
CSDN 博客上看到 《windows上使用git仓库的问题(换行符、文件权限、软链接)》,里面提出下面这个思路。
虽然代码不够严谨,但是思路应该是没有问题的。以后遇到问题可以参考(还没有验证):
- 找出链接文件
- 创建 Windows 链接
- 操作索引区,忽略这个变更
import os
def rindex(lst, value):
try:
return lst.rindex(value)
except ValueError:
return -1
# find symbol link files or dirs
fp = os.popen("git ls-files -s | awk '/120000/{print $4}'")
links = fp.read().strip().split("\n")
# get symbol links' parent dir
link_dir = set()
for link in links:
index = rindex(link, "/")
if (index != -1):
link_dir.add(link[:index])
else:
link_dir.add(".")
work_dir = os.getcwd()
# make link for every symbol link
for d in link_dir:
os.chdir("/".join([work_dir,d]))
fp = os.popen("ls -la")
items = fp.read().strip().split("\n")
for item in items:
if "->" in item:
tks = item.split("->")
src = tks[0].strip().split(" ")[-1]
dst = tks[1].strip().split("/")
if (len(dst) > 1):
dst = "\\\\".join(dst)
else:
dst = dst[0]
print ("link " + src + " -> " + dst)
os.popen("rm " + src)
if (os.path.isfile(dst)):
os.popen("cmd /c mklink /H " + src + " " + dst)
else:
os.popen("cmd /c mklink /j " + src + " " + dst)
# make links unchanged
os.popen("git update-index --assume-unchanged " + "/".join([os.getcwd(), src]))
参考资料与拓展阅读
Git
2020-02-24
https://mp.weixin.qq.com/s/67qBDteTmHROeMwOBUeyaw
如何通过 Git 和 Husky 添加提交钩子并实现代码任务自动化
钩子 |
时机 |
用途 |
pre-commit |
提交之前 |
代码检查 |
prepare-commit-msg |
提交信息生成之前 |
生成提交信息 |
commit-msg |
提交信息保存之前 |
检验提交信息 |
post-commit |
提交之后 |
通知,自动测试,CI 等 |
pre-push |
push 之前 |
代码检查,测试,编译打包 |
applypatch-msg |
生成补丁时 |
验证补丁信息 |
fsmonitor-watchman |
文件系统监视器发现变化时 |
触发版本控制操作 |
pre-applypatch |
应用补丁之前 |
验证补丁信息 |
pre-merge-commit |
合并之前 |
检查将要合并的分支是否符合要求 |
pre-rebase |
rebase 操作之前 |
- |
push-to-checkout |
- |
- |
pre-receive |
接受提交之前 |
代码检查,校验权限 |
post-receive |
接受提交之后 |
通知,自动测试,CI 等 |
update |
更新操作之前(分支、Tag) |
提供从旧版本到新版本的改动列表供用户审核 |
post-update |
更新操作之后(分支、Tag) |
通知,自动测试,CI 等 |
示例
pre-receive
#!/usr/bin/env python
"""
每个人都只能提交代码到 username-date-branchName
username 是 git 用户名
date 是 mmdd 日期
branch 是分支描述,支持小写字母、数字、横杠,2 到 16 个字符
"""
import re
import subprocess
import sys
# 获取提交者的用户名
author = subprocess.check_output(['git', 'config', 'user.name']).decode().strip()
# 获取提交的分支名称
branch = subprocess.check_output(['git', 'rev-parse', '--abbrev-ref', 'HEAD']).decode().strip()
# 定义分支名称的正则表达式
branch_pattern = r'^%s-\d{4}-[a-z0-9\-]{2,}$' % (author,)
# 检查分支名称是否符合正则表达式
if not re.match(branch_pattern, branch):
print('Error: Branch name "{}" does not match the required pattern "{}"'.format(branch, branch_pattern), file=sys.stderr)
sys.exit(1)
# 解析日期并检查其是否合法
try:
_, date_str, _ = branch.split('-')
month, day = int(date_str[:2]), int(date_str[2:])
if month < 1 or month > 12 or day < 1 or day > 31:
raise ValueError
except ValueError:
print('Error: Invalid date format in branch name "{}"'.format(branch), file=sys.stderr)
sys.exit(1)
开发工具 Git
2019-08-01
git log --diff-filter=A --follow --format="%h %ad %ce" -1 -- requirements.txt | cat
# 6a0eebf 2019-05-22 19-47-09 bobo@example.com
参考:https://stackoverflow.com/questions/2390199/finding-the-date-time-a-file-was-first-added-to-a-git-repository
Git
2019-01-03
命令
usage: git submodule [--quiet] [--cached]
or: git submodule [--quiet] add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--] <repository> [<path>]
or: git submodule [--quiet] status [--cached] [--recursive] [--] [<path>...]
or: git submodule [--quiet] init [--] [<path>...]
or: git submodule [--quiet] deinit [-f|--force] (--all| [--] <path>...)
or: git submodule [--quiet] update [--init [--filter=<filter-spec>]] [--remote] [-N|--no-fetch] [-f|--force] [--checkout|--merge|--rebase] [--[no-]recommend-shallow] [--reference <repository>] [--recursive] [--[no-]single-branch] [--] [<path>...]
or: git submodule [--quiet] set-branch (--default|--branch <branch>) [--] <path>
or: git submodule [--quiet] set-url [--] <path> <newurl>
or: git submodule [--quiet] summary [--cached|--files] [--summary-limit <n>] [commit] [--] [<path>...]
or: git submodule [--quiet] foreach [--recursive] <command>
or: git submodule [--quiet] sync [--recursive] [--] [<path>...]
or: git submodule [--quiet] absorbgitdirs [--] [<path>...]
相关文件
-
.gitmodules
[submodule "<moduleName>"]
path = <moduleDir>
url = <repoAddr>
-
.git/config 中有相近的 section:
[submodule "<moduleName>"]
active = true
url = <repoAddr>
-
.git
目录在 .git/modules/<moduleName>
克隆
参考:https://stackoverflow.com/questions/3796927/how-to-git-clone-including-submodules
git clone --recurse-submodules -j8 github.com:shouce/shouce.git # 2.13+
git clone --recursive -j8 github.com:shouce/shouce.git # 1.6.5+
-j
表示子模块并发操作,每次 n 个子模块。
针对更老的版本或者以存在的库:
git clone github.com:shouce/shouce.git
cd shouce
git submodule update --init --recursive
发现一个 clone 参数 --[no-]shallow-submodules
,可以使每个子模块仓库的克隆 deepth 为 1,应该是用得上的。
已存在的项目
可能是克隆的时候没有克隆子仓库,也可能是后面添加进来的子仓库。
$ git submodule init
Submodule '<moduleName>' (<repoAddr>) registered for path '<moduleDir>'
$ git submodule update
Cloning into '<moduleFullPath>'...
Submodule path '<moduleDir>': checked out '<commitID>'
或者二合一:
git submodule update --init --recursive
后面有更新就进入子模块 git pull。
添加子模块
git submodule add -b dev --name devtools gitee.com:catroll/devtools tools/dev
# [submodule "devtools"]
# path = tools/dev
# url = gitee.com:catroll/devtools
# branch = dev
删除子模块
$ git submodule deinit <moduleDir>
Cleared directory '<moduleDir>'
Submodule '<moduleName>' (<remoteAddr>) unregistered for path '<moduleDir>'
作用:
- 清空子模块目录下的所有文件
- 去掉 .git/config 子模块配置
这个操作之后:git status
没有任何变化,.gitmodule
还保留着。
然后:
- 修改 .gitmodules
- 删除子模块目录
- 提交变更
- 推送到远程仓库
Git 开发工具
2018-08-01
git diff
对应 diff
命令
git apply
对应 patch
命令
git diff v1.2.1 v1.2.2 > v1.2.1_v1.2.2.patch
git apply --check v1.2.1_v1.2.2.patch
git apply -v --whitespace=warn v1.2.1_v1.2.2.patch
有部分文档中说 git apply
和 patch
在一些细节上实现不一致,需要留意。但我轻量级使用,没有遇到过什么问题。
Git
2017-12-07
CR:Carriage Return 回车
LF:Line Feed 换行
EOL: End Of Line
平台 |
代码 |
数值 |
转义字符 |
Windows |
CRLF |
13 10 |
\r\n |
Linux/Unix |
LF |
10 |
\n |
Mac OS |
CR |
13 |
\r |
Git 相关配置项
core.eol
,换行符,可选:lf,crlf,native(根据系统判断,默认)
core.safecrlf
,是否接受非 LF 换行,可选:true(拒绝),false(允许),warn(警告,默认)
core.autocrlf
,是否自动转换换行符,可选:true(push lf,pull crlf),false(默认),input(push lf)
Linux 上,这三个配置项的默认值就非常恰当了,不用修改。
代码中的换行符应该由开发者自己判断、处理,工具提醒一下就行了。
如果项目组有共识,那么使用一个共同的配置也可以,比如:
git config --global core.eol lf
git config --global core.safecrlf true
git config --global core.autocrlf input
# 如果 CRLF 转换,会有警告提示:
# warning: in the working copy of 'README.md', CRLF will be replaced by LF the next time Git touches it
Git 开发工具
2017-03-15
有时需要临时分享一个仓库给朋友,我们可以用 SSH 协议:
git clone ssh://markjour@192.168.64.234/home/markjour/Projects/Mine/lego
其实 git-daemon 是一个更好的方法。
Git
2016-09-01
$ git push origin v1.1.2 --delete
error: 目标引用规格 v1.1.2 匹配超过一个
error: 无法推送一些引用到 'gitee.com:markjour/markjour'
$ git push origin v1.1.2 --delete
error: dst refspec v1.1.2 matches more than one
error: failed to push some refs to 'gitee.com:markjour/markjour'
解决办法:
# 如果要删除的是分支
git push origin refs/heads/v1.0.32 --delete
To gitee.com:markjour/markjour
- [deleted] v1.0.32
# 如果要删除的是 Tag
git push origin refs/tags/v1.0.32 --delete
Git
2016-01-31
删除远程分支时报错:
git push --delete origin new
error: 无法删除 'new':远程引用不存在
error: 无法推送一些引用到 'gitee.com:markjour/django-admin'
如果是英文环境就是报:
git push --delete origin new
error: unable to delete 'new': remote ref does not exist
error: failed to push some refs to 'gitee.com:markjour/django-admin'
一般是这个分支已经被别人删除了。
Solution
git branch -d -r origin/new