此为历史版本和 IPFS 入口查阅区,回到作品页
芸枫时
IPFS 指纹 这是什么

作品指纹

「Git 101」非程序员的版本控制

芸枫时
·

如何使用该文章

我们将超出基础的内容放在单独的部分,只对基础知识感兴趣的人来说,不要太分散注意力。 您可以自行决定是否要查看它们:

「了解更多」框包含一般附加信息:

了解更多 此类部分包含超出基础知识的内容,你可能会感觉有些挑战。

「底层细节」详细阐述了底层的技术细节:

底层细节:对于(未来)Git 专家

这里讨论了 Git 底层是如何实现,然而,你绝对不需要 Git 底层的知识,不过,您将在整个过程中遇到 Git 命令无法理解时,看看这里可能会有思路。

如果您是使用本机(即不是基于Windows Subsystem for Linux (WSL))安装 Git 的 Windows 用户,请密切注意所谓的「Windows 特殊情况」中的特别说明:

Windows 特殊情况:仅适用于 Windows 用户

某些文件系统,文件编码问题可能会影响 Git 在 Windows 上的行为。 如有必要,这里提供了问题的解决方法、解释,或者至少对这些不便表示歉意。

创建 Git repo

Git 是一个 DVCS (分布式版本控制系统),这里我们先不看这么奇怪的名词解释,首先要知道的就是版本控制。

我们的目标是通过一个简单的、现实生活中的示例来了解版本控制,能够让非程序员也能使用版本控制来管理文件。

假设您要做一个工作汇报,当你的领导确定最终使用的工作汇报前,你可能存储很多工作汇报。然后你的老板可能会说:还是使用第一个版本吧。这时候可能你的文件变成了这样。

哦不,哪个是新的文件

如果您不使用 Git,您可能会尝试将文件用相同的规则来命名,来跟踪汇报的顺序(例如 My work report 09/09、My work report 09/10、My work report 09/11 0000、My work report 09/11 0100)等来构建自己的版本时间线。

每次您选择另存为并在文件夹中创建一个具有不同名称的新文档时,您都会在版本时间线中创建一个可以返回的快照(snapshots)。 例如,My-work-report 09-11-0100.docx 可以被视为下面的快照。

能不能更好

Git 模仿这个过程,并沿着明确的时间线组织您定义的快照,以便您可以按正确的顺序保留文档的不同版本并返回到以前的版本。

通过 Git 管理会是比复制更加安全,清晰并且占用空间可能会更小。

首先我们按照 datalad handbook 安装 Git。

然后我们进行初始配置。此操作只需执行一次。 在下面的例子中,用你自己的名字替换 Example Users,并且使用您自己的电子邮件地址替换 users@example.com

# 通过输入 ~ 来进入你的主目录。
cd  ~
git  config  --global  --add  user.name  "Example Users"
git  config  --global  --add  user.email  users@example.com

Windows 特殊情况:Unix-like 目录

Windows 中没有 ~ 目录,但 git config --global 不会因目录更改而变化。

此信息用于跟踪您在的 Git 项目中做了什么。 根据此信息,您所做的更改将被关联到您的姓名和电子邮件地址。不用担心,您不会收到来自 Git 的任何电子邮件。

现在,我们可以创建一个 git repo,只需要在你想要的位置输入。可选选项包含在 [ ]

git init [<directory>]

了解更多:git initdirectory 选项是什么?

可选的 directory 选项允许在非当前位置创建 git repo,例如

git init ./directory

这将在当前目录下的 directory 目录创建 git repo。

了解更多:命令

与 shell 的交互采用命令的形式,即向计算机发送基于文本的指令。 命令区分大小写并遵循以下语法:

command [options...] <arguments...>

关于更多可以查看 datalad handbook

开始吧:

git init Git-Learn

这将在当前目录下的 Git-Learn 目录创建 git repo。

创建后,Git repo 看起来就像文件系统上的任何其它目录一样。 目前,它似乎是空的。

$ cd Git-Learn
$ ls # ls 没有任何输出,因为 Git repo 是空的。

