Table of Contents


Intro

This repository will contain all the fundamental tips for git.


Git-files Download


Git Tips


How to commit stuff

Check which files are staged or untracked with git status:

$ git status
On branch master
Changes not staged for commit:
		modified:   TODO.txt
Untracked files:
		NEWSTUFF.txt

We can say that TODO.txt has been modified, and NEWSTUFF.txt is a new file yet to be added to the repository’s index.

We have two ways to commit the modified TODO.txt:

  1. We can add it, and then commit it:

     $ git add TODO.txt
     $ git commit -m "your message"
    
  2. We can simply commit it with the -a option, which commits all the unstaged modified changes without previously using git add <file>:

     $ git commit -am "your message"
    

In either cases, NEWSTUFF.txt won’t be added because it’s an untracked file.

Below, the same example written above that includes NEWSTUFF.txt too:

  1. We can add both, and then commit them:

     $ git add TODO.txt NEWSTUFF.txt
     $ git commit -m "your message"
    
  2. We can simply commit the unstaged modified files with the -a option, and add the untracked one separately before the commit:

     $ git add NEWSTUFF.txt
     $ git commit -am "your message"
    
  3. We can simply add all the files with -A option, and then commit:

     $ git add -A
     $ git commit -m "your message"
    

Beside git add we also have other instructions. Here a list:

# how to add files/folders
$ git add <filename1> <filename2> <filename3>

# how to delete files/folders
$ git rm <filename1> <filename2> <filename3>

# how to move files/folders
$ git mv <old_path_name> <new_path_name>

# how to discard changes of unstaged modified files/folders
$ git checkout -- <filename1> <filename2>

# how to discard changes of staged modified files/folders
$ git reset HEAD <filename1> <filename2>
$ git checkout -- <filename1> <filename2>

# how to reset the local repository as it is in the remote one
$ git reset --hard origin/master


How to add author info
$ git config --global user.email you@example.com
$ git config --global user.name "Your Name"

How to skip SSL certificate validation check
$ git config --global http.sslverify false

How to enable the colors in shell

To enable the colors if they are not present:

$ git config --global color.ui true

On BSD, the colors are not displayed and you see ESC[r] instead. You solve it with:

$ git config --global core.pager 'less -R'

How to setup a credential-helper for git
  • Temporary (stored in ram/cache)
    • On BSD/Linux

      • By default (timeout specified for 15 minutes)

          $ git config --global credential.helper cache
        
      • Custom (timeout specified for an hour)

          $ git config --global credential.helper "cache --timeout=3600"
        
    • On OSX

        $ git config --global credential.helper osxkeychain
      
    • On Windows

        $ git config --global credential.helper wincred
      
  • Permanent (stored in file)
    • On BSD/Linux/OSX/Windows

        $ git config --global credential.helper store
      

      Note: It’s saved as plain text. Its path is usually %userprofile%\.git-credentials on Windows, and ~/.git-credentials on BSD/Linux.

  • Other ways

How to prevent the Wall of Pink issue - Part 1 - Disable the default EOL conversion

The “Wall of Pink” is the dreadful commit where it removes and re-adds all the lines of a file. It usually happens due to a diff misconception of handling cr/lf EOL characters.

Variables like core.autocrlf and core.eol are pointless “today”, because, on mixed repositories, we usually have (e.g.) .bat files with crlf, and .sh files with lf.

If we would set the same EOL for all the text files, we could invalidate many of them. So it’s better disable such feature, and, if you really need, use the .gitattributes file to handle them.

$ git config --global core.autocrlf false

You can unset it by doing:

$ git config --global --unset core.autocrlf

Note: Different git clients than msysgit handle core.autocrlf, core.eol, and .gitattributes differently causing ambiguous walls of pink.

Note2: More info here topic1, topic2


How to prevent the Wall of Pink issue - Part 2 - Specify your own EOL conversion

As previously said, we can use the .gitattibutes file to handle the EOL character to use, some diff options, whether a file should be considered as text or binary, and so on.

If you’ve followed the “Part 1”, you should have set core.autocrlf as false. We’re going to use .gitattributes to specify, in this case, which EOL directive use.

We need to create such file in the repository’s root folder, and not in sub-folders. An example of the .gitattribute is:

### default behavior
* text=auto eol=lf
## note: eol in text auto is fixed since git 2.10 (31 aug 2016)

### windows (always crlf)
*.bat eol=crlf
*.sln eol=crlf
#*.filters eol=crlf
#*.users eol=crlf
#*.vcxproj eol=crlf
#*.*proj eol=crlf

### unix (always lf)
*.sh eol=lf
#*.bash eol=lf
#*.py eol=lf

### archives (always binary)
#*.rar binary
#*.7z binary
#*.zip binary
#*.tar binary
#*.tgz binary
#*.tbz binary
#*.gz binary
#*.bz binary

