This post represents an overview of version control with git. The mentioned commands and parameters are only a small part of what's possible. Git is a popular system for version control. Projects on git are called Repositories. Repositories can be used local or with a server. There are several free hosters, for example:
- Linux (Debian-based)
apt-get install git-all
Git-Repositories are separated into working directory, staging area and repository. The working directory is the local copy of the repository.
Changes on the files are saved here. The repository is the shared project of all contributing persons. Using the staging area, a developert can decide, which elements he/she wants to save from the working directory to the staging area.
Basic administration of a repository
All commands are initiated with the keyword git.
Initialization of a folder as repository:
# New repository git init # Download (clone) of an existing repository git clone path/to/repository
Editing / creating files: test.txt
# Overview of the current status of the repository git status # test.txt is displayed red # Splitting into separate parts: # Untracked Files: New files # Changes not staged for commit: Edited files # Parameters: # -u: Add all edited files, but no new ones. # -A: Add all files (alternative: git add . ) # Adding files to the index git add test.txt # test.txt ist now displayed green # Adding files to the repository git commit -m "Add test"
Each commit is commented with the -m-flag.
This gives the developers a fast overview about the changes made.
Git has some naming-conventions, that tells you to write a commit
- short (<50 characters)
- written in present tense
# Print all commits including details in chronological order git log
The output of this command looks like the following:
- Name of the author
- Email of the author
Configuring names and emails
This configuration is global for every repository (set it up once per device).
git config --global user.name "Marcel Jurtz" git config --global user.email email@example.com
You can set this for each project individually, just leave out the -global-flag.
In the following, HEAD is often mentioned. HEAD is the most recent commit of the current branch.
A remote is a repository on a server / different pc, for example hosted on Github.
In the following, I use Github as remote server.
After creating an account on Github, available repositories are shown and new ones can be created.
When creating a new repository, you can select to add a README- and/or license- & .gitignore-file.
When creating a new repository (of course this can be done later as well), you are prompted to create a README-, license- and .gitignore-file:
- README is a file that represents general information about the project. When hosted on GitHub, this file can be imagined as landing page for visitors. README-files are usually written in markdown. Markdown is similar to HTML, but has lesser functionality and better readability (in my opinion).
- license: All repositories on Github (free accounts) are publicly available. With a license-file, the usage of the repository can be adjusted to different preferences. GitHub offers some pre-defined licenses, for example MIT and GPLv3, along with information on the differences.
- .gitignore: Gitignore-files list files and directories, that will be ignored by git. You can add files and folders, to, for example, prevent temp- or meta-files from being added to the repository.
The following screenshot shows an exemplary repository on Github.
The lading page offers some overview of a repository, for example the files and folders in the root-directory, amount of commits, branches, licensing-info and so on.
After a repository has been created, it can be added as a remote:
git remote add origin url
You can set individual names for the remote, I use origin here.
To upload changes commited in the working directory, use the following:
git push origin master
And this to download changes from a remote:
git pull origin master
Please know that if you have an existing project on your pc and want to add it to a remote, which already contains files, for example README, license, or .gitignore,
youll have to merge the repositories. If you don't have any of these files locally, you'll have no problems, since the files will be automatically implemented.
If you do, this will result into a merge-conflict. Continue reading, to find out more about merging.
For example, user A and user B are editing the same repository, both users can work with the above mentioned methods.
A problem comes up, when both users push the same file: merge conflicts.
Think of a file in the remote repository named test.txt, which has the following content:
Using pull, both users get this file to their working directories.
Now, both users edit the file to the following:
Hello, I am A!
Hello, I am B!
Both users now push their version to the remote. The user submitting first will have no problems doing so. In my example, this will be user B.
When user A pushes his updates, the push will result in an error like the following:
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.
Git now modified the mentioned files, test.txt now has the following content:
Hello, I am B!
Hello, I am A!
A now has to decide, which version is preferred and then commit the changes.
A updates the file to the following:
Hello, we are A and B!
After that, he creates a new commit to document the merge:
git add test.txt git commit -m "Resolve Merge Conflict"
Git uses branches to support developing new features. This supports developing new functionality, without the need to edited the working current version of the project.
Use this to create a new branch:
git branch branch_name
And this to view all existing branches:
The current branch is marked by an asterisk. Usually, this is master in new projects. As you may notice, we used this branch earlier to push commits. Replace this to push to other branches.
git checkout branch_name
Creating a branch and switching to it:
git checkout -b branch_name
When a branch is changed, files in the working directory are automatically updated to match that branch. This way, you don't have to use different folders for different branches and save space on your harddrive.
To merge two branches, switch to the branch you want to merge to (using
git checkout) and merge them:
git merge branch_name
To view differences in branches, you can use
git diff source_branch destination_branch
Branches, that are no longer needed, can be deleted:
git branch -d branch_name
Tags can be added to commits, to highlight completed versions of a project. To select a commit, the first 10 characters of the checksum are needed (
# Creating a new tag git tag 1.0.0 d525ac9ddf # Show all tags git tag # Creating a commented tag git tag 1.0.0 d525ac9ddf -m "Commented Tag" # Show commit using its tag git show 1.0.0
To reset contents of the working directory, you can use the following:
git reset -- filename
This command obtains changes from HEAD and overwrites the content of the working directory to match HEAD. Changes that have been added to the staging area are not overwritten!
To reset contents of the directory, use this:
git reset --hard d525ac9
As shown earlier, you need to add the first characters of the commits checksum to identify the commit. This command should only be used with caution, since it changes the commit-history.
Conventions & Good Practices
To keep repositories as clear as possible, you should follow some general rules in naming commits and branches.
Commits should be written under considering the following:
- Keep it short and simple
- Begin with a normalized set of verbs, written in present tense, for example: add, remove, update
It is useful to use a short and precise formulation here as well. Often, a verb as prefix is used to describe the purpose of the branch. For example: add/feature_a, remove/feature_b.
When contributing to public projects, you should also check the previous commits to adjust to the organization of the other authors.
If you don't like using the terminal, there are some GUI-clients. For example: