Advanced Git

92
Advanced Git Sergiu Ioan Ungur

Transcript of Advanced Git

Advanced GitSergiu Ioan Ungur

Overview

Version Control System (VCS)● Merging● Time capsule

Distributed Version Control System (DVCS)● Central repository● Local copy of the repository

Origins

Linus Torvalds (2005)● Linux Kernel project.● Meant to be distributed, fast and more

natural.● Capable of handling large projects.

Contents

1. Merging vs. Rebasing2. Reset, Checkout, and Revert3. Advanced Git log4. Git Hooks5. Refs and Reflog6. Git Aliases7. References

1. Merging vs. Rebasing

$ git rebase● magical Git voodoo● solve the same problem as git merge:

integrate changes from one branch into another branch

Overview

Incorporate the new commits into your feature branch:

● merging● rebasing

Merge option

$ git checkout feature$ git merge master________________________________________$ git merge master feature

Merge option

● Results in a new “merge commit”.

● Merge is “nice” (non-destructive).

● But... it pollutes your feature branch’s history.

Rebase option

$ git checkout feature$ git rebase master

● Results in moving the entire feature branch to begin on the tip of the master branch.

Rebase option

● Rebasing re-writes the project history.

● A much cleaner project history: perfectly linear project history.

Interactive rebasing

● Complete control over the branch’s commit history.

● Clean up a messy history before merging a feature branch into master.

$ git checkout feature$ git rebase -i master

Interactive rebasing

pick 33d5b7a Message for commit #1pick 9480b3d Message for commit #2pick 5c67e61 Message for commit #3

pick 33d5b7a Message for commit #1fixup 9480b3d Message for commit #2pick 5c67e61 Message for commit #3

Interactive rebasing

● Eliminate insignificant commits.

● git merge simply cannot do this.

Golden Rule of Rebasing

Learn when NOT to do rebasing:

Never use it on public branches.

Golden Rule of Rebasing

Before you run git rebase, always ask yourself: Is anyone else looking at this branch?

Force-Pushing

# Be very careful with this command!$ git push --force● Overwrite the remote master branch to

match the rebased one from your repository.

● One of the only times to use force-pushing: local cleanup on a private feature branch.

Local Cleanup

● Make sure each commit in your feature is focused and meaningful.

● Two options for the new base:■ the feature’s parent branch (e.g. master)■ an earlier commit in your feature

● For instance, we need to fix up the last few commits.

Local cleanup

$ git checkout feature$ git rebase -i HEAD~3To re-write the entire feature, use:$ git merge-base feature master

Incorporate upstream

Let assume that you want to fetch the John’s changes in to your feature branch.

Incorporate upstream

Resolve the fork using merge:$ git checkout feature$ git merge john/feature

Incorporate upstream

Resolve the fork using rebase:$ git checkout feature$ git rebase john/feature

Integrate a feature

After a feature has been approved by your team:

● rebase the feature onto the tip of the master

● then, use git merge to integrate the feature into the main code base

Integrate feature

Integrate feature

Integrate feature

Summary

$ git rebase● clean, linear history free of unnecessary

merge commits$ git merge

● preserve the complete history● avoid the risk of re-writing public

commits

2. Reset, Checkout, Revert

git reset, git checkout, and git revert● some of the most useful tools in your Git

toolbox● all let you undo some kind of changes● the first two can be used to manipulate

either commits or individual files

Reset, Checkout, Revert

Commit-level Operations

● The parameters you pass to git reset and git checkout determine their scope.

● When you don’t include a file path as a parameter, they operate on whole commits.

● Note: git revert has no file-level counterpart.

Reset

● Move the tip of a branch to a different commit.

● Usage: e.g. remove commits from the current branch.

$ git checkout hotfix$ git reset HEAD~2

Reset

Oh crap, what am I doing? I should start over.

Reset

Reset

Flags:● --soft - staged snapshot, working

directory.● --mixed - staged snapshot, working

directory. Default option.● --hard - staged snapshot, working

directory.

Reset scope

Checkout

● Switch between branches:$ git checkout hotfix

● Internally, it moves HEAD to a different branch and update the working directory to match.

Checkout

Checkout

Checkout

$ git checkout HEAD~2=> detached HEAD state

Revert

● Undo a commit by creating a new commit.● Safe way to undo changes.

$ git checkout hotfix$ git revert HEAD~2

Revert

Revert

Revert vs. Reset

$ git revert● undo committed changes

$ git reset HEAD● undo uncommitted changes

File-level Operations

git reset and git checkout● accept an optional file path as a

parameter● this dramatically alters their behaviour● limit their operations to a single file

Reset

● Update the staged snapshot to match the version from the specified commit.

$ git reset HEAD~2 foo.py● Fetch the version of foo.py in the 2nd-to-

