A minimal git work flow
Preface
Target audience
This is intended to allow working together with other people using git. It will only cover the bare minimum of a very simple work flow ignoring many advanced, medium, and even basic features. The target audience are people who don't want to invest a lot of time in learning git but need to know the bare minimum to use it, because their collaborators forced them to do so. There's a summary/short version listing the discussed commands at the very bottom.
Disclaimer
If you really want to learn git, please ignore the present page and consult one of the many good git tutorials, for example the Pro Git book. More information is available on the official git documentation webpage.
Introduction
Git is a distributed version control system. The main idea is, that every user has its own copy of the repository including its wn history. In the following we assume in addition that there is one central version of the repository on a server. The history of different copies may be different and keeping them in sync (to some extend) requires to take explicit action. In this setting there are essentially three types of operations:
- Clone the existing (central) repository to get a local copy.
- Work with your local repository. It is important to note that you can work on this copy independently of the central repository. For example you can commit your changes to your local repository without having access to the central server.
- Syncing your local repository and the central repository on the server.
The following describes a very simple work flow ignoring e.g.
the possibility to use several branches. In git terminology this
means that we will only consider working on the so called master
branch.
The described work flow roughly resembles, the classical work flow
implemented by Subversion.
In all commands described below <arg>
is a placeholder
for an argument and [<arg>]
is a placeholder for an optional
argument.
More details (can be skip on first reading)
It should be noted that this is just one possible work flow and that git allows to do a lot more. For example you can work with multiple branches of a repository, sync with multiple servers, distribute commits by e-mail, modify the repository history afterwards. Also a central server often comes with a nice web front end that allows to nicely view the history, track issues, setup automated test environments, manage merge requests for development, review, and integration of features using multiple branches, etc.
Getting your copy of the repository
To get a copy you need to clone an existing repository
which is often located on a server. A repository
located under some given <adress>
can be cloned using
git clone <adress> [<name>]
If an optional [<name>]
is given, the latter is used
for the generated directory. Otherwise the directory is
named according to the repository. Often, a repository can be
accessed using different protocols encoded in the adress
(e.g. git@git.imp.fu-berlin.de:owner/repository.git
or
https://git.imp.fu-berlin.de/owner/repository.git
).
In this case the git@...
variant is preferred if you
later want to write to the repository.
Notice that this requires properly setup credentials,
which should be no problem, if you have done this before for the server.
The local clone/copy of the repository will not be synchronized automatically (like e.g. Dropbox or Nextcloud) but only once you explicitly initiate this using the command given below.
Working with your local repository
In contrast to Subversion you can work with your local repository
independently of the repository on the server. In order to do this
git manages files by using three different categories.
The versions of files that have been commited and are part of the history
are what makes up the repository which is stored in the hidden .git
subdirectory.
The normal files that you can see and access in the directory are denoted
as working tree. Modifying or adding files in the directory only
changes the working tree and leaves the local repository unchanged.
Finally the index is a list of files to be marked for committing.
One or multiple modified files in the work tree can be committed using
git commit <file1> <file2> ... -m"[short describtion of your changes]"
This will store your modified versions to the repository by creating a new commit/revision. If you simply want to commit all locally modified files this can be achieved using
git commit -a -m"[short describtion of your changes]"
In both versions the index is not involved. Alternatively you can mark several files for committing using
git add <file1> <file2> ...
...
git add <file3> ...
This will add the given files to the index. Later you can commit all files in the index using a plain
git commit -m"[short describtion of your changes]"
While both versions work for modifying existing files, you need to use the second one for new files
git add <newfile>
git commit -m"[short describtion of your changes]"
The message should briefly describe what your change was about, e.g. "Add theorem on bla..." or "Make all text pink since I like this more". Omitting the message will open an editor for you to enter it. If you find your self in the seemingly nerdy VI-editor you may exit it using :q! and retry giving the message on the command line.
To see the status of your repository you can use
git status
This will list all locally modified files in the work tree, all files staged in the index, and all unknown files. Furthermore it will show some information on how your local repository differs from the latest known state of the central repository.
Syncing local and central repositories
All add and commit actions will only modify your local repository. In order to apply your changes to a central repository or get updates form the latter you need to synchronize your repository. To the end git automatically stores information on the location of the original repository when creating your local clone. (This is called a remote in git terminology.)
Updating the local repository
The easiest way to get updates from the central repository is
git pull -r
This will first download the latest version of the central repository,
then bring your local repository to the state of the latter,
and finally try to reapply your local commits on top of this.
This way of combining two states (local and the central repository)
is called rebasing.
It's a good idea to do this before you start modifying files locally.
If this succeeds, git status
will normally tell you, that
your local repository (to be precise its master
branch)
is ahead of the remote repository (origin/server
).
Sending you changes to the central repository
Now you can push your changes to the server using
git push
Then the central repository will be on the same state as the local
one. If the central repository was meanwhile modified (by someone else doing a
git push
), then pushing will fail because you
first have to do git pull -r
again. This way merging of different
versions will always happen locally to avoid generating a broken version
on the server.
More details (can be skip on first reading)
In fact you can do the above in a more fine-grained way. To only download the latest information from the server without modifying your local repository you can use
git fetch
Afterwards git status
may (or may not) tell you that your local repository (master
)
lacks behind what is now known from the central one (origin/master
).
Similarly you can update your repository from the currently known information
without downloading utilizing the rebasing strategy outlined above using
git rebase
Hence git pull -r
is equivalent to git fetch; git rebase
.
There is also another strategy for combining two states of a repository.
Using
git merge
will not try to apply one sequence of changes on top of the other but combine
the final state of both. In contrast to git rebase
this may lead to a diamond-like
history. Again you can do a combined git fetch; git merge
using git pull
.
Short version
Clone existing repository:
git clone <adress> [<name>]
Update local repository:
git pull -r
Add new files (mark for committing):
git add <new file>
Commit files:
git commit <file1> <file2> ... -m"[short describtion of your changes]"
Sent you changes to the server:
git push