Git Basics

Some basic git commands and workflows

Courtesy of rogerdudler.github.io

Create a Repo

Create a new repo with git init:

bbearce@bbearce-XPS-15-9560:~/Desktop/git_practice$ git init
Initialized empty Git repository in /home/bbearce/Desktop/git_practice/.git/

Checkout a Repo

Checkout a repo with git clone:

$ git clone /path/to/repository

When using a remote server, your command will be:

git clone username@host:/path/to/repository

Workflow

Your local repository consists of three "trees" maintained by git. the first one is your Working Directory which holds the actual files. The second one is the Index which acts as a staging area and finally the HEAD which points to the last commit you've made.

Basic Git Workflow

Add and Commit

Basics

You can propose changes (add it to the Index) using:

git add <filename>

or

git add *

This is the first step in the basic git workflow. To actually commit these changes use:

git commit -m "Commit message"

Now the file is committed to the HEAD, but not in your remote repository yet.

git remote -v will tell you which remote you are connected to.

SYNOPSIS
       git remote [-v | --verbose]

...

OPTIONS
       -v, --verbose
           Be a little more verbose and show remote url after name. NOTE: This must be placed between remote and subcommand.

Add hunks

Source

You can use:

git add --patch <filename>

or for short:

git add -p <filename>

Git will break down your file into what it thinks are sensible "hunks" (portions of the file). It will then prompt you with this question:

Stage this hunk [y,n,q,a,d,/,j,J,g,s,e,?]?

Here is a description of each option:

Undo a Commit

Note: really good notes on the diff between reset, revert and rebase here.

Reset

There are two main ways to undo commits: * soft: commit undone and changes left un-staged

git reset --soft HEAD~1
git reset --hard HEAD~1

Here the ~1 indicates go back one commit

Revert

In Git, the revert command is used to perform a revert operation, i.e., to revert some changes. It is similar to the reset command, but the only difference here is that you perform a new commit to go back to a particular commit. In short, it is fair to say that the git revert command is a commit.

The Git revert command does not delete any data while performing the revert operation.

Rebase

Rebase can sometimes be a little confusing to understand because it is very similar to a merge. The goal of merging and rebasing both is to take the commits from my feature branch and put them on to a master branch or any other branch.

Get yourself into the right state which is an up to date develop\main branch and then checkout your feature branch which is a little behind develop\main but has a new feature.

Ex:

bbearce@pop-os:~/Documents/codabench$ git checkout download_buttons                                                                                                                                                                                                                                                                   
Switched to branch 'download_buttons'                                                                                                                                             
Your branch is up to date with 'origin/download_buttons'.                                                                                                                         

bbearce@pop-os:~/Documents/codabench$ git branch                                                                                                                                  
  develop
* download_buttons


Adding a New Remote

Courtesy of articles.assembla.com

To add a new remote, use the git remote add command on the terminal, in the directory your repository is stored at.

The git remote add command takes two arguments:

#set a new remote
git remote add origin git@git.assembla.com:portfolio/space.space_name.git

#Verify new remote
git remote -v

origin  git@git.assembla.com:portfolio/space.space_name.git (fetch)
origin  git@git.assembla.com:portfolio/space.space_name.git (push)

Pushing Changes

Your changes are now in the HEAD of your local working copy. To send those changes to your remote repository, execute:

git push origin master

Change master to whatever branch you want to push your changes to.

If you have not cloned an existing repository and want to connect your repository to a remote server, you need to add it with:

git remote add origin <server>

Now you are able to push your changes to the selected remote server.

Push Without User:Pass

Courtesy of medium.com

A way to skip typing my username/password when using https://github, is by changing the HTTPs origin remote which pointing to an HTTP url into an SSH url.

For example:

https url: https://github.com/<Username>/<Project>.git
ssh url: git@github.com:<Username>/<Project>.git

You can do:

git remote set-url origin git@github.com:<Username>/<Project>.git

to change the url.

You need to have an ssh key pair generated and added to github

Steps:

[1]. Generate Key Pair

Open Terminal.

Paste the text below, substituting in your GitHub email address.

$ ssh-keygen -t rsa -b 4096 -C "your_email@example.com"

