跳至内容

Git 常用命令

配置 Git 用户与登录凭据,查看仓库状态,完成提交、分支切换、远端同步和撤销操作,附常见输出与含义。

  • Git
  • 版本控制
  • 命令行

各小节是独立示例,按需查阅即可,不需要从头连着执行。

  • 仓库地址、文件名和提交哈希都是示例,使用时换成自己的。origin 是远端的名字,main 是主分支名。
  • 全局配置可以在任意目录执行;创建或克隆仓库后,先进入项目目录,再执行后面的命令。
  • 黑底块是示例结果,部分输出做了省略。每行最前面的 # 是本文加的标记;实际文字会随版本和仓库状态变化。

1. 配置用户与登录凭据

1.1 设置提交用户名和邮箱

这两项决定提交记录里显示谁的名字。--global 表示对当前电脑用户生效。

代码块 Shell
1
2
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
运行结果 Text
1
# 配置成功时通常没有输出。

进入仓库后,可以查看当前使用的配置:

代码块 Shell
1
2
git config --get user.name
git config --get user.email
运行结果 Text
1
2
# Your Name
# you@example.com

两行分别是提交用户名和邮箱。如果某个项目要用另一套身份,在该仓库里去掉 --global 重新设置即可。

1.2 保存远端登录凭据

user.name、user.email 只管提交署名,登录远端还需要单独认证。使用 HTTPS 时,可以让凭据管理器记住登录信息。

macOS 可以使用钥匙串:

代码块 Shell
1
git config --global credential.helper osxkeychain
运行结果 Text
1
# 配置成功时通常没有输出。

这条命令只是选好保存位置。第一次访问需要认证的仓库时,仍要完成登录;Windows、Linux 应选择各自可用的 凭据管理器。

例如,克隆一个需要登录的 HTTPS 仓库:

代码块 Shell
1
git clone https://git.example.com/team/project.git
交互提示示例 Text
1
2
3
# Cloning into 'project'...
# Username for 'https://git.example.com':
# Password for 'https://you@git.example.com':
  • Username:输入托管平台的用户名。
  • Password:按平台要求输入密码或个人访问令牌,输入时终端通常不显示字符。

GitHub 的 HTTPS 认证 已经不接受账号密码,使用令牌时要把令牌填在 Password 处。凭据管理器也可能直接打开浏览器登录。 登录成功后,凭据管理器会按配置保存凭据;不要把令牌直接写进仓库 URL。

2. 创建和查看仓库

2.1 初始化本地仓库:git init

在项目目录里执行,创建 Git 仓库。-b main 把初始分支命名为 main。

代码块 Shell
1
git init -b main
运行结果 Text
1
# Initialized empty Git repository in /path/to/project/.git/

当前目录下已经创建 .git,用来保存提交历史和仓库配置。这时还没有提交记录。

2.2 下载已有仓库:git clone

远端已经有项目时,用 clone 下载,不需要再执行 init。

代码块 Shell
1
2
git clone https://git.example.com/team/project.git
cd project
运行结果 Text
1
2
# Cloning into 'project'...
# Receiving objects: 100% (42/42), done.

project 是新建的项目目录;100% 表示这一阶段的 Git 对象已接收完。cd project 进入该目录,成功时没有输出。

2.3 查看当前状态:git status

查看自己在哪个分支、哪些文件改过、哪些改动已经准备好提交。

代码块 Shell
1
git status
运行结果 Text
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# On branch main
# Your branch is up to date with 'origin/main'.
#
# Changes to be committed:
#   modified:   README.md
#
# Changes not staged for commit:
#   modified:   app.py
#
# Untracked files:
#   notes.md
输出含义
On branch main当前在 main 分支
up to date with 'origin/main'与本地记录的远端分支一致;远端有没有新提交,需要先 fetch 才知道
Changes to be committed已暂存,本次 commit 会提交这里的改动
Changes not staged for commit文件改过,但还没用 add 放入暂存区
Untracked files新文件,还没被 Git 跟踪

暂存区就是本次准备提交的内容。 上例直接执行 commit,只会提交 README.md 的已暂存改动。

想让输出短一点,可以加参数:

代码块 Shell
1
git status --short --branch
运行结果 Text
1
2
3
4
# ## main...origin/main
# M  README.md
#  M app.py
# ?? notes.md
  • --short:把文件状态缩成两列标记,也可以写成 -s。
  • --branch:在简短输出中保留分支信息,也可以写成 -b。两项合起来就是 git status -sb。

