4

I have a larger git repository (A) that shares a certain amount of code with another project (B) of mine. To make maintenance easier, I decided to have a third repository with the common code (C) which will then be used via git subtree.

I prepared everything in A (putting the common code in folder "sub") and used the procedure described in Detach (move) subdirectory into separate Git repository to create C

Now that I have C with just a few commits, I wanted to put it back into A, folder sub. I used the approach described in http://www.kernel.org/pub/software/scm/git/docs/howto/using-merge-subtree.html which worked insofar as all commits for the subfolder were now duplicated. I didn't quite mind this, however now I am stuck with no idea how to continue working with this subdirectory.

I made additional changes in A/sub which I want to push to C. As described in git subtree push changes back to subtree project I used

git subtree split --prefix sub -b split-branch

to create a branch with just the subtree. This takes a bit of time, but finishes successfully. Doing

git checkout split-branch
git push remote-c master

gives me

failed to push some refs to "remote-c"
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.

but a git pull remote-c master says I'm already up-to-date.

How do I resolve this situation?

EDIT1: I tried to reproduce the problem with a small test script. Executing this script:

( cd testC; git init --bare )
( cd testA; git init )

cd testA
git remote add C ../testC

mkdir sub
echo subFile1 > sub/subFile1
echo subFile2 > sub/subFile2
git add sub
git commit -m "adding files"

echo FileA > fileA
echo FileB > fileB
git add fileA fileB
git commit -m "add root level files"

# extract subtree and push to C
git subtree split -P sub -b split-branch
git push C split-branch:master

# try to make an update in C
git checkout -b cmaster C/master
echo subFile2new > subFile2
git commit subFile2 -m "updated #2 in C"
git push

This results in

To ../testC
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to '../testC'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. If you did not intend to push that branch, you may want to
hint: specify branches to push or set the 'push.default' configuration
hint: variable to 'current' or 'upstream' to push only the current branch.
Community
  • 1
  • 1
Frankie
  • 653
  • 1
  • 9
  • 20
  • If I'm understanding what you're trying to do, I think a `git` submodule is a better solution than constant subtree merging/extracting. – twalberg Sep 25 '12 at 20:39
  • I'd rather go back to CVS than using git submodule ;-) I tried this once and I still got nightmares. – Frankie Sep 25 '12 at 20:43
  • FYI, http://codingkilledthecat.wordpress.com/2012/04/28/why-your-company-shouldnt-use-git-submodules/ describes some of my issues with submodules. – Frankie Sep 26 '12 at 06:05
  • http://codingkilledthecat.wordpress.com/2012/04/28/why-your-company-shouldnt-use-git-submodules/ is indeed a good article, that I reference in http://stackoverflow.com/a/12078816/6309 and http://stackoverflow.com/a/12123311/6309, I would still recommend them in your case though – VonC Sep 26 '12 at 07:03
  • We did try submodules a while ago for a similar approach. This so terribly backfired that nobody wants to touch submodules ever again. The issue is that my project involves a lot of people with limited experience in git (sometimes any VCS) and submodules require a bit of a gentle hand. Apparently subtrees as well ;-) While in theory submodules are perfect here, their disadvantages are too high for us to be acceptable. – Frankie Sep 26 '12 at 07:08

3 Answers3

1

I tried a git push -f which seems to have worked. Still would like to know what exactly happened and why.

Frankie
  • 653
  • 1
  • 9
  • 20
0

The default behavior of git push is to try to push all branches to the current branch remote if you have same named branches locally and remotely. From the git push manual:

The special refspec : (or +: to allow non-fast-forward updates) directs git to push "matching" branches: for every branch that exists on the local side, the remote side is updated if a branch of the same name already exists on the remote side. This is the default operation mode if no explicit refspec is found (that is neither on the command line nor in any Push line of the corresponding remotes file---see below) and no push.default configuration variable is set.

In this case, since your current remote is C and you have both locally master and remotely C/master it will be pushed, and since the trees will not match at all the push will fail with the master -> master (non-fast-forward) message.

When you git pull to your branch it says up-to-date because you are pulling yo your current branch, which is up to date.

To modify this behavior of git push you need to setup the push.default value in your git config. Look for "push.default" in http://www.kernel.org/pub/software/scm/git/docs/git-config.html

Maic López Sáenz
  • 10,385
  • 4
  • 44
  • 57
0

My solution: upgrade git. :-)

Your test script succeeds for me, assuming the testA and testC directories already exist. I'm using the latest version of git (v1.8.2.1), so perhaps they fixed something since you posted this.

$ mkdir testA testC
$ ./test.sh 
Initialized empty Git repository in /tmp/git/testC/
Initialized empty Git repository in /tmp/git/testA/.git/
[master (root-commit) 3d5644d] adding files
 2 files changed, 2 insertions(+)
 create mode 100644 sub/subFile1
 create mode 100644 sub/subFile2
[master 398c203] add root level files
 2 files changed, 2 insertions(+)
 create mode 100644 fileA
 create mode 100644 fileB
Created branch 'split-branch'
57fe3e8fc226d854b623f11444d82dc77fd45682
Counting objects: 4, done.
Delta compression using up to 16 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 269 bytes, done.
Total 4 (delta 0), reused 0 (delta 0)
To ../testC
 * [new branch]      split-branch -> master
Branch cmaster set up to track remote branch master from C.
Switched to a new branch 'cmaster'
[cmaster 07c7c89] updated #2 in C
 1 file changed, 1 insertion(+), 1 deletion(-)
Counting objects: 5, done.
Delta compression using up to 16 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 285 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To ../testC
   57fe3e8..07c7c89  cmaster -> master
Jeff Terrell Ph.D.
  • 2,563
  • 26
  • 39