Git

yuhuo2022-03-28开发工具
参考链接

工作流程

process

存储分区

工作区(Workspace)

位置:项目目录

文件状态:

  • 未跟踪(untracked):新建文件
  • 未暂存(unstaged):修改文件(modified),删除文件(deleted)
  • 未修改(unmodify)

暂存区(Index / Stage)

位置:项目目录下 .git 文件夹中

文件状态:

  • 已暂存(staged)

本地库(Repository)

位置:项目目录下 .git 文件夹中

文件状态:

  • 已提交(committed)

远程库(Remote)

目前主流远程库有 Githubopen in new windowGitLabopen in new windowGiteeopen in new window

文件状态:

  • 已推送(pushed)

命令

init

创建本地库

git init

clone

克隆远程库到本地库和工作区。

git clone [-b <分支名|标签名>] <https链接|ssh链接> [<文件夹名>]

配置SSH

安装 TortoiseGit 后,打开 设置 - 网络,配置 SSH 客户端改为:D:\Software\Git\usr\bin\ssh.exe。(或者在安装过程中,选择 OpenSSH 协议而非 TortoiseGitPlink 协议,因为 Git 使用的是 OpenSSH 协议)

通过 ssh-keygen -t rsa -C "<邮箱>" 命令,在用户目录中的 .ssh 文件夹生成 id_rsa(私钥)和 id_rsa.pub(公钥),将 id_rsa.pub 文件内容复制到远程库的 SSH 公钥配置中。

新版 Git 因为 SHA-1 算法安全问题,默认禁用 ssh-rsa 公钥,可以采用其他秘钥生成算法(ecdsa-sk 和 ed25519-sk),如 ssh-keygen -t ed25519 -C "<邮箱>"

remote

远程库管理

# 添加远程库
git remote add <远程库名> <远程库链接>

#显示所有远程库
git remote -v

# 显示指定远程库的信息
git remote show <远程库名>

# 远程库名重命名
git remote rename <旧远程库名> <新远程库名>

# 删除指定远程库
git remote rm <远程库名>

branch

分支管理

# 创建本地分支
git branch <分支名>

# 查看所有本地分支
git branch

# 查看所有本地分支和远程分支
git branch -a

# 删除指定本地分支
git branch -d <分支名>

# 强制删除指定本地分支
git branch -D <分支名>

# 重命名分支,旧分支无指定时默认当前分支
git branch -m [<旧分支名>] <新分支名>

checkout

丢弃工作区修改,重置到和暂存区一样

# 将暂存区文件提交到版本库
git checkout -- <文件名>

# 切换分支
git checkout <分支名>

# 创建并切换分支
git checkout -b <分支名>

status

查看文件状态

git status

diff

添加到暂存区前,查看文件修改内容

# 指定文件或所有文件
git diff [<文件名>]

add

将工作区文件添加到暂存区

# 直接使用 . 代表未暂存和未跟踪的文件
git add .

commit

将暂存区文件提交到版本库

# 将暂存区文件提交到版本库
git commit -m "日志"

# 将未暂存文件添加暂存区,并提交到版本库(不包含未跟踪文件)
git commit -am "日志"

log

查看日志

# 详细日志
git log [<指定文件>]
# 简化日志
git log --pretty=oneline
git log --oneline

reflog

查看引用记录(回退后通过 log 命令查看不了已经被退回日志,需要通过 reflog 查看引用记录)

git reflog

reset

重置

# 重置到前1个版本
git reset HEAD^
# 重置到前指定数量个版本
git reset HEAD~<数量>
# 重置到指定版本号的版本
git reset <版本号>

# 软重置:只重置本地库
git reset --soft <版本号>
# 混合(默认):重置本地库+暂存区
git reset --mixed <版本号>
# 硬重置:重置本地库+暂存区+工作区
git reset --hard <版本号>

fetch

以 master 分支为例,会包含本地库 master 分支和远程仓库副本 origin/master 分支。

fetch 操作是获取远程库最新版本到 origin/master 分支。

此时 master 分支依然未被更新,需要再执行合并操作:git merge origin/master

git fetch origin

pull

拉取远程库到远程仓库副本,本地库和工作区,自动合并

# 相当于执行 git fetch origin + git merge origin/master
git pull origin

# 相当于执行 git fetch origin + git rebase origin/master
git pull --rebase origin

push

推送到远程库,并更新远程库的本地副本。

# 完整示例:git push origin master:master
# 本地分支 = 远程分支,省略远程分支,示例:git push origin master
# 当前分支 = 本地分支 = 远程分支,省略分支名,示例:git push origin
git push <远程库名> [<本地分支名>[:<远程分支名>]]

# 推送所有本地分支
git push <远程库名> --all

# 强制推送
git push <远程库名> --force

# 删除远程库的指定分支
git push <远程库名> --delete <远程分支名>

# 本地库关联远程库后的第一次推送,将本地分支和远程分支进行关联
git push -u <远程库名> <分支名>

merge

分支合并

快进式合并:当前分支和目标分支没有产生分叉,则当前分支可以直接前进到目标分支,不会产生一条合并的提交记录。

