Git


本文缩写(英文全称与中文含义)
缩写 英文全称/名称 中文含义
CI Continuous Integration 持续集成
CLI Command-Line Interface 命令行接口
PR Pull Request 代码合并请求
URL Uniform Resource Locator 统一资源定位符,通常指访问地址
https://git-scm.com/docs
https://git-scm.com/book/en/v2
https://cli.github.com/manual/gh_pr_create
https://cli.github.com/manual/gh_release_create
https://docs.github.com/en/pull-requests
https://docs.github.com/en/repositories/releasing-projects-on-github

1. Important Points#

Git command mental model:
    working tree:
        local files

    index / stage:
        files prepared for next commit

    local repository:
        local commits

    remote repository:
        origin / upstream on GitHub / GitLab
safety rules:
    git status before destructive commands
    prefer git revert for commits already pushed
    prefer --force-with-lease over --force
    do not reset shared branch unless team agrees

2. Basic#

本页命令是按场景独立选用的示例,不应从头到尾连续执行。main、feature/order-api、提交哈希和文件路径都要替换为实际值。

HEAD 通常指当前检出的分支最新提交;HEAD~1 是沿第一父提交回退一步。origin/main 是本地保存的远端分支状态,只有 fetch 等操作后才会更新;它与本地 main 是两个不同引用。

在分支整合或回退前,先确认当前分支、上游关系与未提交改动:

git branch --show-current
git branch -vv
git status

git branch -vv 中的 ahead/behind 是与本地缓存的上游状态比较;需要最新远端状态时先执行 git fetch origin。

init repository#

git init

clone repository#

git clone git@github.com:example/order-api.git

check status#

git status

view diff#

比较工作目录与暂存区,显示已跟踪文件中尚未暂存的修改;新建且未跟踪的文件内容不会显示在这里。

git diff

view staged diff#

比较暂存区与 HEAD,显示下一次 commit 将包含的修改。修改文件并 add 后再次编辑,后续编辑还需再次 add 才会进入提交。

git diff --cached

add one file#

git add src/orders/service.ts

add all changes#

将当前目录及其子目录中的新增、修改和删除加入暂存区;在子目录运行时,不会覆盖仓库其他目录。add 不创建提交,也不上传远端。

git add .

add all repository changes from any directory#

git add -A :/
use this when:
    current shell is inside a subdirectory
    you want to stage changes across the whole repository

note:
    :/ means repository root pathspec
    git add . only stages changes under the current directory

commit#

把当前暂存区生成一个本地提交;未暂存的编辑不会包含其中,也不会自动 push。

git commit -m "feat: add order create api"

amend last commit#

替换当前分支的最新提交,同时纳入当前暂存内容并修改提交说明;即使只改说明,commit ID 也会变化。仅用于尚未分享的提交;保留原说明用 --no-edit,相关忽略文件场景见第 13 节。

git commit --amend -m "feat: add order create endpoint"

show commit history#

git log --oneline --decorate --graph --all

show one commit#

git show a1b2c3d

3. Remote#

list remotes#

git remote -v

add remote#

git remote add origin git@github.com:example/order-api.git

change remote URL#

git remote set-url origin git@github.com:example/new-order-api.git

fetch remote#

下载 origin 的提交并按远端配置更新 origin/main 等远端跟踪引用;通常不会修改本地 main、当前分支、暂存区或工作目录。需要整合到当前分支时,再执行 merge 或 rebase。

git fetch origin

fetch all remotes#

抓取各个已配置远端(配置为跳过的除外),并清理远端已删除分支对应的远端跟踪引用;不会删除本地开发分支,也不会自动 merge。这里的 prune 默认不等于删除本地 tag。fetch 说明

git fetch --all --prune

pull current branch#

从当前分支配置的上游抓取并整合更新;通常是同名远端分支,但以 git branch -vv 显示的配置为准。没有上游时需要先设置或显式指定远端与分支。

git pull

pull remote branch into current branch#

从 origin 抓取远端 main,再把它整合到当前检出的分支。 例如当前是 feature/order-api,更新的是这个 feature 分支;命令不会切换到本地 main,也不会向远端提交修改。

