refresher for SoftGroup staff

Wednesday, 12nd of October, 2016

git

  • Distributed version control system
  • Local, no server needed

- multiple backups

- fast operations

- works offline

  • Branching model

- paradigm shift compared to CVS, SVN

- designed for multiple branches

- easy context switching

- enable a lot of workflows

git: (very) basic usage - 1

  • Create a repository
matias@kashyyyk /tmp/training $ git init
Initialized empty Git repository in /tmp/training/.git/

- default branch is called 'master'

matias@kashyyyk /tmp/training $ git status
On branch master

Initial commit

nothing to commit (create/copy files and use "git add" to track)
  • Status of a repository

git: (very) basic usage - 2

  • Committing changes
  •  do the commit, select which files (all files: -a switch) +  mandatory message
matias@kashyyyk /tmp/training $ git commit -a -m "first commit"
  • (stage files to commit, if needed - e.g. for new files)
matias@kashyyyk /tmp/training $ git add .
  •  Write good commit messages ! Help here

NB:
 git commits

(and git objects in general)

are identified

by SHA-1 hashes

commit c9f390172d109cf2bbc688648ca58796ef6f7c9

Use a graphical tool for commits !

  • commit only parts of files
  • synthetic view
  • revert changes

git gui

git: (very) basic usage - 3

  • Create a branch
matias@kashyyyk /tmp/training $ git checkout -b my_new_branch
Switched to a new branch 'my_new_branch'

  • Switch to an existing branch
matias@kashyyyk /tmp/training $ git checkout master
Switched to a new branch 'master'

Use a graphical tool to look at your repository

  • see commits, search
  • see all branches (gitk --all)
  • see changes (gitk specific_file for all changes to 1 file in particular)

gitk

Useful git commands - 1

  • grep in all files of the repository
