将一个存储库导出到另一台计算机

415

我需要一种方法将一个暂存的更改导出到另一台计算机。

在第一台计算机上,我执行了以下操作:

$ git stash save feature

我正在尝试将stash的补丁保存到文件中,然后将其导入另一台计算机

$ git stash show -p > patch

这个命令会生成一个文件,我可以将它移动到另一台已经克隆了该存储库的计算机上,但问题是如何再次将其作为stash导入。


9
请注意,git stash save已被弃用,建议使用git stash push - Ewan
2
不幸的是,git stash show 忽略未跟踪的文件,即使它们已经被存储。 - Andrzej Wąsowski
6
@AndrzejWąsowski 在你发表评论两天前,git 2.32.0版本发布了,其中增加了 [-u|--include-untracked|--only-untracked] 选项,用于显示 git stash 中未跟踪的文件。现在我提供的替代命令是 git stash push --include-untrackedgit stash show --include-untracked --patch > patch。请注意,这里的翻译旨在让读者更易懂原文内容,没有额外的解释和其他内容返回。 - Ben Mares
13个回答

359

你可以通过运行以下命令来应用补丁文件(尚未提交更改):

git apply patchfile

那么,您可以直接从当前工作目录创建一个新的stash:

git stash

41
阅读完这个回答后,我想知道如何从我的所有存储库中选择特定的存储库。 答案在这里:https://dev59.com/l3I-5IYBdhLWcg3wVWvv#1910142。 在这种情况下,我最终执行了以下操作:git stash show "stash@{0}" -p > patch,而不是 OP 的第二个 shell 命令。 - Tim Arnold
1
@TimCamber 我认为你不需要在 stash@{0} 周围加上双引号。 - ari gold
2
@arigold 这取决于你使用的shell。例如在PowerShell中,你需要它们,因为花括号是特殊语法。 - poke
4
如果有人遇到"git patch does not apply"的错误,请尝试使用以下命令进行修复:git apply --reject --whitespace=fix mychanges.patch。注意不要更改原意,并尽可能使翻译通俗易懂。 - rishiehari
2
@rishiehari 非常好!我遇到了一堆“补丁无法应用”、“无法对my_file.aar应用二进制补丁,因为没有完整的索引行”和“git apply --reject --whitespace=fix mypatchfile”做得很不错。它仍然有两个文件有问题,但我可以手动复制这些文件。 - Someone Somewhere
显示剩余5条评论

122
你可以从一台机器上创建一个存储为补丁文件的stash,然后将该补丁文件共享到其他机器。 将stash作为补丁文件创建
$ git stash show "stash@{0}" -p > changes.patch

“stash@{0}”是藏匿的引用。它将使用最新的stash创建补丁文件。 如果您想要不同的,请使用命令$ git stash list查看您的stash列表并选择要打补丁的内容。

应用补丁

现在将stash转移到另一台机器并将其粘贴到项目的根文件夹中。 然后运行此命令。

$ git apply changes.patch

如果有错误并且您想撤销更改

$ git apply changes.patch --reverse

1
我不得不将“-p”参数替换为“--binary”,以使其正常工作。 - Farhan Haider
2
当我尝试在创建补丁的同一台计算机上应用补丁时,出现“补丁不适用”的错误。 - TheCrazyProgrammer
@TheCrazyProgrammer 你运行了 git apply changes.patch 还是 git stash apply changes.patch?前者可行,后者会给我报错(无论是否使用 < 将文件作为输入读取)。 - yuyu5
2
@TheCrazyProgrammer 使用 git apply --3way changes.patch 命令来尝试解决冲突,如果你遇到了 "patch does not apply" 的错误。更多信息请参考:https://dev59.com/3G445IYBdhLWcg3wnrrM#47756467 - epineda
当 diff 要创建新文件时,它无法正常工作。 - Aryeh Beitz
显示剩余3条评论

24

另外,您可以按照以下步骤将整个本地存储(包括其他本地分支、本地标签等)复制到另一台计算机:

  • 在旧的和新的git目录上都执行git pull以确保两者都具有最新更改(或使用git reset --hard commit-hash确保两个仓库具有相同的HEAD)。
  • 将旧git目录中的.git文件夹复制到新的存储库中。

1
尽管.git的压缩tar文件大小达到了700M+,但这比其他建议的解决方案要容易得多,尤其是我有多个存储。 - Chris Warth

23

你可以从你的暂存区(在电脑1上)创建一个分支,使用以下命令:

alternatively you can create a branch from your stash (on computer 1), using


git stash branch stashed_changes_branch

提交您的更改:

git commit -a

然后在第二台电脑上将其添加为远程:

git remote add pc1 user@computer1:/path/to/repo

现在您可以使用以下方法检索远程信息

git fetch pc1

现在你可以按你想要的方式导入提交;使用git cherry-pickgit rebase或者任何你喜欢的方式...

如果你想让它看起来像刚刚使用了git stash apply一样;你可以使用git cherry-pick --no-commit.


如果在计算机1和计算机2之间没有直接连接;你可以使用远程库(比如github或类似的东西):

git push origin stashed_changes_branch

并且在computer2上:

git fetch

