Why Us Services Portfolio Blog Technologies Development process Start a Project →
UA EN RU
← All posts
Development · 29.03.2019 · 10 min read

Setting up Git on a project: a step-by-step guide

A step-by-step usage story rather than theory: how to set up Git on a real project — from the bare repository scheme and the first commands to a settled daily workflow.
Setting up Git on a project: a step-by-step guide

The internet is full of reference material on how developer tooling is built and how it works under the hood. We find "usage stories" more interesting — the simplest possible sequence of steps that you can just repeat on your own project. What follows is exactly that kind of story: how to set up the Git version control system on a project. Nothing superfluous.

Why another Git guide

Plenty of theory has been written about Git, and most of it is excellent. The problem lies elsewhere: when version control has to be set up on a real project today, a developer needs a sequence of actions, not an architecture overview. That is why our knowledge base publishes instructions — from the very first command to a settled working process.

In our knowledge base we publish "usage stories" — the simplest, most step-by-step instructions we can write.Chief Technology Officer

The exchange scheme

To work comfortably in a direct-commit mode with the commands git push origin master and git pull origin master, we use a scheme built around a bare repository (the central one).

Exchange scheme: PRODUCTION, the central bare repository and DEV
The basic exchange scheme: PRODUCTION and DEV exchange code through the central bare repository

Each part of the scheme can live on a separate server, on two servers, or all of it on a single server. Everything depends on the paths to the remote branches.

An option with the parts of the scheme placed on different servers
The parts of the scheme can be spread across different servers
An option with all parts of the scheme on a single server
Or brought together on one server — only the paths to the remote branches change

PRODUCTION

The project's live code. This is where we create .gitignore, run git init, and from here we upload the code to the central repository for the first time.

Bare repository

The central repository with no working copy. The exchange point: changes are pushed here and pulled from here.

DEV

A clone of the central repository. This is where the work on tasks happens — each one in its own branch.

Placement

Different servers, two servers or one — the scheme itself does not change. Only the paths to the remote branches do.

Creating the DEV repository

  1. Create .gitignore on PRODUCTION. In the project root, create a .gitignore file and list in it everything that is not part of the code that will change and that, by its nature, should not fall under version control.
  2. Initialise the repository. After that, run git init.
  3. Make the bare version. Go to the server or the directory where the bare repository will live, and create the bare version there: git init --bare.
  4. Note down the path to the repository. Check where you have ended up: pwd returns, for example, /var/www/sven/data/www/github.
  5. Add the remote alias. Go back to PRODUCTION and register the bare repository as origin: git remote add origin ssh://sven@o.aniart.com.ua/var/www/sven/data/www/github.
  6. Make sure everything is fine. The git remote -v command should show that same address twice — once for fetch and once for push.
  7. Upload the code. From PRODUCTION, push all the code to the bare repository: git push origin master.
  8. Clone DEV. Go to the server (to the directory) where DEV will live and clone everything you have just uploaded from the bare repository: git clone ssh://sven@o.aniart.com.ua/var/www/sven/data/www/github. This sets up the origin alias straight away.

The .gitignore file from our example project looks like this:

  • download/
  • images/
  • song_1.mp3/
  • video/

If you prefer, you can do the same thing step by step, without cloning: git init, then git remote add origin ssh://sven@o.aniart.com.ua/var/www/sven/data/www/github and git pull origin master. All of this is described in great detail in the Git documentation.

The result of cloning the repository into the DEV directory
After cloning, DEV already knows its origin
Why everything is simple from here on. When a repository is cloned, a master branch that tracks origin/master is usually created automatically, so git push and git pull work for that branch out of the box and need no extra arguments.

Useful commands and flags

CommandWhat it does
git remote -vShows which aliases are configured — on separate lines for fetch and for push.
git rm --cached -r imagesRemoves from version control anything that ended up there by mistake. Most often that means images and the download directory.
git rm --cached -r song_1.mp3The same for a single large file.
git pull --allow-unrelated-histories dev masterSaves the day when the repositories share no common ancestor commit.
git checkout -b serverfix origin/serverfixSets a remote branch to be tracked by a local one — saves a great deal of time otherwise spent spelling out aliases and branches.
git push origin serverfix:SVEN-5"Take my serverfix and make it the remote SVEN-5."