# 自动快进式合并:能快进式则快进式,否则用非快进式(默认)
git merge --ff <分支名>
# 非快进式合并
git merge --no-ff <分支名>
# 仅快进式合并(当不能快进式合并时合并失败)
git merge --ff-only <分支名>

# 不自动提交,只对非快进式有效(因为快进式不需要提交),
# 此时合并操作未完成,需要再手动提交或者进行回退才能结束
git merge --no-commit <分支名>

# 将目标分支的更改仅更新到工作区,本地库不变,需要再一次性提交这些更改
# 目标分支的提交记录不会出现在当前分支中
git merge --squash <分支名>

rebase

分支变基

process

# 开始变基
git rebase <分支名>

# 处理完冲突,add之后,继续执行变基
git rebase --continue

# 中止变基,放弃合并,回到操作前的样子
git rebase --abort

stash

贮藏更改,将当前未完成,不想提交的更改暂时保存,以便切换到其他分支工作

# 新增贮藏
git stash push
git stash save '注释'

# 恢复堆栈中最新的贮藏并移除
git stash pop

# 恢复堆栈中指定的贮藏(默认最新贮藏)
git stash apply [stash@{$num}]

# 移除堆栈中指定的贮藏(默认最新贮藏)
git stash drop [stash@{$num}]

# 移除所有贮藏
git stash clear

# 查看贮藏列表
git stash list

#查看堆栈中指定贮藏和当前工作区的差异(默认最新贮藏)
git stash show [stash@{$num}]

clean

删除未跟踪的文件

git clean -f

config

优先级:system < global < local

# 系统级,对所有用户有效,对应 Git安装目录\mingw64\etc\gitconfig文件
git config --system --list
# 用户级,对当前用户有效,对应 用户目录\.gitconfig文件
git config --global --list
# 仓库级,对当前仓库有效,对应 项目目录\.git\config文件
git config --local --list

配置管理

# 查看配置列表(优先级越高排越后)
git config --list
# 显示配置对应的文件
git config --list --show-origin

# 查看指定配置项(多个值时返回优先级最高的)
git config <配置名>
git config --get <配置名>
# 查看指定配置项的所有值
git config --get-all <配置名>

# 修改/新增指定配置项(默认仓库级)
# 存在多个值时返回失败
git config <配置名> <>
# 存在多个值时合并成一个
git config --replace-all <配置名> <>

# 新增指定配置项(默认仓库级)
git config --add <配置名> <>

# 删除指定配置项(默认仓库级)
# 存在多个值时返回失败
git config --unset <配置名>
# 存在多个值时全部删除
git config --unset-all <配置名>

常见配置项

# 用户名
git config --global user.name huoyu
# 邮箱
git config --global user.email huoyu@sohu-inc.com
# 自动保存账号密码
git config --global credential.helper store
# 行尾符处理
# core.autocrlf = true 提交时转换为LF,拉取时转换为CRLF
# core.autocrlf = input 提交时转换为LF,拉取时不转换(推荐)
# core.autocrlf = false 不转换
git config --global core.autocrlf input

# hooks目录
git config --local core.hooksPath git_hooks

行尾符

Windows 使用回车(CR)和换行(LF)两个字符来结束一行,而 macOS 和 Linux 只使用换行(LF)一个字符,不统一时 Git 容易有冲突。

推荐使用 core.autocrlf = input 配置,保证代码库中的行尾符都是 LF。同时将 VSCode 的 EOL 也设置为 LF,保证工作区产生的行尾符也是 LF,从而实现全部统一为LF。

如果当前工作区的文件已经是 CTLF了,则全部转换为 LF,方法见:批量转换 LF 和 CRLFopen in new window

Hooks

Git执行特定事件时触发运行的脚本,默认 hooks 目录是 .git/hooks,目录中每个类型的钩子对应一个相应名称的脚本文件,如 pre-commit 文件(没有后缀名)。目录中默认包含的示例都带 .sample 后缀,以防止被运行。

hooks共享

方法1

在 package.json 的 scripts 字段添加 "prepare": "git config core.hooksPath gitHooks",prepare 脚本会在 install 脚本执行之后自动执行,将钩子目录改成自定义目录 gitHooks,不在.git 目录中,以便保存到代码库。

在 gitHooks 目录中创建钩子文件。在普通项目中可以直接使用 node 脚本。

#!/usr/bin/env node
const dayjs = require("dayjs");

let day = dayjs(new Date());
console.log("钩子执行时间:" + day.format("YYYY-MM-DD HH:mm:ss"));

在指定为 ES6 模块化规范的项目中(package.json 的 type 字段设定为"module"),脚本文件必须要有文件后缀,因此需要间接调用。

#!/usr/bin/env sh
node ./gitHooks/pre-commit.js;
// pre-commit.js;
import dayjs from "dayjs";

let day = dayjs(new Date());
console.log("钩子执行时间:" + day.format("YYYY-MM-DD HH:mm:ss"));

方法2

使用 husky 库(原理其实同方法1一样)

# 安装husky库,package.json 的 scripts 中新增脚本:"prepare": "husky install"
npx husky-init
# 触发 prepare 脚本的执行,
# 执行 git config core.hooksPath .husky,设置git的钩子目录为 .husky 并生成该目录
npm install
Last Updated 2024/4/27 17:44:32