20

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?

jub0bs
  • 60,866
  • 25
  • 183
  • 186
Nikolas
  • 2,322
  • 9
  • 33
  • 55
  • 1
    *I made some changes and now want to save them.* Please be more specific: what do you mean by "save"? You mainly have two options: commit, or stash. Either one will "save" your changes in some sense. Which are you referring to? Also, you may want to create a branch. – jub0bs Jun 22 '15 at 15:12
  • I want to commit my changes. – Nikolas Jun 22 '15 at 15:15
  • I've edited your question accordingly. – jub0bs Jun 22 '15 at 15:17
  • 1
    What do you want to happen to the older commits that are ahead of you? I.e, you went "back" to a commit so there's some commits "in front" of that commit. Do you still care about those? (and have they been pushed upstream to other people, and do you care about those people) – RJFalconer Jun 22 '15 at 15:36
  • I want to merge "in front" commits with this which in detached head state. There are some errors "in front" that's why I back to previous commit. – Nikolas Jun 22 '15 at 15:47
  • I think you want to re-apply existing "in front" commits over a changed parent commit . Does that sound right? Sounds like you want `git rebase -i`, then follow [guide to interactive rebase](https://help.github.com/articles/about-git-rebase/) – RJFalconer Jun 22 '15 at 16:07

4 Answers4

45

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>.

RJFalconer
  • 10,890
  • 5
  • 51
  • 66
8

Create a new branch from this commit and THEN do the commit:

git checkout -b <branchname>
git commit 

Assuming you already staged (i.e. git add myfile1 myfile2) your files.

Яois
  • 3,838
  • 4
  • 28
  • 50
5

to save your work in the detached head:

git checkout -b <new-branch-name-for-detached-head> <sha-of-the-detached-head>

and if you want to merge it to master:

git checkout master
git merge <new-branch-name-you-have-just-created>
John Dow
  • 177
  • 3
  • 14
0

If you are in 'detached HEAD' state because of checking out a tag (git checkout tags/<tag-name>), then you want to create a new branch to retain commits you create, by using -c with the switch command.

git switch -c <new-branch-name>
arikan
  • 1,023
  • 8
  • 6