Xmipp

GIT brief introduction

Basic GIT documentation

GIT basic commands and equivalences to SVN

In the next lines, we will try to explain equivalences from svn typical commands to git ones.

svn command git equivalence
svn checkout repositoryURI git clone repositoryURI
svn add file1_ git add file1
svn commit -m ... git commit -m ... ; git push
svn update git pull

Migration from Subversion to GIT

Enable Git in sourceforge

  • Login as a project administrator and go to the Develop page for your project.
  • From the Project Admin menu, select Feature Settings
  • Select the Available Features tab
  • Check the box for Git; your repository will be instantly enabled, and the heading for Git should move from the Available Features tab to the Enabled Features tab.
Copy from svn to git

 git svn clone  https://newxmippdoc.svn.sourceforge.net/svnroot/newxmippdoc newxmippdoc-git
 cd newxmippdoc-git/
 git config user.name "USERNAME"
 git remote add origin ssh://USERNAME@newxmippdoc.git.sourceforge.net/gitroot/newxmippdoc/newxmippdoc
 git config branch.master.remote origin
 git config branch.master.merge refs/heads/master
 git push origin master

If git clone has interrumped then cd to the repository and continue with the command git svn fetch

download from git repository

https://sourceforge.net/account/services

Download using

 
git clone git://git.code.sf.net/p/newxmipp/code newxmipp-code (read/write)

If you do not want to type your password each type you use git copy your public ssh certificate to sourceforge using the interface

https://sourceforge.net/account/ssh

More info here

http://www.vogella.de/articles/Git/article.html#firstgit

git between local computers

(Git does not work with single files but with the whole repository, no single files checkouts)

Git is not a centralized system. It has been designed to interact with any other git repository (for the same project). A git server may be installed but ssh is adequate for sporadic interchanges ssh may be used

  • Clone git repository at clark.cnb.uam.es in pepe.cnb.uam.es.
In pepe type

git clone ssh://username@clark.cnb.uam.es/home/username/xmipp

* Update pepe (changes made and committed in clark). In pepe type

git pull

(pepe knows that should access clark because the repository was cloned from there, it is also posible to update other repositories) * Update clark (changes made in pepe) In pepe

git push

(remember to commit first) In clark

git checkout

To push to a different directory from which you clone the code: git push path/to/other/repo

Git centralized repository You may use the above approach to create a git centralized repository Init bare git repository in main server (I will call this repository aGEM)

SERVER

   mkdir aGEM
   cd aGEM
   git --bare init 

In client we have directory aGEM-dev with code

CLIENT1
  #go to directory with code and create repository
  #create git repository
  mkdir aGEM-dev
  cd aGEM-dev
   ####cp -r ../aGEM/* .
  git init
  git add .
  git commit -m "create git repository"

send code to main repository

  
  #push to server
  #add auxiliary label remote
  git remote add origin ssh://nataly@biocomp.cnb.csic.es/natalia/aGEM
  git push origin master

Delete local repository an retrieve it from main server

  
#delete client 1 git server and do as in client2  
  
#CLIENT 2 download
   rm -rf 
   git  init 
   git clone ssh://nataly@biocomp.cnb.csic.es/home/natalia/aGEM aGEM-dev

Create new file and push it to main server

#CLIENT1 add new file (locally)

 vi c.c
 git add  c.c
 git commit -m "comment c"   c.c

  #push to main server
  git push

create branch for realese 2.0

##branches
  git branch -a
  git checkout -b release2.0
  git push origin release2.0
  
  ###git checkout release2.0

#retrieve old version

Revert merge if this has not been committed to Sourceforge

Move the pointer of our branch to a previous commit:

git reset --soft HEAD^

The unwanted commit will be removed automatically by git.

Revert merge if this has already been committed to Sourceforge

  • create a branch called master2 from the commit previous the merge commit.

 git branch master2 HASH 

  • Delete master branch:

 git checkout 3.0 
git branch -D master 

  • Rename master2 to master:

 git branch -m master2 master 

  • In Sourceforge remove master branch:

 git symbolic-ref HEAD refs/heads/3.0
git branch -D master 

  • Pull the new master branch (from local repository):

 git checkout master
