Git 版本控制完全指南:从入门到精通

Git 版本控制完全指南:从入门到精通

作为当今最流行的分布式版本控制系统,Git 已经成为开发者必备的技能之一。无论你是独立开发者还是团队协作,Git 都能帮助你高效管理代码版本。本文将带你从零开始,逐步掌握 Git 的核心概念和常用操作。

Git 初始化与配置

Bash 复制代码
git init

这个简单的命令会在当前目录创建一个新的 Git 仓库。Git 仓库是 Git 用来跟踪和管理项目变更的核心机制。执行后,你会看到一个隐藏的 .git 文件夹,它包含了 Git 所需的所有仓库数据。

Bash 复制代码
git config user.name "sin"
git config user.email "123456@qq.com"

这些配置命令非常重要,因为它们设置了提交代码时的作者信息。Git 会将这些信息附加到你的每一次提交上,这样其他人就能知道是谁做了哪些修改。

查看配置项:

Bash 复制代码
git config -l

这个命令会列出所有 Git 配置,包括用户信息、别名设置等。当需要检查或调试配置问题时非常有用。

删除配置

Bash 复制代码
git config -unset user.email

如果你需要删除某个特定的配置项,可以使用这个命令。注意,如果该配置是在全局设置的,你需要使用相同的范围来删除它。

一台服务器可以创建多个本地仓库,加了global相当于配置在全局都生效。

Bash 复制代码
git config --global user,name "sin"

全局配置(--global)会将设置应用于当前用户的所有仓库,而本地配置(不加--global)只影响当前仓库。这在多项目开发中特别有用。

是用global创建的想要重置需要同样是用global关键字。

我们可以进入.get文件:

