My everyday GIT commands

Themes




Definitions

The repository :
you have the remote and the local repository. They contain the repository content (commits, tags, …).
By default the remote contains the whole content because that is the reference while for practical reasons the local that we get by cloning a remote repository contains by default only the default branch and commits associated to. We could of course update the local repository to retrieve anything stored in the remote.

The working tree :
Files and folder that we are currently working on. It is the area before that a file is managed by Git.

The index :
It is an area between our working tree/workspace and our local repository.
The index holds a snapshot of the content of the working tree, and it is this snapshot that is taken as the contents of the next commit (quoted from the official documentation).
Indeed, in Git, we don’t commit changes directly but we add them first in the index or stage area (while we could commit directly but that is generally unadvised).
Sometimes, we chain index adding and commits but some other times, we consider that area as a checkpoint to save our quite stabilized progress but not still enough to perform a commit.

The HEAD :
It is a pointer on the commit of the branch/revision of our working tree.

The origin :
It is the reference name given to the remote repository inside our local git repo.
In commands where we specify branch or commit, if we prefix it with origin such as origin/foo-branch it means that we refer to the remote version of the branch. If we don’t prefix it, it means that we refer to the local version (git local repo) of the branch.

A ref :
A ref is anything pointing to a commit.
For example, branches (heads), tags, and branches.
We have refs stored in our git local repository and we have also refs stored on the git remote repository.
Refs are grouped by folder/category in .git/refs (local or server).
We have for example heads, remotes (in case of local repository), tags folders.

The general workflow :

(Not Git World)      Git stage area    Git repository           Git repository  

Working tree ----->  Index ----->  local repository  ----->  remote repository  
      
              add         commit                     push

Git ignore and Git exclude

Git ignore

Apply the pattern relative to the directory level of the .gitignore file
If we specify a separator at the beginning or middle (or both) of the pattern.
Example:
/config
config/file.txt

Apply the pattern at any level below the .gitignore level.
If we specify no separator or a separator at the end of the pattern.
Example:
config
config/

Git exclude

Ignore the modifications of a local file/directory that exists in the remote repository
Edit the file .git/info/exclude by adding a line specifying the exact location of the file/directory to ignore.
Example:
config/file.txt
The working tree cannot be aware of the change, so we need to force it in this way:
git update-index --assume-unchanged config/file.txt

Company proxy tricks

Disable the ssl verify globally (a trick. Favor the certification rather ):
git config --global http.sslVerify false

Disable the ssl verify for a command :
env GIT_SSL_NO_VERIFY=true git clone...

Or for the current shell instance :
export GIT_SSL_NO_VERIFY=true
git clone...

Set the http proxy :
git config --global http.proxy http://username:password@proxyHost:proxyPort

Set the https proxy :
git config --global https.proxy http://username:password@proxyHost:proxyPort

Setting an http proxy bypass (last entry below) by url along http and https proxy declaration:

[http]
    proxy = http://my.proxy.net:8080
[https]
    proxy = http://my.proxy.net:8443
[http "http://my.internalgitserver.com/"]
    proxy = ""

Minimal config variables to set to work in good conditions

Who we are :
git config --global user.name "fooUsername"
git config --global user.email foo@bar.com

Remember credentials (to not repeat our creds at each interaction with the remote repo) :
git config --global credential.helper (store/manager/... choose the way that suits)

Diff and Merge tools :

Git init repositories

command:
git init

According to the version of git we use, the name of the default branch may be different:
– master
– main

Whatever, we can specify explicitly the default branch by setting the init.defaultBranch configuration option(introduced in Git 2.28.0, released in July 2020).
For example:
git config --global init.defaultBranch main

– We can also specify the default branch name when we initialize a repository:
-b
--initial-branch=

Clone repositories

Clone a remote repository :
git clone http://mydomain/myProject.git [targetFolder]
By default the local git repo is stored under a directory named as the git repository.
To override it we could specify the local target folder at the end of the command.

Flags :
-b BRANCH_NAME :
make HEAD point to point to BRANCH_NAME instead of the cloned repository HEAD (that is generally master).

The args --bare and --mirror may be helpful in some specific cases.
--bare will create only local tracking.
--mirror will do as the default but by fetching all existing branches. So it is a way to copy the whole git repository.

More here :
https://stackoverflow.com/questions/3959924/whats-the-difference-between-git-clone-mirror-and-git-clone-bare

