learning git

Workflows

maneras de estructurar un proyecto con git.
una de las maneras mas comunes es

feature branch workflow:

https://www.youtube.com/watch?v=Lj_jAFwofLs

together with trello, you name a trello card with the same unique ID as the feature branch that works on doing said card.

releases and version naming:
in the case of the video they use an intermediary branch between dev and master called release where they merge the new changes they want for production(master) to it first, to make sure everything works correctly before pushing to prod. And eventually merge release to master.

before merging a feature branch to develop are code reviews and pull requests
critical bug fixes would merge to the latest release commit and then to master. the bug fix would also get merged to develop.

for naming look up semantic versioning. semver.org.
2.0.0
Major breaking changes . Minor changes(new features) . patch (bug fixes)

atomic git commits

commits should be under 150 lines, after that review quality goes down.
commits should be atomic, one change per commit.

so.. I commit atomicaly and before doing a pull request I rebase and squash all the commits into one.

commit without pre-commit hook checks

git commit -m "your commit message" --no-verify

git add

add a change to the staging area
git add -p iteratively review every change and add/edit/negate them

git rebase

useful animationsto understand rebase.
another shorter animation

why it's useful

how it works
rebase replays commits on top of new base.
rewrites history by creating new commits.
merge preserves a branch's history, a rebase doesnt'.

in other words, git rebase looks for the last common commit between the two branches, and from that starting point replays the commits from the branch we are rebasing, THEN adds the current branch commits.

inner workings example explanation (from feature-b):
git rebase master: looks for the last common commit between the two branches > looks for what has changed in feature branch and stashes these changes temporarily > replays the commits from master that aren't in feature branch > unstashes feature-b commits.

Rebasing Locally example
If you need to resolve rebase conflicts, the preferred way to do this is locally, not using the GitHub UI, so that no new commits are introduced.

rebasing is safe on my own local branch
never use rebase on public branches / master.
don't use rebase if I have pushed the changes already and somebody else might have them

undoing commits

all this is recommended to do before pushing to remote. To undo commits on a shared branch consider git revert, which creates a new commit that undoes the changes of the previous commit non destructively.

update branches with main

The workflow for rebasing a branch can be done in multiple ways. If you are unsure of how to achieve this, we recommend the following steps:

  1. git checkout main or the branch to rebase on top of.
  2. git pull Pulls the new content locally
  3. git checkout - The period . allows switching to the previous branch without naming it.
  4. git rebase main Rebase a specific branch on top of master.
  5. git push -f Push changes. --force is needed to rewrite the Git history.

commands

GIT MERGE:

(on master) git merge --squash feature-branch

--squash flag squashes all commits of feature branch  into 1 commit and that gets merges with master.

This command creates a merge(or stages(?)) commit that needs to be committed (and eventually pushed).

git revert

creates a new commit that undoes the changes of the previous commit non destructively.
Consider this command for undoing commits on shared branches.

Git Ammend

a commit -ammend appends the changes you are committing to the last most recent commit, this is useful for cases where you forgot to add some more changes to your last commit.

Cherrypicking

executes specific commits from other branches into current branch

Example: I accidently pushed a commit to master branch that should have been pushed to a feature branch.
I go to feature branch where that commit should have been, cherry-pick the commit from master (with commit hash), and it will execute the same changes on feature branch ,creating a new commit, it doesn't LITERALLY move the commit over.
Then, to cleanup master I can do git reset --hard HEAD~1

git reflog

git reflog stores every movement of the head pointer

example case: you delete with git reset --hard the two last commits on a branch and you realize you shouldn't have done that.
use git reflog to find the hash of the state you want to go back to and then you can use git reset or create a new branch that starts at that previous revision git branch happy-ending commithash123

another use case for reflog is for restoring deleted branches

git submodules

is an integrated way to handle sub libraries.
I believe similar to like npm, maven or cargo

when you clone a repo that uses submodules, you initially pull empty submodule folders that only contain configurations

to download the libraries you have to run git submodule update --init --recursive --init flag for when running for the first time

search and find

git has commands that allow me to find commits by filtering by every parameter: by date, author, commit message, by file, by branch, commit name...
git log --after="2021-7-1" --before="2021-7-5" --grep="refactor" --author="tumai" -- README.md
grep flag for commit message filtering. grep accepts regular expressions
empty -- is to filter by file name, it is necessary to do it this way so git doesn't confuse file names and branch names
git log feature/login..main shows all the changes that are in main branch but not in feature/login.

git bisect

command that helps identify when a commit that introduced a bug was made. you choose commits and have to identify if they have or not have the bug, git does some binary searching to pinpoint where the bug was introduced.

binary search back thro commits to find buggy one

https://training.github.com/downloads/github-git-cheat-sheet/
https://training.github.com/downloads/es_ES/github-git-cheat-sheet/
pdf-Git-Cheatsheet.pdf

Bare repositories

a bare repo is that has no workspace, just the .git folder. it can be used to host a repo for multiple developers to work on instead of a central server like Github.

a bare repo is also needed if I want to checkout multiple branches of the same repo in the same folder using git worktree.

worktrees

enables having multiple branches checked out at one.
it clones the branches as separate dirs inside my worktree dir.

so if im working on 'branch_a' and I need to go work on 'branch_b', instead of stashing all the changes and checking out to another branch I would simply switch directories to one of the added branches I have in my worktree

howto:

clone a repo as a bare repo: `git clone <name_of_my_worktree_dir>
  • add the branches I want to add git worktree add master and so on...
  • git worktree remove <name> if I have commited changes I don't want to commit add the --force flag
  • forking / contributing to open source

  • see if project has contributing guide first.
  • fork repo
  • clone my fork locally
  • keep it updated:
    use github desktop UI or even web UI has a button or there is a github CLI gh that has a command `gh repo sync -b <branch_name> or with git:
    by adding the remote ("remotes" are like nicknames for the URLs of repositories - origin is an example) with `git remote add upstream
    # Add the remote, call it "upstream":
    git remote add upstream https://github.com/whoever/whatever.git
    
    # Fetch all the branches of that remote into remote-tracking branches
    git fetch upstream
    
    # Make sure that you're on your master branch:
    git checkout master
    
    # rebase with master
    git rebase upstream/master
    

    illustrated guide