GIT - Source Control

git is a very different beast than the other traditional source control system. Instead of having a "code centric" view to create trees and branches, git is more of a "developer centric" paradigm. As such, many actions don't have the same parallel as say SVN, even though some commands seems similar on the surface.

git works as a two stage commit. commands to manipulate the local git database which is the central view of the scm. Additionally, git can sync to a remote server (think github), and this is the repo server where many collaborators "check in" their codes for sharing.

diagram for git workflow
Source: https://github.com/Plateful/plateful-mobile/wiki/Git-Workflow-Diagram"


Downloading open source sw
git clone https://github.com/singularityware/singularity.git	# download the whole sw repo
git tag								# see available tagged releases
git tag -l -n99							# get description of tag as well, first 99 tags
git checkout tags/2.2						# switch to use the named tag release (2.2)


git against local copy of repository
diagram for git workflow within developer's laptop
Source: http://365git.tumblr.com/post/472624933/the-four-buckets-how-git-considers-content

git clone			# create a local copy of a source code tree
git commit -a 			# most basic workflow after edit, most like svn, commit all changes


git commit file1 file2		# check into local copy (but other don't see this change yet)
git commit file1 -m "comment"	# provide check in comment on cli rather than launch editor

git add file			# kinda feel like "add new file to be tracked"
				# but really is adding changes into the git db
git add -p 			# patch-based add (allow committing chunk of code at a time rather than whole file)

git status			# show commit staatus within the local copy of repo only.  
				# if the clone had been some time and master had seen other commits, 
				# it will NOT show up in the status command.  
				# only another git fetch would get these changes.

git status -uno 		# or --untracked-files=no  ##  dont show untracked files
git status -s | grep "^ M "  	# short mode, untracked files prefixed with ??



## think these are still acting on local copy.  in fact, it is likely that 
## git act on local copy, except for few commands to interact with master repo...

git log file1
git log 
git log --oneline         	# compact log, easier to read!
git log --oneline file		# changes pertaining to the specified file only
git log --oneline issue123	# changes pertaining to the specified branch only  (?)
git log --decorate
git log --graph			# 
git log --oneline --graph --decorate	# can alias to "lol" for this oft use combo
git log -p 			# patch: show diff introduced by each change (instead of just commit msg for the log)

git log -p [-1] PATH/FILE	# list last -N COMMITED changes.  Current edit against git repo is NOT shown!
git diff ??			# find how PATH/FILE differ from current state with last commit in git
gitk FILE			# GUI tool to see commits/diff (but not branches?)

git log issue123 ^master	# branch diff, changes in branch issue123 but NOT in master
				# ^ indicate "not in"

git show COMMIT_HASH		# details of the commit

git branch			# list branches.  * indicate the current branch working on.
git branch -r			# list all branches avail in (r)emote server
git branch issue123		# create a branch called "issue123" (eg after a bug#)
git branch --edit-description issue123	# modify a description for the named branch.  it brings up a text editor
git branch --list -v    	# list branches and descriptioins
				# actually, the info is last commit msg, branch desc so far only visible in the editor that comes up when using --edit-descriptiong.  thus, also  using git_branch.rst file... but 
git checkout -b issue123	# create a branch and switch to it at the same time (?)
git push -u origin issue123	# push the local branch "issue123" to origin (github) [can push branch tag up upstream even when there are 0 commits]

git branch -d       issue123		# delete local branch
git branch --delete issue123		# delete local branch FORCEFULLY ie, even if NOT merged or pushed yet
git push origin --delete issue123	# delete remote branch 


git tag -a  v0.5   2128f04 -m "eg of adding a tag at a specific commit point"
git push --tags  origin master

git tag -a         2018_0901_wsl -m "wsl git hopefully not creating cr/lf chaos"  	# create a release 
git push -u origin 2018_0901_wsl							# push the tag to github

git tag				# list all tags
git tag show v0.5 		# show description of the specified tag
git tag show --tags		# long output with tag desc and commit diff

