Git
https://cloud.tencent.com/developer/article/1355182
Git在线学习工具:https://learngitbranching.js.org/?NODEMO=&locale=zh_CN
概述
简介
Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.
Git是分布式版本管理系统的一种实现。
缘起
功用
主要用于解决分布式环境下文本文件协同编辑的版本管理问题。可以跟踪文本文件是否改动和改动内容,对二进制文件(如图片、视频等)只能跟踪是否改动
发展
竞品
Mercurial
资料
架构
文件状态变化
untracked
unmodified
modified
staged
工作区 working directory
暂存区 stage area
本地仓库 local repository
远程仓库 remote repository
安装
https://blog.csdn.net/weixin_48077303/article/details/119945896
https://cloud.tencent.com/developer/article/1355182
.git
| 文件或文件夹 | 描述 | 备注 | |
|---|---|---|---|
| hooks | 文件夹 | 钩子 | |
| info | 文件夹 | ||
| logs | 文件夹 | 引用日志 | 该文件夹内容由git维护 |
| objects | 文件夹 | 对象 | 该文件夹内容由git维护 |
| refs | 文件夹 | 引用 | 该文件夹内容由git维护 |
| config | 文本文件 | 本地仓库配置文件 | |
| description | 文本文件 | 仓库描述 | |
| COMMIT_EDITMSG | 文本文件 | 本地仓库最近一次提交的提交信息 | |
| index | 文本文件 | 索引,即暂存区 | |
| HEAD | 文本文件 | 当前引用 | |
| FETCH_HEAD | 文本文件 | ||
| ORIG_HEAD | 文本文件 | ||
| packed-refs | 文本文件 |
hooks
pre-commit:在执行提交操作前运行,可以用于代码检查、格式化等操作,以确保提交的代码符合规范。
pre-receive:在执行推送操作前执行,可以用于进行服务端校验、权限验证等操作,以控制推送到远程仓库的内容。
post-commit:在执行提交操作后运行,可以用于发送通知、执行后续操作等。
post-receive:在执行推送操作后运行,可以用于执行服务器端处理、触发自动部署等操作。
ORIG_HEAD
在 Git 进行一些危险的操作(如 reset、merge 或者 rebase)之前,Git 会将 HEAD 原来所指向的 commit 对象的 SHA-1 值存放于 ORIG_HEAD 文件中。这样做是为了提供一种回退的机制,以防以外操作导致数据丢失或不可逆转的更改。
通过使用 git reset、git merge、git rebase 等命令进行操作后,可以使用 git reset ORIG_HEAD 命令将 HEAD 引用恢复到之前的状态
mac
https://blog.csdn.net/weixin_48077303/article/details/119945896
linux
https://git-scm.com/downloads/linux
命令
配置
git config --system --list
git config --global --list
git config --local --list
# 全局配置(应用级)
git config --global user.name "用户名"
git config --global user.email "用户邮件"
# 本地配置(仓库级)
git config user.name "grassself"
git config user.email "grassself@gmail.com"
git config user.name "dawei"
git config user.email "zhengdawei@l.com"
# git显示八进制不正常显示中文
git config --global core.quotepath false
# 配置代理
git config --global http.proxy "http://127.0.0.1:4780"
# 删除单个配置项
git config --global --unset http.proxy
# 删除一节配置
git config --global --remove-section http
初始化仓库
git init
克隆仓库
git clone [url]
git clone git@github.com:grassself/Blog.git
分支
git branch -a # 查看所有仓库
git branch -r
检出分支
git checkout (branchname)
# 撤销工作区修改(1.修改后未提交至暂存区则会恢复后版本库保持一致,2.修改后提交暂存,随后又修改未提交至暂存区,恢复后与暂存区保持一致)
git cheakout -- <file>
# 强制切换本地分支
git checkout -f newbranch
查看分支状态
git status
查看提交信息
git show --stat
# 通常情况下某一次提交的作者和提交者是同一个人,但若使用rebase二次合并,会使得z提交者不是同一个人
添加文件到暂存区
git add <file>
# 添加所有文件到暂存区
git add -A
撤销文件暂存
将暂存区所有文件撤销暂存
git restore --staged
对于git restore <file>命令,会撤销文件的修改,使文件恢复到暂存区或本地代码库(取决于文件在修改前的状态);
对于git restore --staged <file>命令,把文件从暂存区撤回到工作区,保留文件最后一次修改的内容;
提交文件
git commit
git commit -m "提交信息"
# 提交订正
# 撤销上次提交,并将上次提交内容和本次提交内容合并然后提交
# 适用于漏提交文件或者提交信息写错时订正上次提交
git commit --amend
远程仓库
# 添加远程仓库地址
git remote add origin git@github.com:grassself/Blog.git
git remote add upstream git@github.com:grassself/xxx.git
# 查看远程仓库名称
git remote
# 查看远程仓库链接
git remote --verbose
git remote -v
git remote rm origin
reset
# 回退版本
git reset --hard HEAD^ # 回退至前一个版本
git reset --hard HEAD^^ # 回退至前两个版本
# 以此类推
git reset --hard HEAD~100 #回退至前100个版本
git reset --hard <版本号> #回退至某个版本
–soft
不删除工作空间的改动代码 ,撤销commit,不撤销git add file
–hard
删除工作空间的改动代码,撤销commit且撤销add
推送
# 推送到origin远程仓库与master合并
git push origin master
# 推送本地仓库A1分支到origin远程仓库A2分支
git push origin A1:A2
# 如果A2存在,A1会与A2进行合并
# 如果A2不存在,会自动新建A2分支,但此时远程分支A2并未与本地关联
# 推送到远程分支并与远程分支关联(前提是远程分支存在)
git push --set-upstream origin {本地分支名}:{远程分支名}
git push --set-upstream origin feature_videolist_cascade_zdw
# --set-upstream 可以简写为 -u
# 删除分支
git push origin :<远程分支名> # 推送空分支,等同删除分支
git push origin --delete <远程分支名>
# 强制推送
# git push --force适用于仅单人独立开发分支
# git push --force-with-lease适合多人协作开发分支
# 无条件强制推送,推送后远程分支和本地分支一致
git push --force origin feature
# 若在git push --force之前有第三者向远程分支push代码,git push --force之后该部分代码会丢失,使用git push --force-with-lease可在有此类情况时中止强制推送
git push --force-with-lease origin feature
# github上可以对某些分支进行保护,禁止强制推送或者禁止删除
# 允许合并无关历史
git pull origin {远程分支名} --allow-unrelated-histories
git push --force-with-lease
标签
# 打标签
git tag
# 给当前提交打标签
git tag <name>
git tag -a v1.0 -m "v1.0"
# 注意:标签总是和某个commit挂钩。如果这个commit既出现在master分支,又出现在dev分支,那么在这两个分支上都可以看到这个标签。
git tag -d v1.0
差异对比
git diff <file>
提交日志
git log
git log --pretty=oneline
引用日志
reflog命令会记录本地仓库ref日志,使用reflog可以查找hash,然后使用git checkout 1026b44恢复被git reset --hard hash重置的提交
c566729 (master) HEAD@{1}: reset: moving to HEAD^
1026b44 (HEAD, tag: v1.0) HEAD@{2}: checkout: moving from 1026b44f92f1f1e15cf7d93bd99a47cb2ba4d79a to master
1026b44 (HEAD, tag: v1.0) HEAD@{3}: checkout: moving from master to 1026b44f92f1f1e15cf7d93bd99a47cb2ba4d79a
1026b44 (HEAD, tag: v1.0) HEAD@{4}: checkout: moving from 1026b44f92f1f1e15cf7d93bd99a47cb2ba4d79a to master
1026b44 (HEAD, tag: v1.0) HEAD@{5}: checkout: moving from master to refs/heads/master
1026b44 (HEAD, tag: v1.0) HEAD@{6}: checkout: moving from 1026b44f92f1f1e15cf7d93bd99a47cb2ba4d79a to master
1026b44 (HEAD, tag: v1.0) HEAD@{7}: checkout: moving from master to v1.0
1026b44 (HEAD, tag: v1.0) HEAD@{8}: commit: second commit
c566729 (master) HEAD@{9}: commit (initial): first commit
fetch
# git pull = git fetch + git merge
# fetch
git fetch <远程主机名> <远程分支名>:<本地分支名>
# 例如从远程的origin仓库的master分支下载代码到本地并新建一个temp分支
git fetch origin master:temp
# 如果上述没有冒号,则表示将远程origin仓库的master分支拉取下来到本地当前分支
# 这里git fetch不会进行合并,执行后需要手动执行git merge合并,如下:
merge
git merge temp
pull
git pull <远程主机名> <远程分支名>:<本地分支名>
# 例如将远程主机origin的master分支拉取过来,与本地的branchtest分支合并,命令如下:
git pull origin master:branchtest
#同样如果上述没有冒号,则表示将远程origin仓库的master分支拉取下来与本地当前分支合并
归档
git archive
# 查看支持的归档格式
git archive --list
# 导出新的版本库
git archive -o ./xxx.zip HEAD
git archive -o ../git-1.4.0.tar 8996b47
# 直接从仓库中提取文件
# 在某个web服务中使用git某仓库中的prod_config.json文件,基于git archive可以获取该文件
git archive --remote=git@github.com:common/config_project master prod_config.json|tar -x
gc
Git会周期性运行垃圾回收,将引用压缩至refs/packed-refs文件,可以执行git gc手动压缩。
git gc
refs/packed-refs
# pack-refs with: peeled fully-peeled sorted
1026b44f92f1f1e15cf7d93bd99a47cb2ba4d79a refs/heads/master
1026b44f92f1f1e15cf7d93bd99a47cb2ba4d79a refs/tags/v1.0
clean
git clean用于从工作目录中删除所有没有track过的文件,如清理编译出来的.exe、.o文件
经常与reset配合使用,用于将工作目录完全还原到某一个commit的状态,因为reset只能操作tracked过的文件
# clean演习,显示哪些文件将被清理,不会真正清理
git clean -n
# 清除目录下没有track的文件,不包含.gitignore中指定的文件和文件夹,无论其是否被track
# 不指定目录则默认为当前文件夹
git clean -f [<path>]
# 清理未被track的文件夹
git clean -d
# 清理未被track的文件和文件夹,且忽略.gitignore的作用,无论其是否被track
git clean -fdx
rev-parse
git-rev-parse - Pick out and massage parameters
massage,v,按摩;粉饰
# 显示仓库.git目录位置
git rev-parse --git-dir
# 显示仓库顶层目录,绝对路径
git rev-parse --show-toplevel
# 显示当前位置相对顶层目录的路径前缀,即当前目录相对路径
git rev-parse --show-prefix
# 显示当前目录如何退出到仓库顶层目录
git rev-parse --show-cdup
# 显示HEAD提交的SHA1值
git rev-parse HEAD
git rev-parse master
git rev-parse tag_v1.0
# 打开帮助文档
git rev-parse --help
场景
多人协作开发
git push <仓库名> <分支名>
# 推送失败,说明远程分支比本地分支更新早,需要合并更新
git pull
# 或者使用git fetch获取远程分支,使用git merge进行合并
# 如果合并有冲突,需要解决冲突(指对同一个文件进行了修改?)
# 解决完冲突之后再进行提交
git commit
# 最后进行推送
git push git push <仓库名> <分支名>
本次仓库与远程仓库同步
四种情况
1.本地增加分支同步到远程仓库
2.远程增加分支同步到本地仓库
3.本地删除分支同步到远程仓库
4.远程删除分支同步到本地仓库
# 1.本地增加分支同步到远程仓库
git push origin master
git push origin master:master # 远程分支不存在会创建新的分支
# 2.远程增加分支同步到本地仓库
git fetch #获取远程更新
git branch -a #查看远程分支(记录在本地,需要使用git fetch获取最新信息)
git branch #查看本地分支
git checkout [分支名] # 切换分支
# 3.本地删除分支同步到远程仓库
git push origin -d [分支名] # 删除远程分支
git branch -d [分支名] # 删除本地分支
# 4.远程删除分支同步到本地仓库
git remote show [origin] # 查看远程分支和本地分支的对应关系
git remote prune [origin] # 删除远程已经删除过的分支
关于git文件莫名被修改的一种情况
git diff xxx.py # 比较暂存区和修改后的差别
old mode 100644
new mode 100755
是filemode发生了变化,比如使用chmod命令,可以在本地仓库配置忽略filemode变化
git config --add core.filemode false
git reset –hard与git clean配合回退最近一次提交
# 清理提交的内容
git reset --hard
# 清理未追踪的内容
git clean -df
基于rebase合并多次提交为一次提交
rebase合并多个提交
假设master分支
f4f3bb4 (HEAD -> master) feat: feature_xxx_5
9b42c0d feat: feature_xxx_4
0761f94 feat: feature_xxx_3
aa6e50c feat: feature_xxx_2
25a10f9 feat: feature_xxx_1
而接下来要开发feature_xxx_6,新建分支feature_xxx_6并且后续经过三个阶段的开发完成该功能
2ad6136 (HEAD -> feature_xxx_6) feat: feature_xxx_6 finished
3ee55b7 feat: feature_xxx_6 developing
13612c7 feat: feature_xxx_6 start
f4f3bb4 (master) feat: feature_xxx_5
9b42c0d feat: feature_xxx_4
0761f94 feat: feature_xxx_3
aa6e50c feat: feature_xxx_2
25a10f9 feat: feature_xxx_1
此时希望将feature_xxx_6的三个提交合并为一个,即将f4f3bb4后的所有提交合并以f4f3bb4为base
git rebase -i f4f3bb4
根据说明将pick都替换为squash(注意此时数据是从老到新)
pick 13612c7 feat: feature_xxx_6 start
pick 3ee55b7 feat: feature_xxx_6 developing
pick 2ad6136 feat: feature_xxx_6 finished
# Rebase f4f3bb4..2ad6136 onto f4f3bb4 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified); use -c <commit> to reword the commit message
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
skip 13612c7 feat: feature_xxx_6 start
s 3ee55b7 feat: feature_xxx_6 developing
s 2ad6136 feat: feature_xxx_6 finished
# This is a combination of 3 commits.
# This is the 1st commit message:
feat: feature_xxx_6 start
# This is the commit message #2:
feat: feature_xxx_6 developing
# This is the commit message #3:
feat: feature_xxx_6 finished
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Thu Jan 19 14:24:03 2023 +0800
#
# interactive rebase in progress; onto f4f3bb4
# Last commands done (3 commands done):
# squash 3ee55b7 feat: feature_xxx_6 developing
# squash 2ad6136 feat: feature_xxx_6 finished
# No commands remaining.
# You are currently rebasing branch 'feature_xxx_6' on 'f4f3bb4'.
#
# Changes to be committed:
# new file: 6.txt
#
更改提交信息
feat: feature_xxx_6
40b4d37 (HEAD -> feature_xxx_6) feat: feature_xxx_6
f4f3bb4 (master) feat: feature_xxx_5
9b42c0d feat: feature_xxx_4
0761f94 feat: feature_xxx_3
aa6e50c feat: feature_xxx_2
25a10f9 feat: feature_xxx_1
注意git log –oneline显示的提交信息也只能显示一行
git rebase –autosquash
自动rebase要求commit使用
git commit --fixup=<commit_sha>
3dd62fb (HEAD -> feature_xxx_6) fixup! fixup! fixup! feat: feature_xxx_6
b63e632 fixup! fixup! feat: feature_xxx_6
0eed56e fixup! feat: feature_xxx_6
c3b5d3e feat: feature_xxx_6
f4f3bb4 (master) feat: feature_xxx_5
9b42c0d feat: feature_xxx_4
0761f94 feat: feature_xxx_3
aa6e50c feat: feature_xxx_2
25a10f9 feat: feature_xxx_1
git rebase --autosquash -i f4f3bb4是新功能
# 注意这里是f4f3bb4是新功能提交c3b5d3e的前一个
# 这样在交互文本中会自动生成commit message
在分支feature_x开发中途需要新建分支feature_y解决另外一个问题
clone新仓库并在新仓库中开发feature_y分支
在多个工作区中工作,会额外占用一部分磁盘空间
使用stash暂存
在feature_x分支上使用
git stash暂存当前修改,新建feature_y并解决问题后切换回feature_x,执行git stash pop恢复修改继续开发。适用于feature_y改动简单的情况。直接将当前修改内容提交
在分支feature_x中将当前修改提交,新建feature_y并解决问题后切换回feature_x,继续开发。或者,在feature_x分支上使用
git add -u添加修改和删除的文件并提交,新建feature_y并解决问题后切换回feature_x,先使用git reset HEAD~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 }'
# 查看某个作者的代码量
git log --author="dawei" --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 }'
# 统计每个人的增删行数
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
# 提交数统计
git log --oneline | wc -l
Error
git删除分支提示 The branch ‘xxx’ is not fully merged
原因:本地分支添加新代码后提交到本地仓库,此时删除分支,新代码只在当前的本地分支,删除分支会导致当前新代码的丢失,git branch -d不允许此类删除,使用git branch -D强制删除分支
git diff old mode 100644 new mode 100755
有时git status发现文件发生改变但是git add执行完毕后依然发现文件修改,git diff发现mode发生改变,是由于chmod或其他原因导致该文件权限发生变化但实质内容没变,git add对此类改动无能为力,添加配置忽略此类改动
git config --add core.filemode false # 忽略filemode改动
规范
git commit message规范
https://www.conventionalcommits.org/en/v1.0.0/
<type>[optional scope]: <description> [optional body] [optional footer(s)]Angular规范
type:用于说明commit的类别,规定为如下几种
feat:新增功能
fix:修复bug
docs:修改文档
refactor:代码重构,未新增任何功能和修复任何bug
build:改变构建流程,新增依赖库、工具等(例如webpack修改)
style:仅仅修改了空格、缩进等,不改变代码逻辑
perf:改善性能和体现的修改
chore:非src和test的修改
test:测试用例的修改
ci:自动化流程配置修改
revert:回滚到上一个版本;
分支命名规范
分支: 命名: 说明:
主分支 master 主分支,所有提供给用户使用的正式版本,都在这个主分支上发布
开发分支 dev 开发分支,永远是功能最新最全的分支
功能分支 feature-* 新功能分支,某个功能点正在开发阶段
发布版本 release-* 发布定期要上线的功能
修复分支 bug-* 修复线上代码的 bug
引用
ref,引用
解释HEAD、tag、branch时都是解析最新的一次commit hash
git show HEAD/branch/tag/hash
引用是一种间接使用commit hash的方式,其以文本文件的形式保存在.git/refs路径下,heads中为本地分支,remotes中为远程分支,tags中为标签,每个refs文件内容即为分支或标签的最新commit hash,创建新分支就是创建新文件并将hash写入,提交就是更新文件中的hash,删除分支就是删除对应hash文件
.git/refs/
heads/
master
feature_xxx
remotes/
origin/
master
tags/
v1.0
checkout本地分支master
git checkout refs/heads/master
branch和tag的引用支持简写
git checkout master同样会生效
若branch和tag同名会?
除了引用目录之外,还有一些特别的引用存在于*.git*路径的顶部:
- HEAD – 当前检出的 commit/branch.
- FETCH_HEAD – 最新从远程仓库获取的分支,git fetch。
- ORIG_HEAD – 作为备份指向危险操作前的HEAD。
- MERGE_HEAD – 使用
git merge命令合并进当前分支的提交。 - CHERRY_PICK_HEAD – 使用
git cherry-pick命令的提交。
HEAD文件中会保存引用或者hash,git checkout master时HEAD内容为ref: refs/heads/master,git checkout 1026b44f92f1f1e15cf7d93bd99a47cb2ba4d79a时HEAD内容为1026b44f92f1f1e15cf7d93bd99a47cb2ba4d79a。
HEAD等特殊引用也可以用于git命令,如git reset HEAD
# 查看本地分支与远程分支的对应关系
git branch -vv
# master 487c780 [origin/master] first commit
本地分支、本地远程分支、远程分支
本地远程分支是本地记录的远程分支副本,当本地分支向远程分支推送后,本地分支、本地远程分支、远程分支三者ref相同,本地仓库在pull和push时会更新本地远程分支,所以本地远程分支不一定和远程分支ref一致
git branch -av
git checkout origin/master
# 会切换到游离的一次提交,并不能通过修改本地远程分支从而修改远程分支
Refspecs
引用规范,
refspec被表示为[+]<src>:<dst>。
git push origin +main:main 将本地的 main 分支强制推送到远程仓库的 main 分支,即使这可能导致非快进式更新从而覆盖部分代码
删除远程分支
git push origin :some-feature
git push origin --delete some-feature
.git/config中定制相关行为
通常,git fetch时会获取所有分支
[remote "origin"]
url = https://github.com/xxx/blog.git
fetch = +refs/heads/*:refs/remotes/origin/*
在一些工作流中,并不需要把他们都下载下来。例如,许多持续集成的工作流只关注主分支。为了只获取主分支,可将fetch行修改为
[remote "origin"]
url = https://github.com/xxx/blog.git
fetch = +refs/heads/master:refs/remotes/origin/master
同理branch也可以定制,fetch、merge、push
[branch "master"]
remote = origin
merge = refs/heads/master
别名
git alias
https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases
git config --global alias.ll "log --oneline"
git config --global alias.cm "commit -m"
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
git config --global alias.aa "add ."
git config --global -l
三方别名
git fixup
https://ttys3.dev/post/git-fixup-amend-for-any-older-commits-quickly/
https://words.filippo.io/git-fixup-amending-an-older-commit/
alias.ll=log --oneline
alias.lg=log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
alias.cm=commit -m
alias.aa=add --all
子模块,sub module
将某一个项目作为本项目的子模块,可以将本项目和子模块版本管理分离
- 项目依赖并且要跟踪一个三方项目,可以将三方项目设置为本项目的子模块
- 将本项目中部分内容抽离供多个项目使用,且抽离的部分仍然频繁更新,可以将这部分单独建立项目,并在本项目中设置抽出的项目为子模块
添加子模块
git submodule add url
命令会在.gitmodules文件中添加子模块信息并将子模块clone到主项目仓库下,此时通常会手动提交一次git commit -m "add submodule xxx"表示引入某个子模块,子模块版本单独管理(即切换到子模块目录可单独对子模块进行提交等操作),主项目提交时不会提交子模块内容,仅会将子模块作为空文件夹提交至主项目
获取子模块
添加子模块会自动将子模块内容clone至主项目,但在主项目clone时默认不会clone子模块
# 1.递归克隆项目,会colne子模块
git clone url --recure-submodules
# 2.初始化并更新子模块
git submodule init
git submodule update
更新子模块
对于子模块而言,子模块本身是一个单独的项目,遵循一般项目的更新即可
对于主项目而言,主项目中子模块更新,有三种情况
主项目子模块文件夹中内容发生变化但未提交,即内容变化但版本并未变化
通常是在本地开发主项目时改动了子模块文件夹中内容,在主项目中使用
git status可观察到子模块发生变化但无法在主项目中使用git commit对子模块变化内容进行提交,需要切换目录到子模块,在子模块中使用git commit等单独进行版本管理,提交后即转化为情况2主项目子模块文件夹中内容发生变化且提交,即内容变化且版本发生变化
在主项目中使用
git status可观察到子项目版本变化,可以在子项目中提交子模块文件夹以更新主项目对子模块版本的记录主项目子模块文件夹中内容未发生变化但子模块远程仓库版本发生变化,即本地无变化但远程版本变化
git submodule update会根据主项目中记录的子模块版本将子模块内容更新,但对于子模块远程版本的变化无能为力,需要手动对子模块进行pull# 切换到某个子模块文件夹中并执行 cd sub-project git pull origin master # 或者当主项目中子模块较多时,在主项目中执行 git submodule foreach 'git pull origin master'
删除子模块
git submodule deinit
https://zhuanlan.zhihu.com/p/87053283
subtree
与submodule对比
工作树
工作树使得可以同时在多个工作区的多个不同分支下工作
- 工作区中的提交会保存到本地仓库,删除工作区不会删除已提交的内容
- 工作区中可以任意切换分支,但某一仓库的若干工作区不能同时有两个或以上工作区检出同一分支,即要求同意本地仓库不同工作区检出分支不同
- 使用
git rev-parse --git-common-dir和git rev-parse --show-toplevel确认不同工作区上下文
Git会同时跟踪多个工作树,所有工作树统一使用仓库的钩子
初始化仓库时便会有初始工作树
git init
git worktree list
# E:/project-demo 0000000 [master]
echo xxx > xxx.txt
git add -A
git commit -m "add xxx.txt"
# [master (root-commit) 375117f] add xxx.txt
# 1 file changed, 0 insertions(+), 0 deletions(-)
# create mode 100644 xxx.txt
git worktree list
# E:/project-demo 375117f [master]
git checkout -b feature_x
# Switched to a new branch 'feature_x'
git worktree list
# E:/project-demo 375117f [feature_x]
向工作树添加工作区
# git worktree add 自定义工作区路径(没有会自动创建) 分支名(会检出该分支)
git worktree add ../worktree/project-demo/feature_y master
# Preparing worktree (checking out 'master')
# HEAD is now at 375117f add xxx.txt
git worktree list
# E:/project-demo 375117f [feature_x]
# E:/worktree/project-demo/feature_y 375117f [master]
添加的工作区路径下会有.git文件和工作区当前检出分支的内容,不会有其他分支,即是一个仓库外工作区
工作区.git文件内容形如:
gitdir: E:/project-demo/.git/worktrees/feature_y
切换到某个工作区目录下
cd ../worktree/project-demo/feature_y
git status
# On branch master
# nothing to commit, working tree clean
git checkout -b feature_y
# Switched to a new branch 'feature_y'
从工作树中删除某个工作区
# 通常会使用git worktree remove删除工作树,删除工作树不会删除在工作树中提交的分支,已提交的改动保留在本地仓库而非工作区
git worktree remove ../worktree/project-demo/feature_y
git worktree list
# E:/project-demo 375117f [feature_x]
# 也可以先使用rm -rf删除工作区,然后使用git worktree prune清理其余文件或gc清理其余文件
钩子
https://zhuanlan.zhihu.com/p/521707440
object
https://muzing.top/posts/de22d5a5/#git%E7%9A%84%E4%B8%89%E4%B8%AA%E5%88%86%E5%8C%BA
Git 凭据 .git-credentials
# 设置 credential.helper
git config --global credential.helper store
# 更改 credential.helper
git config --global credential.helper new_helper
# 删除 credential.helper
git config --global --unset credential.helper
需要身份认证时,store类型的credential.helper会首先尝试从~/.git-credentials获取凭证,若没有则控制台以交互形式提示输入凭证信息,随后会存入~/.git-credentials,若有则使用该凭证。
.git-credentials样例:
http://account:password@repo.yuzaoyah.com
由于.git-credentials 文件包含敏感信息,不应当添加到版本控制系统中,应当添加到.gitignore,若需要更加安全的凭证存储方式,可以考虑cache(默认方式,在内存中缓存你的凭据一段时间)等。
.gitkeep
Git 不会追踪空文件夹,在一些场景下(如项目脚手架)需要有空目录保证项目结构完整。社区约定,在空文件夹下放置一个名为.gitkeep的空文本文件,使得 Git 中有该文件夹相关记录又表示仅是保持该文件夹结构。
.gitignore
https://github.com/github/gitignore
https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
https://github.com/github/gitignore/blob/main/Global/Windows.gitignore
https://github.com/github/gitignore/blob/main/Global/macOS.gitignore
https://github.com/github/gitignore/blob/main/Python.gitignore
https://github.com/github/gitignore/blob/main/Java.gitignore
https://github.com/github/gitignore/blob/main/Go.gitignore
GitHub
GitHub配置SSH
https://blog.csdn.net/weixin_42310154/article/details/118340458
GitHub用户信息
https://api.github.com/users/grassself
GitLab
Gitlab权限管理
Gitlab用户在组中有五种权限:Guest、Reporter、Developer、Master、Owner
Guest:可以创建issue、发表评论,不能读写版本库
Reporter:可以克隆代码,不能提交,QA、PM可以赋予这个权限
Developer:可以克隆代码、开发、提交、push,RD可以赋予这个权限
Master:可以创建项目、添加tag、保护分支、添加项目成员、编辑项目,核心RD负责人可以赋予这个权限
Owner:可以设置项目访问权限 - Visibility Level、删除项目、迁移项目、管理组成员,开发组leader可以赋予这个权限
Gitlab中的组和项目有三种访问权限:Private、Internal、Public
Private:只有组成员才能看到
Internal:只要登录的用户就能看到
Public:所有人都能看到
开源项目和组设置的是Internal
sudo yum install -y curl policycoreutils-python openssh-server perl
sudo systemctl enable sshd
sudo systemctl start sshd
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo systemctl reload firewalld
sudo yum install postfix
sudo systemctl enable postfix
sudo systemctl start postfix
curl -fsSL https://packages.gitlab.cn/repository/raw/scripts/setup.sh | /bin/bash
sudo EXTERNAL_URL="http://192.168.1.111" yum install -y gitlab-jh
gitlab 常用命令
#查看服务状态
gitlab-ctl status
使用控制台实时查看日志
# 查看所有的logs; 按 Ctrl-C 退出
gitlab-ctl tail
# 拉取/var/log/gitlab下子目录的日志
gitlab-ctl tail gitlab-rails
# 拉取某个指定的日志文件
gitlab-ctl tail nginx/gitlab_error.log
#启动关闭gitlab
gitlab-ctl start
gitlab-ctl stop #停止
gitlab-ctl status #查看状态
gitlab-ctl restart #重启
gitlab-ctl reconfigure #更新配置文件
gitlab-ctl help #帮助
gitlab-rake gitlab:check SANITIZE=true --trace 检查gitlab
#gitlab 默认的日志文件存放在/var/log/gitlab 目录下
gitlab-ctl tail #查看所有日志
#禁止 Gitlab 开机自启动
systemctl disable gitlab-runsvdir.service
#启用 Gitlab 开机自启动
systemctl enable gitlab-runsvdir.service
修改密码
进入gitlab控制台
gitlab-rails console
查询超级管理员用户并修改密码
user = User.where(id:1).first
user.password='eKLFk1AgNWi2Wi8'
user.save!
git提交记录支持富文本
gitlab 手动备份
创建备份文件
使用一条命令即可创建完整的Gitlab备份。
gitlab-rake gitlab:backup:create
使用命令会在/var/opt/gitlab/backups目录下创建一个压缩包,这个压缩包就是Gitlab整个的完整部分。
备份相关配置
也可以通过/etc/gitlab/gitlab.rb配置文件来修改默认存放备份文件的目录
修改为你想存放备份的目录即可
gitlab_rails['backup_path'] = "/home/gitlab-backup"
#指定备份后数据存放的路径、权限、时间配置
gitlab_rails['manage_backup_path'] = true 开启备份功能
gitlab_rails['backup_path'] = "/home/gitlab-backup" 指定备份的路径
gitlab_rails['backup_archive_permissions'] = 0644 备份文件的权限
gitlab_rails['backup_keep_time'] = 7776000 备份保留时间
修改完成之后使用下面命令重载配置文件即可.
gitlab-ctl reconfigure
自动备份 crontab
#输入命令crontab -e
crontab -e
#输入相应的任务
0 2 * * * /opt/gitlab/bin/gitlab-rake gitlab:backup:create CRON=1
注意:环境变量CRON=1的作用是如果没有任何错误发生时, 抑制备份脚本的所有进度输出
#查看周期性计划任务
crontab -l