Project Versioning
with Git

Why?

  • Create versions (or derivates)
  • Log features, fixes, and chores (better than comments)
  • Check progress
  • Rollback if needed
  • Recover content
  • Collaborate
  • the "CI" thing
  • Experimentation

The basics

  • Commits
    • Staged changes
  • Branches
  • Repositories
  • Remotes
  • Tags

The basic
commands

  • Commit
  • Switch
    • Switch -c
  • Restore
  • Fetch
  • Init, branch

VERY IMPORTANT

  • Branch history is made of commits
  • Commits have a parent (like a "tree")
  • branches and tags are POINTERS to their latest commit

Those new git commands

git switch <branch>
# same as git checkout <branch>

git restore
# git reset 
# ex: git restore .
# ex.: git restore --staged <file-path>
# ex.: git restore --source <some-commit-hash> <file-path>

The Core
scenarios

  • Clone repository
  • Create new local branch (from remote or local)
  • Commit changes
  • Push changes
    • Rebase?
  • Merge/Pull request

Logs that give you an overall scope of current events

git log <branch> --graph
git log <branch> --oneline

Rebase to sync your local branches with their target (usually 'dev')

git rebase <remote-branch>
# ex.: git rebase origin/develop

Not going well?
git rebase --abort

Find default remote branch

git remote show <remote_name>
# ex.: git remote show origin
# check HEAD branch field

and what's being tracked

Only the name of the default branch?

git remote show <remote_name> | grep 'HEAD branch' | cut -d' ' -f5

The (less) Core
scenarios

Undo/recover/move changes

  • Restore files
  • Revert commits
  • Check out a file (maybe from a dangling commits in Reflog)?
  • Cherry-pick a commit?

Change state without losing what you have

  • WIP commit?
  • Stash?
  • Worktree?

Diagnose bugs

  • Bisect?
  • Log a file?
  • Blame?  

Context Change

git commit -a -m "WIP"

git stash --all

git worktree add -b <BRANCH_NAME> <FOLDER> <TARGET_BRANCH>
  • WIP commit — store stuff in your branch, then reset the commit when coming back
  • Git stash — store your files for a while (but don't forget about it!
  • Git worktree — creates literally a new context (with its own folder)

Pick a commit from somewhere else

git cherry-pick <some-commit-or-a-pointer-to-a-commit>
  • creates a NEW commit (with same changes) to adapt changes to the current branch
  • referring to a branch or tag picks the LATEST commit
    • remember: branches and tags are POINTERS to their latest commit

Get file from another commit (or branch, or tag...)

git checkout <branch_or_tag_or_commit> -- <path_to_file>
  • useful to "recover" files (even deleted ones)
  • can be used with -p for review
  • -- is optional, I think
  • git restore?

Recall what you did

(Ref)Log that

git reflog

# or
git log -g --pretty=oneline

# only actions related to a branch
git reflog <BRANCH>

# e.g.: git reflog refs/remotes/origin/main
  • Reflog is an alias
  • Dangling commits are temporary
    • aprox. 30 days, based on local configuratons)
    • Dangling = "lost" commits, not in a branch

Log since a specific time

git log --since="2 weeks ago"
git log --since="1 month ago"
git log --since="2 years ago"

see https://git-scm.com/docs/git-log

Logs for specific files

git log -- <file-path>

see https://git-scm.com/docs/git-log

A better Git Blame

Git blame detects the commit with the last change in a line (could be indentation, refactoring, etc.)

 

Might not be what you want ​
(to find out where the bug came from) 

Then, search for the intended change:

(in Vim) /something ("Enter" and 'n' or 'N' to navigate)

git log -p -m --follow --stat -- path/to/your/file  

Why?

"Good"  Management practices

  • Clean commits
  • Readable repositories 
  • And (automatic?)
  • Predictable planning

Clean commits — Basics

  • Short Summary, detailed description (if needed)
    • Summary at about 50 characters
    • Hard to summarize? Maybe it does too much!
    • Refer to tasks/issues/explanations? Add to details
  • Readability
    • Explain the feature, not the code!
    • Imperative mood, no full stop at end, capitalize start
  • Labelled Conventions (e.g.: Conventional Commit)
    • Feat, Fix, Chore (important for billing, f.e.)
  • Is complete (and testable)
    • Redundant commits — WIP, incompleted, irrelevant to the project history. Amend commits if necessary
  • Only what's needed (.gitignore helps)

Clean commits — Examples of (???)

https://xkcd.com/1296/

Clean commits — Tips from the pros

Clean commits — Conventional Commits

Webpack

Clean commits — Tooling

Commitlint + Conventional Commits

/** @type {import('@commitlint/types').UserConfig} */
export default {
  extends: ["@commitlint/config-conventional"],
  rules: {
    "type-enum": [
      2, 
      "always",
      // for small-medium projects, I think these are enough!
      ["chore", "feat", "fix"]
    ],
  },
};

// https://commitlint.js.org/guides/getting-started.html
// https://www.npmjs.com/package/@commitlint/config-conventional

commitlint.config.js

git show -s --format=%B <SOME_COMMIT_ID> | npx commitlint

Clean commits — Tooling

Commitizen + Conventional Commits

npx commitizen init cz-conventional-changelog --save-dev --save-exact

// package.json
"scripts": {
  // ou outra coisa
    "commit-with-commitizen": "cz"
}

Readable Repositories

  • Clean, navigable structure (README, wiki?)
  • Easy to collaborate (issues, merge/pull requests)
    • Use templates (Issue, Merge/Pull Requests)
    • Feature? Chore/Maintenance? Fix or Hotfix?
  • Be Clean
    • No unnecessary content (.gitignore helps)
    • Clean up deprecated/old branches
  • Patterned and Tagged releases (ideally with semver)
    • Changelog? Github Releases?
  • Safe structure (protect your main branch, please!)

Read(Me.md)-able Repositories

What should a README have?

  • Get started (ASAP)
  • Links to more details (Project documentation, page in project management tool, contact details)
  • Project stack, standards...
  • Code reviewers?

Read(Me.md)-able Repositories

What should a README (your first contact) have?

  • Get started (setting up, developing, collaborating)
  • Technical info and links to detailed stuff
    • Project documentation (manuals, etc.)
    • Page in project management tool
    • Error reporting (e.g.: entry?)
    • Environments (staging, production), with associated branches
    • Project stack, standards...
    • handles for tech leads or code reviewers? (@<USERNAME>)
  • A clear language, with lists, sections, and code snippets (Github-flavoured markdown)
  • Overall, it depends on the target audience
    • Devs with node.js experience?
    • People not familiar with a Unix terminal?

Read(Me.md)-TEmplates?

  1. Introduction (title, summary, basic features. Should just be a paragraph and a list, at most)

  2. Technical info (contacts and environments)

    • Project manager/owner

    • Code reviewers (e.g.: "Miguel Costa (@painatalman, front-end) environment URLs")

    • Environments (main, development, staging)

    • Project-related URLs (related projects, error tracking, etc.)

  3. Get Started (prerequisites, installation, run project)

    • prerequisites (with versions)

    • steps to install

    • run project

    • start working on a feature

  4. Development Workflow

    • branching model (link to Git and Operations)

    • common scenarios (testing methods, data importing)n

  5. Project Architecture

  6. Testing (test data, testing procedures, etc.)

  7. Release and deployment: procedures deployment and release, with:

    • Deployment automation per environment

    • Post-merge procedure

    •  Tag info

  8. Development Scenarios

  9. FAQ and Support