# https://stackoverflow.com/questions/16329776/how-to-keep-a-git-branch-in-sync-with-master
# resync a branch from master (ie master is ahead, have changes that should be incorporated into the branch)
git checkout master		# swich to the master branch (master is trunk branch created by default)
git pull
git checkout issue123		# so sitting on the branch issue123
git merge master		# resync changes done to master into issue123 branch (if master is ahead of issue123)
				

# merge changes done in a branch into master (ie issue123 is ahead of master and ready to "upload/publish")
# could use web gui in github, which is considered a Pull Request.
# or:
git checkout master		# so sitting on master branch
git merge issue123		# retrieve changes in issue123 branchand merge into current (since sitting on master)


git checkout filename.txt #  retrieve filename.txt from repo, discarding local changes (for uncommited changes?)


git mergetool			# launch visual diff tool

git init 			# create a git repo based on content of the current dir (and sub dirs)

git remote add     repoName url	# set a repo name for current "git dir", and url in github where it would upload to
git remote set-url repoName url	# use this if need to change remote github/bitbucket url
				# url for the named repo need to be pre-created in github, bitbucket, etc

git push --set-upstream repoName master	# the first push to a new repo need to specify the repository and branch name 


git reset			# abandone current uncommited changes.  ie revert files to state in the git repo
git clean -nd			# clean is to remove all untracked files in the current dir.   -nd = preview/dry run
git clean -id			# -i for interactive.  -f for force.

git revert			# abandone changes in a checkout ?
git reset head			# undo "git add"


git log --diff-filter=D --summary | grep delete		# list all deleted files in github
git checkout SHA^ -- ./filename				# restore a file.  ^ means right before the commit


git ls-files -d | xargs git checkout -- 					# undelete all unstaged deletion (those not commited yet)
git status | grep 'deleted:' | awk '{print $2}' | xargs git checkout --		# recover  all staged delete (after commit)	

git against "origin"
origin vs upstream?
origin is typically the developer's central repo hosted on github,
or the hosting location of a fork of a project.

For team, non forked project, origin is the central repo residing on github.com or bitbucket.com

If fork is involved, see upstream below.
git push			# get local copy pushed into "central", or source of clone.  other will get the changes now.
				# this uses the default, which really means git push origin master # for primary source, master branch.

git push origin master		# what "git push" is doing when other params are omitted
				# pushes my current "master" branch to central repo "origin" by uploading data (to github)

git pull			# sync local git db with the remote server db (eg github, aka central)
				# recommend to do this before pushing changes back to central.
				# pull (from central) daily or so when working on a branch to keep code merges manageable
				# and the pull does not "post" my local changes to central so no one knows about the local work 

git pull --rebase		# may want to do this before commit... so conflicts are local.
				# rebase has to do with where to insert changes into the original tree... 
				# rebase is typically the most desirable option
				# BUT...
				# in corp env, almost always better to use fetch and merge than pull --rebase
				# Hmm...
				# --rebase may work well between diff branches, where conflict files are few, changes between contributor are in "islands".
				# --rebase may NOT be so good w/in a branch of single contributor, since the edits on different machines likely rooted on same base and don't want to `rebase` that.


git fetch 			# get changes on master repo and sync them to local copy of the repo.  
				# conflict may arise from this.  
				# better resolve conflict here before committing/pushing.

git merge 			# merge branch


# it is prefered to resolve conflicts in local copy, 
# rather than push the changes out
# and have everyone look at changes at the global level, 
# which may cause lot of conflict in other's code.

# config git to use proxy
# note that shell env var http_proxy isn't heeded
git config --global http.proxy http://proxy01.eville.com:2011

git config --global --unset http.proxy


git config --global alias.proxy   "config --global http.proxy http://proxy01.eville.com:2011"
git config --global alias.noproxy "config --global --unset http.proxy"

git config --global alias.lol "log --oneline --graph --decorate"		# create alias "git lol"   # logd

git against "upstream"
upstream usually refer to the "grand daddy" repo of an open source project, where Pull Requests are submitted to add one's contribution to the open source project.
Example workflow can be seen at Singularity documentationcontribution page.

