My Cheatsheet on git

Home

$ git init
$ git config --global user.name "John Smith"
$ git config --global user.email john.smith@cisco.com
$ git add switch.cfg
$ git commit -m "Initial commit"

$ git remote add origin https://github.com/<user>/<repo>
$ git remote -v

$ git push local main

$ git pull

1 SCM and VCS

You can place content in source code management (SCM) such as git. Version control is synonymous with SCM. SCM is also called software configuration management (incorrectly in my opinion). version control is also known as VCS (version control system)

2 Version Control Systems

There are many. I have used RCS in the past, but since Linux Torvalds wrote git, it's simple and powerful features have made it the defacto standard for version control.

VCS manages changes to a set of files, keeping a history of all those changes. VCS keeps these changes in a local or remote directory called a "repository". github.com is one such, very popular, repository. There is a third type of repo called a distributed repo. These three vcs are called local vcs, centralized vcs, and distributed vcs

3 Benefits of version control

  • collaboration
  • accountablity and visibility (can blame someone)
  • isolation while building new features (will need to merge later)
  • safe backups and restores
  • work anywhere where you can get access to the repository

4 The git model

Git models history as a collection of files and folders within a top-level directory.

For example, given this tree structure on a Linux host:

~tree~ 
  .
  .
  ├── ansible-logo.png
  └── foo
      └── bar.txt

Git labels them as follows:

  • "tree" is a folder so in this case, foo is a "tree", "." is a "tree" and in fact the root of the tree is a "tree"
  • "blob" is a file, so in this case, bar.txt is a "blob"

So trees can contain blobs and other trees. But blobs cannot contain trees.

The top level tree is the directory that is being tracked by git.

The history gives a the complete folder structure at any given point in time. Now, you might think that the version history is just a linear sequence of snapshots. But git is more sophisticated than that. It models the history as a directed acyclic graph to model the history.

4.1 Directed acyclic graphs

Each snapshot has some number of parents. Each parent may have more than one child.

git-diagram.png

Figure 1: git Directed Acyclic Graph

5 git datastructure

git has a model of history using pseudo code. It has three types, blobs, trees, and commits. All git objects are one of these 3 types.

type blob = array<bytes>  # an array of bytes.  i.e. it is a file.
type tree = map<string, tree | blob >  # a folder, which is a mapping from
                                       # the filename or dictory name to the
				       # contents, which is either another
				       # tree (i.e. a subtree) or the file

type commit = struct {        # a snapshot, that is what git calls a commit.
     parents: array<commit>   # an array of commits
                              # not the actual commit, but pointers to the
			      # commits.
     author: string           # more metadata for this commit
     message: string
     snapshot: tree           # is the actual contents of the commit which
     }                        # is the snapshot itself, ie the top level tree
                              # corresponding to a particular commit.

This psuedo code comes from this youtube link.

5.1 How git stores this history in its own disk datatore?

git defines an object, which is a blob, or a tree, or a commit.

All objects are content addressed, they are a set of objects maintained as this content addressed store. You put it into the store via a key which is the hash of the object. i.e. a sha1 hash of the object itself.

  • remember a sha1 is a 160 bit hash (Hexadecimal strings, 40 characters

long) (40 hex characters is 20 bytes which is 20*8bits or 160 bits.)

In pseudo code, from MIT missing lecture video:

type object = blob | tree | commit
objects = map<string, object>

# git stores each object by first storing it's hash (id) and then the
# object itself, as follows:
def store(o)
   id = sha1(o)  # the sha 1 hash of the object o
   object[id] = o   # this actually stores to disk i.e. saves the object[id]

# to retrieve an object, you need its id. so a retrieval 
def load(id)
   return object[id]

git doesn't actually store the whole tree or commit in each object. Rather it stores pointers to the object. So you are not duplicating all these commits and trees and blobs, just pointing from one to the other to the other.

So summariziing:

Git's on-disk datastore is a content addressable memory store where objects are addressed by their unique hash.

6 immutablitiy of git

Becauase all git objects reference previous git objects in the tree, it does not make sense to start changing these earlier objects. That is why the git datastructure is immutable. You cannot change it. You can only add to it.

You can give up all the previous changes and create a brand new git database through the use of the git init command. That will create a new git structure based on the directory where you issue the git init command. (you may want to save the .git directory in some backup location before doing this.)

6.1 references are commutable however.

so you can change a reference "fix bug 7" from one commit to another, but you don't change the commit itself. The references can point to particular nodes in a graph. and You can change them at a latter time.

7 Git in 3's

Git is organized in threes, states and stages.

  • three states and
  • three stages

7.1 git files in one of three states

A file can be in one of three states:

  1. modified file has changed but has not been added to the staging area yet
    • in both cases the command git add filename transitions it to 2)
  2. staged file has been added and ready to be committed to the repository
    • the command git commit transitions it to 3)
  3. committed file is saved in local repo (.git directory)

If you create a new file in a directory that is under git control, that file will not yet be added to git. It will be in the "normal" space, and appear as a UNTRACKED file in a git status output. This is a very similar state to the modified state, in that git is not doing anything to these files.

7.2 git's 3 stages

Files can be in (1) the repository, (2) in a staging area, or (3) in a working directory.

gits-3-stages.png

Figure 2: Git and 3's

7.3 git staging (basically the working directory)

git has a concept of a staging area. Any changes added to git, stay in the staging area. You can redo changes, make more changes etc to any files. They still stay in the "staging" area. You can then decide what changes to include in the next snapshot that you create. git status will tell you what files will NOT be included in the next snapshot by saying "untracked files".

The files that are "added" to git are in the staging area. The directory where you are working and editing files is called the working directory. This is NOT to be confused with the staging area.

8 git repository

On a local machine this is in fact the whole .git directory. So you will most likely have several, half-a-dozen local repositories.

9 master (a reference)

You can think of "master" as a pointer to the most up to date version of you project. __ "master" is a reference. It is created by default when you create the repository, i.e. when you type git init. By convention it refers to the main branch of development. i.e. the most up to date version of your project.

Master is a reference. It is a pointer that is updated to point to later commits as they are committed. ha ha But true.

9.1 "head" is a special reference.

Like 'master' 'head' is a special reference. Head points to the current commit. i.e. where you are looking right now, which might not be the latest most up to date version. "points to" means "is referencing the hash for a commit" Usually Head and master point to the latest commit hash.

These are the human readable names, called references. They are mutable and as the project moves along will change and "point" to different commits.

10 git commits and status

You can commit the staged changes, one at a time, or multiple at a time. You can also commit only certain changes within the file, ignoring other changes. A good reason why is when debugging some code, you scatter many extra print statements to see variables at various stages of your program. Finding the problem and implementing the fix might only take 1 line change. It is convenient to be able to commit just that 1 line change, and ignore all the extra print statments that were only there temporarily to help you find the bug.

(venv-xpress) [161] %git add fortune_cookie.py
(venv-xpress) [162] % git commit -m "changes to DevNet training script"
[master 3d58273] changes to DevNet training script
1 file changed, 14 insertions(+), 3 deletions(-)
(venv-xpress) [163] % git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   ../../env_lab.py
        modified:   ../part1/hands_on_exercise.py

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        ../../env_user.py~
        fortune_cookie_debug.py
        ../../venv-xpress/

no changes added to commit (use "git add" and/or "git commit -a")
(venv-xpress) [164] %

10.1 git commit messages

Either by editor, or all on one line

  • git commit # editor
  • git commit -m "this is my commit message" # all-in-one-line

It is important to write good commit messages. They have several features. Good commit messages follow these principles and are meant to help others, or your future self understand why some change was made. Not to neccessarily describe the change itself, because that could be done by looking at the code itself or a git diff. The message tells you why.

  • short
  • gives motivation, answers the question why?
  • meant for future programmers
  • be consistent in style through the git log
  • be consistent in syntax, wrap margins, grammer, capitalization, punctuation
  • be consistent in content (that is really the same as 2)
  • have consistent metadata, i.e. include tracking ids? change mgt tickets?

Given these rules, a possible git log convention for an organization could be the following:

  1. Separate subject from body with a blank line
  2. Limit the subject line to 50 characters
  3. Capitalize the subject line
  4. Do not end the subject line with a period
  5. Use the imperative mood in the subject line *
  6. Wrap the body at 72 characters
  7. Use the body to explain what and why vs. how
  8. imperative mood is used when saying "Hey you! Fix the bug" Same thing is achieved if you use: "if applied correctly, this change

