Skip to content
Thomas Gläßle edited this page May 16, 2017 · 16 revisions

MAD-X has migrated from SVN to git version control.

Cheat sheet

For users not familiar with git, we provide some references and a cheat sheet that will cover the most common use cases:

In more detail:

Getting help

I can't stress this enough: git has among the best help system of all command line tools that you will ever see:

git help
git help COMMAND

Try it now:

git help commit

Note that git also has great official online resources such as tutorials and comprehensive documentation that you should absolutely refer to in case of problems. These will provide a much better insight over the tool than the quick cheat sheet we will provide here.

Git concepts

This following is a non-comprehensive list of the most important conceptual differences between SVN and GIT. It is not strictly required to work with git but understanding it will make your life a lot easier down the road:

  • git history is structured as a DAG (directed acyclic graph) of commits rather than a linear series of revisions. This is great to represent the graph structure due to branching.
  • git commits are labeled by their SHA1 hash rather than a revision number.
  • a branch or tag in git is just a pointer to a commit, in SVN a branch or tag is a copy of a directory. Branching and tagging in git are extremely lightweight operations (creating a pointer).
  • git has an index or staging area that determines what goes into the next commit. Changes can be added with very fine-graded control to the index. If you type git diff, you can see the changes in the current working directory versus the current index. If you type git diff --cached, you can see the changes that have been added to the index versus the current HEAD.
  • git is a distributed VCS, which means that it has a very flexible approach to working with no or many other parties (see Remotes) – as opposed to SVN where you are usually bound to exactly one upstream SVN server.
  • The recommended work-flow in git is that everyone operates on their own repository rather than working simultaneously on the upstream repository as in SVN. This makes it a lot easier to deal with merge conflicts.
  • git checkouts are fully-fledged forks of the entire repository including its history. They can function fully independent of the original repository.
  • That's why most git operations never touch the network, and are therefore very fast operations that don't require a password. This is different from SVN where even simple operations such as svn log may require entering a password.
  • In fact, git can be used without any local or remote server. You can turn arbitrary directories into git repositories by typing git init and later add a remote URL if you want to share or backup your changes.

More about git internals:

  • HEAD is the symbolic name of the commit that is currently checked out.
  • git repositories are a collection of objects stored inside the .git repository.
  • git objects consist of some blob of data and are referenced by their SHA-1 hash. The most important objects and their data blobs are:
    • file: the file content
    • tree: list of references to files and sub trees
    • commit: commit message; reference to the file tree; author, date and other metadata
  • git branches are just pointers (references to) to commits.
  • git has a garbage collector that can delete objects if they become unreferenced for too long (more than one week). Objects referenced directly or indirectly by a branch or tag will never be deleted by git.
  • As long as objects are not deleted they can always be checked out or queried otherwise. git reflog is a useful tool to get the hashes of commits that were deleted by accident.

Overview

The recommended work-flow in git is that everyone operates on their own repository rather than working simultaneously on the upstream repository as in SVN. This makes it a lot easier to deal with merge conflicts.

Do once the following:

In order to contribute patches, do the following:

  • make sure your upstream is up-to-date and create a branch for your new feature/bugfix. Most of the time it's best to branch off the upstream master:

    git fetch upstream
    git checkout -b feature upstream/master
    git push -u origin feature
    

    (Note that the fetch command just fetches data to be stored in the .git folder but never interferes with your local checkout.)

  • edit files, build and test:

    vim src/twiss.f90
    make madx-linux64-gnu
    make tests
    
  • add relevant changes to the INDEX:

    git diff                        # check the diff to be added
    git add src/twiss.f90           # add complete file(s)
    git add src/twiss.f90 -p        # select chunks within file to add
  • inspect the status and commit added changes to your local repository:

    git status                      # check which files will be committed
    git diff --cached               # check the diff to be committed
    git commit -m "Implement awesome feature XYZ"
    
  • check your commit log:

    git log                         # commits of current branch
    git log --all --graph           # all branches
  • if/when you want, upload your changes to github:

    git push
    
  • create a pull request on the github site

  • if there are conflicts with the upstream master:

    # if you have uncommitted changes (or commit!):
    git stash
    
    # pull in the upstream master:
    git pull upstream master
    
    # manually resolve conflicts, relevant sections enclosed by
    # "<<<<", "====", ">>>>>" lines:
    vim src/twiss.f90
    
    # add and commit conflict resolution:
    git add src/twiss.f90
    git status
    git commit
    git push
  • if you want to reorder/join/drop commits or you have a branch that is based on an old version of master and you want to move (reapply) the commits onto the new master (or another branch):

    git fetch upstream
    git rebase -i upstream/master
    

    In certain situations, you might need:

    git rebase -i --onto upstream/master BASE_POINT BRANCH_NAME
    

    Where BASE_POINT specifies the parent of the first commit to reapply onto the upstream master.

