basic git - colorado state university · basic git based in part on ... abstract actual git files...

22
Basic GIT Based in part on the book Pro Git,2 nd Edition, by Scott Chacon and Ben Straub To try out the examples, if you don’t have git on your system, you must install it. If you are running Windows, the easiest thing is to download Git BASH from https://gitforwindows.github.io/ This gives you a terminal window running the bash shell and installs git on your system. Supposedly most Mac and Linux systems have git installed. If not, check out the links from the git book at https://gitscm.com/book/en/v2/GettingStartedInstallingGit To find out if you have git, execute: $ git --version Most slides show sets of command lines, in Courier New font, that you can try. The pictures abstract actual git files and objects, so you won’t be able to match the repository you create with them. We assume you have a $HOME/git directory.

Upload: buiphuc

Post on 25-May-2018

231 views

Category:

Documents


1 download

TRANSCRIPT

Basic GITBased in part on the book Pro Git, 2nd Edition, by Scott Chacon and Ben Straub

To try out the examples, if you don’t have git on your system, you must install it. If you are running Windows, the easiest thing is to download Git BASH from https://git‐for‐windows.github.io/This gives you a terminal window running the bash shell and installs git on your system. Supposedly most Mac and Linux systems have git installed. If not, check out the links from the git book at https://git‐scm.com/book/en/v2/Getting‐Started‐Installing‐Git

To find out if you have git, execute: $ git --version

Most slides show sets of command lines, in Courier New font, that you can try. The pictures abstract actual git files and objects, so you won’t be able to match the repository you create with them. We assume you have a $HOME/git directory.

How Git works

Version 1

File A

Version 2 Version 3 Version 4

File B

File C

A1

B

C1

A1

B1

C2

A2

B2

C3

Time

A “version” is a snapshot of all the files in the project. If files haven’t changed, the snapshot refers to the previous stored copy of the file. Thus, a project looks like a stream of snapshots over time. Everything is check‐summed, and the checksums are used to refer to items.

project tree root

blob sizefirst A

b48a0tree sizeblob b48a0 A

561a2

commit sizetree 561a2

60ff54b$ mkdir $HOME/git$ cd $HOME/git$ mkdir proj1$ cd proj1$ git init$ echo‘first A’ > A$ git add A$ git commit –m “initial file A”

check‐summed file 

The commit object points to the root of the project tree which points to the check‐summed file. (If we had 2 files, the blobs of both would be pointed to by the tree object. If we had another directory with files, a 2nd tree object would be created for the 2nd directory, and the project tree root would point to it, and it would point to the blobs of the additional files.)  

From now on, we’ll just show the commit object on slides. 3

Snapshot 1

Creates repository: .git in current directory (P2):objects/ where all objects are storedrefs/heads names of the most recent commit objects on each branch are storedHEAD location of the most recent commit object on the current branchindex stores staging information

Prints the name of the commit object and information about the commit and creates these 3 objects and stores them in .git/objects. They are named with a checksum, and stored in a directory named by the first 2 digits of the object name in a file named by the rest of the digits

commit object

“checking in” changes

Working DirectoryStaging Area

$HOME/git/proj1/.git(Repository)

$ vim A…..

$ git add A

$ git commit –m ‘added line 2 to A’

Files have 3 stages: modified, staged, and committed.• The Working Directory contains files that are a single checkout of one version of the project.

• Modify files in the Working Directory.• Stage files using ‘git add’ which moves them into the Staging Area.• Commit files using ‘git commit’ which stores the current snapshot in the Repository

$ vim A$ git add A$ git commit –m “added line 2 to A”

$ git checkout proj1

Repository after some changes:

commit sizetree 561a2parentinitial file A

60ff54bcommit sizetree d5b7bparent 60ff54badded line 2 to A

075e235commit sizetree 2e926parent 075e235added line 3 to A

8f64ab5

Snapshot A

Snapshot B

Snapshot C

snapshot pointer

commit object pointer

$ vim A$ git add A$ git commit –m “added line 3 to A”

$ cd $HOME/git$ mkdir proj1$ cd proj1$ git init$ echo‘first A’ > A$ git add A$ git commit –m “initial file A”

$ vim A$ git add A$ git commit –m “added line 2 to A”

These commands create Snapshot A:

These commands create Snapshot B:

These commands create Snapshot C:

File Acontents: 

first Asecond line

first Asecond lineline 3

first A

Branching with Git ‐ preliminaries HEAD

master

commit object

tree root

default branch

60ff54b 075e235 8f64ab5

Snapshot A Snapshot B Snapshot C

Git branches are movable pointers. The default branch is master. The masterpointer moves every time you make a commit. 

There is a special pointer called HEAD that points to the local branch you are working on. 

Create a branch and switch to it

$ git branch testing

This command creates a new pointer, testing, but HEAD stays pointing to master, so that is still your current branch. You created the new branch, but did not switch to it yet.

HEAD

master

commit object (we’ve omitted the snapshots for brevity)

default branch

60ff54b 075e235 8f64ab5

