Undoing temporary changes with Git

Say, I’m on ‘master’ and have a blob:


Now I start debugging in a new branch…

  • Why isn't 'git bisect' branch aware?
  • using git to compare one file from two commits
  • Getting the subversion repository number into code
  • How do I debug a large git commit?
  • Why NetLogo add + 1 twice - when it is not expected?
  • Cross version line matching
  • DEBUG = TRUE # Don't forget to turn off!
    CACHE_SIZE = 0 # Don't forget to set back to 100!

    … fix some bugs, change some code… and merge my fixes back into ‘master’. But unfortunately I have forgotten to return these “don’t forget”-s to the original value.

    How can I automate the process of returning some lines back to the original value? Or at least shorten it to a single command.

    Maybe, some temporary commit, or stash, or some other technique?

  • How to use git over custom ssh software?
  • How to get diff working like git-diff?
  • Git not picking up sub-command in path
  • Cannot build app when using gradle (Android Studio) and local maven repo
  • Jenkins and updating git submodules
  • git merge manipulates the history
  • 3 Solutions collect form web for “Undoing temporary changes with Git”

    Cameron has some good ideas for shorter term debug changes. I wanted to add a common one that works even for larger or more permanent sets of local debug changes, like if you commonly make the same “don’t forget” changes every time you add a feature. I’ve heard it called a loom, quilt, stacked branches, and a pipeline. You can find plugins with those names to help maintain this kind of workflow, but there are subtle differences between them I’ve never really grasped, and the technique is not too difficult to do manually.

    The basic idea is you add another branch between master and feature, let’s call it debug. You make all your “don’t forget” changes in that branch, then branch off again from debug to make feature, which contains all your changes that will go into production as normal. Then, to remove all your “don’t forget” changes in feature, do:

    git rebase --onto master debug feature

    That makes it look like you branched straight from master and never added the changes in the debug branch. Then you merge into master like normal. The next time you want to add a feature, you just merge master into debug and your “don’t forget” changes are automatically reapplied to the latest upstream code. Then just create a new feature branch from debug and the cycle starts again.

    Obviously, you still have to remember to do the rebase before merging into master. Cameron’s hook idea can be used to prevent merges if you forget.

    There’s probably no way to automate rollback of particular lines (since Git doesn’t really have any knowledge of the semantics of file contents), but there are a number of ways you can stop this happening again in future.

    1. Make sure you always inspect the diffs before committing. git diff /path/to/file will show you the changes and you can look for “Don’t forget to…”.
    2. You could automate this a little bit with grep: git diff | grep "Don't forget"
    3. You could even have a hook that checks for a regular expression (e.g. “Don’t forget”) and forbids commits that match. This could be in your local repository or in the repository you’re pushing to.

    Option 2 is probably the easiest. It still takes a bit of discipline – you need to make sure you always put “Don’t forget” (or “TODO”, or “FIXME” or whatever) in the comment and you need to run git diff | grep, but that’s not a lot of overhead.

    Option 3 will make it easier in the long term to prevent this problem, especially if you are part of a team. Of course, anyone can change the comment to “Do not forget” (or just remove the comment altogether) and bypass the check, but it’s better than nothing.

    Some users eschew the Git’s index (e.g. by always using git commit -a and only using git add to introduce new files), but I find the index quite useful for cases like this.

    The idea is to never commit your “debug” changes in the first place.

    1. I run git diff to review the changes that I can stage (i.e. the diff between the index and the working tree).

      1. For files that do not have any “debug” changes, I use

        git add <pathspec> …

        to stage the changes to those files.

      2. If some files have both “debug” and intended changes, then I use

        git add -p <pathspec> …

        on those files to skip all the “debug” hunks.

        If a hunk has both “debug” and intended changes, then I use the split and/or edit commands in git add -p to only stage the intended changes.

    2. Before committing, I use git diff --cached to carefully review the staged changes (i.e. the diff between HEAD and the index).

      • If a “debug” change made it into the final index, then I use

        git reset -p <pathspec> …

        (possibly using its split or edit commands) to discard the “debug” changes from the index.

    Note: If you do testing directly from your “debug” working tree, you should be aware that you are always testing with your “debug“ changes in place. In some code bases the presence of certain “debug” changes can significantly change the behavior of the system under test. If it is important to your team that no published commit ever fails a test, then you should take the time to test exactly what you committed (without the debug changes).

    You can use git stash after every commit to stash your “debug” changes, rebuild, and test exactly what you committed. Once the testing is finished you can git stash pop to restore your “debug” changes to your working tree.

    git reset -p was first available in Git 1.6.5 (also git checkout -p and git stash -p). git add -p was first available in Git 1.5.4.

    Git Baby is a git and github fan, let's start git clone.