Git Tips

git-rebase

Eventually you’ll discover the Easter egg in Git: all meaningful operations can be expressed in terms of the rebase command. Once you figure that out it all makes sense.

Linus Torvalds

What does rebase do?

      A---B---C topic
     /
D---E master
      A---B---C topic
     /
D---E---F---G master
$ git rebase --onto master topic
              A'--B'--C' topic
             /
D---E---F---G master
D---E---F---G--A'--B'--C' topic
 
 

It can get more complex...

o---o---o---o---o  master
     \
      o---o---o---o---o  next
 
 
o---o---o---o---o  master
     \
      o---o---o---o---o  next
                       \
                        o---o---o  topic
$ git rebase --onto master next topic
 o---o---o---o---o  master
     |            \
     |             o'--o'--o'  topic
      \
       o---o---o---o---o  next

When to rebase?

Rebase only topic branches!

Rebasing (or any other form of rewriting) a branch that others have based work on is a bad idea: anyone downstream of it is forced to manually fix their history.

git-rebase --help

git-rebase--interactive

As an idea, squish your commits into one.

This will tidy up the history.

I know what you're thinking...

History? You know how many bugs we have?

Nobody cares about the fucking history!

History is for noobz! Pwnd!

Thats why I'm gonna show you this cool exec trick!

pick deadbee Implement feature XXX
fixup f1a5c00 Fix to feature XXX
exec make
pick c0ffeee The oneline of the next commit
edit deadbab The oneline of the commit after
exec cd subdir; make test

git-merge

What does merge do?

      A---B---C topic
     /
D---E master
      A---B---C topic
     /
D---E---F---G master
$ git merge topic
      A---B---C topic
     /         \
D---E---F---G---H master

See the difference to rebase?

A, B and C are the same!

H has both G and C as parents.

This behaviour is not guaranteed.

      A---B---C topic
     /
D---E master
$ git merge topic
      A---B---C topic
     /          master
D---E

C is the same for both branches!

      A---B---C topic
     /
D---E master
$ git merge topic --no-ff
      A---B---C topic
     /         \
D---E-----------F master

git-branch

Branches are pointers.

Thats why they're fast.

Thats why fast-forwarding is possible.

Each commit has one or many parents.

Thats why you can checkout commits.

Thats why you revert merge commits differently.

git-pull

Like managing your local branches was easy...

      A---B---C topic
     /
D---E master (me)
 
 
D---E---F---H master (you)
$ git pull you master
      A---B---C topic
     /
D---E---F---H master (me)

Consider this.

      A---B---C topic
     /         \
D---E-----------P master (me)
 
 
 
 
D---E---F---H master (you)
 
 
$ git pull you master
      A---B---C topic
     /         \
D---E-----------P---M master (me)
      \            /
       F---H-------

Oh, git-pull merges branches.

      A---B---C topic
     /         \
D---E-----------P master (me)
 
 
D---E---F---H master (you)
$ git pull you master --rebase
      A---B---C topic
     /         \
D---E-----------P---F'--H' master (me)

That's why you don't create PR's from master to master.

It fucks up the history!

      A---B---C topic
     /         \
D---E-----------P master (me)
      A---B---C topic
     /         \
D---E-----------P---H master (you)
$ git pull you master --no-ff
      A---B---C topic
     /         \
D---E-----------P---H---M master (me)

Just give me a moment...

git-reset

      A---B---C topic
     /         \
D---E-----------P---H---M master (me)
 
 
      A---B---C topic
     /         \
D---E-----------P---S---H---M' master (you)
      \            /
       F---G-------

I really don't wanna deal with this crap...

$ git fetch you
$ git reset --hard you/master
      A---B---C topic
     /         \
D---E-----------P---S---H---M' master (me)
      \            /
       F---G-------

But, seriously, be careful!

git-cherry-pick

git-tips

$ git commit -v
$ git commit --amend
$ git reflog
$ git cat-file -p HEAD
$ cat ~/.gitconfig
[help]
autocorrect = 1
$ cat ~/.gitconfig
[alias]
  branches = branch -a
  tags = tag -l
  remotes = remote
  sprout = checkout -b
  switch = checkout
  unstash = stash pop
  forget = checkout -f
  remember = checkout -f
  root = rev-parse --show-toplevel
  back = checkout -
  amend = commit --amend
  track = follow
  state = status -s
  rewind = reset --hard HEAD~1
$ cat ~/bin/git-follow
#!/usr/bin/env bash
#
# Follows the current git branch on a remote. If the remote is not
# specified, it is assumed to be called origin.
#
# Usage:
#   git follow [remote]
 
REMOTE=${1:-origin}
BRANCH=$(git symbolic-ref --short HEAD)
 
git branch --set-upstream-to=$REMOTE/$BRANCH $BRANCH
$ hub --version
git version 1.8.2.3
hub version 1.11.1