views:

961

answers:

7

I have a local Git repository I've been developing under for a few days: it has eighteen commits so far. Tonight, I created a private Github repository I was hoping to push it to; however, when I did so, it only ended up pushing eight of the eighteen commits to Github. I deleted the Github repo and retried, with the same result.

Any thoughts on why this might be happening? I've done this procedure before without a few times successfully, so I'm a bit stumped.

Update: There is, and has always been, only the master branch in this repo. Just to address a few of the posted answers...

+1  A: 

I suppose the first thing I would do would be to run git fsck on your local repository to make sure that it is all in good order.

I've never seen this problem before, and I can't think of what might be wrong.

Greg Hewgill
+2  A: 

Check if you are pushing the correct branches, and that the branches actually have what you think they have. In particular, check if you do not have a detached HEAD, which can be quite confusing if not done on purpose.

The easiest way to check is to use gitk --all, which shows graphically all the branches, the HEAD, and more.

CesarB
A: 

So, it turns out that both: the commit hash in .git/refs/heads/master was in correct and the information in .git/logs/refs/heads/master was incomplete; in that I mean it only went up to and included the commit hash specified in .git/refs/heads/master.

Once I fixed these files (by hand), and pushed back to Github, everything was gravy again. I still have no idea what happened to get things in this state, but I'm glad I've at least figured out the fix.

In case anyone is wondering: to fix .git/refs/heads/master, I just replaced the content of that file with the latest commit hash (HEAD), and to fix .git/logs/refs/heads/master, I simply copied the contents of .git/logs/HEAD into .git/logs/refs/heads/master. Easy peasy... NOT.

rpj
You probably have, as I mentioned in my answer, a "detached HEAD". Check .git/HEAD; if it does NOT have "ref: refs/heads/master" (or another ref: line), you have a detached HEAD, and your commits will go to no branch, only to the HEAD.
CesarB
And, by the way, if you do have a detached HEAD, you only fixed the symptoms, and all your new commits will keep going to the HEAD only. IIRC, the way to get out of that situation is to checkout a branch ("git checkout master"), which will set the HEAD to point to that branch.
CesarB
+12  A: 

I took a look at the repository in question and here's what was going on:

  • At some point, rpj had performed git checkout [commit id]. This pointed HEAD at a loose commit rather than a recognized branch. I believe this is the "dangling HEAD" problem that CesarB is referring to.
  • Not realizing this problem, he went on making changing and committing them, which bumped HEAD up every time. However, HEAD was just pointing at a dangling chain of commits, not at a recognized branch.
  • When he went to push his changes, git pushed everything up to the top of master, which was only about halfway through the current tree he was on.
  • Confusion ensued

This diagram should make it more clear:

                 -- D -- E -- F
                /             ^
   A -- B -- C -              |
   ^         ^               HEAD
   |         |
 remote    master

When he tried to push his changes, only A through C were pushed and remote moved up to C. He couldn't get commits D through F to push because they aren't referenced by a known branch.

Here's what you see when you're in this state:

$ git branch
* (no branch)
master

The solution is to move master up to F in the dangling chain of commits. Here's how I did it.

  • Create a legitimate branch for the current state:

    git checkout -b tmp

    • The tmp branch is now pointing at commit F in the diagram above
  • Fast-forward master to tmp

    git checkout master

    git merge tmp

    • master is now pointing at commit F.
  • Throw away your temporary branch

    git branch -d tmp

  • You can happily push to the remote repository and it should send all of your changes.

farktronix
This approach is fine if you want to be cautious; if you *know* that the merge is going to fast-forward, then you can just delete and recreate the branch. See my answer.
Aristotle Pagaltzis
You're right- if it's not a fast forward you'll end up with a slightly different tree, but you should still get the same end result. However, your answer is much simpler.
farktronix
+1  A: 

I don't have the reputation to comment directly on CesarB's earlier answer, but gitk --all doesn't work in this case because it only lists out known branches.

gitk HEAD shows this problem, but it's not entirely clear. The smoking gun is that master shows up down the commit tree rather than at the most recent commit.

farktronix
+3  A: 

A very simple approach for fixing this sort of problem is to just delete the master branch and recreate it. After all, branches in git are merely names for commits and the master branch is nothing special.

So assuming that the current commit is the one you want master to be, you simply do

git branch -D master

to delete the existing master branch, then do

git checkout -b master

to a) create a new branch called master that points to the current commit and b) update HEAD to point to the master branch. After that, HEAD will be attached to master and therefore master will move forward whenever you commit.

Aristotle Pagaltzis
A: 

I've had this same problem twice, and finally figured out what I was doing that was causing it. In the process of editing an old commit with git rebase -i, instead of calling git commit --amend, I was calling git commit -a by force of habit, immediately followed by git rebase --continue, of course. Someone else might be able to explain what's going on behind the scenes, but it seems that the result is the detached HEAD problem.

Matthew Maravillas