Creating a local branch with git checkout from a remote branch automatically creates what is called a tracking branch. Tracking branches are local branches directly linked to a remote one. If you type git push while you are on a tracking branch, Git already knows which server and which branch to push the changes to. In the same way, running git pull on one of those branches first fetches all the remote references and then automatically merges in the corresponding remote branch.

The git push origin serverfix:SVEN-5 form can be used to push a local branch into a remote branch with a different name: your local serverfix ends up in the SVEN-5 branch of the remote project.

Careful. If you leave out the --cached flag in git rm --cached -r ..., the command will delete all those files from disk.

The DEV working routine

For every assignment or individual task we follow the same cycle.

  1. Create a branch. git checkout -b SVEN-5 — from then on, all the work happens in it and nowhere else.
  2. Do the work. Write the code, add the files you need.
  3. Commit the changes. git add ., then git commit -am "what the work was about".
  4. Merge into master. git checkout master, then git merge SVEN-5.
  5. Push to the central repository. Once you have approval to release to PRODUCTION, run git push origin master. The changes are then pulled from the central repository onto master.
  6. Clean up after yourself. Old branches can be deleted: git branch -d SVEN-5.
  • git branch --merged — shows which branches have already been merged and can be deleted (all of them except the current one, marked with an asterisk).
  • git branch --no-merged — shows which branches have NOT been merged and still contain changes.

Committing changes and working with the index

The standard way to commit changes

  • Option 1. Add the changed files to the index before committing: git add filename1 filename2, then git commit.
  • Option 2. Add every file — changed, new and deleted: git add ., then git commit.

If something ended up in the index by mistake

If something went wrong, you can always remove accidentally added files from the index before you commit.

  • git reset filename1 — remove a specific file from the index.
  • git rm --cached filename1 — the same thing done another way.
  • git reset HEAD — reset the whole index completely.

How to restore files and undo changes

Restore a file from one of the previous commits

You will need the commit identifier and the file name: git checkout commit-id file-name. In practice it looks like this: git checkout 2378d5ad6e3d5fc87df858678c226d9fc9c47c66 temp.tmp. To find the identifier, look at git log.

Remove from the index a file that should not be there

  1. Add the file to .gitignore. So that it no longer falls under version control.
  2. Exclude it from the index. git rm --cached filename.
  3. Commit. Without a commit the change is not recorded.

How to bring a changed file back

The main rule. The best approach is NOT to work in the master branch. Always make changes in a separate branch, and only tested and approved work should be merged into master. Master is the reference stable branch.
  • git reset --soft id-commit — drop the commit from the branch but leave the index and the file tree untouched.
  • git reset --hard id-commit — drop the commit, the index and the files back to the state of the specified commit.

Branches, tags and temporary storage

Working with branches

  • git branch new-branch — creates a new branch called new-branch based on the current one.
  • git checkout branch — switching between branches.
  • git merge — merging branches and resolving any conflicts along the way.

Tags

  • git tag stable-1 — creates a "lightweight" tag attached to the latest commit. If the tag already exists, another one will not be created.
  • git tag -d stable-2 — delete a tag.
  • git tag -l — list the tags.

Temporarily "hiding" changes

This situation comes up often: while you are working on part of your project, everything is in a messy state, and you need to switch branches to spend a little time on something else. The trouble is that you do not want to commit half-finished work just so you can come back to this exact state later. The answer to this problem is the git stash command.

  • git stash — the changes are no longer visible to Git.
  • git stash list — look at the list of stashed work: stash@{0}: WIP on master: 049d078 added the index file, stash@{1}: WIP on master: c264051... Revert "added file_size", stash@{2}: WIP on master: 21d80a5... added number to log.
  • git stash apply — restore the most recently stashed work.
  • git stash apply stash@{2} — apply one of the older stashes by naming it.

Commit history and analytics

Information about the commit history can be obtained at various levels of detail.

CommandLevel of detail
git logBasic statistics on the commits.
git log --statDetail for each commit.
git log --summaryA summary of the history.
git log -pDetail for each file.
git diff filenameChanges in a specific file.
git diff --cachedChanges added to the index.
git showChanges introduced by a single commit.

Did you enjoy this tip? Write to us and tell us what else you would like to learn about.