testing new branch

master

60ff54b 075e235 8f64ab5

testing HEAD

$ git checkout testing

HEAD now points to the testing branch, so this is the branch you are now working on.

Make a change on the new branch

$ vim A$ git add A$ git commit –m “adding line 4 in testing”

testing and HEADmove forward

master

60ff54b 075e235 8f64ab5

testing HEAD

6b45237

master file A: 

first Asecond lineline 3

testing file A: 

first Asecond lineline 3testing line 4

Switch back to the master branch

$ git checkout master

HEADmoves back to the master pointer, AND the files in your Working Directory revert back to the snapshot that master points to.

master

60ff54b 075e235 8f64ab5

testing

HEAD

6b45237

Multiple branches

Now the branches have diverged. This brings us to merging. For the next diagrams, we’ll change the names of the commit objects, to just ‘C’ and a number instead of using a portion of the checksum as their name:

master

60ff54b 075e235 8f64ab5

testing

HEAD

6b45237

$ git checkout master$ git branch quickfix$ git checkout quickfix$ vim A$ git add A$ git commit –m “added line 4 in quickfix”

0f7c8ee

quickfix

master

testing

HEADquickfix

C1 C2 C3C5

C4

master file A: 

first Asecond lineline 3

quickfixfile A: 

first Asecond lineline 3line 4 quickfix

testing file A: 

first Asecond lineline 3testing line 4

Another commit on quickfix:

$ git checkout master$ git merge quickfix

Merge quickfix (C6 commit) into master:

C6 is directly ahead of C3 (master that you switched to with the checkout), so Git just moves the master pointer forward. This ‘fast‐forward’ happens when you merge a commit with another commit that can be reached by following the first commit’s history.

master

testing

HEADquickfix

C1 C2 C3 C5

C4

master

testing

HEAD

quickfix

C1 C2 C3 C5

C4

$ vim A$ git add A$ git commit –m “qf line 5”

C6

C6

master file A: 

quickfixfile A: 

first Asecond lineline 3line 4 quickfixline 5 quickfix

testing file A: 

first Asecond lineline 3testing line 4

first Asecond lineline 3line 4 quickfixline 5 quickfix

Another change on the testing branch:

$ git branch –d quickfix$ git checkout testing$ vim A$ git add A$ git commit –m “added line 5 in testing”

$ git checkout master$ git merge testing

Git does a 3‐way merge using the 2 snapshots pointed to by the branch tips (C6 and C7) and their common ancestor (C3).There is a conflict:

Merge to master:

master

testing

HEAD

C1 C2 C3 C5

C4

C6

C7

testing file A: 

first Asecond lineline 3testing line 4testing line 5

master

testing

HEAD

C1 C2 C3 C5

C4

C6

C7

common ancestor

snapshot to merge into

snapshot to merge in

Auto-merging ACONFLICT (content): Merge conflicts in AAutomatic merge failed; fix conflicts and then commit the result

delete the quickfix branch

Resolving the conflict:$ cat Afirst Asecond lineline 3<<<<<<< HEADline 4 quickfixline 5 quickfix=======testing line 4testing line 5>>>>>>> testing

Lines with no conflict

Conflicting lines in master branch file

Conflicting lines in testing branch file

Simple fix – include all the lines, and change the testing line numbers$ vim A$ cat Afirst Asecond lineline 3line 4 quickfixline 5 quickfixtesting line 6testing line 7$ git add A

$ git statusOn branch masterAll conflicts fixed but you are still merging(use “git commit” to conclude merge)

$ git commit –m “merged testing into master;included all lines, renumbered testing lines”

3‐way merge result:

Git creates a new snapshot from the 3‐way merge, including the file changed to resolve conflicts. A new commit (C8) that points to it is created. This is called a merge commit, and it has 2 parents. 

Once the merge is complete you can delete the testing branch:

$ git branch –d testing

master

testing

HEAD

C1 C2 C3 C5

C4

C6

C7

C8

Viewing the 3‐way merge result:

$ git log ‐‐pretty=format:'%h %s' ‐‐graph*   0ba7fce merged testing into master; included all lines, renumbered testing lines|\| * 6a53ed9 added line 5 in testing| * 6b45237 adding line 4 in testing* | 3127dc4 qf line 5* | 0f7c8ee added line 4 in quickfix|/* 8f64ab5 added line 3 to A* 075e235 added line 2 to A* 60ff54b initial file A

master HEAD

C1 C2 C3 C5

C4

C6

C7

C8

Recovering from commit mistakesTo understand how to recover from commit mistakes, we first need to cover more details about how git works. Consider the state of the repository after merging: 

Recall at the beginning of  these slides we showed 3 “areas” – the working directory, staging area, and repository. For the purposes of recovering from mistakes, the HEAD pointer on the current branch (master) is the thing we care about in the repository.  The staging area is actually a manifest called INDEX that gitmaintains with information about files in the staging area. Assume you execute:

$ git checkout master

Version C8 of File A: first Asecond lineline 3line 4 quickfixline 5 quickfixtesting line 6testing line 7

Repository

Working Directory

A – version C8

Staging Area ‐ INDEX

A – version C8

INDEX initially contains information about the last committed snapshot. The working directory contains what you can modify. Following a checkout it contains the snapshot pointed to by master/HEAD, and this is the same snapshot included in INDEX.

In this and the following slides, we show file information in INDEX, but if you execute git status and there are no files that have been added to the staging area via git add and not yet committed, then git status will report that there are no files in the staging area.

Commit mistakes: forgetting to add a file to the commit

$ vim A$ cat Afirst Asecond lineline 3$ echo “first B” > B$ git add A$ git commit –m “removed quickfix and testing branch lines from file A”

master HEAD

C1 C8 C9

Working Directory

A – version C9B

Staging Area ‐ INDEX

A – version C9

Repository

0ba7fce 76d9be4

Version C9 of File A: first Asecond lineline 3

Forgot to include file B!

Fix: add the second file to the same commit

$ git add B$ git commit –-amend(default editor opens with the previous commit message: change as needed, and save changes:)removed quickfix and testing branch lines from file A, added B

Working Directory

A – version C9B – version C9

Staging Area ‐ INDEX

A – version C9B – version C9

master HEAD

C1 C8 C9

Repository

0ba7fce 3b38281

Version C9 of File A: first Asecond lineline 3

The commit is changed to add file B to the repository with the changed message. There are still a total of 9 commits, but the previous commit object is replaced with a new one (76d9be4 object is replaced with 3b38281 object)

Version C9 of File B: first B

To only change the previous commit message, just use this 

Commit mistakes: adding too many files to the staging area$ vim A$ vim B$ git add *$ git statuschanges to be committed: modified: A

modified: B

master HEAD

C1 C8 C9

Working Directory

A – modifiedB – modified

Staging Area ‐ INDEX

A – modifiedB – modified 

Repository

0ba7fce 76d9be4

Don’t really want to commit B yet!

File A: first Asecond line

File B: first Bline 2

Fix: “remove” staged files

Working Directory

A – modifiedB – modified

Staging Area ‐ INDEX

A – modifiedB – version C9

master HEAD

C1 C8 C9

Repository

0ba7fce 76d9be4

File A: first Asecond line

File B: first Bline 2

$ git reset HEAD B$ git statuschanges to be committed: modified: Achanges not staged for commit: modified: B

Staging area changed to remove B 

$ git commit –m “took out another line from A”$ vim B$ git add B$ git commit –m “added 2 lines to B”

master HEAD

C1 C8 C9

Repository

0ba7fce 76d9be4

C10e25ed45

C11 59935e7

File A: first Asecond line

File B: first Bline 2line 3

(same as version C9 of File B)File B: first B

Commit mistakes: completely messing up$ vim A$ vim B$ git add *$ git commit –m “added another line to both A and B”

Working Directory

A – version C12B – version C12

Staging Area ‐ INDEX

A – version C12B – version C12

File B is wrong and we need to revert to the C10 version of it!

File A: first Asecond lineline 3

File B: first Bline 2line 3line 4

$ git reset HEAD~2 -- BUnstaged changes after reset:M B$ git statuschanges not staged for commit: modified: B

Staging Area ‐ INDEXA – version C12B – version C10Fix:

Staging area changed to version C10 of B, BUT version C12 is still in the Working Directory!

C12f3662fa

master HEAD

C1 C8 C9

Repository

0ba7fce 76d9be4

C10e25ed45

C11 59935e7

Working DirectoryA – version C12B – version C12

$ git commit –m “reverted B to version with 1 line”$ git checkout B

still C12 version of B in Working Directory

now C10 version of B in Working Directory

shorthand for commit that is the parent of the parent of master/HEAD (~ is parent)

Commit mistakes: if all files completely messed up$ vim A$ vim B$ git add *$ git commit –m “added another line to both A and B”

Working Directory

A – version C12B – version C12

Staging Area ‐ INDEX

A – version C12B – version C12

Both files are wrong and we just want to go back to the C11 versions!

File A: first Asecond lineline 3

File B: first Bline 2line 3line 4

C12f3662fa

master HEAD

C1 C8 C9

Repository

0ba7fce 76d9be4

C10e25ed45

C11 59935e7

$ git reset --soft HEAD~$ git checkout masterFix 1: INDEX and Working Directory now have C11 versions

moves master/HEAD back to C11; INDEX has C11 versions, no effect on Working Directory$ git reset --mixed HEAD~$ git checkout masterFix 2: Working Directory now has C11 versions

Fix 3: moves master/HEAD back to C11; INDEX and Working Directory now have C11 versions$ git reset --hard HEAD~

master/HEAD moved to back to C11, INDEX and Working Directory have C11 versions of A and B

$ git branch recover-branch f3662faIf you need the versions in C12 later, use this to create a branch called recover‐branch at the C12 commit

only moves master/HEAD back to C11; INDEX and Working Directory have C12 versions