Generating public/private rsa key pair.

This creates a new ssh key, using the provided email as a label. When you're prompted to "Enter a file in which to save the key," press Enter. This accepts the default file location.

Enter a file in which to save the key (/home/you/.ssh/id_rsa): [Press enter]

At the prompt, type a secure passphrase. For more information, see Working with SSH key passphrases.

Enter passphrase (empty for no passphrase): [Type a passphrase]> Enter same passphrase again: [Type passphrase again]

[2]. Add public key to git account or Add public key to git repo

Possible Issues:

If you get this error:

ERROR: Permission to bbearce/code-journal.git denied to deploy key
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

You need to add your ssh key to the ssh-agent. Before adding a new SSH key to the ssh-agent to manage your keys, you should have checked for existing SSH keys and generated a new SSH key.

If you have checked for existing SSH keys and find one you want to use, follow the below instructions.

  1. Start the ssh-agent in the background.
$ eval "$(ssh-agent -s)"
> Agent pid 59566
  1. Add your SSH private key to the ssh-agent. If you created your key with a different name, or if you are adding an existing key that has a different name, replace id_rsa in the command with the name of your private key file.
$ ssh-add ~/.ssh/<your_ssh_key>

not the .pub file but the file with no extension.

Add the SSH key to your GitHub account.

Access Token

Souce

This link above helps setup a way to push with access tokens.

Branching

Branches are used to develop features isolated from each other. The master branch is the "default" branch when you create a repository. Use other branches for development and merge them back to the master branch upon completion.

Branching Image

Create a new branch named "feature_x" and switch to it using:

git checkout -b feature_x or git branch feature_x

When switching to a new branch commit changes to master before switching. Also same for the new branch when switching to back to master.

Switch back to master:

git checkout master

Delete the branch again:

git branch -d feature_x

A branch is not available to others unless you push the branch to your remote repository:

git push origin <branch>

Show remote branches and their local associations

git remote show origin

See what remote branch your local branch is tracking

git branch -vv

Ex:

debian@codabench-test-acl-220627:~/codabench$ git branch -vv
  develop                   46c1ff7 [origin/develop] Merge pull request #696 from codalab/remove-vnc
* leaderboard_v2_comp_fixes 7c2811e edit compute worker so that yaml gets correct amount of inputs

local develop tracks remote develop branch at remote "origin". leaderboard_v2_comp_fixes is currently not tracking a remote branch

Add local branch to remote

git push -u origin <branch>
# short for
git push --set-upstream origin <branch>

Check out a PR from your repo's branch or another's:

Check out a pr to a local branch

git fetch origin pull/763/head:anyname
git checkout anyname

Update and Merge

To update your local repository to the newest commit, execute:

git pull

In your working directory to fetch and merge remote changes. To merge another branch into your active branch (e.g. master), use:

git merge <branch>

In both cases git tries to auto-merge changes. Unfortunately, this is not always possible and results in conflicts. You are responsible to merge those conflicts manually by editing the files shown by git. After changing, you need to mark them as merged with:

git add <filename>

Before merging changes, you can also preview them by using:

git diff <source_branch> <target_branch>

Undo Merge

Source freecodecamp

Use git reflog to find commit before merge. Why? Because what if you merged in like 30 commits (I did). Then you have to go one by one to find the correct commit to go back to.

Checkout reflog at the bottom of this page under Useful Hints.

Using merge (safer)

Git provides a safer flag which is --merge. Use the HEAD keyword with the --merge flag by running git reset --merge HEAD~1.

Run git reset --merge <previous-commit> for a specific commit.

If you don’t get a response from this command when you use the --merge flag, don’t worry, it works.

Using reset (dangerous)

If you are not sure of the hash of the last commit, you can run git reset --hard HEAD~1 to go back to the commit before the merge

When you get the hash of the commit you want to get back to, run git reset --hard <commit-before-the-merge>

Tagging

It's recommended to create tags for software releases. This is a known concept, which also exists in SVN. You can create a new tag named 1.0.0 by executing:

git tag 1.0.0 1b2e1d63ff

The 1b2e1d63ff stands for the first 10 characters of the commit id you want to reference with your tag. You can get the commit id by looking at the...log.