As you can imagine, .sh files’s EOL will be converted to lf, and .bat files’s EOL to crlf. The .rar files will be considered as binary.

The text=auto directive will enable EOL normalization on text files (it’s a replacement of core.autocrlf), and use the core.eol (or eol directive) parameter to convert the EOL.

As summary, the meaning of these keywords:

  • text turns on eol normalization
  • text=auto turns on auto eol normalization based on core.eol or eol directive
  • -text turns off eol normalization
  • eol=crlf sets the eol normalization character to crlf
  • eol=lf sets the eol normalization character to lf
  • !eol treats the eol attribute as unset (regardless of the user/global settings)
  • diff turns on textual diff patch generation
  • diff=<name> turns on textual diff patch generation using the specified driver
  • -diff turns off textual diff patch generation (binary diff will be applied on the relative file)
  • binary is a short-cut for -text -diff

After adding a .gitattributes file in the repositories, you need to adjust the index again.

$ rm .git/index
$ git add .
$ git commit -m "+fix eol"
$ git push

To update the EOL of the current files, you only need to do: (instead of re-cloning the whole repo)

$ git rm --cached -r .
$ git reset --hard

How to rename a branch
  • To rename the current local branch:

      $ git branch -m <new_branch_name>
    
  • To rename a specified local branch:

      $ git branch -m <old_branch_name> <new_branch_name>
    

After renamed the local branch, we have to “rename” the remote one too:

# pushing the local renamed branch to the remote repository
$ git push origin <new_branch_name>:refs/heads/<new_branch_name>

# delete the old branch from the remote repository
$ git push origin :<old_branch_name>

# fix upstream if required
$ git branch --set-upstream-to=upstream/<new_branch_name> <new_branch_name>

# fix old remote tracking branches
$ git fetch origin --prune

How to delete a branch
  • To delete a local branch:

      $ git branch -D <branch_name>
    
  • To delete a remote branch:

      $ git push origin :<branch_name>
    

How to create a diff between branches or commits
  • To generate a textual diff between commits:

      $ git diff b0a7f70..8c2aef3 > b0a7f70_vs_8c2aef3.diff
    
  • To generate a textual diff between commits:

      $ git diff b0a7f70..8c2aef3 > b0a7f70_vs_8c2aef3.diff
    
  • To generate a textual diff between a branch “master” and “retsam” considering hierarchy (using ... instead of ..) and EOL skipping (using --ignore-space-at-eol):

      $ git diff master...retsam --ignore-space-at-eol > master_vs_retsam.diff
    
  • To apply the generated textual diff somewhere:

      # system built-in diff patcher
      $ patch -p1 < master_vs_retsam.diff
    
      # otherwise, git built-in diff patcher
      $ git apply -p1 < master_vs_retsam.diff
    
  • To generate a diff including binary data between master and master~2 (two commits behind master):

      $ git diff master~2..master --binary < masterb2_vs_master.diff
    
  • To apply the generated diff (binary data included) somewhere:

      $ git apply -p1 < masterb2_vs_master.diff
    

How to create a diff between branches or commits (2nd way - auto commit)
  • To generate a diff between a branch “master” and “retsam” considering hierarchy (using ... instead of ..) and EOL skipping (using --ignore-space-at-eol):

      $ git format-patch master...retsam --ignore-space-at-eol -k --stdout > master_vs_retsam.patch
    
  • To apply the generated diff somewhere:

      $ git am -3 -k < master_vs_retsam.patch
    

How to archive a git repository

You can decide to archive either an entire repository (whether or not including the history) or just one or more branches/tags.

  • Including the history

    Usually, this is made using the git bundle feature. People could also zip the whole repository (including the .git folder), but that’s another story.

    We should now decide if we must create a bundle of the whole repository or of just a branch.

    • Bundle of the whole repo

      To make a bundle of the whole repo, we have to do:

        $ git bundle create <repository_name>.bundle --all
      

      To import a complete bundle, we have two solutions:

      1. Clone the bundle to a new repository

         $ git clone <repository_name>.bundle <repository_name>
        

        In this case, there will be no local branches created so far beside HEAD, but only remote ones. You can print them by doing git branch -r.

        You have to checkout the branch you want to get a local copy of it: (e.g. getting master)

         $ cd <repository_name>
         $ git checkout -b master origin/master
        
      2. Pull the bundle refs, creating so, for each branch, a local one

         # create the folder and enter it
         $ mkdir <repository_name>
         $ cd <repository_name>
        
         # create .git
         $ git init
        
         # fetch the data form the .bundle
         $ git pull <repository_name>.bundle *:*
        

        Note: It will print a warning regarding HEAD, but everything will be fine.

    • Bundle of a bunch of branches

      To make a bundle of a specific branch:

        $ git bundle create <filename>.bundle master
      

      To clone the specific branch:

        $ git clone <filename>.bundle --branch master
      

      To import the specific branch:

        # checkout the specific branch or it will overwrite the current one even though you setup a different local target!
        # and pull from the bundle the branch we need
        $ git checkout -b master
        $ git pull <filename>.bundle master
      

    Note: In all the cases, you should re-set the upstream url

  • Not including the history

    In this case, git archive is the most used. Other Info

    The only inconvenience is that it exports just a branch at a time.

      # create a .tar
      $ git archive <branch_name> --format=tar -o ./<archivename>.tar
    
      # create a .tgz
      $ git archive <branch_name> --format=tgz > ./<archivename>.tgz
    
      # create a .tgz with the best compression from pipe
      $ git archive <branch_name> --format=tar | gzip -9 > ./<archivename>.tgz
    
      # create a .zip with default compression
      $ git archive <branch_name> --format=zip -o ./<archivename>.zip
    
      # create a .zip with the maximum compression
      $ git archive <branch_name> --format=zip -9 -o ./<archivename>.zip
    
