git 仓库中 Composer 包冲突;如何在推送到远程时取消跟踪文件但避免删除文件

2024-03-09

我通过 Composer 在我的 Web 应用程序上安装了一个包。 并将包文件夹添加到 .gitignore,同时提交composer.json and composer.lock

为了部署到我们的服务器,我们推送到服务器上的裸 Git 远程服务器,该远程服务器又将修改后的文件推送到服务器上的相关位置。

这个工作流程一切正常。

后来,处理该存储库的其他人将包文件添加到存储库中,并从 gitignore 中删除了该包。

我们希望包版本完全由 Composer 管理,而不是像以前那样由 git 存储库管理。

到目前为止我唯一的想法是执行以下操作:

  1. 从存储库中删除文件并将包文件夹添加回 gitignore。提交这个。
  2. 推送到远程(这显然会推送删除的文件)
  3. run composer update推送后,请快速在服务器上重新安装已删除的软件包。

但这里的问题是这个will从服务器上删除该包几秒钟,我们希望尽可能避免这种情况,因为它是网站上的核心插件。我们不想造成某些东西损坏。

有什么办法可以删除包裹文件夹的跟踪,同时推送提交时不会导致从远程删除包?

我读过关于assume-unchanged and skip-worktree here (Git - “假设不变”和“跳过工作树”之间的区别 https://stackoverflow.com/questions/13630849/git-difference-between-assume-unchanged-and-skip-worktree/13631525#13631525),但我不确定使用哪个以及这些命令中的任何一个将在遥控器上产生什么效果(如果有)?


有什么办法可以删除包裹文件夹的跟踪,同时推送提交时不会导致从远程删除包?

No.

幸运的是,您可能不需要这样做。

不幸的是,无论你在这里做什么,使用起来都会有些丑陋和痛苦。

我已经阅读过有关假设不变和跳过工作树的内容...但我不确定使用哪个以及这些命令中的任何一个将在远程上产生什么效果(如果有)?

两者都可以,但是--skip-worktree是你应该在这里使用的那个。两者都不会对任何其他 Git 存储库产生任何影响。


要理解所有这些,您需要一个关于 Git 实际功能的正确模型。

首先记住,Git 中的基本存储单位是commit。每个提交都有一个唯一的、又大又难看的哈希 ID,例如083378cc35c4dbcc607e4cdd24a5fca440163d17。该哈希 ID 是提交的“真实名称”。各地的每个 Git 存储库都同意that哈希 ID 保留用于that提交,即使有问题的 Git 存储库没有have尚未提交。 (这就是 Git 中所有真正魔力的来源:这些看似随机但实际上完全不是随机的哈希 ID 的唯一性。)

提交存储的内容分为两部分:data,其中包含所有文件的快照;加上metadata,其中 Git 存储信息,例如谁进行了提交、何时(日期和时间戳)以及原因(日志消息)。作为元数据的重要部分,每次提交还存储一些数据集previous提交哈希 ID,作为文本中的原始哈希 ID。这让 Git 从任何给定的提交开始,向后,到之前的一些提交。

任何 Git 提交的实际哈希 ID 只是其所有数据的校验和。 (从技术上讲,它只是元数据的校验和,因为快照本身存储为一个单独的 Git 对象,其哈希 ID 进入提交对象。但是,这个单独对象的哈希 ID 也是一个校验和,因此通过数学计算默克尔树 https://en.wikipedia.org/wiki/Merkle_tree,一切顺利。)这是why提交中的所有内容都是完全只读的,并且永远冻结。如果您尝试更改提交中的任何内容,实际上您并没有change提交。相反,你会得到一个new提交,并使用新的不同的哈希 ID。旧的提交仍然存在,其哈希 ID 未更改。

所以:Git 就是关于提交的,Git 通过哈希 ID 查找提交。但我们人类无法处理哈希 ID(快说,这是 08337 之类的东西还是 03887 之类的东西?)。我们希望有names, like master。同时,Git 希望有一种快速的方法来找到last在某些提交链中进行提交,并在某个时刻结束。所以 Git 为我们提供了名字,让我们可以创建分支机构名称.

分支名称仅保存分支的哈希 IDlast在某个链中提交。该承诺成立,因为它parent, 的哈希 IDprevious在链中提交。父提交作为其父项(我们最后一次提交的祖父母)保存了向前一步提交的哈希 ID,依此类推:

... <-F <-G <-H   <-- master

如果提交哈希 ID 是单个字母,例如H,这可能是一个准确的绘图:名字master将保存哈希IDH, 犯罪H将保存哈希IDG作为其父级,提交G将保存哈希IDF作为其父级,依此类推。

制作一个的行为new提交包括:

  • 写出所有文件的快照;和
  • 添加适当的元数据:您作为作者和提交者,“现在”作为日期和时间戳,等等。这parent这个新提交的内容应该是currentcommit 是,记录在当前分支名称中。如果master指着H然后是新提交的父提交——我们称之为I-将H, 以便I points back toH`.

实际进行此提交(并在此过程中找到其哈希 ID)后,Git 只需写入新的哈希 IDI进入分支名称master:

... <-F <-G <-H <-I   <-- master

我们有一个新的承诺。

看什么happened在提交中,例如I, Git 将提交(其所有文件)提取到临时区域,然后提取先前的提交H的文件到临时区域,并比较它们。对于那些相同的东西,Git 没有说什么。对于那些不同的,Git 显示了差异。对于那些新的,Git 说它们是“添加”的,对于那些在上一次提交中但不在本次提交中的,git 说它们是“删除”。

现在,做一个git checkout某些特定提交的意思是写入该提交的content—即,以您可以使用的形式输出数据。提交内永久冻结的文件副本采用仅限 Git 的格式,这对于存档来说很好,但对于完成新工作毫无用处。因此,Git 必须将提交提取到工作区,您可以在其中查看和使用文件。 Git 将此工作区称为您的工作树 or 工作树(或这些名称的某些变体)。除了当你要求时将文件写入其中之外,Git 基本上不干涉这个工作区域:那就是your游乐场,而不是 Git 的。

但是新提交中的新快照来自哪里?在某些版本控制系统中,新快照来自工作树中的文件。这是notGit 中的情况。相反,Git 从 Git 中的任何内容进行新的提交index。你不能see这些文件(至少不容易),但是当 Git 第一次提取某些提交时,它会有效地将所有该提交的已保存、冻结文件复制到 Git 的索引中。只有当它们进入索引后,Git 才会将它们复制(并解冻/重新水化)到您的工作树中,以便您可以使用它们。

The crucial difference between the frozen copies in a commit, and the "soft-frozen" copies in the index, is that you can overwrite the index copy.1 You can't overwrite the committed copy, but that's OK: commits cannot be changed, but you can make new and better commits, and that's what version control is about anyway.

每当你跑步时git commit,Git 在第一步(制作快照)中所做的就是简单地打包所有预冻结的文件index每个文件的副本。所以我们可以将索引视为提议的下一次提交。这也是为什么你必须git add文件始终存在,即使它们已经在上一次提交中。什么git add正在做的是copying工作树文件位于该文件索引中的任何内容之上(尽管再次参见脚注 1 了解技术细节)。

这意味着什么每个文件始终有三个“实时”副本。一个被冻结在当前提交。一种是半冷冻的,在index,Git 也将其称为暂存区。最后一个是你的副本,在你的工作树中,你可以用它做任何你想做的事情:它是一个普通文件,而不是特殊的 Git-only 格式。

当你跑步时git status,Git运行两个单独的比较:

  • First, git status比较当前(HEAD) 提交索引中的所有文件。对于每个文件the same,Git 什么也没说。对于每个文件不同的, Git 说这个文件是暂存以供提交。如果索引中的文件是新的 - 不在HEAD——Git 称之为新的;如果一个文件是gone从索引来看,Git 说它是deleted.

  • Then, git status将索引中的所有文件与工作树中的所有文件进行比较。对于每个文件the same,Git 什么也没说。对于每个文件不同的, Git 说这个文件是未暂存提交。如果工作树中的文件是新的——不在索引中——Git 会抱怨该文件是未追踪的。如果一个文件是goneGit 说它已从工作树中删除。

最后一个案例是在哪里未追踪的文件来自.它还为我们提供了未跟踪的定义:如果工作树中存在的文件不存在于索引中,则该文件未被跟踪。既然我们不能see索引,我们只看到这种情况git status抱怨这些未跟踪的文件。

列出 a 中未跟踪的文件.gitignore文件让 Git 闭嘴:git status不会再发牢骚了这也使得git add not add如果文件尚不存在,则将其添加到索引,但对已存在的文件没有影响are在索引中。如果文件位于索引中,则根据定义,它会被跟踪,并且git add会很高兴地添加它。

终于到了这里--assume-unchanged and --skip-worktree进来。这些是您可以在文件上设置的标志are在索引中。设置任一标志都会告诉 Git:嘿,当您要考虑此文件的工作树副本时……您现在可以跳过它。那是,git add查看索引和工作树,并检查.gitignore文件,查看已跟踪的内容、未跟踪的内容、工作树中较新的内容以及需要在建议的下一次提交中更新的内容,等等。如果某个文件是未追踪的并列于.gitignore, git add会跳过它。如果它是tracked,如果工作树副本不同,Git 会添加它......unless跳过标志已设置。如果--assume-unchanged标志已设置,Git 将assume它没有改变,也没有添加它。如果--skip-worktree标志已设置,Git 知道它绝对不应该添加它,即使文件实际上已更改。

So --skip-worktree这里的意思是我们想要的:don't git add这个文件,即使它被改变了。 The --assume-unchangedflag 也可以工作,因为 Git 假设它没有改变,因此不会git add也可以。今天实际操作没有什么区别,但是“skip worktree”表达的是正确的intent.

请注意,因为这些标志是在index(又名暂存区)文件的副本,它们仅适用于tracked文件。跟踪的文件是索引/暂存区域中的文件。在设置标志之前,文件必须位于索引中。并且,如果该文件位于索引中,那个副本文件的内容(现在位于索引中的文件)就是将位于索引中的文件next你做出的承诺。

但是这个文件的副本是从哪里来的呢?答案就在我们的git checkout早些时候:git checkout将我们选择的提交中的所有文件复制到索引。它得到了into索引,然后进入我们的工作树,通过我们的第一个git checkout。如果从那时起我们就对工作树副本大惊小怪,那么,flag我们设定的意思是git add从未将工作树副本复制回索引副本,因此它仍然与旧提交相同。我们一直在使用old文件的副本,保存在索引中。

让这件事变得令人痛苦的是,如果我们git checkout some other提交,另一个提交有一个不同的当我们获取其中文件的副本时,Git 将希望用我们尝试切换到的提交中的副本替换我们的索引副本。将其复制到索引不会删除我们设置的标志,但它will 覆盖工作树副本。如果我们更改了工作树副本,Git 会在不询问的情况下覆盖它(这可能很糟糕)或说:我无法检查该提交,它将覆盖您的(假设/跳过,但我不会提及)该文件的工作树副本。在实践中,Git 采用后一种方法。

为了解决这个问题,每次你git checkout一个承诺would覆盖您标记的文件,您必须移动或复制您的工作树副本,let git checkout覆盖索引和工作树副本,然后将工作树副本移动或复制回原位。显然,最好从一开始就不要陷入这种情况。

但是,如果你git rm这些文件,某人会发生什么else谁从有文件的提交移动到没有文件的提交?例如,也许您正在推送的遥控器现在已签出该文件,然后他们就会git checkout a new承诺你会做到这一点doesn't有那些文件。当然,他们的 Git 会尽职尽责地从theirGit 的索引,以及来自theirGit 用户的工作树。这就是你不想要的,所以现在你不得不保留their该文件的副本yourGit 的索引,以便它进入您的新提交。

这就是这个复杂的舞蹈的意义所在。每次提交都是一个快照在您的新提交中,您希望快照具有their某些特定文件的副本。所以你必须得到their复制到yourGit 的索引。您可以从某些提交中获取它,并将其复制到索引中。然后你把它固定在适当的位置,在yourGit 的索引/暂存区,即使您不在自己的工作树中使用它。在使用这三个副本时,您保留right复制(这不是您的工作树)到您自己的 Git 索引中。


1Technically, what's in the index is a reference to the frozen copy. Updating the index copy consists of making a new frozen copy, ready for commit, and writing the new reference into the index. These details matter if you start using git update-index directly to put new files in, or use git ls-files --stage to view the index: you'll see Git's internal blob object hash IDs here. But you can just think of the index as holding a full copy of each file, in the internal, frozen format: that mental model works well enough for the level at which you normally work with Git.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

git 仓库中 Composer 包冲突;如何在推送到远程时取消跟踪文件但避免删除文件 的相关文章

  • git push --force-with-lease 总是安全吗?

    我一直遵循的规则是 一旦 git 历史记录被推送到远程存储库 就不再修改它 但我想知道交互式变基到推送 force with lease 是否绕过了这条规则 如果强制租约成功 对其他用户来说是否完全安全 或者此策略有任何注意事项吗 预先感谢
  • 有没有一种干净的方法来处理两个以相同内容开头的原始 git 存储库?

    假设我有两个根据相同的初始内容创建的存储库 例如 如果我使用 git 来管理 etc apache2 中的 apache 配置文件 然后我运行git init分别在机器 A 和机器 B 上 此后 我对 machine b 进行了一些配置更改
  • BitBucket 应用程序密码:git 命令行访问有哪些权限?

    我了解如何为 BitBucket 创建应用程序密码 如中所述Atlassian 的应用程序密码信息 https support atlassian com bitbucket cloud docs app passwords and 这个答
  • 如何在多个不同的分支上工作,以便我可以在它们之间轻松切换?

    有没有办法在 GIT 中处理同一个文件但不同的功能 分支 我确信有办法 但最简单的方法是什么 我不想隐藏我的更改 因为这很麻烦 借助 SVN 我能够将 2 个独立的分支作为 2 个不同的实体进行工作 无需任何干预 并且可以轻松在两者之间切换
  • 如何在 EGit 中创建正确的新本地和远程分支组合?

    我想在 Egit 中执行以下操作 git checkout b newbranch git push u origin newbranch 这给了我一个新的本地分支 将其推送到上游服务器并创建正确的跟踪参考 我如何在 Egit 中做同样的事
  • git Push Remote:警告:hooks.mailinglist 有多个值

    我刚刚从使用 gitosis 升级到 gitolite 电子邮件通知适用于所有存储库 但对于 gitolite admin 存储库 我在推送时收到此警告 推送很好 git push remote warning hooks announce
  • 使用 Homebrew 安装 Git 时出现问题 [重复]

    这个问题在这里已经有答案了 可能的重复 使用 Homebrew 升级 Git 时出现问题 https stackoverflow com questions 12362021 problems upgrading git with home
  • gitlab:带有大型存储库的 git clone https 失败

    当尝试通过 https 克隆大型存储库 700MB 时 git 失败并显示 c git projects gt git clone https git mycompany de fs git Cloning into fs Username
  • Jenkins 多分支:更改 Groovy 的工作描述

    我在詹金斯的多分支项目工作正常 但我想修改job描述 默认情况下为 完整项目名称 xxxx 以更有意义 我可以使用以下命令轻松更改构建描述currentBuild当我的变量Jenkinfile已执行 但我不知道如何修改父作业描述 我的用例是
  • 如何仅对最新合并后的提交进行变基?

    考虑以下场景 我从master那里检查了一个分支 我做了一些承诺 我合并了更新的master 我做了更多的承诺 现在我想要从第 4 点开始变基提交 以便从第 2 点开始的提交不受影响 所以如果我最初有 1 2 x x x x x x x m
  • Xcode - 使用 SSH 身份验证添加存储库时出现身份验证失败错误

    我正在尝试通过 Xcode gt 设置 gt 帐户添加存储库 但我被困在正确的地址上 我们的存储库地址非常简单 my domain com port project name 通过 SSH 密钥进行身份验证 有人可以帮助我了解这里发生了什么
  • 将各种提交合并为一而不合并

    是否可以加入各种提交 这是我的情况 我的应用程序在 OSX 10 6 和 10 7 中运行 我已经修复了 10 6 的一些内容 然后提交了 更改为 10 7 并再次修复修复程序 以便它们兼容 然后再次提交 然后返回到 10 6 并再次检查并
  • libgit2 返回:Refspec 'refs/heads/origin/HEAD' 在 TortoiseGit 中未找到错误

    启动 TortoiseGit 时出现此错误 无法获取所有参考文献 libgit2 返回 未找到 Refspec refs heads origin HEAD 虽然很烦人 但这并不妨碍我使用 TortoiseGit 然而 我想让它消失 因为它
  • 包括来自raw.github.com的js

    我有一个 github com 演示页面 链接到https raw github com master file js https raw github com master file js这样我就不需要总是复制 js文件转移到gh pag
  • 为什么我使用某些 git 命令后终端变得无响应?

    我经常 真的每次 使用该命令后git log我的终端对进一步的输入没有响应 这是在 OSX 上 是否有一个我不知道的命令将使终端再次激活 而不是仅仅退出终端并重新开始 您正在使用一个无需滚动即可显示日志的程序 很可能less 可以通过按q
  • 无法使用 Git Bash 对 Visual Studio Team Services 进行身份验证

    由于身份验证失败 我无法对 Visual Studio Team Services VSTS 上的远程存储库运行任何命令 我可以通过 Visual Studio 进行拉取等操作 但只能通过 Visual Studio 不通过 Git Bas
  • 中止 `git stash apply` [重复]

    这个问题在这里已经有答案了 我很遗憾应用了存储 错误的分支 我如何撤消此操作并将我的存储返回到我的存储列表 以便稍后将其应用到正确的分支 如果你还没有承诺 你应该能够git stash再次 可能与git reset HEAD first A
  • 禁止 Gerrit 推送到 refs/for/master

    我已经更新了所有项目昨天获得访问权限 人们说他们今天早上无法将更改推送到存储库 当我恢复访问权限后 他们仍然无法将更改推送到存储库 只能clone工作正常 在将更改推送到远程存储库时 它表示 remote rejected HEAD gt
  • 在 Windows 上从源代码构建 PhantomJS-2

    我正在尝试基于这些在 Windows 8 1 x64 上从源代码构建 PhantomJS 2 的开发版本指示 https github com ariya phantomjs wiki PhantomJS 2 但是我收到以下错误 mingw
  • 使用 Git 部署时压缩 JS/CSS 文件

    我对 git 有点陌生 另外 这是我第一个自动化部署过程的项目 到目前为止 能够做到这一点真是太幸福了git push dev并上传文件 复制配置文件等 现在 当我推送到我的开发服务器时 我想缩小 JS CSS 文件 我正在考虑在服务器上安

随机推荐