This tutorial follows the guide available on atlassian.com
Press "?
" for navigation clues
A sophisticated save button
By far, the most widely used modern version control system in the world today
importantPaper_v27.tex
"Classical version control" | "Git version control" (single file) |
---|---|
|
|
Acceptable excuse:"I am the only one using this file which will not change."
"Someone wants me to use git..."
...users not familiar or starting to learn git
Git is a well known, documented and well maintained tool and used in about any development community. There is a high chance that you already have git installed. Make sure you have the most current version.
$ git --version
$ {command}
denotes that the {command}
following $
is executed in the terminal.
Lines within a code box but without a trailing $
correspond to output.
git version 2.xx.y
with xx >= 16, you have a relatively current version.
If you get a command not found
, you do not have git.
OS | Tool | command |
---|---|---|
macOS | MacPorts | sudo port install git +bash_completion+credential_osxkeychain+doc |
macOS | Homebrew | brew install git |
Debian/Ubuntu | apt-get | sudo apt-get install git |
The pattern is always the same. If you are unsure, also see the git download page .
Since you eventually want to collaborate, you should let git know who you are.
$ git config --global user.name "{My Name}"
$ git config --global user.email "{my@email.address}"
There are multiple ways for initializing a repository. The next slides will walk you through the basic procedure.
Navigate to the folder which will become the repository.
In this example, it will be the directory ~/myProject
.
$ git init myProject
Initialized empty Git repository in ~/myProject/.git/
This initializes the repository and only creates the folder ~/myProject/.git/
(you do not have to care about).
$ ls -a myProject/
. .. .git
git init {folder}
can be used on non-empty folders
It simplies places the .git/
directory into this folder
git status
Let us start by adding an empty Readme.md
file to the repo
$ cd myProject
$ touch Readme.md
Now, there is an untracked
file in the repository.
$ git status
On branch master
No commits yet
Untracked files:
(use "git add {file} .." to include in what will be committed)
Readme.md
nothing added to commit but untracked files present (use "git add" to track)
The branch you are working on. This is not important for now
Nothing to compare against.
What git suggests to do.
git add
To add the previously created Readme.md
file, one has to execute
$ git add Readme.md
The file is now staged
but not yet "saved"
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached {file}..." to unstage)
new file: Readme.md
File is now staged. It can now be committed or unstaged again.
It tells Git that you want to include updates to a particular file in the next commit. However,
git add
doesn't really affect the repository in any significant way—changes are not actually recorded until you rungit commit
This is useful when you work with several files at once. See slide below for an example.
Suppose you have two files, File A
and File B
, where File B
depends on File A
.
File A
until you are satisfied.
In principle you could save File A
, however
File B
wouldn't work anymore.
git add "File A"
.
This can also serve as a reminder of what is already done.
File B
until you are happy,
you git add "File B"
and save the entirely working snapshot.
git commit
Git's main job is to make sure you never lose a committed change.
To finally save the Readme.md
file, one has to execute
$ git commit -m "Committed empty readme file."
[master (root-commit) db35944] Committed empty readme file.
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 Readme.md
Commit file with message (otherwise default editor opens).
Branch, refspec, new commit ID (db35944
) and message.
Changes in file.
The file is now "saved" and the working directory is clean
$ git status
On branch master
nothing to commit, working tree clean
Now theres is nothing left to do.
One can also review all commits by running
$ git log
commit db35944b5054d24eadf49c42c0c254ce4d092040 (HEAD -> master)
Author: Christopher Koerber {my@email.address}
Date: Wed Apr 4 18:03:54 2018 +0200
Committed empty readme file.
The full commit ID.
Author and commit timestamp information.
The commit message.
Usually, one works with several files at once. Lets mimic this.
$ echo "\documentclass{minimal}\begin{document}Hello World\end{document}" > article.tex
$ ls
Readme.md article.tex
Note that you can edit files however you want — you don't have to use bash commands.
$ echo "Compile article.tex by running pdflatex on it" > Readme.md
$ git status
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: Readme.md
Untracked files:
(use "git add {file}..." to include in what will be committed)
article.tex
no changes added to commit (use "git add" and/or "git commit -a")
You now have a tracked but modified file (unstaged).
And a new, untracked file.
You can add the modified file.
You can reset the modified file.
You can also add but not reset the new, untracked file.
$ git add article.tex
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD {file}..." to unstage)
new file: article.tex
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: Readme.md
The new file is now staged but not stored.
$ git add Readme.md
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD {file}..." to unstage)
modified: Readme.md
new file: article.tex
$ git commit -m "Added article and adjusted readme"
[master 44aab06] Added article and adjusted readme
2 files changed, 2 insertions(+)
create mode 100644 article.tex
Status | What does this mean | git command |
---|---|---|
Untracked | Git doesn't know anything about this file | — |
Staged | Git now tracks changes to this file and will save it on the next commit | git add {untracked/unstaged} |
Unstaged | Git tracks this file and found a difference compared to the last recorded stage | — |
Saved | Git tracks this file, has information about the history, and will inform you about differences | git commit -m "{message}" |
.o, .aux, ...
Readme
or building files like a Makefile
.tex
files which compile
git status
is "nothing to commit, working tree clean
"
.gitignore
Once you compile the *.tex
, you obtain files you should not commit
$ pdflatex article.tex
$ git status
Untracked files:
article.aux
article.log
article.pdf
Since you now know how it works, I have left out some (for now irrelevant) output lines
The solution: put them in an .gitignore
file
Create a new file called .gitignore
where each line is a to be ignored file name, directory name or pattern
$ echo '*.aux' > .gitignore
$ echo '*.log' >> .gitignore
$ echo '*.pdf' >> .gitignore
$ git status
Untracked files:
.gitignore
You should also save the .gitignore
file to the repository — others should ignore the same things
$ git add .gitignore
$ git commit -m "Added .gitignore for tex products"
You now know how to add files and their modifications. Next you will learn how to inspect their history.
To see the repository history, use git log
It is helpful to use the --pretty
flag for output styling options
$ git log --pretty="[%ci](%h) %an: %s"
[2018-04-06 15:14:02 +0200](3003795) Christopher Koerber: Added .gitignore for tex products
[2018-04-06 13:33:23 +0200](44aab06) Christopher Koerber: Added article and adjusted readme
[2018-04-04 18:03:54 +0200](db35944) Christopher Koerber: Committed empty readme file.
The strings in parenthesis are commit identifiers. You need them, e.g., for comparing different versions.
How have we changed the Readme
file from first to second commit?
$ git diff db35944 44aab06 Readme.md
diff --git a/Readme.md b/Readme.md
index e69de29..e6da3a6 100644
--- a/Readme.md
+++ b/Readme.md
@@ -0,0 +1 @@
+Compile article.tex by running pdflatex on it
Git metadata (You will not need this information).
Changes from a/Readme.md
get a "-", Changes from b/Readme.md
get a "-"
Diff chunk location: in line zero, one line was added.
This line was added to a/Readme
git diff
The general syntax is
$ git diff {options} {commit1} {commit2} {path}
Where all objects after diff
could be left out
{path}
to last commit{path}
to {commit1}
{path}
between {commit1}
and {commit2}
git checkout
to walk back in timeYou can also revisit old commits
$ git checkout db35944
...
HEAD is now at db35944... Committed empty readme file.
We now went back in history to the point where we only have saved the empty readme file.
$ cat Readme.md
$ ls
Readme.md article.aux article.log article.pdf
git checkout
changes the state of the whole repository folder on the harddrive.
Readme
file is emptyarticle.tex
— this file is gone
.gitignore
file has not been created yet — therefore the product files show up
To go back to the present, execute
$ git checkout master
Previous HEAD position was db35944... Committed empty readme file.
Switched to branch 'master'
git checkout
to revert changesLets say we make some unwanted changes to a file
$ echo "I'm doing something stupid" >> article.tex
$ cat article.tex
\documentclass{minimal}\begin{document}Hell World\end{document}
I'm doing something stupid
$ git status
Changes not staged for commit:
modified: article.tex
Now we want to revert the changes
$ git checkout article.tex
$ cat article.tex
\documentclass{minimal}\begin{document}Hell World\end{document}
$ git status
nothing to commit, working tree clean
We now walked back in time to the last saved snapshot (for this particular file)
This guide assumes a remote repository has already been set up.
For basic usage, you only need two things to start collaborating:
master
or devel
, ...
You just need these infos once to initialize your local copy
— ask the repo owner.
More details on how to set up remote repositories and the git branch system are given in the intermediate course.
git clone
Create a new folder git_tutorial
at the current location containing the complete repository
and it's full history.
$ cd ..
$ git clone https://github.com/ckoerber/git_tutorial.git
Cloning into 'git_tutorial'...
remote: Counting objects: 13, done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 13 (delta 1), reused 9 (delta 0), pack-reused 0
Unpacking objects: 100% (13/13), done.
Go to the folder where you would like to create your local copy of the remote repo. Change that how you like.
Clone repo from this URL source. Can also be other local or remote folder.
Name of the folder containing the local copy of the repo.
Compressing, transferring and unpacking files.
$ cd git_tutorial
$ git checkout devel
Branch 'devel' set up to track remote branch 'devel' from 'origin'.
Switched to a new branch 'devel'
master
. For most linear projects, one branch is sufficient and you can ignore this step.
You can now modify, add
and commit
files as before
git pull
Whenever a remote repository has changed, you should consider updating your local copy.
There are several strategies for doing so. The most direct strategy is git pull
ing.
Note that git warns you before it changes files irreversibly.
Because you just created a copy from the remote repository, there is nothing to update.
$ git pull
Already up to date.
$ git status
On branch devel
Your branch is up to date with 'origin/devel'.
nothing to commit, working tree clean
The current line of development is now called devel
.
Informs you with what the status is compared to.
Scenario | What git does | What you have to do |
---|---|---|
Local status = remote status | Nothing | Nothing |
Local status > remote status (same history) | Nothing | publish your commits (if you are ready) |
Local status < remote status (same history) | Updates your files | Nothing |
Local history != remote history | Merges non-conflicts | Manually merge conflicts (see merging) |
Git will warn you before it overwrites content you have created.
If you and a collaborator work on the same line in the same file at the same time, you create a conflict. Without further input, git does not know what to keep.
Let's mimic the a conflict scenario by creating a local copy of the repo
$ cd ..
$ git clone git_tutorial git_tutorial_B
Cloning into 'git_tutorial_B'...
git_tutorial | git_tutorial_B |
---|---|
|
|
Now imagine git_tutorial_B
pulls from it's origin git_tutorial
$ git pull
error: Pulling is not possible because you have unmerged files.
hint: Fix them up in the work tree, and then use 'git add/rm {file}'
hint: as appropriate to mark resolution and make a commit.
fatal: Exiting because of an unresolved conflict.
git push
Once are ready to share your (accumulated) commits, use git push
.
$ echo "See the LICENSE for usage agreement" >> Readme.md
$ git add Readme.md
$ git commit -m "Mentioned LICENSE in Readme"
$ git status
On branch devel
Your branch is ahead of 'origin/devel' by 1 commit.
(use "git push" to publish your local commits)
Change add and commit files.
Your status is different than origin repo status.
Next possible actions: publish to remote or continue local modifications and push multiple commits.
$ git push
...
To https://github.com/ckoerber/git_tutorial.git
3003795..73ab23c devel -> devel
push
to repositories in which others work
(see remote repositories; that's the origin repository owners duty).
push
syntax is git push {repository} {branch}
.
If you and a collaborator work on the same line in the same file at the same time, you create a conflict. Without further input, git does not know what to keep.
Let's mimic the a conflict scenario by creating a local copy of the repo
$ cd ..
$ git clone git_tutorial git_tutorial_B
Cloning into 'git_tutorial_B'...
git_tutorial | git_tutorial_B |
---|---|
|
|
Now imagine git_tutorial_B
pushes to it's origin git_tutorial
$ git push
To ~/git_tutorial/
! [rejected] devel -> devel (fetch first)
error: failed to push some refs to '~/git_tutorial/'
...
git pull
to obtain updates from remotecommit
them (see status of files)
git add {file}
modified filesgit commit -m "{message}"
complete snapshotsgit push
to publish commits on remote
git pull
before git push
Git does not allow to git push
if you don't have the same history. You have to pull
first.
git status
to ensure correctness of actions
git status
clean
E.g., nothing to do anywhere
latexdiff-vc
Visualization of changes between different commits for .tex
files
$ latexdiff-vc --git --pdf -r {commit-hash} {texfile}
Branches correspond to independent lines of development.
You have already seen examples for different branches: the local master
branch is an independent line of development based on the origin/master
branch.
You can also create local independent lines of development.
$ git branch new-feature master
The syntax is
"git branch {branch-name} {start-point}
"
$ git checkout new-feature
Switched to branch 'new-feature'
$ echo "import numpy" > newFeature.py
$ echo "started to work on new feature" >> Readme.md
$ git add newFeature.py Readme.md
$ git commit -m "Added new feature"
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
$ ls
LICENSE Readme.md article.tex
master
branch
master
branch as a basis and further devel
branches
git merge
In the best possible case, you just use git merge
and git does everything for you.
For example, effectively, git push
& git pull
make use of this command.
git rebase
, which "rebases" the history of your commits
Below, the first 3 scenarios are explained.
The starting point will always be the final state from the branching slide.
(newFeature.py
was created and commited in the new-feature
branch and the master
branch is checked out.)
You have a linear path from current branch to target branch head
new-feature
branch into current branch$ git merge new-feature
Updating 841377f..5321d8f
Fast-forward
newFeature.py | 0
...
You do not have a linear path from current branch to target branch head but it was worked on different parts of files.
$ touch logo.png
$ git add logo.png
$ git commit -m "Added logo"
new-feature
branch into current branch
$ git merge new-feature -m "Merge branch 'new-feature'"
Merge made by the 'recursive' strategy.
Readme.md | 1 +
newFeature.py | 1 +
2 files changed, 2 insertions(+)
create mode 100644 newFeature.py
This creates a new commit
Same as starting scenario as with "3-Way merge without conflict" but now the same file was modified in both branches.
readme
file and commit it
$ echo "I shouldn't be doing this..." > Readme.md
$ git add Readme.md
$ git commit -m "Changed the readme..."
new-feature
branch into current branch CONFLICT!
$ git merge new-feature
Auto-merging Readme.md
CONFLICT (content): Merge conflict in Readme.md
Automatic merge failed; fix conflicts and then commit the result.
You have to adjust the readme
file.
git status
signalizes what needs to be done
$ git status
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Changes to be committed:
new file: newFeature.py
Unmerged paths:
(use "git add {file}..." to mark resolution)
both modified: Readme.md
The readme
file contains now both changes. Adjust it as desired
$ cat Readme.md
<<<<<<< HEAD
I shouldn't be doing this...
=======
Compile article.tex by running pdflatex on it
started to work on new feature
>>>>>>> new-feature
$ echo "Compile article.tew with pdflatex" > Readme.md
$ echo "See the new feature file for more infos" >> Readme.md
$ git add Readme.md
$ git commit -m "Merged branch 'new-feature'. Reverted stupid readme changes..."
Similiar as before, The final commit has merged the new-feature
branch into master
and has created a new commit.
There are several ways to set up remote repositories. The options range from private servers or publicly available domains. Here are a few options
$ git clone me@ssh.remote.com:/home/me/git_tutorial
Where me@ssh.remote.com
are the SSH login name and address of the remote machine and /home/me/git_tutorial
is the path to the remote repository folder.
$ git clone https://github.com/ckoerber/git_tutorial.git
Here, you learn how to set up remote repositories over SSH access. Besides step 1., this is similar for hosting services.
Even though there exist no absolute origin repo in git, for a given project it is useful to push
/pull
from just one source.
Create an empty bare
repository at remote location
$ ssh me@ssh.remote.com
$ cd /home/me
$ git init --bare git_tutorial
$ logout
Go to the path of choice. Make sure you have writing permissions.
The flag "--bare
" signalizes a repo without working directory.
You can only push
& pull
but not add
/commit
.
Tell your local repository the remote location
$ git remote add myRemote me@ssh.remote.com:/home/me/git_tutorial
"myRemote
" is now the git name (abbreviation) for the remote repository. You can name it however you like.
Fill the remote from local repository
$ git push --set-upstream myRemote master
"myRemote
" is now the git name (abbreviation) for the remote repository. You can name it however you like.
You can now clone
, push
& pull
from the remote repo.
See also the atlassian.com git cheat sheet.
Command | Info |
---|---|
git config [--global] user.name {name} |
Define author name to be used for all commits in current repo. One can commonly use the optional --global flag to set config options for current user. The same can be done for user.email . |
git init {directory} |
Creates an empty Git repo in specified directory. |
git clone {repo} |
Clones repo located at {repo} onto local machine. Original repo can be located on the local filesystem or on a remote machine via HTTP or SSH. |
Command | Info |
---|---|
git {command} -h |
Show brief help page for git command. Use --help instead of -h for long description. |
git add {directory/file} |
Stage all changes in {directory/file} for the next commit. |
git commit -m "{message}" |
Commit the staged snapshot and use message as the commit message. |
git status |
List which files are staged, unstaged and untracked. |
git log |
Display the entire commit history. |
git diff {file} |
Show unstaged changes for {file} . |
Nearly all commands come with additional flags, e.g., use git commit -am "{message}"
to automatically stage and commit all unstaged files.
Use -h
to find the flag you are looking for.
Command | Info |
---|---|
git branch {branch} |
Creates a new branch with the name {branch} . List all of the branches in your repo if {branch} is left out. |
git checkout {branch} |
Checks out the branch {branch} . |
git merge {branch} |
Merges {branch} into the current branch. |
Command | Info |
---|---|
git remote add {name} {url} |
Creates a new connection to a remote repo. After adding a remote, you can use {name} as a shortcut for {url} in other commands. Prints all available remotes if {name} and {url} are left out.
|
git pull {remote} |
Merges the specified remote's copy of the current branch into the local copy. |
git push {remote} {branch} |
Pushs the specified branch to {remote} , along with necessary commits and objects. Creates named branch in the remote repo if it doesn't exist.
|
Nearly all commands come with additional flags, e.g., use git push --set-upstream {remote} {branch}
to define the default push remote for specified branch (after this git push
without options automatically pushs the {branch}
to {remote}
).
Use -h
to find the flag you are looking for.