2
假设源系统(computer1)开放接收外部连接,但对于来到这里的大多数人而言,这不太可能成立。如果你想走分支路径,为什么不只是将一个临时分支推送到远程origin,然后从computer2上拉取呢?如果你不想保留分支,那么在拉取之后可以立即删除远程分支。Git中的分支很便宜,通常没有不使用它们的理由。 - indivisible
@indivisible 我不同意,今天连接互联网上的两台计算机有很多机会。回答中描述的技术可能有用,可以在局域网上将正在进行的工作从笔记本电脑传输到台式机上。即使是像Hamachi这样的虚拟VPN服务也可以直接在运行git的计算机之间通过互联网传输文件。 - steampowered
4
@steampowered,确实对于某些人/情况来说可能是正确的,但我认为这一点值得提醒未来的读者,因为这是解决方案工作的硬性要求,并且修改您的本地环境/系统以接受传入的流量需要进行不少配置。在我看来,这种操作对于像这样的任务来说过于繁琐了。 如果您的系统已经开放,则尽管使用此答案-它并不错误。我只是觉得大多数访问此处的用户不会处于那种情况。 - indivisible
Stashes是提交对象,因此已经具有提交哈希(请参见git stash list --oneline),因此您在技术上不必将stash应用于新的提交对象。换句话说,创建一个新分支并不是必要的。但是,直接将stash推送到远程可能会很棘手。 - Tyler Crompton

12

一个stash是介于基础提交和索引之间的工作目录的特殊合并提交。一种方法是将每个存储为单独的补丁,首先检出stash的第一个父级,从这两个补丁还原索引和工作目录,最后还原stash(似乎有一个答案是这样做的)。

这是为了完全重新创建所有stashes的信息,如果您不关心它,您至少应该在还原之前检出stash的第一个父级以避免冲突并跟踪stash的创建位置。

这就是我用来完全恢复一个repo中所有stash的方法。如果您不能将它们保存在同一台计算机上,可以在创建它们之后将stash标记保存在bundle中,并将ref列表和bundle复制到目标计算机。

从原始repo的根目录开始:

  1. 获取stash refs的列表
  2. 标记你的stash refs,这样你就可以使用git fetch检索它们(标记名称不重要,如果有冲突,请更改它。我使用 stash_ +逻辑stash ref中的数字)
  3. 按相反的顺序将逻辑引用转换为sha1哈希值-稍后我们会使用它们
  4. 保存该repo路径-也用于稍后
refs=$(git stash list|cut -d: -f1)
for ref in $refs; do git tag stash_${ref//[^0-9]} $ref; done
refs=$(git rev-parse $refs|tac)
oldpath=$PWD

注意:这需要bash或兼容的shell(ksh、zsh应该都可以...)。如果你的shell不支持${param//pattern},你还可以递增一个变量,例如stash_$((i++))

现在,在新的仓库中,对于每个引用:

  1. 从旧的仓库中获取该引用(我们甚至不需要使用标签名称,因为我们已经标记了它们,可以使用git fetch检索它们)。
  2. 使用该引用的主题作为stash消息重新导入stash。
for ref in $refs; do git fetch $oldpath $ref; git stash store -m "$(git show -s --pretty=%s $ref)" $ref; done

这真的很有用,我刚刚做了一个变化,将我的存储迁移到了一台新机器上,只需对获取存储名称和shas的位置进行了一些小修改。refs=$( git stash list --format=%gd ) ... refs=$( git stash list --format=%h | tac ) - mattlaw
1
请注意,由于您也可以使用git fetch通过其长哈希检索一系列提交,因此可以避免标记提交。例如,hashes=($(git reflog --format=%H refs/stash)会给您一个提交哈希列表,可以使用git fetch $oldpath $hashes检索它们,但仍需要循环执行git stash store - Jonas Hörsch

9

如何在SourceTree中导出Stash:

  1. 从你打算使用Stash的分支中创建一个名为“StashTransfer”的新分支。
  2. 将你的Stash应用到该分支并进行一次提交。

  3. 点击你的提交,并从中创建一个补丁文件,将这个补丁文件带上。

  4. 进入另一个代码仓库,在那里选择与1)中使用的相同的父分支。

  5. 选择操作 / 应用补丁,选择模式:修改工作副本文件,然后应用补丁。现在你的当前工作环境中有来自补丁的未提交修改。

  6. 为当前代码仓库创建一个新的Stash。


7
另一个选择是将一台计算机上的.git文件夹通过rsync同步到另一台计算机。 rsync仅处理文件更改(比复制快)。
这种方法的缺点是配置文件也会被覆盖,如果你在两台机器之间运行不同的.git配置,则可能不希望发生这种情况。但是,您可以使用rsync中的--exclude选项来排除文件,以克服这个问题。
总体而言,我认为原生Git解决方案更加清洁,但是对于匆忙中更熟悉rsync而不是git的人来说,这个rsync技巧也许是个不错的选择。

7

6

原帖中的启动命令:

git stash show -p stash@{x} > patch_file

对我来说不起作用(出于某种原因,它创建了无法使用的补丁文件)。相反我要这样做:

git stash apply stash@{x}
git commit

对于每个我想要转移的stash,我将“父”存储库放置在“子”存储库的file:///范围内,并针对每个stash提交执行以下操作:

git fetch file:///path_to_parent_git && git cherry-pick commit_sha
git reset --soft HEAD^
git stash save my_new_stash_on_child

这个方法比较复杂,但对我很有用。


3
请注意,选项--binary会在导出和导入期间将本地文件隐藏。在搜索一段时间后,我采取了以下措施:
#检查所有隐藏的内容
git stash list
#按编号导出,--option binary对于导出二进制文件非常重要
git stash show stash@{0} -p --binary > patch0
#导入隐藏内容,转到新仓库
git apply /old_repository/patch0
#然后重新隐藏本地更改
#对于所有隐藏的内容stash@{1}, ... ,stash@{n}请重复上述过程

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接