matias@kashyyyk ~/dev/mxcube3 $ git grep SampleChanger
mxcube3/__init__.py:    import routes.Main, routes.Login, routes.Beamline, routes.Collection, routes.Mockups, routes.S
mxcube3/routes/Login.py:            basket = int(sample_info["containerSampleChangerLocation"])
mxcube3/routes/Login.py:                sample_info["containerSampleChangerLocation"] = "%d:%d" % (cell, puck)
mxcube3/routes/Sample.py:    data = {generic_data, "SampleId":id, sample_data={'holderLength': 22.0, 'code': None, 'co
mxcube3/routes/Sample.py:    data = {generic_data, "SampleId":id, sample_data={'holderLength': 22.0, 'code': None, 'co
mxcube3/routes/Sample.py:    return_data={"SampleId":id, sample_data={'holderLength': 22.0, 'code': None, 'containerSa
mxcube3/ui/reducers/SamplesGrid.js:              const limsLocation = `${sampleInfo.containerSampleChangerLocation} :
  • reflog : shows information recorded when branch is updated
matias@kashyyyk ~/dev/mxcube3 $ git reflog
c9f3901 HEAD@{0}: checkout: moving from master to p
38aadf5 HEAD@{1}: checkout: moving from api to master
fe6d237 HEAD@{2}: checkout: moving from server_uistate to api
3c6289a HEAD@{3}: checkout: moving from master to server_uistate
38aadf5 HEAD@{4}: pull origin: Fast-forward
6abec15 HEAD@{5}: pull: Fast-forward
37301af HEAD@{6}: pull: Fast-forward
77c2377 HEAD@{7}: checkout: moving from redux_persist to master

helps recovering from (almost) any situation: lost commits recovery, undo...

Useful git commands - 2

  • git log -S'something'
matias@kashyyyk ~/dev/mxcube3 $  git log -S'SampleGrid' --oneline
d11be99 Changed case of sample_grid to SampleGrid
f732dc8 Improved the way the grid size (width and number of columns) are calculated.
2ea69e2 Added the possibility to move sample items
  • git diff: shows differences between 2 versions
matias@kashyyyk ~/dev/mxcube3 $ git diff master origin/refactoring -- ./mxcube3/__init__.py
diff --git a/mxcube3/__init__.py b/mxcube3/__init__.py
index 7c59ac2..2ee2393 100644
--- a/mxcube3/__init__.py
+++ b/mxcube3/__init__.py
@@ -1,15 +1,13 @@
 from __future__ import absolute_import
 from flask import Flask
-from flask import request
 from flask.ext.socketio import SocketIO
 from flask.ext.session import Session

search for commits adding or removing 'something'

... also works with 'gitk' :)

syntax: git diff branchA branchB -- path to file

Useful git commands - 3

  • Reverting a file from an existing branch
matias@kashyyyk ~/dev/mxcube3 $  git checkout my_branch -- path to file
  • cherry-pick: apply an existing commit to the current branch

Usage: applying a bug fix from a branch to another one, without getting all changes introduced by commits from this branch

matias@kashyyyk ~/dev/mxcube3 $  git cherry-pick a188350

Ready for more advanced stuff ?

A word about HEAD

  • HEAD: pointer to the current commit of the current branch
matias@kashyyyk /tmp/training $ git reset --hard HEAD

command above removes all uncommitted changes (but it doesn't delete untracked files - see 'git clean' for this !)

advice: commit often, commit early to avoid uncommitted changes

you can squash your X latest commits into one using

'git rebase -i HEAD~X'

ACHTUNG: only for commits you didn't share with others yet, since it is rewriting the commits history

Stash

  • git stash: puts all uncommitted changes in a safe place, and restores working tree to latest HEAD
  • git stash list: displays stashes (cachettes)
  • git stash pop: apply latest stash, and removes it
  • git stash drop: discards latest stash
  • git stash branch XXX: create a new branch XXX at the original commit when the stash has been done, apply stashed changes, and removes the stash

Submodules - 1

  • Reference a git repository within another git repository
  • The reference is a precise commit

Very convenient to guarantee the container project works, whatever happened to the submodule

Similar to subversion's Externals, in a way

  • as a consequence, a submodule doesn't follow its parent code automatically : this is what is causing so much trouble to newcomers

When the submodule is initialized, it is in "detached HEAD" state: the HEAD is not in a branch

Submodules - 2

matias@brian /tmp/training $ tree
.
├── HelloC
│   └── hello.c
└── HelloPython
    └── hello.py

1. Two git repositories, HelloC and HelloPython

matias@brian /tmp/training $ mkdir Hello; cd Hello; git init
Initialized empty Git repository in /tmp/submodules/Hello/.git/

2. Let's create a new Hello git repository

3. Add the submodules

matias@brian /tmp/submodules/Hello $ git submodule add ../HelloC
Cloning into 'HelloC'...
done.
matias@brian /tmp/submodules/Hello $ git submodule add ../HelloPython
Cloning into 'HelloPython'...
done.
matias@brian /tmp/submodules/Hello $ tree
.
├── HelloC
│   └── hello.c
└── HelloPython
    └── hello.py

2 directories, 2 files
git commit -a -m "added submodules"
[master (root-commit) 4b1bc96] added submodules
 3 files changed, 8 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 HelloC
 create mode 160000 HelloPython

4. Commit the submodule update

Done !

Collaborating using remotes

  • Distributed nature of git

- remote repositories are versions of your project located elsewhere

- can be on the internet, over a private network, or on disk

- code can be pushed to or pulled from a remote

  • For BCU, first remote for your project is on gitlab (or github in case of external collaboration)

- first remote is often called 'origin'

- this is where the code originally comes from

- ... but it is just a name, remotes can be called anything

  • The remote URL is useful to clone a repository

- git clone : make a local copy of a remote repository

git remote

  • Showing remotes
  • Adding a remote
matias@brian ~/dev/mxcube3 $ git remote -v
matias	git@github.com:mguijarr/mxcube3 (fetch)
matias	git@github.com:mguijarr/mxcube3 (push)
origin	git@github.com:mxcube/mxcube3 (fetch)
origin	git@github.com:mxcube/mxcube3 (push)
matias@brian ~/dev/mxcube3 $ git remote add marcus git://github.com/marcus-oscarsson/mxcube3

matias@brian ~/dev/mxcube3 $ git remote -v
marcus	git://github.com/marcus-oscarsson/mxcube3 (fetch)
marcus	git://github.com/marcus-oscarsson/mxcube3 (push)
matias	git@github.com:mguijarr/mxcube3 (fetch)
matias	git@github.com:mguijarr/mxcube3 (push)
origin	git@github.com:mxcube/mxcube3 (fetch)
origin	git@github.com:mxcube/mxcube3 (push)

git fetch

  • Downloading changes from a remote repository
matias@brian ~/dev/mxcube3 $ git fetch marcus
remote: Counting objects: 430, done.
remote: Compressing objects: 100% (146/146), done.
remote: Total 430 (delta 329), reused 233 (delta 233), pack-reused 51
Receiving objects: 100% (430/430), 84.30 KiB | 0 bytes/s, done.
Resolving deltas: 100% (332/332), completed with 91 local objects.
From git://github.com/marcus-oscarsson/mxcube3
 * [new branch]      api        -> marcus/api
 * [new branch]      master     -> marcus/master
 * [new branch]      prototype  -> marcus/prototype
 * [new branch]      queue-api  -> marcus/queue-api
 * [new branch]      sample-queue-id -> marcus/sample-queue-id
 * [new branch]      samplegrid-queue -> marcus/samplegrid-queue
 * [new branch]      serformat  -> marcus/serformat
 * [new branch]      serialization -> marcus/serialization

Remote branches - 1

  • Getting list of all branches (locales and remotes)
matias@brian ~/dev/mxcube3 $ git branch -ra
 *master
  redux_persist
  server_uistate
  remotes/marcus/api
  remotes/marcus/master
  remotes/marcus/prototype
  remotes/marcus/queue-api
  remotes/marcus/sample-queue-id
  remotes/marcus/samplegrid-queue
  remotes/marcus/serformat
  remotes/marcus/serialization
  remotes/matias/master
  remotes/origin/master
  remotes/origin/mxcube-temporary
  remotes/origin/redux_persist
  remotes/origin/refactoring

  • Duplicating a remote branch for local use
matias@brian ~/dev/mxcube3 $ git checkout -b copy_of_marcus_api marcus/api
Branch copy_of_marcus_api set up to track remote branch api from marcus.
Switched to a new branch 'copy_of_marcus_api'

Remote branches - 2

  • Pushing
matias@brian ~/dev/mxcube3 $ git push origin master

  • Pulling
matias@brian ~/dev/mxcube3 $ git pull

"push the commits from local branch to the origin remote, in the master branch"

'git pull' does a 'git fetch' + a 'git merge'

If remote branch tracking is enabled, it automatically merges the remote branch into the local one

git merge

git rebase

  • much cleaner project history (no merge commits)
  • perfectly linear project history—you can follow the tip of feature all the way to the beginning of the project without any forks
  • easier to navigate with commands like git log, git bisect, and gitk

We prefer rebase vs merge

BUT beware: NEVER rebase a public branch !

Configure 'git pull' to do rebase instead of merge

git config --global pull.rebase true

Our git workflow

  • Feature branch workflow

- stable master branch

- new features in branches

- merge requests (with gitlab)

  • Many advantages

- in theory, master should not contain broken code

- facilitates Continuous Integration

- several developers can work on a new feature without disturbing the main codebase

- communication++ between developers, code review

Merge request

  • Feature branch workflow

- only 1 public repository

- pushed branches have to be merged

- source for merge request will always be from a feature branch

- destination will always be 'master' branch