Software Engineering II: Git
Philipp Fruck Introduction ██ What is a Version Control System (VCS) ██ Why should we use a VCS / git
• Version Control: Track different versions in history • Track history
of a file, e.g. source code • Collaborate safely
• Version Control System (VCS): Software tool that • Experiment without fear
handles version control • Recover from mistakes
• Git is not the first and not the last VCS • git: Industry standard
◦ There have been e.g. Mercurial (distributed) and ◦ Used by open source & enterprises
Subversion (centralized) ◦ Mandatory skill for developers
◦ Jujutsu is a modern, git-compatible VCS ▍ View Linus Torvalds on git: https://www.youtube.com/watch?v=4XpnKHJAok8
▍ Transcript: https://git.wiki.kernel.org/index.php/LinusTalk200705Transcript
Software Engineering II: Git 2 / 28
Command Overview Command │ Description ────────────┼────────────────────────────────────────────────────────────── git init │ Initializes the repository
git branch │ Modifies (-m) or deletes (-d/-D) a branch
git remote │ Set a remote url, e.g. GitHub, GitLab, etc
git add │ Add file contents to the index ("staging area")
git commit │ Create new commit from index ("staging area")
git push │ Push changes to remote repository
git pull │ Pull changes from remote repository
git fetch │ Fetch updates from remote repository without applying changes
git status │ Show "state" of the repo (changes files, current branch, ...)
git diff │ Show the current diff (use --cached to compare index)
git restore │ Restore a given diff (use --staged to restore index)
git reset │ Perform a reset to a given state
Something went wrong? oshitgit.com (https://ohshitgit.com/)
Software Engineering II: Git 3 / 28
Index ██ Description • Git utilizes an index, also called the staging area • Buffer between the working directory and the repository history ◦ Select which changes go into the next commit ◦ Commit changes incrementally ◦ Temporary snapshot • Files are added to the index using git add and restored using git restore --staged
██ Gitignore • To avoid files being added to the index, add them to .gitignore
◦ Do this for e.g. local dependencies, config (secrets), ... • Use /foo for a top-level file
• Use foo to ignore all foo files anywhere in the repo
• .gitignore files can be located in every subfolder of the repo
Software Engineering II: Git 4 / 28
Stash ██ Description Git allows getting rid of changes while saving them for later • git stash saves local changes away
◦ Your working directory is clean again ◦ Changes are added to an internal stack • You can show stashed changes using git stash list
• Get back stashed changes using git stash pop or git stash apply
Software Engineering II: Git 5 / 28
Commit ██ Description ██ Example
A commit is a snapshot of the project![]()
• Records file changes ◦ Represented as diff ◦ Stores full file contents • Identified by a hash • Contains metadata: ◦ Author name and email ◦ Commit date and time ◦ Commit message describing the changes • Linked to parent commit ◦ Forms a Directed Acyclic Graph (DAG) ⚠️ Once in git, always in git. Only because you override a commit does not mean its content will disappear. Once pushed to a remote, the commit will remain there even if not referenced by an active branch. Software Engineering II: Git 6 / 28
HEAD ██ Description ██ Example
HEAD is a symbolic reference![]()
• Pointer to the current commit "you’re on" • Moves when you commit • Usually points to a branch (uses the latest branch commit) ◦ Can also point to commits directly (detached HEAD) Software Engineering II: Git 7 / 28
Branch ██ Description ██ Example
A branch is a movable pointer (label/name) to a commit![]()
• Represents a line of development • Moves forward automatically as you make new commits • Separates features ◦ Encourages experimentation Software Engineering II: Git 8 / 28
Multiple Branches ██ Description ██ Example
Parallel development without interference![]()
• Create as many branches as you want • Work on multiple features simultaneously • Build on features from colleagues without interfering Question: How do we reunite? Software Engineering II: Git 9 / 28
Merging ██ Description ▓▓▓ Before merge
Merging combines multiple branches![]()
• Preserves history (no commits are lost) ◦ Ordered by original timestamp • Creates a merge commit ◦ Special commit with 2 or more parents ◦ Non-linear history ▪ Use git log --graph [--oneline] to show
▪ Easy to use, but suboptimal —————————————————————————————————————————————————————————— ▓▓▓ After merge Software Engineering II: Git 10 / 28
Fast-Forward Merge ██ Description ▓▓▓ Before merge
Occurs when no divergence exists![]()
• No merge commit • Just moves the branch pointer ◦ Linear history remains —————————————————————————————————————————————————————————— ▓▓▓ After merge Note: No merge commit after D
Software Engineering II: Git 11 / 28
Merge Conflicts ██ Description ██ Example
A merge conflict happens when Git is unsure![]()
• Same lines changed differently • Requires manual resolution # git show B # git show C <<<<<<< HEAD
--- a/commit --- a/commit C
+++ b/commit +++ b/commit ||||||| 5f1bca4
@@ -1 +1 @@ @@ -1 +1 @@ A
-A -A =======
+B +C B
>>>>>>> feat
Software Engineering II: Git 12 / 28
Resolving Conflicts ██ What happens ██ Example
• Git stops the merge![]()
• You edit conflicted files • Mark resolved (git add)
• Commit the result ◦ Becomes the merge commit Software Engineering II: Git 13 / 28
Rebase ██ Description ██ Example
Rebasing moves commits to a new base![]()
• Can be from branch to another • Or just updating the base branch • Produces a linear history ◦ Keeps same logical order • Rewrites hashes for new commits • Replays commits one-by-one ◦ Potentially multiple conflicts ◦ Solve them like a merge conflict ◦ Then git rebase --continue
• Hint: git config rerere.enable true
◦ reuse recorded resolution ——————————————————————————————————————————————————————————
◦ Solve repeating conflicts automatically Software Engineering II: Git 14 / 28
Rebase ██ Why? • Cleaner history • Easier to understand • No unnecessary merge commits ▓▓▓ Recommendations ⚠️ Do not rebase shared branches ⚠️ Use git push --force-with-lease for "careful" forced update
• Only forces an update if remote branch has not changed Software Engineering II: Git 15 / 28
Interactive Rebase ██ Description ▓▓▓ Example:
Rewrite commits interactively • git rebase -i A
◦ A is the last original commit hash
• Reorder commits ◦ Leave C as pick
• Edit messages ◦ Set B to delete or d
• Drop commits • Squash commits ▓▓▓ Before rebase
pick 9124c1b # B
pick 00553b4 # C
# Commands:
# 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
▓▓▓ After rebase # d, drop <commit> = remove commit
# [...]
Software Engineering II: Git 16 / 28
Squashing Commits ██ Description ▓▓▓ Before Squash
Squashing combines commits![]()
• Reduces noise • Creates meaningful history • To squash multiple commits, use an interactive rebase ◦ e.g. git rebase -i HEAD~2 to squash the last two
commits ——————————————————————————————————————————————————————————
◦ Leave the first commit as pick
◦ Set the second to squash ▓▓▓ After Squash
◦ Define the commit message for the squashed commit Software Engineering II: Git 17 / 28
Cherry-Pick ██ Description ██ Example
Cherry-picking applies a single commit![]()
• Useful for hotfixes • Avoids full merges • Relevant for backporting • e.g. git cherry-pick B
Software Engineering II: Git 18 / 28
Remote ██ Explanation ██ Best Practices
A remote is another repository • Use feature branches
• Commit small changes • Often shared • Write clear messages
• Enables collaboration • Avoid force-push (except for rebases)
• Example: origin • Enable branch protection
• Rebase, then squash-merge (personal preference) ██ Pull Requests ██ Example A pull request is a review process
• Discuss changes • Run tests (and more automation) • Merge safely Software Engineering II: Git 19 / 28
Commit Messages • Keep commit messages short and descriptive ◦ No "small fixes" -> What did you fix? • Write a summary on the first line • More details (if necessary) after one blank line • Add co-authors after another blank line docs: short commit summary in present tense
# |<---- Using a Maximum Of 50 Characters ---->|
After one blank line, we can start a more detailled message. If you want
to employ a consistent message style, consider conventional commits:
https://www.conventionalcommits.org/en/v1.0.0/
There is also https://gitmoji.dev, but I don't like it personally
# |<---- Try To Limit Each Line to a Maximum Of 72 Characters ---->|
# Co-authored-by: Author <author@example.com>
Software Engineering II: Git 20 / 28
Versioning ██ Tags ██ Releases
• Tags can be used as an alias to a given commit • There are no "releases" in git
• git tag v1.0.0 marks the current commit as version • Releases are a concept of GitHub, GitLab, etc.
v1.0.0 of the software • Releases are bound to a tag and can contain
◦ Can be used later on to see changes between additional description, release binaries, etc.
v1.1.0 and v1.0.0 ◦ Pipelines can be used to create releases from
◦ Both diff and commit messages -> Changelog tags
• Tags can be pushed to the remote via git push --tags ◦ We will do this in a later lecture
Software Engineering II: Git 21 / 28
Config There are three types of git configs: 1. System: git config --system or /etc/gitconfig
2. Global (user): git config --global or ~/.gitconfig / ~/.config/git/config
3. Local (repo): git config --local or <repo>/.git/config
Example settings: ▓▓▓ User Config ▓▓▓ Convenience Features
[user] [branch]
email = a.b@c.de sort = -committerdate
name = Hacker Man [rerere]
enabled = true
For more convenient diffs, start using delta (https://github.com/dandavison/delta)
Software Engineering II: Git 22 / 28
Signing ██ Impersonation
# GPG example
• In git, you can define your name and email as you [user]
want signingkey = ABCDEF1234567890
◦ No verification by e.g. GitHub etc [commit]
◦ Makes it possible to blame other persons for your gpgsign = true
fault [gpg]
• Solution: Commit signing program = gpg
◦ Cryptographically proves who created a commit
◦ Ensures authenticity and integrity ◦ Supports GPG and SSH keys
◦ GPG has key expiry and trust levels, but SSH is # SSH example
simpler [user]
signingkey = ~/.ssh/id_ed25519.pub
[commit]
gpgsign = true
[gpg]
format = ssh
Software Engineering II: Git 23 / 28
Config (bonus) If you want to share different git configs amongst multiple projects, consider the following config: # Enable per-folder git config
[includeIf "gitdir:~/dev/personal/"]
path = config.personal
[includeIf "gitdir:~/dev/work/"]
path = config.work
[includeIf "gitdir:~/dev/dhbw/"]
path = config.dhbw
Software Engineering II: Git 24 / 28
Git Hooks ██ Description Git also has more advanced configuration options that allow automating tasks • Add files in .git/hooks/ and make them executable
• Different hooks are called at different times ◦ pre-commit: Runs before a commit is created
▪ Use for linting, formatting, ... ▪ Can abort the commit with non-zero exit code ◦ pre-push: Runs before pushing to a remote
▪ Can be used for tests etc. ◦ post-merge / post-checkout: Runs after merging or switching branches
▪ Reinstall dependencies, generates files, update $stuff ██ Tools • Tools like pre-commit (https://pre-commit.com) can be used to run checks before your commit
◦ Once configured, add the hook using pre-commit install
Software Engineering II: Git 25 / 28
Git Submodules vs. Subtrees How to include external Git repositories within your project? ██ Comparison at a Glance Feature │ Git Submodules │ Git Subtrees ───────────┼───────────────────────────────┼──────────────────────────────── Storage │ Pointer to a specific commit │ Entire history merged into repo
Workflow │ git submodule update required │ Standard git push/pull
File Size │ Lightweight (metadata only) │ Heavier (includes full source)
Visibility │ Clearly separated │ Seamlessly integrated
▓▓▓ Visual Workflow Software Engineering II: Git 26 / 28
Secrets ██ How do we handle secrets in git? • Wo don't. ◦ Add local secrets to the gitignore as mentioned in the beginning • But if we have to? ◦ This can happen in GitOps workflows ◦ Use SOPS (Secrets OPerationS) to do so ▪ Supports GPG, age, KMS ▪ Encrypt file for multiple users ▪ With correct config, git can produce a plaintext diff ⚠️ Recall the definition of cryptographically safe. While breaking the encryption takes an unrealistic amount of time, you should consider only using this in private repos and/or rotating such secrets every no and then :) Software Engineering II: Git 27 / 28
Thank you for your attention! Don't forget the feedback Software Engineering II: Git 28 / 28