Upload
buiphuc
View
232
Download
1
Embed Size (px)
Citation preview
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