To disable the SSL verification during clone :
env GIT_SSL_NO_VERIFY=true git clone ...

Partial clone and partial checkout

Partial clone makes sense if we don’t need to retrieve all resources to work for :
– repositories with a lot of files
– repositories with big blob files

Pre-requirement : use a recent version of Git.
Version 2.30 and more recent are perfect.
It may work in a some way with older versions but with some potential limitations.

Clone a remote repository :
Helpful shallow clone flags :
--depth DEPTH :
Shallow clone with a history truncated to the specified number of commits.

Implies --single-branch unless --no-single-branch is passed.

--filter=FILTER
Partial clone feature and request that the server sends a subset of reachable objects according to a given object filter.
For example, --filter=blob:none will filter out all blobs (that are finally any file contents) until needed by Git

--sparse
Initialize the sparse-checkout file so that the working directory starts with only the files in the root of the repository.

Default sparse-checkout file
The root directory is added as a parent pattern. The sparse-checkout file contains the following patterns:

/*
!/*/

This says « include everything in root, but nothing two levels below root. »

The sparse-checkout file can be view or updated via the git sparse-checkout command.

Pattern order :
Order matters, so the negative patterns are overridden by the positive patterns that appear lower in the file.

Examples :

Clone the default branch (master) of the myapp.git repository by fetching only the last commit history, without content checkout (blob:none), with only file at the root (so without its directories) :
git clone --depth 1 --filter=blob:none --sparse https://gitlab.com/foo/bar/myapp.git

Variant :
– add the -b foo-branch flag to clone the foo-branch instead of the default (master).

List patterns to checkout of the current list:
git sparse-checkout list

Add a pattern to checkout in the current list :
git sparse-checkout add pattern
Ex: add the foo/bar/superFolder/ folder and all its children resources :
git sparse-checkout add foo/bar/superFolder

Variant ex: add the /foo/bar folder but not directories inside (only files) that but /foo/bar/a full content folder and /foo/bar/b full content folder :
git sparse-checkout add '!/foo/bar/*/' '/foo/bar' '/foo/bar/a' '/foo/bar/b'

Replace the whole current list to checkout by that pattern :
git sparse-checkout set pattern
Ex: replace all existing patterns to checkout by the foo/bar/superFolder/ folder and all its children resources :
git sparse-checkout set foo/bar/superFolder

To keep the original pattern (root folder also without) while setting some new pattern(s) :
git sparse-checkout set '/*' '!/*/' 'myapp/bar'

Manage branches (list, deletion, creation)

List local branches:
git branch

Useful flags :
--sort=-KEY : sort by
Ex: --sort=committerdate
See git-for-each-ref doc for available keys

-r : list remote branches
-a : list both remote and local branches
-d branchName : delete a local branch
Use -D instead of -d to force delete

To delete a remote branch :
git push remoteName -d BranchName
remoteName is generally origin.

To fetch local copies of all remotes branches :
Note : it doesn’t update local branches, nor create remote branches not existing in local

git fetch --all

Make the local repository (HEAD and working tree) to point to a specific branch:
git checkout branchName (without specifying « remotes » or « origin »  as prefix)

Create a local branch, point to that and push the remote upstream information:
git checkout -b branch-name
git push --set-upstream origin branch-name

For more recent version of git, we can use the switch command:
git switch -c branch-name


Manage tags

Two flavor of tags : lightweight (only a pointer on an existing commit) and annotated (tag with its own commit, object and checksum)

To list tags :
git tag

To fetch all tags from the remote :
git fetch origin --tags



To create an annotated tag :
git tag -a tagName -m "commit message"

To show details of the tag :
git show tagName

To push a tag on the remote server : 
Beware similarly to branches, git push doesn’t do that. You have to do :
git push origin tagName

Manage tags and branches with no local reference

In some specific circumstances :
– partial cloning
– missing refs in local git repository

Executing git checkout foo-branch or git checkout tags/foo-tag fails with a error like :

error: pathspec 'foo-branch' did not match any file(s) known to git.

To fetch a specific branch from the remote :
git fetch origin refs/heads/foo:refs/heads/foo
The left part is the branch reference in the remote repository and the right part is the reference that we will use in your local repository.
Then we could checkout that :
git checkout foo