没有冲突时,文件前的第一列看暂存区,第二列看工作区:M 在第一列表示修改已暂存,在第二列表示还有未暂存修改。 ?? 表示未跟踪。第一行的 ## 是 Git 自带的分支标记。详见 status 输出格式。

2.4 查看远端地址:git remote

-v 会把远端名字和地址一起列出来。

代码块 Shell
1
git remote -v
运行结果 Text
1
2
# origin  https://git.example.com/team/project.git (fetch)
# origin  https://git.example.com/team/project.git (push)

两行都叫 origin,分别是拉取和推送使用的地址。

自己用 init 创建的仓库还没有远端,可以添加:

代码块 Shell
1
git remote add origin https://git.example.com/team/project.git
运行结果 Text
1
# 添加成功时通常没有输出。

如果 origin 已经存在,要改地址就用 git remote set-url origin 新地址,成功时同样没有输出。

3. 查看修改并提交

3.1 看具体改了什么:git diff

git diff 查看已跟踪文件中还没暂存的改动,不会显示新建的未跟踪文件内容。

代码块 Shell
1
git diff
运行结果 Text
1
2
3
4
5
6
# diff --git a/app.py b/app.py
# --- a/app.py
# +++ b/app.py
# @@ -1 +1 @@
# -print("old")
# +print("new")

这里把 app.py 第一行的 old 改成了 new:- 是删掉的旧内容,+ 是新增内容。 a/、b/ 分别标记修改前后;@@ -1 +1 @@ 表示这段差异涉及两边的第 1 行。

3.2 选好本次提交的内容:git add

把 app.py 当前的改动放进暂存区,再检查准备提交的内容:

代码块 Shell
1
2
git add app.py
git diff --staged
运行结果 Text
1
2
3
4
5
6
# diff --git a/app.py b/app.py
# --- a/app.py
# +++ b/app.py
# @@ -1 +1 @@
# -print("old")
# +print("new")

add 成功时没有输出;这里显示的是 diff --staged 的结果,说明这处修改已经准备好提交。 普通 diff 看未暂存的内容,diff --staged 看已暂存的内容。

想暂存当前目录及子目录下的全部改动,可以用 git add .,成功时也没有输出。提交前用 git status 看一眼,确认没有带入无关文件。

3.3 保存一次提交:git commit

-m 后面写这次提交的说明。提交只保存在本地,发到远端还要执行 push。

代码块 Shell
1
git commit -m "Update application output"
运行结果 Text
1
2
# [main c0ffee1] Update application output
#  1 file changed, 1 insertion(+), 1 deletion(-)

main 是当前分支,c0ffee1 是这次提交的短哈希。下面一行表示改了 1 个文件,新增 1 行、删除 1 行。

4. 切换与合并分支

4.1 查看分支:git branch

不加参数时列出本地分支。

代码块 Shell
1
git branch
运行结果 Text
1
2
#   feature/login
# * main

这里有两个本地分支,* 表示当前在 main。加 -r 只看远端跟踪分支,加 -a 同时看本地和远端跟踪分支。

4.2 创建或切换分支:git switch

从当前位置创建 feature/login,并切换过去:

代码块 Shell
1
git switch -c feature/login
运行结果 Text
1
# Switched to a new branch 'feature/login'

a new branch 表示新建成功。分支已经存在时,去掉 -c,直接写要切换的分支名:

代码块 Shell
1
git switch main
运行结果 Text
1
2
# Switched to branch 'main'
# Your branch is up to date with 'origin/main'.

现在回到了 main,它与本地记录的 origin/main 一致。如果切换会覆盖未提交的修改,Git 会拒绝,先提交或用第 7 节的 stash 保存。

4.3 把其他分支合进来:git merge

先切到接收改动的分支。假设当前已经在 main,要把 feature/login 合进来:

代码块 Shell
1
git merge feature/login
运行结果:可以直接快进时 Text
1
2
3
4
# Updating 8c19d42..4d3a2b1
# Fast-forward
#  app.py | 2 +-
#  1 file changed, 1 insertion(+), 1 deletion(-)

Fast-forward 表示 main 沿现有历史向前移动,直接跟上了功能分支,没有额外创建合并提交。 下面两行统计合入的文件和行数。

如果两边各自有新提交,Git 可能创建合并提交;出现 CONFLICT 时则需要先处理冲突,再 add、commit。

4.4 删除用完的本地分支:git branch -d

确认分支里的修改已经合并,并切到其他分支后,再删除它:

代码块 Shell
1
git branch -d feature/login
运行结果 Text
1
# Deleted branch feature/login (was 4d3a2b1).

本地 feature/login 已删除,was 后面是它原来指向的提交。远端同名分支不会跟着删除。