will fix the bug"

Summarize changes in around 50 characters or less
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of the commit and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); various tools like `log`, `shortlog`
and `rebase` can get confused if you run the two together.

Explain the problem that this commit is solving. Focus on why you
are making this change as opposed to how (the code explains that).
Are there side effects or other unintuitive consequences of this
change? Here's the place to explain them.

Further paragraphs come after blank lines.

 - Bullet points are okay, too

 - Typically a hyphen or asterisk is used for the bullet, preceded
   by a single space, with blank lines in between, but conventions
   vary here

If you use an issue tracker, put references to them at the bottom,
like this:

Resolves: #123
See also: #456, #789

If the change is very straightforward, then a single line is all that is needed, so skip the body. For example: "Fix typo in intro message"

See git log section, re command git log --oneline

10.2 git commit -a

Will add all the files already tracked in to a commit (without needing to add the files before). However new files will NOT be committed with -a

Typically though you probably want to control which files you put in a commit, and NOT add temporary files that you will be deleting later anyway.

10.3 git reset HEAD~1

If you want to revert this commit, you can use the git rest HEAD command. it will remove commit from your local repository and move changes done in that commit to your working directory

11 git Repository on a Local Machine

You can create a git repository in a local folder which can then be used as a source code version control system of the programs stored in that folder. I have been using git like this the most.

11.1 git help

You can alway type git help at any level, for example:

  • git help init
  • git help commit
  • git help add

11.2 git init

This is the first step to run within that folder. It initializes a git branch with all the files in that folder. If the folder is empty (i.e. you are just starting a new project) the git repository will be empty, but if there are some files already in that folder, the repository will already be "checked in" with those files as version 1

11.2.1 git repo

Running git init effectively creates a new repository, for which the slang is called "git repo"

11.2.2 git init on Centos Linux

git init worked, but when I later added files to be committed, I could not actually do the commit. git was complaining to:

(.venv-ansible) ansible@c8host ~/Centos-ansible[343] $
git status
On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

	new file:   hosts
	new file:   playbook.yml
	new file:   playbooks/all-in-one-playbooks-are-listed-here
	new file:   playbooks/ansible.cheat
	new file:   playbooks/dnf-update.yml
	new file:   roles/basic-utils/tasks/all-3.yml
	new file:   roles/basic-utils/tasks/main.yml
	new file:   roles/each-dir-is-a-role.txt

(.venv-ansible) ansible@c8host ~/Centos-ansible[344] $
(.venv-ansible) ansible@c8host ~/Centos-ansible[344] $
(.venv-ansible) ansible@c8host ~/Centos-ansible[344] $
git commit

*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: empty ident name (for <ansible@c8host.zintis.ops>) not allowed
(.venv-ansible) ansible@c8host ~/Centos-ansible[346] $

I had to enter the two git config command, after which everything was fine.

11.3 .git directory

git init will create a new hidden folder, .git If you delete this folder, you will delete all the change history of the programs in the root folder of the repository, but you will NOT delete the programs themselves.

Because of that, git is not by itself a backup of your code. You would need to use a remote (i.e. github) repository to sync up your code to have a backup. If you wish to keep files local only, you have to rely on another mechanism of backup, i.e. time machine that backs up the programs in the main repository as well as the change history that is stored in the .git directory.

You can also zip the folder, and send it to someone to let that person have immediate access to your repository, changes history included. Cool!

11.4 Tracking changes

If you create a new program in the main repository, git will not itself start tracking changes to this program. You can confirm that with git status. You must git add the file which moves the file into the staging area. After which you can commit changes to that file when you are ready. You may have to re-add the file so that your latest changes are committed when it is time.

11.4.1 git status

This will show that you have the new program and it is "untracked".

11.4.2 git add

Adds all untracked files into git. This is called "staging" were we have staged the file before a commit. If a file is changed before it has been committed, git status will show you two files, one already added, but another that is again "untracked". git at this point ignores the latest changes to the file. If you commit, then only the tracked file is committed to git. If you want to include the newest changes to the file, you must add it again, before committing it.

11.4.3 git commit

This command opens up your editor window with the changes about to be committed. You want to edit this file so that you can add a top line that explains what this commit is about. For example, the first time you might say "Initial commit". Then hit esc and then :wq to write the changes and quit. (if using vi)

11.4.4 git commit -m "Initial commit" readme.txt

This bypasses the editor window and adds the "string in quotes" to the top line all in one command.

11.4.5 git log

Shows who changed what, when, i.e. all the git history.

  • git log --all --graph --decorate
  • git log --graph --decorate <filename>

Almost always better to use the --all --graph --decorate options when using git log as it will show you the graph of the git tree. Otherwise, git log will just show the tree as a flat linear list. A more compact display is git log --all --graph --decorate --oneline

To see what other git log options are availble try git log --help.

To see logs of just one file, try: git log --graph --decorate <filename>

11.4.6 git clone

If you do not want to create a new project, but rather just copy a pre-existing project that you found on github or other repository. The git clone is your answer.

When a client machine clones the repository, it gets the full repository without needing to deal with locking, as in a Centralized Version Control System.

After the local repository is cloned from the remote repository or the remote repository is created from the local repository, the two repositories are independent of each other until the content changes are applied to the other branch through a manual git command execution.

Often also used to simply download some git file. You actually download the whole repository that may only contain one file. For example:

git clone https://github.com/kodecocodes/recipes.git

11.4.7 .gitignore

Keep a list of files or file types that you do NOT want included in git version control. Files listed here will be ignored by git

Just list all the files that git will ignore The best candidate there are the emacs backup files # and ~. You can have a .gitignore file in each directory. Does it also look in my home directory? Does it combine the two files?

11.4.8 git ignore globbing patterns

.gitignore uses globbing patterns to match against file names. You can construct your patterns using various symbols:

Pattern Example Matches Explanation
**/logs logs/debug.log You can prepend a pattern
  logs/Tue/foo.bar with double asterisk to
  build/logs/debug.log match directories anywhere
    in the repository
**/logs/debug.log logs/debug.log double asterisk also matches
  build/logs/debug.log files based on their name &
  NOT: the name of the parent
  logs/build/debug.log directory
*.log debug.log usual
  foo.log  
  .log  
  logs/debug.log  
