为什么需要版本管理?
工作中,经常遇到以下情况:文案、PPT、文档、方案或者设计图在最终敲定前,需要进行多次修改,可能是某处细节的优化,也可能是内容的替换等,这里通常两种做法。第一种做法,是在原来的基础上进行修改,其弊端显而易见:只保留了最新版本的内容,之前的更改无从查起。如果最终敲定的结果是以前的某一个版本,那么就意味着需要再一次回忆之前的工作,进行重复性劳作。第二种做法,是创建一个副本,在副本中进行修改,这样就可以保留历史的版本,方便后续查阅。然而这种做法的弊端是,改动较为频繁时,创建过多的副本,占据过多内存的同时,后续无法准确的找出具体某个改动对应的副本。
而对于程序员来说,工作中改动最为频繁的就是他们的代码。上述两种做法对于代码管理来说,都是非常耗时耗力的做法。为此,需要亟需版本管理的工具。本系列将介绍最为主流的版本控制器之一 —— Git 。
Git 的基本介绍
Git 是开源的代码托管工具,能够帮助开发者管理代码版本,支持跨平台使用:Linux、Unix、Mac 以及 Windows
Git 能做什么?
版本管理:记录下程序员的每次修改以及将所有历史版本存档,支持⾃由进⾏版本回退、撤销、修改等操作
分支管理:在各个开发场景下,可以灵活地创建、切换、合并、删除分支
多人协同开发:Git 为分布式版本控制系统,是多人协同开发模式的前提
注意:相较于二进制文件,如图片、视频、音乐等,Git 更适用于文本文件
Git 的基本操作
Git 的安装
Windows
Linux 环境
由于没有 Linux 的服务器,使用了 wsl 在 windows 上进行操作,详情见链接:安装 WSL | Microsoft Learn
ubantu 版本
创建本地仓库
christy@Christy:~$ git --version
git version 2.43.0
christy@Christy:~$ mkdir gittest
christy@Christy:~$ cd gittest
christy@Christy:~/gittest$ mkdir gitcode
christy@Christy:~/gittest$ cd gitcode
christy@Christy:~/gittest/gitcode$ git init // 创建本地仓库
Initialized empty Git repository in /home/christy/gittest/gitcode/.git/
.git 是个隐藏文件,不要对其随便修改,可用 tree 命令看其树状目录。
// 可用以下命令安装 tree 指令:
christy@Christy:~/gittest/gitcode$ sudo snap install tree
2025-01-04T20:44:12+08:00 INFO Waiting for automatic snapd restart...
tree 2.1.3+pkg-5852 from 林博仁(Buo-ren Lin) (brlin) installed // 问:有没有哪位同行知道这个林博仁是谁呀?
christy@Christy:/mnt/c/Users/92002/gitcode$ tree .git/
.git/
├── COMMIT_EDITMSG
├── HEAD
├── config
├── description
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-merge-commit.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ ├── prepare-commit-msg.sample
│ ├── push-to-checkout.sample
│ ├── sendemail-validate.sample
│ └── update.sample
├── index
├── info
│ └── exclude
├── logs
│ ├── HEAD
│ └── refs
│ └── heads
│ └── master
├── objects
│ ├── 0a
│ │ └── 491e47424a52b3a3c00fc11a6e24336b2b5bd9
│ ├── 32
│ │ └── be1898a86d245861660f4786c73dd512733b67
│ ├── 4b
│ │ └── 825dc642cb6eb9a060e54bf8d69288fbee4904
│ ├── 70
│ │ └── ed1e97a765a880e8e9c1d3a856c464ecae857e
│ ├── 8b
│ │ └── 137891791fe96927ad78e64b0aad7bded08bdc
│ ├── b5
│ │ └── a54e59496ce3baa5486ac0042b88b27a829c1b
│ ├── bc
│ │ └── 32919d49f3781668888d95406478a3f149e6a0
│ ├── info
│ └── pack
└── refs
├── heads
│ └── master
└── tags
查看 git 的属性:
christy@Christy:~/gittest/gitcode$ git config -l
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
本地仓库最重要的两个配置 , name 以及 email,如果没有需要自己设置:
ty@Christy:~/gittest/gitcode$ git config [--global] user.name "1234"
christy@Christy:~/gittest/gitcode$ git config [--global] user.email "abc@163.com"
christy@Christy:~/gittest/gitcode$ git config -l
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
user.name=1234
user.email=abc@163.com
其中,可在设置 name 和 email 时,在 git config 后使用 --global,表示对这台机器上所有的 Git 仓库都使用这个配置,相应的删除这两个属性时,命令也需要添加 --global:
christy@Christy:~/gittest/gitcode$ git config [--global] --unset user.name
christy@Christy:~/gittest/gitcode$ git config [--global] --unset user.email
如果你希望在不同仓库中使⽤不同的 name 或 email 就无需使用。注意的是,执⾏命令时必须要在仓库⾥。
工作区 暂存区 版本库
下面介绍一下 git 版本管理中三个重要的概念,分别为工作区、暂存区以及版本库。三者可以用以下的图来表示:
工作区:需要管理的代码或者文件所在的目录,通常与 .git/ 文件并列的所有文件。
暂存区:英⽂叫stage或index。⼀般存放在 .git/ 文件下的 index 目录下(.git/index),所以暂存区有时也叫作索引(index)。
版本库:⼜名仓库,英⽂为 repository 。隐藏文件 .git/ 就是是 Git 版本库。这个版本库⾥⾯的所有⽂件都可以被 Git 管理起来,每个⽂件的修改、删除,Git 都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
当我们在 gitcode 目录下创建新的文件时,就开始使用 git 来“版本管理”了吗?答案是否定的。要想让 git 接管我们的文件,必须经过以下两个步骤,分别是:add 与 commit。通过 add,将变动的内容(修改、新增、删除)从工作区添加到暂存区,通过 commit 将暂存区中修改的内容提交到当前分支中。
git 是如何进行版本管理的呢?add 做了些什么?commit 做了些什么? 要想回答上述问题,就得看一看.git/ 目录下的 objects 这个部分。 每当我们 add 改动的内容时,都会创建成一个 git 对象,存放在 objects 库中。而暂存区(index)以及分支中存储的,则是这一个个对象的索引。
涉及的代码如下:
christy@Christy:/mnt/c/Users/92002/gitcode$ git add readME1.txt
christy@Christy:/mnt/c/Users/92002/gitcode$ git commit -m "my first commit file to local repository!"
[master 6278578] my first commit file to local repository!
1 file changed, 1 insertion(+), 1 deletion(-)
christy@Christy:/mnt/c/Users/92002/gitcode$ git add readME.txt readME2.txt
christy@Christy:/mnt/c/Users/92002/gitcode$ git commit -m "my second commit to local repository!"
[master d5009ff] my second commit to local repository!
1 file changed, 4 insertions(+), 1 deletion(-)
christy@Christy:/mnt/c/Users/92002/gitcode$ git log
commit d5009ff14bd73f1692ab6293341c8edcc97b5697 (HEAD -> master)
Author: @1234 <abc@163.com>
Date: Mon Jan 27 14:25:59 2025 +0800
my second commit to local repository!
commit 6278578bdb430f0248d8893f94224ed5fc123373
Author: @1234 <abc@163.com>
Date: Mon Jan 27 14:23:49 2025 +0800
my first commit file to local repository!
commit b5a54e59496ce3baa5486ac0042b88b27a829c1b
Author: @1234 <abc@163.com>
Date: Wed Jan 1 20:04:55 2025 +0800
my wishes in 2025
工作区 与 .git 并列存放的文件 版本库 打开 .git ,这里是版本库, .git 目录不属于工作区
christy@Christy:/mnt/c/Users/92002/gitcode$ cat .git/HEAD
ref: refs/heads/master
christy@Christy:/mnt/c/Users/92002/gitcode$ cat .git/refs/heads/master
d5009ff14bd73f1692ab6293341c8edcc97b5697
christy@Christy:/mnt/c/Users/92002/gitcode$ git cat-file -p d5009ff14bd73f1692ab6293341c8edcc97b5697
tree 531a944d7d1fe9eec57fb185c03f059cf9b1eb0f
parent 6278578bdb430f0248d8893f94224ed5fc123373
author @1234 <abc@163.com> 1737959159 +0800
committer @1234 <abc@163.com> 1737959159 +0800
my second commit to local repository!
christy@Christy:/mnt/c/Users/92002/gitcode$ git cat-file -p 531a944d7d1fe9eec57fb185c03f059cf9b1eb0f
100644 blob b7246c83a9f7bf13e4c91f1921f7e81c256c0943 readME.txt
100644 blob 4cf9db0031950fc082db6b370964ecbafbdf9a2b readME1.txt
100644 blob 0a491e47424a52b3a3c00fc11a6e24336b2b5bd9 readME2.txt
christy@Christy:/mnt/c/Users/92002/gitcode$ git cat-file -p b7246c83a9f7bf13e4c91f1921f7e81c256c0943
hello, Avatar Forest!
I love you world!
Keep going on!
Let's go!`
christy@Christy:/mnt/c/Users/92002/gitcode$ git cat-file -p 4cf9db0031950fc082db6b370964ecbafbdf9a2b
I will try my best in 2025~
christy@Christy:/mnt/c/Users/92002/gitcode$ git cat-file -p 0a491e47424a52b3a3c00fc11a6e24336b2b5bd9
I'm coming! big money!
christy@Christy:/mnt/c/Users/92002/gitcode$ git diff readME.txt
diff --git a/readME.txt b/readME.txt
index b7246c8..d0a3145 100644
--- a/readME.txt
+++ b/readME.txt
@@ -1,4 +1,5 @@
hello, Avatar Forest!
I love you world!
Keep going on!
-Let's go!`
+Let's go!^M
+WOW~~~How do you do ?^M
christy@Christy:/mnt/c/Users/92002/gitcode$ git status
On branch master
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: readME.txt
no changes added to commit (use "git add" and/or "git commit -a")
christy@Christy:/mnt/c/Users/92002/gitcode$ git add readME.txt
christy@Christy:/mnt/c/Users/92002/gitcode$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: readME.txt
christy@Christy:/mnt/c/Users/92002/gitcode$ git commit -m "commit all"
christy@Christy:/mnt/c/Users/92002/gitcode$ git status
On branch master
nothing to commit, working tree clean