5. 拉取与推送

5.1 获取远端更新:git fetch

把远端的新提交取到本地,更新 origin/main 这类远端跟踪分支;当前分支和工作区保持原样。

代码块 Shell
1
git fetch origin
运行结果:远端有新提交时 Text
1
2
# From https://git.example.com/team/project
#    8c19d42..61af039  main -> origin/main

远端 main 的更新已取回,本地记录的 origin/main 从 8c19d42 变成 61af039。当前的 main 还没有跟着更新。

5.2 更新当前分支:git pull

pull 会先获取远端更新,再整合到当前分支。下面假设当前分支已关联对应的远端分支:

代码块 Shell
1
git pull --ff-only
运行结果 Text
1
2
3
4
# Updating 8c19d42..61af039
# Fast-forward
#  README.md | 3 +++
#  1 file changed, 3 insertions(+)

当前分支已经跟上远端,README.md 新增了 3 行。--ff-only 只允许快进;本地和远端各有新提交、历史分叉时会停止,留给你决定如何合并。 见 pull 参数说明。

5.3 把本地提交发到远端:git push

第一次推送新分支时,加 -u 关联远端分支:

代码块 Shell
1
git push -u origin feature/login
运行结果 Text
1
2
3
# To https://git.example.com/team/project.git
#  * [new branch]      feature/login -> feature/login
# branch 'feature/login' set up to track 'origin/feature/login'.

[new branch] 表示远端新建了这个分支;set up to track 表示已建立关联,右边的 origin/feature/login 就是它的上游分支。

之后在 feature/login 上继续提交,通常直接推送即可:

代码块 Shell
1
git push
运行结果 Text
1
2
# To https://git.example.com/team/project.git
#    4d3a2b1..7ab3c10  feature/login -> feature/login

远端分支从 4d3a2b1 更新到了 7ab3c10。如果看到 Everything up-to-date,说明这次没有新提交需要推送。

6. 查看历史与撤销操作

6.1 查看提交日志:git log

--oneline 让每条提交只占一行,方便找提交哈希。

代码块 Shell
1
git log --oneline
运行结果 Text
1
2
3
# 4d3a2b1 (HEAD -> main) Add login validation
# 8c19d42 Update README
# a12bc34 Initial commit

左边是短哈希,右边是提交说明。HEAD -> main 表示当前在 main,它指向 4d3a2b1。日志进入分页界面时,按 q 退出。

6.2 取消暂存,保留修改:git restore --staged

文件已经 add,但这次不想提交它,可以先撤出暂存区:

代码块 Shell
1
2
git restore --staged app.py
git status --short
运行结果 Text
1
#  M app.py

restore --staged 成功时没有输出。后面的状态里,M 在第二列:修改还在工作区,只是没有放进暂存区。

6.3 丢弃未暂存的修改:git restore

如果 app.py 的未暂存改动确实不要了,用暂存区中的版本覆盖工作区文件:

代码块 Shell
1
git restore app.py
运行结果 Text
1
# 恢复成功时通常没有输出。

只丢弃未暂存的部分,已经 add 的内容仍保留在暂存区。丢弃的内容不会进入回收站。 这两种 restore 的区别见 官方说明。

6.4 回到合并前的提交:git reset --hard

适用于还没推送、也没交给别人使用的本地历史。先查日志;如果产生过合并提交,加 --first-parent 可以沿当前分支的主线查看:

代码块 Shell
1
git log --oneline --first-parent
运行结果 Text
1
2
3
# 91c2e77 (HEAD -> main) Merge branch 'feature/login'
# 8c19d42 Update README
# a12bc34 Initial commit

这个例子里,91c2e77 是合并提交,合并前的主线提交是 8c19d42。确认要回到这里,再执行:

代码块 Shell
1
git reset --hard 8c19d42
运行结果 Text
1
# HEAD is now at 8c19d42 Update README

当前分支已退回 8c19d42,暂存区和工作区也按这个提交恢复。

--hard 会丢掉已跟踪文件尚未提交的修改。 妨碍恢复目标文件的未跟踪路径也可能被删除。已经共享的历史优先用下面的 revert。见 reset 官方说明。

6.5 撤销已经提交的改动:git revert

revert 新建一次提交,抵消指定提交的修改,适合已经推送的历史。下面撤销一条普通提交,--no-edit 表示采用默认说明:

代码块 Shell
1
git revert --no-edit 4d3a2b1
运行结果:没有冲突时 Text
1
2
# [main 2f7e890] Revert "Add login validation"
#  1 file changed, 1 insertion(+), 1 deletion(-)