git pull origin master 

  • In Sourceforge set HEAD to master again:

 git symbolic-ref HEAD refs/heads/master 

Direct access to sourceforge

ssh -t user,project@shell.sourceforge.net create

Add aliases for branch

git config --add branch.3.0.remote origin git config --add branch.3.0.merge refs/heads/3.0

How to revert all local changes in a GIT managed project to previous state?

If you want to revert changes made to your working copy, do this:

git checkout .

If you want to revert changes made to the index (i.e., that you have added), do this:

git reset

If you want to revert a change that you have committed, do this:

git revert ...

Stashing

Often, when you’ve been working on part of your project, things are in a messy state and you want to switch branches for a bit to work on something else. The problem is, you don’t want to do a commit of half-done work just so you can get back to this point later. The answer to this issue is the git stash command.

$ git stash

At this point, you can easily switch branches and do work elsewhere; your changes are stored on your stack. To see which stashes you’ve stored, you can use

git stash list:

You can reapply the one you just stashed by using the command shown in the help output of the original stash command:

git stash apply

more: http://git-scm.com/book/en/Git-Tools-Stashing

Create a new branch

git branch newBranch
git commit -m "Your comments" yourFiles
git push -u origin newBranch

List all branches

git branch -a

Locally delete a branch

In a different branch from the one you want to remove, do

git branch -d oldBranch

The previous command does not allow to locally remove unless the oldBranch has been merged to another branch. If you want, anyway to locally remove the branch do

git branch -D oldBranch

Delete a remote branch

In a different branch from the one you want to remove, do

git push origin :remoteBranch

Everybody else has to "update" the list of branches in the origin, so that they also get it deleted. To do so

git remote prune origin

Close a branch

git checkout branchToClose
git commit -m "Your comments" allFilesToCommit
git push
git checkout anotherBranch
git merge branchToClose
git branch -d branchToClose
git push origin :branchToClose

Retrieve a remote branch to start working with it

To create a local branch at the status of a remote branch:

git checkout -b newlocalbranchname origin/remotebranchname

To create a branch and also set to track the remote branch:

git checkout -t origin/branch-name [-b newlocalbranch]

Copy a commit or a tail of commits from one branch to another (cherry-pick and rebase)

If you want to repeat one change you did (in one commit) in one branch within another branch, use cherry-picking. To do so, first do the commit as usually and remember (copy) the commit id. Then checkout to the destination branch, update it with the last modifications, and execute

git cherry-pick COMMIT_ID

This creates the commit in the second branch, so you don't need to execute a git commit command. But if you want the change to be uploaded to the remote server, you may want to execute a git push.

If the changes you want to repeat in the other branch are not localizated in just one commit, but in more than one, you can copy all the commits from one branch to another using the rebase utility. For that purpose, it's needed to know the commits hierarchy. Imagine a commit distribution like this...

ab546 --> b45a3 --> ca5ba --> 3651c (master)
           |
          +-> 657ca --> 245ac --> 89a1b (testing)

There you have 2 branches (master and testing) and you need to add the changes introduced in testing from 245ac commit into master branch. To do so you need to checkout to testing branch and execute...

git rebase --onto master 657ca

Note that the commit written in the rebase command is excluded from the rebase. With that command, you will get the following scenario...

ab546 --> b45a3 --> ca5ba --> 3651c (master) --> 478ca [copy of 245ac] --> 18b34 [copy of 89a1b] (testing)
           |
          +-> 657ca --> 245ac --> 89a1b 

In the case of the rebase, you have to be careful, because testing pointer is also moved with the commits, so if you don't checkout again to 89a1b commit and create a new pointer that references it, the garbage collector will act and delete the non-referenced commits (in this case, all the old-named testing branch)

Checkout a commit by date

In case of looking for a commit by date, the repository can be moved by:

git co `git rev-list -n 1 --before="2011-06-21 13:37" master`

Check which commits have not been pushed yet

git log origin/master..master

List the files that are changed between the local and the official repository

git diff origin/branch --name-only

List the files that are changed between two branches

git diff branch1 branch2  --name-only

Undo a merge in the middle of it

