Skip to content

Instantly share code, notes, and snippets.

@nerdCopter
Last active December 8, 2023 15:12
Show Gist options
  • Save nerdCopter/8b28147511aca110aa4eb25a5fae45e5 to your computer and use it in GitHub Desktop.
Save nerdCopter/8b28147511aca110aa4eb25a5fae45e5 to your computer and use it in GitHub Desktop.
git usage notes
git_notes.txt -- assumes CLI in Linux/OSX or Cygwin or WSL (Windows SubSystem for Linux).
https://git-scm.com/docs/
https://www.atlassian.com/git/tutorials/
---
##################################################
### Recommended Windows vs Linux Compatibility ###
##################################################
# recommended git global environment configs:
# windows:
git config --global core.autocrlf true
# linux/osx:
git config --global core.autocrlf input
# cross-platform:
git config --global core.safecrlf warn
git config --global core.whitespace cr-at-eol
git config --global core.filemode false
git config --global help.autocorrect true
########################
### BASIC REPO STUFF ###
########################
#on CLI, with github 2FA, you will need an ssh-key. create a key one time. you will use it often, or add to scripts if you prefer.
ssh-keygen -b 2048 -t rsa -f ~/.ssh/myGitHubKey -q -N ""
#now tell GITHUB to trust the key:
# go to you https://github.com/settings/keys
# create new key, TITLE it your filename or whatever you like ("myGitHubKey")
# copy the content of ~/.ssh/myGitHubKey.pub into the KEY field
#now when you need to communicate with github via CLI, you need to add the key to your CLI session
#but first, very often in Linux you must first "eval" the local ssh-agent. sometimes, not always; use as needed.
eval "$(ssh-agent)"
#now add you generated key into bash-session, but this will exist only temporarily.
ssh-add ~/.ssh/myGitHubKey
# you can also specify time to stay alive, so -t 21600 is 6 hours:
ssh-add -t 21600 ~/.ssh/myGitHubKey
## git status -- use this constantly and consistently if you are CLI. my CLI prompt automatically runs it for me.
git status -uno -sb
# so you want it in your CLI prompt too? add these lines verbatim the the end of your ~/.bashrc
function gitstatus() {
if [[ -e .git ]] ; then
git status -uno -sb
fi
}
PROMPT_COMMAND=gitstatus
#fork a repo on github.com UI (example here EmuFlight)
#now clone it to your local PC
git clone https://github.com/myUSERNAME/EmuFlight.git
cd ~/EmuFlight
## on github prefer `email privacy enabled` -- set/get your private/public email from https://github.com/settings/emails
git config user.email "56356767+myUSERNAME@users.noreply.github.com"
git config user.name myUSERNAME
git remote set-url origin git@github.com:myUSERNAME/EmuFlight #change to ssh for CLI pushing
git remote add upstream https://github.com/emuflight/EmuFlight.git #can use url because will not push
git remote set-url --push upstream disabled
git remote -v
#you do want to keep your repo in sync as often as possible:
#sync personal(origin) repo from official(upstream) repo:
git fetch --all
git checkout master
git pull upstream master
git push origin master
#######################
### BASIC GIT STUFF ###
########################
#note: in most cases of `git` you can add `--dry-run` to see what would happen, but not actually do it.
#always branch from master (after you're synced)
git checkout master
git checkout -b myBranch
# you can git add specific file or all:
# git add src/main/io/osd.c #add a single file
# git add -u #add all modded files
#of course you need to commit your additions
git commit -m "title" -m "description"
# push to your repo after your are complelty satisfied. see below for squashing multiple commit to one
git push #it will show you what to type if you need to create branch server side
#show the recent commits with short commit SHA
git log --oneline --decorate=no | head -n 15 #just show 15 of the most recent, skip the "|head" part if you want all
git log --oneline --decorate=no 0.3.4..master # useful for seeing what commits you've added since TAG
git log --date=short --pretty=format:"%h%x09%an%x09%ad%x09%s" | head -n 30 #git log simple but more info
#fix last commit comment
git commit --amend -m "new fixed comment" -m "new fixed description"
#commit without mods i.e. trigger a build
git commit --allow-empty -m "Trigger build"
#squash all your WIP commits into one and force push a clean branch
git reset --soft <FirstSHAbeforeYourEdits>
git add -u
git commit -m "your clean message" -m "your clean description"
git push --force #overwrite the branch with clean squashed commit.
#delete branch
git branch -d branch_name #alias for --delete
git branch -D branch_name #alias for --delete --force
git push -d <remote_name> <branch_name> #--delete local AND remote #e.g. git push -d origin myBranch
#git reset single files to prior versions
git checkout HEAD -- my-file.txt
git checkout HEAD^ -- my-file.txt
git checkout HEAD~2 -- my-file.txt
git checkout master -- my-file.txt
####################
### HOUSEKEEPING ###
####################
#list untracked files
git ls-files . --exclude-standard --others
# clear untracked file
# use with caution?
git clean -df #delete force
#Cleanup unnecessary files and optimize the local repository
git gc [--aggressive] [--auto] [--quiet] [--prune=<date> | --no-prune] [--force] [--keep-largest-pack]
# deletes local references to non-existing branches on all remotes.
git fetch --prune --progress #same as all of: git remote prune [origin|upstream|etc]
# cleanup/housekeeping of local clone
git gc --prune --aggressive
# cleanup un-referenced
git prune --progress
# delete local [merged|unmerged] branches not on remote [origin]
# just view:
git branch -r | awk '{print $1}' | egrep -v -f /dev/fd/0 <(git branch -vv | grep origin) | awk '{print $1}'
#when comfortable to delete, pipe the same command to to delete
#| xargs git branch -d #for unmerged, use -D
#replace origin with upstream as well
#############################
### INTERMEDIATE GIT STUFF ###
#############################
#basic diff examples:
git diff #implies HEAD
git diff --name-only
git diff HEAD^ #head minus 1
git diff HEAD~3 #arbitrary number of commit histories
git diff HEAD~6 src/js/tabs/led_strip.js
git diff <commitSHA>
git diff master myBranch
git diff <commitSHA> <commitSHA>
git diff HEAD^ > ../path/to/DiffFile.diff #pipe diff to a file for later use
#diff folders/files examples:
git diff HEAD -- src/js/tabs/osd.js
git diff HEAD^ -- src/js/tabs/pid_tuning.js
git diff myBranch:locales/ HEAD:locales/
git diff myBranch:src/tabs/pid_tuning.html master:src/tabs/pid_tuning.html
# diff exclude folder example
git diff master..HEAD -- . ':!src/main/target'
#applying diff-file examples
#it a good idea to review the `--check --stat` before the actual `--apply`
git apply --stat --check ../path/to/DiffFile.diff #just check, no apply
git apply --stat --check --recount ../path/to/DiffFile.diff #same but recount matching lines in-case of differing(modded) HEAD
git apply --stat --check --recount --exclude=src/main/flight/pid.c ../path/to/DiffFile.diff #same , but exclude a file
git apply --apply --stat --check --recount ../path/to/DiffFile.diff #apply, but dont commit, allows for manual git add
git apply --apply --verbose --stat --check --recount -C 5 --exclude=src/main/flight/pid.c ../path/to/DiffFile.diff #apply but try to match more lines for safety
#force reset personal fork master to match upstream master
git remote add upstream /url/to/original/repo ## (e.g. https://github.com/emuflight/EmuFlight.git)
git remote set-url --push upstream disabled
git remote update #update status of remotes
git checkout master #switch to your master
git reset --hard upstream/master #get upstream master
git push origin master --force #push/overwrite your master
#add upstream official repo to personal fork
git remote add upstream https://github.com/emuflight/EmuFlight.git
git remote set-url --push upstream disabled
git remote -v
## use stuff like this to block pushing
git remote set-url --push upstream disabled #if using my own repo w/ official upstream
git remote set-url --push origin disabled #if cloned official emu
#re-enable upstream pushing, be extremely careful, prereq=ssh/key
## if FORKed repo
# git remote set-url --push upstream git@github.com:emuflight/EmuConfigurator
# git remote set-url --push upstream git@github.com:emuflight/EmuFlight
## if CLONE (official) repo
# git remote set-url --push origin git@github.com:emuflight/EmuConfigurator
# git remote set-url --push origin git@github.com:emuflight/EmuFlight
## good idea to disable afterward for protection
## example of enabling & pushing branch upstream and disabling:
### git checkout -b newBranch
### git remote set-url --push upstream git@github.com:emuflight/EmuConfigurator
### git push upstream
### git remote set-url --push upstream disabled
#add a 3rd-party fork to your local repo
git remote add somebody_fork <url of fork>
git remote -v #show remote status before disabling push
git remote set-url --push somebody_fork disabled
git remote -v #show remote status after disabling push
git fetch somebody_fork
git checkout --track somebody_fork/branch_name
# pull someone else's pull-request (PR)
# git checkout -b NewBranch master
# git pull git://github.com/USERNAME/EmuFlight.git PRBRANCH
git checkout -b Kaiowarez-crsf-lq master
git pull git://github.com/Kaiowarez/EmuFlight.git crsf-lq
git checkout -b 20201120_build_tylercorleone_mixer_smoothing master
git pull git://github.com/tylercorleone/EmuFlight.git mixer_smoothing
#braching or cherry-picking somebody_fork examples
git checkout -b my_test_branch somebody_fork/<branch>
git checkout master ; git checkout -b myNewBranch ; git cherry-pick --no-commit somebody_fork/someAtomicBranch #...
#git cherry-pick works often, but sometimes not and needs mods.
#so retain authorship with commits:
git commit --amend --author="Pawel Spychalski <pawel.spychalski@raisin.com>" --no-edit
git commit --author="Quick-Flash <46289813+Quick-Flash@users.noreply.github.com>" -m "all the flight stuffs" -m "QF the prodigious"
git commit --author="Kaiowarez <60309480+Kaiowarez@users.noreply.github.com>" -m "Kaio fixing the targets"
git commit --author="Tom Hensel <80815+gretel@users.noreply.github.com>" -m "thanks Tom"
git commit --author="loutwice <loutwice@gmail.com>" -m "Loutwice patience keeping us sane"
git commit --author="Robert Marinus <bubi-007@hispeed.ch>" -m "technical filtering stuff"
git commit --author="nerdCopter <56646290+nerdCopter@users.noreply.github.com>" -m "backported code from XYX"
git commit --author="Andrey Semjonov <50518855+AndreySemjonov@users.noreply.github.com>" -m "fixing iTerm like King Kraken"
git commit --author="BeauBrewski <85623381+BeauBrewski@users.noreply.github.com>" -m "TargetMaster3001" -m "Co-authored-by: nerdCopter <56646290+nerdCopter@users.noreply.github.com>"
git commit -m "commit message" -m "Co-authored-by: another-name <another-name@example.com>"
git commit -m "commit message" -m "Co-authored-by: Andrey Semjonov <50518855+AndreySemjonov@users.noreply.github.com>"
git commit -m "commit message" -m "Co-authored-by: Kaiowarez <60309480+Kaiowarez@users.noreply.github.com>"
git commit -m "commit message" -m "Co-authored-by: BeauBrewski <85623381+BeauBrewski@users.noreply.github.com>"
git commit -m "commit message" -m "Co-authored-by: nerdCopter <56646290+nerdCopter@users.noreply.github.com>"
# How to use two masters from separate remotes:
# Given repo `alpha` and repo `beta`, and assuming local repo is clone of `alpha`:
git checkout master
git remote add beta https://gitlab.com/someAccount/someRepo
git fetch --all
git checkout -b beta_master beta/master
# There you have beta's remote master stored locally as `beta_master`.
# From now on, you may:
git fetch --all
git checkout beta_master
git pull beta master
# Of course you may use your own naming conventions. (e.g replace `beta` with `gitlab`.)
##########################
### REPAIRING PROBLEMS ###
##########################
#find conflict sections
grep -Iirn -P "[>=<][>=<][>=<][>=<][>=<][>=<][>=<]" src/
#git authentication problems fixes
#assuming CLI with SSH keys being used. set to ssh, not url
# when using 2FA and CLI, ssh and an ssh-key is required. once you have a key, you can add it in your shell session:
eval "$(ssh-agent -s)" #shell/cli usually works without eval, but needed at least when you ssh from another machine, or the agent memory is lost
ssh-add ~/.ssh/myGitHubkey #always add you key to your session
# Now you can set your repo/upstream/forks to ssh
git remote set-url origin git@github.com:USERNAME/FORKNAME #set your origin(personal fork) for ssh
# git remote set-url upstream git@github.com:emuflight/EmuFlight #set upstream(official repo) for ssh
# git remote set-url FORKNAME git@github.com:USERNAME/FORKNAME #set some remote for ssh
#fix failing to find/pull branches
git config --get remote.origin.fetch ## may show botched: +refs/heads/master:refs/remotes/origin/master
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*" #this is the fix
git config --get remote.origin.fetch ## will show fixed: +refs/heads/*:refs/remotes/origin/*
git remote update #now update
# -or-
git fetch --all
#now pull
git pull BRANCH
# -or-
git pull --all
# when it's really broke, and you want to reset to upstream/origin's branch of choice [master]
git fetch origin master
git reset --hard FETCH_HEAD
git clean -df #-x if you want folders too, but you will have to rebuild. e.g. ./downloads/* ./obj/* ./tools/*
# reopen closed PR after a force push
# https://gist.github.com/robertpainsi/2c42c15f1ce6dab03a0675348edd4e2c
############
### TAGS ###
############
git tag tagName #create tag at current commit
git tag --delete tagName #delete local tag
git push --delete [origin|upstream] tagName #delete local
## horrible idea (don't do it), but... push all tags:
## git push --tags
#########################################################
### EmuFlight Specific Build System
### as per https://github.com/emuflight/EmuFlight/pull/552
#########################################################
git checkout [master|branch|commit]
git tag buildTag
git push [upstream|origin] buildTag
git tag --delete buildTag
git push --delete [upstream|origin] buildTag
```
GitHub Actions for Draft-Releases to dev-unstable and dev-master, or Release to Official Repo.
* All tags build to GH-Actions artifacts.
* Tag names containing substring `releas` will draft-release to emuflight repo.
* Tag names containing substring `unstab` or `test` will draft-release to dev-unstable repo.
* Tag names containing substring `master` will draft-release to dev-master repo.
* tag could potentially contain all of the above substrings for draft-release to multiple repos.
* Removes defunct JFrog BinTray uploading.
* Tags will build (building now requires tagging). Should delete tag afterward.
* Forks can use tags as well for personal repo gh-actions artifacts.
* tagname examples: that will draft-release to target repos: forTesting, releaseThis, stableMaster, ReleaseMasterAndUnstable
* How to:
git checkout [master|branch|commit]
git tag buildMe
git push [origin|upstream] buildMe
git tag --delete buildMe #delete local tag
git push --delete [origin|upstream] buildMe #delete remote tag
```
#############
### STYLE ###
#############
# recommended code format restyling
sudo apt install astyle
astyle --style=attach --indent=spaces=4 --pad-oper --convert-tabs --preserve-date --suffix=none --mode=c --delete-empty-lines --recursive ./src/*.c
astyle --style=attach --indent=spaces=4 --pad-oper --convert-tabs --preserve-date --suffix=none --mode=c --delete-empty-lines --recursive ./src/*.h
###############
### CREDITS ###
###############
#many ways to do these things
git shortlog --email --summary --numbered
git log --pretty=format:'%an' | sort -f | uniq -i
git log --all --pretty=format:'%an' | sort -f | uniq -i
git log --pretty=format:'%h - %an <%ae>, %ar : %s' 313a9d5...HEAD
git log --pretty=format:'%an <%ae>' 313a9d5...HEAD | sort | uniq
git log --all --pretty=format:'%an' c28ca22f955...HEAD | sort -f | uniq -i
# co-auth credits:
git log --follow --pretty=format:'Co-authored-by: %an <%ae>' -- src/main/drivers/accgyro/accgyro_spi_icm426xx.c | sort | uniq ## credits per file
############
### TIPS ###
############
#DzikuVx: 1 - for new stuff always create a new branch from current master and just code and commit into it
#DzikuVx: 2 - if you want to do something else, checkout master, pull and create a new branch
#DzikuVx: 3 - when you feel that your feature branch is somehow outdated and it needs a refresh: checkout it, do a fetch of origin (or upstream) and finally just git merge master
#DzikuVx: as a result you land in exactly the same state as if you merged your feature to master and started all over or applied some diff above master
#DzikuVx: http://paul.stadig.name/2010/12/thou-shalt-not-lie-git-rebase-ammend.html
#DzikuVx: https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow
############
### MISC ###
############
Stargazers: https://github.com/ACCOUNT/REPO/watchers
@nerdCopter
Copy link
Author

nerdCopter commented Dec 18, 2020

Automatically show git status in directory of repo (but limit the results -- see aliases below):
~/.bashrc contains:

function gitstatus() {
  if [[ -e .git ]] ; then
    git status -uno -sb | head -n 15
  fi
}
PROMPT_COMMAND=gitstatus

@nerdCopter
Copy link
Author

nerdCopter commented Dec 18, 2020

useful aliases:

alias gl='git log --oneline --decorate=no | head -n 15'
alias gs='git status -uno -sb | less'
alias contains='git branch -r --contains'       #usage: contains SHA

in ~/.bashrc

@nerdCopter
Copy link
Author

nerdCopter commented Dec 18, 2020

Delete local and origin branch:
~/.bashrc contains:

function branchdelete() {
  if [ -z "$1" ] ; then
    echo "no branch specified."
    echo "permanently deletes specified local branch and origin/branch"
  else
    git branch -D "$1"
    git push --delete origin "$1"
  fi
}

@nerdCopter
Copy link
Author

nerdCopter commented Dec 18, 2020

EmuFlight Specific Build System

as per emuflight/EmuFlight#279 , we generally build/compile/draft-release like this:

git checkout [BRANCH]
git tag someDescriptiveTagName
git push [upstream|origin] someDescriptiveTagName
git tag --delete someDescriptiveTagName
git push --delete [upstream|origin] someDescriptiveTagName

Therefore, another useful function for your CLI shell (~/.bashrc) is:

function tagbuild() {
  if [ -z "$2" ] ; then
    echo "usage: tagbuild someDescriptiveTagName [origin|upstream]"
  else
    ## EmuFlight Specific Build System
    # as per https://github.com/emuflight/EmuFlight/pull/279
    git tag "${1}"
    git push "${2}" "${1}"
    git tag --delete "${1}"
    git push --delete "${2}" "${1}"
  fi
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment