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’. 😉 😛

Let’s Git…

It’s been quite a long time that I have posted any tutorial of things I have learnt, apart from the daily diary. So as to prohibit the distance between me and my blog to increase further, I decided to start fresh with Git.

Git Basics

Getting a Git Repository

Creating your own Git repository :

  • Create a new directory for your project. If it is already made, you do not need to make it again.
     ~$ mkdir first_repo 
  • Initialize the repository in your project directory.
    ~$ cd first_repo
    ~$ git init
    

    This creates a new (hidden) subdirectory named .git that contains all of your necessary repository files — a Git repository skeleton.

  • Record your changes to the repository on your local system or in simple words, work the changes in your project directory on your system.

  • Check the status of your files.The main tool you use to determine which files are in which state is the git status command.
     ~$ git status 
  • Git has three main states that your files can reside in: modified, staged and committed.
    Modified means that you have changed the file but have not committed it to your database yet.
    Staged means that you have marked a modified file in its current version to go into your next commit snapshot.
    Committed means that the data is safely stored in your local database.

    This leads us to the three main sections of a Git project: the working directory, the staging area and the Git directory.

  • If you have worked out your changes. Running ‘git status’ would give something like :
    # On branch master
    # Untracked files:
    #   (use "git add ..." to include in what will be committed)
    #
    #	ex31.py
    #	ex32.py
    #	ex33.py
    nothing added to commit but untracked files present (use "git add" to track)
    

    Untracked files are those that have been modified or added but not marked or staged to be committed.

  • Staged means that you have marked a modified file in its current version to go into your next commit snapshot.
    Let’s run ‘git add’ now to stage the changed or newly added files.

    ~$ git add <filename> 
    OR
    ~$ git add <path-to-your-file> (if your current directory is not your working directory)
    
  • Running git status again would give the following output:
    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD ..." to unstage)
    #
    #	new file:   ex31.py
    #	new file:   ex32.py
    #	new file:   ex33.py
    #
    

    It is generally useful to frequently run git status.

  • Commits represent every saved version of a project. Each commit contains a snapshot of the project, your user information, the date, a commit message, and an SHA-1 checksum of its entire contents.
    Run ‘git commit’ to commit the staged changes.

     ~$ git commit -m "My first commit" 

    Specify the message in the commit using -m option and then writing the message in quotes.

  • To view your commit history, run ‘git log’.
    ~$ git log

    Running this, you can see your latest commit at the top.

  • After committing the things, you have saved the changes to your local system. In order to share your project, you must now push the changes to your repository online on the server.
    But, wait ! Have you created a repository on github ? No!! Then create it. Go to your github account and Click on ‘New repository’ button to create the repository.
  • But how would your system come to know where to push the changes ?
    You let your system know this by adding a remote. As you probably know, git is a distributed version control system. Most operations are done locally. To communicate with the outside world, git uses what are called remotes. These are repositories other than the one on your local disk which you can push your changes into (so that other people can see them) or pull from (so that you can get others changes).
    The syntax to add a remote is:

    ~$ git remote add <shortname> <link-to-your-online-repository> 

    Example –

    ~$ git remote add origin https://github.com/saloni10/first_repo

    You can have more than 1 remotes from/to where you can pull or push the things. Remote repositories are versions of your project that are hosted on the Internet or network somewhere.
    The short-name I have given here is origin, and it can be any name as well, which is like an alias to a URL. And origin is the usual path of where the remote repo points to.

  • The last step is to, finally, push your changes.
    ~$ git push origin master

    This is a command that says “push the commits in the local branch named master to the remote named origin”. Once this is executed, all the stuff that you last synchronised with origin will be sent to the remote repository and other people will be able to see them there.

  • At last, Remember the steps…
    1. modify and add your work
    2. track or stage the files (using git add)
    3. then save(their version, if you want) i.e. commit them. (using git commit)

    Cloning an Existing Repository

    If you want to get a copy of an existing Git repository — for example, a project you’d like to contribute to — the command you need is git clone.
    Every version of every file for the history of the project is pulled down when you run git clone.

    • You clone a repository with :
      ~$ git clone [url] 

      For example, if you want to clone the Ruby Git library called Grit, you can do so like this:

      ~$ git clone git://github.com/schacon/grit.git 

      This creates a directory named “grit”, initializes a .git directory inside it, pulls down all the data for that repository, and checks out a working copy of the latest version. If you go into the new grit directory, you’ll see the project files in there, ready to be worked on or used.

    • If you want to clone the repository into a directory named something other than grit, you can specify that as the next command-line option:
      ~$ git clone git://github.com/schacon/grit.git mygrit 

      This command does the same thing as the previous one, but the target directory is called mygrit.

    • This ends the first basic git tutorial. We’ll get into more of ‘Git’ things in the coming posts. Till then, keep practicing !! 🙂