Cloning

For users without github account or SSH key:

git clone https://github.com/MethodicalAcceleratorDesign/MAD-X

For users with github account and SSH key:

git clone [email protected]:MethodicalAcceleratorDesign/MAD-X

Note that (unlike SVN) cloning the repository fetches the entire history and creates a fully-fledged repository on which you can work and commit locally without having to push your changes to the upstream repository.

If you plan to contribute, you should fork the repository:

Forking

Login to your github account and fork the MAD-X repository to your own account (using the button somewhere in the upper right). I recommend accessing your fork via SSH (See Adding an SSH key).

Now clone your fork using:

git clone [email protected]:USERNAME/MAD-X

If you had already cloned the upstream repository, you can add your own fork as an additional remote:

git remote add myfork [email protected]:USERNAME/MAD-X

Remotes

As a distributed version control system, git features a very flexible approach to working with multiple parties. This is captured by the concepts of remotes which specify the URLs (or filesystem path) of remote repositories.

List your remotes:

git remote -v           # -v stands for verbose

Add a new remote and fetch data into your .git folder (does not change the current working directory):

git remote add NAME URL
git fetch NAME

Rename an existing remote:

git remote rename OLD NEW

Delete a remote:

git remote rm NAME

For example, if you have cloned the upstream repository, created a few commits, then forked the repository and you now want to add your fork in order to push commits there, you can add it as a new remote like this:

git remote add myfork [email protected]:USERNAME/MAD-X
git fetch

OR:

git remote rename origin upstream
git remote add origin [email protected]:USERNAME/MAD-X
git fetch origin

Adding an SSH key

If you plan to contribute, I recommend accessing the repository via SSH rather than HTTPS. This means that you will not have to enter your password on every push. If you haven't already, create an SSH key:

ssh-keygen -b 4096

You can leave the password blank to store the key unencrypted (!) to your home folder. In this case, you won't need to enter password when pushing (in my opinion, if someone gets access to your harddrive, all your data is compromised anyway). If you dislike storing the key without further protection, you can enter a password and consider

Copy the SSH public key (cat ~/.ssh/config/id_rsa.pub) and add it on your github settings page.

Contributing changes

Settings and aliases

You may find it convenient to add a few basic aliases and settings to your ~/.gitconfig. I encourage you to try and find out how these aliases work and what they do:

[core]
    editor = vim
    excludesfile = /home/thomas/.gitignore_global
    filemode = true

[alias]
    co = checkout
    cp = cherry-pick
    st = status
    re = remote -v

    # fixup current index to the previous commit
    amend = commit --amend
    amenda = commit --amend -a

    # merge and create a structural merge-commit (no fast-forward)
    mm = merge --no-ff

    # useful diffs:
    cdiff = diff --cached
    wdiff = diff --word-diff=color
    wcdiff = diff --cached --word-diff=color

    # log with graph structure:
    alog = log  --graph --all --format=cmedium

    # unstage (remove from index) some files:
    unstage = reset HEAD --

    # checkout pull request by issue number (and remote name):
    copr = "!f() { git fetch -fu ${2:-origin} refs/pull/$1/head:pr/$1 && git checkout pr/$1; }; f"

# enable/specify colors:
[color]
    ui = true
[color "branch"]
    current = yellow reverse
    local = yellow
    remote = green
[color "diff"]
    meta = yellow bold
    frag = magenta bold
    old = red bold
    new = green bold
[color "status"]
    added = yellow
    updated = green
    changed = magenta
    untracked = cyan
    branch = green bold

[diff]
    tool = vimdiff
[difftool]
    prompt = false

# required for the nice graph log:
[pretty]
    cmedium =\
%C(yellow)%h%C(cyan)% an %C(green)(%ar)%C(red)%d%n\
%C(white)%s%n\

Clone this wiki locally