git pull origin main

pull 包含 fetch 和后续整合两步;上面省略了整合方式,实际行为受 Git 版本及 pull.rebase、pull.ff 等配置影响,分叉时也可能拒绝执行。为表达明确意图,下面三种方式选择一种:pull 官方说明

目的 命令 对当前分支的影响
使用 merge 整合远端 main git pull --no-rebase --ff origin main 可快进时移动分支指针;双方都有新提交时创建 merge commit
使用 rebase 整合远端 main git pull --rebase origin main 将当前分支需要重放的提交放到抓取的 main 之后,重放后的 commit ID 改变
只接受快进 git pull --ff-only origin main 当前分支可沿已有历史直接前进时更新;发生分叉时失败,不自动 merge/rebase

merge 与 rebase 是两种不同的整合方式,rebase 不会随后再自动执行一次 merge。merge 模式用 --ff 明确允许快进或分叉合并,避免仓库的 pull.ff=only 配置改变示例意图。

若想先检查远端新增内容,再决定如何整合,可拆成两步:

git fetch origin
git log --oneline HEAD..origin/main
git merge origin/main
# 或用 git rebase origin/main 代替上面的 merge,不必两者都执行。

HEAD..origin/main 列出远端 main 中当前分支尚未包含的提交。pull 前先提交或 stash 本地编辑;发生冲突后,按第 11 节解决或中止对应的 merge/rebase。

push current branch#

把本地已提交内容发送到配置的远端分支;未提交的文件不会上传。目标由上游、push.default 等配置决定,不能仅凭当前分支名猜测;默认 simple 模式通常推送同名上游分支。

git push

push and set upstream#

将本地 feature/order-api 推送到 origin 的同名分支,并设置它的上游关系,便于之后在该分支运行 pull/push。此命令按显式分支名推送,不会因为当前检出其他分支就改推其他分支。

git push -u origin feature/order-api

4. Branch#

list local branches#

git branch

list all branches#

git branch -a

create branch#

从当前 HEAD 创建分支指针;不会切换分支,也不会把未提交改动保存为提交。

git branch feature/order-api

switch branch#

切换当前分支并更新工作目录。可兼容的未提交改动可能随你一起切换;若会覆盖改动,Git 会拒绝,先 commit 或 stash。

git switch feature/order-api

create and switch branch#

以当前 HEAD 为起点创建并切换分支。若想基于最新远端 main 开发,先 fetch,再使用 git switch -c feature/order-api origin/main;如只想把 main 当起点而不设成上游,可加 --no-track。

git switch -c feature/order-api

create local branch from remote branch#

先执行 git fetch origin 获取最新引用,再从 origin/feature/order-api 创建并切换到本地分支;常规配置下会建立与该远端分支的上游跟踪关系,可用 git branch -vv 确认。

git switch -c feature/order-api origin/feature/order-api

fetch remote branch directly into a local branch#

这里执行的是 fetch,不是 pull。冒号左侧是远端来源分支,右侧是要创建或更新的本地分支;命令不切换分支、不把内容 merge 到当前分支。

git fetch origin feature/order-api:feature/order-api

若目标本地分支已经存在,通常要求更新可快进;Git 默认拒绝直接 fetch 到当前工作树已检出的分支。日常同步当前分支应使用前面的 pull,或先 fetch 再 merge/rebase。

rename current branch#

git branch -m feature/order-api-v2

delete local branch#

只删除本地分支,不删除远端分支。-d 会检查分支是否已合并到其上游(未设上游时检查 HEAD);不能删除被任一 worktree 检出的分支。

git branch -d feature/order-api

force delete local branch#

跳过未合并检查,可能丢失该分支独有提交的正常入口;不会删除远端分支。先检查 git log --oneline HEAD..feature/order-api,确认不再需要这些提交。

git branch -D feature/order-api

delete remote branch#

删除服务器 origin 上的指定分支,不删除同名本地分支;这是对共享远端的修改。

git push origin --delete feature/order-api

5. Merge / Rebase#

