且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

git如何在不同分支中保持配置文件不同?

更新时间:2022-12-05 22:30:55

在Git中无法执行此操作的原因是Git与分支无关. 1

The reason you can't do this in Git is that Git isn't about branches.1

好,不能太强了:如问题所示,您可以手动进行操作.但是,您是正确的,在.gitattributes中使用合并驱动程序将不起作用.原因是当您执行运行git merge时,Git:

OK, can't is too strong: as you've shown in your question, you can do it manually. You're correct, though, that using a merge driver in .gitattributes won't work. The reason is that when you do run git merge, Git:

  • 计算合并基础;
  • 将基础中的配置文件与每个分支提示中的一个进行比较;和
  • 如果文件仅在一个分支提示提交中有所不同,请使用该文件的分支提示提交版本.
  • computes the merge base;
  • compares the config file in the base against the one each branch-tip; and
  • if the file is different in only one branch-tip commit, uses that branch-tip-commit version of the file.

如果您可以手动选择文件的合并基础版本,则可以避免三个输入文件中的两个匹配的情况,但是您不能这样做.

If you could pick the merge base version of the file manually, you could avoid situations in which two out of the three input files match, but you can't do that.

那么,您可以做什么 ?有几种类型的选项:

So, what can you do? There are several classes of options:

  • 结帐后脚本;
  • 过滤器驱动程序;
  • Git本身之外的东西.

过滤器驱动程序的想法很吸引人,但它有一个可怕的缺陷:它在之前运行 Git告诉您提供给git checkoutgit switch命令哪个分支名称.

The filter driver idea is attractive, but it has a terrible flaw: it runs before Git tells you which branch name was supplied to the git checkout or git switch command.

结帐后脚本方法 可以工作.但是,它确实导致了第三种方法:根本不要在Git中执行此操作.原因是您不想修改跟踪文件(位于Git索引/暂存区中的文件),该文件以后会引起各种操作上的麻烦.

The post-checkout script method can work. However, it really leads to the third method: don't do it in Git at all. The reason is that you don't want to modify a tracked file (one that is in Git's index / staging-area), which produces all kinds of operational headaches later.

第三个方法是真正有效的方法. 使用未跟踪和忽略的文件,或完全不在Git存储库或启动指令之外的文件来保存配置.允许此文件或启动指令用于 include 其他如果愿意,可以 在Git中的文件,和/或从Git中的 文件构建此文件.如果有用的话,请让您的软件从Git中维护的文件中读取默认值.但是将实际配置保留在其他位置.

The third method is the one that really works. Use a file that is untracked and ignored, or is entirely outside the Git repository, or a startup directive, to hold the configuration. Allow this file or startup directive to include other files that are in Git, if you like, and/or build this file from files that are in Git. Have your software read defaults from files that are maintained in Git, if that's useful. But keep the actual configuration elsewhere.

现在,配置不在Git存储库中,您可以让Git管理存储库中 内的文件,而不会让Git破坏配置.

Now that the configuration is outside the Git repository, you can have Git manage the files that are in the repository, without having Git damage the configuration.

1 更准确地说,Git 是关于提交的.提交保留文件,但是Git与文件无关.分支 names 拥有提交哈希ID,但是Git也与分支名称无关.我们在这里关心的Git操作(签出和合并),即在提交的基础上进行的工作,以及真实名称"提交的内容是其哈希ID.许多提交一次位于多个分支上,而某些提交有时根本不在任何分支上.在存在没有分支名称的提交的情况下,分支名称不能作为提交存在的基础.由于某些提交是多个分支的提示,并且提交内的存储文件是只读的,因此文件实际上不依赖于分支名称.分支名称可以更改,名称可以四处移动.提交后,这些提交将永久固定在适当的位置.

1More precisely, Git is about commits. Commits hold files, but Git isn't about the files; branch names hold commit hash IDs, but Git isn't about the branch names either. The Git operations we care about here—checkout and merge, that is—work on a commit basis, and the "true name" of a commit is its hash ID. Many commits are on many branches all at once, and some commits are sometimes on no branch at all. With commits existing without branch names, a branch name cannot be the basis for the existence of a commit. With some commits being the tip of multiple branches, and the stored files inside a commit being read-only, the files literally cannot depend on the branch name. Branch names can be changed, and the names can be moved around. The commits, once made, are fixed in place forever.

最后,这里只是一个根本的不匹配.如果您认为Git是关于 commits (而不是分支或文件)的提交持有文件的提交,那么一切都会正常.如果您认为Git与分支有关,那么某些部分就不合适了.

In the end, there's just a fundamental mismatch here. If you think about Git as being about commits—rather than branches or files—with commits holding files, everything all works. If you think about Git as being about branches, some parts just don't fit.