Basics

Git is a development version control tool. Instead of referring to the various Git cloud platforms (such as GitHub, GitLab, Bitbucket or others), we will use the generic term GitSmeg.

Get Git Access

You need access to your organization’s GitSmeg repositories. You may have to ask your local Git administrator for access.

Setup Your GitSmeg Credentials

Important

When you start out, make sure to setup your github credentials and identifying username and email. This is to assist your team in tracking and documenting development history:

git config --global user.name "Jane Smith"
git config --global user.email "janesmith@acme.com"
git config --global push.default simple
git config --global init.defaultBranch main
git config --list  # Print default settings
This will modify your ~/.gitconfig file with those values.
See git-config man page: Search push.default for more details

Clone a Repo

To clone (download) a repository from the web:

  • Find the repo online and get the code string.

  • Copy that string. e.g., “git@github.com:acme/mousetrap.git”

  • Pull a repo down with “git clone”

[bash]: git clone git@github.com:acme/mousetrap.git

  - or for https -

[bash]: git clone https://github.com/acme/mousetrap.git

Changing Branches

  • Change branches with checkout. Try these examples:

    [bash]: git checkout develop
    [bash]: git status
    [bash]: git checkout -b feature/area51
    [bash]: git status
    [bash]: git checkout -
    [bash]: git status
    

Committing Changes

Once changes are made you must commit (and push) changes to safely store them:

  • Change branch to “feature/area51”, change stuff, push:

    [bash]: git checkout feature/area51
    [bash]: vi conf.py     # Make changes to file, write, exit editor
    [bash]: git commit -a  # In the editor, make commit message, write, and exit
    [bash]: git push       # Pushes changes up to GitSmeg
    [bash]: git log        # Inspect the change history
    

Typical Workflow Scenario

The typical workflow for any changes to files is:

  • Create a new branch

  • Add, change, delete files from the branch

  • Commit your changes

  • Push your changes

To create new branch:

git checkout -b branch_name

To add new files:

[bash]: git add -a abc.py def.py
[bash]: git add -A folder  # (adds and removes files from tree)

To commit all changes execute:

[bash]: git commit -am "Message that explains changes"

To finally push up your changes to your repo upstream:

[bash]: git push

New Repo Workflow Scenario

  • Go to GitSmeg website

  • Create an empty repository in the GUI, and get the repo URL

  • Now on your workstation, clone the empty repo:

    [bash]: git clone https://github.com/acme/bogus.git
    [bash]: cd bogus/
    
  • Start writing your code, make files.

  • Add files to your repo and push:

    [bash]: git add -A
    [bash]: git commit -a
    [bash]: git push
    [bash]: git status
    .... ....
    .. Already up-to-date ..
    

Merging Branches

Once you are satisfied with work done in develop, merge it into master.

  • First change branches from develop to master:

    [bash]: git checkout master
    

Now things are as before with master in its original state.

  • Now you want to merge from develop:

    [bash]: git merge develop
      Updating 1530600..2873dc4
      Fast-forward
      .gitignore                             |    2 +
      Makefile                               |   11 +-
      ...
    
  • Now you must push these changes up to your GitSmeg:

    [bash]: git push
      Total 0 (delta 0), reused 0 (delta 0)
      To git@github.com:acme/mousetrap.git
      1530600..2873dc4  master -> master
    

Delete Unwanted Branches

If you want to eject unwanted branches from your repo, make sure to read the git-branch docs and the warnings about being fully merged (–delete option).

To remove a local branch:

git branch -D <branchName>

To remove a remote branch:

git push origin --delete <branchName>

Synchronizing Local Branches and References: Pruning

Sometimes you’ll have a junkyard of old remote branch references that have been long deleted on the hub. You can synchronize them with fetch:

git fetch -p

Revert a Branch to a Prior Commit

git revert will create a new commit that will undo what the prior commit(s) have done and put that into your history. It gives you a log of your undo.

Resetting a Branch to a Prior Commit

  • git checkout feature/area51

  • Identify the number of your last “good” commit:

    git log
    (grab the good commit number: e3f1e37)
    
  • Reset your feature/area51 to that commit level:

    git reset --hard e3f1e37
    
  • Push it up to GitSmeg:

    git push --force origin feature/area51
    
  • Test the diff between local and remote: Should show nothing:

    git diff feature/area51..origin/feature/area51
    

