我看过一些教程,以下是我对语句中显示的"提交"命令的理解:
-
由于git使用了整个代码库的"快照"系统,git需要了解更改的历史记录,并向所有在每一时刻都做了什么的程序员展示。
-
"提交"就像记录项目内存中的更改。
-
上传我更改后的项目版本,即我的分支到主要在线回购(master)是另一回事吗?
-
当我将本地更改上传到项目的主版本时,其他人就会知道我的提交(记录在.git文件中)。
-
将更改上传到master分支就是在"推送"我所有的提交,对吧?
我对这些说法正确吗?
- 由于git使用了整个代码库的"快照"系统,git需要了解更改的历史记录,并向所有做了什么的程序员显示在每一个时刻
这是一种合理的表达方式。
- "提交"就像记录项目内存中的更改
是的,提交是在分支顶部添加更改记录(与上次提交相比)。
- 上传我更改后的项目版本,即我的分支到主在线回购(master)是另一回事吗
当推送时,远程服务器会将您的更改附加到远程分支,前提是您的历史记录遵循服务器历史记录。例如,如果有人在推送之前将任何更改附加到服务器历史记录中,则双方都显示了某个点的不同版本的历史记录。因此,您需要首先重写本地历史记录,使其符合服务器的历史记录。(通常使用git pull
,根据您的选择,它将合并或重新建立分支机构的基础)
- 当我将本地更改上传到项目的主版本时,我的提交(记录在.git文件中)会为其他人所知
是的,当你推送时,你会让其他人知道你是如何修改历史的。
- 将更改上传到master分支是在"推送"我所有的提交,对吧
推送是将您的更改"上传"(如果您希望使用该词)到远程的主分支。正如我之前所说,只有在您的更改建立在远程主机上可用的最新历史记录的基础上时,远程才会接受。
请注意,所有这些对于任何分支都是正确的,您可以拥有任意多的分支,而不仅仅是master。
git基本上使用以下三种东西来存储数据:
blob
只是一个二进制的东西(你的源代码、图像等等)。blob不包含有关内容的类型或名称的信息,只是大量字节tree
指向一个或多个Blob,比如"目录"。它包含它所指向的Blob的文件名等commit
(数据对象,而不是git命令)是一个单独的实体,它只指向一棵树(当时所有文件的状态)和零个或多个其他提交(父级,在存储库中的第一次提交时可能会丢失,在合并的情况下可能会有多个)
就是这样。从概念上讲,它没有其他东西。在实践中,有分支和标记,但这些只是指向提交的特殊"便签"。也有一些机制可以减少存储等,但除非你破解代码或深入研究,否则它们不会引起兴趣。
在这种情况下,回答你的问题很容易:
- 当您将提交签入工作目录时,您将从一个特定的
commit
中获取文件。例如,便签(分支)master
指向提交afd876123
,然后将存储库克隆到新的工作目录中,然后获得commit afd876123
指向的tree
中表示的文件 - git当然会跟踪并创建一个特殊的便签
HEAD
,它存储您在master
和提交afd876123
上的信息。它还创建了一个index
,您可以将其视为匿名tree
- 您可以编辑工作目录中的一些文件
- 运行
git add
时,git会使用您的更改更新index
。虽然在内部它的工作方式不同,但您可以将其视为使用您的更改更新tree "index"
- 没有
commit
与这个tree
相关联,所以它不是一个永久的东西;它不会影响推拉或其他什么 - 当您运行
git commit
时,它会创建一个新的commit
对象,该对象指向由当前索引表示的tree
,以及以前提交的afd876123
和其他信息(如时间戳、日志消息…)。然后将该commit
对象添加到数据存储中,并最终确定
关于推/拉的其他假设基本上是正确的。
1)"由于git使用了整个代码库的"快照"系统,git需要了解更改的历史记录,并向所有在每个时刻都做了什么的程序员显示。">
是的,这就是版本控制系统所做的。它们允许你回到上一个时间点的代码状态,并恢复丢失或删除的工作。它们还可以让你看到谁在什么时候做了什么。转到一个版本化的文件,键入git annotate path/to/file
,看看会发生什么。
2) "提交就像记录项目内存中的更改。">
首先(不要试图分析),对文件的更改不会存储在内存中,就像存储在RAM中一样,它们通过文件系统存储在硬盘驱动器的磁盘扇区上。将更改保存到有问题的文件后,您可以考虑将这些更改存储在git中。这包括两个步骤。首先进行更改,然后提交。暂存更改也称为将更改添加到暂存区域或将更改暂存到索引。可以将暂存区或索引视为"正在构建的提交",但还没有准备好。您可以使用git add
将文件添加到暂存区域。您可以看到使用git status
添加了哪些文件。您可以使用git diff --cached
查看分阶段更改的详细信息。当您最终满意地将要提交的所有更改添加到暂存区域时,可以使用git commit
提交您的暂存更改。因此,commit命令完成了"正在构建的commit"。在内部,git数据库中会创建一个新的提交对象,并更新当前分支的分支指针以指向此提交。这种两阶段提交机制为您提供了一道防线,防止意外提交您不想提交的更改。在提交之前,您必须考虑添加到暂存区的所有内容。试着使用git add -p
来对你所展示的内容和没有展示的内容进行非常精细的控制。
3) "上传我更改后的项目版本,即我的分支机构到主要在线回购(主)是另一回事吗?">
是的,这是另一回事。Git更多的是一种对等体系结构,而不是客户端-服务器体系结构。这允许您在不与其他人共享的情况下进行本地提交。它允许你随心所欲地接受别人的工作,并允许你在真正准备好的时候与他们分享你的工作。在git中可以同时跟踪多个上游存储库。也就是说,git有一些类似于客户端-服务器体系结构的东西,但并不相同。git存储库有两种。开发人员用来相互共享代码的裸存储库(类似于客户端-服务器体系结构中的服务器)和开发人员在其工作站上本地工作的非裸存储库。要将代码更改从(非裸)存储库上的分支移动到首次克隆的联机(裸)存储库上的分支,请使用git push
。裸存储库只包含.git
目录的内容,该目录包括提交数据库,但不包含版本控制的文件本身,因此名称为"裸"。它本身不必命名为.git
。惯例是按照my_project.git的思路为其命名,并通过网络提供服务。另一方面,非裸存储库就像您提交的存储库。有一个隐藏的.git
目录,其中包含与git有关的所有内容以及您直接处理的文件。您不能将更改推送到非裸存储库中,这样做可能会严重干扰其他人的工作。
4) 当我将本地更改上传到项目的主版本时,其他人就会知道我的提交(记录在.git文件中)。
这意味着它们现在存储在公共的裸存储库中。只有当其他人选择使用git fetch
获取这些更改时,他们才会知道这些更改。获取这些更改后,他们可以使用git merge
将这些更改合并到相应的本地分支中,或者使用git rebase
在您的更改之上重新建立本地更改的基础。为了在一个步骤中完成这个过程,他们可以使用git pull
。拉取策略(合并或重新基础)由配置选项pull.rebase
确定,由命令git config pull.rebase true
配置。我强烈建议重新定基而不是合并,因为这鼓励线性历史,因为合并提交有两个祖先提交,而重新定基提交只有一个。
5) "将更改上传到主分支是在推送我所有的提交,对吧?">
几乎是对的。git-push命令也可以接受参数,但如果没有这些参数,它将进行合理的默认推断。Git将使用refspecs和上游分支配置来进行这些推断。推送时,您正在将提交从非裸存储库上的分支移动到裸存储库的分支。如果git不能正确地进行这些推断(即,您希望将更改移动到哪个存储库的哪个分支,以及将更改从哪个本地分支移动),则必须将这些参数显式地提供给git-push命令。