3

Is there any way to reset a remote branch pointer to a SHA that you know is in the remote reflog, but that you don't have in your local repo?

I'm very familiar with how reset (soft/mixed/hard) works on a local repo, but that doesn't help me here.

Here's the situation I'm trying to fix. I hadn't done a fetch in a little while and the remote master had been updated with a merge that I didn't have locally yet.

I screwed up and did a git push --force meaning to update only the remote feature branch but forgot an argument and ended up forcing the feature branch AND master to the revisions that I had locally.

This meant that master was now missing a merge commit that had happened since I last fetched. We're using github, so I had an e-mail that told me the SHA that master was at previously. I was also able to go to the url and see that the commit was still there (not garbage collected yet).

I was able to "fix" it by just redoing the merge that I lost and pushing that out again (which ended up changing the SHA because it was a different committer and time). This isn't optimal and could have been much worse if I'd been missing more than one merge commit on master.

What I would have like to have done was just reset --hard the remote master branch to the SHA that it was supposed to be at. Is there any way to do that without SSH access to the repo?

This is on github, so I don't have direct access to the repo to be able to ssh out there and reset it directly.

Ted Naleid
  • 26,511
  • 10
  • 70
  • 81
  • Are you sure that commit hash isn't on your local somewhere? Have you tried checking it out? – Christopher Jul 16 '12 at 05:11
  • Yep, I'm sure. I tried both checking it out as well as checking the reflog and just doing a `git log`, I don't have it. Github allows you to do the merge on the server by hitting a button (and someone else actually hit the button), but if no one does a `git fetch` after that merge is done on github, then github's reflog is the only one that has that commit if you do something dumb like I did. – Ted Naleid Jul 16 '12 at 05:32

3 Answers3

4

I don't think you can access/reset anything on GitHub directly, without asking them.
Ie without contacting GitHub support for them to look in the reflog of your GitHub repo.
They will be able to make that lost SHA1 visible, by making a new branch or resetting it to an existing branch.

Actually, the repo owner can query the GitHub Event API.
See "Does github remember commit IDs?".


The OP Ted Naleid confirms, mentioning this thread (and this one) as a reason:

This is by design.
That is, when you accidentally push secret data, you can rewind your refs on the server.
Even though the objects still live on the server (until they are garbage-collected) nobody will be able to fetch your secret stuff even if they happen to know the SHA1.

Dan Moulding confirms below in the comments of his own answer:

I've done more testing and found that the clone behavior differs depending on the protocol used.

  • Cloning via SSH (and presumably the via the git protocol) behaves as you've described; i.e. unreachable commits are not transferred to the clone.
    Now I've tested it with HTTPS also (using GitHub itself). And it doesn't look good; the clone does not get unreachable objects.

  • Cloning locally, however, all commits -- unreachable or not -- are transferred.

(But the OP clarifies that it is only because, with local clone, by default the files under .git/objects/ directory are hardlinked to save space when possible.
git clone --no-hardlinks file:///Users/yourUser/your/full/repo/path repo-clone-name would no transfer unreachable commits)

Community
  • 1
  • 1
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Thanks, that's what I was afraid of. You can't do it for the same reason that you [can't fetch by SHA](http://git.661346.n2.nabble.com/Fetch-by-SHA-missing-td5604552.html). – Ted Naleid Jul 16 '12 at 15:32
  • The reason that local clone "works" to keep the is because of hardlinks on the local file system they're not actually copied over. If you clone clean with `git clone --no-hardlinks file:///Users/yourUser/your/full/repo/path repo-clone-name` you're replicating the behavior of a remote clone and ensuring hardlinks are gone. It's because of the hardlinks that local clones are so fast (and don't take up as much diskspace). – Ted Naleid Jul 16 '12 at 18:20
  • @TedNaleid Good point. I have included it in the answer for more visibility as well. – VonC Jul 16 '12 at 18:40
3

Have you tried git push --force origin <sha>:master? This should set master on origin to point to whatever SHA you give it, no questions asked.

Mike Sandler
  • 159
  • 2
1

Have you tried cloning your GitHub repo to a new local repository? I believe a clone may include the "lost" objects. You'll then have the "lost" objects in your newly cloned repo. You can do a reset locally, and then push the fixed refs back to GitHub.

Dan Moulding
  • 211,373
  • 23
  • 97
  • 98
  • Thanks Dan, unfortunately that doesn't work. You can't fetch down anything that isn't pointed to by (or an ancestor of) a commit that's pointed to by a branch or a tag. My understanding is that this is a "security feature" of git so that if you accidentally commit something sensitive (like a password) that you can take it out of history and someone can't retrieve it even if they figure out the SHA. I was hoping that github had a workaround that didn't involve contacting a human, but sounds like it doesn't. – Ted Naleid Jul 16 '12 at 15:30
  • @Ted: In a quick test that I did, cloning the repository retrieved objects not reachable from any branches or refs. I don't believe fetching and cloning are exactly the same operation under the covers. Did you try it? – Dan Moulding Jul 16 '12 at 15:46
  • @Ted: I've done more testing and found that the clone behavior differs depending on the protocol used. Cloning via SSH (and presumably the via the git protocol) behaves as you've described; i.e. unreachable commits are not transferred to the clone. Cloning locally, however, all commits -- unreachable or not -- are transferred. I'm not sure about cloning via HTTP, as I can't as readily test that. – Dan Moulding Jul 16 '12 at 15:58
  • @TedNaleid: Now I've tested it with HTTPS also (using GitHub itself). And it doesn't look good; the clone does not get unreachable objects. Indeed, it looks like manual intervention from GitHub support staff is the only solution. – Dan Moulding Jul 16 '12 at 16:22
  • Interesting. I have included your tests in my answer for more visibility. – VonC Jul 16 '12 at 17:25