Comparison of Git Branches

  • Show only relevant commits between two git refs:

    git log --no-merges master..develop
    

Avoiding Many Small Commits

You can make as many small changes as you like and still have a clean single commit by using git’s amend flag on your commit:

git commit --amend
(make your commit message)
(write/quit)

Every time you make a new commit in this way, you get the benefit of small incremental changes and a clean commit log. If you have already made a mess of things you can try the next technique to Squash your commits.

Squashing Multiple Commits

This allows you to take a lot of many small commits (and their messages) and convert them to a single coherent commit. It keeps the history clean and clear.

In order to do this safely, we recommend only doing this in a feature branch (based on develop) that is not being shared.

Version I: Squashing Against a Prior Commit

Background: You created a branch and made some commits. You want to squash all your small commits into a single unified commit, starting that the root of your branch. The commit just BEFORE your changes is abc123def456.

  • From your feature branch: If you have made several commits starting from (and not including) commit abc123def456, you can squash all your commits with a rebase:

    git rebase -i abc123def456
    
  • When it shows you your commits:

    pick 01d1124 Adding Goods
    pick 6340aaa Moving my period
    pick ebfd367 Hyde has become self-aware.
    pick 30e0ccb Make my typo nice.
    

    edit this to become:

    pick 01d1124 Adding Goods
    squash 6340aaa Moving my period
    squash ebfd367 Hyde has become self-aware.
    squash 30e0ccb Make my typo nice.
    
  • Now you write this out and to fix-up the commit logs in the next screen. Do this by changing to a single unified commit message:

    Feature ACME-1234: Adding Goods
    
    * Moving my period
    * Hyde has become self-aware.
    * Make my typo nice.
    

    then write it out.

  • Now you have to force push, because now git is confused:

    git push -f
    

Version II: Squashing Against a Major Branch

  • From your feature branch, do a rebase with the -i flag:

    git rebase -i develop
    
  • When it shows you the multiple commits, change command in commits after the first “pick” to “squash”. Thus this:

    pick 01d1124 Adding license
    pick 6340aaa Moving license into its own file
    pick ebfd367 Jekyll has become self-aware.
    pick 30e0ccb Changed the tagline in the binary, too.
    

    now becomes:

    pick 01d1124 Adding license
    squash 6340aaa Moving license into its own file
    squash ebfd367 Jekyll has become self-aware.
    squash 30e0ccb Changed the tagline in the binary, too.
    
  • Now you write that out and it will ask you to fix-up the commit logs. Do this by changing to a unified commit message:

    # This is a combination of 4 commits.
    # The first commit's message is:
    Dr Jekyll's final revisions to persona.
    
    - Add that license thing
    - Moving license into its own file
    - Jekyll has become self-aware.
    - Changed the tagline in the binary, too.
    
  • Once you write that out, you need to push it up with force flag to rewrite history:

    git push -f
    
  • If you have already pushed it up prior to this, or even created a Pull, your upstream commits and pulls will get replaced with the unified commit.

Git Stash: Stashing Modified Files

Git’s stash option allows you to put modified files into a temporary holding area. The usual scenario is to stash your mods away then pull from the origin, and then re-place your stashed files into the tree. Then you can push the results back up to origin. Here is a possible workflow:

.... you made changes to develop, but you'd rather it be in a feature....

[bash]: git stash
 > Saved working directory and index state WIP on develop: e38b798 post
 release: 1.0.1 -> 1.0.2dev.....

[bash]: git checkout -b cleanup_on_aisle_7
 > Switched to a new branch 'feature/cleanup_on_aisle_7'

[bash]: git stash pop
.... now you have your new mods overlaid ....
.... make whatever other modifications ....
.... now you can commit all your mods ....

[bash]: git commit -a

[bash]: git push

Cool Ways to Show Logs and Diffs

Often you will need to see your logs and compare different versions:

git log
git log --oneline --graph --decorate --all
git diff
git diff fe492a1 #(between current and some other node)
git diff be158f6 aee7163 #(between two nodes)

Git Warnings and Errors

  • You may you get this warning when trying to push a new branch to origin:

    [bash]: git push
    fatal: The current branch develop has no upstream branch.
    To push the current branch and set the remote as upstream, use
    
        git push --set-upstream origin develop
    

    Although usually safe to follow the suggestions, use caution.

References