1

In my latest commit I did some cleanup in my code, and unfortunately I also introduced a bug.

Now I would like to go back to the previous commit and then bit by bit add the changes from the new commit, so as to see which change is the culprit.

Can I do that in git? If so, how?

  • possible duplicate of [Revert to previous Git commit](http://stackoverflow.com/questions/4114095/revert-to-previous-git-commit) – Madara's Ghost Mar 16 '14 at 09:20
  • 2
    How would Git know how to decompose your commit into meaningful changes, each of which was compilable? – Oliver Charlesworth Mar 16 '14 at 09:21
  • Have you already pushed your breaking commit(s) to the remote repository, or does the offending commit still only exist locally on your computer? – leifericf Mar 16 '14 at 09:21
  • Get diff log, then revert commit and apply diff changes manually. Git can't say if changing one file is enough, or it depend on changes in other file too - at current stage, only human being can. – keltar Mar 16 '14 at 09:23
  • If bit-by-bit is analogous to hunks you can do it with interactive commits. If not though, what you want.... is to get in the habit of frequent, small, atomic commits. – AD7six Mar 16 '14 at 10:25

3 Answers3

1

If you did not push your change, you can do:

git reset HEAD^ # undo the last commit
git add -p      # add some of your changes
git commit      # commit them

Repeat the last two steps as often as you like.

Now you can test the new commits whether they contain the bug. Once you found the buggy commit you can use git rebase -i to remove that commit or fix it.

All of this works fine as long as you did not push your commit, yet. If you already pushed your commit you probably want to revert your commit first and reimplement your feature step by step is small self-contained commits.

michas
  • 25,361
  • 15
  • 76
  • 121
0

Git doesn't track changes "within commits". It sounds like you should use revert to "undo" your offending commit. After reverting, you can reimplement your changes, minus the bugs.

In general, you'll want to make your local commits small and isolated, so that they can easily be reverted and cherry-picked between branches when needed. When a single commit contains loads of unrelated changes, it is hard to "undo" only the buggy parts.

Before pushing to the remote repository, some people use rebase to "squash" commits and clean up their local history; effectively "merging" small, related commits. The remote history is a team asset.

leifericf
  • 2,324
  • 3
  • 26
  • 37
  • Git does indeed track changes "within commits" - a commit (or rather a diff/patch) is made up of hunks which you can e.g. [selectively stage](http://git-scm.com/book/ch6-2.html). – AD7six Mar 16 '14 at 10:30
  • What I meant by "doesn't track changes within commits" is that Git does not keep track of the history of a file on subsequent "OS-level saves", unless you stage and commit something. I.e. you can change a file, save it (`File -> Save`), then edit and save the file again (without staging or committing anything in Git); changing a file multiple times, without involving Git. A Git commit does not include all those "local working revisions" of a files content. – leifericf Mar 16 '14 at 12:23
0

You could use git checkout <commit> -- <files> and git gui to easily retrieve part of the commits.

More precisely, a handy way to do it could be:

git tag ref #to easily point to this commit later
git revert ref #revert the bug

#Start retrieving you changes
git checkout ref -- . #The files have the modifications but aren't modified
git gui # Select only a bit of the modifications, discards the others, and commit
git commit -m "Retrieved part of my modification"

#Continue
git checkout ref -- .
git gui #Incorporate some other modifications
git commit -m "Retrieved part of my modification 2"

# and so on...
gturri
  • 13,807
  • 9
  • 40
  • 57