*.log debug.log patterns defined AFTER a
!important/*.log important/trace.log negatting pattern will re-
  NOT: ignore any previously negated
  important/debug.log files
debug.log debug.log patterns match files in ANY
  subdir/debug.log directory
/debug.log debug.log but NOT prepending a slash matches
  logs/debug.log files ONLY in the repository
    root.
logs logs If you don't append a slash,
  logs/debug.log the pattern will match both
  logs/latest/foo.bar files and the contents of
  build/logs directories with that name.
  build/logs/debug.log In the example matches on the
    left, both directories and
    files named logs are ignored
logs/ logs/anything appending a slash matches a
  prod/logs/anything directory (and all files in
    that directory and subdir)
     

See git ls-files section below, for important info on listing ignored and listing untracked files.

To add a file to .gitignore

11.4.9 git ls-files

To list ignored files do:

  • git ls-files . --ignored --exclude-standard --others

To list untracked files do:

  • git ls-files . --exclude-standard --others

If git ls-files shows source.c, then it must already be in the index. This means that it is already tracked, and possibly already committed. If source.c isn't showing up in git status at all, then the file must have been committed.

Try modifying the file to see if it shows up as modified in git status. To really convince yourself that the file is checked in, run

  • git cat-file -p HEAD:source.c

to see the contents of the checked-in file (see git help revisions for documentation about the HEAD:source.c syntax).

11.4.10 git rm

To remove files that you do not need under git version control. git rm only adds the "removal" to the staging area. It does not perform the second step of updating the git repo itself. It also removes the specified files from the working directory. That it does right away.

% git status
On branch master
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	deleted:    pricethis-v0.1.py
	deleted:    pricethis-v0.2.py
	deleted:    pricethis-v1.py

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	pricethis-enumerate.py~

no changes added to commit (use "git add" and/or "git commit -a")

12 git commands are all just manipulations of this graph data structure.

All there is to a git repository are objects and references. They are the two pieces of data that it stores. At a high level all git command-line commands are manipulations of either the references data or the objects data.

git-commands1.jpeg

Figure 3: git commands1

git-commands2.png

Figure 4: git commands2

git-commands3.png

Figure 5: git commands3

git-commands4.png

Figure 6: git commands4

git-commands5.png

Figure 7: git commands5

git-fetch-pull.png

Figure 8: git fetch vs pull

french-git-commands.jpeg

Figure 9: git in french

13 branches

There is a very good explanation of branches, divergent branches and merging them at git-scm.com

git-branching.png

Figure 10: git Branching

In implementation, git branches are just pointers to appropriate commits.

git-pointers.png

Figure 11: git Branching

git branches are independent from each other, with their own histories and commits. They have their own staging area, and their own working directories. When you checkout one branch, the working directory is over-written!!! with the state of that branch's files. You can flip between branches by repeatedly git checkout one branch then the other, back and forth.

13.1 Best practice w.r.t. branches

Whenever possible, one should try using branches rather than updating the code directly in the master branch. That way you can recover from edits that break the code you already had running.

13.2 Best practices in general

The following workflow should be used in Git to be able to apply fixes to your code and develop new features:

  • Never develop new features or apply bug fixes directly to the main branch.
  • Always create separate branch for a new feature or bug fix.
  • Apply frequent merges of the main branch to your feature or bug fix branch to avoid merge conflicts.
  • When the feature or bug fix is ready, merge it back to the main branch.

14 git branch

git branch will display all the available branches as well as the branch currently active. git branch -vv will be extra verbose about it.

git branch covid-19 creates a new branch called covid-19, which points to the same place where HEAD is pointing. At this point HEAD will point to master as well as covid-19. (=HEAD= -> master, covid-19)

git checkout covid-19 will replace the current directory contents with the contents of what covid-19 is pointing to, (which at this point is the same, so no change really) but git log --all --graph --decorate shows us that we are now (=HEAD= -> covid-19, master) ie. that HEAD is pointing to covid-19 which is also the same place where master is.

Now if you start editing and adding files, the changes will be committed into the covid-19 branch, where HEAD is pointing. Master will still be pointing to the master snapshot.

any changes are committed to covid-19. i.e. (HEAD -> covid-19) and (master) is beside the snapshot it was on before. i.e. master stays the same

If we issue git checkout master, the current directory is overwritten with what was in the master commit, and HEAD -> master, Covid-19 is unchanged.

So you can flip back and forth between two developments streams.

  • git checkout master
  • git checkout covid-19

14.1 adding another branch

You can add another branch branching off of master.

  1. checkout master
  2. git branch covid-plots; git checkout covid-plots
    • git checkout -b covid-plots # the above 2 steps in a single shortcut.
  3. git log shows covid-19 where it was before, covid-plots pointing to HEAD and master.

14.2 git log –all –graph –decorate

Read up what each argument does. but useful command!

  • git log --all --graph --decorate --oneline Is another useful ßargument to the git log command.

14.3 git branch plots; git checkout plots

This create a new branch called plots, and then switches into it at once. This can be done in one step:

  • git checkout -b plots

14.4 git branch -d to delete a branch

Make sure you are not on it, and that you have merged any changes you want from that branch.

git branch -d branchname # only deletes branch if it has been fully merged

git branch -D branchname # deletes branch using force (whatever the merge

15 git merge (opposite of branch)

After you have 1 or more branches and you want to re-combine them into the master train, you use the git merge.

  1. git checkout master # to git you back on the master train.
  2. git log --all --graph --decorate --oneline # just to take bearings
  3. git merge covid-plots If there are no merge conflicts, you are done. However if conflicts arise between master and covid-plots, a human has to decide what changes take precedence and what changes will be discarded. You will have unmerged paths when running git status You have to edit the file(s) that have conflict, to resolve those conflicts, and use git add for each of those files, and commit them again. Then you are done.
  4. git merge --abort if you get messed up, and do NOT want to do the editting at this moment. (editting of the unmerged paths that is)
  5. git mergetool # start comparing what changes over-write each other.
  6. if you configure git properly, you can tell it to use vimdiff every time you run git mergetool. OR, you can manually run vimdiff
  7. vimdiff
  8. git merge --continue to proceed where you left off to make the human conflict resolution change.

16 git merge and how it modifies the directory and the HEAD and master references

A good explanation is available from git.scm.com

17 git checkout ( i.e. move the HEAD pointer)

In a centralized version control system, only one person at a time can work on a particular file??? That seems contradictory to git merge. So what really happens is that a user checks out a branch, then the user can work on that branch independently.

git checkout moves the head pointer AND modifies the current directory so that it matches exactly the "snapshot" or commit that was checked out.

Also, you can run git checkout filename and that wipes out any changes to the filename in the directory, and replaces it with the contents of the filename at last commit. Kind of good for a "oops daisy"

If you run git log –all –graph –decorate after a checkout, you will see that HEAD is no longer pointing at MASTER. It is pointing to the Checked out commit hash.

So git checkout -b 42bf7a2 moves the HEAD to 42bf7a2 and later, when you want to go back to MASTER, simply git checkout master You could also git checkout -b xxxxxx where xxxxxx is the hash of the master commit.

git checkout specifying a new filename will create a new branch from the branch you are currently active on. So your workflow would be like this:

  • git branch # to see if the branch isn't already there
  • git checkout mynewbranch # create mynewbranch

17.1 unified diff output meaning

When run in unified diff mode with the -u option you get:

First two lines are

--- from-file from-file-modification-time
+++++ to-file to-file-modification-time
--- from-file    from-file-modification-time
+++ to-file        to-file-modification-time

Next come one or more chunks of differences with this syntax:

@@ from-file-line-numbers to-file-line-numbers @@
line-from-either-file
line-from-either-file

If a chunk and its context contain two or more lines, its line numbers look like ‘start,count’. Otherwise only its end line number appears.

The lines common to both files begin with a space character.

The lines that actually differ between the two files have either a + or a - characters in the left print column:

‘+’
A line was added here to the first file.

‘-’
A line was removed here from the first file.

Here is a larger example:

$ diff -u 1stfile 2ndfile
--- 1stfile     2020-05-22 11:32:48.000000000 -0400
+++ 2ndfile     2021-02-02 16:20:15.000000000 -0500
@@ -1,12 +1,10 @@
 # The first file has twelve lines in this block
 # The second file ends up with only 10 lines in this block
 #
-# macOS Notice
+# macOS Notice  This line was changed on the 2nd file.
 # 
 # This file is not consulted for DNS hostname resolution, address
 # resolution, or the DNS query routing.
 #
-# This line is in the first file, but will be removed in 2nd file
-# This line also will be removed in 2nd file.
 #
@@ -17,3 +15,5 @@
 nameserver 208.67.220.220
 You can get so confused that you'll start in to race
 down long wiggled roads at a break-necking pace
+#  And        # Two new lines added to second file,
+# On and on . # hence now we are looking at a block of 5 lines in 2nd.

18 git remote repositories

ls .git is your own git repository. git remote lists all of the remote repositories associated with this local repository. You can simulate a remote repository just by creating a different directory and setting that up as if it was remote. In fact, you can call your directory "github" or "gitlab" or just "remote"

Let's try with 'gitlab'.

From the git master directory:

  1. cd ..
  2. mkdir gitlab
  3. cd gitlab
  4. git init --bare You almost never use --bare, just read up on it later.
  5. git remote # still have nothing there, so let's add that directory
  6. git remote add zp-origin ../gitlabzp zp-origin is my NAME of the remote.

18.1 git push

will send local changes to the remote repo

  • git push <remote> <local branch>:<remote branch>
  • git push zp-origin covid-19:covid-19

this sends the changes from my local branch to the remote server, on that specified branch.

git push zp-origin master:master

Every time you want to get the remote repo updated with your latest changes you could run git push zp-origin master:master again. However….. git has a shortcut for this and it is by saving this parameter permanently:

git-push.png

Figure 12: Changes after a git push
  1. git branch –set-upstream-to zp-origin/master

    This lets you type git push rather than git push zp-origin master:master.

    git branch -vv

  2. git log –all –graph –decorate –oneline

    will now show you a third reference, being the remote repo + remote branch

18.2 git fetch

So if you have cloned a remote repository and then want to refresh any new files or changes from that remote repository, simply git fetch. This will fetch any new changes from the default repository, in our case zp-origin.

The git fetch will download the remote repository files into your local repository, NOT your current working directory, so there is no danger of overwriting files in your working directory.

If you have several remote repositories, you can git fetch <remote>

After a fetch, your local master reference will NOT have changed, so if you like the new (more recent) changes you downloaded from the remote repo, you can run git merge to move your local master reference up to the latest new changes you just downloaded.

18.3 git fetch;git merge combo

The git fetch;git merge combo happens so often, git has made a shortcut for this, called git pull. Actually it is more like a

  • git fetch
  • git checkout
  • git merge

18.4 git pull ==> same as git fetch;git checkout;git merge

You will see that you are "fast forwarding" your local repo to be up to date with the remote.

From developer.cisco.com this info on git pull

Local copies of the Git repository do not automatically get updated when another contributor makes an update to the remote Git repository. Updating the local copy of the repository is a manual step. Git provides a git pull command to get updates from a branch or repository. git pull can also be used to integrate the local copy with a non-parent branch.

  1. The local repository (.git directory) is updated with the latest commit, file history, and so on from the remote Git repository. (This is equivalent to the Git command git ~fetch~.)
  2. The working directory and branch is updated with the latest content from step 1. (This is equivalent to the Git command git merge) So, you are in danger of files in your working directory being overwritten.
  3. A single commit is created on the local branch with the changes from step 1. If there is a merge conflict, it will need to be resolved.
  4. The working directory is updated with the latest content.

18.5 Remote git clone

You can download a *entire* remote repository with all the files in it down to a local repo by by using the git clone <url> <folder name> So in our simulated remote repo case we can run git clone ./gitlabzp testing which could be "cloning from the remote repo into a directory called testing"

So your local repository becomes truly like a clone of the remote repository. Usually done when you join a project that has been ongoing by remote users. Or, when you want to simply create a local repository for learning purposes, but want to start with a bunch of public code.

18.6 git config

To set up your personal preferences. or just vim ~/.gitconfig file (accomplishes the same as git config.)

You can also enter config commands from the command line as follows:

  • git config --global user.name "<user's name>"
  • git config --global user.email "<user's email>"

This is a requirement. Git uses this info in git blame

18.7 git clone –shallow

can be fairly big, but –shallow will only get you the master.

18.8 git add -p

This will interactively check each line of changed text to see if you want to include that in the commit. Perfect for the times you have a bunch of temporary debug print statements that you don't need to commit. git diff before you git add -p will also show you all the possible changes before you interatively stage each edit individually. so 'y' or 'n' for each line and you are done.

18.9 typical git add -p workflow:

  • git diff
  • git add -p
  • say 'y' to a few changes, 'n' to a few changes
  • git diff --cached # to see what changes are due for a commit
  • git commit # only the 'y' changes are committed
  • git checkout filename <see note>

<note> the checkout is needed because The local file still has the rejected changes, so we would need to discard them, by overwrittig the direcotry contents with the newly committed git version

18.10 git blame

find who made the change in a give line, find who made the commit and which was the commit that saved that line You can then see the hash (id) of the commit and then git show 252abacef to see all the detail of that change.

18.11 git stash and git stash pop

temporary save some editing changes without committing them. Suppose that you are in the middle of development, and you have not staged any changes yet because your code is not ready to be committed. You are assigned to a more urgent request, so you have to focus on other files, but you do not want to lose changes that you have done so far. You can use the git stash command to temporarily save your current changes. Once you finish with other work, you can then use the git stash pop command to retrieve your previously saved changes.

  • git stash list to show you what's going on.

18.12 git bisect

Let's you automate going back through each commit to find when a version broke some function that was working before.

19 Examples of git clone

Cloning into 'coding-skills-sample-code'...
remote: Counting objects: 201, done.
remote: Total 201 (delta 0), reused 0 (delta 0), pack-reused 201
Receiving objects: 100% (201/201), 55.72 KiB | 0 bytes/s, done.
Resolving deltas: 100% (111/111), done.
Checking connectivity... done.
/Users/zintis/bin/python % 
#+END_EXAMPLE /Users/zintis/bin/python % git clone https://github.com/CiscoDevNet/coding-skills-sample-code

this downloaded the code into a folder "coding-skills-sample-code"

similarly you can:
#+BEGIN_EXAMPLE
/Users/zintis/bin/python % git clone https://github.com/datacenter/nexus9000.git
Cloning into 'nexus9000'...
remote: Counting objects: 520, done.
remote: Total 520 (delta 0), reused 0 (delta 0), pack-reused 520
Receiving objects: 100% (520/520), 1.14 MiB | 843.00 KiB/s, done.
Resolving deltas: 100% (176/176), done.
Checking connectivity... done.
/Users/zintis/bin/python % 

This downloaded n9K code into a directory called nexus9000

/Users/zintis/bin/python % lst
total 272
drwxr-xr-x   6 zintis  staff    204  9 Mar 13:15 nexus9000
drwxr-xr-x  38 zintis  staff   1292  9 Mar 13:15 .
drwxr-xr-x  19 zintis  staff    646  9 Mar 13:04 coding-skills-sample-code

On April 2019 I cloned this:

/Users/zintis/bin/python/bin[35] % git clone https://github.com/CiscoDevNet/netprog_basics
Cloning into 'netprog_basics'...
remote: Enumerating objects: 133, done.
remote: Counting objects: 100% (133/133), done.
remote: Compressing objects: 100% (63/63), done.
remote: Total 739 (delta 68), reused 132 (delta 68), pack-reused 606
Receiving objects: 100% (739/739), 368.57 KiB | 6.25 MiB/s, done.
Resolving deltas: 100% (362/362), done.
/Users/zintis/bin/python/bin[36] % 

For detailed developer documentation, please visit https://opennxos.cisco.com/public/api

April 17th, 2019: git clone https://github.com/CiscoDevNet/python_code_samples_network.git

stored in ~/bin/python

19.1 One last real-world example with Duo TFA

/Users/zintis/git-local[10] % cd ..
/Users/zintis[11] % cd bin
/Users/zintis/bin[12] % git clone https://github.com/duosecurity/duo_unix.git
Cloning into 'duo_unix'...
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 2609 (delta 1), reused 1 (delta 1), pack-reused 2600
Receiving objects: 100% (2609/2609), 1023.65 KiB | 1.78 MiB/s, done.
Resolving deltas: 100% (1597/1597), done.
/Users/zintis/bin[13] % 

20 typical sequence of git commands

20.1 git status

should show the file as "modified", under "Changes not staged for commit:"

20.2 git add filename

Also git add -A to add all the files in the local directory

20.3 git reset filename

To undo a git add, before being committed.

20.4 git status

should now show the file under "Changes to be committed"

20.5 git commit

Asks for you to edit a note explaining the changes, then commits them

20.5.1 git commit -m "you can add the note directly on the command line with the -m option"

This is a commit message, so you don't have to enter the editor at all.

20.5.2 git commit -a

This will commit all the files that were already in the git repository and that had changes. New additions will NOT be committed.

20.6 git clone

Will create a local copy of the files in the repository into the local dir.

20.7 git diff

  • A minus ("-") sign at the beginning of the line refers to the state in your local repository
  • a plus ("+") sign at the beginning of the line refers to currently made changes in your actual live file in the directory

git diff filename will show you what has changed in the file specified, compared to the file as saved in the last commit (i.e. snapshot). Or, more accurately, git diff filename compares current filename to the filename pointed to by HEAD. So you can be explicit and say git diff =HEAD= hello.txt

To look at the diffs from earlier commits, you have to specify the hash of that commit i.e. the commit id

20.7.1 commit id

When looking at output from git log, you will see long (x bits long) commit ids. For example: 784f5199 50179894ffee29872faa6e170f4bc76d . The first 32 bits can be used as the short version, when using commands like git diff. For example 784f5199 for the above id can be used as its commit id. (eight hex characters)

git diff will also take extra arguments that are a commit id. So for instance you can see what has changed from the current file compared to the file as of 3 or 4 or n commits ago. git diff *42bcdea8* hello.txt will show difference between the current file hello.txt on disk, and the commit named 42bcdea8.

git log --all --graph --decorate
git diff 784f519 init.el
git diff 42bcea8 init.el

This checked init.el back to two different versions.

Or you can do git diff *42bcdea8* =HEAD= hello.txt which will compare hello.txt from when the commit was 42bc… to what hello.txt was at the commit that the HEAD reference is pointing to (which might not be the MASTER) at this point in time, and also might not be what is actually on hello.txt on disk.

The contents of the actual folder on the disk drive is what git calls a working directory. The staging is what has been added, but not yet committed.

If you do not supply a hash, git diff will run diff comparing the current file to the file saved as where head is pointing. Remember that head is the pointer to the LAST commit. When you start editing a file, that is not yet added to be staged to git, the file can be changed to whatever.

git diff 42f5bc77 =HEAD= filename will compare the difference between that particular commit and HEAD, vs git diff 42f5bc77 will compare to the current file as it is in the directory (which may have had additional edits after HEAD)

git diff 42f5bc77 HEAD filename current filename to version in commit 42f5bc77
   

21 man giteveryday

git comes with man pages, so man git is a good place to start. There you will see that man giteveryday is another good place for beginners

22 github Hello World

Github itself has an introductory Hello World page that shows you the basics of repositories. It does NOT use the command line, but rather a web interface to git.

23 From DevNet Express

Step Action Git command
1 Clone the Remote Repository git clone <url>
    # copies the entire remote repo
2 Create and Checkout a Local Branch git checkout -b <new branch name>
    working directory not changed but
    staging and commits will be onto
    this branch
3 Incrementally Commit Changes git add <new or modified file>
    moves copy of file from working
    dir to the staging area
4 Commit all changes to the repo git commit -m "Commit Message"
    commits all staged files to an
    immutable snapshot

24 Local installation:

which git /usr/bin/git

25 git, fish shell, oh my fish, and bobthefish theme

Keeping a long story short, using the friendly interactive shell, or 'fish' and specifically the 'bobthefish' theme, you can see the status of your git repo at all times from the commands prompt. Here is an example from feb 2020:

git-and-bobthefish.png

Figure 13: Using git with bobthefish

26 other useful git commands

26.1 git show <id>

for example git show 2097655d8d0d1737a0da7f27ff07d78e797c89e8

commit 2097655d8d0d1737a0da7f27ff07d78e797c89e8
Author: Zintis Perkons <zintis@icloud.com>
Date:   Sat May 9 16:38:35 2020 -0400

    Improved the clarity of the internal links section in orgmode.org.

diff --git a/orgmode.org b/orgmode.org
index bf26b8d..005a468 100644
--- a/orgmode.org
+++ b/orgmode.org
@@ -133,32 +133,38 @@
     It can also be specific lines in files, like my python [[file:emacs.org::*Elpy][Elpy in emacs.org]]

 ** adding links from specific =head=ings in other org files
-   When in the target org file, at the chosen link, type
+   When in the target org file, (or in the current file) at the chosen link, type
    ~C-c l~ for "org-store-link", which was previously set in init.el as follows:

but since humans don't like 40 character long names, git creates the concept of "references"

26.2 git cat-file -p <hash>

will give you information of the object that has the key specified (i.e. the hash) For instance you can use git cat-file -p to drill down into the git data structure using this command.

Here's an example

ansible@c8host ~/playground/demo[1027] $
git commit
[master (root-commit) d8235c4] adding hello.txt to a brand new git repository
 1 file changed, 1 insertion(+)
 create mode 100644 hello.txt

ansible@c8host ~/playground/demo[1028] $
git log
commit d8235c40b7e6e78cdfe80b40339d4242ce95581f (=HEAD= -> master)
Author: Zintis Perkons <ansible@zintis.ops>
Date:   Fri May 15 15:15:26 2020 -0400

    adding hello.txt to a brand new git repository

ansible@c8host ~/playground/demo[1029] $
git cat-file -p d8235c4                            <<<<<=========  * * * 
tree 9f5a7a63c2b6f9e5381cf4cfdb03b0ee55da6b9e
author Zintis Perkons <ansible@zintis.ops> 1589570126 -0400
committer Zintis Perkons <ansible@zintis.ops> 1589570126 -0400

adding hello.txt to a brand new git repository

ansible@c8host ~/playground/demo[1030] $
git cat-file -p 9f5a7a63c2b6f9e5381cf4cfdb03b0ee55da6b9e
100644 blob 9075408ae349c4b9df8e277ce0cd31e7c8a83156	hello.txt

ansible@c8host ~/playground/demo[1031] $
git cat-file -p 9075408ae349c4b9df8e277ce0cd31e7c8a83156
hello wlrd

You can use git cat-file -p hash repeatedly to drill down into the tree as deep as you want. Every deeper object return you can cat-file its hash, and keep going. Start with git log to see the most recent changes, and get that hash and off you go.

  1. Sample exploration of my ~/eg repository using git log and git cat-file
    /Users/zintis/eg/LINUX[72] % git log
    commit b943efc166be5a824735475c474ad1e640799878 (=HEAD= -> master)
    Author: Zintis Perkons <zintis@icloud.com>
    Date:   Thu Jun 25 17:40:34 2020 -0400
    
        Tweaks made during OPS335 week 1 to week6
    
    commit 7962dee55fca0bdf5da21782736877da83e6baff
    Author: Zintis Perkons <zintis@icloud.com>
    Date:   Mon May 11 00:28:14 2020 -0400
    
        More on ansible and varied minor updates to existing outlines.
    
    commit 4104e28e081d0f14e2ee59dfa03b61dc83f73e16
    Author: Zintis Perkons <zintis@icloud.com>
    Date:   Tue Apr 14 01:19:44 2020 -0400
    
        End of OPS335 course in April 2020  with changes in bind, mail, samba
        tar and CentOS networking
    
        .
        .
        .
    
    commit ca8a3b21b5331402b6fc61c5269733c0f97b920f
    Author: Zintis Perkons <zintis@icloud.com>
    Date:   Tue Mar 10 13:44:03 2020 -0400
    
        Deleted mailx.org
         Please enter the commit message for your changes. Lines starting
        .
        .
        .
        .
    
    /Users/zintis/eg/LINUX[73] % git cat-file -p ca8a3b21b5331402b6fc61c5269733c0f97b920f
    tree 4ae3e7e0fb2d77e3188fc36336a12f144d5924bb
    parent e859d7eb65a8f8b3e5402e9e71e5fdf04c9097f9
    author Zintis Perkons <zintis@icloud.com> 1583862243 -0400
    committer Zintis Perkons <zintis@icloud.com> 1583862243 -0400
    
    Deleted mailx.org
     Please enter the commit message for your changes. Lines starting
    
    /Users/zintis/eg/LINUX[75] % git cat-file -p 4ae3e7e0fb2d77e3188fc36336a12f144d5924bb
    100644 blob cfb28e8de267e0d9b8f842808b994f32e729ebd5	.gitignore
    100644 blob d9d338f677e28b4c63eaa2a7000019e5684a46ed	CentOS-network.org
    100644 blob 966924a5e1cb789e1632d74337a5d26eb6a23007	CentOS.org
    100644 blob 4c35c766526516ef5f24438d0fad2e1f14050731	LSCOLORS.org
    100644 blob d7b002cf9afdf627fe47cf80d74a09a69f7bc247	VM-settings.org
    100644 blob 1bc32d0c70c4b9d1ba502dc07ba7c086eae1fb15	apache.org
    100644 blob a11e92d8403b4bfafb05b6c6a5ffa8a2ddc02aea	bash-scripting.org
    100644 blob 34734ba5395ee8e3138ae21376f90ee0c4812aff	bind-cheat-ops335.org
    100644 blob 305cf1de2f3faa132b3fff67c38525f590a2c3ea	bind.org
    100644 blob 492adf2503463d79a6751549123107ddd1be632c	checkseq.sql
    100644 blob 1f577a2f6af117533c1a2f0364ad5931ad7ff55b	cron-backup.org
    100644 blob 228bfdae697a867e0fc127c749dcdd08a529138b	dig.org
    100644 blob c2dbd392aedc0e0557bdae6a38d9fba0ec69ac1a	dovecot.error
    100644 blob 1056bb81528033896132aa2569f947cae0e676e7	eg-iptables.org
    100644 blob 7fa6de9ce58c97aeada951a3ff0600e60e7287ce	fish-cheat.org
    100644 blob 7ec6277c47b27a84d9186f8ed21c3fe742a949e4	fish.org
    100644 blob b18eff74cb8843db057f4734299c7ca40217756f	fusion.org
    100644 blob 62d585f67ed140e81538bdb1dfe7e9096866f483	=head=ers.org
    100644 blob 0e3828898aed3608ade30b903b76762f09d14825	holdme.org
    100644 blob 2375b802d72264de3dfd966fce1540f1cbd30dc7	html-forms.org
    100644 blob 0bcf663bfa7ec79324ac27440836c6684fead8af	iptables.org
    100644 blob 834e1126d3bfcb8bf3cd4ecd2e1621fda6aede65	kvm-install-log.org
    100644 blob b701d6ed6ca89b1f74d85f82b5e85799c19f4692	kvm.org
    100644 blob 74622583fd620eb2542bfad7a9dc349f96f08cf4	lab1-net-config.org
    100644 blob 72c63ca9f90d01f1901a89485ce0be61ee270b7d	lab1-static-ip.org
    100644 blob f294c8b424557225e3cae1a78b6c72c4a24cc111	linux.org
    100644 blob 7cc0ed7c26c3c0db2696b2c07843cd409c06f533	mailx-postfix-dovecot.org
    100644 blob 6ce7eabbf6b11f2c3530cf16436771a6040ebf3c	mysql.org
    100644 blob f95415b4125b826cdec1fecff4af37823c892a4a	nat-iptables.org
    100644 blob cac5fbace1e1cea6b227aa48ad570eff0c1082f6	netstat-tulpn
    100644 blob 44dfe8051db1fa822070c732fdb44f5203ff6061	nmcli-ifcfg-table.org
    100644 blob af4d75c86a3313d3460422c3783d8f9e9a66f36c	nmcli.org
    100644 blob 8bb3393635976f7ae46939f36e86c03f2242ca65	rsync.org
    100644 blob 93004f6343def4f33f26162ccd5ea9e0c4c5c4a3	Samba.org
    100644 blob be710b88b58fd37fe7c57a90fc61fa003b192c81	selinux.org
    100644 blob d947ee05defa6afdb8e266d8052419bfd8b96d79	seneca-bash.org
    100644 blob 9e698e4284ef8a39d584c5ea82cbae19bc8c3c09	Slang.org
    100644 blob 19ffbf89e8873e047e34eb205a5678fad8284f8e	tmux.org
    100644 blob f4e9687fa045ec12bcc0b6fcbc2f7c3260067a39	top.org
    100644 blob bbb5176e859d77ce587130a3c868fda261e0bcd4	trouble-shooting-mysql.org
    100644 blob d6e5211733fe552e47c42518c213e3cdbb9a6a0a	vanilla-etc-named.conf
    100644 blob 1736be1845920d029d7157387c126215406722a4	virsh.org
    100644 blob 9abeac87766e026dc340ddcc4acdcce5ae04ea3a	vm1.var.log.messages.mysql.org
    100644 blob f86d9d7899efdc18f8d88baf0d0d46c2605f6f6c	yum-dnf.org
    /Users/zintis/eg/LINUX[76] % 
    
    
    /Users/zintis/eg/LINUX[77] % git cat-file -p 9e698e4284ef8a39d584c5ea82cbae19bc8c3c09
    
    #+STARTUP: content hidestars
    #+TITLE: Unix Special Character Slang
    #+OPTIONS: H=4
    #+OPTIONS: toc:t
    #+AUTHOR: Zintis Perkons
    #+EMAIL: zintis AT senecacollege DOT ca
    #+DATE: <2020-01-17 Fri>
    
    *  Unix Special Character Slang
      When using the command line in Unix/Linux, there are many shortcuts that
      make you efficient.  Talking about command lines to others though is not
      efficient as many of the special characters have 3, 4 or even 5
      syllables, for instance "ex-cla-ma-tion mark" has 5 syllables.  The slang
      for that is "bang", i.e. one syllable.  Here is a cheat sheet on those
      slangs.
    
    
    | Symbol          | Slang                                              |
    |-----------------+----------------------------------------------------|
    | ~#!~            | shebang, sha-bang, hash-bang,                      |
    |                 | #!/bin/env python                                  |
    |-----------------+----------------------------------------------------|
    | ~!~             | bang or ping                                       |
    | ~!44~           | previous 44th line                                 |
    | ~!v~            | previous line starting with 'v'                    |
    | ~!v:p~          | :p  to print the command without executing it      |
    | ~!-2~           | line 2 back                                        |
    |-----------------+----------------------------------------------------|
    | ~!!~            | bang bang                                          |
    |                 | entire previous line, as in: sudo !!               |
    |-----------------+----------------------------------------------------|
    | ~!^~            | bang-hat                                           |
    |                 | previous line first argument                      |
    |-----------------+----------------------------------------------------|
    | ~!*~            | bang-splat                                         |
    |                 | previous line all arguments                       |
    |-----------------+----------------------------------------------------|
    | ~!$~            | bang-buck                                          |
    |                 | previous line last argument                       |
    |-----------------+----------------------------------------------------|
    | ~!$ &~          | bang-buck-snowman                                  |
    |                 | previous line last argument as background process |
    |-----------------+----------------------------------------------------|
    | ~^~             | hat  often as !^ or bang hat                       |
    |                 | previous line substitute delimiter                 |
    |-----------------+----------------------------------------------------|
    | ~#~             | hash                                               |
    |-----------------+----------------------------------------------------|
    | ~*~             | splat                                              |
    |-----------------+----------------------------------------------------|
    | ~$~             | ding or buck                                       |
    |-----------------+----------------------------------------------------|
    | ~/~             | whack                                              |
    |-----------------+----------------------------------------------------|
    | ~\~             | back-whack                                         |
    |-----------------+----------------------------------------------------|
    | ~~~             | skid                                               |
    |-----------------+----------------------------------------------------|
    | ~'~             | tick  or prime                                     |
    |-----------------+----------------------------------------------------|
    | ~`~             | back-tick                                          |
    |-----------------+----------------------------------------------------|
    | ~,~             | tail                                               |
    |-----------------+----------------------------------------------------|
    | ~"~             | dirk                                               |
    |-----------------+----------------------------------------------------|
    | ~%~             | mod or 007                                         |
    |-----------------+----------------------------------------------------|
    | ~vertical pipe~ | pipe                                               |
    |-----------------+----------------------------------------------------|
    | ~&~             | pretzel  or snowman                                |
    |-----------------+----------------------------------------------------|
    | ~?~             | hook                                               |
    |-----------------+----------------------------------------------------|
    | ~@~             | at                                                 |
    |-----------------+----------------------------------------------------|
    | ~(~             | open                                               |
    |-----------------+----------------------------------------------------|
    | ~)~             | close                                              |
    |-----------------+----------------------------------------------------|
    | ~{~             | curly         or brace                             |
    |-----------------+----------------------------------------------------|
    | ~}~             | curly-close   or un-brace                          |
    |-----------------+----------------------------------------------------|
    | ~+~             | plus                                               |
    |-----------------+----------------------------------------------------|
    | ~-~             | dash                                               |
    |-----------------+----------------------------------------------------|
    | ~.~             | dot                                                |
    |-----------------+----------------------------------------------------|
    | ~:~             | double-dot                                         |
    |-----------------+----------------------------------------------------|
    | ~;~             | semi                                               |
    |-----------------+----------------------------------------------------|
    | ~<~             | from                                               |
    |-----------------+----------------------------------------------------|
    | ~>~             | to                                                 |
    |-----------------+----------------------------------------------------|
    | ~[~             | bra                                                |
    |-----------------+----------------------------------------------------|
    | ~]~             | ket                                                |
    |-----------------+----------------------------------------------------|
    | ~!?~            | interro-bang                                       |
    |-----------------+----------------------------------------------------|
    | ~--~            | dunder                                             |
    |                 | from double underscore                             |
    |-----------------+----------------------------------------------------|
    | ~RETURN~        | hammer                                             |
    |-----------------+----------------------------------------------------|
    | ~etc~           | "ett-see"                                          |
    |-----------------+----------------------------------------------------|
    | ~regex~         | "regg-ex" NOT "rej-ex", from "regular expression"  |
    |-----------------+----------------------------------------------------|
    | ~LatTex~        | "lah-tek" not "lay-teks"                           |
    |-----------------+----------------------------------------------------|
    | ~SCSI~          | "skuzzy"                                           |
    |-----------------+----------------------------------------------------|
    | ~kludge~        | "kloodge"                                          |
    |-----------------+----------------------------------------------------|
    | ~fubar~         | "eeffed up beyond all repair"                      |
    |-----------------+----------------------------------------------------|
    | ~foobar~        | "eeffed up beyond all recongnition                 |
    |-----------------+----------------------------------------------------|
    | ~ID-10-T~       | "idiot"                                            |
    |-----------------+----------------------------------------------------|
    | ~://~           | double-dot whack-whack                             |
    |-----------------+----------------------------------------------------|
    | ~emacs !$ &~    | "emacs bang-buck snowman"                          |
    |-----------------+----------------------------------------------------|
    | ~C-r~           | Interactive reverese search. i.e. start typing     |
    |                 | once on desired line, hit TAB to edit line         |
    |-----------------+----------------------------------------------------|
    
    
    

26.3 references

refernces = map<string, string> Where you create a map of the 40 character hex sting to a human readable string.

The strings are what you write in a commit. A reference is also called a "pointer" They are the same thing.

The git tree and commits is immutable, but references are mutable and typically get moved from one commit to another.

26.4 git checkout -b covid-19

This is actually a shortform for two commands:

  1. git branch covid-19
  2. git checkout covid-19
  1. DANGER: git checkout changes the contents of your directory

    When you realize that a checkout of a previous branch it

    1. moves the HEAD pointer back to that earlier commit, and
    2. it must also then change the contents of the current directory, because that is what was 'current' in the older commit.

    As long as you realize that, you will be ok. You can always move the pointer forward (and back to the MASTER) commit using: git checkout master Always check where you are with git log –all –graph –decorate whenever you checkout a commit.

    So any changes that have not been committed to git will be LOST.

26.4.1 git checkout -b

The -b is for branch and it causes Git to create a new branch - and then switch to it.

26.5 Customer references

You can create custom references, which as all other references are, are simply labels attached to a git hash.

27 Under the git repository folder, you can:

27.1 git pull

pulls down the files from the remote git repository

27.2 git push

will send the locally modifed file to the remote git repository

28 magit

diredmode, type M-x magit

Here is a screen shot of my magit page in ~/bin/python/bin

magit.png

Figure 14: magit help screen

28.1 magit-mode commands:

  • <tab> to expand sections OR to expand a file magit-section-toggle
  • hammer magit-visit-thing ?
  • s on an untagged file, to stage it. magit-stage
  • u on a stagge4d file to unstage it. magit-unstage
  • ? show available commands. magit-dispatch q to quit this command display
  • c commit magit-commit
  • c commit magit-commit-create (c is entered twice )
  • b branch magit-branch
  • b b again which is magit-checkout ( b is entered twice )
  • s spin off a branch magit-branch-spinoff
  • l log magit-log
  • l log magit-log-current (l is entered twice)
  • q quit this command (magit-log-bury-buffer)
  • w magit-am
  • w magit-am-apply-patches (w is entered twice)
  • C-c C-c to close the edited commit.
  • SPC show a magit diff magit-diff-show-or-scroll-up
  • 0 show magit diff default magit-diff-default-context
  • 1 show section level 1
  • 2 show section level 2
  • 3 show section level 3
  • 4 show section level 4
  • : magit-git-command
  • < beginning of buffer
  • > end of buffer

So a typical, basic magit workflow is: M-x magit

  • s -
  • s |- or all changes with S
  • s -
  • c c

Make your editing changes, then C-c C-c actually I think it's C-c c Find out which one.

  • $ bring up the details of the error message that just appeared.
  • P push your commit o repository i.e. github
  1. same function on individual files

    If you type s or u against an expanded file, you can stage (or unstage) individual editing changes made within the file. How cool is that?!

28.2 magit status

M-x magit-status (you can set C-x g to map to M-x magit-status by using: (global-set-key (kbd "C-x g") 'magit-status) in your .emacs-d/init file

Refres (g/G) global-magit-file-mode (C-c M-g) magit-dispatch (C-x M-g)

First a good idea to confirm that C-x g is not being used by anything useful C-h k C-x g See help magit status section above.

? will display the magit commands availale. (must be in the magit-status buffer)

M-n/p, j to move around the git status window (next/previous) M-1 or -2 or -3 or -4 , TAB, S-<tab> for visibility

28.3 magit diff options

D C-c C-t (or M-x magit-diff-trace-definition) ?

Once in the diff buffer (D) see toggles such as -U for context lines and -t for hunk refinements which can show you the actual changes made to files between git commits.

git diff –word-diff (is the equivalent git cli command.

In a diff buffer, you can get the function history list as well… That is a list of historic changes to the function you are currently looking at say in python, or in .php or whatever program is being edited in magit mode.

28.4 Logging options in magit

L can toggle dates from absolute dates or days or hours ago.

28.5 magit blame

shows who and when people committed people.

28.6 close the magit buffers with letter 'q' for quit

28.7 magit stage and unstage with a single letter

$ will show you what is happening with your git commands, at any time you want.

  • to show dates when lines or sections were added or changed or deleted from a git file.

28.8 magit commit

c -e allow empty commit -a stage all modified and deleted files –all

  • v show diff of changes to be committed
  • M-n or M-p can browse through past commit messages. (once in the commit buffer) i.e. have hit c

You can also C-c C-a to commit ammend (see docs for all the options of C-c C-a to commit ammend.)

28.9 magit insert git =head=ers C-c C-r, C-c, C-s

28.10 magit branching

b brings up the branch popup. Can create a new branch, or open a branch, can check it out or not in the same command.

28.10.1 spin-off

Let's say you are working on a branch for a couple of hours, making lots of edits, and make a few commits, when you realize, "oops, I should not be making these commits to master!". What to do? If you have made a couple of commits but have not 'pushed' it yet you can:

hit b and s which will spin off a new branch.

It will reset the master head back to where you were when you started, take the several commits you have done today, and spin off new branch, applying those editting changes on this new branch. All automagically. Thus saving your bacon.

You can spin off of any branch.

28.11 Reverting (V)

V VV (magit-revert-and-commit) Vv (magit-revert-no-commit)

28.12 resetting (X)

Read the docs on this. What follows is just to make you aware that this feature exists, and is fairly useful:

Get your mouse onto a recent commit (pick one) and hit: x (and type Head) to revert to that version. ? x (and bring up the log to see what version you want to revert to.)

28.13 Stashing (z)

z z (magit-stash-both) Stashes index and working tree, untracked files included.

Once a change is stashed, you can hit a on the stash (under git status buffer) at a latter time, to then incorporate the change into the branch at that time.

28.14 Rebasing (r)

r i (magit-rebase-interactive) Rebase allows you to resolve conflicts and rewrite history. ** very useful

magit does this very well.

Look at the log, choose a commit where you want to start the rebase. hit r i For instance c76309r then you will see a list of commands. Read them and use C-c C-c to execute what you want with the rebase. - any errors will pop up for you to resolve, or skip and continue forward.

C-c C-k to kill buffer out of this if you do not want to make any changes.

28.15 Bisectting

B B (magit-bisect-start) B s (magit-bisect-run) B b (magit-bisect-bad) B g (magit-bisect-good) B r (magit-bisect-reset)

This is good if you have a bug and want to know when the bug came into being.

Works good if you have been following proper git etticat, hygene and standards, with proper messages left on commits, etc.

28.16 Rebasing

Read up on this.

28.17 others: magit-tag, magit-notes, submodules, worktree

29 Study topics for Cisco 900 cert

1.8.a Clone git clone <url>

1.8.b Add/remove git add <new or modified files>

1.8.c Commit git commit -m "Commit message"

1.8.d Push / pull The git pull command is used to fetch i.e. download, content from a remote repository and immediately update the local repository to match that content. The git pull command is actually a combination of two other commands, git fetch followed by git merge. In the first stage of operation git pull will execute a git fetch scoped to the local branch that HEAD is pointed at. Once the content is downloaded, git pull will enter a merge workflow. A new merge commit will be-created and HEAD updated to point at the new commit.

git push # will send the locally modified files to the git repository git pull # will receive a copy of the latest version from the git repository

1.8.e Branch git branch will display all the available branches as well as the branch currently active. git branch -vv will be extra verbose about it.

git branch covid-19 creates a new branch called covid-19, which points to the same place where HEAD is pointing. At this point HEAD will point to master as well as covid-19. (HEAD -> master, covid-19)

git checkout covid-19 will replace the current directory contents with the contents of what covid-19 is pointing to, (which at this point is the same, so no change really) but git log --all --graph --decorate shows us that we are now (HEAD -> covid-19, master) ie. that HEAD is pointing to covid-19 which is also the same place where master is.

Now if you start editing and adding files, the changes will be committed into the covid-19 branch, where HEAD is pointing. Master will still be pointing to the master snapshot.

any changes are committed to covid-19. i.e. (HEAD -> covid-19) and (master) is beside the snapshot it was on before. i.e. master stays the same

If we issue git checkout master, the current directory is overwritten with what was in the master commit, and HEAD -> master, Covid-19 is unchanged.

So you can flip back and forth between two developments streams.

  • git checkout master
  • git checkout covid-19

1.8.f Merge and handling conflicts git merge is the opposite of git branch. After you have 1 or more branches and you want to re-combine them into the master train, you use the git merge.

  1. git checkout master # to git you back on the master train.
  2. git log –all –graph –decorate –oneline # just to take bearings
  3. git merge covid-plots If there are no merge conflicts, you are done. However if conflicts arise between master and covid-plots, a human has to decide what changes take precedence and what changes will be discarded.
  4. git merge --abort if you get messed up.
  5. git mergetool # start comparing what changes over-write each other.
  6. if you configure git properly, you can tell it to use vimdiff every time you run git mergetool. OR, you can manually run vimdiff
  7. vimdiff
  8. git merge --continue to proceed where you left off to make the human conflict resolution change.

1.8.g diff git diff filename is the same as saying git diff HEAD filename i.e. it compares the current file to the file as it was in the last commit.

Similarly git diff 42bcdea8 main.py will compare the current main.py file to the state it was in the commit identifited by commit-id 42bcdea8

zp: checkout gitcheckout -b <new branch name> git checkout covid-19 will replace the current directory contents with the contents of what covid-19 is pointing to, (which at this point is the same, so no change really) but git log --all --graph --decorate shows us that we are now (HEAD -> covid-19, master) ie. that HEAD is pointing to covid-19 which is also the same place where master is.

1.5 Explain the benefits of organizing code into methods / functions, classes, and modules 1.6 Identify the advantages of common design patterns (MVC and Observer)

mvc.png

Figure 15: Model View Controller

1.7 Explain the advantages of version control 1.8 Utilize common version control operations with Git

  • a Clone
  • b Add/remove
  • c Commit
  • d Push / pull
  • e Branch
  • f Merge and handling conflicts
  • g diff

30 TODO Graphical overview of git processes.

See youtube on git rebasing for idea to document git checkout, branch, merge and rebase.

31 Good overview of git

From stackoverflow.com :

The index / staging-area In a normal Git repository, there are three items of interest with regard to each file.

  1. There is the file's state in your current (or HEAD) commit.
  2. There is the file's state in your work-tree, where you can edit the file with your favorite editor(s), run any normal commands on it, and so on.
  3. There is the file's state in Git's index, also called Git's "staging area".

The staging area is, in essence, "what will go into the next commit you make". Remember that in Git, every commit is a complete snapshot of your work: every file that is staged (or "tracked", i.e., is not an "untracked file") is recorded exactly as it appears in the staging area. Once you make the commit, the staging area matches the commit you just made. It's not empty. It's full of files But a git diff that compares the commit to the index will be empty, because the index and the commit contain the same stored-up work-tree. If you then modify a file in the work tree and git add it, Git replaces the index version with the work-tree version, so that now the index and the HEAD commit differ.

git status and git diff With that in mind, let's take a look at your specific git diff command, and the git diff documentation. You ran:

git diff origin/newbranch – local-path/test.cs The documentation says, in part:

git diff [–options] <commit> [–] [<path>…] This form is to view the changes you have in your working tree relative to the named <commit>. You can use HEAD to compare it with the latest commit, or a branch name to compare with the tip of a different branch.

This means you were comparing the work-tree version of local-path/test.cs against the version in the commit at the tip of origin/newbranch.

The index version of the file has no part in this comparison.

Now let's look at what git status diffs. These quotes are still from the git diff documentation:

git diff [–options] –cached [<commit>] [–] [<path>…] This form is to view the changes you staged for the next commit relative to the named <commit>. Typically you would want comparison with the latest commit, so if you do not give <commit>, it defaults to HEAD. If HEAD does not exist (e.g. unborn branches) and <commit> is not given, it shows all staged changes. –staged is a synonym of –cached.

You can safely ignore the slightly odd notion of "unborn branch" here. This compares a specific commit versus the index. By default, it compares HEAD vs the index. This tells you what would be different in a new commit.

This is the first diff that git status does, to find out what you would commit if you committed now.

We also find, in the git diff documentation, this:

git diff [–options] [–] [<path>…] This form is to view the changes you made relative to the index (staging area for the next commit). In other words, the differences are what you could tell Git to further add to the index but you still haven't. You can stage these changes by using git-add(1).

In other words, this compares the index to the work-tree. Whatever shows up as different here, you could git add to your index, so that it shows up in the first diff that git status runs. Instead, it currently shows up in the second diff that git status runs.

After git status has run these two diffs, it prints any files that showed up in either one, as "changes staged for commit" or "changes not staged for commit"—or, in some cases, both. (For instance, you can add a line to README and stage that, then add another line to README but not stage it yet. Now you have changes from HEAD to index—the first line you added—and changes from index to work-tree: the second line you added.)

Again, git status reports all of these. You say it is reporting nothing: this means that your HEAD commit matches your index, and your index matches you work-tree. There is one special case to consider before we move on.

For untracked files—which are by definition not in the index and not in the HEAD commit—git status normally reports them as "untracked files". This is often more annoying than useful, so you can use .gitignore to tell git status to shut up about these files. Check your .gitignore to see if it is ignoring local-path/test.cs. Presumably it is not, but if it is, that could be the reason you would not see anything.

Putting it all together You also say that if you git diff origin/newbranch – local-path/test.cs, you do see differences. This means that your work-tree does not match the commit to which origin/newbranch points.

From git status (and assuming no .gitignore action), we know that the HEAD and work-tree versions of local-path/test.cs are the same. And, we see that the origin/newbranch version of local-path/test.cs are different. We can therefore conclude that the HEAD version is not the origin/newbranch version: these must be two different commits.

This is a perfectly normal state. Sometimes git status does report something else for this state, though.

Upstream branches Specifically, each branch can have an upstream branch. No branch is required to have an upstream branch, and there is no constraint on the form of the upstream branch if there is one, but every branch can have one—and only one—upstream.

Normally, a local branch like master or newbranch usually has a remote-tracking branch like origin/master or origin/newbranch as its upstream.

The existence of the upstream is, again, optional. But if there is one, git status uses it to compare the current branch against its upstream.

Specifically, if newbranch has origin/newbranch set as its upstream, and if—as we believe we have just proved—newbranch and origin/newbranch differ, git status will tell us that one branch is ahead of the other, or behind the other, or both. (The git status command does this by comparing the commits—not their contents, just the commits themselves—that are reachable from the two branches. I'm not going into any further detail here; for much more on this, see this answer.)

None of this can happen unless the current branch has an upstream set.

You wrote that you ran:

git checkout -b newbranch This form of git checkout creates a new branch, and by default, does not set an upstream for it.

To set an upstream, use git branch –set-upstream-to (see the documentation for git branch for details).

Note that git checkout name, when name does not currently exist as a local branch, but origin/name does exist, will create the local branch name with its upstream set to origin/name. This is very different from git checkout -b, which creates a local branch with no upstream set (and often a different starting value for the branch tip).

31.1 Home