Git : Undoing Changes

Since Git has so many components, “undoing” can take
on many different meanings. For example, you can:

  • Undo changes in the working directory
  • Undo changes in the staging area
  • Undo an entire commit
    • Unmodifying a Modified File

    • What if you realize that you don’t want to keep your changes you just did to your files in your working directory ? How can you easily unmodify it — revert it back to what it looked like when you last committed (or initially cloned, or however you got it into your working directory)? Luckily, git status tells you how to do that, too.

      • Running git status after modifying a file gives the following result :
        # On branch master
        # Changes not staged for commit:
        #   (use "git add ..." to update what will be committed)
        #   (use "git checkout -- ..." to discard changes in working directory)
        #
        #	modified:   ex2.py
        #
        
      • It tells you pretty explicitly how to discard the changes you’ve made.
        On the terminal, within your project directory, Run :

        git checkout -- <filename> 

        Example :

        ~$ git checkout -- ex2.py
    • Unstaging a Staged File

    • Unstaging, in other words, means Undoing ‘git add’. Once you have added the files using git add, say I added ex2.py, how can I revert it ?
      The command to undo git add is :

      git rm --cached <filename>

      Example:

      ~$ git rm --cached ex2.py 
    • Changing Your Last Commit

    • One of the common undos takes place when you commit too early and possibly forget to add some files, or you mess up your commit message. If you want to try that commit again, you can run commit with the –amend option:

      ~$ git commit --amend

      This command takes your staging area and uses it for the commit. If you’ve have made no changes since your last commit (for instance, you run this command immediately after your previous commit), then your snapshot will look exactly the same and all you’ll change is your commit message.( You can edit the message the same as always, but it overwrites your previous commit ).
      Now, for an example, if you commit and then realize you forgot to stage the changes in a file you wanted to add to this commit, you can do something like this:

      ~$ git commit -m 'initial commit' 
      ~$ git add forgotten_file
      ~$ git commit --amend

      All three of these commands end up with a single commit — the second commit replaces the results of the first.
      Similarly,

      To remove a file from last commit

      Run :

       ~$ git rm--cached <filename> 
      ~$ git commit --amend
    • Undoing the Commits

    • Undoing the commit is little different from the changing the commit using –amend option. Undoing the commit completely reverts the changes made by the specific commit.
      One way to undo a commit is :

      • Use the following command :
        ~$ git reset HEAD~1

        OR

        ~$ git reset --soft HEAD~1
      • The HEAD~1 syntax parameter specifies the commit that occurs immediately before HEAD (likewise, HEAD~2 refers to the second commit before HEAD). By moving the HEAD reference backward, you’re effectively removing the most recent commit from the project’s history.

      • Another way to undo the commits is Reverting. To remedy the problems introduced by resetting public commits, Git developers devised another way to undo commits: the revert. Instead of altering existing commits, reverting adds a new commit that undoes the problem commit:
        ~$ git revert 
      • where the commit-id is the SHA of your desired commit that can be seen using ‘git log’ command.
        This command takes the changes in the specified commit, figures out how to undo them, and creates a new commit with the resulting changeset.

      • Undoing the ‘Undid’ Commit

      Confused ? What I mean here is, what if you undid a commit and realize later that the undid commit was supposed to be there, what then ? In other words, how to undo an ‘undid commit’ or how to undo ‘git reset HEAD’ ?
      Here’s the solution that comes to your rescue. Run the following set of commands :

      • ~$ git reflog show master
      • where master can be replaced by your desired branch.

      • ~$ git reset 
      • where sha is the SHA of your desired commit you want to go to and find its SHA using git log command.

Git : Ignoring Files

Did you ever accidentally push the compiled files( like .pyc files), log files or the executable files(.exe files) or files( such as settings.py ) that you never intend to ?
If yes, then here’s the solution to your problem.

Just ignore the files you do not ever want to push. Hey ! hey ! this isn’t a normal ignore. What actually comes to your rescue is ‘gitignore’.

Creating a .gitignore file

If you create a file in your repository named .gitignore, Git uses it to determine which files and directories to ignore, before you make a commit.

A .gitignore file should be committed into your repository, in order to share the ignore rules with any other users that clone the repository.

  • In Terminal, navigate to the location of your Git repository.
  • Run
    ~$ touch .gitignore

    This creats a .gitignore file.

Now that you have created a .gitignore file, the next step is to put contents in it. We create .gitignore file listing patterns to match the file names you want to ignore.
Here is an example of .gitignore file:

# this is my first .gitignore file
*.pyc
*~
*.[oa]
settings.py

  • The first line starts with # and these are ignored.
  • The second line tells Git to ignore any files ending in .pyc.
  • The third line tells Git to ignore all files that end with a tilde (~), which is used by many text editors such as Emacs to mark temporary files.
  • The fourth line tells git to ignore any files ending in .o or .a — object and archive files that may be the product of building your code.
  • The fifth line tells to ignore the file named ‘settings.py’.
  • You may also include a log, tmp, or pid directory, automatically generated documentation, and so on.

The rules for the patterns you can put in the .gitignore file are as follows:

• Blank lines or lines starting with # are ignored.
• Standard glob patterns work.
• You can end patterns with a forward slash (/) to specify a directory.
• You can negate a pattern by starting it with an exclamation point (!).

Glob patterns are like simplified regular expressions that shells use. An asterisk (*) matches zero or more characters; [abc] matches any character inside the brackets (in this case a, b, or c); a question mark (?) matches a single character; and brackets enclosing characters separated by a hyphen([0-9]) matches any character between them (in this case 0 through 9).

Here is another example of a .gitignore file:

# a comment - this is ignored
*.a # no .a files
!lib.a # but do track lib.a, even though you're ignoring .a files above
/TODO # only ignore the root TODO file, not subdir/TODO
build/ # ignore all files in the build/ directory
doc/*.txt # ignore doc/notes.txt, but not doc/server/arch.txt

Note that, each line in gitignore file specifies a pattern or a filename ( if that is to be ignored everytime ).

If you already have a file checked in, and you want to ignore it, Git will not ignore the file if you add a rule later. In those cases, you must untrack the file first, by running the following command in your terminal:

~$ git rm --cached 

Setting up a .gitignore file before you get going is generally a good idea so you don’t accidentally commit files that you really don’t want in your Git repository.
So, Keep ignoring or, particularly, Keep ‘git-ignoring’. 😉 😛