Bash 复制代码
[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 至关重要。

JavaScript 复制代码
git add file.txt

git add 命令将工作区的修改添加到暂存区。暂存区就像一个准备区,让你可以精心挑选哪些修改要包含在下一次提交中。

JavaScript 复制代码
git commit file.txt -m"本次提交的细节"

git commit 命令将暂存区的修改永久保存到版本库中。提交信息(-m参数)应该清晰描述这次提交的目的,这对日后回溯历史非常有帮助。

JavaScript 复制代码
git log

git log 显示项目的提交历史,包括每次提交的作者、日期和提交信息。这是了解项目演变过程的主要方式。

Git 对象模型

SQL 复制代码
[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 目录中。

JavaScript 复制代码
[root@VM-4-8-centos gitstudy]# cat .git/refs/heads/master
ec8c05d08dbd2166e7550d64239cd997a35e396c

master 分支实际上只是一个指向特定提交对象的指针。这种设计使得分支创建和切换非常高效。

JavaScript 复制代码
git cat-file -p ec8c05d08dbd2166e7550d64239cd997a35e396c

git cat-file 命令可以查看 Git 对象的内容。这是深入了解 Git 内部工作原理的强大工具。

JavaScript 复制代码
[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 +0800

Init and test

这个提交对象包含了指向树对象(tree)的指针、作者信息、提交者信息和提交消息。树对象则包含了项目目录结构和文件指针。

git追踪管理的不是文件,是修改。这意味着 Git 关注的是内容的变化,而不是文件本身。这种设计使得 Git 能够高效地处理文件重命名、移动等操作。

查看状态与差异

JavaScript 复制代码
git status

git status 是日常使用最频繁的命令之一。它会告诉你:

  • 哪些文件被修改但未暂存
  • 哪些文件已暂存准备提交
  • 当前所在的分支
  • 与远程分支的关系
Python 复制代码
[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,可以查看文件的修改:

Python 复制代码
[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"。

版本回退

Python 复制代码
git reset [--soft | --mixed | --hard] [HEAD]

版本回退是 Git 的强大功能之一,但需要谨慎使用。三种模式的区别:

  • --soft: 只移动 HEAD 指针,不改变暂存区和工作区
  • --mixed(默认): 移动 HEAD 指针并重置暂存区,但不改变工作区
  • --hard: 彻底回退,移动 HEAD 指针、重置暂存区和工作区

要慎用hard,防止一次回退导致代码消失。使用 --hard 前,确保你已经保存或提交了所有重要更改。

回退一次之后,如何ID没有被清楚,还是有后悔药可以吃的(撤回回退)

使用git reflog可以查看回退操作。git reflog 记录了 HEAD 的所有变化,即使是被"丢失"的提交也能在这里找到。

撤销修改

如果在工作区中,可以使用下面的代码进行撤销修改:

  1. 手动修改
  2. Git checkout -- [filename]

git checkout -- <file> 会丢弃工作区中指定文件的所有修改,将其恢复到最近一次提交或暂存的状态。

如果代码同时在工作区与暂存区,需要使用git reset进行版本回退。这种情况下,你需要先取消暂存(git reset HEAD <file>),然后再撤销工作区的修改。

删除文件

Git提供删除命令,可以同时删除工作区与暂存区。

Python 复制代码
git rm

git rm 不仅会从工作目录中删除文件,还会将这次删除操作记录到暂存区。这与直接删除文件后运行 git add 效果相同。

分支管理

分支是 Git 最强大的功能之一。Head可以指向其他分支,被指向的分支是当前工作的分支。

创建分支:

Python 复制代码
git branch dev

分支在 Git 中非常轻量级 - 它们只是指向特定提交的指针。创建新分支不会复制任何文件,只是创建一个新的指针。

切换分支:

Python 复制代码
git checkout dev

切换分支会更新工作目录中的文件以匹配该分支指向的提交。如果工作区有未提交的修改,Git 会阻止切换以避免数据丢失。

查看当前分支:

Python 复制代码
git branch

不带参数的 git branch 会列出所有本地分支,并在当前分支前标记星号。

合并操作:

在转到master分支上后运行下面的代码,即可将dev分支合并到master分支上。

Python 复制代码
git merge dev

合并将另一个分支的修改整合到当前分支。Git 会尝试自动合并,如果遇到冲突,需要手动解决。

删除本地分支:

Python 复制代码
git branch -d dev

删除分支前,确保它的所有修改都已经合并到其他分支。如果分支未合并,Git 会拒绝删除,除非使用 -D 强制删除。

git中如果两个分支产生冲突,会在生成的项目中显示出来,之后由开发人员手动修复冲突。冲突标记格式为:

复制代码
<<<<<<< HEAD
当前分支的内容
=======
要合并的分支的内容
>>>>>>> branch-name

在手动合并之后,需要进行一次提交操作。这个提交就是合并提交,记录了冲突解决的结果。

在git中,可以将提交过程展示为可视的图:

Python 复制代码
git log --graph --abbrev-commit

--graph 选项会绘制 ASCII 图形展示分支和合并历史,--abbrev-commit 显示缩写的提交哈希,使输出更简洁。

分支管理策略

FastForward模式下面,并不能看出来这次的提交是正常提交还是通过merge的提交。当合并的分支是当前分支的直接祖先时,Git 默认会使用"快进"(fast-forward)合并,即简单移动分支指针而不创建合并提交。要强制创建合并提交,可以使用 --no-ff 选项。

远程仓库操作

从本地将代码上传到远程仓库:

Python 复制代码
git push

git push 将本地分支的提交上传到远程仓库。第一次推送时需要使用 -u 选项设置上游分支。

将远程仓库拉去到本地:

Python 复制代码
git fetch

git fetch 从远程仓库下载所有数据,但不会自动合并到工作分支。这让你可以在合并前先检查变化。

Python 复制代码
git pull origin master:master

git pull 实际上是 git fetchgit merge 的组合操作。它会从远程仓库获取最新更改并尝试合并到当前分支。

如果远端和本地的名称一样的话也可以使用下面的缩写版:

Python 复制代码
git pull origin master

Git 别名

git除了可以配置name和email,也可以为命令起别名:

Python 复制代码
git config --global alias.lpa 'log --pretty=oneline --abbrev-commit'

别名可以显著提高工作效率。例如,上面的命令创建了一个 lpa 别名,可以显示简洁的提交历史。

标签管理

可以对一次commit进行标签的标识。标签通常用于标记发布版本(v1.0, v2.0等)。

使用下面的命令,可以默认为最新的提交打一个标签:

Python 复制代码
git tag v1.0

标签分为轻量标签(只是一个指向特定提交的指针)和附注标签(包含打标签者信息、日期和消息)。要创建附注标签,使用 -a 选项。

使用下面的命令可以查看现在有哪些标签存在:

Python 复制代码
git tag

在标签命令之后也可以进行评论。使用 -m 选项可以为标签添加注释,这对发布说明特别有用。

可以用下面的代码删除标签:

Python 复制代码
git tag -d v1.0

标签默认只在本地创建,要共享标签到远程仓库,需要显式推送(git push origin v1.0)。

总结

Git 是一个功能强大且灵活的工具,掌握它可以显著提高你的开发效率。建议从基础命令开始练习,逐步熟悉更高级的功能。记住:

  • 频繁提交,保持提交的原子性
  • 编写有意义的提交信息
  • 合理使用分支进行功能开发
  • 定期与远程仓库同步

随着经验的积累,你会越来越欣赏 Git 的设计哲学和强大能力。

相关推荐
tan180°3 小时前
MySQL表的操作(3)
linux·数据库·c++·vscode·后端·mysql
优创学社24 小时前
基于springboot的社区生鲜团购系统
java·spring boot·后端
why技术4 小时前
Stack Overflow,轰然倒下!
前端·人工智能·后端
幽络源小助理4 小时前
SpringBoot基于Mysql的商业辅助决策系统设计与实现
java·vue.js·spring boot·后端·mysql·spring
ai小鬼头5 小时前
AIStarter如何助力用户与创作者?Stable Diffusion一键管理教程!
后端·架构·github
简佐义的博客5 小时前
破解非模式物种GO/KEGG注释难题
开发语言·数据库·后端·oracle·golang
Code blocks6 小时前
使用Jenkins完成springboot项目快速更新
java·运维·spring boot·后端·jenkins
追逐时光者6 小时前
一款开源免费、通用的 WPF 主题控件包
后端·.net