git的工作目录|暂存区|版本库|远程仓库
工作目录 :是用户在本地进行文件操作的实际目录,即项目所在的目录。用户可以在工作目录中创建、修改、删除文件等,这些操作都是在本地进行的,尚未被 Git 跟踪和管理。
暂存区 :也称为索引(Index),是工作目录和版本库之间的中间区域。当使用git add
命令将文件添加到暂存区后,这些文件就准备好被提交到版本库中了。暂存区可以让用户将多次的文件修改组合成一个逻辑上的提交。
版本库 :也叫 Git 仓库,包含了项目的所有版本历史和相关的元数据,存储在隐藏的.git
目录中。当执行git commit
命令时,暂存区中的文件会被提交到版本库中,形成一个新的提交记录。
远程仓库 :是位于网络上的共享版本库,用于团队成员之间共享和协作开发项目。远程仓库可以是自己搭建的服务器,也可以是像 GitHub、GitLab 这样的代码托管平台上的仓库。本地仓库可以与远程仓库进行同步,将本地的提交推送到远程仓库,或者从远程仓库拉取最新的提交。
git的文件状态 git中文件有以下常见的4种状态:未跟踪、未修改、已修改、已暂存
未跟踪(Untracked)
已跟踪(Tracked)
含义 :文件已经被 Git 纳入版本控制,Git 会对其进行跟踪,记录文件的变更历史。已跟踪文件又可细分为以下三种状态。
unmodified(未修改)
含义 :文件在工作目录中,且自从上次提交或更新后,其内容没有发生任何改变,与版本库中的对应版本保持一致。
示例 :如果项目中有一个styles.css
文件,在上次提交后没有对其进行任何编辑操作,那么它就处于unmodified
状态。
modified(已修改)
含义 :文件在工作目录中被修改了,其内容与版本库中的对应版本不一致,Git 检测到了这种变化,但这些修改还未被添加到暂存区。
示例 :对styles.css
文件进行了样式调整,保存后,该文件就处于modified
状态,git status
命令会显示该文件被修改,提示可以选择将这些修改添加到暂存区或者丢弃。
staged(已暂存)
含义 :已修改的文件通过git add
命令被添加到了暂存区,准备好被提交到版本库中,此时文件的修改会被包含在即将进行的提交中。
示例 :在对styles.css
文件修改后,执行git add styles.css
,该文件就从modified
状态变为staged
状态,git status
命令会显示该文件已被暂存,等待提交。
以下所有操作都在实际工作目录下进行
Git本地配置 在正式演示git的添加 ,提交 ,撤回 等操作前,我们需要对git进行简单的配置。
Git配置分为系统 --system
,全局 --global
,本地 --local
三个不同级别,优先级依次递减,其中如果存在重复的配置,那么低级别配置会覆盖高级别配置
local配置:存在每个git仓库的.git/config
文件中
global配置:存在用户目录下的.gitconfig
文件中
system配置:存在${profile}/etc/gitconfig
中,${prefix}
为git的安装目录
git的提交会引用用户的用户名以及邮箱(可以使用github提供的匿名邮箱 ),因此这里需要执行命令进行设置:
1 2 git config --global user.name "DopamineNone" git config --global user.email 123919976 +DopamineNone@users.noreply.github.com
相应的在配置文件中就会出现:
1 2 3 [user] name = DopamineNone email = 123919976+DopamineNone@users.noreply.github.com
除此之外,还可以为git命令设置别名,比如:
1 git config --global alias.ad "add ."
相当于为git add .
起了别名git ad
本地工作目录|暂存区|版本库操作 查看文件状态
git status
: 使用git status
命令可以查看当前工作目录和暂存区的状态,了解哪些文件被修改、新增或删除,以及哪些文件已被暂存准备提交。
查看提交历史
git log
可以查看版本库的提交日志
使用--graph
选项可以查看git提交图谱
初始化仓库
git init
: 会将当前的目录初始化化为git仓库,生成一个隐藏文件夹.git
,用于存储与版本控制相关的信息
这里实践一下:
1 2 3 4 5 6 7 8 9 10 11 DopamineNone@DM MINGW64 ~/Projects/git_test $ git init Initialized empty Git repository in C:/Users/DopamineNone/Projects/git_test/.git/ DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git status On branch master No commits yet nothing to commit (create/copy files and use "git add" to track)
可见刚初始化后的仓库什么都没有
添加至暂存区(untracked, modified -> staged)
git add [file]
这个操作的目的是为了将未跟踪或已修改状态的文件推至暂存区中
可以用git add .
将仓库中所有 未跟踪或已修改状态的文件推至暂存区
实践一下:
1. 创建一个新文件file1.txt,查看状态(untracked)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ touch file1.txtDopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git status On branch master No commits yet Untracked files: (use "git add <file>..." to include in what will be committed) file1.txt nothing added to commit but untracked files present (use "git add" to track)
将file1.txt推送至暂存区,查看状态(staged,这里提示词为changes to be committed,即将要提交的变化); 状态变化:untracked -> staged
1 2 3 4 5 6 7 8 9 10 11 12 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git add file1.txt DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git status On branch master No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: file1.txt
修改file1.txt,查看状态(modified);这里to be committed的是暂存区中file1.txt的快照;状态变化:staged -> modified
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ echo "hello git" > file1.txtDopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git status On branch master No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: file1.txt Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: file1.txt
将file1.txt添加至暂存区,查看状态(staged); 状态变化(modifed -> staged);状态变化:modified -> staged
1 2 3 4 5 6 7 8 9 10 11 12 13 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git add file1.txt warning: in the working copy of 'file1.txt', LF will be replaced by CRLF the next time Git touches it DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git status On branch master No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: file1.txt
提交暂存区文件(staged -> unmodified) git commit -m "message"
提交暂存区内容至版本库
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git commit -m "init project" [master (root-commit) 1384bf0] init project 1 file changed, 1 insertion(+) create mode 100644 file1.txt DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git status On branch master nothing to commit, working tree clean DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git log commit 1384bf0b39111d1f33ffb501f609d0c88797f422 (HEAD -> master) Author: DopamineNone <c20160419raytheon@163.com> Date: Wed Jan 8 13:39:46 2025 +0800 init project
查看不同区域/分支的差异
git diff
可以显示不同区域/分支中的内容差异,包括
查看工作目录与暂存区的差异 1 2 3 4 5 6 7 8 9 10 11 12 13 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ echo "hello world" > file1.txtDopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff file1.txt warning: in the working copy of 'file1.txt', LF will be replaced by CRLF the next time Git touches it diff --git a/file1.txt b/file1.txt index 8d0e412..3b18e51 100644 --- a/file1.txt +++ b/file1.txt @@ -1 +1 @@ -hello git +hello world
查看暂存区与版本库的差异 需要加上选项--staged
或--cached
1 2 3 4 5 6 7 8 9 10 11 12 13 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git add file1.txt warning: in the working copy of 'file1.txt', LF will be replaced by CRLF the next time Git touches it DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff --staged file1.txt diff --git a/file1.txt b/file1.txt index 8d0e412..3b18e51 100644 --- a/file1.txt +++ b/file1.txt @@ -1 +1 @@ -hello git +hello world
查看不同提交版本间的差异 git diff <commit1> <commit2>
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 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git commit -m "replace git by world" [master 407586a] replace git by world 1 file changed, 1 insertion(+), 1 deletion(-) DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git log commit 407586abfd0b5a0239e63dc582abbd5d752edaa0 (HEAD -> master) Author: DopamineNone <xxx> Date: Thu Jan 9 21:05:26 2025 +0800 replace git by world commit 1384bf0b39111d1f33ffb501f609d0c88797f422 Author: DopamineNone <xxx> Date: Wed Jan 8 13:39:46 2025 +0800 init project DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff 407586abfd0b5a0239e63dc582abbd5d752edaa0 1384bf0b39111d1f33ffb501f609d0c88797f422 diff --git a/file1.txt b/file1.txt index 3b18e51..8d0e412 100644 --- a/file1.txt +++ b/file1.txt @@ -1 +1 @@ -hello world +hello git
查看两个分支之间的差异 git diff <branch1> <branch2>
,暂不做演示
撤销工作目录的修改(modified -> unmodified | staged) 这里撤销的只是还没提交至暂存区中的修改
将file1.txt的内容清空,查看状态(modified)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ echo "" > file1.txtDopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git status On branch master No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: file1.txt Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) modified: file1.txt
使用git restore <file>
命令撤回修改
1 2 3 4 5 6 7 8 9 10 11 12 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git restore file1.txt DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git status On branch master No commits yet Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: file1.txt
撤销暂存区的修改 这里分两种情况:
仅将暂存区中文件内容恢复至最近的提交版本,但不修改工作区的文件内容
将暂存区和工作区中的文件内容恢复至最近的提交中
仅撤销暂存区的修改 使用git reset <file>
或git restore --staged <file>
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 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ echo "" > file1.txtDopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git add file1.txt warning: in the working copy of 'file1.txt', LF will be replaced by CRLF the next time Git touches it DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff --staged file1.txt diff --git a/file1.txt b/file1.txt index 3b18e51..8b13789 100644 --- a/file1.txt +++ b/file1.txt @@ -1 +1 @@ -hello world + DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git reset file1.txt Unstaged changes after reset: M file1.txt DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff --staged file1.txt DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff file1.txt warning: in the working copy of 'file1.txt', LF will be replaced by CRLF the next time Git touches it diff --git a/file1.txt b/file1.txt index 3b18e51..8b13789 100644 --- a/file1.txt +++ b/file1.txt @@ -1 +1 @@ -hello world +
撤销工作目录和暂存区的修改 使用git checkout HEAD <file>
命令
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 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git add file1.txt warning: in the working copy of 'file1.txt', LF will be replaced by CRLF the next time Git touches it DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff file1.txt DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff --staged file1.txt diff --git a/file1.txt b/file1.txt index 3b18e51..8b13789 100644 --- a/file1.txt +++ b/file1.txt @@ -1 +1 @@ -hello world + DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git checkout HEAD file1.txt Updated 1 path from 8242445 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff --staged file1.txt DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff file1.txt
撤销提交记录 撤销提交可以由两种git命令实现: git reset
和git revert
,但两者的效果不同
git reset [option] <commit>
分为三种情况:
仅将目标版本之后commit移出,不改变暂存区和工作目录的内容
将目标版本之后commit移出,恢复暂存区内容为当前版本,但不改变工作目录内容
将版本库、暂存区、工作目录的内容恢复至目标提交版本。
而git revert <commit>
表示,提交一个与目标commit的效果相反的commit,从而实现仅撤回某一版本的变化的效果(例如:commit1为在之前版本上新增了func1,那么git revert commit1作用为提交一个删除了func1的commit),撤回的影响包括版本库,暂存区和工作目录
仅撤销版本库提交 使用git reset --soft <commit>
表示撤回到哪个提交记录,如果仅撤回最近的一次提交,可以使用git reset --soft HEAD~1
, HEAD指向本分支最新的提交,~1表示HEAD的前一次提交
下面将git记录回溯至“hello git”
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 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git log commit 407586abfd0b5a0239e63dc582abbd5d752edaa0 (HEAD -> master) Author: DopamineNone <xxx> Date: Thu Jan 9 21:05:26 2025 +0800 replace git by world commit 1384bf0b39111d1f33ffb501f609d0c88797f422 Author: DopamineNone <xxx> Date: Wed Jan 8 13:39:46 2025 +0800 init project DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git reset --soft HEAD~1 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff --staged file1.txt diff --git a/file1.txt b/file1.txt index 8d0e412..3b18e51 100644 --- a/file1.txt +++ b/file1.txt @@ -1 +1 @@ -hello git +hello world
仅撤销版本库提交和恢复暂存区 使用git reset <commit>
即可,等同于git reset --mixed <commit>
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 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git commit -m "replace git by world 2" [master b166262] replace git by world 2 1 file changed, 1 insertion(+), 1 deletion(-) DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git log commit b166262647db5d50e1ea59f644f59845f6fc002b (HEAD -> master) Author: DopamineNone <xxx> Date: Thu Jan 9 21:34:08 2025 +0800 replace git by world 2 commit 1384bf0b39111d1f33ffb501f609d0c88797f422 Author: DopamineNone <xxx> Date: Wed Jan 8 13:39:46 2025 +0800 init project DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git reset HEAD~1 Unstaged changes after reset: M file1.txt DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff --staged file1.txt DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff file1.txt diff --git a/file1.txt b/file1.txt index 8d0e412..3b18e51 100644 --- a/file1.txt +++ b/file1.txt @@ -1 +1 @@ -hello git +hello world
撤销所有区域的变化至上个提交 使用git reset --hard <commit>
,下例中工作区的内容最后也被回溯至”hello git”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git add file1.txt DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git commit -m "replace git by world 3" [master e2f0737] replace git by world 3 1 file changed, 1 insertion(+), 1 deletion(-) DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git reset --hard HEAD~1 HEAD is now at 1384bf0 init project DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git diff file1.txt DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ cat file1.txthello git
仅撤回某一版本的变化 通过git revert <commit1>
实现,如:
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 47 DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ echo " world" >> file1.txtDopamineNone@DM MINGW64 ~/Projects/git_test (master) $ cat file1.txthello git world DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git add file1.txt warning: in the working copy of 'file1.txt', LF will be replaced by CRLF the next time Git touches it DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git commit -m "add world" [master bc2c3ea] add world 1 file changed, 1 insertion(+) DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git revert HEAD [master a52db43] Revert "add world" 1 file changed, 1 deletion(-) DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ git log commit a52db43677856b9e37e880308c3581bdb53f34eb (HEAD -> master) Author: DopamineNone <xxx> Date: Thu Jan 9 22:38:33 2025 +0800 Revert "add world" This reverts commit bc2c3ea660eea6c38d5d3c8ca03f51935a1028ec. commit bc2c3ea660eea6c38d5d3c8ca03f51935a1028ec Author: DopamineNone <xxx> Date: Thu Jan 9 22:33:29 2025 +0800 add world commit 1384bf0b39111d1f33ffb501f609d0c88797f422 Author: DopamineNone <xxx> Date: Wed Jan 8 13:39:46 2025 +0800 init project DopamineNone@DM MINGW64 ~/Projects/git_test (master) $ cat file1.txthello git
git reset 和 git revert的区别:
git reset的作用是撤回至先前的某个版本,而git revert是通过提交一个相反的commit,仅“撤回”某个版本的变化
当撤回一个公共分支(多人合作使用的分支)的某个commit时,用于公共分支的commit只增不减(若删除了公共分支的commit,会导致与其他人的本地分支产生冲突),因此这时候使用git revert最稳妥;但如果时个人分支(即该分支不会被他人直接引用),可以使用git reset 配合 git push -f实现提交撤回,并使日志更加简洁
更多git基本使用方法请见Git 基本用法(2)