Commit: añadir un nodo en la punta de la rama actual
git add . && git commit -m "…"Cada commit recuerda su propio commit padre; una rama no es más que un puntero móvil a un commit, así que al confirmar, main y HEAD avanzan juntos.
149 comandos Git agrupados por situación, cada uno con explicación, ejemplo y nivel de riesgo; búsqueda, copia con un clic y favoritos; incluye diagramas y una terminal de práctica
Esta herramienta no está traducida por completo; parte del contenido usa el idioma de origen o uno de reserva.
git init git init -b main # 指定初始分支名
git clone https://github.com/git/git.git git clone git@github.com:user/repo.git my-dir
git clone --depth 1 --branch v2.0 https://github.com/user/repo.git
git clone -b develop https://github.com/user/repo.git
git config --global user.name "Zhang San" git config --global user.email "zs@example.com"
git config user.email "me@company.com"
git config --list --show-origin git config --get user.name
git config --global core.autocrlf input
git config --global alias.lg "log --oneline --graph --all" git lg
Windows 通常已带 manager;macOS 用 osxkeychain 更安全。
git help rebase git reset -h # 简短用法
git status git status -s # 短格式:M 修改 A 新增 D 删除 ?? 未跟踪
git add src/app.js git add src/ # 整个目录 git add "*.md" # 通配
git add -A git add -u # 只暂存已跟踪文件的修改与删除,不含新文件
git add -p src/app.js # y 暂存这块 n 跳过 s 拆得更小 q 退出
git commit -m "fix: 修正登录超时判断"
git commit -am "docs: update readme"
容易把不想提交的改动一起带进去,提交前先 git status。
git add forgotten.js git commit --amend --no-edit # 补文件但不改说明 git commit --amend -m "新说明"
产生新的提交 id;已经推送过的提交不要 amend,否则需要强推。
git diff git diff src/app.js # 只看一个文件
git diff --staged
git diff main feature git diff HEAD~3 HEAD -- src/ git diff main...feature # feature 相对分叉点的改动
git diff --stat HEAD~1
git diff --word-diff=color README.md
git log git log -5 # 最近 5 条 git log --oneline # 一行一条
git log --oneline --graph --all --decorate
git show HEAD git show a1b2c3d --stat git show HEAD:src/app.js # 看某版本的文件内容
git rm old.txt git rm -r legacy/
git rm --cached .env echo ".env" >> .gitignore
git mv utils.js helpers.js
git branch git branch -a # 含远程分支 git branch -vv # 带最新提交与跟踪关系
git branch feature/login git branch hotfix a1b2c3d # 从指定提交创建
git switch main git switch - # 回到上一个分支
git switch -c feature/search git switch -c hotfix origin/main # 基于远程分支
git checkout -b release/1.2
git branch -m master main git push -u origin main && git push origin --delete master
git branch -d feature/login
git branch -D experiment
分支上的独有提交会成为孤儿,短期内可用 reflog 找回。
git branch --merged main git branch --no-merged # 反过来
git branch -u origin/feature/login
git branch -a --contains a1b2c3d
git checkout v1.0 git switch -c fix-from-v1 # 想保留改动就在此建分支
此状态下的提交不属于任何分支,切走后容易丢。
git branch --sort=-committerdate | head
git fetch -p git remote prune origin
git switch main git merge feature/login
git merge --no-ff feature/login
git merge --squash feature/login git commit -m "feat: login"
git merge --abort
git add src/app.js git commit # 默认说明 Merge branch ...
git checkout --theirs package-lock.json git add package-lock.json
rebase 时 ours / theirs 含义反过来:ours 是被变基到的分支。
git switch feature git rebase main
所有被搬的提交 id 都会变;已推送并有人基于它工作的分支不要 rebase。
git rebase -i HEAD~3 # pick 保留 reword 改说明 squash 并入上一条 fixup 并入且丢说明 drop 删除
git add . git rebase --continue
git rebase --abort
git rebase --onto main server client
适合「分支开错了地方」的情形。
git commit --fixup a1b2c3d git rebase -i --autosquash a1b2c3d~1
git cherry-pick a1b2c3d git cherry-pick a1b2c3d..e5f6g7h # 一段范围(不含 a1b2c3d)
git cherry-pick -n a1b2c3d
git config --global merge.tool vscode git config --global mergetool.vscode.cmd "code --wait $MERGED" git mergetool
git restore src/app.js git restore . # 整个目录
未暂存的改动会直接丢失,无法用 Git 找回。
git restore --staged src/app.js git reset HEAD src/app.js # 旧写法
git restore --source HEAD~2 config.yml git restore --source v1.0 -- src/
git reset --soft HEAD~1 git commit -m "更合适的说明"
git reset HEAD~1
git reset --hard HEAD~1 # 扔掉最后一次提交 git reset --hard origin/main # 与远程完全一致
工作区改动不可恢复;已提交的可用 git reflog 找回。
git reset package-lock.json
git revert HEAD git revert a1b2c3d --no-edit
git revert --no-commit HEAD~3..HEAD git commit -m "revert last 3 commits"
git revert -m 1 f00ba12
撤销合并后再想合入同一分支需先 revert 这个 revert。
git reflog
git reset --hard HEAD@{2} # 回到 2 步之前的状态
git branch rescue a1b2c3d # 给孤儿提交建分支git clean -n # 预览会删什么 git clean -fd # 执行 git clean -fdx # 连 .gitignore 里忽略的也删(如 node_modules)
git checkout -- src/app.js
git fsck --lost-found git show <dangling-commit-id>
git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk
git remote -v
git remote add origin git@github.com:user/repo.git
git remote set-url origin git@github.com:user/repo.git
git remote rename origin upstream
git remote remove upstream
git fetch git fetch origin main git fetch --all --prune
git pull git pull origin main
git pull --rebase origin main
git push git push origin main
git push -u origin feature/login
git push origin --delete feature/old git push origin --delete v0.1 # 也可删远程标签
git push --force-with-lease origin feature/login
优先用它而不是 --force。
git push -f origin feature/login
会抹掉别人推上去的提交;共享分支禁止。
git push --all origin
git ls-remote --heads origin git ls-remote --tags https://github.com/git/git.git
git remote add upstream https://github.com/original/repo.git git fetch upstream git switch main && git merge upstream/main
git pull --ff-only
git stash git stash push -m "登录页半成品"
git stash -u git stash -a # 连忽略文件也收
git stash list
git stash pop
git stash pop stash@{2}git stash apply stash@{1}git stash show -p stash@{0}git stash drop stash@{0}
git stash clear # 全部删除git stash branch fix-from-stash stash@{0}git stash push -m "只收起样式" -- src/styles/
git tag git tag -l "v1.*" # 按模式过滤
git tag -a v1.2.0 -m "Release 1.2.0"
git tag build-2026-09-09
git tag -a v1.1.1 a1b2c3d -m "补打"
git show v1.2.0
git tag -d v1.2.0
git push origin --delete v1.2.0
git describe --tags --always
git submodule add https://github.com/user/lib.git vendor/lib
git submodule update --init --recursive
git clone --recurse-submodules https://github.com/user/repo.git
git submodule update --remote vendor/lib git add vendor/lib && git commit -m "bump lib"
git submodule status
git submodule deinit -f vendor/lib git rm -f vendor/lib rm -rf .git/modules/vendor/lib
git worktree add ../repo-hotfix hotfix/1.2.1 git worktree add -b review ../repo-review origin/pr-42
git worktree list
git worktree remove ../repo-hotfix git worktree prune # 清理已手工删除目录的登记
git clone --filter=blob:none --sparse <url> cd repo && git sparse-checkout set apps/web packages/ui
git log -p -- src/app.js git log --follow -- src/app.js # 跨重命名跟踪
git log --grep="登录" -i --oneline
git log -S"validateToken" --oneline git log -G"regex" --oneline # 正则版
git log main..feature --oneline git log origin/main..HEAD # 还没推送的提交
git log --pretty=format:"%h %ad %an %s" --date=short -10
git log --since="2026-09-01" --until="2026-09-09" --oneline
git shortlog -sn --all --no-merges
git blame -L 40,60 src/app.js git blame -w -C src/app.js # 忽略空白、跟踪移动
git bisect start git bisect bad # 当前是坏的 git bisect good v1.1.0 # 这个版本是好的 # 反复测试并执行 git bisect good/bad git bisect reset
git bisect run npm test
git grep -n "TODO" -- "*.ts" git grep "foo" v1.0 # 在某个版本里搜
git show HEAD~5:src/config.js > old-config.js
git diff --name-only HEAD~3 HEAD git diff --name-status main # 带 M/A/D 状态
git count-objects -vH
git gc --aggressive --prune=now
prune 会真正删除不可达对象,reflog 里的后悔药会一起消失。
git rev-parse --short HEAD git rev-parse --abbrev-ref HEAD git rev-parse --show-toplevel # 仓库根目录
git archive -o release.zip v1.2.0 git archive HEAD src/ | tar -x -C /tmp/out
# .gitignore node_modules/ dist/ *.log .env* !.env.example
git check-ignore -v dist/app.js
git rm -r --cached . git add . git commit -m "chore: apply .gitignore"
echo ".DS_Store" >> ~/.gitignore_global git config --global core.excludesFile ~/.gitignore_global
git update-index --skip-worktree config/local.php git update-index --no-skip-worktree config/local.php # 取消
* text=auto *.sh text eol=lf *.png binary *.psd filter=lfs diff=lfs merge=lfs -text
git lfs install git lfs track "*.psd" git add .gitattributes
Encadenar varios comandos en una receta de «quiero hacer una cosa»; al desplegarla se copia entera.
提交早了 / 说明写错 / 想拆成两个提交(且尚未推送)
git reset --soft HEAD~1提交撤掉,改动仍在暂存区git status确认文件都在「要提交的变更」里git commit -m "新的说明"别人可能已经拉取了,不能改写历史
git revert <commit>生成反向提交git push本地实验搞乱了,想彻底回到某个提交
git log --oneline找到目标提交 idgit stash -u(可选)先收起还想保留的改动git reset --hard <commit>忘了开分支就提交了 N 次
git branch feature/x在当前位置建分支(把这些提交「存」起来)git reset --hard origin/mainmain 回到远程状态git switch feature/x开 PR 之前整理历史(分支未被他人使用)
git rebase -i HEAD~4把后面几行的 pick 改成 squash 或 fixupgit push --force-with-lease分支已推送过才需要main 已经有新提交,功能分支要在其之上继续
git fetch origingit switch feature/xgit rebase origin/main或 git merge origin/main(保留合并提交)统一默认分支名
git branch -m master maingit push -u origin maingit push origin --delete master先在托管平台把默认分支切到 maingit branch -D 之后发现还有用
git reflog找到该分支最后一次提交的 id(如 "commit: xxx")git branch <name> <commit-id>.env 或几百 MB 的文件进了历史
git rm --cached .env && echo ".env" >> .gitignore若只在最近一次提交:接着 git commit --amendgit filter-repo --path .env --invert-paths已在历史深处:用 git-filter-repo 重写全部历史(需单独安装)git push --force-with-lease --all所有协作者都要重新克隆;泄露的密钥无论如何都要作废重发main 上修好的 bug 也要进 release/1.2
git switch release/1.2git cherry-pick <commit>git pushgit merge / pull 报 CONFLICT
git status看哪些文件「双方修改」code <file>在编辑器里处理 <<<<<<< ======= >>>>>>> 标记,保留正确内容git add <file>每修好一个就 add 一个git commitrebase 时则是 git rebase --continue先在本地写了代码,后来才在 GitHub 建了仓库
git init -b main && git add -A && git commit -m "init"git remote add origin git@github.com:user/repo.gitgit push -u origin mainLos círculos son commits y las flechas apuntan al commit padre; las etiquetas verdes son ramas y la violeta indica la rama donde está HEAD; los círculos grises ya no están referenciados por ninguna rama (recuperables con reflog) y los rellenos son los commits que crea esta operación.
git add . && git commit -m "…"Cada commit recuerda su propio commit padre; una rama no es más que un puntero móvil a un commit, así que al confirmar, main y HEAD avanzan juntos.
git switch -c featureLa nueva rama y main apuntan al mismo commit, por lo que crearla es instantáneo; los commits posteriores en feature solo avanzan feature.
git switch main && git merge featureNo se crea ningún commit nuevo y el historial sigue siendo una línea recta. Para conservar el rastro de que aquí hubo una rama, hay que usar --no-ff.
git merge featureGit busca el ancestro común b2, combina los cambios de cada lado respecto a b2 y crea m6 con dos commits padre. Solo hay conflicto cuando la misma zona cambia de forma distinta.
git switch feature && git rebase mainEl historial se vuelve una línea recta, pero c3 y d4 se sustituyen por los nuevos commits c3′ y d4′ (los id cambian). No se debe hacer rebase de una rama ya publicada, o el historial de los demás divergirá.
git reset --hard HEAD~1--soft solo mueve el puntero; --mixed además vacía la zona de preparación; --hard revierte también el árbol de trabajo. El commit huérfano c3 todavía se puede recuperar desde el reflog (se conserva al menos 30 días por defecto).
git revert HEADc3 sigue en el historial y el nuevo commit r4 contiene la inversa de los cambios de c3. Para deshacer un commit ya publicado, conviene usar revert en lugar de reset.
git cherry-pick x7Reaplica sobre main el cambio que x7 introdujo respecto a su commit padre y produce x7′ con el mismo contenido pero distinto id. Es la forma habitual de llevar una corrección concreta a una rama de publicación.
Un simulador de Git completamente en memoria (no es Git real y no se conecta a la red): admite los subcomandos habituales init / add / commit / branch / switch / merge / rebase / reset / revert / stash / tag / remote / push / pull, y el grafo de la derecha se actualiza en tiempo real. 10 niveles van de «la primera confirmación» a «resolver un conflicto de fusión». La práctica de comandos de Linux está enReferencia de comandos de Linux.