To fetch a specific tag from the remote :
git fetch origin refs/tags/foo:refs/tags/foo
The left part is the tag reference in the remote repository and the right part is the reference that we will use in your local repository.
Then we could checkout that :
git checkout tags/foo

Manage tracked repositories

Show the remote information (fetch and pull information) :
git remote -v

Changes the list of branches tracked by the named remote :
git remote set-branches REMOTE-REPO-NAME branchOne branchTwo ...
To track all branches:
git remote set-branches REMOTE-REPO-NAME '*'

Add the fooUrl as a remote repository for pushing (can add multiple if needed):
git remote set-url origin --push --add fooUrl

Pushing to two git remote repo and pulling from a single one should look like

[remote "origin"]
        url = http://gitlab.david.com:8585/gitlab-pipeline/maven-docker-separate-stages-example.git
        pushurl = https://gitlab.com/docker-david-projects/maven-docker-separated-stages-example.git
        fetch = +refs/heads/*:refs/remotes/origin/*
        pushurl = http://gitlab.david.com:8585/gitlab-pipeline/maven-docker-separate-stages-example.git

Allow to pull when we change the repository origin url in the local repo
By default we cannot pull because the current and the previous histories are « unrelated ».
We can bypass it with --allow-unrelated-histories such as : git pull -X ours --allow-unrelated-histories to keep also the current change

Update Local projects

Remote-tracking branches location :  refs/remotes/ directory.

Update your remote-tracking branch :
git fetch [remote]

Merge your remote-tracking branch into our local branch:
git merge

Both operations (Update + Merge remote-tracking into our local branch )
git pull [remote] [branch]

Notes about fetch/merge/pull : 
1)when no remote is specified as argument, by default the origin remote will be used, unless there’s an upstream branch configured for the current branch.
2) fetch doesn’t update local branches under refs/heads (only the refs/remotes directory)

3) After fetching a remote branch in the local repo, we could compare that a local branch to that remote branch with :
git log localBranch..origin/remoteBranch

Rebase

git rebase : Reapply commits on top of another base tip.

The flow is applying commits of the master (or any branch) to the target branch :

$ git checkout feature-x
$ git rebase master

We could have errors if conflicts.
… todo git rebase –continue
And then merge that target branch into the branch we based on for the rebase :

$ git checkout master
$ git merge feature-x

Merge

Sometimes the rebase command rises many conflicts to handle.
In this kind of cases it may be helpful to use instead of the merge command.
If you want update branch_old with all changes from branch_new :

git checkout branch_new
git merge -s ours branch_old
git checkout branch_old
git merge branch_new

Hooks

– Default location : .git/hooks of the current local git repo.

– To make it working on Linux : make them executable (x) and with a correct #!/bin/sh prolog.

– To store the hook files in the source code : add a hooks directory in the current branch with the desired content and set the core.hooksPath property as global to always use that default folder : git config --global core.hooksPath hooks

Work with a repository fetched by a CI tool

CI tools as Jenkins or Gitlab work very closely with Git remote repository that they clone locally.
But generally, the cloned repository is not fully configured to allow us to push anything on it.
For example : a CI job may need to update the version of the component during a release task (ex: 1.0-SNAPSHOT-> 1.0-SNAPSHOT->1.1-SNAPSHOT) on a specific branch, generally the master branch.
To achieve it, we need to update the cloned repository configuration.

Gitlab example : clone a repo with the oauth2 protocol
Requirements :
– Having generated a access token from the user settings/access tokens menu of gitlab.
– Store it as a variable of the CI/CD of the project/group, for example as GITLAB_MY_ACCESS_TOKEN variable.

Tag :
  stage: tag
  tags:
    - maven
  image: maven:3.6.3-openjdk-16
  script:
   # CLONE WITH WRITE RIGHTS CONF
  - gitlabUrlWithCreds=$(echo $CI_PROJECT_URL | sed 's@http://@@' | xargs -I{} echo http://oauth2:${GITLAB_MY_ACCESS_TOKEN}@{}.git)
  - echo "gitlabUrlWithCreds=$gitlabUrlWithCreds"
  - git clone ${gitlabUrlWithCreds} repo-with-creds
  - cd repo-with-rights
  - git config user.email "gitlab pipeline"
  - git config user.name "gitlab pipeline"
  # Not mandatory but prevent warning output appearing since git 2.0
  - git config push.default simple
 
  # Once configured, we could push anything. Ex: a tag 
  - tagVersion=1.0
  - git tag -a $tagVersion -m  "Tagged by gitlab"
  - git push origin $tagVersion

Jenkins example : use the fetched repo for the job and push with credentials (password encoded or not)
Requirements :
– Having two global variables defined to store user and password to push on gitlab. For example : JENKINS_USER and JENKINS_PASSWORD (these could be local but makes more sense to make them global for other projects use)

stage('Tag') {
   when {
       branch "master"
   }
   steps {
       script{
           # We keep all but the https:// part
           GITLAB_PROJECT_URL_PROTOCOL_LESS = sh(returnStdout: true, script: "git config 
           remote.origin.url | sed 's@https:\\/\\/@@'").trim()
           sh """
           / Not mandatory but prevent warning output appearing since git 2.0
           git config push.default simple
           // Not mandatory but may help
           git config http.sslVerify false
           git tag v${VERSION}
           git push https://${JENKINS_USER}:${JENKINS_PASSWORD}@${GITLAB_PROJECT_URL_PROTOCOL_LESS} v${VERSION}
           """
       }
   }
}

Other use case: configure the fetched cloned repo once for all :
In the previous example, we specify the push on the credentials. It means that we may still need to specify them for next pushing operations.
To prevent that, we could configure once for all the local repo with a remote origin url containing credentials.
Ex : add the remote origin url with github:
git remote add origin https://{username}:{password}@github.com/{username}/project.git

Work with a forked repository

1) Fork a repository in your aera from GitHub with the UI.
2) Clone it like any repository with git clone.
3) Generally want to work on a local branch and not the master : 
 git checkout -b my-branch
4) Commit/push like usual.

Rebase a forked repository

At a time  you may need to update your branch from the changes done in the original repository from the fork. 

To do that you have to : 
1) Add the original repository as a remote (first time only). 
For its label, upstream is the norm.  
git remote add upstream https://github.com/xxx/xxx.git
To check its value : git remote -v.

2) Update your local repository against the original repository :
git fetch upstream

3) Squash your changes from the number of commit to rebase:
git rebase -i HEAD~n
or from a specific revision :   
git rebase -i specificRevisionHash

3 Bis) If we need to solve some conflicts, we could use a strategy flag to mean keep theirs (the branch where I merged to) or mine (the reference branch for the rebase).
For example if upstream/master is the reference base for the rebase and that we want to keep the changes from the current branch :
git rebase -i -X theirs upstream/master

To retrieve the revision hash :
git merge-base my-branch upstream/master

Or more simply for 3) : git rebase -i upstream/master

4) In the edited file, replace  pick by squash but for the first one

5) Perform the the local branch rebasing from the upstream/master: 
git rebase upstream/master


Better example : I want to rebase a branch in forked repo on the master branch of the original repo (the upstream)
1) Fetch upstream branches to the local branches : git fetch upstream 
Here commits to the master of the upstream repo  are stored in local in upstream/master.
2)To know new commits between my local branch and the upstream reference branch, I can do : git log mybranch..upstream/master
3) Rebase on master with squash : git rebase -i upstream/master
The pick prefix for the first comment and the next have to be prefixed by squash
3 bis) Or Rebase on master without squash : git rebase upstream/master
5) Force push branch on the origin (force if conflict) :
git push --force

Get content or type and size information of GIT objects

For cat-file : commits, tree or blob objects.
Output the size of an object :
git cat-file -s sha1OfTheObject

Output the content of an object :
git cat-file -p sha1OfTheObject

Output the type of an object :
git cat-file -t sha1OfTheObject

List objects from a revision :
git ls-tree --full-name -r myRevision

List all objects (objectId and file/folder name) whatever the branch:
git rev-list --objects --all

List all objects (objectId and file/folder name) of a specific branch:
git rev-list --objects my-branch

List all objects (objectId, type and size) of the local repository and sort them by size
git cat-file --batch-check --batch-all-objects | sort -n -k3

Show objects

Show the file content at a specific revision :
git show revisionOrBranch:foo/foobar/file.txt

Show the diff of a commit :
git show commitHash

List remote references

Command : git-ls-remote
Displays references available in a remote repository along with the associated commit IDs (last commit).

Two ways of using the command :
– without cloned repository
git ls-remote
– with cloned repository
git ls-remote https://mygit.com/foo.git
If authentication is required, we could use oauth2 token :
git ls-remote https://oauth2:myToken@mygit.com/foo.git

Helpful flags :
– List only tags : --tags or -t
– List only branches : --heads or -h
These options are not mutually exclusive.

– Do not show peeled tags (suffixed with ^{}) or pseudorefs like HEAD in the output : --refs

Git status

Show detailed status of the current git :
– paths that have differences between the index file and the current HEAD commit ( files staged)
– paths that have differences between the working tree and the index file (files with changes but not still staged)
– paths in the working tree that are not tracked by Git (new files) git status

Useful flags :
* short format : -s
* porcelain (may specify a version) or very short format : --porcelain

Git Log

Base command : git log [revision range=fooRange] [path(s)...]
By default it shows all commits leading to the current HEAD.
We could specify paths to limit commit to these files.
We could specify revision range="from..to" to show only commits in the specified revision range.

Useful flags :
-p -- file1 file2 ... : show diffs between each commit for the specified files
--name-only : show names of changed files
--all : show commits of all /refs
--decorate : show the branch name label
--graph : draw a text-based graphical representation of the commit history
--pretty=format : pretty-print the contents of the commit logs in a given format, where format can be one of oneline, short, medium, full, fuller, email, raw, format:string and tformat:string
--abbrev-commit : show only a partial prefix instead of the full 40-byte hexadecimal commit object name
--online : shorthand for "--pretty=oneline --abbrev-commit"
--follow : continue listing the history of a file beyond renames

Useful examples :
Log all with graph and date :
git log --all --graph --oneline --pretty=format:"%h%x09%an%x09%ad%x09%s"

Show all commits between two branches (local or remote) 
Some examples :
git log HEAD..master : commits between HEAD and local master
git log origin/foo..origin/bar : commits between remote foo and remote bar
git log HEAD..origin/bar : commits between HEAD and remote bar
git log origin/foo..foo : log between remote foo and local foo

Retrieve branches information

shows logs of the reference (HEAD is the default) stored in the local repository with the localized date format :
git reflog --date=local

Find the better common ancestor (generally the most recent) for a merge :
git merge-base <commit> <commit>

We could use the commit id returned with git show --summary <commit> to get more details about that commit.

Find commits not yet applied to the upstream branch :
git cherry -v fooUpstreamBranch [child branch]

If « child branch » is not specified, the current branch is used for that.

Compare files/folders

git diff common issues
Problem :
git diff produces a lot of differences with ^M at the end of each line.
Solution:
It is a windows issue which the break line char differs from the linux way.
To solve it, we could set a property that makes automatically the conversion to the Linux way :
git config --global core.autocrlf true

git difftool options
--dir-diff : to perform the graphical comparison from a specific folder. It avoids the difftool app opening a window for each changed file that we need also to close to pass to the next file to compare.

Compare master (last local version) with origin/master (last version fetched locally from remote) :
git diff master origin/master

Compare index changes not still staged :
git diff

Compare only names of index changes not still staged :
git diff --name-only

-C : Detect copies as well as renames. (looks for files only in the same changeset)

--find-copies-harder : Detect copies as well as renames. (looks for files in any changeset)

--compact-summary : Output a condensed summary of extended header information such as file creations or deletions (« new » or « gone », optionally « +l » if it’s a symlink) and mode changes (« +x » or « -x » for adding or removing executable bit respectively) in diffstat.

Compare a file in two distinct commits :
git difftool oneRevision otherRevision -- pathFile

Compare a file(or all files) between the HEAD and the previous commit :
git difftool HEAD~ HEAD (add -- pathFile to specify files)

Compare files between the current working copy and another branch:
git difftool FOO-BRANCH

Apply difftool on the working-copy only for a set of files modified between two commits:
Require 2 steps :
1) Find modified files between the two commits and store them into a file:
git diff --name-only fooCommit master > filesToCompare
2) Compare files between the current working copy and another branch only for these files : 
git difftool --dir-diff master -- $(cat filesToCompare | awk '{files=files " " $1} END {print files}')

Configure Winmerge as graphical merge/diff tool :
Since Git 2.5 :

git config merge.tool winmerge
git config diff.tool winmerge 

where winmerge is the winmerge executable that has to be set in the env var PATH.
We can specify any program able to compare two textual files.

Not working on my configuration.
So also I needed to specify the command absolute path :

git config --replace --global mergetool.winmerge.cmd "\"D:/applications-dev/WinMergePortable/winmerge.exe\" -e -u -dl \"Base\" -dr \"Mine\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\""

Disable prompt confirmation for difftool :
git config --global difftool.prompt false

Conflict management

– When git pull informs a conflict.
Several cases :
1) If we want to merge manually files : git mergetool

2) If we want to keep local changes in case of conflict : git pull -X ours

3) If we want to keep upstream changes in case of conflict : git pull -X theirs


– When git merge remoteBranch informs a conflict.
Several approaches:
1) We want to merge manually files : git mergetool

2) If we don’t want to handle the conflict file by file because too much conflicts and that we know which side (our or their) to keep, we could specify the restart the mege by selecting the conflict strategy for all files:
First we abort the merge : git merge --abort
Then :
* If we want to keep local changes in case of conflict : git merge remoteBranch -X ours
* If we want to keep upstream changes in case of conflict : git merge remoteBranch -X theirs

3) If we want to fix the conflict/unmerge paths for some file(s) by selecting the side (our or their) to keep :
* If we want to keep the local version : git checkout --ours -- file(s)
* If we want to keep the remote version : git checkout --theirs -- file(s)

– When git rebase informs a conflict.
Several cases :
1) If we want to merge manually files : git mergetool

2) If we want to keep local changes in case of conflict : git rebase -i -X theirs BRANCH_REFERENCE

3) If we want to keep upstream changes in case of conflict : git rebase -X ours BRANCH_REFERENCE

Stage files/folders

Stage changes specific tracked or untracked files :
git add <file, file2, ...>

Stage changes all tracked files :
git add .

Stage changes tracked files matched to a path expression whatever its location :
git add *.xml

Useful add flags :
-n : dry-run
-f : allows staging ignored files


Specific staging commands :

Remove files/folders from the working tree and the index :
git rm <file, file2, ...>

Move files/folders in the working tree and the index :
git mv <file, file2, ...>

Commit files/folders

Commit staged files :
git commit -m "message..."

Replace the tip of the current branch by creating a new commit that has the same parents and author as the current one :
git commit --amend

Example : Create a new commit from the current one by using the same message :
git commit --amend --no-edit

Example : Create a new commit from the current one by changing the message :
git commit --amend -m "the new message"

Undo commands

checkout versus reset semantics
– With paths+commit args : 
checkout and reset have a very closed behavior.

– With path arg only :
checkout updates the working tree with the content of the current HEAD.
reset updates the index with the content of the current HEAD.

– With commit arg only : 
checkout switches to a new (detached) branch and update the head to that branch.
reset updates the index with the content of the commit and update the head to that.


undo FAQ 

Undo working tree files :
git checkout .
Undo specific working tree files :
git checkout -- foo bar

Undo staged files :
git reset
Undo specific staged files :
git reset -- foo bar

Undo commited files and moves the HEAD to that commit :
git reset HEAD~1
Undo specific commited files (it doens’t move the HEAD to that commit):
git reset HEAD~1 -- foo bar

Further undo commands.

Set working tree files and index to a commit :
git checkout commit -- paths 
Example : 
git checkout 1545151de -- foo bar 
It updates the a and b working tree files and the index to the specified commit 

Hint : git reset with similar syntax may be used.

Set the current branch head to commit (may modify index and working tree to match).
git reset commit  
By default, the mixed mode is used in that reset form.
Example : 
git reset 1545151de  
Warn : Setting the current branch head to an old commit will make your branch to be behind commits.


Other Examples (to explain):
git reset HEAD~
git reset HEAD~2
git reset 12154df5454dfdf
git reset foobranch
git reset origin/foobranch

HEAD~ means the previous commit to the current HEAD, literally « head – 1 commit ». 
HEAD~2 means « head – 2 commits » and so for…
12154df5454dfdf is a commit revision
foobranch is the local revision of foobranch.
origin/foobranch is the remote revision of foobranch.

checkout :
Two main usages :
1)Switch to another branch and update HEAD and working tree according to  when no paths arg is passed.
Syntax is : git checkout <fooBranch>

2)Update specified working tree files when paths arg is passed.
Syntax is : git checkout <fooBranch> -- file1 file2
To select all files : git checkout <fooBranch> -- .

The 1) way fails if working tree files or index are in conflict with the chosen branch. We need to stash or commit them first.
The 2) way restores from the index state, the specified resources of the working tree if we don’t specify a tree-ish but if we specify that, it restores both the index and the working tree.

reset :
Two main usages :
1) Reset current HEAD and optionally index and working tree to a specified commit 
Syntax is : git reset <fooBranch>

That mode doesn’t allow to specify paths to reset.
About the mode :
Whatever the mode, it resets at least the head to the « commit ».
--soft
Only resets the head to the specific commit, just like all modes do (so don’t touch the index file neither the working tree)
--mixed (default option)
Resets the index to the specific commit but not the working tree
--hard
Resets the index and the working tree.
WARN : Any changes to tracked files in the working tree since the commit are discarded.

2) Reset index for specified paths
Syntax is : git reset <fooBranch> -- file1 file2

That mode doesn’t allow to specify mode (the mixed mode will be used by default).

About untracked files:
These will not be removed when using reset or checkout .
Always use clean to remove them.
Remove untracked files :
git clean -f

Helpful clean flags :
-f : force
-d : remove untracked directories in addition to untracked files
-n : dry-run
-X : remove only resources ignored by git


Examples with reset and mode :
To reset only the head to the previous commit :
git reset --soft HEAD~

To reset head, index and working tree to the previous commit
git reset --hard HEAD~

To reset head, index and working tree to the last remote commit of the master branch :
git reset --hard origin/master

Rename a remote branch (copy the branch and then delete it) :
git branch -m old_branch new_branch
git push -u origin new_branch
git push origin :old_branch

Undo pushed commits (with no trace of undo) :
git reset sha1-commit (make the head and the index to point to a specific commit)
or
git reset sha1-commit (make the working tree, the head and the index to point to a specific commit)
Do/fix your modifications in the working directory…
git commit -m "message" (commit)
git push -f origin branch-name (force the push that will replace further commits by this one)

To force push from the detached HEAD to the remote :
git push -f origin HEAD:name-of-remote-branch

Revert a commit (with trace of undo) :
git revert sha1-commit
Alternative : specify range to revert from the HEAD back to the commit :
git revert --no-commit lastCommitToKeep..HEAD

Revert a merge-commit :
git revert -m <1or2> sha1-commit
Here the -m flag specify the parent commit to keep after the revert(we have two of them in a merge).

Manage GIT properties

Display local GIT properties :
git config --list

Display global GIT properties :
git config --global --list

Set user email information :
git config --global user.email "..."

Set user name information :
git config --global user.name "Your Name"

Unset GIT properties :
If a single value for the entry :
git config --unset myProp

If multiple values for the entry :
git config --unset-all myProp

Open the global configuration :
git config --global --edit

To debug the config values and the files where they come from
Show all config values with their origin :
git config --global --list --show-origin --show-scope

List files and locations of config files :
git config --list --show-origin --show-scope

Store credentials

Linux Or Windows way with the store helper

Store and use the user and the password in plain text (information is stored in the home/.git-credentials file (unix directory) :
For a local git repo :
git config --local credential.helper store
At each authentication need, git checks if the username and the url requested have a matching in that file and so uses that.
For global :
git config --global ...

Where credentials are lookup and stored ?
By default, in the files : ~/.git-credentials or if not found in $XDG_CONFIG_HOME/git/credentials
To override that :
--file=foofile
Ex : git config --global credential.helper 'store --file ~/.my-credentials'
Whatever way, the file will have its filesystem permissions set to prevent other users on the system from reading it.

On Linux, we could clear the file (or the entry) that contains the credentials to not use any longer:
rm ~/.git-credentials

Windows way

To clear git cached password by the credential.helper:
Under Windows 7/10, we need to clear the credential from  Credential Manager/Windows Manager

Store user and password :
git config credential.helper wincred
Deprecated.
We should use :
git config --global credential.helper manager

But sometimes only the wincred value solves the issue.

Whatever OS

To benefit from secure storage provided by the OS : we should use git-credential-cache.

Switch to another user for a specific local git repo :
git config --local username NEW_USERNAME (should do the same thing for the email and the name for consistency reasons)
We also often need to change the credential.username such as :
git config --local credential.username NEW_USERNAME

To disable credential.helper :
git config --global --unset credential.helper
It may be helpful before adding a new one.

Common issues : Credentials are not cleared or git doesn't ask new credentials
1) Look at credential part in the global config and delete duplicate or weird things:
git config --global --edit
2) Clear the cached password (windows or Linux way)

Error when cloning, pulling or pushing a remote repository

remote: The project you were looking for could not be found.
fatal: repository 'http://gitlab.david.com:8585/kubernetes-projects/spring-boot-docker-kubernetes-example.git/' not found

Possible causes :
- error in the url of the project (may be the group name in the url). Check it with curl or your browser
- the user doesn't have the right to access to that project.
To fix : add to him the rights in the gitlab admin.

 

Unix-Windows compatibility tricks

 

 

Convert all files from the linux to the windows format (dos2unix to do the reverse) :

find . -type f -print0 | xargs -0 unix2dos

Uncommon GIT commands but very useful

When the "git clone" command gives this error :

 

fatal: unable to access 'https://github.com/...': error setting certificate verify locations:
  CAfile: C:/Program Files/Git/mingw32/libexec/ssl/certs/ca-bundle.crt
  CApath: none

It means that the path to retrieve the CAfile is probably wrong.
Check it in your filesystem and set the metadata in your git client by doing :
git config --system http.sslcainfo "absolute-path-to-ca-bundle.crt"

-----------------------------------------------------------------------------------------------------
Using meld as tool for merge and diff :

git config --global diff.tool meld
git config --global difftool.prompt false

You can also need to set the path of meld :

git config --global difftool.meld.path meldExecutablePath

Beware, if you already configured another tool for these operations, you have to unset them as git config add and doesn't overwrite (same thing for mergetool).

Graphical viewers

To configure the difftool with meld :

# Add the following to your .gitconfig file.
[diff]
    tool = meld
[difftool]
    prompt = false
[difftool "meld"]
    cmd = meld "$LOCAL" "$REMOTE"

To configure the mergetool with meld :

[merge]
	tool = meld
[mergetool "meld"]
        cmd = meld "$LOCAL" "$MERGED" "$REMOTE" --output "$MERGED"

Predefined variables :
$LOCAL : the temporary file with the diff pre-image
$REMOTE : the temporary file with the diff post-image
$MERGED : the name of the file which is being compared

NB : in difftool "meld" and mergetool "meld" group, we could add the path entry of the command such as :

[difftool "meld"]
    cmd = meld "$LOCAL" "$REMOTE"
    path = c:/foo/meld.exe

If diff-tool dir-diff fails with meld error :

--output option requires an argument

We could also configure difftool and mergetool from command line :
git config --global difftool.meld.cmd 'meld "$LOCAL" "$REMOTE"'
git config --global mergetool.meld.cmd 'meld "$LOCAL" "$MERGED" "$REMOTE" --output "$MERGED"'

Display the logs of all in a GUI graph :
gitk --all

Alias to shortcut common or long commands

Some common useful :

git config --global alias.br branch
git config --global alias.graph "log --graph --oneline"
git config --global alias.co checkout
git config --global alias.ci "commit -m"
git config --global alias.st status
git config --global alias.difd "difftool --dir-diff"

Git Shell

For Windows :
Use the Git Bash program.

For Linux :
Use the git-sh program. It is available via the package manager.
The completion may not work. In that case, we could edit the git-sh.sh program and source the git completion file, something like that on ubuntu :
. /usr/share/bash-completion/completions/git

Cherry pick

The cherry-pick command

Apply the changes introduced by some existing commits
Generally for commits of a specific branch to another one.
Syntax :
git cherry-pick [--edit] [-n] [-m parent-number] [-s] [-x] [--ff] [-S[]] commitHash...
Example :
I want to add the "foo" commit from branch A in the HEAD of the branch B.
git checkout B
git cherry-pick foo

Behavior of a cherry pick commit 

- The cherry pick of a commit creates a new commit at the head of the target branch.
It means the sha1 and the message is a new one.
- the content of that commit is stick to the source branch. It is the difference between the commit-1 and the selected commit of the source branch.

The gitlab cherry-pick feature in merge requests

It allows to cherry pick the content of a terminated merge and so we could apply the created commit to propagate the result of the terminated merge in other branches
That cherry pick has the same characteristics than classic cherry pick command (see above)

Export repository

Export and import all branches for repository:

git clone --mirror <original_repository> 
cd <project>.git
git remote add new_remote <new_repository>
git push --all new_remote --force
Ce contenu a été publié dans Non classé. Vous pouvez le mettre en favoris avec ce permalien.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *