Advanced Git

Slides

https://hs2010-git.github.io/adv/

Git mechanics

A Git repository is just a bunch of objects.

An object is either a commit, a tree, or a blob (file).

Each commit points to a tree, parent commit(s), and has some metadata.

i.e. each commit is a snapshot of files, with some metadata and parent commit(s). That's it.

Git mechanics

Commits form a directed acyclic graph.

  • directed: commits point to their parent(s)
  • acyclic: there cannot be commit cycles
  • graph: commits are nodes, and the parent commit relationships are the edges

Git mechanics

Branches and tags (refs) are just pointers to commits.

The "current branch" is simply whatever is pointed to by the HEAD ref.

Exercise repository

https://github.com/hs2010-git/advgit

Commit and history manipulation

commit --amend

Amends the current commit (HEAD).

Other useful flags with this:
--date, --author, --reset-author

Exercises

  • Amend HEAD to be authored by you on 3 November 2020 at 12:00.
  • Amend HEAD to have an extra file.

rebase -i <base>

Interactive rebase onto base.

p, pick <commit> = use commit
r, reword <commit> = use commit, but edit the commit message
e, edit <commit> = use commit, but stop for amending
s, squash <commit> = use commit, but meld into previous commit
f, fixup <commit> = like "squash", but discard this commit's log message
x, exec <command> = run command (the rest of the line) using shell
b, break = stop here (continue rebase later with 'git rebase --continue')
d, drop <commit> = remove commit
l, label <label> = label current HEAD with a name
t, reset <label> = reset HEAD to a label
m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
.       create a merge commit using the original merge commit's
.       message (or the oneline, if no original merge commit was
.       specified). Use -c <commit> to reword the commit message.

rebase -i <base> Exercises

  • Fix the spelling error in 1dab2c. (There are at least 2 ways of doing so.)
  • Reorder the commits.
  • Drop a commit.

cherry-pick

Pick commits and apply them on top of the current HEAD.

Exercises

  • Cherry-pick e362b5.

Cleaning histories

Sometimes, PRs are created with very messy histories.

Exercise

Clean up the history of this PR.

Patches

Patches

A patch/diff file simply consists of the output of diff, show, etc.

You can send a file to someone else to apply.

apply

Apply a patch.

Exercise: Apply this patch:

diff --git a/hello.c b/hello.c
index 896abe6..d8f149b 100644
--- a/hello.c
+++ b/hello.c
@@ -2,7 +2,7 @@

 int main(int argc, char *argv[]) {
     if (argc > 1) {
-        printf("Hello %s!\n", argv[1]);
+        printf("Hello %s! You said %d more things.\n", argv[1], argc - 2);
     } else {
         printf("Hello uncertain worl\n");
     }

format-patch <since / range>

Generate patches for multiple commits.

This is how one formats patches for the Linux kernel!

am

"Apply mail". This is how Linux kernel maintainers apply patches received on the mailing lists.

Exercise

Apply the two patches in the repository.

Patches on GitHub

You can get patches from a GitHub commit by just adding .patch to the URL.

Bisect

bisect

Binary search for a commit. Usually used to find the commit in which something broke.

Exercises

Bisect the bisect branch. Find the first commit that has "BROKEN" in file.

Now bisect it automatically using bisect run.

reflog

reflog

View a ref's log (i.e. the commits it has pointed to in the past).

Exercises

Do some destructive operation e.g. commit --amend. Use reflog to restore your original commit.

Rewriting a repository

filter-repo

Rewrite a repository.

Exercises

Use filter-repo to remove secret from the repository entirely.

Submodules

submodule

Include a repository within your current directory.

Exercises

Add a submodule. Use any repository, or this if you can't think of any.

Make the submodule refer to a different commit.

Multiple worktrees

worktree

Have multiple branches checked out at a time.

Exercises

Check out the branch branch as a separate worktree.

The .git directory

.git layout

  • HEAD: points to the active ref
  • index: the repository index
  • config: repository-specific configuration
  • objects, refs, logs: as per the name

More information: gitrepository-layout(5)

gc

Optimise the repository and prune unused objects.

Exercises

Add and commit a new file. Then (pretend it's an accident) reset the commit, expire the reflog, and gc to prune the objects. Use cat-file to verify the presence of the object.

Making a commit "by hand"

  • update-index --add ...
  • write-tree
  • commit-tree

More information.

Exercise: do the above

End

Feedback
https://bit.ly/hs2010-advgit-fb

Slides
https://hs2010-git.github.io/adv/