Let's say you are in the middle of a merging, and you regret from the changes you have already been introducing. Files that are not related to the merging conflicts are unaffected by this command.

git merge --abort

Adding a tag to set a release

Let's say we're happy with the code at a certain state, or at least, that we have to release the code at that state. For that purpose we need to set a tag. We go to the desired commit and then...

git tag -a 3.1-release -m '3.1 Xmipp oficial version'

being 3.1-release the name of the tag and the text after -m will be the description that will define the tag

After that, you'll need to upload it to the repository, by writing...

git push --tags

Deleting a remote tag

If you want to, for example, move the 3.1-release tag to one commit to another and you already commited and pushed it, it's not enough deleting it in your working copy and establishing it again. You first need to delete from remote repository by typing...

git tag -d 3.1-release

(delete local tag)

git push origin :refs/tags/3.1-release

After that, the deletion has been completed in the remote repository and then you can proceed adding a new tag with the same name and pushing it as usually

Rewritting authors' data in the history

#################################
# SCRIPT TO AMMEND USER COMMITS #
#################################

INCORRECT_MAIL=
CORRECT_NAME=
if test $# -eq 2; then
  INCORRECT_MAIL=$1
  CORRECT_NAME=$2
  CORRECT_MAIL=$1
elif test $# -eq 3; then
  INCORRECT_MAIL=$1
  CORRECT_NAME=$2
  CORRECT_MAIL=$3
else
  echo "ERROR: this script only takes 2/3 arguments:"
  echo "argument 1: mail of the committer to change"
  echo "argument 2: name that will be written to that committer"
  echo "(optional) argument 3: mail that will replace the former one"
  exit 1
fi

echo "INCORRECT MAIL: $INCORRECT_MAIL"
echo "CORRECT NAME: $CORRECT_NAME"
echo "CORRECT MAIL: $CORRECT_MAIL"

git filter-branch --env-filter 'if [ "$GIT_AUTHOR_EMAIL" = '"$INCORRECT_MAIL"' ]; then
     GIT_AUTHOR_EMAIL='"$CORRECT_MAIL"';
     GIT_AUTHOR_NAME='"$CORRECT_NAME"'; fi' -- --all

Imagine you pushed to the repository using different machines. It is recommended for you to do...

git config --global user.name "Your Name"
git config --global user.email "your@email.domain"

...but let''s say you forget the name you used last time. Your name is Pepe Rodriguez and you used Pepe Rodri in one machine but Pepe R in another different machine. By the time you realize that, a lot of time has passed and you pushed thousands of commits from each machine. How to unify that into one single name for every commit? Here's where the script from above appears into scene. You can use it (it executes git filter-branch) to re-write every commit for unifying your name, and for changing your email into another. If you execute it with 2 args, you'll just re-write every commit with the given e-mail into the given name. If you put 3 args, then you will be also giving the new e-mail you want to write into those commits.

Oh god! my code webpages are not working!

Sometimes sourceforge code webpages can stop working. In our experience, this can be because a missing post-receive hook in the repository. In that case, you need to access the sourceforge repostory via ssh, and, inside hook folder, add the following script named as "post-receive":

#!/bin/bash
# The following is required for site integration, do not remove/modify.
# Place user hook code in post-receive-user and it will be called from here.
curl -s http://sourceforge.net/auth/refresh_repo/p/PROJECTNAME/MOUNTPOINT/

DIR="$(dirname "${BASH_SOURCE[0]}")"
if [ -x $DIR/post-receive-user ]; then
  exec $DIR/post-receive-user
fi

That will do the job. In the specific case of Xmipp, this is placed in /home/git/p/newxmipp/code.git/hooks/post-receive and its code is

#!/bin/bash
# The following is required for site integration, do not remove/modify.
# Place user hook code in post-receive-user and it will be called from here.
curl -s http://sourceforge.net/auth/refresh_repo/p/newxmipp/code/

DIR="$(dirname "${BASH_SOURCE[0]}")"
if [ -x $DIR/post-receive-user ]; then
  exec $DIR/post-receive-user
fi

Brief guide to "How to deal with master and 3.1 branch"

See ReleaseManagement

Additional info

http://freeplane.sourceforge.net/wiki/index.php/Git_howto