ONLY include project-specific content. Should mostly be links to detailed docs:

  • Knowledge Base pages
  • Wiki (if it's too large)

Read(Me.md)-Examples?

# Some whatever project

Official website to promote a resort and their services (golf, restaurants, real estate, etc.).

## Technical info

- Code reviewers: @Painatalman (front-end), @SomeOtherDood (back-end)
- Environments:
  - production: <https://www.example.com/>
    - Backoffice: <https://www.example.com/>
    - Error tracking: <https://www.hiyoooo.com/>
  - staging/development: <https://www.example.com/> (username: **username**, password: **password**)
    - Backoffice: <https://www.example.com/>
    - Error tracking: <https://www.example.com/>
- Stack: [Totally-not-MERN stack](...)

## Get started

See [this stack's "Get Started" section](...), noting that:

- The `things_templates` folder goes to `project/project-home`
- To load data via a MySQL dump, run (with the containers running):

   ```bash
   docker-compose exec -T db mysql --host localhost --port 3310 -pqwerty -u root this_db < this_db.sql
   ```

## Workflow

For information on how to work on features and fixes, check respective stack's [Development Workflow](...)

## Development scenarios

See this stack's [Development scenarios](...), with the following additions/exceptions:

### Access backoffice

When accessing a backoffice, be sure to **log in using your e-mail** and not your username.

### Create backoffice user

1. From the project folder, run:

   ```bash
   docker-compose run --rm web python manage.py createsuperuser
   ```

2. add desired credentials when prompted:

   1. set username
   2. set email address - **important** due to custom implementations, **this field is required**, unlike most projects using `django-admin`
   3. set password twice
   4. access the [backoffice](`<http://localhost:8000/admin>`)
   5. set credentials
   6. username field matches email you inserted
   7. password, as the name implies, matches the prompted password

### Update booking e-mails

Booking e-mails use MJML and a custom setup detailed in [Notification Service's Development Scenarios](...)

### Other scenarios

For overall scenarios, check respective stack's ["Development scenarios" section](...)

Read(Me.md)-Examples?

Need more details?

Consider:

  • Wiki pages (supported by GitLab and GitHub)
  • A Knowledge Base (Notion, Confluence, Docusaurus, MKDocs...)

Readable Repositories

Pull Requests — Why?

  • Plan releases by grouping related commits
  • Having a second (or third or...) opinion
  • Summarize the project's progress
  • It's "live coaching" (with Code Reviews)
  • Can be partially automated (tooling)

Readable Repositories

Pull/Merge Requests — Examples

Readable Repositories

Pull/Merge Requests — Templates

<!-- 
TITLE: "Feature/???"
NOTE: Remove empty sections 
-->

## Changed
<!-- Features that impact the app's behaviour or close issues. E.g.:

- improved styles for form fields (closes #123);
- translated copy for subscription page.
-->

## Chores
<!-- Changes that don't impact the app's behaviour. E.g.:

- added environments to README;
- added tests to component.
-->

## How to test
<!-- numbered steps on how to test the new feature. E.g.:

1. log in with username and password...
2. go to page...
-->

## Post-merge
<!-- Additional steps on what to do when merged. E.g.:

1. release to staging/production
1. run migrations in target environment (run "run migrations" in CI), 
2. disable this page via backoffice
3. run "how to test" from !131
-->
<!--
TITLE: Release/Staging, Release/Production, or Release/<git-tag> (e.g.: "Release/v1.1.0")

ITEM FORMAT:
- Related MR link (! with MR number)
- link to the related task, if possible
- group MRs associated with same task (add description, if appropriate). E.g.:
   - !123 ([task](http://www.example.com))
   - !131, !141 (login form updates, see [task](http://www.example.com))

NOTES:
- check "Release" section in README for release info
- check related MR Post-merge sections
- remove empty sections
-->

## Fixed
<!-- for MRs named "Fix/???" not associated with a new feature -->

## Changed
<!-- for MRs named "Feature/???" -->

## Chores or Redundant
<!-- for MRs named "Chore/???", or redundant MRs like hotfixes (already in production) -->

## Post-merge
<!-- Additional steps on what to do when merged. E.g.:

1. release to staging/production
1. run migrations in target environment (run "run migrations" in CI),
2. disable this page via backoffice
3. run "how to test" from !131
-->

.gitlab/merge_request_templates/Release.md

Readable Repositories

Pull/Merge Requests — Templates

Readable Repositories

Issues — Templates

Readable Repositories

Issues & Pull Requests — Code Review

Should you? Yes, if...

 

 

  • There's guidelines
  • It's clear what "assignee" and "reviewer" are
  • There's focus on communication, team building
  • It's about sharing knowledge and live coaching
  • Keeping track of the project by a team (not a single person)
  • The focus is not on errors (we can occasionally detect errors, but that's rare and normally left to testing)

Tips for
Authors

Tips for
Reviewers

  • You ARE your first reviewer
  • Write clearly the issue(s) at hand, don't focus on code
  • Follow a structure/template (if there's one)
  • Solve any conflicts first (ideally rebasing)

 

  • Be clear when you're nitpicking (e.g.: indentation issues)
  • Offer to meet with the author and discuss live
  • Refer to guidelines and best practices (with reference)
  • Propose alternatives, when applicable

Readable Repositories

Release Changes

  • Keep a Changelog and/or create releases
    • Linked to tags and a specific Pull Requests
  • Automatic creation
    • commit-and-tag-version — creates tag, bumps files, updates Changelog with commits set via Conventional Commit (ignores chores and non-releasable units)
    • Release Please — creates Pull Requests for releases automatically, then creates Github Release, updates changelog, bumps files, tags commits (ignores chores and non-releasable units)
    • Semantic Release, Release It, etc. ...

Gitignore

 

  • .DS_Store
  • node_modules
  • bin files
  • cache files
  • compiled assets
    (done in CI)

Ideally, only add "source code" files (subject to trackable changes). 

Predictable Planning

Have a consistent workflow (that allows collaboration without unneeded complexity).

  • GitFlow
  • Github Flow
  • Trunk-based Development
  • Whatever-works-for-you Flow

Not a metro map

Not a Git project

main commits are tagged, can have support branches

  • derived from main
  • merged to main, develop (and release if applicable)

minor release = hotfix

feature: from develop to develop

release branch goes to both master and develop

release/v1.0.1
release/v.0.1.1

feature/hair-color

  • Simplified, faster than GitHub Flow
  • No "develop" branch
  • Everything branches off of main
  • More CI-centered (while GitFlow can have CI, but may run more frequently, be less performant or complex, etc.)
  • See this comparison 

https://www.alexhyett.com/git-flow-github-flow/

  • 1 "main" branch for development
    • No "develop" or "dev", or whatever
  • ONLY create short-lived feature branches in very large projects, and for code-review and automated testing purposes
  • Release branches exist if needed, but can be done from the trunk (tags)
  • Hotfixes (minor releases), are done through cherry-picking the fixes from the trunk
    • Yes, hotfixes should be done in the trunk

Trunk-based Development — Code review

Trunk-based Development — Releases

Git Habits

that made me
more aware of what I'm doing

Status often

git status
  • which branch are you on?
  • what is staged?
    • And unstaged?
    • And not even included?
  • which branch (if any), is this keeping track of?

Fetch often

git fetch --prune
  • first thing you do when starting work on a project
  • remote references might not be updated
  • no pull. We can merge or rebase later

Why not "pull"?

git pull

Delete merged branches often

git branch --merged | grep -v "*"|awk '{print "git branch -d " $1}'|bash

The oh-whoops!
commit

git commit ...
# forgot to add something, or wants to replace commit message
git commit ... --amend
  • "fixes" commits with mistakes
  • actually replaces commit with a new one (if files are involved)
  • won't work if already pushed (unless you force push)

Need to force push? Add a lease!

git push <remote_probably_origin> <branch> --force-with-lease
  • prevent losing changes from other users
  • used to update a remote branch with undesired commits (like WIPs)

Need to force push? Add a lease!

git push <remote_probably_origin> <branch> --force-with-lease
  • prevent losing changes from other users
  • used to update a remote branch with undesired commits (like WIPs)

Not sure what to include? Try -p

git add -p ...
git checkout -p ...
git reset -p ...
git log -p ...
  • review your work
  • add, remove or reset "hunks" (editable parts) of your changes
  • does NOT include untracked files

Reorganize AND Sync your work with remote target branch

git rebase -i <remote_branch>
# example: git rebase -i origin/develop
  • add your local commits to the tip of the remote branch -- it's rebase, after all...
  • reorganize your new commits
  • ideal right before a PR (and after git fetch)

References

  • https://scotch.io/bar-talk/7-lesser-known-git-commands
  • https://www.freecodecamp.org/news/7-git-commands-you-might-not-know/
  • https://git-scm.com/docs/git-log
  • https://theodorusclarence.com/shorts/husky-commitlint-prettier
  • https://alistapart.com/article/the-art-of-the-commit/
  • https://martinheinz.dev/blog/109
  • https://www.youtube.com/watch?v=aolI_Rz0ZqY
  • https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
  • https://registerspill.thorstenball.com/p/how-i-use-git
  • https://blog.codeminer42.com/git-reflogs-a-guide-to-rescuing-your-lost-work/
  • https://www.youtube.com/watch?v=Md44rcw13k4

Git Stories

By Miguel Costa

Git Stories

In this presentation, I'd like to share with you some interesting stuff about system versioning with GIT.

  • 445