`git 结帐分支 -- .`,不覆盖现有文件
`git checkout branch -- .`, without overwriting existing files
上下文
我有一个包含应用程序开发历史的存储库。该应用程序是从其源代码即时编译的,可以在存储库被克隆后立即使用。
该应用程序使用了几个配置文件,这些文件在几个配置原型中被拒绝。为了便于部署,我想将每个原型存储在一个单独的分支上,并在克隆后从master
获取应用程序并从所选分支获取配置。
简单的解决方案是将配置分支建立在 master
的基础上,但这需要在 master
前进时定期将它们全部变基。因此,我正在尝试使用两个单独的 git 历史的解决方案:
master
分支包含应用程序的源代码;
- 所有
config/<archetype>
都来自一个单独的根目录(通过 git checkout --orphan
创建),并且仅包含构建脚本及其各自的配置。
构建脚本现在必须在构建之前从 master
检索所有源代码,注意不要用来自 master
的默认配置文件覆盖原型配置文件。因此...
问题
我需要 git checkout <branch> -- .
的变体 不 触及现有文件,无论它们处于什么状态(已更改、未更改、已忽略、未跟踪...)。
潜在客户
我找到了 this 个确实有答案的相同问题 (git archive mybranch | tar x --skip-old-files
),但是我遇到了一些问题:
- 我在 Windows 上使用 Powershell,它显然提供了一个没有
--skip-old-files
; 的本机 tar
命令
- Git 的
tar
版本接受该标志,但由于我认为 Powershell 管道工作方式的一个怪癖而失败(来自 [= 的相同命令 运行 63=] Bash 作品):
PS> &"C:\Program Files\Git\bin\git.exe" archive master | &"C:\Program Files\Git\usr\bin\tar.exe" x --skip-old-files
/usr/bin/tar: Malformed extended header: missing newline
/usr/bin/tar: Substituting `.' for empty member name
/usr/bin/tar: Substituting `.' for empty member name
/usr/bin/tar: Skipping to next header
/usr/bin/tar: Exiting with failure status due to previous errors
在这种环境下,我更喜欢只使用 Git.
的解决方案
我不确定这是否正是您所需要的,但您可能想要使用 merge
而不是部分 checkout
,这是解决冲突提交的标准方法。
考虑到你在一个孤立的分支上,你不能使用简单的 git merge
但你必须指定选项 --allow-unrelated-histories
。既然你想编写脚本,就不会有任何冲突:这应该是直接使用正确的合并策略,假设你在 config/<archetype>
中,这可能是 ours
。您还希望您的孤立分支保持不变,仍然可以使用 --no-commit
和后续的 git reset --hard HEAD
。最后,来自 config/<archetype>
的合并命令可能是这样的(未经测试):
git merge --allow-unrelated-histories -s recursive -Xours --no-commit master
就我个人而言,我更喜欢这里的 git archive ... | tar -x --skip-old-files
解决方案,但请考虑以下几点:
你现在在某个孤儿分支 B 上。您有一些文件占用了您的工作树。在提取出现在 master
.
的提示提交中的所有文件后,您希望这些相同的文件出现在您的工作树中
因此,只有两种方法可以实现:
- 从
master
中提取文件,但不要触及任何现有文件:这是可以使用管道完成的解决方案,它不适用于 PowerShell。您还可以构建一个相当奇特的“列出提交顶层的所有文件和目录;对于每个这样的名称,测试它是否存在于此处;如果不存在;从提交中提取该名称;完成”循环。 或
- 将这些文件保存某处:复制或移动它们,从 master 中提取所有文件,然后将这些文件放回原处。
方法二比较简单。在没有子目录的情况下很容易实现。子目录的存在使这两种方法都受到质疑:如果工作树当前有一个目录 d
和一个文件 f
,但是 master
上的提示提交有一个 文件怎么办 名为 d
and/or 一个名为 f
的 目录?对于这种情况,您希望得到什么结果? (tar
方法说 保留现在这里的任何内容 所以你最终会保存 d/*
和 f
,你可以选择手动执行使用方法 2.)
一旦决定如何处理 directory/file 冲突——顺便说一下,这些对于 git checkout
来说也是一个难题——你可以用某种脚本语言编写其余部分以实现方法 2 . 在 git checkout
.
期间使用 mktemp -d
或等价物来隐藏所有现有文件
上下文
我有一个包含应用程序开发历史的存储库。该应用程序是从其源代码即时编译的,可以在存储库被克隆后立即使用。
该应用程序使用了几个配置文件,这些文件在几个配置原型中被拒绝。为了便于部署,我想将每个原型存储在一个单独的分支上,并在克隆后从master
获取应用程序并从所选分支获取配置。
简单的解决方案是将配置分支建立在 master
的基础上,但这需要在 master
前进时定期将它们全部变基。因此,我正在尝试使用两个单独的 git 历史的解决方案:
master
分支包含应用程序的源代码;- 所有
config/<archetype>
都来自一个单独的根目录(通过git checkout --orphan
创建),并且仅包含构建脚本及其各自的配置。
构建脚本现在必须在构建之前从 master
检索所有源代码,注意不要用来自 master
的默认配置文件覆盖原型配置文件。因此...
问题
我需要 git checkout <branch> -- .
的变体 不 触及现有文件,无论它们处于什么状态(已更改、未更改、已忽略、未跟踪...)。
潜在客户
我找到了 this 个确实有答案的相同问题 (git archive mybranch | tar x --skip-old-files
),但是我遇到了一些问题:
- 我在 Windows 上使用 Powershell,它显然提供了一个没有
--skip-old-files
; 的本机 - Git 的
tar
版本接受该标志,但由于我认为 Powershell 管道工作方式的一个怪癖而失败(来自 [= 的相同命令 运行 63=] Bash 作品):
tar
命令
PS> &"C:\Program Files\Git\bin\git.exe" archive master | &"C:\Program Files\Git\usr\bin\tar.exe" x --skip-old-files
/usr/bin/tar: Malformed extended header: missing newline
/usr/bin/tar: Substituting `.' for empty member name
/usr/bin/tar: Substituting `.' for empty member name
/usr/bin/tar: Skipping to next header
/usr/bin/tar: Exiting with failure status due to previous errors
在这种环境下,我更喜欢只使用 Git.
的解决方案我不确定这是否正是您所需要的,但您可能想要使用 merge
而不是部分 checkout
,这是解决冲突提交的标准方法。
考虑到你在一个孤立的分支上,你不能使用简单的 git merge
但你必须指定选项 --allow-unrelated-histories
。既然你想编写脚本,就不会有任何冲突:这应该是直接使用正确的合并策略,假设你在 config/<archetype>
中,这可能是 ours
。您还希望您的孤立分支保持不变,仍然可以使用 --no-commit
和后续的 git reset --hard HEAD
。最后,来自 config/<archetype>
的合并命令可能是这样的(未经测试):
git merge --allow-unrelated-histories -s recursive -Xours --no-commit master
就我个人而言,我更喜欢这里的 git archive ... | tar -x --skip-old-files
解决方案,但请考虑以下几点:
你现在在某个孤儿分支 B 上。您有一些文件占用了您的工作树。在提取出现在
的提示提交中的所有文件后,您希望这些相同的文件出现在您的工作树中master
.因此,只有两种方法可以实现:
- 从
master
中提取文件,但不要触及任何现有文件:这是可以使用管道完成的解决方案,它不适用于 PowerShell。您还可以构建一个相当奇特的“列出提交顶层的所有文件和目录;对于每个这样的名称,测试它是否存在于此处;如果不存在;从提交中提取该名称;完成”循环。 或 - 将这些文件保存某处:复制或移动它们,从 master 中提取所有文件,然后将这些文件放回原处。
方法二比较简单。在没有子目录的情况下很容易实现。子目录的存在使这两种方法都受到质疑:如果工作树当前有一个目录
d
和一个文件f
,但是master
上的提示提交有一个 文件怎么办 名为d
and/or 一个名为f
的 目录?对于这种情况,您希望得到什么结果? (tar
方法说 保留现在这里的任何内容 所以你最终会保存d/*
和f
,你可以选择手动执行使用方法 2.)- 从
一旦决定如何处理 directory/file 冲突——顺便说一下,这些对于 git checkout
来说也是一个难题——你可以用某种脚本语言编写其余部分以实现方法 2 . 在 git checkout
.
mktemp -d
或等价物来隐藏所有现有文件