# fork the project 
# git clone the fork above

git checkout master
git remote add "upstream" https://github.com/singularityware/singularityware.github.io


# made changes
git commit ...


# goal is to make any conflicting changes locally and 
# address them before pushing it upstream 
# where many other folks will see conflict and be affected by it
# below refer to push directly to master, though most project probably should commit to a dev branch of sort.

git pull upstream master		# resync upstream (grand daddy repo) to my master (what i forked)
git pull --rebase upstream master	# (same as?) `git pull --rebase`
# perform any necessary merges
git commit ...
git push origin master 			# (same as?) `git push`

# create Pull Request on github.com 
# forks are tracked by github.com, the PR will submit the changes to the grand daddy repo.

git between branches
  1. create a new branch, make changes, commit, close off branch once it is done
  2. Before branching, checkout into the branch where the merge will eventually be done against. eg git checkout dev; git branch tin-dev

git checkout tin
git pull          origin dev    # pull from origin, the dev branch, into the branch i am sitting in.
                                # do this before commit changes, help keep branch uptodate 
git pull --rebase origin dev    # --rebase seems to work out better when "parent" (dev) branch has lots of changes that I just want to keep.  

                                # git commit and push after pull should produce desirable result

--0--

git fetch				# update all branches ?

--0--

git checkout tin
						# merge had been really messy/fuzzy...
git merge develop		# pull changes from develop branch into the repo I am sitting in (tin)
git push origin   tin	# ie git push?  get my local changes into "origin" (bitbucket)


overall idea is to pull/fetch all changes into the branch I am doing edit.
resolve all conflicts (merge) locally.
then push the changes/commits into origin (bitbucket), then create PR.

If already created PR, 
still fetch all changes from "parent branch" locally.
resolve and commit , then PR will reflect the final change without conflic,
thereby allowing easy merge w/o conflict.



git branch        --delete BRANCH_NAME	# delete local branch, if all changes already pushed
git push   origin --delete BRANCH_NAME	# work on "origin", ie bitbucket, and remove the branch that is there.  ie, it include a push right away.

dealing with conflicts

git config merge.conflictstyle diff3 will got a long way in automatically merging differences. And those that actually have conflicting lines will be marked clearly in the file, search for <<<< |||| >>>>

There are also visual diff tools. command line method using branch can also be used. Refer to post in stackoverflow for many other gory options.

git terminology


github

Example instructions to add files as git repo into github
git config user.email "tin6150@gmail.com"
git config user.name  "tin"

# can use git config --global  if no need to use diff settings per repository
git config --global credential.helper 'cache --timeout=3600'
git config --global github.user   tin6150
git config --global github.token  mytoken
git config --global color.ui      true

git remote add origin https://github.com/tin6150/psg.git
git push -u origin master

Client/tools

git TUI client
git GUI client

git in windows

Install wsl
sudo apt install git
This is pretty usable.
can have the git run outside the lxfs subsystem, eg cd /mnt/c/... and git clone into a folder there. it works too.
Use terminal like Cmnder or apt get install lxterminal and use with like XcSvr.
TL;DR
These notes are pre WSL, or if it was ever desired to use git but not WSL...

There is a git client for windows, but the cli didn't suite my taste and need :(
in the git-bash terminal, git push will prompt for username in the cli, and a pop up GUI window for password.

Cygwin and MobaXterm has provided a quite usable unix-like bash environment for windoze. However, getting git to work has been very tricky :( The following info from stack overflow may help...
unset HOMEPATH
export HOME=/c # in MINGW64 from PortableGit bash terminal

At the end, cygwin with the git that it ships with worked out okay for me, but it is not usable inside a mobaXterm tab.
export HOMEPATH=\
export HOMEDRIVE=H:

git references

Git the Princess

Thanks to the folks at toggl


Doc URL
https://tin6150.github.io/psg/git.html
https://tin6150.gitlab.io/psg/git.html

(cc) Tin Ho. See main page for copyright info.


hoti1
bofh
bofh1