Windows 特殊情况:Unix-like 命令

Windows 中没有 ls 命令,作为替代,Windows 使用 dir。

了解更多:神秘的 .git 文件夹

如果你的文件浏览器没有隐藏文件,或者你使用 ls -a 你可能会看到。

$ ls  -a  # show also hidden files
.
..
.git

你可能会好奇这个 .git 文件是从哪里来的,这个 .git 文件是所有 Git 魔法发挥作用所必需的。 请不要修改它们,更重要的是,不要删除它们。
当然如果你如果想让当前目录不被 Git 管理,那么你可以删除它。

但是,您存储在 Git repo 中的所有文件和目录都可以被跟踪(如果您希望它们被跟踪)。

跟踪意味着对文件所做的编辑会自动与相关的更改,编辑的作者,以及变化的时间关联。 这本身就已经很重要了,例如,寻找文件的出处。但特别有用的是文件或目录的之前版本可以恢复。 这些信息存储在我们所说的 Git repo 的历史中。

$ git log
commit 20f3824...sha1 (HEAD -> master)
Author: Example Users <users@example.com>
Date:   Sun Jan 01 00:00:30 2023 +0000

    feats: add files

commit f112277...sha1
Author: Example Users <users@example.com>
Date:   Sun Jan 01 00:00:00 2023 +0000

    init: init commit

这段历史在当前状态下几乎是最小的,但让我们看一下。 为了查看历史记录,代码示例将使用 git log手册),您可以使用箭头键上下滚动,但如果不能输入任何命令,您可以按 q 退出 git log

恭喜,您刚刚创建了第一个 Git Repo! 现在让我们在里面添加一些内容。

在 Git repo 中增加一些内容

以之前我们说的,工作汇报来演示。你在 Git repo 中创建了一个新的工作汇报文件。

touch My-Work-Report.txt
echo "first line" > My-Work-Report.txt

当然你也可以使用你喜欢的文件管理器和编辑器来修改文件。

这时我们运行 git log,会发现 fatal: your current branch 'master' does not have any commits yet,如果你没有提交(commit)的话 Git 是不会记录你的更改到版本历史中的,这里的错误是因为我们甚至没有提交一次,如果你想看到我们当前目录和 Git 中的区别,可以使用 git status

$ git status

On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    My-Work-Report.txt
nothing added to commit but untracked files present (use "git add" to track)

它告诉了我们下一步要做什么,那么让我们立即使用 git add

git add My-Work-Report.txt

让我们再次使用 git status

$ git status

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
    new file:   My-Work-Report.txt

现在让我们立即提交一次。

git commit

这将打开你的编辑器,修改标题保存退出后就会提交。

另外,你也可以在 commit 命令后添加 -m 选项,将提交信息与命令放在同一行。

$ git commit -m "init: add My-Work-Report"
[master (root-commit) f212277] init: add My-Work-Report
  1 file changed, 1 insertion(+)
  create mode 100644 My-Work-Report.txt

这时我们运行 git log,就会发现我们的文件已经在 Git repo 历史中了。

$ git log
commit f212277...sha1 (HEAD -> master)
Author: Example Users <users@example.com>
Date:   Sun Jan 01 00:00:00 2023 +0000

    init: add My-Work-Report

恭喜,你已经成功在 Git repo 中增加了文件,修改文件并且跟踪版本和上面是一样的,首先打开你最喜欢的编辑器修改文件。

echo "good report" >> My-Work-Report.txt

git add 并且提交它。

$ git add My-Work-Report.txt
$ git commit -m "feats: good report for My-Work-Report"

[master 21f3824] feats: good report for My-Work-Report
  1 file changed, 2 insertions(+), 1 deletion(-)

这时我们再运行 git log,就会发现我们已经有了两个 Git repo 历史记录。

$ git log
commit 21f3824...sha1 (HEAD -> master)
Author: Example Users <users@example.com>
Date:   Sun Jan 01 00:00:30 2023 +0000

    feats: good report for My-Work-Report

