# Git ### Git History Die Entstehung von GIT steht in direkter Verbindung mit der Entwicklung und Instandhaltung des Linux Kernels (1991 - 2002). In dieser Zeit wurden Änderungen in der Software als Patches und archivierte Dokumente unter den Entwicklern ausgetauscht. 2002 begann das Linux Kernel Projekt ein DVCS (Distributed Version Control System) namens BitKeeper zu verwenden. Als BitKeeper 2005 begann, das Tool zu kommerziell zu vermarkten, 2005 stellte BitKeeper die open source Lizenz des Tools ein und vermarktete es ab sofort kommerziell. Aus diesem Anlass begann Linus Torvalds, Initiator und treibende Kraft bei der Entwicklung des Linux-Kernels, mit der Entwicklung eines eigenen Tools, in die er die Erfahrungen einfließen ließ, die man aus der Anwendung von BitKeeper gewonnen hatte. Mit dem neuen System verfolgte man folgende Ziele: - Geschwindigkeit - Einfaches Design - Sehr gute Unterstützung von nicht linearer Entwicklung (Branches) - Vollständig verteilt - Ausgelegt, um große Projekte, wie den Linux Kernel, effektiv abwickeln zu können (Geschwindigkeit und Größe). Seit 2005 hat sich GIT in ein DVCS entwickelt, das nicht nur leicht zu verwenden ist, sondern auch die oben beschriebenen Qualitäten in sich vereint: es ist sehr schnell, sehr effizient auch bei großen Projekten und zeichnet sich durch ein solides Branching-System für nicht-lineare Entwicklung aus. [source: GitPro by Scott Chacon](https://progit.org) ### Git Basics Git unterscheidet sich signifikant von anderen VCS wie Subversion und Perforce. Daher ist es leichter, Git zu verstehen wenn man Subversion oder Perforce gar nicht kennt. Der wesentliche Unterschied liegt nicht im Interface - darin sind sie sich übrigens ziemlich ähnlich - sondern in der Art und Weise, wie Git Informationen speichert und darüber nachdenkt. #### Snapshots und keine Diffs Der wesentlichste Unterschied zwischen GIT und jedem anderen CVS liegt in der Art, wie GIT mit den Daten umgeht. Die meisten anderen VCS speichern Informationen als eine Liste von dokumentbasierenden Änderungen. Diese Systeme behandeln die in ihnen gespeicherte Information als ein Set von Dateien und der Änderungen für jede einzelne Datei im Projektverlauf. GRAFIK Git behandelt und speichert Daten völlig anders, nämlich als ein Set von Momentaufnahmen (Snapshots) eines kleinen Dateisystems. Jedes Mal wenn man einen Commit erstellt - oder den Zustand des Projekts in Git speichert - erstellt Git ein Bild vom Zustand aller Dokumente zu diesem Moment und speichert eine Referenz zu dieser Momentaufnahme. Daraus entstammt auch die Effizient von Git: ändert sich eine Datei nicht, dann speichert Git diese Datei nicht wieder ab, sondern Git speichert einfach einen Link zur bereits in Git vorhandenen Datei. Demnach behandelt Git die in ihm gespeicherten Daten wie einen Strom von Momentaufnahmen. GRAFIK Das ist der wesentlichste Unterschied zw Git und nahezu allen anderen VCS. Dieser Unterschied macht Git zu einem mini Dateisystem mit einigen zusätzlichen mächtigen Tools und daher zu weit mehr als einem einfachen VCS. Dieser Unterschied liegt auch der Möglichkeit zu Grunde, beliebig viele Branches eines Projektes parallel zu führen. #### Fast jeder Befehl wir lokal ausgeführt Ein Großteil der Git Befehle wird lokal ausgeführt. Daher werden in erster Linie nur lokale Dateien und Ressourcen benötigt. Dadurch fällt zB die in CVCS (Centralized Version Control Systems) immanente Network-Latenz vollkommen weg und macht Git unheimlich schnell. Da man den gesamten Verlauf des Projekts direkt auf seinem Rechner hat, laufen die meisten Operationen beinahe unmittelbar ab. Daher kann man auch an Projekten arbeiten, wenn man offline ist. #### Git hat Integrität Jede Änderung in Git erhält eine Checksumme bevor sie gespeichert wird. Diese Checksumme dient zur Referenzierung der Änderung. Das bedeutet, dass es nahezu unmöglich ist, etwas zu ändern, ohne dass Git davon erfährt. Diese Funktionalität ist auf der untersten Ebene in Git verbaut und ist fundamentaler Teil seiner Philosophie. Dadurch ist es nicht möglich, dass Information verloren geht oder eine Datei korrumpiert wird ohne dass Git darauf aufmerksam wird. Der von Git verwendete Mechanismus für die Bildung der Checksumme wird SHA-1 hash genannt. Es handelt sich dabei um einen 40 Zeichen langen String, der sich aus hexadezimalen Zeichen (0-9 und a-f) zusammen setzt. Die Kalkulation der Checksumme basiert auf dem Inhalt einer Datei oder der Dateistruktur in Git. Beispiel für einen SHA-1 hash: `cb6e11ad9518e9c7f7974bdd760b5c4f41739670` Git verwendet diese hash Werte nahezu überall. Die Informationen in Git werden nicht mit dem Dateinamen gespeichert sonder mit dem hash Wert des Inhalts der Dateien. #### Grundsätzlich fügt Git nur Daten hinzu Git macht es einem nicht einfach, Daten zu verlieren, wie es grundsätzlich nur Daten dem System hinzufügt. Auch kann man fast alles wieder rückgängig machen. Natürlich kann man Daten verlieren oder Änderungen durcheinanderbringen aber sobald man etwas in einer Momentaufnahme über einen Commit festgehalten hat, wird es sehr sehr schwer diese Momentaufnahme wieder zu verlieren - speziell dann wenn man die Daten auf seinem lokalen System sichert oder die Git Datenbank auf ein anderes Repository pusht. Dadurch eignet sich Git hervorragen für Experimente ohne Gefahr zu laufen, ein Projekt vollkommen an die Wand zu fahren. [source: GitPro by Scott Chacon](https://progit.org) ### The Three States => The Tree Trees of Git ![The Three Git States](https://www.evernote.com/l/ARAmr1-QA-lKf70f8NYVqrWttoYflRv1N4MB/image.png) Working Directory | Staging Area aka Index | Repository Git can be understood as a content manager of three different trees. _Tree_ can be seen as a "collection of files", not specifically the data structure - in a few cases the Index doesn't exaclty act like a tree, though. Git as a system manages and manipulates three trees in its normal operation: | | The Tree Roles | | -------- | -------------- | | The HEAD | last commit snapshot, next parent | | The Index | proposed next commit snapshot | | The Working Directory | sandbox | #### The HEAD - last commit snapshot, next parent The HEAD in Git is the pointer to the current branch reference, which, in turn, is a pointer to the last commit you made or the last commit that was checked out into your working directory. That also means it will be the parent of the next commit you do. It's generally simplest to think of it as *HEAD is the snapshot of your last commit*. _In fact, it's pretty easy to see what the snapshot of your HEAD looks like. Here is an example of getting the actual directory listing and SHA checksums for each file in the HEAD snapshot:_ $ cat .git/HEAD ref: refs/heads/master $ cat .git/refs/heads/master fdd1783da5bb002780fa710575664e3f76097fac $ git cat-file -p fdd1783da5bb002780fa710575664e3f76097fac tree e76e6dc41889d1dbce4b1274ac424bc4532fd3d6 parent 3aa961cc48b494309241ce85b42134afc8952e36 author criscom 1462872030 +0200 committer criscom 1462872030 +0200 Add git reset information table from Mark Dominus $ git ls-tree -r e76e6dc41889d1dbce4b1274ac424bc4532fd3d6 100644 blob dc413f6a9dca0f7b2aac71eab7e279aa59c342c8 git-real.md #### The Index - next proposed commit snapshot The Index is your proposed next commit. It is not technically a tree structure, it's a flattened manifest. When you run `git commit`, that command only looks at your Index by default, not at anything in your working directory. So it's simplest to think of it as *the Index is the snapshot of your next commit.* $ git ls-files -s 100644 dc413f6a9dca0f7b2aac71eab7e279aa59c342c8 0 git-real.md #### The Working Directory - sandbox, scratch area Finally, you have your working directory. This is where the content of files are placed into actual files on your filesystem so they're easily editable by you. *The Working Directory is your scratch space, used to easily modify file content.* #### The Workflow Git is all about recording snapshots of your project by manipulating these three trees, or collections of contents of files. ![The workflow](http://git-scm.com/images/reset/workflow.png) When checking out a branch, it changes HEAD to point to the new commit, populates the Index with the snapshot of that commit, then checks out the contents of the files in your Index into your Working Directory. #### The Role of Reset `git reset` directly manipulates these three trees in a simple and predictable way. It does up to three basic operations ##### Step 1: Moving HEAD - killing me --soft [ly] git log -3 --pretty=oneline 2b8da2c17a316d53d2f14f7557bedbe03a40fd20 Add a line to 03.md f8ba5a397d76dbf7231c1613d2394124dea2e2ed Add lib folder and readme file fb3bfdfbca3bdfb946d95dc28802cf6ae441b73a Add newline to 01.md Unlike `checkout`, `git reset` does not move what branch HEAD points to, it directly changes the SHA of the reference itself. This means if HEAD is pointing to the 'master' branch, running `git reset f8ba5a3` will first of all make 'master' point to `f8ba5a3` before it does anything else. $ git reset f8ba5a3 Unstaged changes after reset: M 03.md $ git log -3 --pretty=oneline f8ba5a397d76dbf7231c1613d2394124dea2e2ed Add lib folder and readme file fb3bfdfbca3bdfb946d95dc28802cf6ae441b73a Add newline to 01.md 0a829f3f15015bcf9fe9b57d2e45acdf88115ae6 Add a third line to 01.md $ git status On branch master Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) modified: 03.md no changes added to commit (use "git add" and/or "git commit -a") No matter what form of `reset`with a commit you invoke, this is the first thing it will always try to do. If you add the flag `--soft`, this is the *only* thing it will do. With `--soft`, `reset` will simply stop there. `git reset --soft HEAD~` **What it does is essentially undoing the last commit that was made.** It moves HEAD to the parent commit and move the commited file changes into the Index. When you run `git commit`, Git will create a new commit and move the branch that `HEAD` points to up to it. When you `reset`back to `HEAD~` (the parent of HEAD), you are moving the branch back to where it was without changing the Index (staging area) or Working Directory. You could now do a bit more work and `commit` again to accomplish baiscally what `git commit --amend` would have done. If you run `git status` you'll see the difference between the Index and what the new HEAD is. ##### Step 2: Updating the index - having --mixed [feelings] The next thing `reset`will do is to update the Index with the contents of whatever tree HEAD now points to so they're the same. git reset --mixed HEAD~ Unstaged changes after reset: M 03.md $ git log -3 --pretty=oneline f8ba5a397d76dbf7231c1613d2394124dea2e2ed Add lib folder and readme file fb3bfdfbca3bdfb946d95dc28802cf6ae441b73a Add newline to 01.md 0a829f3f15015bcf9fe9b57d2e45acdf88115ae6 Add a third line to 01.md $ git status On branch master Changes not staged for commit: (use "git add ..." to update what will be committed) (use "git checkout -- ..." to discard changes in working directory) modified: 03.md If you specify the `--mixed` option, `reset` will stop at this point. This is also the default, so if you specify no option at all, this is where the command will stop. What `git reset --mixed HEAD~` did was - undo the last `commit` - but also _unstage_ everything We rolled back to before we ran all our `git add`s AND `git commit`. ##### Step 3: Updating the Working Directory - math is --hard The third thing that `reset`will do is to then make the Working Directory look like the Index. If you use the `--hard` option, it will continue to this stage. With `git reset --hard HEAD~` you - undo the last commit - all the git adds - and all the work you did in your working directory. **Thus you will lose all the changes in the last commit.** It's important to note at this point that this is the only way to make the `reset`command dangerous (ie: not working directory safe). Any other invocation of `reset`can be pretty easily undone, the `--hard`option cannot, since it overwrites (without checking) any files in the Working Directory. $ git log -3 --pretty=oneline 3e2357ed723865d15654bedc2a1b2f2d6acea95d Before git reset --hard f8ba5a397d76dbf7231c1613d2394124dea2e2ed Add lib folder and readme file fb3bfdfbca3bdfb946d95dc28802cf6ae441b73a Add newline to 01.md $ git reset --hard HEAD~ HEAD is now at f8ba5a3 Add lib folder and readme file $ git log -3 --pretty=oneline f8ba5a397d76dbf7231c1613d2394124dea2e2ed Add lib folder and readme file fb3bfdfbca3bdfb946d95dc28802cf6ae441b73a Add newline to 01.md 0a829f3f15015bcf9fe9b57d2e45acdf88115ae6 Add a third line to 01.md In this particular case, we still have the changes in 03.md in a commit in our Git DB that we could get back by looking at our `reflog`, but if we had not committed it, Git still would have overwritten the file. Below was taken from: http://blog.plover.com/prog/git-reset.html *The Git subcommand git-reset is one of very few Git commands that can permanently destroy real work.* __`git checkout`can also destroy the working tree.__ | working directoy | index/staging area | target | | working directory | index | HEAD | | ---------------- | ------------------ | ------ | -------- | ----------------- | ----- | ---- | | A | B | C | --soft | A | B | C | | | | | --mixed | A | C | C | | | | | --hard | C | C | C | | | | | --merge | (disallowed) | | | __git-reset__ does up to three things: 1. It points the HEAD ref at a new 'target' commit, if you specified one. 2. Then it copies the tree of the HEAD commit to the index, unless you said --soft. 3. Finally, it copies the contents of the index to the working tree, if you said --hard. #### Git Reset recap The `reset`command overwrites these three trees in a specific order, stopping where you tell it to: - #1 Move HEAD to a different commit (stop if --soft) - #2 THEN make the Index look like that (stop here unless --hard) - #3 THEN make the Working Directory look like that There are also `--merge` and `--keep` options. #### Git Reset with a path ==> unstaging a staged file By specifying a path we can use `git reset filename.txt` to update part of the Index or the Working Directory with previsously committed content. Running `git reset file.txt` assumes `git reset --mixed HEAD filen.txt`which will: - ~~#1 Move HEAD to a different commit (stop if --soft)~~ - #2 THEN make the Index look like that (~~stop here unless --hard~~) So it essentially just takes whatever `file.txt`looks like in HEAD and puts that in the Index. Basicall `git reset file.txt` is the opposite of `git add file.txt`. By specifying a specific commit, we could pull a specific file version to populate our Index, like `git reset 0a829f3 03.md` ### Git reflog `git reflog` shows an ordered list of the commits that HEAD has pointed to: it's undo history for your repo. The reflog isn't part of the repo itself (it's stored separately to the commits themselves) and isn't included in pushes, fetches or clones; it's purely local. Aside: understanding the reflog means you can't really lose data from your repo once it's been committed. If you accidentally reset to an older commit, or rebase wrongly, or any other operation that visually "removes" commits, you can use the reflog to see where you were before and git reset --hard back to that ref to restore your previous state. Remember, refs imply not just the commit but the entire history behind it. $ git reflog f8ba5a3 HEAD@{0}: reset: moving to HEAD~ 3e2357e HEAD@{1}: commit: Before git reset --hard f8ba5a3 HEAD@{2}: reset: moving to HEAD~ 7ce43b9 HEAD@{3}: commit: Committing file 03.md again f8ba5a3 HEAD@{4}: reset: moving to HEAD~ 4490b4d HEAD@{5}: commit: Recommit file changes in 03.md f8ba5a3 HEAD@{6}: reset: moving to f8ba5a3 2b8da2c HEAD@{7}: commit: Add a line to 03.md ... $ git checkout 3e2357e ## Undoing things from gitreal ### Unstaging files git reset HEAD git reset HEAD styles.css >Moves the file from the Staging Area to the Working Directory. The file's modifications remain. ### Discard changes since last commit git checkout -- git checkout -- styles.css >Removes the changes added in the file completely. `git checkout -- ` is only possible in the Working Directory. ## Difference between `reset` and `checkout` >In their simplest form, ```reset``` resets the index without touching the working tree, while `checkout` changes the working tree without touching the index. * [git reset](http://git-scm.com/docs/git-reset) is specifically about **updating the index**, moving the HEAD. * [git checkout](http://git-scm.com/docs/git-checkout) is about **updating the working tree** (to the index or the specified tree). It will update the HEAD only if you checkout a branch (if not, you'll end up with a [detached HEAD](http://stackoverflow.com/a/1000009/6309)) ![git checkout master~3](http://i.stack.imgur.com/C4BCo.png) ![git reset HEAD~3](http://i.stack.imgur.com/Tiv4H.png) [See for more details the discussion on stackoverflow](http://stackoverflow.com/questions/3639342/whats-the-difference-between-git-reset-and-git-checkout) ### Skip staging and commit ```git commit -a -m "Modify readme"``` >not adding files we are tracking ### Undoing a commit ```git reset --soft HEAD^``` * Reset into staging * Undo last commit, put changes into staging * Move to commit before 'HEAD' * Now we can make changes and re-commit ### Undo last commit and all changes ```git reset --hard HEAD^``` ### Undo last 2 commits and all changes ```git reset --hard HEAD^^``` ### Removing files In order to remove files from your tree, you can simply run: `git rm ` This will remove that file from the index (and thus from the next commit) as well as from your working diretory. On your next commit, the tree that commit points to will simply not contain that file anymore. The file will be removed from the folder. ### Adding to a commit git add todo.txt git commit --amend -m "Modify readme & add todo.txt." * When we forgot to add a file * Add to the last commit * Whatever has been staged is added to last commit ### Git diff - show differences #### Show unstaged differences since last commit `git diff` >As a matter of fact running `git diff` with no arguments, will show the differences between the current working directory and the index, i.e. the last time `git add` was ran. What you see is simply a **patch file**. #### Viewing staged differences `git diff --staged` >does the same as running `git diff`with no arguments but in contrast to above command, it will show differences of staged files and the working directory/git directory, i.e. the last time `git commit` was ran. #### Show differences between two commits `git diff --numstat commit-sha1 commit-sha1` git diff --numstat 2d3f5d03e76d2c1846af0a76e2e84b74cf8a1065 cdcd6bee6c8bf5b330c2eb22359c04417472a5ee 0 5 01.md 0 1 02.md `git diff --stat older-commit-sha1 newer-commit-sha1` git diff --stat cdcd6bee6c8bf5b330c2eb22359c04417472a5ee 01.md | 5 +++++ 02.md | 1 + 2 files changed, 6 insertions(+) #### See specific differences `git diff older-commit-sha1 newer-commit-sha1 -- filename` git diff cdcd6bee6c8bf5b330c2eb22359c04417472a5ee 2d3f5d03e76d2c1846af0a76e2e84b74cf8a1065 -- 01.md diff --git a/01.md b/01.md index e69de29..8b6d5f6 100644 --- a/01.md +++ b/01.md @@ -0,0 +1,5 @@ +add 1st line +add 2nd line +add 3rd line - stop +abc +def #### Generating patch files The default output of the `git diff` command is a valid patch file. You can pipe the output into a file and email it to someone, so that they can apply it with the `patch` command. ##### Creating a patch from a branch If you have done some work in an 'experiment' branch, you could create a patch file like this: `git diff master..experiment > experiment.patch` ##### Applying a patch `patch -p < ~/experiment.patch` ### Interactive adding Interactive adding makes for a more controlled and thematic set of commits and is a very powerful tool to controlling what goes into each commit. Say we add changes to our 01.md and 02.md file and add a new TODO file to our project. Later we come back and want to commit, but we don't remember which files hat to do with each other and we don't just want to commit them all together because that's confusing for collaborators trying to review our code. >Interactive mode lets us modify our index interactively before committing. git add -i staged unstaged path 1: unchanged +2/-1 01.md 2: unchanged +3/-1 02.md *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help What now> We can see that we have two files that are being tracked (have been added at some point in the past) that have been modified. We cannot yet see our new TODO file, though. To add that, type `4` for the `add untracked` option and hit `Enter.` What now> 4 1: TODO Add untracked>> added one path You will see all the untracked files in your working directory. Type the numbers of the files you want to add or a range (i.e.: 1-5), and hit enter twice and your're done. This will drop you back to the main menu. You can then type 1 to see what your index looks like now. What now> 1 staged unstaged path 1: unchanged +2/-1 01.md 2: unchanged +3/-1 02.md 3: +0/-0 nothing TODO You can see that the TODO file is now staged (in the index), but the other two are not. Let's add 01.md, but not the 02.md file and commit it. To do that, we hit `2`, which lists the files we can update, type `1`and enter to add the 01.md file, then hit enter again to go back to the main menu. Then we hit `7`to exit an drun the `git commit`command. What now> 2 staged unstaged path 1: unchanged +2/-1 01.md 2: unchanged +3/-1 02.md Update>> 1 staged unstaged path * 1: unchanged +2/-1 01.md 2: unchanged +3/-1 02.md Update>> updated one path What now> 7 Bye. git commit -m "01.md and TODO file added" [master 049da5b] 01.md and TODO file added 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 TODO You can also do more complicated things, like going through all of your change patches hunk by hunk, deciding if each hunk should be applied to the next commit or not. This means that if you’ve made a bunch of changes to one le, you can commit part of those changes in one commit, and the rest in a second. Try the patch menu option in the Interactive Adding menu to try this out. >Beware of using interactive adding if you are already used to running git commit -a. If you run through the whole interactive add process and then run git commit -a, it will basically ignore everything you just did and just add all modified files. ## Formatting Log output `--pretty` is a useful option for formatting the ouput in different ways. For example, we can list the commit `SHA-1`s and the first line of the message with `--pretty=online`: git log --pretty=oneline 534860566b7bae4017d18cadf391371592f5c55f Remove experiment.patch 2ee75e651b9e64811297612ba2caa92f7f347ebf Add fourth line to 01.md 5a6611996b06ce9bd2264cbed29f3922eaef6ca3 Add fourth line to 01.md d2349d29ae0db360893c27c62181a5283c100cef Add 2 lines to 01.md cdcd6bee6c8bf5b330c2eb22359c04417472a5ee Add 01.md With `--pretty`, you can choose between `oneline`, `short`, `medium`, `full`, `fuller`, `email`, `raw` and `format:(string)`, where (string) is a format you specify with variables (ex: `--pretty=format:”%an added %h on %ar”` will give you a bunch of lines like “criscom added 5348605 on 21 minutes ago”). git log --pretty=format:"%an added %h on %ar" criscom added 5348605 on 21 minutes ago criscom added e69dab6 on 26 minutes ago criscom added cdcd6be on 4 hours ago ### Filtering Log Output There are also a number of options for ltering the log output. You can specify the maximum number of commits you want to see with -n, you can limit the range of dates you want to see commits for with —since and —until, you can lter it on the author or committer, text in the commit message and more. Here is an example showing at most 30 commits between yesterday and a month ago by me : `git log -n 30 --since=”1 month ago” --until=yesterday --author=”criscom”` ### Common options to git log | Option | Description | | -------- | ------------- | | -p | Show the patch introduced with each commit. | | --stat | Show statistics for files modified in each commit. | | --shortstat | Display only the changed/insertions/deletions line from the --stat command. | | --name-only | Show the list of files modified after the commit information. | | --name-status | Show the list of files affected with added/modified/deleted information as well. | | --abbrev-commit | Show only the first few characters of the SHA-1 checksum instead of all 40. | | --relative-date | Display the date in a relative format (for example, “2 weeks ago”) instead of using the full date format. | | --graph | Display an ASCII graph of the branch and merge history beside the log output. | | --pretty | Show commits in an alternate format. Options include oneline, short, full, fuller, and format (where you specify your own format). | ### Showing Objects `git show` Running this command on a file will simply output the contents of the file. ### Showing commits If you call it on a commit object (~ a tree), you will get simple imformation about the commit (the author, message, date, etc) and a diff of what changed between taht commit and its parents. git show master commit fb3bfdfbca3bdfb946d95dc28802cf6ae441b73a Author: criscom Date: Tue May 10 10:06:31 2016 +0200 Add newline to 01.md diff --git a/01.md b/01.md index 207ee39..8c17d9d 100644 --- a/01.md +++ b/01.md @@ -7,4 +7,4 @@ ghijk we add a new line and a second line -and now a third \ No newline at end of file +and now a third `git show master^` will show the changes between the penultimate (second to last) commit and its parent. ### Showing Trees `git ls-tree` shows tress and displays SHA-1s of all the blobs and trees that it points to. git ls-tree master 100644 blob 8c17d9dec9efc6d0ad05372d7f6869d833181d0f 01.md 100644 blob fd547b8f094e7cd3bbdff1225f861be9e81a1aa8 02.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 03.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 TODO 040000 tree b405b70664efcdc5de910eba03e55f14745a9c6f lib Christophs-iMac:gittest criscom$ git ls-tree master^ 100644 blob 8c17d9dec9efc6d0ad05372d7f6869d833181d0f 01.md 100644 blob fd547b8f094e7cd3bbdff1225f861be9e81a1aa8 02.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 03.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 TODO Christophs-iMac:gittest criscom$ git ls-tree master{tree} fatal: Not a valid object name master{tree} Christophs-iMac:gittest criscom$ git ls-tree master^{tree} 100644 blob 8c17d9dec9efc6d0ad05372d7f6869d833181d0f 01.md 100644 blob fd547b8f094e7cd3bbdff1225f861be9e81a1aa8 02.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 03.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 TODO 040000 tree b405b70664efcdc5de910eba03e55f14745a9c6f lib Christophs-iMac:gittest criscom$ git ls-tree master^^{tree} 100644 blob 8c17d9dec9efc6d0ad05372d7f6869d833181d0f 01.md 100644 blob fd547b8f094e7cd3bbdff1225f861be9e81a1aa8 02.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 03.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 TODO You can also run the command recursively, so you can see all the subtrees as well. This is a great way to get the SHA-1 of any blob anywhere in the tree without having to walk it one node at a time. git ls-tree -r -t master^{tree} 100644 blob 8c17d9dec9efc6d0ad05372d7f6869d833181d0f 01.md 100644 blob fd547b8f094e7cd3bbdff1225f861be9e81a1aa8 02.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 03.md 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 TODO 040000 tree b405b70664efcdc5de910eba03e55f14745a9c6f lib 100644 blob 06f196f556db9fc496ab9c12f7a047e4157add4e lib/readme.txt `git ls-tree master^{tree}` => `git ls-tree master` ### Showing Blobs Lastly, you may want to extract the contents of individual blobs. The cat-file command is an easy way to do that, and can also serve to let you know what type of object a SHA-1 is, if you don’t know. It is sort of a catch-all command that you can use to inspect objects. `git cat-file -t/-p SHA-1` git cat-file -t 8c17d9dec9efc6d0ad05372d7f6869d833181d0f blob git cat-file -p 8c17d9dec9efc6d0ad05372d7f6869d833181d0f add 1st line add 2nd line add 3rd line - stop abc def ghijk we add a new line and a second line and now a third ## Showing differences between ### Working directory and staging area `git diff` ### Staging area and latest commit `git diff --staged` ### Working directory and commit 4ac0a6733 `git diff 4ac0a6733` ### Commit 4ac0a6733 and the latest commit `git diff 4ac0a6733 HEAD` ### Commit 4ac0a6733 and commit 826793951 `git diff 4ac0a6733 826793951` ### Show differences in log `git log -p` [See git diff documentation](https://git-scm.com/docs/git-diff) ## Working with remote repos ### Adding a remote ```git remote add origin https://github.com/criscom/repository-name.git``` ### Which remotes does git repository know about ```git remote -v``` ### Pushing to remote ```git push -u origin master``` >origin: remote repository name master: local branch to push ### Pulling from remote ```git pull``` ### Having multiple remote To add new remotes: ```git remote add
``` To remove remotes: ```git remote rm ``` To push to remotes: ```git push -u ``` > is usuall "master" **Don't do these after you push** git reset --soft HEAD^ git commit --amend -m "New Message" git reset --hard HEAD^ git reset --hard HEAD^^ **CLONING & BRANCHING** ```git clone https://github.com/codeschool/git-real.git git-demo``` >git-demo = local folder name * Downloads the entire repository into a new git-demo directory * Adds the 'origin' remote, pointing it to the clone URL * Checks out initial branch (likely master) and sets the head. ### Branching out Need to work on a feature that will take some time? Time to branch out. git branch nameofbranch git checkout nameofbranch ### Merge git checkout master git merge nameofbranch ### Branch clean up After merging ```git branch -d nameofbranch``` ### Create branch and automatically checking it out ```git checkout -b admin``` ==> Automatically switches to branch admin ### REMOTE BRANCHES AND TAGS ```git checkout -b shopping_cart``` >create branch shopping_cart ```git push origin shopping_cart``` >links local branch to the remote branch ```git branch -r``` >list all remote branches ```git checkout shopping_cart``` >Branch shopping_cart set up to track remote branch shopping_cart from origin. Switched to a new branch 'shopping_cart' ```git remote show origin``` >Shows all remote and local branches and how they are connected ```git push origin :shopping_cart``` >Delete a remote branch ```git remote prune origin``` >to clean up deleted remote branches ```git push heroku-stagin staging:master``` >Will push and deploy staging on heroku ## Tagging >A tag is a reference to a commit (used mostly for release versioning) ```git tag``` >list all tags ```git checkout v0.0.1``` >checkout code at commit ```git tag -a v0.0.3 -m "version 0.0.3"``` >to add a new tag ```git push --tags``` >to push new tags ### Bibliography: http://schacon.github.io/2008/04/29/peepcode-git-book.html http://scottchacon.com/2011/07/11/reset.html http://blog.plover.com/prog/git-reset.html