_Note: Another way is via git fast-export git fast-import_

How to merge several git repositories

You have to upgrade git to the 2.x version and then follow these commands:

git remote add project-a <path/to/project-a>
git fetch project-a
git merge --allow-unrelated-histories project-a/master
git remote remove project-a

Note: Source discussion


How to show tracked ignored files
# simply:
$ git ls-files -i --exclude-standard

# making an alias of it and calling it
$ git config --global alias.showtrackedignored "ls-files -i --exclude-standard"
$ git showtrackedignored

Note: Source discussion


How to get the size of the repository

Simply:

# cleanup the unnecessary files
$ git gc
# display the size of the repo in megabytes
$ git count-objects -vH

How to get the count of the commits made

Simply:

# show the count of all the commits of every branch
$ git rev-list --count --all
543

# show the count of the commits up to a specific branch/hash
$ git rev-list --count master
543

# show the count separated by committers
$ git shortlog -s
	11	Administrator
	32	Charlie Root
	571	martysama0134

How to delete a file from the whole history

If you have several commits, it will take almost 1 second per commit to remove the relative file and rewrite the history.

# check which files are the most bigger in your git repository
$ git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5
c7dc0e78fa8cce3e0b306aff4ad27f1d40eafcc6 blob   199636 4185 164305
c8255b0cc3afc4017a6ac181d7beed60ce6bae6c blob   204126 15879 355126
1d81968daaefa9bdb047b225976fac04e8c8f715 blob   208219 43106 2308251
781944f1e587b1a7a4e2f0d5087158727cedb27b blob   349680 100481 4267720
b71a1218246b246286980bbbcd7d8abc311c1fae blob   377306 32752 598865

$ git rev-list --objects --all | grep 781944f1e587b1a7a4e2f0d5087158727cedb27b
781944f1e587b1a7a4e2f0d5087158727cedb27b Srcs/Tools/Mysql2Proto/Mysql2Proto/libmysql.lib

# check the starting commit containing that file
$ git log --oneline --branches -- Srcs/Tools/Mysql2Proto/Mysql2Proto/libmysql.lib
50687d0 +Mysql2Proto

# remove the relative file from the whole history from its starting commit
$ git filter-branch --index-filter 'git rm --ignore-unmatch --cached Srcs/Tools/Mysql2Proto/Mysql2Proto/libmysql.lib' -- 50687d0^..

# push all to the remote repository forcefully (some sites don't let you force it if you don't unprotect them before in their website's branch settings)
$ git push --force

# clean the local refs as well (if it takes too much when using git gc, git clone the repo again)
$ rm -Rf .git/refs/original
$ rm -Rf .git/logs/
$ git gc
$ git prune --expire now

# to see the current repository's size
$ git count-objects -v

In case of deleting a folder instead of a file, it’s all the same except the git rm -r option in the git filter-branch command, just like this:

$ git filter-branch --index-filter 'git rm -r --ignore-unmatch --cached Srcs/Tools/Mysql2Proto/' -- 50687d0^..

Note: Source discussion


How to delete a file from the whole history Alternative

There’s a faster way (500 times faster than git filter-branch) to delete files from the whole history, and it’s using BFG.

# remove the following extensions from history (if they are missing in the last commit)
$ java -jar bfg.jar --delete-files "*.{rar,zip,7z,tar,tgz,tbz,gz,bz,exe,lib,dll}" <reponame>
# clear definitely all the removed files
$ cd <reponame> && git reflog expire --expire=now --all && git gc --prune=now --aggressive

Note: By default, it won’t delete any files in the last commit.


How to show and delete all the gitignored files

To show all the gitignored files (and directories with -d specified):

$ git clean -xnd

To delete all of them:

$ git clean -xdf

Other Git Tips

Customizing Git - Git Configuration


This site uses Just the Docs, a documentation theme for Jekyll.