Chapter 4 Leveling Up

4.1 Repository structure

When it comes to working on a git repository that is constantly evolving, it is important to understand how to structure the repository and understand the organizational best practice. While most of the files are going to be project specific there are a few files that occur very often in many open source projects (and closed source too, but we do not see them because they are CLOSED). Here are some of those objects

  1. .gitignore (explain in detail)
  2. LICENSE
  3. README.[md|txt|rst..]
  4. CONTRIBUTING.[md…]
  5. .gitkeep (i don’t know what this is)
  6. .git/
  7. .github/ (git workflow files)
  8. *.json
  9. *.yml
  10. DOCKER*

4.2 Gitignore

There will be times were we will create additional files while working on the projects but we do not want to check them in version control. These files could be temporary files created by program compilers, or credentials file that should never be tracked. Once these files are committed or checked into a remote repository, their history will be available throughout the life of the git repository.

One of the best way to keep these unnecessary or secret files away form git is to put them in a .gitignore. Yes, we can carefully choose not to git add these files, but will take a lot of focus. One important note is that, once the file is committed on git, adding that file on gitignore doesn’t work. FOCUS on this later: The reference of that file will need to be removed from the index b

To add files for git to ignore, create a text file with the name .gitignore and start typin g the name of the file or the subfolder that we want to ignore. The file path is relative to the project diretory. We can use wildcards as well

>$ touch .gitignore

password.txt           #ignore the file password.txt
*.py[cmd]              # ignore any files that end on pyc, pym or pyd
tools/                 # ignore tools directly completely
!tools/veryuseful/     # do not ignore veryuseful inside tools 

There are tools out that that create gitignore files for most use case for you. For example, we can copy the output of this link to our gitignore to ignore all files created by python and macos that are generally ignored.

4.3 .git directory

Every git repository will have this subdirectory. This is where the magic of git happens. We can look at the contents of the files if we are interested, but we do not make changes to this directly.

4.4 GIT Config

We can keep a configuration of our git workflow using git config. Git can have configuration at three level system, global, and project level respectively where the later superseeds the prior. Project level configuration is stored in the .git/config file. Global (or I like to call it user) level git config is located in ~/.gitconfig file and system level will be in /etc directory. At the very minimum, we can add our username and user email to our global git config. This will be used when we commit our files.

git config --global user.name = 'myname'
git config --global user.email = 'email@example.com'

With these two on our config file, when we look at git log we should see the name and email address pop up. Other configuration we can store on the configuration files can be git alias, gpg signing, etc.

4.5 Using SSH Key to authenticate to remote repository {ssh}

Learn more about OpenSSH here

SSH is one of the ways to securely connecting to remote repository from our local machine without having to enter username and password. Here are the major steps to enable SSH to communicate between our local and remote repositories. There are many flags and controls but the following will get us going.

  1. Generate a SSH keypair $> ssh-keygen -t rsa -C <email@domain.com>. Default location will be ~/.ssh/. Enter passphrase to keep it more secure
  2. Copy the public key from SSH Keypair into clipboard. Use pbcopy or clip depending on platform $> clip < ~/.ssh/<public-keyfile>
  3. Log into remote eg. github or gitlab. Then, go to setting (under the “profile picture”) and click SSH and GPG Keys. Click new SSH key and then paste the content from your clibpoard in the field.

Optionally: To make it more secure (and to not have to type ssh passphrase) :

  1. Ensure that SSH-Agent is running in the local machine $> eval $(ssh-agent -s). On windows, we can search for services and find OpenSSH. Double click and choose Automatic. On UNIX, will need to update .bashrc.
  2. Add the private key from the SSH keypair into ssh-agent $> ssh-add ~/.ssh/<private-keyfile>
  3. When the ssh keys are now used, it will ask if you want to add the new “host” to a “known_hosts” file. Type “yes” and return.

4.6 Using GPG key to sign the commits

While we can use SSH to securely communicate between local machine and remote host, we can add additional layer of security to our project by using GPG key. We may not need to use it very frequently, however it can be a great tool to get another level of security. When a git commit or tag is signed with a gpg key, the user can be satisfied with the fact that it comes from a trusted source. In addition, during the transmission of the files between two machines, they will be encrypted (or that is what I think happens).

  1. We need to have gpg tool installed
  2. Check to see if any gpg key is already available for our user gpg --list-key
  3. If no gpg key available or if want a new key, create one gpg --gen-key (do the dance such as choosing rsa, passphrase, etc.)
  4. Copy the public key gpg --armor --export <key-identifier> | pbcopy.
  5. Log into remote repository, go to settings, and paste the public key in the new gpg keys section
  6. Add the gpg key using git config
git config --global gpg.program gpg
git config --global commit.gpgSign true

More detailed steps here

4.7 SHA

4.8 Pull Request

4.9 Code Review

4.10 Fixing mistakes

Back in the days I used to delete the entire repository then clone down the working version from remote every time I had a mistake in my git repository. It works! However, in my mind that is not the proper way of fixing mistakes.

  • git clean
  • git checkout
  • git reset [–[hard | soft] HEAD[^]]
  • updating index

4.10.1 unfixable mistakes

4.11 Conclusion

At the very least, we can do the following to make our lives easier. They only need to be done once. 1. Setting up SSH 2. Configuring git with name and email 3. Using .gitignore file (once per project)