gpt4 book ai didi

git - 使用GIT部署代码- checkout vs重置-难吗?

转载 作者:行者123 更新时间:2023-12-02 06:22:59 25 4
gpt4 key购买 nike

我需要确保服务器上我的python部署位置之一始终与远程分支同步,并删除服务器上的所有更改。选项1和选项2有什么区别?首选哪一个?我打算及时运行此命令,以确保服务器代码与远程同步。

选项1:

git clean -f -x
git fetch --all
git reset --hard origin/master

选项2:
git clean -f -x
git fetch --all
git checkout --force origin/master

最佳答案

为了正确理解差异,让我们从以下定义开始:

  • 一个Git存储库包含提交,这些提交是带有关联元数据的某些目录文件树(一棵树)的快照,通常包括一个父提交(但允许任何数量的父提交ID)。这些提交由丑陋的哈希ID,deadc0defeedbeefac0ffee...等标识。因为这些大的丑陋的哈希ID大,丑陋且看似随机,所以我们使用名称(主要是分支名和标记名)来跟踪它们。

    存储在存储库中的文件具有仅对Git本身有用的形式。普通命令无法读取它们。 (Git只能写这些存储的对象,并且它们只有一次写入的形式:一旦写完,就永远不能更改。这对所有四种Git对象都是如此,但分支名称却不应该更改。 :每次向分支添加新提交时,存储在分支名称下的哈希ID都会更改。)
  • 每个存储库也都有一个索引。索引(请注意,有一个特殊的,独特的“the”索引)是构建您打算进行的下一个提交的位置。它开始匹配一些现有的提交。索引具有多个角色,包括使Git快速运行(其缓存角色),以及处理合并和安排下一次提交(其暂存区角色)。但是它开始匹配一些现有的提交。

    索引本质上是一个扁平的树,因此它就像以特定方式提交的内容一样。与内部Git对象一样,它的形式仅对Git有用。
  • 大多数存储库还具有(单个,不同的)工作树,您可以在其中对文件进行工作。像索引一样,树开始匹配一些提交。由于这些文件是普通文件,计算机的其余部分可以处理,但是它们可以被写入和读取,也可以添加新文件或删除文件。

    如果在工作树中更改文件,并且要提交新版本,则必须将文件从工作树复制到索引中。这就是git add的作用:它将文件复制到索引中,或者替换现有文件(如果文件的路径名以前在其中)或存储一个全新的文件(如果路径名是新文件)。

    同样,要从索引中删除文件,必须运行git rm。默认情况下,这会同时从索引和工作树中删除该文件(但是您可以告诉它不理会工作树的版本)。
  • 存储库always1具有一个当前提交。这称为HEAD提交。 .git/HEAD(它是.git目录中的一个普通文件)的真正工作方式是通常只包含当前分支名称。实际的提交ID存储在分支名称下。但是,Git具有所谓的“分离式HEAD”模式,其中HEAD包含哈希ID。对于git checkoutgit reset来说,这一切都很快。

  • 因此,存在一个当前提交,通常来自当前的分支名称,再加上一个分支名称实际上只是一种查找名称到ID映射以查找提交的方式。我们称它为 HEAD,它的缩写为:“嘿,Git,去阅读 .git/HEAD,找到当前的分支名称,并使用它来查找当前的提交。或者,如果我处于分离式HEAD模式,请像以前一样阅读 .git/HEAD,但请注意,它具有一个哈希ID,然后是当前提交。”

    现在,您在此处查看的两个不同的命令是 git resetgit checkout。这些目标有很大不同:
  • git reset(主要是2)是关于以某种方式更改当前分支名称的名称到ID的映射,还可以选择更改索引,甚至更改以下三个:当前提交,索引和工作树。 。
  • git checkout(主要是)通过将新的分支名称写入HEAD或“分离” HEAD,来更改哪个分支是当前分支:将提交哈希ID写入HEAD。在此过程中,git checkout将同时更改索引和工作树。

  • 这是使事情变得复杂的地方。 :-)因为您使用的是 --hard,所以 git reset将更新索引和工作树。所以现在听起来更像是 git checkout,并且在某些方面更是如此。但是有几个关键的区别:
  • 使用git reset更改将提交当前分支指向。使用git checkout可以更改当前的提交。

    记住,我们在上面说过,像masterdevelop这样的名称是让Git记住大的丑陋哈希ID的方式。效果是这些名称的行为就像标签一样,粘贴或指向特定的提交。 git reset命令使您可以移动标签:更改其指向的位置;将其从一个特定的提交剥离并粘贴到另一个。相比之下,git checkout不会移动标签。而是更改哪个分支名称存储在.git/HEAD中。您可以使用git checkout master切换到分支master,然后使用git checkout develop切换到分支develop。标签保留在原处,但是Git更改了存储在.git/HEAD中的名称。

    在正常情况下,当您处于“分支机构”时,所有这些都适用。如果您处于“分离的HEAD”情况,git reset仍会将分离的HEAD从一个提交移至另一个提交,但是由于不涉及分支名称,因此不会更改任何现有的分支名称。同样,如果您用git checkout表示的不是分支名称,则git checkout通过将原始提交ID写入.git/HEAD来“分离您的HEAD”。

    请注意,git reset永远不会分离HEAD,也永远不会重新连接HEAD。那是git checkout所做的。同时,git checkout永远不会更改任何分支标签,但是git reset不会更改。
  • git checkout命令尝试无损(无论如何在这种模式下;请再次参见脚注2)。 git reset命令愉快地破坏了未保存的工作。

    实际上,这意味着如果您对索引和/或工作树进行了更改,git checkout不会覆盖它们。这变得特别复杂,因为如果可能的话,它将切换分支或提交。这样做是通过将未保存的工作保留在索引和/或工作树中的位置(如果可以)。如果不能,则只会出错。

    相比之下,git reset --hard将丢弃这些未保存的更改:--hard意味着覆盖索引和工作树。

  • 在评论中,您添加了:

    I want to ignore any commits that anyone might have made on the server (even though that is unlikely)



    但是“忽略”与“丢弃”不同,并且这些都不能解决对索引和/或工作树所做的未提交的更改。

    通常,使用这样的集中式服务器的正确做法是设置一个没有工作树的设备,即一个 --bare存储库。没有工作树的存储库无法在其中完成任何工作。首先,没有什么可以保存,可以忽略或可以丢弃的。如果使用此方法,所有这些区别将消失。那是你最好的选择。

    即使您不能或不会使用 --bare信息库,我们也要看看其余的项目。除了上述所有注意事项之外,请记住,一个集中存储库-有人 git push首先向其提交新提交-仍然有一个当前(HEAD)提交,如果未分离,则将其命名为当前分支。它还有一个索引,即使不是裸露的,也有一个工作树。 Git通常会拒绝推送到工作树的当前分支:请参阅 the receive.denyCurrentBranch documentation中的 git config。由于裸存储库没有工作树,因此对于裸存储库,这个特定的Git问题也消失了。

    (不过,您的描述听起来像您已将此设置设置为不是其他人直接推送到的中央服务器,而是作为另一台服务器的客户端,在该服务器上您在客户端上使用 git fetch。如果是这种情况,请注意以下几项成为非问题。)

    因此,假设您有一个带有工作树的非裸仓库。为了使推送成功,您可能需要使用分离的HEAD,否则Git将拒绝推送到当前分支。 (较新的Git可以接受它们,但是您必须非常小心地使用它;有关详细信息,请参见链接的文档。)分离的HEAD将为您提供当前提交而没有当前分支,并且会使 git resetgit checkout与之相比更接近表亲。你在树枝上。

    (它还破坏了客户端在克隆中央存储库时看到的功能:客户端将 checkout 服务器上当前存在的任何分支,即,客户端询问服务器“您的HEAD分支是什么?”并自动将其 checkout 。此功能具有一些可疑的价值,因此您可能不会错过它,但是值得注意。)

    如果使用的是分离式HEAD,则 git reset --hard origin/mastergit checkout origin/master之间的主要区别是未提交的索引和/或工作树修改发生了什么。使用 git reset --hard,它们将被清除,而不会发出警告。在服务器上积极工作的任何人都将是 SOL。索引和工作树将被重置以匹配新提交。

    如果您没有使用分离的HEAD, git reset --hard origin/master会将 origin/master的提交ID写入当前分支名称。和以前一样, git reset也将更新索引和工作树。通过将分支标签从旧提交上剥离并粘贴到新提交上,这不仅清除了 Activity 的工作,而且还丢弃了在当前分支上进行的提交。

    使用 git checkout,这也有点复杂。由于 origin/master是所谓的远程跟踪分支,因此 check out 此名称将为您提供一个分离的HEAD,并将提交哈希直接存储在 .git/HEAD中。不管是否已连接或分离HEAD,这都是正确的。因此,如果 checkout 成功,现在 HEAD是分离的。如果索引和工作树中没有未提交的更改,则 check out 应该成功。如果存在未提交的更改,则 check out 将在可能的情况下将它们带到新的分离的HEAD上,如果在不清除未提交的工作的情况下无法切换到该提交,则结帐失败。

    因此,如果您选择沿此路径前进,那么这些就是您的选择。由于Git是一个大型工具集,而不是一个单独的 jar 装解决方案,因此如果可以,则可以选择其他一些路径。

    (请注意 git clean -f -x将删除未跟踪和忽略的文件,即索引中未包含的内容。但是,如果没有 -d,则不会删除未跟踪的目录。)

    1“始终是当前提交”规则有一个例外,该规则主要用于完全没有提交的新的空存储库。除非您在空的存储库中工作,否则将不会遇到此异常,或者使用 git checkout --orphan创建一个新的但未出生的分支(如Git所称)。

    2 git resetgit checkout都有其他用法,它们的主要功能可能有所不同。我在这里仅描述其主要功能。

    3A git checkout仍然可能由于例如磁盘空间不足而失败。

    关于git - 使用GIT部署代码- checkout vs重置-难吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42569205/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com