Git 版本控制完全指南:从入门到精通
作为当今最流行的分布式版本控制系统,Git 已经成为开发者必备的技能之一。无论你是独立开发者还是团队协作,Git 都能帮助你高效管理代码版本。本文将带你从零开始,逐步掌握 Git 的核心概念和常用操作。
Git 初始化与配置
git init
这个简单的命令会在当前目录创建一个新的 Git 仓库。Git 仓库是 Git 用来跟踪和管理项目变更的核心机制。执行后,你会看到一个隐藏的 .git 文件夹,它包含了 Git 所需的所有仓库数据。
git config user.name "sin"
git config user.email "123456@qq.com"
这些配置命令非常重要,因为它们设置了提交代码时的作者信息。Git 会将这些信息附加到你的每一次提交上,这样其他人就能知道是谁做了哪些修改。
查看配置项:
git config -l
这个命令会列出所有 Git 配置,包括用户信息、别名设置等。当需要检查或调试配置问题时非常有用。
删除配置
git config -unset user.email
如果你需要删除某个特定的配置项,可以使用这个命令。注意,如果该配置是在全局设置的,你需要使用相同的范围来删除它。
一台服务器可以创建多个本地仓库,加了global相当于配置在全局都生效。
git config --global user,name "sin"
全局配置(--global
)会将设置应用于当前用户的所有仓库,而本地配置(不加--global
)只影响当前仓库。这在多项目开发中特别有用。
是用global创建的想要重置需要同样是用global关键字。
我们可以进入.get文件:
[sin@VM-4-8-centos gitcode]$ cd .git
[sin@VM-4-8-centos .git]$ tree ./
./
|-- branches
|-- config
|-- description
|-- HEAD
|-- hooks
| |-- applypatch-msg.sample
| |-- commit-msg.sample
| |-- post-update.sample
| |-- pre-applypatch.sample
| |-- pre-commit.sample
| |-- prepare-commit-msg.sample
| |-- pre-push.sample
| |-- pre-rebase.sample
| -- update.sample
|-- info
| -- exclude
|-- objects
| |-- info
| -- pack
-- refs|-- heads-- tags
.git 目录是 Git 仓库的核心,包含了所有版本控制所需的数据。其中:
objects
目录存储所有数据内容refs
目录存储指向分支和标签的指针HEAD
文件指向当前所在的分支config
文件包含仓库特定的配置选项
不能再.git文件中手动修改任何内容。手动修改可能会导致仓库损坏,应该始终使用 Git 命令来操作。
Git 基本工作流程
这张图清晰地展示了 Git 的三个主要区域:工作区、暂存区(Stage/Index)和版本库(Repository)。理解这三个区域的关系对掌握 Git 至关重要。
git add file.txt
git add
命令将工作区的修改添加到暂存区。暂存区就像一个准备区,让你可以精心挑选哪些修改要包含在下一次提交中。
git commit file.txt -m"本次提交的细节"
git commit
命令将暂存区的修改永久保存到版本库中。提交信息(-m
参数)应该清晰描述这次提交的目的,这对日后回溯历史非常有帮助。
git log
git log
显示项目的提交历史,包括每次提交的作者、日期和提交信息。这是了解项目演变过程的主要方式。
Git 对象模型
[root@VM-4-8-centos gitstudy]# tree .git
.git
|-- branches
|-- COMMIT\_EDITMSG
|-- config
|-- description
|-- HEAD
|-- hooks
| |-- applypatch-msg.sample
| |-- commit-msg.sample
| |-- post-update.sample
| |-- pre-applypatch.sample
| |-- pre-commit.sample
| |-- prepare-commit-msg.sample
| |-- pre-push.sample
| |-- pre-rebase.sample
| -- update.sample
|-- index
|-- info
| -- exclude
|-- logs
| |-- HEAD
| -- refs
| -- heads
| -- master
|-- objects
| |-- 2f
| | -- 96a52bce7a059aab3577e7e9b8499df7aa46dc
| |-- 9c
| | -- 7b41e1c03f5499d21419108d6ef57d0bec1da4
| |-- ec
| | -- 8c05d08dbd2166e7550d64239cd997a35e396c
| |-- info
| -- pack
-- refs|-- heads| -- master-- tags
Git 的核心是一个内容寻址文件系统,这意味着它存储的是文件内容的哈希值而非文件名。每次提交都会创建一个新的对象存储在 objects 目录中。
[root@VM-4-8-centos gitstudy]# cat .git/refs/heads/master
ec8c05d08dbd2166e7550d64239cd997a35e396c
master 分支实际上只是一个指向特定提交对象的指针。这种设计使得分支创建和切换非常高效。
git cat-file -p ec8c05d08dbd2166e7550d64239cd997a35e396c
git cat-file
命令可以查看 Git 对象的内容。这是深入了解 Git 内部工作原理的强大工具。
[root@VM-4-8-centos gitstudy]# git cat-file -p ec8c05d08dbd2166e7550d64239cd997a35e396c
tree 9c7b41e1c03f5499d21419108d6ef57d0bec1da4
author sin <123456@sin.com> 1747633828 +0800
committer sin <123456@sin.com> 1747633828 +0800Init and test
这个提交对象包含了指向树对象(tree)的指针、作者信息、提交者信息和提交消息。树对象则包含了项目目录结构和文件指针。
git追踪管理的不是文件,是修改。这意味着 Git 关注的是内容的变化,而不是文件本身。这种设计使得 Git 能够高效地处理文件重命名、移动等操作。
查看状态与差异
git status
git status
是日常使用最频繁的命令之一。它会告诉你:
- 哪些文件被修改但未暂存
- 哪些文件已暂存准备提交
- 当前所在的分支
- 与远程分支的关系
[root@VM-4-8-centos gitstudy]# touch file1
[root@VM-4-8-centos gitstudy]# ls
file1 readme
[root@VM-4-8-centos gitstudy]# git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# file1
nothing added to commit but untracked files present (use "git add" to track)
这个输出显示我们创建了一个新文件 file1,但它目前处于"未跟踪"状态,意味着 Git 还没有开始跟踪它的变化。
使用git diff,可以查看文件的修改:
[root@VM-4-8-centos gitstudy]# git diff readme
diff --git a/readme b/readme
index 2f96a52..f633a22 100644
--- a/readme
+++ b/readme
@@ -1 +1,2 @@sdsadsad
+nihao
git diff
显示工作区与暂存区之间的差异。这个输出显示我们在 readme 文件中添加了一行"nihao"。
版本回退
git reset [--soft | --mixed | --hard] [HEAD]
版本回退是 Git 的强大功能之一,但需要谨慎使用。三种模式的区别:
--soft
: 只移动 HEAD 指针,不改变暂存区和工作区--mixed
(默认): 移动 HEAD 指针并重置暂存区,但不改变工作区--hard
: 彻底回退,移动 HEAD 指针、重置暂存区和工作区
要慎用hard,防止一次回退导致代码消失。使用 --hard
前,确保你已经保存或提交了所有重要更改。
回退一次之后,如何ID没有被清楚,还是有后悔药可以吃的(撤回回退)
使用git reflog可以查看回退操作。git reflog
记录了 HEAD 的所有变化,即使是被"丢失"的提交也能在这里找到。
撤销修改
如果在工作区中,可以使用下面的代码进行撤销修改:
- 手动修改
- Git checkout – [filename]
git checkout -- <file>
会丢弃工作区中指定文件的所有修改,将其恢复到最近一次提交或暂存的状态。
如果代码同时在工作区与暂存区,需要使用git reset进行版本回退。这种情况下,你需要先取消暂存(git reset HEAD <file>
),然后再撤销工作区的修改。
删除文件
Git提供删除命令,可以同时删除工作区与暂存区。
git rm
git rm
不仅会从工作目录中删除文件,还会将这次删除操作记录到暂存区。这与直接删除文件后运行 git add
效果相同。
分支管理
分支是 Git 最强大的功能之一。Head可以指向其他分支,被指向的分支是当前工作的分支。
创建分支:
git branch dev
分支在 Git 中非常轻量级 - 它们只是指向特定提交的指针。创建新分支不会复制任何文件,只是创建一个新的指针。
切换分支:
git checkout dev
切换分支会更新工作目录中的文件以匹配该分支指向的提交。如果工作区有未提交的修改,Git 会阻止切换以避免数据丢失。
查看当前分支:
git branch
不带参数的 git branch
会列出所有本地分支,并在当前分支前标记星号。
合并操作:
在转到master分支上后运行下面的代码,即可将dev分支合并到master分支上。
git merge dev
合并将另一个分支的修改整合到当前分支。Git 会尝试自动合并,如果遇到冲突,需要手动解决。
删除本地分支:
git branch -d dev
删除分支前,确保它的所有修改都已经合并到其他分支。如果分支未合并,Git 会拒绝删除,除非使用 -D
强制删除。
git中如果两个分支产生冲突,会在生成的项目中显示出来,之后由开发人员手动修复冲突。冲突标记格式为:
<<<<<<< HEAD
当前分支的内容
=======
要合并的分支的内容
>>>>>>> branch-name
在手动合并之后,需要进行一次提交操作。这个提交就是合并提交,记录了冲突解决的结果。
在git中,可以将提交过程展示为可视的图:
git log --graph --abbrev-commit
--graph
选项会绘制 ASCII 图形展示分支和合并历史,--abbrev-commit
显示缩写的提交哈希,使输出更简洁。
分支管理策略
FastForward模式下面,并不能看出来这次的提交是正常提交还是通过merge的提交。当合并的分支是当前分支的直接祖先时,Git 默认会使用"快进"(fast-forward)合并,即简单移动分支指针而不创建合并提交。要强制创建合并提交,可以使用 --no-ff
选项。
远程仓库操作
从本地将代码上传到远程仓库:
git push
git push
将本地分支的提交上传到远程仓库。第一次推送时需要使用 -u
选项设置上游分支。
将远程仓库拉去到本地:
git fetch
git fetch
从远程仓库下载所有数据,但不会自动合并到工作分支。这让你可以在合并前先检查变化。
git pull origin master:master
git pull
实际上是 git fetch
和 git merge
的组合操作。它会从远程仓库获取最新更改并尝试合并到当前分支。
如果远端和本地的名称一样的话也可以使用下面的缩写版:
git pull origin master
Git 别名
git除了可以配置name和email,也可以为命令起别名:
git config --global alias.lpa 'log --pretty=oneline --abbrev-commit'
别名可以显著提高工作效率。例如,上面的命令创建了一个 lpa
别名,可以显示简洁的提交历史。
标签管理
可以对一次commit进行标签的标识。标签通常用于标记发布版本(v1.0, v2.0等)。
使用下面的命令,可以默认为最新的提交打一个标签:
git tag v1.0
标签分为轻量标签(只是一个指向特定提交的指针)和附注标签(包含打标签者信息、日期和消息)。要创建附注标签,使用 -a
选项。
使用下面的命令可以查看现在有哪些标签存在:
git tag
在标签命令之后也可以进行评论。使用 -m
选项可以为标签添加注释,这对发布说明特别有用。
可以用下面的代码删除标签:
git tag -d v1.0
标签默认只在本地创建,要共享标签到远程仓库,需要显式推送(git push origin v1.0
)。
总结
Git 是一个功能强大且灵活的工具,掌握它可以显著提高你的开发效率。建议从基础命令开始练习,逐步熟悉更高级的功能。记住:
- 频繁提交,保持提交的原子性
- 编写有意义的提交信息
- 合理使用分支进行功能开发
- 定期与远程仓库同步
随着经验的积累,你会越来越欣赏 Git 的设计哲学和强大能力。