8

We are having an issue with our GitHub repository. I shall explain our workflow:

Developers create feature/bug fix branches from the mainline branch. They pull request their changes to get it merged back in. They may rebase from the mainline branch to get the latest updates from that as they work. After a rebase they push --force on their feature branch.

Two pull requests were automatically merged using the GitHub web interface recently. Subsequently - about two days after the merge of the request - it was discovered that the changes in these commits were not in the code. Nothing in the history suggests that these changes were reverted or overwritten. The merges themselves do not appear in the commit history and the individual commits themselves do not appear either. But the pull request was successfully merged. One of the missing commits is no longer available to cherry pick. We get a fatal - bad object message when we try.

We suspect some rewriting of history has happened. How can we find out and how can we prevent this from happening. Is there something fundamentally wrong with our workflow?

Daniel Jones
  • 97
  • 1
  • 2
  • 4
    Have you inspected the reflog around the time that this happened? There might be some clues in there as to what is going on. Generally though, force push is considered a bad idea. If they force-pushed to the feature branch after the merge, I'm not sure what would happen, though I would think that it shouldn't lose the commit on the master branch. Methinks someone has accidentally force-pushed to the mainline - can't see any other obvious way that could happen. – MattJenko Nov 17 '12 at 11:57
  • I've emailed Github recently due to similar issue (one of the fellow devs force-pushed without asking anyone) to ask whether it's possible to disallow force push in Github repo, they said it's not configurable now, but if we've lost some commits, we can contact GH to ask for help to recover them. Normally all orphaned commits should be in the reflog in GH as well as the local repo of the dev who intitiated the pull request -- until garbage collected automatically or manually. – jakub.g Nov 17 '12 at 19:17
  • See here for similar thing: http://stackoverflow.com/questions/5094524/github-prevent-colaborator-from-push-f Seems GitHub is not very keen to implement it. For the future you can either 1) have intermediary repo, receiving things, with various hooks set up, which will push to Github when all fine, 2) Restrict number of persons allowed to push to central repo (perhaps only 1 person, rotating each week etc.). I'm aware this answer may not be satisfactory. – jakub.g Nov 17 '12 at 19:26
  • Thanks all for the speedy responses. We do try to implement a workflow whereby all mainline commits are pull requested and only certain people can action those. I guess our real concern is how to identify that this is what happened and also the best way to recover? Even if we decided to use forking and have a separate repository we would still have the situation where a seemingly innocuous pull request was merged without any issues and then subsequently the commit for that pull request and indeed the code in it go missing. I will contact GH for guidance. – Daniel Jones Nov 19 '12 at 10:00
  • OP has decided to ask GitHub support directly – random Aug 21 '13 at 02:59
  • How did you do the git rebase? – Малъ Скрылевъ Nov 27 '13 at 09:19

1 Answers1

3

The problem you are facing has to do with your developers rebasing from the main branch then force pushing their branches. What git rebase actually does is it uncommits all the changes you did, merge the main branch, then re-applies your commits (as if they are patch files). This would create a completely new git commit with a completely new hash.

In short, the old commit was lost, and a new identical commit was created.

That is why it is extremely discouraged to rebase any work that is public, because you are effectively changing history. Any people that branched from your work will have a very bad day if their work is based on changes that are no longer available.

edit: the commit is not lost per se, it still exists in your repo. However, it is no longer available on the branch at hand

Faisal
  • 19,358
  • 4
  • 30
  • 33
  • Well, no. It doesn't "uncommit", and that's not why pushing a rebased branch is discouraged. – jthill Dec 23 '13 at 19:53
  • @jthill: care to elaborate more? you just negated what I said and didn't explain why what I said is wrong. Also, http://git-scm.com/book/ch3-6.html, the perils of rebasing part explains it in the same way I did. Maybe I missed something? – Faisal Dec 23 '13 at 20:04
  • Their explanation isn't the same as yours. The word "uncommit" which you use never appears there, and your answer has even stronger implications than the already somewhat-overstated description there. All the older commits are still in your repo after a rebase, they're *not* lost. – jthill Dec 23 '13 at 20:24
  • "it uncommits" --- it leaves it in the DAG. So the original changeset is still available until garbage collected. It's not reachable from any head, but available as soon as you know its changeset id. – zerkms Dec 24 '13 at 05:13
  • "Also, git-scm.com/book/ch3-6.html, the perils of rebasing part explains it in the same way I did" --- I don't see anything about deleting (uncommitting) the original changesets in the article. Any particular words? Even more: on the image http://git-scm.com/figures/18333fig0329-tn.png they still have `C3` changeset in the graph. – zerkms Dec 24 '13 at 05:16