How to save changes when in detached-head state?

Nikolas picture Nikolas · Jun 22, 2015 · Viewed 9.9k times · Source

Working with Git, I had to go back to a specific commit. I made some changes and I now want to commit them. What is a proper way of doing this?

My project is now in detached-HEAD state. Will my changes be saved if I make a commit with

git commit

? Otherwise, what should I do to not lose my changes?

Answer

RJFalconer picture RJFalconer · Jun 22, 2015

Disclaimer: git isn't complicated, it's just versatile. Don't be scared off just because I've rambled into a long answer :)

You had:
master: a-b-c-d-e-f

and wanted to change c. You did:
* git checkout c (avoid checking out commits in future. Move the branch head instead)
* changed some files

You are in:

master: a-b-c-d-e-f
             \uncommitted-work,detached

If you want to re-apply d-e-f on top of your changed "c"

(If you have pushed, people downstream will be have to recover from upstream rebase)

  1. git stash .
  2. git checkout master
  3. git stash pop (resolve conflicts)
  4. git stage .
  5. git commit -m "temporary name for g"
  6. (master: a-b-c-d-e-f-g)
  7. git rebase c -i ("re-apply my current branch on to point c, and let me manipulate the commits interactively", i.e, re-parent (rebase) d-e-f onto a new c)
  8. Follow guide to interactive rebase. You want to re-order g so it's after c, then change the rebase command from pick to fixup. dd to delete a line, P to place it, i to enter insert mode to type "fixup" then :wq to save and exit vim.
  9. (master: a-b-c'-d'-e'-f', where c' is the result of you merging g and c during the rebase. d-e-f have become d'-e'-f' as their ancestry has changed so they're not the "same" commits as far as git is concerned, but their contents remain the same)

If you want to undo d-e-f (and rewrite history as if you never made them)

(If you have pushed, people downstream will be have to recover from upstream rebase) :

  1. git stash .
  2. git checkout master
  3. (master: a-b-c-d-e-f, with stashed files originally based upon c)
  4. git reset --hard c (discard all files and commits on master since c)
  5. (master: a-b-c, with stashed files)
  6. git stash pop (resolve conflicts)
  7. (master: a-b-c-*)
  8. git stage .
  9. git commit -m "description of g"
  10. (master: a-b-c-g)

If you want to undo d-e-f (but keep them in history)

  1. git stash
  2. git revert --no-commit d
  3. git revert --no-commit e
  4. git revert --no-commit f
  5. git push
  6. git stash pop (will be no conflicts)
  7. git stage .
  8. git commit -m "Undo d-e-f in order to fix..."
  9. git push

If you have git push d-e-f, and you want to keep them separate:

Sounds like your new changes are for a new branch off master. git branch <foo>.