3

Note: I know this is rewriting history, will change all the hashes, and mess everyone else up.


I want to take a commit, and remove its parent. Specifically, the commit should now look like an initial commit. That means its diff will change; it will look as though all the files were created by that commit, at that point in history.

How does one do this? (I could, of course, go edit the commit object, but then the commits wouldn't point to each other.) Also, I would like to do this on a new branch (meaning that there are now two histories: the original one, and another where the commit is the initial commit.)

jub0bs
  • 60,866
  • 25
  • 183
  • 186
PyRulez
  • 10,513
  • 10
  • 42
  • 87
  • If you want to totally disconnect the commit from its parent and have no history, why not just copy over all of the files and create a new repo? – elixenide Jan 28 '16 at 03:10
  • @EdCottrell because I want it's children/descendants to survive. – PyRulez Jan 28 '16 at 03:11
  • So, I'm not 100% sure this will help -- I'm more a Mercurial guy than a git one -- but see http://stackoverflow.com/questions/9844082/how-to-create-a-new-git-repository-from-an-existing-one – elixenide Jan 28 '16 at 03:14
  • @EdCottrell nope, sorry mate. This is rewiring history. – PyRulez Jan 28 '16 at 03:15
  • 1
    To clarify - you want to make your selected commit be the root (losing everything 'before' that)? Otherwise I'm not sure what you are asking. – M.M Jan 28 '16 at 03:41
  • If that is indeed what you are asking, [see here](http://stackoverflow.com/a/14630424/1505939). Assuming there are no merges after the commit in question of course, in which case you're out of luck – M.M Jan 28 '16 at 03:41
  • 1
    also [see here](http://stackoverflow.com/questions/14043961/git-squash-history-after-merge) for how to use `git replace` to hide the history, if your motivation is that you don't particularly care about older commits and don't want them to clutter the output of tools – M.M Jan 28 '16 at 03:43

4 Answers4

2

git rebase -i HEAD~

Then in the editor that pops up after the above terminal cmd Change the start of child commit line from pick to squash. Or 'p' and 's' respectively. Write the file and exit the editor that appeared upon the above command

Edit: Assuming the two commits are the most recent. If not then you can check out the child's child commit hash and use git rebase -i HEAD~2 instead

Edit2: or you could just git rebase -i parentcommithash and the top of the list should be the parent

bgarcia
  • 154
  • 6
2
git checkout -b newbranch
git rev-parse @ >.git/info/grafts   # any equivalent for @ will work e.g. HEAD or newbranch
git filter-branch
rm .git/info/grafts

(edit: added the rm. Without that, this repo will still reflect the grafted ancestry for the original commit)

jthill
  • 55,082
  • 5
  • 77
  • 137
1

Let's say you want your new initial commit to be 123456.

git checkout -b new_master
git filter-branch --commit-filter '
  if git merge-base --is-ancestor 123456 $GIT_COMMIT ;
  then
   git commit-tree "$@";
  else
   skip_commit "$@";
  fi' HEAD

Todo (for anyone): Edit in an explanation

PyRulez
  • 10,513
  • 10
  • 42
  • 87
0

It seems what you want is to squash all commits since your initial commit up until (and including) the commit you want to be the new initial commit.

You can do this with git rebase --interactive --root. This will give you a todo file with all commits. Then go on and edit all the commits from the second to squash, it would look something like this:

pick <hash> initial commit
squash <hash> want change but not commit
squash <hash> want change but not commit
squash <hash> want change but not commit
squash <hash> want change but not commit
squash <hash> this will be new init
pick <hash> this will be the second commit
pick <hash> and so on...

You will be prompted to write the commit message for the resulting squash.

joegomain
  • 536
  • 1
  • 5
  • 22