242

在 git 中,是否可以创建一个存储,将存储推送到远程存储库,在另一台计算机上检索存储,然后应用存储?

或者是我的选择:

  • 创建补丁并将补丁复制到另一台计算机,或
  • 创建一个次要分支并将未完成的工作提交到该分支?
4

12 回答 12

78

注意:我刚刚用 24 小时的 git-fu 重写了这个答案 :) 在我的 shell 历史中,整个 shebang 现在是三个单行。但是,为了您的方便,我对它们进行了压缩。

这样,我希望你能看到我是怎么做的,而不是盲目地复制/粘贴东西。


这是一步一步的。

假设是 ~/OLDREPO 中包含存储的源。创建一个不包含存储的 TEST 克隆:

cd ~/OLDREPO
git clone . /tmp/TEST

将所有存储推入临时分支:

git send-pack /tmp/TEST $(for sha in $(git rev-list -g stash); \
    do echo $sha:refs/heads/stash_$sha; done)

在接收端循环以转换回存储:

cd /tmp/TEST/
for a in $(git rev-list --no-walk --glob='refs/heads/stash_*'); 
do 
    git checkout $a && 
    git reset HEAD^ && 
    git stash save "$(git log --format='%s' -1 HEAD@{1})"
done

如果你愿意,清理你的临时分支

git branch -D $(git branch|cut -c3-|grep ^stash_)

做一个 git stash list 你会是这样的:

stash@{0}: On (no branch): On testing: openmp import
stash@{1}: On (no branch): On testing: zfsrc
stash@{2}: On (no branch): WIP on sehe: 7006283 fixed wrong path to binary in debianized init script (reported as part of issue
stash@{3}: On (no branch): WIP on debian-collab: c5c8037 zfs_pool_alert should be installed by default
stash@{4}: On (no branch): WIP on xattrs: 3972694 removed braindead leftover -O0 flag
stash@{5}: On (no branch): WIP on testing: 3972694 removed braindead leftover -O0 flag
stash@{6}: On (no branch): WIP on testing: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{7}: On (no branch): WIP on xattrs: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{8}: On (no branch): WIP on testing: 28716d4 fixed implicit declaration of stat64
stash@{9}: On (no branch): WIP on emmanuel: bee6660 avoid unrelated changes

在原始存储库上,看起来像

stash@{0}: WIP on emmanuel: bee6660 avoid unrelated changes
stash@{1}: WIP on testing: 28716d4 fixed implicit declaration of stat64
stash@{2}: WIP on xattrs: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{3}: WIP on testing: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{4}: WIP on testing: 3972694 removed braindead leftover -O0 flag
stash@{5}: WIP on xattrs: 3972694 removed braindead leftover -O0 flag
stash@{6}: WIP on debian-collab: c5c8037 zfs_pool_alert should be installed by default
stash@{7}: WIP on sehe: 7006283 fixed wrong path to binary in debianized init script (reported as part of issue #57)
stash@{8}: On testing: zfsrc
stash@{9}: On testing: openmp import
于 2011-03-09T16:22:58.163 回答
71

无法通过 fetch 获取它,镜像 refspec 是fetch = +refs/*:refs/*,即使 stash 是refs/stash它也不会被发送。显式refs/stash:refs/stash也没有效果!

无论如何它只会令人困惑,因为这不会获取所有的存储,只有最新的;stashes 列表是ref的reflogrefs/stashes

于 2009-10-11T10:47:03.120 回答
32

我参加聚会有点晚了,但我相信我找到了一些对我有用的东西,如果你的情况相同或相似,它也可能对你有用。

我正在自己的分支中开发一个功能。该分支不会合并到 master 中并在其完成之前被推送,或者我已经做出让我觉得向公众展示的舒适的提交。因此,当我想将非暂存更改传输到另一台计算机时,我要做的是:

  • 使用“”之类的提交消息进行提交[non-commit] FOR TRANSFER ONLY,其中包含您要传输的内容。
  • 登录到另一台计算机。
  • 然后做:

    git pull ssh+git://<username>@<domain>/path/to/project/ rb:lb

    如果您以不同的方式访问存储库,则 URL 可能会有所不同。这会将来自该 URL 的更改从远程分支“rb”拉到本地分支“lb”。请注意,我在自己的计算机上运行了一个 ssh 服务器,并且能够以这种方式访问​​存储库。

  • git reset HEAD^(暗示--mixed

    这会将 HEAD 重置为指向“[非提交]”提交之前的状态。

来自 git-reset(1):“ --mixed:重置索引但不重置工作树(即,更改的文件被保留但未标记为提交)[...]”

因此,您最终将对文件进行更改,但不会对 master 进行任何提交,也不需要存储。

但是,这将要求您git reset --hard HEAD^在您进行“[非提交]”的存储库中,因为该提交是垃圾。

于 2010-03-29T00:13:25.520 回答
27

有点晚了,但这个答案可能会对某人有所帮助。我想知道这一点,因为我希望能够推送正在进行的功能/错误/任何东西,并在另一台计算机上从同一点工作。

对我有用的是提交我正在进行的代码(在我独自工作的分支中)。当我到达我的另一台计算机时,执行拉取操作,然后使用以下命令撤消提交:

git reset --soft HEAD^

继续按原样工作,在那里进行所有正在进行的更改,未提交且未暂存。

希望能帮助到你。

于 2013-08-28T01:13:18.103 回答
22

似乎有一个非常巧妙的技巧可以解决这个问题。您可以使用git diff > file.diff(并提交文件),然后使用git apply file.diff(从任何地方)恢复更改以获得相同的结果。

这也解释了here

于 2016-11-07T15:34:51.690 回答
12

当前接受的答案在技术上是正确的,您不能直接告诉 Git 将所有存储区推送到远程,然后将所有内容拉到另一台计算机上的本地存储区中。

虽然目前最高投票的答案应该可以工作,但我不喜欢它创建一堆临时分支,并且它需要手动检查存储提交并将其保存为存储,这可能会导致类似此评论的问题提到,并导致重复On (no branch): On testing:。肯定有更好的办法!

因此,虽然您不能直接推送存储,但存储只是一个提交(实际上是两个提交),并且根据git push手册页,您可以推送提交:

通常<src>是您想要推送的分支的名称,但它可以是任意的“SHA-1 表达式”...

我选择将储藏室推到,refs/stashes/*这样我就不会用额外的分支弄乱我的遥控器。所以我可以这样做:

git push origin stash@{0}:refs/stashes/$(git rev-parse --short stash@{0})

(该rev-parse命令获取存储的短散列,这对于存储库来说是唯一的。)

接下来,我需要从另一台计算机获取存储。Git 默认只获取分支,所以我需要专门获取存储:

git fetch origin refs/stashes/*:refs/stashes/*

现在将存储提交转换回实际存储。如前所述,虽然我可以像往常一样检查存储提交、重置和存储,但我不喜欢它需要额外的步骤,或者它可能无法维护存储的索引状态。我在网上寻找一种自动执行此操作的方法,但我的搜索失败了。最后,我浏览了 的手册页git stash,我在其中找到了这个:

create
创建一个 stash(这是一个常规提交对象)并返回其对象名称,而不将其存储在 ref 命名空间中的任何位置。这旨在对脚本有用。它可能不是您要使用的命令;参见上面的“保存”。


通过 git stash create 创建的给定存储(这是一个悬空合并提交)存储在存储引用中,更新存储引用日志。这旨在对脚本有用。它可能不是您要使用的命令;参见上面的“保存”。

因为我已经提交了,store听起来就像我想要的。所以我可以这样做:

git stash store --message "$(git show --no-patch --format=format:%s <SHA>)" <SHA>

<SHA>用刚刚获取的存储替换。

(该git show命令从 stash 提交中获取提交消息,用作 stash 日志的消息。)

存储现在在我的本地存储库中正常显示:

$ git stash list
stash@{0}: On master: temp
...

要清理遥控器,可以从遥控器中删除存储,如下所示:

git push origin :refs/stashes/<SHA>

这种方法还有一个好处是幂等的:如果你push再次运行命令,它会报告Everything up-to-date. 该fetch命令也可以安全地重复运行。虽然stash store如果存储与最近的存储相同,它将跳过存储,但它不会阻止旧存储的重复。不过,这可以解决,就像我在git-rstash脚本中所做的那样,见下文。


为了完成,您还可以轻松推送所有存储(使用):

for i in $(seq 0 $(expr $(git rev-list --walk-reflogs --count stash) - 1))
do
  git push origin stash@{$i}:refs/stashes/$(git rev-parse --short stash@{$i})
done

或导入所有获取的存储:

for stash in $(ls .git/refs/stashes)
do
  git stash store --message "$(git show --no-patch --format=format:%s $stash)" $stash
done

我创建了一个可以作为子命令(例如)调用的git rstash push 0脚本,所以我不必记住所有这些。 git-rstash可以在这里找到。

于 2020-04-22T02:29:57.430 回答
9

我会采用第二种方法,尽管不知道为什么不能将其提交给 master/featured branch 。也可以进行樱桃采摘。

于 2009-10-11T10:39:21.967 回答
6

AFAIK 藏匿的整个想法是在当地地毯下隐藏一些不那么重要的东西。没有人应该知道你最喜欢的废话 ;-) 唯一的“但是”是:但是如果我在几个工作站上开发呢?然后scp就好多了。

于 2011-09-22T07:21:21.387 回答
1

以下内容不适用于存储,但适用于工作目录中未提交的更改。它创建一个分支,自动提交所有当前更改,并推送到远程:

commit_and_push_ ( ) {
    # This will:
    #  1. checkout a new branch stash-XXX
    #  2. commit the current changes in that branch
    #  3. push the branch to the remote
    local locbr=${1:-autostash-XXX}
    git checkout -b $locbr
    git add .
    git commit -a -m "Automatically created commit"
    git push origin $locbr
    echo "Autocommitted changes in branch $locbr ..."
}

像这样使用:

commit_and_push_ my-temp-branch
commit_and_push_
于 2014-07-28T14:10:41.180 回答
1

我只需创建一个新的存储分支并在不需要该分支时删除。

在机器 1 上:

git add . // Add work-in-progress job
git checkout -b stash-branch // Create and checkout to stash-branch
git commit -m 'WIP: job description' // Commit message
git push origin stash-branch // Push to remote

在机器 2 上:

git pull origin stash-branch // Pull the stash-branch
git checkout master // Checkout to working branch
git rebase stash-branch // Rebase the stash-branch
git reset --soft // Equivalent to stash!!
git branch -d stash-branch // Delete branch when not needed from local
git push -d origin stash-branch // Delete branch when not needed from remote
于 2020-03-01T11:39:10.060 回答
0

我将混合上面的 2 个答案,只是为了分享我是如何使用zsh shell做的。

非常感谢@Scott Weldon (答案链接)和@sehe (答案链接)对这个问题的回答!我从他们身上学到了很多!!由于这个问题,我还广泛了解了 shell 脚本!


代码作用的一个非常简单的解释

请参阅上面的答案链接以获得更好的(推荐)理解。

代码的作用:

Stash goes from Machine 1 --> to remote --> to Machine 2

机器 1 上的步骤:

1. Push the stash to remote (using for loop for multiple stashes)

机器 2 上的步骤:

1. Check stash(es) in remote. (This is just to check whether there are  previous stashes in remote. If there are, you must delete them if you don't want them in you stash list. Command for deleting remote stashes are given in bonus)
2. Fetch the stash(es) to a local ref folder named "ref/stashes" in your .git folder in your local repository. (Its like downloading the stashes on your PC)
3. Convert the fetched stash(es) to proper data. (Its like extracting or installing the stashes on your PC)

奖金:

1. Check stash(es) in remote
2. Delete stash(es) from remote 

代码:

在机器 1 上:

1. git push origin $(for sha in $(git rev-list -g stash); do echo $sha:"refs/stashes/$(git rev-parse --short $sha)"; done)

在机器 2 上:

1. git ls-remote
2. git fetch origin "refs/stashes/*":"refs/stashes/*"
3. for sha in $(git rev-list --no-walk --reverse --glob='refs/stashes/*'); do git stash store --message "$(git show --no-patch --format=format:%s $sha)" $sha; done

奖金:

1. git ls-remote
2. git push origin :refs/stashes/<stashFile-1> :refs/stashes/<stashFile-2>

以上代码用于多个存储,也可用于一个存储。只需确保您的远程ref/stashes文件夹在本地存储库中仅包含您想要的存储空间。

于 2021-11-01T01:14:25.123 回答
0

Building on other answers, if you have a public repository on a platform like GitHub, but don't want your in-progress changes to be public, you can create a private repository and add it as a remote.

To sync changes: commit, push to a branch on the private remote, pull on the target device, and do a soft/mixed reset.

于 2021-05-25T23:23:04.157 回答