服务器运维

git 命令大全:运维日常常用命令速查表

日常用到的 git 命令不过三十来条:clone 拿到仓库,status、diff、log 看变化,add、commit 记录,switch、merge 管分支,pull、push 同步,restore、reset、revert 撤销。下面按场景列成速查表,每条一句说明,最后讲在服务器上用 Git 管理配置文件和部署脚本。

作者 顶联产品团队发布于 8 分钟阅读

运维日常用到的 git 命令,按场景可以分成六组:初始化与克隆(git init、git clone),查看状态与历史(git status、git diff、git log),暂存与提交(git add、git commit),分支切换与合并(git switch、git merge),远程同步(git fetch、git pull、git push),撤销与回退(git restore、git reset、git revert、git stash)。下面每组一张速查表,每条命令一句说明,撤销类命令另外标出了风险。动手前先用 git --version 看一下版本:git switch 和 git restore 需要 Git 2.23 或更新的版本,CentOS 7 自带的是 1.8.3.1,没有这两个命令,表里同时给出了老版本的写法。

先分清四个位置:命令都在它们之间搬运内容

理解了 Git 的四个“位置”,大部分命令的作用就不用死记:

位置 是什么 进出的命令
工作区 你看到并直接编辑的文件 编辑文件即改变它;git restore 丢弃这里的修改
暂存区 下一次提交将要包含的内容 git add 放进来;git restore --staged 拿出去
本地仓库 .git 目录里的全部提交历史 git commit 把暂存区记成一个提交;git reset 移动分支的位置
远程仓库 GitLab、Gitea 等服务器上的仓库 git push 推上去;git fetch、git pull 拉下来

git status 会告诉你每个改动处在哪个位置。第一次在一台机器上使用 Git,先设置身份和几项常用配置:

git config --global user.name "zhangsan"
git config --global user.email "[email protected]"
git config --global init.defaultBranch main     # 新仓库的默认分支名,Git 2.28 起支持
git config --global core.editor vim             # 写提交说明时用的编辑器
git config --global pull.ff only                # pull 只接受快进,避免意外生成合并提交
git config --list --show-origin                 # 查看全部配置以及各自来自哪个文件

不加 --global 时,配置只写进当前仓库的 .git/config,适合在服务器上给某个仓库单独设置提交身份。

初始化、克隆与查看:status、diff、log

初始化与克隆

命令 说明
git init 把当前目录变成一个 Git 仓库
git init -b main 初始化并指定分支名(Git 2.28 起)
git clone https://git.example.com/ops/scripts.git 克隆仓库到同名目录,后面再跟一个路径就克隆到指定目录
git clone -b v1.4.2 --depth 1 地址 目录 只取某个分支或标签的最新一次提交,在服务器上部署时省时间和磁盘
git remote -v 查看远程仓库的名字和地址

查看状态、差异与历史

命令 说明
git status 哪些文件改了、哪些已暂存、哪些是新文件,以及当前在哪个分支
git status -sb 简短格式,每个文件一行,第一行显示与远程分支相比领先、落后几个提交
git diff 工作区里还没暂存的改动
git diff --staged 已暂存、即将提交的改动,提交前看一眼
git diff HEAD~3 -- nginx.conf 某个文件和 3 个提交之前相比改了什么
git log --oneline --graph --decorate --all 所有分支的提交历史,一行一个,带分支图
git log --stat -5 最近 5 个提交,以及每个提交改了哪些文件
git log -p -- conf.d/shop.conf 某个文件每一次提交的具体改动
git log --since="2 weeks ago" --author=zhangsan 按时间和作者筛选
git log -S 'client_max_body_size' 找出增加或删除过这段文字的提交,定位某项配置是哪次改的
git show 提交号 某个提交的说明和完整改动
git show HEAD~1:conf.d/shop.conf 查看文件在上一个提交时的内容,不影响工作区
git blame -L 10,20 conf.d/shop.conf 第 10 到 20 行分别由哪个提交、谁、在什么时间改的

HEAD 表示当前所在的提交,HEAD~1 是它的上一个,HEAD~3 是往前数第三个。提交号不用写全,写前 7 位通常就够。

暂存、提交与切换分支

暂存与提交

