SCM GIT
Introduction
Git is a source code management (SCM) software for tracking changes in any set of files, usually used for coordinating work among programmers collaboratively developing source code during software development.
References
What is the purpose of `text=auto` in `.gitattributes` file?
https://askcodes.net/coding/what-is-the-purpose-of-%60text=auto%60-in-%60-gitattributes%60-file-
Feature toggles (aka feature flags)
https://www.atlassian.com/continuous-delivery/principles/feature-flags
See also 'Feature Toggles pattern' > https://sites.google.com/site/pawneecity/architecture/feature-toggles-pattern-architecture
Trunk-based workflows (best practices)
https://www.atlassian.com/continuous-delivery/continuous-integration/trunk-based-development
Gitflow Workflow (fallen in popularity in favor of trunk-based workflows)
https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow
Git: Handling Merge Conflicts Using "Ours" and "Theirs"
https://howchoo.com/git/git-merge-conflicts-rebase-ours-theirs
https://howchoo.com/git/git-merge-conflicts-rebase-ours-theirs
Git: How to replace the master branch
https://skofgar.ch/dev/2020/08/git-how-to-replace-the-master-branch/
Configuration
Generic config
·User info:
git config --global user.email "wsparcie.t@my.dom"
git config --global user.name "Wsparcie T."
·Line endings normalization to LF:
git config --global core.eol lf
git config --global core.autocrlf input
... and also at repository level, in the .gitattributes file, text=auto makes that when someone commits a file, Git guesses whether that file is a text file or not, and if it is, it will commit a version of the file where all CR + LF bytes are replaced with LF bytes. It doesn't directly affect what files look like in the working tree:
* text=auto
·Set UTF-8 display for Git GUI differences window
# Global setting for all you repositories
> git config --global gui.encoding utf-8
# For one repository only
> git config gui.encoding utf-8
·Pull reconcile divergent branches strategy
git config --global pull.rebase false
·Tag default sort order (SemVer descending)
git config --global tag.sort -v:refname
·P4Merge difftool / mergetool
Download P4Merge> https://www.perforce.com/downloads/visual-merge-tool
wget https://cdist2.perforce.com/perforce/r20.2/bin.linux26x86_64/p4v.tgz
Install P4Merge
gunzip p4v.tgz
tar xvf p4v.tar
sudo mkdir /opt/p4merge
sudo mv p4v-2020.2.2028073/* /opt/p4merge
sudo ln -s /opt/p4merge/bin/p4merge /usr/local/bin/p4merge
Add the following commands to git's "global config settings" so p4merge will be used as both git's difftool & mergetool
git config --global merge.tool p4merge
git config --global mergetool.p4merge.path /usr/local/bin/p4merge
git config --global mergetool.prompt false
git config --global diff.tool p4merge
git config --global difftool.p4merge.path /usr/local/bin/p4merge
git config --global difftool.prompt false
.gitignore
# Avoid Windows streams
*:Zone.Identifier
Save username and password config
It might be useful when using HTTPS (instead of SSH).
Unsecure algternative using plaintext files:
https://stackoverflow.com/a/35942890/1323562
Note: Credentials are stored at ~/.git-credentials
Secure alternative is using GCM:
a) Install GCM
https://github.com/git-ecosystem/git-credential-manager/blob/release/docs/install.md
Eg the 'Debian package' method
b) Configure Git to use GCM
https://aka.ms/gcmcore-linuxcredstores
Eg the 'GPG/pass compatible files' method
GitUI
GitUI provides the user experience and comfort of a git GUI but right in the terminal while being portable, fast, free and opensource.
Home > https://github.com/extrawurst/gitui'
Releases > https://github.com/extrawurst/gitui/releases
Install (tested in Ubuntu):
wget https://github.com/extrawurst/gitui/releases/latest/download/gitui-linux-musl.tar.gz
tar xvzf gitui-linux-musl.tar.gz
sudo install gitui /usr/local/bin
Verify installed version
gitui --version
Run (inside a git repo):
gitui
clone or change origin of remote repository
Clone (SSH or HTTPS)
Doc > https://www.atlassian.com/git/tutorials/setting-up-a-repository/git-clone
git clone git@gitlab.cou.edu:COU/pera_back.git
Change origin of remote repository (eg: from SSH to HTTPs)
$ git remote -v
origin git@gitlab.cou.dom:COU/app_back.git (fetch)
origin git@gitlab.cou.dom:COU/app_back.git (push)
$ git remote set-url origin https://gitlab.cou.dom/COU/app_back.git
$ git remote -v
origin https://gitlab.cou.dom/COU/app_back.git (fetch)
origin https://gitlab.cou.dom/COU/app_back.git (push)
checkout
Handling Merge Conflicts Using "Ours" and "Theirs"
[--ours] Keep the version in the current branch:
git checkout --ours myscript.py
[--theirs] Keep the version from the branch being merged in
git checkout --theirs myscript.py
merge
Resolving conflicts using “Xours” and “Xtheirs”
In those situations where you just want to override changes from one branch to another, you can use two merge strategy options: -Xtheirs and -Xours:
[--theirs] Override the changes in the current branch w/ the feature/whatever branch
git merge -Xtheirs feature/whatever
[--ours] Keep the current branch changes
git merge -Xours feature/whatever
Force merge
Assume we want to merge hotfix/whatever to master, but that is impossible.
Create a copy (for backup)
// go to hotfix/whatever branch
git switch (or checkout) hotfix/whatever
// create new branch
git branch hotfixtemp
In branch hotfixtemp
// force merge
git merge -s ours master
In branch master
git merge hotfixtemp
Commit & push
git gui
Create new branch from tag
git checkout -b newbranch existingtag
git checkout -b release/1.3 1.3.10
Rename branch (local and remote) [not tested]
git branch -m old-name new-name
git push origin :old-name new-name
Switch to the branch and then:
git push origin -u new-name
Set master branch to the point of a tag [not tested]
git reset --hard v1.0
Tags
https://git-scm.com/book/en/v2/Git-Basics-Tagging
# Show list of existing tags, w/ the 1st line of the annotation
git tag -n
# Show list of the existing tags, optionally sorting by SemVer descending (config variable 'tag.sort')
git tag --sort=-v:refname
# Create tag "0.2.8"
git tag 0.2.8
# Push tags (transfer all of your tags to the remote server that are not already there)
git push origin --tags
# Push tag "0.2.8" to remote repository
git push origin 0.2.8
# Delete local tag
git tag -d <tag_name>
# Delete remote tag
git push --delete origin <tag_name>
Branches
List branches
List local branches
git branch
List remote branches
git branch -r
List all, local and remote, branches
git branch -a
Rename local and remote branch
git checkout <old_name>
git branch -m <new_name>
git push origin -u <new_name>
git push origin --delete <old_name>
Delete branch branch locally and remotely
https://stackoverflow.com/a/2003515/1323562
git push -d origin <branch_name>
git branch -d <branch_name>
Prune tracking branches not on the remote
git remote prune origin
Replace the master branch
Eg for replacing the current "master" branch with another "mybranch" branch (1st command for 'Local', 2nd for 'Remote'):
git branch -f master mybranch
git push origin +mybranch:master
Blame
Git blame tells you who last modified each line of code in a file.
git blame app/controllers/front_controller.rb
git show <commit>
Commit anterior:
git blame <commit>~1 app/controllers/front_controller.rb
File Locking
Exclusive file locks allows you to lock single files or file extensions and it is done through the command line. Reference:
https://docs.gitlab.com/ee/user/project/file_lock.html
Install Git LFS (in your OS)
sudo apt install git-lfs
Install Git LFS (in your repository)
git lfs install
Configure exclusive file locks
Tell Git LFS which kind of files are lockable
git lfs track "*.png" --lockable
Make sure .gitattributes is tracked
git add .gitattributes
Lock a file
Lock file
git lfs lock path/to/file.png
List files locked with LFS locally
git lfs locks
Unlock a file
Unlock file
git lfs unlock path/to/file.png
Unlock file by id (given by LFS when you view locked files)
git lfs unlock --id=123
Force file unlock (requires Maintainer permission to the project)
git lfs unlock --id=123 --force
Troubleshooting
fatal: detected dubious ownership in repository at '//wsl$/ ...
At Settings "Edit global .gitconfig" and add to [safe] the line directory = *, eg:
[user]
name = thatsme
email = thatsme@cou.edu
[safe]
directory = *
libgit2 returned: failed to get security information: Incorrect function.
This error happens in TortoiseGit, accesing a repository in a WSL path.
The solution is to upgrade the TortoiseGit version to greater than 2.14.0.0 (also works w/ Fix4009-64bit)