Lachlan Cotter
Lachlan Cotter

Reputation: 1889

How did my git branch forget its parent?

I created a git feature branch in the usual way:

git checkout develop
git checkout -b new_feature_branch

When the time came to merge the feature back into the main development branch, the merge produced a huge amount of conflicts (way more than expected since the main line hadn't changed very much).

On investigation, it appears that my feature branch has somehow managed to become orphaned from it's parent. The first 24 commits to this branch are missing from the history, as is the initial fork from the main line.

I know it's exactly 24 commits because they are listed in git reflog --all | grep new_feature_branch.

Since these early commits are missing, the branch now seems to begin with a duplicate of the entire repository that produces a lot of conflicts when I try to merge it back into development.

How did this happen?

How can I recover the missing commits?

Upvotes: 2

Views: 1560

Answers (3)

Lachlan Cotter
Lachlan Cotter

Reputation: 1889

Okay, so here's what I did to fix it:

  1. Run git reflog --all | grep <new_feature_branch> to get a full list of commits on the feature branch, including the early commits that were missing in the history.
  2. Open .git/logs/HEAD and search for the oldest visible commit to find the full SHAs of its original parent (hat tip).
  3. Checkout the parent commit (the one that is now lost from the branch's history) and then checkout a new 'recovery' branch from this commit to create a new base. After doing this, the 'lost' commits reappeared in the tree as part of the recovery branch, properly forked from the develop branch.
  4. Run git cherry-pick <SHA> with the oldest commit from the 'orphaned' branch to copy the base of that branch onto the tip of the recovery branch. Resolve merge conflicts.
  5. Checkout the orphaned branch.
  6. Run git rebase --onto <new-parent> <old-parent> where new-parent is the commit I just copied onto the recovery branch, and old-parent is the oldest commit on the orphaned branch which I copied that commit from. The full branch history was successfully transplanted with minimal conflicts.

Upvotes: 0

Philip Oakley
Philip Oakley

Reputation: 14071

To recover, simply use either a graft or a replace which allows you to re-specify the parents of the base(root) of your orphaned branch.

If you do not need to keep your feature branch once it has been merged, then a simple one off graft could be sufficient for you to see the right branching structure.

However the parent linkage at the merge will still keep the orphaned branch and your repo will the have two root commits [probably not what you desire].

The simple improvement is to do a rebase (of your orphan onto its proper branch point) or a filter-branch after the graft.

It sounds like you had accidentally checked out the specific commit at the original branch point rather than creating a branch (tip) so that you had a detached HEAD situation, and did your fix ups in an inappropriate order after some error message - it's easy to do.

Upvotes: 0

Useless
Useless

Reputation: 67772

How did this happen?

  • you branched from develop - are you sure your local copy of this (as opposed to say origin/develop) was up-to-date when you branched?
  • is develop definitely the parent branch you wanted (not master or something else)?
  • did you rebase develop after branching? This could have rewritten the parent commits in develop's but not in new_feature_branch's, history.
  • did you rebase new_feature_branch at some point, and accidentally re-write the parent commits prior to your branch point that way?

How can I recover the missing commits?

Just rebase your branch onto the desired branch point (see this question, or this book, etc.)

Upvotes: 2

Related Questions