命令 说明
git add 文件 把这个文件的改动放进暂存区
git add -A 暂存所有改动,包括新增和删除的文件
git add -p 逐块询问是否暂存,一次改了几件事、想分成几个提交时用
git commit -m "说明" 把暂存区的内容记成一个提交
git commit -am "说明" 自动暂存所有已跟踪文件的改动并提交,新文件不包括在内
git commit --amend 修改上一个提交的说明,或补进漏掉的文件;已推送的提交不要这样改
git rm --cached 文件 不再跟踪该文件,但保留在磁盘上,通常配合 .gitignore 使用
git mv 旧路径 新路径 移动或重命名文件,并记录这个变化

切换分支:git switch 与 git checkout

命令(Git 2.23 起) 老版本写法 说明
git branch 同左 列出本地分支,当前分支前有 *;-a 连同远程分支一起列出,-vv 显示跟踪关系
git switch dev git checkout dev 切换到 dev;本地没有、远程有同名分支时,自动创建并跟踪它
git switch -c hotfix git checkout -b hotfix 新建分支并切换过去
git switch -c hotfix v1.4.2 git checkout -b hotfix v1.4.2 从某个标签或提交新建分支
git switch - git checkout - 回到上一个分支
git switch --detach v1.4.2 git checkout v1.4.2 切到某个标签,处于“分离 HEAD”状态,部署指定版本时用
git merge dev 同左 把 dev 合并进当前分支
git merge --no-ff dev 同左 即使能快进也生成一个合并提交,保留分支的痕迹
git merge --abort 同左 出现冲突时放弃这次合并,回到合并前
git rebase main 同左 把当前分支的提交挪到 main 最新提交之后;别人也在用的分支不要 rebase
git cherry-pick 提交号 同左 只把某一个提交复制到当前分支,常用于把修复补到发布分支
git branch -d hotfix 同左 删除已合并的分支;没合并的要用 -D 强制删除
git branch -m 旧名 新名 同左 重命名分支

切换分支时,如果工作区里有未提交的修改、并且和目标分支冲突,Git 会拒绝切换并列出冲突的文件,先提交或用 git stash 收起来再切。合并出现冲突时,冲突的文件里会出现 <<<<<<<、=======、>>>>>>> 三种标记,手工改成最终想要的内容并删掉标记,git add 这些文件后执行 git commit 完成合并。

拉取与推送:和远程仓库同步

命令 说明
git fetch 下载远程的新提交,不改动当前分支和工作区
git fetch --prune 同时清理远程已删除的分支在本地留下的记录
git log --oneline HEAD..origin/main fetch 之后,查看远程比本地多出的提交
git pull fetch 加合并,把远程的新提交合进当前分支
git pull --ff-only 只在能快进时更新,本地有分叉就报错停下;服务器上更新代码用它
git pull --rebase 把本地还没推送的提交放到远程提交之后,历史保持一条直线
git push 把当前分支推送到它跟踪的远程分支
git push -u origin hotfix 第一次推送新分支并建立跟踪关系,之后直接 git push
git push origin --delete hotfix 删除远程分支
git tag -a v1.4.3 -m "说明" 在当前提交上打一个附注标签,发布时用
git push origin v1.4.3 推送一个标签;git push --tags 推送全部标签
git push --force-with-lease 改写历史后强制推送,远程被别人更新过时会拒绝;共用分支不要强推
git remote add origin 地址 给本地仓库添加远程仓库
git remote set-url origin 新地址 仓库迁移、改用 SSH 地址后修改远程地址

撤销、回退与 stash

撤销类命令最容易出事,表里多了一列“风险”,执行前先看:

想做的事 命令 老版本写法 风险
丢弃工作区里某个文件的修改 git restore 文件 git checkout -- 文件 未提交的修改直接丢失,找不回来
把文件移出暂存区,修改保留 git restore --staged 文件 git reset HEAD 文件 无
把某个文件恢复成两个提交前的样子 git restore --source=HEAD~2 文件 git checkout HEAD~2 -- 文件(老写法会同时改暂存区) 覆盖该文件当前的内容
撤销最近一次提交,改动留在暂存区 git reset --soft HEAD~1 同左 无,适合说明写错或漏了文件
撤销最近一次提交,改动留在工作区 git reset HEAD~1 同左 无
彻底回到某个提交,之后的一切都不要 git reset --hard 提交号 同左 未提交的修改丢失;已提交的还能从 reflog 找回
撤销一个已经推送的提交 git revert 提交号 同左 无:生成一个反向提交,不改写历史,共用分支用它
删除未跟踪的文件和目录 git clean -n 预览,git clean -fd 执行 同左 删除后无法恢复,务必先看预览
找回 reset 掉的提交 git reflog 找到提交号,再 git switch -c 新分支 提交号 git checkout -b 新分支 提交号 无