2f7e890 是新建的撤销提交,原来的 4d3a2b1 仍留在历史里。随后执行 git push,才会把撤销结果同步到远端。 合并提交需要额外指定主线,不能直接套用这条命令。

6.6 找回重置前的提交:git reflog

reflog 查看本地操作记录,-n 5 表示最多显示 5 条。

代码块 Shell
1
git reflog -n 5
运行结果 Text
1
2
# 8c19d42 HEAD@{0}: reset: moving to 8c19d42
# 91c2e77 HEAD@{1}: merge feature/login: Merge made by the 'ort' strategy.

HEAD@{0} 是最近一次记录,HEAD@{1} 是前一次。这里可以找到重置前的 91c2e77;记录只在本地保存,而且会过期。

7. 临时收起修改:git stash

改到一半需要切换任务,可以先保存修改。-m 给这份记录写个备注:

代码块 Shell
1
git stash push -m "login work"
运行结果 Text
1
# Saved working directory and index state On feature/login: login work

已保存 feature/login 上已跟踪文件的工作区和暂存区改动,并把这些文件恢复到当前提交的状态。 要连新建的未跟踪文件一起保存,加 -u,即 git stash push -u -m "login work"。

查看保存了哪些记录:

代码块 Shell
1
git stash list
运行结果 Text
1
# stash@{0}: On feature/login: login work

stash@{0} 是最近一份,后面显示保存时的分支和备注。

回到原分支,恢复最近一份修改:

代码块 Shell
1
git stash pop
运行结果:没有冲突时 Text
1
2
3
4
# On branch feature/login
# Changes not staged for commit:
#   modified:   app.py
# Dropped refs/stash@{0} (6a7b8c9d...)

app.py 的修改回到了工作区,Dropped 表示这份 stash 记录已删除。如果恢复时发生冲突,记录会保留,先处理冲突即可。 见 stash 官方说明。

8. 常用命令汇总

按需复制单条命令,行尾注释说明用途。地址、文件名、分支和哈希记得替换,不要整块执行。

Git 命令速查 Shell
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 用户配置
git config --global user.name "Your Name"           # 设置提交用户名
git config --global user.email "you@example.com"    # 设置提交邮箱
git config --global credential.helper osxkeychain  # macOS:用钥匙串保存 HTTPS 登录凭据

# 创建与查看
git init -b main                                   # 在当前目录初始化仓库,初始分支为 main
git clone https://git.example.com/team/project.git # 下载已有仓库
git status                                        # 查看分支、暂存和未暂存的改动
git status -sb                                    # 简短状态,等同于 --short --branch
git remote -v                                     # 查看远端名称和地址
git log --oneline                                 # 每行显示一条提交

# 暂存与提交
git diff                                          # 查看已跟踪文件未暂存的修改
git add app.py                                    # 暂存指定文件
git add .                                         # 暂存当前目录及子目录的全部改动
git diff --staged                                 # 查看已暂存的修改
git commit -m "Update application output"          # 提交暂存区内容,-m 后写提交说明

# 分支
git branch                                        # 查看本地分支,* 表示当前分支
git switch -c feature/login                       # 创建并切换到新分支
git switch main                                   # 切换到已有分支
git merge feature/login                           # 将指定分支合入当前分支
git branch -d feature/login                       # 确认已合并后,删除非当前的本地分支

# 与远端同步
git fetch origin                                  # 获取更新,不改当前分支和工作区
git pull --ff-only                                # 拉取并快进更新当前分支;需先关联上游
git push -u origin feature/login                   # 首次推送分支,并关联上游
git push                                          # 推送当前分支的新提交;需先关联上游

# 撤销与历史
git restore --staged app.py                       # 取消暂存,保留文件修改
git restore app.py                                # 丢弃该文件未暂存的修改
git revert --no-edit 4d3a2b1                       # 新建提交,撤销指定普通提交的改动
git log --oneline --first-parent                   # 沿当前分支主线查看日志
git reset --hard 8c19d42                           # 回退未共享的历史,丢弃已跟踪文件的未提交修改;见 6.4
git reflog -n 5                                   # 查看最近 5 条本地 HEAD 操作记录

# 临时保存修改
git stash push -m "login work"                     # 保存已跟踪文件的修改,-m 后写备注
git stash push -u -m "login work"                  # 同时保存未跟踪文件
git stash list                                    # 查看保存的记录
git stash pop                                     # 恢复最近一份,成功后删除该记录

评论

使用 GitHub 登录后参与讨论,评论将公开保存在 GitHub。

阅读到这里时加载评论。