【问题标题】:How do I copy a version of a single file from one Git branch to another?如何将单个文件的版本从一个 Git 分支复制到另一个?
【发布时间】:2010-09-23 09:11:01
【问题描述】:

我有两个完全合并在一起的分支。

但是,在合并完成后,我意识到一个文件已被合并搞砸了(其他人做了自动格式化,哎呀),在另一个文件中更改为新版本会更容易分支,然后将我的一行更改带入我的分支后重新插入。

那么在 Git 中最简单的方法是什么?

【问题讨论】:

  • 请注意,在接受的答案中,第一个解决方案会分阶段进行更改,而第二个解决方案不会。 stackoverflow.com/a/56045704/151841
  • 最新的答案是git restore --source otherbranch path/to/myfile.txt(参见the answer中的解释)。

标签: git git-branch branching-and-merging


【解决方案1】:

从您希望文件结束的分支运行它:

git checkout otherbranch myfile.txt

通用公式:

git checkout <commit_hash> <relative_path_to_file_or_dir>
git checkout <remote_name>/<branch_name> <file_or_dir>

一些笔记(来自 cmets):

  • 使用提交哈希,您可以从任何提交中提取文件
  • 这适用于文件和目录
  • 覆盖文件myfile.txtmydir
  • 通配符不起作用,但相对路径可以
  • 可以指定多个路径

另一种选择:

git show commit_id:path/to/file > path/to/file

【讨论】:

  • 是的,会的。但这就是问题的意图。
  • 可能很明显,但您需要使用完整的文件名...通配符不起作用!
  • 虽然.. 这也是个好方法: git show commit_id:path/to/file > path/to/file
  • 远程:git checkout origin/otherbranch myfile.txt
  • 使用通配符确实有效,您只需要用'' 包装它们,这样它们就不会被shell 解释。
【解决方案2】:

我会使用git restore(从 Git 2.23 开始可用):

git restore --source otherbranch path/to/myfile.txt


为什么比其他选项更好?

  • 默认git restore只修改工作目录中的文件。

git checkout otherbranch -- path/to/myfile.txt 将文件复制到工作目录(磁盘上的文件),也复制到暂存区。这与您手动复制此文件并在其上执行git add 的效果相似。 git restore 默认只更改工作目录。

要获得与git checkout otherbranch -- path/to/myfile.txt 相同的结果,您可以编写git restore --source otherbranch --staged --worktree path/to/myfile.txt

  • 默认git restore会在其他分支中缺少文件时从工作目录中删除文件

git restore 可用于恢复带有git restore --source otherbranch path/to/dir 的整个文件夹。您可以使用git checkout 执行类似的操作,但默认情况下git restore 将删除otherbranch 上缺少的文件。要获得git checkout 行为,请使用--overlay 选项。

例如,如果otherbranch 上的文件比当前工作目录中的文件少(并且这些文件被跟踪),没有--overlay 选项git restore 将删除它们。但这是很好的默认行为,您很可能希望目录状态“与otherbranch 相同”,而不是“与otherbranch 相同,但包含我当前分支的其他文件”。

要获得与git checkout otherbranch -- path/to/dir 相同的结果,您可以编写git restore --source otherbranch --staged --worktree --overlay path/to/dir

  • git restore 不使用 shell 重定向来创建文件(Powershell 唯一问题)

git show otherbranch:path/to/myfile.txt &gt; path/to/myfile.txt 使用标准的 shell 重定向。如果您使用 PowerShell,那么文本编码可能会出现问题,或者如果它是 binary,您可能会得到损坏的文件。使用git restore 更改文件全部由git 可执行文件完成。

