Git Advanced

Agenda

  • Git Commits - Best Practices
  • Git Stash
  • Git Ignore
  • Git Attributes
  • Git Config
  • Git Cherry-pick
  • Git Apply
  • Git Submodules
  • Git Worktree
  • Git Bisect

Git Commits - Best Practices

  • A commit should be a wrapper for related changes
  • Don't commit half-done work into public branches
  • Write good commit messages
    • use the imperative style in the subject line
    • up to 50 characters, provide detailed information if necessary
      • Good commit message: CMA-5430: Add pulsar icon to the user section
      • Bad commit message: Progress
      • Bad commit message: Add tooltip, fix alignment, delete old config
  • Use branches
    • Branching helps you avoid mixing up different lines of development
  • Preserve history and traceability

Git Stash

  • Enables you to save your code without making a commit
  • git stash - stashes all tracked files
  • git stash -- #files - stashes the given files
  • git stash list - displays all stashed changes
  • git stash apply - reapplies the stashed content
  • git stash apply stash@{1} - applies selected stash
  • git stash push -m [message] - creates a stash with a message
  • git stash drop - drops the stashed content
  • git stash pop - apply + drop
  • git stash save - saves the modified file

Git Ignore

  • .gitignore is a file that tracks ignored files
  • Each glob pattern is tested relative to the directory containing the .gitignore file
  • Content:
    • dependency cache (node_modules)
    • compiled code
    • build output directory (bin, build)
    • hidden system files
    • personal files (IDE config, .env file)
  • Example: .gitignore for C++
    1 # Prerequisites
    2 *.d
    3
    4 # Compiled Object files
    5 *.slo
    6 *.lo
    7 *.o
    8 *.obj
    9
    10 # Precompiled Headers
    11 *.gch
    12 *.pch
    13
    14 # Compiled Dynamic libraries
    15 *.so
    16 *.dylib
    17 *.dll
    18
    19 # Compiled Static libraries
    20 *.lai
    21 *.la
    22 *.a
    23 *.lib

Git Attributes

  • Controls a bunch of Git settings, for instance:
    • line endings settings
    • LFS settings
    • binary/text files handling
  • *.{bat, [bB][aA][tT]} text eol=crlf - forces to use CRLF so that if a repo is accessed in Windows, the script will work
  • *.sh text eol=lf - forces bash scripts to always use LF line endings
  • *.blend binary - will treat blend files as binary files
  • *.cs text diff=csharp - will treat cs files as text files and uses csharp module for highlighting

.gitattributes example

1 ###############################################################################
2 # Set default behavior to automatically normalize line endings.
3 ###############################################################################
4 * text=auto
5 ###############################################################################
6 # Set default behavior for command prompt diff.
7 ###############################################################################
8 *.rs text diff=rust
9 ###############################################################################
10 # Set the merge driver for project and solution files
11 ###############################################################################
12 #*.sln merge=binary
13 #*.csproj merge=binary
14 ###############################################################################
15 # diff behavior for common document formats
16 # Don't forget to put the following in .git/config:
17 # [diff "zip"]
18 # textconv = unzip -c -a
19 ###############################################################################
20 *.docx diff=zip

Git Config

  • Contains Git configuration on a global or local project level
  • Can be accessed by using git config [attributes]
  • git config --list - displays both configs
  • git config --global user.name "Dave Dangerous" - sets a global name
  • git config --global user.email "dave@dangerous.com" - sets a global e-mail
  • git config --global core.editor "nano -w"~ - sets nano as the default git editor
  • Example: Local config
    1 [core]
    2 bare = false
    3 [remote "origin"]
    4 url = git@gitlab.com:mojo/dojo.git
    5 fetch = +refs/heads/*:refs/remotes/origin/*
    6 pushurl = git@gitlab.com:mojo/dojo.git
    7 [branch "myfeature"]
    8 remote = origin
    9 merge = refs/heads/myfeature
  • Don't forget to set up your global name and e-mail!

Git Cherry-pick

  • git cherry-pick #commit
  • Takes a commit from any branch and applies it to a different branch
  • Useful when you made a commit to the wrong branch, and you want to apply it quickly to the right one

Cherry-picker

Git Apply

  • Applies a patch of a diff. Used together with git diff > patchfile.patch command

Git Submodules

  • Keep a git repository as a subdirectory of another git repository
  • You can incorporate and track version history of external code
  • Use-cases
    • an external component is changing too fast
    • you have a component you want to track as a vendor dependency
    • you are delegating a piece of the project to a third party
  • Mapping is managed in a .gitmodules file
  • git submodule add [url] - transforms a subdirectory into a submodule
  • Cloning a project with submodules:
    1. git clone /url/to/project
    2. git submodule init
    3. git submodule update

Git Worktree

  • Alternative for git stash
  • Creates a linked copy of your git repository under a separate path
  • You can check out multiple branches at the same time
  • git worktree add ../myfeature - creates a new worktree
  • git worktree list - will display the list of worktrees
  • git worktree remove myfeature - will remove the worktree
  • Workflow
    • Create a worktree
    • Do the task that requires it
    • Commit the work
    • Remove your worktree

Git Bisect

  • Performs a binary search between two given commits
  • Can be used to chase down the commit where a bug first appeared
  • git bisect start - inits the bisect process
  • git bisect good #hash - marks the good commit
  • git bisect bad #hash - marks the bad commit
  • git bisect good - marks the current commit as good
  • git bisect bad - marks the current commit as bad
  • git bisect reset - ends the bisect process
  • git bisect log - shows what has been tested so far
  • git bisect run #script - runs tests along the way
  • git bisect start #bad #good - short-hand

Git Bisect Example

Examples

  • I want to see how the content of myfile.txt looked in the previous commit
1 git show HEAD~:myfile.txt

Examples

  • I want to copy-paste a few files from a different branch into my current branch
1 # Opt 1) for the whole repo
2 git merge otherbranch --no-commit --no-ff -X theirs
3 git reset currentbranch
4
5 # Opt 2)
6 git checkout otherbranch .

Examples

  • I want to see what has changed in a file over time
1 git whatchanged -p myfile.txt

Examples

  • I want to pull a branch that has been rebased and force-pushed on the origin server, without creating a merge request
1 # Opt 1)
2 git fetch
3 git reset origin/master --hard
4
5 # Opt 2)
6 git pull --rebase

Examples

  • I want to squash all commits from B to F into one
1 git reset <commit A>
2 git add .
3 git commit -m "BCDEF"

Summary

  • A commit should be a wrapper for related changes
  • git stash enables to save your code without making a commit
  • .gitignore is a file that tracks ignored files
  • .gitattributes can be used to configure line endings settings
  • Git config contains Git configuration on a global or local project level
  • git cherry-pick takes a commit from any branch and applies it to a different branch
  • git apply applies a patch of a diff
  • Git submodules keep a git repository as a subdirectory of another git repository
  • git worktree creates a linked copy of your git repository under a separate path
  • git bisect performs a binary search between two given commits