2025-03-29 14:35:49 +08:00

942 lines
22 KiB
Markdown
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Git 常用命令
## git配置
```bash
# 显示当前的Git配置
git config --list
# 显示全局配置
git config --list --global
# 编辑Git配置文件
git config -e [--global]
# 设置提交代码时的用户信息, 加global为全局不加为当前项目
git config [--global] user.name "[name]"
git config [--global] user.email "[email address]"
# (可选)设置代理 账号验证和上传可能会有问题
git config --global url."https://ghproxy.com/https://github.com/".insteadOf "https://github.com/"
git config --global protocol.https.allow always
# 查看
cat ~/.gitconfig # 找到insteadOf
# 取消
git config --global --unset url.https://github.com/.insteadof
```
### 推荐配置
```sh
#
git config --global core.pager ''
git config --global merge.ff false
git config --global pull.rebase true
# win系统
git config --global core.autocrlf false // true: 检出时转成crlf, 提交时转成lf
git config --global core.eol lf
# mac linu unix 系统
git config --global core.autocrlf input // 提交时把 CRLF 转换成 LF签出时不转换
git config --global core.safecrlf true // 不允许混用
```
### 生成ssh密钥
除了使用账号密码,还可以用`ssh密钥`进行上传下载
`jihulab`为例:
1. ssh密钥存放路径 macos: `~/.ssh/`
2. 生成:
```bash
# 添加-f参数是为了指定名称方便区分不同的服务商
ssh-keygen -t ed25519 -C 'jqtmviyu@gmail.com' -f ~/.ssh/jihulab_ed25519
# 生成id_ed25519和id_ed25519.pub文件
# 使用 ed25519 算法而不是rsa算法, 是因为rsa算法在新版本的OpenSSH被默认移除
# -C 只是备注信息
```
3. 配置
```bash
vim ~/.ssh/config
# 添加以下配置
====
# jihulab
Host jihulab.com
HostName jihulab.com
User jqtmviyu@gmail.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/jihulab_ed25519
StrictHostKeyChecking=no
====
```
```bash
# 把.pub公钥复制到后台管理页面上
```
4. 测试连接
```bash
ssh -T git@jihulab.com
```
#### 错误解决
* 遇到报错, 权限过高, 忽略私钥
```sh
chmod -R 0722 ~/.ssh
cd ~/.ssh
chmod 0700 私钥
chmod 0722 公钥
# 测试是否连通
ssh -T github.com
```
* `StrictHostKeyChecking=no`
* github具有指纹是否继续(是/否)
```sh
# 将远程服务器添加到您信任的主机列表中
ssh-keyscan github.com >> ~/.ssh/known_hosts
```
### Git中全局忽略.DS_Store文件
```sh
vim ~/.gitconfig
====
[core]
excludesfile = ~/.gitignore_global
====
vim ~/.gitignore_global
====
.DS_Store
**/.DS_Store
.DS_Store?
====
```
## 新建仓库
### 创建一个新仓库
```sh
git clone <url>
cd <文件夹>
git checkout -b main
touch README.md
git add README.md
git commit -m "add README"
git push -u origin main
```
* `git switch`和 `git restore`: 2.23新增的两个命令, 用来替代原来承担太多功能的`git checkout`, `switch`对应分支的操作,`restore`对应更改文件的操作
* `git checkout -b ` ==> `git switch -c`, `-c`是 --create
* `git checkout <分支名>` ==> `git switch <分支名>`
### 推送已有的仓库
```sh
cd <existing_folder>
git init
git remote add origin <url>
git add .
git commit -m "Initial commit"
git push -u origin main
```
* 设置 init 时的分支名为 `main`(原来是master)
```sh
vim ~/.gitconfig
===
[init]
defaultBranch = main
===
```
### 推送现有的 Git 仓库
```sh
cd <existing_repo>
git remote rename origin old-origin
git remote add origin <url>
git push -u origin --all
git push -u origin --tags
```
### 初始化
```bash
# 在当前目录新建一个Git代码库
git init
# 新建一个目录将其初始化为Git代码库
git init <project-name>
```
### 下载
```sh
# 下载一个项目和它的整个代码历史
git clone <url>
# 下载指定分支
git clone -b <branchName> <url>
# 只克隆一次提交,避免项目历史记录过大
git clone <url> --depth=1
# 如果后续需要扩展
git fetch --depth=5
```
## 三个区域
==Git 可以被分为三个主要区域: 工作目录 - 暂存区 - 仓库==
工作目录是你在本地项目中看到的实际文件和目录
暂存区是一个中间区域,它保存你即将提交到 Git 仓库的更改
Git 仓库是一个隐藏的目录(通常是 `.git`),它包含了项目的所有版本历史记录
```sh
工作目录 (Working Directory)
|
| git add
v
暂存区 (Staging Area)
|
| git commit
v
Git 仓库 (Repository)
```
### 工作目录
```sh
# 查看工作目录中哪些文件有更改
git status
# 查看工作目录中的具体更改内容
git diff
```
### 暂存区
```bash
# 添加指定文件到暂存区
git add <file1> [file2...]
# 添加指定目录到暂存区,包括子目录
git add <dir>
# 添加当前目录的所有文件到暂存区
git add .
# 添加每个变化前,都会要求确认
# 对于同一个文件的多处变化,可以实现分次提交
git add -p
# 从暂存区中移除文件的更改(不删除工作目录中的更改)
git reset <file>
# 查看暂存区中的具体更改内容
git diff --cached
```
### git仓库
```sh
# 将暂存区中的更改提交到仓库
git commit -m "message"
# 查看仓库中的提交历史记录
git log
# 查看特定提交的详细信息
git show <commit>
# 删除,并且将这次删除放入暂存区
git rm <file1> [file2...]
# 删除文件但保留工作目录中的文件
git rm --cached <file>
# 改名文件,并且将这个改名放入暂存区
git mv <file-original> <file-renamed>
```
#### git仓库的原理
git仓库使用了一种称为对象数据库的方式, 主要由四种对象组成:
1. **Blob 对象**Binary Large Object
2. **Tree 对象**
3. **Commit 对象**
4. **Tag 对象**
##### 1. Blob 对象
Blob 对象存储文件的内容,但不存储文件名和文件的元数据(如权限)。每个文件的内容都通过 SHA-1 哈希生成一个唯一的标识,这个标识就是 Blob 对象的 ID。
示例:一个名为 `hello.txt` 文件,内容为 "Hello, Git!"。其 Blob ID 可能是:
```
83baae61804e65cc73a7201a7252750c76066a30
```
每当文件被修改并再次添加到 Git 仓库时Git 会为修改后的文件内容创建一个新的 Blob 对象,而不会修改原有的 Blob 对象。每个 Blob 对象都是文件内容的快照,以文件内容的 SHA-1 哈希值为唯一标识符
git使用 zlib 压缩, 在打包过程中Git 会计算初始内容和修改内容之间的差异, 增量存储
Git 会在适当的时候自动进行垃圾回收和优化存储, 如果你删除了大量分支或文件,并希望立即释放磁盘空间,可以运行`git gc`
```sh
du -sh .git
git gc
du -sh .git
```
##### 2. Tree 对象
Tree 对象存储目录结构和文件名。一个 Tree 对象包含多个条目,每个条目指向一个 Blob 对象或另一个 Tree 对象用于子目录。Tree 对象还存储文件的元数据,如权限。
示例:一个包含 `hello.txt` 文件的目录,可能的 Tree 对象结构:
```
100644 blob 83baae61804e65cc73a7201a7252750c76066a30 hello.txt
```
##### 3. Commit 对象
Commit 对象存储每次提交的元数据,包括提交信息、提交时间、作者信息以及指向树对象的指针。每个提交对象还包含指向父提交的指针(除非它是第一次提交)。
示例:一个提交对象,可能的结构:
```
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
parent 83baae61804e65cc73a7201a7252750c76066a30
author John Doe <john.doe@example.com> 1623078749 -0500
committer John Doe <john.doe@example.com> 1623078749 -0500
Initial commit
```
##### 4. Tag 对象
Tag 对象用于为特定的提交打标签,它存储了标签的名字、创建标签的时间、创建标签的人的信息等。
##### Git 的存储过程
1. **生成 Blob 对象**:每个文件的内容都会生成一个 Blob 对象,并存储在 Git 仓库中。
2. **生成 Tree 对象**:每个目录结构都会生成一个 Tree 对象,并存储在 Git 仓库中。
3. **生成 Commit 对象**:每次提交都会生成一个 Commit 对象,指向相应的 Tree 对象,并包含提交信息。
##### 查看对象
```sh
# 查看提交对象
git log
# 查看树对象
git cat-file -p <commit-hash>
# 查看 Blob 对象
git cat-file -p <blob-hash>
```
## 提交
### 代码提交
```bash
# 提交暂存区到仓库区
git commit -m <message>
# 提交暂存区的指定文件到仓库区
git commit [file1] [file2...] -m <message>
# 提交工作区自上次commit之后的变化直接到仓库区
git commit -a
# 提交时显示所有diff信息
git commit -v
```
### 修改提交信息
```sh
# 使用一次新的commit替代上一次提交
# 如果代码没有任何新变化则用来改写上一次commit的提交信息
git commit --amend
# 或者
git commit --amend -m <message>
# 重做上一次commit并包括指定文件的新变化
git commit --amend [file1] [file2...]
```
### 多个提交作者
```sh
# 第一行"不要闭合,回车换行
# 然后回车,两个空行
git commit -m "提交信息
>
>
Co-authored-by: NAME <NAME@email.com>
Co-authored-by: AUTHOR-NAME <another-name@email.com>" # 回车结束
```
## 分支
### 列出分支
```bash
# 列出所有本地分支
git branch
# 列出所有远程分支
git branch -r
# 列出所有本地分支和远程分支
git branch -a
# 查看本地分支和哪个远程分支对应
git branch -vv
```
### 新建分支
```sh
# 新建一个分支,但依然停留在当前分支
git branch <branch-name>
# 新建一个分支,并切换到该分支
git checkout -b <branch-name>
# 示例
# git checkout -b dev origin/dev # 新建分支dev并切换到该分支, 链接到远程dev分支
# 新建一个分支指向指定commit
git branch <branch-name> <commit>
# 新建一个分支,与指定的远程分支建立追踪关系
git branch --track <branch> <remote-branch>
```
### 切换分支
```sh
# 切换到指定分支,并更新工作区
git checkout <branch-name>
# 切换到上一个分支
git checkout -
```
### 改变指向
```sh
# 让分支指向另一个提交
git branch main HEAD~3 # 让main分支指向head的前第3个提交
git branch -f main HEAD~3 # -f表示强制
# 或者指向commit id
git branch <commit id>
```
### 追踪远程分支
```sh
# 建立追踪关系,在现有分支与指定的远程分支之间
git branch -u <remote-branch> <local-branch-name>
# 示例
# git branch -u origin/master local-branch
# -u是 --set-upstream的简写
# 这样 local-branch 就会跟踪 origin/master 了。如果当前就在 local-branch 分支上, 还可以省略 local-branch
# git branch -u origin/master
```
### 合并分支
```sh
# 合并指定分支到当前分支
# 合并前必须保证当前分支和远程仓库一样是最新的, 先fetch, pull, 再merge
git merge <branch-name> # 不推荐
git merge --no-ff <branch-name> # 推荐, 不使用快速合并, 提交历史更加清晰, 不容易出错,可以全局设置
# git 分支合并到主分支时,去掉分支的冗余提交。即,将分支的多次提交一次性合并到主分支上。
git checkout master # 切换到主分支
git merge --squash dev # 一次性合并分支的多次提交
git commit -m 'xxx' # 将刚合并的提交提交到主分支master
# 拷贝一/多个commit合并进当前分支, 比如把dev的c2和c4拷贝为c2', c4', 加到到main分支后面
# 合并时找到他们最近的公共节点进行比较
git cherry-pick <commit1> [commit2...]
```
### 删除分支
```sh
# 删除分支
git branch -d <branch-name>
# 删除远程分支
git push origin --delete <branch-name>
# 或者
git branch -dr <remote/branch>
# 清理本地仓库中已经不存在于远程仓库的远程分支引用
git remote prune origin
```
### checkout的其他用法
```sh
# 从指定的提交中恢复某个文件
git checkout <commit-hash> -- <file-path>
# git checkout abc123 -- a.txt
# 丢弃工作目录中的更改
git checkout -- <file-path>
# git checkout -- a.txt
```
## 标签
### 查看标签
```bash
# 列出所有tag
git tag
# 查看tag信息
git show <tagName>
#列出符合条件的tag筛选作用
git tag -l v1.*
#查询远程tags的命令如下
git ls-remote --tags origin
```
### 新建标签
```sh
# 新建一个tag在当前commit轻量tag无-m标注信息
git tag <tagName>
# 详细编辑提交内容
git tag <tagName> -a
# 新建一个tag在指定commit
git tag <tagName> [commit]
```
### 删除标签
```sh
# 删除本地tag
git tag -d <tagName>
# 删除远程tag
git push origin :refs/tags/<tagName>
# 或者
git push origin --delete <tagName>
```
### 提交标签
```sh
# 提交指定tag
git push <remote> <tagName>
# 提交所有tag
git push <remote> --tags
```
### 从标签新建分支
```sh
# 新建一个分支指向某个tag
git checkout -b <branchName> <tagName>
```
### 拉取标签
```sh
# 拉取分支上现有的tags
git fetch --tags
# 拉取远程指定tag
git fetch origin [远程tag名]
```
## 信息
### 文件状态
```sh
# 显示有变更的文件
git status
# 显示指定文件是什么人在什么时间修改过
git blame <file>
```
### 提交历史
```bash
# 显示当前分支的版本历史
git log
# 显示当前分支的最近几次提交和回退
git reflog
# 就算是被硬重置了也能看到已丢失的记录
# 只显示提交
git log --oneline
# 提交树
git log --oneline --graph
git log --oneline --graph --decorate --all
# 显示commit历史以及每次commit发生变更的文件
git log --stat
# 搜索提交历史,根据关键词
git log -S <keyword>
# 显示某个commit之后的所有变动每个commit占据一行
git log [tagName] HEAD --pretty=format:%s
# 显示某个commit之后的所有变动其"提交说明"必须符合搜索条件
git log [tagName] HEAD --grep feature
# 显示某个文件的版本历史,包括文件改名
git log --follow <file>
# 或者
git whatchanged <file>
# 显示指定文件相关的每一次diff
git log -p <file>
# 显示过去5次提交
git log -5 --pretty --oneline
# 显示所有提交过的用户,按提交次数排序
git shortlog -sn
```
### 对比
```sh
# 显示暂存区和工作区的差异
git diff
# 显示暂存区和上一个commit的差异
git diff --cached <file>
# 显示工作区与当前分支最新commit之间的差异
git diff HEAD
# 显示两次提交之间的差异
git diff <first-branch> <second-branch>
# 本地与远程的差集 :显示远程有而本地没有的commit信息
git log <local-branch> <origin/remote-branch>
# 统计文件的改动
git diff --stat <local-branch> <origin/remote-branch>
# 显示今天你写了多少行代码
git diff --shortstat "@{0 day ago}"
# 显示某次提交的元数据和内容变化
git show <commit>
# 显示某次提交发生变化的文件
git show --name-only <commit>
# 显示某次提交时,某个文件的内容
git show <commit> <filename>
```
## 远程仓库
### 显示信息
```bash
# 显示所有远程仓库
git remote -v
# 显示某个远程仓库的信息
git remote show <shortname>
# git remote show origin
# git remote show upstream
```
### 添加/删除/重命名
```sh
# 增加一个新的远程仓库,并命名
git remote add <shortname> <url>
# 删除一个远程仓库的所有配置
git remote remove <shortname>
# 重命名远程仓库
git remote rename <old-shortname> <new-shortname>
```
### 更新url
```sh
git remote set-url <shortname> <newurl>
```
### 添加/删除 url列表
```sh
# 添加一个新的 URL 到指定远程仓库的 URL 列表
git remote set-url --add <shortname> <url>
# 从一个远程仓库的 URL 列表中删除一个特定的 URL
git remote set-url --delete <shortname> <url>
```
### 从上游仓库的新建一个分支
code --> manin --> view all branches --> new branch --> 选择上游仓库, 选择上游分支
```sh
git fetch upstream
git checkout -b 分支名 upstream/分支名
```
### 上传
```sh
# 上传本地指定分支到远程仓库
git push [-u] <shortname> <remote-branch>
# -u是 --set-upstream的简写, 添加上游跟踪引用,以后可以直接使用 git push 和 git pull
# shortname 比如说叫origin, 是代指远程仓库的别名, 只是在本地用的
# 示例
# git push origin master
# git push -u origin master
# 强行推送当前分支到远程仓库,即使有冲突
git push <shortname> <remote-branch> --force
git push <shortname> <remote-branch> -f
# 上传所有分支
git push -u <shortname> --all
# 推送所有分支到远程仓库
git push <shortname> --all
```
### 下载
```sh
# 下载远程仓库的所有变动
git fetch <remote>
# 所有远程仓库
git fetch -a
# 取回远程仓库的变化,并与本地分支合并
git pull <shortname> [remote-branch]
# pull = fetch + merge
```
### 远程仓库改名
```sh
# 假设远程仓库改名
# 先查看远程仓库的url
git remote -v
# 更新url
git remote set-url origin <new_remote_url>
# 验证
git remote -v
```
## 撤销
### 文件
```bash
# 恢复暂存区的指定文件到工作区
git checkout <file>
# 恢复某个commit的指定文件到暂存区和工作区
git checkout <commit> <file>
# 恢复暂存区的所有文件到工作区
git checkout .
# 将在工作空间但是不在暂存区的文件撤销更改
git restore <file>
# 将暂存区的文件从暂存区撤出,但不会更改文件
git restore --staged <file>
# 重置暂存区的指定文件与上一次commit保持一致但工作区不变
git reset [file]
# 重置暂存区与工作区与上一次commit保持一致 --hard危险操作
git reset --hard
```
### 分支
```sh
# 重置当前分支的指针为指定commit同时重置暂存区但工作区不变
git reset <commit>
# 重置当前分支的HEAD为指定commit同时重置暂存区和工作区与指定commit一致
git reset --hard <commit>
# 未push时, 撤销上次commit
git reset --soft 'HEAD^'
# 不加单引号或者在^前加/ 报错 no matches found
# : 因为 zsh 或其他 shell 中,当 ^ 符号被解释为一个特殊字符
--soft
# 不删除工作空间的改动代码撤销commit撤销的commit会退到暂存区
--hard
# 清空工作区和暂存区撤销commit
--mixed
# 不删除工作空间的改动代码撤销commit, 重置暂存区, 撤销的commit和暂存区会退到工作区
# 重置当前HEAD为指定commit但保持暂存区和工作区不变
git reset --keep <commit>
```
### 抵消撤销
```sh
# 新建一个commit用来撤销指定commit
# 后者的所有变化都将被前者抵消,并且应用到当前分支
git revert <commit>
# 例如假设当前提交是c2, 上一次提交是c1, 执行 git revert HEAD会新增一个提交c2' 提交的状态和c1一样 用处就是可以把这次变化推到远程分支上,其他开发者也能看到
# 而git reset是local的退了就退了其他人看不到 还有想退到上次,要多加^, revert用
```
## 暂存
```bash
# 最常用
# 暂时将未提交的变化移除,稍后再移入
git stash
# 命令恢复之前缓存的工作目录将缓存堆栈中的对应stash删除, 默认为第一个stash,即stash@{0}
git stash pop
# 执行存储时添加备注方便查找只有git stash 也要可以的,但查找时不方便识别
git stash save "save message"
# 查看stash了哪些存储
git stash list
# 显示做了哪些改动默认show第一个存储,如果要显示其他存贮后面加stash@{$num},比如第二个 git stash show stash@{1}
git stash show
# 显示第一个存储的改动如果想显示其他存存储命令git stash show stash@{$num} -p 比如第二个git stash show stash@{1} -p
git stash show -p
# 应用某个存储,但不会把存储从存储列表中删除, 默认使用第一个存储,即stash@{0}
git stash apply
# 丢弃stash@{$num}存储,从列表中删除这个存储
git stash drop stash@{$num}
# 删除所有缓存的stash
git stash clear
```
## 变基
```sh
# 将当前分支的更改应用到指定分支上
git rebase <branch>
# git rebase main
# 交互式 rebase
git rebase -i <base-commit>
# git rebase -i HEAD~3
# 如果 rebase 过程中出现冲突并解决后,继续进行 rebase。
git rebase --continue
# 如果 rebase 过程中某个提交不需要应用,可以跳过
git rebase --skip
# 如果 rebase 过程中出现问题并希望取消,可以中止
git rebase --abort
# 尝试自动处理冲突
git rebase --strategy-option theirs
# 将特定的提交范围重新定位到另一个分支
git rebase --onto <newbase> <upstream> <branch>
# git rebase --onto main feature~1 feature
# 在 rebase 过程中更改提交的作者信息
GIT_AUTHOR_NAME="New Author" GIT_AUTHOR_EMAIL="newauthor@example.com" git rebase <branch>
```
示例:
```sh
git rebase -i HEAD~4
# 弹出一个vim, 可以让你修改4次提交的前后顺序或者删除, 会把修改后的复制一份添加到修改的起始节点, 原来的就丢了 , 后面的4是表示距离HEAD最近的4次
## 如果这里不用 HEAD~4, 而是用id, 那么就得用倒数第5次提交后生成的id, 因为是倒数第5次提交后的那个节点开始操作的
# pick保留该commit缩写:p
# reword保留该commit但我需要修改该commit的注释缩写:r
# edit保留该commit, 但我要停下来修改该提交(不仅仅修改注释)(缩写:e
# squash将该commit和前一个commit合并缩写:s
# fixup将该commit和前一个commit合并但我不要保留该提交的注释信息缩写:f
# exec执行shell命令缩写:x
# drop我要丢弃该commit缩写:d
# 比如有四次提交
pick xxxxxx 倒数第四次提交的注释
pick xxxxxx 倒数第三次提交的注释
pick xxxxxx 倒数第二次提交的注释
pick xxxxxx 最后提交的注释
# 现在四次提交要合并成一次 , 并且改注释
r xxxxxx 倒数第四次提交的注释
f xxxxxx 倒数第三次提交的注释
f xxxxxx 倒数第二次提交的注释
f xxxxxx 最后提交的注释
# ctrl + c 退出, Y, 回车 , 进入编辑注释界面
# 编辑要保存的注释
```
```sh
# 在bigFix上找bug加了一堆调试代码, 提交了多次, 现在找到了, 解决了, 想合并到主分支上, 但不想合并那些加了调试代码的提交, 只想合并解决问题的那次提交
git rebase -i # 先变基
git cherry-pick bugfix
```
https://www.cnblogs.com/code-xu/p/14262963.html
https://www.cnblogs.com/xueweihan/p/5743327.html