[英]Pushing git subtree changes to upstream repository fails
I'm trying to ensure that git's subtrees will work for me before I incorporate it into my project. 我试图确保git的子树在我合并到我的项目之前对我有用。 I encountered a problem when pushing subtree changes to the upstream repository. 将子树更改推送到上游存储库时遇到问题。
The setup is that I have two repos, sub
and main
, and that main
includes the sub
repo as a subtree
. 设置是我有两个repos, sub
和main
,并且main
包括sub
repo作为subtree
。
Then I do the following: 然后我做以下事情:
sub
repo directly (ie outside of main
). 直接更新sub
仓库(即在main
仓外)。 sub
repo from within the main
repo. 更新main
仓库中的sub
仓库。 sub
(using git subtree split
) into a separate branch, which I then checkout. 将更改拆分为sub
(使用git subtree split
)到一个单独的分支,然后我将其签出。 sub
repo. 尝试将上游推送到sub
仓库。 Naturally, this push is rejected because it would lose the direct update to sub
. 当然,这种推动被拒绝,因为它将失去对sub
的直接更新。 sub
repo. 从sub
仓库中拉出新的更改。 sub
repo. 尝试将上游推送到sub
仓库。 This time, it should work, but it doesn't. 这一次,它应该工作,但事实并非如此。 I've written a script that encapsulates this problem. 我写了一个封装这个问题的脚本。 I'm using git version 1.8.2.1 with the subtree
module enabled. 我正在使用git版本1.8.2.1并启用了subtree
模块。 Here's the script: 这是脚本:
#!/bin/bash
echo -n "Wiping old repositories..."
rm -rf main sub sub-home
echo "done"
echo -n "Initializing main and sub repositories..."
mkdir sub-home
( cd sub-home ; git init -q --bare )
git clone sub-home sub > /dev/null 2>&1
( cd sub ; echo subfile > subfile ; git add subfile ;
git commit -qm "adding root-level file to sub-project" ;
git push -q origin master )
mkdir main
( cd main ; git init -q ; echo file > file ; git add file ;
git commit -qm "adding root-level file to main-project" )
echo "done"
echo -n "Adding sub project as a subtree into main project..."
WD=$PWD
( cd main ; git remote add sub-remote file://$WD/sub-home ;
git subtree add -P sub sub-remote master >/dev/null 2>&1 )
echo "done"
echo -n "Committing to sub-project directly..."
( cd sub ; date > the-date ; git add the-date ;
git commit -qm "adding the-date to sub-project"
git push -q origin master )
echo "done"
echo -n "Committing to sub-project from within main project..."
( cd main ; echo 'subfile what?' > sub/subfile ; git add sub/subfile ;
git commit -qm "changing sub-project from within the main project" )
echo "done"
cd main
git subtree split -q -P sub -b split-branch >/dev/null
git checkout -q split-branch
echo -e "\nPushing from main subtree to sub project, which should fail:"
git push sub-remote master
echo -e "\nBut if we pull first..."
git pull -q --no-edit sub-remote master
echo "...then a push *should* work (but it doesn't):"
git push sub-remote master
cd ..
And here's the output: 这是输出:
$ ./test.sh
Wiping old repositories...done
Initializing main and sub repositories...done
Adding sub project as a subtree into main project...done
Committing to sub-project directly...done
Committing to sub-project from within main project...done
Pushing from main subtree to sub project, which should fail:
To file:///tmp/git/sub-home
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'file:///tmp/git/sub-home'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first merge the remote changes (e.g.,
hint: 'git pull') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
But if we pull first...
...then a push *should* work (but it doesn't):
To file:///tmp/git/sub-home
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'file:///tmp/git/sub-home'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and merge the remote changes
hint: (e.g. 'git pull') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Further git pull
commands (from the split-branch
branch of main
) simply say "Already up-to-date". 进一步的git pull
命令(来自main
的split-branch
分支)简单地说“已经是最新的”。
The thing that's really confusing to me is that, as far as I can tell, the git push
command should really be giving the upstream repo a fast-forward commit, as demonstrated by the following git log
output: 对我来说真正令人困惑的是,据我所知, git push
命令应该真正为上游repo提供快进提交,如下面的git log
输出所示:
$ ( cd main ; git log )
commit 357fe9fb42f5d122338940eb4f22d3ca9d276318
Merge: 472904f cb5d1d3
Author: Jeff Terrell <jeff.terrell@acm.org>
Date: Fri Apr 19 16:03:03 2013 -0400
Merge branch 'master' of file:///tmp/git/sub-home into split-branch
commit 472904f432c3a0a89acde02691b8281ac5246fd1
Author: Jeff Terrell <jeff.terrell@acm.org>
Date: Fri Apr 19 16:03:02 2013 -0400
changing sub-project from within the main project
commit cb5d1d34ce56374f78c98c5b3f3daa314907b62d
Author: Jeff Terrell <jeff.terrell@acm.org>
Date: Fri Apr 19 16:03:02 2013 -0400
adding the-date to sub-project
commit 7d1942203d30e0d9e8663517e6d594545bc50640
Author: Jeff Terrell <jeff.terrell@acm.org>
Date: Fri Apr 19 16:03:02 2013 -0400
adding root-level file to sub-project
$ (cd sub ; git log )
commit cb5d1d34ce56374f78c98c5b3f3daa314907b62d
Author: Jeff Terrell <jeff.terrell@acm.org>
Date: Fri Apr 19 16:03:02 2013 -0400
adding the-date to sub-project
commit 7d1942203d30e0d9e8663517e6d594545bc50640
Author: Jeff Terrell <jeff.terrell@acm.org>
Date: Fri Apr 19 16:03:02 2013 -0400
adding root-level file to sub-project
Here are my questions (finally): 以下是我的问题(最后):
--force
option is the answer, how can I be certain I am not doing something destructive?) (如果使用--force
选项是答案,我怎么能确定我没有做破坏性的事情?) subtree
module to avoid this problem? 有没有更好的方法来使用subtree
模块来避免这个问题? (Note: I'm not willing to use submodules.) (注意:我不愿意使用子模块。) Your problem is not really related to git subtree
. 你的问题与git subtree
无关。 You having problems with the good old tricky git ui. 你有好老的棘手的git ui的问题。 In this case git push
. 在这种情况下git push
。 You obviously assumed that its syntax follows git pull
. 你显然假设它的语法遵循git pull
。 That was rather naive – you are using git ;). 这很天真 - 你正在使用git;)。
You push output tells you what is wrong here: 你推输出告诉你这里有什么问题:
To file:///tmp/git/sub-home
! [rejected] master -> master (non-fast-forward)
git pull sub-remote master
fetches and merges the head of sub-remote/master
into your currently checked-out branch, just as you expected. git pull sub-remote master
取出并将sub-remote/master
的头部合并到当前签出的分支中,就像你期望的那样。 But git push sub-remote master
does not push the head of your checked-out branch into sub-remote/master
. 但是git push sub-remote master
不会将签出分支的头部推入sub-remote/master
。 It does push the branch of the same name. 它确实推动了同名的分支。 So in this case that is master
, as you can see in the output above. 所以在这种情况下是master
,正如你在上面的输出中看到的那样。
From git help push
(syntax is git push <repsitory> <refspec>
): 从git help push
(语法是git push <repsitory> <refspec>
):
The format of a
<refspec>
parameter is an optional plus +, followed by the source ref<src>
, followed by a colon:
, followed by the destination ref<dst>
.<refspec>
参数的格式是可选的+,后跟源ref<src>
,后跟冒号:
,后跟目标ref<dst>
。 It is used to specify with what<src>
object the<dst>
ref in the remote repository is to be updated. 它用于指定要更新远程存储库中<dst>
ref的<src>
对象。The
<dst>
tells which ref on the remote side is updated with this push.<dst>
告诉使用此推送更新远程端的哪个ref。 Arbitrary expressions cannot be used here, an actual ref must be named. 这里不能使用任意表达式,必须命名实际的ref。 If:<dst>
is omitted, the same ref as<src>
will be updated. 如果:<dst>
省略:<dst>
,将更新与<src>
相同的引用。
So the command you are looking for is git push sub-remote splitbranch:master
. 所以你要找的命令是git push sub-remote splitbranch:master
。 But why are you not using git subtree push
in the first place? 但是你为什么不首先使用git subtree push
?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.