git reflog 记录了 HEAD 在本地移动过的每一个位置,reset --hard 掉的提交在一段时间内都能从这里找回来;但从来没有提交过的修改,Git 没有任何记录。

stash 用来临时收起手头的修改,比如在服务器上临时改过配置,现在要先拉取新版本:

命令 说明
git stash 或 git stash push -m "说明" 收起已跟踪文件的修改,工作区恢复干净;push -m 需要 Git 2.13 起,老版本写 git stash save "说明"
git stash -u 连同未跟踪的新文件一起收起
git stash list 列出所有收起的记录,最新的是 stash@{0}
git stash show -p stash@{0} 查看某条记录的具体改动
git stash pop 恢复最近一条并从列表删除;有冲突时这条记录会保留
git stash apply stash@{1} 恢复指定的一条,记录仍保留在列表里
git stash drop stash@{1} 删除指定的一条

在服务器上用 Git 管理配置文件和部署脚本

给配置目录加上版本记录

配置文件放进 Git,“谁改了什么、改坏了怎么退回”就有了答案。以 nginx 为例:

cd /etc/nginx
git init
git config user.name "ops-web01"
git config user.email "[email protected]"
printf '%s\n' '*.key' '*.pem' 'ssl/' > .gitignore
git add -A && git commit -m "init: nginx config on web01"

# 每次改配置:改完先看差异,检查通过、加载成功后再提交
vim conf.d/shop.conf
git diff
nginx -t && systemctl reload nginx && git commit -am "shop.conf: client_max_body_size 50m"

# 新配置出了问题:把这个文件退回上一版,重新加载后把回退也记下来
git restore --source=HEAD~1 conf.d/shop.conf
nginx -t && systemctl reload nginx && git commit -am "revert shop.conf"

几点注意:

  • 私钥和带密码的文件不进仓库。 先写好 .gitignore;已经提交过的,git rm --cached 只能让以后不再跟踪,历史里依然有,应当更换这些密钥和密码。
  • Git 不管权限和属主。 它只记录文件的可执行位,不记录属主、属组和其他权限位,也不记录空目录。从 Git 恢复 /etc 下的文件后,用 ls -l 核对一下权限。
  • 仓库要推到别处。 只在本机的仓库,服务器坏了它也跟着没了。加一个远程仓库定期 git push,就多了一份异地的配置历史。
  • 整个 /etc 都想管起来,可以用 etckeeper(RHEL 系在 EPEL 软件源中):它把 /etc 放进 Git,并在用 apt、dnf 安装软件前后自动提交。

Git 记录的是“文件变成了什么样”,记录不了“谁登录了哪台服务器、敲了哪些命令”。两者配合才完整:Toplink DCIM 的 IPMI 远程管理里,经浏览器控制台发起的 SSH 会话会全程录像并记录命令级日志,配置出了问题,可以先用 git log 定位是哪次改动,再对照会话记录找到当时的操作过程。

用 Git 发布部署脚本或代码

服务器拉取仓库,用只读的部署密钥,并且只接受快进更新:

# 1. 生成本机专用的部署密钥,把 .pub 公钥添加到仓库的部署密钥(只读)
ssh-keygen -t ed25519 -f ~/.ssh/deploy_scripts -N '' -C "deploy@web01"
# 2. 在 ~/.ssh/config 里为仓库写一个别名,固定密钥和端口
Host git-ops
    HostName git.example.com
    Port 22022
    User git
    IdentityFile ~/.ssh/deploy_scripts
    IdentitiesOnly yes
# 3. 克隆、日常更新、按标签发布与回滚
ssh -T git-ops                                    # 测试密钥是否被仓库接受
git clone git-ops:ops/scripts.git /opt/scripts
cd /opt/scripts && git pull --ff-only             # 日常更新
git fetch --tags && git switch --detach v1.4.3    # 发布指定版本
git switch --detach v1.4.2                        # 有问题,切回上一个版本

