从另一个分支获取单个文件的方法

从另一个分支获取单个文件的方法

技术背景

在使用Git进行版本控制时,我们常常会在不同的分支上进行开发工作。有时候,我们需要从一个分支中获取某个特定的文件到当前分支,而不是将整个分支合并过来。这可能是因为我们只需要那个文件的最新版本,或者是想查看该文件在某个特定分支上的状态。

实现步骤

Git 2.23 之前的方法

1
2
git checkout main                 # 先切换回主分支
git checkout experiment -- app.js # 然后从 'experiment' 分支复制 app.js 文件

Git 2.23 及之后的方法

1
2
git switch main
git restore --source experiment -- app.js

如果想同时更新索引(即恢复文件内容并将其添加到索引中):

1
2
3
git restore --source experiment --staged --worktree -- app.js
# 简写形式
git restore -s experiment -SW -- app.js

使用 git show 命令

1
git show experiment:path/to/app.js > path/to/app.js

不过,这里需要使用从仓库根目录开始的完整路径。

从特定修订版本获取文件

1
2
git show $REVISION:$FILENAME
git checkout $REVISION -- $FILENAME

$REVISION 可以是如下形式:

1
2
3
experiment@{yesterday}:app.js # app.js 昨天的版本
experiment^:app.js # app.js 在第一次提交父节点的版本
experiment@{2}:app.js # app.js 两个提交之前的版本

从暂存区获取文件

1
git checkout stash -- app.js

从另一个分支获取单个文件到当前分支

1
git checkout new-feature path/to/app.js

注意,new-feature 必须是本地分支,而不是远程分支。

从另一个分支或提交哈希中检出一个或多个文件或目录到当前分支

1
git checkout <branch_name> -- <paths>

示例:

1
2
3
4
5
6
7
8
# 从 'my_branch' 分支检出 'somefile.c'
git checkout my_branch -- somefile.c

# 从 'my_branch' 分支检出 4 个文件
git checkout my_branch -- file1.h file1.cpp mydir/file2.h mydir/file2.cpp

# 从 'my_branch' 分支检出 'path/to/dir' 目录下的所有文件
git checkout my_branch -- path/to/dir

如果不指定 branch_name,默认是 HEAD

1
2
3
4
5
# 从 'HEAD' 检出 'somefile.c',覆盖任何本地未提交的更改
git checkout -- somefile.c

# 从 'HEAD' 检出整个文件夹
git checkout -- some_directory

如果文件之前有暂存的删除操作,需要显式指定分支或提交:

1
2
git checkout HEAD -- somefile.c
git checkout HEAD -- some_directory

将任何文件或文件夹从任何分支或提交哈希检出到计算机上的任何位置

单个文件

1
git show my_branch_or_commit_hash:my_file.cpp > any/path/my_file.cpp

示例:

1
2
mkdir ../temp
git show HEAD~3:main.cpp > ../temp/main_old.cpp

整个目录

1
2
3
4
5
6
7
8
9
# 检出感兴趣的提交
git checkout my_branch_or_commit_hash

# 将感兴趣的目录复制到临时位置
mkdir temp
cp -r path/to/dir_to_copy temp/

# 切回原分支
git checkout -

在解决合并、挑选、变基或还原更改时

1
2
3
4
5
6
7
8
9
# 对文件中的所有冲突保留 'theirs' 版本
git checkout --theirs -- path/to/some/file
# 或对文件中的所有冲突保留 'ours' 版本
git checkout --ours -- path/to/some/file

# 对目录中的所有文件冲突保留 'theirs' 版本
git checkout --theirs -- path/to/some/dir
# 或对目录中的所有文件冲突保留 'ours' 版本
git checkout --ours -- path/to/some/dir

将某个文件或目录重置为与另一个提交或分支中该文件或目录的状态完全匹配

1
2
3
4
git reset my_branch -- path/to/some/file_or_dir
git checkout-index -fa
git clean -fd # 注意:此操作会永久删除未提交的更改
git commit -m "hard reset path/to/some/file_or_dir to its state as it was at my_branch"

核心代码

基本获取文件

1
git checkout <branch_name> -- <path_to_file>

Git 2.23 新命令

1
2
git switch <target_branch>
git restore --source <source_branch> -- <path_to_file>

git show 获取文件

1
git show <branch_name>:<path_to_file> > <local_path>

最佳实践

  • 在进行文件获取操作前,确保当前分支的工作区是干净的,避免丢失未提交的更改。
  • 如果需要获取多个文件或整个目录,建议先进行测试,确认操作的正确性。
  • 对于复杂的情况,可以使用 git diff 查看文件的差异,确保获取的是所需的版本。

常见问题

分支名包含特殊字符

如果分支名包含特殊字符(如 .),需要用引号将分支名括起来:

1
git checkout "fix.june" alive.html

path does not have our versionpath does not have their version 错误

当遇到此类错误时,需要先使用 git rm 删除这些文件,然后再尝试 git checkout --oursgit checkout --theirs 命令。

分支名与文件名冲突

如果分支名和文件名冲突,可能会导致命令执行错误。此时需要明确指定分支和文件的路径。