commit f212277...sha1
Author: Example Users <users@example.com>
Date:   Sun Jan 01 00:00:00 2023 +0000

    init: add My-Work-Report

这时,如果你的老板不认为你的第二版是个好报告的话,你可能会问我该如何将第一版取出,让我们使用 git restore

git restore [--source=<tree>] <pathspec>…​

这里的 source 是我们上面 git log 看到的 sha1 编码,所以我们只需要运行。

git restore --source=f212277 My-Work-Report.txt

这个时候我们再查看 My-Work-Report.txt 中的文件,就已经变为第一版的时候了。

$ cat My-Work-Report.txt
first line

幸好,你的老板没否认你的辛苦努力,所以让我们把这个文件变回第二版。

git restore My-Work-Report.txt

当我们不给 source 参数时,它始终将我们的文件变为最新提交的文件上(git log 看到的最新一条)。

了解更多:HEAD 的位置

其实这个命令是将文件变为 HEAD 指向的提交位置,但由于我们始终没有自己更改过 HEAD,它就会在我们当前分支最新的提交上。
当我们的合并(merge)遇到冲突时,以及手动 git reset 时,才会更改 HEAD 的位置。

了解更多:恢复 git add 的更改

有时你错误 git add 了一个文件,或者你根本不想提交这个更改,这时我们也可以用 git restore 来取消更改。

git restore [--source=<tree>] [--staged] [--worktree] <pathspec>…​

这里我们通过指定 staged 参数来要求 git restore 恢复 git add 中的更改,也就是 stage 中。
如果我们不指定 source,默认是更改变成 HEAD 中的版本。
如果我们不指定 staged 参数,默认是 worktree 参数,就是恢复我们在文件夹中的更改,也就是 working directory 中。

了解更多:工作目录、暂存区域以及 Git 仓库

我们这里提到了工作目录(working directory)、暂存区域(staging area)以及 Git 仓库(Git directory)。这是基于 Git 的三种状态,你的文件可能处于其中之一:已提交(committed)、已修改(modified) 和已暂存(staged)。

  • 已修改表示修改了文件,但还没保存到数据库中。就是你编辑后的文件。

  • 已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。就是 git add 后的文件。

  • 已提交表示数据已经安全地保存在本地数据库中。就是 git commit 后的文件。

这会让我们的 Git 项目拥有三个阶段:工作区、暂存区以及 Git 目录。

基本的 Git 工作流程如下:

  1. 在工作区(working directory)中修改文件。

  2. 将你想要下次提交的更改选择性地暂存(git add),这样只会将更改的部分添加到暂存区(staging area)。

  3. 提交(commit)更新,找到暂存区的文件,将快照永久性存储到 Git 目录(Git directory)。

你可能会觉得这样很复杂,但这样我们可以选择性地提交(commit)文件,比如我们可以第一次将 My-Work-Report.txt 加入 Git repo 中,第二次将 Boss-Work-Report.txt 加入 Git repo 中。但我们的工作区(working directory)在第一次提交(commit)后仍然存在 Boss-Work-Report.txt。

了解更多:git resetgit restore

你可能看到过有些地方(甚至 Git 也会推荐你)使用 git reset,它们的功能你可能会觉得有些相似。
是的,它们在某些方面有些重合,但 git reset 显得更加底层,需要你了解 HEAD 的工作方式,并且了解 softmixedhard 这几种参数分别修改了什么。
但对比 git restore,它使用了更加明确的参数,stagedworktree,让你明白当前在修改什么。
此外,git restore 比较新,Git 手册会提示你这个命令是试验性的,其行为可能会改变

好了,你已经了解如何在 Git repo 中增加,修改文件和恢复文件的版本了。

可能你会觉得这种版本控制其实其它软件也能做到,是的,如果你使用 Windows 的文件历史,macOS 的 Time machine,或者是网络储存的版本历史,你可能会觉得非常熟悉,但 Git 与它们所不同的是,它是一个多分支的版本管理系统,并且不需要服务器。

相关链接

CC BY-NC-ND 4.0 授权