是否有可能将git隐藏到远程存储库?

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

或者我的选择是:

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

我会选择第二种方法,尽管不知道为什么不能提交给main/feature分支。也有可能进行“樱桃挑选”。

不可能通过fetch等方式获得它,镜像refspec是fetch = +refs/*:refs/*,即使stash是refs/stash,它也不会被发送。显式的refs/stash:refs/stash也没有效果!

这只会令人困惑,因为它不会获取所有的存储,只有最新的一个;存储列表是ref refs/stashesreflog

我有点晚了,但我相信我找到了一些适合我的东西,如果你的情况相同或相似,它可能也适用于你。

我在它自己的分支里做一个特性。分支不会合并到master中并推送,直到它完成或者我已经提交了我觉得可以向公众展示的内容。所以当我想要将非阶段性的更改转移到另一台计算机时,我所做的是:

  • 使用提交消息进行提交 比如"[non-commit] FOR TRANSFER ONLY",包含你想要传输的内容
  • 登录到另一台计算机。
  • < p >那么做:

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

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

  • git reset HEAD^(暗示--mixed)

    这将重置HEAD指向“[non-commit]”提交前的状态

< p >从git-reset (1): "--mixed:重置索引,但不重置工作树(即,更改的文件被保留,但不标记为提交)[…]"

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

然而,这将需要你在你做“[非提交]”的存储库中git reset --hard HEAD^,因为那个提交是垃圾。

注意:我刚刚用24小时的时间重写了这个答案:) 在我的shell历史中,整个过程就是三个简单的语句。不过,为了方便起见,我已经将它们解压缩了。< / p >

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


这里是一步一步的。

假设源在~/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@{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

我想,stash的全部思想就是把一些不那么重要的东西藏在当地的的地毯下面。没有人应该知道你最喜欢的废话;-)唯一的“但是”是:但是如果我在几个工作站上开发呢?那么scp就更好了。

有点晚了,但这个答案可能会帮助到一些人。我之所以想知道这些,是因为我想在同一时间点在另一台电脑上发布正在开发的功能/bug/任何东西。

对我有效的是提交我正在进行的代码(在我独自处理的分支中)。当我到达另一台计算机时,执行拉取,然后撤销提交:

git reset --soft HEAD^

继续像以前那样工作,所有正在进行的更改都在那里,没有提交,也没有分期。

希望能有所帮助。

下面的代码不适用于隐藏,但适用于工作目录中未提交的更改。它创建一个分支,自动提交所有当前的更改,并推送到远程:

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_

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

这是解释在这里以及。

我将简单地创建一个新的stash分支,并在不需要该分支时删除该分支。

在机器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

当前接受的答案在技术上是正确的,你不能直接告诉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的手册页,在那里我发现了这个:

< p >创建< br > 创建一个stash(这是一个常规提交对象)并返回其对象名称,而不将其存储在ref名称空间中的任何位置。这对脚本很有用。这可能不是你想要使用的命令;

.

.

. < br > < p >商店 将通过git stash create(这是一个悬空合并提交)创建的给定stash存储在stash ref中,更新stash reflog。这对脚本很有用。这可能不是你想要使用的命令;

.

.

.

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

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

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

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

藏匿现在显示正常在我的本地回购:

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

要清理远程,可以像这样从远程删除存储:

git push origin :refs/stashes/<SHA>

这个方法还有幂等的好处:如果你再次运行push命令,它将报告Everything up-to-datefetch命令也可以安全地重复运行。虽然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可以在这里找到。

在其他答案的基础上,如果你在GitHub这样的平台上有一个公共存储库,但不希望你正在进行的更改是公共的,你可以创建一个私有存储库并将其添加为远程存储库。

要同步更改:提交,推到私有远程上的分支,拉到目标设备,并执行软/混合重置。

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

非常感谢@Scott Weldon (answer-link)和@sehe (answer-link)回答了这个问题!我从他们身上学到了很多!!由于这个问题,我还广泛地学习了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文件夹只有你在本地回购中想要的存储。

请参阅下面两个一行程序,我成功地使用它们将所有存储从多个源回购推到远程主机上的单个目标回购。

这是基于她原来的答案艾伦·克鲁格的评论Keith Robertson的评论Sebastian Schrader的评论合并,并添加远程主机:dir。

# on each src_host:repo_dir
git send-pack <dst_host>:<dst_repo_dir> $(for sha in $(git rev-list -g stash); do echo $sha:refs/heads/stash_$sha; done)


# on the dst_host:repo_dir
for a in $(git rev-list --no-walk --glob='refs/heads/stash_*' | tac); do git checkout $a && git reset HEAD^ && git update-ref --create-reflog -m "$(git show -s --format=%B $a)" refs/stash $a && git restore . && git branch -D stash_$a; done; git checkout master

(我还没有足够的声誉点,否则我会在sehe的原始答案下添加评论)