last commit and stage it for the next commit.

Reset

Reset

Notes:● --soft, --mixed, and --hard flags do not

have any effect on the file-level version of git reset

● staged snapshot is always updated● working directory is never updated

Checkout

● Similar to using git reset with a file path, except it updates the working directory instead of the stage.

$ git checkout HEAD~2 foo.py● Make foo.py in the working directory

match the one from the 2nd-to-last commit.

Checkout

Summary

Command Scope Common use cases

git reset Commit-level Discard commits in a private branch or throw away uncommited changes.

git reset File-level Unstage a file

git checkout Commit-level Switch between branches or inspect old snapshots

git checkout File-level Discard changes in the working directory

git revert Commit-level Undo commits in a public branch

git revert File-level N/A

3. Advanced Git log

1. Formatting how each commit is displayed.2. Filtering which commits are included in the

output.

=> go back into your project and find any information that you could possibly need

Formatting Log Output

Oneline$ git log --oneline

0e25143 Merge branch 'feature'ad8621a Fix a bug in the feature16b36c6 Add a new feature23ad9ad Add the initial code base

Formatting Log Output

Decorating$ git log --oneline --decorate

0e25143 (HEAD, master) Merge branch 'feature'ad8621a (feature) Fix a bug in the feature16b36c6 Add a new feature23ad9ad (tag: v0.9) Add the initial code base

Formatting Log Output

Diffs$ git log --stat

commit f2a238924e89ca1d4947662928218a06d39068c3Author: John <[email protected]>Date: Fri Jun 25 17:30:28 2014 -0500

Add a new feature

hello.py | 105 ++++++++++++++++++++++++----------------- 1 file changed, 67 insertion(+), 38 deletions(-)

Formatting Log Output

Diffs$ git log -p

commit 16b36c697eb2d24302f89aa22d9170dfe609855bAuthor: Mary <[email protected]>Date: Fri Jun 25 17:31:57 2014 -0500

Fix a bug in the feature

diff --git a/hello.py b/hello.pyindex 18ca709..c673b40 100644--- a/hello.py+++ b/hello.py@@ -13,14 +13,14 @@ B-print("Hello, World!")+print("Hello, Git!")

Formatting Log Output

The Shortlog$ git shortlog [-n]

Mary (2): Fix a bug in the feature Fix a serious security hole in our framework

John (3): Add the initial code base Add a new feature Merge branch 'feature'

Formatting Log Output

Graphs$ git log --graph --oneline --decorate

* 0e25143 (HEAD, master) Merge branch 'feature'|\ | * 16b36c6 Fix a bug in the new feature| * 23ad9ad Start a new feature* | ad8621a Fix a critical security issue|/ * 400e4b7 Fix typos in the documentation* 160e224 Add the initial code base

Formatting Log Output

Custom Formatting$ git log --pretty=format:"%cn committed %h on %cd"

John committed 400e4b7 on Fri Jun 24 12:30:04 2014 -0500John committed 89ab2cf on Thu Jun 23 17:09:42 2014 -0500Mary committed 180e223 on Wed Jun 22 17:21:19 2014 -0500John committed f12ca28 on Wed Jun 22 13:50:31 2014 -0500

https://www.kernel.org/pub/software/scm/git/docs/git-log.html#_pretty_formats

Filtering Commit History

● By amount:$ git log -3● By date (--after/--since, --before/--until):$ git log --after="2014-7-1"$ git log --after="yesterday"$ git log --after="2014-7-1" --before="2014-7-4"

Filtering Commit History

● By author (--author, --committer):$ git log --author="John"$ git log --author="John\|Mary"● By message:$ git log --grep="JRA-224:"● By file:$ git log -- foo.py bar.py

Filtering Commit History

● By content (pickaxe):$ git log -S"Hello, World!"● By range:$ git log <since>..<until>$ git log master..feature

Filtering Commit History

Filtering Commit History

● Filtering Merge Commits$ git log --no-merges$ git log --merges

Summary

● Git log gives you the power to pull out exactly what you need from your project history.

4. Git Hooks

Conceptual Overview

Git Hooks● ordinary scripts that Git executes when

certain events occur in the repository● local repository● server-side repository

Conceptual Overview

Installing Hooks● .git/hooks directory

applypatch-msg.sample pre-push.samplecommit-msg.sample pre-rebase.samplepost-update.sample prepare-commit-msg.samplepre-applypatch.sample update.samplepre-commit.sample

Conceptual Overview

Simple prepare-commit-msg hook:● Remove the .sample extension.● Add

#!/bin/shecho "# Please include a useful commit message!" > $1

● Executechmod +x prepare-commit-msg

Conceptual Overview

Scripting Languages● built-in scripts: shell and PERL● you can use any scripting language you

