Workshop

Antoine Froger

Git

 

(survival kit)

Workflow

The Working directory
The Index (or stage)
The HEAD

Sandbox

The 3 trees

Proposed next commit snapshot

Last commit snapshot

New file

Add

Commit

Clean

branches

Display branches

Local branches

$ git branch
* master
  rebase-i-demo
  untracked-demo

All branches (local and distant)

$ git branch -a
* master
  rebase-i-demo
  untracked-demo
  remotes/origin/HEAD -> origin/master 
  remotes/origin/master

Oups...

Wrong name ?

// Rename branch
$ git branch -m branch-old-name branch-new-name
// Rename current branch
$ git branch -m branch-new-name
$ git branch -a
  master
  rebase-i-demo
  untracked-demo
* branch-new-name

Delete branch

Don't need this branch anymore

$ git branch -d obsolete-branch
// equivalent to git branch --delete
error: The branch 'obsolete-branch' is not fully merged.
If you are sure you want to delete it, run 'git branch -D 
obsolete-branch'
$ git branch -D obsolete-branch
// Shortcut for --delete --force
Deleted branch obsolete-branch (was 12345)

Usefull options

Displays some information about the last commit

$ git branch -vv
* master        a3d3414 [origin/master] Add homepage
  rebase-i-demo a15dc16 Revert "Create documentation"
...

-vv

Only displays unmerged branches

$ git branch --no-merged
  rebase-i-demo

--no-merged

Only displays merged branches

$ git branch --merged
* master
  untracked-demo

--merged

Atomic commits

one commit

=

one responsability

easier to understand

easier to review

easier to revert

Detailed status

Show untracked files

$ git status
...
Untracked files:
...
    README.md
    vendor/
$ git status -u
$ // git config --global status.showUntrackedFiles all
$ // git status 
...
Untracked files:
...
    README.md
    vendor/autoload.php
    vendor/composer/ClassLoader.php
    vendor/composer/LICENSE

Show your changes

$ git diff

Unstaged changes

$ git diff --staged

Staged changes

$ git diff -w

Without whitespaces

All files

$ git add .
$ // git add --all
$ git status
...
Changes to be committed:
...
    new file: README.md
    new file: composer.json
...

Add files to the stage

A specific file

$ git add README.md
$ git status
...
Changes to be committed:
...
    new file: README.md

Only add a fragment

Because you want atomic commits and not catch-all commits

$ git add -p README.md
...
# Git (for beginners)

+ This repository is dedicated to the git workshop
...
Stage this hunk [y,n,q,a,d,/,s,e,?]? y

...

## Commits
## Pushes
+## Branches
...
Stage this hunk [y,n,q,a,d,/,s,e,?]? n

Add files to the stage

Unstage files

One file

$ git reset README.md
Unstaged changes after reset
M    README.md

All the files

$ git reset
Unstaged changes after reset
M    README.md

Only a section of a file

$ git reset -p README.md
...
## Pushes
+## Branches
...
Unstage this hunk [y,n,q,a,d,/,s,e,?]?

Keep your changes at hand

git stash is your friend

$ git stash save "Fix a typo"
$ //git stash save -u "Fix a typo" (also stash untracked files)
Unstaged changes after reset
M    README.md

$ git stash list
stash@{0}: On master: Fix a typo
stash@{1}: On my-branch: Add italian translations
stash@{2}: On master: Fix bug #123

 

$ git stash show [stash@{0}]
 README.md | 5 +++--

Get your changes back

Apply a stash

$ git stash apply stash@{1}
...
Changes not staged for commit:
     modified:  README.md
...

Apply and drop a stash

$ git stash pop stash@{1}
...
Changes not staged for commit:
     modified:  README.md
...

And the

untracked files

There is a shortcut for that

$ git stash -u
Saved working directory and index state WIP on branch-name: 8ad48aa My commit comment

HEAD is now at 8ad48aa My commit comment

Remove untracked files or directory

Untracked files

$ git clean

Untracked directories