【讨论】:

  • 不错的答案。是否有 git restore 方法将文件从源分支复制到目标分支上的 new 文件?使用 git show 我可以使用 shell 重定向 (git show otherbranch:path/to/file1.txt &gt; path/to/file2.txt) 来执行此操作,但由于您提到的原因,我想避免 shell 重定向。
  • @AdmiralAdama 不是真的。而且我认为在git restore 中获得它的机会不大(但谁知道;))。这个重定向问题基本上是 Powershell 问题,不确定是否有任何其他 shell 有问题。我通常会回到需要使用“git show with redirection”命令的“git bash”甚至“cmd”。或者使用像 GitExtensions 这样的 GUI,您可以在其中浏览提交的文件树并在任何文件上单击“另存为”。
  • 啊,我明白了。我不使用 Powershell,所以也许 shell 重定向对我来说是 np。感谢您的信息。
  • 小改进:git restore --source=otherbranch path/to/myfile.txtgit restore --source otherbranch path/to/myfile.txt 更好,原因是在第二种情况下,tab 列出可用分支不起作用。
【解决方案3】:

我在类似的搜索中遇到了这个问题。在我的情况下,我希望将另一个分支中的文件提取到与文件原始位置不同的当前工作目录中。 Answer:

git show TREEISH:path/to/file > path/to/local/file

【讨论】:

  • 'git show' 的目的是将数据以可读格式输出到终端,不保证与文件内容完全匹配。同样,最好将一个word文档作为一个整体复制,而不是尝试将其内容复制并粘贴到另一个文档中。
  • 我只是想查看它,以便将内容与当前分支进行比较(检查一些代码)。不过我想用 vim 来做语法高亮等等。
  • 在结帐前比较内容,git diff &lt;other branch&gt; &lt;path to file&gt; 效果很好。
  • @Gonen:从 git 版本 2.21.0 开始,“git show”手册页显示“对于纯 blob,它显示纯内容。”我不确定这是否意味着我们总是很好。我有点担心以这种方式获取图像......
【解决方案4】:

使用 checkout 命令:

  git diff --stat "$branch"
  git checkout --merge "$branch" "$file"
  git diff --stat "$branch"

【讨论】:

  • 如果文件在两个分支上都不存在,则注释合并(第二个命令)无法工作
  • 嗯。我没有差异统计。那是差异工具的特定版本吗,因为我从未听说过它(我应该切换到它吗?):D
  • git diff 支持 --stat 参数,它基本上与 diffstat 做同样的事情。
  • 我必须在本地签出两个分支才能使其正常工作。
【解决方案5】:
  1. 确保您在需要文件副本的分支中。

    例如:我想要master中的子分支文件,所以你需要checkout或者应该在master中git checkout master

  2. 现在将您想要的特定文件从子分支单独签出到master

     git checkout sub_branch file_path/my_file.ext
    

    这里的sub_branch 表示您拥有该文件的位置,后跟需要复制的文件名。

【讨论】:

  • 非常方便且解释清楚。
【解决方案6】:

madlep's answer 之后,您还可以使用目录 blob 从另一个分支复制一个目录。

git checkout other-branch app/**

至于 OP 的问题,如果您只更改了其中的一个文件,这将正常工作。

【讨论】:

  • 注意,两个分支都需要先正确拉取,或者使用origin/other-branch引用repo分支。基本,但咬我。 (答案很好 - 无需编辑)
【解决方案7】:

请注意,在接受的答案中,第一个选项 stages 来自另一个分支的整个文件(如 git add ... 已执行),而第二个选项只会导致复制文件,但不会暂存更改(就好像您刚刚手动编辑了文件并且有明显的差异一样)。

Git copy file from another branch without staging it

变更阶段(例如git add filename)

$ git checkout directory/somefile.php feature-B

$ git status
On branch feature-A
Your branch is up-to-date with 'origin/feature-A'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   directory/somefile.php

未完成的更改(未暂存或提交):

$ git show feature-B:directory/somefile.php > directory/somefile.php

$ git status
On branch feature-A
Your branch is up-to-date with 'origin/feature-A'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   directory/somefile.php

no changes added to commit (use "git add" and/or "git commit -a")

【讨论】:

  • 我得到“feature-B 不是文件”,分支名在前,关于这个 -> "> directory/somefile.php" 可能这会改变文件的编码吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-27
  • 2016-06-15
  • 2020-07-12
  • 2015-12-10
  • 2021-01-04
  • 2021-06-13
相关资源
最近更新 更多