1

I did something bad.. I dont know what i did, but i now have two commits with no parent. As far as i know I am only supposed to have one, which is the initial commit.

Whenever i do a blame, all changes before the funky commit points to commit 2139f47.

This is the funky part of my reflog:

...
49d0d22 HEAD@{313}: commit (merge): unused questions widget removed
2139f47 HEAD@{314}: commit: unused questions widget removed
e548c10 HEAD@{315}: commit: unused questions widget removed
e7d174b HEAD@{316}: pull: Fast-forward
...

The internal linking looks something like this:

  HEAD
   |
  ...         e548c10
   |             |
49d0d22 -----+   |
   |         |   |
2139f47     e7d174b
   |           |
  nil         ...
               |
            initial

The contents of the merge commit object (49d0d22) is:

tree c3989e79c49df4b141b080502192bf0be0f67195
parent 2139f479dac242ad2ef757519aef77f3003ca996
parent e7d174bef4ab7e89b96f8c3de3551d0b760c80f8
author Michael Andersen <***> 1345190024 +0200
committer Michael Andersen <***> 1345190024 +0200

unused questions widget removed

The contents of the funky commit with no parent (2139f47) is:

tree 4cfebc6b5a2a525bc255e4e095008b6aa8b106cc
author Michael Andersen <***> 1345189769 +0200
committer Michael Andersen <***> 1345189918 +0200

unused questions widget removed

The contents of the commit that no object seem to points to (e548c10) is:

tree 0ae0960fccee7faec86ce7a82dd30af70f9c225a
parent e7d174bef4ab7e89b96f8c3de3551d0b760c80f8
author Michael Andersen <***> 1345189769 +0200
committer Michael Andersen <***> 1345189769 +0200

unused questions widget removed

So my question is:

Can I cut out the funky commits? and how does this effect origin and the local repos of my fellow coders?

--- edit ---

I dont care about losing some commit objects. As I see it, i need to cut away 2139f47 and e548c10. How do I do that?

Michael Andersen
  • 939
  • 2
  • 11
  • 19
  • You can certainly cut out the funky commit (more precisely, recreate better ones), but it's not obvious what kind of tree you would *like* to have. Another question is: have you pushed your changes to a server shared by others? – user4815162342 Sep 21 '12 at 16:44
  • I edited the question. It is indeed already pushed to origin (shared with a small group of people) – Michael Andersen Sep 21 '12 at 23:00

2 Answers2

2

You can do the following:

  1. Create a commit with a tree identical to 49d0d22, but with a single parent, e7d174b. This is the step that requires a "plumbing" command that is not used every day.

  2. Rebase descendants of 49d0d22 onto this new commit. This makes your HEAD usable again.

  3. Warn your coworkers that you are about to perform a non-fast-forward push. (If the repo is customized to reject non-fast-forward pushes, talk to the repo administrator to temporarily enable it.) Perform the push.

  4. Make sure your coworkers update their trees with git pull --rebase, so they never attempt a merge with your old HEAD. To verify this, ask them to run git merge-base HEAD 49d0d22 after the pull — it should come out empty.

The commands to implement these steps should look like this:

# 0.
git checkout master # or whatever your working branch is called

# 1.
commit=$(git commit-tree -m "unused questions widget removed" -p e7d174b 49d0d22:)

# $commit should now identify the new commit; you should be able to see it
# with git log $commit or any other git inspection tool.

# 2.
git rebase 49d0d22 --onto $commit
# now your HEAD should be in a valid state.
# git merge-base HEAD 49d0d22 should output nothing

# 3.
git push origin master

git checkout master # or whatever your main branch is called

As for the commit e548c10 — just ignore it. Delete local and remote branches that refer to it, and tell others to ignore it as well. Because this commit doesn't refer to 2139f47 in any way, this step is wholly independent of the surgery above.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
1

Use some grafts or a replace to give you repo the right appearance (linkages) and then use a filter-branch to make it permanent.

This assumes that those funky parts haven't already been published with other relying on it.


EDIT A while back I asked how-do-git-grafts-and-replace-differ, are-grafts-now-deprecated? about the two techniques.

In practice I found grafts easier to set up. It is simply a list of commit - parent pairs that you want respected instead of the existing parents listed inside the commit.

This means, for example, you can break a commit chain with a pair that by-passes a bad commit (remember all commits are simply snapshots;-).

In you case you can make any commit appear to be anywhere in the commit chain by adding the necessary links into the grafts file. You can even create 'fake' merges with a graft (two parents on the line).

So create the list (grafts file) that sets out the links you wish to change and it will then appear (look like) just how you want it. At that point you probably want to make it permanent, so simply run git filter-branch to rewrite those parts. Just make sure any colleagues know what is going to happen so they are not 'surprised'.

Community
  • 1
  • 1
Philip Oakley
  • 13,333
  • 9
  • 48
  • 71
  • I'm sorry but i really don't get what you are saying. What is grafts? and what do you mean by appearance (linkages)? – Michael Andersen Sep 21 '12 at 23:03
  • I've updated my answer to indicate how grafts are created and used. – Philip Oakley Sep 22 '12 at 20:25
  • This is the easiest way for me. This way i dont have to redo merges as when rebasing. I need to update the origin repo, and all the local repos will need to do a new clone, but my situation this is acceptable. It would be nice if you could update your post to show the actual grafts file for the example. Just to help out other users. – Michael Andersen Sep 25 '12 at 12:29