Git is a Version Control System (VCS) for source code created by Linus Torvald (the creator of Linux). It allows to share and collaborate on code efficiently. It somewhat has a high barrier to entry especially because it's packed with feature. However you can learn a few basic terms and commands to use it in an easy way.
In opposition ot other VCS (Subversion for instance), Git is distributed. It means there's no central server and everything you do is happening on your local machine. It also means you can work on your code locally without being connected to the internet and syncronize with a remote repository later.
Here's a list of usual terms you will enconter in the guide, you can refer to it later.
|Repository / History||The Git history represents your code at different stages in its development, all of this is a repository|
|Commit||This is a set of patches bundled together with an author name and email at a specific date. The history is composed of a sequence of commits. Each commit has a parent commit forming a immutable history.|
|Branch||Like a tree branch, a sequence of commits may have diverged from the main (master) branch, usually to develop a new feature that will be merged back to the main branch|
|Merge||Reconcile two branches by creating a merge commit and resolving potential conflicts (the same line in a file have been edited in both branches for instance)|
|Local||A repository on your machine is a local repository|
|Remote||A repository on a server (c4science, github, ...) is a remote repository. A local repository can be bound to multiple remotes at the same time|
|Working copy||These are the files you see in your machine, it represents the states of your repository at a certain point in time (a commit) and space (a branch)|
|Index / Staging area||This is a remporary place where you add changes to be commited. Typically using git add <file>. It's usefull to separate the working copy and the staging area in case you don't want to commit every changes|
The usual workflow when using Git consist of the following sequence of commands:
git clone <URI> git add <file> git commit -m "commit message" git pull git push
Let's break down every command.
This retrieve a remote repository on your machine, downloading the complete history of every branches locally. It's actually a wrapper for other commands:
- git fetch Get all the changes on the remote to a local history
- git checkout HEAD Create a working copy of the HEAD (usually the master branch)
You've made some changes to some file in your repository and now you are ready to settle those in a commit.
The first step is to break down your changes in multiple commits if this make sense. For instance, you added feature-1.c and fixed a bug in main.c. You'd want to have two separate commits so it's easier to review by your peers. You can then do the following:
git add feature-1.c git commit -m "Adding the new feature 1" git add main.c git commit -m "Fixing a nasty bug in main.c"
The result will be two separate commits, each one contains the corresponding patch.
commit 88c8976e60297890060c7ab579a5044833352645 Author: Jean-Baptiste Aubort <email@example.com> Date: Wed Dec 20 16:34:34 2017 +0100 Fixing a nasty bug in main.c commit 7edcd6aae67a3d05cd5b3b5b9d2bfbf5f3d33371 Author: Jean-Baptiste Aubort <firstname.lastname@example.org> Date: Wed Dec 20 16:34:27 2017 +0100 Adding the new feature 1
Those commands let you interact with the remote repository (c4science). You can either pull the new commits from the remote or push your new commits to the server.
It's always a good idea to pull first because Git will not let you push if there are new commits on the server that you don't have on your local copy. You are then in charge of integrating those new commits by merging, and potentially fixing some conflicts.
Conflicts can happen if the remote and local commits modify the same portion of code, a human then have to review both changes and fix them manually. If the changes are in distant portion of code, Git can automatically merge the changes without conflict.
Git has a lot of usefull commands. One of the most important is git status. It will always tell you what to do.
If your working copy has no change and is up to date, here's the output of git status
On branch master nothing to commit, working directory clean
If you have uncommited and unstaged changes in your working copy,:
On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: main.c no changes added to commit (use "git add" and/or "git commit -a")
Git tells you that there are unstaged changes, that you can add them to the staging using git add or the shortcut command git commit -a.
Now if you have a file that is not tracked by Git:
On branch master Untracked files: (use "git add <file>..." to include in what will be committed) feature-2.c nothing added to commit but untracked files present (use "git add" to track)
Git tells you you have an untracked file, Simply run git add feature-2.cto add the file to the staging area.
When you pull / merge and Git cannot merge the changes, you'll end up with a open conflict. git status will tell you what to do:
On branch master Your branch and 'origin/master' have diverged, and have 1 and 1 different commit each, respectively. (use "git pull" to merge the remote branch into yours) You have unmerged paths. (fix conflicts and run "git commit") Unmerged paths: (use "git add <file>..." to mark resolution) both modified: main.c no changes added to commit (use "git add" and/or "git commit -a")
The conflict is in the conflicted file, there are two parts, the local part of the file and the remote part. Separated by the equal sign, in example:
<<<<<<< HEAD blah 123 ======= blah 321 >>>>>>> 9ee0a2a747adeb49e06815b4af1e8f28ff2be088
Simply edit the file, and manually choose which side to keep, and if needed keep some part of the other file, for instance here's my resolution to the conflct, and the commands to fix it.
blah 123 321
git add main.c git commit -m "Fix conflict in main.c manually"