代码目录如果就在网站根目录下,.git 目录可能被人直接下载(访问 https://站点/.git/config 试一下)。在 nginx 里加上 location ~ /\.git { deny all; },或者用 git archive 导出不含 .git 的文件再发布。

没有代码托管平台、只想“推送即部署”,可以在服务器上建一个裸仓库,用钩子把推送的内容检出到发布目录:

# 服务器上(发布目录 /var/www/site 要事先建好,并且 deploy 用户可写)
git init --bare /srv/git/site.git
printf '#!/bin/sh\ngit --work-tree=/var/www/site --git-dir=/srv/git/site.git checkout -f main\n' > /srv/git/site.git/hooks/post-receive
chmod +x /srv/git/site.git/hooks/post-receive

# 自己的电脑上
git remote add prod ssh://[email protected]:22022/srv/git/site.git
git push prod main

服务器上常见的 Git 报错

报错 原因 处理
fatal: detected dubious ownership in repository at '/opt/scripts' 仓库目录属于另一个用户,例如用 deploy 克隆、用 root 执行;Git 2.35.2 起出于安全考虑拒绝操作 用属主的身份执行,如 sudo -u deploy git -C /opt/scripts pull --ff-only;确认可信后才用 git config --global --add safe.directory /opt/scripts 放行
fatal: Not possible to fast-forward, aborting. 服务器上有本地提交,或者远程的历史被改写过 git log --oneline origin/main..HEAD 看本地多了什么,确认无用后 git reset --hard origin/main
fatal: Need to specify how to reconcile divergent branches. 本地和远程分叉了,又没有设置 pull 的方式 设置 pull.ff only 或 pull.rebase true,再按上一行处理分叉
error: Your local changes to the following files would be overwritten by merge: 有人直接在服务器上改了受 Git 管理的文件 先 git diff 看改了什么;要保留就 git stash,拉取后 git stash pop
脚本执行报 /bin/bash^M: bad interpreter 文件在 Windows 上编辑过,换行符是 CRLF 仓库里加 .gitattributes,写入 *.sh text eol=lf,执行 git add --renormalize . 后提交
Permission denied (publickey). 部署公钥没有添加到仓库,或者用错了密钥 ssh -vT git-ops 查看实际提交的是哪把密钥
git diff 显示 old mode 100644 和 new mode 100755 文件的可执行位变了 确实需要可执行就提交;在 Windows 上提交脚本,用 git update-index --chmod=+x deploy.sh 设置可执行位
You are in 'detached HEAD' state. 切到了标签或某个提交上 部署指定版本时属于正常;要在这里改代码,先 git switch -c 新分支名

报错信息里通常已经给出了下一步的建议命令(以 hint: 开头的几行),先读完再动手,尤其不要看到报错就习惯性地加 --force 或 reset --hard。

常见问题

git status 里的中文文件名显示成一串带反斜杠的数字,怎么办?

这是 Git 默认把非 ASCII 字符转义后显示。执行 git config --global core.quotepath false,git status、git diff 里就会直接显示中文;仍是乱码的话,再检查终端和系统的字符集是不是 UTF-8。

git push 每次都要输入账号密码,怎么免输?

推荐改用 SSH 地址:把公钥添加到代码平台的账号或仓库,再把远程地址换成 git@ 开头的写法。必须用 HTTPS 时可以配置 credential.helper,其中 store 会把凭据明文存进 ~/.git-credentials,多人共用的服务器上不要用;不少平台也已不接受账号密码,要改用访问令牌。

Git 能用来备份整个服务器吗?

不适合。Git 适合管理文本文件的变更历史,大文件和二进制文件会让仓库迅速膨胀,运行中的数据库文件直接提交也得不到一致的副本。配置文件和脚本用 Git 管理,数据和系统用专门的备份工具。

想看看在你的机房里怎么用?

从一次产品演示开始,梳理你的业务链路。

查看价格
服务热线 400-112-2951

让我们聊聊你的 IDC 业务

扫码添加企业微信,预约产品演示或申请试用。

Toplink 企业微信二维码

长按保存或使用企业微信 / 微信扫描

也可致电
400-112-2951
Telegram
@TopLink88