like as long as it can be run as an executable

● shebang line #!/bin/sh

Conceptual Overview

Local Hooks

The most useful local hooks:● pre-commit● prepare-commit-msg● commit-msg● post-commit● post-checkout● pre-rebase

Server-side Hooks

Server-side hooks:● pre-receive● update● post-receive

Summary

● The hooks let us plug in to the entire development life cycle.

● Perform customizable actions at every stage in the commit creation process, as well as the git push process.

5. Refs and Reflog

Many ways of referring to a commit

Hashes

● The most directly way to reference a commit is via its SHA-1 hash.

$ git show 0c708f● Resolve a branch, tag or another indirect

reference into the corresponding commit hash.

$ git rev-parse master

Refs

● A ref is an indirect way of referring to a commit (alias).

● Refs are stored in .git/refs directory:.git/refs/ heads/ master some-feature remotes/ origin/ master tags/ v0.9

Specifying Refs

● Passing a ref to a Git command:■ full name of the ref■ short name of the ref

$ git show some-feature● Git resolves some-feature to

refs/heads/some-feature$ git show refs/heads/some-feature

Packed refs

● Git garbage collection => compress refs into a single file

● Force the compression:$ git gc

● .git/packed-refs00f54250cf4e549fdfcafe2cf9a2c90bc3800285 refs/heads/feature0e25143693cfe9d5c2e83944bbaf6d3c4505eb17 refs/heads/masterbb883e4c91c870b5fed88fd36696e752fb6cf8e6 refs/tags/v0.9

Special Refs

● HEAD - The currently checked-out commit/branch.

■ HEAD can contain either a symbolic ref or a commit hash.

● FETCH_HEAD - The most recently fetched branch from a remote repo.

● ORIG_HEAD - A backup reference to HEAD before drastic changes to it.

Special Refs

● MERGE_HEAD - The commit(s) that you’re merging into the current branch with git merge.

● CHERRY_PICK_HEAD - The commit that you’re cherry-picking.

Refspecs

● A refspec maps a branch in the local repository to a branch in a remote repository.

● Specified as [+]<src>:<dst>● <src> - source branch● <dst> - destination branch● + - forcing the remote repository to perform

a non-fast-forward update

Refspecs

● Specify the remote branch:$ git push origin master:refs/heads/qa-master

● Remove a remote branch:$ git push origin :some-feature$ git push origin --delete some-feature

Refspecs

● .git/config[remote "origin"] url = https://[email protected]:mary/example-repo.git fetch = +refs/heads/*:refs/remotes/origin/*

[remote "origin"] url = https://[email protected]:mary/example-repo.git fetch = +refs/heads/master:refs/remotes/origin/master

[remote "origin"] url = https://[email protected]:mary/example-repo.git fetch = +refs/heads/master:refs/remotes/origin/master push = refs/heads/master:refs/heads/qa-master

Refspecs

● Refspecs gives you complete control over how various Git commands transfer branches between repositories.

● Rename/delete branches.● Fetch/push to branches with different

names.● Configure git push and git fetch to work

with only the branches that you want.

Relative Refs

● Refer to commits relative to another commit:

$ git show HEAD~2

● ~ - Follow the first parent of a merge commit.

● ^ - Specify the parent you want to follow.$ git show HEAD^2$ git show HEAD^2^1

Relative Refs

Relative Refs

# Only list commits that are parent of the second parent of a merge commit$ git log HEAD^2

# Remove the last 3 commits from the current branch$ git reset HEAD~3

# Interactively rebase the last 3 commits on the current branch$ git rebase -i HEAD~3

The Reflog

● Git’s safety net.● Record almost every change you make in

your repository$ git reflog400e4b7 HEAD@{0}: checkout: moving from master to HEAD~20e25143 HEAD@{1}: commit (amend): Integrate some awesome feature into `master`00f5425 HEAD@{2}: commit (merge): Merge branch ';feature';ad8621a HEAD@{3}: commit: Finish the feature

The Reflog

● HEAD{<n>} - Reference commits stored in the reflog.

● Revert to a state that would otherwise be lost.

ad8621a HEAD@{0}: reset: moving to HEAD~3298eb9f HEAD@{1}: commit: Some other commit messagebbe9012 HEAD@{2}: commit: Continue the feature9cb79fa HEAD@{3}: commit: Start a new feature

The Reflog

● “Oups, I shouldn’t have done that!”● “Don’t worry :) !”

$ git checkout HEAD@{1}

● Note: this puts you in a detached HEAD state.

Summary

● Git reflog - a way to reference commits that are not available through any other means.

● The point of all this was to be able to pick out exactly the commit that you need in any given development scenario.

6. Git Aliases

● https://github.com/ssergiuss/dotaliases