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)

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
    
    # Rewrite your master branch so that any commits of yours that
    # aren't already in upstream/master are replayed on top of that
    # other branch:
    
    git rebase upstream/master
    

    if I don't want to rewrite history (bc others may have cloned it) I should replace the last command with a merge. However, for making further pull reqeusts that are as clean as possible, it's prob better to rebase.

    after rebasing / merging locally I believe I have to push the changes to the github repo of my fork (origin)
    illustrated guide

    git bisect:

    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

    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.

    git add

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

    git rebase

    Rebase says I want the point at which I branched to move to a new starting point

    a straightforward scenario is: if you started doing some development and then another developer made an unrelated change. You probably want to pull and then rebase to base your changes from the current version from the repository.

    using git rebase instead of merge:

    another shorter animation
    useful animationsto understand rebase.

    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(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.

    workflow example: >make sure master is up to date with remote, checkout to feature branch > rebase feature branch with up to date master > checkout to master and merge feature branch. This will do what is called a fastforward merge, where head pointer in master has to catch up to the feature branch head pointer, this doesn't create a new merge commit.

    git rebase workflow (from another vid)
    pull > checkout into feature branch > rebase master > push to remote > checkout master > pull > rebase feature branch > push to remote
    I think this is no good bc rebases main branch, which is public, and rewrites history.

    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.

    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.

    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