$ git clean -d

Not sure of what you're doing ?

$ git clean -n
// equivalent to --dry-run

Force

$ git clean -f

Finally, commit your changes

$ git commit -m "An intelligible message" README.md
[master 12345] An intelligible message
  1 file changed, 1 insertion(+), 1 deletion(-)
$ git add CHANGELOG-1.0.md
$ git commit --amend --no-edit
[master 67890] An intelligible message
  2 files changed, 2 insertion(+), 1 deletion(-)

Forgot a file ?

$ git commit --amend -m "A new message without typos"

Want to change the message ?

Error in a commit...

$ git reset HEAD~1
// 1 is the number of commit to cancel
Unstaged changes after reset:
M    my-updated-file.md

Cancel a commit

(but do not revert the changes)

Great pushes

Push one branch

at the same time

Push the current branch if it's tracked and distant and local name are identicall (default mode since git 2.0)

Push the current branch if it's tracked (regardless of its name)

$ git config --global push.default simple 
$ git config --global push.default upstream 

Warning: before git 2.0 default mode was matching. Push all branches having the same distant and local name

First push

Push and track

(tracked) $ git push -u origin tracked
...
To git@github.com:antfroger/git-intro.
 * [new branch]  tracked -> tracked

Branch tracked set up to track remote branch to tracked origin

Forget to track ?

(untracked) $ git branch --set-upstream-to=origin/untracked untracked
Branch untracked set up to track remote branch to untracked origin

Clean the history

git rebase -i

(BUG-123) $ git rebase -i origin/BUG-123

Before pushing, clean the history: remove useless commit, merge two commits, reorganise commits...

pick 6e70bd9 Add description
pick 1b6d5ae Add dependency
pick d590486 Forget dependency
pick 08e6ace Fix typo
pick af15bf3 Add changelog + create .gitignore
pick f1f53a9 Create documentation
pick a15dc16 Revert "Create documentation"
...
​# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = se commit, but stop for amending
...

Pull correctly

By default, when you pull, git execute a merge after pulling.

 

But what you want is not merging the distant branch into your current branch but get the distant changes and re-execute your changes on the up-to-date local branch  = rebase.

 

Merge should only be used to integrate your changes into a parent branch.

$ git config --global pull.rebase preserve

Merge or rebase ?

What's the difference ?

Git merge

Join two or more development histories together

A git merge should only be used for incorporating the entire feature set of branch into another one, in order to preserve a useful, semantically correct history graph. Such a clean graph has significant added value.

Christophe Porteneuve

Git rebase

Reapply commits on top of another base tip

Example

Initial situation

Merge

Rebase

Others

features...

Logs

$ git log

Logs are useful to understand what was done.

Logs

Options are available

$ git log --stat
$ git log --graph

Logs

And many others...

$ git log -p
$ git log -s
$ git log -U
$ git log --raw
$ git log --histogram
$ git log --shortstat
$ git log --summary
$ git log -z
$ git log --name-only
$ git log --check

...

La doc de git log: git-scm.com/docs/git-log

Grep

You want to search only on the tracked files ?
git grep is for you

$ git grep -a "doc"
composer.lock:                "doctrine/couchdb": "~1.0@dev",
composer.lock:                "doctrine/dbal": "~2.2",
composer.lock:                "doctrine/annotations": "~1.0",
composer.lock:                "doctrine/common": "~2.2",
...
(END)

Grep

You want to search only on the tracked files ?
git grep is for you

$ git grep -a "doc"
composer.lock:                "doctrine/couchdb": "~1.0@dev",
composer.lock:                "doctrine/dbal": "~2.2",
composer.lock:                "doctrine/annotations": "~1.0",
composer.lock:                "doctrine/common": "~2.2",
...
(END)

And more !

Lots of other functions exist
Read the doc !

 

git-scm.com/docs

Thanks

for listening to me

Antoine Froger
@__tooni__

 

 

Slides available on slides.com/antfroger/git-survival-kit

Made with Slides.com