├── COPYING ├── Makefile ├── book.css ├── conf ├── custom-html.xsl ├── custom-nochunks.xsl ├── en ├── basic.txt ├── branch.txt ├── clone.txt ├── drawbacks.txt ├── grandmaster.txt ├── history.txt ├── intro.txt ├── multiplayer.txt ├── preface.txt ├── secrets.txt └── translate.txt ├── es ├── basic.txt ├── branch.txt ├── clone.txt ├── intro.txt ├── preface.txt └── spanish.txt ├── find_selflink.js ├── makeover └── ru ├── basic.txt ├── branch.txt ├── clone.txt ├── drawbacks.txt ├── grandmaster.txt ├── history.txt ├── intro.txt ├── multiplayer.txt ├── preface.txt ├── secrets.txt └── translate.txt /Makefile: -------------------------------------------------------------------------------- 1 | # The language we are building. 2 | # For example, Run "make LANG=es" to build the Spanish edition. 3 | LANG := en 4 | 5 | .PHONY: target clean sync push 6 | 7 | target: book book/default.css book.html book.pdf 8 | 9 | # The book consists of these text files in the following order: 10 | 11 | TXTFILES := preface.txt intro.txt basic.txt clone.txt branch.txt history.txt \ 12 | multiplayer.txt grandmaster.txt secrets.txt drawbacks.txt translate.txt 13 | 14 | book.xml: $(addprefix $(LANG)/,$(TXTFILES)) 15 | # Kludge to make preface sections work for languages besides English. 16 | echo '[specialsections]' > conf 17 | sed -n '/^== .* ==$$/p' $(LANG)/preface.txt | sed 's/^== \(.*\) ==$$/^\1$$=sect-preface/' >> conf 18 | # Concatenate the text files and feed to AsciiDoc. 19 | # If a file has not yet been translated for the target language, 20 | # then substitute the English version. 21 | ( for FILE in $^ ; do if [ -f $$FILE ]; then cat $$FILE; else \ 22 | cat en/$$(basename $$FILE); fi; echo ; done ) | \ 23 | asciidoc -a lang=$(LANG) -d book -b docbook -f conf - > $@ 24 | 25 | # This rule allows unfinished translations to build. 26 | # Report an error if the English version of the text file is missing. 27 | $(addprefix $(LANG)/,$(TXTFILES)) : 28 | ifeq ($(LANG),en) 29 | @if [ ! -f $@ ]; then echo English file missing: $@; exit 123; fi 30 | else 31 | @if [ ! -f $@ ]; then echo $@ missing: using English version; fi 32 | endif 33 | 34 | # Ignore tidy's exit code because Asciidoc generates section IDs beginning with 35 | # "_", which xmlto converts to "id" attributes of tags. The standard 36 | # insists that "id" attributes begin with a letter, which causes tidy to 37 | # print a warning and return a nonzero code. 38 | # 39 | # When Asciidoc 8.3.0+ is widespread, I'll use its idprefix attribute instead 40 | # of ignoring return codes. 41 | 42 | book: book.xml 43 | xmlto -m custom-html.xsl -o book html book.xml 44 | sed -i 's/xmlns:fo[^ ]*//g' book/*.html 45 | -ls book/*.html | xargs -n 1 tidy -utf8 -m -i -q 46 | ./makeover 47 | 48 | book/default.css: book.css 49 | -mkdir book 50 | rsync book.css book/default.css 51 | 52 | book.html: book.xml 53 | xmlto -m custom-nochunks.xsl html-nochunks $^ 54 | -tidy -utf8 -imq $@ 55 | 56 | # Set SP_ENCODING to avoid "non SGML character" errors. 57 | # Can also do SP_ENCODING="UTF-8". 58 | book.pdf: book.xml 59 | SP_ENCODING="XML" docbook2pdf book.xml 60 | 61 | clean: 62 | -rm -rf book.xml book.html book 63 | 64 | sync: target 65 | rsync -r book.html book.pdf book/* blynn@tl1.stanford.edu:www/gitmagic/intl/$(LANG)/ 66 | 67 | public: 68 | git push blynn@git.or.cz:srv/git/gitmagic.git 69 | git push git@github.com:blynn/gitmagic.git 70 | git push git@gitorious.org:gitmagic/mainline.git 71 | -------------------------------------------------------------------------------- /book.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-size: 90%; 3 | font-family: verdana, arial, sans-serif; 4 | } 5 | 6 | tt, code, pre, .type { 7 | font-family: andale mono, courier new, courier, monospace; 8 | font-size: 90%; 9 | } 10 | 11 | pre { 12 | color: #0000aa; 13 | } 14 | 15 | ul li p { 16 | margin-bottom:0; 17 | } 18 | 19 | /* Based on http://phrogz.net/CSS/columns3.html */ 20 | div.toc { 21 | float: left; 22 | margin: 0; 23 | padding: 0; 24 | padding-top: 0.5em; 25 | border: 0; 26 | width: 16em; 27 | 28 | background-color: #f9f9f9; 29 | margin-right:1em; 30 | } 31 | 32 | div.content { 33 | margin: 0; 34 | padding: 0; 35 | 36 | /* won't match if font is smaller in toc */ 37 | border-left: 16em solid #f9f9f9; 38 | padding-left: 1em; 39 | } 40 | 41 | div.content:after { 42 | content:' '; 43 | clear:both; 44 | display:block; 45 | height:0; 46 | overflow:hidden 47 | } 48 | 49 | div.footer { 50 | clear:left; 51 | padding: 0.5em; 52 | /* background-color: #f9f9f9; 53 | border: 1px solid #aaaaaa; */ 54 | font-size: 80%; 55 | margin: 0; 56 | } 57 | 58 | div.toc ul { 59 | list-style: none; 60 | padding: 0; 61 | margin: 0; 62 | } 63 | 64 | div.toc li ul a, li ul span.currentlink 65 | { 66 | font-weight: normal; 67 | font-size: 90%; 68 | padding-left: 2em; 69 | } 70 | 71 | div.toc a, span.currentlink{ 72 | display:block; 73 | text-decoration: none; 74 | padding-left: 0.5em; 75 | color: #0000aa; 76 | } 77 | 78 | span.currentlink { 79 | text-decoration: none; 80 | background-color: #aaaaf9; 81 | } 82 | 83 | div.toc a:visited { 84 | color: #0000aa; 85 | } 86 | 87 | div.toc a:hover { 88 | background-color: #f9f9aa; 89 | } 90 | 91 | .programlisting, .screen { 92 | margin: 0; 93 | border: 1px solid #aaaaaa; 94 | background-color: #f9f9f9; 95 | padding: 0.17em; 96 | margin: 1em; 97 | margin-right: 3em; 98 | } 99 | 100 | .parameter { 101 | font-style: italic; 102 | } 103 | 104 | h1, h2 { 105 | padding-top: 0.5em; 106 | padding-bottom: 0.17em; 107 | margin: 0; 108 | font-weight: normal; 109 | color: black; 110 | border-bottom: 1px solid #aaaaaa; 111 | } 112 | 113 | h1 { 114 | font-size: 188%; 115 | } 116 | 117 | div.chapter h2 { 118 | font-size: 188%; 119 | } 120 | 121 | div.section h2 { 122 | font-size: 150%; 123 | } 124 | -------------------------------------------------------------------------------- /conf: -------------------------------------------------------------------------------- 1 | [specialsections] 2 | ^Предисловие $=sect-preface 3 | -------------------------------------------------------------------------------- /custom-html.xsl: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | ul 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /custom-nochunks.xsl: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | -------------------------------------------------------------------------------- /en/basic.txt: -------------------------------------------------------------------------------- 1 | == Basic Tricks == 2 | 3 | Rather than diving into a sea of Git commands, use these elementary examples to 4 | get your feet wet. Despite their simplicity, each of them are useful. 5 | Indeed, in my first months with Git I never ventured beyond the material in this chapter. 6 | 7 | === Saving State === 8 | 9 | About to attempt something drastic? Before you do, take a snapshot of all files 10 | in the current directory with: 11 | 12 | $ git init 13 | $ git add . 14 | $ git commit -m "My first backup" 15 | 16 | Now if your new edits go awry, run: 17 | 18 | $ git reset --hard 19 | 20 | to go back to where you were. To save the state again: 21 | 22 | $ git commit -a -m "Another backup" 23 | 24 | ==== Add, Delete, Rename ==== 25 | 26 | The above will only keep track of the files that were present when you first ran *git add*. If you add new files or subdirectories, you'll have to tell Git: 27 | 28 | $ git add NEWFILES... 29 | 30 | Similarly, if you want Git to forget about certain files, maybe because you've deleted them: 31 | 32 | $ git rm OLDFILES... 33 | 34 | Renaming a file is the same as removing the old name and adding the new name. There's also the shortcut *git mv* which has the same syntax as the *mv* command. For example: 35 | 36 | $ git mv OLDFILE NEWFILE 37 | 38 | === Advanced Undo/Redo === 39 | 40 | Sometimes you just want to go back and forget about every change past a certain point because they're all wrong. Then: 41 | 42 | $ git log 43 | 44 | shows you a list of recent commits, and their SHA1 hashes. Next, type: 45 | 46 | $ git reset --hard SHA1_HASH 47 | 48 | to restore the state to a given commit and erase all newer commits from the record permanently. 49 | 50 | Other times you want to hop to an old state briefly. In this case, type: 51 | 52 | $ git checkout SHA1_HASH 53 | 54 | This takes you back in time, while preserving newer commits. However, like time travel in a science-fiction movie, if you now edit and commit, you will be in an alternate reality, because your actions are different to what they were the first time around. 55 | 56 | This alternate reality is called a 'branch', and <>. For now, just remember that 57 | 58 | $ git checkout master 59 | 60 | will take you back to the present. Also, to stop Git complaining, always 61 | commit or reset your changes before running checkout. 62 | 63 | To take the computer game analogy again: 64 | 65 | - *`git reset --hard`*: load an old save and delete all saved games newer than the one just loaded. 66 | 67 | - *`git checkout`*: load an old game, but if you play on, the game state will deviate from the newer saves you made the first time around. Any saved games you make now will end up in a separate branch representing the alternate reality you have entered. <>. 68 | 69 | You can choose only to restore particular files and subdirectories by appending them after the command: 70 | 71 | $ git checkout SHA1_HASH some.file another.file 72 | 73 | Take care, as this form of *checkout* can silently overwrite files. To 74 | prevent accidents, commit before running any checkout command, especially when 75 | first learning Git. In general, whenever you feel unsure about any operation, Git command or not, first run *git commit -a*. 76 | 77 | Don't like cutting and pasting hashes? Then use: 78 | 79 | $ git checkout :/"My first b" 80 | 81 | to jump to the commit that starts with a given message. 82 | You can also ask for the 5th-last saved state: 83 | 84 | $ git checkout master~5 85 | 86 | ==== Reverting ==== 87 | 88 | In a court of law, events can be stricken from the record. Likewise, you can pick specific commits to undo. 89 | 90 | $ git commit -a 91 | $ git revert SHA1_HASH 92 | 93 | will undo just the commit with the given hash. Running *git log* reveals the revert is recorded as a new commit. 94 | 95 | === Changelog Generation === 96 | 97 | Some projects require a http://en.wikipedia.org/wiki/Changelog[changelog]. 98 | Generate one by typing: 99 | 100 | $ git log > ChangeLog 101 | 102 | === Downloading Files === 103 | 104 | Get a copy of a project managed with Git by typing: 105 | 106 | $ git clone git://server/path/to/files 107 | 108 | For example, to get all the files I used to create this site: 109 | 110 | $ git clone git://git.or.cz/gitmagic.git 111 | 112 | We'll have much to say about the *clone* command soon. 113 | 114 | === The Bleeding Edge === 115 | 116 | If you've already downloaded a copy of a project using *git clone*, you can upgrade to the latest version with: 117 | 118 | $ git pull 119 | 120 | === Instant Publishing === 121 | 122 | Suppose you've written a script you'd like to share with others. You could just tell them to download from your computer, but if they do so while you're improving the script or making experimental changes, they could wind up in trouble. Of course, this is why release cycles exist. Developers may work on a project frequently, but they only make the code available when they feel it is presentable. 123 | 124 | To do this with Git, in the directory where your script resides: 125 | 126 | $ git init 127 | $ git add . 128 | $ git commit -m "First release" 129 | 130 | Then tell your users to run: 131 | 132 | $ git clone your.computer:/path/to/script 133 | 134 | to download your script. This assumes they have ssh access. If not, run *git daemon* and tell your users to instead run: 135 | 136 | $ git clone git://your.computer/path/to/script 137 | 138 | From now on, every time your script is ready for release, execute: 139 | 140 | $ git commit -a -m "Next release" 141 | 142 | and your users can upgrade their version by changing to the directory containing your script and typing: 143 | 144 | $ git pull 145 | 146 | Your users will never end up with a version of your script you don't want them to see. Obviously this trick works for anything, not just scripts. 147 | 148 | === What Have I Done? === 149 | 150 | Find out what changes you've made since the last commit with: 151 | 152 | $ git diff 153 | 154 | Or since yesterday: 155 | 156 | $ git diff "@{yesterday}" 157 | 158 | Or between a particular version and 2 versions ago: 159 | 160 | $ git diff SHA1_HASH "master~2" 161 | 162 | In each case the output is a patch that can be applied with *git apply*. 163 | Try also: 164 | 165 | $ git whatchanged --since="2 weeks ago" 166 | 167 | Often I'll browse history with http://sourceforge.net/projects/qgit[qgit] 168 | instead, due to its slick photogenic interface, or 169 | http://jonas.nitro.dk/tig/[tig], a text-mode interface that works well over 170 | slow connections. Alternatively, install a web server, run *git instaweb* and 171 | fire up any web browser. 172 | 173 | === Exercise === 174 | 175 | Let A, B, C, D be four successive commits where B is the same as A except some files have been removed. We want to add the files back at D and not at B. How can we do this? 176 | 177 | There are at least three solutions. Assuming we are at D: 178 | 179 | 1. The difference between A and B are the removed files. We can create a patch representing this difference and apply it: 180 | 181 | $ git diff B A | git apply 182 | 183 | 2. Since we saved the files back at A, we can retrieve them: 184 | 185 | $ git checkout A FILES... 186 | 187 | 3. We can view going from A to B as a change we want to undo: 188 | 189 | $ git revert B 190 | 191 | Which choice is best? Whichever you prefer most. It is easy to get what you want with Git, and often there are many ways to get it. 192 | -------------------------------------------------------------------------------- /en/branch.txt: -------------------------------------------------------------------------------- 1 | == Branch Wizardry == 2 | 3 | Instant branching and merging are the most lethal of Git's killer features. 4 | 5 | *Problem*: External factors inevitably necessitate context switching. A severe 6 | bug manifests in the released version without warning. The deadline for a 7 | certain feature is moved closer. A developer whose help you need for a key section of the project is about to leave. In all cases, you must abruptly drop what you are doing and focus on a completely different task. 8 | 9 | Interrupting your train of thought can be detrimental to your productivity, and the more cumbersome it is to switch contexts, the greater the loss. With centralized version control we must download a fresh working copy from the central server. Distributed systems fare better, as we can clone the desired version locally. 10 | 11 | But cloning still entails copying the whole working directory as well as the entire history up to the given point. Even though Git reduces the cost of this with file sharing and hard links, the project files themselves must be recreated in their entirety in the new working directory. 12 | 13 | *Solution*: Git has a better tool for these situations that is much faster and more space-efficient than cloning: *git branch*. 14 | 15 | With this magic word, the files in your directory suddenly shapeshift from one version to another. This transformation can do more than merely go back or forward in history. Your files can morph from the last release to the experimental version to the current development version to your friend's version and so on. 16 | 17 | === The Boss Key === 18 | 19 | Ever play one of those games where at the push of a button ("the boss key"), the screen would instantly display a spreadsheet or something? So if the boss walked in the office while you were playing the game you could quickly hide it away? 20 | 21 | In some directory: 22 | 23 | $ echo "I'm smarter than my boss" > myfile.txt 24 | $ git init 25 | $ git add . 26 | $ git commit -m "Initial commit" 27 | 28 | We have created a Git repository that tracks one text file containing a certain message. Now type: 29 | 30 | $ git checkout -b boss # nothing seems to change after this 31 | $ echo "My boss is smarter than me" > myfile.txt 32 | $ git commit -a -m "Another commit" 33 | 34 | It looks like we've just overwritten our file and committed it. But it's an illusion. Type: 35 | 36 | $ git checkout master # switch to original version of the file 37 | 38 | and hey presto! The text file is restored. And if the boss decides to snoop around this directory, type: 39 | 40 | $ git checkout boss # switch to version suitable for boss' eyes 41 | 42 | You can switch between the two versions of the file as much as you like, and commit to each independently. 43 | 44 | === Dirty Work === 45 | 46 | [[branch]] 47 | Say you're working on some feature, and for some reason, you need to go back to an old version and temporarily put in a few prints statements to see how something works. Then: 48 | 49 | $ git commit -a 50 | $ git checkout SHA1_HASH 51 | 52 | Now you can add ugly temporary code all over the place. You can even commit these changes. When you're done, 53 | 54 | $ git checkout master 55 | 56 | to return to your original work. Observe that any uncommitted changes are carried over. 57 | 58 | What if you wanted to save the temporary changes after all? Easy: 59 | 60 | $ git checkout -b dirty 61 | 62 | and commit before switching back to the master branch. Whenever you want to return to the dirty changes, simply type 63 | 64 | $ git checkout dirty 65 | 66 | We touched upon this command in an earlier chapter, when discussing loading old states. At last we can tell the whole story: the files change to the requested state, but we must leave the master branch. Any commits made from now on take your files down a different road, which can be named later. 67 | 68 | In other words, after checking out an old state, Git automatically puts you in a new, unnamed branch, which can be named and saved with *git checkout -b*. 69 | 70 | === Quick Fixes === 71 | 72 | You're in the middle of something when you are told to drop everything and fix a newly discovered bug: 73 | 74 | $ git commit -a 75 | $ git checkout -b fixes SHA1_HASH 76 | 77 | Then once you've fixed the bug: 78 | 79 | $ git commit -a -m "Bug fixed" 80 | $ git push # to the central repository 81 | $ git checkout master 82 | 83 | and resume work on your original task. 84 | 85 | === Uninterrupted Workflow === 86 | 87 | Some projects require your code to be reviewed before you may submit it. To make life easier for those reviewing your code, if you have a big change to make you might break it into two or more parts, and get each part separately reviewed. 88 | 89 | What if the second part cannot be written until the first part is approved and checked in? In many version control systems, you'd have to send the first part to the reviewers, and then wait until it has been approved before starting on the second part. 90 | 91 | Actually that's not quite true, but in these systems editing Part II before submitting Part I involves suffering and hardship. In Git, branching and merging are painless (a technical term for fast and local). So after you've committed the first part and sent it for review: 92 | 93 | $ git checkout -b part2 94 | 95 | Next, code the second part of the big change without waiting for the first part to be accepted. When the first part is approved and submitted, 96 | 97 | $ git checkout master 98 | $ git merge part2 99 | $ git branch -d part2 # don't need this branch anymore 100 | 101 | and the second part of the change is ready to review. 102 | 103 | But wait! What if it wasn't that simple? Say you made a mistake in the first part, which you have to correct before submitting. No problem! First, switch back to the master branch with 104 | 105 | $ git checkout master 106 | 107 | Fix the issue with the first part of the change and hope it gets approved. If not we simply repeat this step. You'll probably want to merge the fixed version of Part I into Part II as well: 108 | 109 | $ git checkout part2 110 | $ git merge master 111 | 112 | Now it's the same as before. Once the first part has been approved and submitted: 113 | 114 | $ git checkout master 115 | $ git merge part2 116 | $ git branch -d part2 117 | 118 | and again, the second part is ready to be reviewed. 119 | 120 | It's easy to extend this trick for any number of parts. 121 | 122 | === Reorganizing a Medley === 123 | 124 | Perhaps you like to work on all aspects of a project in the same branch. You want to keep works-in-progress to yourself and want others to see your commits only when they have been neatly organized. Start a couple of branches: 125 | 126 | $ git checkout -b sanitized 127 | $ git checkout -b medley 128 | 129 | Next, work on anything: fix bugs, add features, add temporary code, and so forth, committing often along the way. Then: 130 | 131 | $ git checkout sanitized 132 | $ git cherry-pick SHA1_HASH 133 | 134 | applies a given commit to the "sanitized" branch. With appropriate cherry-picks you can construct a branch that contains only permanent code, and has related commits grouped together. 135 | 136 | === Managing Branches === 137 | 138 | List all branches by typing: 139 | 140 | $ git branch 141 | 142 | There is always a branch named "master", and you start here by default. Some 143 | advocate leaving the "master" branch untouched and creating new branches for 144 | your own edits. 145 | 146 | The *-d* and *-m* options allow you to delete and move (rename) branches. 147 | See *git help branch*. 148 | 149 | The "master" branch is a useful convention. Others may assume that your 150 | repository has a branch with this name, and that it contains the official 151 | version of your project. You can rename or obliterate the "master" branch, but 152 | you might as well respect this custom. 153 | 154 | === Temporary Branches === 155 | 156 | After a while you may realize you are creating short-lived branches 157 | frequently for similar reasons: every other branch merely serves to 158 | save the current state so you can briefly hop back to an older state to 159 | fix a high-priority bug or something. 160 | 161 | It's analogous to changing the TV channel temporarily to see what else is on. 162 | But instead of pushing a couple of buttons, you have to create, check out and 163 | delete temporary branches and commits. Luckily, Git has a shorcut that 164 | is as convenient as a TV remote control: 165 | 166 | $ git stash 167 | 168 | This saves the current state in a temporary location (a 'stash') and 169 | restores the previous state. Your working directory appears exactly as it was 170 | before you started editing, and you can fix bugs, pull in upstream changes, and 171 | so on. When you want to go back to the stashed state, type: 172 | 173 | $ git stash apply # You may need to resolve some conflicts. 174 | 175 | You can have multiple stashes, and manipulate them in various ways. See 176 | *git help stash*. As you may have guessed, Git maintains branches behind the scenes to perform this magic trick. 177 | 178 | === Work How You Want === 179 | 180 | Applications such as http://www.mozilla.com/[Mozilla Firefox] allow you to open multiple tabs and multiple windows. Switching tabs gives you different content in the same window. Git branching is like tabs for your working directory. Continuing this analogy, Git cloning is like opening a new window. Being able to do both improves the user experience. 181 | 182 | On a higher level, several Linux window managers support multiple desktops. 183 | Branching in Git is similar to switching to a different desktop, while cloning 184 | is similar to attaching another monitor to gain another desktop. 185 | 186 | Yet another example is the http://www.gnu.org/software/screen/[*screen*] utility. This gem lets you create, destroy and switch between multiple terminal sessions in the same terminal. Instead of opening new terminals (clone), you can use the same one if you run *screen* (branch). In fact, you can do a lot more with *screen* but that's a topic for another text. 187 | 188 | Cloning, branching, and merging are fast and local in Git, encouraging you to use the combination that best suits you. Git lets you work exactly how you want. 189 | -------------------------------------------------------------------------------- /en/clone.txt: -------------------------------------------------------------------------------- 1 | == Cloning Around == 2 | 3 | In older version control systems, checkout is the standard operation to get files. You retrieve a bunch of files in the requested saved state. 4 | 5 | In Git and other distributed version control systems, cloning is the standard operation. To get files you create a clone of the entire repository. In other words, you practically mirror the central server. Anything the main repository can do, you can do. 6 | 7 | === Sync Computers === 8 | 9 | This is the reason I first used Git. I can tolerate making tarballs or using *rsync* for backups and basic syncing. But sometimes I edit on my laptop, other times on my desktop, and the two may not have talked to each other in between. 10 | 11 | Initialize a Git repository and commit your files on one machine. Then on the other: 12 | 13 | $ git clone other.computer:/path/to/files 14 | 15 | to create a second copy of the files and Git repository. From now on, 16 | 17 | $ git commit -a 18 | $ git pull other.computer:/path/to/files HEAD 19 | 20 | will pull in the state of the files on the other computer into the one you're working on. If you've recently made conflicting edits in the same file, Git will let you know and you should commit again after resolving them. 21 | 22 | === Classic Source Control === 23 | 24 | Initialize a Git repository for your files: 25 | 26 | $ git init 27 | $ git add . 28 | $ git commit -m "Initial commit" 29 | 30 | On the central server, initialize an empty Git repository with some name, 31 | and start the Git daemon if necessary: 32 | 33 | $ GIT_DIR=proj.git git init 34 | $ git daemon --detach # it might already be running 35 | 36 | For Git hosting services, follow the instructions to setup the initially 37 | empty Git repository. Typically one fills in a form on a webpage. 38 | 39 | Push your project to the central server with: 40 | 41 | $ git push git://central.server/path/to/proj.git HEAD 42 | 43 | We're ready. To check out source, a developer types 44 | 45 | $ git clone git://central.server/path/to/proj.git 46 | 47 | After making changes, the code is checked in to the main server by: 48 | 49 | $ git commit -a 50 | $ git push 51 | 52 | If the main server has been updated, the latest version needs to be checked out before the push. To sync to the latest version: 53 | 54 | $ git commit -a 55 | $ git pull 56 | 57 | ==== Push versus pull ==== 58 | 59 | We mostly avoid pushing into a repository, because confusion can ensue 60 | if the destination has a working directory with changes. However, pushing into 61 | a bare repository is a straightforward operation and more suitable than a pull 62 | in this case. 63 | 64 | Pulling from the server requires shelling into the server, and also 65 | knowing the network address of the machine you happen to be working on. 66 | Furthermore, firewalls may interfere. 67 | 68 | === Forking a Project === 69 | 70 | Sick of the way a project is being run? Think you could do a better job? Then on your server: 71 | 72 | $ git clone git://main.server/path/to/files 73 | 74 | Next tell everyone about your fork of the project at your server. 75 | 76 | At any later time, you can merge in the changes from the original project with: 77 | 78 | $ git pull 79 | 80 | === Ultimate Backups === 81 | 82 | Want numerous tamper-proof geographically diverse redundant archives? If your project has many developers, don't do anything! Every clone of your code is effectively a backup. Not just of the current state, but of your project's entire history. Thanks to cryptographic hashing, if anyone's clone becomes corrupted, it will be spotted as soon as they try to communicate with others. 83 | 84 | If your project is not so popular, find as many servers as you can to host clones. 85 | 86 | The truly paranoid should always write down the latest 20-byte SHA1 hash of the HEAD somewhere safe. It has to be safe, not private. For example, publishing it in a newspaper would work well, because it's hard for an attacker to alter every copy of a newspaper. 87 | 88 | === Light-Speed Multitask === 89 | 90 | Say you want to work on several features in parallel. Then commit your project and run: 91 | 92 | $ git clone . /some/new/directory 93 | 94 | Git exploits hard links and file sharing as much as safely possible to create this clone, so it will be ready in a flash, and you can now work on two independent features simultaneously. For example, you can edit one clone while the other is compiling. 95 | 96 | At any time, you can commit and pull changes from the other clone. 97 | 98 | $ git pull /the/other/clone HEAD 99 | 100 | === Guerilla Version Control === 101 | 102 | Are you working on a project that uses some other version control system, and you sorely miss Git? Then initialize a Git repository in your working directory: 103 | 104 | $ git init 105 | $ git add . 106 | $ git commit -m "Initial commit" 107 | 108 | then clone it: 109 | 110 | $ git clone . /some/new/directory 111 | 112 | Now go to the new directory and work here instead, using Git to your heart's content. Once in a while, you'll want to sync with everyone else, in which case go to the original directory, sync using the other version control system, and type: 113 | 114 | $ git add . 115 | $ git commit -m "Sync with everyone else" 116 | 117 | Then go to the new directory and run: 118 | 119 | $ git commit -a -m "Description of my changes" 120 | $ git pull 121 | 122 | The procedure for giving your changes to everyone else depends on the other version control system. The new directory contains the files with your changes. Run whatever commands of the other version control system are needed to upload them to the central repository. 123 | 124 | The *git svn* command automates the above for Subversion repositories, and can 125 | also be used to 126 | http://google-opensource.blogspot.com/2008/05/export-git-project-to-google-code.html[export a Git project to a Subversion repository]. 127 | -------------------------------------------------------------------------------- /en/drawbacks.txt: -------------------------------------------------------------------------------- 1 | == Appendix A: Git Shortcomings == 2 | 3 | There are some Git issues I've swept under the carpet. Some can be handled easily with scripts and hooks, some require reorganizing or redefining the project, and for the few remaining annoyances, one will just have to wait. Or better yet, pitch in and help! 4 | 5 | === SHA1 Weaknesses === 6 | 7 | As time passes, cryptographers discover more and more SHA1 weaknesses. Already, 8 | finding hash collisions is feasible for well-funded organizations. Within 9 | years, perhaps even a typical PC will have enough computing power to silently 10 | corrupt a Git repository. 11 | 12 | Hopefully Git will migrate to a better hash function before further research 13 | destroys SHA1. 14 | 15 | === Microsoft Windows === 16 | 17 | Git on Microsoft Windows can be cumbersome: 18 | 19 | - http://cygwin.com/[Cygwin], a Linux-like environment for Windows, contains http://cygwin.com/packages/git/[a Windows port of Git]. 20 | 21 | - http://code.google.com/p/msysgit/[Git on MSys] is an alternative requiring minimal runtime support, though a few of the commands need some work. 22 | 23 | === Unrelated Files === 24 | 25 | If your project is very large and contains many unrelated files that are constantly being changed, Git may be disadvantaged more than other systems because single files are not tracked. Git tracks changes to the whole project, which is usually beneficial. 26 | 27 | A solution is to break up your project into pieces, each consisting of related files. Use *git submodule* if you still want to keep everything in a single repository. 28 | 29 | === Who's Editing What? === 30 | 31 | Some version control systems force you to explicitly mark a file in some way before editing. While this is especially annoying when this involves talking to a central server, it does have two benefits: 32 | 33 | 1. Diffs are quick because only the marked files need be examined. 34 | 35 | 2. One can discover who else is working on the file by asking the central server who has marked it for editing. 36 | 37 | With appropriate scripting, you can achieve the same with Git. This requires cooperation from the programmer, who should execute particular scripts when editing a file. 38 | 39 | === File History === 40 | 41 | Since Git records project-wide changes, reconstructing the history of a single file requires more work than in version control systems that track individual files. 42 | 43 | The penalty is typically slight, and well worth having as other operations are incredibly efficient. For example, `git checkout` is faster than `cp -a`, and project-wide deltas compress better than collections of file-based deltas. 44 | 45 | === Initial Clone === 46 | 47 | Creating a clone is more expensive than checking out code in other version control systems when there is a lengthy history. 48 | 49 | The initial cost is worth paying in the long run, as most future operations will then be fast and offline. However, in some situations, it may be preferable to create a shallow clone with the `--depth` option. This is much faster, but the resulting clone has reduced functionality. 50 | 51 | === Volatile Projects === 52 | 53 | Git was written to be fast with respect to the size of the changes. Humans make small edits from version to version. A one-liner bugfix here, a new feature there, emended comments, and so forth. But if your files are radically different in successive revisions, then on each commit, your history necessarily grows by the size of your whole project. 54 | 55 | There is nothing any version control system can do about this, but standard Git users will suffer more since normally histories are cloned. 56 | 57 | The reasons why the changes are so great should be examined. Perhaps file formats should be changed. Minor edits should only cause minor changes to at most a few files. 58 | 59 | Or perhaps a database or backup/archival solution is what is actually being sought, not a version control system. For example, version control may be ill-suited for managing photos periodically taken from a webcam. 60 | 61 | If the files really must be constantly morphing and they really must be versioned, a possibility is to use Git in a centralized fashion. One can create shallow clones, which checks out little or no history of the project. Of course, many Git tools will be unavailable, and fixes must be submitted as patches. This is probably fine as it's unclear why anyone would want the history of wildly unstable files. 62 | 63 | Another example is a project depending on firmware, which takes the form of a huge binary file. The history of the firmware is uninteresting to users, and updates compress poorly, so firmware revisions would unnecessarily blow up the size of the repository. 64 | 65 | In this case, the source code should be stored in a Git repository, and the binary file should be kept separately. To make life easier, one could distribute a script that uses Git to clone the code, and rsync or a Git shallow clone for the firmware. 66 | 67 | === Global Counter === 68 | 69 | Some centralized version control systems maintain a positive integer that increases when a new commit is accepted. Git refers to changes by their hash, which is better in many circumstances. 70 | 71 | But some people like having this integer around. Luckily, it's easy to write scripts so that with every update, the central Git repository increments an integer, perhaps in a tag, and associates it with the hash of the latest commit. 72 | 73 | Every clone could maintain such a counter, but this would probably be useless, since only the central repository and its counter matters to everyone. 74 | 75 | === Empty Subdirectories === 76 | 77 | Empty subdirectories cannot be tracked. Create dummy files to work around this problem. 78 | 79 | The current implementation of Git, rather than its design, is to blame for this drawback. With luck, once Git gains more traction, more users will clamour for this feature and it will be implemented. 80 | 81 | === Initial Commit === 82 | 83 | A stereotypical computer scientist counts from 0, rather than 1. Unfortunately, with respect to commits, git does not adhere to this convention. Many commands are unfriendly before the initial commit. Additionally, some corner cases must be handled specially, such as rebasing a branch with a different initial commit. 84 | 85 | Git would benefit from defining the zero commit: as soon as a repository is constructed, HEAD would be set to the string consisting of 20 zero bytes. This special commit represents an empty tree, with no parent, at some time predating all Git repositories. 86 | 87 | Then running git log, for example, would inform the user that no commits have been made yet, instead of exiting with a fatal error. Similarly for other tools. 88 | 89 | Every initial commit is implicitly a descendant of this zero commit. For example, rebasing an unrelated branch would cause the whole branch to be grafted on to the target. Currently, all but the initial commit is applied, resulting in a merge conflict. One workaround is to use `git checkout` followed by `git commit -C` on the initial commit, then rebase the rest. 90 | 91 | There are worse cases unfortunately. If several branches with different initial commits are merged together, then rebasing the result requires substantial manual intervention. 92 | 93 | === Interface Quirks === 94 | 95 | For commits A, B, the meaning of the expressions "A..B" and "A...B" depends 96 | on whether the command expects two endpoints or a range. See *git help diff* 97 | and *git help rev-parse*. 98 | 99 | Some error messages are inscrutable. For example, if Git cannot create the 100 | lockfile +packed-refs.lock+, then you might see: 101 | 102 | $ git branch -D foo 103 | error: cannot delete 'refs/heads/foo' from packed refs 104 | error: Error deleting branch 'foo' 105 | 106 | This could happen if say filesystem trouble prevented the lockfile from being 107 | deleted in a previous Git command. In this case the solution is to delete the 108 | lockfile and try again, after ensuring no Git commands are still running. 109 | 110 | The push command ignores the state of the working directory of the target 111 | repository. To prevent confusion, push only into bare repositories, or setup a 112 | dedicated push-only branch. 113 | -------------------------------------------------------------------------------- /en/grandmaster.txt: -------------------------------------------------------------------------------- 1 | == Git Grandmastery == 2 | 3 | This pretentiously named page is my dumping ground for uncategorized Git tricks. 4 | 5 | === Source Releases === 6 | 7 | For my projects, Git tracks exactly the files I'd like to archive and release 8 | to users. To create a tarball of the source code, I run: 9 | 10 | $ git archive --format=tar --prefix=proj-1.2.3/ HEAD 11 | 12 | === Commit What Changed === 13 | 14 | Telling Git when you've added, deleted and renamed files is troublesome for 15 | certain projects. Instead, you can type: 16 | 17 | $ git add . 18 | $ git add -u 19 | 20 | Git will look at the files in the current directory and work out the details by 21 | itself. Instead of the second add command, run `git commit -a` if you also 22 | intend to commit at this time. See *git help ignore* for how to specify files 23 | that should be ignored. 24 | 25 | You can perform the above in a single pass with: 26 | 27 | $ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove 28 | 29 | The *-z* and *-0* options prevent ill side-effects from filenames containing 30 | strange characters. As this command adds ignored files, you may want to use the 31 | `-x` or `-X` option. 32 | 33 | === My Commit Is Too Big! === 34 | 35 | Have you neglected to commit for too long? Been coding furiously and forgotten 36 | about source control until now? Made a series of unrelated changes, because 37 | that's your style? 38 | 39 | No worries. Run: 40 | 41 | $ git add -p 42 | 43 | For each edit you made, Git will show you the hunk of code that was changed, 44 | and ask if it should be part of the next commit. Answer with "y" or "n". You 45 | have other options, such as postponing the decision; type "?" to learn more. 46 | 47 | Once you're satisfied, type 48 | 49 | $ git commit 50 | 51 | to commit precisely the changes you selected (the 'staged' changes). Make sure 52 | you omit the *-a* option, otherwise Git will commit all the edits. 53 | 54 | What if you've edited many files in many places? Reviewing each change one by 55 | one becomes frustratingly mind-numbing. In this case, use *git add -i*, whose 56 | interface is less straightforward, but more flexible. With a few keystrokes, 57 | you can stage or unstage several files at a time, or review and select changes 58 | in particular files only. Alternatively, run *git commit \--interactive* which 59 | automatically commits after you're done. 60 | 61 | ==== Staged Changes ==== 62 | 63 | So far we have avoided Git's famous 'index', but we must now confront it to 64 | explain the above. The index is a temporary staging area. Git seldom shuttles 65 | data directly between your project and its history. Rather, Git first writes 66 | data to the index, and then copies the data in the index to its final 67 | destination. 68 | 69 | For example, *commit -a* is really a two-step process. The first step places a 70 | snapshot of the current state of every tracked file into the index. The second 71 | step permanently records the snapshot now in the index. Committing without the 72 | *-a* option only performs the second step, and only makes sense after running 73 | commands that somehow change the index, such as *git add*. 74 | 75 | Usually we can ignore the index and pretend we are reading straight from and writing straight to the history. On this occasion, we want finer control on what gets written to history, and are forced to manipulate the index. We place a snapshot of some, but not all, of our changes into the index, and then permanently record this carefully rigged snapshot. 76 | 77 | === Don't Lose Your HEAD === 78 | 79 | The HEAD tag is like a cursor that normally points at the latest commit, advancing with each new commit. Some Git commands let you move it. For example: 80 | 81 | $ git reset HEAD~3 82 | 83 | will move the HEAD three commits back. Thus all Git commands now act as if you hadn't made those last three commits, while your files remain in the present. See the help page for some applications. 84 | 85 | But how can you go back to the future? The past commits know nothing of the future. 86 | 87 | If you have the SHA1 of the original HEAD then: 88 | 89 | $ git reset SHA1 90 | 91 | But suppose you never took it down? Don't worry, for commands like these, Git saves the original HEAD as a tag called ORIG_HEAD, and you can return safe and sound with: 92 | 93 | $ git reset ORIG_HEAD 94 | 95 | === HEAD-hunting === 96 | 97 | Perhaps ORIG_HEAD isn't enough. Perhaps you've just realized you made a monumental mistake and you need to go back to an ancient commit in a long-forgotten branch. 98 | 99 | By default, Git keeps a commit for at least two weeks, even if you ordered 100 | Git to destroy the branch containing it. The trouble is finding the appropriate 101 | hash. You could look at all the hash values in `.git/objects` and use trial 102 | and error to find the one you want. But there's a much easier way. 103 | 104 | Git records every hash of a commit it computes in `.git/logs`. The subdirectory `refs` contains the history of all activity on all branches, while the file `HEAD` shows every hash value it has ever taken. The latter can be used to find hashes of commits on branches that have been accidentally lopped off. 105 | 106 | The reflog command provides a friendly interface to these log files. Try 107 | 108 | $ git reflog 109 | 110 | Instead of cutting and pasting hashes from the reflog, try: 111 | 112 | $ git checkout "@{10 minutes ago}" 113 | 114 | Or checkout the 5th-last visited commit via: 115 | 116 | $ git checkout "@{5}" 117 | 118 | See the ``Specifying Revisions'' section of *git help rev-parse* for more. 119 | 120 | You may wish to configure a longer grace period for doomed commits. For 121 | example: 122 | 123 | $ git config gc.pruneexpire "30 days" 124 | 125 | means a deleted commit will only be permanently lost once 30 days have passed 126 | and *git gc* is run. 127 | 128 | You may also wish to disable automatic invocations of *git gc*: 129 | 130 | $ git conifg gc.auto 0 131 | 132 | in which case commits will only be deleted when you run *git gc* manually. 133 | 134 | === Building On Git === 135 | 136 | In true UNIX fashion, Git's design allows it to be easily used as a low-level component of other programs, such as GUI and web interfaces, alternative command-line interfaces, patch managements tools, importing and conversion tools and so on. In fact, some Git commands are themselves scripts standing on the shoulders of giants. With a little tinkering, you can customize Git to suit your preferences. 137 | 138 | One easy trick is to use built-in Git aliases to shorten your most frequently 139 | used commands: 140 | 141 | $ git config --global alias.co checkout 142 | $ git config --global --get-regexp alias # display current aliases 143 | alias.co checkout 144 | $ git co foo # same as 'git checkout foo' 145 | 146 | Another is to print the current branch in the prompt, or window title. 147 | Invoking 148 | 149 | $ git symbolic-ref HEAD 150 | 151 | shows the current branch name. In practice, you most likely want to remove 152 | the "refs/heads/" and ignore errors: 153 | 154 | $ git symbolic-ref HEAD 2> /dev/null | cut -b 12- 155 | 156 | The +contrib+ subdirectory is a treasure trove of tools built on Git. 157 | In time, some of them may be promoted to official commands. On Debian and 158 | Ubuntu, this directory lives at +/usr/share/doc/git-core/contrib+. 159 | 160 | One popular resident is +workdir/git-new-workdir+. Via clever symlinking, this script creates a new working directory whose history is shared with the original respository: 161 | 162 | $ git-new-workdir an/existing/repo new/directory 163 | 164 | The new directory and files within can be thought of as a clone, except since the history is shared, the two trees automatically stay in sync. There's no need to merge, push or pull. 165 | 166 | === Daring Stunts === 167 | 168 | These days, Git makes it difficult for the user to accidentally destroy data. 169 | But if you know what you are doing, you can override safeguards for common 170 | commands. 171 | 172 | *Checkout*: Uncommitted changes cause checkout to fail. To destroy your changes, and checkout a given commit anyway, use the force flag: 173 | 174 | $ git checkout -f COMMIT 175 | 176 | On the other hand, if you specify particular paths for checkout, then there are no safety checks. The supplied paths are quietly overwritten. Take care if you use checkout in this manner. 177 | 178 | *Reset*: Reset also fails in the presence of uncommitted changes. To force it through, run: 179 | 180 | $ git reset --hard [COMMIT] 181 | 182 | *Branch*: Deleting branches fails if this causes changes to be lost. To force a deletion, type: 183 | 184 | $ git branch -D BRANCH # instead of -d 185 | 186 | Similarly, attempting to overwrite a branch via a move fails if data loss would ensue. To force a branch move, type: 187 | 188 | $ git branch -M [SOURCE] TARGET # instead of -m 189 | 190 | Unlike checkout and reset, these two commands defer data destruction. The 191 | changes are still stored in the .git subdirectory, and can be retrieved by 192 | recovering the appropriate hash from `.git/logs` (see "HEAD-hunting" above). 193 | By default, they will be kept for at least two weeks. 194 | 195 | *Clean*: Some git commands refuse to proceed because they're worried about 196 | clobbering untracked files. If you're certain that all untracked files and 197 | directories are expendable, then delete them mercilessly with: 198 | 199 | $ git clean -f -d 200 | 201 | Next time, that pesky command will work! 202 | 203 | === Improve Your Public Image === 204 | 205 | Stupid mistakes abound in the histories of many of my projects. The most 206 | frightening are missing files due to forgetting to run *git add*. Luckily I 207 | have yet to lose crucial data though accidental omission because I rarely 208 | delete original working directories. I typically notice the error a few commits 209 | later, so the only damage is a bit of missing history and a sheepish admission 210 | of guilt. 211 | 212 | I also regularly commit (literally and git-erally) the lesser transgression of 213 | trailing whitespace. Though harmless, I wish these also never appeared on the 214 | public record. 215 | 216 | In addition, though unscathed so far, I worry about leaving merge conflicts 217 | unresolved. Usually I catch them when I build a project, but there are some 218 | cases this can overlook. 219 | 220 | If only I had bought idiot insurance by using a _hook_ to alert me about these 221 | problems: 222 | 223 | $ cd .git/hooks 224 | $ cp pre-commit.sample pre-commit # Older Git versions: chmod +x pre-commit 225 | 226 | Now Git aborts a commit if useless whitespace or unresolved merge conflicts are 227 | detected. 228 | 229 | For this guide, I eventually added the following to the beginning of the 230 | *pre-commit* hook to guard against absent-mindedness: 231 | 232 | if git ls-files -o | grep '\.txt$'; then 233 | echo FAIL! Untracked .txt files. 234 | exit 1 235 | fi 236 | 237 | Several git operations support hooks; see *git help hooks*. One can write hooks 238 | to complain about spelling mistakes in commit messages, add new files, indent 239 | paragraphs, append an entry to a webpage, play a sound, and so on. 240 | 241 | We encountered the *post-update* hook earlier when discussing Git over 242 | HTTP. This hook updates a few files Git needs for non-native communication. 243 | -------------------------------------------------------------------------------- /en/history.txt: -------------------------------------------------------------------------------- 1 | == Lessons of History == 2 | 3 | A consequence of Git's distributed nature is that history can be edited 4 | easily. But if you tamper with the past, take care: only rewrite that part of 5 | history which you alone possess. Just as nations forever argue over who 6 | committed what atrocity, if someone else has a clone whose version of history 7 | differs to yours, you will have trouble reconciling when your trees interact. 8 | 9 | Of course, if you control all the other trees too, then there is no problem 10 | since you can overwrite them. 11 | 12 | Some developers strongly feel history should be immutable, warts and all. 13 | Others feel trees should be made presentable before they are unleashed in 14 | public. Git accommodates both viewpoints. Like cloning, branching and merging, 15 | rewriting history is simply another power Git gives you. It is up to you 16 | to use it wisely. 17 | 18 | === I Stand Corrected === 19 | 20 | Did you just commit, but wish you had typed a different message? Then run: 21 | 22 | $ git commit --amend 23 | 24 | to change the last message. Realized you forgot to add a file? Run *git add* to 25 | add it, and then run the above command. 26 | 27 | Want to include a few more edits in that last commit? Then make those edits and run: 28 | 29 | $ git commit --amend -a 30 | 31 | === ... And Then Some === 32 | 33 | Let's suppose the previous problem is ten times worse. After a lengthy session you've made a bunch of commits. But you're not quite happy with the way they're organized, and some of those commit messages could use rewording. Then type: 34 | 35 | $ git rebase -i HEAD~10 36 | 37 | and the last 10 commits will appear in your favourite $EDITOR. A sample excerpt: 38 | 39 | pick 5c6eb73 Added repo.or.cz link 40 | pick a311a64 Reordered analogies in "Work How You Want" 41 | pick 100834f Added push target to Makefile 42 | 43 | Then: 44 | 45 | - Remove commits by deleting lines. 46 | - Reorder commits by reordering lines. 47 | - Replace "pick" with "edit" to mark a commit for amending. 48 | - Replace "pick" with "squash" to merge a commit with the previous one. 49 | 50 | If you marked a commit for editing, then run: 51 | 52 | $ git commit --amend 53 | 54 | Otherwise, run: 55 | 56 | $ git rebase --continue 57 | 58 | So commit early and commit often: you can easily tidy up later with rebase. 59 | 60 | === Local Changes Last === 61 | 62 | You're working on an active project. You make some local commits over time, and 63 | then you sync with the official tree with a merge. This cycle repeats itself a few times before you're ready to push to the central tree. 64 | 65 | But now the history in your local Git clone is a messy jumble of your changes and the official changes. You'd prefer to see all your changes in one contiguous section, and after all the official changes. 66 | 67 | This is a job for *git rebase* as described above. In many cases you can use 68 | the *--onto* flag and avoid interaction. 69 | 70 | Also see *git help rebase* for detailed examples of this amazing command. You can split commits. You can even rearrange branches of a tree. 71 | 72 | === Rewriting History === 73 | 74 | Occasionally, you need the source control equivalent of airbrushing people out 75 | of official photos, erasing them from history in a Stalinesque fashion. For 76 | example, suppose we intend to release a project, but it involves a file that 77 | should be kept private for some reason. Perhaps I left my credit card number in 78 | a text file and accidentally added it to the project. Deleting the file is 79 | insufficient, for the file can be accessed from older commits. We must remove 80 | the file from all commits: 81 | 82 | $ git filter-branch --tree-filter 'rm top/secret/file' HEAD 83 | 84 | See *git help filter-branch*, which discusses this example and gives a faster 85 | method. In general, *filter-branch* lets you alter large sections of history 86 | with a single command. 87 | 88 | Afterwards, the +.git/refs/original+ directory describes the state of affairs before the operation. Check the filter-branch command did what you wanted, then delete this directory if you wish to run more filter-branch commands. 89 | 90 | Lastly, replace clones of your project with your revised version if you want to interact with them later. 91 | 92 | === Making History === 93 | 94 | [[makinghistory]] 95 | Want to migrate a project to Git? If it's managed with one of the more well-known systems, then chances are someone has already written a script to export the whole history to Git. 96 | 97 | Otherwise, look up *git fast-import*, which reads text input in a specific 98 | format to create Git history from scratch. Typically a script using this 99 | command is hastily cobbled together and run once, migrating the project in a 100 | single shot. 101 | 102 | As an example, paste the following listing into temporary file, such as `/tmp/history`: 103 | ---------------------------------- 104 | commit refs/heads/master 105 | committer Alice Thu, 01 Jan 1970 00:00:00 +0000 106 | data < 113 | 114 | int main() { 115 | printf("Hello, world!\n"); 116 | return 0; 117 | } 118 | EOT 119 | 120 | 121 | commit refs/heads/master 122 | committer Bob Tue, 14 Mar 2000 01:59:26 -0800 123 | data < 130 | 131 | int main() { 132 | write(1, "Hello, world!\n", 14); 133 | return 0; 134 | } 135 | EOT 136 | 137 | ---------------------------------- 138 | 139 | Then create a Git repository from this temporary file by typing: 140 | 141 | $ mkdir project; cd project; git init 142 | $ git fast-import < /tmp/history 143 | 144 | You can checkout the latest version of the project with: 145 | 146 | $ git checkout master . 147 | 148 | The *git fast-export* command converts any git repository to the 149 | *git fast-import* format, whose output you can study for writing exporters, 150 | and also to transport git repositories in a human-readable format. Indeed, 151 | these commands can send repositories of text files over text-only channels. 152 | 153 | === Where Did It All Go Wrong? === 154 | 155 | You've just discovered a broken feature in your program which you know for sure was working a few months ago. Argh! Where did this bug come from? If only you had been testing the feature as you developed. 156 | 157 | It's too late for that now. However, provided you've been committing often, Git 158 | can pinpoint the problem: 159 | 160 | $ git bisect start 161 | $ git bisect bad SHA1_OF_BAD_VERSION 162 | $ git bisect good SHA1_OF_GOOD_VERSION 163 | 164 | Git checks out a state halfway in between. Test the feature, and if it's still broken: 165 | 166 | $ git bisect bad 167 | 168 | If not, replace "bad" with "good". Git again transports you to a state halfway 169 | between the known good and bad versions, narrowing down the possibilities. 170 | After a few iterations, this binary search will lead you to the commit that 171 | caused the trouble. Once you've finished your investigation, return to your 172 | original state by typing: 173 | 174 | $ git bisect reset 175 | 176 | Instead of testing every change by hand, automate the search by running: 177 | 178 | $ git bisect run COMMAND 179 | 180 | Git uses the return value of the given command, typically a one-off script, to 181 | decide whether a change is good or bad: the command should exit with code 0 182 | when good, 125 when the change should be skipped, and anything else between 1 183 | and 127 if it is bad. A negative return value aborts the bisect. 184 | 185 | You can do much more: the help page explains how to visualize bisects, examine 186 | or replay the bisect log, and eliminate known innocent changes for a speedier 187 | search. 188 | 189 | === Who Made It All Go Wrong? === 190 | 191 | Like many other version control systems, Git has a blame command: 192 | 193 | $ git blame FILE 194 | 195 | which annotates every line in the given file showing who last changed it, and when. Unlike many other version control systems, this operation works offline, reading only from local disk. 196 | 197 | === Personal Experience === 198 | 199 | In a centralized version control system, history modification is a difficult 200 | operation, and only available to administrators. Cloning, branching, and 201 | merging are impossible without network communication. So are basic operations 202 | such as browsing history, or committing a change. In some systems, users 203 | require network connectivity just to view their own changes or open a file for 204 | editing. 205 | 206 | Centralized systems preclude working offline, and need more expensive network 207 | infrastructure, especially as the number of developers grows. Most 208 | importantly, all operations are slower to some degree, usually to the point 209 | where users shun advanced commands unless absolutely necessary. In extreme 210 | cases this is true of even the most basic commands. When users must run slow 211 | commands, productivity suffers because of an interrupted work flow. 212 | 213 | I experienced these phenomena first-hand. Git was the first version control 214 | system I used. I quickly grew accustomed to it, taking many features for 215 | granted. I simply assumed other systems were similar: choosing a version 216 | control system ought to be no different from choosing a text editor or web 217 | browser. 218 | 219 | I was shocked when later forced to use a centralized system. My often flaky 220 | internet connection matters little with Git, but makes development unbearable 221 | when it needs to be as reliable as local disk. Additionally, I found myself 222 | conditioned to avoid certain commands because of the latencies involved, which 223 | ultimately prevented me from following my desired work flow. 224 | 225 | When I had to run a slow command, the interruption to my train of thought 226 | dealt a disproportionate amount of damage. While waiting for server 227 | communication to complete, I'd do something else to pass the time, such as 228 | check email or write documentation. By the time I returned to the original 229 | task, the command had finished long ago, and I would waste more time trying to 230 | remember what I was doing. Humans are bad at context switching. 231 | 232 | There was also an interesting tragedy-of-the-commons effect: anticipating 233 | network congestion, individuals would consume more bandwidth than necessary on 234 | various operations in an attempt to reduce future delays. The combined efforts 235 | intensified congestion, encouraging individuals to consume even more bandwidth 236 | next time to avoid even longer delays. 237 | -------------------------------------------------------------------------------- /en/intro.txt: -------------------------------------------------------------------------------- 1 | == Introduction == 2 | 3 | I'll use an analogy to introduce version control. See http://en.wikipedia.org/wiki/Revision_control[the Wikipedia entry on revision control] for a saner explanation. 4 | 5 | === Work is Play === 6 | 7 | I've played computer games almost all my life. In contrast, I only started using version control systems as an adult. I suspect I'm not alone, and comparing the two may make these concepts easier to explain and understand. 8 | 9 | Think of editing your code or document, or whatever, as playing a game. Once you've made a lot of progress, you'd like to save. To do so, you click on the "Save" button in your trusty editor. 10 | 11 | But this will overwrite the old version. It's like those old school games which only had one save slot: sure you could save, but you could never go back to an older state. Which was a shame, because your previous save might have been right at an exceptionally fun part of the game that you'd like to revisit one day. Or worse still, your current save is in an unwinnable state, and you have to start again. 12 | 13 | === Version Control === 14 | 15 | When editing, you can "Save As..." a different file, or copy the file somewhere first before saving if you want to savour old versions. You can compress them too to save space. This is a primitive and labour-intensive form of version control. Computer games improved on this long ago, many of them providing multiple automatically timestamped save slots. 16 | 17 | Let's make the problem slightly tougher. Say you have a bunch of files that go together, such as source code for a project, or files for a website. Now if you want to keep an old version you have to archive a whole directory. Keeping many versions around by hand is inconvenient, and quickly becomes expensive. 18 | 19 | With some computer games, a saved game really does consist of a directory full of files. These games hide this detail from the player and present a convenient interface to manage different versions of this directory. 20 | 21 | Version control systems are no different. They all have nice interfaces to manage a directory of stuff. You can save the state of the directory every so often, and you can load any one of the saved states later on. Unlike most computer games, they're usually smart about conserving space. Typically, only a few files change between version to version, and not by much. Storing the differences instead of entire new copies saves room. 22 | 23 | === Distributed Control === 24 | 25 | Now imagine a very difficult computer game. So difficult to finish that many experienced gamers all over the world decide to team up and share their saved games to try to beat it. Speedruns are real-life examples: players specializing in different levels of the same game collaborate to produce amazing results. 26 | 27 | How would you set up a system so they can get at each other's saves easily? And upload new ones? 28 | 29 | In the old days, every project used centralized version control. A server somewhere held all the saved games. Nobody else did. Every player kept at most a few saved games on their machine. When a player wanted to make progress, they'd download the latest save from the main server, play a while, save and upload back to the server for everyone else to use. 30 | 31 | What if a player wanted to get an older saved game for some reason? Maybe the current saved game is in an unwinnable state because somebody forgot to pick up an object back in level three, and they want to find the latest saved game where the game can still be completed. Or maybe they want to compare two older saved games to see how much work a particular player did. 32 | 33 | There could be many reasons to want to see an older revision, but the outcome is the same. They have to ask the central server for that old saved game. The more saved games they want, the more they need to communicate. 34 | 35 | The new generation of version control systems, of which Git is a member, are known as distributed systems, and can be thought of as a generalization of centralized systems. When players download from the main server they get every saved game, not just the latest one. It's as if they're mirroring the central server. 36 | 37 | This initial cloning operation can be expensive, especially if there's a long history, but it pays off in the long run. One immediate benefit is that when an old save is desired for any reason, communication with the central server is unnecessary. 38 | 39 | ==== A Silly Superstition ==== 40 | 41 | A popular misconception is that distributed systems are ill-suited for projects requiring an official central repository. Nothing could be further from the truth. Photographing someone does not cause their soul to be stolen. Similarly, cloning the master repository does not diminish its importance. 42 | 43 | A good first approximation is that anything a centralized version control system can do, a well-designed distributed system can do better. Network resources are simply costlier than local resources. While we shall later see there are drawbacks to a distributed approach, one is less likely to make erroneous comparisons with this rule of thumb. 44 | 45 | A small project may only need a fraction of the features offered by such a 46 | system, but saying you should use systems that don't scale well when your 47 | project is tiny is like saying you should use Roman numerals for calculations 48 | involving small numbers. 49 | 50 | Moreover, your project may grow beyond your original expectations. Using Git from the outset is like carrying a Swiss army knife even though you mostly use it to open bottles. On the day you desperately need a screwdriver you'll be glad you have more than a plain bottle-opener. 51 | 52 | === Merge Conflicts === 53 | 54 | For this topic, our computer game analogy becomes too thinly stretched. Instead, let us again consider editing a document. 55 | 56 | Suppose Alice inserts a line at the beginning of a file, and Bob appends one at the end of his copy. They both upload their changes. Most systems will automatically deduce a reasonable course of action: accept and merge their changes, so both Alice's and Bob's edits are applied. 57 | 58 | Now suppose both Alice and Bob have made distinct edits to the same line. Then it is impossible to proceed without human intervention. The second person to upload is informed of a _merge conflict_, and must choose one edit over another, or revise the line entirely. 59 | 60 | More complex situations can arise. Version control systems handle the simpler cases themselves, and leave the difficult cases for humans. Usually their behaviour is configurable. 61 | -------------------------------------------------------------------------------- /en/multiplayer.txt: -------------------------------------------------------------------------------- 1 | == Multiplayer Git == 2 | 3 | Initially I used Git on a private project where I was the sole developer. 4 | Amongst the commands related to Git's distributed nature, I needed only *pull* 5 | and *clone* so could I keep the same project in different places. 6 | 7 | Later I wanted to publish my code with Git, and include changes from 8 | contributors. I had to learn how to manage projects with multiple developers 9 | from all over the world. Fortunately, this is Git's forte, and arguably its 10 | raison d'être. 11 | 12 | === Who Am I? === 13 | 14 | Every commit has an author name and email, which is shown by *git log*. 15 | By default, Git uses system settings to populate these fields. 16 | To set them explicitly, type: 17 | 18 | $ git config --global user.name "John Doe" 19 | $ git config --global user.email johndoe@example.com 20 | 21 | Omit the global flag to set these options only for the current repository. 22 | 23 | === Git Over SSH, HTTP === 24 | 25 | Suppose you have SSH access to a web server, but Git is not installed. Though 26 | less efficient than its native protocol, Git can communicate over HTTP. 27 | 28 | Download, compile and install Git in your account, and create a repository in 29 | your web directory: 30 | 31 | $ GIT_DIR=proj.git git init 32 | 33 | In the "proj.git" directory, run: 34 | 35 | $ git --bare update-server-info 36 | $ cp hooks/post-update.sample hooks/post-update 37 | 38 | For older versions of Git, the copy command fails and you should run: 39 | 40 | $ chmod a+x hooks/post-update 41 | 42 | Now you can publish your latest edits via SSH from any clone: 43 | 44 | $ git push web.server:/path/to/proj.git master 45 | 46 | and anybody can get your project with: 47 | 48 | $ git clone http://web.server/proj.git 49 | 50 | === Git Over Anything === 51 | 52 | Want to synchronize repositories without servers, or even a network connection? 53 | Need to improvise during an emergency? We've seen <>. We could shuttle such files back and forth to transport git 56 | repositories over any medium, but a more efficient tool is *git bundle*. 57 | 58 | The sender creates a 'bundle': 59 | 60 | $ git bundle create somefile HEAD 61 | 62 | then transports the bundle, +somefile+, to the other party somehow: email, 63 | thumb drive, floppy disk, an *xxd* printout and an OCR machine, 64 | reading bits over the phone, smoke signals, etc. The receiver retrieves 65 | commits from the bundle by typing: 66 | 67 | $ git pull somefile 68 | 69 | The receiver can even do this from an empty repository. Despite its 70 | size, +somefile+ contains the entire original git repository. 71 | 72 | In larger projects, eliminate waste by bundling only changes the other 73 | repository lacks: 74 | 75 | $ git bundle create somefile HEAD ^COMMON_SHA1 76 | 77 | If done frequently, one could easily forget which commit was last sent. The 78 | help page suggests using tags to solve this. Namely, after you send a bundle, 79 | type: 80 | 81 | $ git tag -f lastbundle HEAD 82 | 83 | and create new refresher bundles with: 84 | 85 | $ git bundle create newbundle HEAD ^lastbundle 86 | 87 | === Patches: The Global Currency === 88 | 89 | Patches are text representations of your changes that can be easily understood 90 | by computers and humans alike. This gives them universal appeal. You can email a 91 | patch to developers no matter what version control system they're using. As long 92 | as your audience can read their email, they can see your edits. Similarly, on 93 | your side, all you require is an email account: there's no need to setup an online Git repository. 94 | 95 | Recall from the first chapter: 96 | 97 | $ git diff COMMIT 98 | 99 | outputs a patch which can be pasted into an email for discussion. In a Git 100 | repository, type: 101 | 102 | $ git apply < FILE 103 | 104 | to apply the patch. 105 | 106 | In more formal settings, when author names and perhaps signatures should be 107 | recorded, generate the corresponding patches past a certain point by typing: 108 | 109 | $ git format-patch START_COMMIT 110 | 111 | The resulting files can be given to *git-send-email*, or sent by hand. You can also specify a range of commits: 112 | 113 | $ git format-patch START_COMMIT..END_COMMIT 114 | 115 | On the receving end, save an email to a file, then type: 116 | 117 | $ git am < FILE 118 | 119 | This applies the incoming patch and also creates a commit, including information such as the author. 120 | 121 | With a browser email client, you may need to click a button to see the email in its raw original form before saving the patch to a file. 122 | 123 | There are slight differences for mbox-based email clients, but if you use one 124 | of these, you're probably the sort of person who can figure them out easily 125 | without reading tutorials! 126 | 127 | === Sorry, We've Moved === 128 | 129 | After cloning a repository, running *git push* or *git pull* will automatically 130 | push to or pull from the original URL. How does Git do this? The secret lies in 131 | config options initialized created with the clone. Let's take a peek: 132 | 133 | $ git config --list 134 | 135 | The +remote.origin.url+ option controls the source URL; "origin" is a nickname 136 | given to the source repository. As with the "master" branch convention, we may 137 | change or delete this nickname but there is usually no reason for doing so. 138 | 139 | If the the original repository moves, we can update the URL via: 140 | 141 | $ git config remote.origin.url NEW_URL 142 | 143 | The +branch.master.merge+ option specifies the default remote branch in 144 | a *git pull*. During the initial clone, it is set to the current branch of the 145 | source repository, so even if the HEAD of the source repository subsequently 146 | moves to a different branch, a later pull will faithfully follow the 147 | original branch. 148 | 149 | This option only applies to the repository we first cloned from, which is 150 | recorded in the option +branch.master.remote+. If we pull in from other 151 | repositories we must explicitly state which branch we want: 152 | 153 | $ git pull ANOTHER_URL master 154 | 155 | The above explains why some of our earlier push and pull examples had no 156 | arguments. 157 | 158 | === Remote Branches === 159 | 160 | When you clone a repository, you also clone all its branches. You may not have 161 | noticed this because Git hides them away: you must ask for them specifically. 162 | This prevents branches in the remote repository from interfering with 163 | your branches, and also makes Git easier for beginners. 164 | 165 | List the remote branches with: 166 | 167 | $ git branch -r 168 | 169 | You should see something like: 170 | 171 | origin/HEAD 172 | origin/master 173 | origin/experimental 174 | 175 | These represent branches and the HEAD of the remote repository, and can be used 176 | in regular Git commands. For example, suppose you have made many commits, and 177 | wish to compare against the last fetched version. You could search through the 178 | logs for the appropriate SHA1 hash, but it's much easier to type: 179 | 180 | $ git diff origin/HEAD 181 | 182 | Or you can see what the "experimental" branch has been up to: 183 | 184 | $ git log origin/experimental 185 | 186 | === Multiple Remotes === 187 | 188 | Suppose two other developers are working on our project, and we want to 189 | keep tabs on both. We can follow more than one repository at a time with: 190 | 191 | $ git remote add other ANOTHER_URL 192 | $ git pull other some_branch 193 | 194 | Now we have merged in a branch from the second repository, and we have 195 | easy access to all branches of all repositories: 196 | 197 | $ git diff origin/experimental^ other/some_branch~5 198 | 199 | But what if we just want to compare their changes without affecting our own 200 | work? In other words, we want to examine their branches without having 201 | their changes invade our working directory. In this case, rather than pull, 202 | run: 203 | 204 | $ git fetch # Fetch from origin, the default. 205 | $ git fetch other # Fetch from the second programmer. 206 | 207 | This fetches their histories and nothing more, so although the working 208 | directory remains untouched, we can refer to any branch of any repository in 209 | a Git command. By the way, behind the scenes, a pull is simply a fetch followed 210 | by *git merge*; recall the latter merges a given commit into the working 211 | directory. Usually we pull because we want to merge after a fetch; this 212 | situation is a notable exception. 213 | 214 | See *git help remote* for how to remove remote repositories, ignore certain 215 | branches, and more. 216 | 217 | === My Preferences === 218 | 219 | For my projects, I like contributors to prepare Git repositories which I can 220 | pull. Some Git hosting services let you host your own fork of a project with 221 | the click of a button. 222 | 223 | After I fetch a tree, I run Git commands to navigate and examine the changes, 224 | which ideally are well-organized and well-described. I merge unpublished 225 | changes of my own, and perhaps make further edits. Once satisfied, I push to 226 | the official repository. 227 | 228 | Though I infrequently receive contributions, I believe this approach scales 229 | well. See 230 | http://torvalds-family.blogspot.com/2009/06/happiness-is-warm-scm.html[this 231 | blog post by Linus Torvalds]. 232 | 233 | Staying in the Git world is slightly more convenient than patch files, as it 234 | saves me the step of converting them to Git commits. Furthermore, Git 235 | automatically handles details such as recording the author's name and email 236 | address, as well as the time and date, and asks the author to describe 237 | their own change. 238 | -------------------------------------------------------------------------------- /en/preface.txt: -------------------------------------------------------------------------------- 1 | = Git Magic = 2 | Ben Lynn 3 | August 2007 4 | 5 | == Preface == 6 | 7 | http://git.or.cz/[Git] is a version control Swiss army knife. A reliable versatile multipurpose revision control tool whose extraordinary flexibility makes it tricky to learn, let alone master. 8 | 9 | As Arthur C. Clarke observed, any sufficiently advanced technology is indistinguishable from magic. This is a great way to approach Git: newbies can ignore its inner workings and view Git as a gizmo that can amaze friends and infuriate enemies with its wondrous abilities. 10 | 11 | Rather than go into details, we provide rough instructions for particular effects. After repeated use, gradually you will understand how each trick works, and how to tailor the recipes for your needs. 12 | 13 | .Translations 14 | 15 | - http://docs.google.com/View?id=dfwthj68_675gz3bw8kj[Chinese (Simplified)]: by JunJie, Meng and JiangWei. Hosted by Google Docs. 16 | - link:/~blynn/gitmagic/intl/es/[Spanish]: by Rodrigo Toledo. 17 | 18 | .Other Editions 19 | 20 | - link:book.html[Single webpage]: barebones HTML, with no CSS. 21 | - link:book.pdf[PDF file]: printer-friendly. 22 | - http://packages.debian.org/search?searchon=names&keywords=gitmagic[Debian package]: get a fast and local copy of this site. http://packages.ubuntu.com/jaunty/gitmagic[Ubuntu package (Jaunty Jackalope)] also available. Handy http://csdcf.stanford.edu/status/[when this server is offline for maintenance]. 23 | 24 | === Thanks! === 25 | 26 | Kudos to Dustin Sallings, Alberto Bertogli, James Cameron, Douglas Livingstone, 27 | Michael Budde, Richard Albury, Tarmigan, Derek Mahar, Frode Aannevik, and 28 | Keith Rarick for suggestions and improvements. Thanks to Daniel Baumann for 29 | creating and maintaining the Debian package. Thanks also to JunJie, Meng and 30 | JiangWei for the Chinese translation, and Rodrigo Toledo for the Spanish 31 | translation. [If I've left you out, please tell me because I often forget to 32 | update this section.] 33 | 34 | My gratitute goes to many others for your support and praise. I wish this were a real physical book, so I could quote your generous words on the cover to promote it! In seriousness, I greatly appreciate each message. Reading one always brightens my mood. 35 | 36 | .Free Git hosting 37 | 38 | - http://repo.or.cz/[http://repo.or.cz/] hosts free projects. The first Git hosting site. Founded and maintained by one of the earliest Git developers. 39 | - http://gitorious.org/[http://gitorious.org/] is another Git hosting site aimed at open-source projects. 40 | - http://github.com/[http://github.com/] hosts open-source projects for free, and private projects for a fee. 41 | 42 | Many thanks to each of these sites for hosting this guide. 43 | 44 | === License === 45 | 46 | This guide is released under http://www.gnu.org/licenses/gpl-3.0.html[the GNU General Public License version 3]. Naturally, the source is kept in a Git 47 | repository, and can be obtained by typing: 48 | 49 | $ git clone git://repo.or.cz/gitmagic.git # Creates "gitmagic" directory. 50 | 51 | or from one of the mirrors: 52 | 53 | $ git clone git://github.com/blynn/gitmagic.git 54 | $ git clone git://gitorious.org/gitmagic/mainline.git 55 | -------------------------------------------------------------------------------- /en/secrets.txt: -------------------------------------------------------------------------------- 1 | == Secrets Revealed == 2 | 3 | We take a peek under the hood and explain how Git performs its miracles. I will skimp over details. For in-depth descriptions refer to http://www.kernel.org/pub/software/scm/git/docs/user-manual.html[the user manual]. 4 | 5 | === Invisibility === 6 | 7 | How can Git be so unobtrusive? Aside from occasional commits and merges, you can work as if you were unaware that version control exists. That is, until you need it, and that's when you're glad Git was watching over you the whole time. 8 | 9 | Other version control systems don't let you forget about them. Permissions of files may be read-only unless you explicitly tell the server which files you intend to edit. The central server might be keeping track of who's checked out which code, and when. When the network goes down, you'll soon suffer. Developers constantly struggle with virtual red tape and bureaucracy. 10 | 11 | The secret is the `.git` directory in your working directory. Git keeps the history of your project here. The initial "." stops it showing up in `ls` listings. Except when you're pushing and pulling changes, all version control operations operate within this directory. 12 | 13 | You have total control over the fate of your files because Git doesn't care what you do to them. Git can easily recreate a saved state from `.git` at any time. 14 | 15 | === Integrity === 16 | 17 | Most people associate cryptography with keeping information secret, but another equally important goal is keeping information safe. Proper use of cryptographic hash functions can prevent accidental or malicious data corruption. 18 | 19 | A SHA1 hash can be thought of as a unique 160-bit ID number for every string of bytes you'll encounter in your life. Actually more than that: every string of bytes that any human will ever use over many lifetimes. 20 | 21 | As a SHA1 hash is itself a string of bytes, we can hash strings of bytes containing other hashes. This simple observation is surprisingly useful: look up 'hash chains'. We'll later see how Git uses it to efficiently guarantee data integrity. 22 | 23 | Briefly, Git keeps your data in the ".git/objects" subdirectory, where instead of normal filenames, you'll find only IDs. By using IDs as filenames, as well as a few lockfiles and timestamping tricks, Git transforms any humble filesystem into an efficient and robust database. 24 | 25 | === Intelligence === 26 | 27 | How does Git know you renamed a file, even though you never mentioned the fact explicitly? Sure, you may have run *git mv*, but that is exactly the same as a *git rm* followed by a *git add*. 28 | 29 | Git heuristically ferrets out renames and copies between successive versions. In fact, it can detect chunks of code being moved or copied around between files! Though it cannot cover all cases, it does a decent job, and this feature is always improving. If it fails to work for you, try options enabling more expensive copy detection, and consider upgrading. 30 | 31 | === Indexing === 32 | 33 | For every tracked file, Git records information such as its size, creation time and last modification time in a file known as the 'index'. To determine whether a file has changed, Git compares its current stats with that held the index. If they match, then Git can skip reading the file again. 34 | 35 | Since stat calls are considerably faster than file reads, if you only edit a 36 | few files, Git can update its state in almost no time. 37 | 38 | === Bare Repositories === 39 | 40 | You may have been wondering what format those online Git repositories use. 41 | They're plain Git repositories, just like your `.git` directory, except they've got names like `proj.git`, and they have no working directory associated with them. 42 | 43 | Most Git commands expect the Git index to live in `.git`, and will fail on these bare repositories. Fix this by setting the `GIT_DIR` environment variable to the path of the bare repository, or running Git within the directory itself with the `--bare` option. 44 | 45 | === Git's Origins === 46 | 47 | This http://lkml.org/lkml/2005/4/6/121[Linux Kernel Mailing List post] describes the chain of events that led to Git. The entire thread is a fascinating archaeological site for Git historians. 48 | 49 | === The Object Database === 50 | 51 | Here's how to write a Git-like system from scratch in a few hours. 52 | 53 | ==== Blobs ==== 54 | 55 | First, a magic trick. Pick a filename, any filename. In an empty directory: 56 | 57 | $ echo sweet > YOUR_FILENAME 58 | $ git init 59 | $ git add . 60 | $ find .git/objects -type f 61 | 62 | You'll see +.git/objects/aa/823728ea7d592acc69b36875a482cdf3fd5c8d+. 63 | 64 | How do I know this without knowing the filename? It's because the 65 | SHA1 hash of: 66 | 67 | "blob" SP "6" NUL "sweet" LF 68 | 69 | is aa823728ea7d592acc69b36875a482cdf3fd5c8d, 70 | where SP is a space, NUL is a zero byte and LF is a linefeed. You can verify 71 | this by typing: 72 | 73 | $ printf "blob 6\000sweet\n" | sha1sum 74 | 75 | Git is 'content-addressable': files are not stored according to their filename, 76 | but rather by the hash of the data they contain, in a file we call a 'blob 77 | object'. We can think of the hash as a unique ID for a file's contents, so 78 | in a sense we are addressing files by their content. The initial "blob 6" is 79 | merely a header consisting of the object type and its length in bytes; it 80 | simplifies internal bookkeeping. 81 | 82 | Thus I could easily predict what you would see. The file's name is irrelevant: 83 | only the data inside is used to construct the blob object. 84 | 85 | You may be wondering what happens to identical files. Try adding copies of 86 | your file, with any filenames whatsoever. The contents of +.git/objects+ stay 87 | the same no matter how many you add. Git only stores the data once. 88 | 89 | By the way, the files within +.git/objects+ are compressed with zlib so you 90 | should not stare at them directly. Filter them through 91 | http://www.zlib.net/zpipe.c[zpipe -d], or type: 92 | 93 | $ git cat-file -p aa823728ea7d592acc69b36875a482cdf3fd5c8d 94 | 95 | which pretty-prints the given object. 96 | 97 | ==== Trees ==== 98 | 99 | But where are the filenames? They must be stored somewhere at some stage. 100 | Git gets around to the filenames during a commit: 101 | 102 | $ git commit # Type some message. 103 | $ find .git/objects -type f 104 | 105 | You should now see 3 objects. This time I cannot tell you what the 2 new files are, as it partly depends on the filename you picked. We'll proceed assuming you chose "rose". If you didn't, you can rewrite history to make it look like you did: 106 | 107 | $ git filter-branch --tree-filter 'mv YOUR_FILENAME rose' 108 | $ find .git/objects -type f 109 | 110 | Now you should see the file 111 | +.git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9+, because this is the 112 | SHA1 hash of its contents: 113 | 114 | "tree" SP "32" NUL "100644 rose" NUL 0xaa823728ea7d592acc69b36875a482cdf3fd5c8d 115 | 116 | Check this file does indeed contain the above by typing: 117 | 118 | $ echo 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 | git cat-file --batch 119 | 120 | With zpipe, it's easy to verify the hash: 121 | 122 | $ zpipe -d < .git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9 | sha1sum 123 | 124 | Hash verification is trickier via cat-file because its output contains more 125 | than the raw uncompressed object file. 126 | 127 | This file is a 'tree' object: a list of tuples consisting of a file 128 | type, a filename, and a hash. In our example, the file type is "100644", which 129 | means "rose" is a normal file, and the hash is the blob object that contains 130 | the contents of "rose". Other possible file types are executables, symlinks or 131 | directories. In the last case, the hash points to a tree object. 132 | 133 | If you ran filter-branch, you'll have old objects you no longer need. Although 134 | they will be jettisoned automatically once the grace period expires, we'll 135 | delete them now to make our toy example easier to follow: 136 | 137 | $ rm -r .git/refs/original 138 | $ git reflog expire --expire=now --all 139 | $ git prune 140 | 141 | For real projects you should typically avoid commands like this, as you are 142 | destroying backups. If you want a clean repository, it is usually best to make 143 | a fresh clone. Also, take care when directly manipulating +.git+: what if a Git 144 | command is running at the same time, or a sudden power outage occurs? 145 | In general, refs should be deleted with *git update-ref -d*, 146 | though usually it's safe to remove +refs/original+ by hand. 147 | 148 | ==== Commits ==== 149 | 150 | We've explained 2 of the 3 objects. The third is a 'commit' object. Its 151 | contents depend on the commit message as well as the date and time it was 152 | created. To match what we have here, we'll have to tweak it a little: 153 | 154 | $ git commit --amend -m Shakespeare # Change the commit message. 155 | $ git filter-branch --env-filter 'export 156 | GIT_AUTHOR_DATE="Fri 13 Feb 2009 15:31:30 -0800" 157 | GIT_AUTHOR_NAME="Alice" 158 | GIT_AUTHOR_EMAIL="alice@example.com" 159 | GIT_COMMITTER_DATE="Fri, 13 Feb 2009 15:31:30 -0800" 160 | GIT_COMMITTER_NAME="Bob" 161 | GIT_COMMITTER_EMAIL="bob@example.com"' # Rig timestamps and authors. 162 | $ find .git/objects -type f 163 | 164 | You should now see 165 | +.git/objects/49/993fe130c4b3bf24857a15d7969c396b7bc187+ 166 | which is the SHA1 hash of its contents: 167 | 168 | "commit 158" NUL 169 | "tree 05b217bb859794d08bb9e4f7f04cbda4b207fbe9" LF 170 | "author Alice 1234567890 -0800" LF 171 | "committer Bob 1234567890 -0800" LF 172 | LF 173 | "Shakespeare" LF 174 | 175 | As before, you can run zpipe or cat-file to see for yourself. 176 | 177 | This is the first commit, so there are no parent commits, but later commits 178 | will always contain at least one line identifying a parent commit. 179 | 180 | ==== Indistinguishable From Magic ==== 181 | 182 | There's little else to say. We have just exposed the secret behind Git's 183 | powers. It seems too simple: it looks like you could mix together a few shell 184 | scripts and add a dash of C code to cook up the above in a matter of hours, 185 | mixing in lock files and fsyncs for robustness. In fact, this accurately 186 | describes the earliest versions of Git. Nonetheless, apart from ingenious 187 | packing tricks to save space, and ingenious indexing tricks to save time, we 188 | now know how Git deftly changes a filesystem into a database perfect for 189 | version control. 190 | 191 | For example, if any file within the object database is corrupted by a disk 192 | error, then its hash will no longer match, alerting us to the problem. By 193 | hashing hashes of other objects, we maintain integrity at all levels. Commits 194 | are atomic, that is, a commit can never only partially record changes: we can 195 | only compute the hash of a commit and store it in the database after we already 196 | have stored all relevant trees, blobs and parent commits. The object 197 | database is immune to unexpected interruptions such as power outages. 198 | 199 | We defeat even the most devious adversaries. Suppose somebody attempts to 200 | stealthily modify the contents of a file in an ancient version of a project. To 201 | keep the object database looking healthy, they must also change the hash of the 202 | corresponding blob object since it's now a different string of bytes. This 203 | means they'll have to change the hash of any tree object referencing the file, 204 | and in turn change the hash of all commit objects involving such a tree, in 205 | addition to the hashes of all the descendants of these commits. This implies the 206 | hash of the official head differs to that of the bad repository. By 207 | following the trail of mismatching hashes we can pinpoint the mutilated file, 208 | as well as the commit where it was first corrupted. 209 | 210 | In short, so long as the 20 bytes representing the last commit are safe, 211 | it's impossible to tamper with a Git repository. 212 | 213 | What about Git's famous features? Branching? Merging? Tags? 214 | Mere details. The current head is kept in the file +.git/HEAD+, 215 | which contains a hash of a commit object. The hash gets updated during a commit 216 | as well as many other commands. Branches are almost the same: they are files in 217 | +.git/refs/heads+. Tags too: they live in +.git/refs/tags+ but they 218 | are updated by a different set of commands. 219 | -------------------------------------------------------------------------------- /en/translate.txt: -------------------------------------------------------------------------------- 1 | == Appendix B: Translating This Guide == 2 | 3 | Clone the source, then create a directory corresponding to the target http://www.iana.org/assignments/language-subtag-registry[language's IETF tag]: see 4 | http://www.w3.org/International/articles/language-tags/Overview.en.php[the W3C article on internationalization]. For example, English is "en", Japanese is "ja", and Traditional Chinese is "zh-Hant". In the new directory, and translate the +txt+ files from the "en" subdirectory. 5 | 6 | For instance, to translate the guide into http://en.wikipedia.org/wiki/Klingon_language[Klingon], you might type: 7 | 8 | $ git clone git://repo.or.cz/gitmagic.git 9 | $ cd gitmagic 10 | $ mkdir tlh # "tlh" is the IETF language code for Klingon. 11 | $ cd tlh 12 | $ cp ../en/intro.txt . 13 | $ edit intro.txt # Translate the file. 14 | 15 | and so on for each text file. You can review your work incrementally: 16 | 17 | $ make LANG=tlh 18 | $ firefox book.html 19 | 20 | Commit your changes often, then let me know when they're ready. 21 | GitHub.com has an interface that facilitates this: fork the "gitmagic" project, 22 | push your changes, then ask me to merge. 23 | 24 | I like to have translations follow the above scheme so my scripts can produce 25 | HTML and PDF versions. Also, it conveniently keeps all the translations in the 26 | official repository. But please do whatever suits you best: for example, the 27 | Chinese translators used Google Docs. I'm happy as long as your work 28 | enables more people to access my work. 29 | -------------------------------------------------------------------------------- /es/basic.txt: -------------------------------------------------------------------------------- 1 | == Trucos Básicos == 2 | 3 | En lugar de sumergirte en un mar de comandos de Git, usa estos ejemplos elementales para mojarte los pies. A pesar de sus simplicidad, todos son útiles. 4 | De hecho, en mis primeros meses con Git nunca fui más allá del material en este capítulo. 5 | 6 | === Guardando Estados === 7 | 8 | Estás a punto de intentar algo drástico? Antes de hacerlo, toma una instantánea de todos los archivos en el directorio actual con: 9 | 10 | $ git init 11 | $ git add . 12 | $ git commit -m "My first backup" 13 | 14 | Ahora, si tu edición se vuelve irrecuperable, ejecuta: 15 | 16 | $ git reset --hard 17 | 18 | para volver a donde estabas. Para volver a salvar el estado: 19 | 20 | $ git commit -a -m "Otro respaldo" 21 | 22 | ==== Agrega, Elimina, Renombra ==== 23 | 24 | El comando anterior solo seguirá la pista de los archivos que estaban presentes la primera vez que ejecutaste *git add*. Si añades nuevos archivos o subdirectorios, deberás decirle a Git: 25 | 26 | $ git add ARCHIVOSNUEVOS... 27 | 28 | De manera similar, si quieres que Git se olvide de determinados archivos, porque (por ejemplo) los borraste: 29 | 30 | $ git rm ARCHIVOSVIEJOS... 31 | 32 | Renombrar un archivo es lo mismo que eliminar el nombre anterior y agregar el nuevo. También puedes usar *git mv* que tiene la misma sintaxis que el comando *mv*. Por ejemplo: 33 | 34 | $ git mv ARCHIVOVIEJO ARCHIVONUEVO 35 | 36 | === Deshacer/Rehacer Avanzado === 37 | 38 | Algunas veces solo quieres ir hacia atrás y olvidarte de todos los cambios a partir de cierto punto, porque estaban todos mal. Entonces: 39 | 40 | $ git log 41 | 42 | te muestra una lista de commits recientes, y sus hashes SHA1. A continuación, escribe: 43 | 44 | $ git reset --hard SHA1_HASH 45 | 46 | para recuperar el estado de un commit dado, y borrar para siempre cualquier recuerdo de commits más nuevos. 47 | 48 | Otras veces, quieres saltar a un estado anterior temporalmente. En ese caso escribe: 49 | 50 | $ git checkout SHA1_HASH 51 | 52 | Esto te lleva atrás en el tiempo, sin tocar los commits más nuevos. Sin embargo, como en los viajes en el tiempo de las películas de ciencia ficción, estarás en una realidad alternativa, porque tus acciones fueron diferentes a las de la primera vez. 53 | 54 | Esta realidad alternativa se llama 'branch' (rama), y <>. Por ahora solo recuerda que 55 | 56 | $ git checkout master 57 | 58 | te llevará al presente. También, para que Git no se queje, siempre haz un commit o resetea tus cambios antes de ejecutar checkout. 59 | 60 | Para retomar la analogía de los videojuegos: 61 | 62 | - *`git reset \--hard`*: carga un juego viejo y borra todos los que son mas nuevos que el que acabas de cargar. 63 | 64 | - *`git checkout`*: carga un juego viejo, pero si continúas jugando, el estado del juego se desviará de los juegos que salvaste la primera vez. Cualquierpartido nuevo que guardes, terminará en una branch separada, representando la realidad alternativa a la que entraste. <> 65 | 66 | Puedes elegir el restaurar solo archivos o directorios en particular, al agregarlos al final del comando: 67 | You can choose only to restore particular files and subdirectories by appending them after the command: 68 | 69 | $ git checkout SHA1_HASH algun.archivo otro.archivo 70 | 71 | Ten cuidado, esta forma de *checkout* puede sobreescribir archivos sin avisar. Para prevenir accidentes, haz commit antes de ejecutar cualquier comando de checkout, especialmente cuando estás aprendiendo a usar Git. En general, cuando te sientas inseguro del resultado de una operación, sea o no de Git, ejecuta antes *git commit -a*. 72 | 73 | ¿No te gusta cortar y pegar hashes? Entonces usa: 74 | 75 | $ git checkout :/"Mi primer r" 76 | 77 | para saltar al commit que comienza con el mensaje dado. 78 | 79 | También puedes pedir el 5to estado hacia atrás: 80 | 81 | $ git checkout master~5 82 | 83 | ==== Revirtiendo ==== 84 | 85 | En una corte, los eventos pueden ser eliminados del registro. Igualmente, puedes elegir commits específicos para deshacer. 86 | 87 | $ git commit -a 88 | $ git revert SHA1_HASH 89 | 90 | va a deshacer solo el commit con el hash dado. Ejecutar *git log* revela que el revert es registrado como un nuevo commit. 91 | 92 | === Descargando Archivos === 93 | 94 | Obtén una copia de un proyecto administrado por git escribiendo: 95 | 96 | $ git clone git://servidor/ruta/a/los/archivos 97 | 98 | Por ejemplo, para bajar todos los archivos que usé para crear este sitio: 99 | 100 | $ git clone git://git.or.cz/gitmagic.git 101 | 102 | Pronto tendremos más para decir acerca del comando *clone*. 103 | 104 | === Lo Más Nuevo === 105 | 106 | Si ya descargaste una copia de un proyecto usando *git clone*, puedes actualizarte a la última versión con: 107 | 108 | $ git pull 109 | 110 | === Publicación Al Instante === 111 | 112 | Imagina que has escrito un script que te gustaría compartir con otros. Puedes decirles que simplemente lo bajen de tu computadora, pero si lo hacen mientras estás haciendo una modificación, pueden terminar en problemas. Es por esto que existen los ciclos de desarrollo. Los programadores pueden trabajar en un proyecto de manera frecuente, pero solo hacen público el código cuando consideran que es presentable. 113 | 114 | Para hacer esto con Git, en el directorio donde guardas tu script: 115 | 116 | $ git init 117 | $ git add . 118 | $ git commit -m "Primer lanzamiento" 119 | 120 | Entonces puedes decirle a tus usuarios que ejecuten: 121 | 122 | $ git clone tu.maquina:/ruta/al/script 123 | 124 | para descargar tu script. Esto asume que tienen acceso por ssh. Si no es así, ejecuta *git daemon* y dile a tus usuarios que usen: 125 | 126 | $ git clone git://tu.maquina/ruta/al/script 127 | 128 | De ahora en más, cada vez que tu script esté listo para el lanzamiento, escribe: 129 | 130 | $ git commit -a -m "Siguiente lanzamiento" 131 | 132 | y tus usuarios puede actualizar su versión yendo al directorio que tiene tu script y ejecutando: 133 | 134 | $ git pull 135 | 136 | Tus usuarios nunca terminarán usando una versión de tu script que no quieres que vean. Obviamente este truco funciona para lo que sea, no solo scripts. 137 | 138 | === Que es lo que hice? === 139 | 140 | Averigua que cambios hiciste desde el último commit con: 141 | 142 | $ git diff 143 | 144 | O desde ayer: 145 | 146 | $ git diff "@{yesterday}" 147 | 148 | O entre una versión en particular y 2 versiones hacia atrás: 149 | 150 | $ git diff SHA1_HASH "master~2" 151 | 152 | En cado caso la salida es un patch (parche) que puede ser aplicado con *git apply* 153 | Para ver cambios desde hace 2 semanas, puedes intentar: 154 | 155 | $ git whatchanged --since="2 weeks ago" 156 | 157 | Usualmente recorro la historia con http://sourceforge.net/projects/qgit[qgit] 158 | , dada su interfaz pulida y fotogénica, o http://jonas.nitro.dk/tig/[tig], una interfaz en modo texto 159 | que funciona bien a través conexiones lentas. Como alternativa, puedes instalar un servidor web, 160 | ejecutar *git instaweb* y utilizar cualquier navegador web. 161 | 162 | === Ejercicio === 163 | 164 | Siendo A, B, C, y D cuatro commits sucesivos, donde B es el mismo que A pero con algunos archivos eliminados. Queremos volver a agregar los archivos en D pero no en B. ¿Cómo podemos hacer esto? 165 | 166 | Hay por lo menos tres soluciones. Asumiendo que estamos en D: 167 | 168 | 1. La diferencia entre A y B son los archivos eliminados. Podemos crear un patch representando esta diferencia y aplicarlo: 169 | 170 | $ git diff B A | git apply 171 | 172 | 2. Como en A tenemos los archivos guardados, podemos recuperarlos : 173 | 174 | $ git checkout A ARCHIVOS... 175 | 176 | 3. Podemos ver el pasaje de A a B como un cambio que queremos deshacer: 177 | 178 | $ git revert B 179 | 180 | ¿Cuál alternativa es la mejor? Cualquiera que prefieras. Es fácil obtener lo que quieres con Git, y normalmente hay varias formas de hacerlo. 181 | -------------------------------------------------------------------------------- /es/branch.txt: -------------------------------------------------------------------------------- 1 | == Magia Con Los Branches == 2 | 3 | El hacer branches (ramificar) y merges (unir) de manera instantánea, son dos de las prestaciones más letales de Git. 4 | 5 | *Problema*: Factores externos necesitan inevitablemente de cambios de contexto. 6 | Un bug severo se manifiesta en la última versión sin previo aviso. El plazo para 7 | alguna prestación se acorta. Un desarrollador que tiene que ayudar en una sección indispensable 8 | del proyecto está por tomar licencia. En cualquier caso, debes soltar abruptamente lo que estás haciendo 9 | y enfocarte en una tarea completamente diferente. 10 | 11 | Interrumpir tu línea de pensamiento puede ser negativo para tu productividad, y cuanto más engorroso sea el cambiar contextos, mayor es la pérdida. Con los sistemas centralizados, debemos descargar una nueva copia. Los sistemas distribuídos se comportan mejor, dado que podemos clonar la versión deseada localmente. 12 | 13 | Pero el clonar igual implica copiar todo el directorio junto con toda la historia hasta el momento. Aunque Git reduce el costousando hard links y el compartir archivos, los archivos del proyecto deben ser recreados enteramente en el nuevo directorio. 14 | 15 | *Solución*: Git tiene una mejor herramienta para estas situaciones que es mucho más rápida y eficiente en tamaño que clonar *git branch*. 16 | 17 | Con esta palabra mágica, los archivos en tu directorio se transforman súbitamente de una versión en otra. Esta transformación puede hacer más que simplemente ir hacia atrás o adelante en la historia. Tus archivos pueden mutar desde la última versión lanzada, a la versión experimental, a la versión en desarrollo, a la versión de un amigo y así sucesivamente. 18 | 19 | === La Tecla Del Jefe === 20 | 21 | ¿Alguna vez jugaste uno de esos juegos donde con solo presionar un botón ("la tecla del jefe"), la pantalla inmediatamente muestra una hoja de cálculo o algo así? La idea es que si el jefe entra a la oficina mientras estás en el juego, lo puedes esconder rápidamente. 22 | 23 | En algún directorio: 24 | 25 | $ echo "Soy más inteligente que mi jefe" > miarchivo.txt 26 | $ git init 27 | $ git add . 28 | $ git commit -m "Commit inicial" 29 | 30 | Creamos un repositorio de Git que guarda un archivo de texto conteniendo un mensaje dado. Ahora escribe: 31 | 32 | $ git checkout -b jefe # nada parece cambiar luego de esto 33 | $ echo "Mi jefe es más inteligente que yo" > miarchivo.txt 34 | $ git commit -a -m "Otro commit" 35 | 36 | Parecería que sobreescribimos nuestro archivo y le hicimos commit. Pero es una ilusión. Escribe: 37 | 38 | $ git checkout master # cambia a la versión original del archivo 39 | 40 | y presto! El archivo de texto es restaurado. Y si el jefe decide investigar este directorio, escribimos: 41 | 42 | $ git checkout jefe # cambia a la versión adecuada para los ojos del jefe 43 | 44 | Puedes cambiar entre ambas versiones del archivo cuantas veces quieras, y hacer commit en ambas de manera independiente. 45 | 46 | === Trabajo Sucio === 47 | 48 | [[branch]] 49 | Supongamos que estás trabajando en alguna prestación, y que por alguna razón, necesitas volver a una versión vieja y poner temporalmente algunos "print" para ver como funciona algo. Entonces: 50 | 51 | $ git commit -a 52 | $ git checkout SHA1_HASH 53 | 54 | Ahora puedes agregar cualquier código temporal horrible por todos lados. 55 | Incluso puedes hacer commit de estos cambios. Cuando termines, 56 | 57 | $ git checkout master 58 | 59 | para volver a tu trabajo original. Observa que arrastrarás cualquier cambio del que no hayas hecho commit. 60 | 61 | ¿Que pasa si quisieras cambiar los cambios temporales? Facil: 62 | 63 | $ git checkout -b sucio 64 | 65 | y haz commit antes de volver a la branch master. Cuando quieras volver a los cambios sucios, simplemente escribe: 66 | 67 | $ git checkout sucio 68 | 69 | Mencionamos este comando en un capítulo anterior, cuando discutíamos sobre cargar estados antiguos. Al fin podemos contar toda la historia:los archivos cambian al estado pedido, pero debemos dejar la branch master. Cualquier commit de aquí en adelante, llevan tus archivos por un nuevo camino, el podrá ser nombrado posteriormente. 70 | 71 | En otras palabras, luego de traer un estado viejo, Git automáticamente te pone en una nueva branch sin nombre, la cual puede ser nombrada y salvada con *git checkout -b*. 72 | 73 | === Arreglos Rápidos === 74 | 75 | Estás en medio de algo cuando te piden que dejes todo y soluciones un bug recién descubierto: 76 | 77 | $ git commit -a 78 | $ git checkout -b arreglos SHA1_HASH 79 | 80 | Luego, una vez que solucionaste el bug: 81 | 82 | $ git commit -a -m "Bug arreglado" 83 | $ git push # al repositorio central 84 | $ git checkout master 85 | 86 | y continúa con el trabajo en tu tarea original. 87 | 88 | === Flujo De Trabajo Ininterrumpido === 89 | 90 | Algunos proyectos requieren que tu código sea evaluado antes de que puedas subirlo. Para hacer la vida más fácil para aquellos que revisan tu código, si tienes algún cambio grande para hacer, puedes partirlo en dos o mas partes, y hacer que cada parte sea evaluada por separado. 91 | 92 | ¿Que pasa si la segunda parte no puede ser escrita hasta que la primera sea aprobada y subida? En muchos sistemas de control de versiones, deberías enviar primero el código a los evaluadores, y luego esperar hasta que esté aprobado antes de empezar con la segunda parte. 93 | 94 | En realidad, eso no es del todo cierto, pero en estos sistemas, editar la Parte II antes de subir la Parte I involucra sufrimiento e infortunio. En Git, los branches y merges son indoloros (un termino técnico que significa rápidos y locales). Entonces, luego de que hayas hecho commit de la primera parte y la hayas enviado a ser revisada: 95 | 96 | $ git checkout -b parte2 97 | 98 | Luego, escribe la segunda parte del gran cambio sin esperar a que la primera sea aceptada. Cuando la primera parte sea aprobada y subida, 99 | 100 | $ git checkout master 101 | $ git merge parte2 102 | $ git branch -d parte2 # ya no se necesita esta branch 103 | 104 | y la segunda parte del cambio está lista para la evaluación. 105 | 106 | ¡Pero esperen! ¿Qué pasa si no fuera tan simple? Digamos que tuviste un error en la primera parte, el cual hay que corregir antes de subir los cambios. ¡No hay problema! Primero, vuelve a la branch master usando 107 | 108 | $ git checkout master 109 | 110 | Soluciona el error en la primera parte del cambio y espera que sea aprobado. Si no lo es, simplemente repite este paso. Probablemente quieras hacer un merge de la versión arreglada de la Parte I con la Parte II: 111 | 112 | $ git checkout parte2 113 | $ git merge master 114 | 115 | Ahora es igual que lo anterior. Una vez que la primera parte sea aprobada: 116 | 117 | $ git checkout master 118 | $ git merge parte2 119 | $ git branch -d parte2 120 | 121 | y nuevamente, la segunda parte está lista para ser revisada. 122 | 123 | Es fácil extender este truco para cualquier cantidad de partes. 124 | 125 | === Reorganizando Una Mezcla === 126 | 127 | Quizás quieras trabajar en todos los aspectos de un proyecto sobre la misma branch. Quieres dejar los trabajos-en-progreso para ti y quieres que otros vean tus commits solo cuando han sido pulcramente organizados. Inicia un par de branches: 128 | 129 | $ git checkout -b prolijo 130 | $ git checkout -b mezcla 131 | 132 | A continuación, trabaja en lo que sea: soluciona bugs, agrega prestaciones, agrega código temporal o lo que quieras, haciendo commits seguidos a medida que avanzas. Entonces: 133 | 134 | $ git checkout prolijo 135 | $ git cherry-pick SHA1_HASH 136 | 137 | aplica un commit dado a la branch "prolijo". Con cherry-picks apropiados, puedes construir una rama que contenga solo el código permanente, y los commits relacionados juntos en un grupo. 138 | 139 | === Administrando branches === 140 | 141 | Lista todas las branches escribiendo: 142 | 143 | $ git branch 144 | 145 | Siempre hay una branch llamada "master", y es en la que comienzas por defecto. 146 | Algunos aconsejan dejar la rama "master" sin tocar y el crear nuevas branches 147 | para tus propios cambios. 148 | 149 | Las opciones *-d* y *-m* te permiten borrar y mover (renombrar) branches. 150 | Mira en *git help branch* 151 | 152 | La branch "master" es una convención útil. Otros pueden asumir que tu 153 | repositorio tiene una branch con este nombre, y que contiene la versión 154 | oficial del proyecto. Puedes renombrar o destruir la branch "master", pero 155 | también podrías respetar esta costumbre. 156 | 157 | === Branches Temporales === 158 | 159 | Después de un rato puedes notar que estás creando branches de corta vida 160 | de manera frecuente por razones similares: cada branch sirve simplemente 161 | para salvar el estado actual y permitirte saltar a un estado anterior 162 | para solucionar un bug de alta prioridad o algo. 163 | 164 | Es análogo a cambiar el canal de la TV temporalmente, para ver que otra 165 | cosa están dando. Pero en lugar de apretar un par de botones, tienes que 166 | crear, hacer checkout y eliminar branches y commits temporales. Por suerte, 167 | Git tiene un aatajo que es tan conveniente como un control remoto de TV: 168 | 169 | $ git stash 170 | 171 | Esto guarda el estado actual en un lugar temporal (un 'stash') y restaura 172 | el estado anterior. Tu directorio de trabajo se ve idéntico a como estaba 173 | antes de que comenzaras a editar, y puedes solucionar bugs, traer cambios 174 | desde otros repositorios, etc. Cuando quieras volver a los cambios 175 | del stash, escribe: 176 | 177 | $ git stash apply # Puedes necesitar corregir conflictos 178 | 179 | Puedes tener varios stashes, y manipularlos de varias maneras. Mira *git help stash*. 180 | Como es de imaginar, Git mantiene branches de manera interna para lograr este truco mágico. 181 | 182 | === Trabaja como quieras === 183 | 184 | Aplicaciones como http://www.mozilla.com/[Mozilla Firefox] permiten tener varias pestañas y ventanas abiertas. Cambiar de pestaña te da diferente contenido en la misma ventana. Los branches en git son como pestañas para tu directorio de trabajo. Siguiendo esta analogía, el clonar es como abrir una nueva ventana. La posibilidad de ambas cosas es lo que mejora la experiencia del usuario. 185 | 186 | En un nivel más alto, varios window managers en Linux soportan múltiples escritorios. 187 | Usar branches en Git es similar a cambiar a un escritorio diferente, mientras 188 | clonar es similar a conectar otro monitor para ganar un nuevo escritorio. 189 | 190 | Otro ejemplo es el programa http://www.gnu.org/software/screen/[*screen*]. Esta joya permite crear, destruir e intercambiar entre varias sesiones de terminal sobre la misma terminal. En lugar de abrir terminales nuevas (clone), puedes usar la misma si ejecutas *screen* (branch). De hecho, puedes hacer mucho más con *screen*, pero eso es un asunto para otro manual. 191 | 192 | Usar clone, branch y merge, es rápido y local en Git, animándote a usar la combinación que más te favorezca. Git te permite trabajar exactamente como prefieras. 193 | -------------------------------------------------------------------------------- /es/clone.txt: -------------------------------------------------------------------------------- 1 | == Clonando == 2 | 3 | En sistemas de control de versiones antiguos, checkout es la operación standard para obtener archivos. Obtienes un conjunto de archivos en estado guardado que solicistaste. 4 | 5 | En Git, y otros sistemas de control de versiones distribuídos, clonar es la operación standard. Para obtener archivos se crea un clon de un repositorio entero. En otras palabras, practicamente se crea una copia idéntica del servidor central. Todo lo que se pueda hacer en el repositorio principal, también podrás hacerlo. 6 | 7 | === Sincronizar Computadoras === 8 | 9 | Este es el motivo por el que usé Git por primera vez. Puedo tolerar hacer tarballs o usar *rsync* para backups y sincronización básica. Pero algunas veces edito en mi laptop, otras veces en mi desktop, y ambas pueden no haberse comunicado en el medio. 10 | 11 | Inicializa un repositorio de Git y haz haz commit de tus archivos en una máquina, luego en la otra: 12 | 13 | $ git clone otra.computadora:/ruta/a/archivos 14 | 15 | para crear una segunda copia de los archivos y el repositorio Git. De ahora en más, 16 | 17 | $ git commit -a 18 | $ git pull otra.computadora:/ruta/a/archivos HEAD 19 | 20 | va a traer (pull) el estado de los archivos desde la otra máquina hacia la que estás trabajando. Si haz hecho cambios que generen conflictos en un archivo, Git te va a avisar y deberías hacer commit luego de resolverlos. 21 | 22 | === Control Clásico de Fuentes === 23 | 24 | Inicializa un repositorio de Git para tus archivos: 25 | 26 | $ git init 27 | $ git add . 28 | $ git commit -m "Commit Inicial" 29 | 30 | En el servidor central, inicializa un repositorio vacío de Git con algún nombre, 31 | y abre el Git daemon si es necesario: 32 | 33 | $ GIT_DIR=proj.git git init 34 | $ git daemon --detach # podría ya estar corriendo 35 | 36 | Algunos servidores publicos, como http://repo.or.cz[repo.or.cz], tienen un método diferente para configurar el repositorio inicialmente vacío de Git, como llenar un formulario en una página. 37 | 38 | Empuja (push) tu proyecto hacia el servidor central con: 39 | 40 | $ git push git://servidor.central/ruta/al/proyecto.git HEAD 41 | 42 | Ya estamos listos. Para copiarse los fuentes, un desarrollador escribe: 43 | 44 | $ git clone git://servidor.central/ruta/al/proyecto.git 45 | 46 | Luego de hacer cambios, el código en envía al servidor central con: 47 | 48 | $ git commit -a 49 | $ git push 50 | 51 | Si hubo actualizaciones en el servidor principal, la última versión debe ser traída antes de enviar lo nuevo. Para sincronizar con la última versión: 52 | 53 | $ git commit -a 54 | $ git pull 55 | 56 | === Bifurcando (fork) un proyecto === 57 | 58 | ¿Harto de la forma en la que se maneja un proyecto?¿Crees que podrías hacerlo mejor? Entonces en tu servidor: 59 | 60 | $ git clone git://servidor.principal/ruta/a/archivos 61 | 62 | Luego avísale a todos de tu fork del proyecto en tu servidor. 63 | 64 | Luego, en cualquier momento, puedes unir (merge) los cambios del proyecto original con: 65 | 66 | $ git pull 67 | 68 | === Respaldos Definitivos === 69 | 70 | ¿Quieres varios respaldos redundantes a prueba de manipulación y geográficamente diversos? Si tu proyecto tiene varios desarrolladores, ¡no hagas nada! Cada clon de tu código es un backup efectivo. No sólo del estado actual, sino que también de la historia completa de tu proyecto. Gracias al hashing criptográfico, si hay corrupción en cualquiera de los clones, va a ser detectado tan pronto como intente comunicarse con otros. 71 | 72 | Si tu proyecto no es tan popular, busca tantos servidores como puedas para hospedar tus clones. 73 | 74 | El verdadero paranoico debería siempre escribir el último hash SHA1 de 20-bytes de su HEAD en algún lugar seguro. Tiene que ser seguro, no privado. Por ejemplo, publicarlo en un diario funcionaría bien, porque es difícil para un atacante el alterar cada copia de un diario. 75 | 76 | === Multitask A La Velocidad De La Luz === 77 | 78 | Digamos que quieres trabajar en varias prestaciones a la vez. Haz commit de tu proyecto y ejecuta: 79 | 80 | $ git clone . /un/nuevo/directorio 81 | 82 | Git se aprovecha de los hard links y de compartir archivos de la manera mas segura posible para crear este clon, por lo que estará listo en un segundo, y podrás trabajar en dos prestaciones independientes de manera simultánea. Por ejemplo, puedes editar un clon mientras el otro está compilando. 83 | 84 | En cualquier momento, puedes hacer commit y pull de los cambios desde el otro clon. 85 | 86 | $ git pull /el/otro/clon HEAD 87 | 88 | === Control Guerrillero De Versiones === 89 | 90 | ¿Estás trabajando en un proyecto que usa algún otro sistema de control de versiones y extrañas mucho a Git? Entonces inicializa un repositorio de Git en tu directorio de trabajo. 91 | 92 | $ git init 93 | $ git add . 94 | $ git commit -m "Commit Inicial" 95 | 96 | y luego clónalo: 97 | 98 | $ git clone . /un/nuevo/directorio 99 | 100 | Ahora debes trabajar en el nuevo directorio, usando Git como te sea más cómodo. Cada tanto, querrás sincronizar con los demás, en ese caso, ve al directorio original, sincroniza usando el otro sistema de control de versiones y escribe: 101 | 102 | $ git add . 103 | $ git commit -m "Sincronizo con los demás" 104 | 105 | Luego ve al nuevo directorio y escribe: 106 | 107 | $ git commit -a -m "Descripción de mis cambios" 108 | $ git pull 109 | 110 | El procedimiento para pasarle tus cambios a los demás depende de cuál es tu otro sistema de control de versiones. El nuevo directorio contiene los archivos con tus cambios. Ejecuta los comandos que sean necesarios para subirlos al repositorio central del otro sistema de control de versiones. 111 | 112 | El comando *git svn* automatiza lo anterior para repositorios de Subversion, 113 | y también puede ser usado para http://google-opensource.blogspot.com/2008/05/export-git-project-to-google-code.html[exportar un proyecto de Git a un repositorio de Subversion]. 114 | -------------------------------------------------------------------------------- /es/intro.txt: -------------------------------------------------------------------------------- 1 | == Introducción == 2 | 3 | Voy a usar una analogía para explicar el control de versiones. Mira http://es.wikipedia.org/wiki/Control_de_versiones[el artículo de wikipedia sobre control de versiones] para una explicación más cuerda. 4 | 5 | === Trabajar Es Jugar === 6 | 7 | He jugado juegos de PC casi toda mi vida. En cambio, empecé a usar sistemas de control de versiones siendo adulto. Sospecho que no soy el único, y comparar ambas cosas puede hacer que estos conceptos sean más fáciles de explicar y entender. 8 | 9 | Piensa en editar tu código o documento, o lo que sea, como si fuera jugar un juego. Una vez que progresaste mucho, te gustaría guardar. Para lograrlo, haces click en el botón de "Guardar" en tu editor de confianza. 10 | 11 | Pero esto va a sobreescribir tu versión antigua. Es como esos viejos juegos que solo tenían un slot para guardar: se podía guardar, pero nunca podías volver a un estado anterior. Esto era una pena, porque tu versión anterior podía haber estado justo en una parte que era particularmente divertida, y podías querer volver a jugarla algún día. O peor aún, tu partida actual está en un estado donde es imposible ganar, y tienes que volver a empezar. 12 | 13 | === Control De Versiones === 14 | 15 | Cuando estás editando, puedes "Guardar Como..." un archivo diferente, o copiar el archivo a otro lugar antes de guardar si quieres probar versiones viejas. También puedes usar compresión para ahorrar espacio. Esta es una forma primitiva y muy trabajosa de control de versiones. Los videojuegos han mejorado esto hace ya tiempo, muchas veces permitiendo guardar en varios slots, fechados automáticamente. 16 | 17 | Hagamos que el problema sea un poco más complejo. Imagina que tienes un montón de archivos que van juntos, como el código fuente de un proyecto, o archivos para un sitio web. Ahora, si quieres mantener una vieja versión, debes archivar un directorio completo. Tener muchar versiones a mano es inconveniente y rápidamente se vuelve costoso. 18 | 19 | Con algunos juegos, una partida guardada en realidad consiste de un directorio lleno de archivos. Estos videojuegos ocultan este detalle del jugador y presentan una interfaz conveniente para administrar diferentes versiones de este directorio. 20 | 21 | Los sistemas de control de versiones no son diferentes. Todos tienen lindas interfaces para administrar un directorio de cosas. Puedes guardar el estado del directorio tantas veces como quieras, y tiempo después puedes cargar cualquiera de los estados guardados. A diferencia de la mayoría de los juegos, normalmente estos sistemas son inteligentes en cuanto la conservación del espacio. Por lo general, solo algunos pocos archivos cambian de versión a versión, y no es un gran cambio. Guardar las diferencias en lugar de nuevas copias ahorra espacio. 22 | 23 | === Control Distribuído === 24 | 25 | Ahora imagina un juego muy difícil. Tan difícil para terminar, que muchos jugadores experientes alrededor del mundo deciden agruparse e intercambiar sus juegos guardados para intentar terminarlo. Los "Speedruns" son ejemplos de la vida real: los jugadores se especializan en diferents niveles del mismo juego y colaboran para lograr resultados sorprendentes. 26 | ¿Cómo armarías un sistema para que puedan descargar las partidas de los otros de manera simple? ¿Y para que suban las nuevas? 27 | 28 | Antes, cada proyecto usaba un control de versiones centralizado. Un servidor en algún lado contenía todos los juegos salvados. Nadie más los tenía. Cada jugador tenía a lo sumo un un par de juegos guardados en su máquina. Cuando un jugador quería progresar, obtenía la última versión del servidor principal, jugaba un rato, guardaba y volvía a subir al servidor para que todos los demás pudieran usarlo. 29 | 30 | ¿Qué pasa si un jugador quería obtener un juego anterior por algún motivo? Tal vez el juego actual está en un estado donde es imposible ganar, porque alguien olvidó obtener un objeto antes de pasar el nivel tres, por que que se quiere obtener el último juego guardado donde todavía es posible completarlo. O tal vez quieren comparar dos estados antiguos, para ver cuánto trabajo hizo un jugador en particular. 31 | 32 | Puede haber varias razones para querer ver una revisión antigua, pero el resultado es siempre el mismo. Tienen que pedirle esa vieja partida al servidor central. Mientras mas juegos guardados se quieran, más se necesita esa comunicación. 33 | 34 | La nueva generación de sistemas de control de versiones, de la cual Git es miembro, se conoce como sistemas distribuídos, y se puede pensar en ella como una generalización de sistemas centralizados. Cuando los jugadores descargan del servidor central, obtienen todos los juegos guardados, no solo el último. Es como si tuvieran un mirror del servidor central. 35 | 36 | Esta operación inicial de clonado, puede ser cara, especialmente si el historial es largo, pero a la larga termina siendo mejor. Un beneficio inmediato es que cuando se quiere una versión vieja por el motivo que sea, la comunicación con el servidor es innecesaria. 37 | 38 | ==== Una Tonta Superstición ==== 39 | 40 | Una creencia popular errónea es que los sistemas distribuídos son poco apropiados para proyectos que requieren un repositorio central oficial. Nada podría estar más lejos de la verdad. Fotografiar a alguien no hace que su alma sea robada, clonar el repositorio central no disminuye su importancia. 41 | 42 | Una buena aproximación inicial, es que cualquier cosa que se puede hacer con un sistema de control de versiones centralizado, se puede hacer mejor con un sistema de versiones distribuído que esté bien diseñado. Los recursos de red son simplemente más costosos que los recursos locales. Aunque luego veremos que hay algunas desventajas para un sistema distribuído, hay menos probabilidad de hacer comparaciones erroneas al tener esto en cuenta. 43 | 44 | Un proyecto pequeño, puede necesitar solo una fracción de de las características que un sistema así ofrece. Pero, ¿usarías números romanos si solo necesitas usar números pequeños?. Además, tu proyecto puede crecer más allá de tus expectativas originales. Usar Git desde el comienzo, es como llevar una navaja suiza, aunque solo pretendas usarla para abrir botellas. El día que necesites desesperadamente un destornillador, vas a agradecer el tener más que un simple destapador. 45 | 46 | === Conflictos al fusionar === 47 | 48 | Para este tema, habría que estirar demasiado nuestra analogía con un videojuego. En lugar de eso, esta vez consideremos editar un documento. 49 | 50 | Supongamos que Alice inserta una línea al comienzo de un archivo, y Bob agrega una línea al final de su copia. Ambos suben sus cambios. La mayoría de los sistemas automáticamente van a deducir un accionar razonable: aceptar y hacer merge (Nota del Traductor: fusionar en inglés) de los cambios, para que tanto la edición de Alice como la de Bob sean aplicadas. 51 | 52 | Ahora supongamos que Alice y Bob han hecho ediciones distintas sobre la misma línea. Entonces es imposible resolver el conflicto sin intervención humana.Se le informa a la segunda persona en hacer upload que hay un conflicto de merge, y ellos deben elegir entre ambas ediciones, o cambiar la línea por completo. 53 | 54 | Pueden surgir situaciones más complejas. Los sistemas de control de versiones manejan automáticamente los casos simples, y dejan los más complejos para los humanos. Usualmente este comportamiento es configurable. 55 | -------------------------------------------------------------------------------- /es/preface.txt: -------------------------------------------------------------------------------- 1 | = Git Magic = 2 | Ben Lynn 3 | August 2007 4 | 5 | == Prólogo == 6 | 7 | http://git.or.cz/[Git] es la navaja suiza del control de versiones. Una herramienta de control de revisiones confiable, versátil y multipropósito, que por su extraordinaria flexibilidad es complicada de aprender, y más aún de dominar. Estoy documentando lo que he aprendido hasta ahora en estas páginas, porque inicialmente tuve dificultades para comprender http://www.kernel.org/pub/software/scm/git/docs/user-manual.html[el manual de usuario de Git]. 8 | 9 | Tal como observó Arthur C. Clarke, cualquier tecnología suficientemente avanzada, es indistinguible de la magia. Este es un gran modo de acercarce a Git: los novatos pueden ignorar su funcionamiento interno, y ver a Git como un artefacto que puede asombrar a los amigos y enfurecer a los enemigos con sus maravillosas habilidades. 10 | 11 | En lugar de ser detallados, proveemos instrucciones generales para efectos particulares. Luego de un uso reiterado, gradualmente irás entendiendo como funciona cada truco, y como adaptar las recetas a tus necesidades. 12 | 13 | .Otras ediciones 14 | 15 | - http://docs.google.com/View?id=dfwthj68_675gz3bw8kj[Traducción al chino]: por JunJie, Meng y JiangWei. 16 | - link:book.html[Una única página]: HTML simple, sin CSS. 17 | - link:book.pdf[Archivo PDF]: Listo para imprimir. 18 | - http://packages.debian.org/search?searchon=names&keywords=gitmagic[Paquete gitmagic para Debian]: Consigue una copia rápida y local de este sitio. http://packages.ubuntu.com/jaunty/gitmagic[Paquete para Ubuntu (Jaunty Jackalope)] también disponible. Útil http://csdcf.stanford.edu/status/[cuando este servidor está offline para mantenimiento]. 19 | 20 | === Gracias! === 21 | 22 | Agradezco a Dustin Sallings, Alberto Bertogli, James Cameron, Douglas Livingstone, Michael Budde, Richard Albury, Tarmigan, Derek Mahar y Frode Aannevik por sugerencias y mejoras. Gracias a Daniel Baumann por crear y mantener el paquete para Debian. También gracias a JunJie, Meng y JiangWei por la traduccción al chino. [Si me olvidé de tí, por favor recuérdamelo, porque suelo olvidarme de actualizar esta sección] 23 | 24 | Estoy muy agradecido por todos los que me han dado apoyo y elogios. Me gustaría que este fuera un libro real impreso, para poder citar sus generosas palabras en la tapa a modo de promoción. Hablando en serio, aprecio enormemente cada mensaje. El leerlos siempre ilumina mi ánimo. 25 | 26 | === Licencia === 27 | 28 | Esta guía se publica bajo la http://www.gnu.org/licenses/gpl-3.0.html[GNU General Public License versión 3]. Naturalmente, los fuentes se guardan en un repositorio Git, y pueden ser obtenidos escribiendo: 29 | 30 | $ git clone git://repo.or.cz/gitmagic.git # Crea el directorio "gitmagic". 31 | 32 | Ver debajo por otros mirrors. 33 | 34 | === Hosting Git gratuito === 35 | 36 | - http://repo.or.cz/[http://repo.or.cz/] hospeda proyectos gratuitos, 37 | http://repo.or.cz/w/gitmagic.git[incluyendo esta guía]. 38 | - http://gitorious.org/[http://gitorious.org/] es un sitio que apunta al hosting de proyectos open-source. 39 | - http://github.com/[http://github.com/] hospeda proyectos open-source gratis, http://github.com/blynn/gitmagic/tree/master[incluyendo esta guía], y proyectos privados por una cuota. 40 | -------------------------------------------------------------------------------- /es/spanish.txt: -------------------------------------------------------------------------------- 1 | === Last revision in which the translation was synchronized === 2 | preface.txt 09751f37469d32da649b1c64862023820e0d0499 3 | intro.txt 09751f37469d32da649b1c64862023820e0d0499 4 | basic.txt 09751f37469d32da649b1c64862023820e0d0499 5 | clone.txt 46c05532226868b8b3b121d9320c0150491fd181 6 | branch.txt 46c05532226868b8b3b121d9320c0150491fd181 7 | history.txt 8 | grandmaster.txt 9 | secrets.txt 10 | drawbacks.txt 11 | -------------------------------------------------------------------------------- /find_selflink.js: -------------------------------------------------------------------------------- 1 | // From my own website(!) 2 | //TODO: only do this for links in the table of contents menu 3 | 4 | function find_selflink() { 5 | var a = document.links; 6 | var i = 0; 7 | while (i < a.length) { 8 | if (a[i].href == document.URL) { 9 | var c; 10 | var j; 11 | var s_new = document.createElement("span"); 12 | s_new.className = "currentlink"; 13 | c = a[i].childNodes; 14 | for (j=0; j/ { 8 | print $0 9 | getline 10 | print $0 11 | print "
  • '"$TITLE"'
  • " 12 | getline 13 | while (!match($0, "")) { 14 | gsub("pr01.html", "index.html") 15 | print $0 16 | getline 17 | } 18 | print $0 19 | exit 20 | } 21 | ' < $BOOKDIR/index.html > toc.tmp 22 | 23 | # For every file except the index... 24 | for FILE in $BOOKDIR/*.html 25 | do 26 | if [ $FILE != "$BOOKDIR/index.html" ] 27 | then 28 | # Prepend "Git Magic - " to titles of all pages. 29 | sed '// s/<title>/&Git Magic - /' -i $FILE 30 | sed 's/pr01\.html/index.html/g' -i $FILE 31 | # Paste ToC into beginning and add div section with class content for CSS. 32 | sed '/<body/{n; r toc.tmp 33 | a <div class="content"> 34 | }' -i $FILE 35 | sed '/^<\/body/i </div>' -i $FILE 36 | fi 37 | done 38 | 39 | # Originally this link was "My Homepage". Since it appears on translations of 40 | # the guide, I changed it to my name so it doesn't have to be translated. 41 | sed '/^<\/body/i </div><div class="footer"><a href="/~blynn/">Ben Lynn</a></div>' -i $BOOKDIR/*.html 42 | 43 | cp $BOOKDIR/pr01.html $BOOKDIR/index.html 44 | rm toc.tmp 45 | -------------------------------------------------------------------------------- /ru/basic.txt: -------------------------------------------------------------------------------- 1 | == Базовые операции == 2 | 3 | Прежде чем погружаться в дебри многочисленных команд Git, попробуйте воспользоваться приведёнными ниже простыми примерами, чтобы немного освоиться. Несмотря на свою простоту, каждый из них является полезным. 4 | 5 | В самом деле, первые месяцы использования Git я не выходил за рамки материала, изложенного в этой главе. 6 | 7 | === Сохранение состояния === 8 | 9 | Выполняете опасную операцию? Прежде чем сделать это, создайте снимок всех файлов в текущей директории с помощью команд: 10 | 11 | $ git init 12 | $ git add . 13 | $ git commit -m "Мой первый бекап" 14 | 15 | Теперь, если ваши новые правки всё испортили, запустите: 16 | 17 | $ git reset --hard 18 | 19 | чтобы вернуться к исходному состоянию. Чтобы вновь сохраниться, выполните: 20 | 21 | $ git commit -a -m "Другой бекап" 22 | 23 | ==== Добавление, удаление, переименование ==== 24 | 25 | Приведенный выше пример будет отслеживать файлы, которые вы добавили, когда впервые запустили *git add*. Если вы хотите добавить новые файлы или поддиректории, вам придётся сказать Git: 26 | 27 | $ git add НОВЫЕ_ФАЙЛЫ... 28 | 29 | Аналогично, если вы хотите, чтобы Git забыл о некоторых файлах, например, потому что вы удалили их: 30 | 31 | $ git rm СТАРЫЕ_ФАЙЛЫ... 32 | 33 | Переименование файла — это то же, что и удаление старого имени и добавления нового. Для этого есть *git mv*, который имеет тот же синтаксис, что и команда *mv*. Например: 34 | 35 | $ git mv OLDFILE NEWFILE 36 | 37 | === Расширенная отмена/Восстановление === 38 | 39 | Иногда вы просто хотите вернуться к определенной точке и забыть все изменения, потому что все они были неправильными. В таком случае: 40 | 41 | $ git log 42 | 43 | покажет вам список последних изменений (коммитов, прим. пер.) и их SHA1 хеши. Далее введите: 44 | 45 | $ git reset --hard SHA1_HASH 46 | 47 | для восстановления состояния до указанного коммита и удаления всех последующих коммитов безвозвратно. 48 | 49 | Возможно, в другой раз вы захотите быстро вернуться к старому состоянию. В этом случае наберите: 50 | 51 | $ git checkout SHA1_HASH 52 | 53 | Это перенесет вас назад во времени, до тех пор пока вы не сделаете новые коммиты. Как и в фантастических фильмах о путешествиях во времени, если вы редактируете и коммитите код, вы будете находиться в альтернативной реальности, потому что ваши действия отличаются от тех, что вы делали до этого. 54 | 55 | Эта альтернативная реальность называется «ветвь» (branch, прим. пер.), и 56 | <<branch,чуть позже мы поговорим об этом>>. А сейчас просто запомните: 57 | 58 | $ git checkout master 59 | 60 | вернёт вас обратно в настоящее. Кроме того, чтобы не получать предупреждений от Git, всегда делайте коммит или сброс ваших изменений до запуска checkout. 61 | 62 | Ещё раз воспользуемся терминологией компьютерных игр: 63 | 64 | - *`git reset --hard`*: загружает ранее сохраненную игру и удаляет все версии, сохраненные после только что загруженной. 65 | 66 | - *`git checkout`*: загружает старую игру, но если вы продолжаете играть, состояние игры будет отличаться от более новых сохранений, которые вы сделали в первый раз. Любая игра, которую вы теперь сохраняете, попадает в отдельную ветвь, представляющую альтенативную реальность, в которую вы вошли. 67 | <<branch,Как мы договорились, о бранчах поговорим позже>>. 68 | 69 | Вы можете выбрать для восстановления только определенные файлы и поддиректории путём перечисления их имён после команды: 70 | 71 | $ git checkout SHA1_HASH some.file another.file 72 | 73 | Будьте внимательны: такая форма *checkout* может незаметно перезаписать файлы. Чтобы избежать неприятных неожиданностей, выполняйте коммит до запуска checkout, особенно если вы только осваиваетесь с Git. Вообще, если вы не уверены в какой-либо операции, будь то команда Git или нет, сперва выполните *git commit -a*. 74 | 75 | Не любите копировать и вставлять хеши? Используйте: 76 | 77 | $ git checkout :/"Мой первый б" 78 | 79 | для перехода на коммит, который начинается с приведенной строки. 80 | 81 | Можно также запросить 5-ое с конца сохраненное состояние: 82 | 83 | $ git checkout master~5 84 | 85 | ==== Возвраты ==== 86 | 87 | В зале суда в протокол могут вноситься изменения прямо во время слушания. Подобным образом и вы можете выбирать коммиты для возврата. 88 | 89 | $ git commit -a 90 | $ git revert SHA1_HASH 91 | 92 | отменит коммит с выбранным хешем. Запущенный *git log* показывает, что изменение записано в качестве нового коммита. 93 | 94 | === Создание списка изменений === 95 | 96 | Некоторым проектам требуется http://en.wikipedia.org/wiki/Changelog[список изменений] (changelog, прим. пер.). 97 | Создать такой список вы можете, просто направив вывод *git log* в файл: 98 | 99 | $ git log > ChangeLog 100 | 101 | === Скачивание файлов === 102 | 103 | Получить копию проекта под управлением Git можно, набрав: 104 | 105 | $ git clone git://server/path/to/files 106 | 107 | Например, чтобы получить все файлы, я создавал такой сайт: 108 | 109 | $ git clone git://git.or.cz/gitmagic.git 110 | 111 | Мы поговорим больше о команде *clone* позже. 112 | 113 | === На острие ножа === 114 | 115 | Если вы уже загрузили копию проекта с помощью *git clone*, вы можете обновить его до последней версии, используя: 116 | 117 | $ git pull 118 | 119 | === Публичный доступ === 120 | 121 | Предположим, вы написали скрипт, которым хотите поделиться с другими. Можно просто позволить всем загружать его с вашего компьютера, но, если они будут делать это в то время, как вы дорабатываете его или добавляете экспериментальную функциональность, у них могут возникнуть проблемы. Конечно, это одна из причин существования цикла разработки. Разработчики могут долго работать над проектом, но открывать доступ к коду следует только после того, как код приведен в приличный вид. 122 | 123 | Чтобы сделать это с помощью Git, выполните в директории, где лежит ваш скрипт: 124 | 125 | $ git init 126 | $ git add . 127 | $ git commit -m "Первый релиз" 128 | 129 | Затем скажите вашим пользователям запустить: 130 | 131 | $ git clone ваш.компьютер:/path/to/script 132 | 133 | для того чтобы загрузить ваш скрипт. Это подразумевает что у вас есть доступ по ssh. Если нет, запустите *git daemon* и скажите остальным использовать для запуска: 134 | 135 | $ git clone git://ваш.компьютер/path/to/script 136 | 137 | Теперь, всякий раз когда ваш скрипт готов к релизу, выполняйте: 138 | 139 | $ git commit -a -m "Следующий релиз" 140 | 141 | и ваши пользователи смогут обновить свои версии, перейдя в директорию, содержащую ваш скрипт, и, набрав: 142 | 143 | $ git pull 144 | 145 | ваши пользователи никогда не попадут на версии скрипта, доступ к которым вы скрываете. Безусловно, этот трюк работает для всего, а не только в случаях со скриптами. 146 | 147 | === Что я наделал? === 148 | 149 | Выясните, какие изменения вы сделали со времени последнего коммита: 150 | 151 | $ git diff 152 | 153 | Или со вчерашнего дня: 154 | 155 | $ git diff "@{yesterday}" 156 | 157 | Или между определенной версией и версией, сделанной 2 коммита назад: 158 | 159 | $ git diff SHA1_HASH "master~2" 160 | 161 | В каждом случае на выходе будет патч, который может быть применён с помощью *git apply*. 162 | 163 | Попробуйте также: 164 | 165 | $ git whatchanged --since="2 weeks ago" 166 | 167 | Часто я смотрю историю при помощи http://sourceforge.net/projects/qgit[qgit] вместо стандартного способа, 168 | из-за приятного интерфейса, или с помощью http://jonas.nitro.dk/tig[tig] с текстовым интерфейсом, 169 | который хорошо работает при медленном соединении. В качестве альтернативы, можно запустить веб-сервер, 170 | введя *git instaweb*, и запустить любой веб-браузер. 171 | 172 | === Упражнение === 173 | 174 | Пусть A, B, C, D четыре успешных коммита, где В — то же, что и A, но с несколькими удаленными файлами. Мы хотим вернуть файлы в D, но не в B. Как это можно сделать? 175 | 176 | Существует как минимум три решения. Предположим, что мы находимся на D. 177 | 178 | 1. Разница между A и B — удаление файлов. 179 | Мы можем создать патч, отражающий эти изменения, и применить его: 180 | 181 | $ git diff B A | git apply 182 | 183 | 2. Поскольку в коммите A мы сохранили файлы, мы можем получить их обратно: 184 | 185 | $ git checkout A FILES... 186 | 187 | 3. Мы можем рассматривать переход от A до B в качестве изменений, которые мы хотим отменить: 188 | 189 | $ git revert B 190 | 191 | Какой способ лучший? 192 | Тот, который вам больше нравится. С Git легко сделать все, что вы хотите, причём часто существует много разных способов сделать одно и то-же. 193 | 194 | -------------------------------------------------------------------------------- /ru/branch.txt: -------------------------------------------------------------------------------- 1 | == Чудеса ветвления == 2 | Возможности мгновенного разветвления и слияния - самые уникальные особенности Git. 3 | 4 | *Задача*: какие-то причины требуют переключения процессов. В новой версии внезапно возникает серьезная ошибка. Срок завершения работы над определенным свойством близится к концу. Разработчик, помощь которого очень нужна Вам в работе над ключевым разделом, собирается в отпуск. Итак, Вам нужно срочно бросить все, над чем Вы трудитесь в настоящий момент, и переключиться на совершенно другие дела. 5 | 6 | Переключение внимания с одного на другое может серьезно снизить эффективность работы, и чем сложнее переход между процессами, тем больше будет потеря. При централизованном управлении версиями необходимо скачивать вновь разработанную рабочую копию с центрального сервера. Распределенная система предоставляет лучшие возможности, так как позволяет клонировать нужную версию в локальное рабочее место. 7 | 8 | Однако клонирование все же предполагает копирование всей рабочей директории, а, значит, всей истории изменений до настоящего момента. Даже при том, что Git позволяет сэкономить средства за счет возможности совместного использования файлов и жестких ссылок, все файлы проекта придется полностью воссоздать в новой рабочей директории. 9 | 10 | *Решение*: у Git есть более удобный инструмент для этих целей, который, в отличие от клонирования, сэкономит и время, и дисковое пространство - это *git branch*. 11 | 12 | С этой волшебной командой файлы в вашей директории мгновенно изменяются с одной версии на другую. Это изменение позволяет сделать намного больше, чем просто вернуться назад или продвинуться вперед в истории. Ваши файлы могут изменится с последней версии на экспериментальную, с экспериментальной - на опытную, с опытной - на версию вашего друга и так далее. 13 | 14 | === Кнопка босса === 15 | 16 | Наверняка, вы играли в одну из тех игр, где при нажатии определеной клавиши ("кнопка босса"), игра быстро сворачивается и на экране отображается рабочая таблица или что-нибудь другое? То есть, если в офис зашел начальник, а вы играете в игру, вы должны уметь быстро ее скрыть. 17 | 18 | В какой-нибудь директории: 19 | 20 | $ echo "Я хитрее моего босса" > myfile.txt 21 | $ git init 22 | $ git add . 23 | $ git commit -m "Начальный коммит" 24 | 25 | Мы создали Git-репозиторий который содержит один текстовый файл с определенным сообщением. Теперь выполните: 26 | 27 | $ git checkout -b boss # вероятно, это последнее изменение 28 | $ echo "Мой босс меня умнее" > myfile.txt 29 | $ git commit -a -m "Другой коммит" 30 | 31 | Похоже на то, как будто мы перезаписали файл и сделали коммит. Но это иллюзия. Наберите: 32 | 33 | $ git checkout master # переключиться на оригинальную версию файла 34 | 35 | Вуаля! Текстовый файл восстановлен. И если босс будет рядом, запустите 36 | 37 | $ git checkout boss # перейти на специальную версию для босса 38 | 39 | Вы можете переключаться между двумя версиями этого файла так часто, как вам хочется и делать коммиты в каждый из них независимо. 40 | 41 | === Грязная работа === 42 | 43 | [[branch]] 44 | 45 | Допустим, вы работаете над созданием какой-либо функции, и по каким-то причинам необходимо вернуться назад к 46 | старой версии и временно загрузить старый код, чтобы посмотреть как что-либо работало, тогда введите: 47 | 48 | $ git commit -a 49 | $ git checkout SHA1_HASH 50 | 51 | Теперь вы можете добавить везде, где необходимо, временный черновой код. Можно даже сделать коммит изменений. Когда закончите, выполните: 52 | 53 | $ git checkout master 54 | 55 | чтобы вернуться к исходной работе. Заметьте, что любые изменения, не внесенные в коммит, будут перенесены. 56 | 57 | А что, если вы все-таки хотели сохранить временные изменения? Пожалуйста: 58 | 59 | $ git checkout -b dirty 60 | 61 | а затем сделайте коммит перед тем, как переключетесь на ветвь master. Всякий раз когда вы захотите вернуться к черновым изменениям, просто выполните: 62 | 63 | $ git checkout dirty 64 | 65 | Мы говорили об этой команде ранее, в другой главе, когда обсуждали загрузку старых состояний. Теперь у нас перед глазами полная картина: файлы меняются на нужное состояние, но мы должны оставить ветвь master. Любые коммиты, сделанные с этого момента, направят файлы по другому пути, который может быть назван позже. 66 | 67 | Другими словами, после переключения с более старого состояния, Git автоматически направляет вас в новую еще не названную ветвь, которой можно дать имя и сохранить с помощью *git checkout -b*. 68 | 69 | === Быстрые исправления === 70 | 71 | Ваша работа в самом разгаре, когда вдруг выясняется, что нужно все бросить и исправить только что обнаруженную ошибку: 72 | 73 | $ git commit -a 74 | $ git checkout -b fixes SHA1_HASH 75 | 76 | Затем, после того, как вы исправили ошибку: 77 | 78 | $ git commit -a -m "Ошибка исправлена" 79 | $ git push # в центральный репозиторий 80 | $ git checkout master 81 | 82 | и вернитесь к работе над вашими исходными задачами. 83 | 84 | === Бесперебойный рабочий процесс === 85 | 86 | В некоторых проектах необходимо проверять код до того, как выложить его. Чтобы облегчить задачу другим разработчикам, которые будут проверять ваш код, при внесении значительных изменений, разбивайте измененный проект на 2 или более частей и выкладывайте по одной для проверки. 87 | 88 | А что, если вторую часть нельзя записать до того, как первая часть проверена и принята? Во многих системах управления версиями отправить на рассмотрение вторую часть можно только после утверждения первой части. 89 | 90 | На самом деле это не совсем правда, но необходимость в таких системах редактировать часть II перед тем, как отправить часть I, связана с трудностями и неудобствами. В Git, ветвление и слияние гораздо безболезненней (говоря техническим языком - это можно сделать быстрее и на локальном уровне). Поэтому, после того, как вы сделали коммит первой части, и направили его для рассмотрения: 91 | 92 | $ git checkout -b part2 93 | 94 | Далее, можно изменять вторую часть, не ожидая принятия первой части. После того, как первая часть утверждена и выложена, 95 | 96 | $ git checkout master 97 | $ git merge part2 98 | $ git branch -d part2 # эта ветка больше не нужна 99 | 100 | и вторая часть правок готова к проверке. 101 | 102 | Однако не торопитесь! Что, если не все так просто? Что, если в первой части вы сделали ошибку, которую необходимо было исправить до отправки. Запросто! Во-первых, вернитесь в master-ветвь с помощью: 103 | 104 | $ git checkout master 105 | 106 | Исправьте изменения в первой части и отправьте на проверку. Если же они не будут приняты, можно просто повторить этот шаг. Вы, вероятно, также захотите произвести слияние исправлений части I с частью II, тогда выполните: 107 | 108 | $ git checkout part2 109 | $ git merge master 110 | 111 | И теперь - тоже самое. После того, как первая часть утверждена и выложена: 112 | 113 | $ git checkout master 114 | $ git merge part2 115 | $ git branch -d part2 116 | 117 | и снова, вторая часть готова к проверке. 118 | 119 | Вы можете легко использовать этот трюк для любого количества частей. 120 | 121 | === Собрать все в кучу === 122 | 123 | Предположим, вам нравится работать над всеми аспектами проекта в одной и той же ветке. Вы хотите закрыть свой рабочий процесс от других, чтобы все видели ваши коммиты только после того, как они будут хорошо оформлены. Создайте несколько веток: 124 | 125 | $ git checkout -b sanitized 126 | $ git checkout -b medley 127 | 128 | Далее, работайте над чем угодно: исправляйте ошибки, добавляйте новые функции, добавляйте временный код и т.д., при этом постоянно выполняя коммиты. Затем: 129 | 130 | $ git checkout sanitized 131 | $ git cherry-pick SHA1_HASH 132 | 133 | применит данный коммит для ветви"sanitized". С правильно выбранными элементами вы сможете собрать ветвь, которая будет содержать только проверенный код и соответствующие коммиты, сгруппированные вместе. 134 | 135 | === Управление Ветками === 136 | 137 | Для просмотра списка всех веток наберите: 138 | 139 | $ git branch 140 | 141 | Здесь всегда будет ветка с названием "master", с нее вы начинаете работать по умолчанию. Кому-то нравится оставлять ветку "master" нетронутой и создавать новые ветки со своими изменениями. 142 | 143 | Опции *-d* и *-m* позволяют удалять и перемещать (переименовывать) ветки. 144 | 145 | См. *git help branch*. 146 | 147 | Ветка "master" - это полезная традиция. Все считают очевидным то, что ваш репозиторий должен содержать ветку с таким именем, и эта ветка содержит официальную версию проекта. Вы можете переименовать или удалить ветку "master", однако лучше соблюсти всеобщую традицию. 148 | 149 | === Временные Ветки === 150 | 151 | Через какое-то время вы можете обнаружить, что создаете множество временных веток для одной и той краткосрочной цели: нужно сохранить текущее состояние, чтобы была возможность вернуться назад и исправить грубую ошибку или сделать что-то еще. 152 | 153 | Это похоже на то, как вы переключаете телевизионные каналы, чтобы посмотреть что показывают по другим. Но здесь, вместо того, чтобы нажать на пару кнопок на пульте, нужно будет создать, сделать отладку, а затем удалить временные ветки и коммиты. К счастью, в Git есть удобные ярлыки, имитирующие работу дистанционного пульта правления. 154 | 155 | $ git stash 156 | 157 | Это сохраняет текущее состояние в во временном месте ('копилке') и востанавливает предыдущее состояние. Ваша директория становиться точно такой, как и была до того, как вы начали редактирование, и вы можете исправить ошибки, загрузить удаленные изменения и прочее. Когда вы хотите вернуться назад в состояние копилки, наберите: 158 | 159 | $ git stash apply # Возможно, понадобится устранить какие-либо конфликты. 160 | 161 | Можно создавать несколько копилок, приумножать их и использовать по-разному. Смотрите *git help stash*. Как вы могли догадаться, этот чудесный прием возможен благодаря способности Git поддерживать создание закрытых "тайных" веток. 162 | 163 | === Работайте как вам нравится === 164 | 165 | Такие приложения как http://www.mozilla.com/[Mozilla Firefox] позволяют открывать несколько вкладок, и несколько окон. Переключение вкладок позволяет обозревать разное содержание в одном и том же окне. Ветки в Git подобны вкладкам для вашей рабочей директории. Если продолжить аналогию, клонирование в Git подобно открытию нового окна. Эти две возможности делают работу в Git удобной и приятной для пользователя. 166 | 167 | На более высоком уровне, многие оконные менеджеры Linux поддерживают несколько рабочих столов. 168 | 169 | Ветки в Git подобны переключению на другой рабочий стол, а клонирование подобно подключению дополнительно монитора для получения дополнительного рабочего стола. 170 | 171 | Другой пример - это утилита http://www.gnu.org/software/screen/[*screen*]. Эта программа позволяет создавать, закрывать и переключаться между множеством терминальных сессий в одном и том же терминале. Вместо открытия нового терминала (операция клонирования), можно использовать этот, запустив *screen* (создать ветвь). На самом деле у *screen* еще много возможностей, но это уже тема для другой главы. 172 | 173 | Наличие возможностей клонирования, ветвления и быстрого локального слияния позволяет вам выбрать комбинировать их так, как удобно и нужно вам. Git позволяет работать именно так, как вам хочется. 174 | -------------------------------------------------------------------------------- /ru/clone.txt: -------------------------------------------------------------------------------- 1 | == Все о клонировании == 2 | 3 | В старых системах контроля версий checkout - это стандартная операция для получения файлов. Вы получаете файлы в нужном сохраненном состоянии. 4 | 5 | В Git и других распределенных системах контроля версий, клонирование - это обычно дело. Для получение файлов вы создаете клон всего репозитория. Другими словами, вы создаете зеркало центрального сервера. При этом все что можно делать в основном репозитории, можно делать и в локальном. 6 | 7 | === Синхронизация компьютеров === 8 | 9 | По этой причине я начал использовать Git. Я вполне приемлю синхронизацию архивами или использование *rsync* для бэкапа или процедуры стандартной синхронизации. Но я работаю то на ноутбуке, то на стационарном компьютере, которые никак между собой не взаимодействуют. 10 | 11 | Инициализируйте Git репозиторий и делайте коммит файлов на одном компьютере. А потом выполните следующие операции на другом: 12 | 13 | $ git clone other.computer:/path/to/files 14 | 15 | для создания второй копии файлов и Git репозитория. С этого момента выполняйте, 16 | 17 | $ git commit -a 18 | $ git pull other.computer:/path/to/files HEAD 19 | 20 | это синхронизирует состояние ваших файлов с состоянием файлов другого компьютера. Если вы внесли изменения, которые будут конфликтовать с таким же файлом, Git даст Вам знать об этом, и вам придется сделать коммит еще раз, уже после устранения конфликтующих изменений. 21 | 22 | === Классический контроль исходного кода === 23 | 24 | Инициализируйте Git-репозиторий для ваших файлов: 25 | 26 | $ git init 27 | $ git add . 28 | $ git commit -m "Initial commit" 29 | 30 | На центральном сервере инициализируйте пустой Git-репозиторий с присвоением какого-нибудь имени, 31 | 32 | и запустите Git-демон, если необходимо: 33 | 34 | $ GIT_DIR=proj.git git init 35 | $ git daemon --detach # возможно уже запущен 36 | 37 | Публичные репозитории, такие как http://repo.or.cz[repo.or.cz], имеют собственные схемы по организации изначально пустых Git-репозиториев, которые обычно предполагают регистрацию и заполнение формы. 38 | 39 | Чтобы сохранить ваши изменения в центральный репозиторий, запустите: 40 | 41 | $ git push git://central.server/path/to/proj.git HEAD 42 | 43 | Для клонирования, как уже было описано выше, необходимо: 44 | 45 | $ git clone git://central.server/path/to/proj.git 46 | 47 | После внесения изменений, код записывается на главный сервер с помощью: 48 | 49 | $ git commit -a 50 | $ git push 51 | 52 | Если в ходе работы на сервере уже происходили изменения, необходимо обновить локальную копию репозитория перед сохранением собственных изменений. Для синхронизации: 53 | 54 | $ git commit -a 55 | $ git pull 56 | 57 | === Создание форка проекта === 58 | 59 | Не нравится путь развития проекта? Думаете можете сделать лучше? Тогда на Вашем сервере: 60 | 61 | $ git clone git://main.server/path/to/files 62 | 63 | Теперь расскажите всем, что новый проект находится на вашем сервере. 64 | 65 | В любое время вы можете объединить изменения с изначальным проектом, используя: 66 | 67 | $ git pull 68 | 69 | === Окончательные бэкапы === 70 | 71 | Хотите создать множество географически разнесенных, разных, защищенных, резервных архивов? Если в вашем проекте много разработчиков - делать ничего не надо! Каждый клон - это и есть бэкап, причем отражающий не только текущее состояние, но и всю историю изменений проекта. Благодаря криптографическому хешированию, при нарушении какого-либо из клонов, этот клон будет помечен, и это будет видно при любой попытке взаимодействия с ним. 72 | 73 | Если ваш проект не такой популярный, размещайте клоны на как можно большем количестве серверов. 74 | 75 | Особо беспокоящимся рекомендуется всегда записывать самый последний 20-байтный SHA1 хеш HEAD в безопасном месте. В безопасном, но не тайном. Например, в газете, это будет эффективным, потому как сложно изменить каждую копию газеты. 76 | 77 | === Многозадачность со скоростью света === 78 | 79 | Скажем, вы хотите выполнять несколько задач параллельно. Тогда сохраните свой проект и запустите: 80 | 81 | $ git clone . /some/new/directory 82 | 83 | Git использует жесткие ссылки и обмен файлами настолько безопасно, насколько это возможно для создания такого клона, он будет готов мгновенно, после чего можно будет работать с разными функциями одновременно. Например, можно редактировать один клон, компилируя в это время другой. 84 | 85 | В любое время можно сделать коммит и вытянуть изменения из другого клона. 86 | 87 | $ git pull /the/other/clone HEAD 88 | 89 | === Другие системы контроля версий === 90 | 91 | Вы работаете над проектом, который использует другую систему контроля версий, и вам не хватает Git? Тогда инициализируйте Git-репозиторий в свою рабочую папку: 92 | 93 | $ git init 94 | $ git add . 95 | $ git commit -m "Initial commit" 96 | 97 | затем клонируйте его: 98 | 99 | $ git clone . /some/new/directory 100 | 101 | Теперь перейдите в новую директорию и работайте в ней, используя для контроля версий Git. Когда вам понадобиться синхронизировать изменения с другими, перейдите в изначальную директорию и произведите синхронизацию с помощью другой системы контроля версий, затем наберите: 102 | 103 | $ git add . 104 | $ git commit -m "Синхронизироваться с другими" 105 | 106 | Теперь перейдите в новую директорию и запустите: 107 | 108 | $ git commit -a -m "Описание моих изменений" 109 | $ git pull 110 | 111 | Процедура обмена изменениями с другими зависит от используемой системы контроля версий. Новая директория содержит файлы с вашими изменениями. Для загрузки файлов в центральный репозиторий требуется запуск любых необходимых команд другой системы контроля версий. 112 | 113 | Команда *git svn* автоматизирует этот процесс для репозиториев Subversion и может быть использована для http://google-opensource.blogspot.com/2008/05/export-git-project-to-google-code.html[экспорта Git проекта в Subversion репозиторий]. 114 | -------------------------------------------------------------------------------- /ru/drawbacks.txt: -------------------------------------------------------------------------------- 1 | == Недостатки Git == 2 | 3 | Есть некоторые проблемы Git, которые я спрятал под сукно. Некоторые из них можно легко решить с помощью сценариев и хуков, некоторые требуют реорганизации или пересмотра проекта, и из нескольких оставшихся неприятности, одну придется терпеть. Или еще лучше, взяться за нее и решить! 4 | 5 | === Недостатки SHA1 === 6 | 7 | Со временем, криптографы обнаружать более слабые SHA1. Уже нахождения хэш столкновений является допустимым для хорошо финансируемой организации. За годы, возможно, даже типичный ПК будет иметь достаточную вычислительную мощность, чтобы потихоньку скоррумпировать Git репозиторий. 8 | 9 | Надеюсь Git мигрирует к лучшей хэш-функции до того, как дальнейшие исследования разрушат SHA1. 10 | 11 | === Microsoft Windows === 12 | 13 | Git на Microsoft Windows может быть накладным: 14 | 15 | - http://cygwin.com/[Cygwin], Linux-среда для Windows, содержит http://cygwin.com/packages/git/[порт Git на Windows]. 16 | 17 | -http://code.google.com/p/msysgit/[Git на MSys] вариант, требующий минимальной рантайм поддержки, хотя для нескольких команд, нужна доработка. 18 | 19 | === Несвязанные файлы === 20 | 21 | Если ваш проект очень большой и содержит много не связанных файлов, которые постоянно изменяются, Git может оказаться в невыгодном положении по сравнению с другими системами, поскольку отдельные файлы не отслеживаются. Git отслеживает изменения всего проекта, такой подход, как правило, полезен. 22 | 23 | Решение - разбить проект на части, каждая из которых состоит из связанных файлов. Используйте *git submodule* если вы все еще хотите держать все в одном репозитории. 24 | 25 | === Кто и что редактировал ? === 26 | 27 | Некоторые системы контроля версий заставляют вас отметить файл до редактирования. Хотя это особенно раздражает, когда речь идет о работе с центральным сервером, этот способ имеет два преимущества: 28 | 29 | 1. Diff'ы быстры, потому что только отмеченные файлы должны быть изучены. 30 | 31 | 2. Можно обнаружить, кто еще работает с этим файлом, спросив центральный сервер, кто отметил его для редактирования. 32 | 33 | При наличии соответствующих сценариев, вы можете добиться того же с Git. Это требует сотрудничества со стороны других программистов, которые должны выполнять сценарии при редактировании файла. 34 | 35 | === История файлов === 36 | 37 | Поскольку Git записывает изменения всего проекта, то чтобы восстановить историю одного файла требуется больше работы, чем в системах управления версиями, которые позволяют отслеживать отдельные файлы. 38 | 39 | Потери, как правило, небольшие, а также стоит иметь в виду, что другие операции являются невероятно эффективными. Например, `git checkout` быстрее, чем `cp -a`, и вся дельта проекта сжимаются лучше, чем коллекций на основе дельт файлов. 40 | 41 | === Начальное Клонирование === 42 | 43 | Создание клона репозитория дороже обычного чекаута в другие системы управления версиями, особенно когда существует большая история. 44 | 45 | Первоначальная цена окупается в долгосрочной перспективе, так как большинство операций, затем будут происходить быстро и в автономном режиме. Однако в некоторых ситуациях может быть предпочтительным создание мелких клонов с опцией `--depth`. Это намного быстрее, но в результате снижается функциональность клона. 46 | 47 | === Изменчивые Проекты === 48 | 49 | Git был написан, чтобы быть быстрым по отношению к небольшим изменениям. Люди делают небольшие исправления от версии к версии. Однострочные исправление здесь, новые функции там, исправленные комментарии, и так далее. Но если ваши файлы, радикально отличаются в следующей ревизии, то на каждой фиксации ваша история обязательно увеличивается на размер всего вашего проекта. 50 | 51 | Не существует системы управления версиями, которая может решить эту проблему, но пользователи Git пострадают больше, поскольку клонируется вся история. 52 | 53 | Причины, почему эти изменения бывают настолько велики, должны быть изучены. Возможно, формат файла должен быть изменен. Малые изменения должны быть причиной малых изменений в самих файлах. 54 | 55 | Или, возможно, то, что вам было нужно, это базы данных или система резервного копирования или архивы, а не система контроля версий. Например, контроль версий может быть плохо приспособлен для управления фотографиями периодически получаемых с веб-камеры. 56 | 57 | Если файлы действительно должны постоянно изменяться, и они действительно должно быть версионироваться, возможно использовать Git централизованным образом. Можно создать мелкие клоны, с небольшой или без истории проекта. Конечно, многие инструменты Git будут недоступны, и исправления должны быть представлены в виде патчей. Вероятно, это штраф, потому как неясно, почему кто-то хочет вести историю дико неустойчиво файлов. 58 | 59 | Другим примером является проект, зависимый от прошивки, которая принимает форму огромного бинарного файла. История этой микропрограммы неинтересна для пользователей, и обновления сжимаются плохо, так версии микропрограммы могут излишне увеличить размера хранилища. 60 | 61 | В этом случае исходный код должен храниться в хранилище Git, а бинарные файлы - отдельно. Чтобы сделать жизнь проще, можно было бы распространять скрипт, который используется Git чтобы клонировать код и Rsync или мелкий клон Git для прошивки. 62 | 63 | === Глобальный счетчик === 64 | 65 | Некоторые централизованные системы контроля версий, используют положительные числа, которые возрастают, когда происходит новый коммит. Git идентифицирует изменения их хэшем, который лучше во многих обстоятельствах. 66 | 67 | Но некоторым люди нравится эти целые вокруг. К счастью, легко написать сценарии, чтобы при каждом обновлении центральный репозиторий Git увеличивал целое число, возможно, в теге, и связывает его с хэшем последним коммитом. 68 | 69 | Каждый клон может поддерживать такой счетчик, но это, вероятно, будет бесполезным, поскольку только центральный репозиторий имеет значение для всех. 70 | 71 | === Пустые подкаталоги === 72 | 73 | Пустые подкаталоги не могут быть отслежены. Создайте пустой файл, чтобы обойти эту проблему. 74 | 75 | В этом виноват не дизайн Git, а его текущая реализация. Если повезет и пользователи Git уделят больше внимания этой функции, возможно она будет реализована. 76 | 77 | === Первоначальный коммит === 78 | 79 | Обычный ученый в области информатики считает от 0, а не от 1. К сожалению, Git с его коммитами не присоединяется к этой конвенции. Многие команды плохо работают до первого коммита. Кроме того, некоторые частные случаи должны быть обработаны специально, такие, как rebase веток с различными начальными коммитами. 80 | 81 | Git'у желательно определение нулевого совершения: как только будет построено хранилище, HEAD будет установлен в строку, состоящую из 20 нулевых байтов. Этот специальный коммит представляет собой пустое дерево, без родителей, предшествовавшее всему в Git репозитории. 82 | 83 | Затем запустить *git log*, например, будет показывать пользователю, что коммиты еще не были сделаны вместо выхода с фатальной ошибкой. Аналогично для других инструментов. 84 | 85 | Каждая первоначальная фиксация - неявный потомок этого нулевого коммита. Например, несвязанный с какой-либо веткой rebase в целом будет привита на эту цель. В настоящее время применяются все, кроме первоначального коммита, в результате чего получается конфликт слияния. Один из способов заключается в использовании `git checkout` после `git commit -C` первоначального коммита, тогда rebase пройдет нормально. 86 | 87 | К сожалению, в худшем случае, если несколько ветвей с различными начальными коммитами сливаются, то rebase результата требует значительного ручного вмешательства. 88 | -------------------------------------------------------------------------------- /ru/grandmaster.txt: -------------------------------------------------------------------------------- 1 | == Гроссмейстерство Git == 2 | 3 | Эта претенциозно названная глава является собранием приемов работы с Git, которые я не смог отнести к другим главам. 4 | 5 | === Релизы исходников === 6 | 7 | В моих проектах Git управляет только теми файлами, которые я собираюсь архивировать и пускать в релиз. 8 | Чтобы создать тарбол с исходниками, я выполняю: 9 | 10 | $ git archive --format=tar --prefix=proj-1.2.3/ HEAD 11 | 12 | === Сохранение изменений === 13 | 14 | Вручную сообщать Git о том, что вы добавили, удалили или переименовали файлы, может стать непростой задачей 15 | в некоторых проектах. Вместо этого вы можете выполнить команды: 16 | 17 | $ git add . 18 | $ git add -u 19 | 20 | Git просмотрит файлы в текущем каталоге и обработает изменения сам. Вместо второй команды add, выполните *git commit -a*, если вы хотите также сделать коммит с изменениями. В *git help ignore* можно посмотреть, как указать, какие файлы должны игнорироваться. 21 | 22 | Вы можете выполнить все это в один прием: 23 | 24 | $ git ls-files -d -m -o -z | xargs -0 git update-index --add --remove 25 | 26 | Опции *-z* и *-0* предотвращают побочные эффекты от файловых имен, содержащих специальные символы. Поскольку эта команда добавляет игнорируемые файлы, вы можете использовать опции `-x` или `-X`. 27 | 28 | === Слишком большой коммит === 29 | 30 | Вы пренебрегали коммитами слишком долго? Яростно писали код и вспомнили о контроле исходников только сейчас? Внесли ряд несвязанных изменений, потому что это ваш стиль? 31 | 32 | Никаких проблем. Выполните: 33 | 34 | $ git add -p 35 | 36 | Для каждого внесенного изменения Git покажет измененный участок кода и спросит, должно ли это изменение пройти в следующем коммите. Отвечаем "y" или "n". Если вы хотите сделать что-то другое, например отложить выбор, введите "?" чтобы получить дополнительную информацию. 37 | 38 | Как только все будет готово, выполните: 39 | 40 | $ git commit 41 | 42 | для коммита именно тех изменений, которые вы выбрали ('staged' изменения). Убедитесь, что вы не указали опцию *-a*, в противном случае Git добавит в коммит все изменения. 43 | 44 | Что делать, если вы изменили множество файлов во многих местах? Просмотр каждого отдельного изменения - удручающая задача. В этом случае используйте *git add -i*, чей интерфейс менее прост, но более гибок. При помощи нескольких нажатий кнопок можно добавить на этап или убрать с этапа несколько файлов одновременно, либо просмотреть и выделить изменения в отдельных файлах. Как вариант, запустите *git commit \--interactive*, который автоматически сделает коммит после того, как вы закончите. 45 | 46 | ==== Этапные изменения ==== 47 | 48 | До сих пор мы избегали такой известной части Git, как 'index', но теперь мы должны разобраться с ней, чтобы пояснить вышесказанное. Индекс представляет собой временную область. Git редко перемещает данные непосредственно между вашим проектом и его историей. Вместо этого, Git сначала записывает данные в индекс, а уж затем копирует данные из индекса по месту назначения. 49 | 50 | Например, *commit -a* это на самом деле двухэтапный процесс. Сначала снапшот текущего состояния отслеживаемых файлов помещается в индекс. Затем снапшот, находящийся в индексе, записывается в историю. Коммит без опции *-a* выполняет только второй этап, и имеет смысл только после выполнения команд, которые изменяют индекс, например *git add*. 51 | 52 | Обычно мы можем не обращать внимания на индекс и считать, что взаимодействуем с историей напрямую. Но в такого рода сложных случаях нам нужен усиленный контроль над тем, что записывается в историю, и мы вынуждены работать с индексом. Мы помещаем снапшот только части наших изменений в индекс, а потом записываем этот аккуратно сформированный снапшот. 53 | 54 | === Не теряй HEAD === 55 | 56 | Тег HEAD - как курсор. В нормальном состоянии он указывает на последний коммит, продвигаясь вместе с каждым новым коммитом. Есть команды Git, которые позволяют перемещать этот тег. Например: 57 | 58 | $ git reset HEAD~3 59 | 60 | переместит HEAD на три коммита назад. Теперь все команды Git будут работать так, как будто вы не делали последних трех коммитов, хотя файлы останутся в текущем состоянии. В справке описаны некоторые методы использования этого эффекта. 61 | 62 | Но как вернуться назад в будущее? Ведь предыдущие коммиты о нем ничего не знают. 63 | 64 | Если у вас есть SHA1 оригинального HEAD, то: 65 | 66 | $ git reset SHA1 67 | 68 | Но предположим, что вы никогда его не записывали. Тут тоже беспокоиться не стоит. Для команд такого рода Git сохраняет оригинальный HEAD как тег под названием ORIG_HEAD, и вы можете вернуться безопасно и без проблем: 69 | 70 | $ git reset ORIG_HEAD 71 | 72 | === Охота за HEAD'ами === 73 | 74 | Предположим ORIG_HEAD недостаточно. Предположим, что вы только что осознали, что допустили громадную ошибку, и вам нужно вернуться в очень старый коммит давно забытой ветки. 75 | 76 | По умолчанию Git хранит коммиты по крайней мере в течении двух недель, даже если вы сказали ему уничтожить ветку с ними. Проблема в нахождении подходящего хеша. 77 | 78 | Вы можете просмотреть хеши в `.git/objects` и методом проб и ошибок найти нужный. Но есть путь значительно легче. 79 | 80 | Git записывает все хеши коммитов в `.git/logs`. В папке `refs` содержится история активности на всех ветках, а файл `HEAD` содержит каждое значение хеша, которое когда-либо принимал HEAD. Второе можно использовать чтобы найти хеши коммитов на случайно обрубленных ветках. 81 | 82 | Команда reflog предоставляет удобный интерфейс работы с этими логами. Используйте: 83 | 84 | $ git reflog 85 | 86 | Вместо копипейста хешей из reflog, попробуйте: 87 | 88 | $ git checkout "@{10 minutes ago}" 89 | 90 | Или сделайте чекаут пятого из последних посещенных коммитов с помощью: 91 | 92 | $ git checkout "@{5}" 93 | 94 | Смотрите секцию "Specifying Revisions" *git help rev-parse*, если вам нужна дополнительная информация. 95 | Вам может потребоваться установить более долгий период сохранения удаляемых коммитов. 96 | 97 | Например, выполнение: 98 | 99 | $ git config gc.pruneexpire "30 days" 100 | 101 | означает, что в удаленные коммиты будут окончательно потеряны только после того, как пройдут 30 дней с момента удаления, и будет запущена *git gc*. 102 | 103 | Также вам может потребоваться отключить автоматическое выполнение *git gc*: 104 | 105 | $ git config gc.auto 0 106 | 107 | После этого коммиты будут удаляться только когда вы будете запускать *git gc* самостоятельно. 108 | 109 | === Git как основа === 110 | 111 | Дизайн Git'a, разработанный в UNIX стиле, позволяет использовать Git как низкоуровневый компонент других программ: GUI, веб-интерфейсов, альтернативных командных строк, инструментов управления патчами, импортирования, преобразования, и т.д. На самом деле, многие команды Git - сами по себе скрипты, стоящие на плечах гигантов. 112 | Немного поигравшись с Git, вы можете заставить его удовлетворять многие ваши потребности. 113 | 114 | Простейший трюк - использование алиасов Git для выполнения часто 115 | 116 | используемых команд: 117 | 118 | $ git config --global alias.co checkout 119 | $ git config --global --get-regexp alias # отображает текущие алиасы 120 | alias.co checkout 121 | $ git co foo # то-же, что 'git checkout foo' 122 | 123 | Также можно выводить текущую ветку в командную строку или название окна терминала. 124 | 125 | Запуск 126 | 127 | $ git symbolic-ref HEAD 128 | 129 | выводит название текущей ветки. Для практического использования вы 130 | скорее всего захотите убрать "refs/heads/" и сообщения об ошибках: 131 | 132 | $ git symbolic-ref HEAD 2> /dev/null | cut -b 12- 133 | 134 | Папка `contrib` это целая сокровищница инструментов, построенных на Git. 135 | Со временем некоторые из них могут становиться официальными командами. Под Debian и Ubuntu эта папка находится в `/usr/share/doc/git-core/contrib`. 136 | 137 | `workdir/git-new-workdir` - один из популярных и часто используемых инструментов. С помощью хитрых симлинков этот скрипт создает новую рабочую папку, которая будет иметь общую историю с оригинальным репозиторием: 138 | 139 | $ git-new-workdir an/existing/repo new/directory 140 | 141 | Можно думать о новой папке и о файлах в ней, как о клоне, за исключением того, что так как история общая, 142 | два дерева автоматически синхронизируются. Нет необходимости в *merge*, *push* и *pull*. 143 | 144 | === Опасные трюки === 145 | 146 | Случайно уничтожить данные очень сложно с сегодняшними версиями Git. 147 | Но если вы знаете, что делаете, вы можете обойти защиту для общих команд. 148 | 149 | *Checkout*: Незакоммиченные изменения не дают сделать чекаут. Чтобы все-таки сделать чекаут нужного коммита, уничтожив свои изменения, используется флаг *-f*: 150 | 151 | $ git checkout -f COMMIT 152 | 153 | С другой стороны, если вы укажете отдельный путь для чекаута, то проверки на безопасность произведены не будут, и по указанные путям все будет переписываться без каких-либо сообщений. Будьте осторожны, если вы используете чекаут таким образом. 154 | 155 | *Reset*: Ресет также нельзя провести, если есть незакоммиченные изменения. Чтобы обойти это, запустите: 156 | 157 | $ git reset --hard [COMMIT] 158 | 159 | *Branch*: Удаление ветки не проходит, если приводит к потере изменений. Для принудительного удаления используйте: 160 | 161 | $ git branch -D BRANCH # вместо -d 162 | 163 | Аналогично, попытка перезаписи ветки путем перемещения не пройдет, если какие-то данные будут потеряны. Чтобы принудительно переместить ветку, введите: 164 | 165 | $ git branch -M [SOURCE] TARGET #вместо -m 166 | 167 | В отличии от чекаута и ресета, эти две команды задерживают удаление данных. Изменения остаются в папке .git и могут быть восстановлены с помощью нужного хеша из `.git/logs`(смотрите параграф "Охота за HEAD'ами" выше). 168 | 169 | По умолчанию они будут храниться по крайней мере две недели. 170 | 171 | *Clean*: Некоторые команды не будут выполняться, если они могут повредить неотслеживаемые файлы. Если вы уверены, что все неотслеживаемые файлы и папки вам не нужны, то безжалостно удаляйте их командой: 172 | 173 | $ git clean -f -d 174 | 175 | В следующий раз эта надоедливая команда выполнится! 176 | 177 | === Улучшаем свой публичный образ === 178 | 179 | История многих моих проектов полна глупых ошибок. Самое ужасное это кучи недостающих файлов, которые появляются, когда забываешь выполнить *git add*. К счастью, я пока не терял важных файлов из-за того, что пропускал их, потому что я редко удаляю оригинальные рабочие папки. Обычно я замечаю ошибку несколько коммитов спустя, так что единственный вред это отсутствующая история и осознание своей вины. 180 | 181 | Также я регулярно совершаю(и коммичу) меньшее зло - завершающие пробелы. Несмотря на безвредность, я не хотел бы, чтобы это появлялось в публичных записях. 182 | 183 | И наконец, я беспокоюсь о неразрешенных конфликтах, хотя пока они не приносили вреда. Обычно я замечаю их во время билда, но в некоторых случаях могу проглядеть. 184 | Если бы я только поставил защиту от дурака, используя хук, который бы предупреждал меня об этих проблемах... 185 | 186 | $ cd .git/hooks 187 | $ cp pre-commit.sample pre-commit # В старых версиях Git: chmod +x pre-commit 188 | 189 | Теперь Git отменяет коммит, если обнаружены ненужные пробелы или неразрешенные конфликты. 190 | Для этого руководства я в конце концов добавил следующее в начало *pre-commit* хука, чтобы защититься от своей рассеянности: 191 | 192 | if git ls-files -o | grep '\.txt$'; then 193 | echo FAIL! Неотслеживаемые .txt файлы. 194 | exit 1 195 | fi 196 | 197 | Несколько операций Git поддерживают хуки, смотрите *git help hooks*. Вы можете добавить хуки, которые будут сообщать о грамматических ошибках в комментариях к коммиту, добавлять новые файлы, делать отступы перед параграфами, добавлять записи на веб-страничку, проигрывать звуки, в общем, делать что угодно... 198 | 199 | Мы встречались с *post-update* хуком раньше, когда обсуждали Git через http. Этот хук обновлял несколько файлов, которые необходимы для ненативных видов коммуникации с Git. 200 | -------------------------------------------------------------------------------- /ru/history.txt: -------------------------------------------------------------------------------- 1 | == Уроки истории == 2 | 3 | Вследствие распределенной природы Git, историю изменений можно легко редактировать. Однако, если вы вмешиваетесь в прошлое, будьте осторожны: изменяйте только ту часть истории, которой владеете вы и только вы. И также как государства бесконечно выясняют, кто же именно совершил и какие бесчинства, так и у вас будут проблемы с примирением после взаимодействия деревьев истории. 4 | 5 | Конечно, если вы также контролируете и все остальные деревья, то нет никаких проблем поскольку вы можете переписать их. 6 | 7 | Некоторые разработчики убеждены, что история должна быть неизменна со всеми огрехами и прочим. 8 | Другие считают, что деревья должны быть презентабельными, до того как они выпустят их в публичный доступ. 9 | Git учитывает оба мнения. Также как клонирование, ветвление и слияние, переписывание истории - это просто еще одна возможность, которую дает вам Git. Разумное ее использование зависит только от вас. 10 | 11 | === Оставаясь корректным === 12 | 13 | Только что сделали коммит и уже хотите изменить запись в журнале? Запустите: 14 | 15 | $ git commit --amend 16 | 17 | чтобы изменить последнее сообщение коммита. Осознали, что забыли добавить файл? Запустите *git add*, чтобы это сделать и выполните вышеуказанную команду. 18 | 19 | Захотелось добавить еще немного изменений в последний коммит? Так сделайте их и запустите: 20 | 21 | $ git commit --amend -a 22 | 23 | === ...И кое-что еще === 24 | 25 | Давайте представим себе, что предыдущая проблема на самом деле в десять раз хуже. После длительной работы вы сделали ряд фиксаций, но вы не очень-то довольны тем, как они организованы и кое-какие записи в журнале (commit messages) надо бы слегка переформулировать. В этом случае запустите: 26 | 27 | $ git rebase -i HEAD~10 28 | 29 | и записи в журнале от последних 10-ти фиксаций появятся в вашем любимом редаторе (задается переменной окружения $EDITOR). Вот кусок примера: 30 | 31 | pick 5c6eb73 Добавил ссылку repo.or.cz 32 | pick a311a64 Сменил порядок в "Работай как хочешь" 33 | pick 100834f Добавил цель для push в Makefile 34 | 35 | После чего: 36 | 37 | - Убираем коммиты, удаляя строки. 38 | - Меняем порядок коммитов, меняя порядок строк. 39 | - Заменяем "pick" на "edit", если требуется внести изменения в коммиты. 40 | - Заменяем "pick" на "squash" для слияния коммита с предыдущим. 41 | 42 | Если вы отметили коммит для исправлений, запустите: 43 | 44 | $ git commit --amend 45 | 46 | Если нет, запустите: 47 | 48 | $ git rebase --continue 49 | 50 | В общем, делайте коммиты как можно раньше и как можно чаще - всегда потом сможете за собой подчистить при помощи rebase. 51 | 52 | === Локальные изменения сохраняются === 53 | 54 | Предположим, вы работаете над активным проектом. За какое-то время были проведены несколько коммитов, после чего синхронизируетесь с официальным деревом через слияние. Цикл повторяется несколько раз до тех пор, пока вы не готовы отправить (push) изменения в центральное дерево. 55 | 56 | Однако теперь история изменений в локальном клоне Git представляет собой кашу из ваших и официальных изменений. Вам бы хотелось видеть все изменения непрерывной секцией даже после слияния с официальными. 57 | 58 | Это работа для команды *git rebase* в виде, описанном выше. Зачастую, имеет смысл использовать флаг *--onto*, чтобы не использовать интерактивный режим. 59 | 60 | Также стоит взглянуть на вывод команды *git help rebase* для получения подробных примеров использования этой замечательной команды. Вы можете объединять фиксации, вы можете даже перестраивать ветки. 61 | 62 | === Переписывая историю === 63 | 64 | Время от времени вам может понадобиться эквивалент "замазывания" людей на официальных фотографиях, только для систем контроля версий, как бы стирая их из истории в духе сталинизма. Например, предположим, что мы уже собираемся выпустить релиз проекта, но он содержит файл, который не должен стать достоянием общественности по каким-то причинам. Может я сохранил номер своей кредитки в текстовый файл и случайно добавил этот файл к файлам проекта? Просто стирать файл бесполезно - из-за контроля версий всегда можно вытащить такую из старых версий, где этот документ еще есть. Нам надо удалить файл из всех версий когда-либо существовавших. Для этого: 65 | 66 | $ git filter-branch --tree-filter 'rm top/secret/file' HEAD 67 | 68 | Стоит посмотреть вывод команды *git help filter-branch*, где обсуждается этот пример и даже предлагается более быстрый метод решения. Короче говоря, *filter-branch* позволяет изменять существенные части истории при помощи одной-единственной команды. 69 | 70 | В результате директория +.git/refs/original+ будет описывать состояние дел до выполнения операции. Убедитесь, что команда filter-branch проделала все, что вы хотели, и, если хотите опять использовать команду, удалите эту директорию. 71 | 72 | И, наконец, замените клоны вашего проекта обновленной версией, если собираетесь в дальнейшем с ними иметь дело. 73 | 74 | === Создавая Историю === 75 | 76 | [[makinghistory]] 77 | Хотите перевести проект под управление Git? Если сейчас он находится под управлением какой-либо из хорошо известных систем контроля версий, то весьма велики шансы на то, что кто-нибудь уже позаботился и написал необходимые скрипты для экспорта всей истории проекта в Git. 78 | 79 | А если все-таки нет? Тогда смотрите в сторону команды *git fast-import*, которая считывает текстовый ввод в специальном формате для создания истории Git "с нуля". 80 | 81 | Обычно скрипт, использующий эту команду - это наспех состряпанное нечто, 82 | предназначенное для однократного использования, чтоб "перетащить" проект за один раз. 83 | 84 | В качестве примера, вставьте следующий листинг в какой-нибудь файл, типа '/tmp/history': 85 | 86 | ---------------------------------- 87 | commit refs/heads/master 88 | committer Alice <alice@example.com> Thu, 01 Jan 1970 00:00:00 +0000 89 | data <<EOT 90 | Стартовый коммит. 91 | EOT 92 | 93 | M 100644 inline hello.c 94 | data <<EOT 95 | #include <stdio.h> 96 | 97 | int main() { 98 | printf("Hello, world!\n"); 99 | return 0; 100 | } 101 | EOT 102 | 103 | commit refs/heads/master 104 | committer Bob <bob@example.com> Tue, 14 Mar 2000 01:59:26 -0800 105 | data <<EOT 106 | Заменен printf() на write() 107 | EOT 108 | 109 | M 100644 inline hello.c 110 | data <<EOT 111 | #include <unistd.h> 112 | 113 | int main() { 114 | write(1, "Hello, world!\n", 14); 115 | return 0; 116 | } 117 | EOT 118 | 119 | ---------------------------------- 120 | 121 | Затем создайте репозиторий Git из этого временного файла при помощи команд: 122 | 123 | $ mkdir project; cd project; git init 124 | $ git fast-import < /tmp/history 125 | 126 | Вы можете извлечь (checkout) последнюю версию проекта при помощи команды: 127 | 128 | $ git checkout master . 129 | 130 | Команда *git fast-export* преобразует любой репозиторий Git в формат, понимаемый командой *git fast-import*. То есть, ее выход может быть использован как образец для тех кто пишет скрипты-преобразователи и для того, чтобы переносить репозитории в формате, хоть как-то пригодном для чтения человеком. Естественно, при помощи этих команд можно пересылать репозитории текстовых файлов через каналы передачи текста. 131 | 132 | === Когда же все пошло не так? === 133 | 134 | Вы только что обнаружили, что кое-какой функционал вашей программы не работает, но вы совершенно отчетливо помните, что он работал всего несколько месяцев назад. Ну вот, блин! Откуда же взялась ошибка? Вы же это проверяли сразу как разработали. 135 | 136 | В любом случае, уже поздно сожалеть. Однако, если вам хватило ума фиксировать свои изменения часто, то Git сможет сильно помочь точно определить проблему. 137 | 138 | $ git bisect start 139 | $ git bisect bad SHA1_OF_BAD_VERSION 140 | $ git bisect good SHA1_OF_GOOD_VERSION 141 | 142 | Git извлечет состояние ровно посередине. Проверьте работает ли то, что сломалось, и если все еще нет, то введите: 143 | 144 | $ git bisect bad 145 | 146 | Если же работает, то замените "bad" на "good" в предыдущей команде. Git снова переместит вас в состояние посередине между "хорошей" и "плохой" ревизиями, при этом сузив круг подозреваемых ревизий вдвое. 147 | 148 | После нескольких итераций, этот бинарный поиск приведет вас к тому коммиту, на котором все и сломалось. После окончания выяснения, вернуть исходное состояние можно командой: 149 | 150 | $ git bisect reset 151 | 152 | Вместо того, чтоб вручную тестировать каждое изменение - автоматизируйте этот процесс при помощи команды: 153 | 154 | $ git bisect run COMMAND 155 | 156 | Git использует возвращаемое значение заданной команды, обычно "одноразового" скрипта, чтоб определить "хорошее" это было изменение или "плохое". Скрипт должен вернуть 0, если "хорошее", 125 если изменение надо пропустить и любое число от 1 до 127 если "плохое". Отрицательное возвращаемое значение прерывает бинарный поиск. 157 | 158 | На самом деле возможностей еще больше! На странице помощи объясняется как визуализировать бинарный поиск, проанализировать или даже воспроизвести журнал поиска, исключить изменения в которых точно все в порядке для ускорения поиска. 159 | 160 | === Из-за кого все пошло наперекосяк? === 161 | 162 | Как и многие другие системы конроля версий, Git поддерживает команду blame: 163 | 164 | $ git blame FILE 165 | 166 | которая показывает кто и когда изменил каждую строку выбранного файла. В отличие же от многих других систем контроля версий эта операция происходит оффлайн, то есть данные берутся с локального диска. 167 | 168 | === Личный опыт === 169 | 170 | В централизованных системах контроля версий, изменения истории - достаточно сложная операция и для ее проведения необходимо привлечение администраторов. Процедуры клонирования, ветвления и слияния невозможно осуществить без сетевого соединения. Также обстоят дела и с такими базовыми операциями как просмотр журнала изменений или фиксация изменений. В некоторых системах сетевое соединение требуется даже для просмотра собственных изменений или открытия файла для редактирования. 171 | 172 | Централизованные системы исключают возможность работать оффлайн и требуют более дорогой сетевой инфраструктуры, особенно с увеличением количества разработчиков. Еще более важно, из-за того все операции происходят медленнее, пользователи избегают пользоваться "продвинутыми" командами до тех пор пока не "припечет как следует". В особо "запущенных" случаях это касается и большинства базовых команд тоже. Продуктивность страдает из-за остановок в работе, когда пользователи вынуждены запускать "долгоиграющие" команды. 173 | 174 | Я испытал этот феномен на себе. Git был моей первой системой контроля версий. Я быстро привык нему и стал относится к его возможностям как к должному. Я предположил, что и другие системы похожи на него: выбор системы контроля версий не должен отличаться от выбора текстового редактора или браузера. 175 | 176 | Когда, немного позже, я был вынужден использовать централизованную систему контроля версий, я был шокирован. При использовании Git, мое, зачастую капризное, интернет-соединение не имело большого значения, но теперь разработка стала невыносимой когда от него потребовалась надежность как у жесткого диска. Плюс к этому, я обнаружил, что стал избегать использовать некоторые команды из-за получающихся в результате их выполнения задержек, а без них оказалось невозможным следовать моему стилю разработки. 177 | 178 | Когда мне было нужно запустить "медленную" команду, нарушение хода цепочки моих мыслей оказывало несоизмеримый ущерб разработке. Ожидая окончания связи с сервером, я должен был заниматься чем-то другим, чтоб скоротать время, например, чтением почты или написанием документации. Через некоторое время я возвращался к первоначальной задаче, но приходилось тратить уйму времени, чтоб вспомнить на чем же я остановился и что хотел делать дальше. Все-таки люди не очень приспособлены для многозадачности. 179 | 180 | Есть еще один интересный эффект, так называемая, трагедия общин: предвидя будущую загрузку сети, некоторые люди начинают использовать более "широкие" каналы чем им реально требуются для текущих операций в попытке предотвратить будущие задержки. Суммарная активность увеличивает загрузку сети, поощряя людей задействовать еще более высокоскоростные каналы в следующий раз, чтоб избежать еще больших задержек. 181 | -------------------------------------------------------------------------------- /ru/intro.txt: -------------------------------------------------------------------------------- 1 | == Введение == 2 | 3 | Я буду использовать аналогии, чтобы объяснить, что такое контроль версий. Если вам нужно более точное объяснение, обратитесь к http://en.wikipedia.org/wiki/Revision_control[статье википедии]. 4 | 5 | === Работа - это игра === 6 | 7 | Я играл в компьютерные игры почти всю свою жизнь. А вот использовать системы контроля версий я начал уже будучи взрослым. Подозреваю, что я не один такой, и сравнение этих двух занятий может помочь объяснению и пониманию их концепций. 8 | 9 | Представьте, что редактирование кода, документа или чего-либо еще — игра. Далеко продвинувшись, вы захотите сохраниться. Чтобы сделать это, вы нажмете на кнопку "Сохранить" в вашем любимом редакторе. 10 | 11 | Но это перезапишет старую версию. Это как в древних играх, где был только один слот для сохранения: вы можете сохраниться, но вы никогда не сможете вернуться к прежнему состоянию. Что досадно, так как одно из прежних сохранений может указывать на одно из очень интересных мест в игре, и, может быть, однажды вы захотите вернуться к нему. Или, что еще хуже, вы сейчас находитесь в безвыигрышном состоянии и вынуждены начинать заново. 12 | 13 | === Контроль версий === 14 | 15 | Во время редактирования вы можете "Сохранить как ..." в другой файл, или скопировать файл куда-нибудь перед сохранением, чтобы уберечь более старые версии. Может быть и заархивировав их для сохранения места на диске. Это самый примитивный вид контроля версий, к тому же требующий интенсивной ручной работы. Компьютерные игры прошли этот этап давным-давно, в большинстве из них есть множество слотов для сохранения с автоматическими временными метками. 16 | 17 | Давайте усложним условия. Пусть у вас есть несколько файлов, используемых вместе, например, исходный код проекта или файлы для вебсайта. Теперь, чтобы сохранить старую версию, вы должны скопировать весь каталог. Поддерживать множество таких версий вручную неудобно, и быстро становится дорогим удовольствием. 18 | 19 | В некоторых играх сохранение — это и есть каталог с кучей файлов внутри. Эти игры скрывают детали от игрока и предоставляют удобный интерфейс для управления различными версиям этого каталога. 20 | 21 | В системах контроля версий всё точно так же. У них у всех есть приятный интерфейс для управления каталогом, полным-полно всяких данных. Вы можете сохранять состояние каталога так часто, как пожелаете, и вы можете восстановить любую из предыдущих сохраненных версий. Но, в отличие от компьютерных игр, они умнее используют дисковое пространство. Обычно только несколько файлов меняется от версии к версии, не более. Сохранение различий, а не всей копии каталога, не так сильно расходует свободное место. 22 | 23 | === Распределенный контроль === 24 | 25 | А теперь представьте очень сложную компьютерную игру. Её настолько сложно пройти, что множество опытных игроков по всему миру решили объединиться и использовать общие сохранения, чтобы попытаться выиграть. Прохождения на скорость — живой пример. Игроки, специализирующиеся на разных уровнях игры, объединяются, чтобы в итоге получить потрясающий результат. 26 | 27 | Как бы вы организовали такую систему, чтобы игроки смогли легко забирать сохранения других? А загружать свои? 28 | 29 | Раньше каждый проект использовал централизованную систему контроля версий. Какой-нибудь сервер хранил все сохраненные игры. И никто больше. На машине каждого игрока хранилась только очень маленькая часть. Когда игрок хотел пройти немного дальше, он выкачивал самое последнее сохранение с сервера, играл немного, сохранялся и закачивал уже свое сохранение обратно на сервер, чтобы кто-нибудь другой смог его использовать. 30 | 31 | А что, если игрок по какой-то причине захотел использовать более старую сохраненную игру? Возможно, текущая версия сохраненной игры безвыигрышна, потому что кто-то из игроков забыл взять какой-либо игровой предмет на каком-то предыдущем уровне, и они хотят найти последнюю сохраненную игру, которая все еще выигрышна. Или, может быть, они хотят сравнить две более старые сохраненные игры, чтобы установить вклад каждого игрока. 32 | 33 | Может быть много причин вернуться к более старой версии, но выход один. Они должны запросить центральный сервер о той старой сохраненной игре. Чем больше сохраненных игр они захотят, тем больше им понадобится связываться с сервером. 34 | 35 | Новое поколение систем контроля версий, к которым относится Git, известны как распределенные системы, их можно понимать как обобщение централизованных систем. Когда игроки загружаются с главного сервера, они получают каждую сохраненную игру, а не только последнюю. Это как если они зеркалируют центральный сервер. 36 | 37 | Эти первоначальные операции клонирования могут быть интенсивными, особенно если присутствует длинная история разработки, но это сполна окупается при длительной работе. Одна немедленная выгода состоит в том, что если по какой-то причине потребуется более старая версия, дополнительное обращение к серверу не понадобится. 38 | 39 | ==== Глупые предрассудки ==== 40 | 41 | Широко распространенное заблуждение состоит в том, что распределенные системы непригодны для проектов, требующих официального централизованного репозитория. Ничто не может быть более далеким от истины. Получение фотоснимка не приводит к тому, что мы крадем чью-то душу. Проще говоря, клонирование главного репозитория не уменьшает его важность. 42 | 43 | В первом приближении можно сказать, что все, что делает централизованная система контроля версий, хорошо сконструированная распределенная система может сделать лучше. Сетевые ресурсы просто дороже локальных. Хотя дальше мы увидим, что в распределенном подходе есть свои недостатки, менее вероятно провести ложные аналогии руководствуясь этим приближенным правилом. 44 | 45 | Небольшому проекту может понадобиться лишь часть функций, предлагаемых такой системой. Но будете ли вы использовать римские цифры в расчетах с небольшими числами? Более того, ваш проект может вырасти за пределы ваших первоначальных ожиданий. Использовать Git с самого начала — это как держать наготове швейцарский армейский нож, даже если вы только открываете им бутылки. Однажды вам безумно понадобится отвертка и вы будете рады, что под рукой у вас нечто большее, чем простая открывалка. 46 | 47 | === Конфликты при слиянии === 48 | 49 | Для этой темы аналогия с компьютерной игрой становится слишком натянутой. Вместо этого, давайте вернемся к редактированию документа. 50 | 51 | Итак, допустим, что Алиса вставила строчку в начале файла, а Боб — в конец. Оба они закачивают свои изменения. Большинство систем автоматически сделает разумный вывод: принять и объединить их изменения так, чтобы обе правки — и Алисы, и Боба — были применены. 52 | 53 | Теперь предположим, что и Алиса, и Боб независимо друг от друга сделали изменения в одной и той же строке. Тогда становится невозможным разрешить конфликт без человеческого вмешательства. Тот, кто вторым из них закачает на сервер изменения, будет информирован о конфликте слияния, и должен либо выбрать, чье изменение перекроет другое, либо заново отредактировать строку целиком. 54 | 55 | Могут случаться и более сложные ситуации. Системы контроля версий разрешают простые ситуации сами, и оставляют сложные для человека. Обычно такое их поведение поддается настройке. 56 | -------------------------------------------------------------------------------- /ru/multiplayer.txt: -------------------------------------------------------------------------------- 1 | == Групповая работа в Git == 2 | 3 | Сначала я использовал Git для личного проекта, в котором был единственным разработчиком. 4 | Среди команд, связанных с распределенными свойствами Git, мне требовались только *pull* и *clone*, чтобы хранить один и тот же проект в разных местах. 5 | 6 | Позднее я захотел опубликовать свой код при помощи Git и включить изменения помощников. Мне пришлось научиться управлять проектами, которые разрабатываются множеством людей со всего мира. К счастью, это преимущество Git и, возможно, смысл ее существования. 7 | 8 | === Кто я? === 9 | 10 | Каждый коммит содержит имя автора и адрес электронной почты, которые отображаются по команде *git log*. 11 | По умолчанию Git использует системные настройки для заполнения этих полей. 12 | Чтобы установить их явно, введите: 13 | 14 | $ git config --global user.name "John Doe" 15 | $ git config --global user.email johndoe@example.com 16 | 17 | Чтобы установить эти параметры только для текущего репозитория, опустите флаг --global. 18 | 19 | === Git через SSH, HTTP === 20 | 21 | Предположим, у вас есть SSH доступ к веб-серверу, но Git не установлен. Git может связываться через HTTP, хотя это и менее эффективно, чем его собственный протокол. 22 | 23 | Скачайте, скомпилируйте, установите Git в вашем аккаунте; создайте репозиторий в директории, доступной через web: 24 | 25 | $ GIT_DIR=proj.git git init 26 | 27 | В директории "proj.git" запустите: 28 | 29 | $ git --bare update-server-info 30 | $ cp hooks/post-update.sample hooks/post-update 31 | 32 | Для старых версий Git команда копирования выдаст ошибку, и вы должны будете запустить: 33 | 34 | $ chmod a+x hooks/post-update 35 | 36 | Теперь вы можете публиковать свои последние правки через SSH из любой копии: 37 | 38 | $ git push web.server:/path/to/proj.git master 39 | 40 | и кто угодно сможет взять ваш проект через HTTP: 41 | 42 | $ git clone http://web.server/proj.git 43 | 44 | === Git через что угодно === 45 | 46 | Хотите синхронизировать репозитории без серверов или даже без сетевого подключения? 47 | Необходимо импровизировать в чрезвычайной ситуации? 48 | Мы рассмотрели, как <<makinghistory, *git fast-export* и *git fast-import* могут преобразовать 49 | репозитории в один файл и обратно >>. Мы можем обмениваться такими файлами между репозиториями 50 | git с помощью любых носителей, но более эффективным инструментом является *git bundle*. 51 | 52 | Отправитель создает пакет ('bundle'): 53 | 54 | $ git bundle create somefile HEAD 55 | 56 | Затем перенесите bundle, +somefile+, такими средствами, как: email, флешка, дискета, *xxd* печать и последующее распознавание символов, чтение битов по телефону, дымовые сигналы и т.д. Получатель восстанавливает коммиты из пакета, вводя: 57 | 58 | $ git pull somefile 59 | 60 | Получатель может сделать это даже с пустым хранилищем. Несмотря на свой размер, +somefile+ содержит весь исходный Git репозиторий. 61 | 62 | В больших проектах для уменьшения объема пакет содержит только изменения, которых нет в других репозиториях: 63 | 64 | $ git bundle create somefile HEAD ^COMMON_SHA1 65 | 66 | Если это делается часто, то можно легко забыть, какой коммит был отправлен последним. Справка 67 | предлагает для решения этой проблемы использовать метки. А именно, после передачи пакета введите: 68 | 69 | 70 | $ git tag -f lastbundle HEAD 71 | 72 | и создавайте пакеты обновления с помощью: 73 | 74 | $ git bundle create newbundle HEAD ^lastbundle 75 | 76 | === Патчи: Общее применения === 77 | 78 | Патчи представляют собой текст изменений, который может быть легко понят как человеком, так и компьютером. Это делает его очень привлекательным форматом обмена. Можно послать электронное письмо с патчем для разработчиков, независимо от того, какую систему контроля версий они используют. Пока ваши корреспонденты могут читать электронную почту, они могут увидеть ваши изменения. Аналогичным образом с Вашей стороны все, что Вам требуется, - это адрес электронной почты: нет необходимости в установке онлайн хранилища Git. 79 | 80 | Напомним, в первой главе: 81 | 82 | $ git diff COMMIT 83 | 84 | выводит патч, который может быть вставлен в сообщение электронной почты для обсуждения. В Git репозитории, введите: 85 | 86 | $ git apply < FILE 87 | 88 | чтобы применить патч. 89 | 90 | В более формальной обстановке, когда имя автора и подписи должны быть зарегистрированы, генерируйте соответствующие патчи с определенной точки, набрав: 91 | 92 | $ git format-patch START_COMMIT 93 | 94 | Полученные файлы могут быть отправлены с помощью *git-send-email* или вручную. Вы также можете указать диапазон коммитов: 95 | 96 | $ git format-patch START_COMMIT..END_COMMIT 97 | 98 | На принимающей стороне сохраните email в файл и введите: 99 | 100 | $ git am < FILE 101 | 102 | Это применит входящие исправления, а также создаст коммит, включающий такую информацию, как автор. 103 | 104 | С web-клиентом электронной почты вам, возможно, потребуется нажать кнопку, чтобы посмотреть электронную почту в своем первоначальном виде до сохранения исправлений в файл. 105 | 106 | Есть небольшие различия для Mbox-подобных клиентов электронной почты, но если вы используете один 107 | из них, то вы, вероятно, тот человек, который может легко настроить его без чтения руководства! 108 | 109 | === К сожалению, мы переехали === 110 | 111 | Из предыдущих главах, мы видели, что после клонирования репозитория, набор *git push* или *git pull* автоматически проталкивает или стягивает с оригинального URL. Каким образом Git это делает? Секрет кроется в параметрах конфигурации инициализированных при создании клона. Давайте выполним команду: 112 | 113 | $ git config --list 114 | 115 | Опция +remote.origin.url+ контролирует исходный URL; "origin" - имя исходного 116 | репозитория. Как и имя ветки "master" - это соглашение, мы можем 117 | изменить или удалить этот ник, но как правило, нет причин для этого. 118 | 119 | Если адрес оригинального репозитория изменился, можно обновить его с помощью команды: 120 | 121 | $ git config remote.origin.url NEW_URL 122 | 123 | Опция +branch.master.merge+ задает удаленную ветвь по умолчанию для 124 | *git pull*. В ходе первоначального клонирования, он установлен на текущую ветвь 125 | исходного репозитория, так что даже если HEAD исходного репозитария впоследствии 126 | переходит на другую ветку, pull будет продолжать выполняться для исходной ветви. 127 | 128 | Этот параметр применим только к хранилищу, которое мы впервые клонировали, в его настройках 129 | записана +branch.master.remote+. Если мы выполняем pull из других 130 | хранилищ, то мы должны указать необходиму нам ветку: 131 | 132 | $ git pull ANOTHER_URL master 133 | 134 | Это объясняет, почему некоторых из наших более ранних примеров push и pull 135 | не имели аргументов. 136 | 137 | === Удаленные Ветки === 138 | 139 | Когда вы клонируете репозиторий, вы также клонируете все его ветки. Вы можете не 140 | заметить это, потому что Git скрывает их: вы должны указать это явно. 141 | Это предотвращает пересечение веток в удаленном хранилище с вашими, а также делает 142 | Git проще для начинающих. 143 | 144 | Список удаленных веток можно посмотреть коммандой: 145 | 146 | $ git branch -r 147 | 148 | Вы должны увидеть что-то вроде: 149 | 150 | origin/HEAD 151 | origin/master 152 | origin/experimental 153 | 154 | Они представляют собой ветки и HEAD в удаленном хранилище, и могут быть использованы 155 | в обычных командах Git. Например, предположим, что вы сделали много коммитов, и 156 | хотели бы сравнить с последней загруженной версией. Вы можете найти через 157 | журналы для соответствующего SHA1 хэш, но это гораздо легче набрать: 158 | 159 | 160 | $ git diff origin/HEAD 161 | 162 | Также можно увидеть лог ветки "experimental" набрав: 163 | 164 | $ git log origin/experimental 165 | 166 | === Несколько Удаленных Веток === 167 | 168 | Предположим, что два других разработчиков работает над нашим проектом, и мы хотим 169 | следить за обоими. Мы можем наблюдать более чем за одним хранилище одновременно введя: 170 | 171 | $ git remote add other ANOTHER_URL 172 | $ git pull other some_branch 173 | 174 | Сейчас мы объединились в ветвь второго хранилища, и мы получили 175 | легкий доступ для всех ветвей во всех репозиториях: 176 | 177 | $ git diff origin/experimental^ other/some_branch~5 178 | 179 | Но что, если мы просто хотим сравнить их изменения, не затрагивающие нашу собственную 180 | работу? Иными словами, мы хотим, чтобы изучить их ветки без изменения нашей рабочей папки. 181 | В этом случае вместо pull наберите: 182 | 183 | $ git fetch # Fetch from origin, the default. 184 | $ git fetch other # Fetch from the second programmer. 185 | 186 | Это выбирает их историю, и ничего больше, так что, хотя рабочий каталог остается 187 | нетронутыми, мы можем обратиться в любую ветвь в любом хранилище командами Git. 188 | Кстати, за кулисами, pull просто fetch за которым следует *git merge*; 189 | а последний добавляется в рабочую директорию. 190 | Обычно мы используем pull, потому что мы хотим объединить после выполнения fetch; 191 | эта ситуация представляет собой заметное исключение. 192 | 193 | См. *git help remote* о том, как удалить удаленные хранилища, игнорировать определенные 194 | ветки и многое другое. 195 | 196 | === Мои Настройки === 197 | 198 | Для моих проектов я люблю использовать готовые Git репозитории, в которые я могу сделать pull. Некоторые Git хостинги позволяют создавать собственные ветки проекта нажатием одной кнопки. 199 | 200 | После того как я выгрузил дерево, я запускаю Git команды для навигации и изучения изменении, которые в идеале хорошо организованны и описаны. Я объединяю мои собственные неопубликованные изменения, и, возможно, делаю дальнейшие изменения. После изменения, я выгружаю изменения в официальный репозиторий. 201 | 202 | Хотя я редко получают взносы, я считаю, этот подход хорошо масштабируется. Смотрите http://torvalds-family.blogspot.com/2009/06/happiness-is-warm-scm.html[этот пост в блоге Линуса Торвальдса]. 203 | 204 | Пребывание в мире Git немного более удобно, чем патч-файлы, как это экономит мне шаги конвертации их в коммиты Git. Кроме того, Git автоматически обрабатывает информацию, такую как запись с именем автора и адресом электронной почты, а также время и дату, и просит автора описывать свои собственные изменения. 205 | -------------------------------------------------------------------------------- /ru/preface.txt: -------------------------------------------------------------------------------- 1 | = Магия Git = 2 | Ben Lynn 3 | Август 2007 4 | 5 | == Предисловие == 6 | 7 | http://git.or.cz/[Git] это Швейцарский армейский нож контроля версий. Надежный универсальный многоцелевой инструмент контроля версий, чья черезвычайная гибкость делает его сложным в изучении даже для многих профессионалов. 8 | 9 | Как говорил Артур Кларк - любая достаточно развитая технология неотличима от магии. Это отличный способ подхода Git: новички могут игнорировать принципы его внутренней работы и рассматривать Git как гизмо, который может поражать друзей и приводить в бешенство врагов своими чудесными способностями. 10 | 11 | Вместо того, чтобы вдаваться в подробности, мы предоставляем грубую инструкцию для конкретных действий. После частого использования вы постепенно поймете как работает каждый трюк и как адаптировать рецепты для ваших нужд. 12 | 13 | .Переводчики 14 | 15 | - http://docs.google.com/View?id=dfwthj68_675gz3bw8kj[ Китайский (упрощенный)]: JunJie, Meng и JiangWei. Хостинг - Google Docs. 16 | - link:/~blynn/gitmagic/intl/es/[Испанский]: Rodrigo Toledo. 17 | 18 | .Другие Издания 19 | 20 | - link:book.html[HTML одной страницей]: один HTML без CSS. 21 | - link:book.pdf[PDF файл]: для печати. 22 | - http://packages.debian.org/search?searchon=names&keywords=gitmagic[Пакет Debian]: получите локальную копию этого сайта. http://packages.ubuntu.com/jaunty/gitmagic[Пакет Ubuntu (Jaunty Jackalope)]. Также доступен http://csdcf.stanford.edu/status/[когда этот сервер недоступен для сопровождающих]. 23 | 24 | === Благодарности === 25 | 26 | Благодарю Dustin Sallings, Alberto Bertogli, James Cameron, Douglas Livingstone, Michael Budde, Richard Albury, Tarmigan, Derek Mahar и Frode Aannevik за внесенные предложения и улучшения. Спасибо Daniel Baumann за создание и сопровождение пакета для Debian. Также благодарен JunJie, Meng и JiangWei за перевод на китайский, и Rodrigo Toledo за перевод на испанский. [Если я забыл про вас, пожалуйста, сообщите мне, поскольку я часто забывают обновлять этот раздел.] 27 | 28 | Мои благодарности остальным за вашу поддержку и похвалу. Если бы это была реальная физическая книга, я смог бы разместить Ваши щедрые отзывы о ней на обложке, чтобы прорекламировать ее! Серьезно, я высоко ценю каждое ваше сообщение. Чтение их всегда поднимает мне настроение. 29 | 30 | .Бесплатные хостинги Git 31 | 32 | - http://repo.or.cz/[http://repo.or.cz/] хостинг свободных проектов. Первый сайт Git-хостинга. Основан и поддерживается одним из первых разработчиков Git. 33 | - http://gitorious.org/[http://gitorious.org/] другой сайт Git-хостинга, направленный на проекты с открытым кодом. 34 | - http://github.com/[http://github.com/] хостинг проектов с открытым кодом, и закрытых проектов на платной основе. 35 | 36 | Большое спасибо каждому из этих участков для размещения данного руководства. 37 | 38 | === Лицензия === 39 | 40 | Это руководство выпущено под http://www.gnu.org/licenses/gpl-3.0.html[GNU General Public License version 3]. Естественно, что источник находится в репозитории Git, и можно получить, набрав: 41 | 42 | $ git clone git://repo.or.cz/gitmagic.git # Создает каталог "gitmagic". 43 | 44 | или с одного из зеркал: 45 | 46 | $ git clone git://github.com/blynn/gitmagic.git 47 | $ git clone git://gitorious.org/gitmagic/mainline.git 48 | -------------------------------------------------------------------------------- /ru/secrets.txt: -------------------------------------------------------------------------------- 1 | == Раскрываем тайны == 2 | 3 | Мы заглянем под капот и объясним, как Git творит свои чудеса. Я опущу некоторые детали. Для более подробного изучения описаний обратитесь к http://www.kernel.org/pub/software/scm/git/docs/user-manual.html[Руководству пользователя]. 4 | 5 | === Невидимость === 6 | 7 | Как Git может быть таким ненавязчивым? Помимо коммитов время от времени и слияния, вы можете работать так, как будто вы не знали, что контроль версий существует. То есть, пока вам это не нужно, вы его не замечаете, и вот, когда он понадобился вы рады, что Git наблюдал за вами все это время. 8 | 9 | Другие системы контроля версий, не позволят вам забыть о них. Права доступа к файлам может быть только для чтения, пока вы явно не укажите серверу, какие файлы вы хотите изменить. Центральный сервер может отслеживать кто извлекал какой код и когда. Когда сеть падает вы можете от этого пострадать. Разработчики постоянно борются с виртуальной волокитой и бюрократизмом. 10 | 11 | Секрет заключается в каталоге `.git` в вашей рабочей директории. Git хранит историю вашего проекта здесь. Из-за имени, начинающегося с точки каталог не отображается в выводе команды `ls`. Кроме комманд *git push* и *git pull* все остальные операции контроля версий работают в этом каталоге. 12 | 13 | Вы имеете полный контроль над судьбой ваших файлов потому что Gitу не важно, что вы делаете с ними. Git можно легко восстановить сохраненное в `.git` состояние в любое время. 14 | 15 | === Целостность === 16 | 17 | Большинство людей ассоциируют с криптографией поддержание информации в секрете, но другой не менее важной задачей является поддержание информации в сохранности. Правильное использование криптографических хеш-функций может предотвратить случайные или злонамеренные повреждения данных. 18 | 19 | SHA1 хэш может рассматриваться как уникальный 160-битный идентификационный номер для каждой строки байт, с которой вы сталкиваетесь в вашей жизни. На самом деле гораздо больше: каждая строка байтов, которую любой человек когда-нибудь использует в течение многих жизней. 20 | 21 | Так как SHA1 хэш сам является последовательностью байтов, мы можем получить хэш строки байтов, содержащей другие хэши. Это простое наблюдение на удивление полезно: смотрите 'hash chains' (цепи хешей). Позднее мы увидим, как Git использует их для эффективного обеспечения целостности данных. 22 | 23 | Короче говоря, Git хранит ваши данные в подкаталоге ".git/objects", где вместо обычных файлов, вы увидите только ID. С помощью идентификаторов как имен файлов, а также нескольких лок-файлов и трюков с временем создания файлов, Git преобразует любую скромную файловую систему в эффективную и надежную базу данных. 24 | 25 | === Интеллект === 26 | 27 | Каким образом Git знает, что вы переименовали файл, даже если вы никогда не упоминается тот факт явно? Конечно, вы можете запустить *git mv*, но это точно так же, как *git rm* и после *git add*. 28 | 29 | Git эвристически находит переименованные файлы и копирует их в последующие версии. В самом деле, он может обнаружить, что куски кода были перемещены или скопированы между файлами! Хотя она не может охватить все случаи, это достойная работа, и эта функция всегда улучшается. Если это не работает, попробуйте включить опцию обнаружения копирования и рассмотреть вопрос апгрейда. 30 | 31 | === Индексация === 32 | 33 | Для каждого отслеживаемого файла, Git записывает информацию, такую как размер, время создания и время последнего изменения в файл, известный как "индекс". Чтобы определить, что файл был изменен, Git сравнивает его текущее состояние с тем, что сохранено в индексе. Если они совпадают, то Git может пропустить перечитывание это файла. 34 | 35 | Поскольку чтение этой информации значительно быстрее, чем чтение всего файла, то если вы редактировали только несколько файлов, Git может обновить свой индекс почти мгновенно. 36 | 37 | === Голые репозитории === 38 | 39 | Вам, возможно, было интересно, какой формат используется в этих онлайн Git репозиториях. 40 | Они такие-же хранилища Git, как ваш каталог `.git`, кроме того что обычно называются `proj.git`, и они не имеют рабочую директорию связанную с ними. 41 | 42 | Большинство команд Git рассчитывают что индекс Git находится в каталоге `.git`, и не смогут работать на этих голых хранилищах. Исправить это можно, установив переменную окружения `GIT_DIR` в значение, равное пути к репозиторию, или запустить Git в этом каталоге с опцией `--bare`. 43 | 44 | === Происхождение Git === 45 | 46 | Этот http://lkml.org/lkml/2005/4/6/121 [пост] в Linux Kernel Mailing List описывает цепь событий, которые привели к появлению Git. Весь этот трейд - увлекательные археологические раскопки для историков Git. 47 | 48 | === База данных объектов === 49 | 50 | Вот как писать Git-подобной операционной системы с нуля в течение нескольких часов. 51 | 52 | ==== Blobs ==== 53 | 54 | Первый волшебный трюк. Выберите имя файла, любое имя файла. В пустой директории: 55 | 56 | $ echo sweet > YOUR_FILENAME 57 | $ git init 58 | $ git add . 59 | $ find .git/objects -type f 60 | 61 | Вы увидите +.git/objects/aa/823728ea7d592acc69b36875a482cdf3fd5c8d+. 62 | 63 | Откуда я знаю это, не зная имени файла? Это потому, что SHA1 хэш строки: 64 | 65 | "blob" SP "6" NUL "sweet" LF 66 | 67 | является aa823728ea7d592acc69b36875a482cdf3fd5c8d, 68 | где SP это пробел, NUL является нулевым байтом и LF переводом строки. Вы можете проверить это, напечатав: 69 | 70 | $ echo "blob 6"$'\001'"sweet" | tr '\001' '\000' | sha1sum 71 | 72 | Кстати, это написано с учетом особенностей оболочки Bash, другие оболочки возможно способны обработать NUL в командной строке, что исключает необходимость использовать костыль с *tr*. 73 | 74 | Git является 'контент-адресуемым': файлы хранятся в независимости от их имени, а по хэшу содержимого, которое мы называем 'BLOB объект'. Мы можем думать о хеше как о уникальном идентификаторе для содержимого файла, так что в некотором смысле мы обращаемся к файлам по их содержимому. Начальный "blob 6" является лишь заголовком, состоящий из типа объекта и его длины в байтах; она упрощает внутренний учет. 75 | 76 | Таким образом, я могу легко предсказать, что вы увидите. Имя файла не имеет никакого отношения: только данные внутри используется для построения BLOB объекта. 77 | 78 | Вам может быть интересно, что происходит с идентичными файлами. Попробуйте добавить копии с любыми именами файлов вообще. Содержание +.git/objects+ останется тем-же независимо от того, сколько копий вы добавите. Git только хранит данные один раз. 79 | 80 | Кстати, файлы в директории +.git/objects+ сжимаются с Zlib поэтому вы не сможете просмотреть их непосредственно. Пропустите их через фильтр http://www.zlib.net/zpipe.c [zpipe-D], или введите: 81 | 82 | $ git cat-file -p aa823728ea7d592acc69b36875a482cdf3fd5c8d 83 | 84 | который просто выведет данный объект. 85 | 86 | ==== Деревья ==== 87 | 88 | Но где же имена файлов? Они должны храниться где-то на определенном этапе. 89 | Git получает информацию об имени во время коммита: 90 | 91 | $ git commit # Type some message. 92 | $ find .git/objects -type f 93 | 94 | Теперь вы должны увидеть 3 объекта. На этот раз я не могу сказать вам, какие 2 новые файлы, так как это частично зависит от выбранного имени файла. Допустим вы назвали его "rose". Если это не так, то вы можете переписать историю, чтобы она выглядела как будто вы это сделали: 95 | 96 | $ git filter-branch --tree-filter 'mv YOUR_FILENAME rose' 97 | $ find .git/objects -type f 98 | 99 | Теперь вы должны увидеть файл 100 | +.git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9+, потому что это 101 | SHA1 хэш его содержимого: 102 | 103 | "tree" SP "32" NUL "100644 rose" NUL 0xaa823728ea7d592acc69b36875a482cdf3fd5c8d 104 | 105 | Проверьте - этот файл действительно содержит указанную выше строку - наберите: 106 | 107 | $ echo 05b217bb859794d08bb9e4f7f04cbda4b207fbe9 | git cat-file --batch 108 | 109 | С zpipe легко проверить хеш: 110 | 111 | $ zpipe -d < .git/objects/05/b217bb859794d08bb9e4f7f04cbda4b207fbe9 | sha1sum 112 | 113 | Проверка хеша сложнее чем через CAT-файла, поскольку его вывод содержит больше, чем сырой несжатый объектный файл. 114 | 115 | Этот файл является объектом 'tree': список цепочек, состоящих из типа файла, имени файла, и хэша. В нашем примере это тип файла "100644", это означает что "rose", является обычным файлом и хэш BLOB объект, в котором находится содержимое "rose". Другие возможные типы файлов - исполняемые файлы, символические ссылки или каталоги. В последнем случае, хэш указывает на дереве объектов. 116 | 117 | Если вы запускали filter-branch, у вас будут старые объекты которые вам больше не нужны. Хотя они будут автоматически выброшены сразу после истечения льготного периода, мы удалим их сейчас, чтобы наш игрушечный пример было легче исследовать: 118 | 119 | $ rm -r .git/refs/original 120 | $ git reflog expire --expire=now --all 121 | $ git prune 122 | 123 | Для реальных проектов, обычно вы должна избегать использовать такие команды, как эта, так как вы разрушаете резервные копии. Если вы хотите чистое хранилище, то обычно лучше сделать новый клон. Кроме того, будьте внимательны при непосредственном манипулировании +.git+: Что делать, если другая команда Git будет запущена в то же время, или внезапного произойдет отключение питания? В общем случае, ссылки должны быть удалены с помощью *git update-ref -d*, хотя обычно удалить +refs/original+ вручную безопасно. 124 | 125 | ==== Коммиты ==== 126 | 127 | Мы объяснили 2 из 3 объектов. Третий объект - 'коммит'. Его содержимое зависит от сообщения коммита, а также от даты и времени его создания. Для демонстрации того, что мы здесь имеем, мы должны настроить Git немного: 128 | 129 | $ git commit --amend -m Shakespeare # Change the commit message. 130 | $ git filter-branch --env-filter 'export 131 | GIT_AUTHOR_DATE="Fri 13 Feb 2009 15:31:30 -0800" 132 | GIT_AUTHOR_NAME="Alice" 133 | GIT_AUTHOR_EMAIL="alice@example.com" 134 | GIT_COMMITTER_DATE="Fri, 13 Feb 2009 15:31:30 -0800" 135 | GIT_COMMITTER_NAME="Bob" 136 | GIT_COMMITTER_EMAIL="bob@example.com"' # Rig timestamps and authors. 137 | $ find .git/objects -type f 138 | 139 | Теперь вы должны увидеть 140 | +.git/objects/49/993fe130c4b3bf24857a15d7969c396b7bc187+ 141 | который является SHA1 хэшем его содержание: 142 | 143 | "commit 158" NUL 144 | "tree 05b217bb859794d08bb9e4f7f04cbda4b207fbe9" LF 145 | "author Alice <alice@example.com> 1234567890 -0800" LF 146 | "committer Bob <bob@example.com> 1234567890 -0800" LF 147 | LF 148 | "Shakespeare" LF 149 | 150 | Как и раньше, вы можете запустить zpipe или cat-file, чтобы увидить это самостоятельно. 151 | 152 | Это первый коммит, и поэтому нет родительского коммита, но последующие коммиты всегда будет содержать хотя бы одну строку идентифицирующую родительский коммит. 153 | 154 | ==== Неотличимо от магии ==== 155 | 156 | Там мало сказано. Мы только что открыли секрет мощи Git. Это кажется слишком простым: похоже, что вы могли бы смешать вместе несколько скриптов оболочки и добавить немного кода на C, сделанного в считанные часы. По сути, это точное описание ранних версий Git. Тем не менее, помимо гениальных трюков упаковки, чтобы сэкономить место, и трюков индексации, чтобы сэкономить время, мы теперь знаем, как ловко Git преображает файловую систему в базу данных, идеально подходящую для контроля версий. 157 | 158 | Например, если какой-то файл объекта базы данных повредила ошибка диска, то его хэш больше не совпадает, предупреждая о проблеме. При хешировании хэшей других объектов, мы сохраняем целостность на всех уровнях. Коммит являются атомными, то есть, никогда нельзя закоммитить лишь часть изменений: мы можем только вычислить хэш коммита и сохранить его в базу данных после того как мы сохраним все соответствующие деревья, блобы и родительские коммиты. Объектная база данных застрахована от неожиданных прерываний работы с ней таких как перебои в подаче электроэнергии. 159 | 160 | Мы наносим поражение даже самым хитрым противникам. Пусть кто-то попытается тайно изменить содержимое файла в древней версии проекта. Чтобы сохранить объектную базу данных согласованной, они также должны изменить хеш соответствующего объекта BLOB, поскольку это теперь другая последовательность байтов. Это означает, что нужно поменять хэш всех деревьев, содержащих ссылки на объект этого файла, что в свою очередь изменит хэши коммитов всех объектов с участием таких деревьев, в дополнение к хэшам всех потомков этих коммитов. Это означает, хэш официальной головной ревизии будет отличаться от хеша в этом плохом хранилище. По следам несовпадения хэшей мы можем локализовать изуродованный файл, а также коммит, где он впервые был поврежден. 161 | 162 | Короче говоря, пока 20 байт представляющие последний коммит в безопасности, невозможно изменить репозиторий Git. 163 | 164 | Как насчет знаменитых черт Git? Создание ветки? Слияние? Теги? Более подробно. 165 | Текущая HEAD хранится в файле +.git/HEAD+, который содержит хэш объекта фиксации. 166 | Хэш обновляется во время коммита, а также при выполнении многих других команд. 167 | Ветки почти одинаковы: они представляют собой файлы в +.git/refs/heads+. 168 | Тэги тоже: они живут в +.git/refs/tags+, но они обновляться различными наборами команд. 169 | -------------------------------------------------------------------------------- /ru/translate.txt: -------------------------------------------------------------------------------- 1 | == Приложение А: Перевод этого руководства == 2 | 3 | Клонируйте исходные тексты, затем создайте соответствующую директорию http://www.iana.org/assignments/language-subtag-registry[языковой тег IETF]: см 4 | http://www.w3.org/International/articles/language-tags/Overview.en.php[статья W3C по интернационализации]. К примеру, английский язык "en", японский "ja", традиционный китайский "zh-Hant". Скопируйте в директорию файлы +txt+ из "en" поддиректории и переведите их. 5 | 6 | К примеру, для перевода руководства на http://en.wikipedia.org/wiki/Klingon_language[Klingon], вы можете набрать: 7 | 8 | $ git clone git://repo.or.cz/gitmagic.git 9 | $ cd gitmagic 10 | $ mkdir tlh # "tlh" - IETF языковой код для Klingon. 11 | $ cd tlh 12 | $ cp ../en/intro.txt . 13 | $ edit intro.txt # Переведите файл. 14 | 15 | и так с каждым файлом. Вы можете просмотреть всю вашу работу: 16 | 17 | $ make LANG=tlh 18 | $ firefox book.html 19 | 20 | Почаще делайте коммиты, потом дайте знать когда ваш перевод готов 21 | На GitHub.com есть веб-интерфейс, который позволяет упростить всю работу: 22 | сделать форк "gitmagic" проекта, внести ваши изменения, потом попросить меня о слиянии. 23 | Я бы хотел чтобы переводы придерживались такой схемы и мои скрипты могли легко создать 24 | HTML и PDF версии. Также эта схема позволяет удобно хранить все переводы в официальном 25 | репозитории. Но пожалуйста, поступайте как вам удобнее: к примеру, китайский переводчик 26 | использовал Google Docs. Я рад тому что ваша работа открывает доступ большему числу людей 27 | к моей работе. 28 | --------------------------------------------------------------------------------