Log

In its simplest form, you can study repository history using:

git log

You can add a lot of parameters to make the log look like what you want. To see only the commits of a certain author:

git log --author=bob

To see a very compressed log where each commit is one line:

git log --pretty=oneline

Or maybe you want to see an ASCII art tree of all the branches, decorated with the names of tags and branches:

git log --graph --oneline --decorate --all

See only which files have changed:

git log --name-status

These are just a few of the possible parameters you can use. For more, see git log --help

Replace Local Changes

In case you did something wrong, which for sure never happens ;), you can replace local changes using the command:

git checkout -- <filename>

This replaces the changes in your working tree with the last content in HEAD. Changes already added to the index, as well as new files, will be kept.

If you instead want to drop all your local changes and commits, fetch the latest history from the server and point your local master branch at it like this:

git fetch origin
git reset --hard origin/master

Fetching Remote Branch

Source Github

Update:

A new command, git switch has been added that simplifies the effort.

If daves_branch exists on the remote repository, but not on your local branch, you can simply type:

git switch daves_branch

Since you do not have the branch locally, this will automatically make switch look on the remote repo. It will then also automatically set up remote branch tracking.

Original Way:

Checking out a local branch from a remote-tracking branch automatically creates what is called a “tracking branch” (and the branch it tracks is called an “upstream branch”). Tracking branches are local branches that have a direct relationship to a remote branch. If you’re on a tracking branch and type git pull, Git automatically knows which server to fetch from and which branch to merge in.

When you clone a repository, it generally automatically creates a master branch that tracks origin/master. However, you can set up other tracking branches if you wish — ones that track branches on other remotes, or don’t track the master branch. The simple case is the example you just saw, running git checkout -b <branch> <remote>/<branch>. This is a common enough operation that Git provides the --track shorthand:

$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

In fact, this is so common that there’s even a shortcut for that shortcut. If the branch name you’re trying to checkout (a) doesn’t exist and (b) exactly matches a name on only one remote, Git will create a tracking branch for you:

$ git checkout serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

To set up a local branch with a different name than the remote branch, you can easily use the first version with a different local branch name:

$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'

Now, your local branch sf will automatically pull from origin/serverfix.

If you already have a local branch and want to set it to a remote branch you just pulled down, or want to change the upstream branch you’re tracking, you can use the -u or --set-upstream-to option to git branch to explicitly set it at any time.

$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.

Useful Hints

log

General

git log - shows commits.

Commit diff between branches

2 dots:

Suppose you are on myBranch, and you want to see only changes SINCE branching from master.

git log --oneline master..myBranch

3 dots:

The three-dot version gives all changes from the tip of master to the tip of myBranch

git log --oneline master..myBranch

Reflog

Source

Reference logs, sometimes known as "reflogs" keep track of when the tips of branches and other references in the local repository are modified. Reflogs can be used in various Git operations to specify the previous value of a reference.

git reflog <subcommand> <options>

The git reflog can be found in the “.git” directory under the following paths:

.git/logs/refs/heads/

.git/logs/HEAD

.git/logs/refs/stash #if stash has been utilised

Default (git reflog):

git reflog show

Ouptut:

82cdf5f (HEAD -> download_buttons) HEAD@{0}: merge develop: Merge made by the 'ort' strategy.
81fade0 HEAD@{1}: checkout: moving from develop to download_buttons
8b575df (origin/develop, origin/HEAD, develop) HEAD@{2}: pull: Fast-forward
f55e5cc HEAD@{3}: pull: Fast-forward
2b8de96 HEAD@{4}: checkout: moving from manual_comp_create_queue to develop
eca5272 (origin/manual_comp_create_queue) HEAD@{5}: commit: remove debug statement
c035cbe HEAD@{6}: commit: undefined calendar var in initial phase creation

Gitk

If you want a built-in git GUI, use:

gitk

Use colorful git output:

git config color.ui true

To show log on just one line per commit, use:

git config format.pretty oneline

Use interactive adding:

git add -i

Clone Single Branch

Courtesy of stackoverflow

git clone -b <mybranch> --single-branch <git-url>