这些操作的目标是当前检出的分支。引用 origin/main 前先 fetch;merge/rebase 本身不访问远端。merge 保留已有提交,必要时增加合并提交;rebase 重放当前分支提交,通常改变其 ID,避免自行重写他人正在使用的历史。

merge branch into current branch#

将本地 feature/order-api 的历史整合到当前分支;例如先 git switch main 再运行下面的命令,就是把 feature 合入本地 main。被合入的 feature 分支指针不因此移动。

git merge feature/order-api

merge main into current branch#

将本地缓存的远端 main 状态合入当前分支;例如当前是 feature,就是把 main 的更新带入 feature。可快进时默认不产生 merge commit;需要保留显式合并节点时用 git merge --no-ff origin/main。

git merge origin/main

abort merge#

在尚未完成的合并中尝试恢复合并前状态;不是撤销一个已经提交的 merge。合并前若有未提交编辑,可能无法完整恢复,因此应先 commit 或 stash。

git merge --abort

rebase current branch on main#

以 origin/main 为新基点,重放当前分支相对上游需要保留的提交;当前是 feature 时,被重写的是 feature,不是 main。rebase 后不需要再 merge 一次 main。

git rebase origin/main

continue rebase after resolving conflicts#

修改冲突文件、检查内容并执行 git add 后继续;rebase 可能在后续提交再次停下,需要逐次解决,不用手动为每一步另建普通 commit。

git rebase --continue

abort rebase#

中止尚未完成的 rebase,回到开始前的分支状态;不能用它撤销已经完成的 rebase,完成后可通过 reflog 寻找原提交。

git rebase --abort

cherry-pick commit#

将指定提交的改动应用到当前分支,通常生成一个新提交;不会切换到原分支或合入其全部历史。冲突解决并 add 后运行 git cherry-pick --continue,放弃则用 git cherry-pick --abort。

git cherry-pick a1b2c3d

6. Undo / Rollback#

撤销前先区分要改哪一层:工作目录、暂存区、当前分支历史。以下命令分别处理不同情况,不要连续执行。reset 官方说明

操作 当前分支指针 暂存区 工作目录
restore --staged FILE 不变 文件恢复到 HEAD 版本 不变,编辑仍保留
restore FILE 不变 不变 文件恢复到暂存区版本
reset --soft COMMIT 移到目标提交 不变 不变
reset --mixed COMMIT(默认) 移到目标提交 恢复到目标提交 不变
reset --hard COMMIT 移到目标提交 恢复到目标提交 覆盖为目标版本,可能丢失本地改动
revert COMMIT 通常新增撤销提交 完成后与新提交一致 应用反向改动

unstage file#

取消该文件的暂存,保留工作目录里的编辑;不会撤销已有 commit。

git restore --staged src/orders/service.ts

discard file changes#

用暂存区版本覆盖工作目录文件,丢弃该文件尚未暂存的改动。若它已 add,暂存内容仍在;不要将此命令理解为总是恢复到最新 commit。

git restore src/orders/service.ts

restore file from main#

从 origin/main 取指定文件覆盖当前工作目录,不切换分支,也不 merge 整个 main;暂存区不变。先 fetch 保证来源新鲜,检查 git diff 后 add/commit,才会把该文件版本写入当前分支历史。

git restore --source origin/main src/orders/service.ts

revert one commit#

在当前分支创建反向提交来抵消目标提交的改动,保留原历史,适合已分享的提交。冲突解决并 add 后用 git revert --continue,放弃则用 git revert --abort。

git revert a1b2c3d

revert merge commit#

-m 1 表示以合并提交的第一个父提交作为主线,撤销 merge 相对该父提交带来的改动,不是 main 分支编号。先用 git show --no-patch --pretty=raw a1b2c3d 检查父提交顺序;撤销 merge 后直接再次 merge 原分支,通常不会重新引入已撤销的旧改动,需要结合 revert-of-revert 等方案处理。

git revert -m 1 a1b2c3d

cancel a revert commit#

If git revert already created a new commit, the safest way to cancel it is usually to revert the revert.

git log --oneline
git revert REPLACE_REVERT_COMMIT_HASH

Example:

git revert abc1234

This creates another commit that restores the content removed by the previous revert. Use this when the revert commit has already been pushed or shared.

If the revert commit is only local and not pushed yet, you can remove the last commit instead.

下面的 HEAD~1 仅适用于要删除的 revert 正好是最新提交;如果它后面还有其他提交,不可照抄,否则移除的是另一个提交。

Keep the revert changes staged:

git reset --soft HEAD~1

Discard the revert commit and its working tree changes:

git reset --hard HEAD~1
decision:
    already pushed:
        git revert <revert_commit_hash>

    not pushed, want to keep changes staged:
        git reset --soft HEAD~1

    not pushed, want to delete the revert completely:
        git reset --hard HEAD~1

danger:
    reset --hard discards local working tree changes
    check git status before using it

reset last commit but keep changes staged#

将当前分支回退一个提交,暂存区与工作目录保持原样。原最新提交相对其父提交的改动通常会成为已暂存改动,可整理后重新 commit;已有未暂存编辑仍保持未暂存。

git reset --soft HEAD~1

reset last commit and keep changes unstaged#

默认是 --mixed:当前分支回退一个提交,暂存区回到该提交,工作目录保持原样。原最新提交的改动变为未暂存;其中新增文件可能变为未跟踪文件。

git reset HEAD~1

reset working tree to remote branch#

把当前分支本身重置到 origin/main,同时覆盖暂存区和工作目录,不只是同步文件。即使当前分支叫 feature,也会让 feature 指向 main 的提交;它不会切换分支或修改服务器上的 main。先 fetch,并确认本地独有提交与编辑已保留。

git reset --hard origin/main
danger:
    reset --hard discards local working tree changes
    use only after checking git status

find old commit with reflog#

查看本地 HEAD 的移动记录,可寻找 reset/rebase 前的提交。reflog 不等于远端历史或永久备份,记录会过期;它通常无法恢复从未提交或 stash 的编辑。

git reflog

restore branch to reflog point#

HEAD@{3} 是本地 HEAD reflog 中往前数第 3 条状态,不表示 3 个父提交。先通过 git reflog 找到目标,最好复制实际 commit ID,避免后续操作改变序号。下面的 hard reset 会覆盖当前分支和本地编辑。

git reset --hard HEAD@{3}

7. Stash#

stash 保存临时未提交改动供稍后恢复,是本地存储,不会随 push 上传。默认 stash push 保存已跟踪文件的暂存与未暂存改动,通常将这些文件恢复到 HEAD;包含未跟踪文件用 -u,连被忽略文件也包含用 -a,后者可能收走大型本地产物。stash 官方说明

stash current changes#

git stash push -m "wip order api"

list stashes#

git stash list

apply latest stash#

把最新 stash 应用到当前工作目录,保留 stash 条目;也可以指定 stash@{n}。不自动切换回原分支;需要尝试恢复原暂存状态时加 --index。

git stash apply

apply and drop latest stash#

应用成功后删除该 stash;若发生冲突,stash 通常保留。先解决并检查结果,再决定是否 drop,避免重复 pop 同一份改动。

git stash pop

drop one stash#

删除指定 stash 条目,不会应用其中的改动;先用 git stash show -p 'stash@{0}' 确认内容。条目删除后编号会变化。

git stash drop stash@{0}

clear all stashes#

清空本地所有 stash,不会恢复其中的编辑;先确认没有需要保留的工作。

git stash clear

8. Tag#

tag 标记一个固定提交,分支继续开发时它不会随之移动。轻量 tag 只是引用;附注 tag 还保存说明、创建者等信息。下面未指定提交的创建命令都标记当前 HEAD;各个 v1.2.0 创建示例是替代写法,不应依次执行。

创建 tag 只影响本地;普通分支 push 通常不会推送轻量 tag,需显式推送。删除本地 tag 与远端 tag 也是两个独立操作。正式发布后避免随意移动同名 tag。

list tags#

git tag

create lightweight tag#

git tag v1.2.0

create annotated tag#

git tag -a v1.2.0 -m "release v1.2.0"

create tag on specific commit#

git tag -a v1.2.0 a1b2c3d -m "release v1.2.0"

push one tag#

git push origin v1.2.0

push all tags#

推送所有本地 tag,可能包含尚未准备发布的标记;只发布一个版本时使用上一条指定 tag 的命令。

git push origin --tags

delete local tag#

git tag -d v1.2.0

delete remote tag#

git push origin --delete v1.2.0

9. GitHub PR#

git 管理提交和分支,gh 通过 GitHub API 管理 PR、Release 等平台对象。先确认登录账号和当前仓库;创建 PR 不等于合并代码。

login GitHub CLI#

gh auth login

create PR#

创建从 --head feature/order-api 合入 --base main 的 PR;方向是 feature → main。先提交并 push 要审核的分支;创建 PR 不会将未提交文件包含进去,也不会把 main 拉进本地 feature。

gh pr create --base main --head feature/order-api --title "Add order API" --body "Implement order create and query endpoints."

create draft PR#

方向与普通 PR 相同,--draft 将它标记为草稿;准备好后运行 gh pr ready 转为可审核状态。

gh pr create --base main --head feature/order-api --draft --title "WIP order API" --body "Draft for early review."

list PRs#

gh pr list

view PR#

gh pr view 123 --web

checkout PR locally#

抓取并切换到 PR 对应的本地分支,方便测试;会改变当前检出状态,先处理未提交编辑。

gh pr checkout 123

merge PR#

在 GitHub 上把 PR 的改动压成一个提交合入该 PR 的 base 分支;目标不是本地当前分支。--delete-branch 请求合并后删除本地与远端来源分支。操作受仓库检查、保护规则或合并队列约束;合并后本地 main 仍需 fetch/pull 才能同步。gh pr merge 说明

gh pr merge 123 --squash --delete-branch

10. GitHub Release#

Release 是关联 tag 的 GitHub 发布对象,可附说明和产物;创建它不等于把本地未推送提交上传。以下示例先在第 8 节创建并 push 目标 tag,再用 --verify-tag 确认远端已有它。否则默认命令可能在 tag 不存在时,从远端默认分支自动创建 tag,发布到意外的提交。gh release create 说明

create release from tag#

gh release create v1.2.0 --verify-tag --title "v1.2.0" --notes "Release v1.2.0"

create release and generate notes#

与上一条二选一,自动生成发布说明;若需要先审核,将 --draft 加入创建命令以保存草稿。

gh release create v1.2.0 --verify-tag --generate-notes

upload release asset#

将本地文件上传为已有 Release 的附件,不会把它加入 Git 提交;先确认产物版本与该 tag 一致。仓库启用不可变 Release 时,发布后不能再修改附件,应在发布前准备好。

gh release upload v1.2.0 dist/order-api.tar.gz

list releases#

gh release list

delete release#

删除 GitHub 上的发布对象及附件,默认保留关联 tag;不会回退代码或撤销已部署应用。不可变 Release 等仓库规则可能限制删除。

gh release delete v1.2.0

11. Conflict#

先用 git status 确认当前进行的是 merge、rebase、cherry-pick 还是 revert,再采用对应的继续或中止命令。不要只删除冲突标记就认为内容正确,应核对合并结果并运行相关检查。

show conflicted files#

git diff --name-only --diff-filter=U

mark resolved file#

手工编辑得到预期结果后,用 add 将结果写入暂存区并标记已解决;add 本身不会自动解决冲突。若解决方式是删除文件,用 git rm 标记。

git add src/orders/service.ts

finish merge after conflict#

git commit

finish rebase after conflict#

git rebase --continue

12. Worktree#

worktree 让同一仓库在多个目录同时检出不同分支,各自拥有工作目录和暂存区,但共享提交对象及分支引用;同一个分支默认不能同时在多个 worktree 检出。

create worktree for another branch#

把已有 hotfix/payment-timeout 分支检出到新目录,当前目录仍停留在原分支。若要新建分支,改用 git worktree add -b hotfix/payment-timeout ../order-api-hotfix main,其中 main 是起点。

git worktree add ../order-api-hotfix hotfix/payment-timeout

list worktrees#

git worktree list

remove worktree#

移除额外工作目录及其 worktree 登记,不删除对应分支。默认要求目录干净,先保存其中的改动;不要把它误当成只移除 Git 跟踪。

git worktree remove ../order-api-hotfix

13. Ignore / Cached Files#

staged / index meaning#

staged / index:
    files already added to the next commit
    git commit reads from the index, not directly from the working tree

.gitignore:
    prevents new untracked files from being added accidentally
    does not automatically remove files already tracked or staged

remove ignored build output from index#

Use this when files are already staged/tracked, but should stay on disk and be ignored by Git.

git rm --cached -r envs/uat/ap-northeast-1/sns/builds

Then verify:

git status
result:
    files are removed from Git index
    local files remain on disk
    future git add . will not add them if .gitignore matches

common case:
    .gitignore contains **/builds/**
    zip/json build artifacts were staged before the ignore rule
    git rm --cached removes them from the next commit

Do not use plain rm unless you also want to delete local files.

已 commit、尚未 push:改为忽略文件#

场景:执行 git add . 并提交后,才发现某个文件或目录不应该进入版本控制。仅把路径加入 .gitignore 不会取消已有跟踪,需要先从暂存区移除,再修改最新提交。

以下操作适用于要修改的就是最新一次提交,且该提交尚未 push 或分享给他人。在仓库根目录执行;先确认暂存区没有其他不想合入最新提交的修改,因为 amend 会一并提交当前暂存内容。

git status
git diff --cached

先在根目录的 .gitignore 中添加要忽略的路径,例如:

/path/to/file

然后执行(将 path/to/file 替换为实际文件路径):

git rm --cached -- path/to/file
git add .gitignore
git diff --cached
git commit --amend --no-edit
  • git rm --cached:从暂存区移除文件,保留磁盘上的文件。
  • git add .gitignore:把忽略规则一起加入提交,避免以后 git add . 再次添加该文件。
  • git commit --amend --no-edit:用暂存区内容重新生成最新提交,保留原提交说明;commit ID 会改变。

如果误提交的是整个 Terraform .terraform 目录,根目录的 .gitignore 可添加 **/.terraform/,忽略各级目录中的本地初始化产物,然后执行:

git rm -r --cached -- terraform/env/dev/ap-southeast-1/vpc/.terraform
git add .gitignore
git diff --cached
git commit --amend --no-edit

-r 用于递归移除目录。此规则不包含 .terraform.lock.hcl,锁文件通常仍应提交。

最后检查提交、跟踪状态和忽略规则;下面以单文件为例,检查目录时替换成目录路径:

git show --stat HEAD
git ls-files -- path/to/file
git check-ignore -v -- path/to/file
git status

预期:git ls-files 不再列出目标路径,git check-ignore -v 显示命中的忽略规则,本地文件仍在。如果文件是最新提交才首次加入的,amend 后它不会出现在该提交的变更中;如果更早的提交已经跟踪它,最新提交会记录删除,旧历史仍保留文件内容。

如果提交已经 push 或分享,通常以新提交记录停止跟踪,不直接 amend 后强推;如果误提交发生在更早的本地提交,amend 最新提交也不会清除更早历史。涉及密钥泄露时还需撤销或轮换凭据,见 Gitleaks。

14. Clean#

clean 处理未跟踪文件,已跟踪文件的编辑由 restore/reset 等命令处理。以下示例默认排除 .gitignore 匹配项;-x 才会连忽略文件一起处理,-X 则只处理忽略文件。

preview untracked files to delete#

git clean -nd

delete untracked files#

-f 确认删除,-d 包含目录;只会按当前路径范围清理,不能依靠 Git 恢复从未提交过的文件。先用相同范围的 git clean -nd 预览,必要时指定路径缩小范围。

git clean -fd
danger:
    git clean -fd deletes untracked files
    run git clean -nd first

15. Production Checklist#

before merge:
    git status clean
    tests passed
    branch is up to date
    PR reviewed

before rollback:
    prefer git revert for pushed commits
    record commit hash
    know whether commit is merge commit

before release:
    tag name checked
    release notes generated/reviewed
    artifacts uploaded if needed
    rollback plan exists

搜索文档

输入关键词,搜索所有文档。

↑ ↓ 选择 · Enter 打开 · Esc 关闭